[Jifty-commit] r899 - in jifty/branches/jifty-jsan: share/web/static/js share/web/static/js/cssquery share/web/static/js/jsan share/web/static/js/jsan/DOM share/web/static/js/jsan/Upgrade share/web/static/js/jsan/Upgrade/Array share/web/static/js/jsan/Upgrade/Function share/web/templates/_elements

jifty-commit at lists.jifty.org jifty-commit at lists.jifty.org
Sun Apr 23 12:15:39 EDT 2006


Author: trs
Date: Sun Apr 23 12:15:37 2006
New Revision: 899

Added:
   jifty/branches/jifty-jsan/share/web/static/js/cssquery/
   jifty/branches/jifty-jsan/share/web/static/js/cssquery/cssQuery-level2.js
   jifty/branches/jifty-jsan/share/web/static/js/cssquery/cssQuery-level3.js
   jifty/branches/jifty-jsan/share/web/static/js/cssquery/cssQuery-standard.js
   jifty/branches/jifty-jsan/share/web/static/js/cssquery/cssQuery.js
   jifty/branches/jifty-jsan/share/web/static/js/jsan/
   jifty/branches/jifty-jsan/share/web/static/js/jsan/DOM/
   jifty/branches/jifty-jsan/share/web/static/js/jsan/DOM/Events.js
   jifty/branches/jifty-jsan/share/web/static/js/jsan/JSAN.js
   jifty/branches/jifty-jsan/share/web/static/js/jsan/Upgrade/
   jifty/branches/jifty-jsan/share/web/static/js/jsan/Upgrade.js
   jifty/branches/jifty-jsan/share/web/static/js/jsan/Upgrade/Array/
   jifty/branches/jifty-jsan/share/web/static/js/jsan/Upgrade/Array/push.js
   jifty/branches/jifty-jsan/share/web/static/js/jsan/Upgrade/Function/
   jifty/branches/jifty-jsan/share/web/static/js/jsan/Upgrade/Function/apply.js
Modified:
   jifty/branches/jifty-jsan/   (props changed)
   jifty/branches/jifty-jsan/share/web/static/js/behaviour.js
   jifty/branches/jifty-jsan/share/web/templates/_elements/javascript

Log:
 r9947 at zot:  tom | 2006-04-23 00:39:58 -0400
 Reworked Behaviour library to use JSAN and cssQuery


Modified: jifty/branches/jifty-jsan/share/web/static/js/behaviour.js
==============================================================================
--- jifty/branches/jifty-jsan/share/web/static/js/behaviour.js	(original)
+++ jifty/branches/jifty-jsan/share/web/static/js/behaviour.js	Sun Apr 23 12:15:37 2006
@@ -1,254 +1,55 @@
 /*
-   Behaviour v1.1 by Ben Nolan, June 2005. Based largely on the work
-   of Simon Willison (see comments by Simon below).
-
-   Description:
-   	
-   	Uses css selectors to apply javascript behaviours to enable
-   	unobtrusive javascript in html documents.
-   	
+   Modified to fix some bugs, use a different css query engine, and to
+   to use JSAN classes.
+   
+   Based on Behaviour v1.1 by Ben Nolan, June 2005, which was based
+   largely on the work of Simon Willison.
+ 
    Usage:   
    
-	var myrules = {
-		'b.someclass' : function(element){
-			element.onclick = function(){
-				alert(this.innerHTML);
-			}
-		},
-		'#someid u' : function(element){
-			element.onmouseover = function(){
-				this.innerHTML = "BLAH!";
-			}
-		}
-	};
-	
-	Behaviour.register(myrules);
-	
-	// Call Behaviour.apply() to re-apply the rules (if you
-	// update the dom, etc).
+    var myrules = {
+        'b.someclass' : function(element){
+            element.onclick = function(){
+                alert(this.innerHTML);
+            }
+        },
+        '#someid u' : function(element){
+            element.onmouseover = function(){
+                this.innerHTML = "BLAH!";
+            }
+        }
+    };
+    
+    Behaviour.register(myrules);
+    
+    // Call Behaviour.apply() to re-apply the rules (if you
+    // update the dom, etc).
 
-   License:
-   
-   	My stuff is BSD licensed. Not sure about Simon's.
-   	
-   More information:
-   	
-   	http://ripcord.co.nz/behaviour/
-   
 */   
 
