[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