Mercurial > public > madeira
comparison media/django/js/getElementsBySelector.js @ 1:0dcfcdf50c62
Initial import of Madeira project from the private repository.
author | Brian Neal <bgneal@gmail.com> |
---|---|
date | Mon, 06 Apr 2009 03:10:59 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
0:df0370bfe3f0 | 1:0dcfcdf50c62 |
---|---|
1 /* document.getElementsBySelector(selector) | |
2 - returns an array of element objects from the current document | |
3 matching the CSS selector. Selectors can contain element names, | |
4 class names and ids and can be nested. For example: | |
5 | |
6 elements = document.getElementsBySelect('div#main p a.external') | |
7 | |
8 Will return an array of all 'a' elements with 'external' in their | |
9 class attribute that are contained inside 'p' elements that are | |
10 contained inside the 'div' element which has id="main" | |
11 | |
12 New in version 0.4: Support for CSS2 and CSS3 attribute selectors: | |
13 See http://www.w3.org/TR/css3-selectors/#attribute-selectors | |
14 | |
15 Version 0.4 - Simon Willison, March 25th 2003 | |
16 -- Works in Phoenix 0.5, Mozilla 1.3, Opera 7, Internet Explorer 6, Internet Explorer 5 on Windows | |
17 -- Opera 7 fails | |
18 */ | |
19 | |
20 function getAllChildren(e) { | |
21 // Returns all children of element. Workaround required for IE5/Windows. Ugh. | |
22 return e.all ? e.all : e.getElementsByTagName('*'); | |
23 } | |
24 | |
25 document.getElementsBySelector = function(selector) { | |
26 // Attempt to fail gracefully in lesser browsers | |
27 if (!document.getElementsByTagName) { | |
28 return new Array(); | |
29 } | |
30 // Split selector in to tokens | |
31 var tokens = selector.split(' '); | |
32 var currentContext = new Array(document); | |
33 for (var i = 0; i < tokens.length; i++) { | |
34 token = tokens[i].replace(/^\s+/,'').replace(/\s+$/,'');; | |
35 if (token.indexOf('#') > -1) { | |
36 // Token is an ID selector | |
37 var bits = token.split('#'); | |
38 var tagName = bits[0]; | |
39 var id = bits[1]; | |
40 var element = document.getElementById(id); | |
41 if (tagName && element.nodeName.toLowerCase() != tagName) { | |
42 // tag with that ID not found, return false | |
43 return new Array(); | |
44 } | |
45 // Set currentContext to contain just this element | |
46 currentContext = new Array(element); | |
47 continue; // Skip to next token | |
48 } | |
49 if (token.indexOf('.') > -1) { | |
50 // Token contains a class selector | |
51 var bits = token.split('.'); | |
52 var tagName = bits[0]; | |
53 var className = bits[1]; | |
54 if (!tagName) { | |
55 tagName = '*'; | |
56 } | |
57 // Get elements matching tag, filter them for class selector | |
58 var found = new Array; | |
59 var foundCount = 0; | |
60 for (var h = 0; h < currentContext.length; h++) { | |
61 var elements; | |
62 if (tagName == '*') { | |
63 elements = getAllChildren(currentContext[h]); | |
64 } else { | |
65 try { | |
66 elements = currentContext[h].getElementsByTagName(tagName); | |
67 } | |
68 catch(e) { | |
69 elements = []; | |
70 } | |
71 } | |
72 for (var j = 0; j < elements.length; j++) { | |
73 found[foundCount++] = elements[j]; | |
74 } | |
75 } | |
76 currentContext = new Array; | |
77 var currentContextIndex = 0; | |
78 for (var k = 0; k < found.length; k++) { | |
79 if (found[k].className && found[k].className.match(new RegExp('\\b'+className+'\\b'))) { | |
80 currentContext[currentContextIndex++] = found[k]; | |
81 } | |
82 } | |
83 continue; // Skip to next token | |
84 } | |
85 // Code to deal with attribute selectors | |
86 if (token.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/)) { | |
87 var tagName = RegExp.$1; | |
88 var attrName = RegExp.$2; | |
89 var attrOperator = RegExp.$3; | |
90 var attrValue = RegExp.$4; | |
91 if (!tagName) { | |
92 tagName = '*'; | |
93 } | |
94 // Grab all of the tagName elements within current context | |
95 var found = new Array; | |
96 var foundCount = 0; | |
97 for (var h = 0; h < currentContext.length; h++) { | |
98 var elements; | |
99 if (tagName == '*') { | |
100 elements = getAllChildren(currentContext[h]); | |
101 } else { | |
102 elements = currentContext[h].getElementsByTagName(tagName); | |
103 } | |
104 for (var j = 0; j < elements.length; j++) { | |
105 found[foundCount++] = elements[j]; | |
106 } | |
107 } | |
108 currentContext = new Array; | |
109 var currentContextIndex = 0; | |
110 var checkFunction; // This function will be used to filter the elements | |
111 switch (attrOperator) { | |
112 case '=': // Equality | |
113 checkFunction = function(e) { return (e.getAttribute(attrName) == attrValue); }; | |
114 break; | |
115 case '~': // Match one of space seperated words | |
116 checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('\\b'+attrValue+'\\b'))); }; | |
117 break; | |
118 case '|': // Match start with value followed by optional hyphen | |
119 checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('^'+attrValue+'-?'))); }; | |
120 break; | |
121 case '^': // Match starts with value | |
122 checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) == 0); }; | |
123 break; | |
124 case '$': // Match ends with value - fails with "Warning" in Opera 7 | |
125 checkFunction = function(e) { return (e.getAttribute(attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length); }; | |
126 break; | |
127 case '*': // Match ends with value | |
128 checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) > -1); }; | |
129 break; | |
130 default : | |
131 // Just test for existence of attribute | |
132 checkFunction = function(e) { return e.getAttribute(attrName); }; | |
133 } | |
134 currentContext = new Array; | |
135 var currentContextIndex = 0; | |
136 for (var k = 0; k < found.length; k++) { | |
137 if (checkFunction(found[k])) { | |
138 currentContext[currentContextIndex++] = found[k]; | |
139 } | |
140 } | |
141 // alert('Attribute Selector: '+tagName+' '+attrName+' '+attrOperator+' '+attrValue); | |
142 continue; // Skip to next token | |
143 } | |
144 // If we get here, token is JUST an element (not a class or ID selector) | |
145 tagName = token; | |
146 var found = new Array; | |
147 var foundCount = 0; | |
148 for (var h = 0; h < currentContext.length; h++) { | |
149 var elements = currentContext[h].getElementsByTagName(tagName); | |
150 for (var j = 0; j < elements.length; j++) { | |
151 found[foundCount++] = elements[j]; | |
152 } | |
153 } | |
154 currentContext = found; | |
155 } | |
156 return currentContext; | |
157 } | |
158 | |
159 /* That revolting regular expression explained | |
160 /^(\w+)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/ | |
161 \---/ \---/\-------------/ \-------/ | |
162 | | | | | |
163 | | | The value | |
164 | | ~,|,^,$,* or = | |
165 | Attribute | |
166 Tag | |
167 */ |