-var Behaviour = {
-	list : new Array,
-	
-	register : function(sheet){
-		Behaviour.list.push(sheet);
-	},
-	
-	start : function(){
-		Behaviour.addLoadEvent(function(){
-			Behaviour.apply();
-		});
-	},
-	
-	apply : function(){
-		for (h=0;sheet=Behaviour.list[h];h++){
-			for (selector in sheet){
-				list = document.getElementsBySelector(selector);
-				
-				if (!list){
-					continue;
-				}
-
-				for (i=0;element=list[i];i++){
-					sheet[selector](element);
-				}
-			}
-		}
-	},
-	
-	addLoadEvent : function(func){
-		var oldonload = window.onload;
-		
-		if (typeof window.onload != 'function') {
-			window.onload = func;
-		} else {
-			window.onload = function() {
-				oldonload();
-				func();
-			}
-		}
-	}
-}
-
-Behaviour.start();
-
-/*
-   The following code is Copyright (C) Simon Willison 2004.
+JSAN.use("DOM.Events");
+JSAN.use("Upgrade.Array.push");
 
-   document.getElementsBySelector(selector)
-   - returns an array of element objects from the current document
-     matching the CSS selector. Selectors can contain element names, 
-     class names and ids and can be nested. For example:
-     
-       elements = document.getElementsBySelect('div#main p a.external')
-     
-     Will return an array of all 'a' elements with 'external' in their 
-     class attribute that are contained inside 'p' elements that are 
-     contained inside the 'div' element which has id="main"
-
-   New in version 0.4: Support for CSS2 and CSS3 attribute selectors:
-   See http://www.w3.org/TR/css3-selectors/#attribute-selectors
-
-   Version 0.4 - Simon Willison, March 25th 2003
-   -- Works in Phoenix 0.5, Mozilla 1.3, Opera 7, Internet Explorer 6, Internet Explorer 5 on Windows
-   -- Opera 7 fails 
-*/
-
-function getAllChildren(e) {
-  // Returns all children of element. Workaround required for IE5/Windows. Ugh.
-  return e.all ? e.all : e.getElementsByTagName('*');
-}
-
-document.getElementsBySelector = function(selector) {
-  // Attempt to fail gracefully in lesser browsers
-  if (!document.getElementsByTagName) {
-    return new Array();
-  }
-  // Split selector in to tokens
-  var tokens = selector.split(' ');
-  var currentContext = new Array(document);
-  for (var i = 0; i < tokens.length; i++) {
-    token = tokens[i].replace(/^\s+/,'').replace(/\s+$/,'');;
-    if (token.indexOf('#') > -1) {
-      // Token is an ID selector
-      var bits = token.split('#');
-      var tagName = bits[0];
-      var id = bits[1];
-      var element = document.getElementById(id);
-      if (tagName && element.nodeName.toLowerCase() != tagName) {
-        // tag with that ID not found, return false
-        return new Array();
-      }
-      // Set currentContext to contain just this element
-      currentContext = new Array(element);
-      continue; // Skip to next token
-    }
-    if (token.indexOf('.') > -1) {
-      // Token contains a class selector
-      var bits = token.split('.');
-      var tagName = bits[0];
-      var className = bits[1];
-      if (!tagName) {
-        tagName = '*';
-      }
-      // Get elements matching tag, filter them for class selector
-      var found = new Array;
-      var foundCount = 0;
-      for (var h = 0; h < currentContext.length; h++) {
-        var elements;
-        if (tagName == '*') {
-            elements = getAllChildren(currentContext[h]);
-        } else {
-            elements = currentContext[h].getElementsByTagName(tagName);
-        }
-        for (var j = 0; j < elements.length; j++) {
-          found[foundCount++] = elements[j];
-        }
-      }
-      currentContext = new Array;
-      var currentContextIndex = 0;
-      for (var k = 0; k < found.length; k++) {
-        if (found[k].className && found[k].className.match(new RegExp('\\b'+className+'\\b'))) {
-          currentContext[currentContextIndex++] = found[k];
-        }
-      }
-      continue; // Skip to next token
-    }
-    // Code to deal with attribute selectors
-    if (token.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/)) {
-      var tagName = RegExp.$1;
-      var attrName = RegExp.$2;
-      var attrOperator = RegExp.$3;
-      var attrValue = RegExp.$4;
-      if (!tagName) {
-        tagName = '*';
-      }
-      // Grab all of the tagName elements within current context
-      var found = new Array;
-      var foundCount = 0;
-      for (var h = 0; h < currentContext.length; h++) {
-        var elements;
-        if (tagName == '*') {
-            elements = getAllChildren(currentContext[h]);
-        } else {
-            elements = currentContext[h].getElementsByTagName(tagName);
-        }
-        for (var j = 0; j < elements.length; j++) {
-          found[foundCount++] = elements[j];
-        }
-      }
-      currentContext = new Array;
-      var currentContextIndex = 0;
-      var checkFunction; // This function will be used to filter the elements
-      switch (attrOperator) {
-        case '=': // Equality
-          checkFunction = function(e) { return (e.getAttribute(attrName) == attrValue); };
-          break;
-        case '~': // Match one of space seperated words 
-          checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('\\b'+attrValue+'\\b'))); };
-          break;
-        case '|': // Match start with value followed by optional hyphen
-          checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('^'+attrValue+'-?'))); };
-          break;
-        case '^': // Match starts with value
-          checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) == 0); };
-          break;
-        case '$': // Match ends with value - fails with "Warning" in Opera 7
-          checkFunction = function(e) { return (e.getAttribute(attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length); };
-          break;
-        case '*': // Match ends with value
-          checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) > -1); };
-          break;
-        default :
-          // Just test for existence of attribute
-          checkFunction = function(e) { return e.getAttribute(attrName); };
-      }
-      currentContext = new Array;
-      var currentContextIndex = 0;
-      for (var k = 0; k < found.length; k++) {
-        if (checkFunction(found[k])) {
-          currentContext[currentContextIndex++] = found[k];
-        }
-      }
-      // alert('Attribute Selector: '+tagName+' '+attrName+' '+attrOperator+' '+attrValue);
-      continue; // Skip to next token
-    }
+var Behaviour = {
+    list: new Array(),
     
-    if (!currentContext[0]){
-    	return;
-    }
+    register: function(sheet) {
+        Behaviour.list.push(sheet);
+    },
     
-    // If we get here, token is JUST an element (not a class or ID selector)
-    tagName = token;
-    var found = new Array;
-    var foundCount = 0;
-    for (var h = 0; h < currentContext.length; h++) {
-      var elements = currentContext[h].getElementsByTagName(tagName);
-      for (var j = 0; j < elements.length; j++) {
-        found[foundCount++] = elements[j];
-      }
+    apply: function() {
+        for (var h = 0; sheet = Behaviour.list[h]; h++) {
+            for (var selector in sheet) {
+                var elements = cssQuery(selector);
+                
+                if ( !elements ) continue;
+
+                for (var i = 0; element = elements[i]; i++)
+                    sheet[selector](element);
+            }
+        }
     }
-    currentContext = found;
-  }
-  return currentContext;
-}
-
-/* That revolting regular expression explained 
-/^(\w+)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/
-  \---/  \---/\-------------/    \-------/
-    |      |         |               |
-    |      |         |           The value
-    |      |    ~,|,^,$,* or =
-    |   Attribute 
-   Tag
-*/
+}    
+
+DOM.Events.addListener( window, "load", Behaviour.apply );
+

Added: jifty/branches/jifty-jsan/share/web/static/js/cssquery/cssQuery-level2.js
==============================================================================
--- (empty file)
+++ jifty/branches/jifty-jsan/share/web/static/js/cssquery/cssQuery-level2.js	Sun Apr 23 12:15:37 2006
@@ -0,0 +1,142 @@
+/*
+	cssQuery, version 2.0.2 (2005-08-19)
+	Copyright: 2004-2005, Dean Edwards (http://dean.edwards.name/)
+	License: http://creativecommons.org/licenses/LGPL/2.1/
+*/
+
+cssQuery.addModule("css-level2", function() {
+
+// -----------------------------------------------------------------------
+// selectors
+// -----------------------------------------------------------------------
+
+// child selector
+selectors[">"] = function($results, $from, $tagName, $namespace) {
+	var $element, i, j;
+	for (i = 0; i < $from.length; i++) {
+		var $subset = childElements($from[i]);
+		for (j = 0; ($element = $subset[j]); j++)
+			if (compareTagName($element, $tagName, $namespace))
+				$results.push($element);
+	}
+};
+
+// sibling selector
+selectors["+"] = function($results, $from, $tagName, $namespace) {
+	for (var i = 0; i < $from.length; i++) {
+		var $element = nextElementSibling($from[i]);
+		if ($element && compareTagName($element, $tagName, $namespace))
+			$results.push($element);
+	}
+};
+
+// attribute selector
+selectors["@"] = function($results, $from, $attributeSelectorID) {
+	var $test = attributeSelectors[$attributeSelectorID].test;
+	var $element, i;
+	for (i = 0; ($element = $from[i]); i++)
+		if ($test($element)) $results.push($element);
+};
+
+// -----------------------------------------------------------------------
+// pseudo-classes
+// -----------------------------------------------------------------------
+
+pseudoClasses["first-child"] = function($element) {
+	return !previousElementSibling($element);
+};
+
+pseudoClasses["lang"] = function($element, $code) {
+	$code = new RegExp("^" + $code, "i");
+	while ($element && !$element.getAttribute("lang")) $element = $element.parentNode;
+	return $element && $code.test($element.getAttribute("lang"));
+};
+
+// -----------------------------------------------------------------------
+//  attribute selectors
+// -----------------------------------------------------------------------
+
+// constants
+AttributeSelector.NS_IE = /\\:/g;
+AttributeSelector.PREFIX = "@";
+// properties
+AttributeSelector.tests = {};
+// methods
+AttributeSelector.replace = function($match, $attribute, $namespace, $compare, $value) {
+	var $key = this.PREFIX + $match;
+	if (!attributeSelectors[$key]) {
+		$attribute = this.create($attribute, $compare || "", $value || "");
+		// store the selector
+		attributeSelectors[$key] = $attribute;
+		attributeSelectors.push($attribute);
+	}
+	return attributeSelectors[$key].id;
+};
+AttributeSelector.parse = function($selector) {
+	$selector = $selector.replace(this.NS_IE, "|");
+	var $match;
+	while ($match = $selector.match(this.match)) {
+		var $replace = this.replace($match[0], $match[1], $match[2], $match[3], $match[4]);
+		$selector = $selector.replace(this.match, $replace);
+	}
+	return $selector;
+};
+AttributeSelector.create = function($propertyName, $test, $value) {
+	var $attributeSelector = {};
+	$attributeSelector.id = this.PREFIX + attributeSelectors.length;
+	$attributeSelector.name = $propertyName;
+	$test = this.tests[$test];
+	$test = $test ? $test(this.getAttribute($propertyName), getText($value)) : false;
+	$attributeSelector.test = new Function("e", "return " + $test);
+	return $attributeSelector;
+};
+AttributeSelector.getAttribute = function($name) {
+	switch ($name.toLowerCase()) {
+		case "id":
+			return "e.id";
+		case "class":
+			return "e.className";
+		case "for":
+			return "e.htmlFor";
+		case "href":
+			if (isMSIE) {
+				// IE always returns the full path not the fragment in the href attribute
+				//  so we RegExp it out of outerHTML. Opera does the same thing but there
+				//  is no way to get the original attribute.
+				return "String((e.outerHTML.match(/href=\\x22?([^\\s\\x22]*)\\x22?/)||[])[1]||'')";
+			}
+	}
+	return "e.getAttribute('" + $name.replace($NAMESPACE, ":") + "')";
+};
+
+// -----------------------------------------------------------------------
+//  attribute selector tests
+// -----------------------------------------------------------------------
+
+AttributeSelector.tests[""] = function($attribute) {
+	return $attribute;
+};
+
+AttributeSelector.tests["="] = function($attribute, $value) {
+	return $attribute + "==" + Quote.add($value);
+};
+
+AttributeSelector.tests["~="] = function($attribute, $value) {
+	return "/(^| )" + regEscape($value) + "( |$)/.test(" + $attribute + ")";
+};
+
+AttributeSelector.tests["|="] = function($attribute, $value) {
+	return "/^" + regEscape($value) + "(-|$)/.test(" + $attribute + ")";
+};
+
+// -----------------------------------------------------------------------
+//  parsing
+// -----------------------------------------------------------------------
+
+// override parseSelector to parse out attribute selectors
+var _parseSelector = parseSelector;
+parseSelector = function($selector) {
+	return _parseSelector(AttributeSelector.parse($selector));
+};
+
+}); // addModule

