Last active
August 29, 2015 14:04
-
-
Save jcmoore/69a49f887e03c1d2bfa1 to your computer and use it in GitHub Desktop.
querySelector.js proposed patch for Polymer/polymer#629
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright 2013 The Polymer Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style | |
// license that can be found in the LICENSE file. | |
(function(scope) { | |
'use strict'; | |
var HTMLCollection = scope.wrappers.HTMLCollection; | |
var NodeList = scope.wrappers.NodeList; | |
var documentQuerySelector = window.documentQuerySelector = document.querySelector; | |
var elementQuerySelector = window.elementQuerySelector = document.documentElement.querySelector; | |
var documentQuerySelectorAll = window.documentQuerySelectorAll = document.querySelectorAll; | |
var elementQuerySelectorAll = window.elementQuerySelectorAll = document.documentElement.querySelectorAll; | |
var documentGetElementsByTagName = window.documentGetElementsByTagName = document.getElementsByTagName; | |
var elementGetElementsByTagName = window.elementGetElementsByTagName = document.documentElement.getElementsByTagName; | |
var documentGetElementsByTagNameNS = window.documentGetElementsByTagNameNS = document.getElementsByTagNameNS; | |
var elementGetElementsByTagNameNS = window.elementGetElementsByTagNameNS = document.documentElement.getElementsByTagNameNS; | |
var OriginalElement = window.Element; | |
var OriginalDocument = window.HTMLDocument; | |
function filterNodeList(list) { | |
if (list == null) | |
return list; | |
var wrapperList = new NodeList(); | |
var wrappedItem = null; | |
var index = 0; | |
for (var i = 0, length = list.length; i < length; i++) { | |
wrappedItem = wrap(list[i]); | |
if (!wrappedItem.treeScope_ || wrappedItem.treeScope_.parent === null) { | |
wrapperList[index++] = wrappedItem; | |
} | |
} | |
wrapperList.length = index; | |
return wrapperList; | |
} | |
function findOne(node, selector) { | |
var m, el = node.firstElementChild; | |
while (el) { | |
if (el.matches(selector)) | |
return el; | |
m = findOne(el, selector); | |
if (m) | |
return m; | |
el = el.nextElementSibling; | |
} | |
return null; | |
} | |
function matchesSelector(el, selector) { | |
return el.matches(selector); | |
} | |
var XHTML_NS = 'http://www.w3.org/1999/xhtml'; | |
function matchesTagName(el, localName, localNameLowerCase) { | |
var ln = el.localName; | |
return ln === localName || | |
ln === localNameLowerCase && el.namespaceURI === XHTML_NS; | |
} | |
function matchesEveryThing() { | |
return true; | |
} | |
function matchesLocalName(el, localName) { | |
return el.localName === localName; | |
} | |
function matchesNameSpace(el, ns) { | |
return el.namespaceURI === ns; | |
} | |
function matchesLocalNameNS(el, ns, localName) { | |
return el.namespaceURI === ns && el.localName === localName; | |
} | |
function findElements(node, result, p, arg0, arg1) { | |
var el = node.firstElementChild; | |
while (el) { | |
if (p(el, arg0, arg1)) | |
result[result.length++] = el; | |
findElements(el, result, p, arg0, arg1); | |
el = el.nextElementSibling; | |
} | |
return result; | |
} | |
// find and findAll will only match Simple Selectors, | |
// Structural Pseudo Classes are not guarenteed to be correct | |
// http://www.w3.org/TR/css3-selectors/#simple-selectors | |
var SelectorsInterface = { | |
querySelector: function(selector) { | |
var target = this.impl || this; | |
if (target instanceof OriginalElement) { | |
return wrap(elementQuerySelector.call(target, selector)); | |
} else if (target instanceof OriginalDocument) { | |
return wrap(documentQuerySelector.call(target, selector)); | |
} | |
return findOne(this, selector); | |
}, | |
querySelectorAll: function(selector) { | |
var target = this.impl || this; | |
if (target instanceof OriginalElement) { | |
return filterNodeList(elementQuerySelectorAll.call(target, selector)); | |
} else if (target instanceof OriginalDocument) { | |
return filterNodeList(documentQuerySelectorAll.call(target, selector)); | |
} | |
return findElements(this, new NodeList(), matchesSelector, selector); | |
} | |
}; | |
var GetElementsByInterface = { | |
getElementsByTagName: function(localName) { | |
var target = this.impl || this; | |
if (target instanceof OriginalElement) { | |
return filterNodeList(elementGetElementsByTagName.call(target, localName)); | |
} else if (target instanceof OriginalDocument) { | |
return filterNodeList(documentGetElementsByTagName.call(target, localName)); | |
} | |
var result = new HTMLCollection(); | |
if (localName === '*') | |
return findElements(this, result, matchesEveryThing); | |
return findElements(this, result, | |
matchesTagName, | |
localName, | |
localName.toLowerCase()); | |
}, | |
getElementsByClassName: function(className) { | |
// TODO(arv): Check className? | |
return this.querySelectorAll('.' + className); | |
}, | |
getElementsByTagNameNS: function(ns, localName) { | |
var target = this.impl || this; | |
if (target instanceof OriginalElement) { | |
return filterNodeList(elementGetElementsByTagNameNS.call(target, ns, localName)); | |
} else if (target instanceof OriginalDocument) { | |
return filterNodeList(documentGetElementsByTagNameNS.call(target, ns, localName)); | |
} | |
var result = new HTMLCollection(); | |
if (ns === '') { | |
ns = null; | |
} else if (ns === '*') { | |
if (localName === '*') | |
return findElements(this, result, matchesEveryThing); | |
return findElements(this, result, matchesLocalName, localName); | |
} | |
if (localName === '*') | |
return findElements(this, result, matchesNameSpace, ns); | |
return findElements(this, result, matchesLocalNameNS, ns, localName); | |
} | |
}; | |
scope.GetElementsByInterface = GetElementsByInterface; | |
scope.SelectorsInterface = SelectorsInterface; | |
})(window.ShadowDOMPolyfill); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright 2013 The Polymer Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style | |
// license that can be found in the LICENSE file. | |
(function(scope) { | |
'use strict'; | |
var HTMLCollection = scope.wrappers.HTMLCollection; | |
var NodeList = scope.wrappers.NodeList; | |
var wrap = scope.wrapIfNeeded; | |
var documentQuerySelector = document.querySelector; | |
var elementQuerySelector = document.documentElement.querySelector; | |
var documentQuerySelectorAll = document.querySelectorAll; | |
var elementQuerySelectorAll = document.documentElement.querySelectorAll; | |
var documentGetElementsByTagName = document.getElementsByTagName; | |
var elementGetElementsByTagName = document.documentElement.getElementsByTagName; | |
var documentGetElementsByTagNameNS = document.getElementsByTagNameNS; | |
var elementGetElementsByTagNameNS = document.documentElement.getElementsByTagNameNS; | |
var OriginalElement = window.Element; | |
var OriginalDocument = window.HTMLDocument; | |
var OriginalFragment = window.DocumentFragment; | |
function filterNodeList(list, recur, p, index, result, arg0, arg1) { | |
if (list == null) | |
return list; | |
var wrappedItem = null; | |
var root = null; | |
for (var i = 0, length = list.length; i < length; i++) { | |
wrappedItem = wrap(list[i]); | |
if (root = wrappedItem.treeScope_ && wrappedItem.treeScope_.root) { | |
if (root.impl instanceof OriginalFragment) { | |
continue; | |
} | |
} | |
result[index++] = wrappedItem; | |
index = filterNode(wrappedItem, recur, p, index, result, arg0, arg1); | |
} | |
return index; | |
} | |
function filterNode(node, recur, p, index, result, arg0, arg1) { | |
var el = null; | |
if (node.shadowRoot) { | |
el = node.firstElementChild; | |
while (el) { | |
if (p(el, arg0, arg1)) | |
result[index++] = el; | |
index = recur.call(el, p, index, result, arg0, arg1); | |
el = el.nextElementSibling; | |
} | |
} | |
return index; | |
} | |
function findOne(node, selector) { | |
var m, el = node.firstElementChild; | |
while (el) { | |
if (el.matches(selector)) | |
return el; | |
m = findOne(el, selector); | |
if (m) | |
return m; | |
el = el.nextElementSibling; | |
} | |
return null; | |
} | |
function matchesSelector(el, selector) { | |
return el.matches(selector); | |
} | |
var XHTML_NS = 'http://www.w3.org/1999/xhtml'; | |
function matchesTagName(el, localName, localNameLowerCase) { | |
var ln = el.localName; | |
return ln === localName || | |
ln === localNameLowerCase && el.namespaceURI === XHTML_NS; | |
} | |
function matchesEveryThing() { | |
return true; | |
} | |
function matchesLocalName(el, localName) { | |
return el.localName === localName; | |
} | |
function matchesLocalNameOnly(el, ns, localName) { | |
return el.localName === localName; | |
} | |
function matchesNameSpace(el, ns) { | |
return el.namespaceURI === ns; | |
} | |
function matchesLocalNameNS(el, ns, localName) { | |
return el.namespaceURI === ns && el.localName === localName; | |
} | |
function findElements(node, index, result, p, arg0, arg1) { | |
var el = node.firstElementChild; | |
while (el) { | |
if (p(el, arg0, arg1)) | |
result[index++] = el; | |
index = findElements(el, result, p, arg0, arg1); | |
el = el.nextElementSibling; | |
} | |
return index; | |
} | |
// find and findAll will only match Simple Selectors, | |
// Structural Pseudo Classes are not guarenteed to be correct | |
// http://www.w3.org/TR/css3-selectors/#simple-selectors | |
function querySelectorAllFiltered (match, index, result, selector) { | |
var target = this.impl || this; | |
var list = null; | |
if (target instanceof OriginalElement) { | |
list = elementQuerySelectorAll.call(target, selector); | |
} else if (target instanceof OriginalDocument) { | |
list = documentQuerySelectorAll.call(target, selector); | |
} else { | |
return findElements(this, index, result, match, selector); | |
} | |
index = filterNode(wrap(this), querySelectorAllFiltered, match, | |
index, | |
result, | |
selector, | |
null); | |
return filterNodeList(list, querySelectorAllFiltered, match, | |
index, | |
result, | |
selector, | |
null); | |
} | |
var SelectorsInterface = { | |
querySelector: function(selector) { | |
var target = this.impl || this; | |
if (target instanceof OriginalElement) { | |
return wrap(elementQuerySelector.call(target, selector)); | |
} else if (target instanceof OriginalDocument) { | |
return wrap(documentQuerySelector.call(target, selector)); | |
} | |
return findOne(this, selector); | |
}, | |
querySelectorAll: function(selector) { | |
var result = new NodeList(); | |
result.length = querySelectorAllFiltered.call(this, | |
matchesSelector, | |
0, | |
result, | |
selector); | |
return result; | |
} | |
}; | |
function getElementsByTagNameFiltered (match, index, result, localName, lowercase) { | |
var target = this.impl || this; | |
var collection = null; | |
if (target instanceof OriginalElement) { | |
collection = elementGetElementsByTagName.call(target, localName); | |
} else if (target instanceof OriginalDocument) { | |
collection = documentGetElementsByTagName.call(target, localName); | |
} else { | |
return findElements(this, index, result, | |
match, | |
localName, | |
lowercase); | |
} | |
index = filterNode(wrap(this), getElementsByTagNameFiltered, match, | |
index, | |
result, | |
localName, | |
lowercase); | |
return filterNodeList(collection, getElementsByTagNameFiltered, match, | |
index, | |
result, | |
localName, | |
lowercase); | |
} | |
function getElementsByTagNameNSFiltered (match, index, result, ns, localName) { | |
var target = this.impl || this; | |
var collection = null; | |
if (target instanceof OriginalElement) { | |
collection = elementGetElementsByTagNameNS.call(target, ns, localName); | |
} else if (target instanceof OriginalDocument) { | |
collection = documentGetElementsByTagNameNS.call(target, ns, localName); | |
} else { | |
return findElements(this, index, result, match, ns || null, localName); | |
} | |
index = filterNode(wrap(this), getElementsByTagNameNSFiltered, match, | |
index, | |
result, | |
ns, | |
localName); | |
return filterNodeList(collection, getElementsByTagNameNSFiltered, match, | |
index, | |
result, | |
ns, | |
localName); | |
} | |
var GetElementsByInterface = { | |
getElementsByTagName: function(localName) { | |
var result = new HTMLCollection(); | |
var match = (localName === '*') ? matchesEveryThing : matchesTagName; | |
result.length = getElementsByTagNameFiltered.call(this, | |
match, | |
0, | |
result, | |
localName, | |
localName.toLowerCase()); | |
return result; | |
}, | |
getElementsByClassName: function(className) { | |
// TODO(arv): Check className? | |
return this.querySelectorAll('.' + className); | |
}, | |
getElementsByTagNameNS: function(ns, localName) { | |
var result = new HTMLCollection(); | |
var match = null; | |
if (ns === '*') { | |
match = (localName === '*') ? matchesEveryThing : matchesLocalNameOnly; | |
} else { | |
match = (localName === '*') ? matchesNameSpace : matchesLocalNameNS; | |
} | |
result.length = getElementsByTagNameNSFiltered.call(this, | |
match, | |
0, | |
result, | |
ns, | |
localName); | |
return result; | |
} | |
}; | |
scope.GetElementsByInterface = GetElementsByInterface; | |
scope.SelectorsInterface = SelectorsInterface; | |
})(window.ShadowDOMPolyfill); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment