- [ah::js_sources -default] -- will load the prototype javascript library and scriptaculous javascript files by default. +} { + Generates the javascript functions that perform dynamic loading of local javascript files. + http://www.phpied.com/javascript-include/ + WARNING : experimental - It's not recommended to mix scriptaculous and rico. - @author Hamilton Chua (ham@solutiongrove.com) - @creation-date 2006-01-16 + @creation-date 2006-04-20 - @param default Loads the prototype and scriptaculous javascript libraries. - @param source The caller can specify which set of javascript source files to load. - Valid values include - "rounder" : to load the rico corner rounder functions only, use this if you are working primarily with scriptaculous, - "rico" : to load the rico javascript library, - "overlibws" : to load the overlibmws javascript files for dhtml callouts and popups. +} { + set ah_base_url [ah::get_url] + set script "" + return $script +} - @param withbubble Do we want to use the overlibmws plugin for bubble callouts ? - @param scrollable Do we want to use the overlibmws scrollable plugin ? - @param draggable Do we want to use the overlibmws draggable plugin ? +ad_proc -public ah::js_include { + {-js_file ""} +} { + Generates the javscript to include a js file dynamically via DOM to the head section of the page. + WARNING : experimental - @return + @author Hamilton Chua (ham@solutiongrove.com) + @creation-date 2006-04-20 +} { + return "js_include_once('$js_file'); " +} - @error +ad_proc -public ah::js_source_dynamic { + {-js "default"} + {-enclose:boolean} +} { + Uses the javascript dynamic loading functions to load the comma separated list of javascript source file. + WARNING : experimental + @author Hamilton Chua (ham@solutiongrove.com) + @creation-date 2006-04-20 + + + @param js A comma separated list of js files to load. + Possible values include prototype, scriptaculous, rounder, rico, overlibmws, overlibmws_bubble, overlibmws_scroll, overlibmws_drag + @param enclose Specify this if you want the javascript to be enclosed in script tags, which is usually the case unless you include this along with other javascript. } { + set ah_base_url [ah::get_url] set script "" - - if { $default_p } { - # load prototype and scriptaculous js files - append script " \n" - append script " \n" - } else { - if { [info exists source] } { - # load other js libraries - switch $source { - "rico" { - append script " \n" - } - "rounder" { - append script " \n" - } - "overlibmws" { - append script " \n" - append script "\n" - if { $withbubble_p } { - append script "\n" - append script "\n" - } - if { $scrollable_p } { - append script "\n" - } - if { $draggable_p } { - append script "\n" - } - } - default { - # invalid value for source - } + set js_file_list [split $js ","] + + foreach x $js_file_list { + switch $x { + "rico" { + append script [ah::js_include -js_file "${ah_base_url}rico/rico.js"] } + "rounder" { + append script [ah::js_include -js_file "${ah_base_url}rico/rico.js"] + append script [ah::js_include -js_file "${ah_base_url}rico/rounder.js"] + } + "overlibmws" { + append script [ah::js_include -js_file "${ah_base_url}overlibmws/overlibmws.js"] + append script [ah::js_include -js_file "${ah_base_url}overlibmws/overlibmws_overtwo.js"] + } + "overlibmws_bubble" { + append script [ah::js_include -js_file "${ah_base_url}overlibmws/overlibmws_bubble.js"] + } + "overlibmws_scroll" { + append script [ah::js_include -js_file "${ah_base_url}overlibmws/overlibmws_scroll.js"] + } + "overlibmws_drag" { + append script [ah::js_include -js_file "${ah_base_url}overlibmws/overlibmws_draggable.js"] + } + default { + append script [ah::js_include -js_file "${ah_base_url}prototype/prototype.js"] + append script [ah::js_include -js_file "${ah_base_url}scriptaculous/scriptaculous.js"] + } } } - return $script + if { $enclose_p } { set script [ah::enclose_in_script -script ${script} ] } + return $script } ad_proc -private ah::enclose_in_script { @@ -139,7 +145,7 @@ @param script string to enclose in javascript tags. } { - set tag "" return $tag @@ -154,6 +160,7 @@ } { Use prototype's Event object to watch/listen to a specific event from a specific html element. Valid events include click, load, mouseover etc. + See ah::yui::addlistener for Yahoo's implementation which some say is more superior. @author Hamilton Chua (ham@solutiongrove.com) @creation-date 2006-02-28 @@ -196,6 +203,7 @@ ad_proc -public ah::ajaxrequest { -url:required + {-asynchronous "true"} {-pars ""} {-options ""} } { @@ -212,9 +220,10 @@ @param url the url that the javascript will call/query @param pars the parameters that will be passed to Ajax.Request. these parameters should normally be enclosed in single quotes ('') unless you intend to provide a javascript variable or function as a parameter @param options the options that will be passed to the Ajax.Request javascript function + @param asynchronous the default is true } { - set preoptions "asynchronous:'true',method:'post'" + set preoptions "asynchronous:${asynchronous},method:'post'" if { [exists_and_not_null pars] } { append preoptions ",parameters:$pars" @@ -228,6 +237,7 @@ ad_proc -public ah::ajaxupdate { -container:required -url:required + {-asynchronous "true"} {-pars ""} {-options ""} {-effect ""} @@ -236,7 +246,7 @@ {-container_is_var:boolean} } { Generate an Ajax.Updater javascript object. - The parameters are passed directly to Ajax.Update script. + The parameters are passed directly to the Ajax.Update script. You can optionally specify an effect to use as the container is updated. By default it will use the "Appear" effect. Parameters and options are case sensitive, refer to scriptaculous documentation. @@ -268,7 +278,7 @@ set container [ah::isnot_js_var $container] } - set preoptions "asynchronous:'true',method:'post'" + set preoptions "asynchronous:$asynchronous,method:'post'" if { [exists_and_not_null pars] } { append preoptions ",parameters:$pars" @@ -296,6 +306,7 @@ The ah::source must be executed with -source "overlibmws" For more information about the options that you can pass http://www.macridesweb.com/oltest/ + See ah::yui::tooltip for Yahoo's implementation @author Hamilton Chua (ham@solutiongrove.com) @creation-date 2006-02-12 @@ -346,7 +357,7 @@ This proc will generate mouseover and mouseout javascript for dhtml callout or popup using overlibmws and the overlibmws bubble plugin. - The ah::source must be called with -source "overlibmws" -withbubble + The ah::source must be called with -source "overlibmws,overlibmws_bubble" @author Hamilton Chua (ham@solutiongrove.com) @creation-date 2006-01-16 @@ -356,7 +367,6 @@ @param textsize the size of the text in the popup @return - @error } { @@ -382,6 +392,9 @@ @param url the url to make the xmlhttp call to @param pars the parameters in querystring format you want to pass to the url + @param options the options you want to pass to overlibmws + @param type parameter specific to the bubble callout + @param textsize the size of the text in the callout @return @@ -411,10 +424,10 @@ @param element the page element that you want to apply the effect to @param effect specify one of the scriptaculous effects you want to implement - @param options specify the options to pass to the javascript + @param options specify the options to pass to the scritpaculous javascript + @param element_is_var specify this if the element you are passing is a javascript variable @return - @error } { @@ -431,7 +444,7 @@ {-options ""} {-element_is_var:boolean} } { - Generates javascript that toggle the state of an element. + Generates javascript that toggles the state of an element. The parameters are passed directly to the scriptaculous toggle script. Parameters and options are case sensitive, refer to scriptaculous documentation. http://wiki.script.aculo.us/scriptaculous/show/Effect.toggle @@ -441,9 +454,10 @@ @param element the page element that you want to apply the effect to @param effect specify one of the scriptaculous effects you want to toggle - - @return - + @param options specify the options to pass to the scritpaculous javascript + @param element_is_var specify this if the element you are passing is a javascript variable + + @return @error } { @@ -481,9 +495,7 @@ if { !$element_is_var_p } { set element [ah::isnot_js_var $element] } - set script "new Draggable \($element,\{$options\}\);" - return $script } @@ -534,9 +546,9 @@ @creation-date 2006-02-24 @param element the page element that you want to be a droppable + @param element_is_var specify this parameter if the element you are passing is a javscript variable @return - @error } { @@ -563,10 +575,11 @@ @param element the page element that you want to apply the effect to @param options specify the scriptaculous options + @param element_is_var specify this parameter if the element you are passing is a javscript variable @return - @error + } { if { !$element_is_var_p } { set element [ah::isnot_js_var $element] @@ -598,4 +611,62 @@ } set script "Rico.Corner.round\($element, \{$options\}\); " return $script +} + +ad_proc -public ah::js_sources { + {-source "default"} +} { + + Will load the prototype javascript library and scriptaculous javascript files. + + @author Hamilton Chua (ham@solutiongrove.com) + @creation-date 2006-01-16 + + @param source The caller can specify which set of javascript source files to load. This can be a comma seprated list + Valid values include + "default" : to load prototype and scriptaculous libraries + "rounder" : to load the rico corner rounder functions only, use this if you are working primarily with scriptaculous, + "rico" : to load the rico javascript library, + "overlibmws" : to load the overlibmws javascript files for dhtml callouts and popups. + "overlibmws_bubble" : to load the overlibmws javascript files for dhtml callouts and popups. + "overlibmws_scroll" : to load the overlibmws javascript files for dhtml bubble callouts and popups that scroll. + "overlibmws_drag" : to load the overlibmws javascript files for draggable dhtml callouts and popups. + + @return + @error +} { + + set ah_base_url [ah::get_url] + set js_file_list [split $source ","] + set script "" + + foreach x $js_file_list { + switch $x { + "rico" { + append script " \n" + } + "rounder" { + append script " \n" } + "overlibmws" { + append script " \n" + append script "\n" + } + "overlibmws_bubble" { + append script "\n" + append script "\n" + } + "overlibmws_scroll" { + append script "\n" + } + "overlibmws_drag" { + append script "\n" + } + default { + append script " \n" + append script " \n" + } + } + } + + return $script } \ No newline at end of file Index: openacs-4/packages/ajaxhelper/tcl/ajax-yahoo-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/ajaxhelper/tcl/ajax-yahoo-procs.tcl,v diff -u -N -r1.1 -r1.2 --- openacs-4/packages/ajaxhelper/tcl/ajax-yahoo-procs.tcl 5 Apr 2006 06:38:41 -0000 1.1 +++ openacs-4/packages/ajaxhelper/tcl/ajax-yahoo-procs.tcl 20 Aug 2006 14:39:20 -0000 1.2 @@ -7,26 +7,84 @@ @creation-date 2006-01-16 } -namespace eval ah::yahoo { } +namespace eval ah::yui { } -ad_proc -public ah::yahoo::js_sources { - {-default:boolean} - {-source ""} +ad_proc -public ah::yui::js_source_dynamic { + {-js "default"} + {-enclose:boolean} } { + Dynamically Loads the Yahoo UI javascript libraries. + WARNING : experimental, use ah::yui::js_sources instead + + + @author Hamilton Chua (ham@solutiongrove.com) + @creation-date 2006-04-20 + + @param js Comma separated list of javascript files to load + Valid values include + "default" : loads yui.js and dom.js, the most commonly used + "animation" : loads js for animation + "event" : loads js for event monitoring (e.g. listnern) + "treeview" : loads js for Yahoo's Tree View control + "calendar" : loads js for Yahoo's Calendar Control + "dragdrop" : loads js for Yahoo's Drag and Drop functions + "slider" : loads js for slider functions + +} { + + set ah_base_url [ah::get_url] + set script "" + set js_file_list [split $js ","] + foreach x $js_file_list { + switch $x { + "animation" { + append script [ah::js_include -js_file "${ah_base_url}yui/animation/animation.js"] + } + "event" { + append script [ah::js_include -js_file "${ah_base_url}yui/event/event.js"] + } + "treeview" { + append script [ah::js_include -js_file "${ah_base_url}yui/treeview/treeview.js"] + } + "calendar" { + append script [ah::js_include -js_file "${ah_base_url}yui/calendar/calendar.js"] + } + "dragdrop" { + append script [ah::js_include -js_file "${ah_base_url}yui/dragdrop/dragdrop.js"] + } + "slider" { + append script [ah::js_include -js_file "${ah_base_url}yui/slider/slider.js"] + } + default { + append script [ah::js_include -js_file "${ah_base_url}yui/yui.js"] + append script [ah::js_include -js_file "${ah_base_url}yui/dom/dom.js"] + } + } + } + + if { $enclose_p } { set script [ah::enclose_in_script -script ${script} ] } + + return $script +} + +ad_proc -public ah::yui::js_sources { + {-source "default"} +} { + Generates the < script > syntax needed on the head - for Yahoo's User Interface Library + for yui's User Interface Library The code :
- [ah::yahoo::js_sources -default] + [ah::yui::js_sources -default]will load the default YUI javascript library which includes the connections and doms js files @author Hamilton Chua (ham@solutiongrove.com) @creation-date 2006-01-16 @param default Loads the prototype and scriptaculous javascript libraries. - @param source The caller can specify which set of javascript source files to load. + @param source The caller can specify which set of javascript source files to load. You can specify more than one by separating the list with commas. Valid values include "animation" : loads animation.js "event" : loads events.js @@ -36,50 +94,48 @@ "slider" : loads slider.js @return - @error } { set ah_base_url [ah::get_url] set script "" - - if { $default_p } { - append script " \n" - append script " \n" - } else { - if { [info exists source] } { - # load other js libraries - switch $source { - "animation" { - append script " \n" - } - "event" { - append script " \n" - } - "treeview" { - append script " \n" - } - "calendar" { - append script " \n" - } - "dragdrop" { - append script " \n" - } - "slider" { - append script " \n" - } - - default { - # invalid value for source - } + set js_file_list [split $source ","] + + foreach x $js_file_list { + switch $x { + "animation" { + append script " \n" } + "event" { + append script " \n" + } + "treeview" { + append script " \n" + } + "calendar" { + append script " \n" + } + "dragdrop" { + append script " \n" + } + "slider" { + append script " \n" + } + "container" { + append script " \n" + append script " \n" + } + default { + append script " \n" + append script " \n" + } } } return $script } -ad_proc -public ah::yahoo::addlistener { +ad_proc -public ah::yui::addlistener { -element:required -event:required {-callback ""} @@ -91,4 +147,19 @@ set element [ah::isnot_js_var $element] } return "YAHOO.util.Event.addListener($element,\"$event\",${callback});\n" +} + +ad_proc -public ah::yui::tooltip { + -varname:required + -element:required + -message:required + {-enclose:boolean} + {-options ""} +} { + Generates the javascript to create a tooltip using yahoo's user interface javascript library. + For this to work, the default and container sources need to be loaded, see ah::yui::js_sources +} { + set script "var $varname = new YAHOO.widget.Tooltip(\"alertTip\", { context:\"$element\", text:\"$message\", $options });" + if { $enclose_p } { set script [ah::enclose_in_script -script ${script} ] } + return $script } \ No newline at end of file Index: openacs-4/packages/ajaxhelper/www/dynamicInclude.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/ajaxhelper/www/Attic/dynamicInclude.js,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/ajaxhelper/www/dynamicInclude.js 20 Aug 2006 14:39:21 -0000 1.1 @@ -0,0 +1,155 @@ +//Javascript dynamic Include Library +//Code derived from: +//Author: Stoyan Stefanov +//SITE: www.phpied.com +//email: ssttoo at gmaildotcom +//mad props due.. +//I made the manager objects and added the css methods so +//I can use this library for both +//me: Greg Patmore +//hit me up: //greg at ito-ydotcom + + +//js + +//holds the currently loaded .js libraries +//NOTE: idiot alert! any files included outside these methods cannot be +// referenced by this array +var js_includes = new Array(); + + +//use this manager to keep things simple +function JSManager(){ + this.included = js_includes; + this.include = js_include_once; + this.remove = js_remove_include; +} + +function js_include_dom(script_filename) { + var html_doc = document.getElementsByTagName('head').item(0); + var js = document.createElement('script'); + js.setAttribute('language', 'javascript'); + js.setAttribute('type', 'text/javascript'); + js.setAttribute('src', script_filename); + html_doc.appendChild(js); + return false; +} + +function js_include_once(script_filename) { + if (!in_array(script_filename, js_includes)) { + js_includes[js_includes.length] = script_filename; + js_include_dom(script_filename); + } +} + +//"un-includes" the included js file from the document +//use sparingly, as it's a memory whore +//NOTE: will not kill any timeouts you may have going +// but the script will be removed from the rendered source +function js_remove_include(scriptname){ + var docScripts = document.getElementsByTagName('script'); + for(var i=0;i
- * dd = new YAHOO.util.DragDrop("div1", "group1"); - *- * Since none of the event handlers have been implemented, nothing would - * actually happen if you were to run the code above. Normally you would - * override this class or one of the default implementations, but you can - * also override the methods you want on an instance of the class... - *
- * dd.onDragDrop = function(e, id) { - * alert("dd was dropped on " + id); - * } - *- * @constructor - * @param {String} id of the element that is linked to this instance - * @param {String} sGroup the group of related DragDrop objects - */ -YAHOO.util.DragDrop = function(id, sGroup) { - if (id) { - this.init(id, sGroup); - } -}; - -YAHOO.util.DragDrop.prototype = { - - /** - * The id of the element associated with this object. This is what we - * refer to as the "linked element" because the size and position of - * this element is used to determine when the drag and drop objects have - * interacted. - * - * @type String - */ - id: null, - - /** - * The id of the element that will be dragged. By default this is same - * as the linked element , but could be changed to another element. Ex: - * YAHOO.util.DDProxy - * - * @type String - * @private - */ - dragElId: null, - - /** - * the id of the element that initiates the drag operation. By default - * this is the linked element, but could be changed to be a child of this - * element. This lets us do things like only starting the drag when the - * header element within the linked html element is clicked. - * - * @type String - * @private - */ - handleElId: null, - - /** - * An array of HTML tags that will be ignored if clicked. - */ - invalidHandleTypes: null, - - /** - * The linked element's absolute X position at the time the drag was - * started - * - * @type int - * @private - */ - startPageX: 0, - - /** - * The linked element's absolute X position at the time the drag was - * started - * - * @type int - * @private - */ - startPageY: 0, - - /** - * The group defines a logical collection of DragDrop objects that are - * related. Instances only get events when interacting with other - * DragDrop object in the same group. This lets us define multiple - * groups using a single DragDrop subclass if we want. - * - */ - groups: null, - - /** - * Individual drag/drop instances can be locked. This will prevent - * onmousedown start drag. - * - * @type boolean - * @private - */ - locked: false, - - /** - * Lock this instance - */ - lock: function() { this.locked = true; }, - - /** - * Unlock this instace - */ - unlock: function() { this.locked = false; }, - - /** - * By default, all insances can be a drop target. This can be disabled by - * setting isTarget to false. - * - * @type boolean - */ - isTarget: true, - - /** - * The padding configured for this drag and drop object for calculating - * the drop zone intersection with this object. - */ - padding: null, - - /** - * @private - */ - _domRef: null, - - /** - * Internal typeof flag - * @private - */ - __ygDragDrop: true, - - /** - * Set to true when horizontal contraints are applied - * - * @type boolean - * @private - */ - constrainX: false, - - /** - * Set to true when vertical contraints are applied - * - * @type boolean - * @private - */ - constrainY: false, - - /** - * The left constraint - * - * @type int - * @private - */ - minX: 0, - - /** - * The right constraint - * - * @type int - * @private - */ - maxX: 0, - - /** - * The up constraint - * - * @type int - * @private - */ - minY: 0, - - /** - * The down constraint - * - * @type int - * @private - */ - maxY: 0, - - /** - * Maintain offsets when we resetconstraints. Used to maintain the - * slider thumb value, and this needs to be fixed. - * @type boolean - */ - maintainOffset: false, - - /** - * Array of pixel locations the element will snap to if we specified a - * horizontal graduation/interval. This array is generated automatically - * when you define a tick interval. - * @type int[] - */ - xTicks: null, - - /** - * Array of pixel locations the element will snap to if we specified a - * vertical graduation/interval. This array is generated automatically - * when you define a tick interval. - * @type int[] - */ - yTicks: null, - - /** - * By default the drag and drop instance will only respond to the primary - * button click (left button for a right-handed mouse). Set to true to - * allow drag and drop to start with any mouse click that is propogated - * by the browser - * @type boolean - */ - primaryButtonOnly: true, - - /** - * Code that executes immediately before the startDrag event - * @private - */ - b4StartDrag: function(x, y) { }, - - /** - * Abstract method called after a drag/drop object is clicked - * and the drag or mousedown time thresholds have beeen met. - * - * @param {int} X click location - * @param {int} Y click location - */ - startDrag: function(x, y) { /* override this */ }, - - /** - * Code that executes immediately before the onDrag event - * @private - */ - b4Drag: function(e) { }, - - /** - * Abstract method called during the onMouseMove event while dragging an - * object. - * - * @param {Event} e - */ - onDrag: function(e) { /* override this */ }, - - /** - * Code that executes immediately before the onDragEnter event - * @private - */ - // b4DragEnter: function(e) { }, - - /** - * Abstract method called when this element fist begins hovering over - * another DragDrop obj - * - * @param {Event} e - * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element - * id this is hovering over. In INTERSECT mode, an array of one or more - * dragdrop items being hovered over. - */ - onDragEnter: function(e, id) { /* override this */ }, - - /** - * Code that executes immediately before the onDragOver event - * @private - */ - b4DragOver: function(e) { }, - - /** - * Abstract method called when this element is hovering over another - * DragDrop obj - * - * @param {Event} e - * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element - * id this is hovering over. In INTERSECT mode, an array of dd items - * being hovered over. - */ - onDragOver: function(e, id) { /* override this */ }, - - /** - * Code that executes immediately before the onDragOut event - * @private - */ - b4DragOut: function(e) { }, - - /** - * Abstract method called when we are no longer hovering over an element - * - * @param {Event} e - * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element - * id this was hovering over. In INTERSECT mode, an array of dd items - * that the mouse is no longer over. - */ - onDragOut: function(e, id) { /* override this */ }, - - /** - * Code that executes immediately before the onDragDrop event - * @private - */ - b4DragDrop: function(e) { }, - - /** - * Abstract method called when this item is dropped on another DragDrop - * obj - * - * @param {Event} e - * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element - * id this was dropped on. In INTERSECT mode, an array of dd items this - * was dropped on. - */ - onDragDrop: function(e, id) { /* override this */ }, - - /** - * Code that executes immediately before the endDrag event - * @private - */ - b4EndDrag: function(e) { }, - - /** - * Fired when we are done dragging the object - * - * @param {Event} e - */ - endDrag: function(e) { /* override this */ }, - - /** - * Code executed immediately before the onMouseDown event - - * @param {Event} e - * @private - */ - b4MouseDown: function(e) { }, - - /** - * Event handler that fires when a drag/drop obj gets a mousedown - * @param {Event} e - */ - onMouseDown: function(e) { /* override this */ }, - - /** - * Event handler that fires when a drag/drop obj gets a mouseup - * @param {Event} e - */ - onMouseUp: function(e) { /* override this */ }, - - /** - * Returns a reference to the linked element - * - * @return {Object} the html element - */ - getEl: function() { - if (!this._domRef) { - this._domRef = this.DDM.getElement(this.id); - } - - return this._domRef; - }, - - /** - * Returns a reference to the actual element to drag. By default this is - * the same as the html element, but it can be assigned to another - * element. An example of this can be found in YAHOO.util.DDProxy - * - * @return {Object} the html element - */ - getDragEl: function() { - return this.DDM.getElement(this.dragElId); - }, - - /** - * Sets up the DragDrop object. Must be called in the constructor of any - * YAHOO.util.DragDrop subclass - * - * @param id the id of the linked element - * @param {String} sGroup the group of related items - * element is supposed to be a target only, set to false. - */ - init: function(id, sGroup) { - this.initTarget(id, sGroup); - YAHOO.util.Event.addListener(id, "mousedown", - this.handleMouseDown, this, true); - }, - - /** - * Initializes Targeting functionality only... the object does not - * get a mousedown handler. - * - * @param id the id of the linked element - * @param {String} sGroup the group of related items - * element is supposed to be a target only, set to false. - */ - initTarget: function(id, sGroup) { - - // create a local reference to the drag and drop manager - this.DDM = YAHOO.util.DDM; - - // create a logger instance - this.logger = new ygLogger("DragDrop"); - - // set the default padding - this.padding = [0, 0, 0, 0]; - - // initialize the groups array - this.groups = {}; - - // set the id - this.id = id; - - // the element is a drag handle by default - this.setDragElId(id); - - // by default, clicked anchors will not start drag operations - this.invalidHandleTypes = {a : "a"}; - - // We don't want to register this as the handle with the manager - // so we just set the id rather than calling the setter - this.handleElId = id; - - // cache the position of the element if we can - if (document && document.body) { - this.setInitPosition(); - } - - // add to an interaction group - this.addToGroup((sGroup) ? sGroup : "default"); - - }, - - /** - * Configures the padding for the target zone in px. Effectively expands - * (or reduces) the virtual object size for targeting calculations. - * Supports css-style shorthand; if only one parameter is passed, all sides - * will have that padding, and if only two are passed, the top and bottom - * will have the first param, the left and right the second. - * @param {int} iTop Top pad - * @param {int} iRight Right pad - * @param {int} iBot Bot pad - * @param {int} iLeft Left pad - */ - setPadding: function(iTop, iRight, iBot, iLeft) { - // this.padding = [iLeft, iRight, iTop, iBot]; - if (!iRight && 0 !== iRight) { - this.padding = [iTop, iTop, iTop, iTop]; - } else if (!iBot && 0 !== iBot) { - this.padding = [iTop, iRight, iTop, iRight]; - } else { - this.padding = [iTop, iRight, iBot, iLeft]; - } - }, - - /** - * Stores the initial placement of the dd element - */ - setInitPosition: function(diffX, diffY) { - var el = this.getEl(); - - if (!this.DDM.verifyEl(el)) { - this.logger.debug(this.id + " element is broken"); - return; - } - - var dx = diffX || 0; - var dy = diffY || 0; - - var p = YAHOO.util.Dom.getXY( el ); - - this.initPageX = p[0] - dx; - this.initPageY = p[1] - dy; - - this.lastPageX = p[0]; - this.lastPageY = p[1]; - - this.setStartPosition(p); - }, - - /** - * Sets the start position of the element. This is set when the obj - * is initialized, the reset when a drag is started. - * @param pos current position (from previous lookup) - * @private - */ - setStartPosition: function(pos) { - - var p = pos || YAHOO.util.Dom.getXY( this.getEl() ); - - this.startPageX = p[0]; - this.startPageY = p[1]; - }, - - /** - * Add this instance to a group of related drag/drop objects. All - * instances belong to at least one group, and can belong to as many - * groups as needed. - * - * @param sGroup {string} the name of the group - */ - addToGroup: function(sGroup) { - this.groups[sGroup] = true; - this.DDM.regDragDrop(this, sGroup); - }, - - /** - * Allows you to specify that an element other than the linked element - * will be moved with the cursor during a drag - * - * @param id the id of the element that will be used to initiate the drag - */ - setDragElId: function(id) { - this.dragElId = id; - }, - - /** - * Allows you to specify a child of the linked element that should be - * used to initiate the drag operation. An example of this would be if - * you have a content div with text and links. Clicking anywhere in the - * content area would normally start the drag operation. Use this method - * to specify that an element inside of the content div is the element - * that starts the drag operation. - * - * @param id the id of the element that will be used to initiate the drag - */ - setHandleElId: function(id) { - this.handleElId = id; - this.DDM.regHandle(this.id, id); - }, - - /** - * Allows you to set an element outside of the linked element as a drag - * handle - */ - setOuterHandleElId: function(id) { - this.logger.debug("Adding outer handle event: " + id); - YAHOO.util.Event.addListener(id, "mousedown", - this.handleMouseDown, this, true); - this.setHandleElId(id); - }, - - /** - * Remove all drag and drop hooks for this element - */ - unreg: function() { - this.logger.debug("DragDrop obj cleanup " + this.id); - YAHOO.util.Event.removeListener(this.id, "mousedown", - this.handleMouseDown); - this._domRef = null; - this.DDM._remove(this); - }, - - /** - * Returns true if this instance is locked, or the drag drop mgr is locked - * (meaning that all drag/drop is disabled on the page.) - * - * @return {boolean} true if this obj or all drag/drop is locked, else - * false - */ - isLocked: function() { - return (this.DDM.isLocked() || this.locked); - }, - - /** - * Fired when this object is clicked - * - * @param {Event} e - * @param {YAHOO.util.DragDrop} oDD the clicked dd object (this dd obj) - * @private - */ - handleMouseDown: function(e, oDD) { - - this.logger.debug("isLocked: " + this.isLocked()); - - var EU = YAHOO.util.Event; - - - var button = e.which || e.button; - this.logger.debug("button: " + button); - - if (this.primaryButtonOnly && button > 1) { - this.logger.debug("Mousedown was not produced by the primary button"); - return; - } - - if (this.isLocked()) { - this.logger.debug("Drag and drop is disabled, aborting"); - return; - } - - this.logger.debug("mousedown " + this.id); - - this.DDM.refreshCache(this.groups); - - // Only process the event if we really clicked within the linked - // element. The reason we make this check is that in the case that - // another element was moved between the clicked element and the - // cursor in the time between the mousedown and mouseup events. When - // this happens, the element gets the next mousedown event - // regardless of where on the screen it happened. - var pt = new YAHOO.util.Point(EU.getPageX(e), EU.getPageY(e)); - if ( this.DDM.isOverTarget(pt, this) ) { - - this.logger.debug("click is legit"); - - // check to see if the handle was clicked - var srcEl = EU.getTarget(e); - - if (this.isValidHandleChild(srcEl) && - (this.id == this.handleElId || - this.DDM.handleWasClicked(srcEl, this.id)) ) { - - // set the initial element position - this.setStartPosition(); - - this.logger.debug("firing onMouseDown events"); - - - this.b4MouseDown(e); - this.onMouseDown(e); - this.DDM.handleMouseDown(e, this); - - this.DDM.stopEvent(e); - } - } - }, - - /** - * Allows you to specify a tag name that should not start a drag operation - * when clicked. This is designed to facilitate embedding links within a - * drag handle that do something other than start the drag. - * - * @param {string} tagName the type of element to exclude - */ - addInvalidHandleType: function(tagName) { - var type = tagName.toUpperCase(); - this.invalidHandleTypes[type] = type; - }, - - /** - * Unsets an excluded tag name set by addInvalidHandleType - * - * @param {string} tagName the type of element to unexclude - */ - removeInvalidHandleType: function(tagName) { - var type = tagName.toUpperCase(); - this.invalidHandleTypes[type] = null; - }, - - /** - * Checks the tag exclusion list to see if this click should be ignored - * - * @param {ygNode} node - * @return {boolean} true if this is a valid tag type, false if not - */ - isValidHandleChild: function(node) { - var type = node.nodeName; - - if (type == "#text") { - // this.logger.debug("text node, getting parent node type"); - type = node.parentNode.nodeName; - } - - return (!this.invalidHandleTypes[type]); - }, - - /** - * Create the array of horizontal tick marks if an interval was specified - * in setXConstraint(). - * - * @private - */ - setXTicks: function(iStartX, iTickSize) { - this.xTicks = []; - this.xTickSize = iTickSize; - - var tickMap = {}; - - for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) { - if (!tickMap[i]) { - this.xTicks[this.xTicks.length] = i; - tickMap[i] = true; - } - } - - for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) { - if (!tickMap[i]) { - this.xTicks[this.xTicks.length] = i; - tickMap[i] = true; - } - } - - this.xTicks.sort(this.DDM.numericSort) ; - this.logger.debug("xTicks: " + this.xTicks.join()); - }, - - /** - * Create the array of vertical tick marks if an interval was specified in - * setYConstraint(). - * - * @private - */ - setYTicks: function(iStartY, iTickSize) { - this.yTicks = []; - this.yTickSize = iTickSize; - - var tickMap = {}; - - for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) { - if (!tickMap[i]) { - this.yTicks[this.yTicks.length] = i; - tickMap[i] = true; - } - } - - for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) { - if (!tickMap[i]) { - this.yTicks[this.yTicks.length] = i; - tickMap[i] = true; - } - } - - this.yTicks.sort(this.DDM.numericSort) ; - this.logger.debug("yTicks: " + this.yTicks.join()); - }, - - /** - * By default, the element can be dragged any place on the screen. Use - * this method to limit the horizontal travel of the element. Pass in - * 0,0 for the parameters if you want to lock the drag to the y axis. - * - * @param {int} iLeft the number of pixels the element can move to the left - * @param {int} iRight the number of pixels the element can move to the - * right - * @param {int} iTickSize optional parameter for specifying that the - * element - * should move iTickSize pixels at a time. - */ - setXConstraint: function(iLeft, iRight, iTickSize) { - this.leftConstraint = iLeft; - this.rightConstraint = iRight; - - this.minX = this.initPageX - iLeft; - this.maxX = this.initPageX + iRight; - if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); } - - this.constrainX = true; - this.logger.debug("initPageX:" + this.initPageX + " minX:" + this.minX + - " maxX:" + this.maxX); - }, - - /** - * By default, the element can be dragged any place on the screen. Set - * this to limit the vertical travel of the element. Pass in 0,0 for the - * parameters if you want to lock the drag to the x axis. - * - * @param {int} iUp the number of pixels the element can move up - * @param {int} iDown the number of pixels the element can move down - * @param {int} iTickSize optional parameter for specifying that the - * element should move iTickSize pixels at a time. - */ - setYConstraint: function(iUp, iDown, iTickSize) { - this.topConstraint = iUp; - this.bottomConstraint = iDown; - - this.minY = this.initPageY - iUp; - this.maxY = this.initPageY + iDown; - if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); } - - this.constrainY = true; - - this.logger.debug("initPageY:" + this.initPageY + " minY:" + this.minY + - " maxY:" + this.maxY); - }, - - /** - * resetConstraints must be called if you manually reposition a dd element. - * @param {boolean} maintainOffset - */ - resetConstraints: function() { - - // this.logger.debug("init pagexy: " + this.initPageX + ", " + - // this.initPageY); - // this.logger.debug("last pagexy: " + this.lastPageX + ", " + - // this.lastPageY); - - // figure out how much this thing has moved - var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0; - var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0; - - // this.logger.debug("diff: " + dx + ", " + dy); - - // reset the initial location - this.setInitPosition(dx, dy); - - if (this.constrainX) { - this.setXConstraint( this.leftConstraint, - this.rightConstraint, - this.xTickSize ); - } - - if (this.constrainY) { - this.setYConstraint( this.topConstraint, - this.bottomConstraint, - this.yTickSize ); - } - }, - - /** - * Normally the drag element is moved pixel by pixel, but we can specify - * that it move a number of pixels at a time. This method resolves the - * location when we have it set up like this. - * - * @param {int} val where we want to place the object - * @param {int[]} tickArray sorted array of valid points - * @return {int} the closest tick - * @private - */ - getTick: function(val, tickArray) { - - if (!tickArray) { - // If tick interval is not defined, it is effectively 1 pixel, - // so we return the value passed to us. - return val; - } else if (tickArray[0] >= val) { - // The value is lower than the first tick, so we return the first - // tick. - return tickArray[0]; - } else { - for (var i = 0; i < tickArray.length; ++i) { - var next = i + 1; - if (tickArray[next] && tickArray[next] >= val) { - var diff1 = val - tickArray[i]; - var diff2 = tickArray[next] - val; - return (diff2 > diff1) ? tickArray[i] : tickArray[next]; - } - } - - // The value is larger than the last tick, so we return the last - // tick. - return tickArray[tickArray.length - 1]; - } - }, - - /** - * toString method - * @return {string} string representation of the dd obj - */ - toString: function(val, tickArray) { - return ("YAHOO.util.DragDrop {" + this.id + "}"); - } - -}; - -/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */ - -// Only load the library once. Rewriting the manager class would orphan -// existing drag and drop instances. -if (!YAHOO.util.DragDropMgr) { - - /** - * @class Handles the element interaction for all DragDrop items in the - * window. Generally, you will not call this class directly, but it does - * have helper methods that could be useful in your DragDrop - * implementations. This class should not be instantiated; all methods - * are are static. - * - * @constructor - */ - YAHOO.util.DragDropMgr = new function() { - - /** - * utility package shorthand - * @private - */ - var UTIL = YAHOO.util; - - /** - * Two dimensional Array of registered DragDrop objects. The first - * dimension is the DragDrop item group, the second the DragDrop - * object. - * - * @private - */ - this.ids = {}; - - /** - * Array of element ids defined as drag handles. Used to determine - * if the element that generated the mousedown event is actually the - * handle and not the html element itself. - * - * @private - */ - this.handleIds = {}; - - /** - * the DragDrop object that is currently being dragged - * - * @type DragDrop - * @private - **/ - this.dragCurrent = null; - - /** - * the DragDrop object(s) that are being hovered over - * - * @type Array - * @private - */ - this.dragOvers = {}; - - /** - * @private - */ - this.logger = null; - - /** - * the X distance between the cursor and the object being dragged - * - * @type int - * @private - */ - this.deltaX = 0; - - /** - * the Y distance between the cursor and the object being dragged - * - * @type int - * @private - */ - this.deltaY = 0; - - /** - * Flag to determine if we should prevent the default behavior of the - * events we define. By default this is true, but this can be set to - * false if you need the default behavior (not recommended) - * - * @type boolean - */ - this.preventDefault = true; - - /** - * Flag to determine if we should stop the propagation of the events - * we generate. This is true by default but you may want to set it to - * false if the html element contains other features that require the - * mouse click. - * - * @type boolean - */ - this.stopPropagation = true; - - /** - * @private - */ - this.initalized = false; - - /** - * All drag and drop can be disabled. - * - * @private - */ - this.locked = false; - - /** - * Called the first time an element is registered. - * - * @private - */ - this.init = function() { - this.logger = new ygLogger("DragDropMgr"); - }; - - /** - * In point mode, drag and drop interaction is defined by the - * location of the cursor during the drag/drop - * @type int - */ - this.POINT = 0; - - /** - * In intersect mode, drag and drop interactio nis defined by the - * overlap of two or more drag and drop objects. - * @type int - */ - this.INTERSECT = 1; - - /** - * The current drag and drop mode. Default it point mode - * @type int - */ - this.mode = this.POINT; - - /** - * Runs method on all drag and drop objects - * @private - */ - this._execOnAll = function(sMethod, args) { - for (var i in this.ids) { - for (var j in this.ids[i]) { - var oDD = this.ids[i][j]; - if (! this.isTypeOfDD(oDD)) { - continue; - } - oDD[sMethod].apply(oDD, args); - } - } - }; - - /** - * Drag and drop initialization. Sets up the global event handlers - * @private - */ - this._onLoad = function() { - - this._execOnAll("setInitPosition", []); - - this.logger = new ygLogger("DragDropMgr"); - this.logger.debug("DDM onload"); - - var EU = UTIL.Event; - - EU.addListener(document, "mouseup", this.handleMouseUp, this, true); - EU.addListener(document, "mousemove", this.handleMouseMove, this, true); - EU.addListener(window, "unload", this._onUnload, this, true); - EU.addListener(window, "resize", this._onResize, this, true); - // EU.addListener(window, "mouseout", this._test); - - this.initalized = true; - - }; - - /** - * Reset constraints on all drag and drop objs - * @private - */ - this._onResize = function(e) { - this.logger.debug("window resize"); - this._execOnAll("resetConstraints", []); - }; - - /** - * Lock all drag and drop functionality - */ - this.lock = function() { this.locked = true; }; - - /** - * Unlock all drag and drop functionality - */ - this.unlock = function() { this.locked = false; }; - - /** - * Is drag and drop locked? - * - * @return {boolean} True if drag and drop is locked, false otherwise. - */ - this.isLocked = function() { return this.locked; }; - - /** - * Location cache that is set for all drag drop objects when a drag is - * initiated, cleared when the drag is finished. - * - * @private - */ - this.locationCache = {}; - - /** - * Set useCache to false if you want to force object the lookup of each - * drag and drop linked element constantly during a drag. - * @type boolean - */ - this.useCache = true; - - /** - * The number of pixels that the mouse needs to move after the - * mousedown before the drag is initiated. Default=3; - * @type int - */ - this.clickPixelThresh = 3; - - /** - * The number of milliseconds after the mousedown event to initiate the - * drag if we don't get a mouseup event. Default=1000 - * @type int - */ - this.clickTimeThresh = 1000; - - /** - * Flag that indicates that either the drag pixel threshold or the - * mousdown time threshold has been met - * @type boolean - * @private - */ - this.dragThreshMet = false; - - /** - * Timeout used for the click time threshold - * @type Object - * @private - */ - this.clickTimeout = null; - - /** - * The X position of the mousedown event stored for later use when a - * drag threshold is met. - * @type int - * @private - */ - this.startX = 0; - - /** - * The Y position of the mousedown event stored for later use when a - * drag threshold is met. - * @type int - * @private - */ - this.startY = 0; - - /** - * Each DragDrop instance must be registered with the DragDropMgr. - * This is executed in ygDragDrop.init() - * - * @param {DragDrop} oDD the DragDrop object to register - * @param {String} sGroup the name of the group this element belongs to - */ - this.regDragDrop = function(oDD, sGroup) { - if (!this.initialized) { this.init(); } - - if (!this.ids[sGroup]) { - this.ids[sGroup] = {}; - } - this.ids[sGroup][oDD.id] = oDD; - }; - - /** - * Unregisters a drag and drop item. This is executed in - * ygDragDrop.unreg, use that method instead of calling this directly. - * @private - */ - this._remove = function(oDD) { - for (var g in oDD.groups) { - if (g && this.ids[g][oDD.id]) { - delete this.ids[g][oDD.id]; - } - } - delete this.handleIds[oDD.id]; - }; - - /** - * Each DragDrop handle element must be registered. This is done - * automatically when executing ygDragDrop.setHandleElId() - * - * @param {String} sDDId the DragDrop id this element is a handle for - * @param {String} sHandleId the id of the element that is the drag - * handle - */ - this.regHandle = function(sDDId, sHandleId) { - if (!this.handleIds[sDDId]) { - this.handleIds[sDDId] = {}; - } - this.handleIds[sDDId][sHandleId] = sHandleId; - }; - - /** - * Utility function to determine if a given element has been - * registered as a drag drop item. - * - * @param {String} id the element id to check - * @return {boolean} true if this element is a DragDrop item, - * false otherwise - */ - this.isDragDrop = function(id) { - return ( this.getDDById(id) ) ? true : false; - }; - - /** - * Returns the drag and drop instances that are in all groups the - * passed in instance belongs to. - * - * @param {ygDragDrop} p_oDD the obj to get related data for - * @param {boolean} bTargetsOnly if true, only return targetable objs - * @return {ygDragDrop[]} the related instances - */ - this.getRelated = function(p_oDD, bTargetsOnly) { - var oDDs = []; - for (var i in p_oDD.groups) { - for (j in this.ids[i]) { - var dd = this.ids[i][j]; - if (! this.isTypeOfDD(dd)) { - continue; - } - if (!bTargetsOnly || dd.isTarget) { - oDDs[oDDs.length] = dd; - } - } - } - - return oDDs; - }; - - /** - * Returns true if the specified dd target is a legal target for - * the specifice drag obj - * - * @param {ygDragDrop} the drag obj - * @param {ygDragDrop) the target - * @return {boolean} true if the target is a legal target for the - * dd obj - */ - this.isLegalTarget = function (oDD, oTargetDD) { - var targets = this.getRelated(oDD); - for (var i =0;i
- * dd = new YAHOO.util.DragDrop("div1", "group1"); - *- * Since none of the event handlers have been implemented, nothing would - * actually happen if you were to run the code above. Normally you would - * override this class or one of the default implementations, but you can - * also override the methods you want on an instance of the class... - *
- * dd.onDragDrop = function(e, id) { - * alert("dd was dropped on " + id); - * } - *- * @constructor - * @param {String} id of the element that is linked to this instance - * @param {String} sGroup the group of related DragDrop objects - */ -YAHOO.util.DragDrop = function(id, sGroup) { - if (id) { - this.init(id, sGroup); - } -}; - -YAHOO.util.DragDrop.prototype = { - - /** - * The id of the element associated with this object. This is what we - * refer to as the "linked element" because the size and position of - * this element is used to determine when the drag and drop objects have - * interacted. - * - * @type String - */ - id: null, - - /** - * The id of the element that will be dragged. By default this is same - * as the linked element , but could be changed to another element. Ex: - * YAHOO.util.DDProxy - * - * @type String - * @private - */ - dragElId: null, - - /** - * the id of the element that initiates the drag operation. By default - * this is the linked element, but could be changed to be a child of this - * element. This lets us do things like only starting the drag when the - * header element within the linked html element is clicked. - * - * @type String - * @private - */ - handleElId: null, - - /** - * An array of HTML tags that will be ignored if clicked. - */ - invalidHandleTypes: null, - - /** - * The linked element's absolute X position at the time the drag was - * started - * - * @type int - * @private - */ - startPageX: 0, - - /** - * The linked element's absolute X position at the time the drag was - * started - * - * @type int - * @private - */ - startPageY: 0, - - /** - * The group defines a logical collection of DragDrop objects that are - * related. Instances only get events when interacting with other - * DragDrop object in the same group. This lets us define multiple - * groups using a single DragDrop subclass if we want. - * - */ - groups: null, - - /** - * Individual drag/drop instances can be locked. This will prevent - * onmousedown start drag. - * - * @type boolean - * @private - */ - locked: false, - - /** - * Lock this instance - */ - lock: function() { this.locked = true; }, - - /** - * Unlock this instace - */ - unlock: function() { this.locked = false; }, - - /** - * By default, all insances can be a drop target. This can be disabled by - * setting isTarget to false. - * - * @type boolean - */ - isTarget: true, - - /** - * The padding configured for this drag and drop object for calculating - * the drop zone intersection with this object. - */ - padding: null, - - /** - * @private - */ - _domRef: null, - - /** - * Internal typeof flag - * @private - */ - __ygDragDrop: true, - - /** - * Set to true when horizontal contraints are applied - * - * @type boolean - * @private - */ - constrainX: false, - - /** - * Set to true when vertical contraints are applied - * - * @type boolean - * @private - */ - constrainY: false, - - /** - * The left constraint - * - * @type int - * @private - */ - minX: 0, - - /** - * The right constraint - * - * @type int - * @private - */ - maxX: 0, - - /** - * The up constraint - * - * @type int - * @private - */ - minY: 0, - - /** - * The down constraint - * - * @type int - * @private - */ - maxY: 0, - - /** - * Maintain offsets when we resetconstraints. Used to maintain the - * slider thumb value, and this needs to be fixed. - * @type boolean - */ - maintainOffset: false, - - /** - * Array of pixel locations the element will snap to if we specified a - * horizontal graduation/interval. This array is generated automatically - * when you define a tick interval. - * @type int[] - */ - xTicks: null, - - /** - * Array of pixel locations the element will snap to if we specified a - * vertical graduation/interval. This array is generated automatically - * when you define a tick interval. - * @type int[] - */ - yTicks: null, - - /** - * By default the drag and drop instance will only respond to the primary - * button click (left button for a right-handed mouse). Set to true to - * allow drag and drop to start with any mouse click that is propogated - * by the browser - * @type boolean - */ - primaryButtonOnly: true, - - /** - * Code that executes immediately before the startDrag event - * @private - */ - b4StartDrag: function(x, y) { }, - - /** - * Abstract method called after a drag/drop object is clicked - * and the drag or mousedown time thresholds have beeen met. - * - * @param {int} X click location - * @param {int} Y click location - */ - startDrag: function(x, y) { /* override this */ }, - - /** - * Code that executes immediately before the onDrag event - * @private - */ - b4Drag: function(e) { }, - - /** - * Abstract method called during the onMouseMove event while dragging an - * object. - * - * @param {Event} e - */ - onDrag: function(e) { /* override this */ }, - - /** - * Code that executes immediately before the onDragEnter event - * @private - */ - // b4DragEnter: function(e) { }, - - /** - * Abstract method called when this element fist begins hovering over - * another DragDrop obj - * - * @param {Event} e - * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element - * id this is hovering over. In INTERSECT mode, an array of one or more - * dragdrop items being hovered over. - */ - onDragEnter: function(e, id) { /* override this */ }, - - /** - * Code that executes immediately before the onDragOver event - * @private - */ - b4DragOver: function(e) { }, - - /** - * Abstract method called when this element is hovering over another - * DragDrop obj - * - * @param {Event} e - * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element - * id this is hovering over. In INTERSECT mode, an array of dd items - * being hovered over. - */ - onDragOver: function(e, id) { /* override this */ }, - - /** - * Code that executes immediately before the onDragOut event - * @private - */ - b4DragOut: function(e) { }, - - /** - * Abstract method called when we are no longer hovering over an element - * - * @param {Event} e - * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element - * id this was hovering over. In INTERSECT mode, an array of dd items - * that the mouse is no longer over. - */ - onDragOut: function(e, id) { /* override this */ }, - - /** - * Code that executes immediately before the onDragDrop event - * @private - */ - b4DragDrop: function(e) { }, - - /** - * Abstract method called when this item is dropped on another DragDrop - * obj - * - * @param {Event} e - * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element - * id this was dropped on. In INTERSECT mode, an array of dd items this - * was dropped on. - */ - onDragDrop: function(e, id) { /* override this */ }, - - /** - * Code that executes immediately before the endDrag event - * @private - */ - b4EndDrag: function(e) { }, - - /** - * Fired when we are done dragging the object - * - * @param {Event} e - */ - endDrag: function(e) { /* override this */ }, - - /** - * Code executed immediately before the onMouseDown event - - * @param {Event} e - * @private - */ - b4MouseDown: function(e) { }, - - /** - * Event handler that fires when a drag/drop obj gets a mousedown - * @param {Event} e - */ - onMouseDown: function(e) { /* override this */ }, - - /** - * Event handler that fires when a drag/drop obj gets a mouseup - * @param {Event} e - */ - onMouseUp: function(e) { /* override this */ }, - - /** - * Returns a reference to the linked element - * - * @return {Object} the html element - */ - getEl: function() { - if (!this._domRef) { - this._domRef = this.DDM.getElement(this.id); - } - - return this._domRef; - }, - - /** - * Returns a reference to the actual element to drag. By default this is - * the same as the html element, but it can be assigned to another - * element. An example of this can be found in YAHOO.util.DDProxy - * - * @return {Object} the html element - */ - getDragEl: function() { - return this.DDM.getElement(this.dragElId); - }, - - /** - * Sets up the DragDrop object. Must be called in the constructor of any - * YAHOO.util.DragDrop subclass - * - * @param id the id of the linked element - * @param {String} sGroup the group of related items - * element is supposed to be a target only, set to false. - */ - init: function(id, sGroup) { - this.initTarget(id, sGroup); - YAHOO.util.Event.addListener(id, "mousedown", - this.handleMouseDown, this, true); - }, - - /** - * Initializes Targeting functionality only... the object does not - * get a mousedown handler. - * - * @param id the id of the linked element - * @param {String} sGroup the group of related items - * element is supposed to be a target only, set to false. - */ - initTarget: function(id, sGroup) { - - // create a local reference to the drag and drop manager - this.DDM = YAHOO.util.DDM; - - - // set the default padding - this.padding = [0, 0, 0, 0]; - - // initialize the groups array - this.groups = {}; - - // set the id - this.id = id; - - // the element is a drag handle by default - this.setDragElId(id); - - // by default, clicked anchors will not start drag operations - this.invalidHandleTypes = {a : "a"}; - - // We don't want to register this as the handle with the manager - // so we just set the id rather than calling the setter - this.handleElId = id; - - // cache the position of the element if we can - if (document && document.body) { - this.setInitPosition(); - } - - // add to an interaction group - this.addToGroup((sGroup) ? sGroup : "default"); - - }, - - /** - * Configures the padding for the target zone in px. Effectively expands - * (or reduces) the virtual object size for targeting calculations. - * Supports css-style shorthand; if only one parameter is passed, all sides - * will have that padding, and if only two are passed, the top and bottom - * will have the first param, the left and right the second. - * @param {int} iTop Top pad - * @param {int} iRight Right pad - * @param {int} iBot Bot pad - * @param {int} iLeft Left pad - */ - setPadding: function(iTop, iRight, iBot, iLeft) { - // this.padding = [iLeft, iRight, iTop, iBot]; - if (!iRight && 0 !== iRight) { - this.padding = [iTop, iTop, iTop, iTop]; - } else if (!iBot && 0 !== iBot) { - this.padding = [iTop, iRight, iTop, iRight]; - } else { - this.padding = [iTop, iRight, iBot, iLeft]; - } - }, - - /** - * Stores the initial placement of the dd element - */ - setInitPosition: function(diffX, diffY) { - var el = this.getEl(); - - if (!this.DDM.verifyEl(el)) { - return; - } - - var dx = diffX || 0; - var dy = diffY || 0; - - var p = YAHOO.util.Dom.getXY( el ); - - this.initPageX = p[0] - dx; - this.initPageY = p[1] - dy; - - this.lastPageX = p[0]; - this.lastPageY = p[1]; - - this.setStartPosition(p); - }, - - /** - * Sets the start position of the element. This is set when the obj - * is initialized, the reset when a drag is started. - * @param pos current position (from previous lookup) - * @private - */ - setStartPosition: function(pos) { - - var p = pos || YAHOO.util.Dom.getXY( this.getEl() ); - - this.startPageX = p[0]; - this.startPageY = p[1]; - }, - - /** - * Add this instance to a group of related drag/drop objects. All - * instances belong to at least one group, and can belong to as many - * groups as needed. - * - * @param sGroup {string} the name of the group - */ - addToGroup: function(sGroup) { - this.groups[sGroup] = true; - this.DDM.regDragDrop(this, sGroup); - }, - - /** - * Allows you to specify that an element other than the linked element - * will be moved with the cursor during a drag - * - * @param id the id of the element that will be used to initiate the drag - */ - setDragElId: function(id) { - this.dragElId = id; - }, - - /** - * Allows you to specify a child of the linked element that should be - * used to initiate the drag operation. An example of this would be if - * you have a content div with text and links. Clicking anywhere in the - * content area would normally start the drag operation. Use this method - * to specify that an element inside of the content div is the element - * that starts the drag operation. - * - * @param id the id of the element that will be used to initiate the drag - */ - setHandleElId: function(id) { - this.handleElId = id; - this.DDM.regHandle(this.id, id); - }, - - /** - * Allows you to set an element outside of the linked element as a drag - * handle - */ - setOuterHandleElId: function(id) { - YAHOO.util.Event.addListener(id, "mousedown", - this.handleMouseDown, this, true); - this.setHandleElId(id); - }, - - /** - * Remove all drag and drop hooks for this element - */ - unreg: function() { - YAHOO.util.Event.removeListener(this.id, "mousedown", - this.handleMouseDown); - this._domRef = null; - this.DDM._remove(this); - }, - - /** - * Returns true if this instance is locked, or the drag drop mgr is locked - * (meaning that all drag/drop is disabled on the page.) - * - * @return {boolean} true if this obj or all drag/drop is locked, else - * false - */ - isLocked: function() { - return (this.DDM.isLocked() || this.locked); - }, - - /** - * Fired when this object is clicked - * - * @param {Event} e - * @param {YAHOO.util.DragDrop} oDD the clicked dd object (this dd obj) - * @private - */ - handleMouseDown: function(e, oDD) { - - - var EU = YAHOO.util.Event; - - - var button = e.which || e.button; - - if (this.primaryButtonOnly && button > 1) { - return; - } - - if (this.isLocked()) { - return; - } - - - this.DDM.refreshCache(this.groups); - - // Only process the event if we really clicked within the linked - // element. The reason we make this check is that in the case that - // another element was moved between the clicked element and the - // cursor in the time between the mousedown and mouseup events. When - // this happens, the element gets the next mousedown event - // regardless of where on the screen it happened. - var pt = new YAHOO.util.Point(EU.getPageX(e), EU.getPageY(e)); - if ( this.DDM.isOverTarget(pt, this) ) { - - - // check to see if the handle was clicked - var srcEl = EU.getTarget(e); - - if (this.isValidHandleChild(srcEl) && - (this.id == this.handleElId || - this.DDM.handleWasClicked(srcEl, this.id)) ) { - - // set the initial element position - this.setStartPosition(); - - - this.b4MouseDown(e); - this.onMouseDown(e); - this.DDM.handleMouseDown(e, this); - - this.DDM.stopEvent(e); - } - } - }, - - /** - * Allows you to specify a tag name that should not start a drag operation - * when clicked. This is designed to facilitate embedding links within a - * drag handle that do something other than start the drag. - * - * @param {string} tagName the type of element to exclude - */ - addInvalidHandleType: function(tagName) { - var type = tagName.toUpperCase(); - this.invalidHandleTypes[type] = type; - }, - - /** - * Unsets an excluded tag name set by addInvalidHandleType - * - * @param {string} tagName the type of element to unexclude - */ - removeInvalidHandleType: function(tagName) { - var type = tagName.toUpperCase(); - this.invalidHandleTypes[type] = null; - }, - - /** - * Checks the tag exclusion list to see if this click should be ignored - * - * @param {ygNode} node - * @return {boolean} true if this is a valid tag type, false if not - */ - isValidHandleChild: function(node) { - var type = node.nodeName; - - if (type == "#text") { - type = node.parentNode.nodeName; - } - - return (!this.invalidHandleTypes[type]); - }, - - /** - * Create the array of horizontal tick marks if an interval was specified - * in setXConstraint(). - * - * @private - */ - setXTicks: function(iStartX, iTickSize) { - this.xTicks = []; - this.xTickSize = iTickSize; - - var tickMap = {}; - - for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) { - if (!tickMap[i]) { - this.xTicks[this.xTicks.length] = i; - tickMap[i] = true; - } - } - - for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) { - if (!tickMap[i]) { - this.xTicks[this.xTicks.length] = i; - tickMap[i] = true; - } - } - - this.xTicks.sort(this.DDM.numericSort) ; - }, - - /** - * Create the array of vertical tick marks if an interval was specified in - * setYConstraint(). - * - * @private - */ - setYTicks: function(iStartY, iTickSize) { - this.yTicks = []; - this.yTickSize = iTickSize; - - var tickMap = {}; - - for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) { - if (!tickMap[i]) { - this.yTicks[this.yTicks.length] = i; - tickMap[i] = true; - } - } - - for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) { - if (!tickMap[i]) { - this.yTicks[this.yTicks.length] = i; - tickMap[i] = true; - } - } - - this.yTicks.sort(this.DDM.numericSort) ; - }, - - /** - * By default, the element can be dragged any place on the screen. Use - * this method to limit the horizontal travel of the element. Pass in - * 0,0 for the parameters if you want to lock the drag to the y axis. - * - * @param {int} iLeft the number of pixels the element can move to the left - * @param {int} iRight the number of pixels the element can move to the - * right - * @param {int} iTickSize optional parameter for specifying that the - * element - * should move iTickSize pixels at a time. - */ - setXConstraint: function(iLeft, iRight, iTickSize) { - this.leftConstraint = iLeft; - this.rightConstraint = iRight; - - this.minX = this.initPageX - iLeft; - this.maxX = this.initPageX + iRight; - if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); } - - this.constrainX = true; - }, - - /** - * By default, the element can be dragged any place on the screen. Set - * this to limit the vertical travel of the element. Pass in 0,0 for the - * parameters if you want to lock the drag to the x axis. - * - * @param {int} iUp the number of pixels the element can move up - * @param {int} iDown the number of pixels the element can move down - * @param {int} iTickSize optional parameter for specifying that the - * element should move iTickSize pixels at a time. - */ - setYConstraint: function(iUp, iDown, iTickSize) { - this.topConstraint = iUp; - this.bottomConstraint = iDown; - - this.minY = this.initPageY - iUp; - this.maxY = this.initPageY + iDown; - if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); } - - this.constrainY = true; - - }, - - /** - * resetConstraints must be called if you manually reposition a dd element. - * @param {boolean} maintainOffset - */ - resetConstraints: function() { - - - // figure out how much this thing has moved - var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0; - var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0; - - - // reset the initial location - this.setInitPosition(dx, dy); - - if (this.constrainX) { - this.setXConstraint( this.leftConstraint, - this.rightConstraint, - this.xTickSize ); - } - - if (this.constrainY) { - this.setYConstraint( this.topConstraint, - this.bottomConstraint, - this.yTickSize ); - } - }, - - /** - * Normally the drag element is moved pixel by pixel, but we can specify - * that it move a number of pixels at a time. This method resolves the - * location when we have it set up like this. - * - * @param {int} val where we want to place the object - * @param {int[]} tickArray sorted array of valid points - * @return {int} the closest tick - * @private - */ - getTick: function(val, tickArray) { - - if (!tickArray) { - // If tick interval is not defined, it is effectively 1 pixel, - // so we return the value passed to us. - return val; - } else if (tickArray[0] >= val) { - // The value is lower than the first tick, so we return the first - // tick. - return tickArray[0]; - } else { - for (var i = 0; i < tickArray.length; ++i) { - var next = i + 1; - if (tickArray[next] && tickArray[next] >= val) { - var diff1 = val - tickArray[i]; - var diff2 = tickArray[next] - val; - return (diff2 > diff1) ? tickArray[i] : tickArray[next]; - } - } - - // The value is larger than the last tick, so we return the last - // tick. - return tickArray[tickArray.length - 1]; - } - }, - - /** - * toString method - * @return {string} string representation of the dd obj - */ - toString: function(val, tickArray) { - return ("YAHOO.util.DragDrop {" + this.id + "}"); - } - -}; - -/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */ - -// Only load the library once. Rewriting the manager class would orphan -// existing drag and drop instances. -if (!YAHOO.util.DragDropMgr) { - - /** - * @class Handles the element interaction for all DragDrop items in the - * window. Generally, you will not call this class directly, but it does - * have helper methods that could be useful in your DragDrop - * implementations. This class should not be instantiated; all methods - * are are static. - * - * @constructor - */ - YAHOO.util.DragDropMgr = new function() { - - /** - * utility package shorthand - * @private - */ - var UTIL = YAHOO.util; - - /** - * Two dimensional Array of registered DragDrop objects. The first - * dimension is the DragDrop item group, the second the DragDrop - * object. - * - * @private - */ - this.ids = {}; - - /** - * Array of element ids defined as drag handles. Used to determine - * if the element that generated the mousedown event is actually the - * handle and not the html element itself. - * - * @private - */ - this.handleIds = {}; - - /** - * the DragDrop object that is currently being dragged - * - * @type DragDrop - * @private - **/ - this.dragCurrent = null; - - /** - * the DragDrop object(s) that are being hovered over - * - * @type Array - * @private - */ - this.dragOvers = {}; - - /** - * @private - */ - - /** - * the X distance between the cursor and the object being dragged - * - * @type int - * @private - */ - this.deltaX = 0; - - /** - * the Y distance between the cursor and the object being dragged - * - * @type int - * @private - */ - this.deltaY = 0; - - /** - * Flag to determine if we should prevent the default behavior of the - * events we define. By default this is true, but this can be set to - * false if you need the default behavior (not recommended) - * - * @type boolean - */ - this.preventDefault = true; - - /** - * Flag to determine if we should stop the propagation of the events - * we generate. This is true by default but you may want to set it to - * false if the html element contains other features that require the - * mouse click. - * - * @type boolean - */ - this.stopPropagation = true; - - /** - * @private - */ - this.initalized = false; - - /** - * All drag and drop can be disabled. - * - * @private - */ - this.locked = false; - - /** - * Called the first time an element is registered. - * - * @private - */ - this.init = function() { - }; - - /** - * In point mode, drag and drop interaction is defined by the - * location of the cursor during the drag/drop - * @type int - */ - this.POINT = 0; - - /** - * In intersect mode, drag and drop interactio nis defined by the - * overlap of two or more drag and drop objects. - * @type int - */ - this.INTERSECT = 1; - - /** - * The current drag and drop mode. Default it point mode - * @type int - */ - this.mode = this.POINT; - - /** - * Runs method on all drag and drop objects - * @private - */ - this._execOnAll = function(sMethod, args) { - for (var i in this.ids) { - for (var j in this.ids[i]) { - var oDD = this.ids[i][j]; - if (! this.isTypeOfDD(oDD)) { - continue; - } - oDD[sMethod].apply(oDD, args); - } - } - }; - - /** - * Drag and drop initialization. Sets up the global event handlers - * @private - */ - this._onLoad = function() { - - this._execOnAll("setInitPosition", []); - - - var EU = UTIL.Event; - - EU.addListener(document, "mouseup", this.handleMouseUp, this, true); - EU.addListener(document, "mousemove", this.handleMouseMove, this, true); - EU.addListener(window, "unload", this._onUnload, this, true); - EU.addListener(window, "resize", this._onResize, this, true); - // EU.addListener(window, "mouseout", this._test); - - this.initalized = true; - - }; - - /** - * Reset constraints on all drag and drop objs - * @private - */ - this._onResize = function(e) { - this._execOnAll("resetConstraints", []); - }; - - /** - * Lock all drag and drop functionality - */ - this.lock = function() { this.locked = true; }; - - /** - * Unlock all drag and drop functionality - */ - this.unlock = function() { this.locked = false; }; - - /** - * Is drag and drop locked? - * - * @return {boolean} True if drag and drop is locked, false otherwise. - */ - this.isLocked = function() { return this.locked; }; - - /** - * Location cache that is set for all drag drop objects when a drag is - * initiated, cleared when the drag is finished. - * - * @private - */ - this.locationCache = {}; - - /** - * Set useCache to false if you want to force object the lookup of each - * drag and drop linked element constantly during a drag. - * @type boolean - */ - this.useCache = true; - - /** - * The number of pixels that the mouse needs to move after the - * mousedown before the drag is initiated. Default=3; - * @type int - */ - this.clickPixelThresh = 3; - - /** - * The number of milliseconds after the mousedown event to initiate the - * drag if we don't get a mouseup event. Default=1000 - * @type int - */ - this.clickTimeThresh = 1000; - - /** - * Flag that indicates that either the drag pixel threshold or the - * mousdown time threshold has been met - * @type boolean - * @private - */ - this.dragThreshMet = false; - - /** - * Timeout used for the click time threshold - * @type Object - * @private - */ - this.clickTimeout = null; - - /** - * The X position of the mousedown event stored for later use when a - * drag threshold is met. - * @type int - * @private - */ - this.startX = 0; - - /** - * The Y position of the mousedown event stored for later use when a - * drag threshold is met. - * @type int - * @private - */ - this.startY = 0; - - /** - * Each DragDrop instance must be registered with the DragDropMgr. - * This is executed in ygDragDrop.init() - * - * @param {DragDrop} oDD the DragDrop object to register - * @param {String} sGroup the name of the group this element belongs to - */ - this.regDragDrop = function(oDD, sGroup) { - if (!this.initialized) { this.init(); } - - if (!this.ids[sGroup]) { - this.ids[sGroup] = {}; - } - this.ids[sGroup][oDD.id] = oDD; - }; - - /** - * Unregisters a drag and drop item. This is executed in - * ygDragDrop.unreg, use that method instead of calling this directly. - * @private - */ - this._remove = function(oDD) { - for (var g in oDD.groups) { - if (g && this.ids[g][oDD.id]) { - delete this.ids[g][oDD.id]; - } - } - delete this.handleIds[oDD.id]; - }; - - /** - * Each DragDrop handle element must be registered. This is done - * automatically when executing ygDragDrop.setHandleElId() - * - * @param {String} sDDId the DragDrop id this element is a handle for - * @param {String} sHandleId the id of the element that is the drag - * handle - */ - this.regHandle = function(sDDId, sHandleId) { - if (!this.handleIds[sDDId]) { - this.handleIds[sDDId] = {}; - } - this.handleIds[sDDId][sHandleId] = sHandleId; - }; - - /** - * Utility function to determine if a given element has been - * registered as a drag drop item. - * - * @param {String} id the element id to check - * @return {boolean} true if this element is a DragDrop item, - * false otherwise - */ - this.isDragDrop = function(id) { - return ( this.getDDById(id) ) ? true : false; - }; - - /** - * Returns the drag and drop instances that are in all groups the - * passed in instance belongs to. - * - * @param {ygDragDrop} p_oDD the obj to get related data for - * @param {boolean} bTargetsOnly if true, only return targetable objs - * @return {ygDragDrop[]} the related instances - */ - this.getRelated = function(p_oDD, bTargetsOnly) { - var oDDs = []; - for (var i in p_oDD.groups) { - for (j in this.ids[i]) { - var dd = this.ids[i][j]; - if (! this.isTypeOfDD(dd)) { - continue; - } - if (!bTargetsOnly || dd.isTarget) { - oDDs[oDDs.length] = dd; - } - } - } - - return oDDs; - }; - - /** - * Returns true if the specified dd target is a legal target for - * the specifice drag obj - * - * @param {ygDragDrop} the drag obj - * @param {ygDragDrop) the target - * @return {boolean} true if the target is a legal target for the - * dd obj - */ - this.isLegalTarget = function (oDD, oTargetDD) { - var targets = this.getRelated(oDD); - for (var i =0;i
Usage: var myAnim = new YAHOO.util.Anim(el, { width: { from: 10, to: 100 } }, 1, YAHOO.util.Easing.easeOut);
+ * @requires YAHOO.util.AnimMgr + * @requires YAHOO.util.Easing + * @requires YAHOO.util.Dom + * @requires YAHOO.util.Event + * @requires YAHOO.util.CustomEvent + * @constructor + * @param {String or HTMLElement} el Reference to the element that will be animated + * @param {Object} attributes The attribute(s) to be animated. + * Each attribute is an object with at minimum a "to" or "by" member defined. + * Additional optional members are "from" (defaults to current value), "units" (defaults to "px"). + * All attribute names use camelCase. + * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based + * @param {Function} method (optional, defaults to YAHOO.util.Easing.easeNone) Computes the values that are applied to the attributes per frame (generally a YAHOO.util.Easing method) + */ + +YAHOO.util.Anim = function(el, attributes, duration, method) { + if (el) { + this.init(el, attributes, duration, method); + } +}; + +YAHOO.util.Anim.prototype = { + /** + * toString method + * @return {String} string represenation of anim obj + */ + toString: function() { + var el = this.getEl(); + var id = el.id || el.tagName; + return ("Anim " + id); + }, + + patterns: { // cached for performance + noNegatives: /width|height|opacity|padding/i, // keep at zero or above + offsetAttribute: /^((width|height)|(top|left))$/, // use offsetValue as default + defaultUnit: /width|height|top$|bottom$|left$|right$/i, // use 'px' by default + offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i // IE may return these, so convert these to offset + }, + + /** + * Returns the value computed by the animation's "method". + * @param {String} attr The name of the attribute. + * @param {Number} start The value this attribute should start from for this animation. + * @param {Number} end The value this attribute should end at for this animation. + * @return {Number} The Value to be applied to the attribute. + */ + doMethod: function(attr, start, end) { + return this.method(this.currentFrame, start, end - start, this.totalFrames); + }, + + /** + * Applies a value to an attribute + * @param {String} attr The name of the attribute. + * @param {Number} val The value to be applied to the attribute. + * @param {String} unit The unit ('px', '%', etc.) of the value. + */ + setAttribute: function(attr, val, unit) { + if ( this.patterns.noNegatives.test(attr) ) { + val = (val > 0) ? val : 0; + } + + YAHOO.util.Dom.setStyle(this.getEl(), attr, val + unit); + }, + + /** + * Returns current value of the attribute. + * @param {String} attr The name of the attribute. + * @return {Number} val The current value of the attribute. + */ + getAttribute: function(attr) { + var el = this.getEl(); + var val = YAHOO.util.Dom.getStyle(el, attr); + + if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) { + return parseFloat(val); + } + + var a = this.patterns.offsetAttribute.exec(attr) || []; + var pos = !!( a[3] ); // top or left + var box = !!( a[2] ); // width or height + + // use offsets for width/height and abs pos top/left + if ( box || (YAHOO.util.Dom.getStyle(el, 'position') == 'absolute' && pos) ) { + val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)]; + } else { // default to zero for other 'auto' + val = 0; + } + + return val; + }, + + /** + * Returns the unit to use when none is supplied. + * Applies the "defaultUnit" test to decide whether to use pixels or not + * @param {attr} attr The name of the attribute. + * @return {String} The default unit to be used. + */ + getDefaultUnit: function(attr) { + if ( this.patterns.defaultUnit.test(attr) ) { + return 'px'; + } + + return ''; + }, + + /** + * Sets the actual values to be used during the animation. + * Should only be needed for subclass use. + * @param {Object} attr The attribute object + * @private + */ + setRuntimeAttribute: function(attr) { + var start; + var end; + var attributes = this.attributes; + + this.runtimeAttributes[attr] = {}; + + var isset = function(prop) { + return (typeof prop !== 'undefined'); + }; + + if ( !isset(attributes[attr]['to']) && !isset(attributes[attr]['by']) ) { + return false; // note return; nothing to animate to + } + + start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr); + + // To beats by, per SMIL 2.1 spec + if ( isset(attributes[attr]['to']) ) { + end = attributes[attr]['to']; + } else if ( isset(attributes[attr]['by']) ) { + if (start.constructor == Array) { + end = []; + for (var i = 0, len = start.length; i < len; ++i) { + end[i] = start[i] + attributes[attr]['by'][i]; + } + } else { + end = start + attributes[attr]['by']; + } + } + + this.runtimeAttributes[attr].start = start; + this.runtimeAttributes[attr].end = end; + + // set units if needed + this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr); + }, + + /** + * @param {String or HTMLElement} el Reference to the element that will be animated + * @param {Object} attributes The attribute(s) to be animated. + * Each attribute is an object with at minimum a "to" or "by" member defined. + * Additional optional members are "from" (defaults to current value), "units" (defaults to "px"). + * All attribute names use camelCase. + * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based + * @param {Function} method (optional, defaults to YAHOO.util.Easing.easeNone) Computes the values that are applied to the attributes per frame (generally a YAHOO.util.Easing method) + */ + init: function(el, attributes, duration, method) { + /** + * Whether or not the animation is running. + * @private + * @type Boolean + */ + var isAnimated = false; + + /** + * A Date object that is created when the animation begins. + * @private + * @type Date + */ + var startTime = null; + + /** + * The number of frames this animation was able to execute. + * @private + * @type Int + */ + var actualFrames = 0; + + /** + * The element to be animated. + * @private + * @type HTMLElement + */ + el = YAHOO.util.Dom.get(el); + + /** + * The collection of attributes to be animated. + * Each attribute must have at least a "to" or "by" defined in order to animate. + * If "to" is supplied, the animation will end with the attribute at that value. + * If "by" is supplied, the animation will end at that value plus its starting value. + * If both are supplied, "to" is used, and "by" is ignored. + * @member YAHOO#util#Anim + * Optional additional member include "from" (the value the attribute should start animating from, defaults to current value), and "unit" (the units to apply to the values). + * @type Object + */ + this.attributes = attributes || {}; + + /** + * The length of the animation. Defaults to "1" (second). + * @type Number + */ + this.duration = duration || 1; + + /** + * The method that will provide values to the attribute(s) during the animation. + * Defaults to "YAHOO.util.Easing.easeNone". + * @type Function + */ + this.method = method || YAHOO.util.Easing.easeNone; + + /** + * Whether or not the duration should be treated as seconds. + * Defaults to true. + * @type Boolean + */ + this.useSeconds = true; // default to seconds + + /** + * The location of the current animation on the timeline. + * In time-based animations, this is used by AnimMgr to ensure the animation finishes on time. + * @type Int + */ + this.currentFrame = 0; + + /** + * The total number of frames to be executed. + * In time-based animations, this is used by AnimMgr to ensure the animation finishes on time. + * @type Int + */ + this.totalFrames = YAHOO.util.AnimMgr.fps; + + + /** + * Returns a reference to the animated element. + * @return {HTMLElement} + */ + this.getEl = function() { return el; }; + + /** + * Checks whether the element is currently animated. + * @return {Boolean} current value of isAnimated. + */ + this.isAnimated = function() { + return isAnimated; + }; + + /** + * Returns the animation start time. + * @return {Date} current value of startTime. + */ + this.getStartTime = function() { + return startTime; + }; + + this.runtimeAttributes = {}; + + var logger = {}; + logger.log = function() {YAHOO.log.apply(window, arguments)}; + + logger.log('creating new instance of ' + this); + + /** + * Starts the animation by registering it with the animation manager. + */ + this.animate = function() { + if ( this.isAnimated() ) { return false; } + + this.currentFrame = 0; + + this.totalFrames = ( this.useSeconds ) ? Math.ceil(YAHOO.util.AnimMgr.fps * this.duration) : this.duration; + + YAHOO.util.AnimMgr.registerElement(this); + }; + + /** + * Stops the animation. Normally called by AnimMgr when animation completes. + */ + this.stop = function() { + YAHOO.util.AnimMgr.stop(this); + }; + + var onStart = function() { + this.onStart.fire(); + for (var attr in this.attributes) { + this.setRuntimeAttribute(attr); + } + + isAnimated = true; + actualFrames = 0; + startTime = new Date(); + }; + + /** + * Feeds the starting and ending values for each animated attribute to doMethod once per frame, then applies the resulting value to the attribute(s). + * @private + */ + + var onTween = function() { + var data = { + duration: new Date() - this.getStartTime(), + currentFrame: this.currentFrame + }; + + data.toString = function() { + return ( + 'duration: ' + data.duration + + ', currentFrame: ' + data.currentFrame + ); + }; + + this.onTween.fire(data); + + var runtimeAttributes = this.runtimeAttributes; + + for (var attr in runtimeAttributes) { + this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit); + } + + actualFrames += 1; + }; + + var onComplete = function() { + var actual_duration = (new Date() - startTime) / 1000 ; + + var data = { + duration: actual_duration, + frames: actualFrames, + fps: actualFrames / actual_duration + }; + + data.toString = function() { + return ( + 'duration: ' + data.duration + + ', frames: ' + data.frames + + ', fps: ' + data.fps + ); + }; + + isAnimated = false; + actualFrames = 0; + this.onComplete.fire(data); + }; + + /** + * Custom event that fires after onStart, useful in subclassing + * @private + */ + this._onStart = new YAHOO.util.CustomEvent('_start', this, true); + + /** + * Custom event that fires when animation begins + * Listen via subscribe method (e.g. myAnim.onStart.subscribe(someFunction) + */ + this.onStart = new YAHOO.util.CustomEvent('start', this); + + /** + * Custom event that fires between each frame + * Listen via subscribe method (e.g. myAnim.onTween.subscribe(someFunction) + */ + this.onTween = new YAHOO.util.CustomEvent('tween', this); + + /** + * Custom event that fires after onTween + * @private + */ + this._onTween = new YAHOO.util.CustomEvent('_tween', this, true); + + /** + * Custom event that fires when animation ends + * Listen via subscribe method (e.g. myAnim.onComplete.subscribe(someFunction) + */ + this.onComplete = new YAHOO.util.CustomEvent('complete', this); + /** + * Custom event that fires after onComplete + * @private + */ + this._onComplete = new YAHOO.util.CustomEvent('_complete', this, true); + + this._onStart.subscribe(onStart); + this._onTween.subscribe(onTween); + this._onComplete.subscribe(onComplete); + } +}; + +/** + * @class Handles animation queueing and threading. + * Used by Anim and subclasses. + */ +YAHOO.util.AnimMgr = new function() { + /** + * Reference to the animation Interval + * @private + * @type Int + */ + var thread = null; + + /** + * The current queue of registered animation objects. + * @private + * @type Array + */ + var queue = []; + + /** + * The number of active animations. + * @private + * @type Int + */ + var tweenCount = 0; + + /** + * Base frame rate (frames per second). + * Arbitrarily high for better x-browser calibration (slower browsers drop more frames). + * @type Int + * + */ + this.fps = 200; + + /** + * Interval delay in milliseconds, defaults to fastest possible. + * @type Int + * + */ + this.delay = 1; + + /** + * Adds an animation instance to the animation queue. + * All animation instances must be registered in order to animate. + * @param {object} tween The Anim instance to be be registered + */ + this.registerElement = function(tween) { + queue[queue.length] = tween; + tweenCount += 1; + tween._onStart.fire(); + this.start(); + }; + + this.unRegister = function(tween, index) { + tween._onComplete.fire(); + index = index || getIndex(tween); + if (index != -1) { queue.splice(index, 1); } + + tweenCount -= 1; + if (tweenCount <= 0) { this.stop(); } + }; + + /** + * Starts the animation thread. + * Only one thread can run at a time. + */ + this.start = function() { + if (thread === null) { thread = setInterval(this.run, this.delay); } + }; + + /** + * Stops the animation thread or a specific animation instance. + * @param {object} tween A specific Anim instance to stop (optional) + * If no instance given, Manager stops thread and all animations. + */ + this.stop = function(tween) { + if (!tween) { + clearInterval(thread); + for (var i = 0, len = queue.length; i < len; ++i) { + if (queue[i].isAnimated()) { + this.unRegister(tween, i); + } + } + queue = []; + thread = null; + tweenCount = 0; + } + else { + this.unRegister(tween); + } + }; + + /** + * Called per Interval to handle each animation frame. + */ + this.run = function() { + for (var i = 0, len = queue.length; i < len; ++i) { + var tween = queue[i]; + if ( !tween || !tween.isAnimated() ) { continue; } + + if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null) + { + tween.currentFrame += 1; + + if (tween.useSeconds) { + correctFrame(tween); + } + tween._onTween.fire(); + } + else { YAHOO.util.AnimMgr.stop(tween, i); } + } + }; + + var getIndex = function(anim) { + for (var i = 0, len = queue.length; i < len; ++i) { + if (queue[i] == anim) { + return i; // note return; + } + } + return -1; + }; + + /** + * On the fly frame correction to keep animation on time. + * @private + * @param {Object} tween The Anim instance being corrected. + */ + var correctFrame = function(tween) { + var frames = tween.totalFrames; + var frame = tween.currentFrame; + var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames); + var elapsed = (new Date() - tween.getStartTime()); + var tweak = 0; + + if (elapsed < tween.duration * 1000) { // check if falling behind + tweak = Math.round((elapsed / expected - 1) * tween.currentFrame); + } else { // went over duration, so jump to end + tweak = frames - (frame + 1); + } + if (tweak > 0 && isFinite(tweak)) { // adjust if needed + if (tween.currentFrame + tweak >= frames) {// dont go past last frame + tweak = frames - (frame + 1); + } + + tween.currentFrame += tweak; + } + }; +}; +/** + * + * @class Used to calculate Bezier splines for any number of control points. + * + */ +YAHOO.util.Bezier = new function() +{ + /** + * Get the current position of the animated element based on t. + * Each point is an array of "x" and "y" values (0 = x, 1 = y) + * At least 2 points are required (start and end). + * First point is start. Last point is end. + * Additional control points are optional. + * @param {Array} points An array containing Bezier points + * @param {Number} t A number between 0 and 1 which is the basis for determining current position + * @return {Array} An array containing int x and y member data + */ + this.getPosition = function(points, t) + { + var n = points.length; + var tmp = []; + + for (var i = 0; i < n; ++i){ + tmp[i] = [points[i][0], points[i][1]]; // save input + } + + for (var j = 1; j < n; ++j) { + for (i = 0; i < n - j; ++i) { + tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0]; + tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1]; + } + } + + return [ tmp[0][0], tmp[0][1] ]; + + }; +}; +/** + * @class ColorAnim subclass for color fading + *Usage: var myAnim = new Y.ColorAnim(el, { backgroundColor: { from: '#FF0000', to: '#FFFFFF' } }, 1, Y.Easing.easeOut);
Color values can be specified with either 112233, #112233, [255,255,255], or rgb(255,255,255) + * @requires YAHOO.util.Anim + * @requires YAHOO.util.AnimMgr + * @requires YAHOO.util.Easing + * @requires YAHOO.util.Bezier + * @requires YAHOO.util.Dom + * @requires YAHOO.util.Event + * @constructor + * @param {HTMLElement | String} el Reference to the element that will be animated + * @param {Object} attributes The attribute(s) to be animated. + * Each attribute is an object with at minimum a "to" or "by" member defined. + * Additional optional members are "from" (defaults to current value), "units" (defaults to "px"). + * All attribute names use camelCase. + * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based + * @param {Function} method (optional, defaults to YAHOO.util.Easing.easeNone) Computes the values that are applied to the attributes per frame (generally a YAHOO.util.Easing method) + */ +(function() { + YAHOO.util.ColorAnim = function(el, attributes, duration, method) { + YAHOO.util.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method); + }; + + YAHOO.extend(YAHOO.util.ColorAnim, YAHOO.util.Anim); + + // shorthand + var Y = YAHOO.util; + var superclass = Y.ColorAnim.superclass; + var proto = Y.ColorAnim.prototype; + + /** + * toString method + * @return {String} string represenation of anim obj + */ + proto.toString = function() { + var el = this.getEl(); + var id = el.id || el.tagName; + return ("ColorAnim " + id); + }; + + /** + * Only certain attributes should be treated as colors. + * @type Object + */ + proto.patterns.color = /color$/i; + proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i; + proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i; + proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i; + + /** + * Attempts to parse the given string and return a 3-tuple. + * @param {String} s The string to parse. + * @return {Array} The 3-tuple of rgb values. + */ + proto.parseColor = function(s) { + if (s.length == 3) { return s; } + + var c = this.patterns.hex.exec(s); + if (c && c.length == 4) { + return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ]; + } + + c = this.patterns.rgb.exec(s); + if (c && c.length == 4) { + return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ]; + } + + c = this.patterns.hex3.exec(s); + if (c && c.length == 4) { + return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ]; + } + + return null; + }; + + /** + * Returns current value of the attribute. + * @param {String} attr The name of the attribute. + * @return {Number} val The current value of the attribute. + */ + proto.getAttribute = function(attr) { + var el = this.getEl(); + if ( this.patterns.color.test(attr) ) { + var val = YAHOO.util.Dom.getStyle(el, attr); + + if (val == 'transparent') { // bgcolor default + var parent = el.parentNode; // try and get from an ancestor + val = Y.Dom.getStyle(parent, attr); + + while (parent && val == 'transparent') { + parent = parent.parentNode; + val = Y.Dom.getStyle(parent, attr); + if (parent.tagName.toUpperCase() == 'HTML') { + val = 'ffffff'; + } + } + } + } else { + val = superclass.getAttribute.call(this, attr); + } + + return val; + }; + + /** + * Returns the value computed by the animation's "method". + * @param {String} attr The name of the attribute. + * @param {Number} start The value this attribute should start from for this animation. + * @param {Number} end The value this attribute should end at for this animation. + * @return {Number} The Value to be applied to the attribute. + */ + proto.doMethod = function(attr, start, end) { + var val; + + if ( this.patterns.color.test(attr) ) { + val = []; + for (var i = 0, len = start.length; i < len; ++i) { + val[i] = superclass.doMethod.call(this, attr, start[i], end[i]); + } + + val = 'rgb('+Math.floor(val[0])+','+Math.floor(val[1])+','+Math.floor(val[2])+')'; + } + else { + val = superclass.doMethod.call(this, attr, start, end); + } + + return val; + }; + + /** + * Sets the actual values to be used during the animation. + * Should only be needed for subclass use. + * @param {Object} attr The attribute object + * @private + */ + proto.setRuntimeAttribute = function(attr) { + superclass.setRuntimeAttribute.call(this, attr); + + if ( this.patterns.color.test(attr) ) { + var attributes = this.attributes; + var start = this.parseColor(this.runtimeAttributes[attr].start); + var end = this.parseColor(this.runtimeAttributes[attr].end); + // fix colors if going "by" + if ( typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined' ) { + end = this.parseColor(attributes[attr].by); + + for (var i = 0, len = start.length; i < len; ++i) { + end[i] = start[i] + end[i]; + } + } + + this.runtimeAttributes[attr].start = start; + this.runtimeAttributes[attr].end = end; + } + }; +})();/* +TERMS OF USE - EASING EQUATIONS +Open source under the BSD License. +Copyright � 2001 Robert Penner All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +YAHOO.util.Easing = { + + /** + * Uniform speed between points. + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @return {Number} The computed value for the current animation frame. + */ + easeNone: function (t, b, c, d) { + return c*t/d + b; + }, + + /** + * Begins slowly and accelerates towards end. (quadratic) + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @return {Number} The computed value for the current animation frame. + */ + easeIn: function (t, b, c, d) { + return c*(t/=d)*t + b; + }, + + /** + * Begins quickly and decelerates towards end. (quadratic) + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @return {Number} The computed value for the current animation frame. + */ + easeOut: function (t, b, c, d) { + return -c *(t/=d)*(t-2) + b; + }, + + /** + * Begins slowly and decelerates towards end. (quadratic) + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @return {Number} The computed value for the current animation frame. + */ + easeBoth: function (t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t + b; + return -c/2 * ((--t)*(t-2) - 1) + b; + }, + + /** + * Begins slowly and accelerates towards end. (quartic) + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @return {Number} The computed value for the current animation frame. + */ + easeInStrong: function (t, b, c, d) { + return c*(t/=d)*t*t*t + b; + }, + + /** + * Begins quickly and decelerates towards end. (quartic) + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @return {Number} The computed value for the current animation frame. + */ + easeOutStrong: function (t, b, c, d) { + return -c * ((t=t/d-1)*t*t*t - 1) + b; + }, + + /** + * Begins slowly and decelerates towards end. (quartic) + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @return {Number} The computed value for the current animation frame. + */ + easeBothStrong: function (t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t*t*t + b; + return -c/2 * ((t-=2)*t*t*t - 2) + b; + }, + + /** + * snap in elastic effect + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @param {Number} p Period (optional) + * @return {Number} The computed value for the current animation frame. + */ + + elasticIn: function (t, b, c, d, a, p) { + if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; + if (!a || a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; + }, + + /** + * snap out elastic effect + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @param {Number} p Period (optional) + * @return {Number} The computed value for the current animation frame. + */ + elasticOut: function (t, b, c, d, a, p) { + if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; + if (!a || a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b; + }, + + /** + * snap both elastic effect + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @param {Number} p Period (optional) + * @return {Number} The computed value for the current animation frame. + */ + elasticBoth: function (t, b, c, d, a, p) { + if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); + if (!a || a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; + return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b; + }, + + + /** + * back easing in - backtracking slightly, then reversing direction and moving to target + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @param {Number) s Overshoot (optional) + * @return {Number} The computed value for the current animation frame. + */ + backIn: function (t, b, c, d, s) { + if (typeof s == 'undefined') s = 1.70158; + return c*(t/=d)*t*((s+1)*t - s) + b; + }, + + /** + * back easing out - moving towards target, overshooting it slightly, + * then reversing and coming back to target + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @param {Number) s Overshoot (optional) + * @return {Number} The computed value for the current animation frame. + */ + backOut: function (t, b, c, d, s) { + if (typeof s == 'undefined') s = 1.70158; + return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; + }, + + /** + * back easing in/out - backtracking slightly, then reversing direction and moving to target, + * then overshooting target, reversing, and finally coming back to target + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @param {Number) s Overshoot (optional) + * @return {Number} The computed value for the current animation frame. + */ + backBoth: function (t, b, c, d, s) { + if (typeof s == 'undefined') s = 1.70158; + if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; + return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; + }, + + /** + * bounce in + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @return {Number} The computed value for the current animation frame. + */ + bounceIn: function (t, b, c, d) { + return c - YAHOO.util.Easing.bounceOut(d-t, 0, c, d) + b; + }, + + /** + * bounce out + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @return {Number} The computed value for the current animation frame. + */ + bounceOut: function (t, b, c, d) { + if ((t/=d) < (1/2.75)) { + return c*(7.5625*t*t) + b; + } else if (t < (2/2.75)) { + return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; + } else if (t < (2.5/2.75)) { + return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; + } else { + return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; + } + }, + + /** + * bounce both + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @return {Number} The computed value for the current animation frame. + */ + bounceBoth: function (t, b, c, d) { + if (t < d/2) return YAHOO.util.Easing.bounceIn(t*2, 0, c, d) * .5 + b; + return YAHOO.util.Easing.bounceOut(t*2-d, 0, c, d) * .5 + c*.5 + b; + } +}; + +/** + * @class Anim subclass for moving elements along a path defined by the "points" member of "attributes". All "points" are arrays with x, y coordinates. + *
Usage: var myAnim = new YAHOO.util.Motion(el, { points: { to: [800, 800] } }, 1, YAHOO.util.Easing.easeOut);
Usage: var myAnim = new YAHOO.util.Scroll(el, { scroll: { to: [0, 800] } }, 1, YAHOO.util.Easing.easeOut);
Usage: var myAnim = new YAHOO.util.Anim(el, { width: { from: 10, to: 100 } }, 1, YAHOO.util.Easing.easeOut);
+ * @requires YAHOO.util.AnimMgr + * @requires YAHOO.util.Easing + * @requires YAHOO.util.Dom + * @requires YAHOO.util.Event + * @requires YAHOO.util.CustomEvent + * @constructor + * @param {String or HTMLElement} el Reference to the element that will be animated + * @param {Object} attributes The attribute(s) to be animated. + * Each attribute is an object with at minimum a "to" or "by" member defined. + * Additional optional members are "from" (defaults to current value), "units" (defaults to "px"). + * All attribute names use camelCase. + * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based + * @param {Function} method (optional, defaults to YAHOO.util.Easing.easeNone) Computes the values that are applied to the attributes per frame (generally a YAHOO.util.Easing method) + */ + +YAHOO.util.Anim = function(el, attributes, duration, method) { + if (el) { + this.init(el, attributes, duration, method); + } +}; + +YAHOO.util.Anim.prototype = { + /** + * toString method + * @return {String} string represenation of anim obj + */ + toString: function() { + var el = this.getEl(); + var id = el.id || el.tagName; + return ("Anim " + id); + }, + + patterns: { // cached for performance + noNegatives: /width|height|opacity|padding/i, // keep at zero or above + offsetAttribute: /^((width|height)|(top|left))$/, // use offsetValue as default + defaultUnit: /width|height|top$|bottom$|left$|right$/i, // use 'px' by default + offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i // IE may return these, so convert these to offset + }, + + /** + * Returns the value computed by the animation's "method". + * @param {String} attr The name of the attribute. + * @param {Number} start The value this attribute should start from for this animation. + * @param {Number} end The value this attribute should end at for this animation. + * @return {Number} The Value to be applied to the attribute. + */ + doMethod: function(attr, start, end) { + return this.method(this.currentFrame, start, end - start, this.totalFrames); + }, + + /** + * Applies a value to an attribute + * @param {String} attr The name of the attribute. + * @param {Number} val The value to be applied to the attribute. + * @param {String} unit The unit ('px', '%', etc.) of the value. + */ + setAttribute: function(attr, val, unit) { + if ( this.patterns.noNegatives.test(attr) ) { + val = (val > 0) ? val : 0; + } + + YAHOO.util.Dom.setStyle(this.getEl(), attr, val + unit); + }, + + /** + * Returns current value of the attribute. + * @param {String} attr The name of the attribute. + * @return {Number} val The current value of the attribute. + */ + getAttribute: function(attr) { + var el = this.getEl(); + var val = YAHOO.util.Dom.getStyle(el, attr); + + if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) { + return parseFloat(val); + } + + var a = this.patterns.offsetAttribute.exec(attr) || []; + var pos = !!( a[3] ); // top or left + var box = !!( a[2] ); // width or height + + // use offsets for width/height and abs pos top/left + if ( box || (YAHOO.util.Dom.getStyle(el, 'position') == 'absolute' && pos) ) { + val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)]; + } else { // default to zero for other 'auto' + val = 0; + } + + return val; + }, + + /** + * Returns the unit to use when none is supplied. + * Applies the "defaultUnit" test to decide whether to use pixels or not + * @param {attr} attr The name of the attribute. + * @return {String} The default unit to be used. + */ + getDefaultUnit: function(attr) { + if ( this.patterns.defaultUnit.test(attr) ) { + return 'px'; + } + + return ''; + }, + + /** + * Sets the actual values to be used during the animation. + * Should only be needed for subclass use. + * @param {Object} attr The attribute object + * @private + */ + setRuntimeAttribute: function(attr) { + var start; + var end; + var attributes = this.attributes; + + this.runtimeAttributes[attr] = {}; + + var isset = function(prop) { + return (typeof prop !== 'undefined'); + }; + + if ( !isset(attributes[attr]['to']) && !isset(attributes[attr]['by']) ) { + return false; // note return; nothing to animate to + } + + start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr); + + // To beats by, per SMIL 2.1 spec + if ( isset(attributes[attr]['to']) ) { + end = attributes[attr]['to']; + } else if ( isset(attributes[attr]['by']) ) { + if (start.constructor == Array) { + end = []; + for (var i = 0, len = start.length; i < len; ++i) { + end[i] = start[i] + attributes[attr]['by'][i]; + } + } else { + end = start + attributes[attr]['by']; + } + } + + this.runtimeAttributes[attr].start = start; + this.runtimeAttributes[attr].end = end; + + // set units if needed + this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr); + }, + + /** + * @param {String or HTMLElement} el Reference to the element that will be animated + * @param {Object} attributes The attribute(s) to be animated. + * Each attribute is an object with at minimum a "to" or "by" member defined. + * Additional optional members are "from" (defaults to current value), "units" (defaults to "px"). + * All attribute names use camelCase. + * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based + * @param {Function} method (optional, defaults to YAHOO.util.Easing.easeNone) Computes the values that are applied to the attributes per frame (generally a YAHOO.util.Easing method) + */ + init: function(el, attributes, duration, method) { + /** + * Whether or not the animation is running. + * @private + * @type Boolean + */ + var isAnimated = false; + + /** + * A Date object that is created when the animation begins. + * @private + * @type Date + */ + var startTime = null; + + /** + * The number of frames this animation was able to execute. + * @private + * @type Int + */ + var actualFrames = 0; + + /** + * The element to be animated. + * @private + * @type HTMLElement + */ + el = YAHOO.util.Dom.get(el); + + /** + * The collection of attributes to be animated. + * Each attribute must have at least a "to" or "by" defined in order to animate. + * If "to" is supplied, the animation will end with the attribute at that value. + * If "by" is supplied, the animation will end at that value plus its starting value. + * If both are supplied, "to" is used, and "by" is ignored. + * @member YAHOO#util#Anim + * Optional additional member include "from" (the value the attribute should start animating from, defaults to current value), and "unit" (the units to apply to the values). + * @type Object + */ + this.attributes = attributes || {}; + + /** + * The length of the animation. Defaults to "1" (second). + * @type Number + */ + this.duration = duration || 1; + + /** + * The method that will provide values to the attribute(s) during the animation. + * Defaults to "YAHOO.util.Easing.easeNone". + * @type Function + */ + this.method = method || YAHOO.util.Easing.easeNone; + + /** + * Whether or not the duration should be treated as seconds. + * Defaults to true. + * @type Boolean + */ + this.useSeconds = true; // default to seconds + + /** + * The location of the current animation on the timeline. + * In time-based animations, this is used by AnimMgr to ensure the animation finishes on time. + * @type Int + */ + this.currentFrame = 0; + + /** + * The total number of frames to be executed. + * In time-based animations, this is used by AnimMgr to ensure the animation finishes on time. + * @type Int + */ + this.totalFrames = YAHOO.util.AnimMgr.fps; + + + /** + * Returns a reference to the animated element. + * @return {HTMLElement} + */ + this.getEl = function() { return el; }; + + /** + * Checks whether the element is currently animated. + * @return {Boolean} current value of isAnimated. + */ + this.isAnimated = function() { + return isAnimated; + }; + + /** + * Returns the animation start time. + * @return {Date} current value of startTime. + */ + this.getStartTime = function() { + return startTime; + }; + + this.runtimeAttributes = {}; + + + + /** + * Starts the animation by registering it with the animation manager. + */ + this.animate = function() { + if ( this.isAnimated() ) { return false; } + + this.currentFrame = 0; + + this.totalFrames = ( this.useSeconds ) ? Math.ceil(YAHOO.util.AnimMgr.fps * this.duration) : this.duration; + + YAHOO.util.AnimMgr.registerElement(this); + }; + + /** + * Stops the animation. Normally called by AnimMgr when animation completes. + */ + this.stop = function() { + YAHOO.util.AnimMgr.stop(this); + }; + + var onStart = function() { + this.onStart.fire(); + for (var attr in this.attributes) { + this.setRuntimeAttribute(attr); + } + + isAnimated = true; + actualFrames = 0; + startTime = new Date(); + }; + + /** + * Feeds the starting and ending values for each animated attribute to doMethod once per frame, then applies the resulting value to the attribute(s). + * @private + */ + + var onTween = function() { + var data = { + duration: new Date() - this.getStartTime(), + currentFrame: this.currentFrame + }; + + data.toString = function() { + return ( + 'duration: ' + data.duration + + ', currentFrame: ' + data.currentFrame + ); + }; + + this.onTween.fire(data); + + var runtimeAttributes = this.runtimeAttributes; + + for (var attr in runtimeAttributes) { + this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit); + } + + actualFrames += 1; + }; + + var onComplete = function() { + var actual_duration = (new Date() - startTime) / 1000 ; + + var data = { + duration: actual_duration, + frames: actualFrames, + fps: actualFrames / actual_duration + }; + + data.toString = function() { + return ( + 'duration: ' + data.duration + + ', frames: ' + data.frames + + ', fps: ' + data.fps + ); + }; + + isAnimated = false; + actualFrames = 0; + this.onComplete.fire(data); + }; + + /** + * Custom event that fires after onStart, useful in subclassing + * @private + */ + this._onStart = new YAHOO.util.CustomEvent('_start', this, true); + + /** + * Custom event that fires when animation begins + * Listen via subscribe method (e.g. myAnim.onStart.subscribe(someFunction) + */ + this.onStart = new YAHOO.util.CustomEvent('start', this); + + /** + * Custom event that fires between each frame + * Listen via subscribe method (e.g. myAnim.onTween.subscribe(someFunction) + */ + this.onTween = new YAHOO.util.CustomEvent('tween', this); + + /** + * Custom event that fires after onTween + * @private + */ + this._onTween = new YAHOO.util.CustomEvent('_tween', this, true); + + /** + * Custom event that fires when animation ends + * Listen via subscribe method (e.g. myAnim.onComplete.subscribe(someFunction) + */ + this.onComplete = new YAHOO.util.CustomEvent('complete', this); + /** + * Custom event that fires after onComplete + * @private + */ + this._onComplete = new YAHOO.util.CustomEvent('_complete', this, true); + + this._onStart.subscribe(onStart); + this._onTween.subscribe(onTween); + this._onComplete.subscribe(onComplete); + } +}; + +/** + * @class Handles animation queueing and threading. + * Used by Anim and subclasses. + */ +YAHOO.util.AnimMgr = new function() { + /** + * Reference to the animation Interval + * @private + * @type Int + */ + var thread = null; + + /** + * The current queue of registered animation objects. + * @private + * @type Array + */ + var queue = []; + + /** + * The number of active animations. + * @private + * @type Int + */ + var tweenCount = 0; + + /** + * Base frame rate (frames per second). + * Arbitrarily high for better x-browser calibration (slower browsers drop more frames). + * @type Int + * + */ + this.fps = 200; + + /** + * Interval delay in milliseconds, defaults to fastest possible. + * @type Int + * + */ + this.delay = 1; + + /** + * Adds an animation instance to the animation queue. + * All animation instances must be registered in order to animate. + * @param {object} tween The Anim instance to be be registered + */ + this.registerElement = function(tween) { + queue[queue.length] = tween; + tweenCount += 1; + tween._onStart.fire(); + this.start(); + }; + + this.unRegister = function(tween, index) { + tween._onComplete.fire(); + index = index || getIndex(tween); + if (index != -1) { queue.splice(index, 1); } + + tweenCount -= 1; + if (tweenCount <= 0) { this.stop(); } + }; + + /** + * Starts the animation thread. + * Only one thread can run at a time. + */ + this.start = function() { + if (thread === null) { thread = setInterval(this.run, this.delay); } + }; + + /** + * Stops the animation thread or a specific animation instance. + * @param {object} tween A specific Anim instance to stop (optional) + * If no instance given, Manager stops thread and all animations. + */ + this.stop = function(tween) { + if (!tween) { + clearInterval(thread); + for (var i = 0, len = queue.length; i < len; ++i) { + if (queue[i].isAnimated()) { + this.unRegister(tween, i); + } + } + queue = []; + thread = null; + tweenCount = 0; + } + else { + this.unRegister(tween); + } + }; + + /** + * Called per Interval to handle each animation frame. + */ + this.run = function() { + for (var i = 0, len = queue.length; i < len; ++i) { + var tween = queue[i]; + if ( !tween || !tween.isAnimated() ) { continue; } + + if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null) + { + tween.currentFrame += 1; + + if (tween.useSeconds) { + correctFrame(tween); + } + tween._onTween.fire(); + } + else { YAHOO.util.AnimMgr.stop(tween, i); } + } + }; + + var getIndex = function(anim) { + for (var i = 0, len = queue.length; i < len; ++i) { + if (queue[i] == anim) { + return i; // note return; + } + } + return -1; + }; + + /** + * On the fly frame correction to keep animation on time. + * @private + * @param {Object} tween The Anim instance being corrected. + */ + var correctFrame = function(tween) { + var frames = tween.totalFrames; + var frame = tween.currentFrame; + var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames); + var elapsed = (new Date() - tween.getStartTime()); + var tweak = 0; + + if (elapsed < tween.duration * 1000) { // check if falling behind + tweak = Math.round((elapsed / expected - 1) * tween.currentFrame); + } else { // went over duration, so jump to end + tweak = frames - (frame + 1); + } + if (tweak > 0 && isFinite(tweak)) { // adjust if needed + if (tween.currentFrame + tweak >= frames) {// dont go past last frame + tweak = frames - (frame + 1); + } + + tween.currentFrame += tweak; + } + }; +}; +/** + * + * @class Used to calculate Bezier splines for any number of control points. + * + */ +YAHOO.util.Bezier = new function() +{ + /** + * Get the current position of the animated element based on t. + * Each point is an array of "x" and "y" values (0 = x, 1 = y) + * At least 2 points are required (start and end). + * First point is start. Last point is end. + * Additional control points are optional. + * @param {Array} points An array containing Bezier points + * @param {Number} t A number between 0 and 1 which is the basis for determining current position + * @return {Array} An array containing int x and y member data + */ + this.getPosition = function(points, t) + { + var n = points.length; + var tmp = []; + + for (var i = 0; i < n; ++i){ + tmp[i] = [points[i][0], points[i][1]]; // save input + } + + for (var j = 1; j < n; ++j) { + for (i = 0; i < n - j; ++i) { + tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0]; + tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1]; + } + } + + return [ tmp[0][0], tmp[0][1] ]; + + }; +}; +/** + * @class ColorAnim subclass for color fading + *Usage: var myAnim = new Y.ColorAnim(el, { backgroundColor: { from: '#FF0000', to: '#FFFFFF' } }, 1, Y.Easing.easeOut);
Color values can be specified with either 112233, #112233, [255,255,255], or rgb(255,255,255) + * @requires YAHOO.util.Anim + * @requires YAHOO.util.AnimMgr + * @requires YAHOO.util.Easing + * @requires YAHOO.util.Bezier + * @requires YAHOO.util.Dom + * @requires YAHOO.util.Event + * @constructor + * @param {HTMLElement | String} el Reference to the element that will be animated + * @param {Object} attributes The attribute(s) to be animated. + * Each attribute is an object with at minimum a "to" or "by" member defined. + * Additional optional members are "from" (defaults to current value), "units" (defaults to "px"). + * All attribute names use camelCase. + * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based + * @param {Function} method (optional, defaults to YAHOO.util.Easing.easeNone) Computes the values that are applied to the attributes per frame (generally a YAHOO.util.Easing method) + */ +(function() { + YAHOO.util.ColorAnim = function(el, attributes, duration, method) { + YAHOO.util.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method); + }; + + YAHOO.extend(YAHOO.util.ColorAnim, YAHOO.util.Anim); + + // shorthand + var Y = YAHOO.util; + var superclass = Y.ColorAnim.superclass; + var proto = Y.ColorAnim.prototype; + + /** + * toString method + * @return {String} string represenation of anim obj + */ + proto.toString = function() { + var el = this.getEl(); + var id = el.id || el.tagName; + return ("ColorAnim " + id); + }; + + /** + * Only certain attributes should be treated as colors. + * @type Object + */ + proto.patterns.color = /color$/i; + proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i; + proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i; + proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i; + + /** + * Attempts to parse the given string and return a 3-tuple. + * @param {String} s The string to parse. + * @return {Array} The 3-tuple of rgb values. + */ + proto.parseColor = function(s) { + if (s.length == 3) { return s; } + + var c = this.patterns.hex.exec(s); + if (c && c.length == 4) { + return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ]; + } + + c = this.patterns.rgb.exec(s); + if (c && c.length == 4) { + return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ]; + } + + c = this.patterns.hex3.exec(s); + if (c && c.length == 4) { + return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ]; + } + + return null; + }; + + /** + * Returns current value of the attribute. + * @param {String} attr The name of the attribute. + * @return {Number} val The current value of the attribute. + */ + proto.getAttribute = function(attr) { + var el = this.getEl(); + if ( this.patterns.color.test(attr) ) { + var val = YAHOO.util.Dom.getStyle(el, attr); + + if (val == 'transparent') { // bgcolor default + var parent = el.parentNode; // try and get from an ancestor + val = Y.Dom.getStyle(parent, attr); + + while (parent && val == 'transparent') { + parent = parent.parentNode; + val = Y.Dom.getStyle(parent, attr); + if (parent.tagName.toUpperCase() == 'HTML') { + val = 'ffffff'; + } + } + } + } else { + val = superclass.getAttribute.call(this, attr); + } + + return val; + }; + + /** + * Returns the value computed by the animation's "method". + * @param {String} attr The name of the attribute. + * @param {Number} start The value this attribute should start from for this animation. + * @param {Number} end The value this attribute should end at for this animation. + * @return {Number} The Value to be applied to the attribute. + */ + proto.doMethod = function(attr, start, end) { + var val; + + if ( this.patterns.color.test(attr) ) { + val = []; + for (var i = 0, len = start.length; i < len; ++i) { + val[i] = superclass.doMethod.call(this, attr, start[i], end[i]); + } + + val = 'rgb('+Math.floor(val[0])+','+Math.floor(val[1])+','+Math.floor(val[2])+')'; + } + else { + val = superclass.doMethod.call(this, attr, start, end); + } + + return val; + }; + + /** + * Sets the actual values to be used during the animation. + * Should only be needed for subclass use. + * @param {Object} attr The attribute object + * @private + */ + proto.setRuntimeAttribute = function(attr) { + superclass.setRuntimeAttribute.call(this, attr); + + if ( this.patterns.color.test(attr) ) { + var attributes = this.attributes; + var start = this.parseColor(this.runtimeAttributes[attr].start); + var end = this.parseColor(this.runtimeAttributes[attr].end); + // fix colors if going "by" + if ( typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined' ) { + end = this.parseColor(attributes[attr].by); + + for (var i = 0, len = start.length; i < len; ++i) { + end[i] = start[i] + end[i]; + } + } + + this.runtimeAttributes[attr].start = start; + this.runtimeAttributes[attr].end = end; + } + }; +})();/* +TERMS OF USE - EASING EQUATIONS +Open source under the BSD License. +Copyright � 2001 Robert Penner All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +YAHOO.util.Easing = { + + /** + * Uniform speed between points. + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @return {Number} The computed value for the current animation frame. + */ + easeNone: function (t, b, c, d) { + return c*t/d + b; + }, + + /** + * Begins slowly and accelerates towards end. (quadratic) + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @return {Number} The computed value for the current animation frame. + */ + easeIn: function (t, b, c, d) { + return c*(t/=d)*t + b; + }, + + /** + * Begins quickly and decelerates towards end. (quadratic) + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @return {Number} The computed value for the current animation frame. + */ + easeOut: function (t, b, c, d) { + return -c *(t/=d)*(t-2) + b; + }, + + /** + * Begins slowly and decelerates towards end. (quadratic) + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @return {Number} The computed value for the current animation frame. + */ + easeBoth: function (t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t + b; + return -c/2 * ((--t)*(t-2) - 1) + b; + }, + + /** + * Begins slowly and accelerates towards end. (quartic) + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @return {Number} The computed value for the current animation frame. + */ + easeInStrong: function (t, b, c, d) { + return c*(t/=d)*t*t*t + b; + }, + + /** + * Begins quickly and decelerates towards end. (quartic) + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @return {Number} The computed value for the current animation frame. + */ + easeOutStrong: function (t, b, c, d) { + return -c * ((t=t/d-1)*t*t*t - 1) + b; + }, + + /** + * Begins slowly and decelerates towards end. (quartic) + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @return {Number} The computed value for the current animation frame. + */ + easeBothStrong: function (t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t*t*t + b; + return -c/2 * ((t-=2)*t*t*t - 2) + b; + }, + + /** + * snap in elastic effect + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @param {Number} p Period (optional) + * @return {Number} The computed value for the current animation frame. + */ + + elasticIn: function (t, b, c, d, a, p) { + if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; + if (!a || a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; + }, + + /** + * snap out elastic effect + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @param {Number} p Period (optional) + * @return {Number} The computed value for the current animation frame. + */ + elasticOut: function (t, b, c, d, a, p) { + if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; + if (!a || a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b; + }, + + /** + * snap both elastic effect + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @param {Number} p Period (optional) + * @return {Number} The computed value for the current animation frame. + */ + elasticBoth: function (t, b, c, d, a, p) { + if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); + if (!a || a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; + return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b; + }, + + /** + * back easing in - backtracking slightly, then reversing direction and moving to target + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @param {Number) s Overshoot (optional) + * @return {Number} The computed value for the current animation frame. + */ + backIn: function (t, b, c, d, s) { + if (typeof s == 'undefined') s = 1.70158; + return c*(t/=d)*t*((s+1)*t - s) + b; + }, + + /** + * back easing out - moving towards target, overshooting it slightly, + * then reversing and coming back to target + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @param {Number) s Overshoot (optional) + * @return {Number} The computed value for the current animation frame. + */ + backOut: function (t, b, c, d, s) { + if (typeof s == 'undefined') s = 1.70158; + return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; + }, + + /** + * back easing in/out - backtracking slightly, then reversing direction and moving to target, + * then overshooting target, reversing, and finally coming back to target + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @param {Number) s Overshoot (optional) + * @return {Number} The computed value for the current animation frame. + */ + backBoth: function (t, b, c, d, s) { + if (typeof s == 'undefined') s = 1.70158; + if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; + return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; + }, + + /** + * bounce in + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @return {Number} The computed value for the current animation frame. + */ + bounceIn: function (t, b, c, d) { + return c - YAHOO.util.Easing.bounceOut(d-t, 0, c, d) + b; + }, + + /** + * bounce out + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @return {Number} The computed value for the current animation frame. + */ + bounceOut: function (t, b, c, d) { + if ((t/=d) < (1/2.75)) { + return c*(7.5625*t*t) + b; + } else if (t < (2/2.75)) { + return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; + } else if (t < (2.5/2.75)) { + return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; + } else { + return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; + } + }, + + /** + * bounce both + * @param {Number} t Time value used to compute current value. + * @param {Number} b Starting value. + * @param {Number} c Delta between start and end values. + * @param {Number} d Total length of animation. + * @return {Number} The computed value for the current animation frame. + */ + bounceBoth: function (t, b, c, d) { + if (t < d/2) return YAHOO.util.Easing.bounceIn(t*2, 0, c, d) * .5 + b; + return YAHOO.util.Easing.bounceOut(t*2-d, 0, c, d) * .5 + c*.5 + b; + } +}; + +/** + * @class Anim subclass for moving elements along a path defined by the "points" member of "attributes". All "points" are arrays with x, y coordinates. + *
Usage: var myAnim = new YAHOO.util.Motion(el, { points: { to: [800, 800] } }, 1, YAHOO.util.Easing.easeOut);
Usage: var myAnim = new YAHOO.util.Scroll(el, { scroll: { to: [0, 800] } }, 1, YAHOO.util.Easing.easeOut);