Added: jifty/branches/jifty-jsan/share/web/static/js/cssquery/cssQuery-level3.js
==============================================================================
--- (empty file)
+++ jifty/branches/jifty-jsan/share/web/static/js/cssquery/cssQuery-level3.js	Sun Apr 23 12:15:37 2006
@@ -0,0 +1,150 @@
+/*
+	cssQuery, version 2.0.2 (2005-08-19)
+	Copyright: 2004-2005, Dean Edwards (http://dean.edwards.name/)
+	License: http://creativecommons.org/licenses/LGPL/2.1/
+*/
+
+/* Thanks to Bill Edney */
+
+cssQuery.addModule("css-level3", function() {
+
+// -----------------------------------------------------------------------
+// selectors
+// -----------------------------------------------------------------------
+
+// indirect sibling selector
+selectors["~"] = function($results, $from, $tagName, $namespace) {
+	var $element, i;
+	for (i = 0; ($element = $from[i]); i++) {
+		while ($element = nextElementSibling($element)) {
+			if (compareTagName($element, $tagName, $namespace))
+				$results.push($element);
+		}
+	}
+};
+
+// -----------------------------------------------------------------------
+// pseudo-classes
+// -----------------------------------------------------------------------
+
+// I'm hoping these pseudo-classes are pretty readable. Let me know if
+//  any need explanation.
+
+pseudoClasses["contains"] = function($element, $text) {
+	$text = new RegExp(regEscape(getText($text)));
+	return $text.test(getTextContent($element));
+};
+
+pseudoClasses["root"] = function($element) {
+	return $element == getDocument($element).documentElement;
+};
+
+pseudoClasses["empty"] = function($element) {
+	var $node, i;
+	for (i = 0; ($node = $element.childNodes[i]); i++) {
+		if (thisElement($node) || $node.nodeType == 3) return false;
+	}
+	return true;
+};
+
+pseudoClasses["last-child"] = function($element) {
+	return !nextElementSibling($element);
+};
+
+pseudoClasses["only-child"] = function($element) {
+	$element = $element.parentNode;
+	return firstElementChild($element) == lastElementChild($element);
+};
+
+pseudoClasses["not"] = function($element, $selector) {
+	var $negated = cssQuery($selector, getDocument($element));
+	for (var i = 0; i < $negated.length; i++) {
+		if ($negated[i] == $element) return false;
+	}
+	return true;
+};
+
+pseudoClasses["nth-child"] = function($element, $arguments) {
+	return nthChild($element, $arguments, previousElementSibling);
+};
+
+pseudoClasses["nth-last-child"] = function($element, $arguments) {
+	return nthChild($element, $arguments, nextElementSibling);
+};
+
+pseudoClasses["target"] = function($element) {
+	return $element.id == location.hash.slice(1);
+};
+
+// UI element states
+
+pseudoClasses["checked"] = function($element) {
+	return $element.checked;
+};
+
+pseudoClasses["enabled"] = function($element) {
+	return $element.disabled === false;
+};
+
+pseudoClasses["disabled"] = function($element) {
+	return $element.disabled;
+};
+
+pseudoClasses["indeterminate"] = function($element) {
+	return $element.indeterminate;
+};
+
+// -----------------------------------------------------------------------
+//  attribute selector tests
+// -----------------------------------------------------------------------
+
+AttributeSelector.tests["^="] = function($attribute, $value) {
+	return "/^" + regEscape($value) + "/.test(" + $attribute + ")";
+};
+
+AttributeSelector.tests["$="] = function($attribute, $value) {
+	return "/" + regEscape($value) + "$/.test(" + $attribute + ")";
+};
+
+AttributeSelector.tests["*="] = function($attribute, $value) {
+	return "/" + regEscape($value) + "/.test(" + $attribute + ")";
+};
+
+// -----------------------------------------------------------------------
+//  nth child support (Bill Edney)
+// -----------------------------------------------------------------------
+
+function nthChild($element, $arguments, $traverse) {
+	switch ($arguments) {
+		case "n": return true;
+		case "even": $arguments = "2n"; break;
+		case "odd": $arguments = "2n+1";
+	}
+
+	var $$children = childElements($element.parentNode);
+	function _checkIndex($index) {
+		var $index = ($traverse == nextElementSibling) ? $$children.length - $index : $index - 1;
+		return $$children[$index] == $element;
+	};
+
+	//	it was just a number (no "n")
+	if (!isNaN($arguments)) return _checkIndex($arguments);
+
+	$arguments = $arguments.split("n");
+	var $multiplier = parseInt($arguments[0]);
+	var $step = parseInt($arguments[1]);
+
+	if ((isNaN($multiplier) || $multiplier == 1) && $step == 0) return true;
+	if ($multiplier == 0 && !isNaN($step)) return _checkIndex($step);
+	if (isNaN($step)) $step = 0;
+
+	var $count = 1;
+	while ($element = $traverse($element)) $count++;
+
+	if (isNaN($multiplier) || $multiplier == 1)
+		return ($traverse == nextElementSibling) ? ($count <= $step) : ($step >= $count);
+
+	return ($count % $multiplier) == $step;
+};
+
+}); // addModule

