diff --git a/packages/elements/src/extract-projectable-nodes.ts b/packages/elements/src/extract-projectable-nodes.ts new file mode 100644 index 0000000000..b6df05bcba --- /dev/null +++ b/packages/elements/src/extract-projectable-nodes.ts @@ -0,0 +1,54 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +// NOTE: This is a (slightly improved) version of what is used in ngUpgrade's +// `DowngradeComponentAdapter`. +// TODO(gkalpak): Investigate if it makes sense to share the code. + +import {isElement, matchesSelector} from './utils'; + +export function extractProjectableNodes(host: HTMLElement, ngContentSelectors: string[]): Node[][] { + const nodes = host.childNodes; + const projectableNodes: Node[][] = ngContentSelectors.map(() => []); + let wildcardIndex = -1; + + ngContentSelectors.some((selector, i) => { + if (selector === '*') { + wildcardIndex = i; + return true; + } + return false; + }); + + for (let i = 0, ii = nodes.length; i < ii; ++i) { + const node = nodes[i]; + const ngContentIndex = findMatchingIndex(node, ngContentSelectors, wildcardIndex); + + if (ngContentIndex !== -1) { + projectableNodes[ngContentIndex].push(node); + } + } + + return projectableNodes; +} + +function findMatchingIndex(node: Node, selectors: string[], defaultIndex: number): number { + let matchingIndex = defaultIndex; + + if (isElement(node)) { + selectors.some((selector, i) => { + if ((selector !== '*') && matchesSelector(node, selector)) { + matchingIndex = i; + return true; + } + return false; + }); + } + + return matchingIndex; +} diff --git a/packages/elements/test/extract-projectable-nodes_spec.ts b/packages/elements/test/extract-projectable-nodes_spec.ts new file mode 100644 index 0000000000..9d79760916 --- /dev/null +++ b/packages/elements/test/extract-projectable-nodes_spec.ts @@ -0,0 +1,83 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {extractProjectableNodes} from '../src/extract-projectable-nodes'; + +export function main() { + describe('extractProjectableNodes()', () => { + let elem: HTMLElement; + let childNodes: NodeList; + + const expectProjectableNodes = (matches: {[selector: string]: number[]}) => { + const selectors = Object.keys(matches); + const expected = selectors.map(selector => { + const matchingIndices = matches[selector]; + return matchingIndices.map(idx => childNodes[idx]); + }); + + expect(extractProjectableNodes(elem, selectors)).toEqual(expected); + }; + const test = (matches: {[selector: string]: number[]}) => () => expectProjectableNodes(matches); + + beforeEach(() => { + elem = document.createElement('div'); + elem.innerHTML = '