jazz/ActiveMQ/08-10-27: behaviour.js

File behaviour.js, 7.7 KB (added by jazz, 16 years ago)
Line 
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 (var 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 (var 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    if (typeof window.onload != 'function') {
72      window.onload = func;
73    } else {
74      window.onload = function() {
75        oldonload();
76        if(func != null) {
77           func();
78        }
79      }
80    }
81  }
82}
83
84Behaviour.start();
85
86/*
87   The following code is Copyright (C) Simon Willison 2004.
88
89   document.getElementsBySelector(selector)
90   - returns an array of element objects from the current document
91     matching the CSS selector. Selectors can contain element names,
92     class names and ids and can be nested. For example:
93     
94       elements = document.getElementsBySelect('div#main p a.external')
95     
96     Will return an array of all 'a' elements with 'external' in their
97     class attribute that are contained inside 'p' elements that are
98     contained inside the 'div' element which has id="main"
99
100   New in version 0.4: Support for CSS2 and CSS3 attribute selectors:
101   See http://www.w3.org/TR/css3-selectors/#attribute-selectors
102
103   Version 0.4 - Simon Willison, March 25th 2003
104   -- Works in Phoenix 0.5, Mozilla 1.3, Opera 7, Internet Explorer 6, Internet Explorer 5 on Windows
105   -- Opera 7 fails
106*/
107
108function getAllChildren(e) {
109  // Returns all children of element. Workaround required for IE5/Windows. Ugh.
110  return e.all ? e.all : e.getElementsByTagName('*');
111}
112
113document.getElementsBySelector = function(selector) {
114  // Attempt to fail gracefully in lesser browsers
115  if (!document.getElementsByTagName) {
116    return new Array();
117  }
118  // Split selector in to tokens
119  var tokens = selector.split(' ');
120  var currentContext = new Array(document);
121  for (var i = 0; i < tokens.length; i++) {
122    token = tokens[i].replace(/^\s+/,'').replace(/\s+$/,'');;
123    if (token.indexOf('#') > -1) {
124      // Token is an ID selector
125      var bits = token.split('#');
126      var tagName = bits[0];
127      var id = bits[1];
128      var element = document.getElementById(id);
129      if (tagName && element.nodeName.toLowerCase() != tagName) {
130        // tag with that ID not found, return false
131        return new Array();
132      }
133      // Set currentContext to contain just this element
134      currentContext = new Array(element);
135      continue; // Skip to next token
136    }
137    if (token.indexOf('.') > -1) {
138      // Token contains a class selector
139      var bits = token.split('.');
140      var tagName = bits[0];
141      var className = bits[1];
142      if (!tagName) {
143        tagName = '*';
144      }
145      // Get elements matching tag, filter them for class selector
146      var found = new Array;
147      var foundCount = 0;
148      for (var h = 0; h < currentContext.length; h++) {
149        var elements;
150        if (tagName == '*') {
151            elements = getAllChildren(currentContext[h]);
152        } else {
153            elements = currentContext[h].getElementsByTagName(tagName);
154        }
155        for (var j = 0; j < elements.length; j++) {
156          found[foundCount++] = elements[j];
157        }
158      }
159      currentContext = new Array;
160      var currentContextIndex = 0;
161      for (var k = 0; k < found.length; k++) {
162        if (found[k].className && found[k].className.match(new RegExp('\\b'+className+'\\b'))) {
163          currentContext[currentContextIndex++] = found[k];
164        }
165      }
166      continue; // Skip to next token
167    }
168    // Code to deal with attribute selectors
169    if (token.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/)) {
170      var tagName = RegExp.$1;
171      var attrName = RegExp.$2;
172      var attrOperator = RegExp.$3;
173      var attrValue = RegExp.$4;
174      if (!tagName) {
175        tagName = '*';
176      }
177      // Grab all of the tagName elements within current context
178      var found = new Array;
179      var foundCount = 0;
180      for (var h = 0; h < currentContext.length; h++) {
181        var elements;
182        if (tagName == '*') {
183            elements = getAllChildren(currentContext[h]);
184        } else {
185            elements = currentContext[h].getElementsByTagName(tagName);
186        }
187        for (var j = 0; j < elements.length; j++) {
188          found[foundCount++] = elements[j];
189        }
190      }
191      currentContext = new Array;
192      var currentContextIndex = 0;
193      var checkFunction; // This function will be used to filter the elements
194      switch (attrOperator) {
195        case '=': // Equality
196          checkFunction = function(e) { return (e.getAttribute(attrName) == attrValue); };
197          break;
198        case '~': // Match one of space seperated words
199          checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('\\b'+attrValue+'\\b'))); };
200          break;
201        case '|': // Match start with value followed by optional hyphen
202          checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('^'+attrValue+'-?'))); };
203          break;
204        case '^': // Match starts with value
205          checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) == 0); };
206          break;
207        case '$': // Match ends with value - fails with "Warning" in Opera 7
208          checkFunction = function(e) { return (e.getAttribute(attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length); };
209          break;
210        case '*': // Match ends with value
211          checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) > -1); };
212          break;
213        default :
214          // Just test for existence of attribute
215          checkFunction = function(e) { return e.getAttribute(attrName); };
216      }
217      currentContext = new Array;
218      var currentContextIndex = 0;
219      for (var k = 0; k < found.length; k++) {
220        if (checkFunction(found[k])) {
221          currentContext[currentContextIndex++] = found[k];
222        }
223      }
224      // alert('Attribute Selector: '+tagName+' '+attrName+' '+attrOperator+' '+attrValue);
225      continue; // Skip to next token
226    }
227   
228    if (!currentContext[0]){
229      return;
230    }
231   
232    // If we get here, token is JUST an element (not a class or ID selector)
233    tagName = token;
234    var found = new Array;
235    var foundCount = 0;
236    for (var h = 0; h < currentContext.length; h++) {
237      var elements = currentContext[h].getElementsByTagName(tagName);
238      for (var j = 0; j < elements.length; j++) {
239        found[foundCount++] = elements[j];
240      }
241    }
242    currentContext = found;
243  }
244  return currentContext;
245}
246
247/* That revolting regular expression explained
248/^(\w+)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/
249  \---/  \---/\-------------/    \-------/
250    |      |         |               |
251    |      |         |           The value
252    |      |    ~,|,^,$,* or =
253    |   Attribute
254   Tag
255*/