Added: jifty/branches/jifty-jsan/share/web/static/js/cssquery/cssQuery-standard.js
==============================================================================
--- (empty file)
+++ jifty/branches/jifty-jsan/share/web/static/js/cssquery/cssQuery-standard.js	Sun Apr 23 12:15:37 2006
@@ -0,0 +1,53 @@
+/*
+	cssQuery, version 2.0.2 (2005-08-19)
+	Copyright: 2004-2005, Dean Edwards (http://dean.edwards.name/)
+	License: http://creativecommons.org/licenses/LGPL/2.1/
+*/
+
+cssQuery.addModule("css-standard", function() { // override IE optimisation
+
+// cssQuery was originally written as the CSS engine for IE7. It is
+//  optimised (in terms of size not speed) for IE so this module is
+//  provided separately to provide cross-browser support.
+
+// -----------------------------------------------------------------------
+// browser compatibility
+// -----------------------------------------------------------------------
+
+// sniff for Win32 Explorer
+isMSIE = eval("false;/*@cc_on at if(@\x5fwin32)isMSIE=true at end@*/");
+
+if (!isMSIE) {
+	getElementsByTagName = function($element, $tagName, $namespace) {
+		return $namespace ? $element.getElementsByTagNameNS("*", $tagName) :
+			$element.getElementsByTagName($tagName);
+	};
+
+	compareNamespace = function($element, $namespace) {
+		return !$namespace || ($namespace == "*") || ($element.prefix == $namespace);
+	};
+
+	isXML = document.contentType ? function($element) {
+		return /xml/i.test(getDocument($element).contentType);
+	} : function($element) {
+		return getDocument($element).documentElement.tagName != "HTML";
+	};
+
+	getTextContent = function($element) {
+		// mozilla || opera || other
+		return $element.textContent || $element.innerText || _getTextContent($element);
+	};
+
+	function _getTextContent($element) {
+		var $textContent = "", $node, i;
+		for (i = 0; ($node = $element.childNodes[i]); i++) {
+			switch ($node.nodeType) {
+				case 11: // document fragment
+				case 1: $textContent += _getTextContent($node); break;
+				case 3: $textContent += $node.nodeValue; break;
+			}
+		}
+		return $textContent;
+	};
+}
+}); // addModule

