javascripts/right-src.js in right-rails-0.4.4 vs javascripts/right-src.js in right-rails-0.5.0
- old
+ new
@@ -1,52 +1,30 @@
/**
* RightJS, http://rightjs.org
* Released under the MIT license
*
- * Custom build with options: no-olds
- *
- * Copyright (C) 2008-2009 Nikolay Nemshilov
+ * Copyright (C) 2008-2010 Nikolay Nemshilov
*/
/**
* The framework description object
*
- * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
-var RightJS = {
- version: "1.5.3",
- modules: ["core", "form", "cookie", "xhr", "fx"]
+RightJS = {
+ version: "1.5.6",
+ modules: ["core", "dom", "form", "cookie", "xhr", "fx"]
};
/**
- * this object will contain info about the current browser
- *
- * Copyright (C) 2008 Nikolay V. Nemshilov aka St. <nemshilov#gma-il>
- */
-var Browser = (function(agent) {
- return {
- IE: !!(window.attachEvent && !window.opera),
- Opera: !!window.opera,
- WebKit: agent.indexOf('AppleWebKit/') > -1,
- Gecko: agent.indexOf('Gecko') > -1 && agent.indexOf('KHTML') < 0,
- MobileSafari: !!agent.match(/Apple.*Mobile.*Safari/),
- Konqueror: agent.indexOf('Konqueror') > -1,
-
- // marker for the browsers which don't give access to the HTMLElement unit
- OLD: agent.indexOf('MSIE 6') > -1 || agent.indexOf('MSIE 7') > -1,
- IE8: agent.indexOf('MSIE 8') > -1
- }
-})(navigator.userAgent);
-
-/**
* There are some util methods
*
* Credits:
* Some of the functionality and names are inspired or copied from
* - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
* - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
*
- * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-il>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
/**
* extends the first object with the keys and values of the second one
*
@@ -57,14 +35,14 @@
* @param Object source object
* @param Boolean flag if the function should not overwrite intersecting values
* @return Objecte extended destination object
*/
function $ext(dest, src, dont_overwrite) {
- var src = src || {};
+ var src = src || {}, key;
- for (var key in src)
- if (dont_overwrite === undefined || dest[key] === undefined)
+ for (key in src)
+ if (dont_overwrite !== true || typeof(dest[key]) === 'undefined')
dest[key] = src[key];
return dest;
};
@@ -83,11 +61,11 @@
return arguments[i]();
} catch(e) {}
}
};
-/**
+/** !#server
* evals the given javascript text in the context of the current window
*
* @param String javascript
* @return void
*/
@@ -140,28 +118,14 @@
*
* @param mixed value
* @return boolean check result
*/
function defined(value) {
- return value !== undefined;
+ return typeof(value) !== 'undefined';
};
-/**
- * checks if the given value is a hash-like object
- *
- * @param mixed value
- * @return boolean check result
- */
-function isHash(value) {
- return typeof(value) === 'object' && value !== null && value.constructor === Object;
-};
-// Opera 10.00 and Konqueror 3 heed some extra care with that
-if (isHash(document.createElement('p'))) {
- eval(isHash.toString().replace(';', '&&!(arguments[0] instanceof HTMLElement);'));
-}
-
/**
* checks if the given value is a function
*
* @param mixed value
* @return boolean check result
@@ -178,19 +142,10 @@
*/
function isString(value) {
return typeof(value) === 'string';
};
-/**
- * checks if the given value is an array
- *
- * @param mixed value to check
- * @return boolean check result
- */
-function isArray(value) {
- return value instanceof Array;
-};
/**
* checks if the given value is a number
*
* @param mixed value to check
@@ -198,70 +153,52 @@
*/
function isNumber(value) {
return typeof(value) === 'number';
};
-/**
+/** !#server
* checks if the given value is an element
*
* @param mixed value to check
* @return boolean check result
*/
function isElement(value) {
return value && value.tagName;
};
-/**
+/** !#server
* checks if the given value is a DOM-node
*
* @param mixed value to check
* @return boolean check result
*/
function isNode(value) {
return value && value.nodeType;
};
-/**
- * converts any iterables into an array
- *
- * @param Object iterable
- * @return Array list
- */
-var $A = (function(slice) {
- return function (it) {
- try {
- return slice.call(it);
- } catch(e) {
- for (var a=[], i=0, length = it.length; i < length; i++)
- a[i] = it[i];
- return a;
- }
- };
-})(Array.prototype.slice);
-
-/**
+/** !#server
* shortcut to instance new elements
*
* @param String tag name
* @param object options
* @return Element instance
*/
function $E(tag_name, options) {
return new Element(tag_name, options);
};
-/**
+/** !#server
* searches an element by id and/or extends it with the framework extentions
*
* @param String element id or Element to extend
* @return Element or null
*/
function $(element) {
return typeof(element) === 'string' ? document.getElementById(element) : element;
};
-/**
+/** !#server
* searches for elements in the document which matches the given css-rule
*
* @param String css-rule
* @return Array matching elements list
*/
@@ -275,44 +212,106 @@
* @param String string
* @return Array of words
*/
function $w(string) {
return string.trim().split(/\s+/);
-}
+};
-/**
- * generates an unique id for an object
- *
- * @param Object object
- * @return Integer uniq id
- */
-var $uid = (function(UID) {
- return function(item) {
+// we need to generate those functions in an anonymous scope
+(function() {
+ var to_s = Object.prototype.toString, slice = Array.prototype.slice, UID = 1;
+
+ /**
+ * checks if the given value is a hash-like object
+ *
+ * @param mixed value
+ * @return boolean check result
+ */
+ isHash = function(value) {
+ return to_s.call(value) === '[object Object]';
+ };
+
+ /** !#server
+ * Internet Explorer needs some additional mumbo-jumbo in here
+ */
+ if (isHash(document.documentElement)) {
+ isHash = function(value) {
+ return to_s.call(value) === '[object Object]' &&
+ value !== null && typeof(value) !== 'undefined' &&
+ typeof(value.hasOwnProperty) !== 'undefined';
+ };
+ }
+
+ /**
+ * checks if the given value is an array
+ *
+ * @param mixed value to check
+ * @return boolean check result
+ */
+ isArray = function(value) {
+ return to_s.call(value) === '[object Array]';
+ };
+
+ /**
+ * converts any iterables into an array
+ *
+ * @param Object iterable
+ * @return Array list
+ */
+ $A = function (it) {
+ try {
+ return slice.call(it);
+ } catch(e) {
+ for (var a=[], i=0, length = it.length; i < length; i++)
+ a[i] = it[i];
+ return a;
+ }
+ };
+
+ /**
+ * generates an unique id for an object
+ *
+ * @param Object object
+ * @return Integer uniq id
+ */
+ $uid = function(item) {
return item.uid || (item.uid = UID++);
};
-})(1);
+
+ /**
+ * Generating methods for native units extending
+ */
+ for (var i=0, natives = [Array, Function, Number, String, Date, RegExp]; i < natives.length; i++) {
+ natives[i].include = function(module, dont_overwrite) {
+ $ext(this.prototype, module, dont_overwrite);
+ return this;
+ };
+ }
+})();
+
+
/**
* The Object class extentions
*
* Credits:
* Some functionality is inspired by
* - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
*
- * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-il>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
$ext(Object, {
/**
* extracts the list of the attribute names of the given object
*
* @param Object object
* @return Array keys list
*/
keys: function(object) {
- var keys = [];
- for (var key in object)
+ var keys = [], key;
+ for (key in object)
keys.push(key);
return keys;
},
/**
@@ -320,12 +319,12 @@
*
* @param Object object
* @return Array values list
*/
values: function(object) {
- var values = [];
- for (var key in object)
+ var values = [], key;
+ for (key in object)
values.push(object[key]);
return values;
},
/**
@@ -348,13 +347,13 @@
* @param String key-name to exclude
* .....
* @return Object filtered copy
*/
without: function() {
- var filter = $A(arguments), object = filter.shift(), copy = {};
+ var filter = $A(arguments), object = filter.shift(), copy = {}, key;
- for (var key in object)
+ for (key in object)
if (!filter.includes(key))
copy[key] = object[key];
return copy;
},
@@ -369,13 +368,14 @@
* @param String key name to exclude
* .....
* @return Object filtered copy
*/
only: function() {
- var filter = $A(arguments), object = filter.shift(), copy = {};
+ var filter = $A(arguments), object = filter.shift(), copy = {},
+ i=0, length = filter.length;
- for (var i=0, length = filter.length; i < length; i++) {
+ for (; i < length; i++) {
if (defined(object[filter[i]]))
copy[filter[i]] = object[filter[i]];
}
return copy;
@@ -393,12 +393,12 @@
* @param Object mixing
* ......
* @return Object merged object
*/
merge: function() {
- var object = {};
- for (var i=0, length = arguments.length; i < length; i++) {
+ var object = {}, i=0, length = arguments.length;
+ for (; i < length; i++) {
if (isHash(arguments[i])) {
$ext(object, arguments[i]);
}
}
return object;
@@ -409,26 +409,26 @@
*
* @param Object object
* @return String query
*/
toQueryString: function(object) {
- var tokens = [];
- for (var key in object) {
+ var tokens = [], key;
+ for (key in object) {
tokens.push(key+'='+encodeURIComponent(object[key]))
}
return tokens.join('&');
}
-});
+}, true);
/**
* here are the starndard Math object extends
*
* Credits:
* The idea of random mehtod is taken from
* - Ruby (http://www.ruby-lang.org) Copyright (C) Yukihiro Matsumoto
*
- * Copyright (C) 2008 Nikolay V. Nemshilov aka St. <nemshilov#gma-il>
+ * Copyright (C) 2008 Nikolay V. Nemshilov
*/
$ext(Math, {
/**
* the standard random method replacement, to make it more useful
*
@@ -460,13 +460,13 @@
* Credits:
* Some of the functionality is inspired by
* - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
* - Ruby (http://www.ruby-lang.org) Copyright (C) Yukihiro Matsumoto
*
- * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-il>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
-$ext(Array.prototype, (function(A_proto) {
+(function(A_proto) {
// JavaScript 1.6 methods recatching up or faking
var for_each = A_proto.forEach || function(callback, scope) {
for (var i=0, length = this.length; i < length; i++)
callback.call(scope, this[i], i, this);
@@ -501,33 +501,33 @@
return false;
}
return true;
};
- var first = function(callback, scope) {
+ function first(callback, scope) {
for (var i=0, length = this.length; i < length; i++) {
if (callback.call(scope, this[i], i, this))
return this[i];
}
- return undefined;
+ return this._$u; // <- undefined, see #191
};
- var last = function(callback, scope) {
+ function last(callback, scope) {
for (var i=this.length-1; i > -1; i--) {
if (callback.call(scope, this[i], i, this))
return this[i];
}
- return undefined;
+ return this._$u; // <- undefined, see #191
};
//
// RightJS callbacks magick preprocessing
//
// prepares a correct callback function
- var guess_callback = function(args, array) {
+ function guess_callback(args, array) {
var callback = args[0], args = A_proto.slice.call(args, 1), scope = array;
if (isString(callback)) {
var attr = callback;
if (array.length && isFunction(array[0][attr])) {
@@ -541,17 +541,22 @@
return [callback, scope];
};
// calls the given method with preprocessing the arguments
- var call_method = function(func, scope, args) {
+ function call_method(func, scope, args) {
try {
return func.apply(scope, guess_callback(args, scope));
} catch(e) { if (!(e instanceof Break)) throw(e); }
};
-return {
+ // checks the value as a boolean
+ function boolean_check(i) {
+ return !!i;
+ };
+
+Array.include({
/**
* IE fix
* returns the index of the value in the array
*
* @param mixed value
@@ -682,23 +687,23 @@
*
* @param Function optional callback for checks
* @param Object optional scope for the callback
* @return boolean check result
*/
- some: function() {
- return call_method(some, this, arguments.length ? arguments : [function(i) { return !!i; }]);
+ some: function(value) {
+ return call_method(some, this, value ? arguments : [boolean_check]);
},
/**
* checks if all the array elements are logically true
*
* @param Function optional callback for checks
* @param Object optional scope for the callback
* @return Boolean check result
*/
- every: function() {
- return call_method(every, this, arguments.length ? arguments : [function(i) { return !!i; }]);
+ every: function(value) {
+ return call_method(every, this, value ? arguments : [boolean_check]);
},
/**
* applies the given lambda to each element in the array
*
@@ -719,14 +724,14 @@
* @param Array to merge
* ....................
* @return Array new merged
*/
merge: function() {
- for (var copy = this.clone(), arg, i=0, length = arguments.length; i < length; i++) {
+ for (var copy = this.clone(), arg, i=0, j, length = arguments.length; i < length; i++) {
arg = arguments[i];
if (isArray(arg)) {
- for (var j=0; j < arg.length; j++) {
+ for (j=0; j < arg.length; j++) {
if (copy.indexOf(arg[j]) == -1)
copy.push(arg[j]);
}
} else if (copy.indexOf(arg) == -1) {
copy.push(arg);
@@ -756,11 +761,11 @@
* returns a copy of the array whithout any null or undefined values
*
* @return Array filtered version
*/
compact: function() {
- return this.without(null, undefined);
+ return this.without(null, this._$u); // <- this._u === undefined, see #191
},
/**
* returns a copy of the array which contains only the unique values
*
@@ -803,14 +808,13 @@
* Shuffles the array items in a random order
*
* @return Array shuffled version
*/
shuffle: function() {
- var shuff = this.clone();
+ var shuff = this.clone(), j, x, i = shuff.length;
- for (var j, x, i = shuff.length; i;
- j = Math.random(i-1), x = shuff[--i], shuff[i] = shuff[j], shuff[j] = x);
+ for (; i; j = Math.random(i-1), x = shuff[--i], shuff[i] = shuff[j], shuff[j] = x);
return shuff;
},
/**
@@ -829,30 +833,34 @@
}
}).sort(function(a, b) {
return a.value > b.value ? 1 : a.value < b.value ? -1 : 0;
}).map('item');
}
-}})(Array.prototype));
+});
-$alias(Array.prototype, {
+$alias(A_proto, {
include: 'includes',
all: 'every',
any: 'some'
});
+})(Array.prototype);
+
+
+
/**
* The String class extentions
*
* Credits:
* Some of the functionality inspired by
* - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
* The trim function taken from work of Steven Levithan
* - http://blog.stevenlevithan.com/archives/faster-trim-javascript
*
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov aka St. <nemshilov#gma-il>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
-$ext(String.prototype, {
+String.include({
/**
* checks if the string is an empty string
*
* @return boolean check result
*/
@@ -923,11 +931,11 @@
* evals all the scripts in the string
*
* @return String self (unchanged version with scripts still in their place)
*/
evalScripts: function() {
- $eval(this.extractScripts());
+ this.stripScripts(true);
return this;
},
/**
* converts underscored or dasherized string to a camelized one
@@ -1025,31 +1033,25 @@
*
* Credits:
* Some of the functionality inspired by
* - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
*
- * Copyright (C) 2008 Nikolay V. Nemshilov aka St. <nemshilov#gma-il>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
-$ext(Function.prototype, (function() {
- // creating a local reference to the method for a faster access
- var _A = Array.prototype.slice;
-
-return {
+Function.include({
/**
* binds the function to be executed in the given scope
*
* @param Object scope
* @param mixed optional curry (left) argument
* ....
* @return Function binded function
*/
bind: function() {
- if (arguments.length < 2 && !arguments[0]) return this;
-
- var slice = _A, args = slice.call(arguments), scope = args.shift(), func = this;
+ var args = $A(arguments), scope = args.shift(), func = this;
return function() {
- return func.apply(scope, (args.length != 0 || arguments.length != 0) ? args.concat(slice.call(arguments)) : args);
+ return func.apply(scope, (args.length || arguments.length) ? args.concat($A(arguments)) : args);
};
},
/**
* binds the function as an event listener to the given scope object
@@ -1058,13 +1060,13 @@
* @param mixed optional curry (left) argument
* .......
* @return Function binded function
*/
bindAsEventListener: function() {
- var slice = _A, args = slice.call(arguments), scope = args.shift(), func = this;
+ var args = $A(arguments), scope = args.shift(), func = this;
return function(event) {
- return func.apply(scope, [event || window.event].concat(args).concat(slice.call(arguments)));
+ return func.apply(scope, [event || window.event].concat(args).concat($A(arguments)));
};
},
/**
* allows you to put some curry in your cookery
@@ -1072,24 +1074,24 @@
* @param mixed value to curry
* ....
* @return Function curried function
*/
curry: function() {
- return this.bind.apply(this, [this].concat(_A.call(arguments)));
+ return this.bind.apply(this, [this].concat($A(arguments)));
},
/**
* The right side curry feature
*
* @param mixed value to curry
* ....
* @return Function curried function
*/
rcurry: function() {
- var curry = _A.call(arguments), func = this;
+ var curry = $A(arguments), func = this;
return function() {
- return func.apply(func, _A.call(arguments).concat(curry));
+ return func.apply(func, $A(arguments).concat(curry));
}
},
/**
* delays the function execution
@@ -1098,12 +1100,12 @@
* @param mixed value to curry
* .....
* @return Integer timeout marker
*/
delay: function() {
- var args = _A.call(arguments), timeout = args.shift();
- var timer = new Number(window.setTimeout(this.bind.apply(this, [this].concat(args)), timeout));
+ var args = $A(arguments), timeout = args.shift(),
+ timer = new Number(window.setTimeout(this.bind.apply(this, [this].concat(args)), timeout));
timer.cancel = function() { window.clearTimeout(this); };
return timer;
},
@@ -1115,12 +1117,12 @@
* @param mixed value to curry
* ...
* @return Ineger interval marker
*/
periodical: function() {
- var args = _A.call(arguments), timeout = args.shift();
- var timer = new Number(window.setInterval(this.bind.apply(this, [this].concat(args)), timeout));
+ var args = $A(arguments), timeout = args.shift(),
+ timer = new Number(window.setInterval(this.bind.apply(this, [this].concat(args)), timeout));
timer.stop = function() { window.clearInterval(this); };
return timer;
},
@@ -1132,29 +1134,29 @@
* @param mixed optional value to curry
* ......
* @return Function chained function
*/
chain: function() {
- var args = _A.call(arguments), func = args.shift(), current = this;
+ var args = $A(arguments), func = args.shift(), current = this;
return function() {
var result = current.apply(current, arguments);
func.apply(func, args);
return result;
};
}
-}})());
+});
/**
* The Number class extentions
*
* Credits:
* Some methods inspired by
* - Ruby (http://www.ruby-lang.org) Copyright (C) Yukihiro Matsumoto
*
- * Copyright (C) 2008 Nikolay V. Nemshilov aka St. <nemshilov#gma-il>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
-$ext(Number.prototype, {
+Number.include({
/**
* executes the given callback the given number of times
*
* @param Function callback
* @param Object optional callback execution scope
@@ -1205,48 +1207,48 @@
*
* Credits:
* Inspired by
* - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
*
- * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-il>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
-$ext(RegExp, {
- /**
- * Escapes the string for safely use as a regular expression
- *
- * @param String raw string
- * @return String escaped string
- */
- escape: function(string) {
- return String(string).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
- }
-});
+
+ /**
+ * Escapes the string for safely use as a regular expression
+ *
+ * @param String raw string
+ * @return String escaped string
+ */
+RegExp.escape = function(string) {
+ return (''+string).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
+};
+
/**
* The basic Class unit
*
* Credits:
* The Class unit is inspired by its implementation in
* - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
* - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
* - Ruby (http://www.ruby-lang.org) Copyright (C) Yukihiro Matsumoto
*
- * Copyright (C) 2008 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
var Class = function() {
var args = $A(arguments), properties = args.pop() || {}, parent = args.pop();
+
+ // basic class object definition
+ function klass() {
+ return this.initialize ? this.initialize.apply(this, arguments) : this;
+ };
// if only the parent class has been specified
if (!args.length && !isHash(properties)) {
parent = properties; properties = {};
}
-
- // basic class object definition
- var klass = function() {
- return this.initialize ? this.initialize.apply(this, arguments) : this;
- };
-
+
// attaching main class-level methods
$ext(klass, Class.Methods).inherit(parent);
// catching the injections
$w('extend include').each(function(name) {
@@ -1273,28 +1275,28 @@
* @return Object hash or null if nothing found
*/
Class.findSet = function(object, property) {
var upcased = property.toUpperCase(), capcased = property.capitalize(),
candidates = [object, object.constructor].concat(object.constructor.ancestors),
- holder = candidates.first(function(o) { return o[upcased] || o[capcased]});
+ holder = candidates.first(function(o) { return o && (o[upcased] || o[capcased]) });
return holder ? holder[upcased] || holder[capcased] : null;
};
/**
* This module contains the methods by which the Class instances
* will be extended. It provides basic and standard way to work
* with the classes.
*
- * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
Class.Methods = (function() {
- var commons = $w('selfExtended self_extended selfIncluded self_included');
- var extend = commons.concat($w('prototype parent extend include'));
- var include = commons.concat(['constructor']);
+ var commons = $w('selfExtended self_extended selfIncluded self_included'),
+ extend = commons.concat($w('prototype parent extend include')),
+ include = commons.concat(['constructor']);
- var clean_module = function(module, what) {
+ function clean_module(module, what) {
return Object.without.apply(Object, [module].concat(what == 'e' ? extend : include));
};
return {
/**
@@ -1392,26 +1394,25 @@
*
* Credits:
* The idea of the module is inspired by
* - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
*
- * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
-var Options = {
+Options = {
/**
* assigns the options by merging them with the default ones
*
* @param Object options
* @return Object current instance
*/
setOptions: function(options) {
- var options = this.options = Object.merge(Class.findSet(this, 'options'), options);
+ var options = this.options = Object.merge(Class.findSet(this, 'options'), options), match, key;
// hooking up the observer options
if (isFunction(this.on)) {
- var match;
- for (var key in options) {
+ for (key in options) {
if (match = key.match(/on([A-Z][A-Za-z]+)/)) {
this.on(match[1].toLowerCase(), options[key]);
delete(options[key]);
}
}
@@ -1442,13 +1443,13 @@
*
* Credits:
* The naming principle is inspired by
* - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
*
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov aka St. <nemshilov#gma-il>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
-var Observer = new Class({
+Observer = new Class({
include: Options,
/**
* general constructor
*
@@ -1494,22 +1495,22 @@
this.$listeners.push(hash);
break;
default:
if (isArray(callback)) {
- callback.each(function(params) {
- this.observe.apply(this, [event].concat(
- isArray(params) ? params : [params]
+ for (var i=0; i < callback.length; i++) {
+ this.on.apply(this, [event].concat(
+ isArray(callback[i]) ? callback[i] : [callback[i]]
).concat(args));
- }, this);
+ }
}
}
} else {
// assuming it's a hash of key-value pairs
for (var name in event) {
- this.observe.apply(this, [name].concat(
+ this.on.apply(this, [name].concat(
isArray(event[name]) ? event[name] : [event[name]]
).concat(args));
}
}
@@ -1527,21 +1528,17 @@
* observes(String event, Function callback)
*
* @retun boolean check result
*/
observes: function(event, callback) {
- if (this.$listeners) {
- if (!isString(event)) { callback = event; event = null; }
- if (isString(callback)) callback = this[callback];
-
- return this.$listeners.some(function(i) {
- return (event && callback) ? i.e == event && i.f == callback :
- event ? i.e == event : i.f == callback;
- });
- }
+ if (!isString(event)) { callback = event; event = null; }
+ if (isString(callback)) callback = this[callback];
- return false;
+ return (this.$listeners || []).some(function(i) {
+ return (event && callback) ? i.e === event && i.f === callback :
+ event ? i.e === event : i.f === callback;
+ });
},
/**
* stops observing an event or/and function
*
@@ -1551,15 +1548,19 @@
* stopObserving(String event, Function callback)
*
* @return Observer self
*/
stopObserving: function(event, callback) {
- if (this.$listeners) {
+ if (isHash(event)) {
+ for (var key in event) {
+ this.stopObserving(key, event[key]);
+ }
+ } else {
if (!isString(event)) { callback = event; event = null; }
if (isString(callback)) callback = this[callback];
- this.$listeners = this.$listeners.filter(function(i) {
+ this.$listeners = (this.$listeners || []).filter(function(i) {
return (event && callback) ? (i.e !== event || i.f !== callback) :
(event ? i.e !== event : i.f !== callback);
}, this);
}
@@ -1637,28 +1638,47 @@
$alias(Observer.prototype, { observe: 'on' });
/**
* iterators in-callbacks break exception
*
- * Copyright (C) 2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-il>
+ * Copyright (C) 2009-2010 Nikolay V. Nemshilov
*/
-var Break = new Class(Error, {
+Break = new Class(Error, {
message: "Manual iterator break"
});
/**
+ * this object will contain info about the current browser
+ *
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
+ */
+Browser = (function(agent) {
+ return {
+ IE: !!(window.attachEvent && !window.opera),
+ Opera: !!window.opera,
+ WebKit: agent.indexOf('AppleWebKit/') > -1,
+ Gecko: agent.indexOf('Gecko') > -1 && agent.indexOf('KHTML') < 0,
+ MobileSafari: !!agent.match(/Apple.*Mobile.*Safari/),
+ Konqueror: agent.indexOf('Konqueror') > -1,
+
+ // marker for the browsers which don't give access to the HTMLElement unit
+ OLD: !!(window.attachEvent && !window.opera) && !document.querySelector
+ }
+})(navigator.userAgent);
+
+/**
* represents some additional functionality for the Event class
*
* NOTE: there more additional functionality for the Event class in the rightjs-goods project
*
* Credits:
* The additional method names are inspired by
* - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
*
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
-var Event = new Class(Event, {
+Event = new Class(window.Event, {
extend: {
/**
* extends a native object with additional functionality
*
* @param Event event
@@ -1666,29 +1686,29 @@
* @return Event same event but extended
*/
ext: function(event, bound_element) {
if (!event.stop) {
$ext(event, this.Methods, true);
+ }
+
+ if (!event.target && event.srcElement) {
+ // faking the which button
+ event.which = event.button == 2 ? 3 : event.button == 4 ? 2 : 1;
- if (Browser.IE) {
- // faking the which button
- event.which = event.button == 2 ? 3 : event.button == 4 ? 2 : 1;
-
- // faking the mouse position
- var scrolls = window.scrolls();
+ // faking the mouse position
+ var scrolls = window.scrolls();
- event.pageX = event.clientX + scrolls.x;
- event.pageY = event.clientY + scrolls.y;
-
- // faking the target property
- event.target = event.srcElement || bound_element;
-
- // faking the relatedTarget, currentTarget and other targets
- event.relatedTarget = event[(event.target == event.fromElement ? 'to' : 'from') + 'Element'];
- event.currentTarget = bound_element;
- event.eventPhase = 3; // bubbling phase
- }
+ event.pageX = event.clientX + scrolls.x;
+ event.pageY = event.clientY + scrolls.y;
+
+ // faking the target property
+ event.target = $(event.srcElement) || bound_element;
+
+ // faking the relatedTarget, currentTarget and other targets
+ event.relatedTarget = event.target === event.fromElement ? $(event.toElement) : event.target;
+ event.currentTarget = bound_element;
+ event.eventPhase = 3; // bubbling phase
}
// Safari bug fix
if (event.target && event.target.nodeType == 3)
event.target = event.target.parentNode;
@@ -1742,11 +1762,11 @@
* Registers some additional event extendsions
*
* @param Object methods
* @return void
*/
-Event.addMethods = Event.include = function(methods) {
+Event.include = function(methods) {
$ext(this.Methods, methods);
try { // extending the events prototype
$ext(Event.parent.prototype, methods, true);
} catch(e) {};
@@ -1777,116 +1797,259 @@
/**
* custom events unit, used as a mediator for the artificial events handling in the generic observer
*
- * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
Event.Custom = function(name, options) {
this.type = name;
this.stop = function() {};
$ext(this, options || {});
};
/**
+ * This module contains the basic events-delegation feature support
+ *
+ * Copyright (C) 2010 Nikolay V. Nemshilov
+ */
+Event.extend({
+ /**
+ * Creates an event delegation handler
+ *
+ * USAGE:
+ *
+ * var delegation = Event.delegate({
+ * "css_rule_1": function() { do_something_usual(); },
+ * "css_rule_2": function() { do_something_another(); },
+ *
+ * // us also can use references by name with or without options
+ * "css_rule_3": ['addClass', 'that-class'],
+ * "css_rule_4": 'hide'
+ * });
+ *
+ * $(element).on('click', delegation);
+ *
+ * NOTE:
+ * your delegation handler will be called in contexts of matching _targets_
+ * not in the context of the element where it was attached
+ *
+ * @param Object delegation rules
+ * @return Function delegation handler
+ */
+ delegate: function(options) {
+ return function(event) {
+ var target = event.target, css_rule, args, callback;
+
+ for (css_rule in options) {
+ if ($(this).select(css_rule).include(target)) {
+ args = options[css_rule];
+ args = isArray(args) ? args : [args];
+ callback = args[0];
+ args = args.slice(1);
+
+ if (isString(callback))
+ target[callback].apply(target, args);
+ else
+ callback.apply(target, [event].concat(args));
+ }
+ }
+ };
+ },
+
+ /**
+ * Creates a document-level events delegations catcher
+ *
+ * USAGE:
+ * Event.behave("ul#main-menu li", "click", function() { alert('clicked'); });
+ * Event.behave("ul#main-menu li", "mouseover", "addClass", "hovered");
+ * Event.behave("ul#main-menu li", {
+ * click: function() { alert('clicked'); },
+ * mouseover: ['addClass', 'hovered'],
+ * mouseout: ['removeClass', 'hovered'],
+ * dblclick: 'hide'
+ * });
+ *
+ * @param String css-rule
+ * @param mixed String event name or a Hash of events
+ * @param mixed Function callback or String method name
+ * @param mixed optional curried arguments
+ * @return Object with event handlers description the document.on() function will receive
+ */
+ behave: function(css_rule, options) {
+ var events = {}, hash = {}, args = $A(arguments).slice(1),
+ focus = 'focus', blur = 'blur', focus_blur = [focus, blur];
+
+ if (isString(options)) {
+ hash[args.shift()] = args;
+ options = hash;
+ }
+
+ for (var event in options) {
+ var hash = {}; hash[css_rule] = options[event];
+
+ if (Browser.IE) {
+ // fancy IE browsers have different names for bubbling versions of those events
+ if (event == focus) event = focus + 'in';
+ if (event == blur) event = focus + 'out';
+ }
+
+ events[event] = Event.delegate(hash);
+
+ if (focus_blur.include(event) && !Browser.IE) {
+ // HACK! HACK! HACK!
+ // by default, method #on uses a non-captive events attachment
+ // but for focus and blur effects we need the opposite
+ // so we calling the method directly and pushing the listeners manually
+
+ document.addEventListener(event, events[event], true);
+
+ (document.$listeners = document.$listeners || []).push({
+ e: event, f: events[event], a: []
+ });
+
+ } else {
+ document.on(event, events[event]);
+ }
+ }
+
+ return events;
+ }
+});
+
+
+String.include({
+ /**
+ * A shortcut for document-level events delegation handler attaching
+ *
+ * USAGE:
+ *
+ * "ul#main-menu li".on("click", function() { alert('clicked'); });
+ * "ul#main-menu li".on("mouseover", "addClass", "hovered");
+ * "ul#main-menu li".on("mouseout", "removeClass", "hovered");
+ *
+ * // or like that in a shash
+ * "ul#main-menu li".on({
+ * click: function() { alert('clicked'); },
+ * mouseover: ['addClass', 'hovered'],
+ * mouseout: ['removeClass', 'hovered'],
+ * dblclick: 'hide'
+ * });
+ *
+ * ...
+ * @return String this
+ */
+ on: function() {
+ Event.behave.apply(Event, [''+this].concat($A(arguments)));
+ return this;
+ }
+});
+
+$alias(String.prototype, {behave: 'on'});
+
+
+/**
* The DOM Element unit handling
*
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
-self.Element = (function(old_Element) {
+Element = (function(old_Element) {
- var new_Element = function(tag, options) {
- var element = document.createElement(tag), options = options || {};
+ // Element constructor options mapper
+ var options_map = {
+ id: ['id', 0],
+ html: ['innerHTML', 0],
+ 'class': ['className', 0],
+ style: ['setStyle', 1],
+ observe: ['on', 1],
+ on: ['on', 1]
+ };
+
+ function new_Element(tag, options) {
+ var element = document.createElement(tag);
- if (options.id) { element.id = options.id; delete(options.id); }
- if (options.html) { element.innerHTML = options.html; delete(options.html); }
- if (options['class']) { element.className = options['class']; delete(options['class']); }
- if (options.style) { element.setStyle(options.style); delete(options.style); }
- if (options.observe) { element.observe(options.observe); delete(options.observe); }
+ if (options) {
+ for (var key in options) {
+ if (options_map[key]) {
+ if (options_map[key][1]) element[options_map[key][0]](options[key]);
+ else element[options_map[key][0]] = options[key];
+ } else {
+ element.set(key, options[key]);
+ }
+ }
+ }
- for (var key in options) // a filter in case there is no keys in the options left
- return element.set(options);
return element;
};
if (Browser.IE) {
//
// IE browsers have a bug with checked input elements
// and we kinda hacking the Element constructor so that
// it affected IE browsers only
//
- new_Element = eval('({f:'+new_Element.toString().replace(/(\((\w+), (\w+)\) \{)/,
- '$1if($2=="input"&&$3&&$3.checked)$2="<input checked=true/>";'
- )+'})').f;
+ new_Element = eval('['+new_Element.toString().replace(/(\((\w+),\s*(\w+)\)\s*\{)/,
+ '$1if($2==="input"&&$3)$2="<input name="+$3.name+" type="+$3.type+($3.checked?" checked":"")+"/>";'
+ )+']')[0];
}
// connecting the old Element instance to the new one for IE browsers
if (old_Element) {
$ext(new_Element, old_Element);
new_Element.parent = old_Element;
}
return new_Element;
-})(self.Element);
+})(window.Element);
$ext(Element, {
/**
* registeres the methods on the custom element methods list
- * will add them to prototype and will generate a non extensive static mirror
+ * will add them to prototype and register at the Element.Methods hash
*
* USAGE:
* Element.include({
* foo: function(bar) {}
* });
*
* $(element).foo(bar);
- * Element.foo(element, bar);
*
* @param Object new methods list
* @param Boolean flag if the method should keep the existing methods alive
* @return Element the global Element object
*/
include: function(methods, dont_overwrite) {
$ext(this.Methods, methods, dont_overwrite);
try { // busting up the basic element prototypes
- $ext(HTMLElement.prototype, methods, dont_overwrite);
- } catch(e) {
- try { // IE8 native element extension
- $ext(this.parent.prototype, methods, dont_overwrite);
- } catch(e) {}
- }
+ $ext((window.HTMLElement || this.parent).prototype, methods, dont_overwrite);
+ } catch(e) {}
return this;
},
Methods: {} // DO NOT Extend this object manually unless you really need it, use Element#include
});
-// the old interface alias, NOTE will be nuked
-Element.addMethods = Element.include;
-
/**
* The DOM Element unit structures handling module
*
* NOTE: all the methods will process and return only the Element nodes
* all the textual nodes will be skipped
*
* NOTE: if a css-rule was specified then the result of the method
* will be filtered/adjusted depends on the rule
*
- * the css-rule might be a string or a Selector instance
- *
* Credits:
* The naming principle and most of the names are taken from
* - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
* The insertions system implementation is inspired by
* - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
*
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
Element.include({
parent: function(css_rule) {
return css_rule ? this.parents(css_rule)[0] : $(this.parentNode);
},
@@ -1894,13 +2057,13 @@
parents: function(css_rule) {
return this.rCollect('parentNode', css_rule);
},
subNodes: function(css_rule) {
- var first_child = $(this.firstChild);
- return first_child ? (first_child.tagName && (!css_rule || first_child.match(css_rule)) ? [first_child] : []
- ).concat(this.rCollect.call(first_child, 'nextSibling', css_rule)) : [];
+ return this.select(css_rule).filter(function(element) {
+ return element.parentNode === this;
+ }, this);
},
siblings: function(css_rule) {
return this.prevSiblings(css_rule).reverse().concat(this.nextSiblings(css_rule));
},
@@ -1998,11 +2161,11 @@
*
* @param mixed content (a String, an Element or a list of elements)
* @return Element self
*/
update: function(content) {
- if (isString(content) || isNumber(content)) {
+ if ((isString(content) || isNumber(content)) && !Element.insertions.wraps[this.tagName]) {
var scripts;
this.innerHTML = (''+content).stripScripts(function(s) { scripts = s; });
if (scripts) $eval(scripts);
} else {
this.clean().insert(content);
@@ -2153,11 +2316,11 @@
* Some of the functionality is inspired by
* - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
* - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
* - Dojo (www.dojotoolkit.org) Copyright (C) The Dojo Foundation
*
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
Element.include({
/**
* assigns styles out of the hash to the element
*
@@ -2166,31 +2329,32 @@
* @param Object styles list or String style name
* @param String style value in case of the first param a string style name
* @return Element self
*/
setStyle: function(hash, value) {
- if (value) { var style = {}; style[hash] = value; hash = style; }
+ var key, c_key, style = {};
+
+ if (value) { style[hash] = value; hash = style; }
else if(isString(hash)) {
- var style = {};
hash.split(';').each(function(option) {
var els = option.split(':').map('trim');
if (els[0] && els[1]) {
style[els[0]] = els[1];
}
});
hash = style;
}
- var c_key;
- for (var key in hash) {
+
+ for (key in hash) {
c_key = key.indexOf('-') != -1 ? key.camelize() : key;
if (key === 'opacity') {
if (Browser.IE) {
- this.style.filter = 'alpha(opacity='+ value * 100 +')';
+ this.style.filter = 'alpha(opacity='+ hash[key] * 100 +')';
} else {
- this.style.opacity = value;
+ this.style.opacity = hash[key];
}
} else if (key === 'float') {
c_key = Browser.IE ? 'styleFloat' : 'cssFloat';
}
@@ -2321,11 +2485,11 @@
*
* Credits:
* Most of the naming system in the module inspired by
* - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
*
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov aka St. <nemshilov#gma-il>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
Element.include({
/**
* sets the element attributes
*
@@ -2336,11 +2500,11 @@
set: function(hash, value) {
if (typeof(hash) === 'string') { var val = {}; val[hash] = value; hash = val; }
for (var key in hash) {
// some attributes are not available as properties
- if (this[key] === undefined) {
+ if (typeof(this[key]) === 'undefined') {
this.setAttribute(key, ''+hash[key]);
}
this[key] = hash[key];
}
@@ -2454,11 +2618,11 @@
/**
* this module contains the Element's part of functionality
* responsible for the dimensions and positions getting/setting
*
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov aka St. <nemshilov#gma-il>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
Element.include({
/**
* Returns the element sizes as a hash
*
@@ -2602,22 +2766,23 @@
},
/**
* makes the window be scrolled to the element
*
+ * @param Object fx options
* @return Element self
*/
- scrollThere: function() {
- window.scrollTo(this);
+ scrollThere: function(options) {
+ window.scrollTo(this, options);
return this;
}
});
/**
* DOM Element events handling methods
*
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov aka St. <nemshilov#gma-il>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
Element.include((function() {
var observer = Observer.create({},
$w('click rightclick contextmenu mousedown mouseup mouseover mouseout mousemove keypress keydown keyup')
);
@@ -2626,42 +2791,39 @@
// HACK HACK HACK
//
// I'm kinda patching the observer methods manually in here
// the reason is in building flat and fast functions
//
- observer.observe = observer.on = eval('({f:'+
- observer.observe.toString().replace(/(\$listeners\.push\((\w+?)\);)/, '$1'+
- '$2.e=Event.cleanName($2.e);$2.n=Event.realName($2.e);'+
-
- '$2.w=function(){var a=$A(arguments),e=($2.r&&$2.r!=="stopEvent")?a.shift():Event.ext(a[0],this);'+
- 'return $2.f.apply(this,a.concat($2.a))};'+(
-
- self.attachEvent ?
- '$2.w=$2.w.bind(this);this.attachEvent("on"+$2.n,$2.w);' :
- 'this.addEventListener($2.n,$2.w,false);'
- )
- )+
- '})').f;
+ function hack(name, re, text) {
+ observer[name] = eval('['+ observer[name].toString().replace(re, text) +']')[0];
+ };
- observer.stopObserving = eval('({f:'+
- observer.stopObserving.toString().replace(/(function\s*\((\w+)\)\s*\{\s*)(return\s*)([^}]+)/m,
- '$1var r=$4;'+
- 'if(!r)' + (self.attachEvent ?
- 'this.detachEvent("on"+$2.n,$2.w);' :
- 'this.removeEventListener($2.n,$2.w,false);'
- )+'$3 r')+
- '})').f;
+ hack('on',
+ /(\$listeners\.push\((\w+?)\);)/,
+
+ '$1$2.e=Event.cleanName($2.e);$2.n=Event.realName($2.e);$2.w=function(){var a=$A(arguments),e=($2.r&&$2.r!=="stopEvent")?a.shift():Event.ext(a[0],this);return $2.f.apply(this,a.concat($2.a))};' + (
+ window.attachEvent ?
+ '$2.w=$2.w.bind(this);this.attachEvent("on"+$2.n,$2.w);' :
+ 'this.addEventListener($2.n,$2.w,false);'
+ )
+ );
+ observer.observe = observer.on;
+ hack('stopObserving',
+ /(function\s*\((\w+)\)\s*\{\s*)(return\s*)([^}]+)/m,
+ '$1var r=$4;if(!r)' + (window.attachEvent ?
+ 'this.detachEvent("on"+$2.n,$2.w);' :
+ 'this.removeEventListener($2.n,$2.w,false);'
+ )+'$3 r'
+ );
- observer.fire = eval('({f:'+
- observer.fire.toString().replace(/(\w+)\.f\.apply.*?\.concat\((\w+)\)[^}]/,
- '$1.f.apply(this,[new Event($1.e,$2.shift())].concat($1.a).concat($2))'
- )+
- '})').f;
+ hack('fire',
+ /(\w+)\.f\.apply.*?\.concat\((\w+)\)\)/,
+ '$1.f.apply(this,(($1.r&&$1.r!=="stopEvent")?[]:[new Event($1.e,$2.shift())]).concat($1.a).concat($2))'
+ );
- // a simple events terminator method to be hooked like
- // this.onClick('stopEvent');
+ // a simple events terminator method to be hooked like this.onClick('stopEvent');
observer.stopEvent = function(e) { e.stop(); };
$ext(window, observer);
$ext(document, observer);
@@ -2675,19 +2837,19 @@
* The DOM elements selection handling
*
* NOTE: this module is just a wrap over the native CSS-selectors feature
* see the olds/css.js file for the manual selector code
*
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
Element.include((function() {
/**
* Native css-selectors include the current element into the search context
* and as we actually search only inside of the element we add it's tag
* as a scope for the search
*/
- var stub_rule = function(css_rule, tag) {
+ function stub_rule(css_rule, tag) {
return css_rule ? css_rule.replace(/(^|,)/g, '$1'+ tag + ' ') : '*';
};
return {
/**
@@ -2712,45 +2874,46 @@
},
/**
* checks if the element matches this css-rule
*
+ * NOTE: the element should be attached to the page
+ *
* @param String css-rule
* @return Boolean check result
*/
match: function(css_rule) {
- if (!css_rule || css_rule == '*') return true;
+ var result, parent = this.tagName === 'HTML' ? this.ownerDocument : this.parents().last();
- var fake, result, parent, parents = this.parents();
+ // if it's a single node putting it into the context
+ result = $(parent || $E('p').insert(this)).select(css_rule).include(this);
- parent = parents.length ? parents.last() : fake = $E('div').insert(this);
- result = parent.select(css_rule).include(this);
+ if (!parent) this.remove();
- if (fake) { this.remove(); }
-
return result;
}
}})());
// document-level hooks
$ext(document, {
first: function(css_rule) {
- return this.querySelector(css_rule || '*');
+ return this.querySelector(css_rule);
},
select: function(css_rule) {
- return $A(this.querySelectorAll(css_rule || '*'));
+ return $A(this.querySelectorAll(css_rule));
}
});
+
/**
* the window object extensions
*
- * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-il>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
-$ext(self, (function() {
- var old_scroll = window.scrollTo;
+$ext(window, (function() {
+ var native_scroll = window.scrollTo;
return {
/**
* returns the inner-sizes of the window
*
@@ -2780,23 +2943,31 @@
/**
* overloading the native scrollTo method to support hashes and element references
*
* @param mixed number left position, a hash position, element or a string element id
* @param number top position
+ * @param Object fx options
* @return window self
*/
- scrollTo: function(left, top) {
+ scrollTo: function(left, top, fx_options) {
+ var left_pos = left, top_pos = top; // moving the values into new vars so they didn't get screwed later on
+
if(isElement(left) || (isString(left) && $(left))) {
left = $(left).position();
}
if (isHash(left)) {
- top = left.y;
- left = left.x;
+ top_pos = left.y;
+ left_pos = left.x;
}
- old_scroll(left, top);
+ // checking if a smooth scroll was requested
+ if (isHash(fx_options = fx_options || top) && window.Fx) {
+ new Fx.Scroll(this, fx_options).start({x: left_pos, y: top_pos});
+ } else {
+ native_scroll(left_pos, top_pos);
+ }
return this;
}
};
@@ -2807,18 +2978,18 @@
*
* Credits:
* The basic principles of the module are originated from
* - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
*
- * Copyright (C) 2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
+ * Copyright (C) 2009-2010 Nikolay V. Nemshilov
*/
[window, document].each(function(object) {
Observer.createShortcuts(object, ['ready']);
var ready = object.fire.bind(object, 'ready');
// IE and Konqueror browsers
- if (document.readyState !== undefined) {
+ if (typeof(document.readyState) !== 'undefined') {
(function() {
['loaded','complete'].includes(document.readyState) ? ready() : arguments.callee.delay(50);
})();
} else {
document.addEventListener('DOMContentLoaded', ready, false);
@@ -2831,13 +3002,13 @@
*
* Credits:
* The basic principles of the module are inspired by
* - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
*
- * Copyright (C) 2009-2010 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
+ * Copyright (C) 2009-2010 Nikolay V. Nemshilov
*/
-var Form = function(options) {
+function Form(options) {
var options = options || {}, remote = options.remote,
form = new Element('form', Object.without(options, 'remote'));
if (remote) form.remotize();
@@ -2870,19 +3041,18 @@
$ext(HTMLFormElement.prototype, methods, dont_overwrite);
} catch(e) {}
}
});
-Form.addMethods = Form.include;
Form.include({
/**
* returns the form elements as an array of extended units
*
* @return Array of elements
*/
getElements: function() {
- return this.select('input,select,textarea,button');
+ return $A(this.elements).map($);
},
/**
* returns the list of all the input elements on the form
*
@@ -2971,11 +3141,11 @@
*
* Credits:
* The basic ideas are taken from
* - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
*
- * Copyright (C) 2009-2010 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
+ * Copyright (C) 2009-2010 Nikolay V. Nemshilov
*/
(function() {
// trying to get the input element classes list
try { var input_classes = [HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement, HTMLButtonElement];
} catch(e) { var input_classes = []; }
@@ -3022,11 +3192,11 @@
_focus: 'focus',
_select: 'select'
});
});
})();
-Form.Element.addMethods = Form.Element.include;
+
Form.Element.include({
/**
* uniform access to the element values
*
* @return String element value
@@ -3047,11 +3217,11 @@
* @param String value
* @return Element this
*/
setValue: function(value) {
if (this.type == 'select-multiple') {
- value = (isArray(value) ? value : [value]).map(String);
+ value = $A(isArray(value) ? value : [value]).map(String);
$A(this.getElementsByTagName('option')).each(function(option) {
option.selected = value.includes(option.value);
});
} else {
this.value = value;
@@ -3126,13 +3296,13 @@
*
* Credits:
* Most things in the unit are take from
* - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
*
- * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-il>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
-var Cookie = new Class({
+Cookie = new Class({
include: Options,
extend: {
// sets the cookie
set: function(name, value, options) {
@@ -3219,13 +3389,13 @@
* Some of the functionality inspired by
* - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
* - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
* - jQuery (http://jquery.com) Copyright (C) John Resig
*
- * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-il>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
-var Xhr = new Class(Observer, {
+Xhr = new Class(Observer, {
extend: {
// supported events list
EVENTS: $w('success failure complete request cancel create'),
// default options
@@ -3316,11 +3486,11 @@
*
* @param Object options
* @return Xhr self
*/
send: function(params) {
- var add_params = {}, url = this.url, method = this.method.toLowerCase();
+ var add_params = {}, url = this.url, method = this.method.toLowerCase(), key;
if (method == 'put' || method == 'delete') {
add_params['_method'] = method;
method = 'post';
}
@@ -3330,22 +3500,22 @@
if (this.urlEncoded && method == 'post' && !this.headers['Content-type']) {
this.setHeader('Content-type', 'application/x-www-form-urlencoded;charset='+this.encoding);
}
if (method == 'get') {
- url += (url.includes('?') ? '&' : '?') + data;
+ if (data) url += (url.includes('?') ? '&' : '?') + data;
data = null;
}
this.xhr = this.createXhr();
this.fire('create');
this.xhr.open(method, url, this.async);
this.xhr.onreadystatechange = this.stateChanged.bind(this);
- for (var key in this.headers) {
+ for (key in this.headers) {
this.xhr.setRequestHeader(key, this.headers[key]);
}
this.xhr.send(data);
this.fire('request');
@@ -3446,11 +3616,11 @@
sanitizedJSON: function() {
try {
return JSON.parse(this.text);
} catch(e) {
// manual json consistancy check
- if (self.JSON || !(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(this.text.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''))) {
+ if (window.JSON || !(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(this.text.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''))) {
if (this.secureJSON) {
throw "JSON parse error: "+this.text;
} else {
return null;
}
@@ -3522,11 +3692,11 @@
* Credits:
* Some of the functionality inspired by
* - Prototype (http://prototypejs.org) Copyright (C) Sam Stephenson
* - jQuery (http://jquery.com) Copyright (C) John Resig
*
- * Copyright (C) 2009-2010 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
+ * Copyright (C) 2009-2010 Nikolay V. Nemshilov
*/
Form.include({
/**
* sends the form via xhr request
*
@@ -3578,11 +3748,11 @@
* this module contains the Element unit XHR related extensions
*
* Credits:
* - jQuery (http://jquery.com) Copyright (C) John Resig
*
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov aka St. <nemshilov#gma-il>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
Element.include({
/**
* performs an Xhr request to the given url
* and updates the element internals with the responseText
@@ -3599,11 +3769,11 @@
/**
* This unit presents a fake drop in replacement for the XmlHTTPRequest unit
* but works with an iframe targeting in the background
*
- * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-il>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
Xhr.IFramed = new Class({
/**
* constructor
*
@@ -3636,12 +3806,13 @@
onLoad: function() {
this.status = 200;
this.readyState = 4;
- var doc = window[this.iframe.id].document.documentElement;
- this.responseText = doc ? doc.innerHTML : null;
+ try {
+ this.responseText = window[this.iframe.id].document.documentElement.innerHTML;
+ } catch(e) { }
this.onreadystatechange();
},
// dummy API methods
@@ -3656,13 +3827,13 @@
*
* Credits:
* The basic principles, structures and naming system are inspired by
* - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
*
- * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
-var Fx = new Class(Observer, {
+Fx = new Class(Observer, {
extend: {
EVENTS: $w('start finish cancel'),
// named durations
Durations: {
@@ -3698,21 +3869,29 @@
},
Lin: function(i) {
return i;
}
- }
+ },
+
+ ch: [], // scheduled effects registries
+ cr: [] // currently running effects registries
},
/**
* Basic constructor
*
* @param Object options
*/
initialize: function(element, options) {
this.$super(options);
- this.element = $(element);
+
+ if (this.element = element = $(element)) {
+ var uid = $uid(element);
+ this.ch = (Fx.ch[uid] = Fx.ch[uid] || []);
+ this.cr = (Fx.cr[uid] = Fx.cr[uid] || []);
+ }
},
/**
* starts the transition
*
@@ -3727,29 +3906,36 @@
this.transition = Fx.Transitions[options.transition] || options.transition;
this.steps = (duration / 1000 * this.options.fps).ceil();
this.number = 1;
+ if (this.cr) this.cr.push(this); // adding this effect to the list of currently active
+
return this.fire('start', this).startTimer();
},
/**
* finishes the transition
*
* @return Fx this
*/
finish: function() {
- return this.stopTimer().fire('finish').next();
+ return this.stopTimer().unreg().fire('finish').next();
},
/**
* interrupts the transition
*
+ * NOTE:
+ * this method cancels all the scheduled effects
+ * in the element chain
+ *
* @return Fx this
*/
cancel: function() {
- return this.stopTimer().fire('cancel').next();
+ this.ch.clean();
+ return this.stopTimer().unreg().fire('cancel');
},
/**
* pauses the transition
*
@@ -3786,59 +3972,62 @@
that.w = false;
}
that.number ++;
}
},
-
+
+ // starts the effect timer
startTimer: function() {
this.timer = this.step.periodical((1000 / this.options.fps).round(), this);
return this;
},
+ // stops the effect timer
stopTimer: function() {
if (this.timer) {
this.timer.stop();
}
return this;
},
// handles effects queing
// should return false if there's no queue and true if there is a queue
queue: function(args) {
- if (!this.element) return false;
- if (this.$ch) return this.$ch = false;
+ var chain = this.ch, queue = this.options.queue;
+
+ if (!chain || this.$ch)
+ return this.$ch = false;
- var uid = $uid(this.element), chain;
- Fx.$ch = Fx.$ch || [];
- chain = (Fx.$ch[uid] = Fx.$ch[uid] || []);
-
- if (this.options.queue)
+ if (queue)
chain.push([args, this]);
- this.next = function() {
- var next = chain.shift(); next = chain[0];
- if (next) {
- next[1].$ch = true;
- next[1].start.apply(next[1], next[0]);
- }
- return this;
- };
-
- return this.options.queue && chain[0][1] !== this;
+ return queue && chain[0][1] !== this;
},
+ // calls for the next effect in the queue
next: function() {
+ var chain = this.ch, next = chain.shift(), next = chain[0];
+ if (next) {
+ next[1].$ch = true;
+ next[1].start.apply(next[1], next[0]);
+ }
return this;
+ },
+
+ // unregisters this effect out of the currently running list
+ unreg: function() {
+ var currents = this.cr;
+ if (currents) currents.splice(currents.indexOf(this), 1);
+ return this;
}
-
});
/**
* There are the String unit extensions for the effects library
*
- * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-il>
+ * Copyright (C) 2008-2009 Nikolay V. Nemshilov
*/
String.COLORS = {
maroon: '#800000',
red: '#ff0000',
orange: '#ffA500',
@@ -3857,11 +4046,11 @@
silver: '#c0c0c0',
gray: '#808080',
brown: '#a52a2a'
};
-$ext(String.prototype, {
+String.include({
/**
* converts a #XXX or rgb(X, X, X) sring into standard #XXXXXX color string
*
* @return String hex color
*/
@@ -3905,27 +4094,27 @@
*
* Credits:
* The idea is inspired by the Morph effect from
* - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
*
- * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
Fx.Morph = new Class(Fx, (function() {
// a list of common style names to compact the code a bit
var Color = 'Color', Style = 'Style', Width = 'Width', Bg = 'background',
Border = 'border', Pos = 'Position', BgColor = Bg + Color,
directions = $w('Top Left Right Bottom');
// adds variants to the style names list
- var add_variants = function(keys, key, variants) {
+ function add_variants(keys, key, variants) {
for (var i=0; i < variants.length; i++)
keys.push(key + variants[i]);
};
// adjusts the border-styles
- var check_border_styles = function(before, after) {
+ function check_border_styles(before, after) {
for (var i=0; i < 4; i++) {
var direction = directions[i],
bd_style = Border + direction + Style,
bd_width = Border + direction + Width,
bd_color = Border + direction + Color;
@@ -3944,21 +4133,23 @@
}
}
};
// parses the style hash into a processable format
- var parse_style = function(values) {
- var result = {}, re = /[\d\.\-]+/g, m;
+ function parse_style(values) {
+ var result = {}, re = /[\d\.\-]+/g, m, key, value, i;
- for (var key in values) {
+ for (key in values) {
m = values[key].match(re);
- var value = m.map('toFloat');
+ value = m.map('toFloat');
value.t = values[key].split(re);
value.r = value.t[0] === 'rgb(';
- if (value.t[0] === '' || value.r) value.t.shift();
- for (var i=0; i < value.length; i++) {
- value.t.splice(i*2, 0, value[i]);
+
+ if (value.t.length == 1) value.t.unshift('');
+
+ for (i=0; i < value.length; i++) {
+ value.t.splice(i*2 + 1, 0, value[i]);
}
result[key] = value;
}
return result;
@@ -3979,23 +4170,22 @@
this.before = parse_style(before);
this.after = parse_style(after);
},
render: function(delta) {
- var before, after, value, style = this.element.style;
- for (var key in this.after) {
+ var before, after, value, style = this.element.style, key, i;
+ for (key in this.after) {
before = this.before[key];
after = this.after[key];
- for (var i=0; i < after.length; i++) {
+ for (i=0; i < after.length; i++) {
value = before[i] + (after[i] - before[i]) * delta;
if (after.r) value = Math.round(value);
- after.t[i*2] = value;
+ after.t[i*2 + 1] = value;
}
- value = after.t.join('');
- if (after.r) value = 'rgb('+value;
- style[key] = value;
+
+ style[key] = after.t.join('');
}
},
/**
* Returns a hash of the end style
@@ -4006,13 +4196,13 @@
_endStyle: function(style, keys) {
var dummy = $(this.element.cloneNode(true))
.setStyle('position:absolute;z-index:-1;visibility:hidden')
.insertTo(this.element, 'before')
.setWidth(this.element.sizes().x)
- .setStyle(style);
+ .setStyle(style),
- var after = this._cloneStyle(dummy, keys);
+ after = this._cloneStyle(dummy, keys);
dummy.remove();
return after;
},
@@ -4036,16 +4226,16 @@
*
* @param Object the style hash
* @return Array of clean style keys list
*/
_styleKeys: function(style) {
- var keys = [], border_types = [Style, Color, Width];
+ var keys = [], border_types = [Style, Color, Width], key, i, j;
- for (var key in style) {
+ for (key in style) {
if (key.startsWith(Border))
- for (var i=0; i < border_types.length; i++)
- for (var j=0; j < directions.length; j++)
+ for (i=0; i < border_types.length; i++)
+ for (j=0; j < directions.length; j++)
keys.push(Border + directions[j] + border_types[i]);
else if (key == 'margin' || key == 'padding')
add_variants(keys, key, directions);
else if (key.startsWith(Bg))
add_variants(keys, Bg, [Color, Pos, Pos+'X', Pos+'Y']);
@@ -4064,13 +4254,13 @@
* @param Object before
* @param Object after
* @return void
*/
_cleanStyles: function(before, after) {
- var remove = [];
+ var remove = [], key;
- for (var key in after) {
+ for (key in after) {
// checking the height/width options
if ((key == 'width' || key == 'height') && before[key] == 'auto') {
before[key] = this.element['offset'+key.capitalize()] + 'px';
}
}
@@ -4080,11 +4270,11 @@
// adjusting the border style
check_border_styles.call(this, before, after);
// cleaing up the list
- for (var key in after) {
+ for (key in after) {
// proprocessing colors
if (after[key] !== before[key] && !remove.includes(key) && /color/i.test(key)) {
if (Browser.Opera) {
after[key] = after[key].replace(/"/g, '');
before[key] = before[key].replace(/"/g, '');
@@ -4126,11 +4316,11 @@
/**
* the elements hightlighting effect
*
- * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
Fx.Highlight = new Class(Fx.Morph, {
extend: {
Options: Object.merge(Fx.Options, {
color: '#FF8',
@@ -4162,11 +4352,11 @@
});
/**
* this is a superclass for the bidirectional effects
*
- * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
Fx.Twin = new Class(Fx.Morph, {
/**
* hides the element if it meant to be switched off
@@ -4197,11 +4387,11 @@
});
/**
* the slide effects wrapper
*
- * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
Fx.Slide = new Class(Fx.Twin, {
extend: {
Options: Object.merge(Fx.Options, {
direction: 'top'
@@ -4273,11 +4463,11 @@
});
/**
* The opacity effects wrapper
*
- * Copyright (C) 2008-2009 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
Fx.Fade = new Class(Fx.Twin, {
prepare: function(how) {
this.setHow(how);
@@ -4289,24 +4479,30 @@
});
/**
* A smooth scrolling visual effect
*
- * Copyright (C) 2009 Nikolay V. Nemshilov aka St.
+ * Copyright (C) 2009-2010 Nikolay V. Nemshilov
*/
Fx.Scroll = new Class(Fx, {
+
+ initialize: function(element, options) {
+ // swapping the actual scrollable when it's the window
+ this.$super(element.prompt ? element.document[Browser.WebKit ? 'body' : 'documentElement'] : element, options);
+ },
+
prepare: function(value) {
this.before = {};
this.after = value;
if (defined(value.x)) this.before.x = this.element.scrollLeft;
if (defined(value.y)) this.before.y = this.element.scrollTop;
},
render: function(delta) {
- var before = this.before;
- for (var key in before) {
+ var before = this.before, key;
+ for (key in before) {
this.element['scroll' + (key == 'x' ? 'Left' : 'Top')] = before[key] + (this.after[key] - before[key]) * delta;
}
}
});
@@ -4315,34 +4511,45 @@
*
* Credits:
* Some ideas are inspired by
* - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
*
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov aka St. <nemshilov#gma-ilc-om>
+ * Copyright (C) 2008-2010 Nikolay V. Nemshilov
*/
Element.include((function(methods) {
var old_hide = methods.hide,
old_show = methods.show,
old_scroll = methods.scrollTo;
return {
+ /**
+ * Stops all the visual effects on the element
+ *
+ * @return Element this
+ */
+ stop: function() {
+ (Fx.cr[$uid(this)] || []).each('cancel');
+ return this;
+ },
/**
* hides the element with given visual effect
*
* @param String fx name
* @param Object fx options
+ * @return Element this
*/
hide: function(fx, options) {
return fx ? this.fx(fx, ['out', options]) : old_hide.call(this);
},
/**
* shows the element with the given visual effect
*
* @param String fx name
* @param Object fx options
+ * @return Element this
*/
show: function(fx, options) {
return fx ? this.fx(fx, ['in', options]) : old_show.call(this);
},
@@ -4435,16 +4642,16 @@
*
* Basically it just checks all the script tags on the page
* finds the core inclusion tag and uses it's src attribute
* to dynamically load the olds patch
*
- * Copyright (C) 2009 Nikolay V. Nemshilov aka St.
+ * Copyright (C) 2009-2010 Nikolay V. Nemshilov
*/
if (!document.querySelector) {
(function() {
- var rigth_src_re = /(\/right)([^\/]+)$/;
- var core_src = $A(document.getElementsByTagName('script')).map('src').compact().first('match', rigth_src_re);
+ var rigth_src_re = /(^|\/)(right)([^\/]+)$/,
+ core_src = $A(document.getElementsByTagName('script')).map('src').compact().first('match', rigth_src_re);
if (core_src)
- document.write('<scr'+'ipt src="'+core_src.replace(rigth_src_re, '$1-olds$2')+'"></scr'+'ipt>');
+ document.write('<scr'+'ipt src="'+core_src.replace(rigth_src_re, '$1$2-olds$3')+'"></scr'+'ipt>');
})();
}
\ No newline at end of file