diff --git a/CHANGELOG b/CHANGELOG index 52b0636..8caaa07 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,8 @@ *SVN* -* Fix an issue with serializing empty array inputs, fixes #7516. [stakadush, Mislav Marohnić] +* Optimize document.getElementsByClassName and finalize DOM performance optimization refactoring. Closes #6696. [Mislav Marohnić] + +* Fix an issue with serializing empty array inputs. Closes #7516. [stakadush, Mislav Marohnić] * Add optional third parameter "camelized" to Element.setStyle, for optimized performance if style names are known to be camelCased. [Thomas Fuchs] diff --git a/src/dom.js b/src/dom.js index a342f62..e0cdb95 100644 --- a/src/dom.js +++ b/src/dom.js @@ -18,29 +18,24 @@ if (Prototype.BrowserFeatures.XPath) { results.push(query.snapshotItem(i)); return results; }; -} - -document.getElementsByClassName = function(className, parentElement) { - if (Prototype.BrowserFeatures.XPath) { + document.getElementsByClassName = function(className, parentElement) { var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]"; return document._getElementsByXPath(q, parentElement); - } else { - var children = ($(parentElement) || document.body).getElementsByTagName('*'); - var elements = [], child; - for (var i = 0, length = children.length; i < length; i++) { - child = children[i]; - if (Element.hasClassName(child, className)) - elements.push(Element.extend(child)); - } - return elements; } +} else document.getElementsByClassName = function(className, parentElement) { + var children = ($(parentElement) || document.body).getElementsByTagName('*'); + var elements = [], child; + for (var i = 0, length = children.length; i < length; i++) { + child = children[i]; + if (Element.hasClassName(child, className)) + elements.push(Element.extend(child)); + } + return elements; }; /*--------------------------------------------------------------------------*/ -if (!window.Element) - var Element = new Object(); - +if (!window.Element) var Element = {}; Element.extend = function(element) { var F = Prototype.BrowserFeatures; @@ -421,8 +416,7 @@ if (Prototype.Browser.Opera) { } }; } - -if (Prototype.Browser.IE) { +else if (Prototype.Browser.IE) { Element.Methods.getStyle = function(element, style) { element = $(element); style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); @@ -454,73 +448,8 @@ if (Prototype.Browser.IE) { 'alpha(opacity=' + (value * 100) + ')'; return element; }; -} -if (Prototype.Browser.Gecko) { - Element.Methods.setOpacity = function(element, value) { - element = $(element); - element.style.opacity = (value == 1) ? 0.999999 : - (value === '') ? '' : (value < 0.00001) ? 0 : value; - return element; - }; -} - -Element._attributeTranslations = {}; - -Element._attributeTranslations.names = { - colspan: "colSpan", - rowspan: "rowSpan", - valign: "vAlign", - datetime: "dateTime", - accesskey: "accessKey", - tabindex: "tabIndex", - enctype: "encType", - maxlength: "maxLength", - readonly: "readOnly", - longdesc: "longDesc" -}; - -Element._attributeTranslations.values = { - _getAttr: function(element, attribute) { - return element.getAttribute(attribute, 2); - }, - - _flag: function(element, attribute) { - return $(element).hasAttribute(attribute) ? attribute : null; - }, - - style: function(element) { - return element.style.cssText.toLowerCase(); - }, - - title: function(element) { - var node = element.getAttributeNode('title'); - return node.specified ? node.nodeValue : null; - } -}; - -Object.extend(Element._attributeTranslations.values, { - href: Element._attributeTranslations.values._getAttr, - src: Element._attributeTranslations.values._getAttr, - disabled: Element._attributeTranslations.values._flag, - checked: Element._attributeTranslations.values._flag, - readonly: Element._attributeTranslations.values._flag, - multiple: Element._attributeTranslations.values._flag -}); - -Element.Methods.Simulated = { - hasAttribute: function(element, attribute) { - var t = Element._attributeTranslations, node; - attribute = t.names[attribute] || attribute; - node = $(element).getAttributeNode(attribute); - return node && node.specified; - } -}; - -Element.Methods.ByTag = {}; - -// IE is missing .innerHTML support for TABLE-related elements -if (Prototype.Browser.IE){ + // IE is missing .innerHTML support for TABLE-related elements Element.Methods.update = function(element, html) { element = $(element); html = typeof html == 'undefined' ? '' : html.toString(); @@ -554,8 +483,68 @@ if (Prototype.Browser.IE){ setTimeout(function() {html.evalScripts()}, 10); return element; } +} +else if (Prototype.Browser.Gecko) { + Element.Methods.setOpacity = function(element, value) { + element = $(element); + element.style.opacity = (value == 1) ? 0.999999 : + (value === '') ? '' : (value < 0.00001) ? 0 : value; + return element; + }; +} + +Element._attributeTranslations = { + names: { + colspan: "colSpan", + rowspan: "rowSpan", + valign: "vAlign", + datetime: "dateTime", + accesskey: "accessKey", + tabindex: "tabIndex", + enctype: "encType", + maxlength: "maxLength", + readonly: "readOnly", + longdesc: "longDesc" + }, + values: { + _getAttr: function(element, attribute) { + return element.getAttribute(attribute, 2); + }, + _flag: function(element, attribute) { + return $(element).hasAttribute(attribute) ? attribute : null; + }, + style: function(element) { + return element.style.cssText.toLowerCase(); + }, + title: function(element) { + var node = element.getAttributeNode('title'); + return node.specified ? node.nodeValue : null; + } + } }; +with (Element._attributeTranslations.values) { + Object.extend(this, { + href: _getAttr, + src: _getAttr, + disabled: _flag, + checked: _flag, + readonly: _flag, + multiple: _flag + }); +}; + +Element.Methods.Simulated = { + hasAttribute: function(element, attribute) { + var t = Element._attributeTranslations, node; + attribute = t.names[attribute] || attribute; + node = $(element).getAttributeNode(attribute); + return node && node.specified; + } +}; + +Element.Methods.ByTag = {}; + Object.extend(Element, Element.Methods); if (!Prototype.BrowserFeatures.ElementExtensions && @@ -572,12 +561,9 @@ Element.addMethods = function(methods) { methods = arguments[1]; } - if (!tagName) - Object.extend(Element.Methods, methods || {}); + if (!tagName) Object.extend(Element.Methods, methods || {}); else { - if (tagName.constructor == Array) { - tagName.each(extend); - } + if (tagName.constructor == Array) tagName.each(extend); else extend(tagName); } @@ -637,8 +623,7 @@ Element.addMethods = function(methods) { } }; -var Toggle = new Object(); -Toggle.display = Element.toggle; +var Toggle = { display: Element.toggle }; /*--------------------------------------------------------------------------*/ diff --git a/test/unit/dom.html b/test/unit/dom.html index 57fecf6..e7561f6 100644 --- a/test/unit/dom.html +++ b/test/unit/dom.html @@ -631,12 +631,9 @@ }}, testElementSetStyleCamelized: function() { with(this) { + assertNotEqual('30px', $('style_test_3').style.marginTop); $('style_test_3').setStyle({ marginTop: '30px'}, true); assertEqual('30px', $('style_test_3').style.marginTop); - - // This would work if camelized parameter is false - $('style_test_3').setStyle({ 'margin-top': '20px'}, true); - assertEqual('30px', $('style_test_3').style.marginTop); }}, testElementSetOpacity: function() { with(this) { @@ -728,7 +725,11 @@ }}, testElementReadAttribute: function() {with(this) { - assertEqual('test.html' , $('attributes_with_issues_1').readAttribute('href')); + assertEqual('test.html' , $('attributes_with_issues_1').readAttribute('href'), + 'NOTE: Due to a bug in IE\'s proprietary iFlags extension to getAttribute(), '+ + '"href" attribute lookup fails to grab the exact attribute value for protocols '+ + 'other than http(s), which makes this test fail when run locally (file protocol).'); + assertEqual('L' , $('attributes_with_issues_1').readAttribute('accesskey')); assertEqual('50' , $('attributes_with_issues_1').readAttribute('tabindex')); assertEqual('a link' , $('attributes_with_issues_1').readAttribute('title'));