[Jifty-commit] r5535 - in jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism: .
Jifty commits
jifty-commit at lists.jifty.org
Fri Jun 27 10:35:32 EDT 2008
Author: clkao
Date: Fri Jun 27 10:34:57 2008
New Revision: 5535
Added:
jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/sound.js
Modified:
jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/prototype.js
jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/builder.js
jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/controls.js
jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/dragdrop.js
jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/effects.js
jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/scriptaculous.js
jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/slider.js
jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/unittest.js
Log:
upgrade prototypism's prototype to 1.6.0.2 and scriptaculous to 1.8.1,
which unbreaks the incompatibility with jQuery 1.2.6.
Modified: jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/prototype.js
==============================================================================
--- jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/prototype.js (original)
+++ jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/prototype.js Fri Jun 27 10:34:57 2008
@@ -1,5 +1,5 @@
-/* Prototype JavaScript framework, version 1.6.0
- * (c) 2005-2007 Sam Stephenson
+/* Prototype JavaScript framework, version 1.6.0.2
+ * (c) 2005-2008 Sam Stephenson
*
* Prototype is freely distributable under the terms of an MIT-style license.
* For details, see the Prototype web site: http://www.prototypejs.org/
@@ -7,7 +7,7 @@
*--------------------------------------------------------------------------*/
var Prototype = {
- Version: '1.6.0',
+ Version: '1.6.0.2',
Browser: {
IE: !!(window.attachEvent && !window.opera),
@@ -36,8 +36,6 @@
if (Prototype.Browser.MobileSafari)
Prototype.BrowserFeatures.SpecificElementExtensions = false;
-if (Prototype.Browser.WebKit)
- Prototype.BrowserFeatures.XPath = false;
/* Based on Alex Arnell's inheritance implementation. */
var Class = {
@@ -110,9 +108,9 @@
Object.extend(Object, {
inspect: function(object) {
try {
- if (object === undefined) return 'undefined';
+ if (Object.isUndefined(object)) return 'undefined';
if (object === null) return 'null';
- return object.inspect ? object.inspect() : object.toString();
+ return object.inspect ? object.inspect() : String(object);
} catch (e) {
if (e instanceof RangeError) return '...';
throw e;
@@ -135,7 +133,7 @@
var results = [];
for (var property in object) {
var value = Object.toJSON(object[property]);
- if (value !== undefined)
+ if (!Object.isUndefined(value))
results.push(property.toJSON() + ': ' + value);
}
@@ -173,7 +171,8 @@
},
isArray: function(object) {
- return object && object.constructor === Array;
+ return object != null && typeof object == "object" &&
+ 'splice' in object && 'join' in object;
},
isHash: function(object) {
@@ -204,7 +203,7 @@
},
bind: function() {
- if (arguments.length < 2 && arguments[0] === undefined) return this;
+ if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
var __method = this, args = $A(arguments), object = args.shift();
return function() {
return __method.apply(object, args.concat($A(arguments)));
@@ -351,7 +350,7 @@
sub: function(pattern, replacement, count) {
replacement = this.gsub.prepareReplacement(replacement);
- count = count === undefined ? 1 : count;
+ count = Object.isUndefined(count) ? 1 : count;
return this.gsub(pattern, function(match) {
if (--count < 0) return match[0];
@@ -366,7 +365,7 @@
truncate: function(length, truncation) {
length = length || 30;
- truncation = truncation === undefined ? '...' : truncation;
+ truncation = Object.isUndefined(truncation) ? '...' : truncation;
return this.length > length ?
this.slice(0, length - truncation.length) + truncation : String(this);
},
@@ -486,7 +485,9 @@
},
isJSON: function() {
- var str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
+ var str = this;
+ if (str.blank()) return false;
+ str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
},
@@ -565,7 +566,8 @@
if (before == '\\') return match[2];
var ctx = object, expr = match[3];
- var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/, match = pattern.exec(expr);
+ var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
+ match = pattern.exec(expr);
if (match == null) return before;
while (match != null) {
@@ -577,7 +579,7 @@
}
return before + String.interpret(ctx);
- }.bind(this));
+ });
}
});
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
@@ -686,7 +688,7 @@
},
inGroupsOf: function(number, fillWith) {
- fillWith = fillWith === undefined ? null : fillWith;
+ fillWith = Object.isUndefined(fillWith) ? null : fillWith;
return this.eachSlice(number, function(slice) {
while(slice.length < number) slice.push(fillWith);
return slice;
@@ -713,7 +715,7 @@
var result;
this.each(function(value, index) {
value = iterator(value, index);
- if (result == undefined || value >= result)
+ if (result == null || value >= result)
result = value;
});
return result;
@@ -724,7 +726,7 @@
var result;
this.each(function(value, index) {
value = iterator(value, index);
- if (result == undefined || value < result)
+ if (result == null || value < result)
result = value;
});
return result;
@@ -805,20 +807,20 @@
function $A(iterable) {
if (!iterable) return [];
if (iterable.toArray) return iterable.toArray();
- var length = iterable.length, results = new Array(length);
+ var length = iterable.length || 0, results = new Array(length);
while (length--) results[length] = iterable[length];
return results;
}
if (Prototype.Browser.WebKit) {
- function $A(iterable) {
+ $A = function(iterable) {
if (!iterable) return [];
if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') &&
iterable.toArray) return iterable.toArray();
- var length = iterable.length, results = new Array(length);
+ var length = iterable.length || 0, results = new Array(length);
while (length--) results[length] = iterable[length];
return results;
- }
+ };
}
Array.from = $A;
@@ -904,7 +906,7 @@
var results = [];
this.each(function(object) {
var value = Object.toJSON(object);
- if (value !== undefined) results.push(value);
+ if (!Object.isUndefined(value)) results.push(value);
});
return '[' + results.join(', ') + ']';
}
@@ -984,34 +986,6 @@
};
var Hash = Class.create(Enumerable, (function() {
- if (function() {
- var i = 0, Test = function(value) { this.key = value };
- Test.prototype.key = 'foo';
- for (var property in new Test('bar')) i++;
- return i > 1;
- }()) {
- function each(iterator) {
- var cache = [];
- for (var key in this._object) {
- var value = this._object[key];
- if (cache.include(key)) continue;
- cache.push(key);
- var pair = [key, value];
- pair.key = key;
- pair.value = value;
- iterator(pair);
- }
- }
- } else {
- function each(iterator) {
- for (var key in this._object) {
- var value = this._object[key], pair = [key, value];
- pair.key = key;
- pair.value = value;
- iterator(pair);
- }
- }
- }
function toQueryPair(key, value) {
if (Object.isUndefined(value)) return key;
@@ -1023,7 +997,14 @@
this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
},
- _each: each,
+ _each: function(iterator) {
+ for (var key in this._object) {
+ var value = this._object[key], pair = [key, value];
+ pair.key = key;
+ pair.value = value;
+ iterator(pair);
+ }
+ },
set: function(key, value) {
return this._object[key] = value;
@@ -1187,8 +1168,11 @@
Object.extend(this.options, options || { });
this.options.method = this.options.method.toLowerCase();
+
if (Object.isString(this.options.parameters))
this.options.parameters = this.options.parameters.toQueryParams();
+ else if (Object.isHash(this.options.parameters))
+ this.options.parameters = this.options.parameters.toObject();
}
});
@@ -1262,17 +1246,16 @@
};
if (this.method == 'post') {
- headers['Content-Type'] = this.options.contentType +
- (this.options.encoding ? '; charset=' + this.options.encoding : '');
+ headers['Content-type'] = this.options.contentType +
+ (this.options.encoding ? '; charset=' + this.options.encoding : '');
/* Force "Connection: close" for older Mozilla browsers to work
* around a bug where XMLHttpRequest sends an incorrect
* Content-length header. See Mozilla Bugzilla #246651.
*/
if (this.transport.overrideMimeType &&
- (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) {
+ (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
headers['Connection'] = 'close';
- }
}
// user-defined headers
@@ -1280,20 +1263,14 @@
var extras = this.options.requestHeaders;
if (Object.isFunction(extras.push))
- for (var i = 0, length = extras.length; i < length; i += 2) {
+ for (var i = 0, length = extras.length; i < length; i += 2)
headers[extras[i]] = extras[i+1];
- }
else
- $H(extras).each(function(pair) {
- headers[pair.key] = pair.value
- });
- }
-
- for (var name in headers) {
- if ( typeof headers[name] == "string" )
- this.transport.setRequestHeader(name, headers[name]);
+ $H(extras).each(function(pair) { headers[pair.key] = pair.value });
}
+ for (var name in headers)
+ this.transport.setRequestHeader(name, headers[name]);
},
success: function() {
@@ -1322,7 +1299,7 @@
var contentType = response.getHeader('Content-type');
if (this.options.evalJS == 'force'
- || (this.options.evalJS && contentType
+ || (this.options.evalJS && this.isSameOrigin() && contentType
&& contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
this.evalResponse();
}
@@ -1340,9 +1317,18 @@
}
},
+ isSameOrigin: function() {
+ var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
+ return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
+ protocol: location.protocol,
+ domain: document.domain,
+ port: location.port ? ':' + location.port : ''
+ }));
+ },
+
getHeader: function(name) {
try {
- return this.transport.getResponseHeader(name);
+ return this.transport.getResponseHeader(name) || null;
} catch (e) { return null }
},
@@ -1378,7 +1364,7 @@
if(readyState == 4) {
var xml = transport.responseXML;
- this.responseXML = xml === undefined ? null : xml;
+ this.responseXML = Object.isUndefined(xml) ? null : xml;
this.responseJSON = this._getResponseJSON();
}
},
@@ -1415,7 +1401,8 @@
if (!json) return null;
json = decodeURIComponent(escape(json));
try {
- return json.evalJSON(this.request.options.sanitizeJSON);
+ return json.evalJSON(this.request.options.sanitizeJSON ||
+ !this.request.isSameOrigin());
} catch (e) {
this.request.dispatchException(e);
}
@@ -1424,10 +1411,12 @@
_getResponseJSON: function() {
var options = this.request.options;
if (!options.evalJSON || (options.evalJSON != 'force' &&
- !(this.getHeader('Content-type') || '').include('application/json')))
- return null;
+ !(this.getHeader('Content-type') || '').include('application/json')) ||
+ this.responseText.blank())
+ return null;
try {
- return this.transport.responseText.evalJSON(options.sanitizeJSON);
+ return this.responseText.evalJSON(options.sanitizeJSON ||
+ !this.request.isSameOrigin());
} catch (e) {
this.request.dispatchException(e);
}
@@ -1441,11 +1430,11 @@
failure: (container.failure || (container.success ? null : container))
};
- options = options || { };
+ options = Object.clone(options);
var onComplete = options.onComplete;
- options.onComplete = (function(response, param) {
+ options.onComplete = (function(response, json) {
this.updateContent(response.responseText);
- if (Object.isFunction(onComplete)) onComplete(response, param);
+ if (Object.isFunction(onComplete)) onComplete(response, json);
}).bind(this);
$super(url, options);
@@ -1467,10 +1456,6 @@
}
else receiver.update(responseText);
}
-
- if (this.success()) {
- if (this.onComplete) this.onComplete.bind(this).defer();
- }
}
});
@@ -1635,25 +1620,28 @@
Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
insertions = {bottom:insertions};
- var content, t, range;
+ var content, insert, tagName, childNodes;
- for (position in insertions) {
- if ( position == 'extend' ) continue;
+ for (var position in insertions) {
content = insertions[position];
position = position.toLowerCase();
- t = Element._insertionTranslations[position];
+ insert = Element._insertionTranslations[position];
if (content && content.toElement) content = content.toElement();
if (Object.isElement(content)) {
- t.insert(element, content);
+ insert(element, content);
continue;
}
content = Object.toHTML(content);
- range = element.ownerDocument.createRange();
- t.initializeRange(element, range);
- t.insert(element, range.createContextualFragment(content.stripScripts()));
+ tagName = ((position == 'before' || position == 'after')
+ ? element.parentNode : element).tagName.toUpperCase();
+
+ childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
+
+ if (position == 'top' || position == 'after') childNodes.reverse();
+ childNodes.each(insert.curry(element));
content.evalScripts.bind(content).defer();
}
@@ -1698,7 +1686,7 @@
},
descendants: function(element) {
- return $A($(element).getElementsByTagName('*')).each(Element.extend);
+ return $(element).select("*");
},
firstDescendant: function(element) {
@@ -1737,32 +1725,31 @@
element = $(element);
if (arguments.length == 1) return $(element.parentNode);
var ancestors = element.ancestors();
- return expression ? Selector.findElement(ancestors, expression, index) :
- ancestors[index || 0];
+ return Object.isNumber(expression) ? ancestors[expression] :
+ Selector.findElement(ancestors, expression, index);
},
down: function(element, expression, index) {
element = $(element);
if (arguments.length == 1) return element.firstDescendant();
- var descendants = element.descendants();
- return expression ? Selector.findElement(descendants, expression, index) :
- descendants[index || 0];
+ return Object.isNumber(expression) ? element.descendants()[expression] :
+ element.select(expression)[index || 0];
},
previous: function(element, expression, index) {
element = $(element);
if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
var previousSiblings = element.previousSiblings();
- return expression ? Selector.findElement(previousSiblings, expression, index) :
- previousSiblings[index || 0];
+ return Object.isNumber(expression) ? previousSiblings[expression] :
+ Selector.findElement(previousSiblings, expression, index);
},
next: function(element, expression, index) {
element = $(element);
if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
var nextSiblings = element.nextSiblings();
- return expression ? Selector.findElement(nextSiblings, expression, index) :
- nextSiblings[index || 0];
+ return Object.isNumber(expression) ? nextSiblings[expression] :
+ Selector.findElement(nextSiblings, expression, index);
},
select: function() {
@@ -1803,10 +1790,11 @@
var attributes = { }, t = Element._attributeTranslations.write;
if (typeof name == 'object') attributes = name;
- else attributes[name] = value === undefined ? true : value;
+ else attributes[name] = Object.isUndefined(value) ? true : value;
for (var attr in attributes) {
- var name = t.names[attr] || attr, value = attributes[attr];
+ name = t.names[attr] || attr;
+ value = attributes[attr];
if (t.values[attr]) name = t.values[attr](element, value);
if (value === false || value === null)
element.removeAttribute(name);
@@ -1875,6 +1863,7 @@
descendantOf: function(element, ancestor) {
element = $(element), ancestor = $(ancestor);
+ var originalAncestor = ancestor;
if (element.compareDocumentPosition)
return (element.compareDocumentPosition(ancestor) & 8) === 8;
@@ -1886,11 +1875,12 @@
do { ancestor = ancestor.parentNode; }
while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode);
}
- if (nextAncestor) return (e > a && e < nextAncestor.sourceIndex);
+ if (nextAncestor && nextAncestor.sourceIndex)
+ return (e > a && e < nextAncestor.sourceIndex);
}
while (element = element.parentNode)
- if (element == ancestor) return true;
+ if (element == originalAncestor) return true;
return false;
},
@@ -1929,7 +1919,7 @@
if (property == 'opacity') element.setOpacity(styles[property]);
else
elementStyle[(property == 'float' || property == 'cssFloat') ?
- (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') :
+ (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :
property] = styles[property];
return element;
@@ -2030,7 +2020,7 @@
if (element) {
if (element.tagName == 'BODY') break;
var p = Element.getStyle(element, 'position');
- if (p == 'relative' || p == 'absolute') break;
+ if (p !== 'static') break;
}
} while (element);
return Element._returnOffset(valueL, valueT);
@@ -2179,76 +2169,75 @@
}
};
-
-if (!document.createRange || Prototype.Browser.Opera) {
- Element.Methods.insert = function(element, insertions) {
- element = $(element);
-
- if (Object.isString(insertions) || Object.isNumber(insertions) ||
- Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
- insertions = { bottom: insertions };
-
- var t = Element._insertionTranslations, content, position, pos, tagName;
-
- for (position in insertions) {
- content = insertions[position];
- position = position.toLowerCase();
- pos = t[position];
-
- if (content && content.toElement) content = content.toElement();
- if (Object.isElement(content)) {
- pos.insert(element, content);
- continue;
- }
-
- content = Object.toHTML(content);
- tagName = ((position == 'before' || position == 'after')
- ? element.parentNode : element).tagName.toUpperCase();
-
- if (t.tags[tagName]) {
- var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
- if (position == 'top' || position == 'after') fragments.reverse();
- fragments.each(pos.insert.curry(element));
- }
- // Sartak: pos.adjacency may be undefined. IE6 gets very unhappy if you
- // try to pass undef to insertAdjacentHTML
- else if (pos.adjacency) {
- element.insertAdjacentHTML(pos.adjacency, content.stripScripts());
+if (Prototype.Browser.Opera) {
+ Element.Methods.getStyle = Element.Methods.getStyle.wrap(
+ function(proceed, element, style) {
+ switch (style) {
+ case 'left': case 'top': case 'right': case 'bottom':
+ if (proceed(element, 'position') === 'static') return null;
+ case 'height': case 'width':
+ // returns '0px' for hidden elements; we want it to return null
+ if (!Element.visible(element)) return null;
+
+ // returns the border-box dimensions rather than the content-box
+ // dimensions, so we subtract padding and borders from the value
+ var dim = parseInt(proceed(element, style), 10);
+
+ if (dim !== element['offset' + style.capitalize()])
+ return dim + 'px';
+
+ var properties;
+ if (style === 'height') {
+ properties = ['border-top-width', 'padding-top',
+ 'padding-bottom', 'border-bottom-width'];
+ }
+ else {
+ properties = ['border-left-width', 'padding-left',
+ 'padding-right', 'border-right-width'];
+ }
+ return properties.inject(dim, function(memo, property) {
+ var val = proceed(element, property);
+ return val === null ? memo : memo - parseInt(val, 10);
+ }) + 'px';
+ default: return proceed(element, style);
}
-
- content.evalScripts.bind(content).defer();
}
+ );
- return element;
- };
-}
-
-if (Prototype.Browser.Opera) {
- Element.Methods._getStyle = Element.Methods.getStyle;
- Element.Methods.getStyle = function(element, style) {
- switch(style) {
- case 'left':
- case 'top':
- case 'right':
- case 'bottom':
- if (Element._getStyle(element, 'position') == 'static') return null;
- default: return Element._getStyle(element, style);
+ Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(
+ function(proceed, element, attribute) {
+ if (attribute === 'title') return element.title;
+ return proceed(element, attribute);
}
- };
- Element.Methods._readAttribute = Element.Methods.readAttribute;
- Element.Methods.readAttribute = function(element, attribute) {
- if (attribute == 'title') return element.title;
- return Element._readAttribute(element, attribute);
- };
+ );
}
else if (Prototype.Browser.IE) {
- $w('positionedOffset getOffsetParent viewportOffset').each(function(method) {
+ // IE doesn't report offsets correctly for static elements, so we change them
+ // to "relative" to get the values, then change them back.
+ Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(
+ function(proceed, element) {
+ element = $(element);
+ var position = element.getStyle('position');
+ if (position !== 'static') return proceed(element);
+ element.setStyle({ position: 'relative' });
+ var value = proceed(element);
+ element.setStyle({ position: position });
+ return value;
+ }
+ );
+
+ $w('positionedOffset viewportOffset').each(function(method) {
Element.Methods[method] = Element.Methods[method].wrap(
function(proceed, element) {
element = $(element);
var position = element.getStyle('position');
- if (position != 'static') return proceed(element);
+ if (position !== 'static') return proceed(element);
+ // Trigger hasLayout on the offset parent so that IE6 reports
+ // accurate offsetTop and offsetLeft values for position: fixed.
+ var offsetParent = element.getOffsetParent();
+ if (offsetParent && offsetParent.getStyle('position') === 'fixed')
+ offsetParent.setStyle({ zoom: 1 });
element.setStyle({ position: 'relative' });
var value = proceed(element);
element.setStyle({ position: position });
@@ -2313,7 +2302,7 @@
return node ? node.value : "";
},
_getEv: function(element, attribute) {
- var attribute = element.getAttribute(attribute);
+ attribute = element.getAttribute(attribute);
return attribute ? attribute.toString().slice(23, -2) : null;
},
_flag: function(element, attribute) {
@@ -2330,7 +2319,10 @@
};
Element._attributeTranslations.write = {
- names: Object.clone(Element._attributeTranslations.read.names),
+ names: Object.extend({
+ cellpadding: 'cellPadding',
+ cellspacing: 'cellSpacing'
+ }, Element._attributeTranslations.read.names),
values: {
checked: function(element, value) {
element.checked = !!value;
@@ -2410,7 +2402,7 @@
};
// Safari returns margins on body which is incorrect if the child is absolutely
- // positioned. For performance reasons, redefine Position.cumulativeOffset for
+ // positioned. For performance reasons, redefine Element#cumulativeOffset for
// KHTML/WebKit only.
Element.Methods.cumulativeOffset = function(element) {
var valueT = 0, valueL = 0;
@@ -2450,7 +2442,7 @@
};
}
-if (document.createElement('div').outerHTML) {
+if ('outerHTML' in document.createElement('div')) {
Element.Methods.replace = function(element, content) {
element = $(element);
@@ -2488,45 +2480,25 @@
Element._getContentFromAnonymousElement = function(tagName, html) {
var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];
- div.innerHTML = t[0] + html + t[1];
- t[2].times(function() { div = div.firstChild });
+ if (t) {
+ div.innerHTML = t[0] + html + t[1];
+ t[2].times(function() { div = div.firstChild });
+ } else div.innerHTML = html;
return $A(div.childNodes);
};
Element._insertionTranslations = {
- before: {
- adjacency: 'beforeBegin',
- insert: function(element, node) {
- element.parentNode.insertBefore(node, element);
- },
- initializeRange: function(element, range) {
- range.setStartBefore(element);
- }
+ before: function(element, node) {
+ element.parentNode.insertBefore(node, element);
},
- top: {
- adjacency: 'afterBegin',
- insert: function(element, node) {
- element.insertBefore(node, element.firstChild);
- },
- initializeRange: function(element, range) {
- range.selectNodeContents(element);
- range.collapse(true);
- }
+ top: function(element, node) {
+ element.insertBefore(node, element.firstChild);
},
- bottom: {
- adjacency: 'beforeEnd',
- insert: function(element, node) {
- element.appendChild(node);
- }
+ bottom: function(element, node) {
+ element.appendChild(node);
},
- after: {
- adjacency: 'afterEnd',
- insert: function(element, node) {
- element.parentNode.insertBefore(node, element.nextSibling);
- },
- initializeRange: function(element, range) {
- range.setStartAfter(element);
- }
+ after: function(element, node) {
+ element.parentNode.insertBefore(node, element.nextSibling);
},
tags: {
TABLE: ['<table>', '</table>', 1],
@@ -2538,7 +2510,6 @@
};
(function() {
- this.bottom.initializeRange = this.top.initializeRange;
Object.extend(this.tags, {
THEAD: this.tags.TBODY,
TFOOT: this.tags.TBODY,
@@ -2645,8 +2616,7 @@
onlyIfAbsent = onlyIfAbsent || false;
for (var property in methods) {
var value = methods[property];
- // don't copy update, temporarily
- if (!Object.isFunction(value) || property == 'update') continue;
+ if (!Object.isFunction(value)) continue;
if (!onlyIfAbsent || !(property in destination))
destination[property] = value.methodize();
}
@@ -2700,10 +2670,11 @@
document.viewport = {
getDimensions: function() {
var dimensions = { };
+ var B = Prototype.Browser;
$w('width height').each(function(d) {
var D = d.capitalize();
- dimensions[d] = self['inner' + D] ||
- (document.documentElement['client' + D] || document.body['client' + D]);
+ dimensions[d] = (B.WebKit && !document.evaluate) ? self['inner' + D] :
+ (B.Opera) ? document.body['client' + D] : document.documentElement['client' + D];
});
return dimensions;
},
@@ -2732,9 +2703,26 @@
this.compileMatcher();
},
+ shouldUseXPath: function() {
+ if (!Prototype.BrowserFeatures.XPath) return false;
+
+ var e = this.expression;
+
+ // Safari 3 chokes on :*-of-type and :empty
+ if (Prototype.Browser.WebKit &&
+ (e.include("-of-type") || e.include(":empty")))
+ return false;
+
+ // XPath can't do namespaced attributes, nor can it read
+ // the "checked" property from DOM nodes
+ if ((/(\[[\w-]*?:|:checked)/).test(this.expression))
+ return false;
+
+ return true;
+ },
+
compileMatcher: function() {
- // Selectors with namespaced attributes can't use the XPath version
- if (Prototype.BrowserFeatures.XPath && !(/(\[[\w-]*?:|:checked)/).test(this.expression))
+ if (this.shouldUseXPath())
return this.compileXPathMatcher();
var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
@@ -2857,8 +2845,12 @@
},
className: "[contains(concat(' ', @class, ' '), ' #{1} ')]",
id: "[@id='#{1}']",
- attrPresence: "[@#{1}]",
+ attrPresence: function(m) {
+ m[1] = m[1].toLowerCase();
+ return new Template("[@#{1}]").evaluate(m);
+ },
attr: function(m) {
+ m[1] = m[1].toLowerCase();
m[3] = m[5] || m[6];
return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
},
@@ -2887,7 +2879,7 @@
'enabled': "[not(@disabled)]",
'not': function(m) {
var e = m[6], p = Selector.patterns,
- x = Selector.xpath, le, m, v;
+ x = Selector.xpath, le, v;
var exclusion = [];
while (e && le != e && (/\S/).test(e)) {
@@ -2944,13 +2936,13 @@
},
criteria: {
- tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',
- className: 'n = h.className(n, r, "#{1}", c); c = false;',
- id: 'n = h.id(n, r, "#{1}", c); c = false;',
- attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;',
+ tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',
+ className: 'n = h.className(n, r, "#{1}", c); c = false;',
+ id: 'n = h.id(n, r, "#{1}", c); c = false;',
+ attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;',
attr: function(m) {
m[3] = (m[5] || m[6]);
- return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
+ return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m);
},
pseudo: function(m) {
if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
@@ -2974,7 +2966,8 @@
tagName: /^\s*(\*|[\w\-]+)(\b|$)?/,
id: /^#([\w\-\*]+)(\b|$)/,
className: /^\.([\w\-\*]+)(\b|$)/,
- pseudo: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s)|(?=:))/,
+ pseudo:
+/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/,
attrPresence: /^\[([\w]+)\]/,
attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/
},
@@ -2999,7 +2992,7 @@
attr: function(element, matches) {
var nodeValue = Element.readAttribute(element, matches[1]);
- return Selector.operators[matches[2]](nodeValue, matches[3]);
+ return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]);
}
},
@@ -3014,14 +3007,15 @@
// marks an array of nodes for counting
mark: function(nodes) {
+ var _true = Prototype.emptyFunction;
for (var i = 0, node; node = nodes[i]; i++)
- node._counted = true;
+ node._countedByPrototype = _true;
return nodes;
},
unmark: function(nodes) {
for (var i = 0, node; node = nodes[i]; i++)
- node._counted = undefined;
+ node._countedByPrototype = undefined;
return nodes;
},
@@ -3029,15 +3023,15 @@
// "ofType" flag indicates whether we're indexing for nth-of-type
// rather than nth-child
index: function(parentNode, reverse, ofType) {
- parentNode._counted = true;
+ parentNode._countedByPrototype = Prototype.emptyFunction;
if (reverse) {
for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
var node = nodes[i];
- if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
+ if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
}
} else {
for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
- if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
+ if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
}
},
@@ -3046,8 +3040,8 @@
if (nodes.length == 0) return nodes;
var results = [], n;
for (var i = 0, l = nodes.length; i < l; i++)
- if (!(n = nodes[i])._counted) {
- n._counted = true;
+ if (!(n = nodes[i])._countedByPrototype) {
+ n._countedByPrototype = Prototype.emptyFunction;
results.push(Element.extend(n));
}
return Selector.handlers.unmark(results);
@@ -3064,7 +3058,7 @@
child: function(nodes) {
var h = Selector.handlers;
for (var i = 0, results = [], node; node = nodes[i]; i++) {
- for (var j = 0, children = [], child; child = node.childNodes[j]; j++)
+ for (var j = 0, child; child = node.childNodes[j]; j++)
if (child.nodeType == 1 && child.tagName != '!') results.push(child);
}
return results;
@@ -3099,7 +3093,7 @@
// TOKEN FUNCTIONS
tagName: function(nodes, root, tagName, combinator) {
- tagName = tagName.toUpperCase();
+ var uTagName = tagName.toUpperCase();
var results = [], h = Selector.handlers;
if (nodes) {
if (combinator) {
@@ -3112,7 +3106,7 @@
if (tagName == "*") return nodes;
}
for (var i = 0, node; node = nodes[i]; i++)
- if (node.tagName.toUpperCase() == tagName) results.push(node);
+ if (node.tagName.toUpperCase() === uTagName) results.push(node);
return results;
} else return root.getElementsByTagName(tagName);
},
@@ -3159,16 +3153,18 @@
return results;
},
- attrPresence: function(nodes, root, attr) {
+ attrPresence: function(nodes, root, attr, combinator) {
if (!nodes) nodes = root.getElementsByTagName("*");
+ if (nodes && combinator) nodes = this[combinator](nodes);
var results = [];
for (var i = 0, node; node = nodes[i]; i++)
if (Element.hasAttribute(node, attr)) results.push(node);
return results;
},
- attr: function(nodes, root, attr, value, operator) {
+ attr: function(nodes, root, attr, value, operator, combinator) {
if (!nodes) nodes = root.getElementsByTagName("*");
+ if (nodes && combinator) nodes = this[combinator](nodes);
var handler = Selector.operators[operator], results = [];
for (var i = 0, node; node = nodes[i]; i++) {
var nodeValue = Element.readAttribute(node, attr);
@@ -3247,7 +3243,7 @@
var h = Selector.handlers, results = [], indexed = [], m;
h.mark(nodes);
for (var i = 0, node; node = nodes[i]; i++) {
- if (!node.parentNode._counted) {
+ if (!node.parentNode._countedByPrototype) {
h.index(node.parentNode, reverse, ofType);
indexed.push(node.parentNode);
}
@@ -3285,7 +3281,7 @@
var exclusions = new Selector(selector).findElements(root);
h.mark(exclusions);
for (var i = 0, results = [], node; node = nodes[i]; i++)
- if (!node._counted) results.push(node);
+ if (!node._countedByPrototype) results.push(node);
h.unmark(exclusions);
return results;
},
@@ -3319,11 +3315,19 @@
'|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
},
+ split: function(expression) {
+ var expressions = [];
+ expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
+ expressions.push(m[1].strip());
+ });
+ return expressions;
+ },
+
matchElements: function(elements, expression) {
- var matches = new Selector(expression).findElements(), h = Selector.handlers;
+ var matches = $$(expression), h = Selector.handlers;
h.mark(matches);
for (var i = 0, results = [], element; element = elements[i]; i++)
- if (element._counted) results.push(element);
+ if (element._countedByPrototype) results.push(element);
h.unmark(matches);
return results;
},
@@ -3336,10 +3340,7 @@
},
findChildElements: function(element, expressions) {
- var exprs = expressions.join(','), expressions = [];
- exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
- expressions.push(m[1].strip());
- });
+ expressions = Selector.split(expressions.join(','));
var results = [], h = Selector.handlers;
for (var i = 0, l = expressions.length, selector; i < l; i++) {
selector = new Selector(expressions[i].strip());
@@ -3349,6 +3350,25 @@
}
});
+if (Prototype.Browser.IE) {
+ Object.extend(Selector.handlers, {
+ // IE returns comment nodes on getElementsByTagName("*").
+ // Filter them out.
+ concat: function(a, b) {
+ for (var i = 0, node; node = b[i]; i++)
+ if (node.tagName !== "!") a.push(node);
+ return a;
+ },
+
+ // IE improperly serializes _countedByPrototype in (inner|outer)HTML.
+ unmark: function(nodes) {
+ for (var i = 0, node; node = nodes[i]; i++)
+ node.removeAttribute('_countedByPrototype');
+ return nodes;
+ }
+ });
+}
+
function $$() {
return Selector.findChildElements(document, $A(arguments));
}
@@ -3360,7 +3380,7 @@
serializeElements: function(elements, options) {
if (typeof options != 'object') options = { hash: !!options };
- else if (options.hash === undefined) options.hash = true;
+ else if (Object.isUndefined(options.hash)) options.hash = true;
var key, value, submitted = false, submit = options.submit;
var data = elements.inject({ }, function(result, element) {
@@ -3484,16 +3504,9 @@
if (!element.disabled && element.name) {
var value = element.getValue();
if (value != undefined) {
- // XXX: Jifty: this used to be:
- // var pair = { };
- // pair[element.name] = value
- // return Object.toQueryString(pair)
- // but that included the pair.extend function, which occurred
- // a lot whenever we validated an action. since we're only encoding
- // the key (element.name) and value, do what we actually mean
- return encodeURIComponent(element.name)
- + '='
- + encodeURIComponent(value);
+ var pair = { };
+ pair[element.name] = value;
+ return Object.toQueryString(pair);
}
}
return '';
@@ -3565,17 +3578,17 @@
},
inputSelector: function(element, value) {
- if (value === undefined) return element.checked ? element.value : null;
+ if (Object.isUndefined(value)) return element.checked ? element.value : null;
else element.checked = !!value;
},
textarea: function(element, value) {
- if (value === undefined) return element.value;
+ if (Object.isUndefined(value)) return element.value;
else element.value = value;
},
select: function(element, index) {
- if (index === undefined)
+ if (Object.isUndefined(index))
return this[element.type == 'select-one' ?
'selectOne' : 'selectMany'](element);
else {
@@ -3766,7 +3779,9 @@
findElement: function(event, expression) {
var element = Event.element(event);
- return element.match(expression) ? element : element.up(expression);
+ if (!expression) return element;
+ var elements = [element].concat(element.ancestors());
+ return Selector.findElement(elements, expression, 0);
},
pointer: function(event) {
@@ -3829,9 +3844,9 @@
var cache = Event.cache;
function getEventID(element) {
- if (element._eventID) return element._eventID;
+ if (element._prototypeEventID) return element._prototypeEventID[0];
arguments.callee.id = arguments.callee.id || 1;
- return element._eventID = ++arguments.callee.id;
+ return element._prototypeEventID = [++arguments.callee.id];
}
function getDOMEventName(eventName) {
@@ -3859,7 +3874,7 @@
return false;
Event.extend(event);
- handler.call(element, event)
+ handler.call(element, event);
};
wrapper.handler = handler;
@@ -3941,11 +3956,12 @@
if (element == document && document.createEvent && !element.dispatchEvent)
element = document.documentElement;
+ var event;
if (document.createEvent) {
- var event = document.createEvent("HTMLEvents");
+ event = document.createEvent("HTMLEvents");
event.initEvent("dataavailable", true, true);
} else {
- var event = document.createEventObject();
+ event = document.createEventObject();
event.eventType = "ondataavailable";
}
@@ -3958,7 +3974,7 @@
element.fireEvent(event.eventType, event);
}
- return event;
+ return Event.extend(event);
}
};
})());
@@ -3974,20 +3990,21 @@
Object.extend(document, {
fire: Element.Methods.fire.methodize(),
observe: Element.Methods.observe.methodize(),
- stopObserving: Element.Methods.stopObserving.methodize()
+ stopObserving: Element.Methods.stopObserving.methodize(),
+ loaded: false
});
(function() {
/* Support for the DOMContentLoaded event is based on work by Dan Webb,
Matthias Miller, Dean Edwards and John Resig. */
- var timer, fired = false;
+ var timer;
function fireContentLoadedEvent() {
- if (fired) return;
+ if (document.loaded) return;
if (timer) window.clearInterval(timer);
document.fire("dom:loaded");
- fired = true;
+ document.loaded = true;
}
if (document.addEventListener) {
@@ -4201,4 +4218,4 @@
/*--------------------------------------------------------------------------*/
-Element.addMethods();
+Element.addMethods();
\ No newline at end of file
Modified: jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/builder.js
==============================================================================
--- jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/builder.js (original)
+++ jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/builder.js Fri Jun 27 10:34:57 2008
@@ -1,6 +1,9 @@
-// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// script.aculo.us builder.js v1.8.1, Thu Jan 03 22:07:12 -0500 2008
+
+// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//
-// See scriptaculous.js for full license.
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
var Builder = {
NODEMAP: {
@@ -33,7 +36,7 @@
var element = parentElement.firstChild || null;
// see if browser added wrapping tags
- if(element && (element.tagName != elementName))
+ if(element && (element.tagName.toUpperCase() != elementName))
element = element.getElementsByTagName(elementName)[0];
// fallback to createElement approach
@@ -45,7 +48,8 @@
// attributes (or text)
if(arguments[1])
if(this._isStringOrNumber(arguments[1]) ||
- (arguments[1] instanceof Array)) {
+ (arguments[1] instanceof Array) ||
+ arguments[1].tagName) {
this._children(element, arguments[1]);
} else {
var attrs = this._attributes(arguments[1]);
@@ -61,9 +65,9 @@
for(attr in arguments[1])
element[attr == 'class' ? 'className' : attr] = arguments[1][attr];
}
- if(element.tagName != elementName)
+ if(element.tagName.toUpperCase() != elementName)
element = parentElement.getElementsByTagName(elementName)[0];
- }
+ }
}
// text, or array of children
@@ -75,14 +79,24 @@
_text: function(text) {
return document.createTextNode(text);
},
+
+ ATTR_MAP: {
+ 'className': 'class',
+ 'htmlFor': 'for'
+ },
+
_attributes: function(attributes) {
var attrs = [];
for(attribute in attributes)
- attrs.push((attribute=='className' ? 'class' : attribute) +
- '="' + attributes[attribute].toString().escapeHTML() + '"');
+ attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) +
+ '="' + attributes[attribute].toString().escapeHTML().gsub(/"/,'"') + '"');
return attrs.join(" ");
},
_children: function(element, children) {
+ if(children.tagName) {
+ element.appendChild(children);
+ return;
+ }
if(typeof children=='object') { // array can hold nodes and text
children.flatten().each( function(e) {
if(typeof e=='object')
@@ -92,10 +106,31 @@
element.appendChild(Builder._text(e));
});
} else
- if(Builder._isStringOrNumber(children))
- element.appendChild(Builder._text(children));
+ if(Builder._isStringOrNumber(children))
+ element.appendChild(Builder._text(children));
},
_isStringOrNumber: function(param) {
return(typeof param=='string' || typeof param=='number');
+ },
+ build: function(html) {
+ var element = this.node('div');
+ $(element).update(html.strip());
+ return element.down();
+ },
+ dump: function(scope) {
+ if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope
+
+ var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " +
+ "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " +
+ "FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+
+ "KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+
+ "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+
+ "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);
+
+ tags.each( function(tag){
+ scope[tag] = function() {
+ return Builder.node.apply(Builder, [tag].concat($A(arguments)));
+ }
+ });
}
-}
\ No newline at end of file
+}
Modified: jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/controls.js
==============================================================================
--- jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/controls.js (original)
+++ jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/controls.js Fri Jun 27 10:34:57 2008
@@ -1,12 +1,15 @@
-// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
-// (c) 2005 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
-// (c) 2005 Jon Tirsen (http://www.tirsen.com)
+// script.aculo.us controls.js v1.8.1, Thu Jan 03 22:07:12 -0500 2008
+
+// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// (c) 2005-2007 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
+// (c) 2005-2007 Jon Tirsen (http://www.tirsen.com)
// Contributors:
// Richard Livsey
// Rahul Bhargava
// Rob Wills
//
-// See scriptaculous.js for full license.
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
// Autocompleter.Base handles all the autocompletion functionality
// that's independent of the data source for autocompletion. This
@@ -33,40 +36,50 @@
// useful when one of the tokens is \n (a newline), as it
// allows smart autocompletion after linebreaks.
-var Autocompleter = {}
-Autocompleter.Base = function() {};
-Autocompleter.Base.prototype = {
+if(typeof Effect == 'undefined')
+ throw("controls.js requires including script.aculo.us' effects.js library");
+
+var Autocompleter = { }
+Autocompleter.Base = Class.create({
baseInitialize: function(element, update, options) {
- this.element = $(element);
+ element = $(element)
+ this.element = element;
this.update = $(update);
this.hasFocus = false;
this.changed = false;
this.active = false;
this.index = 0;
this.entryCount = 0;
+ this.oldElementValue = this.element.value;
- if (this.setOptions)
+ if(this.setOptions)
this.setOptions(options);
else
- this.options = options || {};
+ this.options = options || { };
this.options.paramName = this.options.paramName || this.element.name;
this.options.tokens = this.options.tokens || [];
this.options.frequency = this.options.frequency || 0.4;
this.options.minChars = this.options.minChars || 1;
this.options.onShow = this.options.onShow ||
- function(element, update){
- if(!update.style.position || update.style.position=='absolute') {
- update.style.position = 'absolute';
- Position.clone(element, update, {setHeight: false, offsetTop: element.offsetHeight});
- }
- Effect.Appear(update,{duration:0.15});
- };
+ function(element, update){
+ if(!update.style.position || update.style.position=='absolute') {
+ update.style.position = 'absolute';
+ Position.clone(element, update, {
+ setHeight: false,
+ offsetTop: element.offsetHeight
+ });
+ }
+ Effect.Appear(update,{duration:0.15});
+ };
this.options.onHide = this.options.onHide ||
- function(element, update){ new Effect.Fade(update,{duration:0.15}) };
+ function(element, update){ new Effect.Fade(update,{duration:0.15}) };
- if (typeof(this.options.tokens) == 'string')
+ if(typeof(this.options.tokens) == 'string')
this.options.tokens = new Array(this.options.tokens);
+ // Force carriage returns as token delimiters anyway
+ if (!this.options.tokens.include('\n'))
+ this.options.tokens.push('\n');
this.observer = null;
@@ -74,18 +87,14 @@
Element.hide(this.update);
- Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this));
- Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this));
+ Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));
+ Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this));
},
show: function() {
- /* Next line added by TRS, 07 July 2006 */
- if ( this.options.beforeShow ) this.options.beforeShow(this);
-
if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
if(!this.iefix &&
- (navigator.appVersion.indexOf('MSIE')>0) &&
- (navigator.userAgent.indexOf('Opera')<0) &&
+ (Prototype.Browser.IE) &&
(Element.getStyle(this.update, 'position')=='absolute')) {
new Insertion.After(this.update,
'<iframe id="' + this.update.id + '_iefix" '+
@@ -97,16 +106,13 @@
},
fixIEOverlapping: function() {
- Position.clone(this.update, this.iefix);
+ Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
this.iefix.style.zIndex = 1;
this.update.style.zIndex = 2;
Element.show(this.iefix);
},
hide: function() {
- /* Next line added by TRS, 07 July 2006 */
- if ( this.options.beforeHide ) this.options.beforeHide(this);
-
this.stopIndicator();
if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
if(this.iefix) Element.hide(this.iefix);
@@ -138,17 +144,17 @@
case Event.KEY_UP:
this.markPrevious();
this.render();
- if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
+ Event.stop(event);
return;
case Event.KEY_DOWN:
this.markNext();
this.render();
- if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
+ Event.stop(event);
return;
}
else
- if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN)
- return;
+ if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
+ (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;
this.changed = true;
this.hasFocus = true;
@@ -158,6 +164,12 @@
setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
},
+ activate: function() {
+ this.changed = false;
+ this.hasFocus = true;
+ this.getUpdatedChoices();
+ },
+
onHover: function(event) {
var element = Event.findElement(event, 'LI');
if(this.index != element.autocompleteIndex)
@@ -180,15 +192,14 @@
setTimeout(this.hide.bind(this), 250);
this.hasFocus = false;
this.active = false;
- },
-
+ },
+
render: function() {
if(this.entryCount > 0) {
for (var i = 0; i < this.entryCount; i++)
this.index==i ?
Element.addClassName(this.getEntry(i),"selected") :
Element.removeClassName(this.getEntry(i),"selected");
-
if(this.hasFocus) {
this.show();
this.active = true;
@@ -202,11 +213,13 @@
markPrevious: function() {
if(this.index > 0) this.index--
else this.index = this.entryCount-1;
+ this.getEntry(this.index).scrollIntoView(true);
},
markNext: function() {
if(this.index < this.entryCount-1) this.index++
else this.index = 0;
+ this.getEntry(this.index).scrollIntoView(false);
},
getEntry: function(index) {
@@ -229,21 +242,22 @@
}
var value = '';
if (this.options.select) {
- var nodes = document.getElementsByClassName(this.options.select, selectedElement) || [];
+ var nodes = $(selectedElement).select('.' + this.options.select) || [];
if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
} else
value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
- var lastTokenPos = this.findLastToken();
- if (lastTokenPos != -1) {
- var newValue = this.element.value.substr(0, lastTokenPos + 1);
- var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/);
+ var bounds = this.getTokenBounds();
+ if (bounds[0] != -1) {
+ var newValue = this.element.value.substr(0, bounds[0]);
+ var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/);
if (whitespace)
newValue += whitespace[0];
- this.element.value = newValue + value;
+ this.element.value = newValue + value + this.element.value.substr(bounds[1]);
} else {
this.element.value = value;
}
+ this.oldElementValue = this.element.value;
this.element.focus();
if (this.options.afterUpdateElement)
@@ -254,11 +268,11 @@
if(!this.changed && this.hasFocus) {
this.update.innerHTML = choices;
Element.cleanWhitespace(this.update);
- Element.cleanWhitespace(this.update.firstChild);
+ Element.cleanWhitespace(this.update.down());
- if(this.update.firstChild && this.update.firstChild.childNodes) {
+ if(this.update.firstChild && this.update.down().childNodes) {
this.entryCount =
- this.update.firstChild.childNodes.length;
+ this.update.down().childNodes.length;
for (var i = 0; i < this.entryCount; i++) {
var entry = this.getEntry(i);
entry.autocompleteIndex = i;
@@ -269,9 +283,14 @@
}
this.stopIndicator();
-
this.index = 0;
- this.render();
+
+ if(this.entryCount==1 && this.options.autoSelect) {
+ this.selectEntry();
+ this.hide();
+ } else {
+ this.render();
+ }
}
},
@@ -282,41 +301,50 @@
onObserverEvent: function() {
this.changed = false;
+ this.tokenBounds = null;
if(this.getToken().length>=this.options.minChars) {
- this.startIndicator();
this.getUpdatedChoices();
} else {
this.active = false;
this.hide();
}
+ this.oldElementValue = this.element.value;
},
getToken: function() {
- var tokenPos = this.findLastToken();
- if (tokenPos != -1)
- var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/,'').replace(/\s+$/,'');
- else
- var ret = this.element.value;
-
- return /\n/.test(ret) ? '' : ret;
+ var bounds = this.getTokenBounds();
+ return this.element.value.substring(bounds[0], bounds[1]).strip();
},
- findLastToken: function() {
- var lastTokenPos = -1;
-
- for (var i=0; i<this.options.tokens.length; i++) {
- var thisTokenPos = this.element.value.lastIndexOf(this.options.tokens[i]);
- if (thisTokenPos > lastTokenPos)
- lastTokenPos = thisTokenPos;
+ getTokenBounds: function() {
+ if (null != this.tokenBounds) return this.tokenBounds;
+ var value = this.element.value;
+ if (value.strip().empty()) return [-1, 0];
+ var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue);
+ var offset = (diff == this.oldElementValue.length ? 1 : 0);
+ var prevTokenPos = -1, nextTokenPos = value.length;
+ var tp;
+ for (var index = 0, l = this.options.tokens.length; index < l; ++index) {
+ tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1);
+ if (tp > prevTokenPos) prevTokenPos = tp;
+ tp = value.indexOf(this.options.tokens[index], diff + offset);
+ if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp;
}
- return lastTokenPos;
+ return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]);
}
-}
+});
-Ajax.Autocompleter = Class.create();
-Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), {
+Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) {
+ var boundary = Math.min(newS.length, oldS.length);
+ for (var index = 0; index < boundary; ++index)
+ if (newS[index] != oldS[index])
+ return index;
+ return boundary;
+};
+
+Ajax.Autocompleter = Class.create(Autocompleter.Base, {
initialize: function(element, update, url, options) {
- this.baseInitialize(element, update, options);
+ this.baseInitialize(element, update, options);
this.options.asynchronous = true;
this.options.onComplete = this.onComplete.bind(this);
this.options.defaultParams = this.options.parameters || null;
@@ -324,7 +352,9 @@
},
getUpdatedChoices: function() {
- entry = encodeURIComponent(this.options.paramName) + '=' +
+ this.startIndicator();
+
+ var entry = encodeURIComponent(this.options.paramName) + '=' +
encodeURIComponent(this.getToken());
this.options.parameters = this.options.callback ?
@@ -332,14 +362,13 @@
if(this.options.defaultParams)
this.options.parameters += '&' + this.options.defaultParams;
-
+
new Ajax.Request(this.url, this.options);
},
onComplete: function(request) {
this.updateChoices(request.responseText);
}
-
});
// The local array autocompleter. Used when you'd prefer to
@@ -377,8 +406,7 @@
// In that case, the other options above will not apply unless
// you support them.
-Autocompleter.Local = Class.create();
-Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), {
+Autocompleter.Local = Class.create(Autocompleter.Base, {
initialize: function(element, update, array, options) {
this.baseInitialize(element, update, options);
this.options.array = array;
@@ -434,13 +462,12 @@
ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
return "<ul>" + ret.join('') + "</ul>";
}
- }, options || {});
+ }, options || { });
}
});
-// AJAX in-place editor
-//
-// see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor
+// AJAX in-place editor and collection editor
+// Full rewrite by Christophe Porteneuve <tdd at tddsworld.com> (April 2007).
// Use this if you notice weird scrolling problems on some browsers,
// the DOM might be a bit confused when this gets called so do this
@@ -451,310 +478,472 @@
}, 1);
}
-Ajax.InPlaceEditor = Class.create();
-Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99";
-Ajax.InPlaceEditor.prototype = {
+Ajax.InPlaceEditor = Class.create({
initialize: function(element, url, options) {
this.url = url;
- this.element = $(element);
-
- this.options = Object.extend({
- okButton: true,
- okText: "ok",
- cancelLink: true,
- cancelText: "cancel",
- savingText: "Saving...",
- clickToEditText: "Click to edit",
- okText: "ok",
- rows: 1,
- onComplete: function(transport, element) {
- new Effect.Highlight(element, {startcolor: this.options.highlightcolor});
- },
- onFailure: function(transport) {
- alert("Error communicating with the server: " + transport.responseText.stripTags());
- },
- callback: function(form) {
- return Form.serialize(form);
- },
- handleLineBreaks: true,
- loadingText: 'Loading...',
- savingClassName: 'inplaceeditor-saving',
- loadingClassName: 'inplaceeditor-loading',
- formClassName: 'inplaceeditor-form',
- highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor,
- highlightendcolor: "#FFFFFF",
- externalControl: null,
- submitOnBlur: false,
- ajaxOptions: {}
- }, options || {});
-
- if(!this.options.formId && this.element.id) {
- this.options.formId = this.element.id + "-inplaceeditor";
- if ($(this.options.formId)) {
- // there's already a form with that name, don't specify an id
- this.options.formId = null;
- }
+ this.element = element = $(element);
+ this.prepareOptions();
+ this._controls = { };
+ arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!!
+ Object.extend(this.options, options || { });
+ if (!this.options.formId && this.element.id) {
+ this.options.formId = this.element.id + '-inplaceeditor';
+ if ($(this.options.formId))
+ this.options.formId = '';
}
-
- if (this.options.externalControl) {
+ if (this.options.externalControl)
this.options.externalControl = $(this.options.externalControl);
- }
-
- this.originalBackground = Element.getStyle(this.element, 'background-color');
- if (!this.originalBackground) {
- this.originalBackground = "transparent";
- }
-
+ if (!this.options.externalControl)
+ this.options.externalControlOnly = false;
+ this._originalBackground = this.element.getStyle('background-color') || 'transparent';
this.element.title = this.options.clickToEditText;
-
- this.onclickListener = this.enterEditMode.bindAsEventListener(this);
- this.mouseoverListener = this.enterHover.bindAsEventListener(this);
- this.mouseoutListener = this.leaveHover.bindAsEventListener(this);
- Event.observe(this.element, 'click', this.onclickListener);
- Event.observe(this.element, 'mouseover', this.mouseoverListener);
- Event.observe(this.element, 'mouseout', this.mouseoutListener);
- if (this.options.externalControl) {
- Event.observe(this.options.externalControl, 'click', this.onclickListener);
- Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener);
- Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener);
- }
- },
- enterEditMode: function(evt) {
- if (this.saving) return;
- if (this.editing) return;
- this.editing = true;
- this.onEnterEditMode();
- if (this.options.externalControl) {
- Element.hide(this.options.externalControl);
- }
- Element.hide(this.element);
- this.createForm();
- this.element.parentNode.insertBefore(this.form, this.element);
- Field.scrollFreeActivate(this.editField);
- // stop the event to avoid a page refresh in Safari
- if (evt) {
- Event.stop(evt);
+ this._boundCancelHandler = this.handleFormCancellation.bind(this);
+ this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this);
+ this._boundFailureHandler = this.handleAJAXFailure.bind(this);
+ this._boundSubmitHandler = this.handleFormSubmission.bind(this);
+ this._boundWrapperHandler = this.wrapUp.bind(this);
+ this.registerListeners();
+ },
+ checkForEscapeOrReturn: function(e) {
+ if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return;
+ if (Event.KEY_ESC == e.keyCode)
+ this.handleFormCancellation(e);
+ else if (Event.KEY_RETURN == e.keyCode)
+ this.handleFormSubmission(e);
+ },
+ createControl: function(mode, handler, extraClasses) {
+ var control = this.options[mode + 'Control'];
+ var text = this.options[mode + 'Text'];
+ if ('button' == control) {
+ var btn = document.createElement('input');
+ btn.type = 'submit';
+ btn.value = text;
+ btn.className = 'editor_' + mode + '_button';
+ if ('cancel' == mode)
+ btn.onclick = this._boundCancelHandler;
+ this._form.appendChild(btn);
+ this._controls[mode] = btn;
+ } else if ('link' == control) {
+ var link = document.createElement('a');
+ link.href = '#';
+ link.appendChild(document.createTextNode(text));
+ link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler;
+ link.className = 'editor_' + mode + '_link';
+ if (extraClasses)
+ link.className += ' ' + extraClasses;
+ this._form.appendChild(link);
+ this._controls[mode] = link;
}
- return false;
+ },
+ createEditField: function() {
+ var text = (this.options.loadTextURL ? this.options.loadingText : this.getText());
+ var fld;
+ if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) {
+ fld = document.createElement('input');
+ fld.type = 'text';
+ var size = this.options.size || this.options.cols || 0;
+ if (0 < size) fld.size = size;
+ } else {
+ fld = document.createElement('textarea');
+ fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows);
+ fld.cols = this.options.cols || 40;
+ }
+ fld.name = this.options.paramName;
+ fld.value = text; // No HTML breaks conversion anymore
+ fld.className = 'editor_field';
+ if (this.options.submitOnBlur)
+ fld.onblur = this._boundSubmitHandler;
+ this._controls.editor = fld;
+ if (this.options.loadTextURL)
+ this.loadExternalText();
+ this._form.appendChild(this._controls.editor);
},
createForm: function() {
- this.form = document.createElement("form");
- this.form.id = this.options.formId;
- Element.addClassName(this.form, this.options.formClassName)
- this.form.onsubmit = this.onSubmit.bind(this);
-
+ var ipe = this;
+ function addText(mode, condition) {
+ var text = ipe.options['text' + mode + 'Controls'];
+ if (!text || condition === false) return;
+ ipe._form.appendChild(document.createTextNode(text));
+ };
+ this._form = $(document.createElement('form'));
+ this._form.id = this.options.formId;
+ this._form.addClassName(this.options.formClassName);
+ this._form.onsubmit = this._boundSubmitHandler;
this.createEditField();
-
- if (this.options.textarea) {
- var br = document.createElement("br");
- this.form.appendChild(br);
- }
-
- if (this.options.okButton) {
- okButton = document.createElement("input");
- okButton.type = "submit";
- okButton.value = this.options.okText;
- this.form.appendChild(okButton);
- }
-
- if (this.options.cancelLink) {
- cancelLink = document.createElement("a");
- cancelLink.href = "#";
- cancelLink.appendChild(document.createTextNode(this.options.cancelText));
- cancelLink.onclick = this.onclickCancel.bind(this);
- this.form.appendChild(cancelLink);
- }
+ if ('textarea' == this._controls.editor.tagName.toLowerCase())
+ this._form.appendChild(document.createElement('br'));
+ if (this.options.onFormCustomization)
+ this.options.onFormCustomization(this, this._form);
+ addText('Before', this.options.okControl || this.options.cancelControl);
+ this.createControl('ok', this._boundSubmitHandler);
+ addText('Between', this.options.okControl && this.options.cancelControl);
+ this.createControl('cancel', this._boundCancelHandler, 'editor_cancel');
+ addText('After', this.options.okControl || this.options.cancelControl);
+ },
+ destroy: function() {
+ if (this._oldInnerHTML)
+ this.element.innerHTML = this._oldInnerHTML;
+ this.leaveEditMode();
+ this.unregisterListeners();
},
- hasHTMLLineBreaks: function(string) {
- if (!this.options.handleLineBreaks) return false;
- return string.match(/<br/i) || string.match(/<p>/i);
+ enterEditMode: function(e) {
+ if (this._saving || this._editing) return;
+ this._editing = true;
+ this.triggerCallback('onEnterEditMode');
+ if (this.options.externalControl)
+ this.options.externalControl.hide();
+ this.element.hide();
+ this.createForm();
+ this.element.parentNode.insertBefore(this._form, this.element);
+ if (!this.options.loadTextURL)
+ this.postProcessEditField();
+ if (e) Event.stop(e);
+ },
+ enterHover: function(e) {
+ if (this.options.hoverClassName)
+ this.element.addClassName(this.options.hoverClassName);
+ if (this._saving) return;
+ this.triggerCallback('onEnterHover');
},
- convertHTMLLineBreaks: function(string) {
- return string.replace(/<br>/gi, "\n").replace(/<br\/>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<p>/gi, "");
+ getText: function() {
+ return this.element.innerHTML;
},
- createEditField: function() {
- var text;
- if(this.options.loadTextURL) {
- text = this.options.loadingText;
- } else {
- text = this.getText();
- }
-
- var obj = this;
-
- if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) {
- this.options.textarea = false;
- var textField = document.createElement("input");
- textField.obj = this;
- textField.type = "text";
- textField.name = "value";
- textField.value = text;
- textField.style.backgroundColor = this.options.highlightcolor;
- var size = this.options.size || this.options.cols || 0;
- if (size != 0) textField.size = size;
- if (this.options.submitOnBlur)
- textField.onblur = this.onSubmit.bind(this);
- this.editField = textField;
+ handleAJAXFailure: function(transport) {
+ this.triggerCallback('onFailure', transport);
+ if (this._oldInnerHTML) {
+ this.element.innerHTML = this._oldInnerHTML;
+ this._oldInnerHTML = null;
+ }
+ },
+ handleFormCancellation: function(e) {
+ this.wrapUp();
+ if (e) Event.stop(e);
+ },
+ handleFormSubmission: function(e) {
+ var form = this._form;
+ var value = $F(this._controls.editor);
+ this.prepareSubmission();
+ var params = this.options.callback(form, value) || '';
+ if (Object.isString(params))
+ params = params.toQueryParams();
+ params.editorId = this.element.id;
+ if (this.options.htmlResponse) {
+ var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions);
+ Object.extend(options, {
+ parameters: params,
+ onComplete: this._boundWrapperHandler,
+ onFailure: this._boundFailureHandler
+ });
+ new Ajax.Updater({ success: this.element }, this.url, options);
} else {
- this.options.textarea = true;
- var textArea = document.createElement("textarea");
- textArea.obj = this;
- textArea.name = "value";
- textArea.value = this.convertHTMLLineBreaks(text);
- textArea.rows = this.options.rows;
- textArea.cols = this.options.cols || 40;
- if (this.options.submitOnBlur)
- textArea.onblur = this.onSubmit.bind(this);
- this.editField = textArea;
+ var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
+ Object.extend(options, {
+ parameters: params,
+ onComplete: this._boundWrapperHandler,
+ onFailure: this._boundFailureHandler
+ });
+ new Ajax.Request(this.url, options);
}
-
- if(this.options.loadTextURL) {
- this.loadExternalText();
- }
- this.form.appendChild(this.editField);
+ if (e) Event.stop(e);
},
- getText: function() {
- return this.element.innerHTML;
+ leaveEditMode: function() {
+ this.element.removeClassName(this.options.savingClassName);
+ this.removeForm();
+ this.leaveHover();
+ this.element.style.backgroundColor = this._originalBackground;
+ this.element.show();
+ if (this.options.externalControl)
+ this.options.externalControl.show();
+ this._saving = false;
+ this._editing = false;
+ this._oldInnerHTML = null;
+ this.triggerCallback('onLeaveEditMode');
+ },
+ leaveHover: function(e) {
+ if (this.options.hoverClassName)
+ this.element.removeClassName(this.options.hoverClassName);
+ if (this._saving) return;
+ this.triggerCallback('onLeaveHover');
},
loadExternalText: function() {
- Element.addClassName(this.form, this.options.loadingClassName);
- this.editField.disabled = true;
- new Ajax.Request(
- this.options.loadTextURL,
- Object.extend({
- asynchronous: true,
- onComplete: this.onLoadedExternalText.bind(this)
- }, this.options.ajaxOptions)
- );
- },
- onLoadedExternalText: function(transport) {
- Element.removeClassName(this.form, this.options.loadingClassName);
- this.editField.disabled = false;
- this.editField.value = transport.responseText.stripTags();
+ this._form.addClassName(this.options.loadingClassName);
+ this._controls.editor.disabled = true;
+ var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
+ Object.extend(options, {
+ parameters: 'editorId=' + encodeURIComponent(this.element.id),
+ onComplete: Prototype.emptyFunction,
+ onSuccess: function(transport) {
+ this._form.removeClassName(this.options.loadingClassName);
+ var text = transport.responseText;
+ if (this.options.stripLoadedTextTags)
+ text = text.stripTags();
+ this._controls.editor.value = text;
+ this._controls.editor.disabled = false;
+ this.postProcessEditField();
+ }.bind(this),
+ onFailure: this._boundFailureHandler
+ });
+ new Ajax.Request(this.options.loadTextURL, options);
},
- onclickCancel: function() {
- this.onComplete();
- this.leaveEditMode();
- return false;
+ postProcessEditField: function() {
+ var fpc = this.options.fieldPostCreation;
+ if (fpc)
+ $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate']();
+ },
+ prepareOptions: function() {
+ this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions);
+ Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks);
+ [this._extraDefaultOptions].flatten().compact().each(function(defs) {
+ Object.extend(this.options, defs);
+ }.bind(this));
},
- onFailure: function(transport) {
- this.options.onFailure(transport);
- if (this.oldInnerHTML) {
- this.element.innerHTML = this.oldInnerHTML;
- this.oldInnerHTML = null;
- }
- return false;
- },
- onSubmit: function() {
- // onLoading resets these so we need to save them away for the Ajax call
- var form = this.form;
- var value = this.editField.value;
-
- // do this first, sometimes the ajax call returns before we get a chance to switch on Saving...
- // which means this will actually switch on Saving... *after* we've left edit mode causing Saving...
- // to be displayed indefinitely
- this.onLoading();
-
- new Ajax.Updater(
- {
- success: this.element,
- // don't update on failure (this could be an option)
- failure: null
- },
- this.url,
- Object.extend({
- parameters: this.options.callback(form, value),
- onComplete: this.onComplete.bind(this),
- onFailure: this.onFailure.bind(this)
- }, this.options.ajaxOptions)
- );
- // stop the event to avoid a page refresh in Safari
- if (arguments.length > 1) {
- Event.stop(arguments[0]);
- }
- return false;
- },
- onLoading: function() {
- this.saving = true;
+ prepareSubmission: function() {
+ this._saving = true;
this.removeForm();
this.leaveHover();
this.showSaving();
},
- showSaving: function() {
- this.oldInnerHTML = this.element.innerHTML;
- this.element.innerHTML = this.options.savingText;
- Element.addClassName(this.element, this.options.savingClassName);
- this.element.style.backgroundColor = this.originalBackground;
- Element.show(this.element);
+ registerListeners: function() {
+ this._listeners = { };
+ var listener;
+ $H(Ajax.InPlaceEditor.Listeners).each(function(pair) {
+ listener = this[pair.value].bind(this);
+ this._listeners[pair.key] = listener;
+ if (!this.options.externalControlOnly)
+ this.element.observe(pair.key, listener);
+ if (this.options.externalControl)
+ this.options.externalControl.observe(pair.key, listener);
+ }.bind(this));
},
removeForm: function() {
- if(this.form) {
- if (this.form.parentNode) Element.remove(this.form);
- this.form = null;
- }
- },
- enterHover: function() {
- if (this.saving) return;
- this.element.style.backgroundColor = this.options.highlightcolor;
- if (this.effect) {
- this.effect.cancel();
- }
- Element.addClassName(this.element, this.options.hoverClassName)
- },
- leaveHover: function() {
- if (this.options.backgroundColor) {
- this.element.style.backgroundColor = this.oldBackground;
- }
- Element.removeClassName(this.element, this.options.hoverClassName)
- if (this.saving) return;
- this.effect = new Effect.Highlight(this.element, {
- startcolor: this.options.highlightcolor,
- endcolor: this.options.highlightendcolor,
- restorecolor: this.originalBackground
- });
+ if (!this._form) return;
+ this._form.remove();
+ this._form = null;
+ this._controls = { };
},
- leaveEditMode: function() {
- Element.removeClassName(this.element, this.options.savingClassName);
- this.removeForm();
- this.leaveHover();
- this.element.style.backgroundColor = this.originalBackground;
- Element.show(this.element);
- if (this.options.externalControl) {
- Element.show(this.options.externalControl);
- }
- this.editing = false;
- this.saving = false;
- this.oldInnerHTML = null;
- this.onLeaveEditMode();
+ showSaving: function() {
+ this._oldInnerHTML = this.element.innerHTML;
+ this.element.innerHTML = this.options.savingText;
+ this.element.addClassName(this.options.savingClassName);
+ this.element.style.backgroundColor = this._originalBackground;
+ this.element.show();
+ },
+ triggerCallback: function(cbName, arg) {
+ if ('function' == typeof this.options[cbName]) {
+ this.options[cbName](this, arg);
+ }
+ },
+ unregisterListeners: function() {
+ $H(this._listeners).each(function(pair) {
+ if (!this.options.externalControlOnly)
+ this.element.stopObserving(pair.key, pair.value);
+ if (this.options.externalControl)
+ this.options.externalControl.stopObserving(pair.key, pair.value);
+ }.bind(this));
},
- onComplete: function(transport) {
+ wrapUp: function(transport) {
this.leaveEditMode();
- this.options.onComplete.bind(this)(transport, this.element);
+ // Can't use triggerCallback due to backward compatibility: requires
+ // binding + direct element
+ this._boundComplete(transport, this.element);
+ }
+});
+
+Object.extend(Ajax.InPlaceEditor.prototype, {
+ dispose: Ajax.InPlaceEditor.prototype.destroy
+});
+
+Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, {
+ initialize: function($super, element, url, options) {
+ this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions;
+ $super(element, url, options);
},
- onEnterEditMode: function() {},
- onLeaveEditMode: function() {},
- dispose: function() {
- if (this.oldInnerHTML) {
- this.element.innerHTML = this.oldInnerHTML;
- }
- this.leaveEditMode();
- Event.stopObserving(this.element, 'click', this.onclickListener);
- Event.stopObserving(this.element, 'mouseover', this.mouseoverListener);
- Event.stopObserving(this.element, 'mouseout', this.mouseoutListener);
- if (this.options.externalControl) {
- Event.stopObserving(this.options.externalControl, 'click', this.onclickListener);
- Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener);
- Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener);
+
+ createEditField: function() {
+ var list = document.createElement('select');
+ list.name = this.options.paramName;
+ list.size = 1;
+ this._controls.editor = list;
+ this._collection = this.options.collection || [];
+ if (this.options.loadCollectionURL)
+ this.loadCollection();
+ else
+ this.checkForExternalText();
+ this._form.appendChild(this._controls.editor);
+ },
+
+ loadCollection: function() {
+ this._form.addClassName(this.options.loadingClassName);
+ this.showLoadingText(this.options.loadingCollectionText);
+ var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
+ Object.extend(options, {
+ parameters: 'editorId=' + encodeURIComponent(this.element.id),
+ onComplete: Prototype.emptyFunction,
+ onSuccess: function(transport) {
+ var js = transport.responseText.strip();
+ if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check
+ throw 'Server returned an invalid collection representation.';
+ this._collection = eval(js);
+ this.checkForExternalText();
+ }.bind(this),
+ onFailure: this.onFailure
+ });
+ new Ajax.Request(this.options.loadCollectionURL, options);
+ },
+
+ showLoadingText: function(text) {
+ this._controls.editor.disabled = true;
+ var tempOption = this._controls.editor.firstChild;
+ if (!tempOption) {
+ tempOption = document.createElement('option');
+ tempOption.value = '';
+ this._controls.editor.appendChild(tempOption);
+ tempOption.selected = true;
}
+ tempOption.update((text || '').stripScripts().stripTags());
+ },
+
+ checkForExternalText: function() {
+ this._text = this.getText();
+ if (this.options.loadTextURL)
+ this.loadExternalText();
+ else
+ this.buildOptionList();
+ },
+
+ loadExternalText: function() {
+ this.showLoadingText(this.options.loadingText);
+ var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
+ Object.extend(options, {
+ parameters: 'editorId=' + encodeURIComponent(this.element.id),
+ onComplete: Prototype.emptyFunction,
+ onSuccess: function(transport) {
+ this._text = transport.responseText.strip();
+ this.buildOptionList();
+ }.bind(this),
+ onFailure: this.onFailure
+ });
+ new Ajax.Request(this.options.loadTextURL, options);
+ },
+
+ buildOptionList: function() {
+ this._form.removeClassName(this.options.loadingClassName);
+ this._collection = this._collection.map(function(entry) {
+ return 2 === entry.length ? entry : [entry, entry].flatten();
+ });
+ var marker = ('value' in this.options) ? this.options.value : this._text;
+ var textFound = this._collection.any(function(entry) {
+ return entry[0] == marker;
+ }.bind(this));
+ this._controls.editor.update('');
+ var option;
+ this._collection.each(function(entry, index) {
+ option = document.createElement('option');
+ option.value = entry[0];
+ option.selected = textFound ? entry[0] == marker : 0 == index;
+ option.appendChild(document.createTextNode(entry[1]));
+ this._controls.editor.appendChild(option);
+ }.bind(this));
+ this._controls.editor.disabled = false;
+ Field.scrollFreeActivate(this._controls.editor);
}
+});
+
+//**** DEPRECATION LAYER FOR InPlace[Collection]Editor! ****
+//**** This only exists for a while, in order to let ****
+//**** users adapt to the new API. Read up on the new ****
+//**** API and convert your code to it ASAP! ****
+
+Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) {
+ if (!options) return;
+ function fallback(name, expr) {
+ if (name in options || expr === undefined) return;
+ options[name] = expr;
+ };
+ fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' :
+ options.cancelLink == options.cancelButton == false ? false : undefined)));
+ fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' :
+ options.okLink == options.okButton == false ? false : undefined)));
+ fallback('highlightColor', options.highlightcolor);
+ fallback('highlightEndColor', options.highlightendcolor);
+};
+
+Object.extend(Ajax.InPlaceEditor, {
+ DefaultOptions: {
+ ajaxOptions: { },
+ autoRows: 3, // Use when multi-line w/ rows == 1
+ cancelControl: 'link', // 'link'|'button'|false
+ cancelText: 'cancel',
+ clickToEditText: 'Click to edit',
+ externalControl: null, // id|elt
+ externalControlOnly: false,
+ fieldPostCreation: 'activate', // 'activate'|'focus'|false
+ formClassName: 'inplaceeditor-form',
+ formId: null, // id|elt
+ highlightColor: '#ffff99',
+ highlightEndColor: '#ffffff',
+ hoverClassName: '',
+ htmlResponse: true,
+ loadingClassName: 'inplaceeditor-loading',
+ loadingText: 'Loading...',
+ okControl: 'button', // 'link'|'button'|false
+ okText: 'ok',
+ paramName: 'value',
+ rows: 1, // If 1 and multi-line, uses autoRows
+ savingClassName: 'inplaceeditor-saving',
+ savingText: 'Saving...',
+ size: 0,
+ stripLoadedTextTags: false,
+ submitOnBlur: false,
+ textAfterControls: '',
+ textBeforeControls: '',
+ textBetweenControls: ''
+ },
+ DefaultCallbacks: {
+ callback: function(form) {
+ return Form.serialize(form);
+ },
+ onComplete: function(transport, element) {
+ // For backward compatibility, this one is bound to the IPE, and passes
+ // the element directly. It was too often customized, so we don't break it.
+ new Effect.Highlight(element, {
+ startcolor: this.options.highlightColor, keepBackgroundImage: true });
+ },
+ onEnterEditMode: null,
+ onEnterHover: function(ipe) {
+ ipe.element.style.backgroundColor = ipe.options.highlightColor;
+ if (ipe._effect)
+ ipe._effect.cancel();
+ },
+ onFailure: function(transport, ipe) {
+ alert('Error communication with the server: ' + transport.responseText.stripTags());
+ },
+ onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls.
+ onLeaveEditMode: null,
+ onLeaveHover: function(ipe) {
+ ipe._effect = new Effect.Highlight(ipe.element, {
+ startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor,
+ restorecolor: ipe._originalBackground, keepBackgroundImage: true
+ });
+ }
+ },
+ Listeners: {
+ click: 'enterEditMode',
+ keydown: 'checkForEscapeOrReturn',
+ mouseover: 'enterHover',
+ mouseout: 'leaveHover'
+ }
+});
+
+Ajax.InPlaceCollectionEditor.DefaultOptions = {
+ loadingCollectionText: 'Loading options...'
};
// Delayed observer, like Form.Element.Observer,
// but waits for delay after last key input
// Ideal for live-search fields
-Form.Element.DelayedObserver = Class.create();
-Form.Element.DelayedObserver.prototype = {
+Form.Element.DelayedObserver = Class.create({
initialize: function(element, delay, callback) {
this.delay = delay || 0.5;
this.element = $(element);
@@ -773,4 +962,4 @@
this.timer = null;
this.callback(this.element, $F(this.element));
}
-};
+});
Modified: jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/dragdrop.js
==============================================================================
--- jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/dragdrop.js (original)
+++ jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/dragdrop.js Fri Jun 27 10:34:57 2008
@@ -1,8 +1,13 @@
-// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// script.aculo.us dragdrop.js v1.8.1, Thu Jan 03 22:07:12 -0500 2008
+
+// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// (c) 2005-2007 Sammi Williams (http://www.oriontransfer.co.nz, sammi at oriontransfer.co.nz)
//
-// See scriptaculous.js for full license.
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
-/*--------------------------------------------------------------------------*/
+if(Object.isUndefined(Effect))
+ throw("dragdrop.js requires including script.aculo.us' effects.js library");
var Droppables = {
drops: [],
@@ -15,15 +20,15 @@
element = $(element);
var options = Object.extend({
greedy: true,
- hoverclass: null
- }, arguments[1] || {});
+ hoverclass: null,
+ tree: false
+ }, arguments[1] || { });
// cache containers
if(options.containment) {
options._containers = [];
var containment = options.containment;
- if((typeof containment == 'object') &&
- (containment.constructor == Array)) {
+ if(Object.isArray(containment)) {
containment.each( function(c) { options._containers.push($(c)) });
} else {
options._containers.push($(containment));
@@ -37,12 +42,27 @@
this.drops.push(options);
},
+
+ findDeepestChild: function(drops) {
+ deepest = drops[0];
+
+ for (i = 1; i < drops.length; ++i)
+ if (Element.isParent(drops[i].element, deepest.element))
+ deepest = drops[i];
+
+ return deepest;
+ },
isContained: function(element, drop) {
- var parentNode = element.parentNode;
- return drop._containers.detect(function(c) { return parentNode == c });
+ var containmentNode;
+ if(drop.tree) {
+ containmentNode = element.treeNode;
+ } else {
+ containmentNode = element.parentNode;
+ }
+ return drop._containers.detect(function(c) { return containmentNode == c });
},
-
+
isAffected: function(point, element, drop) {
return (
(drop.element!=element) &&
@@ -68,18 +88,24 @@
show: function(point, element) {
if(!this.drops.length) return;
+ var drop, affected = [];
- if(this.last_active) this.deactivate(this.last_active);
this.drops.each( function(drop) {
- if(Droppables.isAffected(point, element, drop)) {
- if(drop.onHover)
- drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
- if(drop.greedy) {
- Droppables.activate(drop);
- throw $break;
- }
- }
+ if(Droppables.isAffected(point, element, drop))
+ affected.push(drop);
});
+
+ if(affected.length>0)
+ drop = Droppables.findDeepestChild(affected);
+
+ if(this.last_active && this.last_active != drop) this.deactivate(this.last_active);
+ if (drop) {
+ Position.within(drop.element, point[0], point[1]);
+ if(drop.onHover)
+ drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
+
+ if (drop != this.last_active) Droppables.activate(drop);
+ }
},
fire: function(event, element) {
@@ -87,8 +113,10 @@
Position.prepare();
if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
- if (this.last_active.onDrop)
- this.last_active.onDrop(element, this.last_active.element, event);
+ if (this.last_active.onDrop) {
+ this.last_active.onDrop(element, this.last_active.element, event);
+ return true;
+ }
},
reset: function() {
@@ -124,11 +152,19 @@
},
activate: function(draggable) {
- window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
- this.activeDraggable = draggable;
+ if(draggable.options.delay) {
+ this._timeout = setTimeout(function() {
+ Draggables._timeout = null;
+ window.focus();
+ Draggables.activeDraggable = draggable;
+ }.bind(this), draggable.options.delay);
+ } else {
+ window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
+ this.activeDraggable = draggable;
+ }
},
- deactivate: function(draggbale) {
+ deactivate: function() {
this.activeDraggable = null;
},
@@ -139,10 +175,15 @@
// the same coordinates, prevent needless redrawing (moz bug?)
if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
this._lastPointer = pointer;
+
this.activeDraggable.updateDrag(event, pointer);
},
endDrag: function(event) {
+ if(this._timeout) {
+ clearTimeout(this._timeout);
+ this._timeout = null;
+ }
if(!this.activeDraggable) return;
this._lastPointer = null;
this.activeDraggable.endDrag(event);
@@ -169,6 +210,7 @@
this.observers.each( function(o) {
if(o[eventName]) o[eventName](eventName, draggable, event);
});
+ if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
},
_cacheObserverCallbacks: function() {
@@ -182,36 +224,61 @@
/*--------------------------------------------------------------------------*/
-var Draggable = Class.create();
-Draggable.prototype = {
+var Draggable = Class.create({
initialize: function(element) {
- var options = Object.extend({
+ var defaults = {
handle: false,
- starteffect: function(element) {
- new Effect.Opacity(element, {duration:0.2, from:1.0, to:0.7});
- },
reverteffect: function(element, top_offset, left_offset) {
var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
- element._revert = new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur});
+ new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
+ queue: {scope:'_draggable', position:'end'}
+ });
},
- endeffect: function(element) {
- new Effect.Opacity(element, {duration:0.2, from:0.7, to:1.0});
+ endeffect: function(element) {
+ var toOpacity = Object.isNumber(element._opacity) ? element._opacity : 1.0;
+ new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
+ queue: {scope:'_draggable', position:'end'},
+ afterFinish: function(){
+ Draggable._dragging[element] = false
+ }
+ });
},
zindex: 1000,
revert: false,
- snap: false // false, or xy or [x,y] or function(x,y){ return [x,y] }
- }, arguments[1] || {});
+ quiet: false,
+ scroll: false,
+ scrollSensitivity: 20,
+ scrollSpeed: 15,
+ snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] }
+ delay: 0
+ };
+
+ if(!arguments[1] || Object.isUndefined(arguments[1].endeffect))
+ Object.extend(defaults, {
+ starteffect: function(element) {
+ element._opacity = Element.getOpacity(element);
+ Draggable._dragging[element] = true;
+ new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});
+ }
+ });
+
+ var options = Object.extend(defaults, arguments[1] || { });
this.element = $(element);
- if(options.handle && (typeof options.handle == 'string'))
- this.handle = Element.childrenWithClassName(this.element, options.handle)[0];
+ if(options.handle && Object.isString(options.handle))
+ this.handle = this.element.down('.'+options.handle, 0);
+
if(!this.handle) this.handle = $(options.handle);
if(!this.handle) this.handle = this.element;
+
+ if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
+ options.scroll = $(options.scroll);
+ this._isScrollChild = Element.childOf(this.element, options.scroll);
+ }
Element.makePositioned(this.element); // fix IE
- this.delta = this.currentDelta();
this.options = options;
this.dragging = false;
@@ -233,20 +300,18 @@
},
initDrag: function(event) {
+ if(!Object.isUndefined(Draggable._dragging[this.element]) &&
+ Draggable._dragging[this.element]) return;
if(Event.isLeftClick(event)) {
// abort on form elements, fixes a Firefox issue
var src = Event.element(event);
- if(src.tagName && (
- src.tagName=='INPUT' ||
- src.tagName=='SELECT' ||
- src.tagName=='BUTTON' ||
- src.tagName=='TEXTAREA')) return;
+ if((tag_name = src.tagName.toUpperCase()) && (
+ tag_name=='INPUT' ||
+ tag_name=='SELECT' ||
+ tag_name=='OPTION' ||
+ tag_name=='BUTTON' ||
+ tag_name=='TEXTAREA')) return;
- if(this.element._revert) {
- this.element._revert.cancel();
- this.element._revert = null;
- }
-
var pointer = [Event.pointerX(event), Event.pointerY(event)];
var pos = Position.cumulativeOffset(this.element);
this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
@@ -258,6 +323,8 @@
startDrag: function(event) {
this.dragging = true;
+ if(!this.delta)
+ this.delta = this.currentDelta();
if(this.options.zindex) {
this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
@@ -266,46 +333,101 @@
if(this.options.ghosting) {
this._clone = this.element.cloneNode(true);
- Position.absolutize(this.element);
+ this.element._originallyAbsolute = (this.element.getStyle('position') == 'absolute');
+ if (!this.element._originallyAbsolute)
+ Position.absolutize(this.element);
this.element.parentNode.insertBefore(this._clone, this.element);
}
+ if(this.options.scroll) {
+ if (this.options.scroll == window) {
+ var where = this._getWindowScroll(this.options.scroll);
+ this.originalScrollLeft = where.left;
+ this.originalScrollTop = where.top;
+ } else {
+ this.originalScrollLeft = this.options.scroll.scrollLeft;
+ this.originalScrollTop = this.options.scroll.scrollTop;
+ }
+ }
+
Draggables.notify('onStart', this, event);
+
if(this.options.starteffect) this.options.starteffect(this.element);
},
updateDrag: function(event, pointer) {
if(!this.dragging) this.startDrag(event);
- Position.prepare();
- Droppables.show(pointer, this.element);
+
+ if(!this.options.quiet){
+ Position.prepare();
+ Droppables.show(pointer, this.element);
+ }
+
Draggables.notify('onDrag', this, event);
+
this.draw(pointer);
if(this.options.change) this.options.change(this);
+ if(this.options.scroll) {
+ this.stopScrolling();
+
+ var p;
+ if (this.options.scroll == window) {
+ with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
+ } else {
+ p = Position.page(this.options.scroll);
+ p[0] += this.options.scroll.scrollLeft + Position.deltaX;
+ p[1] += this.options.scroll.scrollTop + Position.deltaY;
+ p.push(p[0]+this.options.scroll.offsetWidth);
+ p.push(p[1]+this.options.scroll.offsetHeight);
+ }
+ var speed = [0,0];
+ if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);
+ if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);
+ if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);
+ if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
+ this.startScrolling(speed);
+ }
+
// fix AppleWebKit rendering
- if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
+ if(Prototype.Browser.WebKit) window.scrollBy(0,0);
+
Event.stop(event);
},
finishDrag: function(event, success) {
this.dragging = false;
+
+ if(this.options.quiet){
+ Position.prepare();
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
+ Droppables.show(pointer, this.element);
+ }
if(this.options.ghosting) {
- Position.relativize(this.element);
+ if (!this.element._originallyAbsolute)
+ Position.relativize(this.element);
+ delete this.element._originallyAbsolute;
Element.remove(this._clone);
this._clone = null;
}
- if(success) Droppables.fire(event, this.element);
+ var dropped = false;
+ if(success) {
+ dropped = Droppables.fire(event, this.element);
+ if (!dropped) dropped = false;
+ }
+ if(dropped && this.options.onDropped) this.options.onDropped(this.element);
Draggables.notify('onEnd', this, event);
var revert = this.options.revert;
- if(revert && typeof revert == 'function') revert = revert(this.element);
+ if(revert && Object.isFunction(revert)) revert = revert(this.element);
var d = this.currentDelta();
if(revert && this.options.reverteffect) {
- this.options.reverteffect(this.element,
- d[1]-this.delta[1], d[0]-this.delta[0]);
+ if (dropped == 0 || revert != 'failure')
+ this.options.reverteffect(this.element,
+ d[1]-this.delta[1], d[0]-this.delta[0]);
} else {
this.delta = d;
}
@@ -315,40 +437,53 @@
if(this.options.endeffect)
this.options.endeffect(this.element);
-
+
Draggables.deactivate(this);
Droppables.reset();
},
keyPress: function(event) {
- if(!event.keyCode==Event.KEY_ESC) return;
+ if(event.keyCode!=Event.KEY_ESC) return;
this.finishDrag(event, false);
Event.stop(event);
},
endDrag: function(event) {
if(!this.dragging) return;
+ this.stopScrolling();
this.finishDrag(event, true);
Event.stop(event);
},
draw: function(point) {
var pos = Position.cumulativeOffset(this.element);
+ if(this.options.ghosting) {
+ var r = Position.realOffset(this.element);
+ pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
+ }
+
var d = this.currentDelta();
pos[0] -= d[0]; pos[1] -= d[1];
- var p = [0,1].map(function(i){ return (point[i]-pos[i]-this.offset[i]) }.bind(this));
+ if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
+ pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
+ pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
+ }
+
+ var p = [0,1].map(function(i){
+ return (point[i]-pos[i]-this.offset[i])
+ }.bind(this));
if(this.options.snap) {
- if(typeof this.options.snap == 'function') {
- p = this.options.snap(p[0],p[1]);
+ if(Object.isFunction(this.options.snap)) {
+ p = this.options.snap(p[0],p[1],this);
} else {
- if(this.options.snap instanceof Array) {
+ if(Object.isArray(this.options.snap)) {
p = p.map( function(v, i) {
- return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this))
+ return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this))
} else {
p = p.map( function(v) {
- return Math.round(v/this.options.snap)*this.options.snap }.bind(this))
+ return (v/this.options.snap).round()*this.options.snap }.bind(this))
}
}}
@@ -357,14 +492,88 @@
style.left = p[0] + "px";
if((!this.options.constraint) || (this.options.constraint=='vertical'))
style.top = p[1] + "px";
+
if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
+ },
+
+ stopScrolling: function() {
+ if(this.scrollInterval) {
+ clearInterval(this.scrollInterval);
+ this.scrollInterval = null;
+ Draggables._lastScrollPointer = null;
+ }
+ },
+
+ startScrolling: function(speed) {
+ if(!(speed[0] || speed[1])) return;
+ this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
+ this.lastScrolled = new Date();
+ this.scrollInterval = setInterval(this.scroll.bind(this), 10);
+ },
+
+ scroll: function() {
+ var current = new Date();
+ var delta = current - this.lastScrolled;
+ this.lastScrolled = current;
+ if(this.options.scroll == window) {
+ with (this._getWindowScroll(this.options.scroll)) {
+ if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
+ var d = delta / 1000;
+ this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] );
+ }
+ }
+ } else {
+ this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
+ this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000;
+ }
+
+ Position.prepare();
+ Droppables.show(Draggables._lastPointer, this.element);
+ Draggables.notify('onDrag', this);
+ if (this._isScrollChild) {
+ Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
+ Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
+ Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
+ if (Draggables._lastScrollPointer[0] < 0)
+ Draggables._lastScrollPointer[0] = 0;
+ if (Draggables._lastScrollPointer[1] < 0)
+ Draggables._lastScrollPointer[1] = 0;
+ this.draw(Draggables._lastScrollPointer);
+ }
+
+ if(this.options.change) this.options.change(this);
+ },
+
+ _getWindowScroll: function(w) {
+ var T, L, W, H;
+ with (w.document) {
+ if (w.document.documentElement && documentElement.scrollTop) {
+ T = documentElement.scrollTop;
+ L = documentElement.scrollLeft;
+ } else if (w.document.body) {
+ T = body.scrollTop;
+ L = body.scrollLeft;
+ }
+ if (w.innerWidth) {
+ W = w.innerWidth;
+ H = w.innerHeight;
+ } else if (w.document.documentElement && documentElement.clientWidth) {
+ W = documentElement.clientWidth;
+ H = documentElement.clientHeight;
+ } else {
+ W = body.offsetWidth;
+ H = body.offsetHeight
+ }
+ }
+ return { top: T, left: L, width: W, height: H };
}
-}
+});
+
+Draggable._dragging = { };
/*--------------------------------------------------------------------------*/
-var SortableObserver = Class.create();
-SortableObserver.prototype = {
+var SortableObserver = Class.create({
initialize: function(element, observer) {
this.element = $(element);
this.observer = observer;
@@ -380,44 +589,68 @@
if(this.lastValue != Sortable.serialize(this.element))
this.observer(this.element)
}
-}
+});
var Sortable = {
- sortables: new Array(),
+ SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
- options: function(element){
- element = $(element);
- return this.sortables.detect(function(s) { return s.element == element });
+ sortables: { },
+
+ _findRootElement: function(element) {
+ while (element.tagName.toUpperCase() != "BODY") {
+ if(element.id && Sortable.sortables[element.id]) return element;
+ element = element.parentNode;
+ }
+ },
+
+ options: function(element) {
+ element = Sortable._findRootElement($(element));
+ if(!element) return;
+ return Sortable.sortables[element.id];
},
destroy: function(element){
- element = $(element);
- this.sortables.findAll(function(s) { return s.element == element }).each(function(s){
+ var s = Sortable.options(element);
+
+ if(s) {
Draggables.removeObserver(s.element);
s.droppables.each(function(d){ Droppables.remove(d) });
s.draggables.invoke('destroy');
- });
- this.sortables = this.sortables.reject(function(s) { return s.element == element });
+
+ delete Sortable.sortables[s.element.id];
+ }
},
-
+
create: function(element) {
element = $(element);
var options = Object.extend({
element: element,
tag: 'li', // assumes li children, override with tag: 'tagname'
dropOnEmpty: false,
- tree: false, // fixme: unimplemented
+ tree: false,
+ treeTag: 'ul',
overlap: 'vertical', // one of 'vertical', 'horizontal'
constraint: 'vertical', // one of 'vertical', 'horizontal', false
containment: element, // also takes array of elements (or id's); or false
handle: false, // or a CSS class
only: false,
+ delay: 0,
hoverclass: null,
ghosting: false,
- format: null,
+ quiet: false,
+ scroll: false,
+ scrollSensitivity: 20,
+ scrollSpeed: 15,
+ format: this.SERIALIZE_RULE,
+
+ // these take arrays of elements or ids and can be
+ // used for better initialization performance
+ elements: false,
+ handles: false,
+
onChange: Prototype.emptyFunction,
onUpdate: Prototype.emptyFunction
- }, arguments[1] || {});
+ }, arguments[1] || { });
// clear any old sortable with same element
this.destroy(element);
@@ -425,6 +658,11 @@
// build options for the draggables
var options_for_draggable = {
revert: true,
+ quiet: options.quiet,
+ scroll: options.scroll,
+ scrollSpeed: options.scrollSpeed,
+ scrollSensitivity: options.scrollSensitivity,
+ delay: options.delay,
ghosting: options.ghosting,
constraint: options.constraint,
handle: options.handle };
@@ -450,9 +688,16 @@
var options_for_droppable = {
overlap: options.overlap,
containment: options.containment,
+ tree: options.tree,
hoverclass: options.hoverclass,
- onHover: Sortable.onHover,
- greedy: !options.dropOnEmpty
+ onHover: Sortable.onHover
+ }
+
+ var options_for_tree = {
+ onHover: Sortable.onEmptyHover,
+ overlap: options.overlap,
+ containment: options.containment,
+ hoverclass: options.hoverclass
}
// fix for gecko engine
@@ -461,27 +706,32 @@
options.draggables = [];
options.droppables = [];
- // make it so
-
// drop on empty handling
- if(options.dropOnEmpty) {
- Droppables.add(element,
- {containment: options.containment, onHover: Sortable.onEmptyHover, greedy: false});
+ if(options.dropOnEmpty || options.tree) {
+ Droppables.add(element, options_for_tree);
options.droppables.push(element);
}
- (this.findElements(element, options) || []).each( function(e) {
- // handles are per-draggable
- var handle = options.handle ?
- Element.childrenWithClassName(e, options.handle)[0] : e;
+ (options.elements || this.findElements(element, options) || []).each( function(e,i) {
+ var handle = options.handles ? $(options.handles[i]) :
+ (options.handle ? $(e).select('.' + options.handle)[0] : e);
options.draggables.push(
new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
Droppables.add(e, options_for_droppable);
+ if(options.tree) e.treeNode = element;
options.droppables.push(e);
});
+
+ if(options.tree) {
+ (Sortable.findTreeElements(element, options) || []).each( function(e) {
+ Droppables.add(e, options_for_tree);
+ e.treeNode = element;
+ options.droppables.push(e);
+ });
+ }
// keep reference
- this.sortables.push(options);
+ this.sortables[element.id] = options;
// for onupdate
Draggables.addObserver(new SortableObserver(element, options.onUpdate));
@@ -490,23 +740,21 @@
// return all suitable-for-sortable elements in a guaranteed order
findElements: function(element, options) {
- if(!element.hasChildNodes()) return null;
- var elements = [];
- $A(element.childNodes).each( function(e) {
- if(e.tagName && e.tagName.toUpperCase()==options.tag.toUpperCase() &&
- (!options.only || (Element.hasClassName(e, options.only))))
- elements.push(e);
- if(options.tree) {
- var grandchildren = this.findElements(e, options);
- if(grandchildren) elements.push(grandchildren);
- }
- });
-
- return (elements.length>0 ? elements.flatten() : null);
+ return Element.findChildren(
+ element, options.only, options.tree ? true : false, options.tag);
+ },
+
+ findTreeElements: function(element, options) {
+ return Element.findChildren(
+ element, options.only, options.tree ? true : false, options.treeTag);
},
onHover: function(element, dropon, overlap) {
- if(overlap>0.5) {
+ if(Element.isParent(dropon, element)) return;
+
+ if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {
+ return;
+ } else if(overlap>0.5) {
Sortable.mark(dropon, 'before');
if(dropon.previousSibling != element) {
var oldParentNode = element.parentNode;
@@ -529,18 +777,42 @@
}
}
},
-
- onEmptyHover: function(element, dropon) {
- if(element.parentNode!=dropon) {
- var oldParentNode = element.parentNode;
- dropon.appendChild(element);
+
+ onEmptyHover: function(element, dropon, overlap) {
+ var oldParentNode = element.parentNode;
+ var droponOptions = Sortable.options(dropon);
+
+ if(!Element.isParent(dropon, element)) {
+ var index;
+
+ var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only});
+ var child = null;
+
+ if(children) {
+ var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
+
+ for (index = 0; index < children.length; index += 1) {
+ if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {
+ offset -= Element.offsetSize (children[index], droponOptions.overlap);
+ } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
+ child = index + 1 < children.length ? children[index + 1] : null;
+ break;
+ } else {
+ child = children[index];
+ break;
+ }
+ }
+ }
+
+ dropon.insertBefore(element, child);
+
Sortable.options(oldParentNode).onChange(element);
- Sortable.options(dropon).onChange(element);
+ droponOptions.onChange(element);
}
},
unmark: function() {
- if(Sortable._marker) Element.hide(Sortable._marker);
+ if(Sortable._marker) Sortable._marker.hide();
},
mark: function(dropon, position) {
@@ -549,37 +821,154 @@
if(sortable && !sortable.ghosting) return;
if(!Sortable._marker) {
- Sortable._marker = $('dropmarker') || document.createElement('DIV');
- Element.hide(Sortable._marker);
- Element.addClassName(Sortable._marker, 'dropmarker');
- Sortable._marker.style.position = 'absolute';
+ Sortable._marker =
+ ($('dropmarker') || Element.extend(document.createElement('DIV'))).
+ hide().addClassName('dropmarker').setStyle({position:'absolute'});
document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
}
var offsets = Position.cumulativeOffset(dropon);
- Sortable._marker.style.left = offsets[0] + 'px';
- Sortable._marker.style.top = offsets[1] + 'px';
+ Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});
if(position=='after')
if(sortable.overlap == 'horizontal')
- Sortable._marker.style.left = (offsets[0]+dropon.clientWidth) + 'px';
+ Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});
else
- Sortable._marker.style.top = (offsets[1]+dropon.clientHeight) + 'px';
+ Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'});
- Element.show(Sortable._marker);
+ Sortable._marker.show();
},
+
+ _tree: function(element, options, parent) {
+ var children = Sortable.findElements(element, options) || [];
+
+ for (var i = 0; i < children.length; ++i) {
+ var match = children[i].id.match(options.format);
- serialize: function(element) {
+ if (!match) continue;
+
+ var child = {
+ id: encodeURIComponent(match ? match[1] : null),
+ element: element,
+ parent: parent,
+ children: [],
+ position: parent.children.length,
+ container: $(children[i]).down(options.treeTag)
+ }
+
+ /* Get the element containing the children and recurse over it */
+ if (child.container)
+ this._tree(child.container, options, child)
+
+ parent.children.push (child);
+ }
+
+ return parent;
+ },
+
+ tree: function(element) {
element = $(element);
var sortableOptions = this.options(element);
var options = Object.extend({
- tag: sortableOptions.tag,
+ tag: sortableOptions.tag,
+ treeTag: sortableOptions.treeTag,
only: sortableOptions.only,
name: element.id,
- format: sortableOptions.format || /^[^_]*_(.*)$/
- }, arguments[1] || {});
+ format: sortableOptions.format
+ }, arguments[1] || { });
+
+ var root = {
+ id: null,
+ parent: null,
+ children: [],
+ container: element,
+ position: 0
+ }
+
+ return Sortable._tree(element, options, root);
+ },
+
+ /* Construct a [i] index for a particular node */
+ _constructIndex: function(node) {
+ var index = '';
+ do {
+ if (node.id) index = '[' + node.position + ']' + index;
+ } while ((node = node.parent) != null);
+ return index;
+ },
+
+ sequence: function(element) {
+ element = $(element);
+ var options = Object.extend(this.options(element), arguments[1] || { });
+
return $(this.findElements(element, options) || []).map( function(item) {
- return (encodeURIComponent(options.name) + "[]=" +
- encodeURIComponent(item.id.match(options.format) ? item.id.match(options.format)[1] : ''));
- }).join("&");
+ return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
+ });
+ },
+
+ setSequence: function(element, new_sequence) {
+ element = $(element);
+ var options = Object.extend(this.options(element), arguments[2] || { });
+
+ var nodeMap = { };
+ this.findElements(element, options).each( function(n) {
+ if (n.id.match(options.format))
+ nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
+ n.parentNode.removeChild(n);
+ });
+
+ new_sequence.each(function(ident) {
+ var n = nodeMap[ident];
+ if (n) {
+ n[1].appendChild(n[0]);
+ delete nodeMap[ident];
+ }
+ });
+ },
+
+ serialize: function(element) {
+ element = $(element);
+ var options = Object.extend(Sortable.options(element), arguments[1] || { });
+ var name = encodeURIComponent(
+ (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
+
+ if (options.tree) {
+ return Sortable.tree(element, arguments[1]).children.map( function (item) {
+ return [name + Sortable._constructIndex(item) + "[id]=" +
+ encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
+ }).flatten().join('&');
+ } else {
+ return Sortable.sequence(element, arguments[1]).map( function(item) {
+ return name + "[]=" + encodeURIComponent(item);
+ }).join('&');
+ }
}
-}
\ No newline at end of file
+}
+
+// Returns true if child is contained within element
+Element.isParent = function(child, element) {
+ if (!child.parentNode || child == element) return false;
+ if (child.parentNode == element) return true;
+ return Element.isParent(child.parentNode, element);
+}
+
+Element.findChildren = function(element, only, recursive, tagName) {
+ if(!element.hasChildNodes()) return null;
+ tagName = tagName.toUpperCase();
+ if(only) only = [only].flatten();
+ var elements = [];
+ $A(element.childNodes).each( function(e) {
+ if(e.tagName && e.tagName.toUpperCase()==tagName &&
+ (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
+ elements.push(e);
+ if(recursive) {
+ var grandchildren = Element.findChildren(e, only, recursive, tagName);
+ if(grandchildren) elements.push(grandchildren);
+ }
+ });
+
+ return (elements.length>0 ? elements.flatten() : []);
+}
+
+Element.offsetSize = function (element, type) {
+ return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];
+}
Modified: jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/effects.js
==============================================================================
--- jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/effects.js (original)
+++ jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/effects.js Fri Jun 27 10:34:57 2008
@@ -1,107 +1,126 @@
-// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// script.aculo.us effects.js v1.8.1, Thu Jan 03 22:07:12 -0500 2008
+
+// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// Contributors:
// Justin Palmer (http://encytemedia.com/)
// Mark Pilgrim (http://diveintomark.org/)
// Martin Bialasinki
//
-// See scriptaculous.js for full license.
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
-/* ------------- element ext -------------- */
-
// converts rgb() and #xxx to #xxxxxx format,
// returns self (or first argument) if not convertable
String.prototype.parseColor = function() {
- var color = '#';
- if(this.slice(0,4) == 'rgb(') {
+ var color = '#';
+ if (this.slice(0,4) == 'rgb(') {
var cols = this.slice(4,this.length-1).split(',');
var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
} else {
- if(this.slice(0,1) == '#') {
- if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
- if(this.length==7) color = this.toLowerCase();
+ if (this.slice(0,1) == '#') {
+ if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
+ if (this.length==7) color = this.toLowerCase();
}
}
- return(color.length==7 ? color : (arguments[0] || this));
-}
+ return (color.length==7 ? color : (arguments[0] || this));
+};
+
+/*--------------------------------------------------------------------------*/
Element.collectTextNodes = function(element) {
return $A($(element).childNodes).collect( function(node) {
return (node.nodeType==3 ? node.nodeValue :
(node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
}).flatten().join('');
-}
+};
Element.collectTextNodesIgnoreClass = function(element, className) {
return $A($(element).childNodes).collect( function(node) {
return (node.nodeType==3 ? node.nodeValue :
((node.hasChildNodes() && !Element.hasClassName(node,className)) ?
- Element.collectTextNodes(node) : ''));
+ Element.collectTextNodesIgnoreClass(node, className) : ''));
}).flatten().join('');
-}
+};
-Element.setStyle = function(element, style) {
- element = $(element);
- for(k in style) element.style[k.camelize()] = style[k];
-}
+Element.setContentZoom = function(element, percent) {
+ element = $(element);
+ element.setStyle({fontSize: (percent/100) + 'em'});
+ if (Prototype.Browser.WebKit) window.scrollBy(0,0);
+ return element;
+};
-Element.setContentZoom = function(element, percent) {
- Element.setStyle(element, {fontSize: (percent/100) + 'em'});
- if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
-}
-
-Element.getOpacity = function(element){
- var opacity;
- if (opacity = Element.getStyle(element, 'opacity'))
- return parseFloat(opacity);
- if (opacity = (Element.getStyle(element, 'filter') || '').match(/alpha\(opacity=(.*)\)/))
- if(opacity[1]) return parseFloat(opacity[1]) / 100;
- return 1.0;
-}
-
-Element.setOpacity = function(element, value){
- element= $(element);
- if (value == 1){
- Element.setStyle(element, { opacity:
- (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ?
- 0.999999 : null });
- if(/MSIE/.test(navigator.userAgent))
- Element.setStyle(element, {filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')});
- } else {
- if(value < 0.00001) value = 0;
- Element.setStyle(element, {opacity: value});
- if(/MSIE/.test(navigator.userAgent))
- Element.setStyle(element,
- { filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'') +
- 'alpha(opacity='+value*100+')' });
- }
-}
-
-Element.getInlineOpacity = function(element){
+Element.getInlineOpacity = function(element){
return $(element).style.opacity || '';
-}
+};
-Element.childrenWithClassName = function(element, className) {
- return $A($(element).getElementsByTagName('*')).select(
- function(c) { return Element.hasClassName(c, className) });
-}
-
-Array.prototype.call = function() {
- var args = arguments;
- this.each(function(f){ f.apply(this, args) });
-}
+Element.forceRerendering = function(element) {
+ try {
+ element = $(element);
+ var n = document.createTextNode(' ');
+ element.appendChild(n);
+ element.removeChild(n);
+ } catch(e) { }
+};
/*--------------------------------------------------------------------------*/
var Effect = {
+ _elementDoesNotExistError: {
+ name: 'ElementDoesNotExistError',
+ message: 'The specified DOM element does not exist, but is required for this effect to operate'
+ },
+ Transitions: {
+ linear: Prototype.K,
+ sinoidal: function(pos) {
+ return (-Math.cos(pos*Math.PI)/2) + 0.5;
+ },
+ reverse: function(pos) {
+ return 1-pos;
+ },
+ flicker: function(pos) {
+ var pos = ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
+ return pos > 1 ? 1 : pos;
+ },
+ wobble: function(pos) {
+ return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
+ },
+ pulse: function(pos, pulses) {
+ pulses = pulses || 5;
+ return (
+ ((pos % (1/pulses)) * pulses).round() == 0 ?
+ ((pos * pulses * 2) - (pos * pulses * 2).floor()) :
+ 1 - ((pos * pulses * 2) - (pos * pulses * 2).floor())
+ );
+ },
+ spring: function(pos) {
+ return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
+ },
+ none: function(pos) {
+ return 0;
+ },
+ full: function(pos) {
+ return 1;
+ }
+ },
+ DefaultOptions: {
+ duration: 1.0, // seconds
+ fps: 100, // 100= assume 66fps max.
+ sync: false, // true for combining
+ from: 0.0,
+ to: 1.0,
+ delay: 0.0,
+ queue: 'parallel'
+ },
tagifyText: function(element) {
var tagifyStyle = 'position:relative';
- if(/MSIE/.test(navigator.userAgent)) tagifyStyle += ';zoom:1';
+ if (Prototype.Browser.IE) tagifyStyle += ';zoom:1';
+
element = $(element);
$A(element.childNodes).each( function(child) {
- if(child.nodeType==3) {
+ if (child.nodeType==3) {
child.nodeValue.toArray().each( function(character) {
element.insertBefore(
- Builder.node('span',{style: tagifyStyle},
+ new Element('span', {style: tagifyStyle}).update(
character == ' ' ? String.fromCharCode(160) : character),
child);
});
@@ -111,8 +130,8 @@
},
multiple: function(element, effect) {
var elements;
- if(((typeof element == 'object') ||
- (typeof element == 'function')) &&
+ if (((typeof element == 'object') ||
+ Object.isFunction(element)) &&
(element.length))
elements = element;
else
@@ -121,7 +140,7 @@
var options = Object.extend({
speed: 0.1,
delay: 0.0
- }, arguments[2] || {});
+ }, arguments[2] || { });
var masterDelay = options.delay;
$A(elements).each( function(element, index) {
@@ -137,52 +156,21 @@
element = $(element);
effect = (effect || 'appear').toLowerCase();
var options = Object.extend({
- queue: { position:'end', scope:(element.id || 'global') }
- }, arguments[2] || {});
- Effect[Element.visible(element) ?
+ queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
+ }, arguments[2] || { });
+ Effect[element.visible() ?
Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
}
};
-var Effect2 = Effect; // deprecated
-
-/* ------------- transitions ------------- */
-
-Effect.Transitions = {}
-
-Effect.Transitions.linear = function(pos) {
- return pos;
-}
-Effect.Transitions.sinoidal = function(pos) {
- return (-Math.cos(pos*Math.PI)/2) + 0.5;
-}
-Effect.Transitions.reverse = function(pos) {
- return 1-pos;
-}
-Effect.Transitions.flicker = function(pos) {
- return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
-}
-Effect.Transitions.wobble = function(pos) {
- return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
-}
-Effect.Transitions.pulse = function(pos) {
- return (Math.floor(pos*10) % 2 == 0 ?
- (pos*10-Math.floor(pos*10)) : 1-(pos*10-Math.floor(pos*10)));
-}
-Effect.Transitions.none = function(pos) {
- return 0;
-}
-Effect.Transitions.full = function(pos) {
- return 1;
-}
+Effect.DefaultOptions.transition = Effect.Transitions.sinoidal;
/* ------------- core effects ------------- */
-Effect.ScopedQueue = Class.create();
-Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
+Effect.ScopedQueue = Class.create(Enumerable, {
initialize: function() {
this.effects = [];
- this.interval = null;
+ this.interval = null;
},
_each: function(iterator) {
this.effects._each(iterator);
@@ -190,7 +178,7 @@
add: function(effect) {
var timestamp = new Date().getTime();
- var position = (typeof effect.options.queue == 'string') ?
+ var position = Object.isString(effect.options.queue) ?
effect.options.queue : effect.options.queue.position;
switch(position) {
@@ -201,6 +189,9 @@
e.finishOn += effect.finishOn;
});
break;
+ case 'with-last':
+ timestamp = this.effects.pluck('startOn').max() || timestamp;
+ break;
case 'end':
// start effect after last queued effect has finished
timestamp = this.effects.pluck('finishOn').max() || timestamp;
@@ -209,113 +200,112 @@
effect.startOn += timestamp;
effect.finishOn += timestamp;
- this.effects.push(effect);
- if(!this.interval)
- this.interval = setInterval(this.loop.bind(this), 40);
+
+ if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
+ this.effects.push(effect);
+
+ if (!this.interval)
+ this.interval = setInterval(this.loop.bind(this), 15);
},
remove: function(effect) {
this.effects = this.effects.reject(function(e) { return e==effect });
- if(this.effects.length == 0) {
+ if (this.effects.length == 0) {
clearInterval(this.interval);
this.interval = null;
}
},
loop: function() {
var timePos = new Date().getTime();
- this.effects.invoke('loop', timePos);
+ for(var i=0, len=this.effects.length;i<len;i++)
+ this.effects[i] && this.effects[i].loop(timePos);
}
});
Effect.Queues = {
instances: $H(),
get: function(queueName) {
- if(typeof queueName != 'string') return queueName;
+ if (!Object.isString(queueName)) return queueName;
- if(!this.instances.get(queueName))
+ return this.instances.get(queueName) ||
this.instances.set(queueName, new Effect.ScopedQueue());
-
- return this.instances.get(queueName);
}
-}
+};
Effect.Queue = Effect.Queues.get('global');
-Effect.DefaultOptions = {
- transition: Effect.Transitions.sinoidal,
- duration: 1.0, // seconds
- fps: 25.0, // max. 25fps due to Effect.Queue implementation
- sync: false, // true for combining
- from: 0.0,
- to: 1.0,
- delay: 0.0,
- queue: 'parallel'
-}
-
-Effect.Base = function() {};
-Effect.Base.prototype = {
+Effect.Base = Class.create({
position: null,
start: function(options) {
- this.options = Object.extend(Object.extend({},Effect.DefaultOptions), options || {});
+ function codeForEvent(options,eventName){
+ return (
+ (options[eventName+'Internal'] ? 'this.options.'+eventName+'Internal(this);' : '') +
+ (options[eventName] ? 'this.options.'+eventName+'(this);' : '')
+ );
+ }
+ if (options && options.transition === false) options.transition = Effect.Transitions.linear;
+ this.options = Object.extend(Object.extend({ },Effect.DefaultOptions), options || { });
this.currentFrame = 0;
this.state = 'idle';
this.startOn = this.options.delay*1000;
- this.finishOn = this.startOn + (this.options.duration*1000);
+ this.finishOn = this.startOn+(this.options.duration*1000);
+ this.fromToDelta = this.options.to-this.options.from;
+ this.totalTime = this.finishOn-this.startOn;
+ this.totalFrames = this.options.fps*this.options.duration;
+
+ eval('this.render = function(pos){ '+
+ 'if (this.state=="idle"){this.state="running";'+
+ codeForEvent(this.options,'beforeSetup')+
+ (this.setup ? 'this.setup();':'')+
+ codeForEvent(this.options,'afterSetup')+
+ '};if (this.state=="running"){'+
+ 'pos=this.options.transition(pos)*'+this.fromToDelta+'+'+this.options.from+';'+
+ 'this.position=pos;'+
+ codeForEvent(this.options,'beforeUpdate')+
+ (this.update ? 'this.update(pos);':'')+
+ codeForEvent(this.options,'afterUpdate')+
+ '}}');
+
this.event('beforeStart');
- if(!this.options.sync)
- Effect.Queues.get(typeof this.options.queue == 'string' ?
+ if (!this.options.sync)
+ Effect.Queues.get(Object.isString(this.options.queue) ?
'global' : this.options.queue.scope).add(this);
},
loop: function(timePos) {
- if(timePos >= this.startOn) {
- if(timePos >= this.finishOn) {
+ if (timePos >= this.startOn) {
+ if (timePos >= this.finishOn) {
this.render(1.0);
this.cancel();
this.event('beforeFinish');
- if(this.finish) this.finish();
+ if (this.finish) this.finish();
this.event('afterFinish');
return;
}
- var pos = (timePos - this.startOn) / (this.finishOn - this.startOn);
- var frame = Math.round(pos * this.options.fps * this.options.duration);
- if(frame > this.currentFrame) {
+ var pos = (timePos - this.startOn) / this.totalTime,
+ frame = (pos * this.totalFrames).round();
+ if (frame > this.currentFrame) {
this.render(pos);
this.currentFrame = frame;
}
}
},
- render: function(pos) {
- if(this.state == 'idle') {
- this.state = 'running';
- this.event('beforeSetup');
- if(this.setup) this.setup();
- this.event('afterSetup');
- }
- if(this.state == 'running') {
- if(this.options.transition) pos = this.options.transition(pos);
- pos *= (this.options.to-this.options.from);
- pos += this.options.from;
- this.position = pos;
- this.event('beforeUpdate');
- if(this.update) this.update(pos);
- this.event('afterUpdate');
- }
- },
cancel: function() {
- if(!this.options.sync)
- Effect.Queues.get(typeof this.options.queue == 'string' ?
+ if (!this.options.sync)
+ Effect.Queues.get(Object.isString(this.options.queue) ?
'global' : this.options.queue.scope).remove(this);
this.state = 'finished';
},
event: function(eventName) {
- if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
- if(this.options[eventName]) this.options[eventName](this);
+ if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
+ if (this.options[eventName]) this.options[eventName](this);
},
inspect: function() {
- return '#<Effect:' + $H(this).inspect() + ',options:' + $H(this.options).inspect() + '>';
+ var data = $H();
+ for(property in this)
+ if (!Object.isFunction(this[property])) data.set(property, this[property]);
+ return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';
}
-}
+});
-Effect.Parallel = Class.create();
-Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
+Effect.Parallel = Class.create(Effect.Base, {
initialize: function(effects) {
this.effects = effects || [];
this.start(arguments[1]);
@@ -328,59 +318,76 @@
effect.render(1.0);
effect.cancel();
effect.event('beforeFinish');
- if(effect.finish) effect.finish(position);
+ if (effect.finish) effect.finish(position);
effect.event('afterFinish');
});
}
});
-Effect.Opacity = Class.create();
-Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
+Effect.Tween = Class.create(Effect.Base, {
+ initialize: function(object, from, to) {
+ object = Object.isString(object) ? $(object) : object;
+ var args = $A(arguments), method = args.last(),
+ options = args.length == 5 ? args[3] : null;
+ this.method = Object.isFunction(method) ? method.bind(object) :
+ Object.isFunction(object[method]) ? object[method].bind(object) :
+ function(value) { object[method] = value };
+ this.start(Object.extend({ from: from, to: to }, options || { }));
+ },
+ update: function(position) {
+ this.method(position);
+ }
+});
+
+Effect.Event = Class.create(Effect.Base, {
+ initialize: function() {
+ this.start(Object.extend({ duration: 0 }, arguments[0] || { }));
+ },
+ update: Prototype.emptyFunction
+});
+
+Effect.Opacity = Class.create(Effect.Base, {
initialize: function(element) {
this.element = $(element);
+ if (!this.element) throw(Effect._elementDoesNotExistError);
// make this work on IE on elements without 'layout'
- if(/MSIE/.test(navigator.userAgent) && (!this.element.hasLayout))
- Element.setStyle(this.element, {zoom: 1});
+ if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
+ this.element.setStyle({zoom: 1});
var options = Object.extend({
- from: Element.getOpacity(this.element) || 0.0,
+ from: this.element.getOpacity() || 0.0,
to: 1.0
- }, arguments[1] || {});
+ }, arguments[1] || { });
this.start(options);
},
update: function(position) {
- Element.setOpacity(this.element, position);
+ this.element.setOpacity(position);
}
});
-Effect.Move = Class.create();
-Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {
+Effect.Move = Class.create(Effect.Base, {
initialize: function(element) {
this.element = $(element);
+ if (!this.element) throw(Effect._elementDoesNotExistError);
var options = Object.extend({
x: 0,
y: 0,
mode: 'relative'
- }, arguments[1] || {});
+ }, arguments[1] || { });
this.start(options);
},
setup: function() {
- // Bug in Opera: Opera returns the "real" position of a static element or
- // relative element that does not have top/left explicitly set.
- // ==> Always set top and left for position relative elements in your stylesheets
- // (to 0 if you do not need them)
- Element.makePositioned(this.element);
- this.originalLeft = parseFloat(Element.getStyle(this.element,'left') || '0');
- this.originalTop = parseFloat(Element.getStyle(this.element,'top') || '0');
- if(this.options.mode == 'absolute') {
- // absolute movement, so we need to calc deltaX and deltaY
+ this.element.makePositioned();
+ this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
+ this.originalTop = parseFloat(this.element.getStyle('top') || '0');
+ if (this.options.mode == 'absolute') {
this.options.x = this.options.x - this.originalLeft;
this.options.y = this.options.y - this.originalTop;
}
},
update: function(position) {
- Element.setStyle(this.element, {
- left: this.options.x * position + this.originalLeft + 'px',
- top: this.options.y * position + this.originalTop + 'px'
+ this.element.setStyle({
+ left: (this.options.x * position + this.originalLeft).round() + 'px',
+ top: (this.options.y * position + this.originalTop).round() + 'px'
});
}
});
@@ -388,29 +395,29 @@
// for backwards compatibility
Effect.MoveBy = function(element, toTop, toLeft) {
return new Effect.Move(element,
- Object.extend({ x: toLeft, y: toTop }, arguments[3] || {}));
+ Object.extend({ x: toLeft, y: toTop }, arguments[3] || { }));
};
-Effect.Scale = Class.create();
-Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
+Effect.Scale = Class.create(Effect.Base, {
initialize: function(element, percent) {
- this.element = $(element)
+ this.element = $(element);
+ if (!this.element) throw(Effect._elementDoesNotExistError);
var options = Object.extend({
scaleX: true,
scaleY: true,
scaleContent: true,
scaleFromCenter: false,
- scaleMode: 'box', // 'box' or 'contents' or {} with provided values
+ scaleMode: 'box', // 'box' or 'contents' or { } with provided values
scaleFrom: 100.0,
scaleTo: percent
- }, arguments[2] || {});
+ }, arguments[2] || { });
this.start(options);
},
setup: function() {
this.restoreAfterFinish = this.options.restoreAfterFinish || false;
- this.elementPositioning = Element.getStyle(this.element,'position');
+ this.elementPositioning = this.element.getStyle('position');
- this.originalStyle = {};
+ this.originalStyle = { };
['top','left','width','height','fontSize'].each( function(k) {
this.originalStyle[k] = this.element.style[k];
}.bind(this));
@@ -418,9 +425,9 @@
this.originalTop = this.element.offsetTop;
this.originalLeft = this.element.offsetLeft;
- var fontSize = Element.getStyle(this.element,'font-size') || '100%';
- ['em','px','%'].each( function(fontSizeType) {
- if(fontSize.indexOf(fontSizeType)>0) {
+ var fontSize = this.element.getStyle('font-size') || '100%';
+ ['em','px','%','pt'].each( function(fontSizeType) {
+ if (fontSize.indexOf(fontSizeType)>0) {
this.fontSize = parseFloat(fontSize);
this.fontSizeType = fontSizeType;
}
@@ -429,183 +436,184 @@
this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
this.dims = null;
- if(this.options.scaleMode=='box')
+ if (this.options.scaleMode=='box')
this.dims = [this.element.offsetHeight, this.element.offsetWidth];
- if(/^content/.test(this.options.scaleMode))
+ if (/^content/.test(this.options.scaleMode))
this.dims = [this.element.scrollHeight, this.element.scrollWidth];
- if(!this.dims)
+ if (!this.dims)
this.dims = [this.options.scaleMode.originalHeight,
this.options.scaleMode.originalWidth];
},
update: function(position) {
var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
- if(this.options.scaleContent && this.fontSize)
- Element.setStyle(this.element, {fontSize: this.fontSize * currentScale + this.fontSizeType });
+ if (this.options.scaleContent && this.fontSize)
+ this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
},
finish: function(position) {
- if (this.restoreAfterFinish) Element.setStyle(this.element, this.originalStyle);
+ if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
},
setDimensions: function(height, width) {
- var d = {};
- if(this.options.scaleX) d.width = width + 'px';
- if(this.options.scaleY) d.height = height + 'px';
- if(this.options.scaleFromCenter) {
+ var d = { };
+ if (this.options.scaleX) d.width = width.round() + 'px';
+ if (this.options.scaleY) d.height = height.round() + 'px';
+ if (this.options.scaleFromCenter) {
var topd = (height - this.dims[0])/2;
var leftd = (width - this.dims[1])/2;
- if(this.elementPositioning == 'absolute') {
- if(this.options.scaleY) d.top = this.originalTop-topd + 'px';
- if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
+ if (this.elementPositioning == 'absolute') {
+ if (this.options.scaleY) d.top = this.originalTop-topd + 'px';
+ if (this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
} else {
- if(this.options.scaleY) d.top = -topd + 'px';
- if(this.options.scaleX) d.left = -leftd + 'px';
+ if (this.options.scaleY) d.top = -topd + 'px';
+ if (this.options.scaleX) d.left = -leftd + 'px';
}
}
- Element.setStyle(this.element, d);
+ this.element.setStyle(d);
}
});
-Effect.Highlight = Class.create();
-Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
+Effect.Highlight = Class.create(Effect.Base, {
initialize: function(element) {
this.element = $(element);
- var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});
+ if (!this.element) throw(Effect._elementDoesNotExistError);
+ var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || { });
this.start(options);
},
setup: function() {
// Prevent executing on elements not in the layout flow
- if(Element.getStyle(this.element, 'display')=='none') { this.cancel(); return; }
+ if (this.element.getStyle('display')=='none') { this.cancel(); return; }
// Disable background image during the effect
- this.oldStyle = {
- backgroundImage: Element.getStyle(this.element, 'background-image') };
- Element.setStyle(this.element, {backgroundImage: 'none'});
- if(!this.options.endcolor)
- this.options.endcolor = Element.getStyle(this.element, 'background-color').parseColor('#ffffff');
- if(!this.options.restorecolor)
- this.options.restorecolor = Element.getStyle(this.element, 'background-color');
+ this.oldStyle = { };
+ if (!this.options.keepBackgroundImage) {
+ this.oldStyle.backgroundImage = this.element.getStyle('background-image');
+ this.element.setStyle({backgroundImage: 'none'});
+ }
+ if (!this.options.endcolor)
+ this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
+ if (!this.options.restorecolor)
+ this.options.restorecolor = this.element.getStyle('background-color');
// init color calculations
this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
},
update: function(position) {
- Element.setStyle(this.element,{backgroundColor: $R(0,2).inject('#',function(m,v,i){
- return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) });
+ this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
+ return m+((this._base[i]+(this._delta[i]*position)).round().toColorPart()); }.bind(this)) });
},
finish: function() {
- Element.setStyle(this.element, Object.extend(this.oldStyle, {
+ this.element.setStyle(Object.extend(this.oldStyle, {
backgroundColor: this.options.restorecolor
}));
}
});
-Effect.ScrollTo = Class.create();
-Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {
- initialize: function(element) {
- this.element = $(element);
- this.start(arguments[1] || {});
- },
- setup: function() {
- Position.prepare();
- var offsets = Position.cumulativeOffset(this.element);
- if(this.options.offset) offsets[1] += this.options.offset;
- var max = window.innerHeight ?
- window.height - window.innerHeight :
- document.body.scrollHeight -
- (document.documentElement.clientHeight ?
- document.documentElement.clientHeight : document.body.clientHeight);
- this.scrollStart = Position.deltaY;
- this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart;
- },
- update: function(position) {
- Position.prepare();
- window.scrollTo(Position.deltaX,
- this.scrollStart + (position*this.delta));
- }
-});
+Effect.ScrollTo = function(element) {
+ var options = arguments[1] || { },
+ scrollOffsets = document.viewport.getScrollOffsets(),
+ elementOffsets = $(element).cumulativeOffset(),
+ max = (window.height || document.body.scrollHeight) - document.viewport.getHeight();
+
+ if (options.offset) elementOffsets[1] += options.offset;
+
+ return new Effect.Tween(null,
+ scrollOffsets.top,
+ elementOffsets[1] > max ? max : elementOffsets[1],
+ options,
+ function(p){ scrollTo(scrollOffsets.left, p.round()) }
+ );
+};
/* ------------- combination effects ------------- */
Effect.Fade = function(element) {
- var oldOpacity = Element.getInlineOpacity(element);
+ element = $(element);
+ var oldOpacity = element.getInlineOpacity();
var options = Object.extend({
- from: Element.getOpacity(element) || 1.0,
- to: 0.0,
- afterFinishInternal: function(effect) { with(Element) {
- if(effect.options.to!=0) return;
- hide(effect.element);
- setStyle(effect.element, {opacity: oldOpacity}); }}
- }, arguments[1] || {});
+ from: element.getOpacity() || 1.0,
+ to: 0.0,
+ afterFinishInternal: function(effect) {
+ if (effect.options.to!=0) return;
+ effect.element.hide().setStyle({opacity: oldOpacity});
+ }
+ }, arguments[1] || { });
return new Effect.Opacity(element,options);
-}
+};
Effect.Appear = function(element) {
+ element = $(element);
var options = Object.extend({
- from: (Element.getStyle(element, 'display') == 'none' ? 0.0 : Element.getOpacity(element) || 0.0),
+ from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
to: 1.0,
- beforeSetup: function(effect) { with(Element) {
- setOpacity(effect.element, effect.options.from);
- show(effect.element); }}
- }, arguments[1] || {});
+ // force Safari to render floated elements properly
+ afterFinishInternal: function(effect) {
+ effect.element.forceRerendering();
+ },
+ beforeSetup: function(effect) {
+ effect.element.setOpacity(effect.options.from).show();
+ }}, arguments[1] || { });
return new Effect.Opacity(element,options);
-}
+};
Effect.Puff = function(element) {
element = $(element);
- var oldStyle = { opacity: Element.getInlineOpacity(element), position: Element.getStyle(element, 'position') };
+ var oldStyle = {
+ opacity: element.getInlineOpacity(),
+ position: element.getStyle('position'),
+ top: element.style.top,
+ left: element.style.left,
+ width: element.style.width,
+ height: element.style.height
+ };
return new Effect.Parallel(
[ new Effect.Scale(element, 200,
{ sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
Object.extend({ duration: 1.0,
- beforeSetupInternal: function(effect) { with(Element) {
- setStyle(effect.effects[0].element, {position: 'absolute'}); }},
- afterFinishInternal: function(effect) { with(Element) {
- hide(effect.effects[0].element);
- setStyle(effect.effects[0].element, oldStyle); }}
- }, arguments[1] || {})
+ beforeSetupInternal: function(effect) {
+ Position.absolutize(effect.effects[0].element)
+ },
+ afterFinishInternal: function(effect) {
+ effect.effects[0].element.hide().setStyle(oldStyle); }
+ }, arguments[1] || { })
);
-}
+};
Effect.BlindUp = function(element) {
element = $(element);
- Element.makeClipping(element);
- return new Effect.Scale(element, 0,
+ element.makeClipping();
+ return new Effect.Scale(element, 0,
Object.extend({ scaleContent: false,
scaleX: false,
restoreAfterFinish: true,
- afterFinishInternal: function(effect) { with(Element) {
- [hide, undoClipping].call(effect.element); }}
- }, arguments[1] || {})
+ afterFinishInternal: function(effect) {
+ effect.element.hide().undoClipping();
+ }
+ }, arguments[1] || { })
);
-}
+};
Effect.BlindDown = function(element) {
element = $(element);
- var oldHeight = Element.getStyle(element, 'height');
- var elementDimensions = Element.getDimensions(element);
- return new Effect.Scale(element, 100,
- Object.extend({ scaleContent: false,
- scaleX: false,
- scaleFrom: 0,
- scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
- restoreAfterFinish: true,
- afterSetup: function(effect) { with(Element) {
- makeClipping(effect.element);
- setStyle(effect.element, {height: '0px'});
- show(effect.element);
- }},
- afterFinishInternal: function(effect) { with(Element) {
- undoClipping(effect.element);
- setStyle(effect.element, {height: oldHeight});
- }}
- }, arguments[1] || {})
- );
-}
+ var elementDimensions = element.getDimensions();
+ return new Effect.Scale(element, 100, Object.extend({
+ scaleContent: false,
+ scaleX: false,
+ scaleFrom: 0,
+ scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
+ restoreAfterFinish: true,
+ afterSetup: function(effect) {
+ effect.element.makeClipping().setStyle({height: '0px'}).show();
+ },
+ afterFinishInternal: function(effect) {
+ effect.element.undoClipping();
+ }
+ }, arguments[1] || { }));
+};
Effect.SwitchOff = function(element) {
element = $(element);
- var oldOpacity = Element.getInlineOpacity(element);
- return new Effect.Appear(element, {
+ var oldOpacity = element.getInlineOpacity();
+ return new Effect.Appear(element, Object.extend({
duration: 0.4,
from: 0,
transition: Effect.Transitions.flicker,
@@ -613,146 +621,150 @@
new Effect.Scale(effect.element, 1, {
duration: 0.3, scaleFromCenter: true,
scaleX: false, scaleContent: false, restoreAfterFinish: true,
- beforeSetup: function(effect) { with(Element) {
- [makePositioned,makeClipping].call(effect.element);
- }},
- afterFinishInternal: function(effect) { with(Element) {
- [hide,undoClipping,undoPositioned].call(effect.element);
- setStyle(effect.element, {opacity: oldOpacity});
- }}
+ beforeSetup: function(effect) {
+ effect.element.makePositioned().makeClipping();
+ },
+ afterFinishInternal: function(effect) {
+ effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
+ }
})
}
- });
-}
+ }, arguments[1] || { }));
+};
Effect.DropOut = function(element) {
element = $(element);
var oldStyle = {
- top: Element.getStyle(element, 'top'),
- left: Element.getStyle(element, 'left'),
- opacity: Element.getInlineOpacity(element) };
+ top: element.getStyle('top'),
+ left: element.getStyle('left'),
+ opacity: element.getInlineOpacity() };
return new Effect.Parallel(
[ new Effect.Move(element, {x: 0, y: 100, sync: true }),
new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
Object.extend(
{ duration: 0.5,
- beforeSetup: function(effect) { with(Element) {
- makePositioned(effect.effects[0].element); }},
- afterFinishInternal: function(effect) { with(Element) {
- [hide, undoPositioned].call(effect.effects[0].element);
- setStyle(effect.effects[0].element, oldStyle); }}
- }, arguments[1] || {}));
-}
+ beforeSetup: function(effect) {
+ effect.effects[0].element.makePositioned();
+ },
+ afterFinishInternal: function(effect) {
+ effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
+ }
+ }, arguments[1] || { }));
+};
Effect.Shake = function(element) {
element = $(element);
+ var options = Object.extend({
+ distance: 20,
+ duration: 0.5
+ }, arguments[1] || {});
+ var distance = parseFloat(options.distance);
+ var split = parseFloat(options.duration) / 10.0;
var oldStyle = {
- top: Element.getStyle(element, 'top'),
- left: Element.getStyle(element, 'left') };
- return new Effect.Move(element,
- { x: 20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
- new Effect.Move(effect.element,
- { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
- new Effect.Move(effect.element,
- { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
- new Effect.Move(effect.element,
- { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
- new Effect.Move(effect.element,
- { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
- new Effect.Move(effect.element,
- { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { with(Element) {
- undoPositioned(effect.element);
- setStyle(effect.element, oldStyle);
- }}}) }}) }}) }}) }}) }});
-}
+ top: element.getStyle('top'),
+ left: element.getStyle('left') };
+ return new Effect.Move(element,
+ { x: distance, y: 0, duration: split, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
+ new Effect.Move(effect.element,
+ { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) {
+ effect.element.undoPositioned().setStyle(oldStyle);
+ }}) }}) }}) }}) }}) }});
+};
Effect.SlideDown = function(element) {
- element = $(element);
- Element.cleanWhitespace(element);
+ element = $(element).cleanWhitespace();
// SlideDown need to have the content of the element wrapped in a container element with fixed height!
- var oldInnerBottom = Element.getStyle(element.firstChild, 'bottom');
- var elementDimensions = Element.getDimensions(element);
+ var oldInnerBottom = element.down().getStyle('bottom');
+ var elementDimensions = element.getDimensions();
return new Effect.Scale(element, 100, Object.extend({
scaleContent: false,
scaleX: false,
- scaleFrom: 0,
+ scaleFrom: window.opera ? 0 : 1,
scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
restoreAfterFinish: true,
- afterSetup: function(effect) { with(Element) {
- makePositioned(effect.element);
- makePositioned(effect.element.firstChild);
- if(window.opera) setStyle(effect.element, {top: ''});
- makeClipping(effect.element);
- setStyle(effect.element, {height: '0px'});
- show(element); }},
- afterUpdateInternal: function(effect) { with(Element) {
- setStyle(effect.element.firstChild, {bottom:
- (effect.dims[0] - effect.element.clientHeight) + 'px' }); }},
- afterFinishInternal: function(effect) { with(Element) {
- undoClipping(effect.element);
- undoPositioned(effect.element.firstChild);
- undoPositioned(effect.element);
- setStyle(effect.element.firstChild, {bottom: oldInnerBottom}); }}
- }, arguments[1] || {})
+ afterSetup: function(effect) {
+ effect.element.makePositioned();
+ effect.element.down().makePositioned();
+ if (window.opera) effect.element.setStyle({top: ''});
+ effect.element.makeClipping().setStyle({height: '0px'}).show();
+ },
+ afterUpdateInternal: function(effect) {
+ effect.element.down().setStyle({bottom:
+ (effect.dims[0] - effect.element.clientHeight) + 'px' });
+ },
+ afterFinishInternal: function(effect) {
+ effect.element.undoClipping().undoPositioned();
+ effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
+ }, arguments[1] || { })
);
-}
-
+};
+
Effect.SlideUp = function(element) {
- element = $(element);
- Element.cleanWhitespace(element);
- var oldInnerBottom = Element.getStyle(element.firstChild, 'bottom');
- return new Effect.Scale(element, 0,
+ element = $(element).cleanWhitespace();
+ var oldInnerBottom = element.down().getStyle('bottom');
+ var elementDimensions = element.getDimensions();
+ return new Effect.Scale(element, window.opera ? 0 : 1,
Object.extend({ scaleContent: false,
scaleX: false,
scaleMode: 'box',
scaleFrom: 100,
+ scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
restoreAfterFinish: true,
- beforeStartInternal: function(effect) { with(Element) {
- makePositioned(effect.element);
- makePositioned(effect.element.firstChild);
- if(window.opera) setStyle(effect.element, {top: ''});
- makeClipping(effect.element);
- show(element); }},
- afterUpdateInternal: function(effect) { with(Element) {
- setStyle(effect.element.firstChild, {bottom:
- (effect.dims[0] - effect.element.clientHeight) + 'px' }); }},
- afterFinishInternal: function(effect) { with(Element) {
- [hide, undoClipping].call(effect.element);
- undoPositioned(effect.element.firstChild);
- undoPositioned(effect.element);
- setStyle(effect.element.firstChild, {bottom: oldInnerBottom}); }}
- }, arguments[1] || {})
+ afterSetup: function(effect) {
+ effect.element.makePositioned();
+ effect.element.down().makePositioned();
+ if (window.opera) effect.element.setStyle({top: ''});
+ effect.element.makeClipping().show();
+ },
+ afterUpdateInternal: function(effect) {
+ effect.element.down().setStyle({bottom:
+ (effect.dims[0] - effect.element.clientHeight) + 'px' });
+ },
+ afterFinishInternal: function(effect) {
+ effect.element.hide().undoClipping().undoPositioned();
+ effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom});
+ }
+ }, arguments[1] || { })
);
-}
+};
// Bug in opera makes the TD containing this element expand for a instance after finish
Effect.Squish = function(element) {
- return new Effect.Scale(element, window.opera ? 1 : 0,
- { restoreAfterFinish: true,
- beforeSetup: function(effect) { with(Element) {
- makeClipping(effect.element); }},
- afterFinishInternal: function(effect) { with(Element) {
- hide(effect.element);
- undoClipping(effect.element); }}
+ return new Effect.Scale(element, window.opera ? 1 : 0, {
+ restoreAfterFinish: true,
+ beforeSetup: function(effect) {
+ effect.element.makeClipping();
+ },
+ afterFinishInternal: function(effect) {
+ effect.element.hide().undoClipping();
+ }
});
-}
+};
Effect.Grow = function(element) {
element = $(element);
var options = Object.extend({
direction: 'center',
- moveTransistion: Effect.Transitions.sinoidal,
+ moveTransition: Effect.Transitions.sinoidal,
scaleTransition: Effect.Transitions.sinoidal,
opacityTransition: Effect.Transitions.full
- }, arguments[1] || {});
+ }, arguments[1] || { });
var oldStyle = {
top: element.style.top,
left: element.style.left,
height: element.style.height,
width: element.style.width,
- opacity: Element.getInlineOpacity(element) };
+ opacity: element.getInlineOpacity() };
- var dims = Element.getDimensions(element);
+ var dims = element.getDimensions();
var initialMoveX, initialMoveY;
var moveX, moveY;
@@ -788,11 +800,9 @@
x: initialMoveX,
y: initialMoveY,
duration: 0.01,
- beforeSetup: function(effect) { with(Element) {
- hide(effect.element);
- makeClipping(effect.element);
- makePositioned(effect.element);
- }},
+ beforeSetup: function(effect) {
+ effect.element.hide().makeClipping().makePositioned();
+ },
afterFinishInternal: function(effect) {
new Effect.Parallel(
[ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
@@ -801,34 +811,34 @@
scaleMode: { originalHeight: dims.height, originalWidth: dims.width },
sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
], Object.extend({
- beforeSetup: function(effect) { with(Element) {
- setStyle(effect.effects[0].element, {height: '0px'});
- show(effect.effects[0].element); }},
- afterFinishInternal: function(effect) { with(Element) {
- [undoClipping, undoPositioned].call(effect.effects[0].element);
- setStyle(effect.effects[0].element, oldStyle); }}
+ beforeSetup: function(effect) {
+ effect.effects[0].element.setStyle({height: '0px'}).show();
+ },
+ afterFinishInternal: function(effect) {
+ effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);
+ }
}, options)
)
}
});
-}
+};
Effect.Shrink = function(element) {
element = $(element);
var options = Object.extend({
direction: 'center',
- moveTransistion: Effect.Transitions.sinoidal,
+ moveTransition: Effect.Transitions.sinoidal,
scaleTransition: Effect.Transitions.sinoidal,
opacityTransition: Effect.Transitions.none
- }, arguments[1] || {});
+ }, arguments[1] || { });
var oldStyle = {
top: element.style.top,
left: element.style.left,
height: element.style.height,
width: element.style.width,
- opacity: Element.getInlineOpacity(element) };
+ opacity: element.getInlineOpacity() };
- var dims = Element.getDimensions(element);
+ var dims = element.getDimensions();
var moveX, moveY;
switch (options.direction) {
@@ -858,27 +868,27 @@
new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
], Object.extend({
- beforeStartInternal: function(effect) { with(Element) {
- [makePositioned, makeClipping].call(effect.effects[0].element) }},
- afterFinishInternal: function(effect) { with(Element) {
- [hide, undoClipping, undoPositioned].call(effect.effects[0].element);
- setStyle(effect.effects[0].element, oldStyle); }}
+ beforeStartInternal: function(effect) {
+ effect.effects[0].element.makePositioned().makeClipping();
+ },
+ afterFinishInternal: function(effect) {
+ effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
}, options)
);
-}
+};
Effect.Pulsate = function(element) {
element = $(element);
- var options = arguments[1] || {};
- var oldOpacity = Element.getInlineOpacity(element);
+ var options = arguments[1] || { };
+ var oldOpacity = element.getInlineOpacity();
var transition = options.transition || Effect.Transitions.sinoidal;
- var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos)) };
+ var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) };
reverser.bind(transition);
return new Effect.Opacity(element,
- Object.extend(Object.extend({ duration: 3.0, from: 0,
- afterFinishInternal: function(effect) { Element.setStyle(effect.element, {opacity: oldOpacity}); }
+ Object.extend(Object.extend({ duration: 2.0, from: 0,
+ afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
}, options), {transition: reverser}));
-}
+};
Effect.Fold = function(element) {
element = $(element);
@@ -887,7 +897,7 @@
left: element.style.left,
width: element.style.width,
height: element.style.height };
- Element.makeClipping(element);
+ element.makeClipping();
return new Effect.Scale(element, 5, Object.extend({
scaleContent: false,
scaleX: false,
@@ -895,9 +905,218 @@
new Effect.Scale(element, 1, {
scaleContent: false,
scaleY: false,
- afterFinishInternal: function(effect) { with(Element) {
- [hide, undoClipping].call(effect.element);
- setStyle(effect.element, oldStyle);
- }} });
- }}, arguments[1] || {}));
-}
+ afterFinishInternal: function(effect) {
+ effect.element.hide().undoClipping().setStyle(oldStyle);
+ } });
+ }}, arguments[1] || { }));
+};
+
+Effect.Morph = Class.create(Effect.Base, {
+ initialize: function(element) {
+ this.element = $(element);
+ if (!this.element) throw(Effect._elementDoesNotExistError);
+ var options = Object.extend({
+ style: { }
+ }, arguments[1] || { });
+
+ if (!Object.isString(options.style)) this.style = $H(options.style);
+ else {
+ if (options.style.include(':'))
+ this.style = options.style.parseStyle();
+ else {
+ this.element.addClassName(options.style);
+ this.style = $H(this.element.getStyles());
+ this.element.removeClassName(options.style);
+ var css = this.element.getStyles();
+ this.style = this.style.reject(function(style) {
+ return style.value == css[style.key];
+ });
+ options.afterFinishInternal = function(effect) {
+ effect.element.addClassName(effect.options.style);
+ effect.transforms.each(function(transform) {
+ effect.element.style[transform.style] = '';
+ });
+ }
+ }
+ }
+ this.start(options);
+ },
+
+ setup: function(){
+ function parseColor(color){
+ if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
+ color = color.parseColor();
+ return $R(0,2).map(function(i){
+ return parseInt( color.slice(i*2+1,i*2+3), 16 )
+ });
+ }
+ this.transforms = this.style.map(function(pair){
+ var property = pair[0], value = pair[1], unit = null;
+
+ if (value.parseColor('#zzzzzz') != '#zzzzzz') {
+ value = value.parseColor();
+ unit = 'color';
+ } else if (property == 'opacity') {
+ value = parseFloat(value);
+ if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
+ this.element.setStyle({zoom: 1});
+ } else if (Element.CSS_LENGTH.test(value)) {
+ var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
+ value = parseFloat(components[1]);
+ unit = (components.length == 3) ? components[2] : null;
+ }
+
+ var originalValue = this.element.getStyle(property);
+ return {
+ style: property.camelize(),
+ originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0),
+ targetValue: unit=='color' ? parseColor(value) : value,
+ unit: unit
+ };
+ }.bind(this)).reject(function(transform){
+ return (
+ (transform.originalValue == transform.targetValue) ||
+ (
+ transform.unit != 'color' &&
+ (isNaN(transform.originalValue) || isNaN(transform.targetValue))
+ )
+ )
+ });
+ },
+ update: function(position) {
+ var style = { }, transform, i = this.transforms.length;
+ while(i--)
+ style[(transform = this.transforms[i]).style] =
+ transform.unit=='color' ? '#'+
+ (Math.round(transform.originalValue[0]+
+ (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() +
+ (Math.round(transform.originalValue[1]+
+ (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() +
+ (Math.round(transform.originalValue[2]+
+ (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :
+ (transform.originalValue +
+ (transform.targetValue - transform.originalValue) * position).toFixed(3) +
+ (transform.unit === null ? '' : transform.unit);
+ this.element.setStyle(style, true);
+ }
+});
+
+Effect.Transform = Class.create({
+ initialize: function(tracks){
+ this.tracks = [];
+ this.options = arguments[1] || { };
+ this.addTracks(tracks);
+ },
+ addTracks: function(tracks){
+ tracks.each(function(track){
+ track = $H(track);
+ var data = track.values().first();
+ this.tracks.push($H({
+ ids: track.keys().first(),
+ effect: Effect.Morph,
+ options: { style: data }
+ }));
+ }.bind(this));
+ return this;
+ },
+ play: function(){
+ return new Effect.Parallel(
+ this.tracks.map(function(track){
+ var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options');
+ var elements = [$(ids) || $$(ids)].flatten();
+ return elements.map(function(e){ return new effect(e, Object.extend({ sync:true }, options)) });
+ }).flatten(),
+ this.options
+ );
+ }
+});
+
+Element.CSS_PROPERTIES = $w(
+ 'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' +
+ 'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
+ 'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
+ 'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
+ 'fontSize fontWeight height left letterSpacing lineHeight ' +
+ 'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
+ 'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
+ 'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
+ 'right textIndent top width wordSpacing zIndex');
+
+Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
+
+String.__parseStyleElement = document.createElement('div');
+String.prototype.parseStyle = function(){
+ var style, styleRules = $H();
+ if (Prototype.Browser.WebKit)
+ style = new Element('div',{style:this}).style;
+ else {
+ String.__parseStyleElement.innerHTML = '<div style="' + this + '"></div>';
+ style = String.__parseStyleElement.childNodes[0].style;
+ }
+
+ Element.CSS_PROPERTIES.each(function(property){
+ if (style[property]) styleRules.set(property, style[property]);
+ });
+
+ if (Prototype.Browser.IE && this.include('opacity'))
+ styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]);
+
+ return styleRules;
+};
+
+if (document.defaultView && document.defaultView.getComputedStyle) {
+ Element.getStyles = function(element) {
+ var css = document.defaultView.getComputedStyle($(element), null);
+ return Element.CSS_PROPERTIES.inject({ }, function(styles, property) {
+ styles[property] = css[property];
+ return styles;
+ });
+ };
+} else {
+ Element.getStyles = function(element) {
+ element = $(element);
+ var css = element.currentStyle, styles;
+ styles = Element.CSS_PROPERTIES.inject({ }, function(results, property) {
+ results[property] = css[property];
+ return results;
+ });
+ if (!styles.opacity) styles.opacity = element.getOpacity();
+ return styles;
+ };
+};
+
+Effect.Methods = {
+ morph: function(element, style) {
+ element = $(element);
+ new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { }));
+ return element;
+ },
+ visualEffect: function(element, effect, options) {
+ element = $(element)
+ var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1);
+ new Effect[klass](element, options);
+ return element;
+ },
+ highlight: function(element, options) {
+ element = $(element);
+ new Effect.Highlight(element, options);
+ return element;
+ }
+};
+
+$w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+
+ 'pulsate shake puff squish switchOff dropOut').each(
+ function(effect) {
+ Effect.Methods[effect] = function(element, options){
+ element = $(element);
+ Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options);
+ return element;
+ }
+ }
+);
+
+$w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each(
+ function(f) { Effect.Methods[f] = Element[f]; }
+);
+
+Element.addMethods(Effect.Methods);
Modified: jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/scriptaculous.js
==============================================================================
--- jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/scriptaculous.js (original)
+++ jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/scriptaculous.js Fri Jun 27 10:34:57 2008
@@ -1,4 +1,6 @@
-// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// script.aculo.us scriptaculous.js v1.8.1, Thu Jan 03 22:07:12 -0500 2008
+
+// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
@@ -18,25 +20,36 @@
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// For details, see the script.aculo.us web site: http://script.aculo.us/
var Scriptaculous = {
- Version: '1.5.1',
+ Version: '1.8.1',
require: function(libraryName) {
// inserting via DOM fails in Safari 2.0, so brute force approach
- document.write('<script type="text/javascript" src="'+libraryName+'"></script>');
+ document.write('<script type="text/javascript" src="'+libraryName+'"><\/script>');
},
+ REQUIRED_PROTOTYPE: '1.6.0',
load: function() {
- if((typeof Prototype=='undefined') ||
- parseFloat(Prototype.Version.split(".")[0] + "." +
- Prototype.Version.split(".")[1]) < 1.4)
- throw("script.aculo.us requires the Prototype JavaScript framework >= 1.4.0");
+ function convertVersionString(versionString){
+ var r = versionString.split('.');
+ return parseInt(r[0])*100000 + parseInt(r[1])*1000 + parseInt(r[2]);
+ }
+
+ if((typeof Prototype=='undefined') ||
+ (typeof Element == 'undefined') ||
+ (typeof Element.Methods=='undefined') ||
+ (convertVersionString(Prototype.Version) <
+ convertVersionString(Scriptaculous.REQUIRED_PROTOTYPE)))
+ throw("script.aculo.us requires the Prototype JavaScript framework >= " +
+ Scriptaculous.REQUIRED_PROTOTYPE);
$A(document.getElementsByTagName("script")).findAll( function(s) {
return (s.src && s.src.match(/scriptaculous\.js(\?.*)?$/))
}).each( function(s) {
var path = s.src.replace(/scriptaculous\.js(\?.*)?$/,'');
var includes = s.src.match(/\?.*load=([a-z,]*)/);
- (includes ? includes[1] : 'builder,effects,dragdrop,controls,slider').split(',').each(
+ (includes ? includes[1] : 'builder,effects,dragdrop,controls,slider,sound').split(',').each(
function(include) { Scriptaculous.require(path+include+'.js') });
});
}
Modified: jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/slider.js
==============================================================================
--- jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/slider.js (original)
+++ jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/slider.js Fri Jun 27 10:34:57 2008
@@ -1,28 +1,11 @@
-// Copyright (c) 2005 Marty Haught, Thomas Fuchs
-//
-// See http://script.aculo.us for more info
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
+// script.aculo.us slider.js v1.8.1, Thu Jan 03 22:07:12 -0500 2008
+
+// Copyright (c) 2005-2007 Marty Haught, Thomas Fuchs
//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
-if(!Control) var Control = {};
-Control.Slider = Class.create();
+if (!Control) var Control = { };
// options:
// axis: 'vertical', or 'horizontal' (default)
@@ -30,18 +13,18 @@
// callbacks:
// onChange(value)
// onSlide(value)
-Control.Slider.prototype = {
+Control.Slider = Class.create({
initialize: function(handle, track, options) {
var slider = this;
- if(handle instanceof Array) {
+ if (Object.isArray(handle)) {
this.handles = handle.collect( function(e) { return $(e) });
} else {
this.handles = [$(handle)];
}
this.track = $(track);
- this.options = options || {};
+ this.options = options || { };
this.axis = this.options.axis || 'horizontal';
this.increment = this.options.increment || 1;
@@ -64,17 +47,22 @@
this.alignY = parseInt(this.options.alignY || '0');
this.trackLength = this.maximumOffset() - this.minimumOffset();
- this.handleLength = this.isVertical() ? this.handles[0].offsetHeight : this.handles[0].offsetWidth;
+
+ this.handleLength = this.isVertical() ?
+ (this.handles[0].offsetHeight != 0 ?
+ this.handles[0].offsetHeight : this.handles[0].style.height.replace(/px$/,"")) :
+ (this.handles[0].offsetWidth != 0 ? this.handles[0].offsetWidth :
+ this.handles[0].style.width.replace(/px$/,""));
this.active = false;
this.dragging = false;
this.disabled = false;
- if(this.options.disabled) this.setDisabled();
+ if (this.options.disabled) this.setDisabled();
// Allowed values array
this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false;
- if(this.allowedValues) {
+ if (this.allowedValues) {
this.minimum = this.allowedValues.min();
this.maximum = this.allowedValues.max();
}
@@ -87,16 +75,15 @@
this.handles.each( function(h,i) {
i = slider.handles.length-1-i;
slider.setValue(parseFloat(
- (slider.options.sliderValue instanceof Array ?
+ (Object.isArray(slider.options.sliderValue) ?
slider.options.sliderValue[i] : slider.options.sliderValue) ||
slider.range.start), i);
- Element.makePositioned(h); // fix IE
- Event.observe(h, "mousedown", slider.eventMouseDown);
+ h.makePositioned().observe("mousedown", slider.eventMouseDown);
});
- Event.observe(this.track, "mousedown", this.eventMouseDown);
- Event.observe(document, "mouseup", this.eventMouseUp);
- Event.observe(document, "mousemove", this.eventMouseMove);
+ this.track.observe("mousedown", this.eventMouseDown);
+ document.observe("mouseup", this.eventMouseUp);
+ document.observe("mousemove", this.eventMouseMove);
this.initialized = true;
},
@@ -116,36 +103,36 @@
this.disabled = false;
},
getNearestValue: function(value){
- if(this.allowedValues){
- if(value >= this.allowedValues.max()) return(this.allowedValues.max());
- if(value <= this.allowedValues.min()) return(this.allowedValues.min());
+ if (this.allowedValues){
+ if (value >= this.allowedValues.max()) return(this.allowedValues.max());
+ if (value <= this.allowedValues.min()) return(this.allowedValues.min());
var offset = Math.abs(this.allowedValues[0] - value);
var newValue = this.allowedValues[0];
this.allowedValues.each( function(v) {
var currentOffset = Math.abs(v - value);
- if(currentOffset <= offset){
+ if (currentOffset <= offset){
newValue = v;
offset = currentOffset;
}
});
return newValue;
}
- if(value > this.range.end) return this.range.end;
- if(value < this.range.start) return this.range.start;
+ if (value > this.range.end) return this.range.end;
+ if (value < this.range.start) return this.range.start;
return value;
},
setValue: function(sliderValue, handleIdx){
- if(!this.active) {
- this.activeHandle = this.handles[handleIdx];
- this.activeHandleIdx = handleIdx;
+ if (!this.active) {
+ this.activeHandleIdx = handleIdx || 0;
+ this.activeHandle = this.handles[this.activeHandleIdx];
this.updateStyles();
}
handleIdx = handleIdx || this.activeHandleIdx || 0;
- if(this.initialized && this.restricted) {
- if((handleIdx>0) && (sliderValue<this.values[handleIdx-1]))
+ if (this.initialized && this.restricted) {
+ if ((handleIdx>0) && (sliderValue<this.values[handleIdx-1]))
sliderValue = this.values[handleIdx-1];
- if((handleIdx < (this.handles.length-1)) && (sliderValue>this.values[handleIdx+1]))
+ if ((handleIdx < (this.handles.length-1)) && (sliderValue>this.values[handleIdx+1]))
sliderValue = this.values[handleIdx+1];
}
sliderValue = this.getNearestValue(sliderValue);
@@ -156,7 +143,7 @@
this.translateToPx(sliderValue);
this.drawSpans();
- if(!this.dragging || !this.event) this.updateFinished();
+ if (!this.dragging || !this.event) this.updateFinished();
},
setValueBy: function(delta, handleIdx) {
this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta,
@@ -180,30 +167,33 @@
return(this.isVertical() ? this.alignY : this.alignX);
},
maximumOffset: function(){
- return(this.isVertical() ?
- this.track.offsetHeight - this.alignY : this.track.offsetWidth - this.alignX);
+ return(this.isVertical() ?
+ (this.track.offsetHeight != 0 ? this.track.offsetHeight :
+ this.track.style.height.replace(/px$/,"")) - this.alignY :
+ (this.track.offsetWidth != 0 ? this.track.offsetWidth :
+ this.track.style.width.replace(/px$/,"")) - this.alignX);
},
isVertical: function(){
return (this.axis == 'vertical');
},
drawSpans: function() {
var slider = this;
- if(this.spans)
+ if (this.spans)
$R(0, this.spans.length-1).each(function(r) { slider.setSpan(slider.spans[r], slider.getRange(r)) });
- if(this.options.startSpan)
+ if (this.options.startSpan)
this.setSpan(this.options.startSpan,
$R(0, this.values.length>1 ? this.getRange(0).min() : this.value ));
- if(this.options.endSpan)
+ if (this.options.endSpan)
this.setSpan(this.options.endSpan,
$R(this.values.length>1 ? this.getRange(this.spans.length-1).max() : this.value, this.maximum));
},
setSpan: function(span, range) {
- if(this.isVertical()) {
+ if (this.isVertical()) {
span.style.top = this.translateToPx(range.start);
- span.style.height = this.translateToPx(range.end - range.start);
+ span.style.height = this.translateToPx(range.end - range.start + this.range.start);
} else {
span.style.left = this.translateToPx(range.start);
- span.style.width = this.translateToPx(range.end - range.start);
+ span.style.width = this.translateToPx(range.end - range.start + this.range.start);
}
},
updateStyles: function() {
@@ -211,13 +201,14 @@
Element.addClassName(this.activeHandle, 'selected');
},
startDrag: function(event) {
- if(Event.isLeftClick(event)) {
- if(!this.disabled){
+ if (Event.isLeftClick(event)) {
+ if (!this.disabled){
this.active = true;
var handle = Event.element(event);
var pointer = [Event.pointerX(event), Event.pointerY(event)];
- if(handle==this.track) {
+ var track = handle;
+ if (track==this.track) {
var offsets = Position.cumulativeOffset(this.track);
this.event = event;
this.setValue(this.translateToValue(
@@ -230,25 +221,26 @@
// find the handle (prevents issues with Safari)
while((this.handles.indexOf(handle) == -1) && handle.parentNode)
handle = handle.parentNode;
-
- this.activeHandle = handle;
- this.activeHandleIdx = this.handles.indexOf(this.activeHandle);
- this.updateStyles();
-
- var offsets = Position.cumulativeOffset(this.activeHandle);
- this.offsetX = (pointer[0] - offsets[0]);
- this.offsetY = (pointer[1] - offsets[1]);
+
+ if (this.handles.indexOf(handle)!=-1) {
+ this.activeHandle = handle;
+ this.activeHandleIdx = this.handles.indexOf(this.activeHandle);
+ this.updateStyles();
+
+ var offsets = Position.cumulativeOffset(this.activeHandle);
+ this.offsetX = (pointer[0] - offsets[0]);
+ this.offsetY = (pointer[1] - offsets[1]);
+ }
}
}
Event.stop(event);
}
},
update: function(event) {
- if(this.active) {
- if(!this.dragging) this.dragging = true;
+ if (this.active) {
+ if (!this.dragging) this.dragging = true;
this.draw(event);
- // fix AppleWebKit rendering
- if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
+ if (Prototype.Browser.WebKit) window.scrollBy(0,0);
Event.stop(event);
}
},
@@ -259,11 +251,11 @@
pointer[1] -= this.offsetY + offsets[1];
this.event = event;
this.setValue(this.translateToValue( this.isVertical() ? pointer[1] : pointer[0] ));
- if(this.initialized && this.options.onSlide)
+ if (this.initialized && this.options.onSlide)
this.options.onSlide(this.values.length>1 ? this.values : this.value, this);
},
endDrag: function(event) {
- if(this.active && this.dragging) {
+ if (this.active && this.dragging) {
this.finishDrag(event, true);
Event.stop(event);
}
@@ -276,8 +268,8 @@
this.updateFinished();
},
updateFinished: function() {
- if(this.initialized && this.options.onChange)
+ if (this.initialized && this.options.onChange)
this.options.onChange(this.values.length>1 ? this.values : this.value, this);
this.event = null;
}
-}
\ No newline at end of file
+});
Added: jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/sound.js
==============================================================================
--- (empty file)
+++ jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/sound.js Fri Jun 27 10:34:57 2008
@@ -0,0 +1,55 @@
+// script.aculo.us sound.js v1.8.1, Thu Jan 03 22:07:12 -0500 2008
+
+// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//
+// Based on code created by Jules Gravinese (http://www.webveteran.com/)
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+Sound = {
+ tracks: {},
+ _enabled: true,
+ template:
+ new Template('<embed style="height:0" id="sound_#{track}_#{id}" src="#{url}" loop="false" autostart="true" hidden="true"/>'),
+ enable: function(){
+ Sound._enabled = true;
+ },
+ disable: function(){
+ Sound._enabled = false;
+ },
+ play: function(url){
+ if(!Sound._enabled) return;
+ var options = Object.extend({
+ track: 'global', url: url, replace: false
+ }, arguments[1] || {});
+
+ if(options.replace && this.tracks[options.track]) {
+ $R(0, this.tracks[options.track].id).each(function(id){
+ var sound = $('sound_'+options.track+'_'+id);
+ sound.Stop && sound.Stop();
+ sound.remove();
+ })
+ this.tracks[options.track] = null;
+ }
+
+ if(!this.tracks[options.track])
+ this.tracks[options.track] = { id: 0 }
+ else
+ this.tracks[options.track].id++;
+
+ options.id = this.tracks[options.track].id;
+ $$('body')[0].insert(
+ Prototype.Browser.IE ? new Element('bgsound',{
+ id: 'sound_'+options.track+'_'+options.id,
+ src: options.url, loop: 1, autostart: true
+ }) : Sound.template.evaluate(options));
+ }
+};
+
+if(Prototype.Browser.Gecko && navigator.userAgent.indexOf("Win") > 0){
+ if(navigator.plugins && $A(navigator.plugins).detect(function(p){ return p.name.indexOf('QuickTime') != -1 }))
+ Sound.template = new Template('<object id="sound_#{track}_#{id}" width="0" height="0" type="audio/mpeg" data="#{url}"/>')
+ else
+ Sound.play = function(){}
+}
Modified: jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/unittest.js
==============================================================================
--- jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/unittest.js (original)
+++ jifty/trunk/share/plugins/Jifty/Plugin/Prototypism/web/static/js/prototypism/scriptaculous/unittest.js Fri Jun 27 10:34:57 2008
@@ -1,20 +1,27 @@
-// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
-// (c) 2005 Jon Tirsen (http://www.tirsen.com)
-// (c) 2005 Michael Schuerig (http://www.schuerig.de/michael/)
+// script.aculo.us unittest.js v1.8.1, Thu Jan 03 22:07:12 -0500 2008
+
+// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// (c) 2005-2007 Jon Tirsen (http://www.tirsen.com)
+// (c) 2005-2007 Michael Schuerig (http://www.schuerig.de/michael/)
//
-// See scriptaculous.js for full license.
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
// experimental, Firefox-only
Event.simulateMouse = function(element, eventName) {
var options = Object.extend({
pointerX: 0,
pointerY: 0,
- buttons: 0
+ buttons: 0,
+ ctrlKey: false,
+ altKey: false,
+ shiftKey: false,
+ metaKey: false
}, arguments[2] || {});
var oEvent = document.createEvent("MouseEvents");
oEvent.initMouseEvent(eventName, true, true, document.defaultView,
options.buttons, options.pointerX, options.pointerY, options.pointerX, options.pointerY,
- false, false, false, false, 0, $(element));
+ options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, 0, $(element));
if(this.mark) Element.remove(this.mark);
this.mark = document.createElement('div');
@@ -64,24 +71,7 @@
Test.Unit = {};
// security exception workaround
-Test.Unit.inspect = function(obj) {
- var info = [];
-
- if(typeof obj=="string" ||
- typeof obj=="number") {
- return obj;
- } else {
- for(property in obj)
- if(typeof obj[property]!="function")
- info.push(property + ' => ' +
- (typeof obj[property] == "string" ?
- '"' + obj[property] + '"' :
- obj[property]));
- }
-
- return ("'" + obj + "' #" + typeof obj +
- ": {" + info.join(", ") + "}");
-}
+Test.Unit.inspect = Object.inspect;
Test.Unit.Logger = Class.create();
Test.Unit.Logger.prototype = {
@@ -97,6 +87,7 @@
this.lastLogLine = document.createElement('tr');
this.statusCell = document.createElement('td');
this.nameCell = document.createElement('td');
+ this.nameCell.className = "nameCell";
this.nameCell.appendChild(document.createTextNode(testName));
this.messageCell = document.createElement('td');
this.lastLogLine.appendChild(this.statusCell);
@@ -109,6 +100,7 @@
this.lastLogLine.className = status;
this.statusCell.innerHTML = status;
this.messageCell.innerHTML = this._toHTML(summary);
+ this.addLinksToResults();
},
message: function(message) {
if (!this.log) return;
@@ -130,6 +122,16 @@
},
_toHTML: function(txt) {
return txt.escapeHTML().replace(/\n/g,"<br/>");
+ },
+ addLinksToResults: function(){
+ $$("tr.failed .nameCell").each( function(td){ // todo: limit to children of this.log
+ td.title = "Run only this test"
+ Event.observe(td, 'click', function(){ window.location.search = "?tests=" + td.innerHTML;});
+ });
+ $$("tr.passed .nameCell").each( function(td){ // todo: limit to children of this.log
+ td.title = "Run all tests"
+ Event.observe(td, 'click', function(){ window.location.search = "";});
+ });
}
}
@@ -140,6 +142,7 @@
testLog: 'testlog'
}, arguments[1] || {});
this.options.resultsURL = this.parseResultsURLQueryParameter();
+ this.options.tests = this.parseTestsQueryParameter();
if (this.options.testLog) {
this.options.testLog = $(this.options.testLog) || null;
}
@@ -157,7 +160,11 @@
this.tests = [];
for(var testcase in testcases) {
if(/^test/.test(testcase)) {
- this.tests.push(new Test.Unit.Testcase(testcase, testcases[testcase], testcases["setup"], testcases["teardown"]));
+ this.tests.push(
+ new Test.Unit.Testcase(
+ this.options.context ? ' -> ' + this.options.titles[testcase] : testcase,
+ testcases[testcase], testcases["setup"], testcases["teardown"]
+ ));
}
}
}
@@ -169,6 +176,11 @@
parseResultsURLQueryParameter: function() {
return window.location.search.parseQuery()["resultsURL"];
},
+ parseTestsQueryParameter: function(){
+ if (window.location.search.parseQuery()["tests"]){
+ return window.location.search.parseQuery()["tests"].split(',');
+ };
+ },
// Returns:
// "ERROR" if there was an error,
// "FAILURE" if there was a failure, or
@@ -228,6 +240,7 @@
errors += this.tests[i].errors;
}
return (
+ (this.options.context ? this.options.context + ': ': '') +
this.tests.length + " tests, " +
assertions + " assertions, " +
failures + " failures, " +
@@ -257,6 +270,9 @@
this.failures++;
this.messages.push("Failure: " + message);
},
+ info: function(message) {
+ this.messages.push("Info: " + message);
+ },
error: function(error) {
this.errors++;
this.messages.push(error.name + ": "+ error.message + "(" + Test.Unit.inspect(error) +")");
@@ -279,18 +295,54 @@
'", actual "' + Test.Unit.inspect(actual) + '"'); }
catch(e) { this.error(e); }
},
+ assertInspect: function(expected, actual) {
+ var message = arguments[2] || "assertInspect";
+ try { (expected == actual.inspect()) ? this.pass() :
+ this.fail(message + ': expected "' + Test.Unit.inspect(expected) +
+ '", actual "' + Test.Unit.inspect(actual) + '"'); }
+ catch(e) { this.error(e); }
+ },
+ assertEnumEqual: function(expected, actual) {
+ var message = arguments[2] || "assertEnumEqual";
+ try { $A(expected).length == $A(actual).length &&
+ expected.zip(actual).all(function(pair) { return pair[0] == pair[1] }) ?
+ this.pass() : this.fail(message + ': expected ' + Test.Unit.inspect(expected) +
+ ', actual ' + Test.Unit.inspect(actual)); }
+ catch(e) { this.error(e); }
+ },
assertNotEqual: function(expected, actual) {
var message = arguments[2] || "assertNotEqual";
try { (expected != actual) ? this.pass() :
this.fail(message + ': got "' + Test.Unit.inspect(actual) + '"'); }
catch(e) { this.error(e); }
},
+ assertIdentical: function(expected, actual) {
+ var message = arguments[2] || "assertIdentical";
+ try { (expected === actual) ? this.pass() :
+ this.fail(message + ': expected "' + Test.Unit.inspect(expected) +
+ '", actual "' + Test.Unit.inspect(actual) + '"'); }
+ catch(e) { this.error(e); }
+ },
+ assertNotIdentical: function(expected, actual) {
+ var message = arguments[2] || "assertNotIdentical";
+ try { !(expected === actual) ? this.pass() :
+ this.fail(message + ': expected "' + Test.Unit.inspect(expected) +
+ '", actual "' + Test.Unit.inspect(actual) + '"'); }
+ catch(e) { this.error(e); }
+ },
assertNull: function(obj) {
var message = arguments[1] || 'assertNull'
try { (obj==null) ? this.pass() :
this.fail(message + ': got "' + Test.Unit.inspect(obj) + '"'); }
catch(e) { this.error(e); }
},
+ assertMatch: function(expected, actual) {
+ var message = arguments[2] || 'assertMatch';
+ var regex = new RegExp(expected);
+ try { (regex.exec(actual)) ? this.pass() :
+ this.fail(message + ' : regex: "' + Test.Unit.inspect(expected) + ' did not match: ' + Test.Unit.inspect(actual) + '"'); }
+ catch(e) { this.error(e); }
+ },
assertHidden: function(element) {
var message = arguments[1] || 'assertHidden';
this.assertEqual("none", element.style.display, message);
@@ -299,6 +351,22 @@
var message = arguments[1] || 'assertNotNull';
this.assert(object != null, message);
},
+ assertType: function(expected, actual) {
+ var message = arguments[2] || 'assertType';
+ try {
+ (actual.constructor == expected) ? this.pass() :
+ this.fail(message + ': expected "' + Test.Unit.inspect(expected) +
+ '", actual "' + (actual.constructor) + '"'); }
+ catch(e) { this.error(e); }
+ },
+ assertNotOfType: function(expected, actual) {
+ var message = arguments[2] || 'assertNotOfType';
+ try {
+ (actual.constructor != expected) ? this.pass() :
+ this.fail(message + ': expected "' + Test.Unit.inspect(expected) +
+ '", actual "' + (actual.constructor) + '"'); }
+ catch(e) { this.error(e); }
+ },
assertInstanceOf: function(expected, actual) {
var message = arguments[2] || 'assertInstanceOf';
try {
@@ -313,6 +381,63 @@
this.fail(message + ": object was an instance of the not expected type"); }
catch(e) { this.error(e); }
},
+ assertRespondsTo: function(method, obj) {
+ var message = arguments[2] || 'assertRespondsTo';
+ try {
+ (obj[method] && typeof obj[method] == 'function') ? this.pass() :
+ this.fail(message + ": object doesn't respond to [" + method + "]"); }
+ catch(e) { this.error(e); }
+ },
+ assertReturnsTrue: function(method, obj) {
+ var message = arguments[2] || 'assertReturnsTrue';
+ try {
+ var m = obj[method];
+ if(!m) m = obj['is'+method.charAt(0).toUpperCase()+method.slice(1)];
+ m() ? this.pass() :
+ this.fail(message + ": method returned false"); }
+ catch(e) { this.error(e); }
+ },
+ assertReturnsFalse: function(method, obj) {
+ var message = arguments[2] || 'assertReturnsFalse';
+ try {
+ var m = obj[method];
+ if(!m) m = obj['is'+method.charAt(0).toUpperCase()+method.slice(1)];
+ !m() ? this.pass() :
+ this.fail(message + ": method returned true"); }
+ catch(e) { this.error(e); }
+ },
+ assertRaise: function(exceptionName, method) {
+ var message = arguments[2] || 'assertRaise';
+ try {
+ method();
+ this.fail(message + ": exception expected but none was raised"); }
+ catch(e) {
+ ((exceptionName == null) || (e.name==exceptionName)) ? this.pass() : this.error(e);
+ }
+ },
+ assertElementsMatch: function() {
+ var expressions = $A(arguments), elements = $A(expressions.shift());
+ if (elements.length != expressions.length) {
+ this.fail('assertElementsMatch: size mismatch: ' + elements.length + ' elements, ' + expressions.length + ' expressions');
+ return false;
+ }
+ elements.zip(expressions).all(function(pair, index) {
+ var element = $(pair.first()), expression = pair.last();
+ if (element.match(expression)) return true;
+ this.fail('assertElementsMatch: (in index ' + index + ') expected ' + expression.inspect() + ' but got ' + element.inspect());
+ }.bind(this)) && this.pass();
+ },
+ assertElementMatches: function(element, expression) {
+ this.assertElementsMatch([element], expression);
+ },
+ benchmark: function(operation, iterations) {
+ var startAt = new Date();
+ (iterations || 1).times(operation);
+ var timeTaken = ((new Date())-startAt);
+ this.info((arguments[2] || 'Operation') + ' finished ' +
+ iterations + ' iterations in ' + (timeTaken/1000)+'s' );
+ return timeTaken;
+ },
_isVisible: function(element) {
element = $(element);
if(!element.parentNode) return true;
@@ -327,6 +452,14 @@
},
assertVisible: function(element) {
this.assert(this._isVisible(element), Test.Unit.inspect(element) + " was not visible. " + ("" || arguments[1]));
+ },
+ benchmark: function(operation, iterations) {
+ var startAt = new Date();
+ (iterations || 1).times(operation);
+ var timeTaken = ((new Date())-startAt);
+ this.info((arguments[2] || 'Operation') + ' finished ' +
+ iterations + ' iterations in ' + (timeTaken/1000)+'s' );
+ return timeTaken;
}
}
@@ -335,7 +468,17 @@
initialize: function(name, test, setup, teardown) {
Test.Unit.Assertions.prototype.initialize.bind(this)();
this.name = name;
- this.test = test || function() {};
+
+ if(typeof test == 'string') {
+ test = test.gsub(/(\.should[^\(]+\()/,'#{0}this,');
+ test = test.gsub(/(\.should[^\(]+)\(this,\)/,'#{1}(this)');
+ this.test = function() {
+ eval('with(this){'+test+'}');
+ }
+ } else {
+ this.test = test || function() {};
+ }
+
this.setup = setup || function() {};
this.teardown = teardown || function() {};
this.isWaiting = false;
@@ -360,4 +503,66 @@
}
catch(e) { this.error(e); }
}
-});
\ No newline at end of file
+});
+
+// *EXPERIMENTAL* BDD-style testing to please non-technical folk
+// This draws many ideas from RSpec http://rspec.rubyforge.org/
+
+Test.setupBDDExtensionMethods = function(){
+ var METHODMAP = {
+ shouldEqual: 'assertEqual',
+ shouldNotEqual: 'assertNotEqual',
+ shouldEqualEnum: 'assertEnumEqual',
+ shouldBeA: 'assertType',
+ shouldNotBeA: 'assertNotOfType',
+ shouldBeAn: 'assertType',
+ shouldNotBeAn: 'assertNotOfType',
+ shouldBeNull: 'assertNull',
+ shouldNotBeNull: 'assertNotNull',
+
+ shouldBe: 'assertReturnsTrue',
+ shouldNotBe: 'assertReturnsFalse',
+ shouldRespondTo: 'assertRespondsTo'
+ };
+ var makeAssertion = function(assertion, args, object) {
+ this[assertion].apply(this,(args || []).concat([object]));
+ }
+
+ Test.BDDMethods = {};
+ $H(METHODMAP).each(function(pair) {
+ Test.BDDMethods[pair.key] = function() {
+ var args = $A(arguments);
+ var scope = args.shift();
+ makeAssertion.apply(scope, [pair.value, args, this]); };
+ });
+
+ [Array.prototype, String.prototype, Number.prototype, Boolean.prototype].each(
+ function(p){ Object.extend(p, Test.BDDMethods) }
+ );
+}
+
+Test.context = function(name, spec, log){
+ Test.setupBDDExtensionMethods();
+
+ var compiledSpec = {};
+ var titles = {};
+ for(specName in spec) {
+ switch(specName){
+ case "setup":
+ case "teardown":
+ compiledSpec[specName] = spec[specName];
+ break;
+ default:
+ var testName = 'test'+specName.gsub(/\s+/,'-').camelize();
+ var body = spec[specName].toString().split('\n').slice(1);
+ if(/^\{/.test(body[0])) body = body.slice(1);
+ body.pop();
+ body = body.map(function(statement){
+ return statement.strip()
+ });
+ compiledSpec[testName] = body.join('\n');
+ titles[testName] = specName;
+ }
+ }
+ new Test.Unit.Runner(compiledSpec, { titles: titles, testLog: log || 'testlog', context: name });
+};
\ No newline at end of file
More information about the Jifty-commit
mailing list