Added: jifty/branches/jifty-jsan/share/web/static/js/cssquery/cssQuery.js
==============================================================================
--- (empty file)
+++ jifty/branches/jifty-jsan/share/web/static/js/cssquery/cssQuery.js	Sun Apr 23 12:15:37 2006
@@ -0,0 +1,356 @@
+/*
+	cssQuery, version 2.0.2 (2005-08-19)
+	Copyright: 2004-2005, Dean Edwards (http://dean.edwards.name/)
+	License: http://creativecommons.org/licenses/LGPL/2.1/
+*/
+
+// the following functions allow querying of the DOM using CSS selectors
+var cssQuery = function() {
+var version = "2.0.2";
+
+// -----------------------------------------------------------------------
+// main query function
+// -----------------------------------------------------------------------
+
+var $COMMA = /\s*,\s*/;
+var cssQuery = function($selector, $$from) {
+try {
+	var $match = [];
+	var $useCache = arguments.callee.caching && !$$from;
+	var $base = ($$from) ? ($$from.constructor == Array) ? $$from : [$$from] : [document];
+	// process comma separated selectors
+	var $$selectors = parseSelector($selector).split($COMMA), i;
+	for (i = 0; i < $$selectors.length; i++) {
+		// convert the selector to a stream
+		$selector = _toStream($$selectors[i]);
+		// faster chop if it starts with id (MSIE only)
+		if (isMSIE && $selector.slice(0, 3).join("") == " *#") {
+			$selector = $selector.slice(2);
+			$$from = _msie_selectById([], $base, $selector[1]);
+		} else $$from = $base;
+		// process the stream
+		var j = 0, $token, $filter, $arguments, $cacheSelector = "";
+		while (j < $selector.length) {
+			$token = $selector[j++];
+			$filter = $selector[j++];
+			$cacheSelector += $token + $filter;
+			// some pseudo-classes allow arguments to be passed
+			//  e.g. nth-child(even)
+			$arguments = "";
+			if ($selector[j] == "(") {
+				while ($selector[j++] != ")" && j < $selector.length) {
+					$arguments += $selector[j];
+				}
+				$arguments = $arguments.slice(0, -1);
+				$cacheSelector += "(" + $arguments + ")";
+			}
+			// process a token/filter pair use cached results if possible
+			$$from = ($useCache && cache[$cacheSelector]) ?
+				cache[$cacheSelector] : select($$from, $token, $filter, $arguments);
+			if ($useCache) cache[$cacheSelector] = $$from;
+		}
+		$match = $match.concat($$from);
+	}
+	delete cssQuery.error;
+	return $match;
+} catch ($error) {
+	cssQuery.error = $error;
+	return [];
+}};
+
+// -----------------------------------------------------------------------
+// public interface
+// -----------------------------------------------------------------------
+
+cssQuery.toString = function() {
+	return "function cssQuery() {\n  [version " + version + "]\n}";
+};
+
+// caching
+var cache = {};
+cssQuery.caching = false;
+cssQuery.clearCache = function($selector) {
+	if ($selector) {
+		$selector = _toStream($selector).join("");
+		delete cache[$selector];
+	} else cache = {};
+};
+
+// allow extensions
+var modules = {};
+var loaded = false;
+cssQuery.addModule = function($name, $script) {
+	if (loaded) eval("$script=" + String($script));
+	modules[$name] = new $script();;
+};
+
+// hackery
+cssQuery.valueOf = function($code) {
+	return $code ? eval($code) : this;
+};
+
+// -----------------------------------------------------------------------
+// declarations
+// -----------------------------------------------------------------------
+
+var selectors = {};
+var pseudoClasses = {};
+// a safari bug means that these have to be declared here
+var AttributeSelector = {match: /\[([\w-]+(\|[\w-]+)?)\s*(\W?=)?\s*([^\]]*)\]/};
+var attributeSelectors = [];
+
+// -----------------------------------------------------------------------
+// selectors
+// -----------------------------------------------------------------------
+
+// descendant selector
+selectors[" "] = function($results, $from, $tagName, $namespace) {
+	// loop through current selection
+	var $element, i, j;
+	for (i = 0; i < $from.length; i++) {
+		// get descendants
+		var $subset = getElementsByTagName($from[i], $tagName, $namespace);
+		// loop through descendants and add to results selection
+		for (j = 0; ($element = $subset[j]); j++) {
+			if (thisElement($element) && compareNamespace($element, $namespace))
+				$results.push($element);
+		}
+	}
+};
+
+// ID selector
+selectors["#"] = function($results, $from, $id) {
+	// loop through current selection and check ID
+	var $element, j;
+	for (j = 0; ($element = $from[j]); j++) if ($element.id == $id) $results.push($element);
+};
+
+// class selector
+selectors["."] = function($results, $from, $className) {
+	// create a RegExp version of the class
+	$className = new RegExp("(^|\\s)" + $className + "(\\s|$)");
+	// loop through current selection and check class
+	var $element, i;
+	for (i = 0; ($element = $from[i]); i++)
+		if ($className.test($element.className)) $results.push($element);
+};
+
+// pseudo-class selector
+selectors[":"] = function($results, $from, $pseudoClass, $arguments) {
+	// retrieve the cssQuery pseudo-class function
+	var $test = pseudoClasses[$pseudoClass], $element, i;
+	// loop through current selection and apply pseudo-class filter
+	if ($test) for (i = 0; ($element = $from[i]); i++)
+		// if the cssQuery pseudo-class function returns "true" add the element
+		if ($test($element, $arguments)) $results.push($element);
+};
+
+// -----------------------------------------------------------------------
+// pseudo-classes
+// -----------------------------------------------------------------------
+
+pseudoClasses["link"] = function($element) {
+	var $document = getDocument($element);
+	if ($document.links) for (var i = 0; i < $document.links.length; i++) {
+		if ($document.links[i] == $element) return true;
+	}
+};
+
+pseudoClasses["visited"] = function($element) {
+	// can't do this without jiggery-pokery
+};
+
+// -----------------------------------------------------------------------
+// DOM traversal
+// -----------------------------------------------------------------------
+
+// IE5/6 includes comments (LOL) in it's elements collections.
+// so we have to check for this. the test is tagName != "!". LOL (again).
+var thisElement = function($element) {
+	return ($element && $element.nodeType == 1 && $element.tagName != "!") ? $element : null;
+};
+
+// return the previous element to the supplied element
+//  previousSibling is not good enough as it might return a text or comment node
+var previousElementSibling = function($element) {
+	while ($element && ($element = $element.previousSibling) && !thisElement($element)) continue;
+	return $element;
+};
+
+// return the next element to the supplied element
+var nextElementSibling = function($element) {
+	while ($element && ($element = $element.nextSibling) && !thisElement($element)) continue;
+	return $element;
+};
+
+// return the first child ELEMENT of an element
+//  NOT the first child node (though they may be the same thing)
+var firstElementChild = function($element) {
+	return thisElement($element.firstChild) || nextElementSibling($element.firstChild);
+};
+
+var lastElementChild = function($element) {
+	return thisElement($element.lastChild) || previousElementSibling($element.lastChild);
+};
+
+// return child elements of an element (not child nodes)
+var childElements = function($element) {
+	var $childElements = [];
+	$element = firstElementChild($element);
+	while ($element) {
+		$childElements.push($element);
+		$element = nextElementSibling($element);
+	}
+	return $childElements;
+};
+
+// -----------------------------------------------------------------------
+// browser compatibility
+// -----------------------------------------------------------------------
+
+// all of the functions in this section can be overwritten. the default
+//  configuration is for IE. The functions below reflect this. standard
+//  methods are included in a separate module. It would probably be better
+//  the other way round of course but this makes it easier to keep IE7 trim.
+
+var isMSIE = true;
+
+var isXML = function($element) {
+	var $document = getDocument($element);
+	return (typeof $document.mimeType == "unknown") ?
+		/\.xml$/i.test($document.URL) :
+		Boolean($document.mimeType == "XML Document");
+};
+
+// return the element's containing document
+var getDocument = function($element) {
+	return $element.ownerDocument || $element.document;
+};
+
+var getElementsByTagName = function($element, $tagName) {
+	return ($tagName == "*" && $element.all) ? $element.all : $element.getElementsByTagName($tagName);
+};
+
+var compareTagName = function($element, $tagName, $namespace) {
+	if ($tagName == "*") return thisElement($element);
+	if (!compareNamespace($element, $namespace)) return false;
+	if (!isXML($element)) $tagName = $tagName.toUpperCase();
+	return $element.tagName == $tagName;
+};
+
+var compareNamespace = function($element, $namespace) {
+	return !$namespace || ($namespace == "*") || ($element.scopeName == $namespace);
+};
+
+var getTextContent = function($element) {
+	return $element.innerText;
+};
+
+function _msie_selectById($results, $from, id) {
+	var $match, i, j;
+	for (i = 0; i < $from.length; i++) {
+		if ($match = $from[i].all.item(id)) {
+			if ($match.id == id) $results.push($match);
+			else if ($match.length != null) {
+				for (j = 0; j < $match.length; j++) {
+					if ($match[j].id == id) $results.push($match[j]);
+				}
+			}
+		}
+	}
+	return $results;
+};
+
+// for IE5.0
+if (![].push) Array.prototype.push = function() {
+	for (var i = 0; i < arguments.length; i++) {
+		this[this.length] = arguments[i];
+	}
+	return this.length;
+};
+
+// -----------------------------------------------------------------------
+// query support
+// -----------------------------------------------------------------------
+
+// select a set of matching elements.
+// "from" is an array of elements.
+// "token" is a character representing the type of filter
+//  e.g. ">" means child selector
+// "filter" represents the tag name, id or class name that is being selected
+// the function returns an array of matching elements
+var $NAMESPACE = /\|/;
+function select($$from, $token, $filter, $arguments) {
+	if ($NAMESPACE.test($filter)) {
+		$filter = $filter.split($NAMESPACE);
+		$arguments = $filter[0];
+		$filter = $filter[1];
+	}
+	var $results = [];
+	if (selectors[$token]) {
+		selectors[$token]($results, $$from, $filter, $arguments);
+	}
+	return $results;
+};
+
+// -----------------------------------------------------------------------
+// parsing
+// -----------------------------------------------------------------------
+
+// convert css selectors to a stream of tokens and filters
+//  it's not a real stream. it's just an array of strings.
+var $STANDARD_SELECT = /^[^\s>+~]/;
+var $$STREAM = /[\s#.:>+~()@]|[^\s#.:>+~()@]+/g;
+function _toStream($selector) {
+	if ($STANDARD_SELECT.test($selector)) $selector = " " + $selector;
+	return $selector.match($$STREAM) || [];
+};
+
+var $WHITESPACE = /\s*([\s>+~(),]|^|$)\s*/g;
+var $IMPLIED_ALL = /([\s>+~,]|[^(]\+|^)([#.:@])/g;
+var parseSelector = function($selector) {
+	return $selector
+	// trim whitespace
+	.replace($WHITESPACE, "$1")
+	// e.g. ".class1" --> "*.class1"
+	.replace($IMPLIED_ALL, "$1*$2");
+};
+
+var Quote = {
+	toString: function() {return "'"},
+	match: /^('[^']*')|("[^"]*")$/,
+	test: function($string) {
+		return this.match.test($string);
+	},
+	add: function($string) {
+		return this.test($string) ? $string : this + $string + this;
+	},
+	remove: function($string) {
+		return this.test($string) ? $string.slice(1, -1) : $string;
+	}
+};
+
+var getText = function($text) {
+	return Quote.remove($text);
+};
+
+var $ESCAPE = /([\/()[\]?{}|*+-])/g;
+function regEscape($string) {
+	return $string.replace($ESCAPE, "\\$1");
+};
+
+// -----------------------------------------------------------------------
+// modules
+// -----------------------------------------------------------------------
+
+// -------- >>      insert modules here for packaging       << -------- \\
+
+loaded = true;
+
+// -----------------------------------------------------------------------
+// return the query function
+// -----------------------------------------------------------------------
+
+return cssQuery;
+
+}(); // cssQuery

Added: jifty/branches/jifty-jsan/share/web/static/js/jsan/DOM/Events.js
==============================================================================
--- (empty file)
+++ jifty/branches/jifty-jsan/share/web/static/js/jsan/DOM/Events.js	Sun Apr 23 12:15:37 2006
@@ -0,0 +1,262 @@
+/**
+
+=head1 NAME
+
+DOM.Events - Event registration abstraction layer
+
+=head1 SYNOPSIS
+
+  JSAN.use("DOM.Events");
+
+  function handleClick(e) {
+      e.currentTarget.style.backgroundColor = "#68b";
+  }
+
+  DOM.Events.addListener(window, "load", function () {
+      alert("The page is loaded.");
+  });
+
+  DOM.Events.addListener(window, "load", function () {
+      // this listener won't interfere with the first one
+      var divs = document.getElementsByTagName("div");
+      for(var i=0; i<divs.length; i++) {
+          DOM.Events.addListener(divs[i], "click", handleClick);
+      }
+  });
+
+=head1 DESCRIPTION
+
+This library lets you use a single interface to listen for and handle all DOM events
+to reduce browser-specific code branching.  It also helps in dealing with Internet
+Explorer's memory leak problem by automatically unsetting all event listeners when
+the page is unloaded (for IE only).
+
+=cut
+
+*/
+
+(function () {
+	if(typeof DOM == "undefined") DOM = {};
+	DOM.Events = {};
+	
+    DOM.Events.VERSION = "0.02";
+	DOM.Events.EXPORT = [];
+	DOM.Events.EXPORT_OK = ["addListener", "removeListener"];
+	DOM.Events.EXPORT_TAGS = {
+		":common": DOM.Events.EXPORT,
+		":all": [].concat(DOM.Events.EXPORT, DOM.Events.EXPORT_OK)
+	};
+	
+	// list of event listeners set by addListener
+	// offset 0 is null to prevent 0 from being used as a listener identifier
+	var listenerList = [null];
+	
+/**
+
+=head2 Functions
+
+All functions are kept inside the namespace C<DOM.Events> and aren't exported
+automatically.
+
+=head3 addListener( S<I<HTMLElement> element,> S<I<string> eventType,>
+S<I<Function> handler> S<[, I<boolean> makeCompatible = true] )>
+
+Registers an event listener/handler on an element.  The C<eventType> string should
+I<not> be prefixed with "on" (e.g. "mouseover" not "onmouseover"). If C<makeCompatible>
+is C<true> (the default), the handler is put inside a wrapper that lets you handle the
+events using parts of the DOM Level 2 Events model, even in Internet Explorer (and
+behave-alikes). Specifically:
+
+=over
+
+=item *
+
+The event object is passed as the first argument to the event handler, so you don't
+have to access it through C<window.event>.
+
+=item *
+
+The event object has the properties C<target>, C<currentTarget>, and C<relatedTarget>
+and the methods C<preventDefault()> and C<stopPropagation()> that behave as described
+in the DOM Level 2 Events specification (for the most part).
+
+=item *
+
+If possible, the event object for mouse events will have the properties C<pageX> and
+C<pageY> that contain the mouse's position relative to the document at the time the
+event occurred.
+
+=item *
+
+If you attempt to set a duplicate event handler on an element, the duplicate will
+still be added (this is different from the DOM2 Events model, where duplicates are
+discarded).
+
+=back
+
+If C<makeCompatible> is C<false>, the arguments are simply passed to the browser's
+native event registering facilities, which means you'll have to deal with event
+incompatibilities yourself. However, if you don't need to access the event information,
+doing it this way can be slightly faster and it gives you the option of unsetting the
+handler with a different syntax (see below).
+
+The return value is a positive integer identifier for the listener that can be used to
+unregister it later on in your script.
+
+=cut
+
+*/
+    
+	DOM.Events.addListener = function(elt, ev, func, makeCompatible) {
+		var usedFunc = func;
+        var id = listenerList.length;
+		if(makeCompatible == true || makeCompatible == undefined) {
+			usedFunc = makeCompatibilityWrapper(elt, ev, func);
+		}
+		if(elt.addEventListener) {
+			elt.addEventListener(ev, usedFunc, false);
+			listenerList[id] = [elt, ev, usedFunc];
+			return id;
+		}
+		else if(elt.attachEvent) {
+			elt.attachEvent("on" + ev, usedFunc);
+			listenerList[id] = [elt, ev, usedFunc];
+			return id;
+		}
+		else return false;
+	};
+	
+/**
+
+=head3 removeListener( S<I<integer> identifier> )
+
+Unregisters the event listener associated with the given identifier so that it will
+no longer be called when the event fires.
+
+  var listener = DOM.Events.addListener(myElement, "mousedown", myHandler);
+  // later on ...
+  DOM.Events.removeListener(listener);
+
+=head3 removeListener( S<I<HTMLElement> element,> S<I<string> eventType,> S<I<Function> handler )>
+
+This alternative syntax can be also be used to unset an event listener, but it can only
+be used if C<makeCompatible> was C<false> when it was set.
+
+=cut
+
+*/
+
+	DOM.Events.removeListener = function() {
+		var elt, ev, func;
+		if(arguments.length == 1 && listenerList[arguments[0]]) {
+			elt  = listenerList[arguments[0]][0];
+			ev   = listenerList[arguments[0]][1];
+			func = listenerList[arguments[0]][2];
+			delete listenerList[arguments[0]];
+		}
+		else if(arguments.length == 3) {
+			elt  = arguments[0];
+			ev   = arguments[1];
+			func = arguments[2];
+		}
+		else return;
+		
+		if(elt.removeEventListener) {
+			elt.removeEventListener(ev, func, false);
+		}
+		else if(elt.detachEvent) {
+			elt.detachEvent("on" + ev, func);
+		}
+	};
+	
+    var rval;
+    
+    function makeCompatibilityWrapper(elt, ev, func) {
+        return function (e) {
+            rval = true;
+            if(e == undefined && window.event != undefined)
+                e = window.event;
+            if(e.target == undefined && e.srcElement != undefined)
+                e.target = e.srcElement;
+            if(e.currentTarget == undefined)
+                e.currentTarget = elt;
+            if(e.relatedTarget == undefined) {
+                if(ev == "mouseover" && e.fromElement != undefined)
+                    e.relatedTarget = e.fromElement;
+                else if(ev == "mouseout" && e.toElement != undefined)
+                    e.relatedTarget = e.toElement;
+            }
+            if(e.pageX == undefined) {
+                if(document.body.scrollTop != undefined) {
+                    e.pageX = e.clientX + document.body.scrollLeft;
+                    e.pageY = e.clientY + document.body.scrollTop;
+                }
+                if(document.documentElement != undefined
+                && document.documentElement.scrollTop != undefined) {
+                    if(document.documentElement.scrollTop > 0
+                    || document.documentElement.scrollLeft > 0) {
+                        e.pageX = e.clientX + document.documentElement.scrollLeft;
+                        e.pageY = e.clientY + document.documentElement.scrollTop;
+                    }
+                }
+            }
+            if(e.stopPropagation == undefined)
+                e.stopPropagation = IEStopPropagation;
+            if(e.preventDefault == undefined)
+                e.preventDefault = IEPreventDefault;
+            if(e.cancelable == undefined) e.cancelable = true;
+            func(e);
+            return rval;
+        };
+    }
+    
+    function IEStopPropagation() {
+        if(window.event) window.event.cancelBubble = true;
+    }
+    
+    function IEPreventDefault() {
+        rval = false;
+    }
+
+	function cleanUpIE () {
+		for(var i=0; i<listenerList.length; i++) {
+			var listener = listenerList[i];
+			if(listener) {
+				var elt = listener[0];
+                var ev = listener[1];
+                var func = listener[2];
+				elt.detachEvent("on" + ev, func);
+			}
+		}
+        listenerList = null;
+	}
+
+	if(!window.addEventListener && window.attachEvent) {
+		window.attachEvent("onunload", cleanUpIE);
+	}
+
+})();
+
+/**
+
+=head1 SEE ALSO
+
+DOM Level 2 Events Specification,
+L<http://www.w3.org/TR/DOM-Level-2-Events/>
+
+Understanding and Solving Internet Explorer Leak Patterns,
+L<http://msdn.microsoft.com/library/default.asp?url=/library/en-us/IETechCol/dnwebgen/ie_leak_patterns.asp>
+
+=head1 AUTHOR
+
+Justin Constantino, <F<goflyapig at gmail.com>>.
+
+=head1 COPYRIGHT
+
+  Copyright (c) 2005 Justin Constantino.  All rights reserved.
+  This module is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public Licence.
+
+=cut
+
+*/
\ No newline at end of file

Added: jifty/branches/jifty-jsan/share/web/static/js/jsan/JSAN.js
==============================================================================
--- (empty file)
+++ jifty/branches/jifty-jsan/share/web/static/js/jsan/JSAN.js	Sun Apr 23 12:15:37 2006
@@ -0,0 +1,290 @@
+/*
+
+*/
+
+var JSAN = function () { JSAN.addRepository(arguments) }
+
+JSAN.VERSION = 0.10;
+
+/*
+
+*/
+
+JSAN.globalScope   = self;
+JSAN.includePath   = ['.', 'lib'];
+JSAN.errorLevel    = "none";
+JSAN.errorMessage  = "";
+JSAN.loaded        = {};
+
+/*
+
+*/
+
+JSAN.use = function () {
+    var classdef = JSAN.require(arguments[0]);
+    if (!classdef) return null;
+
+    var importList = JSAN._parseUseArgs.apply(JSAN, arguments).importList;
+    JSAN.exporter(classdef, importList);
+
+    return classdef;
+}
+
+/*
+
+*/
+
+JSAN.require = function (pkg) {
+    var path = JSAN._convertPackageToPath(pkg);
+    if (JSAN.loaded[path]) {
+        return JSAN.loaded[path];
+    }
+
+    try {
+        var classdef = eval(pkg);
+        if (typeof classdef != 'undefined') return classdef;
+    } catch (e) { /* nice try, eh? */ }
+
+
+    for (var i = 0; i < JSAN.includePath.length; i++) {
+        var js;
+        try{
+            var url = JSAN._convertPathToUrl(path, JSAN.includePath[i]);
+                js  = JSAN._loadJSFromUrl(url);
+        } catch (e) {
+            if (i == JSAN.includePath.length - 1) throw e;
+        }
+        if (js != null) {
+            var classdef = JSAN._createScript(js, pkg);
+            JSAN.loaded[path] = classdef;
+            return classdef;
+        }
+    }
+    return false;
+
+}
+
+/*
+
+*/
+
+JSAN.exporter = function () {
+    JSAN._exportItems.apply(JSAN, arguments);
+}
+
+/*
+
+*/
+
+JSAN.addRepository = function () {
+    var temp = JSAN._flatten( arguments );
+    // Need to go in reverse to do something as simple as unshift( @foo, @_ );
+    for ( var i = temp.length - 1; i >= 0; i-- )
+        JSAN.includePath.unshift(temp[i]);
+    return JSAN;
+}
+
+JSAN._flatten = function( list1 ) {
+    var list2 = new Array();
+    for ( var i = 0; i < list1.length; i++ ) {
+        if ( typeof list1[i] == 'object' ) {
+            list2 = JSAN._flatten( list1[i], list2 );
+        }
+        else {
+            list2.push( list1[i] );
+        }
+    }
+    return list2;
+};
+
+JSAN._findMyPath = function () {
+    if (document) {
+        var scripts = document.getElementsByTagName('script');
+        for ( var i = 0; i < scripts.length; i++ ) {
+            var src = scripts[i].getAttribute('src');
+            if (src) {
+                var inc = src.match(/^(.*?)\/?JSAN.js/);
+                if (inc && inc[1]) {
+                    var repo = inc[1];
+                    for (var j = 0; j < JSAN.includePath.length; j++) {
+                        if (JSAN.includePath[j] == repo) {
+                            return;
+                        }
+                    }
+                    JSAN.addRepository(repo);
+                }
+            }
+        }
+    }
+}
+JSAN._findMyPath();
+
+JSAN._convertPathToUrl = function (path, repository) {
+    return repository.concat('/' + path);
+};
+    
+
+JSAN._convertPackageToPath = function (pkg) {
+    var path = pkg.replace(/\./g, '/');
+        path = path.concat('.js');
+    return path;
+}
+
+JSAN._parseUseArgs = function () {
+    var pkg        = arguments[0];
+    var importList = [];
+
+    for (var i = 1; i < arguments.length; i++)
+        importList.push(arguments[i]);
+
+    return {
+        pkg:        pkg,
+        importList: importList
+    }
+}
+
+JSAN._loadJSFromUrl = function (url) {
+    return new JSAN.Request().getText(url);
+}
+
+JSAN._findExportInList = function (list, request) {
+    if (list == null) return false;
+    for (var i = 0; i < list.length; i++)
+        if (list[i] == request)
+            return true;
+    return false;
+}
+
+JSAN._findExportInTag = function (tags, request) {
+    if (tags == null) return [];
+    for (var i in tags)
+        if (i == request)
+            return tags[i];
+    return [];
+}
+
+JSAN._exportItems = function (classdef, importList) {
+    var exportList  = new Array();
+    var EXPORT      = classdef.EXPORT;
+    var EXPORT_OK   = classdef.EXPORT_OK;
+    var EXPORT_TAGS = classdef.EXPORT_TAGS;
+    
+    if (importList.length > 0) {
+       importList = JSAN._flatten( importList );
+
+       for (var i = 0; i < importList.length; i++) {
+            var request = importList[i];
+            if (   JSAN._findExportInList(EXPORT,    request)
+                || JSAN._findExportInList(EXPORT_OK, request)) {
+                exportList.push(request);
+                continue;
+            }
+            var list = JSAN._findExportInTag(EXPORT_TAGS, request);
+            for (var i = 0; i < list.length; i++) {
+                exportList.push(list[i]);
+            }
+        }
+    } else {
+        exportList = EXPORT;
+    }
+    JSAN._exportList(classdef, exportList);
+}
+
+JSAN._exportList = function (classdef, exportList) {
+    if (typeof(exportList) != 'object') return null;
+    for (var i = 0; i < exportList.length; i++) {
+        var name = exportList[i];
+
+        if (JSAN.globalScope[name] == null)
+            JSAN.globalScope[name] = classdef[name];
+    }
+}
+
+JSAN._makeNamespace = function(js, pkg) {
+    var spaces = pkg.split('.');
+    var parent = JSAN.globalScope;
+    eval(js);
+    var classdef = eval(pkg);
+    for (var i = 0; i < spaces.length; i++) {
+        var name = spaces[i];
+        if (i == spaces.length - 1) {
+            if (typeof parent[name] == 'undefined') {
+                parent[name] = classdef;
+                if ( typeof classdef['prototype'] != 'undefined' ) {
+                    parent[name].prototype = classdef.prototype;
+                }
+            }
+        } else {
+            if (parent[name] == undefined) {
+                parent[name] = {};
+            }
+        }
+
+        parent = parent[name];
+    }
+    return classdef;
+}
+
+JSAN._handleError = function (msg, level) {
+    if (!level) level = JSAN.errorLevel;
+    JSAN.errorMessage = msg;
+
+    switch (level) {
+        case "none":
+            break;
+        case "warn":
+            alert(msg);
+            break;
+        case "die":
+        default:
+            throw new Error(msg);
+            break;
+    }
+}
+
+JSAN._createScript = function (js, pkg) {
+    try {
+        return JSAN._makeNamespace(js, pkg);
+    } catch (e) {
+        JSAN._handleError("Could not create namespace[" + pkg + "]: " + e);
+    }
+    return null;
+}
+
+
+JSAN.prototype = {
+    use: function () { JSAN.use.apply(JSAN, arguments) }
+};
+
+
+// Low-Level HTTP Request
+JSAN.Request = function (jsan) {
+    if (JSAN.globalScope.XMLHttpRequest) {
+        this._req = new XMLHttpRequest();
+    } else {
+        this._req = new ActiveXObject("Microsoft.XMLHTTP");
+    }
+}
+
+JSAN.Request.prototype = {
+    _req:  null,
+    
+    getText: function (url) {
+        this._req.open("GET", url, false);
+        try {
+            this._req.send(null);
+            if (this._req.status == 200 || this._req.status == 0)
+                return this._req.responseText;
+        } catch (e) {
+            JSAN._handleError("File not found: " + url);
+            return null;
+        };
+
+        JSAN._handleError("File not found: " + url);
+        return null;
+    }
+};
+
+/*
+
+*/

Added: jifty/branches/jifty-jsan/share/web/static/js/jsan/Upgrade.js
==============================================================================
--- (empty file)
+++ jifty/branches/jifty-jsan/share/web/static/js/jsan/Upgrade.js	Sun Apr 23 12:15:37 2006
@@ -0,0 +1,121 @@
+/*
+Keep package scanners happy
+Upgrade.VERSION = 0.04;
+*/
+
+/*
+
+=head1 NAME
+
+Upgrade - Upgrade older JavaScript implementations to support newer features
+
+=head1 SYNOPSIS
+
+  // Upgrade Array.push if the client does not have it
+  JSAN.use("Upgrade.Array.push");
+
+=head1 DESCRIPTION
+
+Many many different JavaScript toolkits start with something like the following:
+
+  // Provides Array.push for implementations that don't have it
+  if ( ! Array.prototype.push ) {
+      Array.prototype.push = function () {
+          var l = this.length;
+          for ( var i = 0; i < arguments.length; i++ ) {
+              this[l+i] = arguments[i];
+          }
+          return this.length;
+      }
+  }
+
+These provide implementations of expected or required functions/classes
+for older JavaScript implementations that do not provide them natively,
+in effect "upgrading" the client at run-time.
+
+In fact, due to its flexibility JavaScript is a language ideally suited
+to this sort of behaviour.
+
+C<Upgrade> is a JSAN package that provides standard implementations for
+many of these standard functions. If your code relies on a particular
+function that you later find to be not as common as you might have
+initially thought, you can simply add a dependency on that function within
+the C<Upgrade> namespace, and if an implementation exists the standard code
+to implement it will be added it the current environment (when it doesn't
+already have it).
+
+Rather than one huge file that provides a "compatibility layer" and upgrades
+verything all at once, C<Upgrade> is broken down into a large number of
+maller .js files, each implementing one function or class.
+
+Generally these functions are ones defined in the ECMA standard, and those
+that aren't, such as C<HTMLHttpRequest> are not provided by Upgrade (as much
+as we would like to) :)
+
+=head1 USING UPGRADE
+
+The C<Upgrade> namespace acts as a parallel root to the global namespace.
+For any function you want to upgrade, you can then simply prepend
+C<"Upgrade"> to it.
+
+For example, to do the very common upgrade for the C<Array.push> function,
+you simply add C<JSAN.use("Upgrade.Array.push") to your module (or manually
+load the C<Upgrade/Array/push.js> file).
+
+One advantage of using these standard implementations rather than your own
+is that when a number of modules with C<Upgrade> depedencies are merged
+together by C<JSAN::Concat> or another package merger it results in only
+a single copy of the upgrading code at the appropriate place in the code.
+
+=head1 UPGRADABLE FUNCTIONS
+
+While implementations are provided seperately, rather than document them
+this way we will instead defined all functions available in the C<Upgrade>
+package here.
+
+=head2 Upgrade.Array.push
+
+This provides the same standard implementation of the instance method
+C<Array.push> (located at Array.prototype.push) as used by all of the
+major frameworks.
+
+=head2 Upgrade.Function.apply
+
+This provides a version of the instance method C<Function.apply>
+(located at C<Function.prototype.apply>) adapted from an implementation
+found in the L<Prototype> framework, which was itself adapted from an
+implementation found on L<http://www.youngpup.net/>.
+
+=head1 METHODS
+
+The C<Upgrade> module itself does not at this time provide any
+functionality, and only acts as a source of documentation.
+
+Likewise, nothing is ever actually created at or beneath the C<Upgrade>
+namespace, but serves as an address mechanism for determining which
+.js files to load. Each of these files only inserts functions into the
+core tree and do not create any additional useless namespace variables.
+
+=head1 SUPPORT
+
+Until the JSAN RT gains package-specific queues, bugs or new functions
+to add to Upgrade should be reported to the jsan-authors mailing list.
+
+For B<non-support> issues or questions, contact the author.
+
+=head1 AUTHOR
+
+Adam Kennedy <jsan at ali.as>, L<http://ali.as/>
+
+=head1 COPYRIGHT
+
+Copyright (c) 2005 Adam Kennedy. All rights reserved.
+This program is free software; you can redistribute it and/or modify
+it under the the terms of the Perl dual GPL/Artistic license.
+
+The full text of the license can be found in the
+LICENSE file included with this package
+
+=cut
+
+*/

Added: jifty/branches/jifty-jsan/share/web/static/js/jsan/Upgrade/Array/push.js
==============================================================================
--- (empty file)
+++ jifty/branches/jifty-jsan/share/web/static/js/jsan/Upgrade/Array/push.js	Sun Apr 23 12:15:37 2006
@@ -0,0 +1,14 @@
+/*
+Upgrade.Array.push.VERSION = 0.04;
+*/
+
+// Provides Array.push for implementations that don't have it
+if ( ! Array.prototype.push ) {
+	Array.prototype.push = function () {
+		var l = this.length;
+		for ( var i = 0; i < arguments.length; i++ ) {
+			this[l+i] = arguments[i];
+		}
+		return this.length;
+	}
+}

Added: jifty/branches/jifty-jsan/share/web/static/js/jsan/Upgrade/Function/apply.js
==============================================================================
--- (empty file)
+++ jifty/branches/jifty-jsan/share/web/static/js/jsan/Upgrade/Function/apply.js	Sun Apr 23 12:15:37 2006
@@ -0,0 +1,19 @@
+/*
+Upgrade.Function.Apply.VERSION = 0.04;
+*/
+// Adapted from a Prototype adaptation of code
+// originally from http://www.youngpup.net/
+if ( ! Function.prototype.apply ) {
+	Function.prototype.apply = function(o, p) {
+		var pstr = new Array();
+		if ( ! o ) o = window;
+		if ( ! p ) p = new Array();
+		for ( var i = 0; i < p.length; i++ ) {
+			pstr[i] = 'p[' + i + ']';
+		}
+    		o.__apply__ = this;
+		var rv = eval('o.__apply__(' + pstr[i].join(', ') + ')' );
+		o.__apply__ = null;
+		return rv;
+	}
+}

Modified: jifty/branches/jifty-jsan/share/web/templates/_elements/javascript
==============================================================================
--- jifty/branches/jifty-jsan/share/web/templates/_elements/javascript	(original)
+++ jifty/branches/jifty-jsan/share/web/templates/_elements/javascript	Sun Apr 23 12:15:37 2006
@@ -4,8 +4,16 @@
 my @libs = qw(
   /static/js/json.js
   /static/js/prototype.js
+  /static/js/jsan/Upgrade/Array/push.js
+  /static/js/jsan/DOM/Events.js
+  /static/js/cssquery/cssQuery.js
+  /static/js/cssquery/cssQuery-level2.js
+  /static/js/cssquery/cssQuery-level3.js
+  /static/js/cssquery/cssQuery-standard.js
   /static/js/behaviour.js
-  /static/js/scriptaculous/scriptaculous.js
+  /static/js/scriptaculous/builder.js
+  /static/js/scriptaculous/effects.js
+  /static/js/scriptaculous/controls.js
   /static/js/jifty.js
   /static/js/dom-drag.js
   /static/js/halo.js
@@ -17,6 +25,16 @@
 );
 
 </%init>
+   <script type="text/javascript">
+   /*
+      JSAN.errorLevel = 'warn';
+      JSAN.addRespository('/static/js');
+   */
+      JSAN = {};
+      JSAN.use = function() {};
+   </script>
+
 % for (@libs) {
    <script type="text/javascript" src="<%$_%>"></script>
 % }
+


More information about the Jifty-commit mailing list