Created
February 26, 2009 10:06
-
-
Save saimonmoore/70775 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| commit 2d361c7a7086db581e5b28fe52adf264491b0445 | |
| Author: Saimon Moore <[email protected]> | |
| Date: Thu Feb 26 11:02:56 2009 +0100 | |
| Adding failing spec for custom mootools events | |
| diff --git a/spec/custom_events_spec.rb b/spec/custom_events_spec.rb | |
| new file mode 100644 | |
| index 0000000..df76140 | |
| --- /dev/null | |
| +++ b/spec/custom_events_spec.rb | |
| @@ -0,0 +1,112 @@ | |
| +require File.dirname(__FILE__) + '/spec_helper.rb' | |
| + | |
| +describe "Mootools Custom Events" do | |
| + | |
| + before :all do | |
| + @browser = Browser.new(:browser => :firefox, :resynchronize => false, :css => false, :log_level => :off, :javascript_exceptions => true) | |
| + end | |
| + | |
| + before :each do | |
| + @browser.goto(HTML_DIR + "/custom_events.html") | |
| + @browser.wait | |
| + @link1 = @browser.link(:id, 'link1'); | |
| + @link1.should_not be_nil | |
| + | |
| + @link2 = @browser.link(:id, 'link2'); | |
| + @link2.should_not be_nil | |
| + | |
| + @link3 = @browser.link(:id, 'link3'); | |
| + @link3.should_not be_nil | |
| + | |
| + @link4 = @browser.link(:id, 'link4'); | |
| + @link4.should_not be_nil | |
| + | |
| + @link5 = @browser.link(:id, 'link5'); | |
| + @link5.should_not be_nil | |
| + | |
| + @link6 = @browser.link(:id, 'link6'); | |
| + @link6.should_not be_nil | |
| + end | |
| + | |
| + describe "on dom loaded event" do | |
| + it "should be logged" do | |
| + @log = @browser.ul(:id, 'log'); | |
| + @log.lis.any? {|li| li.text.include?('inited') }.should be_true | |
| + end | |
| + end | |
| + | |
| + describe "click event with onlick attribute" do | |
| + it "should trigger click event" do | |
| + @link3.click | |
| + @log = @browser.ul(:id, 'log'); | |
| + @log.lis.any? {|li| li.text.include?('click link: link3') }.should be_true | |
| + end | |
| + end | |
| + | |
| + describe "click event with addEvent via delegation" do | |
| + it "should trigger click event" do | |
| + @link5.click | |
| + @log = @browser.ul(:id, 'log'); | |
| + @log.lis.any? {|li| li.text.include?('click link: link5') }.should be_true | |
| + end | |
| + end | |
| + | |
| + describe "click event with addEvent" do | |
| + it "should trigger click event" do | |
| + @link4.click | |
| + @log = @browser.ul(:id, 'log'); | |
| + @log.lis.any? {|li| li.text.include?('click link: link4') }.should be_true | |
| + end | |
| + end | |
| + | |
| + describe "click event with addEvents" do | |
| + it "should trigger click event" do | |
| + @link1.click | |
| + @log = @browser.ul(:id, 'log'); | |
| + @log.lis.any? {|li| li.text.include?('click link: link1') }.should be_true | |
| + end | |
| + | |
| + it "should trigger click once event (via addEvents)" do | |
| + @link1.click | |
| + @log = @browser.ul(:id, 'log'); | |
| + @log.lis.any? {|li| li.text.include?('click link: link1') }.should be_true | |
| + @log.lis.any? {|li| li.text.include?('click once link: link1') }.should be_true | |
| + end | |
| + | |
| + it "should trigger click twice event (via addEvents)" do | |
| + @link1.double_click | |
| + @log = @browser.ul(:id, 'log'); | |
| + @log.lis.any? {|li| li.text.include?('dblclick link: link1') }.should be_true | |
| + @log.lis.any? {|li| li.text.include?('click twice link: link1') }.should be_true | |
| + end | |
| + | |
| + it "should trigger dblclick event (via addEvents)" do | |
| + @link1.double_click | |
| + @log = @browser.ul(:id, 'log'); | |
| + @log.lis.any? {|li| li.text.include?('dblclick link: link1') }.should be_true | |
| + end | |
| + | |
| + it "should trigger click event on dblclick event (via addEvents)" do | |
| + @link1.double_click | |
| + @log = @browser.ul(:id, 'log'); | |
| + @log.lis.any? {|li| li.text.include?('click link: link1') }.should be_true | |
| + end | |
| + | |
| + it "should trigger dblclick event (via addEvent)" do | |
| + @link4.double_click | |
| + @log = @browser.ul(:id, 'log'); | |
| + @log.lis.any? {|li| li.text.include?('dblclick link: link4') }.should be_true | |
| + end | |
| + | |
| + it "should trigger dblclick event (via addEvent with delegation)" do | |
| + @link5.double_click | |
| + @log = @browser.ul(:id, 'log'); | |
| + @log.lis.any? {|li| li.text.include?('dblclick link: link5') }.should be_true | |
| + end | |
| + end | |
| + | |
| + after :all do | |
| + @browser.close | |
| + end | |
| + | |
| +end | |
| diff --git a/spec/html/custom_events.html b/spec/html/custom_events.html | |
| new file mode 100644 | |
| index 0000000..22945b8 | |
| --- /dev/null | |
| +++ b/spec/html/custom_events.html | |
| @@ -0,0 +1,126 @@ | |
| +<html> | |
| + <head> | |
| + <meta http-equiv="Content-type" content="text/html; charset=utf-8"> | |
| + <title>Custom Event Test</title> | |
| + <script type="text/javascript" charset="utf-8" src="mootools-1.2-core.js"></script> | |
| + <script type="text/javascript" charset="utf-8"> | |
| + Element.Events.extend({ | |
| + clickonce: { | |
| + base: 'click', | |
| + condition: function(event){ | |
| + $clear(this.clickDelay); | |
| + this.clickDelay = this.fireEvent.delay(250, this, ['clickonce', event]); | |
| + return false; | |
| + } | |
| + }, | |
| + | |
| + clicktwice: { | |
| + base: 'dblclick', | |
| + condition: function(){ | |
| + $clear(this.clickDelay); | |
| + return true; | |
| + } | |
| + } | |
| + }); | |
| + | |
| + var log = function(msg) { | |
| + var li = new Element('li', {'class': 'log', 'text': msg}); | |
| + li.inject($('log'), 'bottom'); | |
| + }; | |
| + var CustomEventTest = { | |
| + init: function(){ | |
| + log('inited'); | |
| + $$('a.clickable').each(function(link) { | |
| + link.addEvents({ | |
| + 'click': function(e) { | |
| + log('click link: ' + e.target.id); | |
| + e.stop(); | |
| + return false; | |
| + }, | |
| + 'clickonce': function(e) { | |
| + log('click once link: ' + e.target.id); | |
| + e.stop(); | |
| + return false; | |
| + }, | |
| + 'clicktwice': function(e) { | |
| + log('click twice link: ' + e.target.id); | |
| + e.stop(); | |
| + return false; | |
| + }, | |
| + 'dblclick': function(e) { | |
| + log('dblclick link: ' + e.target.id); | |
| + e.stop(); | |
| + return false; | |
| + } | |
| + }) | |
| + }); | |
| + | |
| + $('link4').addEvent('click', function(e) { | |
| + log('click link: ' + e.target.id); | |
| + e.stop(); | |
| + return false; | |
| + }); | |
| + | |
| + $('link4').addEvent('dblclick', function(e) { | |
| + log('dblclick link: ' + e.target.id); | |
| + e.stop(); | |
| + return false; | |
| + }); | |
| + | |
| + $('list2').addEvents({ | |
| + 'click': function(e) { | |
| + e.stop(); | |
| + if ($(e.target.id).hasClass('delegate')) { | |
| + log('click link: ' + e.target.id); | |
| + return false; | |
| + }; | |
| + | |
| + return true; | |
| + }, | |
| + 'clickonce': function(e) { | |
| + e.stop(); | |
| + if ($(e.target.id).hasClass('delegate')) { | |
| + log('click once link: ' + e.target.id); | |
| + return false; | |
| + }; | |
| + | |
| + return true; | |
| + }, | |
| + 'clicktwice': function(e) { | |
| + if ($(e.target.id).hasClass('delegate')) { | |
| + log('click twice link: ' + e.target.id); | |
| + return false; | |
| + }; | |
| + }, | |
| + 'dblclick': function(e) { | |
| + e.stop(); | |
| + if ($(e.target.id).hasClass('delegate')) { | |
| + log('dblclick link: ' + e.target.id); | |
| + return false; | |
| + }; | |
| + return true; | |
| + } | |
| + }); | |
| + } | |
| + }; | |
| + | |
| + window.addEvents({ | |
| + domready: CustomEventTest.init | |
| + }); | |
| + </script> | |
| + </head> | |
| + <body> | |
| + <ul id="list1"> | |
| + <li><a class="clickable" id="link1" href="custom_events.html">Click 1</a></li> | |
| + <li><a class="clickable" id="link2" href="custom_events.html">Click 2</a></li> | |
| + </ul> | |
| + <a id="link3" href="custom_events.html" onclick="log('click link: link3');return false;" >Click 3</a> | |
| + <a id="link4" href="custom_events.html" >Click 4</a> | |
| + | |
| + <ul id="list2"> | |
| + <li><a class="delegate" id="link5" href="custom_events.html">Click 5</a></li> | |
| + <li><a class="delegate" id="link6" href="custom_events.html">Click 6</a></li> | |
| + </ul> | |
| + <ul id="log"></ul> | |
| + </body> | |
| +</html> | |
| \ No newline at end of file | |
| diff --git a/spec/html/mootools-1.2-core.js b/spec/html/mootools-1.2-core.js | |
| new file mode 100644 | |
| index 0000000..b120ec5 | |
| --- /dev/null | |
| +++ b/spec/html/mootools-1.2-core.js | |
| @@ -0,0 +1,3816 @@ | |
| +/* | |
| +Script: Core.js | |
| + MooTools - My Object Oriented JavaScript Tools. | |
| + | |
| +License: | |
| + MIT-style license. | |
| + | |
| +Copyright: | |
| + Copyright (c) 2006-2007 [Valerio Proietti](http://mad4milk.net/). | |
| + | |
| +Code & Documentation: | |
| + [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) | |
| +*/ | |
| + | |
| +var MooTools = { | |
| + 'version': '1.2.0', | |
| + 'build': '' | |
| +}; | |
| + | |
| +var Native = function(options){ | |
| + options = options || {}; | |
| + | |
| + var afterImplement = options.afterImplement || function(){}; | |
| + var generics = options.generics; | |
| + generics = (generics !== false); | |
| + var legacy = options.legacy; | |
| + var initialize = options.initialize; | |
| + var protect = options.protect; | |
| + var name = options.name; | |
| + | |
| + var object = initialize || legacy; | |
| + | |
| + 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.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; | |
| + }; | |
| + | |
| + object.alias = function(a1, a2, a3){ | |
| + if (typeof a1 == 'string'){ | |
| + a1 = this.prototype[a1]; | |
| + if (a1) add(this, a2, a1, a3); | |
| + } else { | |
| + for (var a in a1) this.alias(a, a1[a], a2); | |
| + } | |
| + return this; | |
| + }; | |
| + | |
| + return object; | |
| +}; | |
| + | |
| +Native.implement = function(objects, properties){ | |
| + for (var i = 0, l = objects.length; i < l; i++) objects[i].implement(properties); | |
| +}; | |
| + | |
| +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.typize = function(object, family){ | |
| + if (!object.type) object.type = function(item){ | |
| + return ($type(item) === family); | |
| + }; | |
| +}; | |
| + | |
| +Native.alias = function(objects, a1, a2, a3){ | |
| + for (var i = 0, j = objects.length; i < j; i++) objects[i].alias(a1, a2, a3); | |
| +}; | |
| + | |
| +(function(objects){ | |
| + for (var name in objects) Native.typize(objects[name], name); | |
| +})({'boolean': Boolean, 'native': Native, 'object': Object}); | |
| + | |
| +(function(objects){ | |
| + for (var name in objects) new Native({name: name, initialize: objects[name], protect: true}); | |
| +})({'String': String, 'Function': Function, 'Number': Number, 'Array': Array, 'RegExp': RegExp, 'Date': Date}); | |
| + | |
| +(function(object, methods){ | |
| + for (var i = methods.length; i--; i) Native.genericize(object, methods[i], true); | |
| + return arguments.callee; | |
| +}) | |
| +(Array, ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice', 'toString', 'valueOf', 'indexOf', 'lastIndexOf']) | |
| +(String, ['charAt', 'charCodeAt', 'concat', 'indexOf', 'lastIndexOf', 'match', 'replace', 'search', 'slice', 'split', 'substr', 'substring', 'toLowerCase', 'toUpperCase', 'valueOf']); | |
| + | |
| +function $chk(obj){ | |
| + return !!(obj || obj === 0); | |
| +}; | |
| + | |
| +function $clear(timer){ | |
| + clearTimeout(timer); | |
| + clearInterval(timer); | |
| + return null; | |
| +}; | |
| + | |
| +function $defined(obj){ | |
| + return (obj != undefined); | |
| +}; | |
| + | |
| +function $empty(){}; | |
| + | |
| +function $arguments(i){ | |
| + return function(){ | |
| + return arguments[i]; | |
| + }; | |
| +}; | |
| + | |
| +function $lambda(value){ | |
| + return (typeof value == 'function') ? value : function(){ | |
| + return value; | |
| + }; | |
| +}; | |
| + | |
| +function $extend(original, extended){ | |
| + for (var key in (extended || {})) original[key] = extended[key]; | |
| + return original; | |
| +}; | |
| + | |
| +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 = $unlink(object.getClean()); | |
| + 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; | |
| +}; | |
| + | |
| +function $merge(){ | |
| + var mix = {}; | |
| + for (var i = 0, 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') ? $merge(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().getTime(); | |
| +}; | |
| + | |
| +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; | |
| +}; | |
| + | |
| +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({ | |
| + | |
| + getLength: function(){ | |
| + var length = 0; | |
| + for (var key in this){ | |
| + if (this.hasOwnProperty(key)) length++; | |
| + } | |
| + return length; | |
| + }, | |
| + | |
| + 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; | |
| + } | |
| + | |
| +}); | |
| + | |
| +Hash.alias('forEach', 'each'); | |
| + | |
| +function $H(object){ | |
| + return new Hash(object); | |
| +}; | |
| + | |
| +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 array = []; | |
| + for (var i = 0, l = iterable.length; i < l; i++) array[i] = iterable[i]; | |
| + return array; | |
| + } | |
| + return Array.prototype.slice.call(iterable); | |
| +}; | |
| + | |
| +function $each(iterable, fn, bind){ | |
| + var type = $type(iterable); | |
| + ((type == 'arguments' || type == 'collection' || type == 'array') ? Array : Hash).each(iterable, fn, bind); | |
| +}; | |
| + | |
| + | |
| +/* | |
| +Script: Browser.js | |
| + The Browser Core. Contains Browser initialization, Window and Document, and the Browser Hash. | |
| + | |
| +License: | |
| + MIT-style license. | |
| +*/ | |
| + | |
| +var Browser = new Hash({ | |
| + Engine: {name: 'unknown', version: ''}, | |
| + Platform: {name: (navigator.platform.match(/mac|win|linux/i) || ['other'])[0].toLowerCase()}, | |
| + Features: {xpath: !!(document.evaluate), air: !!(window.runtime)}, | |
| + Plugins: {} | |
| +}); | |
| + | |
| +if (window.opera) Browser.Engine = {name: 'presto', version: (document.getElementsByClassName) ? 950 : 925}; | |
| +else if (window.ActiveXObject) Browser.Engine = {name: 'trident', version: (window.XMLHttpRequest) ? 5 : 4}; | |
| +else if (!navigator.taintEnabled) Browser.Engine = {name: 'webkit', version: (Browser.Features.xpath) ? 420 : 419}; | |
| +else if (document.getBoxObjectFor != null) Browser.Engine = {name: 'gecko', version: (document.getElementsByClassName) ? 19 : 18}; | |
| +Browser.Engine[Browser.Engine.name] = Browser.Engine[Browser.Engine.name + Browser.Engine.version] = true; | |
| + | |
| +if (window.orientation != undefined) Browser.Platform.name = 'ipod'; | |
| + | |
| +Browser.Platform[Browser.Platform.name] = true; | |
| + | |
| +Browser.Request = function(){ | |
| + return $try(function(){ | |
| + return new XMLHttpRequest(); | |
| + }, function(){ | |
| + return new ActiveXObject('MSXML2.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] || 0), build: parseInt(version[2] || 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.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]]"] : {}; | |
| + } | |
| + 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]; | |
| + doc.window = doc.defaultView || doc.parentWindow; | |
| + if (Browser.Engine.trident4) $try(function(){ | |
| + doc.execCommand("BackgroundImageCache", false, true); | |
| + }); | |
| + 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 | |
| + Contains Array Prototypes like copy, each, contains, and remove. | |
| + | |
| +License: | |
| + MIT-style license. | |
| +*/ | |
| + | |
| +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 | |
| + Contains Function Prototypes like create, bind, pass, and delay. | |
| + | |
| +License: | |
| + MIT-style license. | |
| +*/ | |
| + | |
| +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(); | |
| + }; | |
| + }, | |
| + | |
| + pass: function(args, bind){ | |
| + return this.create({arguments: args, bind: bind}); | |
| + }, | |
| + | |
| + attempt: function(args, bind){ | |
| + return this.create({arguments: args, bind: bind, attempt: true})(); | |
| + }, | |
| + | |
| + bind: function(bind, args){ | |
| + return this.create({bind: bind, arguments: args}); | |
| + }, | |
| + | |
| + bindWithEvent: function(bind, args){ | |
| + return this.create({bind: bind, event: true, arguments: args}); | |
| + }, | |
| + | |
| + delay: function(delay, bind, args){ | |
| + return this.create({delay: delay, bind: bind, arguments: args})(); | |
| + }, | |
| + | |
| + periodical: function(interval, bind, args){ | |
| + return this.create({periodical: interval, bind: bind, arguments: args})(); | |
| + }, | |
| + | |
| + run: function(args, bind){ | |
| + return this.apply(bind, $splat(args)); | |
| + } | |
| + | |
| +}); | |
| + | |
| +/* | |
| +Script: Number.js | |
| + Contains Number Prototypes like limit, round, times, and ceil. | |
| + | |
| +License: | |
| + MIT-style license. | |
| +*/ | |
| + | |
| +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 | |
| + Contains String Prototypes like camelCase, capitalize, test, and toInt. | |
| + | |
| +License: | |
| + MIT-style license. | |
| +*/ | |
| + | |
| +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 | |
| + Contains Hash Prototypes. Provides a means for overcoming the JavaScript practical impossibility of extending native Objects. | |
| + | |
| +License: | |
| + MIT-style license. | |
| +*/ | |
| + | |
| +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){ | |
| + var k = this[key]; | |
| + if (k == 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 | |
| + Contains the Event Native, to make the event object completely crossbrowser. | |
| + | |
| +License: | |
| + MIT-style license. | |
| +*/ | |
| + | |
| +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 | |
| + Contains the Class Function for easily creating, extending, and implementing reusable Classes. | |
| + | |
| +License: | |
| + MIT-style license. | |
| +*/ | |
| + | |
| +var Class = new Native({ | |
| + | |
| + name: 'Class', | |
| + | |
| + initialize: function(properties){ | |
| + properties = properties || {}; | |
| + var klass = function(empty){ | |
| + for (var key in this) this[key] = $unlink(this[key]); | |
| + for (var mutator in Class.Mutators){ | |
| + if (!this[mutator]) continue; | |
| + Class.Mutators[mutator](this, this[mutator]); | |
| + delete this[mutator]; | |
| + } | |
| + | |
| + this.constructor = klass; | |
| + if (empty === $empty) return this; | |
| + | |
| + var self = (this.initialize) ? this.initialize.apply(this, arguments) : this; | |
| + if (this.options && this.options.initialize) this.options.initialize.call(this); | |
| + return self; | |
| + }; | |
| + | |
| + $extend(klass, this); | |
| + klass.constructor = Class; | |
| + klass.prototype = properties; | |
| + return klass; | |
| + } | |
| + | |
| +}); | |
| + | |
| +Class.implement({ | |
| + | |
| + implement: function(){ | |
| + Class.Mutators.Implements(this.prototype, Array.slice(arguments)); | |
| + return this; | |
| + } | |
| + | |
| +}); | |
| + | |
| +Class.Mutators = { | |
| + | |
| + Implements: function(self, klasses){ | |
| + $splat(klasses).each(function(klass){ | |
| + $extend(self, ($type(klass) == 'class') ? new klass($empty) : klass); | |
| + }); | |
| + }, | |
| + | |
| + Extends: function(self, klass){ | |
| + var instance = new klass($empty); | |
| + delete instance.parent; | |
| + delete instance.parentOf; | |
| + | |
| + for (var key in instance){ | |
| + var current = self[key], previous = instance[key]; | |
| + if (current == undefined){ | |
| + self[key] = previous; | |
| + continue; | |
| + } | |
| + | |
| + var ctype = $type(current), ptype = $type(previous); | |
| + if (ctype != ptype) continue; | |
| + | |
| + switch (ctype){ | |
| + case 'function': | |
| + // this code will be only executed if the current browser does not support function.caller (currently only opera). | |
| + // we replace the function code with brute force. Not pretty, but it will only be executed if function.caller is not supported. | |
| + | |
| + if (!arguments.callee.caller) self[key] = eval('(' + String(current).replace(/\bthis\.parent\(\s*(\))?/g, function(full, close){ | |
| + return 'arguments.callee._parent_.call(this' + (close || ', '); | |
| + }) + ')'); | |
| + | |
| + // end "opera" code | |
| + self[key]._parent_ = previous; | |
| + break; | |
| + case 'object': self[key] = $merge(previous, current); | |
| + } | |
| + | |
| + } | |
| + | |
| + self.parent = function(){ | |
| + return arguments.callee.caller._parent_.apply(this, arguments); | |
| + }; | |
| + | |
| + self.parentOf = function(descendant){ | |
| + return descendant._parent_.apply(this, Array.slice(arguments, 1)); | |
| + }; | |
| + } | |
| + | |
| +}; | |
| + | |
| + | |
| +/* | |
| +Script: Class.Extras.js | |
| + Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks. | |
| + | |
| +License: | |
| + MIT-style license. | |
| +*/ | |
| + | |
| +var Chain = new Class({ | |
| + | |
| + chain: function(){ | |
| + this.$chain = (this.$chain || []).extend(arguments); | |
| + return this; | |
| + }, | |
| + | |
| + callChain: function(){ | |
| + return (this.$chain && this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false; | |
| + }, | |
| + | |
| + clearChain: function(){ | |
| + if (this.$chain) this.$chain.empty(); | |
| + return this; | |
| + } | |
| + | |
| +}); | |
| + | |
| +var Events = new Class({ | |
| + | |
| + addEvent: function(type, fn, internal){ | |
| + type = Events.removeOn(type); | |
| + if (fn != $empty){ | |
| + this.$events = this.$events || {}; | |
| + 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 || !this.$events[type]) return this; | |
| + if (!fn.internal) this.$events[type].erase(fn); | |
| + return this; | |
| + }, | |
| + | |
| + removeEvents: function(type){ | |
| + for (var e in this.$events){ | |
| + if (type && type != e) continue; | |
| + var fns = this.$events[e]; | |
| + for (var i = fns.length; i--; i) this.removeEvent(e, 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 | |
| + 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. | |
| +*/ | |
| + | |
| +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 $.element(this.createElement(tag)).set(props); | |
| + }, | |
| + | |
| + newTextNode: function(text){ | |
| + return this.createTextNode(text); | |
| + }, | |
| + | |
| + getDocument: function(){ | |
| + return this; | |
| + }, | |
| + | |
| + getWindow: function(){ | |
| + return this.defaultView || this.parentWindow; | |
| + }, | |
| + | |
| + purge: function(){ | |
| + var elements = this.getElementsByTagName('*'); | |
| + for (var i = 0, l = elements.length; i < l; i++) Browser.freeMem(elements[i]); | |
| + } | |
| + | |
| +}); | |
| + | |
| +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 $(tag).set(props); | |
| + }, | |
| + | |
| + afterImplement: function(key, value){ | |
| + if (!Array[key]) Elements.implement(key, Elements.multi(key)); | |
| + Element.Prototype[key] = value; | |
| + } | |
| + | |
| +}); | |
| + | |
| +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 = $(params.iframe) || false; | |
| + var onload = props.onload || $empty; | |
| + delete props.onload; | |
| + props.id = props.name = $pick(props.id, props.name, 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); | |
| + var doc = new Document(iframe.contentWindow.document); | |
| + $extend(win.Element.prototype, Element.Prototype); | |
| + } | |
| + onload.call(iframe.contentWindow, iframe.contentWindow.document); | |
| + }; | |
| + (!window.frames[props.id]) ? iframe.addListener('load', onFrameLoad) : 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 = $.element(elements[i], !options.cash); | |
| + if (options.ddup){ | |
| + if (uniques[el.uid]) continue; | |
| + uniques[el.uid] = true; | |
| + } | |
| + 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)); | |
| + } | |
| + | |
| +}); | |
| + | |
| +Elements.multi = function(property){ | |
| + return function(){ | |
| + var items = []; | |
| + var elements = true; | |
| + for (var i = 0, j = this.length; i < j; i++){ | |
| + var returns = this[i][property].apply(this[i], arguments); | |
| + items.push(returns); | |
| + if (elements) elements = ($type(returns) == 'element'); | |
| + } | |
| + return (elements) ? new Elements(items) : items; | |
| + }; | |
| +}; | |
| + | |
| +Window.implement({ | |
| + | |
| + $: function(el, nocash){ | |
| + if (el && el.$family && el.uid) return el; | |
| + var type = $type(el); | |
| + return ($[type]) ? $[type](el, nocash, this.document) : null; | |
| + }, | |
| + | |
| + $$: 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': item = [item]; break; | |
| + case 'string': item = this.document.getElements(item, true); break; | |
| + default: item = false; | |
| + } | |
| + if (item) elements.extend(item); | |
| + } | |
| + return new Elements(elements); | |
| + }, | |
| + | |
| + getDocument: function(){ | |
| + return this.document; | |
| + }, | |
| + | |
| + getWindow: function(){ | |
| + return this; | |
| + } | |
| + | |
| +}); | |
| + | |
| +$.string = function(id, nocash, doc){ | |
| + id = doc.getElementById(id); | |
| + return (id) ? $.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 $.element(obj.toElement(doc), nocash); | |
| + return null; | |
| +}; | |
| + | |
| +$.textnode = $.whitespace = $.window = $.document = $arguments(0); | |
| + | |
| +Native.implement([Element, Document], { | |
| + | |
| + getElement: function(selector, nocash){ | |
| + return $(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}); | |
| + } | |
| + | |
| +}); | |
| + | |
| +Element.Storage = { | |
| + | |
| + get: function(uid){ | |
| + return (this[uid] || (this[uid] = {})); | |
| + } | |
| + | |
| +}; | |
| + | |
| +Element.Inserters = new Hash({ | |
| + | |
| + 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); | |
| + } | |
| + | |
| +}); | |
| + | |
| +Element.Inserters.inside = Element.Inserters.bottom; | |
| + | |
| +Element.Inserters.each(function(value, key){ | |
| + | |
| + var Key = key.capitalize(); | |
| + | |
| + Element.implement('inject' + Key, function(el){ | |
| + value(this, $(el, true)); | |
| + return this; | |
| + }); | |
| + | |
| + Element.implement('grab' + Key, function(el){ | |
| + value($(el, true), this); | |
| + return this; | |
| + }); | |
| + | |
| +}); | |
| + | |
| +Element.implement({ | |
| + | |
| + getDocument: function(){ | |
| + return this.ownerDocument; | |
| + }, | |
| + | |
| + getWindow: function(){ | |
| + return this.ownerDocument.getWindow(); | |
| + }, | |
| + | |
| + 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 $.element(el, nocash); | |
| + }, | |
| + | |
| + 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, Array.slice(arguments, 1)) : this.removeProperty(prop); | |
| + return this; | |
| + }, | |
| + | |
| + match: function(tag){ | |
| + return (!tag || Element.get(this, 'tag') == tag); | |
| + }, | |
| + | |
| + inject: function(el, where){ | |
| + Element.Inserters.get(where || 'bottom')(this, $(el, true)); | |
| + return this; | |
| + }, | |
| + | |
| + wraps: function(el, where){ | |
| + el = $(el, true); | |
| + return this.replaces(el).grab(el, where); | |
| + }, | |
| + | |
| + grab: function(el, where){ | |
| + Element.Inserters.get(where || 'bottom')($(el, true), this); | |
| + return this; | |
| + }, | |
| + | |
| + appendText: function(text, where){ | |
| + return this.grab(this.getDocument().newTextNode(text), where); | |
| + }, | |
| + | |
| + adopt: function(){ | |
| + Array.flatten(arguments).each(function(element){ | |
| + element = $(element, true); | |
| + if (element) this.appendChild(element); | |
| + }, this); | |
| + return this; | |
| + }, | |
| + | |
| + dispose: function(){ | |
| + return (this.parentNode) ? this.parentNode.removeChild(this) : this; | |
| + }, | |
| + | |
| + clone: function(contents, keepid){ | |
| + switch ($type(this)){ | |
| + case 'element': | |
| + var attributes = {}; | |
| + for (var j = 0, l = this.attributes.length; j < l; j++){ | |
| + var attribute = this.attributes[j], key = attribute.nodeName.toLowerCase(); | |
| + if (Browser.Engine.trident && (/input/i).test(this.tagName) && (/width|height/).test(key)) continue; | |
| + var value = (key == 'style' && this.style) ? this.style.cssText : attribute.nodeValue; | |
| + if (!$chk(value) || key == 'uid' || (key == 'id' && !keepid)) continue; | |
| + if (value != 'inherit' && ['string', 'number'].contains($type(value))) attributes[key] = value; | |
| + } | |
| + var element = new Element(this.nodeName.toLowerCase(), attributes); | |
| + if (contents !== false){ | |
| + for (var i = 0, k = this.childNodes.length; i < k; i++){ | |
| + var child = Element.clone(this.childNodes[i], true, keepid); | |
| + if (child) element.grab(child); | |
| + } | |
| + } | |
| + return element; | |
| + case 'textnode': return document.newTextNode(this.nodeValue); | |
| + } | |
| + return null; | |
| + }, | |
| + | |
| + replaces: function(el){ | |
| + el = $(el, true); | |
| + el.parentNode.replaceChild(this, el); | |
| + 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').clean(); | |
| + return this; | |
| + }, | |
| + | |
| + toggleClass: function(className){ | |
| + return this.hasClass(className) ? this.removeClass(className) : this.addClass(className); | |
| + }, | |
| + | |
| + getComputedStyle: function(property){ | |
| + if (this.currentStyle) return this.currentStyle[property.camelCase()]; | |
| + var computed = this.getWindow().getComputedStyle(this, null); | |
| + return (computed) ? computed.getPropertyValue([property.hyphenate()]) : null; | |
| + }, | |
| + | |
| + empty: function(){ | |
| + $A(this.childNodes).each(function(node){ | |
| + Browser.freeMem(node); | |
| + Element.empty(node); | |
| + Element.dispose(node); | |
| + }, this); | |
| + return this; | |
| + }, | |
| + | |
| + destroy: function(){ | |
| + Browser.freeMem(this.empty().dispose()); | |
| + return null; | |
| + }, | |
| + | |
| + getSelected: function(){ | |
| + return new Elements($A(this.options).filter(function(option){ | |
| + return option.selected; | |
| + })); | |
| + }, | |
| + | |
| + toQueryString: function(){ | |
| + var queryString = []; | |
| + this.getElements('input, select, textarea').each(function(el){ | |
| + if (!el.name || el.disabled) 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 (val) queryString.push(el.name + '=' + encodeURIComponent(val)); | |
| + }); | |
| + }); | |
| + return queryString.join('&'); | |
| + }, | |
| + | |
| + getProperty: function(attribute){ | |
| + var EA = Element.Attributes, key = EA.Props[attribute]; | |
| + var value = (key) ? this[key] : this.getAttribute(attribute, 2); | |
| + return (EA.Bools[attribute]) ? !!value : (key) ? value : value || null; | |
| + }, | |
| + | |
| + getProperties: function(){ | |
| + var args = $A(arguments); | |
| + return args.map(function(attr){ | |
| + return this.getProperty(attr); | |
| + }, this).associate(args); | |
| + }, | |
| + | |
| + setProperty: function(attribute, value){ | |
| + var EA = Element.Attributes, key = EA.Props[attribute], hasValue = $defined(value); | |
| + if (key && EA.Bools[attribute]) value = (value || !hasValue) ? true : false; | |
| + else if (!hasValue) return this.removeProperty(attribute); | |
| + (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; | |
| + }, | |
| + | |
| + removeProperty: function(attribute){ | |
| + var EA = Element.Attributes, key = EA.Props[attribute], isBool = (key && EA.Bools[attribute]); | |
| + (key) ? this[key] = (isBool) ? false : '' : this.removeAttribute(attribute); | |
| + return this; | |
| + }, | |
| + | |
| + removeProperties: function(){ | |
| + Array.each(arguments, this.removeProperty, this); | |
| + return this; | |
| + } | |
| + | |
| +}); | |
| + | |
| +(function(){ | |
| + | |
| +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))){ | |
| + elements.push(el); | |
| + if (!all) break; | |
| + } | |
| + el = el[walk]; | |
| + } | |
| + return (all) ? new Elements(elements, {ddup: false, cash: !nocash}) : $(elements[0], nocash); | |
| +}; | |
| + | |
| +Element.implement({ | |
| + | |
| + 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); | |
| + }, | |
| + | |
| + getChildren: function(match, nocash){ | |
| + return walk(this, 'nextSibling', 'firstChild', match, true, nocash); | |
| + }, | |
| + | |
| + hasChild: function(el){ | |
| + el = $(el, true); | |
| + return (!!el && $A(this.getElementsByTagName(el.tagName)).contains(el)); | |
| + } | |
| + | |
| +}); | |
| + | |
| +})(); | |
| + | |
| +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.href = {get: function(){ | |
| + return (!this.href) ? null : this.href.replace(new RegExp('^' + document.location.protocol + '\/\/' + document.location.host), ''); | |
| +}}; | |
| + | |
| +Element.Properties.html = {set: function(){ | |
| + return this.innerHTML = Array.flatten(arguments).join(''); | |
| +}}; | |
| + | |
| +Native.implement([Element, Window, Document], { | |
| + | |
| + addListener: function(type, fn){ | |
| + 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 = Element.Storage.get(this.uid); | |
| + var prop = storage[property]; | |
| + if ($defined(dflt) && !$defined(prop)) prop = storage[property] = dflt; | |
| + return $pick(prop); | |
| + }, | |
| + | |
| + store: function(property, value){ | |
| + var storage = Element.Storage.get(this.uid); | |
| + storage[property] = value; | |
| + return this; | |
| + }, | |
| + | |
| + eliminate: function(property){ | |
| + var storage = Element.Storage.get(this.uid); | |
| + delete storage[property]; | |
| + return this; | |
| + } | |
| + | |
| +}); | |
| + | |
| +Element.Attributes = new Hash({ | |
| + Props: {'html': 'innerHTML', 'class': 'className', 'for': 'htmlFor', 'text': (Browser.Engine.trident) ? 'innerText' : 'textContent'}, | |
| + Bools: ['compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', 'disabled', 'readonly', 'multiple', 'selected', 'noresize', 'defer'], | |
| + Camels: ['value', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan', 'frameBorder', 'maxLength', 'readOnly', 'rowSpan', 'tabIndex', 'useMap'] | |
| +}); | |
| + | |
| +Browser.freeMem = function(item){ | |
| + if (!item) return; | |
| + if (Browser.Engine.trident && (/object/i).test(item.tagName)){ | |
| + for (var p in item){ | |
| + if (typeof item[p] == 'function') item[p] = $empty; | |
| + } | |
| + Element.dispose(item); | |
| + } | |
| + if (item.uid && item.removeEvents) item.removeEvents(); | |
| +}; | |
| + | |
| +(function(EA){ | |
| + | |
| + var EAB = EA.Bools, EAC = EA.Camels; | |
| + EA.Bools = EAB = EAB.associate(EAB); | |
| + Hash.extend(Hash.combine(EA.Props, EAB), EAC.associate(EAC.map(function(v){ | |
| + return v.toLowerCase(); | |
| + }))); | |
| + EA.erase('Camels'); | |
| + | |
| +})(Element.Attributes); | |
| + | |
| +window.addListener('unload', function(){ | |
| + window.removeListener('unload', arguments.callee); | |
| + document.purge(); | |
| + if (Browser.Engine.trident) CollectGarbage(); | |
| +}); | |
| + | |
| +/* | |
| +Script: Element.Event.js | |
| + Contains Element methods for dealing with events, and custom Events. | |
| + | |
| +License: | |
| + MIT-style license. | |
| +*/ | |
| + | |
| +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 false; | |
| + }; | |
| + } | |
| + realType = custom.base || realType; | |
| + } | |
| + var defn = function(){ | |
| + return fn.call(self); | |
| + }; | |
| + var nativeEvent = Element.NativeEvents[realType] || 0; | |
| + 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; | |
| + var key = events[type].keys.splice(pos, 1)[0]; | |
| + 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(type){ | |
| + var events = this.retrieve('events'); | |
| + if (!events) return this; | |
| + if (!type){ | |
| + for (var evType in events) this.removeEvents(evType); | |
| + events = null; | |
| + } else if (events[type]){ | |
| + while (events[type].keys[0]) this.removeEvent(type, events[type].keys[0]); | |
| + events[type] = 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 = $(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 | |
| + Contains methods for interacting with the styles of Elements in a fashionable way. | |
| + | |
| +License: | |
| + MIT-style license. | |
| +*/ | |
| + | |
| +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)))){ | |
| + 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.each(arguments, 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 | |
| + 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). | |
| +*/ | |
| + | |
| +(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(){ | |
| + 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.trident || Browser.Engine.webkit)){ | |
| + position.x += leftBorder(element); | |
| + position.y += topBorder(element); | |
| + } | |
| + | |
| + element = element.offsetParent; | |
| + if (Browser.Engine.trident){ | |
| + while (element && !element.currentStyle.hasLayout) 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 = $(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')}; | |
| + }, | |
| + | |
| + position: function(obj){ | |
| + return this.setStyles(this.computePosition(obj)); | |
| + } | |
| + | |
| +}); | |
| + | |
| +Native.implement([Document, Window], { | |
| + | |
| + getSize: function(){ | |
| + var win = this.getWindow(); | |
| + if (Browser.Engine.presto || Browser.Engine.webkit) return {x: win.innerWidth, y: win.innerHeight}; | |
| + var doc = getCompatElement(this); | |
| + return {x: doc.clientWidth, y: doc.clientHeight}; | |
| + }, | |
| + | |
| + getScroll: function(){ | |
| + var win = this.getWindow(); | |
| + var doc = getCompatElement(this); | |
| + return {x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop}; | |
| + }, | |
| + | |
| + getScrollSize: function(){ | |
| + var doc = getCompatElement(this); | |
| + var 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 | |
| + | |
| +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 | |
| + Adds advanced CSS Querying capabilities for targeting elements. Also includes pseudoselectors support. | |
| + | |
| +License: | |
| + MIT-style license. | |
| +*/ | |
| + | |
| +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) 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+)(?:([!*^$~|]?=)["']?(.*?)["']?)?\]|:([\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]); | |
| + var a = (inta || inta === 0) ? inta : 1; | |
| + var special = parsed[2] || false; | |
| + var b = parseInt(parsed[3]) || 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[4], pn = m[5], pa = m[6]; | |
| + 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, match, 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(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 false; | |
| + 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 | |
| + | |
| + 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); | |
| + } | |
| + | |
| +}); | |
| + | |
| +/* | |
| +Script: Domready.js | |
| + Contains the domready custom event. | |
| + | |
| +License: | |
| + MIT-style license. | |
| +*/ | |
| + | |
| +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'); | |
| + }; | |
| + | |
| + switch (Browser.Engine.name){ | |
| + | |
| + case 'webkit': (function(){ | |
| + (['loaded', 'complete'].contains(document.readyState)) ? domready() : arguments.callee.delay(50); | |
| + })(); break; | |
| + | |
| + case 'trident': | |
| + var temp = document.createElement('div'); | |
| + (function(){ | |
| + ($try(function(){ | |
| + temp.doScroll('left'); | |
| + return $(temp).inject(document.body).set('html', 'temp').dispose(); | |
| + })) ? domready() : arguments.callee.delay(50); | |
| + })(); | |
| + break; | |
| + | |
| + default: | |
| + window.addEvent('load', domready); | |
| + document.addEvent('DOMContentLoaded', domready); | |
| + | |
| + } | |
| + | |
| +})(); | |
| + | |
| +/* | |
| +Script: JSON.js | |
| + JSON encoder and decoder. | |
| + | |
| +License: | |
| + MIT-style license. | |
| + | |
| +See Also: | |
| + <http://www.json.org/> | |
| +*/ | |
| + | |
| +var JSON = new Hash({ | |
| + | |
| + encode: function(obj){ | |
| + switch ($type(obj)){ | |
| + case 'string': | |
| + return '"' + obj.replace(/[\x00-\x1f\\"]/g, JSON.$replaceChars) + '"'; | |
| + case 'array': | |
| + return '[' + String(obj.map(JSON.encode).filter($defined)) + ']'; | |
| + 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; | |
| + }, | |
| + | |
| + $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); | |
| + }, | |
| + | |
| + 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 | |
| + Class for creating, loading, and saving browser Cookies. | |
| + | |
| +License: | |
| + MIT-style license. | |
| + | |
| +Credits: | |
| + Based on the functions by Peter-Paul Koch (http://quirksmode.org). | |
| +*/ | |
| + | |
| +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 | |
| + Wrapper for embedding SWF movies. Supports (and fixes) External Interface Communication. | |
| + | |
| +License: | |
| + MIT-style license. | |
| + | |
| +Credits: | |
| + Flash detection & Internet Explorer + Flash Player 9 fix inspired by SWFObject. | |
| +*/ | |
| + | |
| +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 = $(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 = $(element, true); | |
| + element.parentNode.replaceChild(this.toElement(), element); | |
| + return this; | |
| + }, | |
| + | |
| + inject: function(element){ | |
| + $(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 | |
| + Contains the basic animation logic to be extended by all other Fx Classes. | |
| + | |
| +License: | |
| + MIT-style license. | |
| +*/ | |
| + | |
| +var Fx = new Class({ | |
| + | |
| + Implements: [Chain, Events, Options], | |
| + | |
| + options: { | |
| + /* | |
| + onStart: $empty, | |
| + onCancel: $empty, | |
| + onComplete: $empty, | |
| + */ | |
| + fps: 50, | |
| + unit: false, | |
| + duration: 500, | |
| + link: 'ignore', | |
| + transition: function(p){ | |
| + return -(Math.cos(Math.PI * p) - 1) / 2; | |
| + } | |
| + }, | |
| + | |
| + 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'; | |
| + }, | |
| + | |
| + step: function(){ | |
| + var time = $time(); | |
| + if (time < this.time + this.options.duration){ | |
| + var delta = this.options.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(caller){ | |
| + if (!this.timer) return true; | |
| + switch (this.options.link){ | |
| + case 'cancel': this.cancel(); return true; | |
| + case 'chain': this.chain(caller.bind(this, Array.slice(arguments, 1))); return false; | |
| + } | |
| + return false; | |
| + }, | |
| + | |
| + start: function(from, to){ | |
| + if (!this.check(arguments.callee, from, to)) return this; | |
| + this.from = from; | |
| + this.to = to; | |
| + this.time = 0; | |
| + 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 | |
| + Contains the CSS animation logic. Used by Fx.Tween, Fx.Morph, Fx.Elements. | |
| + | |
| +License: | |
| + MIT-style license. | |
| +*/ | |
| + | |
| +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 | |
| + Formerly Fx.Style, effect to transition any CSS property for an element. | |
| + | |
| +License: | |
| + MIT-style license. | |
| +*/ | |
| + | |
| +Fx.Tween = new Class({ | |
| + | |
| + Extends: Fx.CSS, | |
| + | |
| + initialize: function(element, options){ | |
| + this.element = this.subject = $(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(arguments.callee, 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 | |
| + 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. | |
| +*/ | |
| + | |
| +Fx.Morph = new Class({ | |
| + | |
| + Extends: Fx.CSS, | |
| + | |
| + initialize: function(element, options){ | |
| + this.element = this.subject = $(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(arguments.callee, 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 | |
| + 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. | |
| +*/ | |
| + | |
| +(function(){ | |
| + | |
| + var old = Fx.prototype.initialize; | |
| + | |
| + Fx.prototype.initialize = function(options){ | |
| + old.call(this, options); | |
| + var trans = this.options.transition; | |
| + if (typeof trans == 'string' && (trans = trans.split(':'))){ | |
| + var base = Fx.Transitions; | |
| + base = base[trans[0]] || base[trans[0].capitalize()]; | |
| + if (trans[1]) base = base['ease' + trans[1].capitalize() + (trans[2] ? trans[2].capitalize() : '')]; | |
| + this.options.transition = base; | |
| + } | |
| + }; | |
| + | |
| +})(); | |
| + | |
| +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 = - Math.pow((11 - 6 * a - 11 * p) / 4, 2) + b * b; | |
| + 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 | |
| + Powerful all purpose Request Class. Uses XMLHTTPRequest. | |
| + | |
| +License: | |
| + MIT-style license. | |
| +*/ | |
| + | |
| +var Request = new Class({ | |
| + | |
| + Implements: [Chain, Events, Options], | |
| + | |
| + options: { | |
| + /*onRequest: $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 | |
| + }, | |
| + | |
| + 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)); | |
| + 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(); | |
| + } | |
| + this.xhr.onreadystatechange = $empty; | |
| + }, | |
| + | |
| + 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(caller){ | |
| + if (!this.running) return true; | |
| + switch (this.options.link){ | |
| + case 'cancel': this.cancel(); return true; | |
| + case 'chain': this.chain(caller.bind(this, Array.slice(arguments, 1))); return false; | |
| + } | |
| + return false; | |
| + }, | |
| + | |
| + send: function(options){ | |
| + if (!this.check(arguments.callee, 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 = options.url, method = options.method; | |
| + | |
| + switch ($type(data)){ | |
| + case 'element': data = $(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 && ['put', 'delete'].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 (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){ | |
| + if (!$try(function(){ | |
| + this.xhr.setRequestHeader(key, value); | |
| + return true; | |
| + }.bind(this))) 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.toLowerCase()})); | |
| + }; | |
| +}); | |
| + | |
| +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 | |
| + Extends the basic Request Class with additional methods for interacting with HTML responses. | |
| + | |
| +License: | |
| + MIT-style license. | |
| +*/ | |
| + | |
| +Request.HTML = new Class({ | |
| + | |
| + Extends: Request, | |
| + | |
| + options: { | |
| + update: 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]; | |
| + 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) $(options.update).empty().adopt(response.tree); | |
| + 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) send.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 | |
| + Extends the basic Request Class with additional methods for sending and receiving JSON data. | |
| + | |
| +License: | |
| + MIT-style license. | |
| +*/ | |
| + | |
| +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); | |
| + } | |
| + | |
| +}); | |
| \ No newline at end of file |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment