-
-
Save patik/1456711 to your computer and use it in GitHub Desktop.
| <!doctype html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <style> .hidden { display: none; } </style> | |
| <script src="zepto.custom.js"></script> | |
| <script> | |
| $(document).ready(function(e) { | |
| // This should print 2 results: #div3 and #div4 | |
| console.log("visible:", $("div:visible")); | |
| // This should print 3 results: #div1, #div2, and #div5 | |
| console.log("hidden:", $("div:hidden")); | |
| }); | |
| </script> | |
| </head> | |
| <body> | |
| <div class="hidden" id="div1"> | |
| <div id="div2"></div> | |
| </div> | |
| <div id="div3"></div> | |
| <div id="div4"> | |
| <div style="display:none;" id="div5"></div> | |
| </div> | |
| </body> | |
| </html> |
| var Zepto = (function() { | |
| // | |
| // ... snipped the Zepto code for brevity ... | |
| // | |
| // Custom selectors | |
| // Each method takes an array/list and returns an array of matching elements | |
| // Method names match the custom selector name (eg, hidden() is for :hidden) | |
| $.customSelectors = { | |
| hidden: function(elems) { | |
| var matches = [], len = elems.length, i = 0; | |
| while (i < len) { | |
| if ($.customSelectors.test.hidden(elems[i])) { | |
| matches.push(elems[i]); | |
| } | |
| i++; | |
| } | |
| return matches; | |
| }, | |
| visible: function(elems) { | |
| var matches = [], len = elems.length, i = 0; | |
| while (i < len) { | |
| if ($.customSelectors.test.visible(elems[i])) { | |
| matches.push(elems[i]); | |
| } | |
| i++; | |
| } | |
| return matches; | |
| }, | |
| // This contains the Boolean functions which test a single element | |
| // Which means you can't create a fake selector div:test unless you rename this... | |
| test: { | |
| // Pulled from jQuery and trimmed down to the basics | |
| hidden: function(elem) { | |
| var width = elem.offsetWidth, | |
| height = elem.offsetHeight; | |
| return (width === 0 && height === 0) || ((elem.style.display || $(elem).css("display")) === "none"); | |
| }, | |
| visible: function(elem) { | |
| return !$.customSelectors.test.hidden(elem); | |
| } | |
| } | |
| } | |
| $.qsa = $$ = function(element, selector) { | |
| var found, standard = "", custom = ""; | |
| // Look for a colon to indicate the presence of a custom selector | |
| if (selector && ~selector.indexOf(":")) { | |
| standard = selector.split(":")[0]; | |
| custom = selector.split(":")[1]; | |
| } | |
| if (custom.length && custom in $.customSelectors) { | |
| // First find all elements matching the non-custom selector(s) | |
| found = standard.length ? $$(element, standard) : $$(element); | |
| // Then filter that result by testing against the custom selector | |
| return $.customSelectors[custom](found); | |
| } | |
| else { | |
| // No function exists for this selector, so we can't perform a query | |
| return emptyArray; | |
| } | |
| } | |
| else { | |
| // This is the original, untouched code from $.qsa | |
| return (element === document && idSelectorRE.test(selector)) ? | |
| ( (found = element.getElementById(RegExp.$1)) ? [found] : emptyArray ) : | |
| slice.call( | |
| classSelectorRE.test(selector) ? element.getElementsByClassName(RegExp.$1) : | |
| tagSelectorRE.test(selector) ? element.getElementsByTagName(selector) : | |
| element.querySelectorAll(selector) | |
| ); | |
| } | |
| } | |
| // ... futher down ... | |
| $.fn = { | |
| // ... functions snipped for brevity ... | |
| filter: function(selector){ | |
| return $([].filter.call(this, function(element){ | |
| var custom = ""; | |
| // Look for a colon to indicate the presence of a custom selector | |
| if (selector && ~selector.indexOf(":")) { | |
| custom = selector.split(":")[1]; | |
| } | |
| if (custom.length && custom in $.customSelectors.test) { | |
| return $.customSelectors.test[custom](element); | |
| } | |
| else { | |
| return element.parentNode && $$(element.parentNode, selector).indexOf(element) >= 0; | |
| } | |
| })); | |
| }, | |
| // ... the rest of $.fn | |
| }; | |
| // | |
| // ... the rest of the Zepto code snipped for brevity ... | |
| // | |
| })(); |
Actually I wanted to avoid that initial if() clause entirely unless the part after the colon was a defined custom selector. (That's why I threw in the check for :not, the only pseudo-class that came to mind at the moment.)
I updated the code so it will use the native qsa for :nth-child, :not, and any other real pseudo-class. I also added code for modifying $.fn.filter so that you can do things like $("div").is(":hidden").
BTW, the fact that I am repeating myself in the $.qsa and $.fn.filter functions is another BIG RED FLAG that this code is inefficient and not for production use :)
I have a pull open in Zepto that creates a function that checks whether or not an element matches a selector(using the speedy native matchesSelector), if that gets accepted that would probably be a good spot to put code like this
I'm not sure you should return an empty array if the custom selector doesn't exist, what if you run
$("div:nth-child(2)")?