1/* 2 Behaviour v1.1 by Ben Nolan, June 2005. Based largely on the work 3 of Simon Willison (see comments by Simon below). 4 5 Description: 6 7 Uses css selectors to apply javascript behaviours to enable 8 unobtrusive javascript in html documents. 9 10 Usage: 11 12 var myrules = { 13 'b.someclass' : function(element){ 14 element.onclick = function(){ 15 alert(this.innerHTML); 16 } 17 }, 18 '#someid u' : function(element){ 19 element.onmouseover = function(){ 20 this.innerHTML = "BLAH!"; 21 } 22 } 23 }; 24 25 Behaviour.register(myrules); 26 27 // Call Behaviour.apply() to re-apply the rules (if you 28 // update the dom, etc). 29 30 License: 31 32 This file is entirely BSD licensed. 33 34 More information: 35 36 http://ripcord.co.nz/behaviour/ 37 38*/ 39 40var Behaviour = { 41 list : new Array, 42 43 register : function(sheet){ 44 Behaviour.list.push(sheet); 45 }, 46 47 start : function(){ 48 Behaviour.addLoadEvent(function(){ 49 Behaviour.apply(); 50 }); 51 }, 52 53 apply : function(){ 54 for (h=0;sheet=Behaviour.list[h];h++){ 55 for (selector in sheet){ 56 list = document.getElementsBySelector(selector); 57 58 if (!list){ 59 continue; 60 } 61 62 for (i=0;element=list[i];i++){ 63 sheet[selector](element); 64 } 65 } 66 } 67 }, 68 69 addLoadEvent : function(func){ 70 var oldonload = window.onload; 71 72 if (typeof window.onload != 'function') { 73 window.onload = func; 74 } else { 75 window.onload = function() { 76 oldonload(); 77 func(); 78 } 79 } 80 } 81} 82 83Behaviour.start(); 84 85/* 86 The following code is Copyright (C) Simon Willison 2004. 87 88 document.getElementsBySelector(selector) 89 - returns an array of element objects from the current document 90 matching the CSS selector. Selectors can contain element names, 91 class names and ids and can be nested. For example: 92 93 elements = document.getElementsBySelect('div#main p a.external') 94 95 Will return an array of all 'a' elements with 'external' in their 96 class attribute that are contained inside 'p' elements that are 97 contained inside the 'div' element which has id="main" 98 99 New in version 0.4: Support for CSS2 and CSS3 attribute selectors: 100 See http://www.w3.org/TR/css3-selectors/#attribute-selectors 101 102 Version 0.4 - Simon Willison, March 25th 2003 103 -- Works in Phoenix 0.5, Mozilla 1.3, Opera 7, Internet Explorer 6, Internet Explorer 5 on Windows 104 -- Opera 7 fails 105*/ 106 107function getAllChildren(e) { 108 // Returns all children of element. Workaround required for IE5/Windows. Ugh. 109 return e.all ? e.all : e.getElementsByTagName('*'); 110} 111 112document.getElementsBySelector = function(selector) { 113 // Attempt to fail gracefully in lesser browsers 114 if (!document.getElementsByTagName) { 115 return new Array(); 116 } 117 // Split selector in to tokens 118 var tokens = selector.split(' '); 119 var currentContext = new Array(document); 120 for (var i = 0; i < tokens.length; i++) { 121 token = tokens[i].replace(/^\s+/,'').replace(/\s+$/,'');; 122 if (token.indexOf('#') > -1) { 123 // Token is an ID selector 124 var bits = token.split('#'); 125 var tagName = bits[0]; 126 var id = bits[1]; 127 var element = document.getElementById(id); 128 if (tagName && element.nodeName.toLowerCase() != tagName) { 129 // tag with that ID not found, return false 130 return new Array(); 131 } 132 // Set currentContext to contain just this element 133 currentContext = new Array(element); 134 continue; // Skip to next token 135 } 136 if (token.indexOf('.') > -1) { 137 // Token contains a class selector 138 var bits = token.split('.'); 139 var tagName = bits[0]; 140 var className = bits[1]; 141 if (!tagName) { 142 tagName = '*'; 143 } 144 // Get elements matching tag, filter them for class selector 145 var found = new Array; 146 var foundCount = 0; 147 for (var h = 0; h < currentContext.length; h++) { 148 var elements; 149 if (tagName == '*') { 150 elements = getAllChildren(currentContext[h]); 151 } else { 152 elements = currentContext[h].getElementsByTagName(tagName); 153 } 154 for (var j = 0; j < elements.length; j++) { 155 found[foundCount++] = elements[j]; 156 } 157 } 158 currentContext = new Array; 159 var currentContextIndex = 0; 160 for (var k = 0; k < found.length; k++) { 161 if (found[k].className && found[k].className.match(new RegExp('\\b'+className+'\\b'))) { 162 currentContext[currentContextIndex++] = found[k]; 163 } 164 } 165 continue; // Skip to next token 166 } 167 // Code to deal with attribute selectors 168 if (token.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/)) { 169 var tagName = RegExp.$1; 170 var attrName = RegExp.$2; 171 var attrOperator = RegExp.$3; 172 var attrValue = RegExp.$4; 173 if (!tagName) { 174 tagName = '*'; 175 } 176 // Grab all of the tagName elements within current context 177 var found = new Array; 178 var foundCount = 0; 179 for (var h = 0; h < currentContext.length; h++) { 180 var elements; 181 if (tagName == '*') { 182 elements = getAllChildren(currentContext[h]); 183 } else { 184 elements = currentContext[h].getElementsByTagName(tagName); 185 } 186 for (var j = 0; j < elements.length; j++) { 187 found[foundCount++] = elements[j]; 188 } 189 } 190 currentContext = new Array; 191 var currentContextIndex = 0; 192 var checkFunction; // This function will be used to filter the elements 193 switch (attrOperator) { 194 case '=': // Equality 195 checkFunction = function(e) { return (e.getAttribute(attrName) == attrValue); }; 196 break; 197 case '~': // Match one of space seperated words 198 checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('\\b'+attrValue+'\\b'))); }; 199 break; 200 case '|': // Match start with value followed by optional hyphen 201 checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('^'+attrValue+'-?'))); }; 202 break; 203 case '^': // Match starts with value 204 checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) == 0); }; 205 break; 206 case '$': // Match ends with value - fails with "Warning" in Opera 7 207 checkFunction = function(e) { return (e.getAttribute(attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length); }; 208 break; 209 case '*': // Match ends with value 210 checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) > -1); }; 211 break; 212 default : 213 // Just test for existence of attribute 214 checkFunction = function(e) { return e.getAttribute(attrName); }; 215 } 216 currentContext = new Array; 217 var currentContextIndex = 0; 218 for (var k = 0; k < found.length; k++) { 219 if (checkFunction(found[k])) { 220 currentContext[currentContextIndex++] = found[k]; 221 } 222 } 223 // alert('Attribute Selector: '+tagName+' '+attrName+' '+attrOperator+' '+attrValue); 224 continue; // Skip to next token 225 } 226 227 if (!currentContext[0]){ 228 return; 229 } 230 231 // If we get here, token is JUST an element (not a class or ID selector) 232 tagName = token; 233 var found = new Array; 234 var foundCount = 0; 235 for (var h = 0; h < currentContext.length; h++) { 236 var elements = currentContext[h].getElementsByTagName(tagName); 237 for (var j = 0; j < elements.length; j++) { 238 found[foundCount++] = elements[j]; 239 } 240 } 241 currentContext = found; 242 } 243 return currentContext; 244} 245
246/* That revolting regular expression explained 247/^(\w+)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/ 248 \---/ \---/\-------------/ \-------/ 249 | | | | 250 | | | The value 251 | | ~,|,^,$,* or = 252 | Attribute 253 Tag 254*/
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.