From 1e465fc70ba7390cf5bd6ccc95cca3b2f24c0856 Mon Sep 17 00:00:00 2001 From: Mohammad Khatib Date: Sun, 29 May 2016 19:23:17 -0700 Subject: [PATCH 1/4] Add toArray utility function to convert array-like objects to arrays. --- src/dom.js | 9 ++--- src/types.js | 16 +++++++++ test/functional/test-types.js | 62 +++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 7 deletions(-) create mode 100644 test/functional/test-types.js diff --git a/src/dom.js b/src/dom.js index 2b81750148a3..7b3aae97b961 100644 --- a/src/dom.js +++ b/src/dom.js @@ -16,6 +16,7 @@ import {dashToCamelCase} from './string'; import {dev} from './log'; +import {toArray} from './types'; /** * Waits until the child element is constructed. Once the child is found, the @@ -328,13 +329,7 @@ export function childElementsByAttr(parent, attr) { scopeSelectorSupported = isScopeSelectorSupported(parent); } if (scopeSelectorSupported) { - const nodeList = parent.querySelectorAll(':scope > [' + attr + ']'); - // Convert NodeList into Array.. - const children = []; - for (let i = 0; i < nodeList.length; i++) { - children.push(nodeList[i]); - } - return children; + return toArray(parent.querySelectorAll(':scope > [' + attr + ']')); } return childElements(parent, el => { return el.hasAttribute(attr); diff --git a/src/types.js b/src/types.js index 45c835aa58ce..32cf9bdb6985 100644 --- a/src/types.js +++ b/src/types.js @@ -35,6 +35,22 @@ export function isArray(value) { return Array.isArray(value); } +/** + * Converts an array-like object to an array. + * @param {?HTMLCollection|?NodeList|*} arrayLike + * @return {!Array.<*>} + */ +export function toArray(arrayLike) { + if (!arrayLike) { + return []; + } + const array = []; + for (let i = 0; i < arrayLike.length; i++) { + array.push(arrayLike[i]); + } + return array; +} + /** * Determines if value is actually an Object. * @param {*} value diff --git a/test/functional/test-types.js b/test/functional/test-types.js new file mode 100644 index 000000000000..b87718cb43b8 --- /dev/null +++ b/test/functional/test-types.js @@ -0,0 +1,62 @@ +/** + * Copyright 2016 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as types from '../../src/types'; + +describe('Types', () => { + describe('toArray', () => { + + it('should return empty array if null passed', () => { + expect(types.toArray(null).length).to.equal(0); + expect(types.toArray(undefined).length).to.equal(0); + }); + + it('should convert NodeList to array', () => { + const parent = document.createElement('div'); + parent.appendChild(document.createElement('p')); + parent.appendChild(document.createElement('span')); + parent.appendChild(document.createElement('div')); + const arr = types.toArray(parent.childNodes); + expect(arr[0]).to.equal(parent.childNodes[0]); + expect(arr.length).to.equal(3); + expect(Array.isArray(arr)).to.be.true; + }); + + it('should convert HTMLCollection to array', () => { + const parent = document.createElement('div'); + parent.appendChild(document.createElement('form')); + parent.appendChild(document.createElement('form')); + document.body.appendChild(parent); + const arr = types.toArray(document.forms); + expect(arr[0]).to.equal(document.forms[0]); + expect(arr.length).to.equal(2); + expect(Array.isArray(arr)).to.be.true; + document.body.removeChild(parent); + }); + + it('should convert HTMLOptionsCollection to array', () => { + const parent = document.createElement('select'); + parent.appendChild(document.createElement('option')); + parent.appendChild(document.createElement('option')); + parent.appendChild(document.createElement('option')); + parent.appendChild(document.createElement('option')); + const arr = types.toArray(parent.options); + expect(arr[0]).to.equal(parent.options[0]); + expect(arr.length).to.equal(4); + expect(Array.isArray(arr)).to.be.true; + }); + }) +}); From a0e95acd590e8c799fc243ee175d8006200f03c9 Mon Sep 17 00:00:00 2001 From: Mohammad Khatib Date: Thu, 2 Jun 2016 15:04:48 -0700 Subject: [PATCH 2/4] Address comments. --- src/types.js | 14 +++++++++----- test/functional/test-types.js | 9 +++++++-- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/types.js b/src/types.js index 32cf9bdb6985..71b20d9c8078 100644 --- a/src/types.js +++ b/src/types.js @@ -37,18 +37,22 @@ export function isArray(value) { /** * Converts an array-like object to an array. - * @param {?HTMLCollection|?NodeList|*} arrayLike + * @param {?IArrayLike<*>|string} arrayLike * @return {!Array.<*>} */ export function toArray(arrayLike) { if (!arrayLike) { return []; } - const array = []; - for (let i = 0; i < arrayLike.length; i++) { - array.push(arrayLike[i]); + const length = arrayLike.length; + if (length > 0) { + const array = new Array(length); + for (let i = 0; i < length; i++) { + array[i] = arrayLike[i]; + } + return array; } - return array; + return []; } /** diff --git a/test/functional/test-types.js b/test/functional/test-types.js index b87718cb43b8..82b58e3f940a 100644 --- a/test/functional/test-types.js +++ b/test/functional/test-types.js @@ -19,11 +19,16 @@ import * as types from '../../src/types'; describe('Types', () => { describe('toArray', () => { - it('should return empty array if null passed', () => { + it('should return empty array if null is passed', () => { expect(types.toArray(null).length).to.equal(0); expect(types.toArray(undefined).length).to.equal(0); }); + it('should return empty array if non-array-like is passed', () => { + expect(types.toArray({}).length).to.equal(0); + expect(types.toArray(document.createElement('p')).length).to.equal(0); + }); + it('should convert NodeList to array', () => { const parent = document.createElement('div'); parent.appendChild(document.createElement('p')); @@ -58,5 +63,5 @@ describe('Types', () => { expect(arr.length).to.equal(4); expect(Array.isArray(arr)).to.be.true; }); - }) + }); }); From a15175733d037ecf6a04e1168b3d5538a887d2b1 Mon Sep 17 00:00:00 2001 From: Mohammad Khatib Date: Thu, 2 Jun 2016 15:33:01 -0700 Subject: [PATCH 3/4] address comments --- src/types.js | 16 +++++++--------- test/functional/test-types.js | 5 ----- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/types.js b/src/types.js index 71b20d9c8078..3a5337159aff 100644 --- a/src/types.js +++ b/src/types.js @@ -37,22 +37,20 @@ export function isArray(value) { /** * Converts an array-like object to an array. - * @param {?IArrayLike<*>|string} arrayLike - * @return {!Array.<*>} + * @param {?IArrayLike|string} arrayLike + * @return {!Array} + * @template T */ export function toArray(arrayLike) { if (!arrayLike) { return []; } const length = arrayLike.length; - if (length > 0) { - const array = new Array(length); - for (let i = 0; i < length; i++) { - array[i] = arrayLike[i]; - } - return array; + const array = new Array(length); + for (let i = 0; i < array.length; i++) { + array[i] = arrayLike[i]; } - return []; + return array; } /** diff --git a/test/functional/test-types.js b/test/functional/test-types.js index 82b58e3f940a..884d94ea5bea 100644 --- a/test/functional/test-types.js +++ b/test/functional/test-types.js @@ -24,11 +24,6 @@ describe('Types', () => { expect(types.toArray(undefined).length).to.equal(0); }); - it('should return empty array if non-array-like is passed', () => { - expect(types.toArray({}).length).to.equal(0); - expect(types.toArray(document.createElement('p')).length).to.equal(0); - }); - it('should convert NodeList to array', () => { const parent = document.createElement('div'); parent.appendChild(document.createElement('p')); From 2a6491f92363e7f6794554f89a2f69795b461c3b Mon Sep 17 00:00:00 2001 From: Mohammad Khatib Date: Thu, 2 Jun 2016 15:47:56 -0700 Subject: [PATCH 4/4] address comments. --- src/types.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/types.js b/src/types.js index 3a5337159aff..400bbb20f41d 100644 --- a/src/types.js +++ b/src/types.js @@ -45,9 +45,8 @@ export function toArray(arrayLike) { if (!arrayLike) { return []; } - const length = arrayLike.length; - const array = new Array(length); - for (let i = 0; i < array.length; i++) { + const array = new Array(arrayLike.length); + for (let i = 0; i < arrayLike.length; i++) { array[i] = arrayLike[i]; } return array;