nl_tokens: Internal function to mutate string selectors into Nodes and validate that they are allowed .
pl_tokens: function ensureNodes ( parentNode , def ) { var adjacentNodes = [ ] var i , j , key , query , branch , boundNode , matchedNodes var adjacentNode , adjacentKey if ( typeof def !== 'object' ) throw new TypeError ( 'The second position must be an object.' ) for ( key in def ) { branch = def [ key ] // Change function or definition object bound to parent. if ( typeof branch === 'function' || ( typeof branch === 'object' && branch !== null && ! Array . isArray ( branch ) ) ) def [ key ] = branch = [ parentNode , branch ] // Cast CSS selector string to array. else if ( typeof branch === 'string' ) def [ key ] = branch = [ branch ] else if ( ! Array . isArray ( branch ) ) throw new TypeError ( 'The binding on key "' + key + '" is invalid.' ) // Dereference CSS selector string to actual DOM element. if ( typeof branch [ 0 ] === 'string' ) { query = branch [ 0 ] // Match all nodes for the selector, pick the first and remove the rest. matchedNodes = parentNode . querySelectorAll ( query ) if ( ! matchedNodes . length ) throw new Error ( 'An element for selector "' + <mask> + '" was not found.' ) for ( i = 1 , j = matchedNodes . length ; i < j ; i ++ ) matchedNodes [ i ] . parentNode . removeChild ( matchedNodes [ i ] ) branch [ 0 ] = matchedNodes [ 0 ] } else if ( ! branch [ 0 ] ) throw new TypeError ( 'The first position on key "' + key + '" must be a CSS selector string.' ) // Auto-detect template tag. if ( 'content' in branch [ 0 ] ) branch [ 0 ] = branch [ 0 ] . content boundNode = branch [ 0 ] if ( typeof branch [ 1 ] === 'object' && branch [ 1 ] !== null ) { Object . defineProperty ( branch , hasDefinitionKey , { value : true } ) if ( branch [ 2 ] && typeof branch [ 2 ] !== 'function' ) throw new TypeError ( 'The third position on key "' + key + '" must be a function.' ) } else if ( branch [ 1 ] && typeof branch [ 1 ] !== 'function' ) throw new TypeError ( 'The second position on key "' + key + '" must be an object or a function.' ) // Special case for binding to parent node. if ( parentNode === boundNode ) { Object . defineProperty ( branch , isBoundToParentKey , { value : true } ) if ( branch [ hasDefinitionKey ] ) ensureNodes ( boundNode , branch [ 1 ] ) else if ( typeof branch [ 1 ] === 'function' ) setReplaceAttribute ( branch , boundNode ) else console . warn ( // eslint-disable-line 'A change function was not defined on the key "' + key + '".' ) setProperties ( branch ) continue } adjacentNodes . push ( [ key , boundNode ] ) if ( ! parentNode . contains ( boundNode ) ) throw new Error ( 'The bound DOM element must be either ' + 'contained in or equal to the element in its parent binding.' ) if ( branch [ hasDefinitionKey ] ) { ensureNodes ( boundNode , branch [ 1 ] ) setProperties ( branch ) continue } setReplaceAttribute ( branch , boundNode ) setProperties ( branch ) } // Need to loop again to invalidate containment in adjacent nodes, after the // adjacent nodes are found. for ( key in def ) { boundNode = def [ key ] [ 0 ] for ( i = 0 , j = adjacentNodes . length ; i < j ; i ++ ) { adjacentKey = adjacentNodes [ i ] [ 0 ] adjacentNode = adjacentNodes [ i ] [ 1 ] if ( adjacentNode . contains ( boundNode ) && adjacentKey !== key ) throw new Error ( 'The element for key "' + key + '" is contained in the ' + 'element for the adjacent key "' + adjacentKey + '".' ) } } setProperties ( def ) }