Skip to content

Instantly share code, notes, and snippets.

@jcmoore
Last active August 29, 2015 14:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jcmoore/69a49f887e03c1d2bfa1 to your computer and use it in GitHub Desktop.
Save jcmoore/69a49f887e03c1d2bfa1 to your computer and use it in GitHub Desktop.
querySelector.js proposed patch for Polymer/polymer#629
// 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);
// 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