From b34355653e1a663764fd8f69b4915f966c58cf55 Mon Sep 17 00:00:00 2001 From: Juriy Zaytsev Date: Fri, 20 Mar 2009 12:04:06 -0400 Subject: [PATCH 1/6] Remove Array#reduce [#569 state:resolved] --- CHANGELOG | 2 ++ src/lang/array.js | 10 ---------- test/unit/array_test.js | 8 -------- test/unit/selector_test.js | 18 +++++++++++------- 4 files changed, 13 insertions(+), 25 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index dfe1afe..de46059 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,5 @@ +* Remove Array#reduce which currently overrides native `reduce` in clients implementing JS1.8, e.g. Firefox 3+ (Tobie Langel, Andrew Dupont, kangax) + * Make sure try/catch/finally is used instead of try/finally for clients without support for the latter one (e.g. Blackberry, IE) (Ville Koskinen, kangax) * Use `in` operator when accessing property of a nodelist to prevent Safari <=2.0.4 from crashing (kangax) diff --git a/src/lang/array.js b/src/lang/array.js index 62f5f4d..c71c1a2 100644 --- a/src/lang/array.js +++ b/src/lang/array.js @@ -206,15 +206,6 @@ Array.from = $A; return (inline !== false ? this : this.toArray())._reverse(); } - /** - * Array#reduce() -> Array - * Reduces arrays: one-element arrays are turned into their unique item, - * while multiple-element arrays are returned untouched. - **/ - function reduce() { - return this.length > 1 ? this : this[0]; - } - /** * Array#uniq([sorted = false]) -> Array * - sorted (Boolean): Whether the array has already been sorted. If `true`, @@ -349,7 +340,6 @@ Array.from = $A; flatten: flatten, without: without, reverse: reverse, - reduce: reduce, uniq: uniq, intersect: intersect, clone: clone, diff --git a/test/unit/array_test.js b/test/unit/array_test.js index 88d8fad..d090504 100644 --- a/test/unit/array_test.js +++ b/test/unit/array_test.js @@ -137,14 +137,6 @@ new Test.Unit.Runner({ this.assertEqual('[\"a\", 1]', ['a', 1].toJSON()); this.assertEqual('[\"a\", {\"b\": null}]', ['a', {'b': null}].toJSON()); }, - - testReduce: function(){ - this.assertUndefined([].reduce()); - this.assertNull([null].reduce()); - this.assertEqual(1, [1].reduce()); - this.assertEnumEqual([1,2,3], [1,2,3].reduce()); - this.assertEnumEqual([1,null,3], [1,null,3].reduce()); - }, testReverse: function(){ this.assertEnumEqual([], [].reverse()); diff --git a/test/unit/selector_test.js b/test/unit/selector_test.js index 5501eed..9ec3c34 100644 --- a/test/unit/selector_test.js +++ b/test/unit/selector_test.js @@ -1,5 +1,9 @@ var $RunBenchmarks = false; +function reduce(arr) { + return arr.length > 1 ? arr : arr[0]; +} + new Test.Unit.Runner({ testSelectorWithTagName: function() { @@ -193,12 +197,12 @@ new Test.Unit.Runner({ testSelectorWithAdjacence: function() { this.assertEnumEqual([$('uncle')], $$('div.brothers + div.brothers')); this.assertEnumEqual([$('uncle')], $$('div.brothers + div')); - this.assertEqual($('level2_2'), $$('#level2_1+span').reduce()); - this.assertEqual($('level2_2'), $$('#level2_1 + span').reduce()); - this.assertEqual($('level2_2'), $$('#level2_1 + *').reduce()); + this.assertEqual($('level2_2'), reduce($$('#level2_1+span'))); + this.assertEqual($('level2_2'), reduce($$('#level2_1 + span'))); + this.assertEqual($('level2_2'), reduce($$('#level2_1 + *'))); this.assertEnumEqual([], $$('#level2_2 + span')); - this.assertEqual($('level3_2'), $$('#level3_1 + span').reduce()); - this.assertEqual($('level3_2'), $$('#level3_1 + *').reduce()); + this.assertEqual($('level3_2'), reduce($$('#level3_1 + span'))); + this.assertEqual($('level3_2'), reduce($$('#level3_1 + *'))); this.assertEnumEqual([], $$('#level3_2 + *')); this.assertEnumEqual([], $$('#level3_1 + em')); $RunBenchmarks && this.wait(500, function() { @@ -208,8 +212,8 @@ new Test.Unit.Runner({ testSelectorWithLaterSibling: function() { this.assertEnumEqual([$('list')], $$('h1 ~ ul')); - this.assertEqual($('level2_2'), $$('#level2_1 ~ span').reduce()); - this.assertEnumEqual($('level2_2', 'level2_3'), $$('#level2_1 ~ *').reduce()); + this.assertEqual($('level2_2'), reduce($$('#level2_1 ~ span'))); + this.assertEnumEqual($('level2_2', 'level2_3'), reduce($$('#level2_1 ~ *'))); this.assertEnumEqual([], $$('#level2_2 ~ span')); this.assertEnumEqual([], $$('#level3_2 ~ *')); this.assertEnumEqual([], $$('#level3_1 ~ em')); From 88d7671f0d93dc1efa18a6bb859bd69c2b196f72 Mon Sep 17 00:00:00 2001 From: Juriy Zaytsev Date: Fri, 20 Mar 2009 16:10:39 -0400 Subject: [PATCH 2/6] Fix Form.reset test in IE --- CHANGELOG | 2 ++ test/unit/form_test.js | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index de46059..dda73b2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,5 @@ +* Fix `Form.reset` test where `respondsTo` wouldn't detect a method due to typeof returning "object" (rather than "function") in IE (kangax) + * Remove Array#reduce which currently overrides native `reduce` in clients implementing JS1.8, e.g. Firefox 3+ (Tobie Langel, Andrew Dupont, kangax) * Make sure try/catch/finally is used instead of try/finally for clients without support for the latter one (e.g. Blackberry, IE) (Ville Koskinen, kangax) diff --git a/test/unit/form_test.js b/test/unit/form_test.js index 38a4666..f3ae538 100644 --- a/test/unit/form_test.js +++ b/test/unit/form_test.js @@ -27,7 +27,7 @@ new Test.Unit.Runner({ }, testFormReset: function() { - this.assertRespondsTo('reset', Form.reset('form')); + this.assert(!Object.isUndefined(Form.reset('form').reset)); }, testFormElementEventObserver: function(){ From 4b9bf985a2523287ba6978759b522e1ed781ab6a Mon Sep 17 00:00:00 2001 From: Juriy Zaytsev Date: Fri, 20 Mar 2009 16:10:39 -0400 Subject: [PATCH 3/6] Fix Form.reset test in IE --- CHANGELOG | 2 ++ test/unit/form_test.js | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index de46059..dda73b2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,5 @@ +* Fix `Form.reset` test where `respondsTo` wouldn't detect a method due to typeof returning "object" (rather than "function") in IE (kangax) + * Remove Array#reduce which currently overrides native `reduce` in clients implementing JS1.8, e.g. Firefox 3+ (Tobie Langel, Andrew Dupont, kangax) * Make sure try/catch/finally is used instead of try/finally for clients without support for the latter one (e.g. Blackberry, IE) (Ville Koskinen, kangax) diff --git a/test/unit/form_test.js b/test/unit/form_test.js index 38a4666..f3ae538 100644 --- a/test/unit/form_test.js +++ b/test/unit/form_test.js @@ -27,7 +27,7 @@ new Test.Unit.Runner({ }, testFormReset: function() { - this.assertRespondsTo('reset', Form.reset('form')); + this.assert(!Object.isUndefined(Form.reset('form').reset)); }, testFormElementEventObserver: function(){ From a97c04436195b02300d403530db44b434b651c94 Mon Sep 17 00:00:00 2001 From: Juriy Zaytsev Date: Fri, 20 Mar 2009 16:24:13 -0400 Subject: [PATCH 4/6] Remove sniffing from one of the DOM tests, making it pass in IE8. --- CHANGELOG | 2 ++ test/unit/dom_test.js | 13 +++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index dda73b2..736fe7a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,5 @@ +* Remove sniffing from one of the DOM tests, which produced failures in IE8 (kangax) + * Fix `Form.reset` test where `respondsTo` wouldn't detect a method due to typeof returning "object" (rather than "function") in IE (kangax) * Remove Array#reduce which currently overrides native `reduce` in clients implementing JS1.8, e.g. Firefox 3+ (Tobie Langel, Andrew Dupont, kangax) diff --git a/test/unit/dom_test.js b/test/unit/dom_test.js index 3b6cd57..b38f748 100644 --- a/test/unit/dom_test.js +++ b/test/unit/dom_test.js @@ -73,7 +73,15 @@ new Test.Unit.Runner({ this.assertElementsMatch(document.getElementsByClassName('A'), 'p.A', 'ul#class_names_ul.A', 'li.A.C'); - if (Prototype.Browser.IE) + + var isElementPrototypeSupported = (function(){ + var el = document.createElement('div'); + var result = typeof el.show != 'undefined'; + el = null; + return result; + })(); + + if (!isElementPrototypeSupported) this.assertUndefined(document.getElementById('unextended').show); this.assertElementsMatch(div.getElementsByClassName('B'), 'ul#class_names_ul.A.B', 'div.B.C.D'); @@ -95,7 +103,8 @@ new Test.Unit.Runner({ this.assertElementsMatch(list.getElementsByClassName({})); // those lookups shouldn't have extended all nodes in document - if (Prototype.Browser.IE) this.assertUndefined(document.getElementById('unextended')['show']); + if (!isElementPrototypeSupported) + this.assertUndefined(document.getElementById('unextended')['show']); }, testElementInsertWithHTML: function() { From 30c1935cdb6f3a8d850dab8b07a37918740233fb Mon Sep 17 00:00:00 2001 From: Juriy Zaytsev Date: Fri, 20 Mar 2009 17:33:56 -0400 Subject: [PATCH 5/6] Fix `writeAttribute` and `readAttribute` failures in IE8. Use proper feature testing when taking care of getAttribute/setAttribute glitches. --- CHANGELOG | 2 + src/dom/dom.js | 105 ++++++++++++++++++++++++++++++++++--------------- 2 files changed, 75 insertions(+), 32 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 83e4ce0..d6373bb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,5 @@ +* Fix `Element#writeAttribute` and `Element#readAttribute` failures in IE8 due to lack of proper feature testing. (kangax) + * Remove sniffing from one of the DOM tests, which produced failures in IE8. (kangax) * Fix `Form.reset` test where `respondsTo` wouldn't detect a method due to typeof returning "object" (rather than "function") in IE (kangax) diff --git a/src/dom/dom.js b/src/dom/dom.js index 1d58343..6ba0765 100644 --- a/src/dom/dom.js +++ b/src/dom/dom.js @@ -1306,42 +1306,83 @@ else if (Prototype.Browser.IE) { return element; }; - Element._attributeTranslations = { - read: { - names: { - 'class': 'className', - 'for': 'htmlFor' - }, - values: { - _getAttr: function(element, attribute) { - return element.getAttribute(attribute, 2); + Element._attributeTranslations = (function(){ + + var classProp = 'className'; + var el = document.createElement('div'); + + // try "className" first (IE <8) + el.setAttribute(classProp, 'x'); + + if (el.className !== 'x') { + + // try "class" (IE 8) + el.setAttribute('class', 'x'); + if (el.className === 'x') { + classProp = 'class'; + } + } + el = null; + + return { + read: { + names: { + 'class': classProp, + 'className': classProp, + 'for': 'htmlFor' }, - _getAttrNode: function(element, attribute) { - var node = element.getAttributeNode(attribute); - return node ? node.value : ""; - }, - _getEv: function(element, attribute) { - attribute = element.getAttribute(attribute); - - // TODO: Need something less ugly here. - if (!attribute) return null; - attribute = attribute.toString(); - attribute = attribute.split('{')[1]; - attribute = attribute.split('}')[0]; - return attribute.strip(); - }, - _flag: function(element, attribute) { - return $(element).hasAttribute(attribute) ? attribute : null; - }, - style: function(element) { - return element.style.cssText.toLowerCase(); - }, - title: function(element) { - return element.title; + values: { + _getAttr: function(element, attribute) { + return element.getAttribute(attribute, 2); + }, + _getAttrNode: function(element, attribute) { + var node = element.getAttributeNode(attribute); + return node ? node.value : ""; + }, + _getEv: (function(){ + + var el = document.createElement('div'); + el.onclick = Prototype.emptyFunction; + var value = el.getAttribute('onclick'); + var f; + + // IE<8 + if (String(value).indexOf('{') > -1) { + // intrinsic event attributes are serialized as `function { ... }` + f = function(element, attribute) { + attribute = element.getAttribute(attribute); + if (!attribute) return null; + attribute = attribute.toString(); + attribute = attribute.split('{')[1]; + attribute = attribute.split('}')[0]; + return attribute.strip(); + } + } + // IE8 + else if (value === '') { + // only function body is serialized + f = function(element, attribute) { + attribute = element.getAttribute(attribute); + if (!attribute) return null; + return attribute.strip(); + } + } + el = null; + return f; + })(), + _flag: function(element, attribute) { + return $(element).hasAttribute(attribute) ? attribute : null; + }, + style: function(element) { + return element.style.cssText.toLowerCase(); + }, + title: function(element) { + return element.title; + } } } } - }; + })(); Element._attributeTranslations.write = { names: Object.extend({ From 06068431f7358c0278c784ea4bb0ad826cc1e620 Mon Sep 17 00:00:00 2001 From: Juriy Zaytsev Date: Fri, 20 Mar 2009 18:08:34 -0400 Subject: [PATCH 6/6] Fix for/htmlFor translation in IE8 --- CHANGELOG | 2 ++ src/dom/dom.js | 20 ++++++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index d6373bb..d0325dc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,5 @@ +* Fix another failure in IE8, `for`/`htmlFor` {get/set}Attribute translation. (kangax) + * Fix `Element#writeAttribute` and `Element#readAttribute` failures in IE8 due to lack of proper feature testing. (kangax) * Remove sniffing from one of the DOM tests, which produced failures in IE8. (kangax) diff --git a/src/dom/dom.js b/src/dom/dom.js index 6ba0765..cad7f70 100644 --- a/src/dom/dom.js +++ b/src/dom/dom.js @@ -1169,7 +1169,7 @@ Element._attributeTranslations = { write: { names: { className: 'class', - htmlFor: 'for' + htmlFor: 'for' }, values: { } } @@ -1309,13 +1309,14 @@ else if (Prototype.Browser.IE) { Element._attributeTranslations = (function(){ var classProp = 'className'; + var forProp = 'for'; + var el = document.createElement('div'); // try "className" first (IE <8) el.setAttribute(classProp, 'x'); if (el.className !== 'x') { - // try "class" (IE 8) el.setAttribute('class', 'x'); if (el.className === 'x') { @@ -1324,12 +1325,23 @@ else if (Prototype.Browser.IE) { } el = null; + el = document.createElement('label'); + el.setAttribute(forProp, 'x'); + if (el.htmlFor !== 'x') { + el.setAttribute('htmlFor', 'x'); + if (el.htmlFor === 'x') { + forProp = 'htmlFor'; + } + } + el = null; + return { read: { names: { 'class': classProp, 'className': classProp, - 'for': 'htmlFor' + 'for': forProp, + 'htmlFor': forProp }, values: { _getAttr: function(element, attribute) { @@ -1905,4 +1917,4 @@ Element.addMethods({ return value; } -}); +}); \ No newline at end of file