-
-
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)")
?