Skip to content

Commit

Permalink
experimental support for jQuery CSS pseudo-selectors
Browse files Browse the repository at this point in the history
  • Loading branch information
mislav authored and lopper committed Apr 24, 2013
1 parent d5e54e4 commit 96aad6f
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 0 deletions.
10 changes: 10 additions & 0 deletions README.md
Expand Up @@ -124,6 +124,16 @@ href="https://github.com/madrobby/zepto/blob/master/src/data.js#files">data</a><
objects in memory.
</td>
</tr>
<tr>
<th><a
href="https://github.com/madrobby/zepto/blob/master/src/selector.js#files">selector</a></th>
<td></td>
<td>
Experimental <a href="http://api.jquery.com/category/selectors/jquery-selector-extensions/">jQuery
CSS extensions</a> support for functionality such as <code>$('div:first')</code> and
<code>el.is(':visible')</code>.
</td>
</tr>
<tr>
<th><a href="https://github.com/madrobby/zepto/blob/master/src/touch.js#files">touch</a></th>
<td>✔</td>
Expand Down
62 changes: 62 additions & 0 deletions src/selector.js
@@ -0,0 +1,62 @@
;(function($){
var zepto = $.zepto, oldQsa = zepto.qsa, oldMatches = zepto.matches

function visible(elem){
elem = $(elem)
return !!(elem.width() || elem.height()) && elem.css("display") !== "none"
}

// Implements a subset from:
// http://api.jquery.com/category/selectors/jquery-selector-extensions/
//
// Complex selectors are not supported:
// li:has(label:contains("foo")) + li:has(label:contains("bar"))
// "> h2"
// ul.inner:first > li
var filters = {
visible: function(){ return visible(this) },
hidden: function(){ return !visible(this) },
selected: function(){ return this.selected },
checked: function(){ return this.checked },
first: function(idx){ return idx === 0 },
eq: function(idx, value){ return idx === value },
contains: function(idx, text){ return $(this).text().indexOf(text) > -1 },
has: function(idx, sel){ return zepto.qsa(this, sel).length }
}

var re = new RegExp('(.*):(\\w+)(?:\\(([^)]+)\\))?$\\s*')

function process(sel, fn) {
var filter, arg, match = sel.match(re)
if (match && match[2] in filters) {
var filter = filters[match[2]], arg = match[3]
sel = match[1]
if (arg) {
var num = Number(arg)
if (isNaN(num)) arg = arg.replace(/^["']|["']$/g, '')
else arg = num
}
}
return fn(sel, filter, arg)
}

zepto.qsa = function(node, selector) {
return process(selector, function(sel, filter, arg){
try {
if (!sel && filter) sel = '*'
var nodes = oldQsa(node, sel)
} catch(e) {
console.error('error performing selector: %o', selector)
throw e
}
return !filter ? nodes : nodes.filter(function(el, i){ return filter.call(el, i, arg) })
})
}

zepto.matches = function(node, selector){
return process(selector, function(sel, filter, arg){
return (!sel || oldMatches(node, sel)) &&
(!filter || filter.call(node, null, arg))
})
}
})(Zepto)
50 changes: 50 additions & 0 deletions test/selector.html
@@ -0,0 +1,50 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="stylesheet" href="test.css">
<title>Zepto selector tests</title>
<script src="../vendor/evidence.js"></script>
<script src="evidence_runner.js"></script>
<script src="../src/polyfill.js"></script>
<script src="../src/zepto.js"></script>
<script src="../src/selector.js"></script>
</head>
<body>
<h1>Zepto selector tests</h1>
<p id="results">
Running… see browser console for results
</p>
<div id="fixtures">
<ul id=list><li>one</li><li>two</li><ul>
<div class=visibility id=vis>look at me!</div>
<div class=visibility id=invis style="display:none">can't see me</div>
</div><!-- fixtures -->

<script>
(function(){
Evidence('ZeptoTest', {
testFirst: function(t) {
var li = $('#list li:first')
t.assertEqual(1, li.size())
t.assertEqual('one', li.text())
t.assertEqual('two', $('#list li:eq(1)').text())
},
testContains: function(t) {
t.assertEqual('two', $('#list li:contains("two")').text())
},
testVisibility: function(t) {
t.assertEqual('vis', $('.visibility:visible').attr('id'))
t.assertEqual('invis', $('.visibility:hidden').attr('id'))
},
testIs: function(t) {
t.assert($('#list').is('ul'))
t.assert($('#vis').is(':visible'))
t.refute($('#invis').is(':visible'))
}
})
})()
</script>
</body>
</html>

0 comments on commit 96aad6f

Please sign in to comment.