prototype: Fix $(form).serialize() in Safari and add support for extending specific tags to Element.addMethods. Closes #7358.
This commit is contained in:
parent
5345085b33
commit
7044da8138
|
@ -1,5 +1,7 @@
|
|||
*SVN*
|
||||
|
||||
* Fix $(form).serialize() in Safari and add support for extending specific tags to Element.addMethods. Closes #7358. [Andrew Dupont]
|
||||
|
||||
* Add String.prototype.startsWith, String.prototype.endsWith, and String.prototype.include. Closes #7075. [Tobie Langel]
|
||||
|
||||
* Improve performance of String.prototype.escapeHTML by using a cached div and text node. Closes #6937. [altblue]
|
||||
|
|
122
src/dom.js
122
src/dom.js
|
@ -41,26 +41,31 @@ document.getElementsByClassName = function(className, parentElement) {
|
|||
if (!window.Element)
|
||||
var Element = new Object();
|
||||
|
||||
|
||||
Element.extend = function(element) {
|
||||
if (!element || _nativeExtensions || element.nodeType == 3) return element;
|
||||
|
||||
if (!element._extended && element.tagName && element != window) {
|
||||
var methods = Object.clone(Element.Methods), cache = Element.extend.cache;
|
||||
|
||||
if (element.tagName == 'FORM')
|
||||
Object.extend(methods, Form.Methods);
|
||||
if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName))
|
||||
Object.extend(methods, Form.Element.Methods);
|
||||
|
||||
Object.extend(methods, Element.Methods.Simulated);
|
||||
|
||||
for (var property in methods) {
|
||||
var value = methods[property];
|
||||
if (typeof value == 'function' && !(property in element))
|
||||
element[property] = cache.findOrStore(value);
|
||||
}
|
||||
var F = Prototype.BrowserFeatures;
|
||||
if (!element || !element.tagName || element.nodeType == 3 ||
|
||||
element._extended || F.SpecificElementExtensions || element == window)
|
||||
return element;
|
||||
|
||||
var methods = {}, tagName = element.tagName, cache = Element.extend.cache,
|
||||
T = Element.Methods.ByTag;
|
||||
|
||||
// extend methods for all tags (Safari doesn't need this)
|
||||
if (!F.ElementExtensions) {
|
||||
Object.extend(methods, Element.Methods),
|
||||
Object.extend(methods, Element.Methods.Simulated);
|
||||
}
|
||||
|
||||
|
||||
// extend methods for specific tags
|
||||
if (T[tagName]) Object.extend(methods, T[tagName]);
|
||||
|
||||
for (var property in methods) {
|
||||
var value = methods[property];
|
||||
if (typeof value == 'function' && !(property in element))
|
||||
element[property] = cache.findOrStore(value);
|
||||
}
|
||||
|
||||
element._extended = true;
|
||||
return element;
|
||||
};
|
||||
|
@ -471,6 +476,8 @@ Element.Methods.Simulated = {
|
|||
}
|
||||
};
|
||||
|
||||
Element.Methods.ByTag = {};
|
||||
|
||||
// IE is missing .innerHTML support for TABLE-related elements
|
||||
if (document.all && !window.opera){
|
||||
Element.Methods.update = function(element, html) {
|
||||
|
@ -510,19 +517,36 @@ if (document.all && !window.opera){
|
|||
|
||||
Object.extend(Element, Element.Methods);
|
||||
|
||||
var _nativeExtensions = false;
|
||||
|
||||
if(/Konqueror|Safari|KHTML/.test(navigator.userAgent))
|
||||
['', 'Form', 'Input', 'TextArea', 'Select'].each(function(tag) {
|
||||
var className = 'HTML' + tag + 'Element';
|
||||
if(window[className]) return;
|
||||
var klass = window[className] = {};
|
||||
klass.prototype = document.createElement(tag ? tag.toLowerCase() : 'div').__proto__;
|
||||
});
|
||||
if (!Prototype.BrowserFeatures.ElementExtensions &&
|
||||
document.createElement('div').__proto__) {
|
||||
window.HTMLElement = {};
|
||||
window.HTMLElement.prototype = document.createElement('div').__proto__;
|
||||
Prototype.BrowserFeatures.ElementExtensions = true;
|
||||
}
|
||||
|
||||
Element.addMethods = function(methods) {
|
||||
Object.extend(Element.Methods, methods || {});
|
||||
var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
|
||||
if (arguments.length == 2) {
|
||||
var tagName = methods;
|
||||
methods = arguments[1];
|
||||
}
|
||||
|
||||
if (!tagName)
|
||||
Object.extend(Element.Methods, methods || {});
|
||||
else {
|
||||
if (tagName.constructor == Array) {
|
||||
tagName.each(extend);
|
||||
}
|
||||
else extend(tagName);
|
||||
}
|
||||
|
||||
function extend(tagName) {
|
||||
tagName = tagName.toUpperCase();
|
||||
if (!Element.Methods.ByTag[tagName])
|
||||
Element.Methods.ByTag[tagName] = {};
|
||||
Object.extend(Element.Methods.ByTag[tagName], methods);
|
||||
}
|
||||
|
||||
function copy(methods, destination, onlyIfAbsent) {
|
||||
onlyIfAbsent = onlyIfAbsent || false;
|
||||
var cache = Element.extend.cache;
|
||||
|
@ -533,16 +557,44 @@ Element.addMethods = function(methods) {
|
|||
}
|
||||
}
|
||||
|
||||
if (typeof HTMLElement != 'undefined') {
|
||||
function findDOMClass(tagName) {
|
||||
var klass;
|
||||
var trans = {
|
||||
"OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
|
||||
"FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
|
||||
"DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
|
||||
"H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
|
||||
"INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
|
||||
"TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
|
||||
"TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
|
||||
"TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
|
||||
"FrameSet", "IFRAME": "IFrame"
|
||||
};
|
||||
if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
|
||||
if (window[klass]) return window[klass];
|
||||
klass = 'HTML' + tagName + 'Element';
|
||||
if (window[klass]) return window[klass];
|
||||
klass = 'HTML' + tagName.capitalize() + 'Element';
|
||||
if (window[klass]) return window[klass];
|
||||
|
||||
window[klass] = {};
|
||||
window[klass].prototype = document.createElement(tagName).__proto__;
|
||||
return window[klass];
|
||||
}
|
||||
|
||||
if (F.ElementExtensions) {
|
||||
copy(Element.Methods, HTMLElement.prototype);
|
||||
copy(Element.Methods.Simulated, HTMLElement.prototype, true);
|
||||
copy(Form.Methods, HTMLFormElement.prototype);
|
||||
[HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) {
|
||||
copy(Form.Element.Methods, klass.prototype);
|
||||
});
|
||||
_nativeExtensions = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (F.SpecificElementExtensions) {
|
||||
for (var tag in Element.Methods.ByTag) {
|
||||
var klass = findDOMClass(tag);
|
||||
if (typeof klass == "undefined") continue;
|
||||
copy(T[tag], klass.prototype);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var Toggle = new Object();
|
||||
Toggle.display = Element.toggle;
|
||||
|
|
10
src/form.js
10
src/form.js
|
@ -156,6 +156,15 @@ Form.Element.Methods = {
|
|||
}
|
||||
|
||||
Object.extend(Form.Element, Form.Element.Methods);
|
||||
Object.extend(Element.Methods.ByTag, {
|
||||
"FORM": Object.clone(Form.Methods),
|
||||
"INPUT": Object.clone(Form.Element.Methods),
|
||||
"SELECT": Object.clone(Form.Element.Methods),
|
||||
"TEXTAREA": Object.clone(Form.Element.Methods)
|
||||
});
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
var Field = Form.Element;
|
||||
var $F = Form.Element.getValue;
|
||||
|
||||
|
@ -304,4 +313,3 @@ Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
|
|||
return Form.serialize(this.element);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -3,7 +3,11 @@
|
|||
var Prototype = {
|
||||
Version: '<%= PROTOTYPE_VERSION %>',
|
||||
BrowserFeatures: {
|
||||
XPath: !!document.evaluate
|
||||
XPath: !!document.evaluate,
|
||||
ElementExtensions: !!window.HTMLElement,
|
||||
SpecificElementExtensions:
|
||||
(document.createElement('div').__proto__ !==
|
||||
document.createElement('form').__proto__)
|
||||
},
|
||||
|
||||
ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
|
||||
|
|
|
@ -256,6 +256,18 @@
|
|||
|
||||
var testVar = 'to be updated';
|
||||
|
||||
Element.addMethods("LI", {
|
||||
pancakes: function(element) { return "pancakes"; }
|
||||
});
|
||||
|
||||
Element.addMethods("DIV", {
|
||||
waffles: function(element) { return "waffles"; }
|
||||
});
|
||||
|
||||
Element.addMethods($w("li div"), {
|
||||
orangeJuice: function(element) { return "orange juice"; }
|
||||
});
|
||||
|
||||
new Test.Unit.Runner({
|
||||
|
||||
testDollarFunction: function() { with(this) {
|
||||
|
@ -271,6 +283,7 @@
|
|||
var elt = $('testdiv');
|
||||
assertIdentical(elt, $(elt));
|
||||
assertRespondsTo('hide', elt);
|
||||
assertRespondsTo('childOf', elt);
|
||||
}},
|
||||
|
||||
testGetElementsByClassName: function() {with(this) {
|
||||
|
@ -282,7 +295,7 @@
|
|||
|
||||
testInsertWithTR: function() {with(this) {
|
||||
new Insertion.After('second_row', '<tr id="third_row"><td>Third Row</td></tr>');
|
||||
assert($('second_row').childOf('table'));
|
||||
assert($('second_row').descendantOf('table'));
|
||||
}},
|
||||
|
||||
testElementVisible: function(){with(this) {
|
||||
|
@ -801,8 +814,27 @@
|
|||
elem.scrollTo();
|
||||
assertEqual(Position.page(elem)[1], 0);
|
||||
window.scrollTo(0, 0);
|
||||
}}
|
||||
}},
|
||||
|
||||
testSpecificElementMethods: function() {with(this) {
|
||||
var elem = $('navigation_test_f');
|
||||
|
||||
assert(Element.Methods.ByTag[elem.tagName]);
|
||||
assertRespondsTo('pancakes', elem);
|
||||
assertEqual("pancakes", elem.pancakes());
|
||||
|
||||
var elem2 = $('test-visible');
|
||||
|
||||
assert(Element.Methods.ByTag[elem2.tagName]);
|
||||
assertUndefined(elem2.pancakes);
|
||||
assertRespondsTo('waffles', elem2);
|
||||
assertEqual("waffles", elem2.waffles());
|
||||
|
||||
assertRespondsTo('orangeJuice', elem);
|
||||
assertRespondsTo('orangeJuice', elem2);
|
||||
assertEqual("orange juice", elem.orangeJuice());
|
||||
assertEqual("orange juice", elem2.orangeJuice());
|
||||
}}
|
||||
}, 'testlog');
|
||||
|
||||
// ]]>
|
||||
|
|
|
@ -280,7 +280,27 @@
|
|||
testFormSerializeWorksWithNonFormElements: function() {with(this) {
|
||||
assertEqual('nvm%5B%5D=One&nvm%5B%5D=Three&evu=&evm%5B%5D=&evm%5B%5D=Three', Form.serialize('form_fieldset'));
|
||||
assertEqual('vu=1&vm%5B%5D=1&vm%5B%5D=3&nvu=One&nvm%5B%5D=One&nvm%5B%5D=Three&evu=&evm%5B%5D=&evm%5B%5D=Three', Form.serialize('form_wrapper'));
|
||||
}}
|
||||
}},
|
||||
|
||||
testFormMethodsOnExtendedElements: function() {with(this) {
|
||||
assertEqual(Form.serialize('form'), $('form').serialize());
|
||||
assertEqual(Form.Element.serialize('input_enabled'), $('input_enabled').serialize());
|
||||
assertNotEqual($('form').serialize, $('input_enabled').serialize);
|
||||
|
||||
Element.addMethods('INPUT', { anInputMethod: function(input) { return 'input' } });
|
||||
Element.addMethods('SELECT', { aSelectMethod: function(select) { return 'select' } });
|
||||
|
||||
document.getElementById('tf_text')._extended = false;
|
||||
document.getElementById('tf_selectOne')._extended = false;
|
||||
|
||||
assert($('tf_text').anInputMethod);
|
||||
assert(!$('tf_text').aSelectMethod);
|
||||
assertEqual('input', $('tf_text').anInputMethod());
|
||||
|
||||
assert($('tf_selectOne').aSelectMethod);
|
||||
assert(!$('tf_selectOne').anInputMethod);
|
||||
assertEqual('select', $('tf_selectOne').aSelectMethod());
|
||||
}}
|
||||
|
||||
}, 'testlog');
|
||||
// ]]>
|
||||
|
|
Loading…
Reference in New Issue