- From: Mercurial notifier <nobody@w3.org>
- Date: Mon, 30 Aug 2010 16:48:56 +0000
- To: Unicorn Updates <www-validator-cvs@w3.org>
changeset: 1470:a7329c2b3cb7 parent: 1465:15aeecb316cb user: Thomas Gambet <tgambet@w3.org> date: Wed Aug 18 01:03:50 2010 -0400 files: WebContent/scripts/mootools-1.2.4-core-nc.js WebContent/scripts/mootools-1.2.4.4-more-nc.js description: + uncompressed versions of mootools core and more for debugging diff -r 15aeecb316cb -r a7329c2b3cb7 WebContent/scripts/mootools-1.2.4-core-nc.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebContent/scripts/mootools-1.2.4-core-nc.js Wed Aug 18 01:03:50 2010 -0400 @@ -0,0 +1,4329 @@ +/* +--- + +script: Core.js + +description: The core of MooTools, contains all the base functions and the Native and Hash implementations. Required by all the other scripts. + +license: MIT-style license. + +copyright: Copyright (c) 2006-2008 [Valerio Proietti](http://mad4milk.net/). + +authors: The MooTools production team (http://mootools.net/developers/) + +inspiration: +- Class implementation inspired by [Base.js](http://dean.edwards.name/weblog/2006/03/base/) Copyright (c) 2006 Dean Edwards, [GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php) +- Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php) + +provides: [Mootools, Native, Hash.base, Array.each, $util] + +... +*/ + +var MooTools = { + 'version': '1.2.4', + 'build': '0d9113241a90b9cd5643b926795852a2026710d4' +}; + +var Native = function(options){ + options = options || {}; + var name = options.name; + var legacy = options.legacy; + var protect = options.protect; + var methods = options.implement; + var generics = options.generics; + var initialize = options.initialize; + var afterImplement = options.afterImplement || function(){}; + var object = initialize || legacy; + generics = generics !== false; + + object.constructor = Native; + object.$family = {name: 'native'}; + if (legacy && initialize) object.prototype = legacy.prototype; + object.prototype.constructor = object; + + if (name){ + var family = name.toLowerCase(); + object.prototype.$family = {name: family}; + Native.typize(object, family); + } + + var add = function(obj, name, method, force){ + if (!protect || force || !obj.prototype[name]) obj.prototype[name] = method; + if (generics) Native.genericize(obj, name, protect); + afterImplement.call(obj, name, method); + return obj; + }; + + object.alias = function(a1, a2, a3){ + if (typeof a1 == 'string'){ + var pa1 = this.prototype[a1]; + if ((a1 = pa1)) return add(this, a2, a1, a3); + } + for (var a in a1) this.alias(a, a1[a], a2); + return this; + }; + + object.implement = function(a1, a2, a3){ + if (typeof a1 == 'string') return add(this, a1, a2, a3); + for (var p in a1) add(this, p, a1[p], a2); + return this; + }; + + if (methods) object.implement(methods); + + return object; +}; + +Native.genericize = function(object, property, check){ + if ((!check || !object[property]) && typeof object.prototype[property] == 'function') object[property] = function(){ + var args = Array.prototype.slice.call(arguments); + return object.prototype[property].apply(args.shift(), args); + }; +}; + +Native.implement = function(objects, properties){ + for (var i = 0, l = objects.length; i < l; i++) objects[i].implement(properties); +}; + +Native.typize = function(object, family){ + if (!object.type) object.type = function(item){ + return ($type(item) === family); + }; +}; + +(function(){ + var natives = {'Array': Array, 'Date': Date, 'Function': Function, 'Number': Number, 'RegExp': RegExp, 'String': String}; + for (var n in natives) new Native({name: n, initialize: natives[n], protect: true}); + + var types = {'boolean': Boolean, 'native': Native, 'object': Object}; + for (var t in types) Native.typize(types[t], t); + + var generics = { + 'Array': ["concat", "indexOf", "join", "lastIndexOf", "pop", "push", "reverse", "shift", "slice", "sort", "splice", "toString", "unshift", "valueOf"], + 'String': ["charAt", "charCodeAt", "concat", "indexOf", "lastIndexOf", "match", "replace", "search", "slice", "split", "substr", "substring", "toLowerCase", "toUpperCase", "valueOf"] + }; + for (var g in generics){ + for (var i = generics[g].length; i--;) Native.genericize(natives[g], generics[g][i], true); + } +})(); + +var Hash = new Native({ + + name: 'Hash', + + initialize: function(object){ + if ($type(object) == 'hash') object = $unlink(object.getClean()); + for (var key in object) this[key] = object[key]; + return this; + } + +}); + +Hash.implement({ + + forEach: function(fn, bind){ + for (var key in this){ + if (this.hasOwnProperty(key)) fn.call(bind, this[key], key, this); + } + }, + + getClean: function(){ + var clean = {}; + for (var key in this){ + if (this.hasOwnProperty(key)) clean[key] = this[key]; + } + return clean; + }, + + getLength: function(){ + var length = 0; + for (var key in this){ + if (this.hasOwnProperty(key)) length++; + } + return length; + } + +}); + +Hash.alias('forEach', 'each'); + +Array.implement({ + + forEach: function(fn, bind){ + for (var i = 0, l = this.length; i < l; i++) fn.call(bind, this[i], i, this); + } + +}); + +Array.alias('forEach', 'each'); + +function $A(iterable){ + if (iterable.item){ + var l = iterable.length, array = new Array(l); + while (l--) array[l] = iterable[l]; + return array; + } + return Array.prototype.slice.call(iterable); +}; + +function $arguments(i){ + return function(){ + return arguments[i]; + }; +}; + +function $chk(obj){ + return !!(obj || obj === 0); +}; + +function $clear(timer){ + clearTimeout(timer); + clearInterval(timer); + return null; +}; + +function $defined(obj){ + return (obj != undefined); +}; + +function $each(iterable, fn, bind){ + var type = $type(iterable); + ((type == 'arguments' || type == 'collection' || type == 'array') ? Array : Hash).each(iterable, fn, bind); +}; + +function $empty(){}; + +function $extend(original, extended){ + for (var key in (extended || {})) original[key] = extended[key]; + return original; +}; + +function $H(object){ + return new Hash(object); +}; + +function $lambda(value){ + return ($type(value) == 'function') ? value : function(){ + return value; + }; +}; + +function $merge(){ + var args = Array.slice(arguments); + args.unshift({}); + return $mixin.apply(null, args); +}; + +function $mixin(mix){ + for (var i = 1, l = arguments.length; i < l; i++){ + var object = arguments[i]; + if ($type(object) != 'object') continue; + for (var key in object){ + var op = object[key], mp = mix[key]; + mix[key] = (mp && $type(op) == 'object' && $type(mp) == 'object') ? $mixin(mp, op) : $unlink(op); + } + } + return mix; +}; + +function $pick(){ + for (var i = 0, l = arguments.length; i < l; i++){ + if (arguments[i] != undefined) return arguments[i]; + } + return null; +}; + +function $random(min, max){ + return Math.floor(Math.random() * (max - min + 1) + min); +}; + +function $splat(obj){ + var type = $type(obj); + return (type) ? ((type != 'array' && type != 'arguments') ? [obj] : obj) : []; +}; + +var $time = Date.now || function(){ + return +new Date; +}; + +function $try(){ + for (var i = 0, l = arguments.length; i < l; i++){ + try { + return arguments[i](); + } catch(e){} + } + return null; +}; + +function $type(obj){ + if (obj == undefined) return false; + if (obj.$family) return (obj.$family.name == 'number' && !isFinite(obj)) ? false : obj.$family.name; + if (obj.nodeName){ + switch (obj.nodeType){ + case 1: return 'element'; + case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace'; + } + } else if (typeof obj.length == 'number'){ + if (obj.callee) return 'arguments'; + else if (obj.item) return 'collection'; + } + return typeof obj; +}; + +function $unlink(object){ + var unlinked; + switch ($type(object)){ + case 'object': + unlinked = {}; + for (var p in object) unlinked[p] = $unlink(object[p]); + break; + case 'hash': + unlinked = new Hash(object); + break; + case 'array': + unlinked = []; + for (var i = 0, l = object.length; i < l; i++) unlinked[i] = $unlink(object[i]); + break; + default: return object; + } + return unlinked; +}; + + +/* +--- + +script: Browser.js + +description: The Browser Core. Contains Browser initialization, Window and Document, and the Browser Hash. + +license: MIT-style license. + +requires: +- /Native +- /$util + +provides: [Browser, Window, Document, $exec] + +... +*/ + +var Browser = $merge({ + + Engine: {name: 'unknown', version: 0}, + + Platform: {name: (window.orientation != undefined) ? 'ipod' : (navigator.platform.match(/mac|win|linux/i) || ['other'])[0].toLowerCase()}, + + Features: {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)}, + + Plugins: {}, + + Engines: { + + presto: function(){ + return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925)); + }, + + trident: function(){ + return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? ((document.querySelectorAll) ? 6 : 5) : 4); + }, + + webkit: function(){ + return (navigator.taintEnabled) ? false : ((Browser.Features.xpath) ? ((Browser.Features.query) ? 525 : 420) : 419); + }, + + gecko: function(){ + return (!document.getBoxObjectFor && window.mozInnerScreenX == null) ? false : ((document.getElementsByClassName) ? 19 : 18); + } + + } + +}, Browser || {}); + +Browser.Platform[Browser.Platform.name] = true; + +Browser.detect = function(){ + + for (var engine in this.Engines){ + var version = this.Engines[engine](); + if (version){ + this.Engine = {name: engine, version: version}; + this.Engine[engine] = this.Engine[engine + version] = true; + break; + } + } + + return {name: engine, version: version}; + +}; + +Browser.detect(); + +Browser.Request = function(){ + return $try(function(){ + return new XMLHttpRequest(); + }, function(){ + return new ActiveXObject('MSXML2.XMLHTTP'); + }, function(){ + return new ActiveXObject('Microsoft.XMLHTTP'); + }); +}; + +Browser.Features.xhr = !!(Browser.Request()); + +Browser.Plugins.Flash = (function(){ + var version = ($try(function(){ + return navigator.plugins['Shockwave Flash'].description; + }, function(){ + return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version'); + }) || '0 r0').match(/\d+/g); + return {version: parseInt(version[0] || 0 + '.' + version[1], 10) || 0, build: parseInt(version[2], 10) || 0}; +})(); + +function $exec(text){ + if (!text) return text; + if (window.execScript){ + window.execScript(text); + } else { + var script = document.createElement('script'); + script.setAttribute('type', 'text/javascript'); + script[(Browser.Engine.webkit && Browser.Engine.version < 420) ? 'innerText' : 'text'] = text; + document.head.appendChild(script); + document.head.removeChild(script); + } + return text; +}; + +Native.UID = 1; + +var $uid = (Browser.Engine.trident) ? function(item){ + return (item.uid || (item.uid = [Native.UID++]))[0]; +} : function(item){ + return item.uid || (item.uid = Native.UID++); +}; + +var Window = new Native({ + + name: 'Window', + + legacy: (Browser.Engine.trident) ? null: window.Window, + + initialize: function(win){ + $uid(win); + if (!win.Element){ + win.Element = $empty; + if (Browser.Engine.webkit) win.document.createElement("iframe"); //fixes safari 2 + win.Element.prototype = (Browser.Engine.webkit) ? window["[[DOMElement.prototype]]"] : {}; + } + win.document.window = win; + return $extend(win, Window.Prototype); + }, + + afterImplement: function(property, value){ + window[property] = Window.Prototype[property] = value; + } + +}); + +Window.Prototype = {$family: {name: 'window'}}; + +new Window(window); + +var Document = new Native({ + + name: 'Document', + + legacy: (Browser.Engine.trident) ? null: window.Document, + + initialize: function(doc){ + $uid(doc); + doc.head = doc.getElementsByTagName('head')[0]; + doc.html = doc.getElementsByTagName('html')[0]; + if (Browser.Engine.trident && Browser.Engine.version <= 4) $try(function(){ + doc.execCommand("BackgroundImageCache", false, true); + }); + if (Browser.Engine.trident) doc.window.attachEvent('onunload', function(){ + doc.window.detachEvent('onunload', arguments.callee); + doc.head = doc.html = doc.window = null; + }); + return $extend(doc, Document.Prototype); + }, + + afterImplement: function(property, value){ + document[property] = Document.Prototype[property] = value; + } + +}); + +Document.Prototype = {$family: {name: 'document'}}; + +new Document(document); + + +/* +--- + +script: Array.js + +description: Contains Array Prototypes like each, contains, and erase. + +license: MIT-style license. + +requires: +- /$util +- /Array.each + +provides: [Array] + +... +*/ + +Array.implement({ + + every: function(fn, bind){ + for (var i = 0, l = this.length; i < l; i++){ + if (!fn.call(bind, this[i], i, this)) return false; + } + return true; + }, + + filter: function(fn, bind){ + var results = []; + for (var i = 0, l = this.length; i < l; i++){ + if (fn.call(bind, this[i], i, this)) results.push(this[i]); + } + return results; + }, + + clean: function(){ + return this.filter($defined); + }, + + indexOf: function(item, from){ + var len = this.length; + for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){ + if (this[i] === item) return i; + } + return -1; + }, + + map: function(fn, bind){ + var results = []; + for (var i = 0, l = this.length; i < l; i++) results[i] = fn.call(bind, this[i], i, this); + return results; + }, + + some: function(fn, bind){ + for (var i = 0, l = this.length; i < l; i++){ + if (fn.call(bind, this[i], i, this)) return true; + } + return false; + }, + + associate: function(keys){ + var obj = {}, length = Math.min(this.length, keys.length); + for (var i = 0; i < length; i++) obj[keys[i]] = this[i]; + return obj; + }, + + link: function(object){ + var result = {}; + for (var i = 0, l = this.length; i < l; i++){ + for (var key in object){ + if (object[key](this[i])){ + result[key] = this[i]; + delete object[key]; + break; + } + } + } + return result; + }, + + contains: function(item, from){ + return this.indexOf(item, from) != -1; + }, + + extend: function(array){ + for (var i = 0, j = array.length; i < j; i++) this.push(array[i]); + return this; + }, + + getLast: function(){ + return (this.length) ? this[this.length - 1] : null; + }, + + getRandom: function(){ + return (this.length) ? this[$random(0, this.length - 1)] : null; + }, + + include: function(item){ + if (!this.contains(item)) this.push(item); + return this; + }, + + combine: function(array){ + for (var i = 0, l = array.length; i < l; i++) this.include(array[i]); + return this; + }, + + erase: function(item){ + for (var i = this.length; i--; i){ + if (this[i] === item) this.splice(i, 1); + } + return this; + }, + + empty: function(){ + this.length = 0; + return this; + }, + + flatten: function(){ + var array = []; + for (var i = 0, l = this.length; i < l; i++){ + var type = $type(this[i]); + if (!type) continue; + array = array.concat((type == 'array' || type == 'collection' || type == 'arguments') ? Array.flatten(this[i]) : this[i]); + } + return array; + }, + + hexToRgb: function(array){ + if (this.length != 3) return null; + var rgb = this.map(function(value){ + if (value.length == 1) value += value; + return value.toInt(16); + }); + return (array) ? rgb : 'rgb(' + rgb + ')'; + }, + + rgbToHex: function(array){ + if (this.length < 3) return null; + if (this.length == 4 && this[3] == 0 && !array) return 'transparent'; + var hex = []; + for (var i = 0; i < 3; i++){ + var bit = (this[i] - 0).toString(16); + hex.push((bit.length == 1) ? '0' + bit : bit); + } + return (array) ? hex : '#' + hex.join(''); + } + +}); + + +/* +--- + +script: Function.js + +description: Contains Function Prototypes like create, bind, pass, and delay. + +license: MIT-style license. + +requires: +- /Native +- /$util + +provides: [Function] + +... +*/ + +Function.implement({ + + extend: function(properties){ + for (var property in properties) this[property] = properties[property]; + return this; + }, + + create: function(options){ + var self = this; + options = options || {}; + return function(event){ + var args = options.arguments; + args = (args != undefined) ? $splat(args) : Array.slice(arguments, (options.event) ? 1 : 0); + if (options.event) args = [event || window.event].extend(args); + var returns = function(){ + return self.apply(options.bind || null, args); + }; + if (options.delay) return setTimeout(returns, options.delay); + if (options.periodical) return setInterval(returns, options.periodical); + if (options.attempt) return $try(returns); + return returns(); + }; + }, + + run: function(args, bind){ + return this.apply(bind, $splat(args)); + }, + + pass: function(args, bind){ + return this.create({bind: bind, arguments: args}); + }, + + bind: function(bind, args){ + return this.create({bind: bind, arguments: args}); + }, + + bindWithEvent: function(bind, args){ + return this.create({bind: bind, arguments: args, event: true}); + }, + + attempt: function(args, bind){ + return this.create({bind: bind, arguments: args, attempt: true})(); + }, + + delay: function(delay, bind, args){ + return this.create({bind: bind, arguments: args, delay: delay})(); + }, + + periodical: function(periodical, bind, args){ + return this.create({bind: bind, arguments: args, periodical: periodical})(); + } + +}); + + +/* +--- + +script: Number.js + +description: Contains Number Prototypes like limit, round, times, and ceil. + +license: MIT-style license. + +requires: +- /Native +- /$util + +provides: [Number] + +... +*/ + +Number.implement({ + + limit: function(min, max){ + return Math.min(max, Math.max(min, this)); + }, + + round: function(precision){ + precision = Math.pow(10, precision || 0); + return Math.round(this * precision) / precision; + }, + + times: function(fn, bind){ + for (var i = 0; i < this; i++) fn.call(bind, i, this); + }, + + toFloat: function(){ + return parseFloat(this); + }, + + toInt: function(base){ + return parseInt(this, base || 10); + } + +}); + +Number.alias('times', 'each'); + +(function(math){ + var methods = {}; + math.each(function(name){ + if (!Number[name]) methods[name] = function(){ + return Math[name].apply(null, [this].concat($A(arguments))); + }; + }); + Number.implement(methods); +})(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']); + + +/* +--- + +script: String.js + +description: Contains String Prototypes like camelCase, capitalize, test, and toInt. + +license: MIT-style license. + +requires: +- /Native + +provides: [String] + +... +*/ + +String.implement({ + + test: function(regex, params){ + return ((typeof regex == 'string') ? new RegExp(regex, params) : regex).test(this); + }, + + contains: function(string, separator){ + return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : this.indexOf(string) > -1; + }, + + trim: function(){ + return this.replace(/^\s+|\s+$/g, ''); + }, + + clean: function(){ + return this.replace(/\s+/g, ' ').trim(); + }, + + camelCase: function(){ + return this.replace(/-\D/g, function(match){ + return match.charAt(1).toUpperCase(); + }); + }, + + hyphenate: function(){ + return this.replace(/[A-Z]/g, function(match){ + return ('-' + match.charAt(0).toLowerCase()); + }); + }, + + capitalize: function(){ + return this.replace(/\b[a-z]/g, function(match){ + return match.toUpperCase(); + }); + }, + + escapeRegExp: function(){ + return this.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1'); + }, + + toInt: function(base){ + return parseInt(this, base || 10); + }, + + toFloat: function(){ + return parseFloat(this); + }, + + hexToRgb: function(array){ + var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); + return (hex) ? hex.slice(1).hexToRgb(array) : null; + }, + + rgbToHex: function(array){ + var rgb = this.match(/\d{1,3}/g); + return (rgb) ? rgb.rgbToHex(array) : null; + }, + + stripScripts: function(option){ + var scripts = ''; + var text = this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(){ + scripts += arguments[1] + '\n'; + return ''; + }); + if (option === true) $exec(scripts); + else if ($type(option) == 'function') option(scripts, text); + return text; + }, + + substitute: function(object, regexp){ + return this.replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){ + if (match.charAt(0) == '\\') return match.slice(1); + return (object[name] != undefined) ? object[name] : ''; + }); + } + +}); + + +/* +--- + +script: Hash.js + +description: Contains Hash Prototypes. Provides a means for overcoming the JavaScript practical impossibility of extending native Objects. + +license: MIT-style license. + +requires: +- /Hash.base + +provides: [Hash] + +... +*/ + +Hash.implement({ + + has: Object.prototype.hasOwnProperty, + + keyOf: function(value){ + for (var key in this){ + if (this.hasOwnProperty(key) && this[key] === value) return key; + } + return null; + }, + + hasValue: function(value){ + return (Hash.keyOf(this, value) !== null); + }, + + extend: function(properties){ + Hash.each(properties || {}, function(value, key){ + Hash.set(this, key, value); + }, this); + return this; + }, + + combine: function(properties){ + Hash.each(properties || {}, function(value, key){ + Hash.include(this, key, value); + }, this); + return this; + }, + + erase: function(key){ + if (this.hasOwnProperty(key)) delete this[key]; + return this; + }, + + get: function(key){ + return (this.hasOwnProperty(key)) ? this[key] : null; + }, + + set: function(key, value){ + if (!this[key] || this.hasOwnProperty(key)) this[key] = value; + return this; + }, + + empty: function(){ + Hash.each(this, function(value, key){ + delete this[key]; + }, this); + return this; + }, + + include: function(key, value){ + if (this[key] == undefined) this[key] = value; + return this; + }, + + map: function(fn, bind){ + var results = new Hash; + Hash.each(this, function(value, key){ + results.set(key, fn.call(bind, value, key, this)); + }, this); + return results; + }, + + filter: function(fn, bind){ + var results = new Hash; + Hash.each(this, function(value, key){ + if (fn.call(bind, value, key, this)) results.set(key, value); + }, this); + return results; + }, + + every: function(fn, bind){ + for (var key in this){ + if (this.hasOwnProperty(key) && !fn.call(bind, this[key], key)) return false; + } + return true; + }, + + some: function(fn, bind){ + for (var key in this){ + if (this.hasOwnProperty(key) && fn.call(bind, this[key], key)) return true; + } + return false; + }, + + getKeys: function(){ + var keys = []; + Hash.each(this, function(value, key){ + keys.push(key); + }); + return keys; + }, + + getValues: function(){ + var values = []; + Hash.each(this, function(value){ + values.push(value); + }); + return values; + }, + + toQueryString: function(base){ + var queryString = []; + Hash.each(this, function(value, key){ + if (base) key = base + '[' + key + ']'; + var result; + switch ($type(value)){ + case 'object': result = Hash.toQueryString(value, key); break; + case 'array': + var qs = {}; + value.each(function(val, i){ + qs[i] = val; + }); + result = Hash.toQueryString(qs, key); + break; + default: result = key + '=' + encodeURIComponent(value); + } + if (value != undefined) queryString.push(result); + }); + + return queryString.join('&'); + } + +}); + +Hash.alias({keyOf: 'indexOf', hasValue: 'contains'}); + + +/* +--- + +script: Event.js + +description: Contains the Event Class, to make the event object cross-browser. + +license: MIT-style license. + +requires: +- /Window +- /Document +- /Hash +- /Array +- /Function +- /String + +provides: [Event] + +... +*/ + +var Event = new Native({ + + name: 'Event', + + initialize: function(event, win){ + win = win || window; + var doc = win.document; + event = event || win.event; + if (event.$extended) return event; + this.$extended = true; + var type = event.type; + var target = event.target || event.srcElement; + while (target && target.nodeType == 3) target = target.parentNode; + + if (type.test(/key/)){ + var code = event.which || event.keyCode; + var key = Event.Keys.keyOf(code); + if (type == 'keydown'){ + var fKey = code - 111; + if (fKey > 0 && fKey < 13) key = 'f' + fKey; + } + key = key || String.fromCharCode(code).toLowerCase(); + } else if (type.match(/(click|mouse|menu)/i)){ + doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body; + var page = { + x: event.pageX || event.clientX + doc.scrollLeft, + y: event.pageY || event.clientY + doc.scrollTop + }; + var client = { + x: (event.pageX) ? event.pageX - win.pageXOffset : event.clientX, + y: (event.pageY) ? event.pageY - win.pageYOffset : event.clientY + }; + if (type.match(/DOMMouseScroll|mousewheel/)){ + var wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3; + } + var rightClick = (event.which == 3) || (event.button == 2); + var related = null; + if (type.match(/over|out/)){ + switch (type){ + case 'mouseover': related = event.relatedTarget || event.fromElement; break; + case 'mouseout': related = event.relatedTarget || event.toElement; + } + if (!(function(){ + while (related && related.nodeType == 3) related = related.parentNode; + return true; + }).create({attempt: Browser.Engine.gecko})()) related = false; + } + } + + return $extend(this, { + event: event, + type: type, + + page: page, + client: client, + rightClick: rightClick, + + wheel: wheel, + + relatedTarget: related, + target: target, + + code: code, + key: key, + + shift: event.shiftKey, + control: event.ctrlKey, + alt: event.altKey, + meta: event.metaKey + }); + } + +}); + +Event.Keys = new Hash({ + 'enter': 13, + 'up': 38, + 'down': 40, + 'left': 37, + 'right': 39, + 'esc': 27, + 'space': 32, + 'backspace': 8, + 'tab': 9, + 'delete': 46 +}); + +Event.implement({ + + stop: function(){ + return this.stopPropagation().preventDefault(); + }, + + stopPropagation: function(){ + if (this.event.stopPropagation) this.event.stopPropagation(); + else this.event.cancelBubble = true; + return this; + }, + + preventDefault: function(){ + if (this.event.preventDefault) this.event.preventDefault(); + else this.event.returnValue = false; + return this; + } + +}); + + +/* +--- + +script: Class.js + +description: Contains the Class Function for easily creating, extending, and implementing reusable Classes. + +license: MIT-style license. + +requires: +- /$util +- /Native +- /Array +- /String +- /Function +- /Number +- /Hash + +provides: [Class] + +... +*/ + +function Class(params){ + + if (params instanceof Function) params = {initialize: params}; + + var newClass = function(){ + Object.reset(this); + if (newClass._prototyping) return this; + this._current = $empty; + var value = (this.initialize) ? this.initialize.apply(this, arguments) : this; + delete this._current; delete this.caller; + return value; + }.extend(this); + + newClass.implement(params); + + newClass.constructor = Class; + newClass.prototype.constructor = newClass; + + return newClass; + +}; + +Function.prototype.protect = function(){ + this._protected = true; + return this; +}; + +Object.reset = function(object, key){ + + if (key == null){ + for (var p in object) Object.reset(object, p); + return object; + } + + delete object[key]; + + switch ($type(object[key])){ + case 'object': + var F = function(){}; + F.prototype = object[key]; + var i = new F; + object[key] = Object.reset(i); + break; + case 'array': object[key] = $unlink(object[key]); break; + } + + return object; + +}; + +new Native({name: 'Class', initialize: Class}).extend({ + + instantiate: function(F){ + F._prototyping = true; + var proto = new F; + delete F._prototyping; + return proto; + }, + + wrap: function(self, key, method){ + if (method._origin) method = method._origin; + + return function(){ + if (method._protected && this._current == null) throw new Error('The method "' + key + '" cannot be called.'); + var caller = this.caller, current = this._current; + this.caller = current; this._current = arguments.callee; + var result = method.apply(this, arguments); + this._current = current; this.caller = caller; + return result; + }.extend({_owner: self, _origin: method, _name: key}); + + } + +}); + +Class.implement({ + + implement: function(key, value){ + + if ($type(key) == 'object'){ + for (var p in key) this.implement(p, key[p]); + return this; + } + + var mutator = Class.Mutators[key]; + + if (mutator){ + value = mutator.call(this, value); + if (value == null) return this; + } + + var proto = this.prototype; + + switch ($type(value)){ + + case 'function': + if (value._hidden) return this; + proto[key] = Class.wrap(this, key, value); + break; + + case 'object': + var previous = proto[key]; + if ($type(previous) == 'object') $mixin(previous, value); + else proto[key] = $unlink(value); + break; + + case 'array': + proto[key] = $unlink(value); + break; + + default: proto[key] = value; + + } + + return this; + + } + +}); + +Class.Mutators = { + + Extends: function(parent){ + + this.parent = parent; + this.prototype = Class.instantiate(parent); + + this.implement('parent', function(){ + var name = this.caller._name, previous = this.caller._owner.parent.prototype[name]; + if (!previous) throw new Error('The method "' + name + '" has no parent.'); + return previous.apply(this, arguments); + }.protect()); + + }, + + Implements: function(items){ + $splat(items).each(function(item){ + if (item instanceof Function) item = Class.instantiate(item); + this.implement(item); + }, this); + + } + +}; + + +/* +--- + +script: Class.Extras.js + +description: Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks. + +license: MIT-style license. + +requires: +- /Class + +provides: [Chain, Events, Options] + +... +*/ + +var Chain = new Class({ + + $chain: [], + + chain: function(){ + this.$chain.extend(Array.flatten(arguments)); + return this; + }, + + callChain: function(){ + return (this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false; + }, + + clearChain: function(){ + this.$chain.empty(); + return this; + } + +}); + +var Events = new Class({ + + $events: {}, + + addEvent: function(type, fn, internal){ + type = Events.removeOn(type); + if (fn != $empty){ + this.$events[type] = this.$events[type] || []; + this.$events[type].include(fn); + if (internal) fn.internal = true; + } + return this; + }, + + addEvents: function(events){ + for (var type in events) this.addEvent(type, events[type]); + return this; + }, + + fireEvent: function(type, args, delay){ + type = Events.removeOn(type); + if (!this.$events || !this.$events[type]) return this; + this.$events[type].each(function(fn){ + fn.create({'bind': this, 'delay': delay, 'arguments': args})(); + }, this); + return this; + }, + + removeEvent: function(type, fn){ + type = Events.removeOn(type); + if (!this.$events[type]) return this; + if (!fn.internal) this.$events[type].erase(fn); + return this; + }, + + removeEvents: function(events){ + var type; + if ($type(events) == 'object'){ + for (type in events) this.removeEvent(type, events[type]); + return this; + } + if (events) events = Events.removeOn(events); + for (type in this.$events){ + if (events && events != type) continue; + var fns = this.$events[type]; + for (var i = fns.length; i--; i) this.removeEvent(type, fns[i]); + } + return this; + } + +}); + +Events.removeOn = function(string){ + return string.replace(/^on([A-Z])/, function(full, first){ + return first.toLowerCase(); + }); +}; + +var Options = new Class({ + + setOptions: function(){ + this.options = $merge.run([this.options].extend(arguments)); + if (!this.addEvent) return this; + for (var option in this.options){ + if ($type(this.options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue; + this.addEvent(option, this.options[option]); + delete this.options[option]; + } + return this; + } + +}); + + +/* +--- + +script: Element.js + +description: One of the most important items in MooTools. Contains the dollar function, the dollars function, and an handful of cross-browser, time-saver methods to let you easily work with HTML Elements. + +license: MIT-style license. + +requires: +- /Window +- /Document +- /Array +- /String +- /Function +- /Number +- /Hash + +provides: [Element, Elements, $, $$, Iframe] + +... +*/ + +var Element = new Native({ + + name: 'Element', + + legacy: window.Element, + + initialize: function(tag, props){ + var konstructor = Element.Constructors.get(tag); + if (konstructor) return konstructor(props); + if (typeof tag == 'string') return document.newElement(tag, props); + return document.id(tag).set(props); + }, + + afterImplement: function(key, value){ + Element.Prototype[key] = value; + if (Array[key]) return; + Elements.implement(key, function(){ + var items = [], elements = true; + for (var i = 0, j = this.length; i < j; i++){ + var returns = this[i][key].apply(this[i], arguments); + items.push(returns); + if (elements) elements = ($type(returns) == 'element'); + } + return (elements) ? new Elements(items) : items; + }); + } + +}); + +Element.Prototype = {$family: {name: 'element'}}; + +Element.Constructors = new Hash; + +var IFrame = new Native({ + + name: 'IFrame', + + generics: false, + + initialize: function(){ + var params = Array.link(arguments, {properties: Object.type, iframe: $defined}); + var props = params.properties || {}; + var iframe = document.id(params.iframe); + var onload = props.onload || $empty; + delete props.onload; + props.id = props.name = $pick(props.id, props.name, iframe ? (iframe.id || iframe.name) : 'IFrame_' + $time()); + iframe = new Element(iframe || 'iframe', props); + var onFrameLoad = function(){ + var host = $try(function(){ + return iframe.contentWindow.location.host; + }); + if (!host || host == window.location.host){ + var win = new Window(iframe.contentWindow); + new Document(iframe.contentWindow.document); + $extend(win.Element.prototype, Element.Prototype); + } + onload.call(iframe.contentWindow, iframe.contentWindow.document); + }; + var contentWindow = $try(function(){ + return iframe.contentWindow; + }); + ((contentWindow && contentWindow.document.body) || window.frames[props.id]) ? onFrameLoad() : iframe.addListener('load', onFrameLoad); + return iframe; + } + +}); + +var Elements = new Native({ + + initialize: function(elements, options){ + options = $extend({ddup: true, cash: true}, options); + elements = elements || []; + if (options.ddup || options.cash){ + var uniques = {}, returned = []; + for (var i = 0, l = elements.length; i < l; i++){ + var el = document.id(elements[i], !options.cash); + if (options.ddup){ + if (uniques[el.uid]) continue; + uniques[el.uid] = true; + } + if (el) returned.push(el); + } + elements = returned; + } + return (options.cash) ? $extend(elements, this) : elements; + } + +}); + +Elements.implement({ + + filter: function(filter, bind){ + if (!filter) return this; + return new Elements(Array.filter(this, (typeof filter == 'string') ? function(item){ + return item.match(filter); + } : filter, bind)); + } + +}); + +Document.implement({ + + newElement: function(tag, props){ + if (Browser.Engine.trident && props){ + ['name', 'type', 'checked'].each(function(attribute){ + if (!props[attribute]) return; + tag += ' ' + attribute + '="' + props[attribute] + '"'; + if (attribute != 'checked') delete props[attribute]; + }); + tag = '<' + tag + '>'; + } + return document.id(this.createElement(tag)).set(props); + }, + + newTextNode: function(text){ + return this.createTextNode(text); + }, + + getDocument: function(){ + return this; + }, + + getWindow: function(){ + return this.window; + }, + + id: (function(){ + + var types = { + + string: function(id, nocash, doc){ + id = doc.getElementById(id); + return (id) ? types.element(id, nocash) : null; + }, + + element: function(el, nocash){ + $uid(el); + if (!nocash && !el.$family && !(/^object|embed$/i).test(el.tagName)){ + var proto = Element.Prototype; + for (var p in proto) el[p] = proto[p]; + }; + return el; + }, + + object: function(obj, nocash, doc){ + if (obj.toElement) return types.element(obj.toElement(doc), nocash); + return null; + } + + }; + + types.textnode = types.whitespace = types.window = types.document = $arguments(0); + + return function(el, nocash, doc){ + if (el && el.$family && el.uid) return el; + var type = $type(el); + return (types[type]) ? types[type](el, nocash, doc || document) : null; + }; + + })() + +}); + +if (window.$ == null) Window.implement({ + $: function(el, nc){ + return document.id(el, nc, this.document); + } +}); + +Window.implement({ + + $$: function(selector){ + if (arguments.length == 1 && typeof selector == 'string') return this.document.getElements(selector); + var elements = []; + var args = Array.flatten(arguments); + for (var i = 0, l = args.length; i < l; i++){ + var item = args[i]; + switch ($type(item)){ + case 'element': elements.push(item); break; + case 'string': elements.extend(this.document.getElements(item, true)); + } + } + return new Elements(elements); + }, + + getDocument: function(){ + return this.document; + }, + + getWindow: function(){ + return this; + } + +}); + +Native.implement([Element, Document], { + + getElement: function(selector, nocash){ + return document.id(this.getElements(selector, true)[0] || null, nocash); + }, + + getElements: function(tags, nocash){ + tags = tags.split(','); + var elements = []; + var ddup = (tags.length > 1); + tags.each(function(tag){ + var partial = this.getElementsByTagName(tag.trim()); + (ddup) ? elements.extend(partial) : elements = partial; + }, this); + return new Elements(elements, {ddup: ddup, cash: !nocash}); + } + +}); + +(function(){ + +var collected = {}, storage = {}; +var props = {input: 'checked', option: 'selected', textarea: (Browser.Engine.webkit && Browser.Engine.version < 420) ? 'innerHTML' : 'value'}; + +var get = function(uid){ + return (storage[uid] || (storage[uid] = {})); +}; + +var clean = function(item, retain){ + if (!item) return; + var uid = item.uid; + if (Browser.Engine.trident){ + if (item.clearAttributes){ + var clone = retain && item.cloneNode(false); + item.clearAttributes(); + if (clone) item.mergeAttributes(clone); + } else if (item.removeEvents){ + item.removeEvents(); + } + if ((/object/i).test(item.tagName)){ + for (var p in item){ + if (typeof item[p] == 'function') item[p] = $empty; + } + Element.dispose(item); + } + } + if (!uid) return; + collected[uid] = storage[uid] = null; +}; + +var purge = function(){ + Hash.each(collected, clean); + if (Browser.Engine.trident) $A(document.getElementsByTagName('object')).each(clean); + if (window.CollectGarbage) CollectGarbage(); + collected = storage = null; +}; + +var walk = function(element, walk, start, match, all, nocash){ + var el = element[start || walk]; + var elements = []; + while (el){ + if (el.nodeType == 1 && (!match || Element.match(el, match))){ + if (!all) return document.id(el, nocash); + elements.push(el); + } + el = el[walk]; + } + return (all) ? new Elements(elements, {ddup: false, cash: !nocash}) : null; +}; + +var attributes = { + 'html': 'innerHTML', + 'class': 'className', + 'for': 'htmlFor', + 'defaultValue': 'defaultValue', + 'text': (Browser.Engine.trident || (Browser.Engine.webkit && Browser.Engine.version < 420)) ? 'innerText' : 'textContent' +}; +var bools = ['compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', 'disabled', 'readonly', 'multiple', 'selected', 'noresize', 'defer']; +var camels = ['value', 'type', 'defaultValue', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan', 'frameBorder', 'maxLength', 'readOnly', 'rowSpan', 'tabIndex', 'useMap']; + +bools = bools.associate(bools); + +Hash.extend(attributes, bools); +Hash.extend(attributes, camels.associate(camels.map(String.toLowerCase))); + +var inserters = { + + before: function(context, element){ + if (element.parentNode) element.parentNode.insertBefore(context, element); + }, + + after: function(context, element){ + if (!element.parentNode) return; + var next = element.nextSibling; + (next) ? element.parentNode.insertBefore(context, next) : element.parentNode.appendChild(context); + }, + + bottom: function(context, element){ + element.appendChild(context); + }, + + top: function(context, element){ + var first = element.firstChild; + (first) ? element.insertBefore(context, first) : element.appendChild(context); + } + +}; + +inserters.inside = inserters.bottom; + +Hash.each(inserters, function(inserter, where){ + + where = where.capitalize(); + + Element.implement('inject' + where, function(el){ + inserter(this, document.id(el, true)); + return this; + }); + + Element.implement('grab' + where, function(el){ + inserter(document.id(el, true), this); + return this; + }); + +}); + +Element.implement({ + + set: function(prop, value){ + switch ($type(prop)){ + case 'object': + for (var p in prop) this.set(p, prop[p]); + break; + case 'string': + var property = Element.Properties.get(prop); + (property && property.set) ? property.set.apply(this, Array.slice(arguments, 1)) : this.setProperty(prop, value); + } + return this; + }, + + get: function(prop){ + var property = Element.Properties.get(prop); + return (property && property.get) ? property.get.apply(this, Array.slice(arguments, 1)) : this.getProperty(prop); + }, + + erase: function(prop){ + var property = Element.Properties.get(prop); + (property && property.erase) ? property.erase.apply(this) : this.removeProperty(prop); + return this; + }, + + setProperty: function(attribute, value){ + var key = attributes[attribute]; + if (value == undefined) return this.removeProperty(attribute); + if (key && bools[attribute]) value = !!value; + (key) ? this[key] = value : this.setAttribute(attribute, '' + value); + return this; + }, + + setProperties: function(attributes){ + for (var attribute in attributes) this.setProperty(attribute, attributes[attribute]); + return this; + }, + + getProperty: function(attribute){ + var key = attributes[attribute]; + var value = (key) ? this[key] : this.getAttribute(attribute, 2); + return (bools[attribute]) ? !!value : (key) ? value : value || null; + }, + + getProperties: function(){ + var args = $A(arguments); + return args.map(this.getProperty, this).associate(args); + }, + + removeProperty: function(attribute){ + var key = attributes[attribute]; + (key) ? this[key] = (key && bools[attribute]) ? false : '' : this.removeAttribute(attribute); + return this; + }, + + removeProperties: function(){ + Array.each(arguments, this.removeProperty, this); + return this; + }, + + hasClass: function(className){ + return this.className.contains(className, ' '); + }, + + addClass: function(className){ + if (!this.hasClass(className)) this.className = (this.className + ' ' + className).clean(); + return this; + }, + + removeClass: function(className){ + this.className = this.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1'); + return this; + }, + + toggleClass: function(className){ + return this.hasClass(className) ? this.removeClass(className) : this.addClass(className); + }, + + adopt: function(){ + Array.flatten(arguments).each(function(element){ + element = document.id(element, true); + if (element) this.appendChild(element); + }, this); + return this; + }, + + appendText: function(text, where){ + return this.grab(this.getDocument().newTextNode(text), where); + }, + + grab: function(el, where){ + inserters[where || 'bottom'](document.id(el, true), this); + return this; + }, + + inject: function(el, where){ + inserters[where || 'bottom'](this, document.id(el, true)); + return this; + }, + + replaces: function(el){ + el = document.id(el, true); + el.parentNode.replaceChild(this, el); + return this; + }, + + wraps: function(el, where){ + el = document.id(el, true); + return this.replaces(el).grab(el, where); + }, + + getPrevious: function(match, nocash){ + return walk(this, 'previousSibling', null, match, false, nocash); + }, + + getAllPrevious: function(match, nocash){ + return walk(this, 'previousSibling', null, match, true, nocash); + }, + + getNext: function(match, nocash){ + return walk(this, 'nextSibling', null, match, false, nocash); + }, + + getAllNext: function(match, nocash){ + return walk(this, 'nextSibling', null, match, true, nocash); + }, + + getFirst: function(match, nocash){ + return walk(this, 'nextSibling', 'firstChild', match, false, nocash); + }, + + getLast: function(match, nocash){ + return walk(this, 'previousSibling', 'lastChild', match, false, nocash); + }, + + getParent: function(match, nocash){ + return walk(this, 'parentNode', null, match, false, nocash); + }, + + getParents: function(match, nocash){ + return walk(this, 'parentNode', null, match, true, nocash); + }, + + getSiblings: function(match, nocash){ + return this.getParent().getChildren(match, nocash).erase(this); + }, + + getChildren: function(match, nocash){ + return walk(this, 'nextSibling', 'firstChild', match, true, nocash); + }, + + getWindow: function(){ + return this.ownerDocument.window; + }, + + getDocument: function(){ + return this.ownerDocument; + }, + + getElementById: function(id, nocash){ + var el = this.ownerDocument.getElementById(id); + if (!el) return null; + for (var parent = el.parentNode; parent != this; parent = parent.parentNode){ + if (!parent) return null; + } + return document.id(el, nocash); + }, + + getSelected: function(){ + return new Elements($A(this.options).filter(function(option){ + return option.selected; + })); + }, + + getComputedStyle: function(property){ + if (this.currentStyle) return this.currentStyle[property.camelCase()]; + var computed = this.getDocument().defaultView.getComputedStyle(this, null); + return (computed) ? computed.getPropertyValue([property.hyphenate()]) : null; + }, + + toQueryString: function(){ + var queryString = []; + this.getElements('input, select, textarea', true).each(function(el){ + if (!el.name || el.disabled || el.type == 'submit' || el.type == 'reset' || el.type == 'file') return; + var value = (el.tagName.toLowerCase() == 'select') ? Element.getSelected(el).map(function(opt){ + return opt.value; + }) : ((el.type == 'radio' || el.type == 'checkbox') && !el.checked) ? null : el.value; + $splat(value).each(function(val){ + if (typeof val != 'undefined') queryString.push(el.name + '=' + encodeURIComponent(val)); + }); + }); + return queryString.join('&'); + }, + + clone: function(contents, keepid){ + contents = contents !== false; + var clone = this.cloneNode(contents); + var clean = function(node, element){ + if (!keepid) node.removeAttribute('id'); + if (Browser.Engine.trident){ + node.clearAttributes(); + node.mergeAttributes(element); + node.removeAttribute('uid'); + if (node.options){ + var no = node.options, eo = element.options; + for (var j = no.length; j--;) no[j].selected = eo[j].selected; + } + } + var prop = props[element.tagName.toLowerCase()]; + if (prop && element[prop]) node[prop] = element[prop]; + }; + + if (contents){ + var ce = clone.getElementsByTagName('*'), te = this.getElementsByTagName('*'); + for (var i = ce.length; i--;) clean(ce[i], te[i]); + } + + clean(clone, this); + return document.id(clone); + }, + + destroy: function(){ + Element.empty(this); + Element.dispose(this); + clean(this, true); + return null; + }, + + empty: function(){ + $A(this.childNodes).each(function(node){ + Element.destroy(node); + }); + return this; + }, + + dispose: function(){ + return (this.parentNode) ? this.parentNode.removeChild(this) : this; + }, + + hasChild: function(el){ + el = document.id(el, true); + if (!el) return false; + if (Browser.Engine.webkit && Browser.Engine.version < 420) return $A(this.getElementsByTagName(el.tagName)).contains(el); + return (this.contains) ? (this != el && this.contains(el)) : !!(this.compareDocumentPosition(el) & 16); + }, + + match: function(tag){ + return (!tag || (tag == this) || (Element.get(this, 'tag') == tag)); + } + +}); + +Native.implement([Element, Window, Document], { + + addListener: function(type, fn){ + if (type == 'unload'){ + var old = fn, self = this; + fn = function(){ + self.removeListener('unload', fn); + old(); + }; + } else { + collected[this.uid] = this; + } + if (this.addEventListener) this.addEventListener(type, fn, false); + else this.attachEvent('on' + type, fn); + return this; + }, + + removeListener: function(type, fn){ + if (this.removeEventListener) this.removeEventListener(type, fn, false); + else this.detachEvent('on' + type, fn); + return this; + }, + + retrieve: function(property, dflt){ + var storage = get(this.uid), prop = storage[property]; + if (dflt != undefined && prop == undefined) prop = storage[property] = dflt; + return $pick(prop); + }, + + store: function(property, value){ + var storage = get(this.uid); + storage[property] = value; + return this; + }, + + eliminate: function(property){ + var storage = get(this.uid); + delete storage[property]; + return this; + } + +}); + +window.addListener('unload', purge); + +})(); + +Element.Properties = new Hash; + +Element.Properties.style = { + + set: function(style){ + this.style.cssText = style; + }, + + get: function(){ + return this.style.cssText; + }, + + erase: function(){ + this.style.cssText = ''; + } + +}; + +Element.Properties.tag = { + + get: function(){ + return this.tagName.toLowerCase(); + } + +}; + +Element.Properties.html = (function(){ + var wrapper = document.createElement('div'); + + var translations = { + table: [1, '<table>', '</table>'], + select: [1, '<select>', '</select>'], + tbody: [2, '<table><tbody>', '</tbody></table>'], + tr: [3, '<table><tbody><tr>', '</tr></tbody></table>'] + }; + translations.thead = translations.tfoot = translations.tbody; + + var html = { + set: function(){ + var html = Array.flatten(arguments).join(''); + var wrap = Browser.Engine.trident && translations[this.get('tag')]; + if (wrap){ + var first = wrapper; + first.innerHTML = wrap[1] + html + wrap[2]; + for (var i = wrap[0]; i--;) first = first.firstChild; + this.empty().adopt(first.childNodes); + } else { + this.innerHTML = html; + } + } + }; + + html.erase = html.set; + + return html; +})(); + +if (Browser.Engine.webkit && Browser.Engine.version < 420) Element.Properties.text = { + get: function(){ + if (this.innerText) return this.innerText; + var temp = this.ownerDocument.newElement('div', {html: this.innerHTML}).inject(this.ownerDocument.body); + var text = temp.innerText; + temp.destroy(); + return text; + } +}; + + +/* +--- + +script: Element.Event.js + +description: Contains Element methods for dealing with events. This file also includes mouseenter and mouseleave custom Element Events. + +license: MIT-style license. + +requires: +- /Element +- /Event + +provides: [Element.Event] + +... +*/ + +Element.Properties.events = {set: function(events){ + this.addEvents(events); +}}; + +Native.implement([Element, Window, Document], { + + addEvent: function(type, fn){ + var events = this.retrieve('events', {}); + events[type] = events[type] || {'keys': [], 'values': []}; + if (events[type].keys.contains(fn)) return this; + events[type].keys.push(fn); + var realType = type, custom = Element.Events.get(type), condition = fn, self = this; + if (custom){ + if (custom.onAdd) custom.onAdd.call(this, fn); + if (custom.condition){ + condition = function(event){ + if (custom.condition.call(this, event)) return fn.call(this, event); + return true; + }; + } + realType = custom.base || realType; + } + var defn = function(){ + return fn.call(self); + }; + var nativeEvent = Element.NativeEvents[realType]; + if (nativeEvent){ + if (nativeEvent == 2){ + defn = function(event){ + event = new Event(event, self.getWindow()); + if (condition.call(self, event) === false) event.stop(); + }; + } + this.addListener(realType, defn); + } + events[type].values.push(defn); + return this; + }, + + removeEvent: function(type, fn){ + var events = this.retrieve('events'); + if (!events || !events[type]) return this; + var pos = events[type].keys.indexOf(fn); + if (pos == -1) return this; + events[type].keys.splice(pos, 1); + var value = events[type].values.splice(pos, 1)[0]; + var custom = Element.Events.get(type); + if (custom){ + if (custom.onRemove) custom.onRemove.call(this, fn); + type = custom.base || type; + } + return (Element.NativeEvents[type]) ? this.removeListener(type, value) : this; + }, + + addEvents: function(events){ + for (var event in events) this.addEvent(event, events[event]); + return this; + }, + + removeEvents: function(events){ + var type; + if ($type(events) == 'object'){ + for (type in events) this.removeEvent(type, events[type]); + return this; + } + var attached = this.retrieve('events'); + if (!attached) return this; + if (!events){ + for (type in attached) this.removeEvents(type); + this.eliminate('events'); + } else if (attached[events]){ + while (attached[events].keys[0]) this.removeEvent(events, attached[events].keys[0]); + attached[events] = null; + } + return this; + }, + + fireEvent: function(type, args, delay){ + var events = this.retrieve('events'); + if (!events || !events[type]) return this; + events[type].keys.each(function(fn){ + fn.create({'bind': this, 'delay': delay, 'arguments': args})(); + }, this); + return this; + }, + + cloneEvents: function(from, type){ + from = document.id(from); + var fevents = from.retrieve('events'); + if (!fevents) return this; + if (!type){ + for (var evType in fevents) this.cloneEvents(from, evType); + } else if (fevents[type]){ + fevents[type].keys.each(function(fn){ + this.addEvent(type, fn); + }, this); + } + return this; + } + +}); + +Element.NativeEvents = { + click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons + mousewheel: 2, DOMMouseScroll: 2, //mouse wheel + mouseover: 2, mouseout: 2, mousemove: 2, selectstart: 2, selectend: 2, //mouse movement + keydown: 2, keypress: 2, keyup: 2, //keyboard + focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, //form elements + load: 1, unload: 1, beforeunload: 2, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window + error: 1, abort: 1, scroll: 1 //misc +}; + +(function(){ + +var $check = function(event){ + var related = event.relatedTarget; + if (related == undefined) return true; + if (related === false) return false; + return ($type(this) != 'document' && related != this && related.prefix != 'xul' && !this.hasChild(related)); +}; + +Element.Events = new Hash({ + + mouseenter: { + base: 'mouseover', + condition: $check + }, + + mouseleave: { + base: 'mouseout', + condition: $check + }, + + mousewheel: { + base: (Browser.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel' + } + +}); + +})(); + + +/* +--- + +script: Element.Style.js + +description: Contains methods for interacting with the styles of Elements in a fashionable way. + +license: MIT-style license. + +requires: +- /Element + +provides: [Element.Style] + +... +*/ + +Element.Properties.styles = {set: function(styles){ + this.setStyles(styles); +}}; + +Element.Properties.opacity = { + + set: function(opacity, novisibility){ + if (!novisibility){ + if (opacity == 0){ + if (this.style.visibility != 'hidden') this.style.visibility = 'hidden'; + } else { + if (this.style.visibility != 'visible') this.style.visibility = 'visible'; + } + } + if (!this.currentStyle || !this.currentStyle.hasLayout) this.style.zoom = 1; + if (Browser.Engine.trident) this.style.filter = (opacity == 1) ? '' : 'alpha(opacity=' + opacity * 100 + ')'; + this.style.opacity = opacity; + this.store('opacity', opacity); + }, + + get: function(){ + return this.retrieve('opacity', 1); + } + +}; + +Element.implement({ + + setOpacity: function(value){ + return this.set('opacity', value, true); + }, + + getOpacity: function(){ + return this.get('opacity'); + }, + + setStyle: function(property, value){ + switch (property){ + case 'opacity': return this.set('opacity', parseFloat(value)); + case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat'; + } + property = property.camelCase(); + if ($type(value) != 'string'){ + var map = (Element.Styles.get(property) || '@').split(' '); + value = $splat(value).map(function(val, i){ + if (!map[i]) return ''; + return ($type(val) == 'number') ? map[i].replace('@', Math.round(val)) : val; + }).join(' '); + } else if (value == String(Number(value))){ + value = Math.round(value); + } + this.style[property] = value; + return this; + }, + + getStyle: function(property){ + switch (property){ + case 'opacity': return this.get('opacity'); + case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat'; + } + property = property.camelCase(); + var result = this.style[property]; + if (!$chk(result)){ + result = []; + for (var style in Element.ShortStyles){ + if (property != style) continue; + for (var s in Element.ShortStyles[style]) result.push(this.getStyle(s)); + return result.join(' '); + } + result = this.getComputedStyle(property); + } + if (result){ + result = String(result); + var color = result.match(/rgba?\([\d\s,]+\)/); + if (color) result = result.replace(color[0], color[0].rgbToHex()); + } + if (Browser.Engine.presto || (Browser.Engine.trident && !$chk(parseInt(result, 10)))){ + if (property.test(/^(height|width)$/)){ + var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'], size = 0; + values.each(function(value){ + size += this.getStyle('border-' + value + '-width').toInt() + this.getStyle('padding-' + value).toInt(); + }, this); + return this['offset' + property.capitalize()] - size + 'px'; + } + if ((Browser.Engine.presto) && String(result).test('px')) return result; + if (property.test(/(border(.+)Width|margin|padding)/)) return '0px'; + } + return result; + }, + + setStyles: function(styles){ + for (var style in styles) this.setStyle(style, styles[style]); + return this; + }, + + getStyles: function(){ + var result = {}; + Array.flatten(arguments).each(function(key){ + result[key] = this.getStyle(key); + }, this); + return result; + } + +}); + +Element.Styles = new Hash({ + left: '@px', top: '@px', bottom: '@px', right: '@px', + width: '@px', height: '@px', maxWidth: '@px', maxHeight: '@px', minWidth: '@px', minHeight: '@px', + backgroundColor: 'rgb(@, @, @)', backgroundPosition: '@px @px', color: 'rgb(@, @, @)', + fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', clip: 'rect(@px @px @px @px)', + margin: '@px @px @px @px', padding: '@px @px @px @px', border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)', + borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)', + zIndex: '@', 'zoom': '@', fontWeight: '@', textIndent: '@px', opacity: '@' +}); + +Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, borderStyle: {}, borderColor: {}}; + +['Top', 'Right', 'Bottom', 'Left'].each(function(direction){ + var Short = Element.ShortStyles; + var All = Element.Styles; + ['margin', 'padding'].each(function(style){ + var sd = style + direction; + Short[style][sd] = All[sd] = '@px'; + }); + var bd = 'border' + direction; + Short.border[bd] = All[bd] = '@px @ rgb(@, @, @)'; + var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color'; + Short[bd] = {}; + Short.borderWidth[bdw] = Short[bd][bdw] = All[bdw] = '@px'; + Short.borderStyle[bds] = Short[bd][bds] = All[bds] = '@'; + Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)'; +}); + + +/* +--- + +script: Element.Dimensions.js + +description: Contains methods to work with size, scroll, or positioning of Elements and the window object. + +license: MIT-style license. + +credits: +- Element positioning based on the [qooxdoo](http://qooxdoo.org/) code and smart browser fixes, [LGPL License](http://www.gnu.org/licenses/lgpl.html). +- Viewport dimensions based on [YUI](http://developer.yahoo.com/yui/) code, [BSD License](http://developer.yahoo.com/yui/license.html). + +requires: +- /Element + +provides: [Element.Dimensions] + +... +*/ + +(function(){ + +Element.implement({ + + scrollTo: function(x, y){ + if (isBody(this)){ + this.getWindow().scrollTo(x, y); + } else { + this.scrollLeft = x; + this.scrollTop = y; + } + return this; + }, + + getSize: function(){ + if (isBody(this)) return this.getWindow().getSize(); + return {x: this.offsetWidth, y: this.offsetHeight}; + }, + + getScrollSize: function(){ + if (isBody(this)) return this.getWindow().getScrollSize(); + return {x: this.scrollWidth, y: this.scrollHeight}; + }, + + getScroll: function(){ + if (isBody(this)) return this.getWindow().getScroll(); + return {x: this.scrollLeft, y: this.scrollTop}; + }, + + getScrolls: function(){ + var element = this, position = {x: 0, y: 0}; + while (element && !isBody(element)){ + position.x += element.scrollLeft; + position.y += element.scrollTop; + element = element.parentNode; + } + return position; + }, + + getOffsetParent: function(){ + var element = this; + if (isBody(element)) return null; + if (!Browser.Engine.trident) return element.offsetParent; + while ((element = element.parentNode) && !isBody(element)){ + if (styleString(element, 'position') != 'static') return element; + } + return null; + }, + + getOffsets: function(){ + if (this.getBoundingClientRect){ + var bound = this.getBoundingClientRect(), + html = document.id(this.getDocument().documentElement), + htmlScroll = html.getScroll(), + elemScrolls = this.getScrolls(), + elemScroll = this.getScroll(), + isFixed = (styleString(this, 'position') == 'fixed'); + + return { + x: bound.left.toInt() + elemScrolls.x - elemScroll.x + ((isFixed) ? 0 : htmlScroll.x) - html.clientLeft, + y: bound.top.toInt() + elemScrolls.y - elemScroll.y + ((isFixed) ? 0 : htmlScroll.y) - html.clientTop + }; + } + + var element = this, position = {x: 0, y: 0}; + if (isBody(this)) return position; + + while (element && !isBody(element)){ + position.x += element.offsetLeft; + position.y += element.offsetTop; + + if (Browser.Engine.gecko){ + if (!borderBox(element)){ + position.x += leftBorder(element); + position.y += topBorder(element); + } + var parent = element.parentNode; + if (parent && styleString(parent, 'overflow') != 'visible'){ + position.x += leftBorder(parent); + position.y += topBorder(parent); + } + } else if (element != this && Browser.Engine.webkit){ + position.x += leftBorder(element); + position.y += topBorder(element); + } + + element = element.offsetParent; + } + if (Browser.Engine.gecko && !borderBox(this)){ + position.x -= leftBorder(this); + position.y -= topBorder(this); + } + return position; + }, + + getPosition: function(relative){ + if (isBody(this)) return {x: 0, y: 0}; + var offset = this.getOffsets(), + scroll = this.getScrolls(); + var position = { + x: offset.x - scroll.x, + y: offset.y - scroll.y + }; + var relativePosition = (relative && (relative = document.id(relative))) ? relative.getPosition() : {x: 0, y: 0}; + return {x: position.x - relativePosition.x, y: position.y - relativePosition.y}; + }, + + getCoordinates: function(element){ + if (isBody(this)) return this.getWindow().getCoordinates(); + var position = this.getPosition(element), + size = this.getSize(); + var obj = { + left: position.x, + top: position.y, + width: size.x, + height: size.y + }; + obj.right = obj.left + obj.width; + obj.bottom = obj.top + obj.height; + return obj; + }, + + computePosition: function(obj){ + return { + left: obj.x - styleNumber(this, 'margin-left'), + top: obj.y - styleNumber(this, 'margin-top') + }; + }, + + setPosition: function(obj){ + return this.setStyles(this.computePosition(obj)); + } + +}); + + +Native.implement([Document, Window], { + + getSize: function(){ + if (Browser.Engine.presto || Browser.Engine.webkit){ + var win = this.getWindow(); + return {x: win.innerWidth, y: win.innerHeight}; + } + var doc = getCompatElement(this); + return {x: doc.clientWidth, y: doc.clientHeight}; + }, + + getScroll: function(){ + var win = this.getWindow(), doc = getCompatElement(this); + return {x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop}; + }, + + getScrollSize: function(){ + var doc = getCompatElement(this), min = this.getSize(); + return {x: Math.max(doc.scrollWidth, min.x), y: Math.max(doc.scrollHeight, min.y)}; + }, + + getPosition: function(){ + return {x: 0, y: 0}; + }, + + getCoordinates: function(){ + var size = this.getSize(); + return {top: 0, left: 0, bottom: size.y, right: size.x, height: size.y, width: size.x}; + } + +}); + +// private methods + +var styleString = Element.getComputedStyle; + +function styleNumber(element, style){ + return styleString(element, style).toInt() || 0; +}; + +function borderBox(element){ + return styleString(element, '-moz-box-sizing') == 'border-box'; +}; + +function topBorder(element){ + return styleNumber(element, 'border-top-width'); +}; + +function leftBorder(element){ + return styleNumber(element, 'border-left-width'); +}; + +function isBody(element){ + return (/^(?:body|html)$/i).test(element.tagName); +}; + +function getCompatElement(element){ + var doc = element.getDocument(); + return (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body; +}; + +})(); + +//aliases +Element.alias('setPosition', 'position'); //compatability + +Native.implement([Window, Document, Element], { + + getHeight: function(){ + return this.getSize().y; + }, + + getWidth: function(){ + return this.getSize().x; + }, + + getScrollTop: function(){ + return this.getScroll().y; + }, + + getScrollLeft: function(){ + return this.getScroll().x; + }, + + getScrollHeight: function(){ + return this.getScrollSize().y; + }, + + getScrollWidth: function(){ + return this.getScrollSize().x; + }, + + getTop: function(){ + return this.getPosition().y; + }, + + getLeft: function(){ + return this.getPosition().x; + } + +}); + + +/* +--- + +script: Selectors.js + +description: Adds advanced CSS-style querying capabilities for targeting HTML Elements. Includes pseudo selectors. + +license: MIT-style license. + +requires: +- /Element + +provides: [Selectors] + +... +*/ + +Native.implement([Document, Element], { + + getElements: function(expression, nocash){ + expression = expression.split(','); + var items, local = {}; + for (var i = 0, l = expression.length; i < l; i++){ + var selector = expression[i], elements = Selectors.Utils.search(this, selector, local); + if (i != 0 && elements.item) elements = $A(elements); + items = (i == 0) ? elements : (items.item) ? $A(items).concat(elements) : items.concat(elements); + } + return new Elements(items, {ddup: (expression.length > 1), cash: !nocash}); + } + +}); + +Element.implement({ + + match: function(selector){ + if (!selector || (selector == this)) return true; + var tagid = Selectors.Utils.parseTagAndID(selector); + var tag = tagid[0], id = tagid[1]; + if (!Selectors.Filters.byID(this, id) || !Selectors.Filters.byTag(this, tag)) return false; + var parsed = Selectors.Utils.parseSelector(selector); + return (parsed) ? Selectors.Utils.filter(this, parsed, {}) : true; + } + +}); + +var Selectors = {Cache: {nth: {}, parsed: {}}}; + +Selectors.RegExps = { + id: (/#([\w-]+)/), + tag: (/^(\w+|\*)/), + quick: (/^(\w+|\*)$/), + splitter: (/\s*([+>~\s])\s*([a-zA-Z#.*:\[])/g), + combined: (/\.([\w-]+)|\[(\w+)(?:([!*^$~|]?=)(["']?)([^\4]*?)\4)?\]|:([\w-]+)(?:\(["']?(.*?)?["']?\)|$)/g) +}; + +Selectors.Utils = { + + chk: function(item, uniques){ + if (!uniques) return true; + var uid = $uid(item); + if (!uniques[uid]) return uniques[uid] = true; + return false; + }, + + parseNthArgument: function(argument){ + if (Selectors.Cache.nth[argument]) return Selectors.Cache.nth[argument]; + var parsed = argument.match(/^([+-]?\d*)?([a-z]+)?([+-]?\d*)?$/); + if (!parsed) return false; + var inta = parseInt(parsed[1], 10); + var a = (inta || inta === 0) ? inta : 1; + var special = parsed[2] || false; + var b = parseInt(parsed[3], 10) || 0; + if (a != 0){ + b--; + while (b < 1) b += a; + while (b >= a) b -= a; + } else { + a = b; + special = 'index'; + } + switch (special){ + case 'n': parsed = {a: a, b: b, special: 'n'}; break; + case 'odd': parsed = {a: 2, b: 0, special: 'n'}; break; + case 'even': parsed = {a: 2, b: 1, special: 'n'}; break; + case 'first': parsed = {a: 0, special: 'index'}; break; + case 'last': parsed = {special: 'last-child'}; break; + case 'only': parsed = {special: 'only-child'}; break; + default: parsed = {a: (a - 1), special: 'index'}; + } + + return Selectors.Cache.nth[argument] = parsed; + }, + + parseSelector: function(selector){ + if (Selectors.Cache.parsed[selector]) return Selectors.Cache.parsed[selector]; + var m, parsed = {classes: [], pseudos: [], attributes: []}; + while ((m = Selectors.RegExps.combined.exec(selector))){ + var cn = m[1], an = m[2], ao = m[3], av = m[5], pn = m[6], pa = m[7]; + if (cn){ + parsed.classes.push(cn); + } else if (pn){ + var parser = Selectors.Pseudo.get(pn); + if (parser) parsed.pseudos.push({parser: parser, argument: pa}); + else parsed.attributes.push({name: pn, operator: '=', value: pa}); + } else if (an){ + parsed.attributes.push({name: an, operator: ao, value: av}); + } + } + if (!parsed.classes.length) delete parsed.classes; + if (!parsed.attributes.length) delete parsed.attributes; + if (!parsed.pseudos.length) delete parsed.pseudos; + if (!parsed.classes && !parsed.attributes && !parsed.pseudos) parsed = null; + return Selectors.Cache.parsed[selector] = parsed; + }, + + parseTagAndID: function(selector){ + var tag = selector.match(Selectors.RegExps.tag); + var id = selector.match(Selectors.RegExps.id); + return [(tag) ? tag[1] : '*', (id) ? id[1] : false]; + }, + + filter: function(item, parsed, local){ + var i; + if (parsed.classes){ + for (i = parsed.classes.length; i--; i){ + var cn = parsed.classes[i]; + if (!Selectors.Filters.byClass(item, cn)) return false; + } + } + if (parsed.attributes){ + for (i = parsed.attributes.length; i--; i){ + var att = parsed.attributes[i]; + if (!Selectors.Filters.byAttribute(item, att.name, att.operator, att.value)) return false; + } + } + if (parsed.pseudos){ + for (i = parsed.pseudos.length; i--; i){ + var psd = parsed.pseudos[i]; + if (!Selectors.Filters.byPseudo(item, psd.parser, psd.argument, local)) return false; + } + } + return true; + }, + + getByTagAndID: function(ctx, tag, id){ + if (id){ + var item = (ctx.getElementById) ? ctx.getElementById(id, true) : Element.getElementById(ctx, id, true); + return (item && Selectors.Filters.byTag(item, tag)) ? [item] : []; + } else { + return ctx.getElementsByTagName(tag); + } + }, + + search: function(self, expression, local){ + var splitters = []; + + var selectors = expression.trim().replace(Selectors.RegExps.splitter, function(m0, m1, m2){ + splitters.push(m1); + return ':)' + m2; + }).split(':)'); + + var items, filtered, item; + + for (var i = 0, l = selectors.length; i < l; i++){ + + var selector = selectors[i]; + + if (i == 0 && Selectors.RegExps.quick.test(selector)){ + items = self.getElementsByTagName(selector); + continue; + } + + var splitter = splitters[i - 1]; + + var tagid = Selectors.Utils.parseTagAndID(selector); + var tag = tagid[0], id = tagid[1]; + + if (i == 0){ + items = Selectors.Utils.getByTagAndID(self, tag, id); + } else { + var uniques = {}, found = []; + for (var j = 0, k = items.length; j < k; j++) found = Selectors.Getters[splitter](found, items[j], tag, id, uniques); + items = found; + } + + var parsed = Selectors.Utils.parseSelector(selector); + + if (parsed){ + filtered = []; + for (var m = 0, n = items.length; m < n; m++){ + item = items[m]; + if (Selectors.Utils.filter(item, parsed, local)) filtered.push(item); + } + items = filtered; + } + + } + + return items; + + } + +}; + +Selectors.Getters = { + + ' ': function(found, self, tag, id, uniques){ + var items = Selectors.Utils.getByTagAndID(self, tag, id); + for (var i = 0, l = items.length; i < l; i++){ + var item = items[i]; + if (Selectors.Utils.chk(item, uniques)) found.push(item); + } + return found; + }, + + '>': function(found, self, tag, id, uniques){ + var children = Selectors.Utils.getByTagAndID(self, tag, id); + for (var i = 0, l = children.length; i < l; i++){ + var child = children[i]; + if (child.parentNode == self && Selectors.Utils.chk(child, uniques)) found.push(child); + } + return found; + }, + + '+': function(found, self, tag, id, uniques){ + while ((self = self.nextSibling)){ + if (self.nodeType == 1){ + if (Selectors.Utils.chk(self, uniques) && Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self); + break; + } + } + return found; + }, + + '~': function(found, self, tag, id, uniques){ + while ((self = self.nextSibling)){ + if (self.nodeType == 1){ + if (!Selectors.Utils.chk(self, uniques)) break; + if (Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self); + } + } + return found; + } + +}; + +Selectors.Filters = { + + byTag: function(self, tag){ + return (tag == '*' || (self.tagName && self.tagName.toLowerCase() == tag)); + }, + + byID: function(self, id){ + return (!id || (self.id && self.id == id)); + }, + + byClass: function(self, klass){ + return (self.className && self.className.contains && self.className.contains(klass, ' ')); + }, + + byPseudo: function(self, parser, argument, local){ + return parser.call(self, argument, local); + }, + + byAttribute: function(self, name, operator, value){ + var result = Element.prototype.getProperty.call(self, name); + if (!result) return (operator == '!='); + if (!operator || value == undefined) return true; + switch (operator){ + case '=': return (result == value); + case '*=': return (result.contains(value)); + case '^=': return (result.substr(0, value.length) == value); + case '$=': return (result.substr(result.length - value.length) == value); + case '!=': return (result != value); + case '~=': return result.contains(value, ' '); + case '|=': return result.contains(value, '-'); + } + return false; + } + +}; + +Selectors.Pseudo = new Hash({ + + // w3c pseudo selectors + + checked: function(){ + return this.checked; + }, + + empty: function(){ + return !(this.innerText || this.textContent || '').length; + }, + + not: function(selector){ + return !Element.match(this, selector); + }, + + contains: function(text){ + return (this.innerText || this.textContent || '').contains(text); + }, + + 'first-child': function(){ + return Selectors.Pseudo.index.call(this, 0); + }, + + 'last-child': function(){ + var element = this; + while ((element = element.nextSibling)){ + if (element.nodeType == 1) return false; + } + return true; + }, + + 'only-child': function(){ + var prev = this; + while ((prev = prev.previousSibling)){ + if (prev.nodeType == 1) return false; + } + var next = this; + while ((next = next.nextSibling)){ + if (next.nodeType == 1) return false; + } + return true; + }, + + 'nth-child': function(argument, local){ + argument = (argument == undefined) ? 'n' : argument; + var parsed = Selectors.Utils.parseNthArgument(argument); + if (parsed.special != 'n') return Selectors.Pseudo[parsed.special].call(this, parsed.a, local); + var count = 0; + local.positions = local.positions || {}; + var uid = $uid(this); + if (!local.positions[uid]){ + var self = this; + while ((self = self.previousSibling)){ + if (self.nodeType != 1) continue; + count ++; + var position = local.positions[$uid(self)]; + if (position != undefined){ + count = position + count; + break; + } + } + local.positions[uid] = count; + } + return (local.positions[uid] % parsed.a == parsed.b); + }, + + // custom pseudo selectors + + index: function(index){ + var element = this, count = 0; + while ((element = element.previousSibling)){ + if (element.nodeType == 1 && ++count > index) return false; + } + return (count == index); + }, + + even: function(argument, local){ + return Selectors.Pseudo['nth-child'].call(this, '2n+1', local); + }, + + odd: function(argument, local){ + return Selectors.Pseudo['nth-child'].call(this, '2n', local); + }, + + selected: function(){ + return this.selected; + }, + + enabled: function(){ + return (this.disabled === false); + } + +}); + + +/* +--- + +script: DomReady.js + +description: Contains the custom event domready. + +license: MIT-style license. + +requires: +- /Element.Event + +provides: [DomReady] + +... +*/ + +Element.Events.domready = { + + onAdd: function(fn){ + if (Browser.loaded) fn.call(this); + } + +}; + +(function(){ + + var domready = function(){ + if (Browser.loaded) return; + Browser.loaded = true; + window.fireEvent('domready'); + document.fireEvent('domready'); + }; + + window.addEvent('load', domready); + + if (Browser.Engine.trident){ + var temp = document.createElement('div'); + (function(){ + ($try(function(){ + temp.doScroll(); // Technique by Diego Perini + return document.id(temp).inject(document.body).set('html', 'temp').dispose(); + })) ? domready() : arguments.callee.delay(50); + })(); + } else if (Browser.Engine.webkit && Browser.Engine.version < 525){ + (function(){ + (['loaded', 'complete'].contains(document.readyState)) ? domready() : arguments.callee.delay(50); + })(); + } else { + document.addEvent('DOMContentLoaded', domready); + } + +})(); + + +/* +--- + +script: JSON.js + +description: JSON encoder and decoder. + +license: MIT-style license. + +See Also: <http://www.json.org/> + +requires: +- /Array +- /String +- /Number +- /Function +- /Hash + +provides: [JSON] + +... +*/ + +var JSON = new Hash(this.JSON && { + stringify: JSON.stringify, + parse: JSON.parse +}).extend({ + + $specialChars: {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'}, + + $replaceChars: function(chr){ + return JSON.$specialChars[chr] || '\\u00' + Math.floor(chr.charCodeAt() / 16).toString(16) + (chr.charCodeAt() % 16).toString(16); + }, + + encode: function(obj){ + switch ($type(obj)){ + case 'string': + return '"' + obj.replace(/[\x00-\x1f\\"]/g, JSON.$replaceChars) + '"'; + case 'array': + return '[' + String(obj.map(JSON.encode).clean()) + ']'; + case 'object': case 'hash': + var string = []; + Hash.each(obj, function(value, key){ + var json = JSON.encode(value); + if (json) string.push(JSON.encode(key) + ':' + json); + }); + return '{' + string + '}'; + case 'number': case 'boolean': return String(obj); + case false: return 'null'; + } + return null; + }, + + decode: function(string, secure){ + if ($type(string) != 'string' || !string.length) return null; + if (secure && !(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(string.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''))) return null; + return eval('(' + string + ')'); + } + +}); + +Native.implement([Hash, Array, String, Number], { + + toJSON: function(){ + return JSON.encode(this); + } + +}); + + +/* +--- + +script: Cookie.js + +description: Class for creating, reading, and deleting browser Cookies. + +license: MIT-style license. + +credits: +- Based on the functions by Peter-Paul Koch (http://quirksmode.org). + +requires: +- /Options + +provides: [Cookie] + +... +*/ + +var Cookie = new Class({ + + Implements: Options, + + options: { + path: false, + domain: false, + duration: false, + secure: false, + document: document + }, + + initialize: function(key, options){ + this.key = key; + this.setOptions(options); + }, + + write: function(value){ + value = encodeURIComponent(value); + if (this.options.domain) value += '; domain=' + this.options.domain; + if (this.options.path) value += '; path=' + this.options.path; + if (this.options.duration){ + var date = new Date(); + date.setTime(date.getTime() + this.options.duration * 24 * 60 * 60 * 1000); + value += '; expires=' + date.toGMTString(); + } + if (this.options.secure) value += '; secure'; + this.options.document.cookie = this.key + '=' + value; + return this; + }, + + read: function(){ + var value = this.options.document.cookie.match('(?:^|;)\\s*' + this.key.escapeRegExp() + '=([^;]*)'); + return (value) ? decodeURIComponent(value[1]) : null; + }, + + dispose: function(){ + new Cookie(this.key, $merge(this.options, {duration: -1})).write(''); + return this; + } + +}); + +Cookie.write = function(key, value, options){ + return new Cookie(key, options).write(value); +}; + +Cookie.read = function(key){ + return new Cookie(key).read(); +}; + +Cookie.dispose = function(key, options){ + return new Cookie(key, options).dispose(); +}; + + +/* +--- + +script: Swiff.js + +description: Wrapper for embedding SWF movies. Supports External Interface Communication. + +license: MIT-style license. + +credits: +- Flash detection & Internet Explorer + Flash Player 9 fix inspired by SWFObject. + +requires: +- /Options +- /$util + +provides: [Swiff] + +... +*/ + +var Swiff = new Class({ + + Implements: [Options], + + options: { + id: null, + height: 1, + width: 1, + container: null, + properties: {}, + params: { + quality: 'high', + allowScriptAccess: 'always', + wMode: 'transparent', + swLiveConnect: true + }, + callBacks: {}, + vars: {} + }, + + toElement: function(){ + return this.object; + }, + + initialize: function(path, options){ + this.instance = 'Swiff_' + $time(); + + this.setOptions(options); + options = this.options; + var id = this.id = options.id || this.instance; + var container = document.id(options.container); + + Swiff.CallBacks[this.instance] = {}; + + var params = options.params, vars = options.vars, callBacks = options.callBacks; + var properties = $extend({height: options.height, width: options.width}, options.properties); + + var self = this; + + for (var callBack in callBacks){ + Swiff.CallBacks[this.instance][callBack] = (function(option){ + return function(){ + return option.apply(self.object, arguments); + }; + })(callBacks[callBack]); + vars[callBack] = 'Swiff.CallBacks.' + this.instance + '.' + callBack; + } + + params.flashVars = Hash.toQueryString(vars); + if (Browser.Engine.trident){ + properties.classid = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000'; + params.movie = path; + } else { + properties.type = 'application/x-shockwave-flash'; + properties.data = path; + } + var build = '<object id="' + id + '"'; + for (var property in properties) build += ' ' + property + '="' + properties[property] + '"'; + build += '>'; + for (var param in params){ + if (params[param]) build += '<param name="' + param + '" value="' + params[param] + '" />'; + } + build += '</object>'; + this.object = ((container) ? container.empty() : new Element('div')).set('html', build).firstChild; + }, + + replaces: function(element){ + element = document.id(element, true); + element.parentNode.replaceChild(this.toElement(), element); + return this; + }, + + inject: function(element){ + document.id(element, true).appendChild(this.toElement()); + return this; + }, + + remote: function(){ + return Swiff.remote.apply(Swiff, [this.toElement()].extend(arguments)); + } + +}); + +Swiff.CallBacks = {}; + +Swiff.remote = function(obj, fn){ + var rs = obj.CallFunction('<invoke name="' + fn + '" returntype="javascript">' + __flash__argumentsToXML(arguments, 2) + '</invoke>'); + return eval(rs); +}; + + +/* +--- + +script: Fx.js + +description: Contains the basic animation logic to be extended by all other Fx Classes. + +license: MIT-style license. + +requires: +- /Chain +- /Events +- /Options + +provides: [Fx] + +... +*/ + +var Fx = new Class({ + + Implements: [Chain, Events, Options], + + options: { + /* + onStart: $empty, + onCancel: $empty, + onComplete: $empty, + */ + fps: 50, + unit: false, + duration: 500, + link: 'ignore' + }, + + initialize: function(options){ + this.subject = this.subject || this; + this.setOptions(options); + this.options.duration = Fx.Durations[this.options.duration] || this.options.duration.toInt(); + var wait = this.options.wait; + if (wait === false) this.options.link = 'cancel'; + }, + + getTransition: function(){ + return function(p){ + return -(Math.cos(Math.PI * p) - 1) / 2; + }; + }, + + step: function(){ + var time = $time(); + if (time < this.time + this.options.duration){ + var delta = this.transition((time - this.time) / this.options.duration); + this.set(this.compute(this.from, this.to, delta)); + } else { + this.set(this.compute(this.from, this.to, 1)); + this.complete(); + } + }, + + set: function(now){ + return now; + }, + + compute: function(from, to, delta){ + return Fx.compute(from, to, delta); + }, + + check: function(){ + if (!this.timer) return true; + switch (this.options.link){ + case 'cancel': this.cancel(); return true; + case 'chain': this.chain(this.caller.bind(this, arguments)); return false; + } + return false; + }, + + start: function(from, to){ + if (!this.check(from, to)) return this; + this.from = from; + this.to = to; + this.time = 0; + this.transition = this.getTransition(); + this.startTimer(); + this.onStart(); + return this; + }, + + complete: function(){ + if (this.stopTimer()) this.onComplete(); + return this; + }, + + cancel: function(){ + if (this.stopTimer()) this.onCancel(); + return this; + }, + + onStart: function(){ + this.fireEvent('start', this.subject); + }, + + onComplete: function(){ + this.fireEvent('complete', this.subject); + if (!this.callChain()) this.fireEvent('chainComplete', this.subject); + }, + + onCancel: function(){ + this.fireEvent('cancel', this.subject).clearChain(); + }, + + pause: function(){ + this.stopTimer(); + return this; + }, + + resume: function(){ + this.startTimer(); + return this; + }, + + stopTimer: function(){ + if (!this.timer) return false; + this.time = $time() - this.time; + this.timer = $clear(this.timer); + return true; + }, + + startTimer: function(){ + if (this.timer) return false; + this.time = $time() - this.time; + this.timer = this.step.periodical(Math.round(1000 / this.options.fps), this); + return true; + } + +}); + +Fx.compute = function(from, to, delta){ + return (to - from) * delta + from; +}; + +Fx.Durations = {'short': 250, 'normal': 500, 'long': 1000}; + + +/* +--- + +script: Fx.CSS.js + +description: Contains the CSS animation logic. Used by Fx.Tween, Fx.Morph, Fx.Elements. + +license: MIT-style license. + +requires: +- /Fx +- /Element.Style + +provides: [Fx.CSS] + +... +*/ + +Fx.CSS = new Class({ + + Extends: Fx, + + //prepares the base from/to object + + prepare: function(element, property, values){ + values = $splat(values); + var values1 = values[1]; + if (!$chk(values1)){ + values[1] = values[0]; + values[0] = element.getStyle(property); + } + var parsed = values.map(this.parse); + return {from: parsed[0], to: parsed[1]}; + }, + + //parses a value into an array + + parse: function(value){ + value = $lambda(value)(); + value = (typeof value == 'string') ? value.split(' ') : $splat(value); + return value.map(function(val){ + val = String(val); + var found = false; + Fx.CSS.Parsers.each(function(parser, key){ + if (found) return; + var parsed = parser.parse(val); + if ($chk(parsed)) found = {value: parsed, parser: parser}; + }); + found = found || {value: val, parser: Fx.CSS.Parsers.String}; + return found; + }); + }, + + //computes by a from and to prepared objects, using their parsers. + + compute: function(from, to, delta){ + var computed = []; + (Math.min(from.length, to.length)).times(function(i){ + computed.push({value: from[i].parser.compute(from[i].value, to[i].value, delta), parser: from[i].parser}); + }); + computed.$family = {name: 'fx:css:value'}; + return computed; + }, + + //serves the value as settable + + serve: function(value, unit){ + if ($type(value) != 'fx:css:value') value = this.parse(value); + var returned = []; + value.each(function(bit){ + returned = returned.concat(bit.parser.serve(bit.value, unit)); + }); + return returned; + }, + + //renders the change to an element + + render: function(element, property, value, unit){ + element.setStyle(property, this.serve(value, unit)); + }, + + //searches inside the page css to find the values for a selector + + search: function(selector){ + if (Fx.CSS.Cache[selector]) return Fx.CSS.Cache[selector]; + var to = {}; + Array.each(document.styleSheets, function(sheet, j){ + var href = sheet.href; + if (href && href.contains('://') && !href.contains(document.domain)) return; + var rules = sheet.rules || sheet.cssRules; + Array.each(rules, function(rule, i){ + if (!rule.style) return; + var selectorText = (rule.selectorText) ? rule.selectorText.replace(/^\w+/, function(m){ + return m.toLowerCase(); + }) : null; + if (!selectorText || !selectorText.test('^' + selector + '$')) return; + Element.Styles.each(function(value, style){ + if (!rule.style[style] || Element.ShortStyles[style]) return; + value = String(rule.style[style]); + to[style] = (value.test(/^rgb/)) ? value.rgbToHex() : value; + }); + }); + }); + return Fx.CSS.Cache[selector] = to; + } + +}); + +Fx.CSS.Cache = {}; + +Fx.CSS.Parsers = new Hash({ + + Color: { + parse: function(value){ + if (value.match(/^#[0-9a-f]{3,6}$/i)) return value.hexToRgb(true); + return ((value = value.match(/(\d+),\s*(\d+),\s*(\d+)/))) ? [value[1], value[2], value[3]] : false; + }, + compute: function(from, to, delta){ + return from.map(function(value, i){ + return Math.round(Fx.compute(from[i], to[i], delta)); + }); + }, + serve: function(value){ + return value.map(Number); + } + }, + + Number: { + parse: parseFloat, + compute: Fx.compute, + serve: function(value, unit){ + return (unit) ? value + unit : value; + } + }, + + String: { + parse: $lambda(false), + compute: $arguments(1), + serve: $arguments(0) + } + +}); + + +/* +--- + +script: Fx.Tween.js + +description: Formerly Fx.Style, effect to transition any CSS property for an element. + +license: MIT-style license. + +requires: +- /Fx.CSS + +provides: [Fx.Tween, Element.fade, Element.highlight] + +... +*/ + +Fx.Tween = new Class({ + + Extends: Fx.CSS, + + initialize: function(element, options){ + this.element = this.subject = document.id(element); + this.parent(options); + }, + + set: function(property, now){ + if (arguments.length == 1){ + now = property; + property = this.property || this.options.property; + } + this.render(this.element, property, now, this.options.unit); + return this; + }, + + start: function(property, from, to){ + if (!this.check(property, from, to)) return this; + var args = Array.flatten(arguments); + this.property = this.options.property || args.shift(); + var parsed = this.prepare(this.element, this.property, args); + return this.parent(parsed.from, parsed.to); + } + +}); + +Element.Properties.tween = { + + set: function(options){ + var tween = this.retrieve('tween'); + if (tween) tween.cancel(); + return this.eliminate('tween').store('tween:options', $extend({link: 'cancel'}, options)); + }, + + get: function(options){ + if (options || !this.retrieve('tween')){ + if (options || !this.retrieve('tween:options')) this.set('tween', options); + this.store('tween', new Fx.Tween(this, this.retrieve('tween:options'))); + } + return this.retrieve('tween'); + } + +}; + +Element.implement({ + + tween: function(property, from, to){ + this.get('tween').start(arguments); + return this; + }, + + fade: function(how){ + var fade = this.get('tween'), o = 'opacity', toggle; + how = $pick(how, 'toggle'); + switch (how){ + case 'in': fade.start(o, 1); break; + case 'out': fade.start(o, 0); break; + case 'show': fade.set(o, 1); break; + case 'hide': fade.set(o, 0); break; + case 'toggle': + var flag = this.retrieve('fade:flag', this.get('opacity') == 1); + fade.start(o, (flag) ? 0 : 1); + this.store('fade:flag', !flag); + toggle = true; + break; + default: fade.start(o, arguments); + } + if (!toggle) this.eliminate('fade:flag'); + return this; + }, + + highlight: function(start, end){ + if (!end){ + end = this.retrieve('highlight:original', this.getStyle('background-color')); + end = (end == 'transparent') ? '#fff' : end; + } + var tween = this.get('tween'); + tween.start('background-color', start || '#ffff88', end).chain(function(){ + this.setStyle('background-color', this.retrieve('highlight:original')); + tween.callChain(); + }.bind(this)); + return this; + } + +}); + + +/* +--- + +script: Fx.Morph.js + +description: Formerly Fx.Styles, effect to transition any number of CSS properties for an element using an object of rules, or CSS based selector rules. + +license: MIT-style license. + +requires: +- /Fx.CSS + +provides: [Fx.Morph] + +... +*/ + +Fx.Morph = new Class({ + + Extends: Fx.CSS, + + initialize: function(element, options){ + this.element = this.subject = document.id(element); + this.parent(options); + }, + + set: function(now){ + if (typeof now == 'string') now = this.search(now); + for (var p in now) this.render(this.element, p, now[p], this.options.unit); + return this; + }, + + compute: function(from, to, delta){ + var now = {}; + for (var p in from) now[p] = this.parent(from[p], to[p], delta); + return now; + }, + + start: function(properties){ + if (!this.check(properties)) return this; + if (typeof properties == 'string') properties = this.search(properties); + var from = {}, to = {}; + for (var p in properties){ + var parsed = this.prepare(this.element, p, properties[p]); + from[p] = parsed.from; + to[p] = parsed.to; + } + return this.parent(from, to); + } + +}); + +Element.Properties.morph = { + + set: function(options){ + var morph = this.retrieve('morph'); + if (morph) morph.cancel(); + return this.eliminate('morph').store('morph:options', $extend({link: 'cancel'}, options)); + }, + + get: function(options){ + if (options || !this.retrieve('morph')){ + if (options || !this.retrieve('morph:options')) this.set('morph', options); + this.store('morph', new Fx.Morph(this, this.retrieve('morph:options'))); + } + return this.retrieve('morph'); + } + +}; + +Element.implement({ + + morph: function(props){ + this.get('morph').start(props); + return this; + } + +}); + + +/* +--- + +script: Fx.Transitions.js + +description: Contains a set of advanced transitions to be used with any of the Fx Classes. + +license: MIT-style license. + +credits: +- Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>, modified and optimized to be used with MooTools. + +requires: +- /Fx + +provides: [Fx.Transitions] + +... +*/ + +Fx.implement({ + + getTransition: function(){ + var trans = this.options.transition || Fx.Transitions.Sine.easeInOut; + if (typeof trans == 'string'){ + var data = trans.split(':'); + trans = Fx.Transitions; + trans = trans[data[0]] || trans[data[0].capitalize()]; + if (data[1]) trans = trans['ease' + data[1].capitalize() + (data[2] ? data[2].capitalize() : '')]; + } + return trans; + } + +}); + +Fx.Transition = function(transition, params){ + params = $splat(params); + return $extend(transition, { + easeIn: function(pos){ + return transition(pos, params); + }, + easeOut: function(pos){ + return 1 - transition(1 - pos, params); + }, + easeInOut: function(pos){ + return (pos <= 0.5) ? transition(2 * pos, params) / 2 : (2 - transition(2 * (1 - pos), params)) / 2; + } + }); +}; + +Fx.Transitions = new Hash({ + + linear: $arguments(0) + +}); + +Fx.Transitions.extend = function(transitions){ + for (var transition in transitions) Fx.Transitions[transition] = new Fx.Transition(transitions[transition]); +}; + +Fx.Transitions.extend({ + + Pow: function(p, x){ + return Math.pow(p, x[0] || 6); + }, + + Expo: function(p){ + return Math.pow(2, 8 * (p - 1)); + }, + + Circ: function(p){ + return 1 - Math.sin(Math.acos(p)); + }, + + Sine: function(p){ + return 1 - Math.sin((1 - p) * Math.PI / 2); + }, + + Back: function(p, x){ + x = x[0] || 1.618; + return Math.pow(p, 2) * ((x + 1) * p - x); + }, + + Bounce: function(p){ + var value; + for (var a = 0, b = 1; 1; a += b, b /= 2){ + if (p >= (7 - 4 * a) / 11){ + value = b * b - Math.pow((11 - 6 * a - 11 * p) / 4, 2); + break; + } + } + return value; + }, + + Elastic: function(p, x){ + return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3); + } + +}); + +['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){ + Fx.Transitions[transition] = new Fx.Transition(function(p){ + return Math.pow(p, [i + 2]); + }); +}); + + +/* +--- + +script: Request.js + +description: Powerful all purpose Request Class. Uses XMLHTTPRequest. + +license: MIT-style license. + +requires: +- /Element +- /Chain +- /Events +- /Options +- /Browser + +provides: [Request] + +... +*/ + +var Request = new Class({ + + Implements: [Chain, Events, Options], + + options: {/* + onRequest: $empty, + onComplete: $empty, + onCancel: $empty, + onSuccess: $empty, + onFailure: $empty, + onException: $empty,*/ + url: '', + data: '', + headers: { + 'X-Requested-With': 'XMLHttpRequest', + 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' + }, + async: true, + format: false, + method: 'post', + link: 'ignore', + isSuccess: null, + emulation: true, + urlEncoded: true, + encoding: 'utf-8', + evalScripts: false, + evalResponse: false, + noCache: false + }, + + initialize: function(options){ + this.xhr = new Browser.Request(); + this.setOptions(options); + this.options.isSuccess = this.options.isSuccess || this.isSuccess; + this.headers = new Hash(this.options.headers); + }, + + onStateChange: function(){ + if (this.xhr.readyState != 4 || !this.running) return; + this.running = false; + this.status = 0; + $try(function(){ + this.status = this.xhr.status; + }.bind(this)); + this.xhr.onreadystatechange = $empty; + if (this.options.isSuccess.call(this, this.status)){ + this.response = {text: this.xhr.responseText, xml: this.xhr.responseXML}; + this.success(this.response.text, this.response.xml); + } else { + this.response = {text: null, xml: null}; + this.failure(); + } + }, + + isSuccess: function(){ + return ((this.status >= 200) && (this.status < 300)); + }, + + processScripts: function(text){ + if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) return $exec(text); + return text.stripScripts(this.options.evalScripts); + }, + + success: function(text, xml){ + this.onSuccess(this.processScripts(text), xml); + }, + + onSuccess: function(){ + this.fireEvent('complete', arguments).fireEvent('success', arguments).callChain(); + }, + + failure: function(){ + this.onFailure(); + }, + + onFailure: function(){ + this.fireEvent('complete').fireEvent('failure', this.xhr); + }, + + setHeader: function(name, value){ + this.headers.set(name, value); + return this; + }, + + getHeader: function(name){ + return $try(function(){ + return this.xhr.getResponseHeader(name); + }.bind(this)); + }, + + check: function(){ + if (!this.running) return true; + switch (this.options.link){ + case 'cancel': this.cancel(); return true; + case 'chain': this.chain(this.caller.bind(this, arguments)); return false; + } + return false; + }, + + send: function(options){ + if (!this.check(options)) return this; + this.running = true; + + var type = $type(options); + if (type == 'string' || type == 'element') options = {data: options}; + + var old = this.options; + options = $extend({data: old.data, url: old.url, method: old.method}, options); + var data = options.data, url = String(options.url), method = options.method.toLowerCase(); + + switch ($type(data)){ + case 'element': data = document.id(data).toQueryString(); break; + case 'object': case 'hash': data = Hash.toQueryString(data); + } + + if (this.options.format){ + var format = 'format=' + this.options.format; + data = (data) ? format + '&' + data : format; + } + + if (this.options.emulation && !['get', 'post'].contains(method)){ + var _method = '_method=' + method; + data = (data) ? _method + '&' + data : _method; + method = 'post'; + } + + if (this.options.urlEncoded && method == 'post'){ + var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : ''; + this.headers.set('Content-type', 'application/x-www-form-urlencoded' + encoding); + } + + if (this.options.noCache){ + var noCache = 'noCache=' + new Date().getTime(); + data = (data) ? noCache + '&' + data : noCache; + } + + var trimPosition = url.lastIndexOf('/'); + if (trimPosition > -1 && (trimPosition = url.indexOf('#')) > -1) url = url.substr(0, trimPosition); + + if (data && method == 'get'){ + url = url + (url.contains('?') ? '&' : '?') + data; + data = null; + } + + this.xhr.open(method.toUpperCase(), url, this.options.async); + + this.xhr.onreadystatechange = this.onStateChange.bind(this); + + this.headers.each(function(value, key){ + try { + this.xhr.setRequestHeader(key, value); + } catch (e){ + this.fireEvent('exception', [key, value]); + } + }, this); + + this.fireEvent('request'); + this.xhr.send(data); + if (!this.options.async) this.onStateChange(); + return this; + }, + + cancel: function(){ + if (!this.running) return this; + this.running = false; + this.xhr.abort(); + this.xhr.onreadystatechange = $empty; + this.xhr = new Browser.Request(); + this.fireEvent('cancel'); + return this; + } + +}); + +(function(){ + +var methods = {}; +['get', 'post', 'put', 'delete', 'GET', 'POST', 'PUT', 'DELETE'].each(function(method){ + methods[method] = function(){ + var params = Array.link(arguments, {url: String.type, data: $defined}); + return this.send($extend(params, {method: method})); + }; +}); + +Request.implement(methods); + +})(); + +Element.Properties.send = { + + set: function(options){ + var send = this.retrieve('send'); + if (send) send.cancel(); + return this.eliminate('send').store('send:options', $extend({ + data: this, link: 'cancel', method: this.get('method') || 'post', url: this.get('action') + }, options)); + }, + + get: function(options){ + if (options || !this.retrieve('send')){ + if (options || !this.retrieve('send:options')) this.set('send', options); + this.store('send', new Request(this.retrieve('send:options'))); + } + return this.retrieve('send'); + } + +}; + +Element.implement({ + + send: function(url){ + var sender = this.get('send'); + sender.send({data: this, url: url || sender.options.url}); + return this; + } + +}); + + +/* +--- + +script: Request.HTML.js + +description: Extends the basic Request Class with additional methods for interacting with HTML responses. + +license: MIT-style license. + +requires: +- /Request +- /Element + +provides: [Request.HTML] + +... +*/ + +Request.HTML = new Class({ + + Extends: Request, + + options: { + update: false, + append: false, + evalScripts: true, + filter: false + }, + + processHTML: function(text){ + var match = text.match(/<body[^>]*>([\s\S]*?)<\/body>/i); + text = (match) ? match[1] : text; + + var container = new Element('div'); + + return $try(function(){ + var root = '<root>' + text + '</root>', doc; + if (Browser.Engine.trident){ + doc = new ActiveXObject('Microsoft.XMLDOM'); + doc.async = false; + doc.loadXML(root); + } else { + doc = new DOMParser().parseFromString(root, 'text/xml'); + } + root = doc.getElementsByTagName('root')[0]; + if (!root) return null; + for (var i = 0, k = root.childNodes.length; i < k; i++){ + var child = Element.clone(root.childNodes[i], true, true); + if (child) container.grab(child); + } + return container; + }) || container.set('html', text); + }, + + success: function(text){ + var options = this.options, response = this.response; + + response.html = text.stripScripts(function(script){ + response.javascript = script; + }); + + var temp = this.processHTML(response.html); + + response.tree = temp.childNodes; + response.elements = temp.getElements('*'); + + if (options.filter) response.tree = response.elements.filter(options.filter); + if (options.update) document.id(options.update).empty().set('html', response.html); + else if (options.append) document.id(options.append).adopt(temp.getChildren()); + if (options.evalScripts) $exec(response.javascript); + + this.onSuccess(response.tree, response.elements, response.html, response.javascript); + } + +}); + +Element.Properties.load = { + + set: function(options){ + var load = this.retrieve('load'); + if (load) load.cancel(); + return this.eliminate('load').store('load:options', $extend({data: this, link: 'cancel', update: this, method: 'get'}, options)); + }, + + get: function(options){ + if (options || ! this.retrieve('load')){ + if (options || !this.retrieve('load:options')) this.set('load', options); + this.store('load', new Request.HTML(this.retrieve('load:options'))); + } + return this.retrieve('load'); + } + +}; + +Element.implement({ + + load: function(){ + this.get('load').send(Array.link(arguments, {data: Object.type, url: String.type})); + return this; + } + +}); + + +/* +--- + +script: Request.JSON.js + +description: Extends the basic Request Class with additional methods for sending and receiving JSON data. + +license: MIT-style license. + +requires: +- /Request JSON + +provides: [Request.HTML] + +... +*/ + +Request.JSON = new Class({ + + Extends: Request, + + options: { + secure: true + }, + + initialize: function(options){ + this.parent(options); + this.headers.extend({'Accept': 'application/json', 'X-Request': 'JSON'}); + }, + + success: function(text){ + this.response.json = JSON.decode(text, this.options.secure); + this.onSuccess(this.response.json, text); + } + +}); diff -r 15aeecb316cb -r a7329c2b3cb7 WebContent/scripts/mootools-1.2.4.4-more-nc.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebContent/scripts/mootools-1.2.4.4-more-nc.js Wed Aug 18 01:03:50 2010 -0400 @@ -0,0 +1,2063 @@ +//MooTools More, <http://mootools.net/more>. Copyright (c) 2006-2009 Aaron Newton <http://clientcide.com/>, Valerio Proietti <http://mad4milk.net> & the MooTools team <http://mootools.net/developers>, MIT Style License. + +/* +--- + +script: More.js + +description: MooTools More + +license: MIT-style license + +authors: +- Guillermo Rauch +- Thomas Aylott +- Scott Kyle + +requires: +- core:1.2.4/MooTools + +provides: [MooTools.More] + +... +*/ + +MooTools.More = { + 'version': '1.2.4.4', + 'build': '6f6057dc645fdb7547689183b2311063bd653ddf' +}; + +/* +--- + +script: MooTools.Lang.js + +description: Provides methods for localization. + +license: MIT-style license + +authors: +- Aaron Newton + +requires: +- core:1.2.4/Events +- /MooTools.More + +provides: [MooTools.Lang] + +... +*/ + +(function(){ + + var data = { + language: 'en-US', + languages: { + 'en-US': {} + }, + cascades: ['en-US'] + }; + + var cascaded; + + MooTools.lang = new Events(); + + $extend(MooTools.lang, { + + setLanguage: function(lang){ + if (!data.languages[lang]) return this; + data.language = lang; + this.load(); + this.fireEvent('langChange', lang); + return this; + }, + + load: function() { + var langs = this.cascade(this.getCurrentLanguage()); + cascaded = {}; + $each(langs, function(set, setName){ + cascaded[setName] = this.lambda(set); + }, this); + }, + + getCurrentLanguage: function(){ + return data.language; + }, + + addLanguage: function(lang){ + data.languages[lang] = data.languages[lang] || {}; + return this; + }, + + cascade: function(lang){ + var cascades = (data.languages[lang] || {}).cascades || []; + cascades.combine(data.cascades); + cascades.erase(lang).push(lang); + var langs = cascades.map(function(lng){ + return data.languages[lng]; + }, this); + return $merge.apply(this, langs); + }, + + lambda: function(set) { + (set || {}).get = function(key, args){ + return $lambda(set[key]).apply(this, $splat(args)); + }; + return set; + }, + + get: function(set, key, args){ + if (cascaded && cascaded[set]) return (key ? cascaded[set].get(key, args) : cascaded[set]); + }, + + set: function(lang, set, members){ + this.addLanguage(lang); + langData = data.languages[lang]; + if (!langData[set]) langData[set] = {}; + $extend(langData[set], members); + if (lang == this.getCurrentLanguage()){ + this.load(); + this.fireEvent('langChange', lang); + } + return this; + }, + + list: function(){ + return Hash.getKeys(data.languages); + } + + }); + +})(); + +/* +--- + +script: Class.Binds.js + +description: Automagically binds specified methods in a class to the instance of the class. + +license: MIT-style license + +authors: +- Aaron Newton + +requires: +- core:1.2.4/Class +- /MooTools.More + +provides: [Class.Binds] + +... +*/ + +Class.Mutators.Binds = function(binds){ + return binds; +}; + +Class.Mutators.initialize = function(initialize){ + return function(){ + $splat(this.Binds).each(function(name){ + var original = this[name]; + if (original) this[name] = original.bind(this); + }, this); + return initialize.apply(this, arguments); + }; +}; + + +/* +--- + +script: Chain.Wait.js + +description: value, Adds a method to inject pauses between chained events. + +license: MIT-style license. + +authors: +- Aaron Newton + +requires: +- core:1.2.4/Chain +- core:1.2.4/Element +- core:1.2.4/Fx +- /MooTools.More + +provides: [Chain.Wait] + +... +*/ + +(function(){ + + var wait = { + wait: function(duration){ + return this.chain(function(){ + this.callChain.delay($pick(duration, 500), this); + }.bind(this)); + } + }; + + Chain.implement(wait); + + if (window.Fx){ + Fx.implement(wait); + ['Css', 'Tween', 'Elements'].each(function(cls){ + if (Fx[cls]) Fx[cls].implement(wait); + }); + } + + Element.implement({ + chains: function(effects){ + $splat($pick(effects, ['tween', 'morph', 'reveal'])).each(function(effect){ + effect = this.get(effect); + if (!effect) return; + effect.setOptions({ + link:'chain' + }); + }, this); + return this; + }, + pauseFx: function(duration, effect){ + this.chains(effect).get($pick(effect, 'tween')).wait(duration); + return this; + } + }); + +})(); + +/* +--- + +script: Date.js + +description: Extends the Date native object to include methods useful in managing dates. + +license: MIT-style license + +authors: +- Aaron Newton +- Nicholas Barthelemy - https://svn.nbarthelemy.com/date-js/ +- Harald Kirshner - mail [at] digitarald.de; http://digitarald.de +- Scott Kyle - scott [at] appden.com; http://appden.com + +requires: +- core:1.2.4/Array +- core:1.2.4/String +- core:1.2.4/Number +- core:1.2.4/Lang +- core:1.2.4/Date.English.US +- /MooTools.More + +provides: [Date] + +... +*/ + +(function(){ + +var Date = this.Date; + +if (!Date.now) Date.now = $time; + +Date.Methods = { + ms: 'Milliseconds', + year: 'FullYear', + min: 'Minutes', + mo: 'Month', + sec: 'Seconds', + hr: 'Hours' +}; + +['Date', 'Day', 'FullYear', 'Hours', 'Milliseconds', 'Minutes', 'Month', 'Seconds', 'Time', 'TimezoneOffset', + 'Week', 'Timezone', 'GMTOffset', 'DayOfYear', 'LastMonth', 'LastDayOfMonth', 'UTCDate', 'UTCDay', 'UTCFullYear', + 'AMPM', 'Ordinal', 'UTCHours', 'UTCMilliseconds', 'UTCMinutes', 'UTCMonth', 'UTCSeconds'].each(function(method){ + Date.Methods[method.toLowerCase()] = method; +}); + +var pad = function(what, length){ + return new Array(length - String(what).length + 1).join('0') + what; +}; + +Date.implement({ + + set: function(prop, value){ + switch ($type(prop)){ + case 'object': + for (var p in prop) this.set(p, prop[p]); + break; + case 'string': + prop = prop.toLowerCase(); + var m = Date.Methods; + if (m[prop]) this['set' + m[prop]](value); + } + return this; + }, + + get: function(prop){ + prop = prop.toLowerCase(); + var m = Date.Methods; + if (m[prop]) return this['get' + m[prop]](); + return null; + }, + + clone: function(){ + return new Date(this.get('time')); + }, + + increment: function(interval, times){ + interval = interval || 'day'; + times = $pick(times, 1); + + switch (interval){ + case 'year': + return this.increment('month', times * 12); + case 'month': + var d = this.get('date'); + this.set('date', 1).set('mo', this.get('mo') + times); + return this.set('date', d.min(this.get('lastdayofmonth'))); + case 'week': + return this.increment('day', times * 7); + case 'day': + return this.set('date', this.get('date') + times); + } + + if (!Date.units[interval]) throw new Error(interval + ' is not a supported interval'); + + return this.set('time', this.get('time') + times * Date.units[interval]()); + }, + + decrement: function(interval, times){ + return this.increment(interval, -1 * $pick(times, 1)); + }, + + isLeapYear: function(){ + return Date.isLeapYear(this.get('year')); + }, + + clearTime: function(){ + return this.set({hr: 0, min: 0, sec: 0, ms: 0}); + }, + + diff: function(date, resolution){ + if ($type(date) == 'string') date = Date.parse(date); + + return ((date - this) / Date.units[resolution || 'day'](3, 3)).toInt(); // non-leap year, 30-day month + }, + + getLastDayOfMonth: function(){ + return Date.daysInMonth(this.get('mo'), this.get('year')); + }, + + getDayOfYear: function(){ + return (Date.UTC(this.get('year'), this.get('mo'), this.get('date') + 1) + - Date.UTC(this.get('year'), 0, 1)) / Date.units.day(); + }, + + getWeek: function(){ + return (this.get('dayofyear') / 7).ceil(); + }, + + getOrdinal: function(day){ + return Date.getMsg('ordinal', day || this.get('date')); + }, + + getTimezone: function(){ + return this.toString() + .replace(/^.*? ([A-Z]{3}).[0-9]{4}.*$/, '$1') + .replace(/^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/, '$1$2$3'); + }, + + getGMTOffset: function(){ + var off = this.get('timezoneOffset'); + return ((off > 0) ? '-' : '+') + pad((off.abs() / 60).floor(), 2) + pad(off % 60, 2); + }, + + setAMPM: function(ampm){ + ampm = ampm.toUpperCase(); + var hr = this.get('hr'); + if (hr > 11 && ampm == 'AM') return this.decrement('hour', 12); + else if (hr < 12 && ampm == 'PM') return this.increment('hour', 12); + return this; + }, + + getAMPM: function(){ + return (this.get('hr') < 12) ? 'AM' : 'PM'; + }, + + parse: function(str){ + this.set('time', Date.parse(str)); + return this; + }, + + isValid: function(date) { + return !!(date || this).valueOf(); + }, + + format: function(f){ + if (!this.isValid()) return 'invalid date'; + f = f || '%x %X'; + f = formats[f.toLowerCase()] || f; // replace short-hand with actual format + var d = this; + return f.replace(/%([a-z%])/gi, + function($0, $1){ + switch ($1){ + case 'a': return Date.getMsg('days')[d.get('day')].substr(0, 3); + case 'A': return Date.getMsg('days')[d.get('day')]; + case 'b': return Date.getMsg('months')[d.get('month')].substr(0, 3); + case 'B': return Date.getMsg('months')[d.get('month')]; + case 'c': return d.toString(); + case 'd': return pad(d.get('date'), 2); + case 'H': return pad(d.get('hr'), 2); + case 'I': return ((d.get('hr') % 12) || 12); + case 'j': return pad(d.get('dayofyear'), 3); + case 'm': return pad((d.get('mo') + 1), 2); + case 'M': return pad(d.get('min'), 2); + case 'o': return d.get('ordinal'); + case 'p': return Date.getMsg(d.get('ampm')); + case 'S': return pad(d.get('seconds'), 2); + case 'U': return pad(d.get('week'), 2); + case 'w': return d.get('day'); + case 'x': return d.format(Date.getMsg('shortDate')); + case 'X': return d.format(Date.getMsg('shortTime')); + case 'y': return d.get('year').toString().substr(2); + case 'Y': return d.get('year'); + case 'T': return d.get('GMTOffset'); + case 'Z': return d.get('Timezone'); + } + return $1; + } + ); + }, + + toISOString: function(){ + return this.format('iso8601'); + } + +}); + +Date.alias('toISOString', 'toJSON'); +Date.alias('diff', 'compare'); +Date.alias('format', 'strftime'); + +var formats = { + db: '%Y-%m-%d %H:%M:%S', + compact: '%Y%m%dT%H%M%S', + iso8601: '%Y-%m-%dT%H:%M:%S%T', + rfc822: '%a, %d %b %Y %H:%M:%S %Z', + 'short': '%d %b %H:%M', + 'long': '%B %d, %Y %H:%M' +}; + +var parsePatterns = []; +var nativeParse = Date.parse; + +var parseWord = function(type, word, num){ + var ret = -1; + var translated = Date.getMsg(type + 's'); + + switch ($type(word)){ + case 'object': + ret = translated[word.get(type)]; + break; + case 'number': + ret = translated[month - 1]; + if (!ret) throw new Error('Invalid ' + type + ' index: ' + index); + break; + case 'string': + var match = translated.filter(function(name){ + return this.test(name); + }, new RegExp('^' + word, 'i')); + if (!match.length) throw new Error('Invalid ' + type + ' string'); + if (match.length > 1) throw new Error('Ambiguous ' + type); + ret = match[0]; + } + + return (num) ? translated.indexOf(ret) : ret; +}; + +Date.extend({ + + getMsg: function(key, args) { + return MooTools.lang.get('Date', key, args); + }, + + units: { + ms: $lambda(1), + second: $lambda(1000), + minute: $lambda(60000), + hour: $lambda(3600000), + day: $lambda(86400000), + week: $lambda(608400000), + month: function(month, year){ + var d = new Date; + return Date.daysInMonth($pick(month, d.get('mo')), $pick(year, d.get('year'))) * 86400000; + }, + year: function(year){ + year = year || new Date().get('year'); + return Date.isLeapYear(year) ? 31622400000 : 31536000000; + } + }, + + daysInMonth: function(month, year){ + return [31, Date.isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; + }, + + isLeapYear: function(year){ + return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0); + }, + + parse: function(from){ + var t = $type(from); + if (t == 'number') return new Date(from); + if (t != 'string') return from; + from = from.clean(); + if (!from.length) return null; + + var parsed; + parsePatterns.some(function(pattern){ + var bits = pattern.re.exec(from); + return (bits) ? (parsed = pattern.handler(bits)) : false; + }); + + return parsed || new Date(nativeParse(from)); + }, + + parseDay: function(day, num){ + return parseWord('day', day, num); + }, + + parseMonth: function(month, num){ + return parseWord('month', month, num); + }, + + parseUTC: function(value){ + var localDate = new Date(value); + var utcSeconds = Date.UTC( + localDate.get('year'), + localDate.get('mo'), + localDate.get('date'), + localDate.get('hr'), + localDate.get('min'), + localDate.get('sec') + ); + return new Date(utcSeconds); + }, + + orderIndex: function(unit){ + return Date.getMsg('dateOrder').indexOf(unit) + 1; + }, + + defineFormat: function(name, format){ + formats[name] = format; + }, + + defineFormats: function(formats){ + for (var name in formats) Date.defineFormat(name, formats[name]); + }, + + parsePatterns: parsePatterns, // this is deprecated + + defineParser: function(pattern){ + parsePatterns.push((pattern.re && pattern.handler) ? pattern : build(pattern)); + }, + + defineParsers: function(){ + Array.flatten(arguments).each(Date.defineParser); + }, + + define2DigitYearStart: function(year){ + startYear = year % 100; + startCentury = year - startYear; + } + +}); + +var startCentury = 1900; +var startYear = 70; + +var regexOf = function(type){ + return new RegExp('(?:' + Date.getMsg(type).map(function(name){ + return name.substr(0, 3); + }).join('|') + ')[a-z]*'); +}; + +var replacers = function(key){ + switch(key){ + case 'x': // iso8601 covers yyyy-mm-dd, so just check if month is first + return ((Date.orderIndex('month') == 1) ? '%m[.-/]%d' : '%d[.-/]%m') + '([.-/]%y)?'; + case 'X': + return '%H([.:]%M)?([.:]%S([.:]%s)?)? ?%p? ?%T?'; + } + return null; +}; + +var keys = { + d: /[0-2]?[0-9]|3[01]/, + H: /[01]?[0-9]|2[0-3]/, + I: /0?[1-9]|1[0-2]/, + M: /[0-5]?\d/, + s: /\d+/, + o: /[a-z]*/, + p: /[ap]\.?m\.?/, + y: /\d{2}|\d{4}/, + Y: /\d{4}/, + T: /Z|[+-]\d{2}(?::?\d{2})?/ +}; + +keys.m = keys.I; +keys.S = keys.M; + +var currentLanguage; + +var recompile = function(language){ + currentLanguage = language; + + keys.a = keys.A = regexOf('days'); + keys.b = keys.B = regexOf('months'); + + parsePatterns.each(function(pattern, i){ + if (pattern.format) parsePatterns[i] = build(pattern.format); + }); +}; + +var build = function(format){ + if (!currentLanguage) return {format: format}; + + var parsed = []; + var re = (format.source || format) // allow format to be regex + .replace(/%([a-z])/gi, + function($0, $1){ + return replacers($1) || $0; + } + ).replace(/\((?!\?)/g, '(?:') // make all groups non-capturing + .replace(/ (?!\?|\*)/g, ',? ') // be forgiving with spaces and commas + .replace(/%([a-z%])/gi, + function($0, $1){ + var p = keys[$1]; + if (!p) return $1; + parsed.push($1); + return '(' + p.source + ')'; + } + ).replace(/\[a-z\]/gi, '[a-z\\u00c0-\\uffff]'); // handle unicode words + + return { + format: format, + re: new RegExp('^' + re + '$', 'i'), + handler: function(bits){ + bits = bits.slice(1).associate(parsed); + var date = new Date().clearTime(); + if ('d' in bits) handle.call(date, 'd', 1); + if ('m' in bits || 'b' in bits || 'B' in bits) handle.call(date, 'm', 1); + for (var key in bits) handle.call(date, key, bits[key]); + return date; + } + }; +}; + +var handle = function(key, value){ + if (!value) return this; + + switch(key){ + case 'a': case 'A': return this.set('day', Date.parseDay(value, true)); + case 'b': case 'B': return this.set('mo', Date.parseMonth(value, true)); + case 'd': return this.set('date', value); + case 'H': case 'I': return this.set('hr', value); + case 'm': return this.set('mo', value - 1); + case 'M': return this.set('min', value); + case 'p': return this.set('ampm', value.replace(/\./g, '')); + case 'S': return this.set('sec', value); + case 's': return this.set('ms', ('0.' + value) * 1000); + case 'w': return this.set('day', value); + case 'Y': return this.set('year', value); + case 'y': + value = +value; + if (value < 100) value += startCentury + (value < startYear ? 100 : 0); + return this.set('year', value); + case 'T': + if (value == 'Z') value = '+00'; + var offset = value.match(/([+-])(\d{2}):?(\d{2})?/); + offset = (offset[1] + '1') * (offset[2] * 60 + (+offset[3] || 0)) + this.getTimezoneOffset(); + return this.set('time', this - offset * 60000); + } + + return this; +}; + +Date.defineParsers( + '%Y([-./]%m([-./]%d((T| )%X)?)?)?', // "1999-12-31", "1999-12-31 11:59pm", "1999-12-31 23:59:59", ISO8601 + '%Y%m%d(T%H(%M%S?)?)?', // "19991231", "19991231T1159", compact + '%x( %X)?', // "12/31", "12.31.99", "12-31-1999", "12/31/2008 11:59 PM" + '%d%o( %b( %Y)?)?( %X)?', // "31st", "31st December", "31 Dec 1999", "31 Dec 1999 11:59pm" + '%b( %d%o)?( %Y)?( %X)?', // Same as above with month and day switched + '%Y %b( %d%o( %X)?)?', // Same as above with year coming first + '%o %b %d %X %T %Y' // "Thu Oct 22 08:11:23 +0000 2009" +); + +MooTools.lang.addEvent('langChange', function(language){ + if (MooTools.lang.get('Date')) recompile(language); +}).fireEvent('langChange', MooTools.lang.getCurrentLanguage()); + +})(); + +/* +--- + +script: Element.Forms.js + +description: Extends the Element native object to include methods useful in managing inputs. + +license: MIT-style license + +authors: +- Aaron Newton + +requires: +- core:1.2.4/Element +- /MooTools.More + +provides: [Element.Forms] + +... +*/ + +Element.implement({ + + tidy: function(){ + this.set('value', this.get('value').tidy()); + }, + + getTextInRange: function(start, end){ + return this.get('value').substring(start, end); + }, + + getSelectedText: function(){ + if (this.setSelectionRange) return this.getTextInRange(this.getSelectionStart(), this.getSelectionEnd()); + return document.selection.createRange().text; + }, + + getSelectedRange: function() { + if ($defined(this.selectionStart)) return {start: this.selectionStart, end: this.selectionEnd}; + var pos = {start: 0, end: 0}; + var range = this.getDocument().selection.createRange(); + if (!range || range.parentElement() != this) return pos; + var dup = range.duplicate(); + if (this.type == 'text') { + pos.start = 0 - dup.moveStart('character', -100000); + pos.end = pos.start + range.text.length; + } else { + var value = this.get('value'); + var offset = value.length; + dup.moveToElementText(this); + dup.setEndPoint('StartToEnd', range); + if(dup.text.length) offset -= value.match(/[\n\r]*$/)[0].length; + pos.end = offset - dup.text.length; + dup.setEndPoint('StartToStart', range); + pos.start = offset - dup.text.length; + } + return pos; + }, + + getSelectionStart: function(){ + return this.getSelectedRange().start; + }, + + getSelectionEnd: function(){ + return this.getSelectedRange().end; + }, + + setCaretPosition: function(pos){ + if (pos == 'end') pos = this.get('value').length; + this.selectRange(pos, pos); + return this; + }, + + getCaretPosition: function(){ + return this.getSelectedRange().start; + }, + + selectRange: function(start, end){ + if (this.setSelectionRange) { + this.focus(); + this.setSelectionRange(start, end); + } else { + var value = this.get('value'); + var diff = value.substr(start, end - start).replace(/\r/g, '').length; + start = value.substr(0, start).replace(/\r/g, '').length; + var range = this.createTextRange(); + range.collapse(true); + range.moveEnd('character', start + diff); + range.moveStart('character', start); + range.select(); + } + return this; + }, + + insertAtCursor: function(value, select){ + var pos = this.getSelectedRange(); + var text = this.get('value'); + this.set('value', text.substring(0, pos.start) + value + text.substring(pos.end, text.length)); + if ($pick(select, true)) this.selectRange(pos.start, pos.start + value.length); + else this.setCaretPosition(pos.start + value.length); + return this; + }, + + insertAroundCursor: function(options, select){ + options = $extend({ + before: '', + defaultMiddle: '', + after: '' + }, options); + var value = this.getSelectedText() || options.defaultMiddle; + var pos = this.getSelectedRange(); + var text = this.get('value'); + if (pos.start == pos.end){ + this.set('value', text.substring(0, pos.start) + options.before + value + options.after + text.substring(pos.end, text.length)); + this.selectRange(pos.start + options.before.length, pos.end + options.before.length + value.length); + } else { + var current = text.substring(pos.start, pos.end); + this.set('value', text.substring(0, pos.start) + options.before + current + options.after + text.substring(pos.end, text.length)); + var selStart = pos.start + options.before.length; + if ($pick(select, true)) this.selectRange(selStart, selStart + current.length); + else this.setCaretPosition(selStart + text.length); + } + return this; + } + +}); + +/* +--- + +script: Element.Shortcuts.js + +description: Extends the Element native object to include some shortcut methods. + +license: MIT-style license + +authors: +- Aaron Newton + +requires: +- core:1.2.4/Element.Style +- /MooTools.More + +provides: [Element.Shortcuts] + +... +*/ + +Element.implement({ + + isDisplayed: function(){ + return this.getStyle('display') != 'none'; + }, + + isVisible: function(){ + var w = this.offsetWidth, + h = this.offsetHeight; + return (w == 0 && h == 0) ? false : (w > 0 && h > 0) ? true : this.isDisplayed(); + }, + + toggle: function(){ + return this[this.isDisplayed() ? 'hide' : 'show'](); + }, + + hide: function(){ + var d; + try { + //IE fails here if the element is not in the dom + d = this.getStyle('display'); + } catch(e){} + return this.store('originalDisplay', d || '').setStyle('display', 'none'); + }, + + show: function(display){ + display = display || this.retrieve('originalDisplay') || 'block'; + return this.setStyle('display', (display == 'none') ? 'block' : display); + }, + + swapClass: function(remove, add){ + return this.removeClass(remove).addClass(add); + } + +}); + + +/* +--- + +script: Form.Validator.js + +description: A css-class based form validation system. + +license: MIT-style license + +authors: +- Aaron Newton + +requires: +- core:1.2.4/Options +- core:1.2.4/Events +- core:1.2.4/Selectors +- core:1.2.4/Element.Event +- core:1.2.4/Element.Style +- core:1.2.4/JSON +- /Lang- /Class.Binds +- /Date Element.Forms +- /Form.Validator.English +- /Element.Shortcuts + +provides: [Form.Validator, InputValidator, FormValidator.BaseValidators] + +... +*/ +if (!window.Form) window.Form = {}; + +var InputValidator = new Class({ + + Implements: [Options], + + options: { + errorMsg: 'Validation failed.', + test: function(field){return true;} + }, + + initialize: function(className, options){ + this.setOptions(options); + this.className = className; + }, + + test: function(field, props){ + if (document.id(field)) return this.options.test(document.id(field), props||this.getProps(field)); + else return false; + }, + + getError: function(field, props){ + var err = this.options.errorMsg; + if ($type(err) == 'function') err = err(document.id(field), props||this.getProps(field)); + return err; + }, + + getProps: function(field){ + if (!document.id(field)) return {}; + return field.get('validatorProps'); + } + +}); + +Element.Properties.validatorProps = { + + set: function(props){ + return this.eliminate('validatorProps').store('validatorProps', props); + }, + + get: function(props){ + if (props) this.set(props); + if (this.retrieve('validatorProps')) return this.retrieve('validatorProps'); + if (this.getProperty('validatorProps')){ + try { + this.store('validatorProps', JSON.decode(this.getProperty('validatorProps'))); + }catch(e){ + return {}; + } + } else { + var vals = this.get('class').split(' ').filter(function(cls){ + return cls.test(':'); + }); + if (!vals.length){ + this.store('validatorProps', {}); + } else { + props = {}; + vals.each(function(cls){ + var split = cls.split(':'); + if (split[1]) { + try { + props[split[0]] = JSON.decode(split[1]); + } catch(e) {} + } + }); + this.store('validatorProps', props); + } + } + return this.retrieve('validatorProps'); + } + +}; + +Form.Validator = new Class({ + + Implements:[Options, Events], + + Binds: ['onSubmit'], + + options: {/* + onFormValidate: $empty(isValid, form, event), + onElementValidate: $empty(isValid, field, className, warn), + onElementPass: $empty(field), + onElementFail: $empty(field, validatorsFailed) */ + fieldSelectors: 'input, select, textarea', + ignoreHidden: true, + ignoreDisabled: true, + useTitles: false, + evaluateOnSubmit: true, + evaluateFieldsOnBlur: true, + evaluateFieldsOnChange: true, + serial: true, + stopOnFailure: true, + warningPrefix: function(){ + return Form.Validator.getMsg('warningPrefix') || 'Warning: '; + }, + errorPrefix: function(){ + return Form.Validator.getMsg('errorPrefix') || 'Error: '; + } + }, + + initialize: function(form, options){ + this.setOptions(options); + this.element = document.id(form); + this.element.store('validator', this); + this.warningPrefix = $lambda(this.options.warningPrefix)(); + this.errorPrefix = $lambda(this.options.errorPrefix)(); + if (this.options.evaluateOnSubmit) this.element.addEvent('submit', this.onSubmit); + if (this.options.evaluateFieldsOnBlur || this.options.evaluateFieldsOnChange) this.watchFields(this.getFields()); + }, + + toElement: function(){ + return this.element; + }, + + getFields: function(){ + return (this.fields = this.element.getElements(this.options.fieldSelectors)); + }, + + watchFields: function(fields){ + fields.each(function(el){ + if (this.options.evaluateFieldsOnBlur) + el.addEvent('blur', this.validationMonitor.pass([el, false], this)); + if (this.options.evaluateFieldsOnChange) + el.addEvent('change', this.validationMonitor.pass([el, true], this)); + }, this); + }, + + validationMonitor: function(){ + $clear(this.timer); + this.timer = this.validateField.delay(50, this, arguments); + }, + + onSubmit: function(event){ + if (!this.validate(event) && event) event.preventDefault(); + else this.reset(); + }, + + reset: function(){ + this.getFields().each(this.resetField, this); + return this; + }, + + validate: function(event){ + var result = this.getFields().map(function(field){ + return this.validateField(field, true); + }, this).every(function(v){ return v;}); + this.fireEvent('formValidate', [result, this.element, event]); + if (this.options.stopOnFailure && !result && event) event.preventDefault(); + return result; + }, + + validateField: function(field, force){ + if (this.paused) return true; + field = document.id(field); + var passed = !field.hasClass('validation-failed'); + var failed, warned; + if (this.options.serial && !force){ + failed = this.element.getElement('.validation-failed'); + warned = this.element.getElement('.warning'); + } + if (field && (!failed || force || field.hasClass('validation-failed') || (failed && !this.options.serial))){ + var validators = field.className.split(' ').some(function(cn){ + return this.getValidator(cn); + }, this); + var validatorsFailed = []; + field.className.split(' ').each(function(className){ + if (className && !this.test(className, field)) validatorsFailed.include(className); + }, this); + passed = validatorsFailed.length === 0; + if (validators && !field.hasClass('warnOnly')){ + if (passed){ + field.addClass('validation-passed').removeClass('validation-failed'); + this.fireEvent('elementPass', field); + } else { + field.addClass('validation-failed').removeClass('validation-passed'); + this.fireEvent('elementFail', [field, validatorsFailed]); + } + } + if (!warned){ + var warnings = field.className.split(' ').some(function(cn){ + if (cn.test('^warn-') || field.hasClass('warnOnly')) + return this.getValidator(cn.replace(/^warn-/,'')); + else return null; + }, this); + field.removeClass('warning'); + var warnResult = field.className.split(' ').map(function(cn){ + if (cn.test('^warn-') || field.hasClass('warnOnly')) + return this.test(cn.replace(/^warn-/,''), field, true); + else return null; + }, this); + } + } + return passed; + }, + + test: function(className, field, warn){ + field = document.id(field); + if((this.options.ignoreHidden && !field.isVisible()) || (this.options.ignoreDisabled && field.get('disabled'))) return true; + var validator = this.getValidator(className); + if (field.hasClass('ignoreValidation')) return true; + warn = $pick(warn, false); + if (field.hasClass('warnOnly')) warn = true; + var isValid = validator ? validator.test(field) : true; + if (validator && field.isVisible()) this.fireEvent('elementValidate', [isValid, field, className, warn]); + if (warn) return true; + return isValid; + }, + + resetField: function(field){ + field = document.id(field); + if (field){ + field.className.split(' ').each(function(className){ + if (className.test('^warn-')) className = className.replace(/^warn-/, ''); + field.removeClass('validation-failed'); + field.removeClass('warning'); + field.removeClass('validation-passed'); + }, this); + } + return this; + }, + + stop: function(){ + this.paused = true; + return this; + }, + + start: function(){ + this.paused = false; + return this; + }, + + ignoreField: function(field, warn){ + field = document.id(field); + if (field){ + this.enforceField(field); + if (warn) field.addClass('warnOnly'); + else field.addClass('ignoreValidation'); + } + return this; + }, + + enforceField: function(field){ + field = document.id(field); + if (field) field.removeClass('warnOnly').removeClass('ignoreValidation'); + return this; + } + +}); + +Form.Validator.getMsg = function(key){ + return MooTools.lang.get('Form.Validator', key); +}; + +Form.Validator.adders = { + + validators:{}, + + add : function(className, options){ + this.validators[className] = new InputValidator(className, options); + //if this is a class (this method is used by instances of Form.Validator and the Form.Validator namespace) + //extend these validators into it + //this allows validators to be global and/or per instance + if (!this.initialize){ + this.implement({ + validators: this.validators + }); + } + }, + + addAllThese : function(validators){ + $A(validators).each(function(validator){ + this.add(validator[0], validator[1]); + }, this); + }, + + getValidator: function(className){ + return this.validators[className.split(':')[0]]; + } + +}; + +$extend(Form.Validator, Form.Validator.adders); + +Form.Validator.implement(Form.Validator.adders); + +Form.Validator.add('IsEmpty', { + + errorMsg: false, + test: function(element){ + if (element.type == 'select-one' || element.type == 'select') + return !(element.selectedIndex >= 0 && element.options[element.selectedIndex].value != ''); + else + return ((element.get('value') == null) || (element.get('value').length == 0)); + } + +}); + +Form.Validator.addAllThese([ + + ['required', { + errorMsg: function(){ + return Form.Validator.getMsg('required'); + }, + test: function(element){ + return !Form.Validator.getValidator('IsEmpty').test(element); + } + }], + + ['minLength', { + errorMsg: function(element, props){ + if ($type(props.minLength)) + return Form.Validator.getMsg('minLength').substitute({minLength:props.minLength,length:element.get('value').length }); + else return ''; + }, + test: function(element, props){ + if ($type(props.minLength)) return (element.get('value').length >= $pick(props.minLength, 0)); + else return true; + } + }], + + ['maxLength', { + errorMsg: function(element, props){ + //props is {maxLength:10} + if ($type(props.maxLength)) + return Form.Validator.getMsg('maxLength').substitute({maxLength:props.maxLength,length:element.get('value').length }); + else return ''; + }, + test: function(element, props){ + //if the value is <= than the maxLength value, element passes test + return (element.get('value').length <= $pick(props.maxLength, 10000)); + } + }], + + ['validate-integer', { + errorMsg: Form.Validator.getMsg.pass('integer'), + test: function(element){ + return Form.Validator.getValidator('IsEmpty').test(element) || (/^(-?[1-9]\d*|0)$/).test(element.get('value')); + } + }], + + ['validate-numeric', { + errorMsg: Form.Validator.getMsg.pass('numeric'), + test: function(element){ + return Form.Validator.getValidator('IsEmpty').test(element) || + (/^-?(?:0$0(?=\d*\.)|[1-9]|0)\d*(\.\d+)?$/).test(element.get('value')); + } + }], + + ['validate-digits', { + errorMsg: Form.Validator.getMsg.pass('digits'), + test: function(element){ + return Form.Validator.getValidator('IsEmpty').test(element) || (/^[\d() .:\-\+#]+$/.test(element.get('value'))); + } + }], + + ['validate-alpha', { + errorMsg: Form.Validator.getMsg.pass('alpha'), + test: function(element){ + return Form.Validator.getValidator('IsEmpty').test(element) || (/^[a-zA-Z]+$/).test(element.get('value')); + } + }], + + ['validate-alphanum', { + errorMsg: Form.Validator.getMsg.pass('alphanum'), + test: function(element){ + return Form.Validator.getValidator('IsEmpty').test(element) || !(/\W/).test(element.get('value')); + } + }], + + ['validate-date', { + errorMsg: function(element, props){ + if (Date.parse){ + var format = props.dateFormat || '%x'; + return Form.Validator.getMsg('dateSuchAs').substitute({date: new Date().format(format)}); + } else { + return Form.Validator.getMsg('dateInFormatMDY'); + } + }, + test: function(element, props){ + if (Form.Validator.getValidator('IsEmpty').test(element)) return true; + var d; + if (Date.parse){ + var format = props.dateFormat || '%x'; + d = Date.parse(element.get('value')); + var formatted = d.format(format); + if (formatted != 'invalid date') element.set('value', formatted); + return !isNaN(d); + } else { + var regex = /^(\d{2})\/(\d{2})\/(\d{4})$/; + if (!regex.test(element.get('value'))) return false; + d = new Date(element.get('value').replace(regex, '$1/$2/$3')); + return (parseInt(RegExp.$1, 10) == (1 + d.getMonth())) && + (parseInt(RegExp.$2, 10) == d.getDate()) && + (parseInt(RegExp.$3, 10) == d.getFullYear()); + } + } + }], + + ['validate-email', { + errorMsg: Form.Validator.getMsg.pass('email'), + test: function(element){ + return Form.Validator.getValidator('IsEmpty').test(element) || (/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i).test(element.get('value')); + } + }], + + ['validate-url', { + errorMsg: Form.Validator.getMsg.pass('url'), + test: function(element){ + return Form.Validator.getValidator('IsEmpty').test(element) || (/^(https?|ftp|rmtp|mms):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)(:(\d+))?\/?/i).test(element.get('value')); + } + }], + + ['validate-currency-dollar', { + errorMsg: Form.Validator.getMsg.pass('currencyDollar'), + test: function(element){ + // [$]1[##][,###]+[.##] + // [$]1###+[.##] + // [$]0.## + // [$].## + return Form.Validator.getValidator('IsEmpty').test(element) || (/^\$?\-?([1-9]{1}[0-9]{0,2}(\,[0-9]{3})*(\.[0-9]{0,2})?|[1-9]{1}\d*(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|(\.[0-9]{1,2})?)$/).test(element.get('value')); + } + }], + + ['validate-one-required', { + errorMsg: Form.Validator.getMsg.pass('oneRequired'), + test: function(element, props){ + var p = document.id(props['validate-one-required']) || element.getParent(); + return p.getElements('input').some(function(el){ + if (['checkbox', 'radio'].contains(el.get('type'))) return el.get('checked'); + return el.get('value'); + }); + } + }] + +]); + +Element.Properties.validator = { + + set: function(options){ + var validator = this.retrieve('validator'); + if (validator) validator.setOptions(options); + return this.store('validator:options'); + }, + + get: function(options){ + if (options || !this.retrieve('validator')){ + if (options || !this.retrieve('validator:options')) this.set('validator', options); + this.store('validator', new Form.Validator(this, this.retrieve('validator:options'))); + } + return this.retrieve('validator'); + } + +}; + +Element.implement({ + + validate: function(options){ + this.set('validator', options); + return this.get('validator', options).validate(); + } + +}); +//legacy +var FormValidator = Form.Validator; + +/* +--- + +script: Fx.Scroll.js + +description: Effect to smoothly scroll any element, including the window. + +license: MIT-style license + +authors: +- Valerio Proietti + +requires: +- core:1.2.4/Fx +- core:1.2.4/Element.Event +- core:1.2.4/Element.Dimensions +- /MooTools.More + +provides: [Fx.Scroll] + +... +*/ + +Fx.Scroll = new Class({ + + Extends: Fx, + + options: { + offset: {x: 0, y: 0}, + wheelStops: true + }, + + initialize: function(element, options){ + this.element = this.subject = document.id(element); + this.parent(options); + var cancel = this.cancel.bind(this, false); + + if ($type(this.element) != 'element') this.element = document.id(this.element.getDocument().body); + + var stopper = this.element; + + if (this.options.wheelStops){ + this.addEvent('start', function(){ + stopper.addEvent('mousewheel', cancel); + }, true); + this.addEvent('complete', function(){ + stopper.removeEvent('mousewheel', cancel); + }, true); + } + }, + + set: function(){ + var now = Array.flatten(arguments); + if (Browser.Engine.gecko) now = [Math.round(now[0]), Math.round(now[1])]; + this.element.scrollTo(now[0], now[1]); + }, + + compute: function(from, to, delta){ + return [0, 1].map(function(i){ + return Fx.compute(from[i], to[i], delta); + }); + }, + + start: function(x, y){ + if (!this.check(x, y)) return this; + var scrollSize = this.element.getScrollSize(), + scroll = this.element.getScroll(), + values = {x: x, y: y}; + for (var z in values){ + var max = scrollSize[z]; + if ($chk(values[z])) values[z] = ($type(values[z]) == 'number') ? values[z] : max; + else values[z] = scroll[z]; + values[z] += this.options.offset[z]; + } + return this.parent([scroll.x, scroll.y], [values.x, values.y]); + }, + + toTop: function(){ + return this.start(false, 0); + }, + + toLeft: function(){ + return this.start(0, false); + }, + + toRight: function(){ + return this.start('right', false); + }, + + toBottom: function(){ + return this.start(false, 'bottom'); + }, + + toElement: function(el){ + var position = document.id(el).getPosition(this.element); + return this.start(position.x, position.y); + }, + + scrollIntoView: function(el, axes, offset){ + axes = axes ? $splat(axes) : ['x','y']; + var to = {}; + el = document.id(el); + var pos = el.getPosition(this.element); + var size = el.getSize(); + var scroll = this.element.getScroll(); + var containerSize = this.element.getSize(); + var edge = { + x: pos.x + size.x, + y: pos.y + size.y + }; + ['x','y'].each(function(axis) { + if (axes.contains(axis)) { + if (edge[axis] > scroll[axis] + containerSize[axis]) to[axis] = edge[axis] - containerSize[axis]; + if (pos[axis] < scroll[axis]) to[axis] = pos[axis]; + } + if (to[axis] == null) to[axis] = scroll[axis]; + if (offset && offset[axis]) to[axis] = to[axis] + offset[axis]; + }, this); + if (to.x != scroll.x || to.y != scroll.y) this.start(to.x, to.y); + return this; + }, + + scrollToCenter: function(el, axes, offset){ + axes = axes ? $splat(axes) : ['x', 'y']; + el = $(el); + var to = {}, + pos = el.getPosition(this.element), + size = el.getSize(), + scroll = this.element.getScroll(), + containerSize = this.element.getSize(), + edge = { + x: pos.x + size.x, + y: pos.y + size.y + }; + + ['x','y'].each(function(axis){ + if(axes.contains(axis)){ + to[axis] = pos[axis] - (containerSize[axis] - size[axis])/2; + } + if(to[axis] == null) to[axis] = scroll[axis]; + if(offset && offset[axis]) to[axis] = to[axis] + offset[axis]; + }, this); + if (to.x != scroll.x || to.y != scroll.y) this.start(to.x, to.y); + return this; + } + +}); + + +/* +--- + +script: Fx.Slide.js + +description: Effect to slide an element in and out of view. + +license: MIT-style license + +authors: +- Valerio Proietti + +requires: +- core:1.2.4/Fx Element.Style +- /MooTools.More + +provides: [Fx.Slide] + +... +*/ + +Fx.Slide = new Class({ + + Extends: Fx, + + options: { + mode: 'vertical', + wrapper: false, + hideOverflow: true + }, + + initialize: function(element, options){ + this.addEvent('complete', function(){ + this.open = (this.wrapper['offset' + this.layout.capitalize()] != 0); + if (this.open) this.wrapper.setStyle('height', ''); + if (this.open && Browser.Engine.webkit419) this.element.dispose().inject(this.wrapper); + }, true); + this.element = this.subject = document.id(element); + this.parent(options); + var wrapper = this.element.retrieve('wrapper'); + var styles = this.element.getStyles('margin', 'position', 'overflow'); + if (this.options.hideOverflow) styles = $extend(styles, {overflow: 'hidden'}); + if (this.options.wrapper) wrapper = document.id(this.options.wrapper).setStyles(styles); + this.wrapper = wrapper || new Element('div', { + styles: styles + }).wraps(this.element); + this.element.store('wrapper', this.wrapper).setStyle('margin', 0); + this.now = []; + this.open = true; + }, + + vertical: function(){ + this.margin = 'margin-top'; + this.layout = 'height'; + this.offset = this.element.offsetHeight; + }, + + horizontal: function(){ + this.margin = 'margin-left'; + this.layout = 'width'; + this.offset = this.element.offsetWidth; + }, + + set: function(now){ + this.element.setStyle(this.margin, now[0]); + this.wrapper.setStyle(this.layout, now[1]); + return this; + }, + + compute: function(from, to, delta){ + return [0, 1].map(function(i){ + return Fx.compute(from[i], to[i], delta); + }); + }, + + start: function(how, mode){ + if (!this.check(how, mode)) return this; + this[mode || this.options.mode](); + var margin = this.element.getStyle(this.margin).toInt(); + var layout = this.wrapper.getStyle(this.layout).toInt(); + var caseIn = [[margin, layout], [0, this.offset]]; + var caseOut = [[margin, layout], [-this.offset, 0]]; + var start; + switch (how){ + case 'in': start = caseIn; break; + case 'out': start = caseOut; break; + case 'toggle': start = (layout == 0) ? caseIn : caseOut; + } + return this.parent(start[0], start[1]); + }, + + slideIn: function(mode){ + return this.start('in', mode); + }, + + slideOut: function(mode){ + return this.start('out', mode); + }, + + hide: function(mode){ + this[mode || this.options.mode](); + this.open = false; + return this.set([-this.offset, 0]); + }, + + show: function(mode){ + this[mode || this.options.mode](); + this.open = true; + return this.set([0, this.offset]); + }, + + toggle: function(mode){ + return this.start('toggle', mode); + } + +}); + +Element.Properties.slide = { + + set: function(options){ + var slide = this.retrieve('slide'); + if (slide) slide.cancel(); + return this.eliminate('slide').store('slide:options', $extend({link: 'cancel'}, options)); + }, + + get: function(options){ + if (options || !this.retrieve('slide')){ + if (options || !this.retrieve('slide:options')) this.set('slide', options); + this.store('slide', new Fx.Slide(this, this.retrieve('slide:options'))); + } + return this.retrieve('slide'); + } + +}; + +Element.implement({ + + slide: function(how, mode){ + how = how || 'toggle'; + var slide = this.get('slide'), toggle; + switch (how){ + case 'hide': slide.hide(mode); break; + case 'show': slide.show(mode); break; + case 'toggle': + var flag = this.retrieve('slide:flag', slide.open); + slide[flag ? 'slideOut' : 'slideIn'](mode); + this.store('slide:flag', !flag); + toggle = true; + break; + default: slide.start(how, mode); + } + if (!toggle) this.eliminate('slide:flag'); + return this; + } + +}); + + +/* +--- + +script: Fx.SmoothScroll.js + +description: Class for creating a smooth scrolling effect to all internal links on the page. + +license: MIT-style license + +authors: +- Valerio Proietti + +requires: +- core:1.2.4/Selectors +- /Fx.Scroll + +provides: [Fx.SmoothScroll] + +... +*/ + +var SmoothScroll = Fx.SmoothScroll = new Class({ + + Extends: Fx.Scroll, + + initialize: function(options, context){ + context = context || document; + this.doc = context.getDocument(); + var win = context.getWindow(); + this.parent(this.doc, options); + this.links = $$(this.options.links || this.doc.links); + var location = win.location.href.match(/^[^#]*/)[0] + '#'; + this.links.each(function(link){ + if (link.href.indexOf(location) != 0) {return;} + var anchor = link.href.substr(location.length); + if (anchor) this.useLink(link, anchor); + }, this); + if (!Browser.Engine.webkit419) { + this.addEvent('complete', function(){ + win.location.hash = this.anchor; + }, true); + } + }, + + useLink: function(link, anchor){ + var el; + link.addEvent('click', function(event){ + if (el !== false && !el) el = document.id(anchor) || this.doc.getElement('a[name=' + anchor + ']'); + if (el) { + event.preventDefault(); + this.anchor = anchor; + this.toElement(el).chain(function(){ + this.fireEvent('scrolledTo', [link, el]); + }.bind(this)); + link.blur(); + } + }.bind(this)); + } +}); + +/* +--- + +script: Tips.js + +description: Class for creating nice tips that follow the mouse cursor when hovering an element. + +license: MIT-style license + +authors: +- Valerio Proietti +- Christoph Pojer + +requires: +- core:1.2.4/Options +- core:1.2.4/Events +- core:1.2.4/Element.Event +- core:1.2.4/Element.Style +- core:1.2.4/Element.Dimensions +- /MooTools.More + +provides: [Tips] + +... +*/ + +(function(){ + +var read = function(option, element){ + return (option) ? ($type(option) == 'function' ? option(element) : element.get(option)) : ''; +}; + +this.Tips = new Class({ + + Implements: [Events, Options], + + options: { + /* + onAttach: $empty(element), + onDetach: $empty(element), + */ + onShow: function(){ + this.tip.setStyle('display', 'block'); + }, + onHide: function(){ + this.tip.setStyle('display', 'none'); + }, + title: 'title', + text: function(element){ + return element.get('rel') || element.get('href'); + }, + showDelay: 100, + hideDelay: 100, + className: 'tip-wrap', + offset: {x: 16, y: 16}, + windowPadding: {x:0, y:0}, + fixed: false + }, + + initialize: function(){ + var params = Array.link(arguments, {options: Object.type, elements: $defined}); + this.setOptions(params.options); + if (params.elements) this.attach(params.elements); + this.container = new Element('div', {'class': 'tip'}); + }, + + toElement: function(){ + if (this.tip) return this.tip; + + return this.tip = new Element('div', { + 'class': this.options.className, + styles: { + position: 'absolute', + top: 0, + left: 0 + } + }).adopt( + new Element('div', {'class': 'tip-top'}), + this.container, + new Element('div', {'class': 'tip-bottom'}) + ).inject(document.body); + }, + + attach: function(elements){ + $$(elements).each(function(element){ + var title = read(this.options.title, element), + text = read(this.options.text, element); + + element.erase('title').store('tip:native', title).retrieve('tip:title', title); + element.retrieve('tip:text', text); + this.fireEvent('attach', [element]); + + var events = ['enter', 'leave']; + if (!this.options.fixed) events.push('move'); + + events.each(function(value){ + var event = element.retrieve('tip:' + value); + if (!event) event = this['element' + value.capitalize()].bindWithEvent(this, element); + + element.store('tip:' + value, event).addEvent('mouse' + value, event); + }, this); + }, this); + + return this; + }, + + detach: function(elements){ + $$(elements).each(function(element){ + ['enter', 'leave', 'move'].each(function(value){ + element.removeEvent('mouse' + value, element.retrieve('tip:' + value)).eliminate('tip:' + value); + }); + + this.fireEvent('detach', [element]); + + if (this.options.title == 'title'){ // This is necessary to check if we can revert the title + var original = element.retrieve('tip:native'); + if (original) element.set('title', original); + } + }, this); + + return this; + }, + + elementEnter: function(event, element){ + this.container.empty(); + + ['title', 'text'].each(function(value){ + var content = element.retrieve('tip:' + value); + if (content) this.fill(new Element('div', {'class': 'tip-' + value}).inject(this.container), content); + }, this); + + $clear(this.timer); + this.timer = (function(){ + this.show(this, element); + this.position((this.options.fixed) ? {page: element.getPosition()} : event); + }).delay(this.options.showDelay, this); + }, + + elementLeave: function(event, element){ + $clear(this.timer); + this.timer = this.hide.delay(this.options.hideDelay, this, element); + this.fireForParent(event, element); + }, + + fireForParent: function(event, element){ + element = element.getParent(); + if (!element || element == document.body) return; + if (element.retrieve('tip:enter')) element.fireEvent('mouseenter', event); + else this.fireForParent(event, element); + }, + + elementMove: function(event, element){ + this.position(event); + }, + + position: function(event){ + if (!this.tip) document.id(this); + + var size = window.getSize(), scroll = window.getScroll(), + tip = {x: this.tip.offsetWidth, y: this.tip.offsetHeight}, + props = {x: 'left', y: 'top'}, + obj = {}; + + for (var z in props){ + obj[props[z]] = event.page[z] + this.options.offset[z]; + if ((obj[props[z]] + tip[z] - scroll[z]) > size[z] - this.options.windowPadding[z]) obj[props[z]] = event.page[z] - this.options.offset[z] - tip[z]; + } + + this.tip.setStyles(obj); + }, + + fill: function(element, contents){ + if(typeof contents == 'string') element.set('html', contents); + else element.adopt(contents); + }, + + show: function(element){ + if (!this.tip) document.id(this); + this.fireEvent('show', [this.tip, element]); + }, + + hide: function(element){ + if (!this.tip) document.id(this); + this.fireEvent('hide', [this.tip, element]); + } + +}); + +})(); + +/* +--- + +script: Date.English.US.js + +description: Date messages for US English. + +license: MIT-style license + +authors: +- Aaron Newton + +requires: +- /Lang +- /Date + +provides: [Date.English.US] + +... +*/ + +MooTools.lang.set('en-US', 'Date', { + + months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], + //culture's date order: MM/DD/YYYY + dateOrder: ['month', 'date', 'year'], + shortDate: '%m/%d/%Y', + shortTime: '%I:%M%p', + AM: 'AM', + PM: 'PM', + + /* Date.Extras */ + ordinal: function(dayOfMonth){ + //1st, 2nd, 3rd, etc. + return (dayOfMonth > 3 && dayOfMonth < 21) ? 'th' : ['th', 'st', 'nd', 'rd', 'th'][Math.min(dayOfMonth % 10, 4)]; + }, + + lessThanMinuteAgo: 'less than a minute ago', + minuteAgo: 'about a minute ago', + minutesAgo: '{delta} minutes ago', + hourAgo: 'about an hour ago', + hoursAgo: 'about {delta} hours ago', + dayAgo: '1 day ago', + daysAgo: '{delta} days ago', + weekAgo: '1 week ago', + weeksAgo: '{delta} weeks ago', + monthAgo: '1 month ago', + monthsAgo: '{delta} months ago', + yearAgo: '1 year ago', + yearsAgo: '{delta} years ago', + lessThanMinuteUntil: 'less than a minute from now', + minuteUntil: 'about a minute from now', + minutesUntil: '{delta} minutes from now', + hourUntil: 'about an hour from now', + hoursUntil: 'about {delta} hours from now', + dayUntil: '1 day from now', + daysUntil: '{delta} days from now', + weekUntil: '1 week from now', + weeksUntil: '{delta} weeks from now', + monthUntil: '1 month from now', + monthsUntil: '{delta} months from now', + yearUntil: '1 year from now', + yearsUntil: '{delta} years from now' + +}); + + +/* +--- + +script: Form.Validator.English.js + +description: Form Validator messages for English. + +license: MIT-style license + +authors: +- Aaron Newton + +requires: +- /Lang +- /Form.Validator + +provides: [Form.Validator.English] + +... +*/ + +MooTools.lang.set('en-US', 'Form.Validator', { + + required:'This field is required.', + minLength:'Please enter at least {minLength} characters (you entered {length} characters).', + maxLength:'Please enter no more than {maxLength} characters (you entered {length} characters).', + integer:'Please enter an integer in this field. Numbers with decimals (e.g. 1.25) are not permitted.', + numeric:'Please enter only numeric values in this field (i.e. "1" or "1.1" or "-1" or "-1.1").', + digits:'Please use numbers and punctuation only in this field (for example, a phone number with dashes or dots is permitted).', + alpha:'Please use letters only (a-z) with in this field. No spaces or other characters are allowed.', + alphanum:'Please use only letters (a-z) or numbers (0-9) only in this field. No spaces or other characters are allowed.', + dateSuchAs:'Please enter a valid date such as {date}', + dateInFormatMDY:'Please enter a valid date such as MM/DD/YYYY (i.e. "12/31/1999")', + email:'Please enter a valid email address. For example "fred@domain.com".', + url:'Please enter a valid URL such as http://www.google.com.', + currencyDollar:'Please enter a valid $ amount. For example $100.00 .', + oneRequired:'Please enter something for at least one of these inputs.', + errorPrefix: 'Error: ', + warningPrefix: 'Warning: ', + + //Form.Validator.Extras + + noSpace: 'There can be no spaces in this input.', + reqChkByNode: 'No items are selected.', + requiredChk: 'This field is required.', + reqChkByName: 'Please select a {label}.', + match: 'This field needs to match the {matchName} field', + startDate: 'the start date', + endDate: 'the end date', + currendDate: 'the current date', + afterDate: 'The date should be the same or after {label}.', + beforeDate: 'The date should be the same or before {label}.', + startMonth: 'Please select a start month', + sameMonth: 'These two dates must be in the same month - you must change one or the other.', + creditcard: 'The credit card number entered is invalid. Please check the number and try again. {length} digits entered.' + +});
Received on Monday, 30 August 2010 16:49:05 UTC