* Although jQuery covers for us in most cases (since .prop didn't exist before jQuery 1.6 and many people abused .attr in laziness of doing their own loop and setting the property manually). It's better to know what we're doing and call the function we intend to call. Both because jQuery may decide to stop rerouting common mistakes to .prop and because it makes code more readable.
* Aside from switching to prop, for boolean properties also replacing null/undefined with false and 'propname' with true. This is no longer being covered by jQuery when using prop directly (as it shouldn't). When an element is created the HTML specification says that the attribute should be set to it's name (ie. '<foo selected="selected">'), the properties however must remain boolean.
* Changing the attribute value for a boolean property (ie. checkbox.setAttribute( 'checked', 'checked' ) does not make the checkbox enabled. All it does is set the attribute. The reason this works with jQuery's attr() is because jQuery calls .prop internally after a bunch of checking inside attr().
-- Reference --
The list of keys that .attr and .removeAttr jQuery is currently (as of jQuery 1.6.1) remapping to use .prop and .removeProp can be found here:
b22c904652/src/attributes.js (L425)
{
tabindex: "tabIndex",
readonly: "readOnly",
"for": "htmlFor",
"class": "className",
maxlength: "maxLength",
cellspacing: "cellSpacing",
cellpadding: "cellPadding",
rowspan: "rowSpan",
colspan: "colSpan",
usemap: "useMap",
frameborder: "frameBorder",
contenteditable: "contentEditable"
}
In addition to those, jQuery also maps these boolean properties to .prop when they are passed to .attr:
rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
(source: b22c904652/src/attributes.js (L9) )
* Browsers should ignore the maxLength when the .value is set manually through JavaScript, but for some reason Safari 4 (not 5 and later) is enforcing the limit even when the value property is set from JavaScript. Usually this bug doesn't become visible in this module because the byteLength can't be lower than the number of characters, so we'd never see the bug. However since r94066 we're supporting callbacks, and callbacks could do anything to the calculation, including but not limited to making the string that is being checked shorter (ie. suppose maxLength/byteLimit is 8, value is 'User:Sam', and callback filters like "return new mw.Title(val).getName()". If we set it to 'User:Samp' (+p) then Safari 4 would chop the value, because the total string is longer than 8. Whereas all other browsers ignore maxLength (like they should) and let it be and would allow our callback to happen and instead give byteLimit 'Samp' which is length 4 and we still have 4 more characters to go until we reach 8.
The fix is easy, simply do not set the maxLength property if there's a callback.
* Fixes (bug 29455) Add support for a filter callback function in jQuery byteLimit plugin.
* Adding unit tests for it
* Changing if-statements in mw.Title's helper functions for regular expression matches. It should check wether the value is not null or undefined. Before it was just a plain if-statement which meant that an empty string would also return false, which made the new byteLimit's tests fail (mw.Title.getMain() expects _name to be a valid string when it does ucFirst() and substr() etc.)
Since the Unicode code point of the character being inserted is passed with the keypress event, we can simply turn it into a string and toss it into jquery.byteLength to calculate the length in bytes.
Also fixed a broken test case that had the wrong number of expected chars.
Note that this will probably still not work right in many circumstances -- pastes, anything dealing with selection, and it's entirely possible that individual 'keypress' events might be totally unreliable when dealing with funky input methods.
* Split the byte length logic into a seperate method to allow it to be called directly on a string (easier to test and easier re-use)
* Added basic unit tests for it.
* 'this' in a fn/prototype context already points to the jQuery object. Calling $(this) is redundant and goes through $.fn.init again untill it reaches the last else case (luckily $.fn.init() has a failsafe case for that, but also makes it harder to spot)
* Adding support for using the current attribute value (to avoid having to duplicate the values between PHP and JavaScript). Fully backwards compatible, I think it's a very handy feature to be able to pass a custom length, but using the maxLength attribute as a default makes sense.