Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Mootools support... booyah

  • Loading branch information...
commit cbf1cd8f868892b761f66cb74c81f9a00261639d 1 parent 2fb76b1
Chris Van Pelt authored
View
BIN  mootools/images/bl.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  mootools/images/bl.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  mootools/images/bm.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  mootools/images/bm.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  mootools/images/br.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  mootools/images/br.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  mootools/images/closebox.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  mootools/images/closebox.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  mootools/images/ml.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  mootools/images/ml.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  mootools/images/mr.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  mootools/images/mr.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  mootools/images/tl.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  mootools/images/tl.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  mootools/images/tm.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  mootools/images/tm.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  mootools/images/tr.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  mootools/images/tr.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
147 mootools/index.html
@@ -0,0 +1,147 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ <title>Fancy Zoom by John Nunemaker</title>
+ <link rel="stylesheet" href="../css/common.css" type="text/css" />
+ <script type="text/javascript" src="js/mootools.1.2.js"></script>
+ <script type="text/javascript" src="js/fancyzoom.min.js"></script>
+ <script type="text/javascript" charset="utf-8">
+ document.addEvent('domready', function() {
+ $$("div.photo a").each(function(el) { new FancyZoom(el, {scaleImg:true}); })
+ new FancyZoom('medium_box_link', {width:400, height:300});
+ new FancyZoom('large_box_link');
+ new FancyZoom('flash_box_link');
+ });
+ </script>
+
+ <style type="text/css" media="screen">
+ #large_box {width:800; height:600;}
+ </style>
+</head>
+<body>
+<div id="wrapper">
+ <div id="header">
+ <h1>Fancy Zoom (Mootools)</h1>
+ <p>Zoomy JavaScript based loosely on Fancy Zoom by Cabel Sasser.</p>
+
+ <ul id="nav">
+ <li><a href="../jquery/index.html">jQuery Version</a></li>
+ <li><a href="../jquery/index.html">Prototype Version</a></li>
+ <li><a href="http://github.com/jnunemaker/fancy-zoom/">Github</a></li>
+ <li><a href="http://jnunemaker.lighthouseapp.com/projects/16389-fancyzoom/overview">Lighthouse</a></li>
+ </ul>
+ </div>
+
+ <div id="content">
+ <p>This works with any html (images, text, headings, flash). The only caveat is it doesn't currently work with AJAX. Whatever you want to zoom to must be html already on the page. Below are several examples. Width and height of zoom box are configurable through optional setting or css.</p>
+
+ <h2>Demos</h2>
+
+ <div id="photos">
+ <h3>Images</h3>
+ <div class="photo">
+ <a href="#github">
+ <img src="http://farm4.static.flickr.com/3250/2765022017_356efe6a25_s.jpg" alt="Github helmet" />
+ </a>
+ </div>
+ <div class="photo">
+ <a href="#hotdog">
+ <img src="http://farm4.static.flickr.com/3150/2726282580_05ed83e3c0_s.jpg" alt="Github helmet" />
+ </a>
+ </div>
+ <div class="photo">
+ <a href="#turtles">
+ <img src="http://farm4.static.flickr.com/3088/2709825025_fb6d71b455_s.jpg" alt="Github helmet" />
+ </a>
+ </div>
+
+ <div id="github">
+ <img src="http://farm4.static.flickr.com/3250/2765022017_356efe6a25.jpg" alt="helmet" />
+ </div>
+ <div id="hotdog">
+ <img src="http://farm4.static.flickr.com/3150/2726282580_05ed83e3c0.jpg" alt="Hot dog" />
+ </div>
+ <div id="turtles">
+ <img src="http://farm4.static.flickr.com/3088/2709825025_fb6d71b455.jpg" alt="Turtles" />
+ <p id="turtles_caption">It's true, they do bite!</p>
+ </div>
+ </div>
+
+ <div id="text">
+ <h3>Text</h3>
+ <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vivamus vitae risus vitae lorem iaculis placerat. Aliquam sit amet felis. Etiam congue. Donec risus risus, pretium ac, tincidunt eu, tempor eu, quam. Morbi blandit mollis magna. Suspendisse eu tortor. <a href="#medium_box" id="medium_box_link">Here is a medium box</a> blandit rhoncus. Ut a pede ac neque mattis facilisis. Nulla nunc ipsum, sodales vitae, hendrerit non, imperdiet ac, ante. <a href="#large_box" id="large_box_link">Here is a large box</a>. Morbi sit amet mi. Ut magna. Curabitur id est. Nulla velit. Sed consectetuer sodales justo. Aliquam dictum gravida libero. Sed eu turpis. Nunc id lorem. Aenean consequat tempor mi. Phasellus in neque. Nunc fermentum convallis ligula. <a href="#flash_box" id ="flash_box_link">You can even embed flash</a>.</p>
+
+ <div id="medium_box">
+ <h2>Here is a medium box</h2>
+ <p><strong>The width and height of this box are set in the options for this fancy zoom.</strong> Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vivamus vitae risus vitae lorem iaculis placerat. Aliquam sit amet felis. Etiam congue. Donec risus risus, pretium ac, tincidunt eu, tempor eu, quam. Morbi blandit mollis magna. Suspendisse eu tortor. Donec vitae felis nec ligula blandit rhoncus.</p>
+
+ <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vivamus vitae risus vitae lorem iaculis placerat. Aliquam sit amet felis. Etiam congue. Donec risus risus, pretium ac, tincidunt eu, tempor eu, quam. Morbi blandit mollis magna. Suspendisse eu tortor. Donec vitae felis nec ligula blandit rhoncus.</p>
+ </div>
+
+ <div id="large_box">
+ <h2>Here is a large box</h2>
+ <p><strong>The width and height for this box are inferred from css. See the style tag in the &lt;head&gt; of this document.</strong> Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vivamus vitae risus vitae lorem iaculis placerat. Aliquam sit amet felis. Etiam congue. Donec risus risus, pretium ac, tincidunt eu, tempor eu, quam. Morbi blandit mollis magna. Suspendisse eu tortor. Donec vitae felis nec ligula blandit rhoncus.</p>
+
+ <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vivamus vitae risus vitae lorem iaculis placerat. Aliquam sit amet felis. Etiam congue. Donec risus risus, pretium ac, tincidunt eu, tempor eu, quam. Morbi blandit mollis magna. Suspendisse eu tortor. Donec vitae felis nec ligula blandit rhoncus.</p>
+ </div>
+
+ <div id="flash_box">
+ <object type="application/x-shockwave-flash" width="400" height="300" data="http://www.flickr.com/apps/video/stewart.swf?v=59154" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000">
+ <param name="flashvars" value="intl_lang=en-us&amp;photo_secret=1869930911&amp;photo_id=2756538377"></param>
+ <param name="movie" value="http://www.flickr.com/apps/video/stewart.swf?v=59154"></param>
+ <param name="bgcolor" value="#000000"></param>
+ <param name="allowFullScreen" value="true"></param>
+ <embed type="application/x-shockwave-flash" src="http://www.flickr.com/apps/video/stewart.swf?v=59154" bgcolor="#000000" allowfullscreen="true" flashvars="intl_lang=en-us&amp;photo_secret=1869930911&amp;photo_id=2756538377" height="300" width="400"></embed>
+ </object>
+ </div>
+ </div>
+
+ <h2>Installation</h2>
+
+ <p>Add the following scripts and checkout the notes below (or view the source of this page).</p>
+
+<pre><code>&lt;script type="text/javascript" src="js/mootools.1.2.js"&gt;&lt;/script&gt;
+&lt;script type="text/javascript" src="js/fancyzoom.js"&gt;&lt;/script&gt;</code></pre>
+
+ <h2>Notes</h2>
+ <p>new FancyZoom(id) where id is the id of the <a> tag you would like to zoom. The <a> tag should have an href that anchors to the id of the box that contains the contents that should be zoomed. For example:</p>
+
+ <pre><code>&lt;a href="#small_box" id="small"&gt;Small Box!&lt;/a&gt;
+&lt;div id="small_box"&gt;
+ &lt;p&gt;Here is the contents that will appear in the zoom.&lt;/p&gt;
+&lt;/div&gt;
+&lt;script type="text/javascript"&gt;
+ new FancyZoom('small');
+&lt;/script&gt;
+
+// other examples
+&lt;script type="text/javascript"&gt;
+ $(document).observe('dom:loaded', function() {
+ $$('a.fancy').each(function(el) { new FancyZoom(el, {width:500, height:300}); });
+ new FancyZoom('small', {scaleImg: true}); // Scales images inside while zooming
+ new FancyZoom('medium');
+ // width and height are optional. defaults to css specifications of width and height.
+ // if width and height are passed in, they override whatever may be in css.
+ new FancyZoom('large', {width:600, height:400});
+ });
+&lt;/script&gt;</code></pre>
+
+ <p>If the images are not in a directory named 'images' that is relative to the html file you can configure it like so:</p>
+
+<pre><code>&lt;script type="text/javascript"&gt;
+ // note that once this option is passed in, it remains the same for every other instance of FancyZoom on the same page
+ new FancyZoom('medium', {directory:'directory'});
+&lt;/script&gt;</code></pre>
+
+ </div>
+
+ <div id="footer">
+ <p>
+ Created by <a href="http://addictedtonew.com/about/">John Nunemaker</a> of <a href="http://orderedlist.com/">Ordered List</a> |
+ <a href="http://orderedlist.com/contact/">Hire me</a>
+ </p>
+ </div>
+</div>
+</body>
+</html>
View
139 mootools/js/fancyzoom.js
@@ -0,0 +1,139 @@
+var FancyZoom = new Class({
+ Implements: Options,
+ options: {
+ //The directory option is global to all future instances of FancyZoom on the same page
+ directory : 'images',
+ scaleImg: false,
+ width: null,
+ height: null
+ },
+ initialize: function(element, options) {
+ this.setOptions(options)
+ if(!$('zoom'))
+ this.setup()
+ this.element = $(element)
+ if (this.element) {
+ this.element.store('content_div', $(this.element.get('href').match(/#(.+)$/)[1]).setStyles({display:'block', position:'absolute', visibility:'hidden'}));
+ this.element.store('scaleImg', this.options.scaleImg)
+ this.element.store('zoom_width', this.options.width);
+ this.element.store('zoom_height', this.options.height);
+ this.element.addEvent('click', FancyZoom.show);
+ }
+ },
+ setup: function() {
+ var ext = (Browser.Engine.trident && !Browser.Engine.trident5) ? 'gif' : 'png'
+ var html = '<table id="zoom_table" style="border-collapse:collapse; width:100%; height:100%;"> \
+ <tbody> \
+ <tr> \
+ <td class="tl" style="background:url(' + this.options.directory + '/tl.'+ext+') 0 0 no-repeat; width:20px height:20px; overflow:hidden;" /> \
+ <td class="tm" style="background:url(' + this.options.directory + '/tm.'+ext+') 0 0 repeat-x; height:20px; overflow:hidden;" /> \
+ <td class="tr" style="background:url(' + this.options.directory + '/tr.'+ext+') 100% 0 no-repeat; width:20px height:20px; overflow:hidden;" /> \
+ </tr> \
+ <tr> \
+ <td class="ml" style="background:url(' + this.options.directory + '/ml.'+ext+') 0 0 repeat-y; width:20px; overflow:hidden;" /> \
+ <td class="mm" style="background:#fff; vertical-align:top; padding:10px;"> \
+ <div id="zoom_content"> \
+ </div> \
+ </td> \
+ <td class="mr" style="background:url(' + this.options.directory + '/mr.'+ext+') 100% 0 repeat-y; width:20px; overflow:hidden;" /> \
+ </tr> \
+ <tr> \
+ <td class="bl" style="background:url(' + this.options.directory + '/bl.'+ext+') 0 100% no-repeat; width:20px height:20px; overflow:hidden;" /> \
+ <td class="bm" style="background:url(' + this.options.directory + '/bm.'+ext+') 0 100% repeat-x; height:20px; overflow:hidden;" /> \
+ <td class="br" style="background:url(' + this.options.directory + '/br.'+ext+') 100% 100% no-repeat; width:20px height:20px; overflow:hidden;" /> \
+ </tr> \
+ </tbody> \
+ </table> \
+ <a href="#" title="Close" id="zoom_close" style="position:absolute; top:0; left:0;"> \
+ <img src="' + this.options.directory + '/closebox.'+ext+'" alt="Close" style="border:none; margin:0; padding:0;" /> \
+ </a>';
+ document.body.grab(new Element('div', {id:"zoom", style:"display:none", html: html}));
+ //Setup the FX as class methods
+ FancyZoom.showFx = new Fx.Morph($('zoom'), {
+ duration: 500,
+ onStart: function(element) {
+ if (element.retrieve('scaleImg')) {
+ $('zoom_content').set('html', element.retrieve('content_div').get('html'));
+ $$('#zoom_content img').setStyle('width', '100%');
+ } else {
+ $('zoom_content').set('html','');
+ }
+ // middle row height must be set for IE otherwise it tries to be "logical" with the height
+ if (Browser.trident) {
+ $A([$$('td.ml'), $$('td.mm'), $$('td.mr')]).flatten().setStyle('height', (height-40));
+ }
+ },
+ onComplete: function(element) {
+ if (!element.retrieve('scaleImg'))
+ $('zoom_content').set('html', element.retrieve('content_div').get('html'));
+ $('zoom_close').setStyle('display', '');
+ }
+ })
+ FancyZoom.hideFx = new Fx.Morph($('zoom'), {
+ duration: 500,
+ onStart: function(element) {
+ if (!element.retrieve('scaleImg'))
+ $('zoom_content').set('html', '')
+ $('zoom_close').setStyle('display', 'none');
+ },
+ onComplete: function(element) {
+ element.setStyle('display', 'none')
+ }
+ })
+ //Attach the events only once
+ $('zoom_close').addEvent('click', FancyZoom.hide);
+ // hide zoom if click fired is not inside zoom
+ $$('html')[0].addEvent('click', function(e) {
+ var click_in_zoom = e.target.match('#zoom') ? e.target : e.target.getParent('#zoom');
+ if (!click_in_zoom)
+ FancyZoom.hide(e);
+ });
+ // esc to close zoom box
+ $(document).addEvent('keyup', function(e) {
+ if (e.key == 'esc')
+ FancyZoom.hide(e);
+ });
+ }
+});
+FancyZoom.show = function(e) {
+ e.stop();
+ var element = e.target.match('a') ? e.target : e.target.getParent('a');
+ var content_div = element.retrieve('content_div')
+ var width = (element.retrieve('zoom_width') || content_div.getWidth()) + 60;
+ var height = (element.retrieve('zoom_height') || content_div.getHeight()) + 60;
+ var d = window.getSize();
+ var yOffset = window.getScrollTop();
+ // ensure that newTop is at least 0 so it doesn't hide close button
+ var newTop = Math.max((d.y/2) - (height/2) + yOffset, 0);
+ var newLeft = (d.x/2) - (width/2);
+ // store this FancyZooms info in the zoom container
+ $('zoom').store('curTop', e.client.y);
+ $('zoom').store('curLeft', e.client.x);
+ $('zoom').store('content_div', content_div)
+ $('zoom').store('scaleImg', element.retrieve('scaleImg'))
+ $('zoom').setStyles({
+ position : 'absolute',
+ display : 'block',
+ opacity : 0,
+ top : e.client.y,
+ left : e.client.x,
+ width : 1,
+ height : 1
+ });
+
+ FancyZoom.showFx.start({
+ opacity: 1,
+ top: newTop,
+ left: newLeft,
+ width: width,
+ height: height})
+}
+FancyZoom.hide = function(e) {
+ e.stop();
+ FancyZoom.hideFx.start({
+ left: $('zoom').retrieve('curLeft'),
+ top: $('zoom').retrieve('curTop'),
+ width: 1,
+ height: 1,
+ opacity: 0});
+}
View
1  mootools/js/fancyzoom.min.js
@@ -0,0 +1 @@
+var FancyZoom=new Class({Implements:Options,options:{directory:"images",scaleImg:false,width:null,height:null},initialize:function(B,A){this.setOptions(A);if(!$("zoom")){this.setup()}this.element=$(B);if(this.element){this.element.store("content_div",$(this.element.get("href").match(/#(.+)$/)[1]).setStyles({display:"block",position:"absolute",visibility:"hidden"}));this.element.store("scaleImg",this.options.scaleImg);this.element.store("zoom_width",this.options.width);this.element.store("zoom_height",this.options.height);this.element.addEvent("click",FancyZoom.show)}},setup:function(){var B=(Browser.Engine.trident&&!Browser.Engine.trident5)?"gif":"png";var A='<table id="zoom_table" style="border-collapse:collapse; width:100%; height:100%;"> <tbody> <tr> <td class="tl" style="background:url('+this.options.directory+"/tl."+B+') 0 0 no-repeat; width:20px height:20px; overflow:hidden;" /> <td class="tm" style="background:url('+this.options.directory+"/tm."+B+') 0 0 repeat-x; height:20px; overflow:hidden;" /> <td class="tr" style="background:url('+this.options.directory+"/tr."+B+') 100% 0 no-repeat; width:20px height:20px; overflow:hidden;" /> </tr> <tr> <td class="ml" style="background:url('+this.options.directory+"/ml."+B+') 0 0 repeat-y; width:20px; overflow:hidden;" /> <td class="mm" style="background:#fff; vertical-align:top; padding:10px;"> <div id="zoom_content"> </div> </td> <td class="mr" style="background:url('+this.options.directory+"/mr."+B+') 100% 0 repeat-y; width:20px; overflow:hidden;" /> </tr> <tr> <td class="bl" style="background:url('+this.options.directory+"/bl."+B+') 0 100% no-repeat; width:20px height:20px; overflow:hidden;" /> <td class="bm" style="background:url('+this.options.directory+"/bm."+B+') 0 100% repeat-x; height:20px; overflow:hidden;" /> <td class="br" style="background:url('+this.options.directory+"/br."+B+') 100% 100% no-repeat; width:20px height:20px; overflow:hidden;" /> </tr> </tbody> </table> <a href="#" title="Close" id="zoom_close" style="position:absolute; top:0; left:0;"> <img src="'+this.options.directory+"/closebox."+B+'" alt="Close" style="border:none; margin:0; padding:0;" /> </a>';document.body.grab(new Element("div",{id:"zoom",style:"display:none",html:A}));FancyZoom.showFx=new Fx.Morph($("zoom"),{duration:500,onStart:function(C){if(C.retrieve("scaleImg")){$("zoom_content").set("html",C.retrieve("content_div").get("html"));$$("#zoom_content img").setStyle("width","100%")}else{$("zoom_content").set("html","")}if(Browser.trident){$A([$$("td.ml"),$$("td.mm"),$$("td.mr")]).flatten().setStyle("height",(height-40))}},onComplete:function(C){if(!C.retrieve("scaleImg")){$("zoom_content").set("html",C.retrieve("content_div").get("html"))}$("zoom_close").setStyle("display","")}});FancyZoom.hideFx=new Fx.Morph($("zoom"),{duration:500,onStart:function(C){if(!C.retrieve("scaleImg")){$("zoom_content").set("html","")}$("zoom_close").setStyle("display","none")},onComplete:function(C){C.setStyle("display","none")}});$("zoom_close").addEvent("click",FancyZoom.hide);$$("html")[0].addEvent("click",function(D){var C=D.target.match("#zoom")?D.target:D.target.getParent("#zoom");if(!C){FancyZoom.hide(D)}});$(document).addEvent("keyup",function(C){if(C.key=="esc"){FancyZoom.hide(C)}})}});FancyZoom.show=function(E){E.stop();var D=E.target.match("a")?E.target:E.target.getParent("a");var A=D.retrieve("content_div");var B=(D.retrieve("zoom_width")||A.getWidth())+60;var I=(D.retrieve("zoom_height")||A.getHeight())+60;var F=window.getSize();var C=window.getScrollTop();var G=Math.max((F.y/2)-(I/2)+C,0);var H=(F.x/2)-(B/2);$("zoom").store("curTop",E.client.y);$("zoom").store("curLeft",E.client.x);$("zoom").store("content_div",A);$("zoom").store("scaleImg",D.retrieve("scaleImg"));$("zoom").setStyles({position:"absolute",display:"block",opacity:0,top:E.client.y,left:E.client.x,width:1,height:1});FancyZoom.showFx.start({opacity:1,top:G,left:H,width:B,height:I})};FancyZoom.hide=function(A){A.stop();FancyZoom.hideFx.start({left:$("zoom").retrieve("curLeft"),top:$("zoom").retrieve("curTop"),width:1,height:1,opacity:0})};
View
3,816 mootools/js/mootools.1.2.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');