Created
December 10, 2011 22:16
-
-
Save patik/1456711 to your computer and use it in GitHub Desktop.
Customized Zepto for fake selectors
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
<!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> |
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
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 ... | |
// | |
})(); |
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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 :)