source: products/qPloneDropDownMenu/branches/0.2/skins/qPloneDropDownMenu/javascripts/behaviour.js @ 1

Last change on this file since 1 was 1, checked in by myroslav, 18 years ago

Building directory structure

File size: 8.0 KB
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 (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*/
Note: See TracBrowser for help on using the repository browser.