| OLD | NEW |
| (Empty) | |
| 1 <!-- |
| 2 @license |
| 3 Copyright (c) 2017 The Polymer Project Authors. All rights reserved. |
| 4 This code may only be used under the BSD style license found at http://polymer.g
ithub.io/LICENSE.txt |
| 5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt |
| 6 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS.txt |
| 7 Code distributed by Google as part of the polymer project is also |
| 8 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS.txt |
| 9 --> |
| 10 <link rel="import" href="../utils/boot.html"> |
| 11 <link rel="import" href="../utils/flattened-nodes-observer.html"> |
| 12 <link rel="import" href="../utils/flush.html"> |
| 13 <script> |
| 14 (function() { |
| 15 'use strict'; |
| 16 |
| 17 const p = Element.prototype; |
| 18 const normalizedMatchesSelector = p.matches || p.matchesSelector || |
| 19 p.mozMatchesSelector || p.msMatchesSelector || |
| 20 p.oMatchesSelector || p.webkitMatchesSelector; |
| 21 |
| 22 /** |
| 23 * Cross-platform `element.matches` shim. |
| 24 * |
| 25 * @function matchesSelector |
| 26 * @memberof Polymer.dom |
| 27 * @param {Node} node Node to check selector against |
| 28 * @param {string} selector Selector to match |
| 29 * @return {boolean} True if node matched selector |
| 30 */ |
| 31 const matchesSelector = function(node, selector) { |
| 32 return normalizedMatchesSelector.call(node, selector); |
| 33 } |
| 34 |
| 35 /** |
| 36 * Node API wrapper class returned from `Polymer.dom.(target)` when |
| 37 * `target` is a `Node`. |
| 38 */ |
| 39 class DomApi { |
| 40 |
| 41 constructor(node) { |
| 42 this.node = node; |
| 43 } |
| 44 |
| 45 /** |
| 46 * Returns an instance of `Polymer.FlattenedNodesObserver` that |
| 47 * listens for node changes on this element. |
| 48 * |
| 49 * @param {Function} callback Called when direct or distributed children |
| 50 * of this element changes |
| 51 * @return {Polymer.FlattenedNodesObserver} Observer instance |
| 52 */ |
| 53 observeNodes(callback) { |
| 54 return new Polymer.FlattenedNodesObserver(this.node, callback); |
| 55 } |
| 56 |
| 57 /** |
| 58 * Disconnects an observer previously created via `observeNodes` |
| 59 * |
| 60 * @param {Polymer.FlattenedNodesObserver} observerHandle Observer instance |
| 61 * to disconnect. |
| 62 */ |
| 63 unobserveNodes(observerHandle) { |
| 64 observerHandle.disconnect(); |
| 65 } |
| 66 |
| 67 /** |
| 68 * Provided as a backwards-compatible API only. This method does nothing. |
| 69 */ |
| 70 notifyObserver() {} |
| 71 |
| 72 /** |
| 73 * Returns true if the provided node is contained with this element's |
| 74 * light-DOM children or shadow root, including any nested shadow roots |
| 75 * of children therein. |
| 76 * |
| 77 * @param {Node} node Node to test |
| 78 * @return {boolean} Returns true if the given `node` is contained within |
| 79 * this element's light or shadow DOM. |
| 80 */ |
| 81 deepContains(node) { |
| 82 if (this.node.contains(node)) { |
| 83 return true; |
| 84 } |
| 85 let n = node; |
| 86 let doc = node.ownerDocument; |
| 87 // walk from node to `this` or `document` |
| 88 while (n && n !== doc && n !== this.node) { |
| 89 // use logical parentnode, or native ShadowRoot host |
| 90 n = n.parentNode || n.host; |
| 91 } |
| 92 return n === this.node; |
| 93 } |
| 94 |
| 95 /** |
| 96 * Returns the root node of this node. Equivalent to `getRoodNode()`. |
| 97 * |
| 98 * @return {Node} Top most element in the dom tree in which the node |
| 99 * exists. If the node is connected to a document this is either a |
| 100 * shadowRoot or the document; otherwise, it may be the node |
| 101 * itself or a node or document fragment containing it. |
| 102 */ |
| 103 getOwnerRoot() { |
| 104 return this.node.getRootNode(); |
| 105 } |
| 106 |
| 107 /** |
| 108 * For slot elements, returns the nodes assigned to the slot; otherwise |
| 109 * an empty array. It is equivalent to `<slot>.addignedNodes({flatten:true})
`. |
| 110 * |
| 111 * @return {Array<Node>} Array of assigned nodes |
| 112 */ |
| 113 getDistributedNodes() { |
| 114 return (this.node.localName === 'slot') ? |
| 115 this.node.assignedNodes({flatten: true}) : |
| 116 []; |
| 117 } |
| 118 |
| 119 /** |
| 120 * Returns an array of all slots this element was distributed to. |
| 121 * |
| 122 * @return {Array<HTMLSlotElement>} Description |
| 123 */ |
| 124 getDestinationInsertionPoints() { |
| 125 let ip$ = []; |
| 126 let n = this.node.assignedSlot; |
| 127 while (n) { |
| 128 ip$.push(n); |
| 129 n = n.assignedSlot; |
| 130 } |
| 131 return ip$; |
| 132 } |
| 133 |
| 134 /** |
| 135 * Calls `importNode` on the `ownerDocument` for this node. |
| 136 * |
| 137 * @param {Node} node Node to import |
| 138 * @param {boolean} deep True if the node should be cloned deeply during |
| 139 * import |
| 140 * @return {Node} Clone of given node imported to this owner document |
| 141 */ |
| 142 importNode(node, deep) { |
| 143 let doc = this.node instanceof Document ? this.node : |
| 144 this.node.ownerDocument; |
| 145 return doc.importNode(node, deep); |
| 146 } |
| 147 |
| 148 /** |
| 149 * Returns a flattened list of all child nodes and nodes distributed |
| 150 * to child slots. |
| 151 * |
| 152 * @return {type} Description |
| 153 */ |
| 154 getEffectiveChildNodes() { |
| 155 return Polymer.FlattenedNodesObserver.getFlattenedNodes(this.node); |
| 156 } |
| 157 |
| 158 /** |
| 159 * Returns a filtered list of flattened child elements for this element base
d |
| 160 * on the given selector. |
| 161 * |
| 162 * @param {string} selector Selector to filter nodes against |
| 163 * @return {Array<HTMLElement>} List of flattened child elements |
| 164 */ |
| 165 queryDistributedElements(selector) { |
| 166 let c$ = this.getEffectiveChildNodes(); |
| 167 let list = []; |
| 168 for (let i=0, l=c$.length, c; (i<l) && (c=c$[i]); i++) { |
| 169 if ((c.nodeType === Node.ELEMENT_NODE) && |
| 170 matchesSelector(c, selector)) { |
| 171 list.push(c); |
| 172 } |
| 173 } |
| 174 return list; |
| 175 } |
| 176 |
| 177 /** |
| 178 * For shadow roots, returns the currently focused element within this |
| 179 * shadow root. |
| 180 * |
| 181 * @return {Node|undefined} Currently focused element |
| 182 */ |
| 183 get activeElement() { |
| 184 let node = this.node; |
| 185 return node._activeElement !== undefined ? node._activeElement : node.acti
veElement; |
| 186 } |
| 187 } |
| 188 |
| 189 function forwardMethods(proto, methods) { |
| 190 for (let i=0; i < methods.length; i++) { |
| 191 let method = methods[i]; |
| 192 proto[method] = function() { |
| 193 return this.node[method].apply(this.node, arguments); |
| 194 } |
| 195 } |
| 196 } |
| 197 |
| 198 function forwardReadOnlyProperties(proto, properties) { |
| 199 for (let i=0; i < properties.length; i++) { |
| 200 let name = properties[i]; |
| 201 Object.defineProperty(proto, name, { |
| 202 get: function() { |
| 203 return this.node[name]; |
| 204 }, |
| 205 configurable: true |
| 206 }); |
| 207 } |
| 208 } |
| 209 |
| 210 function forwardProperties(proto, properties) { |
| 211 for (let i=0; i < properties.length; i++) { |
| 212 let name = properties[i]; |
| 213 Object.defineProperty(proto, name, { |
| 214 get: function() { |
| 215 return this.node[name]; |
| 216 }, |
| 217 set: function(value) { |
| 218 this.node[name] = value; |
| 219 }, |
| 220 configurable: true |
| 221 }); |
| 222 } |
| 223 } |
| 224 |
| 225 forwardMethods(DomApi.prototype, [ |
| 226 'cloneNode', 'appendChild', 'insertBefore', 'removeChild', |
| 227 'replaceChild', 'setAttribute', 'removeAttribute', |
| 228 'querySelector', 'querySelectorAll' |
| 229 ]); |
| 230 |
| 231 forwardReadOnlyProperties(DomApi.prototype, [ |
| 232 'parentNode', 'firstChild', 'lastChild', |
| 233 'nextSibling', 'previousSibling', 'firstElementChild', |
| 234 'lastElementChild', 'nextElementSibling', 'previousElementSibling', |
| 235 'childNodes', 'children', 'classList' |
| 236 ]); |
| 237 |
| 238 forwardProperties(DomApi.prototype, [ |
| 239 'textContent', 'innerHTML' |
| 240 ]); |
| 241 |
| 242 |
| 243 /** |
| 244 * Event API wrapper class returned from `Polymer.dom.(target)` when |
| 245 * `target` is an `Event`. |
| 246 */ |
| 247 class EventApi { |
| 248 constructor(event) { |
| 249 this.event = event; |
| 250 } |
| 251 |
| 252 /** |
| 253 * Returns the first node on the `composedPath` of this event. |
| 254 * |
| 255 * @return {Node} The node this event was dispatched to |
| 256 */ |
| 257 get rootTarget() { |
| 258 return this.event.composedPath()[0]; |
| 259 } |
| 260 |
| 261 /** |
| 262 * Returns the local (re-targeted) target for this event. |
| 263 * |
| 264 * @return {Node} The local (re-targeted) target for this event. |
| 265 */ |
| 266 get localTarget() { |
| 267 return this.event.target; |
| 268 } |
| 269 |
| 270 /** |
| 271 * Returns the `composedPath` for this event. |
| 272 */ |
| 273 get path() { |
| 274 return this.event.composedPath(); |
| 275 } |
| 276 } |
| 277 |
| 278 /** |
| 279 * Legacy DOM and Event manipulation API wrapper factory used to abstract |
| 280 * differences between native Shadow DOM and "Shady DOM" when polyfilling on |
| 281 * older browsers. |
| 282 * |
| 283 * Note that in Polymer 2.x use of `Polymer.dom` is no longer required and |
| 284 * in the majority of cases simply facades directly to the standard native |
| 285 * API. |
| 286 * |
| 287 * @namespace |
| 288 * @summary Legacy DOM and Event manipulation API wrapper factory used to |
| 289 * abstract differences between native Shadow DOM and "Shady DOM." |
| 290 * @memberof Polymer |
| 291 * @param {Node|Event} obj Node or event to operate on |
| 292 * @return {DomApi|EventApi} Wrapper providing either node API or event API |
| 293 */ |
| 294 Polymer.dom = function(obj) { |
| 295 obj = obj || document; |
| 296 let ctor = obj instanceof Event ? EventApi : DomApi; |
| 297 if (!obj.__domApi) { |
| 298 obj.__domApi = new ctor(obj); |
| 299 } |
| 300 return obj.__domApi; |
| 301 }; |
| 302 |
| 303 Polymer.dom.matchesSelector = matchesSelector; |
| 304 |
| 305 /** |
| 306 * Forces several classes of asynchronously queued tasks to flush: |
| 307 * - Debouncers added via `Polymer.enqueueDebouncer` |
| 308 * - ShadyDOM distribution |
| 309 * |
| 310 * This method facades to `Polymer.flush`. |
| 311 * |
| 312 * @memberof Polymer.dom |
| 313 */ |
| 314 Polymer.dom.flush = Polymer.flush; |
| 315 |
| 316 /** |
| 317 * Adds a `Polymer.Debouncer` to a list of globally flushable tasks. |
| 318 * |
| 319 * This method facades to `Polymer.enqueueDebouncer`. |
| 320 * |
| 321 * @memberof Polymer.dom |
| 322 * @param {Polymer.Debouncer} debouncer Debouncer to enqueue |
| 323 */ |
| 324 Polymer.dom.addDebouncer = Polymer.enqueueDebouncer; |
| 325 |
| 326 // expose BC settings. |
| 327 let settings = Polymer.Settings || {}; |
| 328 settings.useShadow = !(window.ShadyDOM); |
| 329 settings.useNativeCSSProperties = |
| 330 Boolean(!window.ShadyCSS || window.ShadyCSS.nativeCss); |
| 331 settings.useNativeCustomElements = |
| 332 !(window.customElements.polyfillWrapFlushCallback); |
| 333 Polymer.Settings = settings; |
| 334 |
| 335 })(); |
| 336 </script> |
| OLD | NEW |