├── .editorconfig ├── .eslintrc ├── .gitattributes ├── .gitignore ├── .travis.yml ├── Docs ├── Browser │ └── Browser.md ├── Class │ ├── Class.Extras.md │ ├── Class.Thenable.md │ └── Class.md ├── Core │ └── Core.md ├── Element │ ├── Element.Delegation.md │ ├── Element.Dimensions.md │ ├── Element.Event.md │ ├── Element.Style.md │ └── Element.md ├── Fx │ ├── Fx.CSS.md │ ├── Fx.Morph.md │ ├── Fx.Transitions.md │ ├── Fx.Tween.md │ └── Fx.md ├── Intro.md ├── Request │ ├── Request.HTML.md │ ├── Request.JSON.md │ └── Request.md ├── Slick │ └── Slick.md ├── Types │ ├── Array.md │ ├── DOMEvent.md │ ├── Function.md │ ├── Number.md │ ├── Object.md │ └── String.md ├── Utilities │ ├── Cookie.md │ ├── DOMReady.md │ └── JSON.md └── license.md ├── Grunt ├── options │ ├── browsers.json │ ├── build.js │ ├── dist.js │ ├── options.js │ └── specs.js ├── plugins │ ├── eslint │ │ └── rules │ │ │ ├── mootools-indent.js │ │ │ └── mootools-whitespace.js │ └── karma │ │ └── syn │ │ ├── index.js │ │ ├── lib │ │ └── syn.js │ │ ├── post-amd.js │ │ └── pre-amd.js └── tasks │ └── tasks.js ├── Gruntfile.js ├── README.md ├── Source ├── Browser │ └── Browser.js ├── Class │ ├── Class.Extras.js │ ├── Class.Thenable.js │ └── Class.js ├── Core │ └── Core.js ├── Element │ ├── Element.Delegation.js │ ├── Element.Dimensions.js │ ├── Element.Event.js │ ├── Element.Style.js │ └── Element.js ├── Fx │ ├── Fx.CSS.js │ ├── Fx.Morph.js │ ├── Fx.Transitions.js │ ├── Fx.Tween.js │ └── Fx.js ├── Request │ ├── Request.HTML.js │ ├── Request.JSON.js │ └── Request.js ├── Slick │ ├── Slick.Finder.js │ └── Slick.Parser.js ├── Types │ ├── Array.js │ ├── DOMEvent.js │ ├── Function.js │ ├── Number.js │ ├── Object.js │ └── String.js ├── Utilities │ ├── Cookie.js │ ├── DOMReady.js │ └── JSON.js └── license.txt ├── Specs ├── Browser │ └── Browser.js ├── Class │ ├── Class.Extras.js │ ├── Class.Thenable.js │ └── Class.js ├── Core │ ├── Core.js │ ├── Native.js │ └── Type.js ├── Element │ ├── Element.Delegation.js │ ├── Element.Dimensions.js │ ├── Element.Event.js │ ├── Element.Style.js │ └── Element.js ├── Fx │ ├── Fx.Morph.js │ ├── Fx.Tween.js │ └── Fx.js ├── Request │ ├── Request.HTML.js │ ├── Request.JSON.js │ └── Request.js ├── Types │ ├── Array.js │ ├── Function.js │ ├── Hash.js │ ├── Number.js │ ├── Object.js │ └── String.js └── Utilities │ ├── Cookie.js │ ├── DOMReady.js │ └── JSON.js ├── Tests ├── DOMReady.php ├── Element │ ├── Element.Delegation.html │ ├── Element.Event.change.html │ └── Element.adopt.html ├── Fx │ └── Fx.html └── package.yml ├── bower.json ├── developers.sh ├── package.json ├── package.yml └── prepare-release /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | 8 | [*.js] 9 | indent_style = tab 10 | indent_size = 4 11 | 12 | [*.{yaml,yml,json}] 13 | indent_style = space 14 | indent_size = 2 15 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | root: true 2 | 3 | extends: 'eslint:recommended' 4 | 5 | rules: 6 | no-cond-assign: 0 7 | no-constant-condition: 0 8 | no-empty: 0 9 | no-extra-semi: 0 10 | no-octal: 0 11 | no-undef: 0 12 | no-unused-vars: 0 13 | linebreak-style: [2, unix] 14 | no-trailing-spaces: 2 15 | no-unneeded-ternary: 2 16 | quotes: [2, single, avoid-escape] 17 | semi: 2 18 | semi-spacing: 2 19 | mootools-indent: [2, tab, {SwitchCase: 1, VariableDeclarator: 1, IndentRootIIFE: false}] 20 | mootools-whitespace: 2 21 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.js text eol=lf 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /dist/ 3 | /node_modules/ 4 | /*.log 5 | mootools-core.tmproj 6 | mootools-core.esproj 7 | .DS_Store 8 | *~ 9 | *.swp 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - '4' 5 | 6 | env: 7 | matrix: 8 | - BUILD='compat' BROWSER='phantomjs' 9 | - BUILD='compat' BROWSER='chrome' 10 | - BUILD='compat' BROWSER='firefox' 11 | - BUILD='compat' BROWSER='edge' 12 | - BUILD='compat' BROWSER='opera12' 13 | - BUILD='compat' BROWSER='safari9' 14 | - BUILD='compat' BROWSER='safari8' 15 | - BUILD='compat' BROWSER='safari7' 16 | - BUILD='compat' BROWSER='safari6' 17 | - BUILD='compat' BROWSER='ie11' 18 | - BUILD='compat' BROWSER='ie10' 19 | - BUILD='compat' BROWSER='ie9' 20 | - BUILD='compat' BROWSER='ie8' 21 | - BUILD='compat' BROWSER='ie7' 22 | 23 | - BUILD='nocompat' BROWSER='phantomjs' 24 | - BUILD='nocompat' BROWSER='chrome' 25 | - BUILD='nocompat' BROWSER='firefox' 26 | - BUILD='nocompat' BROWSER='edge' 27 | - BUILD='nocompat' BROWSER='opera12' 28 | - BUILD='nocompat' BROWSER='safari9' 29 | - BUILD='nocompat' BROWSER='safari8' 30 | - BUILD='nocompat' BROWSER='safari7' 31 | - BUILD='nocompat' BROWSER='safari6' 32 | - BUILD='nocompat' BROWSER='ie11' 33 | - BUILD='nocompat' BROWSER='ie10' 34 | - BUILD='nocompat' BROWSER='ie9' 35 | - BUILD='nocompat' BROWSER='ie8' 36 | - BUILD='nocompat' BROWSER='ie7' 37 | 38 | - BUILD='server' 39 | 40 | global: 41 | - secure: myFP8vndNuVGr2b+WtP4efJ2fJL7By7PUi2yxgbUlaqK82qgkayrp7zu6G7YKYBtWRTaRvwybX4XVZn9zCvFm2xTB8xSeWy3bB63JZcYPGzLpwusgJ69Kr+K5dAn/EzIj23pIjqVic9XmEEFK1FqCLp8V2Ty4kl3RG7onfwALUo= 42 | - secure: PFKH8/mY7hD82ipfa46znhWJQzEZ8226ZgHLVFLiM2LAxHP6aWGDgyYaSZVGlpulAGXx2Pq+RLPjetQRpjy7CA6NWr/2YtAxvx88QkufRRylKyNgEy5Pf1ej/V88SHnfdpGIizNeF/ofAMPmsGfBaDUm3+gU1RT+zLNj5gl3J/4= 43 | 44 | matrix: 45 | include: 46 | - node_js: '0.12' 47 | env: BUILD='server' 48 | - node_js: '0.10' 49 | env: BUILD='server' 50 | 51 | cache: 52 | directories: 53 | - node_modules 54 | 55 | sudo: false 56 | -------------------------------------------------------------------------------- /Docs/Class/Class.md: -------------------------------------------------------------------------------- 1 | Class {#Class} 2 | ====================== 3 | 4 | The base Class of the [MooTools](http://mootools.net/) framework. 5 | 6 | Class Method: constructor {#Class:constructor} 7 | ---------------------------------------------- 8 | 9 | ### Syntax: 10 | 11 | var MyClass = new Class(properties); 12 | 13 | ### Arguments: 14 | 15 | 1. properties - Can be one of the following types: 16 | * (*object*) The collection of properties that apply to the Class. Also accepts some special properties such as Extends, Implements, and initialize (see below). 17 | * (*function*) The initialize function (see below). 18 | 19 | #### Property: Extends 20 | 21 | * (*class*) The Class that this class will extend. 22 | 23 | The methods of this Class that have the same name as the Extends Class, will have a parent property, that allows you to call the other overridden method. 24 | The Extends property should be the first property in a class definition. 25 | 26 | #### Property: Implements 27 | 28 | * (*class*) The properties of a passed Class will be copied into the target Class. 29 | * (*array*) An array of Classes, the properties of which will be copied into this Class. 30 | 31 | Implements is similar to Extends, except that it adopts properties from one or more other classes without inheritance. 32 | Useful when implementing a default set of properties in multiple Classes. The Implements property should come after Extends but before all other properties. 33 | 34 | #### Property: initialize 35 | 36 | * (*function*) The initialize function will be the constructor for this class when new instances are created. 37 | 38 | #### Property: toElement 39 | 40 | * (*function*) A method which returns an element. This method will be automatically called when passing an instance of a class in the [document.id][] function. 41 | 42 | 43 | ### Returns: 44 | 45 | * (*class*) The created Class. 46 | 47 | ### Examples: 48 | 49 | #### Class Example: 50 | 51 | var Cat = new Class({ 52 | initialize: function(name){ 53 | this.name = name; 54 | } 55 | }); 56 | var myCat = new Cat('Micia'); 57 | alert(myCat.name); // alerts 'Micia' 58 | 59 | var Cow = new Class({ 60 | initialize: function(){ 61 | alert('moooo'); 62 | } 63 | }); 64 | 65 | #### Extends Example: 66 | 67 | var Animal = new Class({ 68 | initialize: function(age){ 69 | this.age = age; 70 | } 71 | }); 72 | var Cat = new Class({ 73 | Extends: Animal, 74 | initialize: function(name, age){ 75 | this.parent(age); // calls initialize method of Animal class 76 | this.name = name; 77 | } 78 | }); 79 | var myCat = new Cat('Micia', 20); 80 | alert(myCat.name); // alerts 'Micia'. 81 | alert(myCat.age); // alerts 20. 82 | 83 | #### Implements Example: 84 | 85 | var Animal = new Class({ 86 | initialize: function(age){ 87 | this.age = age; 88 | } 89 | }); 90 | var Cat = new Class({ 91 | Implements: Animal, 92 | setName: function(name){ 93 | this.name = name 94 | } 95 | }); 96 | var myAnimal = new Cat(20); 97 | myAnimal.setName('Micia'); 98 | alert(myAnimal.name); // alerts 'Micia'. 99 | 100 | 101 | 102 | 103 | Class Method: implement {#Class:implement} 104 | ------------------------------------------ 105 | 106 | Implements the passed in properties into the base Class prototypes, altering the base Class. 107 | The same as creating a [new Class](#Class:constructor) with the Implements property, but handy when you need to modify existing classes. 108 | 109 | ### Syntax: 110 | 111 | MyClass.implement(properties); 112 | 113 | ### Arguments: 114 | 115 | 1. properties - (*object*) The properties to add to the base Class. 116 | 117 | ### Examples: 118 | 119 | var Animal = new Class({ 120 | initialize: function(age){ 121 | this.age = age; 122 | } 123 | }); 124 | Animal.implement({ 125 | setName: function(name){ 126 | this.name = name; 127 | } 128 | }); 129 | var myAnimal = new Animal(20); 130 | myAnimal.setName('Micia'); 131 | alert(myAnimal.name); // alerts 'Micia' 132 | 133 | [document.id]: /core/Element/Element#Window:document-id 134 | -------------------------------------------------------------------------------- /Docs/Element/Element.Delegation.md: -------------------------------------------------------------------------------- 1 | Type: Element {#Element} 2 | ======================== 3 | 4 | Extends the [Element][] type to include event-delegation in its event system. 5 | 6 | Event delegation is a common practice where an event listener is attached to a parent element to monitor its children rather than attach events to every single child element. It's more efficient for dynamic content or highly interactive pages with a lot of DOM elements. 7 | 8 | ### Demo: 9 | 10 | * [Element.Delegation](http://mootools.net/demos/?demo=Element.Delegation) 11 | 12 | ### Example: 13 | 14 | An example of how delegation is usually applied. Delegation is extra useful when working with dynamic content like AJAX. 15 | 16 | var myElement = $('myElement'); 17 | var request = new Request({ 18 | // other options 19 | onSuccess: function(text){ 20 | myElement.set('html', text); // No need to attach more click events. 21 | } 22 | }); 23 | // Adding the event, notice the :relay syntax with the selector that matches the target element inside of myElement. 24 | // Every click on an anchor-tag inside of myElement executes this function. 25 | myElement.addEvent('click:relay(a)', function(event, target){ 26 | event.preventDefault(); 27 | request.send({ 28 | url: target.get('href') 29 | }); 30 | }); 31 | 32 | ### Notes: 33 | 34 | * Delegation is especially useful if you are using AJAX to load content into your pages dynamically, as the contents of an element can change with new elements added or others removed and your delegated events need not change. 35 | * By delegating events to parent objects you can dramatically increase the efficiency of your pages. Consider the example above. You could attach events to every link on a page - which may be hundreds of DOM elements - or you can delegate the event to the document body, evaluating your code only when the user actually clicks a link (instead of on page load/domready). 36 | * You can use any selector in combination with any event 37 | * Be wary of the cost of delegation; for example, mouseover/mouseout delegation on an entire document can cause your page to run the selector constantly as the user moves his or her mouse around the page. Delegation is not always the best solution. 38 | * In general it is always better to delegate to the closest parent to your elements as possible; delegate to an element in the page rather than the document body for example. 39 | 40 | Element method: addEvent {#Element:addEvent} 41 | -------------------------------------------- 42 | 43 | Delegates the methods of an element's children to the parent element for greater efficiency when a selector is provided. Otherwise it will work like [addEvent][]. 44 | 45 | ### Syntax: 46 | 47 | myElement.addEvent(typeSelector, fn); 48 | 49 | ### Arguments: 50 | 51 | 2. typeSelector - (*string*) An event name (click, mouseover, etc) that should be monitored paired with a selector (see example) to limit functionality to child elements. 52 | 3. fn - (*function*) The callback to execute when the event occurs (passed the event just like any other [addEvent][] usage and a second argument, the element that matches your selector that was clicked). 53 | 54 | 55 | ### Example: 56 | 57 | // Alerts when an anchor element with class 'myStyle' is clicked inside of myElement 58 | document.id(myElement).addEvent('click:relay(a.myStyle)', function(){ 59 | alert('hello'); 60 | }); 61 | 62 | 63 | document.id('myElement').addEvent('click:relay(a)', function(event, clicked){ 64 | event.preventDefault(); //don't follow the link 65 | alert('you clicked a link!'); 66 | // You can reference the element clicked with the second 67 | // Argument passed to your callback 68 | clicked.setStyle('color', '#777'); 69 | }); 70 | 71 | ### Returns: 72 | 73 | * *element* - This element. 74 | 75 | Element method: addEvents {#Element:addEvents} 76 | ---------------------------------------------- 77 | 78 | Delegates the events to the parent just as with addEvent above. Works like [addEvents][]. 79 | 80 | ### Example: 81 | 82 | $('myElement').addEvents({ 83 | // monitor an element for mouseover 84 | mouseover: fn, 85 | // but only monitor child links for clicks 86 | 'click:relay(a)': fn2 87 | }); 88 | 89 | 90 | Element method: removeEvent {#Element:removeEvent} 91 | -------------------------------------------------- 92 | 93 | Removes a method from an element like [removeEvent][]. 94 | 95 | ### Example: 96 | 97 | var monitor = function(event, element){ 98 | alert('you clicked a link!'); 99 | }; 100 | 101 | $('myElement').addEvent('click:relay(a)', monitor); 102 | // link clicks are delegated to element 103 | 104 | // remove delegation: 105 | $('myElement').removeEvent('click:relay(a)', monitor); 106 | 107 | 108 | Element method: removeEvents {#Element:removeEvents} 109 | ---------------------------------------------------- 110 | 111 | Removes a series of methods from delegation if the functions were used for delegation or else works like [removeEvents][]. 112 | 113 | ### Example: 114 | 115 | var monitor = function(){ 116 | alert('you clicked or moused over a link!'); 117 | }; 118 | 119 | $('myElement').addEvents({ 120 | 'mouseover:relay(a)': monitor, 121 | 'click:relay(a)': monitor 122 | }); 123 | 124 | // link clicks are delegated to element 125 | // remove the delegation: 126 | $('myElement').removeEvents({ 127 | 'mouseover:relay(a)': monitor, 128 | 'click:relay(a)': monitor 129 | }); 130 | 131 | // remove all click:relay(a) events 132 | $('myElement').removeEvents('click:relay(a)'); 133 | 134 | 135 | 136 | [Element]: /core/Element/Element 137 | [addEvent]: /core/Element/Element.Event#Element:addEvent 138 | [addEvents]: /core/Element/Element.Event#Element:addEvents 139 | [removeEvent]: /core/Element/Element.Event#Element:removeEvent 140 | [removeEvents]: /core/Element/Element.Event#Element:removeEvents 141 | -------------------------------------------------------------------------------- /Docs/Element/Element.Style.md: -------------------------------------------------------------------------------- 1 | Type: Element {#Element} 2 | ======================== 3 | 4 | Custom Type to allow all of its methods to be used with any DOM element via the dollar function [$][]. 5 | 6 | 7 | 8 | Element Method: setStyle {#Element:setStyle} 9 | -------------------------------------------- 10 | 11 | Sets a CSS property to the Element. 12 | 13 | ### Syntax: 14 | 15 | myElement.setStyle(property, value); 16 | 17 | ### Arguments: 18 | 19 | 1. property - (*string*) The property to set. 20 | 2. value - (*mixed*) The value to which to set it. Numeric values of properties requiring a unit will automatically be appended with 'px'. 21 | 22 | ### Returns: 23 | 24 | * (*element*) This element. 25 | 26 | ### Example: 27 | //Both lines have the same effect. 28 | $('myElement').setStyle('width', '300px'); // the width is now 300px. 29 | $('myElement').setStyle('width', 300); // the width is now 300px. 30 | 31 | ### Notes: 32 | 33 | - All number values will automatically be rounded to the nearest whole number. 34 | 35 | 36 | 37 | Element Method: getStyle {#Element:getStyle} 38 | -------------------------------------------- 39 | 40 | Returns the style of the Element given the property passed in. 41 | 42 | ### Syntax: 43 | 44 | var style = myElement.getStyle(property); 45 | 46 | ### Arguments: 47 | 48 | 1. property - (*string*) The css style property you want to retrieve. 49 | 50 | ### Returns: 51 | 52 | * (*string*) The style value. 53 | 54 | ### Examples: 55 | 56 | $('myElement').getStyle('width'); // returns "300px". 57 | $('myElement').getStyle('width').toInt(); // returns 300. 58 | 59 | 60 | 61 | Element Method: setStyles {#Element:setStyles} 62 | ---------------------------------------------- 63 | 64 | Applies a collection of styles to the Element. 65 | 66 | ### Syntax: 67 | 68 | myElement.setStyles(styles); 69 | 70 | ### Arguments: 71 | 72 | 1. styles - (*object*) An object of property/value pairs for all the styles to apply. 73 | 74 | ### Returns: 75 | 76 | * (*element*) This element. 77 | 78 | ### Example: 79 | 80 | $('myElement').setStyles({ 81 | border: '1px solid #000', 82 | width: 300, 83 | height: 400 84 | }); 85 | 86 | ### See Also: 87 | 88 | - [Element:getStyle][] 89 | 90 | 91 | 92 | Element Method: getStyles {#Element:getStyles} 93 | ---------------------------------------------- 94 | 95 | Returns an object of styles of the Element for each argument passed in. 96 | 97 | ### Syntax: 98 | 99 | var styles = myElement.getStyles(property[, property2[, property3[, ...]]]); 100 | 101 | ### Arguments: 102 | 103 | 1. properties - (*strings*) Any number of style properties. 104 | 105 | ### Returns: 106 | 107 | * (*object*) An key/value object with the CSS styles as computed by the browser. 108 | 109 | ### Examples: 110 | 111 | $('myElement').getStyles('width', 'height', 'padding'); 112 | // returns {width: '10px', height: '10px', padding: '10px 0px 10px 0px'} 113 | 114 | ### See Also: 115 | 116 | - [Element:getStyle][] 117 | 118 | 119 | 120 | [$]: /core/Element/Element/#Window:dollar 121 | [Element:getStyle]: #Element:getStyle 122 | -------------------------------------------------------------------------------- /Docs/Fx/Fx.CSS.md: -------------------------------------------------------------------------------- 1 | Class: Fx.CSS {#Fx-CSS} 2 | ======================= 3 | 4 | CSS parsing class for effects. Required by [Fx.Tween][], [Fx.Morph][], [Fx.Elements][]. 5 | 6 | Has no public methods. 7 | 8 | 9 | 10 | [Fx.Tween]: /core/Fx/Fx.Tween 11 | [Fx.Morph]: /core/Fx/Fx.Morph 12 | [Fx.Elements]: /more/Fx/Fx.Elements 13 | -------------------------------------------------------------------------------- /Docs/Fx/Fx.Morph.md: -------------------------------------------------------------------------------- 1 | Class: Fx.Morph {#Fx-Morph} 2 | =========================== 3 | 4 | Allows for the animation of multiple CSS properties at once, even by a simple CSS selector. Inherits methods, properties, options and events from [Fx][]. 5 | 6 | ### Extends: 7 | 8 | - [Fx][] 9 | 10 | ### Syntax: 11 | 12 | var myFx = new Fx.Morph(element[, options]); 13 | 14 | ### Arguments: 15 | 16 | 1. element - (*mixed*) A string ID of the Element or an Element to apply the style transitions to. 17 | 2. options - (*object*, optional) The [Fx][] options object. 18 | 19 | ### Returns: 20 | 21 | * (*object*) A new Fx.Morph instance. 22 | 23 | ### Examples: 24 | 25 | Multiple styles with start and end values using an object: 26 | 27 | var myEffect = new Fx.Morph('myElement', { 28 | duration: 'long', 29 | transition: Fx.Transitions.Sine.easeOut 30 | }); 31 | 32 | myEffect.start({ 33 | 'height': [10, 100], // Morphs the 'height' style from 10px to 100px. 34 | 'width': [900, 300] // Morphs the 'width' style from 900px to 300px. 35 | }); 36 | 37 | 38 | Multiple styles with the start value omitted will default to the current Element's value: 39 | 40 | var myEffect = new Fx.Morph('myElement', { 41 | duration: 'short', 42 | transition: Fx.Transitions.Sine.easeOut 43 | }); 44 | 45 | myEffect.start({ 46 | 'height': 100, // Morphs the height from the current to 100px. 47 | 'width': 300 // Morphs the width from the current to 300px. 48 | }); 49 | 50 | 51 | Morphing one Element to match the CSS values within a CSS class. This is useful when 52 | separating the logic and styles: 53 | 54 | var myEffect = new Fx.Morph('myElement', { 55 | duration: 1000, 56 | transition: Fx.Transitions.Sine.easeOut 57 | }); 58 | 59 | // the styles of myClassName will be applied to the target Element. 60 | myEffect.start('.myClassName'); 61 | 62 | ### Notes: 63 | 64 | - This feature only works for simple selectors like a single class or id due to limited browser support for complex selectors. 65 | 66 | ### See Also: 67 | 68 | - [Fx][] 69 | 70 | 71 | 72 | Fx.Morph Method: set {#Fx-Morph:set} 73 | ------------------------------------ 74 | 75 | Sets the Element's CSS properties to the specified values immediately. 76 | 77 | ### Syntax: 78 | 79 | myFx.set(to); 80 | 81 | ### Arguments: 82 | 83 | 1. properties - (*mixed*) Either an *object* of key/value pairs of CSS attributes to change or a *string* representing a CSS selector which can be found within the CSS of the page. If only one value is given for any CSS property, the transition will be from the current value of that property to the value given. 84 | 85 | ### Returns: 86 | 87 | * (*object*) This Fx.Morph instance. 88 | 89 | ### Examples: 90 | 91 | var myFx = new Fx.Morph('myElement').set({ 92 | 'height': 200, 93 | 'width': 200, 94 | 'background-color': '#f00', 95 | 'opacity': 0 96 | }); 97 | var myFx = new Fx.Morph('myElement').set('.myClass'); 98 | 99 | 100 | 101 | Fx.Morph Method: start {#Fx-Morph:start} 102 | ---------------------------------------- 103 | 104 | Executes a transition for any number of CSS properties in tandem. 105 | 106 | ### Syntax: 107 | 108 | myFx.start(properties); 109 | 110 | ### Arguments: 111 | 112 | 1. properties - (*mixed*) An *object* of key/value pairs of CSS attributes to change or a *string* representing a CSS selector which can be found within the CSS of the page. 113 | If only one value is given for any CSS property, the transition will be from the current value of that property to the value given. 114 | 115 | ### Returns: 116 | 117 | * (*object*) This Fx.Morph instance. 118 | 119 | ### Examples: 120 | 121 | var myEffects = new Fx.Morph('myElement', {duration: 1000, transition: Fx.Transitions.Sine.easeOut}); 122 | 123 | myEffects.start({ 124 | 'height': [10, 100], 125 | 'width': [900, 300], 126 | 'opacity': 0, 127 | 'background-color': '#00f' 128 | }); 129 | 130 | ### Notes: 131 | 132 | - If a string is passed as the CSS selector, the selector must be identical to the one within the CSS. 133 | - Multiple selectors (with commas) are not supported. 134 | - @import'ed CSS rules will not be available for Morph calls. All CSS selectors must be present in CSS directly loaded into the page. 135 | 136 | 137 | Object: Element.Properties {#Element-Properties} 138 | ============================================== 139 | 140 | see [Element.Properties][] 141 | 142 | Element Property: morph {#Element-Properties:morph} 143 | --------------------------------------------------- 144 | 145 | ### Setter 146 | 147 | Sets a default Fx.Morph instance for an Element. 148 | 149 | #### Syntax: 150 | 151 | el.set('morph'[, options]); 152 | 153 | #### Arguments: 154 | 155 | 1. options - (*object*, optional) The Fx.Morph options. 156 | 157 | #### Returns: 158 | 159 | * (*element*) This Element. 160 | 161 | #### Examples: 162 | 163 | el.set('morph', {duration: 'long', transition: 'bounce:out'}); 164 | el.morph({height: 100, width: 100}); 165 | 166 | ### Getter 167 | 168 | Gets the default Fx.Morph instance for the Element. 169 | 170 | #### Syntax: 171 | 172 | el.get('morph'); 173 | 174 | #### Arguments: 175 | 176 | 1. property - (*string*) the Fx.Morph property argument. 177 | 178 | #### Returns: 179 | 180 | * (*object*) The Fx.Morph instance. 181 | 182 | #### Examples: 183 | 184 | el.set('morph', {duration: 'long', transition: 'bounce:out'}); 185 | el.morph({height: 100, width: 100}); 186 | el.get('morph'); // the Fx.Morph instance. 187 | 188 | 189 | 190 | Type: Element {#Element} 191 | ========================== 192 | 193 | Element Method: morph {#Element:morph} 194 | -------------------------------------- 195 | 196 | Animates an Element given the properties passed in. 197 | 198 | ### Syntax: 199 | 200 | myElement.morph(properties); 201 | 202 | ### Arguments: 203 | 204 | 1. properties - (*mixed*) The CSS properties to animate. Can be either an object of CSS properties or a string representing a CSS selector. If only one value is given for any CSS property, the transition will be from the current value of that property to the value given. 205 | 206 | ### Returns: 207 | 208 | * (*element*) This Element. 209 | 210 | ### Example: 211 | 212 | With an object: 213 | 214 | $('myElement').morph({height: 100, width: 200}); 215 | 216 | With a selector: 217 | 218 | $('myElement').morph('.class1'); 219 | 220 | ### See Also: 221 | 222 | - [Fx.Morph][] 223 | 224 | 225 | 226 | [$]: /core/Element/Element#Window:dollar 227 | [Fx]: /core/Fx/Fx 228 | [Fx.Morph]: #Fx-Morph 229 | [Element.Properties]: /core/Element/Element/#Element-Properties 230 | -------------------------------------------------------------------------------- /Docs/Fx/Fx.Transitions.md: -------------------------------------------------------------------------------- 1 | Class: Fx {#Fx} 2 | =============== 3 | 4 | Fx.Transitions overrides the base [Fx][] constructor, and adds the possibility to use the transition option as string. 5 | 6 | ### Transition option: 7 | 8 | The equation to use for the effect. See [Fx.Transitions][]. It accepts both a function (ex: Fx.Transitions.Sine.easeIn) or a string ('sine:in', 'bounce:out' or 'quad:in:out') that will map to Fx.Transitions.Sine.easeIn / Fx.Transitions.Bounce.easeOut / Fx.Transitions.Quad.easeInOut 9 | 10 | 11 | Object: Fx.Transitions {#Fx-Transitions} 12 | ====================================== 13 | 14 | A collection of tweening transitions for use with the [Fx][] classes. 15 | 16 | ### Examples: 17 | 18 | $('myElement').set('tween', {transition: Fx.Transitions.Elastic.easeOut}); 19 | $('myElement').tween('margin-top', 100); 20 | 21 | ### See also: 22 | 23 | - [Robert Penner's Easing Equations](http://www.robertpenner.com/easing/) 24 | 25 | ### Note: 26 | 27 | Since MooTools 1.3 this is a native JavaScript Object and not an instance of the deprecated Hash 28 | 29 | 30 | 31 | Fx.Transitions Method: linear {#Fx-Transitions:linear} 32 | ------------------------------------------------------ 33 | 34 | Displays a linear transition. 35 | 36 | Fx.Transitions Method: quad {#Fx-Transitions:quad} 37 | -------------------------------------------------- 38 | 39 | Displays a quadratic transition. Must be used as Quad.easeIn or Quad.easeOut or Quad.easeInOut. 40 | 41 | Fx.Transitions Method: cubic {#Fx-Transitions:cubic} 42 | ---------------------------------------------------- 43 | 44 | Displays a cubicular transition. Must be used as Cubic.easeIn or Cubic.easeOut or Cubic.easeInOut. 45 | 46 | 47 | Fx.Transitions Method: quart {#Fx-Transitions:quart} 48 | ---------------------------------------------------- 49 | 50 | Displays a quartetic transition. Must be used as Quart.easeIn or Quart.easeOut or Quart.easeInOut. 51 | 52 | Fx.Transitions Method: quint {#Fx-Transitions:quint} 53 | ---------------------------------------------------- 54 | 55 | Displays a quintic transition. Must be used as Quint.easeIn or Quint.easeOut or Quint.easeInOut 56 | 57 | Fx.Transitions Method: pow {#Fx-Transitions:pow} 58 | ------------------------------------------------ 59 | 60 | Used to generate Quad, Cubic, Quart and Quint. 61 | 62 | ### Note: 63 | 64 | - The default is `p^6`. 65 | 66 | Fx.Transitions Method: expo {#Fx-Transitions:expo} 67 | -------------------------------------------------- 68 | 69 | Displays a exponential transition. Must be used as Expo.easeIn or Expo.easeOut or Expo.easeInOut. 70 | 71 | 72 | 73 | Fx.Transitions Method: circ {#Fx-Transitions:circ} 74 | -------------------------------------------------- 75 | 76 | Displays a circular transition. Must be used as Circ.easeIn or Circ.easeOut or Circ.easeInOut. 77 | 78 | 79 | 80 | Fx.Transitions Method: sine {#Fx-Transitions:sine} 81 | -------------------------------------------------- 82 | 83 | Displays a sineousidal transition. Must be used as Sine.easeIn or Sine.easeOut or Sine.easeInOut. 84 | 85 | 86 | 87 | Fx.Transitions Method: back {#Fx-Transitions:back} 88 | -------------------------------------------------- 89 | 90 | Makes the transition go back, then all forth. Must be used as Back.easeIn or Back.easeOut or Back.easeInOut. 91 | 92 | 93 | 94 | Fx.Transitions Method: bounce {#Fx-Transitions:bounce} 95 | ------------------------------------------------------ 96 | 97 | Makes the transition bouncy. Must be used as Bounce.easeIn or Bounce.easeOut or Bounce.easeInOut. 98 | 99 | 100 | 101 | Fx.Transitions Method: elastic {#Fx-Transitions:elastic} 102 | -------------------------------------------------------- 103 | 104 | Elastic curve. Must be used as Elastic.easeIn or Elastic.easeOut or Elastic.easeInOut 105 | 106 | 107 | 108 | Class: Fx.Transition {#Fx-Transition} 109 | ===================================== 110 | 111 | This class is only useful for math geniuses who want to write their own easing equations. 112 | Returns an [Fx][] transition function with 'easeIn', 'easeOut', and 'easeInOut' methods. 113 | 114 | ### Syntax: 115 | 116 | var myTransition = new Fx.Transition(transition[, params]); 117 | 118 | ### Arguments: 119 | 120 | 1. transition - (*function*) Can be a [Fx.Transitions][] function or a user-provided function which will be extended with easing functions. 121 | 2. params - (*mixed*, optional) Single value or an array for multiple values to pass as the second parameter for the transition function. A single value will be transformed to an array. 122 | 123 | ### Returns: 124 | 125 | * (*function*) A function with easing functions. 126 | 127 | ### Examples: 128 | 129 | // Your own function. Here overshoot is bigger (now 1.3) when base -> 1 and base != 1. 130 | var myTransition = new Fx.Transition(function(pos, x){ 131 | return 1 - Math.pow(Math.abs(Math.log(pos) / Math.log(x && x[0] || Math.E)), pos); 132 | }, 1.3); 133 | 134 | var myFx = new Fx.Tween('myElement', { 135 | property: 'height', 136 | transition: myTransition.easeOut 137 | }).start(30, 100); 138 | 139 | ### See Also: 140 | 141 | - [Fx.Transitions][] 142 | 143 | 144 | [Fx]: /core/Fx/Fx 145 | [Fx.Transitions]: #Fx-Transitions 146 | [Element.effect]: /core/Element/#Element:effect 147 | [Linear]: ../Docs/assets/images/Linear.png 148 | [Quad]: ../Docs/assets/images/Quad.png 149 | [Cubic]: ../Docs/assets/images/Cubic.png 150 | [Quart]: ../Docs/assets/images/Quart.png 151 | [Quint]: ../Docs/assets/images/Quint.png 152 | [Expo]: ../Docs/assets/images/Expo.png 153 | [Circ]: ../Docs/assets/images/Circ.png 154 | [Sine]: ../Docs/assets/images/Sine.png 155 | [Back]: ../Docs/assets/images/Back.png 156 | [Bounce]: ../Docs/assets/images/Bounce.png 157 | [Elastic]: ../Docs/assets/images/Elastic.png 158 | -------------------------------------------------------------------------------- /Docs/Intro.md: -------------------------------------------------------------------------------- 1 | MooTools API Documentation 2 | ========================== 3 | 4 | Popular Pages 5 | ------------- 6 | 7 | - [Class][] - Use MooTools with Class 8 | - [Element][] - Interact with the DOM 9 | - [Element.Event][] - Add events to DOM Elements 10 | - [Element.Delegation][] - Event Delegation 11 | - [Fx.Tween][] - Create effects for single properties 12 | - [Request][] - An XMLHttpRequest Wrapper 13 | 14 | Interesting Blogposts 15 | --------------------- 16 | 17 | - [Setting Up Elements](http://mootools.net/blog/2010/06/10/setting-up-elements/) 18 | - [A Magical Journey into the Base Fx Class](http://mootools.net/blog/2010/05/18/a-magical-journey-into-the-base-fx-class/) 19 | - [Get friendly with the Natives](http://mootools.net/blog/2010/03/23/get-friendly-with-the-natives/) 20 | - [A Better Way to use Elements](http://mootools.net/blog/2010/03/19/a-better-way-to-use-elements/) 21 | - [Events with MooTools - Element, Class, Delegation and Pseudos](http://mootools.net/blog/2011/03/28/events-with-mootools-element-class-delegation-and-pseudos/) 22 | - [Optimizing MooTools builds sans Internet Explorer](http://mootools.net/blog/2012/08/13/optimizing-mootools-builds-sans-internet-explorer/) 23 | 24 | Previous Versions Documentation 25 | ------------------------------- 26 | 27 | - [MooTools 1.2.5 Docs](http://mootools.net/docs/core125) 28 | - [MooTools 1.1 Docs](http://docs111.mootools.net/) 29 | 30 | [Element]: /core/Element/Element 31 | [Element.Event]: /core/Element/Element.Event 32 | [Element.Delegation]: /core/Element/Element.Delegation 33 | [Class]: /core/Class/Class 34 | [Fx.Tween]: /core/Fx/Fx.Tween 35 | [Request]: /core/Request/Request 36 | -------------------------------------------------------------------------------- /Docs/Request/Request.HTML.md: -------------------------------------------------------------------------------- 1 | Class: Request.HTML {#Request-HTML} 2 | =================================== 3 | 4 | Request Specifically made for receiving HTML. 5 | 6 | ### Extends: 7 | 8 | [Request][] 9 | 10 | ### Syntax: 11 | 12 | var myHTMLRequest = new Request.HTML([options]); 13 | 14 | ### Arguments: 15 | 16 | 1. options - (*object*, optional) See options below. Also inherited are all the options from [Request][]. 17 | 18 | ### Options: 19 | 20 | * evalScripts - (*boolean*: defaults to true) If set to true, `script` tags inside the response will be evaluated. This overrides the `false` default from Request. 21 | * update - (*element*: defaults to null) The Element to insert the response text of the Request into upon completion of the request. 22 | * append - (*element*: defaults to null) The Element to append the response text of the Request into upon completion of the request. 23 | * filter - (*mixed*: defaults to null) To filter the response tree by a selector or function. See [Elements:filter][] 24 | 25 | ### Events: 26 | 27 | #### success 28 | 29 | * (*function*) Function to execute when the HTML request completes. This overrides the signature of the Request success event. 30 | 31 | ##### Signature: 32 | 33 | onSuccess(responseTree, responseElements, responseHTML, responseJavaScript) 34 | 35 | ##### Arguments: 36 | 37 | 1. responseTree - (*element*) The node list of the remote response. 38 | 2. responseElements - (*array*) An array containing all elements of the remote response. 39 | 3. responseHTML - (*string*) The content of the remote response. 40 | 4. responseJavaScript - (*string*) The portion of JavaScript from the remote response. 41 | 42 | ### Returns: 43 | 44 | * (*object*) A new Request.HTML instance. 45 | 46 | ### Examples: 47 | 48 | #### Simple GET Request: 49 | 50 | var myHTMLRequest = new Request.HTML().get('myPage.html'); 51 | 52 | #### POST Request with data as String: 53 | 54 | var myHTMLRequest = new Request.HTML({url: 'myPage.html'}).post('user_id=25&save=true'); 55 | 56 | #### Data from Object Passed via GET: 57 | 58 | //Loads "load/?user_id=25". 59 | var myHTMLRequest = new Request.HTML({url: 'load/'}).get({'user_id': 25}); 60 | 61 | #### Data from Element via POST: 62 | 63 | ##### HTML 64 | 65 |
66 |

67 | Search: 68 | Search in description: 69 | 70 |

71 |
72 | 73 | ##### JavaScript 74 | 75 | //Needs to be in a submit event or the form handler. 76 | var myHTMLRequest = new Request.HTML({url: 'save/'}).post($('user-form')); 77 | 78 | ### See Also: 79 | 80 | [Request][] 81 | 82 | 83 | Object: Element.Properties {#Element-Properties} 84 | ============================================== 85 | 86 | see [Element.Properties][] 87 | 88 | Element Property: load {#Element-Properties:load} 89 | ------------------------------------------------- 90 | 91 | ### Setter 92 | 93 | Sets a default Request.HTML instance for an Element. 94 | 95 | #### Syntax: 96 | 97 | el.set('load'[, options]); 98 | 99 | #### Arguments: 100 | 101 | 1. options - (*object*) The Request options. 102 | 103 | #### Returns: 104 | 105 | * (*element*) The target Element. 106 | 107 | #### Example: 108 | 109 | el.set('load', {evalScripts: true}); 110 | el.load('some/request/uri'); 111 | 112 | 113 | ### Getter 114 | 115 | Returns either the previously set Request.HTML instance or a new one with default options. 116 | 117 | #### Syntax: 118 | 119 | el.get('load'); 120 | 121 | #### Arguments: 122 | 123 | 1. property - (*string*) the Request.HTML property argument. 124 | 125 | #### Returns: 126 | 127 | * (*object*) The Request instance. 128 | 129 | #### Example: 130 | 131 | el.set('load', {method: 'get'}); 132 | el.load('test.html'); 133 | // the getter returns the Request.HTML instance, making its class methods available. 134 | el.get('load').post('http://localhost/script'); 135 | 136 | 137 | 138 | Type: Element {#Element} 139 | ======================== 140 | 141 | Custom Type to allow all of its methods to be used with any DOM element via the dollar function [$][]. 142 | 143 | Element Method: load {#Element:load} 144 | ------------------------------------ 145 | 146 | Updates the content of the Element with a Request.HTML GET request. 147 | 148 | ### Syntax: 149 | 150 | myElement.load(url); 151 | 152 | ### Arguments: 153 | 154 | 1. url - (*string*) The URL pointing to the server-side document. 155 | 156 | ### Returns: 157 | 158 | * (*element*) The target Element. 159 | 160 | ### Example: 161 | 162 | ##### HTML 163 | 164 |
Loading content...
165 | 166 | ##### JavaScript 167 | 168 | $('content').load('page_1.html'); 169 | 170 | ### Cross-Origin Resource Sharing (CORS) note: 171 | 172 | The Request.HTML class will (by default) add a custom header that, if used for a cross-origin request, will have to be reported as allowed in the preflight request, in addition to any other headers you may set yourself: 173 | 174 | Access-Control-Allow-Headers: X-Requested-With 175 | 176 | ### See Also: 177 | 178 | - [$][], [Request](/core/Request/Request) 179 | 180 | [Request]: /core/Request/Request 181 | [$]: /core/Element/Element/#Window:dollar 182 | [Element.Properties]: /core/Element/Element/#Element-Properties 183 | [Elements:filter]: /core/Element/Element#Elements:filter 184 | -------------------------------------------------------------------------------- /Docs/Request/Request.JSON.md: -------------------------------------------------------------------------------- 1 | Class: Request.JSON {#Request-JSON} 2 | ================================= 3 | 4 | Wrapped Request with automated receiving of JavaScript Objects in JSON Format. 5 | 6 | ### Extends: 7 | 8 | [Request](/core/Request/Request) 9 | 10 | ### Syntax: 11 | 12 | var myJSONRemote = new Request.JSON([options]); 13 | 14 | ### Arguments: 15 | 16 | 1. options - (*object*, optional) See below. 17 | 18 | ### Options: 19 | 20 | * secure - (*boolean*: defaults to true) If set to true, a syntax check will be done on the result JSON (see [JSON.decode](/Utilities/JSON#JSON:decode)). 21 | 22 | ### Events: 23 | 24 | #### success 25 | 26 | Fired when the request completes. This overrides the signature of the Request success event. 27 | 28 | ##### Signature: 29 | 30 | onSuccess(responseJSON, responseText) 31 | 32 | ##### Arguments: 33 | 34 | 1. responseJSON - (*object*) The JSON response object from the remote request. 35 | 2. responseText - (*string*) The JSON response as string. 36 | 37 | #### error 38 | 39 | Fired when the parsed JSON is not valid and the secure option is set. 40 | 41 | ##### Signature: 42 | 43 | onError(text, error) 44 | 45 | ##### Arguments: 46 | 47 | 1. text - (string) The response text. 48 | 2. error - (string) The error message. 49 | 50 | #### failure 51 | 52 | Fired when the request failed (error status code). 53 | 54 | ##### Signature: 55 | 56 | onFailure(xhr) 57 | 58 | ##### Arguments: 59 | 60 | xhr - (XMLHttpRequest) The transport instance. 61 | 62 | ### Returns: 63 | 64 | * (*object*) A new Request.JSON instance. 65 | 66 | ### Example: 67 | 68 | // this code will send a data object via a GET request and alert the retrieved data. 69 | var jsonRequest = new Request.JSON({url: 'http://site.com/tellMeAge.php', onSuccess: function(person){ 70 | alert(person.age); // alerts "25 years". 71 | alert(person.height); // alerts "170 cm". 72 | alert(person.weight); // alerts "120 kg". 73 | }}).get({'firstName': 'John', 'lastName': 'Doe'}); 74 | 75 | ### Cross-Origin Resource Sharing (CORS) note: 76 | 77 | The Request.JSON class will (by default) add two custom headers that, if used for a cross-origin request, will have to be reported as allowed in the preflight request, in addition to any other headers you may set yourself: 78 | 79 | Access-Control-Allow-Headers: X-Requested-With, X-Request 80 | 81 | ### See Also: 82 | 83 | [Request](/core/Request/Request) 84 | -------------------------------------------------------------------------------- /Docs/Types/DOMEvent.md: -------------------------------------------------------------------------------- 1 | Type: DOMEvent {#Event} 2 | ==================== 3 | 4 | MooTools DOMEvent Methods. 5 | 6 | DOMEvent Method: constructor {#DOMEvent:constructor} 7 | ---------------------------------------------------- 8 | 9 | ### Syntax: 10 | 11 | new DOMEvent([event[, win]]); 12 | 13 | ### Arguments: 14 | 15 | 1. event - (*event*, required) An HTMLEvent Object. 16 | 2. win - (*window*, optional: defaults to window) The context of the event. 17 | 18 | #### Properties: 19 | 20 | * page.x - (*number*) The x position of the mouse, relative to the full window. 21 | * page.y - (*number*) The y position of the mouse, relative to the full window. 22 | * client.x - (*number*) The x position of the mouse, relative to the viewport. 23 | * client.y - (*number*) The y position of the mouse, relative to the viewport. 24 | * rightClick - (*boolean*) True if the user clicked the right mousebutton 25 | * wheel - (*number*) The amount of third button scrolling. 26 | * relatedTarget - (*element*) The event related target. 27 | * target - (*element*) The event target. 28 | * code - (*number*) The keycode of the key pressed. 29 | * key - (*string*) The key pressed as a lowercase string. key can be 'enter', 'up', 'down', 'left', 'right', 'space', 'backspace', 'tab', 'delete', and 'esc'. 30 | * shift - (*boolean*) True if the user pressed the shift key. 31 | * control - (*boolean*) True if the user pressed the control key. 32 | * alt - (*boolean*) True if the user pressed the alt key. 33 | * meta - (*boolean*) True if the user pressed the meta key. 34 | 35 | ### Examples: 36 | 37 | $('myLink').addEvent('keydown', function(event){ 38 | // the passed event parameter is already an instance of the Event type. 39 | alert(event.key); // returns the lowercase letter pressed. 40 | alert(event.shift); // returns true if the key pressed is shift. 41 | if (event.key == 's' && event.control) alert('Document saved.'); //executes if the user presses Ctr+S. 42 | }); 43 | 44 | ### Notes: 45 | 46 | - Accessing event.page / event.client requires the page to be in [Standards Mode](http://hsivonen.iki.fi/doctype/). 47 | - Every event added with addEvent gets the MooTools method automatically, without the need to manually instance it. 48 | - `event.key` is only reliable with `keydown` or `keyup` events. See [PPK](http://www.quirksmode.org/js/keys.html). 49 | 50 | DOMEvent Method: stop {#DOMEvent:stop} 51 | -------------------------------------- 52 | 53 | Stop an event from propagating and also executes preventDefault. 54 | 55 | ### Syntax: 56 | 57 | myEvent.stop(); 58 | 59 | ### Returns: 60 | 61 | * (*object*) This DOMEvent instance. 62 | 63 | ### Examples: 64 | 65 | ##### HTML: 66 | 67 | Visit Google.com 68 | 69 | ##### JavaScript 70 | 71 | $('myAnchor').addEvent('click', function(event){ 72 | event.stop(); //Prevents the browser from following the link. 73 | this.set('text', 'Where do you think you\'re going?'); //'this' is Element that fires the Event. 74 | (function(){ 75 | this.set('text', 'Instead visit the Blog.').set('href', 'http://blog.mootools.net'); 76 | }).delay(500, this); 77 | }); 78 | 79 | ### Notes: 80 | 81 | - Returning false within the function can also stop the propagation of the Event. 82 | 83 | ### See Also: 84 | 85 | - [Element.addEvent](#Element:addEvent), [DOMEvent.stopPropagation](#DOMEvent:stopPropagation), [DOMEvent.preventDefault](#DOMEvent:preventDefault), [Function:delay][] 86 | 87 | 88 | DOMEvent Method: stopPropagation {#DOMEvent:stopPropagation} 89 | ------------------------------------------------------------ 90 | 91 | Cross browser method to stop the propagation of an event (this stops the event from bubbling up through the DOM). 92 | 93 | ### Syntax: 94 | 95 | myEvent.stopPropagation(); 96 | 97 | ### Returns: 98 | 99 | * (*object*) This DOMEvent object. 100 | 101 | ### Examples: 102 | 103 | "#myChild" does not cover the same area as myElement. Therefore, the 'click' differs from parent and child depending on the click location: 104 | 105 | ##### HTML: 106 | 107 |
108 |
109 |
110 | 111 | ##### JavaScript 112 | 113 | $('myElement').addEvent('click', function(){ 114 | alert('click'); 115 | return false; //equivalent to stopPropagation. 116 | }); 117 | $('myChild').addEvent('click', function(event){ 118 | event.stopPropagation(); //prevents the event from bubbling up, and fires the parent's click event. 119 | }); 120 | 121 | ### See Also: 122 | 123 | - [Element:addEvent][] 124 | - [MDN event.stopPropagation][] 125 | 126 | 127 | DOMEvent Method: preventDefault {#DOMEvent:preventDefault} 128 | -------------------------------------------- 129 | 130 | Cross browser method to prevent the default action of the event. 131 | 132 | ### Syntax: 133 | 134 | myEvent.preventDefault(); 135 | 136 | ### Returns: 137 | 138 | * (*object*) This DOMEvent object. 139 | 140 | ### Examples: 141 | 142 | ##### HTML: 143 | 144 |
145 | 146 |
147 | 148 | ##### JavaScript 149 | 150 | $('myCheckbox').addEvent('click', function(event){ 151 | event.preventDefault(); //prevents the checkbox from being "checked". 152 | }); 153 | 154 | ### See Also: 155 | 156 | - [Element:addEvent][] 157 | - [MDN event.preventDefault][] 158 | 159 | 160 | Function: DOMEvent.defineKey {#DOMEvent:DOMEvent-defineKey} 161 | ----------------------------------------------------------- 162 | 163 | This function allows to add an additional event key code. 164 | 165 | #### Example: 166 | 167 | DOMEvent.defineKey(16, 'shift'); 168 | $('myInput').addEvent('keydown', function(event){ 169 | if (event.key == 'shift') alert('You pressed shift.'); 170 | }); 171 | 172 | #### Predefined keys: 173 | 174 | - enter 175 | - up 176 | - down 177 | - left 178 | - right 179 | - esc 180 | - space 181 | - backspace 182 | - tab 183 | - delete 184 | 185 | ### See Also: 186 | 187 | - [MooTools More Keyboard][] 188 | 189 | 190 | Function: DOMEvent.defineKeys {#DOMEvent:DOMEvent-defineKey} 191 | ----------------------------------------------------------- 192 | 193 | This function allows to add additional event key codes. 194 | 195 | #### Example: 196 | 197 | DOMEvent.defineKeys({ 198 | '16': 'shift', 199 | '17': 'control' 200 | }); 201 | $('myInput').addEvent('keydown', function(event){ 202 | if (event.key == 'control') alert('You pressed control.'); 203 | }); 204 | 205 | 206 | [Element:addEvent]: /core/Element/Element.Event#Element:addEvent 207 | [Function]: /core/Types/Function 208 | [Function:bind]: /core/Types/Function/#Function:bind 209 | [Function:pass]: /core/Types/Function/#Function:pass 210 | [Function:delay]: /core/Types/Function/#Function:delay 211 | [MooTools More Keyboard]: /more/Interface/Keyboard 212 | 213 | [MDN event.stopPropagation]: https://developer.mozilla.org/en/DOM/event.stopPropagation 214 | [MDN event.preventDefault]: https://developer.mozilla.org/en/DOM/event.preventDefault 215 | -------------------------------------------------------------------------------- /Docs/Types/Number.md: -------------------------------------------------------------------------------- 1 | Type: Number {#Number} 2 | ====================== 3 | 4 | A collection of the Number Object methods and functions. 5 | 6 | ### See Also: 7 | 8 | - [MDN Number][] 9 | 10 | ### Notes: 11 | 12 | Every Math method is mirrored in the Number object, both as prototype and generic. 13 | 14 | 15 | 16 | Function: Number.convert {#Number:Number:convert} 17 | ------------------------------------ 18 | 19 | Returns the passed parameter as a Number, or null if not a number. 20 | 21 | ### Syntax: 22 | 23 | Number.convert(arg); 24 | 25 | ### Arguments: 26 | 27 | 1. arg - (*mixed*) The argument to return as a number. 28 | 29 | ### Returns: 30 | 31 | * (*number*) The argument as a number. 32 | * (*null*) Returns null if the number cannot be converted. 33 | 34 | ### Example: 35 | 36 | Number.convert('12') // returns 12 37 | Number.convert('hello') // returns null 38 | 39 | 40 | 41 | Function: Number.random {#Number:Number-random} 42 | ---------------------------------------- 43 | 44 | Returns a random integer between the two passed in values. 45 | 46 | ### Syntax: 47 | 48 | var random = Number.random(min, max); 49 | 50 | ### Arguments: 51 | 52 | 1. min - (*number*) The minimum value (inclusive). 53 | 2. max - (*number*) The maximum value (inclusive). 54 | 55 | ### Returns: 56 | 57 | * (*number*) A random number between min and max. 58 | 59 | ### Example: 60 | 61 | Number.random(5, 20); // returns a random number between 5 and 20. 62 | 63 | 64 | 65 | Number method: limit {#Number:limit} 66 | ----------------------------- 67 | 68 | Limits this number between two bounds. 69 | 70 | ### Syntax: 71 | 72 | myNumber.limit(min, max); 73 | 74 | ### Arguments: 75 | 76 | 1. min - (*number*) The minimum possible value. 77 | 2. max - (*number*) The maximum possible value. 78 | 79 | ### Returns: 80 | 81 | * (*number*) The number bounded between the given limits. 82 | 83 | ### Examples: 84 | 85 | (12).limit(2, 6.5); // returns 6.5 86 | (-4).limit(2, 6.5); // returns 2 87 | (4.3).limit(2, 6.5); // returns 4.3 88 | 89 | 90 | 91 | Number method: round {#Number:round} 92 | ----------------------------- 93 | 94 | Returns this number rounded to the specified precision. 95 | 96 | ### Syntax: 97 | 98 | myNumber.round([precision]); 99 | 100 | ### Arguments: 101 | 102 | 1. precision - (*number*, optional: defaults to 0) The number of digits after the decimal place. 103 | 104 | ### Returns: 105 | 106 | * (number) The number, rounded. 107 | 108 | ### Notes: 109 | 110 | - Argument may also be negative. 111 | 112 | ### Examples: 113 | 114 | (12.45).round() // returns 12 115 | (12.45).round(1) // returns 12.5 116 | (12.45).round(-1) // returns 10 117 | 118 | 119 | 120 | Number method: times {#Number:times} 121 | ----------------------------- 122 | 123 | Executes the function passed in the specified number of times. 124 | 125 | ### Syntax: 126 | 127 | myNumber.times(fn[, bind]); 128 | 129 | ### Arguments: 130 | 131 | 1. fn - (*function*) The function which should be executed on each iteration of the loop. This function is passed the current iteration's index. 132 | 2. bind - (*object*, optional) The object to use as 'this' in the function. For more information see [Function:bind][]. 133 | 134 | ### Examples: 135 | 136 | (4).times(alert); // alerts "0", then "1", then "2", then "3". 137 | 138 | 139 | 140 | Number method: toFloat {#Number:toFloat} 141 | --------------------------------- 142 | 143 | Returns this number as a float. Useful because toFloat must work on both Strings and Numbers. 144 | 145 | ### Syntax: 146 | 147 | myNumber.toFloat(); 148 | 149 | ### Returns: 150 | 151 | * (*number*) The number as a float. 152 | 153 | ### Examples: 154 | 155 | (111).toFloat(); // returns 111 156 | (111.1).toFloat(); // returns 111.1 157 | 158 | 159 | 160 | Number method: toInt {#Number:toInt} 161 | ----------------------------- 162 | 163 | Returns this number as another number with the passed in base. Useful because toInt must work on both Strings and Numbers. 164 | 165 | ### Syntax: 166 | 167 | myNumber.toInt([base]); 168 | 169 | ### Arguments: 170 | 171 | 1. base - (*number*, optional: defaults to 10) The base to use. 172 | 173 | ### Returns: 174 | 175 | * (*number*) A number with the base provided. 176 | 177 | ### Examples: 178 | 179 | (111).toInt(); // returns 111 180 | (111.1).toInt(); // returns 111 181 | (111).toInt(2); // returns 7 182 | 183 | 184 | Math Methods {#Number-Math} 185 | -------------------- 186 | 187 | There are several methods available from the Math object that can be used as Number Methods. 188 | 189 | - abs 190 | - acos 191 | - asin 192 | - atan2 193 | - ceil 194 | - cos 195 | - exp 196 | - floor 197 | - log 198 | - max 199 | - min 200 | - pow 201 | - sin 202 | - sqrt 203 | - tan 204 | 205 | ### Examples: 206 | 207 | (-1).abs(); // returns 1 208 | (3).pow(4); // returns 81 209 | 210 | 211 | [Function:bind]: /core/Types/Function/#Function:bind 212 | [MDN Number]: https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Number 213 | -------------------------------------------------------------------------------- /Docs/Utilities/Cookie.md: -------------------------------------------------------------------------------- 1 | # Object: Cookie {#Cookie} 2 | 3 | Reads and writes a cookie. 4 | 5 | ## Options: {#Cookie-options} 6 | 7 | * domain - (*string*: defaults to false) The domain the cookie belongs to. 8 | * path - (*string*: defaults to '/') The path the cookie belongs to. 9 | * duration - (*number*: defaults to false) The duration of the cookie (in days) before it expires. If set to false or 0, the cookie will be a session cookie that expires when the browser is closed. 10 | * secure - (*boolean*: defaults to false) Stored cookie information can be accessed only from a secure environment. 11 | * httpOnly - (*boolean*: defaults to false) Stored cookie information can be accessed only on the server. 12 | 13 | ## Cookie Method: write {#Cookie:write} 14 | 15 | Writes a cookie in the browser. 16 | 17 | ### Syntax: 18 | 19 | var myCookie = Cookie.write(key, value[, options]); 20 | 21 | ### Arguments: 22 | 23 | 1. key - (*string*) The key (or name) of the cookie. 24 | 2. value - (*string*) The value to set. Cannot contain semicolons. 25 | 3. options - (*mixed*, optional) See [Cookie][]. 26 | 27 | ### Returns: 28 | 29 | * (*object*) An object with the options, the key and the value. You can give it as first parameter to [Cookie.dispose][]. 30 | 31 | ### Examples: 32 | 33 | Saves the cookie for the duration of the session: 34 | 35 | var myCookie = Cookie.write('username', 'JackBauer'); 36 | 37 | Saves the cookie for a day: 38 | 39 | var myCookie = Cookie.write('username', 'JackBauer', {duration: 1}); 40 | 41 | ### Note: 42 | 43 | In order to share the cookie with pages located in a different path, the [Cookie.options.domain][Cookie.options] value must be set. 44 | 45 | ## Cookie Method: read {#Cookie:read} 46 | 47 | Reads the value of a cookie. 48 | 49 | ### Syntax: 50 | 51 | var myCookie = Cookie.read(name); 52 | 53 | ### Arguments: 54 | 55 | 1. name - (*string*) The name of the cookie to read. 56 | 57 | ### Returns: 58 | 59 | * (*mixed*) The cookie string value, or null if not found. 60 | 61 | ### Example: 62 | 63 | Cookie.read('username'); 64 | 65 | ## Cookie Method: dispose {#Cookie:dispose} 66 | 67 | Removes a cookie from the browser. 68 | 69 | ### Syntax: 70 | 71 | var oldCookie = Cookie.dispose(name[, options]); 72 | 73 | ### Arguments: 74 | 75 | 1. name - (*string*) The name of the cookie to remove or a previously saved Cookie instance. 76 | 2. options - (*object*, optional) See [Cookie][]. 77 | 78 | ### Examples: 79 | 80 | Remove a Cookie: 81 | 82 | Cookie.dispose('username'); // Bye-bye JackBauer! 83 | 84 | Creating a cookie and removing it right away: 85 | 86 | var myCookie = Cookie.write('username', 'JackBauer', {domain: 'mootools.net'}); 87 | if (Cookie.read('username') == 'JackBauer') { myCookie.dispose(); } 88 | 89 | ### Credits: 90 | 91 | - Based on the functions by Peter-Paul Koch of [QuirksMode][]. 92 | 93 | [Cookie.dispose]: #Cookie:dispose 94 | [Cookie.options]: #Cookie-options 95 | [Cookie]: #Cookie 96 | [QuirksMode]: http://www.quirksmode.org 97 | -------------------------------------------------------------------------------- /Docs/Utilities/DOMReady.md: -------------------------------------------------------------------------------- 1 | # Window Event: domready 2 | 3 | Contains the window [Event][] 'domready', which executes when the DOM is loaded. 4 | 5 | To ensure that DOM elements exist when the code attempts to access them is executed, they need to be placed within the 'domready' event. 6 | 7 | ### Example: 8 | 9 | window.addEvent('domready', function() { 10 | alert('The DOM is ready!'); 11 | }); 12 | 13 | ### Notes: 14 | 15 | - This event is only available to the window element. 16 | - In some versions of Internet Explorer (ie. IE6) a script tag might be executed twice if the content-type meta-tag declaration is put after a script tag. The content-type should always be declared before any script tags. 17 | 18 | ### See Also: 19 | [Element.Event][Event] 20 | 21 | [Event]: /core/Element/Element.Event 22 | -------------------------------------------------------------------------------- /Docs/Utilities/JSON.md: -------------------------------------------------------------------------------- 1 | # Object: JSON {#JSON} 2 | 3 | JSON decoder and encoder. 4 | 5 | ## JSON Method: encode {#JSON:encode} 6 | 7 | Converts an object or array to a JSON string. 8 | 9 | ### Syntax: 10 | 11 | var myJSON = JSON.encode(obj); 12 | 13 | ### Arguments: 14 | 15 | 1. obj - (*object*) The object to convert to string. 16 | 17 | ### Returns: 18 | 19 | * (*string*) A JSON string. 20 | 21 | ### Examples: 22 | 23 | var fruitsJSON = JSON.encode({apple: 'red', lemon: 'yellow'}); // returns: '{"apple":"red","lemon":"yellow"}' 24 | 25 | ## JSON Method: decode {#JSON:decode} 26 | 27 | Converts a JSON string into a JavaScript object. 28 | 29 | ### Syntax: 30 | 31 | var object = JSON.decode(string[, secure]); 32 | 33 | ### Arguments: 34 | 35 | 1. string - (*string*) The string to evaluate. 36 | 2. secure - (*boolean*, optional: defaults to true) If set to true, checks for any hazardous syntax and returns null if any found. 37 | 38 | There is also a global option `JSON.secure` (*boolean*: defaults to true). If the optional `secure` argument is not defined, the value of `JSON.secure` will be used. 39 | 40 | ### Returns: 41 | 42 | * (*object*) The object represented by the JSON string. 43 | 44 | ### Examples: 45 | 46 | var myObject = JSON.decode('{"apple":"red","lemon":"yellow"}'); // returns: {apple: 'red', lemon: 'yellow'} 47 | 48 | ### See Also: 49 | 50 | - [JSON (JavaScript Object Notation)][] 51 | 52 | ### Credits: 53 | 54 | - JSON test regular expression by [Douglas Crockford][] and [Tobie Langel][]. 55 | 56 | [Douglas Crockford]: http://crockford.com/ 57 | [JSON (JavaScript Object Notation)]: http://www.json.org/ 58 | [Tobie Langel]: http://tobielangel.com/ 59 | -------------------------------------------------------------------------------- /Docs/license.md: -------------------------------------------------------------------------------- 1 | Attribution-NonCommercial-ShareAlike 3.0 2 | ======================================== 3 | 4 | 5 | 6 | ## See Also 7 | 8 | 9 | -------------------------------------------------------------------------------- /Grunt/options/browsers.json: -------------------------------------------------------------------------------- 1 | { 2 | "phantomjs": { 3 | "base": "PhantomJS" 4 | }, 5 | "chrome": { 6 | "base": "SauceLabs", 7 | "platform": "Linux", 8 | "browserName": "chrome" 9 | }, 10 | "firefox": { 11 | "base": "SauceLabs", 12 | "platform": "Linux", 13 | "browserName": "firefox" 14 | }, 15 | "edge": { 16 | "base": "SauceLabs", 17 | "platform": "Windows 10", 18 | "browserName": "microsoftedge" 19 | }, 20 | "opera12": { 21 | "base": "SauceLabs", 22 | "platform": "Windows 7", 23 | "browserName": "opera", 24 | "version": "12" 25 | }, 26 | "safari9": { 27 | "base": "SauceLabs", 28 | "platform": "OS X 10.11", 29 | "browserName": "safari", 30 | "version": "9" 31 | }, 32 | "safari8": { 33 | "base": "SauceLabs", 34 | "platform": "OS X 10.10", 35 | "browserName": "safari", 36 | "version": "8" 37 | }, 38 | "safari7": { 39 | "base": "SauceLabs", 40 | "platform": "OS X 10.9", 41 | "browserName": "safari", 42 | "version": "7" 43 | }, 44 | "safari6": { 45 | "base": "SauceLabs", 46 | "platform": "OS X 10.8", 47 | "browserName": "safari", 48 | "version": "6" 49 | }, 50 | "safari5_osx": { 51 | "base": "SauceLabs", 52 | "platform": "OS X 10.6", 53 | "browserName": "safari", 54 | "version": "5" 55 | }, 56 | "safari5_windows": { 57 | "base": "SauceLabs", 58 | "platform": "Windows 7", 59 | "browserName": "safari", 60 | "version": "5" 61 | }, 62 | "ie11": { 63 | "base": "SauceLabs", 64 | "platform": "Windows 8.1", 65 | "browserName": "internet explorer", 66 | "version": "11" 67 | }, 68 | "ie10": { 69 | "base": "SauceLabs", 70 | "platform": "Windows 8", 71 | "browserName": "internet explorer", 72 | "version": "10" 73 | }, 74 | "ie9": { 75 | "base": "SauceLabs", 76 | "platform": "Windows 7", 77 | "browserName": "internet explorer", 78 | "version": "9" 79 | }, 80 | "ie8": { 81 | "base": "SauceLabs", 82 | "platform": "Windows 7", 83 | "browserName": "internet explorer", 84 | "version": "8" 85 | }, 86 | "ie7": { 87 | "base": "SauceLabs", 88 | "platform": "Windows XP", 89 | "browserName": "internet explorer", 90 | "version": "7" 91 | }, 92 | "ie6": { 93 | "base": "SauceLabs", 94 | "platform": "Windows XP", 95 | "browserName": "internet explorer", 96 | "version": "6" 97 | }, 98 | "android": { 99 | "base": "SauceLabs", 100 | "platform": "Linux", 101 | "browserName": "android", 102 | "deviceOrientation": "portrait" 103 | }, 104 | "iphone": { 105 | "base": "SauceLabs", 106 | "platform": "OS X 10.10", 107 | "browserName": "iphone", 108 | "deviceOrientation": "portrait" 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /Grunt/options/build.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(grunt){ 4 | var dir = grunt.config.get('environment.dir'), 5 | build = grunt.config.get('environment.build'), 6 | travis = grunt.config.get('environment.travis'); 7 | 8 | var config = { 9 | clean: { 10 | 'build': {src: dir.build + '/mootools-*.js'} 11 | }, 12 | karma: { 13 | 'run': { 14 | options: { 15 | files: [dir.build + '/mootools-core.js', dir.build + '/mootools-specs.js'] 16 | } 17 | }, 18 | 'dev': { 19 | options: { 20 | files: [dir.build + '/mootools-core.js', dir.build + '/mootools-specs.js'] 21 | }, 22 | singleRun: false, 23 | captureTimeout: 0 24 | }, 25 | 'travis': { 26 | options: { 27 | files: [dir.build + '/mootools-core.js', dir.build + '/mootools-specs.js'] 28 | }, 29 | reporters: ['progress', 'saucelabs'], 30 | browsers: [travis.browser] 31 | } 32 | }, 33 | mochaTest: { 34 | 'run': { 35 | src: [dir.build + '/mootools-core.js', dir.build + '/mootools-specs.js'] 36 | }, 37 | 'dev': { 38 | options: { 39 | watch: true 40 | }, 41 | src: [dir.build + '/mootools-core.js', dir.build + '/mootools-specs.js'] 42 | }, 43 | 'travis': { 44 | src: [dir.build + '/mootools-core.js', dir.build + '/mootools-specs.js'] 45 | } 46 | }, 47 | packager: { 48 | 'compat': { 49 | options: { 50 | strip: build.compat.strip, 51 | only: build.compat.components 52 | }, 53 | src: build.compat.sources, 54 | dest: dir.build + '/mootools-core.js' 55 | }, 56 | 'nocompat': { 57 | options: { 58 | strip: build.nocompat.strip, 59 | only: build.nocompat.components 60 | }, 61 | src: build.nocompat.sources, 62 | dest: dir.build + '/mootools-core.js' 63 | }, 64 | 'server': { 65 | options: { 66 | strip: build.server.strip, 67 | only: build.server.components 68 | }, 69 | src: build.server.sources, 70 | dest: dir.build + '/mootools-core.js' 71 | } 72 | }, 73 | eslint: { 74 | 'compat': { 75 | src: ['Gruntfile.js', 'Grunt/{options,tasks}/*.js', build.compat.sources, build.compat.specs] 76 | }, 77 | 'nocompat': { 78 | src: ['Gruntfile.js', 'Grunt/{options,tasks}/*.js', build.nocompat.sources, build.nocompat.specs] 79 | }, 80 | 'server': { 81 | src: ['Gruntfile.js', 'Grunt/{options,tasks}/*.js', build.server.sources, build.server.specs] 82 | } 83 | } 84 | }; 85 | 86 | return config; 87 | }; 88 | -------------------------------------------------------------------------------- /Grunt/options/dist.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(grunt){ 4 | var dir = grunt.config.get('environment.dir'), 5 | build = grunt.config.get('environment.build'); 6 | 7 | var config = { 8 | clean: { 9 | 'dist': {src: dir.dist + '/mootools-*.js'}, 10 | 'dist-compat': {src: [dir.dist + '/' + build.compat.name + '.js', dir.dist + '/' + build.compat.name + '.min.js']}, 11 | 'dist-nocompat': {src: [dir.dist + '/' + build.nocompat.name + '.js', dir.dist + '/' + build.nocompat.name + '.min.js']}, 12 | 'dist-server': {src: dir.dist + '/' + build.server.name + '.js'} 13 | }, 14 | karma: { 15 | 'dist-compat': { 16 | options: { 17 | files: [dir.dist + '/' + build.compat.name + '.js', dir.build + '/mootools-specs.js'] 18 | } 19 | }, 20 | 'dist-compat-minified': { 21 | options: { 22 | files: [dir.dist + '/' + build.compat.name + '.min.js', dir.build + '/mootools-specs.js' ] 23 | } 24 | }, 25 | 'dist-nocompat': { 26 | options: { 27 | files: [dir.dist + '/' + build.nocompat.name + '.js', dir.build + '/mootools-specs.js'] 28 | } 29 | }, 30 | 'dist-nocompat-minified': { 31 | options: { 32 | files: [dir.dist + '/' + build.nocompat.name + '.min.js', dir.build + '/mootools-specs.js'] 33 | } 34 | } 35 | }, 36 | mochaTest: { 37 | 'dist-server': { 38 | src: [dir.dist + '/' + build.server.name + '.js', dir.build + '/mootools-specs.js'] 39 | } 40 | }, 41 | packager: { 42 | 'dist-compat': { 43 | options: { 44 | strip: build.compat.strip, 45 | only: build.compat.components 46 | }, 47 | src: build.compat.sources, 48 | dest: dir.dist + '/' + build.compat.name + '.js' 49 | }, 50 | 'dist-nocompat': { 51 | options: { 52 | strip: build.nocompat.strip, 53 | only: build.nocompat.components 54 | }, 55 | src: build.nocompat.sources, 56 | dest: dir.dist + '/' + build.nocompat.name + '.js' 57 | }, 58 | 'dist-server': { 59 | options: { 60 | strip: build.server.strip, 61 | only: build.server.components 62 | }, 63 | src: build.server.sources, 64 | dest: dir.dist + '/' + build.server.name + '.js' 65 | } 66 | }, 67 | uglify: { 68 | 'dist-compat': { 69 | files: [ 70 | {src: dir.dist + '/' + build.compat.name + '.js', dest: dir.dist + '/' + build.compat.name + '.min.js'} 71 | ] 72 | }, 73 | 'dist-nocompat': { 74 | files: [ 75 | {src: dir.dist + '/' + build.nocompat.name + '.js', dest: dir.dist + '/' + build.nocompat.name + '.min.js'} 76 | ] 77 | } 78 | } 79 | }; 80 | 81 | return config; 82 | }; 83 | -------------------------------------------------------------------------------- /Grunt/options/options.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var browsers = require('./browsers'); 5 | 6 | module.exports = function(grunt){ 7 | var travis = grunt.config.get('environment.travis'), 8 | sauceLabs = grunt.config.get('environment.sauceLabs'); 9 | 10 | var config = { 11 | karma: { 12 | options: { 13 | singleRun: true, 14 | captureTimeout: 60000 * 2, 15 | frameworks: ['expect', 'mocha', 'sinon', 'syn'], 16 | plugins: ['karma-*', path.resolve('Grunt/plugins/karma/syn')], 17 | reporters: ['progress'], 18 | browsers: ['PhantomJS'], 19 | sauceLabs: { 20 | username: sauceLabs.username, 21 | accessKey: sauceLabs.accessKey, 22 | testName: 'MooTools-Core. Build: ' + travis.build + '. Browser: ' + travis.browser 23 | }, 24 | customLaunchers: browsers 25 | } 26 | }, 27 | mochaTest: { 28 | options: { 29 | reporter: 'dot', 30 | require: function(){ 31 | global.expect = require('expect.js'); 32 | global.sinon = require('sinon'); 33 | } 34 | } 35 | }, 36 | packager: { 37 | options: { 38 | name: 'Core' 39 | } 40 | }, 41 | uglify: { 42 | options: { 43 | mangle: false, 44 | compress: true, 45 | preserveComments: 'some' 46 | } 47 | }, 48 | eslint: { 49 | options: { 50 | rulePaths: ['Grunt/plugins/eslint/rules'] 51 | } 52 | } 53 | }; 54 | 55 | return config; 56 | }; 57 | -------------------------------------------------------------------------------- /Grunt/options/specs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(grunt){ 4 | var dir = grunt.config.get('environment.dir'), 5 | build = grunt.config.get('environment.build'); 6 | 7 | var config = { 8 | clean: { 9 | 'specs': {src: dir.build + '/mootools-specs.js'} 10 | }, 11 | packager: { 12 | 'specs-compat': { 13 | options: { 14 | name: 'Specs', 15 | strip: build.compat.strip 16 | }, 17 | src: build.compat.specs, 18 | dest: dir.build + '/mootools-specs.js' 19 | }, 20 | 'specs-nocompat': { 21 | options: { 22 | name: 'Specs', 23 | strip: build.nocompat.strip 24 | }, 25 | src: build.nocompat.specs, 26 | dest: dir.build + '/mootools-specs.js' 27 | }, 28 | 'specs-server': { 29 | options: { 30 | name: 'Specs', 31 | strip: build.server.strip 32 | }, 33 | src: build.server.specs, 34 | dest: dir.build + '/mootools-specs.js' 35 | } 36 | } 37 | }; 38 | 39 | return config; 40 | }; 41 | -------------------------------------------------------------------------------- /Grunt/plugins/eslint/rules/mootools-whitespace.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var rules = [ 4 | {regex: /function\s+\(/g, message: 'Unexpected whitespace between "function" and "("'}, 5 | {regex: /\)\s+{/g, message: 'Unexpected whitespace between ")" and "{"'}, 6 | {regex: /(catch|for|if|switch|while|with)\(/g, message: 'Expected whitespace between "%s" and "(" but found none'}, 7 | {regex: /}(catch|else|finally)/g, message: 'Expected whitespace between "}" and "%s" but found none'}, 8 | {regex: /(do|else|finally|try){/g, message: 'Expected whitespace between "%s" and "{" but found none'} 9 | ]; 10 | 11 | module.exports = function(context){ 12 | var errors = []; 13 | 14 | function checkForIrregularWhitespace(node){ 15 | context.getSourceLines().forEach(function(line, index){ 16 | rules.forEach(function(rule){ 17 | var loc, 18 | match; 19 | 20 | while ((match = rule.regex.exec(line)) !== null){ 21 | loc = { 22 | line: index + 1, 23 | column: match.index 24 | }; 25 | errors.push([node, loc, rule.message.replace('%s', match[1])]); 26 | } 27 | }); 28 | }); 29 | } 30 | 31 | return { 32 | 'Program': function(node){ 33 | checkForIrregularWhitespace(node); 34 | }, 35 | 'Program:exit': function(){ 36 | errors.forEach(function(error){ 37 | context.report.apply(context, error); 38 | }); 39 | } 40 | }; 41 | }; 42 | 43 | module.exports.schema = []; 44 | -------------------------------------------------------------------------------- /Grunt/plugins/karma/syn/index.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | 3 | var createPattern = function(path){ 4 | return {pattern: path, included: true, served: true, watched: false}; 5 | }; 6 | 7 | //var initSyn = function(files){ 8 | // files.unshift(createPattern(path.join(__dirname, 'post-amd.js'))); 9 | // files.unshift(createPattern(path.resolve(require.resolve('syn'), '../../syn.js'))); 10 | // files.unshift(createPattern(path.join(__dirname, 'pre-amd.js'))); 11 | //}; 12 | 13 | var initSyn = function(files){ 14 | // Local version that works in IE9 and IE10. 15 | files.unshift(createPattern(path.join(__dirname, 'lib/syn.js'))); 16 | }; 17 | 18 | initSyn.$inject = ['config.files']; 19 | 20 | module.exports = { 21 | 'framework:syn': ['factory', initSyn] 22 | }; 23 | -------------------------------------------------------------------------------- /Grunt/plugins/karma/syn/post-amd.js: -------------------------------------------------------------------------------- 1 | // Distribution versions of syn add a global AMD-style define function. 2 | // Let's make sure we restore whatever existed before loading syn. 3 | 4 | window.define = window._karma_syn.define; 5 | window._karma_syn = undefined; 6 | -------------------------------------------------------------------------------- /Grunt/plugins/karma/syn/pre-amd.js: -------------------------------------------------------------------------------- 1 | // Distribution versions of syn add a global AMD-style define function. 2 | // Let's make sure we can restore whatever exists before loading syn. 3 | 4 | window._karma_syn = {}; 5 | window._karma_syn.define = window.define; 6 | -------------------------------------------------------------------------------- /Grunt/tasks/tasks.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(grunt){ 4 | var travis = grunt.config.get('environment.travis'); 5 | 6 | var build = { 7 | compat: ['eslint:compat', 'clean:build', 'packager:compat', 'packager:specs-compat'], 8 | nocompat: ['eslint:nocompat', 'clean:build', 'packager:nocompat', 'packager:specs-nocompat'], 9 | server: ['eslint:server', 'clean:build', 'packager:server', 'packager:specs-server'] 10 | }, 11 | dist = { 12 | compat: ['clean:dist-compat', 'clean:specs', 'packager:dist-compat', 'uglify:dist-compat', 'packager:specs-compat'], 13 | nocompat: ['clean:dist-nocompat', 'clean:specs', 'packager:dist-nocompat', 'uglify:dist-nocompat', 'packager:specs-nocompat'], 14 | server: ['clean:dist-server', 'clean:specs', 'packager:dist-server', 'packager:specs-server'] 15 | }; 16 | 17 | grunt.registerTask('compat', build.compat.concat('karma:run', 'clean:specs')); 18 | grunt.registerTask('compat:test', build.compat.concat('karma:run', 'clean:build')); 19 | grunt.registerTask('compat:dev', build.compat.concat('karma:dev')); 20 | grunt.registerTask('compat:dist', dist.compat.concat('karma:dist-compat', 'karma:dist-compat-minified', 'clean:specs')); 21 | 22 | grunt.registerTask('nocompat', build.nocompat.concat('karma:run', 'clean:specs')); 23 | grunt.registerTask('nocompat:test', build.nocompat.concat('karma:run', 'clean:build')); 24 | grunt.registerTask('nocompat:dev', build.nocompat.concat('karma:dev')); 25 | grunt.registerTask('nocompat:dist', dist.nocompat.concat('karma:dist-nocompat', 'karma:dist-nocompat-minified', 'clean:specs')); 26 | 27 | grunt.registerTask('server', build.server.concat('mochaTest:run', 'clean:specs')); 28 | grunt.registerTask('server:test', build.server.concat('mochaTest:run', 'clean:build')); 29 | grunt.registerTask('server:dev', build.server.concat('mochaTest:dev')); 30 | grunt.registerTask('server:dist', dist.server.concat('mochaTest:dist-server', 'clean:specs')); 31 | 32 | grunt.registerTask('test', ['compat:test', 'nocompat:test', 'server:test']); 33 | grunt.registerTask('dist', ['clean:dist', 'compat:dist', 'nocompat:dist', 'server:dist']); 34 | 35 | grunt.registerTask('travis', function(){ 36 | if (!travis.enabled){ 37 | grunt.fail.warn('This does not appear to be travis-ci.'); 38 | } 39 | if (!build[travis.build]){ 40 | grunt.fail.fatal('Unknown build "' + travis.build + '".\nValid builds: ' + Object.keys(build).join(', ') + '.'); 41 | } 42 | 43 | if (travis.build == 'server'){ 44 | grunt.task.run(build[travis.build].concat('mochaTest:travis')); 45 | } else if (travis.browser == 'phantomjs' || !travis.pullRequest){ 46 | var browsers = grunt.config.get('karma.options.customLaunchers'); 47 | if (!browsers[travis.browser]){ 48 | grunt.fail.fatal('Unknown browser "' + travis.browser + '".\nValid browsers: ' + Object.keys(browsers).join(', ') + '.'); 49 | } 50 | grunt.task.run(build[travis.build].concat('karma:travis')); 51 | } else { 52 | grunt.log.writeln('This appears to be a Pull Request.'); 53 | grunt.log.writeln('Unfortunately we cannot run browser tests for Pull Requests.'); 54 | } 55 | }); 56 | 57 | grunt.registerTask('default', function(){ 58 | if (travis.enabled){ 59 | grunt.log.writeln('Detected travis-ci environment.'); 60 | grunt.option('verbose', true); 61 | grunt.task.run('travis'); 62 | } else { 63 | grunt.log.writeln('Running all tests.'); 64 | grunt.task.run('test'); 65 | } 66 | }); 67 | }; 68 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(grunt){ 4 | require('load-grunt-tasks')(grunt); 5 | 6 | var pkg = grunt.file.readYAML('package.yml'); 7 | 8 | var config = { 9 | environment: { 10 | dir: { 11 | dist: 'dist', 12 | build: 'build' 13 | }, 14 | build: { 15 | compat: { 16 | name: 'mootools-core-compat', 17 | sources: pkg.sources, 18 | specs: 'Specs/**/*.js' 19 | }, 20 | nocompat: { 21 | name: 'mootools-core', 22 | sources: pkg.sources, 23 | strip: ['.*compat'], 24 | specs: 'Specs/**/*.js' 25 | }, 26 | server: { 27 | name: 'mootools-core-server', 28 | sources: pkg.sources, 29 | components: ['Core/Core', 'Core/Array', 'Core/String', 'Core/Number', 'Core/Function', 'Core/Object', 'Core/Class', 'Core/Class.Extras', 'Core/Class.Thenable', 'Core/JSON'], 30 | strip: ['1.2compat', '1.3compat', '1.4compat', '*compat', 'IE', 'ltIE8', 'ltIE9', '!ES5', '!ES5-bind', 'webkit', 'ltFF4'], 31 | specs: ['Specs/Core/*.js', 'Specs/Class/*.js', 'Specs/Types/*.js', 'Specs/Utilities/JSON.js'], 32 | uglify: false 33 | } 34 | }, 35 | travis: { 36 | enabled: (process.env.TRAVIS === 'true'), 37 | pullRequest: (process.env.TRAVIS_PULL_REQUEST !== 'false'), 38 | browser: process.env.BROWSER, 39 | build: process.env.BUILD 40 | }, 41 | sauceLabs: { 42 | username: process.env.SAUCE_USERNAME, 43 | accessKey: process.env.SAUCE_ACCESS_KEY 44 | } 45 | } 46 | }; 47 | 48 | if (grunt.option('file') || grunt.option('module')){ 49 | Object.getOwnPropertyNames(config.environment.build).forEach(function(name){ 50 | var build = config.environment.build[name]; 51 | if (grunt.option('file')){ 52 | if (build.components == null || build.components.indexOf('Core/' + grunt.option('file')) !== -1){ 53 | build.components = 'Core/' + grunt.option('file'); 54 | build.specs = grunt.file.match('Specs/**/' + grunt.option('file') + '.js', grunt.file.expand(build.specs)); 55 | } else { 56 | build.components = []; 57 | build.specs = []; 58 | } 59 | } 60 | if (grunt.option('module')){ 61 | build.specs = grunt.file.match('Specs/' + grunt.option('module') + '/**.js', grunt.file.expand(build.specs)); 62 | } 63 | }); 64 | } 65 | 66 | grunt.initConfig(config); 67 | grunt.util.linefeed = '\n'; 68 | 69 | grunt.file.expand('./Grunt/options/*.js').forEach(function(file){ 70 | grunt.config.merge(require(file)(grunt)); 71 | }); 72 | 73 | grunt.loadTasks('Grunt/tasks'); 74 | }; 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MooTools Core 2 | 3 | [![Build Status](https://travis-ci.org/mootools/mootools-core.png?branch=master)](https://travis-ci.org/mootools/mootools-core) 4 | 5 | [![Selenium Test Status](https://saucelabs.com/browser-matrix/MooTools-Core.svg)](https://saucelabs.com/u/MooTools-Core) 6 | 7 | --- 8 | 9 | This repository is for MooTools developers; not users. 10 | All users should download MooTools from [MooTools.net](http://mootools.net/download "Download MooTools") 11 | 12 | --- 13 | ## Contribute 14 | 15 | You are welcome to contribute to MooTools! What we ask of you: 16 | 17 | a. __To report a bug:__ 18 | 19 | 1. Create a [jsFiddle](http://jsfiddle.net/) with the minimal amount of code to reproduce the bug. 20 | 2. Create a [GitHub Issue](https://github.com/mootools/mootools-core/issues), and link to the jsFiddle. 21 | 22 | b. __To fix a bug:__ 23 | 24 | 1. Clone the repo. 25 | 2. Add a [spec](https://github.com/Automattic/expect.js#api). 26 | 3. Fix the bug. 27 | 4. Build and run the specs. 28 | 5. Push to your GitHub fork. 29 | 6. Create Pull Request, and send Pull Request. 30 | 31 | 32 | __Do try to contribute!__ This is a community project. 33 | 34 | 35 | ## Building & Testing 36 | 37 | Current build process uses [Grunt](http://github.com/gruntjs), [Grunt MooTools Packager plugin](https://github.com/ibolmo/grunt-packager), and [Karma related repos](http://github.com/karma-runner/grunt-karma). 38 | 39 | **By default**, the build process runs the tests (specs) relevant to the build. To build without testing see the `packager` build targets. 40 | 41 | ### Building MooTools _With_ Compatibility 42 | This means `1.5.1` that is compatible with: `1.4.6`, `1.3.x`, `1.2.x`, and so on. 43 | 44 | **Examples** 45 | 46 | grunt compat # or 47 | grunt packager:compat # to only build the source 48 | 49 | ### Building MooTools _Without_ Compatibility 50 | This means `1.5.1` **without** deprecated code in `1.4.6`, `1.3.x`, `1.2.x`, and so on. 51 | 52 | ``` js 53 | 'Proceed at your own risk' 54 | See the changelog or the blog related to each version for migrating your code. 55 | ``` 56 | 57 | **Examples** 58 | 59 | grunt nocompat # or 60 | grunt packager:nocompat # to only build the source 61 | 62 | 63 | ### Advanced Building and Testing 64 | See the [Gruntfile](https://github.com/mootools/mootools-core/blob/master/Gruntfile.js) and [MooTools packager](https://github.com/ibolmo/grunt-mootools-packager) for further options. 65 | 66 | **Examples** 67 | 68 | # with compat 69 | grunt compat --file=Function # builds with only Core/Function and dependencies, then tests against specs in Specs/Core/Function 70 | grunt compat --module=Class # tests against all specs in the Specs/Class *folder* (use --file to limit the build) 71 | 72 | # without compat 73 | grunt nocompat --file=Function # builds with only Core/Function and dependencies, then tests against specs in Specs/Core/Function 74 | grunt nocompat --module=Class # tests against all specs in the Specs/Class *folder* (use --file to limit the build) 75 | 76 | #### Removing Other Packager Blocks 77 | You'll need to add a specific task to the Gruntfile. See [packager's documentation](https://github.com/ibolmo/grunt-mootools-packager) for more examples. 78 | 79 | ### Testing locally 80 | 81 | I you want to test your local repo you need just some small steps. Follow these in order: 82 | 83 | $ git clone https://github.com/mootools/mootools-core # clone the MooTools repo 84 | $ cd mootools-core # get into the directory 85 | $ npm install # install de testing tools 86 | $ `npm bin`/grunt test # run the specs! 87 | 88 | 89 | To test a build in a local browser, you can run the `:dev` target of that build to start a test server at `http://localhost:9876/` and point your browser to it. When you're done testing, pressing `Ctrl+c` in the window running the grunt process should stop the server. 90 | 91 | Example: 92 | 93 | $ `npm bin`/grunt compat:dev 94 | 95 | If the log is too long, or if you want to store it in a file you can do: 96 | 97 | $ grunt > logs.txt # This will create a new file called logs.txt in the local directory 98 | 99 | ### Testing on Travis & Sauce Labs 100 | 101 | Every new Build and Pull Request is now tested on [Travis](https://travis-ci.org/) and [Sauce Labs](https://saucelabs.com/). You can also open your own free account on [Travis](https://travis-ci.org/) and [Sauce Labs](https://saucelabs.com/) to test new code ideas there. 102 | 103 | [Travis](https://travis-ci.org/) testing uses [PhantomJS](http://phantomjs.org/) which is a headless browser. When connected to [Sauce Labs](https://saucelabs.com/) then it is possible to choose any number of [different Browsers and Platforms](https://saucelabs.com/platforms). You will need in this case to change the login key so it will match your account. 104 | 105 | To add new Browsers in [Sauce Labs](https://saucelabs.com/) testing you can make changes to __[Grunt/options/browsers.json](Grunt/options/browsers.json)__: 106 | 107 | - add a new browser to the custom launchers already in the Gruntfile. 108 | 109 | ... 110 | chrome: { 111 | base: 'SauceLabs', 112 | platform: 'Linux', 113 | browserName: 'chrome', 114 | }, 115 | ... 116 | 117 | 118 | - add the chosen browser, with the correct builds to .travis.yml: 119 | 120 | env: 121 | matrix: 122 | - BUILD='compat' BROWSER='chrome' 123 | 124 | #### Browsers, Platforms, and More 125 | 126 | This test suite is ready for Travis & SauceLabs. 127 | You can also run locally. 128 | 129 | Support: 130 | 131 | - IE 132 | - Edge 133 | - Firefox 134 | - Safari 135 | - Chrome 136 | - Opera 137 | - PhantomJS (headless browser) 138 | 139 | ## More Information 140 | 141 | [See the MooTools Wiki for more information](http://github.com/mootools/mootools-core/wikis) 142 | -------------------------------------------------------------------------------- /Source/Class/Class.Extras.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | 4 | name: Class.Extras 5 | 6 | description: Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks. 7 | 8 | license: MIT-style license. 9 | 10 | requires: Class 11 | 12 | provides: [Class.Extras, Chain, Events, Options] 13 | 14 | ... 15 | */ 16 | 17 | (function(){ 18 | 19 | this.Chain = new Class({ 20 | 21 | $chain: [], 22 | 23 | chain: function(){ 24 | this.$chain.append(Array.flatten(arguments)); 25 | return this; 26 | }, 27 | 28 | callChain: function(){ 29 | return (this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false; 30 | }, 31 | 32 | clearChain: function(){ 33 | this.$chain.empty(); 34 | return this; 35 | } 36 | 37 | }); 38 | 39 | var removeOn = function(string){ 40 | return string.replace(/^on([A-Z])/, function(full, first){ 41 | return first.toLowerCase(); 42 | }); 43 | }; 44 | 45 | this.Events = new Class({ 46 | 47 | $events: {}, 48 | 49 | addEvent: function(type, fn, internal){ 50 | type = removeOn(type); 51 | 52 | /*<1.2compat>*/ 53 | if (fn == $empty) return this; 54 | /**/ 55 | 56 | this.$events[type] = (this.$events[type] || []).include(fn); 57 | if (internal) fn.internal = true; 58 | return this; 59 | }, 60 | 61 | addEvents: function(events){ 62 | for (var type in events) this.addEvent(type, events[type]); 63 | return this; 64 | }, 65 | 66 | fireEvent: function(type, args, delay){ 67 | type = removeOn(type); 68 | var events = this.$events[type]; 69 | if (!events) return this; 70 | args = Array.convert(args); 71 | events.each(function(fn){ 72 | if (delay) fn.delay(delay, this, args); 73 | else fn.apply(this, args); 74 | }, this); 75 | return this; 76 | }, 77 | 78 | removeEvent: function(type, fn){ 79 | type = removeOn(type); 80 | var events = this.$events[type]; 81 | if (events && !fn.internal){ 82 | var index = events.indexOf(fn); 83 | if (index != -1) delete events[index]; 84 | } 85 | return this; 86 | }, 87 | 88 | removeEvents: function(events){ 89 | var type; 90 | if (typeOf(events) == 'object'){ 91 | for (type in events) this.removeEvent(type, events[type]); 92 | return this; 93 | } 94 | if (events) events = removeOn(events); 95 | for (type in this.$events){ 96 | if (events && events != type) continue; 97 | var fns = this.$events[type]; 98 | for (var i = fns.length; i--;) if (i in fns){ 99 | this.removeEvent(type, fns[i]); 100 | } 101 | } 102 | return this; 103 | } 104 | 105 | }); 106 | 107 | this.Options = new Class({ 108 | 109 | setOptions: function(){ 110 | var options = this.options = Object.merge.apply(null, [{}, this.options].append(arguments)); 111 | if (this.addEvent) for (var option in options){ 112 | if (typeOf(options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue; 113 | this.addEvent(option, options[option]); 114 | delete options[option]; 115 | } 116 | return this; 117 | } 118 | 119 | }); 120 | 121 | })(); 122 | -------------------------------------------------------------------------------- /Source/Class/Class.Thenable.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | 4 | name: Class.Thenable 5 | 6 | description: Contains a Utility Class that can be implemented into your own Classes to make them "thenable". 7 | 8 | license: MIT-style license. 9 | 10 | requires: Class 11 | 12 | provides: [Class.Thenable] 13 | 14 | ... 15 | */ 16 | 17 | (function(){ 18 | 19 | var STATE_PENDING = 0, 20 | STATE_FULFILLED = 1, 21 | STATE_REJECTED = 2; 22 | 23 | var Thenable = Class.Thenable = new Class({ 24 | 25 | $thenableState: STATE_PENDING, 26 | $thenableResult: null, 27 | $thenableReactions: [], 28 | 29 | resolve: function(value){ 30 | resolve(this, value); 31 | return this; 32 | }, 33 | 34 | reject: function(reason){ 35 | reject(this, reason); 36 | return this; 37 | }, 38 | 39 | getThenableState: function(){ 40 | switch (this.$thenableState){ 41 | case STATE_PENDING: 42 | return 'pending'; 43 | 44 | case STATE_FULFILLED: 45 | return 'fulfilled'; 46 | 47 | case STATE_REJECTED: 48 | return 'rejected'; 49 | } 50 | }, 51 | 52 | resetThenable: function(reason){ 53 | reject(this, reason); 54 | reset(this); 55 | return this; 56 | }, 57 | 58 | then: function(onFulfilled, onRejected){ 59 | if (typeof onFulfilled !== 'function') onFulfilled = 'Identity'; 60 | if (typeof onRejected !== 'function') onRejected = 'Thrower'; 61 | 62 | var thenable = new Thenable(); 63 | 64 | this.$thenableReactions.push({ 65 | thenable: thenable, 66 | fulfillHandler: onFulfilled, 67 | rejectHandler: onRejected 68 | }); 69 | 70 | if (this.$thenableState !== STATE_PENDING){ 71 | react(this); 72 | } 73 | 74 | return thenable; 75 | }, 76 | 77 | 'catch': function(onRejected){ 78 | return this.then(null, onRejected); 79 | } 80 | 81 | }); 82 | 83 | Thenable.extend({ 84 | resolve: function(value){ 85 | var thenable; 86 | if (value instanceof Thenable){ 87 | thenable = value; 88 | } else { 89 | thenable = new Thenable(); 90 | resolve(thenable, value); 91 | } 92 | return thenable; 93 | }, 94 | reject: function(reason){ 95 | var thenable = new Thenable(); 96 | reject(thenable, reason); 97 | return thenable; 98 | } 99 | }); 100 | 101 | // Private functions 102 | 103 | function resolve(thenable, value){ 104 | if (thenable.$thenableState === STATE_PENDING){ 105 | if (thenable === value){ 106 | reject(thenable, new TypeError('Tried to resolve a thenable with itself.')); 107 | } else if (value && (typeof value === 'object' || typeof value === 'function')){ 108 | var then; 109 | try { 110 | then = value.then; 111 | } catch (exception){ 112 | reject(thenable, exception); 113 | } 114 | if (typeof then === 'function'){ 115 | var resolved = false; 116 | defer(function(){ 117 | try { 118 | then.call( 119 | value, 120 | function(nextValue){ 121 | if (!resolved){ 122 | resolved = true; 123 | resolve(thenable, nextValue); 124 | } 125 | }, 126 | function(reason){ 127 | if (!resolved){ 128 | resolved = true; 129 | reject(thenable, reason); 130 | } 131 | } 132 | ); 133 | } catch (exception){ 134 | if (!resolved){ 135 | resolved = true; 136 | reject(thenable, exception); 137 | } 138 | } 139 | }); 140 | } else { 141 | fulfill(thenable, value); 142 | } 143 | } else { 144 | fulfill(thenable, value); 145 | } 146 | } 147 | } 148 | 149 | function fulfill(thenable, value){ 150 | if (thenable.$thenableState === STATE_PENDING){ 151 | thenable.$thenableResult = value; 152 | thenable.$thenableState = STATE_FULFILLED; 153 | 154 | react(thenable); 155 | } 156 | } 157 | 158 | function reject(thenable, reason){ 159 | if (thenable.$thenableState === STATE_PENDING){ 160 | thenable.$thenableResult = reason; 161 | thenable.$thenableState = STATE_REJECTED; 162 | 163 | react(thenable); 164 | } 165 | } 166 | 167 | function reset(thenable){ 168 | if (thenable.$thenableState !== STATE_PENDING){ 169 | thenable.$thenableResult = null; 170 | thenable.$thenableState = STATE_PENDING; 171 | } 172 | } 173 | 174 | function react(thenable){ 175 | var state = thenable.$thenableState, 176 | result = thenable.$thenableResult, 177 | reactions = thenable.$thenableReactions, 178 | type; 179 | 180 | if (state === STATE_FULFILLED){ 181 | thenable.$thenableReactions = []; 182 | type = 'fulfillHandler'; 183 | } else if (state == STATE_REJECTED){ 184 | thenable.$thenableReactions = []; 185 | type = 'rejectHandler'; 186 | } 187 | 188 | if (type){ 189 | defer(handle.pass([result, reactions, type])); 190 | } 191 | } 192 | 193 | function handle(result, reactions, type){ 194 | for (var i = 0, l = reactions.length; i < l; ++i){ 195 | var reaction = reactions[i], 196 | handler = reaction[type]; 197 | 198 | if (handler === 'Identity'){ 199 | resolve(reaction.thenable, result); 200 | } else if (handler === 'Thrower'){ 201 | reject(reaction.thenable, result); 202 | } else { 203 | try { 204 | resolve(reaction.thenable, handler(result)); 205 | } catch (exception){ 206 | reject(reaction.thenable, exception); 207 | } 208 | } 209 | } 210 | } 211 | 212 | var defer; 213 | if (typeof process !== 'undefined' && typeof process.nextTick === 'function'){ 214 | defer = process.nextTick; 215 | } else if (typeof setImmediate !== 'undefined'){ 216 | defer = setImmediate; 217 | } else { 218 | defer = function(fn){ 219 | setTimeout(fn, 0); 220 | }; 221 | } 222 | 223 | })(); 224 | -------------------------------------------------------------------------------- /Source/Class/Class.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | 4 | name: Class 5 | 6 | description: Contains the Class Function for easily creating, extending, and implementing reusable Classes. 7 | 8 | license: MIT-style license. 9 | 10 | requires: [Array, String, Function, Number] 11 | 12 | provides: Class 13 | 14 | ... 15 | */ 16 | 17 | (function(){ 18 | 19 | var Class = this.Class = new Type('Class', function(params){ 20 | if (instanceOf(params, Function)) params = {initialize: params}; 21 | 22 | var newClass = function(){ 23 | reset(this); 24 | if (newClass.$prototyping) return this; 25 | this.$caller = null; 26 | this.$family = null; 27 | var value = (this.initialize) ? this.initialize.apply(this, arguments) : this; 28 | this.$caller = this.caller = null; 29 | return value; 30 | }.extend(this).implement(params); 31 | 32 | newClass.$constructor = Class; 33 | newClass.prototype.$constructor = newClass; 34 | newClass.prototype.parent = parent; 35 | 36 | return newClass; 37 | }); 38 | 39 | var parent = function(){ 40 | if (!this.$caller) throw new Error('The method "parent" cannot be called.'); 41 | var name = this.$caller.$name, 42 | parent = this.$caller.$owner.parent, 43 | previous = (parent) ? parent.prototype[name] : null; 44 | if (!previous) throw new Error('The method "' + name + '" has no parent.'); 45 | return previous.apply(this, arguments); 46 | }; 47 | 48 | var reset = function(object){ 49 | for (var key in object){ 50 | var value = object[key]; 51 | switch (typeOf(value)){ 52 | case 'object': 53 | var F = function(){}; 54 | F.prototype = value; 55 | object[key] = reset(new F); 56 | break; 57 | case 'array': object[key] = value.clone(); break; 58 | } 59 | } 60 | return object; 61 | }; 62 | 63 | var wrap = function(self, key, method){ 64 | if (method.$origin) method = method.$origin; 65 | var wrapper = function(){ 66 | if (method.$protected && this.$caller == null) throw new Error('The method "' + key + '" cannot be called.'); 67 | var caller = this.caller, current = this.$caller; 68 | this.caller = current; this.$caller = wrapper; 69 | var result = method.apply(this, arguments); 70 | this.$caller = current; this.caller = caller; 71 | return result; 72 | }.extend({$owner: self, $origin: method, $name: key}); 73 | return wrapper; 74 | }; 75 | 76 | var implement = function(key, value, retain){ 77 | if (Class.Mutators.hasOwnProperty(key)){ 78 | value = Class.Mutators[key].call(this, value); 79 | if (value == null) return this; 80 | } 81 | 82 | if (typeOf(value) == 'function'){ 83 | if (value.$hidden) return this; 84 | this.prototype[key] = (retain) ? value : wrap(this, key, value); 85 | } else { 86 | Object.merge(this.prototype, key, value); 87 | } 88 | 89 | return this; 90 | }; 91 | 92 | var getInstance = function(klass){ 93 | klass.$prototyping = true; 94 | var proto = new klass; 95 | delete klass.$prototyping; 96 | return proto; 97 | }; 98 | 99 | Class.implement('implement', implement.overloadSetter()); 100 | 101 | Class.Mutators = { 102 | 103 | Extends: function(parent){ 104 | this.parent = parent; 105 | this.prototype = getInstance(parent); 106 | }, 107 | 108 | Implements: function(items){ 109 | Array.convert(items).each(function(item){ 110 | var instance = new item; 111 | for (var key in instance) implement.call(this, key, instance[key], true); 112 | }, this); 113 | } 114 | }; 115 | 116 | })(); 117 | -------------------------------------------------------------------------------- /Source/Element/Element.Delegation.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | 4 | name: Element.Delegation 5 | 6 | description: Extends the Element native object to include the delegate method for more efficient event management. 7 | 8 | license: MIT-style license. 9 | 10 | requires: [Element.Event] 11 | 12 | provides: [Element.Delegation] 13 | 14 | ... 15 | */ 16 | 17 | (function(){ 18 | 19 | var eventListenerSupport = !!window.addEventListener; 20 | 21 | Element.NativeEvents.focusin = Element.NativeEvents.focusout = 2; 22 | 23 | var bubbleUp = function(self, match, fn, event, target){ 24 | while (target && target != self){ 25 | if (match(target, event)) return fn.call(target, event, target); 26 | target = document.id(target.parentNode); 27 | } 28 | }; 29 | 30 | var map = { 31 | mouseenter: { 32 | base: 'mouseover', 33 | condition: Element.MouseenterCheck 34 | }, 35 | mouseleave: { 36 | base: 'mouseout', 37 | condition: Element.MouseenterCheck 38 | }, 39 | focus: { 40 | base: 'focus' + (eventListenerSupport ? '' : 'in'), 41 | capture: true 42 | }, 43 | blur: { 44 | base: eventListenerSupport ? 'blur' : 'focusout', 45 | capture: true 46 | } 47 | }; 48 | 49 | /**/ 50 | var _key = '$delegation:'; 51 | var formObserver = function(type){ 52 | 53 | return { 54 | 55 | base: 'focusin', 56 | 57 | remove: function(self, uid){ 58 | var list = self.retrieve(_key + type + 'listeners', {})[uid]; 59 | if (list && list.forms) for (var i = list.forms.length; i--;){ 60 | // the form may have been destroyed, so it won't have the 61 | // removeEvent method anymore. In that case the event was 62 | // removed as well. 63 | if (list.forms[i].removeEvent) list.forms[i].removeEvent(type, list.fns[i]); 64 | } 65 | }, 66 | 67 | listen: function(self, match, fn, event, target, uid){ 68 | var form = (target.get('tag') == 'form') ? target : event.target.getParent('form'); 69 | if (!form) return; 70 | 71 | var listeners = self.retrieve(_key + type + 'listeners', {}), 72 | listener = listeners[uid] || {forms: [], fns: []}, 73 | forms = listener.forms, fns = listener.fns; 74 | 75 | if (forms.indexOf(form) != -1) return; 76 | forms.push(form); 77 | 78 | var _fn = function(event){ 79 | bubbleUp(self, match, fn, event, target); 80 | }; 81 | form.addEvent(type, _fn); 82 | fns.push(_fn); 83 | 84 | listeners[uid] = listener; 85 | self.store(_key + type + 'listeners', listeners); 86 | } 87 | }; 88 | }; 89 | 90 | var inputObserver = function(type){ 91 | return { 92 | base: 'focusin', 93 | listen: function(self, match, fn, event, target){ 94 | var events = {blur: function(){ 95 | this.removeEvents(events); 96 | }}; 97 | events[type] = function(event){ 98 | bubbleUp(self, match, fn, event, target); 99 | }; 100 | event.target.addEvents(events); 101 | } 102 | }; 103 | }; 104 | 105 | if (!eventListenerSupport) Object.append(map, { 106 | submit: formObserver('submit'), 107 | reset: formObserver('reset'), 108 | change: inputObserver('change'), 109 | select: inputObserver('select') 110 | }); 111 | /**/ 112 | 113 | var proto = Element.prototype, 114 | addEvent = proto.addEvent, 115 | removeEvent = proto.removeEvent; 116 | 117 | var relay = function(old, method){ 118 | return function(type, fn, useCapture){ 119 | if (type.indexOf(':relay') == -1) return old.call(this, type, fn, useCapture); 120 | var parsed = Slick.parse(type).expressions[0][0]; 121 | if (parsed.pseudos[0].key != 'relay') return old.call(this, type, fn, useCapture); 122 | var newType = parsed.tag; 123 | parsed.pseudos.slice(1).each(function(pseudo){ 124 | newType += ':' + pseudo.key + (pseudo.value ? '(' + pseudo.value + ')' : ''); 125 | }); 126 | old.call(this, type, fn); 127 | return method.call(this, newType, parsed.pseudos[0].value, fn); 128 | }; 129 | }; 130 | 131 | var delegation = { 132 | 133 | addEvent: function(type, match, fn){ 134 | var storage = this.retrieve('$delegates', {}), stored = storage[type]; 135 | if (stored) for (var _uid in stored){ 136 | if (stored[_uid].fn == fn && stored[_uid].match == match) return this; 137 | } 138 | 139 | var _type = type, _match = match, _fn = fn, _map = map[type] || {}; 140 | type = _map.base || _type; 141 | 142 | match = function(target){ 143 | return Slick.match(target, _match); 144 | }; 145 | 146 | var elementEvent = Element.Events[_type]; 147 | if (_map.condition || elementEvent && elementEvent.condition){ 148 | var __match = match, condition = _map.condition || elementEvent.condition; 149 | match = function(target, event){ 150 | return __match(target, event) && condition.call(target, event, type); 151 | }; 152 | } 153 | 154 | var self = this, uid = String.uniqueID(); 155 | var delegator = _map.listen ? function(event, target){ 156 | if (!target && event && event.target) target = event.target; 157 | if (target) _map.listen(self, match, fn, event, target, uid); 158 | } : function(event, target){ 159 | if (!target && event && event.target) target = event.target; 160 | if (target) bubbleUp(self, match, fn, event, target); 161 | }; 162 | 163 | if (!stored) stored = {}; 164 | stored[uid] = { 165 | match: _match, 166 | fn: _fn, 167 | delegator: delegator 168 | }; 169 | storage[_type] = stored; 170 | return addEvent.call(this, type, delegator, _map.capture); 171 | }, 172 | 173 | removeEvent: function(type, match, fn, _uid){ 174 | var storage = this.retrieve('$delegates', {}), stored = storage[type]; 175 | if (!stored) return this; 176 | 177 | if (_uid){ 178 | var _type = type, delegator = stored[_uid].delegator, _map = map[type] || {}; 179 | type = _map.base || _type; 180 | if (_map.remove) _map.remove(this, _uid); 181 | delete stored[_uid]; 182 | storage[_type] = stored; 183 | return removeEvent.call(this, type, delegator, _map.capture); 184 | } 185 | 186 | var __uid, s; 187 | if (fn) for (__uid in stored){ 188 | s = stored[__uid]; 189 | if (s.match == match && s.fn == fn) return delegation.removeEvent.call(this, type, match, fn, __uid); 190 | } else for (__uid in stored){ 191 | s = stored[__uid]; 192 | if (s.match == match) delegation.removeEvent.call(this, type, match, s.fn, __uid); 193 | } 194 | return this; 195 | } 196 | 197 | }; 198 | 199 | [Element, Window, Document].invoke('implement', { 200 | addEvent: relay(addEvent, delegation.addEvent), 201 | removeEvent: relay(removeEvent, delegation.removeEvent) 202 | }); 203 | 204 | })(); 205 | -------------------------------------------------------------------------------- /Source/Element/Element.Event.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | 4 | name: Element.Event 5 | 6 | description: Contains Element methods for dealing with events. This file also includes mouseenter and mouseleave custom Element Events, if necessary. 7 | 8 | license: MIT-style license. 9 | 10 | requires: [Element, Event] 11 | 12 | provides: Element.Event 13 | 14 | ... 15 | */ 16 | 17 | (function(){ 18 | 19 | Element.Properties.events = {set: function(events){ 20 | this.addEvents(events); 21 | }}; 22 | 23 | [Element, Window, Document].invoke('implement', { 24 | 25 | addEvent: function(type, fn){ 26 | var events = this.retrieve('events', {}); 27 | if (!events[type]) events[type] = {keys: [], values: []}; 28 | if (events[type].keys.contains(fn)) return this; 29 | events[type].keys.push(fn); 30 | var realType = type, 31 | custom = Element.Events[type], 32 | condition = fn, 33 | self = this; 34 | if (custom){ 35 | if (custom.onAdd) custom.onAdd.call(this, fn, type); 36 | if (custom.condition){ 37 | condition = function(event){ 38 | if (custom.condition.call(this, event, type)) return fn.call(this, event); 39 | return true; 40 | }; 41 | } 42 | if (custom.base) realType = Function.convert(custom.base).call(this, type); 43 | } 44 | var defn = function(){ 45 | return fn.call(self); 46 | }; 47 | var nativeEvent = Element.NativeEvents[realType]; 48 | if (nativeEvent){ 49 | if (nativeEvent == 2){ 50 | defn = function(event){ 51 | event = new DOMEvent(event, self.getWindow()); 52 | if (condition.call(self, event) === false) event.stop(); 53 | }; 54 | } 55 | this.addListener(realType, defn, arguments[2]); 56 | } 57 | events[type].values.push(defn); 58 | return this; 59 | }, 60 | 61 | removeEvent: function(type, fn){ 62 | var events = this.retrieve('events'); 63 | if (!events || !events[type]) return this; 64 | var list = events[type]; 65 | var index = list.keys.indexOf(fn); 66 | if (index == -1) return this; 67 | var value = list.values[index]; 68 | delete list.keys[index]; 69 | delete list.values[index]; 70 | var custom = Element.Events[type]; 71 | if (custom){ 72 | if (custom.onRemove) custom.onRemove.call(this, fn, type); 73 | if (custom.base) type = Function.convert(custom.base).call(this, type); 74 | } 75 | return (Element.NativeEvents[type]) ? this.removeListener(type, value, arguments[2]) : this; 76 | }, 77 | 78 | addEvents: function(events){ 79 | for (var event in events) this.addEvent(event, events[event]); 80 | return this; 81 | }, 82 | 83 | removeEvents: function(events){ 84 | var type; 85 | if (typeOf(events) == 'object'){ 86 | for (type in events) this.removeEvent(type, events[type]); 87 | return this; 88 | } 89 | var attached = this.retrieve('events'); 90 | if (!attached) return this; 91 | if (!events){ 92 | for (type in attached) this.removeEvents(type); 93 | this.eliminate('events'); 94 | } else if (attached[events]){ 95 | attached[events].keys.each(function(fn){ 96 | this.removeEvent(events, fn); 97 | }, this); 98 | delete attached[events]; 99 | } 100 | return this; 101 | }, 102 | 103 | fireEvent: function(type, args, delay){ 104 | var events = this.retrieve('events'); 105 | if (!events || !events[type]) return this; 106 | args = Array.convert(args); 107 | 108 | events[type].keys.each(function(fn){ 109 | if (delay) fn.delay(delay, this, args); 110 | else fn.apply(this, args); 111 | }, this); 112 | return this; 113 | }, 114 | 115 | cloneEvents: function(from, type){ 116 | from = document.id(from); 117 | var events = from.retrieve('events'); 118 | if (!events) return this; 119 | if (!type){ 120 | for (var eventType in events) this.cloneEvents(from, eventType); 121 | } else if (events[type]){ 122 | events[type].keys.each(function(fn){ 123 | this.addEvent(type, fn); 124 | }, this); 125 | } 126 | return this; 127 | } 128 | 129 | }); 130 | 131 | Element.NativeEvents = { 132 | click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons 133 | wheel: 2, mousewheel: 2, DOMMouseScroll: 2, //mouse wheel 134 | mouseover: 2, mouseout: 2, mousemove: 2, selectstart: 2, selectend: 2, //mouse movement 135 | keydown: 2, keypress: 2, keyup: 2, //keyboard 136 | orientationchange: 2, // mobile 137 | touchstart: 2, touchmove: 2, touchend: 2, touchcancel: 2, // touch 138 | gesturestart: 2, gesturechange: 2, gestureend: 2, // gesture 139 | focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, paste: 2, input: 2, //form elements 140 | load: 2, unload: 1, beforeunload: 2, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window 141 | hashchange: 1, popstate: 2, pageshow: 2, pagehide: 2, // history 142 | error: 1, abort: 1, scroll: 1, message: 2 //misc 143 | }; 144 | 145 | Element.Events = { 146 | mousewheel: { 147 | base: 'onwheel' in document ? 'wheel' : 'onmousewheel' in document ? 'mousewheel' : 'DOMMouseScroll' 148 | } 149 | }; 150 | 151 | var check = function(event){ 152 | var related = event.relatedTarget; 153 | if (related == null) return true; 154 | if (!related) return false; 155 | return (related != this && related.prefix != 'xul' && typeOf(this) != 'document' && !this.contains(related)); 156 | }; 157 | 158 | if ('onmouseenter' in document.documentElement){ 159 | Element.NativeEvents.mouseenter = Element.NativeEvents.mouseleave = 2; 160 | Element.MouseenterCheck = check; 161 | } else { 162 | Element.Events.mouseenter = { 163 | base: 'mouseover', 164 | condition: check 165 | }; 166 | 167 | Element.Events.mouseleave = { 168 | base: 'mouseout', 169 | condition: check 170 | }; 171 | } 172 | 173 | /**/ 174 | if (!window.addEventListener){ 175 | Element.NativeEvents.propertychange = 2; 176 | Element.Events.change = { 177 | base: function(){ 178 | var type = this.type; 179 | return (this.get('tag') == 'input' && (type == 'radio' || type == 'checkbox')) ? 'propertychange' : 'change'; 180 | }, 181 | condition: function(event){ 182 | return event.type != 'propertychange' || event.event.propertyName == 'checked'; 183 | } 184 | }; 185 | } 186 | /**/ 187 | 188 | //<1.2compat> 189 | 190 | Element.Events = new Hash(Element.Events); 191 | 192 | // 193 | 194 | })(); 195 | -------------------------------------------------------------------------------- /Source/Fx/Fx.CSS.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | 4 | name: Fx.CSS 5 | 6 | description: Contains the CSS animation logic. Used by Fx.Tween, Fx.Morph, Fx.Elements. 7 | 8 | license: MIT-style license. 9 | 10 | requires: [Fx, Element.Style] 11 | 12 | provides: Fx.CSS 13 | 14 | ... 15 | */ 16 | 17 | Fx.CSS = new Class({ 18 | 19 | Extends: Fx, 20 | 21 | //prepares the base from/to object 22 | 23 | prepare: function(element, property, values){ 24 | values = Array.convert(values); 25 | var from = values[0], to = values[1]; 26 | if (to == null){ 27 | to = from; 28 | from = element.getStyle(property); 29 | var unit = this.options.unit; 30 | // adapted from: https://github.com/ryanmorr/fx/blob/master/fx.js#L299 31 | if (unit && from && typeof from == 'string' && from.slice(-unit.length) != unit && parseFloat(from) != 0){ 32 | element.setStyle(property, to + unit); 33 | var value = element.getComputedStyle(property); 34 | // IE and Opera support pixelLeft or pixelWidth 35 | if (!(/px$/.test(value))){ 36 | value = element.style[('pixel-' + property).camelCase()]; 37 | if (value == null){ 38 | // adapted from Dean Edwards' http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 39 | var left = element.style.left; 40 | element.style.left = to + unit; 41 | value = element.style.pixelLeft; 42 | element.style.left = left; 43 | } 44 | } 45 | from = (to || 1) / (parseFloat(value) || 1) * (parseFloat(from) || 0); 46 | element.setStyle(property, from + unit); 47 | } 48 | } 49 | return {from: this.parse(from), to: this.parse(to)}; 50 | }, 51 | 52 | //parses a value into an array 53 | 54 | parse: function(value){ 55 | value = Function.convert(value)(); 56 | value = (typeof value == 'string') ? value.split(' ') : Array.convert(value); 57 | return value.map(function(val){ 58 | val = String(val); 59 | var found = false; 60 | Object.each(Fx.CSS.Parsers, function(parser){ 61 | if (found) return; 62 | var parsed = parser.parse(val); 63 | if (parsed || parsed === 0) found = {value: parsed, parser: parser}; 64 | }); 65 | found = found || {value: val, parser: Fx.CSS.Parsers.String}; 66 | return found; 67 | }); 68 | }, 69 | 70 | //computes by a from and to prepared objects, using their parsers. 71 | 72 | compute: function(from, to, delta){ 73 | var computed = []; 74 | (Math.min(from.length, to.length)).times(function(i){ 75 | computed.push({value: from[i].parser.compute(from[i].value, to[i].value, delta), parser: from[i].parser}); 76 | }); 77 | computed.$family = Function.convert('fx:css:value'); 78 | return computed; 79 | }, 80 | 81 | //serves the value as settable 82 | 83 | serve: function(value, unit){ 84 | if (typeOf(value) != 'fx:css:value') value = this.parse(value); 85 | var returned = []; 86 | value.each(function(bit){ 87 | returned = returned.concat(bit.parser.serve(bit.value, unit)); 88 | }); 89 | return returned; 90 | }, 91 | 92 | //renders the change to an element 93 | 94 | render: function(element, property, value, unit){ 95 | element.setStyle(property, this.serve(value, unit)); 96 | }, 97 | 98 | //searches inside the page css to find the values for a selector 99 | 100 | search: function(selector){ 101 | if (Fx.CSS.Cache[selector]) return Fx.CSS.Cache[selector]; 102 | var to = {}, selectorTest = new RegExp('^' + selector.escapeRegExp() + '$'); 103 | 104 | var searchStyles = function(rules){ 105 | Array.each(rules, function(rule){ 106 | if (rule.media){ 107 | searchStyles(rule.rules || rule.cssRules); 108 | return; 109 | } 110 | if (!rule.style) return; 111 | var selectorText = (rule.selectorText) ? rule.selectorText.replace(/^\w+/, function(m){ 112 | return m.toLowerCase(); 113 | }) : null; 114 | if (!selectorText || !selectorTest.test(selectorText)) return; 115 | Object.each(Element.Styles, function(value, style){ 116 | if (!rule.style[style] || Element.ShortStyles[style]) return; 117 | value = String(rule.style[style]); 118 | to[style] = ((/^rgb/).test(value)) ? value.rgbToHex() : value; 119 | }); 120 | }); 121 | }; 122 | 123 | Array.each(document.styleSheets, function(sheet){ 124 | var href = sheet.href; 125 | if (href && href.indexOf('://') > -1 && href.indexOf(document.domain) == -1) return; 126 | var rules = sheet.rules || sheet.cssRules; 127 | searchStyles(rules); 128 | }); 129 | return Fx.CSS.Cache[selector] = to; 130 | } 131 | 132 | }); 133 | 134 | Fx.CSS.Cache = {}; 135 | 136 | Fx.CSS.Parsers = { 137 | 138 | Color: { 139 | parse: function(value){ 140 | if (value.match(/^#[0-9a-f]{3,6}$/i)) return value.hexToRgb(true); 141 | return ((value = value.match(/(\d+),\s*(\d+),\s*(\d+)/))) ? [value[1], value[2], value[3]] : false; 142 | }, 143 | compute: function(from, to, delta){ 144 | return from.map(function(value, i){ 145 | return Math.round(Fx.compute(from[i], to[i], delta)); 146 | }); 147 | }, 148 | serve: function(value){ 149 | return value.map(Number); 150 | } 151 | }, 152 | 153 | Number: { 154 | parse: parseFloat, 155 | compute: Fx.compute, 156 | serve: function(value, unit){ 157 | return (unit) ? value + unit : value; 158 | } 159 | }, 160 | 161 | String: { 162 | parse: Function.convert(false), 163 | compute: function(zero, one){ 164 | return one; 165 | }, 166 | serve: function(zero){ 167 | return zero; 168 | } 169 | } 170 | 171 | }; 172 | 173 | //<1.2compat> 174 | 175 | Fx.CSS.Parsers = new Hash(Fx.CSS.Parsers); 176 | 177 | // 178 | -------------------------------------------------------------------------------- /Source/Fx/Fx.Morph.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | 4 | name: Fx.Morph 5 | 6 | description: Formerly Fx.Styles, effect to transition any number of CSS properties for an element using an object of rules, or CSS based selector rules. 7 | 8 | license: MIT-style license. 9 | 10 | requires: Fx.CSS 11 | 12 | provides: Fx.Morph 13 | 14 | ... 15 | */ 16 | 17 | Fx.Morph = new Class({ 18 | 19 | Extends: Fx.CSS, 20 | 21 | initialize: function(element, options){ 22 | this.element = this.subject = document.id(element); 23 | this.parent(options); 24 | }, 25 | 26 | set: function(now){ 27 | if (typeof now == 'string') now = this.search(now); 28 | for (var p in now) this.render(this.element, p, now[p], this.options.unit); 29 | return this; 30 | }, 31 | 32 | compute: function(from, to, delta){ 33 | var now = {}; 34 | for (var p in from) now[p] = this.parent(from[p], to[p], delta); 35 | return now; 36 | }, 37 | 38 | start: function(properties){ 39 | if (!this.check(properties)) return this; 40 | if (typeof properties == 'string') properties = this.search(properties); 41 | var from = {}, to = {}; 42 | for (var p in properties){ 43 | var parsed = this.prepare(this.element, p, properties[p]); 44 | from[p] = parsed.from; 45 | to[p] = parsed.to; 46 | } 47 | return this.parent(from, to); 48 | } 49 | 50 | }); 51 | 52 | Element.Properties.morph = { 53 | 54 | set: function(options){ 55 | this.get('morph').cancel().setOptions(options); 56 | return this; 57 | }, 58 | 59 | get: function(){ 60 | var morph = this.retrieve('morph'); 61 | if (!morph){ 62 | morph = new Fx.Morph(this, {link: 'cancel'}); 63 | this.store('morph', morph); 64 | } 65 | return morph; 66 | } 67 | 68 | }; 69 | 70 | Element.implement({ 71 | 72 | morph: function(props){ 73 | this.get('morph').start(props); 74 | return this; 75 | } 76 | 77 | }); 78 | -------------------------------------------------------------------------------- /Source/Fx/Fx.Transitions.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | 4 | name: Fx.Transitions 5 | 6 | description: Contains a set of advanced transitions to be used with any of the Fx Classes. 7 | 8 | license: MIT-style license. 9 | 10 | credits: 11 | - Easing Equations by Robert Penner, , modified and optimized to be used with MooTools. 12 | 13 | requires: Fx 14 | 15 | provides: Fx.Transitions 16 | 17 | ... 18 | */ 19 | 20 | Fx.implement({ 21 | 22 | getTransition: function(){ 23 | var trans = this.options.transition || Fx.Transitions.Sine.easeInOut; 24 | if (typeof trans == 'string'){ 25 | var data = trans.split(':'); 26 | trans = Fx.Transitions; 27 | trans = trans[data[0]] || trans[data[0].capitalize()]; 28 | if (data[1]) trans = trans['ease' + data[1].capitalize() + (data[2] ? data[2].capitalize() : '')]; 29 | } 30 | return trans; 31 | } 32 | 33 | }); 34 | 35 | Fx.Transition = function(transition, params){ 36 | params = Array.convert(params); 37 | var easeIn = function(pos){ 38 | return transition(pos, params); 39 | }; 40 | return Object.append(easeIn, { 41 | easeIn: easeIn, 42 | easeOut: function(pos){ 43 | return 1 - transition(1 - pos, params); 44 | }, 45 | easeInOut: function(pos){ 46 | return (pos <= 0.5 ? transition(2 * pos, params) : (2 - transition(2 * (1 - pos), params))) / 2; 47 | } 48 | }); 49 | }; 50 | 51 | Fx.Transitions = { 52 | 53 | linear: function(zero){ 54 | return zero; 55 | } 56 | 57 | }; 58 | 59 | //<1.2compat> 60 | 61 | Fx.Transitions = new Hash(Fx.Transitions); 62 | 63 | // 64 | 65 | Fx.Transitions.extend = function(transitions){ 66 | for (var transition in transitions) Fx.Transitions[transition] = new Fx.Transition(transitions[transition]); 67 | }; 68 | 69 | Fx.Transitions.extend({ 70 | 71 | Pow: function(p, x){ 72 | return Math.pow(p, x && x[0] || 6); 73 | }, 74 | 75 | Expo: function(p){ 76 | return Math.pow(2, 8 * (p - 1)); 77 | }, 78 | 79 | Circ: function(p){ 80 | return 1 - Math.sin(Math.acos(p)); 81 | }, 82 | 83 | Sine: function(p){ 84 | return 1 - Math.cos(p * Math.PI / 2); 85 | }, 86 | 87 | Back: function(p, x){ 88 | x = x && x[0] || 1.618; 89 | return Math.pow(p, 2) * ((x + 1) * p - x); 90 | }, 91 | 92 | Bounce: function(p){ 93 | var value; 94 | for (var a = 0, b = 1; 1; a += b, b /= 2){ 95 | if (p >= (7 - 4 * a) / 11){ 96 | value = b * b - Math.pow((11 - 6 * a - 11 * p) / 4, 2); 97 | break; 98 | } 99 | } 100 | return value; 101 | }, 102 | 103 | Elastic: function(p, x){ 104 | return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x && x[0] || 1) / 3); 105 | } 106 | 107 | }); 108 | 109 | ['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){ 110 | Fx.Transitions[transition] = new Fx.Transition(function(p){ 111 | return Math.pow(p, i + 2); 112 | }); 113 | }); 114 | -------------------------------------------------------------------------------- /Source/Fx/Fx.Tween.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | 4 | name: Fx.Tween 5 | 6 | description: Formerly Fx.Style, effect to transition any CSS property for an element. 7 | 8 | license: MIT-style license. 9 | 10 | requires: Fx.CSS 11 | 12 | provides: [Fx.Tween, Element.fade, Element.highlight] 13 | 14 | ... 15 | */ 16 | 17 | Fx.Tween = new Class({ 18 | 19 | Extends: Fx.CSS, 20 | 21 | initialize: function(element, options){ 22 | this.element = this.subject = document.id(element); 23 | this.parent(options); 24 | }, 25 | 26 | set: function(property, now){ 27 | if (arguments.length == 1){ 28 | now = property; 29 | property = this.property || this.options.property; 30 | } 31 | this.render(this.element, property, now, this.options.unit); 32 | return this; 33 | }, 34 | 35 | start: function(property, from, to){ 36 | if (!this.check(property, from, to)) return this; 37 | var args = Array.flatten(arguments); 38 | this.property = this.options.property || args.shift(); 39 | var parsed = this.prepare(this.element, this.property, args); 40 | return this.parent(parsed.from, parsed.to); 41 | } 42 | 43 | }); 44 | 45 | Element.Properties.tween = { 46 | 47 | set: function(options){ 48 | this.get('tween').cancel().setOptions(options); 49 | return this; 50 | }, 51 | 52 | get: function(){ 53 | var tween = this.retrieve('tween'); 54 | if (!tween){ 55 | tween = new Fx.Tween(this, {link: 'cancel'}); 56 | this.store('tween', tween); 57 | } 58 | return tween; 59 | } 60 | 61 | }; 62 | 63 | Element.implement({ 64 | 65 | tween: function(property, from, to){ 66 | this.get('tween').start(property, from, to); 67 | return this; 68 | }, 69 | 70 | fade: function(){ 71 | var fade = this.get('tween'), method, args = ['opacity'].append(arguments), toggle; 72 | if (args[1] == null) args[1] = 'toggle'; 73 | switch (args[1]){ 74 | case 'in': method = 'start'; args[1] = 1; break; 75 | case 'out': method = 'start'; args[1] = 0; break; 76 | case 'show': method = 'set'; args[1] = 1; break; 77 | case 'hide': method = 'set'; args[1] = 0; break; 78 | case 'toggle': 79 | var flag = this.retrieve('fade:flag', this.getStyle('opacity') == 1); 80 | method = 'start'; 81 | args[1] = flag ? 0 : 1; 82 | this.store('fade:flag', !flag); 83 | toggle = true; 84 | break; 85 | default: method = 'start'; 86 | } 87 | if (!toggle) this.eliminate('fade:flag'); 88 | fade[method].apply(fade, args); 89 | var to = args[args.length - 1]; 90 | 91 | if (method == 'set'){ 92 | this.setStyle('visibility', to == 0 ? 'hidden' : 'visible'); 93 | } else if (to != 0){ 94 | if (fade.$chain.length){ 95 | fade.chain(function(){ 96 | this.element.setStyle('visibility', 'visible'); 97 | this.callChain(); 98 | }); 99 | } else { 100 | this.setStyle('visibility', 'visible'); 101 | } 102 | } else { 103 | fade.chain(function(){ 104 | if (this.element.getStyle('opacity')) return; 105 | this.element.setStyle('visibility', 'hidden'); 106 | this.callChain(); 107 | }); 108 | } 109 | 110 | return this; 111 | }, 112 | 113 | highlight: function(start, end){ 114 | if (!end){ 115 | end = this.retrieve('highlight:original', this.getStyle('background-color')); 116 | end = (end == 'transparent') ? '#fff' : end; 117 | } 118 | var tween = this.get('tween'); 119 | tween.start('background-color', start || '#ffff88', end).chain(function(){ 120 | this.setStyle('background-color', this.retrieve('highlight:original')); 121 | tween.callChain(); 122 | }.bind(this)); 123 | return this; 124 | } 125 | 126 | }); 127 | -------------------------------------------------------------------------------- /Source/Fx/Fx.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | 4 | name: Fx 5 | 6 | description: Contains the basic animation logic to be extended by all other Fx Classes. 7 | 8 | license: MIT-style license. 9 | 10 | requires: [Chain, Events, Options, Class.Thenable] 11 | 12 | provides: Fx 13 | 14 | ... 15 | */ 16 | 17 | (function(){ 18 | 19 | var Fx = this.Fx = new Class({ 20 | 21 | Implements: [Chain, Events, Options, Class.Thenable], 22 | 23 | options: { 24 | /* 25 | onStart: nil, 26 | onCancel: nil, 27 | onComplete: nil, 28 | */ 29 | fps: 60, 30 | unit: false, 31 | duration: 500, 32 | frames: null, 33 | frameSkip: true, 34 | link: 'ignore' 35 | }, 36 | 37 | initialize: function(options){ 38 | this.subject = this.subject || this; 39 | this.setOptions(options); 40 | }, 41 | 42 | getTransition: function(){ 43 | return function(p){ 44 | return -(Math.cos(Math.PI * p) - 1) / 2; 45 | }; 46 | }, 47 | 48 | step: function(now){ 49 | if (this.options.frameSkip){ 50 | var diff = (this.time != null) ? (now - this.time) : 0, frames = diff / this.frameInterval; 51 | this.time = now; 52 | this.frame += frames; 53 | } else { 54 | this.frame++; 55 | } 56 | 57 | if (this.frame < this.frames){ 58 | var delta = this.transition(this.frame / this.frames); 59 | this.set(this.compute(this.from, this.to, delta)); 60 | } else { 61 | this.frame = this.frames; 62 | this.set(this.compute(this.from, this.to, 1)); 63 | this.stop(); 64 | } 65 | }, 66 | 67 | set: function(now){ 68 | return now; 69 | }, 70 | 71 | compute: function(from, to, delta){ 72 | return Fx.compute(from, to, delta); 73 | }, 74 | 75 | check: function(){ 76 | if (!this.isRunning()) return true; 77 | switch (this.options.link){ 78 | case 'cancel': this.cancel(); return true; 79 | case 'chain': this.chain(this.caller.pass(arguments, this)); return false; 80 | } 81 | return false; 82 | }, 83 | 84 | start: function(from, to){ 85 | if (!this.check(from, to)) return this; 86 | this.from = from; 87 | this.to = to; 88 | this.frame = (this.options.frameSkip) ? 0 : -1; 89 | this.time = null; 90 | this.transition = this.getTransition(); 91 | var frames = this.options.frames, fps = this.options.fps, duration = this.options.duration; 92 | this.duration = Fx.Durations[duration] || duration.toInt(); 93 | this.frameInterval = 1000 / fps; 94 | this.frames = frames || Math.round(this.duration / this.frameInterval); 95 | if (this.getThenableState() !== 'pending'){ 96 | this.resetThenable(this.subject); 97 | } 98 | this.fireEvent('start', this.subject); 99 | pushInstance.call(this, fps); 100 | return this; 101 | }, 102 | 103 | stop: function(){ 104 | if (this.isRunning()){ 105 | this.time = null; 106 | pullInstance.call(this, this.options.fps); 107 | if (this.frames == this.frame){ 108 | this.fireEvent('complete', this.subject); 109 | if (!this.callChain()) this.fireEvent('chainComplete', this.subject); 110 | } else { 111 | this.fireEvent('stop', this.subject); 112 | } 113 | this.resolve(this.subject === this ? null : this.subject); 114 | } 115 | return this; 116 | }, 117 | 118 | cancel: function(){ 119 | if (this.isRunning()){ 120 | this.time = null; 121 | pullInstance.call(this, this.options.fps); 122 | this.frame = this.frames; 123 | this.fireEvent('cancel', this.subject).clearChain(); 124 | this.reject(this.subject); 125 | } 126 | return this; 127 | }, 128 | 129 | pause: function(){ 130 | if (this.isRunning()){ 131 | this.time = null; 132 | pullInstance.call(this, this.options.fps); 133 | } 134 | return this; 135 | }, 136 | 137 | resume: function(){ 138 | if (this.isPaused()) pushInstance.call(this, this.options.fps); 139 | return this; 140 | }, 141 | 142 | isRunning: function(){ 143 | var list = instances[this.options.fps]; 144 | return list && list.contains(this); 145 | }, 146 | 147 | isPaused: function(){ 148 | return (this.frame < this.frames) && !this.isRunning(); 149 | } 150 | 151 | }); 152 | 153 | Fx.compute = function(from, to, delta){ 154 | return (to - from) * delta + from; 155 | }; 156 | 157 | Fx.Durations = {'short': 250, 'normal': 500, 'long': 1000}; 158 | 159 | // global timers 160 | 161 | var instances = {}, timers = {}; 162 | 163 | var loop = function(){ 164 | var now = Date.now(); 165 | for (var i = this.length; i--;){ 166 | var instance = this[i]; 167 | if (instance) instance.step(now); 168 | } 169 | }; 170 | 171 | var pushInstance = function(fps){ 172 | var list = instances[fps] || (instances[fps] = []); 173 | list.push(this); 174 | if (!timers[fps]) timers[fps] = loop.periodical(Math.round(1000 / fps), list); 175 | }; 176 | 177 | var pullInstance = function(fps){ 178 | var list = instances[fps]; 179 | if (list){ 180 | list.erase(this); 181 | if (!list.length && timers[fps]){ 182 | delete instances[fps]; 183 | timers[fps] = clearInterval(timers[fps]); 184 | } 185 | } 186 | }; 187 | 188 | })(); 189 | -------------------------------------------------------------------------------- /Source/Request/Request.HTML.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | 4 | name: Request.HTML 5 | 6 | description: Extends the basic Request Class with additional methods for interacting with HTML responses. 7 | 8 | license: MIT-style license. 9 | 10 | requires: [Element, Request] 11 | 12 | provides: Request.HTML 13 | 14 | ... 15 | */ 16 | 17 | Request.HTML = new Class({ 18 | 19 | Extends: Request, 20 | 21 | options: { 22 | update: false, 23 | append: false, 24 | evalScripts: true, 25 | filter: false, 26 | headers: { 27 | Accept: 'text/html, application/xml, text/xml, */*' 28 | } 29 | }, 30 | 31 | success: function(text){ 32 | var options = this.options, response = this.response; 33 | 34 | response.html = text.stripScripts(function(script){ 35 | response.javascript = script; 36 | }); 37 | 38 | var match = response.html.match(/]*>([\s\S]*?)<\/body>/i); 39 | if (match) response.html = match[1]; 40 | var temp = new Element('div').set('html', response.html); 41 | 42 | response.tree = temp.childNodes; 43 | response.elements = temp.getElements(options.filter || '*'); 44 | 45 | if (options.filter) response.tree = response.elements; 46 | if (options.update){ 47 | var update = document.id(options.update).empty(); 48 | if (options.filter) update.adopt(response.elements); 49 | else update.set('html', response.html); 50 | } else if (options.append){ 51 | var append = document.id(options.append); 52 | if (options.filter) response.elements.reverse().inject(append); 53 | else append.adopt(temp.getChildren()); 54 | } 55 | if (options.evalScripts) Browser.exec(response.javascript); 56 | 57 | this.onSuccess(response.tree, response.elements, response.html, response.javascript); 58 | this.resolve({tree: response.tree, elements: response.elements, html: response.html, javascript: response.javascript}); 59 | } 60 | 61 | }); 62 | 63 | Element.Properties.load = { 64 | 65 | set: function(options){ 66 | var load = this.get('load').cancel(); 67 | load.setOptions(options); 68 | return this; 69 | }, 70 | 71 | get: function(){ 72 | var load = this.retrieve('load'); 73 | if (!load){ 74 | load = new Request.HTML({data: this, link: 'cancel', update: this, method: 'get'}); 75 | this.store('load', load); 76 | } 77 | return load; 78 | } 79 | 80 | }; 81 | 82 | Element.implement({ 83 | 84 | load: function(){ 85 | this.get('load').send(Array.link(arguments, {data: Type.isObject, url: Type.isString})); 86 | return this; 87 | } 88 | 89 | }); 90 | -------------------------------------------------------------------------------- /Source/Request/Request.JSON.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | 4 | name: Request.JSON 5 | 6 | description: Extends the basic Request Class with additional methods for sending and receiving JSON data. 7 | 8 | license: MIT-style license. 9 | 10 | requires: [Request, JSON] 11 | 12 | provides: Request.JSON 13 | 14 | ... 15 | */ 16 | 17 | Request.JSON = new Class({ 18 | 19 | Extends: Request, 20 | 21 | options: { 22 | /*onError: function(text, error){},*/ 23 | secure: true 24 | }, 25 | 26 | initialize: function(options){ 27 | this.parent(options); 28 | Object.append(this.headers, { 29 | 'Accept': 'application/json', 30 | 'X-Request': 'JSON' 31 | }); 32 | }, 33 | 34 | success: function(text){ 35 | var json; 36 | try { 37 | json = this.response.json = JSON.decode(text, this.options.secure); 38 | } catch (error){ 39 | this.fireEvent('error', [text, error]); 40 | return; 41 | } 42 | if (json == null){ 43 | this.failure(); 44 | } else { 45 | this.onSuccess(json, text); 46 | this.resolve({json: json, text: text}); 47 | } 48 | } 49 | 50 | }); 51 | -------------------------------------------------------------------------------- /Source/Types/Array.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | 4 | name: Array 5 | 6 | description: Contains Array Prototypes like each, contains, and erase. 7 | 8 | license: MIT-style license. 9 | 10 | requires: [Type] 11 | 12 | provides: Array 13 | 14 | ... 15 | */ 16 | 17 | Array.implement({ 18 | 19 | /**/ 20 | every: function(fn, bind){ 21 | for (var i = 0, l = this.length >>> 0; i < l; i++){ 22 | if ((i in this) && !fn.call(bind, this[i], i, this)) return false; 23 | } 24 | return true; 25 | }, 26 | 27 | filter: function(fn, bind){ 28 | var results = []; 29 | for (var value, i = 0, l = this.length >>> 0; i < l; i++) if (i in this){ 30 | value = this[i]; 31 | if (fn.call(bind, value, i, this)) results.push(value); 32 | } 33 | return results; 34 | }, 35 | 36 | indexOf: function(item, from){ 37 | var length = this.length >>> 0; 38 | for (var i = (from < 0) ? Math.max(0, length + from) : from || 0; i < length; i++){ 39 | if (this[i] === item) return i; 40 | } 41 | return -1; 42 | }, 43 | 44 | map: function(fn, bind){ 45 | var length = this.length >>> 0, results = Array(length); 46 | for (var i = 0; i < length; i++){ 47 | if (i in this) results[i] = fn.call(bind, this[i], i, this); 48 | } 49 | return results; 50 | }, 51 | 52 | some: function(fn, bind){ 53 | for (var i = 0, l = this.length >>> 0; i < l; i++){ 54 | if ((i in this) && fn.call(bind, this[i], i, this)) return true; 55 | } 56 | return false; 57 | }, 58 | /**/ 59 | 60 | clean: function(){ 61 | return this.filter(function(item){ 62 | return item != null; 63 | }); 64 | }, 65 | 66 | invoke: function(methodName){ 67 | var args = Array.slice(arguments, 1); 68 | return this.map(function(item){ 69 | return item[methodName].apply(item, args); 70 | }); 71 | }, 72 | 73 | associate: function(keys){ 74 | var obj = {}, length = Math.min(this.length, keys.length); 75 | for (var i = 0; i < length; i++) obj[keys[i]] = this[i]; 76 | return obj; 77 | }, 78 | 79 | link: function(object){ 80 | var result = {}; 81 | for (var i = 0, l = this.length; i < l; i++){ 82 | for (var key in object){ 83 | if (object[key](this[i])){ 84 | result[key] = this[i]; 85 | delete object[key]; 86 | break; 87 | } 88 | } 89 | } 90 | return result; 91 | }, 92 | 93 | contains: function(item, from){ 94 | return this.indexOf(item, from) != -1; 95 | }, 96 | 97 | append: function(array){ 98 | this.push.apply(this, array); 99 | return this; 100 | }, 101 | 102 | getLast: function(){ 103 | return (this.length) ? this[this.length - 1] : null; 104 | }, 105 | 106 | getRandom: function(){ 107 | return (this.length) ? this[Number.random(0, this.length - 1)] : null; 108 | }, 109 | 110 | include: function(item){ 111 | if (!this.contains(item)) this.push(item); 112 | return this; 113 | }, 114 | 115 | combine: function(array){ 116 | for (var i = 0, l = array.length; i < l; i++) this.include(array[i]); 117 | return this; 118 | }, 119 | 120 | erase: function(item){ 121 | for (var i = this.length; i--;){ 122 | if (this[i] === item) this.splice(i, 1); 123 | } 124 | return this; 125 | }, 126 | 127 | empty: function(){ 128 | this.length = 0; 129 | return this; 130 | }, 131 | 132 | flatten: function(){ 133 | var array = []; 134 | for (var i = 0, l = this.length; i < l; i++){ 135 | var type = typeOf(this[i]); 136 | if (type == 'null') continue; 137 | array = array.concat((type == 'array' || type == 'collection' || type == 'arguments' || instanceOf(this[i], Array)) ? Array.flatten(this[i]) : this[i]); 138 | } 139 | return array; 140 | }, 141 | 142 | pick: function(){ 143 | for (var i = 0, l = this.length; i < l; i++){ 144 | if (this[i] != null) return this[i]; 145 | } 146 | return null; 147 | }, 148 | 149 | hexToRgb: function(array){ 150 | if (this.length != 3) return null; 151 | var rgb = this.map(function(value){ 152 | if (value.length == 1) value += value; 153 | return parseInt(value, 16); 154 | }); 155 | return (array) ? rgb : 'rgb(' + rgb + ')'; 156 | }, 157 | 158 | rgbToHex: function(array){ 159 | if (this.length < 3) return null; 160 | if (this.length == 4 && this[3] == 0 && !array) return 'transparent'; 161 | var hex = []; 162 | for (var i = 0; i < 3; i++){ 163 | var bit = (this[i] - 0).toString(16); 164 | hex.push((bit.length == 1) ? '0' + bit : bit); 165 | } 166 | return (array) ? hex : '#' + hex.join(''); 167 | } 168 | 169 | }); 170 | 171 | //<1.2compat> 172 | 173 | Array.alias('extend', 'append'); 174 | 175 | var $pick = this.$pick = function(){ 176 | return Array.convert(arguments).pick(); 177 | }; 178 | 179 | // 180 | -------------------------------------------------------------------------------- /Source/Types/DOMEvent.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | 4 | name: Event 5 | 6 | description: Contains the Event Type, to make the event object cross-browser. 7 | 8 | license: MIT-style license. 9 | 10 | requires: [Window, Document, Array, Function, String, Object] 11 | 12 | provides: Event 13 | 14 | ... 15 | */ 16 | 17 | (function(){ 18 | 19 | var _keys = {}; 20 | var normalizeWheelSpeed = function(event){ 21 | var normalized; 22 | if (event.wheelDelta){ 23 | normalized = event.wheelDelta % 120 == 0 ? event.wheelDelta / 120 : event.wheelDelta / 12; 24 | } else { 25 | var rawAmount = event.deltaY || event.detail || 0; 26 | normalized = -(rawAmount % 3 == 0 ? rawAmount / 3 : rawAmount * 10); 27 | } 28 | return normalized; 29 | }; 30 | 31 | var DOMEvent = this.DOMEvent = new Type('DOMEvent', function(event, win){ 32 | if (!win) win = window; 33 | event = event || win.event; 34 | if (event.$extended) return event; 35 | this.event = event; 36 | this.$extended = true; 37 | this.shift = event.shiftKey; 38 | this.control = event.ctrlKey; 39 | this.alt = event.altKey; 40 | this.meta = event.metaKey; 41 | var type = this.type = event.type; 42 | var target = event.target || event.srcElement; 43 | while (target && target.nodeType == 3) target = target.parentNode; 44 | this.target = document.id(target); 45 | 46 | if (type.indexOf('key') == 0){ 47 | var code = this.code = (event.which || event.keyCode); 48 | if (!this.shift || type != 'keypress') this.key = _keys[code]/*<1.3compat>*/ || Object.keyOf(Event.Keys, code)/**/; 49 | if (type == 'keydown' || type == 'keyup'){ 50 | if (code > 111 && code < 124) this.key = 'f' + (code - 111); 51 | else if (code > 95 && code < 106) this.key = code - 96; 52 | } 53 | if (this.key == null) this.key = String.fromCharCode(code).toLowerCase(); 54 | } else if (type == 'click' || type == 'dblclick' || type == 'contextmenu' || type == 'wheel' || type == 'DOMMouseScroll' || type.indexOf('mouse') == 0){ 55 | var doc = win.document; 56 | doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body; 57 | this.page = { 58 | x: (event.pageX != null) ? event.pageX : event.clientX + doc.scrollLeft, 59 | y: (event.pageY != null) ? event.pageY : event.clientY + doc.scrollTop 60 | }; 61 | this.client = { 62 | x: (event.pageX != null) ? event.pageX - win.pageXOffset : event.clientX, 63 | y: (event.pageY != null) ? event.pageY - win.pageYOffset : event.clientY 64 | }; 65 | if (type == 'DOMMouseScroll' || type == 'wheel' || type == 'mousewheel') this.wheel = normalizeWheelSpeed(event); 66 | this.rightClick = (event.which == 3 || event.button == 2); 67 | if (type == 'mouseover' || type == 'mouseout' || type == 'mouseenter' || type == 'mouseleave'){ 68 | var overTarget = type == 'mouseover' || type == 'mouseenter'; 69 | var related = event.relatedTarget || event[(overTarget ? 'from' : 'to') + 'Element']; 70 | while (related && related.nodeType == 3) related = related.parentNode; 71 | this.relatedTarget = document.id(related); 72 | } 73 | } else if (type.indexOf('touch') == 0 || type.indexOf('gesture') == 0){ 74 | this.rotation = event.rotation; 75 | this.scale = event.scale; 76 | this.targetTouches = event.targetTouches; 77 | this.changedTouches = event.changedTouches; 78 | var touches = this.touches = event.touches; 79 | if (touches && touches[0]){ 80 | var touch = touches[0]; 81 | this.page = {x: touch.pageX, y: touch.pageY}; 82 | this.client = {x: touch.clientX, y: touch.clientY}; 83 | } 84 | } 85 | 86 | if (!this.client) this.client = {}; 87 | if (!this.page) this.page = {}; 88 | }); 89 | 90 | DOMEvent.implement({ 91 | 92 | stop: function(){ 93 | return this.preventDefault().stopPropagation(); 94 | }, 95 | 96 | stopPropagation: function(){ 97 | if (this.event.stopPropagation) this.event.stopPropagation(); 98 | else this.event.cancelBubble = true; 99 | return this; 100 | }, 101 | 102 | preventDefault: function(){ 103 | if (this.event.preventDefault) this.event.preventDefault(); 104 | else this.event.returnValue = false; 105 | return this; 106 | } 107 | 108 | }); 109 | 110 | DOMEvent.defineKey = function(code, key){ 111 | _keys[code] = key; 112 | return this; 113 | }; 114 | 115 | DOMEvent.defineKeys = DOMEvent.defineKey.overloadSetter(true); 116 | 117 | DOMEvent.defineKeys({ 118 | '38': 'up', '40': 'down', '37': 'left', '39': 'right', 119 | '27': 'esc', '32': 'space', '8': 'backspace', '9': 'tab', 120 | '46': 'delete', '13': 'enter' 121 | }); 122 | 123 | })(); 124 | 125 | /*<1.3compat>*/ 126 | var Event = this.Event = DOMEvent; 127 | Event.Keys = {}; 128 | /**/ 129 | 130 | /*<1.2compat>*/ 131 | 132 | Event.Keys = new Hash(Event.Keys); 133 | 134 | /**/ 135 | -------------------------------------------------------------------------------- /Source/Types/Function.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | 4 | name: Function 5 | 6 | description: Contains Function Prototypes like create, bind, pass, and delay. 7 | 8 | license: MIT-style license. 9 | 10 | requires: Type 11 | 12 | provides: Function 13 | 14 | ... 15 | */ 16 | 17 | Function.extend({ 18 | 19 | attempt: function(){ 20 | for (var i = 0, l = arguments.length; i < l; i++){ 21 | try { 22 | return arguments[i](); 23 | } catch (e){} 24 | } 25 | return null; 26 | } 27 | 28 | }); 29 | 30 | Function.implement({ 31 | 32 | attempt: function(args, bind){ 33 | try { 34 | return this.apply(bind, Array.convert(args)); 35 | } catch (e){} 36 | 37 | return null; 38 | }, 39 | 40 | /**/ 41 | bind: function(that){ 42 | var self = this, 43 | args = arguments.length > 1 ? Array.slice(arguments, 1) : null, 44 | F = function(){}; 45 | 46 | var bound = function(){ 47 | var context = that, length = arguments.length; 48 | if (this instanceof bound){ 49 | F.prototype = self.prototype; 50 | context = new F; 51 | } 52 | var result = (!args && !length) 53 | ? self.call(context) 54 | : self.apply(context, args && length ? args.concat(Array.slice(arguments)) : args || arguments); 55 | return context == that ? result : context; 56 | }; 57 | return bound; 58 | }, 59 | /**/ 60 | 61 | pass: function(args, bind){ 62 | var self = this; 63 | if (args != null) args = Array.convert(args); 64 | return function(){ 65 | return self.apply(bind, args || arguments); 66 | }; 67 | }, 68 | 69 | delay: function(delay, bind, args){ 70 | return setTimeout(this.pass((args == null ? [] : args), bind), delay); 71 | }, 72 | 73 | periodical: function(periodical, bind, args){ 74 | return setInterval(this.pass((args == null ? [] : args), bind), periodical); 75 | } 76 | 77 | }); 78 | 79 | //<1.2compat> 80 | 81 | delete Function.prototype.bind; 82 | 83 | Function.implement({ 84 | 85 | create: function(options){ 86 | var self = this; 87 | options = options || {}; 88 | return function(event){ 89 | var args = options.arguments; 90 | args = (args != null) ? Array.convert(args) : Array.slice(arguments, (options.event) ? 1 : 0); 91 | if (options.event) args.unshift(event || window.event); 92 | var returns = function(){ 93 | return self.apply(options.bind || null, args); 94 | }; 95 | if (options.delay) return setTimeout(returns, options.delay); 96 | if (options.periodical) return setInterval(returns, options.periodical); 97 | if (options.attempt) return Function.attempt(returns); 98 | return returns(); 99 | }; 100 | }, 101 | 102 | bind: function(bind, args){ 103 | var self = this; 104 | if (args != null) args = Array.convert(args); 105 | return function(){ 106 | return self.apply(bind, args || arguments); 107 | }; 108 | }, 109 | 110 | bindWithEvent: function(bind, args){ 111 | var self = this; 112 | if (args != null) args = Array.convert(args); 113 | return function(event){ 114 | return self.apply(bind, (args == null) ? arguments : [event].concat(args)); 115 | }; 116 | }, 117 | 118 | run: function(args, bind){ 119 | return this.apply(bind, Array.convert(args)); 120 | } 121 | 122 | }); 123 | 124 | if (Object.create == Function.prototype.create) Object.create = null; 125 | 126 | var $try = Function.attempt; 127 | 128 | // 129 | -------------------------------------------------------------------------------- /Source/Types/Number.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | 4 | name: Number 5 | 6 | description: Contains Number Prototypes like limit, round, times, and ceil. 7 | 8 | license: MIT-style license. 9 | 10 | requires: Type 11 | 12 | provides: Number 13 | 14 | ... 15 | */ 16 | 17 | Number.implement({ 18 | 19 | limit: function(min, max){ 20 | return Math.min(max, Math.max(min, this)); 21 | }, 22 | 23 | round: function(precision){ 24 | precision = Math.pow(10, precision || 0).toFixed(precision < 0 ? -precision : 0); 25 | return Math.round(this * precision) / precision; 26 | }, 27 | 28 | times: function(fn, bind){ 29 | for (var i = 0; i < this; i++) fn.call(bind, i, this); 30 | }, 31 | 32 | toFloat: function(){ 33 | return parseFloat(this); 34 | }, 35 | 36 | toInt: function(base){ 37 | return parseInt(this, base || 10); 38 | } 39 | 40 | }); 41 | 42 | Number.alias('each', 'times'); 43 | 44 | (function(math){ 45 | 46 | var methods = {}; 47 | 48 | math.each(function(name){ 49 | if (!Number[name]) methods[name] = function(){ 50 | return Math[name].apply(null, [this].concat(Array.convert(arguments))); 51 | }; 52 | }); 53 | 54 | Number.implement(methods); 55 | 56 | })(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']); 57 | -------------------------------------------------------------------------------- /Source/Types/Object.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | 4 | name: Object 5 | 6 | description: Object generic methods 7 | 8 | license: MIT-style license. 9 | 10 | requires: Type 11 | 12 | provides: [Object, Hash] 13 | 14 | ... 15 | */ 16 | 17 | (function(){ 18 | 19 | Object.extend({ 20 | 21 | subset: function(object, keys){ 22 | var results = {}; 23 | for (var i = 0, l = keys.length; i < l; i++){ 24 | var k = keys[i]; 25 | if (k in object) results[k] = object[k]; 26 | } 27 | return results; 28 | }, 29 | 30 | map: function(object, fn, bind){ 31 | var results = {}; 32 | var keys = Object.keys(object); 33 | for (var i = 0; i < keys.length; i++){ 34 | var key = keys[i]; 35 | results[key] = fn.call(bind, object[key], key, object); 36 | } 37 | return results; 38 | }, 39 | 40 | filter: function(object, fn, bind){ 41 | var results = {}; 42 | var keys = Object.keys(object); 43 | for (var i = 0; i < keys.length; i++){ 44 | var key = keys[i], value = object[key]; 45 | if (fn.call(bind, value, key, object)) results[key] = value; 46 | } 47 | return results; 48 | }, 49 | 50 | every: function(object, fn, bind){ 51 | var keys = Object.keys(object); 52 | for (var i = 0; i < keys.length; i++){ 53 | var key = keys[i]; 54 | if (!fn.call(bind, object[key], key)) return false; 55 | } 56 | return true; 57 | }, 58 | 59 | some: function(object, fn, bind){ 60 | var keys = Object.keys(object); 61 | for (var i = 0; i < keys.length; i++){ 62 | var key = keys[i]; 63 | if (fn.call(bind, object[key], key)) return true; 64 | } 65 | return false; 66 | }, 67 | 68 | values: function(object){ 69 | var values = []; 70 | var keys = Object.keys(object); 71 | for (var i = 0; i < keys.length; i++){ 72 | var k = keys[i]; 73 | values.push(object[k]); 74 | } 75 | return values; 76 | }, 77 | 78 | getLength: function(object){ 79 | return Object.keys(object).length; 80 | }, 81 | 82 | keyOf: function(object, value){ 83 | var keys = Object.keys(object); 84 | for (var i = 0; i < keys.length; i++){ 85 | var key = keys[i]; 86 | if (object[key] === value) return key; 87 | } 88 | return null; 89 | }, 90 | 91 | contains: function(object, value){ 92 | return Object.keyOf(object, value) != null; 93 | }, 94 | 95 | toQueryString: function(object, base){ 96 | var queryString = []; 97 | 98 | Object.each(object, function(value, key){ 99 | if (base) key = base + '[' + key + ']'; 100 | var result; 101 | switch (typeOf(value)){ 102 | case 'object': result = Object.toQueryString(value, key); break; 103 | case 'array': 104 | var qs = {}; 105 | value.each(function(val, i){ 106 | qs[i] = val; 107 | }); 108 | result = Object.toQueryString(qs, key); 109 | break; 110 | default: result = key + '=' + encodeURIComponent(value); 111 | } 112 | if (value != null) queryString.push(result); 113 | }); 114 | 115 | return queryString.join('&'); 116 | } 117 | 118 | }); 119 | 120 | })(); 121 | 122 | //<1.2compat> 123 | 124 | Hash.implement({ 125 | 126 | has: Object.prototype.hasOwnProperty, 127 | 128 | keyOf: function(value){ 129 | return Object.keyOf(this, value); 130 | }, 131 | 132 | hasValue: function(value){ 133 | return Object.contains(this, value); 134 | }, 135 | 136 | extend: function(properties){ 137 | Hash.each(properties || {}, function(value, key){ 138 | Hash.set(this, key, value); 139 | }, this); 140 | return this; 141 | }, 142 | 143 | combine: function(properties){ 144 | Hash.each(properties || {}, function(value, key){ 145 | Hash.include(this, key, value); 146 | }, this); 147 | return this; 148 | }, 149 | 150 | erase: function(key){ 151 | if (this.hasOwnProperty(key)) delete this[key]; 152 | return this; 153 | }, 154 | 155 | get: function(key){ 156 | return (this.hasOwnProperty(key)) ? this[key] : null; 157 | }, 158 | 159 | set: function(key, value){ 160 | if (!this[key] || this.hasOwnProperty(key)) this[key] = value; 161 | return this; 162 | }, 163 | 164 | empty: function(){ 165 | Hash.each(this, function(value, key){ 166 | delete this[key]; 167 | }, this); 168 | return this; 169 | }, 170 | 171 | include: function(key, value){ 172 | if (this[key] == null) this[key] = value; 173 | return this; 174 | }, 175 | 176 | map: function(fn, bind){ 177 | return new Hash(Object.map(this, fn, bind)); 178 | }, 179 | 180 | filter: function(fn, bind){ 181 | return new Hash(Object.filter(this, fn, bind)); 182 | }, 183 | 184 | every: function(fn, bind){ 185 | return Object.every(this, fn, bind); 186 | }, 187 | 188 | some: function(fn, bind){ 189 | return Object.some(this, fn, bind); 190 | }, 191 | 192 | getKeys: function(){ 193 | return Object.keys(this); 194 | }, 195 | 196 | getValues: function(){ 197 | return Object.values(this); 198 | }, 199 | 200 | toQueryString: function(base){ 201 | return Object.toQueryString(this, base); 202 | } 203 | 204 | }); 205 | 206 | Hash.extend = Object.append; 207 | 208 | Hash.alias({indexOf: 'keyOf', contains: 'hasValue'}); 209 | 210 | // 211 | -------------------------------------------------------------------------------- /Source/Types/String.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | 4 | name: String 5 | 6 | description: Contains String Prototypes like camelCase, capitalize, test, and toInt. 7 | 8 | license: MIT-style license. 9 | 10 | requires: [Type, Array] 11 | 12 | provides: String 13 | 14 | ... 15 | */ 16 | 17 | String.implement({ 18 | 19 | // 20 | contains: function(string, index){ 21 | return (index ? String(this).slice(index) : String(this)).indexOf(string) > -1; 22 | }, 23 | // 24 | 25 | test: function(regex, params){ 26 | return ((typeOf(regex) == 'regexp') ? regex : new RegExp('' + regex, params)).test(this); 27 | }, 28 | 29 | trim: function(){ 30 | return String(this).replace(/^\s+|\s+$/g, ''); 31 | }, 32 | 33 | clean: function(){ 34 | return String(this).replace(/\s+/g, ' ').trim(); 35 | }, 36 | 37 | camelCase: function(){ 38 | return String(this).replace(/-\D/g, function(match){ 39 | return match.charAt(1).toUpperCase(); 40 | }); 41 | }, 42 | 43 | hyphenate: function(){ 44 | return String(this).replace(/[A-Z]/g, function(match){ 45 | return ('-' + match.charAt(0).toLowerCase()); 46 | }); 47 | }, 48 | 49 | capitalize: function(){ 50 | return String(this).replace(/\b[a-z]/g, function(match){ 51 | return match.toUpperCase(); 52 | }); 53 | }, 54 | 55 | escapeRegExp: function(){ 56 | return String(this).replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1'); 57 | }, 58 | 59 | toInt: function(base){ 60 | return parseInt(this, base || 10); 61 | }, 62 | 63 | toFloat: function(){ 64 | return parseFloat(this); 65 | }, 66 | 67 | hexToRgb: function(array){ 68 | var hex = String(this).match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); 69 | return (hex) ? hex.slice(1).hexToRgb(array) : null; 70 | }, 71 | 72 | rgbToHex: function(array){ 73 | var rgb = String(this).match(/\d{1,3}/g); 74 | return (rgb) ? rgb.rgbToHex(array) : null; 75 | }, 76 | 77 | substitute: function(object, regexp){ 78 | return String(this).replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){ 79 | if (match.charAt(0) == '\\') return match.slice(1); 80 | return (object[name] != null) ? object[name] : ''; 81 | }); 82 | } 83 | 84 | }); 85 | 86 | //<1.4compat> 87 | String.prototype.contains = function(string, separator){ 88 | return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : String(this).indexOf(string) > -1; 89 | }; 90 | // 91 | -------------------------------------------------------------------------------- /Source/Utilities/Cookie.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | 4 | name: Cookie 5 | 6 | description: Class for creating, reading, and deleting browser Cookies. 7 | 8 | license: MIT-style license. 9 | 10 | credits: 11 | - Based on the functions by Peter-Paul Koch (http://quirksmode.org). 12 | 13 | requires: [Options, Browser] 14 | 15 | provides: Cookie 16 | 17 | ... 18 | */ 19 | 20 | var Cookie = new Class({ 21 | 22 | Implements: Options, 23 | 24 | options: { 25 | path: '/', 26 | domain: false, 27 | duration: false, 28 | secure: false, 29 | document: document, 30 | encode: true, 31 | httpOnly: false 32 | }, 33 | 34 | initialize: function(key, options){ 35 | this.key = key; 36 | this.setOptions(options); 37 | }, 38 | 39 | write: function(value){ 40 | if (this.options.encode) value = encodeURIComponent(value); 41 | if (this.options.domain) value += '; domain=' + this.options.domain; 42 | if (this.options.path) value += '; path=' + this.options.path; 43 | if (this.options.duration){ 44 | var date = new Date(); 45 | date.setTime(date.getTime() + this.options.duration * 24 * 60 * 60 * 1000); 46 | value += '; expires=' + date.toGMTString(); 47 | } 48 | if (this.options.secure) value += '; secure'; 49 | if (this.options.httpOnly) value += '; HttpOnly'; 50 | this.options.document.cookie = this.key + '=' + value; 51 | return this; 52 | }, 53 | 54 | read: function(){ 55 | var value = this.options.document.cookie.match('(?:^|;)\\s*' + this.key.escapeRegExp() + '=([^;]*)'); 56 | return (value) ? decodeURIComponent(value[1]) : null; 57 | }, 58 | 59 | dispose: function(){ 60 | new Cookie(this.key, Object.merge({}, this.options, {duration: -1})).write(''); 61 | return this; 62 | } 63 | 64 | }); 65 | 66 | Cookie.write = function(key, value, options){ 67 | return new Cookie(key, options).write(value); 68 | }; 69 | 70 | Cookie.read = function(key){ 71 | return new Cookie(key).read(); 72 | }; 73 | 74 | Cookie.dispose = function(key, options){ 75 | return new Cookie(key, options).dispose(); 76 | }; 77 | -------------------------------------------------------------------------------- /Source/Utilities/DOMReady.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | 4 | name: DOMReady 5 | 6 | description: Contains the custom event domready. 7 | 8 | license: MIT-style license. 9 | 10 | requires: [Browser, Element, Element.Event] 11 | 12 | provides: [DOMReady, DomReady] 13 | 14 | ... 15 | */ 16 | 17 | (function(window, document){ 18 | 19 | var ready, 20 | loaded, 21 | checks = [], 22 | shouldPoll, 23 | timer, 24 | testElement = document.createElement('div'); 25 | 26 | var domready = function(){ 27 | clearTimeout(timer); 28 | if (!ready){ 29 | Browser.loaded = ready = true; 30 | document.removeListener('DOMContentLoaded', domready).removeListener('readystatechange', check); 31 | document.fireEvent('domready'); 32 | window.fireEvent('domready'); 33 | } 34 | // cleanup scope vars 35 | document = window = testElement = null; 36 | }; 37 | 38 | var check = function(){ 39 | for (var i = checks.length; i--;) if (checks[i]()){ 40 | domready(); 41 | return true; 42 | } 43 | return false; 44 | }; 45 | 46 | var poll = function(){ 47 | clearTimeout(timer); 48 | if (!check()) timer = setTimeout(poll, 10); 49 | }; 50 | 51 | document.addListener('DOMContentLoaded', domready); 52 | 53 | /**/ 54 | // doScroll technique by Diego Perini http://javascript.nwbox.com/IEContentLoaded/ 55 | // testElement.doScroll() throws when the DOM is not ready, only in the top window 56 | var doScrollWorks = function(){ 57 | try { 58 | testElement.doScroll(); 59 | return true; 60 | } catch (e){} 61 | return false; 62 | }; 63 | // If doScroll works already, it can't be used to determine domready 64 | // e.g. in an iframe 65 | if (testElement.doScroll && !doScrollWorks()){ 66 | checks.push(doScrollWorks); 67 | shouldPoll = true; 68 | } 69 | /**/ 70 | 71 | if (document.readyState) checks.push(function(){ 72 | var state = document.readyState; 73 | return (state == 'loaded' || state == 'complete'); 74 | }); 75 | 76 | if ('onreadystatechange' in document) document.addListener('readystatechange', check); 77 | else shouldPoll = true; 78 | 79 | if (shouldPoll) poll(); 80 | 81 | Element.Events.domready = { 82 | onAdd: function(fn){ 83 | if (ready) fn.call(this); 84 | } 85 | }; 86 | 87 | // Make sure that domready fires before load 88 | Element.Events.load = { 89 | base: 'load', 90 | onAdd: function(fn){ 91 | if (loaded && this == window) fn.call(this); 92 | }, 93 | condition: function(){ 94 | if (this == window){ 95 | domready(); 96 | delete Element.Events.load; 97 | } 98 | return true; 99 | } 100 | }; 101 | 102 | // This is based on the custom load event 103 | window.addEvent('load', function(){ 104 | loaded = true; 105 | }); 106 | 107 | })(window, document); 108 | -------------------------------------------------------------------------------- /Source/Utilities/JSON.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | 4 | name: JSON 5 | 6 | description: JSON encoder and decoder. 7 | 8 | license: MIT-style license. 9 | 10 | SeeAlso: 11 | 12 | requires: [Array, String, Number, Function] 13 | 14 | provides: JSON 15 | 16 | ... 17 | */ 18 | 19 | if (typeof JSON == 'undefined') this.JSON = {}; 20 | 21 | //<1.2compat> 22 | 23 | JSON = new Hash({ 24 | stringify: JSON.stringify, 25 | parse: JSON.parse 26 | }); 27 | 28 | // 29 | 30 | (function(){ 31 | 32 | var special = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'}; 33 | 34 | var escape = function(chr){ 35 | return special[chr] || '\\u' + ('0000' + chr.charCodeAt(0).toString(16)).slice(-4); 36 | }; 37 | 38 | JSON.validate = function(string){ 39 | string = string.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'). 40 | replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'). 41 | replace(/(?:^|:|,)(?:\s*\[)+/g, ''); 42 | 43 | return (/^[\],:{}\s]*$/).test(string); 44 | }; 45 | 46 | JSON.encode = JSON.stringify ? function(obj){ 47 | return JSON.stringify(obj); 48 | } : function(obj){ 49 | if (obj && obj.toJSON) obj = obj.toJSON(); 50 | 51 | switch (typeOf(obj)){ 52 | case 'string': 53 | return '"' + obj.replace(/[\x00-\x1f\\"]/g, escape) + '"'; 54 | case 'array': 55 | return '[' + obj.map(JSON.encode).clean() + ']'; 56 | case 'object': case 'hash': 57 | var string = []; 58 | Object.each(obj, function(value, key){ 59 | var json = JSON.encode(value); 60 | if (json) string.push(JSON.encode(key) + ':' + json); 61 | }); 62 | return '{' + string + '}'; 63 | case 'number': case 'boolean': return '' + obj; 64 | case 'null': return 'null'; 65 | } 66 | 67 | return null; 68 | }; 69 | 70 | JSON.secure = true; 71 | //<1.4compat> 72 | JSON.secure = false; 73 | // 74 | 75 | JSON.decode = function(string, secure){ 76 | if (!string || typeOf(string) != 'string') return null; 77 | 78 | if (secure == null) secure = JSON.secure; 79 | if (secure){ 80 | if (JSON.parse) return JSON.parse(string); 81 | if (!JSON.validate(string)) throw new Error('JSON could not decode the input; security is enabled and the value is not secure.'); 82 | } 83 | 84 | return eval('(' + string + ')'); 85 | }; 86 | 87 | })(); 88 | -------------------------------------------------------------------------------- /Source/license.txt: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2006-2015 Valerio Proietti, 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Specs/Core/Native.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | name: Native 4 | requires: ~ 5 | provides: ~ 6 | ... 7 | */ 8 | 9 | //<1.2compat> 10 | (function(){ 11 | 12 | var Instrument = new Native({ 13 | 14 | name: 'instrument', 15 | 16 | initialize: function(name){ 17 | this.name = name; 18 | } 19 | 20 | }); 21 | 22 | Instrument.implement({ 23 | 24 | method: function(){ 25 | return this.property + ' ' + this.name; 26 | }, 27 | 28 | property: 'stuff' 29 | 30 | }); 31 | 32 | var Car = new Native({ 33 | 34 | name: 'car', 35 | 36 | initialize: function(name){ 37 | this.name = name; 38 | } 39 | 40 | }); 41 | 42 | Car.implement({ 43 | 44 | property: 'stuff', 45 | 46 | method: function(){ 47 | return this.name + '_' + this.property; 48 | } 49 | 50 | }); 51 | 52 | describe('Native (private)', function(){ 53 | 54 | it('should allow implementation over existing methods when browser option is not set', function(){ 55 | Instrument.implement({ property: 'staff' }); 56 | var myInstrument = new Instrument('xeelophone'); 57 | expect(myInstrument.method()).to.equal('staff xeelophone'); 58 | }); 59 | 60 | it('should allow generic calls', function(){ 61 | expect(Car.method({name: 'ciccio', property: 'bello'})).to.equal('ciccio_bello'); 62 | }); 63 | 64 | it('should have a "native" type', function(){ 65 | expect(Native.type(Car)).to.equal(true); 66 | }); 67 | 68 | }); 69 | 70 | })(); 71 | // 72 | -------------------------------------------------------------------------------- /Specs/Core/Type.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | name: Type 4 | requires: ~ 5 | provides: ~ 6 | ... 7 | */ 8 | 9 | (function(){ 10 | 11 | var Instrument = new Type('Instrument', function(name){ 12 | this.name = name; 13 | }); 14 | 15 | Instrument.implement({ 16 | 17 | method: function(){ 18 | return this.property + ' ' + this.name; 19 | }, 20 | 21 | property: 'stuff' 22 | 23 | }); 24 | 25 | var Car = new Type('Car', function(name){ 26 | this.name = name; 27 | }); 28 | 29 | Car.implement({ 30 | 31 | property: 'stuff', 32 | 33 | method: function(){ 34 | return this.name + '_' + this.property; 35 | } 36 | 37 | }); 38 | 39 | describe('Type (private)', function(){ 40 | 41 | it('should allow implementation over existing methods when browser option is not set', function(){ 42 | Instrument.implement({ property: 'staff' }); 43 | var myInstrument = new Instrument('xeelophone'); 44 | expect(myInstrument.method()).to.equal('staff xeelophone'); 45 | }); 46 | 47 | it('should allow generic calls', function(){ 48 | expect(Car.method({name: 'ciccio', property: 'bello'})).to.equal('ciccio_bello'); 49 | }); 50 | 51 | it('should have a "native" type', function(){ 52 | expect(Type.isType(Car)).to.equal(true); 53 | }); 54 | 55 | }); 56 | 57 | })(); 58 | -------------------------------------------------------------------------------- /Specs/Element/Element.Delegation.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | name: Element.Delegation 4 | requires: ~ 5 | provides: ~ 6 | ... 7 | */ 8 | 9 | describe('Element.Delegation', function(){ 10 | 11 | describe('fireEvent', function(){ 12 | 13 | it('should fire the added `click:relay(a)` function with fireEvent', function(){ 14 | var a = new Element('a[text=Hello World]'), result, self; 15 | var div = new Element('div').inject(document.body).adopt(a).addEvent('click:relay(a)', function(){ 16 | result = arguments[1]; 17 | self = this; 18 | }).fireEvent('click:relay(a)', [null, a]); 19 | 20 | expect(result).to.equal(a); 21 | expect(self).to.equal(div); 22 | 23 | div.destroy(); 24 | }); 25 | 26 | it('Should fire click events through fireEvent and delegate when a target is passed as argument', function(){ 27 | var a = new Element('a[text="Hello World"]'), result, self; 28 | var div = new Element('div').inject(document.body).adopt(a).addEvent('click:relay(a)', function(){ 29 | result = arguments[1]; 30 | self = this; 31 | }).fireEvent('click', [null, a]); 32 | 33 | expect(result).to.equal(a); 34 | expect(self).to.equal(a); 35 | 36 | div.destroy(); 37 | }); 38 | 39 | it('Should not fire click events through fireEvent when added as delegated events without an target', function(){ 40 | var spy = sinon.spy(); 41 | var a = new Element('a[text="Hello World"]'); 42 | var div = new Element('div').inject(document.body).adopt(a).addEvent('click:relay(a)', spy).fireEvent('click'); 43 | 44 | expect(spy.called).to.equal(false); 45 | 46 | div.destroy(); 47 | }); 48 | 49 | }); 50 | 51 | describe('removeEvent', function(){ 52 | 53 | describe('submit', function(){ 54 | 55 | it('should remove nicely', function(){ 56 | var element = new Element('div', { 57 | html: '
' 58 | }); 59 | 60 | var input = element.getElement('input'); 61 | var listener = function(){}; 62 | 63 | element.addEvent('submit:relay(form)', listener); 64 | 65 | // IE8, fireEvent on the observer element. This adds the 66 | // submit event to the
element. 67 | element.fireEvent('focusin', [{target: input}, input]); 68 | 69 | // Remove element, which also removes the form, 70 | element.getElement('div').destroy(); 71 | 72 | // Now removing the event, should remove the submit event from the 73 | // form, but it's not there anymore, so it may not throw an error. 74 | element.removeEvent('submit:relay(form)', listener); 75 | }); 76 | 77 | }); 78 | 79 | }); 80 | 81 | }); 82 | -------------------------------------------------------------------------------- /Specs/Fx/Fx.Morph.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | name: Fx.Morph 4 | requires: ~ 5 | provides: ~ 6 | ... 7 | */ 8 | 9 | describe('Fx.Morph', function(){ 10 | 11 | beforeEach(function(){ 12 | this.clock = sinon.useFakeTimers(); 13 | 14 | this.div = new Element('div', {'class': 'pos-abs-left'}); 15 | this.style = new Element('style'); 16 | var definition = [ 17 | '.pos-abs-left {', 18 | ' position: absolute;', 19 | ' width: 200px;', 20 | ' height: 200px;', 21 | ' left: 10%;', 22 | ' background: red', 23 | '}' 24 | ].join(''); 25 | 26 | [this.style, this.div].invoke('inject', document.body); 27 | 28 | if (this.style.styleSheet) this.style.styleSheet.cssText = definition; 29 | else this.style.set('text', definition); 30 | }); 31 | 32 | afterEach(function(){ 33 | this.clock.reset(); 34 | this.clock.restore(); 35 | [this.div, this.style].invoke('destroy'); 36 | }); 37 | 38 | it('should morph the style of an element', function(){ 39 | var element = new Element('div', { 40 | styles: { 41 | height: 100, 42 | width: 100 43 | } 44 | }).inject(document.body); 45 | 46 | var fx = new Fx.Morph(element, { 47 | duration: 100 48 | }); 49 | 50 | fx.start({ 51 | height: [10, 50], 52 | width: [10, 50] 53 | }); 54 | 55 | this.clock.tick(200); 56 | 57 | expect(element.getStyle('height').toInt()).to.equal(50); 58 | expect(element.getStyle('width').toInt()).to.equal(50); 59 | element.destroy(); 60 | }); 61 | 62 | it('should set morph options with the element getter and setter', function(){ 63 | var element = new Element('div'); 64 | 65 | element.set('morph', { 66 | duration: 100 67 | }); 68 | 69 | expect(element.get('morph').options.duration).to.equal(100); 70 | }); 71 | 72 | it('should morph between % units', function(){ 73 | sinon.spy(this.div, 'setStyle'); 74 | this.div.set('morph', {unit : '%'}).morph({'left': [10, 50]}); 75 | 76 | this.clock.tick(1000); 77 | 78 | expect(this.div.setStyle.calledWith('left', ['10%'])).to.equal(true); 79 | expect(this.div.setStyle.calledWith('left', ['50%'])).to.equal(true); 80 | 81 | this.div.setStyle.restore(); 82 | }); 83 | 84 | it('it should morph when the unit option is set, but an empty value', function(){ 85 | this.div.set('morph', { 86 | duration: 100, 87 | unit: 'px' 88 | }).morph({ 89 | opacity: 1, 90 | top : 100 91 | }); 92 | 93 | this.clock.tick(150); 94 | 95 | expect(this.div.getStyle('top')).to.equal('100px'); 96 | expect(this.div.getStyle('opacity')).to.equal(1); 97 | }); 98 | 99 | it('it should morph when the unit option is set, but the style value is a number', function(){ 100 | this.div.setStyles({ 101 | top: '50px', 102 | opacity: 0 103 | }).set('morph', { 104 | duration: 100, 105 | unit: 'px' 106 | }).morph({ 107 | opacity: 1, 108 | top : 100 109 | }); 110 | 111 | this.clock.tick(150); 112 | 113 | expect(this.div.getStyle('top')).to.equal('100px'); 114 | expect(this.div.getStyle('opacity')).to.equal(1); 115 | }); 116 | 117 | }); 118 | -------------------------------------------------------------------------------- /Specs/Fx/Fx.Tween.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | name: Fx.Tween 4 | requires: ~ 5 | provides: ~ 6 | ... 7 | */ 8 | 9 | describe('Fx.Tween', function(){ 10 | 11 | beforeEach(function(){ 12 | this.clock = sinon.useFakeTimers(); 13 | }); 14 | 15 | afterEach(function(){ 16 | this.clock.reset(); 17 | this.clock.restore(); 18 | }); 19 | 20 | it('should tween the style of an element', function(){ 21 | var element = new Element('div#st_el', { 22 | styles: { 23 | height: 100 24 | } 25 | }).inject(document.body); 26 | 27 | var fx = new Fx.Tween(element, { 28 | duration: 100, 29 | property: 'height' 30 | }); 31 | 32 | fx.start(10, 50); 33 | 34 | this.clock.tick(200); 35 | 36 | expect(element.getStyle('height').toInt()).to.equal(50); 37 | element.destroy(); 38 | }); 39 | 40 | it('should tween the style of an element via Element.tween', function(){ 41 | var element = new Element('div', { 42 | styles: { 43 | width: 100 44 | }, 45 | tween: { 46 | duration: 100 47 | } 48 | }).inject(document.body).tween('width', 50); 49 | 50 | this.clock.tick(200); 51 | 52 | expect(element.getStyle('width').toInt()).to.equal(50); 53 | element.destroy(); 54 | }); 55 | 56 | it('should fade an element', function(){ 57 | var element = new Element('div', { 58 | styles: { opacity: 0 } 59 | }).inject(document.body); 60 | 61 | element.set('tween', { 62 | duration: 100 63 | }); 64 | 65 | element.fade('in'); 66 | 67 | this.clock.tick(130); 68 | 69 | expect(element.getStyle('opacity').toInt()).to.equal(1); 70 | element.destroy(); 71 | }); 72 | 73 | it('should fade out an element and fade in when triggerd inside the onComplete event', function(){ 74 | var element = new Element('div').inject($(document.body)); 75 | var firstOpacity, lastOpacity, lastVisibility, runOnce = true; 76 | element.set('tween', { 77 | duration: 100, 78 | onComplete: function(){ 79 | if (runOnce){ 80 | firstOpacity = this.element.getStyle('opacity'); 81 | runOnce && this.element.fade(); 82 | runOnce = false; 83 | } 84 | } 85 | }); 86 | 87 | element.fade(); 88 | this.clock.tick(250); 89 | lastOpacity = element.getStyle('opacity'); 90 | lastVisibility = element.getStyle('visibility'); 91 | 92 | expect(firstOpacity.toInt()).to.equal(0); 93 | expect(lastOpacity.toInt()).to.equal(1); 94 | expect(lastVisibility).to.equal('visible'); 95 | element.destroy(); 96 | }); 97 | 98 | it('should fade an element with toggle', function(){ 99 | var element = new Element('div', { 100 | styles: { opacity: 1 } 101 | }).inject(document.body); 102 | 103 | element.set('tween', { 104 | duration: 100 105 | }); 106 | 107 | element.fade('toggle'); 108 | 109 | this.clock.tick(130); 110 | 111 | expect(element.getStyle('opacity').toInt()).to.equal(0); 112 | element.destroy(); 113 | }); 114 | 115 | it('should set tween options with the element getter en setter', function(){ 116 | var element = new Element('div'); 117 | 118 | element.set('tween', { 119 | duration: 100 120 | }); 121 | 122 | expect(element.get('tween').options.duration).to.equal(100); 123 | }); 124 | 125 | it('should fade an element with toggle', function(){ 126 | var element = new Element('div', { 127 | tween: { 128 | duration: 10 129 | } 130 | }).setStyle('background-color', '#fff').inject(document.body); 131 | 132 | element.highlight('#f00'); 133 | 134 | this.clock.tick(40); 135 | 136 | expect(['#fff', '#ffffff']).to.contain(element.getStyle('background-color').toLowerCase()); 137 | element.destroy(); 138 | }); 139 | 140 | describe('Element.fade', function(){ 141 | 142 | it('Should set the visibility style', function(){ 143 | var element = new Element('div', {styles: {'visibility': 'visible'}}).inject(document.body); 144 | 145 | expect(element.getStyles('opacity', 'visibility')).to.eql({opacity: 1, visibility: 'visible'}); 146 | 147 | element.fade(0.5); 148 | this.clock.tick(600); 149 | expect(element.getStyles('opacity', 'visibility')).to.eql({opacity: 0.5, visibility: 'visible'}); 150 | 151 | element.fade(0); 152 | this.clock.tick(600); 153 | expect(element.getStyles('opacity', 'visibility')).to.eql({opacity: 0, visibility: 'hidden'}); 154 | 155 | element.fade(1); 156 | this.clock.tick(600); 157 | expect(element.getStyles('opacity', 'visibility')).to.eql({opacity: 1, visibility: 'visible'}); 158 | 159 | element.destroy(); 160 | }); 161 | 162 | it('should accept the old style arguments (0, 1)', function(){ 163 | var element = new Element('div'); 164 | element.fade(1, 0); 165 | 166 | var tween = element.get('tween'); 167 | 168 | expect(tween.from[0].value).to.equal(1); 169 | expect(tween.to[0].value).to.equal(0); 170 | 171 | this.clock.tick(1000); 172 | 173 | expect(element.getStyle('opacity')).to.equal(0); 174 | }); 175 | 176 | }); 177 | 178 | }); 179 | -------------------------------------------------------------------------------- /Specs/Fx/Fx.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | name: Fx 4 | requires: ~ 5 | provides: ~ 6 | ... 7 | */ 8 | 9 | describe('Fx', function(){ 10 | 11 | beforeEach(function(){ 12 | this.clock = sinon.useFakeTimers(); 13 | }); 14 | 15 | afterEach(function(){ 16 | this.clock.reset(); 17 | this.clock.restore(); 18 | }); 19 | 20 | Object.each(Fx.Transitions, function(value, transition){ 21 | if (transition == 'extend') return; 22 | 23 | it('should start a Fx and call the onComplete event with ' + transition + ' as timing function', function(){ 24 | var onComplete = sinon.spy(), 25 | onStart = sinon.spy(); 26 | 27 | var fx = new Fx({ 28 | duration: 500, 29 | transition: Fx.Transitions[transition], 30 | onComplete: onComplete, 31 | onStart: onStart 32 | }); 33 | 34 | expect(onStart.called).to.equal(false); 35 | 36 | fx.start(10, 20); 37 | 38 | this.clock.tick(100); 39 | expect(onStart.called).to.equal(true); 40 | expect(onComplete.called).to.equal(false); 41 | 42 | this.clock.tick(1000); 43 | expect(onComplete.called).to.equal(true); 44 | }); 45 | }); 46 | 47 | it('should cancel a Fx', function(){ 48 | var onCancel = sinon.spy(); 49 | 50 | var fx = new Fx({ 51 | duration: 500, 52 | transition: 'sine:in:out', 53 | onCancel: onCancel 54 | }); 55 | 56 | fx.start(); 57 | expect(onCancel.called).to.equal(false); 58 | 59 | fx.cancel(); 60 | expect(onCancel.called).to.equal(true); 61 | }); 62 | 63 | it('should set the computed value', function(){ 64 | var FxLog = new Class({ 65 | Extends: Fx, 66 | set: function(current){ 67 | this.foo = current; 68 | } 69 | }); 70 | 71 | var fx = new FxLog({ 72 | duration: 1000 73 | }).start(0, 10); 74 | 75 | this.clock.tick(2000); 76 | expect(fx.foo).to.equal(10); 77 | }); 78 | 79 | it('should pause and resume', function(){ 80 | var FxLog = new Class({ 81 | Extends: Fx, 82 | set: function(current){ 83 | this.foo = current; 84 | } 85 | }); 86 | 87 | var fx = new FxLog({ 88 | duration: 2000 89 | }).start(0, 1); 90 | 91 | this.clock.tick(1000); 92 | 93 | var value; 94 | 95 | fx.pause(); 96 | value = fx.foo; 97 | expect(fx.foo).to.be.greaterThan(0); 98 | expect(fx.foo).to.be.lessThan(1); 99 | 100 | this.clock.tick(1000); 101 | 102 | expect(fx.foo).to.equal(value); 103 | fx.resume(); 104 | 105 | this.clock.tick(2000); 106 | expect(fx.foo).to.equal(1); 107 | }); 108 | 109 | it('should chain the Fx', function(){ 110 | var counter = 0; 111 | var fx = new Fx({ 112 | duration: 500, 113 | onComplete: function(){ 114 | counter++; 115 | }, 116 | link: 'chain' 117 | }); 118 | 119 | fx.start().start(); 120 | 121 | this.clock.tick(1000); 122 | this.clock.tick(1000); 123 | 124 | expect(counter).to.equal(2); 125 | }); 126 | 127 | it('should cancel the Fx after a new Fx:start with the link = cancel option', function(){ 128 | var onCancel = sinon.spy(); 129 | 130 | var fx = new Fx({ 131 | duration: 500, 132 | onCancel: onCancel, 133 | link: 'cancel' 134 | }); 135 | 136 | fx.start().start(); 137 | 138 | this.clock.tick(1000); 139 | expect(onCancel.called).to.equal(true); 140 | }); 141 | 142 | it('should return the paused state', function(){ 143 | var fx = new Fx({ 144 | duration: 500 145 | }).start(); 146 | 147 | expect(fx.isPaused()).to.equal(false); 148 | 149 | this.clock.tick(300); 150 | fx.pause(); 151 | 152 | expect(fx.isPaused()).to.equal(true); 153 | 154 | fx.resume(); 155 | this.clock.tick(600); 156 | expect(fx.isPaused()).to.equal(false); 157 | }); 158 | 159 | }); 160 | 161 | describe('Fx (thenable)', function(){ 162 | 163 | beforeEach(function(){ 164 | this.fx = new Fx({ 165 | duration: 1, 166 | transition: 'sine:in:out' 167 | }); 168 | 169 | var self = this; 170 | this.onFulfilled = sinon.spy(function(){ self.expectations.apply(self, arguments); }); 171 | this.onRejected = sinon.spy(function(){ self.expectations.apply(self, arguments); }); 172 | 173 | this.fx.then(this.onFulfilled, this.onRejected); 174 | }); 175 | 176 | it('should fulfill when completed', function(done){ 177 | this.fx.start(10, 20); 178 | 179 | expect(this.onRejected.called).to.equal(false); 180 | expect(this.onFulfilled.called).to.equal(false); 181 | 182 | this.expectations = function(){ 183 | var error; 184 | try { 185 | expect(this.onRejected.called).to.equal(false); 186 | expect(this.onFulfilled.called).to.equal(true); 187 | expect(this.onFulfilled.args[0][0]).to.equal(null); 188 | } catch (thrown){ 189 | error = thrown; 190 | } 191 | done(error); 192 | }; 193 | }); 194 | 195 | it('should reject when cancelled', function(done){ 196 | this.fx.start(); 197 | 198 | expect(this.onFulfilled.called).to.equal(false); 199 | expect(this.onRejected.called).to.equal(false); 200 | 201 | this.fx.cancel(); 202 | 203 | this.expectations = function(){ 204 | var error; 205 | try { 206 | expect(this.onFulfilled.called).to.equal(false); 207 | expect(this.onRejected.called).to.equal(true); 208 | expect(this.onRejected.args[0][0]).to.equal(this.fx); 209 | } catch (thrown){ 210 | error = thrown; 211 | } 212 | done(error); 213 | }; 214 | }); 215 | 216 | }); 217 | -------------------------------------------------------------------------------- /Specs/Request/Request.JSON.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | name: Request.JSON 4 | requires: ~ 5 | provides: ~ 6 | ... 7 | */ 8 | 9 | describe('Request.JSON', function(){ 10 | 11 | beforeEach(function(){ 12 | this.spy = sinon.spy(); 13 | this.xhr = sinon.useFakeXMLHttpRequest(); 14 | var requests = this.requests = []; 15 | this.xhr.onCreate = function(xhr){ 16 | requests.push(xhr); 17 | }; 18 | }); 19 | 20 | afterEach(function(){ 21 | this.xhr.restore(); 22 | }); 23 | 24 | it('should create a JSON request', function(){ 25 | var response = '{"ok":true}'; 26 | 27 | this.spy.identity = 'Requst.JSON'; 28 | this.request = new Request.JSON({ 29 | url: '../Helpers/request.php', 30 | onComplete: this.spy 31 | }).send({data: { 32 | '__response': response 33 | }}); 34 | 35 | this.requests[0].respond(200, {'Content-Type': 'text/json'}, response); 36 | expect(this.spy.called).to.equal(true); 37 | 38 | // Checks the first argument from the first call. 39 | expect(this.spy.args[0][0]).to.eql({ok: true}); 40 | }); 41 | 42 | it('should fire the error event', function(){ 43 | var response = '{"ok":function(){invalid;}}'; 44 | 45 | this.spy.identity = 'Requst.JSON error'; 46 | this.request = new Request.JSON({ 47 | url: '../Helpers/request.php', 48 | onError: this.spy 49 | }).send({data: { 50 | '__response': response 51 | }}); 52 | 53 | this.requests[0].respond(200, {'Content-Type': 'text/json'}, response); 54 | expect(this.spy.called).to.equal(true); 55 | 56 | // Checks the first argument from the first call. 57 | expect(this.spy.args[0][0]).to.equal('{"ok":function(){invalid;}}'); 58 | }); 59 | 60 | }); 61 | -------------------------------------------------------------------------------- /Specs/Types/Number.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | name: Number 4 | requires: ~ 5 | provides: ~ 6 | ... 7 | */ 8 | 9 | describe('Number Method', function(){ 10 | 11 | describe('Number.toInt', function(){ 12 | 13 | it('should convert a number to an integer', function(){ 14 | expect((111).toInt()).to.equal(111); 15 | }); 16 | 17 | it('should convert a number depending on the radix provided', function(){ 18 | expect((111).toInt(2)).to.equal(7); 19 | expect((0x16).toInt(10)).to.equal(22); // ECMA standard, radix is optional so if starts with 0x then parsed as hexadecimal. 20 | expect((016).toInt(10)).to.equal(14); // ECMA standard, radix is optional so if starts with 0 then parsed as octal. 21 | }); 22 | 23 | }); 24 | 25 | describe('Number.toFloat', function(){ 26 | 27 | it('should convert a number to a float', function(){ 28 | expect((1.00).toFloat()).to.equal(1); 29 | expect((1.12 - 0.12).toFloat()).to.equal(1); 30 | expect((0.0010).toFloat()).to.equal(0.001); 31 | expect((Number.MIN_VALUE).toFloat()).to.equal(Number.MIN_VALUE); 32 | }); 33 | }); 34 | 35 | describe('Number.limit', function(){ 36 | 37 | it('should limit a number within a range', function(){ 38 | expect((-1).limit(0, 1)).to.equal(0); 39 | expect((3).limit(1, 2)).to.equal(2); 40 | }); 41 | 42 | it('should not limit a number if within the range', function(){ 43 | expect((2).limit(0, 4)).to.equal(2); 44 | }); 45 | 46 | }); 47 | 48 | describe('Number.round', function(){ 49 | 50 | it('should round a number to the nearest whole number if units place is not specified', function(){ 51 | expect((0.01).round()).to.equal(0); 52 | }); 53 | 54 | it('should round a number according the units place specified', function(){ 55 | expect((0.01).round(2)).to.equal(0.01); 56 | expect((1).round(3)).to.equal(1); 57 | expect((-1.01).round()).to.equal(-1); 58 | expect((-1.01).round(2)).to.equal(-1.01); 59 | expect((111).round(-1)).to.equal(110); 60 | expect((-111).round(-2)).to.equal(-100); 61 | expect((100).round(-5)).to.equal(0); 62 | }); 63 | 64 | }); 65 | 66 | describe('Number.times', function(){ 67 | 68 | it('should call the function for the specified number of times', function(){ 69 | var found = 0; 70 | (3).times(function(i){ 71 | found = i; 72 | }); 73 | 74 | var found2 = -1; 75 | (0).times(function(i){ 76 | found2 = i; 77 | }); 78 | 79 | expect(found).to.equal(2); 80 | expect(found2).to.equal(-1); 81 | }); 82 | 83 | it('should bind and call the function for the specified number of times', function(){ 84 | var aTest = 'hi'; 85 | var found3 = false; 86 | (1).times(function(){ 87 | found3 = (this == aTest); 88 | }, aTest); 89 | expect(found3).to.equal(true); 90 | }); 91 | 92 | }); 93 | 94 | }); 95 | 96 | (function(math){ 97 | 98 | describe('Number Math Methods', function(){ 99 | 100 | Object.each(math, function(value, key){ 101 | var b = value.test[1]; 102 | it('should return the ' + value.title + ' value of the number' + ((b) ? ' and the passed number' : ''), function(){ 103 | expect(value.test[0][key](b)).to.equal(Math[key].apply(null, value.test)); 104 | }); 105 | }); 106 | 107 | }); 108 | 109 | })({ 110 | abs: { test: [-1], title: 'absolute' }, 111 | acos: { test: [0], title: 'arc cosine' }, 112 | asin: { test: [0.5], title: 'arc sine' }, 113 | atan: { test: [0.5], title: 'arc tangent' }, 114 | atan2: { test: [0.1, 0.5], title: 'arc tangent' }, 115 | ceil: { test: [0.6], title: 'number closest to and not less than the' }, 116 | cos: { test: [30], title: 'cosine' }, 117 | exp: { test: [2], title: 'exponent' }, 118 | floor: { test: [2.4], title: 'integer closet to and not greater than' }, 119 | log: { test: [2], title: 'log' }, 120 | max: { test: [5, 3], title: 'maximum' }, 121 | min: { test: [-4, 2], title: 'minimum' }, 122 | pow: { test: [2, 2], title: 'power' }, 123 | sin: { test: [0.5], title: 'sine' }, 124 | sqrt: { test: [4], title: 'square root' }, 125 | tan: { test: [0.3], title: 'tangent' } 126 | }); 127 | -------------------------------------------------------------------------------- /Specs/Types/Object.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | name: Object 4 | requires: ~ 5 | provides: ~ 6 | ... 7 | */ 8 | 9 | (function(){ 10 | 11 | var object = { a: 'string', b: 233, c: {} }; 12 | 13 | describe('Object Method', function(){ 14 | 15 | describe('Object.subset', function(){ 16 | 17 | it('should return an object with only the specified keys', function(){ 18 | expect(Object.subset(object, ['a', 'b'])).to.eql({a:'string', b:233}); 19 | }); 20 | 21 | it('should ignore undefined keys', function(){ 22 | var obj = { 23 | b: 'string', 24 | d: null 25 | }; 26 | var subset = Object.subset(obj, ['a', 'b', 'c', 'd']); 27 | expect(subset).to.eql({b: 'string', d: null}); 28 | expect('a' in subset).to.equal(false); 29 | expect('c' in subset).to.equal(false); 30 | }); 31 | 32 | }); 33 | 34 | describe('Object.keyOf', function(){ 35 | 36 | it('should return the key of the value or null if not found', function(){ 37 | expect(Object.keyOf(object, 'string')).to.equal('a'); 38 | expect(Object.keyOf(object, 'not found')).to.equal(null); 39 | }); 40 | 41 | }); 42 | 43 | describe('Object.contains', function(){ 44 | 45 | it('should return true if the object contains value otherwise false', function(){ 46 | expect(Object.contains(object, 'string')).to.equal(true); 47 | expect(Object.contains(object, 'not found')).to.equal(false); 48 | }); 49 | 50 | }); 51 | 52 | describe('Object.map', function(){ 53 | 54 | it('should map a new object according to the comparator', function(){ 55 | expect(Object.map(object, Type.isNumber)).to.eql({a:false, b:true, c:false}); 56 | }); 57 | 58 | }); 59 | 60 | describe('Object.filter', function(){ 61 | 62 | it('should filter the object according to the comparator', function(){ 63 | expect(Object.filter(object, Type.isNumber)).to.eql({b:233}); 64 | }); 65 | 66 | }); 67 | 68 | describe('Object.every', function(){ 69 | 70 | it('should return true if every value matches the comparator, otherwise false', function(){ 71 | expect(Object.every(object, typeOf)).to.equal(true); 72 | expect(Object.every(object, Type.isNumber)).to.equal(false); 73 | }); 74 | 75 | }); 76 | 77 | describe('Object.some', function(){ 78 | 79 | it('should return true if some of the values match the comparator, otherwise false', function(){ 80 | expect(Object.some(object, Type.isNumber)).to.equal(true); 81 | expect(Object.some(object, Type.isArray)).to.equal(false); 82 | }); 83 | 84 | }); 85 | 86 | describe('Object.values', function(){ 87 | 88 | it('values should return an empty array', function(){ 89 | expect(Object.values({})).to.eql([]); 90 | }); 91 | 92 | it('should return an array with the values of the object', function(){ 93 | expect(Object.values(object)).to.eql(['string', 233, {}]); 94 | }); 95 | 96 | }); 97 | 98 | describe('Object.toQueryString', function(){ 99 | 100 | it('should return a query string', function(){ 101 | var myObject = {apple: 'red', lemon: 'yellow'}; 102 | expect(Object.toQueryString(myObject)).to.equal('apple=red&lemon=yellow'); 103 | 104 | var myObject2 = {apple: ['red', 'yellow'], lemon: ['green', 'yellow']}; 105 | expect(Object.toQueryString(myObject2)).to.equal('apple[0]=red&apple[1]=yellow&lemon[0]=green&lemon[1]=yellow'); 106 | 107 | var myObject3 = {fruits: {apple: ['red', 'yellow'], lemon: ['green', 'yellow']}}; 108 | expect(Object.toQueryString(myObject3)).to.equal('fruits[apple][0]=red&fruits[apple][1]=yellow&fruits[lemon][0]=green&fruits[lemon][1]=yellow'); 109 | }); 110 | 111 | }); 112 | 113 | describe('Object.getLength', function(){ 114 | 115 | it('should get the amount of items in an object', function(){ 116 | var object = { 117 | a: [0, 1, 2], 118 | s: "It's-me-Valerio!", 119 | n: 1, 120 | f: 3.14, 121 | b: false 122 | }; 123 | 124 | expect(Object.getLength(object)).to.equal(5); 125 | 126 | object.n = null; 127 | 128 | expect(Object.getLength(object)).to.equal(5); 129 | }); 130 | 131 | }); 132 | 133 | describe('Object.hasOwnProperty', function(){ 134 | 135 | var dit = (typeof window === 'undefined' ? xit : it); 136 | dit('should not fail on window', function(){ 137 | expect(function(){ 138 | var fn = function(){}; 139 | Object.each(window, fn); 140 | Object.keys(window); 141 | Object.values(window); 142 | Object.map(window, fn); 143 | Object.every(window, fn); 144 | Object.some(window, fn); 145 | Object.keyOf(window, document); 146 | }).to.not.throwError(); 147 | }); 148 | 149 | }); 150 | 151 | }); 152 | 153 | })(); 154 | -------------------------------------------------------------------------------- /Specs/Types/String.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | name: String 4 | requires: ~ 5 | provides: ~ 6 | ... 7 | */ 8 | 9 | describe('String Method', function(){ 10 | 11 | describe('String.capitalize', function(){ 12 | 13 | it('should capitalize each word', function(){ 14 | expect('i like cookies'.capitalize()).to.equal('I Like Cookies'); 15 | expect('I Like cOOKIES'.capitalize()).to.equal('I Like COOKIES'); 16 | }); 17 | 18 | }); 19 | 20 | describe('String.camelCase', function(){ 21 | 22 | it('should convert a hyphenated string into a camel cased string', function(){ 23 | expect('i-like-cookies'.camelCase()).to.equal('iLikeCookies'); 24 | expect('I-Like-Cookies'.camelCase()).to.equal('ILikeCookies'); 25 | }); 26 | 27 | }); 28 | 29 | describe('String.hyphenate', function(){ 30 | 31 | it('should convert a camel cased string into a hyphenated string', function(){ 32 | expect('iLikeCookies'.hyphenate()).to.equal('i-like-cookies'); 33 | expect('ILikeCookies'.hyphenate()).to.equal('-i-like-cookies'); 34 | }); 35 | 36 | }); 37 | 38 | describe('String.clean', function(){ 39 | 40 | it('should clean all extraneous whitespace from the string', function(){ 41 | expect(' i like cookies '.clean()).to.equal('i like cookies'); 42 | expect(' i\nlike \n cookies \n\t '.clean()).to.equal('i like cookies'); 43 | }); 44 | 45 | }); 46 | 47 | describe('String.trim', function(){ 48 | 49 | it('should trim left and right whitespace from the string', function(){ 50 | expect(' i like cookies '.trim()).to.equal('i like cookies'); 51 | expect(' i \tlike cookies '.trim()).to.equal('i \tlike cookies'); 52 | }); 53 | 54 | }); 55 | 56 | //<1.4compat> 57 | describe('String.contains', function(){ 58 | 59 | it('should return true if the string contains a string otherwise false', function(){ 60 | expect('i like cookies'.contains('cookies')).to.equal(true); 61 | expect('i,like,cookies'.contains('cookies')).to.equal(true); 62 | expect('mootools'.contains('inefficient javascript')).to.equal(false); 63 | }); 64 | 65 | it('should return true if the string constains the string and separator otherwise false', function(){ 66 | expect('i like cookies'.contains('cookies', ' ')).to.equal(true); 67 | expect('i like cookies'.contains('cookies', ',')).to.equal(false); 68 | 69 | expect('i,like,cookies'.contains('cookies', ' ')).to.equal(false); 70 | expect('i,like,cookies'.contains('cookies', ',')).to.equal(true); 71 | }); 72 | 73 | }); 74 | // 75 | 76 | describe('String.test', function(){ 77 | 78 | it('should return true if the test matches the string otherwise false', function(){ 79 | expect('i like the cookies'.test('cookies')).to.equal(true); 80 | expect('i like cookies'.test('ke coo')).to.equal(true); 81 | expect('I LIKE COOKIES'.test('cookie', 'i')).to.equal(true); 82 | expect('i like cookies'.test('cookiez')).to.equal(false); 83 | }); 84 | 85 | it('should return true if the regular expression test matches the string otherwise false', function(){ 86 | expect('i like cookies'.test(/like/)).to.equal(true); 87 | expect('i like cookies'.test(/^l/)).to.equal(false); 88 | }); 89 | 90 | }); 91 | 92 | describe('String.toInt', function(){ 93 | 94 | it('should convert the string into an integer', function(){ 95 | expect('10'.toInt()).to.equal(10); 96 | expect('10px'.toInt()).to.equal(10); 97 | expect('10.10em'.toInt()).to.equal(10); 98 | }); 99 | 100 | it('should convert the string into an integer with a specific base', function(){ 101 | expect('10'.toInt(5)).to.equal(5); 102 | }); 103 | 104 | }); 105 | 106 | describe('String.toFloat', function(){ 107 | 108 | it('should convert the string into a float', function(){ 109 | expect('10.11'.toFloat()).to.equal(10.11); 110 | expect('10.55px'.toFloat()).to.equal(10.55); 111 | }); 112 | 113 | }); 114 | 115 | describe('String.rgbToHex', function(){ 116 | 117 | it('should convert the string into a CSS hex string', function(){ 118 | expect('rgb(255,255,255)'.rgbToHex()).to.equal('#ffffff'); 119 | expect('rgb(255,255,255,0)'.rgbToHex()).to.equal('transparent'); 120 | }); 121 | 122 | }); 123 | 124 | describe('String.hexToRgb', function(){ 125 | 126 | it('should convert the CSS hex string into a CSS rgb string', function(){ 127 | expect('#fff'.hexToRgb()).to.equal('rgb(255,255,255)'); 128 | expect('ff00'.hexToRgb()).to.equal('rgb(255,0,0)'); 129 | expect('#000000'.hexToRgb()).to.equal('rgb(0,0,0)'); 130 | }); 131 | 132 | }); 133 | 134 | describe('String.substitute', function(){ 135 | 136 | it('should substitute values from objects', function(){ 137 | expect('This is {color}.'.substitute({'color': 'blue'})).to.equal('This is blue.'); 138 | expect('This is {color} and {size}.'.substitute({'color': 'blue', 'size': 'small'})).to.equal('This is blue and small.'); 139 | }); 140 | 141 | it('should substitute values from arrays', function(){ 142 | expect('This is {0}.'.substitute(['blue'])).to.equal('This is blue.'); 143 | expect('This is {0} and {1}.'.substitute(['blue', 'small'])).to.equal('This is blue and small.'); 144 | }); 145 | 146 | it('should remove undefined values', function(){ 147 | expect('Checking {0}, {1}, {2}, {3} and {4}.'.substitute([1, 0, undefined, null])).to.equal('Checking 1, 0, , and .'); 148 | expect('This is {not-set}.'.substitute({})).to.equal('This is .'); 149 | }); 150 | 151 | it('should ignore escaped placeholders', function(){ 152 | expect('Ignore \\{this} but not {that}.'.substitute({'that': 'the others'})).to.equal('Ignore {this} but not the others.'); 153 | }); 154 | 155 | it('should substitute with a custom regex', function(){ 156 | var php = (/\$([\w-]+)/g); 157 | expect('I feel so $language.'.substitute({'language': 'PHP'}, php)).to.equal('I feel so PHP.'); 158 | var ror = (/#\{([^}]+)\}/g); 159 | expect('I feel so #{language}.'.substitute({'language': 'RoR'}, ror)).to.equal('I feel so RoR.'); 160 | }); 161 | 162 | it('should substitute without goofing up nested curly braces', function(){ 163 | expect('fred {is {not} very} cool'.substitute({'is {not':'BROKEN'})).to.not.equal('fred BROKEN very} cool'); 164 | expect('this {should {break} mo} betta'.substitute({'break':'work'})).to.equal('this {should work mo} betta'); 165 | }); 166 | 167 | }); 168 | 169 | }); 170 | -------------------------------------------------------------------------------- /Specs/Utilities/Cookie.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | name: Cookie 4 | requires: ~ 5 | provides: ~ 6 | ... 7 | */ 8 | 9 | describe('Cookie', function(){ 10 | 11 | it('should set a cookie', function(){ 12 | Cookie.write('test', 1); 13 | }); 14 | 15 | it('should read and write a cookie', function(){ 16 | var options = { 17 | duration: 1 18 | }; 19 | 20 | Cookie.write('key', 'value', options); 21 | expect(Cookie.read('key', options)).to.equal('value'); 22 | 23 | Cookie.dispose('key', options); 24 | expect(Cookie.read('key', options)).to.equal(null); 25 | }); 26 | 27 | it('should set HttpCookie flag correctly', function(){ 28 | var instance = new Cookie('key', { 29 | httpOnly: true, 30 | document: { 31 | cookie: '' 32 | } 33 | }).write('value'); 34 | 35 | expect(instance.options.document.cookie.indexOf('HttpOnly')).to.not.equal(-1); 36 | }); 37 | 38 | }); 39 | -------------------------------------------------------------------------------- /Specs/Utilities/DOMReady.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | name: DomReady 4 | requires: ~ 5 | provides: ~ 6 | ... 7 | */ 8 | 9 | /* todo 10 | document.addListener = function(type, fn){ 11 | if (this.addEventListener){ 12 | this.addEventListener(type, fn, false); 13 | } else { 14 | this.attachEvent('on' + type, fn); 15 | } 16 | return this; 17 | }; 18 | 19 | document.removeListener = function(type, fn){ 20 | if (this.removeEventListener){ 21 | this.removeEventListener(type, fn, false); 22 | } else { 23 | this.detachEvent('on' + type, fn); 24 | } 25 | return this; 26 | }; 27 | 28 | window.fireEvent = document.fireEvent = function(type){ 29 | if (type == 'domready'){ 30 | for (var i = 0; i < domreadyCallbacks.length; ++i){ 31 | domreadyCallbacks[i](); 32 | } 33 | } 34 | }; 35 | 36 | window.addEvent = function(){}; 37 | 38 | var Element = this.Element || {}; 39 | Element.Events = {}; 40 | */ 41 | -------------------------------------------------------------------------------- /Specs/Utilities/JSON.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | name: JSON 4 | requires: ~ 5 | provides: ~ 6 | ... 7 | */ 8 | 9 | describe('JSON', function(){ 10 | 11 | it('should encode and decode an object', function(){ 12 | var object = { 13 | a: [0, 1, 2], 14 | s: "It's-me-Valerio!", 15 | u: '\x01', 16 | n: 1, 17 | f: 3.14, 18 | b: false, 19 | nil: null, 20 | o: { 21 | a: 1, 22 | b: [1, 2], 23 | c: { 24 | a: 2, 25 | b: 3 26 | } 27 | } 28 | }; 29 | 30 | expect(JSON.decode(JSON.encode(object))).to.eql(object); 31 | }); 32 | 33 | }); 34 | 35 | describe('JSON', function(){ 36 | 37 | var win = (typeof window === 'undefined' ? global : window); 38 | var goodString = '{"name":"Jim Cowart","location":{"city":{"name":"Chattanooga","population":167674}}}'; 39 | var badString = 'alert("I\'m a bad string!")'; 40 | 41 | it('should parse a valid JSON string by default', function(){ 42 | expect(typeOf(JSON.decode(goodString))).to.equal('object'); 43 | }); 44 | 45 | it('should parse a valid JSON string when secure is set to false', function(){ 46 | expect(typeOf(JSON.decode(goodString, false))).to.equal('object'); 47 | }); 48 | 49 | it('should parse a hazarous string when secure is set to false', function(){ 50 | var _old_alert = win.alert; 51 | win.alert = function(string){ 52 | if (string == "I'm a bad string!") return true; 53 | return false; 54 | }; 55 | expect(JSON.decode(badString, false)).to.equal(true); 56 | win.alert = _old_alert; 57 | }); 58 | 59 | it('should parse a hazarous string when JSON.secure is set to false and secure is not defined', function(){ 60 | var _old_alert = win.alert; 61 | win.alert = function(string){ 62 | if (string == "I'm a bad string!") return true; 63 | return false; 64 | }; 65 | JSON.secure = false; 66 | expect(JSON.decode(badString)).to.equal(true); 67 | win.alert = _old_alert; 68 | JSON.secure = true; 69 | }); 70 | 71 | it('should NOT parse a hazarous string by default', function(){ 72 | var err; 73 | try { 74 | JSON.decode(badString); 75 | } catch (e){ 76 | err = !!e; 77 | }; 78 | expect(err).to.equal(true); 79 | }); 80 | 81 | }); 82 | -------------------------------------------------------------------------------- /Tests/Element/Element.Event.change.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Element Delegation Tests 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 75 | 76 | 77 | 78 | 79 |
80 |

Log

81 |
82 |
83 | 84 | 95 | 96 |
97 | 98 |

Change

99 | 100 |

101 | It should fire events in a consistent way 102 |

103 | 104 |
105 |
106 |
111 |
112 | 113 |
114 | 115 | 126 | 127 |
128 | 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /Tests/Element/Element.adopt.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Element Adopt Leak Test 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Tests/Fx/Fx.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Fx Tests 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 87 | 88 | 89 | 90 | 91 |
92 |

Log

93 |
94 |
95 | 96 | 107 | 108 |
109 | 110 |

Fx.Tween

111 | 112 |

113 | tween 114 |

115 | 116 |
117 | 118 | 133 | 134 | 135 |

Fx.Morph

136 | 137 |

138 | morph 139 |

140 | 141 |
142 | 143 | 161 | 162 |

Element.morph

163 | 164 |

165 | start 166 |

167 | 168 |
169 | 170 | 176 | 177 | 192 | 193 |

Fx.Morph with % as unit

194 | 195 |

196 | morph 197 |

198 | 199 |
200 |
201 |
202 | 203 | 225 | 226 |

.fade

227 | 228 |

229 | fade
230 | 231 |

232 | 233 |
234 |
235 |

test

236 |
237 | 238 | 260 | 261 |
262 | 263 | 264 | 265 | -------------------------------------------------------------------------------- /Tests/package.yml: -------------------------------------------------------------------------------- 1 | name: "Core-Specs-1.4client" 2 | 3 | license: "[MIT License](http://mootools.net/license.txt)" 4 | 5 | copyright: "© [MooTools](http://mootools.net)" 6 | 7 | authors: "[MooTools Development Team](http://mootools.net/developers)" 8 | 9 | sources: 10 | - "Element/Element.Event.js" 11 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mootools", 3 | "homepage": "https://github.com/mootools/mootools-core", 4 | "authors": [ 5 | "Valerio Proietti" 6 | ], 7 | "main": [ 8 | "dist/mootools-core.js", 9 | "dist/mootools-core-compat.js", 10 | "dist/mootools-core-min.js", 11 | "dist/mootools-core-compat-min.js" 12 | ], 13 | "license": "MIT", 14 | "ignore": [ 15 | "**/.*", 16 | "node_modules", 17 | "bower_components", 18 | "Specs", 19 | "Tests", 20 | "Docs" 21 | ], 22 | "description": "MooTools is a compact, modular, Object-Oriented JavaScript framework designed for the intermediate to advanced JavaScript developer.", 23 | "keywords": [ 24 | "mootools", 25 | "browser", 26 | "class", 27 | "utilities", 28 | "types", 29 | "framework", 30 | "DOM", 31 | "Fx", 32 | "Request" 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /developers.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | git remote add mootools https://github.com/mootools/mootools-core.git 3 | git fetch mootools 4 | 5 | # Valerio Proietti 6 | # @kamicane, http://mad4milk.net 7 | git remote add kamicane https://github.com/kamicane/mootools-core.git 8 | git fetch kamicane 9 | 10 | # Tim Wienk 11 | # @timwienk, http://tim.wienk.name 12 | git remote add timwienk https://github.com/timwienk/mootools-core.git 13 | git fetch timwienk 14 | 15 | # Arian Stolwijk 16 | # @astolwijk, http://aryweb.nl 17 | git remote add arian https://github.com/arian/mootools-core.git 18 | git fetch arian 19 | 20 | # Darren Waddell 21 | # @fakedarren, http://blog.fakedarren.com 22 | git remote add fakedarren https://github.com/fakedarren/mootools-core.git 23 | git fetch fakedarren 24 | 25 | # Sebastian Markbåge 26 | # @sebmarkbage, http://calyptus.eu 27 | git remote add calyptus https://github.com/calyptus/mootools-core.git 28 | git fetch calyptus 29 | 30 | # Christoph Pojer 31 | # @cpojer, http://cpojer.net/ 32 | git remote add cpojer https://github.com/cpojer/mootools-core.git 33 | git fetch cpojer 34 | 35 | # Aaron Newton 36 | # @anutron, http://clientcide.com 37 | git remote add anutron https://github.com/anutron/mootools-core.git 38 | git fetch anutron 39 | 40 | # Djamil Legato 41 | # @w00fz, http://djamil.it 42 | git remote add w00fz https://github.com/w00fz/mootools-core.git 43 | git fetch w00fz 44 | 45 | # Fábio Miranda Costa 46 | # @fabiomiranda, http://meiocodigo.com 47 | git remote add fabiomcosta https://github.com/fabiomcosta/mootools-core.git 48 | git fetch fabiomcosta 49 | 50 | # Thomas Aylott 51 | # @SubtleGradient, http://subtlegradient.com 52 | git remote add subtleGradient https://github.com/subtleGradient/mootools-core.git 53 | git fetch subtleGradient 54 | 55 | # Jan Kassens 56 | # @kassens, http://mootools.kassens.net/ 57 | git remote add kassens https://github.com/kassens/mootools-core.git 58 | git fetch kassens 59 | 60 | # Olmo Maldonado 61 | # @ibolmo, http://ibolmo.com/ 62 | git remote add ibolmo https://github.com/ibolmo/mootools-core.git 63 | git fetch ibolmo 64 | 65 | # David Walsh 66 | # @davidwalshblog, http://davidwalsh.name 67 | git remote add darkwing https://github.com/darkwing/mootools-core.git 68 | git fetch darkwing 69 | 70 | # Scott Kyle 71 | # @appden, http://appden.com 72 | git remote add appden https://github.com/appden/mootools-core.git 73 | git fetch appden 74 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mootools-core", 3 | "version": "1.6.1-dev", 4 | "description": "MooTools is a compact, modular, Object-Oriented JavaScript framework designed for the intermediate to advanced JavaScript developer.", 5 | "main": "dist/mootools-core.js", 6 | "scripts": { 7 | "test": "grunt default" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/mootools/mootools-core.git" 12 | }, 13 | "keywords": [ 14 | "mootools", 15 | "browser", 16 | "class", 17 | "utilities", 18 | "types", 19 | "framework", 20 | "DOM", 21 | "Fx", 22 | "Request" 23 | ], 24 | "author": "MooTools Team", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/mootools/mootools-core/issues" 28 | }, 29 | "homepage": "http://mootools.net", 30 | "devDependencies": { 31 | "expect.js": "^0.3.1", 32 | "grunt": "^0.4.5", 33 | "grunt-cli": "^0.1.13", 34 | "grunt-contrib-clean": "^0.6.0", 35 | "grunt-contrib-uglify": "^0.9.2", 36 | "grunt-eslint": "^17.3.1", 37 | "grunt-karma": "^2.0.0", 38 | "grunt-mocha-test": "^0.12.7", 39 | "grunt-mootools-packager": "^0.4.0", 40 | "karma": "^1.7.0", 41 | "karma-expect": "^1.1", 42 | "karma-mocha": "^0.2.0", 43 | "karma-phantomjs-launcher": "^1.0.4", 44 | "karma-sauce-launcher": "^1.2.0", 45 | "karma-sinon-ie": "^1.0", 46 | "load-grunt-tasks": "^3.2", 47 | "mocha": "^2.3", 48 | "phantomjs": "^2.1.7", 49 | "promises-aplus-tests": "^2.1", 50 | "sinon": "~1.14", 51 | "syn": "^0.1.2" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /package.yml: -------------------------------------------------------------------------------- 1 | name: "Core" 2 | 3 | exports: "mootools-core.js" 4 | 5 | web: "[mootools.net](http://mootools.net)" 6 | 7 | description: "MooTools, The JavaScript framework" 8 | 9 | license: "[MIT License](http://mootools.net/license.txt)" 10 | 11 | copyright: "© [MooTools](http://mootools.net)" 12 | 13 | authors: "[MooTools Development Team](http://mootools.net/developers)" 14 | 15 | sources: 16 | - "Source/Core/Core.js" 17 | - "Source/Types/Array.js" 18 | - "Source/Types/String.js" 19 | - "Source/Types/Number.js" 20 | - "Source/Types/Function.js" 21 | - "Source/Types/Object.js" 22 | - "Source/Types/DOMEvent.js" 23 | - "Source/Browser/Browser.js" 24 | - "Source/Class/Class.js" 25 | - "Source/Class/Class.Extras.js" 26 | - "Source/Class/Class.Thenable.js" 27 | - "Source/Slick/Slick.Parser.js" 28 | - "Source/Slick/Slick.Finder.js" 29 | - "Source/Element/Element.js" 30 | - "Source/Element/Element.Style.js" 31 | - "Source/Element/Element.Event.js" 32 | - "Source/Element/Element.Delegation.js" 33 | - "Source/Element/Element.Dimensions.js" 34 | - "Source/Fx/Fx.js" 35 | - "Source/Fx/Fx.CSS.js" 36 | - "Source/Fx/Fx.Tween.js" 37 | - "Source/Fx/Fx.Morph.js" 38 | - "Source/Fx/Fx.Transitions.js" 39 | - "Source/Request/Request.js" 40 | - "Source/Request/Request.HTML.js" 41 | - "Source/Request/Request.JSON.js" 42 | - "Source/Utilities/Cookie.js" 43 | - "Source/Utilities/JSON.js" 44 | - "Source/Utilities/DOMReady.js" 45 | -------------------------------------------------------------------------------- /prepare-release: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | TAGLENGTH=3 4 | COREFILE='Source/Core/Core.js' 5 | PKGFILES='package.json bower.json' 6 | 7 | DIST='node_modules/.bin/grunt' 8 | DIST_ARGS='dist' 9 | DIST_DIR='dist' 10 | 11 | DIR=`dirname "$0"` 12 | COREFILE="$DIR/$COREFILE" 13 | TAG=`echo "$1" | cut -d'.' -f-$TAGLENGTH` 14 | SUFFIX="`echo "$2" | tr '[A-Z]' '[a-z]'`" 15 | BUILD=`sh -c "cd '$DIR' && git rev-parse HEAD"` 16 | CUTLENGTH=`echo "$TAGLENGTH - 1" | bc` 17 | 18 | usage(){ 19 | moo "Usage: $0 [suffix] 20 | 21 | suffix: alpha, beta or rc*" 22 | } 23 | 24 | moo(){ 25 | echo "$1" >&2 26 | exit 1 27 | } 28 | 29 | get_suffixnumber(){ 30 | NUMBER=`echo "$1" | sed 's/^[a-z]*[ ]*\([0-9]*\).*/\1/'` 31 | [ -n "$NUMBER" ] && echo "$NUMBER" || echo "1" 32 | } 33 | 34 | [ -z "$1" -o "$1" = '-h' -o "$1" = '--help' ] && usage 35 | [ -z "$BUILD" ] && moo 'Unable to determine build.' 36 | [ -z "$DIST" -o -x "$DIR/$DIST" ] || moo "Cannot execute '$DIST', did you npm install?" 37 | 38 | until [ -n "`echo "$TAG." | cut -d'.' -f$TAGLENGTH`" ]; do 39 | TAG="$TAG.0" 40 | done 41 | 42 | case "$SUFFIX" in 43 | '') RELEASE=''; SUFFIX='';; 44 | a*) NUMBER="`get_suffixnumber $SUFFIX`"; RELEASE=" Alpha $NUMBER"; SUFFIX="-a$NUMBER";; 45 | b*) NUMBER="`get_suffixnumber $SUFFIX`"; RELEASE=" Beta $NUMBER"; SUFFIX="-b$NUMBER";; 46 | rc*) NUMBER="`get_suffixnumber $SUFFIX`"; RELEASE=" Release Candidate $NUMBER"; SUFFIX="-rc$NUMBER";; 47 | *) moo 'Invalid suffix specified.';; 48 | esac 49 | 50 | if [ "$TAG" != "$1" ]; then 51 | echo -n "Did you mean $TAG$SUFFIX? (y/n): " 52 | read FIXTAG 53 | [ "$FIXTAG" = "y" ] || moo "Invalid tag specified, this project's tags consist of $TAGLENGTH parts." 54 | fi 55 | 56 | sh -c "cd '$DIR' && git show-ref --quiet --tags '$TAG$SUFFIX'" && moo "Tag $TAG$SUFFIX already exists." 57 | 58 | if [ -z "$SUFFIX" ]; then 59 | MINOR=`echo "$TAG" | cut -d'.' -f$TAGLENGTH-` 60 | [ -z "$MINOR" ] && MINOR='0' 61 | NEXTTAG="`echo "$TAG" | cut -d'.' -f-$CUTLENGTH`.`echo "$MINOR + 1" | bc`-dev" 62 | else 63 | NEXTTAG="${TAG}-dev" 64 | fi 65 | 66 | if [ -n "$DIST" -a -d "$DIR/$DIST_DIR" ]; then 67 | echo -n "The '$DIST_DIR' directory already exists. Overwrite it? (y/n): " 68 | read DELETEDIST 69 | if [ "$DELETEDIST" = "y" ]; then 70 | sh -c "cd '$DIR' && git rm -r '$DIR/$DIST_DIR'" 71 | else 72 | moo "Aborting, will not overwrite '$DIST_DIR'." 73 | fi 74 | fi 75 | 76 | # Replace build and version strings. 77 | sed -i".$BUILD" -e "s/\(version:[ ]*\)'[0-9.]*-dev'/\1'$TAG$SUFFIX'/" -e "s/\(build:[ ]*\)'%build%'/\1'$BUILD'/" "$COREFILE" || moo "Error setting version and build for $TAG$SUFFIX in $COREFILE." 78 | sh -c "cd '$DIR' && git add '$COREFILE'" || moo "Error adding changed $COREFILE for $TAG$SUFFIX to repository." 79 | for PKGFILE in $PKGFILES; do 80 | PKGFILE="$DIR/$PKGFILE" 81 | sed -i".$BUILD" -e "s/^\([ ]*\"version\":[ ]*\)\"[0-9.]*-dev\"/\1\"$TAG$SUFFIX\"/" "$PKGFILE" || moo "Error setting version for $TAG$SUFFIX in $PKGFILE." 82 | sh -c "cd '$DIR' && git add '$PKGFILE'" || moo "Error adding changed $PKGFILE for $TAG$SUFFIX to repository." 83 | done 84 | 85 | # Build dist files. 86 | if [ -n "$DIST" ]; then 87 | echo "Building '$DIST_DIR' files." >&2 88 | sh -c "cd '$DIR' && $DIST $DIST_ARGS" || moo "Error building '$DIST_DIR' files." 89 | sh -c "cd '$DIR' && git add -f '$DIR/$DIST_DIR'" || moo "Error adding '$DIST_DIR' files to repository." 90 | echo "Successfully built '$DIST_DIR' files." >&2 91 | fi 92 | 93 | # Make the new release final. 94 | sh -c "cd '$DIR' && git commit -qm 'Welcome $TAG$SUFFIX.'" || moo "Error committing $TAG$SUFFIX." 95 | sh -c "cd '$DIR' && git tag -am '$TAG$RELEASE.' '$TAG$SUFFIX'" || moo "Error tagging $TAG$SUFFIX." 96 | echo "Tagged $TAG$SUFFIX." >&2 97 | 98 | # Revert to old corefile and pkgfiles. 99 | mv "$COREFILE.$BUILD" "$COREFILE" || moo "Error reverting version and build in $COREFILE." 100 | for PKGFILE in $PKGFILES; do 101 | PKGFILE="$DIR/$PKGFILE" 102 | mv "$PKGFILE.$BUILD" "$PKGFILE" || moo "Error reverting version in $PKFILE." 103 | done 104 | 105 | # Replace build and version strings. 106 | sed -i".$BUILD" -e "s/\(version:[ ]*\)'[0-9.]*-dev'/\1'$NEXTTAG'/" "$COREFILE" || moo "Error setting version $NEXTTAG in $COREFILE." 107 | sh -c "cd '$DIR' && git add '$COREFILE'" || moo "Error adding changed $COREFILE for $NEXTTAG to repository." 108 | for PKGFILE in $PKGFILES; do 109 | PKGFILE="$DIR/$PKGFILE" 110 | sed -i".$BUILD" -e "s/^\([ ]*\"version\":[ ]*\)\"[0-9.]*-dev\"/\1\"$NEXTTAG\"/" "$PKGFILE" || moo "Error setting version for $NEXTTAG in $PKGFILE." 111 | sh -c "cd '$DIR' && git add '$PKGFILE'" || moo "Error adding changed $PKGFILE for $NEXTTAG to repository." 112 | done 113 | 114 | # Clean up temporary and dist files. 115 | rm "$COREFILE.$BUILD" || moo "Error cleaning up $COREFILE.$BUILD." 116 | for PKGFILE in $PKGFILES; do 117 | PKGFILE="$DIR/$PKGFILE" 118 | rm "$PKGFILE.$BUILD" || moo "Error cleaning up $PKGFILE.$BUILD." 119 | done 120 | if [ -n "$DIST" ]; then 121 | sh -c "cd '$DIR' && git rm -qr '$DIR/$DIST_DIR'" || moo "Error cleaning up '$DIST_DIR' files." 122 | fi 123 | 124 | # Make the new dev version final. 125 | sh -c "cd '$DIR' && git commit -qm 'Hello $NEXTTAG.'" || moo "Error committing $NEXTTAG." 126 | echo "Committed $NEXTTAG." >&2 127 | --------------------------------------------------------------------------------