PageRenderTime 18ms CodeModel.GetById 2ms app.highlight 13ms RepoModel.GetById 1ms app.codeStats 0ms

/hudson-war/src/main/webapp/scripts/behavior.js

http://github.com/hudson/hudson
JavaScript | 257 lines | 174 code | 15 blank | 68 comment | 22 complexity | e3b782dc6868bfbe8432818777afac67 MD5 | raw file
  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        this.applySubtree(document);
 55    },
 56
 57    applySubtree : function(startNode) {
 58        Behaviour.list._each(function(sheet) {
 59            for (var selector in sheet){
 60                var list = findElementsBySelector(startNode,selector);
 61                list._each(sheet[selector]);
 62            }
 63        });
 64    },
 65
 66    addLoadEvent : function(func){
 67		var oldonload = window.onload;
 68
 69		if (typeof window.onload != 'function') {
 70			window.onload = func;
 71		} else {
 72			window.onload = function() {
 73				oldonload();
 74				func();
 75			}
 76		}
 77	}
 78}
 79
 80Behaviour.start();
 81
 82/*
 83   The following code is Copyright (C) Simon Willison 2004.
 84
 85   document.getElementsBySelector(selector)
 86   - returns an array of element objects from the current document
 87     matching the CSS selector. Selectors can contain element names,
 88     class names and ids and can be nested. For example:
 89
 90       elements = document.getElementsBySelect('div#main p a.external')
 91
 92     Will return an array of all 'a' elements with 'external' in their
 93     class attribute that are contained inside 'p' elements that are
 94     contained inside the 'div' element which has id="main"
 95
 96   New in version 0.4: Support for CSS2 and CSS3 attribute selectors:
 97   See http://www.w3.org/TR/css3-selectors/#attribute-selectors
 98
 99   Version 0.4 - Simon Willison, March 25th 2003
100   -- Works in Phoenix 0.5, Mozilla 1.3, Opera 7, Internet Explorer 6, Internet Explorer 5 on Windows
101   -- Opera 7 fails
102*/
103
104function getAllChildren(e) {
105  // Returns all children of element. Workaround required for IE5/Windows. Ugh.
106  return e.all ? e.all : e.getElementsByTagName('*');
107}
108
109function isAncestor(p,c) {
110  while(true) {
111    if(p==c)      return true;
112    if(c==null)   return false;
113    c = c.parentNode;
114  }
115}
116
117function findElementsBySelector(startNode,selector) {
118  // Split selector in to tokens
119  var tokens = selector.replace(/^\s+/,'').replace(/\s+$/,'').split(' ');
120  var currentContext = new Array(startNode);
121  for (var i = 0; i < tokens.length; i++) {
122    var 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 [];
132      }
133
134      // make sure this node is a descendant of the current context
135      if(currentContext.find(function(n) {return isAncestor(n,element)})==null)
136        return []; // not a descendant
137
138      // Set currentContext to contain just this element
139      currentContext = [element];
140      continue; // Skip to next token
141    }
142    if (token.indexOf('.') > -1) {
143      // Token contains a class selector
144      var bits = token.split('.');
145      var tagName = bits[0];
146      var className = new RegExp('\\b'+bits[1]+'\\b');
147      if (!tagName) {
148        tagName = '*';
149      }
150      // Get elements matching tag, filter them for class selector
151      var found = [];
152      for (var h = 0; h < currentContext.length; h++) {
153        var elements;
154        if (tagName == '*') {
155            elements = getAllChildren(currentContext[h]);
156        } else {
157            elements = currentContext[h].getElementsByTagName(tagName);
158        }
159        for (var j = 0; j < elements.length; j++) {
160          found.push(elements[j]);
161        }
162      }
163
164      currentContext = [];
165      for (var k = 0; k < found.length; k++) {
166        if (found[k].className && found[k].className.match(className)) {
167          currentContext.push(found[k]);
168        }
169      }
170      continue; // Skip to next token
171    }
172    // Code to deal with attribute selectors
173    bits = /^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/.exec(token);
174    if (bits!=null) {
175      var tagName = bits[1];
176      var attrName = bits[2];
177      var attrOperator = bits[3];
178      var attrValue = bits[4];
179      if (!tagName) {
180        tagName = '*';
181      }
182      // Grab all of the tagName elements within current context
183      var found = new Array;
184      var foundCount = 0;
185      for (var h = 0; h < currentContext.length; h++) {
186        var elements;
187        if (tagName == '*') {
188            elements = getAllChildren(currentContext[h]);
189        } else {
190            elements = currentContext[h].getElementsByTagName(tagName);
191        }
192        for (var j = 0; j < elements.length; j++) {
193          found.push(elements[j]);
194        }
195      }
196
197      var checkFunction; // This function will be used to filter the elements
198      switch (attrOperator) {
199        case '=': // Equality
200          checkFunction = function(e) { return (e.getAttribute(attrName) == attrValue); };
201          break;
202        case '~': // Match one of space seperated words
203          checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('\\b'+attrValue+'\\b'))); };
204          break;
205        case '|': // Match start with value followed by optional hyphen
206          checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('^'+attrValue+'-?'))); };
207          break;
208        case '^': // Match starts with value
209          checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) == 0); };
210          break;
211        case '$': // Match ends with value - fails with "Warning" in Opera 7
212          checkFunction = function(e) { return (e.getAttribute(attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length); };
213          break;
214        case '*': // Match ends with value
215          checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) > -1); };
216          break;
217        default :
218          // Just test for existence of attribute
219          checkFunction = function(e) { return e.getAttribute(attrName); };
220      }
221
222      currentContext = found.findAll(checkFunction);
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    for (var h = 0; h < currentContext.length; h++) {
235      var elements = currentContext[h].getElementsByTagName(tagName);
236      for (var j = 0; j < elements.length; j++) {
237        found.push(elements[j]);
238      }
239    }
240    currentContext = found;
241  }
242  return currentContext;
243}
244
245document.getElementsBySelector = function(selector) {
246    return findElementsBySelector(document,selector);
247}
248
249/* That revolting regular expression explained
250/^(\w+)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/
251  \---/  \---/\-------------/    \-------/
252    |      |         |               |
253    |      |         |           The value
254    |      |    ~,|,^,$,* or =
255    |   Attribute
256   Tag
257*/