feat(elements): implement extractProjectableNodes()
				
					
				
			This commit is contained in:
		
							parent
							
								
									24f17f913a
								
							
						
					
					
						commit
						6b30fbf94e
					
				
							
								
								
									
										54
									
								
								packages/elements/src/extract-projectable-nodes.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								packages/elements/src/extract-projectable-nodes.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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; | ||||
| } | ||||
							
								
								
									
										83
									
								
								packages/elements/test/extract-projectable-nodes_spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								packages/elements/test/extract-projectable-nodes_spec.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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 = '<div class="foo" first="">' + | ||||
|           '<span class="bar"></span>' + | ||||
|           '</div>' + | ||||
|           '<span id="bar"></span>' + | ||||
|           '<!-- Comment -->' + | ||||
|           'Text' + | ||||
|           '<blink class="foo" id="quux"></blink>' + | ||||
|           'More text'; | ||||
|       childNodes = Array.prototype.slice.call(elem.childNodes); | ||||
|     }); | ||||
| 
 | ||||
|     it('should match each node to the corresponding selector', test({ | ||||
|          '[first]': [0], | ||||
|          '#bar': [1], | ||||
|          '#quux': [4], | ||||
|        })); | ||||
| 
 | ||||
|     it('should ignore non-matching nodes', test({ | ||||
|          '.zoo': [], | ||||
|        })); | ||||
| 
 | ||||
|     it('should only match top-level child nodes', test({ | ||||
|          'span': [1], | ||||
|          '.bar': [], | ||||
|        })); | ||||
| 
 | ||||
|     it('should support complex selectors', test({ | ||||
|          '.foo:not(div)': [4], | ||||
|          'div + #bar': [1], | ||||
|        })); | ||||
| 
 | ||||
|     it('should match each node with the first matching selector', test({ | ||||
|          'div': [0], | ||||
|          '.foo': [4], | ||||
|          'blink': [], | ||||
|        })); | ||||
| 
 | ||||
|     describe('(with wildcard selector)', () => { | ||||
|       it('should match non-element nodes to `*` (but still ignore comments)', test({ | ||||
|            'div,span,blink': [0, 1, 4], | ||||
|            '*': [2, 3, 5], | ||||
|          })); | ||||
| 
 | ||||
|       it('should match otherwise unmatched nodes to `*`', test({ | ||||
|            'div,blink': [0, 4], | ||||
|            '*': [1, 2, 3, 5], | ||||
|          })); | ||||
| 
 | ||||
|       it('should give higher priority to `*` (eve if it appears first)', test({ | ||||
|            '*': [2, 3, 5], | ||||
|            'div,span,blink': [0, 1, 4], | ||||
|          })); | ||||
|     }); | ||||
|   }); | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user