Static default values used to populate callback configuration properties.
+ * Preconfigured defaults include:
+ *
+ *
+ *
autoContinue: true
+ *
iterations: 1
+ *
timeout: 10 (10ms between callbacks)
+ *
until: (function to run until iterations <= 0)
+ *
+ *
+ * @property AsyncQueue.defaults
+ * @type {Object}
+ * @static
+ */
+Queue.defaults = Y.mix({
+ autoContinue : true,
+ iterations : 1,
+ timeout : 10,
+ until : function () {
+ this.iterations |= 0;
+ return this.iterations <= 0;
+ }
+}, Y.config.queueDefaults || {});
+
+Y.extend(Queue, Y.EventTarget, {
+ /**
+ * Used to indicate the queue is currently executing a callback.
+ *
+ * @property _running
+ * @type {Boolean|Object} true for synchronous callback execution, the
+ * return handle from Y.later for async callbacks.
+ * Otherwise false.
+ * @protected
+ */
+ _running : false,
+
+ /**
+ * Initializes the AsyncQueue instance properties and events.
+ *
+ * @method _init
+ * @protected
+ */
+ _init : function () {
+ Y.EventTarget.call(this, { emitFacade: true });
+
+ this._q = [];
+
+ /**
+ * Callback defaults for this instance. Static defaults that are not
+ * overridden are also included.
+ *
+ * @property defaults
+ * @type {Object}
+ */
+ this.defaults = {};
+
+ this._initEvents();
+ },
+
+ /**
+ * Initializes the instance events.
+ *
+ * @method _initEvents
+ * @protected
+ */
+ _initEvents : function () {
+ /*
+ this.publish({
+ 'execute' : { defaultFn : this._defExecFn },
+ 'shift' : { defaultFn : this._defShiftFn },
+ 'add' : { defaultFn : this._defAddFn },
+ 'promote' : { defaultFn : this._defPromoteFn },
+ 'remove' : { defaultFn : this._defRemoveFn }
+ });
+ */
+ this.publish('execute' , { defaultFn : this._defExecFn, emitFacade: true });
+ this.publish('shift' , { defaultFn : this._defShiftFn, emitFacade: true });
+ this.publish('add' , { defaultFn : this._defAddFn, emitFacade: true });
+ this.publish('promote' , { defaultFn : this._defPromoteFn, emitFacade: true });
+ this.publish('remove' , { defaultFn : this._defRemoveFn, emitFacade: true });
+ },
+
+ /**
+ * Returns the next callback needing execution. If a callback is
+ * configured to repeat via iterations or until, it will be returned until
+ * the completion criteria is met.
+ *
+ * When the queue is empty, null is returned.
+ *
+ * @method next
+ * @return {Function} the callback to execute
+ */
+ next : function () {
+ var callback;
+
+ while (this._q.length) {
+ callback = this._q[0] = this._prepare(this._q[0]);
+ if (callback && callback.until()) {
+ this.fire(SHIFT, { callback: callback });
+ callback = null;
+ } else {
+ break;
+ }
+ }
+
+ return callback || null;
+ },
+
+ /**
+ * Default functionality for the "shift" event. Shifts the
+ * callback stored in the event object's callback property from
+ * the queue if it is the first item.
+ *
+ * @method _defShiftFn
+ * @param e {Event} The event object
+ * @protected
+ */
+ _defShiftFn : function (e) {
+ if (this.indexOf(e.callback) === 0) {
+ this._q.shift();
+ }
+ },
+
+ /**
+ * Creates a wrapper function to execute the callback using the aggregated
+ * configuration generated by combining the static AsyncQueue.defaults, the
+ * instance defaults, and the specified callback settings.
+ *
+ * The wrapper function is decorated with the callback configuration as
+ * properties for runtime modification.
+ *
+ * @method _prepare
+ * @param callback {Object|Function} the raw callback
+ * @return {Function} a decorated function wrapper to execute the callback
+ * @protected
+ */
+ _prepare: function (callback) {
+ if (isFunction(callback) && callback._prepared) {
+ return callback;
+ }
+
+ var config = Y.merge(
+ Queue.defaults,
+ { context : this, args: [], _prepared: true },
+ this.defaults,
+ (isFunction(callback) ? { fn: callback } : callback)),
+
+ wrapper = Y.bind(function () {
+ if (!wrapper._running) {
+ wrapper.iterations--;
+ }
+ if (isFunction(wrapper.fn)) {
+ wrapper.fn.apply(wrapper.context || Y,
+ Y.Array(wrapper.args));
+ }
+ }, this);
+
+ return Y.mix(wrapper, config);
+ },
+
+ /**
+ * Sets the queue in motion. All queued callbacks will be executed in
+ * order unless pause() or stop() is called or if one of the callbacks is
+ * configured with autoContinue: false.
+ *
+ * @method run
+ * @return {AsyncQueue} the AsyncQueue instance
+ * @chainable
+ */
+ run : function () {
+ var callback,
+ cont = true;
+
+ for (callback = this.next();
+ cont && callback && !this.isRunning();
+ callback = this.next())
+ {
+ cont = (callback.timeout < 0) ?
+ this._execute(callback) :
+ this._schedule(callback);
+ }
+
+ if (!callback) {
+ /**
+ * Event fired after the last queued callback is executed.
+ * @event complete
+ */
+ this.fire('complete');
+ }
+
+ return this;
+ },
+
+ /**
+ * Handles the execution of callbacks. Returns a boolean indicating
+ * whether it is appropriate to continue running.
+ *
+ * @method _execute
+ * @param callback {Object} the callback object to execute
+ * @return {Boolean} whether the run loop should continue
+ * @protected
+ */
+ _execute : function (callback) {
+ this._running = callback._running = true;
+
+ callback.iterations--;
+ this.fire(EXECUTE, { callback: callback });
+
+ var cont = this._running && callback.autoContinue;
+
+ this._running = callback._running = false;
+
+ return cont;
+ },
+
+ /**
+ * Schedules the execution of asynchronous callbacks.
+ *
+ * @method _schedule
+ * @param callback {Object} the callback object to execute
+ * @return {Boolean} whether the run loop should continue
+ * @protected
+ */
+ _schedule : function (callback) {
+ this._running = Y.later(callback.timeout, this, function () {
+ if (this._execute(callback)) {
+ this.run();
+ }
+ });
+
+ return false;
+ },
+
+ /**
+ * Determines if the queue is waiting for a callback to complete execution.
+ *
+ * @method isRunning
+ * @return {Boolean} true if queue is waiting for a
+ * from any initiated transactions
+ */
+ isRunning : function () {
+ return !!this._running;
+ },
+
+ /**
+ * Default functionality for the "execute" event. Executes the
+ * callback function
+ *
+ * @method _defExecFn
+ * @param e {Event} the event object
+ * @protected
+ */
+ _defExecFn : function (e) {
+ e.callback();
+ },
+
+ /**
+ * Add any number of callbacks to the end of the queue. Callbacks may be
+ * provided as functions or objects.
+ *
+ * @method add
+ * @param callback* {Function|Object} 0..n callbacks
+ * @return {AsyncQueue} the AsyncQueue instance
+ * @chainable
+ */
+ add : function () {
+ this.fire('add', { callbacks: Y.Array(arguments,0,true) });
+
+ return this;
+ },
+
+ /**
+ * Default functionality for the "add" event. Adds the callbacks
+ * in the event facade to the queue. Callbacks successfully added to the
+ * queue are present in the event's added property in the
+ * after phase.
+ *
+ * @method _defAddFn
+ * @param e {Event} the event object
+ * @protected
+ */
+ _defAddFn : function(e) {
+ var _q = this._q,
+ added = [];
+
+ Y.Array.each(e.callbacks, function (c) {
+ if (isObject(c)) {
+ _q.push(c);
+ added.push(c);
+ }
+ });
+
+ e.added = added;
+ },
+
+ /**
+ * Pause the execution of the queue after the execution of the current
+ * callback completes. If called from code outside of a queued callback,
+ * clears the timeout for the pending callback. Paused queue can be
+ * restarted with q.run()
+ *
+ * @method pause
+ * @return {AsyncQueue} the AsyncQueue instance
+ * @chainable
+ */
+ pause: function () {
+ if (isObject(this._running)) {
+ this._running.cancel();
+ }
+
+ this._running = false;
+
+ return this;
+ },
+
+ /**
+ * Stop and clear the queue after the current execution of the
+ * current callback completes.
+ *
+ * @method stop
+ * @return {AsyncQueue} the AsyncQueue instance
+ * @chainable
+ */
+ stop : function () {
+ this._q = [];
+
+ return this.pause();
+ },
+
+ /**
+ * Returns the current index of a callback. Pass in either the id or
+ * callback function from getCallback.
+ *
+ * @method indexOf
+ * @param callback {String|Function} the callback or its specified id
+ * @return {Number} index of the callback or -1 if not found
+ */
+ indexOf : function (callback) {
+ var i = 0, len = this._q.length, c;
+
+ for (; i < len; ++i) {
+ c = this._q[i];
+ if (c === callback || c.id === callback) {
+ return i;
+ }
+ }
+
+ return -1;
+ },
+
+ /**
+ * Retrieve a callback by its id. Useful to modify the configuration
+ * while the queue is running.
+ *
+ * @method getCallback
+ * @param id {String} the id assigned to the callback
+ * @return {Object} the callback object
+ */
+ getCallback : function (id) {
+ var i = this.indexOf(id);
+
+ return (i > -1) ? this._q[i] : null;
+ },
+
+ /**
+ * Promotes the named callback to the top of the queue. If a callback is
+ * currently executing or looping (via until or iterations), the promotion
+ * is scheduled to occur after the current callback has completed.
+ *
+ * @method promote
+ * @param callback {String|Object} the callback object or a callback's id
+ * @return {AsyncQueue} the AsyncQueue instance
+ * @chainable
+ */
+ promote : function (callback) {
+ var payload = { callback : callback },e;
+
+ if (this.isRunning()) {
+ e = this.after(SHIFT, function () {
+ this.fire(PROMOTE, payload);
+ e.detach();
+ }, this);
+ } else {
+ this.fire(PROMOTE, payload);
+ }
+
+ return this;
+ },
+
+ /**
+ *
Default functionality for the "promote" event. Promotes the
+ * named callback to the head of the queue.
+ *
+ *
The event object will contain a property "callback", which
+ * holds the id of a callback or the callback object itself.
+ *
+ * @method _defPromoteFn
+ * @param e {Event} the custom event
+ * @protected
+ */
+ _defPromoteFn : function (e) {
+ var i = this.indexOf(e.callback),
+ promoted = (i > -1) ? this._q.splice(i,1)[0] : null;
+
+ e.promoted = promoted;
+
+ if (promoted) {
+ this._q.unshift(promoted);
+ }
+ },
+
+ /**
+ * Removes the callback from the queue. If the queue is active, the
+ * removal is scheduled to occur after the current callback has completed.
+ *
+ * @method remove
+ * @param callback {String|Object} the callback object or a callback's id
+ * @return {AsyncQueue} the AsyncQueue instance
+ * @chainable
+ */
+ remove : function (callback) {
+ var payload = { callback : callback },e;
+
+ // Can't return the removed callback because of the deferral until
+ // current callback is complete
+ if (this.isRunning()) {
+ e = this.after(SHIFT, function () {
+ this.fire(REMOVE, payload);
+ e.detach();
+ },this);
+ } else {
+ this.fire(REMOVE, payload);
+ }
+
+ return this;
+ },
+
+ /**
+ *
Default functionality for the "remove" event. Removes the
+ * callback from the queue.
+ *
+ *
The event object will contain a property "callback", which
+ * holds the id of a callback or the callback object itself.
+ *
+ * @method _defRemoveFn
+ * @param e {Event} the custom event
+ * @protected
+ */
+ _defRemoveFn : function (e) {
+ var i = this.indexOf(e.callback);
+
+ e.removed = (i > -1) ? this._q.splice(i,1)[0] : null;
+ },
+
+ /**
+ * Returns the number of callbacks in the queue.
+ *
+ * @method size
+ * @return {Number}
+ */
+ size : function () {
+ // next() flushes callbacks that have met their until() criteria and
+ // therefore shouldn't count since they wouldn't execute anyway.
+ if (!this.isRunning()) {
+ this.next();
+ }
+
+ return this._q.length;
+ }
+});
+
+
+
+}, '3.0.0' ,{requires:['event-custom']});
diff --git a/lib/yui/3.0.0/async-queue/async-queue-min.js b/lib/yui/3.0.0/async-queue/async-queue-min.js
new file mode 100644
index 0000000000..1287ae94eb
--- /dev/null
+++ b/lib/yui/3.0.0/async-queue/async-queue-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("async-queue",function(G){G.AsyncQueue=function(){this._init();this.add.apply(this,arguments);};var E=G.AsyncQueue,C="execute",B="shift",D="promote",H="remove",A=G.Lang.isObject,F=G.Lang.isFunction;E.defaults=G.mix({autoContinue:true,iterations:1,timeout:10,until:function(){this.iterations|=0;return this.iterations<=0;}},G.config.queueDefaults||{});G.extend(E,G.EventTarget,{_running:false,_init:function(){G.EventTarget.call(this,{emitFacade:true});this._q=[];this.defaults={};this._initEvents();},_initEvents:function(){this.publish("execute",{defaultFn:this._defExecFn,emitFacade:true});this.publish("shift",{defaultFn:this._defShiftFn,emitFacade:true});this.publish("add",{defaultFn:this._defAddFn,emitFacade:true});this.publish("promote",{defaultFn:this._defPromoteFn,emitFacade:true});this.publish("remove",{defaultFn:this._defRemoveFn,emitFacade:true});},next:function(){var I;while(this._q.length){I=this._q[0]=this._prepare(this._q[0]);if(I&&I.until()){this.fire(B,{callback:I});I=null;}else{break;}}return I||null;},_defShiftFn:function(I){if(this.indexOf(I.callback)===0){this._q.shift();}},_prepare:function(K){if(F(K)&&K._prepared){return K;}var I=G.merge(E.defaults,{context:this,args:[],_prepared:true},this.defaults,(F(K)?{fn:K}:K)),J=G.bind(function(){if(!J._running){J.iterations--;}if(F(J.fn)){J.fn.apply(J.context||G,G.Array(J.args));}},this);return G.mix(J,I);},run:function(){var J,I=true;for(J=this.next();I&&J&&!this.isRunning();J=this.next()){I=(J.timeout<0)?this._execute(J):this._schedule(J);}if(!J){this.fire("complete");}return this;},_execute:function(J){this._running=J._running=true;J.iterations--;this.fire(C,{callback:J});var I=this._running&&J.autoContinue;this._running=J._running=false;return I;},_schedule:function(I){this._running=G.later(I.timeout,this,function(){if(this._execute(I)){this.run();}});return false;},isRunning:function(){return !!this._running;},_defExecFn:function(I){I.callback();},add:function(){this.fire("add",{callbacks:G.Array(arguments,0,true)});return this;},_defAddFn:function(J){var K=this._q,I=[];G.Array.each(J.callbacks,function(L){if(A(L)){K.push(L);I.push(L);}});J.added=I;},pause:function(){if(A(this._running)){this._running.cancel();}this._running=false;return this;},stop:function(){this._q=[];return this.pause();},indexOf:function(L){var J=0,I=this._q.length,K;for(;J-1)?this._q[I]:null;},promote:function(K){var J={callback:K},I;if(this.isRunning()){I=this.after(B,function(){this.fire(D,J);I.detach();},this);}else{this.fire(D,J);}return this;},_defPromoteFn:function(K){var I=this.indexOf(K.callback),J=(I>-1)?this._q.splice(I,1)[0]:null;K.promoted=J;if(J){this._q.unshift(J);}},remove:function(K){var J={callback:K},I;if(this.isRunning()){I=this.after(B,function(){this.fire(H,J);I.detach();},this);}else{this.fire(H,J);}return this;},_defRemoveFn:function(J){var I=this.indexOf(J.callback);J.removed=(I>-1)?this._q.splice(I,1)[0]:null;},size:function(){if(!this.isRunning()){this.next();}return this._q.length;}});},"3.0.0",{requires:["event-custom"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/async-queue/async-queue.js b/lib/yui/3.0.0/async-queue/async-queue.js
new file mode 100644
index 0000000000..1025fe6fd1
--- /dev/null
+++ b/lib/yui/3.0.0/async-queue/async-queue.js
@@ -0,0 +1,536 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('async-queue', function(Y) {
+
+/**
+ *
AsyncQueue allows you create a chain of function callbacks executed
+ * via setTimeout (or synchronously) that are guaranteed to run in order.
+ * Items in the queue can be promoted or removed. Start or resume the
+ * execution chain with run(). pause() to temporarily delay execution, or
+ * stop() to halt and clear the queue.
+ *
+ * @module async-queue
+ */
+
+/**
+ *
A specialized queue class that supports scheduling callbacks to execute
+ * sequentially, iteratively, even asynchronously.
+ *
+ *
Callbacks can be function refs or objects with the following keys. Only
+ * the fn key is required.
+ *
+ *
+ *
fn -- The callback function
+ *
context -- The execution context for the callbackFn.
+ *
args -- Arguments to pass to callbackFn.
+ *
timeout -- Millisecond delay before executing callbackFn.
+ * (Applies to each iterative execution of callback)
+ *
iterations -- Number of times to repeat the callback.
+ *
until -- Repeat the callback until this function returns
+ * true. This setting trumps iterations.
+ *
autoContinue -- Set to false to prevent the AsyncQueue from
+ * executing the next callback in the Queue after
+ * the callback completes.
+ *
id -- Name that can be used to get, promote, get the
+ * indexOf, or delete this callback.
Static default values used to populate callback configuration properties.
+ * Preconfigured defaults include:
+ *
+ *
+ *
autoContinue: true
+ *
iterations: 1
+ *
timeout: 10 (10ms between callbacks)
+ *
until: (function to run until iterations <= 0)
+ *
+ *
+ * @property AsyncQueue.defaults
+ * @type {Object}
+ * @static
+ */
+Queue.defaults = Y.mix({
+ autoContinue : true,
+ iterations : 1,
+ timeout : 10,
+ until : function () {
+ this.iterations |= 0;
+ return this.iterations <= 0;
+ }
+}, Y.config.queueDefaults || {});
+
+Y.extend(Queue, Y.EventTarget, {
+ /**
+ * Used to indicate the queue is currently executing a callback.
+ *
+ * @property _running
+ * @type {Boolean|Object} true for synchronous callback execution, the
+ * return handle from Y.later for async callbacks.
+ * Otherwise false.
+ * @protected
+ */
+ _running : false,
+
+ /**
+ * Initializes the AsyncQueue instance properties and events.
+ *
+ * @method _init
+ * @protected
+ */
+ _init : function () {
+ Y.EventTarget.call(this, { emitFacade: true });
+
+ this._q = [];
+
+ /**
+ * Callback defaults for this instance. Static defaults that are not
+ * overridden are also included.
+ *
+ * @property defaults
+ * @type {Object}
+ */
+ this.defaults = {};
+
+ this._initEvents();
+ },
+
+ /**
+ * Initializes the instance events.
+ *
+ * @method _initEvents
+ * @protected
+ */
+ _initEvents : function () {
+ /*
+ this.publish({
+ 'execute' : { defaultFn : this._defExecFn },
+ 'shift' : { defaultFn : this._defShiftFn },
+ 'add' : { defaultFn : this._defAddFn },
+ 'promote' : { defaultFn : this._defPromoteFn },
+ 'remove' : { defaultFn : this._defRemoveFn }
+ });
+ */
+ this.publish('execute' , { defaultFn : this._defExecFn, emitFacade: true });
+ this.publish('shift' , { defaultFn : this._defShiftFn, emitFacade: true });
+ this.publish('add' , { defaultFn : this._defAddFn, emitFacade: true });
+ this.publish('promote' , { defaultFn : this._defPromoteFn, emitFacade: true });
+ this.publish('remove' , { defaultFn : this._defRemoveFn, emitFacade: true });
+ },
+
+ /**
+ * Returns the next callback needing execution. If a callback is
+ * configured to repeat via iterations or until, it will be returned until
+ * the completion criteria is met.
+ *
+ * When the queue is empty, null is returned.
+ *
+ * @method next
+ * @return {Function} the callback to execute
+ */
+ next : function () {
+ var callback;
+
+ while (this._q.length) {
+ callback = this._q[0] = this._prepare(this._q[0]);
+ if (callback && callback.until()) {
+ this.fire(SHIFT, { callback: callback });
+ callback = null;
+ } else {
+ break;
+ }
+ }
+
+ return callback || null;
+ },
+
+ /**
+ * Default functionality for the "shift" event. Shifts the
+ * callback stored in the event object's callback property from
+ * the queue if it is the first item.
+ *
+ * @method _defShiftFn
+ * @param e {Event} The event object
+ * @protected
+ */
+ _defShiftFn : function (e) {
+ if (this.indexOf(e.callback) === 0) {
+ this._q.shift();
+ }
+ },
+
+ /**
+ * Creates a wrapper function to execute the callback using the aggregated
+ * configuration generated by combining the static AsyncQueue.defaults, the
+ * instance defaults, and the specified callback settings.
+ *
+ * The wrapper function is decorated with the callback configuration as
+ * properties for runtime modification.
+ *
+ * @method _prepare
+ * @param callback {Object|Function} the raw callback
+ * @return {Function} a decorated function wrapper to execute the callback
+ * @protected
+ */
+ _prepare: function (callback) {
+ if (isFunction(callback) && callback._prepared) {
+ return callback;
+ }
+
+ var config = Y.merge(
+ Queue.defaults,
+ { context : this, args: [], _prepared: true },
+ this.defaults,
+ (isFunction(callback) ? { fn: callback } : callback)),
+
+ wrapper = Y.bind(function () {
+ if (!wrapper._running) {
+ wrapper.iterations--;
+ }
+ if (isFunction(wrapper.fn)) {
+ wrapper.fn.apply(wrapper.context || Y,
+ Y.Array(wrapper.args));
+ }
+ }, this);
+
+ return Y.mix(wrapper, config);
+ },
+
+ /**
+ * Sets the queue in motion. All queued callbacks will be executed in
+ * order unless pause() or stop() is called or if one of the callbacks is
+ * configured with autoContinue: false.
+ *
+ * @method run
+ * @return {AsyncQueue} the AsyncQueue instance
+ * @chainable
+ */
+ run : function () {
+ var callback,
+ cont = true;
+
+ for (callback = this.next();
+ cont && callback && !this.isRunning();
+ callback = this.next())
+ {
+ cont = (callback.timeout < 0) ?
+ this._execute(callback) :
+ this._schedule(callback);
+ }
+
+ if (!callback) {
+ /**
+ * Event fired after the last queued callback is executed.
+ * @event complete
+ */
+ this.fire('complete');
+ }
+
+ return this;
+ },
+
+ /**
+ * Handles the execution of callbacks. Returns a boolean indicating
+ * whether it is appropriate to continue running.
+ *
+ * @method _execute
+ * @param callback {Object} the callback object to execute
+ * @return {Boolean} whether the run loop should continue
+ * @protected
+ */
+ _execute : function (callback) {
+ this._running = callback._running = true;
+
+ callback.iterations--;
+ this.fire(EXECUTE, { callback: callback });
+
+ var cont = this._running && callback.autoContinue;
+
+ this._running = callback._running = false;
+
+ return cont;
+ },
+
+ /**
+ * Schedules the execution of asynchronous callbacks.
+ *
+ * @method _schedule
+ * @param callback {Object} the callback object to execute
+ * @return {Boolean} whether the run loop should continue
+ * @protected
+ */
+ _schedule : function (callback) {
+ this._running = Y.later(callback.timeout, this, function () {
+ if (this._execute(callback)) {
+ this.run();
+ }
+ });
+
+ return false;
+ },
+
+ /**
+ * Determines if the queue is waiting for a callback to complete execution.
+ *
+ * @method isRunning
+ * @return {Boolean} true if queue is waiting for a
+ * from any initiated transactions
+ */
+ isRunning : function () {
+ return !!this._running;
+ },
+
+ /**
+ * Default functionality for the "execute" event. Executes the
+ * callback function
+ *
+ * @method _defExecFn
+ * @param e {Event} the event object
+ * @protected
+ */
+ _defExecFn : function (e) {
+ e.callback();
+ },
+
+ /**
+ * Add any number of callbacks to the end of the queue. Callbacks may be
+ * provided as functions or objects.
+ *
+ * @method add
+ * @param callback* {Function|Object} 0..n callbacks
+ * @return {AsyncQueue} the AsyncQueue instance
+ * @chainable
+ */
+ add : function () {
+ this.fire('add', { callbacks: Y.Array(arguments,0,true) });
+
+ return this;
+ },
+
+ /**
+ * Default functionality for the "add" event. Adds the callbacks
+ * in the event facade to the queue. Callbacks successfully added to the
+ * queue are present in the event's added property in the
+ * after phase.
+ *
+ * @method _defAddFn
+ * @param e {Event} the event object
+ * @protected
+ */
+ _defAddFn : function(e) {
+ var _q = this._q,
+ added = [];
+
+ Y.Array.each(e.callbacks, function (c) {
+ if (isObject(c)) {
+ _q.push(c);
+ added.push(c);
+ }
+ });
+
+ e.added = added;
+ },
+
+ /**
+ * Pause the execution of the queue after the execution of the current
+ * callback completes. If called from code outside of a queued callback,
+ * clears the timeout for the pending callback. Paused queue can be
+ * restarted with q.run()
+ *
+ * @method pause
+ * @return {AsyncQueue} the AsyncQueue instance
+ * @chainable
+ */
+ pause: function () {
+ if (isObject(this._running)) {
+ this._running.cancel();
+ }
+
+ this._running = false;
+
+ return this;
+ },
+
+ /**
+ * Stop and clear the queue after the current execution of the
+ * current callback completes.
+ *
+ * @method stop
+ * @return {AsyncQueue} the AsyncQueue instance
+ * @chainable
+ */
+ stop : function () {
+ this._q = [];
+
+ return this.pause();
+ },
+
+ /**
+ * Returns the current index of a callback. Pass in either the id or
+ * callback function from getCallback.
+ *
+ * @method indexOf
+ * @param callback {String|Function} the callback or its specified id
+ * @return {Number} index of the callback or -1 if not found
+ */
+ indexOf : function (callback) {
+ var i = 0, len = this._q.length, c;
+
+ for (; i < len; ++i) {
+ c = this._q[i];
+ if (c === callback || c.id === callback) {
+ return i;
+ }
+ }
+
+ return -1;
+ },
+
+ /**
+ * Retrieve a callback by its id. Useful to modify the configuration
+ * while the queue is running.
+ *
+ * @method getCallback
+ * @param id {String} the id assigned to the callback
+ * @return {Object} the callback object
+ */
+ getCallback : function (id) {
+ var i = this.indexOf(id);
+
+ return (i > -1) ? this._q[i] : null;
+ },
+
+ /**
+ * Promotes the named callback to the top of the queue. If a callback is
+ * currently executing or looping (via until or iterations), the promotion
+ * is scheduled to occur after the current callback has completed.
+ *
+ * @method promote
+ * @param callback {String|Object} the callback object or a callback's id
+ * @return {AsyncQueue} the AsyncQueue instance
+ * @chainable
+ */
+ promote : function (callback) {
+ var payload = { callback : callback },e;
+
+ if (this.isRunning()) {
+ e = this.after(SHIFT, function () {
+ this.fire(PROMOTE, payload);
+ e.detach();
+ }, this);
+ } else {
+ this.fire(PROMOTE, payload);
+ }
+
+ return this;
+ },
+
+ /**
+ *
Default functionality for the "promote" event. Promotes the
+ * named callback to the head of the queue.
+ *
+ *
The event object will contain a property "callback", which
+ * holds the id of a callback or the callback object itself.
+ *
+ * @method _defPromoteFn
+ * @param e {Event} the custom event
+ * @protected
+ */
+ _defPromoteFn : function (e) {
+ var i = this.indexOf(e.callback),
+ promoted = (i > -1) ? this._q.splice(i,1)[0] : null;
+
+ e.promoted = promoted;
+
+ if (promoted) {
+ this._q.unshift(promoted);
+ }
+ },
+
+ /**
+ * Removes the callback from the queue. If the queue is active, the
+ * removal is scheduled to occur after the current callback has completed.
+ *
+ * @method remove
+ * @param callback {String|Object} the callback object or a callback's id
+ * @return {AsyncQueue} the AsyncQueue instance
+ * @chainable
+ */
+ remove : function (callback) {
+ var payload = { callback : callback },e;
+
+ // Can't return the removed callback because of the deferral until
+ // current callback is complete
+ if (this.isRunning()) {
+ e = this.after(SHIFT, function () {
+ this.fire(REMOVE, payload);
+ e.detach();
+ },this);
+ } else {
+ this.fire(REMOVE, payload);
+ }
+
+ return this;
+ },
+
+ /**
+ *
Default functionality for the "remove" event. Removes the
+ * callback from the queue.
+ *
+ *
The event object will contain a property "callback", which
+ * holds the id of a callback or the callback object itself.
+ *
+ * @method _defRemoveFn
+ * @param e {Event} the custom event
+ * @protected
+ */
+ _defRemoveFn : function (e) {
+ var i = this.indexOf(e.callback);
+
+ e.removed = (i > -1) ? this._q.splice(i,1)[0] : null;
+ },
+
+ /**
+ * Returns the number of callbacks in the queue.
+ *
+ * @method size
+ * @return {Number}
+ */
+ size : function () {
+ // next() flushes callbacks that have met their until() criteria and
+ // therefore shouldn't count since they wouldn't execute anyway.
+ if (!this.isRunning()) {
+ this.next();
+ }
+
+ return this._q.length;
+ }
+});
+
+
+
+}, '3.0.0' ,{requires:['event-custom']});
diff --git a/lib/yui/3.0.0/attribute/attribute-base-debug.js b/lib/yui/3.0.0/attribute/attribute-base-debug.js
new file mode 100644
index 0000000000..d4f503fed5
--- /dev/null
+++ b/lib/yui/3.0.0/attribute/attribute-base-debug.js
@@ -0,0 +1,1079 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('attribute-base', function(Y) {
+
+ /**
+ * The State class maintains state for a collection of named items, with
+ * a varying number of properties defined.
+ *
+ * It avoids the need to create a separate class for the item, and separate instances
+ * of these classes for each item, by storing the state in a 2 level hash table,
+ * improving performance when the number of items is likely to be large.
+ *
+ * @constructor
+ * @class State
+ */
+ Y.State = function() {
+ /**
+ * Hash of attributes
+ * @property data
+ */
+ this.data = {};
+ };
+
+ Y.State.prototype = {
+
+ /**
+ * Adds a property to an item.
+ *
+ * @method add
+ * @param name {String} The name of the item.
+ * @param key {String} The name of the property.
+ * @param val {Any} The value of the property.
+ */
+ add : function(name, key, val) {
+ var d = this.data;
+ d[key] = d[key] || {};
+ d[key][name] = val;
+ },
+
+ /**
+ * Adds multiple properties to an item.
+ *
+ * @method addAll
+ * @param name {String} The name of the item.
+ * @param o {Object} A hash of property/value pairs.
+ */
+ addAll: function(name, o) {
+ var key;
+ for (key in o) {
+ if (o.hasOwnProperty(key)) {
+ this.add(name, key, o[key]);
+ }
+ }
+ },
+
+ /**
+ * Removes a property from an item.
+ *
+ * @method remove
+ * @param name {String} The name of the item.
+ * @param key {String} The property to remove.
+ */
+ remove: function(name, key) {
+ var d = this.data;
+ if (d[key] && (name in d[key])) {
+ delete d[key][name];
+ }
+ },
+
+ /**
+ * Removes multiple properties from an item, or remove the item completely.
+ *
+ * @method removeAll
+ * @param name {String} The name of the item.
+ * @param o {Object|Array} Collection of properties to delete. If not provided, the entire item is removed.
+ */
+ removeAll: function(name, o) {
+ var d = this.data;
+
+ Y.each(o || d, function(v, k) {
+ if(Y.Lang.isString(k)) {
+ this.remove(name, k);
+ } else {
+ this.remove(name, v);
+ }
+ }, this);
+ },
+
+ /**
+ * For a given item, returns the value of the property requested, or undefined if not found.
+ *
+ * @method get
+ * @param name {String} The name of the item
+ * @param key {String} Optional. The property value to retrieve.
+ * @return {Any} The value of the supplied property.
+ */
+ get: function(name, key) {
+ var d = this.data;
+ return (d[key] && name in d[key]) ? d[key][name] : undefined;
+ },
+
+ /**
+ * For the given item, returns a disposable object with all of the
+ * item's property/value pairs.
+ *
+ * @method getAll
+ * @param name {String} The name of the item
+ * @return {Object} An object with property/value pairs for the item.
+ */
+ getAll : function(name) {
+ var d = this.data, o;
+
+ Y.each(d, function(v, k) {
+ if (name in d[k]) {
+ o = o || {};
+ o[k] = v[name];
+ }
+ }, this);
+
+ return o;
+ }
+ };
+ /**
+ * The attribute module provides an augmentable Attribute implementation, which
+ * adds configurable attributes and attribute change events to the class being
+ * augmented. It also provides a State class, which is used internally by Attribute,
+ * but can also be used independently to provide a name/property/value data structure to
+ * store state.
+ *
+ * @module attribute
+ */
+
+ /**
+ * The attribute-base submodule provides core attribute handling support, with everything
+ * aside from complex attribute handling in the provider's constructor.
+ *
+ * @module attribute
+ * @submodule attribute-base
+ */
+ var O = Y.Object,
+ Lang = Y.Lang,
+ EventTarget = Y.EventTarget,
+
+ DOT = ".",
+ CHANGE = "Change",
+
+ // Externally configurable props
+ GETTER = "getter",
+ SETTER = "setter",
+ READ_ONLY = "readOnly",
+ WRITE_ONCE = "writeOnce",
+ VALIDATOR = "validator",
+ VALUE = "value",
+ VALUE_FN = "valueFn",
+ BROADCAST = "broadcast",
+ LAZY_ADD = "lazyAdd",
+ BYPASS_PROXY = "_bypassProxy",
+
+ // Used for internal state management
+ ADDED = "added",
+ INITIALIZING = "initializing",
+ INIT_VALUE = "initValue",
+ PUBLISHED = "published",
+ DEF_VALUE = "defaultValue",
+ LAZY = "lazy",
+ IS_LAZY_ADD = "isLazyAdd",
+
+ INVALID_VALUE,
+ MODIFIABLE = {};
+
+ // Properties which can be changed after the attribute has been added.
+ MODIFIABLE[READ_ONLY] = 1;
+ MODIFIABLE[WRITE_ONCE] = 1;
+ MODIFIABLE[GETTER] = 1;
+ MODIFIABLE[BROADCAST] = 1;
+
+ /**
+ *
+ * Attribute provides configurable attribute support along with attribute change events. It is designed to be
+ * augmented on to a host class, and provides the host with the ability to configure attributes to store and retrieve state,
+ * along with attribute change events.
+ *
+ *
For example, attributes added to the host can be configured:
+ *
+ *
As read only.
+ *
As write once.
+ *
With a setter function, which can be used to manipulate
+ * values passed to Attribute's set method, before they are stored.
+ *
With a getter function, which can be used to manipulate stored values,
+ * before they are returned by Attribute's get method.
+ *
With a validator function, to validate values before they are stored.
+ *
+ *
+ *
See the addAttr method, for the complete set of configuration
+ * options available for attributes
.
+ *
+ *
NOTE: Most implementations will be better off extending the Base class,
+ * instead of augmenting Attribute directly. Base augments Attribute and will handle the initial configuration
+ * of attributes for derived classes, accounting for values passed into the constructor.
+ *
+ * @class Attribute
+ * @uses EventTarget
+ */
+ function Attribute() {
+ Y.log('Attribute constructor called', 'info', 'attribute');
+
+ var host = this, // help compression
+ attrs = this.constructor.ATTRS,
+ Base = Y.Base;
+
+ // Perf tweak - avoid creating event literals if not required.
+ host._ATTR_E_FACADE = {};
+
+ EventTarget.call(host, {emitFacade:true});
+
+ // _conf maintained for backwards compat
+ host._conf = host._state = new Y.State();
+
+ host._stateProxy = host._stateProxy || null;
+ host._requireAddAttr = host._requireAddAttr || false;
+
+ // ATTRS support for Node, which is not Base based
+ if ( attrs && !(Base && host instanceof Base)) {
+ host.addAttrs(this._protectAttrs(attrs));
+ }
+ }
+
+ /**
+ *
The value to return from an attribute setter in order to prevent the set from going through.
+ *
+ *
You can return this value from your setter if you wish to combine validator and setter
+ * functionality into a single setter function, which either returns the massaged value to be stored or
+ * Attribute.INVALID_VALUE to prevent invalid values from being stored.
+ *
+ * @property Attribute.INVALID_VALUE
+ * @type Object
+ * @static
+ * @final
+ */
+ Attribute.INVALID_VALUE = {};
+ INVALID_VALUE = Attribute.INVALID_VALUE;
+
+ /**
+ * The list of properties which can be configured for
+ * each attribute (e.g. setter, getter, writeOnce etc.).
+ *
+ * This property is used internally as a whitelist for faster
+ * Y.mix operations.
+ *
+ * @property Attribute._ATTR_CFG
+ * @type Array
+ * @static
+ * @protected
+ */
+ Attribute._ATTR_CFG = [SETTER, GETTER, VALIDATOR, VALUE, VALUE_FN, WRITE_ONCE, READ_ONLY, LAZY_ADD, BROADCAST, BYPASS_PROXY];
+
+ Attribute.prototype = {
+ /**
+ *
+ * Adds an attribute with the provided configuration to the host object.
+ *
+ *
+ * The config argument object supports the following properties:
+ *
+ *
+ *
+ *
value <Any>
+ *
The initial value to set on the attribute
+ *
+ *
valueFn <Function>
+ *
A function, which will return the initial value to set on the attribute. This is useful
+ * for cases where the attribute configuration is defined statically, but needs to
+ * reference the host instance ("this") to obtain an initial value.
+ * If defined, this precedence over the value property.
+ *
+ *
readOnly <boolean>
+ *
Whether or not the attribute is read only. Attributes having readOnly set to true
+ * cannot be modified by invoking the set method.
+ *
+ *
writeOnce <boolean>
+ *
Whether or not the attribute is "write once". Attributes having writeOnce set to true,
+ * can only have their values set once, be it through the default configuration,
+ * constructor configuration arguments, or by invoking set.
+ *
+ *
setter <Function>
+ *
The setter function used to massage or normalize the value passed to the set method for the attribute.
+ * The value returned by the setter will be the final stored value. Returning
+ * Attribute.INVALID_VALUE, from the setter will prevent
+ * the value from being stored.
+ *
+ *
getter <Function>
+ *
The getter function used to massage or normalize the value returned by the get method for the attribute.
+ * The value returned by the getter function is the value which will be returned to the user when they
+ * invoke get.
+ *
+ *
validator <Function>
+ *
The validator function invoked prior to setting the stored value. Returning
+ * false from the validator function will prevent the value from being stored.
+ *
+ *
broadcast <int>
+ *
If and how attribute change events for this attribute should be broadcast. See CustomEvent's broadcast property for
+ * valid values. By default attribute change events are not broadcast.
+ *
+ *
lazyAdd <boolean>
+ *
Whether or not to delay initialization of the attribute until the first call to get/set it.
+ * This flag can be used to over-ride lazy initialization on a per attribute basis, when adding multiple attributes through
+ * the addAttrs method.
+ *
+ *
+ *
+ *
The setter, getter and validator are invoked with the value and name passed in as the first and second arguments, and with
+ * the context ("this") set to the host object.
+ *
+ *
Configuration properties outside of the list mentioned above are considered private properties used internally by attribute, and are not intended for public use.
+ *
+ * @method addAttr
+ *
+ * @param {String} name The name of the attribute.
+ * @param {Object} config An object with attribute configuration property/value pairs, specifying the configuration for the attribute.
+ *
+ *
+ * NOTE: The configuration object is modified when adding an attribute, so if you need
+ * to protect the original values, you will need to merge the object.
+ *
+ *
+ * @param {boolean} lazy (optional) Whether or not to add this attribute lazily (on the first call to get/set).
+ *
+ * @return {Object} A reference to the host object.
+ *
+ * @chainable
+ */
+ addAttr: function(name, config, lazy) {
+
+ Y.log('Adding attribute: ' + name, 'info', 'attribute');
+
+ var host = this, // help compression
+ state = host._state,
+ value,
+ hasValue;
+
+ lazy = (LAZY_ADD in config) ? config[LAZY_ADD] : lazy;
+
+ if (lazy && !host.attrAdded(name)) {
+ state.add(name, LAZY, config || {});
+ state.add(name, ADDED, true);
+ } else {
+
+ if (host.attrAdded(name) && !state.get(name, IS_LAZY_ADD)) { Y.log('Attribute: ' + name + ' already exists. Cannot add it again without removing it first', 'warn', 'attribute'); }
+
+ if (!host.attrAdded(name) || state.get(name, IS_LAZY_ADD)) {
+
+ config = config || {};
+
+ hasValue = (VALUE in config);
+
+ if (config.readOnly && !hasValue) { Y.log('readOnly attribute: ' + name + ', added without an initial value. Value will be set on initial call to set', 'warn', 'attribute');}
+
+ if(hasValue) {
+ // We'll go through set, don't want to set value in _state directly
+ value = config.value;
+ delete config.value;
+ }
+
+ config.added = true;
+ config.initializing = true;
+
+ state.addAll(name, config);
+
+ if (hasValue) {
+ // Go through set, so that raw values get normalized/validated
+ host.set(name, value);
+ }
+
+ state.remove(name, INITIALIZING);
+ }
+ }
+
+ return host;
+ },
+
+ /**
+ * Checks if the given attribute has been added to the host
+ *
+ * @method attrAdded
+ * @param {String} name The name of the attribute to check.
+ * @return {boolean} true if an attribute with the given name has been added, false if it hasn't. This method will return true for lazily added attributes.
+ */
+ attrAdded: function(name) {
+ return !!this._state.get(name, ADDED);
+ },
+
+ /**
+ * Updates the configuration of an attribute which has already been added.
+ *
+ * The properties which can be modified through this interface are limited
+ * to the following subset of attributes, which can be safely modified
+ * after a value has already been set on the attribute: readOnly, writeOnce,
+ * broadcast and getter.
+ *
+ * @method modifyAttr
+ * @param {String} name The name of the attribute whose configuration is to be updated.
+ * @param {Object} config An object with configuration property/value pairs, specifying the configuration properties to modify.
+ */
+ modifyAttr: function(name, config) {
+ var host = this, // help compression
+ prop, state;
+
+ if (host.attrAdded(name)) {
+
+ if (host._isLazyAttr(name)) {
+ host._addLazyAttr(name);
+ }
+
+ state = host._state;
+ for (prop in config) {
+ if (MODIFIABLE[prop] && config.hasOwnProperty(prop)) {
+ state.add(name, prop, config[prop]);
+
+ // If we reconfigured broadcast, need to republish
+ if (prop === BROADCAST) {
+ state.remove(name, PUBLISHED);
+ }
+ }
+ }
+ }
+
+ if (!host.attrAdded(name)) {Y.log('Attribute modifyAttr:' + name + ' has not been added. Use addAttr to add the attribute', 'warn', 'attribute');}
+ },
+
+ /**
+ * Removes an attribute from the host object
+ *
+ * @method removeAttr
+ * @param {String} name The name of the attribute to be removed.
+ */
+ removeAttr: function(name) {
+ this._state.removeAll(name);
+ },
+
+ /**
+ * Returns the current value of the attribute. If the attribute
+ * has been configured with a 'getter' function, this method will delegate
+ * to the 'getter' to obtain the value of the attribute.
+ *
+ * @method get
+ *
+ * @param {String} name The name of the attribute. If the value of the attribute is an Object,
+ * dot notation can be used to obtain the value of a property of the object (e.g. get("x.y.z"))
+ *
+ * @return {Any} The value of the attribute
+ */
+ get : function(name) {
+ return this._getAttr(name);
+ },
+
+ /**
+ * Checks whether or not the attribute is one which has been
+ * added lazily and still requires initialization.
+ *
+ * @method _isLazyAttr
+ * @private
+ * @param {String} name The name of the attribute
+ * @return {boolean} true if it's a lazily added attribute, false otherwise.
+ */
+ _isLazyAttr: function(name) {
+ return this._state.get(name, LAZY);
+ },
+
+ /**
+ * Finishes initializing an attribute which has been lazily added.
+ *
+ * @method _addLazyAttr
+ * @private
+ * @param {Object} name The name of the attribute
+ */
+ _addLazyAttr: function(name) {
+ var state = this._state,
+ lazyCfg = state.get(name, LAZY);
+
+ state.add(name, IS_LAZY_ADD, true);
+ state.remove(name, LAZY);
+ this.addAttr(name, lazyCfg);
+ },
+
+ /**
+ * Sets the value of an attribute.
+ *
+ * @method set
+ * @chainable
+ *
+ * @param {String} name The name of the attribute. If the
+ * current value of the attribute is an Object, dot notation can be used
+ * to set the value of a property within the object (e.g. set("x.y.z", 5)).
+ *
+ * @param {Any} value The value to set the attribute to.
+ *
+ * @param {Object} opts (Optional) Optional event data to be mixed into
+ * the event facade passed to subscribers of the attribute's change event. This
+ * can be used as a flexible way to identify the source of a call to set, allowing
+ * the developer to distinguish between set called internally by the host, vs.
+ * set called externally by the application developer.
+ *
+ * @return {Object} A reference to the host object.
+ */
+ set : function(name, val, opts) {
+ return this._setAttr(name, val, opts);
+ },
+
+ /**
+ * Resets the attribute (or all attributes) to its initial value, as long as
+ * the attribute is not readOnly, or writeOnce.
+ *
+ * @method reset
+ * @param {String} name Optional. The name of the attribute to reset. If omitted, all attributes are reset.
+ * @return {Object} A reference to the host object.
+ * @chainable
+ */
+ reset : function(name) {
+ var host = this, // help compression
+ added;
+
+ if (name) {
+ if (host._isLazyAttr(name)) {
+ host._addLazyAttr(name);
+ }
+ host.set(name, host._state.get(name, INIT_VALUE));
+ } else {
+ added = host._state.data.added;
+ Y.each(added, function(v, n) {
+ host.reset(n);
+ }, host);
+ }
+ return host;
+ },
+
+ /**
+ * Allows setting of readOnly/writeOnce attributes. See set for argument details.
+ *
+ * @method _set
+ * @protected
+ * @chainable
+ *
+ * @param {String} name The name of the attribute.
+ * @param {Any} val The value to set the attribute to.
+ * @param {Object} opts (Optional) Optional event data to be mixed into
+ * the event facade passed to subscribers of the attribute's change event.
+ * @return {Object} A reference to the host object.
+ */
+ _set : function(name, val, opts) {
+ return this._setAttr(name, val, opts, true);
+ },
+
+ /**
+ * Provides the common implementation for the public get method,
+ * allowing Attribute hosts to over-ride either method.
+ *
+ * See get for argument details.
+ *
+ * @method _getAttr
+ * @protected
+ * @chainable
+ *
+ * @param {String} name The name of the attribute.
+ * @return {Any} The value of the attribute.
+ */
+ _getAttr : function(name) {
+ var host = this, // help compression
+ fullName = name,
+ state = host._state,
+ path,
+ getter,
+ val,
+ cfg;
+
+ if (name.indexOf(DOT) !== -1) {
+ path = name.split(DOT);
+ name = path.shift();
+ }
+
+ // On Demand - Should be rare - handles out of order valueFn references
+ if (host._tCfgs && host._tCfgs[name]) {
+ cfg = {};
+ cfg[name] = host._tCfgs[name];
+ delete host._tCfgs[name];
+ host._addAttrs(cfg, host._tVals);
+ }
+
+ // Lazy Init
+ if (host._isLazyAttr(name)) {
+ host._addLazyAttr(name);
+ }
+
+ val = host._getStateVal(name);
+ getter = state.get(name, GETTER);
+
+ val = (getter) ? getter.call(host, val, fullName) : val;
+ val = (path) ? O.getValue(val, path) : val;
+
+ return val;
+ },
+
+ /**
+ * Provides the common implementation for the public set and protected _set methods.
+ *
+ * See set for argument details.
+ *
+ * @method _setAttr
+ * @protected
+ * @chainable
+ *
+ * @param {String} name The name of the attribute.
+ * @param {Any} value The value to set the attribute to.
+ * @param {Object} opts (Optional) Optional event data to be mixed into
+ * the event facade passed to subscribers of the attribute's change event.
+ * @param {boolean} force If true, allows the caller to set values for
+ * readOnly or writeOnce attributes which have already been set.
+ *
+ * @return {Object} A reference to the host object.
+ */
+ _setAttr : function(name, val, opts, force) {
+ var allowSet = true,
+ state = this._state,
+ stateProxy = this._stateProxy,
+ data = state.data,
+ initialSet,
+ strPath,
+ path,
+ currVal;
+
+ if (name.indexOf(DOT) !== -1) {
+ strPath = name;
+ path = name.split(DOT);
+ name = path.shift();
+ }
+
+ if (this._isLazyAttr(name)) {
+ this._addLazyAttr(name);
+ }
+
+ initialSet = (!data.value || !(name in data.value));
+
+ if (stateProxy && name in stateProxy && !this._state.get(name, BYPASS_PROXY)) {
+ // TODO: Value is always set for proxy. Can we do any better? Maybe take a snapshot as the initial value for the first call to set?
+ initialSet = false;
+ }
+
+ if (this._requireAddAttr && !this.attrAdded(name)) {
+ Y.log('Set attribute:' + name + ', aborted; Attribute is not configured', 'warn', 'attribute');
+ } else {
+
+ if (!initialSet && !force) {
+
+ if (state.get(name, WRITE_ONCE)) {
+ Y.log('Set attribute:' + name + ', aborted; Attribute is writeOnce', 'warn', 'attribute');
+ allowSet = false;
+ }
+
+ if (state.get(name, READ_ONLY)) {
+ Y.log('Set attribute:' + name + ', aborted; Attribute is readOnly', 'warn', 'attribute');
+ allowSet = false;
+ }
+ }
+
+ if (allowSet) {
+ // Don't need currVal if initialSet (might fail in custom getter if it always expects a non-undefined/non-null value)
+ if (!initialSet) {
+ currVal = this.get(name);
+ }
+
+ if (path) {
+ val = O.setValue(Y.clone(currVal), path, val);
+
+ if (val === undefined) {
+ Y.log('Set attribute path:' + strPath + ', aborted; Path is invalid', 'warn', 'attribute');
+ allowSet = false;
+ }
+ }
+
+ if (allowSet) {
+ if (state.get(name, INITIALIZING)) {
+ this._setAttrVal(name, strPath, currVal, val);
+ } else {
+ this._fireAttrChange(name, strPath, currVal, val, opts);
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ /**
+ * Utility method to help setup the event payload and fire the attribute change event.
+ *
+ * @method _fireAttrChange
+ * @private
+ * @param {String} attrName The name of the attribute
+ * @param {String} subAttrName The full path of the property being changed,
+ * if this is a sub-attribute value being change. Otherwise null.
+ * @param {Any} currVal The current value of the attribute
+ * @param {Any} newVal The new value of the attribute
+ * @param {Object} opts Any additional event data to mix into the attribute change event's event facade.
+ */
+ _fireAttrChange : function(attrName, subAttrName, currVal, newVal, opts) {
+ var host = this,
+ eventName = attrName + CHANGE,
+ state = host._state,
+ facade;
+
+ if (!state.get(attrName, PUBLISHED)) {
+ host.publish(eventName, {
+ queuable:false,
+ defaultFn:host._defAttrChangeFn,
+ silent:true,
+ broadcast : state.get(attrName, BROADCAST)
+ });
+ state.add(attrName, PUBLISHED, true);
+ }
+
+ facade = (opts) ? Y.merge(opts) : host._ATTR_E_FACADE;
+
+ facade.type = eventName;
+ facade.attrName = attrName;
+ facade.subAttrName = subAttrName;
+ facade.prevVal = currVal;
+ facade.newVal = newVal;
+
+ host.fire(facade);
+ },
+
+ /**
+ * Default function for attribute change events.
+ *
+ * @private
+ * @method _defAttrChangeFn
+ * @param {EventFacade} e The event object for attribute change events.
+ */
+ _defAttrChangeFn : function(e) {
+ if (!this._setAttrVal(e.attrName, e.subAttrName, e.prevVal, e.newVal)) {
+ Y.log('State not updated and stopImmediatePropagation called for attribute: ' + e.attrName + ' , value:' + e.newVal, 'warn', 'attribute');
+ // Prevent "after" listeners from being invoked since nothing changed.
+ e.stopImmediatePropagation();
+ } else {
+ e.newVal = this._getStateVal(e.attrName);
+ }
+ },
+
+ /**
+ * Gets the stored value for the attribute, from either the
+ * internal state object, or the state proxy if it exits
+ *
+ * @method _getStateVal
+ * @private
+ * @param {String} name The name of the attribute
+ * @return {Any} The stored value of the attribute
+ */
+ _getStateVal : function(name) {
+ var stateProxy = this._stateProxy;
+ return stateProxy && (name in stateProxy) && !this._state.get(name, BYPASS_PROXY) ? stateProxy[name] : this._state.get(name, VALUE);
+ },
+
+ /**
+ * Sets the stored value for the attribute, in either the
+ * internal state object, or the state proxy if it exits
+ *
+ * @method _setStateVal
+ * @private
+ * @param {String} name The name of the attribute
+ * @param {Any} value The value of the attribute
+ */
+ _setStateVal : function(name, value) {
+ var stateProxy = this._stateProxy;
+ if (stateProxy && (name in stateProxy) && !this._state.get(name, BYPASS_PROXY)) {
+ stateProxy[name] = value;
+ } else {
+ this._state.add(name, VALUE, value);
+ }
+ },
+
+ /**
+ * Updates the stored value of the attribute in the privately held State object,
+ * if validation and setter passes.
+ *
+ * @method _setAttrVal
+ * @private
+ * @param {String} attrName The attribute name.
+ * @param {String} subAttrName The sub-attribute name, if setting a sub-attribute property ("x.y.z").
+ * @param {Any} prevVal The currently stored value of the attribute.
+ * @param {Any} newVal The value which is going to be stored.
+ *
+ * @return {booolean} true if the new attribute value was stored, false if not.
+ */
+ _setAttrVal : function(attrName, subAttrName, prevVal, newVal) {
+
+ var host = this,
+ allowSet = true,
+ state = host._state,
+
+ validator = state.get(attrName, VALIDATOR),
+ setter = state.get(attrName, SETTER),
+ initializing = state.get(attrName, INITIALIZING),
+ prevValRaw = this._getStateVal(attrName),
+
+ name = subAttrName || attrName,
+ retVal,
+ valid;
+
+ if (validator) {
+ valid = validator.call(host, newVal, name);
+
+ if (!valid && initializing) {
+ newVal = state.get(attrName, DEF_VALUE);
+ valid = true; // Assume it's valid, for perf.
+ }
+ }
+
+ if (!validator || valid) {
+ if (setter) {
+ retVal = setter.call(host, newVal, name);
+
+ if (retVal === INVALID_VALUE) {
+ Y.log('Attribute: ' + attrName + ', setter returned Attribute.INVALID_VALUE for value:' + newVal, 'warn', 'attribute');
+ allowSet = false;
+ } else if (retVal !== undefined){
+ Y.log('Attribute: ' + attrName + ', raw value: ' + newVal + ' modified by setter to:' + retVal, 'info', 'attribute');
+ newVal = retVal;
+ }
+ }
+
+ if (allowSet) {
+ if(!subAttrName && (newVal === prevValRaw) && !Lang.isObject(newVal)) {
+ Y.log('Attribute: ' + attrName + ', value unchanged:' + newVal, 'warn', 'attribute');
+ allowSet = false;
+ } else {
+ // Store value
+ if (state.get(attrName, INIT_VALUE) === undefined) {
+ state.add(attrName, INIT_VALUE, newVal);
+ }
+ host._setStateVal(attrName, newVal);
+ }
+ }
+
+ } else {
+ Y.log('Attribute:' + attrName + ', Validation failed for value:' + newVal, 'warn', 'attribute');
+ allowSet = false;
+ }
+
+ return allowSet;
+ },
+
+ /**
+ * Sets multiple attribute values.
+ *
+ * @method setAttrs
+ * @param {Object} attrs An object with attributes name/value pairs.
+ * @return {Object} A reference to the host object.
+ * @chainable
+ */
+ setAttrs : function(attrs, opts) {
+ return this._setAttrs(attrs, opts);
+ },
+
+ /**
+ * Implementation behind the public setAttrs method, to set multiple attribute values.
+ *
+ * @method _setAttrs
+ * @protected
+ * @param {Object} attrs An object with attributes name/value pairs.
+ * @return {Object} A reference to the host object.
+ * @chainable
+ */
+ _setAttrs : function(attrs, opts) {
+ for (var attr in attrs) {
+ if ( attrs.hasOwnProperty(attr) ) {
+ this.set(attr, attrs[attr]);
+ }
+ }
+ return this;
+ },
+
+ /**
+ * Gets multiple attribute values.
+ *
+ * @method getAttrs
+ * @param {Array | boolean} attrs Optional. An array of attribute names. If omitted, all attribute values are
+ * returned. If set to true, all attributes modified from their initial values are returned.
+ * @return {Object} An object with attribute name/value pairs.
+ */
+ getAttrs : function(attrs) {
+ return this._getAttrs(attrs);
+ },
+
+ /**
+ * Implementation behind the public getAttrs method, to get multiple attribute values.
+ *
+ * @method _getAttrs
+ * @protected
+ * @param {Array | boolean} attrs Optional. An array of attribute names. If omitted, all attribute values are
+ * returned. If set to true, all attributes modified from their initial values are returned.
+ * @return {Object} An object with attribute name/value pairs.
+ */
+ _getAttrs : function(attrs) {
+ var host = this,
+ o = {},
+ i, l, attr, val,
+ modifiedOnly = (attrs === true);
+
+ attrs = (attrs && !modifiedOnly) ? attrs : O.keys(host._state.data.added);
+
+ for (i = 0, l = attrs.length; i < l; i++) {
+ // Go through get, to honor cloning/normalization
+ attr = attrs[i];
+ val = host.get(attr);
+
+ if (!modifiedOnly || host._getStateVal(attr) != host._state.get(attr, INIT_VALUE)) {
+ o[attr] = host.get(attr);
+ }
+ }
+
+ return o;
+ },
+
+ /**
+ * Configures a group of attributes, and sets initial values.
+ *
+ *
+ * NOTE: This method does not isolate the configuration object by merging/cloning.
+ * The caller is responsible for merging/cloning the configuration object if required.
+ *
+ *
+ * @method addAttrs
+ * @chainable
+ *
+ * @param {Object} cfgs An object with attribute name/configuration pairs.
+ * @param {Object} values An object with attribute name/value pairs, defining the initial values to apply.
+ * Values defined in the cfgs argument will be over-written by values in this argument unless defined as read only.
+ * @param {boolean} lazy Whether or not to delay the intialization of these attributes until the first call to get/set.
+ * Individual attributes can over-ride this behavior by defining a lazyAdd configuration property in their configuration.
+ * See addAttr.
+ *
+ * @return {Object} A reference to the host object.
+ */
+ addAttrs : function(cfgs, values, lazy) {
+ var host = this; // help compression
+ if (cfgs) {
+ host._tCfgs = cfgs;
+ host._tVals = host._normAttrVals(values);
+ host._addAttrs(cfgs, host._tVals, lazy);
+ host._tCfgs = host._tVals = null;
+ }
+
+ return host;
+ },
+
+ /**
+ * Implementation behind the public addAttrs method.
+ *
+ * This method is invoked directly by get if it encounters a scenario
+ * in which an attribute's valueFn attempts to obtain the
+ * value an attribute in the same group of attributes, which has not yet
+ * been added (on demand initialization).
+ *
+ * @method _addAttrs
+ * @private
+ * @param {Object} cfgs An object with attribute name/configuration pairs.
+ * @param {Object} values An object with attribute name/value pairs, defining the initial values to apply.
+ * Values defined in the cfgs argument will be over-written by values in this argument unless defined as read only.
+ * @param {boolean} lazy Whether or not to delay the intialization of these attributes until the first call to get/set.
+ * Individual attributes can over-ride this behavior by defining a lazyAdd configuration property in their configuration.
+ * See addAttr.
+ */
+ _addAttrs : function(cfgs, values, lazy) {
+ var host = this, // help compression
+ attr,
+ attrCfg,
+ value;
+
+ for (attr in cfgs) {
+ if (cfgs.hasOwnProperty(attr)) {
+
+ // Not Merging. Caller is responsible for isolating configs
+ attrCfg = cfgs[attr];
+ attrCfg.defaultValue = attrCfg.value;
+
+ // Handle simple, complex and user values, accounting for read-only
+ value = host._getAttrInitVal(attr, attrCfg, host._tVals);
+
+ if (value !== undefined) {
+ attrCfg.value = value;
+ }
+
+ if (host._tCfgs[attr]) {
+ delete host._tCfgs[attr];
+ }
+
+ host.addAttr(attr, attrCfg, lazy);
+ }
+ }
+ },
+
+ /**
+ * Utility method to protect an attribute configuration
+ * hash, by merging the entire object and the individual
+ * attr config objects.
+ *
+ * @method _protectAttrs
+ * @protected
+ * @param {Object} attrs A hash of attribute to configuration object pairs.
+ * @return {Object} A protected version of the attrs argument.
+ */
+ _protectAttrs : function(attrs) {
+ if (attrs) {
+ attrs = Y.merge(attrs);
+ for (var attr in attrs) {
+ if (attrs.hasOwnProperty(attr)) {
+ attrs[attr] = Y.merge(attrs[attr]);
+ }
+ }
+ }
+ return attrs;
+ },
+
+ /**
+ * Utility method to normalize attribute values. The base implementation
+ * simply merges the hash to protect the original.
+ *
+ * @method _normAttrVals
+ * @param {Object} valueHash An object with attribute name/value pairs
+ *
+ * @return {Object}
+ *
+ * @private
+ */
+ _normAttrVals : function(valueHash) {
+ return (valueHash) ? Y.merge(valueHash) : null;
+ },
+
+ /**
+ * Returns the initial value of the given attribute from
+ * either the default configuration provided, or the
+ * over-ridden value if it exists in the set of initValues
+ * provided and the attribute is not read-only.
+ *
+ * @param {String} attr The name of the attribute
+ * @param {Object} cfg The attribute configuration object
+ * @param {Object} initValues The object with simple and complex attribute name/value pairs returned from _normAttrVals
+ *
+ * @return {Any} The initial value of the attribute.
+ *
+ * @method _getAttrInitVal
+ * @private
+ */
+ _getAttrInitVal : function(attr, cfg, initValues) {
+
+ // init value is provided by the user if it exists, else, provided by the config
+ var val = (!cfg[READ_ONLY] && initValues && initValues.hasOwnProperty(attr)) ?
+ val = initValues[attr] :
+ (cfg[VALUE_FN]) ?
+ cfg[VALUE_FN].call(this) :
+ cfg[VALUE];
+
+ Y.log('initValue for ' + attr + ':' + val, 'info', 'attribute');
+
+ return val;
+ }
+ };
+
+ // Basic prototype augment - no lazy constructor invocation.
+ Y.mix(Attribute, EventTarget, false, null, 1);
+
+ Y.Attribute = Attribute;
+
+
+}, '3.0.0' ,{requires:['event-custom']});
diff --git a/lib/yui/3.0.0/attribute/attribute-base-min.js b/lib/yui/3.0.0/attribute/attribute-base-min.js
new file mode 100644
index 0000000000..70a47dee12
--- /dev/null
+++ b/lib/yui/3.0.0/attribute/attribute-base-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("attribute-base",function(C){C.State=function(){this.data={};};C.State.prototype={add:function(O,Y,e){var c=this.data;c[Y]=c[Y]||{};c[Y][O]=e;},addAll:function(O,c){var Y;for(Y in c){if(c.hasOwnProperty(Y)){this.add(O,Y,c[Y]);}}},remove:function(O,Y){var c=this.data;if(c[Y]&&(O in c[Y])){delete c[Y][O];}},removeAll:function(O,c){var Y=this.data;C.each(c||Y,function(e,d){if(C.Lang.isString(d)){this.remove(O,d);}else{this.remove(O,e);}},this);},get:function(O,Y){var c=this.data;return(c[Y]&&O in c[Y])?c[Y][O]:undefined;},getAll:function(O){var c=this.data,Y;C.each(c,function(e,d){if(O in c[d]){Y=Y||{};Y[d]=e[O];}},this);return Y;}};var K=C.Object,F=C.Lang,L=C.EventTarget,W=".",U="Change",N="getter",M="setter",P="readOnly",X="writeOnce",b="validator",H="value",Q="valueFn",E="broadcast",S="lazyAdd",J="_bypassProxy",a="added",B="initializing",I="initValue",V="published",T="defaultValue",A="lazy",R="isLazyAdd",G,Z={};Z[P]=1;Z[X]=1;Z[N]=1;Z[E]=1;function D(){var c=this,O=this.constructor.ATTRS,Y=C.Base;c._ATTR_E_FACADE={};L.call(c,{emitFacade:true});c._conf=c._state=new C.State();c._stateProxy=c._stateProxy||null;c._requireAddAttr=c._requireAddAttr||false;if(O&&!(Y&&c instanceof Y)){c.addAttrs(this._protectAttrs(O));}}D.INVALID_VALUE={};G=D.INVALID_VALUE;D._ATTR_CFG=[M,N,b,H,Q,X,P,S,E,J];D.prototype={addAttr:function(Y,O,d){var e=this,g=e._state,f,c;d=(S in O)?O[S]:d;if(d&&!e.attrAdded(Y)){g.add(Y,A,O||{});g.add(Y,a,true);}else{if(!e.attrAdded(Y)||g.get(Y,R)){O=O||{};c=(H in O);if(c){f=O.value;delete O.value;}O.added=true;O.initializing=true;g.addAll(Y,O);if(c){e.set(Y,f);}g.remove(Y,B);}}return e;},attrAdded:function(O){return !!this._state.get(O,a);},modifyAttr:function(Y,O){var c=this,e,d;if(c.attrAdded(Y)){if(c._isLazyAttr(Y)){c._addLazyAttr(Y);}d=c._state;for(e in O){if(Z[e]&&O.hasOwnProperty(e)){d.add(Y,e,O[e]);if(e===E){d.remove(Y,V);}}}}},removeAttr:function(O){this._state.removeAll(O);},get:function(O){return this._getAttr(O);},_isLazyAttr:function(O){return this._state.get(O,A);},_addLazyAttr:function(Y){var c=this._state,O=c.get(Y,A);c.add(Y,R,true);c.remove(Y,A);this.addAttr(Y,O);},set:function(O,c,Y){return this._setAttr(O,c,Y);},reset:function(O){var c=this,Y;if(O){if(c._isLazyAttr(O)){c._addLazyAttr(O);}c.set(O,c._state.get(O,I));}else{Y=c._state.data.added;C.each(Y,function(d,e){c.reset(e);},c);}return c;},_set:function(O,c,Y){return this._setAttr(O,c,Y,true);},_getAttr:function(c){var d=this,h=c,e=d._state,f,O,g,Y;if(c.indexOf(W)!==-1){f=c.split(W);c=f.shift();}if(d._tCfgs&&d._tCfgs[c]){Y={};Y[c]=d._tCfgs[c];delete d._tCfgs[c];d._addAttrs(Y,d._tVals);}if(d._isLazyAttr(c)){d._addLazyAttr(c);}g=d._getStateVal(c);O=e.get(c,N);g=(O)?O.call(d,g,h):g;g=(f)?K.getValue(g,f):g;return g;},_setAttr:function(c,f,O,d){var i=true,Y=this._state,g=this._stateProxy,j=Y.data,h,k,l,e;if(c.indexOf(W)!==-1){k=c;l=c.split(W);c=l.shift();}if(this._isLazyAttr(c)){this._addLazyAttr(c);}h=(!j.value||!(c in j.value));if(g&&c in g&&!this._state.get(c,J)){h=false;}if(this._requireAddAttr&&!this.attrAdded(c)){}else{if(!h&&!d){if(Y.get(c,X)){i=false;}if(Y.get(c,P)){i=false;}}if(i){if(!h){e=this.get(c);}if(l){f=K.setValue(C.clone(e),l,f);if(f===undefined){i=false;}}if(i){if(Y.get(c,B)){this._setAttrVal(c,k,e,f);}else{this._fireAttrChange(c,k,e,f,O);}}}}return this;},_fireAttrChange:function(g,f,d,c,O){var i=this,e=g+U,Y=i._state,h;if(!Y.get(g,V)){i.publish(e,{queuable:false,defaultFn:i._defAttrChangeFn,silent:true,broadcast:Y.get(g,E)});Y.add(g,V,true);}h=(O)?C.merge(O):i._ATTR_E_FACADE;h.type=e;h.attrName=g;h.subAttrName=f;h.prevVal=d;h.newVal=c;i.fire(h);},_defAttrChangeFn:function(O){if(!this._setAttrVal(O.attrName,O.subAttrName,O.prevVal,O.newVal)){O.stopImmediatePropagation();}else{O.newVal=this._getStateVal(O.attrName);}},_getStateVal:function(O){var Y=this._stateProxy;return Y&&(O in Y)&&!this._state.get(O,J)?Y[O]:this._state.get(O,H);},_setStateVal:function(O,c){var Y=this._stateProxy;if(Y&&(O in Y)&&!this._state.get(O,J)){Y[O]=c;}else{this._state.add(O,H,c);}},_setAttrVal:function(l,k,h,f){var n=this,i=true,c=n._state,d=c.get(l,b),g=c.get(l,M),j=c.get(l,B),m=this._getStateVal(l),Y=k||l,e,O;if(d){O=d.call(n,f,Y);if(!O&&j){f=c.get(l,T);O=true;}}if(!d||O){if(g){e=g.call(n,f,Y);if(e===G){i=false;}else{if(e!==undefined){f=e;}}}if(i){if(!k&&(f===m)&&!F.isObject(f)){i=false;}else{if(c.get(l,I)===undefined){c.add(l,I,f);}n._setStateVal(l,f);}}}else{i=false;}return i;},setAttrs:function(O,Y){return this._setAttrs(O,Y);},_setAttrs:function(Y,c){for(var O in Y){if(Y.hasOwnProperty(O)){this.set(O,Y[O]);}}return this;},getAttrs:function(O){return this._getAttrs(O);},_getAttrs:function(d){var f=this,h={},e,Y,O,g,c=(d===true);d=(d&&!c)?d:K.keys(f._state.data.added);for(e=0,Y=d.length;e
+ * Attribute provides configurable attribute support along with attribute change events. It is designed to be
+ * augmented on to a host class, and provides the host with the ability to configure attributes to store and retrieve state,
+ * along with attribute change events.
+ *
+ *
For example, attributes added to the host can be configured:
+ *
+ *
As read only.
+ *
As write once.
+ *
With a setter function, which can be used to manipulate
+ * values passed to Attribute's set method, before they are stored.
+ *
With a getter function, which can be used to manipulate stored values,
+ * before they are returned by Attribute's get method.
+ *
With a validator function, to validate values before they are stored.
+ *
+ *
+ *
See the addAttr method, for the complete set of configuration
+ * options available for attributes
.
+ *
+ *
NOTE: Most implementations will be better off extending the Base class,
+ * instead of augmenting Attribute directly. Base augments Attribute and will handle the initial configuration
+ * of attributes for derived classes, accounting for values passed into the constructor.
+ *
+ * @class Attribute
+ * @uses EventTarget
+ */
+ function Attribute() {
+
+ var host = this, // help compression
+ attrs = this.constructor.ATTRS,
+ Base = Y.Base;
+
+ // Perf tweak - avoid creating event literals if not required.
+ host._ATTR_E_FACADE = {};
+
+ EventTarget.call(host, {emitFacade:true});
+
+ // _conf maintained for backwards compat
+ host._conf = host._state = new Y.State();
+
+ host._stateProxy = host._stateProxy || null;
+ host._requireAddAttr = host._requireAddAttr || false;
+
+ // ATTRS support for Node, which is not Base based
+ if ( attrs && !(Base && host instanceof Base)) {
+ host.addAttrs(this._protectAttrs(attrs));
+ }
+ }
+
+ /**
+ *
The value to return from an attribute setter in order to prevent the set from going through.
+ *
+ *
You can return this value from your setter if you wish to combine validator and setter
+ * functionality into a single setter function, which either returns the massaged value to be stored or
+ * Attribute.INVALID_VALUE to prevent invalid values from being stored.
+ *
+ * @property Attribute.INVALID_VALUE
+ * @type Object
+ * @static
+ * @final
+ */
+ Attribute.INVALID_VALUE = {};
+ INVALID_VALUE = Attribute.INVALID_VALUE;
+
+ /**
+ * The list of properties which can be configured for
+ * each attribute (e.g. setter, getter, writeOnce etc.).
+ *
+ * This property is used internally as a whitelist for faster
+ * Y.mix operations.
+ *
+ * @property Attribute._ATTR_CFG
+ * @type Array
+ * @static
+ * @protected
+ */
+ Attribute._ATTR_CFG = [SETTER, GETTER, VALIDATOR, VALUE, VALUE_FN, WRITE_ONCE, READ_ONLY, LAZY_ADD, BROADCAST, BYPASS_PROXY];
+
+ Attribute.prototype = {
+ /**
+ *
+ * Adds an attribute with the provided configuration to the host object.
+ *
+ *
+ * The config argument object supports the following properties:
+ *
+ *
+ *
+ *
value <Any>
+ *
The initial value to set on the attribute
+ *
+ *
valueFn <Function>
+ *
A function, which will return the initial value to set on the attribute. This is useful
+ * for cases where the attribute configuration is defined statically, but needs to
+ * reference the host instance ("this") to obtain an initial value.
+ * If defined, this precedence over the value property.
+ *
+ *
readOnly <boolean>
+ *
Whether or not the attribute is read only. Attributes having readOnly set to true
+ * cannot be modified by invoking the set method.
+ *
+ *
writeOnce <boolean>
+ *
Whether or not the attribute is "write once". Attributes having writeOnce set to true,
+ * can only have their values set once, be it through the default configuration,
+ * constructor configuration arguments, or by invoking set.
+ *
+ *
setter <Function>
+ *
The setter function used to massage or normalize the value passed to the set method for the attribute.
+ * The value returned by the setter will be the final stored value. Returning
+ * Attribute.INVALID_VALUE, from the setter will prevent
+ * the value from being stored.
+ *
+ *
getter <Function>
+ *
The getter function used to massage or normalize the value returned by the get method for the attribute.
+ * The value returned by the getter function is the value which will be returned to the user when they
+ * invoke get.
+ *
+ *
validator <Function>
+ *
The validator function invoked prior to setting the stored value. Returning
+ * false from the validator function will prevent the value from being stored.
+ *
+ *
broadcast <int>
+ *
If and how attribute change events for this attribute should be broadcast. See CustomEvent's broadcast property for
+ * valid values. By default attribute change events are not broadcast.
+ *
+ *
lazyAdd <boolean>
+ *
Whether or not to delay initialization of the attribute until the first call to get/set it.
+ * This flag can be used to over-ride lazy initialization on a per attribute basis, when adding multiple attributes through
+ * the addAttrs method.
+ *
+ *
+ *
+ *
The setter, getter and validator are invoked with the value and name passed in as the first and second arguments, and with
+ * the context ("this") set to the host object.
+ *
+ *
Configuration properties outside of the list mentioned above are considered private properties used internally by attribute, and are not intended for public use.
+ *
+ * @method addAttr
+ *
+ * @param {String} name The name of the attribute.
+ * @param {Object} config An object with attribute configuration property/value pairs, specifying the configuration for the attribute.
+ *
+ *
+ * NOTE: The configuration object is modified when adding an attribute, so if you need
+ * to protect the original values, you will need to merge the object.
+ *
+ *
+ * @param {boolean} lazy (optional) Whether or not to add this attribute lazily (on the first call to get/set).
+ *
+ * @return {Object} A reference to the host object.
+ *
+ * @chainable
+ */
+ addAttr: function(name, config, lazy) {
+
+
+ var host = this, // help compression
+ state = host._state,
+ value,
+ hasValue;
+
+ lazy = (LAZY_ADD in config) ? config[LAZY_ADD] : lazy;
+
+ if (lazy && !host.attrAdded(name)) {
+ state.add(name, LAZY, config || {});
+ state.add(name, ADDED, true);
+ } else {
+
+
+ if (!host.attrAdded(name) || state.get(name, IS_LAZY_ADD)) {
+
+ config = config || {};
+
+ hasValue = (VALUE in config);
+
+
+ if(hasValue) {
+ // We'll go through set, don't want to set value in _state directly
+ value = config.value;
+ delete config.value;
+ }
+
+ config.added = true;
+ config.initializing = true;
+
+ state.addAll(name, config);
+
+ if (hasValue) {
+ // Go through set, so that raw values get normalized/validated
+ host.set(name, value);
+ }
+
+ state.remove(name, INITIALIZING);
+ }
+ }
+
+ return host;
+ },
+
+ /**
+ * Checks if the given attribute has been added to the host
+ *
+ * @method attrAdded
+ * @param {String} name The name of the attribute to check.
+ * @return {boolean} true if an attribute with the given name has been added, false if it hasn't. This method will return true for lazily added attributes.
+ */
+ attrAdded: function(name) {
+ return !!this._state.get(name, ADDED);
+ },
+
+ /**
+ * Updates the configuration of an attribute which has already been added.
+ *
+ * The properties which can be modified through this interface are limited
+ * to the following subset of attributes, which can be safely modified
+ * after a value has already been set on the attribute: readOnly, writeOnce,
+ * broadcast and getter.
+ *
+ * @method modifyAttr
+ * @param {String} name The name of the attribute whose configuration is to be updated.
+ * @param {Object} config An object with configuration property/value pairs, specifying the configuration properties to modify.
+ */
+ modifyAttr: function(name, config) {
+ var host = this, // help compression
+ prop, state;
+
+ if (host.attrAdded(name)) {
+
+ if (host._isLazyAttr(name)) {
+ host._addLazyAttr(name);
+ }
+
+ state = host._state;
+ for (prop in config) {
+ if (MODIFIABLE[prop] && config.hasOwnProperty(prop)) {
+ state.add(name, prop, config[prop]);
+
+ // If we reconfigured broadcast, need to republish
+ if (prop === BROADCAST) {
+ state.remove(name, PUBLISHED);
+ }
+ }
+ }
+ }
+
+ },
+
+ /**
+ * Removes an attribute from the host object
+ *
+ * @method removeAttr
+ * @param {String} name The name of the attribute to be removed.
+ */
+ removeAttr: function(name) {
+ this._state.removeAll(name);
+ },
+
+ /**
+ * Returns the current value of the attribute. If the attribute
+ * has been configured with a 'getter' function, this method will delegate
+ * to the 'getter' to obtain the value of the attribute.
+ *
+ * @method get
+ *
+ * @param {String} name The name of the attribute. If the value of the attribute is an Object,
+ * dot notation can be used to obtain the value of a property of the object (e.g. get("x.y.z"))
+ *
+ * @return {Any} The value of the attribute
+ */
+ get : function(name) {
+ return this._getAttr(name);
+ },
+
+ /**
+ * Checks whether or not the attribute is one which has been
+ * added lazily and still requires initialization.
+ *
+ * @method _isLazyAttr
+ * @private
+ * @param {String} name The name of the attribute
+ * @return {boolean} true if it's a lazily added attribute, false otherwise.
+ */
+ _isLazyAttr: function(name) {
+ return this._state.get(name, LAZY);
+ },
+
+ /**
+ * Finishes initializing an attribute which has been lazily added.
+ *
+ * @method _addLazyAttr
+ * @private
+ * @param {Object} name The name of the attribute
+ */
+ _addLazyAttr: function(name) {
+ var state = this._state,
+ lazyCfg = state.get(name, LAZY);
+
+ state.add(name, IS_LAZY_ADD, true);
+ state.remove(name, LAZY);
+ this.addAttr(name, lazyCfg);
+ },
+
+ /**
+ * Sets the value of an attribute.
+ *
+ * @method set
+ * @chainable
+ *
+ * @param {String} name The name of the attribute. If the
+ * current value of the attribute is an Object, dot notation can be used
+ * to set the value of a property within the object (e.g. set("x.y.z", 5)).
+ *
+ * @param {Any} value The value to set the attribute to.
+ *
+ * @param {Object} opts (Optional) Optional event data to be mixed into
+ * the event facade passed to subscribers of the attribute's change event. This
+ * can be used as a flexible way to identify the source of a call to set, allowing
+ * the developer to distinguish between set called internally by the host, vs.
+ * set called externally by the application developer.
+ *
+ * @return {Object} A reference to the host object.
+ */
+ set : function(name, val, opts) {
+ return this._setAttr(name, val, opts);
+ },
+
+ /**
+ * Resets the attribute (or all attributes) to its initial value, as long as
+ * the attribute is not readOnly, or writeOnce.
+ *
+ * @method reset
+ * @param {String} name Optional. The name of the attribute to reset. If omitted, all attributes are reset.
+ * @return {Object} A reference to the host object.
+ * @chainable
+ */
+ reset : function(name) {
+ var host = this, // help compression
+ added;
+
+ if (name) {
+ if (host._isLazyAttr(name)) {
+ host._addLazyAttr(name);
+ }
+ host.set(name, host._state.get(name, INIT_VALUE));
+ } else {
+ added = host._state.data.added;
+ Y.each(added, function(v, n) {
+ host.reset(n);
+ }, host);
+ }
+ return host;
+ },
+
+ /**
+ * Allows setting of readOnly/writeOnce attributes. See set for argument details.
+ *
+ * @method _set
+ * @protected
+ * @chainable
+ *
+ * @param {String} name The name of the attribute.
+ * @param {Any} val The value to set the attribute to.
+ * @param {Object} opts (Optional) Optional event data to be mixed into
+ * the event facade passed to subscribers of the attribute's change event.
+ * @return {Object} A reference to the host object.
+ */
+ _set : function(name, val, opts) {
+ return this._setAttr(name, val, opts, true);
+ },
+
+ /**
+ * Provides the common implementation for the public get method,
+ * allowing Attribute hosts to over-ride either method.
+ *
+ * See get for argument details.
+ *
+ * @method _getAttr
+ * @protected
+ * @chainable
+ *
+ * @param {String} name The name of the attribute.
+ * @return {Any} The value of the attribute.
+ */
+ _getAttr : function(name) {
+ var host = this, // help compression
+ fullName = name,
+ state = host._state,
+ path,
+ getter,
+ val,
+ cfg;
+
+ if (name.indexOf(DOT) !== -1) {
+ path = name.split(DOT);
+ name = path.shift();
+ }
+
+ // On Demand - Should be rare - handles out of order valueFn references
+ if (host._tCfgs && host._tCfgs[name]) {
+ cfg = {};
+ cfg[name] = host._tCfgs[name];
+ delete host._tCfgs[name];
+ host._addAttrs(cfg, host._tVals);
+ }
+
+ // Lazy Init
+ if (host._isLazyAttr(name)) {
+ host._addLazyAttr(name);
+ }
+
+ val = host._getStateVal(name);
+ getter = state.get(name, GETTER);
+
+ val = (getter) ? getter.call(host, val, fullName) : val;
+ val = (path) ? O.getValue(val, path) : val;
+
+ return val;
+ },
+
+ /**
+ * Provides the common implementation for the public set and protected _set methods.
+ *
+ * See set for argument details.
+ *
+ * @method _setAttr
+ * @protected
+ * @chainable
+ *
+ * @param {String} name The name of the attribute.
+ * @param {Any} value The value to set the attribute to.
+ * @param {Object} opts (Optional) Optional event data to be mixed into
+ * the event facade passed to subscribers of the attribute's change event.
+ * @param {boolean} force If true, allows the caller to set values for
+ * readOnly or writeOnce attributes which have already been set.
+ *
+ * @return {Object} A reference to the host object.
+ */
+ _setAttr : function(name, val, opts, force) {
+ var allowSet = true,
+ state = this._state,
+ stateProxy = this._stateProxy,
+ data = state.data,
+ initialSet,
+ strPath,
+ path,
+ currVal;
+
+ if (name.indexOf(DOT) !== -1) {
+ strPath = name;
+ path = name.split(DOT);
+ name = path.shift();
+ }
+
+ if (this._isLazyAttr(name)) {
+ this._addLazyAttr(name);
+ }
+
+ initialSet = (!data.value || !(name in data.value));
+
+ if (stateProxy && name in stateProxy && !this._state.get(name, BYPASS_PROXY)) {
+ // TODO: Value is always set for proxy. Can we do any better? Maybe take a snapshot as the initial value for the first call to set?
+ initialSet = false;
+ }
+
+ if (this._requireAddAttr && !this.attrAdded(name)) {
+ } else {
+
+ if (!initialSet && !force) {
+
+ if (state.get(name, WRITE_ONCE)) {
+ allowSet = false;
+ }
+
+ if (state.get(name, READ_ONLY)) {
+ allowSet = false;
+ }
+ }
+
+ if (allowSet) {
+ // Don't need currVal if initialSet (might fail in custom getter if it always expects a non-undefined/non-null value)
+ if (!initialSet) {
+ currVal = this.get(name);
+ }
+
+ if (path) {
+ val = O.setValue(Y.clone(currVal), path, val);
+
+ if (val === undefined) {
+ allowSet = false;
+ }
+ }
+
+ if (allowSet) {
+ if (state.get(name, INITIALIZING)) {
+ this._setAttrVal(name, strPath, currVal, val);
+ } else {
+ this._fireAttrChange(name, strPath, currVal, val, opts);
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ /**
+ * Utility method to help setup the event payload and fire the attribute change event.
+ *
+ * @method _fireAttrChange
+ * @private
+ * @param {String} attrName The name of the attribute
+ * @param {String} subAttrName The full path of the property being changed,
+ * if this is a sub-attribute value being change. Otherwise null.
+ * @param {Any} currVal The current value of the attribute
+ * @param {Any} newVal The new value of the attribute
+ * @param {Object} opts Any additional event data to mix into the attribute change event's event facade.
+ */
+ _fireAttrChange : function(attrName, subAttrName, currVal, newVal, opts) {
+ var host = this,
+ eventName = attrName + CHANGE,
+ state = host._state,
+ facade;
+
+ if (!state.get(attrName, PUBLISHED)) {
+ host.publish(eventName, {
+ queuable:false,
+ defaultFn:host._defAttrChangeFn,
+ silent:true,
+ broadcast : state.get(attrName, BROADCAST)
+ });
+ state.add(attrName, PUBLISHED, true);
+ }
+
+ facade = (opts) ? Y.merge(opts) : host._ATTR_E_FACADE;
+
+ facade.type = eventName;
+ facade.attrName = attrName;
+ facade.subAttrName = subAttrName;
+ facade.prevVal = currVal;
+ facade.newVal = newVal;
+
+ host.fire(facade);
+ },
+
+ /**
+ * Default function for attribute change events.
+ *
+ * @private
+ * @method _defAttrChangeFn
+ * @param {EventFacade} e The event object for attribute change events.
+ */
+ _defAttrChangeFn : function(e) {
+ if (!this._setAttrVal(e.attrName, e.subAttrName, e.prevVal, e.newVal)) {
+ // Prevent "after" listeners from being invoked since nothing changed.
+ e.stopImmediatePropagation();
+ } else {
+ e.newVal = this._getStateVal(e.attrName);
+ }
+ },
+
+ /**
+ * Gets the stored value for the attribute, from either the
+ * internal state object, or the state proxy if it exits
+ *
+ * @method _getStateVal
+ * @private
+ * @param {String} name The name of the attribute
+ * @return {Any} The stored value of the attribute
+ */
+ _getStateVal : function(name) {
+ var stateProxy = this._stateProxy;
+ return stateProxy && (name in stateProxy) && !this._state.get(name, BYPASS_PROXY) ? stateProxy[name] : this._state.get(name, VALUE);
+ },
+
+ /**
+ * Sets the stored value for the attribute, in either the
+ * internal state object, or the state proxy if it exits
+ *
+ * @method _setStateVal
+ * @private
+ * @param {String} name The name of the attribute
+ * @param {Any} value The value of the attribute
+ */
+ _setStateVal : function(name, value) {
+ var stateProxy = this._stateProxy;
+ if (stateProxy && (name in stateProxy) && !this._state.get(name, BYPASS_PROXY)) {
+ stateProxy[name] = value;
+ } else {
+ this._state.add(name, VALUE, value);
+ }
+ },
+
+ /**
+ * Updates the stored value of the attribute in the privately held State object,
+ * if validation and setter passes.
+ *
+ * @method _setAttrVal
+ * @private
+ * @param {String} attrName The attribute name.
+ * @param {String} subAttrName The sub-attribute name, if setting a sub-attribute property ("x.y.z").
+ * @param {Any} prevVal The currently stored value of the attribute.
+ * @param {Any} newVal The value which is going to be stored.
+ *
+ * @return {booolean} true if the new attribute value was stored, false if not.
+ */
+ _setAttrVal : function(attrName, subAttrName, prevVal, newVal) {
+
+ var host = this,
+ allowSet = true,
+ state = host._state,
+
+ validator = state.get(attrName, VALIDATOR),
+ setter = state.get(attrName, SETTER),
+ initializing = state.get(attrName, INITIALIZING),
+ prevValRaw = this._getStateVal(attrName),
+
+ name = subAttrName || attrName,
+ retVal,
+ valid;
+
+ if (validator) {
+ valid = validator.call(host, newVal, name);
+
+ if (!valid && initializing) {
+ newVal = state.get(attrName, DEF_VALUE);
+ valid = true; // Assume it's valid, for perf.
+ }
+ }
+
+ if (!validator || valid) {
+ if (setter) {
+ retVal = setter.call(host, newVal, name);
+
+ if (retVal === INVALID_VALUE) {
+ allowSet = false;
+ } else if (retVal !== undefined){
+ newVal = retVal;
+ }
+ }
+
+ if (allowSet) {
+ if(!subAttrName && (newVal === prevValRaw) && !Lang.isObject(newVal)) {
+ allowSet = false;
+ } else {
+ // Store value
+ if (state.get(attrName, INIT_VALUE) === undefined) {
+ state.add(attrName, INIT_VALUE, newVal);
+ }
+ host._setStateVal(attrName, newVal);
+ }
+ }
+
+ } else {
+ allowSet = false;
+ }
+
+ return allowSet;
+ },
+
+ /**
+ * Sets multiple attribute values.
+ *
+ * @method setAttrs
+ * @param {Object} attrs An object with attributes name/value pairs.
+ * @return {Object} A reference to the host object.
+ * @chainable
+ */
+ setAttrs : function(attrs, opts) {
+ return this._setAttrs(attrs, opts);
+ },
+
+ /**
+ * Implementation behind the public setAttrs method, to set multiple attribute values.
+ *
+ * @method _setAttrs
+ * @protected
+ * @param {Object} attrs An object with attributes name/value pairs.
+ * @return {Object} A reference to the host object.
+ * @chainable
+ */
+ _setAttrs : function(attrs, opts) {
+ for (var attr in attrs) {
+ if ( attrs.hasOwnProperty(attr) ) {
+ this.set(attr, attrs[attr]);
+ }
+ }
+ return this;
+ },
+
+ /**
+ * Gets multiple attribute values.
+ *
+ * @method getAttrs
+ * @param {Array | boolean} attrs Optional. An array of attribute names. If omitted, all attribute values are
+ * returned. If set to true, all attributes modified from their initial values are returned.
+ * @return {Object} An object with attribute name/value pairs.
+ */
+ getAttrs : function(attrs) {
+ return this._getAttrs(attrs);
+ },
+
+ /**
+ * Implementation behind the public getAttrs method, to get multiple attribute values.
+ *
+ * @method _getAttrs
+ * @protected
+ * @param {Array | boolean} attrs Optional. An array of attribute names. If omitted, all attribute values are
+ * returned. If set to true, all attributes modified from their initial values are returned.
+ * @return {Object} An object with attribute name/value pairs.
+ */
+ _getAttrs : function(attrs) {
+ var host = this,
+ o = {},
+ i, l, attr, val,
+ modifiedOnly = (attrs === true);
+
+ attrs = (attrs && !modifiedOnly) ? attrs : O.keys(host._state.data.added);
+
+ for (i = 0, l = attrs.length; i < l; i++) {
+ // Go through get, to honor cloning/normalization
+ attr = attrs[i];
+ val = host.get(attr);
+
+ if (!modifiedOnly || host._getStateVal(attr) != host._state.get(attr, INIT_VALUE)) {
+ o[attr] = host.get(attr);
+ }
+ }
+
+ return o;
+ },
+
+ /**
+ * Configures a group of attributes, and sets initial values.
+ *
+ *
+ * NOTE: This method does not isolate the configuration object by merging/cloning.
+ * The caller is responsible for merging/cloning the configuration object if required.
+ *
+ *
+ * @method addAttrs
+ * @chainable
+ *
+ * @param {Object} cfgs An object with attribute name/configuration pairs.
+ * @param {Object} values An object with attribute name/value pairs, defining the initial values to apply.
+ * Values defined in the cfgs argument will be over-written by values in this argument unless defined as read only.
+ * @param {boolean} lazy Whether or not to delay the intialization of these attributes until the first call to get/set.
+ * Individual attributes can over-ride this behavior by defining a lazyAdd configuration property in their configuration.
+ * See addAttr.
+ *
+ * @return {Object} A reference to the host object.
+ */
+ addAttrs : function(cfgs, values, lazy) {
+ var host = this; // help compression
+ if (cfgs) {
+ host._tCfgs = cfgs;
+ host._tVals = host._normAttrVals(values);
+ host._addAttrs(cfgs, host._tVals, lazy);
+ host._tCfgs = host._tVals = null;
+ }
+
+ return host;
+ },
+
+ /**
+ * Implementation behind the public addAttrs method.
+ *
+ * This method is invoked directly by get if it encounters a scenario
+ * in which an attribute's valueFn attempts to obtain the
+ * value an attribute in the same group of attributes, which has not yet
+ * been added (on demand initialization).
+ *
+ * @method _addAttrs
+ * @private
+ * @param {Object} cfgs An object with attribute name/configuration pairs.
+ * @param {Object} values An object with attribute name/value pairs, defining the initial values to apply.
+ * Values defined in the cfgs argument will be over-written by values in this argument unless defined as read only.
+ * @param {boolean} lazy Whether or not to delay the intialization of these attributes until the first call to get/set.
+ * Individual attributes can over-ride this behavior by defining a lazyAdd configuration property in their configuration.
+ * See addAttr.
+ */
+ _addAttrs : function(cfgs, values, lazy) {
+ var host = this, // help compression
+ attr,
+ attrCfg,
+ value;
+
+ for (attr in cfgs) {
+ if (cfgs.hasOwnProperty(attr)) {
+
+ // Not Merging. Caller is responsible for isolating configs
+ attrCfg = cfgs[attr];
+ attrCfg.defaultValue = attrCfg.value;
+
+ // Handle simple, complex and user values, accounting for read-only
+ value = host._getAttrInitVal(attr, attrCfg, host._tVals);
+
+ if (value !== undefined) {
+ attrCfg.value = value;
+ }
+
+ if (host._tCfgs[attr]) {
+ delete host._tCfgs[attr];
+ }
+
+ host.addAttr(attr, attrCfg, lazy);
+ }
+ }
+ },
+
+ /**
+ * Utility method to protect an attribute configuration
+ * hash, by merging the entire object and the individual
+ * attr config objects.
+ *
+ * @method _protectAttrs
+ * @protected
+ * @param {Object} attrs A hash of attribute to configuration object pairs.
+ * @return {Object} A protected version of the attrs argument.
+ */
+ _protectAttrs : function(attrs) {
+ if (attrs) {
+ attrs = Y.merge(attrs);
+ for (var attr in attrs) {
+ if (attrs.hasOwnProperty(attr)) {
+ attrs[attr] = Y.merge(attrs[attr]);
+ }
+ }
+ }
+ return attrs;
+ },
+
+ /**
+ * Utility method to normalize attribute values. The base implementation
+ * simply merges the hash to protect the original.
+ *
+ * @method _normAttrVals
+ * @param {Object} valueHash An object with attribute name/value pairs
+ *
+ * @return {Object}
+ *
+ * @private
+ */
+ _normAttrVals : function(valueHash) {
+ return (valueHash) ? Y.merge(valueHash) : null;
+ },
+
+ /**
+ * Returns the initial value of the given attribute from
+ * either the default configuration provided, or the
+ * over-ridden value if it exists in the set of initValues
+ * provided and the attribute is not read-only.
+ *
+ * @param {String} attr The name of the attribute
+ * @param {Object} cfg The attribute configuration object
+ * @param {Object} initValues The object with simple and complex attribute name/value pairs returned from _normAttrVals
+ *
+ * @return {Any} The initial value of the attribute.
+ *
+ * @method _getAttrInitVal
+ * @private
+ */
+ _getAttrInitVal : function(attr, cfg, initValues) {
+
+ // init value is provided by the user if it exists, else, provided by the config
+ var val = (!cfg[READ_ONLY] && initValues && initValues.hasOwnProperty(attr)) ?
+ val = initValues[attr] :
+ (cfg[VALUE_FN]) ?
+ cfg[VALUE_FN].call(this) :
+ cfg[VALUE];
+
+
+ return val;
+ }
+ };
+
+ // Basic prototype augment - no lazy constructor invocation.
+ Y.mix(Attribute, EventTarget, false, null, 1);
+
+ Y.Attribute = Attribute;
+
+
+}, '3.0.0' ,{requires:['event-custom']});
diff --git a/lib/yui/3.0.0/attribute/attribute-complex-debug.js b/lib/yui/3.0.0/attribute/attribute-complex-debug.js
new file mode 100644
index 0000000000..2299c87f1c
--- /dev/null
+++ b/lib/yui/3.0.0/attribute/attribute-complex-debug.js
@@ -0,0 +1,120 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('attribute-complex', function(Y) {
+
+ /**
+ * Adds support for attribute providers to handle complex attributes in the constructor
+ *
+ * @module attribute
+ * @submodule attribute-complex
+ * @for Attribute
+ */
+
+ var O = Y.Object,
+ DOT = ".";
+
+ Y.Attribute.Complex = function() {};
+ Y.Attribute.Complex.prototype = {
+
+ /**
+ * Utility method to split out simple attribute name/value pairs ("x")
+ * from complex attribute name/value pairs ("x.y.z"), so that complex
+ * attributes can be keyed by the top level attribute name.
+ *
+ * @method _normAttrVals
+ * @param {Object} valueHash An object with attribute name/value pairs
+ *
+ * @return {Object} An object literal with 2 properties - "simple" and "complex",
+ * containing simple and complex attribute values respectively keyed
+ * by the top level attribute name, or null, if valueHash is falsey.
+ *
+ * @private
+ */
+ _normAttrVals : function(valueHash) {
+ var vals = {},
+ subvals = {},
+ path,
+ attr,
+ v, k;
+
+ if (valueHash) {
+ for (k in valueHash) {
+ if (valueHash.hasOwnProperty(k)) {
+ if (k.indexOf(DOT) !== -1) {
+ path = k.split(DOT);
+ attr = path.shift();
+ v = subvals[attr] = subvals[attr] || [];
+ v[v.length] = {
+ path : path,
+ value: valueHash[k]
+ };
+ } else {
+ vals[k] = valueHash[k];
+ }
+ }
+ }
+ return { simple:vals, complex:subvals };
+ } else {
+ return null;
+ }
+ },
+
+ /**
+ * Returns the initial value of the given attribute from
+ * either the default configuration provided, or the
+ * over-ridden value if it exists in the set of initValues
+ * provided and the attribute is not read-only.
+ *
+ * @param {String} attr The name of the attribute
+ * @param {Object} cfg The attribute configuration object
+ * @param {Object} initValues The object with simple and complex attribute name/value pairs returned from _normAttrVals
+ *
+ * @return {Any} The initial value of the attribute.
+ *
+ * @method _getAttrInitVal
+ * @private
+ */
+ _getAttrInitVal : function(attr, cfg, initValues) {
+
+ var val = (cfg.valueFn) ? cfg.valueFn.call(this) : cfg.value,
+ simple,
+ complex,
+ i,
+ l,
+ path,
+ subval,
+ subvals;
+
+ if (!cfg.readOnly && initValues) {
+
+ // Simple Attributes
+ simple = initValues.simple;
+ if (simple && simple.hasOwnProperty(attr)) {
+ val = simple[attr];
+ }
+
+ // Complex Attributes (complex values applied, after simple, incase both are set)
+ complex = initValues.complex;
+ if (complex && complex.hasOwnProperty(attr)) {
+ subvals = complex[attr];
+ for (i = 0, l = subvals.length; i < l; ++i) {
+ path = subvals[i].path;
+ subval = subvals[i].value;
+ O.setValue(val, path, subval);
+ }
+ }
+ }
+
+ return val;
+ }
+ };
+
+ Y.mix(Y.Attribute, Y.Attribute.Complex, true, null, 1);
+
+
+}, '3.0.0' ,{requires:['attribute-base']});
diff --git a/lib/yui/3.0.0/attribute/attribute-complex-min.js b/lib/yui/3.0.0/attribute/attribute-complex-min.js
new file mode 100644
index 0000000000..3e07463646
--- /dev/null
+++ b/lib/yui/3.0.0/attribute/attribute-complex-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("attribute-complex",function(B){var A=B.Object,C=".";B.Attribute.Complex=function(){};B.Attribute.Complex.prototype={_normAttrVals:function(G){var I={},H={},J,D,F,E;if(G){for(E in G){if(G.hasOwnProperty(E)){if(E.indexOf(C)!==-1){J=E.split(C);D=J.shift();F=H[D]=H[D]||[];F[F.length]={path:J,value:G[E]};}else{I[E]=G[E];}}}return{simple:I,complex:H};}else{return null;}},_getAttrInitVal:function(K,I,M){var E=(I.valueFn)?I.valueFn.call(this):I.value,D,F,H,G,N,L,J;if(!I.readOnly&&M){D=M.simple;if(D&&D.hasOwnProperty(K)){E=D[K];}F=M.complex;if(F&&F.hasOwnProperty(K)){J=F[K];for(H=0,G=J.length;H
+ * Attribute provides configurable attribute support along with attribute change events. It is designed to be
+ * augmented on to a host class, and provides the host with the ability to configure attributes to store and retrieve state,
+ * along with attribute change events.
+ *
+ *
For example, attributes added to the host can be configured:
+ *
+ *
As read only.
+ *
As write once.
+ *
With a setter function, which can be used to manipulate
+ * values passed to Attribute's set method, before they are stored.
+ *
With a getter function, which can be used to manipulate stored values,
+ * before they are returned by Attribute's get method.
+ *
With a validator function, to validate values before they are stored.
+ *
+ *
+ *
See the addAttr method, for the complete set of configuration
+ * options available for attributes
.
+ *
+ *
NOTE: Most implementations will be better off extending the Base class,
+ * instead of augmenting Attribute directly. Base augments Attribute and will handle the initial configuration
+ * of attributes for derived classes, accounting for values passed into the constructor.
+ *
+ * @class Attribute
+ * @uses EventTarget
+ */
+ function Attribute() {
+ Y.log('Attribute constructor called', 'info', 'attribute');
+
+ var host = this, // help compression
+ attrs = this.constructor.ATTRS,
+ Base = Y.Base;
+
+ // Perf tweak - avoid creating event literals if not required.
+ host._ATTR_E_FACADE = {};
+
+ EventTarget.call(host, {emitFacade:true});
+
+ // _conf maintained for backwards compat
+ host._conf = host._state = new Y.State();
+
+ host._stateProxy = host._stateProxy || null;
+ host._requireAddAttr = host._requireAddAttr || false;
+
+ // ATTRS support for Node, which is not Base based
+ if ( attrs && !(Base && host instanceof Base)) {
+ host.addAttrs(this._protectAttrs(attrs));
+ }
+ }
+
+ /**
+ *
The value to return from an attribute setter in order to prevent the set from going through.
+ *
+ *
You can return this value from your setter if you wish to combine validator and setter
+ * functionality into a single setter function, which either returns the massaged value to be stored or
+ * Attribute.INVALID_VALUE to prevent invalid values from being stored.
+ *
+ * @property Attribute.INVALID_VALUE
+ * @type Object
+ * @static
+ * @final
+ */
+ Attribute.INVALID_VALUE = {};
+ INVALID_VALUE = Attribute.INVALID_VALUE;
+
+ /**
+ * The list of properties which can be configured for
+ * each attribute (e.g. setter, getter, writeOnce etc.).
+ *
+ * This property is used internally as a whitelist for faster
+ * Y.mix operations.
+ *
+ * @property Attribute._ATTR_CFG
+ * @type Array
+ * @static
+ * @protected
+ */
+ Attribute._ATTR_CFG = [SETTER, GETTER, VALIDATOR, VALUE, VALUE_FN, WRITE_ONCE, READ_ONLY, LAZY_ADD, BROADCAST, BYPASS_PROXY];
+
+ Attribute.prototype = {
+ /**
+ *
+ * Adds an attribute with the provided configuration to the host object.
+ *
+ *
+ * The config argument object supports the following properties:
+ *
+ *
+ *
+ *
value <Any>
+ *
The initial value to set on the attribute
+ *
+ *
valueFn <Function>
+ *
A function, which will return the initial value to set on the attribute. This is useful
+ * for cases where the attribute configuration is defined statically, but needs to
+ * reference the host instance ("this") to obtain an initial value.
+ * If defined, this precedence over the value property.
+ *
+ *
readOnly <boolean>
+ *
Whether or not the attribute is read only. Attributes having readOnly set to true
+ * cannot be modified by invoking the set method.
+ *
+ *
writeOnce <boolean>
+ *
Whether or not the attribute is "write once". Attributes having writeOnce set to true,
+ * can only have their values set once, be it through the default configuration,
+ * constructor configuration arguments, or by invoking set.
+ *
+ *
setter <Function>
+ *
The setter function used to massage or normalize the value passed to the set method for the attribute.
+ * The value returned by the setter will be the final stored value. Returning
+ * Attribute.INVALID_VALUE, from the setter will prevent
+ * the value from being stored.
+ *
+ *
getter <Function>
+ *
The getter function used to massage or normalize the value returned by the get method for the attribute.
+ * The value returned by the getter function is the value which will be returned to the user when they
+ * invoke get.
+ *
+ *
validator <Function>
+ *
The validator function invoked prior to setting the stored value. Returning
+ * false from the validator function will prevent the value from being stored.
+ *
+ *
broadcast <int>
+ *
If and how attribute change events for this attribute should be broadcast. See CustomEvent's broadcast property for
+ * valid values. By default attribute change events are not broadcast.
+ *
+ *
lazyAdd <boolean>
+ *
Whether or not to delay initialization of the attribute until the first call to get/set it.
+ * This flag can be used to over-ride lazy initialization on a per attribute basis, when adding multiple attributes through
+ * the addAttrs method.
+ *
+ *
+ *
+ *
The setter, getter and validator are invoked with the value and name passed in as the first and second arguments, and with
+ * the context ("this") set to the host object.
+ *
+ *
Configuration properties outside of the list mentioned above are considered private properties used internally by attribute, and are not intended for public use.
+ *
+ * @method addAttr
+ *
+ * @param {String} name The name of the attribute.
+ * @param {Object} config An object with attribute configuration property/value pairs, specifying the configuration for the attribute.
+ *
+ *
+ * NOTE: The configuration object is modified when adding an attribute, so if you need
+ * to protect the original values, you will need to merge the object.
+ *
+ *
+ * @param {boolean} lazy (optional) Whether or not to add this attribute lazily (on the first call to get/set).
+ *
+ * @return {Object} A reference to the host object.
+ *
+ * @chainable
+ */
+ addAttr: function(name, config, lazy) {
+
+ Y.log('Adding attribute: ' + name, 'info', 'attribute');
+
+ var host = this, // help compression
+ state = host._state,
+ value,
+ hasValue;
+
+ lazy = (LAZY_ADD in config) ? config[LAZY_ADD] : lazy;
+
+ if (lazy && !host.attrAdded(name)) {
+ state.add(name, LAZY, config || {});
+ state.add(name, ADDED, true);
+ } else {
+
+ if (host.attrAdded(name) && !state.get(name, IS_LAZY_ADD)) { Y.log('Attribute: ' + name + ' already exists. Cannot add it again without removing it first', 'warn', 'attribute'); }
+
+ if (!host.attrAdded(name) || state.get(name, IS_LAZY_ADD)) {
+
+ config = config || {};
+
+ hasValue = (VALUE in config);
+
+ if (config.readOnly && !hasValue) { Y.log('readOnly attribute: ' + name + ', added without an initial value. Value will be set on initial call to set', 'warn', 'attribute');}
+
+ if(hasValue) {
+ // We'll go through set, don't want to set value in _state directly
+ value = config.value;
+ delete config.value;
+ }
+
+ config.added = true;
+ config.initializing = true;
+
+ state.addAll(name, config);
+
+ if (hasValue) {
+ // Go through set, so that raw values get normalized/validated
+ host.set(name, value);
+ }
+
+ state.remove(name, INITIALIZING);
+ }
+ }
+
+ return host;
+ },
+
+ /**
+ * Checks if the given attribute has been added to the host
+ *
+ * @method attrAdded
+ * @param {String} name The name of the attribute to check.
+ * @return {boolean} true if an attribute with the given name has been added, false if it hasn't. This method will return true for lazily added attributes.
+ */
+ attrAdded: function(name) {
+ return !!this._state.get(name, ADDED);
+ },
+
+ /**
+ * Updates the configuration of an attribute which has already been added.
+ *
+ * The properties which can be modified through this interface are limited
+ * to the following subset of attributes, which can be safely modified
+ * after a value has already been set on the attribute: readOnly, writeOnce,
+ * broadcast and getter.
+ *
+ * @method modifyAttr
+ * @param {String} name The name of the attribute whose configuration is to be updated.
+ * @param {Object} config An object with configuration property/value pairs, specifying the configuration properties to modify.
+ */
+ modifyAttr: function(name, config) {
+ var host = this, // help compression
+ prop, state;
+
+ if (host.attrAdded(name)) {
+
+ if (host._isLazyAttr(name)) {
+ host._addLazyAttr(name);
+ }
+
+ state = host._state;
+ for (prop in config) {
+ if (MODIFIABLE[prop] && config.hasOwnProperty(prop)) {
+ state.add(name, prop, config[prop]);
+
+ // If we reconfigured broadcast, need to republish
+ if (prop === BROADCAST) {
+ state.remove(name, PUBLISHED);
+ }
+ }
+ }
+ }
+
+ if (!host.attrAdded(name)) {Y.log('Attribute modifyAttr:' + name + ' has not been added. Use addAttr to add the attribute', 'warn', 'attribute');}
+ },
+
+ /**
+ * Removes an attribute from the host object
+ *
+ * @method removeAttr
+ * @param {String} name The name of the attribute to be removed.
+ */
+ removeAttr: function(name) {
+ this._state.removeAll(name);
+ },
+
+ /**
+ * Returns the current value of the attribute. If the attribute
+ * has been configured with a 'getter' function, this method will delegate
+ * to the 'getter' to obtain the value of the attribute.
+ *
+ * @method get
+ *
+ * @param {String} name The name of the attribute. If the value of the attribute is an Object,
+ * dot notation can be used to obtain the value of a property of the object (e.g. get("x.y.z"))
+ *
+ * @return {Any} The value of the attribute
+ */
+ get : function(name) {
+ return this._getAttr(name);
+ },
+
+ /**
+ * Checks whether or not the attribute is one which has been
+ * added lazily and still requires initialization.
+ *
+ * @method _isLazyAttr
+ * @private
+ * @param {String} name The name of the attribute
+ * @return {boolean} true if it's a lazily added attribute, false otherwise.
+ */
+ _isLazyAttr: function(name) {
+ return this._state.get(name, LAZY);
+ },
+
+ /**
+ * Finishes initializing an attribute which has been lazily added.
+ *
+ * @method _addLazyAttr
+ * @private
+ * @param {Object} name The name of the attribute
+ */
+ _addLazyAttr: function(name) {
+ var state = this._state,
+ lazyCfg = state.get(name, LAZY);
+
+ state.add(name, IS_LAZY_ADD, true);
+ state.remove(name, LAZY);
+ this.addAttr(name, lazyCfg);
+ },
+
+ /**
+ * Sets the value of an attribute.
+ *
+ * @method set
+ * @chainable
+ *
+ * @param {String} name The name of the attribute. If the
+ * current value of the attribute is an Object, dot notation can be used
+ * to set the value of a property within the object (e.g. set("x.y.z", 5)).
+ *
+ * @param {Any} value The value to set the attribute to.
+ *
+ * @param {Object} opts (Optional) Optional event data to be mixed into
+ * the event facade passed to subscribers of the attribute's change event. This
+ * can be used as a flexible way to identify the source of a call to set, allowing
+ * the developer to distinguish between set called internally by the host, vs.
+ * set called externally by the application developer.
+ *
+ * @return {Object} A reference to the host object.
+ */
+ set : function(name, val, opts) {
+ return this._setAttr(name, val, opts);
+ },
+
+ /**
+ * Resets the attribute (or all attributes) to its initial value, as long as
+ * the attribute is not readOnly, or writeOnce.
+ *
+ * @method reset
+ * @param {String} name Optional. The name of the attribute to reset. If omitted, all attributes are reset.
+ * @return {Object} A reference to the host object.
+ * @chainable
+ */
+ reset : function(name) {
+ var host = this, // help compression
+ added;
+
+ if (name) {
+ if (host._isLazyAttr(name)) {
+ host._addLazyAttr(name);
+ }
+ host.set(name, host._state.get(name, INIT_VALUE));
+ } else {
+ added = host._state.data.added;
+ Y.each(added, function(v, n) {
+ host.reset(n);
+ }, host);
+ }
+ return host;
+ },
+
+ /**
+ * Allows setting of readOnly/writeOnce attributes. See set for argument details.
+ *
+ * @method _set
+ * @protected
+ * @chainable
+ *
+ * @param {String} name The name of the attribute.
+ * @param {Any} val The value to set the attribute to.
+ * @param {Object} opts (Optional) Optional event data to be mixed into
+ * the event facade passed to subscribers of the attribute's change event.
+ * @return {Object} A reference to the host object.
+ */
+ _set : function(name, val, opts) {
+ return this._setAttr(name, val, opts, true);
+ },
+
+ /**
+ * Provides the common implementation for the public get method,
+ * allowing Attribute hosts to over-ride either method.
+ *
+ * See get for argument details.
+ *
+ * @method _getAttr
+ * @protected
+ * @chainable
+ *
+ * @param {String} name The name of the attribute.
+ * @return {Any} The value of the attribute.
+ */
+ _getAttr : function(name) {
+ var host = this, // help compression
+ fullName = name,
+ state = host._state,
+ path,
+ getter,
+ val,
+ cfg;
+
+ if (name.indexOf(DOT) !== -1) {
+ path = name.split(DOT);
+ name = path.shift();
+ }
+
+ // On Demand - Should be rare - handles out of order valueFn references
+ if (host._tCfgs && host._tCfgs[name]) {
+ cfg = {};
+ cfg[name] = host._tCfgs[name];
+ delete host._tCfgs[name];
+ host._addAttrs(cfg, host._tVals);
+ }
+
+ // Lazy Init
+ if (host._isLazyAttr(name)) {
+ host._addLazyAttr(name);
+ }
+
+ val = host._getStateVal(name);
+ getter = state.get(name, GETTER);
+
+ val = (getter) ? getter.call(host, val, fullName) : val;
+ val = (path) ? O.getValue(val, path) : val;
+
+ return val;
+ },
+
+ /**
+ * Provides the common implementation for the public set and protected _set methods.
+ *
+ * See set for argument details.
+ *
+ * @method _setAttr
+ * @protected
+ * @chainable
+ *
+ * @param {String} name The name of the attribute.
+ * @param {Any} value The value to set the attribute to.
+ * @param {Object} opts (Optional) Optional event data to be mixed into
+ * the event facade passed to subscribers of the attribute's change event.
+ * @param {boolean} force If true, allows the caller to set values for
+ * readOnly or writeOnce attributes which have already been set.
+ *
+ * @return {Object} A reference to the host object.
+ */
+ _setAttr : function(name, val, opts, force) {
+ var allowSet = true,
+ state = this._state,
+ stateProxy = this._stateProxy,
+ data = state.data,
+ initialSet,
+ strPath,
+ path,
+ currVal;
+
+ if (name.indexOf(DOT) !== -1) {
+ strPath = name;
+ path = name.split(DOT);
+ name = path.shift();
+ }
+
+ if (this._isLazyAttr(name)) {
+ this._addLazyAttr(name);
+ }
+
+ initialSet = (!data.value || !(name in data.value));
+
+ if (stateProxy && name in stateProxy && !this._state.get(name, BYPASS_PROXY)) {
+ // TODO: Value is always set for proxy. Can we do any better? Maybe take a snapshot as the initial value for the first call to set?
+ initialSet = false;
+ }
+
+ if (this._requireAddAttr && !this.attrAdded(name)) {
+ Y.log('Set attribute:' + name + ', aborted; Attribute is not configured', 'warn', 'attribute');
+ } else {
+
+ if (!initialSet && !force) {
+
+ if (state.get(name, WRITE_ONCE)) {
+ Y.log('Set attribute:' + name + ', aborted; Attribute is writeOnce', 'warn', 'attribute');
+ allowSet = false;
+ }
+
+ if (state.get(name, READ_ONLY)) {
+ Y.log('Set attribute:' + name + ', aborted; Attribute is readOnly', 'warn', 'attribute');
+ allowSet = false;
+ }
+ }
+
+ if (allowSet) {
+ // Don't need currVal if initialSet (might fail in custom getter if it always expects a non-undefined/non-null value)
+ if (!initialSet) {
+ currVal = this.get(name);
+ }
+
+ if (path) {
+ val = O.setValue(Y.clone(currVal), path, val);
+
+ if (val === undefined) {
+ Y.log('Set attribute path:' + strPath + ', aborted; Path is invalid', 'warn', 'attribute');
+ allowSet = false;
+ }
+ }
+
+ if (allowSet) {
+ if (state.get(name, INITIALIZING)) {
+ this._setAttrVal(name, strPath, currVal, val);
+ } else {
+ this._fireAttrChange(name, strPath, currVal, val, opts);
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ /**
+ * Utility method to help setup the event payload and fire the attribute change event.
+ *
+ * @method _fireAttrChange
+ * @private
+ * @param {String} attrName The name of the attribute
+ * @param {String} subAttrName The full path of the property being changed,
+ * if this is a sub-attribute value being change. Otherwise null.
+ * @param {Any} currVal The current value of the attribute
+ * @param {Any} newVal The new value of the attribute
+ * @param {Object} opts Any additional event data to mix into the attribute change event's event facade.
+ */
+ _fireAttrChange : function(attrName, subAttrName, currVal, newVal, opts) {
+ var host = this,
+ eventName = attrName + CHANGE,
+ state = host._state,
+ facade;
+
+ if (!state.get(attrName, PUBLISHED)) {
+ host.publish(eventName, {
+ queuable:false,
+ defaultFn:host._defAttrChangeFn,
+ silent:true,
+ broadcast : state.get(attrName, BROADCAST)
+ });
+ state.add(attrName, PUBLISHED, true);
+ }
+
+ facade = (opts) ? Y.merge(opts) : host._ATTR_E_FACADE;
+
+ facade.type = eventName;
+ facade.attrName = attrName;
+ facade.subAttrName = subAttrName;
+ facade.prevVal = currVal;
+ facade.newVal = newVal;
+
+ host.fire(facade);
+ },
+
+ /**
+ * Default function for attribute change events.
+ *
+ * @private
+ * @method _defAttrChangeFn
+ * @param {EventFacade} e The event object for attribute change events.
+ */
+ _defAttrChangeFn : function(e) {
+ if (!this._setAttrVal(e.attrName, e.subAttrName, e.prevVal, e.newVal)) {
+ Y.log('State not updated and stopImmediatePropagation called for attribute: ' + e.attrName + ' , value:' + e.newVal, 'warn', 'attribute');
+ // Prevent "after" listeners from being invoked since nothing changed.
+ e.stopImmediatePropagation();
+ } else {
+ e.newVal = this._getStateVal(e.attrName);
+ }
+ },
+
+ /**
+ * Gets the stored value for the attribute, from either the
+ * internal state object, or the state proxy if it exits
+ *
+ * @method _getStateVal
+ * @private
+ * @param {String} name The name of the attribute
+ * @return {Any} The stored value of the attribute
+ */
+ _getStateVal : function(name) {
+ var stateProxy = this._stateProxy;
+ return stateProxy && (name in stateProxy) && !this._state.get(name, BYPASS_PROXY) ? stateProxy[name] : this._state.get(name, VALUE);
+ },
+
+ /**
+ * Sets the stored value for the attribute, in either the
+ * internal state object, or the state proxy if it exits
+ *
+ * @method _setStateVal
+ * @private
+ * @param {String} name The name of the attribute
+ * @param {Any} value The value of the attribute
+ */
+ _setStateVal : function(name, value) {
+ var stateProxy = this._stateProxy;
+ if (stateProxy && (name in stateProxy) && !this._state.get(name, BYPASS_PROXY)) {
+ stateProxy[name] = value;
+ } else {
+ this._state.add(name, VALUE, value);
+ }
+ },
+
+ /**
+ * Updates the stored value of the attribute in the privately held State object,
+ * if validation and setter passes.
+ *
+ * @method _setAttrVal
+ * @private
+ * @param {String} attrName The attribute name.
+ * @param {String} subAttrName The sub-attribute name, if setting a sub-attribute property ("x.y.z").
+ * @param {Any} prevVal The currently stored value of the attribute.
+ * @param {Any} newVal The value which is going to be stored.
+ *
+ * @return {booolean} true if the new attribute value was stored, false if not.
+ */
+ _setAttrVal : function(attrName, subAttrName, prevVal, newVal) {
+
+ var host = this,
+ allowSet = true,
+ state = host._state,
+
+ validator = state.get(attrName, VALIDATOR),
+ setter = state.get(attrName, SETTER),
+ initializing = state.get(attrName, INITIALIZING),
+ prevValRaw = this._getStateVal(attrName),
+
+ name = subAttrName || attrName,
+ retVal,
+ valid;
+
+ if (validator) {
+ valid = validator.call(host, newVal, name);
+
+ if (!valid && initializing) {
+ newVal = state.get(attrName, DEF_VALUE);
+ valid = true; // Assume it's valid, for perf.
+ }
+ }
+
+ if (!validator || valid) {
+ if (setter) {
+ retVal = setter.call(host, newVal, name);
+
+ if (retVal === INVALID_VALUE) {
+ Y.log('Attribute: ' + attrName + ', setter returned Attribute.INVALID_VALUE for value:' + newVal, 'warn', 'attribute');
+ allowSet = false;
+ } else if (retVal !== undefined){
+ Y.log('Attribute: ' + attrName + ', raw value: ' + newVal + ' modified by setter to:' + retVal, 'info', 'attribute');
+ newVal = retVal;
+ }
+ }
+
+ if (allowSet) {
+ if(!subAttrName && (newVal === prevValRaw) && !Lang.isObject(newVal)) {
+ Y.log('Attribute: ' + attrName + ', value unchanged:' + newVal, 'warn', 'attribute');
+ allowSet = false;
+ } else {
+ // Store value
+ if (state.get(attrName, INIT_VALUE) === undefined) {
+ state.add(attrName, INIT_VALUE, newVal);
+ }
+ host._setStateVal(attrName, newVal);
+ }
+ }
+
+ } else {
+ Y.log('Attribute:' + attrName + ', Validation failed for value:' + newVal, 'warn', 'attribute');
+ allowSet = false;
+ }
+
+ return allowSet;
+ },
+
+ /**
+ * Sets multiple attribute values.
+ *
+ * @method setAttrs
+ * @param {Object} attrs An object with attributes name/value pairs.
+ * @return {Object} A reference to the host object.
+ * @chainable
+ */
+ setAttrs : function(attrs, opts) {
+ return this._setAttrs(attrs, opts);
+ },
+
+ /**
+ * Implementation behind the public setAttrs method, to set multiple attribute values.
+ *
+ * @method _setAttrs
+ * @protected
+ * @param {Object} attrs An object with attributes name/value pairs.
+ * @return {Object} A reference to the host object.
+ * @chainable
+ */
+ _setAttrs : function(attrs, opts) {
+ for (var attr in attrs) {
+ if ( attrs.hasOwnProperty(attr) ) {
+ this.set(attr, attrs[attr]);
+ }
+ }
+ return this;
+ },
+
+ /**
+ * Gets multiple attribute values.
+ *
+ * @method getAttrs
+ * @param {Array | boolean} attrs Optional. An array of attribute names. If omitted, all attribute values are
+ * returned. If set to true, all attributes modified from their initial values are returned.
+ * @return {Object} An object with attribute name/value pairs.
+ */
+ getAttrs : function(attrs) {
+ return this._getAttrs(attrs);
+ },
+
+ /**
+ * Implementation behind the public getAttrs method, to get multiple attribute values.
+ *
+ * @method _getAttrs
+ * @protected
+ * @param {Array | boolean} attrs Optional. An array of attribute names. If omitted, all attribute values are
+ * returned. If set to true, all attributes modified from their initial values are returned.
+ * @return {Object} An object with attribute name/value pairs.
+ */
+ _getAttrs : function(attrs) {
+ var host = this,
+ o = {},
+ i, l, attr, val,
+ modifiedOnly = (attrs === true);
+
+ attrs = (attrs && !modifiedOnly) ? attrs : O.keys(host._state.data.added);
+
+ for (i = 0, l = attrs.length; i < l; i++) {
+ // Go through get, to honor cloning/normalization
+ attr = attrs[i];
+ val = host.get(attr);
+
+ if (!modifiedOnly || host._getStateVal(attr) != host._state.get(attr, INIT_VALUE)) {
+ o[attr] = host.get(attr);
+ }
+ }
+
+ return o;
+ },
+
+ /**
+ * Configures a group of attributes, and sets initial values.
+ *
+ *
+ * NOTE: This method does not isolate the configuration object by merging/cloning.
+ * The caller is responsible for merging/cloning the configuration object if required.
+ *
+ *
+ * @method addAttrs
+ * @chainable
+ *
+ * @param {Object} cfgs An object with attribute name/configuration pairs.
+ * @param {Object} values An object with attribute name/value pairs, defining the initial values to apply.
+ * Values defined in the cfgs argument will be over-written by values in this argument unless defined as read only.
+ * @param {boolean} lazy Whether or not to delay the intialization of these attributes until the first call to get/set.
+ * Individual attributes can over-ride this behavior by defining a lazyAdd configuration property in their configuration.
+ * See addAttr.
+ *
+ * @return {Object} A reference to the host object.
+ */
+ addAttrs : function(cfgs, values, lazy) {
+ var host = this; // help compression
+ if (cfgs) {
+ host._tCfgs = cfgs;
+ host._tVals = host._normAttrVals(values);
+ host._addAttrs(cfgs, host._tVals, lazy);
+ host._tCfgs = host._tVals = null;
+ }
+
+ return host;
+ },
+
+ /**
+ * Implementation behind the public addAttrs method.
+ *
+ * This method is invoked directly by get if it encounters a scenario
+ * in which an attribute's valueFn attempts to obtain the
+ * value an attribute in the same group of attributes, which has not yet
+ * been added (on demand initialization).
+ *
+ * @method _addAttrs
+ * @private
+ * @param {Object} cfgs An object with attribute name/configuration pairs.
+ * @param {Object} values An object with attribute name/value pairs, defining the initial values to apply.
+ * Values defined in the cfgs argument will be over-written by values in this argument unless defined as read only.
+ * @param {boolean} lazy Whether or not to delay the intialization of these attributes until the first call to get/set.
+ * Individual attributes can over-ride this behavior by defining a lazyAdd configuration property in their configuration.
+ * See addAttr.
+ */
+ _addAttrs : function(cfgs, values, lazy) {
+ var host = this, // help compression
+ attr,
+ attrCfg,
+ value;
+
+ for (attr in cfgs) {
+ if (cfgs.hasOwnProperty(attr)) {
+
+ // Not Merging. Caller is responsible for isolating configs
+ attrCfg = cfgs[attr];
+ attrCfg.defaultValue = attrCfg.value;
+
+ // Handle simple, complex and user values, accounting for read-only
+ value = host._getAttrInitVal(attr, attrCfg, host._tVals);
+
+ if (value !== undefined) {
+ attrCfg.value = value;
+ }
+
+ if (host._tCfgs[attr]) {
+ delete host._tCfgs[attr];
+ }
+
+ host.addAttr(attr, attrCfg, lazy);
+ }
+ }
+ },
+
+ /**
+ * Utility method to protect an attribute configuration
+ * hash, by merging the entire object and the individual
+ * attr config objects.
+ *
+ * @method _protectAttrs
+ * @protected
+ * @param {Object} attrs A hash of attribute to configuration object pairs.
+ * @return {Object} A protected version of the attrs argument.
+ */
+ _protectAttrs : function(attrs) {
+ if (attrs) {
+ attrs = Y.merge(attrs);
+ for (var attr in attrs) {
+ if (attrs.hasOwnProperty(attr)) {
+ attrs[attr] = Y.merge(attrs[attr]);
+ }
+ }
+ }
+ return attrs;
+ },
+
+ /**
+ * Utility method to normalize attribute values. The base implementation
+ * simply merges the hash to protect the original.
+ *
+ * @method _normAttrVals
+ * @param {Object} valueHash An object with attribute name/value pairs
+ *
+ * @return {Object}
+ *
+ * @private
+ */
+ _normAttrVals : function(valueHash) {
+ return (valueHash) ? Y.merge(valueHash) : null;
+ },
+
+ /**
+ * Returns the initial value of the given attribute from
+ * either the default configuration provided, or the
+ * over-ridden value if it exists in the set of initValues
+ * provided and the attribute is not read-only.
+ *
+ * @param {String} attr The name of the attribute
+ * @param {Object} cfg The attribute configuration object
+ * @param {Object} initValues The object with simple and complex attribute name/value pairs returned from _normAttrVals
+ *
+ * @return {Any} The initial value of the attribute.
+ *
+ * @method _getAttrInitVal
+ * @private
+ */
+ _getAttrInitVal : function(attr, cfg, initValues) {
+
+ // init value is provided by the user if it exists, else, provided by the config
+ var val = (!cfg[READ_ONLY] && initValues && initValues.hasOwnProperty(attr)) ?
+ val = initValues[attr] :
+ (cfg[VALUE_FN]) ?
+ cfg[VALUE_FN].call(this) :
+ cfg[VALUE];
+
+ Y.log('initValue for ' + attr + ':' + val, 'info', 'attribute');
+
+ return val;
+ }
+ };
+
+ // Basic prototype augment - no lazy constructor invocation.
+ Y.mix(Attribute, EventTarget, false, null, 1);
+
+ Y.Attribute = Attribute;
+
+
+}, '3.0.0' ,{requires:['event-custom']});
+YUI.add('attribute-complex', function(Y) {
+
+ /**
+ * Adds support for attribute providers to handle complex attributes in the constructor
+ *
+ * @module attribute
+ * @submodule attribute-complex
+ * @for Attribute
+ */
+
+ var O = Y.Object,
+ DOT = ".";
+
+ Y.Attribute.Complex = function() {};
+ Y.Attribute.Complex.prototype = {
+
+ /**
+ * Utility method to split out simple attribute name/value pairs ("x")
+ * from complex attribute name/value pairs ("x.y.z"), so that complex
+ * attributes can be keyed by the top level attribute name.
+ *
+ * @method _normAttrVals
+ * @param {Object} valueHash An object with attribute name/value pairs
+ *
+ * @return {Object} An object literal with 2 properties - "simple" and "complex",
+ * containing simple and complex attribute values respectively keyed
+ * by the top level attribute name, or null, if valueHash is falsey.
+ *
+ * @private
+ */
+ _normAttrVals : function(valueHash) {
+ var vals = {},
+ subvals = {},
+ path,
+ attr,
+ v, k;
+
+ if (valueHash) {
+ for (k in valueHash) {
+ if (valueHash.hasOwnProperty(k)) {
+ if (k.indexOf(DOT) !== -1) {
+ path = k.split(DOT);
+ attr = path.shift();
+ v = subvals[attr] = subvals[attr] || [];
+ v[v.length] = {
+ path : path,
+ value: valueHash[k]
+ };
+ } else {
+ vals[k] = valueHash[k];
+ }
+ }
+ }
+ return { simple:vals, complex:subvals };
+ } else {
+ return null;
+ }
+ },
+
+ /**
+ * Returns the initial value of the given attribute from
+ * either the default configuration provided, or the
+ * over-ridden value if it exists in the set of initValues
+ * provided and the attribute is not read-only.
+ *
+ * @param {String} attr The name of the attribute
+ * @param {Object} cfg The attribute configuration object
+ * @param {Object} initValues The object with simple and complex attribute name/value pairs returned from _normAttrVals
+ *
+ * @return {Any} The initial value of the attribute.
+ *
+ * @method _getAttrInitVal
+ * @private
+ */
+ _getAttrInitVal : function(attr, cfg, initValues) {
+
+ var val = (cfg.valueFn) ? cfg.valueFn.call(this) : cfg.value,
+ simple,
+ complex,
+ i,
+ l,
+ path,
+ subval,
+ subvals;
+
+ if (!cfg.readOnly && initValues) {
+
+ // Simple Attributes
+ simple = initValues.simple;
+ if (simple && simple.hasOwnProperty(attr)) {
+ val = simple[attr];
+ }
+
+ // Complex Attributes (complex values applied, after simple, incase both are set)
+ complex = initValues.complex;
+ if (complex && complex.hasOwnProperty(attr)) {
+ subvals = complex[attr];
+ for (i = 0, l = subvals.length; i < l; ++i) {
+ path = subvals[i].path;
+ subval = subvals[i].value;
+ O.setValue(val, path, subval);
+ }
+ }
+ }
+
+ return val;
+ }
+ };
+
+ Y.mix(Y.Attribute, Y.Attribute.Complex, true, null, 1);
+
+
+}, '3.0.0' ,{requires:['attribute-base']});
+
+
+YUI.add('attribute', function(Y){}, '3.0.0' ,{use:['attribute-base', 'attribute-complex']});
+
diff --git a/lib/yui/3.0.0/attribute/attribute-min.js b/lib/yui/3.0.0/attribute/attribute-min.js
new file mode 100644
index 0000000000..c5a63783b2
--- /dev/null
+++ b/lib/yui/3.0.0/attribute/attribute-min.js
@@ -0,0 +1,9 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("attribute-base",function(C){C.State=function(){this.data={};};C.State.prototype={add:function(O,Y,e){var c=this.data;c[Y]=c[Y]||{};c[Y][O]=e;},addAll:function(O,c){var Y;for(Y in c){if(c.hasOwnProperty(Y)){this.add(O,Y,c[Y]);}}},remove:function(O,Y){var c=this.data;if(c[Y]&&(O in c[Y])){delete c[Y][O];}},removeAll:function(O,c){var Y=this.data;C.each(c||Y,function(e,d){if(C.Lang.isString(d)){this.remove(O,d);}else{this.remove(O,e);}},this);},get:function(O,Y){var c=this.data;return(c[Y]&&O in c[Y])?c[Y][O]:undefined;},getAll:function(O){var c=this.data,Y;C.each(c,function(e,d){if(O in c[d]){Y=Y||{};Y[d]=e[O];}},this);return Y;}};var K=C.Object,F=C.Lang,L=C.EventTarget,W=".",U="Change",N="getter",M="setter",P="readOnly",X="writeOnce",b="validator",H="value",Q="valueFn",E="broadcast",S="lazyAdd",J="_bypassProxy",a="added",B="initializing",I="initValue",V="published",T="defaultValue",A="lazy",R="isLazyAdd",G,Z={};Z[P]=1;Z[X]=1;Z[N]=1;Z[E]=1;function D(){var c=this,O=this.constructor.ATTRS,Y=C.Base;c._ATTR_E_FACADE={};L.call(c,{emitFacade:true});c._conf=c._state=new C.State();c._stateProxy=c._stateProxy||null;c._requireAddAttr=c._requireAddAttr||false;if(O&&!(Y&&c instanceof Y)){c.addAttrs(this._protectAttrs(O));}}D.INVALID_VALUE={};G=D.INVALID_VALUE;D._ATTR_CFG=[M,N,b,H,Q,X,P,S,E,J];D.prototype={addAttr:function(Y,O,d){var e=this,g=e._state,f,c;d=(S in O)?O[S]:d;if(d&&!e.attrAdded(Y)){g.add(Y,A,O||{});g.add(Y,a,true);}else{if(!e.attrAdded(Y)||g.get(Y,R)){O=O||{};c=(H in O);if(c){f=O.value;delete O.value;}O.added=true;O.initializing=true;g.addAll(Y,O);if(c){e.set(Y,f);}g.remove(Y,B);}}return e;},attrAdded:function(O){return !!this._state.get(O,a);},modifyAttr:function(Y,O){var c=this,e,d;if(c.attrAdded(Y)){if(c._isLazyAttr(Y)){c._addLazyAttr(Y);}d=c._state;for(e in O){if(Z[e]&&O.hasOwnProperty(e)){d.add(Y,e,O[e]);if(e===E){d.remove(Y,V);}}}}},removeAttr:function(O){this._state.removeAll(O);},get:function(O){return this._getAttr(O);},_isLazyAttr:function(O){return this._state.get(O,A);},_addLazyAttr:function(Y){var c=this._state,O=c.get(Y,A);c.add(Y,R,true);c.remove(Y,A);this.addAttr(Y,O);},set:function(O,c,Y){return this._setAttr(O,c,Y);},reset:function(O){var c=this,Y;if(O){if(c._isLazyAttr(O)){c._addLazyAttr(O);}c.set(O,c._state.get(O,I));}else{Y=c._state.data.added;C.each(Y,function(d,e){c.reset(e);},c);}return c;},_set:function(O,c,Y){return this._setAttr(O,c,Y,true);},_getAttr:function(c){var d=this,h=c,e=d._state,f,O,g,Y;if(c.indexOf(W)!==-1){f=c.split(W);c=f.shift();}if(d._tCfgs&&d._tCfgs[c]){Y={};Y[c]=d._tCfgs[c];delete d._tCfgs[c];d._addAttrs(Y,d._tVals);}if(d._isLazyAttr(c)){d._addLazyAttr(c);}g=d._getStateVal(c);O=e.get(c,N);g=(O)?O.call(d,g,h):g;g=(f)?K.getValue(g,f):g;return g;},_setAttr:function(c,f,O,d){var i=true,Y=this._state,g=this._stateProxy,j=Y.data,h,k,l,e;if(c.indexOf(W)!==-1){k=c;l=c.split(W);c=l.shift();}if(this._isLazyAttr(c)){this._addLazyAttr(c);}h=(!j.value||!(c in j.value));if(g&&c in g&&!this._state.get(c,J)){h=false;}if(this._requireAddAttr&&!this.attrAdded(c)){}else{if(!h&&!d){if(Y.get(c,X)){i=false;}if(Y.get(c,P)){i=false;}}if(i){if(!h){e=this.get(c);}if(l){f=K.setValue(C.clone(e),l,f);if(f===undefined){i=false;}}if(i){if(Y.get(c,B)){this._setAttrVal(c,k,e,f);}else{this._fireAttrChange(c,k,e,f,O);}}}}return this;},_fireAttrChange:function(g,f,d,c,O){var i=this,e=g+U,Y=i._state,h;if(!Y.get(g,V)){i.publish(e,{queuable:false,defaultFn:i._defAttrChangeFn,silent:true,broadcast:Y.get(g,E)});Y.add(g,V,true);}h=(O)?C.merge(O):i._ATTR_E_FACADE;h.type=e;h.attrName=g;h.subAttrName=f;h.prevVal=d;h.newVal=c;i.fire(h);},_defAttrChangeFn:function(O){if(!this._setAttrVal(O.attrName,O.subAttrName,O.prevVal,O.newVal)){O.stopImmediatePropagation();}else{O.newVal=this._getStateVal(O.attrName);}},_getStateVal:function(O){var Y=this._stateProxy;return Y&&(O in Y)&&!this._state.get(O,J)?Y[O]:this._state.get(O,H);},_setStateVal:function(O,c){var Y=this._stateProxy;if(Y&&(O in Y)&&!this._state.get(O,J)){Y[O]=c;}else{this._state.add(O,H,c);}},_setAttrVal:function(l,k,h,f){var n=this,i=true,c=n._state,d=c.get(l,b),g=c.get(l,M),j=c.get(l,B),m=this._getStateVal(l),Y=k||l,e,O;if(d){O=d.call(n,f,Y);if(!O&&j){f=c.get(l,T);O=true;}}if(!d||O){if(g){e=g.call(n,f,Y);if(e===G){i=false;}else{if(e!==undefined){f=e;}}}if(i){if(!k&&(f===m)&&!F.isObject(f)){i=false;}else{if(c.get(l,I)===undefined){c.add(l,I,f);}n._setStateVal(l,f);}}}else{i=false;}return i;},setAttrs:function(O,Y){return this._setAttrs(O,Y);},_setAttrs:function(Y,c){for(var O in Y){if(Y.hasOwnProperty(O)){this.set(O,Y[O]);}}return this;},getAttrs:function(O){return this._getAttrs(O);},_getAttrs:function(d){var f=this,h={},e,Y,O,g,c=(d===true);d=(d&&!c)?d:K.keys(f._state.data.added);for(e=0,Y=d.length;e
+ * Attribute provides configurable attribute support along with attribute change events. It is designed to be
+ * augmented on to a host class, and provides the host with the ability to configure attributes to store and retrieve state,
+ * along with attribute change events.
+ *
+ *
For example, attributes added to the host can be configured:
+ *
+ *
As read only.
+ *
As write once.
+ *
With a setter function, which can be used to manipulate
+ * values passed to Attribute's set method, before they are stored.
+ *
With a getter function, which can be used to manipulate stored values,
+ * before they are returned by Attribute's get method.
+ *
With a validator function, to validate values before they are stored.
+ *
+ *
+ *
See the addAttr method, for the complete set of configuration
+ * options available for attributes
.
+ *
+ *
NOTE: Most implementations will be better off extending the Base class,
+ * instead of augmenting Attribute directly. Base augments Attribute and will handle the initial configuration
+ * of attributes for derived classes, accounting for values passed into the constructor.
+ *
+ * @class Attribute
+ * @uses EventTarget
+ */
+ function Attribute() {
+
+ var host = this, // help compression
+ attrs = this.constructor.ATTRS,
+ Base = Y.Base;
+
+ // Perf tweak - avoid creating event literals if not required.
+ host._ATTR_E_FACADE = {};
+
+ EventTarget.call(host, {emitFacade:true});
+
+ // _conf maintained for backwards compat
+ host._conf = host._state = new Y.State();
+
+ host._stateProxy = host._stateProxy || null;
+ host._requireAddAttr = host._requireAddAttr || false;
+
+ // ATTRS support for Node, which is not Base based
+ if ( attrs && !(Base && host instanceof Base)) {
+ host.addAttrs(this._protectAttrs(attrs));
+ }
+ }
+
+ /**
+ *
The value to return from an attribute setter in order to prevent the set from going through.
+ *
+ *
You can return this value from your setter if you wish to combine validator and setter
+ * functionality into a single setter function, which either returns the massaged value to be stored or
+ * Attribute.INVALID_VALUE to prevent invalid values from being stored.
+ *
+ * @property Attribute.INVALID_VALUE
+ * @type Object
+ * @static
+ * @final
+ */
+ Attribute.INVALID_VALUE = {};
+ INVALID_VALUE = Attribute.INVALID_VALUE;
+
+ /**
+ * The list of properties which can be configured for
+ * each attribute (e.g. setter, getter, writeOnce etc.).
+ *
+ * This property is used internally as a whitelist for faster
+ * Y.mix operations.
+ *
+ * @property Attribute._ATTR_CFG
+ * @type Array
+ * @static
+ * @protected
+ */
+ Attribute._ATTR_CFG = [SETTER, GETTER, VALIDATOR, VALUE, VALUE_FN, WRITE_ONCE, READ_ONLY, LAZY_ADD, BROADCAST, BYPASS_PROXY];
+
+ Attribute.prototype = {
+ /**
+ *
+ * Adds an attribute with the provided configuration to the host object.
+ *
+ *
+ * The config argument object supports the following properties:
+ *
+ *
+ *
+ *
value <Any>
+ *
The initial value to set on the attribute
+ *
+ *
valueFn <Function>
+ *
A function, which will return the initial value to set on the attribute. This is useful
+ * for cases where the attribute configuration is defined statically, but needs to
+ * reference the host instance ("this") to obtain an initial value.
+ * If defined, this precedence over the value property.
+ *
+ *
readOnly <boolean>
+ *
Whether or not the attribute is read only. Attributes having readOnly set to true
+ * cannot be modified by invoking the set method.
+ *
+ *
writeOnce <boolean>
+ *
Whether or not the attribute is "write once". Attributes having writeOnce set to true,
+ * can only have their values set once, be it through the default configuration,
+ * constructor configuration arguments, or by invoking set.
+ *
+ *
setter <Function>
+ *
The setter function used to massage or normalize the value passed to the set method for the attribute.
+ * The value returned by the setter will be the final stored value. Returning
+ * Attribute.INVALID_VALUE, from the setter will prevent
+ * the value from being stored.
+ *
+ *
getter <Function>
+ *
The getter function used to massage or normalize the value returned by the get method for the attribute.
+ * The value returned by the getter function is the value which will be returned to the user when they
+ * invoke get.
+ *
+ *
validator <Function>
+ *
The validator function invoked prior to setting the stored value. Returning
+ * false from the validator function will prevent the value from being stored.
+ *
+ *
broadcast <int>
+ *
If and how attribute change events for this attribute should be broadcast. See CustomEvent's broadcast property for
+ * valid values. By default attribute change events are not broadcast.
+ *
+ *
lazyAdd <boolean>
+ *
Whether or not to delay initialization of the attribute until the first call to get/set it.
+ * This flag can be used to over-ride lazy initialization on a per attribute basis, when adding multiple attributes through
+ * the addAttrs method.
+ *
+ *
+ *
+ *
The setter, getter and validator are invoked with the value and name passed in as the first and second arguments, and with
+ * the context ("this") set to the host object.
+ *
+ *
Configuration properties outside of the list mentioned above are considered private properties used internally by attribute, and are not intended for public use.
+ *
+ * @method addAttr
+ *
+ * @param {String} name The name of the attribute.
+ * @param {Object} config An object with attribute configuration property/value pairs, specifying the configuration for the attribute.
+ *
+ *
+ * NOTE: The configuration object is modified when adding an attribute, so if you need
+ * to protect the original values, you will need to merge the object.
+ *
+ *
+ * @param {boolean} lazy (optional) Whether or not to add this attribute lazily (on the first call to get/set).
+ *
+ * @return {Object} A reference to the host object.
+ *
+ * @chainable
+ */
+ addAttr: function(name, config, lazy) {
+
+
+ var host = this, // help compression
+ state = host._state,
+ value,
+ hasValue;
+
+ lazy = (LAZY_ADD in config) ? config[LAZY_ADD] : lazy;
+
+ if (lazy && !host.attrAdded(name)) {
+ state.add(name, LAZY, config || {});
+ state.add(name, ADDED, true);
+ } else {
+
+
+ if (!host.attrAdded(name) || state.get(name, IS_LAZY_ADD)) {
+
+ config = config || {};
+
+ hasValue = (VALUE in config);
+
+
+ if(hasValue) {
+ // We'll go through set, don't want to set value in _state directly
+ value = config.value;
+ delete config.value;
+ }
+
+ config.added = true;
+ config.initializing = true;
+
+ state.addAll(name, config);
+
+ if (hasValue) {
+ // Go through set, so that raw values get normalized/validated
+ host.set(name, value);
+ }
+
+ state.remove(name, INITIALIZING);
+ }
+ }
+
+ return host;
+ },
+
+ /**
+ * Checks if the given attribute has been added to the host
+ *
+ * @method attrAdded
+ * @param {String} name The name of the attribute to check.
+ * @return {boolean} true if an attribute with the given name has been added, false if it hasn't. This method will return true for lazily added attributes.
+ */
+ attrAdded: function(name) {
+ return !!this._state.get(name, ADDED);
+ },
+
+ /**
+ * Updates the configuration of an attribute which has already been added.
+ *
+ * The properties which can be modified through this interface are limited
+ * to the following subset of attributes, which can be safely modified
+ * after a value has already been set on the attribute: readOnly, writeOnce,
+ * broadcast and getter.
+ *
+ * @method modifyAttr
+ * @param {String} name The name of the attribute whose configuration is to be updated.
+ * @param {Object} config An object with configuration property/value pairs, specifying the configuration properties to modify.
+ */
+ modifyAttr: function(name, config) {
+ var host = this, // help compression
+ prop, state;
+
+ if (host.attrAdded(name)) {
+
+ if (host._isLazyAttr(name)) {
+ host._addLazyAttr(name);
+ }
+
+ state = host._state;
+ for (prop in config) {
+ if (MODIFIABLE[prop] && config.hasOwnProperty(prop)) {
+ state.add(name, prop, config[prop]);
+
+ // If we reconfigured broadcast, need to republish
+ if (prop === BROADCAST) {
+ state.remove(name, PUBLISHED);
+ }
+ }
+ }
+ }
+
+ },
+
+ /**
+ * Removes an attribute from the host object
+ *
+ * @method removeAttr
+ * @param {String} name The name of the attribute to be removed.
+ */
+ removeAttr: function(name) {
+ this._state.removeAll(name);
+ },
+
+ /**
+ * Returns the current value of the attribute. If the attribute
+ * has been configured with a 'getter' function, this method will delegate
+ * to the 'getter' to obtain the value of the attribute.
+ *
+ * @method get
+ *
+ * @param {String} name The name of the attribute. If the value of the attribute is an Object,
+ * dot notation can be used to obtain the value of a property of the object (e.g. get("x.y.z"))
+ *
+ * @return {Any} The value of the attribute
+ */
+ get : function(name) {
+ return this._getAttr(name);
+ },
+
+ /**
+ * Checks whether or not the attribute is one which has been
+ * added lazily and still requires initialization.
+ *
+ * @method _isLazyAttr
+ * @private
+ * @param {String} name The name of the attribute
+ * @return {boolean} true if it's a lazily added attribute, false otherwise.
+ */
+ _isLazyAttr: function(name) {
+ return this._state.get(name, LAZY);
+ },
+
+ /**
+ * Finishes initializing an attribute which has been lazily added.
+ *
+ * @method _addLazyAttr
+ * @private
+ * @param {Object} name The name of the attribute
+ */
+ _addLazyAttr: function(name) {
+ var state = this._state,
+ lazyCfg = state.get(name, LAZY);
+
+ state.add(name, IS_LAZY_ADD, true);
+ state.remove(name, LAZY);
+ this.addAttr(name, lazyCfg);
+ },
+
+ /**
+ * Sets the value of an attribute.
+ *
+ * @method set
+ * @chainable
+ *
+ * @param {String} name The name of the attribute. If the
+ * current value of the attribute is an Object, dot notation can be used
+ * to set the value of a property within the object (e.g. set("x.y.z", 5)).
+ *
+ * @param {Any} value The value to set the attribute to.
+ *
+ * @param {Object} opts (Optional) Optional event data to be mixed into
+ * the event facade passed to subscribers of the attribute's change event. This
+ * can be used as a flexible way to identify the source of a call to set, allowing
+ * the developer to distinguish between set called internally by the host, vs.
+ * set called externally by the application developer.
+ *
+ * @return {Object} A reference to the host object.
+ */
+ set : function(name, val, opts) {
+ return this._setAttr(name, val, opts);
+ },
+
+ /**
+ * Resets the attribute (or all attributes) to its initial value, as long as
+ * the attribute is not readOnly, or writeOnce.
+ *
+ * @method reset
+ * @param {String} name Optional. The name of the attribute to reset. If omitted, all attributes are reset.
+ * @return {Object} A reference to the host object.
+ * @chainable
+ */
+ reset : function(name) {
+ var host = this, // help compression
+ added;
+
+ if (name) {
+ if (host._isLazyAttr(name)) {
+ host._addLazyAttr(name);
+ }
+ host.set(name, host._state.get(name, INIT_VALUE));
+ } else {
+ added = host._state.data.added;
+ Y.each(added, function(v, n) {
+ host.reset(n);
+ }, host);
+ }
+ return host;
+ },
+
+ /**
+ * Allows setting of readOnly/writeOnce attributes. See set for argument details.
+ *
+ * @method _set
+ * @protected
+ * @chainable
+ *
+ * @param {String} name The name of the attribute.
+ * @param {Any} val The value to set the attribute to.
+ * @param {Object} opts (Optional) Optional event data to be mixed into
+ * the event facade passed to subscribers of the attribute's change event.
+ * @return {Object} A reference to the host object.
+ */
+ _set : function(name, val, opts) {
+ return this._setAttr(name, val, opts, true);
+ },
+
+ /**
+ * Provides the common implementation for the public get method,
+ * allowing Attribute hosts to over-ride either method.
+ *
+ * See get for argument details.
+ *
+ * @method _getAttr
+ * @protected
+ * @chainable
+ *
+ * @param {String} name The name of the attribute.
+ * @return {Any} The value of the attribute.
+ */
+ _getAttr : function(name) {
+ var host = this, // help compression
+ fullName = name,
+ state = host._state,
+ path,
+ getter,
+ val,
+ cfg;
+
+ if (name.indexOf(DOT) !== -1) {
+ path = name.split(DOT);
+ name = path.shift();
+ }
+
+ // On Demand - Should be rare - handles out of order valueFn references
+ if (host._tCfgs && host._tCfgs[name]) {
+ cfg = {};
+ cfg[name] = host._tCfgs[name];
+ delete host._tCfgs[name];
+ host._addAttrs(cfg, host._tVals);
+ }
+
+ // Lazy Init
+ if (host._isLazyAttr(name)) {
+ host._addLazyAttr(name);
+ }
+
+ val = host._getStateVal(name);
+ getter = state.get(name, GETTER);
+
+ val = (getter) ? getter.call(host, val, fullName) : val;
+ val = (path) ? O.getValue(val, path) : val;
+
+ return val;
+ },
+
+ /**
+ * Provides the common implementation for the public set and protected _set methods.
+ *
+ * See set for argument details.
+ *
+ * @method _setAttr
+ * @protected
+ * @chainable
+ *
+ * @param {String} name The name of the attribute.
+ * @param {Any} value The value to set the attribute to.
+ * @param {Object} opts (Optional) Optional event data to be mixed into
+ * the event facade passed to subscribers of the attribute's change event.
+ * @param {boolean} force If true, allows the caller to set values for
+ * readOnly or writeOnce attributes which have already been set.
+ *
+ * @return {Object} A reference to the host object.
+ */
+ _setAttr : function(name, val, opts, force) {
+ var allowSet = true,
+ state = this._state,
+ stateProxy = this._stateProxy,
+ data = state.data,
+ initialSet,
+ strPath,
+ path,
+ currVal;
+
+ if (name.indexOf(DOT) !== -1) {
+ strPath = name;
+ path = name.split(DOT);
+ name = path.shift();
+ }
+
+ if (this._isLazyAttr(name)) {
+ this._addLazyAttr(name);
+ }
+
+ initialSet = (!data.value || !(name in data.value));
+
+ if (stateProxy && name in stateProxy && !this._state.get(name, BYPASS_PROXY)) {
+ // TODO: Value is always set for proxy. Can we do any better? Maybe take a snapshot as the initial value for the first call to set?
+ initialSet = false;
+ }
+
+ if (this._requireAddAttr && !this.attrAdded(name)) {
+ } else {
+
+ if (!initialSet && !force) {
+
+ if (state.get(name, WRITE_ONCE)) {
+ allowSet = false;
+ }
+
+ if (state.get(name, READ_ONLY)) {
+ allowSet = false;
+ }
+ }
+
+ if (allowSet) {
+ // Don't need currVal if initialSet (might fail in custom getter if it always expects a non-undefined/non-null value)
+ if (!initialSet) {
+ currVal = this.get(name);
+ }
+
+ if (path) {
+ val = O.setValue(Y.clone(currVal), path, val);
+
+ if (val === undefined) {
+ allowSet = false;
+ }
+ }
+
+ if (allowSet) {
+ if (state.get(name, INITIALIZING)) {
+ this._setAttrVal(name, strPath, currVal, val);
+ } else {
+ this._fireAttrChange(name, strPath, currVal, val, opts);
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ /**
+ * Utility method to help setup the event payload and fire the attribute change event.
+ *
+ * @method _fireAttrChange
+ * @private
+ * @param {String} attrName The name of the attribute
+ * @param {String} subAttrName The full path of the property being changed,
+ * if this is a sub-attribute value being change. Otherwise null.
+ * @param {Any} currVal The current value of the attribute
+ * @param {Any} newVal The new value of the attribute
+ * @param {Object} opts Any additional event data to mix into the attribute change event's event facade.
+ */
+ _fireAttrChange : function(attrName, subAttrName, currVal, newVal, opts) {
+ var host = this,
+ eventName = attrName + CHANGE,
+ state = host._state,
+ facade;
+
+ if (!state.get(attrName, PUBLISHED)) {
+ host.publish(eventName, {
+ queuable:false,
+ defaultFn:host._defAttrChangeFn,
+ silent:true,
+ broadcast : state.get(attrName, BROADCAST)
+ });
+ state.add(attrName, PUBLISHED, true);
+ }
+
+ facade = (opts) ? Y.merge(opts) : host._ATTR_E_FACADE;
+
+ facade.type = eventName;
+ facade.attrName = attrName;
+ facade.subAttrName = subAttrName;
+ facade.prevVal = currVal;
+ facade.newVal = newVal;
+
+ host.fire(facade);
+ },
+
+ /**
+ * Default function for attribute change events.
+ *
+ * @private
+ * @method _defAttrChangeFn
+ * @param {EventFacade} e The event object for attribute change events.
+ */
+ _defAttrChangeFn : function(e) {
+ if (!this._setAttrVal(e.attrName, e.subAttrName, e.prevVal, e.newVal)) {
+ // Prevent "after" listeners from being invoked since nothing changed.
+ e.stopImmediatePropagation();
+ } else {
+ e.newVal = this._getStateVal(e.attrName);
+ }
+ },
+
+ /**
+ * Gets the stored value for the attribute, from either the
+ * internal state object, or the state proxy if it exits
+ *
+ * @method _getStateVal
+ * @private
+ * @param {String} name The name of the attribute
+ * @return {Any} The stored value of the attribute
+ */
+ _getStateVal : function(name) {
+ var stateProxy = this._stateProxy;
+ return stateProxy && (name in stateProxy) && !this._state.get(name, BYPASS_PROXY) ? stateProxy[name] : this._state.get(name, VALUE);
+ },
+
+ /**
+ * Sets the stored value for the attribute, in either the
+ * internal state object, or the state proxy if it exits
+ *
+ * @method _setStateVal
+ * @private
+ * @param {String} name The name of the attribute
+ * @param {Any} value The value of the attribute
+ */
+ _setStateVal : function(name, value) {
+ var stateProxy = this._stateProxy;
+ if (stateProxy && (name in stateProxy) && !this._state.get(name, BYPASS_PROXY)) {
+ stateProxy[name] = value;
+ } else {
+ this._state.add(name, VALUE, value);
+ }
+ },
+
+ /**
+ * Updates the stored value of the attribute in the privately held State object,
+ * if validation and setter passes.
+ *
+ * @method _setAttrVal
+ * @private
+ * @param {String} attrName The attribute name.
+ * @param {String} subAttrName The sub-attribute name, if setting a sub-attribute property ("x.y.z").
+ * @param {Any} prevVal The currently stored value of the attribute.
+ * @param {Any} newVal The value which is going to be stored.
+ *
+ * @return {booolean} true if the new attribute value was stored, false if not.
+ */
+ _setAttrVal : function(attrName, subAttrName, prevVal, newVal) {
+
+ var host = this,
+ allowSet = true,
+ state = host._state,
+
+ validator = state.get(attrName, VALIDATOR),
+ setter = state.get(attrName, SETTER),
+ initializing = state.get(attrName, INITIALIZING),
+ prevValRaw = this._getStateVal(attrName),
+
+ name = subAttrName || attrName,
+ retVal,
+ valid;
+
+ if (validator) {
+ valid = validator.call(host, newVal, name);
+
+ if (!valid && initializing) {
+ newVal = state.get(attrName, DEF_VALUE);
+ valid = true; // Assume it's valid, for perf.
+ }
+ }
+
+ if (!validator || valid) {
+ if (setter) {
+ retVal = setter.call(host, newVal, name);
+
+ if (retVal === INVALID_VALUE) {
+ allowSet = false;
+ } else if (retVal !== undefined){
+ newVal = retVal;
+ }
+ }
+
+ if (allowSet) {
+ if(!subAttrName && (newVal === prevValRaw) && !Lang.isObject(newVal)) {
+ allowSet = false;
+ } else {
+ // Store value
+ if (state.get(attrName, INIT_VALUE) === undefined) {
+ state.add(attrName, INIT_VALUE, newVal);
+ }
+ host._setStateVal(attrName, newVal);
+ }
+ }
+
+ } else {
+ allowSet = false;
+ }
+
+ return allowSet;
+ },
+
+ /**
+ * Sets multiple attribute values.
+ *
+ * @method setAttrs
+ * @param {Object} attrs An object with attributes name/value pairs.
+ * @return {Object} A reference to the host object.
+ * @chainable
+ */
+ setAttrs : function(attrs, opts) {
+ return this._setAttrs(attrs, opts);
+ },
+
+ /**
+ * Implementation behind the public setAttrs method, to set multiple attribute values.
+ *
+ * @method _setAttrs
+ * @protected
+ * @param {Object} attrs An object with attributes name/value pairs.
+ * @return {Object} A reference to the host object.
+ * @chainable
+ */
+ _setAttrs : function(attrs, opts) {
+ for (var attr in attrs) {
+ if ( attrs.hasOwnProperty(attr) ) {
+ this.set(attr, attrs[attr]);
+ }
+ }
+ return this;
+ },
+
+ /**
+ * Gets multiple attribute values.
+ *
+ * @method getAttrs
+ * @param {Array | boolean} attrs Optional. An array of attribute names. If omitted, all attribute values are
+ * returned. If set to true, all attributes modified from their initial values are returned.
+ * @return {Object} An object with attribute name/value pairs.
+ */
+ getAttrs : function(attrs) {
+ return this._getAttrs(attrs);
+ },
+
+ /**
+ * Implementation behind the public getAttrs method, to get multiple attribute values.
+ *
+ * @method _getAttrs
+ * @protected
+ * @param {Array | boolean} attrs Optional. An array of attribute names. If omitted, all attribute values are
+ * returned. If set to true, all attributes modified from their initial values are returned.
+ * @return {Object} An object with attribute name/value pairs.
+ */
+ _getAttrs : function(attrs) {
+ var host = this,
+ o = {},
+ i, l, attr, val,
+ modifiedOnly = (attrs === true);
+
+ attrs = (attrs && !modifiedOnly) ? attrs : O.keys(host._state.data.added);
+
+ for (i = 0, l = attrs.length; i < l; i++) {
+ // Go through get, to honor cloning/normalization
+ attr = attrs[i];
+ val = host.get(attr);
+
+ if (!modifiedOnly || host._getStateVal(attr) != host._state.get(attr, INIT_VALUE)) {
+ o[attr] = host.get(attr);
+ }
+ }
+
+ return o;
+ },
+
+ /**
+ * Configures a group of attributes, and sets initial values.
+ *
+ *
+ * NOTE: This method does not isolate the configuration object by merging/cloning.
+ * The caller is responsible for merging/cloning the configuration object if required.
+ *
+ *
+ * @method addAttrs
+ * @chainable
+ *
+ * @param {Object} cfgs An object with attribute name/configuration pairs.
+ * @param {Object} values An object with attribute name/value pairs, defining the initial values to apply.
+ * Values defined in the cfgs argument will be over-written by values in this argument unless defined as read only.
+ * @param {boolean} lazy Whether or not to delay the intialization of these attributes until the first call to get/set.
+ * Individual attributes can over-ride this behavior by defining a lazyAdd configuration property in their configuration.
+ * See addAttr.
+ *
+ * @return {Object} A reference to the host object.
+ */
+ addAttrs : function(cfgs, values, lazy) {
+ var host = this; // help compression
+ if (cfgs) {
+ host._tCfgs = cfgs;
+ host._tVals = host._normAttrVals(values);
+ host._addAttrs(cfgs, host._tVals, lazy);
+ host._tCfgs = host._tVals = null;
+ }
+
+ return host;
+ },
+
+ /**
+ * Implementation behind the public addAttrs method.
+ *
+ * This method is invoked directly by get if it encounters a scenario
+ * in which an attribute's valueFn attempts to obtain the
+ * value an attribute in the same group of attributes, which has not yet
+ * been added (on demand initialization).
+ *
+ * @method _addAttrs
+ * @private
+ * @param {Object} cfgs An object with attribute name/configuration pairs.
+ * @param {Object} values An object with attribute name/value pairs, defining the initial values to apply.
+ * Values defined in the cfgs argument will be over-written by values in this argument unless defined as read only.
+ * @param {boolean} lazy Whether or not to delay the intialization of these attributes until the first call to get/set.
+ * Individual attributes can over-ride this behavior by defining a lazyAdd configuration property in their configuration.
+ * See addAttr.
+ */
+ _addAttrs : function(cfgs, values, lazy) {
+ var host = this, // help compression
+ attr,
+ attrCfg,
+ value;
+
+ for (attr in cfgs) {
+ if (cfgs.hasOwnProperty(attr)) {
+
+ // Not Merging. Caller is responsible for isolating configs
+ attrCfg = cfgs[attr];
+ attrCfg.defaultValue = attrCfg.value;
+
+ // Handle simple, complex and user values, accounting for read-only
+ value = host._getAttrInitVal(attr, attrCfg, host._tVals);
+
+ if (value !== undefined) {
+ attrCfg.value = value;
+ }
+
+ if (host._tCfgs[attr]) {
+ delete host._tCfgs[attr];
+ }
+
+ host.addAttr(attr, attrCfg, lazy);
+ }
+ }
+ },
+
+ /**
+ * Utility method to protect an attribute configuration
+ * hash, by merging the entire object and the individual
+ * attr config objects.
+ *
+ * @method _protectAttrs
+ * @protected
+ * @param {Object} attrs A hash of attribute to configuration object pairs.
+ * @return {Object} A protected version of the attrs argument.
+ */
+ _protectAttrs : function(attrs) {
+ if (attrs) {
+ attrs = Y.merge(attrs);
+ for (var attr in attrs) {
+ if (attrs.hasOwnProperty(attr)) {
+ attrs[attr] = Y.merge(attrs[attr]);
+ }
+ }
+ }
+ return attrs;
+ },
+
+ /**
+ * Utility method to normalize attribute values. The base implementation
+ * simply merges the hash to protect the original.
+ *
+ * @method _normAttrVals
+ * @param {Object} valueHash An object with attribute name/value pairs
+ *
+ * @return {Object}
+ *
+ * @private
+ */
+ _normAttrVals : function(valueHash) {
+ return (valueHash) ? Y.merge(valueHash) : null;
+ },
+
+ /**
+ * Returns the initial value of the given attribute from
+ * either the default configuration provided, or the
+ * over-ridden value if it exists in the set of initValues
+ * provided and the attribute is not read-only.
+ *
+ * @param {String} attr The name of the attribute
+ * @param {Object} cfg The attribute configuration object
+ * @param {Object} initValues The object with simple and complex attribute name/value pairs returned from _normAttrVals
+ *
+ * @return {Any} The initial value of the attribute.
+ *
+ * @method _getAttrInitVal
+ * @private
+ */
+ _getAttrInitVal : function(attr, cfg, initValues) {
+
+ // init value is provided by the user if it exists, else, provided by the config
+ var val = (!cfg[READ_ONLY] && initValues && initValues.hasOwnProperty(attr)) ?
+ val = initValues[attr] :
+ (cfg[VALUE_FN]) ?
+ cfg[VALUE_FN].call(this) :
+ cfg[VALUE];
+
+
+ return val;
+ }
+ };
+
+ // Basic prototype augment - no lazy constructor invocation.
+ Y.mix(Attribute, EventTarget, false, null, 1);
+
+ Y.Attribute = Attribute;
+
+
+}, '3.0.0' ,{requires:['event-custom']});
+YUI.add('attribute-complex', function(Y) {
+
+ /**
+ * Adds support for attribute providers to handle complex attributes in the constructor
+ *
+ * @module attribute
+ * @submodule attribute-complex
+ * @for Attribute
+ */
+
+ var O = Y.Object,
+ DOT = ".";
+
+ Y.Attribute.Complex = function() {};
+ Y.Attribute.Complex.prototype = {
+
+ /**
+ * Utility method to split out simple attribute name/value pairs ("x")
+ * from complex attribute name/value pairs ("x.y.z"), so that complex
+ * attributes can be keyed by the top level attribute name.
+ *
+ * @method _normAttrVals
+ * @param {Object} valueHash An object with attribute name/value pairs
+ *
+ * @return {Object} An object literal with 2 properties - "simple" and "complex",
+ * containing simple and complex attribute values respectively keyed
+ * by the top level attribute name, or null, if valueHash is falsey.
+ *
+ * @private
+ */
+ _normAttrVals : function(valueHash) {
+ var vals = {},
+ subvals = {},
+ path,
+ attr,
+ v, k;
+
+ if (valueHash) {
+ for (k in valueHash) {
+ if (valueHash.hasOwnProperty(k)) {
+ if (k.indexOf(DOT) !== -1) {
+ path = k.split(DOT);
+ attr = path.shift();
+ v = subvals[attr] = subvals[attr] || [];
+ v[v.length] = {
+ path : path,
+ value: valueHash[k]
+ };
+ } else {
+ vals[k] = valueHash[k];
+ }
+ }
+ }
+ return { simple:vals, complex:subvals };
+ } else {
+ return null;
+ }
+ },
+
+ /**
+ * Returns the initial value of the given attribute from
+ * either the default configuration provided, or the
+ * over-ridden value if it exists in the set of initValues
+ * provided and the attribute is not read-only.
+ *
+ * @param {String} attr The name of the attribute
+ * @param {Object} cfg The attribute configuration object
+ * @param {Object} initValues The object with simple and complex attribute name/value pairs returned from _normAttrVals
+ *
+ * @return {Any} The initial value of the attribute.
+ *
+ * @method _getAttrInitVal
+ * @private
+ */
+ _getAttrInitVal : function(attr, cfg, initValues) {
+
+ var val = (cfg.valueFn) ? cfg.valueFn.call(this) : cfg.value,
+ simple,
+ complex,
+ i,
+ l,
+ path,
+ subval,
+ subvals;
+
+ if (!cfg.readOnly && initValues) {
+
+ // Simple Attributes
+ simple = initValues.simple;
+ if (simple && simple.hasOwnProperty(attr)) {
+ val = simple[attr];
+ }
+
+ // Complex Attributes (complex values applied, after simple, incase both are set)
+ complex = initValues.complex;
+ if (complex && complex.hasOwnProperty(attr)) {
+ subvals = complex[attr];
+ for (i = 0, l = subvals.length; i < l; ++i) {
+ path = subvals[i].path;
+ subval = subvals[i].value;
+ O.setValue(val, path, subval);
+ }
+ }
+ }
+
+ return val;
+ }
+ };
+
+ Y.mix(Y.Attribute, Y.Attribute.Complex, true, null, 1);
+
+
+}, '3.0.0' ,{requires:['attribute-base']});
+
+
+YUI.add('attribute', function(Y){}, '3.0.0' ,{use:['attribute-base', 'attribute-complex']});
+
diff --git a/lib/yui/3.0.0/base/base-base-debug.js b/lib/yui/3.0.0/base/base-base-debug.js
new file mode 100644
index 0000000000..36c00088ff
--- /dev/null
+++ b/lib/yui/3.0.0/base/base-base-debug.js
@@ -0,0 +1,536 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('base-base', function(Y) {
+
+ /**
+ * The base module provides the Base class, which objects requiring attribute and custom event support can extend.
+ * The module also provides two ways to reuse code - An augmentable Plugin.Host interface which provides plugin support
+ * (which is augmented to the Base class) and Base.build which provides a way to
+ * build custom classes using extensions.
+ *
+ * @module base
+ */
+
+ /**
+ * The base-base submodule provides the Base class without the Plugin support, provided by Plugin.Host,
+ * and without the extension support provided by Base.build.
+ *
+ * @module base
+ * @submodule base-base
+ */
+ var O = Y.Object,
+ L = Y.Lang,
+ DOT = ".",
+ DESTROY = "destroy",
+ INIT = "init",
+ INITIALIZED = "initialized",
+ DESTROYED = "destroyed",
+ INITIALIZER = "initializer",
+ OBJECT_CONSTRUCTOR = Object.prototype.constructor,
+ DEEP = "deep",
+ SHALLOW = "shallow",
+ DESTRUCTOR = "destructor",
+
+ Attribute = Y.Attribute;
+
+ /**
+ *
+ * A base class which objects requiring attributes and custom event support can
+ * extend. Base also handles the chaining of initializer and destructor methods across
+ * the hierarchy as part of object construction and destruction. Additionally, attributes configured
+ * through the static ATTRS property for each class
+ * in the hierarchy will be initialized by Base.
+ *
+ *
+ *
+ * The static NAME property of each class extending
+ * from Base will be used as the identifier for the class, and is used by Base to prefix
+ * all events fired by instances of that class.
+ *
+ * @class Base
+ * @constructor
+ * @uses Attribute
+ * @uses Plugin.Host
+ *
+ * @param {Object} config Object with configuration property name/value pairs
+ */
+ function Base() {
+ Y.log('constructor called', 'life', 'base');
+
+ Attribute.call(this);
+
+ // If Plugin.Host has been augmented [ through base-pluginhost ], setup it's
+ // initial state, but don't initialize Plugins yet. That's done after initialization.
+ var PluginHost = Y.Plugin && Y.Plugin.Host;
+ if (this._initPlugins && PluginHost) {
+ PluginHost.call(this);
+ }
+
+ if (this._lazyAddAttrs !== false) { this._lazyAddAttrs = true; }
+
+ this.init.apply(this, arguments);
+ }
+
+ /**
+ * The list of properties which can be configured for
+ * each attribute (e.g. setter, getter, writeOnce, readOnly etc.)
+ *
+ * @property Base._ATTR_CFG
+ * @type Array
+ * @static
+ * @private
+ */
+ Base._ATTR_CFG = Attribute._ATTR_CFG.concat("cloneDefaultValue");
+
+ /**
+ *
+ * The string to be used to identify instances of
+ * this class, for example in prefixing events.
+ *
+ *
+ * Classes extending Base, should define their own
+ * static NAME property, which should be camelCase by
+ * convention (e.g. MyClass.NAME = "myClass";).
+ *
+ * @property Base.NAME
+ * @type String
+ * @static
+ */
+ Base.NAME = "base";
+
+ /**
+ * The default set of attributes which will be available for instances of this class, and
+ * their configuration. In addition to the configuration properties listed by
+ * Attribute's addAttr method, the attribute
+ * can also be configured with a "cloneDefaultValue" property, which defines how the statically
+ * defined value field should be protected ("shallow", "deep" and false are supported values).
+ *
+ * By default if the value is an object literal or an array it will be "shallow" cloned, to
+ * protect the default value.
+ *
+ * @property Base.ATTRS
+ * @type Object
+ * @static
+ */
+ Base.ATTRS = {
+ /**
+ * Flag indicating whether or not this object
+ * has been through the init lifecycle phase.
+ *
+ * @attribute initialized
+ * @readonly
+ * @default false
+ * @type boolean
+ */
+ initialized: {
+ readOnly:true,
+ value:false
+ },
+
+ /**
+ * Flag indicating whether or not this object
+ * has been through the destroy lifecycle phase.
+ *
+ * @attribute destroyed
+ * @readonly
+ * @default false
+ * @type boolean
+ */
+ destroyed: {
+ readOnly:true,
+ value:false
+ }
+ };
+
+ Base.prototype = {
+
+ /**
+ * Init lifecycle method, invoked during construction.
+ * Fires the init event prior to setting up attributes and
+ * invoking initializers for the class hierarchy.
+ *
+ * @method init
+ * @final
+ * @chainable
+ * @param {Object} config Object with configuration property name/value pairs
+ * @return {Base} A reference to this object
+ */
+ init: function(config) {
+ Y.log('init called', 'life', 'base');
+
+ /**
+ * The string used to identify the class of this object.
+ *
+ * @deprecated Use this.constructor.NAME
+ * @property name
+ * @type String
+ */
+ this._yuievt.config.prefix = this.name = this.constructor.NAME;
+
+ /**
+ *
+ * Lifecycle event for the init phase, fired prior to initialization.
+ * Invoking the preventDefault() method on the event object provided
+ * to subscribers will prevent initialization from occuring.
+ *
+ *
+ * Subscribers to the "after" momemt of this event, will be notified
+ * after initialization of the object is complete (and therefore
+ * cannot prevent initialization).
+ *
+ *
+ * @event init
+ * @preventable _defInitFn
+ * @param {EventFacade} e Event object, with a cfg property which
+ * refers to the configuration object passed to the constructor.
+ */
+ this.publish(INIT, {
+ queuable:false,
+ defaultFn:this._defInitFn
+ });
+
+ if (config) {
+ if (config.on) {
+ this.on(config.on);
+ }
+ if (config.after) {
+ this.after(config.after);
+ }
+ }
+
+ this.fire(INIT, {cfg: config});
+
+ return this;
+ },
+
+ /**
+ *
+ * Destroy lifecycle method. Fires the destroy
+ * event, prior to invoking destructors for the
+ * class hierarchy.
+ *
+ *
+ * Subscribers to the destroy
+ * event can invoke preventDefault on the event object, to prevent destruction
+ * from proceeding.
+ *
+ * Lifecycle event for the destroy phase,
+ * fired prior to destruction. Invoking the preventDefault
+ * method on the event object provided to subscribers will
+ * prevent destruction from proceeding.
+ *
+ *
+ * Subscribers to the "after" moment of this event, will be notified
+ * after destruction is complete (and as a result cannot prevent
+ * destruction).
+ *
+ * @event destroy
+ * @preventable _defDestroyFn
+ * @param {EventFacade} e Event object
+ */
+ this.publish(DESTROY, {
+ queuable:false,
+ defaultFn: this._defDestroyFn
+ });
+ this.fire(DESTROY);
+ return this;
+ },
+
+ /**
+ * Default init event handler
+ *
+ * @method _defInitFn
+ * @param {EventFacade} e Event object, with a cfg property which
+ * refers to the configuration object passed to the constructor.
+ * @protected
+ */
+ _defInitFn : function(e) {
+ this._initHierarchy(e.cfg);
+ if (this._initPlugins) {
+ // Need to initPlugins manually, to handle constructor parsing, static Plug parsing
+ this._initPlugins(e.cfg);
+ }
+ this._set(INITIALIZED, true);
+ },
+
+ /**
+ * Default destroy event handler
+ *
+ * @method _defDestroyFn
+ * @param {EventFacade} e Event object
+ * @protected
+ */
+ _defDestroyFn : function(e) {
+ this._destroyHierarchy();
+ if (this._destroyPlugins) {
+ this._destroyPlugins();
+ }
+ this._set(DESTROYED, true);
+ },
+
+ /**
+ * Returns the class hierarchy for this object, with Base being the last class in the array.
+ *
+ * @method _getClasses
+ * @protected
+ * @return {Function[]} An array of classes (constructor functions), making up the class hierarchy for this object.
+ * This value is cached the first time the method, or _getAttrCfgs, is invoked. Subsequent invocations return the
+ * cached value.
+ */
+ _getClasses : function() {
+ if (!this._classes) {
+ this._initHierarchyData();
+ }
+ return this._classes;
+ },
+
+ /**
+ * Returns an aggregated set of attribute configurations, by traversing the class hierarchy.
+ *
+ * @method _getAttrCfgs
+ * @protected
+ * @return {Object} The hash of attribute configurations, aggregated across classes in the hierarchy
+ * This value is cached the first time the method, or _getClasses, is invoked. Subsequent invocations return
+ * the cached value.
+ */
+ _getAttrCfgs : function() {
+ if (!this._attrs) {
+ this._initHierarchyData();
+ }
+ return this._attrs;
+ },
+
+ /**
+ * A helper method used when processing ATTRS across the class hierarchy during
+ * initialization. Returns a disposable object with the attributes defined for
+ * the provided class, extracted from the set of all attributes passed in .
+ *
+ * @method _filterAttrCfs
+ * @private
+ *
+ * @param {Function} clazz The class for which the desired attributes are required.
+ * @param {Object} allCfgs The set of all attribute configurations for this instance.
+ * Attributes will be removed from this set, if they belong to the filtered class, so
+ * that by the time all classes are processed, allCfgs will be empty.
+ *
+ * @return {Object} The set of attributes belonging to the class passed in, in the form
+ * of an object with attribute name/configuration pairs.
+ */
+ _filterAttrCfgs : function(clazz, allCfgs) {
+ var cfgs = null, attr, attrs = clazz.ATTRS;
+
+ if (attrs) {
+ for (attr in attrs) {
+ if (attrs.hasOwnProperty(attr) && allCfgs[attr]) {
+ cfgs = cfgs || {};
+ cfgs[attr] = allCfgs[attr];
+ delete allCfgs[attr];
+ }
+ }
+ }
+
+ return cfgs;
+ },
+
+ /**
+ * A helper method used by _getClasses and _getAttrCfgs, which determines both
+ * the array of classes and aggregate set of attribute configurations
+ * across the class hierarchy for the instance.
+ *
+ * @method _initHierarchyData
+ * @private
+ */
+ _initHierarchyData : function() {
+ var c = this.constructor,
+ classes = [],
+ attrs = [];
+
+ while (c) {
+ // Add to classes
+ classes[classes.length] = c;
+
+ // Add to attributes
+ if (c.ATTRS) {
+ attrs[attrs.length] = c.ATTRS;
+ }
+ c = c.superclass ? c.superclass.constructor : null;
+ }
+
+ this._classes = classes;
+ this._attrs = this._aggregateAttrs(attrs);
+ },
+
+ /**
+ * A helper method, used by _initHierarchyData to aggregate
+ * attribute configuration across the instances class hierarchy.
+ *
+ * The method will potect the attribute configuration value to protect the statically defined
+ * default value in ATTRS if required (if the value is an object literal, array or the
+ * attribute configuration has cloneDefaultValue set to shallow or deep).
+ *
+ * @method _aggregateAttrs
+ * @private
+ * @param {Array} allAttrs An array of ATTRS definitions across classes in the hierarchy
+ * (subclass first, Base last)
+ * @return {Object} The aggregate set of ATTRS definitions for the instance
+ */
+ _aggregateAttrs : function(allAttrs) {
+ var attr,
+ attrs,
+ cfg,
+ val,
+ path,
+ i,
+ clone,
+ cfgProps = Base._ATTR_CFG,
+ aggAttrs = {};
+
+ if (allAttrs) {
+ for (i = allAttrs.length-1; i >= 0; --i) {
+ attrs = allAttrs[i];
+
+ for (attr in attrs) {
+ if (attrs.hasOwnProperty(attr)) {
+
+ // Protect config passed in
+ cfg = Y.mix({}, attrs[attr], true, cfgProps);
+
+ val = cfg.value;
+ clone = cfg.cloneDefaultValue;
+
+ if (val) {
+ if ( (clone === undefined && (OBJECT_CONSTRUCTOR === val.constructor || L.isArray(val))) || clone === DEEP || clone === true) {
+ Y.log('Cloning default value for attribute:' + attr, 'info', 'base');
+ cfg.value = Y.clone(val);
+ } else if (clone === SHALLOW) {
+ Y.log('Merging default value for attribute:' + attr, 'info', 'base');
+ cfg.value = Y.merge(val);
+ }
+ // else if (clone === false), don't clone the static default value.
+ // It's intended to be used by reference.
+ }
+
+ path = null;
+ if (attr.indexOf(DOT) !== -1) {
+ path = attr.split(DOT);
+ attr = path.shift();
+ }
+
+ if (path && aggAttrs[attr] && aggAttrs[attr].value) {
+ O.setValue(aggAttrs[attr].value, path, val);
+ } else if (!path){
+ if (!aggAttrs[attr]) {
+ aggAttrs[attr] = cfg;
+ } else {
+ Y.mix(aggAttrs[attr], cfg, true, cfgProps);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return aggAttrs;
+ },
+
+ /**
+ * Initializes the class hierarchy for the instance, which includes
+ * initializing attributes for each class defined in the class's
+ * static ATTRS property and
+ * invoking the initializer method on the prototype of each class in the hierarchy.
+ *
+ * @method _initHierarchy
+ * @param {Object} userVals Object with configuration property name/value pairs
+ * @private
+ */
+ _initHierarchy : function(userVals) {
+ var lazy = this._lazyAddAttrs,
+ constr,
+ constrProto,
+ ci,
+ ei,
+ el,
+ classes = this._getClasses(),
+ attrCfgs = this._getAttrCfgs();
+
+ for (ci = classes.length-1; ci >= 0; ci--) {
+
+ constr = classes[ci];
+ constrProto = constr.prototype;
+
+ if (constr._yuibuild && constr._yuibuild.exts && !constr._yuibuild.dynamic) {
+ for (ei = 0, el = constr._yuibuild.exts.length; ei < el; ei++) {
+ constr._yuibuild.exts[ei].apply(this, arguments);
+ }
+ }
+
+ this.addAttrs(this._filterAttrCfgs(constr, attrCfgs), userVals, lazy);
+
+ if (constrProto.hasOwnProperty(INITIALIZER)) {
+ constrProto.initializer.apply(this, arguments);
+ }
+ }
+ },
+
+ /**
+ * Destroys the class hierarchy for this instance by invoking
+ * the descructor method on the prototype of each class in the hierarchy.
+ *
+ * @method _destroyHierarchy
+ * @private
+ */
+ _destroyHierarchy : function() {
+ var constr,
+ constrProto,
+ ci, cl,
+ classes = this._getClasses();
+
+ for (ci = 0, cl = classes.length; ci < cl; ci++) {
+ constr = classes[ci];
+ constrProto = constr.prototype;
+ if (constrProto.hasOwnProperty(DESTRUCTOR)) {
+ constrProto.destructor.apply(this, arguments);
+ }
+ }
+ },
+
+ /**
+ * Default toString implementation. Provides the constructor NAME
+ * and the instance ID.
+ *
+ * @method toString
+ * @return {String} String representation for this object
+ */
+ toString: function() {
+ return this.constructor.NAME + "[" + Y.stamp(this) + "]";
+ }
+ };
+
+ // Straightup augment, no wrapper functions
+ Y.mix(Base, Attribute, false, null, 1);
+
+ // Fix constructor
+ Base.prototype.constructor = Base;
+
+ Y.Base = Base;
+
+ // Fix constructor
+ Base.prototype.constructor = Base;
+
+
+}, '3.0.0' ,{requires:['attribute-base']});
diff --git a/lib/yui/3.0.0/base/base-base-min.js b/lib/yui/3.0.0/base/base-base-min.js
new file mode 100644
index 0000000000..a35d0a8498
--- /dev/null
+++ b/lib/yui/3.0.0/base/base-base-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("base-base",function(B){var H=B.Object,J=B.Lang,I=".",F="destroy",P="init",N="initialized",G="destroyed",D="initializer",C=Object.prototype.constructor,K="deep",Q="shallow",M="destructor",A=B.Attribute;function E(){A.call(this);var L=B.Plugin&&B.Plugin.Host;if(this._initPlugins&&L){L.call(this);}if(this._lazyAddAttrs!==false){this._lazyAddAttrs=true;}this.init.apply(this,arguments);}E._ATTR_CFG=A._ATTR_CFG.concat("cloneDefaultValue");E.NAME="base";E.ATTRS={initialized:{readOnly:true,value:false},destroyed:{readOnly:true,value:false}};E.prototype={init:function(L){this._yuievt.config.prefix=this.name=this.constructor.NAME;this.publish(P,{queuable:false,defaultFn:this._defInitFn});if(L){if(L.on){this.on(L.on);}if(L.after){this.after(L.after);}}this.fire(P,{cfg:L});return this;},destroy:function(){this.publish(F,{queuable:false,defaultFn:this._defDestroyFn});this.fire(F);return this;},_defInitFn:function(L){this._initHierarchy(L.cfg);if(this._initPlugins){this._initPlugins(L.cfg);}this._set(N,true);},_defDestroyFn:function(L){this._destroyHierarchy();if(this._destroyPlugins){this._destroyPlugins();}this._set(G,true);},_getClasses:function(){if(!this._classes){this._initHierarchyData();}return this._classes;},_getAttrCfgs:function(){if(!this._attrs){this._initHierarchyData();}return this._attrs;},_filterAttrCfgs:function(T,O){var R=null,L,S=T.ATTRS;if(S){for(L in S){if(S.hasOwnProperty(L)&&O[L]){R=R||{};R[L]=O[L];delete O[L];}}}return R;},_initHierarchyData:function(){var R=this.constructor,O=[],L=[];while(R){O[O.length]=R;if(R.ATTRS){L[L.length]=R.ATTRS;}R=R.superclass?R.superclass.constructor:null;}this._classes=O;this._attrs=this._aggregateAttrs(L);},_aggregateAttrs:function(W){var T,X,S,L,Y,O,V,R=E._ATTR_CFG,U={};if(W){for(O=W.length-1;O>=0;--O){X=W[O];for(T in X){if(X.hasOwnProperty(T)){S=B.mix({},X[T],true,R);L=S.value;V=S.cloneDefaultValue;if(L){if((V===undefined&&(C===L.constructor||J.isArray(L)))||V===K||V===true){S.value=B.clone(L);}else{if(V===Q){S.value=B.merge(L);}}}Y=null;if(T.indexOf(I)!==-1){Y=T.split(I);T=Y.shift();}if(Y&&U[T]&&U[T].value){H.setValue(U[T].value,Y,L);}else{if(!Y){if(!U[T]){U[T]=S;}else{B.mix(U[T],S,true,R);}}}}}}}return U;},_initHierarchy:function(U){var R=this._lazyAddAttrs,V,W,X,S,O,T=this._getClasses(),L=this._getAttrCfgs();for(X=T.length-1;X>=0;X--){V=T[X];W=V.prototype;if(V._yuibuild&&V._yuibuild.exts&&!V._yuibuild.dynamic){for(S=0,O=V._yuibuild.exts.length;S
+ * A base class which objects requiring attributes and custom event support can
+ * extend. Base also handles the chaining of initializer and destructor methods across
+ * the hierarchy as part of object construction and destruction. Additionally, attributes configured
+ * through the static ATTRS property for each class
+ * in the hierarchy will be initialized by Base.
+ *
+ *
+ *
+ * The static NAME property of each class extending
+ * from Base will be used as the identifier for the class, and is used by Base to prefix
+ * all events fired by instances of that class.
+ *
+ * @class Base
+ * @constructor
+ * @uses Attribute
+ * @uses Plugin.Host
+ *
+ * @param {Object} config Object with configuration property name/value pairs
+ */
+ function Base() {
+
+ Attribute.call(this);
+
+ // If Plugin.Host has been augmented [ through base-pluginhost ], setup it's
+ // initial state, but don't initialize Plugins yet. That's done after initialization.
+ var PluginHost = Y.Plugin && Y.Plugin.Host;
+ if (this._initPlugins && PluginHost) {
+ PluginHost.call(this);
+ }
+
+ if (this._lazyAddAttrs !== false) { this._lazyAddAttrs = true; }
+
+ this.init.apply(this, arguments);
+ }
+
+ /**
+ * The list of properties which can be configured for
+ * each attribute (e.g. setter, getter, writeOnce, readOnly etc.)
+ *
+ * @property Base._ATTR_CFG
+ * @type Array
+ * @static
+ * @private
+ */
+ Base._ATTR_CFG = Attribute._ATTR_CFG.concat("cloneDefaultValue");
+
+ /**
+ *
+ * The string to be used to identify instances of
+ * this class, for example in prefixing events.
+ *
+ *
+ * Classes extending Base, should define their own
+ * static NAME property, which should be camelCase by
+ * convention (e.g. MyClass.NAME = "myClass";).
+ *
+ * @property Base.NAME
+ * @type String
+ * @static
+ */
+ Base.NAME = "base";
+
+ /**
+ * The default set of attributes which will be available for instances of this class, and
+ * their configuration. In addition to the configuration properties listed by
+ * Attribute's addAttr method, the attribute
+ * can also be configured with a "cloneDefaultValue" property, which defines how the statically
+ * defined value field should be protected ("shallow", "deep" and false are supported values).
+ *
+ * By default if the value is an object literal or an array it will be "shallow" cloned, to
+ * protect the default value.
+ *
+ * @property Base.ATTRS
+ * @type Object
+ * @static
+ */
+ Base.ATTRS = {
+ /**
+ * Flag indicating whether or not this object
+ * has been through the init lifecycle phase.
+ *
+ * @attribute initialized
+ * @readonly
+ * @default false
+ * @type boolean
+ */
+ initialized: {
+ readOnly:true,
+ value:false
+ },
+
+ /**
+ * Flag indicating whether or not this object
+ * has been through the destroy lifecycle phase.
+ *
+ * @attribute destroyed
+ * @readonly
+ * @default false
+ * @type boolean
+ */
+ destroyed: {
+ readOnly:true,
+ value:false
+ }
+ };
+
+ Base.prototype = {
+
+ /**
+ * Init lifecycle method, invoked during construction.
+ * Fires the init event prior to setting up attributes and
+ * invoking initializers for the class hierarchy.
+ *
+ * @method init
+ * @final
+ * @chainable
+ * @param {Object} config Object with configuration property name/value pairs
+ * @return {Base} A reference to this object
+ */
+ init: function(config) {
+
+ /**
+ * The string used to identify the class of this object.
+ *
+ * @deprecated Use this.constructor.NAME
+ * @property name
+ * @type String
+ */
+ this._yuievt.config.prefix = this.name = this.constructor.NAME;
+
+ /**
+ *
+ * Lifecycle event for the init phase, fired prior to initialization.
+ * Invoking the preventDefault() method on the event object provided
+ * to subscribers will prevent initialization from occuring.
+ *
+ *
+ * Subscribers to the "after" momemt of this event, will be notified
+ * after initialization of the object is complete (and therefore
+ * cannot prevent initialization).
+ *
+ *
+ * @event init
+ * @preventable _defInitFn
+ * @param {EventFacade} e Event object, with a cfg property which
+ * refers to the configuration object passed to the constructor.
+ */
+ this.publish(INIT, {
+ queuable:false,
+ defaultFn:this._defInitFn
+ });
+
+ if (config) {
+ if (config.on) {
+ this.on(config.on);
+ }
+ if (config.after) {
+ this.after(config.after);
+ }
+ }
+
+ this.fire(INIT, {cfg: config});
+
+ return this;
+ },
+
+ /**
+ *
+ * Destroy lifecycle method. Fires the destroy
+ * event, prior to invoking destructors for the
+ * class hierarchy.
+ *
+ *
+ * Subscribers to the destroy
+ * event can invoke preventDefault on the event object, to prevent destruction
+ * from proceeding.
+ *
+ * @method destroy
+ * @return {Base} A reference to this object
+ * @final
+ * @chainable
+ */
+ destroy: function() {
+
+ /**
+ *
+ * Lifecycle event for the destroy phase,
+ * fired prior to destruction. Invoking the preventDefault
+ * method on the event object provided to subscribers will
+ * prevent destruction from proceeding.
+ *
+ *
+ * Subscribers to the "after" moment of this event, will be notified
+ * after destruction is complete (and as a result cannot prevent
+ * destruction).
+ *
+ * @event destroy
+ * @preventable _defDestroyFn
+ * @param {EventFacade} e Event object
+ */
+ this.publish(DESTROY, {
+ queuable:false,
+ defaultFn: this._defDestroyFn
+ });
+ this.fire(DESTROY);
+ return this;
+ },
+
+ /**
+ * Default init event handler
+ *
+ * @method _defInitFn
+ * @param {EventFacade} e Event object, with a cfg property which
+ * refers to the configuration object passed to the constructor.
+ * @protected
+ */
+ _defInitFn : function(e) {
+ this._initHierarchy(e.cfg);
+ if (this._initPlugins) {
+ // Need to initPlugins manually, to handle constructor parsing, static Plug parsing
+ this._initPlugins(e.cfg);
+ }
+ this._set(INITIALIZED, true);
+ },
+
+ /**
+ * Default destroy event handler
+ *
+ * @method _defDestroyFn
+ * @param {EventFacade} e Event object
+ * @protected
+ */
+ _defDestroyFn : function(e) {
+ this._destroyHierarchy();
+ if (this._destroyPlugins) {
+ this._destroyPlugins();
+ }
+ this._set(DESTROYED, true);
+ },
+
+ /**
+ * Returns the class hierarchy for this object, with Base being the last class in the array.
+ *
+ * @method _getClasses
+ * @protected
+ * @return {Function[]} An array of classes (constructor functions), making up the class hierarchy for this object.
+ * This value is cached the first time the method, or _getAttrCfgs, is invoked. Subsequent invocations return the
+ * cached value.
+ */
+ _getClasses : function() {
+ if (!this._classes) {
+ this._initHierarchyData();
+ }
+ return this._classes;
+ },
+
+ /**
+ * Returns an aggregated set of attribute configurations, by traversing the class hierarchy.
+ *
+ * @method _getAttrCfgs
+ * @protected
+ * @return {Object} The hash of attribute configurations, aggregated across classes in the hierarchy
+ * This value is cached the first time the method, or _getClasses, is invoked. Subsequent invocations return
+ * the cached value.
+ */
+ _getAttrCfgs : function() {
+ if (!this._attrs) {
+ this._initHierarchyData();
+ }
+ return this._attrs;
+ },
+
+ /**
+ * A helper method used when processing ATTRS across the class hierarchy during
+ * initialization. Returns a disposable object with the attributes defined for
+ * the provided class, extracted from the set of all attributes passed in .
+ *
+ * @method _filterAttrCfs
+ * @private
+ *
+ * @param {Function} clazz The class for which the desired attributes are required.
+ * @param {Object} allCfgs The set of all attribute configurations for this instance.
+ * Attributes will be removed from this set, if they belong to the filtered class, so
+ * that by the time all classes are processed, allCfgs will be empty.
+ *
+ * @return {Object} The set of attributes belonging to the class passed in, in the form
+ * of an object with attribute name/configuration pairs.
+ */
+ _filterAttrCfgs : function(clazz, allCfgs) {
+ var cfgs = null, attr, attrs = clazz.ATTRS;
+
+ if (attrs) {
+ for (attr in attrs) {
+ if (attrs.hasOwnProperty(attr) && allCfgs[attr]) {
+ cfgs = cfgs || {};
+ cfgs[attr] = allCfgs[attr];
+ delete allCfgs[attr];
+ }
+ }
+ }
+
+ return cfgs;
+ },
+
+ /**
+ * A helper method used by _getClasses and _getAttrCfgs, which determines both
+ * the array of classes and aggregate set of attribute configurations
+ * across the class hierarchy for the instance.
+ *
+ * @method _initHierarchyData
+ * @private
+ */
+ _initHierarchyData : function() {
+ var c = this.constructor,
+ classes = [],
+ attrs = [];
+
+ while (c) {
+ // Add to classes
+ classes[classes.length] = c;
+
+ // Add to attributes
+ if (c.ATTRS) {
+ attrs[attrs.length] = c.ATTRS;
+ }
+ c = c.superclass ? c.superclass.constructor : null;
+ }
+
+ this._classes = classes;
+ this._attrs = this._aggregateAttrs(attrs);
+ },
+
+ /**
+ * A helper method, used by _initHierarchyData to aggregate
+ * attribute configuration across the instances class hierarchy.
+ *
+ * The method will potect the attribute configuration value to protect the statically defined
+ * default value in ATTRS if required (if the value is an object literal, array or the
+ * attribute configuration has cloneDefaultValue set to shallow or deep).
+ *
+ * @method _aggregateAttrs
+ * @private
+ * @param {Array} allAttrs An array of ATTRS definitions across classes in the hierarchy
+ * (subclass first, Base last)
+ * @return {Object} The aggregate set of ATTRS definitions for the instance
+ */
+ _aggregateAttrs : function(allAttrs) {
+ var attr,
+ attrs,
+ cfg,
+ val,
+ path,
+ i,
+ clone,
+ cfgProps = Base._ATTR_CFG,
+ aggAttrs = {};
+
+ if (allAttrs) {
+ for (i = allAttrs.length-1; i >= 0; --i) {
+ attrs = allAttrs[i];
+
+ for (attr in attrs) {
+ if (attrs.hasOwnProperty(attr)) {
+
+ // Protect config passed in
+ cfg = Y.mix({}, attrs[attr], true, cfgProps);
+
+ val = cfg.value;
+ clone = cfg.cloneDefaultValue;
+
+ if (val) {
+ if ( (clone === undefined && (OBJECT_CONSTRUCTOR === val.constructor || L.isArray(val))) || clone === DEEP || clone === true) {
+ cfg.value = Y.clone(val);
+ } else if (clone === SHALLOW) {
+ cfg.value = Y.merge(val);
+ }
+ // else if (clone === false), don't clone the static default value.
+ // It's intended to be used by reference.
+ }
+
+ path = null;
+ if (attr.indexOf(DOT) !== -1) {
+ path = attr.split(DOT);
+ attr = path.shift();
+ }
+
+ if (path && aggAttrs[attr] && aggAttrs[attr].value) {
+ O.setValue(aggAttrs[attr].value, path, val);
+ } else if (!path){
+ if (!aggAttrs[attr]) {
+ aggAttrs[attr] = cfg;
+ } else {
+ Y.mix(aggAttrs[attr], cfg, true, cfgProps);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return aggAttrs;
+ },
+
+ /**
+ * Initializes the class hierarchy for the instance, which includes
+ * initializing attributes for each class defined in the class's
+ * static ATTRS property and
+ * invoking the initializer method on the prototype of each class in the hierarchy.
+ *
+ * @method _initHierarchy
+ * @param {Object} userVals Object with configuration property name/value pairs
+ * @private
+ */
+ _initHierarchy : function(userVals) {
+ var lazy = this._lazyAddAttrs,
+ constr,
+ constrProto,
+ ci,
+ ei,
+ el,
+ classes = this._getClasses(),
+ attrCfgs = this._getAttrCfgs();
+
+ for (ci = classes.length-1; ci >= 0; ci--) {
+
+ constr = classes[ci];
+ constrProto = constr.prototype;
+
+ if (constr._yuibuild && constr._yuibuild.exts && !constr._yuibuild.dynamic) {
+ for (ei = 0, el = constr._yuibuild.exts.length; ei < el; ei++) {
+ constr._yuibuild.exts[ei].apply(this, arguments);
+ }
+ }
+
+ this.addAttrs(this._filterAttrCfgs(constr, attrCfgs), userVals, lazy);
+
+ if (constrProto.hasOwnProperty(INITIALIZER)) {
+ constrProto.initializer.apply(this, arguments);
+ }
+ }
+ },
+
+ /**
+ * Destroys the class hierarchy for this instance by invoking
+ * the descructor method on the prototype of each class in the hierarchy.
+ *
+ * @method _destroyHierarchy
+ * @private
+ */
+ _destroyHierarchy : function() {
+ var constr,
+ constrProto,
+ ci, cl,
+ classes = this._getClasses();
+
+ for (ci = 0, cl = classes.length; ci < cl; ci++) {
+ constr = classes[ci];
+ constrProto = constr.prototype;
+ if (constrProto.hasOwnProperty(DESTRUCTOR)) {
+ constrProto.destructor.apply(this, arguments);
+ }
+ }
+ },
+
+ /**
+ * Default toString implementation. Provides the constructor NAME
+ * and the instance ID.
+ *
+ * @method toString
+ * @return {String} String representation for this object
+ */
+ toString: function() {
+ return this.constructor.NAME + "[" + Y.stamp(this) + "]";
+ }
+ };
+
+ // Straightup augment, no wrapper functions
+ Y.mix(Base, Attribute, false, null, 1);
+
+ // Fix constructor
+ Base.prototype.constructor = Base;
+
+ Y.Base = Base;
+
+ // Fix constructor
+ Base.prototype.constructor = Base;
+
+
+}, '3.0.0' ,{requires:['attribute-base']});
diff --git a/lib/yui/3.0.0/base/base-build-debug.js b/lib/yui/3.0.0/base/base-build-debug.js
new file mode 100644
index 0000000000..e907453806
--- /dev/null
+++ b/lib/yui/3.0.0/base/base-build-debug.js
@@ -0,0 +1,201 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('base-build', function(Y) {
+
+ /**
+ * The base-build submodule provides Base.build functionality, which
+ * can be used to create custom classes, by aggregating extensions onto
+ * a main class.
+ *
+ * @module base
+ * @submodule base-build
+ * @for Base
+ */
+
+ var Base = Y.Base,
+ L = Y.Lang;
+
+ /**
+ * The build configuration for the Base class.
+ *
+ * Defines the static fields which need to be aggregated
+ * when the Base class is used as the main class passed to
+ * the Base.build method.
+ *
+ * @property Base._buildCfg
+ * @type Object
+ * @static
+ * @final
+ * @private
+ */
+ Base._buildCfg = {
+ aggregates : ["ATTRS", "_PLUG", "_UNPLUG"]
+ };
+
+ /**
+ *
+ * Builds a custom constructor function (class) from the
+ * main function, and array of extension functions (classes)
+ * provided. The NAME field for the constructor function is
+ * defined by the first argument passed in.
+ *
+ *
+ * The cfg object supports the following properties
+ *
+ *
+ *
dynamic <boolean>
+ *
+ *
If true (default), a completely new class
+ * is created which extends the main class, and acts as the
+ * host on which the extension classes are augmented.
+ *
If false, the extensions classes are augmented directly to
+ * the main class, modifying the main class' prototype.
+ *
+ *
aggregates <String[]>
+ *
An array of static property names, which will get aggregated
+ * on to the built class, in addition to the default properties build
+ * will always aggregate as defined by the main class' static _buildCfg
+ * property.
+ *
+ *
+ *
+ * @method Base.build
+ * @static
+ * @param {Function} name The name of the new class. Used to defined the NAME property for the new class.
+ * @param {Function} main The main class on which to base the built class
+ * @param {Function[]} extensions The set of extension classes which will be
+ * augmented/aggregated to the built class.
+ * @param {Object} cfg Optional. Build configuration for the class (see description).
+ * @return {Function} A custom class, created from the provided main and extension classes
+ */
+ Base.build = function(name, main, extensions, cfg) {
+
+ var build = Base.build,
+ builtClass = build._getClass(main, cfg),
+ aggregates = build._getAggregates(main, cfg),
+ dynamic = builtClass._yuibuild.dynamic,
+ i, l, val, extClass;
+
+ // Shallow isolate aggregates
+ if (dynamic) {
+ if (aggregates) {
+ for (i = 0, l = aggregates.length; i < l; ++i) {
+ val = aggregates[i];
+ if (main.hasOwnProperty(val)) {
+ builtClass[val] = L.isArray(main[val]) ? [] : {};
+ }
+ }
+ Y.aggregate(builtClass, main, true, aggregates);
+ }
+ }
+
+ // Augment/Aggregate
+ for (i = 0, l = extensions.length; i < l; i++) {
+ extClass = extensions[i];
+
+ if (aggregates) {
+ Y.aggregate(builtClass, extClass, true, aggregates);
+ }
+
+ // Old augment
+ Y.mix(builtClass, extClass, true, null, 1);
+
+ builtClass._yuibuild.exts.push(extClass);
+ }
+
+ builtClass.prototype.hasImpl = build._hasImpl;
+
+ if (dynamic) {
+ builtClass.NAME = name;
+ builtClass.prototype.constructor = builtClass;
+ }
+
+ return builtClass;
+ };
+
+ Y.mix(Base.build, {
+
+ _template: function(main) {
+
+ function BuiltClass() {
+
+ BuiltClass.superclass.constructor.apply(this, arguments);
+
+ var f = BuiltClass._yuibuild.exts,
+ l = f.length,
+ i;
+
+ for (i = 0; i < l; i++) {
+ f[i].apply(this, arguments);
+ }
+
+ return this;
+ }
+ Y.extend(BuiltClass, main);
+
+ return BuiltClass;
+ },
+
+ _hasImpl : function(extClass) {
+ var classes = this._getClasses();
+ for (var i = 0, l = classes.length; i < l; i++) {
+ var cls = classes[i];
+
+ if (cls._yuibuild) {
+ var exts = cls._yuibuild.exts,
+ ll = exts.length,
+ j;
+
+ for (j = 0; j < ll; j++) {
+ if (exts[j] === extClass) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ },
+
+ _getClass : function(main, cfg) {
+
+ var dynamic = (cfg && false === cfg.dynamic) ? false : true,
+ builtClass = (dynamic) ? Base.build._template(main) : main;
+
+ builtClass._yuibuild = {
+ id: null,
+ exts : [],
+ dynamic : dynamic
+ };
+
+ return builtClass;
+ },
+
+ _getAggregates : function(main, cfg) {
+ var aggr = [],
+ cfgAggr = (cfg && cfg.aggregates),
+ c = main,
+ classAggr;
+
+ while (c && c.prototype) {
+ classAggr = c._buildCfg && c._buildCfg.aggregates;
+ if (classAggr) {
+ aggr = aggr.concat(classAggr);
+ }
+ c = c.superclass ? c.superclass.constructor : null;
+ }
+
+ if (cfgAggr) {
+ aggr = aggr.concat(cfgAggr);
+ }
+
+ return aggr;
+ }
+ });
+
+
+}, '3.0.0' ,{requires:['base-base']});
diff --git a/lib/yui/3.0.0/base/base-build-min.js b/lib/yui/3.0.0/base/base-build-min.js
new file mode 100644
index 0000000000..174c0625ae
--- /dev/null
+++ b/lib/yui/3.0.0/base/base-build-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("base-build",function(C){var B=C.Base,A=C.Lang;B._buildCfg={aggregates:["ATTRS","_PLUG","_UNPLUG"]};B.build=function(D,I,M,L){var O=B.build,E=O._getClass(I,L),K=O._getAggregates(I,L),G=E._yuibuild.dynamic,J,H,F,N;if(G){if(K){for(J=0,H=K.length;JBase.build method.
+ *
+ * @property Base._buildCfg
+ * @type Object
+ * @static
+ * @final
+ * @private
+ */
+ Base._buildCfg = {
+ aggregates : ["ATTRS", "_PLUG", "_UNPLUG"]
+ };
+
+ /**
+ *
+ * Builds a custom constructor function (class) from the
+ * main function, and array of extension functions (classes)
+ * provided. The NAME field for the constructor function is
+ * defined by the first argument passed in.
+ *
+ *
+ * The cfg object supports the following properties
+ *
+ *
+ *
dynamic <boolean>
+ *
+ *
If true (default), a completely new class
+ * is created which extends the main class, and acts as the
+ * host on which the extension classes are augmented.
+ *
If false, the extensions classes are augmented directly to
+ * the main class, modifying the main class' prototype.
+ *
+ *
aggregates <String[]>
+ *
An array of static property names, which will get aggregated
+ * on to the built class, in addition to the default properties build
+ * will always aggregate as defined by the main class' static _buildCfg
+ * property.
+ *
+ *
+ *
+ * @method Base.build
+ * @static
+ * @param {Function} name The name of the new class. Used to defined the NAME property for the new class.
+ * @param {Function} main The main class on which to base the built class
+ * @param {Function[]} extensions The set of extension classes which will be
+ * augmented/aggregated to the built class.
+ * @param {Object} cfg Optional. Build configuration for the class (see description).
+ * @return {Function} A custom class, created from the provided main and extension classes
+ */
+ Base.build = function(name, main, extensions, cfg) {
+
+ var build = Base.build,
+ builtClass = build._getClass(main, cfg),
+ aggregates = build._getAggregates(main, cfg),
+ dynamic = builtClass._yuibuild.dynamic,
+ i, l, val, extClass;
+
+ // Shallow isolate aggregates
+ if (dynamic) {
+ if (aggregates) {
+ for (i = 0, l = aggregates.length; i < l; ++i) {
+ val = aggregates[i];
+ if (main.hasOwnProperty(val)) {
+ builtClass[val] = L.isArray(main[val]) ? [] : {};
+ }
+ }
+ Y.aggregate(builtClass, main, true, aggregates);
+ }
+ }
+
+ // Augment/Aggregate
+ for (i = 0, l = extensions.length; i < l; i++) {
+ extClass = extensions[i];
+
+ if (aggregates) {
+ Y.aggregate(builtClass, extClass, true, aggregates);
+ }
+
+ // Old augment
+ Y.mix(builtClass, extClass, true, null, 1);
+
+ builtClass._yuibuild.exts.push(extClass);
+ }
+
+ builtClass.prototype.hasImpl = build._hasImpl;
+
+ if (dynamic) {
+ builtClass.NAME = name;
+ builtClass.prototype.constructor = builtClass;
+ }
+
+ return builtClass;
+ };
+
+ Y.mix(Base.build, {
+
+ _template: function(main) {
+
+ function BuiltClass() {
+
+ BuiltClass.superclass.constructor.apply(this, arguments);
+
+ var f = BuiltClass._yuibuild.exts,
+ l = f.length,
+ i;
+
+ for (i = 0; i < l; i++) {
+ f[i].apply(this, arguments);
+ }
+
+ return this;
+ }
+ Y.extend(BuiltClass, main);
+
+ return BuiltClass;
+ },
+
+ _hasImpl : function(extClass) {
+ var classes = this._getClasses();
+ for (var i = 0, l = classes.length; i < l; i++) {
+ var cls = classes[i];
+
+ if (cls._yuibuild) {
+ var exts = cls._yuibuild.exts,
+ ll = exts.length,
+ j;
+
+ for (j = 0; j < ll; j++) {
+ if (exts[j] === extClass) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ },
+
+ _getClass : function(main, cfg) {
+
+ var dynamic = (cfg && false === cfg.dynamic) ? false : true,
+ builtClass = (dynamic) ? Base.build._template(main) : main;
+
+ builtClass._yuibuild = {
+ id: null,
+ exts : [],
+ dynamic : dynamic
+ };
+
+ return builtClass;
+ },
+
+ _getAggregates : function(main, cfg) {
+ var aggr = [],
+ cfgAggr = (cfg && cfg.aggregates),
+ c = main,
+ classAggr;
+
+ while (c && c.prototype) {
+ classAggr = c._buildCfg && c._buildCfg.aggregates;
+ if (classAggr) {
+ aggr = aggr.concat(classAggr);
+ }
+ c = c.superclass ? c.superclass.constructor : null;
+ }
+
+ if (cfgAggr) {
+ aggr = aggr.concat(cfgAggr);
+ }
+
+ return aggr;
+ }
+ });
+
+
+}, '3.0.0' ,{requires:['base-base']});
diff --git a/lib/yui/3.0.0/base/base-debug.js b/lib/yui/3.0.0/base/base-debug.js
new file mode 100644
index 0000000000..ff65c1cf66
--- /dev/null
+++ b/lib/yui/3.0.0/base/base-debug.js
@@ -0,0 +1,770 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('base-base', function(Y) {
+
+ /**
+ * The base module provides the Base class, which objects requiring attribute and custom event support can extend.
+ * The module also provides two ways to reuse code - An augmentable Plugin.Host interface which provides plugin support
+ * (which is augmented to the Base class) and Base.build which provides a way to
+ * build custom classes using extensions.
+ *
+ * @module base
+ */
+
+ /**
+ * The base-base submodule provides the Base class without the Plugin support, provided by Plugin.Host,
+ * and without the extension support provided by Base.build.
+ *
+ * @module base
+ * @submodule base-base
+ */
+ var O = Y.Object,
+ L = Y.Lang,
+ DOT = ".",
+ DESTROY = "destroy",
+ INIT = "init",
+ INITIALIZED = "initialized",
+ DESTROYED = "destroyed",
+ INITIALIZER = "initializer",
+ OBJECT_CONSTRUCTOR = Object.prototype.constructor,
+ DEEP = "deep",
+ SHALLOW = "shallow",
+ DESTRUCTOR = "destructor",
+
+ Attribute = Y.Attribute;
+
+ /**
+ *
+ * A base class which objects requiring attributes and custom event support can
+ * extend. Base also handles the chaining of initializer and destructor methods across
+ * the hierarchy as part of object construction and destruction. Additionally, attributes configured
+ * through the static ATTRS property for each class
+ * in the hierarchy will be initialized by Base.
+ *
+ *
+ *
+ * The static NAME property of each class extending
+ * from Base will be used as the identifier for the class, and is used by Base to prefix
+ * all events fired by instances of that class.
+ *
+ * @class Base
+ * @constructor
+ * @uses Attribute
+ * @uses Plugin.Host
+ *
+ * @param {Object} config Object with configuration property name/value pairs
+ */
+ function Base() {
+ Y.log('constructor called', 'life', 'base');
+
+ Attribute.call(this);
+
+ // If Plugin.Host has been augmented [ through base-pluginhost ], setup it's
+ // initial state, but don't initialize Plugins yet. That's done after initialization.
+ var PluginHost = Y.Plugin && Y.Plugin.Host;
+ if (this._initPlugins && PluginHost) {
+ PluginHost.call(this);
+ }
+
+ if (this._lazyAddAttrs !== false) { this._lazyAddAttrs = true; }
+
+ this.init.apply(this, arguments);
+ }
+
+ /**
+ * The list of properties which can be configured for
+ * each attribute (e.g. setter, getter, writeOnce, readOnly etc.)
+ *
+ * @property Base._ATTR_CFG
+ * @type Array
+ * @static
+ * @private
+ */
+ Base._ATTR_CFG = Attribute._ATTR_CFG.concat("cloneDefaultValue");
+
+ /**
+ *
+ * The string to be used to identify instances of
+ * this class, for example in prefixing events.
+ *
+ *
+ * Classes extending Base, should define their own
+ * static NAME property, which should be camelCase by
+ * convention (e.g. MyClass.NAME = "myClass";).
+ *
+ * @property Base.NAME
+ * @type String
+ * @static
+ */
+ Base.NAME = "base";
+
+ /**
+ * The default set of attributes which will be available for instances of this class, and
+ * their configuration. In addition to the configuration properties listed by
+ * Attribute's addAttr method, the attribute
+ * can also be configured with a "cloneDefaultValue" property, which defines how the statically
+ * defined value field should be protected ("shallow", "deep" and false are supported values).
+ *
+ * By default if the value is an object literal or an array it will be "shallow" cloned, to
+ * protect the default value.
+ *
+ * @property Base.ATTRS
+ * @type Object
+ * @static
+ */
+ Base.ATTRS = {
+ /**
+ * Flag indicating whether or not this object
+ * has been through the init lifecycle phase.
+ *
+ * @attribute initialized
+ * @readonly
+ * @default false
+ * @type boolean
+ */
+ initialized: {
+ readOnly:true,
+ value:false
+ },
+
+ /**
+ * Flag indicating whether or not this object
+ * has been through the destroy lifecycle phase.
+ *
+ * @attribute destroyed
+ * @readonly
+ * @default false
+ * @type boolean
+ */
+ destroyed: {
+ readOnly:true,
+ value:false
+ }
+ };
+
+ Base.prototype = {
+
+ /**
+ * Init lifecycle method, invoked during construction.
+ * Fires the init event prior to setting up attributes and
+ * invoking initializers for the class hierarchy.
+ *
+ * @method init
+ * @final
+ * @chainable
+ * @param {Object} config Object with configuration property name/value pairs
+ * @return {Base} A reference to this object
+ */
+ init: function(config) {
+ Y.log('init called', 'life', 'base');
+
+ /**
+ * The string used to identify the class of this object.
+ *
+ * @deprecated Use this.constructor.NAME
+ * @property name
+ * @type String
+ */
+ this._yuievt.config.prefix = this.name = this.constructor.NAME;
+
+ /**
+ *
+ * Lifecycle event for the init phase, fired prior to initialization.
+ * Invoking the preventDefault() method on the event object provided
+ * to subscribers will prevent initialization from occuring.
+ *
+ *
+ * Subscribers to the "after" momemt of this event, will be notified
+ * after initialization of the object is complete (and therefore
+ * cannot prevent initialization).
+ *
+ *
+ * @event init
+ * @preventable _defInitFn
+ * @param {EventFacade} e Event object, with a cfg property which
+ * refers to the configuration object passed to the constructor.
+ */
+ this.publish(INIT, {
+ queuable:false,
+ defaultFn:this._defInitFn
+ });
+
+ if (config) {
+ if (config.on) {
+ this.on(config.on);
+ }
+ if (config.after) {
+ this.after(config.after);
+ }
+ }
+
+ this.fire(INIT, {cfg: config});
+
+ return this;
+ },
+
+ /**
+ *
+ * Destroy lifecycle method. Fires the destroy
+ * event, prior to invoking destructors for the
+ * class hierarchy.
+ *
+ *
+ * Subscribers to the destroy
+ * event can invoke preventDefault on the event object, to prevent destruction
+ * from proceeding.
+ *
+ * Lifecycle event for the destroy phase,
+ * fired prior to destruction. Invoking the preventDefault
+ * method on the event object provided to subscribers will
+ * prevent destruction from proceeding.
+ *
+ *
+ * Subscribers to the "after" moment of this event, will be notified
+ * after destruction is complete (and as a result cannot prevent
+ * destruction).
+ *
+ * @event destroy
+ * @preventable _defDestroyFn
+ * @param {EventFacade} e Event object
+ */
+ this.publish(DESTROY, {
+ queuable:false,
+ defaultFn: this._defDestroyFn
+ });
+ this.fire(DESTROY);
+ return this;
+ },
+
+ /**
+ * Default init event handler
+ *
+ * @method _defInitFn
+ * @param {EventFacade} e Event object, with a cfg property which
+ * refers to the configuration object passed to the constructor.
+ * @protected
+ */
+ _defInitFn : function(e) {
+ this._initHierarchy(e.cfg);
+ if (this._initPlugins) {
+ // Need to initPlugins manually, to handle constructor parsing, static Plug parsing
+ this._initPlugins(e.cfg);
+ }
+ this._set(INITIALIZED, true);
+ },
+
+ /**
+ * Default destroy event handler
+ *
+ * @method _defDestroyFn
+ * @param {EventFacade} e Event object
+ * @protected
+ */
+ _defDestroyFn : function(e) {
+ this._destroyHierarchy();
+ if (this._destroyPlugins) {
+ this._destroyPlugins();
+ }
+ this._set(DESTROYED, true);
+ },
+
+ /**
+ * Returns the class hierarchy for this object, with Base being the last class in the array.
+ *
+ * @method _getClasses
+ * @protected
+ * @return {Function[]} An array of classes (constructor functions), making up the class hierarchy for this object.
+ * This value is cached the first time the method, or _getAttrCfgs, is invoked. Subsequent invocations return the
+ * cached value.
+ */
+ _getClasses : function() {
+ if (!this._classes) {
+ this._initHierarchyData();
+ }
+ return this._classes;
+ },
+
+ /**
+ * Returns an aggregated set of attribute configurations, by traversing the class hierarchy.
+ *
+ * @method _getAttrCfgs
+ * @protected
+ * @return {Object} The hash of attribute configurations, aggregated across classes in the hierarchy
+ * This value is cached the first time the method, or _getClasses, is invoked. Subsequent invocations return
+ * the cached value.
+ */
+ _getAttrCfgs : function() {
+ if (!this._attrs) {
+ this._initHierarchyData();
+ }
+ return this._attrs;
+ },
+
+ /**
+ * A helper method used when processing ATTRS across the class hierarchy during
+ * initialization. Returns a disposable object with the attributes defined for
+ * the provided class, extracted from the set of all attributes passed in .
+ *
+ * @method _filterAttrCfs
+ * @private
+ *
+ * @param {Function} clazz The class for which the desired attributes are required.
+ * @param {Object} allCfgs The set of all attribute configurations for this instance.
+ * Attributes will be removed from this set, if they belong to the filtered class, so
+ * that by the time all classes are processed, allCfgs will be empty.
+ *
+ * @return {Object} The set of attributes belonging to the class passed in, in the form
+ * of an object with attribute name/configuration pairs.
+ */
+ _filterAttrCfgs : function(clazz, allCfgs) {
+ var cfgs = null, attr, attrs = clazz.ATTRS;
+
+ if (attrs) {
+ for (attr in attrs) {
+ if (attrs.hasOwnProperty(attr) && allCfgs[attr]) {
+ cfgs = cfgs || {};
+ cfgs[attr] = allCfgs[attr];
+ delete allCfgs[attr];
+ }
+ }
+ }
+
+ return cfgs;
+ },
+
+ /**
+ * A helper method used by _getClasses and _getAttrCfgs, which determines both
+ * the array of classes and aggregate set of attribute configurations
+ * across the class hierarchy for the instance.
+ *
+ * @method _initHierarchyData
+ * @private
+ */
+ _initHierarchyData : function() {
+ var c = this.constructor,
+ classes = [],
+ attrs = [];
+
+ while (c) {
+ // Add to classes
+ classes[classes.length] = c;
+
+ // Add to attributes
+ if (c.ATTRS) {
+ attrs[attrs.length] = c.ATTRS;
+ }
+ c = c.superclass ? c.superclass.constructor : null;
+ }
+
+ this._classes = classes;
+ this._attrs = this._aggregateAttrs(attrs);
+ },
+
+ /**
+ * A helper method, used by _initHierarchyData to aggregate
+ * attribute configuration across the instances class hierarchy.
+ *
+ * The method will potect the attribute configuration value to protect the statically defined
+ * default value in ATTRS if required (if the value is an object literal, array or the
+ * attribute configuration has cloneDefaultValue set to shallow or deep).
+ *
+ * @method _aggregateAttrs
+ * @private
+ * @param {Array} allAttrs An array of ATTRS definitions across classes in the hierarchy
+ * (subclass first, Base last)
+ * @return {Object} The aggregate set of ATTRS definitions for the instance
+ */
+ _aggregateAttrs : function(allAttrs) {
+ var attr,
+ attrs,
+ cfg,
+ val,
+ path,
+ i,
+ clone,
+ cfgProps = Base._ATTR_CFG,
+ aggAttrs = {};
+
+ if (allAttrs) {
+ for (i = allAttrs.length-1; i >= 0; --i) {
+ attrs = allAttrs[i];
+
+ for (attr in attrs) {
+ if (attrs.hasOwnProperty(attr)) {
+
+ // Protect config passed in
+ cfg = Y.mix({}, attrs[attr], true, cfgProps);
+
+ val = cfg.value;
+ clone = cfg.cloneDefaultValue;
+
+ if (val) {
+ if ( (clone === undefined && (OBJECT_CONSTRUCTOR === val.constructor || L.isArray(val))) || clone === DEEP || clone === true) {
+ Y.log('Cloning default value for attribute:' + attr, 'info', 'base');
+ cfg.value = Y.clone(val);
+ } else if (clone === SHALLOW) {
+ Y.log('Merging default value for attribute:' + attr, 'info', 'base');
+ cfg.value = Y.merge(val);
+ }
+ // else if (clone === false), don't clone the static default value.
+ // It's intended to be used by reference.
+ }
+
+ path = null;
+ if (attr.indexOf(DOT) !== -1) {
+ path = attr.split(DOT);
+ attr = path.shift();
+ }
+
+ if (path && aggAttrs[attr] && aggAttrs[attr].value) {
+ O.setValue(aggAttrs[attr].value, path, val);
+ } else if (!path){
+ if (!aggAttrs[attr]) {
+ aggAttrs[attr] = cfg;
+ } else {
+ Y.mix(aggAttrs[attr], cfg, true, cfgProps);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return aggAttrs;
+ },
+
+ /**
+ * Initializes the class hierarchy for the instance, which includes
+ * initializing attributes for each class defined in the class's
+ * static ATTRS property and
+ * invoking the initializer method on the prototype of each class in the hierarchy.
+ *
+ * @method _initHierarchy
+ * @param {Object} userVals Object with configuration property name/value pairs
+ * @private
+ */
+ _initHierarchy : function(userVals) {
+ var lazy = this._lazyAddAttrs,
+ constr,
+ constrProto,
+ ci,
+ ei,
+ el,
+ classes = this._getClasses(),
+ attrCfgs = this._getAttrCfgs();
+
+ for (ci = classes.length-1; ci >= 0; ci--) {
+
+ constr = classes[ci];
+ constrProto = constr.prototype;
+
+ if (constr._yuibuild && constr._yuibuild.exts && !constr._yuibuild.dynamic) {
+ for (ei = 0, el = constr._yuibuild.exts.length; ei < el; ei++) {
+ constr._yuibuild.exts[ei].apply(this, arguments);
+ }
+ }
+
+ this.addAttrs(this._filterAttrCfgs(constr, attrCfgs), userVals, lazy);
+
+ if (constrProto.hasOwnProperty(INITIALIZER)) {
+ constrProto.initializer.apply(this, arguments);
+ }
+ }
+ },
+
+ /**
+ * Destroys the class hierarchy for this instance by invoking
+ * the descructor method on the prototype of each class in the hierarchy.
+ *
+ * @method _destroyHierarchy
+ * @private
+ */
+ _destroyHierarchy : function() {
+ var constr,
+ constrProto,
+ ci, cl,
+ classes = this._getClasses();
+
+ for (ci = 0, cl = classes.length; ci < cl; ci++) {
+ constr = classes[ci];
+ constrProto = constr.prototype;
+ if (constrProto.hasOwnProperty(DESTRUCTOR)) {
+ constrProto.destructor.apply(this, arguments);
+ }
+ }
+ },
+
+ /**
+ * Default toString implementation. Provides the constructor NAME
+ * and the instance ID.
+ *
+ * @method toString
+ * @return {String} String representation for this object
+ */
+ toString: function() {
+ return this.constructor.NAME + "[" + Y.stamp(this) + "]";
+ }
+ };
+
+ // Straightup augment, no wrapper functions
+ Y.mix(Base, Attribute, false, null, 1);
+
+ // Fix constructor
+ Base.prototype.constructor = Base;
+
+ Y.Base = Base;
+
+ // Fix constructor
+ Base.prototype.constructor = Base;
+
+
+}, '3.0.0' ,{requires:['attribute-base']});
+YUI.add('base-pluginhost', function(Y) {
+
+ /**
+ * The base-pluginhost submodule adds Plugin support to Base, by augmenting Base with
+ * Plugin.Host and setting up static (class level) Base.plug and Base.unplug methods.
+ *
+ * @module base
+ * @submodule base-pluginhost
+ * @for Base
+ */
+
+ var Base = Y.Base,
+ PluginHost = Y.Plugin.Host;
+
+ Y.mix(Base, PluginHost, false, null, 1);
+
+ /**
+ * Alias for Plugin.Host.plug. See aliased
+ * method for argument and return value details.
+ *
+ * @method Base.plug
+ * @static
+ */
+ Base.plug = PluginHost.plug;
+
+ /**
+ * Alias for Plugin.Host.unplug. See the
+ * aliased method for argument and return value details.
+ *
+ * @method Base.unplug
+ * @static
+ */
+ Base.unplug = PluginHost.unplug;
+
+
+}, '3.0.0' ,{requires:['base-base', 'pluginhost']});
+YUI.add('base-build', function(Y) {
+
+ /**
+ * The base-build submodule provides Base.build functionality, which
+ * can be used to create custom classes, by aggregating extensions onto
+ * a main class.
+ *
+ * @module base
+ * @submodule base-build
+ * @for Base
+ */
+
+ var Base = Y.Base,
+ L = Y.Lang;
+
+ /**
+ * The build configuration for the Base class.
+ *
+ * Defines the static fields which need to be aggregated
+ * when the Base class is used as the main class passed to
+ * the Base.build method.
+ *
+ * @property Base._buildCfg
+ * @type Object
+ * @static
+ * @final
+ * @private
+ */
+ Base._buildCfg = {
+ aggregates : ["ATTRS", "_PLUG", "_UNPLUG"]
+ };
+
+ /**
+ *
+ * Builds a custom constructor function (class) from the
+ * main function, and array of extension functions (classes)
+ * provided. The NAME field for the constructor function is
+ * defined by the first argument passed in.
+ *
+ *
+ * The cfg object supports the following properties
+ *
+ *
+ *
dynamic <boolean>
+ *
+ *
If true (default), a completely new class
+ * is created which extends the main class, and acts as the
+ * host on which the extension classes are augmented.
+ *
If false, the extensions classes are augmented directly to
+ * the main class, modifying the main class' prototype.
+ *
+ *
aggregates <String[]>
+ *
An array of static property names, which will get aggregated
+ * on to the built class, in addition to the default properties build
+ * will always aggregate as defined by the main class' static _buildCfg
+ * property.
+ *
+ *
+ *
+ * @method Base.build
+ * @static
+ * @param {Function} name The name of the new class. Used to defined the NAME property for the new class.
+ * @param {Function} main The main class on which to base the built class
+ * @param {Function[]} extensions The set of extension classes which will be
+ * augmented/aggregated to the built class.
+ * @param {Object} cfg Optional. Build configuration for the class (see description).
+ * @return {Function} A custom class, created from the provided main and extension classes
+ */
+ Base.build = function(name, main, extensions, cfg) {
+
+ var build = Base.build,
+ builtClass = build._getClass(main, cfg),
+ aggregates = build._getAggregates(main, cfg),
+ dynamic = builtClass._yuibuild.dynamic,
+ i, l, val, extClass;
+
+ // Shallow isolate aggregates
+ if (dynamic) {
+ if (aggregates) {
+ for (i = 0, l = aggregates.length; i < l; ++i) {
+ val = aggregates[i];
+ if (main.hasOwnProperty(val)) {
+ builtClass[val] = L.isArray(main[val]) ? [] : {};
+ }
+ }
+ Y.aggregate(builtClass, main, true, aggregates);
+ }
+ }
+
+ // Augment/Aggregate
+ for (i = 0, l = extensions.length; i < l; i++) {
+ extClass = extensions[i];
+
+ if (aggregates) {
+ Y.aggregate(builtClass, extClass, true, aggregates);
+ }
+
+ // Old augment
+ Y.mix(builtClass, extClass, true, null, 1);
+
+ builtClass._yuibuild.exts.push(extClass);
+ }
+
+ builtClass.prototype.hasImpl = build._hasImpl;
+
+ if (dynamic) {
+ builtClass.NAME = name;
+ builtClass.prototype.constructor = builtClass;
+ }
+
+ return builtClass;
+ };
+
+ Y.mix(Base.build, {
+
+ _template: function(main) {
+
+ function BuiltClass() {
+
+ BuiltClass.superclass.constructor.apply(this, arguments);
+
+ var f = BuiltClass._yuibuild.exts,
+ l = f.length,
+ i;
+
+ for (i = 0; i < l; i++) {
+ f[i].apply(this, arguments);
+ }
+
+ return this;
+ }
+ Y.extend(BuiltClass, main);
+
+ return BuiltClass;
+ },
+
+ _hasImpl : function(extClass) {
+ var classes = this._getClasses();
+ for (var i = 0, l = classes.length; i < l; i++) {
+ var cls = classes[i];
+
+ if (cls._yuibuild) {
+ var exts = cls._yuibuild.exts,
+ ll = exts.length,
+ j;
+
+ for (j = 0; j < ll; j++) {
+ if (exts[j] === extClass) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ },
+
+ _getClass : function(main, cfg) {
+
+ var dynamic = (cfg && false === cfg.dynamic) ? false : true,
+ builtClass = (dynamic) ? Base.build._template(main) : main;
+
+ builtClass._yuibuild = {
+ id: null,
+ exts : [],
+ dynamic : dynamic
+ };
+
+ return builtClass;
+ },
+
+ _getAggregates : function(main, cfg) {
+ var aggr = [],
+ cfgAggr = (cfg && cfg.aggregates),
+ c = main,
+ classAggr;
+
+ while (c && c.prototype) {
+ classAggr = c._buildCfg && c._buildCfg.aggregates;
+ if (classAggr) {
+ aggr = aggr.concat(classAggr);
+ }
+ c = c.superclass ? c.superclass.constructor : null;
+ }
+
+ if (cfgAggr) {
+ aggr = aggr.concat(cfgAggr);
+ }
+
+ return aggr;
+ }
+ });
+
+
+}, '3.0.0' ,{requires:['base-base']});
+
+
+YUI.add('base', function(Y){}, '3.0.0' ,{use:['base-base', 'base-pluginhost', 'base-build']});
+
diff --git a/lib/yui/3.0.0/base/base-min.js b/lib/yui/3.0.0/base/base-min.js
new file mode 100644
index 0000000000..d2181dc578
--- /dev/null
+++ b/lib/yui/3.0.0/base/base-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("base-base",function(B){var H=B.Object,J=B.Lang,I=".",F="destroy",P="init",N="initialized",G="destroyed",D="initializer",C=Object.prototype.constructor,K="deep",Q="shallow",M="destructor",A=B.Attribute;function E(){A.call(this);var L=B.Plugin&&B.Plugin.Host;if(this._initPlugins&&L){L.call(this);}if(this._lazyAddAttrs!==false){this._lazyAddAttrs=true;}this.init.apply(this,arguments);}E._ATTR_CFG=A._ATTR_CFG.concat("cloneDefaultValue");E.NAME="base";E.ATTRS={initialized:{readOnly:true,value:false},destroyed:{readOnly:true,value:false}};E.prototype={init:function(L){this._yuievt.config.prefix=this.name=this.constructor.NAME;this.publish(P,{queuable:false,defaultFn:this._defInitFn});if(L){if(L.on){this.on(L.on);}if(L.after){this.after(L.after);}}this.fire(P,{cfg:L});return this;},destroy:function(){this.publish(F,{queuable:false,defaultFn:this._defDestroyFn});this.fire(F);return this;},_defInitFn:function(L){this._initHierarchy(L.cfg);if(this._initPlugins){this._initPlugins(L.cfg);}this._set(N,true);},_defDestroyFn:function(L){this._destroyHierarchy();if(this._destroyPlugins){this._destroyPlugins();}this._set(G,true);},_getClasses:function(){if(!this._classes){this._initHierarchyData();}return this._classes;},_getAttrCfgs:function(){if(!this._attrs){this._initHierarchyData();}return this._attrs;},_filterAttrCfgs:function(T,O){var R=null,L,S=T.ATTRS;if(S){for(L in S){if(S.hasOwnProperty(L)&&O[L]){R=R||{};R[L]=O[L];delete O[L];}}}return R;},_initHierarchyData:function(){var R=this.constructor,O=[],L=[];while(R){O[O.length]=R;if(R.ATTRS){L[L.length]=R.ATTRS;}R=R.superclass?R.superclass.constructor:null;}this._classes=O;this._attrs=this._aggregateAttrs(L);},_aggregateAttrs:function(W){var T,X,S,L,Y,O,V,R=E._ATTR_CFG,U={};if(W){for(O=W.length-1;O>=0;--O){X=W[O];for(T in X){if(X.hasOwnProperty(T)){S=B.mix({},X[T],true,R);L=S.value;V=S.cloneDefaultValue;if(L){if((V===undefined&&(C===L.constructor||J.isArray(L)))||V===K||V===true){S.value=B.clone(L);}else{if(V===Q){S.value=B.merge(L);}}}Y=null;if(T.indexOf(I)!==-1){Y=T.split(I);T=Y.shift();}if(Y&&U[T]&&U[T].value){H.setValue(U[T].value,Y,L);}else{if(!Y){if(!U[T]){U[T]=S;}else{B.mix(U[T],S,true,R);}}}}}}}return U;},_initHierarchy:function(U){var R=this._lazyAddAttrs,V,W,X,S,O,T=this._getClasses(),L=this._getAttrCfgs();for(X=T.length-1;X>=0;X--){V=T[X];W=V.prototype;if(V._yuibuild&&V._yuibuild.exts&&!V._yuibuild.dynamic){for(S=0,O=V._yuibuild.exts.length;SPlugin.Host.plug. See aliased
+ * method for argument and return value details.
+ *
+ * @method Base.plug
+ * @static
+ */
+ Base.plug = PluginHost.plug;
+
+ /**
+ * Alias for Plugin.Host.unplug. See the
+ * aliased method for argument and return value details.
+ *
+ * @method Base.unplug
+ * @static
+ */
+ Base.unplug = PluginHost.unplug;
+
+
+}, '3.0.0' ,{requires:['base-base', 'pluginhost']});
diff --git a/lib/yui/3.0.0/base/base-pluginhost-min.js b/lib/yui/3.0.0/base/base-pluginhost-min.js
new file mode 100644
index 0000000000..ac6efdd6da
--- /dev/null
+++ b/lib/yui/3.0.0/base/base-pluginhost-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("base-pluginhost",function(C){var A=C.Base,B=C.Plugin.Host;C.mix(A,B,false,null,1);A.plug=B.plug;A.unplug=B.unplug;},"3.0.0",{requires:["base-base","pluginhost"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/base/base-pluginhost.js b/lib/yui/3.0.0/base/base-pluginhost.js
new file mode 100644
index 0000000000..6b29f67913
--- /dev/null
+++ b/lib/yui/3.0.0/base/base-pluginhost.js
@@ -0,0 +1,43 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('base-pluginhost', function(Y) {
+
+ /**
+ * The base-pluginhost submodule adds Plugin support to Base, by augmenting Base with
+ * Plugin.Host and setting up static (class level) Base.plug and Base.unplug methods.
+ *
+ * @module base
+ * @submodule base-pluginhost
+ * @for Base
+ */
+
+ var Base = Y.Base,
+ PluginHost = Y.Plugin.Host;
+
+ Y.mix(Base, PluginHost, false, null, 1);
+
+ /**
+ * Alias for Plugin.Host.plug. See aliased
+ * method for argument and return value details.
+ *
+ * @method Base.plug
+ * @static
+ */
+ Base.plug = PluginHost.plug;
+
+ /**
+ * Alias for Plugin.Host.unplug. See the
+ * aliased method for argument and return value details.
+ *
+ * @method Base.unplug
+ * @static
+ */
+ Base.unplug = PluginHost.unplug;
+
+
+}, '3.0.0' ,{requires:['base-base', 'pluginhost']});
diff --git a/lib/yui/3.0.0/base/base.js b/lib/yui/3.0.0/base/base.js
new file mode 100644
index 0000000000..9f98c7969c
--- /dev/null
+++ b/lib/yui/3.0.0/base/base.js
@@ -0,0 +1,765 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('base-base', function(Y) {
+
+ /**
+ * The base module provides the Base class, which objects requiring attribute and custom event support can extend.
+ * The module also provides two ways to reuse code - An augmentable Plugin.Host interface which provides plugin support
+ * (which is augmented to the Base class) and Base.build which provides a way to
+ * build custom classes using extensions.
+ *
+ * @module base
+ */
+
+ /**
+ * The base-base submodule provides the Base class without the Plugin support, provided by Plugin.Host,
+ * and without the extension support provided by Base.build.
+ *
+ * @module base
+ * @submodule base-base
+ */
+ var O = Y.Object,
+ L = Y.Lang,
+ DOT = ".",
+ DESTROY = "destroy",
+ INIT = "init",
+ INITIALIZED = "initialized",
+ DESTROYED = "destroyed",
+ INITIALIZER = "initializer",
+ OBJECT_CONSTRUCTOR = Object.prototype.constructor,
+ DEEP = "deep",
+ SHALLOW = "shallow",
+ DESTRUCTOR = "destructor",
+
+ Attribute = Y.Attribute;
+
+ /**
+ *
+ * A base class which objects requiring attributes and custom event support can
+ * extend. Base also handles the chaining of initializer and destructor methods across
+ * the hierarchy as part of object construction and destruction. Additionally, attributes configured
+ * through the static ATTRS property for each class
+ * in the hierarchy will be initialized by Base.
+ *
+ *
+ *
+ * The static NAME property of each class extending
+ * from Base will be used as the identifier for the class, and is used by Base to prefix
+ * all events fired by instances of that class.
+ *
+ * @class Base
+ * @constructor
+ * @uses Attribute
+ * @uses Plugin.Host
+ *
+ * @param {Object} config Object with configuration property name/value pairs
+ */
+ function Base() {
+
+ Attribute.call(this);
+
+ // If Plugin.Host has been augmented [ through base-pluginhost ], setup it's
+ // initial state, but don't initialize Plugins yet. That's done after initialization.
+ var PluginHost = Y.Plugin && Y.Plugin.Host;
+ if (this._initPlugins && PluginHost) {
+ PluginHost.call(this);
+ }
+
+ if (this._lazyAddAttrs !== false) { this._lazyAddAttrs = true; }
+
+ this.init.apply(this, arguments);
+ }
+
+ /**
+ * The list of properties which can be configured for
+ * each attribute (e.g. setter, getter, writeOnce, readOnly etc.)
+ *
+ * @property Base._ATTR_CFG
+ * @type Array
+ * @static
+ * @private
+ */
+ Base._ATTR_CFG = Attribute._ATTR_CFG.concat("cloneDefaultValue");
+
+ /**
+ *
+ * The string to be used to identify instances of
+ * this class, for example in prefixing events.
+ *
+ *
+ * Classes extending Base, should define their own
+ * static NAME property, which should be camelCase by
+ * convention (e.g. MyClass.NAME = "myClass";).
+ *
+ * @property Base.NAME
+ * @type String
+ * @static
+ */
+ Base.NAME = "base";
+
+ /**
+ * The default set of attributes which will be available for instances of this class, and
+ * their configuration. In addition to the configuration properties listed by
+ * Attribute's addAttr method, the attribute
+ * can also be configured with a "cloneDefaultValue" property, which defines how the statically
+ * defined value field should be protected ("shallow", "deep" and false are supported values).
+ *
+ * By default if the value is an object literal or an array it will be "shallow" cloned, to
+ * protect the default value.
+ *
+ * @property Base.ATTRS
+ * @type Object
+ * @static
+ */
+ Base.ATTRS = {
+ /**
+ * Flag indicating whether or not this object
+ * has been through the init lifecycle phase.
+ *
+ * @attribute initialized
+ * @readonly
+ * @default false
+ * @type boolean
+ */
+ initialized: {
+ readOnly:true,
+ value:false
+ },
+
+ /**
+ * Flag indicating whether or not this object
+ * has been through the destroy lifecycle phase.
+ *
+ * @attribute destroyed
+ * @readonly
+ * @default false
+ * @type boolean
+ */
+ destroyed: {
+ readOnly:true,
+ value:false
+ }
+ };
+
+ Base.prototype = {
+
+ /**
+ * Init lifecycle method, invoked during construction.
+ * Fires the init event prior to setting up attributes and
+ * invoking initializers for the class hierarchy.
+ *
+ * @method init
+ * @final
+ * @chainable
+ * @param {Object} config Object with configuration property name/value pairs
+ * @return {Base} A reference to this object
+ */
+ init: function(config) {
+
+ /**
+ * The string used to identify the class of this object.
+ *
+ * @deprecated Use this.constructor.NAME
+ * @property name
+ * @type String
+ */
+ this._yuievt.config.prefix = this.name = this.constructor.NAME;
+
+ /**
+ *
+ * Lifecycle event for the init phase, fired prior to initialization.
+ * Invoking the preventDefault() method on the event object provided
+ * to subscribers will prevent initialization from occuring.
+ *
+ *
+ * Subscribers to the "after" momemt of this event, will be notified
+ * after initialization of the object is complete (and therefore
+ * cannot prevent initialization).
+ *
+ *
+ * @event init
+ * @preventable _defInitFn
+ * @param {EventFacade} e Event object, with a cfg property which
+ * refers to the configuration object passed to the constructor.
+ */
+ this.publish(INIT, {
+ queuable:false,
+ defaultFn:this._defInitFn
+ });
+
+ if (config) {
+ if (config.on) {
+ this.on(config.on);
+ }
+ if (config.after) {
+ this.after(config.after);
+ }
+ }
+
+ this.fire(INIT, {cfg: config});
+
+ return this;
+ },
+
+ /**
+ *
+ * Destroy lifecycle method. Fires the destroy
+ * event, prior to invoking destructors for the
+ * class hierarchy.
+ *
+ *
+ * Subscribers to the destroy
+ * event can invoke preventDefault on the event object, to prevent destruction
+ * from proceeding.
+ *
+ * @method destroy
+ * @return {Base} A reference to this object
+ * @final
+ * @chainable
+ */
+ destroy: function() {
+
+ /**
+ *
+ * Lifecycle event for the destroy phase,
+ * fired prior to destruction. Invoking the preventDefault
+ * method on the event object provided to subscribers will
+ * prevent destruction from proceeding.
+ *
+ *
+ * Subscribers to the "after" moment of this event, will be notified
+ * after destruction is complete (and as a result cannot prevent
+ * destruction).
+ *
+ * @event destroy
+ * @preventable _defDestroyFn
+ * @param {EventFacade} e Event object
+ */
+ this.publish(DESTROY, {
+ queuable:false,
+ defaultFn: this._defDestroyFn
+ });
+ this.fire(DESTROY);
+ return this;
+ },
+
+ /**
+ * Default init event handler
+ *
+ * @method _defInitFn
+ * @param {EventFacade} e Event object, with a cfg property which
+ * refers to the configuration object passed to the constructor.
+ * @protected
+ */
+ _defInitFn : function(e) {
+ this._initHierarchy(e.cfg);
+ if (this._initPlugins) {
+ // Need to initPlugins manually, to handle constructor parsing, static Plug parsing
+ this._initPlugins(e.cfg);
+ }
+ this._set(INITIALIZED, true);
+ },
+
+ /**
+ * Default destroy event handler
+ *
+ * @method _defDestroyFn
+ * @param {EventFacade} e Event object
+ * @protected
+ */
+ _defDestroyFn : function(e) {
+ this._destroyHierarchy();
+ if (this._destroyPlugins) {
+ this._destroyPlugins();
+ }
+ this._set(DESTROYED, true);
+ },
+
+ /**
+ * Returns the class hierarchy for this object, with Base being the last class in the array.
+ *
+ * @method _getClasses
+ * @protected
+ * @return {Function[]} An array of classes (constructor functions), making up the class hierarchy for this object.
+ * This value is cached the first time the method, or _getAttrCfgs, is invoked. Subsequent invocations return the
+ * cached value.
+ */
+ _getClasses : function() {
+ if (!this._classes) {
+ this._initHierarchyData();
+ }
+ return this._classes;
+ },
+
+ /**
+ * Returns an aggregated set of attribute configurations, by traversing the class hierarchy.
+ *
+ * @method _getAttrCfgs
+ * @protected
+ * @return {Object} The hash of attribute configurations, aggregated across classes in the hierarchy
+ * This value is cached the first time the method, or _getClasses, is invoked. Subsequent invocations return
+ * the cached value.
+ */
+ _getAttrCfgs : function() {
+ if (!this._attrs) {
+ this._initHierarchyData();
+ }
+ return this._attrs;
+ },
+
+ /**
+ * A helper method used when processing ATTRS across the class hierarchy during
+ * initialization. Returns a disposable object with the attributes defined for
+ * the provided class, extracted from the set of all attributes passed in .
+ *
+ * @method _filterAttrCfs
+ * @private
+ *
+ * @param {Function} clazz The class for which the desired attributes are required.
+ * @param {Object} allCfgs The set of all attribute configurations for this instance.
+ * Attributes will be removed from this set, if they belong to the filtered class, so
+ * that by the time all classes are processed, allCfgs will be empty.
+ *
+ * @return {Object} The set of attributes belonging to the class passed in, in the form
+ * of an object with attribute name/configuration pairs.
+ */
+ _filterAttrCfgs : function(clazz, allCfgs) {
+ var cfgs = null, attr, attrs = clazz.ATTRS;
+
+ if (attrs) {
+ for (attr in attrs) {
+ if (attrs.hasOwnProperty(attr) && allCfgs[attr]) {
+ cfgs = cfgs || {};
+ cfgs[attr] = allCfgs[attr];
+ delete allCfgs[attr];
+ }
+ }
+ }
+
+ return cfgs;
+ },
+
+ /**
+ * A helper method used by _getClasses and _getAttrCfgs, which determines both
+ * the array of classes and aggregate set of attribute configurations
+ * across the class hierarchy for the instance.
+ *
+ * @method _initHierarchyData
+ * @private
+ */
+ _initHierarchyData : function() {
+ var c = this.constructor,
+ classes = [],
+ attrs = [];
+
+ while (c) {
+ // Add to classes
+ classes[classes.length] = c;
+
+ // Add to attributes
+ if (c.ATTRS) {
+ attrs[attrs.length] = c.ATTRS;
+ }
+ c = c.superclass ? c.superclass.constructor : null;
+ }
+
+ this._classes = classes;
+ this._attrs = this._aggregateAttrs(attrs);
+ },
+
+ /**
+ * A helper method, used by _initHierarchyData to aggregate
+ * attribute configuration across the instances class hierarchy.
+ *
+ * The method will potect the attribute configuration value to protect the statically defined
+ * default value in ATTRS if required (if the value is an object literal, array or the
+ * attribute configuration has cloneDefaultValue set to shallow or deep).
+ *
+ * @method _aggregateAttrs
+ * @private
+ * @param {Array} allAttrs An array of ATTRS definitions across classes in the hierarchy
+ * (subclass first, Base last)
+ * @return {Object} The aggregate set of ATTRS definitions for the instance
+ */
+ _aggregateAttrs : function(allAttrs) {
+ var attr,
+ attrs,
+ cfg,
+ val,
+ path,
+ i,
+ clone,
+ cfgProps = Base._ATTR_CFG,
+ aggAttrs = {};
+
+ if (allAttrs) {
+ for (i = allAttrs.length-1; i >= 0; --i) {
+ attrs = allAttrs[i];
+
+ for (attr in attrs) {
+ if (attrs.hasOwnProperty(attr)) {
+
+ // Protect config passed in
+ cfg = Y.mix({}, attrs[attr], true, cfgProps);
+
+ val = cfg.value;
+ clone = cfg.cloneDefaultValue;
+
+ if (val) {
+ if ( (clone === undefined && (OBJECT_CONSTRUCTOR === val.constructor || L.isArray(val))) || clone === DEEP || clone === true) {
+ cfg.value = Y.clone(val);
+ } else if (clone === SHALLOW) {
+ cfg.value = Y.merge(val);
+ }
+ // else if (clone === false), don't clone the static default value.
+ // It's intended to be used by reference.
+ }
+
+ path = null;
+ if (attr.indexOf(DOT) !== -1) {
+ path = attr.split(DOT);
+ attr = path.shift();
+ }
+
+ if (path && aggAttrs[attr] && aggAttrs[attr].value) {
+ O.setValue(aggAttrs[attr].value, path, val);
+ } else if (!path){
+ if (!aggAttrs[attr]) {
+ aggAttrs[attr] = cfg;
+ } else {
+ Y.mix(aggAttrs[attr], cfg, true, cfgProps);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return aggAttrs;
+ },
+
+ /**
+ * Initializes the class hierarchy for the instance, which includes
+ * initializing attributes for each class defined in the class's
+ * static ATTRS property and
+ * invoking the initializer method on the prototype of each class in the hierarchy.
+ *
+ * @method _initHierarchy
+ * @param {Object} userVals Object with configuration property name/value pairs
+ * @private
+ */
+ _initHierarchy : function(userVals) {
+ var lazy = this._lazyAddAttrs,
+ constr,
+ constrProto,
+ ci,
+ ei,
+ el,
+ classes = this._getClasses(),
+ attrCfgs = this._getAttrCfgs();
+
+ for (ci = classes.length-1; ci >= 0; ci--) {
+
+ constr = classes[ci];
+ constrProto = constr.prototype;
+
+ if (constr._yuibuild && constr._yuibuild.exts && !constr._yuibuild.dynamic) {
+ for (ei = 0, el = constr._yuibuild.exts.length; ei < el; ei++) {
+ constr._yuibuild.exts[ei].apply(this, arguments);
+ }
+ }
+
+ this.addAttrs(this._filterAttrCfgs(constr, attrCfgs), userVals, lazy);
+
+ if (constrProto.hasOwnProperty(INITIALIZER)) {
+ constrProto.initializer.apply(this, arguments);
+ }
+ }
+ },
+
+ /**
+ * Destroys the class hierarchy for this instance by invoking
+ * the descructor method on the prototype of each class in the hierarchy.
+ *
+ * @method _destroyHierarchy
+ * @private
+ */
+ _destroyHierarchy : function() {
+ var constr,
+ constrProto,
+ ci, cl,
+ classes = this._getClasses();
+
+ for (ci = 0, cl = classes.length; ci < cl; ci++) {
+ constr = classes[ci];
+ constrProto = constr.prototype;
+ if (constrProto.hasOwnProperty(DESTRUCTOR)) {
+ constrProto.destructor.apply(this, arguments);
+ }
+ }
+ },
+
+ /**
+ * Default toString implementation. Provides the constructor NAME
+ * and the instance ID.
+ *
+ * @method toString
+ * @return {String} String representation for this object
+ */
+ toString: function() {
+ return this.constructor.NAME + "[" + Y.stamp(this) + "]";
+ }
+ };
+
+ // Straightup augment, no wrapper functions
+ Y.mix(Base, Attribute, false, null, 1);
+
+ // Fix constructor
+ Base.prototype.constructor = Base;
+
+ Y.Base = Base;
+
+ // Fix constructor
+ Base.prototype.constructor = Base;
+
+
+}, '3.0.0' ,{requires:['attribute-base']});
+YUI.add('base-pluginhost', function(Y) {
+
+ /**
+ * The base-pluginhost submodule adds Plugin support to Base, by augmenting Base with
+ * Plugin.Host and setting up static (class level) Base.plug and Base.unplug methods.
+ *
+ * @module base
+ * @submodule base-pluginhost
+ * @for Base
+ */
+
+ var Base = Y.Base,
+ PluginHost = Y.Plugin.Host;
+
+ Y.mix(Base, PluginHost, false, null, 1);
+
+ /**
+ * Alias for Plugin.Host.plug. See aliased
+ * method for argument and return value details.
+ *
+ * @method Base.plug
+ * @static
+ */
+ Base.plug = PluginHost.plug;
+
+ /**
+ * Alias for Plugin.Host.unplug. See the
+ * aliased method for argument and return value details.
+ *
+ * @method Base.unplug
+ * @static
+ */
+ Base.unplug = PluginHost.unplug;
+
+
+}, '3.0.0' ,{requires:['base-base', 'pluginhost']});
+YUI.add('base-build', function(Y) {
+
+ /**
+ * The base-build submodule provides Base.build functionality, which
+ * can be used to create custom classes, by aggregating extensions onto
+ * a main class.
+ *
+ * @module base
+ * @submodule base-build
+ * @for Base
+ */
+
+ var Base = Y.Base,
+ L = Y.Lang;
+
+ /**
+ * The build configuration for the Base class.
+ *
+ * Defines the static fields which need to be aggregated
+ * when the Base class is used as the main class passed to
+ * the Base.build method.
+ *
+ * @property Base._buildCfg
+ * @type Object
+ * @static
+ * @final
+ * @private
+ */
+ Base._buildCfg = {
+ aggregates : ["ATTRS", "_PLUG", "_UNPLUG"]
+ };
+
+ /**
+ *
+ * Builds a custom constructor function (class) from the
+ * main function, and array of extension functions (classes)
+ * provided. The NAME field for the constructor function is
+ * defined by the first argument passed in.
+ *
+ *
+ * The cfg object supports the following properties
+ *
+ *
+ *
dynamic <boolean>
+ *
+ *
If true (default), a completely new class
+ * is created which extends the main class, and acts as the
+ * host on which the extension classes are augmented.
+ *
If false, the extensions classes are augmented directly to
+ * the main class, modifying the main class' prototype.
+ *
+ *
aggregates <String[]>
+ *
An array of static property names, which will get aggregated
+ * on to the built class, in addition to the default properties build
+ * will always aggregate as defined by the main class' static _buildCfg
+ * property.
+ *
+ *
+ *
+ * @method Base.build
+ * @static
+ * @param {Function} name The name of the new class. Used to defined the NAME property for the new class.
+ * @param {Function} main The main class on which to base the built class
+ * @param {Function[]} extensions The set of extension classes which will be
+ * augmented/aggregated to the built class.
+ * @param {Object} cfg Optional. Build configuration for the class (see description).
+ * @return {Function} A custom class, created from the provided main and extension classes
+ */
+ Base.build = function(name, main, extensions, cfg) {
+
+ var build = Base.build,
+ builtClass = build._getClass(main, cfg),
+ aggregates = build._getAggregates(main, cfg),
+ dynamic = builtClass._yuibuild.dynamic,
+ i, l, val, extClass;
+
+ // Shallow isolate aggregates
+ if (dynamic) {
+ if (aggregates) {
+ for (i = 0, l = aggregates.length; i < l; ++i) {
+ val = aggregates[i];
+ if (main.hasOwnProperty(val)) {
+ builtClass[val] = L.isArray(main[val]) ? [] : {};
+ }
+ }
+ Y.aggregate(builtClass, main, true, aggregates);
+ }
+ }
+
+ // Augment/Aggregate
+ for (i = 0, l = extensions.length; i < l; i++) {
+ extClass = extensions[i];
+
+ if (aggregates) {
+ Y.aggregate(builtClass, extClass, true, aggregates);
+ }
+
+ // Old augment
+ Y.mix(builtClass, extClass, true, null, 1);
+
+ builtClass._yuibuild.exts.push(extClass);
+ }
+
+ builtClass.prototype.hasImpl = build._hasImpl;
+
+ if (dynamic) {
+ builtClass.NAME = name;
+ builtClass.prototype.constructor = builtClass;
+ }
+
+ return builtClass;
+ };
+
+ Y.mix(Base.build, {
+
+ _template: function(main) {
+
+ function BuiltClass() {
+
+ BuiltClass.superclass.constructor.apply(this, arguments);
+
+ var f = BuiltClass._yuibuild.exts,
+ l = f.length,
+ i;
+
+ for (i = 0; i < l; i++) {
+ f[i].apply(this, arguments);
+ }
+
+ return this;
+ }
+ Y.extend(BuiltClass, main);
+
+ return BuiltClass;
+ },
+
+ _hasImpl : function(extClass) {
+ var classes = this._getClasses();
+ for (var i = 0, l = classes.length; i < l; i++) {
+ var cls = classes[i];
+
+ if (cls._yuibuild) {
+ var exts = cls._yuibuild.exts,
+ ll = exts.length,
+ j;
+
+ for (j = 0; j < ll; j++) {
+ if (exts[j] === extClass) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ },
+
+ _getClass : function(main, cfg) {
+
+ var dynamic = (cfg && false === cfg.dynamic) ? false : true,
+ builtClass = (dynamic) ? Base.build._template(main) : main;
+
+ builtClass._yuibuild = {
+ id: null,
+ exts : [],
+ dynamic : dynamic
+ };
+
+ return builtClass;
+ },
+
+ _getAggregates : function(main, cfg) {
+ var aggr = [],
+ cfgAggr = (cfg && cfg.aggregates),
+ c = main,
+ classAggr;
+
+ while (c && c.prototype) {
+ classAggr = c._buildCfg && c._buildCfg.aggregates;
+ if (classAggr) {
+ aggr = aggr.concat(classAggr);
+ }
+ c = c.superclass ? c.superclass.constructor : null;
+ }
+
+ if (cfgAggr) {
+ aggr = aggr.concat(cfgAggr);
+ }
+
+ return aggr;
+ }
+ });
+
+
+}, '3.0.0' ,{requires:['base-base']});
+
+
+YUI.add('base', function(Y){}, '3.0.0' ,{use:['base-base', 'base-pluginhost', 'base-build']});
+
diff --git a/lib/yui/3.0.0/cache/cache-debug.js b/lib/yui/3.0.0/cache/cache-debug.js
new file mode 100644
index 0000000000..d9d7ca3cc0
--- /dev/null
+++ b/lib/yui/3.0.0/cache/cache-debug.js
@@ -0,0 +1,366 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('cache', function(Y) {
+
+/**
+ * The Cache utility provides a common configurable interface for components to
+ * cache and retrieve data from a local JavaScript struct.
+ *
+ * @module cache
+ */
+var LANG = Y.Lang,
+
+/**
+ * Base class for the YUI Cache utility.
+ * @class Cache
+ * @extends Plugin.Base
+ * @constructor
+ */
+Cache = function() {
+ Cache.superclass.constructor.apply(this, arguments);
+};
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // Cache static properties
+ //
+ /////////////////////////////////////////////////////////////////////////////
+Y.mix(Cache, {
+ /**
+ * The namespace for the plugin. This will be the property on the host which
+ * references the plugin instance.
+ *
+ * @property NS
+ * @type String
+ * @static
+ * @final
+ * @value "cache"
+ */
+ NS: "cache",
+
+
+ /**
+ * Class name.
+ *
+ * @property NAME
+ * @type String
+ * @static
+ * @final
+ * @value "cache"
+ */
+ NAME: "cache",
+
+
+ ATTRS: {
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // Cache Attributes
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * @attribute max
+ * @description Maximum number of entries the Cache can hold.
+ * Set to 0 to turn off caching.
+ * @type Number
+ * @default 0
+ */
+ max: {
+ value: 0,
+ validator: function(value) {
+ return (LANG.isNumber(value));
+ },
+ setter: function(value) {
+ // If the cache is full, make room by removing stalest element (index=0)
+ var entries = this._entries;
+ if(value > 0) {
+ if(entries) {
+ while(entries.length > value) {
+ entries.shift();
+ }
+ }
+ }
+ else {
+ this._entries = [];
+ }
+ return value;
+ }
+ },
+
+ /**
+ * @attribute size
+ * @description Number of entries currently cached.
+ * @type Number
+ */
+ size: {
+ readOnly: true,
+ getter: function() {
+ return this._entries.length;
+ }
+ },
+
+ /**
+ * @attribute uniqueKeys
+ * @description Validate uniqueness of stored keys. Default is false and
+ * is more performant.
+ * @type Number
+ */
+ uniqueKeys: {
+ value: false,
+ validator: function(value) {
+ return (LANG.isBoolean(value));
+ }
+ },
+
+ /**
+ * @attribute entries
+ * @description Cached entries.
+ * @type Array
+ */
+ entries: {
+ readOnly: true,
+ getter: function() {
+ return this._entries;
+ }
+ }
+ }
+});
+
+Y.extend(Cache, Y.Plugin.Base, {
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // Cache private properties
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Array of request/response objects indexed chronologically.
+ *
+ * @property _entries
+ * @type Object[]
+ * @private
+ */
+ _entries: null,
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // Cache private methods
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * @method initializer
+ * @description Internal init() handler.
+ * @param config {Object} Config object.
+ * @private
+ */
+ initializer: function(config) {
+
+ /**
+ * @event add
+ * @description Fired when an entry is added.
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
entry (Object)
The cached entry.
+ *
+ * @preventable _defAddFn
+ */
+ this.publish("add", {defaultFn: this._defAddFn});
+
+ /**
+ * @event flush
+ * @description Fired when the cache is flushed.
+ * @param e {Event.Facade} Event Facade object.
+ * @preventable _defFlushFn
+ */
+ this.publish("flush", {defaultFn: this._defFlushFn});
+
+ /**
+ * @event request
+ * @description Fired when an entry is requested from the cache.
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
request (Object)
The request object.
+ *
+ */
+
+ /**
+ * @event retrieve
+ * @description Fired when an entry is retrieved from the cache.
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ * @protected
+ */
+ _defAddFn: function(e) {
+ var entries = this._entries,
+ max = this.get("max"),
+ entry = e.entry;
+
+ if(this.get("uniqueKeys") && (this.retrieve(e.entry.request))) {
+ entries.shift();
+ }
+
+
+ // If the cache at or over capacity, make room by removing stalest element (index=0)
+ while(entries.length>=max) {
+ entries.shift();
+ }
+
+ // Add entry to cache in the newest position, at the end of the array
+ entries[entries.length] = entry;
+ Y.log("Cached entry: " + Y.dump(entry), "info", "cache");
+ },
+
+ /**
+ * Flushes cache.
+ *
+ * @method _defFlushFn
+ * @param e {Event.Facade} Event Facade object.
+ * @protected
+ */
+ _defFlushFn: function(e) {
+ this._entries = [];
+ Y.log("Cache flushed", "info", "cache");
+ },
+
+ /**
+ * Default overridable method compares current request with given cache entry.
+ * Returns true if current request matches the cached request, otherwise
+ * false. Implementers should override this method to customize the
+ * cache-matching algorithm.
+ *
+ * @method _isMatch
+ * @param request {Object} Request object.
+ * @param entry {Object} Cached entry.
+ * @return {Boolean} True if current request matches given cached request, false otherwise.
+ * @protected
+ */
+ _isMatch: function(request, entry) {
+ return (request === entry.request);
+ },
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // Cache public methods
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Adds a new entry to the cache of the format
+ * {request:request, response:response, payload:payload}.
+ * If cache is full, evicts the stalest entry before adding the new one.
+ *
+ * @method add
+ * @param request {Object} Request value.
+ * @param response {Object} Response value.
+ * @param payload {Object} (optional) Arbitrary data payload.
+ */
+ add: function(request, response, payload) {
+ if(this.get("entries") && (this.get("max")>0) &&
+ (LANG.isValue(request) || LANG.isNull(request) || LANG.isUndefined(request))) {
+ this.fire("add", {entry: {request:request, response:response, payload:payload}});
+ }
+ else {
+ Y.log("Could not add " + Y.dump(response) + " to cache for " + Y.dump(request), "info", "cache");
+ }
+ },
+
+ /**
+ * Flushes cache.
+ *
+ * @method flush
+ */
+ flush: function() {
+ this.fire("flush");
+ },
+
+ /**
+ * Retrieves cached entry for given request, if available, and refreshes
+ * entry in the cache. Returns null if there is no cache match.
+ *
+ * @method retrieve
+ * @param request {Object} Request object.
+ * @return {Object} Cached entry object with the properties request, response, and payload, or null.
+ */
+ retrieve: function(request) {
+ // If cache is enabled...
+ var entries = this._entries,
+ length = entries.length,
+ entry = null,
+ i = length-1;
+
+ if((this.get("max") > 0) && (length > 0)) {
+ this.fire("request", {request: request});
+
+ // Loop through each cached entry starting from the newest
+ for(; i >= 0; i--) {
+ entry = entries[i];
+
+ // Execute matching function
+ if(this._isMatch(request, entry)) {
+ this.fire("retrieve", {entry: entry});
+
+ // Refresh the position of the cache hit
+ if(i < length-1) {
+ // Remove element from its original location
+ entries.splice(i,1);
+ // Add as newest
+ entries[entries.length] = entry;
+ Y.log("Refreshed cache entry: " + Y.dump(entry) +
+ " for request: " + Y.dump(request), "info", "cache");
+ }
+
+ Y.log("Retrieved cached response: " + Y.dump(entry) +
+ " for request: " + Y.dump(request), "info", "cache");
+ return entry;
+ }
+ }
+ }
+ return null;
+ }
+});
+
+Y.Cache = Cache;
+
+
+
+
+}, '3.0.0' ,{requires:['plugin']});
diff --git a/lib/yui/3.0.0/cache/cache-min.js b/lib/yui/3.0.0/cache/cache-min.js
new file mode 100644
index 0000000000..e776f1154b
--- /dev/null
+++ b/lib/yui/3.0.0/cache/cache-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("cache",function(C){var A=C.Lang,B=function(){B.superclass.constructor.apply(this,arguments);};C.mix(B,{NS:"cache",NAME:"cache",ATTRS:{max:{value:0,validator:function(D){return(A.isNumber(D));},setter:function(E){var D=this._entries;if(E>0){if(D){while(D.length>E){D.shift();}}}else{this._entries=[];}return E;}},size:{readOnly:true,getter:function(){return this._entries.length;}},uniqueKeys:{value:false,validator:function(D){return(A.isBoolean(D));}},entries:{readOnly:true,getter:function(){return this._entries;}}}});C.extend(B,C.Plugin.Base,{_entries:null,initializer:function(D){this.publish("add",{defaultFn:this._defAddFn});this.publish("flush",{defaultFn:this._defFlushFn});this._entries=[];},destructor:function(){this._entries=null;},_defAddFn:function(G){var E=this._entries,D=this.get("max"),F=G.entry;if(this.get("uniqueKeys")&&(this.retrieve(G.entry.request))){E.shift();}while(E.length>=D){E.shift();}E[E.length]=F;},_defFlushFn:function(D){this._entries=[];},_isMatch:function(E,D){return(E===D.request);},add:function(E,D,F){if(this.get("entries")&&(this.get("max")>0)&&(A.isValue(E)||A.isNull(E)||A.isUndefined(E))){this.fire("add",{entry:{request:E,response:D,payload:F}});}else{}},flush:function(){this.fire("flush");},retrieve:function(H){var D=this._entries,G=D.length,F=null,E=G-1;if((this.get("max")>0)&&(G>0)){this.fire("request",{request:H});for(;E>=0;E--){F=D[E];if(this._isMatch(H,F)){this.fire("retrieve",{entry:F});if(E 0) {
+ if(entries) {
+ while(entries.length > value) {
+ entries.shift();
+ }
+ }
+ }
+ else {
+ this._entries = [];
+ }
+ return value;
+ }
+ },
+
+ /**
+ * @attribute size
+ * @description Number of entries currently cached.
+ * @type Number
+ */
+ size: {
+ readOnly: true,
+ getter: function() {
+ return this._entries.length;
+ }
+ },
+
+ /**
+ * @attribute uniqueKeys
+ * @description Validate uniqueness of stored keys. Default is false and
+ * is more performant.
+ * @type Number
+ */
+ uniqueKeys: {
+ value: false,
+ validator: function(value) {
+ return (LANG.isBoolean(value));
+ }
+ },
+
+ /**
+ * @attribute entries
+ * @description Cached entries.
+ * @type Array
+ */
+ entries: {
+ readOnly: true,
+ getter: function() {
+ return this._entries;
+ }
+ }
+ }
+});
+
+Y.extend(Cache, Y.Plugin.Base, {
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // Cache private properties
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Array of request/response objects indexed chronologically.
+ *
+ * @property _entries
+ * @type Object[]
+ * @private
+ */
+ _entries: null,
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // Cache private methods
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * @method initializer
+ * @description Internal init() handler.
+ * @param config {Object} Config object.
+ * @private
+ */
+ initializer: function(config) {
+
+ /**
+ * @event add
+ * @description Fired when an entry is added.
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
entry (Object)
The cached entry.
+ *
+ * @preventable _defAddFn
+ */
+ this.publish("add", {defaultFn: this._defAddFn});
+
+ /**
+ * @event flush
+ * @description Fired when the cache is flushed.
+ * @param e {Event.Facade} Event Facade object.
+ * @preventable _defFlushFn
+ */
+ this.publish("flush", {defaultFn: this._defFlushFn});
+
+ /**
+ * @event request
+ * @description Fired when an entry is requested from the cache.
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
request (Object)
The request object.
+ *
+ */
+
+ /**
+ * @event retrieve
+ * @description Fired when an entry is retrieved from the cache.
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ * @protected
+ */
+ _defAddFn: function(e) {
+ var entries = this._entries,
+ max = this.get("max"),
+ entry = e.entry;
+
+ if(this.get("uniqueKeys") && (this.retrieve(e.entry.request))) {
+ entries.shift();
+ }
+
+
+ // If the cache at or over capacity, make room by removing stalest element (index=0)
+ while(entries.length>=max) {
+ entries.shift();
+ }
+
+ // Add entry to cache in the newest position, at the end of the array
+ entries[entries.length] = entry;
+ },
+
+ /**
+ * Flushes cache.
+ *
+ * @method _defFlushFn
+ * @param e {Event.Facade} Event Facade object.
+ * @protected
+ */
+ _defFlushFn: function(e) {
+ this._entries = [];
+ },
+
+ /**
+ * Default overridable method compares current request with given cache entry.
+ * Returns true if current request matches the cached request, otherwise
+ * false. Implementers should override this method to customize the
+ * cache-matching algorithm.
+ *
+ * @method _isMatch
+ * @param request {Object} Request object.
+ * @param entry {Object} Cached entry.
+ * @return {Boolean} True if current request matches given cached request, false otherwise.
+ * @protected
+ */
+ _isMatch: function(request, entry) {
+ return (request === entry.request);
+ },
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // Cache public methods
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Adds a new entry to the cache of the format
+ * {request:request, response:response, payload:payload}.
+ * If cache is full, evicts the stalest entry before adding the new one.
+ *
+ * @method add
+ * @param request {Object} Request value.
+ * @param response {Object} Response value.
+ * @param payload {Object} (optional) Arbitrary data payload.
+ */
+ add: function(request, response, payload) {
+ if(this.get("entries") && (this.get("max")>0) &&
+ (LANG.isValue(request) || LANG.isNull(request) || LANG.isUndefined(request))) {
+ this.fire("add", {entry: {request:request, response:response, payload:payload}});
+ }
+ else {
+ }
+ },
+
+ /**
+ * Flushes cache.
+ *
+ * @method flush
+ */
+ flush: function() {
+ this.fire("flush");
+ },
+
+ /**
+ * Retrieves cached entry for given request, if available, and refreshes
+ * entry in the cache. Returns null if there is no cache match.
+ *
+ * @method retrieve
+ * @param request {Object} Request object.
+ * @return {Object} Cached entry object with the properties request, response, and payload, or null.
+ */
+ retrieve: function(request) {
+ // If cache is enabled...
+ var entries = this._entries,
+ length = entries.length,
+ entry = null,
+ i = length-1;
+
+ if((this.get("max") > 0) && (length > 0)) {
+ this.fire("request", {request: request});
+
+ // Loop through each cached entry starting from the newest
+ for(; i >= 0; i--) {
+ entry = entries[i];
+
+ // Execute matching function
+ if(this._isMatch(request, entry)) {
+ this.fire("retrieve", {entry: entry});
+
+ // Refresh the position of the cache hit
+ if(i < length-1) {
+ // Remove element from its original location
+ entries.splice(i,1);
+ // Add as newest
+ entries[entries.length] = entry;
+ }
+
+ return entry;
+ }
+ }
+ }
+ return null;
+ }
+});
+
+Y.Cache = Cache;
+
+
+
+
+}, '3.0.0' ,{requires:['plugin']});
diff --git a/lib/yui/3.0.0/classnamemanager/classnamemanager-debug.js b/lib/yui/3.0.0/classnamemanager/classnamemanager-debug.js
new file mode 100644
index 0000000000..b2c5d25f4e
--- /dev/null
+++ b/lib/yui/3.0.0/classnamemanager/classnamemanager-debug.js
@@ -0,0 +1,87 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('classnamemanager', function(Y) {
+
+/**
+* Contains a singleton (ClassNameManager) that enables easy creation and caching of
+* prefixed class names.
+* @module classnamemanager
+*/
+
+/**
+ * A singleton class providing:
+ *
+ *
+ *
Easy creation of prefixed class names
+ *
Caching of previously created class names for improved performance.
+ *
+ *
+ * @class ClassNameManager
+ * @static
+ */
+
+// String constants
+var CLASS_NAME_PREFIX = 'classNamePrefix',
+ CLASS_NAME_DELIMITER = 'classNameDelimiter',
+ CONFIG = Y.config;
+
+// Global config
+
+/**
+ * Configuration property indicating the prefix for all CSS class names in this YUI instance.
+ *
+ * @property Y.config.classNamePrefix
+ * @type {String}
+ * @default "yui"
+ * @static
+ */
+CONFIG[CLASS_NAME_PREFIX] = CONFIG[CLASS_NAME_PREFIX] || 'yui';
+
+/**
+ * Configuration property indicating the delimiter used to compose all CSS class names in
+ * this YUI instance.
+ *
+ * @property Y.config.classNameDelimiter
+ * @type {String}
+ * @default "-"
+ * @static
+ */
+CONFIG[CLASS_NAME_DELIMITER] = CONFIG[CLASS_NAME_DELIMITER] || '-';
+
+Y.ClassNameManager = function () {
+
+ var sPrefix = CONFIG[CLASS_NAME_PREFIX],
+ sDelimiter = CONFIG[CLASS_NAME_DELIMITER];
+
+ return {
+
+ /**
+ * Returns a class name prefixed with the the value of the
+ * Y.config.classNamePrefix attribute + the provided strings.
+ * Uses the Y.config.classNameDelimiter attribute to delimit the
+ * provided strings. E.g. Y.ClassNameManager.getClassName('foo','bar'); // yui-foo-bar
+ *
+ * @method getClassName
+ * @param {String}+ one or more classname bits to be joined and prefixed
+ */
+ getClassName: Y.cached(function (c, x) {
+
+ var sClass = sPrefix + sDelimiter +
+ // ((x) ? Y.Array(arguments, 0, true).join(sDelimiter) : c);
+ ((x) ? Array.prototype.join.call(arguments, sDelimiter) : c);
+
+ return sClass.replace(/\s/g, '');
+
+ })
+
+ };
+
+}();
+
+
+}, '3.0.0' );
diff --git a/lib/yui/3.0.0/classnamemanager/classnamemanager-min.js b/lib/yui/3.0.0/classnamemanager/classnamemanager-min.js
new file mode 100644
index 0000000000..15c4019e67
--- /dev/null
+++ b/lib/yui/3.0.0/classnamemanager/classnamemanager-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("classnamemanager",function(C){var B="classNamePrefix",D="classNameDelimiter",A=C.config;A[B]=A[B]||"yui";A[D]=A[D]||"-";C.ClassNameManager=function(){var E=A[B],F=A[D];return{getClassName:C.cached(function(I,G){var H=E+F+((G)?Array.prototype.join.call(arguments,F):I);return H.replace(/\s/g,"");})};}();},"3.0.0");
\ No newline at end of file
diff --git a/lib/yui/3.0.0/classnamemanager/classnamemanager.js b/lib/yui/3.0.0/classnamemanager/classnamemanager.js
new file mode 100644
index 0000000000..b2c5d25f4e
--- /dev/null
+++ b/lib/yui/3.0.0/classnamemanager/classnamemanager.js
@@ -0,0 +1,87 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('classnamemanager', function(Y) {
+
+/**
+* Contains a singleton (ClassNameManager) that enables easy creation and caching of
+* prefixed class names.
+* @module classnamemanager
+*/
+
+/**
+ * A singleton class providing:
+ *
+ *
+ *
Easy creation of prefixed class names
+ *
Caching of previously created class names for improved performance.
+ *
+ *
+ * @class ClassNameManager
+ * @static
+ */
+
+// String constants
+var CLASS_NAME_PREFIX = 'classNamePrefix',
+ CLASS_NAME_DELIMITER = 'classNameDelimiter',
+ CONFIG = Y.config;
+
+// Global config
+
+/**
+ * Configuration property indicating the prefix for all CSS class names in this YUI instance.
+ *
+ * @property Y.config.classNamePrefix
+ * @type {String}
+ * @default "yui"
+ * @static
+ */
+CONFIG[CLASS_NAME_PREFIX] = CONFIG[CLASS_NAME_PREFIX] || 'yui';
+
+/**
+ * Configuration property indicating the delimiter used to compose all CSS class names in
+ * this YUI instance.
+ *
+ * @property Y.config.classNameDelimiter
+ * @type {String}
+ * @default "-"
+ * @static
+ */
+CONFIG[CLASS_NAME_DELIMITER] = CONFIG[CLASS_NAME_DELIMITER] || '-';
+
+Y.ClassNameManager = function () {
+
+ var sPrefix = CONFIG[CLASS_NAME_PREFIX],
+ sDelimiter = CONFIG[CLASS_NAME_DELIMITER];
+
+ return {
+
+ /**
+ * Returns a class name prefixed with the the value of the
+ * Y.config.classNamePrefix attribute + the provided strings.
+ * Uses the Y.config.classNameDelimiter attribute to delimit the
+ * provided strings. E.g. Y.ClassNameManager.getClassName('foo','bar'); // yui-foo-bar
+ *
+ * @method getClassName
+ * @param {String}+ one or more classname bits to be joined and prefixed
+ */
+ getClassName: Y.cached(function (c, x) {
+
+ var sClass = sPrefix + sDelimiter +
+ // ((x) ? Y.Array(arguments, 0, true).join(sDelimiter) : c);
+ ((x) ? Array.prototype.join.call(arguments, sDelimiter) : c);
+
+ return sClass.replace(/\s/g, '');
+
+ })
+
+ };
+
+}();
+
+
+}, '3.0.0' );
diff --git a/lib/yui/3.0.0/collection/collection-debug.js b/lib/yui/3.0.0/collection/collection-debug.js
new file mode 100644
index 0000000000..d7fdeea14d
--- /dev/null
+++ b/lib/yui/3.0.0/collection/collection-debug.js
@@ -0,0 +1,294 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('collection', function(Y) {
+
+/**
+ * Collection utilities beyond what is provided in the YUI core
+ * @module collection
+ */
+
+var L = Y.Lang, Native = Array.prototype, A = Y.Array;
+
+/**
+ * Adds the following array utilities to the YUI instance
+ * (Y.Array). This is in addition to the methods provided
+ * in the core.
+ * @class YUI~array~extras
+ */
+
+/**
+ * Returns the index of the last item in the array
+ * that contains the specified value, -1 if the
+ * value isn't found.
+ * method Array.lastIndexOf
+ * @static
+ * @param a {Array} the array to search
+ * @param val the value to search for
+ * @return {int} the index of hte item that contains the value or -1
+ */
+A.lastIndexOf = (Native.lastIndexOf) ?
+ function(a ,val) {
+ return a.lastIndexOf(val);
+ } :
+ function(a, val) {
+ for (var i=a.length-1; i>=0; i=i-1) {
+ if (a[i] === val) {
+ break;
+ }
+ }
+ return i;
+ };
+
+/**
+ * Returns a copy of the array with the duplicate entries removed
+ * @method Array.unique
+ * @static
+ * @param a {Array} the array to find the subset of uniques for
+ * @param sort {bool} flag to denote if the array is sorted or not. Defaults to false, the more general operation
+ * @return {Array} a copy of the array with duplicate entries removed
+ */
+A.unique = function(a, sort) {
+ var b = a.slice(), i = 0, n = -1, item = null;
+
+ while (i < b.length) {
+ item = b[i];
+ while ((n = b.lastIndexOf(item)) !== i) {
+ b.splice(n, 1);
+ }
+ i += 1;
+ }
+
+ // Note: the sort option doesn't really belong here... I think it was added
+ // because there was a way to fast path the two operations together. That
+ // implementation was not working, so I replaced it with the following.
+ // Leaving it in so that the API doesn't get broken.
+ if (sort) {
+ if (L.isNumber(b[0])) {
+ b.sort(A.numericSort);
+ } else {
+ b.sort();
+ }
+ }
+
+ return b;
+};
+
+/**
+* Executes the supplied function on each item in the array.
+* Returns a new array containing the items that the supplied
+* function returned true for.
+* @method Array.filter
+* @param a {Array} the array to iterate
+* @param f {Function} the function to execute on each item
+* @param o Optional context object
+* @static
+* @return {Array} The items on which the supplied function
+* returned true. If no items matched an empty array is
+* returned.
+*/
+A.filter = (Native.filter) ?
+ function(a, f, o) {
+ return Native.filter.call(a, f, o);
+ } :
+ function(a, f, o) {
+ var results = [];
+ A.each(a, function(item, i, a) {
+ if (f.call(o, item, i, a)) {
+ results.push(item);
+ }
+ });
+
+ return results;
+ };
+
+/**
+* The inverse of filter. Executes the supplied function on each item.
+* Returns a new array containing the items that the supplied
+* function returned *false* for.
+* @method Array.reject
+* @param a {Array} the array to iterate
+* @param f {Function} the function to execute on each item
+* @param o Optional context object
+* @static
+* @return {Array} The items on which the supplied function
+* returned false.
+*/
+A.reject = function(a, f, o) {
+ return A.filter(a, function(item, i, a) {
+ return !f.call(o, item, i, a);
+ });
+};
+
+/**
+* Executes the supplied function on each item in the array.
+* @method Array.every
+* @param a {Array} the array to iterate
+* @param f {Function} the function to execute on each item
+* @param o Optional context object
+* @static
+* @return {boolean} true if every item in the array returns true
+* from the supplied function.
+*/
+A.every = (Native.every) ?
+ function(a, f, o) {
+ return Native.every.call(a,f,o);
+ } :
+ function(a, f, o) {
+ var l = a.length;
+ for (var i = 0; i < l; i=i+1) {
+ if (!f.call(o, a[i], i, a)) {
+ return false;
+ }
+ }
+
+ return true;
+ };
+
+/**
+* Executes the supplied function on each item in the array.
+* @method Array.map
+* @param a {Array} the array to iterate
+* @param f {Function} the function to execute on each item
+* @param o Optional context object
+* @static
+* @return {Array} A new array containing the return value
+* of the supplied function for each item in the original
+* array.
+*/
+A.map = (Native.map) ?
+ function(a, f, o) {
+ return Native.map.call(a, f, o);
+ } :
+ function(a, f, o) {
+ var results = [];
+ A.each(a, function(item, i, a) {
+ results.push(f.call(o, item, i, a));
+ });
+ return results;
+ };
+
+
+/**
+* Executes the supplied function on each item in the array.
+* Reduce "folds" the array into a single value.
+* @method Array.reduce
+* @param a {Array} the array to iterate
+* @param init The initial value to start from
+* @param f {Function} the function to execute on each item. It
+* is responsible for returning the updated value of the
+* computation.
+* @param o Optional context object
+* @static
+* @return A value that results from iteratively applying the
+* supplied function to each element in the array.
+*/
+A.reduce = (Native.reduce) ?
+ function(a, init, f, o) {
+ //Firefox's Array.reduce does not allow inclusion of a
+ // thisObject, so we need to implement it manually
+ return Native.reduce.call(a, function(init, item, i, a) {
+ return f.call(o, init, item, i, a);
+ }, init);
+ } :
+ function(a, init, f, o) {
+ var r = init;
+ A.each(a, function (item, i, a) {
+ r = f.call(o, r, item, i, a);
+ });
+ return r;
+ };
+
+
+/**
+* Executes the supplied function on each item in the array,
+* searching for the first item that matches the supplied
+* function.
+* @method Array.find
+* @param a {Array} the array to search
+* @param f {Function} the function to execute on each item.
+* Iteration is stopped as soon as this function returns true
+* on an item.
+* @param o Optional context object
+* @static
+* @return {object} the first item that the supplied function
+* returns true for, or null if it never returns true
+*/
+A.find = function(a, f, o) {
+ var l = a.length;
+ for(var i=0; i < l; i++) {
+ if (f.call(o, a[i], i, a)) {
+ return a[i];
+ }
+ }
+ return null;
+};
+
+/**
+* Iterates over an array, returning a new array of all the elements
+* that match the supplied regular expression
+* @method Array.grep
+* @param a {Array} a collection to iterate over
+* @param pattern {RegExp} The regular expression to test against
+* each item
+* @static
+* @return {Array} All the items in the collection that
+* produce a match against the supplied regular expression.
+* If no items match, an empty array is returned.
+*/
+A.grep = function (a, pattern) {
+ return A.filter(a, function (item, index) {
+ return pattern.test(item);
+ });
+};
+
+
+/**
+* Partitions an array into two new arrays, one with the items
+* that match the supplied function, and one with the items that
+* do not.
+* @method Array.partition
+* @param a {Array} a collection to iterate over
+* @paran f {Function} a function that will receive each item
+* in the collection and its index.
+* @param o Optional execution context of f.
+* @static
+* @return An object with two members, 'matches' and 'rejects',
+* that are arrays containing the items that were selected or
+* rejected by the test function (or an empty array).
+*/
+A.partition = function (a, f, o) {
+ var results = {matches: [], rejects: []};
+ A.each(a, function (item, index) {
+ var set = f.call(o, item, index, a) ? results.matches : results.rejects;
+ set.push(item);
+ });
+ return results;
+};
+
+/**
+* Creates an array of arrays by pairing the corresponding
+* elements of two arrays together into a new array.
+* @method Array.zip
+* @param a {Array} a collection to iterate over
+* @param a2 {Array} another collection whose members will be
+* paired with members of the first parameter
+* @static
+* @return An array of arrays formed by pairing each element
+* of the first collection with an item in the second collection
+* having the corresponding index.
+*/
+A.zip = function (a, a2) {
+ var results = [];
+ A.each(a, function (item, index) {
+ results.push([item, a2[index]]);
+ });
+ return results;
+};
+
+
+}, '3.0.0' );
diff --git a/lib/yui/3.0.0/collection/collection-min.js b/lib/yui/3.0.0/collection/collection-min.js
new file mode 100644
index 0000000000..7ce8dbeb69
--- /dev/null
+++ b/lib/yui/3.0.0/collection/collection-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("collection",function(E){var C=E.Lang,D=Array.prototype,B=E.Array;B.lastIndexOf=(D.lastIndexOf)?function(A,F){return A.lastIndexOf(F);}:function(A,G){for(var F=A.length-1;F>=0;F=F-1){if(A[F]===G){break;}}return F;};B.unique=function(F,H){var A=F.slice(),G=0,J=-1,I=null;while(G=0; i=i-1) {
+ if (a[i] === val) {
+ break;
+ }
+ }
+ return i;
+ };
+
+/**
+ * Returns a copy of the array with the duplicate entries removed
+ * @method Array.unique
+ * @static
+ * @param a {Array} the array to find the subset of uniques for
+ * @param sort {bool} flag to denote if the array is sorted or not. Defaults to false, the more general operation
+ * @return {Array} a copy of the array with duplicate entries removed
+ */
+A.unique = function(a, sort) {
+ var b = a.slice(), i = 0, n = -1, item = null;
+
+ while (i < b.length) {
+ item = b[i];
+ while ((n = b.lastIndexOf(item)) !== i) {
+ b.splice(n, 1);
+ }
+ i += 1;
+ }
+
+ // Note: the sort option doesn't really belong here... I think it was added
+ // because there was a way to fast path the two operations together. That
+ // implementation was not working, so I replaced it with the following.
+ // Leaving it in so that the API doesn't get broken.
+ if (sort) {
+ if (L.isNumber(b[0])) {
+ b.sort(A.numericSort);
+ } else {
+ b.sort();
+ }
+ }
+
+ return b;
+};
+
+/**
+* Executes the supplied function on each item in the array.
+* Returns a new array containing the items that the supplied
+* function returned true for.
+* @method Array.filter
+* @param a {Array} the array to iterate
+* @param f {Function} the function to execute on each item
+* @param o Optional context object
+* @static
+* @return {Array} The items on which the supplied function
+* returned true. If no items matched an empty array is
+* returned.
+*/
+A.filter = (Native.filter) ?
+ function(a, f, o) {
+ return Native.filter.call(a, f, o);
+ } :
+ function(a, f, o) {
+ var results = [];
+ A.each(a, function(item, i, a) {
+ if (f.call(o, item, i, a)) {
+ results.push(item);
+ }
+ });
+
+ return results;
+ };
+
+/**
+* The inverse of filter. Executes the supplied function on each item.
+* Returns a new array containing the items that the supplied
+* function returned *false* for.
+* @method Array.reject
+* @param a {Array} the array to iterate
+* @param f {Function} the function to execute on each item
+* @param o Optional context object
+* @static
+* @return {Array} The items on which the supplied function
+* returned false.
+*/
+A.reject = function(a, f, o) {
+ return A.filter(a, function(item, i, a) {
+ return !f.call(o, item, i, a);
+ });
+};
+
+/**
+* Executes the supplied function on each item in the array.
+* @method Array.every
+* @param a {Array} the array to iterate
+* @param f {Function} the function to execute on each item
+* @param o Optional context object
+* @static
+* @return {boolean} true if every item in the array returns true
+* from the supplied function.
+*/
+A.every = (Native.every) ?
+ function(a, f, o) {
+ return Native.every.call(a,f,o);
+ } :
+ function(a, f, o) {
+ var l = a.length;
+ for (var i = 0; i < l; i=i+1) {
+ if (!f.call(o, a[i], i, a)) {
+ return false;
+ }
+ }
+
+ return true;
+ };
+
+/**
+* Executes the supplied function on each item in the array.
+* @method Array.map
+* @param a {Array} the array to iterate
+* @param f {Function} the function to execute on each item
+* @param o Optional context object
+* @static
+* @return {Array} A new array containing the return value
+* of the supplied function for each item in the original
+* array.
+*/
+A.map = (Native.map) ?
+ function(a, f, o) {
+ return Native.map.call(a, f, o);
+ } :
+ function(a, f, o) {
+ var results = [];
+ A.each(a, function(item, i, a) {
+ results.push(f.call(o, item, i, a));
+ });
+ return results;
+ };
+
+
+/**
+* Executes the supplied function on each item in the array.
+* Reduce "folds" the array into a single value.
+* @method Array.reduce
+* @param a {Array} the array to iterate
+* @param init The initial value to start from
+* @param f {Function} the function to execute on each item. It
+* is responsible for returning the updated value of the
+* computation.
+* @param o Optional context object
+* @static
+* @return A value that results from iteratively applying the
+* supplied function to each element in the array.
+*/
+A.reduce = (Native.reduce) ?
+ function(a, init, f, o) {
+ //Firefox's Array.reduce does not allow inclusion of a
+ // thisObject, so we need to implement it manually
+ return Native.reduce.call(a, function(init, item, i, a) {
+ return f.call(o, init, item, i, a);
+ }, init);
+ } :
+ function(a, init, f, o) {
+ var r = init;
+ A.each(a, function (item, i, a) {
+ r = f.call(o, r, item, i, a);
+ });
+ return r;
+ };
+
+
+/**
+* Executes the supplied function on each item in the array,
+* searching for the first item that matches the supplied
+* function.
+* @method Array.find
+* @param a {Array} the array to search
+* @param f {Function} the function to execute on each item.
+* Iteration is stopped as soon as this function returns true
+* on an item.
+* @param o Optional context object
+* @static
+* @return {object} the first item that the supplied function
+* returns true for, or null if it never returns true
+*/
+A.find = function(a, f, o) {
+ var l = a.length;
+ for(var i=0; i < l; i++) {
+ if (f.call(o, a[i], i, a)) {
+ return a[i];
+ }
+ }
+ return null;
+};
+
+/**
+* Iterates over an array, returning a new array of all the elements
+* that match the supplied regular expression
+* @method Array.grep
+* @param a {Array} a collection to iterate over
+* @param pattern {RegExp} The regular expression to test against
+* each item
+* @static
+* @return {Array} All the items in the collection that
+* produce a match against the supplied regular expression.
+* If no items match, an empty array is returned.
+*/
+A.grep = function (a, pattern) {
+ return A.filter(a, function (item, index) {
+ return pattern.test(item);
+ });
+};
+
+
+/**
+* Partitions an array into two new arrays, one with the items
+* that match the supplied function, and one with the items that
+* do not.
+* @method Array.partition
+* @param a {Array} a collection to iterate over
+* @paran f {Function} a function that will receive each item
+* in the collection and its index.
+* @param o Optional execution context of f.
+* @static
+* @return An object with two members, 'matches' and 'rejects',
+* that are arrays containing the items that were selected or
+* rejected by the test function (or an empty array).
+*/
+A.partition = function (a, f, o) {
+ var results = {matches: [], rejects: []};
+ A.each(a, function (item, index) {
+ var set = f.call(o, item, index, a) ? results.matches : results.rejects;
+ set.push(item);
+ });
+ return results;
+};
+
+/**
+* Creates an array of arrays by pairing the corresponding
+* elements of two arrays together into a new array.
+* @method Array.zip
+* @param a {Array} a collection to iterate over
+* @param a2 {Array} another collection whose members will be
+* paired with members of the first parameter
+* @static
+* @return An array of arrays formed by pairing each element
+* of the first collection with an item in the second collection
+* having the corresponding index.
+*/
+A.zip = function (a, a2) {
+ var results = [];
+ A.each(a, function (item, index) {
+ results.push([item, a2[index]]);
+ });
+ return results;
+};
+
+
+}, '3.0.0' );
diff --git a/lib/yui/3.0.0/compat/compat-debug.js b/lib/yui/3.0.0/compat/compat-debug.js
new file mode 100644
index 0000000000..b289d0bb55
--- /dev/null
+++ b/lib/yui/3.0.0/compat/compat-debug.js
@@ -0,0 +1,900 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('compat', function(Y) {
+
+
+var COMPAT_ARG = '~yui|2|compat~';
+
+
+if (window.YAHOO != YUI) {
+
+ // get any existing YAHOO obj props
+ var o = (window.YAHOO) ? YUI.merge(window.YAHOO) : null;
+
+ // Make the YUI global the YAHOO global
+ window.YAHOO = YUI;
+
+ // augment old YAHOO props
+ if (o) {
+ Y.mix(Y, o);
+ }
+}
+
+// add old namespaces
+Y.namespace("util", "widget", "example");
+
+// case/location change
+Y.env = (Y.env) ? Y.mix(Y.env, Y.Env) : Y.Env;
+Y.lang = (Y.lang) ? Y.mix(Y.lang, Y.Lang) : Y.Lang;
+Y.env.ua = Y.UA;
+
+// support Y.register
+Y.mix(Y.env, {
+ modules: [],
+ listeners: [],
+ getVersion: function(name) {
+ return this.Env.modules[name] || null;
+ }
+});
+
+var L = Y.lang;
+
+// add old lang properties
+Y.mix(L, {
+
+ augmentObject: function(r, s) {
+ var a = arguments, wl = (a.length > 2) ? Y.Array(a, 2, true) : null;
+ return Y.mix(r, s, (wl), wl);
+ },
+
+ augmentProto: function(r, s) {
+ var a = arguments, wl = (a.length > 2) ? Y.Array(a, 2, true) : null;
+ return Y.mix(r, s, (wl), wl, 1);
+ },
+
+ // extend: Y.bind(Y.extend, Y),
+ extend: Y.extend,
+ // merge: Y.bind(Y.merge, Y)
+ merge: Y.merge
+}, true);
+
+L.augment = L.augmentProto;
+
+L.hasOwnProperty = function(o, k) {
+ return (o.hasOwnProperty(k));
+};
+
+Y.augmentProto = L.augmentProto;
+
+// add register function
+Y.mix(Y, {
+ register: function(name, mainClass, data) {
+ var mods = Y.Env.modules;
+ if (!mods[name]) {
+ mods[name] = { versions:[], builds:[] };
+ }
+ var m=mods[name],v=data.version,b=data.build,ls=Y.Env.listeners;
+ m.name = name;
+ m.version = v;
+ m.build = b;
+ m.versions.push(v);
+ m.builds.push(b);
+ m.mainClass = mainClass;
+ // fire the module load listeners
+ for (var i=0;i= this.left &&
+ region.right <= this.right &&
+ region.top >= this.top &&
+ region.bottom <= this.bottom );
+
+ // this.logger.debug("does " + this + " contain " + region + " ... " + ret);
+};
+
+YAHOO.util.Region.prototype.getArea = function() {
+ return ( (this.bottom - this.top) * (this.right - this.left) );
+};
+
+YAHOO.util.Region.prototype.intersect = function(region) {
+ var t = Math.max( this.top, region.top );
+ var r = Math.min( this.right, region.right );
+ var b = Math.min( this.bottom, region.bottom );
+ var l = Math.max( this.left, region.left );
+
+ if (b >= t && r >= l) {
+ return new YAHOO.util.Region(t, r, b, l);
+ } else {
+ return null;
+ }
+};
+
+YAHOO.util.Region.prototype.union = function(region) {
+ var t = Math.min( this.top, region.top );
+ var r = Math.max( this.right, region.right );
+ var b = Math.max( this.bottom, region.bottom );
+ var l = Math.min( this.left, region.left );
+
+ return new YAHOO.util.Region(t, r, b, l);
+};
+
+YAHOO.util.Region.prototype.toString = function() {
+ return ( "Region {" +
+ "top: " + this.top +
+ ", right: " + this.right +
+ ", bottom: " + this.bottom +
+ ", left: " + this.left +
+ "}" );
+};
+
+YAHOO.util.Region.getRegion = function(el) {
+ return YUI.DOM.region(el);
+};
+
+YAHOO.util.Point = function(x, y) {
+ if (YAHOO.lang.isArray(x)) { // accept input from Dom.getXY, Event.getXY, etc.
+ y = x[1]; // dont blow away x yet
+ x = x[0];
+ }
+
+ this.x = this.right = this.left = this[0] = x;
+ this.y = this.top = this.bottom = this[1] = y;
+};
+
+YAHOO.util.Point.prototype = new YAHOO.util.Region();
+
+
+
+}, '3.0.0' ,{requires:['dom','event']});
+YUI._setup(); YUI.use('dom', 'event', 'compat');
diff --git a/lib/yui/3.0.0/compat/compat-min.js b/lib/yui/3.0.0/compat/compat-min.js
new file mode 100644
index 0000000000..1dcc703b9b
--- /dev/null
+++ b/lib/yui/3.0.0/compat/compat-min.js
@@ -0,0 +1,9 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("compat",function(D){var S="~yui|2|compat~";if(window.YAHOO!=YUI){var M=(window.YAHOO)?YUI.merge(window.YAHOO):null;window.YAHOO=YUI;if(M){D.mix(D,M);}}D.namespace("util","widget","example");D.env=(D.env)?D.mix(D.env,D.Env):D.Env;D.lang=(D.lang)?D.mix(D.lang,D.Lang):D.Lang;D.env.ua=D.UA;D.mix(D.env,{modules:[],listeners:[],getVersion:function(L){return this.Env.modules[L]||null;}});var G=D.lang;D.mix(G,{augmentObject:function(V,U){var L=arguments,W=(L.length>2)?D.Array(L,2,true):null;return D.mix(V,U,(W),W);},augmentProto:function(V,U){var L=arguments,W=(L.length>2)?D.Array(L,2,true):null;return D.mix(V,U,(W),W,1);},extend:D.extend,merge:D.merge},true);G.augment=G.augmentProto;G.hasOwnProperty=function(U,L){return(U.hasOwnProperty(L));};D.augmentProto=G.augmentProto;D.mix(D,{register:function(L,X,W){var c=D.Env.modules;if(!c[L]){c[L]={versions:[],builds:[]};}var U=c[L],a=W.version,Z=W.build,Y=D.Env.listeners;U.name=L;U.version=a;U.build=Z;U.versions.push(a);U.builds.push(Z);U.mainClass=X;for(var V=0;V=this.left&&L.right<=this.right&&L.top>=this.top&&L.bottom<=this.bottom);};YAHOO.util.Region.prototype.getArea=function(){return((this.bottom-this.top)*(this.right-this.left));};YAHOO.util.Region.prototype.intersect=function(X){var V=Math.max(this.top,X.top);var W=Math.min(this.right,X.right);var L=Math.min(this.bottom,X.bottom);var U=Math.max(this.left,X.left);if(L>=V&&W>=U){return new YAHOO.util.Region(V,W,L,U);}else{return null;}};YAHOO.util.Region.prototype.union=function(X){var V=Math.min(this.top,X.top);var W=Math.max(this.right,X.right);var L=Math.max(this.bottom,X.bottom);var U=Math.min(this.left,X.left);return new YAHOO.util.Region(V,W,L,U);};YAHOO.util.Region.prototype.toString=function(){return("Region {"+"top: "+this.top+", right: "+this.right+", bottom: "+this.bottom+", left: "+this.left+"}");};YAHOO.util.Region.getRegion=function(L){return YUI.DOM.region(L);};YAHOO.util.Point=function(L,U){if(YAHOO.lang.isArray(L)){U=L[1];L=L[0];}this.x=this.right=this.left=this[0]=L;this.y=this.top=this.bottom=this[1]=U;};YAHOO.util.Point.prototype=new YAHOO.util.Region();},"3.0.0",{requires:["dom","event"]});YUI._setup();YUI.use("dom","event","compat");
\ No newline at end of file
diff --git a/lib/yui/3.0.0/compat/compat.js b/lib/yui/3.0.0/compat/compat.js
new file mode 100644
index 0000000000..12528df9c6
--- /dev/null
+++ b/lib/yui/3.0.0/compat/compat.js
@@ -0,0 +1,896 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('compat', function(Y) {
+
+
+var COMPAT_ARG = '~yui|2|compat~';
+
+
+if (window.YAHOO != YUI) {
+
+ // get any existing YAHOO obj props
+ var o = (window.YAHOO) ? YUI.merge(window.YAHOO) : null;
+
+ // Make the YUI global the YAHOO global
+ window.YAHOO = YUI;
+
+ // augment old YAHOO props
+ if (o) {
+ Y.mix(Y, o);
+ }
+}
+
+// add old namespaces
+Y.namespace("util", "widget", "example");
+
+// case/location change
+Y.env = (Y.env) ? Y.mix(Y.env, Y.Env) : Y.Env;
+Y.lang = (Y.lang) ? Y.mix(Y.lang, Y.Lang) : Y.Lang;
+Y.env.ua = Y.UA;
+
+// support Y.register
+Y.mix(Y.env, {
+ modules: [],
+ listeners: [],
+ getVersion: function(name) {
+ return this.Env.modules[name] || null;
+ }
+});
+
+var L = Y.lang;
+
+// add old lang properties
+Y.mix(L, {
+
+ augmentObject: function(r, s) {
+ var a = arguments, wl = (a.length > 2) ? Y.Array(a, 2, true) : null;
+ return Y.mix(r, s, (wl), wl);
+ },
+
+ augmentProto: function(r, s) {
+ var a = arguments, wl = (a.length > 2) ? Y.Array(a, 2, true) : null;
+ return Y.mix(r, s, (wl), wl, 1);
+ },
+
+ // extend: Y.bind(Y.extend, Y),
+ extend: Y.extend,
+ // merge: Y.bind(Y.merge, Y)
+ merge: Y.merge
+}, true);
+
+L.augment = L.augmentProto;
+
+L.hasOwnProperty = function(o, k) {
+ return (o.hasOwnProperty(k));
+};
+
+Y.augmentProto = L.augmentProto;
+
+// add register function
+Y.mix(Y, {
+ register: function(name, mainClass, data) {
+ var mods = Y.Env.modules;
+ if (!mods[name]) {
+ mods[name] = { versions:[], builds:[] };
+ }
+ var m=mods[name],v=data.version,b=data.build,ls=Y.Env.listeners;
+ m.name = name;
+ m.version = v;
+ m.build = b;
+ m.versions.push(v);
+ m.builds.push(b);
+ m.mainClass = mainClass;
+ // fire the module load listeners
+ for (var i=0;i= this.left &&
+ region.right <= this.right &&
+ region.top >= this.top &&
+ region.bottom <= this.bottom );
+
+};
+
+YAHOO.util.Region.prototype.getArea = function() {
+ return ( (this.bottom - this.top) * (this.right - this.left) );
+};
+
+YAHOO.util.Region.prototype.intersect = function(region) {
+ var t = Math.max( this.top, region.top );
+ var r = Math.min( this.right, region.right );
+ var b = Math.min( this.bottom, region.bottom );
+ var l = Math.max( this.left, region.left );
+
+ if (b >= t && r >= l) {
+ return new YAHOO.util.Region(t, r, b, l);
+ } else {
+ return null;
+ }
+};
+
+YAHOO.util.Region.prototype.union = function(region) {
+ var t = Math.min( this.top, region.top );
+ var r = Math.max( this.right, region.right );
+ var b = Math.max( this.bottom, region.bottom );
+ var l = Math.min( this.left, region.left );
+
+ return new YAHOO.util.Region(t, r, b, l);
+};
+
+YAHOO.util.Region.prototype.toString = function() {
+ return ( "Region {" +
+ "top: " + this.top +
+ ", right: " + this.right +
+ ", bottom: " + this.bottom +
+ ", left: " + this.left +
+ "}" );
+};
+
+YAHOO.util.Region.getRegion = function(el) {
+ return YUI.DOM.region(el);
+};
+
+YAHOO.util.Point = function(x, y) {
+ if (YAHOO.lang.isArray(x)) { // accept input from Dom.getXY, Event.getXY, etc.
+ y = x[1]; // dont blow away x yet
+ x = x[0];
+ }
+
+ this.x = this.right = this.left = this[0] = x;
+ this.y = this.top = this.bottom = this[1] = y;
+};
+
+YAHOO.util.Point.prototype = new YAHOO.util.Region();
+
+
+
+}, '3.0.0' ,{requires:['dom','event']});
+YUI._setup(); YUI.use('dom', 'event', 'compat');
diff --git a/lib/yui/3.0.0/console/assets/console-core.css b/lib/yui/3.0.0/console/assets/console-core.css
new file mode 100644
index 0000000000..dbc8374a30
--- /dev/null
+++ b/lib/yui/3.0.0/console/assets/console-core.css
@@ -0,0 +1,7 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
diff --git a/lib/yui/3.0.0/console/assets/console-filters-core.css b/lib/yui/3.0.0/console/assets/console-filters-core.css
new file mode 100644
index 0000000000..dbc8374a30
--- /dev/null
+++ b/lib/yui/3.0.0/console/assets/console-filters-core.css
@@ -0,0 +1,7 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
diff --git a/lib/yui/3.0.0/console/assets/skins/sam/bg.png b/lib/yui/3.0.0/console/assets/skins/sam/bg.png
new file mode 100644
index 0000000000000000000000000000000000000000..652fce6ccd8ca02d82780e686e12581161753579
GIT binary patch
literal 219
zcmeAS@N?(olHy`uVBq!ia0vp^%s?E#0U}?&vA+VOBuiW)N`mv#O3D+9QW+dm@{>{(
zJaZG%Q-e|yQz{EjrrH1%83g!*xITRJ_}{;OfByXW{rmT?U%%de`0(P@tEbPN{rvg!
z+qdsuzJ7i4=IzH%pKjc^b?5H=|NsB1Ei5Ys>UH#VaSW-r_2lqr!2=2$4hP$nn(TkQ
zzvk)pQqg*IirRgpPkKuOvRy+9%axi8*|K$`vd>r=8dtryIcNE1@BeRH1`K(}xW#!V
S|9%fNjKR~@&t;ucLK6Uym}f@-
literal 0
HcmV?d00001
diff --git a/lib/yui/3.0.0/console/assets/skins/sam/console-filters-skin.css b/lib/yui/3.0.0/console/assets/skins/sam/console-filters-skin.css
new file mode 100644
index 0000000000..dc870f3ac4
--- /dev/null
+++ b/lib/yui/3.0.0/console/assets/skins/sam/console-filters-skin.css
@@ -0,0 +1,34 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+.yui-skin-sam .yui-console-ft .yui-console-filters-categories,
+.yui-skin-sam .yui-console-ft .yui-console-filters-sources {
+ text-align: left;
+ padding: 5px 0;
+ border: 1px inset;
+ margin: 0 2px;
+}
+.yui-skin-sam .yui-console-ft .yui-console-filters-categories {
+ background: #fff;
+ border-bottom: 2px ridge;
+}
+.yui-skin-sam .yui-console-ft .yui-console-filters-sources {
+ background: #fff;
+ margin-bottom: 2px;
+
+ border-top: 0 none;
+ border-bottom-right-radius: 10px;
+ border-bottom-left-radius: 10px;
+ -moz-border-radius-bottomright: 10px;
+ -moz-border-radius-bottomleft: 10px;
+ -webkit-border-bottom-right-radius: 10px;
+ -webkit-border-bottom-left-radius: 10px;
+}
+.yui-skin-sam .yui-console-filter-label {
+ white-space: nowrap;
+ margin-left: 1ex;
+}
diff --git a/lib/yui/3.0.0/console/assets/skins/sam/console-filters.css b/lib/yui/3.0.0/console/assets/skins/sam/console-filters.css
new file mode 100644
index 0000000000..cb9fb4193e
--- /dev/null
+++ b/lib/yui/3.0.0/console/assets/skins/sam/console-filters.css
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+.yui-skin-sam .yui-console-ft .yui-console-filters-categories,.yui-skin-sam .yui-console-ft .yui-console-filters-sources{text-align:left;padding:5px 0;border:1px inset;margin:0 2px;}.yui-skin-sam .yui-console-ft .yui-console-filters-categories{background:#fff;border-bottom:2px ridge;}.yui-skin-sam .yui-console-ft .yui-console-filters-sources{background:#fff;margin-bottom:2px;border-top:0 none;border-bottom-right-radius:10px;border-bottom-left-radius:10px;-moz-border-radius-bottomright:10px;-moz-border-radius-bottomleft:10px;-webkit-border-bottom-right-radius:10px;-webkit-border-bottom-left-radius:10px;}.yui-skin-sam .yui-console-filter-label{white-space:nowrap;margin-left:1ex;}
diff --git a/lib/yui/3.0.0/console/assets/skins/sam/console-skin.css b/lib/yui/3.0.0/console/assets/skins/sam/console-skin.css
new file mode 100644
index 0000000000..829cd572a8
--- /dev/null
+++ b/lib/yui/3.0.0/console/assets/skins/sam/console-skin.css
@@ -0,0 +1,192 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+.yui-skin-sam .yui-separate-console {
+ position:absolute;
+ right:1em;
+ top:1em;
+ z-index:999;
+}
+
+.yui-skin-sam .yui-inline-console {
+ /* xbrowser inline-block styles */
+ display: -moz-inline-stack; /* FF2 */
+ display: inline-block;
+ *display: inline; /* IE 7- (with zoom) */
+ zoom: 1;
+ vertical-align: top;
+}
+.yui-skin-sam .yui-inline-console .yui-console-content {
+ position: relative;
+}
+
+.yui-skin-sam .yui-console-content {
+ background: #777;
+ _background: #D8D8DA url(bg.png) repeat-x 0 0;
+ font: normal 13px/1.3 Arial, sans-serif;
+ text-align: left;
+
+ border: 1px solid #777;
+ border-radius: 10px;
+ -moz-border-radius: 10px;
+ -webkit-border-radius: 10px;
+}
+
+.yui-skin-sam .yui-console-hd,
+.yui-skin-sam .yui-console-bd,
+.yui-skin-sam .yui-console-ft {
+ position: relative;
+}
+
+.yui-skin-sam .yui-console-hd,
+.yui-skin-sam .yui-console-ft .yui-console-controls {
+ text-align: right;
+}
+
+.yui-skin-sam .yui-console-hd {
+ background: #D8D8DA url(bg.png) repeat-x 0 0;
+ padding: 1ex;
+
+ border: 1px solid transparent;
+ _border: 0 none;
+ border-top-right-radius: 10px;
+ border-top-left-radius: 10px;
+ -moz-border-radius-topright: 10px;
+ -moz-border-radius-topleft: 10px;
+ -webkit-border-top-right-radius: 10px;
+ -webkit-border-top-left-radius: 10px;
+}
+
+.yui-skin-sam .yui-console-bd {
+ background: #fff;
+ border-top: 1px solid #777;
+ border-bottom: 1px solid #777;
+ color: #000;
+ font-size: 11px;
+ overflow: auto;
+ overflow-x: auto;
+ overflow-y: scroll;
+ _width: 100%;
+}
+
+.yui-skin-sam .yui-console-ft {
+ background: #D8D8DA url(bg.png) repeat-x 0 0;
+
+ border: 1px solid transparent;
+ _border: 0 none;
+ border-bottom-right-radius: 10px;
+ border-bottom-left-radius: 10px;
+ -moz-border-radius-bottomright: 10px;
+ -moz-border-radius-bottomleft: 10px;
+ -webkit-border-bottom-right-radius: 10px;
+ -webkit-border-bottom-left-radius: 10px;
+}
+
+.yui-skin-sam .yui-console-controls {
+ padding: 4px 1ex;
+ zoom: 1;
+}
+
+.yui-skin-sam .yui-console-title {
+ color: #000;
+ display: inline;
+ float: left;
+ font-weight: bold;
+ font-size: 13px;
+ height: 24px;
+ line-height: 24px;
+ margin: 0;
+ padding-left: 1ex;
+}
+
+.yui-skin-sam .yui-console-pause-label {
+ float: left;
+}
+.yui-skin-sam .yui-console-button {
+ line-height: 1.3;
+}
+
+.yui-skin-sam .yui-console-collapsed .yui-console-bd,
+.yui-skin-sam .yui-console-collapsed .yui-console-ft {
+ display: none;
+}
+.yui-skin-sam .yui-console-content.yui-console-collapsed {
+ -webkit-border-radius: 0;
+}
+.yui-skin-sam .yui-console-collapsed .yui-console-hd {
+ border-radius: 10px;
+ -moz-border-radius: 10px;
+ -webkit-border-radius: 0;
+}
+
+/* Log entries */
+.yui-skin-sam .yui-console-entry {
+ border-bottom: 1px solid #aaa;
+ min-height: 32px;
+ _height: 32px;
+}
+
+.yui-skin-sam .yui-console-entry-meta {
+ margin: 0;
+ overflow: hidden;
+}
+
+.yui-skin-sam .yui-console-entry-content {
+ margin: 0;
+ padding: 0 1ex;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+}
+
+.yui-skin-sam .yui-console-entry-meta .yui-console-entry-src {
+ color: #000;
+ font-style: italic;
+ font-weight: bold;
+ float: right;
+ margin: 2px 5px 0 0;
+}
+.yui-skin-sam .yui-console-entry-meta .yui-console-entry-time {
+ color: #777;
+ padding-left: 1ex;
+}
+.yui-skin-sam .yui-console-entry-warn .yui-console-entry-meta .yui-console-entry-time {
+ color: #555;
+}
+
+.yui-skin-sam .yui-console-entry-info .yui-console-entry-meta .yui-console-entry-cat,
+.yui-skin-sam .yui-console-entry-warn .yui-console-entry-meta .yui-console-entry-cat,
+.yui-skin-sam .yui-console-entry-error .yui-console-entry-meta .yui-console-entry-cat {
+ display: none;
+}
+.yui-skin-sam .yui-console-entry-warn {
+ background: #aee url(warn_error.png) no-repeat -15px 15px;
+}
+.yui-skin-sam .yui-console-entry-error {
+ background: #ffa url(warn_error.png) no-repeat 5px -24px;
+ color: #900;
+}
+.yui-skin-sam .yui-console-entry-warn .yui-console-entry-content,
+.yui-skin-sam .yui-console-entry-error .yui-console-entry-content {
+ padding-left: 24px;
+}
+.yui-skin-sam .yui-console-entry-cat {
+ text-transform: uppercase;
+ padding: 1px 4px;
+ background-color: #ccc;
+}
+.yui-skin-sam .yui-console-entry-info .yui-console-entry-cat {
+ background-color: #ac2;
+}
+.yui-skin-sam .yui-console-entry-warn .yui-console-entry-cat {
+ background-color: #e81;
+}
+.yui-skin-sam .yui-console-entry-error .yui-console-entry-cat {
+ background-color: #b00;
+ color: #fff;
+}
+
+.yui-skin-sam .yui-console-hidden { display: none; }
diff --git a/lib/yui/3.0.0/console/assets/skins/sam/console.css b/lib/yui/3.0.0/console/assets/skins/sam/console.css
new file mode 100644
index 0000000000..5688517efc
--- /dev/null
+++ b/lib/yui/3.0.0/console/assets/skins/sam/console.css
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+.yui-skin-sam .yui-separate-console{position:absolute;right:1em;top:1em;z-index:999;}.yui-skin-sam .yui-inline-console{display:-moz-inline-stack;display:inline-block;*display:inline;zoom:1;vertical-align:top;}.yui-skin-sam .yui-inline-console .yui-console-content{position:relative;}.yui-skin-sam .yui-console-content{background:#777;_background:#D8D8DA url(bg.png) repeat-x 0 0;font:normal 13px/1.3 Arial,sans-serif;text-align:left;border:1px solid #777;border-radius:10px;-moz-border-radius:10px;-webkit-border-radius:10px;}.yui-skin-sam .yui-console-hd,.yui-skin-sam .yui-console-bd,.yui-skin-sam .yui-console-ft{position:relative;}.yui-skin-sam .yui-console-hd,.yui-skin-sam .yui-console-ft .yui-console-controls{text-align:right;}.yui-skin-sam .yui-console-hd{background:#D8D8DA url(bg.png) repeat-x 0 0;padding:1ex;border:1px solid transparent;_border:0 none;border-top-right-radius:10px;border-top-left-radius:10px;-moz-border-radius-topright:10px;-moz-border-radius-topleft:10px;-webkit-border-top-right-radius:10px;-webkit-border-top-left-radius:10px;}.yui-skin-sam .yui-console-bd{background:#fff;border-top:1px solid #777;border-bottom:1px solid #777;color:#000;font-size:11px;overflow:auto;overflow-x:auto;overflow-y:scroll;_width:100%;}.yui-skin-sam .yui-console-ft{background:#D8D8DA url(bg.png) repeat-x 0 0;border:1px solid transparent;_border:0 none;border-bottom-right-radius:10px;border-bottom-left-radius:10px;-moz-border-radius-bottomright:10px;-moz-border-radius-bottomleft:10px;-webkit-border-bottom-right-radius:10px;-webkit-border-bottom-left-radius:10px;}.yui-skin-sam .yui-console-controls{padding:4px 1ex;zoom:1;}.yui-skin-sam .yui-console-title{color:#000;display:inline;float:left;font-weight:bold;font-size:13px;height:24px;line-height:24px;margin:0;padding-left:1ex;}.yui-skin-sam .yui-console-pause-label{float:left;}.yui-skin-sam .yui-console-button{line-height:1.3;}.yui-skin-sam .yui-console-collapsed .yui-console-bd,.yui-skin-sam .yui-console-collapsed .yui-console-ft{display:none;}.yui-skin-sam .yui-console-content.yui-console-collapsed{-webkit-border-radius:0;}.yui-skin-sam .yui-console-collapsed .yui-console-hd{border-radius:10px;-moz-border-radius:10px;-webkit-border-radius:0;}.yui-skin-sam .yui-console-entry{border-bottom:1px solid #aaa;min-height:32px;_height:32px;}.yui-skin-sam .yui-console-entry-meta{margin:0;overflow:hidden;}.yui-skin-sam .yui-console-entry-content{margin:0;padding:0 1ex;white-space:pre-wrap;word-wrap:break-word;}.yui-skin-sam .yui-console-entry-meta .yui-console-entry-src{color:#000;font-style:italic;font-weight:bold;float:right;margin:2px 5px 0 0;}.yui-skin-sam .yui-console-entry-meta .yui-console-entry-time{color:#777;padding-left:1ex;}.yui-skin-sam .yui-console-entry-warn .yui-console-entry-meta .yui-console-entry-time{color:#555;}.yui-skin-sam .yui-console-entry-info .yui-console-entry-meta .yui-console-entry-cat,.yui-skin-sam .yui-console-entry-warn .yui-console-entry-meta .yui-console-entry-cat,.yui-skin-sam .yui-console-entry-error .yui-console-entry-meta .yui-console-entry-cat{display:none;}.yui-skin-sam .yui-console-entry-warn{background:#aee url(warn_error.png) no-repeat -15px 15px;}.yui-skin-sam .yui-console-entry-error{background:#ffa url(warn_error.png) no-repeat 5px -24px;color:#900;}.yui-skin-sam .yui-console-entry-warn .yui-console-entry-content,.yui-skin-sam .yui-console-entry-error .yui-console-entry-content{padding-left:24px;}.yui-skin-sam .yui-console-entry-cat{text-transform:uppercase;padding:1px 4px;background-color:#ccc;}.yui-skin-sam .yui-console-entry-info .yui-console-entry-cat{background-color:#ac2;}.yui-skin-sam .yui-console-entry-warn .yui-console-entry-cat{background-color:#e81;}.yui-skin-sam .yui-console-entry-error .yui-console-entry-cat{background-color:#b00;color:#fff;}.yui-skin-sam .yui-console-hidden{display:none;}
diff --git a/lib/yui/3.0.0/console/assets/skins/sam/warn_error.png b/lib/yui/3.0.0/console/assets/skins/sam/warn_error.png
new file mode 100644
index 0000000000000000000000000000000000000000..db4e55483e346c03b793a2bd0be72847505c9ef0
GIT binary patch
literal 703
zcmeAS@N?(olHy`uVBq!ia0vp^%0O(w!3-qLuM~O!DajJoh?3y^w370~qErUQl>DSr
z1<%~X^wgl##FWaylc_d9MF#?WLR_z0x$^3j+16hJ(a~a$ADg(l
zxoT@mu2`{RxvFYzZthZf`DxRp9XondM^Vw5fuXjxcH1_sPoF+bVPMc^WPG%J`@Xoi
zojZ4SGcbgPghWS0tuZ#9!@w|OhVt#DOBXOOl$Mrm_w$>{z~JpIvU;`p!-o%TZ1|EH
z7_6;j%*=Re85oWq*Go)HeEat8@87?Zlg0J)cr_#>E?qL5$IH9f);1$OeSw&mp@E*g
zJ-@Ip%Z+*S7V`1^|No!wQ)fQVFAgO^e!)O4C4k{j^+p#421ZX$7srr_TW_w!<~JFL
zusztu@yU?&r-om^hA3AVtwqv@%>Mu1A9Zq5s<`c)x965+R(*W3#5O;wq}?s8KTEpQ
znnkeW4u5;~;g^QS##gsX-3v3zFuHs^Vzt4(FyjLYlDjysl_lNeGurv_jJ9A}2j|83
zoSmKJRq5vrJ^0LFu=ZatyNUMX7c9#&)uUbW=0wbiwExlcgO}-D-x=m(v&)-Ko@1)c
z2(`28xLIWzY2mgyb9Up^>DOg7Ki?>>GXA?-{#l~jv-;l0XP@8q7cx3%c&1y4|22cj
z(uGFHgr==<DSr
z1<%~X^wgl##FWaylc_d9MF#?WLR_z0x$^3j+16hJ(a~a$ADg(l
zxoT@mu2`{RxvFYzZthZf`DxRp9XondM^Vw5fuXjxcH1_sPoF+bVPMc^WPG%J`@Xoi
zojZ4SGcbgPghWS0tuZ#9!@w|OhVt#DOBXOOl$Mrm_w$>{z~JpIvU;`p!-o%TZ1|EH
z7_6;j%*=Re85oWq*Go)HeEat8@87?Zlg0J)cr_#>E?qL5$IH9f);1$OeSw&mp@E*g
zJ-@Ip%Z+*S7V`1^|No!wQ)fQVFAgO^e!)O4C4k{j^+p#421ZX$7srr_TW_w!<~JFL
zusztu@yU?&r-om^hA3AVtwqv@%>Mu1A9Zq5s<`c)x965+R(*W3#5O;wq}?s8KTEpQ
znnkeW4u5;~;g^QS##gsX-3v3zFuHs^Vzt4(FyjLYlDjysl_lNeGurv_jJ9A}2j|83
zoSmKJRq5vrJ^0LFu=ZatyNUMX7c9#&)uUbW=0wbiwExlcgO}-D-x=m(v&)-Ko@1)c
z2(`28xLIWzY2mgyb9Up^>DOg7Ki?>>GXA?-{#l~jv-;l0XP@8q7cx3%c&1y4|22cj
z(uGFHgr==<Y.log( message, category, source ) method. The
+ * debug versions of YUI modules will include logging statements to offer some
+ * insight into the steps executed during that module's operation. Including
+ * log statements in your code will cause those messages to also appear in the
+ * Console. Use Console to aid in developing your page or application.
+ *
+ * Entry categories "info", "warn", and "error"
+ * are also referred to as the log level, and entries are filtered against the
+ * configured logLevel.
+ *
+ * @module console
+ * @class Console
+ * @extends Widget
+ * @param conf {Object} Configuration object (see Configuration attributes)
+ * @constructor
+ */
+function Console() {
+ Console.superclass.constructor.apply(this,arguments);
+}
+
+var getCN = Y.ClassNameManager.getClassName,
+ CHECKED = 'checked',
+ CLEAR = 'clear',
+ CLICK = 'click',
+ COLLAPSED = 'collapsed',
+ CONSOLE = 'console',
+ CONTENT_BOX = 'contentBox',
+ DISABLED = 'disabled',
+ ENTRY = 'entry',
+ ERROR = 'error',
+ HEIGHT = 'height',
+ INFO = 'info',
+ INNER_HTML = 'innerHTML',
+ LAST_TIME = 'lastTime',
+ PAUSE = 'pause',
+ PAUSED = 'paused',
+ RESET = 'reset',
+ START_TIME = 'startTime',
+ TITLE = 'title',
+ WARN = 'warn',
+
+ DOT = '.',
+
+ C_BUTTON = getCN(CONSOLE,'button'),
+ C_CHECKBOX = getCN(CONSOLE,'checkbox'),
+ C_CLEAR = getCN(CONSOLE,CLEAR),
+ C_COLLAPSE = getCN(CONSOLE,'collapse'),
+ C_COLLAPSED = getCN(CONSOLE,COLLAPSED),
+ C_CONSOLE_CONTROLS = getCN(CONSOLE,'controls'),
+ C_CONSOLE_HD = getCN(CONSOLE,'hd'),
+ C_CONSOLE_BD = getCN(CONSOLE,'bd'),
+ C_CONSOLE_FT = getCN(CONSOLE,'ft'),
+ C_CONSOLE_TITLE = getCN(CONSOLE,TITLE),
+ C_ENTRY = getCN(CONSOLE,ENTRY),
+ C_ENTRY_CAT = getCN(CONSOLE,ENTRY,'cat'),
+ C_ENTRY_CONTENT = getCN(CONSOLE,ENTRY,'content'),
+ C_ENTRY_META = getCN(CONSOLE,ENTRY,'meta'),
+ C_ENTRY_SRC = getCN(CONSOLE,ENTRY,'src'),
+ C_ENTRY_TIME = getCN(CONSOLE,ENTRY,'time'),
+ C_PAUSE = getCN(CONSOLE,PAUSE),
+ C_PAUSE_LABEL = getCN(CONSOLE,PAUSE,'label'),
+
+ RE_INLINE_SOURCE = /^(\S+)\s/,
+ RE_AMP = /&/g,
+ RE_GT = />/g,
+ RE_LT = /'+
+ '
',
+
+ /**
+ * Markup template used to generate the DOM structure for the Console body
+ * (where the messages are inserted) when it is rendered. The template
+ * includes only the {placeholder} "console_bd_class", which is
+ * constributed by Console.CHROME_CLASSES.
+ *
+ * @property Console.BODY_TEMPLATE
+ * @type String
+ * @static
+ */
+ BODY_TEMPLATE : '',
+
+ /**
+ * Markup template used to generate the DOM structure for the footer
+ * section of the Console when it is rendered. The template includes
+ * many of the {placeholder}s from Console.CHROME_CLASSES as well as:
+ *
+ *
+ *
id_guid - generated unique id, relates the label and checkbox
',
+
+ /**
+ * Default markup template used to create the DOM structure for Console
+ * entries. The markup contains {placeholder}s for content and classes
+ * that are replaced via Y.substitute. The default template contains
+ * the {placeholder}s identified in Console.ENTRY_CLASSES as well as the
+ * following placeholders that will be populated by the log entry data:
+ *
+ *
+ *
cat_class
+ *
src_class
+ *
totalTime
+ *
elapsedTime
+ *
localTime
+ *
sourceAndDetail
+ *
message
+ *
+ *
+ * @property Console.ENTRY_TEMPLATE
+ * @type String
+ * @static
+ */
+ ENTRY_TEMPLATE : ENTRY_TEMPLATE_STR,
+
+ /**
+ * Static property used to define the default attribute configuration of
+ * the Widget.
+ *
+ * @property Console.ATTRS
+ * @Type Object
+ * @static
+ */
+ ATTRS : {
+
+ /**
+ * Name of the custom event that will communicate log messages.
+ *
+ * @attribute logEvent
+ * @type String
+ * @default "yui:log"
+ */
+ logEvent : {
+ value : 'yui:log',
+ writeOnce : true,
+ validator : isString
+ },
+
+ /**
+ * Object that will emit the log events. By default the YUI instance.
+ * To have a single Console capture events from all YUI instances, set
+ * this to the Y.Global object.
+ *
+ * @attribute logSource
+ * @type EventTarget
+ * @default Y
+ */
+ logSource : {
+ value : Y,
+ writeOnce : true,
+ validator : function (v) {
+ return v && Y.Lang.isFunction(v.on);
+ }
+ },
+
+ /**
+ * Collection of strings used to label elements in the Console UI.
+ * Default collection contains the following name:value pairs:
+ *
+ *
+ *
title : "Log Console"
+ *
pause : "Pause"
+ *
clear : "Clear"
+ *
collapse : "Collapse"
+ *
expand : "Expand"
+ *
+ *
+ * @attribute strings
+ * @type Object
+ */
+ strings : {
+ value : {
+ title : "Log Console",
+ pause : "Pause",
+ clear : "Clear",
+ collapse : "Collapse",
+ expand : "Expand"
+ }
+ },
+
+ /**
+ * Boolean to pause the outputting of new messages to the console.
+ * When paused, messages will accumulate in the buffer.
+ *
+ * @attribute paused
+ * @type boolean
+ * @default false
+ */
+ paused : {
+ value : false,
+ validator : L.isBoolean
+ },
+
+ /**
+ * If a category is not specified in the Y.log(..) statement, this
+ * category will be used. Categories "info",
+ * "warn", and "error" are also called log level.
+ *
+ * @attribute defaultCategory
+ * @type String
+ * @default "info"
+ */
+ defaultCategory : {
+ value : INFO,
+ validator : isString
+ },
+
+ /**
+ * If a source is not specified in the Y.log(..) statement, this
+ * source will be used.
+ *
+ * @attribute defaultSource
+ * @type String
+ * @default "global"
+ */
+ defaultSource : {
+ value : 'global',
+ validator : isString
+ },
+
+ /**
+ * Markup template used to create the DOM structure for Console entries.
+ *
+ * @attribute entryTemplate
+ * @type String
+ * @default Console.ENTRY_TEMPLATE
+ */
+ entryTemplate : {
+ value : ENTRY_TEMPLATE_STR,
+ validator : isString
+ },
+
+ /**
+ * Minimum entry log level to render into the Console. The initial
+ * logLevel value for all Console instances defaults from the
+ * Y.config.logLevel YUI configuration, or Console.LOG_LEVEL_INFO if
+ * that configuration is not set.
+ *
+ * Possible values are "info", "warn",
+ * "error" (case insensitive), or their corresponding statics
+ * Console.LOG_LEVEL_INFO and so on.
+ *
+ * @attribute logLevel
+ * @type String
+ * @default Y.config.logLevel or Console.LOG_LEVEL_INFO
+ */
+ logLevel : {
+ value : Y.config.logLevel || INFO,
+ setter : function (v) {
+ return this._setLogLevel(v);
+ }
+ },
+
+ /**
+ * Millisecond timeout between iterations of the print loop, moving
+ * entries from the buffer to the UI.
+ *
+ * @attribute printTimeout
+ * @type Number
+ * @default 100
+ */
+ printTimeout : {
+ value : 100,
+ validator : isNumber
+ },
+
+ /**
+ * Maximum number of entries printed in each iteration of the print
+ * loop. This is used to prevent excessive logging locking the page UI.
+ *
+ * @attribute printLimit
+ * @type Number
+ * @default 50
+ */
+ printLimit : {
+ value : 50,
+ validator : isNumber
+ },
+
+ /**
+ * Maximum number of Console entries allowed in the Console body at one
+ * time. This is used to keep acquired messages from exploding the
+ * DOM tree and impacting page performance.
+ *
+ * @attribute consoleLimit
+ * @type Number
+ * @default 300
+ */
+ consoleLimit : {
+ value : 300,
+ validator : isNumber
+ },
+
+ /**
+ * New entries should display at the top of the Console or the bottom?
+ *
+ * @attribute newestOnTop
+ * @type Boolean
+ * @default true
+ */
+ newestOnTop : {
+ value : true
+ },
+
+ /**
+ * When new entries are added to the Console UI, should they be
+ * scrolled into view?
+ *
+ * @attribute scrollIntoView
+ * @type Boolean
+ * @default true
+ */
+ scrollIntoView : {
+ value : true
+ },
+
+ /**
+ * The baseline time for this Console instance, used to measure elapsed
+ * time from the moment the console module is used to the
+ * moment each new entry is logged (not rendered).
+ *
+ * This value is reset by the instance method myConsole.reset().
+ *
+ * @attribute startTime
+ * @type Date
+ * @default The moment the console module is used
+ */
+ startTime : {
+ value : new Date()
+ },
+
+ /**
+ * The precise time the last entry was logged. Used to measure elapsed
+ * time between log messages.
+ *
+ * @attribute lastTime
+ * @type Date
+ * @default The moment the console module is used
+ */
+ lastTime : {
+ value : new Date(),
+ readOnly: true
+ },
+
+ /**
+ * Controls the collapsed state of the Console
+ *
+ * @attribute collapsed
+ * @type Boolean
+ * @default false
+ */
+ collapsed : {
+ value : false
+ },
+
+ /**
+ * String with units, or number, representing the height of the Console,
+ * inclusive of header and footer. If a number is provided, the default
+ * unit, defined by Widget's DEF_UNIT, property is used.
+ *
+ * @attribute height
+ * @default "300px"
+ * @type {String | Number}
+ */
+ height: {
+ value: "300px"
+ },
+
+ /**
+ * String with units, or number, representing the width of the Console.
+ * If a number is provided, the default unit, defined by Widget's
+ * DEF_UNIT, property is used.
+ *
+ * @attribute width
+ * @default "300px"
+ * @type {String | Number}
+ */
+ width: {
+ value: "300px"
+ },
+
+ /**
+ * Pass through to the YUI instance useBrowserConsole configuration.
+ * By default this is set to false, which will disable logging to the
+ * browser console when a Console instance is created. If the
+ * logSource is not a YUI instance, this has no effect.
+ *
+ * @attribute useBrowserConsole
+ * @type {Boolean}
+ * @default false
+ */
+ useBrowserConsole : {
+ lazyAdd: false,
+ value: false,
+ getter : function () {
+ var logSource = this.get('logSource');
+ return logSource instanceof YUI ?
+ logSource.config.useBrowserConsole : null;
+ },
+ setter : function (v) {
+ var logSource = this.get('logSource');
+ if (logSource instanceof YUI) {
+ v = !!v;
+ logSource.config.useBrowserConsole = !!v;
+ return v;
+ } else {
+ return Y.Attribute.INVALID_VALUE;
+ }
+ }
+ },
+
+ /**
+ * Allows the Console to flow in the document. Available values are
+ * 'inline', 'block', and 'separate' (the default).
+ *
+ * @attribute style
+ * @type {String}
+ * @default 'separate'
+ */
+ style : {
+ value : 'separate',
+ writeOnce : true,
+ validator : function (v) {
+ return this._validateStyle(v);
+ }
+ }
+ }
+
+});
+
+Y.extend(Console,Y.Widget,{
+
+ /**
+ * Category to prefix all event subscriptions to allow for ease of detach
+ * during destroy.
+ *
+ * @property _evtCat
+ * @type string
+ * @protected
+ */
+ _evtCat : null,
+
+ /**
+ * Reference to the Node instance containing the header contents.
+ *
+ * @property _head
+ * @type Node
+ * @default null
+ * @protected
+ */
+ _head : null,
+
+ /**
+ * Reference to the Node instance that will house the console messages.
+ *
+ * @property _body
+ * @type Node
+ * @default null
+ * @protected
+ */
+ _body : null,
+
+ /**
+ * Reference to the Node instance containing the footer contents.
+ *
+ * @property _foot
+ * @type Node
+ * @default null
+ * @protected
+ */
+ _foot : null,
+
+ /**
+ * Holds the object API returned from Y.later for the print
+ * loop interval.
+ *
+ * @property _printLoop
+ * @type Object
+ * @default null
+ * @protected
+ */
+ _printLoop : null,
+
+ /**
+ * Array of normalized message objects awaiting printing.
+ *
+ * @property buffer
+ * @type Array
+ * @default null
+ * @protected
+ */
+ buffer : null,
+
+ /**
+ * Wrapper for Y.log.
+ *
+ * @method log
+ * @param arg* {MIXED} (all arguments passed through to Y.log)
+ * @chainable
+ */
+ log : function () {
+ Y.log.apply(Y,arguments);
+
+ return this;
+ },
+
+ /**
+ * Clear the console of messages and flush the buffer of pending messages.
+ *
+ * @method clearConsole
+ * @chainable
+ */
+ clearConsole : function () {
+ // TODO: clear event listeners from console contents
+ this._body.set(INNER_HTML,'');
+
+ this._cancelPrintLoop();
+
+ this.buffer = [];
+
+ return this;
+ },
+
+ /**
+ * Clears the console and resets internal timers.
+ *
+ * @method reset
+ * @chainable
+ */
+ reset : function () {
+ this.fire(RESET);
+
+ return this;
+ },
+
+ /**
+ * Collapses the body and footer.
+ *
+ * @method collapse
+ * @chainable
+ */
+ collapse : function () {
+ this.set(COLLAPSED, true);
+
+ return this;
+ },
+
+ /**
+ * Expands the body and footer if collapsed.
+ *
+ * @method expand
+ * @chainable
+ */
+ expand : function () {
+ this.set(COLLAPSED, false);
+
+ return this;
+ },
+
+ /**
+ * Outputs buffered messages to the console UI. This is typically called
+ * from a scheduled interval until the buffer is empty (referred to as the
+ * print loop). The number of buffered messages output to the Console is
+ * limited to the number provided as an argument. If no limit is passed,
+ * all buffered messages are rendered.
+ *
+ * @method printBuffer
+ * @param limit {Number} (optional) max number of buffered entries to write
+ * @chainable
+ */
+ printBuffer: function (limit) {
+ var messages = this.buffer,
+ debug = Y.config.debug,
+ entries = [],
+ consoleLimit= this.get('consoleLimit'),
+ newestOnTop = this.get('newestOnTop'),
+ anchor = newestOnTop ? this._body.get('firstChild') : null,
+ i;
+
+ if (messages.length > consoleLimit) {
+ messages.splice(0, messages.length - consoleLimit);
+ }
+
+ limit = Math.min(messages.length, (limit || messages.length));
+
+ // turn off logging system
+ Y.config.debug = false;
+
+ if (!this.get(PAUSED) && this.get('rendered')) {
+
+ for (i = 0; i < limit && messages.length; ++i) {
+ entries[i] = this._createEntryHTML(messages.shift());
+ }
+
+ if (!messages.length) {
+ this._cancelPrintLoop();
+ }
+
+ if (entries.length) {
+ if (newestOnTop) {
+ entries.reverse();
+ }
+
+ this._body.insertBefore(create(entries.join('')), anchor);
+
+ if (this.get('scrollIntoView')) {
+ this.scrollToLatest();
+ }
+
+ this._trimOldEntries();
+ }
+ }
+
+ // restore logging system
+ Y.config.debug = debug;
+
+ return this;
+ },
+
+
+ /**
+ * Constructor code. Set up the buffer and entry template, publish
+ * internal events, and subscribe to the configured logEvent.
+ *
+ * @method initializer
+ * @protected
+ */
+ initializer : function () {
+ this._evtCat = Y.stamp(this) + '|';
+
+ this.buffer = [];
+
+ this.get('logSource').on(this._evtCat +
+ this.get('logEvent'),Y.bind("_onLogEvent",this));
+
+ /**
+ * Transfers a received message to the print loop buffer. Default
+ * behavior defined in _defEntryFn.
+ *
+ * @event entry
+ * @param event {Event.Facade} An Event Facade object with the following attribute specific properties added:
+ *
+ *
message
+ *
The message data normalized into an object literal (see _normalizeMessage)
+ *
+ * @preventable _defEntryFn
+ */
+ this.publish(ENTRY, { defaultFn: this._defEntryFn });
+
+ /**
+ * Triggers the reset behavior via the default logic in _defResetFn.
+ *
+ * @event reset
+ * @param event {Event.Facade} Event Facade object
+ * @preventable _defResetFn
+ */
+ this.publish(RESET, { defaultFn: this._defResetFn });
+
+ this.after('rendered', this._schedulePrint);
+ },
+
+ /**
+ * Tears down the instance, flushing event subscriptions and purging the UI.
+ *
+ * @method destructor
+ * @protected
+ */
+ destructor : function () {
+ var bb = this.get('boundingBox');
+
+ this._cancelPrintLoop();
+
+ this.get('logSource').detach(this._evtCat + '*');
+
+ Y.Event.purgeElement(bb, true);
+
+ bb.set('innerHTML','');
+ },
+
+ /**
+ * Generate the Console UI.
+ *
+ * @method renderUI
+ * @protected
+ */
+ renderUI : function () {
+ this._initHead();
+ this._initBody();
+ this._initFoot();
+
+ // Apply positioning to the bounding box if appropriate
+ var style = this.get('style');
+ if (style !== 'block') {
+ this.get('boundingBox').addClass('yui-'+style+'-console');
+ }
+ },
+
+ /**
+ * Sync the UI state to the current attribute state.
+ *
+ * @method syncUI
+ */
+ syncUI : function () {
+ this._uiUpdatePaused(this.get(PAUSED));
+ this._uiUpdateCollapsed(this.get(COLLAPSED));
+ this._uiSetHeight(this.get(HEIGHT));
+ },
+
+ /**
+ * Set up event listeners to wire up the UI to the internal state.
+ *
+ * @method bindUI
+ * @protected
+ */
+ bindUI : function () {
+ this.get(CONTENT_BOX).query('button.'+C_COLLAPSE).
+ on(CLICK,this._onCollapseClick,this);
+
+ this.get(CONTENT_BOX).query('input[type=checkbox].'+C_PAUSE).
+ on(CLICK,this._onPauseClick,this);
+
+ this.get(CONTENT_BOX).query('button.'+C_CLEAR).
+ on(CLICK,this._onClearClick,this);
+
+ // Attribute changes
+ this.after(this._evtCat + 'stringsChange',
+ this._afterStringsChange);
+ this.after(this._evtCat + 'pausedChange',
+ this._afterPausedChange);
+ this.after(this._evtCat + 'consoleLimitChange',
+ this._afterConsoleLimitChange);
+ this.after(this._evtCat + 'collapsedChange',
+ this._afterCollapsedChange);
+ },
+
+
+ /**
+ * Create the DOM structure for the header elements.
+ *
+ * @method _initHead
+ * @protected
+ */
+ _initHead : function () {
+ var cb = this.get(CONTENT_BOX),
+ info = merge(Console.CHROME_CLASSES, {
+ str_collapse : this.get('strings.collapse'),
+ str_title : this.get('strings.title')
+ });
+
+ this._head = create(substitute(Console.HEADER_TEMPLATE,info));
+
+ cb.insertBefore(this._head,cb.get('firstChild'));
+ },
+
+ /**
+ * Create the DOM structure for the console body—where messages are
+ * rendered.
+ *
+ * @method _initBody
+ * @protected
+ */
+ _initBody : function () {
+ this._body = create(substitute(
+ Console.BODY_TEMPLATE,
+ Console.CHROME_CLASSES));
+
+ this.get(CONTENT_BOX).appendChild(this._body);
+ },
+
+ /**
+ * Create the DOM structure for the footer elements.
+ *
+ * @method _initFoot
+ * @protected
+ */
+ _initFoot : function () {
+ var info = merge(Console.CHROME_CLASSES, {
+ id_guid : Y.guid(),
+ str_pause : this.get('strings.pause'),
+ str_clear : this.get('strings.clear')
+ });
+
+ this._foot = create(substitute(Console.FOOTER_TEMPLATE,info));
+
+ this.get(CONTENT_BOX).appendChild(this._foot);
+ },
+
+ /**
+ * Determine if incoming log messages are within the configured logLevel
+ * to be buffered for printing.
+ *
+ * @method _isInLogLevel
+ * @protected
+ */
+ _isInLogLevel : function (e) {
+ var cat = e.cat, lvl = this.get('logLevel');
+
+ if (lvl !== INFO) {
+ cat = cat || INFO;
+
+ if (isString(cat)) {
+ cat = cat.toLowerCase();
+ }
+
+ if ((cat === WARN && lvl === ERROR) ||
+ (cat === INFO && lvl !== INFO)) {
+ return false;
+ }
+ }
+
+ return true;
+ },
+
+ /**
+ * Create a log entry message from the inputs including the following keys:
+ *
+ *
time - this moment
+ *
message - leg message
+ *
category - logLevel or custom category for the message
+ *
source - when provided, the widget or util calling Y.log
+ *
sourceAndDetail - same as source but can include instance info
+ *
localTime - readable version of time
+ *
elapsedTime - ms since last entry
+ *
totalTime - ms since Console was instantiated or reset
+ *
+ *
+ * @method _normalizeMessage
+ * @param e {Event} custom event containing the log message
+ * @return Object the message object
+ * @protected
+ */
+ _normalizeMessage : function (e) {
+
+ var msg = e.msg,
+ cat = e.cat,
+ src = e.src,
+
+ m = {
+ time : new Date(),
+ message : msg,
+ category : cat || this.get('defaultCategory'),
+ sourceAndDetail : src || this.get('defaultSource'),
+ source : null,
+ localTime : null,
+ elapsedTime : null,
+ totalTime : null
+ };
+
+ // Extract m.source "Foo" from m.sourceAndDetail "Foo bar baz"
+ m.source = RE_INLINE_SOURCE.test(m.sourceAndDetail) ?
+ RegExp.$1 : m.sourceAndDetail;
+ m.localTime = m.time.toLocaleTimeString ?
+ m.time.toLocaleTimeString() : (m.time + '');
+ m.elapsedTime = m.time - this.get(LAST_TIME);
+ m.totalTime = m.time - this.get(START_TIME);
+
+ this._set(LAST_TIME,m.time);
+
+ return m;
+ },
+
+ /**
+ * Sets an interval for buffered messages to be output to the console.
+ *
+ * @method _schedulePrint
+ * @protected
+ */
+ _schedulePrint : function () {
+ if (!this._printLoop && !this.get(PAUSED) && this.get('rendered')) {
+ this._printLoop = Y.later(
+ this.get('printTimeout'),
+ this, this.printBuffer,
+ this.get('printLimit'), true);
+ }
+ },
+
+ /**
+ * Translates message meta into the markup for a console entry.
+ *
+ * @method _createEntryHTML
+ * @param m {Object} object literal containing normalized message metadata
+ * @return String
+ * @protected
+ */
+ _createEntryHTML : function (m) {
+ m = merge(
+ this._htmlEscapeMessage(m),
+ Console.ENTRY_CLASSES,
+ {
+ cat_class : this.getClassName(ENTRY,m.category),
+ src_class : this.getClassName(ENTRY,m.source)
+ });
+
+ return this.get('entryTemplate').replace(/\{(\w+)\}/g,
+ function (_,token) {
+ return token in m ? m[token] : '';
+ });
+ },
+
+ /**
+ * Scrolls to the most recent entry
+ *
+ * @method scrollToLatest
+ * @chainable
+ */
+ scrollToLatest : function () {
+ var scrollTop = this.get('newestOnTop') ?
+ 0 :
+ this._body.get('scrollHeight');
+
+ this._body.set('scrollTop', scrollTop);
+ },
+
+ /**
+ * Performs HTML escaping on strings in the message object.
+ *
+ * @method _htmlEscapeMessage
+ * @param m {Object} the normalized message object
+ * @return Object the message object with proper escapement
+ * @protected
+ */
+ _htmlEscapeMessage : function (m) {
+ m.message = this._encodeHTML(m.message);
+ m.source = this._encodeHTML(m.source);
+ m.sourceAndDetail = this._encodeHTML(m.sourceAndDetail);
+ m.category = this._encodeHTML(m.category);
+
+ return m;
+ },
+
+ /**
+ * Removes the oldest message entries from the UI to maintain the limit
+ * specified in the consoleLimit configuration.
+ *
+ * @method _trimOldEntries
+ * @protected
+ */
+ _trimOldEntries : function () {
+ // Turn off the logging system for the duration of this operation
+ // to prevent an infinite loop
+ Y.config.debug = false;
+
+ var bd = this._body,
+ limit = this.get('consoleLimit'),
+ debug = Y.config.debug,
+ entries,e,i,l;
+
+ if (bd) {
+ entries = bd.queryAll(DOT+C_ENTRY);
+ l = entries.size() - limit;
+
+ if (l > 0) {
+ if (this.get('newestOnTop')) {
+ i = limit;
+ l = entries.size();
+ } else {
+ i = 0;
+ }
+
+ this._body.setStyle('display','none');
+
+ for (;i < l; ++i) {
+ e = entries.item(i);
+ if (e) {
+ e.remove();
+ }
+ }
+
+ this._body.setStyle('display','');
+ }
+
+ }
+
+ Y.config.debug = debug;
+ },
+
+ /**
+ * Returns the input string with ampersands (&), <, and > encoded
+ * as HTML entities.
+ *
+ * @method _encodeHTML
+ * @param s {String} the raw string
+ * @return String the encoded string
+ * @protected
+ */
+ _encodeHTML : function (s) {
+ return isString(s) ?
+ s.replace(RE_AMP,ESC_AMP).
+ replace(RE_LT, ESC_LT).
+ replace(RE_GT, ESC_GT) :
+ s;
+ },
+
+ /**
+ * Clears the timeout for printing buffered messages.
+ *
+ * @method _cancelPrintLoop
+ * @protected
+ */
+ _cancelPrintLoop : function () {
+ if (this._printLoop) {
+ this._printLoop.cancel();
+ this._printLoop = null;
+ }
+ },
+
+ /**
+ * Validates input value for style attribute. Accepts only values 'inline',
+ * 'block', and 'separate'.
+ *
+ * @method _validateStyle
+ * @param style {String} the proposed value
+ * @return {Boolean} pass/fail
+ * @protected
+ */
+ _validateStyle : function (style) {
+ return style === 'inline' || style === 'block' || style === 'separate';
+ },
+
+ /**
+ * Event handler for clicking on the Pause checkbox to update the paused
+ * attribute.
+ *
+ * @method _onPauseClick
+ * @param e {Event} DOM event facade for the click event
+ * @protected
+ */
+ _onPauseClick : function (e) {
+ this.set(PAUSED,e.target.get(CHECKED));
+ },
+
+ /**
+ * Event handler for clicking on the Clear button. Pass-through to
+ * this.clearConsole().
+ *
+ * @method _onClearClick
+ * @param e {Event} DOM event facade for the click event
+ * @protected
+ */
+ _onClearClick : function (e) {
+ this.clearConsole();
+ },
+
+ /**
+ * Event handler for clicking on the Collapse/Expand button. Sets the
+ * "collapsed" attribute accordingly.
+ *
+ * @method _onCollapseClick
+ * @param e {Event} DOM event facade for the click event
+ * @protected
+ */
+ _onCollapseClick : function (e) {
+ this.set(COLLAPSED, !this.get(COLLAPSED));
+ },
+
+
+ /**
+ * Setter method for logLevel attribute. Acceptable values are
+ * "error", "warn", and "info" (case
+ * insensitive). Other values are treated as "info".
+ *
+ * @method _setLogLevel
+ * @param v {String} the desired log level
+ * @return String One of Console.LOG_LEVEL_INFO, _WARN, or _ERROR
+ * @protected
+ */
+ _setLogLevel : function (v) {
+ if (isString(v)) {
+ v = v.toLowerCase();
+ }
+
+ return (v === WARN || v === ERROR) ? v : INFO;
+ },
+
+ /**
+ * Set the height of the Console container. Set the body height to the difference between the configured height and the calculated heights of the header and footer.
+ * Overrides Widget.prototype._uiSetHeight.
+ *
+ * @method _uiSetHeight
+ * @param v {String|Number} the new height
+ * @protected
+ */
+ _uiSetHeight : function (v) {
+ Console.superclass._uiSetHeight.apply(this,arguments);
+
+ if (this._head && this._foot) {
+ var h = this.get('boundingBox').get('offsetHeight') -
+ this._head.get('offsetHeight') -
+ this._foot.get('offsetHeight');
+
+ this._body.setStyle(HEIGHT,h+'px');
+ }
+ },
+
+ /**
+ * Updates the UI if changes are made to any of the strings in the strings
+ * attribute.
+ *
+ * @method _afterStringsChange
+ * @param e {Event} Custom event for the attribute change
+ * @protected
+ */
+ _afterStringsChange : function (e) {
+ var prop = e.subAttrName ? e.subAttrName.split(DOT)[1] : null,
+ cb = this.get(CONTENT_BOX),
+ before = e.prevVal,
+ after = e.newVal;
+
+ if ((!prop || prop === TITLE) && before.title !== after.title) {
+ cb.queryAll(DOT+C_CONSOLE_TITLE).set(INNER_HTML, after.title);
+ }
+
+ if ((!prop || prop === PAUSE) && before.pause !== after.pause) {
+ cb.queryAll(DOT+C_PAUSE_LABEL).set(INNER_HTML, after.pause);
+ }
+
+ if ((!prop || prop === CLEAR) && before.clear !== after.clear) {
+ cb.queryAll(DOT+C_CLEAR).set('value',after.clear);
+ }
+ },
+
+ /**
+ * Updates the UI and schedules or cancels the print loop.
+ *
+ * @method _afterPausedChange
+ * @param e {Event} Custom event for the attribute change
+ * @protected
+ */
+ _afterPausedChange : function (e) {
+ var paused = e.newVal;
+
+ if (e.src !== Y.Widget.SRC_UI) {
+ this._uiUpdatePaused(paused);
+ }
+
+ if (!paused) {
+ this._schedulePrint();
+ } else if (this._printLoop) {
+ this._cancelPrintLoop();
+ }
+ },
+
+ /**
+ * Checks or unchecks the paused checkbox
+ *
+ * @method _uiUpdatePaused
+ * @param on {Boolean} the new checked state
+ * @protected
+ */
+ _uiUpdatePaused : function (on) {
+ var node = this._foot.queryAll('input[type=checkbox].'+C_PAUSE);
+
+ if (node) {
+ node.set(CHECKED,on);
+ }
+ },
+
+ /**
+ * Calls this._trimOldEntries() in response to changes in the configured
+ * consoleLimit attribute.
+ *
+ * @method _afterConsoleLimitChange
+ * @param e {Event} Custom event for the attribute change
+ * @protected
+ */
+ _afterConsoleLimitChange : function () {
+ this._trimOldEntries();
+ },
+
+
+ /**
+ * Updates the className of the contentBox, which should trigger CSS to
+ * hide or show the body and footer sections depending on the new value.
+ *
+ * @method _afterCollapsedChange
+ * @param e {Event} Custom event for the attribute change
+ * @protected
+ */
+ _afterCollapsedChange : function (e) {
+ this._uiUpdateCollapsed(e.newVal);
+ },
+
+ /**
+ * Updates the UI to reflect the new Collapsed state
+ *
+ * @method _uiUpdateCollapsed
+ * @param v {Boolean} true for collapsed, false for expanded
+ * @protected
+ */
+ _uiUpdateCollapsed : function (v) {
+ var bb = this.get('boundingBox'),
+ button = bb.queryAll('button.'+C_COLLAPSE),
+ method = v ? 'addClass' : 'removeClass',
+ str = this.get('strings.'+(v ? 'expand' : 'collapse'));
+
+ bb[method](C_COLLAPSED);
+
+ if (button) {
+ button.set('innerHTML',str);
+ }
+
+ this._uiSetHeight(v ? this._head.get('offsetHeight'): this.get(HEIGHT));
+ },
+
+ /**
+ * Makes adjustments to the UI if needed when the Console is hidden or shown
+ *
+ * @method _afterVisibleChange
+ * @param e {Event} the visibleChange event
+ * @protected
+ */
+ _afterVisibleChange : function (e) {
+ Console.superclass._afterVisibleChange.apply(this,arguments);
+
+ this._uiUpdateFromHideShow(e.newVal);
+ },
+
+ /**
+ * Recalculates dimensions and updates appropriately when shown
+ *
+ * @method _uiUpdateFromHideShow
+ * @param v {Boolean} true for visible, false for hidden
+ * @protected
+ */
+ _uiUpdateFromHideShow : function (v) {
+ if (v) {
+ this._uiSetHeight(this.get(HEIGHT));
+ }
+ },
+
+ /**
+ * Responds to log events by normalizing qualifying messages and passing
+ * them along through the entry event for buffering etc.
+ *
+ * @method _onLogEvent
+ * @param msg {String} the log message
+ * @param cat {String} OPTIONAL the category or logLevel of the message
+ * @param src {String} OPTIONAL the source of the message (e.g. widget name)
+ * @protected
+ */
+ _onLogEvent : function (e) {
+
+ if (!this.get(DISABLED) && this._isInLogLevel(e)) {
+
+ var debug = Y.config.debug;
+
+ /* TODO: needed? */
+ Y.config.debug = false;
+
+ this.fire(ENTRY, {
+ message : this._normalizeMessage(e)
+ });
+
+ Y.config.debug = debug;
+ }
+ },
+
+ /**
+ * Clears the console, resets the startTime attribute, enables and
+ * unpauses the widget.
+ *
+ * @method _defResetFn
+ * @protected
+ */
+ _defResetFn : function () {
+ this.clearConsole();
+ this.set(START_TIME,new Date());
+ this.set(DISABLED,false);
+ this.set(PAUSED,false);
+ },
+
+ /**
+ * Buffers incoming message objects and schedules the printing.
+ *
+ * @method _defEntryFn
+ * @param e {Event} The Custom event carrying the message in its payload
+ * @protected
+ */
+ _defEntryFn : function (e) {
+ if (e.message) {
+ this.buffer.push(e.message);
+ this._schedulePrint();
+ }
+ }
+
+});
+
+Y.Console = Console;
+
+
+}, '3.0.0' ,{requires:['substitute','widget']});
diff --git a/lib/yui/3.0.0/console/console-filters-debug.js b/lib/yui/3.0.0/console/console-filters-debug.js
new file mode 100644
index 0000000000..126e6a665e
--- /dev/null
+++ b/lib/yui/3.0.0/console/console-filters-debug.js
@@ -0,0 +1,710 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('console-filters', function(Y) {
+
+/**
+ *
Provides Plugin.ConsoleFilters plugin class.
+ *
+ *
This plugin adds the ability to control which Console entries display by filtering on category and source. Two groups of checkboxes are added to the Console footer, one for categories and the other for sources. Only those messages that match a checked category or source are displayed.
Map of entry categories to their visibility status. Update a
+ * particular category's visibility by setting the subattribute to true
+ * (visible) or false (hidden).
+ *
+ *
For example, yconsole.filter.set('category.info', false) to hide
+ * log entries with the category/logLevel of 'info'.
+ *
+ *
Similarly, yconsole.filter.get('category.warn') will return a
+ * boolean indicating whether that category is currently being included
+ * in the UI.
+ *
+ *
Unlike the YUI instance configuration's logInclude and logExclude
+ * properties, filtered entries are only hidden from the UI, but
+ * can be made visible again.
Map of entry sources to their visibility status. Update a
+ * particular sources's visibility by setting the subattribute to true
+ * (visible) or false (hidden).
+ *
+ *
For example, yconsole.filter.set('sources.slider', false) to hide
+ * log entries originating from Y.Slider.
+ *
+ * @attribute source
+ * @type Object
+ */
+ source : {
+ value : {},
+ validator : function (v,k) {
+ return this._validateSource(k,v);
+ }
+ },
+
+ /**
+ * Maximum number of entries to store in the message cache. Use this to
+ * limit the memory footprint in environments with heavy log usage.
+ * By default, there is no limit (Number.POSITIVE_INFINITY).
+ *
+ * @attribute cacheLimit
+ * @type {Number}
+ * @default Number.POSITIVE_INFINITY
+ */
+ cacheLimit : {
+ value : Number.POSITIVE_INFINITY,
+ setter : function (v) {
+ if (Y.Lang.isNumber(v)) {
+ this._cacheLimit = v;
+ return v;
+ } else {
+ return Y.Attribute.INVALID_VALUE;
+ }
+ }
+ }
+ }
+});
+
+Y.extend(ConsoleFilters, Y.Plugin.Base, {
+
+ /**
+ * Collection of all log messages passed through since the plugin's
+ * instantiation. This holds all messages regardless of filter status.
+ * Used as a single source of truth for repopulating the Console body when
+ * filters are changed.
+ *
+ * @property _entries
+ * @type Array
+ * @protected
+ */
+ _entries : null,
+
+ _cacheLimit : Number.POSITIVE_INFINITY,
+
+ /**
+ * The container node created to house the category filters.
+ *
+ * @property _categories
+ * @type Node
+ * @protected
+ */
+ _categories : null,
+
+ /**
+ * The container node created to house the source filters.
+ *
+ * @property _sources
+ * @type Node
+ * @protected
+ */
+ _sources : null,
+
+ /**
+ * Initialize entries collection and attach listeners to host events and
+ * methods.
+ *
+ * @method initializer
+ * @protected
+ */
+ initializer : function () {
+ this._entries = [];
+
+ this.get(HOST).on("entry", this._onEntry, this);
+
+ this.doAfter("renderUI", this.renderUI);
+ this.doAfter("syncUI", this.syncUI);
+ this.doAfter("bindUI", this.bindUI);
+
+ this.doAfter("clearConsole", this._afterClearConsole);
+
+ if (this.get(HOST).get('rendered')) {
+ this.renderUI();
+ this.syncUI();
+ this.bindUI();
+ }
+
+ this.after("cacheLimitChange", this._afterCacheLimitChange);
+ },
+
+ /**
+ * Removes the plugin UI and unwires events.
+ *
+ * @method destructor
+ * @protected
+ */
+ destructor : function () {
+ //TODO: grab last {consoleLimit} entries and update the console with
+ //them (no filtering)
+ this._entries = [];
+
+ if (this._categories) {
+ this._categories.get(PARENT_NODE).removeChild(this._categories);
+ }
+ if (this._sources) {
+ this._sources.get(PARENT_NODE).removeChild(this._sources);
+ }
+ },
+
+ /**
+ * Adds the category and source filter sections to the Console footer.
+ *
+ * @method renderUI
+ * @protected
+ */
+ renderUI : function () {
+ var foot = this.get(HOST).get('contentBox').query(C_FOOT),
+ html;
+
+ if (foot) {
+ html = Y.substitute(
+ ConsoleFilters.CATEGORIES_TEMPLATE,
+ ConsoleFilters.CHROME_CLASSES);
+
+ this._categories = foot.appendChild(Y.Node.create(html));
+
+ html = Y.substitute(
+ ConsoleFilters.SOURCES_TEMPLATE,
+ ConsoleFilters.CHROME_CLASSES);
+
+ this._sources = foot.appendChild(Y.Node.create(html));
+ }
+ },
+
+ /**
+ * Binds to checkbox click events and internal attribute change events to
+ * maintain the UI state.
+ *
+ * @method bindUI
+ * @protected
+ */
+ bindUI : function () {
+ this._categories.on('click', Y.bind(this._onCategoryCheckboxClick, this));
+
+ this._sources.on('click', Y.bind(this._onSourceCheckboxClick, this));
+
+ this.after('categoryChange',this._afterCategoryChange);
+ this.after('sourceChange', this._afterSourceChange);
+ },
+
+ /**
+ * Updates the UI to be in accordance with the current state of the plugin.
+ *
+ * @method syncUI
+ */
+ syncUI : function () {
+ Y.each(this.get(CATEGORY), function (v, k) {
+ this._uiSetCheckbox(CATEGORY, k, v);
+ }, this);
+
+ Y.each(this.get(SOURCE), function (v, k) {
+ this._uiSetCheckbox(SOURCE, k, v);
+ }, this);
+
+ this.refreshConsole();
+ },
+
+ /**
+ * Ensures a filter is set up for any new categories or sources and
+ * collects the messages in _entries. If the message is stamped with a
+ * category or source that is currently being filtered out, the message
+ * will not pass to the Console's print buffer.
+ *
+ * @method _onEntry
+ * @param e {Event} the custom event object
+ * @protected
+ */
+ _onEntry : function (e) {
+ this._entries.push(e.message);
+
+ var cat = CATEGORY_DOT + e.message.category,
+ src = SOURCE_DOT + e.message.source,
+ cat_filter = this.get(cat),
+ src_filter = this.get(src),
+ overLimit = this._entries.length - this._cacheLimit,
+ visible;
+
+ if (overLimit > 0) {
+ this._entries.splice(0, overLimit);
+ }
+
+ if (cat_filter === undefined) {
+ visible = this.get(DEF_VISIBILITY);
+ this.set(cat, visible);
+ cat_filter = visible;
+ }
+
+ if (src_filter === undefined) {
+ visible = this.get(DEF_VISIBILITY);
+ this.set(src, visible);
+ src_filter = visible;
+ }
+
+ if (!cat_filter || !src_filter) {
+ e.preventDefault();
+ }
+ },
+
+ /**
+ * Flushes the cached entries after a call to the Console's clearConsole().
+ *
+ * @method _afterClearConsole
+ * @protected
+ */
+ _afterClearConsole : function () {
+ this._entries = [];
+ },
+
+ /**
+ * Triggers the Console to update if a known category filter
+ * changes value (e.g. visible => hidden). Updates the appropriate
+ * checkbox's checked state if necessary.
+ *
+ * @method _afterCategoryChange
+ * @param e {Event} the attribute change event object
+ * @protected
+ */
+ _afterCategoryChange : function (e) {
+ var cat = e.subAttrName.replace(/category\./, EMPTY),
+ before = e.prevVal,
+ after = e.newVal;
+
+ // Don't update the console for new categories
+ if (!cat || before[cat] !== undefined) {
+ this.refreshConsole();
+
+ this._filterBuffer();
+ }
+
+ if (cat && !e.fromUI) {
+ this._uiSetCheckbox(CATEGORY, cat, after[cat]);
+ }
+ },
+
+ /**
+ * Triggers the Console to update if a known source filter
+ * changes value (e.g. visible => hidden). Updates the appropriate
+ * checkbox's checked state if necessary.
+ *
+ * @method _afterSourceChange
+ * @param e {Event} the attribute change event object
+ * @protected
+ */
+ _afterSourceChange : function (e) {
+ var src = e.subAttrName.replace(/source\./, EMPTY),
+ before = e.prevVal,
+ after = e.newVal;
+
+ // Don't update the console for new sources
+ if (!src || before[src] !== undefined) {
+ this.refreshConsole();
+
+ this._filterBuffer();
+ }
+
+ if (src && !e.fromUI) {
+ this._uiSetCheckbox(SOURCE, src, after[src]);
+ }
+ },
+
+ /**
+ * Flushes the Console's print buffer of any entries that have a category
+ * or source that is currently being excluded.
+ *
+ * @method _filterBuffer
+ * @protected
+ */
+ _filterBuffer : function () {
+ var cats = this.get(CATEGORY),
+ srcs = this.get(SOURCE),
+ buffer = this.get(HOST).buffer,
+ start = null,
+ i;
+
+ for (i = buffer.length - 1; i >= 0; --i) {
+ if (!cats[buffer[i].category] || !srcs[buffer[i].source]) {
+ start = start || i;
+ } else if (start) {
+ buffer.splice(i,(start - i));
+ start = null;
+ }
+ }
+ if (start) {
+ buffer.splice(0,start + 1);
+ }
+ },
+
+ /**
+ * Trims the cache of entries to the appropriate new length.
+ *
+ * @method _afterCacheLimitChange
+ * @param e {Event} the attribute change event object
+ * @protected
+ */
+ _afterCacheLimitChange : function (e) {
+ if (isFinite(e.newVal)) {
+ var delta = this._entries.length - e.newVal;
+
+ if (delta > 0) {
+ this._entries.splice(0,delta);
+ }
+ }
+ },
+
+ /**
+ * Repopulates the Console with entries appropriate to the current filter
+ * settings.
+ *
+ * @method refreshConsole
+ */
+ refreshConsole : function () {
+ var entries = this._entries,
+ host = this.get(HOST),
+ body = host.get('contentBox').query(C_BODY),
+ remaining = host.get('consoleLimit'),
+ cats = this.get(CATEGORY),
+ srcs = this.get(SOURCE),
+ buffer = [],
+ i,e;
+
+ if (body) {
+ host._cancelPrintLoop();
+
+ // Evaluate all entries from latest to oldest
+ for (i = entries.length - 1; i >= 0 && remaining >= 0; --i) {
+ e = entries[i];
+ if (cats[e.category] && srcs[e.source]) {
+ buffer.unshift(e);
+ --remaining;
+ }
+ }
+
+ body.set('innerHTML',EMPTY);
+ host.buffer = buffer;
+ host.printBuffer();
+ }
+ },
+
+ /**
+ * Updates the checked property of a filter checkbox of the specified type.
+ * If no checkbox is found for the input params, one is created.
+ *
+ * @method _uiSetCheckbox
+ * @param type {String} 'category' or 'source'
+ * @param item {String} the name of the filter (e.g. 'info', 'event')
+ * @param checked {Boolean} value to set the checkbox's checked property
+ * @protected
+ */
+ _uiSetCheckbox : function (type, item, checked) {
+ if (type && item) {
+ var container = type === CATEGORY ?
+ this._categories :
+ this._sources,
+ sel = SEL_CHECK + getCN(CONSOLE,FILTER,item),
+ checkbox = container.query(sel),
+ host;
+
+ if (!checkbox) {
+ host = this.get(HOST);
+
+ this._createCheckbox(container, item);
+
+ checkbox = container.query(sel);
+
+ host._uiSetHeight(host.get('height'));
+ }
+
+ checkbox.set(CHECKED, checked);
+ }
+ },
+
+ /**
+ * Passes checkbox clicks on to the category attribute.
+ *
+ * @method _onCategoryCheckboxClick
+ * @param e {Event} the DOM event
+ * @protected
+ */
+ _onCategoryCheckboxClick : function (e) {
+ var t = e.target, cat;
+
+ if (t.hasClass(ConsoleFilters.CHROME_CLASSES.filter)) {
+ cat = t.get('value');
+ if (cat && cat in this.get(CATEGORY)) {
+ this.set(CATEGORY_DOT + cat, t.get(CHECKED), { fromUI: true });
+ }
+ }
+ },
+
+ /**
+ * Passes checkbox clicks on to the source attribute.
+ *
+ * @method _onSourceCheckboxClick
+ * @param e {Event} the DOM event
+ * @protected
+ */
+ _onSourceCheckboxClick : function (e) {
+ var t = e.target, src;
+
+ if (t.hasClass(ConsoleFilters.CHROME_CLASSES.filter)) {
+ src = t.get('value');
+ if (src && src in this.get(SOURCE)) {
+ this.set(SOURCE_DOT + src, t.get(CHECKED), { fromUI: true });
+ }
+ }
+ },
+
+ /**
+ * Hides any number of categories from the UI. Convenience method for
+ * myConsole.filter.set('category.foo', false); set('category.bar', false);
+ * and so on.
+ *
+ * @method hideCategory
+ * @param cat* {String} 1..n categories to filter out of the UI
+ */
+ hideCategory : function (cat, multiple) {
+ if (isString(multiple)) {
+ Y.Array.each(arguments, arguments.callee, this);
+ } else {
+ this.set(CATEGORY_DOT + cat, false);
+ }
+ },
+
+ /**
+ * Shows any number of categories in the UI. Convenience method for
+ * myConsole.filter.set('category.foo', true); set('category.bar', true);
+ * and so on.
+ *
+ * @method showCategory
+ * @param cat* {String} 1..n categories to allow to display in the UI
+ */
+ showCategory : function (cat, multiple) {
+ if (isString(multiple)) {
+ Y.Array.each(arguments, arguments.callee, this);
+ } else {
+ this.set(CATEGORY_DOT + cat, true);
+ }
+ },
+
+ /**
+ * Hides any number of sources from the UI. Convenience method for
+ * myConsole.filter.set('source.foo', false); set('source.bar', false);
+ * and so on.
+ *
+ * @method hideSource
+ * @param src* {String} 1..n sources to filter out of the UI
+ */
+ hideSource : function (src, multiple) {
+ if (isString(multiple)) {
+ Y.Array.each(arguments, arguments.callee, this);
+ } else {
+ this.set(SOURCE_DOT + src, false);
+ }
+ },
+
+ /**
+ * Shows any number of sources in the UI. Convenience method for
+ * myConsole.filter.set('source.foo', true); set('source.bar', true);
+ * and so on.
+ *
+ * @method showSource
+ * @param src* {String} 1..n sources to allow to display in the UI
+ */
+ showSource : function (src, multiple) {
+ if (isString(multiple)) {
+ Y.Array.each(arguments, arguments.callee, this);
+ } else {
+ this.set(SOURCE_DOT + src, true);
+ }
+ },
+
+ /**
+ * Creates a checkbox and label from the ConsoleFilters.FILTER_TEMPLATE for
+ * the provided type and name. The checkbox and label are appended to the
+ * container node passes as the first arg.
+ *
+ * @method _createCheckbox
+ * @param container {Node} the parentNode of the new checkbox and label
+ * @param name {String} the identifier of the filter
+ * @protected
+ */
+ _createCheckbox : function (container, name) {
+ var info = Y.merge(ConsoleFilters.CHROME_CLASSES, {
+ filter_name : name,
+ filter_class : getCN(CONSOLE, FILTER, name)
+ }),
+ node = Y.Node.create(
+ Y.substitute(ConsoleFilters.FILTER_TEMPLATE, info));
+
+ container.appendChild(node);
+ },
+
+ /**
+ * Validates category updates are objects and the subattribute is not too
+ * deep.
+ *
+ * @method _validateCategory
+ * @param cat {String} the new category:visibility map
+ * @param v {String} the subattribute path updated
+ * @return Boolean
+ * @protected
+ */
+ _validateCategory : function (cat, v) {
+ return Y.Lang.isObject(v,true) && cat.split(/\./).length < 3;
+ },
+
+ /**
+ * Validates source updates are objects and the subattribute is not too
+ * deep.
+ *
+ * @method _validateSource
+ * @param cat {String} the new source:visibility map
+ * @param v {String} the subattribute path updated
+ * @return Boolean
+ * @protected
+ */
+ _validateSource : function (src, v) {
+ return Y.Lang.isObject(v,true) && src.split(/\./).length < 3;
+ }
+
+});
+
+Y.namespace('Plugin').ConsoleFilters = ConsoleFilters;
+
+
+}, '3.0.0' ,{requires:['console','plugin']});
diff --git a/lib/yui/3.0.0/console/console-filters-min.js b/lib/yui/3.0.0/console/console-filters-min.js
new file mode 100644
index 0000000000..36ca861d4b
--- /dev/null
+++ b/lib/yui/3.0.0/console/console-filters-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("console-filters",function(C){var Q=C.ClassNameManager.getClassName,G="console",B="filters",L="filter",F="category",D="source",E="category.",M="source.",P="host",H="parentNode",R="checked",O="defaultVisibility",N=".",T="",S=N+C.Console.CHROME_CLASSES.console_bd_class,I=N+C.Console.CHROME_CLASSES.console_ft_class,A="input[type=checkbox].",J=C.Lang.isString;function K(){K.superclass.constructor.apply(this,arguments);}C.mix(K,{NAME:"consoleFilters",NS:L,CATEGORIES_TEMPLATE:'',SOURCES_TEMPLATE:'',FILTER_TEMPLATE:' ",CHROME_CLASSES:{categories:Q(G,B,"categories"),sources:Q(G,B,"sources"),category:Q(G,L,F),source:Q(G,L,D),filter:Q(G,L),filter_label:Q(G,L,"label")},ATTRS:{defaultVisibility:{value:true,validator:C.Lang.isBoolean},category:{value:{},validator:function(V,U){return this._validateCategory(U,V);}},source:{value:{},validator:function(V,U){return this._validateSource(U,V);}},cacheLimit:{value:Number.POSITIVE_INFINITY,setter:function(U){if(C.Lang.isNumber(U)){this._cacheLimit=U;return U;}else{return C.Attribute.INVALID_VALUE;}}}}});C.extend(K,C.Plugin.Base,{_entries:null,_cacheLimit:Number.POSITIVE_INFINITY,_categories:null,_sources:null,initializer:function(){this._entries=[];this.get(P).on("entry",this._onEntry,this);this.doAfter("renderUI",this.renderUI);this.doAfter("syncUI",this.syncUI);this.doAfter("bindUI",this.bindUI);this.doAfter("clearConsole",this._afterClearConsole);if(this.get(P).get("rendered")){this.renderUI();this.syncUI();this.bindUI();}this.after("cacheLimitChange",this._afterCacheLimitChange);},destructor:function(){this._entries=[];if(this._categories){this._categories.get(H).removeChild(this._categories);}if(this._sources){this._sources.get(H).removeChild(this._sources);}},renderUI:function(){var V=this.get(P).get("contentBox").query(I),U;if(V){U=C.substitute(K.CATEGORIES_TEMPLATE,K.CHROME_CLASSES);this._categories=V.appendChild(C.Node.create(U));U=C.substitute(K.SOURCES_TEMPLATE,K.CHROME_CLASSES);this._sources=V.appendChild(C.Node.create(U));}},bindUI:function(){this._categories.on("click",C.bind(this._onCategoryCheckboxClick,this));this._sources.on("click",C.bind(this._onSourceCheckboxClick,this));this.after("categoryChange",this._afterCategoryChange);this.after("sourceChange",this._afterSourceChange);},syncUI:function(){C.each(this.get(F),function(V,U){this._uiSetCheckbox(F,U,V);},this);C.each(this.get(D),function(V,U){this._uiSetCheckbox(D,U,V);},this);this.refreshConsole();},_onEntry:function(X){this._entries.push(X.message);var U=E+X.message.category,Z=M+X.message.source,V=this.get(U),a=this.get(Z),W=this._entries.length-this._cacheLimit,Y;if(W>0){this._entries.splice(0,W);}if(V===undefined){Y=this.get(O);this.set(U,Y);V=Y;}if(a===undefined){Y=this.get(O);this.set(Z,Y);a=Y;}if(!V||!a){X.preventDefault();}},_afterClearConsole:function(){this._entries=[];},_afterCategoryChange:function(W){var U=W.subAttrName.replace(/category\./,T),V=W.prevVal,X=W.newVal;if(!U||V[U]!==undefined){this.refreshConsole();this._filterBuffer();}if(U&&!W.fromUI){this._uiSetCheckbox(F,U,X[U]);}},_afterSourceChange:function(V){var X=V.subAttrName.replace(/source\./,T),U=V.prevVal,W=V.newVal;if(!X||U[X]!==undefined){this.refreshConsole();this._filterBuffer();}if(X&&!V.fromUI){this._uiSetCheckbox(D,X,W[X]);}},_filterBuffer:function(){var V=this.get(F),X=this.get(D),U=this.get(P).buffer,Y=null,W;for(W=U.length-1;W>=0;--W){if(!V[U[W].category]||!X[U[W].source]){Y=Y||W;}else{if(Y){U.splice(W,(Y-W));Y=null;}}}if(Y){U.splice(0,Y+1);}},_afterCacheLimitChange:function(U){if(isFinite(U.newVal)){var V=this._entries.length-U.newVal;if(V>0){this._entries.splice(0,V);}}},refreshConsole:function(){var Y=this._entries,c=this.get(P),Z=c.get("contentBox").query(S),V=c.get("consoleLimit"),b=this.get(F),U=this.get(D),W=[],X,a;if(Z){c._cancelPrintLoop();for(X=Y.length-1;X>=0&&V>=0;--X){a=Y[X];if(b[a.category]&&U[a.source]){W.unshift(a);--V;}}Z.set("innerHTML",T);c.buffer=W;c.printBuffer();}},_uiSetCheckbox:function(V,Y,X){if(V&&Y){var U=V===F?this._categories:this._sources,a=A+Q(G,L,Y),Z=U.query(a),W;if(!Z){W=this.get(P);this._createCheckbox(U,Y);Z=U.query(a);W._uiSetHeight(W.get("height"));}Z.set(R,X);}},_onCategoryCheckboxClick:function(W){var V=W.target,U;if(V.hasClass(K.CHROME_CLASSES.filter)){U=V.get("value");if(U&&U in this.get(F)){this.set(E+U,V.get(R),{fromUI:true});}}},_onSourceCheckboxClick:function(V){var U=V.target,W;if(U.hasClass(K.CHROME_CLASSES.filter)){W=U.get("value");if(W&&W in this.get(D)){this.set(M+W,U.get(R),{fromUI:true});}}},hideCategory:function(V,U){if(J(U)){C.Array.each(arguments,arguments.callee,this);}else{this.set(E+V,false);}},showCategory:function(V,U){if(J(U)){C.Array.each(arguments,arguments.callee,this);}else{this.set(E+V,true);}},hideSource:function(V,U){if(J(U)){C.Array.each(arguments,arguments.callee,this);}else{this.set(M+V,false);}},showSource:function(V,U){if(J(U)){C.Array.each(arguments,arguments.callee,this);}else{this.set(M+V,true);}},_createCheckbox:function(U,V){var X=C.merge(K.CHROME_CLASSES,{filter_name:V,filter_class:Q(G,L,V)}),W=C.Node.create(C.substitute(K.FILTER_TEMPLATE,X));U.appendChild(W);},_validateCategory:function(U,V){return C.Lang.isObject(V,true)&&U.split(/\./).length<3;},_validateSource:function(V,U){return C.Lang.isObject(U,true)&&V.split(/\./).length<3;}});C.namespace("Plugin").ConsoleFilters=K;},"3.0.0",{requires:["console","plugin"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/console/console-filters.js b/lib/yui/3.0.0/console/console-filters.js
new file mode 100644
index 0000000000..126e6a665e
--- /dev/null
+++ b/lib/yui/3.0.0/console/console-filters.js
@@ -0,0 +1,710 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('console-filters', function(Y) {
+
+/**
+ *
Provides Plugin.ConsoleFilters plugin class.
+ *
+ *
This plugin adds the ability to control which Console entries display by filtering on category and source. Two groups of checkboxes are added to the Console footer, one for categories and the other for sources. Only those messages that match a checked category or source are displayed.
Map of entry categories to their visibility status. Update a
+ * particular category's visibility by setting the subattribute to true
+ * (visible) or false (hidden).
+ *
+ *
For example, yconsole.filter.set('category.info', false) to hide
+ * log entries with the category/logLevel of 'info'.
+ *
+ *
Similarly, yconsole.filter.get('category.warn') will return a
+ * boolean indicating whether that category is currently being included
+ * in the UI.
+ *
+ *
Unlike the YUI instance configuration's logInclude and logExclude
+ * properties, filtered entries are only hidden from the UI, but
+ * can be made visible again.
Map of entry sources to their visibility status. Update a
+ * particular sources's visibility by setting the subattribute to true
+ * (visible) or false (hidden).
+ *
+ *
For example, yconsole.filter.set('sources.slider', false) to hide
+ * log entries originating from Y.Slider.
+ *
+ * @attribute source
+ * @type Object
+ */
+ source : {
+ value : {},
+ validator : function (v,k) {
+ return this._validateSource(k,v);
+ }
+ },
+
+ /**
+ * Maximum number of entries to store in the message cache. Use this to
+ * limit the memory footprint in environments with heavy log usage.
+ * By default, there is no limit (Number.POSITIVE_INFINITY).
+ *
+ * @attribute cacheLimit
+ * @type {Number}
+ * @default Number.POSITIVE_INFINITY
+ */
+ cacheLimit : {
+ value : Number.POSITIVE_INFINITY,
+ setter : function (v) {
+ if (Y.Lang.isNumber(v)) {
+ this._cacheLimit = v;
+ return v;
+ } else {
+ return Y.Attribute.INVALID_VALUE;
+ }
+ }
+ }
+ }
+});
+
+Y.extend(ConsoleFilters, Y.Plugin.Base, {
+
+ /**
+ * Collection of all log messages passed through since the plugin's
+ * instantiation. This holds all messages regardless of filter status.
+ * Used as a single source of truth for repopulating the Console body when
+ * filters are changed.
+ *
+ * @property _entries
+ * @type Array
+ * @protected
+ */
+ _entries : null,
+
+ _cacheLimit : Number.POSITIVE_INFINITY,
+
+ /**
+ * The container node created to house the category filters.
+ *
+ * @property _categories
+ * @type Node
+ * @protected
+ */
+ _categories : null,
+
+ /**
+ * The container node created to house the source filters.
+ *
+ * @property _sources
+ * @type Node
+ * @protected
+ */
+ _sources : null,
+
+ /**
+ * Initialize entries collection and attach listeners to host events and
+ * methods.
+ *
+ * @method initializer
+ * @protected
+ */
+ initializer : function () {
+ this._entries = [];
+
+ this.get(HOST).on("entry", this._onEntry, this);
+
+ this.doAfter("renderUI", this.renderUI);
+ this.doAfter("syncUI", this.syncUI);
+ this.doAfter("bindUI", this.bindUI);
+
+ this.doAfter("clearConsole", this._afterClearConsole);
+
+ if (this.get(HOST).get('rendered')) {
+ this.renderUI();
+ this.syncUI();
+ this.bindUI();
+ }
+
+ this.after("cacheLimitChange", this._afterCacheLimitChange);
+ },
+
+ /**
+ * Removes the plugin UI and unwires events.
+ *
+ * @method destructor
+ * @protected
+ */
+ destructor : function () {
+ //TODO: grab last {consoleLimit} entries and update the console with
+ //them (no filtering)
+ this._entries = [];
+
+ if (this._categories) {
+ this._categories.get(PARENT_NODE).removeChild(this._categories);
+ }
+ if (this._sources) {
+ this._sources.get(PARENT_NODE).removeChild(this._sources);
+ }
+ },
+
+ /**
+ * Adds the category and source filter sections to the Console footer.
+ *
+ * @method renderUI
+ * @protected
+ */
+ renderUI : function () {
+ var foot = this.get(HOST).get('contentBox').query(C_FOOT),
+ html;
+
+ if (foot) {
+ html = Y.substitute(
+ ConsoleFilters.CATEGORIES_TEMPLATE,
+ ConsoleFilters.CHROME_CLASSES);
+
+ this._categories = foot.appendChild(Y.Node.create(html));
+
+ html = Y.substitute(
+ ConsoleFilters.SOURCES_TEMPLATE,
+ ConsoleFilters.CHROME_CLASSES);
+
+ this._sources = foot.appendChild(Y.Node.create(html));
+ }
+ },
+
+ /**
+ * Binds to checkbox click events and internal attribute change events to
+ * maintain the UI state.
+ *
+ * @method bindUI
+ * @protected
+ */
+ bindUI : function () {
+ this._categories.on('click', Y.bind(this._onCategoryCheckboxClick, this));
+
+ this._sources.on('click', Y.bind(this._onSourceCheckboxClick, this));
+
+ this.after('categoryChange',this._afterCategoryChange);
+ this.after('sourceChange', this._afterSourceChange);
+ },
+
+ /**
+ * Updates the UI to be in accordance with the current state of the plugin.
+ *
+ * @method syncUI
+ */
+ syncUI : function () {
+ Y.each(this.get(CATEGORY), function (v, k) {
+ this._uiSetCheckbox(CATEGORY, k, v);
+ }, this);
+
+ Y.each(this.get(SOURCE), function (v, k) {
+ this._uiSetCheckbox(SOURCE, k, v);
+ }, this);
+
+ this.refreshConsole();
+ },
+
+ /**
+ * Ensures a filter is set up for any new categories or sources and
+ * collects the messages in _entries. If the message is stamped with a
+ * category or source that is currently being filtered out, the message
+ * will not pass to the Console's print buffer.
+ *
+ * @method _onEntry
+ * @param e {Event} the custom event object
+ * @protected
+ */
+ _onEntry : function (e) {
+ this._entries.push(e.message);
+
+ var cat = CATEGORY_DOT + e.message.category,
+ src = SOURCE_DOT + e.message.source,
+ cat_filter = this.get(cat),
+ src_filter = this.get(src),
+ overLimit = this._entries.length - this._cacheLimit,
+ visible;
+
+ if (overLimit > 0) {
+ this._entries.splice(0, overLimit);
+ }
+
+ if (cat_filter === undefined) {
+ visible = this.get(DEF_VISIBILITY);
+ this.set(cat, visible);
+ cat_filter = visible;
+ }
+
+ if (src_filter === undefined) {
+ visible = this.get(DEF_VISIBILITY);
+ this.set(src, visible);
+ src_filter = visible;
+ }
+
+ if (!cat_filter || !src_filter) {
+ e.preventDefault();
+ }
+ },
+
+ /**
+ * Flushes the cached entries after a call to the Console's clearConsole().
+ *
+ * @method _afterClearConsole
+ * @protected
+ */
+ _afterClearConsole : function () {
+ this._entries = [];
+ },
+
+ /**
+ * Triggers the Console to update if a known category filter
+ * changes value (e.g. visible => hidden). Updates the appropriate
+ * checkbox's checked state if necessary.
+ *
+ * @method _afterCategoryChange
+ * @param e {Event} the attribute change event object
+ * @protected
+ */
+ _afterCategoryChange : function (e) {
+ var cat = e.subAttrName.replace(/category\./, EMPTY),
+ before = e.prevVal,
+ after = e.newVal;
+
+ // Don't update the console for new categories
+ if (!cat || before[cat] !== undefined) {
+ this.refreshConsole();
+
+ this._filterBuffer();
+ }
+
+ if (cat && !e.fromUI) {
+ this._uiSetCheckbox(CATEGORY, cat, after[cat]);
+ }
+ },
+
+ /**
+ * Triggers the Console to update if a known source filter
+ * changes value (e.g. visible => hidden). Updates the appropriate
+ * checkbox's checked state if necessary.
+ *
+ * @method _afterSourceChange
+ * @param e {Event} the attribute change event object
+ * @protected
+ */
+ _afterSourceChange : function (e) {
+ var src = e.subAttrName.replace(/source\./, EMPTY),
+ before = e.prevVal,
+ after = e.newVal;
+
+ // Don't update the console for new sources
+ if (!src || before[src] !== undefined) {
+ this.refreshConsole();
+
+ this._filterBuffer();
+ }
+
+ if (src && !e.fromUI) {
+ this._uiSetCheckbox(SOURCE, src, after[src]);
+ }
+ },
+
+ /**
+ * Flushes the Console's print buffer of any entries that have a category
+ * or source that is currently being excluded.
+ *
+ * @method _filterBuffer
+ * @protected
+ */
+ _filterBuffer : function () {
+ var cats = this.get(CATEGORY),
+ srcs = this.get(SOURCE),
+ buffer = this.get(HOST).buffer,
+ start = null,
+ i;
+
+ for (i = buffer.length - 1; i >= 0; --i) {
+ if (!cats[buffer[i].category] || !srcs[buffer[i].source]) {
+ start = start || i;
+ } else if (start) {
+ buffer.splice(i,(start - i));
+ start = null;
+ }
+ }
+ if (start) {
+ buffer.splice(0,start + 1);
+ }
+ },
+
+ /**
+ * Trims the cache of entries to the appropriate new length.
+ *
+ * @method _afterCacheLimitChange
+ * @param e {Event} the attribute change event object
+ * @protected
+ */
+ _afterCacheLimitChange : function (e) {
+ if (isFinite(e.newVal)) {
+ var delta = this._entries.length - e.newVal;
+
+ if (delta > 0) {
+ this._entries.splice(0,delta);
+ }
+ }
+ },
+
+ /**
+ * Repopulates the Console with entries appropriate to the current filter
+ * settings.
+ *
+ * @method refreshConsole
+ */
+ refreshConsole : function () {
+ var entries = this._entries,
+ host = this.get(HOST),
+ body = host.get('contentBox').query(C_BODY),
+ remaining = host.get('consoleLimit'),
+ cats = this.get(CATEGORY),
+ srcs = this.get(SOURCE),
+ buffer = [],
+ i,e;
+
+ if (body) {
+ host._cancelPrintLoop();
+
+ // Evaluate all entries from latest to oldest
+ for (i = entries.length - 1; i >= 0 && remaining >= 0; --i) {
+ e = entries[i];
+ if (cats[e.category] && srcs[e.source]) {
+ buffer.unshift(e);
+ --remaining;
+ }
+ }
+
+ body.set('innerHTML',EMPTY);
+ host.buffer = buffer;
+ host.printBuffer();
+ }
+ },
+
+ /**
+ * Updates the checked property of a filter checkbox of the specified type.
+ * If no checkbox is found for the input params, one is created.
+ *
+ * @method _uiSetCheckbox
+ * @param type {String} 'category' or 'source'
+ * @param item {String} the name of the filter (e.g. 'info', 'event')
+ * @param checked {Boolean} value to set the checkbox's checked property
+ * @protected
+ */
+ _uiSetCheckbox : function (type, item, checked) {
+ if (type && item) {
+ var container = type === CATEGORY ?
+ this._categories :
+ this._sources,
+ sel = SEL_CHECK + getCN(CONSOLE,FILTER,item),
+ checkbox = container.query(sel),
+ host;
+
+ if (!checkbox) {
+ host = this.get(HOST);
+
+ this._createCheckbox(container, item);
+
+ checkbox = container.query(sel);
+
+ host._uiSetHeight(host.get('height'));
+ }
+
+ checkbox.set(CHECKED, checked);
+ }
+ },
+
+ /**
+ * Passes checkbox clicks on to the category attribute.
+ *
+ * @method _onCategoryCheckboxClick
+ * @param e {Event} the DOM event
+ * @protected
+ */
+ _onCategoryCheckboxClick : function (e) {
+ var t = e.target, cat;
+
+ if (t.hasClass(ConsoleFilters.CHROME_CLASSES.filter)) {
+ cat = t.get('value');
+ if (cat && cat in this.get(CATEGORY)) {
+ this.set(CATEGORY_DOT + cat, t.get(CHECKED), { fromUI: true });
+ }
+ }
+ },
+
+ /**
+ * Passes checkbox clicks on to the source attribute.
+ *
+ * @method _onSourceCheckboxClick
+ * @param e {Event} the DOM event
+ * @protected
+ */
+ _onSourceCheckboxClick : function (e) {
+ var t = e.target, src;
+
+ if (t.hasClass(ConsoleFilters.CHROME_CLASSES.filter)) {
+ src = t.get('value');
+ if (src && src in this.get(SOURCE)) {
+ this.set(SOURCE_DOT + src, t.get(CHECKED), { fromUI: true });
+ }
+ }
+ },
+
+ /**
+ * Hides any number of categories from the UI. Convenience method for
+ * myConsole.filter.set('category.foo', false); set('category.bar', false);
+ * and so on.
+ *
+ * @method hideCategory
+ * @param cat* {String} 1..n categories to filter out of the UI
+ */
+ hideCategory : function (cat, multiple) {
+ if (isString(multiple)) {
+ Y.Array.each(arguments, arguments.callee, this);
+ } else {
+ this.set(CATEGORY_DOT + cat, false);
+ }
+ },
+
+ /**
+ * Shows any number of categories in the UI. Convenience method for
+ * myConsole.filter.set('category.foo', true); set('category.bar', true);
+ * and so on.
+ *
+ * @method showCategory
+ * @param cat* {String} 1..n categories to allow to display in the UI
+ */
+ showCategory : function (cat, multiple) {
+ if (isString(multiple)) {
+ Y.Array.each(arguments, arguments.callee, this);
+ } else {
+ this.set(CATEGORY_DOT + cat, true);
+ }
+ },
+
+ /**
+ * Hides any number of sources from the UI. Convenience method for
+ * myConsole.filter.set('source.foo', false); set('source.bar', false);
+ * and so on.
+ *
+ * @method hideSource
+ * @param src* {String} 1..n sources to filter out of the UI
+ */
+ hideSource : function (src, multiple) {
+ if (isString(multiple)) {
+ Y.Array.each(arguments, arguments.callee, this);
+ } else {
+ this.set(SOURCE_DOT + src, false);
+ }
+ },
+
+ /**
+ * Shows any number of sources in the UI. Convenience method for
+ * myConsole.filter.set('source.foo', true); set('source.bar', true);
+ * and so on.
+ *
+ * @method showSource
+ * @param src* {String} 1..n sources to allow to display in the UI
+ */
+ showSource : function (src, multiple) {
+ if (isString(multiple)) {
+ Y.Array.each(arguments, arguments.callee, this);
+ } else {
+ this.set(SOURCE_DOT + src, true);
+ }
+ },
+
+ /**
+ * Creates a checkbox and label from the ConsoleFilters.FILTER_TEMPLATE for
+ * the provided type and name. The checkbox and label are appended to the
+ * container node passes as the first arg.
+ *
+ * @method _createCheckbox
+ * @param container {Node} the parentNode of the new checkbox and label
+ * @param name {String} the identifier of the filter
+ * @protected
+ */
+ _createCheckbox : function (container, name) {
+ var info = Y.merge(ConsoleFilters.CHROME_CLASSES, {
+ filter_name : name,
+ filter_class : getCN(CONSOLE, FILTER, name)
+ }),
+ node = Y.Node.create(
+ Y.substitute(ConsoleFilters.FILTER_TEMPLATE, info));
+
+ container.appendChild(node);
+ },
+
+ /**
+ * Validates category updates are objects and the subattribute is not too
+ * deep.
+ *
+ * @method _validateCategory
+ * @param cat {String} the new category:visibility map
+ * @param v {String} the subattribute path updated
+ * @return Boolean
+ * @protected
+ */
+ _validateCategory : function (cat, v) {
+ return Y.Lang.isObject(v,true) && cat.split(/\./).length < 3;
+ },
+
+ /**
+ * Validates source updates are objects and the subattribute is not too
+ * deep.
+ *
+ * @method _validateSource
+ * @param cat {String} the new source:visibility map
+ * @param v {String} the subattribute path updated
+ * @return Boolean
+ * @protected
+ */
+ _validateSource : function (src, v) {
+ return Y.Lang.isObject(v,true) && src.split(/\./).length < 3;
+ }
+
+});
+
+Y.namespace('Plugin').ConsoleFilters = ConsoleFilters;
+
+
+}, '3.0.0' ,{requires:['console','plugin']});
diff --git a/lib/yui/3.0.0/console/console-min.js b/lib/yui/3.0.0/console/console-min.js
new file mode 100644
index 0000000000..2a2b7954c9
--- /dev/null
+++ b/lib/yui/3.0.0/console/console-min.js
@@ -0,0 +1,9 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("console",function(D){function V(){V.superclass.constructor.apply(this,arguments);}var G=D.ClassNameManager.getClassName,B="checked",s="clear",r="click",T="collapsed",AE="console",d="contentBox",h="disabled",o="entry",l="error",j="height",P="info",y="innerHTML",M="lastTime",F="pause",f="paused",x="reset",v="startTime",p="title",i="warn",Z=".",X=G(AE,"button"),b=G(AE,"checkbox"),AD=G(AE,s),w=G(AE,"collapse"),S=G(AE,T),E=G(AE,"controls"),e=G(AE,"hd"),c=G(AE,"bd"),C=G(AE,"ft"),k=G(AE,p),z=G(AE,o),t=G(AE,o,"cat"),a=G(AE,o,"content"),U=G(AE,o,"meta"),g=G(AE,o,"src"),A=G(AE,o,"time"),Q=G(AE,F),W=G(AE,F,"label"),n=/^(\S+)\s/,AA=/&/g,u=/>/g,J=/'+'
',
+
+ /**
+ * Markup template used to generate the DOM structure for the Console body
+ * (where the messages are inserted) when it is rendered. The template
+ * includes only the {placeholder} "console_bd_class", which is
+ * constributed by Console.CHROME_CLASSES.
+ *
+ * @property Console.BODY_TEMPLATE
+ * @type String
+ * @static
+ */
+ BODY_TEMPLATE : '',
+
+ /**
+ * Markup template used to generate the DOM structure for the footer
+ * section of the Console when it is rendered. The template includes
+ * many of the {placeholder}s from Console.CHROME_CLASSES as well as:
+ *
+ *
+ *
id_guid - generated unique id, relates the label and checkbox
',
+
+ /**
+ * Default markup template used to create the DOM structure for Console
+ * entries. The markup contains {placeholder}s for content and classes
+ * that are replaced via Y.substitute. The default template contains
+ * the {placeholder}s identified in Console.ENTRY_CLASSES as well as the
+ * following placeholders that will be populated by the log entry data:
+ *
+ *
+ *
cat_class
+ *
src_class
+ *
totalTime
+ *
elapsedTime
+ *
localTime
+ *
sourceAndDetail
+ *
message
+ *
+ *
+ * @property Console.ENTRY_TEMPLATE
+ * @type String
+ * @static
+ */
+ ENTRY_TEMPLATE : ENTRY_TEMPLATE_STR,
+
+ /**
+ * Static property used to define the default attribute configuration of
+ * the Widget.
+ *
+ * @property Console.ATTRS
+ * @Type Object
+ * @static
+ */
+ ATTRS : {
+
+ /**
+ * Name of the custom event that will communicate log messages.
+ *
+ * @attribute logEvent
+ * @type String
+ * @default "yui:log"
+ */
+ logEvent : {
+ value : 'yui:log',
+ writeOnce : true,
+ validator : isString
+ },
+
+ /**
+ * Object that will emit the log events. By default the YUI instance.
+ * To have a single Console capture events from all YUI instances, set
+ * this to the Y.Global object.
+ *
+ * @attribute logSource
+ * @type EventTarget
+ * @default Y
+ */
+ logSource : {
+ value : Y,
+ writeOnce : true,
+ validator : function (v) {
+ return v && Y.Lang.isFunction(v.on);
+ }
+ },
+
+ /**
+ * Collection of strings used to label elements in the Console UI.
+ * Default collection contains the following name:value pairs:
+ *
+ *
+ *
title : "Log Console"
+ *
pause : "Pause"
+ *
clear : "Clear"
+ *
collapse : "Collapse"
+ *
expand : "Expand"
+ *
+ *
+ * @attribute strings
+ * @type Object
+ */
+ strings : {
+ value : {
+ title : "Log Console",
+ pause : "Pause",
+ clear : "Clear",
+ collapse : "Collapse",
+ expand : "Expand"
+ }
+ },
+
+ /**
+ * Boolean to pause the outputting of new messages to the console.
+ * When paused, messages will accumulate in the buffer.
+ *
+ * @attribute paused
+ * @type boolean
+ * @default false
+ */
+ paused : {
+ value : false,
+ validator : L.isBoolean
+ },
+
+ /**
+ * If a category is not specified in the Y.log(..) statement, this
+ * category will be used. Categories "info",
+ * "warn", and "error" are also called log level.
+ *
+ * @attribute defaultCategory
+ * @type String
+ * @default "info"
+ */
+ defaultCategory : {
+ value : INFO,
+ validator : isString
+ },
+
+ /**
+ * If a source is not specified in the Y.log(..) statement, this
+ * source will be used.
+ *
+ * @attribute defaultSource
+ * @type String
+ * @default "global"
+ */
+ defaultSource : {
+ value : 'global',
+ validator : isString
+ },
+
+ /**
+ * Markup template used to create the DOM structure for Console entries.
+ *
+ * @attribute entryTemplate
+ * @type String
+ * @default Console.ENTRY_TEMPLATE
+ */
+ entryTemplate : {
+ value : ENTRY_TEMPLATE_STR,
+ validator : isString
+ },
+
+ /**
+ * Minimum entry log level to render into the Console. The initial
+ * logLevel value for all Console instances defaults from the
+ * Y.config.logLevel YUI configuration, or Console.LOG_LEVEL_INFO if
+ * that configuration is not set.
+ *
+ * Possible values are "info", "warn",
+ * "error" (case insensitive), or their corresponding statics
+ * Console.LOG_LEVEL_INFO and so on.
+ *
+ * @attribute logLevel
+ * @type String
+ * @default Y.config.logLevel or Console.LOG_LEVEL_INFO
+ */
+ logLevel : {
+ value : Y.config.logLevel || INFO,
+ setter : function (v) {
+ return this._setLogLevel(v);
+ }
+ },
+
+ /**
+ * Millisecond timeout between iterations of the print loop, moving
+ * entries from the buffer to the UI.
+ *
+ * @attribute printTimeout
+ * @type Number
+ * @default 100
+ */
+ printTimeout : {
+ value : 100,
+ validator : isNumber
+ },
+
+ /**
+ * Maximum number of entries printed in each iteration of the print
+ * loop. This is used to prevent excessive logging locking the page UI.
+ *
+ * @attribute printLimit
+ * @type Number
+ * @default 50
+ */
+ printLimit : {
+ value : 50,
+ validator : isNumber
+ },
+
+ /**
+ * Maximum number of Console entries allowed in the Console body at one
+ * time. This is used to keep acquired messages from exploding the
+ * DOM tree and impacting page performance.
+ *
+ * @attribute consoleLimit
+ * @type Number
+ * @default 300
+ */
+ consoleLimit : {
+ value : 300,
+ validator : isNumber
+ },
+
+ /**
+ * New entries should display at the top of the Console or the bottom?
+ *
+ * @attribute newestOnTop
+ * @type Boolean
+ * @default true
+ */
+ newestOnTop : {
+ value : true
+ },
+
+ /**
+ * When new entries are added to the Console UI, should they be
+ * scrolled into view?
+ *
+ * @attribute scrollIntoView
+ * @type Boolean
+ * @default true
+ */
+ scrollIntoView : {
+ value : true
+ },
+
+ /**
+ * The baseline time for this Console instance, used to measure elapsed
+ * time from the moment the console module is used to the
+ * moment each new entry is logged (not rendered).
+ *
+ * This value is reset by the instance method myConsole.reset().
+ *
+ * @attribute startTime
+ * @type Date
+ * @default The moment the console module is used
+ */
+ startTime : {
+ value : new Date()
+ },
+
+ /**
+ * The precise time the last entry was logged. Used to measure elapsed
+ * time between log messages.
+ *
+ * @attribute lastTime
+ * @type Date
+ * @default The moment the console module is used
+ */
+ lastTime : {
+ value : new Date(),
+ readOnly: true
+ },
+
+ /**
+ * Controls the collapsed state of the Console
+ *
+ * @attribute collapsed
+ * @type Boolean
+ * @default false
+ */
+ collapsed : {
+ value : false
+ },
+
+ /**
+ * String with units, or number, representing the height of the Console,
+ * inclusive of header and footer. If a number is provided, the default
+ * unit, defined by Widget's DEF_UNIT, property is used.
+ *
+ * @attribute height
+ * @default "300px"
+ * @type {String | Number}
+ */
+ height: {
+ value: "300px"
+ },
+
+ /**
+ * String with units, or number, representing the width of the Console.
+ * If a number is provided, the default unit, defined by Widget's
+ * DEF_UNIT, property is used.
+ *
+ * @attribute width
+ * @default "300px"
+ * @type {String | Number}
+ */
+ width: {
+ value: "300px"
+ },
+
+ /**
+ * Pass through to the YUI instance useBrowserConsole configuration.
+ * By default this is set to false, which will disable logging to the
+ * browser console when a Console instance is created. If the
+ * logSource is not a YUI instance, this has no effect.
+ *
+ * @attribute useBrowserConsole
+ * @type {Boolean}
+ * @default false
+ */
+ useBrowserConsole : {
+ lazyAdd: false,
+ value: false,
+ getter : function () {
+ var logSource = this.get('logSource');
+ return logSource instanceof YUI ?
+ logSource.config.useBrowserConsole : null;
+ },
+ setter : function (v) {
+ var logSource = this.get('logSource');
+ if (logSource instanceof YUI) {
+ v = !!v;
+ logSource.config.useBrowserConsole = !!v;
+ return v;
+ } else {
+ return Y.Attribute.INVALID_VALUE;
+ }
+ }
+ },
+
+ /**
+ * Allows the Console to flow in the document. Available values are
+ * 'inline', 'block', and 'separate' (the default).
+ *
+ * @attribute style
+ * @type {String}
+ * @default 'separate'
+ */
+ style : {
+ value : 'separate',
+ writeOnce : true,
+ validator : function (v) {
+ return this._validateStyle(v);
+ }
+ }
+ }
+
+});
+
+Y.extend(Console,Y.Widget,{
+
+ /**
+ * Category to prefix all event subscriptions to allow for ease of detach
+ * during destroy.
+ *
+ * @property _evtCat
+ * @type string
+ * @protected
+ */
+ _evtCat : null,
+
+ /**
+ * Reference to the Node instance containing the header contents.
+ *
+ * @property _head
+ * @type Node
+ * @default null
+ * @protected
+ */
+ _head : null,
+
+ /**
+ * Reference to the Node instance that will house the console messages.
+ *
+ * @property _body
+ * @type Node
+ * @default null
+ * @protected
+ */
+ _body : null,
+
+ /**
+ * Reference to the Node instance containing the footer contents.
+ *
+ * @property _foot
+ * @type Node
+ * @default null
+ * @protected
+ */
+ _foot : null,
+
+ /**
+ * Holds the object API returned from Y.later for the print
+ * loop interval.
+ *
+ * @property _printLoop
+ * @type Object
+ * @default null
+ * @protected
+ */
+ _printLoop : null,
+
+ /**
+ * Array of normalized message objects awaiting printing.
+ *
+ * @property buffer
+ * @type Array
+ * @default null
+ * @protected
+ */
+ buffer : null,
+
+ /**
+ * Wrapper for Y.log.
+ *
+ * @method log
+ * @param arg* {MIXED} (all arguments passed through to Y.log)
+ * @chainable
+ */
+ log : function () {
+ Y.log.apply(Y,arguments);
+
+ return this;
+ },
+
+ /**
+ * Clear the console of messages and flush the buffer of pending messages.
+ *
+ * @method clearConsole
+ * @chainable
+ */
+ clearConsole : function () {
+ // TODO: clear event listeners from console contents
+ this._body.set(INNER_HTML,'');
+
+ this._cancelPrintLoop();
+
+ this.buffer = [];
+
+ return this;
+ },
+
+ /**
+ * Clears the console and resets internal timers.
+ *
+ * @method reset
+ * @chainable
+ */
+ reset : function () {
+ this.fire(RESET);
+
+ return this;
+ },
+
+ /**
+ * Collapses the body and footer.
+ *
+ * @method collapse
+ * @chainable
+ */
+ collapse : function () {
+ this.set(COLLAPSED, true);
+
+ return this;
+ },
+
+ /**
+ * Expands the body and footer if collapsed.
+ *
+ * @method expand
+ * @chainable
+ */
+ expand : function () {
+ this.set(COLLAPSED, false);
+
+ return this;
+ },
+
+ /**
+ * Outputs buffered messages to the console UI. This is typically called
+ * from a scheduled interval until the buffer is empty (referred to as the
+ * print loop). The number of buffered messages output to the Console is
+ * limited to the number provided as an argument. If no limit is passed,
+ * all buffered messages are rendered.
+ *
+ * @method printBuffer
+ * @param limit {Number} (optional) max number of buffered entries to write
+ * @chainable
+ */
+ printBuffer: function (limit) {
+ var messages = this.buffer,
+ debug = Y.config.debug,
+ entries = [],
+ consoleLimit= this.get('consoleLimit'),
+ newestOnTop = this.get('newestOnTop'),
+ anchor = newestOnTop ? this._body.get('firstChild') : null,
+ i;
+
+ if (messages.length > consoleLimit) {
+ messages.splice(0, messages.length - consoleLimit);
+ }
+
+ limit = Math.min(messages.length, (limit || messages.length));
+
+ // turn off logging system
+ Y.config.debug = false;
+
+ if (!this.get(PAUSED) && this.get('rendered')) {
+
+ for (i = 0; i < limit && messages.length; ++i) {
+ entries[i] = this._createEntryHTML(messages.shift());
+ }
+
+ if (!messages.length) {
+ this._cancelPrintLoop();
+ }
+
+ if (entries.length) {
+ if (newestOnTop) {
+ entries.reverse();
+ }
+
+ this._body.insertBefore(create(entries.join('')), anchor);
+
+ if (this.get('scrollIntoView')) {
+ this.scrollToLatest();
+ }
+
+ this._trimOldEntries();
+ }
+ }
+
+ // restore logging system
+ Y.config.debug = debug;
+
+ return this;
+ },
+
+
+ /**
+ * Constructor code. Set up the buffer and entry template, publish
+ * internal events, and subscribe to the configured logEvent.
+ *
+ * @method initializer
+ * @protected
+ */
+ initializer : function () {
+ this._evtCat = Y.stamp(this) + '|';
+
+ this.buffer = [];
+
+ this.get('logSource').on(this._evtCat +
+ this.get('logEvent'),Y.bind("_onLogEvent",this));
+
+ /**
+ * Transfers a received message to the print loop buffer. Default
+ * behavior defined in _defEntryFn.
+ *
+ * @event entry
+ * @param event {Event.Facade} An Event Facade object with the following attribute specific properties added:
+ *
+ *
message
+ *
The message data normalized into an object literal (see _normalizeMessage)
+ *
+ * @preventable _defEntryFn
+ */
+ this.publish(ENTRY, { defaultFn: this._defEntryFn });
+
+ /**
+ * Triggers the reset behavior via the default logic in _defResetFn.
+ *
+ * @event reset
+ * @param event {Event.Facade} Event Facade object
+ * @preventable _defResetFn
+ */
+ this.publish(RESET, { defaultFn: this._defResetFn });
+
+ this.after('rendered', this._schedulePrint);
+ },
+
+ /**
+ * Tears down the instance, flushing event subscriptions and purging the UI.
+ *
+ * @method destructor
+ * @protected
+ */
+ destructor : function () {
+ var bb = this.get('boundingBox');
+
+ this._cancelPrintLoop();
+
+ this.get('logSource').detach(this._evtCat + '*');
+
+ Y.Event.purgeElement(bb, true);
+
+ bb.set('innerHTML','');
+ },
+
+ /**
+ * Generate the Console UI.
+ *
+ * @method renderUI
+ * @protected
+ */
+ renderUI : function () {
+ this._initHead();
+ this._initBody();
+ this._initFoot();
+
+ // Apply positioning to the bounding box if appropriate
+ var style = this.get('style');
+ if (style !== 'block') {
+ this.get('boundingBox').addClass('yui-'+style+'-console');
+ }
+ },
+
+ /**
+ * Sync the UI state to the current attribute state.
+ *
+ * @method syncUI
+ */
+ syncUI : function () {
+ this._uiUpdatePaused(this.get(PAUSED));
+ this._uiUpdateCollapsed(this.get(COLLAPSED));
+ this._uiSetHeight(this.get(HEIGHT));
+ },
+
+ /**
+ * Set up event listeners to wire up the UI to the internal state.
+ *
+ * @method bindUI
+ * @protected
+ */
+ bindUI : function () {
+ this.get(CONTENT_BOX).query('button.'+C_COLLAPSE).
+ on(CLICK,this._onCollapseClick,this);
+
+ this.get(CONTENT_BOX).query('input[type=checkbox].'+C_PAUSE).
+ on(CLICK,this._onPauseClick,this);
+
+ this.get(CONTENT_BOX).query('button.'+C_CLEAR).
+ on(CLICK,this._onClearClick,this);
+
+ // Attribute changes
+ this.after(this._evtCat + 'stringsChange',
+ this._afterStringsChange);
+ this.after(this._evtCat + 'pausedChange',
+ this._afterPausedChange);
+ this.after(this._evtCat + 'consoleLimitChange',
+ this._afterConsoleLimitChange);
+ this.after(this._evtCat + 'collapsedChange',
+ this._afterCollapsedChange);
+ },
+
+
+ /**
+ * Create the DOM structure for the header elements.
+ *
+ * @method _initHead
+ * @protected
+ */
+ _initHead : function () {
+ var cb = this.get(CONTENT_BOX),
+ info = merge(Console.CHROME_CLASSES, {
+ str_collapse : this.get('strings.collapse'),
+ str_title : this.get('strings.title')
+ });
+
+ this._head = create(substitute(Console.HEADER_TEMPLATE,info));
+
+ cb.insertBefore(this._head,cb.get('firstChild'));
+ },
+
+ /**
+ * Create the DOM structure for the console body—where messages are
+ * rendered.
+ *
+ * @method _initBody
+ * @protected
+ */
+ _initBody : function () {
+ this._body = create(substitute(
+ Console.BODY_TEMPLATE,
+ Console.CHROME_CLASSES));
+
+ this.get(CONTENT_BOX).appendChild(this._body);
+ },
+
+ /**
+ * Create the DOM structure for the footer elements.
+ *
+ * @method _initFoot
+ * @protected
+ */
+ _initFoot : function () {
+ var info = merge(Console.CHROME_CLASSES, {
+ id_guid : Y.guid(),
+ str_pause : this.get('strings.pause'),
+ str_clear : this.get('strings.clear')
+ });
+
+ this._foot = create(substitute(Console.FOOTER_TEMPLATE,info));
+
+ this.get(CONTENT_BOX).appendChild(this._foot);
+ },
+
+ /**
+ * Determine if incoming log messages are within the configured logLevel
+ * to be buffered for printing.
+ *
+ * @method _isInLogLevel
+ * @protected
+ */
+ _isInLogLevel : function (e) {
+ var cat = e.cat, lvl = this.get('logLevel');
+
+ if (lvl !== INFO) {
+ cat = cat || INFO;
+
+ if (isString(cat)) {
+ cat = cat.toLowerCase();
+ }
+
+ if ((cat === WARN && lvl === ERROR) ||
+ (cat === INFO && lvl !== INFO)) {
+ return false;
+ }
+ }
+
+ return true;
+ },
+
+ /**
+ * Create a log entry message from the inputs including the following keys:
+ *
+ *
time - this moment
+ *
message - leg message
+ *
category - logLevel or custom category for the message
+ *
source - when provided, the widget or util calling Y.log
+ *
sourceAndDetail - same as source but can include instance info
+ *
localTime - readable version of time
+ *
elapsedTime - ms since last entry
+ *
totalTime - ms since Console was instantiated or reset
+ *
+ *
+ * @method _normalizeMessage
+ * @param e {Event} custom event containing the log message
+ * @return Object the message object
+ * @protected
+ */
+ _normalizeMessage : function (e) {
+
+ var msg = e.msg,
+ cat = e.cat,
+ src = e.src,
+
+ m = {
+ time : new Date(),
+ message : msg,
+ category : cat || this.get('defaultCategory'),
+ sourceAndDetail : src || this.get('defaultSource'),
+ source : null,
+ localTime : null,
+ elapsedTime : null,
+ totalTime : null
+ };
+
+ // Extract m.source "Foo" from m.sourceAndDetail "Foo bar baz"
+ m.source = RE_INLINE_SOURCE.test(m.sourceAndDetail) ?
+ RegExp.$1 : m.sourceAndDetail;
+ m.localTime = m.time.toLocaleTimeString ?
+ m.time.toLocaleTimeString() : (m.time + '');
+ m.elapsedTime = m.time - this.get(LAST_TIME);
+ m.totalTime = m.time - this.get(START_TIME);
+
+ this._set(LAST_TIME,m.time);
+
+ return m;
+ },
+
+ /**
+ * Sets an interval for buffered messages to be output to the console.
+ *
+ * @method _schedulePrint
+ * @protected
+ */
+ _schedulePrint : function () {
+ if (!this._printLoop && !this.get(PAUSED) && this.get('rendered')) {
+ this._printLoop = Y.later(
+ this.get('printTimeout'),
+ this, this.printBuffer,
+ this.get('printLimit'), true);
+ }
+ },
+
+ /**
+ * Translates message meta into the markup for a console entry.
+ *
+ * @method _createEntryHTML
+ * @param m {Object} object literal containing normalized message metadata
+ * @return String
+ * @protected
+ */
+ _createEntryHTML : function (m) {
+ m = merge(
+ this._htmlEscapeMessage(m),
+ Console.ENTRY_CLASSES,
+ {
+ cat_class : this.getClassName(ENTRY,m.category),
+ src_class : this.getClassName(ENTRY,m.source)
+ });
+
+ return this.get('entryTemplate').replace(/\{(\w+)\}/g,
+ function (_,token) {
+ return token in m ? m[token] : '';
+ });
+ },
+
+ /**
+ * Scrolls to the most recent entry
+ *
+ * @method scrollToLatest
+ * @chainable
+ */
+ scrollToLatest : function () {
+ var scrollTop = this.get('newestOnTop') ?
+ 0 :
+ this._body.get('scrollHeight');
+
+ this._body.set('scrollTop', scrollTop);
+ },
+
+ /**
+ * Performs HTML escaping on strings in the message object.
+ *
+ * @method _htmlEscapeMessage
+ * @param m {Object} the normalized message object
+ * @return Object the message object with proper escapement
+ * @protected
+ */
+ _htmlEscapeMessage : function (m) {
+ m.message = this._encodeHTML(m.message);
+ m.source = this._encodeHTML(m.source);
+ m.sourceAndDetail = this._encodeHTML(m.sourceAndDetail);
+ m.category = this._encodeHTML(m.category);
+
+ return m;
+ },
+
+ /**
+ * Removes the oldest message entries from the UI to maintain the limit
+ * specified in the consoleLimit configuration.
+ *
+ * @method _trimOldEntries
+ * @protected
+ */
+ _trimOldEntries : function () {
+ // Turn off the logging system for the duration of this operation
+ // to prevent an infinite loop
+ Y.config.debug = false;
+
+ var bd = this._body,
+ limit = this.get('consoleLimit'),
+ debug = Y.config.debug,
+ entries,e,i,l;
+
+ if (bd) {
+ entries = bd.queryAll(DOT+C_ENTRY);
+ l = entries.size() - limit;
+
+ if (l > 0) {
+ if (this.get('newestOnTop')) {
+ i = limit;
+ l = entries.size();
+ } else {
+ i = 0;
+ }
+
+ this._body.setStyle('display','none');
+
+ for (;i < l; ++i) {
+ e = entries.item(i);
+ if (e) {
+ e.remove();
+ }
+ }
+
+ this._body.setStyle('display','');
+ }
+
+ }
+
+ Y.config.debug = debug;
+ },
+
+ /**
+ * Returns the input string with ampersands (&), <, and > encoded
+ * as HTML entities.
+ *
+ * @method _encodeHTML
+ * @param s {String} the raw string
+ * @return String the encoded string
+ * @protected
+ */
+ _encodeHTML : function (s) {
+ return isString(s) ?
+ s.replace(RE_AMP,ESC_AMP).
+ replace(RE_LT, ESC_LT).
+ replace(RE_GT, ESC_GT) :
+ s;
+ },
+
+ /**
+ * Clears the timeout for printing buffered messages.
+ *
+ * @method _cancelPrintLoop
+ * @protected
+ */
+ _cancelPrintLoop : function () {
+ if (this._printLoop) {
+ this._printLoop.cancel();
+ this._printLoop = null;
+ }
+ },
+
+ /**
+ * Validates input value for style attribute. Accepts only values 'inline',
+ * 'block', and 'separate'.
+ *
+ * @method _validateStyle
+ * @param style {String} the proposed value
+ * @return {Boolean} pass/fail
+ * @protected
+ */
+ _validateStyle : function (style) {
+ return style === 'inline' || style === 'block' || style === 'separate';
+ },
+
+ /**
+ * Event handler for clicking on the Pause checkbox to update the paused
+ * attribute.
+ *
+ * @method _onPauseClick
+ * @param e {Event} DOM event facade for the click event
+ * @protected
+ */
+ _onPauseClick : function (e) {
+ this.set(PAUSED,e.target.get(CHECKED));
+ },
+
+ /**
+ * Event handler for clicking on the Clear button. Pass-through to
+ * this.clearConsole().
+ *
+ * @method _onClearClick
+ * @param e {Event} DOM event facade for the click event
+ * @protected
+ */
+ _onClearClick : function (e) {
+ this.clearConsole();
+ },
+
+ /**
+ * Event handler for clicking on the Collapse/Expand button. Sets the
+ * "collapsed" attribute accordingly.
+ *
+ * @method _onCollapseClick
+ * @param e {Event} DOM event facade for the click event
+ * @protected
+ */
+ _onCollapseClick : function (e) {
+ this.set(COLLAPSED, !this.get(COLLAPSED));
+ },
+
+
+ /**
+ * Setter method for logLevel attribute. Acceptable values are
+ * "error", "warn", and "info" (case
+ * insensitive). Other values are treated as "info".
+ *
+ * @method _setLogLevel
+ * @param v {String} the desired log level
+ * @return String One of Console.LOG_LEVEL_INFO, _WARN, or _ERROR
+ * @protected
+ */
+ _setLogLevel : function (v) {
+ if (isString(v)) {
+ v = v.toLowerCase();
+ }
+
+ return (v === WARN || v === ERROR) ? v : INFO;
+ },
+
+ /**
+ * Set the height of the Console container. Set the body height to the difference between the configured height and the calculated heights of the header and footer.
+ * Overrides Widget.prototype._uiSetHeight.
+ *
+ * @method _uiSetHeight
+ * @param v {String|Number} the new height
+ * @protected
+ */
+ _uiSetHeight : function (v) {
+ Console.superclass._uiSetHeight.apply(this,arguments);
+
+ if (this._head && this._foot) {
+ var h = this.get('boundingBox').get('offsetHeight') -
+ this._head.get('offsetHeight') -
+ this._foot.get('offsetHeight');
+
+ this._body.setStyle(HEIGHT,h+'px');
+ }
+ },
+
+ /**
+ * Updates the UI if changes are made to any of the strings in the strings
+ * attribute.
+ *
+ * @method _afterStringsChange
+ * @param e {Event} Custom event for the attribute change
+ * @protected
+ */
+ _afterStringsChange : function (e) {
+ var prop = e.subAttrName ? e.subAttrName.split(DOT)[1] : null,
+ cb = this.get(CONTENT_BOX),
+ before = e.prevVal,
+ after = e.newVal;
+
+ if ((!prop || prop === TITLE) && before.title !== after.title) {
+ cb.queryAll(DOT+C_CONSOLE_TITLE).set(INNER_HTML, after.title);
+ }
+
+ if ((!prop || prop === PAUSE) && before.pause !== after.pause) {
+ cb.queryAll(DOT+C_PAUSE_LABEL).set(INNER_HTML, after.pause);
+ }
+
+ if ((!prop || prop === CLEAR) && before.clear !== after.clear) {
+ cb.queryAll(DOT+C_CLEAR).set('value',after.clear);
+ }
+ },
+
+ /**
+ * Updates the UI and schedules or cancels the print loop.
+ *
+ * @method _afterPausedChange
+ * @param e {Event} Custom event for the attribute change
+ * @protected
+ */
+ _afterPausedChange : function (e) {
+ var paused = e.newVal;
+
+ if (e.src !== Y.Widget.SRC_UI) {
+ this._uiUpdatePaused(paused);
+ }
+
+ if (!paused) {
+ this._schedulePrint();
+ } else if (this._printLoop) {
+ this._cancelPrintLoop();
+ }
+ },
+
+ /**
+ * Checks or unchecks the paused checkbox
+ *
+ * @method _uiUpdatePaused
+ * @param on {Boolean} the new checked state
+ * @protected
+ */
+ _uiUpdatePaused : function (on) {
+ var node = this._foot.queryAll('input[type=checkbox].'+C_PAUSE);
+
+ if (node) {
+ node.set(CHECKED,on);
+ }
+ },
+
+ /**
+ * Calls this._trimOldEntries() in response to changes in the configured
+ * consoleLimit attribute.
+ *
+ * @method _afterConsoleLimitChange
+ * @param e {Event} Custom event for the attribute change
+ * @protected
+ */
+ _afterConsoleLimitChange : function () {
+ this._trimOldEntries();
+ },
+
+
+ /**
+ * Updates the className of the contentBox, which should trigger CSS to
+ * hide or show the body and footer sections depending on the new value.
+ *
+ * @method _afterCollapsedChange
+ * @param e {Event} Custom event for the attribute change
+ * @protected
+ */
+ _afterCollapsedChange : function (e) {
+ this._uiUpdateCollapsed(e.newVal);
+ },
+
+ /**
+ * Updates the UI to reflect the new Collapsed state
+ *
+ * @method _uiUpdateCollapsed
+ * @param v {Boolean} true for collapsed, false for expanded
+ * @protected
+ */
+ _uiUpdateCollapsed : function (v) {
+ var bb = this.get('boundingBox'),
+ button = bb.queryAll('button.'+C_COLLAPSE),
+ method = v ? 'addClass' : 'removeClass',
+ str = this.get('strings.'+(v ? 'expand' : 'collapse'));
+
+ bb[method](C_COLLAPSED);
+
+ if (button) {
+ button.set('innerHTML',str);
+ }
+
+ this._uiSetHeight(v ? this._head.get('offsetHeight'): this.get(HEIGHT));
+ },
+
+ /**
+ * Makes adjustments to the UI if needed when the Console is hidden or shown
+ *
+ * @method _afterVisibleChange
+ * @param e {Event} the visibleChange event
+ * @protected
+ */
+ _afterVisibleChange : function (e) {
+ Console.superclass._afterVisibleChange.apply(this,arguments);
+
+ this._uiUpdateFromHideShow(e.newVal);
+ },
+
+ /**
+ * Recalculates dimensions and updates appropriately when shown
+ *
+ * @method _uiUpdateFromHideShow
+ * @param v {Boolean} true for visible, false for hidden
+ * @protected
+ */
+ _uiUpdateFromHideShow : function (v) {
+ if (v) {
+ this._uiSetHeight(this.get(HEIGHT));
+ }
+ },
+
+ /**
+ * Responds to log events by normalizing qualifying messages and passing
+ * them along through the entry event for buffering etc.
+ *
+ * @method _onLogEvent
+ * @param msg {String} the log message
+ * @param cat {String} OPTIONAL the category or logLevel of the message
+ * @param src {String} OPTIONAL the source of the message (e.g. widget name)
+ * @protected
+ */
+ _onLogEvent : function (e) {
+
+ if (!this.get(DISABLED) && this._isInLogLevel(e)) {
+
+ var debug = Y.config.debug;
+
+ /* TODO: needed? */
+ Y.config.debug = false;
+
+ this.fire(ENTRY, {
+ message : this._normalizeMessage(e)
+ });
+
+ Y.config.debug = debug;
+ }
+ },
+
+ /**
+ * Clears the console, resets the startTime attribute, enables and
+ * unpauses the widget.
+ *
+ * @method _defResetFn
+ * @protected
+ */
+ _defResetFn : function () {
+ this.clearConsole();
+ this.set(START_TIME,new Date());
+ this.set(DISABLED,false);
+ this.set(PAUSED,false);
+ },
+
+ /**
+ * Buffers incoming message objects and schedules the printing.
+ *
+ * @method _defEntryFn
+ * @param e {Event} The Custom event carrying the message in its payload
+ * @protected
+ */
+ _defEntryFn : function (e) {
+ if (e.message) {
+ this.buffer.push(e.message);
+ this._schedulePrint();
+ }
+ }
+
+});
+
+Y.Console = Console;
+
+
+}, '3.0.0' ,{requires:['substitute','widget']});
diff --git a/lib/yui/3.0.0/cookie/cookie-debug.js b/lib/yui/3.0.0/cookie/cookie-debug.js
new file mode 100644
index 0000000000..4190ef4f4b
--- /dev/null
+++ b/lib/yui/3.0.0/cookie/cookie-debug.js
@@ -0,0 +1,491 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('cookie', function(Y) {
+
+/**
+ * Utilities for cookie management
+ * @module cookie
+ */
+
+ //shortcuts
+ var L = Y.Lang,
+ O = Y.Object,
+ NULL = null,
+
+ //shortcuts to functions
+ isString = L.isString,
+ isObject = L.isObject,
+ isUndefined = L.isUndefined,
+ isFunction = L.isFunction,
+ encode = encodeURIComponent,
+ decode = decodeURIComponent,
+
+ //shortcut to document
+ doc = Y.config.doc;
+
+ /*
+ * Throws an error message.
+ */
+ function error(message){
+ throw new TypeError(message);
+ }
+
+ /*
+ * Checks the validity of a cookie name.
+ */
+ function validateCookieName(name){
+ if (!isString(name) || name === ""){
+ error("Cookie name must be a non-empty string.");
+ }
+ }
+
+ /*
+ * Checks the validity of a subcookie name.
+ */
+ function validateSubcookieName(subName){
+ if (!isString(subName) || subName === ""){
+ error("Subcookie name must be a non-empty string.");
+ }
+ }
+
+ /**
+ * Cookie utility.
+ * @class Cookie
+ * @static
+ */
+ Y.Cookie = {
+
+ //-------------------------------------------------------------------------
+ // Private Methods
+ //-------------------------------------------------------------------------
+
+ /**
+ * Creates a cookie string that can be assigned into document.cookie.
+ * @param {String} name The name of the cookie.
+ * @param {String} value The value of the cookie.
+ * @param {Boolean} encodeValue True to encode the value, false to leave as-is.
+ * @param {Object} options (Optional) Options for the cookie.
+ * @return {String} The formatted cookie string.
+ * @method _createCookieString
+ * @private
+ * @static
+ */
+ _createCookieString : function (name /*:String*/, value /*:Variant*/, encodeValue /*:Boolean*/, options /*:Object*/) /*:String*/ {
+
+ options = options || {};
+
+ var text /*:String*/ = encode(name) + "=" + (encodeValue ? encode(value) : value),
+ expires = options.expires,
+ path = options.path,
+ domain = options.domain;
+
+
+ if (isObject(options)){
+ //expiration date
+ if (expires instanceof Date){
+ text += "; expires=" + expires.toUTCString();
+ }
+
+ //path
+ if (isString(path) && path !== ""){
+ text += "; path=" + path;
+ }
+
+ //domain
+ if (isString(domain) && domain !== ""){
+ text += "; domain=" + domain;
+ }
+
+ //secure
+ if (options.secure === true){
+ text += "; secure";
+ }
+ }
+
+ return text;
+ },
+
+ /**
+ * Formats a cookie value for an object containing multiple values.
+ * @param {Object} hash An object of key-value pairs to create a string for.
+ * @return {String} A string suitable for use as a cookie value.
+ * @method _createCookieHashString
+ * @private
+ * @static
+ */
+ _createCookieHashString : function (hash /*:Object*/) /*:String*/ {
+ if (!isObject(hash)){
+ error("Cookie._createCookieHashString(): Argument must be an object.");
+ }
+
+ var text /*:Array*/ = [];
+
+ O.each(hash, function(value, key){
+ if (!isFunction(value) && !isUndefined(value)){
+ text.push(encode(key) + "=" + encode(String(value)));
+ }
+ });
+
+ return text.join("&");
+ },
+
+ /**
+ * Parses a cookie hash string into an object.
+ * @param {String} text The cookie hash string to parse (format: n1=v1&n2=v2).
+ * @return {Object} An object containing entries for each cookie value.
+ * @method _parseCookieHash
+ * @private
+ * @static
+ */
+ _parseCookieHash : function (text) {
+
+ var hashParts = text.split("&"),
+ hashPart = NULL,
+ hash = {};
+
+ if (text.length){
+ for (var i=0, len=hashParts.length; i < len; i++){
+ hashPart = hashParts[i].split("=");
+ hash[decode(hashPart[0])] = decode(hashPart[1]);
+ }
+ }
+
+ return hash;
+ },
+
+ /**
+ * Parses a cookie string into an object representing all accessible cookies.
+ * @param {String} text The cookie string to parse.
+ * @param {Boolean} shouldDecode (Optional) Indicates if the cookie values should be decoded or not. Default is true.
+ * @return {Object} An object containing entries for each accessible cookie.
+ * @method _parseCookieString
+ * @private
+ * @static
+ */
+ _parseCookieString : function (text /*:String*/, shouldDecode /*:Boolean*/) /*:Object*/ {
+
+ var cookies /*:Object*/ = {};
+
+ if (isString(text) && text.length > 0) {
+
+ var decodeValue = (shouldDecode === false ? function(s){return s;} : decode),
+ cookieParts = text.split(/;\s/g),
+ cookieName = NULL,
+ cookieValue = NULL,
+ cookieNameValue = NULL;
+
+ for (var i=0, len=cookieParts.length; i < len; i++){
+
+ //check for normally-formatted cookie (name-value)
+ cookieNameValue = cookieParts[i].match(/([^=]+)=/i);
+ if (cookieNameValue instanceof Array){
+ try {
+ cookieName = decode(cookieNameValue[1]);
+ cookieValue = decodeValue(cookieParts[i].substring(cookieNameValue[1].length+1));
+ } catch (ex){
+ //intentionally ignore the cookie - the encoding is wrong
+ }
+ } else {
+ //means the cookie does not have an "=", so treat it as a boolean flag
+ cookieName = decode(cookieParts[i]);
+ cookieValue = "";
+ }
+ cookies[cookieName] = cookieValue;
+ }
+
+ }
+
+ return cookies;
+ },
+
+ //-------------------------------------------------------------------------
+ // Public Methods
+ //-------------------------------------------------------------------------
+
+ /**
+ * Determines if the cookie with the given name exists. This is useful for
+ * Boolean cookies (those that do not follow the name=value convention).
+ * @param {String} name The name of the cookie to check.
+ * @return {Boolean} True if the cookie exists, false if not.
+ * @method exists
+ * @static
+ */
+ exists: function(name) {
+
+ validateCookieName(name); //throws error
+
+ var cookies = this._parseCookieString(doc.cookie, true);
+
+ return cookies.hasOwnProperty(name);
+ },
+
+ /**
+ * Returns the cookie value for the given name.
+ * @param {String} name The name of the cookie to retrieve.
+ * @param {Function|Object} options (Optional) An object containing one or more
+ * cookie options: raw (true/false) and converter (a function).
+ * The converter function is run on the value before returning it. The
+ * function is not used if the cookie doesn't exist. The function can be
+ * passed instead of the options object for backwards compatibility. When
+ * raw is set to true, the cookie value is not URI decoded.
+ * @return {Variant} If no converter is specified, returns a string or null if
+ * the cookie doesn't exist. If the converter is specified, returns the value
+ * returned from the converter or null if the cookie doesn't exist.
+ * @method get
+ * @static
+ */
+ get : function (name, options) {
+
+ validateCookieName(name); //throws error
+
+ var cookies,
+ cookie,
+ converter;
+
+ //if options is a function, then it's the converter
+ if (isFunction(options)) {
+ converter = options;
+ options = {};
+ } else if (isObject(options)) {
+ converter = options.converter;
+ } else {
+ options = {};
+ }
+
+ cookies = this._parseCookieString(doc.cookie, !options.raw);
+ cookie = cookies[name];
+
+ //should return null, not undefined if the cookie doesn't exist
+ if (isUndefined(cookie)) {
+ return NULL;
+ }
+
+ if (!isFunction(converter)){
+ return cookie;
+ } else {
+ return converter(cookie);
+ }
+ },
+
+ /**
+ * Returns the value of a subcookie.
+ * @param {String} name The name of the cookie to retrieve.
+ * @param {String} subName The name of the subcookie to retrieve.
+ * @param {Function} converter (Optional) A function to run on the value before returning
+ * it. The function is not used if the cookie doesn't exist.
+ * @return {Variant} If the cookie doesn't exist, null is returned. If the subcookie
+ * doesn't exist, null if also returned. If no converter is specified and the
+ * subcookie exists, a string is returned. If a converter is specified and the
+ * subcookie exists, the value returned from the converter is returned.
+ * @method getSub
+ * @static
+ */
+ getSub : function (name /*:String*/, subName /*:String*/, converter /*:Function*/) /*:Variant*/ {
+
+ var hash /*:Variant*/ = this.getSubs(name);
+
+ if (hash !== NULL) {
+
+ validateSubcookieName(subName); //throws error
+
+ if (isUndefined(hash[subName])){
+ return NULL;
+ }
+
+ if (!isFunction(converter)){
+ return hash[subName];
+ } else {
+ return converter(hash[subName]);
+ }
+ } else {
+ return NULL;
+ }
+
+ },
+
+ /**
+ * Returns an object containing name-value pairs stored in the cookie with the given name.
+ * @param {String} name The name of the cookie to retrieve.
+ * @return {Object} An object of name-value pairs if the cookie with the given name
+ * exists, null if it does not.
+ * @method getSubs
+ * @static
+ */
+ getSubs : function (name) {
+
+ validateCookieName(name); //throws error
+
+ var cookies = this._parseCookieString(doc.cookie, false);
+ if (isString(cookies[name])){
+ return this._parseCookieHash(cookies[name]);
+ }
+ return NULL;
+ },
+
+ /**
+ * Removes a cookie from the machine by setting its expiration date to
+ * sometime in the past.
+ * @param {String} name The name of the cookie to remove.
+ * @param {Object} options (Optional) An object containing one or more
+ * cookie options: path (a string), domain (a string),
+ * and secure (true/false). The expires option will be overwritten
+ * by the method.
+ * @return {String} The created cookie string.
+ * @method remove
+ * @static
+ */
+ remove : function (name, options) {
+
+ validateCookieName(name); //throws error
+
+ //set options
+ options = Y.merge(options || {}, {
+ expires: new Date(0)
+ });
+
+ //set cookie
+ return this.set(name, "", options);
+ },
+
+ /**
+ * Removes a sub cookie with a given name.
+ * @param {String} name The name of the cookie in which the subcookie exists.
+ * @param {String} subName The name of the subcookie to remove.
+ * @param {Object} options (Optional) An object containing one or more
+ * cookie options: path (a string), domain (a string), expires (a Date object),
+ * removeIfEmpty (true/false), and secure (true/false). This must be the same
+ * settings as the original subcookie.
+ * @return {String} The created cookie string.
+ * @method removeSub
+ * @static
+ */
+ removeSub : function(name, subName, options) {
+
+ validateCookieName(name); //throws error
+
+ validateSubcookieName(subName); //throws error
+
+ options = options || {};
+
+ //get all subcookies for this cookie
+ var subs = this.getSubs(name);
+
+ //delete the indicated subcookie
+ if (isObject(subs) && subs.hasOwnProperty(subName)){
+ delete subs[subName];
+
+ if (!options.removeIfEmpty) {
+ //reset the cookie
+
+ return this.setSubs(name, subs, options);
+ } else {
+ //reset the cookie if there are subcookies left, else remove
+ for (var key in subs){
+ if (subs.hasOwnProperty(key) && !isFunction(subs[key]) && !isUndefined(subs[key])){
+ return this.setSubs(name, subs, options);
+ }
+ }
+
+ return this.remove(name, options);
+ }
+ } else {
+ return "";
+ }
+
+ },
+
+ /**
+ * Sets a cookie with a given name and value.
+ * @param {String} name The name of the cookie to set.
+ * @param {Variant} value The value to set for the cookie.
+ * @param {Object} options (Optional) An object containing one or more
+ * cookie options: path (a string), domain (a string), expires (a Date object),
+ * secure (true/false), and raw (true/false). Setting raw to true indicates
+ * that the cookie should not be URI encoded before being set.
+ * @return {String} The created cookie string.
+ * @method set
+ * @static
+ */
+ set : function (name, value, options) {
+
+ validateCookieName(name); //throws error
+
+ if (isUndefined(value)){
+ error("Cookie.set(): Value cannot be undefined.");
+ }
+
+ options = options || {};
+
+ var text = this._createCookieString(name, value, !options.raw, options);
+ doc.cookie = text;
+ return text;
+ },
+
+ /**
+ * Sets a sub cookie with a given name to a particular value.
+ * @param {String} name The name of the cookie to set.
+ * @param {String} subName The name of the subcookie to set.
+ * @param {Variant} value The value to set.
+ * @param {Object} options (Optional) An object containing one or more
+ * cookie options: path (a string), domain (a string), expires (a Date object),
+ * and secure (true/false).
+ * @return {String} The created cookie string.
+ * @method setSub
+ * @static
+ */
+ setSub : function (name, subName, value, options) {
+
+ validateCookieName(name); //throws error
+
+ validateSubcookieName(subName); //throws error
+
+ if (isUndefined(value)){
+ error("Cookie.setSub(): Subcookie value cannot be undefined.");
+ }
+
+ var hash = this.getSubs(name);
+
+ if (!isObject(hash)){
+ hash = {};
+ }
+
+ hash[subName] = value;
+
+ return this.setSubs(name, hash, options);
+
+ },
+
+ /**
+ * Sets a cookie with a given name to contain a hash of name-value pairs.
+ * @param {String} name The name of the cookie to set.
+ * @param {Object} value An object containing name-value pairs.
+ * @param {Object} options (Optional) An object containing one or more
+ * cookie options: path (a string), domain (a string), expires (a Date object),
+ * and secure (true/false).
+ * @return {String} The created cookie string.
+ * @method setSubs
+ * @static
+ */
+ setSubs : function (name, value, options) {
+
+ validateCookieName(name); //throws error
+
+ if (!isObject(value)){
+ error("Cookie.setSubs(): Cookie value must be an object.");
+ }
+
+ var text /*:String*/ = this._createCookieString(name, this._createCookieHashString(value), false, options);
+ doc.cookie = text;
+ return text;
+ }
+
+ };
+
+
+
+}, '3.0.0' ,{requires:['yui-base']});
diff --git a/lib/yui/3.0.0/cookie/cookie-min.js b/lib/yui/3.0.0/cookie/cookie-min.js
new file mode 100644
index 0000000000..e80ed476b8
--- /dev/null
+++ b/lib/yui/3.0.0/cookie/cookie-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("cookie",function(C){var K=C.Lang,I=C.Object,G=null,D=K.isString,P=K.isObject,F=K.isUndefined,E=K.isFunction,H=encodeURIComponent,B=decodeURIComponent,N=C.config.doc;function J(L){throw new TypeError(L);}function M(L){if(!D(L)||L===""){J("Cookie name must be a non-empty string.");}}function A(L){if(!D(L)||L===""){J("Subcookie name must be a non-empty string.");}}C.Cookie={_createCookieString:function(Q,T,R,O){O=O||{};var V=H(Q)+"="+(R?H(T):T),L=O.expires,U=O.path,S=O.domain;if(P(O)){if(L instanceof Date){V+="; expires="+L.toUTCString();}if(D(U)&&U!==""){V+="; path="+U;}if(D(S)&&S!==""){V+="; domain="+S;}if(O.secure===true){V+="; secure";}}return V;},_createCookieHashString:function(L){if(!P(L)){J("Cookie._createCookieHashString(): Argument must be an object.");}var O=[];I.each(L,function(R,Q){if(!E(R)&&!F(R)){O.push(H(Q)+"="+H(String(R)));}});return O.join("&");},_parseCookieHash:function(S){var R=S.split("&"),T=G,Q={};if(S.length){for(var O=0,L=R.length;O0){var L=(Y===false?function(Z){return Z;}:B),U=W.split(/;\s/g),V=G,O=G,R=G;for(var Q=0,S=U.length;Q 0) {
+
+ var decodeValue = (shouldDecode === false ? function(s){return s;} : decode),
+ cookieParts = text.split(/;\s/g),
+ cookieName = NULL,
+ cookieValue = NULL,
+ cookieNameValue = NULL;
+
+ for (var i=0, len=cookieParts.length; i < len; i++){
+
+ //check for normally-formatted cookie (name-value)
+ cookieNameValue = cookieParts[i].match(/([^=]+)=/i);
+ if (cookieNameValue instanceof Array){
+ try {
+ cookieName = decode(cookieNameValue[1]);
+ cookieValue = decodeValue(cookieParts[i].substring(cookieNameValue[1].length+1));
+ } catch (ex){
+ //intentionally ignore the cookie - the encoding is wrong
+ }
+ } else {
+ //means the cookie does not have an "=", so treat it as a boolean flag
+ cookieName = decode(cookieParts[i]);
+ cookieValue = "";
+ }
+ cookies[cookieName] = cookieValue;
+ }
+
+ }
+
+ return cookies;
+ },
+
+ //-------------------------------------------------------------------------
+ // Public Methods
+ //-------------------------------------------------------------------------
+
+ /**
+ * Determines if the cookie with the given name exists. This is useful for
+ * Boolean cookies (those that do not follow the name=value convention).
+ * @param {String} name The name of the cookie to check.
+ * @return {Boolean} True if the cookie exists, false if not.
+ * @method exists
+ * @static
+ */
+ exists: function(name) {
+
+ validateCookieName(name); //throws error
+
+ var cookies = this._parseCookieString(doc.cookie, true);
+
+ return cookies.hasOwnProperty(name);
+ },
+
+ /**
+ * Returns the cookie value for the given name.
+ * @param {String} name The name of the cookie to retrieve.
+ * @param {Function|Object} options (Optional) An object containing one or more
+ * cookie options: raw (true/false) and converter (a function).
+ * The converter function is run on the value before returning it. The
+ * function is not used if the cookie doesn't exist. The function can be
+ * passed instead of the options object for backwards compatibility. When
+ * raw is set to true, the cookie value is not URI decoded.
+ * @return {Variant} If no converter is specified, returns a string or null if
+ * the cookie doesn't exist. If the converter is specified, returns the value
+ * returned from the converter or null if the cookie doesn't exist.
+ * @method get
+ * @static
+ */
+ get : function (name, options) {
+
+ validateCookieName(name); //throws error
+
+ var cookies,
+ cookie,
+ converter;
+
+ //if options is a function, then it's the converter
+ if (isFunction(options)) {
+ converter = options;
+ options = {};
+ } else if (isObject(options)) {
+ converter = options.converter;
+ } else {
+ options = {};
+ }
+
+ cookies = this._parseCookieString(doc.cookie, !options.raw);
+ cookie = cookies[name];
+
+ //should return null, not undefined if the cookie doesn't exist
+ if (isUndefined(cookie)) {
+ return NULL;
+ }
+
+ if (!isFunction(converter)){
+ return cookie;
+ } else {
+ return converter(cookie);
+ }
+ },
+
+ /**
+ * Returns the value of a subcookie.
+ * @param {String} name The name of the cookie to retrieve.
+ * @param {String} subName The name of the subcookie to retrieve.
+ * @param {Function} converter (Optional) A function to run on the value before returning
+ * it. The function is not used if the cookie doesn't exist.
+ * @return {Variant} If the cookie doesn't exist, null is returned. If the subcookie
+ * doesn't exist, null if also returned. If no converter is specified and the
+ * subcookie exists, a string is returned. If a converter is specified and the
+ * subcookie exists, the value returned from the converter is returned.
+ * @method getSub
+ * @static
+ */
+ getSub : function (name /*:String*/, subName /*:String*/, converter /*:Function*/) /*:Variant*/ {
+
+ var hash /*:Variant*/ = this.getSubs(name);
+
+ if (hash !== NULL) {
+
+ validateSubcookieName(subName); //throws error
+
+ if (isUndefined(hash[subName])){
+ return NULL;
+ }
+
+ if (!isFunction(converter)){
+ return hash[subName];
+ } else {
+ return converter(hash[subName]);
+ }
+ } else {
+ return NULL;
+ }
+
+ },
+
+ /**
+ * Returns an object containing name-value pairs stored in the cookie with the given name.
+ * @param {String} name The name of the cookie to retrieve.
+ * @return {Object} An object of name-value pairs if the cookie with the given name
+ * exists, null if it does not.
+ * @method getSubs
+ * @static
+ */
+ getSubs : function (name) {
+
+ validateCookieName(name); //throws error
+
+ var cookies = this._parseCookieString(doc.cookie, false);
+ if (isString(cookies[name])){
+ return this._parseCookieHash(cookies[name]);
+ }
+ return NULL;
+ },
+
+ /**
+ * Removes a cookie from the machine by setting its expiration date to
+ * sometime in the past.
+ * @param {String} name The name of the cookie to remove.
+ * @param {Object} options (Optional) An object containing one or more
+ * cookie options: path (a string), domain (a string),
+ * and secure (true/false). The expires option will be overwritten
+ * by the method.
+ * @return {String} The created cookie string.
+ * @method remove
+ * @static
+ */
+ remove : function (name, options) {
+
+ validateCookieName(name); //throws error
+
+ //set options
+ options = Y.merge(options || {}, {
+ expires: new Date(0)
+ });
+
+ //set cookie
+ return this.set(name, "", options);
+ },
+
+ /**
+ * Removes a sub cookie with a given name.
+ * @param {String} name The name of the cookie in which the subcookie exists.
+ * @param {String} subName The name of the subcookie to remove.
+ * @param {Object} options (Optional) An object containing one or more
+ * cookie options: path (a string), domain (a string), expires (a Date object),
+ * removeIfEmpty (true/false), and secure (true/false). This must be the same
+ * settings as the original subcookie.
+ * @return {String} The created cookie string.
+ * @method removeSub
+ * @static
+ */
+ removeSub : function(name, subName, options) {
+
+ validateCookieName(name); //throws error
+
+ validateSubcookieName(subName); //throws error
+
+ options = options || {};
+
+ //get all subcookies for this cookie
+ var subs = this.getSubs(name);
+
+ //delete the indicated subcookie
+ if (isObject(subs) && subs.hasOwnProperty(subName)){
+ delete subs[subName];
+
+ if (!options.removeIfEmpty) {
+ //reset the cookie
+
+ return this.setSubs(name, subs, options);
+ } else {
+ //reset the cookie if there are subcookies left, else remove
+ for (var key in subs){
+ if (subs.hasOwnProperty(key) && !isFunction(subs[key]) && !isUndefined(subs[key])){
+ return this.setSubs(name, subs, options);
+ }
+ }
+
+ return this.remove(name, options);
+ }
+ } else {
+ return "";
+ }
+
+ },
+
+ /**
+ * Sets a cookie with a given name and value.
+ * @param {String} name The name of the cookie to set.
+ * @param {Variant} value The value to set for the cookie.
+ * @param {Object} options (Optional) An object containing one or more
+ * cookie options: path (a string), domain (a string), expires (a Date object),
+ * secure (true/false), and raw (true/false). Setting raw to true indicates
+ * that the cookie should not be URI encoded before being set.
+ * @return {String} The created cookie string.
+ * @method set
+ * @static
+ */
+ set : function (name, value, options) {
+
+ validateCookieName(name); //throws error
+
+ if (isUndefined(value)){
+ error("Cookie.set(): Value cannot be undefined.");
+ }
+
+ options = options || {};
+
+ var text = this._createCookieString(name, value, !options.raw, options);
+ doc.cookie = text;
+ return text;
+ },
+
+ /**
+ * Sets a sub cookie with a given name to a particular value.
+ * @param {String} name The name of the cookie to set.
+ * @param {String} subName The name of the subcookie to set.
+ * @param {Variant} value The value to set.
+ * @param {Object} options (Optional) An object containing one or more
+ * cookie options: path (a string), domain (a string), expires (a Date object),
+ * and secure (true/false).
+ * @return {String} The created cookie string.
+ * @method setSub
+ * @static
+ */
+ setSub : function (name, subName, value, options) {
+
+ validateCookieName(name); //throws error
+
+ validateSubcookieName(subName); //throws error
+
+ if (isUndefined(value)){
+ error("Cookie.setSub(): Subcookie value cannot be undefined.");
+ }
+
+ var hash = this.getSubs(name);
+
+ if (!isObject(hash)){
+ hash = {};
+ }
+
+ hash[subName] = value;
+
+ return this.setSubs(name, hash, options);
+
+ },
+
+ /**
+ * Sets a cookie with a given name to contain a hash of name-value pairs.
+ * @param {String} name The name of the cookie to set.
+ * @param {Object} value An object containing name-value pairs.
+ * @param {Object} options (Optional) An object containing one or more
+ * cookie options: path (a string), domain (a string), expires (a Date object),
+ * and secure (true/false).
+ * @return {String} The created cookie string.
+ * @method setSubs
+ * @static
+ */
+ setSubs : function (name, value, options) {
+
+ validateCookieName(name); //throws error
+
+ if (!isObject(value)){
+ error("Cookie.setSubs(): Cookie value must be an object.");
+ }
+
+ var text /*:String*/ = this._createCookieString(name, this._createCookieHashString(value), false, options);
+ doc.cookie = text;
+ return text;
+ }
+
+ };
+
+
+
+}, '3.0.0' ,{requires:['yui-base']});
diff --git a/lib/yui/3.0.0/cssbase/base-context-min.css b/lib/yui/3.0.0/cssbase/base-context-min.css
new file mode 100644
index 0000000000..f92c93e5eb
--- /dev/null
+++ b/lib/yui/3.0.0/cssbase/base-context-min.css
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+.yui-cssbase h1{font-size:138.5%;}.yui-cssbase h2{font-size:123.1%;}.yui-cssbase h3{font-size:108%;}.yui-cssbase h1,.yui-cssbase h2,.yui-cssbase h3{margin:1em 0;}.yui-cssbase h1,.yui-cssbase h2,.yui-cssbase h3,.yui-cssbase h4,.yui-cssbase h5,.yui-cssbase h6,.yui-cssbase strong{font-weight:bold;}.yui-cssbase abbr,.yui-cssbase acronym{border-bottom:1px dotted #000;cursor:help;}.yui-cssbase em{font-style:italic;}.yui-cssbase blockquote,.yui-cssbase ul,.yui-cssbase ol,.yui-cssbase dl{margin:1em;}.yui-cssbase ol,.yui-cssbase ul,.yui-cssbase dl{margin-left:2em;}.yui-cssbase ol li{list-style:decimal outside;}.yui-cssbase ul li{list-style:disc outside;}.yui-cssbase dl dd{margin-left:1em;}.yui-cssbase th,.yui-cssbase td{border:1px solid #000;padding:.5em;}.yui-cssbase th{font-weight:bold;text-align:center;}.yui-cssbase caption{margin-bottom:.5em;text-align:center;}.yui-cssbase p,.yui-cssbase fieldset,.yui-cssbase table,.yui-cssbase pre{margin-bottom:1em;}.yui-cssbase input[type=text],.yui-cssbase input[type=password],.yui-cssbase textarea{width:12.25em;*width:11.9em;}
\ No newline at end of file
diff --git a/lib/yui/3.0.0/cssbase/base-context.css b/lib/yui/3.0.0/cssbase/base-context.css
new file mode 100644
index 0000000000..afef2b2004
--- /dev/null
+++ b/lib/yui/3.0.0/cssbase/base-context.css
@@ -0,0 +1,80 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+/* base.css, part of YUI's CSS Foundation */
+.yui-cssbase h1 {
+ /*18px via YUI Fonts CSS foundation*/
+ font-size:138.5%;
+}
+.yui-cssbase h2 {
+ /*16px via YUI Fonts CSS foundation*/
+ font-size:123.1%;
+}
+.yui-cssbase h3 {
+ /*14px via YUI Fonts CSS foundation*/
+ font-size:108%;
+}
+.yui-cssbase h1,.yui-cssbase h2,.yui-cssbase h3 {
+ /* top & bottom margin based on font size */
+ margin:1em 0;
+}
+.yui-cssbase h1,.yui-cssbase h2,.yui-cssbase h3,.yui-cssbase h4,.yui-cssbase h5,.yui-cssbase h6,.yui-cssbase strong {
+ /*bringing boldness back to headers and the strong element*/
+ font-weight:bold;
+}
+.yui-cssbase abbr,.yui-cssbase acronym {
+ /*indicating to users that more info is available */
+ border-bottom:1px dotted #000;
+ cursor:help;
+}
+.yui-cssbase em {
+ /*bringing italics back to the em element*/
+ font-style:italic;
+}
+.yui-cssbase blockquote,.yui-cssbase ul,.yui-cssbase ol,.yui-cssbase dl {
+ /*giving blockquotes and lists room to breath*/
+ margin:1em;
+}
+.yui-cssbase ol,.yui-cssbase ul,.yui-cssbase dl {
+ /*bringing lists on to the page with breathing room */
+ margin-left:2em;
+}
+.yui-cssbase ol li {
+ /*giving OL's LIs generated numbers*/
+ list-style: decimal outside;
+}
+.yui-cssbase ul li {
+ /*giving UL's LIs generated disc markers*/
+ list-style: disc outside;
+}
+.yui-cssbase dl dd {
+ /*providing spacing for definition terms*/
+ margin-left:1em;
+}
+.yui-cssbase th,.yui-cssbase td {
+ /*borders and padding to make the table readable*/
+ border:1px solid #000;
+ padding:.5em;
+}
+.yui-cssbase th {
+ /*distinguishing table headers from data cells*/
+ font-weight:bold;
+ text-align:center;
+}
+.yui-cssbase caption {
+ /*coordinated margin to match cell's padding*/
+ margin-bottom:.5em;
+ /*centered so it doesn't blend in to other content*/
+ text-align:center;
+}
+.yui-cssbase p,.yui-cssbase fieldset,.yui-cssbase table,.yui-cssbase pre {
+ /*so things don't run into each other*/
+ margin-bottom:1em;
+}
+/* setting a consistent width, 160px;
+ control of type=file still not possible */
+.yui-cssbase input[type=text],.yui-cssbase input[type=password],.yui-cssbase textarea{width:12.25em;*width:11.9em;}
diff --git a/lib/yui/3.0.0/cssbase/base-min.css b/lib/yui/3.0.0/cssbase/base-min.css
new file mode 100644
index 0000000000..ba9fc00a2e
--- /dev/null
+++ b/lib/yui/3.0.0/cssbase/base-min.css
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+h1{font-size:138.5%;}h2{font-size:123.1%;}h3{font-size:108%;}h1,h2,h3{margin:1em 0;}h1,h2,h3,h4,h5,h6,strong{font-weight:bold;}abbr,acronym{border-bottom:1px dotted #000;cursor:help;}em{font-style:italic;}blockquote,ul,ol,dl{margin:1em;}ol,ul,dl{margin-left:2em;}ol li{list-style:decimal outside;}ul li{list-style:disc outside;}dl dd{margin-left:1em;}th,td{border:1px solid #000;padding:.5em;}th{font-weight:bold;text-align:center;}caption{margin-bottom:.5em;text-align:center;}p,fieldset,table,pre{margin-bottom:1em;}input[type=text],input[type=password],textarea{width:12.25em;*width:11.9em;}
\ No newline at end of file
diff --git a/lib/yui/3.0.0/cssbase/base.css b/lib/yui/3.0.0/cssbase/base.css
new file mode 100644
index 0000000000..3bdce2a7c0
--- /dev/null
+++ b/lib/yui/3.0.0/cssbase/base.css
@@ -0,0 +1,80 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+/* base.css, part of YUI's CSS Foundation */
+h1 {
+ /*18px via YUI Fonts CSS foundation*/
+ font-size:138.5%;
+}
+h2 {
+ /*16px via YUI Fonts CSS foundation*/
+ font-size:123.1%;
+}
+h3 {
+ /*14px via YUI Fonts CSS foundation*/
+ font-size:108%;
+}
+h1,h2,h3 {
+ /* top & bottom margin based on font size */
+ margin:1em 0;
+}
+h1,h2,h3,h4,h5,h6,strong {
+ /*bringing boldness back to headers and the strong element*/
+ font-weight:bold;
+}
+abbr,acronym {
+ /*indicating to users that more info is available */
+ border-bottom:1px dotted #000;
+ cursor:help;
+}
+em {
+ /*bringing italics back to the em element*/
+ font-style:italic;
+}
+blockquote,ul,ol,dl {
+ /*giving blockquotes and lists room to breath*/
+ margin:1em;
+}
+ol,ul,dl {
+ /*bringing lists on to the page with breathing room */
+ margin-left:2em;
+}
+ol li {
+ /*giving OL's LIs generated numbers*/
+ list-style: decimal outside;
+}
+ul li {
+ /*giving UL's LIs generated disc markers*/
+ list-style: disc outside;
+}
+dl dd {
+ /*providing spacing for definition terms*/
+ margin-left:1em;
+}
+th,td {
+ /*borders and padding to make the table readable*/
+ border:1px solid #000;
+ padding:.5em;
+}
+th {
+ /*distinguishing table headers from data cells*/
+ font-weight:bold;
+ text-align:center;
+}
+caption {
+ /*coordinated margin to match cell's padding*/
+ margin-bottom:.5em;
+ /*centered so it doesn't blend in to other content*/
+ text-align:center;
+}
+p,fieldset,table,pre {
+ /*so things don't run into each other*/
+ margin-bottom:1em;
+}
+/* setting a consistent width, 160px;
+ control of type=file still not possible */
+input[type=text],input[type=password],textarea{width:12.25em;*width:11.9em;}
diff --git a/lib/yui/3.0.0/cssfonts/fonts-context-min.css b/lib/yui/3.0.0/cssfonts/fonts-context-min.css
new file mode 100644
index 0000000000..176d243561
--- /dev/null
+++ b/lib/yui/3.0.0/cssfonts/fonts-context-min.css
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+.yui-cssfonts body,.yui-cssfonts{font:13px/1.231 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}.yui-cssfonts select,.yui-cssfonts input,.yui-cssfonts button,.yui-cssfonts textarea{font:99% arial,helvetica,clean,sans-serif;}.yui-cssfonts table{font-size:inherit;font:100%;}.yui-cssfonts pre,.yui-cssfonts code,.yui-cssfonts kbd,.yui-cssfonts samp,.yui-cssfonts tt{font-family:monospace;*font-size:108%;line-height:100%;}
\ No newline at end of file
diff --git a/lib/yui/3.0.0/cssfonts/fonts-context.css b/lib/yui/3.0.0/cssfonts/fonts-context.css
new file mode 100644
index 0000000000..5d0f8abbcf
--- /dev/null
+++ b/lib/yui/3.0.0/cssfonts/fonts-context.css
@@ -0,0 +1,47 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+/**
+ * Percents could work for IE, but for backCompat purposes, we are using keywords.
+ * x-small is for IE6/7 quirks mode.
+ */
+.yui-cssfonts body, .yui-cssfonts {
+ font:13px/1.231 arial,helvetica,clean,sans-serif;
+ *font-size:small; /* for IE */
+ *font:x-small; /* for IE in quirks mode */
+}
+
+/**
+ * Nudge down to get to 13px equivalent for these form elements
+ */
+.yui-cssfonts select,
+.yui-cssfonts input,
+.yui-cssfonts button,
+.yui-cssfonts textarea {
+ font:99% arial,helvetica,clean,sans-serif;
+}
+
+/**
+ * To help tables remember to inherit
+ */
+.yui-cssfonts table {
+ font-size:inherit;
+ font:100%;
+}
+
+/**
+ * Bump up IE to get to 13px equivalent for these fixed-width elements
+ */
+.yui-cssfonts pre,
+.yui-cssfonts code,
+.yui-cssfonts kbd,
+.yui-cssfonts samp,
+.yui-cssfonts tt {
+ font-family:monospace;
+ *font-size:108%;
+ line-height:100%;
+}
\ No newline at end of file
diff --git a/lib/yui/3.0.0/cssfonts/fonts-min.css b/lib/yui/3.0.0/cssfonts/fonts-min.css
new file mode 100644
index 0000000000..aad94dc7ca
--- /dev/null
+++ b/lib/yui/3.0.0/cssfonts/fonts-min.css
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+body{font:13px/1.231 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}select,input,button,textarea{font:99% arial,helvetica,clean,sans-serif;}table{font-size:inherit;font:100%;}pre,code,kbd,samp,tt{font-family:monospace;*font-size:108%;line-height:100%;}
\ No newline at end of file
diff --git a/lib/yui/3.0.0/cssfonts/fonts.css b/lib/yui/3.0.0/cssfonts/fonts.css
new file mode 100644
index 0000000000..23fb353ffb
--- /dev/null
+++ b/lib/yui/3.0.0/cssfonts/fonts.css
@@ -0,0 +1,47 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+/**
+ * Percents could work for IE, but for backCompat purposes, we are using keywords.
+ * x-small is for IE6/7 quirks mode.
+ */
+body {
+ font:13px/1.231 arial,helvetica,clean,sans-serif;
+ *font-size:small; /* for IE */
+ *font:x-small; /* for IE in quirks mode */
+}
+
+/**
+ * Nudge down to get to 13px equivalent for these form elements
+ */
+select,
+input,
+button,
+textarea {
+ font:99% arial,helvetica,clean,sans-serif;
+}
+
+/**
+ * To help tables remember to inherit
+ */
+table {
+ font-size:inherit;
+ font:100%;
+}
+
+/**
+ * Bump up IE to get to 13px equivalent for these fixed-width elements
+ */
+pre,
+code,
+kbd,
+samp,
+tt {
+ font-family:monospace;
+ *font-size:108%;
+ line-height:100%;
+}
\ No newline at end of file
diff --git a/lib/yui/3.0.0/cssgrids/grids-context-min.css b/lib/yui/3.0.0/cssgrids/grids-context-min.css
new file mode 100644
index 0000000000..b19a3af6cd
--- /dev/null
+++ b/lib/yui/3.0.0/cssgrids/grids-context-min.css
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+.yui-cssgrids body{text-align:center;margin-left:auto;margin-right:auto;}.yui-cssgrids .yui-d0,.yui-cssgrids .yui-d1,.yui-cssgrids .yui-d1f,.yui-cssgrids .yui-d2,.yui-cssgrids .yui-d2f,.yui-cssgrids .yui-d3,.yui-cssgrids .yui-d3f{margin:auto;text-align:left;width:57.69em;*width:56.25em;}.yui-cssgrids .yui-t1,.yui-cssgrids .yui-t2,.yui-cssgrids .yui-t3,.yui-cssgrids .yui-t4,.yui-cssgrids .yui-t5,.yui-cssgrids .yui-t6{margin:auto;text-align:left;width:100%;}.yui-cssgrids .yui-d0{margin:auto 10px;width:auto;}.yui-cssgrids .yui-d0f{width:100%;}.yui-cssgrids .yui-d2{width:73.076em;*width:71.25em;}.yui-cssgrids .yui-d2f{width:950px;}.yui-cssgrids .yui-d3{width:74.923em;*width:73.05em;}.yui-cssgrids .yui-d3f{width:974px;}.yui-cssgrids .yui-b{position:relative;}.yui-cssgrids .yui-b{_position:static;}.yui-cssgrids .yui-main .yui-b{position:static;}.yui-cssgrids .yui-main{width:100%;}.yui-cssgrids .yui-t1 .yui-main,.yui-cssgrids .yui-t2 .yui-main,.yui-cssgrids .yui-t3 .yui-main{float:right;margin-left:-25em;}.yui-cssgrids .yui-t4 .yui-main,.yui-cssgrids .yui-t5 .yui-main,.yui-cssgrids .yui-t6 .yui-main{float:left;margin-right:-25em;}.yui-cssgrids .yui-t1 .yui-b{float:left;width:12.30769em;*width:12.00em;}.yui-cssgrids .yui-t1 .yui-main .yui-b{margin-left:13.30769em;*margin-left:12.975em;}.yui-cssgrids .yui-t2 .yui-b{float:left;width:13.84615em;*width:13.50em;}.yui-cssgrids .yui-t2 .yui-main .yui-b{margin-left:14.84615em;*margin-left:14.475em;}.yui-cssgrids .yui-t3 .yui-b{float:left;width:23.0769em;*width:22.50em;}.yui-cssgrids .yui-t3 .yui-main .yui-b{margin-left:24.0769em;*margin-left:23.475em;}.yui-cssgrids .yui-t4 .yui-b{float:right;width:13.8456em;*width:13.50em;}.yui-cssgrids .yui-t4 .yui-main .yui-b{margin-right:14.8456em;*margin-right:14.475em;}.yui-cssgrids .yui-t5 .yui-b{float:right;width:18.4615em;*width:18.00em;}.yui-cssgrids .yui-t5 .yui-main .yui-b{margin-right:19.4615em;*margin-right:18.975em;}.yui-cssgrids .yui-t6 .yui-b{float:right;width:23.0769em;*width:22.50em;}.yui-cssgrids .yui-t6 .yui-main .yui-b{margin-right:24.0769em;*margin-right:23.475em;}.yui-cssgrids .yui-main .yui-b{float:none;width:auto;}.yui-cssgrids .yui-gb .yui-u,.yui-cssgrids .yui-g .yui-gb .yui-u,.yui-cssgrids .yui-gb .yui-g,.yui-cssgrids .yui-gb .yui-gb,.yui-cssgrids .yui-gb .yui-gc,.yui-cssgrids .yui-gb .yui-gd,.yui-cssgrids .yui-gb .yui-ge,.yui-cssgrids .yui-gb .yui-gf,.yui-cssgrids .yui-gc .yui-u,.yui-cssgrids .yui-gc .yui-g,.yui-cssgrids .yui-gd .yui-u{float:left;}.yui-cssgrids .yui-g .yui-u,.yui-cssgrids .yui-g .yui-g,.yui-cssgrids .yui-g .yui-gb,.yui-cssgrids .yui-g .yui-gc,.yui-cssgrids .yui-g .yui-gd,.yui-cssgrids .yui-g .yui-ge,.yui-cssgrids .yui-g .yui-gf,.yui-cssgrids .yui-gc .yui-u,.yui-cssgrids .yui-gd .yui-g,.yui-cssgrids .yui-g .yui-gc .yui-u,.yui-cssgrids .yui-ge .yui-u,.yui-cssgrids .yui-ge .yui-g,.yui-cssgrids .yui-gf .yui-g,.yui-cssgrids .yui-gf .yui-u{float:right;}.yui-cssgrids .yui-g div.first,.yui-cssgrids .yui-gb div.first,.yui-cssgrids .yui-gc div.first,.yui-cssgrids .yui-gd div.first,.yui-cssgrids .yui-ge div.first,.yui-cssgrids .yui-gf div.first,.yui-cssgrids .yui-g .yui-gc div.first,.yui-cssgrids .yui-g .yui-ge div.first,.yui-cssgrids .yui-gc div.first div.first{float:left;}.yui-cssgrids .yui-g .yui-u,.yui-cssgrids .yui-g .yui-g,.yui-cssgrids .yui-g .yui-gb,.yui-cssgrids .yui-g .yui-gc,.yui-cssgrids .yui-g .yui-gd,.yui-cssgrids .yui-g .yui-ge,.yui-cssgrids .yui-g .yui-gf{width:49.1%;}.yui-cssgrids .yui-gb .yui-u,.yui-cssgrids .yui-g .yui-gb .yui-u,.yui-cssgrids .yui-gb .yui-g,.yui-cssgrids .yui-gb .yui-gb,.yui-cssgrids .yui-gb .yui-gc,.yui-cssgrids .yui-gb .yui-gd,.yui-cssgrids .yui-gb .yui-ge,.yui-cssgrids .yui-gb .yui-gf,.yui-cssgrids .yui-gc .yui-u,.yui-cssgrids .yui-gc .yui-g,.yui-cssgrids .yui-gd .yui-u{width:32%;margin-left:2.0%;}.yui-cssgrids .yui-gb .yui-u{*width:31.8%;*margin-left:1.9%;}.yui-cssgrids .yui-gc div.first,.yui-cssgrids .yui-gd .yui-u{width:66%;_width:65.7%;}.yui-cssgrids .yui-gd div.first{width:32%;_width:31.5%;}.yui-cssgrids .yui-ge div.first,.yui-cssgrids .yui-gf .yui-u{width:74.2%;_width:74%;}.yui-cssgrids .yui-ge .yui-u,.yui-cssgrids .yui-gf div.first{width:24%;_width:23.8%;}.yui-cssgrids .yui-g .yui-gb div.first,.yui-cssgrids .yui-gb div.first,.yui-cssgrids .yui-gc div.first,.yui-cssgrids .yui-gd div.first{margin-left:0;}.yui-cssgrids .yui-g .yui-g .yui-u,.yui-cssgrids .yui-gb .yui-g .yui-u,.yui-cssgrids .yui-gc .yui-g .yui-u,.yui-cssgrids .yui-gd .yui-g .yui-u,.yui-cssgrids .yui-ge .yui-g .yui-u,.yui-cssgrids .yui-gf .yui-g .yui-u{width:49%;*width:48.1%;*margin-left:0;}.yui-cssgrids .yui-g .yui-gb div.first,.yui-cssgrids .yui-gb .yui-gb div.first{*margin-right:0;*width:32%;_width:31.7%;}.yui-cssgrids .yui-g .yui-gc div.first,.yui-cssgrids .yui-gd .yui-g{width:66%;}.yui-cssgrids .yui-gb .yui-g div.first{*margin-right:4%;_margin-right:1.3%;}.yui-cssgrids .yui-gb .yui-gc div.first,.yui-cssgrids .yui-gb .yui-gd div.first{*margin-right:0;}.yui-cssgrids .yui-gb .yui-gb .yui-u,.yui-cssgrids .yui-gb .yui-gc .yui-u{*margin-left:1.8%;_margin-left:4%;}.yui-cssgrids .yui-g .yui-gb .yui-u{_margin-left:1.0%;}.yui-cssgrids .yui-gb .yui-gd .yui-u{*width:66%;_width:61.2%;}.yui-cssgrids .yui-gb .yui-gd div.first{*width:31%;_width:29.5%;}.yui-cssgrids .yui-g .yui-gc .yui-u,.yui-cssgrids .yui-gb .yui-gc .yui-u{width:32%;_float:right;margin-right:0;_margin-left:0;}.yui-cssgrids .yui-gb .yui-gc div.first{width:66%;*float:left;*margin-left:0;}.yui-cssgrids .yui-gb .yui-ge .yui-u,.yui-cssgrids .yui-gb .yui-gf .yui-u{margin:0;}.yui-cssgrids .yui-gb .yui-gb .yui-u{_margin-left:.7%;}.yui-cssgrids .yui-gb .yui-g div.first,.yui-cssgrids .yui-gb .yui-gb div.first{*margin-left:0;}.yui-cssgrids .yui-gc .yui-g .yui-u,.yui-cssgrids .yui-gd .yui-g .yui-u{*width:48.1%;*margin-left:0;}.yui-cssgrids .yui-gb .yui-gd div.first{width:32%;}.yui-cssgrids .yui-g .yui-gd div.first{_width:29.9%;}.yui-cssgrids .yui-ge .yui-g{width:24%;}.yui-cssgrids .yui-gf .yui-g{width:74.2%;}.yui-cssgrids .yui-gb .yui-ge div.yui-u,.yui-cssgrids .yui-gb .yui-gf div.yui-u{float:right;}.yui-cssgrids .yui-gb .yui-ge div.first,.yui-cssgrids .yui-gb .yui-gf div.first{float:left;}.yui-cssgrids .yui-gb .yui-ge .yui-u,.yui-cssgrids .yui-gb .yui-gf div.first{*width:24%;_width:20%;}.yui-cssgrids .yui-gc .yui-gf .yui-u{width:74%;_width:73%;}.yui-cssgrids .yui-gc .yui-gf div.first{width:24%;}.yui-cssgrids .yui-gb .yui-ge div.first,.yui-cssgrids .yui-gb .yui-gf .yui-u{*width:73.5%;_width:65.5%;}.yui-cssgrids .yui-ge div.first .yui-gd .yui-u{width:65%;}.yui-cssgrids .yui-ge div.first .yui-gd div.first{width:32%;}.yui-cssgrids #bd:after,.yui-cssgrids .yui-g:after,.yui-cssgrids .yui-gb:after,.yui-cssgrids .yui-gc:after,.yui-cssgrids .yui-gd:after,.yui-cssgrids .yui-ge:after,.yui-cssgrids .yui-gf:after,.yui-cssgrids .yui-t1:after,.yui-cssgrids .yui-t2:after,.yui-cssgrids .yui-t3:after,.yui-cssgrids .yui-t4:after,.yui-cssgrids .yui-t5:after,.yui-cssgrids .yui-t6:after{content:".";display:block;height:0;clear:both;visibility:hidden;}.yui-cssgrids #bd,.yui-cssgrids .yui-g,.yui-cssgrids .yui-gb,.yui-cssgrids .yui-gc,.yui-cssgrids .yui-gd,.yui-cssgrids .yui-ge,.yui-cssgrids .yui-gf,.yui-cssgrids .yui-t1,.yui-cssgrids .yui-t2,.yui-cssgrids .yui-t3,.yui-cssgrids .yui-t4,.yui-cssgrids .yui-t5,.yui-cssgrids .yui-t6{zoom:1;}
\ No newline at end of file
diff --git a/lib/yui/3.0.0/cssgrids/grids-context.css b/lib/yui/3.0.0/cssgrids/grids-context.css
new file mode 100644
index 0000000000..ae6725a85a
--- /dev/null
+++ b/lib/yui/3.0.0/cssgrids/grids-context.css
@@ -0,0 +1,491 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+/*
+*
+* The YUI CSS Foundation uses the *property and _property CSS filter
+* techniques to shield a value from A-grade browsers [1] other than
+* IE6 & IE7 (*property) and IE6 (_property)
+*
+/
+Section: General Rules
+*/
+.yui-cssgrids body {
+ /* center the page */
+ text-align: center;
+ margin-left: auto;
+ margin-right: auto;
+}
+/*
+Section: Page Width Rules (#doc, #doc2, #doc3, #doc4)
+*/
+/*
+Subsection: General
+*/
+.yui-cssgrids .yui-d0, /* 100% */
+.yui-cssgrids .yui-d1, /* 750px */
+.yui-cssgrids .yui-d1f, /* 750px fixed */
+.yui-cssgrids .yui-d2, /* 950px */
+.yui-cssgrids .yui-d2f, /* 950px fixed */
+.yui-cssgrids .yui-d3, /* 974px */
+.yui-cssgrids .yui-d3f { /* 974px fixed */
+ margin: auto;
+ text-align: left;
+ width: 57.69em;
+ *width: 56.25em; /* doc1*/
+}
+
+.yui-cssgrids .yui-t1,
+.yui-cssgrids .yui-t2,
+.yui-cssgrids .yui-t3,
+.yui-cssgrids .yui-t4,
+.yui-cssgrids .yui-t5,
+.yui-cssgrids .yui-t6 {
+ margin: auto;
+ text-align: left;
+ width: 100%;
+}
+
+/*
+Subsection: 100% (doc)
+*/
+.yui-cssgrids .yui-d0 {
+ /* Left and Right margins are not a structural part of Grids. Without them Grids
+ works fine, but content bleeds to the very edge of the document, which often
+ impairs readability and usability. They are
+ provided because they prevent the content from "bleeding" into the browser's chrome.*/
+ margin: auto 10px;
+ width: auto;
+}
+.yui-cssgrids .yui-d0f {
+ width: 100%;
+}
+
+/*
+Subsection: 950 Centered (doc2)
+*/
+.yui-cssgrids .yui-d2 {
+ width: 73.076em;
+ *width: 71.25em;
+}
+.yui-cssgrids .yui-d2f {
+ width: 950px;
+}
+/*
+Subsection: 974 Centered (doc3)
+*/
+.yui-cssgrids .yui-d3 {
+ width: 74.923em;
+ *width: 73.05em;
+}
+.yui-cssgrids .yui-d3f {
+ width: 974px;
+}
+/*
+Section: Preset Template Rules (.yui-t[1-6])
+*/
+/*
+Subsection: General
+*/
+
+/* to preserve source-order independence for Gecko without breaking IE */
+.yui-cssgrids .yui-b {
+ position: relative;
+}
+.yui-cssgrids .yui-b {
+ _position: static;
+}
+.yui-cssgrids .yui-main .yui-b {
+ position: static;
+}
+.yui-cssgrids .yui-main {
+ width: 100%;
+}
+.yui-cssgrids .yui-t1 .yui-main,
+.yui-cssgrids .yui-t2 .yui-main,
+.yui-cssgrids .yui-t3 .yui-main {
+ float: right;
+ /* IE: preserve layout at narrow widths */
+ margin-left: -25em;
+}
+.yui-cssgrids .yui-t4 .yui-main,
+.yui-cssgrids .yui-t5 .yui-main,
+.yui-cssgrids .yui-t6 .yui-main {
+ float: left;
+ /* IE: preserve layout at narrow widths */
+ margin-right: -25em;
+}
+
+/* Subsection: For Specific Template Presets */
+
+/**
+* Nudge down to get to 13px equivalent for these form elements
+*/
+
+/*
+TODO Create t1-6's that are based on fixed widths
+*/
+/* t1 narrow block = left, equivalent of 160px */
+.yui-cssgrids .yui-t1 .yui-b {
+ float: left;
+ width: 12.30769em;
+ *width: 12.00em;
+}
+.yui-cssgrids .yui-t1 .yui-main .yui-b {
+ margin-left: 13.30769em;
+ *margin-left:12.975em;
+}
+/* t2 narrow block = left, equivalent of 180px */
+.yui-cssgrids .yui-t2 .yui-b {
+ float: left;
+ width: 13.84615em;
+ *width: 13.50em;
+}
+.yui-cssgrids .yui-t2 .yui-main .yui-b {
+ margin-left: 14.84615em;
+ *margin-left: 14.475em;
+}
+/* t3 narrow block = left, equivalent of 300px */
+.yui-cssgrids .yui-t3 .yui-b {
+ float: left;
+ width: 23.0769em;
+ *width: 22.50em;
+}
+.yui-cssgrids .yui-t3 .yui-main .yui-b {
+ margin-left: 24.0769em;
+ *margin-left: 23.475em;
+}
+/* t4 narrow block = right, equivalent of 180px */
+.yui-cssgrids .yui-t4 .yui-b {
+ float: right;
+ width: 13.8456em;
+ *width: 13.50em;
+}
+.yui-cssgrids .yui-t4 .yui-main .yui-b {
+ margin-right: 14.8456em;
+ *margin-right: 14.475em;
+}
+/* t5 narrow block = right, equivalent of 240px */
+.yui-cssgrids .yui-t5 .yui-b {
+ float: right;
+ width: 18.4615em;
+ *width: 18.00em;
+}
+.yui-cssgrids .yui-t5 .yui-main .yui-b {
+ margin-right: 19.4615em;
+ *margin-right: 18.975em;
+}
+/* t6 narrow block = equivalent of 300px */
+.yui-cssgrids .yui-t6 .yui-b {
+ float: right;
+ width: 23.0769em;
+ *width: 22.50em;
+}
+.yui-cssgrids .yui-t6 .yui-main .yui-b {
+ margin-right: 24.0769em;
+ *margin-right: 23.475em;
+}
+
+.yui-cssgrids .yui-main .yui-b {
+ float: none;
+ width: auto;
+}
+
+/*
+Section: Grids and Nesting Grids
+*/
+
+/*
+Subsection: Children generally take half the available space
+*/
+
+.yui-cssgrids .yui-gb .yui-u,
+.yui-cssgrids .yui-g .yui-gb .yui-u,
+.yui-cssgrids .yui-gb .yui-g,
+.yui-cssgrids .yui-gb .yui-gb,
+.yui-cssgrids .yui-gb .yui-gc,
+.yui-cssgrids .yui-gb .yui-gd,
+.yui-cssgrids .yui-gb .yui-ge,
+.yui-cssgrids .yui-gb .yui-gf,
+.yui-cssgrids .yui-gc .yui-u,
+.yui-cssgrids .yui-gc .yui-g,
+.yui-cssgrids .yui-gd .yui-u {
+ float: left;
+}
+
+/*Float units (and sub grids) to the right */
+.yui-cssgrids .yui-g .yui-u,
+.yui-cssgrids .yui-g .yui-g,
+.yui-cssgrids .yui-g .yui-gb,
+.yui-cssgrids .yui-g .yui-gc,
+.yui-cssgrids .yui-g .yui-gd,
+.yui-cssgrids .yui-g .yui-ge,
+.yui-cssgrids .yui-g .yui-gf,
+.yui-cssgrids .yui-gc .yui-u,
+.yui-cssgrids .yui-gd .yui-g,
+.yui-cssgrids .yui-g .yui-gc .yui-u,
+.yui-cssgrids .yui-ge .yui-u,
+.yui-cssgrids .yui-ge .yui-g,
+.yui-cssgrids .yui-gf .yui-g,
+.yui-cssgrids .yui-gf .yui-u {
+ float: right;
+}
+
+/*Float units (and sub grids) to the left */
+.yui-cssgrids .yui-g div.first,
+.yui-cssgrids .yui-gb div.first,
+.yui-cssgrids .yui-gc div.first,
+.yui-cssgrids .yui-gd div.first,
+.yui-cssgrids .yui-ge div.first,
+.yui-cssgrids .yui-gf div.first,
+.yui-cssgrids .yui-g .yui-gc div.first,
+.yui-cssgrids .yui-g .yui-ge div.first,
+.yui-cssgrids .yui-gc div.first div.first {
+ float: left;
+}
+
+.yui-cssgrids .yui-g .yui-u,
+.yui-cssgrids .yui-g .yui-g,
+.yui-cssgrids .yui-g .yui-gb,
+.yui-cssgrids .yui-g .yui-gc,
+.yui-cssgrids .yui-g .yui-gd,
+.yui-cssgrids .yui-g .yui-ge,
+.yui-cssgrids .yui-g .yui-gf {
+ width: 49.1%;
+}
+
+.yui-cssgrids .yui-gb .yui-u,
+.yui-cssgrids .yui-g .yui-gb .yui-u,
+.yui-cssgrids .yui-gb .yui-g,
+.yui-cssgrids .yui-gb .yui-gb,
+.yui-cssgrids .yui-gb .yui-gc,
+.yui-cssgrids .yui-gb .yui-gd,
+.yui-cssgrids .yui-gb .yui-ge,
+.yui-cssgrids .yui-gb .yui-gf,
+.yui-cssgrids .yui-gc .yui-u,
+.yui-cssgrids .yui-gc .yui-g,
+.yui-cssgrids .yui-gd .yui-u {
+ width: 32%;
+ margin-left: 2.0%;
+}
+
+/* Give IE some extra breathing room for 1/3-based rounding issues */
+.yui-cssgrids .yui-gb .yui-u {
+ *width: 31.8%;
+ *margin-left: 1.9%;
+}
+
+.yui-cssgrids .yui-gc div.first,
+.yui-cssgrids .yui-gd .yui-u {
+ width: 66%;
+ _width: 65.7%;
+}
+.yui-cssgrids .yui-gd div.first {
+ width: 32%;
+ _width: 31.5%;
+}
+
+.yui-cssgrids .yui-ge div.first,
+.yui-cssgrids .yui-gf .yui-u {
+ width: 74.2%;
+ _width: 74%;
+}
+
+.yui-cssgrids .yui-ge .yui-u,
+.yui-cssgrids .yui-gf div.first {
+ width: 24%;
+ _width: 23.8%;
+}
+
+.yui-cssgrids .yui-g .yui-gb div.first,
+.yui-cssgrids .yui-gb div.first,
+.yui-cssgrids .yui-gc div.first,
+.yui-cssgrids .yui-gd div.first {
+ margin-left: 0;
+}
+
+/*
+Section: Deep Nesting
+*/
+.yui-cssgrids .yui-g .yui-g .yui-u,
+.yui-cssgrids .yui-gb .yui-g .yui-u,
+.yui-cssgrids .yui-gc .yui-g .yui-u,
+.yui-cssgrids .yui-gd .yui-g .yui-u,
+.yui-cssgrids .yui-ge .yui-g .yui-u,
+.yui-cssgrids .yui-gf .yui-g .yui-u {
+ width: 49%;
+ *width: 48.1%;
+ *margin-left: 0;
+}
+
+.yui-cssgrids .yui-g .yui-gb div.first,
+.yui-cssgrids .yui-gb .yui-gb div.first {
+ *margin-right: 0;
+ *width: 32%;
+ _width: 31.7%;
+}
+
+.yui-cssgrids .yui-g .yui-gc div.first,
+.yui-cssgrids .yui-gd .yui-g {
+ width: 66%;
+}
+
+.yui-cssgrids .yui-gb .yui-g div.first {
+ *margin-right: 4%;
+ _margin-right: 1.3%;
+}
+
+.yui-cssgrids .yui-gb .yui-gc div.first,
+.yui-cssgrids .yui-gb .yui-gd div.first {
+ *margin-right: 0;
+}
+
+.yui-cssgrids .yui-gb .yui-gb .yui-u,
+.yui-cssgrids .yui-gb .yui-gc .yui-u {
+ *margin-left: 1.8%;
+ _margin-left: 4%;
+}
+
+.yui-cssgrids .yui-g .yui-gb .yui-u {
+ _margin-left: 1.0%;
+}
+
+.yui-cssgrids .yui-gb .yui-gd .yui-u {
+ *width: 66%;
+ _width: 61.2%;
+}
+.yui-cssgrids .yui-gb .yui-gd div.first {
+ *width: 31%;
+ _width: 29.5%;
+}
+
+.yui-cssgrids .yui-g .yui-gc .yui-u,
+.yui-cssgrids .yui-gb .yui-gc .yui-u {
+ width: 32%;
+ _float: right;
+ margin-right: 0;
+ _margin-left: 0;
+}
+.yui-cssgrids .yui-gb .yui-gc div.first {
+ width: 66%;
+ *float: left;
+ *margin-left: 0;
+}
+
+.yui-cssgrids .yui-gb .yui-ge .yui-u,
+.yui-cssgrids .yui-gb .yui-gf .yui-u {
+ margin: 0;
+}
+
+.yui-cssgrids .yui-gb .yui-gb .yui-u {
+ _margin-left: .7%;
+}
+
+.yui-cssgrids .yui-gb .yui-g div.first,
+.yui-cssgrids .yui-gb .yui-gb div.first {
+ *margin-left:0;
+}
+
+.yui-cssgrids .yui-gc .yui-g .yui-u,
+.yui-cssgrids .yui-gd .yui-g .yui-u {
+ *width: 48.1%;
+ *margin-left: 0;
+}
+
+.yui-cssgrids .yui-gb .yui-gd div.first {
+ width: 32%;
+}
+.yui-cssgrids .yui-g .yui-gd div.first {
+ _width: 29.9%;
+}
+
+.yui-cssgrids .yui-ge .yui-g {
+ width: 24%;
+}
+.yui-cssgrids .yui-gf .yui-g {
+ width: 74.2%;
+}
+
+.yui-cssgrids .yui-gb .yui-ge div.yui-u,
+.yui-cssgrids .yui-gb .yui-gf div.yui-u {
+ float: right;
+}
+.yui-cssgrids .yui-gb .yui-ge div.first,
+.yui-cssgrids .yui-gb .yui-gf div.first {
+ float: left;
+}
+
+/* Width Accommodation for Nested Contexts */
+.yui-cssgrids .yui-gb .yui-ge .yui-u,
+.yui-cssgrids .yui-gb .yui-gf div.first {
+ *width: 24%;
+ _width: 20%;
+}
+
+/* Width Accommodation for Nested Contexts */
+
+.yui-cssgrids .yui-gc .yui-gf .yui-u {
+ width: 74%;
+ _width: 73%;
+}
+
+.yui-cssgrids .yui-gc .yui-gf div.first {
+ width: 24%;
+}
+
+.yui-cssgrids .yui-gb .yui-ge div.first,
+.yui-cssgrids .yui-gb .yui-gf .yui-u {
+ *width: 73.5%;
+ _width: 65.5%;
+}
+
+/* Patch for GD within GE */
+.yui-cssgrids .yui-ge div.first .yui-gd .yui-u {
+ width: 65%;
+}
+.yui-cssgrids .yui-ge div.first .yui-gd div.first {
+ width: 32%;
+}
+
+/*
+Section: Clearing. zoom for IE, :after for others
+*/
+
+.yui-cssgrids #bd:after,
+.yui-cssgrids .yui-g:after,
+.yui-cssgrids .yui-gb:after,
+.yui-cssgrids .yui-gc:after,
+.yui-cssgrids .yui-gd:after,
+.yui-cssgrids .yui-ge:after,
+.yui-cssgrids .yui-gf:after,
+.yui-cssgrids .yui-t1:after,
+.yui-cssgrids .yui-t2:after,
+.yui-cssgrids .yui-t3:after,
+.yui-cssgrids .yui-t4:after,
+.yui-cssgrids .yui-t5:after,
+.yui-cssgrids .yui-t6:after {
+ content: ".";
+ display: block;
+ height: 0;
+ clear: both;
+ visibility: hidden;
+}
+.yui-cssgrids #bd,
+.yui-cssgrids .yui-g,
+.yui-cssgrids .yui-gb,
+.yui-cssgrids .yui-gc,
+.yui-cssgrids .yui-gd,
+.yui-cssgrids .yui-ge,
+.yui-cssgrids .yui-gf,
+.yui-cssgrids .yui-t1,
+.yui-cssgrids .yui-t2,
+.yui-cssgrids .yui-t3,
+.yui-cssgrids .yui-t4,
+.yui-cssgrids .yui-t5,
+.yui-cssgrids .yui-t6 {
+ zoom: 1;
+}
\ No newline at end of file
diff --git a/lib/yui/3.0.0/cssgrids/grids-min.css b/lib/yui/3.0.0/cssgrids/grids-min.css
new file mode 100644
index 0000000000..f614a63552
--- /dev/null
+++ b/lib/yui/3.0.0/cssgrids/grids-min.css
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+body{text-align:center;margin-left:auto;margin-right:auto;}.yui-d0,.yui-d1,.yui-d1f,.yui-d2,.yui-d2f,.yui-d3,.yui-d3f{margin:auto;text-align:left;width:57.69em;*width:56.25em;}.yui-t1,.yui-t2,.yui-t3,.yui-t4,.yui-t5,.yui-t6{margin:auto;text-align:left;width:100%;}.yui-d0{margin:auto 10px;width:auto;}.yui-d0f{width:100%;}.yui-d2{width:73.076em;*width:71.25em;}.yui-d2f{width:950px;}.yui-d3{width:74.923em;*width:73.05em;}.yui-d3f{width:974px;}.yui-b{position:relative;}.yui-b{_position:static;}.yui-main .yui-b{position:static;}.yui-main{width:100%;}.yui-t1 .yui-main,.yui-t2 .yui-main,.yui-t3 .yui-main{float:right;margin-left:-25em;}.yui-t4 .yui-main,.yui-t5 .yui-main,.yui-t6 .yui-main{float:left;margin-right:-25em;}.yui-t1 .yui-b{float:left;width:12.30769em;*width:12.00em;}.yui-t1 .yui-main .yui-b{margin-left:13.30769em;*margin-left:12.975em;}.yui-t2 .yui-b{float:left;width:13.84615em;*width:13.50em;}.yui-t2 .yui-main .yui-b{margin-left:14.84615em;*margin-left:14.475em;}.yui-t3 .yui-b{float:left;width:23.0769em;*width:22.50em;}.yui-t3 .yui-main .yui-b{margin-left:24.0769em;*margin-left:23.475em;}.yui-t4 .yui-b{float:right;width:13.8456em;*width:13.50em;}.yui-t4 .yui-main .yui-b{margin-right:14.8456em;*margin-right:14.475em;}.yui-t5 .yui-b{float:right;width:18.4615em;*width:18.00em;}.yui-t5 .yui-main .yui-b{margin-right:19.4615em;*margin-right:18.975em;}.yui-t6 .yui-b{float:right;width:23.0769em;*width:22.50em;}.yui-t6 .yui-main .yui-b{margin-right:24.0769em;*margin-right:23.475em;}.yui-main .yui-b{float:none;width:auto;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf,.yui-gc .yui-u,.yui-gd .yui-g,.yui-g .yui-gc .yui-u,.yui-ge .yui-u,.yui-ge .yui-g,.yui-gf .yui-g,.yui-gf .yui-u{float:right;}.yui-g div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first,.yui-ge div.first,.yui-gf div.first,.yui-g .yui-gc div.first,.yui-g .yui-ge div.first,.yui-gc div.first div.first{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf{width:49.1%;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{width:32%;margin-left:2.0%;}.yui-gb .yui-u{*width:31.8%;*margin-left:1.9%;}.yui-gc div.first,.yui-gd .yui-u{width:66%;_width:65.7%;}.yui-gd div.first{width:32%;_width:31.5%;}.yui-ge div.first,.yui-gf .yui-u{width:74.2%;_width:74%;}.yui-ge .yui-u,.yui-gf div.first{width:24%;_width:23.8%;}.yui-g .yui-gb div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first{margin-left:0;}.yui-g .yui-g .yui-u,.yui-gb .yui-g .yui-u,.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u,.yui-ge .yui-g .yui-u,.yui-gf .yui-g .yui-u{width:49%;*width:48.1%;*margin-left:0;}.yui-g .yui-gb div.first,.yui-gb .yui-gb div.first{*margin-right:0;*width:32%;_width:31.7%;}.yui-g .yui-gc div.first,.yui-gd .yui-g{width:66%;}.yui-gb .yui-g div.first{*margin-right:4%;_margin-right:1.3%;}.yui-gb .yui-gc div.first,.yui-gb .yui-gd div.first{*margin-right:0;}.yui-gb .yui-gb .yui-u,.yui-gb .yui-gc .yui-u{*margin-left:1.8%;_margin-left:4%;}.yui-g .yui-gb .yui-u{_margin-left:1.0%;}.yui-gb .yui-gd .yui-u{*width:66%;_width:61.2%;}.yui-gb .yui-gd div.first{*width:31%;_width:29.5%;}.yui-g .yui-gc .yui-u,.yui-gb .yui-gc .yui-u{width:32%;_float:right;margin-right:0;_margin-left:0;}.yui-gb .yui-gc div.first{width:66%;*float:left;*margin-left:0;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf .yui-u{margin:0;}.yui-gb .yui-gb .yui-u{_margin-left:.7%;}.yui-gb .yui-g div.first,.yui-gb .yui-gb div.first{*margin-left:0;}.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u{*width:48.1%;*margin-left:0;}.yui-gb .yui-gd div.first{width:32%;}.yui-g .yui-gd div.first{_width:29.9%;}.yui-ge .yui-g{width:24%;}.yui-gf .yui-g{width:74.2%;}.yui-gb .yui-ge div.yui-u,.yui-gb .yui-gf div.yui-u{float:right;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf div.first{float:left;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf div.first{*width:24%;_width:20%;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf .yui-u{*width:73.5%;_width:65.5%;}.yui-ge div.first .yui-gd .yui-u{width:65%;}.yui-ge div.first .yui-gd div.first{width:32%;}#bd:after,.yui-g:after,.yui-gb:after,.yui-gc:after,.yui-gd:after,.yui-ge:after,.yui-gf:after,.yui-t1:after,.yui-t2:after,.yui-t3:after,.yui-t4:after,.yui-t5:after,.yui-t6:after{content:".";display:block;height:0;clear:both;visibility:hidden;}#bd,.yui-g,.yui-gb,.yui-gc,.yui-gd,.yui-ge,.yui-gf,.yui-t1,.yui-t2,.yui-t3,.yui-t4,.yui-t5,.yui-t6{zoom:1;}
\ No newline at end of file
diff --git a/lib/yui/3.0.0/cssgrids/grids.css b/lib/yui/3.0.0/cssgrids/grids.css
new file mode 100644
index 0000000000..584394b026
--- /dev/null
+++ b/lib/yui/3.0.0/cssgrids/grids.css
@@ -0,0 +1,481 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+/*
+*
+* The YUI CSS Foundation uses the *property and _property CSS filter
+* techniques to shield a value from A-grade browsers [1] other than
+* IE6 & IE7 (*property) and IE6 (_property)
+*
+/
+Section: General Rules
+*/
+body {
+ /* center the page */
+ text-align: center;
+ margin-left: auto;
+ margin-right: auto;
+}
+/*
+Section: Page Width Rules (#doc, #doc2, #doc3, #doc4)
+*/
+/*
+Subsection: General
+*/
+.yui-d0, /* 100% */
+.yui-d1, /* 750px */
+.yui-d1f, /* 750px fixed */
+.yui-d2, /* 950px */
+.yui-d2f, /* 950px fixed */
+.yui-d3, /* 974px */
+.yui-d3f { /* 974px fixed */
+ margin: auto;
+ text-align: left;
+ width: 57.69em;
+ *width: 56.25em; /* doc1*/
+}
+
+.yui-t1,
+.yui-t2,
+.yui-t3,
+.yui-t4,
+.yui-t5,
+.yui-t6 {
+ margin: auto;
+ text-align: left;
+ width: 100%;
+}
+
+/*
+Subsection: 100% (doc)
+*/
+.yui-d0 {
+ /* Left and Right margins are not a structural part of Grids. Without them Grids
+ works fine, but content bleeds to the very edge of the document, which often
+ impairs readability and usability. They are
+ provided because they prevent the content from "bleeding" into the browser's chrome.*/
+ margin: auto 10px;
+ width: auto;
+}
+.yui-d0f {
+ width: 100%;
+}
+
+/*
+Subsection: 950 Centered (doc2)
+*/
+.yui-d2 {
+ width: 73.076em;
+ *width: 71.25em;
+}
+.yui-d2f {
+ width: 950px;
+}
+/*
+Subsection: 974 Centered (doc3)
+*/
+.yui-d3 {
+ width: 74.923em;
+ *width: 73.05em;
+}
+.yui-d3f {
+ width: 974px;
+}
+/*
+Section: Preset Template Rules (.yui-t[1-6])
+*/
+/*
+Subsection: General
+*/
+
+/* to preserve source-order independence for Gecko without breaking IE */
+.yui-b {
+ position: relative;
+}
+.yui-b {
+ _position: static;
+}
+.yui-main .yui-b {
+ position: static;
+}
+.yui-main {
+ width: 100%;
+}
+.yui-t1 .yui-main,
+.yui-t2 .yui-main,
+.yui-t3 .yui-main {
+ float: right;
+ /* IE: preserve layout at narrow widths */
+ margin-left: -25em;
+}
+.yui-t4 .yui-main,
+.yui-t5 .yui-main,
+.yui-t6 .yui-main {
+ float: left;
+ /* IE: preserve layout at narrow widths */
+ margin-right: -25em;
+}
+
+/* Subsection: For Specific Template Presets */
+
+/**
+* Nudge down to get to 13px equivalent for these form elements
+*/
+
+/*
+TODO Create t1-6's that are based on fixed widths
+*/
+/* t1 narrow block = left, equivalent of 160px */
+.yui-t1 .yui-b {
+ float: left;
+ width: 12.30769em;
+ *width: 12.00em;
+}
+.yui-t1 .yui-main .yui-b {
+ margin-left: 13.30769em;
+ *margin-left:12.975em;
+}
+/* t2 narrow block = left, equivalent of 180px */
+.yui-t2 .yui-b {
+ float: left;
+ width: 13.84615em;
+ *width: 13.50em;
+}
+.yui-t2 .yui-main .yui-b {
+ margin-left: 14.84615em;
+ *margin-left: 14.475em;
+}
+/* t3 narrow block = left, equivalent of 300px */
+.yui-t3 .yui-b {
+ float: left;
+ width: 23.0769em;
+ *width: 22.50em;
+}
+.yui-t3 .yui-main .yui-b {
+ margin-left: 24.0769em;
+ *margin-left: 23.475em;
+}
+/* t4 narrow block = right, equivalent of 180px */
+.yui-t4 .yui-b {
+ float: right;
+ width: 13.8456em;
+ *width: 13.50em;
+}
+.yui-t4 .yui-main .yui-b {
+ margin-right: 14.8456em;
+ *margin-right: 14.475em;
+}
+/* t5 narrow block = right, equivalent of 240px */
+.yui-t5 .yui-b {
+ float: right;
+ width: 18.4615em;
+ *width: 18.00em;
+}
+.yui-t5 .yui-main .yui-b {
+ margin-right: 19.4615em;
+ *margin-right: 18.975em;
+}
+/* t6 narrow block = equivalent of 300px */
+.yui-t6 .yui-b {
+ float: right;
+ width: 23.0769em;
+ *width: 22.50em;
+}
+.yui-t6 .yui-main .yui-b {
+ margin-right: 24.0769em;
+ *margin-right: 23.475em;
+}
+
+.yui-main .yui-b {
+ float: none;
+ width: auto;
+}
+
+/*
+Section: Grids and Nesting Grids
+*/
+
+/*
+Subsection: Children generally take half the available space
+*/
+
+.yui-gb .yui-u,
+.yui-g .yui-gb .yui-u,
+.yui-gb .yui-g,
+.yui-gb .yui-gb,
+.yui-gb .yui-gc,
+.yui-gb .yui-gd,
+.yui-gb .yui-ge,
+.yui-gb .yui-gf,
+.yui-gc .yui-u,
+.yui-gc .yui-g,
+.yui-gd .yui-u {
+ float: left;
+}
+
+/*Float units (and sub grids) to the right */
+.yui-g .yui-u,
+.yui-g .yui-g,
+.yui-g .yui-gb,
+.yui-g .yui-gc,
+.yui-g .yui-gd,
+.yui-g .yui-ge,
+.yui-g .yui-gf,
+.yui-gc .yui-u,
+.yui-gd .yui-g,
+.yui-g .yui-gc .yui-u,
+.yui-ge .yui-u,
+.yui-ge .yui-g,
+.yui-gf .yui-g,
+.yui-gf .yui-u {
+ float: right;
+}
+
+/*Float units (and sub grids) to the left */
+.yui-g div.first,
+.yui-gb div.first,
+.yui-gc div.first,
+.yui-gd div.first,
+.yui-ge div.first,
+.yui-gf div.first,
+.yui-g .yui-gc div.first,
+.yui-g .yui-ge div.first,
+.yui-gc div.first div.first {
+ float: left;
+}
+
+.yui-g .yui-u,
+.yui-g .yui-g,
+.yui-g .yui-gb,
+.yui-g .yui-gc,
+.yui-g .yui-gd,
+.yui-g .yui-ge,
+.yui-g .yui-gf {
+ width: 49.1%;
+}
+
+.yui-gb .yui-u,
+.yui-g .yui-gb .yui-u,
+.yui-gb .yui-g,
+.yui-gb .yui-gb,
+.yui-gb .yui-gc,
+.yui-gb .yui-gd,
+.yui-gb .yui-ge,
+.yui-gb .yui-gf,
+.yui-gc .yui-u,
+.yui-gc .yui-g,
+.yui-gd .yui-u {
+ width: 32%;
+ margin-left: 2.0%;
+}
+
+/* Give IE some extra breathing room for 1/3-based rounding issues */
+.yui-gb .yui-u {
+ *width: 31.8%;
+ *margin-left: 1.9%;
+}
+
+.yui-gc div.first,
+.yui-gd .yui-u {
+ width: 66%;
+ _width: 65.7%;
+}
+.yui-gd div.first {
+ width: 32%;
+ _width: 31.5%;
+}
+
+.yui-ge div.first,
+.yui-gf .yui-u {
+ width: 74.2%;
+ _width: 74%;
+}
+
+.yui-ge .yui-u,
+.yui-gf div.first {
+ width: 24%;
+ _width: 23.8%;
+}
+
+.yui-g .yui-gb div.first,
+.yui-gb div.first,
+.yui-gc div.first,
+.yui-gd div.first {
+ margin-left: 0;
+}
+
+/*
+Section: Deep Nesting
+*/
+.yui-g .yui-g .yui-u,
+.yui-gb .yui-g .yui-u,
+.yui-gc .yui-g .yui-u,
+.yui-gd .yui-g .yui-u,
+.yui-ge .yui-g .yui-u,
+.yui-gf .yui-g .yui-u {
+ width: 49%;
+ *width: 48.1%;
+ *margin-left: 0;
+}
+
+.yui-g .yui-gb div.first,
+.yui-gb .yui-gb div.first {
+ *margin-right: 0;
+ *width: 32%;
+ _width: 31.7%;
+}
+
+.yui-g .yui-gc div.first,
+.yui-gd .yui-g {
+ width: 66%;
+}
+
+.yui-gb .yui-g div.first {
+ *margin-right: 4%;
+ _margin-right: 1.3%;
+}
+
+.yui-gb .yui-gc div.first,
+.yui-gb .yui-gd div.first {
+ *margin-right: 0;
+}
+
+.yui-gb .yui-gb .yui-u,
+.yui-gb .yui-gc .yui-u {
+ *margin-left: 1.8%;
+ _margin-left: 4%;
+}
+
+.yui-g .yui-gb .yui-u {
+ _margin-left: 1.0%;
+}
+
+.yui-gb .yui-gd .yui-u {
+ *width: 66%;
+ _width: 61.2%;
+}
+.yui-gb .yui-gd div.first {
+ *width: 31%;
+ _width: 29.5%;
+}
+
+.yui-g .yui-gc .yui-u,
+.yui-gb .yui-gc .yui-u {
+ width: 32%;
+ _float: right;
+ margin-right: 0;
+ _margin-left: 0;
+}
+.yui-gb .yui-gc div.first {
+ width: 66%;
+ *float: left;
+ *margin-left: 0;
+}
+
+.yui-gb .yui-ge .yui-u,
+.yui-gb .yui-gf .yui-u {
+ margin: 0;
+}
+
+.yui-gb .yui-gb .yui-u {
+ _margin-left: .7%;
+}
+
+.yui-gb .yui-g div.first,
+.yui-gb .yui-gb div.first {
+ *margin-left:0;
+}
+
+.yui-gc .yui-g .yui-u,
+.yui-gd .yui-g .yui-u {
+ *width: 48.1%;
+ *margin-left: 0;
+}
+
+.yui-gb .yui-gd div.first {
+ width: 32%;
+}
+.yui-g .yui-gd div.first {
+ _width: 29.9%;
+}
+
+.yui-ge .yui-g {
+ width: 24%;
+}
+.yui-gf .yui-g {
+ width: 74.2%;
+}
+
+.yui-gb .yui-ge div.yui-u,
+.yui-gb .yui-gf div.yui-u {
+ float: right;
+}
+.yui-gb .yui-ge div.first,
+.yui-gb .yui-gf div.first {
+ float: left;
+}
+
+/* Width Accommodation for Nested Contexts */
+.yui-gb .yui-ge .yui-u,
+.yui-gb .yui-gf div.first {
+ *width: 24%;
+ _width: 20%;
+}
+
+/* Width Accommodation for Nested Contexts */
+.yui-gb .yui-ge div.first,
+.yui-gb .yui-gf .yui-u {
+ *width: 73.5%;
+ _width: 65.5%;
+}
+
+/* Patch for GD within GE */
+.yui-ge div.first .yui-gd .yui-u {
+ width: 65%;
+}
+.yui-ge div.first .yui-gd div.first {
+ width: 32%;
+}
+
+/*
+Section: Clearing. zoom for IE, :after for others
+*/
+
+#bd:after,
+.yui-g:after,
+.yui-gb:after,
+.yui-gc:after,
+.yui-gd:after,
+.yui-ge:after,
+.yui-gf:after,
+.yui-t1:after,
+.yui-t2:after,
+.yui-t3:after,
+.yui-t4:after,
+.yui-t5:after,
+.yui-t6:after {
+ content: ".";
+ display: block;
+ height: 0;
+ clear: both;
+ visibility: hidden;
+}
+#bd,
+.yui-g,
+.yui-gb,
+.yui-gc,
+.yui-gd,
+.yui-ge,
+.yui-gf,
+.yui-t1,
+.yui-t2,
+.yui-t3,
+.yui-t4,
+.yui-t5,
+.yui-t6 {
+ zoom: 1;
+}
\ No newline at end of file
diff --git a/lib/yui/3.0.0/cssreset/reset-context-min.css b/lib/yui/3.0.0/cssreset/reset-context-min.css
new file mode 100644
index 0000000000..fdc4dbf230
--- /dev/null
+++ b/lib/yui/3.0.0/cssreset/reset-context-min.css
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+.yui-cssreset html{color:#000;background:#FFF;}.yui-cssreset body,.yui-cssreset div,.yui-cssreset dl,.yui-cssreset dt,.yui-cssreset dd,.yui-cssreset ul,.yui-cssreset ol,.yui-cssreset li,.yui-cssreset h1,.yui-cssreset h2,.yui-cssreset h3,.yui-cssreset h4,.yui-cssreset h5,.yui-cssreset h6,.yui-cssreset pre,.yui-cssreset code,.yui-cssreset form,.yui-cssreset fieldset,.yui-cssreset legend,.yui-cssreset input,.yui-cssreset textarea,.yui-cssreset p,.yui-cssreset blockquote,.yui-cssreset th,.yui-cssreset td{margin:0;padding:0;}.yui-cssreset table{border-collapse:collapse;border-spacing:0;}.yui-cssreset fieldset,.yui-cssreset img{border:0;}.yui-cssreset address,.yui-cssreset caption,.yui-cssreset cite,.yui-cssreset code,.yui-cssreset dfn,.yui-cssreset em,.yui-cssreset strong,.yui-cssreset th,.yui-cssreset var{font-style:normal;font-weight:normal;}.yui-cssreset li{list-style:none;}.yui-cssreset caption,.yui-cssreset th{text-align:left;}.yui-cssreset h1,.yui-cssreset h2,.yui-cssreset h3,.yui-cssreset h4,.yui-cssreset h5,.yui-cssreset h6{font-size:100%;font-weight:normal;}.yui-cssreset q:before,.yui-cssreset q:after{content:'';}.yui-cssreset abbr,.yui-cssreset acronym{border:0;font-variant:normal;}.yui-cssreset sup{vertical-align:text-top;}.yui-cssreset sub{vertical-align:text-bottom;}.yui-cssreset input,.yui-cssreset textarea,.yui-cssreset select{font-family:inherit;font-size:inherit;font-weight:inherit;}.yui-cssreset input,.yui-cssreset textarea,.yui-cssreset select{*font-size:100%;}.yui-cssreset legend{color:#000;}
\ No newline at end of file
diff --git a/lib/yui/3.0.0/cssreset/reset-context.css b/lib/yui/3.0.0/cssreset/reset-context.css
new file mode 100644
index 0000000000..6233f21fc2
--- /dev/null
+++ b/lib/yui/3.0.0/cssreset/reset-context.css
@@ -0,0 +1,126 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+/*e
+ TODO will need to remove settings on HTML since we can't namespace it.
+ TODO with the prefix, should I group by selector or property for weight savings?
+*/
+.yui-cssreset html{
+ color:#000;
+ background:#FFF;
+}
+/*
+ TODO remove settings on BODY since we can't namespace it.
+*/
+/*
+ TODO test putting a class on HEAD.
+ - Fails on FF.
+*/
+.yui-cssreset body,
+.yui-cssreset div,
+.yui-cssreset dl,
+.yui-cssreset dt,
+.yui-cssreset dd,
+.yui-cssreset ul,
+.yui-cssreset ol,
+.yui-cssreset li,
+.yui-cssreset h1,
+.yui-cssreset h2,
+.yui-cssreset h3,
+.yui-cssreset h4,
+.yui-cssreset h5,
+.yui-cssreset h6,
+.yui-cssreset pre,
+.yui-cssreset code,
+.yui-cssreset form,
+.yui-cssreset fieldset,
+.yui-cssreset legend,
+.yui-cssreset input,
+.yui-cssreset textarea,
+.yui-cssreset p,
+.yui-cssreset blockquote,
+.yui-cssreset th,
+.yui-cssreset td {
+ margin:0;
+ padding:0;
+}
+.yui-cssreset table {
+ border-collapse:collapse;
+ border-spacing:0;
+}
+.yui-cssreset fieldset,
+.yui-cssreset img {
+ border:0;
+}
+/*
+ TODO think about hanlding inheritence differently, maybe letting IE6 fail a bit...
+*/
+.yui-cssreset address,
+.yui-cssreset caption,
+.yui-cssreset cite,
+.yui-cssreset code,
+.yui-cssreset dfn,
+.yui-cssreset em,
+.yui-cssreset strong,
+.yui-cssreset th,
+.yui-cssreset var {
+ font-style:normal;
+ font-weight:normal;
+}
+/*
+ TODO Figure out where this list-style rule is best set. Hedger has a request to investigate.
+*/
+.yui-cssreset li {
+ list-style:none;
+}
+
+.yui-cssreset caption,
+.yui-cssreset th {
+ text-align:left;
+}
+.yui-cssreset h1,
+.yui-cssreset h2,
+.yui-cssreset h3,
+.yui-cssreset h4,
+.yui-cssreset h5,
+.yui-cssreset h6 {
+ font-size:100%;
+ font-weight:normal;
+}
+.yui-cssreset q:before,
+.yui-cssreset q:after {
+ content:'';
+}
+.yui-cssreset abbr,
+.yui-cssreset acronym {
+ border:0;
+ font-variant:normal;
+}
+/* to preserve line-height and selector appearance */
+.yui-cssreset sup {
+ vertical-align:text-top;
+}
+.yui-cssreset sub {
+ vertical-align:text-bottom;
+}
+.yui-cssreset input,
+.yui-cssreset textarea,
+.yui-cssreset select {
+ font-family:inherit;
+ font-size:inherit;
+ font-weight:inherit;
+}
+/*to enable resizing for IE*/
+.yui-cssreset input,
+.yui-cssreset textarea,
+.yui-cssreset select {
+ *font-size:100%;
+}
+/*because legend doesn't inherit in IE */
+.yui-cssreset legend {
+ color:#000;
+}
\ No newline at end of file
diff --git a/lib/yui/3.0.0/cssreset/reset-min.css b/lib/yui/3.0.0/cssreset/reset-min.css
new file mode 100644
index 0000000000..fb264a0c5a
--- /dev/null
+++ b/lib/yui/3.0.0/cssreset/reset-min.css
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:text-top;}sub{vertical-align:text-bottom;}input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit;}input,textarea,select{*font-size:100%;}legend{color:#000;}
\ No newline at end of file
diff --git a/lib/yui/3.0.0/cssreset/reset.css b/lib/yui/3.0.0/cssreset/reset.css
new file mode 100644
index 0000000000..ccc5479eac
--- /dev/null
+++ b/lib/yui/3.0.0/cssreset/reset.css
@@ -0,0 +1,126 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+/*
+ TODO will need to remove settings on HTML since we can't namespace it.
+ TODO with the prefix, should I group by selector or property for weight savings?
+*/
+html{
+ color:#000;
+ background:#FFF;
+}
+/*
+ TODO remove settings on BODY since we can't namespace it.
+*/
+/*
+ TODO test putting a class on HEAD.
+ - Fails on FF.
+*/
+body,
+div,
+dl,
+dt,
+dd,
+ul,
+ol,
+li,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+pre,
+code,
+form,
+fieldset,
+legend,
+input,
+textarea,
+p,
+blockquote,
+th,
+td {
+ margin:0;
+ padding:0;
+}
+table {
+ border-collapse:collapse;
+ border-spacing:0;
+}
+fieldset,
+img {
+ border:0;
+}
+/*
+ TODO think about hanlding inheritence differently, maybe letting IE6 fail a bit...
+*/
+address,
+caption,
+cite,
+code,
+dfn,
+em,
+strong,
+th,
+var {
+ font-style:normal;
+ font-weight:normal;
+}
+/*
+ TODO Figure out where this list-style rule is best set. Hedger has a request to investigate.
+*/
+li {
+ list-style:none;
+}
+
+caption,
+th {
+ text-align:left;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ font-size:100%;
+ font-weight:normal;
+}
+q:before,
+q:after {
+ content:'';
+}
+abbr,
+acronym {
+ border:0;
+ font-variant:normal;
+}
+/* to preserve line-height and selector appearance */
+sup {
+ vertical-align:text-top;
+}
+sub {
+ vertical-align:text-bottom;
+}
+input,
+textarea,
+select {
+ font-family:inherit;
+ font-size:inherit;
+ font-weight:inherit;
+}
+/*to enable resizing for IE*/
+input,
+textarea,
+select {
+ *font-size:100%;
+}
+/*because legend doesn't inherit in IE */
+legend {
+ color:#000;
+}
\ No newline at end of file
diff --git a/lib/yui/3.0.0/dataschema/dataschema-array-debug.js b/lib/yui/3.0.0/dataschema/dataschema-array-debug.js
new file mode 100644
index 0000000000..883a55b25c
--- /dev/null
+++ b/lib/yui/3.0.0/dataschema/dataschema-array-debug.js
@@ -0,0 +1,110 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dataschema-array', function(Y) {
+
+/**
+ * Provides a DataSchema implementation which can be used to work with data stored in arrays.
+ *
+ * @module dataschema
+ * @submodule dataschema-array
+ */
+
+/**
+ * Array subclass for the DataSchema Utility.
+ * @class DataSchema.Array
+ * @extends DataSchema.Base
+ * @static
+ */
+var LANG = Y.Lang,
+
+ SchemaArray = {
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSchema.Array static methods
+ //
+ /////////////////////////////////////////////////////////////////////////////
+ /**
+ * Applies a given schema to given Array data.
+ *
+ * @method apply
+ * @param schema {Object} Schema to apply.
+ * @param data {Object} Array data.
+ * @return {Object} Schema-parsed data.
+ * @static
+ */
+ apply: function(schema, data) {
+ var data_in = data,
+ data_out = {results:[],meta:{}};
+
+ if(LANG.isArray(data_in)) {
+ if(LANG.isArray(schema.resultFields)) {
+ // Parse results data
+ data_out = SchemaArray._parseResults(schema.resultFields, data_in, data_out);
+ }
+ else {
+ data_out.results = data_in;
+ Y.log("Schema resultFields property not found: " + Y.dump(schema), "warn", "dataschema-array");
+ }
+ }
+ else {
+ Y.log("Array data could not be schema-parsed: " + Y.dump(data) + " " + Y.dump(data), "error", "dataschema-array");
+ data_out.error = new Error("Array schema parse failure");
+ }
+
+ return data_out;
+ },
+
+ /**
+ * Schema-parsed list of results from full data
+ *
+ * @method _parseResults
+ * @param fields {Array} Schema to parse against.
+ * @param array_in {Array} Array to parse.
+ * @param data_out {Object} In-progress parsed data to update.
+ * @return {Object} Parsed data object.
+ * @static
+ * @protected
+ */
+ _parseResults: function(fields, array_in, data_out) {
+ var results = [],
+ result, item, type, field, key, value, i, j;
+
+ for(i=array_in.length-1; i>-1; i--) {
+ result = {};
+ item = array_in[i];
+ type = (LANG.isObject(item) && !LANG.isFunction(item)) ? 2 : (LANG.isArray(item)) ? 1 : (LANG.isString(item)) ? 0 : -1;
+ if(type > 0) {
+ for(j=fields.length-1; j>-1; j--) {
+ field = fields[j];
+ key = (!LANG.isUndefined(field.key)) ? field.key : field;
+ value = (!LANG.isUndefined(item[key])) ? item[key] : item[j];
+ result[key] = Y.DataSchema.Base.parse(value, field);
+ }
+ }
+ else if(type === 0) {
+ result = item;
+ }
+ else {
+ //TODO: null or {}?
+ result = null;
+ Y.log("Unexpected type while parsing array: " + Y.dump(item), "warn", "dataschema-array");
+ }
+ results[i] = result;
+ }
+ data_out.results = results;
+
+ return data_out;
+ }
+ };
+
+Y.DataSchema.Array = Y.mix(SchemaArray, Y.DataSchema.Base);
+
+
+
+}, '3.0.0' ,{requires:['dataschema-base']});
diff --git a/lib/yui/3.0.0/dataschema/dataschema-array-min.js b/lib/yui/3.0.0/dataschema/dataschema-array-min.js
new file mode 100644
index 0000000000..c28b3d9c28
--- /dev/null
+++ b/lib/yui/3.0.0/dataschema/dataschema-array-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("dataschema-array",function(C){var A=C.Lang,B={apply:function(F,G){var D=G,E={results:[],meta:{}};if(A.isArray(D)){if(A.isArray(F.resultFields)){E=B._parseResults(F.resultFields,D,E);}else{E.results=D;}}else{E.error=new Error("Array schema parse failure");}return E;},_parseResults:function(H,K,D){var G=[],O,N,I,J,M,L,F,E;for(F=K.length-1;F>-1;F--){O={};N=K[F];I=(A.isObject(N)&&!A.isFunction(N))?2:(A.isArray(N))?1:(A.isString(N))?0:-1;if(I>0){for(E=H.length-1;E>-1;E--){J=H[E];M=(!A.isUndefined(J.key))?J.key:J;L=(!A.isUndefined(N[M]))?N[M]:N[E];O[M]=C.DataSchema.Base.parse(L,J);}}else{if(I===0){O=N;}else{O=null;}}G[F]=O;}D.results=G;return D;}};C.DataSchema.Array=C.mix(B,C.DataSchema.Base);},"3.0.0",{requires:["dataschema-base"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/dataschema/dataschema-array.js b/lib/yui/3.0.0/dataschema/dataschema-array.js
new file mode 100644
index 0000000000..ab8008f349
--- /dev/null
+++ b/lib/yui/3.0.0/dataschema/dataschema-array.js
@@ -0,0 +1,107 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dataschema-array', function(Y) {
+
+/**
+ * Provides a DataSchema implementation which can be used to work with data stored in arrays.
+ *
+ * @module dataschema
+ * @submodule dataschema-array
+ */
+
+/**
+ * Array subclass for the DataSchema Utility.
+ * @class DataSchema.Array
+ * @extends DataSchema.Base
+ * @static
+ */
+var LANG = Y.Lang,
+
+ SchemaArray = {
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSchema.Array static methods
+ //
+ /////////////////////////////////////////////////////////////////////////////
+ /**
+ * Applies a given schema to given Array data.
+ *
+ * @method apply
+ * @param schema {Object} Schema to apply.
+ * @param data {Object} Array data.
+ * @return {Object} Schema-parsed data.
+ * @static
+ */
+ apply: function(schema, data) {
+ var data_in = data,
+ data_out = {results:[],meta:{}};
+
+ if(LANG.isArray(data_in)) {
+ if(LANG.isArray(schema.resultFields)) {
+ // Parse results data
+ data_out = SchemaArray._parseResults(schema.resultFields, data_in, data_out);
+ }
+ else {
+ data_out.results = data_in;
+ }
+ }
+ else {
+ data_out.error = new Error("Array schema parse failure");
+ }
+
+ return data_out;
+ },
+
+ /**
+ * Schema-parsed list of results from full data
+ *
+ * @method _parseResults
+ * @param fields {Array} Schema to parse against.
+ * @param array_in {Array} Array to parse.
+ * @param data_out {Object} In-progress parsed data to update.
+ * @return {Object} Parsed data object.
+ * @static
+ * @protected
+ */
+ _parseResults: function(fields, array_in, data_out) {
+ var results = [],
+ result, item, type, field, key, value, i, j;
+
+ for(i=array_in.length-1; i>-1; i--) {
+ result = {};
+ item = array_in[i];
+ type = (LANG.isObject(item) && !LANG.isFunction(item)) ? 2 : (LANG.isArray(item)) ? 1 : (LANG.isString(item)) ? 0 : -1;
+ if(type > 0) {
+ for(j=fields.length-1; j>-1; j--) {
+ field = fields[j];
+ key = (!LANG.isUndefined(field.key)) ? field.key : field;
+ value = (!LANG.isUndefined(item[key])) ? item[key] : item[j];
+ result[key] = Y.DataSchema.Base.parse(value, field);
+ }
+ }
+ else if(type === 0) {
+ result = item;
+ }
+ else {
+ //TODO: null or {}?
+ result = null;
+ }
+ results[i] = result;
+ }
+ data_out.results = results;
+
+ return data_out;
+ }
+ };
+
+Y.DataSchema.Array = Y.mix(SchemaArray, Y.DataSchema.Base);
+
+
+
+}, '3.0.0' ,{requires:['dataschema-base']});
diff --git a/lib/yui/3.0.0/dataschema/dataschema-base-debug.js b/lib/yui/3.0.0/dataschema/dataschema-base-debug.js
new file mode 100644
index 0000000000..11835b1ae8
--- /dev/null
+++ b/lib/yui/3.0.0/dataschema/dataschema-base-debug.js
@@ -0,0 +1,74 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dataschema-base', function(Y) {
+
+/**
+ * The DataSchema utility provides a common configurable interface for widgets to
+ * apply a given schema to a variety of data.
+ *
+ * @module dataschema
+ */
+
+/**
+ * Provides the base DataSchema implementation, which can be extended to
+ * create DataSchemas for specific data formats, such XML, JSON, text and
+ * arrays.
+ *
+ * @module dataschema
+ * @submodule dataschema-base
+ */
+
+var LANG = Y.Lang,
+/**
+ * Base class for the YUI DataSchema Utility.
+ * @class DataSchema.Base
+ * @static
+ */
+ SchemaBase = {
+ /**
+ * Overridable method returns data as-is.
+ *
+ * @method apply
+ * @param schema {Object} Schema to apply.
+ * @param data {Object} Data.
+ * @return {Object} Schema-parsed data.
+ * @static
+ */
+ apply: function(schema, data) {
+ return data;
+ },
+
+ /**
+ * Applies field parser, if defined
+ *
+ * @method parse
+ * @param value {Object} Original value.
+ * @param field {Object} Field.
+ * @return {Object} Type-converted value.
+ */
+ parse: function(value, field) {
+ if(field.parser) {
+ var parser = (LANG.isFunction(field.parser)) ?
+ field.parser : Y.Parsers[field.parser+''];
+ if(parser) {
+ value = parser.call(this, value);
+ }
+ else {
+ Y.log("Could not find parser for field " + Y.dump(field), "warn", "dataschema-json");
+ }
+ }
+ return value;
+ }
+};
+
+Y.namespace("DataSchema").Base = SchemaBase;
+Y.namespace("Parsers");
+
+
+
+}, '3.0.0' ,{requires:['base']});
diff --git a/lib/yui/3.0.0/dataschema/dataschema-base-min.js b/lib/yui/3.0.0/dataschema/dataschema-base-min.js
new file mode 100644
index 0000000000..4e3f2da80c
--- /dev/null
+++ b/lib/yui/3.0.0/dataschema/dataschema-base-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("dataschema-base",function(B){var A=B.Lang,C={apply:function(D,E){return E;},parse:function(D,E){if(E.parser){var F=(A.isFunction(E.parser))?E.parser:B.Parsers[E.parser+""];if(F){D=F.call(this,D);}else{}}return D;}};B.namespace("DataSchema").Base=C;B.namespace("Parsers");},"3.0.0",{requires:["base"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/dataschema/dataschema-base.js b/lib/yui/3.0.0/dataschema/dataschema-base.js
new file mode 100644
index 0000000000..940155e673
--- /dev/null
+++ b/lib/yui/3.0.0/dataschema/dataschema-base.js
@@ -0,0 +1,73 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dataschema-base', function(Y) {
+
+/**
+ * The DataSchema utility provides a common configurable interface for widgets to
+ * apply a given schema to a variety of data.
+ *
+ * @module dataschema
+ */
+
+/**
+ * Provides the base DataSchema implementation, which can be extended to
+ * create DataSchemas for specific data formats, such XML, JSON, text and
+ * arrays.
+ *
+ * @module dataschema
+ * @submodule dataschema-base
+ */
+
+var LANG = Y.Lang,
+/**
+ * Base class for the YUI DataSchema Utility.
+ * @class DataSchema.Base
+ * @static
+ */
+ SchemaBase = {
+ /**
+ * Overridable method returns data as-is.
+ *
+ * @method apply
+ * @param schema {Object} Schema to apply.
+ * @param data {Object} Data.
+ * @return {Object} Schema-parsed data.
+ * @static
+ */
+ apply: function(schema, data) {
+ return data;
+ },
+
+ /**
+ * Applies field parser, if defined
+ *
+ * @method parse
+ * @param value {Object} Original value.
+ * @param field {Object} Field.
+ * @return {Object} Type-converted value.
+ */
+ parse: function(value, field) {
+ if(field.parser) {
+ var parser = (LANG.isFunction(field.parser)) ?
+ field.parser : Y.Parsers[field.parser+''];
+ if(parser) {
+ value = parser.call(this, value);
+ }
+ else {
+ }
+ }
+ return value;
+ }
+};
+
+Y.namespace("DataSchema").Base = SchemaBase;
+Y.namespace("Parsers");
+
+
+
+}, '3.0.0' ,{requires:['base']});
diff --git a/lib/yui/3.0.0/dataschema/dataschema-debug.js b/lib/yui/3.0.0/dataschema/dataschema-debug.js
new file mode 100644
index 0000000000..4a730f6278
--- /dev/null
+++ b/lib/yui/3.0.0/dataschema/dataschema-debug.js
@@ -0,0 +1,745 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dataschema-base', function(Y) {
+
+/**
+ * The DataSchema utility provides a common configurable interface for widgets to
+ * apply a given schema to a variety of data.
+ *
+ * @module dataschema
+ */
+
+/**
+ * Provides the base DataSchema implementation, which can be extended to
+ * create DataSchemas for specific data formats, such XML, JSON, text and
+ * arrays.
+ *
+ * @module dataschema
+ * @submodule dataschema-base
+ */
+
+var LANG = Y.Lang,
+/**
+ * Base class for the YUI DataSchema Utility.
+ * @class DataSchema.Base
+ * @static
+ */
+ SchemaBase = {
+ /**
+ * Overridable method returns data as-is.
+ *
+ * @method apply
+ * @param schema {Object} Schema to apply.
+ * @param data {Object} Data.
+ * @return {Object} Schema-parsed data.
+ * @static
+ */
+ apply: function(schema, data) {
+ return data;
+ },
+
+ /**
+ * Applies field parser, if defined
+ *
+ * @method parse
+ * @param value {Object} Original value.
+ * @param field {Object} Field.
+ * @return {Object} Type-converted value.
+ */
+ parse: function(value, field) {
+ if(field.parser) {
+ var parser = (LANG.isFunction(field.parser)) ?
+ field.parser : Y.Parsers[field.parser+''];
+ if(parser) {
+ value = parser.call(this, value);
+ }
+ else {
+ Y.log("Could not find parser for field " + Y.dump(field), "warn", "dataschema-json");
+ }
+ }
+ return value;
+ }
+};
+
+Y.namespace("DataSchema").Base = SchemaBase;
+Y.namespace("Parsers");
+
+
+
+}, '3.0.0' ,{requires:['base']});
+
+YUI.add('dataschema-json', function(Y) {
+
+/**
+ * Provides a DataSchema implementation which can be used to work with JSON data.
+ *
+ * @module dataschema
+ * @submodule dataschema-json
+ */
+
+/**
+ * JSON subclass for the DataSchema Utility.
+ * @class DataSchema.JSON
+ * @extends DataSchema.Base
+ * @static
+ */
+var LANG = Y.Lang,
+
+ SchemaJSON = {
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSchema.JSON static methods
+ //
+ /////////////////////////////////////////////////////////////////////////////
+ /**
+ * Utility function converts JSON locator strings into walkable paths
+ *
+ * @method DataSchema.JSON.getPath
+ * @param locator {String} JSON value locator.
+ * @return {String[]} Walkable path to data value.
+ * @static
+ */
+ getPath: function(locator) {
+ var path = null,
+ keys = [],
+ i = 0;
+
+ if (locator) {
+ // Strip the ["string keys"] and [1] array indexes
+ locator = locator.
+ replace(/\[(['"])(.*?)\1\]/g,
+ function (x,$1,$2) {keys[i]=$2;return '.@'+(i++);}).
+ replace(/\[(\d+)\]/g,
+ function (x,$1) {keys[i]=parseInt($1,10)|0;return '.@'+(i++);}).
+ replace(/^\./,''); // remove leading dot
+
+ // Validate against problematic characters.
+ if (!/[^\w\.\$@]/.test(locator)) {
+ path = locator.split('.');
+ for (i=path.length-1; i >= 0; --i) {
+ if (path[i].charAt(0) === '@') {
+ path[i] = keys[parseInt(path[i].substr(1),10)];
+ }
+ }
+ }
+ else {
+ Y.log("Invalid locator: " + locator, "error", "dataschema-json");
+ }
+ }
+ return path;
+ },
+
+ /**
+ * Utility function to walk a path and return the value located there.
+ *
+ * @method DataSchema.JSON.getLocationValue
+ * @param path {String[]} Locator path.
+ * @param data {String} Data to traverse.
+ * @return {Object} Data value at location.
+ * @static
+ */
+ getLocationValue: function (path, data) {
+ var i = 0,
+ len = path.length;
+ for (;i=0; --i) {
+ record = {};
+ result = array_in[i];
+ if(result) {
+ // Cycle through simpleLocators
+ for (j=simplePaths.length-1; j>=0; --j) {
+ // Bug 1777850: The result might be an array instead of object
+ record[simplePaths[j].key] = Y.DataSchema.Base.parse(
+ (LANG.isUndefined(result[simplePaths[j].path]) ?
+ result[j] : result[simplePaths[j].path]), simplePaths[j]);
+ }
+
+ // Cycle through complexLocators
+ for (j=complexPaths.length - 1; j>=0; --j) {
+ record[complexPaths[j].key] = Y.DataSchema.Base.parse(
+ (SchemaJSON.getLocationValue(complexPaths[j].path, result)), complexPaths[j] );
+ }
+
+ // Cycle through fieldParsers
+ for (j=fieldParsers.length-1; j>=0; --j) {
+ key = fieldParsers[j].key;
+ record[key] = fieldParsers[j].parser(record[key]);
+ // Safety net
+ if (LANG.isUndefined(record[key])) {
+ record[key] = null;
+ }
+ }
+ results[i] = record;
+ }
+ }
+ data_out.results = results;
+ return data_out;
+ },
+
+ /**
+ * Parses results data according to schema
+ *
+ * @method _parseMeta
+ * @param metaFields {Object} Metafields definitions.
+ * @param json_in {Object} JSON to parse.
+ * @param data_out {Object} In-progress parsed data to update.
+ * @return {Object} Schema-parsed meta data.
+ * @static
+ * @protected
+ */
+ _parseMeta: function(metaFields, json_in, data_out) {
+ if(LANG.isObject(metaFields)) {
+ var key, path;
+ for(key in metaFields) {
+ if (metaFields.hasOwnProperty(key)) {
+ path = SchemaJSON.getPath(metaFields[key]);
+ if (path && json_in) {
+ data_out.meta[key] = SchemaJSON.getLocationValue(path, json_in);
+ }
+ }
+ }
+ }
+ else {
+ data_out.error = new Error("JSON meta data retrieval failure");
+ }
+ return data_out;
+ }
+ };
+
+Y.DataSchema.JSON = Y.mix(SchemaJSON, Y.DataSchema.Base);
+
+
+
+}, '3.0.0' ,{requires:['json', 'dataschema-base']});
+
+YUI.add('dataschema-xml', function(Y) {
+
+/**
+ * Provides a DataSchema implementation which can be used to work with XML data.
+ *
+ * @module dataschema
+ * @submodule dataschema-xml
+ */
+var LANG = Y.Lang,
+
+ /**
+ * XML subclass for the DataSchema Utility.
+ * @class DataSchema.XML
+ * @extends DataSchema.Base
+ * @static
+ */
+ SchemaXML = {
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSchema.XML static methods
+ //
+ /////////////////////////////////////////////////////////////////////////////
+ /**
+ * Applies a given schema to given XML data.
+ *
+ * @method apply
+ * @param schema {Object} Schema to apply.
+ * @param data {XMLDoc} XML document.
+ * @return {Object} Schema-parsed data.
+ * @static
+ */
+ apply: function(schema, data) {
+ var xmldoc = data,
+ data_out = {results:[],meta:{}};
+
+ if(xmldoc && xmldoc.nodeType && (xmldoc.nodeType === 9 || xmldoc.nodeType === 1 || xmldoc.nodeType === 11) && schema) {
+ // Parse results data
+ data_out = SchemaXML._parseResults(schema, xmldoc, data_out);
+
+ // Parse meta data
+ data_out = SchemaXML._parseMeta(schema.metaFields, xmldoc, data_out);
+ }
+ else {
+ Y.log("XML data could not be schema-parsed: " + Y.dump(data) + " " + Y.dump(data), "error", "dataschema-xml");
+ data_out.error = new Error("XML schema parse failure");
+ }
+
+ return data_out;
+ },
+
+ /**
+ * Get an XPath-specified value for a given field from an XML node or document.
+ *
+ * @method _getLocationValue
+ * @param field {String | Object} Field definition.
+ * @param context {Object} XML node or document to search within.
+ * @return {Object} Data value or null.
+ * @static
+ * @protected
+ */
+ _getLocationValue: function(field, context) {
+ var locator = field.locator || field.key || field,
+ xmldoc = context.ownerDocument || context,
+ result, res, value = null;
+
+ try {
+ // Standards mode
+ if(!LANG.isUndefined(xmldoc.evaluate)) {
+ result = xmldoc.evaluate(locator, context, xmldoc.createNSResolver(!context.ownerDocument ? context.documentElement : context.ownerDocument.documentElement), 0, null);
+ while(res = result.iterateNext()) {
+ value = res.textContent;
+ }
+ }
+ // IE mode
+ else {
+ xmldoc.setProperty("SelectionLanguage", "XPath");
+ result = context.selectNodes(locator)[0];
+ value = result.value || result.text || null;
+ }
+ return Y.DataSchema.Base.parse(value, field);
+
+ }
+ catch(e) {
+ }
+ },
+
+ /**
+ * Parses results data according to schema
+ *
+ * @method _parseMeta
+ * @param xmldoc_in {Object} XML document parse.
+ * @param data_out {Object} In-progress schema-parsed data to update.
+ * @return {Object} Schema-parsed data.
+ * @static
+ * @protected
+ */
+ _parseMeta: function(metaFields, xmldoc_in, data_out) {
+ if(LANG.isObject(metaFields)) {
+ var key,
+ xmldoc = xmldoc_in.ownerDocument || xmldoc_in;
+
+ for(key in metaFields) {
+ if (metaFields.hasOwnProperty(key)) {
+ data_out.meta[key] = SchemaXML._getLocationValue(metaFields[key], xmldoc);
+ }
+ }
+ }
+ return data_out;
+ },
+
+ /**
+ * Schema-parsed list of results from full data
+ *
+ * @method _parseResults
+ * @param schema {Object} Schema to parse against.
+ * @param xmldoc_in {Object} XML document parse.
+ * @param data_out {Object} In-progress schema-parsed data to update.
+ * @return {Object} Schema-parsed data.
+ * @static
+ * @protected
+ */
+ _parseResults: function(schema, xmldoc_in, data_out) {
+ if(schema.resultListLocator && LANG.isArray(schema.resultFields)) {
+ var nodeList = xmldoc_in.getElementsByTagName(schema.resultListLocator),
+ fields = schema.resultFields,
+ results = [],
+ node, field, result, i, j;
+
+ if(nodeList.length) {
+ // Loop through each result node
+ for(i=nodeList.length-1; i>= 0; i--) {
+ result = {};
+ node = nodeList[i];
+
+ // Find each field value
+ for(j=fields.length-1; j>= 0; j--) {
+ field = fields[j];
+ result[field.key || field] = SchemaXML._getLocationValue(field, node);
+ }
+ results[i] = result;
+ }
+
+ data_out.results = results;
+ }
+ else {
+ data_out.error = new Error("XML schema result nodes retrieval failure");
+ }
+ }
+ return data_out;
+ }
+ };
+
+Y.DataSchema.XML = Y.mix(SchemaXML, Y.DataSchema.Base);
+
+
+
+}, '3.0.0' ,{requires:['dataschema-base']});
+
+YUI.add('dataschema-array', function(Y) {
+
+/**
+ * Provides a DataSchema implementation which can be used to work with data stored in arrays.
+ *
+ * @module dataschema
+ * @submodule dataschema-array
+ */
+
+/**
+ * Array subclass for the DataSchema Utility.
+ * @class DataSchema.Array
+ * @extends DataSchema.Base
+ * @static
+ */
+var LANG = Y.Lang,
+
+ SchemaArray = {
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSchema.Array static methods
+ //
+ /////////////////////////////////////////////////////////////////////////////
+ /**
+ * Applies a given schema to given Array data.
+ *
+ * @method apply
+ * @param schema {Object} Schema to apply.
+ * @param data {Object} Array data.
+ * @return {Object} Schema-parsed data.
+ * @static
+ */
+ apply: function(schema, data) {
+ var data_in = data,
+ data_out = {results:[],meta:{}};
+
+ if(LANG.isArray(data_in)) {
+ if(LANG.isArray(schema.resultFields)) {
+ // Parse results data
+ data_out = SchemaArray._parseResults(schema.resultFields, data_in, data_out);
+ }
+ else {
+ data_out.results = data_in;
+ Y.log("Schema resultFields property not found: " + Y.dump(schema), "warn", "dataschema-array");
+ }
+ }
+ else {
+ Y.log("Array data could not be schema-parsed: " + Y.dump(data) + " " + Y.dump(data), "error", "dataschema-array");
+ data_out.error = new Error("Array schema parse failure");
+ }
+
+ return data_out;
+ },
+
+ /**
+ * Schema-parsed list of results from full data
+ *
+ * @method _parseResults
+ * @param fields {Array} Schema to parse against.
+ * @param array_in {Array} Array to parse.
+ * @param data_out {Object} In-progress parsed data to update.
+ * @return {Object} Parsed data object.
+ * @static
+ * @protected
+ */
+ _parseResults: function(fields, array_in, data_out) {
+ var results = [],
+ result, item, type, field, key, value, i, j;
+
+ for(i=array_in.length-1; i>-1; i--) {
+ result = {};
+ item = array_in[i];
+ type = (LANG.isObject(item) && !LANG.isFunction(item)) ? 2 : (LANG.isArray(item)) ? 1 : (LANG.isString(item)) ? 0 : -1;
+ if(type > 0) {
+ for(j=fields.length-1; j>-1; j--) {
+ field = fields[j];
+ key = (!LANG.isUndefined(field.key)) ? field.key : field;
+ value = (!LANG.isUndefined(item[key])) ? item[key] : item[j];
+ result[key] = Y.DataSchema.Base.parse(value, field);
+ }
+ }
+ else if(type === 0) {
+ result = item;
+ }
+ else {
+ //TODO: null or {}?
+ result = null;
+ Y.log("Unexpected type while parsing array: " + Y.dump(item), "warn", "dataschema-array");
+ }
+ results[i] = result;
+ }
+ data_out.results = results;
+
+ return data_out;
+ }
+ };
+
+Y.DataSchema.Array = Y.mix(SchemaArray, Y.DataSchema.Base);
+
+
+
+}, '3.0.0' ,{requires:['dataschema-base']});
+
+YUI.add('dataschema-text', function(Y) {
+
+/**
+ * Provides a DataSchema implementation which can be used to work with delimited text data.
+ *
+ * @module dataschema
+ * @submodule dataschema-text
+ */
+
+/**
+ * Text subclass for the DataSchema Utility.
+ * @class DataSchema.Text
+ * @extends DataSchema.Base
+ * @static
+ */
+
+var LANG = Y.Lang,
+
+ SchemaText = {
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSchema.Text static methods
+ //
+ /////////////////////////////////////////////////////////////////////////////
+ /**
+ * Applies a given schema to given delimited text data.
+ *
+ * @method apply
+ * @param schema {Object} Schema to apply.
+ * @param data {Object} Text data.
+ * @return {Object} Schema-parsed data.
+ * @static
+ */
+ apply: function(schema, data) {
+ var data_in = data,
+ data_out = {results:[],meta:{}};
+
+ if(LANG.isString(data_in) && LANG.isString(schema.resultDelimiter)) {
+ // Parse results data
+ data_out = SchemaText._parseResults(schema, data_in, data_out);
+ }
+ else {
+ Y.log("Text data could not be schema-parsed: " + Y.dump(data) + " " + Y.dump(data), "error", "dataschema-text");
+ data_out.error = new Error("Text schema parse failure");
+ }
+
+ return data_out;
+ },
+
+ /**
+ * Schema-parsed list of results from full data
+ *
+ * @method _parseResults
+ * @param schema {Array} Schema to parse against.
+ * @param text_in {String} Text to parse.
+ * @param data_out {Object} In-progress parsed data to update.
+ * @return {Object} Parsed data object.
+ * @static
+ * @protected
+ */
+ _parseResults: function(schema, text_in, data_out) {
+ var resultDelim = schema.resultDelimiter,
+ results = [],
+ results_in, fields_in, result, item, fields, field, key, value, i, j,
+
+ // Delete final delimiter at end of string if there
+ tmpLength = text_in.length-resultDelim.length;
+ if(text_in.substr(tmpLength) == resultDelim) {
+ text_in = text_in.substr(0, tmpLength);
+ }
+
+ // Split into results
+ results_in = text_in.split(schema.resultDelimiter);
+
+ for(i=results_in.length-1; i>-1; i--) {
+ result = {};
+ item = results_in[i];
+
+ if(LANG.isString(schema.fieldDelimiter)) {
+ fields_in = item.split(schema.fieldDelimiter);
+
+ if(LANG.isArray(schema.resultFields)) {
+ fields = schema.resultFields;
+ for(j=fields.length-1; j>-1; j--) {
+ field = fields[j];
+ key = (!LANG.isUndefined(field.key)) ? field.key : field;
+ value = (!LANG.isUndefined(fields_in[key])) ? fields_in[key] : fields_in[j];
+ result[key] = Y.DataSchema.Base.parse(value, field);
+ }
+ }
+
+ }
+ else {
+ result = item;
+ }
+
+ results[i] = result;
+ }
+ data_out.results = results;
+
+ return data_out;
+ }
+ };
+
+Y.DataSchema.Text = Y.mix(SchemaText, Y.DataSchema.Base);
+
+
+
+}, '3.0.0' ,{requires:['dataschema-base']});
+
+
+
+YUI.add('dataschema', function(Y){}, '3.0.0' ,{use:['dataschema-base','dataschema-json','dataschema-xml','dataschema-array','dataschema-text']});
+
diff --git a/lib/yui/3.0.0/dataschema/dataschema-json-debug.js b/lib/yui/3.0.0/dataschema/dataschema-json-debug.js
new file mode 100644
index 0000000000..b1df20ae23
--- /dev/null
+++ b/lib/yui/3.0.0/dataschema/dataschema-json-debug.js
@@ -0,0 +1,298 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dataschema-json', function(Y) {
+
+/**
+ * Provides a DataSchema implementation which can be used to work with JSON data.
+ *
+ * @module dataschema
+ * @submodule dataschema-json
+ */
+
+/**
+ * JSON subclass for the DataSchema Utility.
+ * @class DataSchema.JSON
+ * @extends DataSchema.Base
+ * @static
+ */
+var LANG = Y.Lang,
+
+ SchemaJSON = {
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSchema.JSON static methods
+ //
+ /////////////////////////////////////////////////////////////////////////////
+ /**
+ * Utility function converts JSON locator strings into walkable paths
+ *
+ * @method DataSchema.JSON.getPath
+ * @param locator {String} JSON value locator.
+ * @return {String[]} Walkable path to data value.
+ * @static
+ */
+ getPath: function(locator) {
+ var path = null,
+ keys = [],
+ i = 0;
+
+ if (locator) {
+ // Strip the ["string keys"] and [1] array indexes
+ locator = locator.
+ replace(/\[(['"])(.*?)\1\]/g,
+ function (x,$1,$2) {keys[i]=$2;return '.@'+(i++);}).
+ replace(/\[(\d+)\]/g,
+ function (x,$1) {keys[i]=parseInt($1,10)|0;return '.@'+(i++);}).
+ replace(/^\./,''); // remove leading dot
+
+ // Validate against problematic characters.
+ if (!/[^\w\.\$@]/.test(locator)) {
+ path = locator.split('.');
+ for (i=path.length-1; i >= 0; --i) {
+ if (path[i].charAt(0) === '@') {
+ path[i] = keys[parseInt(path[i].substr(1),10)];
+ }
+ }
+ }
+ else {
+ Y.log("Invalid locator: " + locator, "error", "dataschema-json");
+ }
+ }
+ return path;
+ },
+
+ /**
+ * Utility function to walk a path and return the value located there.
+ *
+ * @method DataSchema.JSON.getLocationValue
+ * @param path {String[]} Locator path.
+ * @param data {String} Data to traverse.
+ * @return {Object} Data value at location.
+ * @static
+ */
+ getLocationValue: function (path, data) {
+ var i = 0,
+ len = path.length;
+ for (;i=0; --i) {
+ record = {};
+ result = array_in[i];
+ if(result) {
+ // Cycle through simpleLocators
+ for (j=simplePaths.length-1; j>=0; --j) {
+ // Bug 1777850: The result might be an array instead of object
+ record[simplePaths[j].key] = Y.DataSchema.Base.parse(
+ (LANG.isUndefined(result[simplePaths[j].path]) ?
+ result[j] : result[simplePaths[j].path]), simplePaths[j]);
+ }
+
+ // Cycle through complexLocators
+ for (j=complexPaths.length - 1; j>=0; --j) {
+ record[complexPaths[j].key] = Y.DataSchema.Base.parse(
+ (SchemaJSON.getLocationValue(complexPaths[j].path, result)), complexPaths[j] );
+ }
+
+ // Cycle through fieldParsers
+ for (j=fieldParsers.length-1; j>=0; --j) {
+ key = fieldParsers[j].key;
+ record[key] = fieldParsers[j].parser(record[key]);
+ // Safety net
+ if (LANG.isUndefined(record[key])) {
+ record[key] = null;
+ }
+ }
+ results[i] = record;
+ }
+ }
+ data_out.results = results;
+ return data_out;
+ },
+
+ /**
+ * Parses results data according to schema
+ *
+ * @method _parseMeta
+ * @param metaFields {Object} Metafields definitions.
+ * @param json_in {Object} JSON to parse.
+ * @param data_out {Object} In-progress parsed data to update.
+ * @return {Object} Schema-parsed meta data.
+ * @static
+ * @protected
+ */
+ _parseMeta: function(metaFields, json_in, data_out) {
+ if(LANG.isObject(metaFields)) {
+ var key, path;
+ for(key in metaFields) {
+ if (metaFields.hasOwnProperty(key)) {
+ path = SchemaJSON.getPath(metaFields[key]);
+ if (path && json_in) {
+ data_out.meta[key] = SchemaJSON.getLocationValue(path, json_in);
+ }
+ }
+ }
+ }
+ else {
+ data_out.error = new Error("JSON meta data retrieval failure");
+ }
+ return data_out;
+ }
+ };
+
+Y.DataSchema.JSON = Y.mix(SchemaJSON, Y.DataSchema.Base);
+
+
+
+}, '3.0.0' ,{requires:['json', 'dataschema-base']});
diff --git a/lib/yui/3.0.0/dataschema/dataschema-json-min.js b/lib/yui/3.0.0/dataschema/dataschema-json-min.js
new file mode 100644
index 0000000000..2f21817235
--- /dev/null
+++ b/lib/yui/3.0.0/dataschema/dataschema-json-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("dataschema-json",function(C){var A=C.Lang,B={getPath:function(D){var G=null,F=[],E=0;if(D){D=D.replace(/\[(['"])(.*?)\1\]/g,function(I,H,J){F[E]=J;return".@"+(E++);}).replace(/\[(\d+)\]/g,function(I,H){F[E]=parseInt(H,10)|0;return".@"+(E++);}).replace(/^\./,"");if(!/[^\w\.\$@]/.test(D)){G=D.split(".");for(E=G.length-1;E>=0;--E){if(G[E].charAt(0)==="@"){G[E]=F[parseInt(G[E].substr(1),10)];}}}else{}}return G;},getLocationValue:function(G,F){var E=0,D=G.length;for(;E=0;--H){I={};R=P[H];if(R){for(F=J.length-1;F>=0;--F){I[J[F].key]=C.DataSchema.Base.parse((A.isUndefined(R[J[F].path])?R[F]:R[J[F].path]),J[F]);}for(F=N.length-1;F>=0;--F){I[N[F].key]=C.DataSchema.Base.parse((B.getLocationValue(N[F].path,R)),N[F]);}for(F=L.length-1;F>=0;--F){Q=L[F].key;I[Q]=L[F].parser(I[Q]);if(A.isUndefined(I[Q])){I[Q]=null;}}G[H]=I;}}E.results=G;return E;},_parseMeta:function(G,D,F){if(A.isObject(G)){var E,H;for(E in G){if(G.hasOwnProperty(E)){H=B.getPath(G[E]);if(H&&D){F.meta[E]=B.getLocationValue(H,D);}}}}else{F.error=new Error("JSON meta data retrieval failure");}return F;}};C.DataSchema.JSON=C.mix(B,C.DataSchema.Base);},"3.0.0",{requires:["json","dataschema-base"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/dataschema/dataschema-json.js b/lib/yui/3.0.0/dataschema/dataschema-json.js
new file mode 100644
index 0000000000..7bfe4879ea
--- /dev/null
+++ b/lib/yui/3.0.0/dataschema/dataschema-json.js
@@ -0,0 +1,294 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dataschema-json', function(Y) {
+
+/**
+ * Provides a DataSchema implementation which can be used to work with JSON data.
+ *
+ * @module dataschema
+ * @submodule dataschema-json
+ */
+
+/**
+ * JSON subclass for the DataSchema Utility.
+ * @class DataSchema.JSON
+ * @extends DataSchema.Base
+ * @static
+ */
+var LANG = Y.Lang,
+
+ SchemaJSON = {
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSchema.JSON static methods
+ //
+ /////////////////////////////////////////////////////////////////////////////
+ /**
+ * Utility function converts JSON locator strings into walkable paths
+ *
+ * @method DataSchema.JSON.getPath
+ * @param locator {String} JSON value locator.
+ * @return {String[]} Walkable path to data value.
+ * @static
+ */
+ getPath: function(locator) {
+ var path = null,
+ keys = [],
+ i = 0;
+
+ if (locator) {
+ // Strip the ["string keys"] and [1] array indexes
+ locator = locator.
+ replace(/\[(['"])(.*?)\1\]/g,
+ function (x,$1,$2) {keys[i]=$2;return '.@'+(i++);}).
+ replace(/\[(\d+)\]/g,
+ function (x,$1) {keys[i]=parseInt($1,10)|0;return '.@'+(i++);}).
+ replace(/^\./,''); // remove leading dot
+
+ // Validate against problematic characters.
+ if (!/[^\w\.\$@]/.test(locator)) {
+ path = locator.split('.');
+ for (i=path.length-1; i >= 0; --i) {
+ if (path[i].charAt(0) === '@') {
+ path[i] = keys[parseInt(path[i].substr(1),10)];
+ }
+ }
+ }
+ else {
+ }
+ }
+ return path;
+ },
+
+ /**
+ * Utility function to walk a path and return the value located there.
+ *
+ * @method DataSchema.JSON.getLocationValue
+ * @param path {String[]} Locator path.
+ * @param data {String} Data to traverse.
+ * @return {Object} Data value at location.
+ * @static
+ */
+ getLocationValue: function (path, data) {
+ var i = 0,
+ len = path.length;
+ for (;i=0; --i) {
+ record = {};
+ result = array_in[i];
+ if(result) {
+ // Cycle through simpleLocators
+ for (j=simplePaths.length-1; j>=0; --j) {
+ // Bug 1777850: The result might be an array instead of object
+ record[simplePaths[j].key] = Y.DataSchema.Base.parse(
+ (LANG.isUndefined(result[simplePaths[j].path]) ?
+ result[j] : result[simplePaths[j].path]), simplePaths[j]);
+ }
+
+ // Cycle through complexLocators
+ for (j=complexPaths.length - 1; j>=0; --j) {
+ record[complexPaths[j].key] = Y.DataSchema.Base.parse(
+ (SchemaJSON.getLocationValue(complexPaths[j].path, result)), complexPaths[j] );
+ }
+
+ // Cycle through fieldParsers
+ for (j=fieldParsers.length-1; j>=0; --j) {
+ key = fieldParsers[j].key;
+ record[key] = fieldParsers[j].parser(record[key]);
+ // Safety net
+ if (LANG.isUndefined(record[key])) {
+ record[key] = null;
+ }
+ }
+ results[i] = record;
+ }
+ }
+ data_out.results = results;
+ return data_out;
+ },
+
+ /**
+ * Parses results data according to schema
+ *
+ * @method _parseMeta
+ * @param metaFields {Object} Metafields definitions.
+ * @param json_in {Object} JSON to parse.
+ * @param data_out {Object} In-progress parsed data to update.
+ * @return {Object} Schema-parsed meta data.
+ * @static
+ * @protected
+ */
+ _parseMeta: function(metaFields, json_in, data_out) {
+ if(LANG.isObject(metaFields)) {
+ var key, path;
+ for(key in metaFields) {
+ if (metaFields.hasOwnProperty(key)) {
+ path = SchemaJSON.getPath(metaFields[key]);
+ if (path && json_in) {
+ data_out.meta[key] = SchemaJSON.getLocationValue(path, json_in);
+ }
+ }
+ }
+ }
+ else {
+ data_out.error = new Error("JSON meta data retrieval failure");
+ }
+ return data_out;
+ }
+ };
+
+Y.DataSchema.JSON = Y.mix(SchemaJSON, Y.DataSchema.Base);
+
+
+
+}, '3.0.0' ,{requires:['json', 'dataschema-base']});
diff --git a/lib/yui/3.0.0/dataschema/dataschema-min.js b/lib/yui/3.0.0/dataschema/dataschema-min.js
new file mode 100644
index 0000000000..d0e6a4795d
--- /dev/null
+++ b/lib/yui/3.0.0/dataschema/dataschema-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("dataschema-base",function(B){var A=B.Lang,C={apply:function(D,E){return E;},parse:function(D,E){if(E.parser){var F=(A.isFunction(E.parser))?E.parser:B.Parsers[E.parser+""];if(F){D=F.call(this,D);}else{}}return D;}};B.namespace("DataSchema").Base=C;B.namespace("Parsers");},"3.0.0",{requires:["base"]});YUI.add("dataschema-json",function(C){var A=C.Lang,B={getPath:function(D){var G=null,F=[],E=0;if(D){D=D.replace(/\[(['"])(.*?)\1\]/g,function(I,H,J){F[E]=J;return".@"+(E++);}).replace(/\[(\d+)\]/g,function(I,H){F[E]=parseInt(H,10)|0;return".@"+(E++);}).replace(/^\./,"");if(!/[^\w\.\$@]/.test(D)){G=D.split(".");for(E=G.length-1;E>=0;--E){if(G[E].charAt(0)==="@"){G[E]=F[parseInt(G[E].substr(1),10)];}}}else{}}return G;},getLocationValue:function(G,F){var E=0,D=G.length;for(;E=0;--H){I={};R=P[H];if(R){for(F=J.length-1;F>=0;--F){I[J[F].key]=C.DataSchema.Base.parse((A.isUndefined(R[J[F].path])?R[F]:R[J[F].path]),J[F]);}for(F=N.length-1;F>=0;--F){I[N[F].key]=C.DataSchema.Base.parse((B.getLocationValue(N[F].path,R)),N[F]);}for(F=L.length-1;F>=0;--F){Q=L[F].key;I[Q]=L[F].parser(I[Q]);if(A.isUndefined(I[Q])){I[Q]=null;}}G[H]=I;}}E.results=G;return E;},_parseMeta:function(G,D,F){if(A.isObject(G)){var E,H;for(E in G){if(G.hasOwnProperty(E)){H=B.getPath(G[E]);if(H&&D){F.meta[E]=B.getLocationValue(H,D);}}}}else{F.error=new Error("JSON meta data retrieval failure");}return F;}};C.DataSchema.JSON=C.mix(B,C.DataSchema.Base);},"3.0.0",{requires:["json","dataschema-base"]});YUI.add("dataschema-xml",function(C){var B=C.Lang,A={apply:function(F,G){var D=G,E={results:[],meta:{}};if(D&&D.nodeType&&(D.nodeType===9||D.nodeType===1||D.nodeType===11)&&F){E=A._parseResults(F,D,E);E=A._parseMeta(F.metaFields,D,E);}else{E.error=new Error("XML schema parse failure");}return E;},_getLocationValue:function(K,H){var F=K.locator||K.key||K,E=H.ownerDocument||H,D,G,I=null;try{if(!B.isUndefined(E.evaluate)){D=E.evaluate(F,H,E.createNSResolver(!H.ownerDocument?H.documentElement:H.ownerDocument.documentElement),0,null);while(G=D.iterateNext()){I=G.textContent;}}else{E.setProperty("SelectionLanguage","XPath");D=H.selectNodes(F)[0];I=D.value||D.text||null;}return C.DataSchema.Base.parse(I,K);}catch(J){}},_parseMeta:function(H,G,F){if(B.isObject(H)){var E,D=G.ownerDocument||G;for(E in H){if(H.hasOwnProperty(E)){F.meta[E]=A._getLocationValue(H[E],D);}}}return F;},_parseResults:function(F,K,G){if(F.resultListLocator&&B.isArray(F.resultFields)){var E=K.getElementsByTagName(F.resultListLocator),L=F.resultFields,J=[],D,M,N,I,H;if(E.length){for(I=E.length-1;I>=0;I--){N={};D=E[I];for(H=L.length-1;H>=0;H--){M=L[H];N[M.key||M]=A._getLocationValue(M,D);}J[I]=N;}G.results=J;}else{G.error=new Error("XML schema result nodes retrieval failure");}}return G;}};C.DataSchema.XML=C.mix(A,C.DataSchema.Base);},"3.0.0",{requires:["dataschema-base"]});YUI.add("dataschema-array",function(C){var A=C.Lang,B={apply:function(F,G){var D=G,E={results:[],meta:{}};if(A.isArray(D)){if(A.isArray(F.resultFields)){E=B._parseResults(F.resultFields,D,E);}else{E.results=D;}}else{E.error=new Error("Array schema parse failure");}return E;},_parseResults:function(H,K,D){var G=[],O,N,I,J,M,L,F,E;for(F=K.length-1;F>-1;F--){O={};N=K[F];I=(A.isObject(N)&&!A.isFunction(N))?2:(A.isArray(N))?1:(A.isString(N))?0:-1;if(I>0){for(E=H.length-1;E>-1;E--){J=H[E];M=(!A.isUndefined(J.key))?J.key:J;L=(!A.isUndefined(N[M]))?N[M]:N[E];O[M]=C.DataSchema.Base.parse(L,J);}}else{if(I===0){O=N;}else{O=null;}}G[F]=O;}D.results=G;return D;}};C.DataSchema.Array=C.mix(B,C.DataSchema.Base);},"3.0.0",{requires:["dataschema-base"]});YUI.add("dataschema-text",function(C){var B=C.Lang,A={apply:function(F,G){var D=G,E={results:[],meta:{}};if(B.isString(D)&&B.isString(F.resultDelimiter)){E=A._parseResults(F,D,E);}else{E.error=new Error("Text schema parse failure");}return E;},_parseResults:function(D,K,E){var I=D.resultDelimiter,H=[],L,P,S,R,J,N,Q,O,G,F,M=K.length-I.length;if(K.substr(M)==I){K=K.substr(0,M);}L=K.split(D.resultDelimiter);for(G=L.length-1;G>-1;G--){S={};R=L[G];if(B.isString(D.fieldDelimiter)){P=R.split(D.fieldDelimiter);if(B.isArray(D.resultFields)){J=D.resultFields;for(F=J.length-1;F>-1;F--){N=J[F];Q=(!B.isUndefined(N.key))?N.key:N;O=(!B.isUndefined(P[Q]))?P[Q]:P[F];S[Q]=C.DataSchema.Base.parse(O,N);}}}else{S=R;}H[G]=S;}E.results=H;return E;}};C.DataSchema.Text=C.mix(A,C.DataSchema.Base);},"3.0.0",{requires:["dataschema-base"]});YUI.add("dataschema",function(A){},"3.0.0",{use:["dataschema-base","dataschema-json","dataschema-xml","dataschema-array","dataschema-text"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/dataschema/dataschema-text-debug.js b/lib/yui/3.0.0/dataschema/dataschema-text-debug.js
new file mode 100644
index 0000000000..2ef36b4f91
--- /dev/null
+++ b/lib/yui/3.0.0/dataschema/dataschema-text-debug.js
@@ -0,0 +1,117 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dataschema-text', function(Y) {
+
+/**
+ * Provides a DataSchema implementation which can be used to work with delimited text data.
+ *
+ * @module dataschema
+ * @submodule dataschema-text
+ */
+
+/**
+ * Text subclass for the DataSchema Utility.
+ * @class DataSchema.Text
+ * @extends DataSchema.Base
+ * @static
+ */
+
+var LANG = Y.Lang,
+
+ SchemaText = {
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSchema.Text static methods
+ //
+ /////////////////////////////////////////////////////////////////////////////
+ /**
+ * Applies a given schema to given delimited text data.
+ *
+ * @method apply
+ * @param schema {Object} Schema to apply.
+ * @param data {Object} Text data.
+ * @return {Object} Schema-parsed data.
+ * @static
+ */
+ apply: function(schema, data) {
+ var data_in = data,
+ data_out = {results:[],meta:{}};
+
+ if(LANG.isString(data_in) && LANG.isString(schema.resultDelimiter)) {
+ // Parse results data
+ data_out = SchemaText._parseResults(schema, data_in, data_out);
+ }
+ else {
+ Y.log("Text data could not be schema-parsed: " + Y.dump(data) + " " + Y.dump(data), "error", "dataschema-text");
+ data_out.error = new Error("Text schema parse failure");
+ }
+
+ return data_out;
+ },
+
+ /**
+ * Schema-parsed list of results from full data
+ *
+ * @method _parseResults
+ * @param schema {Array} Schema to parse against.
+ * @param text_in {String} Text to parse.
+ * @param data_out {Object} In-progress parsed data to update.
+ * @return {Object} Parsed data object.
+ * @static
+ * @protected
+ */
+ _parseResults: function(schema, text_in, data_out) {
+ var resultDelim = schema.resultDelimiter,
+ results = [],
+ results_in, fields_in, result, item, fields, field, key, value, i, j,
+
+ // Delete final delimiter at end of string if there
+ tmpLength = text_in.length-resultDelim.length;
+ if(text_in.substr(tmpLength) == resultDelim) {
+ text_in = text_in.substr(0, tmpLength);
+ }
+
+ // Split into results
+ results_in = text_in.split(schema.resultDelimiter);
+
+ for(i=results_in.length-1; i>-1; i--) {
+ result = {};
+ item = results_in[i];
+
+ if(LANG.isString(schema.fieldDelimiter)) {
+ fields_in = item.split(schema.fieldDelimiter);
+
+ if(LANG.isArray(schema.resultFields)) {
+ fields = schema.resultFields;
+ for(j=fields.length-1; j>-1; j--) {
+ field = fields[j];
+ key = (!LANG.isUndefined(field.key)) ? field.key : field;
+ value = (!LANG.isUndefined(fields_in[key])) ? fields_in[key] : fields_in[j];
+ result[key] = Y.DataSchema.Base.parse(value, field);
+ }
+ }
+
+ }
+ else {
+ result = item;
+ }
+
+ results[i] = result;
+ }
+ data_out.results = results;
+
+ return data_out;
+ }
+ };
+
+Y.DataSchema.Text = Y.mix(SchemaText, Y.DataSchema.Base);
+
+
+
+}, '3.0.0' ,{requires:['dataschema-base']});
diff --git a/lib/yui/3.0.0/dataschema/dataschema-text-min.js b/lib/yui/3.0.0/dataschema/dataschema-text-min.js
new file mode 100644
index 0000000000..59b5d93dd1
--- /dev/null
+++ b/lib/yui/3.0.0/dataschema/dataschema-text-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("dataschema-text",function(C){var B=C.Lang,A={apply:function(F,G){var D=G,E={results:[],meta:{}};if(B.isString(D)&&B.isString(F.resultDelimiter)){E=A._parseResults(F,D,E);}else{E.error=new Error("Text schema parse failure");}return E;},_parseResults:function(D,K,E){var I=D.resultDelimiter,H=[],L,P,S,R,J,N,Q,O,G,F,M=K.length-I.length;if(K.substr(M)==I){K=K.substr(0,M);}L=K.split(D.resultDelimiter);for(G=L.length-1;G>-1;G--){S={};R=L[G];if(B.isString(D.fieldDelimiter)){P=R.split(D.fieldDelimiter);if(B.isArray(D.resultFields)){J=D.resultFields;for(F=J.length-1;F>-1;F--){N=J[F];Q=(!B.isUndefined(N.key))?N.key:N;O=(!B.isUndefined(P[Q]))?P[Q]:P[F];S[Q]=C.DataSchema.Base.parse(O,N);}}}else{S=R;}H[G]=S;}E.results=H;return E;}};C.DataSchema.Text=C.mix(A,C.DataSchema.Base);},"3.0.0",{requires:["dataschema-base"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/dataschema/dataschema-text.js b/lib/yui/3.0.0/dataschema/dataschema-text.js
new file mode 100644
index 0000000000..417517cf92
--- /dev/null
+++ b/lib/yui/3.0.0/dataschema/dataschema-text.js
@@ -0,0 +1,116 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dataschema-text', function(Y) {
+
+/**
+ * Provides a DataSchema implementation which can be used to work with delimited text data.
+ *
+ * @module dataschema
+ * @submodule dataschema-text
+ */
+
+/**
+ * Text subclass for the DataSchema Utility.
+ * @class DataSchema.Text
+ * @extends DataSchema.Base
+ * @static
+ */
+
+var LANG = Y.Lang,
+
+ SchemaText = {
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSchema.Text static methods
+ //
+ /////////////////////////////////////////////////////////////////////////////
+ /**
+ * Applies a given schema to given delimited text data.
+ *
+ * @method apply
+ * @param schema {Object} Schema to apply.
+ * @param data {Object} Text data.
+ * @return {Object} Schema-parsed data.
+ * @static
+ */
+ apply: function(schema, data) {
+ var data_in = data,
+ data_out = {results:[],meta:{}};
+
+ if(LANG.isString(data_in) && LANG.isString(schema.resultDelimiter)) {
+ // Parse results data
+ data_out = SchemaText._parseResults(schema, data_in, data_out);
+ }
+ else {
+ data_out.error = new Error("Text schema parse failure");
+ }
+
+ return data_out;
+ },
+
+ /**
+ * Schema-parsed list of results from full data
+ *
+ * @method _parseResults
+ * @param schema {Array} Schema to parse against.
+ * @param text_in {String} Text to parse.
+ * @param data_out {Object} In-progress parsed data to update.
+ * @return {Object} Parsed data object.
+ * @static
+ * @protected
+ */
+ _parseResults: function(schema, text_in, data_out) {
+ var resultDelim = schema.resultDelimiter,
+ results = [],
+ results_in, fields_in, result, item, fields, field, key, value, i, j,
+
+ // Delete final delimiter at end of string if there
+ tmpLength = text_in.length-resultDelim.length;
+ if(text_in.substr(tmpLength) == resultDelim) {
+ text_in = text_in.substr(0, tmpLength);
+ }
+
+ // Split into results
+ results_in = text_in.split(schema.resultDelimiter);
+
+ for(i=results_in.length-1; i>-1; i--) {
+ result = {};
+ item = results_in[i];
+
+ if(LANG.isString(schema.fieldDelimiter)) {
+ fields_in = item.split(schema.fieldDelimiter);
+
+ if(LANG.isArray(schema.resultFields)) {
+ fields = schema.resultFields;
+ for(j=fields.length-1; j>-1; j--) {
+ field = fields[j];
+ key = (!LANG.isUndefined(field.key)) ? field.key : field;
+ value = (!LANG.isUndefined(fields_in[key])) ? fields_in[key] : fields_in[j];
+ result[key] = Y.DataSchema.Base.parse(value, field);
+ }
+ }
+
+ }
+ else {
+ result = item;
+ }
+
+ results[i] = result;
+ }
+ data_out.results = results;
+
+ return data_out;
+ }
+ };
+
+Y.DataSchema.Text = Y.mix(SchemaText, Y.DataSchema.Base);
+
+
+
+}, '3.0.0' ,{requires:['dataschema-base']});
diff --git a/lib/yui/3.0.0/dataschema/dataschema-xml-debug.js b/lib/yui/3.0.0/dataschema/dataschema-xml-debug.js
new file mode 100644
index 0000000000..60347d9f14
--- /dev/null
+++ b/lib/yui/3.0.0/dataschema/dataschema-xml-debug.js
@@ -0,0 +1,165 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dataschema-xml', function(Y) {
+
+/**
+ * Provides a DataSchema implementation which can be used to work with XML data.
+ *
+ * @module dataschema
+ * @submodule dataschema-xml
+ */
+var LANG = Y.Lang,
+
+ /**
+ * XML subclass for the DataSchema Utility.
+ * @class DataSchema.XML
+ * @extends DataSchema.Base
+ * @static
+ */
+ SchemaXML = {
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSchema.XML static methods
+ //
+ /////////////////////////////////////////////////////////////////////////////
+ /**
+ * Applies a given schema to given XML data.
+ *
+ * @method apply
+ * @param schema {Object} Schema to apply.
+ * @param data {XMLDoc} XML document.
+ * @return {Object} Schema-parsed data.
+ * @static
+ */
+ apply: function(schema, data) {
+ var xmldoc = data,
+ data_out = {results:[],meta:{}};
+
+ if(xmldoc && xmldoc.nodeType && (xmldoc.nodeType === 9 || xmldoc.nodeType === 1 || xmldoc.nodeType === 11) && schema) {
+ // Parse results data
+ data_out = SchemaXML._parseResults(schema, xmldoc, data_out);
+
+ // Parse meta data
+ data_out = SchemaXML._parseMeta(schema.metaFields, xmldoc, data_out);
+ }
+ else {
+ Y.log("XML data could not be schema-parsed: " + Y.dump(data) + " " + Y.dump(data), "error", "dataschema-xml");
+ data_out.error = new Error("XML schema parse failure");
+ }
+
+ return data_out;
+ },
+
+ /**
+ * Get an XPath-specified value for a given field from an XML node or document.
+ *
+ * @method _getLocationValue
+ * @param field {String | Object} Field definition.
+ * @param context {Object} XML node or document to search within.
+ * @return {Object} Data value or null.
+ * @static
+ * @protected
+ */
+ _getLocationValue: function(field, context) {
+ var locator = field.locator || field.key || field,
+ xmldoc = context.ownerDocument || context,
+ result, res, value = null;
+
+ try {
+ // Standards mode
+ if(!LANG.isUndefined(xmldoc.evaluate)) {
+ result = xmldoc.evaluate(locator, context, xmldoc.createNSResolver(!context.ownerDocument ? context.documentElement : context.ownerDocument.documentElement), 0, null);
+ while(res = result.iterateNext()) {
+ value = res.textContent;
+ }
+ }
+ // IE mode
+ else {
+ xmldoc.setProperty("SelectionLanguage", "XPath");
+ result = context.selectNodes(locator)[0];
+ value = result.value || result.text || null;
+ }
+ return Y.DataSchema.Base.parse(value, field);
+
+ }
+ catch(e) {
+ }
+ },
+
+ /**
+ * Parses results data according to schema
+ *
+ * @method _parseMeta
+ * @param xmldoc_in {Object} XML document parse.
+ * @param data_out {Object} In-progress schema-parsed data to update.
+ * @return {Object} Schema-parsed data.
+ * @static
+ * @protected
+ */
+ _parseMeta: function(metaFields, xmldoc_in, data_out) {
+ if(LANG.isObject(metaFields)) {
+ var key,
+ xmldoc = xmldoc_in.ownerDocument || xmldoc_in;
+
+ for(key in metaFields) {
+ if (metaFields.hasOwnProperty(key)) {
+ data_out.meta[key] = SchemaXML._getLocationValue(metaFields[key], xmldoc);
+ }
+ }
+ }
+ return data_out;
+ },
+
+ /**
+ * Schema-parsed list of results from full data
+ *
+ * @method _parseResults
+ * @param schema {Object} Schema to parse against.
+ * @param xmldoc_in {Object} XML document parse.
+ * @param data_out {Object} In-progress schema-parsed data to update.
+ * @return {Object} Schema-parsed data.
+ * @static
+ * @protected
+ */
+ _parseResults: function(schema, xmldoc_in, data_out) {
+ if(schema.resultListLocator && LANG.isArray(schema.resultFields)) {
+ var nodeList = xmldoc_in.getElementsByTagName(schema.resultListLocator),
+ fields = schema.resultFields,
+ results = [],
+ node, field, result, i, j;
+
+ if(nodeList.length) {
+ // Loop through each result node
+ for(i=nodeList.length-1; i>= 0; i--) {
+ result = {};
+ node = nodeList[i];
+
+ // Find each field value
+ for(j=fields.length-1; j>= 0; j--) {
+ field = fields[j];
+ result[field.key || field] = SchemaXML._getLocationValue(field, node);
+ }
+ results[i] = result;
+ }
+
+ data_out.results = results;
+ }
+ else {
+ data_out.error = new Error("XML schema result nodes retrieval failure");
+ }
+ }
+ return data_out;
+ }
+ };
+
+Y.DataSchema.XML = Y.mix(SchemaXML, Y.DataSchema.Base);
+
+
+
+}, '3.0.0' ,{requires:['dataschema-base']});
diff --git a/lib/yui/3.0.0/dataschema/dataschema-xml-min.js b/lib/yui/3.0.0/dataschema/dataschema-xml-min.js
new file mode 100644
index 0000000000..e20dd832a3
--- /dev/null
+++ b/lib/yui/3.0.0/dataschema/dataschema-xml-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("dataschema-xml",function(C){var B=C.Lang,A={apply:function(F,G){var D=G,E={results:[],meta:{}};if(D&&D.nodeType&&(D.nodeType===9||D.nodeType===1||D.nodeType===11)&&F){E=A._parseResults(F,D,E);E=A._parseMeta(F.metaFields,D,E);}else{E.error=new Error("XML schema parse failure");}return E;},_getLocationValue:function(K,H){var F=K.locator||K.key||K,E=H.ownerDocument||H,D,G,I=null;try{if(!B.isUndefined(E.evaluate)){D=E.evaluate(F,H,E.createNSResolver(!H.ownerDocument?H.documentElement:H.ownerDocument.documentElement),0,null);while(G=D.iterateNext()){I=G.textContent;}}else{E.setProperty("SelectionLanguage","XPath");D=H.selectNodes(F)[0];I=D.value||D.text||null;}return C.DataSchema.Base.parse(I,K);}catch(J){}},_parseMeta:function(H,G,F){if(B.isObject(H)){var E,D=G.ownerDocument||G;for(E in H){if(H.hasOwnProperty(E)){F.meta[E]=A._getLocationValue(H[E],D);}}}return F;},_parseResults:function(F,K,G){if(F.resultListLocator&&B.isArray(F.resultFields)){var E=K.getElementsByTagName(F.resultListLocator),L=F.resultFields,J=[],D,M,N,I,H;if(E.length){for(I=E.length-1;I>=0;I--){N={};D=E[I];for(H=L.length-1;H>=0;H--){M=L[H];N[M.key||M]=A._getLocationValue(M,D);}J[I]=N;}G.results=J;}else{G.error=new Error("XML schema result nodes retrieval failure");}}return G;}};C.DataSchema.XML=C.mix(A,C.DataSchema.Base);},"3.0.0",{requires:["dataschema-base"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/dataschema/dataschema-xml.js b/lib/yui/3.0.0/dataschema/dataschema-xml.js
new file mode 100644
index 0000000000..be3d818201
--- /dev/null
+++ b/lib/yui/3.0.0/dataschema/dataschema-xml.js
@@ -0,0 +1,164 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dataschema-xml', function(Y) {
+
+/**
+ * Provides a DataSchema implementation which can be used to work with XML data.
+ *
+ * @module dataschema
+ * @submodule dataschema-xml
+ */
+var LANG = Y.Lang,
+
+ /**
+ * XML subclass for the DataSchema Utility.
+ * @class DataSchema.XML
+ * @extends DataSchema.Base
+ * @static
+ */
+ SchemaXML = {
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSchema.XML static methods
+ //
+ /////////////////////////////////////////////////////////////////////////////
+ /**
+ * Applies a given schema to given XML data.
+ *
+ * @method apply
+ * @param schema {Object} Schema to apply.
+ * @param data {XMLDoc} XML document.
+ * @return {Object} Schema-parsed data.
+ * @static
+ */
+ apply: function(schema, data) {
+ var xmldoc = data,
+ data_out = {results:[],meta:{}};
+
+ if(xmldoc && xmldoc.nodeType && (xmldoc.nodeType === 9 || xmldoc.nodeType === 1 || xmldoc.nodeType === 11) && schema) {
+ // Parse results data
+ data_out = SchemaXML._parseResults(schema, xmldoc, data_out);
+
+ // Parse meta data
+ data_out = SchemaXML._parseMeta(schema.metaFields, xmldoc, data_out);
+ }
+ else {
+ data_out.error = new Error("XML schema parse failure");
+ }
+
+ return data_out;
+ },
+
+ /**
+ * Get an XPath-specified value for a given field from an XML node or document.
+ *
+ * @method _getLocationValue
+ * @param field {String | Object} Field definition.
+ * @param context {Object} XML node or document to search within.
+ * @return {Object} Data value or null.
+ * @static
+ * @protected
+ */
+ _getLocationValue: function(field, context) {
+ var locator = field.locator || field.key || field,
+ xmldoc = context.ownerDocument || context,
+ result, res, value = null;
+
+ try {
+ // Standards mode
+ if(!LANG.isUndefined(xmldoc.evaluate)) {
+ result = xmldoc.evaluate(locator, context, xmldoc.createNSResolver(!context.ownerDocument ? context.documentElement : context.ownerDocument.documentElement), 0, null);
+ while(res = result.iterateNext()) {
+ value = res.textContent;
+ }
+ }
+ // IE mode
+ else {
+ xmldoc.setProperty("SelectionLanguage", "XPath");
+ result = context.selectNodes(locator)[0];
+ value = result.value || result.text || null;
+ }
+ return Y.DataSchema.Base.parse(value, field);
+
+ }
+ catch(e) {
+ }
+ },
+
+ /**
+ * Parses results data according to schema
+ *
+ * @method _parseMeta
+ * @param xmldoc_in {Object} XML document parse.
+ * @param data_out {Object} In-progress schema-parsed data to update.
+ * @return {Object} Schema-parsed data.
+ * @static
+ * @protected
+ */
+ _parseMeta: function(metaFields, xmldoc_in, data_out) {
+ if(LANG.isObject(metaFields)) {
+ var key,
+ xmldoc = xmldoc_in.ownerDocument || xmldoc_in;
+
+ for(key in metaFields) {
+ if (metaFields.hasOwnProperty(key)) {
+ data_out.meta[key] = SchemaXML._getLocationValue(metaFields[key], xmldoc);
+ }
+ }
+ }
+ return data_out;
+ },
+
+ /**
+ * Schema-parsed list of results from full data
+ *
+ * @method _parseResults
+ * @param schema {Object} Schema to parse against.
+ * @param xmldoc_in {Object} XML document parse.
+ * @param data_out {Object} In-progress schema-parsed data to update.
+ * @return {Object} Schema-parsed data.
+ * @static
+ * @protected
+ */
+ _parseResults: function(schema, xmldoc_in, data_out) {
+ if(schema.resultListLocator && LANG.isArray(schema.resultFields)) {
+ var nodeList = xmldoc_in.getElementsByTagName(schema.resultListLocator),
+ fields = schema.resultFields,
+ results = [],
+ node, field, result, i, j;
+
+ if(nodeList.length) {
+ // Loop through each result node
+ for(i=nodeList.length-1; i>= 0; i--) {
+ result = {};
+ node = nodeList[i];
+
+ // Find each field value
+ for(j=fields.length-1; j>= 0; j--) {
+ field = fields[j];
+ result[field.key || field] = SchemaXML._getLocationValue(field, node);
+ }
+ results[i] = result;
+ }
+
+ data_out.results = results;
+ }
+ else {
+ data_out.error = new Error("XML schema result nodes retrieval failure");
+ }
+ }
+ return data_out;
+ }
+ };
+
+Y.DataSchema.XML = Y.mix(SchemaXML, Y.DataSchema.Base);
+
+
+
+}, '3.0.0' ,{requires:['dataschema-base']});
diff --git a/lib/yui/3.0.0/dataschema/dataschema.js b/lib/yui/3.0.0/dataschema/dataschema.js
new file mode 100644
index 0000000000..5090f9e816
--- /dev/null
+++ b/lib/yui/3.0.0/dataschema/dataschema.js
@@ -0,0 +1,735 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dataschema-base', function(Y) {
+
+/**
+ * The DataSchema utility provides a common configurable interface for widgets to
+ * apply a given schema to a variety of data.
+ *
+ * @module dataschema
+ */
+
+/**
+ * Provides the base DataSchema implementation, which can be extended to
+ * create DataSchemas for specific data formats, such XML, JSON, text and
+ * arrays.
+ *
+ * @module dataschema
+ * @submodule dataschema-base
+ */
+
+var LANG = Y.Lang,
+/**
+ * Base class for the YUI DataSchema Utility.
+ * @class DataSchema.Base
+ * @static
+ */
+ SchemaBase = {
+ /**
+ * Overridable method returns data as-is.
+ *
+ * @method apply
+ * @param schema {Object} Schema to apply.
+ * @param data {Object} Data.
+ * @return {Object} Schema-parsed data.
+ * @static
+ */
+ apply: function(schema, data) {
+ return data;
+ },
+
+ /**
+ * Applies field parser, if defined
+ *
+ * @method parse
+ * @param value {Object} Original value.
+ * @param field {Object} Field.
+ * @return {Object} Type-converted value.
+ */
+ parse: function(value, field) {
+ if(field.parser) {
+ var parser = (LANG.isFunction(field.parser)) ?
+ field.parser : Y.Parsers[field.parser+''];
+ if(parser) {
+ value = parser.call(this, value);
+ }
+ else {
+ }
+ }
+ return value;
+ }
+};
+
+Y.namespace("DataSchema").Base = SchemaBase;
+Y.namespace("Parsers");
+
+
+
+}, '3.0.0' ,{requires:['base']});
+
+YUI.add('dataschema-json', function(Y) {
+
+/**
+ * Provides a DataSchema implementation which can be used to work with JSON data.
+ *
+ * @module dataschema
+ * @submodule dataschema-json
+ */
+
+/**
+ * JSON subclass for the DataSchema Utility.
+ * @class DataSchema.JSON
+ * @extends DataSchema.Base
+ * @static
+ */
+var LANG = Y.Lang,
+
+ SchemaJSON = {
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSchema.JSON static methods
+ //
+ /////////////////////////////////////////////////////////////////////////////
+ /**
+ * Utility function converts JSON locator strings into walkable paths
+ *
+ * @method DataSchema.JSON.getPath
+ * @param locator {String} JSON value locator.
+ * @return {String[]} Walkable path to data value.
+ * @static
+ */
+ getPath: function(locator) {
+ var path = null,
+ keys = [],
+ i = 0;
+
+ if (locator) {
+ // Strip the ["string keys"] and [1] array indexes
+ locator = locator.
+ replace(/\[(['"])(.*?)\1\]/g,
+ function (x,$1,$2) {keys[i]=$2;return '.@'+(i++);}).
+ replace(/\[(\d+)\]/g,
+ function (x,$1) {keys[i]=parseInt($1,10)|0;return '.@'+(i++);}).
+ replace(/^\./,''); // remove leading dot
+
+ // Validate against problematic characters.
+ if (!/[^\w\.\$@]/.test(locator)) {
+ path = locator.split('.');
+ for (i=path.length-1; i >= 0; --i) {
+ if (path[i].charAt(0) === '@') {
+ path[i] = keys[parseInt(path[i].substr(1),10)];
+ }
+ }
+ }
+ else {
+ }
+ }
+ return path;
+ },
+
+ /**
+ * Utility function to walk a path and return the value located there.
+ *
+ * @method DataSchema.JSON.getLocationValue
+ * @param path {String[]} Locator path.
+ * @param data {String} Data to traverse.
+ * @return {Object} Data value at location.
+ * @static
+ */
+ getLocationValue: function (path, data) {
+ var i = 0,
+ len = path.length;
+ for (;i=0; --i) {
+ record = {};
+ result = array_in[i];
+ if(result) {
+ // Cycle through simpleLocators
+ for (j=simplePaths.length-1; j>=0; --j) {
+ // Bug 1777850: The result might be an array instead of object
+ record[simplePaths[j].key] = Y.DataSchema.Base.parse(
+ (LANG.isUndefined(result[simplePaths[j].path]) ?
+ result[j] : result[simplePaths[j].path]), simplePaths[j]);
+ }
+
+ // Cycle through complexLocators
+ for (j=complexPaths.length - 1; j>=0; --j) {
+ record[complexPaths[j].key] = Y.DataSchema.Base.parse(
+ (SchemaJSON.getLocationValue(complexPaths[j].path, result)), complexPaths[j] );
+ }
+
+ // Cycle through fieldParsers
+ for (j=fieldParsers.length-1; j>=0; --j) {
+ key = fieldParsers[j].key;
+ record[key] = fieldParsers[j].parser(record[key]);
+ // Safety net
+ if (LANG.isUndefined(record[key])) {
+ record[key] = null;
+ }
+ }
+ results[i] = record;
+ }
+ }
+ data_out.results = results;
+ return data_out;
+ },
+
+ /**
+ * Parses results data according to schema
+ *
+ * @method _parseMeta
+ * @param metaFields {Object} Metafields definitions.
+ * @param json_in {Object} JSON to parse.
+ * @param data_out {Object} In-progress parsed data to update.
+ * @return {Object} Schema-parsed meta data.
+ * @static
+ * @protected
+ */
+ _parseMeta: function(metaFields, json_in, data_out) {
+ if(LANG.isObject(metaFields)) {
+ var key, path;
+ for(key in metaFields) {
+ if (metaFields.hasOwnProperty(key)) {
+ path = SchemaJSON.getPath(metaFields[key]);
+ if (path && json_in) {
+ data_out.meta[key] = SchemaJSON.getLocationValue(path, json_in);
+ }
+ }
+ }
+ }
+ else {
+ data_out.error = new Error("JSON meta data retrieval failure");
+ }
+ return data_out;
+ }
+ };
+
+Y.DataSchema.JSON = Y.mix(SchemaJSON, Y.DataSchema.Base);
+
+
+
+}, '3.0.0' ,{requires:['json', 'dataschema-base']});
+
+YUI.add('dataschema-xml', function(Y) {
+
+/**
+ * Provides a DataSchema implementation which can be used to work with XML data.
+ *
+ * @module dataschema
+ * @submodule dataschema-xml
+ */
+var LANG = Y.Lang,
+
+ /**
+ * XML subclass for the DataSchema Utility.
+ * @class DataSchema.XML
+ * @extends DataSchema.Base
+ * @static
+ */
+ SchemaXML = {
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSchema.XML static methods
+ //
+ /////////////////////////////////////////////////////////////////////////////
+ /**
+ * Applies a given schema to given XML data.
+ *
+ * @method apply
+ * @param schema {Object} Schema to apply.
+ * @param data {XMLDoc} XML document.
+ * @return {Object} Schema-parsed data.
+ * @static
+ */
+ apply: function(schema, data) {
+ var xmldoc = data,
+ data_out = {results:[],meta:{}};
+
+ if(xmldoc && xmldoc.nodeType && (xmldoc.nodeType === 9 || xmldoc.nodeType === 1 || xmldoc.nodeType === 11) && schema) {
+ // Parse results data
+ data_out = SchemaXML._parseResults(schema, xmldoc, data_out);
+
+ // Parse meta data
+ data_out = SchemaXML._parseMeta(schema.metaFields, xmldoc, data_out);
+ }
+ else {
+ data_out.error = new Error("XML schema parse failure");
+ }
+
+ return data_out;
+ },
+
+ /**
+ * Get an XPath-specified value for a given field from an XML node or document.
+ *
+ * @method _getLocationValue
+ * @param field {String | Object} Field definition.
+ * @param context {Object} XML node or document to search within.
+ * @return {Object} Data value or null.
+ * @static
+ * @protected
+ */
+ _getLocationValue: function(field, context) {
+ var locator = field.locator || field.key || field,
+ xmldoc = context.ownerDocument || context,
+ result, res, value = null;
+
+ try {
+ // Standards mode
+ if(!LANG.isUndefined(xmldoc.evaluate)) {
+ result = xmldoc.evaluate(locator, context, xmldoc.createNSResolver(!context.ownerDocument ? context.documentElement : context.ownerDocument.documentElement), 0, null);
+ while(res = result.iterateNext()) {
+ value = res.textContent;
+ }
+ }
+ // IE mode
+ else {
+ xmldoc.setProperty("SelectionLanguage", "XPath");
+ result = context.selectNodes(locator)[0];
+ value = result.value || result.text || null;
+ }
+ return Y.DataSchema.Base.parse(value, field);
+
+ }
+ catch(e) {
+ }
+ },
+
+ /**
+ * Parses results data according to schema
+ *
+ * @method _parseMeta
+ * @param xmldoc_in {Object} XML document parse.
+ * @param data_out {Object} In-progress schema-parsed data to update.
+ * @return {Object} Schema-parsed data.
+ * @static
+ * @protected
+ */
+ _parseMeta: function(metaFields, xmldoc_in, data_out) {
+ if(LANG.isObject(metaFields)) {
+ var key,
+ xmldoc = xmldoc_in.ownerDocument || xmldoc_in;
+
+ for(key in metaFields) {
+ if (metaFields.hasOwnProperty(key)) {
+ data_out.meta[key] = SchemaXML._getLocationValue(metaFields[key], xmldoc);
+ }
+ }
+ }
+ return data_out;
+ },
+
+ /**
+ * Schema-parsed list of results from full data
+ *
+ * @method _parseResults
+ * @param schema {Object} Schema to parse against.
+ * @param xmldoc_in {Object} XML document parse.
+ * @param data_out {Object} In-progress schema-parsed data to update.
+ * @return {Object} Schema-parsed data.
+ * @static
+ * @protected
+ */
+ _parseResults: function(schema, xmldoc_in, data_out) {
+ if(schema.resultListLocator && LANG.isArray(schema.resultFields)) {
+ var nodeList = xmldoc_in.getElementsByTagName(schema.resultListLocator),
+ fields = schema.resultFields,
+ results = [],
+ node, field, result, i, j;
+
+ if(nodeList.length) {
+ // Loop through each result node
+ for(i=nodeList.length-1; i>= 0; i--) {
+ result = {};
+ node = nodeList[i];
+
+ // Find each field value
+ for(j=fields.length-1; j>= 0; j--) {
+ field = fields[j];
+ result[field.key || field] = SchemaXML._getLocationValue(field, node);
+ }
+ results[i] = result;
+ }
+
+ data_out.results = results;
+ }
+ else {
+ data_out.error = new Error("XML schema result nodes retrieval failure");
+ }
+ }
+ return data_out;
+ }
+ };
+
+Y.DataSchema.XML = Y.mix(SchemaXML, Y.DataSchema.Base);
+
+
+
+}, '3.0.0' ,{requires:['dataschema-base']});
+
+YUI.add('dataschema-array', function(Y) {
+
+/**
+ * Provides a DataSchema implementation which can be used to work with data stored in arrays.
+ *
+ * @module dataschema
+ * @submodule dataschema-array
+ */
+
+/**
+ * Array subclass for the DataSchema Utility.
+ * @class DataSchema.Array
+ * @extends DataSchema.Base
+ * @static
+ */
+var LANG = Y.Lang,
+
+ SchemaArray = {
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSchema.Array static methods
+ //
+ /////////////////////////////////////////////////////////////////////////////
+ /**
+ * Applies a given schema to given Array data.
+ *
+ * @method apply
+ * @param schema {Object} Schema to apply.
+ * @param data {Object} Array data.
+ * @return {Object} Schema-parsed data.
+ * @static
+ */
+ apply: function(schema, data) {
+ var data_in = data,
+ data_out = {results:[],meta:{}};
+
+ if(LANG.isArray(data_in)) {
+ if(LANG.isArray(schema.resultFields)) {
+ // Parse results data
+ data_out = SchemaArray._parseResults(schema.resultFields, data_in, data_out);
+ }
+ else {
+ data_out.results = data_in;
+ }
+ }
+ else {
+ data_out.error = new Error("Array schema parse failure");
+ }
+
+ return data_out;
+ },
+
+ /**
+ * Schema-parsed list of results from full data
+ *
+ * @method _parseResults
+ * @param fields {Array} Schema to parse against.
+ * @param array_in {Array} Array to parse.
+ * @param data_out {Object} In-progress parsed data to update.
+ * @return {Object} Parsed data object.
+ * @static
+ * @protected
+ */
+ _parseResults: function(fields, array_in, data_out) {
+ var results = [],
+ result, item, type, field, key, value, i, j;
+
+ for(i=array_in.length-1; i>-1; i--) {
+ result = {};
+ item = array_in[i];
+ type = (LANG.isObject(item) && !LANG.isFunction(item)) ? 2 : (LANG.isArray(item)) ? 1 : (LANG.isString(item)) ? 0 : -1;
+ if(type > 0) {
+ for(j=fields.length-1; j>-1; j--) {
+ field = fields[j];
+ key = (!LANG.isUndefined(field.key)) ? field.key : field;
+ value = (!LANG.isUndefined(item[key])) ? item[key] : item[j];
+ result[key] = Y.DataSchema.Base.parse(value, field);
+ }
+ }
+ else if(type === 0) {
+ result = item;
+ }
+ else {
+ //TODO: null or {}?
+ result = null;
+ }
+ results[i] = result;
+ }
+ data_out.results = results;
+
+ return data_out;
+ }
+ };
+
+Y.DataSchema.Array = Y.mix(SchemaArray, Y.DataSchema.Base);
+
+
+
+}, '3.0.0' ,{requires:['dataschema-base']});
+
+YUI.add('dataschema-text', function(Y) {
+
+/**
+ * Provides a DataSchema implementation which can be used to work with delimited text data.
+ *
+ * @module dataschema
+ * @submodule dataschema-text
+ */
+
+/**
+ * Text subclass for the DataSchema Utility.
+ * @class DataSchema.Text
+ * @extends DataSchema.Base
+ * @static
+ */
+
+var LANG = Y.Lang,
+
+ SchemaText = {
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSchema.Text static methods
+ //
+ /////////////////////////////////////////////////////////////////////////////
+ /**
+ * Applies a given schema to given delimited text data.
+ *
+ * @method apply
+ * @param schema {Object} Schema to apply.
+ * @param data {Object} Text data.
+ * @return {Object} Schema-parsed data.
+ * @static
+ */
+ apply: function(schema, data) {
+ var data_in = data,
+ data_out = {results:[],meta:{}};
+
+ if(LANG.isString(data_in) && LANG.isString(schema.resultDelimiter)) {
+ // Parse results data
+ data_out = SchemaText._parseResults(schema, data_in, data_out);
+ }
+ else {
+ data_out.error = new Error("Text schema parse failure");
+ }
+
+ return data_out;
+ },
+
+ /**
+ * Schema-parsed list of results from full data
+ *
+ * @method _parseResults
+ * @param schema {Array} Schema to parse against.
+ * @param text_in {String} Text to parse.
+ * @param data_out {Object} In-progress parsed data to update.
+ * @return {Object} Parsed data object.
+ * @static
+ * @protected
+ */
+ _parseResults: function(schema, text_in, data_out) {
+ var resultDelim = schema.resultDelimiter,
+ results = [],
+ results_in, fields_in, result, item, fields, field, key, value, i, j,
+
+ // Delete final delimiter at end of string if there
+ tmpLength = text_in.length-resultDelim.length;
+ if(text_in.substr(tmpLength) == resultDelim) {
+ text_in = text_in.substr(0, tmpLength);
+ }
+
+ // Split into results
+ results_in = text_in.split(schema.resultDelimiter);
+
+ for(i=results_in.length-1; i>-1; i--) {
+ result = {};
+ item = results_in[i];
+
+ if(LANG.isString(schema.fieldDelimiter)) {
+ fields_in = item.split(schema.fieldDelimiter);
+
+ if(LANG.isArray(schema.resultFields)) {
+ fields = schema.resultFields;
+ for(j=fields.length-1; j>-1; j--) {
+ field = fields[j];
+ key = (!LANG.isUndefined(field.key)) ? field.key : field;
+ value = (!LANG.isUndefined(fields_in[key])) ? fields_in[key] : fields_in[j];
+ result[key] = Y.DataSchema.Base.parse(value, field);
+ }
+ }
+
+ }
+ else {
+ result = item;
+ }
+
+ results[i] = result;
+ }
+ data_out.results = results;
+
+ return data_out;
+ }
+ };
+
+Y.DataSchema.Text = Y.mix(SchemaText, Y.DataSchema.Base);
+
+
+
+}, '3.0.0' ,{requires:['dataschema-base']});
+
+
+
+YUI.add('dataschema', function(Y){}, '3.0.0' ,{use:['dataschema-base','dataschema-json','dataschema-xml','dataschema-array','dataschema-text']});
+
diff --git a/lib/yui/3.0.0/datasource/datasource-arrayschema-debug.js b/lib/yui/3.0.0/datasource/datasource-arrayschema-debug.js
new file mode 100644
index 0000000000..7011cc2e2d
--- /dev/null
+++ b/lib/yui/3.0.0/datasource/datasource-arrayschema-debug.js
@@ -0,0 +1,113 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('datasource-arrayschema', function(Y) {
+
+/**
+ * Extends DataSource with schema-parsing on array data.
+ *
+ * @module datasource
+ * @submodule datasource-arrayschema
+ */
+
+/**
+ * Adds schema-parsing to the DataSource Utility.
+ * @class DataSourceArraySchema
+ * @extends Plugin.Base
+ */
+var DataSourceArraySchema = function() {
+ DataSourceArraySchema.superclass.constructor.apply(this, arguments);
+};
+
+Y.mix(DataSourceArraySchema, {
+ /**
+ * The namespace for the plugin. This will be the property on the host which
+ * references the plugin instance.
+ *
+ * @property NS
+ * @type String
+ * @static
+ * @final
+ * @value "schema"
+ */
+ NS: "schema",
+
+ /**
+ * Class name.
+ *
+ * @property NAME
+ * @type String
+ * @static
+ * @final
+ * @value "dataSourceArraySchema"
+ */
+ NAME: "dataSourceArraySchema",
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSourceArraySchema Attributes
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ ATTRS: {
+ schema: {
+ //value: {}
+ }
+ }
+});
+
+Y.extend(DataSourceArraySchema, Y.Plugin.Base, {
+ /**
+ * Internal init() handler.
+ *
+ * @method initializer
+ * @param config {Object} Config object.
+ * @private
+ */
+ initializer: function(config) {
+ this.doBefore("_defDataFn", this._beforeDefDataFn);
+ },
+
+ /**
+ * Parses raw data into a normalized response.
+ *
+ * @method _beforeDefDataFn
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
data (Object)
Raw data.
+ *
+ * @protected
+ */
+ _beforeDefDataFn: function(e) {
+ var data = (Y.DataSource.IO && (this.get("host") instanceof Y.DataSource.IO) && Y.Lang.isString(e.data.responseText)) ? e.data.responseText : e.data,
+ response = Y.DataSchema.Array.apply(this.get("schema"), data);
+
+ // Default
+ if(!response) {
+ response = {
+ meta: {},
+ results: data
+ };
+ }
+
+ this.get("host").fire("response", Y.mix({response:response}, e));
+ return new Y.Do.Halt("DataSourceArraySchema plugin halted _defDataFn");
+ }
+});
+
+Y.namespace('Plugin').DataSourceArraySchema = DataSourceArraySchema;
+
+
+
+}, '3.0.0' ,{requires:['plugin', 'datasource-local', 'dataschema-array']});
diff --git a/lib/yui/3.0.0/datasource/datasource-arrayschema-min.js b/lib/yui/3.0.0/datasource/datasource-arrayschema-min.js
new file mode 100644
index 0000000000..6c229d14b9
--- /dev/null
+++ b/lib/yui/3.0.0/datasource/datasource-arrayschema-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("datasource-arrayschema",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};B.mix(A,{NS:"schema",NAME:"dataSourceArraySchema",ATTRS:{schema:{}}});B.extend(A,B.Plugin.Base,{initializer:function(C){this.doBefore("_defDataFn",this._beforeDefDataFn);},_beforeDefDataFn:function(E){var D=(B.DataSource.IO&&(this.get("host") instanceof B.DataSource.IO)&&B.Lang.isString(E.data.responseText))?E.data.responseText:E.data,C=B.DataSchema.Array.apply(this.get("schema"),D);if(!C){C={meta:{},results:D};}this.get("host").fire("response",B.mix({response:C},E));return new B.Do.Halt("DataSourceArraySchema plugin halted _defDataFn");}});B.namespace("Plugin").DataSourceArraySchema=A;},"3.0.0",{requires:["plugin","datasource-local","dataschema-array"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/datasource/datasource-arrayschema.js b/lib/yui/3.0.0/datasource/datasource-arrayschema.js
new file mode 100644
index 0000000000..7011cc2e2d
--- /dev/null
+++ b/lib/yui/3.0.0/datasource/datasource-arrayschema.js
@@ -0,0 +1,113 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('datasource-arrayschema', function(Y) {
+
+/**
+ * Extends DataSource with schema-parsing on array data.
+ *
+ * @module datasource
+ * @submodule datasource-arrayschema
+ */
+
+/**
+ * Adds schema-parsing to the DataSource Utility.
+ * @class DataSourceArraySchema
+ * @extends Plugin.Base
+ */
+var DataSourceArraySchema = function() {
+ DataSourceArraySchema.superclass.constructor.apply(this, arguments);
+};
+
+Y.mix(DataSourceArraySchema, {
+ /**
+ * The namespace for the plugin. This will be the property on the host which
+ * references the plugin instance.
+ *
+ * @property NS
+ * @type String
+ * @static
+ * @final
+ * @value "schema"
+ */
+ NS: "schema",
+
+ /**
+ * Class name.
+ *
+ * @property NAME
+ * @type String
+ * @static
+ * @final
+ * @value "dataSourceArraySchema"
+ */
+ NAME: "dataSourceArraySchema",
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSourceArraySchema Attributes
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ ATTRS: {
+ schema: {
+ //value: {}
+ }
+ }
+});
+
+Y.extend(DataSourceArraySchema, Y.Plugin.Base, {
+ /**
+ * Internal init() handler.
+ *
+ * @method initializer
+ * @param config {Object} Config object.
+ * @private
+ */
+ initializer: function(config) {
+ this.doBefore("_defDataFn", this._beforeDefDataFn);
+ },
+
+ /**
+ * Parses raw data into a normalized response.
+ *
+ * @method _beforeDefDataFn
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
data (Object)
Raw data.
+ *
+ * @protected
+ */
+ _beforeDefDataFn: function(e) {
+ var data = (Y.DataSource.IO && (this.get("host") instanceof Y.DataSource.IO) && Y.Lang.isString(e.data.responseText)) ? e.data.responseText : e.data,
+ response = Y.DataSchema.Array.apply(this.get("schema"), data);
+
+ // Default
+ if(!response) {
+ response = {
+ meta: {},
+ results: data
+ };
+ }
+
+ this.get("host").fire("response", Y.mix({response:response}, e));
+ return new Y.Do.Halt("DataSourceArraySchema plugin halted _defDataFn");
+ }
+});
+
+Y.namespace('Plugin').DataSourceArraySchema = DataSourceArraySchema;
+
+
+
+}, '3.0.0' ,{requires:['plugin', 'datasource-local', 'dataschema-array']});
diff --git a/lib/yui/3.0.0/datasource/datasource-cache-debug.js b/lib/yui/3.0.0/datasource/datasource-cache-debug.js
new file mode 100644
index 0000000000..19c96694c3
--- /dev/null
+++ b/lib/yui/3.0.0/datasource/datasource-cache-debug.js
@@ -0,0 +1,136 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('datasource-cache', function(Y) {
+
+/**
+ * Extends DataSource with caching functionality.
+ *
+ * @module datasource
+ * @submodule datasource-cache
+ */
+
+/**
+ * Adds cacheability to the DataSource Utility.
+ * @class DataSourceCache
+ * @extends Cache
+ */
+var DataSourceCache = function() {
+ DataSourceCache.superclass.constructor.apply(this, arguments);
+};
+
+Y.mix(DataSourceCache, {
+ /**
+ * The namespace for the plugin. This will be the property on the host which
+ * references the plugin instance.
+ *
+ * @property NS
+ * @type String
+ * @static
+ * @final
+ * @value "cache"
+ */
+ NS: "cache",
+
+ /**
+ * Class name.
+ *
+ * @property NAME
+ * @type String
+ * @static
+ * @final
+ * @value "dataSourceCache"
+ */
+ NAME: "dataSourceCache",
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSourceCache Attributes
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ ATTRS: {
+
+ }
+});
+
+Y.extend(DataSourceCache, Y.Cache, {
+ /**
+ * Internal init() handler.
+ *
+ * @method initializer
+ * @param config {Object} Config object.
+ * @private
+ */
+ initializer: function(config) {
+ this.doBefore("_defRequestFn", this._beforeDefRequestFn);
+ this.doBefore("_defResponseFn", this._beforeDefResponseFn);
+ },
+
+ /**
+ * First look for cached response, then send request to live data.
+ *
+ * @method _beforeDefRequestFn
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object.
+ *
cfg (Object)
Configuration object.
+ *
+ * @protected
+ */
+ _beforeDefRequestFn: function(e) {
+ // Is response already in the Cache?
+ var entry = (this.retrieve(e.request)) || null;
+ if(entry && entry.response) {
+ this.get("host").fire("response", Y.mix({response: entry.response}, e));
+ return new Y.Do.Halt("DataSourceCache plugin halted _defRequestFn");
+ }
+ },
+
+ /**
+ * Adds data to cache before returning data.
+ *
+ * @method _beforeDefResponseFn
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
data (Object)
Raw data.
+ *
response (Object)
Normalized response object with the following properties:
+ *
+ *
cached (Object)
True when response is cached.
+ *
results (Object)
Parsed results.
+ *
meta (Object)
Parsed meta data.
+ *
error (Object)
Error object.
+ *
+ *
+ *
cfg (Object)
Configuration object.
+ *
+ * @protected
+ */
+ _beforeDefResponseFn: function(e) {
+ // Add to Cache before returning
+ if(e.response && !e.response.cached) {
+ e.response.cached = true;
+ this.add(e.request, e.response, (e.callback && e.callback.argument));
+ }
+ }
+});
+
+Y.namespace('Plugin').DataSourceCache = DataSourceCache;
+
+
+
+}, '3.0.0' ,{requires:['datasource-local', 'cache']});
diff --git a/lib/yui/3.0.0/datasource/datasource-cache-min.js b/lib/yui/3.0.0/datasource/datasource-cache-min.js
new file mode 100644
index 0000000000..dd5888f419
--- /dev/null
+++ b/lib/yui/3.0.0/datasource/datasource-cache-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("datasource-cache",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};B.mix(A,{NS:"cache",NAME:"dataSourceCache",ATTRS:{}});B.extend(A,B.Cache,{initializer:function(C){this.doBefore("_defRequestFn",this._beforeDefRequestFn);this.doBefore("_defResponseFn",this._beforeDefResponseFn);},_beforeDefRequestFn:function(D){var C=(this.retrieve(D.request))||null;if(C&&C.response){this.get("host").fire("response",B.mix({response:C.response},D));return new B.Do.Halt("DataSourceCache plugin halted _defRequestFn");}},_beforeDefResponseFn:function(C){if(C.response&&!C.response.cached){C.response.cached=true;this.add(C.request,C.response,(C.callback&&C.callback.argument));}}});B.namespace("Plugin").DataSourceCache=A;},"3.0.0",{requires:["datasource-local","cache"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/datasource/datasource-cache.js b/lib/yui/3.0.0/datasource/datasource-cache.js
new file mode 100644
index 0000000000..19c96694c3
--- /dev/null
+++ b/lib/yui/3.0.0/datasource/datasource-cache.js
@@ -0,0 +1,136 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('datasource-cache', function(Y) {
+
+/**
+ * Extends DataSource with caching functionality.
+ *
+ * @module datasource
+ * @submodule datasource-cache
+ */
+
+/**
+ * Adds cacheability to the DataSource Utility.
+ * @class DataSourceCache
+ * @extends Cache
+ */
+var DataSourceCache = function() {
+ DataSourceCache.superclass.constructor.apply(this, arguments);
+};
+
+Y.mix(DataSourceCache, {
+ /**
+ * The namespace for the plugin. This will be the property on the host which
+ * references the plugin instance.
+ *
+ * @property NS
+ * @type String
+ * @static
+ * @final
+ * @value "cache"
+ */
+ NS: "cache",
+
+ /**
+ * Class name.
+ *
+ * @property NAME
+ * @type String
+ * @static
+ * @final
+ * @value "dataSourceCache"
+ */
+ NAME: "dataSourceCache",
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSourceCache Attributes
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ ATTRS: {
+
+ }
+});
+
+Y.extend(DataSourceCache, Y.Cache, {
+ /**
+ * Internal init() handler.
+ *
+ * @method initializer
+ * @param config {Object} Config object.
+ * @private
+ */
+ initializer: function(config) {
+ this.doBefore("_defRequestFn", this._beforeDefRequestFn);
+ this.doBefore("_defResponseFn", this._beforeDefResponseFn);
+ },
+
+ /**
+ * First look for cached response, then send request to live data.
+ *
+ * @method _beforeDefRequestFn
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object.
+ *
cfg (Object)
Configuration object.
+ *
+ * @protected
+ */
+ _beforeDefRequestFn: function(e) {
+ // Is response already in the Cache?
+ var entry = (this.retrieve(e.request)) || null;
+ if(entry && entry.response) {
+ this.get("host").fire("response", Y.mix({response: entry.response}, e));
+ return new Y.Do.Halt("DataSourceCache plugin halted _defRequestFn");
+ }
+ },
+
+ /**
+ * Adds data to cache before returning data.
+ *
+ * @method _beforeDefResponseFn
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
data (Object)
Raw data.
+ *
response (Object)
Normalized response object with the following properties:
+ *
+ *
cached (Object)
True when response is cached.
+ *
results (Object)
Parsed results.
+ *
meta (Object)
Parsed meta data.
+ *
error (Object)
Error object.
+ *
+ *
+ *
cfg (Object)
Configuration object.
+ *
+ * @protected
+ */
+ _beforeDefResponseFn: function(e) {
+ // Add to Cache before returning
+ if(e.response && !e.response.cached) {
+ e.response.cached = true;
+ this.add(e.request, e.response, (e.callback && e.callback.argument));
+ }
+ }
+});
+
+Y.namespace('Plugin').DataSourceCache = DataSourceCache;
+
+
+
+}, '3.0.0' ,{requires:['datasource-local', 'cache']});
diff --git a/lib/yui/3.0.0/datasource/datasource-debug.js b/lib/yui/3.0.0/datasource/datasource-debug.js
new file mode 100644
index 0000000000..ad6b218bfb
--- /dev/null
+++ b/lib/yui/3.0.0/datasource/datasource-debug.js
@@ -0,0 +1,1471 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('datasource-local', function(Y) {
+
+/**
+ * The DataSource utility provides a common configurable interface for widgets to
+ * access a variety of data, from JavaScript arrays to online database servers.
+ *
+ * @module datasource
+ */
+
+/**
+ * Provides the base DataSource implementation, which can be extended to
+ * create DataSources for specific data protocols, such as the IO Utility, the
+ * Get Utility, or custom functions.
+ *
+ * @module datasource
+ * @submodule datasource-local
+ */
+
+/**
+ * Base class for the DataSource Utility.
+ * @class DataSource.Local
+ * @extends Base
+ * @constructor
+ */
+var LANG = Y.Lang,
+
+DSLocal = function() {
+ DSLocal.superclass.constructor.apply(this, arguments);
+};
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSource static properties
+ //
+ /////////////////////////////////////////////////////////////////////////////
+Y.mix(DSLocal, {
+ /**
+ * Class name.
+ *
+ * @property NAME
+ * @type String
+ * @static
+ * @final
+ * @value "dataSourceLocal"
+ */
+ NAME: "dataSourceLocal",
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSource Attributes
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ ATTRS: {
+ /**
+ * @attribute source
+ * @description Pointer to live data.
+ * @type MIXED
+ * @default null
+ */
+ source: {
+ value: null
+ }
+ },
+
+ /**
+ * Global transaction counter.
+ *
+ * @property DataSource._tId
+ * @type Number
+ * @static
+ * @private
+ * @default 0
+ */
+ _tId: 0,
+
+ /**
+ * Executes a given callback. The third param determines whether to execute
+ *
+ * @method DataSource.issueCallback
+ * @param callback {Object} The callback object.
+ * @param params {Array} params to be passed to the callback method
+ * @param error {Boolean} whether an error occurred
+ * @static
+ */
+ issueCallback: function (e) {
+ if(e.callback) {
+ var callbackFunc = (e.error && e.callback.failure) || e.callback.success;
+ if (callbackFunc) {
+ callbackFunc(e);
+ }
+ }
+ }
+});
+
+Y.extend(DSLocal, Y.Base, {
+ /**
+ * Internal init() handler.
+ *
+ * @method initializer
+ * @param config {Object} Config object.
+ * @private
+ */
+ initializer: function(config) {
+ this._initEvents();
+ },
+
+ /**
+ * This method creates all the events for this module.
+ * @method _initEvents
+ * @private
+ */
+ _initEvents: function() {
+ /**
+ * Fired when a data request is received.
+ *
+ * @event request
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object.
+ *
cfg (Object)
Configuration object.
+ *
+ * @preventable _defRequestFn
+ */
+ this.publish("request", {defaultFn: Y.bind("_defRequestFn", this), queuable:true});
+
+ /**
+ * Fired when raw data is received.
+ *
+ * @event data
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
cfg (Object)
Configuration object.
+ *
data (Object)
Raw data.
+ *
+ * @preventable _defDataFn
+ */
+ this.publish("data", {defaultFn: Y.bind("_defDataFn", this), queuable:true});
+
+ /**
+ * Fired when response is returned.
+ *
+ * @event response
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
cfg (Object)
Configuration object.
+ *
data (Object)
Raw data.
+ *
response (Object)
Normalized response object with the following properties:
+ *
+ *
results (Object)
Parsed results.
+ *
meta (Object)
Parsed meta data.
+ *
error (Boolean)
Error flag.
+ *
+ *
+ *
+ * @preventable _defResponseFn
+ */
+ this.publish("response", {defaultFn: Y.bind("_defResponseFn", this), queuable:true});
+
+ /**
+ * Fired when an error is encountered.
+ *
+ * @event error
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
cfg (Object)
Configuration object.
+ *
data (Object)
Raw data.
+ *
response (Object)
Normalized response object with the following properties:
+ *
+ *
results (Object)
Parsed results.
+ *
meta (Object)
Parsed meta data.
+ *
error (Object)
Error object.
+ *
+ *
+ *
+ */
+
+ },
+
+ /**
+ * Manages request/response transaction. Must fire response
+ * event when response is received. This method should be implemented by
+ * subclasses to achieve more complex behavior such as accessing remote data.
+ *
+ * @method _defRequestFn
+ * @param e {Event.Facade} Event Facadewith the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
cfg (Object)
Configuration object.
+ *
+ * @protected
+ */
+ _defRequestFn: function(e) {
+ var data = this.get("source");
+
+ // Problematic data
+ if(LANG.isUndefined(data)) {
+ e.error = new Error("Local source undefined");
+ }
+ if(e.error) {
+ this.fire("error", e);
+ Y.log("Error in response", "error", "datasource-local");
+ }
+
+ this.fire("data", Y.mix({data:data}, e));
+ Y.log("Transaction " + e.tId + " complete. Request: " +
+ Y.dump(e.request) + " . Response: " + Y.dump(e.response), "info", "datasource-local");
+ },
+
+ /**
+ * Normalizes raw data into a response that includes results and meta properties.
+ *
+ * @method _defDataFn
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
cfg (Object)
Configuration object.
+ *
data (Object)
Raw data.
+ *
+ * @protected
+ */
+ _defDataFn: function(e) {
+ var data = e.data,
+ meta = e.meta,
+ response = {
+ results: (LANG.isArray(data)) ? data : [data],
+ meta: (meta) ? meta : {}
+ };
+
+ this.fire("response", Y.mix({response: response}, e));
+ },
+
+ /**
+ * Sends data as a normalized response to callback.
+ *
+ * @method _defResponseFn
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
cfg (Object)
Configuration object.
+ *
data (Object)
Raw data.
+ *
response (Object)
Normalized response object with the following properties:
+ *
+ *
results (Object)
Parsed results.
+ *
meta (Object)
Parsed meta data.
+ *
error (Boolean)
Error flag.
+ *
+ *
+ *
+ * @protected
+ */
+ _defResponseFn: function(e) {
+ // Send the response back to the callback
+ DSLocal.issueCallback(e);
+ },
+
+ /**
+ * Generates a unique transaction ID and fires request event.
+ *
+ * @method sendRequest
+ * @param request {Object} Request.
+ * @param callback {Object} An object literal with the following properties:
+ *
+ *
success
+ *
The function to call when the data is ready.
+ *
failure
+ *
The function to call upon a response failure condition.
+ *
argument
+ *
Arbitrary data payload that will be passed back to the success and failure handlers.
Array of queued request objects: {request:request, callback:callback}.
+ *
+ * @type Object
+ * @default {interval:null, conn:null, requests:[]}
+ * @private
+ */
+ _queue: null,
+
+ /**
+ * Passes query string to IO. Fires response event when
+ * response is received asynchronously.
+ *
+ * @method _defRequestFn
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
cfg (Object)
Configuration object.
+ *
+ * @protected
+ */
+ _defRequestFn: function(e) {
+ var uri = this.get("source"),
+ io = this.get("io"),
+ request = e.request,
+ cfg = Y.mix(e.cfg, {
+ on: {
+ success: function (id, response, e) {
+ this.fire("data", Y.mix({data:response}, e));
+ },
+ failure: function (id, response, e) {
+ e.error = new Error("IO data failure");
+ this.fire("error", Y.mix({data:response}, e));
+ this.fire("data", Y.mix({data:response}, e));
+ }
+ },
+ context: this,
+ arguments: e
+ });
+
+ // Support for POST transactions
+ if(Y.Lang.isString(request)) {
+ if(cfg.method && (cfg.method.toUpperCase() === "POST")) {
+ cfg.data = cfg.data ? cfg.data+request : request;
+ }
+ else {
+ uri += request;
+ }
+ }
+ io(uri, cfg);
+ return e.tId;
+ }
+});
+
+Y.DataSource.IO = DSIO;
+
+
+
+
+}, '3.0.0' ,{requires:['datasource-local', 'io']});
diff --git a/lib/yui/3.0.0/datasource/datasource-jsonschema-debug.js b/lib/yui/3.0.0/datasource/datasource-jsonschema-debug.js
new file mode 100644
index 0000000000..afc316f406
--- /dev/null
+++ b/lib/yui/3.0.0/datasource/datasource-jsonschema-debug.js
@@ -0,0 +1,113 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('datasource-jsonschema', function(Y) {
+
+/**
+ * Extends DataSource with schema-parsing on JSON data.
+ *
+ * @module datasource
+ * @submodule datasource-jsonschema
+ */
+
+/**
+ * Adds schema-parsing to the DataSource Utility.
+ * @class DataSourceJSONSchema
+ * @extends Plugin.Base
+ */
+var DataSourceJSONSchema = function() {
+ DataSourceJSONSchema.superclass.constructor.apply(this, arguments);
+};
+
+Y.mix(DataSourceJSONSchema, {
+ /**
+ * The namespace for the plugin. This will be the property on the host which
+ * references the plugin instance.
+ *
+ * @property NS
+ * @type String
+ * @static
+ * @final
+ * @value "schema"
+ */
+ NS: "schema",
+
+ /**
+ * Class name.
+ *
+ * @property NAME
+ * @type String
+ * @static
+ * @final
+ * @value "dataSourceJSONSchema"
+ */
+ NAME: "dataSourceJSONSchema",
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSourceJSONSchema Attributes
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ ATTRS: {
+ schema: {
+ //value: {}
+ }
+ }
+});
+
+Y.extend(DataSourceJSONSchema, Y.Plugin.Base, {
+ /**
+ * Internal init() handler.
+ *
+ * @method initializer
+ * @param config {Object} Config object.
+ * @private
+ */
+ initializer: function(config) {
+ this.doBefore("_defDataFn", this._beforeDefDataFn);
+ },
+
+ /**
+ * Parses raw data into a normalized response.
+ *
+ * @method _beforeDefDataFn
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
data (Object)
Raw data.
+ *
+ * @protected
+ */
+ _beforeDefDataFn: function(e) {
+ var data = (Y.DataSource.IO && (this.get("host") instanceof Y.DataSource.IO) && Y.Lang.isString(e.data.responseText)) ? e.data.responseText : e.data,
+ response = Y.DataSchema.JSON.apply(this.get("schema"), data);
+
+ // Default
+ if(!response) {
+ response = {
+ meta: {},
+ results: data
+ };
+ }
+
+ this.get("host").fire("response", Y.mix({response:response}, e));
+ return new Y.Do.Halt("DataSourceJSONSchema plugin halted _defDataFn");
+ }
+});
+
+Y.namespace('Plugin').DataSourceJSONSchema = DataSourceJSONSchema;
+
+
+
+}, '3.0.0' ,{requires:['plugin', 'datasource-local', 'dataschema-json']});
diff --git a/lib/yui/3.0.0/datasource/datasource-jsonschema-min.js b/lib/yui/3.0.0/datasource/datasource-jsonschema-min.js
new file mode 100644
index 0000000000..930917be65
--- /dev/null
+++ b/lib/yui/3.0.0/datasource/datasource-jsonschema-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("datasource-jsonschema",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};B.mix(A,{NS:"schema",NAME:"dataSourceJSONSchema",ATTRS:{schema:{}}});B.extend(A,B.Plugin.Base,{initializer:function(C){this.doBefore("_defDataFn",this._beforeDefDataFn);},_beforeDefDataFn:function(E){var D=(B.DataSource.IO&&(this.get("host") instanceof B.DataSource.IO)&&B.Lang.isString(E.data.responseText))?E.data.responseText:E.data,C=B.DataSchema.JSON.apply(this.get("schema"),D);if(!C){C={meta:{},results:D};}this.get("host").fire("response",B.mix({response:C},E));return new B.Do.Halt("DataSourceJSONSchema plugin halted _defDataFn");}});B.namespace("Plugin").DataSourceJSONSchema=A;},"3.0.0",{requires:["plugin","datasource-local","dataschema-json"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/datasource/datasource-jsonschema.js b/lib/yui/3.0.0/datasource/datasource-jsonschema.js
new file mode 100644
index 0000000000..afc316f406
--- /dev/null
+++ b/lib/yui/3.0.0/datasource/datasource-jsonschema.js
@@ -0,0 +1,113 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('datasource-jsonschema', function(Y) {
+
+/**
+ * Extends DataSource with schema-parsing on JSON data.
+ *
+ * @module datasource
+ * @submodule datasource-jsonschema
+ */
+
+/**
+ * Adds schema-parsing to the DataSource Utility.
+ * @class DataSourceJSONSchema
+ * @extends Plugin.Base
+ */
+var DataSourceJSONSchema = function() {
+ DataSourceJSONSchema.superclass.constructor.apply(this, arguments);
+};
+
+Y.mix(DataSourceJSONSchema, {
+ /**
+ * The namespace for the plugin. This will be the property on the host which
+ * references the plugin instance.
+ *
+ * @property NS
+ * @type String
+ * @static
+ * @final
+ * @value "schema"
+ */
+ NS: "schema",
+
+ /**
+ * Class name.
+ *
+ * @property NAME
+ * @type String
+ * @static
+ * @final
+ * @value "dataSourceJSONSchema"
+ */
+ NAME: "dataSourceJSONSchema",
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSourceJSONSchema Attributes
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ ATTRS: {
+ schema: {
+ //value: {}
+ }
+ }
+});
+
+Y.extend(DataSourceJSONSchema, Y.Plugin.Base, {
+ /**
+ * Internal init() handler.
+ *
+ * @method initializer
+ * @param config {Object} Config object.
+ * @private
+ */
+ initializer: function(config) {
+ this.doBefore("_defDataFn", this._beforeDefDataFn);
+ },
+
+ /**
+ * Parses raw data into a normalized response.
+ *
+ * @method _beforeDefDataFn
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
data (Object)
Raw data.
+ *
+ * @protected
+ */
+ _beforeDefDataFn: function(e) {
+ var data = (Y.DataSource.IO && (this.get("host") instanceof Y.DataSource.IO) && Y.Lang.isString(e.data.responseText)) ? e.data.responseText : e.data,
+ response = Y.DataSchema.JSON.apply(this.get("schema"), data);
+
+ // Default
+ if(!response) {
+ response = {
+ meta: {},
+ results: data
+ };
+ }
+
+ this.get("host").fire("response", Y.mix({response:response}, e));
+ return new Y.Do.Halt("DataSourceJSONSchema plugin halted _defDataFn");
+ }
+});
+
+Y.namespace('Plugin').DataSourceJSONSchema = DataSourceJSONSchema;
+
+
+
+}, '3.0.0' ,{requires:['plugin', 'datasource-local', 'dataschema-json']});
diff --git a/lib/yui/3.0.0/datasource/datasource-local-debug.js b/lib/yui/3.0.0/datasource/datasource-local-debug.js
new file mode 100644
index 0000000000..9c5d846a95
--- /dev/null
+++ b/lib/yui/3.0.0/datasource/datasource-local-debug.js
@@ -0,0 +1,340 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('datasource-local', function(Y) {
+
+/**
+ * The DataSource utility provides a common configurable interface for widgets to
+ * access a variety of data, from JavaScript arrays to online database servers.
+ *
+ * @module datasource
+ */
+
+/**
+ * Provides the base DataSource implementation, which can be extended to
+ * create DataSources for specific data protocols, such as the IO Utility, the
+ * Get Utility, or custom functions.
+ *
+ * @module datasource
+ * @submodule datasource-local
+ */
+
+/**
+ * Base class for the DataSource Utility.
+ * @class DataSource.Local
+ * @extends Base
+ * @constructor
+ */
+var LANG = Y.Lang,
+
+DSLocal = function() {
+ DSLocal.superclass.constructor.apply(this, arguments);
+};
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSource static properties
+ //
+ /////////////////////////////////////////////////////////////////////////////
+Y.mix(DSLocal, {
+ /**
+ * Class name.
+ *
+ * @property NAME
+ * @type String
+ * @static
+ * @final
+ * @value "dataSourceLocal"
+ */
+ NAME: "dataSourceLocal",
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSource Attributes
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ ATTRS: {
+ /**
+ * @attribute source
+ * @description Pointer to live data.
+ * @type MIXED
+ * @default null
+ */
+ source: {
+ value: null
+ }
+ },
+
+ /**
+ * Global transaction counter.
+ *
+ * @property DataSource._tId
+ * @type Number
+ * @static
+ * @private
+ * @default 0
+ */
+ _tId: 0,
+
+ /**
+ * Executes a given callback. The third param determines whether to execute
+ *
+ * @method DataSource.issueCallback
+ * @param callback {Object} The callback object.
+ * @param params {Array} params to be passed to the callback method
+ * @param error {Boolean} whether an error occurred
+ * @static
+ */
+ issueCallback: function (e) {
+ if(e.callback) {
+ var callbackFunc = (e.error && e.callback.failure) || e.callback.success;
+ if (callbackFunc) {
+ callbackFunc(e);
+ }
+ }
+ }
+});
+
+Y.extend(DSLocal, Y.Base, {
+ /**
+ * Internal init() handler.
+ *
+ * @method initializer
+ * @param config {Object} Config object.
+ * @private
+ */
+ initializer: function(config) {
+ this._initEvents();
+ },
+
+ /**
+ * This method creates all the events for this module.
+ * @method _initEvents
+ * @private
+ */
+ _initEvents: function() {
+ /**
+ * Fired when a data request is received.
+ *
+ * @event request
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object.
+ *
cfg (Object)
Configuration object.
+ *
+ * @preventable _defRequestFn
+ */
+ this.publish("request", {defaultFn: Y.bind("_defRequestFn", this), queuable:true});
+
+ /**
+ * Fired when raw data is received.
+ *
+ * @event data
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
cfg (Object)
Configuration object.
+ *
data (Object)
Raw data.
+ *
+ * @preventable _defDataFn
+ */
+ this.publish("data", {defaultFn: Y.bind("_defDataFn", this), queuable:true});
+
+ /**
+ * Fired when response is returned.
+ *
+ * @event response
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
cfg (Object)
Configuration object.
+ *
data (Object)
Raw data.
+ *
response (Object)
Normalized response object with the following properties:
+ *
+ *
results (Object)
Parsed results.
+ *
meta (Object)
Parsed meta data.
+ *
error (Boolean)
Error flag.
+ *
+ *
+ *
+ * @preventable _defResponseFn
+ */
+ this.publish("response", {defaultFn: Y.bind("_defResponseFn", this), queuable:true});
+
+ /**
+ * Fired when an error is encountered.
+ *
+ * @event error
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
cfg (Object)
Configuration object.
+ *
data (Object)
Raw data.
+ *
response (Object)
Normalized response object with the following properties:
+ *
+ *
results (Object)
Parsed results.
+ *
meta (Object)
Parsed meta data.
+ *
error (Object)
Error object.
+ *
+ *
+ *
+ */
+
+ },
+
+ /**
+ * Manages request/response transaction. Must fire response
+ * event when response is received. This method should be implemented by
+ * subclasses to achieve more complex behavior such as accessing remote data.
+ *
+ * @method _defRequestFn
+ * @param e {Event.Facade} Event Facadewith the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
cfg (Object)
Configuration object.
+ *
+ * @protected
+ */
+ _defRequestFn: function(e) {
+ var data = this.get("source");
+
+ // Problematic data
+ if(LANG.isUndefined(data)) {
+ e.error = new Error("Local source undefined");
+ }
+ if(e.error) {
+ this.fire("error", e);
+ Y.log("Error in response", "error", "datasource-local");
+ }
+
+ this.fire("data", Y.mix({data:data}, e));
+ Y.log("Transaction " + e.tId + " complete. Request: " +
+ Y.dump(e.request) + " . Response: " + Y.dump(e.response), "info", "datasource-local");
+ },
+
+ /**
+ * Normalizes raw data into a response that includes results and meta properties.
+ *
+ * @method _defDataFn
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
cfg (Object)
Configuration object.
+ *
data (Object)
Raw data.
+ *
+ * @protected
+ */
+ _defDataFn: function(e) {
+ var data = e.data,
+ meta = e.meta,
+ response = {
+ results: (LANG.isArray(data)) ? data : [data],
+ meta: (meta) ? meta : {}
+ };
+
+ this.fire("response", Y.mix({response: response}, e));
+ },
+
+ /**
+ * Sends data as a normalized response to callback.
+ *
+ * @method _defResponseFn
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
cfg (Object)
Configuration object.
+ *
data (Object)
Raw data.
+ *
response (Object)
Normalized response object with the following properties:
+ *
+ *
results (Object)
Parsed results.
+ *
meta (Object)
Parsed meta data.
+ *
error (Boolean)
Error flag.
+ *
+ *
+ *
+ * @protected
+ */
+ _defResponseFn: function(e) {
+ // Send the response back to the callback
+ DSLocal.issueCallback(e);
+ },
+
+ /**
+ * Generates a unique transaction ID and fires request event.
+ *
+ * @method sendRequest
+ * @param request {Object} Request.
+ * @param callback {Object} An object literal with the following properties:
+ *
+ *
success
+ *
The function to call when the data is ready.
+ *
failure
+ *
The function to call upon a response failure condition.
+ *
argument
+ *
Arbitrary data payload that will be passed back to the success and failure handlers.
+ *
+ * @param cfg {Object} Configuration object
+ * @return {Number} Transaction ID.
+ */
+ sendRequest: function(request, callback, cfg) {
+ var tId = DSLocal._tId++;
+ this.fire("request", {tId:tId, request:request, callback:callback, cfg:cfg || {}});
+ Y.log("Transaction " + tId + " sent request: " + Y.dump(request), "info", "datasource-local");
+ return tId;
+ }
+});
+
+Y.namespace("DataSource").Local = DSLocal;
+
+
+
+}, '3.0.0' ,{requires:['base']});
diff --git a/lib/yui/3.0.0/datasource/datasource-local-min.js b/lib/yui/3.0.0/datasource/datasource-local-min.js
new file mode 100644
index 0000000000..091dbe73e4
--- /dev/null
+++ b/lib/yui/3.0.0/datasource/datasource-local-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("datasource-local",function(C){var B=C.Lang,A=function(){A.superclass.constructor.apply(this,arguments);};C.mix(A,{NAME:"dataSourceLocal",ATTRS:{source:{value:null}},_tId:0,issueCallback:function(E){if(E.callback){var D=(E.error&&E.callback.failure)||E.callback.success;if(D){D(E);}}}});C.extend(A,C.Base,{initializer:function(D){this._initEvents();},_initEvents:function(){this.publish("request",{defaultFn:C.bind("_defRequestFn",this),queuable:true});this.publish("data",{defaultFn:C.bind("_defDataFn",this),queuable:true});this.publish("response",{defaultFn:C.bind("_defResponseFn",this),queuable:true});},_defRequestFn:function(E){var D=this.get("source");if(B.isUndefined(D)){E.error=new Error("Local source undefined");}if(E.error){this.fire("error",E);}this.fire("data",C.mix({data:D},E));},_defDataFn:function(G){var E=G.data,F=G.meta,D={results:(B.isArray(E))?E:[E],meta:(F)?F:{}};this.fire("response",C.mix({response:D},G));},_defResponseFn:function(D){A.issueCallback(D);},sendRequest:function(E,G,D){var F=A._tId++;this.fire("request",{tId:F,request:E,callback:G,cfg:D||{}});return F;}});C.namespace("DataSource").Local=A;},"3.0.0",{requires:["base"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/datasource/datasource-local.js b/lib/yui/3.0.0/datasource/datasource-local.js
new file mode 100644
index 0000000000..25de7c2df0
--- /dev/null
+++ b/lib/yui/3.0.0/datasource/datasource-local.js
@@ -0,0 +1,336 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('datasource-local', function(Y) {
+
+/**
+ * The DataSource utility provides a common configurable interface for widgets to
+ * access a variety of data, from JavaScript arrays to online database servers.
+ *
+ * @module datasource
+ */
+
+/**
+ * Provides the base DataSource implementation, which can be extended to
+ * create DataSources for specific data protocols, such as the IO Utility, the
+ * Get Utility, or custom functions.
+ *
+ * @module datasource
+ * @submodule datasource-local
+ */
+
+/**
+ * Base class for the DataSource Utility.
+ * @class DataSource.Local
+ * @extends Base
+ * @constructor
+ */
+var LANG = Y.Lang,
+
+DSLocal = function() {
+ DSLocal.superclass.constructor.apply(this, arguments);
+};
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSource static properties
+ //
+ /////////////////////////////////////////////////////////////////////////////
+Y.mix(DSLocal, {
+ /**
+ * Class name.
+ *
+ * @property NAME
+ * @type String
+ * @static
+ * @final
+ * @value "dataSourceLocal"
+ */
+ NAME: "dataSourceLocal",
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSource Attributes
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ ATTRS: {
+ /**
+ * @attribute source
+ * @description Pointer to live data.
+ * @type MIXED
+ * @default null
+ */
+ source: {
+ value: null
+ }
+ },
+
+ /**
+ * Global transaction counter.
+ *
+ * @property DataSource._tId
+ * @type Number
+ * @static
+ * @private
+ * @default 0
+ */
+ _tId: 0,
+
+ /**
+ * Executes a given callback. The third param determines whether to execute
+ *
+ * @method DataSource.issueCallback
+ * @param callback {Object} The callback object.
+ * @param params {Array} params to be passed to the callback method
+ * @param error {Boolean} whether an error occurred
+ * @static
+ */
+ issueCallback: function (e) {
+ if(e.callback) {
+ var callbackFunc = (e.error && e.callback.failure) || e.callback.success;
+ if (callbackFunc) {
+ callbackFunc(e);
+ }
+ }
+ }
+});
+
+Y.extend(DSLocal, Y.Base, {
+ /**
+ * Internal init() handler.
+ *
+ * @method initializer
+ * @param config {Object} Config object.
+ * @private
+ */
+ initializer: function(config) {
+ this._initEvents();
+ },
+
+ /**
+ * This method creates all the events for this module.
+ * @method _initEvents
+ * @private
+ */
+ _initEvents: function() {
+ /**
+ * Fired when a data request is received.
+ *
+ * @event request
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object.
+ *
cfg (Object)
Configuration object.
+ *
+ * @preventable _defRequestFn
+ */
+ this.publish("request", {defaultFn: Y.bind("_defRequestFn", this), queuable:true});
+
+ /**
+ * Fired when raw data is received.
+ *
+ * @event data
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
cfg (Object)
Configuration object.
+ *
data (Object)
Raw data.
+ *
+ * @preventable _defDataFn
+ */
+ this.publish("data", {defaultFn: Y.bind("_defDataFn", this), queuable:true});
+
+ /**
+ * Fired when response is returned.
+ *
+ * @event response
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
cfg (Object)
Configuration object.
+ *
data (Object)
Raw data.
+ *
response (Object)
Normalized response object with the following properties:
+ *
+ *
results (Object)
Parsed results.
+ *
meta (Object)
Parsed meta data.
+ *
error (Boolean)
Error flag.
+ *
+ *
+ *
+ * @preventable _defResponseFn
+ */
+ this.publish("response", {defaultFn: Y.bind("_defResponseFn", this), queuable:true});
+
+ /**
+ * Fired when an error is encountered.
+ *
+ * @event error
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
cfg (Object)
Configuration object.
+ *
data (Object)
Raw data.
+ *
response (Object)
Normalized response object with the following properties:
+ *
+ *
results (Object)
Parsed results.
+ *
meta (Object)
Parsed meta data.
+ *
error (Object)
Error object.
+ *
+ *
+ *
+ */
+
+ },
+
+ /**
+ * Manages request/response transaction. Must fire response
+ * event when response is received. This method should be implemented by
+ * subclasses to achieve more complex behavior such as accessing remote data.
+ *
+ * @method _defRequestFn
+ * @param e {Event.Facade} Event Facadewith the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
cfg (Object)
Configuration object.
+ *
+ * @protected
+ */
+ _defRequestFn: function(e) {
+ var data = this.get("source");
+
+ // Problematic data
+ if(LANG.isUndefined(data)) {
+ e.error = new Error("Local source undefined");
+ }
+ if(e.error) {
+ this.fire("error", e);
+ }
+
+ this.fire("data", Y.mix({data:data}, e));
+ },
+
+ /**
+ * Normalizes raw data into a response that includes results and meta properties.
+ *
+ * @method _defDataFn
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
cfg (Object)
Configuration object.
+ *
data (Object)
Raw data.
+ *
+ * @protected
+ */
+ _defDataFn: function(e) {
+ var data = e.data,
+ meta = e.meta,
+ response = {
+ results: (LANG.isArray(data)) ? data : [data],
+ meta: (meta) ? meta : {}
+ };
+
+ this.fire("response", Y.mix({response: response}, e));
+ },
+
+ /**
+ * Sends data as a normalized response to callback.
+ *
+ * @method _defResponseFn
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
cfg (Object)
Configuration object.
+ *
data (Object)
Raw data.
+ *
response (Object)
Normalized response object with the following properties:
+ *
+ *
results (Object)
Parsed results.
+ *
meta (Object)
Parsed meta data.
+ *
error (Boolean)
Error flag.
+ *
+ *
+ *
+ * @protected
+ */
+ _defResponseFn: function(e) {
+ // Send the response back to the callback
+ DSLocal.issueCallback(e);
+ },
+
+ /**
+ * Generates a unique transaction ID and fires request event.
+ *
+ * @method sendRequest
+ * @param request {Object} Request.
+ * @param callback {Object} An object literal with the following properties:
+ *
+ *
success
+ *
The function to call when the data is ready.
+ *
failure
+ *
The function to call upon a response failure condition.
+ *
argument
+ *
Arbitrary data payload that will be passed back to the success and failure handlers.
+ *
+ * @param cfg {Object} Configuration object
+ * @return {Number} Transaction ID.
+ */
+ sendRequest: function(request, callback, cfg) {
+ var tId = DSLocal._tId++;
+ this.fire("request", {tId:tId, request:request, callback:callback, cfg:cfg || {}});
+ return tId;
+ }
+});
+
+Y.namespace("DataSource").Local = DSLocal;
+
+
+
+}, '3.0.0' ,{requires:['base']});
diff --git a/lib/yui/3.0.0/datasource/datasource-min.js b/lib/yui/3.0.0/datasource/datasource-min.js
new file mode 100644
index 0000000000..45122817b7
--- /dev/null
+++ b/lib/yui/3.0.0/datasource/datasource-min.js
@@ -0,0 +1,9 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("datasource-local",function(C){var B=C.Lang,A=function(){A.superclass.constructor.apply(this,arguments);};C.mix(A,{NAME:"dataSourceLocal",ATTRS:{source:{value:null}},_tId:0,issueCallback:function(E){if(E.callback){var D=(E.error&&E.callback.failure)||E.callback.success;if(D){D(E);}}}});C.extend(A,C.Base,{initializer:function(D){this._initEvents();},_initEvents:function(){this.publish("request",{defaultFn:C.bind("_defRequestFn",this),queuable:true});this.publish("data",{defaultFn:C.bind("_defDataFn",this),queuable:true});this.publish("response",{defaultFn:C.bind("_defResponseFn",this),queuable:true});},_defRequestFn:function(E){var D=this.get("source");if(B.isUndefined(D)){E.error=new Error("Local source undefined");}if(E.error){this.fire("error",E);}this.fire("data",C.mix({data:D},E));},_defDataFn:function(G){var E=G.data,F=G.meta,D={results:(B.isArray(E))?E:[E],meta:(F)?F:{}};this.fire("response",C.mix({response:D},G));},_defResponseFn:function(D){A.issueCallback(D);},sendRequest:function(E,G,D){var F=A._tId++;this.fire("request",{tId:F,request:E,callback:G,cfg:D||{}});return F;}});C.namespace("DataSource").Local=A;},"3.0.0",{requires:["base"]});YUI.add("datasource-io",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};B.mix(A,{NAME:"dataSourceIO",ATTRS:{io:{value:B.io,cloneDefaultValue:false}}});B.extend(A,B.DataSource.Local,{initializer:function(C){this._queue={interval:null,conn:null,requests:[]};},_queue:null,_defRequestFn:function(F){var E=this.get("source"),G=this.get("io"),D=F.request,C=B.mix(F.cfg,{on:{success:function(J,H,I){this.fire("data",B.mix({data:H},I));},failure:function(J,H,I){I.error=new Error("IO data failure");this.fire("error",B.mix({data:H},I));this.fire("data",B.mix({data:H},I));}},context:this,arguments:F});if(B.Lang.isString(D)){if(C.method&&(C.method.toUpperCase()==="POST")){C.data=C.data?C.data+D:D;}else{E+=D;}}G(E,C);return F.tId;}});B.DataSource.IO=A;},"3.0.0",{requires:["datasource-local","io"]});YUI.add("datasource-get",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};B.mix(A,{NAME:"dataSourceGet",ATTRS:{get:{value:B.Get,cloneDefaultValue:false},asyncMode:{value:"allowAll"},scriptCallbackParam:{value:"callback"},generateRequestCallback:{value:function(C,D){return"&"+C.get("scriptCallbackParam")+"=YUI.Env.DataSource.callbacks["+D+"]";}}},callbacks:[],_tId:0});B.extend(A,B.DataSource.Local,{_defRequestFn:function(F){var E=this.get("source"),D=this.get("get"),G=A._tId++,C=this;YUI.Env.DataSource.callbacks[G]=B.rbind(function(H){if((C.get("asyncMode")!=="ignoreStaleResponses")||(G===A.callbacks.length-1)){C.fire("data",B.mix({data:H},F));}else{}delete A.callbacks[G];},this,G);E+=F.request+this.get("generateRequestCallback")(this,G);D.script(E,{autopurge:true,onFailure:B.bind(function(H){H.error=new Error("Script node data failure");this.fire("error",H);},this,F)});return F.tId;}});B.DataSource.Get=A;YUI.namespace("Env.DataSource.callbacks");},"3.0.0",{requires:["datasource-local","get"]});YUI.add("datasource-function",function(B){var A=B.Lang,C=function(){C.superclass.constructor.apply(this,arguments);};B.mix(C,{NAME:"dataSourceFunction",ATTRS:{source:{validator:A.isFunction}}});B.extend(C,B.DataSource.Local,{_defRequestFn:function(G){var F=this.get("source"),D;if(F){try{D=F(G.request,this,G);this.fire("data",B.mix({data:D},G));}catch(E){G.error=E;this.fire("error",G);}}else{G.error=new Error("Function data failure");this.fire("error",G);}return G.tId;}});B.DataSource.Function=C;},"3.0.0",{requires:["datasource-local"]});YUI.add("datasource-cache",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};B.mix(A,{NS:"cache",NAME:"dataSourceCache",ATTRS:{}});B.extend(A,B.Cache,{initializer:function(C){this.doBefore("_defRequestFn",this._beforeDefRequestFn);this.doBefore("_defResponseFn",this._beforeDefResponseFn);},_beforeDefRequestFn:function(D){var C=(this.retrieve(D.request))||null;if(C&&C.response){this.get("host").fire("response",B.mix({response:C.response},D));return new B.Do.Halt("DataSourceCache plugin halted _defRequestFn");}},_beforeDefResponseFn:function(C){if(C.response&&!C.response.cached){C.response.cached=true;this.add(C.request,C.response,(C.callback&&C.callback.argument));}}});B.namespace("Plugin").DataSourceCache=A;},"3.0.0",{requires:["datasource-local","cache"]});YUI.add("datasource-jsonschema",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};B.mix(A,{NS:"schema",NAME:"dataSourceJSONSchema",ATTRS:{schema:{}}});B.extend(A,B.Plugin.Base,{initializer:function(C){this.doBefore("_defDataFn",this._beforeDefDataFn);},_beforeDefDataFn:function(E){var D=(B.DataSource.IO&&(this.get("host") instanceof B.DataSource.IO)&&B.Lang.isString(E.data.responseText))?E.data.responseText:E.data,C=B.DataSchema.JSON.apply(this.get("schema"),D);if(!C){C={meta:{},results:D};}this.get("host").fire("response",B.mix({response:C},E));return new B.Do.Halt("DataSourceJSONSchema plugin halted _defDataFn");}});B.namespace("Plugin").DataSourceJSONSchema=A;},"3.0.0",{requires:["plugin","datasource-local","dataschema-json"]});YUI.add("datasource-xmlschema",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};B.mix(A,{NS:"schema",NAME:"dataSourceXMLSchema",ATTRS:{schema:{}}});B.extend(A,B.Plugin.Base,{initializer:function(C){this.doBefore("_defDataFn",this._beforeDefDataFn);},_beforeDefDataFn:function(E){var D=(B.DataSource.IO&&(this.get("host") instanceof B.DataSource.IO)&&E.data.responseXML&&(E.data.responseXML.nodeType===9))?E.data.responseXML:E.data,C=B.DataSchema.XML.apply(this.get("schema"),D);if(!C){C={meta:{},results:D};}this.get("host").fire("response",B.mix({response:C},E));return new B.Do.Halt("DataSourceXMLSchema plugin halted _defDataFn");}});B.namespace("Plugin").DataSourceXMLSchema=A;},"3.0.0",{requires:["plugin","datasource-local","dataschema-xml"]});YUI.add("datasource-arrayschema",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);
+};B.mix(A,{NS:"schema",NAME:"dataSourceArraySchema",ATTRS:{schema:{}}});B.extend(A,B.Plugin.Base,{initializer:function(C){this.doBefore("_defDataFn",this._beforeDefDataFn);},_beforeDefDataFn:function(E){var D=(B.DataSource.IO&&(this.get("host") instanceof B.DataSource.IO)&&B.Lang.isString(E.data.responseText))?E.data.responseText:E.data,C=B.DataSchema.Array.apply(this.get("schema"),D);if(!C){C={meta:{},results:D};}this.get("host").fire("response",B.mix({response:C},E));return new B.Do.Halt("DataSourceArraySchema plugin halted _defDataFn");}});B.namespace("Plugin").DataSourceArraySchema=A;},"3.0.0",{requires:["plugin","datasource-local","dataschema-array"]});YUI.add("datasource-textschema",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};B.mix(A,{NS:"schema",NAME:"dataSourceTextSchema",ATTRS:{schema:{}}});B.extend(A,B.Plugin.Base,{initializer:function(C){this.doBefore("_defDataFn",this._beforeDefDataFn);},_beforeDefDataFn:function(E){var D=(B.DataSource.IO&&(this.get("host") instanceof B.DataSource.IO)&&B.Lang.isString(E.data.responseText))?E.data.responseText:E.data,C=B.DataSchema.Text.apply(this.get("schema"),D);if(!C){C={meta:{},results:D};}this.get("host").fire("response",B.mix({response:C},E));return new B.Do.Halt("DataSourceTextSchema plugin halted _defDataFn");}});B.namespace("Plugin").DataSourceTextSchema=A;},"3.0.0",{requires:["plugin","datasource-local","dataschema-text"]});YUI.add("datasource-polling",function(C){var A=C.Lang,B=function(){this._intervals={};};B.prototype={_intervals:null,setInterval:function(F,E,G){var D=C.later(F,this,this.sendRequest,[E,G],true);this._intervals[D.id]=D;return D.id;},clearInterval:function(E,D){E=D||E;if(this._intervals[E]){this._intervals[E].cancel();delete this._intervals[E];}},clearAllIntervals:function(){C.each(this._intervals,this.clearInterval,this);}};C.augment(C.DataSource.Local,B);},"3.0.0",{requires:["datasource-local"]});YUI.add("datasource",function(A){},"3.0.0",{use:["datasource-local","datasource-io","datasource-get","datasource-function","datasource-cache","datasource-jsonschema","datasource-xmlschema","datasource-arrayschema","datasource-textschema","datasource-polling"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/datasource/datasource-polling-debug.js b/lib/yui/3.0.0/datasource/datasource-polling-debug.js
new file mode 100644
index 0000000000..cb7297b5b7
--- /dev/null
+++ b/lib/yui/3.0.0/datasource/datasource-polling-debug.js
@@ -0,0 +1,93 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('datasource-polling', function(Y) {
+
+/**
+ * Extends DataSource with polling functionality.
+ *
+ * @module datasource
+ * @submodule datasource-polling
+ */
+
+/**
+ * Adds polling to the DataSource Utility.
+ * @class Pollable
+ * @extends DataSource.Local
+ */
+var LANG = Y.Lang,
+
+ Pollable = function() {
+ this._intervals = {};
+ };
+
+Pollable.prototype = {
+
+ /**
+ * @property _intervals
+ * @description Hash of polling interval IDs that have been enabled,
+ * stored here to be able to clear all intervals.
+ * @private
+ */
+ _intervals: null,
+
+ /**
+ * Sets up a polling mechanism to send requests at set intervals and forward
+ * responses to given callback.
+ *
+ * @method setInterval
+ * @param msec {Number} Length of interval in milliseconds.
+ * @param request {Object} Request object.
+ * @param callback {Object} An object literal with the following properties:
+ *
+ *
success
+ *
The function to call when the data is ready.
+ *
failure
+ *
The function to call upon a response failure condition.
+ *
argument
+ *
Arbitrary data that will be passed back to the success and failure handlers.
+ *
+ * @return {Number} Interval ID.
+ */
+ setInterval: function(msec, request, callback) {
+ var x = Y.later(msec, this, this.sendRequest, [request, callback], true);
+ this._intervals[x.id] = x;
+ return x.id;
+ },
+
+ /**
+ * Disables polling mechanism associated with the given interval ID.
+ *
+ * @method clearInterval
+ * @param id {Number} Interval ID.
+ */
+ clearInterval: function(id, key) {
+ // In case of being called by clearAllIntervals()
+ id = key || id;
+ if(this._intervals[id]) {
+ // Clear the interval
+ this._intervals[id].cancel();
+ // Clear from tracker
+ delete this._intervals[id];
+ }
+ },
+
+ /**
+ * Clears all intervals.
+ *
+ * @method clearAllIntervals
+ */
+ clearAllIntervals: function() {
+ Y.each(this._intervals, this.clearInterval, this);
+ }
+};
+
+Y.augment(Y.DataSource.Local, Pollable);
+
+
+
+}, '3.0.0' ,{requires:['datasource-local']});
diff --git a/lib/yui/3.0.0/datasource/datasource-polling-min.js b/lib/yui/3.0.0/datasource/datasource-polling-min.js
new file mode 100644
index 0000000000..538b07cd54
--- /dev/null
+++ b/lib/yui/3.0.0/datasource/datasource-polling-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("datasource-polling",function(C){var A=C.Lang,B=function(){this._intervals={};};B.prototype={_intervals:null,setInterval:function(F,E,G){var D=C.later(F,this,this.sendRequest,[E,G],true);this._intervals[D.id]=D;return D.id;},clearInterval:function(E,D){E=D||E;if(this._intervals[E]){this._intervals[E].cancel();delete this._intervals[E];}},clearAllIntervals:function(){C.each(this._intervals,this.clearInterval,this);}};C.augment(C.DataSource.Local,B);},"3.0.0",{requires:["datasource-local"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/datasource/datasource-polling.js b/lib/yui/3.0.0/datasource/datasource-polling.js
new file mode 100644
index 0000000000..cb7297b5b7
--- /dev/null
+++ b/lib/yui/3.0.0/datasource/datasource-polling.js
@@ -0,0 +1,93 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('datasource-polling', function(Y) {
+
+/**
+ * Extends DataSource with polling functionality.
+ *
+ * @module datasource
+ * @submodule datasource-polling
+ */
+
+/**
+ * Adds polling to the DataSource Utility.
+ * @class Pollable
+ * @extends DataSource.Local
+ */
+var LANG = Y.Lang,
+
+ Pollable = function() {
+ this._intervals = {};
+ };
+
+Pollable.prototype = {
+
+ /**
+ * @property _intervals
+ * @description Hash of polling interval IDs that have been enabled,
+ * stored here to be able to clear all intervals.
+ * @private
+ */
+ _intervals: null,
+
+ /**
+ * Sets up a polling mechanism to send requests at set intervals and forward
+ * responses to given callback.
+ *
+ * @method setInterval
+ * @param msec {Number} Length of interval in milliseconds.
+ * @param request {Object} Request object.
+ * @param callback {Object} An object literal with the following properties:
+ *
+ *
success
+ *
The function to call when the data is ready.
+ *
failure
+ *
The function to call upon a response failure condition.
+ *
argument
+ *
Arbitrary data that will be passed back to the success and failure handlers.
+ *
+ * @return {Number} Interval ID.
+ */
+ setInterval: function(msec, request, callback) {
+ var x = Y.later(msec, this, this.sendRequest, [request, callback], true);
+ this._intervals[x.id] = x;
+ return x.id;
+ },
+
+ /**
+ * Disables polling mechanism associated with the given interval ID.
+ *
+ * @method clearInterval
+ * @param id {Number} Interval ID.
+ */
+ clearInterval: function(id, key) {
+ // In case of being called by clearAllIntervals()
+ id = key || id;
+ if(this._intervals[id]) {
+ // Clear the interval
+ this._intervals[id].cancel();
+ // Clear from tracker
+ delete this._intervals[id];
+ }
+ },
+
+ /**
+ * Clears all intervals.
+ *
+ * @method clearAllIntervals
+ */
+ clearAllIntervals: function() {
+ Y.each(this._intervals, this.clearInterval, this);
+ }
+};
+
+Y.augment(Y.DataSource.Local, Pollable);
+
+
+
+}, '3.0.0' ,{requires:['datasource-local']});
diff --git a/lib/yui/3.0.0/datasource/datasource-textschema-debug.js b/lib/yui/3.0.0/datasource/datasource-textschema-debug.js
new file mode 100644
index 0000000000..3f38090897
--- /dev/null
+++ b/lib/yui/3.0.0/datasource/datasource-textschema-debug.js
@@ -0,0 +1,113 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('datasource-textschema', function(Y) {
+
+/**
+ * Extends DataSource with schema-parsing on text data.
+ *
+ * @module datasource
+ * @submodule datasource-textschema
+ */
+
+/**
+ * Adds schema-parsing to the DataSource Utility.
+ * @class DataSourceTextSchema
+ * @extends Plugin.Base
+ */
+var DataSourceTextSchema = function() {
+ DataSourceTextSchema.superclass.constructor.apply(this, arguments);
+};
+
+Y.mix(DataSourceTextSchema, {
+ /**
+ * The namespace for the plugin. This will be the property on the host which
+ * references the plugin instance.
+ *
+ * @property NS
+ * @type String
+ * @static
+ * @final
+ * @value "schema"
+ */
+ NS: "schema",
+
+ /**
+ * Class name.
+ *
+ * @property NAME
+ * @type String
+ * @static
+ * @final
+ * @value "dataSourceTextSchema"
+ */
+ NAME: "dataSourceTextSchema",
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSourceTextSchema Attributes
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ ATTRS: {
+ schema: {
+ //value: {}
+ }
+ }
+});
+
+Y.extend(DataSourceTextSchema, Y.Plugin.Base, {
+ /**
+ * Internal init() handler.
+ *
+ * @method initializer
+ * @param config {Object} Config object.
+ * @private
+ */
+ initializer: function(config) {
+ this.doBefore("_defDataFn", this._beforeDefDataFn);
+ },
+
+ /**
+ * Parses raw data into a normalized response.
+ *
+ * @method _beforeDefDataFn
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
data (Object)
Raw data.
+ *
+ * @protected
+ */
+ _beforeDefDataFn: function(e) {
+ var data = (Y.DataSource.IO && (this.get("host") instanceof Y.DataSource.IO) && Y.Lang.isString(e.data.responseText)) ? e.data.responseText : e.data,
+ response = Y.DataSchema.Text.apply(this.get("schema"), data);
+
+ // Default
+ if(!response) {
+ response = {
+ meta: {},
+ results: data
+ };
+ }
+
+ this.get("host").fire("response", Y.mix({response:response}, e));
+ return new Y.Do.Halt("DataSourceTextSchema plugin halted _defDataFn");
+ }
+});
+
+Y.namespace('Plugin').DataSourceTextSchema = DataSourceTextSchema;
+
+
+
+}, '3.0.0' ,{requires:['plugin', 'datasource-local', 'dataschema-text']});
diff --git a/lib/yui/3.0.0/datasource/datasource-textschema-min.js b/lib/yui/3.0.0/datasource/datasource-textschema-min.js
new file mode 100644
index 0000000000..1e68b5b77f
--- /dev/null
+++ b/lib/yui/3.0.0/datasource/datasource-textschema-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("datasource-textschema",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};B.mix(A,{NS:"schema",NAME:"dataSourceTextSchema",ATTRS:{schema:{}}});B.extend(A,B.Plugin.Base,{initializer:function(C){this.doBefore("_defDataFn",this._beforeDefDataFn);},_beforeDefDataFn:function(E){var D=(B.DataSource.IO&&(this.get("host") instanceof B.DataSource.IO)&&B.Lang.isString(E.data.responseText))?E.data.responseText:E.data,C=B.DataSchema.Text.apply(this.get("schema"),D);if(!C){C={meta:{},results:D};}this.get("host").fire("response",B.mix({response:C},E));return new B.Do.Halt("DataSourceTextSchema plugin halted _defDataFn");}});B.namespace("Plugin").DataSourceTextSchema=A;},"3.0.0",{requires:["plugin","datasource-local","dataschema-text"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/datasource/datasource-textschema.js b/lib/yui/3.0.0/datasource/datasource-textschema.js
new file mode 100644
index 0000000000..3f38090897
--- /dev/null
+++ b/lib/yui/3.0.0/datasource/datasource-textschema.js
@@ -0,0 +1,113 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('datasource-textschema', function(Y) {
+
+/**
+ * Extends DataSource with schema-parsing on text data.
+ *
+ * @module datasource
+ * @submodule datasource-textschema
+ */
+
+/**
+ * Adds schema-parsing to the DataSource Utility.
+ * @class DataSourceTextSchema
+ * @extends Plugin.Base
+ */
+var DataSourceTextSchema = function() {
+ DataSourceTextSchema.superclass.constructor.apply(this, arguments);
+};
+
+Y.mix(DataSourceTextSchema, {
+ /**
+ * The namespace for the plugin. This will be the property on the host which
+ * references the plugin instance.
+ *
+ * @property NS
+ * @type String
+ * @static
+ * @final
+ * @value "schema"
+ */
+ NS: "schema",
+
+ /**
+ * Class name.
+ *
+ * @property NAME
+ * @type String
+ * @static
+ * @final
+ * @value "dataSourceTextSchema"
+ */
+ NAME: "dataSourceTextSchema",
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSourceTextSchema Attributes
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ ATTRS: {
+ schema: {
+ //value: {}
+ }
+ }
+});
+
+Y.extend(DataSourceTextSchema, Y.Plugin.Base, {
+ /**
+ * Internal init() handler.
+ *
+ * @method initializer
+ * @param config {Object} Config object.
+ * @private
+ */
+ initializer: function(config) {
+ this.doBefore("_defDataFn", this._beforeDefDataFn);
+ },
+
+ /**
+ * Parses raw data into a normalized response.
+ *
+ * @method _beforeDefDataFn
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
data (Object)
Raw data.
+ *
+ * @protected
+ */
+ _beforeDefDataFn: function(e) {
+ var data = (Y.DataSource.IO && (this.get("host") instanceof Y.DataSource.IO) && e.data.responseXML && (e.data.responseXML.nodeType === 9)) ? e.data.responseXML : e.data,
+ response = Y.DataSchema.XML.apply(this.get("schema"), data);
+
+ // Default
+ if(!response) {
+ response = {
+ meta: {},
+ results: data
+ };
+ }
+
+ this.get("host").fire("response", Y.mix({response:response}, e));
+ return new Y.Do.Halt("DataSourceXMLSchema plugin halted _defDataFn");
+ }
+});
+
+Y.namespace('Plugin').DataSourceXMLSchema = DataSourceXMLSchema;
+
+
+
+}, '3.0.0' ,{requires:['plugin', 'datasource-local', 'dataschema-xml']});
diff --git a/lib/yui/3.0.0/datasource/datasource-xmlschema-min.js b/lib/yui/3.0.0/datasource/datasource-xmlschema-min.js
new file mode 100644
index 0000000000..4173020523
--- /dev/null
+++ b/lib/yui/3.0.0/datasource/datasource-xmlschema-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("datasource-xmlschema",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};B.mix(A,{NS:"schema",NAME:"dataSourceXMLSchema",ATTRS:{schema:{}}});B.extend(A,B.Plugin.Base,{initializer:function(C){this.doBefore("_defDataFn",this._beforeDefDataFn);},_beforeDefDataFn:function(E){var D=(B.DataSource.IO&&(this.get("host") instanceof B.DataSource.IO)&&E.data.responseXML&&(E.data.responseXML.nodeType===9))?E.data.responseXML:E.data,C=B.DataSchema.XML.apply(this.get("schema"),D);if(!C){C={meta:{},results:D};}this.get("host").fire("response",B.mix({response:C},E));return new B.Do.Halt("DataSourceXMLSchema plugin halted _defDataFn");}});B.namespace("Plugin").DataSourceXMLSchema=A;},"3.0.0",{requires:["plugin","datasource-local","dataschema-xml"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/datasource/datasource-xmlschema.js b/lib/yui/3.0.0/datasource/datasource-xmlschema.js
new file mode 100644
index 0000000000..83d3f8eeda
--- /dev/null
+++ b/lib/yui/3.0.0/datasource/datasource-xmlschema.js
@@ -0,0 +1,113 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('datasource-xmlschema', function(Y) {
+
+/**
+ * Extends DataSource with schema-parsing on XML data.
+ *
+ * @module datasource
+ * @submodule datasource-xmlschema
+ */
+
+/**
+ * Adds schema-parsing to the DataSource Utility.
+ * @class DataSourceXMLSchema
+ * @extends Plugin.Base
+ */
+var DataSourceXMLSchema = function() {
+ DataSourceXMLSchema.superclass.constructor.apply(this, arguments);
+};
+
+Y.mix(DataSourceXMLSchema, {
+ /**
+ * The namespace for the plugin. This will be the property on the host which
+ * references the plugin instance.
+ *
+ * @property NS
+ * @type String
+ * @static
+ * @final
+ * @value "schema"
+ */
+ NS: "schema",
+
+ /**
+ * Class name.
+ *
+ * @property NAME
+ * @type String
+ * @static
+ * @final
+ * @value "dataSourceXMLSchema"
+ */
+ NAME: "dataSourceXMLSchema",
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSourceXMLSchema Attributes
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ ATTRS: {
+ schema: {
+ //value: {}
+ }
+ }
+});
+
+Y.extend(DataSourceXMLSchema, Y.Plugin.Base, {
+ /**
+ * Internal init() handler.
+ *
+ * @method initializer
+ * @param config {Object} Config object.
+ * @private
+ */
+ initializer: function(config) {
+ this.doBefore("_defDataFn", this._beforeDefDataFn);
+ },
+
+ /**
+ * Parses raw data into a normalized response.
+ *
+ * @method _beforeDefDataFn
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
data (Object)
Raw data.
+ *
+ * @protected
+ */
+ _beforeDefDataFn: function(e) {
+ var data = (Y.DataSource.IO && (this.get("host") instanceof Y.DataSource.IO) && e.data.responseXML && (e.data.responseXML.nodeType === 9)) ? e.data.responseXML : e.data,
+ response = Y.DataSchema.XML.apply(this.get("schema"), data);
+
+ // Default
+ if(!response) {
+ response = {
+ meta: {},
+ results: data
+ };
+ }
+
+ this.get("host").fire("response", Y.mix({response:response}, e));
+ return new Y.Do.Halt("DataSourceXMLSchema plugin halted _defDataFn");
+ }
+});
+
+Y.namespace('Plugin').DataSourceXMLSchema = DataSourceXMLSchema;
+
+
+
+}, '3.0.0' ,{requires:['plugin', 'datasource-local', 'dataschema-xml']});
diff --git a/lib/yui/3.0.0/datasource/datasource.js b/lib/yui/3.0.0/datasource/datasource.js
new file mode 100644
index 0000000000..38c400660b
--- /dev/null
+++ b/lib/yui/3.0.0/datasource/datasource.js
@@ -0,0 +1,1463 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('datasource-local', function(Y) {
+
+/**
+ * The DataSource utility provides a common configurable interface for widgets to
+ * access a variety of data, from JavaScript arrays to online database servers.
+ *
+ * @module datasource
+ */
+
+/**
+ * Provides the base DataSource implementation, which can be extended to
+ * create DataSources for specific data protocols, such as the IO Utility, the
+ * Get Utility, or custom functions.
+ *
+ * @module datasource
+ * @submodule datasource-local
+ */
+
+/**
+ * Base class for the DataSource Utility.
+ * @class DataSource.Local
+ * @extends Base
+ * @constructor
+ */
+var LANG = Y.Lang,
+
+DSLocal = function() {
+ DSLocal.superclass.constructor.apply(this, arguments);
+};
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSource static properties
+ //
+ /////////////////////////////////////////////////////////////////////////////
+Y.mix(DSLocal, {
+ /**
+ * Class name.
+ *
+ * @property NAME
+ * @type String
+ * @static
+ * @final
+ * @value "dataSourceLocal"
+ */
+ NAME: "dataSourceLocal",
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // DataSource Attributes
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ ATTRS: {
+ /**
+ * @attribute source
+ * @description Pointer to live data.
+ * @type MIXED
+ * @default null
+ */
+ source: {
+ value: null
+ }
+ },
+
+ /**
+ * Global transaction counter.
+ *
+ * @property DataSource._tId
+ * @type Number
+ * @static
+ * @private
+ * @default 0
+ */
+ _tId: 0,
+
+ /**
+ * Executes a given callback. The third param determines whether to execute
+ *
+ * @method DataSource.issueCallback
+ * @param callback {Object} The callback object.
+ * @param params {Array} params to be passed to the callback method
+ * @param error {Boolean} whether an error occurred
+ * @static
+ */
+ issueCallback: function (e) {
+ if(e.callback) {
+ var callbackFunc = (e.error && e.callback.failure) || e.callback.success;
+ if (callbackFunc) {
+ callbackFunc(e);
+ }
+ }
+ }
+});
+
+Y.extend(DSLocal, Y.Base, {
+ /**
+ * Internal init() handler.
+ *
+ * @method initializer
+ * @param config {Object} Config object.
+ * @private
+ */
+ initializer: function(config) {
+ this._initEvents();
+ },
+
+ /**
+ * This method creates all the events for this module.
+ * @method _initEvents
+ * @private
+ */
+ _initEvents: function() {
+ /**
+ * Fired when a data request is received.
+ *
+ * @event request
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object.
+ *
cfg (Object)
Configuration object.
+ *
+ * @preventable _defRequestFn
+ */
+ this.publish("request", {defaultFn: Y.bind("_defRequestFn", this), queuable:true});
+
+ /**
+ * Fired when raw data is received.
+ *
+ * @event data
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
cfg (Object)
Configuration object.
+ *
data (Object)
Raw data.
+ *
+ * @preventable _defDataFn
+ */
+ this.publish("data", {defaultFn: Y.bind("_defDataFn", this), queuable:true});
+
+ /**
+ * Fired when response is returned.
+ *
+ * @event response
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
cfg (Object)
Configuration object.
+ *
data (Object)
Raw data.
+ *
response (Object)
Normalized response object with the following properties:
+ *
+ *
results (Object)
Parsed results.
+ *
meta (Object)
Parsed meta data.
+ *
error (Boolean)
Error flag.
+ *
+ *
+ *
+ * @preventable _defResponseFn
+ */
+ this.publish("response", {defaultFn: Y.bind("_defResponseFn", this), queuable:true});
+
+ /**
+ * Fired when an error is encountered.
+ *
+ * @event error
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
cfg (Object)
Configuration object.
+ *
data (Object)
Raw data.
+ *
response (Object)
Normalized response object with the following properties:
+ *
+ *
results (Object)
Parsed results.
+ *
meta (Object)
Parsed meta data.
+ *
error (Object)
Error object.
+ *
+ *
+ *
+ */
+
+ },
+
+ /**
+ * Manages request/response transaction. Must fire response
+ * event when response is received. This method should be implemented by
+ * subclasses to achieve more complex behavior such as accessing remote data.
+ *
+ * @method _defRequestFn
+ * @param e {Event.Facade} Event Facadewith the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
cfg (Object)
Configuration object.
+ *
+ * @protected
+ */
+ _defRequestFn: function(e) {
+ var data = this.get("source");
+
+ // Problematic data
+ if(LANG.isUndefined(data)) {
+ e.error = new Error("Local source undefined");
+ }
+ if(e.error) {
+ this.fire("error", e);
+ }
+
+ this.fire("data", Y.mix({data:data}, e));
+ },
+
+ /**
+ * Normalizes raw data into a response that includes results and meta properties.
+ *
+ * @method _defDataFn
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
cfg (Object)
Configuration object.
+ *
data (Object)
Raw data.
+ *
+ * @protected
+ */
+ _defDataFn: function(e) {
+ var data = e.data,
+ meta = e.meta,
+ response = {
+ results: (LANG.isArray(data)) ? data : [data],
+ meta: (meta) ? meta : {}
+ };
+
+ this.fire("response", Y.mix({response: response}, e));
+ },
+
+ /**
+ * Sends data as a normalized response to callback.
+ *
+ * @method _defResponseFn
+ * @param e {Event.Facade} Event Facade with the following properties:
+ *
+ *
tId (Number)
Unique transaction ID.
+ *
request (Object)
The request.
+ *
callback (Object)
The callback object with the following properties:
+ *
+ *
success (Function)
Success handler.
+ *
failure (Function)
Failure handler.
+ *
+ *
+ *
cfg (Object)
Configuration object.
+ *
data (Object)
Raw data.
+ *
response (Object)
Normalized response object with the following properties:
+ *
+ *
results (Object)
Parsed results.
+ *
meta (Object)
Parsed meta data.
+ *
error (Boolean)
Error flag.
+ *
+ *
+ *
+ * @protected
+ */
+ _defResponseFn: function(e) {
+ // Send the response back to the callback
+ DSLocal.issueCallback(e);
+ },
+
+ /**
+ * Generates a unique transaction ID and fires request event.
+ *
+ * @method sendRequest
+ * @param request {Object} Request.
+ * @param callback {Object} An object literal with the following properties:
+ *
+ *
success
+ *
The function to call when the data is ready.
+ *
failure
+ *
The function to call upon a response failure condition.
+ *
argument
+ *
Arbitrary data payload that will be passed back to the success and failure handlers.
+ * This javascript implementation supports all the PHP specifiers and a few more. The full list is below.
+ *
+ *
+ * If not specified, it defaults to the ISO8601 standard date format: %Y-%m-%d. This may be overridden by changing Y.config.dateFormat
+ *
+ *
+ *
%a
abbreviated weekday name according to the current locale
+ *
%A
full weekday name according to the current locale
+ *
%b
abbreviated month name according to the current locale
+ *
%B
full month name according to the current locale
+ *
%c
preferred date and time representation for the current locale
+ *
%C
century number (the year divided by 100 and truncated to an integer, range 00 to 99)
+ *
%d
day of the month as a decimal number (range 01 to 31)
+ *
%D
same as %m/%d/%y
+ *
%e
day of the month as a decimal number, a single digit is preceded by a space (range " 1" to "31")
+ *
%F
same as %Y-%m-%d (ISO 8601 date format)
+ *
%g
like %G, but without the century
+ *
%G
The 4-digit year corresponding to the ISO week number
+ *
%h
same as %b
+ *
%H
hour as a decimal number using a 24-hour clock (range 00 to 23)
+ *
%I
hour as a decimal number using a 12-hour clock (range 01 to 12)
+ *
%j
day of the year as a decimal number (range 001 to 366)
+ *
%k
hour as a decimal number using a 24-hour clock (range 0 to 23); single digits are preceded by a blank. (See also %H.)
+ *
%l
hour as a decimal number using a 12-hour clock (range 1 to 12); single digits are preceded by a blank. (See also %I.)
+ *
%m
month as a decimal number (range 01 to 12)
+ *
%M
minute as a decimal number
+ *
%n
newline character
+ *
%p
either "AM" or "PM" according to the given time value, or the corresponding strings for the current locale
+ *
%P
like %p, but lower case
+ *
%r
time in a.m. and p.m. notation equal to %I:%M:%S %p
+ *
%R
time in 24 hour notation equal to %H:%M
+ *
%s
number of seconds since the Epoch, ie, since 1970-01-01 00:00:00 UTC
+ *
%S
second as a decimal number
+ *
%t
tab character
+ *
%T
current time, equal to %H:%M:%S
+ *
%u
weekday as a decimal number [1,7], with 1 representing Monday
+ *
%U
week number of the current year as a decimal number, starting with the
+ * first Sunday as the first day of the first week
+ *
%V
The ISO 8601:1988 week number of the current year as a decimal number,
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ *
%w
day of the week as a decimal, Sunday being 0
+ *
%W
week number of the current year as a decimal number, starting with the
+ * first Monday as the first day of the first week
+ *
%x
preferred date representation for the current locale without the time
+ *
%X
preferred time representation for the current locale without the date
+ *
%y
year as a decimal number without a century (range 00 to 99)
+ *
%Y
year as a decimal number including the century
+ *
%z
numerical time zone representation
+ *
%Z
time zone name or abbreviation
+ *
%%
a literal "%" character
+ *
+ *
+ *
locale {String} (Optional)
+ *
+ * The locale to use when displaying days of week, months of the year, and other locale specific
+ * strings. If not specified, this defaults to "en" (though this may be overridden by changing Y.config.locale).
+ * The following locales are built in:
+ *
+ *
en
+ *
English
+ *
en-US
+ *
US English
+ *
en-GB
+ *
British English
+ *
en-AU
+ *
Australian English (identical to British English)
+ *
+ * More locales may be added by subclassing of Y.DataType.Date.Locale["en"].
+ * See Y.DataType.Date.Locale for more information.
+ *
+ *
+ * @return {String} Formatted date for display.
+ */
+ format : function (oDate, oConfig) {
+ oConfig = oConfig || {};
+
+ if(!Y.Lang.isDate(oDate)) {
+ Y.log("format called without a date", "WARN", "datatype-date");
+ return Y.Lang.isValue(oDate) ? oDate : "";
+ }
+
+ var format = oConfig.format || Y.config.dateFormat,
+ sLocale = oConfig.locale || Y.config.locale,
+ LOCALE = Y.DataType.Date.Locale;
+
+ sLocale = sLocale.replace(/_/g, "-");
+
+ // Make sure we have a definition for the requested locale, or default to en.
+ if(!LOCALE[sLocale]) {
+ Y.log("selected locale " + sLocale + " not found, trying alternatives", "WARN", "datatype-date");
+ var tmpLocale = sLocale.replace(/-[a-zA-Z]+$/, "");
+ if(tmpLocale in LOCALE) {
+ sLocale = tmpLocale;
+ } else if(Y.config.locale in LOCALE) {
+ sLocale = Y.config.locale;
+ } else {
+ sLocale = "en";
+ }
+ Y.log("falling back to " + sLocale, "INFO", "datatype-date");
+ }
+
+ var aLocale = LOCALE[sLocale];
+
+ var replace_aggs = function (m0, m1) {
+ var f = Dt.aggregates[m1];
+ return (f === "locale" ? aLocale[m1] : f);
+ };
+
+ var replace_formats = function (m0, m1) {
+ var f = Dt.formats[m1];
+ switch(Y.Lang.type(f)) {
+ case "string": // string => built in date function
+ return oDate[f]();
+ case "function": // function => our own function
+ return f.call(oDate, oDate, aLocale);
+ case "array": // built in function with padding
+ if(Y.Lang.type(f[0]) === "string") {
+ return xPad(oDate[f[0]](), f[1]);
+ } // no break; (fall through to default:)
+ default:
+ Y.log("unrecognised replacement type, please file a bug (format: " + oConfig.format || Y.config.dateFormat + ")", "WARN", "datatype-date");
+ return m1;
+ }
+ };
+
+ // First replace aggregates (run in a loop because an agg may be made up of other aggs)
+ while(format.match(/%[cDFhnrRtTxX]/)) {
+ format = format.replace(/%([cDFhnrRtTxX])/g, replace_aggs);
+ }
+
+ // Now replace formats (do not run in a loop otherwise %%a will be replace with the value of %a)
+ var str = format.replace(/%([aAbBCdegGHIjklmMpPsSuUVwWyYzZ%])/g, replace_formats);
+
+ replace_aggs = replace_formats = undefined;
+
+ return str;
+ }
+};
+
+Y.mix(Y.namespace("DataType.Date"), Dt);
+
+/**
+ * @module datatype
+*/
+
+/**
+ * The Date.Locale class is a container for all localised date strings
+ * used by Y.DataType.Date. It is used internally, but may be extended
+ * to provide new date localisations.
+ *
+ * To create your own Locale, follow these steps:
+ *
+ *
Find an existing locale that matches closely with your needs
+ *
Use this as your base class. Use Y.DataType.Date.Locale["en"] if nothing
+ * matches.
+ *
Create your own class as an extension of the base class using
+ * Y.merge, and add your own localisations where needed.
+ *
+ * See the Y.DataType.Date.Locale["en-US"] and Y.DataType.Date.Locale["en-GB"]
+ * classes which extend Y.DataType.Date.Locale["en"].
+ *
+ * For example, to implement locales for French french and Canadian french,
+ * we would do the following:
+ *
+ *
For French french, we have no existing similar locale, so use
+ * Y.DataType.Date.Locale["en"] as the base, and extend it:
+ *
+ * This javascript implementation supports all the PHP specifiers and a few more. The full list is below.
+ *
+ *
+ * If not specified, it defaults to the ISO8601 standard date format: %Y-%m-%d. This may be overridden by changing Y.config.dateFormat
+ *
+ *
+ *
%a
abbreviated weekday name according to the current locale
+ *
%A
full weekday name according to the current locale
+ *
%b
abbreviated month name according to the current locale
+ *
%B
full month name according to the current locale
+ *
%c
preferred date and time representation for the current locale
+ *
%C
century number (the year divided by 100 and truncated to an integer, range 00 to 99)
+ *
%d
day of the month as a decimal number (range 01 to 31)
+ *
%D
same as %m/%d/%y
+ *
%e
day of the month as a decimal number, a single digit is preceded by a space (range " 1" to "31")
+ *
%F
same as %Y-%m-%d (ISO 8601 date format)
+ *
%g
like %G, but without the century
+ *
%G
The 4-digit year corresponding to the ISO week number
+ *
%h
same as %b
+ *
%H
hour as a decimal number using a 24-hour clock (range 00 to 23)
+ *
%I
hour as a decimal number using a 12-hour clock (range 01 to 12)
+ *
%j
day of the year as a decimal number (range 001 to 366)
+ *
%k
hour as a decimal number using a 24-hour clock (range 0 to 23); single digits are preceded by a blank. (See also %H.)
+ *
%l
hour as a decimal number using a 12-hour clock (range 1 to 12); single digits are preceded by a blank. (See also %I.)
+ *
%m
month as a decimal number (range 01 to 12)
+ *
%M
minute as a decimal number
+ *
%n
newline character
+ *
%p
either "AM" or "PM" according to the given time value, or the corresponding strings for the current locale
+ *
%P
like %p, but lower case
+ *
%r
time in a.m. and p.m. notation equal to %I:%M:%S %p
+ *
%R
time in 24 hour notation equal to %H:%M
+ *
%s
number of seconds since the Epoch, ie, since 1970-01-01 00:00:00 UTC
+ *
%S
second as a decimal number
+ *
%t
tab character
+ *
%T
current time, equal to %H:%M:%S
+ *
%u
weekday as a decimal number [1,7], with 1 representing Monday
+ *
%U
week number of the current year as a decimal number, starting with the
+ * first Sunday as the first day of the first week
+ *
%V
The ISO 8601:1988 week number of the current year as a decimal number,
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ *
%w
day of the week as a decimal, Sunday being 0
+ *
%W
week number of the current year as a decimal number, starting with the
+ * first Monday as the first day of the first week
+ *
%x
preferred date representation for the current locale without the time
+ *
%X
preferred time representation for the current locale without the date
+ *
%y
year as a decimal number without a century (range 00 to 99)
+ *
%Y
year as a decimal number including the century
+ *
%z
numerical time zone representation
+ *
%Z
time zone name or abbreviation
+ *
%%
a literal "%" character
+ *
+ *
+ *
locale {String} (Optional)
+ *
+ * The locale to use when displaying days of week, months of the year, and other locale specific
+ * strings. If not specified, this defaults to "en" (though this may be overridden by changing Y.config.locale).
+ * The following locales are built in:
+ *
+ *
en
+ *
English
+ *
en-US
+ *
US English
+ *
en-GB
+ *
British English
+ *
en-AU
+ *
Australian English (identical to British English)
+ *
+ * More locales may be added by subclassing of Y.DataType.Date.Locale["en"].
+ * See Y.DataType.Date.Locale for more information.
+ *
+ *
+ * @return {String} Formatted date for display.
+ */
+ format : function (oDate, oConfig) {
+ oConfig = oConfig || {};
+
+ if(!Y.Lang.isDate(oDate)) {
+ Y.log("format called without a date", "WARN", "datatype-date");
+ return Y.Lang.isValue(oDate) ? oDate : "";
+ }
+
+ var format = oConfig.format || Y.config.dateFormat,
+ sLocale = oConfig.locale || Y.config.locale,
+ LOCALE = Y.DataType.Date.Locale;
+
+ sLocale = sLocale.replace(/_/g, "-");
+
+ // Make sure we have a definition for the requested locale, or default to en.
+ if(!LOCALE[sLocale]) {
+ Y.log("selected locale " + sLocale + " not found, trying alternatives", "WARN", "datatype-date");
+ var tmpLocale = sLocale.replace(/-[a-zA-Z]+$/, "");
+ if(tmpLocale in LOCALE) {
+ sLocale = tmpLocale;
+ } else if(Y.config.locale in LOCALE) {
+ sLocale = Y.config.locale;
+ } else {
+ sLocale = "en";
+ }
+ Y.log("falling back to " + sLocale, "INFO", "datatype-date");
+ }
+
+ var aLocale = LOCALE[sLocale];
+
+ var replace_aggs = function (m0, m1) {
+ var f = Dt.aggregates[m1];
+ return (f === "locale" ? aLocale[m1] : f);
+ };
+
+ var replace_formats = function (m0, m1) {
+ var f = Dt.formats[m1];
+ switch(Y.Lang.type(f)) {
+ case "string": // string => built in date function
+ return oDate[f]();
+ case "function": // function => our own function
+ return f.call(oDate, oDate, aLocale);
+ case "array": // built in function with padding
+ if(Y.Lang.type(f[0]) === "string") {
+ return xPad(oDate[f[0]](), f[1]);
+ } // no break; (fall through to default:)
+ default:
+ Y.log("unrecognised replacement type, please file a bug (format: " + oConfig.format || Y.config.dateFormat + ")", "WARN", "datatype-date");
+ return m1;
+ }
+ };
+
+ // First replace aggregates (run in a loop because an agg may be made up of other aggs)
+ while(format.match(/%[cDFhnrRtTxX]/)) {
+ format = format.replace(/%([cDFhnrRtTxX])/g, replace_aggs);
+ }
+
+ // Now replace formats (do not run in a loop otherwise %%a will be replace with the value of %a)
+ var str = format.replace(/%([aAbBCdegGHIjklmMpPsSuUVwWyYzZ%])/g, replace_formats);
+
+ replace_aggs = replace_formats = undefined;
+
+ return str;
+ }
+};
+
+Y.mix(Y.namespace("DataType.Date"), Dt);
+
+/**
+ * @module datatype
+*/
+
+/**
+ * The Date.Locale class is a container for all localised date strings
+ * used by Y.DataType.Date. It is used internally, but may be extended
+ * to provide new date localisations.
+ *
+ * To create your own Locale, follow these steps:
+ *
+ *
Find an existing locale that matches closely with your needs
+ *
Use this as your base class. Use Y.DataType.Date.Locale["en"] if nothing
+ * matches.
+ *
Create your own class as an extension of the base class using
+ * Y.merge, and add your own localisations where needed.
+ *
+ * See the Y.DataType.Date.Locale["en-US"] and Y.DataType.Date.Locale["en-GB"]
+ * classes which extend Y.DataType.Date.Locale["en"].
+ *
+ * For example, to implement locales for French french and Canadian french,
+ * we would do the following:
+ *
+ *
For French french, we have no existing similar locale, so use
+ * Y.DataType.Date.Locale["en"] as the base, and extend it:
+ *
+ * This javascript implementation supports all the PHP specifiers and a few more. The full list is below.
+ *
+ *
+ * If not specified, it defaults to the ISO8601 standard date format: %Y-%m-%d. This may be overridden by changing Y.config.dateFormat
+ *
+ *
+ *
%a
abbreviated weekday name according to the current locale
+ *
%A
full weekday name according to the current locale
+ *
%b
abbreviated month name according to the current locale
+ *
%B
full month name according to the current locale
+ *
%c
preferred date and time representation for the current locale
+ *
%C
century number (the year divided by 100 and truncated to an integer, range 00 to 99)
+ *
%d
day of the month as a decimal number (range 01 to 31)
+ *
%D
same as %m/%d/%y
+ *
%e
day of the month as a decimal number, a single digit is preceded by a space (range " 1" to "31")
+ *
%F
same as %Y-%m-%d (ISO 8601 date format)
+ *
%g
like %G, but without the century
+ *
%G
The 4-digit year corresponding to the ISO week number
+ *
%h
same as %b
+ *
%H
hour as a decimal number using a 24-hour clock (range 00 to 23)
+ *
%I
hour as a decimal number using a 12-hour clock (range 01 to 12)
+ *
%j
day of the year as a decimal number (range 001 to 366)
+ *
%k
hour as a decimal number using a 24-hour clock (range 0 to 23); single digits are preceded by a blank. (See also %H.)
+ *
%l
hour as a decimal number using a 12-hour clock (range 1 to 12); single digits are preceded by a blank. (See also %I.)
+ *
%m
month as a decimal number (range 01 to 12)
+ *
%M
minute as a decimal number
+ *
%n
newline character
+ *
%p
either "AM" or "PM" according to the given time value, or the corresponding strings for the current locale
+ *
%P
like %p, but lower case
+ *
%r
time in a.m. and p.m. notation equal to %I:%M:%S %p
+ *
%R
time in 24 hour notation equal to %H:%M
+ *
%s
number of seconds since the Epoch, ie, since 1970-01-01 00:00:00 UTC
+ *
%S
second as a decimal number
+ *
%t
tab character
+ *
%T
current time, equal to %H:%M:%S
+ *
%u
weekday as a decimal number [1,7], with 1 representing Monday
+ *
%U
week number of the current year as a decimal number, starting with the
+ * first Sunday as the first day of the first week
+ *
%V
The ISO 8601:1988 week number of the current year as a decimal number,
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ *
%w
day of the week as a decimal, Sunday being 0
+ *
%W
week number of the current year as a decimal number, starting with the
+ * first Monday as the first day of the first week
+ *
%x
preferred date representation for the current locale without the time
+ *
%X
preferred time representation for the current locale without the date
+ *
%y
year as a decimal number without a century (range 00 to 99)
+ *
%Y
year as a decimal number including the century
+ *
%z
numerical time zone representation
+ *
%Z
time zone name or abbreviation
+ *
%%
a literal "%" character
+ *
+ *
+ *
locale {String} (Optional)
+ *
+ * The locale to use when displaying days of week, months of the year, and other locale specific
+ * strings. If not specified, this defaults to "en" (though this may be overridden by changing Y.config.locale).
+ * The following locales are built in:
+ *
+ *
en
+ *
English
+ *
en-US
+ *
US English
+ *
en-GB
+ *
British English
+ *
en-AU
+ *
Australian English (identical to British English)
+ *
+ * More locales may be added by subclassing of Y.DataType.Date.Locale["en"].
+ * See Y.DataType.Date.Locale for more information.
+ *
+ *
+ * @return {String} Formatted date for display.
+ */
+ format : function (oDate, oConfig) {
+ oConfig = oConfig || {};
+
+ if(!Y.Lang.isDate(oDate)) {
+ return Y.Lang.isValue(oDate) ? oDate : "";
+ }
+
+ var format = oConfig.format || Y.config.dateFormat,
+ sLocale = oConfig.locale || Y.config.locale,
+ LOCALE = Y.DataType.Date.Locale;
+
+ sLocale = sLocale.replace(/_/g, "-");
+
+ // Make sure we have a definition for the requested locale, or default to en.
+ if(!LOCALE[sLocale]) {
+ var tmpLocale = sLocale.replace(/-[a-zA-Z]+$/, "");
+ if(tmpLocale in LOCALE) {
+ sLocale = tmpLocale;
+ } else if(Y.config.locale in LOCALE) {
+ sLocale = Y.config.locale;
+ } else {
+ sLocale = "en";
+ }
+ }
+
+ var aLocale = LOCALE[sLocale];
+
+ var replace_aggs = function (m0, m1) {
+ var f = Dt.aggregates[m1];
+ return (f === "locale" ? aLocale[m1] : f);
+ };
+
+ var replace_formats = function (m0, m1) {
+ var f = Dt.formats[m1];
+ switch(Y.Lang.type(f)) {
+ case "string": // string => built in date function
+ return oDate[f]();
+ case "function": // function => our own function
+ return f.call(oDate, oDate, aLocale);
+ case "array": // built in function with padding
+ if(Y.Lang.type(f[0]) === "string") {
+ return xPad(oDate[f[0]](), f[1]);
+ } // no break; (fall through to default:)
+ default:
+ return m1;
+ }
+ };
+
+ // First replace aggregates (run in a loop because an agg may be made up of other aggs)
+ while(format.match(/%[cDFhnrRtTxX]/)) {
+ format = format.replace(/%([cDFhnrRtTxX])/g, replace_aggs);
+ }
+
+ // Now replace formats (do not run in a loop otherwise %%a will be replace with the value of %a)
+ var str = format.replace(/%([aAbBCdegGHIjklmMpPsSuUVwWyYzZ%])/g, replace_formats);
+
+ replace_aggs = replace_formats = undefined;
+
+ return str;
+ }
+};
+
+Y.mix(Y.namespace("DataType.Date"), Dt);
+
+/**
+ * @module datatype
+*/
+
+/**
+ * The Date.Locale class is a container for all localised date strings
+ * used by Y.DataType.Date. It is used internally, but may be extended
+ * to provide new date localisations.
+ *
+ * To create your own Locale, follow these steps:
+ *
+ *
Find an existing locale that matches closely with your needs
+ *
Use this as your base class. Use Y.DataType.Date.Locale["en"] if nothing
+ * matches.
+ *
Create your own class as an extension of the base class using
+ * Y.merge, and add your own localisations where needed.
+ *
+ * See the Y.DataType.Date.Locale["en-US"] and Y.DataType.Date.Locale["en-GB"]
+ * classes which extend Y.DataType.Date.Locale["en"].
+ *
+ * For example, to implement locales for French french and Canadian french,
+ * we would do the following:
+ *
+ *
For French french, we have no existing similar locale, so use
+ * Y.DataType.Date.Locale["en"] as the base, and extend it:
+ *
+ * This javascript implementation supports all the PHP specifiers and a few more. The full list is below.
+ *
+ *
+ * If not specified, it defaults to the ISO8601 standard date format: %Y-%m-%d. This may be overridden by changing Y.config.dateFormat
+ *
+ *
+ *
%a
abbreviated weekday name according to the current locale
+ *
%A
full weekday name according to the current locale
+ *
%b
abbreviated month name according to the current locale
+ *
%B
full month name according to the current locale
+ *
%c
preferred date and time representation for the current locale
+ *
%C
century number (the year divided by 100 and truncated to an integer, range 00 to 99)
+ *
%d
day of the month as a decimal number (range 01 to 31)
+ *
%D
same as %m/%d/%y
+ *
%e
day of the month as a decimal number, a single digit is preceded by a space (range " 1" to "31")
+ *
%F
same as %Y-%m-%d (ISO 8601 date format)
+ *
%g
like %G, but without the century
+ *
%G
The 4-digit year corresponding to the ISO week number
+ *
%h
same as %b
+ *
%H
hour as a decimal number using a 24-hour clock (range 00 to 23)
+ *
%I
hour as a decimal number using a 12-hour clock (range 01 to 12)
+ *
%j
day of the year as a decimal number (range 001 to 366)
+ *
%k
hour as a decimal number using a 24-hour clock (range 0 to 23); single digits are preceded by a blank. (See also %H.)
+ *
%l
hour as a decimal number using a 12-hour clock (range 1 to 12); single digits are preceded by a blank. (See also %I.)
+ *
%m
month as a decimal number (range 01 to 12)
+ *
%M
minute as a decimal number
+ *
%n
newline character
+ *
%p
either "AM" or "PM" according to the given time value, or the corresponding strings for the current locale
+ *
%P
like %p, but lower case
+ *
%r
time in a.m. and p.m. notation equal to %I:%M:%S %p
+ *
%R
time in 24 hour notation equal to %H:%M
+ *
%s
number of seconds since the Epoch, ie, since 1970-01-01 00:00:00 UTC
+ *
%S
second as a decimal number
+ *
%t
tab character
+ *
%T
current time, equal to %H:%M:%S
+ *
%u
weekday as a decimal number [1,7], with 1 representing Monday
+ *
%U
week number of the current year as a decimal number, starting with the
+ * first Sunday as the first day of the first week
+ *
%V
The ISO 8601:1988 week number of the current year as a decimal number,
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ *
%w
day of the week as a decimal, Sunday being 0
+ *
%W
week number of the current year as a decimal number, starting with the
+ * first Monday as the first day of the first week
+ *
%x
preferred date representation for the current locale without the time
+ *
%X
preferred time representation for the current locale without the date
+ *
%y
year as a decimal number without a century (range 00 to 99)
+ *
%Y
year as a decimal number including the century
+ *
%z
numerical time zone representation
+ *
%Z
time zone name or abbreviation
+ *
%%
a literal "%" character
+ *
+ *
+ *
locale {String} (Optional)
+ *
+ * The locale to use when displaying days of week, months of the year, and other locale specific
+ * strings. If not specified, this defaults to "en" (though this may be overridden by changing Y.config.locale).
+ * The following locales are built in:
+ *
+ *
en
+ *
English
+ *
en-US
+ *
US English
+ *
en-GB
+ *
British English
+ *
en-AU
+ *
Australian English (identical to British English)
+ *
+ * More locales may be added by subclassing of Y.DataType.Date.Locale["en"].
+ * See Y.DataType.Date.Locale for more information.
+ *
+ *
+ * @return {String} Formatted date for display.
+ */
+ format : function (oDate, oConfig) {
+ oConfig = oConfig || {};
+
+ if(!Y.Lang.isDate(oDate)) {
+ return Y.Lang.isValue(oDate) ? oDate : "";
+ }
+
+ var format = oConfig.format || Y.config.dateFormat,
+ sLocale = oConfig.locale || Y.config.locale,
+ LOCALE = Y.DataType.Date.Locale;
+
+ sLocale = sLocale.replace(/_/g, "-");
+
+ // Make sure we have a definition for the requested locale, or default to en.
+ if(!LOCALE[sLocale]) {
+ var tmpLocale = sLocale.replace(/-[a-zA-Z]+$/, "");
+ if(tmpLocale in LOCALE) {
+ sLocale = tmpLocale;
+ } else if(Y.config.locale in LOCALE) {
+ sLocale = Y.config.locale;
+ } else {
+ sLocale = "en";
+ }
+ }
+
+ var aLocale = LOCALE[sLocale];
+
+ var replace_aggs = function (m0, m1) {
+ var f = Dt.aggregates[m1];
+ return (f === "locale" ? aLocale[m1] : f);
+ };
+
+ var replace_formats = function (m0, m1) {
+ var f = Dt.formats[m1];
+ switch(Y.Lang.type(f)) {
+ case "string": // string => built in date function
+ return oDate[f]();
+ case "function": // function => our own function
+ return f.call(oDate, oDate, aLocale);
+ case "array": // built in function with padding
+ if(Y.Lang.type(f[0]) === "string") {
+ return xPad(oDate[f[0]](), f[1]);
+ } // no break; (fall through to default:)
+ default:
+ return m1;
+ }
+ };
+
+ // First replace aggregates (run in a loop because an agg may be made up of other aggs)
+ while(format.match(/%[cDFhnrRtTxX]/)) {
+ format = format.replace(/%([cDFhnrRtTxX])/g, replace_aggs);
+ }
+
+ // Now replace formats (do not run in a loop otherwise %%a will be replace with the value of %a)
+ var str = format.replace(/%([aAbBCdegGHIjklmMpPsSuUVwWyYzZ%])/g, replace_formats);
+
+ replace_aggs = replace_formats = undefined;
+
+ return str;
+ }
+};
+
+Y.mix(Y.namespace("DataType.Date"), Dt);
+
+/**
+ * @module datatype
+*/
+
+/**
+ * The Date.Locale class is a container for all localised date strings
+ * used by Y.DataType.Date. It is used internally, but may be extended
+ * to provide new date localisations.
+ *
+ * To create your own Locale, follow these steps:
+ *
+ *
Find an existing locale that matches closely with your needs
+ *
Use this as your base class. Use Y.DataType.Date.Locale["en"] if nothing
+ * matches.
+ *
Create your own class as an extension of the base class using
+ * Y.merge, and add your own localisations where needed.
+ *
+ * See the Y.DataType.Date.Locale["en-US"] and Y.DataType.Date.Locale["en-GB"]
+ * classes which extend Y.DataType.Date.Locale["en"].
+ *
+ * For example, to implement locales for French french and Canadian french,
+ * we would do the following:
+ *
+ *
For French french, we have no existing similar locale, so use
+ * Y.DataType.Date.Locale["en"] as the base, and extend it:
+ *
+ * This javascript implementation supports all the PHP specifiers and a few more. The full list is below.
+ *
+ *
+ * If not specified, it defaults to the ISO8601 standard date format: %Y-%m-%d. This may be overridden by changing Y.config.dateFormat
+ *
+ *
+ *
%a
abbreviated weekday name according to the current locale
+ *
%A
full weekday name according to the current locale
+ *
%b
abbreviated month name according to the current locale
+ *
%B
full month name according to the current locale
+ *
%c
preferred date and time representation for the current locale
+ *
%C
century number (the year divided by 100 and truncated to an integer, range 00 to 99)
+ *
%d
day of the month as a decimal number (range 01 to 31)
+ *
%D
same as %m/%d/%y
+ *
%e
day of the month as a decimal number, a single digit is preceded by a space (range " 1" to "31")
+ *
%F
same as %Y-%m-%d (ISO 8601 date format)
+ *
%g
like %G, but without the century
+ *
%G
The 4-digit year corresponding to the ISO week number
+ *
%h
same as %b
+ *
%H
hour as a decimal number using a 24-hour clock (range 00 to 23)
+ *
%I
hour as a decimal number using a 12-hour clock (range 01 to 12)
+ *
%j
day of the year as a decimal number (range 001 to 366)
+ *
%k
hour as a decimal number using a 24-hour clock (range 0 to 23); single digits are preceded by a blank. (See also %H.)
+ *
%l
hour as a decimal number using a 12-hour clock (range 1 to 12); single digits are preceded by a blank. (See also %I.)
+ *
%m
month as a decimal number (range 01 to 12)
+ *
%M
minute as a decimal number
+ *
%n
newline character
+ *
%p
either "AM" or "PM" according to the given time value, or the corresponding strings for the current locale
+ *
%P
like %p, but lower case
+ *
%r
time in a.m. and p.m. notation equal to %I:%M:%S %p
+ *
%R
time in 24 hour notation equal to %H:%M
+ *
%s
number of seconds since the Epoch, ie, since 1970-01-01 00:00:00 UTC
+ *
%S
second as a decimal number
+ *
%t
tab character
+ *
%T
current time, equal to %H:%M:%S
+ *
%u
weekday as a decimal number [1,7], with 1 representing Monday
+ *
%U
week number of the current year as a decimal number, starting with the
+ * first Sunday as the first day of the first week
+ *
%V
The ISO 8601:1988 week number of the current year as a decimal number,
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ *
%w
day of the week as a decimal, Sunday being 0
+ *
%W
week number of the current year as a decimal number, starting with the
+ * first Monday as the first day of the first week
+ *
%x
preferred date representation for the current locale without the time
+ *
%X
preferred time representation for the current locale without the date
+ *
%y
year as a decimal number without a century (range 00 to 99)
+ *
%Y
year as a decimal number including the century
+ *
%z
numerical time zone representation
+ *
%Z
time zone name or abbreviation
+ *
%%
a literal "%" character
+ *
+ *
+ *
locale {String} (Optional)
+ *
+ * The locale to use when displaying days of week, months of the year, and other locale specific
+ * strings. If not specified, this defaults to "en" (though this may be overridden by changing Y.config.locale).
+ * The following locales are built in:
+ *
+ *
en
+ *
English
+ *
en-US
+ *
US English
+ *
en-GB
+ *
British English
+ *
en-AU
+ *
Australian English (identical to British English)
+ *
+ * More locales may be added by subclassing of Y.DataType.Date.Locale["en"].
+ * See Y.DataType.Date.Locale for more information.
+ *
+ *
+ * @return {String} Formatted date for display.
+ */
+ format : function (oDate, oConfig) {
+ oConfig = oConfig || {};
+
+ if(!Y.Lang.isDate(oDate)) {
+ Y.log("format called without a date", "WARN", "datatype-date");
+ return Y.Lang.isValue(oDate) ? oDate : "";
+ }
+
+ var format = oConfig.format || Y.config.dateFormat,
+ sLocale = oConfig.locale || Y.config.locale,
+ LOCALE = Y.DataType.Date.Locale;
+
+ sLocale = sLocale.replace(/_/g, "-");
+
+ // Make sure we have a definition for the requested locale, or default to en.
+ if(!LOCALE[sLocale]) {
+ Y.log("selected locale " + sLocale + " not found, trying alternatives", "WARN", "datatype-date");
+ var tmpLocale = sLocale.replace(/-[a-zA-Z]+$/, "");
+ if(tmpLocale in LOCALE) {
+ sLocale = tmpLocale;
+ } else if(Y.config.locale in LOCALE) {
+ sLocale = Y.config.locale;
+ } else {
+ sLocale = "en";
+ }
+ Y.log("falling back to " + sLocale, "INFO", "datatype-date");
+ }
+
+ var aLocale = LOCALE[sLocale];
+
+ var replace_aggs = function (m0, m1) {
+ var f = Dt.aggregates[m1];
+ return (f === "locale" ? aLocale[m1] : f);
+ };
+
+ var replace_formats = function (m0, m1) {
+ var f = Dt.formats[m1];
+ switch(Y.Lang.type(f)) {
+ case "string": // string => built in date function
+ return oDate[f]();
+ case "function": // function => our own function
+ return f.call(oDate, oDate, aLocale);
+ case "array": // built in function with padding
+ if(Y.Lang.type(f[0]) === "string") {
+ return xPad(oDate[f[0]](), f[1]);
+ } // no break; (fall through to default:)
+ default:
+ Y.log("unrecognised replacement type, please file a bug (format: " + oConfig.format || Y.config.dateFormat + ")", "WARN", "datatype-date");
+ return m1;
+ }
+ };
+
+ // First replace aggregates (run in a loop because an agg may be made up of other aggs)
+ while(format.match(/%[cDFhnrRtTxX]/)) {
+ format = format.replace(/%([cDFhnrRtTxX])/g, replace_aggs);
+ }
+
+ // Now replace formats (do not run in a loop otherwise %%a will be replace with the value of %a)
+ var str = format.replace(/%([aAbBCdegGHIjklmMpPsSuUVwWyYzZ%])/g, replace_formats);
+
+ replace_aggs = replace_formats = undefined;
+
+ return str;
+ }
+};
+
+Y.mix(Y.namespace("DataType.Date"), Dt);
+
+/**
+ * @module datatype
+*/
+
+/**
+ * The Date.Locale class is a container for all localised date strings
+ * used by Y.DataType.Date. It is used internally, but may be extended
+ * to provide new date localisations.
+ *
+ * To create your own Locale, follow these steps:
+ *
+ *
Find an existing locale that matches closely with your needs
+ *
Use this as your base class. Use Y.DataType.Date.Locale["en"] if nothing
+ * matches.
+ *
Create your own class as an extension of the base class using
+ * Y.merge, and add your own localisations where needed.
+ *
+ * See the Y.DataType.Date.Locale["en-US"] and Y.DataType.Date.Locale["en-GB"]
+ * classes which extend Y.DataType.Date.Locale["en"].
+ *
+ * For example, to implement locales for French french and Canadian french,
+ * we would do the following:
+ *
+ *
For French french, we have no existing similar locale, so use
+ * Y.DataType.Date.Locale["en"] as the base, and extend it:
+ *
+ * This javascript implementation supports all the PHP specifiers and a few more. The full list is below.
+ *
+ *
+ * If not specified, it defaults to the ISO8601 standard date format: %Y-%m-%d. This may be overridden by changing Y.config.dateFormat
+ *
+ *
+ *
%a
abbreviated weekday name according to the current locale
+ *
%A
full weekday name according to the current locale
+ *
%b
abbreviated month name according to the current locale
+ *
%B
full month name according to the current locale
+ *
%c
preferred date and time representation for the current locale
+ *
%C
century number (the year divided by 100 and truncated to an integer, range 00 to 99)
+ *
%d
day of the month as a decimal number (range 01 to 31)
+ *
%D
same as %m/%d/%y
+ *
%e
day of the month as a decimal number, a single digit is preceded by a space (range " 1" to "31")
+ *
%F
same as %Y-%m-%d (ISO 8601 date format)
+ *
%g
like %G, but without the century
+ *
%G
The 4-digit year corresponding to the ISO week number
+ *
%h
same as %b
+ *
%H
hour as a decimal number using a 24-hour clock (range 00 to 23)
+ *
%I
hour as a decimal number using a 12-hour clock (range 01 to 12)
+ *
%j
day of the year as a decimal number (range 001 to 366)
+ *
%k
hour as a decimal number using a 24-hour clock (range 0 to 23); single digits are preceded by a blank. (See also %H.)
+ *
%l
hour as a decimal number using a 12-hour clock (range 1 to 12); single digits are preceded by a blank. (See also %I.)
+ *
%m
month as a decimal number (range 01 to 12)
+ *
%M
minute as a decimal number
+ *
%n
newline character
+ *
%p
either "AM" or "PM" according to the given time value, or the corresponding strings for the current locale
+ *
%P
like %p, but lower case
+ *
%r
time in a.m. and p.m. notation equal to %I:%M:%S %p
+ *
%R
time in 24 hour notation equal to %H:%M
+ *
%s
number of seconds since the Epoch, ie, since 1970-01-01 00:00:00 UTC
+ *
%S
second as a decimal number
+ *
%t
tab character
+ *
%T
current time, equal to %H:%M:%S
+ *
%u
weekday as a decimal number [1,7], with 1 representing Monday
+ *
%U
week number of the current year as a decimal number, starting with the
+ * first Sunday as the first day of the first week
+ *
%V
The ISO 8601:1988 week number of the current year as a decimal number,
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ *
%w
day of the week as a decimal, Sunday being 0
+ *
%W
week number of the current year as a decimal number, starting with the
+ * first Monday as the first day of the first week
+ *
%x
preferred date representation for the current locale without the time
+ *
%X
preferred time representation for the current locale without the date
+ *
%y
year as a decimal number without a century (range 00 to 99)
+ *
%Y
year as a decimal number including the century
+ *
%z
numerical time zone representation
+ *
%Z
time zone name or abbreviation
+ *
%%
a literal "%" character
+ *
+ *
+ *
locale {String} (Optional)
+ *
+ * The locale to use when displaying days of week, months of the year, and other locale specific
+ * strings. If not specified, this defaults to "en" (though this may be overridden by changing Y.config.locale).
+ * The following locales are built in:
+ *
+ *
en
+ *
English
+ *
en-US
+ *
US English
+ *
en-GB
+ *
British English
+ *
en-AU
+ *
Australian English (identical to British English)
+ *
+ * More locales may be added by subclassing of Y.DataType.Date.Locale["en"].
+ * See Y.DataType.Date.Locale for more information.
+ *
+ *
+ * @return {String} Formatted date for display.
+ */
+ format : function (oDate, oConfig) {
+ oConfig = oConfig || {};
+
+ if(!Y.Lang.isDate(oDate)) {
+ return Y.Lang.isValue(oDate) ? oDate : "";
+ }
+
+ var format = oConfig.format || Y.config.dateFormat,
+ sLocale = oConfig.locale || Y.config.locale,
+ LOCALE = Y.DataType.Date.Locale;
+
+ sLocale = sLocale.replace(/_/g, "-");
+
+ // Make sure we have a definition for the requested locale, or default to en.
+ if(!LOCALE[sLocale]) {
+ var tmpLocale = sLocale.replace(/-[a-zA-Z]+$/, "");
+ if(tmpLocale in LOCALE) {
+ sLocale = tmpLocale;
+ } else if(Y.config.locale in LOCALE) {
+ sLocale = Y.config.locale;
+ } else {
+ sLocale = "en";
+ }
+ }
+
+ var aLocale = LOCALE[sLocale];
+
+ var replace_aggs = function (m0, m1) {
+ var f = Dt.aggregates[m1];
+ return (f === "locale" ? aLocale[m1] : f);
+ };
+
+ var replace_formats = function (m0, m1) {
+ var f = Dt.formats[m1];
+ switch(Y.Lang.type(f)) {
+ case "string": // string => built in date function
+ return oDate[f]();
+ case "function": // function => our own function
+ return f.call(oDate, oDate, aLocale);
+ case "array": // built in function with padding
+ if(Y.Lang.type(f[0]) === "string") {
+ return xPad(oDate[f[0]](), f[1]);
+ } // no break; (fall through to default:)
+ default:
+ return m1;
+ }
+ };
+
+ // First replace aggregates (run in a loop because an agg may be made up of other aggs)
+ while(format.match(/%[cDFhnrRtTxX]/)) {
+ format = format.replace(/%([cDFhnrRtTxX])/g, replace_aggs);
+ }
+
+ // Now replace formats (do not run in a loop otherwise %%a will be replace with the value of %a)
+ var str = format.replace(/%([aAbBCdegGHIjklmMpPsSuUVwWyYzZ%])/g, replace_formats);
+
+ replace_aggs = replace_formats = undefined;
+
+ return str;
+ }
+};
+
+Y.mix(Y.namespace("DataType.Date"), Dt);
+
+/**
+ * @module datatype
+*/
+
+/**
+ * The Date.Locale class is a container for all localised date strings
+ * used by Y.DataType.Date. It is used internally, but may be extended
+ * to provide new date localisations.
+ *
+ * To create your own Locale, follow these steps:
+ *
+ *
Find an existing locale that matches closely with your needs
+ *
Use this as your base class. Use Y.DataType.Date.Locale["en"] if nothing
+ * matches.
+ *
Create your own class as an extension of the base class using
+ * Y.merge, and add your own localisations where needed.
+ *
+ * See the Y.DataType.Date.Locale["en-US"] and Y.DataType.Date.Locale["en-GB"]
+ * classes which extend Y.DataType.Date.Locale["en"].
+ *
+ * For example, to implement locales for French french and Canadian french,
+ * we would do the following:
+ *
+ *
For French french, we have no existing similar locale, so use
+ * Y.DataType.Date.Locale["en"] as the base, and extend it:
+ *
+ * @requires oop
+ * @class DataType.Date.Locale
+ * @static
+ */
+var YDateEn = {
+ a: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ A: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+ b: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+ B: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+ c: "%a %d %b %Y %T %Z",
+ p: ["AM", "PM"],
+ P: ["am", "pm"],
+ r: "%I:%M:%S %p",
+ x: "%d/%m/%y",
+ X: "%T"
+};
+
+Y.namespace("DataType.Date.Locale");
+
+Y.DataType.Date.Locale["en"] = YDateEn;
+
+Y.DataType.Date.Locale["en-US"] = Y.merge(YDateEn, {
+ c: "%a %d %b %Y %I:%M:%S %p %Z",
+ x: "%m/%d/%Y",
+ X: "%I:%M:%S %p"
+});
+
+Y.DataType.Date.Locale["en-GB"] = Y.merge(YDateEn, {
+ r: "%l:%M:%S %P %Z"
+});
+Y.DataType.Date.Locale["en-AU"] = Y.merge(YDateEn);
+
+
+
+
+
+}, '3.0.0' );
+
+
+
+YUI.add('datatype-date', function(Y){}, '3.0.0' ,{use:['datatype-date-parse', 'datatype-date-format']});
+
+
+YUI.add('datatype-xml-parse', function(Y) {
+
+/**
+ * Parse XML submodule.
+ *
+ * @module datatype
+ * @submodule datatype-xml-parse
+ * @for DataType.XML
+ */
+
+var LANG = Y.Lang;
+
+Y.mix(Y.namespace("DataType.XML"), {
+ /**
+ * Converts data to type XMLDocument.
+ *
+ * @method parse
+ * @param data {String} Data to convert.
+ * @return {XMLDoc} XML Document.
+ */
+ parse: function(data) {
+ var xmlDoc = null;
+ if(LANG.isString(data)) {
+ try {
+ if(!LANG.isUndefined(DOMParser)) {
+ xmlDoc = new DOMParser().parseFromString(data, "text/xml");
+ }
+ }
+ catch(e) {
+ try {
+ if(!LANG.isUndefined(ActiveXObject)) {
+ xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
+ xmlDoc.async = false;
+ xmlDoc.loadXML(data);
+ }
+ }
+ catch(ee) {
+ }
+ }
+ }
+
+ if( (LANG.isNull(xmlDoc)) || (LANG.isNull(xmlDoc.documentElement)) || (xmlDoc.documentElement.nodeName === "parsererror") ) {
+ }
+
+ return xmlDoc;
+ }
+});
+
+// Add Parsers shortcut
+Y.namespace("Parsers").xml = Y.DataType.XML.parse;
+
+
+
+
+}, '3.0.0' );
+
+YUI.add('datatype-xml-format', function(Y) {
+
+/**
+ * Format XML submodule.
+ *
+ * @module datatype
+ * @submodule datatype-xml-format
+ */
+
+/**
+ * XML submodule.
+ *
+ * @module datatype
+ * @submodule datatype-xml
+ */
+
+/**
+ * DataType.XML provides a set of utility functions to operate against XML documents.
+ *
+ * @class DataType.XML
+ * @static
+ */
+var LANG = Y.Lang;
+
+Y.mix(Y.namespace("DataType.XML"), {
+ /**
+ * Converts data to type XMLDocument.
+ *
+ * @method format
+ * @param data {XMLDoc} Data to convert.
+ * @return {String} String.
+ */
+ format: function(data) {
+ try {
+ if(!LANG.isUndefined(XMLSerializer)) {
+ return (new XMLSerializer()).serializeToString(data);
+ }
+ }
+ catch(e) {
+ if(data && data.xml) {
+ return data.xml;
+ }
+ else {
+ return (LANG.isValue(data) && data.toString) ? data.toString() : "";
+ }
+ }
+ }
+});
+
+
+
+
+}, '3.0.0' );
+
+
+
+YUI.add('datatype-xml', function(Y){}, '3.0.0' ,{use:['datatype-xml-parse', 'datatype-xml-format']});
+
+
+
+
+YUI.add('datatype', function(Y){}, '3.0.0' ,{use:['datatype-number', 'datatype-date', 'datatype-xml']});
+
diff --git a/lib/yui/3.0.0/dd/dd-constrain-debug.js b/lib/yui/3.0.0/dd/dd-constrain-debug.js
new file mode 100644
index 0000000000..7d2b5e1459
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-constrain-debug.js
@@ -0,0 +1,425 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dd-constrain', function(Y) {
+
+
+ /**
+ * The Drag & Drop Utility allows you to create a draggable interface efficiently, buffering you from browser-level abnormalities and enabling you to focus on the interesting logic surrounding your particular implementation. This component enables you to create a variety of standard draggable objects with just a few lines of code and then, using its extensive API, add your own specific implementation logic.
+ * @module dd
+ * @submodule dd-constrain
+ */
+ /**
+ * This is a plugin for the dd-drag module to add the constraining methods to it. It supports constraining to a renodenode or viewport. It anode* supports tick based moves and XY axis constraints.
+ * @class DragConstrained
+ * @extends Base
+ * @constructor
+ * @namespace Plugin
+ */
+
+ var DRAG_NODE = 'dragNode',
+ OFFSET_HEIGHT = 'offsetHeight',
+ OFFSET_WIDTH = 'offsetWidth',
+ HOST = 'host',
+ CON_2_REGION = 'constrain2region',
+ CON_2_NODE = 'constrain2node',
+ TICK_X_ARRAY = 'tickXArray',
+ TICK_Y_ARRAY = 'tickYArray',
+ DDM = Y.DD.DDM,
+ TOP = 'top',
+ RIGHT = 'right',
+ BOTTOM = 'bottom',
+ LEFT = 'left',
+ proto = null;
+
+ var C = function(config) {
+ C.superclass.constructor.apply(this, arguments);
+ };
+
+ C.NAME = 'DragConstrained';
+ /**
+ * @property con
+ * @description The Constrained instance will be placed on the Drag instance under the con namespace.
+ * @type {String}
+ */
+ C.NS = 'con';
+
+ C.ATTRS = {
+ host: {
+ },
+ /**
+ * @attribute stickX
+ * @description Stick the drag movement to the X-Axis. Default: false
+ * @type Boolean
+ */
+ stickX: {
+ value: false
+ },
+ /**
+ * @attribute stickY
+ * @description Stick the drag movement to the Y-Axis
+ * @type Boolean
+ */
+ stickY: {
+ value: false
+ },
+ /**
+ * @attribute tickX
+ * @description The X tick offset the drag node should snap to on each drag move. False for no ticks. Default: false
+ * @type Number/false
+ */
+ tickX: {
+ value: false
+ },
+ /**
+ * @attribute tickY
+ * @description The Y tick offset the drag node should snap to on each drag move. False for no ticks. Default: false
+ * @type Number/false
+ */
+ tickY: {
+ value: false
+ },
+ /**
+ * @attribute tickXArray
+ * @description An array of page coordinates to use as X ticks for drag movement.
+ * @type Array
+ */
+ tickXArray: {
+ value: false
+ },
+ /**
+ * @attribute tickYArray
+ * @description An array of page coordinates to use as Y ticks for drag movement.
+ * @type Array
+ */
+ tickYArray: {
+ value: false
+ },
+ /**
+ * @attribute constrain2region
+ * @description An Object Literal containing a valid region (top, right, bottom, left) of page positions to constrain the drag node to.
+ * @type Object
+ */
+ constrain2region: {
+ value: false,
+ getter: function(r) {
+ if (Y.Lang.isObject(r)) {
+ var o = {};
+ Y.mix(o, r);
+ return o;
+ } else {
+ return false;
+ }
+ },
+ setter: function (r) {
+ if (Y.Lang.isObject(r)) {
+ if (Y.Lang.isNumber(r[TOP]) && Y.Lang.isNumber(r[RIGHT]) && Y.Lang.isNumber(r[LEFT]) && Y.Lang.isNumber(r[BOTTOM])) {
+ var o = {};
+ Y.mix(o, r);
+ return o;
+ } else {
+ return false;
+ }
+ } else if (r !== false) {
+ return false;
+ }
+ return r;
+ }
+ },
+ /**
+ * @attribute gutter
+ * @description CSS style string for the gutter of a region (supports negative values): '5 0' (sets top and bottom to 5px, left and right to 0px), '1 2 3 4' (top 1px, right 2px, bottom 3px, left 4px)
+ * @type String
+ */
+ gutter: {
+ value: '0',
+ setter: function(gutter) {
+ return Y.DD.DDM.cssSizestoObject(gutter);
+ }
+ },
+ /**
+ * @attribute constrain2node
+ * @description Will attempt to constrain the drag node to the boundaries of this node.
+ * @type Object
+ */
+ constrain2node: {
+ value: false,
+ setter: function(n) {
+ if (!this.get(CON_2_REGION)) {
+ var node = Y.Node.get(n);
+ if (node) {
+ return node;
+ }
+ } else if (this.get(CON_2_REGION) !== false) {
+ }
+ return false;
+ }
+ },
+ /**
+ * @attribute constrain2view
+ * @description Will attempt to constrain the drag node to the boundaries of the viewport region.
+ * @type Object
+ */
+ constrain2view: {
+ value: false
+ }
+ };
+
+ proto = {
+ initializer: function() {
+ this.get(HOST).on('drag:start', Y.bind(this._handleStart, this));
+ this.get(HOST).after('drag:align', Y.bind(this.align, this));
+ },
+ /**
+ * @private
+ * @method _handleStart
+ * @description Fires on drag:start and clears the _regionCache
+ */
+ _handleStart: function() {
+ this._regionCache = null;
+ },
+ /**
+ * @private
+ * @property _regionCache
+ * @description Store a cache of the region that we are constraining to
+ * @type Object
+ */
+ _regionCache: null,
+ /**
+ * @private
+ * @method _cacheRegion
+ * @description Get's the region and caches it, called from window.resize and when the cache is null
+ */
+ _cacheRegion: function() {
+ this._regionCache = this.get(CON_2_NODE).get('region');
+ },
+ /**
+ * @method getRegion
+ * @description Get the active region: viewport, node, custom region
+ * @param {Boolean} inc Include the node's height and width
+ * @return {Object}
+ */
+ getRegion: function(inc) {
+ var r = {}, oh = null, ow = null,
+ g = this.get('gutter'),
+ host = this.get(HOST);
+
+ if (this.get(CON_2_NODE)) {
+ if (!this._regionCache) {
+ Y.on('resize', Y.bind(this._cacheRegion, this), window);
+ this._cacheRegion();
+ }
+ r = Y.clone(this._regionCache);
+ } else if (this.get(CON_2_REGION)) {
+ r = this.get(CON_2_REGION);
+ } else if (this.get('constrain2view')) {
+ r = host.get(DRAG_NODE).get('viewportRegion');
+ } else {
+ return false;
+ }
+
+ Y.each(g, function(i, n) {
+ if ((n == RIGHT) || (n == BOTTOM)) {
+ r[n] -= i;
+ } else {
+ r[n] += i;
+ }
+ });
+ if (inc) {
+ oh = host.get(DRAG_NODE).get(OFFSET_HEIGHT);
+ ow = host.get(DRAG_NODE).get(OFFSET_WIDTH);
+ r[RIGHT] = r[RIGHT] - ow;
+ r[BOTTOM] = r[BOTTOM] - oh;
+ }
+ return r;
+ },
+ /**
+ * @private
+ * @method _checkRegion
+ * @description Check if xy is inside a given region, if not change to it be inside.
+ * @param {Array} _xy The XY to check if it's in the current region, if it isn't inside the region, it will reset the xy array to be inside the region.
+ * @return {Array} The new XY that is inside the region
+ */
+ _checkRegion: function(_xy) {
+ var oxy = _xy,
+ r = this.getRegion(),
+ host = this.get(HOST),
+ oh = host.get(DRAG_NODE).get(OFFSET_HEIGHT),
+ ow = host.get(DRAG_NODE).get(OFFSET_WIDTH);
+
+ if (oxy[1] > (r[BOTTOM] - oh)) {
+ _xy[1] = (r[BOTTOM] - oh);
+ }
+ if (r[TOP] > oxy[1]) {
+ _xy[1] = r[TOP];
+
+ }
+ if (oxy[0] > (r[RIGHT] - ow)) {
+ _xy[0] = (r[RIGHT] - ow);
+ }
+ if (r[LEFT] > oxy[0]) {
+ _xy[0] = r[LEFT];
+ }
+
+ return _xy;
+ },
+ /**
+ * @method inRegion
+ * @description Checks if the XY passed or the dragNode is inside the active region.
+ * @param {Array} xy Optional XY to check, if not supplied this.get('dragNode').getXY() is used.
+ * @return {Boolean} True if the XY is inside the region, false otherwise.
+ */
+ inRegion: function(xy) {
+ xy = xy || this.get(HOST).get(DRAG_NODE).getXY();
+
+ var _xy = this._checkRegion([xy[0], xy[1]]),
+ inside = false;
+ if ((xy[0] === _xy[0]) && (xy[1] === _xy[1])) {
+ inside = true;
+ }
+ return inside;
+ },
+ /**
+ * @method align
+ * @description Modifies the Drag.actXY method from the after drag:align event. This is where the constraining happens.
+ */
+ align: function() {
+ var host = this.get(HOST),
+ _xy = host.actXY,
+ r = this.getRegion(true);
+
+ if (this.get('stickX')) {
+ _xy[1] = (host.startXY[1] - host.deltaXY[1]);
+ }
+ if (this.get('stickY')) {
+ _xy[0] = (host.startXY[0] - host.deltaXY[0]);
+ }
+
+ if (r) {
+ _xy = this._checkRegion(_xy);
+ }
+
+ _xy = this._checkTicks(_xy, r);
+ host.actXY = _xy;
+ },
+ /**
+ * @private
+ * @method _checkTicks
+ * @description This method delegates the proper helper method for tick calculations
+ * @param {Array} xy The XY coords for the Drag
+ * @param {Object} r The optional region that we are bound to.
+ * @return {Array} The calced XY coords
+ */
+ _checkTicks: function(xy, r) {
+ var host = this.get(HOST),
+ lx = (host.startXY[0] - host.deltaXY[0]),
+ ly = (host.startXY[1] - host.deltaXY[1]),
+ xt = this.get('tickX'),
+ yt = this.get('tickY');
+ if (xt && !this.get(TICK_X_ARRAY)) {
+ xy[0] = DDM._calcTicks(xy[0], lx, xt, r[LEFT], r[RIGHT]);
+ }
+ if (yt && !this.get(TICK_Y_ARRAY)) {
+ xy[1] = DDM._calcTicks(xy[1], ly, yt, r[TOP], r[BOTTOM]);
+ }
+ if (this.get(TICK_X_ARRAY)) {
+ xy[0] = DDM._calcTickArray(xy[0], this.get(TICK_X_ARRAY), r[LEFT], r[RIGHT]);
+ }
+ if (this.get(TICK_Y_ARRAY)) {
+ xy[1] = DDM._calcTickArray(xy[1], this.get(TICK_Y_ARRAY), r[TOP], r[BOTTOM]);
+ }
+
+ return xy;
+ }
+ };
+
+ Y.namespace('Plugin');
+ Y.extend(C, Y.Base, proto);
+ Y.Plugin.DDConstrained = C;
+
+ Y.mix(DDM, {
+ /**
+ * @for DDM
+ * @namespace DD
+ * @private
+ * @method _calcTicks
+ * @description Helper method to calculate the tick offsets for a given position
+ * @param {Number} pos The current X or Y position
+ * @param {Number} start The start X or Y position
+ * @param {Number} tick The X or Y tick increment
+ * @param {Number} off1 The min offset that we can't pass (region)
+ * @param {Number} off2 The max offset that we can't pass (region)
+ * @return {Number} The new position based on the tick calculation
+ */
+ _calcTicks: function(pos, start, tick, off1, off2) {
+ var ix = ((pos - start) / tick),
+ min = Math.floor(ix),
+ max = Math.ceil(ix);
+ if ((min !== 0) || (max !== 0)) {
+ if ((ix >= min) && (ix <= max)) {
+ pos = (start + (tick * min));
+ if (off1 && off2) {
+ if (pos < off1) {
+ pos = (start + (tick * (min + 1)));
+ }
+ if (pos > off2) {
+ pos = (start + (tick * (min - 1)));
+ }
+ }
+ }
+ }
+ return pos;
+ },
+ /**
+ * @for DDM
+ * @namespace DD
+ * @private
+ * @method _calcTickArray
+ * @description This method is used with the tickXArray and tickYArray config options
+ * @param {Number} pos The current X or Y position
+ * @param {Number} ticks The array containing our custom tick positions.
+ * @param {Number} off1 The min offset that we can't pass (region)
+ * @param {Number} off2 The max offset that we can't pass (region)
+ * @return The tick position
+ */
+ _calcTickArray: function(pos, ticks, off1, off2) {
+ var i = 0, len = ticks.length, next = 0,
+ diff1, diff2, ret;
+
+ if (!ticks || (ticks.length === 0)) {
+ return pos;
+ } else if (ticks[0] >= pos) {
+ return ticks[0];
+ } else {
+ for (i = 0; i < len; i++) {
+ next = (i + 1);
+ if (ticks[next] && ticks[next] >= pos) {
+ diff1 = pos - ticks[i];
+ diff2 = ticks[next] - pos;
+ ret = (diff2 > diff1) ? ticks[i] : ticks[next];
+ if (off1 && off2) {
+ if (ret > off2) {
+ if (ticks[i]) {
+ ret = ticks[i];
+ } else {
+ ret = ticks[len - 1];
+ }
+ }
+ }
+ return ret;
+ }
+
+ }
+ return ticks[ticks.length - 1];
+ }
+ }
+ });
+
+
+
+
+}, '3.0.0' ,{requires:['dd-drag'], skinnable:false});
diff --git a/lib/yui/3.0.0/dd/dd-constrain-min.js b/lib/yui/3.0.0/dd/dd-constrain-min.js
new file mode 100644
index 0000000000..5f3f7fb96c
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-constrain-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("dd-constrain",function(B){var K="dragNode",M="offsetHeight",F="offsetWidth",Q="host",P="constrain2region",H="constrain2node",G="tickXArray",O="tickYArray",N=B.DD.DDM,E="top",J="right",L="bottom",D="left",I=null;var A=function(C){A.superclass.constructor.apply(this,arguments);};A.NAME="DragConstrained";A.NS="con";A.ATTRS={host:{},stickX:{value:false},stickY:{value:false},tickX:{value:false},tickY:{value:false},tickXArray:{value:false},tickYArray:{value:false},constrain2region:{value:false,getter:function(C){if(B.Lang.isObject(C)){var R={};B.mix(R,C);return R;}else{return false;}},setter:function(C){if(B.Lang.isObject(C)){if(B.Lang.isNumber(C[E])&&B.Lang.isNumber(C[J])&&B.Lang.isNumber(C[D])&&B.Lang.isNumber(C[L])){var R={};B.mix(R,C);return R;}else{return false;}}else{if(C!==false){return false;}}return C;}},gutter:{value:"0",setter:function(C){return B.DD.DDM.cssSizestoObject(C);}},constrain2node:{value:false,setter:function(R){if(!this.get(P)){var C=B.Node.get(R);if(C){return C;}}else{if(this.get(P)!==false){}}return false;}},constrain2view:{value:false}};I={initializer:function(){this.get(Q).on("drag:start",B.bind(this._handleStart,this));this.get(Q).after("drag:align",B.bind(this.align,this));},_handleStart:function(){this._regionCache=null;},_regionCache:null,_cacheRegion:function(){this._regionCache=this.get(H).get("region");},getRegion:function(V){var T={},U=null,C=null,S=this.get("gutter"),R=this.get(Q);if(this.get(H)){if(!this._regionCache){B.on("resize",B.bind(this._cacheRegion,this),window);this._cacheRegion();}T=B.clone(this._regionCache);}else{if(this.get(P)){T=this.get(P);}else{if(this.get("constrain2view")){T=R.get(K).get("viewportRegion");}else{return false;}}}B.each(S,function(W,X){if((X==J)||(X==L)){T[X]-=W;}else{T[X]+=W;}});if(V){U=R.get(K).get(M);C=R.get(K).get(F);T[J]=T[J]-C;T[L]=T[L]-U;}return T;},_checkRegion:function(C){var S=C,U=this.getRegion(),T=this.get(Q),V=T.get(K).get(M),R=T.get(K).get(F);if(S[1]>(U[L]-V)){C[1]=(U[L]-V);}if(U[E]>S[1]){C[1]=U[E];}if(S[0]>(U[J]-R)){C[0]=(U[J]-R);}if(U[D]>S[0]){C[0]=U[D];}return C;},inRegion:function(S){S=S||this.get(Q).get(K).getXY();var R=this._checkRegion([S[0],S[1]]),C=false;if((S[0]===R[0])&&(S[1]===R[1])){C=true;}return C;},align:function(){var S=this.get(Q),C=S.actXY,R=this.getRegion(true);if(this.get("stickX")){C[1]=(S.startXY[1]-S.deltaXY[1]);}if(this.get("stickY")){C[0]=(S.startXY[0]-S.deltaXY[0]);}if(R){C=this._checkRegion(C);}C=this._checkTicks(C,R);S.actXY=C;},_checkTicks:function(W,U){var T=this.get(Q),V=(T.startXY[0]-T.deltaXY[0]),S=(T.startXY[1]-T.deltaXY[1]),C=this.get("tickX"),R=this.get("tickY");if(C&&!this.get(G)){W[0]=N._calcTicks(W[0],V,C,U[D],U[J]);}if(R&&!this.get(O)){W[1]=N._calcTicks(W[1],S,R,U[E],U[L]);}if(this.get(G)){W[0]=N._calcTickArray(W[0],this.get(G),U[D],U[J]);}if(this.get(O)){W[1]=N._calcTickArray(W[1],this.get(O),U[E],U[L]);}return W;}};B.namespace("Plugin");B.extend(A,B.Base,I);B.Plugin.DDConstrained=A;B.mix(N,{_calcTicks:function(X,W,T,V,U){var R=((X-W)/T),S=Math.floor(R),C=Math.ceil(R);if((S!==0)||(C!==0)){if((R>=S)&&(R<=C)){X=(W+(T*S));if(V&&U){if(XU){X=(W+(T*(S-1)));}}}}return X;},_calcTickArray:function(Y,Z,X,U){var R=0,V=Z.length,T=0,S,C,W;if(!Z||(Z.length===0)){return Y;}else{if(Z[0]>=Y){return Z[0];}else{for(R=0;R=Y){S=Y-Z[R];C=Z[T]-Y;W=(C>S)?Z[R]:Z[T];if(X&&U){if(W>U){if(Z[R]){W=Z[R];}else{W=Z[V-1];}}}return W;}}return Z[Z.length-1];}}}});},"3.0.0",{requires:["dd-drag"],skinnable:false});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/dd/dd-constrain.js b/lib/yui/3.0.0/dd/dd-constrain.js
new file mode 100644
index 0000000000..7d2b5e1459
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-constrain.js
@@ -0,0 +1,425 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dd-constrain', function(Y) {
+
+
+ /**
+ * The Drag & Drop Utility allows you to create a draggable interface efficiently, buffering you from browser-level abnormalities and enabling you to focus on the interesting logic surrounding your particular implementation. This component enables you to create a variety of standard draggable objects with just a few lines of code and then, using its extensive API, add your own specific implementation logic.
+ * @module dd
+ * @submodule dd-constrain
+ */
+ /**
+ * This is a plugin for the dd-drag module to add the constraining methods to it. It supports constraining to a renodenode or viewport. It anode* supports tick based moves and XY axis constraints.
+ * @class DragConstrained
+ * @extends Base
+ * @constructor
+ * @namespace Plugin
+ */
+
+ var DRAG_NODE = 'dragNode',
+ OFFSET_HEIGHT = 'offsetHeight',
+ OFFSET_WIDTH = 'offsetWidth',
+ HOST = 'host',
+ CON_2_REGION = 'constrain2region',
+ CON_2_NODE = 'constrain2node',
+ TICK_X_ARRAY = 'tickXArray',
+ TICK_Y_ARRAY = 'tickYArray',
+ DDM = Y.DD.DDM,
+ TOP = 'top',
+ RIGHT = 'right',
+ BOTTOM = 'bottom',
+ LEFT = 'left',
+ proto = null;
+
+ var C = function(config) {
+ C.superclass.constructor.apply(this, arguments);
+ };
+
+ C.NAME = 'DragConstrained';
+ /**
+ * @property con
+ * @description The Constrained instance will be placed on the Drag instance under the con namespace.
+ * @type {String}
+ */
+ C.NS = 'con';
+
+ C.ATTRS = {
+ host: {
+ },
+ /**
+ * @attribute stickX
+ * @description Stick the drag movement to the X-Axis. Default: false
+ * @type Boolean
+ */
+ stickX: {
+ value: false
+ },
+ /**
+ * @attribute stickY
+ * @description Stick the drag movement to the Y-Axis
+ * @type Boolean
+ */
+ stickY: {
+ value: false
+ },
+ /**
+ * @attribute tickX
+ * @description The X tick offset the drag node should snap to on each drag move. False for no ticks. Default: false
+ * @type Number/false
+ */
+ tickX: {
+ value: false
+ },
+ /**
+ * @attribute tickY
+ * @description The Y tick offset the drag node should snap to on each drag move. False for no ticks. Default: false
+ * @type Number/false
+ */
+ tickY: {
+ value: false
+ },
+ /**
+ * @attribute tickXArray
+ * @description An array of page coordinates to use as X ticks for drag movement.
+ * @type Array
+ */
+ tickXArray: {
+ value: false
+ },
+ /**
+ * @attribute tickYArray
+ * @description An array of page coordinates to use as Y ticks for drag movement.
+ * @type Array
+ */
+ tickYArray: {
+ value: false
+ },
+ /**
+ * @attribute constrain2region
+ * @description An Object Literal containing a valid region (top, right, bottom, left) of page positions to constrain the drag node to.
+ * @type Object
+ */
+ constrain2region: {
+ value: false,
+ getter: function(r) {
+ if (Y.Lang.isObject(r)) {
+ var o = {};
+ Y.mix(o, r);
+ return o;
+ } else {
+ return false;
+ }
+ },
+ setter: function (r) {
+ if (Y.Lang.isObject(r)) {
+ if (Y.Lang.isNumber(r[TOP]) && Y.Lang.isNumber(r[RIGHT]) && Y.Lang.isNumber(r[LEFT]) && Y.Lang.isNumber(r[BOTTOM])) {
+ var o = {};
+ Y.mix(o, r);
+ return o;
+ } else {
+ return false;
+ }
+ } else if (r !== false) {
+ return false;
+ }
+ return r;
+ }
+ },
+ /**
+ * @attribute gutter
+ * @description CSS style string for the gutter of a region (supports negative values): '5 0' (sets top and bottom to 5px, left and right to 0px), '1 2 3 4' (top 1px, right 2px, bottom 3px, left 4px)
+ * @type String
+ */
+ gutter: {
+ value: '0',
+ setter: function(gutter) {
+ return Y.DD.DDM.cssSizestoObject(gutter);
+ }
+ },
+ /**
+ * @attribute constrain2node
+ * @description Will attempt to constrain the drag node to the boundaries of this node.
+ * @type Object
+ */
+ constrain2node: {
+ value: false,
+ setter: function(n) {
+ if (!this.get(CON_2_REGION)) {
+ var node = Y.Node.get(n);
+ if (node) {
+ return node;
+ }
+ } else if (this.get(CON_2_REGION) !== false) {
+ }
+ return false;
+ }
+ },
+ /**
+ * @attribute constrain2view
+ * @description Will attempt to constrain the drag node to the boundaries of the viewport region.
+ * @type Object
+ */
+ constrain2view: {
+ value: false
+ }
+ };
+
+ proto = {
+ initializer: function() {
+ this.get(HOST).on('drag:start', Y.bind(this._handleStart, this));
+ this.get(HOST).after('drag:align', Y.bind(this.align, this));
+ },
+ /**
+ * @private
+ * @method _handleStart
+ * @description Fires on drag:start and clears the _regionCache
+ */
+ _handleStart: function() {
+ this._regionCache = null;
+ },
+ /**
+ * @private
+ * @property _regionCache
+ * @description Store a cache of the region that we are constraining to
+ * @type Object
+ */
+ _regionCache: null,
+ /**
+ * @private
+ * @method _cacheRegion
+ * @description Get's the region and caches it, called from window.resize and when the cache is null
+ */
+ _cacheRegion: function() {
+ this._regionCache = this.get(CON_2_NODE).get('region');
+ },
+ /**
+ * @method getRegion
+ * @description Get the active region: viewport, node, custom region
+ * @param {Boolean} inc Include the node's height and width
+ * @return {Object}
+ */
+ getRegion: function(inc) {
+ var r = {}, oh = null, ow = null,
+ g = this.get('gutter'),
+ host = this.get(HOST);
+
+ if (this.get(CON_2_NODE)) {
+ if (!this._regionCache) {
+ Y.on('resize', Y.bind(this._cacheRegion, this), window);
+ this._cacheRegion();
+ }
+ r = Y.clone(this._regionCache);
+ } else if (this.get(CON_2_REGION)) {
+ r = this.get(CON_2_REGION);
+ } else if (this.get('constrain2view')) {
+ r = host.get(DRAG_NODE).get('viewportRegion');
+ } else {
+ return false;
+ }
+
+ Y.each(g, function(i, n) {
+ if ((n == RIGHT) || (n == BOTTOM)) {
+ r[n] -= i;
+ } else {
+ r[n] += i;
+ }
+ });
+ if (inc) {
+ oh = host.get(DRAG_NODE).get(OFFSET_HEIGHT);
+ ow = host.get(DRAG_NODE).get(OFFSET_WIDTH);
+ r[RIGHT] = r[RIGHT] - ow;
+ r[BOTTOM] = r[BOTTOM] - oh;
+ }
+ return r;
+ },
+ /**
+ * @private
+ * @method _checkRegion
+ * @description Check if xy is inside a given region, if not change to it be inside.
+ * @param {Array} _xy The XY to check if it's in the current region, if it isn't inside the region, it will reset the xy array to be inside the region.
+ * @return {Array} The new XY that is inside the region
+ */
+ _checkRegion: function(_xy) {
+ var oxy = _xy,
+ r = this.getRegion(),
+ host = this.get(HOST),
+ oh = host.get(DRAG_NODE).get(OFFSET_HEIGHT),
+ ow = host.get(DRAG_NODE).get(OFFSET_WIDTH);
+
+ if (oxy[1] > (r[BOTTOM] - oh)) {
+ _xy[1] = (r[BOTTOM] - oh);
+ }
+ if (r[TOP] > oxy[1]) {
+ _xy[1] = r[TOP];
+
+ }
+ if (oxy[0] > (r[RIGHT] - ow)) {
+ _xy[0] = (r[RIGHT] - ow);
+ }
+ if (r[LEFT] > oxy[0]) {
+ _xy[0] = r[LEFT];
+ }
+
+ return _xy;
+ },
+ /**
+ * @method inRegion
+ * @description Checks if the XY passed or the dragNode is inside the active region.
+ * @param {Array} xy Optional XY to check, if not supplied this.get('dragNode').getXY() is used.
+ * @return {Boolean} True if the XY is inside the region, false otherwise.
+ */
+ inRegion: function(xy) {
+ xy = xy || this.get(HOST).get(DRAG_NODE).getXY();
+
+ var _xy = this._checkRegion([xy[0], xy[1]]),
+ inside = false;
+ if ((xy[0] === _xy[0]) && (xy[1] === _xy[1])) {
+ inside = true;
+ }
+ return inside;
+ },
+ /**
+ * @method align
+ * @description Modifies the Drag.actXY method from the after drag:align event. This is where the constraining happens.
+ */
+ align: function() {
+ var host = this.get(HOST),
+ _xy = host.actXY,
+ r = this.getRegion(true);
+
+ if (this.get('stickX')) {
+ _xy[1] = (host.startXY[1] - host.deltaXY[1]);
+ }
+ if (this.get('stickY')) {
+ _xy[0] = (host.startXY[0] - host.deltaXY[0]);
+ }
+
+ if (r) {
+ _xy = this._checkRegion(_xy);
+ }
+
+ _xy = this._checkTicks(_xy, r);
+ host.actXY = _xy;
+ },
+ /**
+ * @private
+ * @method _checkTicks
+ * @description This method delegates the proper helper method for tick calculations
+ * @param {Array} xy The XY coords for the Drag
+ * @param {Object} r The optional region that we are bound to.
+ * @return {Array} The calced XY coords
+ */
+ _checkTicks: function(xy, r) {
+ var host = this.get(HOST),
+ lx = (host.startXY[0] - host.deltaXY[0]),
+ ly = (host.startXY[1] - host.deltaXY[1]),
+ xt = this.get('tickX'),
+ yt = this.get('tickY');
+ if (xt && !this.get(TICK_X_ARRAY)) {
+ xy[0] = DDM._calcTicks(xy[0], lx, xt, r[LEFT], r[RIGHT]);
+ }
+ if (yt && !this.get(TICK_Y_ARRAY)) {
+ xy[1] = DDM._calcTicks(xy[1], ly, yt, r[TOP], r[BOTTOM]);
+ }
+ if (this.get(TICK_X_ARRAY)) {
+ xy[0] = DDM._calcTickArray(xy[0], this.get(TICK_X_ARRAY), r[LEFT], r[RIGHT]);
+ }
+ if (this.get(TICK_Y_ARRAY)) {
+ xy[1] = DDM._calcTickArray(xy[1], this.get(TICK_Y_ARRAY), r[TOP], r[BOTTOM]);
+ }
+
+ return xy;
+ }
+ };
+
+ Y.namespace('Plugin');
+ Y.extend(C, Y.Base, proto);
+ Y.Plugin.DDConstrained = C;
+
+ Y.mix(DDM, {
+ /**
+ * @for DDM
+ * @namespace DD
+ * @private
+ * @method _calcTicks
+ * @description Helper method to calculate the tick offsets for a given position
+ * @param {Number} pos The current X or Y position
+ * @param {Number} start The start X or Y position
+ * @param {Number} tick The X or Y tick increment
+ * @param {Number} off1 The min offset that we can't pass (region)
+ * @param {Number} off2 The max offset that we can't pass (region)
+ * @return {Number} The new position based on the tick calculation
+ */
+ _calcTicks: function(pos, start, tick, off1, off2) {
+ var ix = ((pos - start) / tick),
+ min = Math.floor(ix),
+ max = Math.ceil(ix);
+ if ((min !== 0) || (max !== 0)) {
+ if ((ix >= min) && (ix <= max)) {
+ pos = (start + (tick * min));
+ if (off1 && off2) {
+ if (pos < off1) {
+ pos = (start + (tick * (min + 1)));
+ }
+ if (pos > off2) {
+ pos = (start + (tick * (min - 1)));
+ }
+ }
+ }
+ }
+ return pos;
+ },
+ /**
+ * @for DDM
+ * @namespace DD
+ * @private
+ * @method _calcTickArray
+ * @description This method is used with the tickXArray and tickYArray config options
+ * @param {Number} pos The current X or Y position
+ * @param {Number} ticks The array containing our custom tick positions.
+ * @param {Number} off1 The min offset that we can't pass (region)
+ * @param {Number} off2 The max offset that we can't pass (region)
+ * @return The tick position
+ */
+ _calcTickArray: function(pos, ticks, off1, off2) {
+ var i = 0, len = ticks.length, next = 0,
+ diff1, diff2, ret;
+
+ if (!ticks || (ticks.length === 0)) {
+ return pos;
+ } else if (ticks[0] >= pos) {
+ return ticks[0];
+ } else {
+ for (i = 0; i < len; i++) {
+ next = (i + 1);
+ if (ticks[next] && ticks[next] >= pos) {
+ diff1 = pos - ticks[i];
+ diff2 = ticks[next] - pos;
+ ret = (diff2 > diff1) ? ticks[i] : ticks[next];
+ if (off1 && off2) {
+ if (ret > off2) {
+ if (ticks[i]) {
+ ret = ticks[i];
+ } else {
+ ret = ticks[len - 1];
+ }
+ }
+ }
+ return ret;
+ }
+
+ }
+ return ticks[ticks.length - 1];
+ }
+ }
+ });
+
+
+
+
+}, '3.0.0' ,{requires:['dd-drag'], skinnable:false});
diff --git a/lib/yui/3.0.0/dd/dd-ddm-base-debug.js b/lib/yui/3.0.0/dd/dd-ddm-base-debug.js
new file mode 100644
index 0000000000..2d39630a90
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-ddm-base-debug.js
@@ -0,0 +1,289 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dd-ddm-base', function(Y) {
+
+
+ /**
+ * Provides the base Drag Drop Manger required for making a Node draggable.
+ * @module dd
+ * @submodule dd-ddm-base
+ */
+ /**
+ * Provides the base Drag Drop Manger required for making a Node draggable.
+ * @class DDM
+ * @extends Base
+ * @constructor
+ * @namespace DD
+ */
+
+ var DDMBase = function() {
+ DDMBase.superclass.constructor.apply(this, arguments);
+ };
+
+ DDMBase.NAME = 'ddm';
+
+ DDMBase.ATTRS = {
+ /**
+ * @attribute dragCursor
+ * @description The cursor to apply when dragging, if shimmed the shim will get the cursor.
+ * @type String
+ */
+ dragCursor: {
+ value: 'move'
+ },
+ /**
+ * @attribute clickPixelThresh
+ * @description The number of pixels to move to start a drag operation, default is 3.
+ * @type Number
+ */
+ clickPixelThresh: {
+ value: 3
+ },
+ /**
+ * @attribute clickTimeThresh
+ * @description The number of milliseconds a mousedown has to pass to start a drag operation, default is 1000.
+ * @type Number
+ */
+ clickTimeThresh: {
+ value: 1000
+ },
+ /**
+ * @attribute dragMode
+ * @description This attribute only works if the dd-drop module is active. It will set the dragMode (point, intersect, strict) of all future Drag instances.
+ * @type String
+ */
+ dragMode: {
+ value: 'point',
+ setter: function(mode) {
+ this._setDragMode(mode);
+ return mode;
+ }
+ }
+
+ };
+
+ Y.extend(DDMBase, Y.Base, {
+ /**
+ * @property _active
+ * @description flag set when we activate our first drag, so DDM can start listening for events.
+ * @type {Boolean}
+ */
+ _active: null,
+ /**
+ * @private
+ * @method _setDragMode
+ * @description Handler for dragMode attribute setter.
+ * @param String/Number The Number value or the String for the DragMode to default all future drag instances to.
+ * @return Number The Mode to be set
+ */
+ _setDragMode: function(mode) {
+ if (mode === null) {
+ mode = Y.DD.DDM.get('dragMode');
+ }
+ switch (mode) {
+ case 1:
+ case 'intersect':
+ return 1;
+ case 2:
+ case 'strict':
+ return 2;
+ case 0:
+ case 'point':
+ return 0;
+ }
+ return 0;
+ },
+ /**
+ * @property CSS_PREFIX
+ * @description The PREFIX to attach to all DD CSS class names
+ * @type {String}
+ */
+ CSS_PREFIX: 'yui-dd',
+ _activateTargets: function() {},
+ /**
+ * @private
+ * @property _drags
+ * @description Holder for all registered drag elements.
+ * @type {Array}
+ */
+ _drags: [],
+ /**
+ * @property activeDrag
+ * @description A reference to the currently active draggable object.
+ * @type {Drag}
+ */
+ activeDrag: false,
+ /**
+ * @private
+ * @method _regDrag
+ * @description Adds a reference to the drag object to the DDM._drags array, called in the constructor of Drag.
+ * @param {Drag} d The Drag object
+ */
+ _regDrag: function(d) {
+ if (this.getDrag(d.get('node'))) {
+ return false;
+ }
+
+ if (!this._active) {
+ this._setupListeners();
+ }
+ this._drags.push(d);
+ return true;
+ },
+ /**
+ * @private
+ * @method _unregDrag
+ * @description Remove this drag object from the DDM._drags array.
+ * @param {Drag} d The drag object.
+ */
+ _unregDrag: function(d) {
+ var tmp = [];
+ Y.each(this._drags, function(n, i) {
+ if (n !== d) {
+ tmp[tmp.length] = n;
+ }
+ });
+ this._drags = tmp;
+ },
+ /**
+ * @private
+ * @method _setupListeners
+ * @description Add the document listeners.
+ */
+ _setupListeners: function() {
+ this._active = true;
+ var doc = Y.get(document);
+ doc.on('mousemove', Y.bind(this._move, this));
+ //Y.Event.nativeAdd(document, 'mousemove', Y.bind(this._move, this));
+ doc.on('mouseup', Y.bind(this._end, this));
+ },
+ /**
+ * @private
+ * @method _start
+ * @description Internal method used by Drag to signal the start of a drag operation
+ */
+ _start: function() {
+ this.fire('ddm:start');
+ this._startDrag();
+ },
+ /**
+ * @private
+ * @method _startDrag
+ * @description Factory method to be overwritten by other DDM's
+ * @param {Number} x The x position of the drag element
+ * @param {Number} y The y position of the drag element
+ * @param {Number} w The width of the drag element
+ * @param {Number} h The height of the drag element
+ */
+ _startDrag: function() {},
+ /**
+ * @private
+ * @method _endDrag
+ * @description Factory method to be overwritten by other DDM's
+ */
+ _endDrag: function() {},
+ _dropMove: function() {},
+ /**
+ * @private
+ * @method _end
+ * @description Internal method used by Drag to signal the end of a drag operation
+ */
+ _end: function() {
+ if (this.activeDrag) {
+ this._endDrag();
+ this.fire('ddm:end');
+ this.activeDrag.end.call(this.activeDrag);
+ this.activeDrag = null;
+ }
+ },
+ /**
+ * @method stopDrag
+ * @description Method will forcefully stop a drag operation. For example calling this from inside an ESC keypress handler will stop this drag.
+ * @return {Self}
+ * @chainable
+ */
+ stopDrag: function() {
+ if (this.activeDrag) {
+ this._end();
+ }
+ return this;
+ },
+ /**
+ * @private
+ * @method _move
+ * @description Internal listener for the mousemove DOM event to pass to the Drag's move method.
+ * @param {Event.Facade} ev The Dom mousemove Event
+ */
+ _move: function(ev) {
+ if (this.activeDrag) {
+ this.activeDrag._move.call(this.activeDrag, ev);
+ this._dropMove();
+ }
+ },
+ /**
+ * //TODO Private, rename??...
+ * @private
+ * @method cssSizestoObject
+ * @description Helper method to use to set the gutter from the attribute setter.
+ * @param {String} gutter CSS style string for gutter: '5 0' (sets top and bottom to 5px, left and right to 0px), '1 2 3 4' (top 1px, right 2px, bottom 3px, left 4px)
+ * @return {Object} The gutter Object Literal.
+ */
+ cssSizestoObject: function(gutter) {
+ var x = gutter.split(' ');
+
+ switch (x.length) {
+ case 1: x[1] = x[2] = x[3] = x[0]; break;
+ case 2: x[2] = x[0]; x[3] = x[1]; break;
+ case 3: x[3] = x[1]; break;
+ }
+
+ return {
+ top : parseInt(x[0],10),
+ right : parseInt(x[1],10),
+ bottom: parseInt(x[2],10),
+ left : parseInt(x[3],10)
+ };
+ },
+ /**
+ * @method getDrag
+ * @description Get a valid Drag instance back from a Node or a selector string, false otherwise
+ * @param {String/Object} node The Node instance or Selector string to check for a valid Drag Object
+ * @return {Object}
+ */
+ getDrag: function(node) {
+ var drag = false,
+ n = Y.get(node);
+ if (n instanceof Y.Node) {
+ Y.each(this._drags, function(v, k) {
+ if (n.compareTo(v.get('node'))) {
+ drag = v;
+ }
+ });
+ }
+ return drag;
+ }
+ });
+
+ Y.namespace('DD');
+ Y.DD.DDM = new DDMBase();
+
+ /**
+ * @event ddm:start
+ * @description Fires from the DDM before all drag events fire.
+ * @type {Event.Custom}
+ */
+ /**
+ * @event ddm:end
+ * @description Fires from the DDM after the DDM finishes, before the drag end events.
+ * @type {Event.Custom}
+ */
+
+
+
+
+}, '3.0.0' ,{requires:['node', 'base'], skinnable:false});
diff --git a/lib/yui/3.0.0/dd/dd-ddm-base-min.js b/lib/yui/3.0.0/dd/dd-ddm-base-min.js
new file mode 100644
index 0000000000..a1539c2d84
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-ddm-base-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("dd-ddm-base",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};A.NAME="ddm";A.ATTRS={dragCursor:{value:"move"},clickPixelThresh:{value:3},clickTimeThresh:{value:1000},dragMode:{value:"point",setter:function(C){this._setDragMode(C);return C;}}};B.extend(A,B.Base,{_active:null,_setDragMode:function(C){if(C===null){C=B.DD.DDM.get("dragMode");}switch(C){case 1:case"intersect":return 1;case 2:case"strict":return 2;case 0:case"point":return 0;}return 0;},CSS_PREFIX:"yui-dd",_activateTargets:function(){},_drags:[],activeDrag:false,_regDrag:function(C){if(this.getDrag(C.get("node"))){return false;}if(!this._active){this._setupListeners();}this._drags.push(C);return true;},_unregDrag:function(D){var C=[];B.each(this._drags,function(F,E){if(F!==D){C[C.length]=F;}});this._drags=C;},_setupListeners:function(){this._active=true;var C=B.get(document);C.on("mousemove",B.bind(this._move,this));C.on("mouseup",B.bind(this._end,this));},_start:function(){this.fire("ddm:start");this._startDrag();},_startDrag:function(){},_endDrag:function(){},_dropMove:function(){},_end:function(){if(this.activeDrag){this._endDrag();this.fire("ddm:end");this.activeDrag.end.call(this.activeDrag);this.activeDrag=null;}},stopDrag:function(){if(this.activeDrag){this._end();}return this;},_move:function(C){if(this.activeDrag){this.activeDrag._move.call(this.activeDrag,C);this._dropMove();}},cssSizestoObject:function(D){var C=D.split(" ");switch(C.length){case 1:C[1]=C[2]=C[3]=C[0];break;case 2:C[2]=C[0];C[3]=C[1];break;case 3:C[3]=C[1];break;}return{top:parseInt(C[0],10),right:parseInt(C[1],10),bottom:parseInt(C[2],10),left:parseInt(C[3],10)};},getDrag:function(D){var C=false,E=B.get(D);if(E instanceof B.Node){B.each(this._drags,function(G,F){if(E.compareTo(G.get("node"))){C=G;}});}return C;}});B.namespace("DD");B.DD.DDM=new A();},"3.0.0",{requires:["node","base"],skinnable:false});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/dd/dd-ddm-base.js b/lib/yui/3.0.0/dd/dd-ddm-base.js
new file mode 100644
index 0000000000..2d39630a90
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-ddm-base.js
@@ -0,0 +1,289 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dd-ddm-base', function(Y) {
+
+
+ /**
+ * Provides the base Drag Drop Manger required for making a Node draggable.
+ * @module dd
+ * @submodule dd-ddm-base
+ */
+ /**
+ * Provides the base Drag Drop Manger required for making a Node draggable.
+ * @class DDM
+ * @extends Base
+ * @constructor
+ * @namespace DD
+ */
+
+ var DDMBase = function() {
+ DDMBase.superclass.constructor.apply(this, arguments);
+ };
+
+ DDMBase.NAME = 'ddm';
+
+ DDMBase.ATTRS = {
+ /**
+ * @attribute dragCursor
+ * @description The cursor to apply when dragging, if shimmed the shim will get the cursor.
+ * @type String
+ */
+ dragCursor: {
+ value: 'move'
+ },
+ /**
+ * @attribute clickPixelThresh
+ * @description The number of pixels to move to start a drag operation, default is 3.
+ * @type Number
+ */
+ clickPixelThresh: {
+ value: 3
+ },
+ /**
+ * @attribute clickTimeThresh
+ * @description The number of milliseconds a mousedown has to pass to start a drag operation, default is 1000.
+ * @type Number
+ */
+ clickTimeThresh: {
+ value: 1000
+ },
+ /**
+ * @attribute dragMode
+ * @description This attribute only works if the dd-drop module is active. It will set the dragMode (point, intersect, strict) of all future Drag instances.
+ * @type String
+ */
+ dragMode: {
+ value: 'point',
+ setter: function(mode) {
+ this._setDragMode(mode);
+ return mode;
+ }
+ }
+
+ };
+
+ Y.extend(DDMBase, Y.Base, {
+ /**
+ * @property _active
+ * @description flag set when we activate our first drag, so DDM can start listening for events.
+ * @type {Boolean}
+ */
+ _active: null,
+ /**
+ * @private
+ * @method _setDragMode
+ * @description Handler for dragMode attribute setter.
+ * @param String/Number The Number value or the String for the DragMode to default all future drag instances to.
+ * @return Number The Mode to be set
+ */
+ _setDragMode: function(mode) {
+ if (mode === null) {
+ mode = Y.DD.DDM.get('dragMode');
+ }
+ switch (mode) {
+ case 1:
+ case 'intersect':
+ return 1;
+ case 2:
+ case 'strict':
+ return 2;
+ case 0:
+ case 'point':
+ return 0;
+ }
+ return 0;
+ },
+ /**
+ * @property CSS_PREFIX
+ * @description The PREFIX to attach to all DD CSS class names
+ * @type {String}
+ */
+ CSS_PREFIX: 'yui-dd',
+ _activateTargets: function() {},
+ /**
+ * @private
+ * @property _drags
+ * @description Holder for all registered drag elements.
+ * @type {Array}
+ */
+ _drags: [],
+ /**
+ * @property activeDrag
+ * @description A reference to the currently active draggable object.
+ * @type {Drag}
+ */
+ activeDrag: false,
+ /**
+ * @private
+ * @method _regDrag
+ * @description Adds a reference to the drag object to the DDM._drags array, called in the constructor of Drag.
+ * @param {Drag} d The Drag object
+ */
+ _regDrag: function(d) {
+ if (this.getDrag(d.get('node'))) {
+ return false;
+ }
+
+ if (!this._active) {
+ this._setupListeners();
+ }
+ this._drags.push(d);
+ return true;
+ },
+ /**
+ * @private
+ * @method _unregDrag
+ * @description Remove this drag object from the DDM._drags array.
+ * @param {Drag} d The drag object.
+ */
+ _unregDrag: function(d) {
+ var tmp = [];
+ Y.each(this._drags, function(n, i) {
+ if (n !== d) {
+ tmp[tmp.length] = n;
+ }
+ });
+ this._drags = tmp;
+ },
+ /**
+ * @private
+ * @method _setupListeners
+ * @description Add the document listeners.
+ */
+ _setupListeners: function() {
+ this._active = true;
+ var doc = Y.get(document);
+ doc.on('mousemove', Y.bind(this._move, this));
+ //Y.Event.nativeAdd(document, 'mousemove', Y.bind(this._move, this));
+ doc.on('mouseup', Y.bind(this._end, this));
+ },
+ /**
+ * @private
+ * @method _start
+ * @description Internal method used by Drag to signal the start of a drag operation
+ */
+ _start: function() {
+ this.fire('ddm:start');
+ this._startDrag();
+ },
+ /**
+ * @private
+ * @method _startDrag
+ * @description Factory method to be overwritten by other DDM's
+ * @param {Number} x The x position of the drag element
+ * @param {Number} y The y position of the drag element
+ * @param {Number} w The width of the drag element
+ * @param {Number} h The height of the drag element
+ */
+ _startDrag: function() {},
+ /**
+ * @private
+ * @method _endDrag
+ * @description Factory method to be overwritten by other DDM's
+ */
+ _endDrag: function() {},
+ _dropMove: function() {},
+ /**
+ * @private
+ * @method _end
+ * @description Internal method used by Drag to signal the end of a drag operation
+ */
+ _end: function() {
+ if (this.activeDrag) {
+ this._endDrag();
+ this.fire('ddm:end');
+ this.activeDrag.end.call(this.activeDrag);
+ this.activeDrag = null;
+ }
+ },
+ /**
+ * @method stopDrag
+ * @description Method will forcefully stop a drag operation. For example calling this from inside an ESC keypress handler will stop this drag.
+ * @return {Self}
+ * @chainable
+ */
+ stopDrag: function() {
+ if (this.activeDrag) {
+ this._end();
+ }
+ return this;
+ },
+ /**
+ * @private
+ * @method _move
+ * @description Internal listener for the mousemove DOM event to pass to the Drag's move method.
+ * @param {Event.Facade} ev The Dom mousemove Event
+ */
+ _move: function(ev) {
+ if (this.activeDrag) {
+ this.activeDrag._move.call(this.activeDrag, ev);
+ this._dropMove();
+ }
+ },
+ /**
+ * //TODO Private, rename??...
+ * @private
+ * @method cssSizestoObject
+ * @description Helper method to use to set the gutter from the attribute setter.
+ * @param {String} gutter CSS style string for gutter: '5 0' (sets top and bottom to 5px, left and right to 0px), '1 2 3 4' (top 1px, right 2px, bottom 3px, left 4px)
+ * @return {Object} The gutter Object Literal.
+ */
+ cssSizestoObject: function(gutter) {
+ var x = gutter.split(' ');
+
+ switch (x.length) {
+ case 1: x[1] = x[2] = x[3] = x[0]; break;
+ case 2: x[2] = x[0]; x[3] = x[1]; break;
+ case 3: x[3] = x[1]; break;
+ }
+
+ return {
+ top : parseInt(x[0],10),
+ right : parseInt(x[1],10),
+ bottom: parseInt(x[2],10),
+ left : parseInt(x[3],10)
+ };
+ },
+ /**
+ * @method getDrag
+ * @description Get a valid Drag instance back from a Node or a selector string, false otherwise
+ * @param {String/Object} node The Node instance or Selector string to check for a valid Drag Object
+ * @return {Object}
+ */
+ getDrag: function(node) {
+ var drag = false,
+ n = Y.get(node);
+ if (n instanceof Y.Node) {
+ Y.each(this._drags, function(v, k) {
+ if (n.compareTo(v.get('node'))) {
+ drag = v;
+ }
+ });
+ }
+ return drag;
+ }
+ });
+
+ Y.namespace('DD');
+ Y.DD.DDM = new DDMBase();
+
+ /**
+ * @event ddm:start
+ * @description Fires from the DDM before all drag events fire.
+ * @type {Event.Custom}
+ */
+ /**
+ * @event ddm:end
+ * @description Fires from the DDM after the DDM finishes, before the drag end events.
+ * @type {Event.Custom}
+ */
+
+
+
+
+}, '3.0.0' ,{requires:['node', 'base'], skinnable:false});
diff --git a/lib/yui/3.0.0/dd/dd-ddm-debug.js b/lib/yui/3.0.0/dd/dd-ddm-debug.js
new file mode 100644
index 0000000000..b7bc373bf8
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-ddm-debug.js
@@ -0,0 +1,135 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dd-ddm', function(Y) {
+
+
+ /**
+ * Extends the dd-ddm-base Class to add support for the viewport shim to allow a draggable node to drag to be dragged over an iframe or any other node that traps mousemove events.
+ * It is also required to have Drop Targets enabled, as the viewport shim will contain the shims for the Drop Targets.
+ * @module dd
+ * @submodule dd-ddm
+ * @for DDM
+ * @namespace DD
+ */
+ Y.mix(Y.DD.DDM, {
+ /**
+ * @private
+ * @property _pg
+ * @description The shim placed over the screen to track the mousemove event.
+ * @type {Node}
+ */
+ _pg: null,
+ /**
+ * @private
+ * @property _debugShim
+ * @description Set this to true to set the shims opacity to .5 for debugging it, default: false.
+ * @type {Boolean}
+ */
+ _debugShim: false,
+ _activateTargets: function() {},
+ _deactivateTargets: function() {},
+ _startDrag: function() {
+ if (this.activeDrag.get('useShim')) {
+ this._pg_activate();
+ this._activateTargets();
+ }
+ },
+ _endDrag: function() {
+ this._pg_deactivate();
+ this._deactivateTargets();
+ },
+ /**
+ * @private
+ * @method _pg_deactivate
+ * @description Deactivates the shim
+ */
+ _pg_deactivate: function() {
+ this._pg.setStyle('display', 'none');
+ },
+ /**
+ * @private
+ * @method _pg_activate
+ * @description Activates the shim
+ */
+ _pg_activate: function() {
+ var ah = this.activeDrag.get('activeHandle'), cur = 'auto';
+ if (ah) {
+ cur = ah.getStyle('cursor');
+ }
+ if (cur == 'auto') {
+ cur = this.get('dragCursor');
+ }
+
+ this._pg_size();
+ this._pg.setStyles({
+ top: 0,
+ left: 0,
+ display: 'block',
+ opacity: ((this._debugShim) ? '.5' : '0'),
+ cursor: cur
+ });
+ },
+ /**
+ * @private
+ * @method _pg_size
+ * @description Sizes the shim on: activatation, window:scroll, window:resize
+ */
+ _pg_size: function() {
+ if (this.activeDrag) {
+ var b = Y.get('body'),
+ h = b.get('docHeight'),
+ w = b.get('docWidth');
+ this._pg.setStyles({
+ height: h + 'px',
+ width: w + 'px'
+ });
+ }
+ },
+ /**
+ * @private
+ * @method _createPG
+ * @description Creates the shim and adds it's listeners to it.
+ */
+ _createPG: function() {
+ var pg = Y.Node.create(''),
+ bd = Y.get('body');
+ pg.setStyles({
+ top: '0',
+ left: '0',
+ position: 'absolute',
+ zIndex: '9999',
+ overflow: 'hidden',
+ backgroundColor: 'red',
+ display: 'none',
+ height: '5px',
+ width: '5px'
+ });
+ pg.set('id', Y.stamp(pg));
+ pg.addClass('yui-dd-shim');
+ if (bd.get('firstChild')) {
+ bd.insertBefore(pg, bd.get('firstChild'));
+ } else {
+ bd.appendChild(pg);
+ }
+ this._pg = pg;
+ this._pg.on('mouseup', Y.bind(this._end, this));
+ this._pg.on('mousemove', Y.bind(this._move, this));
+
+ var win = Y.get(window);
+ Y.on('window:resize', Y.bind(this._pg_size, this));
+ win.on('scroll', Y.bind(this._pg_size, this));
+ }
+ }, true);
+
+ Y.on('domready', Y.bind(Y.DD.DDM._createPG, Y.DD.DDM));
+
+
+
+
+
+}, '3.0.0' ,{requires:['dd-ddm-base', 'event-resize'], skinnable:false});
diff --git a/lib/yui/3.0.0/dd/dd-ddm-drop-debug.js b/lib/yui/3.0.0/dd/dd-ddm-drop-debug.js
new file mode 100644
index 0000000000..525524295b
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-ddm-drop-debug.js
@@ -0,0 +1,411 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dd-ddm-drop', function(Y) {
+
+
+ /**
+ * Extends the dd-ddm Class to add support for the placement of Drop Target shims inside the viewport shim. It also handles all Drop Target related events and interactions.
+ * @module dd
+ * @submodule dd-ddm-drop
+ * @for DDM
+ * @namespace DD
+ */
+
+ //TODO CSS class name for the bestMatch..
+ Y.mix(Y.DD.DDM, {
+ /**
+ * @private
+ * @property _noShim
+ * @description This flag turns off the use of the mouseover/mouseout shim. It should not be used unless you know what you are doing.
+ * @type {Boolean}
+ */
+ _noShim: false,
+ /**
+ * @private
+ * @property _activeShims
+ * @description Placeholder for all active shims on the page
+ * @type {Array}
+ */
+ _activeShims: [],
+ /**
+ * @private
+ * @method _hasActiveShim
+ * @description This method checks the _activeShims Object to see if there is a shim active.
+ * @return {Boolean}
+ */
+ _hasActiveShim: function() {
+ if (this._noShim) {
+ return true;
+ }
+ return this._activeShims.length;
+ },
+ /**
+ * @private
+ * @method _addActiveShim
+ * @description Adds a Drop Target to the list of active shims
+ * @param {Object} d The Drop instance to add to the list.
+ */
+ _addActiveShim: function(d) {
+ this._activeShims[this._activeShims.length] = d;
+ },
+ /**
+ * @private
+ * @method _removeActiveShim
+ * @description Removes a Drop Target to the list of active shims
+ * @param {Object} d The Drop instance to remove from the list.
+ */
+ _removeActiveShim: function(d) {
+ var s = [];
+ Y.each(this._activeShims, function(v, k) {
+ if (v._yuid !== d._yuid) {
+ s[s.length] = v;
+ }
+
+ });
+ this._activeShims = s;
+ },
+ /**
+ * @method syncActiveShims
+ * @description This method will sync the position of the shims on the Drop Targets that are currently active.
+ * @param {Boolean} force Resize/sync all Targets.
+ */
+ syncActiveShims: function(force) {
+ Y.later(0, this, function(force) {
+ var drops = ((force) ? this.targets : this._lookup());
+ Y.each(drops, function(v, k) {
+ v.sizeShim.call(v);
+ }, this);
+ }, force);
+ },
+ /**
+ * @private
+ * @property mode
+ * @description The mode that the drag operations will run in 0 for Point, 1 for Intersect, 2 for Strict
+ * @type Number
+ */
+ mode: 0,
+ /**
+ * @private
+ * @property POINT
+ * @description In point mode, a Drop is targeted by the cursor being over the Target
+ * @type Number
+ */
+ POINT: 0,
+ /**
+ * @private
+ * @property INTERSECT
+ * @description In intersect mode, a Drop is targeted by "part" of the drag node being over the Target
+ * @type Number
+ */
+ INTERSECT: 1,
+ /**
+ * @private
+ * @property STRICT
+ * @description In strict mode, a Drop is targeted by the "entire" drag node being over the Target
+ * @type Number
+ */
+ STRICT: 2,
+ /**
+ * @property useHash
+ * @description Should we only check targets that are in the viewport on drags (for performance), default: true
+ * @type {Boolean}
+ */
+ useHash: true,
+ /**
+ * @property activeDrop
+ * @description A reference to the active Drop Target
+ * @type {Object}
+ */
+ activeDrop: null,
+ /**
+ * @property validDrops
+ * @description An array of the valid Drop Targets for this interaction.
+ * @type {Array}
+ */
+ //TODO Change array/object literals to be in sync..
+ validDrops: [],
+ /**
+ * @property otherDrops
+ * @description An object literal of Other Drop Targets that we encountered during this interaction (in the case of overlapping Drop Targets)
+ * @type {Object}
+ */
+ otherDrops: {},
+ /**
+ * @property targets
+ * @description All of the Targets
+ * @type {Array}
+ */
+ targets: [],
+ /**
+ * @private
+ * @method _addValid
+ * @description Add a Drop Target to the list of Valid Targets. This list get's regenerated on each new drag operation.
+ * @param {Object} drop
+ * @return {Self}
+ * @chainable
+ */
+ _addValid: function(drop) {
+ this.validDrops[this.validDrops.length] = drop;
+ return this;
+ },
+ /**
+ * @private
+ * @method _removeValid
+ * @description Removes a Drop Target from the list of Valid Targets. This list get's regenerated on each new drag operation.
+ * @param {Object} drop
+ * @return {Self}
+ * @chainable
+ */
+ _removeValid: function(drop) {
+ var drops = [];
+ Y.each(this.validDrops, function(v, k) {
+ if (v !== drop) {
+ drops[drops.length] = v;
+ }
+ });
+
+ this.validDrops = drops;
+ return this;
+ },
+ /**
+ * @method isOverTarget
+ * @description Check to see if the Drag element is over the target, method varies on current mode
+ * @param {Object} drop The drop to check against
+ * @return {Boolean}
+ */
+ isOverTarget: function(drop) {
+ if (this.activeDrag && drop) {
+ var xy = this.activeDrag.mouseXY, r, dMode = this.activeDrag.get('dragMode'),
+ aRegion;
+ if (xy && this.activeDrag) {
+ aRegion = this.activeDrag.region;
+ if (dMode == this.STRICT) {
+ return this.activeDrag.get('dragNode').inRegion(drop.region, true, aRegion);
+ } else {
+ if (drop && drop.shim) {
+ if ((dMode == this.INTERSECT) && this._noShim) {
+ r = ((aRegion) ? aRegion : this.activeDrag.get('node'));
+ return drop.get('node').intersect(r).inRegion;
+ } else {
+ return drop.shim.intersect({
+ top: xy[1],
+ bottom: xy[1],
+ left: xy[0],
+ right: xy[0]
+ }, drop.region).inRegion;
+ }
+ } else {
+ return false;
+ }
+ }
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ },
+ /**
+ * @method clearCache
+ * @description Clears the cache data used for this interaction.
+ */
+ clearCache: function() {
+ this.validDrops = [];
+ this.otherDrops = {};
+ this._activeShims = [];
+ },
+ /**
+ * @private
+ * @method _activateTargets
+ * @description Clear the cache and activate the shims of all the targets
+ */
+ _activateTargets: function() {
+ this.clearCache();
+ Y.each(this.targets, function(v, k) {
+ v._activateShim.apply(v, []);
+ }, this);
+ this._handleTargetOver();
+
+ },
+ /**
+ * @method getBestMatch
+ * @description This method will gather the area for all potential targets and see which has the hightest covered area and return it.
+ * @param {Array} drops An Array of drops to scan for the best match.
+ * @param {Boolean} all If present, it returns an Array. First item is best match, second is an Array of the other items in the original Array.
+ * @return {Object or Array}
+ */
+ getBestMatch: function(drops, all) {
+ var biggest = null, area = 0, out;
+
+ Y.each(drops, function(v, k) {
+ var inter = this.activeDrag.get('dragNode').intersect(v.get('node'));
+ v.region.area = inter.area;
+
+ if (inter.inRegion) {
+ if (inter.area > area) {
+ area = inter.area;
+ biggest = v;
+ }
+ }
+ }, this);
+ if (all) {
+ out = [];
+ //TODO Sort the others in numeric order by area covered..
+ Y.each(drops, function(v, k) {
+ if (v !== biggest) {
+ out[out.length] = v;
+ }
+ }, this);
+ return [biggest, out];
+ } else {
+ return biggest;
+ }
+ },
+ /**
+ * @private
+ * @method _deactivateTargets
+ * @description This method fires the drop:hit, drag:drophit, drag:dropmiss methods and deactivates the shims..
+ */
+ _deactivateTargets: function() {
+ var other = [], tmp,
+ activeDrag = this.activeDrag,
+ activeDrop = this.activeDrop;
+
+ //TODO why is this check so hard??
+ if (activeDrag && activeDrop && this.otherDrops[activeDrop]) {
+ if (!activeDrag.get('dragMode')) {
+ //TODO otherDrops -- private..
+ other = this.otherDrops;
+ delete other[activeDrop];
+ } else {
+ tmp = this.getBestMatch(this.otherDrops, true);
+ activeDrop = tmp[0];
+ other = tmp[1];
+ }
+ activeDrag.get('node').removeClass(this.CSS_PREFIX + '-drag-over');
+ if (activeDrop) {
+ activeDrop.fire('drop:hit', { drag: activeDrag, drop: activeDrop, others: other });
+ activeDrag.fire('drag:drophit', { drag: activeDrag, drop: activeDrop, others: other });
+ }
+ } else if (activeDrag) {
+ activeDrag.get('node').removeClass(this.CSS_PREFIX + '-drag-over');
+ activeDrag.fire('drag:dropmiss', { pageX: activeDrag.lastXY[0], pageY: activeDrag.lastXY[1] });
+ } else {
+ }
+
+ this.activeDrop = null;
+
+ Y.each(this.targets, function(v, k) {
+ v._deactivateShim.apply(v, []);
+ }, this);
+ },
+ /**
+ * @private
+ * @method _dropMove
+ * @description This method is called when the move method is called on the Drag Object.
+ */
+ _dropMove: function() {
+ if (this._hasActiveShim()) {
+ this._handleTargetOver();
+ } else {
+ Y.each(this.otherDrops, function(v, k) {
+ v._handleOut.apply(v, []);
+ });
+ }
+ },
+ /**
+ * @private
+ * @method _lookup
+ * @description Filters the list of Drops down to those in the viewport.
+ * @return {Array} The valid Drop Targets that are in the viewport.
+ */
+ _lookup: function() {
+ if (!this.useHash || this._noShim) {
+ return this.validDrops;
+ }
+ var drops = [];
+ //Only scan drop shims that are in the Viewport
+ Y.each(this.validDrops, function(v, k) {
+ if (v.shim && v.shim.inViewportRegion(false, v.region)) {
+ drops[drops.length] = v;
+ }
+ });
+ return drops;
+
+ },
+ /**
+ * @private
+ * @method _handleTargetOver
+ * @description This method execs _handleTargetOver on all valid Drop Targets
+ */
+ _handleTargetOver: function() {
+ var drops = this._lookup();
+ Y.each(drops, function(v, k) {
+ v._handleTargetOver.call(v);
+ }, this);
+ },
+ /**
+ * @private
+ * @method _regTarget
+ * @description Add the passed in Target to the targets collection
+ * @param {Object} t The Target to add to the targets collection
+ */
+ _regTarget: function(t) {
+ this.targets[this.targets.length] = t;
+ },
+ /**
+ * @private
+ * @method _unregTarget
+ * @description Remove the passed in Target from the targets collection
+ * @param {Object} drop The Target to remove from the targets collection
+ */
+ _unregTarget: function(drop) {
+ var targets = [], vdrops;
+ Y.each(this.targets, function(v, k) {
+ if (v != drop) {
+ targets[targets.length] = v;
+ }
+ }, this);
+ this.targets = targets;
+
+ vdrops = [];
+ Y.each(this.validDrops, function(v, k) {
+ if (v !== drop) {
+ vdrops[vdrops.length] = v;
+ }
+ });
+
+ this.validDrops = vdrops;
+ },
+ /**
+ * @method getDrop
+ * @description Get a valid Drop instance back from a Node or a selector string, false otherwise
+ * @param {String/Object} node The Node instance or Selector string to check for a valid Drop Object
+ * @return {Object}
+ */
+ getDrop: function(node) {
+ var drop = false,
+ n = Y.Node.get(node);
+ if (n instanceof Y.Node) {
+ Y.each(this.targets, function(v, k) {
+ if (n.compareTo(v.get('node'))) {
+ drop = v;
+ }
+ });
+ }
+ return drop;
+ }
+ }, true);
+
+
+
+
+
+
+
+}, '3.0.0' ,{requires:['dd-ddm'], skinnable:false});
diff --git a/lib/yui/3.0.0/dd/dd-ddm-drop-min.js b/lib/yui/3.0.0/dd/dd-ddm-drop-min.js
new file mode 100644
index 0000000000..88713a806f
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-ddm-drop-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("dd-ddm-drop",function(A){A.mix(A.DD.DDM,{_noShim:false,_activeShims:[],_hasActiveShim:function(){if(this._noShim){return true;}return this._activeShims.length;},_addActiveShim:function(B){this._activeShims[this._activeShims.length]=B;},_removeActiveShim:function(C){var B=[];A.each(this._activeShims,function(E,D){if(E._yuid!==C._yuid){B[B.length]=E;}});this._activeShims=B;},syncActiveShims:function(B){A.later(0,this,function(C){var D=((C)?this.targets:this._lookup());A.each(D,function(F,E){F.sizeShim.call(F);},this);},B);},mode:0,POINT:0,INTERSECT:1,STRICT:2,useHash:true,activeDrop:null,validDrops:[],otherDrops:{},targets:[],_addValid:function(B){this.validDrops[this.validDrops.length]=B;return this;},_removeValid:function(B){var C=[];A.each(this.validDrops,function(E,D){if(E!==B){C[C.length]=E;}});this.validDrops=C;return this;},isOverTarget:function(C){if(this.activeDrag&&C){var F=this.activeDrag.mouseXY,E,B=this.activeDrag.get("dragMode"),D;if(F&&this.activeDrag){D=this.activeDrag.region;if(B==this.STRICT){return this.activeDrag.get("dragNode").inRegion(C.region,true,D);}else{if(C&&C.shim){if((B==this.INTERSECT)&&this._noShim){E=((D)?D:this.activeDrag.get("node"));return C.get("node").intersect(E).inRegion;}else{return C.shim.intersect({top:F[1],bottom:F[1],left:F[0],right:F[0]},C.region).inRegion;}}else{return false;}}}else{return false;}}else{return false;}},clearCache:function(){this.validDrops=[];this.otherDrops={};this._activeShims=[];},_activateTargets:function(){this.clearCache();A.each(this.targets,function(C,B){C._activateShim.apply(C,[]);},this);this._handleTargetOver();},getBestMatch:function(F,D){var C=null,E=0,B;A.each(F,function(I,H){var G=this.activeDrag.get("dragNode").intersect(I.get("node"));I.region.area=G.area;if(G.inRegion){if(G.area>E){E=G.area;C=I;}}},this);if(D){B=[];A.each(F,function(H,G){if(H!==C){B[B.length]=H;}},this);return[C,B];}else{return C;}},_deactivateTargets:function(){var B=[],C,E=this.activeDrag,D=this.activeDrop;if(E&&D&&this.otherDrops[D]){if(!E.get("dragMode")){B=this.otherDrops;delete B[D];}else{C=this.getBestMatch(this.otherDrops,true);D=C[0];B=C[1];}E.get("node").removeClass(this.CSS_PREFIX+"-drag-over");if(D){D.fire("drop:hit",{drag:E,drop:D,others:B});E.fire("drag:drophit",{drag:E,drop:D,others:B});}}else{if(E){E.get("node").removeClass(this.CSS_PREFIX+"-drag-over");E.fire("drag:dropmiss",{pageX:E.lastXY[0],pageY:E.lastXY[1]});}else{}}this.activeDrop=null;A.each(this.targets,function(G,F){G._deactivateShim.apply(G,[]);},this);},_dropMove:function(){if(this._hasActiveShim()){this._handleTargetOver();}else{A.each(this.otherDrops,function(C,B){C._handleOut.apply(C,[]);});}},_lookup:function(){if(!this.useHash||this._noShim){return this.validDrops;}var B=[];A.each(this.validDrops,function(D,C){if(D.shim&&D.shim.inViewportRegion(false,D.region)){B[B.length]=D;}});return B;},_handleTargetOver:function(){var B=this._lookup();A.each(B,function(D,C){D._handleTargetOver.call(D);},this);},_regTarget:function(B){this.targets[this.targets.length]=B;},_unregTarget:function(C){var B=[],D;A.each(this.targets,function(F,E){if(F!=C){B[B.length]=F;}},this);this.targets=B;D=[];A.each(this.validDrops,function(F,E){if(F!==C){D[D.length]=F;}});this.validDrops=D;},getDrop:function(C){var B=false,D=A.Node.get(C);if(D instanceof A.Node){A.each(this.targets,function(F,E){if(D.compareTo(F.get("node"))){B=F;}});}return B;}},true);},"3.0.0",{requires:["dd-ddm"],skinnable:false});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/dd/dd-ddm-drop.js b/lib/yui/3.0.0/dd/dd-ddm-drop.js
new file mode 100644
index 0000000000..525524295b
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-ddm-drop.js
@@ -0,0 +1,411 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dd-ddm-drop', function(Y) {
+
+
+ /**
+ * Extends the dd-ddm Class to add support for the placement of Drop Target shims inside the viewport shim. It also handles all Drop Target related events and interactions.
+ * @module dd
+ * @submodule dd-ddm-drop
+ * @for DDM
+ * @namespace DD
+ */
+
+ //TODO CSS class name for the bestMatch..
+ Y.mix(Y.DD.DDM, {
+ /**
+ * @private
+ * @property _noShim
+ * @description This flag turns off the use of the mouseover/mouseout shim. It should not be used unless you know what you are doing.
+ * @type {Boolean}
+ */
+ _noShim: false,
+ /**
+ * @private
+ * @property _activeShims
+ * @description Placeholder for all active shims on the page
+ * @type {Array}
+ */
+ _activeShims: [],
+ /**
+ * @private
+ * @method _hasActiveShim
+ * @description This method checks the _activeShims Object to see if there is a shim active.
+ * @return {Boolean}
+ */
+ _hasActiveShim: function() {
+ if (this._noShim) {
+ return true;
+ }
+ return this._activeShims.length;
+ },
+ /**
+ * @private
+ * @method _addActiveShim
+ * @description Adds a Drop Target to the list of active shims
+ * @param {Object} d The Drop instance to add to the list.
+ */
+ _addActiveShim: function(d) {
+ this._activeShims[this._activeShims.length] = d;
+ },
+ /**
+ * @private
+ * @method _removeActiveShim
+ * @description Removes a Drop Target to the list of active shims
+ * @param {Object} d The Drop instance to remove from the list.
+ */
+ _removeActiveShim: function(d) {
+ var s = [];
+ Y.each(this._activeShims, function(v, k) {
+ if (v._yuid !== d._yuid) {
+ s[s.length] = v;
+ }
+
+ });
+ this._activeShims = s;
+ },
+ /**
+ * @method syncActiveShims
+ * @description This method will sync the position of the shims on the Drop Targets that are currently active.
+ * @param {Boolean} force Resize/sync all Targets.
+ */
+ syncActiveShims: function(force) {
+ Y.later(0, this, function(force) {
+ var drops = ((force) ? this.targets : this._lookup());
+ Y.each(drops, function(v, k) {
+ v.sizeShim.call(v);
+ }, this);
+ }, force);
+ },
+ /**
+ * @private
+ * @property mode
+ * @description The mode that the drag operations will run in 0 for Point, 1 for Intersect, 2 for Strict
+ * @type Number
+ */
+ mode: 0,
+ /**
+ * @private
+ * @property POINT
+ * @description In point mode, a Drop is targeted by the cursor being over the Target
+ * @type Number
+ */
+ POINT: 0,
+ /**
+ * @private
+ * @property INTERSECT
+ * @description In intersect mode, a Drop is targeted by "part" of the drag node being over the Target
+ * @type Number
+ */
+ INTERSECT: 1,
+ /**
+ * @private
+ * @property STRICT
+ * @description In strict mode, a Drop is targeted by the "entire" drag node being over the Target
+ * @type Number
+ */
+ STRICT: 2,
+ /**
+ * @property useHash
+ * @description Should we only check targets that are in the viewport on drags (for performance), default: true
+ * @type {Boolean}
+ */
+ useHash: true,
+ /**
+ * @property activeDrop
+ * @description A reference to the active Drop Target
+ * @type {Object}
+ */
+ activeDrop: null,
+ /**
+ * @property validDrops
+ * @description An array of the valid Drop Targets for this interaction.
+ * @type {Array}
+ */
+ //TODO Change array/object literals to be in sync..
+ validDrops: [],
+ /**
+ * @property otherDrops
+ * @description An object literal of Other Drop Targets that we encountered during this interaction (in the case of overlapping Drop Targets)
+ * @type {Object}
+ */
+ otherDrops: {},
+ /**
+ * @property targets
+ * @description All of the Targets
+ * @type {Array}
+ */
+ targets: [],
+ /**
+ * @private
+ * @method _addValid
+ * @description Add a Drop Target to the list of Valid Targets. This list get's regenerated on each new drag operation.
+ * @param {Object} drop
+ * @return {Self}
+ * @chainable
+ */
+ _addValid: function(drop) {
+ this.validDrops[this.validDrops.length] = drop;
+ return this;
+ },
+ /**
+ * @private
+ * @method _removeValid
+ * @description Removes a Drop Target from the list of Valid Targets. This list get's regenerated on each new drag operation.
+ * @param {Object} drop
+ * @return {Self}
+ * @chainable
+ */
+ _removeValid: function(drop) {
+ var drops = [];
+ Y.each(this.validDrops, function(v, k) {
+ if (v !== drop) {
+ drops[drops.length] = v;
+ }
+ });
+
+ this.validDrops = drops;
+ return this;
+ },
+ /**
+ * @method isOverTarget
+ * @description Check to see if the Drag element is over the target, method varies on current mode
+ * @param {Object} drop The drop to check against
+ * @return {Boolean}
+ */
+ isOverTarget: function(drop) {
+ if (this.activeDrag && drop) {
+ var xy = this.activeDrag.mouseXY, r, dMode = this.activeDrag.get('dragMode'),
+ aRegion;
+ if (xy && this.activeDrag) {
+ aRegion = this.activeDrag.region;
+ if (dMode == this.STRICT) {
+ return this.activeDrag.get('dragNode').inRegion(drop.region, true, aRegion);
+ } else {
+ if (drop && drop.shim) {
+ if ((dMode == this.INTERSECT) && this._noShim) {
+ r = ((aRegion) ? aRegion : this.activeDrag.get('node'));
+ return drop.get('node').intersect(r).inRegion;
+ } else {
+ return drop.shim.intersect({
+ top: xy[1],
+ bottom: xy[1],
+ left: xy[0],
+ right: xy[0]
+ }, drop.region).inRegion;
+ }
+ } else {
+ return false;
+ }
+ }
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ },
+ /**
+ * @method clearCache
+ * @description Clears the cache data used for this interaction.
+ */
+ clearCache: function() {
+ this.validDrops = [];
+ this.otherDrops = {};
+ this._activeShims = [];
+ },
+ /**
+ * @private
+ * @method _activateTargets
+ * @description Clear the cache and activate the shims of all the targets
+ */
+ _activateTargets: function() {
+ this.clearCache();
+ Y.each(this.targets, function(v, k) {
+ v._activateShim.apply(v, []);
+ }, this);
+ this._handleTargetOver();
+
+ },
+ /**
+ * @method getBestMatch
+ * @description This method will gather the area for all potential targets and see which has the hightest covered area and return it.
+ * @param {Array} drops An Array of drops to scan for the best match.
+ * @param {Boolean} all If present, it returns an Array. First item is best match, second is an Array of the other items in the original Array.
+ * @return {Object or Array}
+ */
+ getBestMatch: function(drops, all) {
+ var biggest = null, area = 0, out;
+
+ Y.each(drops, function(v, k) {
+ var inter = this.activeDrag.get('dragNode').intersect(v.get('node'));
+ v.region.area = inter.area;
+
+ if (inter.inRegion) {
+ if (inter.area > area) {
+ area = inter.area;
+ biggest = v;
+ }
+ }
+ }, this);
+ if (all) {
+ out = [];
+ //TODO Sort the others in numeric order by area covered..
+ Y.each(drops, function(v, k) {
+ if (v !== biggest) {
+ out[out.length] = v;
+ }
+ }, this);
+ return [biggest, out];
+ } else {
+ return biggest;
+ }
+ },
+ /**
+ * @private
+ * @method _deactivateTargets
+ * @description This method fires the drop:hit, drag:drophit, drag:dropmiss methods and deactivates the shims..
+ */
+ _deactivateTargets: function() {
+ var other = [], tmp,
+ activeDrag = this.activeDrag,
+ activeDrop = this.activeDrop;
+
+ //TODO why is this check so hard??
+ if (activeDrag && activeDrop && this.otherDrops[activeDrop]) {
+ if (!activeDrag.get('dragMode')) {
+ //TODO otherDrops -- private..
+ other = this.otherDrops;
+ delete other[activeDrop];
+ } else {
+ tmp = this.getBestMatch(this.otherDrops, true);
+ activeDrop = tmp[0];
+ other = tmp[1];
+ }
+ activeDrag.get('node').removeClass(this.CSS_PREFIX + '-drag-over');
+ if (activeDrop) {
+ activeDrop.fire('drop:hit', { drag: activeDrag, drop: activeDrop, others: other });
+ activeDrag.fire('drag:drophit', { drag: activeDrag, drop: activeDrop, others: other });
+ }
+ } else if (activeDrag) {
+ activeDrag.get('node').removeClass(this.CSS_PREFIX + '-drag-over');
+ activeDrag.fire('drag:dropmiss', { pageX: activeDrag.lastXY[0], pageY: activeDrag.lastXY[1] });
+ } else {
+ }
+
+ this.activeDrop = null;
+
+ Y.each(this.targets, function(v, k) {
+ v._deactivateShim.apply(v, []);
+ }, this);
+ },
+ /**
+ * @private
+ * @method _dropMove
+ * @description This method is called when the move method is called on the Drag Object.
+ */
+ _dropMove: function() {
+ if (this._hasActiveShim()) {
+ this._handleTargetOver();
+ } else {
+ Y.each(this.otherDrops, function(v, k) {
+ v._handleOut.apply(v, []);
+ });
+ }
+ },
+ /**
+ * @private
+ * @method _lookup
+ * @description Filters the list of Drops down to those in the viewport.
+ * @return {Array} The valid Drop Targets that are in the viewport.
+ */
+ _lookup: function() {
+ if (!this.useHash || this._noShim) {
+ return this.validDrops;
+ }
+ var drops = [];
+ //Only scan drop shims that are in the Viewport
+ Y.each(this.validDrops, function(v, k) {
+ if (v.shim && v.shim.inViewportRegion(false, v.region)) {
+ drops[drops.length] = v;
+ }
+ });
+ return drops;
+
+ },
+ /**
+ * @private
+ * @method _handleTargetOver
+ * @description This method execs _handleTargetOver on all valid Drop Targets
+ */
+ _handleTargetOver: function() {
+ var drops = this._lookup();
+ Y.each(drops, function(v, k) {
+ v._handleTargetOver.call(v);
+ }, this);
+ },
+ /**
+ * @private
+ * @method _regTarget
+ * @description Add the passed in Target to the targets collection
+ * @param {Object} t The Target to add to the targets collection
+ */
+ _regTarget: function(t) {
+ this.targets[this.targets.length] = t;
+ },
+ /**
+ * @private
+ * @method _unregTarget
+ * @description Remove the passed in Target from the targets collection
+ * @param {Object} drop The Target to remove from the targets collection
+ */
+ _unregTarget: function(drop) {
+ var targets = [], vdrops;
+ Y.each(this.targets, function(v, k) {
+ if (v != drop) {
+ targets[targets.length] = v;
+ }
+ }, this);
+ this.targets = targets;
+
+ vdrops = [];
+ Y.each(this.validDrops, function(v, k) {
+ if (v !== drop) {
+ vdrops[vdrops.length] = v;
+ }
+ });
+
+ this.validDrops = vdrops;
+ },
+ /**
+ * @method getDrop
+ * @description Get a valid Drop instance back from a Node or a selector string, false otherwise
+ * @param {String/Object} node The Node instance or Selector string to check for a valid Drop Object
+ * @return {Object}
+ */
+ getDrop: function(node) {
+ var drop = false,
+ n = Y.Node.get(node);
+ if (n instanceof Y.Node) {
+ Y.each(this.targets, function(v, k) {
+ if (n.compareTo(v.get('node'))) {
+ drop = v;
+ }
+ });
+ }
+ return drop;
+ }
+ }, true);
+
+
+
+
+
+
+
+}, '3.0.0' ,{requires:['dd-ddm'], skinnable:false});
diff --git a/lib/yui/3.0.0/dd/dd-ddm-min.js b/lib/yui/3.0.0/dd/dd-ddm-min.js
new file mode 100644
index 0000000000..37c7f07ef6
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-ddm-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("dd-ddm",function(A){A.mix(A.DD.DDM,{_pg:null,_debugShim:false,_activateTargets:function(){},_deactivateTargets:function(){},_startDrag:function(){if(this.activeDrag.get("useShim")){this._pg_activate();this._activateTargets();}},_endDrag:function(){this._pg_deactivate();this._deactivateTargets();},_pg_deactivate:function(){this._pg.setStyle("display","none");},_pg_activate:function(){var B=this.activeDrag.get("activeHandle"),C="auto";if(B){C=B.getStyle("cursor");}if(C=="auto"){C=this.get("dragCursor");}this._pg_size();this._pg.setStyles({top:0,left:0,display:"block",opacity:((this._debugShim)?".5":"0"),cursor:C});},_pg_size:function(){if(this.activeDrag){var B=A.get("body"),D=B.get("docHeight"),C=B.get("docWidth");this._pg.setStyles({height:D+"px",width:C+"px"});}},_createPG:function(){var D=A.Node.create(""),B=A.get("body");D.setStyles({top:"0",left:"0",position:"absolute",zIndex:"9999",overflow:"hidden",backgroundColor:"red",display:"none",height:"5px",width:"5px"});D.set("id",A.stamp(D));D.addClass("yui-dd-shim");if(B.get("firstChild")){B.insertBefore(D,B.get("firstChild"));}else{B.appendChild(D);}this._pg=D;this._pg.on("mouseup",A.bind(this._end,this));this._pg.on("mousemove",A.bind(this._move,this));var C=A.get(window);A.on("window:resize",A.bind(this._pg_size,this));C.on("scroll",A.bind(this._pg_size,this));}},true);A.on("domready",A.bind(A.DD.DDM._createPG,A.DD.DDM));},"3.0.0",{requires:["dd-ddm-base","event-resize"],skinnable:false});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/dd/dd-ddm.js b/lib/yui/3.0.0/dd/dd-ddm.js
new file mode 100644
index 0000000000..b7bc373bf8
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-ddm.js
@@ -0,0 +1,135 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dd-ddm', function(Y) {
+
+
+ /**
+ * Extends the dd-ddm-base Class to add support for the viewport shim to allow a draggable node to drag to be dragged over an iframe or any other node that traps mousemove events.
+ * It is also required to have Drop Targets enabled, as the viewport shim will contain the shims for the Drop Targets.
+ * @module dd
+ * @submodule dd-ddm
+ * @for DDM
+ * @namespace DD
+ */
+ Y.mix(Y.DD.DDM, {
+ /**
+ * @private
+ * @property _pg
+ * @description The shim placed over the screen to track the mousemove event.
+ * @type {Node}
+ */
+ _pg: null,
+ /**
+ * @private
+ * @property _debugShim
+ * @description Set this to true to set the shims opacity to .5 for debugging it, default: false.
+ * @type {Boolean}
+ */
+ _debugShim: false,
+ _activateTargets: function() {},
+ _deactivateTargets: function() {},
+ _startDrag: function() {
+ if (this.activeDrag.get('useShim')) {
+ this._pg_activate();
+ this._activateTargets();
+ }
+ },
+ _endDrag: function() {
+ this._pg_deactivate();
+ this._deactivateTargets();
+ },
+ /**
+ * @private
+ * @method _pg_deactivate
+ * @description Deactivates the shim
+ */
+ _pg_deactivate: function() {
+ this._pg.setStyle('display', 'none');
+ },
+ /**
+ * @private
+ * @method _pg_activate
+ * @description Activates the shim
+ */
+ _pg_activate: function() {
+ var ah = this.activeDrag.get('activeHandle'), cur = 'auto';
+ if (ah) {
+ cur = ah.getStyle('cursor');
+ }
+ if (cur == 'auto') {
+ cur = this.get('dragCursor');
+ }
+
+ this._pg_size();
+ this._pg.setStyles({
+ top: 0,
+ left: 0,
+ display: 'block',
+ opacity: ((this._debugShim) ? '.5' : '0'),
+ cursor: cur
+ });
+ },
+ /**
+ * @private
+ * @method _pg_size
+ * @description Sizes the shim on: activatation, window:scroll, window:resize
+ */
+ _pg_size: function() {
+ if (this.activeDrag) {
+ var b = Y.get('body'),
+ h = b.get('docHeight'),
+ w = b.get('docWidth');
+ this._pg.setStyles({
+ height: h + 'px',
+ width: w + 'px'
+ });
+ }
+ },
+ /**
+ * @private
+ * @method _createPG
+ * @description Creates the shim and adds it's listeners to it.
+ */
+ _createPG: function() {
+ var pg = Y.Node.create(''),
+ bd = Y.get('body');
+ pg.setStyles({
+ top: '0',
+ left: '0',
+ position: 'absolute',
+ zIndex: '9999',
+ overflow: 'hidden',
+ backgroundColor: 'red',
+ display: 'none',
+ height: '5px',
+ width: '5px'
+ });
+ pg.set('id', Y.stamp(pg));
+ pg.addClass('yui-dd-shim');
+ if (bd.get('firstChild')) {
+ bd.insertBefore(pg, bd.get('firstChild'));
+ } else {
+ bd.appendChild(pg);
+ }
+ this._pg = pg;
+ this._pg.on('mouseup', Y.bind(this._end, this));
+ this._pg.on('mousemove', Y.bind(this._move, this));
+
+ var win = Y.get(window);
+ Y.on('window:resize', Y.bind(this._pg_size, this));
+ win.on('scroll', Y.bind(this._pg_size, this));
+ }
+ }, true);
+
+ Y.on('domready', Y.bind(Y.DD.DDM._createPG, Y.DD.DDM));
+
+
+
+
+
+}, '3.0.0' ,{requires:['dd-ddm-base', 'event-resize'], skinnable:false});
diff --git a/lib/yui/3.0.0/dd/dd-debug.js b/lib/yui/3.0.0/dd/dd-debug.js
new file mode 100644
index 0000000000..69282f2057
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-debug.js
@@ -0,0 +1,3529 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dd-ddm-base', function(Y) {
+
+
+ /**
+ * Provides the base Drag Drop Manger required for making a Node draggable.
+ * @module dd
+ * @submodule dd-ddm-base
+ */
+ /**
+ * Provides the base Drag Drop Manger required for making a Node draggable.
+ * @class DDM
+ * @extends Base
+ * @constructor
+ * @namespace DD
+ */
+
+ var DDMBase = function() {
+ DDMBase.superclass.constructor.apply(this, arguments);
+ };
+
+ DDMBase.NAME = 'ddm';
+
+ DDMBase.ATTRS = {
+ /**
+ * @attribute dragCursor
+ * @description The cursor to apply when dragging, if shimmed the shim will get the cursor.
+ * @type String
+ */
+ dragCursor: {
+ value: 'move'
+ },
+ /**
+ * @attribute clickPixelThresh
+ * @description The number of pixels to move to start a drag operation, default is 3.
+ * @type Number
+ */
+ clickPixelThresh: {
+ value: 3
+ },
+ /**
+ * @attribute clickTimeThresh
+ * @description The number of milliseconds a mousedown has to pass to start a drag operation, default is 1000.
+ * @type Number
+ */
+ clickTimeThresh: {
+ value: 1000
+ },
+ /**
+ * @attribute dragMode
+ * @description This attribute only works if the dd-drop module is active. It will set the dragMode (point, intersect, strict) of all future Drag instances.
+ * @type String
+ */
+ dragMode: {
+ value: 'point',
+ setter: function(mode) {
+ this._setDragMode(mode);
+ return mode;
+ }
+ }
+
+ };
+
+ Y.extend(DDMBase, Y.Base, {
+ /**
+ * @property _active
+ * @description flag set when we activate our first drag, so DDM can start listening for events.
+ * @type {Boolean}
+ */
+ _active: null,
+ /**
+ * @private
+ * @method _setDragMode
+ * @description Handler for dragMode attribute setter.
+ * @param String/Number The Number value or the String for the DragMode to default all future drag instances to.
+ * @return Number The Mode to be set
+ */
+ _setDragMode: function(mode) {
+ if (mode === null) {
+ mode = Y.DD.DDM.get('dragMode');
+ }
+ switch (mode) {
+ case 1:
+ case 'intersect':
+ return 1;
+ case 2:
+ case 'strict':
+ return 2;
+ case 0:
+ case 'point':
+ return 0;
+ }
+ return 0;
+ },
+ /**
+ * @property CSS_PREFIX
+ * @description The PREFIX to attach to all DD CSS class names
+ * @type {String}
+ */
+ CSS_PREFIX: 'yui-dd',
+ _activateTargets: function() {},
+ /**
+ * @private
+ * @property _drags
+ * @description Holder for all registered drag elements.
+ * @type {Array}
+ */
+ _drags: [],
+ /**
+ * @property activeDrag
+ * @description A reference to the currently active draggable object.
+ * @type {Drag}
+ */
+ activeDrag: false,
+ /**
+ * @private
+ * @method _regDrag
+ * @description Adds a reference to the drag object to the DDM._drags array, called in the constructor of Drag.
+ * @param {Drag} d The Drag object
+ */
+ _regDrag: function(d) {
+ if (this.getDrag(d.get('node'))) {
+ return false;
+ }
+
+ if (!this._active) {
+ this._setupListeners();
+ }
+ this._drags.push(d);
+ return true;
+ },
+ /**
+ * @private
+ * @method _unregDrag
+ * @description Remove this drag object from the DDM._drags array.
+ * @param {Drag} d The drag object.
+ */
+ _unregDrag: function(d) {
+ var tmp = [];
+ Y.each(this._drags, function(n, i) {
+ if (n !== d) {
+ tmp[tmp.length] = n;
+ }
+ });
+ this._drags = tmp;
+ },
+ /**
+ * @private
+ * @method _setupListeners
+ * @description Add the document listeners.
+ */
+ _setupListeners: function() {
+ this._active = true;
+ var doc = Y.get(document);
+ doc.on('mousemove', Y.bind(this._move, this));
+ //Y.Event.nativeAdd(document, 'mousemove', Y.bind(this._move, this));
+ doc.on('mouseup', Y.bind(this._end, this));
+ },
+ /**
+ * @private
+ * @method _start
+ * @description Internal method used by Drag to signal the start of a drag operation
+ */
+ _start: function() {
+ this.fire('ddm:start');
+ this._startDrag();
+ },
+ /**
+ * @private
+ * @method _startDrag
+ * @description Factory method to be overwritten by other DDM's
+ * @param {Number} x The x position of the drag element
+ * @param {Number} y The y position of the drag element
+ * @param {Number} w The width of the drag element
+ * @param {Number} h The height of the drag element
+ */
+ _startDrag: function() {},
+ /**
+ * @private
+ * @method _endDrag
+ * @description Factory method to be overwritten by other DDM's
+ */
+ _endDrag: function() {},
+ _dropMove: function() {},
+ /**
+ * @private
+ * @method _end
+ * @description Internal method used by Drag to signal the end of a drag operation
+ */
+ _end: function() {
+ if (this.activeDrag) {
+ this._endDrag();
+ this.fire('ddm:end');
+ this.activeDrag.end.call(this.activeDrag);
+ this.activeDrag = null;
+ }
+ },
+ /**
+ * @method stopDrag
+ * @description Method will forcefully stop a drag operation. For example calling this from inside an ESC keypress handler will stop this drag.
+ * @return {Self}
+ * @chainable
+ */
+ stopDrag: function() {
+ if (this.activeDrag) {
+ this._end();
+ }
+ return this;
+ },
+ /**
+ * @private
+ * @method _move
+ * @description Internal listener for the mousemove DOM event to pass to the Drag's move method.
+ * @param {Event.Facade} ev The Dom mousemove Event
+ */
+ _move: function(ev) {
+ if (this.activeDrag) {
+ this.activeDrag._move.call(this.activeDrag, ev);
+ this._dropMove();
+ }
+ },
+ /**
+ * //TODO Private, rename??...
+ * @private
+ * @method cssSizestoObject
+ * @description Helper method to use to set the gutter from the attribute setter.
+ * @param {String} gutter CSS style string for gutter: '5 0' (sets top and bottom to 5px, left and right to 0px), '1 2 3 4' (top 1px, right 2px, bottom 3px, left 4px)
+ * @return {Object} The gutter Object Literal.
+ */
+ cssSizestoObject: function(gutter) {
+ var x = gutter.split(' ');
+
+ switch (x.length) {
+ case 1: x[1] = x[2] = x[3] = x[0]; break;
+ case 2: x[2] = x[0]; x[3] = x[1]; break;
+ case 3: x[3] = x[1]; break;
+ }
+
+ return {
+ top : parseInt(x[0],10),
+ right : parseInt(x[1],10),
+ bottom: parseInt(x[2],10),
+ left : parseInt(x[3],10)
+ };
+ },
+ /**
+ * @method getDrag
+ * @description Get a valid Drag instance back from a Node or a selector string, false otherwise
+ * @param {String/Object} node The Node instance or Selector string to check for a valid Drag Object
+ * @return {Object}
+ */
+ getDrag: function(node) {
+ var drag = false,
+ n = Y.get(node);
+ if (n instanceof Y.Node) {
+ Y.each(this._drags, function(v, k) {
+ if (n.compareTo(v.get('node'))) {
+ drag = v;
+ }
+ });
+ }
+ return drag;
+ }
+ });
+
+ Y.namespace('DD');
+ Y.DD.DDM = new DDMBase();
+
+ /**
+ * @event ddm:start
+ * @description Fires from the DDM before all drag events fire.
+ * @type {Event.Custom}
+ */
+ /**
+ * @event ddm:end
+ * @description Fires from the DDM after the DDM finishes, before the drag end events.
+ * @type {Event.Custom}
+ */
+
+
+
+
+}, '3.0.0' ,{requires:['node', 'base'], skinnable:false});
+YUI.add('dd-ddm', function(Y) {
+
+
+ /**
+ * Extends the dd-ddm-base Class to add support for the viewport shim to allow a draggable node to drag to be dragged over an iframe or any other node that traps mousemove events.
+ * It is also required to have Drop Targets enabled, as the viewport shim will contain the shims for the Drop Targets.
+ * @module dd
+ * @submodule dd-ddm
+ * @for DDM
+ * @namespace DD
+ */
+ Y.mix(Y.DD.DDM, {
+ /**
+ * @private
+ * @property _pg
+ * @description The shim placed over the screen to track the mousemove event.
+ * @type {Node}
+ */
+ _pg: null,
+ /**
+ * @private
+ * @property _debugShim
+ * @description Set this to true to set the shims opacity to .5 for debugging it, default: false.
+ * @type {Boolean}
+ */
+ _debugShim: false,
+ _activateTargets: function() {},
+ _deactivateTargets: function() {},
+ _startDrag: function() {
+ if (this.activeDrag.get('useShim')) {
+ this._pg_activate();
+ this._activateTargets();
+ }
+ },
+ _endDrag: function() {
+ this._pg_deactivate();
+ this._deactivateTargets();
+ },
+ /**
+ * @private
+ * @method _pg_deactivate
+ * @description Deactivates the shim
+ */
+ _pg_deactivate: function() {
+ this._pg.setStyle('display', 'none');
+ },
+ /**
+ * @private
+ * @method _pg_activate
+ * @description Activates the shim
+ */
+ _pg_activate: function() {
+ var ah = this.activeDrag.get('activeHandle'), cur = 'auto';
+ if (ah) {
+ cur = ah.getStyle('cursor');
+ }
+ if (cur == 'auto') {
+ cur = this.get('dragCursor');
+ }
+
+ this._pg_size();
+ this._pg.setStyles({
+ top: 0,
+ left: 0,
+ display: 'block',
+ opacity: ((this._debugShim) ? '.5' : '0'),
+ cursor: cur
+ });
+ },
+ /**
+ * @private
+ * @method _pg_size
+ * @description Sizes the shim on: activatation, window:scroll, window:resize
+ */
+ _pg_size: function() {
+ if (this.activeDrag) {
+ var b = Y.get('body'),
+ h = b.get('docHeight'),
+ w = b.get('docWidth');
+ this._pg.setStyles({
+ height: h + 'px',
+ width: w + 'px'
+ });
+ }
+ },
+ /**
+ * @private
+ * @method _createPG
+ * @description Creates the shim and adds it's listeners to it.
+ */
+ _createPG: function() {
+ var pg = Y.Node.create(''),
+ bd = Y.get('body');
+ pg.setStyles({
+ top: '0',
+ left: '0',
+ position: 'absolute',
+ zIndex: '9999',
+ overflow: 'hidden',
+ backgroundColor: 'red',
+ display: 'none',
+ height: '5px',
+ width: '5px'
+ });
+ pg.set('id', Y.stamp(pg));
+ pg.addClass('yui-dd-shim');
+ if (bd.get('firstChild')) {
+ bd.insertBefore(pg, bd.get('firstChild'));
+ } else {
+ bd.appendChild(pg);
+ }
+ this._pg = pg;
+ this._pg.on('mouseup', Y.bind(this._end, this));
+ this._pg.on('mousemove', Y.bind(this._move, this));
+
+ var win = Y.get(window);
+ Y.on('window:resize', Y.bind(this._pg_size, this));
+ win.on('scroll', Y.bind(this._pg_size, this));
+ }
+ }, true);
+
+ Y.on('domready', Y.bind(Y.DD.DDM._createPG, Y.DD.DDM));
+
+
+
+
+
+}, '3.0.0' ,{requires:['dd-ddm-base', 'event-resize'], skinnable:false});
+YUI.add('dd-ddm-drop', function(Y) {
+
+
+ /**
+ * Extends the dd-ddm Class to add support for the placement of Drop Target shims inside the viewport shim. It also handles all Drop Target related events and interactions.
+ * @module dd
+ * @submodule dd-ddm-drop
+ * @for DDM
+ * @namespace DD
+ */
+
+ //TODO CSS class name for the bestMatch..
+ Y.mix(Y.DD.DDM, {
+ /**
+ * @private
+ * @property _noShim
+ * @description This flag turns off the use of the mouseover/mouseout shim. It should not be used unless you know what you are doing.
+ * @type {Boolean}
+ */
+ _noShim: false,
+ /**
+ * @private
+ * @property _activeShims
+ * @description Placeholder for all active shims on the page
+ * @type {Array}
+ */
+ _activeShims: [],
+ /**
+ * @private
+ * @method _hasActiveShim
+ * @description This method checks the _activeShims Object to see if there is a shim active.
+ * @return {Boolean}
+ */
+ _hasActiveShim: function() {
+ if (this._noShim) {
+ return true;
+ }
+ return this._activeShims.length;
+ },
+ /**
+ * @private
+ * @method _addActiveShim
+ * @description Adds a Drop Target to the list of active shims
+ * @param {Object} d The Drop instance to add to the list.
+ */
+ _addActiveShim: function(d) {
+ this._activeShims[this._activeShims.length] = d;
+ },
+ /**
+ * @private
+ * @method _removeActiveShim
+ * @description Removes a Drop Target to the list of active shims
+ * @param {Object} d The Drop instance to remove from the list.
+ */
+ _removeActiveShim: function(d) {
+ var s = [];
+ Y.each(this._activeShims, function(v, k) {
+ if (v._yuid !== d._yuid) {
+ s[s.length] = v;
+ }
+
+ });
+ this._activeShims = s;
+ },
+ /**
+ * @method syncActiveShims
+ * @description This method will sync the position of the shims on the Drop Targets that are currently active.
+ * @param {Boolean} force Resize/sync all Targets.
+ */
+ syncActiveShims: function(force) {
+ Y.later(0, this, function(force) {
+ var drops = ((force) ? this.targets : this._lookup());
+ Y.each(drops, function(v, k) {
+ v.sizeShim.call(v);
+ }, this);
+ }, force);
+ },
+ /**
+ * @private
+ * @property mode
+ * @description The mode that the drag operations will run in 0 for Point, 1 for Intersect, 2 for Strict
+ * @type Number
+ */
+ mode: 0,
+ /**
+ * @private
+ * @property POINT
+ * @description In point mode, a Drop is targeted by the cursor being over the Target
+ * @type Number
+ */
+ POINT: 0,
+ /**
+ * @private
+ * @property INTERSECT
+ * @description In intersect mode, a Drop is targeted by "part" of the drag node being over the Target
+ * @type Number
+ */
+ INTERSECT: 1,
+ /**
+ * @private
+ * @property STRICT
+ * @description In strict mode, a Drop is targeted by the "entire" drag node being over the Target
+ * @type Number
+ */
+ STRICT: 2,
+ /**
+ * @property useHash
+ * @description Should we only check targets that are in the viewport on drags (for performance), default: true
+ * @type {Boolean}
+ */
+ useHash: true,
+ /**
+ * @property activeDrop
+ * @description A reference to the active Drop Target
+ * @type {Object}
+ */
+ activeDrop: null,
+ /**
+ * @property validDrops
+ * @description An array of the valid Drop Targets for this interaction.
+ * @type {Array}
+ */
+ //TODO Change array/object literals to be in sync..
+ validDrops: [],
+ /**
+ * @property otherDrops
+ * @description An object literal of Other Drop Targets that we encountered during this interaction (in the case of overlapping Drop Targets)
+ * @type {Object}
+ */
+ otherDrops: {},
+ /**
+ * @property targets
+ * @description All of the Targets
+ * @type {Array}
+ */
+ targets: [],
+ /**
+ * @private
+ * @method _addValid
+ * @description Add a Drop Target to the list of Valid Targets. This list get's regenerated on each new drag operation.
+ * @param {Object} drop
+ * @return {Self}
+ * @chainable
+ */
+ _addValid: function(drop) {
+ this.validDrops[this.validDrops.length] = drop;
+ return this;
+ },
+ /**
+ * @private
+ * @method _removeValid
+ * @description Removes a Drop Target from the list of Valid Targets. This list get's regenerated on each new drag operation.
+ * @param {Object} drop
+ * @return {Self}
+ * @chainable
+ */
+ _removeValid: function(drop) {
+ var drops = [];
+ Y.each(this.validDrops, function(v, k) {
+ if (v !== drop) {
+ drops[drops.length] = v;
+ }
+ });
+
+ this.validDrops = drops;
+ return this;
+ },
+ /**
+ * @method isOverTarget
+ * @description Check to see if the Drag element is over the target, method varies on current mode
+ * @param {Object} drop The drop to check against
+ * @return {Boolean}
+ */
+ isOverTarget: function(drop) {
+ if (this.activeDrag && drop) {
+ var xy = this.activeDrag.mouseXY, r, dMode = this.activeDrag.get('dragMode'),
+ aRegion;
+ if (xy && this.activeDrag) {
+ aRegion = this.activeDrag.region;
+ if (dMode == this.STRICT) {
+ return this.activeDrag.get('dragNode').inRegion(drop.region, true, aRegion);
+ } else {
+ if (drop && drop.shim) {
+ if ((dMode == this.INTERSECT) && this._noShim) {
+ r = ((aRegion) ? aRegion : this.activeDrag.get('node'));
+ return drop.get('node').intersect(r).inRegion;
+ } else {
+ return drop.shim.intersect({
+ top: xy[1],
+ bottom: xy[1],
+ left: xy[0],
+ right: xy[0]
+ }, drop.region).inRegion;
+ }
+ } else {
+ return false;
+ }
+ }
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ },
+ /**
+ * @method clearCache
+ * @description Clears the cache data used for this interaction.
+ */
+ clearCache: function() {
+ this.validDrops = [];
+ this.otherDrops = {};
+ this._activeShims = [];
+ },
+ /**
+ * @private
+ * @method _activateTargets
+ * @description Clear the cache and activate the shims of all the targets
+ */
+ _activateTargets: function() {
+ this.clearCache();
+ Y.each(this.targets, function(v, k) {
+ v._activateShim.apply(v, []);
+ }, this);
+ this._handleTargetOver();
+
+ },
+ /**
+ * @method getBestMatch
+ * @description This method will gather the area for all potential targets and see which has the hightest covered area and return it.
+ * @param {Array} drops An Array of drops to scan for the best match.
+ * @param {Boolean} all If present, it returns an Array. First item is best match, second is an Array of the other items in the original Array.
+ * @return {Object or Array}
+ */
+ getBestMatch: function(drops, all) {
+ var biggest = null, area = 0, out;
+
+ Y.each(drops, function(v, k) {
+ var inter = this.activeDrag.get('dragNode').intersect(v.get('node'));
+ v.region.area = inter.area;
+
+ if (inter.inRegion) {
+ if (inter.area > area) {
+ area = inter.area;
+ biggest = v;
+ }
+ }
+ }, this);
+ if (all) {
+ out = [];
+ //TODO Sort the others in numeric order by area covered..
+ Y.each(drops, function(v, k) {
+ if (v !== biggest) {
+ out[out.length] = v;
+ }
+ }, this);
+ return [biggest, out];
+ } else {
+ return biggest;
+ }
+ },
+ /**
+ * @private
+ * @method _deactivateTargets
+ * @description This method fires the drop:hit, drag:drophit, drag:dropmiss methods and deactivates the shims..
+ */
+ _deactivateTargets: function() {
+ var other = [], tmp,
+ activeDrag = this.activeDrag,
+ activeDrop = this.activeDrop;
+
+ //TODO why is this check so hard??
+ if (activeDrag && activeDrop && this.otherDrops[activeDrop]) {
+ if (!activeDrag.get('dragMode')) {
+ //TODO otherDrops -- private..
+ other = this.otherDrops;
+ delete other[activeDrop];
+ } else {
+ tmp = this.getBestMatch(this.otherDrops, true);
+ activeDrop = tmp[0];
+ other = tmp[1];
+ }
+ activeDrag.get('node').removeClass(this.CSS_PREFIX + '-drag-over');
+ if (activeDrop) {
+ activeDrop.fire('drop:hit', { drag: activeDrag, drop: activeDrop, others: other });
+ activeDrag.fire('drag:drophit', { drag: activeDrag, drop: activeDrop, others: other });
+ }
+ } else if (activeDrag) {
+ activeDrag.get('node').removeClass(this.CSS_PREFIX + '-drag-over');
+ activeDrag.fire('drag:dropmiss', { pageX: activeDrag.lastXY[0], pageY: activeDrag.lastXY[1] });
+ } else {
+ }
+
+ this.activeDrop = null;
+
+ Y.each(this.targets, function(v, k) {
+ v._deactivateShim.apply(v, []);
+ }, this);
+ },
+ /**
+ * @private
+ * @method _dropMove
+ * @description This method is called when the move method is called on the Drag Object.
+ */
+ _dropMove: function() {
+ if (this._hasActiveShim()) {
+ this._handleTargetOver();
+ } else {
+ Y.each(this.otherDrops, function(v, k) {
+ v._handleOut.apply(v, []);
+ });
+ }
+ },
+ /**
+ * @private
+ * @method _lookup
+ * @description Filters the list of Drops down to those in the viewport.
+ * @return {Array} The valid Drop Targets that are in the viewport.
+ */
+ _lookup: function() {
+ if (!this.useHash || this._noShim) {
+ return this.validDrops;
+ }
+ var drops = [];
+ //Only scan drop shims that are in the Viewport
+ Y.each(this.validDrops, function(v, k) {
+ if (v.shim && v.shim.inViewportRegion(false, v.region)) {
+ drops[drops.length] = v;
+ }
+ });
+ return drops;
+
+ },
+ /**
+ * @private
+ * @method _handleTargetOver
+ * @description This method execs _handleTargetOver on all valid Drop Targets
+ */
+ _handleTargetOver: function() {
+ var drops = this._lookup();
+ Y.each(drops, function(v, k) {
+ v._handleTargetOver.call(v);
+ }, this);
+ },
+ /**
+ * @private
+ * @method _regTarget
+ * @description Add the passed in Target to the targets collection
+ * @param {Object} t The Target to add to the targets collection
+ */
+ _regTarget: function(t) {
+ this.targets[this.targets.length] = t;
+ },
+ /**
+ * @private
+ * @method _unregTarget
+ * @description Remove the passed in Target from the targets collection
+ * @param {Object} drop The Target to remove from the targets collection
+ */
+ _unregTarget: function(drop) {
+ var targets = [], vdrops;
+ Y.each(this.targets, function(v, k) {
+ if (v != drop) {
+ targets[targets.length] = v;
+ }
+ }, this);
+ this.targets = targets;
+
+ vdrops = [];
+ Y.each(this.validDrops, function(v, k) {
+ if (v !== drop) {
+ vdrops[vdrops.length] = v;
+ }
+ });
+
+ this.validDrops = vdrops;
+ },
+ /**
+ * @method getDrop
+ * @description Get a valid Drop instance back from a Node or a selector string, false otherwise
+ * @param {String/Object} node The Node instance or Selector string to check for a valid Drop Object
+ * @return {Object}
+ */
+ getDrop: function(node) {
+ var drop = false,
+ n = Y.Node.get(node);
+ if (n instanceof Y.Node) {
+ Y.each(this.targets, function(v, k) {
+ if (n.compareTo(v.get('node'))) {
+ drop = v;
+ }
+ });
+ }
+ return drop;
+ }
+ }, true);
+
+
+
+
+
+
+
+}, '3.0.0' ,{requires:['dd-ddm'], skinnable:false});
+YUI.add('dd-drag', function(Y) {
+
+
+ /**
+ * The Drag & Drop Utility allows you to create a draggable interface efficiently, buffering you from browser-level abnormalities and enabling you to focus on the interesting logic surrounding your particular implementation. This component enables you to create a variety of standard draggable objects with just a few lines of code and then, using its extensive API, add your own specific implementation logic.
+ * @module dd
+ * @submodule dd-drag
+ */
+ /**
+ * This class provides the ability to drag a Node.
+ * @class Drag
+ * @extends Base
+ * @constructor
+ * @namespace DD
+ */
+
+ var DDM = Y.DD.DDM,
+ NODE = 'node',
+ DRAGGING = 'dragging',
+ DRAG_NODE = 'dragNode',
+ OFFSET_HEIGHT = 'offsetHeight',
+ OFFSET_WIDTH = 'offsetWidth',
+ MOUSE_UP = 'mouseup',
+ MOUSE_DOWN = 'mousedown',
+ DRAG_START = 'dragstart',
+ /**
+ * @event drag:mouseDown
+ * @description Handles the mousedown DOM event, checks to see if you have a valid handle then starts the drag timers.
+ * @preventable _defMouseDownFn
+ * @param {Event.Facade} ev The mousedown event.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_MOUSE_DOWN = 'drag:mouseDown',
+ /**
+ * @event drag:afterMouseDown
+ * @description Fires after the mousedown event has been cleared.
+ * @param {Event.Facade} ev The mousedown event.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_AFTER_MOUSE_DOWN = 'drag:afterMouseDown',
+ /**
+ * @event drag:removeHandle
+ * @description Fires after a handle is removed.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_REMOVE_HANDLE = 'drag:removeHandle',
+ /**
+ * @event drag:addHandle
+ * @description Fires after a handle is added.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_ADD_HANDLE = 'drag:addHandle',
+ /**
+ * @event drag:removeInvalid
+ * @description Fires after an invalid selector is removed.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_REMOVE_INVALID = 'drag:removeInvalid',
+ /**
+ * @event drag:addInvalid
+ * @description Fires after an invalid selector is added.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_ADD_INVALID = 'drag:addInvalid',
+ /**
+ * @event drag:start
+ * @description Fires at the start of a drag operation.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_START = 'drag:start',
+ /**
+ * @event drag:end
+ * @description Fires at the end of a drag operation.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_END = 'drag:end',
+ /**
+ * @event drag:drag
+ * @description Fires every mousemove during a drag operation.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_DRAG = 'drag:drag',
+ /**
+ * @event drag:align
+ * @preventable _defAlignFn
+ * @description Fires when this node is aligned.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_ALIGN = 'drag:align',
+ /**
+ * @event drag:over
+ * @description Fires when this node is over a Drop Target. (Fired from dd-drop)
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ /**
+ * @event drag:enter
+ * @description Fires when this node enters a Drop Target. (Fired from dd-drop)
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ /**
+ * @event drag:exit
+ * @description Fires when this node exits a Drop Target. (Fired from dd-drop)
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ /**
+ * @event drag:drophit
+ * @description Fires when this node is dropped on a valid Drop Target. (Fired from dd-ddm-drop)
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ /**
+ * @event drag:dropmiss
+ * @description Fires when this node is dropped on an invalid Drop Target. (Fired from dd-ddm-drop)
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+
+ Drag = function(o) {
+ this._lazyAddAttrs = false;
+ Drag.superclass.constructor.apply(this, arguments);
+
+ var valid = DDM._regDrag(this);
+ if (!valid) {
+ Y.error('Failed to register node, already in use: ' + o.node);
+ }
+ };
+
+ Drag.NAME = 'drag';
+
+ Drag.ATTRS = {
+ /**
+ * @attribute node
+ * @description Y.Node instanace to use as the element to initiate a drag operation
+ * @type Node
+ */
+ node: {
+ setter: function(node) {
+ var n = Y.get(node);
+ if (!n) {
+ Y.error('DD.Drag: Invalid Node Given: ' + node);
+ } else {
+ n = n.item(0);
+ }
+ return n;
+ }
+ },
+ /**
+ * @attribute dragNode
+ * @description Y.Node instanace to use as the draggable element, defaults to node
+ * @type Node
+ */
+ dragNode: {
+ setter: function(node) {
+ var n = Y.Node.get(node);
+ if (!n) {
+ Y.error('DD.Drag: Invalid dragNode Given: ' + node);
+ }
+ return n;
+ }
+ },
+ /**
+ * @attribute offsetNode
+ * @description Offset the drag element by the difference in cursor position: default true
+ * @type Boolean
+ */
+ offsetNode: {
+ value: true
+ },
+ /**
+ * @attribute clickPixelThresh
+ * @description The number of pixels to move to start a drag operation, default is 3.
+ * @type Number
+ */
+ clickPixelThresh: {
+ value: DDM.get('clickPixelThresh')
+ },
+ /**
+ * @attribute clickTimeThresh
+ * @description The number of milliseconds a mousedown has to pass to start a drag operation, default is 1000.
+ * @type Number
+ */
+ clickTimeThresh: {
+ value: DDM.get('clickTimeThresh')
+ },
+ /**
+ * @attribute lock
+ * @description Set to lock this drag element so that it can't be dragged: default false.
+ * @type Boolean
+ */
+ lock: {
+ value: false,
+ setter: function(lock) {
+ if (lock) {
+ this.get(NODE).addClass(DDM.CSS_PREFIX + '-locked');
+ } else {
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-locked');
+ }
+ return lock;
+ }
+ },
+ /**
+ * @attribute data
+ * @description A payload holder to store arbitrary data about this drag object, can be used to store any value.
+ * @type Mixed
+ */
+ data: {
+ value: false
+ },
+ /**
+ * @attribute move
+ * @description If this is false, the drag element will not move with the cursor: default true. Can be used to "resize" the element.
+ * @type Boolean
+ */
+ move: {
+ value: true
+ },
+ /**
+ * @attribute useShim
+ * @description Use the protective shim on all drag operations: default true. Only works with dd-ddm, not dd-ddm-base.
+ * @type Boolean
+ */
+ useShim: {
+ value: true
+ },
+ /**
+ * @attribute activeHandle
+ * @description This config option is set by Drag to inform you of which handle fired the drag event (in the case that there are several handles): default false.
+ * @type Node
+ */
+ activeHandle: {
+ value: false
+ },
+ /**
+ * @attribute primaryButtonOnly
+ * @description By default a drag operation will only begin if the mousedown occurred with the primary mouse button. Setting this to false will allow for all mousedown events to trigger a drag.
+ * @type Boolean
+ */
+ primaryButtonOnly: {
+ value: true
+ },
+ /**
+ * @attribute dragging
+ * @description This attribute is not meant to be used by the implementor, it is meant to be used as an Event tracker so you can listen for it to change.
+ * @type Boolean
+ */
+ dragging: {
+ value: false
+ },
+ parent: {
+ value: false
+ },
+ /**
+ * @attribute target
+ * @description This attribute only works if the dd-drop module has been loaded. It will make this node a drop target as well as draggable.
+ * @type Boolean
+ */
+ target: {
+ value: false,
+ setter: function(config) {
+ this._handleTarget(config);
+ return config;
+ }
+ },
+ /**
+ * @attribute dragMode
+ * @description This attribute only works if the dd-drop module is active. It will set the dragMode (point, intersect, strict) of this Drag instance.
+ * @type String
+ */
+ dragMode: {
+ value: null,
+ setter: function(mode) {
+ return DDM._setDragMode(mode);
+ }
+ },
+ /**
+ * @attribute groups
+ * @description Array of groups to add this drag into.
+ * @type Array
+ */
+ groups: {
+ value: ['default'],
+ getter: function() {
+ if (!this._groups) {
+ this._groups = {};
+ }
+ var ret = [];
+ Y.each(this._groups, function(v, k) {
+ ret[ret.length] = k;
+ });
+ return ret;
+ },
+ setter: function(g) {
+ this._groups = {};
+ Y.each(g, function(v, k) {
+ this._groups[v] = true;
+ }, this);
+ return g;
+ }
+ },
+ /**
+ * @attribute handles
+ * @description Array of valid handles to add. Adding something here will set all handles, even if previously added with addHandle
+ * @type Array
+ */
+ handles: {
+ value: null,
+ setter: function(g) {
+ if (g) {
+ this._handles = {};
+ Y.each(g, function(v, k) {
+ this._handles[v] = true;
+ }, this);
+ } else {
+ this._handles = null;
+ }
+ return g;
+ }
+ },
+ /**
+ * @attribute bubbles
+ * @description Controls the default bubble parent for this Drag instance. Default: Y.DD.DDM. Set to false to disable bubbling.
+ * @type Object
+ */
+ bubbles: {
+ writeOnce: true,
+ value: Y.DD.DDM
+ }
+ };
+
+ Y.extend(Drag, Y.Base, {
+ /**
+ * @method addToGroup
+ * @description Add this Drag instance to a group, this should be used for on-the-fly group additions.
+ * @param {String} g The group to add this Drag Instance to.
+ * @return {Self}
+ * @chainable
+ */
+ addToGroup: function(g) {
+ this._groups[g] = true;
+ DDM._activateTargets();
+ return this;
+ },
+ /**
+ * @method removeFromGroup
+ * @description Remove this Drag instance from a group, this should be used for on-the-fly group removals.
+ * @param {String} g The group to remove this Drag Instance from.
+ * @return {Self}
+ * @chainable
+ */
+ removeFromGroup: function(g) {
+ delete this._groups[g];
+ DDM._activateTargets();
+ return this;
+ },
+ /**
+ * @property target
+ * @description This will be a reference to the Drop instance associated with this drag if the target: true config attribute is set..
+ * @type {Object}
+ */
+ target: null,
+ /**
+ * @private
+ * @method _handleTarget
+ * @description Attribute handler for the target config attribute.
+ * @param {Boolean/Object}
+ * @return {Boolean/Object}
+ */
+ _handleTarget: function(config) {
+ if (Y.DD.Drop) {
+ if (config === false) {
+ if (this.target) {
+ DDM._unregTarget(this.target);
+ this.target = null;
+ }
+ return false;
+ } else {
+ if (!Y.Lang.isObject(config)) {
+ config = {};
+ }
+ config.bubbles = ('bubbles' in config) ? config.bubbles : this.get('bubbles');
+ config.node = this.get(NODE);
+ config.groups = config.groups || this.get('groups');
+ this.target = new Y.DD.Drop(config);
+ }
+ } else {
+ return false;
+ }
+ },
+ /**
+ * @private
+ * @property _groups
+ * @description Storage Array for the groups this drag belongs to.
+ * @type {Array}
+ */
+ _groups: null,
+ /**
+ * @private
+ * @method _createEvents
+ * @description This method creates all the events for this Event Target and publishes them so we get Event Bubbling.
+ */
+ _createEvents: function() {
+
+ this.publish(EV_MOUSE_DOWN, {
+ defaultFn: this._defMouseDownFn,
+ queuable: false,
+ emitFacade: true,
+ bubbles: true,
+ prefix: 'drag'
+ });
+
+ this.publish(EV_ALIGN, {
+ defaultFn: this._defAlignFn,
+ queuable: false,
+ emitFacade: true,
+ bubbles: true,
+ prefix: 'drag'
+ });
+
+ this.publish(EV_DRAG, {
+ defaultFn: this._defDragFn,
+ queuable: false,
+ emitFacade: true,
+ bubbles: true,
+ prefix: 'drag'
+ });
+
+ this.publish(EV_END, {
+ preventedFn: this._prevEndFn,
+ queuable: false,
+ emitFacade: true,
+ bubbles: true,
+ prefix: 'drag'
+ });
+
+ var ev = [
+ EV_AFTER_MOUSE_DOWN,
+ EV_REMOVE_HANDLE,
+ EV_ADD_HANDLE,
+ EV_REMOVE_INVALID,
+ EV_ADD_INVALID,
+ EV_START,
+ 'drag:drophit',
+ 'drag:dropmiss',
+ 'drag:over',
+ 'drag:enter',
+ 'drag:exit'
+ ];
+
+ Y.each(ev, function(v, k) {
+ this.publish(v, {
+ type: v,
+ emitFacade: true,
+ bubbles: true,
+ preventable: false,
+ queuable: false,
+ prefix: 'drag'
+ });
+ }, this);
+
+ if (this.get('bubbles')) {
+ this.addTarget(this.get('bubbles'));
+ }
+
+
+ },
+ /**
+ * @private
+ * @property _ev_md
+ * @description A private reference to the mousedown DOM event
+ * @type {Event.Facade}
+ */
+ _ev_md: null,
+ /**
+ * @private
+ * @property _startTime
+ * @description The getTime of the mousedown event. Not used, just here in case someone wants/needs to use it.
+ * @type Date
+ */
+ _startTime: null,
+ /**
+ * @private
+ * @property _endTime
+ * @description The getTime of the mouseup event. Not used, just here in case someone wants/needs to use it.
+ * @type Date
+ */
+ _endTime: null,
+ /**
+ * @private
+ * @property _handles
+ * @description A private hash of the valid drag handles
+ * @type {Object}
+ */
+ _handles: null,
+ /**
+ * @private
+ * @property _invalids
+ * @description A private hash of the invalid selector strings
+ * @type {Object}
+ */
+ _invalids: null,
+ /**
+ * @private
+ * @property _invalidsDefault
+ * @description A private hash of the default invalid selector strings: {'textarea': true, 'input': true, 'a': true, 'button': true, 'select': true}
+ * @type {Object}
+ */
+ _invalidsDefault: {'textarea': true, 'input': true, 'a': true, 'button': true, 'select': true },
+ /**
+ * @private
+ * @property _dragThreshMet
+ * @description Private flag to see if the drag threshhold was met
+ * @type {Boolean}
+ */
+ _dragThreshMet: null,
+ /**
+ * @private
+ * @property _fromTimeout
+ * @description Flag to determine if the drag operation came from a timeout
+ * @type {Boolean}
+ */
+ _fromTimeout: null,
+ /**
+ * @private
+ * @property _clickTimeout
+ * @description Holder for the setTimeout call
+ * @type {Boolean}
+ */
+ _clickTimeout: null,
+ /**
+ * @property deltaXY
+ * @description The offset of the mouse position to the element's position
+ * @type {Array}
+ */
+ deltaXY: null,
+ /**
+ * @property startXY
+ * @description The initial mouse position
+ * @type {Array}
+ */
+ startXY: null,
+ /**
+ * @property nodeXY
+ * @description The initial element position
+ * @type {Array}
+ */
+ nodeXY: null,
+ /**
+ * @property lastXY
+ * @description The position of the element as it's moving (for offset calculations)
+ * @type {Array}
+ */
+ lastXY: null,
+ /**
+ * @property actXY
+ * @description The xy that the node will be set to. Changing this will alter the position as it's dragged.
+ * @type {Array}
+ */
+ actXY: null,
+ /**
+ * @property realXY
+ * @description The real xy position of the node.
+ * @type {Array}
+ */
+ realXY: null,
+ /**
+ * @property mouseXY
+ * @description The XY coords of the mousemove
+ * @type {Array}
+ */
+ mouseXY: null,
+ /**
+ * @property region
+ * @description A region object associated with this drag, used for checking regions while dragging.
+ * @type Object
+ */
+ region: null,
+ /**
+ * @private
+ * @method _handleMouseUp
+ * @description Handler for the mouseup DOM event
+ * @param {Event.Facade}
+ */
+ _handleMouseUp: function(ev) {
+ this._fixIEMouseUp();
+ if (DDM.activeDrag) {
+ DDM._end();
+ }
+ },
+ /**
+ * @private
+ * @method _fixDragStart
+ * @description The function we use as the ondragstart handler when we start a drag in Internet Explorer. This keeps IE from blowing up on images as drag handles.
+ */
+ _fixDragStart: function(e) {
+ e.preventDefault();
+ },
+ /**
+ * @private
+ * @method _ieSelectFix
+ * @description The function we use as the onselectstart handler when we start a drag in Internet Explorer
+ */
+ _ieSelectFix: function() {
+ return false;
+ },
+ /**
+ * @private
+ * @property _ieSelectBack
+ * @description We will hold a copy of the current "onselectstart" method on this property, and reset it after we are done using it.
+ */
+ _ieSelectBack: null,
+ /**
+ * @private
+ * @method _fixIEMouseDown
+ * @description This method copies the onselectstart listner on the document to the _ieSelectFix property
+ */
+ _fixIEMouseDown: function() {
+ if (Y.UA.ie) {
+ this._ieSelectBack = Y.config.doc.body.onselectstart;
+ Y.config.doc.body.onselectstart = this._ieSelectFix;
+ }
+ },
+ /**
+ * @private
+ * @method _fixIEMouseUp
+ * @description This method copies the _ieSelectFix property back to the onselectstart listner on the document.
+ */
+ _fixIEMouseUp: function() {
+ if (Y.UA.ie) {
+ Y.config.doc.body.onselectstart = this._ieSelectBack;
+ }
+ },
+ /**
+ * @private
+ * @method _handleMouseDownEvent
+ * @description Handler for the mousedown DOM event
+ * @param {Event.Facade}
+ */
+ _handleMouseDownEvent: function(ev) {
+ this.fire(EV_MOUSE_DOWN, { ev: ev });
+ },
+ /**
+ * @private
+ * @method _defMouseDownFn
+ * @description Handler for the mousedown DOM event
+ * @param {Event.Facade}
+ */
+ _defMouseDownFn: function(e) {
+ var ev = e.ev;
+ this._dragThreshMet = false;
+ this._ev_md = ev;
+
+ if (this.get('primaryButtonOnly') && ev.button > 1) {
+ return false;
+ }
+ if (this.validClick(ev)) {
+ this._fixIEMouseDown();
+ ev.halt();
+ this._setStartPosition([ev.pageX, ev.pageY]);
+
+ DDM.activeDrag = this;
+
+ this._clickTimeout = Y.later(this.get('clickTimeThresh'), this, this._timeoutCheck);
+ }
+ this.fire(EV_AFTER_MOUSE_DOWN, { ev: ev });
+ },
+ /**
+ * @method validClick
+ * @description Method first checks to see if we have handles, if so it validates the click against the handle. Then if it finds a valid handle, it checks it against the invalid handles list. Returns true if a good handle was used, false otherwise.
+ * @param {Event.Facade}
+ * @return {Boolean}
+ */
+ validClick: function(ev) {
+ var r = false, n = false,
+ tar = ev.target,
+ hTest = null,
+ els = null,
+ set = false;
+ if (this._handles) {
+ Y.each(this._handles, function(i, n) {
+ if (Y.Lang.isString(n)) {
+ //Am I this or am I inside this
+ if (tar.test(n + ', ' + n + ' *') && !hTest) {
+ hTest = n;
+ r = true;
+ }
+ }
+ });
+ } else {
+ n = this.get(NODE)
+ if (n.contains(tar) || n.compareTo(tar)) {
+ r = true;
+ }
+ }
+ if (r) {
+ if (this._invalids) {
+ Y.each(this._invalids, function(i, n) {
+ if (Y.Lang.isString(n)) {
+ //Am I this or am I inside this
+ if (tar.test(n + ', ' + n + ' *')) {
+ r = false;
+ }
+ }
+ });
+ }
+ }
+ if (r) {
+ if (hTest) {
+ els = ev.currentTarget.queryAll(hTest);
+ set = false;
+ els.each(function(n, i) {
+ if ((n.contains(tar) || n.compareTo(tar)) && !set) {
+ set = true;
+ this.set('activeHandle', n);
+ }
+ }, this);
+ } else {
+ this.set('activeHandle', this.get(NODE));
+ }
+ }
+ return r;
+ },
+ /**
+ * @private
+ * @method _setStartPosition
+ * @description Sets the current position of the Element and calculates the offset
+ * @param {Array} xy The XY coords to set the position to.
+ */
+ _setStartPosition: function(xy) {
+ this.startXY = xy;
+
+ this.nodeXY = this.lastXY = this.realXY = this.get(NODE).getXY();
+
+ if (this.get('offsetNode')) {
+ this.deltaXY = [(this.startXY[0] - this.nodeXY[0]), (this.startXY[1] - this.nodeXY[1])];
+ } else {
+ this.deltaXY = [0, 0];
+ }
+ },
+ /**
+ * @private
+ * @method _timeoutCheck
+ * @description The method passed to setTimeout to determine if the clickTimeThreshold was met.
+ */
+ _timeoutCheck: function() {
+ if (!this.get('lock') && !this._dragThreshMet) {
+ this._fromTimeout = this._dragThreshMet = true;
+ this.start();
+ this._alignNode([this._ev_md.pageX, this._ev_md.pageY], true);
+ }
+ },
+ /**
+ * @method removeHandle
+ * @description Remove a Selector added by addHandle
+ * @param {String} str The selector for the handle to be removed.
+ * @return {Self}
+ * @chainable
+ */
+ removeHandle: function(str) {
+ if (this._handles[str]) {
+ delete this._handles[str];
+ this.fire(EV_REMOVE_HANDLE, { handle: str });
+ }
+ return this;
+ },
+ /**
+ * @method addHandle
+ * @description Add a handle to a drag element. Drag only initiates when a mousedown happens on this element.
+ * @param {String} str The selector to test for a valid handle. Must be a child of the element.
+ * @return {Self}
+ * @chainable
+ */
+ addHandle: function(str) {
+ if (!this._handles) {
+ this._handles = {};
+ }
+ if (Y.Lang.isString(str)) {
+ this._handles[str] = true;
+ this.fire(EV_ADD_HANDLE, { handle: str });
+ }
+ return this;
+ },
+ /**
+ * @method removeInvalid
+ * @description Remove an invalid handle added by addInvalid
+ * @param {String} str The invalid handle to remove from the internal list.
+ * @return {Self}
+ * @chainable
+ */
+ removeInvalid: function(str) {
+ if (this._invalids[str]) {
+ this._invalids[str] = null;
+ delete this._invalids[str];
+ this.fire(EV_REMOVE_INVALID, { handle: str });
+ }
+ return this;
+ },
+ /**
+ * @method addInvalid
+ * @description Add a selector string to test the handle against. If the test passes the drag operation will not continue.
+ * @param {String} str The selector to test against to determine if this is an invalid drag handle.
+ * @return {Self}
+ * @chainable
+ */
+ addInvalid: function(str) {
+ if (Y.Lang.isString(str)) {
+ this._invalids[str] = true;
+ this.fire(EV_ADD_INVALID, { handle: str });
+ }
+ return this;
+ },
+ /**
+ * @private
+ * @method initializer
+ * @description Internal init handler
+ */
+ initializer: function() {
+ this.get(NODE).dd = this;
+
+ if (!this.get(NODE).get('id')) {
+ var id = Y.stamp(this.get(NODE));
+ this.get(NODE).set('id', id);
+ }
+
+ this.actXY = [];
+
+ this._invalids = Y.clone(this._invalidsDefault, true);
+
+ this._createEvents();
+
+ if (!this.get(DRAG_NODE)) {
+ this.set(DRAG_NODE, this.get(NODE));
+ }
+
+ //Fix for #2528096
+ //Don't prep the DD instance until all plugins are loaded.
+ this.on('initializedChange', Y.bind(this._prep, this));
+
+ //Shouldn't have to do this..
+ this.set('groups', this.get('groups'));
+ },
+ /**
+ * @private
+ * @method _prep
+ * @description Attach event listners and add classname
+ */
+ _prep: function() {
+ this._dragThreshMet = false;
+ var node = this.get(NODE);
+ node.addClass(DDM.CSS_PREFIX + '-draggable');
+ node.on(MOUSE_DOWN, Y.bind(this._handleMouseDownEvent, this));
+ node.on(MOUSE_UP, Y.bind(this._handleMouseUp, this));
+ node.on(DRAG_START, Y.bind(this._fixDragStart, this));
+ },
+ /**
+ * @private
+ * @method _unprep
+ * @description Detach event listeners and remove classname
+ */
+ _unprep: function() {
+ var node = this.get(NODE);
+ node.removeClass(DDM.CSS_PREFIX + '-draggable');
+ node.detachAll();
+ },
+ /**
+ * @method start
+ * @description Starts the drag operation
+ * @return {Self}
+ * @chainable
+ */
+ start: function() {
+ if (!this.get('lock') && !this.get(DRAGGING)) {
+ var node = this.get(NODE), ow = node.get(OFFSET_WIDTH), oh = node.get(OFFSET_HEIGHT);
+ this._startTime = (new Date()).getTime();
+
+ DDM._start();
+ node.addClass(DDM.CSS_PREFIX + '-dragging');
+ this.fire(EV_START, {
+ pageX: this.nodeXY[0],
+ pageY: this.nodeXY[1],
+ startTime: this._startTime
+ });
+ var xy = this.nodeXY;
+
+
+ this.region = {
+ '0': xy[0],
+ '1': xy[1],
+ area: 0,
+ top: xy[1],
+ right: xy[0] + ow,
+ bottom: xy[1] + oh,
+ left: xy[0]
+ };
+ this.set(DRAGGING, true);
+ }
+ return this;
+ },
+ /**
+ * @method end
+ * @description Ends the drag operation
+ * @return {Self}
+ * @chainable
+ */
+ end: function() {
+ this._endTime = (new Date()).getTime();
+ if (this._clickTimeout) {
+ this._clickTimeout.cancel();
+ }
+ this._dragThreshMet = false;
+ this._fromTimeout = false;
+ if (!this.get('lock') && this.get(DRAGGING)) {
+ this.fire(EV_END, {
+ pageX: this.lastXY[0],
+ pageY: this.lastXY[1],
+ startTime: this._startTime,
+ endTime: this._endTime
+ });
+ }
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-dragging');
+ this.set(DRAGGING, false);
+ this.deltaXY = [0, 0];
+
+ return this;
+ },
+ /**
+ * @private
+ * @method _prevEndFn
+ * @description Handler for preventing the drag:end event. It will reset the node back to it's start position
+ */
+ _prevEndFn: function(e) {
+ //Bug #1852577
+ this.get(DRAG_NODE).setXY(this.nodeXY);
+ },
+ /**
+ * @private
+ * @method _align
+ * @description Calculates the offsets and set's the XY that the element will move to.
+ * @param {Array} xy The xy coords to align with.
+ */
+ _align: function(xy) {
+ this.fire(EV_ALIGN, {pageX: xy[0], pageY: xy[1] });
+ },
+ /**
+ * @private
+ * @method _defAlignFn
+ * @description Calculates the offsets and set's the XY that the element will move to.
+ * @param {Event.Facade} e The drag:align event.
+ */
+ _defAlignFn: function(e) {
+ this.actXY = [e.pageX - this.deltaXY[0], e.pageY - this.deltaXY[1]];
+ },
+ /**
+ * @private
+ * @method _alignNode
+ * @description This method performs the alignment before the element move.
+ * @param {Array} eXY The XY to move the element to, usually comes from the mousemove DOM event.
+ */
+ _alignNode: function(eXY) {
+ this._align(eXY);
+ this._moveNode();
+ },
+ /**
+ * @private
+ * @method _moveNode
+ * @description This method performs the actual element move.
+ */
+ _moveNode: function(scroll) {
+ //if (!this.get(DRAGGING)) {
+ // return;
+ //}
+ var diffXY = [], diffXY2 = [], startXY = this.nodeXY, xy = this.actXY;
+
+ diffXY[0] = (xy[0] - this.lastXY[0]);
+ diffXY[1] = (xy[1] - this.lastXY[1]);
+
+ diffXY2[0] = (xy[0] - this.nodeXY[0]);
+ diffXY2[1] = (xy[1] - this.nodeXY[1]);
+
+
+ this.region = {
+ '0': xy[0],
+ '1': xy[1],
+ area: 0,
+ top: xy[1],
+ right: xy[0] + this.get(DRAG_NODE).get(OFFSET_WIDTH),
+ bottom: xy[1] + this.get(DRAG_NODE).get(OFFSET_HEIGHT),
+ left: xy[0]
+ };
+
+ this.fire(EV_DRAG, {
+ pageX: xy[0],
+ pageY: xy[1],
+ scroll: scroll,
+ info: {
+ start: startXY,
+ xy: xy,
+ delta: diffXY,
+ offset: diffXY2
+ }
+ });
+
+ this.lastXY = xy;
+ },
+ /**
+ * @private
+ * @method _defDragFn
+ * @description Default function for drag:drag. Fired from _moveNode.
+ * @param {Event.Facade} ev The drag:drag event
+ */
+ _defDragFn: function(e) {
+ if (this.get('move')) {
+ if (e.scroll) {
+ e.scroll.node.set('scrollTop', e.scroll.top);
+ e.scroll.node.set('scrollLeft', e.scroll.left);
+ }
+ this.get(DRAG_NODE).setXY([e.pageX, e.pageY]);
+ this.realXY = [e.pageX, e.pageY];
+ }
+ },
+ /**
+ * @private
+ * @method _move
+ * @description Fired from DragDropMgr (DDM) on mousemove.
+ * @param {Event.Facade} ev The mousemove DOM event
+ */
+ _move: function(ev) {
+ if (this.get('lock')) {
+ return false;
+ } else {
+ this.mouseXY = [ev.pageX, ev.pageY];
+ if (!this._dragThreshMet) {
+ var diffX = Math.abs(this.startXY[0] - ev.pageX),
+ diffY = Math.abs(this.startXY[1] - ev.pageY);
+ if (diffX > this.get('clickPixelThresh') || diffY > this.get('clickPixelThresh')) {
+ this._dragThreshMet = true;
+ this.start();
+ this._alignNode([ev.pageX, ev.pageY]);
+ }
+ } else {
+ if (this._clickTimeout) {
+ this._clickTimeout.cancel();
+ }
+ this._alignNode([ev.pageX, ev.pageY]);
+ }
+ }
+ },
+ /**
+ * @method stopDrag
+ * @description Method will forcefully stop a drag operation. For example calling this from inside an ESC keypress handler will stop this drag.
+ * @return {Self}
+ * @chainable
+ */
+ stopDrag: function() {
+ if (this.get(DRAGGING)) {
+ DDM._end();
+ }
+ return this;
+ },
+ /**
+ * @private
+ * @method destructor
+ * @description Lifecycle destructor, unreg the drag from the DDM and remove listeners
+ */
+ destructor: function() {
+ this._unprep();
+ this.detachAll();
+ if (this.target) {
+ this.target.destroy();
+ }
+ DDM._unregDrag(this);
+ }
+ });
+ Y.namespace('DD');
+ Y.DD.Drag = Drag;
+
+
+
+
+
+}, '3.0.0' ,{requires:['dd-ddm-base'], skinnable:false});
+YUI.add('dd-proxy', function(Y) {
+
+
+ /**
+ * The Drag & Drop Utility allows you to create a draggable interface efficiently, buffering you from browser-level abnormalities and enabling you to focus on the interesting logic surrounding your particular implementation. This component enables you to create a variety of standard draggable objects with just a few lines of code and then, using its extensive API, add your own specific implementation logic.
+ * @module dd
+ * @submodule dd-proxy
+ */
+ /**
+ * This plugin for dd-drag is for creating a proxy drag node, instead of dragging the original node.
+ * @class DDProxy
+ * @extends Base
+ * @constructor
+ * @namespace Plugin
+ */
+ var DDM = Y.DD.DDM,
+ NODE = 'node',
+ DRAG_NODE = 'dragNode',
+ HOST = 'host',
+ TRUE = true;
+
+ var P = function(config) {
+ P.superclass.constructor.apply(this, arguments);
+ };
+
+ P.NAME = 'DDProxy';
+ /**
+ * @property proxy
+ * @description The Proxy instance will be placed on the Drag instance under the proxy namespace.
+ * @type {String}
+ */
+ P.NS = 'proxy';
+
+ P.ATTRS = {
+ host: {
+ },
+ /**
+ * @attribute moveOnEnd
+ * @description Move the original node at the end of the drag. Default: true
+ * @type Boolean
+ */
+ moveOnEnd: {
+ value: TRUE
+ },
+ /**
+ * @attribute hideOnEnd
+ * @description Hide the drag node at the end of the drag. Default: true
+ * @type Boolean
+ */
+ hideOnEnd: {
+ value: TRUE
+ },
+ /**
+ * @attribute resizeFrame
+ * @description Make the Proxy node assume the size of the original node. Default: true
+ * @type Boolean
+ */
+ resizeFrame: {
+ value: TRUE
+ },
+ /**
+ * @attribute positionProxy
+ * @description Make the Proxy node appear in the same place as the original node. Default: true
+ * @type Boolean
+ */
+ positionProxy: {
+ value: TRUE
+ },
+ /**
+ * @attribute borderStyle
+ * @description The default border style for the border of the proxy. Default: 1px solid #808080
+ * @type Boolean
+ */
+ borderStyle: {
+ value: '1px solid #808080'
+ }
+ };
+
+ var proto = {
+ /**
+ * @private
+ * @property _hands
+ * @description Holds the event handles for setting the proxy
+ */
+ _hands: null,
+ /**
+ * @private
+ * @method _init
+ * @description Handler for the proxy config attribute
+ */
+ _init: function() {
+ if (!DDM._proxy) {
+ Y.on('domready', Y.bind(this._init, this));
+ return;
+ }
+ if (!this._hands) {
+ this._hands = [];
+ }
+ var i, h, h1, host = this.get(HOST), dnode = host.get(DRAG_NODE);
+ if (dnode.compareTo(host.get(NODE))) {
+ if (DDM._proxy) {
+ host.set(DRAG_NODE, DDM._proxy);
+ }
+ }
+ Y.each(this._hands, function(v) {
+ v.detach();
+ });
+ h = DDM.on('ddm:start', Y.bind(function() {
+ if (DDM.activeDrag === host) {
+ DDM._setFrame(host);
+ }
+ }, this));
+ h1 = DDM.on('ddm:end', Y.bind(function() {
+ if (host.get('dragging')) {
+ if (this.get('moveOnEnd')) {
+ host.get(NODE).setXY(host.lastXY);
+ }
+ if (this.get('hideOnEnd')) {
+ host.get(DRAG_NODE).setStyle('display', 'none');
+ }
+ }
+ }, this));
+ this._hands = [h, h1];
+ },
+ initializer: function() {
+ this._init();
+ },
+ destructor: function() {
+ var host = this.get(HOST);
+ Y.each(this._hands, function(v) {
+ v.detach();
+ });
+ host.set(DRAG_NODE, host.get(NODE));
+ }
+ };
+
+ Y.namespace('Plugin');
+ Y.extend(P, Y.Base, proto);
+ Y.Plugin.DDProxy = P;
+
+ //Add a couple of methods to the DDM
+ Y.mix(DDM, {
+ /**
+ * @private
+ * @for DDM
+ * @namespace DD
+ * @method _createFrame
+ * @description Create the proxy element if it doesn't already exist and set the DD.DDM._proxy value
+ */
+ _createFrame: function() {
+ if (!DDM._proxy) {
+ DDM._proxy = TRUE;
+
+ var p = Y.Node.create(''),
+ b = Y.Node.get('body');
+
+ p.setStyles({
+ position: 'absolute',
+ display: 'none',
+ zIndex: '999',
+ top: '-999px',
+ left: '-999px'
+ });
+
+ b.insertBefore(p, b.get('firstChild'));
+ p.set('id', Y.stamp(p));
+ p.addClass(DDM.CSS_PREFIX + '-proxy');
+ DDM._proxy = p;
+ }
+ },
+ /**
+ * @private
+ * @for DDM
+ * @namespace DD
+ * @method _setFrame
+ * @description If resizeProxy is set to true (default) it will resize the proxy element to match the size of the Drag Element.
+ * If positionProxy is set to true (default) it will position the proxy element in the same location as the Drag Element.
+ */
+ _setFrame: function(drag) {
+ var n = drag.get(NODE), d = drag.get(DRAG_NODE), ah, cur = 'auto';
+ if (drag.proxy.get('resizeFrame')) {
+ DDM._proxy.setStyles({
+ height: n.get('offsetHeight') + 'px',
+ width: n.get('offsetWidth') + 'px'
+ });
+ }
+
+ ah = DDM.activeDrag.get('activeHandle');
+ if (ah) {
+ cur = ah.getStyle('cursor');
+ }
+ if (cur == 'auto') {
+ cur = DDM.get('dragCursor');
+ }
+
+
+ d.setStyles({
+ visibility: 'hidden',
+ display: 'block',
+ cursor: cur,
+ border: drag.proxy.get('borderStyle')
+ });
+
+
+
+ if (drag.proxy.get('positionProxy')) {
+ d.setXY(drag.nodeXY);
+ }
+ d.setStyle('visibility', 'visible');
+ }
+ });
+
+ //Create the frame when DOM is ready
+ Y.on('domready', Y.bind(DDM._createFrame, DDM));
+
+
+
+}, '3.0.0' ,{requires:['dd-ddm', 'dd-drag'], skinnable:false});
+YUI.add('dd-constrain', function(Y) {
+
+
+ /**
+ * The Drag & Drop Utility allows you to create a draggable interface efficiently, buffering you from browser-level abnormalities and enabling you to focus on the interesting logic surrounding your particular implementation. This component enables you to create a variety of standard draggable objects with just a few lines of code and then, using its extensive API, add your own specific implementation logic.
+ * @module dd
+ * @submodule dd-constrain
+ */
+ /**
+ * This is a plugin for the dd-drag module to add the constraining methods to it. It supports constraining to a renodenode or viewport. It anode* supports tick based moves and XY axis constraints.
+ * @class DragConstrained
+ * @extends Base
+ * @constructor
+ * @namespace Plugin
+ */
+
+ var DRAG_NODE = 'dragNode',
+ OFFSET_HEIGHT = 'offsetHeight',
+ OFFSET_WIDTH = 'offsetWidth',
+ HOST = 'host',
+ CON_2_REGION = 'constrain2region',
+ CON_2_NODE = 'constrain2node',
+ TICK_X_ARRAY = 'tickXArray',
+ TICK_Y_ARRAY = 'tickYArray',
+ DDM = Y.DD.DDM,
+ TOP = 'top',
+ RIGHT = 'right',
+ BOTTOM = 'bottom',
+ LEFT = 'left',
+ proto = null;
+
+ var C = function(config) {
+ C.superclass.constructor.apply(this, arguments);
+ };
+
+ C.NAME = 'DragConstrained';
+ /**
+ * @property con
+ * @description The Constrained instance will be placed on the Drag instance under the con namespace.
+ * @type {String}
+ */
+ C.NS = 'con';
+
+ C.ATTRS = {
+ host: {
+ },
+ /**
+ * @attribute stickX
+ * @description Stick the drag movement to the X-Axis. Default: false
+ * @type Boolean
+ */
+ stickX: {
+ value: false
+ },
+ /**
+ * @attribute stickY
+ * @description Stick the drag movement to the Y-Axis
+ * @type Boolean
+ */
+ stickY: {
+ value: false
+ },
+ /**
+ * @attribute tickX
+ * @description The X tick offset the drag node should snap to on each drag move. False for no ticks. Default: false
+ * @type Number/false
+ */
+ tickX: {
+ value: false
+ },
+ /**
+ * @attribute tickY
+ * @description The Y tick offset the drag node should snap to on each drag move. False for no ticks. Default: false
+ * @type Number/false
+ */
+ tickY: {
+ value: false
+ },
+ /**
+ * @attribute tickXArray
+ * @description An array of page coordinates to use as X ticks for drag movement.
+ * @type Array
+ */
+ tickXArray: {
+ value: false
+ },
+ /**
+ * @attribute tickYArray
+ * @description An array of page coordinates to use as Y ticks for drag movement.
+ * @type Array
+ */
+ tickYArray: {
+ value: false
+ },
+ /**
+ * @attribute constrain2region
+ * @description An Object Literal containing a valid region (top, right, bottom, left) of page positions to constrain the drag node to.
+ * @type Object
+ */
+ constrain2region: {
+ value: false,
+ getter: function(r) {
+ if (Y.Lang.isObject(r)) {
+ var o = {};
+ Y.mix(o, r);
+ return o;
+ } else {
+ return false;
+ }
+ },
+ setter: function (r) {
+ if (Y.Lang.isObject(r)) {
+ if (Y.Lang.isNumber(r[TOP]) && Y.Lang.isNumber(r[RIGHT]) && Y.Lang.isNumber(r[LEFT]) && Y.Lang.isNumber(r[BOTTOM])) {
+ var o = {};
+ Y.mix(o, r);
+ return o;
+ } else {
+ return false;
+ }
+ } else if (r !== false) {
+ return false;
+ }
+ return r;
+ }
+ },
+ /**
+ * @attribute gutter
+ * @description CSS style string for the gutter of a region (supports negative values): '5 0' (sets top and bottom to 5px, left and right to 0px), '1 2 3 4' (top 1px, right 2px, bottom 3px, left 4px)
+ * @type String
+ */
+ gutter: {
+ value: '0',
+ setter: function(gutter) {
+ return Y.DD.DDM.cssSizestoObject(gutter);
+ }
+ },
+ /**
+ * @attribute constrain2node
+ * @description Will attempt to constrain the drag node to the boundaries of this node.
+ * @type Object
+ */
+ constrain2node: {
+ value: false,
+ setter: function(n) {
+ if (!this.get(CON_2_REGION)) {
+ var node = Y.Node.get(n);
+ if (node) {
+ return node;
+ }
+ } else if (this.get(CON_2_REGION) !== false) {
+ }
+ return false;
+ }
+ },
+ /**
+ * @attribute constrain2view
+ * @description Will attempt to constrain the drag node to the boundaries of the viewport region.
+ * @type Object
+ */
+ constrain2view: {
+ value: false
+ }
+ };
+
+ proto = {
+ initializer: function() {
+ this.get(HOST).on('drag:start', Y.bind(this._handleStart, this));
+ this.get(HOST).after('drag:align', Y.bind(this.align, this));
+ },
+ /**
+ * @private
+ * @method _handleStart
+ * @description Fires on drag:start and clears the _regionCache
+ */
+ _handleStart: function() {
+ this._regionCache = null;
+ },
+ /**
+ * @private
+ * @property _regionCache
+ * @description Store a cache of the region that we are constraining to
+ * @type Object
+ */
+ _regionCache: null,
+ /**
+ * @private
+ * @method _cacheRegion
+ * @description Get's the region and caches it, called from window.resize and when the cache is null
+ */
+ _cacheRegion: function() {
+ this._regionCache = this.get(CON_2_NODE).get('region');
+ },
+ /**
+ * @method getRegion
+ * @description Get the active region: viewport, node, custom region
+ * @param {Boolean} inc Include the node's height and width
+ * @return {Object}
+ */
+ getRegion: function(inc) {
+ var r = {}, oh = null, ow = null,
+ g = this.get('gutter'),
+ host = this.get(HOST);
+
+ if (this.get(CON_2_NODE)) {
+ if (!this._regionCache) {
+ Y.on('resize', Y.bind(this._cacheRegion, this), window);
+ this._cacheRegion();
+ }
+ r = Y.clone(this._regionCache);
+ } else if (this.get(CON_2_REGION)) {
+ r = this.get(CON_2_REGION);
+ } else if (this.get('constrain2view')) {
+ r = host.get(DRAG_NODE).get('viewportRegion');
+ } else {
+ return false;
+ }
+
+ Y.each(g, function(i, n) {
+ if ((n == RIGHT) || (n == BOTTOM)) {
+ r[n] -= i;
+ } else {
+ r[n] += i;
+ }
+ });
+ if (inc) {
+ oh = host.get(DRAG_NODE).get(OFFSET_HEIGHT);
+ ow = host.get(DRAG_NODE).get(OFFSET_WIDTH);
+ r[RIGHT] = r[RIGHT] - ow;
+ r[BOTTOM] = r[BOTTOM] - oh;
+ }
+ return r;
+ },
+ /**
+ * @private
+ * @method _checkRegion
+ * @description Check if xy is inside a given region, if not change to it be inside.
+ * @param {Array} _xy The XY to check if it's in the current region, if it isn't inside the region, it will reset the xy array to be inside the region.
+ * @return {Array} The new XY that is inside the region
+ */
+ _checkRegion: function(_xy) {
+ var oxy = _xy,
+ r = this.getRegion(),
+ host = this.get(HOST),
+ oh = host.get(DRAG_NODE).get(OFFSET_HEIGHT),
+ ow = host.get(DRAG_NODE).get(OFFSET_WIDTH);
+
+ if (oxy[1] > (r[BOTTOM] - oh)) {
+ _xy[1] = (r[BOTTOM] - oh);
+ }
+ if (r[TOP] > oxy[1]) {
+ _xy[1] = r[TOP];
+
+ }
+ if (oxy[0] > (r[RIGHT] - ow)) {
+ _xy[0] = (r[RIGHT] - ow);
+ }
+ if (r[LEFT] > oxy[0]) {
+ _xy[0] = r[LEFT];
+ }
+
+ return _xy;
+ },
+ /**
+ * @method inRegion
+ * @description Checks if the XY passed or the dragNode is inside the active region.
+ * @param {Array} xy Optional XY to check, if not supplied this.get('dragNode').getXY() is used.
+ * @return {Boolean} True if the XY is inside the region, false otherwise.
+ */
+ inRegion: function(xy) {
+ xy = xy || this.get(HOST).get(DRAG_NODE).getXY();
+
+ var _xy = this._checkRegion([xy[0], xy[1]]),
+ inside = false;
+ if ((xy[0] === _xy[0]) && (xy[1] === _xy[1])) {
+ inside = true;
+ }
+ return inside;
+ },
+ /**
+ * @method align
+ * @description Modifies the Drag.actXY method from the after drag:align event. This is where the constraining happens.
+ */
+ align: function() {
+ var host = this.get(HOST),
+ _xy = host.actXY,
+ r = this.getRegion(true);
+
+ if (this.get('stickX')) {
+ _xy[1] = (host.startXY[1] - host.deltaXY[1]);
+ }
+ if (this.get('stickY')) {
+ _xy[0] = (host.startXY[0] - host.deltaXY[0]);
+ }
+
+ if (r) {
+ _xy = this._checkRegion(_xy);
+ }
+
+ _xy = this._checkTicks(_xy, r);
+ host.actXY = _xy;
+ },
+ /**
+ * @private
+ * @method _checkTicks
+ * @description This method delegates the proper helper method for tick calculations
+ * @param {Array} xy The XY coords for the Drag
+ * @param {Object} r The optional region that we are bound to.
+ * @return {Array} The calced XY coords
+ */
+ _checkTicks: function(xy, r) {
+ var host = this.get(HOST),
+ lx = (host.startXY[0] - host.deltaXY[0]),
+ ly = (host.startXY[1] - host.deltaXY[1]),
+ xt = this.get('tickX'),
+ yt = this.get('tickY');
+ if (xt && !this.get(TICK_X_ARRAY)) {
+ xy[0] = DDM._calcTicks(xy[0], lx, xt, r[LEFT], r[RIGHT]);
+ }
+ if (yt && !this.get(TICK_Y_ARRAY)) {
+ xy[1] = DDM._calcTicks(xy[1], ly, yt, r[TOP], r[BOTTOM]);
+ }
+ if (this.get(TICK_X_ARRAY)) {
+ xy[0] = DDM._calcTickArray(xy[0], this.get(TICK_X_ARRAY), r[LEFT], r[RIGHT]);
+ }
+ if (this.get(TICK_Y_ARRAY)) {
+ xy[1] = DDM._calcTickArray(xy[1], this.get(TICK_Y_ARRAY), r[TOP], r[BOTTOM]);
+ }
+
+ return xy;
+ }
+ };
+
+ Y.namespace('Plugin');
+ Y.extend(C, Y.Base, proto);
+ Y.Plugin.DDConstrained = C;
+
+ Y.mix(DDM, {
+ /**
+ * @for DDM
+ * @namespace DD
+ * @private
+ * @method _calcTicks
+ * @description Helper method to calculate the tick offsets for a given position
+ * @param {Number} pos The current X or Y position
+ * @param {Number} start The start X or Y position
+ * @param {Number} tick The X or Y tick increment
+ * @param {Number} off1 The min offset that we can't pass (region)
+ * @param {Number} off2 The max offset that we can't pass (region)
+ * @return {Number} The new position based on the tick calculation
+ */
+ _calcTicks: function(pos, start, tick, off1, off2) {
+ var ix = ((pos - start) / tick),
+ min = Math.floor(ix),
+ max = Math.ceil(ix);
+ if ((min !== 0) || (max !== 0)) {
+ if ((ix >= min) && (ix <= max)) {
+ pos = (start + (tick * min));
+ if (off1 && off2) {
+ if (pos < off1) {
+ pos = (start + (tick * (min + 1)));
+ }
+ if (pos > off2) {
+ pos = (start + (tick * (min - 1)));
+ }
+ }
+ }
+ }
+ return pos;
+ },
+ /**
+ * @for DDM
+ * @namespace DD
+ * @private
+ * @method _calcTickArray
+ * @description This method is used with the tickXArray and tickYArray config options
+ * @param {Number} pos The current X or Y position
+ * @param {Number} ticks The array containing our custom tick positions.
+ * @param {Number} off1 The min offset that we can't pass (region)
+ * @param {Number} off2 The max offset that we can't pass (region)
+ * @return The tick position
+ */
+ _calcTickArray: function(pos, ticks, off1, off2) {
+ var i = 0, len = ticks.length, next = 0,
+ diff1, diff2, ret;
+
+ if (!ticks || (ticks.length === 0)) {
+ return pos;
+ } else if (ticks[0] >= pos) {
+ return ticks[0];
+ } else {
+ for (i = 0; i < len; i++) {
+ next = (i + 1);
+ if (ticks[next] && ticks[next] >= pos) {
+ diff1 = pos - ticks[i];
+ diff2 = ticks[next] - pos;
+ ret = (diff2 > diff1) ? ticks[i] : ticks[next];
+ if (off1 && off2) {
+ if (ret > off2) {
+ if (ticks[i]) {
+ ret = ticks[i];
+ } else {
+ ret = ticks[len - 1];
+ }
+ }
+ }
+ return ret;
+ }
+
+ }
+ return ticks[ticks.length - 1];
+ }
+ }
+ });
+
+
+
+
+}, '3.0.0' ,{requires:['dd-drag'], skinnable:false});
+YUI.add('dd-scroll', function(Y) {
+
+
+ /**
+ * The Drag & Drop Utility allows you to create a draggable interface efficiently, buffering you from browser-level abnormalities and enabling you to focus on the interesting logic surrounding your particular implementation. This component enables you to create a variety of standard draggable objects with just a few lines of code and then, using its extensive API, add your own specific implementation logic.
+ * @module dd
+ * @submodule dd-scroll
+ */
+ /**
+ * This class is the base scroller class used to create the Plugin.DDNodeScroll and Plugin.DDWinScroll.
+ * This class should not be called on it's own, it's designed to be a plugin.
+ * @class Scroll
+ * @extends Base
+ * @namespace DD
+ * @constructor
+ */
+
+ var S = function() {
+ S.superclass.constructor.apply(this, arguments);
+
+ },
+ HOST = 'host',
+ BUFFER = 'buffer',
+ PARENT_SCROLL = 'parentScroll',
+ WINDOW_SCROLL = 'windowScroll',
+ SCROLL_TOP = 'scrollTop',
+ SCROLL_LEFT = 'scrollLeft',
+ OFFSET_WIDTH = 'offsetWidth',
+ OFFSET_HEIGHT = 'offsetHeight';
+
+
+ S.ATTRS = {
+ /**
+ * @attribute parentScroll
+ * @description Internal config option to hold the node that we are scrolling. Should not be set by the developer.
+ * @type Node
+ */
+ parentScroll: {
+ value: false,
+ setter: function(node) {
+ if (node) {
+ return node;
+ }
+ return false;
+ }
+ },
+ /**
+ * @attribute buffer
+ * @description The number of pixels from the edge of the screen to turn on scrolling. Default: 30
+ * @type Number
+ */
+ buffer: {
+ value: 30
+ },
+ /**
+ * @attribute scrollDelay
+ * @description The number of milliseconds delay to pass to the auto scroller. Default: 235
+ * @type Number
+ */
+ scrollDelay: {
+ value: 235
+ },
+ /**
+ * @attribute host
+ * @description The host we are plugged into.
+ * @type Object
+ */
+ host: {
+ value: null
+ },
+ /**
+ * @attribute windowScroll
+ * @description Turn on window scroll support, default: false
+ * @type Boolean
+ */
+ windowScroll: {
+ value: false
+ },
+ /**
+ * @attribute vertical
+ * @description Allow vertical scrolling, default: true.
+ * @type Boolean
+ */
+ vertical: {
+ value: true
+ },
+ /**
+ * @attribute horizontal
+ * @description Allow horizontal scrolling, default: true.
+ * @type Boolean
+ */
+ horizontal: {
+ value: true
+ }
+ };
+
+ Y.extend(S, Y.Base, {
+ /**
+ * @private
+ * @property _scrolling
+ * @description Tells if we are actively scrolling or not.
+ * @type Boolean
+ */
+ _scrolling: null,
+ /**
+ * @private
+ * @property _vpRegionCache
+ * @description Cache of the Viewport dims.
+ * @type Object
+ */
+ _vpRegionCache: null,
+ /**
+ * @private
+ * @property _dimCache
+ * @description Cache of the dragNode dims.
+ * @type Object
+ */
+ _dimCache: null,
+ /**
+ * @private
+ * @property _scrollTimer
+ * @description Holder for the Timer object returned from Y.later.
+ * @type {Y.later}
+ */
+ _scrollTimer: null,
+ /**
+ * @private
+ * @method _getVPRegion
+ * @description Sets the _vpRegionCache property with an Object containing the dims from the viewport.
+ */
+ _getVPRegion: function() {
+ var r = {};
+ //if (!this._vpRegionCache) {
+ var n = this.get(PARENT_SCROLL),
+ b = this.get(BUFFER),
+ ws = this.get(WINDOW_SCROLL),
+ xy = ((ws) ? [] : n.getXY()),
+ w = ((ws) ? 'winWidth' : OFFSET_WIDTH),
+ h = ((ws) ? 'winHeight' : OFFSET_HEIGHT),
+ t = ((ws) ? n.get(SCROLL_TOP) : xy[1]),
+ l = ((ws) ? n.get(SCROLL_LEFT) : xy[0]);
+
+ r = {
+ top: t + b,
+ right: (n.get(w) + l) - b,
+ bottom: (n.get(h) + t) - b,
+ left: l + b
+ };
+ this._vpRegionCache = r;
+ //} else {
+ // r = this._vpRegionCache;
+ //}
+ return r;
+ },
+ initializer: function() {
+ var h = this.get(HOST);
+ h.after('drag:start', Y.bind(this.start, this));
+ h.after('drag:end', Y.bind(this.end, this));
+ h.on('drag:align', Y.bind(this.align, this));
+
+ //TODO - This doesn't work yet??
+ Y.get(window).on('scroll', Y.bind(function() {
+ this._vpRegionCache = null;
+ }, this));
+ },
+ /**
+ * @private
+ * @method _checkWinScroll
+ * @description Check to see if we need to fire the scroll timer. If scroll timer is running this will scroll the window.
+ * @param {Boolean} move Should we move the window. From Y.later
+ */
+ _checkWinScroll: function(move) {
+ var r = this._getVPRegion(),
+ ho = this.get(HOST),
+ ws = this.get(WINDOW_SCROLL),
+ xy = ho.lastXY,
+ scroll = false,
+ b = this.get(BUFFER),
+ win = this.get(PARENT_SCROLL),
+ sTop = win.get(SCROLL_TOP),
+ sLeft = win.get(SCROLL_LEFT),
+ w = this._dimCache.w,
+ h = this._dimCache.h,
+ bottom = xy[1] + h,
+ top = xy[1],
+ right = xy[0] + w,
+ left = xy[0],
+ nt = top,
+ nl = left,
+ st = sTop,
+ sl = sLeft;
+
+ if (this.get('horizontal')) {
+ if (left <= r.left) {
+ scroll = true;
+ nl = xy[0] - ((ws) ? b : 0);
+ sl = sLeft - b;
+ }
+ if (right >= r.right) {
+ scroll = true;
+ nl = xy[0] + ((ws) ? b : 0);
+ sl = sLeft + b;
+ }
+ }
+ if (this.get('vertical')) {
+ if (bottom >= r.bottom) {
+ scroll = true;
+ nt = xy[1] + ((ws) ? b : 0);
+ st = sTop + b;
+
+ }
+ if (top <= r.top) {
+ scroll = true;
+ nt = xy[1] - ((ws) ? b : 0);
+ st = sTop - b;
+ }
+ }
+
+ if (st < 0) {
+ st = 0;
+ nt = xy[1];
+ }
+
+ if (sl < 0) {
+ sl = 0;
+ nl = xy[0];
+ }
+
+ if (nt < 0) {
+ nt = xy[1];
+ }
+ if (nl < 0) {
+ nl = xy[0];
+ }
+ if (move) {
+ ho.actXY = [nl, nt];
+ ho._moveNode({ node: win, top: st, left: sl});
+ if (!st && !sl) {
+ this._cancelScroll();
+ }
+ } else {
+ if (scroll) {
+ this._initScroll();
+ } else {
+ this._cancelScroll();
+ }
+ }
+ },
+ /**
+ * @private
+ * @method _initScroll
+ * @description Cancel a previous scroll timer and init a new one.
+ */
+ _initScroll: function() {
+ this._cancelScroll();
+ this._scrollTimer = Y.Lang.later(this.get('scrollDelay'), this, this._checkWinScroll, [true], true);
+
+ },
+ /**
+ * @private
+ * @method _cancelScroll
+ * @description Cancel a currently running scroll timer.
+ */
+ _cancelScroll: function() {
+ this._scrolling = false;
+ if (this._scrollTimer) {
+ this._scrollTimer.cancel();
+ delete this._scrollTimer;
+ }
+ },
+ /**
+ * @method align
+ * @description Called from the drag:align event to determine if we need to scroll.
+ */
+ align: function(e) {
+ if (this._scrolling) {
+ this._cancelScroll();
+ e.preventDefault();
+ }
+ if (!this._scrolling) {
+ this._checkWinScroll();
+ }
+ },
+ /**
+ * @private
+ * @method _setDimCache
+ * @description Set the cache of the dragNode dims.
+ */
+ _setDimCache: function() {
+ var node = this.get(HOST).get('dragNode');
+ this._dimCache = {
+ h: node.get(OFFSET_HEIGHT),
+ w: node.get(OFFSET_WIDTH)
+ };
+ },
+ /**
+ * @method start
+ * @description Called from the drag:start event
+ */
+ start: function() {
+ this._setDimCache();
+ },
+ /**
+ * @method end
+ * @description Called from the drag:end event
+ */
+ end: function(xy) {
+ this._dimCache = null;
+ this._cancelScroll();
+ },
+ /**
+ * @method toString
+ * @description General toString method for logging
+ * @return String name for the object
+ */
+ toString: function() {
+ return S.NAME + ' #' + this.get('node').get('id');
+ }
+ });
+
+ Y.namespace('Plugin');
+
+
+ /**
+ * Extends the Scroll class to make the window scroll while dragging.
+ * @class DDWindowScroll
+ * @extends DD.Scroll
+ * @namespace Plugin
+ * @constructor
+ */
+ var WS = function() {
+ WS.superclass.constructor.apply(this, arguments);
+ };
+ WS.ATTRS = Y.merge(S.ATTRS, {
+ /**
+ * @attribute windowScroll
+ * @description Turn on window scroll support, default: true
+ * @type Boolean
+ */
+ windowScroll: {
+ value: true,
+ setter: function(scroll) {
+ if (scroll) {
+ this.set(PARENT_SCROLL, Y.get(window));
+ }
+ return scroll;
+ }
+ }
+ });
+ Y.extend(WS, S, {
+ //Shouldn't have to do this..
+ initializer: function() {
+ this.set('windowScroll', this.get('windowScroll'));
+ }
+ });
+ WS.NAME = WS.NS = 'winscroll';
+ Y.Plugin.DDWinScroll = WS;
+
+
+ /**
+ * Extends the Scroll class to make a parent node scroll while dragging.
+ * @class DDNodeScroll
+ * @extends DD.Scroll
+ * @namespace Plugin
+ * @constructor
+ */
+ var NS = function() {
+ NS.superclass.constructor.apply(this, arguments);
+
+ };
+ NS.ATTRS = Y.merge(S.ATTRS, {
+ /**
+ * @attribute node
+ * @description The node we want to scroll. Used to set the internal parentScroll attribute.
+ * @type Node
+ */
+ node: {
+ value: false,
+ setter: function(node) {
+ var n = Y.get(node);
+ if (!n) {
+ if (node !== false) {
+ Y.error('DDNodeScroll: Invalid Node Given: ' + node);
+ }
+ } else {
+ n = n.item(0);
+ this.set(PARENT_SCROLL, n);
+ }
+ return n;
+ }
+ }
+ });
+ Y.extend(NS, S, {
+ //Shouldn't have to do this..
+ initializer: function() {
+ this.set('node', this.get('node'));
+ }
+ });
+ NS.NAME = NS.NS = 'nodescroll';
+ Y.Plugin.DDNodeScroll = NS;
+
+ Y.DD.Scroll = S;
+
+
+
+}, '3.0.0' ,{skinnable:false, requires:['dd-drag'], optional:['dd-proxy']});
+YUI.add('dd-plugin', function(Y) {
+
+
+ /**
+ * This is a simple Drag plugin that can be attached to a Node via the plug method.
+ * @module dd
+ * @submodule dd-plugin
+ */
+ /**
+ * This is a simple Drag plugin that can be attached to a Node via the plug method.
+ * @class Drag
+ * @extends DD.Drag
+ * @constructor
+ * @namespace Plugin
+ */
+
+
+ var Drag = function(config) {
+ config.node = ((Y.Widget && config.host instanceof Y.Widget) ? config.host.get('boundingBox') : config.host);
+ Drag.superclass.constructor.apply(this, arguments);
+ };
+
+ /**
+ * @property NAME
+ * @description dd-plugin
+ * @type {String}
+ */
+ Drag.NAME = "dd-plugin";
+
+ /**
+ * @property NS
+ * @description The Drag instance will be placed on the Node instance under the dd namespace. It can be accessed via Node.dd;
+ * @type {String}
+ */
+ Drag.NS = "dd";
+
+
+ Y.extend(Drag, Y.DD.Drag);
+ Y.namespace('Plugin');
+ Y.Plugin.Drag = Drag;
+
+
+
+
+
+}, '3.0.0' ,{skinnable:false, requires:['dd-drag'], optional:['dd-constrain', 'dd-proxy']});
+YUI.add('dd-drop', function(Y) {
+
+
+ /**
+ * The Drag & Drop Utility allows you to create a draggable interface efficiently, buffering you from browser-level abnormalities and enabling you to focus on the interesting logic surrounding your particular implementation. This component enables you to create a variety of standard draggable objects with just a few lines of code and then, using its extensive API, add your own specific implementation logic.
+ * @module dd
+ * @submodule dd-drop
+ */
+ /**
+ * This class provides the ability to create a Drop Target.
+ * @class Drop
+ * @extends Base
+ * @constructor
+ * @namespace DD
+ */
+
+ var NODE = 'node',
+ DDM = Y.DD.DDM,
+ OFFSET_HEIGHT = 'offsetHeight',
+ OFFSET_WIDTH = 'offsetWidth',
+ /**
+ * @event drop:over
+ * @description Fires when a drag element is over this target.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_DROP_OVER = 'drop:over',
+ /**
+ * @event drop:enter
+ * @description Fires when a drag element enters this target.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_DROP_ENTER = 'drop:enter',
+ /**
+ * @event drop:exit
+ * @description Fires when a drag element exits this target.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_DROP_EXIT = 'drop:exit',
+
+ /**
+ * @event drop:hit
+ * @description Fires when a draggable node is dropped on this Drop Target. (Fired from dd-ddm-drop)
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+
+
+ Drop = function() {
+ this._lazyAddAttrs = false;
+ Drop.superclass.constructor.apply(this, arguments);
+
+
+ //DD init speed up.
+ Y.on('domready', Y.bind(function() {
+ Y.later(100, this, this._createShim);
+ }, this));
+ DDM._regTarget(this);
+
+ /* TODO
+ if (Dom.getStyle(this.el, 'position') == 'fixed') {
+ Event.on(window, 'scroll', function() {
+ this.activateShim();
+ }, this, true);
+ }
+ */
+ };
+
+ Drop.NAME = 'drop';
+
+ Drop.ATTRS = {
+ /**
+ * @attribute node
+ * @description Y.Node instanace to use as the element to make a Drop Target
+ * @type Node
+ */
+ node: {
+ setter: function(node) {
+ var n = Y.Node.get(node);
+ if (!n) {
+ Y.error('DD.Drop: Invalid Node Given: ' + node);
+ }
+ return n;
+ }
+ },
+ /**
+ * @attribute groups
+ * @description Array of groups to add this drop into.
+ * @type Array
+ */
+ groups: {
+ value: ['default'],
+ setter: function(g) {
+ this._groups = {};
+ Y.each(g, function(v, k) {
+ this._groups[v] = true;
+ }, this);
+ return g;
+ }
+ },
+ /**
+ * @attribute padding
+ * @description CSS style padding to make the Drop Target bigger than the node.
+ * @type String
+ */
+ padding: {
+ value: '0',
+ setter: function(p) {
+ return DDM.cssSizestoObject(p);
+ }
+ },
+ /**
+ * @attribute lock
+ * @description Set to lock this drop element.
+ * @type Boolean
+ */
+ lock: {
+ value: false,
+ setter: function(lock) {
+ if (lock) {
+ this.get(NODE).addClass(DDM.CSS_PREFIX + '-drop-locked');
+ } else {
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-locked');
+ }
+ return lock;
+ }
+ },
+ /**
+ * @attribute bubbles
+ * @description Controls the default bubble parent for this Drop instance. Default: Y.DD.DDM. Set to false to disable bubbling.
+ * @type Object
+ */
+ bubbles: {
+ writeOnce: true,
+ value: Y.DD.DDM
+ }
+ };
+
+ Y.extend(Drop, Y.Base, {
+ /**
+ * @private
+ * @method _createEvents
+ * @description This method creates all the events for this Event Target and publishes them so we get Event Bubbling.
+ */
+ _createEvents: function() {
+
+ var ev = [
+ EV_DROP_OVER,
+ EV_DROP_ENTER,
+ EV_DROP_EXIT,
+ 'drop:hit'
+ ];
+
+ Y.each(ev, function(v, k) {
+ this.publish(v, {
+ type: v,
+ emitFacade: true,
+ preventable: false,
+ bubbles: true,
+ queuable: false,
+ prefix: 'drop'
+ });
+ }, this);
+
+ if (this.get('bubbles')) {
+ this.addTarget(this.get('bubbles'));
+ }
+
+ },
+ /**
+ * @private
+ * @property _valid
+ * @description Flag for determining if the target is valid in this operation.
+ * @type Boolean
+ */
+ _valid: null,
+ /**
+ * @private
+ * @property _groups
+ * @description The groups this target belongs to.
+ * @type Array
+ */
+ _groups: null,
+ /**
+ * @property shim
+ * @description Node reference to the targets shim
+ * @type {Object}
+ */
+ shim: null,
+ /**
+ * @property region
+ * @description A region object associated with this target, used for checking regions while dragging.
+ * @type Object
+ */
+ region: null,
+ /**
+ * @property overTarget
+ * @description This flag is tripped when a drag element is over this target.
+ * @type Boolean
+ */
+ overTarget: null,
+ /**
+ * @method inGroup
+ * @description Check if this target is in one of the supplied groups.
+ * @param {Array} groups The groups to check against
+ * @return Boolean
+ */
+ inGroup: function(groups) {
+ this._valid = false;
+ var ret = false;
+ Y.each(groups, function(v, k) {
+ if (this._groups[v]) {
+ ret = true;
+ this._valid = true;
+ }
+ }, this);
+ return ret;
+ },
+ /**
+ * @private
+ * @method initializer
+ * @description Private lifecycle method
+ */
+ initializer: function() {
+ //this._createEvents();
+ Y.later(100, this, this._createEvents);
+
+ var node = this.get(NODE), id;
+ if (!node.get('id')) {
+ id = Y.stamp(node);
+ node.set('id', id);
+ }
+ node.addClass(DDM.CSS_PREFIX + '-drop');
+ //Shouldn't have to do this..
+ this.set('groups', this.get('groups'));
+ },
+ /**
+ * @private
+ * @method destructor
+ * @description Lifecycle destructor, unreg the drag from the DDM and remove listeners
+ */
+ destructor: function() {
+ DDM._unregTarget(this);
+ if (this.shim) {
+ this.shim.detachAll();
+ this.shim.get('parentNode').removeChild(this.shim);
+ this.shim = null;
+ }
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop');
+ this.detachAll();
+ },
+ /**
+ * @private
+ * @method _deactivateShim
+ * @description Removes classes from the target, resets some flags and sets the shims deactive position [-999, -999]
+ */
+ _deactivateShim: function() {
+ if (!this.shim) {
+ return false;
+ }
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-active-valid');
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-active-invalid');
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-over');
+ this.shim.setStyles({
+ top: '-999px',
+ left: '-999px',
+ zIndex: '1'
+ });
+ this.overTarget = false;
+ },
+ /**
+ * @private
+ * @method _activateShim
+ * @description Activates the shim and adds some interaction CSS classes
+ */
+ _activateShim: function() {
+ if (!DDM.activeDrag) {
+ return false; //Nothing is dragging, no reason to activate.
+ }
+ if (this.get(NODE) === DDM.activeDrag.get(NODE)) {
+ return false;
+ }
+ if (this.get('lock')) {
+ return false;
+ }
+ var node = this.get(NODE);
+ //TODO Visibility Check..
+ //if (this.inGroup(DDM.activeDrag.get('groups')) && this.get(NODE).isVisible()) {
+ if (this.inGroup(DDM.activeDrag.get('groups'))) {
+ node.removeClass(DDM.CSS_PREFIX + '-drop-active-invalid');
+ node.addClass(DDM.CSS_PREFIX + '-drop-active-valid');
+ DDM._addValid(this);
+ this.overTarget = false;
+ this.sizeShim();
+ } else {
+ DDM._removeValid(this);
+ node.removeClass(DDM.CSS_PREFIX + '-drop-active-valid');
+ node.addClass(DDM.CSS_PREFIX + '-drop-active-invalid');
+ }
+ },
+ /**
+ * @method sizeShim
+ * @description Positions and sizes the shim with the raw data from the node, this can be used to programatically adjust the Targets shim for Animation..
+ */
+ sizeShim: function() {
+ if (!DDM.activeDrag) {
+ return false; //Nothing is dragging, no reason to activate.
+ }
+ if (this.get(NODE) === DDM.activeDrag.get(NODE)) {
+ return false;
+ }
+ if (this.get('lock')) {
+ return false;
+ }
+ if (!this.shim) {
+ Y.later(100, this, this.sizeShim);
+ return false;
+ }
+ var node = this.get(NODE),
+ nh = node.get(OFFSET_HEIGHT),
+ nw = node.get(OFFSET_WIDTH),
+ xy = node.getXY(),
+ p = this.get('padding'),
+ dd, dH, dW;
+
+
+ //Apply padding
+ nw = nw + p.left + p.right;
+ nh = nh + p.top + p.bottom;
+ xy[0] = xy[0] - p.left;
+ xy[1] = xy[1] - p.top;
+
+
+ if (DDM.activeDrag.get('dragMode') === DDM.INTERSECT) {
+ //Intersect Mode, make the shim bigger
+ dd = DDM.activeDrag;
+ dH = dd.get(NODE).get(OFFSET_HEIGHT);
+ dW = dd.get(NODE).get(OFFSET_WIDTH);
+
+ nh = (nh + dH);
+ nw = (nw + dW);
+ xy[0] = xy[0] - (dW - dd.deltaXY[0]);
+ xy[1] = xy[1] - (dH - dd.deltaXY[1]);
+
+ }
+
+ //Set the style on the shim
+ this.shim.setStyles({
+ height: nh + 'px',
+ width: nw + 'px',
+ top: xy[1] + 'px',
+ left: xy[0] + 'px'
+ });
+
+ //Create the region to be used by intersect when a drag node is over us.
+ this.region = {
+ '0': xy[0],
+ '1': xy[1],
+ area: 0,
+ top: xy[1],
+ right: xy[0] + nw,
+ bottom: xy[1] + nh,
+ left: xy[0]
+ };
+ },
+ /**
+ * @private
+ * @method _createShim
+ * @description Creates the Target shim and adds it to the DDM's playground..
+ */
+ _createShim: function() {
+ //No playground, defer
+ if (!DDM._pg) {
+ Y.later(10, this, this._createShim);
+ return;
+ }
+ //Shim already here, cancel
+ if (this.shim) {
+ return;
+ }
+ var s = Y.Node.create('');
+
+ s.setStyles({
+ height: this.get(NODE).get(OFFSET_HEIGHT) + 'px',
+ width: this.get(NODE).get(OFFSET_WIDTH) + 'px',
+ backgroundColor: 'yellow',
+ opacity: '.5',
+ zIndex: '1',
+ overflow: 'hidden',
+ top: '-900px',
+ left: '-900px',
+ position: 'absolute'
+ });
+ DDM._pg.appendChild(s);
+ this.shim = s;
+
+ s.on('mouseover', Y.bind(this._handleOverEvent, this));
+ s.on('mouseout', Y.bind(this._handleOutEvent, this));
+ },
+ /**
+ * @private
+ * @method _handleOverTarget
+ * @description This handles the over target call made from this object or from the DDM
+ */
+ _handleTargetOver: function() {
+ if (DDM.isOverTarget(this)) {
+ this.get(NODE).addClass(DDM.CSS_PREFIX + '-drop-over');
+ DDM.activeDrop = this;
+ DDM.otherDrops[this] = this;
+ if (this.overTarget) {
+ DDM.activeDrag.fire('drag:over', { drop: this, drag: DDM.activeDrag });
+ this.fire(EV_DROP_OVER, { drop: this, drag: DDM.activeDrag });
+ } else {
+ this.overTarget = true;
+ this.fire(EV_DROP_ENTER, { drop: this, drag: DDM.activeDrag });
+ DDM.activeDrag.fire('drag:enter', { drop: this, drag: DDM.activeDrag });
+ DDM.activeDrag.get(NODE).addClass(DDM.CSS_PREFIX + '-drag-over');
+ //TODO - Is this needed??
+ //DDM._handleTargetOver();
+ }
+ } else {
+ this._handleOut();
+ }
+ },
+ /**
+ * @private
+ * @method _handleOverEvent
+ * @description Handles the mouseover DOM event on the Target Shim
+ */
+ _handleOverEvent: function() {
+ this.shim.setStyle('zIndex', '999');
+ DDM._addActiveShim(this);
+ },
+ /**
+ * @private
+ * @method _handleOutEvent
+ * @description Handles the mouseout DOM event on the Target Shim
+ */
+ _handleOutEvent: function() {
+ this.shim.setStyle('zIndex', '1');
+ DDM._removeActiveShim(this);
+ },
+ /**
+ * @private
+ * @method _handleOut
+ * @description Handles out of target calls/checks
+ */
+ _handleOut: function(force) {
+ if (!DDM.isOverTarget(this) || force) {
+ if (this.overTarget) {
+ this.overTarget = false;
+ if (!force) {
+ DDM._removeActiveShim(this);
+ }
+ if (DDM.activeDrag) {
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-over');
+ DDM.activeDrag.get(NODE).removeClass(DDM.CSS_PREFIX + '-drag-over');
+ this.fire(EV_DROP_EXIT);
+ DDM.activeDrag.fire('drag:exit', { drop: this });
+ delete DDM.otherDrops[this];
+ //if (DDM.activeDrop === this) {
+ // DDM.activeDrop = null;
+ //}
+ }
+ }
+ }
+ }
+ });
+
+ Y.DD.Drop = Drop;
+
+
+
+
+
+}, '3.0.0' ,{requires:['dd-ddm-drop', 'dd-drag'], skinnable:false});
+YUI.add('dd-drop-plugin', function(Y) {
+
+
+ /**
+ * This is a simple Drop plugin that can be attached to a Node via the plug method.
+ * @module dd
+ * @submodule dd-drop-plugin
+ */
+ /**
+ * This is a simple Drop plugin that can be attached to a Node via the plug method.
+ * @class Drop
+ * @extends DD.Drop
+ * @constructor
+ * @namespace Plugin
+ */
+
+
+ var Drop = function(config) {
+ config.node = config.host;
+ Drop.superclass.constructor.apply(this, arguments);
+ };
+
+ /**
+ * @property NAME
+ * @description dd-drop-plugin
+ * @type {String}
+ */
+ Drop.NAME = "dd-drop-plugin";
+ /**
+ * @property NS
+ * @description The Drop instance will be placed on the Node instance under the drop namespace. It can be accessed via Node.drop;
+ * @type {String}
+ */
+ Drop.NS = "drop";
+
+
+ Y.extend(Drop, Y.DD.Drop);
+ Y.namespace('Plugin');
+ Y.Plugin.Drop = Drop;
+
+
+
+
+
+}, '3.0.0' ,{requires:['dd-drop'], skinnable:false});
+
+
+YUI.add('dd', function(Y){}, '3.0.0' ,{use:['dd-ddm-base', 'dd-ddm', 'dd-ddm-drop', 'dd-drag', 'dd-proxy', 'dd-constrain', 'dd-plugin', 'dd-drop', 'dd-drop-plugin', 'dd-scroll'], skinnable:false});
+
diff --git a/lib/yui/3.0.0/dd/dd-drag-debug.js b/lib/yui/3.0.0/dd/dd-drag-debug.js
new file mode 100644
index 0000000000..41df2211de
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-drag-debug.js
@@ -0,0 +1,1100 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dd-drag', function(Y) {
+
+
+ /**
+ * The Drag & Drop Utility allows you to create a draggable interface efficiently, buffering you from browser-level abnormalities and enabling you to focus on the interesting logic surrounding your particular implementation. This component enables you to create a variety of standard draggable objects with just a few lines of code and then, using its extensive API, add your own specific implementation logic.
+ * @module dd
+ * @submodule dd-drag
+ */
+ /**
+ * This class provides the ability to drag a Node.
+ * @class Drag
+ * @extends Base
+ * @constructor
+ * @namespace DD
+ */
+
+ var DDM = Y.DD.DDM,
+ NODE = 'node',
+ DRAGGING = 'dragging',
+ DRAG_NODE = 'dragNode',
+ OFFSET_HEIGHT = 'offsetHeight',
+ OFFSET_WIDTH = 'offsetWidth',
+ MOUSE_UP = 'mouseup',
+ MOUSE_DOWN = 'mousedown',
+ DRAG_START = 'dragstart',
+ /**
+ * @event drag:mouseDown
+ * @description Handles the mousedown DOM event, checks to see if you have a valid handle then starts the drag timers.
+ * @preventable _defMouseDownFn
+ * @param {Event.Facade} ev The mousedown event.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_MOUSE_DOWN = 'drag:mouseDown',
+ /**
+ * @event drag:afterMouseDown
+ * @description Fires after the mousedown event has been cleared.
+ * @param {Event.Facade} ev The mousedown event.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_AFTER_MOUSE_DOWN = 'drag:afterMouseDown',
+ /**
+ * @event drag:removeHandle
+ * @description Fires after a handle is removed.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_REMOVE_HANDLE = 'drag:removeHandle',
+ /**
+ * @event drag:addHandle
+ * @description Fires after a handle is added.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_ADD_HANDLE = 'drag:addHandle',
+ /**
+ * @event drag:removeInvalid
+ * @description Fires after an invalid selector is removed.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_REMOVE_INVALID = 'drag:removeInvalid',
+ /**
+ * @event drag:addInvalid
+ * @description Fires after an invalid selector is added.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_ADD_INVALID = 'drag:addInvalid',
+ /**
+ * @event drag:start
+ * @description Fires at the start of a drag operation.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_START = 'drag:start',
+ /**
+ * @event drag:end
+ * @description Fires at the end of a drag operation.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_END = 'drag:end',
+ /**
+ * @event drag:drag
+ * @description Fires every mousemove during a drag operation.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_DRAG = 'drag:drag',
+ /**
+ * @event drag:align
+ * @preventable _defAlignFn
+ * @description Fires when this node is aligned.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_ALIGN = 'drag:align',
+ /**
+ * @event drag:over
+ * @description Fires when this node is over a Drop Target. (Fired from dd-drop)
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ /**
+ * @event drag:enter
+ * @description Fires when this node enters a Drop Target. (Fired from dd-drop)
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ /**
+ * @event drag:exit
+ * @description Fires when this node exits a Drop Target. (Fired from dd-drop)
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ /**
+ * @event drag:drophit
+ * @description Fires when this node is dropped on a valid Drop Target. (Fired from dd-ddm-drop)
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ /**
+ * @event drag:dropmiss
+ * @description Fires when this node is dropped on an invalid Drop Target. (Fired from dd-ddm-drop)
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+
+ Drag = function(o) {
+ this._lazyAddAttrs = false;
+ Drag.superclass.constructor.apply(this, arguments);
+
+ var valid = DDM._regDrag(this);
+ if (!valid) {
+ Y.error('Failed to register node, already in use: ' + o.node);
+ }
+ };
+
+ Drag.NAME = 'drag';
+
+ Drag.ATTRS = {
+ /**
+ * @attribute node
+ * @description Y.Node instanace to use as the element to initiate a drag operation
+ * @type Node
+ */
+ node: {
+ setter: function(node) {
+ var n = Y.get(node);
+ if (!n) {
+ Y.error('DD.Drag: Invalid Node Given: ' + node);
+ } else {
+ n = n.item(0);
+ }
+ return n;
+ }
+ },
+ /**
+ * @attribute dragNode
+ * @description Y.Node instanace to use as the draggable element, defaults to node
+ * @type Node
+ */
+ dragNode: {
+ setter: function(node) {
+ var n = Y.Node.get(node);
+ if (!n) {
+ Y.error('DD.Drag: Invalid dragNode Given: ' + node);
+ }
+ return n;
+ }
+ },
+ /**
+ * @attribute offsetNode
+ * @description Offset the drag element by the difference in cursor position: default true
+ * @type Boolean
+ */
+ offsetNode: {
+ value: true
+ },
+ /**
+ * @attribute clickPixelThresh
+ * @description The number of pixels to move to start a drag operation, default is 3.
+ * @type Number
+ */
+ clickPixelThresh: {
+ value: DDM.get('clickPixelThresh')
+ },
+ /**
+ * @attribute clickTimeThresh
+ * @description The number of milliseconds a mousedown has to pass to start a drag operation, default is 1000.
+ * @type Number
+ */
+ clickTimeThresh: {
+ value: DDM.get('clickTimeThresh')
+ },
+ /**
+ * @attribute lock
+ * @description Set to lock this drag element so that it can't be dragged: default false.
+ * @type Boolean
+ */
+ lock: {
+ value: false,
+ setter: function(lock) {
+ if (lock) {
+ this.get(NODE).addClass(DDM.CSS_PREFIX + '-locked');
+ } else {
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-locked');
+ }
+ return lock;
+ }
+ },
+ /**
+ * @attribute data
+ * @description A payload holder to store arbitrary data about this drag object, can be used to store any value.
+ * @type Mixed
+ */
+ data: {
+ value: false
+ },
+ /**
+ * @attribute move
+ * @description If this is false, the drag element will not move with the cursor: default true. Can be used to "resize" the element.
+ * @type Boolean
+ */
+ move: {
+ value: true
+ },
+ /**
+ * @attribute useShim
+ * @description Use the protective shim on all drag operations: default true. Only works with dd-ddm, not dd-ddm-base.
+ * @type Boolean
+ */
+ useShim: {
+ value: true
+ },
+ /**
+ * @attribute activeHandle
+ * @description This config option is set by Drag to inform you of which handle fired the drag event (in the case that there are several handles): default false.
+ * @type Node
+ */
+ activeHandle: {
+ value: false
+ },
+ /**
+ * @attribute primaryButtonOnly
+ * @description By default a drag operation will only begin if the mousedown occurred with the primary mouse button. Setting this to false will allow for all mousedown events to trigger a drag.
+ * @type Boolean
+ */
+ primaryButtonOnly: {
+ value: true
+ },
+ /**
+ * @attribute dragging
+ * @description This attribute is not meant to be used by the implementor, it is meant to be used as an Event tracker so you can listen for it to change.
+ * @type Boolean
+ */
+ dragging: {
+ value: false
+ },
+ parent: {
+ value: false
+ },
+ /**
+ * @attribute target
+ * @description This attribute only works if the dd-drop module has been loaded. It will make this node a drop target as well as draggable.
+ * @type Boolean
+ */
+ target: {
+ value: false,
+ setter: function(config) {
+ this._handleTarget(config);
+ return config;
+ }
+ },
+ /**
+ * @attribute dragMode
+ * @description This attribute only works if the dd-drop module is active. It will set the dragMode (point, intersect, strict) of this Drag instance.
+ * @type String
+ */
+ dragMode: {
+ value: null,
+ setter: function(mode) {
+ return DDM._setDragMode(mode);
+ }
+ },
+ /**
+ * @attribute groups
+ * @description Array of groups to add this drag into.
+ * @type Array
+ */
+ groups: {
+ value: ['default'],
+ getter: function() {
+ if (!this._groups) {
+ this._groups = {};
+ }
+ var ret = [];
+ Y.each(this._groups, function(v, k) {
+ ret[ret.length] = k;
+ });
+ return ret;
+ },
+ setter: function(g) {
+ this._groups = {};
+ Y.each(g, function(v, k) {
+ this._groups[v] = true;
+ }, this);
+ return g;
+ }
+ },
+ /**
+ * @attribute handles
+ * @description Array of valid handles to add. Adding something here will set all handles, even if previously added with addHandle
+ * @type Array
+ */
+ handles: {
+ value: null,
+ setter: function(g) {
+ if (g) {
+ this._handles = {};
+ Y.each(g, function(v, k) {
+ this._handles[v] = true;
+ }, this);
+ } else {
+ this._handles = null;
+ }
+ return g;
+ }
+ },
+ /**
+ * @attribute bubbles
+ * @description Controls the default bubble parent for this Drag instance. Default: Y.DD.DDM. Set to false to disable bubbling.
+ * @type Object
+ */
+ bubbles: {
+ writeOnce: true,
+ value: Y.DD.DDM
+ }
+ };
+
+ Y.extend(Drag, Y.Base, {
+ /**
+ * @method addToGroup
+ * @description Add this Drag instance to a group, this should be used for on-the-fly group additions.
+ * @param {String} g The group to add this Drag Instance to.
+ * @return {Self}
+ * @chainable
+ */
+ addToGroup: function(g) {
+ this._groups[g] = true;
+ DDM._activateTargets();
+ return this;
+ },
+ /**
+ * @method removeFromGroup
+ * @description Remove this Drag instance from a group, this should be used for on-the-fly group removals.
+ * @param {String} g The group to remove this Drag Instance from.
+ * @return {Self}
+ * @chainable
+ */
+ removeFromGroup: function(g) {
+ delete this._groups[g];
+ DDM._activateTargets();
+ return this;
+ },
+ /**
+ * @property target
+ * @description This will be a reference to the Drop instance associated with this drag if the target: true config attribute is set..
+ * @type {Object}
+ */
+ target: null,
+ /**
+ * @private
+ * @method _handleTarget
+ * @description Attribute handler for the target config attribute.
+ * @param {Boolean/Object}
+ * @return {Boolean/Object}
+ */
+ _handleTarget: function(config) {
+ if (Y.DD.Drop) {
+ if (config === false) {
+ if (this.target) {
+ DDM._unregTarget(this.target);
+ this.target = null;
+ }
+ return false;
+ } else {
+ if (!Y.Lang.isObject(config)) {
+ config = {};
+ }
+ config.bubbles = ('bubbles' in config) ? config.bubbles : this.get('bubbles');
+ config.node = this.get(NODE);
+ config.groups = config.groups || this.get('groups');
+ this.target = new Y.DD.Drop(config);
+ }
+ } else {
+ return false;
+ }
+ },
+ /**
+ * @private
+ * @property _groups
+ * @description Storage Array for the groups this drag belongs to.
+ * @type {Array}
+ */
+ _groups: null,
+ /**
+ * @private
+ * @method _createEvents
+ * @description This method creates all the events for this Event Target and publishes them so we get Event Bubbling.
+ */
+ _createEvents: function() {
+
+ this.publish(EV_MOUSE_DOWN, {
+ defaultFn: this._defMouseDownFn,
+ queuable: false,
+ emitFacade: true,
+ bubbles: true,
+ prefix: 'drag'
+ });
+
+ this.publish(EV_ALIGN, {
+ defaultFn: this._defAlignFn,
+ queuable: false,
+ emitFacade: true,
+ bubbles: true,
+ prefix: 'drag'
+ });
+
+ this.publish(EV_DRAG, {
+ defaultFn: this._defDragFn,
+ queuable: false,
+ emitFacade: true,
+ bubbles: true,
+ prefix: 'drag'
+ });
+
+ this.publish(EV_END, {
+ preventedFn: this._prevEndFn,
+ queuable: false,
+ emitFacade: true,
+ bubbles: true,
+ prefix: 'drag'
+ });
+
+ var ev = [
+ EV_AFTER_MOUSE_DOWN,
+ EV_REMOVE_HANDLE,
+ EV_ADD_HANDLE,
+ EV_REMOVE_INVALID,
+ EV_ADD_INVALID,
+ EV_START,
+ 'drag:drophit',
+ 'drag:dropmiss',
+ 'drag:over',
+ 'drag:enter',
+ 'drag:exit'
+ ];
+
+ Y.each(ev, function(v, k) {
+ this.publish(v, {
+ type: v,
+ emitFacade: true,
+ bubbles: true,
+ preventable: false,
+ queuable: false,
+ prefix: 'drag'
+ });
+ }, this);
+
+ if (this.get('bubbles')) {
+ this.addTarget(this.get('bubbles'));
+ }
+
+
+ },
+ /**
+ * @private
+ * @property _ev_md
+ * @description A private reference to the mousedown DOM event
+ * @type {Event.Facade}
+ */
+ _ev_md: null,
+ /**
+ * @private
+ * @property _startTime
+ * @description The getTime of the mousedown event. Not used, just here in case someone wants/needs to use it.
+ * @type Date
+ */
+ _startTime: null,
+ /**
+ * @private
+ * @property _endTime
+ * @description The getTime of the mouseup event. Not used, just here in case someone wants/needs to use it.
+ * @type Date
+ */
+ _endTime: null,
+ /**
+ * @private
+ * @property _handles
+ * @description A private hash of the valid drag handles
+ * @type {Object}
+ */
+ _handles: null,
+ /**
+ * @private
+ * @property _invalids
+ * @description A private hash of the invalid selector strings
+ * @type {Object}
+ */
+ _invalids: null,
+ /**
+ * @private
+ * @property _invalidsDefault
+ * @description A private hash of the default invalid selector strings: {'textarea': true, 'input': true, 'a': true, 'button': true, 'select': true}
+ * @type {Object}
+ */
+ _invalidsDefault: {'textarea': true, 'input': true, 'a': true, 'button': true, 'select': true },
+ /**
+ * @private
+ * @property _dragThreshMet
+ * @description Private flag to see if the drag threshhold was met
+ * @type {Boolean}
+ */
+ _dragThreshMet: null,
+ /**
+ * @private
+ * @property _fromTimeout
+ * @description Flag to determine if the drag operation came from a timeout
+ * @type {Boolean}
+ */
+ _fromTimeout: null,
+ /**
+ * @private
+ * @property _clickTimeout
+ * @description Holder for the setTimeout call
+ * @type {Boolean}
+ */
+ _clickTimeout: null,
+ /**
+ * @property deltaXY
+ * @description The offset of the mouse position to the element's position
+ * @type {Array}
+ */
+ deltaXY: null,
+ /**
+ * @property startXY
+ * @description The initial mouse position
+ * @type {Array}
+ */
+ startXY: null,
+ /**
+ * @property nodeXY
+ * @description The initial element position
+ * @type {Array}
+ */
+ nodeXY: null,
+ /**
+ * @property lastXY
+ * @description The position of the element as it's moving (for offset calculations)
+ * @type {Array}
+ */
+ lastXY: null,
+ /**
+ * @property actXY
+ * @description The xy that the node will be set to. Changing this will alter the position as it's dragged.
+ * @type {Array}
+ */
+ actXY: null,
+ /**
+ * @property realXY
+ * @description The real xy position of the node.
+ * @type {Array}
+ */
+ realXY: null,
+ /**
+ * @property mouseXY
+ * @description The XY coords of the mousemove
+ * @type {Array}
+ */
+ mouseXY: null,
+ /**
+ * @property region
+ * @description A region object associated with this drag, used for checking regions while dragging.
+ * @type Object
+ */
+ region: null,
+ /**
+ * @private
+ * @method _handleMouseUp
+ * @description Handler for the mouseup DOM event
+ * @param {Event.Facade}
+ */
+ _handleMouseUp: function(ev) {
+ this._fixIEMouseUp();
+ if (DDM.activeDrag) {
+ DDM._end();
+ }
+ },
+ /**
+ * @private
+ * @method _fixDragStart
+ * @description The function we use as the ondragstart handler when we start a drag in Internet Explorer. This keeps IE from blowing up on images as drag handles.
+ */
+ _fixDragStart: function(e) {
+ e.preventDefault();
+ },
+ /**
+ * @private
+ * @method _ieSelectFix
+ * @description The function we use as the onselectstart handler when we start a drag in Internet Explorer
+ */
+ _ieSelectFix: function() {
+ return false;
+ },
+ /**
+ * @private
+ * @property _ieSelectBack
+ * @description We will hold a copy of the current "onselectstart" method on this property, and reset it after we are done using it.
+ */
+ _ieSelectBack: null,
+ /**
+ * @private
+ * @method _fixIEMouseDown
+ * @description This method copies the onselectstart listner on the document to the _ieSelectFix property
+ */
+ _fixIEMouseDown: function() {
+ if (Y.UA.ie) {
+ this._ieSelectBack = Y.config.doc.body.onselectstart;
+ Y.config.doc.body.onselectstart = this._ieSelectFix;
+ }
+ },
+ /**
+ * @private
+ * @method _fixIEMouseUp
+ * @description This method copies the _ieSelectFix property back to the onselectstart listner on the document.
+ */
+ _fixIEMouseUp: function() {
+ if (Y.UA.ie) {
+ Y.config.doc.body.onselectstart = this._ieSelectBack;
+ }
+ },
+ /**
+ * @private
+ * @method _handleMouseDownEvent
+ * @description Handler for the mousedown DOM event
+ * @param {Event.Facade}
+ */
+ _handleMouseDownEvent: function(ev) {
+ this.fire(EV_MOUSE_DOWN, { ev: ev });
+ },
+ /**
+ * @private
+ * @method _defMouseDownFn
+ * @description Handler for the mousedown DOM event
+ * @param {Event.Facade}
+ */
+ _defMouseDownFn: function(e) {
+ var ev = e.ev;
+ this._dragThreshMet = false;
+ this._ev_md = ev;
+
+ if (this.get('primaryButtonOnly') && ev.button > 1) {
+ return false;
+ }
+ if (this.validClick(ev)) {
+ this._fixIEMouseDown();
+ ev.halt();
+ this._setStartPosition([ev.pageX, ev.pageY]);
+
+ DDM.activeDrag = this;
+
+ this._clickTimeout = Y.later(this.get('clickTimeThresh'), this, this._timeoutCheck);
+ }
+ this.fire(EV_AFTER_MOUSE_DOWN, { ev: ev });
+ },
+ /**
+ * @method validClick
+ * @description Method first checks to see if we have handles, if so it validates the click against the handle. Then if it finds a valid handle, it checks it against the invalid handles list. Returns true if a good handle was used, false otherwise.
+ * @param {Event.Facade}
+ * @return {Boolean}
+ */
+ validClick: function(ev) {
+ var r = false, n = false,
+ tar = ev.target,
+ hTest = null,
+ els = null,
+ set = false;
+ if (this._handles) {
+ Y.each(this._handles, function(i, n) {
+ if (Y.Lang.isString(n)) {
+ //Am I this or am I inside this
+ if (tar.test(n + ', ' + n + ' *') && !hTest) {
+ hTest = n;
+ r = true;
+ }
+ }
+ });
+ } else {
+ n = this.get(NODE)
+ if (n.contains(tar) || n.compareTo(tar)) {
+ r = true;
+ }
+ }
+ if (r) {
+ if (this._invalids) {
+ Y.each(this._invalids, function(i, n) {
+ if (Y.Lang.isString(n)) {
+ //Am I this or am I inside this
+ if (tar.test(n + ', ' + n + ' *')) {
+ r = false;
+ }
+ }
+ });
+ }
+ }
+ if (r) {
+ if (hTest) {
+ els = ev.currentTarget.queryAll(hTest);
+ set = false;
+ els.each(function(n, i) {
+ if ((n.contains(tar) || n.compareTo(tar)) && !set) {
+ set = true;
+ this.set('activeHandle', n);
+ }
+ }, this);
+ } else {
+ this.set('activeHandle', this.get(NODE));
+ }
+ }
+ return r;
+ },
+ /**
+ * @private
+ * @method _setStartPosition
+ * @description Sets the current position of the Element and calculates the offset
+ * @param {Array} xy The XY coords to set the position to.
+ */
+ _setStartPosition: function(xy) {
+ this.startXY = xy;
+
+ this.nodeXY = this.lastXY = this.realXY = this.get(NODE).getXY();
+
+ if (this.get('offsetNode')) {
+ this.deltaXY = [(this.startXY[0] - this.nodeXY[0]), (this.startXY[1] - this.nodeXY[1])];
+ } else {
+ this.deltaXY = [0, 0];
+ }
+ },
+ /**
+ * @private
+ * @method _timeoutCheck
+ * @description The method passed to setTimeout to determine if the clickTimeThreshold was met.
+ */
+ _timeoutCheck: function() {
+ if (!this.get('lock') && !this._dragThreshMet) {
+ this._fromTimeout = this._dragThreshMet = true;
+ this.start();
+ this._alignNode([this._ev_md.pageX, this._ev_md.pageY], true);
+ }
+ },
+ /**
+ * @method removeHandle
+ * @description Remove a Selector added by addHandle
+ * @param {String} str The selector for the handle to be removed.
+ * @return {Self}
+ * @chainable
+ */
+ removeHandle: function(str) {
+ if (this._handles[str]) {
+ delete this._handles[str];
+ this.fire(EV_REMOVE_HANDLE, { handle: str });
+ }
+ return this;
+ },
+ /**
+ * @method addHandle
+ * @description Add a handle to a drag element. Drag only initiates when a mousedown happens on this element.
+ * @param {String} str The selector to test for a valid handle. Must be a child of the element.
+ * @return {Self}
+ * @chainable
+ */
+ addHandle: function(str) {
+ if (!this._handles) {
+ this._handles = {};
+ }
+ if (Y.Lang.isString(str)) {
+ this._handles[str] = true;
+ this.fire(EV_ADD_HANDLE, { handle: str });
+ }
+ return this;
+ },
+ /**
+ * @method removeInvalid
+ * @description Remove an invalid handle added by addInvalid
+ * @param {String} str The invalid handle to remove from the internal list.
+ * @return {Self}
+ * @chainable
+ */
+ removeInvalid: function(str) {
+ if (this._invalids[str]) {
+ this._invalids[str] = null;
+ delete this._invalids[str];
+ this.fire(EV_REMOVE_INVALID, { handle: str });
+ }
+ return this;
+ },
+ /**
+ * @method addInvalid
+ * @description Add a selector string to test the handle against. If the test passes the drag operation will not continue.
+ * @param {String} str The selector to test against to determine if this is an invalid drag handle.
+ * @return {Self}
+ * @chainable
+ */
+ addInvalid: function(str) {
+ if (Y.Lang.isString(str)) {
+ this._invalids[str] = true;
+ this.fire(EV_ADD_INVALID, { handle: str });
+ }
+ return this;
+ },
+ /**
+ * @private
+ * @method initializer
+ * @description Internal init handler
+ */
+ initializer: function() {
+ this.get(NODE).dd = this;
+
+ if (!this.get(NODE).get('id')) {
+ var id = Y.stamp(this.get(NODE));
+ this.get(NODE).set('id', id);
+ }
+
+ this.actXY = [];
+
+ this._invalids = Y.clone(this._invalidsDefault, true);
+
+ this._createEvents();
+
+ if (!this.get(DRAG_NODE)) {
+ this.set(DRAG_NODE, this.get(NODE));
+ }
+
+ //Fix for #2528096
+ //Don't prep the DD instance until all plugins are loaded.
+ this.on('initializedChange', Y.bind(this._prep, this));
+
+ //Shouldn't have to do this..
+ this.set('groups', this.get('groups'));
+ },
+ /**
+ * @private
+ * @method _prep
+ * @description Attach event listners and add classname
+ */
+ _prep: function() {
+ this._dragThreshMet = false;
+ var node = this.get(NODE);
+ node.addClass(DDM.CSS_PREFIX + '-draggable');
+ node.on(MOUSE_DOWN, Y.bind(this._handleMouseDownEvent, this));
+ node.on(MOUSE_UP, Y.bind(this._handleMouseUp, this));
+ node.on(DRAG_START, Y.bind(this._fixDragStart, this));
+ },
+ /**
+ * @private
+ * @method _unprep
+ * @description Detach event listeners and remove classname
+ */
+ _unprep: function() {
+ var node = this.get(NODE);
+ node.removeClass(DDM.CSS_PREFIX + '-draggable');
+ node.detachAll();
+ },
+ /**
+ * @method start
+ * @description Starts the drag operation
+ * @return {Self}
+ * @chainable
+ */
+ start: function() {
+ if (!this.get('lock') && !this.get(DRAGGING)) {
+ var node = this.get(NODE), ow = node.get(OFFSET_WIDTH), oh = node.get(OFFSET_HEIGHT);
+ this._startTime = (new Date()).getTime();
+
+ DDM._start();
+ node.addClass(DDM.CSS_PREFIX + '-dragging');
+ this.fire(EV_START, {
+ pageX: this.nodeXY[0],
+ pageY: this.nodeXY[1],
+ startTime: this._startTime
+ });
+ var xy = this.nodeXY;
+
+
+ this.region = {
+ '0': xy[0],
+ '1': xy[1],
+ area: 0,
+ top: xy[1],
+ right: xy[0] + ow,
+ bottom: xy[1] + oh,
+ left: xy[0]
+ };
+ this.set(DRAGGING, true);
+ }
+ return this;
+ },
+ /**
+ * @method end
+ * @description Ends the drag operation
+ * @return {Self}
+ * @chainable
+ */
+ end: function() {
+ this._endTime = (new Date()).getTime();
+ if (this._clickTimeout) {
+ this._clickTimeout.cancel();
+ }
+ this._dragThreshMet = false;
+ this._fromTimeout = false;
+ if (!this.get('lock') && this.get(DRAGGING)) {
+ this.fire(EV_END, {
+ pageX: this.lastXY[0],
+ pageY: this.lastXY[1],
+ startTime: this._startTime,
+ endTime: this._endTime
+ });
+ }
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-dragging');
+ this.set(DRAGGING, false);
+ this.deltaXY = [0, 0];
+
+ return this;
+ },
+ /**
+ * @private
+ * @method _prevEndFn
+ * @description Handler for preventing the drag:end event. It will reset the node back to it's start position
+ */
+ _prevEndFn: function(e) {
+ //Bug #1852577
+ this.get(DRAG_NODE).setXY(this.nodeXY);
+ },
+ /**
+ * @private
+ * @method _align
+ * @description Calculates the offsets and set's the XY that the element will move to.
+ * @param {Array} xy The xy coords to align with.
+ */
+ _align: function(xy) {
+ this.fire(EV_ALIGN, {pageX: xy[0], pageY: xy[1] });
+ },
+ /**
+ * @private
+ * @method _defAlignFn
+ * @description Calculates the offsets and set's the XY that the element will move to.
+ * @param {Event.Facade} e The drag:align event.
+ */
+ _defAlignFn: function(e) {
+ this.actXY = [e.pageX - this.deltaXY[0], e.pageY - this.deltaXY[1]];
+ },
+ /**
+ * @private
+ * @method _alignNode
+ * @description This method performs the alignment before the element move.
+ * @param {Array} eXY The XY to move the element to, usually comes from the mousemove DOM event.
+ */
+ _alignNode: function(eXY) {
+ this._align(eXY);
+ this._moveNode();
+ },
+ /**
+ * @private
+ * @method _moveNode
+ * @description This method performs the actual element move.
+ */
+ _moveNode: function(scroll) {
+ //if (!this.get(DRAGGING)) {
+ // return;
+ //}
+ var diffXY = [], diffXY2 = [], startXY = this.nodeXY, xy = this.actXY;
+
+ diffXY[0] = (xy[0] - this.lastXY[0]);
+ diffXY[1] = (xy[1] - this.lastXY[1]);
+
+ diffXY2[0] = (xy[0] - this.nodeXY[0]);
+ diffXY2[1] = (xy[1] - this.nodeXY[1]);
+
+
+ this.region = {
+ '0': xy[0],
+ '1': xy[1],
+ area: 0,
+ top: xy[1],
+ right: xy[0] + this.get(DRAG_NODE).get(OFFSET_WIDTH),
+ bottom: xy[1] + this.get(DRAG_NODE).get(OFFSET_HEIGHT),
+ left: xy[0]
+ };
+
+ this.fire(EV_DRAG, {
+ pageX: xy[0],
+ pageY: xy[1],
+ scroll: scroll,
+ info: {
+ start: startXY,
+ xy: xy,
+ delta: diffXY,
+ offset: diffXY2
+ }
+ });
+
+ this.lastXY = xy;
+ },
+ /**
+ * @private
+ * @method _defDragFn
+ * @description Default function for drag:drag. Fired from _moveNode.
+ * @param {Event.Facade} ev The drag:drag event
+ */
+ _defDragFn: function(e) {
+ if (this.get('move')) {
+ if (e.scroll) {
+ e.scroll.node.set('scrollTop', e.scroll.top);
+ e.scroll.node.set('scrollLeft', e.scroll.left);
+ }
+ this.get(DRAG_NODE).setXY([e.pageX, e.pageY]);
+ this.realXY = [e.pageX, e.pageY];
+ }
+ },
+ /**
+ * @private
+ * @method _move
+ * @description Fired from DragDropMgr (DDM) on mousemove.
+ * @param {Event.Facade} ev The mousemove DOM event
+ */
+ _move: function(ev) {
+ if (this.get('lock')) {
+ return false;
+ } else {
+ this.mouseXY = [ev.pageX, ev.pageY];
+ if (!this._dragThreshMet) {
+ var diffX = Math.abs(this.startXY[0] - ev.pageX),
+ diffY = Math.abs(this.startXY[1] - ev.pageY);
+ if (diffX > this.get('clickPixelThresh') || diffY > this.get('clickPixelThresh')) {
+ this._dragThreshMet = true;
+ this.start();
+ this._alignNode([ev.pageX, ev.pageY]);
+ }
+ } else {
+ if (this._clickTimeout) {
+ this._clickTimeout.cancel();
+ }
+ this._alignNode([ev.pageX, ev.pageY]);
+ }
+ }
+ },
+ /**
+ * @method stopDrag
+ * @description Method will forcefully stop a drag operation. For example calling this from inside an ESC keypress handler will stop this drag.
+ * @return {Self}
+ * @chainable
+ */
+ stopDrag: function() {
+ if (this.get(DRAGGING)) {
+ DDM._end();
+ }
+ return this;
+ },
+ /**
+ * @private
+ * @method destructor
+ * @description Lifecycle destructor, unreg the drag from the DDM and remove listeners
+ */
+ destructor: function() {
+ this._unprep();
+ this.detachAll();
+ if (this.target) {
+ this.target.destroy();
+ }
+ DDM._unregDrag(this);
+ }
+ });
+ Y.namespace('DD');
+ Y.DD.Drag = Drag;
+
+
+
+
+
+}, '3.0.0' ,{requires:['dd-ddm-base'], skinnable:false});
diff --git a/lib/yui/3.0.0/dd/dd-drag-min.js b/lib/yui/3.0.0/dd/dd-drag-min.js
new file mode 100644
index 0000000000..e8af792dfa
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-drag-min.js
@@ -0,0 +1,9 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("dd-drag",function(D){var E=D.DD.DDM,U="node",G="dragging",N="dragNode",C="offsetHeight",K="offsetWidth",S="mouseup",P="mousedown",M="dragstart",H="drag:mouseDown",B="drag:afterMouseDown",F="drag:removeHandle",L="drag:addHandle",R="drag:removeInvalid",T="drag:addInvalid",J="drag:start",I="drag:end",O="drag:drag",Q="drag:align",A=function(W){this._lazyAddAttrs=false;A.superclass.constructor.apply(this,arguments);var V=E._regDrag(this);if(!V){D.error("Failed to register node, already in use: "+W.node);}};A.NAME="drag";A.ATTRS={node:{setter:function(V){var W=D.get(V);if(!W){D.error("DD.Drag: Invalid Node Given: "+V);}else{W=W.item(0);}return W;}},dragNode:{setter:function(V){var W=D.Node.get(V);if(!W){D.error("DD.Drag: Invalid dragNode Given: "+V);}return W;}},offsetNode:{value:true},clickPixelThresh:{value:E.get("clickPixelThresh")},clickTimeThresh:{value:E.get("clickTimeThresh")},lock:{value:false,setter:function(V){if(V){this.get(U).addClass(E.CSS_PREFIX+"-locked");}else{this.get(U).removeClass(E.CSS_PREFIX+"-locked");}return V;}},data:{value:false},move:{value:true},useShim:{value:true},activeHandle:{value:false},primaryButtonOnly:{value:true},dragging:{value:false},parent:{value:false},target:{value:false,setter:function(V){this._handleTarget(V);return V;}},dragMode:{value:null,setter:function(V){return E._setDragMode(V);}},groups:{value:["default"],getter:function(){if(!this._groups){this._groups={};}var V=[];D.each(this._groups,function(X,W){V[V.length]=W;});return V;},setter:function(V){this._groups={};D.each(V,function(X,W){this._groups[X]=true;},this);return V;}},handles:{value:null,setter:function(V){if(V){this._handles={};D.each(V,function(X,W){this._handles[X]=true;},this);}else{this._handles=null;}return V;}},bubbles:{writeOnce:true,value:D.DD.DDM}};D.extend(A,D.Base,{addToGroup:function(V){this._groups[V]=true;E._activateTargets();return this;},removeFromGroup:function(V){delete this._groups[V];E._activateTargets();return this;},target:null,_handleTarget:function(V){if(D.DD.Drop){if(V===false){if(this.target){E._unregTarget(this.target);this.target=null;}return false;}else{if(!D.Lang.isObject(V)){V={};}V.bubbles=("bubbles" in V)?V.bubbles:this.get("bubbles");V.node=this.get(U);V.groups=V.groups||this.get("groups");this.target=new D.DD.Drop(V);}}else{return false;}},_groups:null,_createEvents:function(){this.publish(H,{defaultFn:this._defMouseDownFn,queuable:false,emitFacade:true,bubbles:true,prefix:"drag"});this.publish(Q,{defaultFn:this._defAlignFn,queuable:false,emitFacade:true,bubbles:true,prefix:"drag"});this.publish(O,{defaultFn:this._defDragFn,queuable:false,emitFacade:true,bubbles:true,prefix:"drag"});this.publish(I,{preventedFn:this._prevEndFn,queuable:false,emitFacade:true,bubbles:true,prefix:"drag"});var V=[B,F,L,R,T,J,"drag:drophit","drag:dropmiss","drag:over","drag:enter","drag:exit"];D.each(V,function(X,W){this.publish(X,{type:X,emitFacade:true,bubbles:true,preventable:false,queuable:false,prefix:"drag"});},this);if(this.get("bubbles")){this.addTarget(this.get("bubbles"));}},_ev_md:null,_startTime:null,_endTime:null,_handles:null,_invalids:null,_invalidsDefault:{"textarea":true,"input":true,"a":true,"button":true,"select":true},_dragThreshMet:null,_fromTimeout:null,_clickTimeout:null,deltaXY:null,startXY:null,nodeXY:null,lastXY:null,actXY:null,realXY:null,mouseXY:null,region:null,_handleMouseUp:function(V){this._fixIEMouseUp();if(E.activeDrag){E._end();}},_fixDragStart:function(V){V.preventDefault();},_ieSelectFix:function(){return false;},_ieSelectBack:null,_fixIEMouseDown:function(){if(D.UA.ie){this._ieSelectBack=D.config.doc.body.onselectstart;D.config.doc.body.onselectstart=this._ieSelectFix;}},_fixIEMouseUp:function(){if(D.UA.ie){D.config.doc.body.onselectstart=this._ieSelectBack;}},_handleMouseDownEvent:function(V){this.fire(H,{ev:V});},_defMouseDownFn:function(W){var V=W.ev;this._dragThreshMet=false;this._ev_md=V;if(this.get("primaryButtonOnly")&&V.button>1){return false;}if(this.validClick(V)){this._fixIEMouseDown();V.halt();this._setStartPosition([V.pageX,V.pageY]);E.activeDrag=this;this._clickTimeout=D.later(this.get("clickTimeThresh"),this,this._timeoutCheck);}this.fire(B,{ev:V});},validClick:function(Z){var Y=false,b=false,V=Z.target,X=null,W=null,a=false;if(this._handles){D.each(this._handles,function(c,d){if(D.Lang.isString(d)){if(V.test(d+", "+d+" *")&&!X){X=d;Y=true;}}});}else{b=this.get(U);if(b.contains(V)||b.compareTo(V)){Y=true;}}if(Y){if(this._invalids){D.each(this._invalids,function(c,d){if(D.Lang.isString(d)){if(V.test(d+", "+d+" *")){Y=false;}}});}}if(Y){if(X){W=Z.currentTarget.queryAll(X);a=false;W.each(function(d,c){if((d.contains(V)||d.compareTo(V))&&!a){a=true;this.set("activeHandle",d);}},this);}else{this.set("activeHandle",this.get(U));}}return Y;},_setStartPosition:function(V){this.startXY=V;this.nodeXY=this.lastXY=this.realXY=this.get(U).getXY();if(this.get("offsetNode")){this.deltaXY=[(this.startXY[0]-this.nodeXY[0]),(this.startXY[1]-this.nodeXY[1])];}else{this.deltaXY=[0,0];}},_timeoutCheck:function(){if(!this.get("lock")&&!this._dragThreshMet){this._fromTimeout=this._dragThreshMet=true;this.start();this._alignNode([this._ev_md.pageX,this._ev_md.pageY],true);}},removeHandle:function(V){if(this._handles[V]){delete this._handles[V];this.fire(F,{handle:V});}return this;},addHandle:function(V){if(!this._handles){this._handles={};}if(D.Lang.isString(V)){this._handles[V]=true;this.fire(L,{handle:V});}return this;},removeInvalid:function(V){if(this._invalids[V]){this._invalids[V]=null;delete this._invalids[V];this.fire(R,{handle:V});}return this;},addInvalid:function(V){if(D.Lang.isString(V)){this._invalids[V]=true;this.fire(T,{handle:V});}return this;},initializer:function(){this.get(U).dd=this;if(!this.get(U).get("id")){var V=D.stamp(this.get(U));this.get(U).set("id",V);}this.actXY=[];this._invalids=D.clone(this._invalidsDefault,true);this._createEvents();if(!this.get(N)){this.set(N,this.get(U));}this.on("initializedChange",D.bind(this._prep,this));
+this.set("groups",this.get("groups"));},_prep:function(){this._dragThreshMet=false;var V=this.get(U);V.addClass(E.CSS_PREFIX+"-draggable");V.on(P,D.bind(this._handleMouseDownEvent,this));V.on(S,D.bind(this._handleMouseUp,this));V.on(M,D.bind(this._fixDragStart,this));},_unprep:function(){var V=this.get(U);V.removeClass(E.CSS_PREFIX+"-draggable");V.detachAll();},start:function(){if(!this.get("lock")&&!this.get(G)){var W=this.get(U),V=W.get(K),X=W.get(C);this._startTime=(new Date()).getTime();E._start();W.addClass(E.CSS_PREFIX+"-dragging");this.fire(J,{pageX:this.nodeXY[0],pageY:this.nodeXY[1],startTime:this._startTime});var Y=this.nodeXY;this.region={"0":Y[0],"1":Y[1],area:0,top:Y[1],right:Y[0]+V,bottom:Y[1]+X,left:Y[0]};this.set(G,true);}return this;},end:function(){this._endTime=(new Date()).getTime();if(this._clickTimeout){this._clickTimeout.cancel();}this._dragThreshMet=false;this._fromTimeout=false;if(!this.get("lock")&&this.get(G)){this.fire(I,{pageX:this.lastXY[0],pageY:this.lastXY[1],startTime:this._startTime,endTime:this._endTime});}this.get(U).removeClass(E.CSS_PREFIX+"-dragging");this.set(G,false);this.deltaXY=[0,0];return this;},_prevEndFn:function(V){this.get(N).setXY(this.nodeXY);},_align:function(V){this.fire(Q,{pageX:V[0],pageY:V[1]});},_defAlignFn:function(V){this.actXY=[V.pageX-this.deltaXY[0],V.pageY-this.deltaXY[1]];},_alignNode:function(V){this._align(V);this._moveNode();},_moveNode:function(V){var W=[],X=[],Z=this.nodeXY,Y=this.actXY;W[0]=(Y[0]-this.lastXY[0]);W[1]=(Y[1]-this.lastXY[1]);X[0]=(Y[0]-this.nodeXY[0]);X[1]=(Y[1]-this.nodeXY[1]);this.region={"0":Y[0],"1":Y[1],area:0,top:Y[1],right:Y[0]+this.get(N).get(K),bottom:Y[1]+this.get(N).get(C),left:Y[0]};this.fire(O,{pageX:Y[0],pageY:Y[1],scroll:V,info:{start:Z,xy:Y,delta:W,offset:X}});this.lastXY=Y;},_defDragFn:function(V){if(this.get("move")){if(V.scroll){V.scroll.node.set("scrollTop",V.scroll.top);V.scroll.node.set("scrollLeft",V.scroll.left);}this.get(N).setXY([V.pageX,V.pageY]);this.realXY=[V.pageX,V.pageY];}},_move:function(X){if(this.get("lock")){return false;}else{this.mouseXY=[X.pageX,X.pageY];if(!this._dragThreshMet){var W=Math.abs(this.startXY[0]-X.pageX),V=Math.abs(this.startXY[1]-X.pageY);if(W>this.get("clickPixelThresh")||V>this.get("clickPixelThresh")){this._dragThreshMet=true;this.start();this._alignNode([X.pageX,X.pageY]);}}else{if(this._clickTimeout){this._clickTimeout.cancel();}this._alignNode([X.pageX,X.pageY]);}}},stopDrag:function(){if(this.get(G)){E._end();}return this;},destructor:function(){this._unprep();this.detachAll();if(this.target){this.target.destroy();}E._unregDrag(this);}});D.namespace("DD");D.DD.Drag=A;},"3.0.0",{requires:["dd-ddm-base"],skinnable:false});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/dd/dd-drag.js b/lib/yui/3.0.0/dd/dd-drag.js
new file mode 100644
index 0000000000..41df2211de
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-drag.js
@@ -0,0 +1,1100 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dd-drag', function(Y) {
+
+
+ /**
+ * The Drag & Drop Utility allows you to create a draggable interface efficiently, buffering you from browser-level abnormalities and enabling you to focus on the interesting logic surrounding your particular implementation. This component enables you to create a variety of standard draggable objects with just a few lines of code and then, using its extensive API, add your own specific implementation logic.
+ * @module dd
+ * @submodule dd-drag
+ */
+ /**
+ * This class provides the ability to drag a Node.
+ * @class Drag
+ * @extends Base
+ * @constructor
+ * @namespace DD
+ */
+
+ var DDM = Y.DD.DDM,
+ NODE = 'node',
+ DRAGGING = 'dragging',
+ DRAG_NODE = 'dragNode',
+ OFFSET_HEIGHT = 'offsetHeight',
+ OFFSET_WIDTH = 'offsetWidth',
+ MOUSE_UP = 'mouseup',
+ MOUSE_DOWN = 'mousedown',
+ DRAG_START = 'dragstart',
+ /**
+ * @event drag:mouseDown
+ * @description Handles the mousedown DOM event, checks to see if you have a valid handle then starts the drag timers.
+ * @preventable _defMouseDownFn
+ * @param {Event.Facade} ev The mousedown event.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_MOUSE_DOWN = 'drag:mouseDown',
+ /**
+ * @event drag:afterMouseDown
+ * @description Fires after the mousedown event has been cleared.
+ * @param {Event.Facade} ev The mousedown event.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_AFTER_MOUSE_DOWN = 'drag:afterMouseDown',
+ /**
+ * @event drag:removeHandle
+ * @description Fires after a handle is removed.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_REMOVE_HANDLE = 'drag:removeHandle',
+ /**
+ * @event drag:addHandle
+ * @description Fires after a handle is added.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_ADD_HANDLE = 'drag:addHandle',
+ /**
+ * @event drag:removeInvalid
+ * @description Fires after an invalid selector is removed.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_REMOVE_INVALID = 'drag:removeInvalid',
+ /**
+ * @event drag:addInvalid
+ * @description Fires after an invalid selector is added.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_ADD_INVALID = 'drag:addInvalid',
+ /**
+ * @event drag:start
+ * @description Fires at the start of a drag operation.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_START = 'drag:start',
+ /**
+ * @event drag:end
+ * @description Fires at the end of a drag operation.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_END = 'drag:end',
+ /**
+ * @event drag:drag
+ * @description Fires every mousemove during a drag operation.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_DRAG = 'drag:drag',
+ /**
+ * @event drag:align
+ * @preventable _defAlignFn
+ * @description Fires when this node is aligned.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_ALIGN = 'drag:align',
+ /**
+ * @event drag:over
+ * @description Fires when this node is over a Drop Target. (Fired from dd-drop)
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ /**
+ * @event drag:enter
+ * @description Fires when this node enters a Drop Target. (Fired from dd-drop)
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ /**
+ * @event drag:exit
+ * @description Fires when this node exits a Drop Target. (Fired from dd-drop)
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ /**
+ * @event drag:drophit
+ * @description Fires when this node is dropped on a valid Drop Target. (Fired from dd-ddm-drop)
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ /**
+ * @event drag:dropmiss
+ * @description Fires when this node is dropped on an invalid Drop Target. (Fired from dd-ddm-drop)
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+
+ Drag = function(o) {
+ this._lazyAddAttrs = false;
+ Drag.superclass.constructor.apply(this, arguments);
+
+ var valid = DDM._regDrag(this);
+ if (!valid) {
+ Y.error('Failed to register node, already in use: ' + o.node);
+ }
+ };
+
+ Drag.NAME = 'drag';
+
+ Drag.ATTRS = {
+ /**
+ * @attribute node
+ * @description Y.Node instanace to use as the element to initiate a drag operation
+ * @type Node
+ */
+ node: {
+ setter: function(node) {
+ var n = Y.get(node);
+ if (!n) {
+ Y.error('DD.Drag: Invalid Node Given: ' + node);
+ } else {
+ n = n.item(0);
+ }
+ return n;
+ }
+ },
+ /**
+ * @attribute dragNode
+ * @description Y.Node instanace to use as the draggable element, defaults to node
+ * @type Node
+ */
+ dragNode: {
+ setter: function(node) {
+ var n = Y.Node.get(node);
+ if (!n) {
+ Y.error('DD.Drag: Invalid dragNode Given: ' + node);
+ }
+ return n;
+ }
+ },
+ /**
+ * @attribute offsetNode
+ * @description Offset the drag element by the difference in cursor position: default true
+ * @type Boolean
+ */
+ offsetNode: {
+ value: true
+ },
+ /**
+ * @attribute clickPixelThresh
+ * @description The number of pixels to move to start a drag operation, default is 3.
+ * @type Number
+ */
+ clickPixelThresh: {
+ value: DDM.get('clickPixelThresh')
+ },
+ /**
+ * @attribute clickTimeThresh
+ * @description The number of milliseconds a mousedown has to pass to start a drag operation, default is 1000.
+ * @type Number
+ */
+ clickTimeThresh: {
+ value: DDM.get('clickTimeThresh')
+ },
+ /**
+ * @attribute lock
+ * @description Set to lock this drag element so that it can't be dragged: default false.
+ * @type Boolean
+ */
+ lock: {
+ value: false,
+ setter: function(lock) {
+ if (lock) {
+ this.get(NODE).addClass(DDM.CSS_PREFIX + '-locked');
+ } else {
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-locked');
+ }
+ return lock;
+ }
+ },
+ /**
+ * @attribute data
+ * @description A payload holder to store arbitrary data about this drag object, can be used to store any value.
+ * @type Mixed
+ */
+ data: {
+ value: false
+ },
+ /**
+ * @attribute move
+ * @description If this is false, the drag element will not move with the cursor: default true. Can be used to "resize" the element.
+ * @type Boolean
+ */
+ move: {
+ value: true
+ },
+ /**
+ * @attribute useShim
+ * @description Use the protective shim on all drag operations: default true. Only works with dd-ddm, not dd-ddm-base.
+ * @type Boolean
+ */
+ useShim: {
+ value: true
+ },
+ /**
+ * @attribute activeHandle
+ * @description This config option is set by Drag to inform you of which handle fired the drag event (in the case that there are several handles): default false.
+ * @type Node
+ */
+ activeHandle: {
+ value: false
+ },
+ /**
+ * @attribute primaryButtonOnly
+ * @description By default a drag operation will only begin if the mousedown occurred with the primary mouse button. Setting this to false will allow for all mousedown events to trigger a drag.
+ * @type Boolean
+ */
+ primaryButtonOnly: {
+ value: true
+ },
+ /**
+ * @attribute dragging
+ * @description This attribute is not meant to be used by the implementor, it is meant to be used as an Event tracker so you can listen for it to change.
+ * @type Boolean
+ */
+ dragging: {
+ value: false
+ },
+ parent: {
+ value: false
+ },
+ /**
+ * @attribute target
+ * @description This attribute only works if the dd-drop module has been loaded. It will make this node a drop target as well as draggable.
+ * @type Boolean
+ */
+ target: {
+ value: false,
+ setter: function(config) {
+ this._handleTarget(config);
+ return config;
+ }
+ },
+ /**
+ * @attribute dragMode
+ * @description This attribute only works if the dd-drop module is active. It will set the dragMode (point, intersect, strict) of this Drag instance.
+ * @type String
+ */
+ dragMode: {
+ value: null,
+ setter: function(mode) {
+ return DDM._setDragMode(mode);
+ }
+ },
+ /**
+ * @attribute groups
+ * @description Array of groups to add this drag into.
+ * @type Array
+ */
+ groups: {
+ value: ['default'],
+ getter: function() {
+ if (!this._groups) {
+ this._groups = {};
+ }
+ var ret = [];
+ Y.each(this._groups, function(v, k) {
+ ret[ret.length] = k;
+ });
+ return ret;
+ },
+ setter: function(g) {
+ this._groups = {};
+ Y.each(g, function(v, k) {
+ this._groups[v] = true;
+ }, this);
+ return g;
+ }
+ },
+ /**
+ * @attribute handles
+ * @description Array of valid handles to add. Adding something here will set all handles, even if previously added with addHandle
+ * @type Array
+ */
+ handles: {
+ value: null,
+ setter: function(g) {
+ if (g) {
+ this._handles = {};
+ Y.each(g, function(v, k) {
+ this._handles[v] = true;
+ }, this);
+ } else {
+ this._handles = null;
+ }
+ return g;
+ }
+ },
+ /**
+ * @attribute bubbles
+ * @description Controls the default bubble parent for this Drag instance. Default: Y.DD.DDM. Set to false to disable bubbling.
+ * @type Object
+ */
+ bubbles: {
+ writeOnce: true,
+ value: Y.DD.DDM
+ }
+ };
+
+ Y.extend(Drag, Y.Base, {
+ /**
+ * @method addToGroup
+ * @description Add this Drag instance to a group, this should be used for on-the-fly group additions.
+ * @param {String} g The group to add this Drag Instance to.
+ * @return {Self}
+ * @chainable
+ */
+ addToGroup: function(g) {
+ this._groups[g] = true;
+ DDM._activateTargets();
+ return this;
+ },
+ /**
+ * @method removeFromGroup
+ * @description Remove this Drag instance from a group, this should be used for on-the-fly group removals.
+ * @param {String} g The group to remove this Drag Instance from.
+ * @return {Self}
+ * @chainable
+ */
+ removeFromGroup: function(g) {
+ delete this._groups[g];
+ DDM._activateTargets();
+ return this;
+ },
+ /**
+ * @property target
+ * @description This will be a reference to the Drop instance associated with this drag if the target: true config attribute is set..
+ * @type {Object}
+ */
+ target: null,
+ /**
+ * @private
+ * @method _handleTarget
+ * @description Attribute handler for the target config attribute.
+ * @param {Boolean/Object}
+ * @return {Boolean/Object}
+ */
+ _handleTarget: function(config) {
+ if (Y.DD.Drop) {
+ if (config === false) {
+ if (this.target) {
+ DDM._unregTarget(this.target);
+ this.target = null;
+ }
+ return false;
+ } else {
+ if (!Y.Lang.isObject(config)) {
+ config = {};
+ }
+ config.bubbles = ('bubbles' in config) ? config.bubbles : this.get('bubbles');
+ config.node = this.get(NODE);
+ config.groups = config.groups || this.get('groups');
+ this.target = new Y.DD.Drop(config);
+ }
+ } else {
+ return false;
+ }
+ },
+ /**
+ * @private
+ * @property _groups
+ * @description Storage Array for the groups this drag belongs to.
+ * @type {Array}
+ */
+ _groups: null,
+ /**
+ * @private
+ * @method _createEvents
+ * @description This method creates all the events for this Event Target and publishes them so we get Event Bubbling.
+ */
+ _createEvents: function() {
+
+ this.publish(EV_MOUSE_DOWN, {
+ defaultFn: this._defMouseDownFn,
+ queuable: false,
+ emitFacade: true,
+ bubbles: true,
+ prefix: 'drag'
+ });
+
+ this.publish(EV_ALIGN, {
+ defaultFn: this._defAlignFn,
+ queuable: false,
+ emitFacade: true,
+ bubbles: true,
+ prefix: 'drag'
+ });
+
+ this.publish(EV_DRAG, {
+ defaultFn: this._defDragFn,
+ queuable: false,
+ emitFacade: true,
+ bubbles: true,
+ prefix: 'drag'
+ });
+
+ this.publish(EV_END, {
+ preventedFn: this._prevEndFn,
+ queuable: false,
+ emitFacade: true,
+ bubbles: true,
+ prefix: 'drag'
+ });
+
+ var ev = [
+ EV_AFTER_MOUSE_DOWN,
+ EV_REMOVE_HANDLE,
+ EV_ADD_HANDLE,
+ EV_REMOVE_INVALID,
+ EV_ADD_INVALID,
+ EV_START,
+ 'drag:drophit',
+ 'drag:dropmiss',
+ 'drag:over',
+ 'drag:enter',
+ 'drag:exit'
+ ];
+
+ Y.each(ev, function(v, k) {
+ this.publish(v, {
+ type: v,
+ emitFacade: true,
+ bubbles: true,
+ preventable: false,
+ queuable: false,
+ prefix: 'drag'
+ });
+ }, this);
+
+ if (this.get('bubbles')) {
+ this.addTarget(this.get('bubbles'));
+ }
+
+
+ },
+ /**
+ * @private
+ * @property _ev_md
+ * @description A private reference to the mousedown DOM event
+ * @type {Event.Facade}
+ */
+ _ev_md: null,
+ /**
+ * @private
+ * @property _startTime
+ * @description The getTime of the mousedown event. Not used, just here in case someone wants/needs to use it.
+ * @type Date
+ */
+ _startTime: null,
+ /**
+ * @private
+ * @property _endTime
+ * @description The getTime of the mouseup event. Not used, just here in case someone wants/needs to use it.
+ * @type Date
+ */
+ _endTime: null,
+ /**
+ * @private
+ * @property _handles
+ * @description A private hash of the valid drag handles
+ * @type {Object}
+ */
+ _handles: null,
+ /**
+ * @private
+ * @property _invalids
+ * @description A private hash of the invalid selector strings
+ * @type {Object}
+ */
+ _invalids: null,
+ /**
+ * @private
+ * @property _invalidsDefault
+ * @description A private hash of the default invalid selector strings: {'textarea': true, 'input': true, 'a': true, 'button': true, 'select': true}
+ * @type {Object}
+ */
+ _invalidsDefault: {'textarea': true, 'input': true, 'a': true, 'button': true, 'select': true },
+ /**
+ * @private
+ * @property _dragThreshMet
+ * @description Private flag to see if the drag threshhold was met
+ * @type {Boolean}
+ */
+ _dragThreshMet: null,
+ /**
+ * @private
+ * @property _fromTimeout
+ * @description Flag to determine if the drag operation came from a timeout
+ * @type {Boolean}
+ */
+ _fromTimeout: null,
+ /**
+ * @private
+ * @property _clickTimeout
+ * @description Holder for the setTimeout call
+ * @type {Boolean}
+ */
+ _clickTimeout: null,
+ /**
+ * @property deltaXY
+ * @description The offset of the mouse position to the element's position
+ * @type {Array}
+ */
+ deltaXY: null,
+ /**
+ * @property startXY
+ * @description The initial mouse position
+ * @type {Array}
+ */
+ startXY: null,
+ /**
+ * @property nodeXY
+ * @description The initial element position
+ * @type {Array}
+ */
+ nodeXY: null,
+ /**
+ * @property lastXY
+ * @description The position of the element as it's moving (for offset calculations)
+ * @type {Array}
+ */
+ lastXY: null,
+ /**
+ * @property actXY
+ * @description The xy that the node will be set to. Changing this will alter the position as it's dragged.
+ * @type {Array}
+ */
+ actXY: null,
+ /**
+ * @property realXY
+ * @description The real xy position of the node.
+ * @type {Array}
+ */
+ realXY: null,
+ /**
+ * @property mouseXY
+ * @description The XY coords of the mousemove
+ * @type {Array}
+ */
+ mouseXY: null,
+ /**
+ * @property region
+ * @description A region object associated with this drag, used for checking regions while dragging.
+ * @type Object
+ */
+ region: null,
+ /**
+ * @private
+ * @method _handleMouseUp
+ * @description Handler for the mouseup DOM event
+ * @param {Event.Facade}
+ */
+ _handleMouseUp: function(ev) {
+ this._fixIEMouseUp();
+ if (DDM.activeDrag) {
+ DDM._end();
+ }
+ },
+ /**
+ * @private
+ * @method _fixDragStart
+ * @description The function we use as the ondragstart handler when we start a drag in Internet Explorer. This keeps IE from blowing up on images as drag handles.
+ */
+ _fixDragStart: function(e) {
+ e.preventDefault();
+ },
+ /**
+ * @private
+ * @method _ieSelectFix
+ * @description The function we use as the onselectstart handler when we start a drag in Internet Explorer
+ */
+ _ieSelectFix: function() {
+ return false;
+ },
+ /**
+ * @private
+ * @property _ieSelectBack
+ * @description We will hold a copy of the current "onselectstart" method on this property, and reset it after we are done using it.
+ */
+ _ieSelectBack: null,
+ /**
+ * @private
+ * @method _fixIEMouseDown
+ * @description This method copies the onselectstart listner on the document to the _ieSelectFix property
+ */
+ _fixIEMouseDown: function() {
+ if (Y.UA.ie) {
+ this._ieSelectBack = Y.config.doc.body.onselectstart;
+ Y.config.doc.body.onselectstart = this._ieSelectFix;
+ }
+ },
+ /**
+ * @private
+ * @method _fixIEMouseUp
+ * @description This method copies the _ieSelectFix property back to the onselectstart listner on the document.
+ */
+ _fixIEMouseUp: function() {
+ if (Y.UA.ie) {
+ Y.config.doc.body.onselectstart = this._ieSelectBack;
+ }
+ },
+ /**
+ * @private
+ * @method _handleMouseDownEvent
+ * @description Handler for the mousedown DOM event
+ * @param {Event.Facade}
+ */
+ _handleMouseDownEvent: function(ev) {
+ this.fire(EV_MOUSE_DOWN, { ev: ev });
+ },
+ /**
+ * @private
+ * @method _defMouseDownFn
+ * @description Handler for the mousedown DOM event
+ * @param {Event.Facade}
+ */
+ _defMouseDownFn: function(e) {
+ var ev = e.ev;
+ this._dragThreshMet = false;
+ this._ev_md = ev;
+
+ if (this.get('primaryButtonOnly') && ev.button > 1) {
+ return false;
+ }
+ if (this.validClick(ev)) {
+ this._fixIEMouseDown();
+ ev.halt();
+ this._setStartPosition([ev.pageX, ev.pageY]);
+
+ DDM.activeDrag = this;
+
+ this._clickTimeout = Y.later(this.get('clickTimeThresh'), this, this._timeoutCheck);
+ }
+ this.fire(EV_AFTER_MOUSE_DOWN, { ev: ev });
+ },
+ /**
+ * @method validClick
+ * @description Method first checks to see if we have handles, if so it validates the click against the handle. Then if it finds a valid handle, it checks it against the invalid handles list. Returns true if a good handle was used, false otherwise.
+ * @param {Event.Facade}
+ * @return {Boolean}
+ */
+ validClick: function(ev) {
+ var r = false, n = false,
+ tar = ev.target,
+ hTest = null,
+ els = null,
+ set = false;
+ if (this._handles) {
+ Y.each(this._handles, function(i, n) {
+ if (Y.Lang.isString(n)) {
+ //Am I this or am I inside this
+ if (tar.test(n + ', ' + n + ' *') && !hTest) {
+ hTest = n;
+ r = true;
+ }
+ }
+ });
+ } else {
+ n = this.get(NODE)
+ if (n.contains(tar) || n.compareTo(tar)) {
+ r = true;
+ }
+ }
+ if (r) {
+ if (this._invalids) {
+ Y.each(this._invalids, function(i, n) {
+ if (Y.Lang.isString(n)) {
+ //Am I this or am I inside this
+ if (tar.test(n + ', ' + n + ' *')) {
+ r = false;
+ }
+ }
+ });
+ }
+ }
+ if (r) {
+ if (hTest) {
+ els = ev.currentTarget.queryAll(hTest);
+ set = false;
+ els.each(function(n, i) {
+ if ((n.contains(tar) || n.compareTo(tar)) && !set) {
+ set = true;
+ this.set('activeHandle', n);
+ }
+ }, this);
+ } else {
+ this.set('activeHandle', this.get(NODE));
+ }
+ }
+ return r;
+ },
+ /**
+ * @private
+ * @method _setStartPosition
+ * @description Sets the current position of the Element and calculates the offset
+ * @param {Array} xy The XY coords to set the position to.
+ */
+ _setStartPosition: function(xy) {
+ this.startXY = xy;
+
+ this.nodeXY = this.lastXY = this.realXY = this.get(NODE).getXY();
+
+ if (this.get('offsetNode')) {
+ this.deltaXY = [(this.startXY[0] - this.nodeXY[0]), (this.startXY[1] - this.nodeXY[1])];
+ } else {
+ this.deltaXY = [0, 0];
+ }
+ },
+ /**
+ * @private
+ * @method _timeoutCheck
+ * @description The method passed to setTimeout to determine if the clickTimeThreshold was met.
+ */
+ _timeoutCheck: function() {
+ if (!this.get('lock') && !this._dragThreshMet) {
+ this._fromTimeout = this._dragThreshMet = true;
+ this.start();
+ this._alignNode([this._ev_md.pageX, this._ev_md.pageY], true);
+ }
+ },
+ /**
+ * @method removeHandle
+ * @description Remove a Selector added by addHandle
+ * @param {String} str The selector for the handle to be removed.
+ * @return {Self}
+ * @chainable
+ */
+ removeHandle: function(str) {
+ if (this._handles[str]) {
+ delete this._handles[str];
+ this.fire(EV_REMOVE_HANDLE, { handle: str });
+ }
+ return this;
+ },
+ /**
+ * @method addHandle
+ * @description Add a handle to a drag element. Drag only initiates when a mousedown happens on this element.
+ * @param {String} str The selector to test for a valid handle. Must be a child of the element.
+ * @return {Self}
+ * @chainable
+ */
+ addHandle: function(str) {
+ if (!this._handles) {
+ this._handles = {};
+ }
+ if (Y.Lang.isString(str)) {
+ this._handles[str] = true;
+ this.fire(EV_ADD_HANDLE, { handle: str });
+ }
+ return this;
+ },
+ /**
+ * @method removeInvalid
+ * @description Remove an invalid handle added by addInvalid
+ * @param {String} str The invalid handle to remove from the internal list.
+ * @return {Self}
+ * @chainable
+ */
+ removeInvalid: function(str) {
+ if (this._invalids[str]) {
+ this._invalids[str] = null;
+ delete this._invalids[str];
+ this.fire(EV_REMOVE_INVALID, { handle: str });
+ }
+ return this;
+ },
+ /**
+ * @method addInvalid
+ * @description Add a selector string to test the handle against. If the test passes the drag operation will not continue.
+ * @param {String} str The selector to test against to determine if this is an invalid drag handle.
+ * @return {Self}
+ * @chainable
+ */
+ addInvalid: function(str) {
+ if (Y.Lang.isString(str)) {
+ this._invalids[str] = true;
+ this.fire(EV_ADD_INVALID, { handle: str });
+ }
+ return this;
+ },
+ /**
+ * @private
+ * @method initializer
+ * @description Internal init handler
+ */
+ initializer: function() {
+ this.get(NODE).dd = this;
+
+ if (!this.get(NODE).get('id')) {
+ var id = Y.stamp(this.get(NODE));
+ this.get(NODE).set('id', id);
+ }
+
+ this.actXY = [];
+
+ this._invalids = Y.clone(this._invalidsDefault, true);
+
+ this._createEvents();
+
+ if (!this.get(DRAG_NODE)) {
+ this.set(DRAG_NODE, this.get(NODE));
+ }
+
+ //Fix for #2528096
+ //Don't prep the DD instance until all plugins are loaded.
+ this.on('initializedChange', Y.bind(this._prep, this));
+
+ //Shouldn't have to do this..
+ this.set('groups', this.get('groups'));
+ },
+ /**
+ * @private
+ * @method _prep
+ * @description Attach event listners and add classname
+ */
+ _prep: function() {
+ this._dragThreshMet = false;
+ var node = this.get(NODE);
+ node.addClass(DDM.CSS_PREFIX + '-draggable');
+ node.on(MOUSE_DOWN, Y.bind(this._handleMouseDownEvent, this));
+ node.on(MOUSE_UP, Y.bind(this._handleMouseUp, this));
+ node.on(DRAG_START, Y.bind(this._fixDragStart, this));
+ },
+ /**
+ * @private
+ * @method _unprep
+ * @description Detach event listeners and remove classname
+ */
+ _unprep: function() {
+ var node = this.get(NODE);
+ node.removeClass(DDM.CSS_PREFIX + '-draggable');
+ node.detachAll();
+ },
+ /**
+ * @method start
+ * @description Starts the drag operation
+ * @return {Self}
+ * @chainable
+ */
+ start: function() {
+ if (!this.get('lock') && !this.get(DRAGGING)) {
+ var node = this.get(NODE), ow = node.get(OFFSET_WIDTH), oh = node.get(OFFSET_HEIGHT);
+ this._startTime = (new Date()).getTime();
+
+ DDM._start();
+ node.addClass(DDM.CSS_PREFIX + '-dragging');
+ this.fire(EV_START, {
+ pageX: this.nodeXY[0],
+ pageY: this.nodeXY[1],
+ startTime: this._startTime
+ });
+ var xy = this.nodeXY;
+
+
+ this.region = {
+ '0': xy[0],
+ '1': xy[1],
+ area: 0,
+ top: xy[1],
+ right: xy[0] + ow,
+ bottom: xy[1] + oh,
+ left: xy[0]
+ };
+ this.set(DRAGGING, true);
+ }
+ return this;
+ },
+ /**
+ * @method end
+ * @description Ends the drag operation
+ * @return {Self}
+ * @chainable
+ */
+ end: function() {
+ this._endTime = (new Date()).getTime();
+ if (this._clickTimeout) {
+ this._clickTimeout.cancel();
+ }
+ this._dragThreshMet = false;
+ this._fromTimeout = false;
+ if (!this.get('lock') && this.get(DRAGGING)) {
+ this.fire(EV_END, {
+ pageX: this.lastXY[0],
+ pageY: this.lastXY[1],
+ startTime: this._startTime,
+ endTime: this._endTime
+ });
+ }
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-dragging');
+ this.set(DRAGGING, false);
+ this.deltaXY = [0, 0];
+
+ return this;
+ },
+ /**
+ * @private
+ * @method _prevEndFn
+ * @description Handler for preventing the drag:end event. It will reset the node back to it's start position
+ */
+ _prevEndFn: function(e) {
+ //Bug #1852577
+ this.get(DRAG_NODE).setXY(this.nodeXY);
+ },
+ /**
+ * @private
+ * @method _align
+ * @description Calculates the offsets and set's the XY that the element will move to.
+ * @param {Array} xy The xy coords to align with.
+ */
+ _align: function(xy) {
+ this.fire(EV_ALIGN, {pageX: xy[0], pageY: xy[1] });
+ },
+ /**
+ * @private
+ * @method _defAlignFn
+ * @description Calculates the offsets and set's the XY that the element will move to.
+ * @param {Event.Facade} e The drag:align event.
+ */
+ _defAlignFn: function(e) {
+ this.actXY = [e.pageX - this.deltaXY[0], e.pageY - this.deltaXY[1]];
+ },
+ /**
+ * @private
+ * @method _alignNode
+ * @description This method performs the alignment before the element move.
+ * @param {Array} eXY The XY to move the element to, usually comes from the mousemove DOM event.
+ */
+ _alignNode: function(eXY) {
+ this._align(eXY);
+ this._moveNode();
+ },
+ /**
+ * @private
+ * @method _moveNode
+ * @description This method performs the actual element move.
+ */
+ _moveNode: function(scroll) {
+ //if (!this.get(DRAGGING)) {
+ // return;
+ //}
+ var diffXY = [], diffXY2 = [], startXY = this.nodeXY, xy = this.actXY;
+
+ diffXY[0] = (xy[0] - this.lastXY[0]);
+ diffXY[1] = (xy[1] - this.lastXY[1]);
+
+ diffXY2[0] = (xy[0] - this.nodeXY[0]);
+ diffXY2[1] = (xy[1] - this.nodeXY[1]);
+
+
+ this.region = {
+ '0': xy[0],
+ '1': xy[1],
+ area: 0,
+ top: xy[1],
+ right: xy[0] + this.get(DRAG_NODE).get(OFFSET_WIDTH),
+ bottom: xy[1] + this.get(DRAG_NODE).get(OFFSET_HEIGHT),
+ left: xy[0]
+ };
+
+ this.fire(EV_DRAG, {
+ pageX: xy[0],
+ pageY: xy[1],
+ scroll: scroll,
+ info: {
+ start: startXY,
+ xy: xy,
+ delta: diffXY,
+ offset: diffXY2
+ }
+ });
+
+ this.lastXY = xy;
+ },
+ /**
+ * @private
+ * @method _defDragFn
+ * @description Default function for drag:drag. Fired from _moveNode.
+ * @param {Event.Facade} ev The drag:drag event
+ */
+ _defDragFn: function(e) {
+ if (this.get('move')) {
+ if (e.scroll) {
+ e.scroll.node.set('scrollTop', e.scroll.top);
+ e.scroll.node.set('scrollLeft', e.scroll.left);
+ }
+ this.get(DRAG_NODE).setXY([e.pageX, e.pageY]);
+ this.realXY = [e.pageX, e.pageY];
+ }
+ },
+ /**
+ * @private
+ * @method _move
+ * @description Fired from DragDropMgr (DDM) on mousemove.
+ * @param {Event.Facade} ev The mousemove DOM event
+ */
+ _move: function(ev) {
+ if (this.get('lock')) {
+ return false;
+ } else {
+ this.mouseXY = [ev.pageX, ev.pageY];
+ if (!this._dragThreshMet) {
+ var diffX = Math.abs(this.startXY[0] - ev.pageX),
+ diffY = Math.abs(this.startXY[1] - ev.pageY);
+ if (diffX > this.get('clickPixelThresh') || diffY > this.get('clickPixelThresh')) {
+ this._dragThreshMet = true;
+ this.start();
+ this._alignNode([ev.pageX, ev.pageY]);
+ }
+ } else {
+ if (this._clickTimeout) {
+ this._clickTimeout.cancel();
+ }
+ this._alignNode([ev.pageX, ev.pageY]);
+ }
+ }
+ },
+ /**
+ * @method stopDrag
+ * @description Method will forcefully stop a drag operation. For example calling this from inside an ESC keypress handler will stop this drag.
+ * @return {Self}
+ * @chainable
+ */
+ stopDrag: function() {
+ if (this.get(DRAGGING)) {
+ DDM._end();
+ }
+ return this;
+ },
+ /**
+ * @private
+ * @method destructor
+ * @description Lifecycle destructor, unreg the drag from the DDM and remove listeners
+ */
+ destructor: function() {
+ this._unprep();
+ this.detachAll();
+ if (this.target) {
+ this.target.destroy();
+ }
+ DDM._unregDrag(this);
+ }
+ });
+ Y.namespace('DD');
+ Y.DD.Drag = Drag;
+
+
+
+
+
+}, '3.0.0' ,{requires:['dd-ddm-base'], skinnable:false});
diff --git a/lib/yui/3.0.0/dd/dd-drop-debug.js b/lib/yui/3.0.0/dd/dd-drop-debug.js
new file mode 100644
index 0000000000..633a267232
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-drop-debug.js
@@ -0,0 +1,485 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dd-drop', function(Y) {
+
+
+ /**
+ * The Drag & Drop Utility allows you to create a draggable interface efficiently, buffering you from browser-level abnormalities and enabling you to focus on the interesting logic surrounding your particular implementation. This component enables you to create a variety of standard draggable objects with just a few lines of code and then, using its extensive API, add your own specific implementation logic.
+ * @module dd
+ * @submodule dd-drop
+ */
+ /**
+ * This class provides the ability to create a Drop Target.
+ * @class Drop
+ * @extends Base
+ * @constructor
+ * @namespace DD
+ */
+
+ var NODE = 'node',
+ DDM = Y.DD.DDM,
+ OFFSET_HEIGHT = 'offsetHeight',
+ OFFSET_WIDTH = 'offsetWidth',
+ /**
+ * @event drop:over
+ * @description Fires when a drag element is over this target.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_DROP_OVER = 'drop:over',
+ /**
+ * @event drop:enter
+ * @description Fires when a drag element enters this target.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_DROP_ENTER = 'drop:enter',
+ /**
+ * @event drop:exit
+ * @description Fires when a drag element exits this target.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_DROP_EXIT = 'drop:exit',
+
+ /**
+ * @event drop:hit
+ * @description Fires when a draggable node is dropped on this Drop Target. (Fired from dd-ddm-drop)
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+
+
+ Drop = function() {
+ this._lazyAddAttrs = false;
+ Drop.superclass.constructor.apply(this, arguments);
+
+
+ //DD init speed up.
+ Y.on('domready', Y.bind(function() {
+ Y.later(100, this, this._createShim);
+ }, this));
+ DDM._regTarget(this);
+
+ /* TODO
+ if (Dom.getStyle(this.el, 'position') == 'fixed') {
+ Event.on(window, 'scroll', function() {
+ this.activateShim();
+ }, this, true);
+ }
+ */
+ };
+
+ Drop.NAME = 'drop';
+
+ Drop.ATTRS = {
+ /**
+ * @attribute node
+ * @description Y.Node instanace to use as the element to make a Drop Target
+ * @type Node
+ */
+ node: {
+ setter: function(node) {
+ var n = Y.Node.get(node);
+ if (!n) {
+ Y.error('DD.Drop: Invalid Node Given: ' + node);
+ }
+ return n;
+ }
+ },
+ /**
+ * @attribute groups
+ * @description Array of groups to add this drop into.
+ * @type Array
+ */
+ groups: {
+ value: ['default'],
+ setter: function(g) {
+ this._groups = {};
+ Y.each(g, function(v, k) {
+ this._groups[v] = true;
+ }, this);
+ return g;
+ }
+ },
+ /**
+ * @attribute padding
+ * @description CSS style padding to make the Drop Target bigger than the node.
+ * @type String
+ */
+ padding: {
+ value: '0',
+ setter: function(p) {
+ return DDM.cssSizestoObject(p);
+ }
+ },
+ /**
+ * @attribute lock
+ * @description Set to lock this drop element.
+ * @type Boolean
+ */
+ lock: {
+ value: false,
+ setter: function(lock) {
+ if (lock) {
+ this.get(NODE).addClass(DDM.CSS_PREFIX + '-drop-locked');
+ } else {
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-locked');
+ }
+ return lock;
+ }
+ },
+ /**
+ * @attribute bubbles
+ * @description Controls the default bubble parent for this Drop instance. Default: Y.DD.DDM. Set to false to disable bubbling.
+ * @type Object
+ */
+ bubbles: {
+ writeOnce: true,
+ value: Y.DD.DDM
+ }
+ };
+
+ Y.extend(Drop, Y.Base, {
+ /**
+ * @private
+ * @method _createEvents
+ * @description This method creates all the events for this Event Target and publishes them so we get Event Bubbling.
+ */
+ _createEvents: function() {
+
+ var ev = [
+ EV_DROP_OVER,
+ EV_DROP_ENTER,
+ EV_DROP_EXIT,
+ 'drop:hit'
+ ];
+
+ Y.each(ev, function(v, k) {
+ this.publish(v, {
+ type: v,
+ emitFacade: true,
+ preventable: false,
+ bubbles: true,
+ queuable: false,
+ prefix: 'drop'
+ });
+ }, this);
+
+ if (this.get('bubbles')) {
+ this.addTarget(this.get('bubbles'));
+ }
+
+ },
+ /**
+ * @private
+ * @property _valid
+ * @description Flag for determining if the target is valid in this operation.
+ * @type Boolean
+ */
+ _valid: null,
+ /**
+ * @private
+ * @property _groups
+ * @description The groups this target belongs to.
+ * @type Array
+ */
+ _groups: null,
+ /**
+ * @property shim
+ * @description Node reference to the targets shim
+ * @type {Object}
+ */
+ shim: null,
+ /**
+ * @property region
+ * @description A region object associated with this target, used for checking regions while dragging.
+ * @type Object
+ */
+ region: null,
+ /**
+ * @property overTarget
+ * @description This flag is tripped when a drag element is over this target.
+ * @type Boolean
+ */
+ overTarget: null,
+ /**
+ * @method inGroup
+ * @description Check if this target is in one of the supplied groups.
+ * @param {Array} groups The groups to check against
+ * @return Boolean
+ */
+ inGroup: function(groups) {
+ this._valid = false;
+ var ret = false;
+ Y.each(groups, function(v, k) {
+ if (this._groups[v]) {
+ ret = true;
+ this._valid = true;
+ }
+ }, this);
+ return ret;
+ },
+ /**
+ * @private
+ * @method initializer
+ * @description Private lifecycle method
+ */
+ initializer: function() {
+ //this._createEvents();
+ Y.later(100, this, this._createEvents);
+
+ var node = this.get(NODE), id;
+ if (!node.get('id')) {
+ id = Y.stamp(node);
+ node.set('id', id);
+ }
+ node.addClass(DDM.CSS_PREFIX + '-drop');
+ //Shouldn't have to do this..
+ this.set('groups', this.get('groups'));
+ },
+ /**
+ * @private
+ * @method destructor
+ * @description Lifecycle destructor, unreg the drag from the DDM and remove listeners
+ */
+ destructor: function() {
+ DDM._unregTarget(this);
+ if (this.shim) {
+ this.shim.detachAll();
+ this.shim.get('parentNode').removeChild(this.shim);
+ this.shim = null;
+ }
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop');
+ this.detachAll();
+ },
+ /**
+ * @private
+ * @method _deactivateShim
+ * @description Removes classes from the target, resets some flags and sets the shims deactive position [-999, -999]
+ */
+ _deactivateShim: function() {
+ if (!this.shim) {
+ return false;
+ }
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-active-valid');
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-active-invalid');
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-over');
+ this.shim.setStyles({
+ top: '-999px',
+ left: '-999px',
+ zIndex: '1'
+ });
+ this.overTarget = false;
+ },
+ /**
+ * @private
+ * @method _activateShim
+ * @description Activates the shim and adds some interaction CSS classes
+ */
+ _activateShim: function() {
+ if (!DDM.activeDrag) {
+ return false; //Nothing is dragging, no reason to activate.
+ }
+ if (this.get(NODE) === DDM.activeDrag.get(NODE)) {
+ return false;
+ }
+ if (this.get('lock')) {
+ return false;
+ }
+ var node = this.get(NODE);
+ //TODO Visibility Check..
+ //if (this.inGroup(DDM.activeDrag.get('groups')) && this.get(NODE).isVisible()) {
+ if (this.inGroup(DDM.activeDrag.get('groups'))) {
+ node.removeClass(DDM.CSS_PREFIX + '-drop-active-invalid');
+ node.addClass(DDM.CSS_PREFIX + '-drop-active-valid');
+ DDM._addValid(this);
+ this.overTarget = false;
+ this.sizeShim();
+ } else {
+ DDM._removeValid(this);
+ node.removeClass(DDM.CSS_PREFIX + '-drop-active-valid');
+ node.addClass(DDM.CSS_PREFIX + '-drop-active-invalid');
+ }
+ },
+ /**
+ * @method sizeShim
+ * @description Positions and sizes the shim with the raw data from the node, this can be used to programatically adjust the Targets shim for Animation..
+ */
+ sizeShim: function() {
+ if (!DDM.activeDrag) {
+ return false; //Nothing is dragging, no reason to activate.
+ }
+ if (this.get(NODE) === DDM.activeDrag.get(NODE)) {
+ return false;
+ }
+ if (this.get('lock')) {
+ return false;
+ }
+ if (!this.shim) {
+ Y.later(100, this, this.sizeShim);
+ return false;
+ }
+ var node = this.get(NODE),
+ nh = node.get(OFFSET_HEIGHT),
+ nw = node.get(OFFSET_WIDTH),
+ xy = node.getXY(),
+ p = this.get('padding'),
+ dd, dH, dW;
+
+
+ //Apply padding
+ nw = nw + p.left + p.right;
+ nh = nh + p.top + p.bottom;
+ xy[0] = xy[0] - p.left;
+ xy[1] = xy[1] - p.top;
+
+
+ if (DDM.activeDrag.get('dragMode') === DDM.INTERSECT) {
+ //Intersect Mode, make the shim bigger
+ dd = DDM.activeDrag;
+ dH = dd.get(NODE).get(OFFSET_HEIGHT);
+ dW = dd.get(NODE).get(OFFSET_WIDTH);
+
+ nh = (nh + dH);
+ nw = (nw + dW);
+ xy[0] = xy[0] - (dW - dd.deltaXY[0]);
+ xy[1] = xy[1] - (dH - dd.deltaXY[1]);
+
+ }
+
+ //Set the style on the shim
+ this.shim.setStyles({
+ height: nh + 'px',
+ width: nw + 'px',
+ top: xy[1] + 'px',
+ left: xy[0] + 'px'
+ });
+
+ //Create the region to be used by intersect when a drag node is over us.
+ this.region = {
+ '0': xy[0],
+ '1': xy[1],
+ area: 0,
+ top: xy[1],
+ right: xy[0] + nw,
+ bottom: xy[1] + nh,
+ left: xy[0]
+ };
+ },
+ /**
+ * @private
+ * @method _createShim
+ * @description Creates the Target shim and adds it to the DDM's playground..
+ */
+ _createShim: function() {
+ //No playground, defer
+ if (!DDM._pg) {
+ Y.later(10, this, this._createShim);
+ return;
+ }
+ //Shim already here, cancel
+ if (this.shim) {
+ return;
+ }
+ var s = Y.Node.create('');
+
+ s.setStyles({
+ height: this.get(NODE).get(OFFSET_HEIGHT) + 'px',
+ width: this.get(NODE).get(OFFSET_WIDTH) + 'px',
+ backgroundColor: 'yellow',
+ opacity: '.5',
+ zIndex: '1',
+ overflow: 'hidden',
+ top: '-900px',
+ left: '-900px',
+ position: 'absolute'
+ });
+ DDM._pg.appendChild(s);
+ this.shim = s;
+
+ s.on('mouseover', Y.bind(this._handleOverEvent, this));
+ s.on('mouseout', Y.bind(this._handleOutEvent, this));
+ },
+ /**
+ * @private
+ * @method _handleOverTarget
+ * @description This handles the over target call made from this object or from the DDM
+ */
+ _handleTargetOver: function() {
+ if (DDM.isOverTarget(this)) {
+ this.get(NODE).addClass(DDM.CSS_PREFIX + '-drop-over');
+ DDM.activeDrop = this;
+ DDM.otherDrops[this] = this;
+ if (this.overTarget) {
+ DDM.activeDrag.fire('drag:over', { drop: this, drag: DDM.activeDrag });
+ this.fire(EV_DROP_OVER, { drop: this, drag: DDM.activeDrag });
+ } else {
+ this.overTarget = true;
+ this.fire(EV_DROP_ENTER, { drop: this, drag: DDM.activeDrag });
+ DDM.activeDrag.fire('drag:enter', { drop: this, drag: DDM.activeDrag });
+ DDM.activeDrag.get(NODE).addClass(DDM.CSS_PREFIX + '-drag-over');
+ //TODO - Is this needed??
+ //DDM._handleTargetOver();
+ }
+ } else {
+ this._handleOut();
+ }
+ },
+ /**
+ * @private
+ * @method _handleOverEvent
+ * @description Handles the mouseover DOM event on the Target Shim
+ */
+ _handleOverEvent: function() {
+ this.shim.setStyle('zIndex', '999');
+ DDM._addActiveShim(this);
+ },
+ /**
+ * @private
+ * @method _handleOutEvent
+ * @description Handles the mouseout DOM event on the Target Shim
+ */
+ _handleOutEvent: function() {
+ this.shim.setStyle('zIndex', '1');
+ DDM._removeActiveShim(this);
+ },
+ /**
+ * @private
+ * @method _handleOut
+ * @description Handles out of target calls/checks
+ */
+ _handleOut: function(force) {
+ if (!DDM.isOverTarget(this) || force) {
+ if (this.overTarget) {
+ this.overTarget = false;
+ if (!force) {
+ DDM._removeActiveShim(this);
+ }
+ if (DDM.activeDrag) {
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-over');
+ DDM.activeDrag.get(NODE).removeClass(DDM.CSS_PREFIX + '-drag-over');
+ this.fire(EV_DROP_EXIT);
+ DDM.activeDrag.fire('drag:exit', { drop: this });
+ delete DDM.otherDrops[this];
+ //if (DDM.activeDrop === this) {
+ // DDM.activeDrop = null;
+ //}
+ }
+ }
+ }
+ }
+ });
+
+ Y.DD.Drop = Drop;
+
+
+
+
+
+}, '3.0.0' ,{requires:['dd-ddm-drop', 'dd-drag'], skinnable:false});
diff --git a/lib/yui/3.0.0/dd/dd-drop-min.js b/lib/yui/3.0.0/dd/dd-drop-min.js
new file mode 100644
index 0000000000..5b5d5342f2
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-drop-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("dd-drop",function(A){var B="node",G=A.DD.DDM,F="offsetHeight",C="offsetWidth",I="drop:over",H="drop:enter",D="drop:exit",E=function(){this._lazyAddAttrs=false;E.superclass.constructor.apply(this,arguments);A.on("domready",A.bind(function(){A.later(100,this,this._createShim);},this));G._regTarget(this);};E.NAME="drop";E.ATTRS={node:{setter:function(J){var K=A.Node.get(J);if(!K){A.error("DD.Drop: Invalid Node Given: "+J);}return K;}},groups:{value:["default"],setter:function(J){this._groups={};A.each(J,function(L,K){this._groups[L]=true;},this);return J;}},padding:{value:"0",setter:function(J){return G.cssSizestoObject(J);}},lock:{value:false,setter:function(J){if(J){this.get(B).addClass(G.CSS_PREFIX+"-drop-locked");}else{this.get(B).removeClass(G.CSS_PREFIX+"-drop-locked");}return J;}},bubbles:{writeOnce:true,value:A.DD.DDM}};A.extend(E,A.Base,{_createEvents:function(){var J=[I,H,D,"drop:hit"];A.each(J,function(L,K){this.publish(L,{type:L,emitFacade:true,preventable:false,bubbles:true,queuable:false,prefix:"drop"});},this);if(this.get("bubbles")){this.addTarget(this.get("bubbles"));}},_valid:null,_groups:null,shim:null,region:null,overTarget:null,inGroup:function(J){this._valid=false;var K=false;A.each(J,function(M,L){if(this._groups[M]){K=true;this._valid=true;}},this);return K;},initializer:function(){A.later(100,this,this._createEvents);var J=this.get(B),K;if(!J.get("id")){K=A.stamp(J);J.set("id",K);}J.addClass(G.CSS_PREFIX+"-drop");this.set("groups",this.get("groups"));},destructor:function(){G._unregTarget(this);if(this.shim){this.shim.detachAll();this.shim.get("parentNode").removeChild(this.shim);this.shim=null;}this.get(B).removeClass(G.CSS_PREFIX+"-drop");this.detachAll();},_deactivateShim:function(){if(!this.shim){return false;}this.get(B).removeClass(G.CSS_PREFIX+"-drop-active-valid");this.get(B).removeClass(G.CSS_PREFIX+"-drop-active-invalid");this.get(B).removeClass(G.CSS_PREFIX+"-drop-over");this.shim.setStyles({top:"-999px",left:"-999px",zIndex:"1"});this.overTarget=false;},_activateShim:function(){if(!G.activeDrag){return false;}if(this.get(B)===G.activeDrag.get(B)){return false;}if(this.get("lock")){return false;}var J=this.get(B);if(this.inGroup(G.activeDrag.get("groups"))){J.removeClass(G.CSS_PREFIX+"-drop-active-invalid");J.addClass(G.CSS_PREFIX+"-drop-active-valid");G._addValid(this);this.overTarget=false;this.sizeShim();}else{G._removeValid(this);J.removeClass(G.CSS_PREFIX+"-drop-active-valid");J.addClass(G.CSS_PREFIX+"-drop-active-invalid");}},sizeShim:function(){if(!G.activeDrag){return false;}if(this.get(B)===G.activeDrag.get(B)){return false;}if(this.get("lock")){return false;}if(!this.shim){A.later(100,this,this.sizeShim);return false;}var O=this.get(B),M=O.get(F),K=O.get(C),Q=O.getXY(),P=this.get("padding"),J,N,L;K=K+P.left+P.right;M=M+P.top+P.bottom;Q[0]=Q[0]-P.left;Q[1]=Q[1]-P.top;if(G.activeDrag.get("dragMode")===G.INTERSECT){J=G.activeDrag;N=J.get(B).get(F);L=J.get(B).get(C);M=(M+N);K=(K+L);Q[0]=Q[0]-(L-J.deltaXY[0]);Q[1]=Q[1]-(N-J.deltaXY[1]);}this.shim.setStyles({height:M+"px",width:K+"px",top:Q[1]+"px",left:Q[0]+"px"});this.region={"0":Q[0],"1":Q[1],area:0,top:Q[1],right:Q[0]+K,bottom:Q[1]+M,left:Q[0]};},_createShim:function(){if(!G._pg){A.later(10,this,this._createShim);return;}if(this.shim){return;}var J=A.Node.create('');J.setStyles({height:this.get(B).get(F)+"px",width:this.get(B).get(C)+"px",backgroundColor:"yellow",opacity:".5",zIndex:"1",overflow:"hidden",top:"-900px",left:"-900px",position:"absolute"});G._pg.appendChild(J);this.shim=J;J.on("mouseover",A.bind(this._handleOverEvent,this));J.on("mouseout",A.bind(this._handleOutEvent,this));},_handleTargetOver:function(){if(G.isOverTarget(this)){this.get(B).addClass(G.CSS_PREFIX+"-drop-over");G.activeDrop=this;G.otherDrops[this]=this;if(this.overTarget){G.activeDrag.fire("drag:over",{drop:this,drag:G.activeDrag});this.fire(I,{drop:this,drag:G.activeDrag});}else{this.overTarget=true;this.fire(H,{drop:this,drag:G.activeDrag});G.activeDrag.fire("drag:enter",{drop:this,drag:G.activeDrag});G.activeDrag.get(B).addClass(G.CSS_PREFIX+"-drag-over");}}else{this._handleOut();}},_handleOverEvent:function(){this.shim.setStyle("zIndex","999");G._addActiveShim(this);},_handleOutEvent:function(){this.shim.setStyle("zIndex","1");G._removeActiveShim(this);},_handleOut:function(J){if(!G.isOverTarget(this)||J){if(this.overTarget){this.overTarget=false;if(!J){G._removeActiveShim(this);}if(G.activeDrag){this.get(B).removeClass(G.CSS_PREFIX+"-drop-over");G.activeDrag.get(B).removeClass(G.CSS_PREFIX+"-drag-over");this.fire(D);G.activeDrag.fire("drag:exit",{drop:this});delete G.otherDrops[this];}}}}});A.DD.Drop=E;},"3.0.0",{requires:["dd-ddm-drop","dd-drag"],skinnable:false});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/dd/dd-drop-plugin-debug.js b/lib/yui/3.0.0/dd/dd-drop-plugin-debug.js
new file mode 100644
index 0000000000..68b21b90cd
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-drop-plugin-debug.js
@@ -0,0 +1,52 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dd-drop-plugin', function(Y) {
+
+
+ /**
+ * This is a simple Drop plugin that can be attached to a Node via the plug method.
+ * @module dd
+ * @submodule dd-drop-plugin
+ */
+ /**
+ * This is a simple Drop plugin that can be attached to a Node via the plug method.
+ * @class Drop
+ * @extends DD.Drop
+ * @constructor
+ * @namespace Plugin
+ */
+
+
+ var Drop = function(config) {
+ config.node = config.host;
+ Drop.superclass.constructor.apply(this, arguments);
+ };
+
+ /**
+ * @property NAME
+ * @description dd-drop-plugin
+ * @type {String}
+ */
+ Drop.NAME = "dd-drop-plugin";
+ /**
+ * @property NS
+ * @description The Drop instance will be placed on the Node instance under the drop namespace. It can be accessed via Node.drop;
+ * @type {String}
+ */
+ Drop.NS = "drop";
+
+
+ Y.extend(Drop, Y.DD.Drop);
+ Y.namespace('Plugin');
+ Y.Plugin.Drop = Drop;
+
+
+
+
+
+}, '3.0.0' ,{requires:['dd-drop'], skinnable:false});
diff --git a/lib/yui/3.0.0/dd/dd-drop-plugin-min.js b/lib/yui/3.0.0/dd/dd-drop-plugin-min.js
new file mode 100644
index 0000000000..33da7e25ec
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-drop-plugin-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("dd-drop-plugin",function(A){var B=function(C){C.node=C.host;B.superclass.constructor.apply(this,arguments);};B.NAME="dd-drop-plugin";B.NS="drop";A.extend(B,A.DD.Drop);A.namespace("Plugin");A.Plugin.Drop=B;},"3.0.0",{requires:["dd-drop"],skinnable:false});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/dd/dd-drop-plugin.js b/lib/yui/3.0.0/dd/dd-drop-plugin.js
new file mode 100644
index 0000000000..68b21b90cd
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-drop-plugin.js
@@ -0,0 +1,52 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dd-drop-plugin', function(Y) {
+
+
+ /**
+ * This is a simple Drop plugin that can be attached to a Node via the plug method.
+ * @module dd
+ * @submodule dd-drop-plugin
+ */
+ /**
+ * This is a simple Drop plugin that can be attached to a Node via the plug method.
+ * @class Drop
+ * @extends DD.Drop
+ * @constructor
+ * @namespace Plugin
+ */
+
+
+ var Drop = function(config) {
+ config.node = config.host;
+ Drop.superclass.constructor.apply(this, arguments);
+ };
+
+ /**
+ * @property NAME
+ * @description dd-drop-plugin
+ * @type {String}
+ */
+ Drop.NAME = "dd-drop-plugin";
+ /**
+ * @property NS
+ * @description The Drop instance will be placed on the Node instance under the drop namespace. It can be accessed via Node.drop;
+ * @type {String}
+ */
+ Drop.NS = "drop";
+
+
+ Y.extend(Drop, Y.DD.Drop);
+ Y.namespace('Plugin');
+ Y.Plugin.Drop = Drop;
+
+
+
+
+
+}, '3.0.0' ,{requires:['dd-drop'], skinnable:false});
diff --git a/lib/yui/3.0.0/dd/dd-drop.js b/lib/yui/3.0.0/dd/dd-drop.js
new file mode 100644
index 0000000000..633a267232
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-drop.js
@@ -0,0 +1,485 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dd-drop', function(Y) {
+
+
+ /**
+ * The Drag & Drop Utility allows you to create a draggable interface efficiently, buffering you from browser-level abnormalities and enabling you to focus on the interesting logic surrounding your particular implementation. This component enables you to create a variety of standard draggable objects with just a few lines of code and then, using its extensive API, add your own specific implementation logic.
+ * @module dd
+ * @submodule dd-drop
+ */
+ /**
+ * This class provides the ability to create a Drop Target.
+ * @class Drop
+ * @extends Base
+ * @constructor
+ * @namespace DD
+ */
+
+ var NODE = 'node',
+ DDM = Y.DD.DDM,
+ OFFSET_HEIGHT = 'offsetHeight',
+ OFFSET_WIDTH = 'offsetWidth',
+ /**
+ * @event drop:over
+ * @description Fires when a drag element is over this target.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_DROP_OVER = 'drop:over',
+ /**
+ * @event drop:enter
+ * @description Fires when a drag element enters this target.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_DROP_ENTER = 'drop:enter',
+ /**
+ * @event drop:exit
+ * @description Fires when a drag element exits this target.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_DROP_EXIT = 'drop:exit',
+
+ /**
+ * @event drop:hit
+ * @description Fires when a draggable node is dropped on this Drop Target. (Fired from dd-ddm-drop)
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+
+
+ Drop = function() {
+ this._lazyAddAttrs = false;
+ Drop.superclass.constructor.apply(this, arguments);
+
+
+ //DD init speed up.
+ Y.on('domready', Y.bind(function() {
+ Y.later(100, this, this._createShim);
+ }, this));
+ DDM._regTarget(this);
+
+ /* TODO
+ if (Dom.getStyle(this.el, 'position') == 'fixed') {
+ Event.on(window, 'scroll', function() {
+ this.activateShim();
+ }, this, true);
+ }
+ */
+ };
+
+ Drop.NAME = 'drop';
+
+ Drop.ATTRS = {
+ /**
+ * @attribute node
+ * @description Y.Node instanace to use as the element to make a Drop Target
+ * @type Node
+ */
+ node: {
+ setter: function(node) {
+ var n = Y.Node.get(node);
+ if (!n) {
+ Y.error('DD.Drop: Invalid Node Given: ' + node);
+ }
+ return n;
+ }
+ },
+ /**
+ * @attribute groups
+ * @description Array of groups to add this drop into.
+ * @type Array
+ */
+ groups: {
+ value: ['default'],
+ setter: function(g) {
+ this._groups = {};
+ Y.each(g, function(v, k) {
+ this._groups[v] = true;
+ }, this);
+ return g;
+ }
+ },
+ /**
+ * @attribute padding
+ * @description CSS style padding to make the Drop Target bigger than the node.
+ * @type String
+ */
+ padding: {
+ value: '0',
+ setter: function(p) {
+ return DDM.cssSizestoObject(p);
+ }
+ },
+ /**
+ * @attribute lock
+ * @description Set to lock this drop element.
+ * @type Boolean
+ */
+ lock: {
+ value: false,
+ setter: function(lock) {
+ if (lock) {
+ this.get(NODE).addClass(DDM.CSS_PREFIX + '-drop-locked');
+ } else {
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-locked');
+ }
+ return lock;
+ }
+ },
+ /**
+ * @attribute bubbles
+ * @description Controls the default bubble parent for this Drop instance. Default: Y.DD.DDM. Set to false to disable bubbling.
+ * @type Object
+ */
+ bubbles: {
+ writeOnce: true,
+ value: Y.DD.DDM
+ }
+ };
+
+ Y.extend(Drop, Y.Base, {
+ /**
+ * @private
+ * @method _createEvents
+ * @description This method creates all the events for this Event Target and publishes them so we get Event Bubbling.
+ */
+ _createEvents: function() {
+
+ var ev = [
+ EV_DROP_OVER,
+ EV_DROP_ENTER,
+ EV_DROP_EXIT,
+ 'drop:hit'
+ ];
+
+ Y.each(ev, function(v, k) {
+ this.publish(v, {
+ type: v,
+ emitFacade: true,
+ preventable: false,
+ bubbles: true,
+ queuable: false,
+ prefix: 'drop'
+ });
+ }, this);
+
+ if (this.get('bubbles')) {
+ this.addTarget(this.get('bubbles'));
+ }
+
+ },
+ /**
+ * @private
+ * @property _valid
+ * @description Flag for determining if the target is valid in this operation.
+ * @type Boolean
+ */
+ _valid: null,
+ /**
+ * @private
+ * @property _groups
+ * @description The groups this target belongs to.
+ * @type Array
+ */
+ _groups: null,
+ /**
+ * @property shim
+ * @description Node reference to the targets shim
+ * @type {Object}
+ */
+ shim: null,
+ /**
+ * @property region
+ * @description A region object associated with this target, used for checking regions while dragging.
+ * @type Object
+ */
+ region: null,
+ /**
+ * @property overTarget
+ * @description This flag is tripped when a drag element is over this target.
+ * @type Boolean
+ */
+ overTarget: null,
+ /**
+ * @method inGroup
+ * @description Check if this target is in one of the supplied groups.
+ * @param {Array} groups The groups to check against
+ * @return Boolean
+ */
+ inGroup: function(groups) {
+ this._valid = false;
+ var ret = false;
+ Y.each(groups, function(v, k) {
+ if (this._groups[v]) {
+ ret = true;
+ this._valid = true;
+ }
+ }, this);
+ return ret;
+ },
+ /**
+ * @private
+ * @method initializer
+ * @description Private lifecycle method
+ */
+ initializer: function() {
+ //this._createEvents();
+ Y.later(100, this, this._createEvents);
+
+ var node = this.get(NODE), id;
+ if (!node.get('id')) {
+ id = Y.stamp(node);
+ node.set('id', id);
+ }
+ node.addClass(DDM.CSS_PREFIX + '-drop');
+ //Shouldn't have to do this..
+ this.set('groups', this.get('groups'));
+ },
+ /**
+ * @private
+ * @method destructor
+ * @description Lifecycle destructor, unreg the drag from the DDM and remove listeners
+ */
+ destructor: function() {
+ DDM._unregTarget(this);
+ if (this.shim) {
+ this.shim.detachAll();
+ this.shim.get('parentNode').removeChild(this.shim);
+ this.shim = null;
+ }
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop');
+ this.detachAll();
+ },
+ /**
+ * @private
+ * @method _deactivateShim
+ * @description Removes classes from the target, resets some flags and sets the shims deactive position [-999, -999]
+ */
+ _deactivateShim: function() {
+ if (!this.shim) {
+ return false;
+ }
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-active-valid');
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-active-invalid');
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-over');
+ this.shim.setStyles({
+ top: '-999px',
+ left: '-999px',
+ zIndex: '1'
+ });
+ this.overTarget = false;
+ },
+ /**
+ * @private
+ * @method _activateShim
+ * @description Activates the shim and adds some interaction CSS classes
+ */
+ _activateShim: function() {
+ if (!DDM.activeDrag) {
+ return false; //Nothing is dragging, no reason to activate.
+ }
+ if (this.get(NODE) === DDM.activeDrag.get(NODE)) {
+ return false;
+ }
+ if (this.get('lock')) {
+ return false;
+ }
+ var node = this.get(NODE);
+ //TODO Visibility Check..
+ //if (this.inGroup(DDM.activeDrag.get('groups')) && this.get(NODE).isVisible()) {
+ if (this.inGroup(DDM.activeDrag.get('groups'))) {
+ node.removeClass(DDM.CSS_PREFIX + '-drop-active-invalid');
+ node.addClass(DDM.CSS_PREFIX + '-drop-active-valid');
+ DDM._addValid(this);
+ this.overTarget = false;
+ this.sizeShim();
+ } else {
+ DDM._removeValid(this);
+ node.removeClass(DDM.CSS_PREFIX + '-drop-active-valid');
+ node.addClass(DDM.CSS_PREFIX + '-drop-active-invalid');
+ }
+ },
+ /**
+ * @method sizeShim
+ * @description Positions and sizes the shim with the raw data from the node, this can be used to programatically adjust the Targets shim for Animation..
+ */
+ sizeShim: function() {
+ if (!DDM.activeDrag) {
+ return false; //Nothing is dragging, no reason to activate.
+ }
+ if (this.get(NODE) === DDM.activeDrag.get(NODE)) {
+ return false;
+ }
+ if (this.get('lock')) {
+ return false;
+ }
+ if (!this.shim) {
+ Y.later(100, this, this.sizeShim);
+ return false;
+ }
+ var node = this.get(NODE),
+ nh = node.get(OFFSET_HEIGHT),
+ nw = node.get(OFFSET_WIDTH),
+ xy = node.getXY(),
+ p = this.get('padding'),
+ dd, dH, dW;
+
+
+ //Apply padding
+ nw = nw + p.left + p.right;
+ nh = nh + p.top + p.bottom;
+ xy[0] = xy[0] - p.left;
+ xy[1] = xy[1] - p.top;
+
+
+ if (DDM.activeDrag.get('dragMode') === DDM.INTERSECT) {
+ //Intersect Mode, make the shim bigger
+ dd = DDM.activeDrag;
+ dH = dd.get(NODE).get(OFFSET_HEIGHT);
+ dW = dd.get(NODE).get(OFFSET_WIDTH);
+
+ nh = (nh + dH);
+ nw = (nw + dW);
+ xy[0] = xy[0] - (dW - dd.deltaXY[0]);
+ xy[1] = xy[1] - (dH - dd.deltaXY[1]);
+
+ }
+
+ //Set the style on the shim
+ this.shim.setStyles({
+ height: nh + 'px',
+ width: nw + 'px',
+ top: xy[1] + 'px',
+ left: xy[0] + 'px'
+ });
+
+ //Create the region to be used by intersect when a drag node is over us.
+ this.region = {
+ '0': xy[0],
+ '1': xy[1],
+ area: 0,
+ top: xy[1],
+ right: xy[0] + nw,
+ bottom: xy[1] + nh,
+ left: xy[0]
+ };
+ },
+ /**
+ * @private
+ * @method _createShim
+ * @description Creates the Target shim and adds it to the DDM's playground..
+ */
+ _createShim: function() {
+ //No playground, defer
+ if (!DDM._pg) {
+ Y.later(10, this, this._createShim);
+ return;
+ }
+ //Shim already here, cancel
+ if (this.shim) {
+ return;
+ }
+ var s = Y.Node.create('');
+
+ s.setStyles({
+ height: this.get(NODE).get(OFFSET_HEIGHT) + 'px',
+ width: this.get(NODE).get(OFFSET_WIDTH) + 'px',
+ backgroundColor: 'yellow',
+ opacity: '.5',
+ zIndex: '1',
+ overflow: 'hidden',
+ top: '-900px',
+ left: '-900px',
+ position: 'absolute'
+ });
+ DDM._pg.appendChild(s);
+ this.shim = s;
+
+ s.on('mouseover', Y.bind(this._handleOverEvent, this));
+ s.on('mouseout', Y.bind(this._handleOutEvent, this));
+ },
+ /**
+ * @private
+ * @method _handleOverTarget
+ * @description This handles the over target call made from this object or from the DDM
+ */
+ _handleTargetOver: function() {
+ if (DDM.isOverTarget(this)) {
+ this.get(NODE).addClass(DDM.CSS_PREFIX + '-drop-over');
+ DDM.activeDrop = this;
+ DDM.otherDrops[this] = this;
+ if (this.overTarget) {
+ DDM.activeDrag.fire('drag:over', { drop: this, drag: DDM.activeDrag });
+ this.fire(EV_DROP_OVER, { drop: this, drag: DDM.activeDrag });
+ } else {
+ this.overTarget = true;
+ this.fire(EV_DROP_ENTER, { drop: this, drag: DDM.activeDrag });
+ DDM.activeDrag.fire('drag:enter', { drop: this, drag: DDM.activeDrag });
+ DDM.activeDrag.get(NODE).addClass(DDM.CSS_PREFIX + '-drag-over');
+ //TODO - Is this needed??
+ //DDM._handleTargetOver();
+ }
+ } else {
+ this._handleOut();
+ }
+ },
+ /**
+ * @private
+ * @method _handleOverEvent
+ * @description Handles the mouseover DOM event on the Target Shim
+ */
+ _handleOverEvent: function() {
+ this.shim.setStyle('zIndex', '999');
+ DDM._addActiveShim(this);
+ },
+ /**
+ * @private
+ * @method _handleOutEvent
+ * @description Handles the mouseout DOM event on the Target Shim
+ */
+ _handleOutEvent: function() {
+ this.shim.setStyle('zIndex', '1');
+ DDM._removeActiveShim(this);
+ },
+ /**
+ * @private
+ * @method _handleOut
+ * @description Handles out of target calls/checks
+ */
+ _handleOut: function(force) {
+ if (!DDM.isOverTarget(this) || force) {
+ if (this.overTarget) {
+ this.overTarget = false;
+ if (!force) {
+ DDM._removeActiveShim(this);
+ }
+ if (DDM.activeDrag) {
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-over');
+ DDM.activeDrag.get(NODE).removeClass(DDM.CSS_PREFIX + '-drag-over');
+ this.fire(EV_DROP_EXIT);
+ DDM.activeDrag.fire('drag:exit', { drop: this });
+ delete DDM.otherDrops[this];
+ //if (DDM.activeDrop === this) {
+ // DDM.activeDrop = null;
+ //}
+ }
+ }
+ }
+ }
+ });
+
+ Y.DD.Drop = Drop;
+
+
+
+
+
+}, '3.0.0' ,{requires:['dd-ddm-drop', 'dd-drag'], skinnable:false});
diff --git a/lib/yui/3.0.0/dd/dd-min.js b/lib/yui/3.0.0/dd/dd-min.js
new file mode 100644
index 0000000000..9ad1a52417
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-min.js
@@ -0,0 +1,12 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("dd-ddm-base",function(B){var A=function(){A.superclass.constructor.apply(this,arguments);};A.NAME="ddm";A.ATTRS={dragCursor:{value:"move"},clickPixelThresh:{value:3},clickTimeThresh:{value:1000},dragMode:{value:"point",setter:function(C){this._setDragMode(C);return C;}}};B.extend(A,B.Base,{_active:null,_setDragMode:function(C){if(C===null){C=B.DD.DDM.get("dragMode");}switch(C){case 1:case"intersect":return 1;case 2:case"strict":return 2;case 0:case"point":return 0;}return 0;},CSS_PREFIX:"yui-dd",_activateTargets:function(){},_drags:[],activeDrag:false,_regDrag:function(C){if(this.getDrag(C.get("node"))){return false;}if(!this._active){this._setupListeners();}this._drags.push(C);return true;},_unregDrag:function(D){var C=[];B.each(this._drags,function(F,E){if(F!==D){C[C.length]=F;}});this._drags=C;},_setupListeners:function(){this._active=true;var C=B.get(document);C.on("mousemove",B.bind(this._move,this));C.on("mouseup",B.bind(this._end,this));},_start:function(){this.fire("ddm:start");this._startDrag();},_startDrag:function(){},_endDrag:function(){},_dropMove:function(){},_end:function(){if(this.activeDrag){this._endDrag();this.fire("ddm:end");this.activeDrag.end.call(this.activeDrag);this.activeDrag=null;}},stopDrag:function(){if(this.activeDrag){this._end();}return this;},_move:function(C){if(this.activeDrag){this.activeDrag._move.call(this.activeDrag,C);this._dropMove();}},cssSizestoObject:function(D){var C=D.split(" ");switch(C.length){case 1:C[1]=C[2]=C[3]=C[0];break;case 2:C[2]=C[0];C[3]=C[1];break;case 3:C[3]=C[1];break;}return{top:parseInt(C[0],10),right:parseInt(C[1],10),bottom:parseInt(C[2],10),left:parseInt(C[3],10)};},getDrag:function(D){var C=false,E=B.get(D);if(E instanceof B.Node){B.each(this._drags,function(G,F){if(E.compareTo(G.get("node"))){C=G;}});}return C;}});B.namespace("DD");B.DD.DDM=new A();},"3.0.0",{requires:["node","base"],skinnable:false});YUI.add("dd-ddm",function(A){A.mix(A.DD.DDM,{_pg:null,_debugShim:false,_activateTargets:function(){},_deactivateTargets:function(){},_startDrag:function(){if(this.activeDrag.get("useShim")){this._pg_activate();this._activateTargets();}},_endDrag:function(){this._pg_deactivate();this._deactivateTargets();},_pg_deactivate:function(){this._pg.setStyle("display","none");},_pg_activate:function(){var B=this.activeDrag.get("activeHandle"),C="auto";if(B){C=B.getStyle("cursor");}if(C=="auto"){C=this.get("dragCursor");}this._pg_size();this._pg.setStyles({top:0,left:0,display:"block",opacity:((this._debugShim)?".5":"0"),cursor:C});},_pg_size:function(){if(this.activeDrag){var B=A.get("body"),D=B.get("docHeight"),C=B.get("docWidth");this._pg.setStyles({height:D+"px",width:C+"px"});}},_createPG:function(){var D=A.Node.create(""),B=A.get("body");D.setStyles({top:"0",left:"0",position:"absolute",zIndex:"9999",overflow:"hidden",backgroundColor:"red",display:"none",height:"5px",width:"5px"});D.set("id",A.stamp(D));D.addClass("yui-dd-shim");if(B.get("firstChild")){B.insertBefore(D,B.get("firstChild"));}else{B.appendChild(D);}this._pg=D;this._pg.on("mouseup",A.bind(this._end,this));this._pg.on("mousemove",A.bind(this._move,this));var C=A.get(window);A.on("window:resize",A.bind(this._pg_size,this));C.on("scroll",A.bind(this._pg_size,this));}},true);A.on("domready",A.bind(A.DD.DDM._createPG,A.DD.DDM));},"3.0.0",{requires:["dd-ddm-base","event-resize"],skinnable:false});YUI.add("dd-ddm-drop",function(A){A.mix(A.DD.DDM,{_noShim:false,_activeShims:[],_hasActiveShim:function(){if(this._noShim){return true;}return this._activeShims.length;},_addActiveShim:function(B){this._activeShims[this._activeShims.length]=B;},_removeActiveShim:function(C){var B=[];A.each(this._activeShims,function(E,D){if(E._yuid!==C._yuid){B[B.length]=E;}});this._activeShims=B;},syncActiveShims:function(B){A.later(0,this,function(C){var D=((C)?this.targets:this._lookup());A.each(D,function(F,E){F.sizeShim.call(F);},this);},B);},mode:0,POINT:0,INTERSECT:1,STRICT:2,useHash:true,activeDrop:null,validDrops:[],otherDrops:{},targets:[],_addValid:function(B){this.validDrops[this.validDrops.length]=B;return this;},_removeValid:function(B){var C=[];A.each(this.validDrops,function(E,D){if(E!==B){C[C.length]=E;}});this.validDrops=C;return this;},isOverTarget:function(C){if(this.activeDrag&&C){var F=this.activeDrag.mouseXY,E,B=this.activeDrag.get("dragMode"),D;if(F&&this.activeDrag){D=this.activeDrag.region;if(B==this.STRICT){return this.activeDrag.get("dragNode").inRegion(C.region,true,D);}else{if(C&&C.shim){if((B==this.INTERSECT)&&this._noShim){E=((D)?D:this.activeDrag.get("node"));return C.get("node").intersect(E).inRegion;}else{return C.shim.intersect({top:F[1],bottom:F[1],left:F[0],right:F[0]},C.region).inRegion;}}else{return false;}}}else{return false;}}else{return false;}},clearCache:function(){this.validDrops=[];this.otherDrops={};this._activeShims=[];},_activateTargets:function(){this.clearCache();A.each(this.targets,function(C,B){C._activateShim.apply(C,[]);},this);this._handleTargetOver();},getBestMatch:function(F,D){var C=null,E=0,B;A.each(F,function(I,H){var G=this.activeDrag.get("dragNode").intersect(I.get("node"));I.region.area=G.area;if(G.inRegion){if(G.area>E){E=G.area;C=I;}}},this);if(D){B=[];A.each(F,function(H,G){if(H!==C){B[B.length]=H;}},this);return[C,B];}else{return C;}},_deactivateTargets:function(){var B=[],C,E=this.activeDrag,D=this.activeDrop;if(E&&D&&this.otherDrops[D]){if(!E.get("dragMode")){B=this.otherDrops;delete B[D];}else{C=this.getBestMatch(this.otherDrops,true);D=C[0];B=C[1];}E.get("node").removeClass(this.CSS_PREFIX+"-drag-over");if(D){D.fire("drop:hit",{drag:E,drop:D,others:B});E.fire("drag:drophit",{drag:E,drop:D,others:B});}}else{if(E){E.get("node").removeClass(this.CSS_PREFIX+"-drag-over");E.fire("drag:dropmiss",{pageX:E.lastXY[0],pageY:E.lastXY[1]});}else{}}this.activeDrop=null;A.each(this.targets,function(G,F){G._deactivateShim.apply(G,[]);},this);},_dropMove:function(){if(this._hasActiveShim()){this._handleTargetOver();
+}else{A.each(this.otherDrops,function(C,B){C._handleOut.apply(C,[]);});}},_lookup:function(){if(!this.useHash||this._noShim){return this.validDrops;}var B=[];A.each(this.validDrops,function(D,C){if(D.shim&&D.shim.inViewportRegion(false,D.region)){B[B.length]=D;}});return B;},_handleTargetOver:function(){var B=this._lookup();A.each(B,function(D,C){D._handleTargetOver.call(D);},this);},_regTarget:function(B){this.targets[this.targets.length]=B;},_unregTarget:function(C){var B=[],D;A.each(this.targets,function(F,E){if(F!=C){B[B.length]=F;}},this);this.targets=B;D=[];A.each(this.validDrops,function(F,E){if(F!==C){D[D.length]=F;}});this.validDrops=D;},getDrop:function(C){var B=false,D=A.Node.get(C);if(D instanceof A.Node){A.each(this.targets,function(F,E){if(D.compareTo(F.get("node"))){B=F;}});}return B;}},true);},"3.0.0",{requires:["dd-ddm"],skinnable:false});YUI.add("dd-drag",function(D){var E=D.DD.DDM,U="node",G="dragging",N="dragNode",C="offsetHeight",K="offsetWidth",S="mouseup",P="mousedown",M="dragstart",H="drag:mouseDown",B="drag:afterMouseDown",F="drag:removeHandle",L="drag:addHandle",R="drag:removeInvalid",T="drag:addInvalid",J="drag:start",I="drag:end",O="drag:drag",Q="drag:align",A=function(W){this._lazyAddAttrs=false;A.superclass.constructor.apply(this,arguments);var V=E._regDrag(this);if(!V){D.error("Failed to register node, already in use: "+W.node);}};A.NAME="drag";A.ATTRS={node:{setter:function(V){var W=D.get(V);if(!W){D.error("DD.Drag: Invalid Node Given: "+V);}else{W=W.item(0);}return W;}},dragNode:{setter:function(V){var W=D.Node.get(V);if(!W){D.error("DD.Drag: Invalid dragNode Given: "+V);}return W;}},offsetNode:{value:true},clickPixelThresh:{value:E.get("clickPixelThresh")},clickTimeThresh:{value:E.get("clickTimeThresh")},lock:{value:false,setter:function(V){if(V){this.get(U).addClass(E.CSS_PREFIX+"-locked");}else{this.get(U).removeClass(E.CSS_PREFIX+"-locked");}return V;}},data:{value:false},move:{value:true},useShim:{value:true},activeHandle:{value:false},primaryButtonOnly:{value:true},dragging:{value:false},parent:{value:false},target:{value:false,setter:function(V){this._handleTarget(V);return V;}},dragMode:{value:null,setter:function(V){return E._setDragMode(V);}},groups:{value:["default"],getter:function(){if(!this._groups){this._groups={};}var V=[];D.each(this._groups,function(X,W){V[V.length]=W;});return V;},setter:function(V){this._groups={};D.each(V,function(X,W){this._groups[X]=true;},this);return V;}},handles:{value:null,setter:function(V){if(V){this._handles={};D.each(V,function(X,W){this._handles[X]=true;},this);}else{this._handles=null;}return V;}},bubbles:{writeOnce:true,value:D.DD.DDM}};D.extend(A,D.Base,{addToGroup:function(V){this._groups[V]=true;E._activateTargets();return this;},removeFromGroup:function(V){delete this._groups[V];E._activateTargets();return this;},target:null,_handleTarget:function(V){if(D.DD.Drop){if(V===false){if(this.target){E._unregTarget(this.target);this.target=null;}return false;}else{if(!D.Lang.isObject(V)){V={};}V.bubbles=("bubbles" in V)?V.bubbles:this.get("bubbles");V.node=this.get(U);V.groups=V.groups||this.get("groups");this.target=new D.DD.Drop(V);}}else{return false;}},_groups:null,_createEvents:function(){this.publish(H,{defaultFn:this._defMouseDownFn,queuable:false,emitFacade:true,bubbles:true,prefix:"drag"});this.publish(Q,{defaultFn:this._defAlignFn,queuable:false,emitFacade:true,bubbles:true,prefix:"drag"});this.publish(O,{defaultFn:this._defDragFn,queuable:false,emitFacade:true,bubbles:true,prefix:"drag"});this.publish(I,{preventedFn:this._prevEndFn,queuable:false,emitFacade:true,bubbles:true,prefix:"drag"});var V=[B,F,L,R,T,J,"drag:drophit","drag:dropmiss","drag:over","drag:enter","drag:exit"];D.each(V,function(X,W){this.publish(X,{type:X,emitFacade:true,bubbles:true,preventable:false,queuable:false,prefix:"drag"});},this);if(this.get("bubbles")){this.addTarget(this.get("bubbles"));}},_ev_md:null,_startTime:null,_endTime:null,_handles:null,_invalids:null,_invalidsDefault:{"textarea":true,"input":true,"a":true,"button":true,"select":true},_dragThreshMet:null,_fromTimeout:null,_clickTimeout:null,deltaXY:null,startXY:null,nodeXY:null,lastXY:null,actXY:null,realXY:null,mouseXY:null,region:null,_handleMouseUp:function(V){this._fixIEMouseUp();if(E.activeDrag){E._end();}},_fixDragStart:function(V){V.preventDefault();},_ieSelectFix:function(){return false;},_ieSelectBack:null,_fixIEMouseDown:function(){if(D.UA.ie){this._ieSelectBack=D.config.doc.body.onselectstart;D.config.doc.body.onselectstart=this._ieSelectFix;}},_fixIEMouseUp:function(){if(D.UA.ie){D.config.doc.body.onselectstart=this._ieSelectBack;}},_handleMouseDownEvent:function(V){this.fire(H,{ev:V});},_defMouseDownFn:function(W){var V=W.ev;this._dragThreshMet=false;this._ev_md=V;if(this.get("primaryButtonOnly")&&V.button>1){return false;}if(this.validClick(V)){this._fixIEMouseDown();V.halt();this._setStartPosition([V.pageX,V.pageY]);E.activeDrag=this;this._clickTimeout=D.later(this.get("clickTimeThresh"),this,this._timeoutCheck);}this.fire(B,{ev:V});},validClick:function(Z){var Y=false,b=false,V=Z.target,X=null,W=null,a=false;if(this._handles){D.each(this._handles,function(c,d){if(D.Lang.isString(d)){if(V.test(d+", "+d+" *")&&!X){X=d;Y=true;}}});}else{b=this.get(U);if(b.contains(V)||b.compareTo(V)){Y=true;}}if(Y){if(this._invalids){D.each(this._invalids,function(c,d){if(D.Lang.isString(d)){if(V.test(d+", "+d+" *")){Y=false;}}});}}if(Y){if(X){W=Z.currentTarget.queryAll(X);a=false;W.each(function(d,c){if((d.contains(V)||d.compareTo(V))&&!a){a=true;this.set("activeHandle",d);}},this);}else{this.set("activeHandle",this.get(U));}}return Y;},_setStartPosition:function(V){this.startXY=V;this.nodeXY=this.lastXY=this.realXY=this.get(U).getXY();if(this.get("offsetNode")){this.deltaXY=[(this.startXY[0]-this.nodeXY[0]),(this.startXY[1]-this.nodeXY[1])];}else{this.deltaXY=[0,0];}},_timeoutCheck:function(){if(!this.get("lock")&&!this._dragThreshMet){this._fromTimeout=this._dragThreshMet=true;
+this.start();this._alignNode([this._ev_md.pageX,this._ev_md.pageY],true);}},removeHandle:function(V){if(this._handles[V]){delete this._handles[V];this.fire(F,{handle:V});}return this;},addHandle:function(V){if(!this._handles){this._handles={};}if(D.Lang.isString(V)){this._handles[V]=true;this.fire(L,{handle:V});}return this;},removeInvalid:function(V){if(this._invalids[V]){this._invalids[V]=null;delete this._invalids[V];this.fire(R,{handle:V});}return this;},addInvalid:function(V){if(D.Lang.isString(V)){this._invalids[V]=true;this.fire(T,{handle:V});}return this;},initializer:function(){this.get(U).dd=this;if(!this.get(U).get("id")){var V=D.stamp(this.get(U));this.get(U).set("id",V);}this.actXY=[];this._invalids=D.clone(this._invalidsDefault,true);this._createEvents();if(!this.get(N)){this.set(N,this.get(U));}this.on("initializedChange",D.bind(this._prep,this));this.set("groups",this.get("groups"));},_prep:function(){this._dragThreshMet=false;var V=this.get(U);V.addClass(E.CSS_PREFIX+"-draggable");V.on(P,D.bind(this._handleMouseDownEvent,this));V.on(S,D.bind(this._handleMouseUp,this));V.on(M,D.bind(this._fixDragStart,this));},_unprep:function(){var V=this.get(U);V.removeClass(E.CSS_PREFIX+"-draggable");V.detachAll();},start:function(){if(!this.get("lock")&&!this.get(G)){var W=this.get(U),V=W.get(K),X=W.get(C);this._startTime=(new Date()).getTime();E._start();W.addClass(E.CSS_PREFIX+"-dragging");this.fire(J,{pageX:this.nodeXY[0],pageY:this.nodeXY[1],startTime:this._startTime});var Y=this.nodeXY;this.region={"0":Y[0],"1":Y[1],area:0,top:Y[1],right:Y[0]+V,bottom:Y[1]+X,left:Y[0]};this.set(G,true);}return this;},end:function(){this._endTime=(new Date()).getTime();if(this._clickTimeout){this._clickTimeout.cancel();}this._dragThreshMet=false;this._fromTimeout=false;if(!this.get("lock")&&this.get(G)){this.fire(I,{pageX:this.lastXY[0],pageY:this.lastXY[1],startTime:this._startTime,endTime:this._endTime});}this.get(U).removeClass(E.CSS_PREFIX+"-dragging");this.set(G,false);this.deltaXY=[0,0];return this;},_prevEndFn:function(V){this.get(N).setXY(this.nodeXY);},_align:function(V){this.fire(Q,{pageX:V[0],pageY:V[1]});},_defAlignFn:function(V){this.actXY=[V.pageX-this.deltaXY[0],V.pageY-this.deltaXY[1]];},_alignNode:function(V){this._align(V);this._moveNode();},_moveNode:function(V){var W=[],X=[],Z=this.nodeXY,Y=this.actXY;W[0]=(Y[0]-this.lastXY[0]);W[1]=(Y[1]-this.lastXY[1]);X[0]=(Y[0]-this.nodeXY[0]);X[1]=(Y[1]-this.nodeXY[1]);this.region={"0":Y[0],"1":Y[1],area:0,top:Y[1],right:Y[0]+this.get(N).get(K),bottom:Y[1]+this.get(N).get(C),left:Y[0]};this.fire(O,{pageX:Y[0],pageY:Y[1],scroll:V,info:{start:Z,xy:Y,delta:W,offset:X}});this.lastXY=Y;},_defDragFn:function(V){if(this.get("move")){if(V.scroll){V.scroll.node.set("scrollTop",V.scroll.top);V.scroll.node.set("scrollLeft",V.scroll.left);}this.get(N).setXY([V.pageX,V.pageY]);this.realXY=[V.pageX,V.pageY];}},_move:function(X){if(this.get("lock")){return false;}else{this.mouseXY=[X.pageX,X.pageY];if(!this._dragThreshMet){var W=Math.abs(this.startXY[0]-X.pageX),V=Math.abs(this.startXY[1]-X.pageY);if(W>this.get("clickPixelThresh")||V>this.get("clickPixelThresh")){this._dragThreshMet=true;this.start();this._alignNode([X.pageX,X.pageY]);}}else{if(this._clickTimeout){this._clickTimeout.cancel();}this._alignNode([X.pageX,X.pageY]);}}},stopDrag:function(){if(this.get(G)){E._end();}return this;},destructor:function(){this._unprep();this.detachAll();if(this.target){this.target.destroy();}E._unregDrag(this);}});D.namespace("DD");D.DD.Drag=A;},"3.0.0",{requires:["dd-ddm-base"],skinnable:false});YUI.add("dd-proxy",function(H){var F=H.DD.DDM,B="node",C="dragNode",A="host",D=true;var G=function(I){G.superclass.constructor.apply(this,arguments);};G.NAME="DDProxy";G.NS="proxy";G.ATTRS={host:{},moveOnEnd:{value:D},hideOnEnd:{value:D},resizeFrame:{value:D},positionProxy:{value:D},borderStyle:{value:"1px solid #808080"}};var E={_hands:null,_init:function(){if(!F._proxy){H.on("domready",H.bind(this._init,this));return;}if(!this._hands){this._hands=[];}var K,L,J,M=this.get(A),I=M.get(C);if(I.compareTo(M.get(B))){if(F._proxy){M.set(C,F._proxy);}}H.each(this._hands,function(N){N.detach();});L=F.on("ddm:start",H.bind(function(){if(F.activeDrag===M){F._setFrame(M);}},this));J=F.on("ddm:end",H.bind(function(){if(M.get("dragging")){if(this.get("moveOnEnd")){M.get(B).setXY(M.lastXY);}if(this.get("hideOnEnd")){M.get(C).setStyle("display","none");}}},this));this._hands=[L,J];},initializer:function(){this._init();},destructor:function(){var I=this.get(A);H.each(this._hands,function(J){J.detach();});I.set(C,I.get(B));}};H.namespace("Plugin");H.extend(G,H.Base,E);H.Plugin.DDProxy=G;H.mix(F,{_createFrame:function(){if(!F._proxy){F._proxy=D;var J=H.Node.create(""),I=H.Node.get("body");J.setStyles({position:"absolute",display:"none",zIndex:"999",top:"-999px",left:"-999px"});I.insertBefore(J,I.get("firstChild"));J.set("id",H.stamp(J));J.addClass(F.CSS_PREFIX+"-proxy");F._proxy=J;}},_setFrame:function(J){var M=J.get(B),L=J.get(C),I,K="auto";if(J.proxy.get("resizeFrame")){F._proxy.setStyles({height:M.get("offsetHeight")+"px",width:M.get("offsetWidth")+"px"});}I=F.activeDrag.get("activeHandle");if(I){K=I.getStyle("cursor");}if(K=="auto"){K=F.get("dragCursor");}L.setStyles({visibility:"hidden",display:"block",cursor:K,border:J.proxy.get("borderStyle")});if(J.proxy.get("positionProxy")){L.setXY(J.nodeXY);}L.setStyle("visibility","visible");}});H.on("domready",H.bind(F._createFrame,F));},"3.0.0",{requires:["dd-ddm","dd-drag"],skinnable:false});YUI.add("dd-constrain",function(B){var K="dragNode",M="offsetHeight",F="offsetWidth",Q="host",P="constrain2region",H="constrain2node",G="tickXArray",O="tickYArray",N=B.DD.DDM,E="top",J="right",L="bottom",D="left",I=null;var A=function(C){A.superclass.constructor.apply(this,arguments);};A.NAME="DragConstrained";A.NS="con";A.ATTRS={host:{},stickX:{value:false},stickY:{value:false},tickX:{value:false},tickY:{value:false},tickXArray:{value:false},tickYArray:{value:false},constrain2region:{value:false,getter:function(C){if(B.Lang.isObject(C)){var R={};
+B.mix(R,C);return R;}else{return false;}},setter:function(C){if(B.Lang.isObject(C)){if(B.Lang.isNumber(C[E])&&B.Lang.isNumber(C[J])&&B.Lang.isNumber(C[D])&&B.Lang.isNumber(C[L])){var R={};B.mix(R,C);return R;}else{return false;}}else{if(C!==false){return false;}}return C;}},gutter:{value:"0",setter:function(C){return B.DD.DDM.cssSizestoObject(C);}},constrain2node:{value:false,setter:function(R){if(!this.get(P)){var C=B.Node.get(R);if(C){return C;}}else{if(this.get(P)!==false){}}return false;}},constrain2view:{value:false}};I={initializer:function(){this.get(Q).on("drag:start",B.bind(this._handleStart,this));this.get(Q).after("drag:align",B.bind(this.align,this));},_handleStart:function(){this._regionCache=null;},_regionCache:null,_cacheRegion:function(){this._regionCache=this.get(H).get("region");},getRegion:function(V){var T={},U=null,C=null,S=this.get("gutter"),R=this.get(Q);if(this.get(H)){if(!this._regionCache){B.on("resize",B.bind(this._cacheRegion,this),window);this._cacheRegion();}T=B.clone(this._regionCache);}else{if(this.get(P)){T=this.get(P);}else{if(this.get("constrain2view")){T=R.get(K).get("viewportRegion");}else{return false;}}}B.each(S,function(W,X){if((X==J)||(X==L)){T[X]-=W;}else{T[X]+=W;}});if(V){U=R.get(K).get(M);C=R.get(K).get(F);T[J]=T[J]-C;T[L]=T[L]-U;}return T;},_checkRegion:function(C){var S=C,U=this.getRegion(),T=this.get(Q),V=T.get(K).get(M),R=T.get(K).get(F);if(S[1]>(U[L]-V)){C[1]=(U[L]-V);}if(U[E]>S[1]){C[1]=U[E];}if(S[0]>(U[J]-R)){C[0]=(U[J]-R);}if(U[D]>S[0]){C[0]=U[D];}return C;},inRegion:function(S){S=S||this.get(Q).get(K).getXY();var R=this._checkRegion([S[0],S[1]]),C=false;if((S[0]===R[0])&&(S[1]===R[1])){C=true;}return C;},align:function(){var S=this.get(Q),C=S.actXY,R=this.getRegion(true);if(this.get("stickX")){C[1]=(S.startXY[1]-S.deltaXY[1]);}if(this.get("stickY")){C[0]=(S.startXY[0]-S.deltaXY[0]);}if(R){C=this._checkRegion(C);}C=this._checkTicks(C,R);S.actXY=C;},_checkTicks:function(W,U){var T=this.get(Q),V=(T.startXY[0]-T.deltaXY[0]),S=(T.startXY[1]-T.deltaXY[1]),C=this.get("tickX"),R=this.get("tickY");if(C&&!this.get(G)){W[0]=N._calcTicks(W[0],V,C,U[D],U[J]);}if(R&&!this.get(O)){W[1]=N._calcTicks(W[1],S,R,U[E],U[L]);}if(this.get(G)){W[0]=N._calcTickArray(W[0],this.get(G),U[D],U[J]);}if(this.get(O)){W[1]=N._calcTickArray(W[1],this.get(O),U[E],U[L]);}return W;}};B.namespace("Plugin");B.extend(A,B.Base,I);B.Plugin.DDConstrained=A;B.mix(N,{_calcTicks:function(X,W,T,V,U){var R=((X-W)/T),S=Math.floor(R),C=Math.ceil(R);if((S!==0)||(C!==0)){if((R>=S)&&(R<=C)){X=(W+(T*S));if(V&&U){if(XU){X=(W+(T*(S-1)));}}}}return X;},_calcTickArray:function(Y,Z,X,U){var R=0,V=Z.length,T=0,S,C,W;if(!Z||(Z.length===0)){return Y;}else{if(Z[0]>=Y){return Z[0];}else{for(R=0;R=Y){S=Y-Z[R];C=Z[T]-Y;W=(C>S)?Z[R]:Z[T];if(X&&U){if(W>U){if(Z[R]){W=Z[R];}else{W=Z[V-1];}}}return W;}}return Z[Z.length-1];}}}});},"3.0.0",{requires:["dd-drag"],skinnable:false});YUI.add("dd-scroll",function(C){var H=function(){H.superclass.constructor.apply(this,arguments);},L="host",A="buffer",J="parentScroll",G="windowScroll",I="scrollTop",F="scrollLeft",E="offsetWidth",K="offsetHeight";H.ATTRS={parentScroll:{value:false,setter:function(M){if(M){return M;}return false;}},buffer:{value:30},scrollDelay:{value:235},host:{value:null},windowScroll:{value:false},vertical:{value:true},horizontal:{value:true}};C.extend(H,C.Base,{_scrolling:null,_vpRegionCache:null,_dimCache:null,_scrollTimer:null,_getVPRegion:function(){var M={};var N=this.get(J),R=this.get(A),Q=this.get(G),U=((Q)?[]:N.getXY()),S=((Q)?"winWidth":E),P=((Q)?"winHeight":K),T=((Q)?N.get(I):U[1]),O=((Q)?N.get(F):U[0]);M={top:T+R,right:(N.get(S)+O)-R,bottom:(N.get(P)+T)-R,left:O+R};this._vpRegionCache=M;return M;},initializer:function(){var M=this.get(L);M.after("drag:start",C.bind(this.start,this));M.after("drag:end",C.bind(this.end,this));M.on("drag:align",C.bind(this.align,this));C.get(window).on("scroll",C.bind(function(){this._vpRegionCache=null;},this));},_checkWinScroll:function(Y){var X=this._getVPRegion(),M=this.get(L),O=this.get(G),S=M.lastXY,N=false,e=this.get(A),R=this.get(J),g=R.get(I),U=R.get(F),V=this._dimCache.w,a=this._dimCache.h,T=S[1]+a,W=S[1],d=S[0]+V,Q=S[0],f=W,P=Q,Z=g,c=U;if(this.get("horizontal")){if(Q<=X.left){N=true;P=S[0]-((O)?e:0);c=U-e;}if(d>=X.right){N=true;P=S[0]+((O)?e:0);c=U+e;}}if(this.get("vertical")){if(T>=X.bottom){N=true;f=S[1]+((O)?e:0);Z=g+e;}if(W<=X.top){N=true;f=S[1]-((O)?e:0);Z=g-e;}}if(Z<0){Z=0;f=S[1];}if(c<0){c=0;P=S[0];}if(f<0){f=S[1];}if(P<0){P=S[0];}if(Y){M.actXY=[P,f];M._moveNode({node:R,top:Z,left:c});if(!Z&&!c){this._cancelScroll();}}else{if(N){this._initScroll();}else{this._cancelScroll();}}},_initScroll:function(){this._cancelScroll();this._scrollTimer=C.Lang.later(this.get("scrollDelay"),this,this._checkWinScroll,[true],true);},_cancelScroll:function(){this._scrolling=false;if(this._scrollTimer){this._scrollTimer.cancel();delete this._scrollTimer;}},align:function(M){if(this._scrolling){this._cancelScroll();M.preventDefault();}if(!this._scrolling){this._checkWinScroll();}},_setDimCache:function(){var M=this.get(L).get("dragNode");this._dimCache={h:M.get(K),w:M.get(E)};},start:function(){this._setDimCache();},end:function(M){this._dimCache=null;this._cancelScroll();},toString:function(){return H.NAME+" #"+this.get("node").get("id");}});C.namespace("Plugin");var B=function(){B.superclass.constructor.apply(this,arguments);};B.ATTRS=C.merge(H.ATTRS,{windowScroll:{value:true,setter:function(M){if(M){this.set(J,C.get(window));}return M;}}});C.extend(B,H,{initializer:function(){this.set("windowScroll",this.get("windowScroll"));}});B.NAME=B.NS="winscroll";C.Plugin.DDWinScroll=B;var D=function(){D.superclass.constructor.apply(this,arguments);};D.ATTRS=C.merge(H.ATTRS,{node:{value:false,setter:function(M){var N=C.get(M);if(!N){if(M!==false){C.error("DDNodeScroll: Invalid Node Given: "+M);}}else{N=N.item(0);this.set(J,N);}return N;}}});C.extend(D,H,{initializer:function(){this.set("node",this.get("node"));
+}});D.NAME=D.NS="nodescroll";C.Plugin.DDNodeScroll=D;C.DD.Scroll=H;},"3.0.0",{skinnable:false,requires:["dd-drag"],optional:["dd-proxy"]});YUI.add("dd-plugin",function(B){var A=function(C){C.node=((B.Widget&&C.host instanceof B.Widget)?C.host.get("boundingBox"):C.host);A.superclass.constructor.apply(this,arguments);};A.NAME="dd-plugin";A.NS="dd";B.extend(A,B.DD.Drag);B.namespace("Plugin");B.Plugin.Drag=A;},"3.0.0",{skinnable:false,requires:["dd-drag"],optional:["dd-constrain","dd-proxy"]});YUI.add("dd-drop",function(A){var B="node",G=A.DD.DDM,F="offsetHeight",C="offsetWidth",I="drop:over",H="drop:enter",D="drop:exit",E=function(){this._lazyAddAttrs=false;E.superclass.constructor.apply(this,arguments);A.on("domready",A.bind(function(){A.later(100,this,this._createShim);},this));G._regTarget(this);};E.NAME="drop";E.ATTRS={node:{setter:function(J){var K=A.Node.get(J);if(!K){A.error("DD.Drop: Invalid Node Given: "+J);}return K;}},groups:{value:["default"],setter:function(J){this._groups={};A.each(J,function(L,K){this._groups[L]=true;},this);return J;}},padding:{value:"0",setter:function(J){return G.cssSizestoObject(J);}},lock:{value:false,setter:function(J){if(J){this.get(B).addClass(G.CSS_PREFIX+"-drop-locked");}else{this.get(B).removeClass(G.CSS_PREFIX+"-drop-locked");}return J;}},bubbles:{writeOnce:true,value:A.DD.DDM}};A.extend(E,A.Base,{_createEvents:function(){var J=[I,H,D,"drop:hit"];A.each(J,function(L,K){this.publish(L,{type:L,emitFacade:true,preventable:false,bubbles:true,queuable:false,prefix:"drop"});},this);if(this.get("bubbles")){this.addTarget(this.get("bubbles"));}},_valid:null,_groups:null,shim:null,region:null,overTarget:null,inGroup:function(J){this._valid=false;var K=false;A.each(J,function(M,L){if(this._groups[M]){K=true;this._valid=true;}},this);return K;},initializer:function(){A.later(100,this,this._createEvents);var J=this.get(B),K;if(!J.get("id")){K=A.stamp(J);J.set("id",K);}J.addClass(G.CSS_PREFIX+"-drop");this.set("groups",this.get("groups"));},destructor:function(){G._unregTarget(this);if(this.shim){this.shim.detachAll();this.shim.get("parentNode").removeChild(this.shim);this.shim=null;}this.get(B).removeClass(G.CSS_PREFIX+"-drop");this.detachAll();},_deactivateShim:function(){if(!this.shim){return false;}this.get(B).removeClass(G.CSS_PREFIX+"-drop-active-valid");this.get(B).removeClass(G.CSS_PREFIX+"-drop-active-invalid");this.get(B).removeClass(G.CSS_PREFIX+"-drop-over");this.shim.setStyles({top:"-999px",left:"-999px",zIndex:"1"});this.overTarget=false;},_activateShim:function(){if(!G.activeDrag){return false;}if(this.get(B)===G.activeDrag.get(B)){return false;}if(this.get("lock")){return false;}var J=this.get(B);if(this.inGroup(G.activeDrag.get("groups"))){J.removeClass(G.CSS_PREFIX+"-drop-active-invalid");J.addClass(G.CSS_PREFIX+"-drop-active-valid");G._addValid(this);this.overTarget=false;this.sizeShim();}else{G._removeValid(this);J.removeClass(G.CSS_PREFIX+"-drop-active-valid");J.addClass(G.CSS_PREFIX+"-drop-active-invalid");}},sizeShim:function(){if(!G.activeDrag){return false;}if(this.get(B)===G.activeDrag.get(B)){return false;}if(this.get("lock")){return false;}if(!this.shim){A.later(100,this,this.sizeShim);return false;}var O=this.get(B),M=O.get(F),K=O.get(C),Q=O.getXY(),P=this.get("padding"),J,N,L;K=K+P.left+P.right;M=M+P.top+P.bottom;Q[0]=Q[0]-P.left;Q[1]=Q[1]-P.top;if(G.activeDrag.get("dragMode")===G.INTERSECT){J=G.activeDrag;N=J.get(B).get(F);L=J.get(B).get(C);M=(M+N);K=(K+L);Q[0]=Q[0]-(L-J.deltaXY[0]);Q[1]=Q[1]-(N-J.deltaXY[1]);}this.shim.setStyles({height:M+"px",width:K+"px",top:Q[1]+"px",left:Q[0]+"px"});this.region={"0":Q[0],"1":Q[1],area:0,top:Q[1],right:Q[0]+K,bottom:Q[1]+M,left:Q[0]};},_createShim:function(){if(!G._pg){A.later(10,this,this._createShim);return;}if(this.shim){return;}var J=A.Node.create('');J.setStyles({height:this.get(B).get(F)+"px",width:this.get(B).get(C)+"px",backgroundColor:"yellow",opacity:".5",zIndex:"1",overflow:"hidden",top:"-900px",left:"-900px",position:"absolute"});G._pg.appendChild(J);this.shim=J;J.on("mouseover",A.bind(this._handleOverEvent,this));J.on("mouseout",A.bind(this._handleOutEvent,this));},_handleTargetOver:function(){if(G.isOverTarget(this)){this.get(B).addClass(G.CSS_PREFIX+"-drop-over");G.activeDrop=this;G.otherDrops[this]=this;if(this.overTarget){G.activeDrag.fire("drag:over",{drop:this,drag:G.activeDrag});this.fire(I,{drop:this,drag:G.activeDrag});}else{this.overTarget=true;this.fire(H,{drop:this,drag:G.activeDrag});G.activeDrag.fire("drag:enter",{drop:this,drag:G.activeDrag});G.activeDrag.get(B).addClass(G.CSS_PREFIX+"-drag-over");}}else{this._handleOut();}},_handleOverEvent:function(){this.shim.setStyle("zIndex","999");G._addActiveShim(this);},_handleOutEvent:function(){this.shim.setStyle("zIndex","1");G._removeActiveShim(this);},_handleOut:function(J){if(!G.isOverTarget(this)||J){if(this.overTarget){this.overTarget=false;if(!J){G._removeActiveShim(this);}if(G.activeDrag){this.get(B).removeClass(G.CSS_PREFIX+"-drop-over");G.activeDrag.get(B).removeClass(G.CSS_PREFIX+"-drag-over");this.fire(D);G.activeDrag.fire("drag:exit",{drop:this});delete G.otherDrops[this];}}}}});A.DD.Drop=E;},"3.0.0",{requires:["dd-ddm-drop","dd-drag"],skinnable:false});YUI.add("dd-drop-plugin",function(A){var B=function(C){C.node=C.host;B.superclass.constructor.apply(this,arguments);};B.NAME="dd-drop-plugin";B.NS="drop";A.extend(B,A.DD.Drop);A.namespace("Plugin");A.Plugin.Drop=B;},"3.0.0",{requires:["dd-drop"],skinnable:false});YUI.add("dd",function(A){},"3.0.0",{use:["dd-ddm-base","dd-ddm","dd-ddm-drop","dd-drag","dd-proxy","dd-constrain","dd-plugin","dd-drop","dd-drop-plugin","dd-scroll"],skinnable:false});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/dd/dd-plugin-debug.js b/lib/yui/3.0.0/dd/dd-plugin-debug.js
new file mode 100644
index 0000000000..c45fb88b81
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-plugin-debug.js
@@ -0,0 +1,53 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dd-plugin', function(Y) {
+
+
+ /**
+ * This is a simple Drag plugin that can be attached to a Node via the plug method.
+ * @module dd
+ * @submodule dd-plugin
+ */
+ /**
+ * This is a simple Drag plugin that can be attached to a Node via the plug method.
+ * @class Drag
+ * @extends DD.Drag
+ * @constructor
+ * @namespace Plugin
+ */
+
+
+ var Drag = function(config) {
+ config.node = ((Y.Widget && config.host instanceof Y.Widget) ? config.host.get('boundingBox') : config.host);
+ Drag.superclass.constructor.apply(this, arguments);
+ };
+
+ /**
+ * @property NAME
+ * @description dd-plugin
+ * @type {String}
+ */
+ Drag.NAME = "dd-plugin";
+
+ /**
+ * @property NS
+ * @description The Drag instance will be placed on the Node instance under the dd namespace. It can be accessed via Node.dd;
+ * @type {String}
+ */
+ Drag.NS = "dd";
+
+
+ Y.extend(Drag, Y.DD.Drag);
+ Y.namespace('Plugin');
+ Y.Plugin.Drag = Drag;
+
+
+
+
+
+}, '3.0.0' ,{skinnable:false, requires:['dd-drag'], optional:['dd-constrain', 'dd-proxy']});
diff --git a/lib/yui/3.0.0/dd/dd-plugin-min.js b/lib/yui/3.0.0/dd/dd-plugin-min.js
new file mode 100644
index 0000000000..209cf6b73d
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-plugin-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("dd-plugin",function(B){var A=function(C){C.node=((B.Widget&&C.host instanceof B.Widget)?C.host.get("boundingBox"):C.host);A.superclass.constructor.apply(this,arguments);};A.NAME="dd-plugin";A.NS="dd";B.extend(A,B.DD.Drag);B.namespace("Plugin");B.Plugin.Drag=A;},"3.0.0",{skinnable:false,requires:["dd-drag"],optional:["dd-constrain","dd-proxy"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/dd/dd-plugin.js b/lib/yui/3.0.0/dd/dd-plugin.js
new file mode 100644
index 0000000000..c45fb88b81
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-plugin.js
@@ -0,0 +1,53 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dd-plugin', function(Y) {
+
+
+ /**
+ * This is a simple Drag plugin that can be attached to a Node via the plug method.
+ * @module dd
+ * @submodule dd-plugin
+ */
+ /**
+ * This is a simple Drag plugin that can be attached to a Node via the plug method.
+ * @class Drag
+ * @extends DD.Drag
+ * @constructor
+ * @namespace Plugin
+ */
+
+
+ var Drag = function(config) {
+ config.node = ((Y.Widget && config.host instanceof Y.Widget) ? config.host.get('boundingBox') : config.host);
+ Drag.superclass.constructor.apply(this, arguments);
+ };
+
+ /**
+ * @property NAME
+ * @description dd-plugin
+ * @type {String}
+ */
+ Drag.NAME = "dd-plugin";
+
+ /**
+ * @property NS
+ * @description The Drag instance will be placed on the Node instance under the dd namespace. It can be accessed via Node.dd;
+ * @type {String}
+ */
+ Drag.NS = "dd";
+
+
+ Y.extend(Drag, Y.DD.Drag);
+ Y.namespace('Plugin');
+ Y.Plugin.Drag = Drag;
+
+
+
+
+
+}, '3.0.0' ,{skinnable:false, requires:['dd-drag'], optional:['dd-constrain', 'dd-proxy']});
diff --git a/lib/yui/3.0.0/dd/dd-proxy-debug.js b/lib/yui/3.0.0/dd/dd-proxy-debug.js
new file mode 100644
index 0000000000..7d49d55647
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-proxy-debug.js
@@ -0,0 +1,225 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dd-proxy', function(Y) {
+
+
+ /**
+ * The Drag & Drop Utility allows you to create a draggable interface efficiently, buffering you from browser-level abnormalities and enabling you to focus on the interesting logic surrounding your particular implementation. This component enables you to create a variety of standard draggable objects with just a few lines of code and then, using its extensive API, add your own specific implementation logic.
+ * @module dd
+ * @submodule dd-proxy
+ */
+ /**
+ * This plugin for dd-drag is for creating a proxy drag node, instead of dragging the original node.
+ * @class DDProxy
+ * @extends Base
+ * @constructor
+ * @namespace Plugin
+ */
+ var DDM = Y.DD.DDM,
+ NODE = 'node',
+ DRAG_NODE = 'dragNode',
+ HOST = 'host',
+ TRUE = true;
+
+ var P = function(config) {
+ P.superclass.constructor.apply(this, arguments);
+ };
+
+ P.NAME = 'DDProxy';
+ /**
+ * @property proxy
+ * @description The Proxy instance will be placed on the Drag instance under the proxy namespace.
+ * @type {String}
+ */
+ P.NS = 'proxy';
+
+ P.ATTRS = {
+ host: {
+ },
+ /**
+ * @attribute moveOnEnd
+ * @description Move the original node at the end of the drag. Default: true
+ * @type Boolean
+ */
+ moveOnEnd: {
+ value: TRUE
+ },
+ /**
+ * @attribute hideOnEnd
+ * @description Hide the drag node at the end of the drag. Default: true
+ * @type Boolean
+ */
+ hideOnEnd: {
+ value: TRUE
+ },
+ /**
+ * @attribute resizeFrame
+ * @description Make the Proxy node assume the size of the original node. Default: true
+ * @type Boolean
+ */
+ resizeFrame: {
+ value: TRUE
+ },
+ /**
+ * @attribute positionProxy
+ * @description Make the Proxy node appear in the same place as the original node. Default: true
+ * @type Boolean
+ */
+ positionProxy: {
+ value: TRUE
+ },
+ /**
+ * @attribute borderStyle
+ * @description The default border style for the border of the proxy. Default: 1px solid #808080
+ * @type Boolean
+ */
+ borderStyle: {
+ value: '1px solid #808080'
+ }
+ };
+
+ var proto = {
+ /**
+ * @private
+ * @property _hands
+ * @description Holds the event handles for setting the proxy
+ */
+ _hands: null,
+ /**
+ * @private
+ * @method _init
+ * @description Handler for the proxy config attribute
+ */
+ _init: function() {
+ if (!DDM._proxy) {
+ Y.on('domready', Y.bind(this._init, this));
+ return;
+ }
+ if (!this._hands) {
+ this._hands = [];
+ }
+ var i, h, h1, host = this.get(HOST), dnode = host.get(DRAG_NODE);
+ if (dnode.compareTo(host.get(NODE))) {
+ if (DDM._proxy) {
+ host.set(DRAG_NODE, DDM._proxy);
+ }
+ }
+ Y.each(this._hands, function(v) {
+ v.detach();
+ });
+ h = DDM.on('ddm:start', Y.bind(function() {
+ if (DDM.activeDrag === host) {
+ DDM._setFrame(host);
+ }
+ }, this));
+ h1 = DDM.on('ddm:end', Y.bind(function() {
+ if (host.get('dragging')) {
+ if (this.get('moveOnEnd')) {
+ host.get(NODE).setXY(host.lastXY);
+ }
+ if (this.get('hideOnEnd')) {
+ host.get(DRAG_NODE).setStyle('display', 'none');
+ }
+ }
+ }, this));
+ this._hands = [h, h1];
+ },
+ initializer: function() {
+ this._init();
+ },
+ destructor: function() {
+ var host = this.get(HOST);
+ Y.each(this._hands, function(v) {
+ v.detach();
+ });
+ host.set(DRAG_NODE, host.get(NODE));
+ }
+ };
+
+ Y.namespace('Plugin');
+ Y.extend(P, Y.Base, proto);
+ Y.Plugin.DDProxy = P;
+
+ //Add a couple of methods to the DDM
+ Y.mix(DDM, {
+ /**
+ * @private
+ * @for DDM
+ * @namespace DD
+ * @method _createFrame
+ * @description Create the proxy element if it doesn't already exist and set the DD.DDM._proxy value
+ */
+ _createFrame: function() {
+ if (!DDM._proxy) {
+ DDM._proxy = TRUE;
+
+ var p = Y.Node.create(''),
+ b = Y.Node.get('body');
+
+ p.setStyles({
+ position: 'absolute',
+ display: 'none',
+ zIndex: '999',
+ top: '-999px',
+ left: '-999px'
+ });
+
+ b.insertBefore(p, b.get('firstChild'));
+ p.set('id', Y.stamp(p));
+ p.addClass(DDM.CSS_PREFIX + '-proxy');
+ DDM._proxy = p;
+ }
+ },
+ /**
+ * @private
+ * @for DDM
+ * @namespace DD
+ * @method _setFrame
+ * @description If resizeProxy is set to true (default) it will resize the proxy element to match the size of the Drag Element.
+ * If positionProxy is set to true (default) it will position the proxy element in the same location as the Drag Element.
+ */
+ _setFrame: function(drag) {
+ var n = drag.get(NODE), d = drag.get(DRAG_NODE), ah, cur = 'auto';
+ if (drag.proxy.get('resizeFrame')) {
+ DDM._proxy.setStyles({
+ height: n.get('offsetHeight') + 'px',
+ width: n.get('offsetWidth') + 'px'
+ });
+ }
+
+ ah = DDM.activeDrag.get('activeHandle');
+ if (ah) {
+ cur = ah.getStyle('cursor');
+ }
+ if (cur == 'auto') {
+ cur = DDM.get('dragCursor');
+ }
+
+
+ d.setStyles({
+ visibility: 'hidden',
+ display: 'block',
+ cursor: cur,
+ border: drag.proxy.get('borderStyle')
+ });
+
+
+
+ if (drag.proxy.get('positionProxy')) {
+ d.setXY(drag.nodeXY);
+ }
+ d.setStyle('visibility', 'visible');
+ }
+ });
+
+ //Create the frame when DOM is ready
+ Y.on('domready', Y.bind(DDM._createFrame, DDM));
+
+
+
+}, '3.0.0' ,{requires:['dd-ddm', 'dd-drag'], skinnable:false});
diff --git a/lib/yui/3.0.0/dd/dd-proxy-min.js b/lib/yui/3.0.0/dd/dd-proxy-min.js
new file mode 100644
index 0000000000..02d0ec02a8
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-proxy-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("dd-proxy",function(H){var F=H.DD.DDM,B="node",C="dragNode",A="host",D=true;var G=function(I){G.superclass.constructor.apply(this,arguments);};G.NAME="DDProxy";G.NS="proxy";G.ATTRS={host:{},moveOnEnd:{value:D},hideOnEnd:{value:D},resizeFrame:{value:D},positionProxy:{value:D},borderStyle:{value:"1px solid #808080"}};var E={_hands:null,_init:function(){if(!F._proxy){H.on("domready",H.bind(this._init,this));return;}if(!this._hands){this._hands=[];}var K,L,J,M=this.get(A),I=M.get(C);if(I.compareTo(M.get(B))){if(F._proxy){M.set(C,F._proxy);}}H.each(this._hands,function(N){N.detach();});L=F.on("ddm:start",H.bind(function(){if(F.activeDrag===M){F._setFrame(M);}},this));J=F.on("ddm:end",H.bind(function(){if(M.get("dragging")){if(this.get("moveOnEnd")){M.get(B).setXY(M.lastXY);}if(this.get("hideOnEnd")){M.get(C).setStyle("display","none");}}},this));this._hands=[L,J];},initializer:function(){this._init();},destructor:function(){var I=this.get(A);H.each(this._hands,function(J){J.detach();});I.set(C,I.get(B));}};H.namespace("Plugin");H.extend(G,H.Base,E);H.Plugin.DDProxy=G;H.mix(F,{_createFrame:function(){if(!F._proxy){F._proxy=D;var J=H.Node.create(""),I=H.Node.get("body");J.setStyles({position:"absolute",display:"none",zIndex:"999",top:"-999px",left:"-999px"});I.insertBefore(J,I.get("firstChild"));J.set("id",H.stamp(J));J.addClass(F.CSS_PREFIX+"-proxy");F._proxy=J;}},_setFrame:function(J){var M=J.get(B),L=J.get(C),I,K="auto";if(J.proxy.get("resizeFrame")){F._proxy.setStyles({height:M.get("offsetHeight")+"px",width:M.get("offsetWidth")+"px"});}I=F.activeDrag.get("activeHandle");if(I){K=I.getStyle("cursor");}if(K=="auto"){K=F.get("dragCursor");}L.setStyles({visibility:"hidden",display:"block",cursor:K,border:J.proxy.get("borderStyle")});if(J.proxy.get("positionProxy")){L.setXY(J.nodeXY);}L.setStyle("visibility","visible");}});H.on("domready",H.bind(F._createFrame,F));},"3.0.0",{requires:["dd-ddm","dd-drag"],skinnable:false});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/dd/dd-proxy.js b/lib/yui/3.0.0/dd/dd-proxy.js
new file mode 100644
index 0000000000..7d49d55647
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-proxy.js
@@ -0,0 +1,225 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dd-proxy', function(Y) {
+
+
+ /**
+ * The Drag & Drop Utility allows you to create a draggable interface efficiently, buffering you from browser-level abnormalities and enabling you to focus on the interesting logic surrounding your particular implementation. This component enables you to create a variety of standard draggable objects with just a few lines of code and then, using its extensive API, add your own specific implementation logic.
+ * @module dd
+ * @submodule dd-proxy
+ */
+ /**
+ * This plugin for dd-drag is for creating a proxy drag node, instead of dragging the original node.
+ * @class DDProxy
+ * @extends Base
+ * @constructor
+ * @namespace Plugin
+ */
+ var DDM = Y.DD.DDM,
+ NODE = 'node',
+ DRAG_NODE = 'dragNode',
+ HOST = 'host',
+ TRUE = true;
+
+ var P = function(config) {
+ P.superclass.constructor.apply(this, arguments);
+ };
+
+ P.NAME = 'DDProxy';
+ /**
+ * @property proxy
+ * @description The Proxy instance will be placed on the Drag instance under the proxy namespace.
+ * @type {String}
+ */
+ P.NS = 'proxy';
+
+ P.ATTRS = {
+ host: {
+ },
+ /**
+ * @attribute moveOnEnd
+ * @description Move the original node at the end of the drag. Default: true
+ * @type Boolean
+ */
+ moveOnEnd: {
+ value: TRUE
+ },
+ /**
+ * @attribute hideOnEnd
+ * @description Hide the drag node at the end of the drag. Default: true
+ * @type Boolean
+ */
+ hideOnEnd: {
+ value: TRUE
+ },
+ /**
+ * @attribute resizeFrame
+ * @description Make the Proxy node assume the size of the original node. Default: true
+ * @type Boolean
+ */
+ resizeFrame: {
+ value: TRUE
+ },
+ /**
+ * @attribute positionProxy
+ * @description Make the Proxy node appear in the same place as the original node. Default: true
+ * @type Boolean
+ */
+ positionProxy: {
+ value: TRUE
+ },
+ /**
+ * @attribute borderStyle
+ * @description The default border style for the border of the proxy. Default: 1px solid #808080
+ * @type Boolean
+ */
+ borderStyle: {
+ value: '1px solid #808080'
+ }
+ };
+
+ var proto = {
+ /**
+ * @private
+ * @property _hands
+ * @description Holds the event handles for setting the proxy
+ */
+ _hands: null,
+ /**
+ * @private
+ * @method _init
+ * @description Handler for the proxy config attribute
+ */
+ _init: function() {
+ if (!DDM._proxy) {
+ Y.on('domready', Y.bind(this._init, this));
+ return;
+ }
+ if (!this._hands) {
+ this._hands = [];
+ }
+ var i, h, h1, host = this.get(HOST), dnode = host.get(DRAG_NODE);
+ if (dnode.compareTo(host.get(NODE))) {
+ if (DDM._proxy) {
+ host.set(DRAG_NODE, DDM._proxy);
+ }
+ }
+ Y.each(this._hands, function(v) {
+ v.detach();
+ });
+ h = DDM.on('ddm:start', Y.bind(function() {
+ if (DDM.activeDrag === host) {
+ DDM._setFrame(host);
+ }
+ }, this));
+ h1 = DDM.on('ddm:end', Y.bind(function() {
+ if (host.get('dragging')) {
+ if (this.get('moveOnEnd')) {
+ host.get(NODE).setXY(host.lastXY);
+ }
+ if (this.get('hideOnEnd')) {
+ host.get(DRAG_NODE).setStyle('display', 'none');
+ }
+ }
+ }, this));
+ this._hands = [h, h1];
+ },
+ initializer: function() {
+ this._init();
+ },
+ destructor: function() {
+ var host = this.get(HOST);
+ Y.each(this._hands, function(v) {
+ v.detach();
+ });
+ host.set(DRAG_NODE, host.get(NODE));
+ }
+ };
+
+ Y.namespace('Plugin');
+ Y.extend(P, Y.Base, proto);
+ Y.Plugin.DDProxy = P;
+
+ //Add a couple of methods to the DDM
+ Y.mix(DDM, {
+ /**
+ * @private
+ * @for DDM
+ * @namespace DD
+ * @method _createFrame
+ * @description Create the proxy element if it doesn't already exist and set the DD.DDM._proxy value
+ */
+ _createFrame: function() {
+ if (!DDM._proxy) {
+ DDM._proxy = TRUE;
+
+ var p = Y.Node.create(''),
+ b = Y.Node.get('body');
+
+ p.setStyles({
+ position: 'absolute',
+ display: 'none',
+ zIndex: '999',
+ top: '-999px',
+ left: '-999px'
+ });
+
+ b.insertBefore(p, b.get('firstChild'));
+ p.set('id', Y.stamp(p));
+ p.addClass(DDM.CSS_PREFIX + '-proxy');
+ DDM._proxy = p;
+ }
+ },
+ /**
+ * @private
+ * @for DDM
+ * @namespace DD
+ * @method _setFrame
+ * @description If resizeProxy is set to true (default) it will resize the proxy element to match the size of the Drag Element.
+ * If positionProxy is set to true (default) it will position the proxy element in the same location as the Drag Element.
+ */
+ _setFrame: function(drag) {
+ var n = drag.get(NODE), d = drag.get(DRAG_NODE), ah, cur = 'auto';
+ if (drag.proxy.get('resizeFrame')) {
+ DDM._proxy.setStyles({
+ height: n.get('offsetHeight') + 'px',
+ width: n.get('offsetWidth') + 'px'
+ });
+ }
+
+ ah = DDM.activeDrag.get('activeHandle');
+ if (ah) {
+ cur = ah.getStyle('cursor');
+ }
+ if (cur == 'auto') {
+ cur = DDM.get('dragCursor');
+ }
+
+
+ d.setStyles({
+ visibility: 'hidden',
+ display: 'block',
+ cursor: cur,
+ border: drag.proxy.get('borderStyle')
+ });
+
+
+
+ if (drag.proxy.get('positionProxy')) {
+ d.setXY(drag.nodeXY);
+ }
+ d.setStyle('visibility', 'visible');
+ }
+ });
+
+ //Create the frame when DOM is ready
+ Y.on('domready', Y.bind(DDM._createFrame, DDM));
+
+
+
+}, '3.0.0' ,{requires:['dd-ddm', 'dd-drag'], skinnable:false});
diff --git a/lib/yui/3.0.0/dd/dd-scroll-debug.js b/lib/yui/3.0.0/dd/dd-scroll-debug.js
new file mode 100644
index 0000000000..4a45666a37
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-scroll-debug.js
@@ -0,0 +1,413 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dd-scroll', function(Y) {
+
+
+ /**
+ * The Drag & Drop Utility allows you to create a draggable interface efficiently, buffering you from browser-level abnormalities and enabling you to focus on the interesting logic surrounding your particular implementation. This component enables you to create a variety of standard draggable objects with just a few lines of code and then, using its extensive API, add your own specific implementation logic.
+ * @module dd
+ * @submodule dd-scroll
+ */
+ /**
+ * This class is the base scroller class used to create the Plugin.DDNodeScroll and Plugin.DDWinScroll.
+ * This class should not be called on it's own, it's designed to be a plugin.
+ * @class Scroll
+ * @extends Base
+ * @namespace DD
+ * @constructor
+ */
+
+ var S = function() {
+ S.superclass.constructor.apply(this, arguments);
+
+ },
+ HOST = 'host',
+ BUFFER = 'buffer',
+ PARENT_SCROLL = 'parentScroll',
+ WINDOW_SCROLL = 'windowScroll',
+ SCROLL_TOP = 'scrollTop',
+ SCROLL_LEFT = 'scrollLeft',
+ OFFSET_WIDTH = 'offsetWidth',
+ OFFSET_HEIGHT = 'offsetHeight';
+
+
+ S.ATTRS = {
+ /**
+ * @attribute parentScroll
+ * @description Internal config option to hold the node that we are scrolling. Should not be set by the developer.
+ * @type Node
+ */
+ parentScroll: {
+ value: false,
+ setter: function(node) {
+ if (node) {
+ return node;
+ }
+ return false;
+ }
+ },
+ /**
+ * @attribute buffer
+ * @description The number of pixels from the edge of the screen to turn on scrolling. Default: 30
+ * @type Number
+ */
+ buffer: {
+ value: 30
+ },
+ /**
+ * @attribute scrollDelay
+ * @description The number of milliseconds delay to pass to the auto scroller. Default: 235
+ * @type Number
+ */
+ scrollDelay: {
+ value: 235
+ },
+ /**
+ * @attribute host
+ * @description The host we are plugged into.
+ * @type Object
+ */
+ host: {
+ value: null
+ },
+ /**
+ * @attribute windowScroll
+ * @description Turn on window scroll support, default: false
+ * @type Boolean
+ */
+ windowScroll: {
+ value: false
+ },
+ /**
+ * @attribute vertical
+ * @description Allow vertical scrolling, default: true.
+ * @type Boolean
+ */
+ vertical: {
+ value: true
+ },
+ /**
+ * @attribute horizontal
+ * @description Allow horizontal scrolling, default: true.
+ * @type Boolean
+ */
+ horizontal: {
+ value: true
+ }
+ };
+
+ Y.extend(S, Y.Base, {
+ /**
+ * @private
+ * @property _scrolling
+ * @description Tells if we are actively scrolling or not.
+ * @type Boolean
+ */
+ _scrolling: null,
+ /**
+ * @private
+ * @property _vpRegionCache
+ * @description Cache of the Viewport dims.
+ * @type Object
+ */
+ _vpRegionCache: null,
+ /**
+ * @private
+ * @property _dimCache
+ * @description Cache of the dragNode dims.
+ * @type Object
+ */
+ _dimCache: null,
+ /**
+ * @private
+ * @property _scrollTimer
+ * @description Holder for the Timer object returned from Y.later.
+ * @type {Y.later}
+ */
+ _scrollTimer: null,
+ /**
+ * @private
+ * @method _getVPRegion
+ * @description Sets the _vpRegionCache property with an Object containing the dims from the viewport.
+ */
+ _getVPRegion: function() {
+ var r = {};
+ //if (!this._vpRegionCache) {
+ var n = this.get(PARENT_SCROLL),
+ b = this.get(BUFFER),
+ ws = this.get(WINDOW_SCROLL),
+ xy = ((ws) ? [] : n.getXY()),
+ w = ((ws) ? 'winWidth' : OFFSET_WIDTH),
+ h = ((ws) ? 'winHeight' : OFFSET_HEIGHT),
+ t = ((ws) ? n.get(SCROLL_TOP) : xy[1]),
+ l = ((ws) ? n.get(SCROLL_LEFT) : xy[0]);
+
+ r = {
+ top: t + b,
+ right: (n.get(w) + l) - b,
+ bottom: (n.get(h) + t) - b,
+ left: l + b
+ };
+ this._vpRegionCache = r;
+ //} else {
+ // r = this._vpRegionCache;
+ //}
+ return r;
+ },
+ initializer: function() {
+ var h = this.get(HOST);
+ h.after('drag:start', Y.bind(this.start, this));
+ h.after('drag:end', Y.bind(this.end, this));
+ h.on('drag:align', Y.bind(this.align, this));
+
+ //TODO - This doesn't work yet??
+ Y.get(window).on('scroll', Y.bind(function() {
+ this._vpRegionCache = null;
+ }, this));
+ },
+ /**
+ * @private
+ * @method _checkWinScroll
+ * @description Check to see if we need to fire the scroll timer. If scroll timer is running this will scroll the window.
+ * @param {Boolean} move Should we move the window. From Y.later
+ */
+ _checkWinScroll: function(move) {
+ var r = this._getVPRegion(),
+ ho = this.get(HOST),
+ ws = this.get(WINDOW_SCROLL),
+ xy = ho.lastXY,
+ scroll = false,
+ b = this.get(BUFFER),
+ win = this.get(PARENT_SCROLL),
+ sTop = win.get(SCROLL_TOP),
+ sLeft = win.get(SCROLL_LEFT),
+ w = this._dimCache.w,
+ h = this._dimCache.h,
+ bottom = xy[1] + h,
+ top = xy[1],
+ right = xy[0] + w,
+ left = xy[0],
+ nt = top,
+ nl = left,
+ st = sTop,
+ sl = sLeft;
+
+ if (this.get('horizontal')) {
+ if (left <= r.left) {
+ scroll = true;
+ nl = xy[0] - ((ws) ? b : 0);
+ sl = sLeft - b;
+ }
+ if (right >= r.right) {
+ scroll = true;
+ nl = xy[0] + ((ws) ? b : 0);
+ sl = sLeft + b;
+ }
+ }
+ if (this.get('vertical')) {
+ if (bottom >= r.bottom) {
+ scroll = true;
+ nt = xy[1] + ((ws) ? b : 0);
+ st = sTop + b;
+
+ }
+ if (top <= r.top) {
+ scroll = true;
+ nt = xy[1] - ((ws) ? b : 0);
+ st = sTop - b;
+ }
+ }
+
+ if (st < 0) {
+ st = 0;
+ nt = xy[1];
+ }
+
+ if (sl < 0) {
+ sl = 0;
+ nl = xy[0];
+ }
+
+ if (nt < 0) {
+ nt = xy[1];
+ }
+ if (nl < 0) {
+ nl = xy[0];
+ }
+ if (move) {
+ ho.actXY = [nl, nt];
+ ho._moveNode({ node: win, top: st, left: sl});
+ if (!st && !sl) {
+ this._cancelScroll();
+ }
+ } else {
+ if (scroll) {
+ this._initScroll();
+ } else {
+ this._cancelScroll();
+ }
+ }
+ },
+ /**
+ * @private
+ * @method _initScroll
+ * @description Cancel a previous scroll timer and init a new one.
+ */
+ _initScroll: function() {
+ this._cancelScroll();
+ this._scrollTimer = Y.Lang.later(this.get('scrollDelay'), this, this._checkWinScroll, [true], true);
+
+ },
+ /**
+ * @private
+ * @method _cancelScroll
+ * @description Cancel a currently running scroll timer.
+ */
+ _cancelScroll: function() {
+ this._scrolling = false;
+ if (this._scrollTimer) {
+ this._scrollTimer.cancel();
+ delete this._scrollTimer;
+ }
+ },
+ /**
+ * @method align
+ * @description Called from the drag:align event to determine if we need to scroll.
+ */
+ align: function(e) {
+ if (this._scrolling) {
+ this._cancelScroll();
+ e.preventDefault();
+ }
+ if (!this._scrolling) {
+ this._checkWinScroll();
+ }
+ },
+ /**
+ * @private
+ * @method _setDimCache
+ * @description Set the cache of the dragNode dims.
+ */
+ _setDimCache: function() {
+ var node = this.get(HOST).get('dragNode');
+ this._dimCache = {
+ h: node.get(OFFSET_HEIGHT),
+ w: node.get(OFFSET_WIDTH)
+ };
+ },
+ /**
+ * @method start
+ * @description Called from the drag:start event
+ */
+ start: function() {
+ this._setDimCache();
+ },
+ /**
+ * @method end
+ * @description Called from the drag:end event
+ */
+ end: function(xy) {
+ this._dimCache = null;
+ this._cancelScroll();
+ },
+ /**
+ * @method toString
+ * @description General toString method for logging
+ * @return String name for the object
+ */
+ toString: function() {
+ return S.NAME + ' #' + this.get('node').get('id');
+ }
+ });
+
+ Y.namespace('Plugin');
+
+
+ /**
+ * Extends the Scroll class to make the window scroll while dragging.
+ * @class DDWindowScroll
+ * @extends DD.Scroll
+ * @namespace Plugin
+ * @constructor
+ */
+ var WS = function() {
+ WS.superclass.constructor.apply(this, arguments);
+ };
+ WS.ATTRS = Y.merge(S.ATTRS, {
+ /**
+ * @attribute windowScroll
+ * @description Turn on window scroll support, default: true
+ * @type Boolean
+ */
+ windowScroll: {
+ value: true,
+ setter: function(scroll) {
+ if (scroll) {
+ this.set(PARENT_SCROLL, Y.get(window));
+ }
+ return scroll;
+ }
+ }
+ });
+ Y.extend(WS, S, {
+ //Shouldn't have to do this..
+ initializer: function() {
+ this.set('windowScroll', this.get('windowScroll'));
+ }
+ });
+ WS.NAME = WS.NS = 'winscroll';
+ Y.Plugin.DDWinScroll = WS;
+
+
+ /**
+ * Extends the Scroll class to make a parent node scroll while dragging.
+ * @class DDNodeScroll
+ * @extends DD.Scroll
+ * @namespace Plugin
+ * @constructor
+ */
+ var NS = function() {
+ NS.superclass.constructor.apply(this, arguments);
+
+ };
+ NS.ATTRS = Y.merge(S.ATTRS, {
+ /**
+ * @attribute node
+ * @description The node we want to scroll. Used to set the internal parentScroll attribute.
+ * @type Node
+ */
+ node: {
+ value: false,
+ setter: function(node) {
+ var n = Y.get(node);
+ if (!n) {
+ if (node !== false) {
+ Y.error('DDNodeScroll: Invalid Node Given: ' + node);
+ }
+ } else {
+ n = n.item(0);
+ this.set(PARENT_SCROLL, n);
+ }
+ return n;
+ }
+ }
+ });
+ Y.extend(NS, S, {
+ //Shouldn't have to do this..
+ initializer: function() {
+ this.set('node', this.get('node'));
+ }
+ });
+ NS.NAME = NS.NS = 'nodescroll';
+ Y.Plugin.DDNodeScroll = NS;
+
+ Y.DD.Scroll = S;
+
+
+
+}, '3.0.0' ,{skinnable:false, requires:['dd-drag'], optional:['dd-proxy']});
diff --git a/lib/yui/3.0.0/dd/dd-scroll-min.js b/lib/yui/3.0.0/dd/dd-scroll-min.js
new file mode 100644
index 0000000000..7de0479e17
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-scroll-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("dd-scroll",function(C){var H=function(){H.superclass.constructor.apply(this,arguments);},L="host",A="buffer",J="parentScroll",G="windowScroll",I="scrollTop",F="scrollLeft",E="offsetWidth",K="offsetHeight";H.ATTRS={parentScroll:{value:false,setter:function(M){if(M){return M;}return false;}},buffer:{value:30},scrollDelay:{value:235},host:{value:null},windowScroll:{value:false},vertical:{value:true},horizontal:{value:true}};C.extend(H,C.Base,{_scrolling:null,_vpRegionCache:null,_dimCache:null,_scrollTimer:null,_getVPRegion:function(){var M={};var N=this.get(J),R=this.get(A),Q=this.get(G),U=((Q)?[]:N.getXY()),S=((Q)?"winWidth":E),P=((Q)?"winHeight":K),T=((Q)?N.get(I):U[1]),O=((Q)?N.get(F):U[0]);M={top:T+R,right:(N.get(S)+O)-R,bottom:(N.get(P)+T)-R,left:O+R};this._vpRegionCache=M;return M;},initializer:function(){var M=this.get(L);M.after("drag:start",C.bind(this.start,this));M.after("drag:end",C.bind(this.end,this));M.on("drag:align",C.bind(this.align,this));C.get(window).on("scroll",C.bind(function(){this._vpRegionCache=null;},this));},_checkWinScroll:function(Y){var X=this._getVPRegion(),M=this.get(L),O=this.get(G),S=M.lastXY,N=false,e=this.get(A),R=this.get(J),g=R.get(I),U=R.get(F),V=this._dimCache.w,a=this._dimCache.h,T=S[1]+a,W=S[1],d=S[0]+V,Q=S[0],f=W,P=Q,Z=g,c=U;if(this.get("horizontal")){if(Q<=X.left){N=true;P=S[0]-((O)?e:0);c=U-e;}if(d>=X.right){N=true;P=S[0]+((O)?e:0);c=U+e;}}if(this.get("vertical")){if(T>=X.bottom){N=true;f=S[1]+((O)?e:0);Z=g+e;}if(W<=X.top){N=true;f=S[1]-((O)?e:0);Z=g-e;}}if(Z<0){Z=0;f=S[1];}if(c<0){c=0;P=S[0];}if(f<0){f=S[1];}if(P<0){P=S[0];}if(Y){M.actXY=[P,f];M._moveNode({node:R,top:Z,left:c});if(!Z&&!c){this._cancelScroll();}}else{if(N){this._initScroll();}else{this._cancelScroll();}}},_initScroll:function(){this._cancelScroll();this._scrollTimer=C.Lang.later(this.get("scrollDelay"),this,this._checkWinScroll,[true],true);},_cancelScroll:function(){this._scrolling=false;if(this._scrollTimer){this._scrollTimer.cancel();delete this._scrollTimer;}},align:function(M){if(this._scrolling){this._cancelScroll();M.preventDefault();}if(!this._scrolling){this._checkWinScroll();}},_setDimCache:function(){var M=this.get(L).get("dragNode");this._dimCache={h:M.get(K),w:M.get(E)};},start:function(){this._setDimCache();},end:function(M){this._dimCache=null;this._cancelScroll();},toString:function(){return H.NAME+" #"+this.get("node").get("id");}});C.namespace("Plugin");var B=function(){B.superclass.constructor.apply(this,arguments);};B.ATTRS=C.merge(H.ATTRS,{windowScroll:{value:true,setter:function(M){if(M){this.set(J,C.get(window));}return M;}}});C.extend(B,H,{initializer:function(){this.set("windowScroll",this.get("windowScroll"));}});B.NAME=B.NS="winscroll";C.Plugin.DDWinScroll=B;var D=function(){D.superclass.constructor.apply(this,arguments);};D.ATTRS=C.merge(H.ATTRS,{node:{value:false,setter:function(M){var N=C.get(M);if(!N){if(M!==false){C.error("DDNodeScroll: Invalid Node Given: "+M);}}else{N=N.item(0);this.set(J,N);}return N;}}});C.extend(D,H,{initializer:function(){this.set("node",this.get("node"));}});D.NAME=D.NS="nodescroll";C.Plugin.DDNodeScroll=D;C.DD.Scroll=H;},"3.0.0",{skinnable:false,requires:["dd-drag"],optional:["dd-proxy"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/dd/dd-scroll.js b/lib/yui/3.0.0/dd/dd-scroll.js
new file mode 100644
index 0000000000..4a45666a37
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd-scroll.js
@@ -0,0 +1,413 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dd-scroll', function(Y) {
+
+
+ /**
+ * The Drag & Drop Utility allows you to create a draggable interface efficiently, buffering you from browser-level abnormalities and enabling you to focus on the interesting logic surrounding your particular implementation. This component enables you to create a variety of standard draggable objects with just a few lines of code and then, using its extensive API, add your own specific implementation logic.
+ * @module dd
+ * @submodule dd-scroll
+ */
+ /**
+ * This class is the base scroller class used to create the Plugin.DDNodeScroll and Plugin.DDWinScroll.
+ * This class should not be called on it's own, it's designed to be a plugin.
+ * @class Scroll
+ * @extends Base
+ * @namespace DD
+ * @constructor
+ */
+
+ var S = function() {
+ S.superclass.constructor.apply(this, arguments);
+
+ },
+ HOST = 'host',
+ BUFFER = 'buffer',
+ PARENT_SCROLL = 'parentScroll',
+ WINDOW_SCROLL = 'windowScroll',
+ SCROLL_TOP = 'scrollTop',
+ SCROLL_LEFT = 'scrollLeft',
+ OFFSET_WIDTH = 'offsetWidth',
+ OFFSET_HEIGHT = 'offsetHeight';
+
+
+ S.ATTRS = {
+ /**
+ * @attribute parentScroll
+ * @description Internal config option to hold the node that we are scrolling. Should not be set by the developer.
+ * @type Node
+ */
+ parentScroll: {
+ value: false,
+ setter: function(node) {
+ if (node) {
+ return node;
+ }
+ return false;
+ }
+ },
+ /**
+ * @attribute buffer
+ * @description The number of pixels from the edge of the screen to turn on scrolling. Default: 30
+ * @type Number
+ */
+ buffer: {
+ value: 30
+ },
+ /**
+ * @attribute scrollDelay
+ * @description The number of milliseconds delay to pass to the auto scroller. Default: 235
+ * @type Number
+ */
+ scrollDelay: {
+ value: 235
+ },
+ /**
+ * @attribute host
+ * @description The host we are plugged into.
+ * @type Object
+ */
+ host: {
+ value: null
+ },
+ /**
+ * @attribute windowScroll
+ * @description Turn on window scroll support, default: false
+ * @type Boolean
+ */
+ windowScroll: {
+ value: false
+ },
+ /**
+ * @attribute vertical
+ * @description Allow vertical scrolling, default: true.
+ * @type Boolean
+ */
+ vertical: {
+ value: true
+ },
+ /**
+ * @attribute horizontal
+ * @description Allow horizontal scrolling, default: true.
+ * @type Boolean
+ */
+ horizontal: {
+ value: true
+ }
+ };
+
+ Y.extend(S, Y.Base, {
+ /**
+ * @private
+ * @property _scrolling
+ * @description Tells if we are actively scrolling or not.
+ * @type Boolean
+ */
+ _scrolling: null,
+ /**
+ * @private
+ * @property _vpRegionCache
+ * @description Cache of the Viewport dims.
+ * @type Object
+ */
+ _vpRegionCache: null,
+ /**
+ * @private
+ * @property _dimCache
+ * @description Cache of the dragNode dims.
+ * @type Object
+ */
+ _dimCache: null,
+ /**
+ * @private
+ * @property _scrollTimer
+ * @description Holder for the Timer object returned from Y.later.
+ * @type {Y.later}
+ */
+ _scrollTimer: null,
+ /**
+ * @private
+ * @method _getVPRegion
+ * @description Sets the _vpRegionCache property with an Object containing the dims from the viewport.
+ */
+ _getVPRegion: function() {
+ var r = {};
+ //if (!this._vpRegionCache) {
+ var n = this.get(PARENT_SCROLL),
+ b = this.get(BUFFER),
+ ws = this.get(WINDOW_SCROLL),
+ xy = ((ws) ? [] : n.getXY()),
+ w = ((ws) ? 'winWidth' : OFFSET_WIDTH),
+ h = ((ws) ? 'winHeight' : OFFSET_HEIGHT),
+ t = ((ws) ? n.get(SCROLL_TOP) : xy[1]),
+ l = ((ws) ? n.get(SCROLL_LEFT) : xy[0]);
+
+ r = {
+ top: t + b,
+ right: (n.get(w) + l) - b,
+ bottom: (n.get(h) + t) - b,
+ left: l + b
+ };
+ this._vpRegionCache = r;
+ //} else {
+ // r = this._vpRegionCache;
+ //}
+ return r;
+ },
+ initializer: function() {
+ var h = this.get(HOST);
+ h.after('drag:start', Y.bind(this.start, this));
+ h.after('drag:end', Y.bind(this.end, this));
+ h.on('drag:align', Y.bind(this.align, this));
+
+ //TODO - This doesn't work yet??
+ Y.get(window).on('scroll', Y.bind(function() {
+ this._vpRegionCache = null;
+ }, this));
+ },
+ /**
+ * @private
+ * @method _checkWinScroll
+ * @description Check to see if we need to fire the scroll timer. If scroll timer is running this will scroll the window.
+ * @param {Boolean} move Should we move the window. From Y.later
+ */
+ _checkWinScroll: function(move) {
+ var r = this._getVPRegion(),
+ ho = this.get(HOST),
+ ws = this.get(WINDOW_SCROLL),
+ xy = ho.lastXY,
+ scroll = false,
+ b = this.get(BUFFER),
+ win = this.get(PARENT_SCROLL),
+ sTop = win.get(SCROLL_TOP),
+ sLeft = win.get(SCROLL_LEFT),
+ w = this._dimCache.w,
+ h = this._dimCache.h,
+ bottom = xy[1] + h,
+ top = xy[1],
+ right = xy[0] + w,
+ left = xy[0],
+ nt = top,
+ nl = left,
+ st = sTop,
+ sl = sLeft;
+
+ if (this.get('horizontal')) {
+ if (left <= r.left) {
+ scroll = true;
+ nl = xy[0] - ((ws) ? b : 0);
+ sl = sLeft - b;
+ }
+ if (right >= r.right) {
+ scroll = true;
+ nl = xy[0] + ((ws) ? b : 0);
+ sl = sLeft + b;
+ }
+ }
+ if (this.get('vertical')) {
+ if (bottom >= r.bottom) {
+ scroll = true;
+ nt = xy[1] + ((ws) ? b : 0);
+ st = sTop + b;
+
+ }
+ if (top <= r.top) {
+ scroll = true;
+ nt = xy[1] - ((ws) ? b : 0);
+ st = sTop - b;
+ }
+ }
+
+ if (st < 0) {
+ st = 0;
+ nt = xy[1];
+ }
+
+ if (sl < 0) {
+ sl = 0;
+ nl = xy[0];
+ }
+
+ if (nt < 0) {
+ nt = xy[1];
+ }
+ if (nl < 0) {
+ nl = xy[0];
+ }
+ if (move) {
+ ho.actXY = [nl, nt];
+ ho._moveNode({ node: win, top: st, left: sl});
+ if (!st && !sl) {
+ this._cancelScroll();
+ }
+ } else {
+ if (scroll) {
+ this._initScroll();
+ } else {
+ this._cancelScroll();
+ }
+ }
+ },
+ /**
+ * @private
+ * @method _initScroll
+ * @description Cancel a previous scroll timer and init a new one.
+ */
+ _initScroll: function() {
+ this._cancelScroll();
+ this._scrollTimer = Y.Lang.later(this.get('scrollDelay'), this, this._checkWinScroll, [true], true);
+
+ },
+ /**
+ * @private
+ * @method _cancelScroll
+ * @description Cancel a currently running scroll timer.
+ */
+ _cancelScroll: function() {
+ this._scrolling = false;
+ if (this._scrollTimer) {
+ this._scrollTimer.cancel();
+ delete this._scrollTimer;
+ }
+ },
+ /**
+ * @method align
+ * @description Called from the drag:align event to determine if we need to scroll.
+ */
+ align: function(e) {
+ if (this._scrolling) {
+ this._cancelScroll();
+ e.preventDefault();
+ }
+ if (!this._scrolling) {
+ this._checkWinScroll();
+ }
+ },
+ /**
+ * @private
+ * @method _setDimCache
+ * @description Set the cache of the dragNode dims.
+ */
+ _setDimCache: function() {
+ var node = this.get(HOST).get('dragNode');
+ this._dimCache = {
+ h: node.get(OFFSET_HEIGHT),
+ w: node.get(OFFSET_WIDTH)
+ };
+ },
+ /**
+ * @method start
+ * @description Called from the drag:start event
+ */
+ start: function() {
+ this._setDimCache();
+ },
+ /**
+ * @method end
+ * @description Called from the drag:end event
+ */
+ end: function(xy) {
+ this._dimCache = null;
+ this._cancelScroll();
+ },
+ /**
+ * @method toString
+ * @description General toString method for logging
+ * @return String name for the object
+ */
+ toString: function() {
+ return S.NAME + ' #' + this.get('node').get('id');
+ }
+ });
+
+ Y.namespace('Plugin');
+
+
+ /**
+ * Extends the Scroll class to make the window scroll while dragging.
+ * @class DDWindowScroll
+ * @extends DD.Scroll
+ * @namespace Plugin
+ * @constructor
+ */
+ var WS = function() {
+ WS.superclass.constructor.apply(this, arguments);
+ };
+ WS.ATTRS = Y.merge(S.ATTRS, {
+ /**
+ * @attribute windowScroll
+ * @description Turn on window scroll support, default: true
+ * @type Boolean
+ */
+ windowScroll: {
+ value: true,
+ setter: function(scroll) {
+ if (scroll) {
+ this.set(PARENT_SCROLL, Y.get(window));
+ }
+ return scroll;
+ }
+ }
+ });
+ Y.extend(WS, S, {
+ //Shouldn't have to do this..
+ initializer: function() {
+ this.set('windowScroll', this.get('windowScroll'));
+ }
+ });
+ WS.NAME = WS.NS = 'winscroll';
+ Y.Plugin.DDWinScroll = WS;
+
+
+ /**
+ * Extends the Scroll class to make a parent node scroll while dragging.
+ * @class DDNodeScroll
+ * @extends DD.Scroll
+ * @namespace Plugin
+ * @constructor
+ */
+ var NS = function() {
+ NS.superclass.constructor.apply(this, arguments);
+
+ };
+ NS.ATTRS = Y.merge(S.ATTRS, {
+ /**
+ * @attribute node
+ * @description The node we want to scroll. Used to set the internal parentScroll attribute.
+ * @type Node
+ */
+ node: {
+ value: false,
+ setter: function(node) {
+ var n = Y.get(node);
+ if (!n) {
+ if (node !== false) {
+ Y.error('DDNodeScroll: Invalid Node Given: ' + node);
+ }
+ } else {
+ n = n.item(0);
+ this.set(PARENT_SCROLL, n);
+ }
+ return n;
+ }
+ }
+ });
+ Y.extend(NS, S, {
+ //Shouldn't have to do this..
+ initializer: function() {
+ this.set('node', this.get('node'));
+ }
+ });
+ NS.NAME = NS.NS = 'nodescroll';
+ Y.Plugin.DDNodeScroll = NS;
+
+ Y.DD.Scroll = S;
+
+
+
+}, '3.0.0' ,{skinnable:false, requires:['dd-drag'], optional:['dd-proxy']});
diff --git a/lib/yui/3.0.0/dd/dd.js b/lib/yui/3.0.0/dd/dd.js
new file mode 100644
index 0000000000..69282f2057
--- /dev/null
+++ b/lib/yui/3.0.0/dd/dd.js
@@ -0,0 +1,3529 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dd-ddm-base', function(Y) {
+
+
+ /**
+ * Provides the base Drag Drop Manger required for making a Node draggable.
+ * @module dd
+ * @submodule dd-ddm-base
+ */
+ /**
+ * Provides the base Drag Drop Manger required for making a Node draggable.
+ * @class DDM
+ * @extends Base
+ * @constructor
+ * @namespace DD
+ */
+
+ var DDMBase = function() {
+ DDMBase.superclass.constructor.apply(this, arguments);
+ };
+
+ DDMBase.NAME = 'ddm';
+
+ DDMBase.ATTRS = {
+ /**
+ * @attribute dragCursor
+ * @description The cursor to apply when dragging, if shimmed the shim will get the cursor.
+ * @type String
+ */
+ dragCursor: {
+ value: 'move'
+ },
+ /**
+ * @attribute clickPixelThresh
+ * @description The number of pixels to move to start a drag operation, default is 3.
+ * @type Number
+ */
+ clickPixelThresh: {
+ value: 3
+ },
+ /**
+ * @attribute clickTimeThresh
+ * @description The number of milliseconds a mousedown has to pass to start a drag operation, default is 1000.
+ * @type Number
+ */
+ clickTimeThresh: {
+ value: 1000
+ },
+ /**
+ * @attribute dragMode
+ * @description This attribute only works if the dd-drop module is active. It will set the dragMode (point, intersect, strict) of all future Drag instances.
+ * @type String
+ */
+ dragMode: {
+ value: 'point',
+ setter: function(mode) {
+ this._setDragMode(mode);
+ return mode;
+ }
+ }
+
+ };
+
+ Y.extend(DDMBase, Y.Base, {
+ /**
+ * @property _active
+ * @description flag set when we activate our first drag, so DDM can start listening for events.
+ * @type {Boolean}
+ */
+ _active: null,
+ /**
+ * @private
+ * @method _setDragMode
+ * @description Handler for dragMode attribute setter.
+ * @param String/Number The Number value or the String for the DragMode to default all future drag instances to.
+ * @return Number The Mode to be set
+ */
+ _setDragMode: function(mode) {
+ if (mode === null) {
+ mode = Y.DD.DDM.get('dragMode');
+ }
+ switch (mode) {
+ case 1:
+ case 'intersect':
+ return 1;
+ case 2:
+ case 'strict':
+ return 2;
+ case 0:
+ case 'point':
+ return 0;
+ }
+ return 0;
+ },
+ /**
+ * @property CSS_PREFIX
+ * @description The PREFIX to attach to all DD CSS class names
+ * @type {String}
+ */
+ CSS_PREFIX: 'yui-dd',
+ _activateTargets: function() {},
+ /**
+ * @private
+ * @property _drags
+ * @description Holder for all registered drag elements.
+ * @type {Array}
+ */
+ _drags: [],
+ /**
+ * @property activeDrag
+ * @description A reference to the currently active draggable object.
+ * @type {Drag}
+ */
+ activeDrag: false,
+ /**
+ * @private
+ * @method _regDrag
+ * @description Adds a reference to the drag object to the DDM._drags array, called in the constructor of Drag.
+ * @param {Drag} d The Drag object
+ */
+ _regDrag: function(d) {
+ if (this.getDrag(d.get('node'))) {
+ return false;
+ }
+
+ if (!this._active) {
+ this._setupListeners();
+ }
+ this._drags.push(d);
+ return true;
+ },
+ /**
+ * @private
+ * @method _unregDrag
+ * @description Remove this drag object from the DDM._drags array.
+ * @param {Drag} d The drag object.
+ */
+ _unregDrag: function(d) {
+ var tmp = [];
+ Y.each(this._drags, function(n, i) {
+ if (n !== d) {
+ tmp[tmp.length] = n;
+ }
+ });
+ this._drags = tmp;
+ },
+ /**
+ * @private
+ * @method _setupListeners
+ * @description Add the document listeners.
+ */
+ _setupListeners: function() {
+ this._active = true;
+ var doc = Y.get(document);
+ doc.on('mousemove', Y.bind(this._move, this));
+ //Y.Event.nativeAdd(document, 'mousemove', Y.bind(this._move, this));
+ doc.on('mouseup', Y.bind(this._end, this));
+ },
+ /**
+ * @private
+ * @method _start
+ * @description Internal method used by Drag to signal the start of a drag operation
+ */
+ _start: function() {
+ this.fire('ddm:start');
+ this._startDrag();
+ },
+ /**
+ * @private
+ * @method _startDrag
+ * @description Factory method to be overwritten by other DDM's
+ * @param {Number} x The x position of the drag element
+ * @param {Number} y The y position of the drag element
+ * @param {Number} w The width of the drag element
+ * @param {Number} h The height of the drag element
+ */
+ _startDrag: function() {},
+ /**
+ * @private
+ * @method _endDrag
+ * @description Factory method to be overwritten by other DDM's
+ */
+ _endDrag: function() {},
+ _dropMove: function() {},
+ /**
+ * @private
+ * @method _end
+ * @description Internal method used by Drag to signal the end of a drag operation
+ */
+ _end: function() {
+ if (this.activeDrag) {
+ this._endDrag();
+ this.fire('ddm:end');
+ this.activeDrag.end.call(this.activeDrag);
+ this.activeDrag = null;
+ }
+ },
+ /**
+ * @method stopDrag
+ * @description Method will forcefully stop a drag operation. For example calling this from inside an ESC keypress handler will stop this drag.
+ * @return {Self}
+ * @chainable
+ */
+ stopDrag: function() {
+ if (this.activeDrag) {
+ this._end();
+ }
+ return this;
+ },
+ /**
+ * @private
+ * @method _move
+ * @description Internal listener for the mousemove DOM event to pass to the Drag's move method.
+ * @param {Event.Facade} ev The Dom mousemove Event
+ */
+ _move: function(ev) {
+ if (this.activeDrag) {
+ this.activeDrag._move.call(this.activeDrag, ev);
+ this._dropMove();
+ }
+ },
+ /**
+ * //TODO Private, rename??...
+ * @private
+ * @method cssSizestoObject
+ * @description Helper method to use to set the gutter from the attribute setter.
+ * @param {String} gutter CSS style string for gutter: '5 0' (sets top and bottom to 5px, left and right to 0px), '1 2 3 4' (top 1px, right 2px, bottom 3px, left 4px)
+ * @return {Object} The gutter Object Literal.
+ */
+ cssSizestoObject: function(gutter) {
+ var x = gutter.split(' ');
+
+ switch (x.length) {
+ case 1: x[1] = x[2] = x[3] = x[0]; break;
+ case 2: x[2] = x[0]; x[3] = x[1]; break;
+ case 3: x[3] = x[1]; break;
+ }
+
+ return {
+ top : parseInt(x[0],10),
+ right : parseInt(x[1],10),
+ bottom: parseInt(x[2],10),
+ left : parseInt(x[3],10)
+ };
+ },
+ /**
+ * @method getDrag
+ * @description Get a valid Drag instance back from a Node or a selector string, false otherwise
+ * @param {String/Object} node The Node instance or Selector string to check for a valid Drag Object
+ * @return {Object}
+ */
+ getDrag: function(node) {
+ var drag = false,
+ n = Y.get(node);
+ if (n instanceof Y.Node) {
+ Y.each(this._drags, function(v, k) {
+ if (n.compareTo(v.get('node'))) {
+ drag = v;
+ }
+ });
+ }
+ return drag;
+ }
+ });
+
+ Y.namespace('DD');
+ Y.DD.DDM = new DDMBase();
+
+ /**
+ * @event ddm:start
+ * @description Fires from the DDM before all drag events fire.
+ * @type {Event.Custom}
+ */
+ /**
+ * @event ddm:end
+ * @description Fires from the DDM after the DDM finishes, before the drag end events.
+ * @type {Event.Custom}
+ */
+
+
+
+
+}, '3.0.0' ,{requires:['node', 'base'], skinnable:false});
+YUI.add('dd-ddm', function(Y) {
+
+
+ /**
+ * Extends the dd-ddm-base Class to add support for the viewport shim to allow a draggable node to drag to be dragged over an iframe or any other node that traps mousemove events.
+ * It is also required to have Drop Targets enabled, as the viewport shim will contain the shims for the Drop Targets.
+ * @module dd
+ * @submodule dd-ddm
+ * @for DDM
+ * @namespace DD
+ */
+ Y.mix(Y.DD.DDM, {
+ /**
+ * @private
+ * @property _pg
+ * @description The shim placed over the screen to track the mousemove event.
+ * @type {Node}
+ */
+ _pg: null,
+ /**
+ * @private
+ * @property _debugShim
+ * @description Set this to true to set the shims opacity to .5 for debugging it, default: false.
+ * @type {Boolean}
+ */
+ _debugShim: false,
+ _activateTargets: function() {},
+ _deactivateTargets: function() {},
+ _startDrag: function() {
+ if (this.activeDrag.get('useShim')) {
+ this._pg_activate();
+ this._activateTargets();
+ }
+ },
+ _endDrag: function() {
+ this._pg_deactivate();
+ this._deactivateTargets();
+ },
+ /**
+ * @private
+ * @method _pg_deactivate
+ * @description Deactivates the shim
+ */
+ _pg_deactivate: function() {
+ this._pg.setStyle('display', 'none');
+ },
+ /**
+ * @private
+ * @method _pg_activate
+ * @description Activates the shim
+ */
+ _pg_activate: function() {
+ var ah = this.activeDrag.get('activeHandle'), cur = 'auto';
+ if (ah) {
+ cur = ah.getStyle('cursor');
+ }
+ if (cur == 'auto') {
+ cur = this.get('dragCursor');
+ }
+
+ this._pg_size();
+ this._pg.setStyles({
+ top: 0,
+ left: 0,
+ display: 'block',
+ opacity: ((this._debugShim) ? '.5' : '0'),
+ cursor: cur
+ });
+ },
+ /**
+ * @private
+ * @method _pg_size
+ * @description Sizes the shim on: activatation, window:scroll, window:resize
+ */
+ _pg_size: function() {
+ if (this.activeDrag) {
+ var b = Y.get('body'),
+ h = b.get('docHeight'),
+ w = b.get('docWidth');
+ this._pg.setStyles({
+ height: h + 'px',
+ width: w + 'px'
+ });
+ }
+ },
+ /**
+ * @private
+ * @method _createPG
+ * @description Creates the shim and adds it's listeners to it.
+ */
+ _createPG: function() {
+ var pg = Y.Node.create(''),
+ bd = Y.get('body');
+ pg.setStyles({
+ top: '0',
+ left: '0',
+ position: 'absolute',
+ zIndex: '9999',
+ overflow: 'hidden',
+ backgroundColor: 'red',
+ display: 'none',
+ height: '5px',
+ width: '5px'
+ });
+ pg.set('id', Y.stamp(pg));
+ pg.addClass('yui-dd-shim');
+ if (bd.get('firstChild')) {
+ bd.insertBefore(pg, bd.get('firstChild'));
+ } else {
+ bd.appendChild(pg);
+ }
+ this._pg = pg;
+ this._pg.on('mouseup', Y.bind(this._end, this));
+ this._pg.on('mousemove', Y.bind(this._move, this));
+
+ var win = Y.get(window);
+ Y.on('window:resize', Y.bind(this._pg_size, this));
+ win.on('scroll', Y.bind(this._pg_size, this));
+ }
+ }, true);
+
+ Y.on('domready', Y.bind(Y.DD.DDM._createPG, Y.DD.DDM));
+
+
+
+
+
+}, '3.0.0' ,{requires:['dd-ddm-base', 'event-resize'], skinnable:false});
+YUI.add('dd-ddm-drop', function(Y) {
+
+
+ /**
+ * Extends the dd-ddm Class to add support for the placement of Drop Target shims inside the viewport shim. It also handles all Drop Target related events and interactions.
+ * @module dd
+ * @submodule dd-ddm-drop
+ * @for DDM
+ * @namespace DD
+ */
+
+ //TODO CSS class name for the bestMatch..
+ Y.mix(Y.DD.DDM, {
+ /**
+ * @private
+ * @property _noShim
+ * @description This flag turns off the use of the mouseover/mouseout shim. It should not be used unless you know what you are doing.
+ * @type {Boolean}
+ */
+ _noShim: false,
+ /**
+ * @private
+ * @property _activeShims
+ * @description Placeholder for all active shims on the page
+ * @type {Array}
+ */
+ _activeShims: [],
+ /**
+ * @private
+ * @method _hasActiveShim
+ * @description This method checks the _activeShims Object to see if there is a shim active.
+ * @return {Boolean}
+ */
+ _hasActiveShim: function() {
+ if (this._noShim) {
+ return true;
+ }
+ return this._activeShims.length;
+ },
+ /**
+ * @private
+ * @method _addActiveShim
+ * @description Adds a Drop Target to the list of active shims
+ * @param {Object} d The Drop instance to add to the list.
+ */
+ _addActiveShim: function(d) {
+ this._activeShims[this._activeShims.length] = d;
+ },
+ /**
+ * @private
+ * @method _removeActiveShim
+ * @description Removes a Drop Target to the list of active shims
+ * @param {Object} d The Drop instance to remove from the list.
+ */
+ _removeActiveShim: function(d) {
+ var s = [];
+ Y.each(this._activeShims, function(v, k) {
+ if (v._yuid !== d._yuid) {
+ s[s.length] = v;
+ }
+
+ });
+ this._activeShims = s;
+ },
+ /**
+ * @method syncActiveShims
+ * @description This method will sync the position of the shims on the Drop Targets that are currently active.
+ * @param {Boolean} force Resize/sync all Targets.
+ */
+ syncActiveShims: function(force) {
+ Y.later(0, this, function(force) {
+ var drops = ((force) ? this.targets : this._lookup());
+ Y.each(drops, function(v, k) {
+ v.sizeShim.call(v);
+ }, this);
+ }, force);
+ },
+ /**
+ * @private
+ * @property mode
+ * @description The mode that the drag operations will run in 0 for Point, 1 for Intersect, 2 for Strict
+ * @type Number
+ */
+ mode: 0,
+ /**
+ * @private
+ * @property POINT
+ * @description In point mode, a Drop is targeted by the cursor being over the Target
+ * @type Number
+ */
+ POINT: 0,
+ /**
+ * @private
+ * @property INTERSECT
+ * @description In intersect mode, a Drop is targeted by "part" of the drag node being over the Target
+ * @type Number
+ */
+ INTERSECT: 1,
+ /**
+ * @private
+ * @property STRICT
+ * @description In strict mode, a Drop is targeted by the "entire" drag node being over the Target
+ * @type Number
+ */
+ STRICT: 2,
+ /**
+ * @property useHash
+ * @description Should we only check targets that are in the viewport on drags (for performance), default: true
+ * @type {Boolean}
+ */
+ useHash: true,
+ /**
+ * @property activeDrop
+ * @description A reference to the active Drop Target
+ * @type {Object}
+ */
+ activeDrop: null,
+ /**
+ * @property validDrops
+ * @description An array of the valid Drop Targets for this interaction.
+ * @type {Array}
+ */
+ //TODO Change array/object literals to be in sync..
+ validDrops: [],
+ /**
+ * @property otherDrops
+ * @description An object literal of Other Drop Targets that we encountered during this interaction (in the case of overlapping Drop Targets)
+ * @type {Object}
+ */
+ otherDrops: {},
+ /**
+ * @property targets
+ * @description All of the Targets
+ * @type {Array}
+ */
+ targets: [],
+ /**
+ * @private
+ * @method _addValid
+ * @description Add a Drop Target to the list of Valid Targets. This list get's regenerated on each new drag operation.
+ * @param {Object} drop
+ * @return {Self}
+ * @chainable
+ */
+ _addValid: function(drop) {
+ this.validDrops[this.validDrops.length] = drop;
+ return this;
+ },
+ /**
+ * @private
+ * @method _removeValid
+ * @description Removes a Drop Target from the list of Valid Targets. This list get's regenerated on each new drag operation.
+ * @param {Object} drop
+ * @return {Self}
+ * @chainable
+ */
+ _removeValid: function(drop) {
+ var drops = [];
+ Y.each(this.validDrops, function(v, k) {
+ if (v !== drop) {
+ drops[drops.length] = v;
+ }
+ });
+
+ this.validDrops = drops;
+ return this;
+ },
+ /**
+ * @method isOverTarget
+ * @description Check to see if the Drag element is over the target, method varies on current mode
+ * @param {Object} drop The drop to check against
+ * @return {Boolean}
+ */
+ isOverTarget: function(drop) {
+ if (this.activeDrag && drop) {
+ var xy = this.activeDrag.mouseXY, r, dMode = this.activeDrag.get('dragMode'),
+ aRegion;
+ if (xy && this.activeDrag) {
+ aRegion = this.activeDrag.region;
+ if (dMode == this.STRICT) {
+ return this.activeDrag.get('dragNode').inRegion(drop.region, true, aRegion);
+ } else {
+ if (drop && drop.shim) {
+ if ((dMode == this.INTERSECT) && this._noShim) {
+ r = ((aRegion) ? aRegion : this.activeDrag.get('node'));
+ return drop.get('node').intersect(r).inRegion;
+ } else {
+ return drop.shim.intersect({
+ top: xy[1],
+ bottom: xy[1],
+ left: xy[0],
+ right: xy[0]
+ }, drop.region).inRegion;
+ }
+ } else {
+ return false;
+ }
+ }
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ },
+ /**
+ * @method clearCache
+ * @description Clears the cache data used for this interaction.
+ */
+ clearCache: function() {
+ this.validDrops = [];
+ this.otherDrops = {};
+ this._activeShims = [];
+ },
+ /**
+ * @private
+ * @method _activateTargets
+ * @description Clear the cache and activate the shims of all the targets
+ */
+ _activateTargets: function() {
+ this.clearCache();
+ Y.each(this.targets, function(v, k) {
+ v._activateShim.apply(v, []);
+ }, this);
+ this._handleTargetOver();
+
+ },
+ /**
+ * @method getBestMatch
+ * @description This method will gather the area for all potential targets and see which has the hightest covered area and return it.
+ * @param {Array} drops An Array of drops to scan for the best match.
+ * @param {Boolean} all If present, it returns an Array. First item is best match, second is an Array of the other items in the original Array.
+ * @return {Object or Array}
+ */
+ getBestMatch: function(drops, all) {
+ var biggest = null, area = 0, out;
+
+ Y.each(drops, function(v, k) {
+ var inter = this.activeDrag.get('dragNode').intersect(v.get('node'));
+ v.region.area = inter.area;
+
+ if (inter.inRegion) {
+ if (inter.area > area) {
+ area = inter.area;
+ biggest = v;
+ }
+ }
+ }, this);
+ if (all) {
+ out = [];
+ //TODO Sort the others in numeric order by area covered..
+ Y.each(drops, function(v, k) {
+ if (v !== biggest) {
+ out[out.length] = v;
+ }
+ }, this);
+ return [biggest, out];
+ } else {
+ return biggest;
+ }
+ },
+ /**
+ * @private
+ * @method _deactivateTargets
+ * @description This method fires the drop:hit, drag:drophit, drag:dropmiss methods and deactivates the shims..
+ */
+ _deactivateTargets: function() {
+ var other = [], tmp,
+ activeDrag = this.activeDrag,
+ activeDrop = this.activeDrop;
+
+ //TODO why is this check so hard??
+ if (activeDrag && activeDrop && this.otherDrops[activeDrop]) {
+ if (!activeDrag.get('dragMode')) {
+ //TODO otherDrops -- private..
+ other = this.otherDrops;
+ delete other[activeDrop];
+ } else {
+ tmp = this.getBestMatch(this.otherDrops, true);
+ activeDrop = tmp[0];
+ other = tmp[1];
+ }
+ activeDrag.get('node').removeClass(this.CSS_PREFIX + '-drag-over');
+ if (activeDrop) {
+ activeDrop.fire('drop:hit', { drag: activeDrag, drop: activeDrop, others: other });
+ activeDrag.fire('drag:drophit', { drag: activeDrag, drop: activeDrop, others: other });
+ }
+ } else if (activeDrag) {
+ activeDrag.get('node').removeClass(this.CSS_PREFIX + '-drag-over');
+ activeDrag.fire('drag:dropmiss', { pageX: activeDrag.lastXY[0], pageY: activeDrag.lastXY[1] });
+ } else {
+ }
+
+ this.activeDrop = null;
+
+ Y.each(this.targets, function(v, k) {
+ v._deactivateShim.apply(v, []);
+ }, this);
+ },
+ /**
+ * @private
+ * @method _dropMove
+ * @description This method is called when the move method is called on the Drag Object.
+ */
+ _dropMove: function() {
+ if (this._hasActiveShim()) {
+ this._handleTargetOver();
+ } else {
+ Y.each(this.otherDrops, function(v, k) {
+ v._handleOut.apply(v, []);
+ });
+ }
+ },
+ /**
+ * @private
+ * @method _lookup
+ * @description Filters the list of Drops down to those in the viewport.
+ * @return {Array} The valid Drop Targets that are in the viewport.
+ */
+ _lookup: function() {
+ if (!this.useHash || this._noShim) {
+ return this.validDrops;
+ }
+ var drops = [];
+ //Only scan drop shims that are in the Viewport
+ Y.each(this.validDrops, function(v, k) {
+ if (v.shim && v.shim.inViewportRegion(false, v.region)) {
+ drops[drops.length] = v;
+ }
+ });
+ return drops;
+
+ },
+ /**
+ * @private
+ * @method _handleTargetOver
+ * @description This method execs _handleTargetOver on all valid Drop Targets
+ */
+ _handleTargetOver: function() {
+ var drops = this._lookup();
+ Y.each(drops, function(v, k) {
+ v._handleTargetOver.call(v);
+ }, this);
+ },
+ /**
+ * @private
+ * @method _regTarget
+ * @description Add the passed in Target to the targets collection
+ * @param {Object} t The Target to add to the targets collection
+ */
+ _regTarget: function(t) {
+ this.targets[this.targets.length] = t;
+ },
+ /**
+ * @private
+ * @method _unregTarget
+ * @description Remove the passed in Target from the targets collection
+ * @param {Object} drop The Target to remove from the targets collection
+ */
+ _unregTarget: function(drop) {
+ var targets = [], vdrops;
+ Y.each(this.targets, function(v, k) {
+ if (v != drop) {
+ targets[targets.length] = v;
+ }
+ }, this);
+ this.targets = targets;
+
+ vdrops = [];
+ Y.each(this.validDrops, function(v, k) {
+ if (v !== drop) {
+ vdrops[vdrops.length] = v;
+ }
+ });
+
+ this.validDrops = vdrops;
+ },
+ /**
+ * @method getDrop
+ * @description Get a valid Drop instance back from a Node or a selector string, false otherwise
+ * @param {String/Object} node The Node instance or Selector string to check for a valid Drop Object
+ * @return {Object}
+ */
+ getDrop: function(node) {
+ var drop = false,
+ n = Y.Node.get(node);
+ if (n instanceof Y.Node) {
+ Y.each(this.targets, function(v, k) {
+ if (n.compareTo(v.get('node'))) {
+ drop = v;
+ }
+ });
+ }
+ return drop;
+ }
+ }, true);
+
+
+
+
+
+
+
+}, '3.0.0' ,{requires:['dd-ddm'], skinnable:false});
+YUI.add('dd-drag', function(Y) {
+
+
+ /**
+ * The Drag & Drop Utility allows you to create a draggable interface efficiently, buffering you from browser-level abnormalities and enabling you to focus on the interesting logic surrounding your particular implementation. This component enables you to create a variety of standard draggable objects with just a few lines of code and then, using its extensive API, add your own specific implementation logic.
+ * @module dd
+ * @submodule dd-drag
+ */
+ /**
+ * This class provides the ability to drag a Node.
+ * @class Drag
+ * @extends Base
+ * @constructor
+ * @namespace DD
+ */
+
+ var DDM = Y.DD.DDM,
+ NODE = 'node',
+ DRAGGING = 'dragging',
+ DRAG_NODE = 'dragNode',
+ OFFSET_HEIGHT = 'offsetHeight',
+ OFFSET_WIDTH = 'offsetWidth',
+ MOUSE_UP = 'mouseup',
+ MOUSE_DOWN = 'mousedown',
+ DRAG_START = 'dragstart',
+ /**
+ * @event drag:mouseDown
+ * @description Handles the mousedown DOM event, checks to see if you have a valid handle then starts the drag timers.
+ * @preventable _defMouseDownFn
+ * @param {Event.Facade} ev The mousedown event.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_MOUSE_DOWN = 'drag:mouseDown',
+ /**
+ * @event drag:afterMouseDown
+ * @description Fires after the mousedown event has been cleared.
+ * @param {Event.Facade} ev The mousedown event.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_AFTER_MOUSE_DOWN = 'drag:afterMouseDown',
+ /**
+ * @event drag:removeHandle
+ * @description Fires after a handle is removed.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_REMOVE_HANDLE = 'drag:removeHandle',
+ /**
+ * @event drag:addHandle
+ * @description Fires after a handle is added.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_ADD_HANDLE = 'drag:addHandle',
+ /**
+ * @event drag:removeInvalid
+ * @description Fires after an invalid selector is removed.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_REMOVE_INVALID = 'drag:removeInvalid',
+ /**
+ * @event drag:addInvalid
+ * @description Fires after an invalid selector is added.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_ADD_INVALID = 'drag:addInvalid',
+ /**
+ * @event drag:start
+ * @description Fires at the start of a drag operation.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_START = 'drag:start',
+ /**
+ * @event drag:end
+ * @description Fires at the end of a drag operation.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_END = 'drag:end',
+ /**
+ * @event drag:drag
+ * @description Fires every mousemove during a drag operation.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_DRAG = 'drag:drag',
+ /**
+ * @event drag:align
+ * @preventable _defAlignFn
+ * @description Fires when this node is aligned.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_ALIGN = 'drag:align',
+ /**
+ * @event drag:over
+ * @description Fires when this node is over a Drop Target. (Fired from dd-drop)
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ /**
+ * @event drag:enter
+ * @description Fires when this node enters a Drop Target. (Fired from dd-drop)
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ /**
+ * @event drag:exit
+ * @description Fires when this node exits a Drop Target. (Fired from dd-drop)
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ /**
+ * @event drag:drophit
+ * @description Fires when this node is dropped on a valid Drop Target. (Fired from dd-ddm-drop)
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ /**
+ * @event drag:dropmiss
+ * @description Fires when this node is dropped on an invalid Drop Target. (Fired from dd-ddm-drop)
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+
+ Drag = function(o) {
+ this._lazyAddAttrs = false;
+ Drag.superclass.constructor.apply(this, arguments);
+
+ var valid = DDM._regDrag(this);
+ if (!valid) {
+ Y.error('Failed to register node, already in use: ' + o.node);
+ }
+ };
+
+ Drag.NAME = 'drag';
+
+ Drag.ATTRS = {
+ /**
+ * @attribute node
+ * @description Y.Node instanace to use as the element to initiate a drag operation
+ * @type Node
+ */
+ node: {
+ setter: function(node) {
+ var n = Y.get(node);
+ if (!n) {
+ Y.error('DD.Drag: Invalid Node Given: ' + node);
+ } else {
+ n = n.item(0);
+ }
+ return n;
+ }
+ },
+ /**
+ * @attribute dragNode
+ * @description Y.Node instanace to use as the draggable element, defaults to node
+ * @type Node
+ */
+ dragNode: {
+ setter: function(node) {
+ var n = Y.Node.get(node);
+ if (!n) {
+ Y.error('DD.Drag: Invalid dragNode Given: ' + node);
+ }
+ return n;
+ }
+ },
+ /**
+ * @attribute offsetNode
+ * @description Offset the drag element by the difference in cursor position: default true
+ * @type Boolean
+ */
+ offsetNode: {
+ value: true
+ },
+ /**
+ * @attribute clickPixelThresh
+ * @description The number of pixels to move to start a drag operation, default is 3.
+ * @type Number
+ */
+ clickPixelThresh: {
+ value: DDM.get('clickPixelThresh')
+ },
+ /**
+ * @attribute clickTimeThresh
+ * @description The number of milliseconds a mousedown has to pass to start a drag operation, default is 1000.
+ * @type Number
+ */
+ clickTimeThresh: {
+ value: DDM.get('clickTimeThresh')
+ },
+ /**
+ * @attribute lock
+ * @description Set to lock this drag element so that it can't be dragged: default false.
+ * @type Boolean
+ */
+ lock: {
+ value: false,
+ setter: function(lock) {
+ if (lock) {
+ this.get(NODE).addClass(DDM.CSS_PREFIX + '-locked');
+ } else {
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-locked');
+ }
+ return lock;
+ }
+ },
+ /**
+ * @attribute data
+ * @description A payload holder to store arbitrary data about this drag object, can be used to store any value.
+ * @type Mixed
+ */
+ data: {
+ value: false
+ },
+ /**
+ * @attribute move
+ * @description If this is false, the drag element will not move with the cursor: default true. Can be used to "resize" the element.
+ * @type Boolean
+ */
+ move: {
+ value: true
+ },
+ /**
+ * @attribute useShim
+ * @description Use the protective shim on all drag operations: default true. Only works with dd-ddm, not dd-ddm-base.
+ * @type Boolean
+ */
+ useShim: {
+ value: true
+ },
+ /**
+ * @attribute activeHandle
+ * @description This config option is set by Drag to inform you of which handle fired the drag event (in the case that there are several handles): default false.
+ * @type Node
+ */
+ activeHandle: {
+ value: false
+ },
+ /**
+ * @attribute primaryButtonOnly
+ * @description By default a drag operation will only begin if the mousedown occurred with the primary mouse button. Setting this to false will allow for all mousedown events to trigger a drag.
+ * @type Boolean
+ */
+ primaryButtonOnly: {
+ value: true
+ },
+ /**
+ * @attribute dragging
+ * @description This attribute is not meant to be used by the implementor, it is meant to be used as an Event tracker so you can listen for it to change.
+ * @type Boolean
+ */
+ dragging: {
+ value: false
+ },
+ parent: {
+ value: false
+ },
+ /**
+ * @attribute target
+ * @description This attribute only works if the dd-drop module has been loaded. It will make this node a drop target as well as draggable.
+ * @type Boolean
+ */
+ target: {
+ value: false,
+ setter: function(config) {
+ this._handleTarget(config);
+ return config;
+ }
+ },
+ /**
+ * @attribute dragMode
+ * @description This attribute only works if the dd-drop module is active. It will set the dragMode (point, intersect, strict) of this Drag instance.
+ * @type String
+ */
+ dragMode: {
+ value: null,
+ setter: function(mode) {
+ return DDM._setDragMode(mode);
+ }
+ },
+ /**
+ * @attribute groups
+ * @description Array of groups to add this drag into.
+ * @type Array
+ */
+ groups: {
+ value: ['default'],
+ getter: function() {
+ if (!this._groups) {
+ this._groups = {};
+ }
+ var ret = [];
+ Y.each(this._groups, function(v, k) {
+ ret[ret.length] = k;
+ });
+ return ret;
+ },
+ setter: function(g) {
+ this._groups = {};
+ Y.each(g, function(v, k) {
+ this._groups[v] = true;
+ }, this);
+ return g;
+ }
+ },
+ /**
+ * @attribute handles
+ * @description Array of valid handles to add. Adding something here will set all handles, even if previously added with addHandle
+ * @type Array
+ */
+ handles: {
+ value: null,
+ setter: function(g) {
+ if (g) {
+ this._handles = {};
+ Y.each(g, function(v, k) {
+ this._handles[v] = true;
+ }, this);
+ } else {
+ this._handles = null;
+ }
+ return g;
+ }
+ },
+ /**
+ * @attribute bubbles
+ * @description Controls the default bubble parent for this Drag instance. Default: Y.DD.DDM. Set to false to disable bubbling.
+ * @type Object
+ */
+ bubbles: {
+ writeOnce: true,
+ value: Y.DD.DDM
+ }
+ };
+
+ Y.extend(Drag, Y.Base, {
+ /**
+ * @method addToGroup
+ * @description Add this Drag instance to a group, this should be used for on-the-fly group additions.
+ * @param {String} g The group to add this Drag Instance to.
+ * @return {Self}
+ * @chainable
+ */
+ addToGroup: function(g) {
+ this._groups[g] = true;
+ DDM._activateTargets();
+ return this;
+ },
+ /**
+ * @method removeFromGroup
+ * @description Remove this Drag instance from a group, this should be used for on-the-fly group removals.
+ * @param {String} g The group to remove this Drag Instance from.
+ * @return {Self}
+ * @chainable
+ */
+ removeFromGroup: function(g) {
+ delete this._groups[g];
+ DDM._activateTargets();
+ return this;
+ },
+ /**
+ * @property target
+ * @description This will be a reference to the Drop instance associated with this drag if the target: true config attribute is set..
+ * @type {Object}
+ */
+ target: null,
+ /**
+ * @private
+ * @method _handleTarget
+ * @description Attribute handler for the target config attribute.
+ * @param {Boolean/Object}
+ * @return {Boolean/Object}
+ */
+ _handleTarget: function(config) {
+ if (Y.DD.Drop) {
+ if (config === false) {
+ if (this.target) {
+ DDM._unregTarget(this.target);
+ this.target = null;
+ }
+ return false;
+ } else {
+ if (!Y.Lang.isObject(config)) {
+ config = {};
+ }
+ config.bubbles = ('bubbles' in config) ? config.bubbles : this.get('bubbles');
+ config.node = this.get(NODE);
+ config.groups = config.groups || this.get('groups');
+ this.target = new Y.DD.Drop(config);
+ }
+ } else {
+ return false;
+ }
+ },
+ /**
+ * @private
+ * @property _groups
+ * @description Storage Array for the groups this drag belongs to.
+ * @type {Array}
+ */
+ _groups: null,
+ /**
+ * @private
+ * @method _createEvents
+ * @description This method creates all the events for this Event Target and publishes them so we get Event Bubbling.
+ */
+ _createEvents: function() {
+
+ this.publish(EV_MOUSE_DOWN, {
+ defaultFn: this._defMouseDownFn,
+ queuable: false,
+ emitFacade: true,
+ bubbles: true,
+ prefix: 'drag'
+ });
+
+ this.publish(EV_ALIGN, {
+ defaultFn: this._defAlignFn,
+ queuable: false,
+ emitFacade: true,
+ bubbles: true,
+ prefix: 'drag'
+ });
+
+ this.publish(EV_DRAG, {
+ defaultFn: this._defDragFn,
+ queuable: false,
+ emitFacade: true,
+ bubbles: true,
+ prefix: 'drag'
+ });
+
+ this.publish(EV_END, {
+ preventedFn: this._prevEndFn,
+ queuable: false,
+ emitFacade: true,
+ bubbles: true,
+ prefix: 'drag'
+ });
+
+ var ev = [
+ EV_AFTER_MOUSE_DOWN,
+ EV_REMOVE_HANDLE,
+ EV_ADD_HANDLE,
+ EV_REMOVE_INVALID,
+ EV_ADD_INVALID,
+ EV_START,
+ 'drag:drophit',
+ 'drag:dropmiss',
+ 'drag:over',
+ 'drag:enter',
+ 'drag:exit'
+ ];
+
+ Y.each(ev, function(v, k) {
+ this.publish(v, {
+ type: v,
+ emitFacade: true,
+ bubbles: true,
+ preventable: false,
+ queuable: false,
+ prefix: 'drag'
+ });
+ }, this);
+
+ if (this.get('bubbles')) {
+ this.addTarget(this.get('bubbles'));
+ }
+
+
+ },
+ /**
+ * @private
+ * @property _ev_md
+ * @description A private reference to the mousedown DOM event
+ * @type {Event.Facade}
+ */
+ _ev_md: null,
+ /**
+ * @private
+ * @property _startTime
+ * @description The getTime of the mousedown event. Not used, just here in case someone wants/needs to use it.
+ * @type Date
+ */
+ _startTime: null,
+ /**
+ * @private
+ * @property _endTime
+ * @description The getTime of the mouseup event. Not used, just here in case someone wants/needs to use it.
+ * @type Date
+ */
+ _endTime: null,
+ /**
+ * @private
+ * @property _handles
+ * @description A private hash of the valid drag handles
+ * @type {Object}
+ */
+ _handles: null,
+ /**
+ * @private
+ * @property _invalids
+ * @description A private hash of the invalid selector strings
+ * @type {Object}
+ */
+ _invalids: null,
+ /**
+ * @private
+ * @property _invalidsDefault
+ * @description A private hash of the default invalid selector strings: {'textarea': true, 'input': true, 'a': true, 'button': true, 'select': true}
+ * @type {Object}
+ */
+ _invalidsDefault: {'textarea': true, 'input': true, 'a': true, 'button': true, 'select': true },
+ /**
+ * @private
+ * @property _dragThreshMet
+ * @description Private flag to see if the drag threshhold was met
+ * @type {Boolean}
+ */
+ _dragThreshMet: null,
+ /**
+ * @private
+ * @property _fromTimeout
+ * @description Flag to determine if the drag operation came from a timeout
+ * @type {Boolean}
+ */
+ _fromTimeout: null,
+ /**
+ * @private
+ * @property _clickTimeout
+ * @description Holder for the setTimeout call
+ * @type {Boolean}
+ */
+ _clickTimeout: null,
+ /**
+ * @property deltaXY
+ * @description The offset of the mouse position to the element's position
+ * @type {Array}
+ */
+ deltaXY: null,
+ /**
+ * @property startXY
+ * @description The initial mouse position
+ * @type {Array}
+ */
+ startXY: null,
+ /**
+ * @property nodeXY
+ * @description The initial element position
+ * @type {Array}
+ */
+ nodeXY: null,
+ /**
+ * @property lastXY
+ * @description The position of the element as it's moving (for offset calculations)
+ * @type {Array}
+ */
+ lastXY: null,
+ /**
+ * @property actXY
+ * @description The xy that the node will be set to. Changing this will alter the position as it's dragged.
+ * @type {Array}
+ */
+ actXY: null,
+ /**
+ * @property realXY
+ * @description The real xy position of the node.
+ * @type {Array}
+ */
+ realXY: null,
+ /**
+ * @property mouseXY
+ * @description The XY coords of the mousemove
+ * @type {Array}
+ */
+ mouseXY: null,
+ /**
+ * @property region
+ * @description A region object associated with this drag, used for checking regions while dragging.
+ * @type Object
+ */
+ region: null,
+ /**
+ * @private
+ * @method _handleMouseUp
+ * @description Handler for the mouseup DOM event
+ * @param {Event.Facade}
+ */
+ _handleMouseUp: function(ev) {
+ this._fixIEMouseUp();
+ if (DDM.activeDrag) {
+ DDM._end();
+ }
+ },
+ /**
+ * @private
+ * @method _fixDragStart
+ * @description The function we use as the ondragstart handler when we start a drag in Internet Explorer. This keeps IE from blowing up on images as drag handles.
+ */
+ _fixDragStart: function(e) {
+ e.preventDefault();
+ },
+ /**
+ * @private
+ * @method _ieSelectFix
+ * @description The function we use as the onselectstart handler when we start a drag in Internet Explorer
+ */
+ _ieSelectFix: function() {
+ return false;
+ },
+ /**
+ * @private
+ * @property _ieSelectBack
+ * @description We will hold a copy of the current "onselectstart" method on this property, and reset it after we are done using it.
+ */
+ _ieSelectBack: null,
+ /**
+ * @private
+ * @method _fixIEMouseDown
+ * @description This method copies the onselectstart listner on the document to the _ieSelectFix property
+ */
+ _fixIEMouseDown: function() {
+ if (Y.UA.ie) {
+ this._ieSelectBack = Y.config.doc.body.onselectstart;
+ Y.config.doc.body.onselectstart = this._ieSelectFix;
+ }
+ },
+ /**
+ * @private
+ * @method _fixIEMouseUp
+ * @description This method copies the _ieSelectFix property back to the onselectstart listner on the document.
+ */
+ _fixIEMouseUp: function() {
+ if (Y.UA.ie) {
+ Y.config.doc.body.onselectstart = this._ieSelectBack;
+ }
+ },
+ /**
+ * @private
+ * @method _handleMouseDownEvent
+ * @description Handler for the mousedown DOM event
+ * @param {Event.Facade}
+ */
+ _handleMouseDownEvent: function(ev) {
+ this.fire(EV_MOUSE_DOWN, { ev: ev });
+ },
+ /**
+ * @private
+ * @method _defMouseDownFn
+ * @description Handler for the mousedown DOM event
+ * @param {Event.Facade}
+ */
+ _defMouseDownFn: function(e) {
+ var ev = e.ev;
+ this._dragThreshMet = false;
+ this._ev_md = ev;
+
+ if (this.get('primaryButtonOnly') && ev.button > 1) {
+ return false;
+ }
+ if (this.validClick(ev)) {
+ this._fixIEMouseDown();
+ ev.halt();
+ this._setStartPosition([ev.pageX, ev.pageY]);
+
+ DDM.activeDrag = this;
+
+ this._clickTimeout = Y.later(this.get('clickTimeThresh'), this, this._timeoutCheck);
+ }
+ this.fire(EV_AFTER_MOUSE_DOWN, { ev: ev });
+ },
+ /**
+ * @method validClick
+ * @description Method first checks to see if we have handles, if so it validates the click against the handle. Then if it finds a valid handle, it checks it against the invalid handles list. Returns true if a good handle was used, false otherwise.
+ * @param {Event.Facade}
+ * @return {Boolean}
+ */
+ validClick: function(ev) {
+ var r = false, n = false,
+ tar = ev.target,
+ hTest = null,
+ els = null,
+ set = false;
+ if (this._handles) {
+ Y.each(this._handles, function(i, n) {
+ if (Y.Lang.isString(n)) {
+ //Am I this or am I inside this
+ if (tar.test(n + ', ' + n + ' *') && !hTest) {
+ hTest = n;
+ r = true;
+ }
+ }
+ });
+ } else {
+ n = this.get(NODE)
+ if (n.contains(tar) || n.compareTo(tar)) {
+ r = true;
+ }
+ }
+ if (r) {
+ if (this._invalids) {
+ Y.each(this._invalids, function(i, n) {
+ if (Y.Lang.isString(n)) {
+ //Am I this or am I inside this
+ if (tar.test(n + ', ' + n + ' *')) {
+ r = false;
+ }
+ }
+ });
+ }
+ }
+ if (r) {
+ if (hTest) {
+ els = ev.currentTarget.queryAll(hTest);
+ set = false;
+ els.each(function(n, i) {
+ if ((n.contains(tar) || n.compareTo(tar)) && !set) {
+ set = true;
+ this.set('activeHandle', n);
+ }
+ }, this);
+ } else {
+ this.set('activeHandle', this.get(NODE));
+ }
+ }
+ return r;
+ },
+ /**
+ * @private
+ * @method _setStartPosition
+ * @description Sets the current position of the Element and calculates the offset
+ * @param {Array} xy The XY coords to set the position to.
+ */
+ _setStartPosition: function(xy) {
+ this.startXY = xy;
+
+ this.nodeXY = this.lastXY = this.realXY = this.get(NODE).getXY();
+
+ if (this.get('offsetNode')) {
+ this.deltaXY = [(this.startXY[0] - this.nodeXY[0]), (this.startXY[1] - this.nodeXY[1])];
+ } else {
+ this.deltaXY = [0, 0];
+ }
+ },
+ /**
+ * @private
+ * @method _timeoutCheck
+ * @description The method passed to setTimeout to determine if the clickTimeThreshold was met.
+ */
+ _timeoutCheck: function() {
+ if (!this.get('lock') && !this._dragThreshMet) {
+ this._fromTimeout = this._dragThreshMet = true;
+ this.start();
+ this._alignNode([this._ev_md.pageX, this._ev_md.pageY], true);
+ }
+ },
+ /**
+ * @method removeHandle
+ * @description Remove a Selector added by addHandle
+ * @param {String} str The selector for the handle to be removed.
+ * @return {Self}
+ * @chainable
+ */
+ removeHandle: function(str) {
+ if (this._handles[str]) {
+ delete this._handles[str];
+ this.fire(EV_REMOVE_HANDLE, { handle: str });
+ }
+ return this;
+ },
+ /**
+ * @method addHandle
+ * @description Add a handle to a drag element. Drag only initiates when a mousedown happens on this element.
+ * @param {String} str The selector to test for a valid handle. Must be a child of the element.
+ * @return {Self}
+ * @chainable
+ */
+ addHandle: function(str) {
+ if (!this._handles) {
+ this._handles = {};
+ }
+ if (Y.Lang.isString(str)) {
+ this._handles[str] = true;
+ this.fire(EV_ADD_HANDLE, { handle: str });
+ }
+ return this;
+ },
+ /**
+ * @method removeInvalid
+ * @description Remove an invalid handle added by addInvalid
+ * @param {String} str The invalid handle to remove from the internal list.
+ * @return {Self}
+ * @chainable
+ */
+ removeInvalid: function(str) {
+ if (this._invalids[str]) {
+ this._invalids[str] = null;
+ delete this._invalids[str];
+ this.fire(EV_REMOVE_INVALID, { handle: str });
+ }
+ return this;
+ },
+ /**
+ * @method addInvalid
+ * @description Add a selector string to test the handle against. If the test passes the drag operation will not continue.
+ * @param {String} str The selector to test against to determine if this is an invalid drag handle.
+ * @return {Self}
+ * @chainable
+ */
+ addInvalid: function(str) {
+ if (Y.Lang.isString(str)) {
+ this._invalids[str] = true;
+ this.fire(EV_ADD_INVALID, { handle: str });
+ }
+ return this;
+ },
+ /**
+ * @private
+ * @method initializer
+ * @description Internal init handler
+ */
+ initializer: function() {
+ this.get(NODE).dd = this;
+
+ if (!this.get(NODE).get('id')) {
+ var id = Y.stamp(this.get(NODE));
+ this.get(NODE).set('id', id);
+ }
+
+ this.actXY = [];
+
+ this._invalids = Y.clone(this._invalidsDefault, true);
+
+ this._createEvents();
+
+ if (!this.get(DRAG_NODE)) {
+ this.set(DRAG_NODE, this.get(NODE));
+ }
+
+ //Fix for #2528096
+ //Don't prep the DD instance until all plugins are loaded.
+ this.on('initializedChange', Y.bind(this._prep, this));
+
+ //Shouldn't have to do this..
+ this.set('groups', this.get('groups'));
+ },
+ /**
+ * @private
+ * @method _prep
+ * @description Attach event listners and add classname
+ */
+ _prep: function() {
+ this._dragThreshMet = false;
+ var node = this.get(NODE);
+ node.addClass(DDM.CSS_PREFIX + '-draggable');
+ node.on(MOUSE_DOWN, Y.bind(this._handleMouseDownEvent, this));
+ node.on(MOUSE_UP, Y.bind(this._handleMouseUp, this));
+ node.on(DRAG_START, Y.bind(this._fixDragStart, this));
+ },
+ /**
+ * @private
+ * @method _unprep
+ * @description Detach event listeners and remove classname
+ */
+ _unprep: function() {
+ var node = this.get(NODE);
+ node.removeClass(DDM.CSS_PREFIX + '-draggable');
+ node.detachAll();
+ },
+ /**
+ * @method start
+ * @description Starts the drag operation
+ * @return {Self}
+ * @chainable
+ */
+ start: function() {
+ if (!this.get('lock') && !this.get(DRAGGING)) {
+ var node = this.get(NODE), ow = node.get(OFFSET_WIDTH), oh = node.get(OFFSET_HEIGHT);
+ this._startTime = (new Date()).getTime();
+
+ DDM._start();
+ node.addClass(DDM.CSS_PREFIX + '-dragging');
+ this.fire(EV_START, {
+ pageX: this.nodeXY[0],
+ pageY: this.nodeXY[1],
+ startTime: this._startTime
+ });
+ var xy = this.nodeXY;
+
+
+ this.region = {
+ '0': xy[0],
+ '1': xy[1],
+ area: 0,
+ top: xy[1],
+ right: xy[0] + ow,
+ bottom: xy[1] + oh,
+ left: xy[0]
+ };
+ this.set(DRAGGING, true);
+ }
+ return this;
+ },
+ /**
+ * @method end
+ * @description Ends the drag operation
+ * @return {Self}
+ * @chainable
+ */
+ end: function() {
+ this._endTime = (new Date()).getTime();
+ if (this._clickTimeout) {
+ this._clickTimeout.cancel();
+ }
+ this._dragThreshMet = false;
+ this._fromTimeout = false;
+ if (!this.get('lock') && this.get(DRAGGING)) {
+ this.fire(EV_END, {
+ pageX: this.lastXY[0],
+ pageY: this.lastXY[1],
+ startTime: this._startTime,
+ endTime: this._endTime
+ });
+ }
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-dragging');
+ this.set(DRAGGING, false);
+ this.deltaXY = [0, 0];
+
+ return this;
+ },
+ /**
+ * @private
+ * @method _prevEndFn
+ * @description Handler for preventing the drag:end event. It will reset the node back to it's start position
+ */
+ _prevEndFn: function(e) {
+ //Bug #1852577
+ this.get(DRAG_NODE).setXY(this.nodeXY);
+ },
+ /**
+ * @private
+ * @method _align
+ * @description Calculates the offsets and set's the XY that the element will move to.
+ * @param {Array} xy The xy coords to align with.
+ */
+ _align: function(xy) {
+ this.fire(EV_ALIGN, {pageX: xy[0], pageY: xy[1] });
+ },
+ /**
+ * @private
+ * @method _defAlignFn
+ * @description Calculates the offsets and set's the XY that the element will move to.
+ * @param {Event.Facade} e The drag:align event.
+ */
+ _defAlignFn: function(e) {
+ this.actXY = [e.pageX - this.deltaXY[0], e.pageY - this.deltaXY[1]];
+ },
+ /**
+ * @private
+ * @method _alignNode
+ * @description This method performs the alignment before the element move.
+ * @param {Array} eXY The XY to move the element to, usually comes from the mousemove DOM event.
+ */
+ _alignNode: function(eXY) {
+ this._align(eXY);
+ this._moveNode();
+ },
+ /**
+ * @private
+ * @method _moveNode
+ * @description This method performs the actual element move.
+ */
+ _moveNode: function(scroll) {
+ //if (!this.get(DRAGGING)) {
+ // return;
+ //}
+ var diffXY = [], diffXY2 = [], startXY = this.nodeXY, xy = this.actXY;
+
+ diffXY[0] = (xy[0] - this.lastXY[0]);
+ diffXY[1] = (xy[1] - this.lastXY[1]);
+
+ diffXY2[0] = (xy[0] - this.nodeXY[0]);
+ diffXY2[1] = (xy[1] - this.nodeXY[1]);
+
+
+ this.region = {
+ '0': xy[0],
+ '1': xy[1],
+ area: 0,
+ top: xy[1],
+ right: xy[0] + this.get(DRAG_NODE).get(OFFSET_WIDTH),
+ bottom: xy[1] + this.get(DRAG_NODE).get(OFFSET_HEIGHT),
+ left: xy[0]
+ };
+
+ this.fire(EV_DRAG, {
+ pageX: xy[0],
+ pageY: xy[1],
+ scroll: scroll,
+ info: {
+ start: startXY,
+ xy: xy,
+ delta: diffXY,
+ offset: diffXY2
+ }
+ });
+
+ this.lastXY = xy;
+ },
+ /**
+ * @private
+ * @method _defDragFn
+ * @description Default function for drag:drag. Fired from _moveNode.
+ * @param {Event.Facade} ev The drag:drag event
+ */
+ _defDragFn: function(e) {
+ if (this.get('move')) {
+ if (e.scroll) {
+ e.scroll.node.set('scrollTop', e.scroll.top);
+ e.scroll.node.set('scrollLeft', e.scroll.left);
+ }
+ this.get(DRAG_NODE).setXY([e.pageX, e.pageY]);
+ this.realXY = [e.pageX, e.pageY];
+ }
+ },
+ /**
+ * @private
+ * @method _move
+ * @description Fired from DragDropMgr (DDM) on mousemove.
+ * @param {Event.Facade} ev The mousemove DOM event
+ */
+ _move: function(ev) {
+ if (this.get('lock')) {
+ return false;
+ } else {
+ this.mouseXY = [ev.pageX, ev.pageY];
+ if (!this._dragThreshMet) {
+ var diffX = Math.abs(this.startXY[0] - ev.pageX),
+ diffY = Math.abs(this.startXY[1] - ev.pageY);
+ if (diffX > this.get('clickPixelThresh') || diffY > this.get('clickPixelThresh')) {
+ this._dragThreshMet = true;
+ this.start();
+ this._alignNode([ev.pageX, ev.pageY]);
+ }
+ } else {
+ if (this._clickTimeout) {
+ this._clickTimeout.cancel();
+ }
+ this._alignNode([ev.pageX, ev.pageY]);
+ }
+ }
+ },
+ /**
+ * @method stopDrag
+ * @description Method will forcefully stop a drag operation. For example calling this from inside an ESC keypress handler will stop this drag.
+ * @return {Self}
+ * @chainable
+ */
+ stopDrag: function() {
+ if (this.get(DRAGGING)) {
+ DDM._end();
+ }
+ return this;
+ },
+ /**
+ * @private
+ * @method destructor
+ * @description Lifecycle destructor, unreg the drag from the DDM and remove listeners
+ */
+ destructor: function() {
+ this._unprep();
+ this.detachAll();
+ if (this.target) {
+ this.target.destroy();
+ }
+ DDM._unregDrag(this);
+ }
+ });
+ Y.namespace('DD');
+ Y.DD.Drag = Drag;
+
+
+
+
+
+}, '3.0.0' ,{requires:['dd-ddm-base'], skinnable:false});
+YUI.add('dd-proxy', function(Y) {
+
+
+ /**
+ * The Drag & Drop Utility allows you to create a draggable interface efficiently, buffering you from browser-level abnormalities and enabling you to focus on the interesting logic surrounding your particular implementation. This component enables you to create a variety of standard draggable objects with just a few lines of code and then, using its extensive API, add your own specific implementation logic.
+ * @module dd
+ * @submodule dd-proxy
+ */
+ /**
+ * This plugin for dd-drag is for creating a proxy drag node, instead of dragging the original node.
+ * @class DDProxy
+ * @extends Base
+ * @constructor
+ * @namespace Plugin
+ */
+ var DDM = Y.DD.DDM,
+ NODE = 'node',
+ DRAG_NODE = 'dragNode',
+ HOST = 'host',
+ TRUE = true;
+
+ var P = function(config) {
+ P.superclass.constructor.apply(this, arguments);
+ };
+
+ P.NAME = 'DDProxy';
+ /**
+ * @property proxy
+ * @description The Proxy instance will be placed on the Drag instance under the proxy namespace.
+ * @type {String}
+ */
+ P.NS = 'proxy';
+
+ P.ATTRS = {
+ host: {
+ },
+ /**
+ * @attribute moveOnEnd
+ * @description Move the original node at the end of the drag. Default: true
+ * @type Boolean
+ */
+ moveOnEnd: {
+ value: TRUE
+ },
+ /**
+ * @attribute hideOnEnd
+ * @description Hide the drag node at the end of the drag. Default: true
+ * @type Boolean
+ */
+ hideOnEnd: {
+ value: TRUE
+ },
+ /**
+ * @attribute resizeFrame
+ * @description Make the Proxy node assume the size of the original node. Default: true
+ * @type Boolean
+ */
+ resizeFrame: {
+ value: TRUE
+ },
+ /**
+ * @attribute positionProxy
+ * @description Make the Proxy node appear in the same place as the original node. Default: true
+ * @type Boolean
+ */
+ positionProxy: {
+ value: TRUE
+ },
+ /**
+ * @attribute borderStyle
+ * @description The default border style for the border of the proxy. Default: 1px solid #808080
+ * @type Boolean
+ */
+ borderStyle: {
+ value: '1px solid #808080'
+ }
+ };
+
+ var proto = {
+ /**
+ * @private
+ * @property _hands
+ * @description Holds the event handles for setting the proxy
+ */
+ _hands: null,
+ /**
+ * @private
+ * @method _init
+ * @description Handler for the proxy config attribute
+ */
+ _init: function() {
+ if (!DDM._proxy) {
+ Y.on('domready', Y.bind(this._init, this));
+ return;
+ }
+ if (!this._hands) {
+ this._hands = [];
+ }
+ var i, h, h1, host = this.get(HOST), dnode = host.get(DRAG_NODE);
+ if (dnode.compareTo(host.get(NODE))) {
+ if (DDM._proxy) {
+ host.set(DRAG_NODE, DDM._proxy);
+ }
+ }
+ Y.each(this._hands, function(v) {
+ v.detach();
+ });
+ h = DDM.on('ddm:start', Y.bind(function() {
+ if (DDM.activeDrag === host) {
+ DDM._setFrame(host);
+ }
+ }, this));
+ h1 = DDM.on('ddm:end', Y.bind(function() {
+ if (host.get('dragging')) {
+ if (this.get('moveOnEnd')) {
+ host.get(NODE).setXY(host.lastXY);
+ }
+ if (this.get('hideOnEnd')) {
+ host.get(DRAG_NODE).setStyle('display', 'none');
+ }
+ }
+ }, this));
+ this._hands = [h, h1];
+ },
+ initializer: function() {
+ this._init();
+ },
+ destructor: function() {
+ var host = this.get(HOST);
+ Y.each(this._hands, function(v) {
+ v.detach();
+ });
+ host.set(DRAG_NODE, host.get(NODE));
+ }
+ };
+
+ Y.namespace('Plugin');
+ Y.extend(P, Y.Base, proto);
+ Y.Plugin.DDProxy = P;
+
+ //Add a couple of methods to the DDM
+ Y.mix(DDM, {
+ /**
+ * @private
+ * @for DDM
+ * @namespace DD
+ * @method _createFrame
+ * @description Create the proxy element if it doesn't already exist and set the DD.DDM._proxy value
+ */
+ _createFrame: function() {
+ if (!DDM._proxy) {
+ DDM._proxy = TRUE;
+
+ var p = Y.Node.create(''),
+ b = Y.Node.get('body');
+
+ p.setStyles({
+ position: 'absolute',
+ display: 'none',
+ zIndex: '999',
+ top: '-999px',
+ left: '-999px'
+ });
+
+ b.insertBefore(p, b.get('firstChild'));
+ p.set('id', Y.stamp(p));
+ p.addClass(DDM.CSS_PREFIX + '-proxy');
+ DDM._proxy = p;
+ }
+ },
+ /**
+ * @private
+ * @for DDM
+ * @namespace DD
+ * @method _setFrame
+ * @description If resizeProxy is set to true (default) it will resize the proxy element to match the size of the Drag Element.
+ * If positionProxy is set to true (default) it will position the proxy element in the same location as the Drag Element.
+ */
+ _setFrame: function(drag) {
+ var n = drag.get(NODE), d = drag.get(DRAG_NODE), ah, cur = 'auto';
+ if (drag.proxy.get('resizeFrame')) {
+ DDM._proxy.setStyles({
+ height: n.get('offsetHeight') + 'px',
+ width: n.get('offsetWidth') + 'px'
+ });
+ }
+
+ ah = DDM.activeDrag.get('activeHandle');
+ if (ah) {
+ cur = ah.getStyle('cursor');
+ }
+ if (cur == 'auto') {
+ cur = DDM.get('dragCursor');
+ }
+
+
+ d.setStyles({
+ visibility: 'hidden',
+ display: 'block',
+ cursor: cur,
+ border: drag.proxy.get('borderStyle')
+ });
+
+
+
+ if (drag.proxy.get('positionProxy')) {
+ d.setXY(drag.nodeXY);
+ }
+ d.setStyle('visibility', 'visible');
+ }
+ });
+
+ //Create the frame when DOM is ready
+ Y.on('domready', Y.bind(DDM._createFrame, DDM));
+
+
+
+}, '3.0.0' ,{requires:['dd-ddm', 'dd-drag'], skinnable:false});
+YUI.add('dd-constrain', function(Y) {
+
+
+ /**
+ * The Drag & Drop Utility allows you to create a draggable interface efficiently, buffering you from browser-level abnormalities and enabling you to focus on the interesting logic surrounding your particular implementation. This component enables you to create a variety of standard draggable objects with just a few lines of code and then, using its extensive API, add your own specific implementation logic.
+ * @module dd
+ * @submodule dd-constrain
+ */
+ /**
+ * This is a plugin for the dd-drag module to add the constraining methods to it. It supports constraining to a renodenode or viewport. It anode* supports tick based moves and XY axis constraints.
+ * @class DragConstrained
+ * @extends Base
+ * @constructor
+ * @namespace Plugin
+ */
+
+ var DRAG_NODE = 'dragNode',
+ OFFSET_HEIGHT = 'offsetHeight',
+ OFFSET_WIDTH = 'offsetWidth',
+ HOST = 'host',
+ CON_2_REGION = 'constrain2region',
+ CON_2_NODE = 'constrain2node',
+ TICK_X_ARRAY = 'tickXArray',
+ TICK_Y_ARRAY = 'tickYArray',
+ DDM = Y.DD.DDM,
+ TOP = 'top',
+ RIGHT = 'right',
+ BOTTOM = 'bottom',
+ LEFT = 'left',
+ proto = null;
+
+ var C = function(config) {
+ C.superclass.constructor.apply(this, arguments);
+ };
+
+ C.NAME = 'DragConstrained';
+ /**
+ * @property con
+ * @description The Constrained instance will be placed on the Drag instance under the con namespace.
+ * @type {String}
+ */
+ C.NS = 'con';
+
+ C.ATTRS = {
+ host: {
+ },
+ /**
+ * @attribute stickX
+ * @description Stick the drag movement to the X-Axis. Default: false
+ * @type Boolean
+ */
+ stickX: {
+ value: false
+ },
+ /**
+ * @attribute stickY
+ * @description Stick the drag movement to the Y-Axis
+ * @type Boolean
+ */
+ stickY: {
+ value: false
+ },
+ /**
+ * @attribute tickX
+ * @description The X tick offset the drag node should snap to on each drag move. False for no ticks. Default: false
+ * @type Number/false
+ */
+ tickX: {
+ value: false
+ },
+ /**
+ * @attribute tickY
+ * @description The Y tick offset the drag node should snap to on each drag move. False for no ticks. Default: false
+ * @type Number/false
+ */
+ tickY: {
+ value: false
+ },
+ /**
+ * @attribute tickXArray
+ * @description An array of page coordinates to use as X ticks for drag movement.
+ * @type Array
+ */
+ tickXArray: {
+ value: false
+ },
+ /**
+ * @attribute tickYArray
+ * @description An array of page coordinates to use as Y ticks for drag movement.
+ * @type Array
+ */
+ tickYArray: {
+ value: false
+ },
+ /**
+ * @attribute constrain2region
+ * @description An Object Literal containing a valid region (top, right, bottom, left) of page positions to constrain the drag node to.
+ * @type Object
+ */
+ constrain2region: {
+ value: false,
+ getter: function(r) {
+ if (Y.Lang.isObject(r)) {
+ var o = {};
+ Y.mix(o, r);
+ return o;
+ } else {
+ return false;
+ }
+ },
+ setter: function (r) {
+ if (Y.Lang.isObject(r)) {
+ if (Y.Lang.isNumber(r[TOP]) && Y.Lang.isNumber(r[RIGHT]) && Y.Lang.isNumber(r[LEFT]) && Y.Lang.isNumber(r[BOTTOM])) {
+ var o = {};
+ Y.mix(o, r);
+ return o;
+ } else {
+ return false;
+ }
+ } else if (r !== false) {
+ return false;
+ }
+ return r;
+ }
+ },
+ /**
+ * @attribute gutter
+ * @description CSS style string for the gutter of a region (supports negative values): '5 0' (sets top and bottom to 5px, left and right to 0px), '1 2 3 4' (top 1px, right 2px, bottom 3px, left 4px)
+ * @type String
+ */
+ gutter: {
+ value: '0',
+ setter: function(gutter) {
+ return Y.DD.DDM.cssSizestoObject(gutter);
+ }
+ },
+ /**
+ * @attribute constrain2node
+ * @description Will attempt to constrain the drag node to the boundaries of this node.
+ * @type Object
+ */
+ constrain2node: {
+ value: false,
+ setter: function(n) {
+ if (!this.get(CON_2_REGION)) {
+ var node = Y.Node.get(n);
+ if (node) {
+ return node;
+ }
+ } else if (this.get(CON_2_REGION) !== false) {
+ }
+ return false;
+ }
+ },
+ /**
+ * @attribute constrain2view
+ * @description Will attempt to constrain the drag node to the boundaries of the viewport region.
+ * @type Object
+ */
+ constrain2view: {
+ value: false
+ }
+ };
+
+ proto = {
+ initializer: function() {
+ this.get(HOST).on('drag:start', Y.bind(this._handleStart, this));
+ this.get(HOST).after('drag:align', Y.bind(this.align, this));
+ },
+ /**
+ * @private
+ * @method _handleStart
+ * @description Fires on drag:start and clears the _regionCache
+ */
+ _handleStart: function() {
+ this._regionCache = null;
+ },
+ /**
+ * @private
+ * @property _regionCache
+ * @description Store a cache of the region that we are constraining to
+ * @type Object
+ */
+ _regionCache: null,
+ /**
+ * @private
+ * @method _cacheRegion
+ * @description Get's the region and caches it, called from window.resize and when the cache is null
+ */
+ _cacheRegion: function() {
+ this._regionCache = this.get(CON_2_NODE).get('region');
+ },
+ /**
+ * @method getRegion
+ * @description Get the active region: viewport, node, custom region
+ * @param {Boolean} inc Include the node's height and width
+ * @return {Object}
+ */
+ getRegion: function(inc) {
+ var r = {}, oh = null, ow = null,
+ g = this.get('gutter'),
+ host = this.get(HOST);
+
+ if (this.get(CON_2_NODE)) {
+ if (!this._regionCache) {
+ Y.on('resize', Y.bind(this._cacheRegion, this), window);
+ this._cacheRegion();
+ }
+ r = Y.clone(this._regionCache);
+ } else if (this.get(CON_2_REGION)) {
+ r = this.get(CON_2_REGION);
+ } else if (this.get('constrain2view')) {
+ r = host.get(DRAG_NODE).get('viewportRegion');
+ } else {
+ return false;
+ }
+
+ Y.each(g, function(i, n) {
+ if ((n == RIGHT) || (n == BOTTOM)) {
+ r[n] -= i;
+ } else {
+ r[n] += i;
+ }
+ });
+ if (inc) {
+ oh = host.get(DRAG_NODE).get(OFFSET_HEIGHT);
+ ow = host.get(DRAG_NODE).get(OFFSET_WIDTH);
+ r[RIGHT] = r[RIGHT] - ow;
+ r[BOTTOM] = r[BOTTOM] - oh;
+ }
+ return r;
+ },
+ /**
+ * @private
+ * @method _checkRegion
+ * @description Check if xy is inside a given region, if not change to it be inside.
+ * @param {Array} _xy The XY to check if it's in the current region, if it isn't inside the region, it will reset the xy array to be inside the region.
+ * @return {Array} The new XY that is inside the region
+ */
+ _checkRegion: function(_xy) {
+ var oxy = _xy,
+ r = this.getRegion(),
+ host = this.get(HOST),
+ oh = host.get(DRAG_NODE).get(OFFSET_HEIGHT),
+ ow = host.get(DRAG_NODE).get(OFFSET_WIDTH);
+
+ if (oxy[1] > (r[BOTTOM] - oh)) {
+ _xy[1] = (r[BOTTOM] - oh);
+ }
+ if (r[TOP] > oxy[1]) {
+ _xy[1] = r[TOP];
+
+ }
+ if (oxy[0] > (r[RIGHT] - ow)) {
+ _xy[0] = (r[RIGHT] - ow);
+ }
+ if (r[LEFT] > oxy[0]) {
+ _xy[0] = r[LEFT];
+ }
+
+ return _xy;
+ },
+ /**
+ * @method inRegion
+ * @description Checks if the XY passed or the dragNode is inside the active region.
+ * @param {Array} xy Optional XY to check, if not supplied this.get('dragNode').getXY() is used.
+ * @return {Boolean} True if the XY is inside the region, false otherwise.
+ */
+ inRegion: function(xy) {
+ xy = xy || this.get(HOST).get(DRAG_NODE).getXY();
+
+ var _xy = this._checkRegion([xy[0], xy[1]]),
+ inside = false;
+ if ((xy[0] === _xy[0]) && (xy[1] === _xy[1])) {
+ inside = true;
+ }
+ return inside;
+ },
+ /**
+ * @method align
+ * @description Modifies the Drag.actXY method from the after drag:align event. This is where the constraining happens.
+ */
+ align: function() {
+ var host = this.get(HOST),
+ _xy = host.actXY,
+ r = this.getRegion(true);
+
+ if (this.get('stickX')) {
+ _xy[1] = (host.startXY[1] - host.deltaXY[1]);
+ }
+ if (this.get('stickY')) {
+ _xy[0] = (host.startXY[0] - host.deltaXY[0]);
+ }
+
+ if (r) {
+ _xy = this._checkRegion(_xy);
+ }
+
+ _xy = this._checkTicks(_xy, r);
+ host.actXY = _xy;
+ },
+ /**
+ * @private
+ * @method _checkTicks
+ * @description This method delegates the proper helper method for tick calculations
+ * @param {Array} xy The XY coords for the Drag
+ * @param {Object} r The optional region that we are bound to.
+ * @return {Array} The calced XY coords
+ */
+ _checkTicks: function(xy, r) {
+ var host = this.get(HOST),
+ lx = (host.startXY[0] - host.deltaXY[0]),
+ ly = (host.startXY[1] - host.deltaXY[1]),
+ xt = this.get('tickX'),
+ yt = this.get('tickY');
+ if (xt && !this.get(TICK_X_ARRAY)) {
+ xy[0] = DDM._calcTicks(xy[0], lx, xt, r[LEFT], r[RIGHT]);
+ }
+ if (yt && !this.get(TICK_Y_ARRAY)) {
+ xy[1] = DDM._calcTicks(xy[1], ly, yt, r[TOP], r[BOTTOM]);
+ }
+ if (this.get(TICK_X_ARRAY)) {
+ xy[0] = DDM._calcTickArray(xy[0], this.get(TICK_X_ARRAY), r[LEFT], r[RIGHT]);
+ }
+ if (this.get(TICK_Y_ARRAY)) {
+ xy[1] = DDM._calcTickArray(xy[1], this.get(TICK_Y_ARRAY), r[TOP], r[BOTTOM]);
+ }
+
+ return xy;
+ }
+ };
+
+ Y.namespace('Plugin');
+ Y.extend(C, Y.Base, proto);
+ Y.Plugin.DDConstrained = C;
+
+ Y.mix(DDM, {
+ /**
+ * @for DDM
+ * @namespace DD
+ * @private
+ * @method _calcTicks
+ * @description Helper method to calculate the tick offsets for a given position
+ * @param {Number} pos The current X or Y position
+ * @param {Number} start The start X or Y position
+ * @param {Number} tick The X or Y tick increment
+ * @param {Number} off1 The min offset that we can't pass (region)
+ * @param {Number} off2 The max offset that we can't pass (region)
+ * @return {Number} The new position based on the tick calculation
+ */
+ _calcTicks: function(pos, start, tick, off1, off2) {
+ var ix = ((pos - start) / tick),
+ min = Math.floor(ix),
+ max = Math.ceil(ix);
+ if ((min !== 0) || (max !== 0)) {
+ if ((ix >= min) && (ix <= max)) {
+ pos = (start + (tick * min));
+ if (off1 && off2) {
+ if (pos < off1) {
+ pos = (start + (tick * (min + 1)));
+ }
+ if (pos > off2) {
+ pos = (start + (tick * (min - 1)));
+ }
+ }
+ }
+ }
+ return pos;
+ },
+ /**
+ * @for DDM
+ * @namespace DD
+ * @private
+ * @method _calcTickArray
+ * @description This method is used with the tickXArray and tickYArray config options
+ * @param {Number} pos The current X or Y position
+ * @param {Number} ticks The array containing our custom tick positions.
+ * @param {Number} off1 The min offset that we can't pass (region)
+ * @param {Number} off2 The max offset that we can't pass (region)
+ * @return The tick position
+ */
+ _calcTickArray: function(pos, ticks, off1, off2) {
+ var i = 0, len = ticks.length, next = 0,
+ diff1, diff2, ret;
+
+ if (!ticks || (ticks.length === 0)) {
+ return pos;
+ } else if (ticks[0] >= pos) {
+ return ticks[0];
+ } else {
+ for (i = 0; i < len; i++) {
+ next = (i + 1);
+ if (ticks[next] && ticks[next] >= pos) {
+ diff1 = pos - ticks[i];
+ diff2 = ticks[next] - pos;
+ ret = (diff2 > diff1) ? ticks[i] : ticks[next];
+ if (off1 && off2) {
+ if (ret > off2) {
+ if (ticks[i]) {
+ ret = ticks[i];
+ } else {
+ ret = ticks[len - 1];
+ }
+ }
+ }
+ return ret;
+ }
+
+ }
+ return ticks[ticks.length - 1];
+ }
+ }
+ });
+
+
+
+
+}, '3.0.0' ,{requires:['dd-drag'], skinnable:false});
+YUI.add('dd-scroll', function(Y) {
+
+
+ /**
+ * The Drag & Drop Utility allows you to create a draggable interface efficiently, buffering you from browser-level abnormalities and enabling you to focus on the interesting logic surrounding your particular implementation. This component enables you to create a variety of standard draggable objects with just a few lines of code and then, using its extensive API, add your own specific implementation logic.
+ * @module dd
+ * @submodule dd-scroll
+ */
+ /**
+ * This class is the base scroller class used to create the Plugin.DDNodeScroll and Plugin.DDWinScroll.
+ * This class should not be called on it's own, it's designed to be a plugin.
+ * @class Scroll
+ * @extends Base
+ * @namespace DD
+ * @constructor
+ */
+
+ var S = function() {
+ S.superclass.constructor.apply(this, arguments);
+
+ },
+ HOST = 'host',
+ BUFFER = 'buffer',
+ PARENT_SCROLL = 'parentScroll',
+ WINDOW_SCROLL = 'windowScroll',
+ SCROLL_TOP = 'scrollTop',
+ SCROLL_LEFT = 'scrollLeft',
+ OFFSET_WIDTH = 'offsetWidth',
+ OFFSET_HEIGHT = 'offsetHeight';
+
+
+ S.ATTRS = {
+ /**
+ * @attribute parentScroll
+ * @description Internal config option to hold the node that we are scrolling. Should not be set by the developer.
+ * @type Node
+ */
+ parentScroll: {
+ value: false,
+ setter: function(node) {
+ if (node) {
+ return node;
+ }
+ return false;
+ }
+ },
+ /**
+ * @attribute buffer
+ * @description The number of pixels from the edge of the screen to turn on scrolling. Default: 30
+ * @type Number
+ */
+ buffer: {
+ value: 30
+ },
+ /**
+ * @attribute scrollDelay
+ * @description The number of milliseconds delay to pass to the auto scroller. Default: 235
+ * @type Number
+ */
+ scrollDelay: {
+ value: 235
+ },
+ /**
+ * @attribute host
+ * @description The host we are plugged into.
+ * @type Object
+ */
+ host: {
+ value: null
+ },
+ /**
+ * @attribute windowScroll
+ * @description Turn on window scroll support, default: false
+ * @type Boolean
+ */
+ windowScroll: {
+ value: false
+ },
+ /**
+ * @attribute vertical
+ * @description Allow vertical scrolling, default: true.
+ * @type Boolean
+ */
+ vertical: {
+ value: true
+ },
+ /**
+ * @attribute horizontal
+ * @description Allow horizontal scrolling, default: true.
+ * @type Boolean
+ */
+ horizontal: {
+ value: true
+ }
+ };
+
+ Y.extend(S, Y.Base, {
+ /**
+ * @private
+ * @property _scrolling
+ * @description Tells if we are actively scrolling or not.
+ * @type Boolean
+ */
+ _scrolling: null,
+ /**
+ * @private
+ * @property _vpRegionCache
+ * @description Cache of the Viewport dims.
+ * @type Object
+ */
+ _vpRegionCache: null,
+ /**
+ * @private
+ * @property _dimCache
+ * @description Cache of the dragNode dims.
+ * @type Object
+ */
+ _dimCache: null,
+ /**
+ * @private
+ * @property _scrollTimer
+ * @description Holder for the Timer object returned from Y.later.
+ * @type {Y.later}
+ */
+ _scrollTimer: null,
+ /**
+ * @private
+ * @method _getVPRegion
+ * @description Sets the _vpRegionCache property with an Object containing the dims from the viewport.
+ */
+ _getVPRegion: function() {
+ var r = {};
+ //if (!this._vpRegionCache) {
+ var n = this.get(PARENT_SCROLL),
+ b = this.get(BUFFER),
+ ws = this.get(WINDOW_SCROLL),
+ xy = ((ws) ? [] : n.getXY()),
+ w = ((ws) ? 'winWidth' : OFFSET_WIDTH),
+ h = ((ws) ? 'winHeight' : OFFSET_HEIGHT),
+ t = ((ws) ? n.get(SCROLL_TOP) : xy[1]),
+ l = ((ws) ? n.get(SCROLL_LEFT) : xy[0]);
+
+ r = {
+ top: t + b,
+ right: (n.get(w) + l) - b,
+ bottom: (n.get(h) + t) - b,
+ left: l + b
+ };
+ this._vpRegionCache = r;
+ //} else {
+ // r = this._vpRegionCache;
+ //}
+ return r;
+ },
+ initializer: function() {
+ var h = this.get(HOST);
+ h.after('drag:start', Y.bind(this.start, this));
+ h.after('drag:end', Y.bind(this.end, this));
+ h.on('drag:align', Y.bind(this.align, this));
+
+ //TODO - This doesn't work yet??
+ Y.get(window).on('scroll', Y.bind(function() {
+ this._vpRegionCache = null;
+ }, this));
+ },
+ /**
+ * @private
+ * @method _checkWinScroll
+ * @description Check to see if we need to fire the scroll timer. If scroll timer is running this will scroll the window.
+ * @param {Boolean} move Should we move the window. From Y.later
+ */
+ _checkWinScroll: function(move) {
+ var r = this._getVPRegion(),
+ ho = this.get(HOST),
+ ws = this.get(WINDOW_SCROLL),
+ xy = ho.lastXY,
+ scroll = false,
+ b = this.get(BUFFER),
+ win = this.get(PARENT_SCROLL),
+ sTop = win.get(SCROLL_TOP),
+ sLeft = win.get(SCROLL_LEFT),
+ w = this._dimCache.w,
+ h = this._dimCache.h,
+ bottom = xy[1] + h,
+ top = xy[1],
+ right = xy[0] + w,
+ left = xy[0],
+ nt = top,
+ nl = left,
+ st = sTop,
+ sl = sLeft;
+
+ if (this.get('horizontal')) {
+ if (left <= r.left) {
+ scroll = true;
+ nl = xy[0] - ((ws) ? b : 0);
+ sl = sLeft - b;
+ }
+ if (right >= r.right) {
+ scroll = true;
+ nl = xy[0] + ((ws) ? b : 0);
+ sl = sLeft + b;
+ }
+ }
+ if (this.get('vertical')) {
+ if (bottom >= r.bottom) {
+ scroll = true;
+ nt = xy[1] + ((ws) ? b : 0);
+ st = sTop + b;
+
+ }
+ if (top <= r.top) {
+ scroll = true;
+ nt = xy[1] - ((ws) ? b : 0);
+ st = sTop - b;
+ }
+ }
+
+ if (st < 0) {
+ st = 0;
+ nt = xy[1];
+ }
+
+ if (sl < 0) {
+ sl = 0;
+ nl = xy[0];
+ }
+
+ if (nt < 0) {
+ nt = xy[1];
+ }
+ if (nl < 0) {
+ nl = xy[0];
+ }
+ if (move) {
+ ho.actXY = [nl, nt];
+ ho._moveNode({ node: win, top: st, left: sl});
+ if (!st && !sl) {
+ this._cancelScroll();
+ }
+ } else {
+ if (scroll) {
+ this._initScroll();
+ } else {
+ this._cancelScroll();
+ }
+ }
+ },
+ /**
+ * @private
+ * @method _initScroll
+ * @description Cancel a previous scroll timer and init a new one.
+ */
+ _initScroll: function() {
+ this._cancelScroll();
+ this._scrollTimer = Y.Lang.later(this.get('scrollDelay'), this, this._checkWinScroll, [true], true);
+
+ },
+ /**
+ * @private
+ * @method _cancelScroll
+ * @description Cancel a currently running scroll timer.
+ */
+ _cancelScroll: function() {
+ this._scrolling = false;
+ if (this._scrollTimer) {
+ this._scrollTimer.cancel();
+ delete this._scrollTimer;
+ }
+ },
+ /**
+ * @method align
+ * @description Called from the drag:align event to determine if we need to scroll.
+ */
+ align: function(e) {
+ if (this._scrolling) {
+ this._cancelScroll();
+ e.preventDefault();
+ }
+ if (!this._scrolling) {
+ this._checkWinScroll();
+ }
+ },
+ /**
+ * @private
+ * @method _setDimCache
+ * @description Set the cache of the dragNode dims.
+ */
+ _setDimCache: function() {
+ var node = this.get(HOST).get('dragNode');
+ this._dimCache = {
+ h: node.get(OFFSET_HEIGHT),
+ w: node.get(OFFSET_WIDTH)
+ };
+ },
+ /**
+ * @method start
+ * @description Called from the drag:start event
+ */
+ start: function() {
+ this._setDimCache();
+ },
+ /**
+ * @method end
+ * @description Called from the drag:end event
+ */
+ end: function(xy) {
+ this._dimCache = null;
+ this._cancelScroll();
+ },
+ /**
+ * @method toString
+ * @description General toString method for logging
+ * @return String name for the object
+ */
+ toString: function() {
+ return S.NAME + ' #' + this.get('node').get('id');
+ }
+ });
+
+ Y.namespace('Plugin');
+
+
+ /**
+ * Extends the Scroll class to make the window scroll while dragging.
+ * @class DDWindowScroll
+ * @extends DD.Scroll
+ * @namespace Plugin
+ * @constructor
+ */
+ var WS = function() {
+ WS.superclass.constructor.apply(this, arguments);
+ };
+ WS.ATTRS = Y.merge(S.ATTRS, {
+ /**
+ * @attribute windowScroll
+ * @description Turn on window scroll support, default: true
+ * @type Boolean
+ */
+ windowScroll: {
+ value: true,
+ setter: function(scroll) {
+ if (scroll) {
+ this.set(PARENT_SCROLL, Y.get(window));
+ }
+ return scroll;
+ }
+ }
+ });
+ Y.extend(WS, S, {
+ //Shouldn't have to do this..
+ initializer: function() {
+ this.set('windowScroll', this.get('windowScroll'));
+ }
+ });
+ WS.NAME = WS.NS = 'winscroll';
+ Y.Plugin.DDWinScroll = WS;
+
+
+ /**
+ * Extends the Scroll class to make a parent node scroll while dragging.
+ * @class DDNodeScroll
+ * @extends DD.Scroll
+ * @namespace Plugin
+ * @constructor
+ */
+ var NS = function() {
+ NS.superclass.constructor.apply(this, arguments);
+
+ };
+ NS.ATTRS = Y.merge(S.ATTRS, {
+ /**
+ * @attribute node
+ * @description The node we want to scroll. Used to set the internal parentScroll attribute.
+ * @type Node
+ */
+ node: {
+ value: false,
+ setter: function(node) {
+ var n = Y.get(node);
+ if (!n) {
+ if (node !== false) {
+ Y.error('DDNodeScroll: Invalid Node Given: ' + node);
+ }
+ } else {
+ n = n.item(0);
+ this.set(PARENT_SCROLL, n);
+ }
+ return n;
+ }
+ }
+ });
+ Y.extend(NS, S, {
+ //Shouldn't have to do this..
+ initializer: function() {
+ this.set('node', this.get('node'));
+ }
+ });
+ NS.NAME = NS.NS = 'nodescroll';
+ Y.Plugin.DDNodeScroll = NS;
+
+ Y.DD.Scroll = S;
+
+
+
+}, '3.0.0' ,{skinnable:false, requires:['dd-drag'], optional:['dd-proxy']});
+YUI.add('dd-plugin', function(Y) {
+
+
+ /**
+ * This is a simple Drag plugin that can be attached to a Node via the plug method.
+ * @module dd
+ * @submodule dd-plugin
+ */
+ /**
+ * This is a simple Drag plugin that can be attached to a Node via the plug method.
+ * @class Drag
+ * @extends DD.Drag
+ * @constructor
+ * @namespace Plugin
+ */
+
+
+ var Drag = function(config) {
+ config.node = ((Y.Widget && config.host instanceof Y.Widget) ? config.host.get('boundingBox') : config.host);
+ Drag.superclass.constructor.apply(this, arguments);
+ };
+
+ /**
+ * @property NAME
+ * @description dd-plugin
+ * @type {String}
+ */
+ Drag.NAME = "dd-plugin";
+
+ /**
+ * @property NS
+ * @description The Drag instance will be placed on the Node instance under the dd namespace. It can be accessed via Node.dd;
+ * @type {String}
+ */
+ Drag.NS = "dd";
+
+
+ Y.extend(Drag, Y.DD.Drag);
+ Y.namespace('Plugin');
+ Y.Plugin.Drag = Drag;
+
+
+
+
+
+}, '3.0.0' ,{skinnable:false, requires:['dd-drag'], optional:['dd-constrain', 'dd-proxy']});
+YUI.add('dd-drop', function(Y) {
+
+
+ /**
+ * The Drag & Drop Utility allows you to create a draggable interface efficiently, buffering you from browser-level abnormalities and enabling you to focus on the interesting logic surrounding your particular implementation. This component enables you to create a variety of standard draggable objects with just a few lines of code and then, using its extensive API, add your own specific implementation logic.
+ * @module dd
+ * @submodule dd-drop
+ */
+ /**
+ * This class provides the ability to create a Drop Target.
+ * @class Drop
+ * @extends Base
+ * @constructor
+ * @namespace DD
+ */
+
+ var NODE = 'node',
+ DDM = Y.DD.DDM,
+ OFFSET_HEIGHT = 'offsetHeight',
+ OFFSET_WIDTH = 'offsetWidth',
+ /**
+ * @event drop:over
+ * @description Fires when a drag element is over this target.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_DROP_OVER = 'drop:over',
+ /**
+ * @event drop:enter
+ * @description Fires when a drag element enters this target.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_DROP_ENTER = 'drop:enter',
+ /**
+ * @event drop:exit
+ * @description Fires when a drag element exits this target.
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+ EV_DROP_EXIT = 'drop:exit',
+
+ /**
+ * @event drop:hit
+ * @description Fires when a draggable node is dropped on this Drop Target. (Fired from dd-ddm-drop)
+ * @bubbles DDM
+ * @type {Event.Custom}
+ */
+
+
+ Drop = function() {
+ this._lazyAddAttrs = false;
+ Drop.superclass.constructor.apply(this, arguments);
+
+
+ //DD init speed up.
+ Y.on('domready', Y.bind(function() {
+ Y.later(100, this, this._createShim);
+ }, this));
+ DDM._regTarget(this);
+
+ /* TODO
+ if (Dom.getStyle(this.el, 'position') == 'fixed') {
+ Event.on(window, 'scroll', function() {
+ this.activateShim();
+ }, this, true);
+ }
+ */
+ };
+
+ Drop.NAME = 'drop';
+
+ Drop.ATTRS = {
+ /**
+ * @attribute node
+ * @description Y.Node instanace to use as the element to make a Drop Target
+ * @type Node
+ */
+ node: {
+ setter: function(node) {
+ var n = Y.Node.get(node);
+ if (!n) {
+ Y.error('DD.Drop: Invalid Node Given: ' + node);
+ }
+ return n;
+ }
+ },
+ /**
+ * @attribute groups
+ * @description Array of groups to add this drop into.
+ * @type Array
+ */
+ groups: {
+ value: ['default'],
+ setter: function(g) {
+ this._groups = {};
+ Y.each(g, function(v, k) {
+ this._groups[v] = true;
+ }, this);
+ return g;
+ }
+ },
+ /**
+ * @attribute padding
+ * @description CSS style padding to make the Drop Target bigger than the node.
+ * @type String
+ */
+ padding: {
+ value: '0',
+ setter: function(p) {
+ return DDM.cssSizestoObject(p);
+ }
+ },
+ /**
+ * @attribute lock
+ * @description Set to lock this drop element.
+ * @type Boolean
+ */
+ lock: {
+ value: false,
+ setter: function(lock) {
+ if (lock) {
+ this.get(NODE).addClass(DDM.CSS_PREFIX + '-drop-locked');
+ } else {
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-locked');
+ }
+ return lock;
+ }
+ },
+ /**
+ * @attribute bubbles
+ * @description Controls the default bubble parent for this Drop instance. Default: Y.DD.DDM. Set to false to disable bubbling.
+ * @type Object
+ */
+ bubbles: {
+ writeOnce: true,
+ value: Y.DD.DDM
+ }
+ };
+
+ Y.extend(Drop, Y.Base, {
+ /**
+ * @private
+ * @method _createEvents
+ * @description This method creates all the events for this Event Target and publishes them so we get Event Bubbling.
+ */
+ _createEvents: function() {
+
+ var ev = [
+ EV_DROP_OVER,
+ EV_DROP_ENTER,
+ EV_DROP_EXIT,
+ 'drop:hit'
+ ];
+
+ Y.each(ev, function(v, k) {
+ this.publish(v, {
+ type: v,
+ emitFacade: true,
+ preventable: false,
+ bubbles: true,
+ queuable: false,
+ prefix: 'drop'
+ });
+ }, this);
+
+ if (this.get('bubbles')) {
+ this.addTarget(this.get('bubbles'));
+ }
+
+ },
+ /**
+ * @private
+ * @property _valid
+ * @description Flag for determining if the target is valid in this operation.
+ * @type Boolean
+ */
+ _valid: null,
+ /**
+ * @private
+ * @property _groups
+ * @description The groups this target belongs to.
+ * @type Array
+ */
+ _groups: null,
+ /**
+ * @property shim
+ * @description Node reference to the targets shim
+ * @type {Object}
+ */
+ shim: null,
+ /**
+ * @property region
+ * @description A region object associated with this target, used for checking regions while dragging.
+ * @type Object
+ */
+ region: null,
+ /**
+ * @property overTarget
+ * @description This flag is tripped when a drag element is over this target.
+ * @type Boolean
+ */
+ overTarget: null,
+ /**
+ * @method inGroup
+ * @description Check if this target is in one of the supplied groups.
+ * @param {Array} groups The groups to check against
+ * @return Boolean
+ */
+ inGroup: function(groups) {
+ this._valid = false;
+ var ret = false;
+ Y.each(groups, function(v, k) {
+ if (this._groups[v]) {
+ ret = true;
+ this._valid = true;
+ }
+ }, this);
+ return ret;
+ },
+ /**
+ * @private
+ * @method initializer
+ * @description Private lifecycle method
+ */
+ initializer: function() {
+ //this._createEvents();
+ Y.later(100, this, this._createEvents);
+
+ var node = this.get(NODE), id;
+ if (!node.get('id')) {
+ id = Y.stamp(node);
+ node.set('id', id);
+ }
+ node.addClass(DDM.CSS_PREFIX + '-drop');
+ //Shouldn't have to do this..
+ this.set('groups', this.get('groups'));
+ },
+ /**
+ * @private
+ * @method destructor
+ * @description Lifecycle destructor, unreg the drag from the DDM and remove listeners
+ */
+ destructor: function() {
+ DDM._unregTarget(this);
+ if (this.shim) {
+ this.shim.detachAll();
+ this.shim.get('parentNode').removeChild(this.shim);
+ this.shim = null;
+ }
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop');
+ this.detachAll();
+ },
+ /**
+ * @private
+ * @method _deactivateShim
+ * @description Removes classes from the target, resets some flags and sets the shims deactive position [-999, -999]
+ */
+ _deactivateShim: function() {
+ if (!this.shim) {
+ return false;
+ }
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-active-valid');
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-active-invalid');
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-over');
+ this.shim.setStyles({
+ top: '-999px',
+ left: '-999px',
+ zIndex: '1'
+ });
+ this.overTarget = false;
+ },
+ /**
+ * @private
+ * @method _activateShim
+ * @description Activates the shim and adds some interaction CSS classes
+ */
+ _activateShim: function() {
+ if (!DDM.activeDrag) {
+ return false; //Nothing is dragging, no reason to activate.
+ }
+ if (this.get(NODE) === DDM.activeDrag.get(NODE)) {
+ return false;
+ }
+ if (this.get('lock')) {
+ return false;
+ }
+ var node = this.get(NODE);
+ //TODO Visibility Check..
+ //if (this.inGroup(DDM.activeDrag.get('groups')) && this.get(NODE).isVisible()) {
+ if (this.inGroup(DDM.activeDrag.get('groups'))) {
+ node.removeClass(DDM.CSS_PREFIX + '-drop-active-invalid');
+ node.addClass(DDM.CSS_PREFIX + '-drop-active-valid');
+ DDM._addValid(this);
+ this.overTarget = false;
+ this.sizeShim();
+ } else {
+ DDM._removeValid(this);
+ node.removeClass(DDM.CSS_PREFIX + '-drop-active-valid');
+ node.addClass(DDM.CSS_PREFIX + '-drop-active-invalid');
+ }
+ },
+ /**
+ * @method sizeShim
+ * @description Positions and sizes the shim with the raw data from the node, this can be used to programatically adjust the Targets shim for Animation..
+ */
+ sizeShim: function() {
+ if (!DDM.activeDrag) {
+ return false; //Nothing is dragging, no reason to activate.
+ }
+ if (this.get(NODE) === DDM.activeDrag.get(NODE)) {
+ return false;
+ }
+ if (this.get('lock')) {
+ return false;
+ }
+ if (!this.shim) {
+ Y.later(100, this, this.sizeShim);
+ return false;
+ }
+ var node = this.get(NODE),
+ nh = node.get(OFFSET_HEIGHT),
+ nw = node.get(OFFSET_WIDTH),
+ xy = node.getXY(),
+ p = this.get('padding'),
+ dd, dH, dW;
+
+
+ //Apply padding
+ nw = nw + p.left + p.right;
+ nh = nh + p.top + p.bottom;
+ xy[0] = xy[0] - p.left;
+ xy[1] = xy[1] - p.top;
+
+
+ if (DDM.activeDrag.get('dragMode') === DDM.INTERSECT) {
+ //Intersect Mode, make the shim bigger
+ dd = DDM.activeDrag;
+ dH = dd.get(NODE).get(OFFSET_HEIGHT);
+ dW = dd.get(NODE).get(OFFSET_WIDTH);
+
+ nh = (nh + dH);
+ nw = (nw + dW);
+ xy[0] = xy[0] - (dW - dd.deltaXY[0]);
+ xy[1] = xy[1] - (dH - dd.deltaXY[1]);
+
+ }
+
+ //Set the style on the shim
+ this.shim.setStyles({
+ height: nh + 'px',
+ width: nw + 'px',
+ top: xy[1] + 'px',
+ left: xy[0] + 'px'
+ });
+
+ //Create the region to be used by intersect when a drag node is over us.
+ this.region = {
+ '0': xy[0],
+ '1': xy[1],
+ area: 0,
+ top: xy[1],
+ right: xy[0] + nw,
+ bottom: xy[1] + nh,
+ left: xy[0]
+ };
+ },
+ /**
+ * @private
+ * @method _createShim
+ * @description Creates the Target shim and adds it to the DDM's playground..
+ */
+ _createShim: function() {
+ //No playground, defer
+ if (!DDM._pg) {
+ Y.later(10, this, this._createShim);
+ return;
+ }
+ //Shim already here, cancel
+ if (this.shim) {
+ return;
+ }
+ var s = Y.Node.create('');
+
+ s.setStyles({
+ height: this.get(NODE).get(OFFSET_HEIGHT) + 'px',
+ width: this.get(NODE).get(OFFSET_WIDTH) + 'px',
+ backgroundColor: 'yellow',
+ opacity: '.5',
+ zIndex: '1',
+ overflow: 'hidden',
+ top: '-900px',
+ left: '-900px',
+ position: 'absolute'
+ });
+ DDM._pg.appendChild(s);
+ this.shim = s;
+
+ s.on('mouseover', Y.bind(this._handleOverEvent, this));
+ s.on('mouseout', Y.bind(this._handleOutEvent, this));
+ },
+ /**
+ * @private
+ * @method _handleOverTarget
+ * @description This handles the over target call made from this object or from the DDM
+ */
+ _handleTargetOver: function() {
+ if (DDM.isOverTarget(this)) {
+ this.get(NODE).addClass(DDM.CSS_PREFIX + '-drop-over');
+ DDM.activeDrop = this;
+ DDM.otherDrops[this] = this;
+ if (this.overTarget) {
+ DDM.activeDrag.fire('drag:over', { drop: this, drag: DDM.activeDrag });
+ this.fire(EV_DROP_OVER, { drop: this, drag: DDM.activeDrag });
+ } else {
+ this.overTarget = true;
+ this.fire(EV_DROP_ENTER, { drop: this, drag: DDM.activeDrag });
+ DDM.activeDrag.fire('drag:enter', { drop: this, drag: DDM.activeDrag });
+ DDM.activeDrag.get(NODE).addClass(DDM.CSS_PREFIX + '-drag-over');
+ //TODO - Is this needed??
+ //DDM._handleTargetOver();
+ }
+ } else {
+ this._handleOut();
+ }
+ },
+ /**
+ * @private
+ * @method _handleOverEvent
+ * @description Handles the mouseover DOM event on the Target Shim
+ */
+ _handleOverEvent: function() {
+ this.shim.setStyle('zIndex', '999');
+ DDM._addActiveShim(this);
+ },
+ /**
+ * @private
+ * @method _handleOutEvent
+ * @description Handles the mouseout DOM event on the Target Shim
+ */
+ _handleOutEvent: function() {
+ this.shim.setStyle('zIndex', '1');
+ DDM._removeActiveShim(this);
+ },
+ /**
+ * @private
+ * @method _handleOut
+ * @description Handles out of target calls/checks
+ */
+ _handleOut: function(force) {
+ if (!DDM.isOverTarget(this) || force) {
+ if (this.overTarget) {
+ this.overTarget = false;
+ if (!force) {
+ DDM._removeActiveShim(this);
+ }
+ if (DDM.activeDrag) {
+ this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-over');
+ DDM.activeDrag.get(NODE).removeClass(DDM.CSS_PREFIX + '-drag-over');
+ this.fire(EV_DROP_EXIT);
+ DDM.activeDrag.fire('drag:exit', { drop: this });
+ delete DDM.otherDrops[this];
+ //if (DDM.activeDrop === this) {
+ // DDM.activeDrop = null;
+ //}
+ }
+ }
+ }
+ }
+ });
+
+ Y.DD.Drop = Drop;
+
+
+
+
+
+}, '3.0.0' ,{requires:['dd-ddm-drop', 'dd-drag'], skinnable:false});
+YUI.add('dd-drop-plugin', function(Y) {
+
+
+ /**
+ * This is a simple Drop plugin that can be attached to a Node via the plug method.
+ * @module dd
+ * @submodule dd-drop-plugin
+ */
+ /**
+ * This is a simple Drop plugin that can be attached to a Node via the plug method.
+ * @class Drop
+ * @extends DD.Drop
+ * @constructor
+ * @namespace Plugin
+ */
+
+
+ var Drop = function(config) {
+ config.node = config.host;
+ Drop.superclass.constructor.apply(this, arguments);
+ };
+
+ /**
+ * @property NAME
+ * @description dd-drop-plugin
+ * @type {String}
+ */
+ Drop.NAME = "dd-drop-plugin";
+ /**
+ * @property NS
+ * @description The Drop instance will be placed on the Node instance under the drop namespace. It can be accessed via Node.drop;
+ * @type {String}
+ */
+ Drop.NS = "drop";
+
+
+ Y.extend(Drop, Y.DD.Drop);
+ Y.namespace('Plugin');
+ Y.Plugin.Drop = Drop;
+
+
+
+
+
+}, '3.0.0' ,{requires:['dd-drop'], skinnable:false});
+
+
+YUI.add('dd', function(Y){}, '3.0.0' ,{use:['dd-ddm-base', 'dd-ddm', 'dd-ddm-drop', 'dd-drag', 'dd-proxy', 'dd-constrain', 'dd-plugin', 'dd-drop', 'dd-drop-plugin', 'dd-scroll'], skinnable:false});
+
diff --git a/lib/yui/3.0.0/dom/dom-base-debug.js b/lib/yui/3.0.0/dom/dom-base-debug.js
new file mode 100644
index 0000000000..c7dcc253ef
--- /dev/null
+++ b/lib/yui/3.0.0/dom/dom-base-debug.js
@@ -0,0 +1,740 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dom-base', function(Y) {
+
+(function(Y) {
+/**
+ * The DOM utility provides a cross-browser abtraction layer
+ * normalizing DOM tasks, and adds extra helper functionality
+ * for other common tasks.
+ * @module dom
+ * @submodule dom-base
+ *
+ */
+
+/**
+ * Provides DOM helper methods.
+ * @class DOM
+ *
+ */
+var NODE_TYPE = 'nodeType',
+ OWNER_DOCUMENT = 'ownerDocument',
+ DEFAULT_VIEW = 'defaultView',
+ PARENT_WINDOW = 'parentWindow',
+ TAG_NAME = 'tagName',
+ PARENT_NODE = 'parentNode',
+ FIRST_CHILD = 'firstChild',
+ PREVIOUS_SIBLING = 'previousSibling',
+ NEXT_SIBLING = 'nextSibling',
+ CONTAINS = 'contains',
+ COMPARE_DOCUMENT_POSITION = 'compareDocumentPosition',
+
+ documentElement = document.documentElement,
+
+ re_tag = /<([a-z]+)/i;
+
+Y.DOM = {
+ /**
+ * Returns the HTMLElement with the given ID (Wrapper for document.getElementById).
+ * @method byId
+ * @param {String} id the id attribute
+ * @param {Object} doc optional The document to search. Defaults to current document
+ * @return {HTMLElement | null} The HTMLElement with the id, or null if none found.
+ */
+ byId: function(id, doc) {
+ doc = doc || Y.config.doc;
+ // TODO: IE Name
+ return doc.getElementById(id);
+ },
+
+ // @deprecated
+ children: function(node, tag) {
+ var ret = [];
+ if (node) {
+ tag = tag || '*';
+ ret = Y.Selector.query('> ' + tag, node);
+ }
+ return ret;
+ },
+
+ // @deprecated
+ firstByTag: function(tag, root) {
+ var ret;
+ root = root || Y.config.doc;
+
+ if (tag && root.getElementsByTagName) {
+ ret = root.getElementsByTagName(tag)[0];
+ }
+
+ return ret || null;
+ },
+
+ /**
+ * Returns the text content of the HTMLElement.
+ * @method getText
+ * @param {HTMLElement} element The html element.
+ * @return {String} The text content of the element (includes text of any descending elements).
+ */
+ getText: (documentElement.textContent !== undefined) ?
+ function(element) {
+ var ret = '';
+ if (element) {
+ ret = element.textContent;
+ }
+ return ret || '';
+ } : function(element) {
+ var ret = '';
+ if (element) {
+ ret = element.innerText;
+ }
+ return ret || '';
+ },
+
+ /**
+ * Sets the text content of the HTMLElement.
+ * @method setText
+ * @param {HTMLElement} element The html element.
+ * @param {String} content The content to add.
+ */
+ setText: (documentElement.textContent !== undefined) ?
+ function(element, content) {
+ if (element) {
+ element.textContent = content;
+ }
+ } : function(element, content) {
+ if (element) {
+ element.innerText = content;
+ }
+ },
+
+ /*
+ * Finds the previous sibling of the element.
+ * @method previous
+ * @deprecated Use elementByAxis
+ * @param {HTMLElement} element The html element.
+ * @param {Function} fn optional An optional boolean test to apply.
+ * The optional function is passed the current DOM node being tested as its only argument.
+ * If no function is given, the first sibling is returned.
+ * @param {Boolean} all optional Whether all node types should be scanned, or just element nodes.
+ * @return {HTMLElement | null} The matching DOM node or null if none found.
+ */
+ previous: function(element, fn, all) {
+ return Y.DOM.elementByAxis(element, PREVIOUS_SIBLING, fn, all);
+ },
+
+ /*
+ * Finds the next sibling of the element.
+ * @method next
+ * @deprecated Use elementByAxis
+ * @param {HTMLElement} element The html element.
+ * @param {Function} fn optional An optional boolean test to apply.
+ * The optional function is passed the current DOM node being tested as its only argument.
+ * If no function is given, the first sibling is returned.
+ * @param {Boolean} all optional Whether all node types should be scanned, or just element nodes.
+ * @return {HTMLElement | null} The matching DOM node or null if none found.
+ */
+ next: function(element, fn, all) {
+ return Y.DOM.elementByAxis(element, NEXT_SIBLING, fn, all);
+ },
+
+ /*
+ * Finds the ancestor of the element.
+ * @method ancestor
+ * @deprecated Use elementByAxis
+ * @param {HTMLElement} element The html element.
+ * @param {Function} fn optional An optional boolean test to apply.
+ * The optional function is passed the current DOM node being tested as its only argument.
+ * If no function is given, the parentNode is returned.
+ * @param {Boolean} all optional Whether all node types should be scanned, or just element nodes.
+ * @return {HTMLElement | null} The matching DOM node or null if none found.
+ */
+ // TODO: optional stopAt node?
+ ancestor: function(element, fn, all) {
+ return Y.DOM.elementByAxis(element, PARENT_NODE, fn, all);
+ },
+
+ /**
+ * Searches the element by the given axis for the first matching element.
+ * @method elementByAxis
+ * @param {HTMLElement} element The html element.
+ * @param {String} axis The axis to search (parentNode, nextSibling, previousSibling).
+ * @param {Function} fn optional An optional boolean test to apply.
+ * @param {Boolean} all optional Whether all node types should be returned, or just element nodes.
+ * The optional function is passed the current HTMLElement being tested as its only argument.
+ * If no function is given, the first element is returned.
+ * @return {HTMLElement | null} The matching element or null if none found.
+ */
+ elementByAxis: function(element, axis, fn, all) {
+ while (element && (element = element[axis])) { // NOTE: assignment
+ if ( (all || element[TAG_NAME]) && (!fn || fn(element)) ) {
+ return element;
+ }
+ }
+ return null;
+ },
+
+ /**
+ * Determines whether or not one HTMLElement is or contains another HTMLElement.
+ * @method contains
+ * @param {HTMLElement} element The containing html element.
+ * @param {HTMLElement} needle The html element that may be contained.
+ * @return {Boolean} Whether or not the element is or contains the needle.
+ */
+ contains: function(element, needle) {
+ var ret = false;
+
+ if ( !needle || !element || !needle[NODE_TYPE] || !element[NODE_TYPE]) {
+ ret = false;
+ } else if (element[CONTAINS]) {
+ if (Y.UA.opera || needle[NODE_TYPE] === 1) { // IE & SAF contains fail if needle not an ELEMENT_NODE
+ ret = element[CONTAINS](needle);
+ } else {
+ ret = Y.DOM._bruteContains(element, needle);
+ }
+ } else if (element[COMPARE_DOCUMENT_POSITION]) { // gecko
+ if (element === needle || !!(element[COMPARE_DOCUMENT_POSITION](needle) & 16)) {
+ ret = true;
+ }
+ }
+
+ return ret;
+ },
+
+ /**
+ * Determines whether or not the HTMLElement is part of the document.
+ * @method inDoc
+ * @param {HTMLElement} element The containing html element.
+ * @param {HTMLElement} doc optional The document to check.
+ * @return {Boolean} Whether or not the element is attached to the document.
+ */
+ inDoc: function(element, doc) {
+ doc = doc || element[OWNER_DOCUMENT];
+ var id = element.id;
+ if (!id) { // TODO: remove when done?
+ id = element.id = Y.guid();
+ }
+
+ return !! (doc.getElementById(id));
+ },
+
+ /**
+ * Creates a new dom node using the provided markup string.
+ * @method create
+ * @param {String} html The markup used to create the element
+ * @param {HTMLDocument} doc An optional document context
+ */
+ create: function(html, doc) {
+ if (typeof html === 'string') {
+ html = Y.Lang.trim(html); // match IE which trims whitespace from innerHTML
+ }
+
+ if (!doc && Y.DOM._cloneCache[html]) {
+ return Y.DOM._cloneCache[html].cloneNode(true); // NOTE: return
+ }
+
+ doc = doc || Y.config.doc;
+ var m = re_tag.exec(html),
+ create = Y.DOM._create,
+ custom = Y.DOM.creators,
+ ret = null,
+ tag, nodes;
+
+ if (m && custom[m[1]]) {
+ if (typeof custom[m[1]] === 'function') {
+ create = custom[m[1]];
+ } else {
+ tag = custom[m[1]];
+ }
+ }
+
+ nodes = create(html, doc, tag).childNodes;
+
+ if (nodes.length === 1) { // return single node, breaking parentNode ref from "fragment"
+ ret = nodes[0].parentNode.removeChild(nodes[0]);
+ } else { // return multiple nodes as a fragment
+ ret = Y.DOM._nl2frag(nodes, doc);
+ }
+
+ if (ret) {
+ Y.DOM._cloneCache[html] = ret.cloneNode(true);
+ }
+ return ret;
+ },
+
+ _nl2frag: function(nodes, doc) {
+ var ret = null,
+ i, len;
+
+ if (nodes && (nodes.push || nodes.item) && nodes[0]) {
+ doc = doc || nodes[0].ownerDocument;
+ ret = doc.createDocumentFragment();
+
+ if (nodes.item) { // convert live list to static array
+ nodes = Y.Array(nodes, 0, true);
+ }
+
+ for (i = 0, len = nodes.length; i < len; i++) {
+ ret.appendChild(nodes[i]);
+ }
+ } // else inline with log for minification
+ else { Y.log('unable to convert ' + nodes + ' to fragment', 'warn', 'dom'); }
+ return ret;
+ },
+
+
+ CUSTOM_ATTRIBUTES: (!documentElement.hasAttribute) ? { // IE < 8
+ 'for': 'htmlFor',
+ 'class': 'className'
+ } : { // w3c
+ 'htmlFor': 'for',
+ 'className': 'class'
+ },
+
+ /**
+ * Provides a normalized attribute interface.
+ * @method setAttibute
+ * @param {String | HTMLElement} el The target element for the attribute.
+ * @param {String} attr The attribute to set.
+ * @param {String} val The value of the attribute.
+ */
+ setAttribute: function(el, attr, val, ieAttr) {
+ if (el && el.setAttribute) {
+ attr = Y.DOM.CUSTOM_ATTRIBUTES[attr] || attr;
+ el.setAttribute(attr, val, ieAttr);
+ }
+ },
+
+
+ /**
+ * Provides a normalized attribute interface.
+ * @method getAttibute
+ * @param {String | HTMLElement} el The target element for the attribute.
+ * @param {String} attr The attribute to get.
+ * @return {String} The current value of the attribute.
+ */
+ getAttribute: function(el, attr, ieAttr) {
+ ieAttr = (ieAttr !== undefined) ? ieAttr : 2;
+ var ret = '';
+ if (el && el.getAttribute) {
+ attr = Y.DOM.CUSTOM_ATTRIBUTES[attr] || attr;
+ ret = el.getAttribute(attr, ieAttr);
+
+ if (ret === null) {
+ ret = ''; // per DOM spec
+ }
+ }
+ return ret;
+ },
+
+ isWindow: function(obj) {
+ return obj.alert && obj.document;
+ },
+
+ _fragClones: {
+ div: document.createElement('div')
+ },
+
+ _create: function(html, doc, tag) {
+ tag = tag || 'div';
+
+ var frag = Y.DOM._fragClones[tag];
+ if (frag) {
+ frag = frag.cloneNode(false);
+ } else {
+ frag = Y.DOM._fragClones[tag] = doc.createElement(tag);
+ }
+ frag.innerHTML = html;
+ return frag;
+ },
+
+ _removeChildNodes: function(node) {
+ while (node.firstChild) {
+ node.removeChild(node.firstChild);
+ }
+ },
+
+ _cloneCache: {},
+
+ /**
+ * Inserts content in a node at the given location
+ * @method addHTML
+ * @param {HTMLElement} node The node to insert into
+ * @param {String} content The content to be inserted
+ * @param {String} where Where to insert the content; default is after lastChild
+ */
+ addHTML: function(node, content, where) {
+ if (typeof content === 'string') {
+ content = Y.Lang.trim(content); // match IE which trims whitespace from innerHTML
+ }
+
+ var newNode = Y.DOM._cloneCache[content],
+ nodeParent = node.parentNode;
+
+ if (newNode) {
+ newNode = newNode.cloneNode(true);
+ } else {
+ if (content.nodeType) { // domNode
+ newNode = content;
+ } else { // create from string and cache
+ newNode = Y.DOM.create(content);
+ }
+ }
+
+ if (where) {
+ if (where.nodeType) { // insert regardless of relationship to node
+ // TODO: check if node.contains(where)?
+ where.parentNode.insertBefore(newNode, where);
+ } else {
+ switch (where) {
+ case 'replace':
+ while (node.firstChild) {
+ node.removeChild(node.firstChild);
+ }
+ node.appendChild(newNode);
+ break;
+ case 'before':
+ nodeParent.insertBefore(newNode, node);
+ break;
+ case 'after':
+ if (node.nextSibling) { // IE errors if refNode is null
+ nodeParent.insertBefore(newNode, node.nextSibling);
+ } else {
+ nodeParent.appendChild(newNode);
+ }
+ break;
+ default:
+ node.appendChild(newNode);
+ }
+ }
+ } else {
+ node.appendChild(newNode);
+ }
+
+ return newNode;
+ },
+
+ VALUE_SETTERS: {},
+
+ VALUE_GETTERS: {},
+
+ getValue: function(node) {
+ var ret = '', // TODO: return null?
+ getter;
+
+ if (node && node[TAG_NAME]) {
+ getter = Y.DOM.VALUE_GETTERS[node[TAG_NAME].toLowerCase()];
+
+ if (getter) {
+ ret = getter(node);
+ } else {
+ ret = node.value;
+ }
+ }
+
+ return (typeof ret === 'string') ? ret : '';
+ },
+
+ setValue: function(node, val) {
+ var setter;
+
+ if (node && node[TAG_NAME]) {
+ setter = Y.DOM.VALUE_SETTERS[node[TAG_NAME].toLowerCase()];
+
+ if (setter) {
+ setter(node, val);
+ } else {
+ node.value = val;
+ }
+ }
+ },
+
+ /**
+ * Brute force version of contains.
+ * Used for browsers without contains support for non-HTMLElement Nodes (textNodes, etc).
+ * @method _bruteContains
+ * @private
+ * @param {HTMLElement} element The containing html element.
+ * @param {HTMLElement} needle The html element that may be contained.
+ * @return {Boolean} Whether or not the element is or contains the needle.
+ */
+ _bruteContains: function(element, needle) {
+ while (needle) {
+ if (element === needle) {
+ return true;
+ }
+ needle = needle.parentNode;
+ }
+ return false;
+ },
+
+// TODO: move to Lang?
+ /**
+ * Memoizes dynamic regular expressions to boost runtime performance.
+ * @method _getRegExp
+ * @private
+ * @param {String} str The string to convert to a regular expression.
+ * @param {String} flags optional An optinal string of flags.
+ * @return {RegExp} An instance of RegExp
+ */
+ _getRegExp: function(str, flags) {
+ flags = flags || '';
+ Y.DOM._regexCache = Y.DOM._regexCache || {};
+ if (!Y.DOM._regexCache[str + flags]) {
+ Y.DOM._regexCache[str + flags] = new RegExp(str, flags);
+ }
+ return Y.DOM._regexCache[str + flags];
+ },
+
+// TODO: make getDoc/Win true privates?
+ /**
+ * returns the appropriate document.
+ * @method _getDoc
+ * @private
+ * @param {HTMLElement} element optional Target element.
+ * @return {Object} The document for the given element or the default document.
+ */
+ _getDoc: function(element) {
+ element = element || {};
+
+ return (element[NODE_TYPE] === 9) ? element : // element === document
+ element[OWNER_DOCUMENT] || // element === DOM node
+ element.document || // element === window
+ Y.config.doc; // default
+ },
+
+ /**
+ * returns the appropriate window.
+ * @method _getWin
+ * @private
+ * @param {HTMLElement} element optional Target element.
+ * @return {Object} The window for the given element or the default window.
+ */
+ _getWin: function(element) {
+ var doc = Y.DOM._getDoc(element);
+ return doc[DEFAULT_VIEW] || doc[PARENT_WINDOW] || Y.config.win;
+ },
+
+ _batch: function(nodes, fn, arg1, arg2, arg3, etc) {
+ fn = (typeof name === 'string') ? Y.DOM[fn] : fn;
+ var result,
+ ret = [];
+
+ if (fn && nodes) {
+ Y.each(nodes, function(node) {
+ if ((result = fn.call(Y.DOM, node, arg1, arg2, arg3, etc)) !== undefined) {
+ ret[ret.length] = result;
+ }
+ });
+ }
+
+ return ret.length ? ret : nodes;
+ },
+
+ _testElement: function(element, tag, fn) {
+ tag = (tag && tag !== '*') ? tag.toUpperCase() : null;
+ return (element && element[TAG_NAME] &&
+ (!tag || element[TAG_NAME].toUpperCase() === tag) &&
+ (!fn || fn(element)));
+ },
+
+ creators: {},
+
+ _IESimpleCreate: function(html, doc) {
+ doc = doc || Y.config.doc;
+ return doc.createElement(html);
+ }
+};
+
+
+(function(Y) {
+ var creators = Y.DOM.creators,
+ create = Y.DOM.create,
+ re_tbody = /(?:\/(?:thead|tfoot|tbody|caption|col|colgroup)>)+\s* 1 && tb && !re_tbody.test(html)) {
+ tb[PARENT_NODE].removeChild(tb); // strip extraneous tbody
+ }
+ return frag;
+ },
+
+ script: function(html, doc) {
+ var frag = doc.createElement('div');
+
+ frag.innerHTML = '-' + html;
+ frag.removeChild(frag[FIRST_CHILD]);
+ return frag;
+ }
+
+ }, true);
+
+ Y.mix(Y.DOM.VALUE_GETTERS, {
+ button: function(node) {
+ return (node.attributes && node.attributes.value) ? node.attributes.value.value : '';
+ }
+ });
+
+ Y.mix(Y.DOM.VALUE_SETTERS, {
+ // IE: node.value changes the button text, which should be handled via innerHTML
+ button: function(node, val) {
+ var attr = node.attributes.value;
+ if (!attr) {
+ attr = node[OWNER_DOCUMENT].createAttribute('value');
+ node.setAttributeNode(attr);
+ }
+
+ attr.value = val;
+ }
+ });
+ }
+
+ if (Y.UA.gecko || Y.UA.ie) {
+ Y.mix(creators, {
+ option: function(html, doc) {
+ return create('', doc);
+ },
+
+ tr: function(html, doc) {
+ return create('' + html + '', doc);
+ },
+
+ td: function(html, doc) {
+ return create('
' + html + '
', doc);
+ },
+
+ tbody: function(html, doc) {
+ return create(TABLE_OPEN + html + TABLE_CLOSE, doc);
+ }
+ });
+
+ Y.mix(creators, {
+ legend: 'fieldset',
+ th: creators.td,
+ thead: creators.tbody,
+ tfoot: creators.tbody,
+ caption: creators.tbody,
+ colgroup: creators.tbody,
+ col: creators.tbody,
+ optgroup: creators.option
+ });
+ }
+
+ Y.mix(Y.DOM.VALUE_GETTERS, {
+ option: function(node) {
+ var attrs = node.attributes;
+ return (attrs.value && attrs.value.specified) ? node.value : node.text;
+ },
+
+ select: function(node) {
+ var val = node.value,
+ options = node.options;
+
+ if (options && val === '') {
+ if (node.multiple) {
+ Y.log('multiple select normalization not implemented', 'warn', 'DOM');
+ } else {
+ val = Y.DOM.getValue(options[node.selectedIndex], 'value');
+ }
+ }
+
+ return val;
+ }
+ });
+})(Y);
+
+})(Y);
+var addClass, hasClass, removeClass;
+
+Y.mix(Y.DOM, {
+ /**
+ * Determines whether a DOM element has the given className.
+ * @method hasClass
+ * @param {HTMLElement} element The DOM element.
+ * @param {String} className the class name to search for
+ * @return {Boolean} Whether or not the element has the given class.
+ */
+ hasClass: function(node, className) {
+ var re = Y.DOM._getRegExp('(?:^|\\s+)' + className + '(?:\\s+|$)');
+ return re.test(node.className);
+ },
+
+ /**
+ * Adds a class name to a given DOM element.
+ * @method addClass
+ * @param {HTMLElement} element The DOM element.
+ * @param {String} className the class name to add to the class attribute
+ */
+ addClass: function(node, className) {
+ if (!Y.DOM.hasClass(node, className)) { // skip if already present
+ node.className = Y.Lang.trim([node.className, className].join(' '));
+ }
+ },
+
+ /**
+ * Removes a class name from a given element.
+ * @method removeClass
+ * @param {HTMLElement} element The DOM element.
+ * @param {String} className the class name to remove from the class attribute
+ */
+ removeClass: function(node, className) {
+ if (className && hasClass(node, className)) {
+ node.className = Y.Lang.trim(node.className.replace(Y.DOM._getRegExp('(?:^|\\s+)' +
+ className + '(?:\\s+|$)'), ' '));
+
+ if ( hasClass(node, className) ) { // in case of multiple adjacent
+ removeClass(node, className);
+ }
+ }
+ },
+
+ /**
+ * Replace a class with another class for a given element.
+ * If no oldClassName is present, the newClassName is simply added.
+ * @method replaceClass
+ * @param {HTMLElement} element The DOM element.
+ * @param {String} oldClassName the class name to be replaced
+ * @param {String} newClassName the class name that will be replacing the old class name
+ */
+ replaceClass: function(node, oldC, newC) {
+ //Y.log('replaceClass replacing ' + oldC + ' with ' + newC, 'info', 'Node');
+ addClass(node, newC);
+ removeClass(node, oldC);
+ },
+
+ /**
+ * If the className exists on the node it is removed, if it doesn't exist it is added.
+ * @method toggleClass
+ * @param {HTMLElement} element The DOM element.
+ * @param {String} className the class name to be toggled
+ */
+ toggleClass: function(node, className) {
+ if (hasClass(node, className)) {
+ removeClass(node, className);
+ } else {
+ addClass(node, className);
+ }
+ }
+});
+
+hasClass = Y.DOM.hasClass;
+removeClass = Y.DOM.removeClass;
+addClass = Y.DOM.addClass;
+
+
+
+}, '3.0.0' ,{requires:['oop']});
diff --git a/lib/yui/3.0.0/dom/dom-base-min.js b/lib/yui/3.0.0/dom/dom-base-min.js
new file mode 100644
index 0000000000..c1c847efd7
--- /dev/null
+++ b/lib/yui/3.0.0/dom/dom-base-min.js
@@ -0,0 +1,9 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("dom-base",function(D){(function(H){var R="nodeType",F="ownerDocument",E="defaultView",J="parentWindow",M="tagName",O="parentNode",Q="firstChild",L="previousSibling",P="nextSibling",K="contains",G="compareDocumentPosition",N=document.documentElement,I=/<([a-z]+)/i;H.DOM={byId:function(T,S){S=S||H.config.doc;return S.getElementById(T);},children:function(U,S){var T=[];if(U){S=S||"*";T=H.Selector.query("> "+S,U);}return T;},firstByTag:function(S,T){var U;T=T||H.config.doc;if(S&&T.getElementsByTagName){U=T.getElementsByTagName(S)[0];}return U||null;},getText:(N.textContent!==undefined)?function(T){var S="";if(T){S=T.textContent;}return S||"";}:function(T){var S="";if(T){S=T.innerText;}return S||"";},setText:(N.textContent!==undefined)?function(S,T){if(S){S.textContent=T;}}:function(S,T){if(S){S.innerText=T;}},previous:function(S,U,T){return H.DOM.elementByAxis(S,L,U,T);},next:function(S,U,T){return H.DOM.elementByAxis(S,P,U,T);},ancestor:function(S,U,T){return H.DOM.elementByAxis(S,O,U,T);},elementByAxis:function(S,V,U,T){while(S&&(S=S[V])){if((T||S[M])&&(!U||U(S))){return S;}}return null;},contains:function(T,U){var S=false;if(!U||!T||!U[R]||!T[R]){S=false;}else{if(T[K]){if(H.UA.opera||U[R]===1){S=T[K](U);}else{S=H.DOM._bruteContains(T,U);}}else{if(T[G]){if(T===U||!!(T[G](U)&16)){S=true;}}}}return S;},inDoc:function(S,T){T=T||S[F];var U=S.id;if(!U){U=S.id=H.guid();}return !!(T.getElementById(U));},create:function(X,Z){if(typeof X==="string"){X=H.Lang.trim(X);}if(!Z&&H.DOM._cloneCache[X]){return H.DOM._cloneCache[X].cloneNode(true);}Z=Z||H.config.doc;var T=I.exec(X),W=H.DOM._create,Y=H.DOM.creators,V=null,S,U;if(T&&Y[T[1]]){if(typeof Y[T[1]]==="function"){W=Y[T[1]];}else{S=Y[T[1]];}}U=W(X,Z,S).childNodes;if(U.length===1){V=U[0].parentNode.removeChild(U[0]);}else{V=H.DOM._nl2frag(U,Z);}if(V){H.DOM._cloneCache[X]=V.cloneNode(true);}return V;},_nl2frag:function(T,W){var U=null,V,S;if(T&&(T.push||T.item)&&T[0]){W=W||T[0].ownerDocument;U=W.createDocumentFragment();if(T.item){T=H.Array(T,0,true);}for(V=0,S=T.length;V)+\s*",T="";if(W.UA.ie){W.mix(X,{tbody:function(Z,a){var b=S(U+Z+T,a),Y=b.children.tags("tbody")[0];if(b.children.length>1&&Y&&!V.test(Z)){Y[O].removeChild(Y);}return b;},script:function(Y,Z){var a=Z.createElement("div");a.innerHTML="-"+Y;a.removeChild(a[Q]);return a;}},true);W.mix(W.DOM.VALUE_GETTERS,{button:function(Y){return(Y.attributes&&Y.attributes.value)?Y.attributes.value.value:"";}});W.mix(W.DOM.VALUE_SETTERS,{button:function(Z,a){var Y=Z.attributes.value;if(!Y){Y=Z[F].createAttribute("value");Z.setAttributeNode(Y);}Y.value=a;}});}if(W.UA.gecko||W.UA.ie){W.mix(X,{option:function(Y,Z){return S("",Z);},tr:function(Y,Z){return S(""+Y+"",Z);},td:function(Y,Z){return S("
"+Y+"
",Z);},tbody:function(Y,Z){return S(U+Y+T,Z);}});W.mix(X,{legend:"fieldset",th:X.td,thead:X.tbody,tfoot:X.tbody,caption:X.tbody,colgroup:X.tbody,col:X.tbody,optgroup:X.option});}W.mix(W.DOM.VALUE_GETTERS,{option:function(Z){var Y=Z.attributes;return(Y.value&&Y.value.specified)?Z.value:Z.text;},select:function(Z){var a=Z.value,Y=Z.options;if(Y&&a===""){if(Z.multiple){}else{a=W.DOM.getValue(Y[Z.selectedIndex],"value");}}return a;}});})(H);})(D);var B,A,C;D.mix(D.DOM,{hasClass:function(G,F){var E=D.DOM._getRegExp("(?:^|\\s+)"+F+"(?:\\s+|$)");return E.test(G.className);},addClass:function(F,E){if(!D.DOM.hasClass(F,E)){F.className=D.Lang.trim([F.className,E].join(" "));
+}},removeClass:function(F,E){if(E&&A(F,E)){F.className=D.Lang.trim(F.className.replace(D.DOM._getRegExp("(?:^|\\s+)"+E+"(?:\\s+|$)")," "));if(A(F,E)){C(F,E);}}},replaceClass:function(F,E,G){B(F,G);C(F,E);},toggleClass:function(F,E){if(A(F,E)){C(F,E);}else{B(F,E);}}});A=D.DOM.hasClass;C=D.DOM.removeClass;B=D.DOM.addClass;},"3.0.0",{requires:["oop"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/dom/dom-base.js b/lib/yui/3.0.0/dom/dom-base.js
new file mode 100644
index 0000000000..80181ff6cb
--- /dev/null
+++ b/lib/yui/3.0.0/dom/dom-base.js
@@ -0,0 +1,737 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dom-base', function(Y) {
+
+(function(Y) {
+/**
+ * The DOM utility provides a cross-browser abtraction layer
+ * normalizing DOM tasks, and adds extra helper functionality
+ * for other common tasks.
+ * @module dom
+ * @submodule dom-base
+ *
+ */
+
+/**
+ * Provides DOM helper methods.
+ * @class DOM
+ *
+ */
+var NODE_TYPE = 'nodeType',
+ OWNER_DOCUMENT = 'ownerDocument',
+ DEFAULT_VIEW = 'defaultView',
+ PARENT_WINDOW = 'parentWindow',
+ TAG_NAME = 'tagName',
+ PARENT_NODE = 'parentNode',
+ FIRST_CHILD = 'firstChild',
+ PREVIOUS_SIBLING = 'previousSibling',
+ NEXT_SIBLING = 'nextSibling',
+ CONTAINS = 'contains',
+ COMPARE_DOCUMENT_POSITION = 'compareDocumentPosition',
+
+ documentElement = document.documentElement,
+
+ re_tag = /<([a-z]+)/i;
+
+Y.DOM = {
+ /**
+ * Returns the HTMLElement with the given ID (Wrapper for document.getElementById).
+ * @method byId
+ * @param {String} id the id attribute
+ * @param {Object} doc optional The document to search. Defaults to current document
+ * @return {HTMLElement | null} The HTMLElement with the id, or null if none found.
+ */
+ byId: function(id, doc) {
+ doc = doc || Y.config.doc;
+ // TODO: IE Name
+ return doc.getElementById(id);
+ },
+
+ // @deprecated
+ children: function(node, tag) {
+ var ret = [];
+ if (node) {
+ tag = tag || '*';
+ ret = Y.Selector.query('> ' + tag, node);
+ }
+ return ret;
+ },
+
+ // @deprecated
+ firstByTag: function(tag, root) {
+ var ret;
+ root = root || Y.config.doc;
+
+ if (tag && root.getElementsByTagName) {
+ ret = root.getElementsByTagName(tag)[0];
+ }
+
+ return ret || null;
+ },
+
+ /**
+ * Returns the text content of the HTMLElement.
+ * @method getText
+ * @param {HTMLElement} element The html element.
+ * @return {String} The text content of the element (includes text of any descending elements).
+ */
+ getText: (documentElement.textContent !== undefined) ?
+ function(element) {
+ var ret = '';
+ if (element) {
+ ret = element.textContent;
+ }
+ return ret || '';
+ } : function(element) {
+ var ret = '';
+ if (element) {
+ ret = element.innerText;
+ }
+ return ret || '';
+ },
+
+ /**
+ * Sets the text content of the HTMLElement.
+ * @method setText
+ * @param {HTMLElement} element The html element.
+ * @param {String} content The content to add.
+ */
+ setText: (documentElement.textContent !== undefined) ?
+ function(element, content) {
+ if (element) {
+ element.textContent = content;
+ }
+ } : function(element, content) {
+ if (element) {
+ element.innerText = content;
+ }
+ },
+
+ /*
+ * Finds the previous sibling of the element.
+ * @method previous
+ * @deprecated Use elementByAxis
+ * @param {HTMLElement} element The html element.
+ * @param {Function} fn optional An optional boolean test to apply.
+ * The optional function is passed the current DOM node being tested as its only argument.
+ * If no function is given, the first sibling is returned.
+ * @param {Boolean} all optional Whether all node types should be scanned, or just element nodes.
+ * @return {HTMLElement | null} The matching DOM node or null if none found.
+ */
+ previous: function(element, fn, all) {
+ return Y.DOM.elementByAxis(element, PREVIOUS_SIBLING, fn, all);
+ },
+
+ /*
+ * Finds the next sibling of the element.
+ * @method next
+ * @deprecated Use elementByAxis
+ * @param {HTMLElement} element The html element.
+ * @param {Function} fn optional An optional boolean test to apply.
+ * The optional function is passed the current DOM node being tested as its only argument.
+ * If no function is given, the first sibling is returned.
+ * @param {Boolean} all optional Whether all node types should be scanned, or just element nodes.
+ * @return {HTMLElement | null} The matching DOM node or null if none found.
+ */
+ next: function(element, fn, all) {
+ return Y.DOM.elementByAxis(element, NEXT_SIBLING, fn, all);
+ },
+
+ /*
+ * Finds the ancestor of the element.
+ * @method ancestor
+ * @deprecated Use elementByAxis
+ * @param {HTMLElement} element The html element.
+ * @param {Function} fn optional An optional boolean test to apply.
+ * The optional function is passed the current DOM node being tested as its only argument.
+ * If no function is given, the parentNode is returned.
+ * @param {Boolean} all optional Whether all node types should be scanned, or just element nodes.
+ * @return {HTMLElement | null} The matching DOM node or null if none found.
+ */
+ // TODO: optional stopAt node?
+ ancestor: function(element, fn, all) {
+ return Y.DOM.elementByAxis(element, PARENT_NODE, fn, all);
+ },
+
+ /**
+ * Searches the element by the given axis for the first matching element.
+ * @method elementByAxis
+ * @param {HTMLElement} element The html element.
+ * @param {String} axis The axis to search (parentNode, nextSibling, previousSibling).
+ * @param {Function} fn optional An optional boolean test to apply.
+ * @param {Boolean} all optional Whether all node types should be returned, or just element nodes.
+ * The optional function is passed the current HTMLElement being tested as its only argument.
+ * If no function is given, the first element is returned.
+ * @return {HTMLElement | null} The matching element or null if none found.
+ */
+ elementByAxis: function(element, axis, fn, all) {
+ while (element && (element = element[axis])) { // NOTE: assignment
+ if ( (all || element[TAG_NAME]) && (!fn || fn(element)) ) {
+ return element;
+ }
+ }
+ return null;
+ },
+
+ /**
+ * Determines whether or not one HTMLElement is or contains another HTMLElement.
+ * @method contains
+ * @param {HTMLElement} element The containing html element.
+ * @param {HTMLElement} needle The html element that may be contained.
+ * @return {Boolean} Whether or not the element is or contains the needle.
+ */
+ contains: function(element, needle) {
+ var ret = false;
+
+ if ( !needle || !element || !needle[NODE_TYPE] || !element[NODE_TYPE]) {
+ ret = false;
+ } else if (element[CONTAINS]) {
+ if (Y.UA.opera || needle[NODE_TYPE] === 1) { // IE & SAF contains fail if needle not an ELEMENT_NODE
+ ret = element[CONTAINS](needle);
+ } else {
+ ret = Y.DOM._bruteContains(element, needle);
+ }
+ } else if (element[COMPARE_DOCUMENT_POSITION]) { // gecko
+ if (element === needle || !!(element[COMPARE_DOCUMENT_POSITION](needle) & 16)) {
+ ret = true;
+ }
+ }
+
+ return ret;
+ },
+
+ /**
+ * Determines whether or not the HTMLElement is part of the document.
+ * @method inDoc
+ * @param {HTMLElement} element The containing html element.
+ * @param {HTMLElement} doc optional The document to check.
+ * @return {Boolean} Whether or not the element is attached to the document.
+ */
+ inDoc: function(element, doc) {
+ doc = doc || element[OWNER_DOCUMENT];
+ var id = element.id;
+ if (!id) { // TODO: remove when done?
+ id = element.id = Y.guid();
+ }
+
+ return !! (doc.getElementById(id));
+ },
+
+ /**
+ * Creates a new dom node using the provided markup string.
+ * @method create
+ * @param {String} html The markup used to create the element
+ * @param {HTMLDocument} doc An optional document context
+ */
+ create: function(html, doc) {
+ if (typeof html === 'string') {
+ html = Y.Lang.trim(html); // match IE which trims whitespace from innerHTML
+ }
+
+ if (!doc && Y.DOM._cloneCache[html]) {
+ return Y.DOM._cloneCache[html].cloneNode(true); // NOTE: return
+ }
+
+ doc = doc || Y.config.doc;
+ var m = re_tag.exec(html),
+ create = Y.DOM._create,
+ custom = Y.DOM.creators,
+ ret = null,
+ tag, nodes;
+
+ if (m && custom[m[1]]) {
+ if (typeof custom[m[1]] === 'function') {
+ create = custom[m[1]];
+ } else {
+ tag = custom[m[1]];
+ }
+ }
+
+ nodes = create(html, doc, tag).childNodes;
+
+ if (nodes.length === 1) { // return single node, breaking parentNode ref from "fragment"
+ ret = nodes[0].parentNode.removeChild(nodes[0]);
+ } else { // return multiple nodes as a fragment
+ ret = Y.DOM._nl2frag(nodes, doc);
+ }
+
+ if (ret) {
+ Y.DOM._cloneCache[html] = ret.cloneNode(true);
+ }
+ return ret;
+ },
+
+ _nl2frag: function(nodes, doc) {
+ var ret = null,
+ i, len;
+
+ if (nodes && (nodes.push || nodes.item) && nodes[0]) {
+ doc = doc || nodes[0].ownerDocument;
+ ret = doc.createDocumentFragment();
+
+ if (nodes.item) { // convert live list to static array
+ nodes = Y.Array(nodes, 0, true);
+ }
+
+ for (i = 0, len = nodes.length; i < len; i++) {
+ ret.appendChild(nodes[i]);
+ }
+ } // else inline with log for minification
+ return ret;
+ },
+
+
+ CUSTOM_ATTRIBUTES: (!documentElement.hasAttribute) ? { // IE < 8
+ 'for': 'htmlFor',
+ 'class': 'className'
+ } : { // w3c
+ 'htmlFor': 'for',
+ 'className': 'class'
+ },
+
+ /**
+ * Provides a normalized attribute interface.
+ * @method setAttibute
+ * @param {String | HTMLElement} el The target element for the attribute.
+ * @param {String} attr The attribute to set.
+ * @param {String} val The value of the attribute.
+ */
+ setAttribute: function(el, attr, val, ieAttr) {
+ if (el && el.setAttribute) {
+ attr = Y.DOM.CUSTOM_ATTRIBUTES[attr] || attr;
+ el.setAttribute(attr, val, ieAttr);
+ }
+ },
+
+
+ /**
+ * Provides a normalized attribute interface.
+ * @method getAttibute
+ * @param {String | HTMLElement} el The target element for the attribute.
+ * @param {String} attr The attribute to get.
+ * @return {String} The current value of the attribute.
+ */
+ getAttribute: function(el, attr, ieAttr) {
+ ieAttr = (ieAttr !== undefined) ? ieAttr : 2;
+ var ret = '';
+ if (el && el.getAttribute) {
+ attr = Y.DOM.CUSTOM_ATTRIBUTES[attr] || attr;
+ ret = el.getAttribute(attr, ieAttr);
+
+ if (ret === null) {
+ ret = ''; // per DOM spec
+ }
+ }
+ return ret;
+ },
+
+ isWindow: function(obj) {
+ return obj.alert && obj.document;
+ },
+
+ _fragClones: {
+ div: document.createElement('div')
+ },
+
+ _create: function(html, doc, tag) {
+ tag = tag || 'div';
+
+ var frag = Y.DOM._fragClones[tag];
+ if (frag) {
+ frag = frag.cloneNode(false);
+ } else {
+ frag = Y.DOM._fragClones[tag] = doc.createElement(tag);
+ }
+ frag.innerHTML = html;
+ return frag;
+ },
+
+ _removeChildNodes: function(node) {
+ while (node.firstChild) {
+ node.removeChild(node.firstChild);
+ }
+ },
+
+ _cloneCache: {},
+
+ /**
+ * Inserts content in a node at the given location
+ * @method addHTML
+ * @param {HTMLElement} node The node to insert into
+ * @param {String} content The content to be inserted
+ * @param {String} where Where to insert the content; default is after lastChild
+ */
+ addHTML: function(node, content, where) {
+ if (typeof content === 'string') {
+ content = Y.Lang.trim(content); // match IE which trims whitespace from innerHTML
+ }
+
+ var newNode = Y.DOM._cloneCache[content],
+ nodeParent = node.parentNode;
+
+ if (newNode) {
+ newNode = newNode.cloneNode(true);
+ } else {
+ if (content.nodeType) { // domNode
+ newNode = content;
+ } else { // create from string and cache
+ newNode = Y.DOM.create(content);
+ }
+ }
+
+ if (where) {
+ if (where.nodeType) { // insert regardless of relationship to node
+ // TODO: check if node.contains(where)?
+ where.parentNode.insertBefore(newNode, where);
+ } else {
+ switch (where) {
+ case 'replace':
+ while (node.firstChild) {
+ node.removeChild(node.firstChild);
+ }
+ node.appendChild(newNode);
+ break;
+ case 'before':
+ nodeParent.insertBefore(newNode, node);
+ break;
+ case 'after':
+ if (node.nextSibling) { // IE errors if refNode is null
+ nodeParent.insertBefore(newNode, node.nextSibling);
+ } else {
+ nodeParent.appendChild(newNode);
+ }
+ break;
+ default:
+ node.appendChild(newNode);
+ }
+ }
+ } else {
+ node.appendChild(newNode);
+ }
+
+ return newNode;
+ },
+
+ VALUE_SETTERS: {},
+
+ VALUE_GETTERS: {},
+
+ getValue: function(node) {
+ var ret = '', // TODO: return null?
+ getter;
+
+ if (node && node[TAG_NAME]) {
+ getter = Y.DOM.VALUE_GETTERS[node[TAG_NAME].toLowerCase()];
+
+ if (getter) {
+ ret = getter(node);
+ } else {
+ ret = node.value;
+ }
+ }
+
+ return (typeof ret === 'string') ? ret : '';
+ },
+
+ setValue: function(node, val) {
+ var setter;
+
+ if (node && node[TAG_NAME]) {
+ setter = Y.DOM.VALUE_SETTERS[node[TAG_NAME].toLowerCase()];
+
+ if (setter) {
+ setter(node, val);
+ } else {
+ node.value = val;
+ }
+ }
+ },
+
+ /**
+ * Brute force version of contains.
+ * Used for browsers without contains support for non-HTMLElement Nodes (textNodes, etc).
+ * @method _bruteContains
+ * @private
+ * @param {HTMLElement} element The containing html element.
+ * @param {HTMLElement} needle The html element that may be contained.
+ * @return {Boolean} Whether or not the element is or contains the needle.
+ */
+ _bruteContains: function(element, needle) {
+ while (needle) {
+ if (element === needle) {
+ return true;
+ }
+ needle = needle.parentNode;
+ }
+ return false;
+ },
+
+// TODO: move to Lang?
+ /**
+ * Memoizes dynamic regular expressions to boost runtime performance.
+ * @method _getRegExp
+ * @private
+ * @param {String} str The string to convert to a regular expression.
+ * @param {String} flags optional An optinal string of flags.
+ * @return {RegExp} An instance of RegExp
+ */
+ _getRegExp: function(str, flags) {
+ flags = flags || '';
+ Y.DOM._regexCache = Y.DOM._regexCache || {};
+ if (!Y.DOM._regexCache[str + flags]) {
+ Y.DOM._regexCache[str + flags] = new RegExp(str, flags);
+ }
+ return Y.DOM._regexCache[str + flags];
+ },
+
+// TODO: make getDoc/Win true privates?
+ /**
+ * returns the appropriate document.
+ * @method _getDoc
+ * @private
+ * @param {HTMLElement} element optional Target element.
+ * @return {Object} The document for the given element or the default document.
+ */
+ _getDoc: function(element) {
+ element = element || {};
+
+ return (element[NODE_TYPE] === 9) ? element : // element === document
+ element[OWNER_DOCUMENT] || // element === DOM node
+ element.document || // element === window
+ Y.config.doc; // default
+ },
+
+ /**
+ * returns the appropriate window.
+ * @method _getWin
+ * @private
+ * @param {HTMLElement} element optional Target element.
+ * @return {Object} The window for the given element or the default window.
+ */
+ _getWin: function(element) {
+ var doc = Y.DOM._getDoc(element);
+ return doc[DEFAULT_VIEW] || doc[PARENT_WINDOW] || Y.config.win;
+ },
+
+ _batch: function(nodes, fn, arg1, arg2, arg3, etc) {
+ fn = (typeof name === 'string') ? Y.DOM[fn] : fn;
+ var result,
+ ret = [];
+
+ if (fn && nodes) {
+ Y.each(nodes, function(node) {
+ if ((result = fn.call(Y.DOM, node, arg1, arg2, arg3, etc)) !== undefined) {
+ ret[ret.length] = result;
+ }
+ });
+ }
+
+ return ret.length ? ret : nodes;
+ },
+
+ _testElement: function(element, tag, fn) {
+ tag = (tag && tag !== '*') ? tag.toUpperCase() : null;
+ return (element && element[TAG_NAME] &&
+ (!tag || element[TAG_NAME].toUpperCase() === tag) &&
+ (!fn || fn(element)));
+ },
+
+ creators: {},
+
+ _IESimpleCreate: function(html, doc) {
+ doc = doc || Y.config.doc;
+ return doc.createElement(html);
+ }
+};
+
+
+(function(Y) {
+ var creators = Y.DOM.creators,
+ create = Y.DOM.create,
+ re_tbody = /(?:\/(?:thead|tfoot|tbody|caption|col|colgroup)>)+\s* 1 && tb && !re_tbody.test(html)) {
+ tb[PARENT_NODE].removeChild(tb); // strip extraneous tbody
+ }
+ return frag;
+ },
+
+ script: function(html, doc) {
+ var frag = doc.createElement('div');
+
+ frag.innerHTML = '-' + html;
+ frag.removeChild(frag[FIRST_CHILD]);
+ return frag;
+ }
+
+ }, true);
+
+ Y.mix(Y.DOM.VALUE_GETTERS, {
+ button: function(node) {
+ return (node.attributes && node.attributes.value) ? node.attributes.value.value : '';
+ }
+ });
+
+ Y.mix(Y.DOM.VALUE_SETTERS, {
+ // IE: node.value changes the button text, which should be handled via innerHTML
+ button: function(node, val) {
+ var attr = node.attributes.value;
+ if (!attr) {
+ attr = node[OWNER_DOCUMENT].createAttribute('value');
+ node.setAttributeNode(attr);
+ }
+
+ attr.value = val;
+ }
+ });
+ }
+
+ if (Y.UA.gecko || Y.UA.ie) {
+ Y.mix(creators, {
+ option: function(html, doc) {
+ return create('', doc);
+ },
+
+ tr: function(html, doc) {
+ return create('' + html + '', doc);
+ },
+
+ td: function(html, doc) {
+ return create('
' + html + '
', doc);
+ },
+
+ tbody: function(html, doc) {
+ return create(TABLE_OPEN + html + TABLE_CLOSE, doc);
+ }
+ });
+
+ Y.mix(creators, {
+ legend: 'fieldset',
+ th: creators.td,
+ thead: creators.tbody,
+ tfoot: creators.tbody,
+ caption: creators.tbody,
+ colgroup: creators.tbody,
+ col: creators.tbody,
+ optgroup: creators.option
+ });
+ }
+
+ Y.mix(Y.DOM.VALUE_GETTERS, {
+ option: function(node) {
+ var attrs = node.attributes;
+ return (attrs.value && attrs.value.specified) ? node.value : node.text;
+ },
+
+ select: function(node) {
+ var val = node.value,
+ options = node.options;
+
+ if (options && val === '') {
+ if (node.multiple) {
+ } else {
+ val = Y.DOM.getValue(options[node.selectedIndex], 'value');
+ }
+ }
+
+ return val;
+ }
+ });
+})(Y);
+
+})(Y);
+var addClass, hasClass, removeClass;
+
+Y.mix(Y.DOM, {
+ /**
+ * Determines whether a DOM element has the given className.
+ * @method hasClass
+ * @param {HTMLElement} element The DOM element.
+ * @param {String} className the class name to search for
+ * @return {Boolean} Whether or not the element has the given class.
+ */
+ hasClass: function(node, className) {
+ var re = Y.DOM._getRegExp('(?:^|\\s+)' + className + '(?:\\s+|$)');
+ return re.test(node.className);
+ },
+
+ /**
+ * Adds a class name to a given DOM element.
+ * @method addClass
+ * @param {HTMLElement} element The DOM element.
+ * @param {String} className the class name to add to the class attribute
+ */
+ addClass: function(node, className) {
+ if (!Y.DOM.hasClass(node, className)) { // skip if already present
+ node.className = Y.Lang.trim([node.className, className].join(' '));
+ }
+ },
+
+ /**
+ * Removes a class name from a given element.
+ * @method removeClass
+ * @param {HTMLElement} element The DOM element.
+ * @param {String} className the class name to remove from the class attribute
+ */
+ removeClass: function(node, className) {
+ if (className && hasClass(node, className)) {
+ node.className = Y.Lang.trim(node.className.replace(Y.DOM._getRegExp('(?:^|\\s+)' +
+ className + '(?:\\s+|$)'), ' '));
+
+ if ( hasClass(node, className) ) { // in case of multiple adjacent
+ removeClass(node, className);
+ }
+ }
+ },
+
+ /**
+ * Replace a class with another class for a given element.
+ * If no oldClassName is present, the newClassName is simply added.
+ * @method replaceClass
+ * @param {HTMLElement} element The DOM element.
+ * @param {String} oldClassName the class name to be replaced
+ * @param {String} newClassName the class name that will be replacing the old class name
+ */
+ replaceClass: function(node, oldC, newC) {
+ addClass(node, newC);
+ removeClass(node, oldC);
+ },
+
+ /**
+ * If the className exists on the node it is removed, if it doesn't exist it is added.
+ * @method toggleClass
+ * @param {HTMLElement} element The DOM element.
+ * @param {String} className the class name to be toggled
+ */
+ toggleClass: function(node, className) {
+ if (hasClass(node, className)) {
+ removeClass(node, className);
+ } else {
+ addClass(node, className);
+ }
+ }
+});
+
+hasClass = Y.DOM.hasClass;
+removeClass = Y.DOM.removeClass;
+addClass = Y.DOM.addClass;
+
+
+
+}, '3.0.0' ,{requires:['oop']});
diff --git a/lib/yui/3.0.0/dom/dom-debug.js b/lib/yui/3.0.0/dom/dom-debug.js
new file mode 100644
index 0000000000..a594ea5ca3
--- /dev/null
+++ b/lib/yui/3.0.0/dom/dom-debug.js
@@ -0,0 +1,2486 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dom-base', function(Y) {
+
+(function(Y) {
+/**
+ * The DOM utility provides a cross-browser abtraction layer
+ * normalizing DOM tasks, and adds extra helper functionality
+ * for other common tasks.
+ * @module dom
+ * @submodule dom-base
+ *
+ */
+
+/**
+ * Provides DOM helper methods.
+ * @class DOM
+ *
+ */
+var NODE_TYPE = 'nodeType',
+ OWNER_DOCUMENT = 'ownerDocument',
+ DEFAULT_VIEW = 'defaultView',
+ PARENT_WINDOW = 'parentWindow',
+ TAG_NAME = 'tagName',
+ PARENT_NODE = 'parentNode',
+ FIRST_CHILD = 'firstChild',
+ PREVIOUS_SIBLING = 'previousSibling',
+ NEXT_SIBLING = 'nextSibling',
+ CONTAINS = 'contains',
+ COMPARE_DOCUMENT_POSITION = 'compareDocumentPosition',
+
+ documentElement = document.documentElement,
+
+ re_tag = /<([a-z]+)/i;
+
+Y.DOM = {
+ /**
+ * Returns the HTMLElement with the given ID (Wrapper for document.getElementById).
+ * @method byId
+ * @param {String} id the id attribute
+ * @param {Object} doc optional The document to search. Defaults to current document
+ * @return {HTMLElement | null} The HTMLElement with the id, or null if none found.
+ */
+ byId: function(id, doc) {
+ doc = doc || Y.config.doc;
+ // TODO: IE Name
+ return doc.getElementById(id);
+ },
+
+ // @deprecated
+ children: function(node, tag) {
+ var ret = [];
+ if (node) {
+ tag = tag || '*';
+ ret = Y.Selector.query('> ' + tag, node);
+ }
+ return ret;
+ },
+
+ // @deprecated
+ firstByTag: function(tag, root) {
+ var ret;
+ root = root || Y.config.doc;
+
+ if (tag && root.getElementsByTagName) {
+ ret = root.getElementsByTagName(tag)[0];
+ }
+
+ return ret || null;
+ },
+
+ /**
+ * Returns the text content of the HTMLElement.
+ * @method getText
+ * @param {HTMLElement} element The html element.
+ * @return {String} The text content of the element (includes text of any descending elements).
+ */
+ getText: (documentElement.textContent !== undefined) ?
+ function(element) {
+ var ret = '';
+ if (element) {
+ ret = element.textContent;
+ }
+ return ret || '';
+ } : function(element) {
+ var ret = '';
+ if (element) {
+ ret = element.innerText;
+ }
+ return ret || '';
+ },
+
+ /**
+ * Sets the text content of the HTMLElement.
+ * @method setText
+ * @param {HTMLElement} element The html element.
+ * @param {String} content The content to add.
+ */
+ setText: (documentElement.textContent !== undefined) ?
+ function(element, content) {
+ if (element) {
+ element.textContent = content;
+ }
+ } : function(element, content) {
+ if (element) {
+ element.innerText = content;
+ }
+ },
+
+ /*
+ * Finds the previous sibling of the element.
+ * @method previous
+ * @deprecated Use elementByAxis
+ * @param {HTMLElement} element The html element.
+ * @param {Function} fn optional An optional boolean test to apply.
+ * The optional function is passed the current DOM node being tested as its only argument.
+ * If no function is given, the first sibling is returned.
+ * @param {Boolean} all optional Whether all node types should be scanned, or just element nodes.
+ * @return {HTMLElement | null} The matching DOM node or null if none found.
+ */
+ previous: function(element, fn, all) {
+ return Y.DOM.elementByAxis(element, PREVIOUS_SIBLING, fn, all);
+ },
+
+ /*
+ * Finds the next sibling of the element.
+ * @method next
+ * @deprecated Use elementByAxis
+ * @param {HTMLElement} element The html element.
+ * @param {Function} fn optional An optional boolean test to apply.
+ * The optional function is passed the current DOM node being tested as its only argument.
+ * If no function is given, the first sibling is returned.
+ * @param {Boolean} all optional Whether all node types should be scanned, or just element nodes.
+ * @return {HTMLElement | null} The matching DOM node or null if none found.
+ */
+ next: function(element, fn, all) {
+ return Y.DOM.elementByAxis(element, NEXT_SIBLING, fn, all);
+ },
+
+ /*
+ * Finds the ancestor of the element.
+ * @method ancestor
+ * @deprecated Use elementByAxis
+ * @param {HTMLElement} element The html element.
+ * @param {Function} fn optional An optional boolean test to apply.
+ * The optional function is passed the current DOM node being tested as its only argument.
+ * If no function is given, the parentNode is returned.
+ * @param {Boolean} all optional Whether all node types should be scanned, or just element nodes.
+ * @return {HTMLElement | null} The matching DOM node or null if none found.
+ */
+ // TODO: optional stopAt node?
+ ancestor: function(element, fn, all) {
+ return Y.DOM.elementByAxis(element, PARENT_NODE, fn, all);
+ },
+
+ /**
+ * Searches the element by the given axis for the first matching element.
+ * @method elementByAxis
+ * @param {HTMLElement} element The html element.
+ * @param {String} axis The axis to search (parentNode, nextSibling, previousSibling).
+ * @param {Function} fn optional An optional boolean test to apply.
+ * @param {Boolean} all optional Whether all node types should be returned, or just element nodes.
+ * The optional function is passed the current HTMLElement being tested as its only argument.
+ * If no function is given, the first element is returned.
+ * @return {HTMLElement | null} The matching element or null if none found.
+ */
+ elementByAxis: function(element, axis, fn, all) {
+ while (element && (element = element[axis])) { // NOTE: assignment
+ if ( (all || element[TAG_NAME]) && (!fn || fn(element)) ) {
+ return element;
+ }
+ }
+ return null;
+ },
+
+ /**
+ * Determines whether or not one HTMLElement is or contains another HTMLElement.
+ * @method contains
+ * @param {HTMLElement} element The containing html element.
+ * @param {HTMLElement} needle The html element that may be contained.
+ * @return {Boolean} Whether or not the element is or contains the needle.
+ */
+ contains: function(element, needle) {
+ var ret = false;
+
+ if ( !needle || !element || !needle[NODE_TYPE] || !element[NODE_TYPE]) {
+ ret = false;
+ } else if (element[CONTAINS]) {
+ if (Y.UA.opera || needle[NODE_TYPE] === 1) { // IE & SAF contains fail if needle not an ELEMENT_NODE
+ ret = element[CONTAINS](needle);
+ } else {
+ ret = Y.DOM._bruteContains(element, needle);
+ }
+ } else if (element[COMPARE_DOCUMENT_POSITION]) { // gecko
+ if (element === needle || !!(element[COMPARE_DOCUMENT_POSITION](needle) & 16)) {
+ ret = true;
+ }
+ }
+
+ return ret;
+ },
+
+ /**
+ * Determines whether or not the HTMLElement is part of the document.
+ * @method inDoc
+ * @param {HTMLElement} element The containing html element.
+ * @param {HTMLElement} doc optional The document to check.
+ * @return {Boolean} Whether or not the element is attached to the document.
+ */
+ inDoc: function(element, doc) {
+ doc = doc || element[OWNER_DOCUMENT];
+ var id = element.id;
+ if (!id) { // TODO: remove when done?
+ id = element.id = Y.guid();
+ }
+
+ return !! (doc.getElementById(id));
+ },
+
+ /**
+ * Creates a new dom node using the provided markup string.
+ * @method create
+ * @param {String} html The markup used to create the element
+ * @param {HTMLDocument} doc An optional document context
+ */
+ create: function(html, doc) {
+ if (typeof html === 'string') {
+ html = Y.Lang.trim(html); // match IE which trims whitespace from innerHTML
+ }
+
+ if (!doc && Y.DOM._cloneCache[html]) {
+ return Y.DOM._cloneCache[html].cloneNode(true); // NOTE: return
+ }
+
+ doc = doc || Y.config.doc;
+ var m = re_tag.exec(html),
+ create = Y.DOM._create,
+ custom = Y.DOM.creators,
+ ret = null,
+ tag, nodes;
+
+ if (m && custom[m[1]]) {
+ if (typeof custom[m[1]] === 'function') {
+ create = custom[m[1]];
+ } else {
+ tag = custom[m[1]];
+ }
+ }
+
+ nodes = create(html, doc, tag).childNodes;
+
+ if (nodes.length === 1) { // return single node, breaking parentNode ref from "fragment"
+ ret = nodes[0].parentNode.removeChild(nodes[0]);
+ } else { // return multiple nodes as a fragment
+ ret = Y.DOM._nl2frag(nodes, doc);
+ }
+
+ if (ret) {
+ Y.DOM._cloneCache[html] = ret.cloneNode(true);
+ }
+ return ret;
+ },
+
+ _nl2frag: function(nodes, doc) {
+ var ret = null,
+ i, len;
+
+ if (nodes && (nodes.push || nodes.item) && nodes[0]) {
+ doc = doc || nodes[0].ownerDocument;
+ ret = doc.createDocumentFragment();
+
+ if (nodes.item) { // convert live list to static array
+ nodes = Y.Array(nodes, 0, true);
+ }
+
+ for (i = 0, len = nodes.length; i < len; i++) {
+ ret.appendChild(nodes[i]);
+ }
+ } // else inline with log for minification
+ else { Y.log('unable to convert ' + nodes + ' to fragment', 'warn', 'dom'); }
+ return ret;
+ },
+
+
+ CUSTOM_ATTRIBUTES: (!documentElement.hasAttribute) ? { // IE < 8
+ 'for': 'htmlFor',
+ 'class': 'className'
+ } : { // w3c
+ 'htmlFor': 'for',
+ 'className': 'class'
+ },
+
+ /**
+ * Provides a normalized attribute interface.
+ * @method setAttibute
+ * @param {String | HTMLElement} el The target element for the attribute.
+ * @param {String} attr The attribute to set.
+ * @param {String} val The value of the attribute.
+ */
+ setAttribute: function(el, attr, val, ieAttr) {
+ if (el && el.setAttribute) {
+ attr = Y.DOM.CUSTOM_ATTRIBUTES[attr] || attr;
+ el.setAttribute(attr, val, ieAttr);
+ }
+ },
+
+
+ /**
+ * Provides a normalized attribute interface.
+ * @method getAttibute
+ * @param {String | HTMLElement} el The target element for the attribute.
+ * @param {String} attr The attribute to get.
+ * @return {String} The current value of the attribute.
+ */
+ getAttribute: function(el, attr, ieAttr) {
+ ieAttr = (ieAttr !== undefined) ? ieAttr : 2;
+ var ret = '';
+ if (el && el.getAttribute) {
+ attr = Y.DOM.CUSTOM_ATTRIBUTES[attr] || attr;
+ ret = el.getAttribute(attr, ieAttr);
+
+ if (ret === null) {
+ ret = ''; // per DOM spec
+ }
+ }
+ return ret;
+ },
+
+ isWindow: function(obj) {
+ return obj.alert && obj.document;
+ },
+
+ _fragClones: {
+ div: document.createElement('div')
+ },
+
+ _create: function(html, doc, tag) {
+ tag = tag || 'div';
+
+ var frag = Y.DOM._fragClones[tag];
+ if (frag) {
+ frag = frag.cloneNode(false);
+ } else {
+ frag = Y.DOM._fragClones[tag] = doc.createElement(tag);
+ }
+ frag.innerHTML = html;
+ return frag;
+ },
+
+ _removeChildNodes: function(node) {
+ while (node.firstChild) {
+ node.removeChild(node.firstChild);
+ }
+ },
+
+ _cloneCache: {},
+
+ /**
+ * Inserts content in a node at the given location
+ * @method addHTML
+ * @param {HTMLElement} node The node to insert into
+ * @param {String} content The content to be inserted
+ * @param {String} where Where to insert the content; default is after lastChild
+ */
+ addHTML: function(node, content, where) {
+ if (typeof content === 'string') {
+ content = Y.Lang.trim(content); // match IE which trims whitespace from innerHTML
+ }
+
+ var newNode = Y.DOM._cloneCache[content],
+ nodeParent = node.parentNode;
+
+ if (newNode) {
+ newNode = newNode.cloneNode(true);
+ } else {
+ if (content.nodeType) { // domNode
+ newNode = content;
+ } else { // create from string and cache
+ newNode = Y.DOM.create(content);
+ }
+ }
+
+ if (where) {
+ if (where.nodeType) { // insert regardless of relationship to node
+ // TODO: check if node.contains(where)?
+ where.parentNode.insertBefore(newNode, where);
+ } else {
+ switch (where) {
+ case 'replace':
+ while (node.firstChild) {
+ node.removeChild(node.firstChild);
+ }
+ node.appendChild(newNode);
+ break;
+ case 'before':
+ nodeParent.insertBefore(newNode, node);
+ break;
+ case 'after':
+ if (node.nextSibling) { // IE errors if refNode is null
+ nodeParent.insertBefore(newNode, node.nextSibling);
+ } else {
+ nodeParent.appendChild(newNode);
+ }
+ break;
+ default:
+ node.appendChild(newNode);
+ }
+ }
+ } else {
+ node.appendChild(newNode);
+ }
+
+ return newNode;
+ },
+
+ VALUE_SETTERS: {},
+
+ VALUE_GETTERS: {},
+
+ getValue: function(node) {
+ var ret = '', // TODO: return null?
+ getter;
+
+ if (node && node[TAG_NAME]) {
+ getter = Y.DOM.VALUE_GETTERS[node[TAG_NAME].toLowerCase()];
+
+ if (getter) {
+ ret = getter(node);
+ } else {
+ ret = node.value;
+ }
+ }
+
+ return (typeof ret === 'string') ? ret : '';
+ },
+
+ setValue: function(node, val) {
+ var setter;
+
+ if (node && node[TAG_NAME]) {
+ setter = Y.DOM.VALUE_SETTERS[node[TAG_NAME].toLowerCase()];
+
+ if (setter) {
+ setter(node, val);
+ } else {
+ node.value = val;
+ }
+ }
+ },
+
+ /**
+ * Brute force version of contains.
+ * Used for browsers without contains support for non-HTMLElement Nodes (textNodes, etc).
+ * @method _bruteContains
+ * @private
+ * @param {HTMLElement} element The containing html element.
+ * @param {HTMLElement} needle The html element that may be contained.
+ * @return {Boolean} Whether or not the element is or contains the needle.
+ */
+ _bruteContains: function(element, needle) {
+ while (needle) {
+ if (element === needle) {
+ return true;
+ }
+ needle = needle.parentNode;
+ }
+ return false;
+ },
+
+// TODO: move to Lang?
+ /**
+ * Memoizes dynamic regular expressions to boost runtime performance.
+ * @method _getRegExp
+ * @private
+ * @param {String} str The string to convert to a regular expression.
+ * @param {String} flags optional An optinal string of flags.
+ * @return {RegExp} An instance of RegExp
+ */
+ _getRegExp: function(str, flags) {
+ flags = flags || '';
+ Y.DOM._regexCache = Y.DOM._regexCache || {};
+ if (!Y.DOM._regexCache[str + flags]) {
+ Y.DOM._regexCache[str + flags] = new RegExp(str, flags);
+ }
+ return Y.DOM._regexCache[str + flags];
+ },
+
+// TODO: make getDoc/Win true privates?
+ /**
+ * returns the appropriate document.
+ * @method _getDoc
+ * @private
+ * @param {HTMLElement} element optional Target element.
+ * @return {Object} The document for the given element or the default document.
+ */
+ _getDoc: function(element) {
+ element = element || {};
+
+ return (element[NODE_TYPE] === 9) ? element : // element === document
+ element[OWNER_DOCUMENT] || // element === DOM node
+ element.document || // element === window
+ Y.config.doc; // default
+ },
+
+ /**
+ * returns the appropriate window.
+ * @method _getWin
+ * @private
+ * @param {HTMLElement} element optional Target element.
+ * @return {Object} The window for the given element or the default window.
+ */
+ _getWin: function(element) {
+ var doc = Y.DOM._getDoc(element);
+ return doc[DEFAULT_VIEW] || doc[PARENT_WINDOW] || Y.config.win;
+ },
+
+ _batch: function(nodes, fn, arg1, arg2, arg3, etc) {
+ fn = (typeof name === 'string') ? Y.DOM[fn] : fn;
+ var result,
+ ret = [];
+
+ if (fn && nodes) {
+ Y.each(nodes, function(node) {
+ if ((result = fn.call(Y.DOM, node, arg1, arg2, arg3, etc)) !== undefined) {
+ ret[ret.length] = result;
+ }
+ });
+ }
+
+ return ret.length ? ret : nodes;
+ },
+
+ _testElement: function(element, tag, fn) {
+ tag = (tag && tag !== '*') ? tag.toUpperCase() : null;
+ return (element && element[TAG_NAME] &&
+ (!tag || element[TAG_NAME].toUpperCase() === tag) &&
+ (!fn || fn(element)));
+ },
+
+ creators: {},
+
+ _IESimpleCreate: function(html, doc) {
+ doc = doc || Y.config.doc;
+ return doc.createElement(html);
+ }
+};
+
+
+(function(Y) {
+ var creators = Y.DOM.creators,
+ create = Y.DOM.create,
+ re_tbody = /(?:\/(?:thead|tfoot|tbody|caption|col|colgroup)>)+\s* 1 && tb && !re_tbody.test(html)) {
+ tb[PARENT_NODE].removeChild(tb); // strip extraneous tbody
+ }
+ return frag;
+ },
+
+ script: function(html, doc) {
+ var frag = doc.createElement('div');
+
+ frag.innerHTML = '-' + html;
+ frag.removeChild(frag[FIRST_CHILD]);
+ return frag;
+ }
+
+ }, true);
+
+ Y.mix(Y.DOM.VALUE_GETTERS, {
+ button: function(node) {
+ return (node.attributes && node.attributes.value) ? node.attributes.value.value : '';
+ }
+ });
+
+ Y.mix(Y.DOM.VALUE_SETTERS, {
+ // IE: node.value changes the button text, which should be handled via innerHTML
+ button: function(node, val) {
+ var attr = node.attributes.value;
+ if (!attr) {
+ attr = node[OWNER_DOCUMENT].createAttribute('value');
+ node.setAttributeNode(attr);
+ }
+
+ attr.value = val;
+ }
+ });
+ }
+
+ if (Y.UA.gecko || Y.UA.ie) {
+ Y.mix(creators, {
+ option: function(html, doc) {
+ return create('', doc);
+ },
+
+ tr: function(html, doc) {
+ return create('' + html + '', doc);
+ },
+
+ td: function(html, doc) {
+ return create('
' + html + '
', doc);
+ },
+
+ tbody: function(html, doc) {
+ return create(TABLE_OPEN + html + TABLE_CLOSE, doc);
+ }
+ });
+
+ Y.mix(creators, {
+ legend: 'fieldset',
+ th: creators.td,
+ thead: creators.tbody,
+ tfoot: creators.tbody,
+ caption: creators.tbody,
+ colgroup: creators.tbody,
+ col: creators.tbody,
+ optgroup: creators.option
+ });
+ }
+
+ Y.mix(Y.DOM.VALUE_GETTERS, {
+ option: function(node) {
+ var attrs = node.attributes;
+ return (attrs.value && attrs.value.specified) ? node.value : node.text;
+ },
+
+ select: function(node) {
+ var val = node.value,
+ options = node.options;
+
+ if (options && val === '') {
+ if (node.multiple) {
+ Y.log('multiple select normalization not implemented', 'warn', 'DOM');
+ } else {
+ val = Y.DOM.getValue(options[node.selectedIndex], 'value');
+ }
+ }
+
+ return val;
+ }
+ });
+})(Y);
+
+})(Y);
+var addClass, hasClass, removeClass;
+
+Y.mix(Y.DOM, {
+ /**
+ * Determines whether a DOM element has the given className.
+ * @method hasClass
+ * @param {HTMLElement} element The DOM element.
+ * @param {String} className the class name to search for
+ * @return {Boolean} Whether or not the element has the given class.
+ */
+ hasClass: function(node, className) {
+ var re = Y.DOM._getRegExp('(?:^|\\s+)' + className + '(?:\\s+|$)');
+ return re.test(node.className);
+ },
+
+ /**
+ * Adds a class name to a given DOM element.
+ * @method addClass
+ * @param {HTMLElement} element The DOM element.
+ * @param {String} className the class name to add to the class attribute
+ */
+ addClass: function(node, className) {
+ if (!Y.DOM.hasClass(node, className)) { // skip if already present
+ node.className = Y.Lang.trim([node.className, className].join(' '));
+ }
+ },
+
+ /**
+ * Removes a class name from a given element.
+ * @method removeClass
+ * @param {HTMLElement} element The DOM element.
+ * @param {String} className the class name to remove from the class attribute
+ */
+ removeClass: function(node, className) {
+ if (className && hasClass(node, className)) {
+ node.className = Y.Lang.trim(node.className.replace(Y.DOM._getRegExp('(?:^|\\s+)' +
+ className + '(?:\\s+|$)'), ' '));
+
+ if ( hasClass(node, className) ) { // in case of multiple adjacent
+ removeClass(node, className);
+ }
+ }
+ },
+
+ /**
+ * Replace a class with another class for a given element.
+ * If no oldClassName is present, the newClassName is simply added.
+ * @method replaceClass
+ * @param {HTMLElement} element The DOM element.
+ * @param {String} oldClassName the class name to be replaced
+ * @param {String} newClassName the class name that will be replacing the old class name
+ */
+ replaceClass: function(node, oldC, newC) {
+ //Y.log('replaceClass replacing ' + oldC + ' with ' + newC, 'info', 'Node');
+ addClass(node, newC);
+ removeClass(node, oldC);
+ },
+
+ /**
+ * If the className exists on the node it is removed, if it doesn't exist it is added.
+ * @method toggleClass
+ * @param {HTMLElement} element The DOM element.
+ * @param {String} className the class name to be toggled
+ */
+ toggleClass: function(node, className) {
+ if (hasClass(node, className)) {
+ removeClass(node, className);
+ } else {
+ addClass(node, className);
+ }
+ }
+});
+
+hasClass = Y.DOM.hasClass;
+removeClass = Y.DOM.removeClass;
+addClass = Y.DOM.addClass;
+
+
+
+}, '3.0.0' ,{requires:['oop']});
+YUI.add('dom-style', function(Y) {
+
+(function(Y) {
+/**
+ * Add style management functionality to DOM.
+ * @module dom
+ * @submodule dom-style
+ * @for DOM
+ */
+
+var DOCUMENT_ELEMENT = 'documentElement',
+ DEFAULT_VIEW = 'defaultView',
+ OWNER_DOCUMENT = 'ownerDocument',
+ STYLE = 'style',
+ FLOAT = 'float',
+ CSS_FLOAT = 'cssFloat',
+ STYLE_FLOAT = 'styleFloat',
+ TRANSPARENT = 'transparent',
+ GET_COMPUTED_STYLE = 'getComputedStyle',
+
+ DOCUMENT = Y.config.doc,
+ UNDEFINED = undefined,
+
+ re_color = /color$/i;
+
+
+Y.mix(Y.DOM, {
+ CUSTOM_STYLES: {
+ },
+
+
+ /**
+ * Sets a style property for a given element.
+ * @method setStyle
+ * @param {HTMLElement} An HTMLElement to apply the style to.
+ * @param {String} att The style property to set.
+ * @param {String|Number} val The value.
+ */
+ setStyle: function(node, att, val, style) {
+ style = style || node.style;
+ var CUSTOM_STYLES = Y.DOM.CUSTOM_STYLES;
+
+ if (style) {
+ if (val === null) {
+ val = ''; // normalize for unsetting
+ }
+ if (att in CUSTOM_STYLES) {
+ if (CUSTOM_STYLES[att].set) {
+ CUSTOM_STYLES[att].set(node, val, style);
+ return; // NOTE: return
+ } else if (typeof CUSTOM_STYLES[att] === 'string') {
+ att = CUSTOM_STYLES[att];
+ }
+ }
+ style[att] = val;
+ }
+ },
+
+ /**
+ * Returns the current style value for the given property.
+ * @method getStyle
+ * @param {HTMLElement} An HTMLElement to get the style from.
+ * @param {String} att The style property to get.
+ */
+ getStyle: function(node, att) {
+ var style = node[STYLE],
+ CUSTOM_STYLES = Y.DOM.CUSTOM_STYLES,
+ val = '';
+
+ if (style) {
+ if (att in CUSTOM_STYLES) {
+ if (CUSTOM_STYLES[att].get) {
+ return CUSTOM_STYLES[att].get(node, att, style); // NOTE: return
+ } else if (typeof CUSTOM_STYLES[att] === 'string') {
+ att = CUSTOM_STYLES[att];
+ }
+ }
+ val = style[att];
+ if (val === '') { // TODO: is empty string sufficient?
+ val = Y.DOM[GET_COMPUTED_STYLE](node, att);
+ }
+ }
+
+ return val;
+ },
+
+ /**
+ * Sets multiple style properties.
+ * @method setStyles
+ * @param {HTMLElement} node An HTMLElement to apply the styles to.
+ * @param {Object} hash An object literal of property:value pairs.
+ */
+ setStyles: function(node, hash) {
+ var style = node.style;
+ Y.each(hash, function(v, n) {
+ Y.DOM.setStyle(node, n, v, style);
+ }, Y.DOM);
+ },
+
+ /**
+ * Returns the computed style for the given node.
+ * @method getComputedStyle
+ * @param {HTMLElement} An HTMLElement to get the style from.
+ * @param {String} att The style property to get.
+ * @return {String} The computed value of the style property.
+ */
+ getComputedStyle: function(node, att) {
+ var val = '',
+ doc = node[OWNER_DOCUMENT];
+
+ if (node[STYLE]) {
+ val = doc[DEFAULT_VIEW][GET_COMPUTED_STYLE](node, null)[att];
+ }
+ return val;
+ }
+});
+
+// normalize reserved word float alternatives ("cssFloat" or "styleFloat")
+if (DOCUMENT[DOCUMENT_ELEMENT][STYLE][CSS_FLOAT] !== UNDEFINED) {
+ Y.DOM.CUSTOM_STYLES[FLOAT] = CSS_FLOAT;
+} else if (DOCUMENT[DOCUMENT_ELEMENT][STYLE][STYLE_FLOAT] !== UNDEFINED) {
+ Y.DOM.CUSTOM_STYLES[FLOAT] = STYLE_FLOAT;
+}
+
+// fix opera computedStyle default color unit (convert to rgb)
+if (Y.UA.opera) {
+ Y.DOM[GET_COMPUTED_STYLE] = function(node, att) {
+ var view = node[OWNER_DOCUMENT][DEFAULT_VIEW],
+ val = view[GET_COMPUTED_STYLE](node, '')[att];
+
+ if (re_color.test(att)) {
+ val = Y.Color.toRGB(val);
+ }
+
+ return val;
+ };
+
+}
+
+// safari converts transparent to rgba(), others use "transparent"
+if (Y.UA.webkit) {
+ Y.DOM[GET_COMPUTED_STYLE] = function(node, att) {
+ var view = node[OWNER_DOCUMENT][DEFAULT_VIEW],
+ val = view[GET_COMPUTED_STYLE](node, '')[att];
+
+ if (val === 'rgba(0, 0, 0, 0)') {
+ val = TRANSPARENT;
+ }
+
+ return val;
+ };
+
+}
+})(Y);
+(function(Y) {
+var PARSE_INT = parseInt,
+ RE = RegExp;
+
+Y.Color = {
+ KEYWORDS: {
+ black: '000',
+ silver: 'c0c0c0',
+ gray: '808080',
+ white: 'fff',
+ maroon: '800000',
+ red: 'f00',
+ purple: '800080',
+ fuchsia: 'f0f',
+ green: '008000',
+ lime: '0f0',
+ olive: '808000',
+ yellow: 'ff0',
+ navy: '000080',
+ blue: '00f',
+ teal: '008080',
+ aqua: '0ff'
+ },
+
+ re_RGB: /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i,
+ re_hex: /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i,
+ re_hex3: /([0-9A-F])/gi,
+
+ toRGB: function(val) {
+ if (!Y.Color.re_RGB.test(val)) {
+ val = Y.Color.toHex(val);
+ }
+
+ if(Y.Color.re_hex.exec(val)) {
+ val = 'rgb(' + [
+ PARSE_INT(RE.$1, 16),
+ PARSE_INT(RE.$2, 16),
+ PARSE_INT(RE.$3, 16)
+ ].join(', ') + ')';
+ }
+ return val;
+ },
+
+ toHex: function(val) {
+ val = Y.Color.KEYWORDS[val] || val;
+ if (Y.Color.re_RGB.exec(val)) {
+ val = [
+ Number(RE.$1).toString(16),
+ Number(RE.$2).toString(16),
+ Number(RE.$3).toString(16)
+ ];
+
+ for (var i = 0; i < val.length; i++) {
+ if (val[i].length < 2) {
+ val[i] = val[i].replace(Y.Color.re_hex3, '$1$1');
+ }
+ }
+
+ val = '#' + val.join('');
+ }
+
+ if (val.length < 6) {
+ val = val.replace(Y.Color.re_hex3, '$1$1');
+ }
+
+ if (val !== 'transparent' && val.indexOf('#') < 0) {
+ val = '#' + val;
+ }
+
+ return val.toLowerCase();
+ }
+};
+})(Y);
+
+(function(Y) {
+var HAS_LAYOUT = 'hasLayout',
+ PX = 'px',
+ FILTER = 'filter',
+ FILTERS = 'filters',
+ OPACITY = 'opacity',
+ AUTO = 'auto',
+
+ BORDER_WIDTH = 'borderWidth',
+ BORDER_TOP_WIDTH = 'borderTopWidth',
+ BORDER_RIGHT_WIDTH = 'borderRightWidth',
+ BORDER_BOTTOM_WIDTH = 'borderBottomWidth',
+ BORDER_LEFT_WIDTH = 'borderLeftWidth',
+ WIDTH = 'width',
+ HEIGHT = 'height',
+ TRANSPARENT = 'transparent',
+ VISIBLE = 'visible',
+ GET_COMPUTED_STYLE = 'getComputedStyle',
+ UNDEFINED = undefined,
+ documentElement = document.documentElement,
+
+ // TODO: unit-less lineHeight (e.g. 1.22)
+ re_unit = /^(\d[.\d]*)+(em|ex|px|gd|rem|vw|vh|vm|ch|mm|cm|in|pt|pc|deg|rad|ms|s|hz|khz|%){1}?/i,
+
+ _getStyleObj = function(node) {
+ return node.currentStyle || node.style;
+ },
+
+ ComputedStyle = {
+ CUSTOM_STYLES: {},
+
+ get: function(el, property) {
+ var value = '',
+ current;
+
+ if (el) {
+ current = _getStyleObj(el)[property];
+
+ if (property === OPACITY && Y.DOM.CUSTOM_STYLES[OPACITY]) {
+ value = Y.DOM.CUSTOM_STYLES[OPACITY].get(el);
+ } else if (!current || (current.indexOf && current.indexOf(PX) > -1)) { // no need to convert
+ value = current;
+ } else if (Y.DOM.IE.COMPUTED[property]) { // use compute function
+ value = Y.DOM.IE.COMPUTED[property](el, property);
+ } else if (re_unit.test(current)) { // convert to pixel
+ value = ComputedStyle.getPixel(el, property) + PX;
+ } else {
+ value = current;
+ }
+ }
+
+ return value;
+ },
+
+ sizeOffsets: {
+ width: ['Left', 'Right'],
+ height: ['Top', 'Bottom'],
+ top: ['Top'],
+ bottom: ['Bottom']
+ },
+
+ getOffset: function(el, prop) {
+ var current = _getStyleObj(el)[prop], // value of "width", "top", etc.
+ capped = prop.charAt(0).toUpperCase() + prop.substr(1), // "Width", "Top", etc.
+ offset = 'offset' + capped, // "offsetWidth", "offsetTop", etc.
+ pixel = 'pixel' + capped, // "pixelWidth", "pixelTop", etc.
+ sizeOffsets = ComputedStyle.sizeOffsets[prop],
+ value = '';
+
+ // IE pixelWidth incorrect for percent
+ // manually compute by subtracting padding and border from offset size
+ // NOTE: clientWidth/Height (size minus border) is 0 when current === AUTO so offsetHeight is used
+ // reverting to auto from auto causes position stacking issues (old impl)
+ if (current === AUTO || current.indexOf('%') > -1) {
+ value = el['offset' + capped];
+
+ if (sizeOffsets[0]) {
+ value -= ComputedStyle.getPixel(el, 'padding' + sizeOffsets[0]);
+ value -= ComputedStyle.getBorderWidth(el, 'border' + sizeOffsets[0] + 'Width', 1);
+ }
+
+ if (sizeOffsets[1]) {
+ value -= ComputedStyle.getPixel(el, 'padding' + sizeOffsets[1]);
+ value -= ComputedStyle.getBorderWidth(el, 'border' + sizeOffsets[1] + 'Width', 1);
+ }
+
+ } else { // use style.pixelWidth, etc. to convert to pixels
+ // need to map style.width to currentStyle (no currentStyle.pixelWidth)
+ if (!el.style[pixel] && !el.style[prop]) {
+ el.style[prop] = current;
+ }
+ value = el.style[pixel];
+
+ }
+ return value + PX;
+ },
+
+ borderMap: {
+ thin: '2px',
+ medium: '4px',
+ thick: '6px'
+ },
+
+ getBorderWidth: function(el, property, omitUnit) {
+ var unit = omitUnit ? '' : PX,
+ current = el.currentStyle[property];
+
+ if (current.indexOf(PX) < 0) { // look up keywords
+ if (ComputedStyle.borderMap[current]) {
+ current = ComputedStyle.borderMap[current];
+ } else {
+ Y.log('borderWidth computing not implemented', 'warn', 'dom-ie-style');
+ }
+ }
+ return (omitUnit) ? parseFloat(current) : current;
+ },
+
+ getPixel: function(node, att) {
+ // use pixelRight to convert to px
+ var val = null,
+ style = _getStyleObj(node),
+ styleRight = style.right,
+ current = style[att];
+
+ node.style.right = current;
+ val = node.style.pixelRight;
+ node.style.right = styleRight; // revert
+
+ return val;
+ },
+
+ getMargin: function(node, att) {
+ var val,
+ style = _getStyleObj(node);
+
+ if (style[att] == AUTO) {
+ val = 0;
+ } else {
+ val = ComputedStyle.getPixel(node, att);
+ }
+ return val + PX;
+ },
+
+ getVisibility: function(node, att) {
+ var current;
+ while ( (current = node.currentStyle) && current[att] == 'inherit') { // NOTE: assignment in test
+ node = node.parentNode;
+ }
+ return (current) ? current[att] : VISIBLE;
+ },
+
+ getColor: function(node, att) {
+ var current = _getStyleObj(node)[att];
+
+ if (!current || current === TRANSPARENT) {
+ Y.DOM.elementByAxis(node, 'parentNode', null, function(parent) {
+ current = _getStyleObj(parent)[att];
+ if (current && current !== TRANSPARENT) {
+ node = parent;
+ return true;
+ }
+ });
+ }
+
+ return Y.Color.toRGB(current);
+ },
+
+ getBorderColor: function(node, att) {
+ var current = _getStyleObj(node),
+ val = current[att] || current.color;
+ return Y.Color.toRGB(Y.Color.toHex(val));
+ }
+ },
+
+ //fontSize: getPixelFont,
+ IEComputed = {};
+
+// use alpha filter for IE opacity
+try {
+ if (documentElement.style[OPACITY] === UNDEFINED &&
+ documentElement[FILTERS]) {
+ Y.DOM.CUSTOM_STYLES[OPACITY] = {
+ get: function(node) {
+ var val = 100;
+ try { // will error if no DXImageTransform
+ val = node[FILTERS]['DXImageTransform.Microsoft.Alpha'][OPACITY];
+
+ } catch(e) {
+ try { // make sure its in the document
+ val = node[FILTERS]('alpha')[OPACITY];
+ } catch(err) {
+ Y.log('getStyle: IE opacity filter not found; returning 1', 'warn', 'dom-style');
+ }
+ }
+ return val / 100;
+ },
+
+ set: function(node, val, style) {
+ var current,
+ styleObj;
+
+ if (val === '') { // normalize inline style behavior
+ styleObj = _getStyleObj(node);
+ current = (OPACITY in styleObj) ? styleObj[OPACITY] : 1; // revert to original opacity
+ val = current;
+ }
+
+ if (typeof style[FILTER] == 'string') { // in case not appended
+ style[FILTER] = 'alpha(' + OPACITY + '=' + val * 100 + ')';
+
+ if (!node.currentStyle || !node.currentStyle[HAS_LAYOUT]) {
+ style.zoom = 1; // needs layout
+ }
+ }
+ }
+ };
+ }
+} catch(e) {
+ Y.log('document.documentElement.filters error (activeX disabled)', 'warn', 'dom-style');
+}
+
+try {
+ document.createElement('div').style.height = '-1px';
+} catch(e) { // IE throws error on invalid style set; trap common cases
+ Y.DOM.CUSTOM_STYLES.height = {
+ set: function(node, val, style) {
+ var floatVal = parseFloat(val);
+ if (isNaN(floatVal) || floatVal >= 0) {
+ style.height = val;
+ } else {
+ Y.log('invalid style value for height: ' + val, 'warn', 'dom-style');
+ }
+ }
+ };
+
+ Y.DOM.CUSTOM_STYLES.width = {
+ set: function(node, val, style) {
+ var floatVal = parseFloat(val);
+ if (isNaN(floatVal) || floatVal >= 0) {
+ style.width = val;
+ } else {
+ Y.log('invalid style value for width: ' + val, 'warn', 'dom-style');
+ }
+ }
+ };
+}
+
+// TODO: top, right, bottom, left
+IEComputed[WIDTH] = IEComputed[HEIGHT] = ComputedStyle.getOffset;
+
+IEComputed.color = IEComputed.backgroundColor = ComputedStyle.getColor;
+
+IEComputed[BORDER_WIDTH] = IEComputed[BORDER_TOP_WIDTH] = IEComputed[BORDER_RIGHT_WIDTH] =
+ IEComputed[BORDER_BOTTOM_WIDTH] = IEComputed[BORDER_LEFT_WIDTH] =
+ ComputedStyle.getBorderWidth;
+
+IEComputed.marginTop = IEComputed.marginRight = IEComputed.marginBottom =
+ IEComputed.marginLeft = ComputedStyle.getMargin;
+
+IEComputed.visibility = ComputedStyle.getVisibility;
+IEComputed.borderColor = IEComputed.borderTopColor =
+ IEComputed.borderRightColor = IEComputed.borderBottomColor =
+ IEComputed.borderLeftColor = ComputedStyle.getBorderColor;
+
+if (!Y.config.win[GET_COMPUTED_STYLE]) {
+ Y.DOM[GET_COMPUTED_STYLE] = ComputedStyle.get;
+}
+
+Y.namespace('DOM.IE');
+Y.DOM.IE.COMPUTED = IEComputed;
+Y.DOM.IE.ComputedStyle = ComputedStyle;
+
+})(Y);
+
+
+}, '3.0.0' ,{requires:['dom-base']});
+YUI.add('dom-screen', function(Y) {
+
+(function(Y) {
+
+/**
+ * Adds position and region management functionality to DOM.
+ * @module dom
+ * @submodule dom-screen
+ * @for DOM
+ */
+
+var DOCUMENT_ELEMENT = 'documentElement',
+ COMPAT_MODE = 'compatMode',
+ POSITION = 'position',
+ FIXED = 'fixed',
+ RELATIVE = 'relative',
+ LEFT = 'left',
+ TOP = 'top',
+ _BACK_COMPAT = 'BackCompat',
+ MEDIUM = 'medium',
+ BORDER_LEFT_WIDTH = 'borderLeftWidth',
+ BORDER_TOP_WIDTH = 'borderTopWidth',
+ GET_BOUNDING_CLIENT_RECT = 'getBoundingClientRect',
+ GET_COMPUTED_STYLE = 'getComputedStyle',
+
+ // TODO: how about thead/tbody/tfoot/tr?
+ // TODO: does caption matter?
+ RE_TABLE = /^t(?:able|d|h)$/i;
+
+Y.mix(Y.DOM, {
+ /**
+ * Returns the inner height of the viewport (exludes scrollbar).
+ * @method winHeight
+ * @return {Number} The current height of the viewport.
+ */
+ winHeight: function(node) {
+ var h = Y.DOM._getWinSize(node).height;
+ Y.log('winHeight returning ' + h, 'info', 'dom-screen');
+ return h;
+ },
+
+ /**
+ * Returns the inner width of the viewport (exludes scrollbar).
+ * @method winWidth
+ * @return {Number} The current width of the viewport.
+ */
+ winWidth: function(node) {
+ var w = Y.DOM._getWinSize(node).width;
+ Y.log('winWidth returning ' + w, 'info', 'dom-screen');
+ return w;
+ },
+
+ /**
+ * Document height
+ * @method docHeight
+ * @return {Number} The current height of the document.
+ */
+ docHeight: function(node) {
+ var h = Y.DOM._getDocSize(node).height;
+ Y.log('docHeight returning ' + h, 'info', 'dom-screen');
+ return Math.max(h, Y.DOM._getWinSize(node).height);
+ },
+
+ /**
+ * Document width
+ * @method docWidth
+ * @return {Number} The current width of the document.
+ */
+ docWidth: function(node) {
+ var w = Y.DOM._getDocSize(node).width;
+ Y.log('docWidth returning ' + w, 'info', 'dom-screen');
+ return Math.max(w, Y.DOM._getWinSize(node).width);
+ },
+
+ /**
+ * Amount page has been scroll horizontally
+ * @method docScrollX
+ * @return {Number} The current amount the screen is scrolled horizontally.
+ */
+ docScrollX: function(node) {
+ var doc = Y.DOM._getDoc(node);
+ return Math.max(doc[DOCUMENT_ELEMENT].scrollLeft, doc.body.scrollLeft);
+ },
+
+ /**
+ * Amount page has been scroll vertically
+ * @method docScrollY
+ * @return {Number} The current amount the screen is scrolled vertically.
+ */
+ docScrollY: function(node) {
+ var doc = Y.DOM._getDoc(node);
+ return Math.max(doc[DOCUMENT_ELEMENT].scrollTop, doc.body.scrollTop);
+ },
+
+ /**
+ * Gets the current position of an element based on page coordinates.
+ * Element must be part of the DOM tree to have page coordinates
+ * (display:none or elements not appended return false).
+ * @method getXY
+ * @param element The target element
+ * @return {Array} The XY position of the element
+
+ TODO: test inDocument/display?
+ */
+ getXY: function() {
+ if (document[DOCUMENT_ELEMENT][GET_BOUNDING_CLIENT_RECT]) {
+ return function(node) {
+ var xy = null,
+ scrollLeft,
+ scrollTop,
+ box,
+ off1, off2,
+ bLeft, bTop,
+ mode,
+ doc;
+
+ if (node) {
+ if (Y.DOM.inDoc(node)) {
+ scrollLeft = Y.DOM.docScrollX(node);
+ scrollTop = Y.DOM.docScrollY(node);
+ box = node[GET_BOUNDING_CLIENT_RECT]();
+ doc = Y.DOM._getDoc(node);
+ xy = [box.left, box.top];
+
+ if (Y.UA.ie) {
+ off1 = 2;
+ off2 = 2;
+ mode = doc[COMPAT_MODE];
+ bLeft = Y.DOM[GET_COMPUTED_STYLE](doc[DOCUMENT_ELEMENT], BORDER_LEFT_WIDTH);
+ bTop = Y.DOM[GET_COMPUTED_STYLE](doc[DOCUMENT_ELEMENT], BORDER_TOP_WIDTH);
+
+ if (Y.UA.ie === 6) {
+ if (mode !== _BACK_COMPAT) {
+ off1 = 0;
+ off2 = 0;
+ }
+ }
+
+ if ((mode == _BACK_COMPAT)) {
+ if (bLeft !== MEDIUM) {
+ off1 = parseInt(bLeft, 10);
+ }
+ if (bTop !== MEDIUM) {
+ off2 = parseInt(bTop, 10);
+ }
+ }
+
+ xy[0] -= off1;
+ xy[1] -= off2;
+
+ }
+
+ if ((scrollTop || scrollLeft)) {
+ xy[0] += scrollLeft;
+ xy[1] += scrollTop;
+ }
+ } else { // default to current offsets
+ xy = Y.DOM._getOffset(node);
+ }
+ }
+ return xy;
+ };
+ } else {
+ return function(node) { // manually calculate by crawling up offsetParents
+ //Calculate the Top and Left border sizes (assumes pixels)
+ var xy = null,
+ parentNode,
+ bCheck,
+ scrollTop,
+ scrollLeft;
+
+ if (node) {
+ if (Y.DOM.inDoc(node)) {
+ xy = [node.offsetLeft, node.offsetTop];
+ parentNode = node;
+ // TODO: refactor with !! or just falsey
+ bCheck = ((Y.UA.gecko || Y.UA.webkit > 519) ? true : false);
+
+ // TODO: worth refactoring for TOP/LEFT only?
+ while ((parentNode = parentNode.offsetParent)) {
+ xy[0] += parentNode.offsetLeft;
+ xy[1] += parentNode.offsetTop;
+ if (bCheck) {
+ xy = Y.DOM._calcBorders(parentNode, xy);
+ }
+ }
+
+ // account for any scrolled ancestors
+ if (Y.DOM.getStyle(node, POSITION) != FIXED) {
+ parentNode = node;
+
+ while ((parentNode = parentNode.parentNode)) {
+ scrollTop = parentNode.scrollTop;
+ scrollLeft = parentNode.scrollLeft;
+
+ //Firefox does something funky with borders when overflow is not visible.
+ if (Y.UA.gecko && (Y.DOM.getStyle(parentNode, 'overflow') !== 'visible')) {
+ xy = Y.DOM._calcBorders(parentNode, xy);
+ }
+
+
+ if (scrollTop || scrollLeft) {
+ xy[0] -= scrollLeft;
+ xy[1] -= scrollTop;
+ }
+ }
+ xy[0] += Y.DOM.docScrollX(node);
+ xy[1] += Y.DOM.docScrollY(node);
+
+ } else {
+ //Fix FIXED position -- add scrollbars
+ xy[0] += Y.DOM.docScrollX(node);
+ xy[1] += Y.DOM.docScrollY(node);
+ }
+ } else {
+ xy = Y.DOM._getOffset(node);
+ }
+ }
+
+ return xy;
+ };
+ }
+ }(),// NOTE: Executing for loadtime branching
+
+ _getOffset: function(node) {
+ var pos,
+ xy = null;
+
+ if (node) {
+ pos = Y.DOM.getStyle(node, POSITION);
+ xy = [
+ parseInt(Y.DOM[GET_COMPUTED_STYLE](node, LEFT), 10),
+ parseInt(Y.DOM[GET_COMPUTED_STYLE](node, TOP), 10)
+ ];
+
+ if ( isNaN(xy[0]) ) { // in case of 'auto'
+ xy[0] = parseInt(Y.DOM.getStyle(node, LEFT), 10); // try inline
+ if ( isNaN(xy[0]) ) { // default to offset value
+ xy[0] = (pos === RELATIVE) ? 0 : node.offsetLeft || 0;
+ }
+ }
+
+ if ( isNaN(xy[1]) ) { // in case of 'auto'
+ xy[1] = parseInt(Y.DOM.getStyle(node, TOP), 10); // try inline
+ if ( isNaN(xy[1]) ) { // default to offset value
+ xy[1] = (pos === RELATIVE) ? 0 : node.offsetTop || 0;
+ }
+ }
+ }
+
+ return xy;
+
+ },
+
+ /**
+ * Gets the current X position of an element based on page coordinates.
+ * Element must be part of the DOM tree to have page coordinates
+ * (display:none or elements not appended return false).
+ * @method getX
+ * @param element The target element
+ * @return {Int} The X position of the element
+ */
+
+ getX: function(node) {
+ return Y.DOM.getXY(node)[0];
+ },
+
+ /**
+ * Gets the current Y position of an element based on page coordinates.
+ * Element must be part of the DOM tree to have page coordinates
+ * (display:none or elements not appended return false).
+ * @method getY
+ * @param element The target element
+ * @return {Int} The Y position of the element
+ */
+
+ getY: function(node) {
+ return Y.DOM.getXY(node)[1];
+ },
+
+ /**
+ * Set the position of an html element in page coordinates.
+ * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+ * @method setXY
+ * @param element The target element
+ * @param {Array} xy Contains X & Y values for new position (coordinates are page-based)
+ * @param {Boolean} noRetry By default we try and set the position a second time if the first fails
+ */
+ setXY: function(node, xy, noRetry) {
+ var setStyle = Y.DOM.setStyle,
+ pos,
+ delta,
+ newXY,
+ currentXY;
+
+ if (node && xy) {
+ pos = Y.DOM.getStyle(node, POSITION);
+
+ delta = Y.DOM._getOffset(node);
+
+ if (pos == 'static') { // default to relative
+ pos = RELATIVE;
+ setStyle(node, POSITION, pos);
+ }
+
+ currentXY = Y.DOM.getXY(node);
+
+ if (xy[0] !== null) {
+ setStyle(node, LEFT, xy[0] - currentXY[0] + delta[0] + 'px');
+ }
+
+ if (xy[1] !== null) {
+ setStyle(node, TOP, xy[1] - currentXY[1] + delta[1] + 'px');
+ }
+
+ if (!noRetry) {
+ newXY = Y.DOM.getXY(node);
+ if (newXY[0] !== xy[0] || newXY[1] !== xy[1]) {
+ Y.DOM.setXY(node, xy, true);
+ }
+ }
+
+ Y.log('setXY setting position to ' + xy, 'info', 'dom-screen');
+ } else {
+ Y.log('setXY failed to set ' + node + ' to ' + xy, 'info', 'dom-screen');
+ }
+ },
+
+ /**
+ * Set the X position of an html element in page coordinates, regardless of how the element is positioned.
+ * The element(s) must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+ * @method setX
+ * @param element The target element
+ * @param {Int} x The X values for new position (coordinates are page-based)
+ */
+ setX: function(node, x) {
+ return Y.DOM.setXY(node, [x, null]);
+ },
+
+ /**
+ * Set the Y position of an html element in page coordinates, regardless of how the element is positioned.
+ * The element(s) must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+ * @method setY
+ * @param element The target element
+ * @param {Int} y The Y values for new position (coordinates are page-based)
+ */
+ setY: function(node, y) {
+ return Y.DOM.setXY(node, [null, y]);
+ },
+
+ _calcBorders: function(node, xy2) {
+ var t = parseInt(Y.DOM[GET_COMPUTED_STYLE](node, BORDER_TOP_WIDTH), 10) || 0,
+ l = parseInt(Y.DOM[GET_COMPUTED_STYLE](node, BORDER_LEFT_WIDTH), 10) || 0;
+ if (Y.UA.gecko) {
+ if (RE_TABLE.test(node.tagName)) {
+ t = 0;
+ l = 0;
+ }
+ }
+ xy2[0] += l;
+ xy2[1] += t;
+ return xy2;
+ },
+
+ _getWinSize: function(node) {
+ var doc = Y.DOM._getDoc(),
+ win = doc.defaultView || doc.parentWindow,
+ mode = doc[COMPAT_MODE],
+ h = win.innerHeight,
+ w = win.innerWidth,
+ root = doc[DOCUMENT_ELEMENT];
+
+ if ( mode && !Y.UA.opera ) { // IE, Gecko
+ if (mode != 'CSS1Compat') { // Quirks
+ root = doc.body;
+ }
+ h = root.clientHeight;
+ w = root.clientWidth;
+ }
+ return { height: h, width: w };
+ },
+
+ _getDocSize: function(node) {
+ var doc = Y.DOM._getDoc(),
+ root = doc[DOCUMENT_ELEMENT];
+
+ if (doc[COMPAT_MODE] != 'CSS1Compat') {
+ root = doc.body;
+ }
+
+ return { height: root.scrollHeight, width: root.scrollWidth };
+ }
+});
+})(Y);
+(function(Y) {
+var TOP = 'top',
+ RIGHT = 'right',
+ BOTTOM = 'bottom',
+ LEFT = 'left',
+
+ getOffsets = function(r1, r2) {
+ var t = Math.max(r1[TOP], r2[TOP]),
+ r = Math.min(r1[RIGHT], r2[RIGHT]),
+ b = Math.min(r1[BOTTOM], r2[BOTTOM]),
+ l = Math.max(r1[LEFT], r2[LEFT]),
+ ret = {};
+
+ ret[TOP] = t;
+ ret[RIGHT] = r;
+ ret[BOTTOM] = b;
+ ret[LEFT] = l;
+ return ret;
+ },
+
+ DOM = Y.DOM;
+
+Y.mix(DOM, {
+ /**
+ * Returns an Object literal containing the following about this element: (top, right, bottom, left)
+ * @method region
+ * @param {HTMLElement} element The DOM element.
+ @return {Object} Object literal containing the following about this element: (top, right, bottom, left)
+ */
+ region: function(node) {
+ var xy = DOM.getXY(node),
+ ret = false;
+
+ if (node && xy) {
+ ret = DOM._getRegion(
+ xy[1], // top
+ xy[0] + node.offsetWidth, // right
+ xy[1] + node.offsetHeight, // bottom
+ xy[0] // left
+ );
+ }
+
+ return ret;
+ },
+
+ /**
+ * Find the intersect information for the passes nodes.
+ * @method intersect
+ * @param {HTMLElement} element The first element
+ * @param {HTMLElement | Object} element2 The element or region to check the interect with
+ * @param {Object} altRegion An object literal containing the region for the first element if we already have the data (for performance i.e. DragDrop)
+ @return {Object} Object literal containing the following intersection data: (top, right, bottom, left, area, yoff, xoff, inRegion)
+ */
+ intersect: function(node, node2, altRegion) {
+ var r = altRegion || DOM.region(node), region = {},
+ n = node2,
+ off;
+
+ if (n.tagName) {
+ region = DOM.region(n);
+ } else if (Y.Lang.isObject(node2)) {
+ region = node2;
+ } else {
+ return false;
+ }
+
+ off = getOffsets(region, r);
+ return {
+ top: off[TOP],
+ right: off[RIGHT],
+ bottom: off[BOTTOM],
+ left: off[LEFT],
+ area: ((off[BOTTOM] - off[TOP]) * (off[RIGHT] - off[LEFT])),
+ yoff: ((off[BOTTOM] - off[TOP])),
+ xoff: (off[RIGHT] - off[LEFT]),
+ inRegion: DOM.inRegion(node, node2, false, altRegion)
+ };
+
+ },
+ /**
+ * Check if any part of this node is in the passed region
+ * @method inRegion
+ * @param {Object} node2 The node to get the region from or an Object literal of the region
+ * $param {Boolean} all Should all of the node be inside the region
+ * @param {Object} altRegion An object literal containing the region for this node if we already have the data (for performance i.e. DragDrop)
+ * @return {Boolean} True if in region, false if not.
+ */
+ inRegion: function(node, node2, all, altRegion) {
+ var region = {},
+ r = altRegion || DOM.region(node),
+ n = node2,
+ off;
+
+ if (n.tagName) {
+ region = DOM.region(n);
+ } else if (Y.Lang.isObject(node2)) {
+ region = node2;
+ } else {
+ return false;
+ }
+
+ if (all) {
+ return (
+ r[LEFT] >= region[LEFT] &&
+ r[RIGHT] <= region[RIGHT] &&
+ r[TOP] >= region[TOP] &&
+ r[BOTTOM] <= region[BOTTOM] );
+ } else {
+ off = getOffsets(region, r);
+ if (off[BOTTOM] >= off[TOP] && off[RIGHT] >= off[LEFT]) {
+ return true;
+ } else {
+ return false;
+ }
+
+ }
+ },
+
+ /**
+ * Check if any part of this element is in the viewport
+ * @method inViewportRegion
+ * @param {HTMLElement} element The DOM element.
+ * @param {Boolean} all Should all of the node be inside the region
+ * @param {Object} altRegion An object literal containing the region for this node if we already have the data (for performance i.e. DragDrop)
+ * @return {Boolean} True if in region, false if not.
+ */
+ inViewportRegion: function(node, all, altRegion) {
+ return DOM.inRegion(node, DOM.viewportRegion(node), all, altRegion);
+
+ },
+
+ _getRegion: function(t, r, b, l) {
+ var region = {};
+
+ region[TOP] = region[1] = t;
+ region[LEFT] = region[0] = l;
+ region[BOTTOM] = b;
+ region[RIGHT] = r;
+ region.width = region[RIGHT] - region[LEFT];
+ region.height = region[BOTTOM] - region[TOP];
+
+ return region;
+ },
+
+ /**
+ * Returns an Object literal containing the following about the visible region of viewport: (top, right, bottom, left)
+ * @method viewportRegion
+ @return {Object} Object literal containing the following about the visible region of the viewport: (top, right, bottom, left)
+ */
+ viewportRegion: function(node) {
+ node = node || Y.config.doc.documentElement;
+ var ret = false,
+ scrollX,
+ scrollY;
+
+ if (node) {
+ scrollX = DOM.docScrollX(node);
+ scrollY = DOM.docScrollY(node);
+
+ ret = DOM._getRegion(scrollY, // top
+ DOM.winWidth(node) + scrollX, // right
+ scrollY + DOM.winHeight(node), // bottom
+ scrollX); // left
+ }
+
+ return ret;
+ }
+});
+})(Y);
+
+
+}, '3.0.0' ,{requires:['dom-base', 'dom-style']});
+YUI.add('selector-native', function(Y) {
+
+(function(Y) {
+/**
+ * The selector-native module provides support for native querySelector
+ * @module dom
+ * @submodule selector-native
+ * @for Selector
+ */
+
+/**
+ * Provides support for using CSS selectors to query the DOM
+ * @class Selector
+ * @static
+ * @for Selector
+ */
+
+Y.namespace('Selector'); // allow native module to standalone
+
+var COMPARE_DOCUMENT_POSITION = 'compareDocumentPosition',
+ OWNER_DOCUMENT = 'ownerDocument',
+ TMP_PREFIX = 'yui-tmp-',
+ g_counter = 0;
+
+var Selector = {
+ _foundCache: [],
+
+ useNative: true,
+
+ _compare: ('sourceIndex' in document.documentElement) ?
+ function(nodeA, nodeB) {
+ var a = nodeA.sourceIndex,
+ b = nodeB.sourceIndex;
+
+ if (a === b) {
+ return 0;
+ } else if (a > b) {
+ return 1;
+ }
+
+ return -1;
+
+ } : (document.documentElement[COMPARE_DOCUMENT_POSITION] ?
+ function(nodeA, nodeB) {
+ if (nodeA[COMPARE_DOCUMENT_POSITION](nodeB) & 4) {
+ return -1;
+ } else {
+ return 1;
+ }
+ } :
+ function(nodeA, nodeB) {
+ var rangeA, rangeB, compare;
+ if (nodeA && nodeB) {
+ rangeA = nodeA[OWNER_DOCUMENT].createRange();
+ rangeA.setStart(nodeA, 0);
+ rangeB = nodeB[OWNER_DOCUMENT].createRange();
+ rangeB.setStart(nodeB, 0);
+ compare = rangeA.compareBoundaryPoints(1, rangeB); // 1 === Range.START_TO_END
+ }
+
+ return compare;
+
+ }),
+
+ _sort: function(nodes) {
+ if (nodes) {
+ nodes = Y.Array(nodes, 0, true);
+ if (nodes.sort) {
+ nodes.sort(Selector._compare);
+ }
+ }
+
+ return nodes;
+ },
+
+ _deDupe: function(nodes) {
+ var ret = [],
+ i, node;
+
+ for (i = 0; (node = nodes[i++]);) {
+ if (!node._found) {
+ ret[ret.length] = node;
+ node._found = true;
+ }
+ }
+
+ for (i = 0; (node = ret[i++]);) {
+ node._found = null;
+ node.removeAttribute('_found');
+ }
+
+ return ret;
+ },
+
+ /**
+ * Retrieves a set of nodes based on a given CSS selector.
+ * @method query
+ *
+ * @param {string} selector The CSS Selector to test the node against.
+ * @param {HTMLElement} root optional An HTMLElement to start the query from. Defaults to Y.config.doc
+ * @param {Boolean} firstOnly optional Whether or not to return only the first match.
+ * @return {Array} An array of nodes that match the given selector.
+ * @static
+ */
+ query: function(selector, root, firstOnly, skipNative) {
+ root = root || Y.config.doc;
+ var ret = [],
+ useNative = (Y.Selector.useNative && document.querySelector && !skipNative),
+ queries = [[selector, root]],
+ query,
+ result,
+ i,
+ fn = (useNative) ? Y.Selector._nativeQuery : Y.Selector._bruteQuery;
+
+ if (selector && fn) {
+ // split group into seperate queries
+ if (!skipNative && // already done if skipping
+ (!useNative || root.tagName)) { // split native when element scoping is needed
+ queries = Selector._splitQueries(selector, root);
+ }
+
+ for (i = 0; (query = queries[i++]);) {
+ result = fn(query[0], query[1], firstOnly);
+ if (!firstOnly) { // coerce DOM Collection to Array
+ result = Y.Array(result, 0, true);
+ }
+ if (result) {
+ ret = ret.concat(result);
+ }
+ }
+
+ if (queries.length > 1) { // remove dupes and sort by doc order
+ ret = Selector._sort(Selector._deDupe(ret));
+ }
+ }
+
+ Y.log('query: ' + selector + ' returning: ' + ret.length, 'info', 'Selector');
+ return (firstOnly) ? (ret[0] || null) : ret;
+
+ },
+
+ // allows element scoped queries to begin with combinator
+ // e.g. query('> p', document.body) === query('body > p')
+ _splitQueries: function(selector, node) {
+ var groups = selector.split(','),
+ queries = [],
+ prefix = '',
+ i, len;
+
+ if (node) {
+ // enforce for element scoping
+ if (node.tagName) {
+ node.id = node.id || Y.guid();
+ prefix = '#' + node.id + ' ';
+ }
+
+ for (i = 0, len = groups.length; i < len; ++i) {
+ selector = prefix + groups[i];
+ queries.push([selector, node]);
+ }
+ }
+
+ return queries;
+ },
+
+ _nativeQuery: function(selector, root, one) {
+ try {
+ //Y.log('trying native query with: ' + selector, 'info', 'selector-native');
+ return root['querySelector' + (one ? '' : 'All')](selector);
+ } catch(e) { // fallback to brute if available
+ //Y.log('native query error; reverting to brute query with: ' + selector, 'info', 'selector-native');
+ return Y.Selector.query(selector, root, one, true); // redo with skipNative true
+ }
+ },
+
+ filter: function(nodes, selector) {
+ var ret = [],
+ i, node;
+
+ if (nodes && selector) {
+ for (i = 0; (node = nodes[i++]);) {
+ if (Y.Selector.test(node, selector)) {
+ ret[ret.length] = node;
+ }
+ }
+ } else {
+ Y.log('invalid filter input (nodes: ' + nodes +
+ ', selector: ' + selector + ')', 'warn', 'Selector');
+ }
+
+ return ret;
+ },
+
+ test: function(node, selector, root) {
+ var ret = false,
+ groups = selector.split(','),
+ item,
+ i, group;
+
+ if (node && node.tagName) { // only test HTMLElements
+ root = root || node.ownerDocument;
+
+ if (!node.id) {
+ node.id = TMP_PREFIX + g_counter++;
+ }
+ for (i = 0; (group = groups[i++]);) { // TODO: off-dom test
+ group += '#' + node.id; // add ID for uniqueness
+ item = Y.Selector.query(group, root, true);
+ ret = (item === node);
+ if (ret) {
+ break;
+ }
+ }
+ }
+
+ return ret;
+ }
+};
+
+Y.mix(Y.Selector, Selector, true);
+
+})(Y);
+
+
+}, '3.0.0' ,{requires:['dom-base']});
+YUI.add('selector-css2', function(Y) {
+
+/**
+ * The selector module provides helper methods allowing CSS2 Selectors to be used with DOM elements.
+ * @module dom
+ * @submodule selector-css2
+ * @for Selector
+ */
+
+/**
+ * Provides helper methods for collecting and filtering DOM elements.
+ */
+
+var PARENT_NODE = 'parentNode',
+ TAG_NAME = 'tagName',
+ ATTRIBUTES = 'attributes',
+ COMBINATOR = 'combinator',
+ PSEUDOS = 'pseudos',
+
+ Selector = Y.Selector,
+
+ SelectorCSS2 = {
+ SORT_RESULTS: true,
+ _children: function(node, tag) {
+ var ret = node.children,
+ i,
+ children = [],
+ childNodes,
+ child;
+
+ if (node.children && tag && node.children.tags) {
+ children = node.children.tags(tag);
+ } else if ((!ret && node[TAG_NAME]) || (ret && tag)) { // only HTMLElements have children
+ childNodes = ret || node.childNodes;
+ ret = [];
+ for (i = 0; (child = childNodes[i++]);) {
+ if (child.tagName) {
+ if (!tag || tag === child.tagName) {
+ ret.push(child);
+ }
+ }
+ }
+ }
+
+ return ret || [];
+ },
+
+ _regexCache: {},
+
+ _re: {
+ attr: /(\[.*\])/g,
+ pseudos: /:([\-\w]+(?:\(?:['"]?(.+)['"]?\)))*/i
+ },
+
+ /**
+ * Mapping of shorthand tokens to corresponding attribute selector
+ * @property shorthand
+ * @type object
+ */
+ shorthand: {
+ '\\#(-?[_a-z]+[-\\w]*)': '[id=$1]',
+ '\\.(-?[_a-z]+[-\\w]*)': '[className~=$1]'
+ },
+
+ /**
+ * List of operators and corresponding boolean functions.
+ * These functions are passed the attribute and the current node's value of the attribute.
+ * @property operators
+ * @type object
+ */
+ operators: {
+ '': function(node, attr) { return Y.DOM.getAttribute(node, attr) !== ''; }, // Just test for existence of attribute
+ //'': '.+',
+ //'=': '^{val}$', // equality
+ '~=': '(?:^|\\s+){val}(?:\\s+|$)', // space-delimited
+ '|=': '^{val}-?' // optional hyphen-delimited
+ },
+
+ pseudos: {
+ 'first-child': function(node) {
+ return Y.Selector._children(node[PARENT_NODE])[0] === node;
+ }
+ },
+
+ _bruteQuery: function(selector, root, firstOnly) {
+ var ret = [],
+ nodes = [],
+ tokens = Selector._tokenize(selector),
+ token = tokens[tokens.length - 1],
+ rootDoc = Y.DOM._getDoc(root),
+ id,
+ className,
+ tagName;
+
+
+ // if we have an initial ID, set to root when in document
+ if (tokens[0] && rootDoc === root &&
+ (id = tokens[0].id) &&
+ rootDoc.getElementById(id)) {
+ root = rootDoc.getElementById(id);
+ }
+
+ if (token) {
+ // prefilter nodes
+ id = token.id;
+ className = token.className;
+ tagName = token.tagName || '*';
+
+ // try ID first
+ if (id) {
+ if (rootDoc.getElementById(id)) { // if in document
+ nodes = [rootDoc.getElementById(id)]; // TODO: DOM.byId?
+ }
+ // try className if supported
+ } else if (className) {
+ nodes = root.getElementsByClassName(className);
+ } else if (tagName) { // default to tagName
+ nodes = root.getElementsByTagName(tagName || '*');
+ }
+
+ if (nodes.length) {
+ ret = Selector._filterNodes(nodes, tokens, firstOnly);
+ }
+ }
+
+ return ret;
+ },
+
+ _filterNodes: function(nodes, tokens, firstOnly) {
+ var i = 0,
+ j,
+ len = tokens.length,
+ n = len - 1,
+ result = [],
+ node = nodes[0],
+ tmpNode = node,
+ getters = Y.Selector.getters,
+ operator,
+ combinator,
+ token,
+ path,
+ pass,
+ //FUNCTION = 'function',
+ value,
+ tests,
+ test;
+
+ //do {
+ for (i = 0; (tmpNode = node = nodes[i++]);) {
+ n = len - 1;
+ path = null;
+
+ testLoop:
+ while (tmpNode && tmpNode.tagName) {
+ token = tokens[n];
+ tests = token.tests;
+ j = tests.length;
+ if (j && !pass) {
+ while ((test = tests[--j])) {
+ operator = test[1];
+ if (getters[test[0]]) {
+ value = getters[test[0]](tmpNode, test[0]);
+ } else {
+ value = tmpNode[test[0]];
+ // use getAttribute for non-standard attributes
+ if (value === undefined && tmpNode.getAttribute) {
+ value = tmpNode.getAttribute(test[0]);
+ }
+ }
+
+ if ((operator === '=' && value !== test[2]) || // fast path for equality
+ (operator.test && !operator.test(value)) || // regex test
+ (operator.call && !operator(tmpNode, test[0]))) { // function test
+
+ // skip non element nodes or non-matching tags
+ if ((tmpNode = tmpNode[path])) {
+ while (tmpNode &&
+ (!tmpNode.tagName ||
+ (token.tagName && token.tagName !== tmpNode.tagName))
+ ) {
+ tmpNode = tmpNode[path];
+ }
+ }
+ continue testLoop;
+ }
+ }
+ }
+
+ n--; // move to next token
+ // now that we've passed the test, move up the tree by combinator
+ if (!pass && (combinator = token.combinator)) {
+ path = combinator.axis;
+ tmpNode = tmpNode[path];
+
+ // skip non element nodes
+ while (tmpNode && !tmpNode.tagName) {
+ tmpNode = tmpNode[path];
+ }
+
+ if (combinator.direct) { // one pass only
+ path = null;
+ }
+
+ } else { // success if we made it this far
+ result.push(node);
+ if (firstOnly) {
+ return result;
+ }
+ break;
+ }
+ }
+ }// while (tmpNode = node = nodes[++i]);
+ node = tmpNode = null;
+ return result;
+ },
+
+ _getRegExp: function(str, flags) {
+ var regexCache = Selector._regexCache;
+ flags = flags || '';
+ if (!regexCache[str + flags]) {
+ regexCache[str + flags] = new RegExp(str, flags);
+ }
+ return regexCache[str + flags];
+ },
+
+ combinators: {
+ ' ': {
+ axis: 'parentNode'
+ },
+
+ '>': {
+ axis: 'parentNode',
+ direct: true
+ },
+
+
+ '+': {
+ axis: 'previousSibling',
+ direct: true
+ }
+ },
+
+ _parsers: [
+ {
+ name: ATTRIBUTES,
+ re: /^\[([a-z]+\w*)+([~\|\^\$\*!=]=?)?['"]?([^\]]*?)['"]?\]/i,
+ fn: function(match, token) {
+ var operator = match[2] || '',
+ operators = Y.Selector.operators,
+ test;
+
+ // add prefiltering for ID and CLASS
+ if ((match[1] === 'id' && operator === '=') ||
+ (match[1] === 'className' &&
+ document.getElementsByClassName &&
+ (operator === '~=' || operator === '='))) {
+ token.prefilter = match[1];
+ token[match[1]] = match[3];
+ }
+
+ // add tests
+ if (operator in operators) {
+ test = operators[operator];
+ if (typeof test === 'string') {
+ test = Y.Selector._getRegExp(test.replace('{val}', match[3]));
+ }
+ match[2] = test;
+ }
+ if (!token.last || token.prefilter !== match[1]) {
+ return match.slice(1);
+ }
+ }
+
+ },
+ {
+ name: TAG_NAME,
+ re: /^((?:-?[_a-z]+[\w-]*)|\*)/i,
+ fn: function(match, token) {
+ var tag = match[1].toUpperCase();
+ token.tagName = tag;
+
+ if (tag !== '*' && (!token.last || token.prefilter)) {
+ return [TAG_NAME, '=', tag];
+ }
+ if (!token.prefilter) {
+ token.prefilter = 'tagName';
+ }
+ }
+ },
+ {
+ name: COMBINATOR,
+ re: /^\s*([>+~]|\s)\s*/,
+ fn: function(match, token) {
+ }
+ },
+ {
+ name: PSEUDOS,
+ re: /^:([\-\w]+)(?:\(['"]?(.+)['"]?\))*/i,
+ fn: function(match, token) {
+ var test = Selector[PSEUDOS][match[1]];
+ if (test) { // reorder match array
+ return [match[2], test];
+ } else { // selector token not supported (possibly missing CSS3 module)
+ return false;
+ }
+ }
+ }
+ ],
+
+ _getToken: function(token) {
+ return {
+ tagName: null,
+ id: null,
+ className: null,
+ attributes: {},
+ combinator: null,
+ tests: []
+ };
+ },
+
+ /**
+ Break selector into token units per simple selector.
+ Combinator is attached to the previous token.
+ */
+ _tokenize: function(selector) {
+ selector = selector || '';
+ selector = Selector._replaceShorthand(Y.Lang.trim(selector));
+ var token = Selector._getToken(), // one token per simple selector (left selector holds combinator)
+ query = selector, // original query for debug report
+ tokens = [], // array of tokens
+ found = false, // whether or not any matches were found this pass
+ match, // the regex match
+ test,
+ i, parser;
+
+ /*
+ Search for selector patterns, store, and strip them from the selector string
+ until no patterns match (invalid selector) or we run out of chars.
+
+ Multiple attributes and pseudos are allowed, in any order.
+ for example:
+ 'form:first-child[type=button]:not(button)[lang|=en]'
+ */
+ outer:
+ do {
+ found = false; // reset after full pass
+ for (i = 0; (parser = Selector._parsers[i++]);) {
+ if ( (match = parser.re.exec(selector)) ) { // note assignment
+ if (parser !== COMBINATOR ) {
+ token.selector = selector;
+ }
+ selector = selector.replace(match[0], ''); // strip current match from selector
+ if (!selector.length) {
+ token.last = true;
+ }
+
+ if (Selector._attrFilters[match[1]]) { // convert class to className, etc.
+ match[1] = Selector._attrFilters[match[1]];
+ }
+
+ test = parser.fn(match, token);
+ if (test === false) { // selector not supported
+ found = false;
+ break outer;
+ } else if (test) {
+ token.tests.push(test);
+ }
+
+ if (!selector.length || parser.name === COMBINATOR) {
+ tokens.push(token);
+ token = Selector._getToken(token);
+ if (parser.name === COMBINATOR) {
+ token.combinator = Y.Selector.combinators[match[1]];
+ }
+ }
+ found = true;
+ }
+ }
+ } while (found && selector.length);
+
+ if (!found || selector.length) { // not fully parsed
+ Y.log('query: ' + query + ' contains unsupported token in: ' + selector, 'warn', 'Selector');
+ tokens = [];
+ }
+ return tokens;
+ },
+
+ _replaceShorthand: function(selector) {
+ var shorthand = Selector.shorthand,
+ attrs = selector.match(Selector._re.attr), // pull attributes to avoid false pos on "." and "#"
+ pseudos = selector.match(Selector._re.pseudos), // pull attributes to avoid false pos on "." and "#"
+ re, i, len;
+
+ if (pseudos) {
+ selector = selector.replace(Selector._re.pseudos, '!!REPLACED_PSEUDO!!');
+ }
+
+ if (attrs) {
+ selector = selector.replace(Selector._re.attr, '!!REPLACED_ATTRIBUTE!!');
+ }
+
+ for (re in shorthand) {
+ if (shorthand.hasOwnProperty(re)) {
+ selector = selector.replace(Selector._getRegExp(re, 'gi'), shorthand[re]);
+ }
+ }
+
+ if (attrs) {
+ for (i = 0, len = attrs.length; i < len; ++i) {
+ selector = selector.replace('!!REPLACED_ATTRIBUTE!!', attrs[i]);
+ }
+ }
+ if (pseudos) {
+ for (i = 0, len = pseudos.length; i < len; ++i) {
+ selector = selector.replace('!!REPLACED_PSEUDO!!', pseudos[i]);
+ }
+ }
+ return selector;
+ },
+
+ _attrFilters: {
+ 'class': 'className',
+ 'for': 'htmlFor'
+ },
+
+ getters: {
+ href: function(node, attr) {
+ return Y.DOM.getAttribute(node, attr);
+ }
+ }
+ };
+
+Y.mix(Y.Selector, SelectorCSS2, true);
+Y.Selector.getters.src = Y.Selector.getters.rel = Y.Selector.getters.href;
+
+// IE wants class with native queries
+if (Y.Selector.useNative && document.querySelector) {
+ Y.Selector.shorthand['\\.(-?[_a-z]+[-\\w]*)'] = '[class~=$1]';
+}
+
+
+
+}, '3.0.0' ,{requires:['selector-native']});
+
+
+YUI.add('selector', function(Y){}, '3.0.0' ,{use:['selector-native', 'selector-css2']});
+
+
+
+YUI.add('dom', function(Y){}, '3.0.0' ,{use:['dom-base', 'dom-style', 'dom-screen', 'selector']});
+
diff --git a/lib/yui/3.0.0/dom/dom-min.js b/lib/yui/3.0.0/dom/dom-min.js
new file mode 100644
index 0000000000..496452ab59
--- /dev/null
+++ b/lib/yui/3.0.0/dom/dom-min.js
@@ -0,0 +1,11 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("dom-base",function(D){(function(H){var R="nodeType",F="ownerDocument",E="defaultView",J="parentWindow",M="tagName",O="parentNode",Q="firstChild",L="previousSibling",P="nextSibling",K="contains",G="compareDocumentPosition",N=document.documentElement,I=/<([a-z]+)/i;H.DOM={byId:function(T,S){S=S||H.config.doc;return S.getElementById(T);},children:function(U,S){var T=[];if(U){S=S||"*";T=H.Selector.query("> "+S,U);}return T;},firstByTag:function(S,T){var U;T=T||H.config.doc;if(S&&T.getElementsByTagName){U=T.getElementsByTagName(S)[0];}return U||null;},getText:(N.textContent!==undefined)?function(T){var S="";if(T){S=T.textContent;}return S||"";}:function(T){var S="";if(T){S=T.innerText;}return S||"";},setText:(N.textContent!==undefined)?function(S,T){if(S){S.textContent=T;}}:function(S,T){if(S){S.innerText=T;}},previous:function(S,U,T){return H.DOM.elementByAxis(S,L,U,T);},next:function(S,U,T){return H.DOM.elementByAxis(S,P,U,T);},ancestor:function(S,U,T){return H.DOM.elementByAxis(S,O,U,T);},elementByAxis:function(S,V,U,T){while(S&&(S=S[V])){if((T||S[M])&&(!U||U(S))){return S;}}return null;},contains:function(T,U){var S=false;if(!U||!T||!U[R]||!T[R]){S=false;}else{if(T[K]){if(H.UA.opera||U[R]===1){S=T[K](U);}else{S=H.DOM._bruteContains(T,U);}}else{if(T[G]){if(T===U||!!(T[G](U)&16)){S=true;}}}}return S;},inDoc:function(S,T){T=T||S[F];var U=S.id;if(!U){U=S.id=H.guid();}return !!(T.getElementById(U));},create:function(X,Z){if(typeof X==="string"){X=H.Lang.trim(X);}if(!Z&&H.DOM._cloneCache[X]){return H.DOM._cloneCache[X].cloneNode(true);}Z=Z||H.config.doc;var T=I.exec(X),W=H.DOM._create,Y=H.DOM.creators,V=null,S,U;if(T&&Y[T[1]]){if(typeof Y[T[1]]==="function"){W=Y[T[1]];}else{S=Y[T[1]];}}U=W(X,Z,S).childNodes;if(U.length===1){V=U[0].parentNode.removeChild(U[0]);}else{V=H.DOM._nl2frag(U,Z);}if(V){H.DOM._cloneCache[X]=V.cloneNode(true);}return V;},_nl2frag:function(T,W){var U=null,V,S;if(T&&(T.push||T.item)&&T[0]){W=W||T[0].ownerDocument;U=W.createDocumentFragment();if(T.item){T=H.Array(T,0,true);}for(V=0,S=T.length;V)+\s*",T="";if(W.UA.ie){W.mix(X,{tbody:function(Z,a){var b=S(U+Z+T,a),Y=b.children.tags("tbody")[0];if(b.children.length>1&&Y&&!V.test(Z)){Y[O].removeChild(Y);}return b;},script:function(Y,Z){var a=Z.createElement("div");a.innerHTML="-"+Y;a.removeChild(a[Q]);return a;}},true);W.mix(W.DOM.VALUE_GETTERS,{button:function(Y){return(Y.attributes&&Y.attributes.value)?Y.attributes.value.value:"";}});W.mix(W.DOM.VALUE_SETTERS,{button:function(Z,a){var Y=Z.attributes.value;if(!Y){Y=Z[F].createAttribute("value");Z.setAttributeNode(Y);}Y.value=a;}});}if(W.UA.gecko||W.UA.ie){W.mix(X,{option:function(Y,Z){return S("",Z);},tr:function(Y,Z){return S(""+Y+"",Z);},td:function(Y,Z){return S("
"+Y+"
",Z);},tbody:function(Y,Z){return S(U+Y+T,Z);}});W.mix(X,{legend:"fieldset",th:X.td,thead:X.tbody,tfoot:X.tbody,caption:X.tbody,colgroup:X.tbody,col:X.tbody,optgroup:X.option});}W.mix(W.DOM.VALUE_GETTERS,{option:function(Z){var Y=Z.attributes;return(Y.value&&Y.value.specified)?Z.value:Z.text;},select:function(Z){var a=Z.value,Y=Z.options;if(Y&&a===""){if(Z.multiple){}else{a=W.DOM.getValue(Y[Z.selectedIndex],"value");}}return a;}});})(H);})(D);var B,A,C;D.mix(D.DOM,{hasClass:function(G,F){var E=D.DOM._getRegExp("(?:^|\\s+)"+F+"(?:\\s+|$)");return E.test(G.className);},addClass:function(F,E){if(!D.DOM.hasClass(F,E)){F.className=D.Lang.trim([F.className,E].join(" "));
+}},removeClass:function(F,E){if(E&&A(F,E)){F.className=D.Lang.trim(F.className.replace(D.DOM._getRegExp("(?:^|\\s+)"+E+"(?:\\s+|$)")," "));if(A(F,E)){C(F,E);}}},replaceClass:function(F,E,G){B(F,G);C(F,E);},toggleClass:function(F,E){if(A(F,E)){C(F,E);}else{B(F,E);}}});A=D.DOM.hasClass;C=D.DOM.removeClass;B=D.DOM.addClass;},"3.0.0",{requires:["oop"]});YUI.add("dom-style",function(A){(function(E){var C="documentElement",B="defaultView",D="ownerDocument",L="style",N="float",F="cssFloat",G="styleFloat",J="transparent",H="getComputedStyle",M=E.config.doc,I=undefined,K=/color$/i;E.mix(E.DOM,{CUSTOM_STYLES:{},setStyle:function(R,O,S,Q){Q=Q||R.style;var P=E.DOM.CUSTOM_STYLES;if(Q){if(S===null){S="";}if(O in P){if(P[O].set){P[O].set(R,S,Q);return;}else{if(typeof P[O]==="string"){O=P[O];}}}Q[O]=S;}},getStyle:function(R,O){var Q=R[L],P=E.DOM.CUSTOM_STYLES,S="";if(Q){if(O in P){if(P[O].get){return P[O].get(R,O,Q);}else{if(typeof P[O]==="string"){O=P[O];}}}S=Q[O];if(S===""){S=E.DOM[H](R,O);}}return S;},setStyles:function(P,Q){var O=P.style;E.each(Q,function(R,S){E.DOM.setStyle(P,S,R,O);},E.DOM);},getComputedStyle:function(P,O){var R="",Q=P[D];if(P[L]){R=Q[B][H](P,null)[O];}return R;}});if(M[C][L][F]!==I){E.DOM.CUSTOM_STYLES[N]=F;}else{if(M[C][L][G]!==I){E.DOM.CUSTOM_STYLES[N]=G;}}if(E.UA.opera){E.DOM[H]=function(Q,P){var O=Q[D][B],R=O[H](Q,"")[P];if(K.test(P)){R=E.Color.toRGB(R);}return R;};}if(E.UA.webkit){E.DOM[H]=function(Q,P){var O=Q[D][B],R=O[H](Q,"")[P];if(R==="rgba(0, 0, 0, 0)"){R=J;}return R;};}})(A);(function(D){var B=parseInt,C=RegExp;D.Color={KEYWORDS:{black:"000",silver:"c0c0c0",gray:"808080",white:"fff",maroon:"800000",red:"f00",purple:"800080",fuchsia:"f0f",green:"008000",lime:"0f0",olive:"808000",yellow:"ff0",navy:"000080",blue:"00f",teal:"008080",aqua:"0ff"},re_RGB:/^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i,re_hex:/^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i,re_hex3:/([0-9A-F])/gi,toRGB:function(E){if(!D.Color.re_RGB.test(E)){E=D.Color.toHex(E);}if(D.Color.re_hex.exec(E)){E="rgb("+[B(C.$1,16),B(C.$2,16),B(C.$3,16)].join(", ")+")";}return E;},toHex:function(F){F=D.Color.KEYWORDS[F]||F;if(D.Color.re_RGB.exec(F)){F=[Number(C.$1).toString(16),Number(C.$2).toString(16),Number(C.$3).toString(16)];for(var E=0;E-1)){a=c;}else{if(D.DOM.IE.COMPUTED[b]){a=D.DOM.IE.COMPUTED[b](Y,b);}else{if(P.test(c)){a=N.getPixel(Y,b)+K;}else{a=c;}}}}}return a;},sizeOffsets:{width:["Left","Right"],height:["Top","Bottom"],top:["Top"],bottom:["Bottom"]},getOffset:function(b,g){var d=E(b)[g],Y=g.charAt(0).toUpperCase()+g.substr(1),f="offset"+Y,a="pixel"+Y,e=N.sizeOffsets[g],c="";if(d===M||d.indexOf("%")>-1){c=b["offset"+Y];if(e[0]){c-=N.getPixel(b,"padding"+e[0]);c-=N.getBorderWidth(b,"border"+e[0]+"Width",1);}if(e[1]){c-=N.getPixel(b,"padding"+e[1]);c-=N.getBorderWidth(b,"border"+e[1]+"Width",1);}}else{if(!b.style[a]&&!b.style[g]){b.style[g]=d;}c=b.style[a];}return c+K;},borderMap:{thin:"2px",medium:"4px",thick:"6px"},getBorderWidth:function(a,c,Y){var b=Y?"":K,d=a.currentStyle[c];if(d.indexOf(K)<0){if(N.borderMap[d]){d=N.borderMap[d];}else{}}return(Y)?parseFloat(d):d;},getPixel:function(b,Y){var d=null,a=E(b),e=a.right,c=a[Y];b.style.right=c;d=b.style.pixelRight;b.style.right=e;return d;},getMargin:function(b,Y){var c,a=E(b);if(a[Y]==M){c=0;}else{c=N.getPixel(b,Y);}return c+K;},getVisibility:function(a,Y){var b;while((b=a.currentStyle)&&b[Y]=="inherit"){a=a.parentNode;}return(b)?b[Y]:S;},getColor:function(a,Y){var b=E(a)[Y];if(!b||b===R){D.DOM.elementByAxis(a,"parentNode",null,function(c){b=E(c)[Y];if(b&&b!==R){a=c;return true;}});}return D.Color.toRGB(b);},getBorderColor:function(a,Y){var b=E(a),c=b[Y]||b.color;return D.Color.toRGB(D.Color.toHex(c));}},F={};try{if(X.style[T]===Z&&X[B]){D.DOM.CUSTOM_STYLES[T]={get:function(a){var c=100;try{c=a[B]["DXImageTransform.Microsoft.Alpha"][T];}catch(b){try{c=a[B]("alpha")[T];}catch(Y){}}return c/100;},set:function(a,d,Y){var c,b;if(d===""){b=E(a);c=(T in b)?b[T]:1;d=c;}if(typeof Y[L]=="string"){Y[L]="alpha("+T+"="+d*100+")";if(!a.currentStyle||!a.currentStyle[W]){Y.zoom=1;}}}};}}catch(U){}try{document.createElement("div").style.height="-1px";}catch(U){D.DOM.CUSTOM_STYLES.height={set:function(b,c,a){var Y=parseFloat(c);if(isNaN(Y)||Y>=0){a.height=c;}else{}}};D.DOM.CUSTOM_STYLES.width={set:function(b,c,a){var Y=parseFloat(c);if(isNaN(Y)||Y>=0){a.width=c;}else{}}};}F[I]=F[O]=N.getOffset;F.color=F.backgroundColor=N.getColor;F[G]=F[J]=F[Q]=F[V]=F[H]=N.getBorderWidth;F.marginTop=F.marginRight=F.marginBottom=F.marginLeft=N.getMargin;F.visibility=N.getVisibility;F.borderColor=F.borderTopColor=F.borderRightColor=F.borderBottomColor=F.borderLeftColor=N.getBorderColor;if(!D.config.win[C]){D.DOM[C]=N.get;}D.namespace("DOM.IE");D.DOM.IE.COMPUTED=F;D.DOM.IE.ComputedStyle=N;})(A);},"3.0.0",{requires:["dom-base"]});YUI.add("dom-screen",function(A){(function(F){var D="documentElement",O="compatMode",M="position",C="fixed",K="relative",G="left",H="top",I="BackCompat",N="medium",E="borderLeftWidth",B="borderTopWidth",P="getBoundingClientRect",J="getComputedStyle",L=/^t(?:able|d|h)$/i;F.mix(F.DOM,{winHeight:function(R){var Q=F.DOM._getWinSize(R).height;return Q;},winWidth:function(R){var Q=F.DOM._getWinSize(R).width;
+return Q;},docHeight:function(R){var Q=F.DOM._getDocSize(R).height;return Math.max(Q,F.DOM._getWinSize(R).height);},docWidth:function(R){var Q=F.DOM._getDocSize(R).width;return Math.max(Q,F.DOM._getWinSize(R).width);},docScrollX:function(Q){var R=F.DOM._getDoc(Q);return Math.max(R[D].scrollLeft,R.body.scrollLeft);},docScrollY:function(Q){var R=F.DOM._getDoc(Q);return Math.max(R[D].scrollTop,R.body.scrollTop);},getXY:function(){if(document[D][P]){return function(T){var a=null,U,R,V,Y,X,Q,S,W,Z;if(T){if(F.DOM.inDoc(T)){U=F.DOM.docScrollX(T);R=F.DOM.docScrollY(T);V=T[P]();Z=F.DOM._getDoc(T);a=[V.left,V.top];if(F.UA.ie){Y=2;X=2;W=Z[O];Q=F.DOM[J](Z[D],E);S=F.DOM[J](Z[D],B);if(F.UA.ie===6){if(W!==I){Y=0;X=0;}}if((W==I)){if(Q!==N){Y=parseInt(Q,10);}if(S!==N){X=parseInt(S,10);}}a[0]-=Y;a[1]-=X;}if((R||U)){a[0]+=U;a[1]+=R;}}else{a=F.DOM._getOffset(T);}}return a;};}else{return function(R){var T=null,Q,V,S,U;if(R){if(F.DOM.inDoc(R)){T=[R.offsetLeft,R.offsetTop];Q=R;V=((F.UA.gecko||F.UA.webkit>519)?true:false);while((Q=Q.offsetParent)){T[0]+=Q.offsetLeft;T[1]+=Q.offsetTop;if(V){T=F.DOM._calcBorders(Q,T);}}if(F.DOM.getStyle(R,M)!=C){Q=R;while((Q=Q.parentNode)){S=Q.scrollTop;U=Q.scrollLeft;if(F.UA.gecko&&(F.DOM.getStyle(Q,"overflow")!=="visible")){T=F.DOM._calcBorders(Q,T);}if(S||U){T[0]-=U;T[1]-=S;}}T[0]+=F.DOM.docScrollX(R);T[1]+=F.DOM.docScrollY(R);}else{T[0]+=F.DOM.docScrollX(R);T[1]+=F.DOM.docScrollY(R);}}else{T=F.DOM._getOffset(R);}}return T;};}}(),_getOffset:function(Q){var S,R=null;if(Q){S=F.DOM.getStyle(Q,M);R=[parseInt(F.DOM[J](Q,G),10),parseInt(F.DOM[J](Q,H),10)];if(isNaN(R[0])){R[0]=parseInt(F.DOM.getStyle(Q,G),10);if(isNaN(R[0])){R[0]=(S===K)?0:Q.offsetLeft||0;}}if(isNaN(R[1])){R[1]=parseInt(F.DOM.getStyle(Q,H),10);if(isNaN(R[1])){R[1]=(S===K)?0:Q.offsetTop||0;}}}return R;},getX:function(Q){return F.DOM.getXY(Q)[0];},getY:function(Q){return F.DOM.getXY(Q)[1];},setXY:function(R,U,X){var S=F.DOM.setStyle,W,V,Q,T;if(R&&U){W=F.DOM.getStyle(R,M);V=F.DOM._getOffset(R);if(W=="static"){W=K;S(R,M,W);}T=F.DOM.getXY(R);if(U[0]!==null){S(R,G,U[0]-T[0]+V[0]+"px");}if(U[1]!==null){S(R,H,U[1]-T[1]+V[1]+"px");}if(!X){Q=F.DOM.getXY(R);if(Q[0]!==U[0]||Q[1]!==U[1]){F.DOM.setXY(R,U,true);}}}else{}},setX:function(R,Q){return F.DOM.setXY(R,[Q,null]);},setY:function(Q,R){return F.DOM.setXY(Q,[null,R]);},_calcBorders:function(S,T){var R=parseInt(F.DOM[J](S,B),10)||0,Q=parseInt(F.DOM[J](S,E),10)||0;if(F.UA.gecko){if(L.test(S.tagName)){R=0;Q=0;}}T[0]+=Q;T[1]+=R;return T;},_getWinSize:function(T){var V=F.DOM._getDoc(),U=V.defaultView||V.parentWindow,W=V[O],S=U.innerHeight,R=U.innerWidth,Q=V[D];if(W&&!F.UA.opera){if(W!="CSS1Compat"){Q=V.body;}S=Q.clientHeight;R=Q.clientWidth;}return{height:S,width:R};},_getDocSize:function(R){var S=F.DOM._getDoc(),Q=S[D];if(S[O]!="CSS1Compat"){Q=S.body;}return{height:Q.scrollHeight,width:Q.scrollWidth};}});})(A);(function(G){var D="top",C="right",H="bottom",B="left",F=function(L,K){var N=Math.max(L[D],K[D]),O=Math.min(L[C],K[C]),I=Math.min(L[H],K[H]),J=Math.max(L[B],K[B]),M={};M[D]=N;M[C]=O;M[H]=I;M[B]=J;return M;},E=G.DOM;G.mix(E,{region:function(J){var K=E.getXY(J),I=false;if(J&&K){I=E._getRegion(K[1],K[0]+J.offsetWidth,K[1]+J.offsetHeight,K[0]);}return I;},intersect:function(K,I,M){var J=M||E.region(K),L={},O=I,N;if(O.tagName){L=E.region(O);}else{if(G.Lang.isObject(I)){L=I;}else{return false;}}N=F(L,J);return{top:N[D],right:N[C],bottom:N[H],left:N[B],area:((N[H]-N[D])*(N[C]-N[B])),yoff:((N[H]-N[D])),xoff:(N[C]-N[B]),inRegion:E.inRegion(K,I,false,M)};},inRegion:function(L,I,J,N){var M={},K=N||E.region(L),P=I,O;if(P.tagName){M=E.region(P);}else{if(G.Lang.isObject(I)){M=I;}else{return false;}}if(J){return(K[B]>=M[B]&&K[C]<=M[C]&&K[D]>=M[D]&&K[H]<=M[H]);}else{O=F(M,K);if(O[H]>=O[D]&&O[C]>=O[B]){return true;}else{return false;}}},inViewportRegion:function(J,I,K){return E.inRegion(J,E.viewportRegion(J),I,K);},_getRegion:function(K,L,I,J){var M={};M[D]=M[1]=K;M[B]=M[0]=J;M[H]=I;M[C]=L;M.width=M[C]-M[B];M.height=M[H]-M[D];return M;},viewportRegion:function(J){J=J||G.config.doc.documentElement;var I=false,L,K;if(J){L=E.docScrollX(J);K=E.docScrollY(J);I=E._getRegion(K,E.winWidth(J)+L,K+E.winHeight(J),L);}return I;}});})(A);},"3.0.0",{requires:["dom-base","dom-style"]});YUI.add("selector-native",function(A){(function(G){G.namespace("Selector");var E="compareDocumentPosition",F="ownerDocument",D="yui-tmp-",C=0;var B={_foundCache:[],useNative:true,_compare:("sourceIndex" in document.documentElement)?function(K,J){var I=K.sourceIndex,H=J.sourceIndex;if(I===H){return 0;}else{if(I>H){return 1;}}return -1;}:(document.documentElement[E]?function(I,H){if(I[E](H)&4){return -1;}else{return 1;}}:function(L,K){var J,H,I;if(L&&K){J=L[F].createRange();J.setStart(L,0);H=K[F].createRange();H.setStart(K,0);I=J.compareBoundaryPoints(1,H);}return I;}),_sort:function(H){if(H){H=G.Array(H,0,true);if(H.sort){H.sort(B._compare);}}return H;},_deDupe:function(H){var I=[],J,K;for(J=0;(K=H[J++]);){if(!K._found){I[I.length]=K;K._found=true;}}for(J=0;(K=I[J++]);){K._found=null;K.removeAttribute("_found");}return I;},query:function(I,P,Q,H){P=P||G.config.doc;var M=[],J=(G.Selector.useNative&&document.querySelector&&!H),L=[[I,P]],N,R,K,O=(J)?G.Selector._nativeQuery:G.Selector._bruteQuery;if(I&&O){if(!H&&(!J||P.tagName)){L=B._splitQueries(I,P);}for(K=0;(N=L[K++]);){R=O(N[0],N[1],Q);if(!Q){R=G.Array(R,0,true);}if(R){M=M.concat(R);}}if(L.length>1){M=B._sort(B._deDupe(M));}}return(Q)?(M[0]||null):M;},_splitQueries:function(J,M){var I=J.split(","),K=[],N="",L,H;if(M){if(M.tagName){M.id=M.id||G.guid();N="#"+M.id+" ";}for(L=0,H=I.length;L":{axis:"parentNode",direct:true},"+":{axis:"previousSibling",direct:true}},_parsers:[{name:E,re:/^\[([a-z]+\w*)+([~\|\^\$\*!=]=?)?['"]?([^\]]*?)['"]?\]/i,fn:function(K,L){var J=K[2]||"",I=G.Selector.operators,M;if((K[1]==="id"&&J==="=")||(K[1]==="className"&&document.getElementsByClassName&&(J==="~="||J==="="))){L.prefilter=K[1];L[K[1]]=K[3];}if(J in I){M=I[J];if(typeof M==="string"){M=G.Selector._getRegExp(M.replace("{val}",K[3]));}K[2]=M;}if(!L.last||L.prefilter!==K[1]){return K.slice(1);}}},{name:D,re:/^((?:-?[_a-z]+[\w-]*)|\*)/i,fn:function(J,K){var I=J[1].toUpperCase();K.tagName=I;if(I!=="*"&&(!K.last||K.prefilter)){return[D,"=",I];}if(!K.prefilter){K.prefilter="tagName";}}},{name:A,re:/^\s*([>+~]|\s)\s*/,fn:function(I,J){}},{name:F,re:/^:([\-\w]+)(?:\(['"]?(.+)['"]?\))*/i,fn:function(I,J){var K=C[F][I[1]];if(K){return[I[2],K];}else{return false;}}}],_getToken:function(I){return{tagName:null,id:null,className:null,attributes:{},combinator:null,tests:[]};},_tokenize:function(K){K=K||"";K=C._replaceShorthand(G.Lang.trim(K));var J=C._getToken(),P=K,O=[],Q=false,M,N,L,I;outer:do{Q=false;for(L=0;(I=C._parsers[L++]);){if((M=I.re.exec(K))){if(I!==A){J.selector=K;}K=K.replace(M[0],"");if(!K.length){J.last=true;}if(C._attrFilters[M[1]]){M[1]=C._attrFilters[M[1]];}N=I.fn(M,J);if(N===false){Q=false;break outer;}else{if(N){J.tests.push(N);}}if(!K.length||I.name===A){O.push(J);J=C._getToken(J);if(I.name===A){J.combinator=G.Selector.combinators[M[1]];}}Q=true;}}}while(Q&&K.length);if(!Q||K.length){O=[];}return O;},_replaceShorthand:function(J){var K=C.shorthand,L=J.match(C._re.attr),O=J.match(C._re.pseudos),N,M,I;if(O){J=J.replace(C._re.pseudos,"!!REPLACED_PSEUDO!!");}if(L){J=J.replace(C._re.attr,"!!REPLACED_ATTRIBUTE!!");}for(N in K){if(K.hasOwnProperty(N)){J=J.replace(C._getRegExp(N,"gi"),K[N]);}}if(L){for(M=0,I=L.length;M 519) ? true : false);
+
+ // TODO: worth refactoring for TOP/LEFT only?
+ while ((parentNode = parentNode.offsetParent)) {
+ xy[0] += parentNode.offsetLeft;
+ xy[1] += parentNode.offsetTop;
+ if (bCheck) {
+ xy = Y.DOM._calcBorders(parentNode, xy);
+ }
+ }
+
+ // account for any scrolled ancestors
+ if (Y.DOM.getStyle(node, POSITION) != FIXED) {
+ parentNode = node;
+
+ while ((parentNode = parentNode.parentNode)) {
+ scrollTop = parentNode.scrollTop;
+ scrollLeft = parentNode.scrollLeft;
+
+ //Firefox does something funky with borders when overflow is not visible.
+ if (Y.UA.gecko && (Y.DOM.getStyle(parentNode, 'overflow') !== 'visible')) {
+ xy = Y.DOM._calcBorders(parentNode, xy);
+ }
+
+
+ if (scrollTop || scrollLeft) {
+ xy[0] -= scrollLeft;
+ xy[1] -= scrollTop;
+ }
+ }
+ xy[0] += Y.DOM.docScrollX(node);
+ xy[1] += Y.DOM.docScrollY(node);
+
+ } else {
+ //Fix FIXED position -- add scrollbars
+ xy[0] += Y.DOM.docScrollX(node);
+ xy[1] += Y.DOM.docScrollY(node);
+ }
+ } else {
+ xy = Y.DOM._getOffset(node);
+ }
+ }
+
+ return xy;
+ };
+ }
+ }(),// NOTE: Executing for loadtime branching
+
+ _getOffset: function(node) {
+ var pos,
+ xy = null;
+
+ if (node) {
+ pos = Y.DOM.getStyle(node, POSITION);
+ xy = [
+ parseInt(Y.DOM[GET_COMPUTED_STYLE](node, LEFT), 10),
+ parseInt(Y.DOM[GET_COMPUTED_STYLE](node, TOP), 10)
+ ];
+
+ if ( isNaN(xy[0]) ) { // in case of 'auto'
+ xy[0] = parseInt(Y.DOM.getStyle(node, LEFT), 10); // try inline
+ if ( isNaN(xy[0]) ) { // default to offset value
+ xy[0] = (pos === RELATIVE) ? 0 : node.offsetLeft || 0;
+ }
+ }
+
+ if ( isNaN(xy[1]) ) { // in case of 'auto'
+ xy[1] = parseInt(Y.DOM.getStyle(node, TOP), 10); // try inline
+ if ( isNaN(xy[1]) ) { // default to offset value
+ xy[1] = (pos === RELATIVE) ? 0 : node.offsetTop || 0;
+ }
+ }
+ }
+
+ return xy;
+
+ },
+
+ /**
+ * Gets the current X position of an element based on page coordinates.
+ * Element must be part of the DOM tree to have page coordinates
+ * (display:none or elements not appended return false).
+ * @method getX
+ * @param element The target element
+ * @return {Int} The X position of the element
+ */
+
+ getX: function(node) {
+ return Y.DOM.getXY(node)[0];
+ },
+
+ /**
+ * Gets the current Y position of an element based on page coordinates.
+ * Element must be part of the DOM tree to have page coordinates
+ * (display:none or elements not appended return false).
+ * @method getY
+ * @param element The target element
+ * @return {Int} The Y position of the element
+ */
+
+ getY: function(node) {
+ return Y.DOM.getXY(node)[1];
+ },
+
+ /**
+ * Set the position of an html element in page coordinates.
+ * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+ * @method setXY
+ * @param element The target element
+ * @param {Array} xy Contains X & Y values for new position (coordinates are page-based)
+ * @param {Boolean} noRetry By default we try and set the position a second time if the first fails
+ */
+ setXY: function(node, xy, noRetry) {
+ var setStyle = Y.DOM.setStyle,
+ pos,
+ delta,
+ newXY,
+ currentXY;
+
+ if (node && xy) {
+ pos = Y.DOM.getStyle(node, POSITION);
+
+ delta = Y.DOM._getOffset(node);
+
+ if (pos == 'static') { // default to relative
+ pos = RELATIVE;
+ setStyle(node, POSITION, pos);
+ }
+
+ currentXY = Y.DOM.getXY(node);
+
+ if (xy[0] !== null) {
+ setStyle(node, LEFT, xy[0] - currentXY[0] + delta[0] + 'px');
+ }
+
+ if (xy[1] !== null) {
+ setStyle(node, TOP, xy[1] - currentXY[1] + delta[1] + 'px');
+ }
+
+ if (!noRetry) {
+ newXY = Y.DOM.getXY(node);
+ if (newXY[0] !== xy[0] || newXY[1] !== xy[1]) {
+ Y.DOM.setXY(node, xy, true);
+ }
+ }
+
+ Y.log('setXY setting position to ' + xy, 'info', 'dom-screen');
+ } else {
+ Y.log('setXY failed to set ' + node + ' to ' + xy, 'info', 'dom-screen');
+ }
+ },
+
+ /**
+ * Set the X position of an html element in page coordinates, regardless of how the element is positioned.
+ * The element(s) must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+ * @method setX
+ * @param element The target element
+ * @param {Int} x The X values for new position (coordinates are page-based)
+ */
+ setX: function(node, x) {
+ return Y.DOM.setXY(node, [x, null]);
+ },
+
+ /**
+ * Set the Y position of an html element in page coordinates, regardless of how the element is positioned.
+ * The element(s) must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+ * @method setY
+ * @param element The target element
+ * @param {Int} y The Y values for new position (coordinates are page-based)
+ */
+ setY: function(node, y) {
+ return Y.DOM.setXY(node, [null, y]);
+ },
+
+ _calcBorders: function(node, xy2) {
+ var t = parseInt(Y.DOM[GET_COMPUTED_STYLE](node, BORDER_TOP_WIDTH), 10) || 0,
+ l = parseInt(Y.DOM[GET_COMPUTED_STYLE](node, BORDER_LEFT_WIDTH), 10) || 0;
+ if (Y.UA.gecko) {
+ if (RE_TABLE.test(node.tagName)) {
+ t = 0;
+ l = 0;
+ }
+ }
+ xy2[0] += l;
+ xy2[1] += t;
+ return xy2;
+ },
+
+ _getWinSize: function(node) {
+ var doc = Y.DOM._getDoc(),
+ win = doc.defaultView || doc.parentWindow,
+ mode = doc[COMPAT_MODE],
+ h = win.innerHeight,
+ w = win.innerWidth,
+ root = doc[DOCUMENT_ELEMENT];
+
+ if ( mode && !Y.UA.opera ) { // IE, Gecko
+ if (mode != 'CSS1Compat') { // Quirks
+ root = doc.body;
+ }
+ h = root.clientHeight;
+ w = root.clientWidth;
+ }
+ return { height: h, width: w };
+ },
+
+ _getDocSize: function(node) {
+ var doc = Y.DOM._getDoc(),
+ root = doc[DOCUMENT_ELEMENT];
+
+ if (doc[COMPAT_MODE] != 'CSS1Compat') {
+ root = doc.body;
+ }
+
+ return { height: root.scrollHeight, width: root.scrollWidth };
+ }
+});
+})(Y);
+(function(Y) {
+var TOP = 'top',
+ RIGHT = 'right',
+ BOTTOM = 'bottom',
+ LEFT = 'left',
+
+ getOffsets = function(r1, r2) {
+ var t = Math.max(r1[TOP], r2[TOP]),
+ r = Math.min(r1[RIGHT], r2[RIGHT]),
+ b = Math.min(r1[BOTTOM], r2[BOTTOM]),
+ l = Math.max(r1[LEFT], r2[LEFT]),
+ ret = {};
+
+ ret[TOP] = t;
+ ret[RIGHT] = r;
+ ret[BOTTOM] = b;
+ ret[LEFT] = l;
+ return ret;
+ },
+
+ DOM = Y.DOM;
+
+Y.mix(DOM, {
+ /**
+ * Returns an Object literal containing the following about this element: (top, right, bottom, left)
+ * @method region
+ * @param {HTMLElement} element The DOM element.
+ @return {Object} Object literal containing the following about this element: (top, right, bottom, left)
+ */
+ region: function(node) {
+ var xy = DOM.getXY(node),
+ ret = false;
+
+ if (node && xy) {
+ ret = DOM._getRegion(
+ xy[1], // top
+ xy[0] + node.offsetWidth, // right
+ xy[1] + node.offsetHeight, // bottom
+ xy[0] // left
+ );
+ }
+
+ return ret;
+ },
+
+ /**
+ * Find the intersect information for the passes nodes.
+ * @method intersect
+ * @param {HTMLElement} element The first element
+ * @param {HTMLElement | Object} element2 The element or region to check the interect with
+ * @param {Object} altRegion An object literal containing the region for the first element if we already have the data (for performance i.e. DragDrop)
+ @return {Object} Object literal containing the following intersection data: (top, right, bottom, left, area, yoff, xoff, inRegion)
+ */
+ intersect: function(node, node2, altRegion) {
+ var r = altRegion || DOM.region(node), region = {},
+ n = node2,
+ off;
+
+ if (n.tagName) {
+ region = DOM.region(n);
+ } else if (Y.Lang.isObject(node2)) {
+ region = node2;
+ } else {
+ return false;
+ }
+
+ off = getOffsets(region, r);
+ return {
+ top: off[TOP],
+ right: off[RIGHT],
+ bottom: off[BOTTOM],
+ left: off[LEFT],
+ area: ((off[BOTTOM] - off[TOP]) * (off[RIGHT] - off[LEFT])),
+ yoff: ((off[BOTTOM] - off[TOP])),
+ xoff: (off[RIGHT] - off[LEFT]),
+ inRegion: DOM.inRegion(node, node2, false, altRegion)
+ };
+
+ },
+ /**
+ * Check if any part of this node is in the passed region
+ * @method inRegion
+ * @param {Object} node2 The node to get the region from or an Object literal of the region
+ * $param {Boolean} all Should all of the node be inside the region
+ * @param {Object} altRegion An object literal containing the region for this node if we already have the data (for performance i.e. DragDrop)
+ * @return {Boolean} True if in region, false if not.
+ */
+ inRegion: function(node, node2, all, altRegion) {
+ var region = {},
+ r = altRegion || DOM.region(node),
+ n = node2,
+ off;
+
+ if (n.tagName) {
+ region = DOM.region(n);
+ } else if (Y.Lang.isObject(node2)) {
+ region = node2;
+ } else {
+ return false;
+ }
+
+ if (all) {
+ return (
+ r[LEFT] >= region[LEFT] &&
+ r[RIGHT] <= region[RIGHT] &&
+ r[TOP] >= region[TOP] &&
+ r[BOTTOM] <= region[BOTTOM] );
+ } else {
+ off = getOffsets(region, r);
+ if (off[BOTTOM] >= off[TOP] && off[RIGHT] >= off[LEFT]) {
+ return true;
+ } else {
+ return false;
+ }
+
+ }
+ },
+
+ /**
+ * Check if any part of this element is in the viewport
+ * @method inViewportRegion
+ * @param {HTMLElement} element The DOM element.
+ * @param {Boolean} all Should all of the node be inside the region
+ * @param {Object} altRegion An object literal containing the region for this node if we already have the data (for performance i.e. DragDrop)
+ * @return {Boolean} True if in region, false if not.
+ */
+ inViewportRegion: function(node, all, altRegion) {
+ return DOM.inRegion(node, DOM.viewportRegion(node), all, altRegion);
+
+ },
+
+ _getRegion: function(t, r, b, l) {
+ var region = {};
+
+ region[TOP] = region[1] = t;
+ region[LEFT] = region[0] = l;
+ region[BOTTOM] = b;
+ region[RIGHT] = r;
+ region.width = region[RIGHT] - region[LEFT];
+ region.height = region[BOTTOM] - region[TOP];
+
+ return region;
+ },
+
+ /**
+ * Returns an Object literal containing the following about the visible region of viewport: (top, right, bottom, left)
+ * @method viewportRegion
+ @return {Object} Object literal containing the following about the visible region of the viewport: (top, right, bottom, left)
+ */
+ viewportRegion: function(node) {
+ node = node || Y.config.doc.documentElement;
+ var ret = false,
+ scrollX,
+ scrollY;
+
+ if (node) {
+ scrollX = DOM.docScrollX(node);
+ scrollY = DOM.docScrollY(node);
+
+ ret = DOM._getRegion(scrollY, // top
+ DOM.winWidth(node) + scrollX, // right
+ scrollY + DOM.winHeight(node), // bottom
+ scrollX); // left
+ }
+
+ return ret;
+ }
+});
+})(Y);
+
+
+}, '3.0.0' ,{requires:['dom-base', 'dom-style']});
diff --git a/lib/yui/3.0.0/dom/dom-screen-min.js b/lib/yui/3.0.0/dom/dom-screen-min.js
new file mode 100644
index 0000000000..7e8786c917
--- /dev/null
+++ b/lib/yui/3.0.0/dom/dom-screen-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("dom-screen",function(A){(function(F){var D="documentElement",O="compatMode",M="position",C="fixed",K="relative",G="left",H="top",I="BackCompat",N="medium",E="borderLeftWidth",B="borderTopWidth",P="getBoundingClientRect",J="getComputedStyle",L=/^t(?:able|d|h)$/i;F.mix(F.DOM,{winHeight:function(R){var Q=F.DOM._getWinSize(R).height;return Q;},winWidth:function(R){var Q=F.DOM._getWinSize(R).width;return Q;},docHeight:function(R){var Q=F.DOM._getDocSize(R).height;return Math.max(Q,F.DOM._getWinSize(R).height);},docWidth:function(R){var Q=F.DOM._getDocSize(R).width;return Math.max(Q,F.DOM._getWinSize(R).width);},docScrollX:function(Q){var R=F.DOM._getDoc(Q);return Math.max(R[D].scrollLeft,R.body.scrollLeft);},docScrollY:function(Q){var R=F.DOM._getDoc(Q);return Math.max(R[D].scrollTop,R.body.scrollTop);},getXY:function(){if(document[D][P]){return function(T){var a=null,U,R,V,Y,X,Q,S,W,Z;if(T){if(F.DOM.inDoc(T)){U=F.DOM.docScrollX(T);R=F.DOM.docScrollY(T);V=T[P]();Z=F.DOM._getDoc(T);a=[V.left,V.top];if(F.UA.ie){Y=2;X=2;W=Z[O];Q=F.DOM[J](Z[D],E);S=F.DOM[J](Z[D],B);if(F.UA.ie===6){if(W!==I){Y=0;X=0;}}if((W==I)){if(Q!==N){Y=parseInt(Q,10);}if(S!==N){X=parseInt(S,10);}}a[0]-=Y;a[1]-=X;}if((R||U)){a[0]+=U;a[1]+=R;}}else{a=F.DOM._getOffset(T);}}return a;};}else{return function(R){var T=null,Q,V,S,U;if(R){if(F.DOM.inDoc(R)){T=[R.offsetLeft,R.offsetTop];Q=R;V=((F.UA.gecko||F.UA.webkit>519)?true:false);while((Q=Q.offsetParent)){T[0]+=Q.offsetLeft;T[1]+=Q.offsetTop;if(V){T=F.DOM._calcBorders(Q,T);}}if(F.DOM.getStyle(R,M)!=C){Q=R;while((Q=Q.parentNode)){S=Q.scrollTop;U=Q.scrollLeft;if(F.UA.gecko&&(F.DOM.getStyle(Q,"overflow")!=="visible")){T=F.DOM._calcBorders(Q,T);}if(S||U){T[0]-=U;T[1]-=S;}}T[0]+=F.DOM.docScrollX(R);T[1]+=F.DOM.docScrollY(R);}else{T[0]+=F.DOM.docScrollX(R);T[1]+=F.DOM.docScrollY(R);}}else{T=F.DOM._getOffset(R);}}return T;};}}(),_getOffset:function(Q){var S,R=null;if(Q){S=F.DOM.getStyle(Q,M);R=[parseInt(F.DOM[J](Q,G),10),parseInt(F.DOM[J](Q,H),10)];if(isNaN(R[0])){R[0]=parseInt(F.DOM.getStyle(Q,G),10);if(isNaN(R[0])){R[0]=(S===K)?0:Q.offsetLeft||0;}}if(isNaN(R[1])){R[1]=parseInt(F.DOM.getStyle(Q,H),10);if(isNaN(R[1])){R[1]=(S===K)?0:Q.offsetTop||0;}}}return R;},getX:function(Q){return F.DOM.getXY(Q)[0];},getY:function(Q){return F.DOM.getXY(Q)[1];},setXY:function(R,U,X){var S=F.DOM.setStyle,W,V,Q,T;if(R&&U){W=F.DOM.getStyle(R,M);V=F.DOM._getOffset(R);if(W=="static"){W=K;S(R,M,W);}T=F.DOM.getXY(R);if(U[0]!==null){S(R,G,U[0]-T[0]+V[0]+"px");}if(U[1]!==null){S(R,H,U[1]-T[1]+V[1]+"px");}if(!X){Q=F.DOM.getXY(R);if(Q[0]!==U[0]||Q[1]!==U[1]){F.DOM.setXY(R,U,true);}}}else{}},setX:function(R,Q){return F.DOM.setXY(R,[Q,null]);},setY:function(Q,R){return F.DOM.setXY(Q,[null,R]);},_calcBorders:function(S,T){var R=parseInt(F.DOM[J](S,B),10)||0,Q=parseInt(F.DOM[J](S,E),10)||0;if(F.UA.gecko){if(L.test(S.tagName)){R=0;Q=0;}}T[0]+=Q;T[1]+=R;return T;},_getWinSize:function(T){var V=F.DOM._getDoc(),U=V.defaultView||V.parentWindow,W=V[O],S=U.innerHeight,R=U.innerWidth,Q=V[D];if(W&&!F.UA.opera){if(W!="CSS1Compat"){Q=V.body;}S=Q.clientHeight;R=Q.clientWidth;}return{height:S,width:R};},_getDocSize:function(R){var S=F.DOM._getDoc(),Q=S[D];if(S[O]!="CSS1Compat"){Q=S.body;}return{height:Q.scrollHeight,width:Q.scrollWidth};}});})(A);(function(G){var D="top",C="right",H="bottom",B="left",F=function(L,K){var N=Math.max(L[D],K[D]),O=Math.min(L[C],K[C]),I=Math.min(L[H],K[H]),J=Math.max(L[B],K[B]),M={};M[D]=N;M[C]=O;M[H]=I;M[B]=J;return M;},E=G.DOM;G.mix(E,{region:function(J){var K=E.getXY(J),I=false;if(J&&K){I=E._getRegion(K[1],K[0]+J.offsetWidth,K[1]+J.offsetHeight,K[0]);}return I;},intersect:function(K,I,M){var J=M||E.region(K),L={},O=I,N;if(O.tagName){L=E.region(O);}else{if(G.Lang.isObject(I)){L=I;}else{return false;}}N=F(L,J);return{top:N[D],right:N[C],bottom:N[H],left:N[B],area:((N[H]-N[D])*(N[C]-N[B])),yoff:((N[H]-N[D])),xoff:(N[C]-N[B]),inRegion:E.inRegion(K,I,false,M)};},inRegion:function(L,I,J,N){var M={},K=N||E.region(L),P=I,O;if(P.tagName){M=E.region(P);}else{if(G.Lang.isObject(I)){M=I;}else{return false;}}if(J){return(K[B]>=M[B]&&K[C]<=M[C]&&K[D]>=M[D]&&K[H]<=M[H]);}else{O=F(M,K);if(O[H]>=O[D]&&O[C]>=O[B]){return true;}else{return false;}}},inViewportRegion:function(J,I,K){return E.inRegion(J,E.viewportRegion(J),I,K);},_getRegion:function(K,L,I,J){var M={};M[D]=M[1]=K;M[B]=M[0]=J;M[H]=I;M[C]=L;M.width=M[C]-M[B];M.height=M[H]-M[D];return M;},viewportRegion:function(J){J=J||G.config.doc.documentElement;var I=false,L,K;if(J){L=E.docScrollX(J);K=E.docScrollY(J);I=E._getRegion(K,E.winWidth(J)+L,K+E.winHeight(J),L);}return I;}});})(A);},"3.0.0",{requires:["dom-base","dom-style"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/dom/dom-screen.js b/lib/yui/3.0.0/dom/dom-screen.js
new file mode 100644
index 0000000000..de02ad8214
--- /dev/null
+++ b/lib/yui/3.0.0/dom/dom-screen.js
@@ -0,0 +1,567 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dom-screen', function(Y) {
+
+(function(Y) {
+
+/**
+ * Adds position and region management functionality to DOM.
+ * @module dom
+ * @submodule dom-screen
+ * @for DOM
+ */
+
+var DOCUMENT_ELEMENT = 'documentElement',
+ COMPAT_MODE = 'compatMode',
+ POSITION = 'position',
+ FIXED = 'fixed',
+ RELATIVE = 'relative',
+ LEFT = 'left',
+ TOP = 'top',
+ _BACK_COMPAT = 'BackCompat',
+ MEDIUM = 'medium',
+ BORDER_LEFT_WIDTH = 'borderLeftWidth',
+ BORDER_TOP_WIDTH = 'borderTopWidth',
+ GET_BOUNDING_CLIENT_RECT = 'getBoundingClientRect',
+ GET_COMPUTED_STYLE = 'getComputedStyle',
+
+ // TODO: how about thead/tbody/tfoot/tr?
+ // TODO: does caption matter?
+ RE_TABLE = /^t(?:able|d|h)$/i;
+
+Y.mix(Y.DOM, {
+ /**
+ * Returns the inner height of the viewport (exludes scrollbar).
+ * @method winHeight
+ * @return {Number} The current height of the viewport.
+ */
+ winHeight: function(node) {
+ var h = Y.DOM._getWinSize(node).height;
+ return h;
+ },
+
+ /**
+ * Returns the inner width of the viewport (exludes scrollbar).
+ * @method winWidth
+ * @return {Number} The current width of the viewport.
+ */
+ winWidth: function(node) {
+ var w = Y.DOM._getWinSize(node).width;
+ return w;
+ },
+
+ /**
+ * Document height
+ * @method docHeight
+ * @return {Number} The current height of the document.
+ */
+ docHeight: function(node) {
+ var h = Y.DOM._getDocSize(node).height;
+ return Math.max(h, Y.DOM._getWinSize(node).height);
+ },
+
+ /**
+ * Document width
+ * @method docWidth
+ * @return {Number} The current width of the document.
+ */
+ docWidth: function(node) {
+ var w = Y.DOM._getDocSize(node).width;
+ return Math.max(w, Y.DOM._getWinSize(node).width);
+ },
+
+ /**
+ * Amount page has been scroll horizontally
+ * @method docScrollX
+ * @return {Number} The current amount the screen is scrolled horizontally.
+ */
+ docScrollX: function(node) {
+ var doc = Y.DOM._getDoc(node);
+ return Math.max(doc[DOCUMENT_ELEMENT].scrollLeft, doc.body.scrollLeft);
+ },
+
+ /**
+ * Amount page has been scroll vertically
+ * @method docScrollY
+ * @return {Number} The current amount the screen is scrolled vertically.
+ */
+ docScrollY: function(node) {
+ var doc = Y.DOM._getDoc(node);
+ return Math.max(doc[DOCUMENT_ELEMENT].scrollTop, doc.body.scrollTop);
+ },
+
+ /**
+ * Gets the current position of an element based on page coordinates.
+ * Element must be part of the DOM tree to have page coordinates
+ * (display:none or elements not appended return false).
+ * @method getXY
+ * @param element The target element
+ * @return {Array} The XY position of the element
+
+ TODO: test inDocument/display?
+ */
+ getXY: function() {
+ if (document[DOCUMENT_ELEMENT][GET_BOUNDING_CLIENT_RECT]) {
+ return function(node) {
+ var xy = null,
+ scrollLeft,
+ scrollTop,
+ box,
+ off1, off2,
+ bLeft, bTop,
+ mode,
+ doc;
+
+ if (node) {
+ if (Y.DOM.inDoc(node)) {
+ scrollLeft = Y.DOM.docScrollX(node);
+ scrollTop = Y.DOM.docScrollY(node);
+ box = node[GET_BOUNDING_CLIENT_RECT]();
+ doc = Y.DOM._getDoc(node);
+ xy = [box.left, box.top];
+
+ if (Y.UA.ie) {
+ off1 = 2;
+ off2 = 2;
+ mode = doc[COMPAT_MODE];
+ bLeft = Y.DOM[GET_COMPUTED_STYLE](doc[DOCUMENT_ELEMENT], BORDER_LEFT_WIDTH);
+ bTop = Y.DOM[GET_COMPUTED_STYLE](doc[DOCUMENT_ELEMENT], BORDER_TOP_WIDTH);
+
+ if (Y.UA.ie === 6) {
+ if (mode !== _BACK_COMPAT) {
+ off1 = 0;
+ off2 = 0;
+ }
+ }
+
+ if ((mode == _BACK_COMPAT)) {
+ if (bLeft !== MEDIUM) {
+ off1 = parseInt(bLeft, 10);
+ }
+ if (bTop !== MEDIUM) {
+ off2 = parseInt(bTop, 10);
+ }
+ }
+
+ xy[0] -= off1;
+ xy[1] -= off2;
+
+ }
+
+ if ((scrollTop || scrollLeft)) {
+ xy[0] += scrollLeft;
+ xy[1] += scrollTop;
+ }
+ } else { // default to current offsets
+ xy = Y.DOM._getOffset(node);
+ }
+ }
+ return xy;
+ };
+ } else {
+ return function(node) { // manually calculate by crawling up offsetParents
+ //Calculate the Top and Left border sizes (assumes pixels)
+ var xy = null,
+ parentNode,
+ bCheck,
+ scrollTop,
+ scrollLeft;
+
+ if (node) {
+ if (Y.DOM.inDoc(node)) {
+ xy = [node.offsetLeft, node.offsetTop];
+ parentNode = node;
+ // TODO: refactor with !! or just falsey
+ bCheck = ((Y.UA.gecko || Y.UA.webkit > 519) ? true : false);
+
+ // TODO: worth refactoring for TOP/LEFT only?
+ while ((parentNode = parentNode.offsetParent)) {
+ xy[0] += parentNode.offsetLeft;
+ xy[1] += parentNode.offsetTop;
+ if (bCheck) {
+ xy = Y.DOM._calcBorders(parentNode, xy);
+ }
+ }
+
+ // account for any scrolled ancestors
+ if (Y.DOM.getStyle(node, POSITION) != FIXED) {
+ parentNode = node;
+
+ while ((parentNode = parentNode.parentNode)) {
+ scrollTop = parentNode.scrollTop;
+ scrollLeft = parentNode.scrollLeft;
+
+ //Firefox does something funky with borders when overflow is not visible.
+ if (Y.UA.gecko && (Y.DOM.getStyle(parentNode, 'overflow') !== 'visible')) {
+ xy = Y.DOM._calcBorders(parentNode, xy);
+ }
+
+
+ if (scrollTop || scrollLeft) {
+ xy[0] -= scrollLeft;
+ xy[1] -= scrollTop;
+ }
+ }
+ xy[0] += Y.DOM.docScrollX(node);
+ xy[1] += Y.DOM.docScrollY(node);
+
+ } else {
+ //Fix FIXED position -- add scrollbars
+ xy[0] += Y.DOM.docScrollX(node);
+ xy[1] += Y.DOM.docScrollY(node);
+ }
+ } else {
+ xy = Y.DOM._getOffset(node);
+ }
+ }
+
+ return xy;
+ };
+ }
+ }(),// NOTE: Executing for loadtime branching
+
+ _getOffset: function(node) {
+ var pos,
+ xy = null;
+
+ if (node) {
+ pos = Y.DOM.getStyle(node, POSITION);
+ xy = [
+ parseInt(Y.DOM[GET_COMPUTED_STYLE](node, LEFT), 10),
+ parseInt(Y.DOM[GET_COMPUTED_STYLE](node, TOP), 10)
+ ];
+
+ if ( isNaN(xy[0]) ) { // in case of 'auto'
+ xy[0] = parseInt(Y.DOM.getStyle(node, LEFT), 10); // try inline
+ if ( isNaN(xy[0]) ) { // default to offset value
+ xy[0] = (pos === RELATIVE) ? 0 : node.offsetLeft || 0;
+ }
+ }
+
+ if ( isNaN(xy[1]) ) { // in case of 'auto'
+ xy[1] = parseInt(Y.DOM.getStyle(node, TOP), 10); // try inline
+ if ( isNaN(xy[1]) ) { // default to offset value
+ xy[1] = (pos === RELATIVE) ? 0 : node.offsetTop || 0;
+ }
+ }
+ }
+
+ return xy;
+
+ },
+
+ /**
+ * Gets the current X position of an element based on page coordinates.
+ * Element must be part of the DOM tree to have page coordinates
+ * (display:none or elements not appended return false).
+ * @method getX
+ * @param element The target element
+ * @return {Int} The X position of the element
+ */
+
+ getX: function(node) {
+ return Y.DOM.getXY(node)[0];
+ },
+
+ /**
+ * Gets the current Y position of an element based on page coordinates.
+ * Element must be part of the DOM tree to have page coordinates
+ * (display:none or elements not appended return false).
+ * @method getY
+ * @param element The target element
+ * @return {Int} The Y position of the element
+ */
+
+ getY: function(node) {
+ return Y.DOM.getXY(node)[1];
+ },
+
+ /**
+ * Set the position of an html element in page coordinates.
+ * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+ * @method setXY
+ * @param element The target element
+ * @param {Array} xy Contains X & Y values for new position (coordinates are page-based)
+ * @param {Boolean} noRetry By default we try and set the position a second time if the first fails
+ */
+ setXY: function(node, xy, noRetry) {
+ var setStyle = Y.DOM.setStyle,
+ pos,
+ delta,
+ newXY,
+ currentXY;
+
+ if (node && xy) {
+ pos = Y.DOM.getStyle(node, POSITION);
+
+ delta = Y.DOM._getOffset(node);
+
+ if (pos == 'static') { // default to relative
+ pos = RELATIVE;
+ setStyle(node, POSITION, pos);
+ }
+
+ currentXY = Y.DOM.getXY(node);
+
+ if (xy[0] !== null) {
+ setStyle(node, LEFT, xy[0] - currentXY[0] + delta[0] + 'px');
+ }
+
+ if (xy[1] !== null) {
+ setStyle(node, TOP, xy[1] - currentXY[1] + delta[1] + 'px');
+ }
+
+ if (!noRetry) {
+ newXY = Y.DOM.getXY(node);
+ if (newXY[0] !== xy[0] || newXY[1] !== xy[1]) {
+ Y.DOM.setXY(node, xy, true);
+ }
+ }
+
+ } else {
+ }
+ },
+
+ /**
+ * Set the X position of an html element in page coordinates, regardless of how the element is positioned.
+ * The element(s) must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+ * @method setX
+ * @param element The target element
+ * @param {Int} x The X values for new position (coordinates are page-based)
+ */
+ setX: function(node, x) {
+ return Y.DOM.setXY(node, [x, null]);
+ },
+
+ /**
+ * Set the Y position of an html element in page coordinates, regardless of how the element is positioned.
+ * The element(s) must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+ * @method setY
+ * @param element The target element
+ * @param {Int} y The Y values for new position (coordinates are page-based)
+ */
+ setY: function(node, y) {
+ return Y.DOM.setXY(node, [null, y]);
+ },
+
+ _calcBorders: function(node, xy2) {
+ var t = parseInt(Y.DOM[GET_COMPUTED_STYLE](node, BORDER_TOP_WIDTH), 10) || 0,
+ l = parseInt(Y.DOM[GET_COMPUTED_STYLE](node, BORDER_LEFT_WIDTH), 10) || 0;
+ if (Y.UA.gecko) {
+ if (RE_TABLE.test(node.tagName)) {
+ t = 0;
+ l = 0;
+ }
+ }
+ xy2[0] += l;
+ xy2[1] += t;
+ return xy2;
+ },
+
+ _getWinSize: function(node) {
+ var doc = Y.DOM._getDoc(),
+ win = doc.defaultView || doc.parentWindow,
+ mode = doc[COMPAT_MODE],
+ h = win.innerHeight,
+ w = win.innerWidth,
+ root = doc[DOCUMENT_ELEMENT];
+
+ if ( mode && !Y.UA.opera ) { // IE, Gecko
+ if (mode != 'CSS1Compat') { // Quirks
+ root = doc.body;
+ }
+ h = root.clientHeight;
+ w = root.clientWidth;
+ }
+ return { height: h, width: w };
+ },
+
+ _getDocSize: function(node) {
+ var doc = Y.DOM._getDoc(),
+ root = doc[DOCUMENT_ELEMENT];
+
+ if (doc[COMPAT_MODE] != 'CSS1Compat') {
+ root = doc.body;
+ }
+
+ return { height: root.scrollHeight, width: root.scrollWidth };
+ }
+});
+})(Y);
+(function(Y) {
+var TOP = 'top',
+ RIGHT = 'right',
+ BOTTOM = 'bottom',
+ LEFT = 'left',
+
+ getOffsets = function(r1, r2) {
+ var t = Math.max(r1[TOP], r2[TOP]),
+ r = Math.min(r1[RIGHT], r2[RIGHT]),
+ b = Math.min(r1[BOTTOM], r2[BOTTOM]),
+ l = Math.max(r1[LEFT], r2[LEFT]),
+ ret = {};
+
+ ret[TOP] = t;
+ ret[RIGHT] = r;
+ ret[BOTTOM] = b;
+ ret[LEFT] = l;
+ return ret;
+ },
+
+ DOM = Y.DOM;
+
+Y.mix(DOM, {
+ /**
+ * Returns an Object literal containing the following about this element: (top, right, bottom, left)
+ * @method region
+ * @param {HTMLElement} element The DOM element.
+ @return {Object} Object literal containing the following about this element: (top, right, bottom, left)
+ */
+ region: function(node) {
+ var xy = DOM.getXY(node),
+ ret = false;
+
+ if (node && xy) {
+ ret = DOM._getRegion(
+ xy[1], // top
+ xy[0] + node.offsetWidth, // right
+ xy[1] + node.offsetHeight, // bottom
+ xy[0] // left
+ );
+ }
+
+ return ret;
+ },
+
+ /**
+ * Find the intersect information for the passes nodes.
+ * @method intersect
+ * @param {HTMLElement} element The first element
+ * @param {HTMLElement | Object} element2 The element or region to check the interect with
+ * @param {Object} altRegion An object literal containing the region for the first element if we already have the data (for performance i.e. DragDrop)
+ @return {Object} Object literal containing the following intersection data: (top, right, bottom, left, area, yoff, xoff, inRegion)
+ */
+ intersect: function(node, node2, altRegion) {
+ var r = altRegion || DOM.region(node), region = {},
+ n = node2,
+ off;
+
+ if (n.tagName) {
+ region = DOM.region(n);
+ } else if (Y.Lang.isObject(node2)) {
+ region = node2;
+ } else {
+ return false;
+ }
+
+ off = getOffsets(region, r);
+ return {
+ top: off[TOP],
+ right: off[RIGHT],
+ bottom: off[BOTTOM],
+ left: off[LEFT],
+ area: ((off[BOTTOM] - off[TOP]) * (off[RIGHT] - off[LEFT])),
+ yoff: ((off[BOTTOM] - off[TOP])),
+ xoff: (off[RIGHT] - off[LEFT]),
+ inRegion: DOM.inRegion(node, node2, false, altRegion)
+ };
+
+ },
+ /**
+ * Check if any part of this node is in the passed region
+ * @method inRegion
+ * @param {Object} node2 The node to get the region from or an Object literal of the region
+ * $param {Boolean} all Should all of the node be inside the region
+ * @param {Object} altRegion An object literal containing the region for this node if we already have the data (for performance i.e. DragDrop)
+ * @return {Boolean} True if in region, false if not.
+ */
+ inRegion: function(node, node2, all, altRegion) {
+ var region = {},
+ r = altRegion || DOM.region(node),
+ n = node2,
+ off;
+
+ if (n.tagName) {
+ region = DOM.region(n);
+ } else if (Y.Lang.isObject(node2)) {
+ region = node2;
+ } else {
+ return false;
+ }
+
+ if (all) {
+ return (
+ r[LEFT] >= region[LEFT] &&
+ r[RIGHT] <= region[RIGHT] &&
+ r[TOP] >= region[TOP] &&
+ r[BOTTOM] <= region[BOTTOM] );
+ } else {
+ off = getOffsets(region, r);
+ if (off[BOTTOM] >= off[TOP] && off[RIGHT] >= off[LEFT]) {
+ return true;
+ } else {
+ return false;
+ }
+
+ }
+ },
+
+ /**
+ * Check if any part of this element is in the viewport
+ * @method inViewportRegion
+ * @param {HTMLElement} element The DOM element.
+ * @param {Boolean} all Should all of the node be inside the region
+ * @param {Object} altRegion An object literal containing the region for this node if we already have the data (for performance i.e. DragDrop)
+ * @return {Boolean} True if in region, false if not.
+ */
+ inViewportRegion: function(node, all, altRegion) {
+ return DOM.inRegion(node, DOM.viewportRegion(node), all, altRegion);
+
+ },
+
+ _getRegion: function(t, r, b, l) {
+ var region = {};
+
+ region[TOP] = region[1] = t;
+ region[LEFT] = region[0] = l;
+ region[BOTTOM] = b;
+ region[RIGHT] = r;
+ region.width = region[RIGHT] - region[LEFT];
+ region.height = region[BOTTOM] - region[TOP];
+
+ return region;
+ },
+
+ /**
+ * Returns an Object literal containing the following about the visible region of viewport: (top, right, bottom, left)
+ * @method viewportRegion
+ @return {Object} Object literal containing the following about the visible region of the viewport: (top, right, bottom, left)
+ */
+ viewportRegion: function(node) {
+ node = node || Y.config.doc.documentElement;
+ var ret = false,
+ scrollX,
+ scrollY;
+
+ if (node) {
+ scrollX = DOM.docScrollX(node);
+ scrollY = DOM.docScrollY(node);
+
+ ret = DOM._getRegion(scrollY, // top
+ DOM.winWidth(node) + scrollX, // right
+ scrollY + DOM.winHeight(node), // bottom
+ scrollX); // left
+ }
+
+ return ret;
+ }
+});
+})(Y);
+
+
+}, '3.0.0' ,{requires:['dom-base', 'dom-style']});
diff --git a/lib/yui/3.0.0/dom/dom-style-debug.js b/lib/yui/3.0.0/dom/dom-style-debug.js
new file mode 100644
index 0000000000..638b6ddffb
--- /dev/null
+++ b/lib/yui/3.0.0/dom/dom-style-debug.js
@@ -0,0 +1,511 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dom-style', function(Y) {
+
+(function(Y) {
+/**
+ * Add style management functionality to DOM.
+ * @module dom
+ * @submodule dom-style
+ * @for DOM
+ */
+
+var DOCUMENT_ELEMENT = 'documentElement',
+ DEFAULT_VIEW = 'defaultView',
+ OWNER_DOCUMENT = 'ownerDocument',
+ STYLE = 'style',
+ FLOAT = 'float',
+ CSS_FLOAT = 'cssFloat',
+ STYLE_FLOAT = 'styleFloat',
+ TRANSPARENT = 'transparent',
+ GET_COMPUTED_STYLE = 'getComputedStyle',
+
+ DOCUMENT = Y.config.doc,
+ UNDEFINED = undefined,
+
+ re_color = /color$/i;
+
+
+Y.mix(Y.DOM, {
+ CUSTOM_STYLES: {
+ },
+
+
+ /**
+ * Sets a style property for a given element.
+ * @method setStyle
+ * @param {HTMLElement} An HTMLElement to apply the style to.
+ * @param {String} att The style property to set.
+ * @param {String|Number} val The value.
+ */
+ setStyle: function(node, att, val, style) {
+ style = style || node.style;
+ var CUSTOM_STYLES = Y.DOM.CUSTOM_STYLES;
+
+ if (style) {
+ if (val === null) {
+ val = ''; // normalize for unsetting
+ }
+ if (att in CUSTOM_STYLES) {
+ if (CUSTOM_STYLES[att].set) {
+ CUSTOM_STYLES[att].set(node, val, style);
+ return; // NOTE: return
+ } else if (typeof CUSTOM_STYLES[att] === 'string') {
+ att = CUSTOM_STYLES[att];
+ }
+ }
+ style[att] = val;
+ }
+ },
+
+ /**
+ * Returns the current style value for the given property.
+ * @method getStyle
+ * @param {HTMLElement} An HTMLElement to get the style from.
+ * @param {String} att The style property to get.
+ */
+ getStyle: function(node, att) {
+ var style = node[STYLE],
+ CUSTOM_STYLES = Y.DOM.CUSTOM_STYLES,
+ val = '';
+
+ if (style) {
+ if (att in CUSTOM_STYLES) {
+ if (CUSTOM_STYLES[att].get) {
+ return CUSTOM_STYLES[att].get(node, att, style); // NOTE: return
+ } else if (typeof CUSTOM_STYLES[att] === 'string') {
+ att = CUSTOM_STYLES[att];
+ }
+ }
+ val = style[att];
+ if (val === '') { // TODO: is empty string sufficient?
+ val = Y.DOM[GET_COMPUTED_STYLE](node, att);
+ }
+ }
+
+ return val;
+ },
+
+ /**
+ * Sets multiple style properties.
+ * @method setStyles
+ * @param {HTMLElement} node An HTMLElement to apply the styles to.
+ * @param {Object} hash An object literal of property:value pairs.
+ */
+ setStyles: function(node, hash) {
+ var style = node.style;
+ Y.each(hash, function(v, n) {
+ Y.DOM.setStyle(node, n, v, style);
+ }, Y.DOM);
+ },
+
+ /**
+ * Returns the computed style for the given node.
+ * @method getComputedStyle
+ * @param {HTMLElement} An HTMLElement to get the style from.
+ * @param {String} att The style property to get.
+ * @return {String} The computed value of the style property.
+ */
+ getComputedStyle: function(node, att) {
+ var val = '',
+ doc = node[OWNER_DOCUMENT];
+
+ if (node[STYLE]) {
+ val = doc[DEFAULT_VIEW][GET_COMPUTED_STYLE](node, null)[att];
+ }
+ return val;
+ }
+});
+
+// normalize reserved word float alternatives ("cssFloat" or "styleFloat")
+if (DOCUMENT[DOCUMENT_ELEMENT][STYLE][CSS_FLOAT] !== UNDEFINED) {
+ Y.DOM.CUSTOM_STYLES[FLOAT] = CSS_FLOAT;
+} else if (DOCUMENT[DOCUMENT_ELEMENT][STYLE][STYLE_FLOAT] !== UNDEFINED) {
+ Y.DOM.CUSTOM_STYLES[FLOAT] = STYLE_FLOAT;
+}
+
+// fix opera computedStyle default color unit (convert to rgb)
+if (Y.UA.opera) {
+ Y.DOM[GET_COMPUTED_STYLE] = function(node, att) {
+ var view = node[OWNER_DOCUMENT][DEFAULT_VIEW],
+ val = view[GET_COMPUTED_STYLE](node, '')[att];
+
+ if (re_color.test(att)) {
+ val = Y.Color.toRGB(val);
+ }
+
+ return val;
+ };
+
+}
+
+// safari converts transparent to rgba(), others use "transparent"
+if (Y.UA.webkit) {
+ Y.DOM[GET_COMPUTED_STYLE] = function(node, att) {
+ var view = node[OWNER_DOCUMENT][DEFAULT_VIEW],
+ val = view[GET_COMPUTED_STYLE](node, '')[att];
+
+ if (val === 'rgba(0, 0, 0, 0)') {
+ val = TRANSPARENT;
+ }
+
+ return val;
+ };
+
+}
+})(Y);
+(function(Y) {
+var PARSE_INT = parseInt,
+ RE = RegExp;
+
+Y.Color = {
+ KEYWORDS: {
+ black: '000',
+ silver: 'c0c0c0',
+ gray: '808080',
+ white: 'fff',
+ maroon: '800000',
+ red: 'f00',
+ purple: '800080',
+ fuchsia: 'f0f',
+ green: '008000',
+ lime: '0f0',
+ olive: '808000',
+ yellow: 'ff0',
+ navy: '000080',
+ blue: '00f',
+ teal: '008080',
+ aqua: '0ff'
+ },
+
+ re_RGB: /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i,
+ re_hex: /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i,
+ re_hex3: /([0-9A-F])/gi,
+
+ toRGB: function(val) {
+ if (!Y.Color.re_RGB.test(val)) {
+ val = Y.Color.toHex(val);
+ }
+
+ if(Y.Color.re_hex.exec(val)) {
+ val = 'rgb(' + [
+ PARSE_INT(RE.$1, 16),
+ PARSE_INT(RE.$2, 16),
+ PARSE_INT(RE.$3, 16)
+ ].join(', ') + ')';
+ }
+ return val;
+ },
+
+ toHex: function(val) {
+ val = Y.Color.KEYWORDS[val] || val;
+ if (Y.Color.re_RGB.exec(val)) {
+ val = [
+ Number(RE.$1).toString(16),
+ Number(RE.$2).toString(16),
+ Number(RE.$3).toString(16)
+ ];
+
+ for (var i = 0; i < val.length; i++) {
+ if (val[i].length < 2) {
+ val[i] = val[i].replace(Y.Color.re_hex3, '$1$1');
+ }
+ }
+
+ val = '#' + val.join('');
+ }
+
+ if (val.length < 6) {
+ val = val.replace(Y.Color.re_hex3, '$1$1');
+ }
+
+ if (val !== 'transparent' && val.indexOf('#') < 0) {
+ val = '#' + val;
+ }
+
+ return val.toLowerCase();
+ }
+};
+})(Y);
+
+(function(Y) {
+var HAS_LAYOUT = 'hasLayout',
+ PX = 'px',
+ FILTER = 'filter',
+ FILTERS = 'filters',
+ OPACITY = 'opacity',
+ AUTO = 'auto',
+
+ BORDER_WIDTH = 'borderWidth',
+ BORDER_TOP_WIDTH = 'borderTopWidth',
+ BORDER_RIGHT_WIDTH = 'borderRightWidth',
+ BORDER_BOTTOM_WIDTH = 'borderBottomWidth',
+ BORDER_LEFT_WIDTH = 'borderLeftWidth',
+ WIDTH = 'width',
+ HEIGHT = 'height',
+ TRANSPARENT = 'transparent',
+ VISIBLE = 'visible',
+ GET_COMPUTED_STYLE = 'getComputedStyle',
+ UNDEFINED = undefined,
+ documentElement = document.documentElement,
+
+ // TODO: unit-less lineHeight (e.g. 1.22)
+ re_unit = /^(\d[.\d]*)+(em|ex|px|gd|rem|vw|vh|vm|ch|mm|cm|in|pt|pc|deg|rad|ms|s|hz|khz|%){1}?/i,
+
+ _getStyleObj = function(node) {
+ return node.currentStyle || node.style;
+ },
+
+ ComputedStyle = {
+ CUSTOM_STYLES: {},
+
+ get: function(el, property) {
+ var value = '',
+ current;
+
+ if (el) {
+ current = _getStyleObj(el)[property];
+
+ if (property === OPACITY && Y.DOM.CUSTOM_STYLES[OPACITY]) {
+ value = Y.DOM.CUSTOM_STYLES[OPACITY].get(el);
+ } else if (!current || (current.indexOf && current.indexOf(PX) > -1)) { // no need to convert
+ value = current;
+ } else if (Y.DOM.IE.COMPUTED[property]) { // use compute function
+ value = Y.DOM.IE.COMPUTED[property](el, property);
+ } else if (re_unit.test(current)) { // convert to pixel
+ value = ComputedStyle.getPixel(el, property) + PX;
+ } else {
+ value = current;
+ }
+ }
+
+ return value;
+ },
+
+ sizeOffsets: {
+ width: ['Left', 'Right'],
+ height: ['Top', 'Bottom'],
+ top: ['Top'],
+ bottom: ['Bottom']
+ },
+
+ getOffset: function(el, prop) {
+ var current = _getStyleObj(el)[prop], // value of "width", "top", etc.
+ capped = prop.charAt(0).toUpperCase() + prop.substr(1), // "Width", "Top", etc.
+ offset = 'offset' + capped, // "offsetWidth", "offsetTop", etc.
+ pixel = 'pixel' + capped, // "pixelWidth", "pixelTop", etc.
+ sizeOffsets = ComputedStyle.sizeOffsets[prop],
+ value = '';
+
+ // IE pixelWidth incorrect for percent
+ // manually compute by subtracting padding and border from offset size
+ // NOTE: clientWidth/Height (size minus border) is 0 when current === AUTO so offsetHeight is used
+ // reverting to auto from auto causes position stacking issues (old impl)
+ if (current === AUTO || current.indexOf('%') > -1) {
+ value = el['offset' + capped];
+
+ if (sizeOffsets[0]) {
+ value -= ComputedStyle.getPixel(el, 'padding' + sizeOffsets[0]);
+ value -= ComputedStyle.getBorderWidth(el, 'border' + sizeOffsets[0] + 'Width', 1);
+ }
+
+ if (sizeOffsets[1]) {
+ value -= ComputedStyle.getPixel(el, 'padding' + sizeOffsets[1]);
+ value -= ComputedStyle.getBorderWidth(el, 'border' + sizeOffsets[1] + 'Width', 1);
+ }
+
+ } else { // use style.pixelWidth, etc. to convert to pixels
+ // need to map style.width to currentStyle (no currentStyle.pixelWidth)
+ if (!el.style[pixel] && !el.style[prop]) {
+ el.style[prop] = current;
+ }
+ value = el.style[pixel];
+
+ }
+ return value + PX;
+ },
+
+ borderMap: {
+ thin: '2px',
+ medium: '4px',
+ thick: '6px'
+ },
+
+ getBorderWidth: function(el, property, omitUnit) {
+ var unit = omitUnit ? '' : PX,
+ current = el.currentStyle[property];
+
+ if (current.indexOf(PX) < 0) { // look up keywords
+ if (ComputedStyle.borderMap[current]) {
+ current = ComputedStyle.borderMap[current];
+ } else {
+ Y.log('borderWidth computing not implemented', 'warn', 'dom-ie-style');
+ }
+ }
+ return (omitUnit) ? parseFloat(current) : current;
+ },
+
+ getPixel: function(node, att) {
+ // use pixelRight to convert to px
+ var val = null,
+ style = _getStyleObj(node),
+ styleRight = style.right,
+ current = style[att];
+
+ node.style.right = current;
+ val = node.style.pixelRight;
+ node.style.right = styleRight; // revert
+
+ return val;
+ },
+
+ getMargin: function(node, att) {
+ var val,
+ style = _getStyleObj(node);
+
+ if (style[att] == AUTO) {
+ val = 0;
+ } else {
+ val = ComputedStyle.getPixel(node, att);
+ }
+ return val + PX;
+ },
+
+ getVisibility: function(node, att) {
+ var current;
+ while ( (current = node.currentStyle) && current[att] == 'inherit') { // NOTE: assignment in test
+ node = node.parentNode;
+ }
+ return (current) ? current[att] : VISIBLE;
+ },
+
+ getColor: function(node, att) {
+ var current = _getStyleObj(node)[att];
+
+ if (!current || current === TRANSPARENT) {
+ Y.DOM.elementByAxis(node, 'parentNode', null, function(parent) {
+ current = _getStyleObj(parent)[att];
+ if (current && current !== TRANSPARENT) {
+ node = parent;
+ return true;
+ }
+ });
+ }
+
+ return Y.Color.toRGB(current);
+ },
+
+ getBorderColor: function(node, att) {
+ var current = _getStyleObj(node),
+ val = current[att] || current.color;
+ return Y.Color.toRGB(Y.Color.toHex(val));
+ }
+ },
+
+ //fontSize: getPixelFont,
+ IEComputed = {};
+
+// use alpha filter for IE opacity
+try {
+ if (documentElement.style[OPACITY] === UNDEFINED &&
+ documentElement[FILTERS]) {
+ Y.DOM.CUSTOM_STYLES[OPACITY] = {
+ get: function(node) {
+ var val = 100;
+ try { // will error if no DXImageTransform
+ val = node[FILTERS]['DXImageTransform.Microsoft.Alpha'][OPACITY];
+
+ } catch(e) {
+ try { // make sure its in the document
+ val = node[FILTERS]('alpha')[OPACITY];
+ } catch(err) {
+ Y.log('getStyle: IE opacity filter not found; returning 1', 'warn', 'dom-style');
+ }
+ }
+ return val / 100;
+ },
+
+ set: function(node, val, style) {
+ var current,
+ styleObj;
+
+ if (val === '') { // normalize inline style behavior
+ styleObj = _getStyleObj(node);
+ current = (OPACITY in styleObj) ? styleObj[OPACITY] : 1; // revert to original opacity
+ val = current;
+ }
+
+ if (typeof style[FILTER] == 'string') { // in case not appended
+ style[FILTER] = 'alpha(' + OPACITY + '=' + val * 100 + ')';
+
+ if (!node.currentStyle || !node.currentStyle[HAS_LAYOUT]) {
+ style.zoom = 1; // needs layout
+ }
+ }
+ }
+ };
+ }
+} catch(e) {
+ Y.log('document.documentElement.filters error (activeX disabled)', 'warn', 'dom-style');
+}
+
+try {
+ document.createElement('div').style.height = '-1px';
+} catch(e) { // IE throws error on invalid style set; trap common cases
+ Y.DOM.CUSTOM_STYLES.height = {
+ set: function(node, val, style) {
+ var floatVal = parseFloat(val);
+ if (isNaN(floatVal) || floatVal >= 0) {
+ style.height = val;
+ } else {
+ Y.log('invalid style value for height: ' + val, 'warn', 'dom-style');
+ }
+ }
+ };
+
+ Y.DOM.CUSTOM_STYLES.width = {
+ set: function(node, val, style) {
+ var floatVal = parseFloat(val);
+ if (isNaN(floatVal) || floatVal >= 0) {
+ style.width = val;
+ } else {
+ Y.log('invalid style value for width: ' + val, 'warn', 'dom-style');
+ }
+ }
+ };
+}
+
+// TODO: top, right, bottom, left
+IEComputed[WIDTH] = IEComputed[HEIGHT] = ComputedStyle.getOffset;
+
+IEComputed.color = IEComputed.backgroundColor = ComputedStyle.getColor;
+
+IEComputed[BORDER_WIDTH] = IEComputed[BORDER_TOP_WIDTH] = IEComputed[BORDER_RIGHT_WIDTH] =
+ IEComputed[BORDER_BOTTOM_WIDTH] = IEComputed[BORDER_LEFT_WIDTH] =
+ ComputedStyle.getBorderWidth;
+
+IEComputed.marginTop = IEComputed.marginRight = IEComputed.marginBottom =
+ IEComputed.marginLeft = ComputedStyle.getMargin;
+
+IEComputed.visibility = ComputedStyle.getVisibility;
+IEComputed.borderColor = IEComputed.borderTopColor =
+ IEComputed.borderRightColor = IEComputed.borderBottomColor =
+ IEComputed.borderLeftColor = ComputedStyle.getBorderColor;
+
+if (!Y.config.win[GET_COMPUTED_STYLE]) {
+ Y.DOM[GET_COMPUTED_STYLE] = ComputedStyle.get;
+}
+
+Y.namespace('DOM.IE');
+Y.DOM.IE.COMPUTED = IEComputed;
+Y.DOM.IE.ComputedStyle = ComputedStyle;
+
+})(Y);
+
+
+}, '3.0.0' ,{requires:['dom-base']});
diff --git a/lib/yui/3.0.0/dom/dom-style-min.js b/lib/yui/3.0.0/dom/dom-style-min.js
new file mode 100644
index 0000000000..9406790941
--- /dev/null
+++ b/lib/yui/3.0.0/dom/dom-style-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("dom-style",function(A){(function(E){var C="documentElement",B="defaultView",D="ownerDocument",L="style",N="float",F="cssFloat",G="styleFloat",J="transparent",H="getComputedStyle",M=E.config.doc,I=undefined,K=/color$/i;E.mix(E.DOM,{CUSTOM_STYLES:{},setStyle:function(R,O,S,Q){Q=Q||R.style;var P=E.DOM.CUSTOM_STYLES;if(Q){if(S===null){S="";}if(O in P){if(P[O].set){P[O].set(R,S,Q);return;}else{if(typeof P[O]==="string"){O=P[O];}}}Q[O]=S;}},getStyle:function(R,O){var Q=R[L],P=E.DOM.CUSTOM_STYLES,S="";if(Q){if(O in P){if(P[O].get){return P[O].get(R,O,Q);}else{if(typeof P[O]==="string"){O=P[O];}}}S=Q[O];if(S===""){S=E.DOM[H](R,O);}}return S;},setStyles:function(P,Q){var O=P.style;E.each(Q,function(R,S){E.DOM.setStyle(P,S,R,O);},E.DOM);},getComputedStyle:function(P,O){var R="",Q=P[D];if(P[L]){R=Q[B][H](P,null)[O];}return R;}});if(M[C][L][F]!==I){E.DOM.CUSTOM_STYLES[N]=F;}else{if(M[C][L][G]!==I){E.DOM.CUSTOM_STYLES[N]=G;}}if(E.UA.opera){E.DOM[H]=function(Q,P){var O=Q[D][B],R=O[H](Q,"")[P];if(K.test(P)){R=E.Color.toRGB(R);}return R;};}if(E.UA.webkit){E.DOM[H]=function(Q,P){var O=Q[D][B],R=O[H](Q,"")[P];if(R==="rgba(0, 0, 0, 0)"){R=J;}return R;};}})(A);(function(D){var B=parseInt,C=RegExp;D.Color={KEYWORDS:{black:"000",silver:"c0c0c0",gray:"808080",white:"fff",maroon:"800000",red:"f00",purple:"800080",fuchsia:"f0f",green:"008000",lime:"0f0",olive:"808000",yellow:"ff0",navy:"000080",blue:"00f",teal:"008080",aqua:"0ff"},re_RGB:/^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i,re_hex:/^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i,re_hex3:/([0-9A-F])/gi,toRGB:function(E){if(!D.Color.re_RGB.test(E)){E=D.Color.toHex(E);}if(D.Color.re_hex.exec(E)){E="rgb("+[B(C.$1,16),B(C.$2,16),B(C.$3,16)].join(", ")+")";}return E;},toHex:function(F){F=D.Color.KEYWORDS[F]||F;if(D.Color.re_RGB.exec(F)){F=[Number(C.$1).toString(16),Number(C.$2).toString(16),Number(C.$3).toString(16)];for(var E=0;E-1)){a=c;}else{if(D.DOM.IE.COMPUTED[b]){a=D.DOM.IE.COMPUTED[b](Y,b);}else{if(P.test(c)){a=N.getPixel(Y,b)+K;}else{a=c;}}}}}return a;},sizeOffsets:{width:["Left","Right"],height:["Top","Bottom"],top:["Top"],bottom:["Bottom"]},getOffset:function(b,g){var d=E(b)[g],Y=g.charAt(0).toUpperCase()+g.substr(1),f="offset"+Y,a="pixel"+Y,e=N.sizeOffsets[g],c="";if(d===M||d.indexOf("%")>-1){c=b["offset"+Y];if(e[0]){c-=N.getPixel(b,"padding"+e[0]);c-=N.getBorderWidth(b,"border"+e[0]+"Width",1);}if(e[1]){c-=N.getPixel(b,"padding"+e[1]);c-=N.getBorderWidth(b,"border"+e[1]+"Width",1);}}else{if(!b.style[a]&&!b.style[g]){b.style[g]=d;}c=b.style[a];}return c+K;},borderMap:{thin:"2px",medium:"4px",thick:"6px"},getBorderWidth:function(a,c,Y){var b=Y?"":K,d=a.currentStyle[c];if(d.indexOf(K)<0){if(N.borderMap[d]){d=N.borderMap[d];}else{}}return(Y)?parseFloat(d):d;},getPixel:function(b,Y){var d=null,a=E(b),e=a.right,c=a[Y];b.style.right=c;d=b.style.pixelRight;b.style.right=e;return d;},getMargin:function(b,Y){var c,a=E(b);if(a[Y]==M){c=0;}else{c=N.getPixel(b,Y);}return c+K;},getVisibility:function(a,Y){var b;while((b=a.currentStyle)&&b[Y]=="inherit"){a=a.parentNode;}return(b)?b[Y]:S;},getColor:function(a,Y){var b=E(a)[Y];if(!b||b===R){D.DOM.elementByAxis(a,"parentNode",null,function(c){b=E(c)[Y];if(b&&b!==R){a=c;return true;}});}return D.Color.toRGB(b);},getBorderColor:function(a,Y){var b=E(a),c=b[Y]||b.color;return D.Color.toRGB(D.Color.toHex(c));}},F={};try{if(X.style[T]===Z&&X[B]){D.DOM.CUSTOM_STYLES[T]={get:function(a){var c=100;try{c=a[B]["DXImageTransform.Microsoft.Alpha"][T];}catch(b){try{c=a[B]("alpha")[T];}catch(Y){}}return c/100;},set:function(a,d,Y){var c,b;if(d===""){b=E(a);c=(T in b)?b[T]:1;d=c;}if(typeof Y[L]=="string"){Y[L]="alpha("+T+"="+d*100+")";if(!a.currentStyle||!a.currentStyle[W]){Y.zoom=1;}}}};}}catch(U){}try{document.createElement("div").style.height="-1px";}catch(U){D.DOM.CUSTOM_STYLES.height={set:function(b,c,a){var Y=parseFloat(c);if(isNaN(Y)||Y>=0){a.height=c;}else{}}};D.DOM.CUSTOM_STYLES.width={set:function(b,c,a){var Y=parseFloat(c);if(isNaN(Y)||Y>=0){a.width=c;}else{}}};}F[I]=F[O]=N.getOffset;F.color=F.backgroundColor=N.getColor;F[G]=F[J]=F[Q]=F[V]=F[H]=N.getBorderWidth;F.marginTop=F.marginRight=F.marginBottom=F.marginLeft=N.getMargin;F.visibility=N.getVisibility;F.borderColor=F.borderTopColor=F.borderRightColor=F.borderBottomColor=F.borderLeftColor=N.getBorderColor;if(!D.config.win[C]){D.DOM[C]=N.get;}D.namespace("DOM.IE");D.DOM.IE.COMPUTED=F;D.DOM.IE.ComputedStyle=N;})(A);},"3.0.0",{requires:["dom-base"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/dom/dom-style.js b/lib/yui/3.0.0/dom/dom-style.js
new file mode 100644
index 0000000000..9b774b3ecc
--- /dev/null
+++ b/lib/yui/3.0.0/dom/dom-style.js
@@ -0,0 +1,506 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dom-style', function(Y) {
+
+(function(Y) {
+/**
+ * Add style management functionality to DOM.
+ * @module dom
+ * @submodule dom-style
+ * @for DOM
+ */
+
+var DOCUMENT_ELEMENT = 'documentElement',
+ DEFAULT_VIEW = 'defaultView',
+ OWNER_DOCUMENT = 'ownerDocument',
+ STYLE = 'style',
+ FLOAT = 'float',
+ CSS_FLOAT = 'cssFloat',
+ STYLE_FLOAT = 'styleFloat',
+ TRANSPARENT = 'transparent',
+ GET_COMPUTED_STYLE = 'getComputedStyle',
+
+ DOCUMENT = Y.config.doc,
+ UNDEFINED = undefined,
+
+ re_color = /color$/i;
+
+
+Y.mix(Y.DOM, {
+ CUSTOM_STYLES: {
+ },
+
+
+ /**
+ * Sets a style property for a given element.
+ * @method setStyle
+ * @param {HTMLElement} An HTMLElement to apply the style to.
+ * @param {String} att The style property to set.
+ * @param {String|Number} val The value.
+ */
+ setStyle: function(node, att, val, style) {
+ style = style || node.style;
+ var CUSTOM_STYLES = Y.DOM.CUSTOM_STYLES;
+
+ if (style) {
+ if (val === null) {
+ val = ''; // normalize for unsetting
+ }
+ if (att in CUSTOM_STYLES) {
+ if (CUSTOM_STYLES[att].set) {
+ CUSTOM_STYLES[att].set(node, val, style);
+ return; // NOTE: return
+ } else if (typeof CUSTOM_STYLES[att] === 'string') {
+ att = CUSTOM_STYLES[att];
+ }
+ }
+ style[att] = val;
+ }
+ },
+
+ /**
+ * Returns the current style value for the given property.
+ * @method getStyle
+ * @param {HTMLElement} An HTMLElement to get the style from.
+ * @param {String} att The style property to get.
+ */
+ getStyle: function(node, att) {
+ var style = node[STYLE],
+ CUSTOM_STYLES = Y.DOM.CUSTOM_STYLES,
+ val = '';
+
+ if (style) {
+ if (att in CUSTOM_STYLES) {
+ if (CUSTOM_STYLES[att].get) {
+ return CUSTOM_STYLES[att].get(node, att, style); // NOTE: return
+ } else if (typeof CUSTOM_STYLES[att] === 'string') {
+ att = CUSTOM_STYLES[att];
+ }
+ }
+ val = style[att];
+ if (val === '') { // TODO: is empty string sufficient?
+ val = Y.DOM[GET_COMPUTED_STYLE](node, att);
+ }
+ }
+
+ return val;
+ },
+
+ /**
+ * Sets multiple style properties.
+ * @method setStyles
+ * @param {HTMLElement} node An HTMLElement to apply the styles to.
+ * @param {Object} hash An object literal of property:value pairs.
+ */
+ setStyles: function(node, hash) {
+ var style = node.style;
+ Y.each(hash, function(v, n) {
+ Y.DOM.setStyle(node, n, v, style);
+ }, Y.DOM);
+ },
+
+ /**
+ * Returns the computed style for the given node.
+ * @method getComputedStyle
+ * @param {HTMLElement} An HTMLElement to get the style from.
+ * @param {String} att The style property to get.
+ * @return {String} The computed value of the style property.
+ */
+ getComputedStyle: function(node, att) {
+ var val = '',
+ doc = node[OWNER_DOCUMENT];
+
+ if (node[STYLE]) {
+ val = doc[DEFAULT_VIEW][GET_COMPUTED_STYLE](node, null)[att];
+ }
+ return val;
+ }
+});
+
+// normalize reserved word float alternatives ("cssFloat" or "styleFloat")
+if (DOCUMENT[DOCUMENT_ELEMENT][STYLE][CSS_FLOAT] !== UNDEFINED) {
+ Y.DOM.CUSTOM_STYLES[FLOAT] = CSS_FLOAT;
+} else if (DOCUMENT[DOCUMENT_ELEMENT][STYLE][STYLE_FLOAT] !== UNDEFINED) {
+ Y.DOM.CUSTOM_STYLES[FLOAT] = STYLE_FLOAT;
+}
+
+// fix opera computedStyle default color unit (convert to rgb)
+if (Y.UA.opera) {
+ Y.DOM[GET_COMPUTED_STYLE] = function(node, att) {
+ var view = node[OWNER_DOCUMENT][DEFAULT_VIEW],
+ val = view[GET_COMPUTED_STYLE](node, '')[att];
+
+ if (re_color.test(att)) {
+ val = Y.Color.toRGB(val);
+ }
+
+ return val;
+ };
+
+}
+
+// safari converts transparent to rgba(), others use "transparent"
+if (Y.UA.webkit) {
+ Y.DOM[GET_COMPUTED_STYLE] = function(node, att) {
+ var view = node[OWNER_DOCUMENT][DEFAULT_VIEW],
+ val = view[GET_COMPUTED_STYLE](node, '')[att];
+
+ if (val === 'rgba(0, 0, 0, 0)') {
+ val = TRANSPARENT;
+ }
+
+ return val;
+ };
+
+}
+})(Y);
+(function(Y) {
+var PARSE_INT = parseInt,
+ RE = RegExp;
+
+Y.Color = {
+ KEYWORDS: {
+ black: '000',
+ silver: 'c0c0c0',
+ gray: '808080',
+ white: 'fff',
+ maroon: '800000',
+ red: 'f00',
+ purple: '800080',
+ fuchsia: 'f0f',
+ green: '008000',
+ lime: '0f0',
+ olive: '808000',
+ yellow: 'ff0',
+ navy: '000080',
+ blue: '00f',
+ teal: '008080',
+ aqua: '0ff'
+ },
+
+ re_RGB: /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i,
+ re_hex: /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i,
+ re_hex3: /([0-9A-F])/gi,
+
+ toRGB: function(val) {
+ if (!Y.Color.re_RGB.test(val)) {
+ val = Y.Color.toHex(val);
+ }
+
+ if(Y.Color.re_hex.exec(val)) {
+ val = 'rgb(' + [
+ PARSE_INT(RE.$1, 16),
+ PARSE_INT(RE.$2, 16),
+ PARSE_INT(RE.$3, 16)
+ ].join(', ') + ')';
+ }
+ return val;
+ },
+
+ toHex: function(val) {
+ val = Y.Color.KEYWORDS[val] || val;
+ if (Y.Color.re_RGB.exec(val)) {
+ val = [
+ Number(RE.$1).toString(16),
+ Number(RE.$2).toString(16),
+ Number(RE.$3).toString(16)
+ ];
+
+ for (var i = 0; i < val.length; i++) {
+ if (val[i].length < 2) {
+ val[i] = val[i].replace(Y.Color.re_hex3, '$1$1');
+ }
+ }
+
+ val = '#' + val.join('');
+ }
+
+ if (val.length < 6) {
+ val = val.replace(Y.Color.re_hex3, '$1$1');
+ }
+
+ if (val !== 'transparent' && val.indexOf('#') < 0) {
+ val = '#' + val;
+ }
+
+ return val.toLowerCase();
+ }
+};
+})(Y);
+
+(function(Y) {
+var HAS_LAYOUT = 'hasLayout',
+ PX = 'px',
+ FILTER = 'filter',
+ FILTERS = 'filters',
+ OPACITY = 'opacity',
+ AUTO = 'auto',
+
+ BORDER_WIDTH = 'borderWidth',
+ BORDER_TOP_WIDTH = 'borderTopWidth',
+ BORDER_RIGHT_WIDTH = 'borderRightWidth',
+ BORDER_BOTTOM_WIDTH = 'borderBottomWidth',
+ BORDER_LEFT_WIDTH = 'borderLeftWidth',
+ WIDTH = 'width',
+ HEIGHT = 'height',
+ TRANSPARENT = 'transparent',
+ VISIBLE = 'visible',
+ GET_COMPUTED_STYLE = 'getComputedStyle',
+ UNDEFINED = undefined,
+ documentElement = document.documentElement,
+
+ // TODO: unit-less lineHeight (e.g. 1.22)
+ re_unit = /^(\d[.\d]*)+(em|ex|px|gd|rem|vw|vh|vm|ch|mm|cm|in|pt|pc|deg|rad|ms|s|hz|khz|%){1}?/i,
+
+ _getStyleObj = function(node) {
+ return node.currentStyle || node.style;
+ },
+
+ ComputedStyle = {
+ CUSTOM_STYLES: {},
+
+ get: function(el, property) {
+ var value = '',
+ current;
+
+ if (el) {
+ current = _getStyleObj(el)[property];
+
+ if (property === OPACITY && Y.DOM.CUSTOM_STYLES[OPACITY]) {
+ value = Y.DOM.CUSTOM_STYLES[OPACITY].get(el);
+ } else if (!current || (current.indexOf && current.indexOf(PX) > -1)) { // no need to convert
+ value = current;
+ } else if (Y.DOM.IE.COMPUTED[property]) { // use compute function
+ value = Y.DOM.IE.COMPUTED[property](el, property);
+ } else if (re_unit.test(current)) { // convert to pixel
+ value = ComputedStyle.getPixel(el, property) + PX;
+ } else {
+ value = current;
+ }
+ }
+
+ return value;
+ },
+
+ sizeOffsets: {
+ width: ['Left', 'Right'],
+ height: ['Top', 'Bottom'],
+ top: ['Top'],
+ bottom: ['Bottom']
+ },
+
+ getOffset: function(el, prop) {
+ var current = _getStyleObj(el)[prop], // value of "width", "top", etc.
+ capped = prop.charAt(0).toUpperCase() + prop.substr(1), // "Width", "Top", etc.
+ offset = 'offset' + capped, // "offsetWidth", "offsetTop", etc.
+ pixel = 'pixel' + capped, // "pixelWidth", "pixelTop", etc.
+ sizeOffsets = ComputedStyle.sizeOffsets[prop],
+ value = '';
+
+ // IE pixelWidth incorrect for percent
+ // manually compute by subtracting padding and border from offset size
+ // NOTE: clientWidth/Height (size minus border) is 0 when current === AUTO so offsetHeight is used
+ // reverting to auto from auto causes position stacking issues (old impl)
+ if (current === AUTO || current.indexOf('%') > -1) {
+ value = el['offset' + capped];
+
+ if (sizeOffsets[0]) {
+ value -= ComputedStyle.getPixel(el, 'padding' + sizeOffsets[0]);
+ value -= ComputedStyle.getBorderWidth(el, 'border' + sizeOffsets[0] + 'Width', 1);
+ }
+
+ if (sizeOffsets[1]) {
+ value -= ComputedStyle.getPixel(el, 'padding' + sizeOffsets[1]);
+ value -= ComputedStyle.getBorderWidth(el, 'border' + sizeOffsets[1] + 'Width', 1);
+ }
+
+ } else { // use style.pixelWidth, etc. to convert to pixels
+ // need to map style.width to currentStyle (no currentStyle.pixelWidth)
+ if (!el.style[pixel] && !el.style[prop]) {
+ el.style[prop] = current;
+ }
+ value = el.style[pixel];
+
+ }
+ return value + PX;
+ },
+
+ borderMap: {
+ thin: '2px',
+ medium: '4px',
+ thick: '6px'
+ },
+
+ getBorderWidth: function(el, property, omitUnit) {
+ var unit = omitUnit ? '' : PX,
+ current = el.currentStyle[property];
+
+ if (current.indexOf(PX) < 0) { // look up keywords
+ if (ComputedStyle.borderMap[current]) {
+ current = ComputedStyle.borderMap[current];
+ } else {
+ }
+ }
+ return (omitUnit) ? parseFloat(current) : current;
+ },
+
+ getPixel: function(node, att) {
+ // use pixelRight to convert to px
+ var val = null,
+ style = _getStyleObj(node),
+ styleRight = style.right,
+ current = style[att];
+
+ node.style.right = current;
+ val = node.style.pixelRight;
+ node.style.right = styleRight; // revert
+
+ return val;
+ },
+
+ getMargin: function(node, att) {
+ var val,
+ style = _getStyleObj(node);
+
+ if (style[att] == AUTO) {
+ val = 0;
+ } else {
+ val = ComputedStyle.getPixel(node, att);
+ }
+ return val + PX;
+ },
+
+ getVisibility: function(node, att) {
+ var current;
+ while ( (current = node.currentStyle) && current[att] == 'inherit') { // NOTE: assignment in test
+ node = node.parentNode;
+ }
+ return (current) ? current[att] : VISIBLE;
+ },
+
+ getColor: function(node, att) {
+ var current = _getStyleObj(node)[att];
+
+ if (!current || current === TRANSPARENT) {
+ Y.DOM.elementByAxis(node, 'parentNode', null, function(parent) {
+ current = _getStyleObj(parent)[att];
+ if (current && current !== TRANSPARENT) {
+ node = parent;
+ return true;
+ }
+ });
+ }
+
+ return Y.Color.toRGB(current);
+ },
+
+ getBorderColor: function(node, att) {
+ var current = _getStyleObj(node),
+ val = current[att] || current.color;
+ return Y.Color.toRGB(Y.Color.toHex(val));
+ }
+ },
+
+ //fontSize: getPixelFont,
+ IEComputed = {};
+
+// use alpha filter for IE opacity
+try {
+ if (documentElement.style[OPACITY] === UNDEFINED &&
+ documentElement[FILTERS]) {
+ Y.DOM.CUSTOM_STYLES[OPACITY] = {
+ get: function(node) {
+ var val = 100;
+ try { // will error if no DXImageTransform
+ val = node[FILTERS]['DXImageTransform.Microsoft.Alpha'][OPACITY];
+
+ } catch(e) {
+ try { // make sure its in the document
+ val = node[FILTERS]('alpha')[OPACITY];
+ } catch(err) {
+ }
+ }
+ return val / 100;
+ },
+
+ set: function(node, val, style) {
+ var current,
+ styleObj;
+
+ if (val === '') { // normalize inline style behavior
+ styleObj = _getStyleObj(node);
+ current = (OPACITY in styleObj) ? styleObj[OPACITY] : 1; // revert to original opacity
+ val = current;
+ }
+
+ if (typeof style[FILTER] == 'string') { // in case not appended
+ style[FILTER] = 'alpha(' + OPACITY + '=' + val * 100 + ')';
+
+ if (!node.currentStyle || !node.currentStyle[HAS_LAYOUT]) {
+ style.zoom = 1; // needs layout
+ }
+ }
+ }
+ };
+ }
+} catch(e) {
+}
+
+try {
+ document.createElement('div').style.height = '-1px';
+} catch(e) { // IE throws error on invalid style set; trap common cases
+ Y.DOM.CUSTOM_STYLES.height = {
+ set: function(node, val, style) {
+ var floatVal = parseFloat(val);
+ if (isNaN(floatVal) || floatVal >= 0) {
+ style.height = val;
+ } else {
+ }
+ }
+ };
+
+ Y.DOM.CUSTOM_STYLES.width = {
+ set: function(node, val, style) {
+ var floatVal = parseFloat(val);
+ if (isNaN(floatVal) || floatVal >= 0) {
+ style.width = val;
+ } else {
+ }
+ }
+ };
+}
+
+// TODO: top, right, bottom, left
+IEComputed[WIDTH] = IEComputed[HEIGHT] = ComputedStyle.getOffset;
+
+IEComputed.color = IEComputed.backgroundColor = ComputedStyle.getColor;
+
+IEComputed[BORDER_WIDTH] = IEComputed[BORDER_TOP_WIDTH] = IEComputed[BORDER_RIGHT_WIDTH] =
+ IEComputed[BORDER_BOTTOM_WIDTH] = IEComputed[BORDER_LEFT_WIDTH] =
+ ComputedStyle.getBorderWidth;
+
+IEComputed.marginTop = IEComputed.marginRight = IEComputed.marginBottom =
+ IEComputed.marginLeft = ComputedStyle.getMargin;
+
+IEComputed.visibility = ComputedStyle.getVisibility;
+IEComputed.borderColor = IEComputed.borderTopColor =
+ IEComputed.borderRightColor = IEComputed.borderBottomColor =
+ IEComputed.borderLeftColor = ComputedStyle.getBorderColor;
+
+if (!Y.config.win[GET_COMPUTED_STYLE]) {
+ Y.DOM[GET_COMPUTED_STYLE] = ComputedStyle.get;
+}
+
+Y.namespace('DOM.IE');
+Y.DOM.IE.COMPUTED = IEComputed;
+Y.DOM.IE.ComputedStyle = ComputedStyle;
+
+})(Y);
+
+
+}, '3.0.0' ,{requires:['dom-base']});
diff --git a/lib/yui/3.0.0/dom/dom.js b/lib/yui/3.0.0/dom/dom.js
new file mode 100644
index 0000000000..c41260b6d5
--- /dev/null
+++ b/lib/yui/3.0.0/dom/dom.js
@@ -0,0 +1,2466 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dom-base', function(Y) {
+
+(function(Y) {
+/**
+ * The DOM utility provides a cross-browser abtraction layer
+ * normalizing DOM tasks, and adds extra helper functionality
+ * for other common tasks.
+ * @module dom
+ * @submodule dom-base
+ *
+ */
+
+/**
+ * Provides DOM helper methods.
+ * @class DOM
+ *
+ */
+var NODE_TYPE = 'nodeType',
+ OWNER_DOCUMENT = 'ownerDocument',
+ DEFAULT_VIEW = 'defaultView',
+ PARENT_WINDOW = 'parentWindow',
+ TAG_NAME = 'tagName',
+ PARENT_NODE = 'parentNode',
+ FIRST_CHILD = 'firstChild',
+ PREVIOUS_SIBLING = 'previousSibling',
+ NEXT_SIBLING = 'nextSibling',
+ CONTAINS = 'contains',
+ COMPARE_DOCUMENT_POSITION = 'compareDocumentPosition',
+
+ documentElement = document.documentElement,
+
+ re_tag = /<([a-z]+)/i;
+
+Y.DOM = {
+ /**
+ * Returns the HTMLElement with the given ID (Wrapper for document.getElementById).
+ * @method byId
+ * @param {String} id the id attribute
+ * @param {Object} doc optional The document to search. Defaults to current document
+ * @return {HTMLElement | null} The HTMLElement with the id, or null if none found.
+ */
+ byId: function(id, doc) {
+ doc = doc || Y.config.doc;
+ // TODO: IE Name
+ return doc.getElementById(id);
+ },
+
+ // @deprecated
+ children: function(node, tag) {
+ var ret = [];
+ if (node) {
+ tag = tag || '*';
+ ret = Y.Selector.query('> ' + tag, node);
+ }
+ return ret;
+ },
+
+ // @deprecated
+ firstByTag: function(tag, root) {
+ var ret;
+ root = root || Y.config.doc;
+
+ if (tag && root.getElementsByTagName) {
+ ret = root.getElementsByTagName(tag)[0];
+ }
+
+ return ret || null;
+ },
+
+ /**
+ * Returns the text content of the HTMLElement.
+ * @method getText
+ * @param {HTMLElement} element The html element.
+ * @return {String} The text content of the element (includes text of any descending elements).
+ */
+ getText: (documentElement.textContent !== undefined) ?
+ function(element) {
+ var ret = '';
+ if (element) {
+ ret = element.textContent;
+ }
+ return ret || '';
+ } : function(element) {
+ var ret = '';
+ if (element) {
+ ret = element.innerText;
+ }
+ return ret || '';
+ },
+
+ /**
+ * Sets the text content of the HTMLElement.
+ * @method setText
+ * @param {HTMLElement} element The html element.
+ * @param {String} content The content to add.
+ */
+ setText: (documentElement.textContent !== undefined) ?
+ function(element, content) {
+ if (element) {
+ element.textContent = content;
+ }
+ } : function(element, content) {
+ if (element) {
+ element.innerText = content;
+ }
+ },
+
+ /*
+ * Finds the previous sibling of the element.
+ * @method previous
+ * @deprecated Use elementByAxis
+ * @param {HTMLElement} element The html element.
+ * @param {Function} fn optional An optional boolean test to apply.
+ * The optional function is passed the current DOM node being tested as its only argument.
+ * If no function is given, the first sibling is returned.
+ * @param {Boolean} all optional Whether all node types should be scanned, or just element nodes.
+ * @return {HTMLElement | null} The matching DOM node or null if none found.
+ */
+ previous: function(element, fn, all) {
+ return Y.DOM.elementByAxis(element, PREVIOUS_SIBLING, fn, all);
+ },
+
+ /*
+ * Finds the next sibling of the element.
+ * @method next
+ * @deprecated Use elementByAxis
+ * @param {HTMLElement} element The html element.
+ * @param {Function} fn optional An optional boolean test to apply.
+ * The optional function is passed the current DOM node being tested as its only argument.
+ * If no function is given, the first sibling is returned.
+ * @param {Boolean} all optional Whether all node types should be scanned, or just element nodes.
+ * @return {HTMLElement | null} The matching DOM node or null if none found.
+ */
+ next: function(element, fn, all) {
+ return Y.DOM.elementByAxis(element, NEXT_SIBLING, fn, all);
+ },
+
+ /*
+ * Finds the ancestor of the element.
+ * @method ancestor
+ * @deprecated Use elementByAxis
+ * @param {HTMLElement} element The html element.
+ * @param {Function} fn optional An optional boolean test to apply.
+ * The optional function is passed the current DOM node being tested as its only argument.
+ * If no function is given, the parentNode is returned.
+ * @param {Boolean} all optional Whether all node types should be scanned, or just element nodes.
+ * @return {HTMLElement | null} The matching DOM node or null if none found.
+ */
+ // TODO: optional stopAt node?
+ ancestor: function(element, fn, all) {
+ return Y.DOM.elementByAxis(element, PARENT_NODE, fn, all);
+ },
+
+ /**
+ * Searches the element by the given axis for the first matching element.
+ * @method elementByAxis
+ * @param {HTMLElement} element The html element.
+ * @param {String} axis The axis to search (parentNode, nextSibling, previousSibling).
+ * @param {Function} fn optional An optional boolean test to apply.
+ * @param {Boolean} all optional Whether all node types should be returned, or just element nodes.
+ * The optional function is passed the current HTMLElement being tested as its only argument.
+ * If no function is given, the first element is returned.
+ * @return {HTMLElement | null} The matching element or null if none found.
+ */
+ elementByAxis: function(element, axis, fn, all) {
+ while (element && (element = element[axis])) { // NOTE: assignment
+ if ( (all || element[TAG_NAME]) && (!fn || fn(element)) ) {
+ return element;
+ }
+ }
+ return null;
+ },
+
+ /**
+ * Determines whether or not one HTMLElement is or contains another HTMLElement.
+ * @method contains
+ * @param {HTMLElement} element The containing html element.
+ * @param {HTMLElement} needle The html element that may be contained.
+ * @return {Boolean} Whether or not the element is or contains the needle.
+ */
+ contains: function(element, needle) {
+ var ret = false;
+
+ if ( !needle || !element || !needle[NODE_TYPE] || !element[NODE_TYPE]) {
+ ret = false;
+ } else if (element[CONTAINS]) {
+ if (Y.UA.opera || needle[NODE_TYPE] === 1) { // IE & SAF contains fail if needle not an ELEMENT_NODE
+ ret = element[CONTAINS](needle);
+ } else {
+ ret = Y.DOM._bruteContains(element, needle);
+ }
+ } else if (element[COMPARE_DOCUMENT_POSITION]) { // gecko
+ if (element === needle || !!(element[COMPARE_DOCUMENT_POSITION](needle) & 16)) {
+ ret = true;
+ }
+ }
+
+ return ret;
+ },
+
+ /**
+ * Determines whether or not the HTMLElement is part of the document.
+ * @method inDoc
+ * @param {HTMLElement} element The containing html element.
+ * @param {HTMLElement} doc optional The document to check.
+ * @return {Boolean} Whether or not the element is attached to the document.
+ */
+ inDoc: function(element, doc) {
+ doc = doc || element[OWNER_DOCUMENT];
+ var id = element.id;
+ if (!id) { // TODO: remove when done?
+ id = element.id = Y.guid();
+ }
+
+ return !! (doc.getElementById(id));
+ },
+
+ /**
+ * Creates a new dom node using the provided markup string.
+ * @method create
+ * @param {String} html The markup used to create the element
+ * @param {HTMLDocument} doc An optional document context
+ */
+ create: function(html, doc) {
+ if (typeof html === 'string') {
+ html = Y.Lang.trim(html); // match IE which trims whitespace from innerHTML
+ }
+
+ if (!doc && Y.DOM._cloneCache[html]) {
+ return Y.DOM._cloneCache[html].cloneNode(true); // NOTE: return
+ }
+
+ doc = doc || Y.config.doc;
+ var m = re_tag.exec(html),
+ create = Y.DOM._create,
+ custom = Y.DOM.creators,
+ ret = null,
+ tag, nodes;
+
+ if (m && custom[m[1]]) {
+ if (typeof custom[m[1]] === 'function') {
+ create = custom[m[1]];
+ } else {
+ tag = custom[m[1]];
+ }
+ }
+
+ nodes = create(html, doc, tag).childNodes;
+
+ if (nodes.length === 1) { // return single node, breaking parentNode ref from "fragment"
+ ret = nodes[0].parentNode.removeChild(nodes[0]);
+ } else { // return multiple nodes as a fragment
+ ret = Y.DOM._nl2frag(nodes, doc);
+ }
+
+ if (ret) {
+ Y.DOM._cloneCache[html] = ret.cloneNode(true);
+ }
+ return ret;
+ },
+
+ _nl2frag: function(nodes, doc) {
+ var ret = null,
+ i, len;
+
+ if (nodes && (nodes.push || nodes.item) && nodes[0]) {
+ doc = doc || nodes[0].ownerDocument;
+ ret = doc.createDocumentFragment();
+
+ if (nodes.item) { // convert live list to static array
+ nodes = Y.Array(nodes, 0, true);
+ }
+
+ for (i = 0, len = nodes.length; i < len; i++) {
+ ret.appendChild(nodes[i]);
+ }
+ } // else inline with log for minification
+ return ret;
+ },
+
+
+ CUSTOM_ATTRIBUTES: (!documentElement.hasAttribute) ? { // IE < 8
+ 'for': 'htmlFor',
+ 'class': 'className'
+ } : { // w3c
+ 'htmlFor': 'for',
+ 'className': 'class'
+ },
+
+ /**
+ * Provides a normalized attribute interface.
+ * @method setAttibute
+ * @param {String | HTMLElement} el The target element for the attribute.
+ * @param {String} attr The attribute to set.
+ * @param {String} val The value of the attribute.
+ */
+ setAttribute: function(el, attr, val, ieAttr) {
+ if (el && el.setAttribute) {
+ attr = Y.DOM.CUSTOM_ATTRIBUTES[attr] || attr;
+ el.setAttribute(attr, val, ieAttr);
+ }
+ },
+
+
+ /**
+ * Provides a normalized attribute interface.
+ * @method getAttibute
+ * @param {String | HTMLElement} el The target element for the attribute.
+ * @param {String} attr The attribute to get.
+ * @return {String} The current value of the attribute.
+ */
+ getAttribute: function(el, attr, ieAttr) {
+ ieAttr = (ieAttr !== undefined) ? ieAttr : 2;
+ var ret = '';
+ if (el && el.getAttribute) {
+ attr = Y.DOM.CUSTOM_ATTRIBUTES[attr] || attr;
+ ret = el.getAttribute(attr, ieAttr);
+
+ if (ret === null) {
+ ret = ''; // per DOM spec
+ }
+ }
+ return ret;
+ },
+
+ isWindow: function(obj) {
+ return obj.alert && obj.document;
+ },
+
+ _fragClones: {
+ div: document.createElement('div')
+ },
+
+ _create: function(html, doc, tag) {
+ tag = tag || 'div';
+
+ var frag = Y.DOM._fragClones[tag];
+ if (frag) {
+ frag = frag.cloneNode(false);
+ } else {
+ frag = Y.DOM._fragClones[tag] = doc.createElement(tag);
+ }
+ frag.innerHTML = html;
+ return frag;
+ },
+
+ _removeChildNodes: function(node) {
+ while (node.firstChild) {
+ node.removeChild(node.firstChild);
+ }
+ },
+
+ _cloneCache: {},
+
+ /**
+ * Inserts content in a node at the given location
+ * @method addHTML
+ * @param {HTMLElement} node The node to insert into
+ * @param {String} content The content to be inserted
+ * @param {String} where Where to insert the content; default is after lastChild
+ */
+ addHTML: function(node, content, where) {
+ if (typeof content === 'string') {
+ content = Y.Lang.trim(content); // match IE which trims whitespace from innerHTML
+ }
+
+ var newNode = Y.DOM._cloneCache[content],
+ nodeParent = node.parentNode;
+
+ if (newNode) {
+ newNode = newNode.cloneNode(true);
+ } else {
+ if (content.nodeType) { // domNode
+ newNode = content;
+ } else { // create from string and cache
+ newNode = Y.DOM.create(content);
+ }
+ }
+
+ if (where) {
+ if (where.nodeType) { // insert regardless of relationship to node
+ // TODO: check if node.contains(where)?
+ where.parentNode.insertBefore(newNode, where);
+ } else {
+ switch (where) {
+ case 'replace':
+ while (node.firstChild) {
+ node.removeChild(node.firstChild);
+ }
+ node.appendChild(newNode);
+ break;
+ case 'before':
+ nodeParent.insertBefore(newNode, node);
+ break;
+ case 'after':
+ if (node.nextSibling) { // IE errors if refNode is null
+ nodeParent.insertBefore(newNode, node.nextSibling);
+ } else {
+ nodeParent.appendChild(newNode);
+ }
+ break;
+ default:
+ node.appendChild(newNode);
+ }
+ }
+ } else {
+ node.appendChild(newNode);
+ }
+
+ return newNode;
+ },
+
+ VALUE_SETTERS: {},
+
+ VALUE_GETTERS: {},
+
+ getValue: function(node) {
+ var ret = '', // TODO: return null?
+ getter;
+
+ if (node && node[TAG_NAME]) {
+ getter = Y.DOM.VALUE_GETTERS[node[TAG_NAME].toLowerCase()];
+
+ if (getter) {
+ ret = getter(node);
+ } else {
+ ret = node.value;
+ }
+ }
+
+ return (typeof ret === 'string') ? ret : '';
+ },
+
+ setValue: function(node, val) {
+ var setter;
+
+ if (node && node[TAG_NAME]) {
+ setter = Y.DOM.VALUE_SETTERS[node[TAG_NAME].toLowerCase()];
+
+ if (setter) {
+ setter(node, val);
+ } else {
+ node.value = val;
+ }
+ }
+ },
+
+ /**
+ * Brute force version of contains.
+ * Used for browsers without contains support for non-HTMLElement Nodes (textNodes, etc).
+ * @method _bruteContains
+ * @private
+ * @param {HTMLElement} element The containing html element.
+ * @param {HTMLElement} needle The html element that may be contained.
+ * @return {Boolean} Whether or not the element is or contains the needle.
+ */
+ _bruteContains: function(element, needle) {
+ while (needle) {
+ if (element === needle) {
+ return true;
+ }
+ needle = needle.parentNode;
+ }
+ return false;
+ },
+
+// TODO: move to Lang?
+ /**
+ * Memoizes dynamic regular expressions to boost runtime performance.
+ * @method _getRegExp
+ * @private
+ * @param {String} str The string to convert to a regular expression.
+ * @param {String} flags optional An optinal string of flags.
+ * @return {RegExp} An instance of RegExp
+ */
+ _getRegExp: function(str, flags) {
+ flags = flags || '';
+ Y.DOM._regexCache = Y.DOM._regexCache || {};
+ if (!Y.DOM._regexCache[str + flags]) {
+ Y.DOM._regexCache[str + flags] = new RegExp(str, flags);
+ }
+ return Y.DOM._regexCache[str + flags];
+ },
+
+// TODO: make getDoc/Win true privates?
+ /**
+ * returns the appropriate document.
+ * @method _getDoc
+ * @private
+ * @param {HTMLElement} element optional Target element.
+ * @return {Object} The document for the given element or the default document.
+ */
+ _getDoc: function(element) {
+ element = element || {};
+
+ return (element[NODE_TYPE] === 9) ? element : // element === document
+ element[OWNER_DOCUMENT] || // element === DOM node
+ element.document || // element === window
+ Y.config.doc; // default
+ },
+
+ /**
+ * returns the appropriate window.
+ * @method _getWin
+ * @private
+ * @param {HTMLElement} element optional Target element.
+ * @return {Object} The window for the given element or the default window.
+ */
+ _getWin: function(element) {
+ var doc = Y.DOM._getDoc(element);
+ return doc[DEFAULT_VIEW] || doc[PARENT_WINDOW] || Y.config.win;
+ },
+
+ _batch: function(nodes, fn, arg1, arg2, arg3, etc) {
+ fn = (typeof name === 'string') ? Y.DOM[fn] : fn;
+ var result,
+ ret = [];
+
+ if (fn && nodes) {
+ Y.each(nodes, function(node) {
+ if ((result = fn.call(Y.DOM, node, arg1, arg2, arg3, etc)) !== undefined) {
+ ret[ret.length] = result;
+ }
+ });
+ }
+
+ return ret.length ? ret : nodes;
+ },
+
+ _testElement: function(element, tag, fn) {
+ tag = (tag && tag !== '*') ? tag.toUpperCase() : null;
+ return (element && element[TAG_NAME] &&
+ (!tag || element[TAG_NAME].toUpperCase() === tag) &&
+ (!fn || fn(element)));
+ },
+
+ creators: {},
+
+ _IESimpleCreate: function(html, doc) {
+ doc = doc || Y.config.doc;
+ return doc.createElement(html);
+ }
+};
+
+
+(function(Y) {
+ var creators = Y.DOM.creators,
+ create = Y.DOM.create,
+ re_tbody = /(?:\/(?:thead|tfoot|tbody|caption|col|colgroup)>)+\s* 1 && tb && !re_tbody.test(html)) {
+ tb[PARENT_NODE].removeChild(tb); // strip extraneous tbody
+ }
+ return frag;
+ },
+
+ script: function(html, doc) {
+ var frag = doc.createElement('div');
+
+ frag.innerHTML = '-' + html;
+ frag.removeChild(frag[FIRST_CHILD]);
+ return frag;
+ }
+
+ }, true);
+
+ Y.mix(Y.DOM.VALUE_GETTERS, {
+ button: function(node) {
+ return (node.attributes && node.attributes.value) ? node.attributes.value.value : '';
+ }
+ });
+
+ Y.mix(Y.DOM.VALUE_SETTERS, {
+ // IE: node.value changes the button text, which should be handled via innerHTML
+ button: function(node, val) {
+ var attr = node.attributes.value;
+ if (!attr) {
+ attr = node[OWNER_DOCUMENT].createAttribute('value');
+ node.setAttributeNode(attr);
+ }
+
+ attr.value = val;
+ }
+ });
+ }
+
+ if (Y.UA.gecko || Y.UA.ie) {
+ Y.mix(creators, {
+ option: function(html, doc) {
+ return create('', doc);
+ },
+
+ tr: function(html, doc) {
+ return create('' + html + '', doc);
+ },
+
+ td: function(html, doc) {
+ return create('
' + html + '
', doc);
+ },
+
+ tbody: function(html, doc) {
+ return create(TABLE_OPEN + html + TABLE_CLOSE, doc);
+ }
+ });
+
+ Y.mix(creators, {
+ legend: 'fieldset',
+ th: creators.td,
+ thead: creators.tbody,
+ tfoot: creators.tbody,
+ caption: creators.tbody,
+ colgroup: creators.tbody,
+ col: creators.tbody,
+ optgroup: creators.option
+ });
+ }
+
+ Y.mix(Y.DOM.VALUE_GETTERS, {
+ option: function(node) {
+ var attrs = node.attributes;
+ return (attrs.value && attrs.value.specified) ? node.value : node.text;
+ },
+
+ select: function(node) {
+ var val = node.value,
+ options = node.options;
+
+ if (options && val === '') {
+ if (node.multiple) {
+ } else {
+ val = Y.DOM.getValue(options[node.selectedIndex], 'value');
+ }
+ }
+
+ return val;
+ }
+ });
+})(Y);
+
+})(Y);
+var addClass, hasClass, removeClass;
+
+Y.mix(Y.DOM, {
+ /**
+ * Determines whether a DOM element has the given className.
+ * @method hasClass
+ * @param {HTMLElement} element The DOM element.
+ * @param {String} className the class name to search for
+ * @return {Boolean} Whether or not the element has the given class.
+ */
+ hasClass: function(node, className) {
+ var re = Y.DOM._getRegExp('(?:^|\\s+)' + className + '(?:\\s+|$)');
+ return re.test(node.className);
+ },
+
+ /**
+ * Adds a class name to a given DOM element.
+ * @method addClass
+ * @param {HTMLElement} element The DOM element.
+ * @param {String} className the class name to add to the class attribute
+ */
+ addClass: function(node, className) {
+ if (!Y.DOM.hasClass(node, className)) { // skip if already present
+ node.className = Y.Lang.trim([node.className, className].join(' '));
+ }
+ },
+
+ /**
+ * Removes a class name from a given element.
+ * @method removeClass
+ * @param {HTMLElement} element The DOM element.
+ * @param {String} className the class name to remove from the class attribute
+ */
+ removeClass: function(node, className) {
+ if (className && hasClass(node, className)) {
+ node.className = Y.Lang.trim(node.className.replace(Y.DOM._getRegExp('(?:^|\\s+)' +
+ className + '(?:\\s+|$)'), ' '));
+
+ if ( hasClass(node, className) ) { // in case of multiple adjacent
+ removeClass(node, className);
+ }
+ }
+ },
+
+ /**
+ * Replace a class with another class for a given element.
+ * If no oldClassName is present, the newClassName is simply added.
+ * @method replaceClass
+ * @param {HTMLElement} element The DOM element.
+ * @param {String} oldClassName the class name to be replaced
+ * @param {String} newClassName the class name that will be replacing the old class name
+ */
+ replaceClass: function(node, oldC, newC) {
+ addClass(node, newC);
+ removeClass(node, oldC);
+ },
+
+ /**
+ * If the className exists on the node it is removed, if it doesn't exist it is added.
+ * @method toggleClass
+ * @param {HTMLElement} element The DOM element.
+ * @param {String} className the class name to be toggled
+ */
+ toggleClass: function(node, className) {
+ if (hasClass(node, className)) {
+ removeClass(node, className);
+ } else {
+ addClass(node, className);
+ }
+ }
+});
+
+hasClass = Y.DOM.hasClass;
+removeClass = Y.DOM.removeClass;
+addClass = Y.DOM.addClass;
+
+
+
+}, '3.0.0' ,{requires:['oop']});
+YUI.add('dom-style', function(Y) {
+
+(function(Y) {
+/**
+ * Add style management functionality to DOM.
+ * @module dom
+ * @submodule dom-style
+ * @for DOM
+ */
+
+var DOCUMENT_ELEMENT = 'documentElement',
+ DEFAULT_VIEW = 'defaultView',
+ OWNER_DOCUMENT = 'ownerDocument',
+ STYLE = 'style',
+ FLOAT = 'float',
+ CSS_FLOAT = 'cssFloat',
+ STYLE_FLOAT = 'styleFloat',
+ TRANSPARENT = 'transparent',
+ GET_COMPUTED_STYLE = 'getComputedStyle',
+
+ DOCUMENT = Y.config.doc,
+ UNDEFINED = undefined,
+
+ re_color = /color$/i;
+
+
+Y.mix(Y.DOM, {
+ CUSTOM_STYLES: {
+ },
+
+
+ /**
+ * Sets a style property for a given element.
+ * @method setStyle
+ * @param {HTMLElement} An HTMLElement to apply the style to.
+ * @param {String} att The style property to set.
+ * @param {String|Number} val The value.
+ */
+ setStyle: function(node, att, val, style) {
+ style = style || node.style;
+ var CUSTOM_STYLES = Y.DOM.CUSTOM_STYLES;
+
+ if (style) {
+ if (val === null) {
+ val = ''; // normalize for unsetting
+ }
+ if (att in CUSTOM_STYLES) {
+ if (CUSTOM_STYLES[att].set) {
+ CUSTOM_STYLES[att].set(node, val, style);
+ return; // NOTE: return
+ } else if (typeof CUSTOM_STYLES[att] === 'string') {
+ att = CUSTOM_STYLES[att];
+ }
+ }
+ style[att] = val;
+ }
+ },
+
+ /**
+ * Returns the current style value for the given property.
+ * @method getStyle
+ * @param {HTMLElement} An HTMLElement to get the style from.
+ * @param {String} att The style property to get.
+ */
+ getStyle: function(node, att) {
+ var style = node[STYLE],
+ CUSTOM_STYLES = Y.DOM.CUSTOM_STYLES,
+ val = '';
+
+ if (style) {
+ if (att in CUSTOM_STYLES) {
+ if (CUSTOM_STYLES[att].get) {
+ return CUSTOM_STYLES[att].get(node, att, style); // NOTE: return
+ } else if (typeof CUSTOM_STYLES[att] === 'string') {
+ att = CUSTOM_STYLES[att];
+ }
+ }
+ val = style[att];
+ if (val === '') { // TODO: is empty string sufficient?
+ val = Y.DOM[GET_COMPUTED_STYLE](node, att);
+ }
+ }
+
+ return val;
+ },
+
+ /**
+ * Sets multiple style properties.
+ * @method setStyles
+ * @param {HTMLElement} node An HTMLElement to apply the styles to.
+ * @param {Object} hash An object literal of property:value pairs.
+ */
+ setStyles: function(node, hash) {
+ var style = node.style;
+ Y.each(hash, function(v, n) {
+ Y.DOM.setStyle(node, n, v, style);
+ }, Y.DOM);
+ },
+
+ /**
+ * Returns the computed style for the given node.
+ * @method getComputedStyle
+ * @param {HTMLElement} An HTMLElement to get the style from.
+ * @param {String} att The style property to get.
+ * @return {String} The computed value of the style property.
+ */
+ getComputedStyle: function(node, att) {
+ var val = '',
+ doc = node[OWNER_DOCUMENT];
+
+ if (node[STYLE]) {
+ val = doc[DEFAULT_VIEW][GET_COMPUTED_STYLE](node, null)[att];
+ }
+ return val;
+ }
+});
+
+// normalize reserved word float alternatives ("cssFloat" or "styleFloat")
+if (DOCUMENT[DOCUMENT_ELEMENT][STYLE][CSS_FLOAT] !== UNDEFINED) {
+ Y.DOM.CUSTOM_STYLES[FLOAT] = CSS_FLOAT;
+} else if (DOCUMENT[DOCUMENT_ELEMENT][STYLE][STYLE_FLOAT] !== UNDEFINED) {
+ Y.DOM.CUSTOM_STYLES[FLOAT] = STYLE_FLOAT;
+}
+
+// fix opera computedStyle default color unit (convert to rgb)
+if (Y.UA.opera) {
+ Y.DOM[GET_COMPUTED_STYLE] = function(node, att) {
+ var view = node[OWNER_DOCUMENT][DEFAULT_VIEW],
+ val = view[GET_COMPUTED_STYLE](node, '')[att];
+
+ if (re_color.test(att)) {
+ val = Y.Color.toRGB(val);
+ }
+
+ return val;
+ };
+
+}
+
+// safari converts transparent to rgba(), others use "transparent"
+if (Y.UA.webkit) {
+ Y.DOM[GET_COMPUTED_STYLE] = function(node, att) {
+ var view = node[OWNER_DOCUMENT][DEFAULT_VIEW],
+ val = view[GET_COMPUTED_STYLE](node, '')[att];
+
+ if (val === 'rgba(0, 0, 0, 0)') {
+ val = TRANSPARENT;
+ }
+
+ return val;
+ };
+
+}
+})(Y);
+(function(Y) {
+var PARSE_INT = parseInt,
+ RE = RegExp;
+
+Y.Color = {
+ KEYWORDS: {
+ black: '000',
+ silver: 'c0c0c0',
+ gray: '808080',
+ white: 'fff',
+ maroon: '800000',
+ red: 'f00',
+ purple: '800080',
+ fuchsia: 'f0f',
+ green: '008000',
+ lime: '0f0',
+ olive: '808000',
+ yellow: 'ff0',
+ navy: '000080',
+ blue: '00f',
+ teal: '008080',
+ aqua: '0ff'
+ },
+
+ re_RGB: /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i,
+ re_hex: /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i,
+ re_hex3: /([0-9A-F])/gi,
+
+ toRGB: function(val) {
+ if (!Y.Color.re_RGB.test(val)) {
+ val = Y.Color.toHex(val);
+ }
+
+ if(Y.Color.re_hex.exec(val)) {
+ val = 'rgb(' + [
+ PARSE_INT(RE.$1, 16),
+ PARSE_INT(RE.$2, 16),
+ PARSE_INT(RE.$3, 16)
+ ].join(', ') + ')';
+ }
+ return val;
+ },
+
+ toHex: function(val) {
+ val = Y.Color.KEYWORDS[val] || val;
+ if (Y.Color.re_RGB.exec(val)) {
+ val = [
+ Number(RE.$1).toString(16),
+ Number(RE.$2).toString(16),
+ Number(RE.$3).toString(16)
+ ];
+
+ for (var i = 0; i < val.length; i++) {
+ if (val[i].length < 2) {
+ val[i] = val[i].replace(Y.Color.re_hex3, '$1$1');
+ }
+ }
+
+ val = '#' + val.join('');
+ }
+
+ if (val.length < 6) {
+ val = val.replace(Y.Color.re_hex3, '$1$1');
+ }
+
+ if (val !== 'transparent' && val.indexOf('#') < 0) {
+ val = '#' + val;
+ }
+
+ return val.toLowerCase();
+ }
+};
+})(Y);
+
+(function(Y) {
+var HAS_LAYOUT = 'hasLayout',
+ PX = 'px',
+ FILTER = 'filter',
+ FILTERS = 'filters',
+ OPACITY = 'opacity',
+ AUTO = 'auto',
+
+ BORDER_WIDTH = 'borderWidth',
+ BORDER_TOP_WIDTH = 'borderTopWidth',
+ BORDER_RIGHT_WIDTH = 'borderRightWidth',
+ BORDER_BOTTOM_WIDTH = 'borderBottomWidth',
+ BORDER_LEFT_WIDTH = 'borderLeftWidth',
+ WIDTH = 'width',
+ HEIGHT = 'height',
+ TRANSPARENT = 'transparent',
+ VISIBLE = 'visible',
+ GET_COMPUTED_STYLE = 'getComputedStyle',
+ UNDEFINED = undefined,
+ documentElement = document.documentElement,
+
+ // TODO: unit-less lineHeight (e.g. 1.22)
+ re_unit = /^(\d[.\d]*)+(em|ex|px|gd|rem|vw|vh|vm|ch|mm|cm|in|pt|pc|deg|rad|ms|s|hz|khz|%){1}?/i,
+
+ _getStyleObj = function(node) {
+ return node.currentStyle || node.style;
+ },
+
+ ComputedStyle = {
+ CUSTOM_STYLES: {},
+
+ get: function(el, property) {
+ var value = '',
+ current;
+
+ if (el) {
+ current = _getStyleObj(el)[property];
+
+ if (property === OPACITY && Y.DOM.CUSTOM_STYLES[OPACITY]) {
+ value = Y.DOM.CUSTOM_STYLES[OPACITY].get(el);
+ } else if (!current || (current.indexOf && current.indexOf(PX) > -1)) { // no need to convert
+ value = current;
+ } else if (Y.DOM.IE.COMPUTED[property]) { // use compute function
+ value = Y.DOM.IE.COMPUTED[property](el, property);
+ } else if (re_unit.test(current)) { // convert to pixel
+ value = ComputedStyle.getPixel(el, property) + PX;
+ } else {
+ value = current;
+ }
+ }
+
+ return value;
+ },
+
+ sizeOffsets: {
+ width: ['Left', 'Right'],
+ height: ['Top', 'Bottom'],
+ top: ['Top'],
+ bottom: ['Bottom']
+ },
+
+ getOffset: function(el, prop) {
+ var current = _getStyleObj(el)[prop], // value of "width", "top", etc.
+ capped = prop.charAt(0).toUpperCase() + prop.substr(1), // "Width", "Top", etc.
+ offset = 'offset' + capped, // "offsetWidth", "offsetTop", etc.
+ pixel = 'pixel' + capped, // "pixelWidth", "pixelTop", etc.
+ sizeOffsets = ComputedStyle.sizeOffsets[prop],
+ value = '';
+
+ // IE pixelWidth incorrect for percent
+ // manually compute by subtracting padding and border from offset size
+ // NOTE: clientWidth/Height (size minus border) is 0 when current === AUTO so offsetHeight is used
+ // reverting to auto from auto causes position stacking issues (old impl)
+ if (current === AUTO || current.indexOf('%') > -1) {
+ value = el['offset' + capped];
+
+ if (sizeOffsets[0]) {
+ value -= ComputedStyle.getPixel(el, 'padding' + sizeOffsets[0]);
+ value -= ComputedStyle.getBorderWidth(el, 'border' + sizeOffsets[0] + 'Width', 1);
+ }
+
+ if (sizeOffsets[1]) {
+ value -= ComputedStyle.getPixel(el, 'padding' + sizeOffsets[1]);
+ value -= ComputedStyle.getBorderWidth(el, 'border' + sizeOffsets[1] + 'Width', 1);
+ }
+
+ } else { // use style.pixelWidth, etc. to convert to pixels
+ // need to map style.width to currentStyle (no currentStyle.pixelWidth)
+ if (!el.style[pixel] && !el.style[prop]) {
+ el.style[prop] = current;
+ }
+ value = el.style[pixel];
+
+ }
+ return value + PX;
+ },
+
+ borderMap: {
+ thin: '2px',
+ medium: '4px',
+ thick: '6px'
+ },
+
+ getBorderWidth: function(el, property, omitUnit) {
+ var unit = omitUnit ? '' : PX,
+ current = el.currentStyle[property];
+
+ if (current.indexOf(PX) < 0) { // look up keywords
+ if (ComputedStyle.borderMap[current]) {
+ current = ComputedStyle.borderMap[current];
+ } else {
+ }
+ }
+ return (omitUnit) ? parseFloat(current) : current;
+ },
+
+ getPixel: function(node, att) {
+ // use pixelRight to convert to px
+ var val = null,
+ style = _getStyleObj(node),
+ styleRight = style.right,
+ current = style[att];
+
+ node.style.right = current;
+ val = node.style.pixelRight;
+ node.style.right = styleRight; // revert
+
+ return val;
+ },
+
+ getMargin: function(node, att) {
+ var val,
+ style = _getStyleObj(node);
+
+ if (style[att] == AUTO) {
+ val = 0;
+ } else {
+ val = ComputedStyle.getPixel(node, att);
+ }
+ return val + PX;
+ },
+
+ getVisibility: function(node, att) {
+ var current;
+ while ( (current = node.currentStyle) && current[att] == 'inherit') { // NOTE: assignment in test
+ node = node.parentNode;
+ }
+ return (current) ? current[att] : VISIBLE;
+ },
+
+ getColor: function(node, att) {
+ var current = _getStyleObj(node)[att];
+
+ if (!current || current === TRANSPARENT) {
+ Y.DOM.elementByAxis(node, 'parentNode', null, function(parent) {
+ current = _getStyleObj(parent)[att];
+ if (current && current !== TRANSPARENT) {
+ node = parent;
+ return true;
+ }
+ });
+ }
+
+ return Y.Color.toRGB(current);
+ },
+
+ getBorderColor: function(node, att) {
+ var current = _getStyleObj(node),
+ val = current[att] || current.color;
+ return Y.Color.toRGB(Y.Color.toHex(val));
+ }
+ },
+
+ //fontSize: getPixelFont,
+ IEComputed = {};
+
+// use alpha filter for IE opacity
+try {
+ if (documentElement.style[OPACITY] === UNDEFINED &&
+ documentElement[FILTERS]) {
+ Y.DOM.CUSTOM_STYLES[OPACITY] = {
+ get: function(node) {
+ var val = 100;
+ try { // will error if no DXImageTransform
+ val = node[FILTERS]['DXImageTransform.Microsoft.Alpha'][OPACITY];
+
+ } catch(e) {
+ try { // make sure its in the document
+ val = node[FILTERS]('alpha')[OPACITY];
+ } catch(err) {
+ }
+ }
+ return val / 100;
+ },
+
+ set: function(node, val, style) {
+ var current,
+ styleObj;
+
+ if (val === '') { // normalize inline style behavior
+ styleObj = _getStyleObj(node);
+ current = (OPACITY in styleObj) ? styleObj[OPACITY] : 1; // revert to original opacity
+ val = current;
+ }
+
+ if (typeof style[FILTER] == 'string') { // in case not appended
+ style[FILTER] = 'alpha(' + OPACITY + '=' + val * 100 + ')';
+
+ if (!node.currentStyle || !node.currentStyle[HAS_LAYOUT]) {
+ style.zoom = 1; // needs layout
+ }
+ }
+ }
+ };
+ }
+} catch(e) {
+}
+
+try {
+ document.createElement('div').style.height = '-1px';
+} catch(e) { // IE throws error on invalid style set; trap common cases
+ Y.DOM.CUSTOM_STYLES.height = {
+ set: function(node, val, style) {
+ var floatVal = parseFloat(val);
+ if (isNaN(floatVal) || floatVal >= 0) {
+ style.height = val;
+ } else {
+ }
+ }
+ };
+
+ Y.DOM.CUSTOM_STYLES.width = {
+ set: function(node, val, style) {
+ var floatVal = parseFloat(val);
+ if (isNaN(floatVal) || floatVal >= 0) {
+ style.width = val;
+ } else {
+ }
+ }
+ };
+}
+
+// TODO: top, right, bottom, left
+IEComputed[WIDTH] = IEComputed[HEIGHT] = ComputedStyle.getOffset;
+
+IEComputed.color = IEComputed.backgroundColor = ComputedStyle.getColor;
+
+IEComputed[BORDER_WIDTH] = IEComputed[BORDER_TOP_WIDTH] = IEComputed[BORDER_RIGHT_WIDTH] =
+ IEComputed[BORDER_BOTTOM_WIDTH] = IEComputed[BORDER_LEFT_WIDTH] =
+ ComputedStyle.getBorderWidth;
+
+IEComputed.marginTop = IEComputed.marginRight = IEComputed.marginBottom =
+ IEComputed.marginLeft = ComputedStyle.getMargin;
+
+IEComputed.visibility = ComputedStyle.getVisibility;
+IEComputed.borderColor = IEComputed.borderTopColor =
+ IEComputed.borderRightColor = IEComputed.borderBottomColor =
+ IEComputed.borderLeftColor = ComputedStyle.getBorderColor;
+
+if (!Y.config.win[GET_COMPUTED_STYLE]) {
+ Y.DOM[GET_COMPUTED_STYLE] = ComputedStyle.get;
+}
+
+Y.namespace('DOM.IE');
+Y.DOM.IE.COMPUTED = IEComputed;
+Y.DOM.IE.ComputedStyle = ComputedStyle;
+
+})(Y);
+
+
+}, '3.0.0' ,{requires:['dom-base']});
+YUI.add('dom-screen', function(Y) {
+
+(function(Y) {
+
+/**
+ * Adds position and region management functionality to DOM.
+ * @module dom
+ * @submodule dom-screen
+ * @for DOM
+ */
+
+var DOCUMENT_ELEMENT = 'documentElement',
+ COMPAT_MODE = 'compatMode',
+ POSITION = 'position',
+ FIXED = 'fixed',
+ RELATIVE = 'relative',
+ LEFT = 'left',
+ TOP = 'top',
+ _BACK_COMPAT = 'BackCompat',
+ MEDIUM = 'medium',
+ BORDER_LEFT_WIDTH = 'borderLeftWidth',
+ BORDER_TOP_WIDTH = 'borderTopWidth',
+ GET_BOUNDING_CLIENT_RECT = 'getBoundingClientRect',
+ GET_COMPUTED_STYLE = 'getComputedStyle',
+
+ // TODO: how about thead/tbody/tfoot/tr?
+ // TODO: does caption matter?
+ RE_TABLE = /^t(?:able|d|h)$/i;
+
+Y.mix(Y.DOM, {
+ /**
+ * Returns the inner height of the viewport (exludes scrollbar).
+ * @method winHeight
+ * @return {Number} The current height of the viewport.
+ */
+ winHeight: function(node) {
+ var h = Y.DOM._getWinSize(node).height;
+ return h;
+ },
+
+ /**
+ * Returns the inner width of the viewport (exludes scrollbar).
+ * @method winWidth
+ * @return {Number} The current width of the viewport.
+ */
+ winWidth: function(node) {
+ var w = Y.DOM._getWinSize(node).width;
+ return w;
+ },
+
+ /**
+ * Document height
+ * @method docHeight
+ * @return {Number} The current height of the document.
+ */
+ docHeight: function(node) {
+ var h = Y.DOM._getDocSize(node).height;
+ return Math.max(h, Y.DOM._getWinSize(node).height);
+ },
+
+ /**
+ * Document width
+ * @method docWidth
+ * @return {Number} The current width of the document.
+ */
+ docWidth: function(node) {
+ var w = Y.DOM._getDocSize(node).width;
+ return Math.max(w, Y.DOM._getWinSize(node).width);
+ },
+
+ /**
+ * Amount page has been scroll horizontally
+ * @method docScrollX
+ * @return {Number} The current amount the screen is scrolled horizontally.
+ */
+ docScrollX: function(node) {
+ var doc = Y.DOM._getDoc(node);
+ return Math.max(doc[DOCUMENT_ELEMENT].scrollLeft, doc.body.scrollLeft);
+ },
+
+ /**
+ * Amount page has been scroll vertically
+ * @method docScrollY
+ * @return {Number} The current amount the screen is scrolled vertically.
+ */
+ docScrollY: function(node) {
+ var doc = Y.DOM._getDoc(node);
+ return Math.max(doc[DOCUMENT_ELEMENT].scrollTop, doc.body.scrollTop);
+ },
+
+ /**
+ * Gets the current position of an element based on page coordinates.
+ * Element must be part of the DOM tree to have page coordinates
+ * (display:none or elements not appended return false).
+ * @method getXY
+ * @param element The target element
+ * @return {Array} The XY position of the element
+
+ TODO: test inDocument/display?
+ */
+ getXY: function() {
+ if (document[DOCUMENT_ELEMENT][GET_BOUNDING_CLIENT_RECT]) {
+ return function(node) {
+ var xy = null,
+ scrollLeft,
+ scrollTop,
+ box,
+ off1, off2,
+ bLeft, bTop,
+ mode,
+ doc;
+
+ if (node) {
+ if (Y.DOM.inDoc(node)) {
+ scrollLeft = Y.DOM.docScrollX(node);
+ scrollTop = Y.DOM.docScrollY(node);
+ box = node[GET_BOUNDING_CLIENT_RECT]();
+ doc = Y.DOM._getDoc(node);
+ xy = [box.left, box.top];
+
+ if (Y.UA.ie) {
+ off1 = 2;
+ off2 = 2;
+ mode = doc[COMPAT_MODE];
+ bLeft = Y.DOM[GET_COMPUTED_STYLE](doc[DOCUMENT_ELEMENT], BORDER_LEFT_WIDTH);
+ bTop = Y.DOM[GET_COMPUTED_STYLE](doc[DOCUMENT_ELEMENT], BORDER_TOP_WIDTH);
+
+ if (Y.UA.ie === 6) {
+ if (mode !== _BACK_COMPAT) {
+ off1 = 0;
+ off2 = 0;
+ }
+ }
+
+ if ((mode == _BACK_COMPAT)) {
+ if (bLeft !== MEDIUM) {
+ off1 = parseInt(bLeft, 10);
+ }
+ if (bTop !== MEDIUM) {
+ off2 = parseInt(bTop, 10);
+ }
+ }
+
+ xy[0] -= off1;
+ xy[1] -= off2;
+
+ }
+
+ if ((scrollTop || scrollLeft)) {
+ xy[0] += scrollLeft;
+ xy[1] += scrollTop;
+ }
+ } else { // default to current offsets
+ xy = Y.DOM._getOffset(node);
+ }
+ }
+ return xy;
+ };
+ } else {
+ return function(node) { // manually calculate by crawling up offsetParents
+ //Calculate the Top and Left border sizes (assumes pixels)
+ var xy = null,
+ parentNode,
+ bCheck,
+ scrollTop,
+ scrollLeft;
+
+ if (node) {
+ if (Y.DOM.inDoc(node)) {
+ xy = [node.offsetLeft, node.offsetTop];
+ parentNode = node;
+ // TODO: refactor with !! or just falsey
+ bCheck = ((Y.UA.gecko || Y.UA.webkit > 519) ? true : false);
+
+ // TODO: worth refactoring for TOP/LEFT only?
+ while ((parentNode = parentNode.offsetParent)) {
+ xy[0] += parentNode.offsetLeft;
+ xy[1] += parentNode.offsetTop;
+ if (bCheck) {
+ xy = Y.DOM._calcBorders(parentNode, xy);
+ }
+ }
+
+ // account for any scrolled ancestors
+ if (Y.DOM.getStyle(node, POSITION) != FIXED) {
+ parentNode = node;
+
+ while ((parentNode = parentNode.parentNode)) {
+ scrollTop = parentNode.scrollTop;
+ scrollLeft = parentNode.scrollLeft;
+
+ //Firefox does something funky with borders when overflow is not visible.
+ if (Y.UA.gecko && (Y.DOM.getStyle(parentNode, 'overflow') !== 'visible')) {
+ xy = Y.DOM._calcBorders(parentNode, xy);
+ }
+
+
+ if (scrollTop || scrollLeft) {
+ xy[0] -= scrollLeft;
+ xy[1] -= scrollTop;
+ }
+ }
+ xy[0] += Y.DOM.docScrollX(node);
+ xy[1] += Y.DOM.docScrollY(node);
+
+ } else {
+ //Fix FIXED position -- add scrollbars
+ xy[0] += Y.DOM.docScrollX(node);
+ xy[1] += Y.DOM.docScrollY(node);
+ }
+ } else {
+ xy = Y.DOM._getOffset(node);
+ }
+ }
+
+ return xy;
+ };
+ }
+ }(),// NOTE: Executing for loadtime branching
+
+ _getOffset: function(node) {
+ var pos,
+ xy = null;
+
+ if (node) {
+ pos = Y.DOM.getStyle(node, POSITION);
+ xy = [
+ parseInt(Y.DOM[GET_COMPUTED_STYLE](node, LEFT), 10),
+ parseInt(Y.DOM[GET_COMPUTED_STYLE](node, TOP), 10)
+ ];
+
+ if ( isNaN(xy[0]) ) { // in case of 'auto'
+ xy[0] = parseInt(Y.DOM.getStyle(node, LEFT), 10); // try inline
+ if ( isNaN(xy[0]) ) { // default to offset value
+ xy[0] = (pos === RELATIVE) ? 0 : node.offsetLeft || 0;
+ }
+ }
+
+ if ( isNaN(xy[1]) ) { // in case of 'auto'
+ xy[1] = parseInt(Y.DOM.getStyle(node, TOP), 10); // try inline
+ if ( isNaN(xy[1]) ) { // default to offset value
+ xy[1] = (pos === RELATIVE) ? 0 : node.offsetTop || 0;
+ }
+ }
+ }
+
+ return xy;
+
+ },
+
+ /**
+ * Gets the current X position of an element based on page coordinates.
+ * Element must be part of the DOM tree to have page coordinates
+ * (display:none or elements not appended return false).
+ * @method getX
+ * @param element The target element
+ * @return {Int} The X position of the element
+ */
+
+ getX: function(node) {
+ return Y.DOM.getXY(node)[0];
+ },
+
+ /**
+ * Gets the current Y position of an element based on page coordinates.
+ * Element must be part of the DOM tree to have page coordinates
+ * (display:none or elements not appended return false).
+ * @method getY
+ * @param element The target element
+ * @return {Int} The Y position of the element
+ */
+
+ getY: function(node) {
+ return Y.DOM.getXY(node)[1];
+ },
+
+ /**
+ * Set the position of an html element in page coordinates.
+ * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+ * @method setXY
+ * @param element The target element
+ * @param {Array} xy Contains X & Y values for new position (coordinates are page-based)
+ * @param {Boolean} noRetry By default we try and set the position a second time if the first fails
+ */
+ setXY: function(node, xy, noRetry) {
+ var setStyle = Y.DOM.setStyle,
+ pos,
+ delta,
+ newXY,
+ currentXY;
+
+ if (node && xy) {
+ pos = Y.DOM.getStyle(node, POSITION);
+
+ delta = Y.DOM._getOffset(node);
+
+ if (pos == 'static') { // default to relative
+ pos = RELATIVE;
+ setStyle(node, POSITION, pos);
+ }
+
+ currentXY = Y.DOM.getXY(node);
+
+ if (xy[0] !== null) {
+ setStyle(node, LEFT, xy[0] - currentXY[0] + delta[0] + 'px');
+ }
+
+ if (xy[1] !== null) {
+ setStyle(node, TOP, xy[1] - currentXY[1] + delta[1] + 'px');
+ }
+
+ if (!noRetry) {
+ newXY = Y.DOM.getXY(node);
+ if (newXY[0] !== xy[0] || newXY[1] !== xy[1]) {
+ Y.DOM.setXY(node, xy, true);
+ }
+ }
+
+ } else {
+ }
+ },
+
+ /**
+ * Set the X position of an html element in page coordinates, regardless of how the element is positioned.
+ * The element(s) must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+ * @method setX
+ * @param element The target element
+ * @param {Int} x The X values for new position (coordinates are page-based)
+ */
+ setX: function(node, x) {
+ return Y.DOM.setXY(node, [x, null]);
+ },
+
+ /**
+ * Set the Y position of an html element in page coordinates, regardless of how the element is positioned.
+ * The element(s) must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+ * @method setY
+ * @param element The target element
+ * @param {Int} y The Y values for new position (coordinates are page-based)
+ */
+ setY: function(node, y) {
+ return Y.DOM.setXY(node, [null, y]);
+ },
+
+ _calcBorders: function(node, xy2) {
+ var t = parseInt(Y.DOM[GET_COMPUTED_STYLE](node, BORDER_TOP_WIDTH), 10) || 0,
+ l = parseInt(Y.DOM[GET_COMPUTED_STYLE](node, BORDER_LEFT_WIDTH), 10) || 0;
+ if (Y.UA.gecko) {
+ if (RE_TABLE.test(node.tagName)) {
+ t = 0;
+ l = 0;
+ }
+ }
+ xy2[0] += l;
+ xy2[1] += t;
+ return xy2;
+ },
+
+ _getWinSize: function(node) {
+ var doc = Y.DOM._getDoc(),
+ win = doc.defaultView || doc.parentWindow,
+ mode = doc[COMPAT_MODE],
+ h = win.innerHeight,
+ w = win.innerWidth,
+ root = doc[DOCUMENT_ELEMENT];
+
+ if ( mode && !Y.UA.opera ) { // IE, Gecko
+ if (mode != 'CSS1Compat') { // Quirks
+ root = doc.body;
+ }
+ h = root.clientHeight;
+ w = root.clientWidth;
+ }
+ return { height: h, width: w };
+ },
+
+ _getDocSize: function(node) {
+ var doc = Y.DOM._getDoc(),
+ root = doc[DOCUMENT_ELEMENT];
+
+ if (doc[COMPAT_MODE] != 'CSS1Compat') {
+ root = doc.body;
+ }
+
+ return { height: root.scrollHeight, width: root.scrollWidth };
+ }
+});
+})(Y);
+(function(Y) {
+var TOP = 'top',
+ RIGHT = 'right',
+ BOTTOM = 'bottom',
+ LEFT = 'left',
+
+ getOffsets = function(r1, r2) {
+ var t = Math.max(r1[TOP], r2[TOP]),
+ r = Math.min(r1[RIGHT], r2[RIGHT]),
+ b = Math.min(r1[BOTTOM], r2[BOTTOM]),
+ l = Math.max(r1[LEFT], r2[LEFT]),
+ ret = {};
+
+ ret[TOP] = t;
+ ret[RIGHT] = r;
+ ret[BOTTOM] = b;
+ ret[LEFT] = l;
+ return ret;
+ },
+
+ DOM = Y.DOM;
+
+Y.mix(DOM, {
+ /**
+ * Returns an Object literal containing the following about this element: (top, right, bottom, left)
+ * @method region
+ * @param {HTMLElement} element The DOM element.
+ @return {Object} Object literal containing the following about this element: (top, right, bottom, left)
+ */
+ region: function(node) {
+ var xy = DOM.getXY(node),
+ ret = false;
+
+ if (node && xy) {
+ ret = DOM._getRegion(
+ xy[1], // top
+ xy[0] + node.offsetWidth, // right
+ xy[1] + node.offsetHeight, // bottom
+ xy[0] // left
+ );
+ }
+
+ return ret;
+ },
+
+ /**
+ * Find the intersect information for the passes nodes.
+ * @method intersect
+ * @param {HTMLElement} element The first element
+ * @param {HTMLElement | Object} element2 The element or region to check the interect with
+ * @param {Object} altRegion An object literal containing the region for the first element if we already have the data (for performance i.e. DragDrop)
+ @return {Object} Object literal containing the following intersection data: (top, right, bottom, left, area, yoff, xoff, inRegion)
+ */
+ intersect: function(node, node2, altRegion) {
+ var r = altRegion || DOM.region(node), region = {},
+ n = node2,
+ off;
+
+ if (n.tagName) {
+ region = DOM.region(n);
+ } else if (Y.Lang.isObject(node2)) {
+ region = node2;
+ } else {
+ return false;
+ }
+
+ off = getOffsets(region, r);
+ return {
+ top: off[TOP],
+ right: off[RIGHT],
+ bottom: off[BOTTOM],
+ left: off[LEFT],
+ area: ((off[BOTTOM] - off[TOP]) * (off[RIGHT] - off[LEFT])),
+ yoff: ((off[BOTTOM] - off[TOP])),
+ xoff: (off[RIGHT] - off[LEFT]),
+ inRegion: DOM.inRegion(node, node2, false, altRegion)
+ };
+
+ },
+ /**
+ * Check if any part of this node is in the passed region
+ * @method inRegion
+ * @param {Object} node2 The node to get the region from or an Object literal of the region
+ * $param {Boolean} all Should all of the node be inside the region
+ * @param {Object} altRegion An object literal containing the region for this node if we already have the data (for performance i.e. DragDrop)
+ * @return {Boolean} True if in region, false if not.
+ */
+ inRegion: function(node, node2, all, altRegion) {
+ var region = {},
+ r = altRegion || DOM.region(node),
+ n = node2,
+ off;
+
+ if (n.tagName) {
+ region = DOM.region(n);
+ } else if (Y.Lang.isObject(node2)) {
+ region = node2;
+ } else {
+ return false;
+ }
+
+ if (all) {
+ return (
+ r[LEFT] >= region[LEFT] &&
+ r[RIGHT] <= region[RIGHT] &&
+ r[TOP] >= region[TOP] &&
+ r[BOTTOM] <= region[BOTTOM] );
+ } else {
+ off = getOffsets(region, r);
+ if (off[BOTTOM] >= off[TOP] && off[RIGHT] >= off[LEFT]) {
+ return true;
+ } else {
+ return false;
+ }
+
+ }
+ },
+
+ /**
+ * Check if any part of this element is in the viewport
+ * @method inViewportRegion
+ * @param {HTMLElement} element The DOM element.
+ * @param {Boolean} all Should all of the node be inside the region
+ * @param {Object} altRegion An object literal containing the region for this node if we already have the data (for performance i.e. DragDrop)
+ * @return {Boolean} True if in region, false if not.
+ */
+ inViewportRegion: function(node, all, altRegion) {
+ return DOM.inRegion(node, DOM.viewportRegion(node), all, altRegion);
+
+ },
+
+ _getRegion: function(t, r, b, l) {
+ var region = {};
+
+ region[TOP] = region[1] = t;
+ region[LEFT] = region[0] = l;
+ region[BOTTOM] = b;
+ region[RIGHT] = r;
+ region.width = region[RIGHT] - region[LEFT];
+ region.height = region[BOTTOM] - region[TOP];
+
+ return region;
+ },
+
+ /**
+ * Returns an Object literal containing the following about the visible region of viewport: (top, right, bottom, left)
+ * @method viewportRegion
+ @return {Object} Object literal containing the following about the visible region of the viewport: (top, right, bottom, left)
+ */
+ viewportRegion: function(node) {
+ node = node || Y.config.doc.documentElement;
+ var ret = false,
+ scrollX,
+ scrollY;
+
+ if (node) {
+ scrollX = DOM.docScrollX(node);
+ scrollY = DOM.docScrollY(node);
+
+ ret = DOM._getRegion(scrollY, // top
+ DOM.winWidth(node) + scrollX, // right
+ scrollY + DOM.winHeight(node), // bottom
+ scrollX); // left
+ }
+
+ return ret;
+ }
+});
+})(Y);
+
+
+}, '3.0.0' ,{requires:['dom-base', 'dom-style']});
+YUI.add('selector-native', function(Y) {
+
+(function(Y) {
+/**
+ * The selector-native module provides support for native querySelector
+ * @module dom
+ * @submodule selector-native
+ * @for Selector
+ */
+
+/**
+ * Provides support for using CSS selectors to query the DOM
+ * @class Selector
+ * @static
+ * @for Selector
+ */
+
+Y.namespace('Selector'); // allow native module to standalone
+
+var COMPARE_DOCUMENT_POSITION = 'compareDocumentPosition',
+ OWNER_DOCUMENT = 'ownerDocument',
+ TMP_PREFIX = 'yui-tmp-',
+ g_counter = 0;
+
+var Selector = {
+ _foundCache: [],
+
+ useNative: true,
+
+ _compare: ('sourceIndex' in document.documentElement) ?
+ function(nodeA, nodeB) {
+ var a = nodeA.sourceIndex,
+ b = nodeB.sourceIndex;
+
+ if (a === b) {
+ return 0;
+ } else if (a > b) {
+ return 1;
+ }
+
+ return -1;
+
+ } : (document.documentElement[COMPARE_DOCUMENT_POSITION] ?
+ function(nodeA, nodeB) {
+ if (nodeA[COMPARE_DOCUMENT_POSITION](nodeB) & 4) {
+ return -1;
+ } else {
+ return 1;
+ }
+ } :
+ function(nodeA, nodeB) {
+ var rangeA, rangeB, compare;
+ if (nodeA && nodeB) {
+ rangeA = nodeA[OWNER_DOCUMENT].createRange();
+ rangeA.setStart(nodeA, 0);
+ rangeB = nodeB[OWNER_DOCUMENT].createRange();
+ rangeB.setStart(nodeB, 0);
+ compare = rangeA.compareBoundaryPoints(1, rangeB); // 1 === Range.START_TO_END
+ }
+
+ return compare;
+
+ }),
+
+ _sort: function(nodes) {
+ if (nodes) {
+ nodes = Y.Array(nodes, 0, true);
+ if (nodes.sort) {
+ nodes.sort(Selector._compare);
+ }
+ }
+
+ return nodes;
+ },
+
+ _deDupe: function(nodes) {
+ var ret = [],
+ i, node;
+
+ for (i = 0; (node = nodes[i++]);) {
+ if (!node._found) {
+ ret[ret.length] = node;
+ node._found = true;
+ }
+ }
+
+ for (i = 0; (node = ret[i++]);) {
+ node._found = null;
+ node.removeAttribute('_found');
+ }
+
+ return ret;
+ },
+
+ /**
+ * Retrieves a set of nodes based on a given CSS selector.
+ * @method query
+ *
+ * @param {string} selector The CSS Selector to test the node against.
+ * @param {HTMLElement} root optional An HTMLElement to start the query from. Defaults to Y.config.doc
+ * @param {Boolean} firstOnly optional Whether or not to return only the first match.
+ * @return {Array} An array of nodes that match the given selector.
+ * @static
+ */
+ query: function(selector, root, firstOnly, skipNative) {
+ root = root || Y.config.doc;
+ var ret = [],
+ useNative = (Y.Selector.useNative && document.querySelector && !skipNative),
+ queries = [[selector, root]],
+ query,
+ result,
+ i,
+ fn = (useNative) ? Y.Selector._nativeQuery : Y.Selector._bruteQuery;
+
+ if (selector && fn) {
+ // split group into seperate queries
+ if (!skipNative && // already done if skipping
+ (!useNative || root.tagName)) { // split native when element scoping is needed
+ queries = Selector._splitQueries(selector, root);
+ }
+
+ for (i = 0; (query = queries[i++]);) {
+ result = fn(query[0], query[1], firstOnly);
+ if (!firstOnly) { // coerce DOM Collection to Array
+ result = Y.Array(result, 0, true);
+ }
+ if (result) {
+ ret = ret.concat(result);
+ }
+ }
+
+ if (queries.length > 1) { // remove dupes and sort by doc order
+ ret = Selector._sort(Selector._deDupe(ret));
+ }
+ }
+
+ return (firstOnly) ? (ret[0] || null) : ret;
+
+ },
+
+ // allows element scoped queries to begin with combinator
+ // e.g. query('> p', document.body) === query('body > p')
+ _splitQueries: function(selector, node) {
+ var groups = selector.split(','),
+ queries = [],
+ prefix = '',
+ i, len;
+
+ if (node) {
+ // enforce for element scoping
+ if (node.tagName) {
+ node.id = node.id || Y.guid();
+ prefix = '#' + node.id + ' ';
+ }
+
+ for (i = 0, len = groups.length; i < len; ++i) {
+ selector = prefix + groups[i];
+ queries.push([selector, node]);
+ }
+ }
+
+ return queries;
+ },
+
+ _nativeQuery: function(selector, root, one) {
+ try {
+ return root['querySelector' + (one ? '' : 'All')](selector);
+ } catch(e) { // fallback to brute if available
+ return Y.Selector.query(selector, root, one, true); // redo with skipNative true
+ }
+ },
+
+ filter: function(nodes, selector) {
+ var ret = [],
+ i, node;
+
+ if (nodes && selector) {
+ for (i = 0; (node = nodes[i++]);) {
+ if (Y.Selector.test(node, selector)) {
+ ret[ret.length] = node;
+ }
+ }
+ } else {
+ }
+
+ return ret;
+ },
+
+ test: function(node, selector, root) {
+ var ret = false,
+ groups = selector.split(','),
+ item,
+ i, group;
+
+ if (node && node.tagName) { // only test HTMLElements
+ root = root || node.ownerDocument;
+
+ if (!node.id) {
+ node.id = TMP_PREFIX + g_counter++;
+ }
+ for (i = 0; (group = groups[i++]);) { // TODO: off-dom test
+ group += '#' + node.id; // add ID for uniqueness
+ item = Y.Selector.query(group, root, true);
+ ret = (item === node);
+ if (ret) {
+ break;
+ }
+ }
+ }
+
+ return ret;
+ }
+};
+
+Y.mix(Y.Selector, Selector, true);
+
+})(Y);
+
+
+}, '3.0.0' ,{requires:['dom-base']});
+YUI.add('selector-css2', function(Y) {
+
+/**
+ * The selector module provides helper methods allowing CSS2 Selectors to be used with DOM elements.
+ * @module dom
+ * @submodule selector-css2
+ * @for Selector
+ */
+
+/**
+ * Provides helper methods for collecting and filtering DOM elements.
+ */
+
+var PARENT_NODE = 'parentNode',
+ TAG_NAME = 'tagName',
+ ATTRIBUTES = 'attributes',
+ COMBINATOR = 'combinator',
+ PSEUDOS = 'pseudos',
+
+ Selector = Y.Selector,
+
+ SelectorCSS2 = {
+ SORT_RESULTS: true,
+ _children: function(node, tag) {
+ var ret = node.children,
+ i,
+ children = [],
+ childNodes,
+ child;
+
+ if (node.children && tag && node.children.tags) {
+ children = node.children.tags(tag);
+ } else if ((!ret && node[TAG_NAME]) || (ret && tag)) { // only HTMLElements have children
+ childNodes = ret || node.childNodes;
+ ret = [];
+ for (i = 0; (child = childNodes[i++]);) {
+ if (child.tagName) {
+ if (!tag || tag === child.tagName) {
+ ret.push(child);
+ }
+ }
+ }
+ }
+
+ return ret || [];
+ },
+
+ _regexCache: {},
+
+ _re: {
+ attr: /(\[.*\])/g,
+ pseudos: /:([\-\w]+(?:\(?:['"]?(.+)['"]?\)))*/i
+ },
+
+ /**
+ * Mapping of shorthand tokens to corresponding attribute selector
+ * @property shorthand
+ * @type object
+ */
+ shorthand: {
+ '\\#(-?[_a-z]+[-\\w]*)': '[id=$1]',
+ '\\.(-?[_a-z]+[-\\w]*)': '[className~=$1]'
+ },
+
+ /**
+ * List of operators and corresponding boolean functions.
+ * These functions are passed the attribute and the current node's value of the attribute.
+ * @property operators
+ * @type object
+ */
+ operators: {
+ '': function(node, attr) { return Y.DOM.getAttribute(node, attr) !== ''; }, // Just test for existence of attribute
+ //'': '.+',
+ //'=': '^{val}$', // equality
+ '~=': '(?:^|\\s+){val}(?:\\s+|$)', // space-delimited
+ '|=': '^{val}-?' // optional hyphen-delimited
+ },
+
+ pseudos: {
+ 'first-child': function(node) {
+ return Y.Selector._children(node[PARENT_NODE])[0] === node;
+ }
+ },
+
+ _bruteQuery: function(selector, root, firstOnly) {
+ var ret = [],
+ nodes = [],
+ tokens = Selector._tokenize(selector),
+ token = tokens[tokens.length - 1],
+ rootDoc = Y.DOM._getDoc(root),
+ id,
+ className,
+ tagName;
+
+
+ // if we have an initial ID, set to root when in document
+ if (tokens[0] && rootDoc === root &&
+ (id = tokens[0].id) &&
+ rootDoc.getElementById(id)) {
+ root = rootDoc.getElementById(id);
+ }
+
+ if (token) {
+ // prefilter nodes
+ id = token.id;
+ className = token.className;
+ tagName = token.tagName || '*';
+
+ // try ID first
+ if (id) {
+ if (rootDoc.getElementById(id)) { // if in document
+ nodes = [rootDoc.getElementById(id)]; // TODO: DOM.byId?
+ }
+ // try className if supported
+ } else if (className) {
+ nodes = root.getElementsByClassName(className);
+ } else if (tagName) { // default to tagName
+ nodes = root.getElementsByTagName(tagName || '*');
+ }
+
+ if (nodes.length) {
+ ret = Selector._filterNodes(nodes, tokens, firstOnly);
+ }
+ }
+
+ return ret;
+ },
+
+ _filterNodes: function(nodes, tokens, firstOnly) {
+ var i = 0,
+ j,
+ len = tokens.length,
+ n = len - 1,
+ result = [],
+ node = nodes[0],
+ tmpNode = node,
+ getters = Y.Selector.getters,
+ operator,
+ combinator,
+ token,
+ path,
+ pass,
+ //FUNCTION = 'function',
+ value,
+ tests,
+ test;
+
+ //do {
+ for (i = 0; (tmpNode = node = nodes[i++]);) {
+ n = len - 1;
+ path = null;
+
+ testLoop:
+ while (tmpNode && tmpNode.tagName) {
+ token = tokens[n];
+ tests = token.tests;
+ j = tests.length;
+ if (j && !pass) {
+ while ((test = tests[--j])) {
+ operator = test[1];
+ if (getters[test[0]]) {
+ value = getters[test[0]](tmpNode, test[0]);
+ } else {
+ value = tmpNode[test[0]];
+ // use getAttribute for non-standard attributes
+ if (value === undefined && tmpNode.getAttribute) {
+ value = tmpNode.getAttribute(test[0]);
+ }
+ }
+
+ if ((operator === '=' && value !== test[2]) || // fast path for equality
+ (operator.test && !operator.test(value)) || // regex test
+ (operator.call && !operator(tmpNode, test[0]))) { // function test
+
+ // skip non element nodes or non-matching tags
+ if ((tmpNode = tmpNode[path])) {
+ while (tmpNode &&
+ (!tmpNode.tagName ||
+ (token.tagName && token.tagName !== tmpNode.tagName))
+ ) {
+ tmpNode = tmpNode[path];
+ }
+ }
+ continue testLoop;
+ }
+ }
+ }
+
+ n--; // move to next token
+ // now that we've passed the test, move up the tree by combinator
+ if (!pass && (combinator = token.combinator)) {
+ path = combinator.axis;
+ tmpNode = tmpNode[path];
+
+ // skip non element nodes
+ while (tmpNode && !tmpNode.tagName) {
+ tmpNode = tmpNode[path];
+ }
+
+ if (combinator.direct) { // one pass only
+ path = null;
+ }
+
+ } else { // success if we made it this far
+ result.push(node);
+ if (firstOnly) {
+ return result;
+ }
+ break;
+ }
+ }
+ }// while (tmpNode = node = nodes[++i]);
+ node = tmpNode = null;
+ return result;
+ },
+
+ _getRegExp: function(str, flags) {
+ var regexCache = Selector._regexCache;
+ flags = flags || '';
+ if (!regexCache[str + flags]) {
+ regexCache[str + flags] = new RegExp(str, flags);
+ }
+ return regexCache[str + flags];
+ },
+
+ combinators: {
+ ' ': {
+ axis: 'parentNode'
+ },
+
+ '>': {
+ axis: 'parentNode',
+ direct: true
+ },
+
+
+ '+': {
+ axis: 'previousSibling',
+ direct: true
+ }
+ },
+
+ _parsers: [
+ {
+ name: ATTRIBUTES,
+ re: /^\[([a-z]+\w*)+([~\|\^\$\*!=]=?)?['"]?([^\]]*?)['"]?\]/i,
+ fn: function(match, token) {
+ var operator = match[2] || '',
+ operators = Y.Selector.operators,
+ test;
+
+ // add prefiltering for ID and CLASS
+ if ((match[1] === 'id' && operator === '=') ||
+ (match[1] === 'className' &&
+ document.getElementsByClassName &&
+ (operator === '~=' || operator === '='))) {
+ token.prefilter = match[1];
+ token[match[1]] = match[3];
+ }
+
+ // add tests
+ if (operator in operators) {
+ test = operators[operator];
+ if (typeof test === 'string') {
+ test = Y.Selector._getRegExp(test.replace('{val}', match[3]));
+ }
+ match[2] = test;
+ }
+ if (!token.last || token.prefilter !== match[1]) {
+ return match.slice(1);
+ }
+ }
+
+ },
+ {
+ name: TAG_NAME,
+ re: /^((?:-?[_a-z]+[\w-]*)|\*)/i,
+ fn: function(match, token) {
+ var tag = match[1].toUpperCase();
+ token.tagName = tag;
+
+ if (tag !== '*' && (!token.last || token.prefilter)) {
+ return [TAG_NAME, '=', tag];
+ }
+ if (!token.prefilter) {
+ token.prefilter = 'tagName';
+ }
+ }
+ },
+ {
+ name: COMBINATOR,
+ re: /^\s*([>+~]|\s)\s*/,
+ fn: function(match, token) {
+ }
+ },
+ {
+ name: PSEUDOS,
+ re: /^:([\-\w]+)(?:\(['"]?(.+)['"]?\))*/i,
+ fn: function(match, token) {
+ var test = Selector[PSEUDOS][match[1]];
+ if (test) { // reorder match array
+ return [match[2], test];
+ } else { // selector token not supported (possibly missing CSS3 module)
+ return false;
+ }
+ }
+ }
+ ],
+
+ _getToken: function(token) {
+ return {
+ tagName: null,
+ id: null,
+ className: null,
+ attributes: {},
+ combinator: null,
+ tests: []
+ };
+ },
+
+ /**
+ Break selector into token units per simple selector.
+ Combinator is attached to the previous token.
+ */
+ _tokenize: function(selector) {
+ selector = selector || '';
+ selector = Selector._replaceShorthand(Y.Lang.trim(selector));
+ var token = Selector._getToken(), // one token per simple selector (left selector holds combinator)
+ query = selector, // original query for debug report
+ tokens = [], // array of tokens
+ found = false, // whether or not any matches were found this pass
+ match, // the regex match
+ test,
+ i, parser;
+
+ /*
+ Search for selector patterns, store, and strip them from the selector string
+ until no patterns match (invalid selector) or we run out of chars.
+
+ Multiple attributes and pseudos are allowed, in any order.
+ for example:
+ 'form:first-child[type=button]:not(button)[lang|=en]'
+ */
+ outer:
+ do {
+ found = false; // reset after full pass
+ for (i = 0; (parser = Selector._parsers[i++]);) {
+ if ( (match = parser.re.exec(selector)) ) { // note assignment
+ if (parser !== COMBINATOR ) {
+ token.selector = selector;
+ }
+ selector = selector.replace(match[0], ''); // strip current match from selector
+ if (!selector.length) {
+ token.last = true;
+ }
+
+ if (Selector._attrFilters[match[1]]) { // convert class to className, etc.
+ match[1] = Selector._attrFilters[match[1]];
+ }
+
+ test = parser.fn(match, token);
+ if (test === false) { // selector not supported
+ found = false;
+ break outer;
+ } else if (test) {
+ token.tests.push(test);
+ }
+
+ if (!selector.length || parser.name === COMBINATOR) {
+ tokens.push(token);
+ token = Selector._getToken(token);
+ if (parser.name === COMBINATOR) {
+ token.combinator = Y.Selector.combinators[match[1]];
+ }
+ }
+ found = true;
+ }
+ }
+ } while (found && selector.length);
+
+ if (!found || selector.length) { // not fully parsed
+ tokens = [];
+ }
+ return tokens;
+ },
+
+ _replaceShorthand: function(selector) {
+ var shorthand = Selector.shorthand,
+ attrs = selector.match(Selector._re.attr), // pull attributes to avoid false pos on "." and "#"
+ pseudos = selector.match(Selector._re.pseudos), // pull attributes to avoid false pos on "." and "#"
+ re, i, len;
+
+ if (pseudos) {
+ selector = selector.replace(Selector._re.pseudos, '!!REPLACED_PSEUDO!!');
+ }
+
+ if (attrs) {
+ selector = selector.replace(Selector._re.attr, '!!REPLACED_ATTRIBUTE!!');
+ }
+
+ for (re in shorthand) {
+ if (shorthand.hasOwnProperty(re)) {
+ selector = selector.replace(Selector._getRegExp(re, 'gi'), shorthand[re]);
+ }
+ }
+
+ if (attrs) {
+ for (i = 0, len = attrs.length; i < len; ++i) {
+ selector = selector.replace('!!REPLACED_ATTRIBUTE!!', attrs[i]);
+ }
+ }
+ if (pseudos) {
+ for (i = 0, len = pseudos.length; i < len; ++i) {
+ selector = selector.replace('!!REPLACED_PSEUDO!!', pseudos[i]);
+ }
+ }
+ return selector;
+ },
+
+ _attrFilters: {
+ 'class': 'className',
+ 'for': 'htmlFor'
+ },
+
+ getters: {
+ href: function(node, attr) {
+ return Y.DOM.getAttribute(node, attr);
+ }
+ }
+ };
+
+Y.mix(Y.Selector, SelectorCSS2, true);
+Y.Selector.getters.src = Y.Selector.getters.rel = Y.Selector.getters.href;
+
+// IE wants class with native queries
+if (Y.Selector.useNative && document.querySelector) {
+ Y.Selector.shorthand['\\.(-?[_a-z]+[-\\w]*)'] = '[class~=$1]';
+}
+
+
+
+}, '3.0.0' ,{requires:['selector-native']});
+
+
+YUI.add('selector', function(Y){}, '3.0.0' ,{use:['selector-native', 'selector-css2']});
+
+
+
+YUI.add('dom', function(Y){}, '3.0.0' ,{use:['dom-base', 'dom-style', 'dom-screen', 'selector']});
+
diff --git a/lib/yui/3.0.0/dom/selector-css2-debug.js b/lib/yui/3.0.0/dom/selector-css2-debug.js
new file mode 100644
index 0000000000..0f2c11b718
--- /dev/null
+++ b/lib/yui/3.0.0/dom/selector-css2-debug.js
@@ -0,0 +1,450 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('selector-css2', function(Y) {
+
+/**
+ * The selector module provides helper methods allowing CSS2 Selectors to be used with DOM elements.
+ * @module dom
+ * @submodule selector-css2
+ * @for Selector
+ */
+
+/**
+ * Provides helper methods for collecting and filtering DOM elements.
+ */
+
+var PARENT_NODE = 'parentNode',
+ TAG_NAME = 'tagName',
+ ATTRIBUTES = 'attributes',
+ COMBINATOR = 'combinator',
+ PSEUDOS = 'pseudos',
+
+ Selector = Y.Selector,
+
+ SelectorCSS2 = {
+ SORT_RESULTS: true,
+ _children: function(node, tag) {
+ var ret = node.children,
+ i,
+ children = [],
+ childNodes,
+ child;
+
+ if (node.children && tag && node.children.tags) {
+ children = node.children.tags(tag);
+ } else if ((!ret && node[TAG_NAME]) || (ret && tag)) { // only HTMLElements have children
+ childNodes = ret || node.childNodes;
+ ret = [];
+ for (i = 0; (child = childNodes[i++]);) {
+ if (child.tagName) {
+ if (!tag || tag === child.tagName) {
+ ret.push(child);
+ }
+ }
+ }
+ }
+
+ return ret || [];
+ },
+
+ _regexCache: {},
+
+ _re: {
+ attr: /(\[.*\])/g,
+ pseudos: /:([\-\w]+(?:\(?:['"]?(.+)['"]?\)))*/i
+ },
+
+ /**
+ * Mapping of shorthand tokens to corresponding attribute selector
+ * @property shorthand
+ * @type object
+ */
+ shorthand: {
+ '\\#(-?[_a-z]+[-\\w]*)': '[id=$1]',
+ '\\.(-?[_a-z]+[-\\w]*)': '[className~=$1]'
+ },
+
+ /**
+ * List of operators and corresponding boolean functions.
+ * These functions are passed the attribute and the current node's value of the attribute.
+ * @property operators
+ * @type object
+ */
+ operators: {
+ '': function(node, attr) { return Y.DOM.getAttribute(node, attr) !== ''; }, // Just test for existence of attribute
+ //'': '.+',
+ //'=': '^{val}$', // equality
+ '~=': '(?:^|\\s+){val}(?:\\s+|$)', // space-delimited
+ '|=': '^{val}-?' // optional hyphen-delimited
+ },
+
+ pseudos: {
+ 'first-child': function(node) {
+ return Y.Selector._children(node[PARENT_NODE])[0] === node;
+ }
+ },
+
+ _bruteQuery: function(selector, root, firstOnly) {
+ var ret = [],
+ nodes = [],
+ tokens = Selector._tokenize(selector),
+ token = tokens[tokens.length - 1],
+ rootDoc = Y.DOM._getDoc(root),
+ id,
+ className,
+ tagName;
+
+
+ // if we have an initial ID, set to root when in document
+ if (tokens[0] && rootDoc === root &&
+ (id = tokens[0].id) &&
+ rootDoc.getElementById(id)) {
+ root = rootDoc.getElementById(id);
+ }
+
+ if (token) {
+ // prefilter nodes
+ id = token.id;
+ className = token.className;
+ tagName = token.tagName || '*';
+
+ // try ID first
+ if (id) {
+ if (rootDoc.getElementById(id)) { // if in document
+ nodes = [rootDoc.getElementById(id)]; // TODO: DOM.byId?
+ }
+ // try className if supported
+ } else if (className) {
+ nodes = root.getElementsByClassName(className);
+ } else if (tagName) { // default to tagName
+ nodes = root.getElementsByTagName(tagName || '*');
+ }
+
+ if (nodes.length) {
+ ret = Selector._filterNodes(nodes, tokens, firstOnly);
+ }
+ }
+
+ return ret;
+ },
+
+ _filterNodes: function(nodes, tokens, firstOnly) {
+ var i = 0,
+ j,
+ len = tokens.length,
+ n = len - 1,
+ result = [],
+ node = nodes[0],
+ tmpNode = node,
+ getters = Y.Selector.getters,
+ operator,
+ combinator,
+ token,
+ path,
+ pass,
+ //FUNCTION = 'function',
+ value,
+ tests,
+ test;
+
+ //do {
+ for (i = 0; (tmpNode = node = nodes[i++]);) {
+ n = len - 1;
+ path = null;
+
+ testLoop:
+ while (tmpNode && tmpNode.tagName) {
+ token = tokens[n];
+ tests = token.tests;
+ j = tests.length;
+ if (j && !pass) {
+ while ((test = tests[--j])) {
+ operator = test[1];
+ if (getters[test[0]]) {
+ value = getters[test[0]](tmpNode, test[0]);
+ } else {
+ value = tmpNode[test[0]];
+ // use getAttribute for non-standard attributes
+ if (value === undefined && tmpNode.getAttribute) {
+ value = tmpNode.getAttribute(test[0]);
+ }
+ }
+
+ if ((operator === '=' && value !== test[2]) || // fast path for equality
+ (operator.test && !operator.test(value)) || // regex test
+ (operator.call && !operator(tmpNode, test[0]))) { // function test
+
+ // skip non element nodes or non-matching tags
+ if ((tmpNode = tmpNode[path])) {
+ while (tmpNode &&
+ (!tmpNode.tagName ||
+ (token.tagName && token.tagName !== tmpNode.tagName))
+ ) {
+ tmpNode = tmpNode[path];
+ }
+ }
+ continue testLoop;
+ }
+ }
+ }
+
+ n--; // move to next token
+ // now that we've passed the test, move up the tree by combinator
+ if (!pass && (combinator = token.combinator)) {
+ path = combinator.axis;
+ tmpNode = tmpNode[path];
+
+ // skip non element nodes
+ while (tmpNode && !tmpNode.tagName) {
+ tmpNode = tmpNode[path];
+ }
+
+ if (combinator.direct) { // one pass only
+ path = null;
+ }
+
+ } else { // success if we made it this far
+ result.push(node);
+ if (firstOnly) {
+ return result;
+ }
+ break;
+ }
+ }
+ }// while (tmpNode = node = nodes[++i]);
+ node = tmpNode = null;
+ return result;
+ },
+
+ _getRegExp: function(str, flags) {
+ var regexCache = Selector._regexCache;
+ flags = flags || '';
+ if (!regexCache[str + flags]) {
+ regexCache[str + flags] = new RegExp(str, flags);
+ }
+ return regexCache[str + flags];
+ },
+
+ combinators: {
+ ' ': {
+ axis: 'parentNode'
+ },
+
+ '>': {
+ axis: 'parentNode',
+ direct: true
+ },
+
+
+ '+': {
+ axis: 'previousSibling',
+ direct: true
+ }
+ },
+
+ _parsers: [
+ {
+ name: ATTRIBUTES,
+ re: /^\[([a-z]+\w*)+([~\|\^\$\*!=]=?)?['"]?([^\]]*?)['"]?\]/i,
+ fn: function(match, token) {
+ var operator = match[2] || '',
+ operators = Y.Selector.operators,
+ test;
+
+ // add prefiltering for ID and CLASS
+ if ((match[1] === 'id' && operator === '=') ||
+ (match[1] === 'className' &&
+ document.getElementsByClassName &&
+ (operator === '~=' || operator === '='))) {
+ token.prefilter = match[1];
+ token[match[1]] = match[3];
+ }
+
+ // add tests
+ if (operator in operators) {
+ test = operators[operator];
+ if (typeof test === 'string') {
+ test = Y.Selector._getRegExp(test.replace('{val}', match[3]));
+ }
+ match[2] = test;
+ }
+ if (!token.last || token.prefilter !== match[1]) {
+ return match.slice(1);
+ }
+ }
+
+ },
+ {
+ name: TAG_NAME,
+ re: /^((?:-?[_a-z]+[\w-]*)|\*)/i,
+ fn: function(match, token) {
+ var tag = match[1].toUpperCase();
+ token.tagName = tag;
+
+ if (tag !== '*' && (!token.last || token.prefilter)) {
+ return [TAG_NAME, '=', tag];
+ }
+ if (!token.prefilter) {
+ token.prefilter = 'tagName';
+ }
+ }
+ },
+ {
+ name: COMBINATOR,
+ re: /^\s*([>+~]|\s)\s*/,
+ fn: function(match, token) {
+ }
+ },
+ {
+ name: PSEUDOS,
+ re: /^:([\-\w]+)(?:\(['"]?(.+)['"]?\))*/i,
+ fn: function(match, token) {
+ var test = Selector[PSEUDOS][match[1]];
+ if (test) { // reorder match array
+ return [match[2], test];
+ } else { // selector token not supported (possibly missing CSS3 module)
+ return false;
+ }
+ }
+ }
+ ],
+
+ _getToken: function(token) {
+ return {
+ tagName: null,
+ id: null,
+ className: null,
+ attributes: {},
+ combinator: null,
+ tests: []
+ };
+ },
+
+ /**
+ Break selector into token units per simple selector.
+ Combinator is attached to the previous token.
+ */
+ _tokenize: function(selector) {
+ selector = selector || '';
+ selector = Selector._replaceShorthand(Y.Lang.trim(selector));
+ var token = Selector._getToken(), // one token per simple selector (left selector holds combinator)
+ query = selector, // original query for debug report
+ tokens = [], // array of tokens
+ found = false, // whether or not any matches were found this pass
+ match, // the regex match
+ test,
+ i, parser;
+
+ /*
+ Search for selector patterns, store, and strip them from the selector string
+ until no patterns match (invalid selector) or we run out of chars.
+
+ Multiple attributes and pseudos are allowed, in any order.
+ for example:
+ 'form:first-child[type=button]:not(button)[lang|=en]'
+ */
+ outer:
+ do {
+ found = false; // reset after full pass
+ for (i = 0; (parser = Selector._parsers[i++]);) {
+ if ( (match = parser.re.exec(selector)) ) { // note assignment
+ if (parser !== COMBINATOR ) {
+ token.selector = selector;
+ }
+ selector = selector.replace(match[0], ''); // strip current match from selector
+ if (!selector.length) {
+ token.last = true;
+ }
+
+ if (Selector._attrFilters[match[1]]) { // convert class to className, etc.
+ match[1] = Selector._attrFilters[match[1]];
+ }
+
+ test = parser.fn(match, token);
+ if (test === false) { // selector not supported
+ found = false;
+ break outer;
+ } else if (test) {
+ token.tests.push(test);
+ }
+
+ if (!selector.length || parser.name === COMBINATOR) {
+ tokens.push(token);
+ token = Selector._getToken(token);
+ if (parser.name === COMBINATOR) {
+ token.combinator = Y.Selector.combinators[match[1]];
+ }
+ }
+ found = true;
+ }
+ }
+ } while (found && selector.length);
+
+ if (!found || selector.length) { // not fully parsed
+ Y.log('query: ' + query + ' contains unsupported token in: ' + selector, 'warn', 'Selector');
+ tokens = [];
+ }
+ return tokens;
+ },
+
+ _replaceShorthand: function(selector) {
+ var shorthand = Selector.shorthand,
+ attrs = selector.match(Selector._re.attr), // pull attributes to avoid false pos on "." and "#"
+ pseudos = selector.match(Selector._re.pseudos), // pull attributes to avoid false pos on "." and "#"
+ re, i, len;
+
+ if (pseudos) {
+ selector = selector.replace(Selector._re.pseudos, '!!REPLACED_PSEUDO!!');
+ }
+
+ if (attrs) {
+ selector = selector.replace(Selector._re.attr, '!!REPLACED_ATTRIBUTE!!');
+ }
+
+ for (re in shorthand) {
+ if (shorthand.hasOwnProperty(re)) {
+ selector = selector.replace(Selector._getRegExp(re, 'gi'), shorthand[re]);
+ }
+ }
+
+ if (attrs) {
+ for (i = 0, len = attrs.length; i < len; ++i) {
+ selector = selector.replace('!!REPLACED_ATTRIBUTE!!', attrs[i]);
+ }
+ }
+ if (pseudos) {
+ for (i = 0, len = pseudos.length; i < len; ++i) {
+ selector = selector.replace('!!REPLACED_PSEUDO!!', pseudos[i]);
+ }
+ }
+ return selector;
+ },
+
+ _attrFilters: {
+ 'class': 'className',
+ 'for': 'htmlFor'
+ },
+
+ getters: {
+ href: function(node, attr) {
+ return Y.DOM.getAttribute(node, attr);
+ }
+ }
+ };
+
+Y.mix(Y.Selector, SelectorCSS2, true);
+Y.Selector.getters.src = Y.Selector.getters.rel = Y.Selector.getters.href;
+
+// IE wants class with native queries
+if (Y.Selector.useNative && document.querySelector) {
+ Y.Selector.shorthand['\\.(-?[_a-z]+[-\\w]*)'] = '[class~=$1]';
+}
+
+
+
+}, '3.0.0' ,{requires:['selector-native']});
diff --git a/lib/yui/3.0.0/dom/selector-css2-min.js b/lib/yui/3.0.0/dom/selector-css2-min.js
new file mode 100644
index 0000000000..28e798522d
--- /dev/null
+++ b/lib/yui/3.0.0/dom/selector-css2-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("selector-css2",function(G){var H="parentNode",D="tagName",E="attributes",A="combinator",F="pseudos",C=G.Selector,B={SORT_RESULTS:true,_children:function(M,I){var J=M.children,L,K=[],N,O;if(M.children&&I&&M.children.tags){K=M.children.tags(I);}else{if((!J&&M[D])||(J&&I)){N=J||M.childNodes;J=[];for(L=0;(O=N[L++]);){if(O.tagName){if(!I||I===O.tagName){J.push(O);}}}}}return J||[];},_regexCache:{},_re:{attr:/(\[.*\])/g,pseudos:/:([\-\w]+(?:\(?:['"]?(.+)['"]?\)))*/i},shorthand:{"\\#(-?[_a-z]+[-\\w]*)":"[id=$1]","\\.(-?[_a-z]+[-\\w]*)":"[className~=$1]"},operators:{"":function(J,I){return G.DOM.getAttribute(J,I)!=="";},"~=":"(?:^|\\s+){val}(?:\\s+|$)","|=":"^{val}-?"},pseudos:{"first-child":function(I){return G.Selector._children(I[H])[0]===I;}},_bruteQuery:function(M,Q,S){var N=[],I=[],P=C._tokenize(M),L=P[P.length-1],R=G.DOM._getDoc(Q),J,O,K;if(P[0]&&R===Q&&(J=P[0].id)&&R.getElementById(J)){Q=R.getElementById(J);}if(L){J=L.id;O=L.className;K=L.tagName||"*";if(J){if(R.getElementById(J)){I=[R.getElementById(J)];}}else{if(O){I=Q.getElementsByClassName(O);}else{if(K){I=Q.getElementsByTagName(K||"*");}}}if(I.length){N=C._filterNodes(I,P,S);}}return N;},_filterNodes:function(R,N,P){var W=0,V,X=N.length,Q=X-1,M=[],T=R[0],a=T,Y=G.Selector.getters,L,U,K,O,I,S,J,Z;for(W=0;(a=T=R[W++]);){Q=X-1;O=null;testLoop:while(a&&a.tagName){K=N[Q];J=K.tests;V=J.length;if(V&&!I){while((Z=J[--V])){L=Z[1];if(Y[Z[0]]){S=Y[Z[0]](a,Z[0]);}else{S=a[Z[0]];if(S===undefined&&a.getAttribute){S=a.getAttribute(Z[0]);}}if((L==="="&&S!==Z[2])||(L.test&&!L.test(S))||(L.call&&!L(a,Z[0]))){if((a=a[O])){while(a&&(!a.tagName||(K.tagName&&K.tagName!==a.tagName))){a=a[O];}}continue testLoop;}}}Q--;if(!I&&(U=K.combinator)){O=U.axis;a=a[O];while(a&&!a.tagName){a=a[O];}if(U.direct){O=null;}}else{M.push(T);if(P){return M;}break;}}}T=a=null;return M;},_getRegExp:function(K,I){var J=C._regexCache;I=I||"";if(!J[K+I]){J[K+I]=new RegExp(K,I);}return J[K+I];},combinators:{" ":{axis:"parentNode"},">":{axis:"parentNode",direct:true},"+":{axis:"previousSibling",direct:true}},_parsers:[{name:E,re:/^\[([a-z]+\w*)+([~\|\^\$\*!=]=?)?['"]?([^\]]*?)['"]?\]/i,fn:function(K,L){var J=K[2]||"",I=G.Selector.operators,M;if((K[1]==="id"&&J==="=")||(K[1]==="className"&&document.getElementsByClassName&&(J==="~="||J==="="))){L.prefilter=K[1];L[K[1]]=K[3];}if(J in I){M=I[J];if(typeof M==="string"){M=G.Selector._getRegExp(M.replace("{val}",K[3]));}K[2]=M;}if(!L.last||L.prefilter!==K[1]){return K.slice(1);}}},{name:D,re:/^((?:-?[_a-z]+[\w-]*)|\*)/i,fn:function(J,K){var I=J[1].toUpperCase();K.tagName=I;if(I!=="*"&&(!K.last||K.prefilter)){return[D,"=",I];}if(!K.prefilter){K.prefilter="tagName";}}},{name:A,re:/^\s*([>+~]|\s)\s*/,fn:function(I,J){}},{name:F,re:/^:([\-\w]+)(?:\(['"]?(.+)['"]?\))*/i,fn:function(I,J){var K=C[F][I[1]];if(K){return[I[2],K];}else{return false;}}}],_getToken:function(I){return{tagName:null,id:null,className:null,attributes:{},combinator:null,tests:[]};},_tokenize:function(K){K=K||"";K=C._replaceShorthand(G.Lang.trim(K));var J=C._getToken(),P=K,O=[],Q=false,M,N,L,I;outer:do{Q=false;for(L=0;(I=C._parsers[L++]);){if((M=I.re.exec(K))){if(I!==A){J.selector=K;}K=K.replace(M[0],"");if(!K.length){J.last=true;}if(C._attrFilters[M[1]]){M[1]=C._attrFilters[M[1]];}N=I.fn(M,J);if(N===false){Q=false;break outer;}else{if(N){J.tests.push(N);}}if(!K.length||I.name===A){O.push(J);J=C._getToken(J);if(I.name===A){J.combinator=G.Selector.combinators[M[1]];}}Q=true;}}}while(Q&&K.length);if(!Q||K.length){O=[];}return O;},_replaceShorthand:function(J){var K=C.shorthand,L=J.match(C._re.attr),O=J.match(C._re.pseudos),N,M,I;if(O){J=J.replace(C._re.pseudos,"!!REPLACED_PSEUDO!!");}if(L){J=J.replace(C._re.attr,"!!REPLACED_ATTRIBUTE!!");}for(N in K){if(K.hasOwnProperty(N)){J=J.replace(C._getRegExp(N,"gi"),K[N]);}}if(L){for(M=0,I=L.length;M': {
+ axis: 'parentNode',
+ direct: true
+ },
+
+
+ '+': {
+ axis: 'previousSibling',
+ direct: true
+ }
+ },
+
+ _parsers: [
+ {
+ name: ATTRIBUTES,
+ re: /^\[([a-z]+\w*)+([~\|\^\$\*!=]=?)?['"]?([^\]]*?)['"]?\]/i,
+ fn: function(match, token) {
+ var operator = match[2] || '',
+ operators = Y.Selector.operators,
+ test;
+
+ // add prefiltering for ID and CLASS
+ if ((match[1] === 'id' && operator === '=') ||
+ (match[1] === 'className' &&
+ document.getElementsByClassName &&
+ (operator === '~=' || operator === '='))) {
+ token.prefilter = match[1];
+ token[match[1]] = match[3];
+ }
+
+ // add tests
+ if (operator in operators) {
+ test = operators[operator];
+ if (typeof test === 'string') {
+ test = Y.Selector._getRegExp(test.replace('{val}', match[3]));
+ }
+ match[2] = test;
+ }
+ if (!token.last || token.prefilter !== match[1]) {
+ return match.slice(1);
+ }
+ }
+
+ },
+ {
+ name: TAG_NAME,
+ re: /^((?:-?[_a-z]+[\w-]*)|\*)/i,
+ fn: function(match, token) {
+ var tag = match[1].toUpperCase();
+ token.tagName = tag;
+
+ if (tag !== '*' && (!token.last || token.prefilter)) {
+ return [TAG_NAME, '=', tag];
+ }
+ if (!token.prefilter) {
+ token.prefilter = 'tagName';
+ }
+ }
+ },
+ {
+ name: COMBINATOR,
+ re: /^\s*([>+~]|\s)\s*/,
+ fn: function(match, token) {
+ }
+ },
+ {
+ name: PSEUDOS,
+ re: /^:([\-\w]+)(?:\(['"]?(.+)['"]?\))*/i,
+ fn: function(match, token) {
+ var test = Selector[PSEUDOS][match[1]];
+ if (test) { // reorder match array
+ return [match[2], test];
+ } else { // selector token not supported (possibly missing CSS3 module)
+ return false;
+ }
+ }
+ }
+ ],
+
+ _getToken: function(token) {
+ return {
+ tagName: null,
+ id: null,
+ className: null,
+ attributes: {},
+ combinator: null,
+ tests: []
+ };
+ },
+
+ /**
+ Break selector into token units per simple selector.
+ Combinator is attached to the previous token.
+ */
+ _tokenize: function(selector) {
+ selector = selector || '';
+ selector = Selector._replaceShorthand(Y.Lang.trim(selector));
+ var token = Selector._getToken(), // one token per simple selector (left selector holds combinator)
+ query = selector, // original query for debug report
+ tokens = [], // array of tokens
+ found = false, // whether or not any matches were found this pass
+ match, // the regex match
+ test,
+ i, parser;
+
+ /*
+ Search for selector patterns, store, and strip them from the selector string
+ until no patterns match (invalid selector) or we run out of chars.
+
+ Multiple attributes and pseudos are allowed, in any order.
+ for example:
+ 'form:first-child[type=button]:not(button)[lang|=en]'
+ */
+ outer:
+ do {
+ found = false; // reset after full pass
+ for (i = 0; (parser = Selector._parsers[i++]);) {
+ if ( (match = parser.re.exec(selector)) ) { // note assignment
+ if (parser !== COMBINATOR ) {
+ token.selector = selector;
+ }
+ selector = selector.replace(match[0], ''); // strip current match from selector
+ if (!selector.length) {
+ token.last = true;
+ }
+
+ if (Selector._attrFilters[match[1]]) { // convert class to className, etc.
+ match[1] = Selector._attrFilters[match[1]];
+ }
+
+ test = parser.fn(match, token);
+ if (test === false) { // selector not supported
+ found = false;
+ break outer;
+ } else if (test) {
+ token.tests.push(test);
+ }
+
+ if (!selector.length || parser.name === COMBINATOR) {
+ tokens.push(token);
+ token = Selector._getToken(token);
+ if (parser.name === COMBINATOR) {
+ token.combinator = Y.Selector.combinators[match[1]];
+ }
+ }
+ found = true;
+ }
+ }
+ } while (found && selector.length);
+
+ if (!found || selector.length) { // not fully parsed
+ tokens = [];
+ }
+ return tokens;
+ },
+
+ _replaceShorthand: function(selector) {
+ var shorthand = Selector.shorthand,
+ attrs = selector.match(Selector._re.attr), // pull attributes to avoid false pos on "." and "#"
+ pseudos = selector.match(Selector._re.pseudos), // pull attributes to avoid false pos on "." and "#"
+ re, i, len;
+
+ if (pseudos) {
+ selector = selector.replace(Selector._re.pseudos, '!!REPLACED_PSEUDO!!');
+ }
+
+ if (attrs) {
+ selector = selector.replace(Selector._re.attr, '!!REPLACED_ATTRIBUTE!!');
+ }
+
+ for (re in shorthand) {
+ if (shorthand.hasOwnProperty(re)) {
+ selector = selector.replace(Selector._getRegExp(re, 'gi'), shorthand[re]);
+ }
+ }
+
+ if (attrs) {
+ for (i = 0, len = attrs.length; i < len; ++i) {
+ selector = selector.replace('!!REPLACED_ATTRIBUTE!!', attrs[i]);
+ }
+ }
+ if (pseudos) {
+ for (i = 0, len = pseudos.length; i < len; ++i) {
+ selector = selector.replace('!!REPLACED_PSEUDO!!', pseudos[i]);
+ }
+ }
+ return selector;
+ },
+
+ _attrFilters: {
+ 'class': 'className',
+ 'for': 'htmlFor'
+ },
+
+ getters: {
+ href: function(node, attr) {
+ return Y.DOM.getAttribute(node, attr);
+ }
+ }
+ };
+
+Y.mix(Y.Selector, SelectorCSS2, true);
+Y.Selector.getters.src = Y.Selector.getters.rel = Y.Selector.getters.href;
+
+// IE wants class with native queries
+if (Y.Selector.useNative && document.querySelector) {
+ Y.Selector.shorthand['\\.(-?[_a-z]+[-\\w]*)'] = '[class~=$1]';
+}
+
+
+
+}, '3.0.0' ,{requires:['selector-native']});
diff --git a/lib/yui/3.0.0/dom/selector-css3-debug.js b/lib/yui/3.0.0/dom/selector-css3-debug.js
new file mode 100644
index 0000000000..7149667533
--- /dev/null
+++ b/lib/yui/3.0.0/dom/selector-css3-debug.js
@@ -0,0 +1,151 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('selector-css3', function(Y) {
+
+/**
+ * The selector css3 module provides support for css3 selectors.
+ * @module dom
+ * @submodule selector-css3
+ * @for Selector
+ */
+
+/*
+ an+b = get every _a_th node starting at the _b_th
+ 0n+b = no repeat ("0" and "n" may both be omitted (together) , e.g. "0n+1" or "1", not "0+1"), return only the _b_th element
+ 1n+b = get every element starting from b ("1" may may be omitted, e.g. "1n+0" or "n+0" or "n")
+ an+0 = get every _a_th element, "0" may be omitted
+*/
+
+Y.Selector._reNth = /^(?:([\-]?\d*)(n){1}|(odd|even)$)*([\-+]?\d*)$/;
+
+Y.Selector._getNth = function(node, expr, tag, reverse) {
+ Y.Selector._reNth.test(expr);
+ var a = parseInt(RegExp.$1, 10), // include every _a_ elements (zero means no repeat, just first _a_)
+ n = RegExp.$2, // "n"
+ oddeven = RegExp.$3, // "odd" or "even"
+ b = parseInt(RegExp.$4, 10) || 0, // start scan from element _b_
+ result = [],
+ siblings = Y.Selector._children(node.parentNode, tag),
+ op;
+
+ if (oddeven) {
+ a = 2; // always every other
+ op = '+';
+ n = 'n';
+ b = (oddeven === 'odd') ? 1 : 0;
+ } else if ( isNaN(a) ) {
+ a = (n) ? 1 : 0; // start from the first or no repeat
+ }
+
+ if (a === 0) { // just the first
+ if (reverse) {
+ b = siblings.length - b + 1;
+ }
+
+ if (siblings[b - 1] === node) {
+ return true;
+ } else {
+ return false;
+ }
+
+ } else if (a < 0) {
+ reverse = !!reverse;
+ a = Math.abs(a);
+ }
+
+ if (!reverse) {
+ for (var i = b - 1, len = siblings.length; i < len; i += a) {
+ if ( i >= 0 && siblings[i] === node ) {
+ return true;
+ }
+ }
+ } else {
+ for (var i = siblings.length - b, len = siblings.length; i >= 0; i -= a) {
+ if ( i < len && siblings[i] === node ) {
+ return true;
+ }
+ }
+ }
+ return false;
+};
+
+Y.mix(Y.Selector.pseudos, {
+ 'root': function(node) {
+ return node === node.ownerDocument.documentElement;
+ },
+
+ 'nth-child': function(node, expr) {
+ return Y.Selector._getNth(node, expr);
+ },
+
+ 'nth-last-child': function(node, expr) {
+ return Y.Selector._getNth(node, expr, null, true);
+ },
+
+ 'nth-of-type': function(node, expr) {
+ return Y.Selector._getNth(node, expr, node.tagName);
+ },
+
+ 'nth-last-of-type': function(node, expr) {
+ return Y.Selector._getNth(node, expr, node.tagName, true);
+ },
+
+ 'last-child': function(node) {
+ var children = Y.Selector._children(node.parentNode);
+ return children[children.length - 1] === node;
+ },
+
+ 'first-of-type': function(node) {
+ return Y.Selector._children(node.parentNode, node.tagName)[0] === node;
+ },
+
+ 'last-of-type': function(node) {
+ var children = Y.Selector._children(node.parentNode, node.tagName);
+ return children[children.length - 1] === node;
+ },
+
+ 'only-child': function(node) {
+ var children = Y.Selector._children(node.parentNode);
+ return children.length === 1 && children[0] === node;
+ },
+
+ 'only-of-type': function(node) {
+ var children = Y.Selector._children(node.parentNode, node.tagName);
+ return children.length === 1 && children[0] === node;
+ },
+
+ 'empty': function(node) {
+ return node.childNodes.length === 0;
+ },
+
+ 'not': function(node, expr) {
+ return !Y.Selector.test(node, expr);
+ },
+
+ 'contains': function(node, expr) {
+ var text = node.innerText || node.textContent || '';
+ return text.indexOf(expr) > -1;
+ },
+
+ 'checked': function(node) {
+ return node.checked === true;
+ }
+});
+
+Y.mix(Y.Selector.operators, {
+ '^=': '^{val}', // Match starts with value
+ '$=': '{val}$', // Match ends with value
+ '*=': '{val}' // Match contains value as substring
+});
+
+Y.Selector.combinators['~'] = {
+ axis: 'previousSibling'
+};
+
+
+}, '3.0.0' ,{requires:['dom-base', 'selector-native', 'selector-css2']});
diff --git a/lib/yui/3.0.0/dom/selector-css3-min.js b/lib/yui/3.0.0/dom/selector-css3-min.js
new file mode 100644
index 0000000000..2a0deb7767
--- /dev/null
+++ b/lib/yui/3.0.0/dom/selector-css3-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("selector-css3",function(A){A.Selector._reNth=/^(?:([\-]?\d*)(n){1}|(odd|even)$)*([\-+]?\d*)$/;A.Selector._getNth=function(C,L,N,G){A.Selector._reNth.test(L);var K=parseInt(RegExp.$1,10),B=RegExp.$2,H=RegExp.$3,I=parseInt(RegExp.$4,10)||0,M=[],J=A.Selector._children(C.parentNode,N),E;if(H){K=2;E="+";B="n";I=(H==="odd")?1:0;}else{if(isNaN(K)){K=(B)?1:0;}}if(K===0){if(G){I=J.length-I+1;}if(J[I-1]===C){return true;}else{return false;}}else{if(K<0){G=!!G;K=Math.abs(K);}}if(!G){for(var D=I-1,F=J.length;D=0&&J[D]===C){return true;}}}else{for(var D=J.length-I,F=J.length;D>=0;D-=K){if(D-1;},"checked":function(B){return B.checked===true;}});A.mix(A.Selector.operators,{"^=":"^{val}","$=":"{val}$","*=":"{val}"});A.Selector.combinators["~"]={axis:"previousSibling"};},"3.0.0",{requires:["dom-base","selector-native","selector-css2"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/dom/selector-css3.js b/lib/yui/3.0.0/dom/selector-css3.js
new file mode 100644
index 0000000000..7149667533
--- /dev/null
+++ b/lib/yui/3.0.0/dom/selector-css3.js
@@ -0,0 +1,151 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('selector-css3', function(Y) {
+
+/**
+ * The selector css3 module provides support for css3 selectors.
+ * @module dom
+ * @submodule selector-css3
+ * @for Selector
+ */
+
+/*
+ an+b = get every _a_th node starting at the _b_th
+ 0n+b = no repeat ("0" and "n" may both be omitted (together) , e.g. "0n+1" or "1", not "0+1"), return only the _b_th element
+ 1n+b = get every element starting from b ("1" may may be omitted, e.g. "1n+0" or "n+0" or "n")
+ an+0 = get every _a_th element, "0" may be omitted
+*/
+
+Y.Selector._reNth = /^(?:([\-]?\d*)(n){1}|(odd|even)$)*([\-+]?\d*)$/;
+
+Y.Selector._getNth = function(node, expr, tag, reverse) {
+ Y.Selector._reNth.test(expr);
+ var a = parseInt(RegExp.$1, 10), // include every _a_ elements (zero means no repeat, just first _a_)
+ n = RegExp.$2, // "n"
+ oddeven = RegExp.$3, // "odd" or "even"
+ b = parseInt(RegExp.$4, 10) || 0, // start scan from element _b_
+ result = [],
+ siblings = Y.Selector._children(node.parentNode, tag),
+ op;
+
+ if (oddeven) {
+ a = 2; // always every other
+ op = '+';
+ n = 'n';
+ b = (oddeven === 'odd') ? 1 : 0;
+ } else if ( isNaN(a) ) {
+ a = (n) ? 1 : 0; // start from the first or no repeat
+ }
+
+ if (a === 0) { // just the first
+ if (reverse) {
+ b = siblings.length - b + 1;
+ }
+
+ if (siblings[b - 1] === node) {
+ return true;
+ } else {
+ return false;
+ }
+
+ } else if (a < 0) {
+ reverse = !!reverse;
+ a = Math.abs(a);
+ }
+
+ if (!reverse) {
+ for (var i = b - 1, len = siblings.length; i < len; i += a) {
+ if ( i >= 0 && siblings[i] === node ) {
+ return true;
+ }
+ }
+ } else {
+ for (var i = siblings.length - b, len = siblings.length; i >= 0; i -= a) {
+ if ( i < len && siblings[i] === node ) {
+ return true;
+ }
+ }
+ }
+ return false;
+};
+
+Y.mix(Y.Selector.pseudos, {
+ 'root': function(node) {
+ return node === node.ownerDocument.documentElement;
+ },
+
+ 'nth-child': function(node, expr) {
+ return Y.Selector._getNth(node, expr);
+ },
+
+ 'nth-last-child': function(node, expr) {
+ return Y.Selector._getNth(node, expr, null, true);
+ },
+
+ 'nth-of-type': function(node, expr) {
+ return Y.Selector._getNth(node, expr, node.tagName);
+ },
+
+ 'nth-last-of-type': function(node, expr) {
+ return Y.Selector._getNth(node, expr, node.tagName, true);
+ },
+
+ 'last-child': function(node) {
+ var children = Y.Selector._children(node.parentNode);
+ return children[children.length - 1] === node;
+ },
+
+ 'first-of-type': function(node) {
+ return Y.Selector._children(node.parentNode, node.tagName)[0] === node;
+ },
+
+ 'last-of-type': function(node) {
+ var children = Y.Selector._children(node.parentNode, node.tagName);
+ return children[children.length - 1] === node;
+ },
+
+ 'only-child': function(node) {
+ var children = Y.Selector._children(node.parentNode);
+ return children.length === 1 && children[0] === node;
+ },
+
+ 'only-of-type': function(node) {
+ var children = Y.Selector._children(node.parentNode, node.tagName);
+ return children.length === 1 && children[0] === node;
+ },
+
+ 'empty': function(node) {
+ return node.childNodes.length === 0;
+ },
+
+ 'not': function(node, expr) {
+ return !Y.Selector.test(node, expr);
+ },
+
+ 'contains': function(node, expr) {
+ var text = node.innerText || node.textContent || '';
+ return text.indexOf(expr) > -1;
+ },
+
+ 'checked': function(node) {
+ return node.checked === true;
+ }
+});
+
+Y.mix(Y.Selector.operators, {
+ '^=': '^{val}', // Match starts with value
+ '$=': '{val}$', // Match ends with value
+ '*=': '{val}' // Match contains value as substring
+});
+
+Y.Selector.combinators['~'] = {
+ axis: 'previousSibling'
+};
+
+
+}, '3.0.0' ,{requires:['dom-base', 'selector-native', 'selector-css2']});
diff --git a/lib/yui/3.0.0/dom/selector-debug.js b/lib/yui/3.0.0/dom/selector-debug.js
new file mode 100644
index 0000000000..692f5a620a
--- /dev/null
+++ b/lib/yui/3.0.0/dom/selector-debug.js
@@ -0,0 +1,679 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('selector-native', function(Y) {
+
+(function(Y) {
+/**
+ * The selector-native module provides support for native querySelector
+ * @module dom
+ * @submodule selector-native
+ * @for Selector
+ */
+
+/**
+ * Provides support for using CSS selectors to query the DOM
+ * @class Selector
+ * @static
+ * @for Selector
+ */
+
+Y.namespace('Selector'); // allow native module to standalone
+
+var COMPARE_DOCUMENT_POSITION = 'compareDocumentPosition',
+ OWNER_DOCUMENT = 'ownerDocument',
+ TMP_PREFIX = 'yui-tmp-',
+ g_counter = 0;
+
+var Selector = {
+ _foundCache: [],
+
+ useNative: true,
+
+ _compare: ('sourceIndex' in document.documentElement) ?
+ function(nodeA, nodeB) {
+ var a = nodeA.sourceIndex,
+ b = nodeB.sourceIndex;
+
+ if (a === b) {
+ return 0;
+ } else if (a > b) {
+ return 1;
+ }
+
+ return -1;
+
+ } : (document.documentElement[COMPARE_DOCUMENT_POSITION] ?
+ function(nodeA, nodeB) {
+ if (nodeA[COMPARE_DOCUMENT_POSITION](nodeB) & 4) {
+ return -1;
+ } else {
+ return 1;
+ }
+ } :
+ function(nodeA, nodeB) {
+ var rangeA, rangeB, compare;
+ if (nodeA && nodeB) {
+ rangeA = nodeA[OWNER_DOCUMENT].createRange();
+ rangeA.setStart(nodeA, 0);
+ rangeB = nodeB[OWNER_DOCUMENT].createRange();
+ rangeB.setStart(nodeB, 0);
+ compare = rangeA.compareBoundaryPoints(1, rangeB); // 1 === Range.START_TO_END
+ }
+
+ return compare;
+
+ }),
+
+ _sort: function(nodes) {
+ if (nodes) {
+ nodes = Y.Array(nodes, 0, true);
+ if (nodes.sort) {
+ nodes.sort(Selector._compare);
+ }
+ }
+
+ return nodes;
+ },
+
+ _deDupe: function(nodes) {
+ var ret = [],
+ i, node;
+
+ for (i = 0; (node = nodes[i++]);) {
+ if (!node._found) {
+ ret[ret.length] = node;
+ node._found = true;
+ }
+ }
+
+ for (i = 0; (node = ret[i++]);) {
+ node._found = null;
+ node.removeAttribute('_found');
+ }
+
+ return ret;
+ },
+
+ /**
+ * Retrieves a set of nodes based on a given CSS selector.
+ * @method query
+ *
+ * @param {string} selector The CSS Selector to test the node against.
+ * @param {HTMLElement} root optional An HTMLElement to start the query from. Defaults to Y.config.doc
+ * @param {Boolean} firstOnly optional Whether or not to return only the first match.
+ * @return {Array} An array of nodes that match the given selector.
+ * @static
+ */
+ query: function(selector, root, firstOnly, skipNative) {
+ root = root || Y.config.doc;
+ var ret = [],
+ useNative = (Y.Selector.useNative && document.querySelector && !skipNative),
+ queries = [[selector, root]],
+ query,
+ result,
+ i,
+ fn = (useNative) ? Y.Selector._nativeQuery : Y.Selector._bruteQuery;
+
+ if (selector && fn) {
+ // split group into seperate queries
+ if (!skipNative && // already done if skipping
+ (!useNative || root.tagName)) { // split native when element scoping is needed
+ queries = Selector._splitQueries(selector, root);
+ }
+
+ for (i = 0; (query = queries[i++]);) {
+ result = fn(query[0], query[1], firstOnly);
+ if (!firstOnly) { // coerce DOM Collection to Array
+ result = Y.Array(result, 0, true);
+ }
+ if (result) {
+ ret = ret.concat(result);
+ }
+ }
+
+ if (queries.length > 1) { // remove dupes and sort by doc order
+ ret = Selector._sort(Selector._deDupe(ret));
+ }
+ }
+
+ Y.log('query: ' + selector + ' returning: ' + ret.length, 'info', 'Selector');
+ return (firstOnly) ? (ret[0] || null) : ret;
+
+ },
+
+ // allows element scoped queries to begin with combinator
+ // e.g. query('> p', document.body) === query('body > p')
+ _splitQueries: function(selector, node) {
+ var groups = selector.split(','),
+ queries = [],
+ prefix = '',
+ i, len;
+
+ if (node) {
+ // enforce for element scoping
+ if (node.tagName) {
+ node.id = node.id || Y.guid();
+ prefix = '#' + node.id + ' ';
+ }
+
+ for (i = 0, len = groups.length; i < len; ++i) {
+ selector = prefix + groups[i];
+ queries.push([selector, node]);
+ }
+ }
+
+ return queries;
+ },
+
+ _nativeQuery: function(selector, root, one) {
+ try {
+ //Y.log('trying native query with: ' + selector, 'info', 'selector-native');
+ return root['querySelector' + (one ? '' : 'All')](selector);
+ } catch(e) { // fallback to brute if available
+ //Y.log('native query error; reverting to brute query with: ' + selector, 'info', 'selector-native');
+ return Y.Selector.query(selector, root, one, true); // redo with skipNative true
+ }
+ },
+
+ filter: function(nodes, selector) {
+ var ret = [],
+ i, node;
+
+ if (nodes && selector) {
+ for (i = 0; (node = nodes[i++]);) {
+ if (Y.Selector.test(node, selector)) {
+ ret[ret.length] = node;
+ }
+ }
+ } else {
+ Y.log('invalid filter input (nodes: ' + nodes +
+ ', selector: ' + selector + ')', 'warn', 'Selector');
+ }
+
+ return ret;
+ },
+
+ test: function(node, selector, root) {
+ var ret = false,
+ groups = selector.split(','),
+ item,
+ i, group;
+
+ if (node && node.tagName) { // only test HTMLElements
+ root = root || node.ownerDocument;
+
+ if (!node.id) {
+ node.id = TMP_PREFIX + g_counter++;
+ }
+ for (i = 0; (group = groups[i++]);) { // TODO: off-dom test
+ group += '#' + node.id; // add ID for uniqueness
+ item = Y.Selector.query(group, root, true);
+ ret = (item === node);
+ if (ret) {
+ break;
+ }
+ }
+ }
+
+ return ret;
+ }
+};
+
+Y.mix(Y.Selector, Selector, true);
+
+})(Y);
+
+
+}, '3.0.0' ,{requires:['dom-base']});
+YUI.add('selector-css2', function(Y) {
+
+/**
+ * The selector module provides helper methods allowing CSS2 Selectors to be used with DOM elements.
+ * @module dom
+ * @submodule selector-css2
+ * @for Selector
+ */
+
+/**
+ * Provides helper methods for collecting and filtering DOM elements.
+ */
+
+var PARENT_NODE = 'parentNode',
+ TAG_NAME = 'tagName',
+ ATTRIBUTES = 'attributes',
+ COMBINATOR = 'combinator',
+ PSEUDOS = 'pseudos',
+
+ Selector = Y.Selector,
+
+ SelectorCSS2 = {
+ SORT_RESULTS: true,
+ _children: function(node, tag) {
+ var ret = node.children,
+ i,
+ children = [],
+ childNodes,
+ child;
+
+ if (node.children && tag && node.children.tags) {
+ children = node.children.tags(tag);
+ } else if ((!ret && node[TAG_NAME]) || (ret && tag)) { // only HTMLElements have children
+ childNodes = ret || node.childNodes;
+ ret = [];
+ for (i = 0; (child = childNodes[i++]);) {
+ if (child.tagName) {
+ if (!tag || tag === child.tagName) {
+ ret.push(child);
+ }
+ }
+ }
+ }
+
+ return ret || [];
+ },
+
+ _regexCache: {},
+
+ _re: {
+ attr: /(\[.*\])/g,
+ pseudos: /:([\-\w]+(?:\(?:['"]?(.+)['"]?\)))*/i
+ },
+
+ /**
+ * Mapping of shorthand tokens to corresponding attribute selector
+ * @property shorthand
+ * @type object
+ */
+ shorthand: {
+ '\\#(-?[_a-z]+[-\\w]*)': '[id=$1]',
+ '\\.(-?[_a-z]+[-\\w]*)': '[className~=$1]'
+ },
+
+ /**
+ * List of operators and corresponding boolean functions.
+ * These functions are passed the attribute and the current node's value of the attribute.
+ * @property operators
+ * @type object
+ */
+ operators: {
+ '': function(node, attr) { return Y.DOM.getAttribute(node, attr) !== ''; }, // Just test for existence of attribute
+ //'': '.+',
+ //'=': '^{val}$', // equality
+ '~=': '(?:^|\\s+){val}(?:\\s+|$)', // space-delimited
+ '|=': '^{val}-?' // optional hyphen-delimited
+ },
+
+ pseudos: {
+ 'first-child': function(node) {
+ return Y.Selector._children(node[PARENT_NODE])[0] === node;
+ }
+ },
+
+ _bruteQuery: function(selector, root, firstOnly) {
+ var ret = [],
+ nodes = [],
+ tokens = Selector._tokenize(selector),
+ token = tokens[tokens.length - 1],
+ rootDoc = Y.DOM._getDoc(root),
+ id,
+ className,
+ tagName;
+
+
+ // if we have an initial ID, set to root when in document
+ if (tokens[0] && rootDoc === root &&
+ (id = tokens[0].id) &&
+ rootDoc.getElementById(id)) {
+ root = rootDoc.getElementById(id);
+ }
+
+ if (token) {
+ // prefilter nodes
+ id = token.id;
+ className = token.className;
+ tagName = token.tagName || '*';
+
+ // try ID first
+ if (id) {
+ if (rootDoc.getElementById(id)) { // if in document
+ nodes = [rootDoc.getElementById(id)]; // TODO: DOM.byId?
+ }
+ // try className if supported
+ } else if (className) {
+ nodes = root.getElementsByClassName(className);
+ } else if (tagName) { // default to tagName
+ nodes = root.getElementsByTagName(tagName || '*');
+ }
+
+ if (nodes.length) {
+ ret = Selector._filterNodes(nodes, tokens, firstOnly);
+ }
+ }
+
+ return ret;
+ },
+
+ _filterNodes: function(nodes, tokens, firstOnly) {
+ var i = 0,
+ j,
+ len = tokens.length,
+ n = len - 1,
+ result = [],
+ node = nodes[0],
+ tmpNode = node,
+ getters = Y.Selector.getters,
+ operator,
+ combinator,
+ token,
+ path,
+ pass,
+ //FUNCTION = 'function',
+ value,
+ tests,
+ test;
+
+ //do {
+ for (i = 0; (tmpNode = node = nodes[i++]);) {
+ n = len - 1;
+ path = null;
+
+ testLoop:
+ while (tmpNode && tmpNode.tagName) {
+ token = tokens[n];
+ tests = token.tests;
+ j = tests.length;
+ if (j && !pass) {
+ while ((test = tests[--j])) {
+ operator = test[1];
+ if (getters[test[0]]) {
+ value = getters[test[0]](tmpNode, test[0]);
+ } else {
+ value = tmpNode[test[0]];
+ // use getAttribute for non-standard attributes
+ if (value === undefined && tmpNode.getAttribute) {
+ value = tmpNode.getAttribute(test[0]);
+ }
+ }
+
+ if ((operator === '=' && value !== test[2]) || // fast path for equality
+ (operator.test && !operator.test(value)) || // regex test
+ (operator.call && !operator(tmpNode, test[0]))) { // function test
+
+ // skip non element nodes or non-matching tags
+ if ((tmpNode = tmpNode[path])) {
+ while (tmpNode &&
+ (!tmpNode.tagName ||
+ (token.tagName && token.tagName !== tmpNode.tagName))
+ ) {
+ tmpNode = tmpNode[path];
+ }
+ }
+ continue testLoop;
+ }
+ }
+ }
+
+ n--; // move to next token
+ // now that we've passed the test, move up the tree by combinator
+ if (!pass && (combinator = token.combinator)) {
+ path = combinator.axis;
+ tmpNode = tmpNode[path];
+
+ // skip non element nodes
+ while (tmpNode && !tmpNode.tagName) {
+ tmpNode = tmpNode[path];
+ }
+
+ if (combinator.direct) { // one pass only
+ path = null;
+ }
+
+ } else { // success if we made it this far
+ result.push(node);
+ if (firstOnly) {
+ return result;
+ }
+ break;
+ }
+ }
+ }// while (tmpNode = node = nodes[++i]);
+ node = tmpNode = null;
+ return result;
+ },
+
+ _getRegExp: function(str, flags) {
+ var regexCache = Selector._regexCache;
+ flags = flags || '';
+ if (!regexCache[str + flags]) {
+ regexCache[str + flags] = new RegExp(str, flags);
+ }
+ return regexCache[str + flags];
+ },
+
+ combinators: {
+ ' ': {
+ axis: 'parentNode'
+ },
+
+ '>': {
+ axis: 'parentNode',
+ direct: true
+ },
+
+
+ '+': {
+ axis: 'previousSibling',
+ direct: true
+ }
+ },
+
+ _parsers: [
+ {
+ name: ATTRIBUTES,
+ re: /^\[([a-z]+\w*)+([~\|\^\$\*!=]=?)?['"]?([^\]]*?)['"]?\]/i,
+ fn: function(match, token) {
+ var operator = match[2] || '',
+ operators = Y.Selector.operators,
+ test;
+
+ // add prefiltering for ID and CLASS
+ if ((match[1] === 'id' && operator === '=') ||
+ (match[1] === 'className' &&
+ document.getElementsByClassName &&
+ (operator === '~=' || operator === '='))) {
+ token.prefilter = match[1];
+ token[match[1]] = match[3];
+ }
+
+ // add tests
+ if (operator in operators) {
+ test = operators[operator];
+ if (typeof test === 'string') {
+ test = Y.Selector._getRegExp(test.replace('{val}', match[3]));
+ }
+ match[2] = test;
+ }
+ if (!token.last || token.prefilter !== match[1]) {
+ return match.slice(1);
+ }
+ }
+
+ },
+ {
+ name: TAG_NAME,
+ re: /^((?:-?[_a-z]+[\w-]*)|\*)/i,
+ fn: function(match, token) {
+ var tag = match[1].toUpperCase();
+ token.tagName = tag;
+
+ if (tag !== '*' && (!token.last || token.prefilter)) {
+ return [TAG_NAME, '=', tag];
+ }
+ if (!token.prefilter) {
+ token.prefilter = 'tagName';
+ }
+ }
+ },
+ {
+ name: COMBINATOR,
+ re: /^\s*([>+~]|\s)\s*/,
+ fn: function(match, token) {
+ }
+ },
+ {
+ name: PSEUDOS,
+ re: /^:([\-\w]+)(?:\(['"]?(.+)['"]?\))*/i,
+ fn: function(match, token) {
+ var test = Selector[PSEUDOS][match[1]];
+ if (test) { // reorder match array
+ return [match[2], test];
+ } else { // selector token not supported (possibly missing CSS3 module)
+ return false;
+ }
+ }
+ }
+ ],
+
+ _getToken: function(token) {
+ return {
+ tagName: null,
+ id: null,
+ className: null,
+ attributes: {},
+ combinator: null,
+ tests: []
+ };
+ },
+
+ /**
+ Break selector into token units per simple selector.
+ Combinator is attached to the previous token.
+ */
+ _tokenize: function(selector) {
+ selector = selector || '';
+ selector = Selector._replaceShorthand(Y.Lang.trim(selector));
+ var token = Selector._getToken(), // one token per simple selector (left selector holds combinator)
+ query = selector, // original query for debug report
+ tokens = [], // array of tokens
+ found = false, // whether or not any matches were found this pass
+ match, // the regex match
+ test,
+ i, parser;
+
+ /*
+ Search for selector patterns, store, and strip them from the selector string
+ until no patterns match (invalid selector) or we run out of chars.
+
+ Multiple attributes and pseudos are allowed, in any order.
+ for example:
+ 'form:first-child[type=button]:not(button)[lang|=en]'
+ */
+ outer:
+ do {
+ found = false; // reset after full pass
+ for (i = 0; (parser = Selector._parsers[i++]);) {
+ if ( (match = parser.re.exec(selector)) ) { // note assignment
+ if (parser !== COMBINATOR ) {
+ token.selector = selector;
+ }
+ selector = selector.replace(match[0], ''); // strip current match from selector
+ if (!selector.length) {
+ token.last = true;
+ }
+
+ if (Selector._attrFilters[match[1]]) { // convert class to className, etc.
+ match[1] = Selector._attrFilters[match[1]];
+ }
+
+ test = parser.fn(match, token);
+ if (test === false) { // selector not supported
+ found = false;
+ break outer;
+ } else if (test) {
+ token.tests.push(test);
+ }
+
+ if (!selector.length || parser.name === COMBINATOR) {
+ tokens.push(token);
+ token = Selector._getToken(token);
+ if (parser.name === COMBINATOR) {
+ token.combinator = Y.Selector.combinators[match[1]];
+ }
+ }
+ found = true;
+ }
+ }
+ } while (found && selector.length);
+
+ if (!found || selector.length) { // not fully parsed
+ Y.log('query: ' + query + ' contains unsupported token in: ' + selector, 'warn', 'Selector');
+ tokens = [];
+ }
+ return tokens;
+ },
+
+ _replaceShorthand: function(selector) {
+ var shorthand = Selector.shorthand,
+ attrs = selector.match(Selector._re.attr), // pull attributes to avoid false pos on "." and "#"
+ pseudos = selector.match(Selector._re.pseudos), // pull attributes to avoid false pos on "." and "#"
+ re, i, len;
+
+ if (pseudos) {
+ selector = selector.replace(Selector._re.pseudos, '!!REPLACED_PSEUDO!!');
+ }
+
+ if (attrs) {
+ selector = selector.replace(Selector._re.attr, '!!REPLACED_ATTRIBUTE!!');
+ }
+
+ for (re in shorthand) {
+ if (shorthand.hasOwnProperty(re)) {
+ selector = selector.replace(Selector._getRegExp(re, 'gi'), shorthand[re]);
+ }
+ }
+
+ if (attrs) {
+ for (i = 0, len = attrs.length; i < len; ++i) {
+ selector = selector.replace('!!REPLACED_ATTRIBUTE!!', attrs[i]);
+ }
+ }
+ if (pseudos) {
+ for (i = 0, len = pseudos.length; i < len; ++i) {
+ selector = selector.replace('!!REPLACED_PSEUDO!!', pseudos[i]);
+ }
+ }
+ return selector;
+ },
+
+ _attrFilters: {
+ 'class': 'className',
+ 'for': 'htmlFor'
+ },
+
+ getters: {
+ href: function(node, attr) {
+ return Y.DOM.getAttribute(node, attr);
+ }
+ }
+ };
+
+Y.mix(Y.Selector, SelectorCSS2, true);
+Y.Selector.getters.src = Y.Selector.getters.rel = Y.Selector.getters.href;
+
+// IE wants class with native queries
+if (Y.Selector.useNative && document.querySelector) {
+ Y.Selector.shorthand['\\.(-?[_a-z]+[-\\w]*)'] = '[class~=$1]';
+}
+
+
+
+}, '3.0.0' ,{requires:['selector-native']});
+
+
+YUI.add('selector', function(Y){}, '3.0.0' ,{use:['selector-native', 'selector-css2']});
+
diff --git a/lib/yui/3.0.0/dom/selector-min.js b/lib/yui/3.0.0/dom/selector-min.js
new file mode 100644
index 0000000000..ca2f869539
--- /dev/null
+++ b/lib/yui/3.0.0/dom/selector-min.js
@@ -0,0 +1,9 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("selector-native",function(A){(function(G){G.namespace("Selector");var E="compareDocumentPosition",F="ownerDocument",D="yui-tmp-",C=0;var B={_foundCache:[],useNative:true,_compare:("sourceIndex" in document.documentElement)?function(K,J){var I=K.sourceIndex,H=J.sourceIndex;if(I===H){return 0;}else{if(I>H){return 1;}}return -1;}:(document.documentElement[E]?function(I,H){if(I[E](H)&4){return -1;}else{return 1;}}:function(L,K){var J,H,I;if(L&&K){J=L[F].createRange();J.setStart(L,0);H=K[F].createRange();H.setStart(K,0);I=J.compareBoundaryPoints(1,H);}return I;}),_sort:function(H){if(H){H=G.Array(H,0,true);if(H.sort){H.sort(B._compare);}}return H;},_deDupe:function(H){var I=[],J,K;for(J=0;(K=H[J++]);){if(!K._found){I[I.length]=K;K._found=true;}}for(J=0;(K=I[J++]);){K._found=null;K.removeAttribute("_found");}return I;},query:function(I,P,Q,H){P=P||G.config.doc;var M=[],J=(G.Selector.useNative&&document.querySelector&&!H),L=[[I,P]],N,R,K,O=(J)?G.Selector._nativeQuery:G.Selector._bruteQuery;if(I&&O){if(!H&&(!J||P.tagName)){L=B._splitQueries(I,P);}for(K=0;(N=L[K++]);){R=O(N[0],N[1],Q);if(!Q){R=G.Array(R,0,true);}if(R){M=M.concat(R);}}if(L.length>1){M=B._sort(B._deDupe(M));}}return(Q)?(M[0]||null):M;},_splitQueries:function(J,M){var I=J.split(","),K=[],N="",L,H;if(M){if(M.tagName){M.id=M.id||G.guid();N="#"+M.id+" ";}for(L=0,H=I.length;L":{axis:"parentNode",direct:true},"+":{axis:"previousSibling",direct:true}},_parsers:[{name:E,re:/^\[([a-z]+\w*)+([~\|\^\$\*!=]=?)?['"]?([^\]]*?)['"]?\]/i,fn:function(K,L){var J=K[2]||"",I=G.Selector.operators,M;if((K[1]==="id"&&J==="=")||(K[1]==="className"&&document.getElementsByClassName&&(J==="~="||J==="="))){L.prefilter=K[1];L[K[1]]=K[3];}if(J in I){M=I[J];if(typeof M==="string"){M=G.Selector._getRegExp(M.replace("{val}",K[3]));}K[2]=M;}if(!L.last||L.prefilter!==K[1]){return K.slice(1);}}},{name:D,re:/^((?:-?[_a-z]+[\w-]*)|\*)/i,fn:function(J,K){var I=J[1].toUpperCase();K.tagName=I;if(I!=="*"&&(!K.last||K.prefilter)){return[D,"=",I];}if(!K.prefilter){K.prefilter="tagName";}}},{name:A,re:/^\s*([>+~]|\s)\s*/,fn:function(I,J){}},{name:F,re:/^:([\-\w]+)(?:\(['"]?(.+)['"]?\))*/i,fn:function(I,J){var K=C[F][I[1]];if(K){return[I[2],K];}else{return false;}}}],_getToken:function(I){return{tagName:null,id:null,className:null,attributes:{},combinator:null,tests:[]};},_tokenize:function(K){K=K||"";K=C._replaceShorthand(G.Lang.trim(K));var J=C._getToken(),P=K,O=[],Q=false,M,N,L,I;outer:do{Q=false;for(L=0;(I=C._parsers[L++]);){if((M=I.re.exec(K))){if(I!==A){J.selector=K;}K=K.replace(M[0],"");if(!K.length){J.last=true;}if(C._attrFilters[M[1]]){M[1]=C._attrFilters[M[1]];}N=I.fn(M,J);if(N===false){Q=false;break outer;}else{if(N){J.tests.push(N);}}if(!K.length||I.name===A){O.push(J);J=C._getToken(J);if(I.name===A){J.combinator=G.Selector.combinators[M[1]];}}Q=true;}}}while(Q&&K.length);if(!Q||K.length){O=[];}return O;},_replaceShorthand:function(J){var K=C.shorthand,L=J.match(C._re.attr),O=J.match(C._re.pseudos),N,M,I;if(O){J=J.replace(C._re.pseudos,"!!REPLACED_PSEUDO!!");}if(L){J=J.replace(C._re.attr,"!!REPLACED_ATTRIBUTE!!");}for(N in K){if(K.hasOwnProperty(N)){J=J.replace(C._getRegExp(N,"gi"),K[N]);}}if(L){for(M=0,I=L.length;M b) {
+ return 1;
+ }
+
+ return -1;
+
+ } : (document.documentElement[COMPARE_DOCUMENT_POSITION] ?
+ function(nodeA, nodeB) {
+ if (nodeA[COMPARE_DOCUMENT_POSITION](nodeB) & 4) {
+ return -1;
+ } else {
+ return 1;
+ }
+ } :
+ function(nodeA, nodeB) {
+ var rangeA, rangeB, compare;
+ if (nodeA && nodeB) {
+ rangeA = nodeA[OWNER_DOCUMENT].createRange();
+ rangeA.setStart(nodeA, 0);
+ rangeB = nodeB[OWNER_DOCUMENT].createRange();
+ rangeB.setStart(nodeB, 0);
+ compare = rangeA.compareBoundaryPoints(1, rangeB); // 1 === Range.START_TO_END
+ }
+
+ return compare;
+
+ }),
+
+ _sort: function(nodes) {
+ if (nodes) {
+ nodes = Y.Array(nodes, 0, true);
+ if (nodes.sort) {
+ nodes.sort(Selector._compare);
+ }
+ }
+
+ return nodes;
+ },
+
+ _deDupe: function(nodes) {
+ var ret = [],
+ i, node;
+
+ for (i = 0; (node = nodes[i++]);) {
+ if (!node._found) {
+ ret[ret.length] = node;
+ node._found = true;
+ }
+ }
+
+ for (i = 0; (node = ret[i++]);) {
+ node._found = null;
+ node.removeAttribute('_found');
+ }
+
+ return ret;
+ },
+
+ /**
+ * Retrieves a set of nodes based on a given CSS selector.
+ * @method query
+ *
+ * @param {string} selector The CSS Selector to test the node against.
+ * @param {HTMLElement} root optional An HTMLElement to start the query from. Defaults to Y.config.doc
+ * @param {Boolean} firstOnly optional Whether or not to return only the first match.
+ * @return {Array} An array of nodes that match the given selector.
+ * @static
+ */
+ query: function(selector, root, firstOnly, skipNative) {
+ root = root || Y.config.doc;
+ var ret = [],
+ useNative = (Y.Selector.useNative && document.querySelector && !skipNative),
+ queries = [[selector, root]],
+ query,
+ result,
+ i,
+ fn = (useNative) ? Y.Selector._nativeQuery : Y.Selector._bruteQuery;
+
+ if (selector && fn) {
+ // split group into seperate queries
+ if (!skipNative && // already done if skipping
+ (!useNative || root.tagName)) { // split native when element scoping is needed
+ queries = Selector._splitQueries(selector, root);
+ }
+
+ for (i = 0; (query = queries[i++]);) {
+ result = fn(query[0], query[1], firstOnly);
+ if (!firstOnly) { // coerce DOM Collection to Array
+ result = Y.Array(result, 0, true);
+ }
+ if (result) {
+ ret = ret.concat(result);
+ }
+ }
+
+ if (queries.length > 1) { // remove dupes and sort by doc order
+ ret = Selector._sort(Selector._deDupe(ret));
+ }
+ }
+
+ Y.log('query: ' + selector + ' returning: ' + ret.length, 'info', 'Selector');
+ return (firstOnly) ? (ret[0] || null) : ret;
+
+ },
+
+ // allows element scoped queries to begin with combinator
+ // e.g. query('> p', document.body) === query('body > p')
+ _splitQueries: function(selector, node) {
+ var groups = selector.split(','),
+ queries = [],
+ prefix = '',
+ i, len;
+
+ if (node) {
+ // enforce for element scoping
+ if (node.tagName) {
+ node.id = node.id || Y.guid();
+ prefix = '#' + node.id + ' ';
+ }
+
+ for (i = 0, len = groups.length; i < len; ++i) {
+ selector = prefix + groups[i];
+ queries.push([selector, node]);
+ }
+ }
+
+ return queries;
+ },
+
+ _nativeQuery: function(selector, root, one) {
+ try {
+ //Y.log('trying native query with: ' + selector, 'info', 'selector-native');
+ return root['querySelector' + (one ? '' : 'All')](selector);
+ } catch(e) { // fallback to brute if available
+ //Y.log('native query error; reverting to brute query with: ' + selector, 'info', 'selector-native');
+ return Y.Selector.query(selector, root, one, true); // redo with skipNative true
+ }
+ },
+
+ filter: function(nodes, selector) {
+ var ret = [],
+ i, node;
+
+ if (nodes && selector) {
+ for (i = 0; (node = nodes[i++]);) {
+ if (Y.Selector.test(node, selector)) {
+ ret[ret.length] = node;
+ }
+ }
+ } else {
+ Y.log('invalid filter input (nodes: ' + nodes +
+ ', selector: ' + selector + ')', 'warn', 'Selector');
+ }
+
+ return ret;
+ },
+
+ test: function(node, selector, root) {
+ var ret = false,
+ groups = selector.split(','),
+ item,
+ i, group;
+
+ if (node && node.tagName) { // only test HTMLElements
+ root = root || node.ownerDocument;
+
+ if (!node.id) {
+ node.id = TMP_PREFIX + g_counter++;
+ }
+ for (i = 0; (group = groups[i++]);) { // TODO: off-dom test
+ group += '#' + node.id; // add ID for uniqueness
+ item = Y.Selector.query(group, root, true);
+ ret = (item === node);
+ if (ret) {
+ break;
+ }
+ }
+ }
+
+ return ret;
+ }
+};
+
+Y.mix(Y.Selector, Selector, true);
+
+})(Y);
+
+
+}, '3.0.0' ,{requires:['dom-base']});
diff --git a/lib/yui/3.0.0/dom/selector-native-min.js b/lib/yui/3.0.0/dom/selector-native-min.js
new file mode 100644
index 0000000000..66aaad134e
--- /dev/null
+++ b/lib/yui/3.0.0/dom/selector-native-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("selector-native",function(A){(function(G){G.namespace("Selector");var E="compareDocumentPosition",F="ownerDocument",D="yui-tmp-",C=0;var B={_foundCache:[],useNative:true,_compare:("sourceIndex" in document.documentElement)?function(K,J){var I=K.sourceIndex,H=J.sourceIndex;if(I===H){return 0;}else{if(I>H){return 1;}}return -1;}:(document.documentElement[E]?function(I,H){if(I[E](H)&4){return -1;}else{return 1;}}:function(L,K){var J,H,I;if(L&&K){J=L[F].createRange();J.setStart(L,0);H=K[F].createRange();H.setStart(K,0);I=J.compareBoundaryPoints(1,H);}return I;}),_sort:function(H){if(H){H=G.Array(H,0,true);if(H.sort){H.sort(B._compare);}}return H;},_deDupe:function(H){var I=[],J,K;for(J=0;(K=H[J++]);){if(!K._found){I[I.length]=K;K._found=true;}}for(J=0;(K=I[J++]);){K._found=null;K.removeAttribute("_found");}return I;},query:function(I,P,Q,H){P=P||G.config.doc;var M=[],J=(G.Selector.useNative&&document.querySelector&&!H),L=[[I,P]],N,R,K,O=(J)?G.Selector._nativeQuery:G.Selector._bruteQuery;if(I&&O){if(!H&&(!J||P.tagName)){L=B._splitQueries(I,P);}for(K=0;(N=L[K++]);){R=O(N[0],N[1],Q);if(!Q){R=G.Array(R,0,true);}if(R){M=M.concat(R);}}if(L.length>1){M=B._sort(B._deDupe(M));}}return(Q)?(M[0]||null):M;},_splitQueries:function(J,M){var I=J.split(","),K=[],N="",L,H;if(M){if(M.tagName){M.id=M.id||G.guid();N="#"+M.id+" ";}for(L=0,H=I.length;L b) {
+ return 1;
+ }
+
+ return -1;
+
+ } : (document.documentElement[COMPARE_DOCUMENT_POSITION] ?
+ function(nodeA, nodeB) {
+ if (nodeA[COMPARE_DOCUMENT_POSITION](nodeB) & 4) {
+ return -1;
+ } else {
+ return 1;
+ }
+ } :
+ function(nodeA, nodeB) {
+ var rangeA, rangeB, compare;
+ if (nodeA && nodeB) {
+ rangeA = nodeA[OWNER_DOCUMENT].createRange();
+ rangeA.setStart(nodeA, 0);
+ rangeB = nodeB[OWNER_DOCUMENT].createRange();
+ rangeB.setStart(nodeB, 0);
+ compare = rangeA.compareBoundaryPoints(1, rangeB); // 1 === Range.START_TO_END
+ }
+
+ return compare;
+
+ }),
+
+ _sort: function(nodes) {
+ if (nodes) {
+ nodes = Y.Array(nodes, 0, true);
+ if (nodes.sort) {
+ nodes.sort(Selector._compare);
+ }
+ }
+
+ return nodes;
+ },
+
+ _deDupe: function(nodes) {
+ var ret = [],
+ i, node;
+
+ for (i = 0; (node = nodes[i++]);) {
+ if (!node._found) {
+ ret[ret.length] = node;
+ node._found = true;
+ }
+ }
+
+ for (i = 0; (node = ret[i++]);) {
+ node._found = null;
+ node.removeAttribute('_found');
+ }
+
+ return ret;
+ },
+
+ /**
+ * Retrieves a set of nodes based on a given CSS selector.
+ * @method query
+ *
+ * @param {string} selector The CSS Selector to test the node against.
+ * @param {HTMLElement} root optional An HTMLElement to start the query from. Defaults to Y.config.doc
+ * @param {Boolean} firstOnly optional Whether or not to return only the first match.
+ * @return {Array} An array of nodes that match the given selector.
+ * @static
+ */
+ query: function(selector, root, firstOnly, skipNative) {
+ root = root || Y.config.doc;
+ var ret = [],
+ useNative = (Y.Selector.useNative && document.querySelector && !skipNative),
+ queries = [[selector, root]],
+ query,
+ result,
+ i,
+ fn = (useNative) ? Y.Selector._nativeQuery : Y.Selector._bruteQuery;
+
+ if (selector && fn) {
+ // split group into seperate queries
+ if (!skipNative && // already done if skipping
+ (!useNative || root.tagName)) { // split native when element scoping is needed
+ queries = Selector._splitQueries(selector, root);
+ }
+
+ for (i = 0; (query = queries[i++]);) {
+ result = fn(query[0], query[1], firstOnly);
+ if (!firstOnly) { // coerce DOM Collection to Array
+ result = Y.Array(result, 0, true);
+ }
+ if (result) {
+ ret = ret.concat(result);
+ }
+ }
+
+ if (queries.length > 1) { // remove dupes and sort by doc order
+ ret = Selector._sort(Selector._deDupe(ret));
+ }
+ }
+
+ return (firstOnly) ? (ret[0] || null) : ret;
+
+ },
+
+ // allows element scoped queries to begin with combinator
+ // e.g. query('> p', document.body) === query('body > p')
+ _splitQueries: function(selector, node) {
+ var groups = selector.split(','),
+ queries = [],
+ prefix = '',
+ i, len;
+
+ if (node) {
+ // enforce for element scoping
+ if (node.tagName) {
+ node.id = node.id || Y.guid();
+ prefix = '#' + node.id + ' ';
+ }
+
+ for (i = 0, len = groups.length; i < len; ++i) {
+ selector = prefix + groups[i];
+ queries.push([selector, node]);
+ }
+ }
+
+ return queries;
+ },
+
+ _nativeQuery: function(selector, root, one) {
+ try {
+ return root['querySelector' + (one ? '' : 'All')](selector);
+ } catch(e) { // fallback to brute if available
+ return Y.Selector.query(selector, root, one, true); // redo with skipNative true
+ }
+ },
+
+ filter: function(nodes, selector) {
+ var ret = [],
+ i, node;
+
+ if (nodes && selector) {
+ for (i = 0; (node = nodes[i++]);) {
+ if (Y.Selector.test(node, selector)) {
+ ret[ret.length] = node;
+ }
+ }
+ } else {
+ }
+
+ return ret;
+ },
+
+ test: function(node, selector, root) {
+ var ret = false,
+ groups = selector.split(','),
+ item,
+ i, group;
+
+ if (node && node.tagName) { // only test HTMLElements
+ root = root || node.ownerDocument;
+
+ if (!node.id) {
+ node.id = TMP_PREFIX + g_counter++;
+ }
+ for (i = 0; (group = groups[i++]);) { // TODO: off-dom test
+ group += '#' + node.id; // add ID for uniqueness
+ item = Y.Selector.query(group, root, true);
+ ret = (item === node);
+ if (ret) {
+ break;
+ }
+ }
+ }
+
+ return ret;
+ }
+};
+
+Y.mix(Y.Selector, Selector, true);
+
+})(Y);
+
+
+}, '3.0.0' ,{requires:['dom-base']});
diff --git a/lib/yui/3.0.0/dom/selector.js b/lib/yui/3.0.0/dom/selector.js
new file mode 100644
index 0000000000..5210626726
--- /dev/null
+++ b/lib/yui/3.0.0/dom/selector.js
@@ -0,0 +1,673 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('selector-native', function(Y) {
+
+(function(Y) {
+/**
+ * The selector-native module provides support for native querySelector
+ * @module dom
+ * @submodule selector-native
+ * @for Selector
+ */
+
+/**
+ * Provides support for using CSS selectors to query the DOM
+ * @class Selector
+ * @static
+ * @for Selector
+ */
+
+Y.namespace('Selector'); // allow native module to standalone
+
+var COMPARE_DOCUMENT_POSITION = 'compareDocumentPosition',
+ OWNER_DOCUMENT = 'ownerDocument',
+ TMP_PREFIX = 'yui-tmp-',
+ g_counter = 0;
+
+var Selector = {
+ _foundCache: [],
+
+ useNative: true,
+
+ _compare: ('sourceIndex' in document.documentElement) ?
+ function(nodeA, nodeB) {
+ var a = nodeA.sourceIndex,
+ b = nodeB.sourceIndex;
+
+ if (a === b) {
+ return 0;
+ } else if (a > b) {
+ return 1;
+ }
+
+ return -1;
+
+ } : (document.documentElement[COMPARE_DOCUMENT_POSITION] ?
+ function(nodeA, nodeB) {
+ if (nodeA[COMPARE_DOCUMENT_POSITION](nodeB) & 4) {
+ return -1;
+ } else {
+ return 1;
+ }
+ } :
+ function(nodeA, nodeB) {
+ var rangeA, rangeB, compare;
+ if (nodeA && nodeB) {
+ rangeA = nodeA[OWNER_DOCUMENT].createRange();
+ rangeA.setStart(nodeA, 0);
+ rangeB = nodeB[OWNER_DOCUMENT].createRange();
+ rangeB.setStart(nodeB, 0);
+ compare = rangeA.compareBoundaryPoints(1, rangeB); // 1 === Range.START_TO_END
+ }
+
+ return compare;
+
+ }),
+
+ _sort: function(nodes) {
+ if (nodes) {
+ nodes = Y.Array(nodes, 0, true);
+ if (nodes.sort) {
+ nodes.sort(Selector._compare);
+ }
+ }
+
+ return nodes;
+ },
+
+ _deDupe: function(nodes) {
+ var ret = [],
+ i, node;
+
+ for (i = 0; (node = nodes[i++]);) {
+ if (!node._found) {
+ ret[ret.length] = node;
+ node._found = true;
+ }
+ }
+
+ for (i = 0; (node = ret[i++]);) {
+ node._found = null;
+ node.removeAttribute('_found');
+ }
+
+ return ret;
+ },
+
+ /**
+ * Retrieves a set of nodes based on a given CSS selector.
+ * @method query
+ *
+ * @param {string} selector The CSS Selector to test the node against.
+ * @param {HTMLElement} root optional An HTMLElement to start the query from. Defaults to Y.config.doc
+ * @param {Boolean} firstOnly optional Whether or not to return only the first match.
+ * @return {Array} An array of nodes that match the given selector.
+ * @static
+ */
+ query: function(selector, root, firstOnly, skipNative) {
+ root = root || Y.config.doc;
+ var ret = [],
+ useNative = (Y.Selector.useNative && document.querySelector && !skipNative),
+ queries = [[selector, root]],
+ query,
+ result,
+ i,
+ fn = (useNative) ? Y.Selector._nativeQuery : Y.Selector._bruteQuery;
+
+ if (selector && fn) {
+ // split group into seperate queries
+ if (!skipNative && // already done if skipping
+ (!useNative || root.tagName)) { // split native when element scoping is needed
+ queries = Selector._splitQueries(selector, root);
+ }
+
+ for (i = 0; (query = queries[i++]);) {
+ result = fn(query[0], query[1], firstOnly);
+ if (!firstOnly) { // coerce DOM Collection to Array
+ result = Y.Array(result, 0, true);
+ }
+ if (result) {
+ ret = ret.concat(result);
+ }
+ }
+
+ if (queries.length > 1) { // remove dupes and sort by doc order
+ ret = Selector._sort(Selector._deDupe(ret));
+ }
+ }
+
+ return (firstOnly) ? (ret[0] || null) : ret;
+
+ },
+
+ // allows element scoped queries to begin with combinator
+ // e.g. query('> p', document.body) === query('body > p')
+ _splitQueries: function(selector, node) {
+ var groups = selector.split(','),
+ queries = [],
+ prefix = '',
+ i, len;
+
+ if (node) {
+ // enforce for element scoping
+ if (node.tagName) {
+ node.id = node.id || Y.guid();
+ prefix = '#' + node.id + ' ';
+ }
+
+ for (i = 0, len = groups.length; i < len; ++i) {
+ selector = prefix + groups[i];
+ queries.push([selector, node]);
+ }
+ }
+
+ return queries;
+ },
+
+ _nativeQuery: function(selector, root, one) {
+ try {
+ return root['querySelector' + (one ? '' : 'All')](selector);
+ } catch(e) { // fallback to brute if available
+ return Y.Selector.query(selector, root, one, true); // redo with skipNative true
+ }
+ },
+
+ filter: function(nodes, selector) {
+ var ret = [],
+ i, node;
+
+ if (nodes && selector) {
+ for (i = 0; (node = nodes[i++]);) {
+ if (Y.Selector.test(node, selector)) {
+ ret[ret.length] = node;
+ }
+ }
+ } else {
+ }
+
+ return ret;
+ },
+
+ test: function(node, selector, root) {
+ var ret = false,
+ groups = selector.split(','),
+ item,
+ i, group;
+
+ if (node && node.tagName) { // only test HTMLElements
+ root = root || node.ownerDocument;
+
+ if (!node.id) {
+ node.id = TMP_PREFIX + g_counter++;
+ }
+ for (i = 0; (group = groups[i++]);) { // TODO: off-dom test
+ group += '#' + node.id; // add ID for uniqueness
+ item = Y.Selector.query(group, root, true);
+ ret = (item === node);
+ if (ret) {
+ break;
+ }
+ }
+ }
+
+ return ret;
+ }
+};
+
+Y.mix(Y.Selector, Selector, true);
+
+})(Y);
+
+
+}, '3.0.0' ,{requires:['dom-base']});
+YUI.add('selector-css2', function(Y) {
+
+/**
+ * The selector module provides helper methods allowing CSS2 Selectors to be used with DOM elements.
+ * @module dom
+ * @submodule selector-css2
+ * @for Selector
+ */
+
+/**
+ * Provides helper methods for collecting and filtering DOM elements.
+ */
+
+var PARENT_NODE = 'parentNode',
+ TAG_NAME = 'tagName',
+ ATTRIBUTES = 'attributes',
+ COMBINATOR = 'combinator',
+ PSEUDOS = 'pseudos',
+
+ Selector = Y.Selector,
+
+ SelectorCSS2 = {
+ SORT_RESULTS: true,
+ _children: function(node, tag) {
+ var ret = node.children,
+ i,
+ children = [],
+ childNodes,
+ child;
+
+ if (node.children && tag && node.children.tags) {
+ children = node.children.tags(tag);
+ } else if ((!ret && node[TAG_NAME]) || (ret && tag)) { // only HTMLElements have children
+ childNodes = ret || node.childNodes;
+ ret = [];
+ for (i = 0; (child = childNodes[i++]);) {
+ if (child.tagName) {
+ if (!tag || tag === child.tagName) {
+ ret.push(child);
+ }
+ }
+ }
+ }
+
+ return ret || [];
+ },
+
+ _regexCache: {},
+
+ _re: {
+ attr: /(\[.*\])/g,
+ pseudos: /:([\-\w]+(?:\(?:['"]?(.+)['"]?\)))*/i
+ },
+
+ /**
+ * Mapping of shorthand tokens to corresponding attribute selector
+ * @property shorthand
+ * @type object
+ */
+ shorthand: {
+ '\\#(-?[_a-z]+[-\\w]*)': '[id=$1]',
+ '\\.(-?[_a-z]+[-\\w]*)': '[className~=$1]'
+ },
+
+ /**
+ * List of operators and corresponding boolean functions.
+ * These functions are passed the attribute and the current node's value of the attribute.
+ * @property operators
+ * @type object
+ */
+ operators: {
+ '': function(node, attr) { return Y.DOM.getAttribute(node, attr) !== ''; }, // Just test for existence of attribute
+ //'': '.+',
+ //'=': '^{val}$', // equality
+ '~=': '(?:^|\\s+){val}(?:\\s+|$)', // space-delimited
+ '|=': '^{val}-?' // optional hyphen-delimited
+ },
+
+ pseudos: {
+ 'first-child': function(node) {
+ return Y.Selector._children(node[PARENT_NODE])[0] === node;
+ }
+ },
+
+ _bruteQuery: function(selector, root, firstOnly) {
+ var ret = [],
+ nodes = [],
+ tokens = Selector._tokenize(selector),
+ token = tokens[tokens.length - 1],
+ rootDoc = Y.DOM._getDoc(root),
+ id,
+ className,
+ tagName;
+
+
+ // if we have an initial ID, set to root when in document
+ if (tokens[0] && rootDoc === root &&
+ (id = tokens[0].id) &&
+ rootDoc.getElementById(id)) {
+ root = rootDoc.getElementById(id);
+ }
+
+ if (token) {
+ // prefilter nodes
+ id = token.id;
+ className = token.className;
+ tagName = token.tagName || '*';
+
+ // try ID first
+ if (id) {
+ if (rootDoc.getElementById(id)) { // if in document
+ nodes = [rootDoc.getElementById(id)]; // TODO: DOM.byId?
+ }
+ // try className if supported
+ } else if (className) {
+ nodes = root.getElementsByClassName(className);
+ } else if (tagName) { // default to tagName
+ nodes = root.getElementsByTagName(tagName || '*');
+ }
+
+ if (nodes.length) {
+ ret = Selector._filterNodes(nodes, tokens, firstOnly);
+ }
+ }
+
+ return ret;
+ },
+
+ _filterNodes: function(nodes, tokens, firstOnly) {
+ var i = 0,
+ j,
+ len = tokens.length,
+ n = len - 1,
+ result = [],
+ node = nodes[0],
+ tmpNode = node,
+ getters = Y.Selector.getters,
+ operator,
+ combinator,
+ token,
+ path,
+ pass,
+ //FUNCTION = 'function',
+ value,
+ tests,
+ test;
+
+ //do {
+ for (i = 0; (tmpNode = node = nodes[i++]);) {
+ n = len - 1;
+ path = null;
+
+ testLoop:
+ while (tmpNode && tmpNode.tagName) {
+ token = tokens[n];
+ tests = token.tests;
+ j = tests.length;
+ if (j && !pass) {
+ while ((test = tests[--j])) {
+ operator = test[1];
+ if (getters[test[0]]) {
+ value = getters[test[0]](tmpNode, test[0]);
+ } else {
+ value = tmpNode[test[0]];
+ // use getAttribute for non-standard attributes
+ if (value === undefined && tmpNode.getAttribute) {
+ value = tmpNode.getAttribute(test[0]);
+ }
+ }
+
+ if ((operator === '=' && value !== test[2]) || // fast path for equality
+ (operator.test && !operator.test(value)) || // regex test
+ (operator.call && !operator(tmpNode, test[0]))) { // function test
+
+ // skip non element nodes or non-matching tags
+ if ((tmpNode = tmpNode[path])) {
+ while (tmpNode &&
+ (!tmpNode.tagName ||
+ (token.tagName && token.tagName !== tmpNode.tagName))
+ ) {
+ tmpNode = tmpNode[path];
+ }
+ }
+ continue testLoop;
+ }
+ }
+ }
+
+ n--; // move to next token
+ // now that we've passed the test, move up the tree by combinator
+ if (!pass && (combinator = token.combinator)) {
+ path = combinator.axis;
+ tmpNode = tmpNode[path];
+
+ // skip non element nodes
+ while (tmpNode && !tmpNode.tagName) {
+ tmpNode = tmpNode[path];
+ }
+
+ if (combinator.direct) { // one pass only
+ path = null;
+ }
+
+ } else { // success if we made it this far
+ result.push(node);
+ if (firstOnly) {
+ return result;
+ }
+ break;
+ }
+ }
+ }// while (tmpNode = node = nodes[++i]);
+ node = tmpNode = null;
+ return result;
+ },
+
+ _getRegExp: function(str, flags) {
+ var regexCache = Selector._regexCache;
+ flags = flags || '';
+ if (!regexCache[str + flags]) {
+ regexCache[str + flags] = new RegExp(str, flags);
+ }
+ return regexCache[str + flags];
+ },
+
+ combinators: {
+ ' ': {
+ axis: 'parentNode'
+ },
+
+ '>': {
+ axis: 'parentNode',
+ direct: true
+ },
+
+
+ '+': {
+ axis: 'previousSibling',
+ direct: true
+ }
+ },
+
+ _parsers: [
+ {
+ name: ATTRIBUTES,
+ re: /^\[([a-z]+\w*)+([~\|\^\$\*!=]=?)?['"]?([^\]]*?)['"]?\]/i,
+ fn: function(match, token) {
+ var operator = match[2] || '',
+ operators = Y.Selector.operators,
+ test;
+
+ // add prefiltering for ID and CLASS
+ if ((match[1] === 'id' && operator === '=') ||
+ (match[1] === 'className' &&
+ document.getElementsByClassName &&
+ (operator === '~=' || operator === '='))) {
+ token.prefilter = match[1];
+ token[match[1]] = match[3];
+ }
+
+ // add tests
+ if (operator in operators) {
+ test = operators[operator];
+ if (typeof test === 'string') {
+ test = Y.Selector._getRegExp(test.replace('{val}', match[3]));
+ }
+ match[2] = test;
+ }
+ if (!token.last || token.prefilter !== match[1]) {
+ return match.slice(1);
+ }
+ }
+
+ },
+ {
+ name: TAG_NAME,
+ re: /^((?:-?[_a-z]+[\w-]*)|\*)/i,
+ fn: function(match, token) {
+ var tag = match[1].toUpperCase();
+ token.tagName = tag;
+
+ if (tag !== '*' && (!token.last || token.prefilter)) {
+ return [TAG_NAME, '=', tag];
+ }
+ if (!token.prefilter) {
+ token.prefilter = 'tagName';
+ }
+ }
+ },
+ {
+ name: COMBINATOR,
+ re: /^\s*([>+~]|\s)\s*/,
+ fn: function(match, token) {
+ }
+ },
+ {
+ name: PSEUDOS,
+ re: /^:([\-\w]+)(?:\(['"]?(.+)['"]?\))*/i,
+ fn: function(match, token) {
+ var test = Selector[PSEUDOS][match[1]];
+ if (test) { // reorder match array
+ return [match[2], test];
+ } else { // selector token not supported (possibly missing CSS3 module)
+ return false;
+ }
+ }
+ }
+ ],
+
+ _getToken: function(token) {
+ return {
+ tagName: null,
+ id: null,
+ className: null,
+ attributes: {},
+ combinator: null,
+ tests: []
+ };
+ },
+
+ /**
+ Break selector into token units per simple selector.
+ Combinator is attached to the previous token.
+ */
+ _tokenize: function(selector) {
+ selector = selector || '';
+ selector = Selector._replaceShorthand(Y.Lang.trim(selector));
+ var token = Selector._getToken(), // one token per simple selector (left selector holds combinator)
+ query = selector, // original query for debug report
+ tokens = [], // array of tokens
+ found = false, // whether or not any matches were found this pass
+ match, // the regex match
+ test,
+ i, parser;
+
+ /*
+ Search for selector patterns, store, and strip them from the selector string
+ until no patterns match (invalid selector) or we run out of chars.
+
+ Multiple attributes and pseudos are allowed, in any order.
+ for example:
+ 'form:first-child[type=button]:not(button)[lang|=en]'
+ */
+ outer:
+ do {
+ found = false; // reset after full pass
+ for (i = 0; (parser = Selector._parsers[i++]);) {
+ if ( (match = parser.re.exec(selector)) ) { // note assignment
+ if (parser !== COMBINATOR ) {
+ token.selector = selector;
+ }
+ selector = selector.replace(match[0], ''); // strip current match from selector
+ if (!selector.length) {
+ token.last = true;
+ }
+
+ if (Selector._attrFilters[match[1]]) { // convert class to className, etc.
+ match[1] = Selector._attrFilters[match[1]];
+ }
+
+ test = parser.fn(match, token);
+ if (test === false) { // selector not supported
+ found = false;
+ break outer;
+ } else if (test) {
+ token.tests.push(test);
+ }
+
+ if (!selector.length || parser.name === COMBINATOR) {
+ tokens.push(token);
+ token = Selector._getToken(token);
+ if (parser.name === COMBINATOR) {
+ token.combinator = Y.Selector.combinators[match[1]];
+ }
+ }
+ found = true;
+ }
+ }
+ } while (found && selector.length);
+
+ if (!found || selector.length) { // not fully parsed
+ tokens = [];
+ }
+ return tokens;
+ },
+
+ _replaceShorthand: function(selector) {
+ var shorthand = Selector.shorthand,
+ attrs = selector.match(Selector._re.attr), // pull attributes to avoid false pos on "." and "#"
+ pseudos = selector.match(Selector._re.pseudos), // pull attributes to avoid false pos on "." and "#"
+ re, i, len;
+
+ if (pseudos) {
+ selector = selector.replace(Selector._re.pseudos, '!!REPLACED_PSEUDO!!');
+ }
+
+ if (attrs) {
+ selector = selector.replace(Selector._re.attr, '!!REPLACED_ATTRIBUTE!!');
+ }
+
+ for (re in shorthand) {
+ if (shorthand.hasOwnProperty(re)) {
+ selector = selector.replace(Selector._getRegExp(re, 'gi'), shorthand[re]);
+ }
+ }
+
+ if (attrs) {
+ for (i = 0, len = attrs.length; i < len; ++i) {
+ selector = selector.replace('!!REPLACED_ATTRIBUTE!!', attrs[i]);
+ }
+ }
+ if (pseudos) {
+ for (i = 0, len = pseudos.length; i < len; ++i) {
+ selector = selector.replace('!!REPLACED_PSEUDO!!', pseudos[i]);
+ }
+ }
+ return selector;
+ },
+
+ _attrFilters: {
+ 'class': 'className',
+ 'for': 'htmlFor'
+ },
+
+ getters: {
+ href: function(node, attr) {
+ return Y.DOM.getAttribute(node, attr);
+ }
+ }
+ };
+
+Y.mix(Y.Selector, SelectorCSS2, true);
+Y.Selector.getters.src = Y.Selector.getters.rel = Y.Selector.getters.href;
+
+// IE wants class with native queries
+if (Y.Selector.useNative && document.querySelector) {
+ Y.Selector.shorthand['\\.(-?[_a-z]+[-\\w]*)'] = '[class~=$1]';
+}
+
+
+
+}, '3.0.0' ,{requires:['selector-native']});
+
+
+YUI.add('selector', function(Y){}, '3.0.0' ,{use:['selector-native', 'selector-css2']});
+
diff --git a/lib/yui/3.0.0/dump/dump-debug.js b/lib/yui/3.0.0/dump/dump-debug.js
new file mode 100644
index 0000000000..66aa7595fa
--- /dev/null
+++ b/lib/yui/3.0.0/dump/dump-debug.js
@@ -0,0 +1,119 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dump', function(Y) {
+
+/**
+ * Returns a simple string representation of the object or array.
+ * Other types of objects will be returned unprocessed. Arrays
+ * are expected to be indexed. Use object notation for
+ * associative arrays.
+ *
+ * If included, the dump method is added to the YUI instance.
+ *
+ * @module dump
+ */
+
+ var L=Y.Lang, OBJ='{...}', FUN='f(){...}', COMMA=', ', ARROW=' => ',
+
+ /**
+ * The following methods are added to the YUI instance
+ * @class YUI~dump
+ */
+
+ /**
+ * Returns a simple string representation of the object or array.
+ * Other types of objects will be returned unprocessed. Arrays
+ * are expected to be indexed. Use object notation for
+ * associative arrays.
+ *
+ * @TODO dumping a window is causing an unhandled exception in
+ * FireFox.
+ *
+ * This method is in the 'dump' module, which is not bundled with
+ * the core YUI object
+ *
+ * @method dump
+ * @param o {object} The object to dump
+ * @param d {int} How deep to recurse child objects, default 3
+ * @return {string} the dump result
+ */
+ dump = function(o, d) {
+ var i, len, s = [], type = L.type(o);
+
+ // Cast non-objects to string
+ // Skip dates because the std toString is what we want
+ // Skip HTMLElement-like objects because trying to dump
+ // an element will cause an unhandled exception in FF 2.x
+ if (!L.isObject(o)) {
+ return o + "";
+ } else if (type == "date") {
+ return o;
+ } else if (o.nodeType && o.tagName) {
+ return o.tagName + '#' + o.id;
+ } else if (o.document && o.navigator) {
+ return 'window';
+ } else if (o.location && o.body) {
+ return 'document';
+ } else if (type == "function") {
+ return FUN;
+ }
+
+ // dig into child objects the depth specifed. Default 3
+ d = (L.isNumber(d)) ? d : 3;
+
+ // arrays [1, 2, 3]
+ if (type == "array") {
+ s.push("[");
+ for (i=0,len=o.length;i 0) ? L.dump(o[i], d-1) : OBJ);
+ } else {
+ s.push(o[i]);
+ }
+ s.push(COMMA);
+ }
+ if (s.length > 1) {
+ s.pop();
+ }
+ s.push("]");
+ // regexp /foo/
+ } else if (type == "regexp") {
+ s.push(o.toString());
+ // objects {k1 => v1, k2 => v2}
+ } else {
+ s.push("{");
+ for (i in o) {
+ if (o.hasOwnProperty(i)) {
+ try {
+ s.push(i + ARROW);
+ if (L.isObject(o[i])) {
+ s.push((d > 0) ? L.dump(o[i], d-1) : OBJ);
+ } else {
+ s.push(o[i]);
+ }
+ s.push(COMMA);
+ } catch(e) {
+ s.push('Error: ' + e.message);
+ }
+ }
+ }
+ if (s.length > 1) {
+ s.pop();
+ }
+ s.push("}");
+ }
+
+ return s.join("");
+ };
+
+ Y.dump = dump;
+ L.dump = dump;
+
+
+
+}, '3.0.0' );
diff --git a/lib/yui/3.0.0/dump/dump-min.js b/lib/yui/3.0.0/dump/dump-min.js
new file mode 100644
index 0000000000..65f3b66f9c
--- /dev/null
+++ b/lib/yui/3.0.0/dump/dump-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("dump",function(G){var B=G.Lang,C="{...}",F="f(){...}",A=", ",D=" => ",E=function(N,M){var I,H,K=[],J=B.type(N);if(!B.isObject(N)){return N+"";}else{if(J=="date"){return N;}else{if(N.nodeType&&N.tagName){return N.tagName+"#"+N.id;}else{if(N.document&&N.navigator){return"window";}else{if(N.location&&N.body){return"document";}else{if(J=="function"){return F;}}}}}}M=(B.isNumber(M))?M:3;if(J=="array"){K.push("[");for(I=0,H=N.length;I0)?B.dump(N[I],M-1):C);}else{K.push(N[I]);}K.push(A);}if(K.length>1){K.pop();}K.push("]");}else{if(J=="regexp"){K.push(N.toString());}else{K.push("{");for(I in N){if(N.hasOwnProperty(I)){try{K.push(I+D);if(B.isObject(N[I])){K.push((M>0)?B.dump(N[I],M-1):C);}else{K.push(N[I]);}K.push(A);}catch(L){K.push("Error: "+L.message);}}}if(K.length>1){K.pop();}K.push("}");}}return K.join("");};G.dump=E;B.dump=E;},"3.0.0");
\ No newline at end of file
diff --git a/lib/yui/3.0.0/dump/dump.js b/lib/yui/3.0.0/dump/dump.js
new file mode 100644
index 0000000000..66aa7595fa
--- /dev/null
+++ b/lib/yui/3.0.0/dump/dump.js
@@ -0,0 +1,119 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('dump', function(Y) {
+
+/**
+ * Returns a simple string representation of the object or array.
+ * Other types of objects will be returned unprocessed. Arrays
+ * are expected to be indexed. Use object notation for
+ * associative arrays.
+ *
+ * If included, the dump method is added to the YUI instance.
+ *
+ * @module dump
+ */
+
+ var L=Y.Lang, OBJ='{...}', FUN='f(){...}', COMMA=', ', ARROW=' => ',
+
+ /**
+ * The following methods are added to the YUI instance
+ * @class YUI~dump
+ */
+
+ /**
+ * Returns a simple string representation of the object or array.
+ * Other types of objects will be returned unprocessed. Arrays
+ * are expected to be indexed. Use object notation for
+ * associative arrays.
+ *
+ * @TODO dumping a window is causing an unhandled exception in
+ * FireFox.
+ *
+ * This method is in the 'dump' module, which is not bundled with
+ * the core YUI object
+ *
+ * @method dump
+ * @param o {object} The object to dump
+ * @param d {int} How deep to recurse child objects, default 3
+ * @return {string} the dump result
+ */
+ dump = function(o, d) {
+ var i, len, s = [], type = L.type(o);
+
+ // Cast non-objects to string
+ // Skip dates because the std toString is what we want
+ // Skip HTMLElement-like objects because trying to dump
+ // an element will cause an unhandled exception in FF 2.x
+ if (!L.isObject(o)) {
+ return o + "";
+ } else if (type == "date") {
+ return o;
+ } else if (o.nodeType && o.tagName) {
+ return o.tagName + '#' + o.id;
+ } else if (o.document && o.navigator) {
+ return 'window';
+ } else if (o.location && o.body) {
+ return 'document';
+ } else if (type == "function") {
+ return FUN;
+ }
+
+ // dig into child objects the depth specifed. Default 3
+ d = (L.isNumber(d)) ? d : 3;
+
+ // arrays [1, 2, 3]
+ if (type == "array") {
+ s.push("[");
+ for (i=0,len=o.length;i 0) ? L.dump(o[i], d-1) : OBJ);
+ } else {
+ s.push(o[i]);
+ }
+ s.push(COMMA);
+ }
+ if (s.length > 1) {
+ s.pop();
+ }
+ s.push("]");
+ // regexp /foo/
+ } else if (type == "regexp") {
+ s.push(o.toString());
+ // objects {k1 => v1, k2 => v2}
+ } else {
+ s.push("{");
+ for (i in o) {
+ if (o.hasOwnProperty(i)) {
+ try {
+ s.push(i + ARROW);
+ if (L.isObject(o[i])) {
+ s.push((d > 0) ? L.dump(o[i], d-1) : OBJ);
+ } else {
+ s.push(o[i]);
+ }
+ s.push(COMMA);
+ } catch(e) {
+ s.push('Error: ' + e.message);
+ }
+ }
+ }
+ if (s.length > 1) {
+ s.pop();
+ }
+ s.push("}");
+ }
+
+ return s.join("");
+ };
+
+ Y.dump = dump;
+ L.dump = dump;
+
+
+
+}, '3.0.0' );
diff --git a/lib/yui/3.0.0/event-custom/event-custom-base-debug.js b/lib/yui/3.0.0/event-custom/event-custom-base-debug.js
new file mode 100644
index 0000000000..e821070504
--- /dev/null
+++ b/lib/yui/3.0.0/event-custom/event-custom-base-debug.js
@@ -0,0 +1,1732 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('event-custom-base', function(Y) {
+
+/**
+ * Custom event engine, DOM event listener abstraction layer, synthetic DOM
+ * events.
+ * @module event-custom
+ */
+
+Y.Env.evt = {
+ handles: {},
+ plugins: {}
+};
+
+
+/**
+ * Custom event engine, DOM event listener abstraction layer, synthetic DOM
+ * events.
+ * @module event-custom
+ * @submodule event-custom-base
+ */
+(function() {
+
+/**
+ * Allows for the insertion of methods that are executed before or after
+ * a specified method
+ * @class Do
+ * @static
+ */
+
+var BEFORE = 0,
+ AFTER = 1;
+
+Y.Do = {
+
+ /**
+ * Cache of objects touched by the utility
+ * @property objs
+ * @static
+ */
+ objs: {},
+
+ /**
+ * Execute the supplied method before the specified function
+ * @method before
+ * @param fn {Function} the function to execute
+ * @param obj the object hosting the method to displace
+ * @param sFn {string} the name of the method to displace
+ * @param c The execution context for fn
+ * @return {string} handle for the subscription
+ * @static
+ */
+ before: function(fn, obj, sFn, c) {
+ // Y.log('Do before: ' + sFn, 'info', 'event');
+ var f = fn, a;
+ if (c) {
+ a = [fn, c].concat(Y.Array(arguments, 4, true));
+ f = Y.rbind.apply(Y, a);
+ }
+
+ return this._inject(BEFORE, f, obj, sFn);
+ },
+
+ /**
+ * Execute the supplied method after the specified function
+ * @method after
+ * @param fn {Function} the function to execute
+ * @param obj the object hosting the method to displace
+ * @param sFn {string} the name of the method to displace
+ * @param c The execution context for fn
+ * @return {string} handle for the subscription
+ * @static
+ */
+ after: function(fn, obj, sFn, c) {
+ var f = fn, a;
+ if (c) {
+ a = [fn, c].concat(Y.Array(arguments, 4, true));
+ f = Y.rbind.apply(Y, a);
+ }
+
+ return this._inject(AFTER, f, obj, sFn);
+ },
+
+ /**
+ * Execute the supplied method after the specified function
+ * @method _inject
+ * @param when {string} before or after
+ * @param fn {Function} the function to execute
+ * @param obj the object hosting the method to displace
+ * @param sFn {string} the name of the method to displace
+ * @param c The execution context for fn
+ * @return {string} handle for the subscription
+ * @private
+ * @static
+ */
+ _inject: function(when, fn, obj, sFn) {
+
+ // object id
+ var id = Y.stamp(obj), o, sid;
+
+ if (! this.objs[id]) {
+ // create a map entry for the obj if it doesn't exist
+ this.objs[id] = {};
+ }
+
+ o = this.objs[id];
+
+ if (! o[sFn]) {
+ // create a map entry for the method if it doesn't exist
+ o[sFn] = new Y.Do.Method(obj, sFn);
+
+ // re-route the method to our wrapper
+ obj[sFn] =
+ function() {
+ return o[sFn].exec.apply(o[sFn], arguments);
+ };
+ }
+
+ // subscriber id
+ sid = id + Y.stamp(fn) + sFn;
+
+ // register the callback
+ o[sFn].register(sid, fn, when);
+
+ return new Y.EventHandle(o[sFn], sid);
+
+ },
+
+ /**
+ * Detach a before or after subscription
+ * @method detach
+ * @param handle {string} the subscription handle
+ */
+ detach: function(handle) {
+
+ if (handle.detach) {
+ handle.detach();
+ }
+
+ },
+
+ _unload: function(e, me) {
+
+ }
+};
+
+//////////////////////////////////////////////////////////////////////////
+
+/**
+ * Wrapper for a displaced method with aop enabled
+ * @class Do.Method
+ * @constructor
+ * @param obj The object to operate on
+ * @param sFn The name of the method to displace
+ */
+Y.Do.Method = function(obj, sFn) {
+ this.obj = obj;
+ this.methodName = sFn;
+ this.method = obj[sFn];
+ this.before = {};
+ this.after = {};
+};
+
+/**
+ * Register a aop subscriber
+ * @method register
+ * @param sid {string} the subscriber id
+ * @param fn {Function} the function to execute
+ * @param when {string} when to execute the function
+ */
+Y.Do.Method.prototype.register = function (sid, fn, when) {
+ if (when) {
+ this.after[sid] = fn;
+ } else {
+ this.before[sid] = fn;
+ }
+};
+
+/**
+ * Unregister a aop subscriber
+ * @method delete
+ * @param sid {string} the subscriber id
+ * @param fn {Function} the function to execute
+ * @param when {string} when to execute the function
+ */
+Y.Do.Method.prototype._delete = function (sid) {
+ // Y.log('Y.Do._delete: ' + sid, 'info', 'Event');
+ delete this.before[sid];
+ delete this.after[sid];
+};
+
+/**
+ * Execute the wrapped method
+ * @method exec
+ */
+Y.Do.Method.prototype.exec = function () {
+
+ var args = Y.Array(arguments, 0, true),
+ i, ret, newRet,
+ bf = this.before,
+ af = this.after,
+ prevented = false;
+
+ // execute before
+ for (i in bf) {
+ if (bf.hasOwnProperty(i)) {
+ ret = bf[i].apply(this.obj, args);
+ if (ret) {
+ switch (ret.constructor) {
+ case Y.Do.Halt:
+ return ret.retVal;
+ case Y.Do.AlterArgs:
+ args = ret.newArgs;
+ break;
+ case Y.Do.Prevent:
+ prevented = true;
+ break;
+ default:
+ }
+ }
+ }
+ }
+
+ // execute method
+ if (!prevented) {
+ ret = this.method.apply(this.obj, args);
+ }
+
+ // execute after methods.
+ for (i in af) {
+ if (af.hasOwnProperty(i)) {
+ newRet = af[i].apply(this.obj, args);
+ // Stop processing if a Halt object is returned
+ if (newRet && newRet.constructor == Y.Do.Halt) {
+ return newRet.retVal;
+ // Check for a new return value
+ } else if (newRet && newRet.constructor == Y.Do.AlterReturn) {
+ ret = newRet.newRetVal;
+ }
+ }
+ }
+
+ return ret;
+};
+
+//////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * Return an AlterArgs object when you want to change the arguments that
+ * were passed into the function. An example would be a service that scrubs
+ * out illegal characters prior to executing the core business logic.
+ * @class Do.AlterArgs
+ */
+Y.Do.AlterArgs = function(msg, newArgs) {
+ this.msg = msg;
+ this.newArgs = newArgs;
+};
+
+/**
+ * Return an AlterReturn object when you want to change the result returned
+ * from the core method to the caller
+ * @class Do.AlterReturn
+ */
+Y.Do.AlterReturn = function(msg, newRetVal) {
+ this.msg = msg;
+ this.newRetVal = newRetVal;
+};
+
+/**
+ * Return a Halt object when you want to terminate the execution
+ * of all subsequent subscribers as well as the wrapped method
+ * if it has not exectued yet.
+ * @class Do.Halt
+ */
+Y.Do.Halt = function(msg, retVal) {
+ this.msg = msg;
+ this.retVal = retVal;
+};
+
+/**
+ * Return a Prevent object when you want to prevent the wrapped function
+ * from executing, but want the remaining listeners to execute
+ * @class Do.Prevent
+ */
+Y.Do.Prevent = function(msg) {
+ this.msg = msg;
+};
+
+/**
+ * Return an Error object when you want to terminate the execution
+ * of all subsequent method calls.
+ * @class Do.Error
+ * @deprecated use Y.Do.Halt or Y.Do.Prevent
+ */
+Y.Do.Error = Y.Do.Halt;
+
+//////////////////////////////////////////////////////////////////////////
+
+// Y["Event"] && Y.Event.addListener(window, "unload", Y.Do._unload, Y.Do);
+
+})();
+
+/**
+ * Custom event engine, DOM event listener abstraction layer, synthetic DOM
+ * events.
+ * @module event-custom
+ * @submodule event-custom-base
+ */
+
+/**
+ * Return value from all subscribe operations
+ * @class EventHandle
+ * @constructor
+ * @param evt {CustomEvent} the custom event
+ * @param sub {Subscriber} the subscriber
+ */
+
+// var onsubscribeType = "_event:onsub",
+var AFTER = 'after',
+ CONFIGS = [
+ 'broadcast',
+ 'bubbles',
+ 'context',
+ 'contextFn',
+ 'currentTarget',
+ 'defaultFn',
+ 'details',
+ 'emitFacade',
+ 'fireOnce',
+ 'host',
+ 'preventable',
+ 'preventedFn',
+ 'queuable',
+ 'silent',
+ 'stoppedFn',
+ 'target',
+ 'type'
+ ],
+
+
+ YUI3_SIGNATURE = 9,
+ YUI_LOG = 'yui:log';
+
+Y.EventHandle = function(evt, sub) {
+
+ /**
+ * The custom event
+ * @type CustomEvent
+ */
+ this.evt = evt;
+
+ /**
+ * The subscriber object
+ * @type Subscriber
+ */
+ this.sub = sub;
+};
+
+Y.EventHandle.prototype = {
+
+ /**
+ * Detaches this subscriber
+ * @method detach
+ */
+ detach: function() {
+ var evt = this.evt, i;
+ if (evt) {
+ // Y.log('EventHandle.detach: ' + this.sub, 'info', 'Event');
+ if (Y.Lang.isArray(evt)) {
+ for (i=0; i 2) {
+// this.log('CustomEvent context and silent are now in the config', 'warn', 'Event');
+ // }
+
+ o = o || {};
+
+ this.id = Y.stamp(this);
+
+ /**
+ * The type of event, returned to subscribers when the event fires
+ * @property type
+ * @type string
+ */
+ this.type = type;
+
+ /**
+ * The context the the event will fire from by default. Defaults to the YUI
+ * instance.
+ * @property context
+ * @type object
+ */
+ this.context = Y;
+
+ this.logSystem = (type == YUI_LOG);
+
+ /**
+ * If 0, this event does not broadcast. If 1, the YUI instance is notified
+ * every time this event fires. If 2, the YUI instance and the YUI global
+ * (if event is enabled on the global) are notified every time this event
+ * fires.
+ * @property broadcast
+ * @type int
+ */
+ // this.broadcast = 0;
+
+ /**
+ * By default all custom events are logged in the debug build, set silent
+ * to true to disable debug outpu for this event.
+ * @property silent
+ * @type boolean
+ */
+ this.silent = this.logSystem;
+
+ /**
+ * Specifies whether this event should be queued when the host is actively
+ * processing an event. This will effect exectution order of the callbacks
+ * for the various events.
+ * @property queuable
+ * @type boolean
+ * @default false
+ */
+ // this.queuable = false;
+
+ /**
+ * The subscribers to this event
+ * @property subscribers
+ * @type Subscriber{}
+ */
+ this.subscribers = {};
+
+ /**
+ * 'After' subscribers
+ * @property afters
+ * @type Subscriber{}
+ */
+ this.afters = {};
+
+ /**
+ * This event has fired if true
+ *
+ * @property fired
+ * @type boolean
+ * @default false;
+ */
+ // this.fired = false;
+
+ /**
+ * An array containing the arguments the custom event
+ * was last fired with.
+ * @property firedWith
+ * @type Array
+ */
+ // this.firedWith;
+
+ /**
+ * This event should only fire one time if true, and if
+ * it has fired, any new subscribers should be notified
+ * immediately.
+ *
+ * @property fireOnce
+ * @type boolean
+ * @default false;
+ */
+ // this.fireOnce = false;
+
+ /**
+ * Flag for stopPropagation that is modified during fire()
+ * 1 means to stop propagation to bubble targets. 2 means
+ * to also stop additional subscribers on this target.
+ * @property stopped
+ * @type int
+ */
+ // this.stopped = 0;
+
+ /**
+ * Flag for preventDefault that is modified during fire().
+ * if it is not 0, the default behavior for this event
+ * @property prevented
+ * @type int
+ */
+ // this.prevented = 0;
+
+ /**
+ * Specifies the host for this custom event. This is used
+ * to enable event bubbling
+ * @property host
+ * @type EventTarget
+ */
+ // this.host = null;
+
+ /**
+ * The default function to execute after event listeners
+ * have fire, but only if the default action was not
+ * prevented.
+ * @property defaultFn
+ * @type Function
+ */
+ // this.defaultFn = null;
+
+ /**
+ * The function to execute if a subscriber calls
+ * stopPropagation or stopImmediatePropagation
+ * @property stoppedFn
+ * @type Function
+ */
+ // this.stoppedFn = null;
+
+ /**
+ * The function to execute if a subscriber calls
+ * preventDefault
+ * @property preventedFn
+ * @type Function
+ */
+ // this.preventedFn = null;
+
+ /**
+ * Specifies whether or not this event's default function
+ * can be cancelled by a subscriber by executing preventDefault()
+ * on the event facade
+ * @property preventable
+ * @type boolean
+ * @default true
+ */
+ this.preventable = true;
+
+ /**
+ * Specifies whether or not a subscriber can stop the event propagation
+ * via stopPropagation(), stopImmediatePropagation(), or halt()
+ * @property bubbles
+ * @type boolean
+ * @default true
+ */
+ this.bubbles = true;
+
+ /**
+ * Supports multiple options for listener signatures in order to
+ * port YUI 2 apps.
+ * @property signature
+ * @type int
+ * @default 9
+ */
+ this.signature = YUI3_SIGNATURE;
+
+ // this.hasSubscribers = false;
+
+ // this.hasAfters = false;
+
+ /**
+ * If set to true, the custom event will deliver an EventFacade object
+ * that is similar to a DOM event object.
+ * @property emitFacade
+ * @type boolean
+ * @default false
+ */
+ // this.emitFacade = false;
+
+ this.applyConfig(o, true);
+
+ // this.log("Creating " + this.type);
+
+};
+
+Y.CustomEvent.prototype = {
+
+ /**
+ * Apply configuration properties. Only applies the CONFIG whitelist
+ * @method applyConfig
+ * @param o hash of properties to apply
+ * @param force {boolean} if true, properties that exist on the event
+ * will be overwritten.
+ */
+ applyConfig: function(o, force) {
+ if (o) {
+ Y.mix(this, o, force, CONFIGS);
+ }
+ },
+
+ _on: function(fn, context, args, when) {
+
+ if (!fn) {
+ this.log("Invalid callback for CE: " + this.type);
+ }
+
+ var s = new Y.Subscriber(fn, context, args, when);
+
+ if (this.fireOnce && this.fired) {
+ Y.later(0, this, Y.bind(this._notify, this, s, this.firedWith));
+ }
+
+ if (when == AFTER) {
+ this.afters[s.id] = s;
+ this.hasAfters = true;
+ } else {
+ this.subscribers[s.id] = s;
+ this.hasSubscribers = true;
+ }
+
+ return new Y.EventHandle(this, s);
+
+ },
+
+ /**
+ * Listen for this event
+ * @method subscribe
+ * @param {Function} fn The function to execute
+ * @return {EventHandle|EventTarget} unsubscribe handle or a
+ * chainable event target depending on the 'chain' config.
+ * @deprecated use on
+ */
+ subscribe: function(fn, context) {
+ Y.log('ce.subscribe deprecated, use "on"', 'warn', 'deprecated');
+ var a = (arguments.length > 2) ? Y.Array(arguments, 2, true): null;
+ return this._on(fn, context, a, true);
+ },
+
+ /**
+ * Listen for this event
+ * @method on
+ * @param {Function} fn The function to execute
+ * @return {EventHandle|EventTarget} unsubscribe handle or a
+ * chainable event target depending on the 'chain' config.
+ */
+ on: function(fn, context) {
+ var a = (arguments.length > 2) ? Y.Array(arguments, 2, true): null;
+ return this._on(fn, context, a, true);
+ },
+
+ /**
+ * Listen for this event after the normal subscribers have been notified and
+ * the default behavior has been applied. If a normal subscriber prevents the
+ * default behavior, it also prevents after listeners from firing.
+ * @method after
+ * @param {Function} fn The function to execute
+ * @return {EventHandle|EventTarget} unsubscribe handle or a
+ * chainable event target depending on the 'chain' config.
+ */
+ after: function(fn, context) {
+ var a = (arguments.length > 2) ? Y.Array(arguments, 2, true): null;
+ return this._on(fn, context, a, AFTER);
+ },
+
+ /**
+ * Detach listeners.
+ * @method detach
+ * @param {Function} fn The subscribed function to remove, if not supplied
+ * all will be removed
+ * @param {Object} context The context object passed to subscribe.
+ * @return {int|EventTarget} returns a chainable event target
+ * or the number of subscribers unsubscribed.
+ */
+ detach: function(fn, context) {
+ // unsubscribe handle
+ if (fn && fn.detach) {
+ return fn.detach();
+ }
+
+ var found = 0, subs = this.subscribers, i, s;
+
+ for (i in subs) {
+ if (subs.hasOwnProperty(i)) {
+ s = subs[i];
+ if (s && (!fn || fn === s.fn)) {
+ this._delete(s);
+ found++;
+ }
+ }
+ }
+
+ return found;
+ },
+
+ /**
+ * Detach listeners.
+ * @method unsubscribe
+ * @param {Function} fn The subscribed function to remove, if not supplied
+ * all will be removed
+ * @param {Object} context The context object passed to subscribe.
+ * @return {boolean|EventTarget} returns a chainable event target
+ * or a boolean for legacy detach support.
+ * @deprecated use detach
+ */
+ unsubscribe: function() {
+ return this.detach.apply(this, arguments);
+ },
+
+
+ /**
+ * Notify a single subscriber
+ * @method _notify
+ * @param s {Subscriber} the subscriber
+ * @param args {Array} the arguments array to apply to the listener
+ * @private
+ */
+ _notify: function(s, args, ef) {
+
+ this.log(this.type + "->" + "sub: " + s.id);
+
+ var ret;
+
+ ret = s.notify(args, this);
+
+ if (false === ret || this.stopped > 1) {
+ this.log(this.type + " cancelled by subscriber");
+ return false;
+ }
+
+ return true;
+ },
+
+ /**
+ * Logger abstraction to centralize the application of the silent flag
+ * @method log
+ * @param msg {string} message to log
+ * @param cat {string} log category
+ */
+ log: function(msg, cat) {
+ if (!this.silent) {
+ Y.log(this.id + ': ' + msg, cat || "info", "event");
+ }
+ },
+
+ /**
+ * Notifies the subscribers. The callback functions will be executed
+ * from the context specified when the event was created, and with the
+ * following parameters:
+ *
+ *
The type of event
+ *
All of the arguments fire() was executed with as an array
+ *
The custom object (if any) that was passed into the subscribe()
+ * method
+ *
+ * @method fire
+ * @param {Object*} arguments an arbitrary set of parameters to pass to
+ * the handler.
+ * @return {boolean} false if one of the subscribers returned false,
+ * true otherwise
+ *
+ */
+ fire: function() {
+ if (this.fireOnce && this.fired) {
+ this.log('fireOnce event: ' + this.type + ' already fired');
+ return true;
+ } else {
+
+ var args = Y.Array(arguments, 0, true);
+
+ this.fired = true;
+ this.firedWith = args;
+
+ if (this.emitFacade) {
+ return this.fireComplex(args);
+ } else {
+ return this.fireSimple(args);
+ }
+ }
+ },
+
+ fireSimple: function(args) {
+ if (this.hasSubscribers || this.hasAfters) {
+ this._procSubs(Y.merge(this.subscribers, this.afters), args);
+ }
+ this._broadcast(args);
+ return this.stopped ? false : true;
+ },
+
+ // Requires the event-custom-complex module for full funcitonality.
+ fireComplex: function(args) {
+ args[0] = args[0] || {};
+ return this.fireSimple(args);
+ },
+
+ _procSubs: function(subs, args, ef) {
+ var s, i;
+ for (i in subs) {
+ if (subs.hasOwnProperty(i)) {
+ s = subs[i];
+ if (s && s.fn) {
+ if (false === this._notify(s, args, ef)) {
+ this.stopped = 2;
+ }
+ if (this.stopped == 2) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ },
+
+ _broadcast: function(args) {
+ if (!this.stopped && this.broadcast) {
+
+ var a = Y.Array(args);
+ a.unshift(this.type);
+
+ if (this.host !== Y) {
+ Y.fire.apply(Y, a);
+ }
+
+ if (this.broadcast == 2) {
+ Y.Global.fire.apply(Y.Global, a);
+ }
+ }
+ },
+
+ /**
+ * Removes all listeners
+ * @method unsubscribeAll
+ * @return {int} The number of listeners unsubscribed
+ * @deprecated use detachAll
+ */
+ unsubscribeAll: function() {
+ return this.detachAll.apply(this, arguments);
+ },
+
+ /**
+ * Removes all listeners
+ * @method detachAll
+ * @return {int} The number of listeners unsubscribed
+ */
+ detachAll: function() {
+ return this.detach();
+ },
+
+ /**
+ * @method _delete
+ * @param subscriber object
+ * @private
+ */
+ _delete: function(s) {
+ if (s) {
+ delete s.fn;
+ delete s.context;
+ delete this.subscribers[s.id];
+ delete this.afters[s.id];
+ }
+ }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn The wrapped function to execute
+ * @param {Object} context The value of the keyword 'this' in the listener
+ * @param {Array} args* 0..n additional arguments to supply the listener
+ *
+ * @class Subscriber
+ * @constructor
+ */
+Y.Subscriber = function(fn, context, args) {
+
+ /**
+ * The callback that will be execute when the event fires
+ * This is wrapped by Y.rbind if obj was supplied.
+ * @property fn
+ * @type Function
+ */
+ this.fn = fn;
+
+ /**
+ * Optional 'this' keyword for the listener
+ * @property context
+ * @type Object
+ */
+ this.context = context;
+
+ /**
+ * Unique subscriber id
+ * @property id
+ * @type String
+ */
+ this.id = Y.stamp(this);
+
+ /**
+ * Additional arguments to propagate to the subscriber
+ * @property args
+ * @type Array
+ */
+ this.args = args;
+
+ /**
+ * Custom events for a given fire transaction.
+ * @property events
+ * @type {EventTarget}
+ */
+ this.events = null;
+
+};
+
+Y.Subscriber.prototype = {
+
+ _notify: function(c, args, ce) {
+ var a = this.args, ret;
+ switch (ce.signature) {
+ case 0:
+ ret = this.fn.call(c, ce.type, args, c);
+ break;
+ case 1:
+ ret = this.fn.call(c, args[0] || null, c);
+ break;
+ default:
+ if (a || args) {
+ args = args || [];
+ a = (a) ? args.concat(a) : args;
+ ret = this.fn.apply(c, a);
+ } else {
+ ret = this.fn.call(c);
+ }
+ }
+
+ return ret;
+ },
+
+ /**
+ * Executes the subscriber.
+ * @method notify
+ * @param args {Array} Arguments array for the subscriber
+ * @param ce {CustomEvent} The custom event that sent the notification
+ */
+ notify: function(args, ce) {
+ var c = this.context,
+ ret = true;
+
+ if (!c) {
+ c = (ce.contextFn) ? ce.contextFn() : ce.context;
+ }
+
+ // only catch errors if we will not re-throw them.
+ if (Y.config.throwFail) {
+ ret = this._notify(c, args, ce);
+ } else {
+ try {
+ ret = this._notify(c, args, ce);
+ } catch(e) {
+ Y.error(this + ' failed: ' + e.message, e);
+ }
+ }
+
+ return ret;
+ },
+
+ /**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} context optional 'this' keyword for the listener
+ * @return {boolean} true if the supplied arguments match this
+ * subscriber's signature.
+ */
+ contains: function(fn, context) {
+ if (context) {
+ return ((this.fn == fn) && this.context == context);
+ } else {
+ return (this.fn == fn);
+ }
+ }
+
+};
+
+/**
+ * Custom event engine, DOM event listener abstraction layer, synthetic DOM
+ * events.
+ * @module event-custom
+ * @submodule event-custom-base
+ */
+(function() {
+
+/**
+ * EventTarget provides the implementation for any object to
+ * publish, subscribe and fire to custom events, and also
+ * alows other EventTargets to target the object with events
+ * sourced from the other object.
+ * EventTarget is designed to be used with Y.augment to wrap
+ * EventCustom in an interface that allows events to be listened to
+ * and fired by name. This makes it possible for implementing code to
+ * subscribe to an event that either has not been created yet, or will
+ * not be created at all.
+ * @class EventTarget
+ * @param opts a configuration object
+ * @config emitFacade {boolean} if true, all events will emit event
+ * facade payloads by default (default false)
+ * @config prefix {string} the prefix to apply to non-prefixed event names
+ * @config chain {boolean} if true, on/after/detach return the host to allow
+ * chaining, otherwise they return an EventHandle (default false)
+ */
+
+var L = Y.Lang,
+ PREFIX_DELIMITER = ':',
+ CATEGORY_DELIMITER = '|',
+ AFTER_PREFIX = '~AFTER~',
+
+ /**
+ * If the instance has a prefix attribute and the
+ * event type is not prefixed, the instance prefix is
+ * applied to the supplied type.
+ * @method _getType
+ * @private
+ */
+ _getType = Y.cached(function(type, pre) {
+
+ if (!pre || !L.isString(type) || type.indexOf(PREFIX_DELIMITER) > -1) {
+ return type;
+ }
+
+ return pre + PREFIX_DELIMITER + type;
+ }),
+
+ /**
+ * Returns an array with the detach key (if provided),
+ * and the prefixed event name from _getType
+ * Y.on('detachcategory, menu:click', fn)
+ * @method _parseType
+ * @private
+ */
+ _parseType = Y.cached(function(type, pre) {
+
+ var t = type, detachcategory, after, i;
+
+ if (!L.isString(t)) {
+ return t;
+ }
+
+ i = t.indexOf(AFTER_PREFIX);
+
+ if (i > -1) {
+ after = true;
+ t = t.substr(AFTER_PREFIX.length);
+ // Y.log(t);
+ }
+
+ i = t.indexOf(CATEGORY_DELIMITER);
+
+ if (i > -1) {
+ detachcategory = t.substr(0, (i));
+ t = t.substr(i+1);
+ if (t == '*') {
+ t = null;
+ }
+ }
+
+ // detach category, full type with instance prefix, is this an after listener, short type
+ return [detachcategory, (pre) ? _getType(t, pre) : t, after, t];
+ }),
+
+ ET = function(opts) {
+
+ // Y.log('EventTarget constructor executed: ' + this._yuid);
+
+ var o = (L.isObject(opts)) ? opts : {};
+
+ this._yuievt = this._yuievt || {
+
+ id: Y.guid(),
+
+ events: {},
+
+ targets: {},
+
+ config: o,
+
+ chain: ('chain' in o) ? o.chain : Y.config.chain,
+
+ defaults: {
+ context: o.context || this,
+ host: this,
+ emitFacade: o.emitFacade,
+ fireOnce: o.fireOnce,
+ queuable: o.queuable,
+ broadcast: o.broadcast,
+ bubbles: ('bubbles' in o) ? o.bubbles : true
+ }
+ };
+
+ };
+
+
+ET.prototype = {
+
+ /**
+ * Subscribe to a custom event hosted by this object
+ * @method on
+ * @param type {string} The type of the event
+ * @param fn {Function} The callback
+ * @return the event target or a detach handle per 'chain' config
+ */
+ on: function(type, fn, context, x) {
+
+ var parts = _parseType(type, this._yuievt.config.prefix), f, c, args, ret, ce,
+ detachcategory, handle, store = Y.Env.evt.handles, after, adapt, shorttype,
+ Node = Y.Node, n, domevent;
+
+ if (L.isObject(type)) {
+
+ if (L.isFunction(type)) {
+ return Y.Do.before.apply(Y.Do, arguments);
+ }
+
+ f = fn;
+ c = context;
+ args = Y.Array(arguments, 0, true);
+ ret = {};
+ after = type._after;
+ delete type._after;
+
+ Y.each(type, function(v, k) {
+
+ if (v) {
+ f = v.fn || ((Y.Lang.isFunction(v)) ? v : f);
+ c = v.context || c;
+ }
+
+ args[0] = (after) ? AFTER_PREFIX + k : k;
+ args[1] = f;
+ args[2] = c;
+
+ ret[k] = this.on.apply(this, args);
+
+ }, this);
+
+ return (this._yuievt.chain) ? this : new Y.EventHandle(ret);
+
+ }
+
+ detachcategory = parts[0];
+ after = parts[2];
+ shorttype = parts[3];
+
+ // extra redirection so we catch adaptor events too. take a look at this.
+ if (Node && (this instanceof Node) && (shorttype in Node.DOM_EVENTS)) {
+ args = Y.Array(arguments, 0, true);
+ args.splice(2, 0, Node.getDOMNode(this));
+ // Y.log("Node detected, redirecting with these args: " + args);
+ return Y.on.apply(Y, args);
+ }
+
+ type = parts[1];
+
+ if (this instanceof YUI) {
+
+ adapt = Y.Env.evt.plugins[type];
+ args = Y.Array(arguments, 0, true);
+ args[0] = shorttype;
+
+ if (Node) {
+ n = args[2];
+
+ if (n instanceof Y.NodeList) {
+ n = Y.NodeList.getDOMNodes(n);
+ } else if (n instanceof Node) {
+ n = Node.getDOMNode(n);
+ }
+
+ domevent = (shorttype in Node.DOM_EVENTS);
+
+ // Captures both DOM events and event plugins.
+ if (domevent) {
+ args[2] = n;
+ }
+ }
+
+ // check for the existance of an event adaptor
+ if (adapt) {
+ Y.log('Using adaptor for ' + shorttype + ', ' + n, 'info', 'event');
+ handle = adapt.on.apply(Y, args);
+ } else if ((!type) || domevent) {
+ handle = Y.Event._attach(args);
+ }
+
+ }
+
+ if (!handle) {
+ ce = this._yuievt.events[type] || this.publish(type);
+ handle = ce._on(fn, context, (arguments.length > 3) ? Y.Array(arguments, 3, true) : null, (after) ? 'after' : true);
+ }
+
+ if (detachcategory) {
+ store[detachcategory] = store[detachcategory] || {};
+ store[detachcategory][type] = store[detachcategory][type] || [];
+ store[detachcategory][type].push(handle);
+ }
+
+ return (this._yuievt.chain) ? this : handle;
+
+ },
+
+ /**
+ * subscribe to an event
+ * @method subscribe
+ * @deprecated use on
+ */
+ subscribe: function() {
+ Y.log('EventTarget subscribe() is deprecated, use on()', 'warn', 'deprecated');
+ return this.on.apply(this, arguments);
+ },
+
+ /**
+ * Detach one or more listeners the from the specified event
+ * @method detach
+ * @param type {string|Object} Either the handle to the subscriber or the
+ * type of event. If the type
+ * is not specified, it will attempt to remove
+ * the listener from all hosted events.
+ * @param fn {Function} The subscribed function to unsubscribe, if not
+ * supplied, all subscribers will be removed.
+ * @param context {Object} The custom object passed to subscribe. This is
+ * optional, but if supplied will be used to
+ * disambiguate multiple listeners that are the same
+ * (e.g., you subscribe many object using a function
+ * that lives on the prototype)
+ * @return {EventTarget} the host
+ */
+ detach: function(type, fn, context) {
+ var evts = this._yuievt.events, i, ret,
+ Node = Y.Node, isNode = (this instanceof Node);
+
+ // detachAll disabled on the Y instance.
+ if (!type && (this !== Y)) {
+ for (i in evts) {
+ if (evts.hasOwnProperty(i)) {
+ ret = evts[i].detach(fn, context);
+ }
+ }
+ if (isNode) {
+
+ Y.Event.purgeElement(Node.getDOMNode(this));
+ }
+
+ return ret;
+ }
+
+ var parts = _parseType(type, this._yuievt.config.prefix),
+ detachcategory = L.isArray(parts) ? parts[0] : null,
+ shorttype = (parts) ? parts[3] : null,
+ handle, adapt, store = Y.Env.evt.handles, cat, args,
+ ce,
+
+ keyDetacher = function(lcat, ltype) {
+ var handles = lcat[ltype];
+ if (handles) {
+ while (handles.length) {
+ handle = handles.pop();
+ handle.detach();
+ }
+ }
+ };
+
+ if (detachcategory) {
+
+ cat = store[detachcategory];
+ type = parts[1];
+
+ if (cat) {
+ if (type) {
+ keyDetacher(cat, type);
+ } else {
+ for (i in cat) {
+ if (cat.hasOwnProperty(i)) {
+ keyDetacher(cat, i);
+ }
+ }
+ }
+
+ return (this._yuievt.chain) ? this : true;
+ }
+
+ // If this is an event handle, use it to detach
+ } else if (L.isObject(type) && type.detach) {
+ ret = type.detach();
+ return (this._yuievt.chain) ? this : ret;
+ // extra redirection so we catch adaptor events too. take a look at this.
+ } else if (isNode && ((!shorttype) || (shorttype in Node.DOM_EVENTS))) {
+ args = Y.Array(arguments, 0, true);
+ args[2] = Node.getDOMNode(this);
+ return Y.detach.apply(Y, args);
+ }
+
+ adapt = Y.Env.evt.plugins[shorttype];
+
+ // The YUI instance handles DOM events and adaptors
+ if (this instanceof YUI) {
+ args = Y.Array(arguments, 0, true);
+ // use the adaptor specific detach code if
+ if (adapt && adapt.detach) {
+ return adapt.detach.apply(Y, args);
+ // DOM event fork
+ } else if (!type || (!adapt && Node && (type in Node.DOM_EVENTS))) {
+ args[0] = type;
+ return Y.Event.detach.apply(Y.Event, args);
+ }
+ }
+
+ ce = evts[type];
+ if (ce) {
+ ret = ce.detach(fn, context);
+ }
+
+ return (this._yuievt.chain) ? this : ret;
+ },
+
+ /**
+ * detach a listener
+ * @method unsubscribe
+ * @deprecated use detach
+ */
+ unsubscribe: function() {
+ return this.detach.apply(this, arguments);
+ },
+
+ /**
+ * Removes all listeners from the specified event. If the event type
+ * is not specified, all listeners from all hosted custom events will
+ * be removed.
+ * @method detachAll
+ * @param type {string} The type, or name of the event
+ */
+ detachAll: function(type) {
+ return this.detach(type);
+ },
+
+ /**
+ * Removes all listeners from the specified event. If the event type
+ * is not specified, all listeners from all hosted custom events will
+ * be removed.
+ * @method unsubscribeAll
+ * @param type {string} The type, or name of the event
+ * @deprecated use detachAll
+ */
+ unsubscribeAll: function() {
+ return this.detachAll.apply(this, arguments);
+ },
+
+ /**
+ * Creates a new custom event of the specified type. If a custom event
+ * by that name already exists, it will not be re-created. In either
+ * case the custom event is returned.
+ *
+ * @method publish
+ *
+ * @param type {string} the type, or name of the event
+ * @param opts {object} optional config params. Valid properties are:
+ *
+ *
+ *
+ * 'broadcast': whether or not the YUI instance and YUI global are notified when the event is fired (false)
+ *
+ *
+ * 'bubbles': whether or not this event bubbles (true)
+ *
+ *
+ * 'context': the default execution context for the listeners (this)
+ *
+ *
+ * 'defaultFn': the default function to execute when this event fires if preventDefault was not called
+ *
+ *
+ * 'emitFacade': whether or not this event emits a facade (false)
+ *
+ *
+ * 'prefix': the prefix for this targets events, e.g., 'menu' in 'menu:click'
+ *
+ *
+ * 'fireOnce': if an event is configured to fire once, new subscribers after
+ * the fire will be notified immediately.
+ *
+ *
+ * 'preventable': whether or not preventDefault() has an effect (true)
+ *
+ *
+ * 'preventedFn': a function that is executed when preventDefault is called
+ *
+ *
+ * 'queuable': whether or not this event can be queued during bubbling (false)
+ *
+ *
+ * 'silent': if silent is true, debug messages are not provided for this event.
+ *
+ *
+ * 'stoppedFn': a function that is executed when stopPropagation is called
+ *
+ *
+ * 'type': the event type (valid option if not provided as the first parameter to publish)
+ *
+ *
+ *
+ * @return {Event.Custom} the custom event
+ *
+ */
+ publish: function(type, opts) {
+ var events, ce, ret, pre = this._yuievt.config.prefix;
+
+ type = (pre) ? _getType(type, pre) : type;
+
+
+ if (L.isObject(type)) {
+ ret = {};
+ Y.each(type, function(v, k) {
+ ret[k] = this.publish(k, v || opts);
+ }, this);
+
+ return ret;
+ }
+
+ events = this._yuievt.events;
+ ce = events[type];
+
+ if (ce) {
+// ce.log("publish applying new config to published event: '"+type+"' exists", 'info', 'event');
+ if (opts) {
+ ce.applyConfig(opts, true);
+ }
+ } else {
+ // apply defaults
+ ce = new Y.CustomEvent(type, (opts) ? Y.mix(opts, this._yuievt.defaults) : this._yuievt.defaults);
+ events[type] = ce;
+ }
+
+ // make sure we turn the broadcast flag off if this
+ // event was published as a result of bubbling
+ // if (opts instanceof Y.CustomEvent) {
+ // events[type].broadcast = false;
+ // }
+
+ return events[type];
+ },
+
+ /**
+ * Registers another EventTarget as a bubble target. Bubble order
+ * is determined by the order registered. Multiple targets can
+ * be specified.
+ * @method addTarget
+ * @param o {EventTarget} the target to add
+ */
+ addTarget: function(o) {
+ this._yuievt.targets[Y.stamp(o)] = o;
+ this._yuievt.hasTargets = true;
+ },
+
+ /**
+ * Removes a bubble target
+ * @method removeTarget
+ * @param o {EventTarget} the target to remove
+ */
+ removeTarget: function(o) {
+ delete this._yuievt.targets[Y.stamp(o)];
+ },
+
+ /**
+ * Fire a custom event by name. The callback functions will be executed
+ * from the context specified when the event was created, and with the
+ * following parameters.
+ *
+ * If the custom event object hasn't been created, then the event hasn't
+ * been published and it has no subscribers. For performance sake, we
+ * immediate exit in this case. This means the event won't bubble, so
+ * if the intention is that a bubble target be notified, the event must
+ * be published on this object first.
+ *
+ * The first argument is the event type, and any additional arguments are
+ * passed to the listeners as parameters. If the first of these is an
+ * object literal, and the event is configured to emit an event facade,
+ * that object is mixed into the event facade and the facade is provided
+ * in place of the original object.
+ *
+ * @method fire
+ * @param type {String|Object} The type of the event, or an object that contains
+ * a 'type' property.
+ * @param arguments {Object*} an arbitrary set of parameters to pass to
+ * the handler. If the first of these is an object literal and the event is
+ * configured to emit an event facade, the event facade will replace that
+ * parameter after the properties the object literal contains are copied to
+ * the event facade.
+ * @return {Event.Target} the event host
+ *
+ */
+ fire: function(type) {
+
+ var typeIncluded = L.isString(type),
+ t = (typeIncluded) ? type : (type && type.type),
+ ce, a, ret, pre=this._yuievt.config.prefix;
+
+ t = (pre) ? _getType(t, pre) : t;
+ ce = this.getEvent(t, true);
+
+ // this event has not been published or subscribed to
+ if (!ce) {
+
+ if (this._yuievt.hasTargets) {
+ a = (typeIncluded) ? arguments : Y.Array(arguments, 0, true).unshift(t);
+ return this.bubble(null, a, this);
+ }
+
+ // otherwise there is nothing to be done
+ ret = true;
+
+ } else {
+
+ a = Y.Array(arguments, (typeIncluded) ? 1 : 0, true);
+ ret = ce.fire.apply(ce, a);
+
+ // clear target for next fire()
+ ce.target = null;
+ }
+
+ return (this._yuievt.chain) ? this : ret;
+ },
+
+ /**
+ * Returns the custom event of the provided type has been created, a
+ * falsy value otherwise
+ * @method getEvent
+ * @param type {string} the type, or name of the event
+ * @param prefixed {string} if true, the type is prefixed already
+ * @return {Event.Custom} the custom event or null
+ */
+ getEvent: function(type, prefixed) {
+ var pre, e;
+ if (!prefixed) {
+ pre = this._yuievt.config.prefix;
+ type = (pre) ? _getType(type, pre) : type;
+ }
+ e = this._yuievt.events;
+ return (e && type in e) ? e[type] : null;
+ },
+
+ /**
+ * Subscribe to a custom event hosted by this object. The
+ * supplied callback will execute after any listeners add
+ * via the subscribe method, and after the default function,
+ * if configured for the event, has executed.
+ * @method after
+ * @param type {string} The type of the event
+ * @param fn {Function} The callback
+ * @return the event target or a detach handle per 'chain' config
+ */
+ after: function(type, fn) {
+
+ var a = Y.Array(arguments, 0, true);
+
+ switch (L.type(type)) {
+ case 'function':
+ return Y.Do.after.apply(Y.Do, arguments);
+ case 'object':
+ a[0]._after = true;
+ break;
+ default:
+ a[0] = AFTER_PREFIX + type;
+ }
+
+ return this.on.apply(this, a);
+
+ },
+
+ /**
+ * Executes the callback before a DOM event, custom event
+ * or method. If the first argument is a function, it
+ * is assumed the target is a method. For DOM and custom
+ * events, this is an alias for Y.on.
+ *
+ * For DOM and custom events:
+ * type, callback, context, 0-n arguments
+ *
+ * For methods:
+ * callback, object (method host), methodName, context, 0-n arguments
+ *
+ * @method before
+ * @return detach handle
+ * @deprecated use the on method
+ */
+ before: function() {
+ return this.on.apply(this, arguments);
+ }
+
+};
+
+Y.EventTarget = ET;
+
+// make Y an event target
+Y.mix(Y, ET.prototype, false, false, {
+ bubbles: false
+});
+
+ET.call(Y);
+
+YUI.Env.globalEvents = YUI.Env.globalEvents || new ET();
+
+/**
+ * Hosts YUI page level events. This is where events bubble to
+ * when the broadcast config is set to 2. This property is
+ * only available if the custom event module is loaded.
+ * @property Global
+ * @type EventTarget
+ * @for YUI
+ */
+Y.Global = YUI.Env.globalEvents;
+
+// @TODO implement a global namespace function on Y.Global?
+
+})();
+
+
+/**
+ * YUI's on method is a unified interface for subscribing to
+ * most events exposed by YUI. This includes custom events, DOM events, and
+ * function events. detach is also provided to remove listeners
+ * serviced by this function.
+ *
+ * The signature that on accepts varies depending on the type
+ * of event being consumed. Refer to the specific methods that will
+ * service a specific request for additional information about subscribing
+ * to that type of event.
+ *
+ *
+ *
Custom events. These events are defined by various
+ * modules in the library. This type of event is delegated to
+ * EventTarget's on method.
+ *
DOM events. These are moments reported by the browser related
+ * to browser functionality and user interaction.
+ * This type of event is delegated to Event's
+ * attach method.
+ *
+ *
The type of the event
+ *
The callback to execute
+ *
The specification for the Node(s) to attach the listener
+ * to. This can be a selector, collections, or Node/Element
+ * refereces.
Function events. These events can be used to react before or after a
+ * function is executed. This type of event is delegated to Event.Do's
+ * before method.
+ *
+ *
The callback to execute
+ *
The object that has the function that will be listened for.
+ *
The name of the function to listen for.
+ *
An optional context object
+ *
0..n additional arguments to supply the callback.
+ *
+ * Example Y.on(function(arg1, arg2, etc) { // obj.methodname was executed }, obj 'methodname');
+ *
+ *
+ *
+ * on corresponds to the moment before any default behavior of
+ * the event. after works the same way, but these listeners
+ * execute after the event's default behavior. before is an
+ * alias for on.
+ *
+ * @method on
+ * @param type** event type (this parameter does not apply for function events)
+ * @param fn the callback
+ * @param target** a descriptor for the target (applies to custom events only).
+ * For function events, this is the object that contains the function to
+ * execute.
+ * @param extra** 0..n Extra information a particular event may need. These
+ * will be documented with the event. In the case of function events, this
+ * is the name of the function to execute on the host. In the case of
+ * delegate listeners, this is the event delegation specification.
+ * @param context optionally change the value of 'this' in the callback
+ * @param args* 0..n additional arguments to pass to the callback.
+ * @return the event target or a detach handle per 'chain' config
+ * @for YUI
+ */
+
+/**
+ * after() is a unified interface for subscribing to
+ * most events exposed by YUI. This includes custom events,
+ * DOM events, and AOP events. This works the same way as
+ * the on() function, only it operates after any default
+ * behavior for the event has executed. @see on for more
+ * information.
+ * @method after
+ * @param type event type (this parameter does not apply for function events)
+ * @param fn the callback
+ * @param target a descriptor for the target (applies to custom events only).
+ * For function events, this is the object that contains the function to
+ * execute.
+ * @param extra 0..n Extra information a particular event may need. These
+ * will be documented with the event. In the case of function events, this
+ * is the name of the function to execute on the host. In the case of
+ * delegate listeners, this is the event delegation specification.
+ * @param context optionally change the value of 'this' in the callback
+ * @param args* 0..n additional arguments to pass to the callback.
+ * @return the event target or a detach handle per 'chain' config
+ * @for YUI
+ */
+
+
+}, '3.0.0' ,{requires:['oop']});
diff --git a/lib/yui/3.0.0/event-custom/event-custom-base-min.js b/lib/yui/3.0.0/event-custom/event-custom-base-min.js
new file mode 100644
index 0000000000..05975d934f
--- /dev/null
+++ b/lib/yui/3.0.0/event-custom/event-custom-base-min.js
@@ -0,0 +1,9 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("event-custom-base",function(E){E.Env.evt={handles:{},plugins:{}};(function(){var F=0,G=1;E.Do={objs:{},before:function(I,K,L,M){var J=I,H;if(M){H=[I,M].concat(E.Array(arguments,4,true));J=E.rbind.apply(E,H);}return this._inject(F,J,K,L);},after:function(I,K,L,M){var J=I,H;if(M){H=[I,M].concat(E.Array(arguments,4,true));J=E.rbind.apply(E,H);}return this._inject(G,J,K,L);},_inject:function(H,J,K,M){var N=E.stamp(K),L,I;if(!this.objs[N]){this.objs[N]={};}L=this.objs[N];if(!L[M]){L[M]=new E.Do.Method(K,M);K[M]=function(){return L[M].exec.apply(L[M],arguments);};}I=N+E.stamp(J)+M;L[M].register(I,J,H);return new E.EventHandle(L[M],I);},detach:function(H){if(H.detach){H.detach();}},_unload:function(I,H){}};E.Do.Method=function(H,I){this.obj=H;this.methodName=I;this.method=H[I];this.before={};this.after={};};E.Do.Method.prototype.register=function(I,J,H){if(H){this.after[I]=J;}else{this.before[I]=J;}};E.Do.Method.prototype._delete=function(H){delete this.before[H];delete this.after[H];};E.Do.Method.prototype.exec=function(){var J=E.Array(arguments,0,true),K,I,N,L=this.before,H=this.after,M=false;for(K in L){if(L.hasOwnProperty(K)){I=L[K].apply(this.obj,J);if(I){switch(I.constructor){case E.Do.Halt:return I.retVal;case E.Do.AlterArgs:J=I.newArgs;break;case E.Do.Prevent:M=true;break;default:}}}}if(!M){I=this.method.apply(this.obj,J);}for(K in H){if(H.hasOwnProperty(K)){N=H[K].apply(this.obj,J);if(N&&N.constructor==E.Do.Halt){return N.retVal;}else{if(N&&N.constructor==E.Do.AlterReturn){I=N.newRetVal;}}}}return I;};E.Do.AlterArgs=function(I,H){this.msg=I;this.newArgs=H;};E.Do.AlterReturn=function(I,H){this.msg=I;this.newRetVal=H;};E.Do.Halt=function(I,H){this.msg=I;this.retVal=H;};E.Do.Prevent=function(H){this.msg=H;};E.Do.Error=E.Do.Halt;})();var D="after",B=["broadcast","bubbles","context","contextFn","currentTarget","defaultFn","details","emitFacade","fireOnce","host","preventable","preventedFn","queuable","silent","stoppedFn","target","type"],C=9,A="yui:log";E.EventHandle=function(F,G){this.evt=F;this.sub=G;};E.EventHandle.prototype={detach:function(){var F=this.evt,G;if(F){if(E.Lang.isArray(F)){for(G=0;G2)?E.Array(arguments,2,true):null;return this._on(H,G,F,true);},on:function(H,G){var F=(arguments.length>2)?E.Array(arguments,2,true):null;return this._on(H,G,F,true);},after:function(H,G){var F=(arguments.length>2)?E.Array(arguments,2,true):null;return this._on(H,G,F,D);},detach:function(J,H){if(J&&J.detach){return J.detach();}var K=0,G=this.subscribers,F,I;for(F in G){if(G.hasOwnProperty(F)){I=G[F];if(I&&(!J||J===I.fn)){this._delete(I);K++;}}}return K;},unsubscribe:function(){return this.detach.apply(this,arguments);},_notify:function(I,H,F){this.log(this.type+"->"+"sub: "+I.id);var G;G=I.notify(H,this);if(false===G||this.stopped>1){this.log(this.type+" cancelled by subscriber");return false;}return true;},log:function(G,F){if(!this.silent){}},fire:function(){if(this.fireOnce&&this.fired){this.log("fireOnce event: "+this.type+" already fired");return true;}else{var F=E.Array(arguments,0,true);this.fired=true;this.firedWith=F;if(this.emitFacade){return this.fireComplex(F);}else{return this.fireSimple(F);}}},fireSimple:function(F){if(this.hasSubscribers||this.hasAfters){this._procSubs(E.merge(this.subscribers,this.afters),F);}this._broadcast(F);return this.stopped?false:true;},fireComplex:function(F){F[0]=F[0]||{};return this.fireSimple(F);},_procSubs:function(I,G,F){var J,H;for(H in I){if(I.hasOwnProperty(H)){J=I[H];if(J&&J.fn){if(false===this._notify(J,G,F)){this.stopped=2;}if(this.stopped==2){return false;}}}}return true;},_broadcast:function(G){if(!this.stopped&&this.broadcast){var F=E.Array(G);F.unshift(this.type);if(this.host!==E){E.fire.apply(E,F);}if(this.broadcast==2){E.Global.fire.apply(E.Global,F);}}},unsubscribeAll:function(){return this.detachAll.apply(this,arguments);},detachAll:function(){return this.detach();},_delete:function(F){if(F){delete F.fn;delete F.context;delete this.subscribers[F.id];delete this.afters[F.id];}}};E.Subscriber=function(H,G,F){this.fn=H;this.context=G;this.id=E.stamp(this);this.args=F;this.events=null;};E.Subscriber.prototype={_notify:function(J,H,I){var F=this.args,G;switch(I.signature){case 0:G=this.fn.call(J,I.type,H,J);break;case 1:G=this.fn.call(J,H[0]||null,J);break;default:if(F||H){H=H||[];F=(F)?H.concat(F):H;G=this.fn.apply(J,F);}else{G=this.fn.call(J);}}return G;},notify:function(G,I){var J=this.context,F=true;if(!J){J=(I.contextFn)?I.contextFn():I.context;}if(E.config.throwFail){F=this._notify(J,G,I);}else{try{F=this._notify(J,G,I);}catch(H){E.error(this+" failed: "+H.message,H);}}return F;},contains:function(G,F){if(F){return((this.fn==G)&&this.context==F);}else{return(this.fn==G);}}};(function(){var F=E.Lang,H=":",I="|",J="~AFTER~",K=E.cached(function(L,N){if(!N||!F.isString(L)||L.indexOf(H)>-1){return L;}return N+H+L;}),G=E.cached(function(O,Q){var N=O,P,R,L;if(!F.isString(N)){return N;}L=N.indexOf(J);if(L>-1){R=true;N=N.substr(J.length);}L=N.indexOf(I);if(L>-1){P=N.substr(0,(L));N=N.substr(L+1);if(N=="*"){N=null;}}return[P,(Q)?K(N,Q):N,R,N];}),M=function(L){var N=(F.isObject(L))?L:{};this._yuievt=this._yuievt||{id:E.guid(),events:{},targets:{},config:N,chain:("chain" in N)?N.chain:E.config.chain,defaults:{context:N.context||this,host:this,emitFacade:N.emitFacade,fireOnce:N.fireOnce,queuable:N.queuable,broadcast:N.broadcast,bubbles:("bubbles" in N)?N.bubbles:true}};
+};M.prototype={on:function(Q,U,O,V){var Z=G(Q,this._yuievt.config.prefix),a,b,N,g,X,W,d,R=E.Env.evt.handles,P,L,S,e=E.Node,Y,T;if(F.isObject(Q)){if(F.isFunction(Q)){return E.Do.before.apply(E.Do,arguments);}a=U;b=O;N=E.Array(arguments,0,true);g={};P=Q._after;delete Q._after;E.each(Q,function(f,c){if(f){a=f.fn||((E.Lang.isFunction(f))?f:a);b=f.context||b;}N[0]=(P)?J+c:c;N[1]=a;N[2]=b;g[c]=this.on.apply(this,N);},this);return(this._yuievt.chain)?this:new E.EventHandle(g);}W=Z[0];P=Z[2];S=Z[3];if(e&&(this instanceof e)&&(S in e.DOM_EVENTS)){N=E.Array(arguments,0,true);N.splice(2,0,e.getDOMNode(this));return E.on.apply(E,N);}Q=Z[1];if(this instanceof YUI){L=E.Env.evt.plugins[Q];N=E.Array(arguments,0,true);N[0]=S;if(e){Y=N[2];if(Y instanceof E.NodeList){Y=E.NodeList.getDOMNodes(Y);}else{if(Y instanceof e){Y=e.getDOMNode(Y);}}T=(S in e.DOM_EVENTS);if(T){N[2]=Y;}}if(L){d=L.on.apply(E,N);}else{if((!Q)||T){d=E.Event._attach(N);}}}if(!d){X=this._yuievt.events[Q]||this.publish(Q);d=X._on(U,O,(arguments.length>3)?E.Array(arguments,3,true):null,(P)?"after":true);}if(W){R[W]=R[W]||{};R[W][Q]=R[W][Q]||[];R[W][Q].push(d);}return(this._yuievt.chain)?this:d;},subscribe:function(){return this.on.apply(this,arguments);},detach:function(P,U,O){var T=this._yuievt.events,Z,d,c=E.Node,Y=(this instanceof c);if(!P&&(this!==E)){for(Z in T){if(T.hasOwnProperty(Z)){d=T[Z].detach(U,O);}}if(Y){E.Event.purgeElement(c.getDOMNode(this));}return d;}var X=G(P,this._yuievt.config.prefix),V=F.isArray(X)?X[0]:null,R=(X)?X[3]:null,b,L,Q=E.Env.evt.handles,S,N,W,a=function(g,f){var e=g[f];if(e){while(e.length){b=e.pop();b.detach();}}};if(V){S=Q[V];P=X[1];if(S){if(P){a(S,P);}else{for(Z in S){if(S.hasOwnProperty(Z)){a(S,Z);}}}return(this._yuievt.chain)?this:true;}}else{if(F.isObject(P)&&P.detach){d=P.detach();return(this._yuievt.chain)?this:d;}else{if(Y&&((!R)||(R in c.DOM_EVENTS))){N=E.Array(arguments,0,true);N[2]=c.getDOMNode(this);return E.detach.apply(E,N);}}}L=E.Env.evt.plugins[R];if(this instanceof YUI){N=E.Array(arguments,0,true);if(L&&L.detach){return L.detach.apply(E,N);}else{if(!P||(!L&&c&&(P in c.DOM_EVENTS))){N[0]=P;return E.Event.detach.apply(E.Event,N);}}}W=T[P];if(W){d=W.detach(U,O);}return(this._yuievt.chain)?this:d;},unsubscribe:function(){return this.detach.apply(this,arguments);},detachAll:function(L){return this.detach(L);},unsubscribeAll:function(){return this.detachAll.apply(this,arguments);},publish:function(O,P){var N,R,L,Q=this._yuievt.config.prefix;O=(Q)?K(O,Q):O;if(F.isObject(O)){L={};E.each(O,function(T,S){L[S]=this.publish(S,T||P);},this);return L;}N=this._yuievt.events;R=N[O];if(R){if(P){R.applyConfig(P,true);}}else{R=new E.CustomEvent(O,(P)?E.mix(P,this._yuievt.defaults):this._yuievt.defaults);N[O]=R;}return N[O];},addTarget:function(L){this._yuievt.targets[E.stamp(L)]=L;this._yuievt.hasTargets=true;},removeTarget:function(L){delete this._yuievt.targets[E.stamp(L)];},fire:function(P){var S=F.isString(P),O=(S)?P:(P&&P.type),R,L,N,Q=this._yuievt.config.prefix;O=(Q)?K(O,Q):O;R=this.getEvent(O,true);if(!R){if(this._yuievt.hasTargets){L=(S)?arguments:E.Array(arguments,0,true).unshift(O);return this.bubble(null,L,this);}N=true;}else{L=E.Array(arguments,(S)?1:0,true);N=R.fire.apply(R,L);R.target=null;}return(this._yuievt.chain)?this:N;},getEvent:function(N,L){var P,O;if(!L){P=this._yuievt.config.prefix;N=(P)?K(N,P):N;}O=this._yuievt.events;return(O&&N in O)?O[N]:null;},after:function(O,N){var L=E.Array(arguments,0,true);switch(F.type(O)){case"function":return E.Do.after.apply(E.Do,arguments);case"object":L[0]._after=true;break;default:L[0]=J+O;}return this.on.apply(this,L);},before:function(){return this.on.apply(this,arguments);}};E.EventTarget=M;E.mix(E,M.prototype,false,false,{bubbles:false});M.call(E);YUI.Env.globalEvents=YUI.Env.globalEvents||new M();E.Global=YUI.Env.globalEvents;})();},"3.0.0",{requires:["oop"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/event-custom/event-custom-base.js b/lib/yui/3.0.0/event-custom/event-custom-base.js
new file mode 100644
index 0000000000..88c6723a32
--- /dev/null
+++ b/lib/yui/3.0.0/event-custom/event-custom-base.js
@@ -0,0 +1,1722 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('event-custom-base', function(Y) {
+
+/**
+ * Custom event engine, DOM event listener abstraction layer, synthetic DOM
+ * events.
+ * @module event-custom
+ */
+
+Y.Env.evt = {
+ handles: {},
+ plugins: {}
+};
+
+
+/**
+ * Custom event engine, DOM event listener abstraction layer, synthetic DOM
+ * events.
+ * @module event-custom
+ * @submodule event-custom-base
+ */
+(function() {
+
+/**
+ * Allows for the insertion of methods that are executed before or after
+ * a specified method
+ * @class Do
+ * @static
+ */
+
+var BEFORE = 0,
+ AFTER = 1;
+
+Y.Do = {
+
+ /**
+ * Cache of objects touched by the utility
+ * @property objs
+ * @static
+ */
+ objs: {},
+
+ /**
+ * Execute the supplied method before the specified function
+ * @method before
+ * @param fn {Function} the function to execute
+ * @param obj the object hosting the method to displace
+ * @param sFn {string} the name of the method to displace
+ * @param c The execution context for fn
+ * @return {string} handle for the subscription
+ * @static
+ */
+ before: function(fn, obj, sFn, c) {
+ var f = fn, a;
+ if (c) {
+ a = [fn, c].concat(Y.Array(arguments, 4, true));
+ f = Y.rbind.apply(Y, a);
+ }
+
+ return this._inject(BEFORE, f, obj, sFn);
+ },
+
+ /**
+ * Execute the supplied method after the specified function
+ * @method after
+ * @param fn {Function} the function to execute
+ * @param obj the object hosting the method to displace
+ * @param sFn {string} the name of the method to displace
+ * @param c The execution context for fn
+ * @return {string} handle for the subscription
+ * @static
+ */
+ after: function(fn, obj, sFn, c) {
+ var f = fn, a;
+ if (c) {
+ a = [fn, c].concat(Y.Array(arguments, 4, true));
+ f = Y.rbind.apply(Y, a);
+ }
+
+ return this._inject(AFTER, f, obj, sFn);
+ },
+
+ /**
+ * Execute the supplied method after the specified function
+ * @method _inject
+ * @param when {string} before or after
+ * @param fn {Function} the function to execute
+ * @param obj the object hosting the method to displace
+ * @param sFn {string} the name of the method to displace
+ * @param c The execution context for fn
+ * @return {string} handle for the subscription
+ * @private
+ * @static
+ */
+ _inject: function(when, fn, obj, sFn) {
+
+ // object id
+ var id = Y.stamp(obj), o, sid;
+
+ if (! this.objs[id]) {
+ // create a map entry for the obj if it doesn't exist
+ this.objs[id] = {};
+ }
+
+ o = this.objs[id];
+
+ if (! o[sFn]) {
+ // create a map entry for the method if it doesn't exist
+ o[sFn] = new Y.Do.Method(obj, sFn);
+
+ // re-route the method to our wrapper
+ obj[sFn] =
+ function() {
+ return o[sFn].exec.apply(o[sFn], arguments);
+ };
+ }
+
+ // subscriber id
+ sid = id + Y.stamp(fn) + sFn;
+
+ // register the callback
+ o[sFn].register(sid, fn, when);
+
+ return new Y.EventHandle(o[sFn], sid);
+
+ },
+
+ /**
+ * Detach a before or after subscription
+ * @method detach
+ * @param handle {string} the subscription handle
+ */
+ detach: function(handle) {
+
+ if (handle.detach) {
+ handle.detach();
+ }
+
+ },
+
+ _unload: function(e, me) {
+
+ }
+};
+
+//////////////////////////////////////////////////////////////////////////
+
+/**
+ * Wrapper for a displaced method with aop enabled
+ * @class Do.Method
+ * @constructor
+ * @param obj The object to operate on
+ * @param sFn The name of the method to displace
+ */
+Y.Do.Method = function(obj, sFn) {
+ this.obj = obj;
+ this.methodName = sFn;
+ this.method = obj[sFn];
+ this.before = {};
+ this.after = {};
+};
+
+/**
+ * Register a aop subscriber
+ * @method register
+ * @param sid {string} the subscriber id
+ * @param fn {Function} the function to execute
+ * @param when {string} when to execute the function
+ */
+Y.Do.Method.prototype.register = function (sid, fn, when) {
+ if (when) {
+ this.after[sid] = fn;
+ } else {
+ this.before[sid] = fn;
+ }
+};
+
+/**
+ * Unregister a aop subscriber
+ * @method delete
+ * @param sid {string} the subscriber id
+ * @param fn {Function} the function to execute
+ * @param when {string} when to execute the function
+ */
+Y.Do.Method.prototype._delete = function (sid) {
+ delete this.before[sid];
+ delete this.after[sid];
+};
+
+/**
+ * Execute the wrapped method
+ * @method exec
+ */
+Y.Do.Method.prototype.exec = function () {
+
+ var args = Y.Array(arguments, 0, true),
+ i, ret, newRet,
+ bf = this.before,
+ af = this.after,
+ prevented = false;
+
+ // execute before
+ for (i in bf) {
+ if (bf.hasOwnProperty(i)) {
+ ret = bf[i].apply(this.obj, args);
+ if (ret) {
+ switch (ret.constructor) {
+ case Y.Do.Halt:
+ return ret.retVal;
+ case Y.Do.AlterArgs:
+ args = ret.newArgs;
+ break;
+ case Y.Do.Prevent:
+ prevented = true;
+ break;
+ default:
+ }
+ }
+ }
+ }
+
+ // execute method
+ if (!prevented) {
+ ret = this.method.apply(this.obj, args);
+ }
+
+ // execute after methods.
+ for (i in af) {
+ if (af.hasOwnProperty(i)) {
+ newRet = af[i].apply(this.obj, args);
+ // Stop processing if a Halt object is returned
+ if (newRet && newRet.constructor == Y.Do.Halt) {
+ return newRet.retVal;
+ // Check for a new return value
+ } else if (newRet && newRet.constructor == Y.Do.AlterReturn) {
+ ret = newRet.newRetVal;
+ }
+ }
+ }
+
+ return ret;
+};
+
+//////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * Return an AlterArgs object when you want to change the arguments that
+ * were passed into the function. An example would be a service that scrubs
+ * out illegal characters prior to executing the core business logic.
+ * @class Do.AlterArgs
+ */
+Y.Do.AlterArgs = function(msg, newArgs) {
+ this.msg = msg;
+ this.newArgs = newArgs;
+};
+
+/**
+ * Return an AlterReturn object when you want to change the result returned
+ * from the core method to the caller
+ * @class Do.AlterReturn
+ */
+Y.Do.AlterReturn = function(msg, newRetVal) {
+ this.msg = msg;
+ this.newRetVal = newRetVal;
+};
+
+/**
+ * Return a Halt object when you want to terminate the execution
+ * of all subsequent subscribers as well as the wrapped method
+ * if it has not exectued yet.
+ * @class Do.Halt
+ */
+Y.Do.Halt = function(msg, retVal) {
+ this.msg = msg;
+ this.retVal = retVal;
+};
+
+/**
+ * Return a Prevent object when you want to prevent the wrapped function
+ * from executing, but want the remaining listeners to execute
+ * @class Do.Prevent
+ */
+Y.Do.Prevent = function(msg) {
+ this.msg = msg;
+};
+
+/**
+ * Return an Error object when you want to terminate the execution
+ * of all subsequent method calls.
+ * @class Do.Error
+ * @deprecated use Y.Do.Halt or Y.Do.Prevent
+ */
+Y.Do.Error = Y.Do.Halt;
+
+//////////////////////////////////////////////////////////////////////////
+
+// Y["Event"] && Y.Event.addListener(window, "unload", Y.Do._unload, Y.Do);
+
+})();
+
+/**
+ * Custom event engine, DOM event listener abstraction layer, synthetic DOM
+ * events.
+ * @module event-custom
+ * @submodule event-custom-base
+ */
+
+/**
+ * Return value from all subscribe operations
+ * @class EventHandle
+ * @constructor
+ * @param evt {CustomEvent} the custom event
+ * @param sub {Subscriber} the subscriber
+ */
+
+// var onsubscribeType = "_event:onsub",
+var AFTER = 'after',
+ CONFIGS = [
+ 'broadcast',
+ 'bubbles',
+ 'context',
+ 'contextFn',
+ 'currentTarget',
+ 'defaultFn',
+ 'details',
+ 'emitFacade',
+ 'fireOnce',
+ 'host',
+ 'preventable',
+ 'preventedFn',
+ 'queuable',
+ 'silent',
+ 'stoppedFn',
+ 'target',
+ 'type'
+ ],
+
+
+ YUI3_SIGNATURE = 9,
+ YUI_LOG = 'yui:log';
+
+Y.EventHandle = function(evt, sub) {
+
+ /**
+ * The custom event
+ * @type CustomEvent
+ */
+ this.evt = evt;
+
+ /**
+ * The subscriber object
+ * @type Subscriber
+ */
+ this.sub = sub;
+};
+
+Y.EventHandle.prototype = {
+
+ /**
+ * Detaches this subscriber
+ * @method detach
+ */
+ detach: function() {
+ var evt = this.evt, i;
+ if (evt) {
+ if (Y.Lang.isArray(evt)) {
+ for (i=0; i 2) {
+// this.log('CustomEvent context and silent are now in the config', 'warn', 'Event');
+ // }
+
+ o = o || {};
+
+ this.id = Y.stamp(this);
+
+ /**
+ * The type of event, returned to subscribers when the event fires
+ * @property type
+ * @type string
+ */
+ this.type = type;
+
+ /**
+ * The context the the event will fire from by default. Defaults to the YUI
+ * instance.
+ * @property context
+ * @type object
+ */
+ this.context = Y;
+
+ this.logSystem = (type == YUI_LOG);
+
+ /**
+ * If 0, this event does not broadcast. If 1, the YUI instance is notified
+ * every time this event fires. If 2, the YUI instance and the YUI global
+ * (if event is enabled on the global) are notified every time this event
+ * fires.
+ * @property broadcast
+ * @type int
+ */
+ // this.broadcast = 0;
+
+ /**
+ * By default all custom events are logged in the debug build, set silent
+ * to true to disable debug outpu for this event.
+ * @property silent
+ * @type boolean
+ */
+ this.silent = this.logSystem;
+
+ /**
+ * Specifies whether this event should be queued when the host is actively
+ * processing an event. This will effect exectution order of the callbacks
+ * for the various events.
+ * @property queuable
+ * @type boolean
+ * @default false
+ */
+ // this.queuable = false;
+
+ /**
+ * The subscribers to this event
+ * @property subscribers
+ * @type Subscriber{}
+ */
+ this.subscribers = {};
+
+ /**
+ * 'After' subscribers
+ * @property afters
+ * @type Subscriber{}
+ */
+ this.afters = {};
+
+ /**
+ * This event has fired if true
+ *
+ * @property fired
+ * @type boolean
+ * @default false;
+ */
+ // this.fired = false;
+
+ /**
+ * An array containing the arguments the custom event
+ * was last fired with.
+ * @property firedWith
+ * @type Array
+ */
+ // this.firedWith;
+
+ /**
+ * This event should only fire one time if true, and if
+ * it has fired, any new subscribers should be notified
+ * immediately.
+ *
+ * @property fireOnce
+ * @type boolean
+ * @default false;
+ */
+ // this.fireOnce = false;
+
+ /**
+ * Flag for stopPropagation that is modified during fire()
+ * 1 means to stop propagation to bubble targets. 2 means
+ * to also stop additional subscribers on this target.
+ * @property stopped
+ * @type int
+ */
+ // this.stopped = 0;
+
+ /**
+ * Flag for preventDefault that is modified during fire().
+ * if it is not 0, the default behavior for this event
+ * @property prevented
+ * @type int
+ */
+ // this.prevented = 0;
+
+ /**
+ * Specifies the host for this custom event. This is used
+ * to enable event bubbling
+ * @property host
+ * @type EventTarget
+ */
+ // this.host = null;
+
+ /**
+ * The default function to execute after event listeners
+ * have fire, but only if the default action was not
+ * prevented.
+ * @property defaultFn
+ * @type Function
+ */
+ // this.defaultFn = null;
+
+ /**
+ * The function to execute if a subscriber calls
+ * stopPropagation or stopImmediatePropagation
+ * @property stoppedFn
+ * @type Function
+ */
+ // this.stoppedFn = null;
+
+ /**
+ * The function to execute if a subscriber calls
+ * preventDefault
+ * @property preventedFn
+ * @type Function
+ */
+ // this.preventedFn = null;
+
+ /**
+ * Specifies whether or not this event's default function
+ * can be cancelled by a subscriber by executing preventDefault()
+ * on the event facade
+ * @property preventable
+ * @type boolean
+ * @default true
+ */
+ this.preventable = true;
+
+ /**
+ * Specifies whether or not a subscriber can stop the event propagation
+ * via stopPropagation(), stopImmediatePropagation(), or halt()
+ * @property bubbles
+ * @type boolean
+ * @default true
+ */
+ this.bubbles = true;
+
+ /**
+ * Supports multiple options for listener signatures in order to
+ * port YUI 2 apps.
+ * @property signature
+ * @type int
+ * @default 9
+ */
+ this.signature = YUI3_SIGNATURE;
+
+ // this.hasSubscribers = false;
+
+ // this.hasAfters = false;
+
+ /**
+ * If set to true, the custom event will deliver an EventFacade object
+ * that is similar to a DOM event object.
+ * @property emitFacade
+ * @type boolean
+ * @default false
+ */
+ // this.emitFacade = false;
+
+ this.applyConfig(o, true);
+
+ // this.log("Creating " + this.type);
+
+};
+
+Y.CustomEvent.prototype = {
+
+ /**
+ * Apply configuration properties. Only applies the CONFIG whitelist
+ * @method applyConfig
+ * @param o hash of properties to apply
+ * @param force {boolean} if true, properties that exist on the event
+ * will be overwritten.
+ */
+ applyConfig: function(o, force) {
+ if (o) {
+ Y.mix(this, o, force, CONFIGS);
+ }
+ },
+
+ _on: function(fn, context, args, when) {
+
+ if (!fn) {
+ this.log("Invalid callback for CE: " + this.type);
+ }
+
+ var s = new Y.Subscriber(fn, context, args, when);
+
+ if (this.fireOnce && this.fired) {
+ Y.later(0, this, Y.bind(this._notify, this, s, this.firedWith));
+ }
+
+ if (when == AFTER) {
+ this.afters[s.id] = s;
+ this.hasAfters = true;
+ } else {
+ this.subscribers[s.id] = s;
+ this.hasSubscribers = true;
+ }
+
+ return new Y.EventHandle(this, s);
+
+ },
+
+ /**
+ * Listen for this event
+ * @method subscribe
+ * @param {Function} fn The function to execute
+ * @return {EventHandle|EventTarget} unsubscribe handle or a
+ * chainable event target depending on the 'chain' config.
+ * @deprecated use on
+ */
+ subscribe: function(fn, context) {
+ var a = (arguments.length > 2) ? Y.Array(arguments, 2, true): null;
+ return this._on(fn, context, a, true);
+ },
+
+ /**
+ * Listen for this event
+ * @method on
+ * @param {Function} fn The function to execute
+ * @return {EventHandle|EventTarget} unsubscribe handle or a
+ * chainable event target depending on the 'chain' config.
+ */
+ on: function(fn, context) {
+ var a = (arguments.length > 2) ? Y.Array(arguments, 2, true): null;
+ return this._on(fn, context, a, true);
+ },
+
+ /**
+ * Listen for this event after the normal subscribers have been notified and
+ * the default behavior has been applied. If a normal subscriber prevents the
+ * default behavior, it also prevents after listeners from firing.
+ * @method after
+ * @param {Function} fn The function to execute
+ * @return {EventHandle|EventTarget} unsubscribe handle or a
+ * chainable event target depending on the 'chain' config.
+ */
+ after: function(fn, context) {
+ var a = (arguments.length > 2) ? Y.Array(arguments, 2, true): null;
+ return this._on(fn, context, a, AFTER);
+ },
+
+ /**
+ * Detach listeners.
+ * @method detach
+ * @param {Function} fn The subscribed function to remove, if not supplied
+ * all will be removed
+ * @param {Object} context The context object passed to subscribe.
+ * @return {int|EventTarget} returns a chainable event target
+ * or the number of subscribers unsubscribed.
+ */
+ detach: function(fn, context) {
+ // unsubscribe handle
+ if (fn && fn.detach) {
+ return fn.detach();
+ }
+
+ var found = 0, subs = this.subscribers, i, s;
+
+ for (i in subs) {
+ if (subs.hasOwnProperty(i)) {
+ s = subs[i];
+ if (s && (!fn || fn === s.fn)) {
+ this._delete(s);
+ found++;
+ }
+ }
+ }
+
+ return found;
+ },
+
+ /**
+ * Detach listeners.
+ * @method unsubscribe
+ * @param {Function} fn The subscribed function to remove, if not supplied
+ * all will be removed
+ * @param {Object} context The context object passed to subscribe.
+ * @return {boolean|EventTarget} returns a chainable event target
+ * or a boolean for legacy detach support.
+ * @deprecated use detach
+ */
+ unsubscribe: function() {
+ return this.detach.apply(this, arguments);
+ },
+
+
+ /**
+ * Notify a single subscriber
+ * @method _notify
+ * @param s {Subscriber} the subscriber
+ * @param args {Array} the arguments array to apply to the listener
+ * @private
+ */
+ _notify: function(s, args, ef) {
+
+ this.log(this.type + "->" + "sub: " + s.id);
+
+ var ret;
+
+ ret = s.notify(args, this);
+
+ if (false === ret || this.stopped > 1) {
+ this.log(this.type + " cancelled by subscriber");
+ return false;
+ }
+
+ return true;
+ },
+
+ /**
+ * Logger abstraction to centralize the application of the silent flag
+ * @method log
+ * @param msg {string} message to log
+ * @param cat {string} log category
+ */
+ log: function(msg, cat) {
+ if (!this.silent) {
+ }
+ },
+
+ /**
+ * Notifies the subscribers. The callback functions will be executed
+ * from the context specified when the event was created, and with the
+ * following parameters:
+ *
+ *
The type of event
+ *
All of the arguments fire() was executed with as an array
+ *
The custom object (if any) that was passed into the subscribe()
+ * method
+ *
+ * @method fire
+ * @param {Object*} arguments an arbitrary set of parameters to pass to
+ * the handler.
+ * @return {boolean} false if one of the subscribers returned false,
+ * true otherwise
+ *
+ */
+ fire: function() {
+ if (this.fireOnce && this.fired) {
+ this.log('fireOnce event: ' + this.type + ' already fired');
+ return true;
+ } else {
+
+ var args = Y.Array(arguments, 0, true);
+
+ this.fired = true;
+ this.firedWith = args;
+
+ if (this.emitFacade) {
+ return this.fireComplex(args);
+ } else {
+ return this.fireSimple(args);
+ }
+ }
+ },
+
+ fireSimple: function(args) {
+ if (this.hasSubscribers || this.hasAfters) {
+ this._procSubs(Y.merge(this.subscribers, this.afters), args);
+ }
+ this._broadcast(args);
+ return this.stopped ? false : true;
+ },
+
+ // Requires the event-custom-complex module for full funcitonality.
+ fireComplex: function(args) {
+ args[0] = args[0] || {};
+ return this.fireSimple(args);
+ },
+
+ _procSubs: function(subs, args, ef) {
+ var s, i;
+ for (i in subs) {
+ if (subs.hasOwnProperty(i)) {
+ s = subs[i];
+ if (s && s.fn) {
+ if (false === this._notify(s, args, ef)) {
+ this.stopped = 2;
+ }
+ if (this.stopped == 2) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ },
+
+ _broadcast: function(args) {
+ if (!this.stopped && this.broadcast) {
+
+ var a = Y.Array(args);
+ a.unshift(this.type);
+
+ if (this.host !== Y) {
+ Y.fire.apply(Y, a);
+ }
+
+ if (this.broadcast == 2) {
+ Y.Global.fire.apply(Y.Global, a);
+ }
+ }
+ },
+
+ /**
+ * Removes all listeners
+ * @method unsubscribeAll
+ * @return {int} The number of listeners unsubscribed
+ * @deprecated use detachAll
+ */
+ unsubscribeAll: function() {
+ return this.detachAll.apply(this, arguments);
+ },
+
+ /**
+ * Removes all listeners
+ * @method detachAll
+ * @return {int} The number of listeners unsubscribed
+ */
+ detachAll: function() {
+ return this.detach();
+ },
+
+ /**
+ * @method _delete
+ * @param subscriber object
+ * @private
+ */
+ _delete: function(s) {
+ if (s) {
+ delete s.fn;
+ delete s.context;
+ delete this.subscribers[s.id];
+ delete this.afters[s.id];
+ }
+ }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn The wrapped function to execute
+ * @param {Object} context The value of the keyword 'this' in the listener
+ * @param {Array} args* 0..n additional arguments to supply the listener
+ *
+ * @class Subscriber
+ * @constructor
+ */
+Y.Subscriber = function(fn, context, args) {
+
+ /**
+ * The callback that will be execute when the event fires
+ * This is wrapped by Y.rbind if obj was supplied.
+ * @property fn
+ * @type Function
+ */
+ this.fn = fn;
+
+ /**
+ * Optional 'this' keyword for the listener
+ * @property context
+ * @type Object
+ */
+ this.context = context;
+
+ /**
+ * Unique subscriber id
+ * @property id
+ * @type String
+ */
+ this.id = Y.stamp(this);
+
+ /**
+ * Additional arguments to propagate to the subscriber
+ * @property args
+ * @type Array
+ */
+ this.args = args;
+
+ /**
+ * Custom events for a given fire transaction.
+ * @property events
+ * @type {EventTarget}
+ */
+ this.events = null;
+
+};
+
+Y.Subscriber.prototype = {
+
+ _notify: function(c, args, ce) {
+ var a = this.args, ret;
+ switch (ce.signature) {
+ case 0:
+ ret = this.fn.call(c, ce.type, args, c);
+ break;
+ case 1:
+ ret = this.fn.call(c, args[0] || null, c);
+ break;
+ default:
+ if (a || args) {
+ args = args || [];
+ a = (a) ? args.concat(a) : args;
+ ret = this.fn.apply(c, a);
+ } else {
+ ret = this.fn.call(c);
+ }
+ }
+
+ return ret;
+ },
+
+ /**
+ * Executes the subscriber.
+ * @method notify
+ * @param args {Array} Arguments array for the subscriber
+ * @param ce {CustomEvent} The custom event that sent the notification
+ */
+ notify: function(args, ce) {
+ var c = this.context,
+ ret = true;
+
+ if (!c) {
+ c = (ce.contextFn) ? ce.contextFn() : ce.context;
+ }
+
+ // only catch errors if we will not re-throw them.
+ if (Y.config.throwFail) {
+ ret = this._notify(c, args, ce);
+ } else {
+ try {
+ ret = this._notify(c, args, ce);
+ } catch(e) {
+ Y.error(this + ' failed: ' + e.message, e);
+ }
+ }
+
+ return ret;
+ },
+
+ /**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} context optional 'this' keyword for the listener
+ * @return {boolean} true if the supplied arguments match this
+ * subscriber's signature.
+ */
+ contains: function(fn, context) {
+ if (context) {
+ return ((this.fn == fn) && this.context == context);
+ } else {
+ return (this.fn == fn);
+ }
+ }
+
+};
+
+/**
+ * Custom event engine, DOM event listener abstraction layer, synthetic DOM
+ * events.
+ * @module event-custom
+ * @submodule event-custom-base
+ */
+(function() {
+
+/**
+ * EventTarget provides the implementation for any object to
+ * publish, subscribe and fire to custom events, and also
+ * alows other EventTargets to target the object with events
+ * sourced from the other object.
+ * EventTarget is designed to be used with Y.augment to wrap
+ * EventCustom in an interface that allows events to be listened to
+ * and fired by name. This makes it possible for implementing code to
+ * subscribe to an event that either has not been created yet, or will
+ * not be created at all.
+ * @class EventTarget
+ * @param opts a configuration object
+ * @config emitFacade {boolean} if true, all events will emit event
+ * facade payloads by default (default false)
+ * @config prefix {string} the prefix to apply to non-prefixed event names
+ * @config chain {boolean} if true, on/after/detach return the host to allow
+ * chaining, otherwise they return an EventHandle (default false)
+ */
+
+var L = Y.Lang,
+ PREFIX_DELIMITER = ':',
+ CATEGORY_DELIMITER = '|',
+ AFTER_PREFIX = '~AFTER~',
+
+ /**
+ * If the instance has a prefix attribute and the
+ * event type is not prefixed, the instance prefix is
+ * applied to the supplied type.
+ * @method _getType
+ * @private
+ */
+ _getType = Y.cached(function(type, pre) {
+
+ if (!pre || !L.isString(type) || type.indexOf(PREFIX_DELIMITER) > -1) {
+ return type;
+ }
+
+ return pre + PREFIX_DELIMITER + type;
+ }),
+
+ /**
+ * Returns an array with the detach key (if provided),
+ * and the prefixed event name from _getType
+ * Y.on('detachcategory, menu:click', fn)
+ * @method _parseType
+ * @private
+ */
+ _parseType = Y.cached(function(type, pre) {
+
+ var t = type, detachcategory, after, i;
+
+ if (!L.isString(t)) {
+ return t;
+ }
+
+ i = t.indexOf(AFTER_PREFIX);
+
+ if (i > -1) {
+ after = true;
+ t = t.substr(AFTER_PREFIX.length);
+ }
+
+ i = t.indexOf(CATEGORY_DELIMITER);
+
+ if (i > -1) {
+ detachcategory = t.substr(0, (i));
+ t = t.substr(i+1);
+ if (t == '*') {
+ t = null;
+ }
+ }
+
+ // detach category, full type with instance prefix, is this an after listener, short type
+ return [detachcategory, (pre) ? _getType(t, pre) : t, after, t];
+ }),
+
+ ET = function(opts) {
+
+
+ var o = (L.isObject(opts)) ? opts : {};
+
+ this._yuievt = this._yuievt || {
+
+ id: Y.guid(),
+
+ events: {},
+
+ targets: {},
+
+ config: o,
+
+ chain: ('chain' in o) ? o.chain : Y.config.chain,
+
+ defaults: {
+ context: o.context || this,
+ host: this,
+ emitFacade: o.emitFacade,
+ fireOnce: o.fireOnce,
+ queuable: o.queuable,
+ broadcast: o.broadcast,
+ bubbles: ('bubbles' in o) ? o.bubbles : true
+ }
+ };
+
+ };
+
+
+ET.prototype = {
+
+ /**
+ * Subscribe to a custom event hosted by this object
+ * @method on
+ * @param type {string} The type of the event
+ * @param fn {Function} The callback
+ * @return the event target or a detach handle per 'chain' config
+ */
+ on: function(type, fn, context, x) {
+
+ var parts = _parseType(type, this._yuievt.config.prefix), f, c, args, ret, ce,
+ detachcategory, handle, store = Y.Env.evt.handles, after, adapt, shorttype,
+ Node = Y.Node, n, domevent;
+
+ if (L.isObject(type)) {
+
+ if (L.isFunction(type)) {
+ return Y.Do.before.apply(Y.Do, arguments);
+ }
+
+ f = fn;
+ c = context;
+ args = Y.Array(arguments, 0, true);
+ ret = {};
+ after = type._after;
+ delete type._after;
+
+ Y.each(type, function(v, k) {
+
+ if (v) {
+ f = v.fn || ((Y.Lang.isFunction(v)) ? v : f);
+ c = v.context || c;
+ }
+
+ args[0] = (after) ? AFTER_PREFIX + k : k;
+ args[1] = f;
+ args[2] = c;
+
+ ret[k] = this.on.apply(this, args);
+
+ }, this);
+
+ return (this._yuievt.chain) ? this : new Y.EventHandle(ret);
+
+ }
+
+ detachcategory = parts[0];
+ after = parts[2];
+ shorttype = parts[3];
+
+ // extra redirection so we catch adaptor events too. take a look at this.
+ if (Node && (this instanceof Node) && (shorttype in Node.DOM_EVENTS)) {
+ args = Y.Array(arguments, 0, true);
+ args.splice(2, 0, Node.getDOMNode(this));
+ return Y.on.apply(Y, args);
+ }
+
+ type = parts[1];
+
+ if (this instanceof YUI) {
+
+ adapt = Y.Env.evt.plugins[type];
+ args = Y.Array(arguments, 0, true);
+ args[0] = shorttype;
+
+ if (Node) {
+ n = args[2];
+
+ if (n instanceof Y.NodeList) {
+ n = Y.NodeList.getDOMNodes(n);
+ } else if (n instanceof Node) {
+ n = Node.getDOMNode(n);
+ }
+
+ domevent = (shorttype in Node.DOM_EVENTS);
+
+ // Captures both DOM events and event plugins.
+ if (domevent) {
+ args[2] = n;
+ }
+ }
+
+ // check for the existance of an event adaptor
+ if (adapt) {
+ handle = adapt.on.apply(Y, args);
+ } else if ((!type) || domevent) {
+ handle = Y.Event._attach(args);
+ }
+
+ }
+
+ if (!handle) {
+ ce = this._yuievt.events[type] || this.publish(type);
+ handle = ce._on(fn, context, (arguments.length > 3) ? Y.Array(arguments, 3, true) : null, (after) ? 'after' : true);
+ }
+
+ if (detachcategory) {
+ store[detachcategory] = store[detachcategory] || {};
+ store[detachcategory][type] = store[detachcategory][type] || [];
+ store[detachcategory][type].push(handle);
+ }
+
+ return (this._yuievt.chain) ? this : handle;
+
+ },
+
+ /**
+ * subscribe to an event
+ * @method subscribe
+ * @deprecated use on
+ */
+ subscribe: function() {
+ return this.on.apply(this, arguments);
+ },
+
+ /**
+ * Detach one or more listeners the from the specified event
+ * @method detach
+ * @param type {string|Object} Either the handle to the subscriber or the
+ * type of event. If the type
+ * is not specified, it will attempt to remove
+ * the listener from all hosted events.
+ * @param fn {Function} The subscribed function to unsubscribe, if not
+ * supplied, all subscribers will be removed.
+ * @param context {Object} The custom object passed to subscribe. This is
+ * optional, but if supplied will be used to
+ * disambiguate multiple listeners that are the same
+ * (e.g., you subscribe many object using a function
+ * that lives on the prototype)
+ * @return {EventTarget} the host
+ */
+ detach: function(type, fn, context) {
+ var evts = this._yuievt.events, i, ret,
+ Node = Y.Node, isNode = (this instanceof Node);
+
+ // detachAll disabled on the Y instance.
+ if (!type && (this !== Y)) {
+ for (i in evts) {
+ if (evts.hasOwnProperty(i)) {
+ ret = evts[i].detach(fn, context);
+ }
+ }
+ if (isNode) {
+
+ Y.Event.purgeElement(Node.getDOMNode(this));
+ }
+
+ return ret;
+ }
+
+ var parts = _parseType(type, this._yuievt.config.prefix),
+ detachcategory = L.isArray(parts) ? parts[0] : null,
+ shorttype = (parts) ? parts[3] : null,
+ handle, adapt, store = Y.Env.evt.handles, cat, args,
+ ce,
+
+ keyDetacher = function(lcat, ltype) {
+ var handles = lcat[ltype];
+ if (handles) {
+ while (handles.length) {
+ handle = handles.pop();
+ handle.detach();
+ }
+ }
+ };
+
+ if (detachcategory) {
+
+ cat = store[detachcategory];
+ type = parts[1];
+
+ if (cat) {
+ if (type) {
+ keyDetacher(cat, type);
+ } else {
+ for (i in cat) {
+ if (cat.hasOwnProperty(i)) {
+ keyDetacher(cat, i);
+ }
+ }
+ }
+
+ return (this._yuievt.chain) ? this : true;
+ }
+
+ // If this is an event handle, use it to detach
+ } else if (L.isObject(type) && type.detach) {
+ ret = type.detach();
+ return (this._yuievt.chain) ? this : ret;
+ // extra redirection so we catch adaptor events too. take a look at this.
+ } else if (isNode && ((!shorttype) || (shorttype in Node.DOM_EVENTS))) {
+ args = Y.Array(arguments, 0, true);
+ args[2] = Node.getDOMNode(this);
+ return Y.detach.apply(Y, args);
+ }
+
+ adapt = Y.Env.evt.plugins[shorttype];
+
+ // The YUI instance handles DOM events and adaptors
+ if (this instanceof YUI) {
+ args = Y.Array(arguments, 0, true);
+ // use the adaptor specific detach code if
+ if (adapt && adapt.detach) {
+ return adapt.detach.apply(Y, args);
+ // DOM event fork
+ } else if (!type || (!adapt && Node && (type in Node.DOM_EVENTS))) {
+ args[0] = type;
+ return Y.Event.detach.apply(Y.Event, args);
+ }
+ }
+
+ ce = evts[type];
+ if (ce) {
+ ret = ce.detach(fn, context);
+ }
+
+ return (this._yuievt.chain) ? this : ret;
+ },
+
+ /**
+ * detach a listener
+ * @method unsubscribe
+ * @deprecated use detach
+ */
+ unsubscribe: function() {
+ return this.detach.apply(this, arguments);
+ },
+
+ /**
+ * Removes all listeners from the specified event. If the event type
+ * is not specified, all listeners from all hosted custom events will
+ * be removed.
+ * @method detachAll
+ * @param type {string} The type, or name of the event
+ */
+ detachAll: function(type) {
+ return this.detach(type);
+ },
+
+ /**
+ * Removes all listeners from the specified event. If the event type
+ * is not specified, all listeners from all hosted custom events will
+ * be removed.
+ * @method unsubscribeAll
+ * @param type {string} The type, or name of the event
+ * @deprecated use detachAll
+ */
+ unsubscribeAll: function() {
+ return this.detachAll.apply(this, arguments);
+ },
+
+ /**
+ * Creates a new custom event of the specified type. If a custom event
+ * by that name already exists, it will not be re-created. In either
+ * case the custom event is returned.
+ *
+ * @method publish
+ *
+ * @param type {string} the type, or name of the event
+ * @param opts {object} optional config params. Valid properties are:
+ *
+ *
+ *
+ * 'broadcast': whether or not the YUI instance and YUI global are notified when the event is fired (false)
+ *
+ *
+ * 'bubbles': whether or not this event bubbles (true)
+ *
+ *
+ * 'context': the default execution context for the listeners (this)
+ *
+ *
+ * 'defaultFn': the default function to execute when this event fires if preventDefault was not called
+ *
+ *
+ * 'emitFacade': whether or not this event emits a facade (false)
+ *
+ *
+ * 'prefix': the prefix for this targets events, e.g., 'menu' in 'menu:click'
+ *
+ *
+ * 'fireOnce': if an event is configured to fire once, new subscribers after
+ * the fire will be notified immediately.
+ *
+ *
+ * 'preventable': whether or not preventDefault() has an effect (true)
+ *
+ *
+ * 'preventedFn': a function that is executed when preventDefault is called
+ *
+ *
+ * 'queuable': whether or not this event can be queued during bubbling (false)
+ *
+ *
+ * 'silent': if silent is true, debug messages are not provided for this event.
+ *
+ *
+ * 'stoppedFn': a function that is executed when stopPropagation is called
+ *
+ *
+ * 'type': the event type (valid option if not provided as the first parameter to publish)
+ *
+ *
+ *
+ * @return {Event.Custom} the custom event
+ *
+ */
+ publish: function(type, opts) {
+ var events, ce, ret, pre = this._yuievt.config.prefix;
+
+ type = (pre) ? _getType(type, pre) : type;
+
+
+ if (L.isObject(type)) {
+ ret = {};
+ Y.each(type, function(v, k) {
+ ret[k] = this.publish(k, v || opts);
+ }, this);
+
+ return ret;
+ }
+
+ events = this._yuievt.events;
+ ce = events[type];
+
+ if (ce) {
+// ce.log("publish applying new config to published event: '"+type+"' exists", 'info', 'event');
+ if (opts) {
+ ce.applyConfig(opts, true);
+ }
+ } else {
+ // apply defaults
+ ce = new Y.CustomEvent(type, (opts) ? Y.mix(opts, this._yuievt.defaults) : this._yuievt.defaults);
+ events[type] = ce;
+ }
+
+ // make sure we turn the broadcast flag off if this
+ // event was published as a result of bubbling
+ // if (opts instanceof Y.CustomEvent) {
+ // events[type].broadcast = false;
+ // }
+
+ return events[type];
+ },
+
+ /**
+ * Registers another EventTarget as a bubble target. Bubble order
+ * is determined by the order registered. Multiple targets can
+ * be specified.
+ * @method addTarget
+ * @param o {EventTarget} the target to add
+ */
+ addTarget: function(o) {
+ this._yuievt.targets[Y.stamp(o)] = o;
+ this._yuievt.hasTargets = true;
+ },
+
+ /**
+ * Removes a bubble target
+ * @method removeTarget
+ * @param o {EventTarget} the target to remove
+ */
+ removeTarget: function(o) {
+ delete this._yuievt.targets[Y.stamp(o)];
+ },
+
+ /**
+ * Fire a custom event by name. The callback functions will be executed
+ * from the context specified when the event was created, and with the
+ * following parameters.
+ *
+ * If the custom event object hasn't been created, then the event hasn't
+ * been published and it has no subscribers. For performance sake, we
+ * immediate exit in this case. This means the event won't bubble, so
+ * if the intention is that a bubble target be notified, the event must
+ * be published on this object first.
+ *
+ * The first argument is the event type, and any additional arguments are
+ * passed to the listeners as parameters. If the first of these is an
+ * object literal, and the event is configured to emit an event facade,
+ * that object is mixed into the event facade and the facade is provided
+ * in place of the original object.
+ *
+ * @method fire
+ * @param type {String|Object} The type of the event, or an object that contains
+ * a 'type' property.
+ * @param arguments {Object*} an arbitrary set of parameters to pass to
+ * the handler. If the first of these is an object literal and the event is
+ * configured to emit an event facade, the event facade will replace that
+ * parameter after the properties the object literal contains are copied to
+ * the event facade.
+ * @return {Event.Target} the event host
+ *
+ */
+ fire: function(type) {
+
+ var typeIncluded = L.isString(type),
+ t = (typeIncluded) ? type : (type && type.type),
+ ce, a, ret, pre=this._yuievt.config.prefix;
+
+ t = (pre) ? _getType(t, pre) : t;
+ ce = this.getEvent(t, true);
+
+ // this event has not been published or subscribed to
+ if (!ce) {
+
+ if (this._yuievt.hasTargets) {
+ a = (typeIncluded) ? arguments : Y.Array(arguments, 0, true).unshift(t);
+ return this.bubble(null, a, this);
+ }
+
+ // otherwise there is nothing to be done
+ ret = true;
+
+ } else {
+
+ a = Y.Array(arguments, (typeIncluded) ? 1 : 0, true);
+ ret = ce.fire.apply(ce, a);
+
+ // clear target for next fire()
+ ce.target = null;
+ }
+
+ return (this._yuievt.chain) ? this : ret;
+ },
+
+ /**
+ * Returns the custom event of the provided type has been created, a
+ * falsy value otherwise
+ * @method getEvent
+ * @param type {string} the type, or name of the event
+ * @param prefixed {string} if true, the type is prefixed already
+ * @return {Event.Custom} the custom event or null
+ */
+ getEvent: function(type, prefixed) {
+ var pre, e;
+ if (!prefixed) {
+ pre = this._yuievt.config.prefix;
+ type = (pre) ? _getType(type, pre) : type;
+ }
+ e = this._yuievt.events;
+ return (e && type in e) ? e[type] : null;
+ },
+
+ /**
+ * Subscribe to a custom event hosted by this object. The
+ * supplied callback will execute after any listeners add
+ * via the subscribe method, and after the default function,
+ * if configured for the event, has executed.
+ * @method after
+ * @param type {string} The type of the event
+ * @param fn {Function} The callback
+ * @return the event target or a detach handle per 'chain' config
+ */
+ after: function(type, fn) {
+
+ var a = Y.Array(arguments, 0, true);
+
+ switch (L.type(type)) {
+ case 'function':
+ return Y.Do.after.apply(Y.Do, arguments);
+ case 'object':
+ a[0]._after = true;
+ break;
+ default:
+ a[0] = AFTER_PREFIX + type;
+ }
+
+ return this.on.apply(this, a);
+
+ },
+
+ /**
+ * Executes the callback before a DOM event, custom event
+ * or method. If the first argument is a function, it
+ * is assumed the target is a method. For DOM and custom
+ * events, this is an alias for Y.on.
+ *
+ * For DOM and custom events:
+ * type, callback, context, 0-n arguments
+ *
+ * For methods:
+ * callback, object (method host), methodName, context, 0-n arguments
+ *
+ * @method before
+ * @return detach handle
+ * @deprecated use the on method
+ */
+ before: function() {
+ return this.on.apply(this, arguments);
+ }
+
+};
+
+Y.EventTarget = ET;
+
+// make Y an event target
+Y.mix(Y, ET.prototype, false, false, {
+ bubbles: false
+});
+
+ET.call(Y);
+
+YUI.Env.globalEvents = YUI.Env.globalEvents || new ET();
+
+/**
+ * Hosts YUI page level events. This is where events bubble to
+ * when the broadcast config is set to 2. This property is
+ * only available if the custom event module is loaded.
+ * @property Global
+ * @type EventTarget
+ * @for YUI
+ */
+Y.Global = YUI.Env.globalEvents;
+
+// @TODO implement a global namespace function on Y.Global?
+
+})();
+
+
+/**
+ * YUI's on method is a unified interface for subscribing to
+ * most events exposed by YUI. This includes custom events, DOM events, and
+ * function events. detach is also provided to remove listeners
+ * serviced by this function.
+ *
+ * The signature that on accepts varies depending on the type
+ * of event being consumed. Refer to the specific methods that will
+ * service a specific request for additional information about subscribing
+ * to that type of event.
+ *
+ *
+ *
Custom events. These events are defined by various
+ * modules in the library. This type of event is delegated to
+ * EventTarget's on method.
+ *
DOM events. These are moments reported by the browser related
+ * to browser functionality and user interaction.
+ * This type of event is delegated to Event's
+ * attach method.
+ *
+ *
The type of the event
+ *
The callback to execute
+ *
The specification for the Node(s) to attach the listener
+ * to. This can be a selector, collections, or Node/Element
+ * refereces.
Function events. These events can be used to react before or after a
+ * function is executed. This type of event is delegated to Event.Do's
+ * before method.
+ *
+ *
The callback to execute
+ *
The object that has the function that will be listened for.
+ *
The name of the function to listen for.
+ *
An optional context object
+ *
0..n additional arguments to supply the callback.
+ *
+ * Example Y.on(function(arg1, arg2, etc) { // obj.methodname was executed }, obj 'methodname');
+ *
+ *
+ *
+ * on corresponds to the moment before any default behavior of
+ * the event. after works the same way, but these listeners
+ * execute after the event's default behavior. before is an
+ * alias for on.
+ *
+ * @method on
+ * @param type** event type (this parameter does not apply for function events)
+ * @param fn the callback
+ * @param target** a descriptor for the target (applies to custom events only).
+ * For function events, this is the object that contains the function to
+ * execute.
+ * @param extra** 0..n Extra information a particular event may need. These
+ * will be documented with the event. In the case of function events, this
+ * is the name of the function to execute on the host. In the case of
+ * delegate listeners, this is the event delegation specification.
+ * @param context optionally change the value of 'this' in the callback
+ * @param args* 0..n additional arguments to pass to the callback.
+ * @return the event target or a detach handle per 'chain' config
+ * @for YUI
+ */
+
+/**
+ * after() is a unified interface for subscribing to
+ * most events exposed by YUI. This includes custom events,
+ * DOM events, and AOP events. This works the same way as
+ * the on() function, only it operates after any default
+ * behavior for the event has executed. @see on for more
+ * information.
+ * @method after
+ * @param type event type (this parameter does not apply for function events)
+ * @param fn the callback
+ * @param target a descriptor for the target (applies to custom events only).
+ * For function events, this is the object that contains the function to
+ * execute.
+ * @param extra 0..n Extra information a particular event may need. These
+ * will be documented with the event. In the case of function events, this
+ * is the name of the function to execute on the host. In the case of
+ * delegate listeners, this is the event delegation specification.
+ * @param context optionally change the value of 'this' in the callback
+ * @param args* 0..n additional arguments to pass to the callback.
+ * @return the event target or a detach handle per 'chain' config
+ * @for YUI
+ */
+
+
+}, '3.0.0' ,{requires:['oop']});
diff --git a/lib/yui/3.0.0/event-custom/event-custom-complex-debug.js b/lib/yui/3.0.0/event-custom/event-custom-complex-debug.js
new file mode 100644
index 0000000000..753d18cbcc
--- /dev/null
+++ b/lib/yui/3.0.0/event-custom/event-custom-complex-debug.js
@@ -0,0 +1,364 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('event-custom-complex', function(Y) {
+
+
+/**
+ * Adds event facades, preventable default behavior, and bubbling.
+ * events.
+ * @module event-custom
+ * @submodule event-custom-complex
+ */
+
+(function() {
+
+var FACADE, FACADE_KEYS, CEProto = Y.CustomEvent.prototype;
+
+/**
+ * Wraps and protects a custom event for use when emitFacade is set to true.
+ * Requires the event-custom-complex module
+ * @class EventFacade
+ * @param e {Event} the custom event
+ * @param currentTarget {HTMLElement} the element the listener was attached to
+ */
+
+Y.EventFacade = function(e, currentTarget) {
+
+ e = e || {};
+
+ /**
+ * The arguments passed to fire
+ * @property details
+ * @type Array
+ */
+ this.details = e.details;
+
+ /**
+ * The event type
+ * @property type
+ * @type string
+ */
+ this.type = e.type;
+
+ //////////////////////////////////////////////////////
+
+ /**
+ * Node reference for the targeted eventtarget
+ * @propery target
+ * @type Node
+ */
+ this.target = e.target;
+
+ /**
+ * Node reference for the element that the listener was attached to.
+ * @propery currentTarget
+ * @type Node
+ */
+ this.currentTarget = currentTarget;
+
+ /**
+ * Node reference to the relatedTarget
+ * @propery relatedTarget
+ * @type Node
+ */
+ this.relatedTarget = e.relatedTarget;
+
+ /**
+ * Stops the propagation to the next bubble target
+ * @method stopPropagation
+ */
+ this.stopPropagation = function() {
+ e.stopPropagation();
+ };
+
+ /**
+ * Stops the propagation to the next bubble target and
+ * prevents any additional listeners from being exectued
+ * on the current target.
+ * @method stopImmediatePropagation
+ */
+ this.stopImmediatePropagation = function() {
+ e.stopImmediatePropagation();
+ };
+
+ /**
+ * Prevents the event's default behavior
+ * @method preventDefault
+ */
+ this.preventDefault = function() {
+ e.preventDefault();
+ };
+
+ /**
+ * Stops the event propagation and prevents the default
+ * event behavior.
+ * @method halt
+ * @param immediate {boolean} if true additional listeners
+ * on the current target will not be executed
+ */
+ this.halt = function(immediate) {
+ e.halt(immediate);
+ };
+
+};
+
+CEProto.fireComplex = function(args) {
+ var es = Y.Env._eventstack, ef, q, queue, ce, ret, events;
+
+ if (es) {
+ // queue this event if the current item in the queue bubbles
+ if (this.queuable && this.type != es.next.type) {
+ this.log('queue ' + this.type);
+ es.queue.push([this, args]);
+ return true;
+ }
+ } else {
+ Y.Env._eventstack = {
+ // id of the first event in the stack
+ id: this.id,
+ next: this,
+ silent: this.silent,
+ stopped: 0,
+ prevented: 0,
+ queue: []
+ };
+ es = Y.Env._eventstack;
+ }
+
+ this.stopped = 0;
+ this.prevented = 0;
+ this.target = this.target || this.host;
+
+ events = new Y.EventTarget({
+ fireOnce: true,
+ context: this.host
+ });
+
+ this.events = events;
+
+ if (this.preventedFn) {
+ events.on('prevented', this.preventedFn);
+ }
+
+ if (this.stoppedFn) {
+ events.on('stopped', this.stoppedFn);
+ }
+
+ this.currentTarget = this.host || this.currentTarget;
+
+ this.details = args.slice(); // original arguments in the details
+
+ // this.log("Firing " + this + ", " + "args: " + args);
+ this.log("Firing " + this.type);
+
+ this._facade = null; // kill facade to eliminate stale properties
+
+ ef = this._getFacade(args);
+
+ if (Y.Lang.isObject(args[0])) {
+ args[0] = ef;
+ } else {
+ args.unshift(ef);
+ }
+
+ if (this.hasSubscribers) {
+ this._procSubs(Y.merge(this.subscribers), args, ef);
+ }
+
+ // bubble if this is hosted in an event target and propagation has not been stopped
+ if (this.bubbles && this.host && this.host.bubble && !this.stopped) {
+ es.stopped = 0;
+ es.prevented = 0;
+ ret = this.host.bubble(this);
+
+ this.stopped = Math.max(this.stopped, es.stopped);
+ this.prevented = Math.max(this.prevented, es.prevented);
+
+ }
+
+ // execute the default behavior if not prevented
+ if (this.defaultFn && !this.prevented) {
+ this.defaultFn.apply(this.host || this, args);
+ }
+
+ // broadcast listeners are fired as discreet events on the
+ // YUI instance and potentially the YUI global.
+ this._broadcast(args);
+
+ // process after listeners. If the default behavior was
+ // prevented, the after events don't fire.
+ if (this.hasAfters && !this.prevented && this.stopped < 2) {
+ this._procSubs(Y.merge(this.afters), args, ef);
+ }
+
+ if (es.id === this.id) {
+ queue = es.queue;
+
+ while (queue.length) {
+ q = queue.pop();
+ ce = q[0];
+ es.stopped = 0;
+ es.prevented = 0;
+ // set up stack to allow the next item to be processed
+ es.next = ce;
+ ce.fire.apply(ce, q[1]);
+ }
+
+ Y.Env._eventstack = null;
+ }
+
+ return this.stopped ? false : true;
+};
+
+CEProto._getFacade = function() {
+
+ var ef = this._facade, o, o2,
+ args = this.details;
+
+ if (!ef) {
+ ef = new Y.EventFacade(this, this.currentTarget);
+ }
+
+ // if the first argument is an object literal, apply the
+ // properties to the event facade
+ o = args && args[0];
+
+ if (Y.Lang.isObject(o, true)) {
+
+ o2 = {};
+
+ // protect the event facade properties
+ Y.mix(o2, ef, true, FACADE_KEYS);
+
+ // mix the data
+ Y.mix(ef, o, true);
+
+ // restore ef
+ Y.mix(ef, o2, true, FACADE_KEYS);
+ }
+
+ // update the details field with the arguments
+ // ef.type = this.type;
+ ef.details = this.details;
+ ef.target = this.target;
+ ef.currentTarget = this.currentTarget;
+ ef.stopped = 0;
+ ef.prevented = 0;
+
+ this._facade = ef;
+
+ return this._facade;
+};
+
+/**
+ * Stop propagation to bubble targets
+ * @for CustomEvent
+ * @method stopPropagation
+ */
+CEProto.stopPropagation = function() {
+ this.stopped = 1;
+ Y.Env._eventstack.stopped = 1;
+ this.events.fire('stopped', this);
+};
+
+/**
+ * Stops propagation to bubble targets, and prevents any remaining
+ * subscribers on the current target from executing.
+ * @method stopImmediatePropagation
+ */
+CEProto.stopImmediatePropagation = function() {
+ this.stopped = 2;
+ Y.Env._eventstack.stopped = 2;
+ this.events.fire('stopped', this);
+};
+
+/**
+ * Prevents the execution of this event's defaultFn
+ * @method preventDefault
+ */
+CEProto.preventDefault = function() {
+ if (this.preventable) {
+ this.prevented = 1;
+ Y.Env._eventstack.prevented = 1;
+ this.events.fire('prevented', this);
+ }
+};
+
+/**
+ * Stops the event propagation and prevents the default
+ * event behavior.
+ * @method halt
+ * @param immediate {boolean} if true additional listeners
+ * on the current target will not be executed
+ */
+CEProto.halt = function(immediate) {
+ if (immediate) {
+ this.stopImmediatePropagation();
+ } else {
+ this.stopPropagation();
+ }
+ this.preventDefault();
+};
+
+/**
+ * Propagate an event. Requires the event-custom-complex module.
+ * @method bubble
+ * @param evt {Event.Custom} the custom event to propagate
+ * @return {boolean} the aggregated return value from Event.Custom.fire
+ * @for EventTarget
+ */
+Y.EventTarget.prototype.bubble = function(evt, args, target) {
+
+ var targs = this._yuievt.targets, ret = true,
+ t, type, ce, i, bc;
+
+ if (!evt || ((!evt.stopped) && targs)) {
+
+ // Y.log('Bubbling ' + evt.type);
+ for (i in targs) {
+ if (targs.hasOwnProperty(i)) {
+ t = targs[i];
+ type = evt && evt.type;
+ ce = t.getEvent(type, true);
+
+ // if this event was not published on the bubble target,
+ // publish it with sensible default properties
+ if (!ce) {
+
+ if (t._yuievt.hasTargets) {
+ t.bubble.call(t, evt, args, target);
+ }
+
+ } else {
+ ce.target = target || (evt && evt.target) || this;
+ ce.currentTarget = t;
+
+ bc = ce.broadcast;
+ ce.broadcast = false;
+ ret = ret && ce.fire.apply(ce, args || evt.details);
+ ce.broadcast = bc;
+
+ // stopPropagation() was called
+ if (ce.stopped) {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return ret;
+};
+
+FACADE = new Y.EventFacade();
+FACADE_KEYS = Y.Object.keys(FACADE);
+
+})();
+
+
+}, '3.0.0' ,{requires:['event-custom-base']});
diff --git a/lib/yui/3.0.0/event-custom/event-custom-complex-min.js b/lib/yui/3.0.0/event-custom/event-custom-complex-min.js
new file mode 100644
index 0000000000..9270ba0746
--- /dev/null
+++ b/lib/yui/3.0.0/event-custom/event-custom-complex-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("event-custom-complex",function(A){(function(){var C,D,B=A.CustomEvent.prototype;A.EventFacade=function(F,E){F=F||{};this.details=F.details;this.type=F.type;this.target=F.target;this.currentTarget=E;this.relatedTarget=F.relatedTarget;this.stopPropagation=function(){F.stopPropagation();};this.stopImmediatePropagation=function(){F.stopImmediatePropagation();};this.preventDefault=function(){F.preventDefault();};this.halt=function(G){F.halt(G);};};B.fireComplex=function(H){var L=A.Env._eventstack,F,J,E,K,G,I;if(L){if(this.queuable&&this.type!=L.next.type){this.log("queue "+this.type);L.queue.push([this,H]);return true;}}else{A.Env._eventstack={id:this.id,next:this,silent:this.silent,stopped:0,prevented:0,queue:[]};L=A.Env._eventstack;}this.stopped=0;this.prevented=0;this.target=this.target||this.host;I=new A.EventTarget({fireOnce:true,context:this.host});this.events=I;if(this.preventedFn){I.on("prevented",this.preventedFn);}if(this.stoppedFn){I.on("stopped",this.stoppedFn);}this.currentTarget=this.host||this.currentTarget;this.details=H.slice();this.log("Firing "+this.type);this._facade=null;F=this._getFacade(H);if(A.Lang.isObject(H[0])){H[0]=F;}else{H.unshift(F);}if(this.hasSubscribers){this._procSubs(A.merge(this.subscribers),H,F);}if(this.bubbles&&this.host&&this.host.bubble&&!this.stopped){L.stopped=0;L.prevented=0;G=this.host.bubble(this);this.stopped=Math.max(this.stopped,L.stopped);this.prevented=Math.max(this.prevented,L.prevented);}if(this.defaultFn&&!this.prevented){this.defaultFn.apply(this.host||this,H);}this._broadcast(H);if(this.hasAfters&&!this.prevented&&this.stopped<2){this._procSubs(A.merge(this.afters),H,F);}if(L.id===this.id){E=L.queue;while(E.length){J=E.pop();K=J[0];L.stopped=0;L.prevented=0;L.next=K;K.fire.apply(K,J[1]);}A.Env._eventstack=null;}return this.stopped?false:true;};B._getFacade=function(){var E=this._facade,H,G,F=this.details;if(!E){E=new A.EventFacade(this,this.currentTarget);}H=F&&F[0];if(A.Lang.isObject(H,true)){G={};A.mix(G,E,true,D);A.mix(E,H,true);A.mix(E,G,true,D);}E.details=this.details;E.target=this.target;E.currentTarget=this.currentTarget;E.stopped=0;E.prevented=0;this._facade=E;return this._facade;};B.stopPropagation=function(){this.stopped=1;A.Env._eventstack.stopped=1;this.events.fire("stopped",this);};B.stopImmediatePropagation=function(){this.stopped=2;A.Env._eventstack.stopped=2;this.events.fire("stopped",this);};B.preventDefault=function(){if(this.preventable){this.prevented=1;A.Env._eventstack.prevented=1;this.events.fire("prevented",this);}};B.halt=function(E){if(E){this.stopImmediatePropagation();}else{this.stopPropagation();}this.preventDefault();};A.EventTarget.prototype.bubble=function(M,K,I){var G=this._yuievt.targets,J=true,N,L,E,F,H;if(!M||((!M.stopped)&&G)){for(F in G){if(G.hasOwnProperty(F)){N=G[F];L=M&&M.type;E=N.getEvent(L,true);if(!E){if(N._yuievt.hasTargets){N.bubble.call(N,M,K,I);}}else{E.target=I||(M&&M.target)||this;E.currentTarget=N;H=E.broadcast;E.broadcast=false;J=J&&E.fire.apply(E,K||M.details);E.broadcast=H;if(E.stopped){break;}}}}}return J;};C=new A.EventFacade();D=A.Object.keys(C);})();},"3.0.0",{requires:["event-custom-base"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/event-custom/event-custom-complex.js b/lib/yui/3.0.0/event-custom/event-custom-complex.js
new file mode 100644
index 0000000000..5c36d49545
--- /dev/null
+++ b/lib/yui/3.0.0/event-custom/event-custom-complex.js
@@ -0,0 +1,363 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('event-custom-complex', function(Y) {
+
+
+/**
+ * Adds event facades, preventable default behavior, and bubbling.
+ * events.
+ * @module event-custom
+ * @submodule event-custom-complex
+ */
+
+(function() {
+
+var FACADE, FACADE_KEYS, CEProto = Y.CustomEvent.prototype;
+
+/**
+ * Wraps and protects a custom event for use when emitFacade is set to true.
+ * Requires the event-custom-complex module
+ * @class EventFacade
+ * @param e {Event} the custom event
+ * @param currentTarget {HTMLElement} the element the listener was attached to
+ */
+
+Y.EventFacade = function(e, currentTarget) {
+
+ e = e || {};
+
+ /**
+ * The arguments passed to fire
+ * @property details
+ * @type Array
+ */
+ this.details = e.details;
+
+ /**
+ * The event type
+ * @property type
+ * @type string
+ */
+ this.type = e.type;
+
+ //////////////////////////////////////////////////////
+
+ /**
+ * Node reference for the targeted eventtarget
+ * @propery target
+ * @type Node
+ */
+ this.target = e.target;
+
+ /**
+ * Node reference for the element that the listener was attached to.
+ * @propery currentTarget
+ * @type Node
+ */
+ this.currentTarget = currentTarget;
+
+ /**
+ * Node reference to the relatedTarget
+ * @propery relatedTarget
+ * @type Node
+ */
+ this.relatedTarget = e.relatedTarget;
+
+ /**
+ * Stops the propagation to the next bubble target
+ * @method stopPropagation
+ */
+ this.stopPropagation = function() {
+ e.stopPropagation();
+ };
+
+ /**
+ * Stops the propagation to the next bubble target and
+ * prevents any additional listeners from being exectued
+ * on the current target.
+ * @method stopImmediatePropagation
+ */
+ this.stopImmediatePropagation = function() {
+ e.stopImmediatePropagation();
+ };
+
+ /**
+ * Prevents the event's default behavior
+ * @method preventDefault
+ */
+ this.preventDefault = function() {
+ e.preventDefault();
+ };
+
+ /**
+ * Stops the event propagation and prevents the default
+ * event behavior.
+ * @method halt
+ * @param immediate {boolean} if true additional listeners
+ * on the current target will not be executed
+ */
+ this.halt = function(immediate) {
+ e.halt(immediate);
+ };
+
+};
+
+CEProto.fireComplex = function(args) {
+ var es = Y.Env._eventstack, ef, q, queue, ce, ret, events;
+
+ if (es) {
+ // queue this event if the current item in the queue bubbles
+ if (this.queuable && this.type != es.next.type) {
+ this.log('queue ' + this.type);
+ es.queue.push([this, args]);
+ return true;
+ }
+ } else {
+ Y.Env._eventstack = {
+ // id of the first event in the stack
+ id: this.id,
+ next: this,
+ silent: this.silent,
+ stopped: 0,
+ prevented: 0,
+ queue: []
+ };
+ es = Y.Env._eventstack;
+ }
+
+ this.stopped = 0;
+ this.prevented = 0;
+ this.target = this.target || this.host;
+
+ events = new Y.EventTarget({
+ fireOnce: true,
+ context: this.host
+ });
+
+ this.events = events;
+
+ if (this.preventedFn) {
+ events.on('prevented', this.preventedFn);
+ }
+
+ if (this.stoppedFn) {
+ events.on('stopped', this.stoppedFn);
+ }
+
+ this.currentTarget = this.host || this.currentTarget;
+
+ this.details = args.slice(); // original arguments in the details
+
+ // this.log("Firing " + this + ", " + "args: " + args);
+ this.log("Firing " + this.type);
+
+ this._facade = null; // kill facade to eliminate stale properties
+
+ ef = this._getFacade(args);
+
+ if (Y.Lang.isObject(args[0])) {
+ args[0] = ef;
+ } else {
+ args.unshift(ef);
+ }
+
+ if (this.hasSubscribers) {
+ this._procSubs(Y.merge(this.subscribers), args, ef);
+ }
+
+ // bubble if this is hosted in an event target and propagation has not been stopped
+ if (this.bubbles && this.host && this.host.bubble && !this.stopped) {
+ es.stopped = 0;
+ es.prevented = 0;
+ ret = this.host.bubble(this);
+
+ this.stopped = Math.max(this.stopped, es.stopped);
+ this.prevented = Math.max(this.prevented, es.prevented);
+
+ }
+
+ // execute the default behavior if not prevented
+ if (this.defaultFn && !this.prevented) {
+ this.defaultFn.apply(this.host || this, args);
+ }
+
+ // broadcast listeners are fired as discreet events on the
+ // YUI instance and potentially the YUI global.
+ this._broadcast(args);
+
+ // process after listeners. If the default behavior was
+ // prevented, the after events don't fire.
+ if (this.hasAfters && !this.prevented && this.stopped < 2) {
+ this._procSubs(Y.merge(this.afters), args, ef);
+ }
+
+ if (es.id === this.id) {
+ queue = es.queue;
+
+ while (queue.length) {
+ q = queue.pop();
+ ce = q[0];
+ es.stopped = 0;
+ es.prevented = 0;
+ // set up stack to allow the next item to be processed
+ es.next = ce;
+ ce.fire.apply(ce, q[1]);
+ }
+
+ Y.Env._eventstack = null;
+ }
+
+ return this.stopped ? false : true;
+};
+
+CEProto._getFacade = function() {
+
+ var ef = this._facade, o, o2,
+ args = this.details;
+
+ if (!ef) {
+ ef = new Y.EventFacade(this, this.currentTarget);
+ }
+
+ // if the first argument is an object literal, apply the
+ // properties to the event facade
+ o = args && args[0];
+
+ if (Y.Lang.isObject(o, true)) {
+
+ o2 = {};
+
+ // protect the event facade properties
+ Y.mix(o2, ef, true, FACADE_KEYS);
+
+ // mix the data
+ Y.mix(ef, o, true);
+
+ // restore ef
+ Y.mix(ef, o2, true, FACADE_KEYS);
+ }
+
+ // update the details field with the arguments
+ // ef.type = this.type;
+ ef.details = this.details;
+ ef.target = this.target;
+ ef.currentTarget = this.currentTarget;
+ ef.stopped = 0;
+ ef.prevented = 0;
+
+ this._facade = ef;
+
+ return this._facade;
+};
+
+/**
+ * Stop propagation to bubble targets
+ * @for CustomEvent
+ * @method stopPropagation
+ */
+CEProto.stopPropagation = function() {
+ this.stopped = 1;
+ Y.Env._eventstack.stopped = 1;
+ this.events.fire('stopped', this);
+};
+
+/**
+ * Stops propagation to bubble targets, and prevents any remaining
+ * subscribers on the current target from executing.
+ * @method stopImmediatePropagation
+ */
+CEProto.stopImmediatePropagation = function() {
+ this.stopped = 2;
+ Y.Env._eventstack.stopped = 2;
+ this.events.fire('stopped', this);
+};
+
+/**
+ * Prevents the execution of this event's defaultFn
+ * @method preventDefault
+ */
+CEProto.preventDefault = function() {
+ if (this.preventable) {
+ this.prevented = 1;
+ Y.Env._eventstack.prevented = 1;
+ this.events.fire('prevented', this);
+ }
+};
+
+/**
+ * Stops the event propagation and prevents the default
+ * event behavior.
+ * @method halt
+ * @param immediate {boolean} if true additional listeners
+ * on the current target will not be executed
+ */
+CEProto.halt = function(immediate) {
+ if (immediate) {
+ this.stopImmediatePropagation();
+ } else {
+ this.stopPropagation();
+ }
+ this.preventDefault();
+};
+
+/**
+ * Propagate an event. Requires the event-custom-complex module.
+ * @method bubble
+ * @param evt {Event.Custom} the custom event to propagate
+ * @return {boolean} the aggregated return value from Event.Custom.fire
+ * @for EventTarget
+ */
+Y.EventTarget.prototype.bubble = function(evt, args, target) {
+
+ var targs = this._yuievt.targets, ret = true,
+ t, type, ce, i, bc;
+
+ if (!evt || ((!evt.stopped) && targs)) {
+
+ for (i in targs) {
+ if (targs.hasOwnProperty(i)) {
+ t = targs[i];
+ type = evt && evt.type;
+ ce = t.getEvent(type, true);
+
+ // if this event was not published on the bubble target,
+ // publish it with sensible default properties
+ if (!ce) {
+
+ if (t._yuievt.hasTargets) {
+ t.bubble.call(t, evt, args, target);
+ }
+
+ } else {
+ ce.target = target || (evt && evt.target) || this;
+ ce.currentTarget = t;
+
+ bc = ce.broadcast;
+ ce.broadcast = false;
+ ret = ret && ce.fire.apply(ce, args || evt.details);
+ ce.broadcast = bc;
+
+ // stopPropagation() was called
+ if (ce.stopped) {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return ret;
+};
+
+FACADE = new Y.EventFacade();
+FACADE_KEYS = Y.Object.keys(FACADE);
+
+})();
+
+
+}, '3.0.0' ,{requires:['event-custom-base']});
diff --git a/lib/yui/3.0.0/event-custom/event-custom-debug.js b/lib/yui/3.0.0/event-custom/event-custom-debug.js
new file mode 100644
index 0000000000..f800951015
--- /dev/null
+++ b/lib/yui/3.0.0/event-custom/event-custom-debug.js
@@ -0,0 +1,2093 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('event-custom-base', function(Y) {
+
+/**
+ * Custom event engine, DOM event listener abstraction layer, synthetic DOM
+ * events.
+ * @module event-custom
+ */
+
+Y.Env.evt = {
+ handles: {},
+ plugins: {}
+};
+
+
+/**
+ * Custom event engine, DOM event listener abstraction layer, synthetic DOM
+ * events.
+ * @module event-custom
+ * @submodule event-custom-base
+ */
+(function() {
+
+/**
+ * Allows for the insertion of methods that are executed before or after
+ * a specified method
+ * @class Do
+ * @static
+ */
+
+var BEFORE = 0,
+ AFTER = 1;
+
+Y.Do = {
+
+ /**
+ * Cache of objects touched by the utility
+ * @property objs
+ * @static
+ */
+ objs: {},
+
+ /**
+ * Execute the supplied method before the specified function
+ * @method before
+ * @param fn {Function} the function to execute
+ * @param obj the object hosting the method to displace
+ * @param sFn {string} the name of the method to displace
+ * @param c The execution context for fn
+ * @return {string} handle for the subscription
+ * @static
+ */
+ before: function(fn, obj, sFn, c) {
+ // Y.log('Do before: ' + sFn, 'info', 'event');
+ var f = fn, a;
+ if (c) {
+ a = [fn, c].concat(Y.Array(arguments, 4, true));
+ f = Y.rbind.apply(Y, a);
+ }
+
+ return this._inject(BEFORE, f, obj, sFn);
+ },
+
+ /**
+ * Execute the supplied method after the specified function
+ * @method after
+ * @param fn {Function} the function to execute
+ * @param obj the object hosting the method to displace
+ * @param sFn {string} the name of the method to displace
+ * @param c The execution context for fn
+ * @return {string} handle for the subscription
+ * @static
+ */
+ after: function(fn, obj, sFn, c) {
+ var f = fn, a;
+ if (c) {
+ a = [fn, c].concat(Y.Array(arguments, 4, true));
+ f = Y.rbind.apply(Y, a);
+ }
+
+ return this._inject(AFTER, f, obj, sFn);
+ },
+
+ /**
+ * Execute the supplied method after the specified function
+ * @method _inject
+ * @param when {string} before or after
+ * @param fn {Function} the function to execute
+ * @param obj the object hosting the method to displace
+ * @param sFn {string} the name of the method to displace
+ * @param c The execution context for fn
+ * @return {string} handle for the subscription
+ * @private
+ * @static
+ */
+ _inject: function(when, fn, obj, sFn) {
+
+ // object id
+ var id = Y.stamp(obj), o, sid;
+
+ if (! this.objs[id]) {
+ // create a map entry for the obj if it doesn't exist
+ this.objs[id] = {};
+ }
+
+ o = this.objs[id];
+
+ if (! o[sFn]) {
+ // create a map entry for the method if it doesn't exist
+ o[sFn] = new Y.Do.Method(obj, sFn);
+
+ // re-route the method to our wrapper
+ obj[sFn] =
+ function() {
+ return o[sFn].exec.apply(o[sFn], arguments);
+ };
+ }
+
+ // subscriber id
+ sid = id + Y.stamp(fn) + sFn;
+
+ // register the callback
+ o[sFn].register(sid, fn, when);
+
+ return new Y.EventHandle(o[sFn], sid);
+
+ },
+
+ /**
+ * Detach a before or after subscription
+ * @method detach
+ * @param handle {string} the subscription handle
+ */
+ detach: function(handle) {
+
+ if (handle.detach) {
+ handle.detach();
+ }
+
+ },
+
+ _unload: function(e, me) {
+
+ }
+};
+
+//////////////////////////////////////////////////////////////////////////
+
+/**
+ * Wrapper for a displaced method with aop enabled
+ * @class Do.Method
+ * @constructor
+ * @param obj The object to operate on
+ * @param sFn The name of the method to displace
+ */
+Y.Do.Method = function(obj, sFn) {
+ this.obj = obj;
+ this.methodName = sFn;
+ this.method = obj[sFn];
+ this.before = {};
+ this.after = {};
+};
+
+/**
+ * Register a aop subscriber
+ * @method register
+ * @param sid {string} the subscriber id
+ * @param fn {Function} the function to execute
+ * @param when {string} when to execute the function
+ */
+Y.Do.Method.prototype.register = function (sid, fn, when) {
+ if (when) {
+ this.after[sid] = fn;
+ } else {
+ this.before[sid] = fn;
+ }
+};
+
+/**
+ * Unregister a aop subscriber
+ * @method delete
+ * @param sid {string} the subscriber id
+ * @param fn {Function} the function to execute
+ * @param when {string} when to execute the function
+ */
+Y.Do.Method.prototype._delete = function (sid) {
+ // Y.log('Y.Do._delete: ' + sid, 'info', 'Event');
+ delete this.before[sid];
+ delete this.after[sid];
+};
+
+/**
+ * Execute the wrapped method
+ * @method exec
+ */
+Y.Do.Method.prototype.exec = function () {
+
+ var args = Y.Array(arguments, 0, true),
+ i, ret, newRet,
+ bf = this.before,
+ af = this.after,
+ prevented = false;
+
+ // execute before
+ for (i in bf) {
+ if (bf.hasOwnProperty(i)) {
+ ret = bf[i].apply(this.obj, args);
+ if (ret) {
+ switch (ret.constructor) {
+ case Y.Do.Halt:
+ return ret.retVal;
+ case Y.Do.AlterArgs:
+ args = ret.newArgs;
+ break;
+ case Y.Do.Prevent:
+ prevented = true;
+ break;
+ default:
+ }
+ }
+ }
+ }
+
+ // execute method
+ if (!prevented) {
+ ret = this.method.apply(this.obj, args);
+ }
+
+ // execute after methods.
+ for (i in af) {
+ if (af.hasOwnProperty(i)) {
+ newRet = af[i].apply(this.obj, args);
+ // Stop processing if a Halt object is returned
+ if (newRet && newRet.constructor == Y.Do.Halt) {
+ return newRet.retVal;
+ // Check for a new return value
+ } else if (newRet && newRet.constructor == Y.Do.AlterReturn) {
+ ret = newRet.newRetVal;
+ }
+ }
+ }
+
+ return ret;
+};
+
+//////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * Return an AlterArgs object when you want to change the arguments that
+ * were passed into the function. An example would be a service that scrubs
+ * out illegal characters prior to executing the core business logic.
+ * @class Do.AlterArgs
+ */
+Y.Do.AlterArgs = function(msg, newArgs) {
+ this.msg = msg;
+ this.newArgs = newArgs;
+};
+
+/**
+ * Return an AlterReturn object when you want to change the result returned
+ * from the core method to the caller
+ * @class Do.AlterReturn
+ */
+Y.Do.AlterReturn = function(msg, newRetVal) {
+ this.msg = msg;
+ this.newRetVal = newRetVal;
+};
+
+/**
+ * Return a Halt object when you want to terminate the execution
+ * of all subsequent subscribers as well as the wrapped method
+ * if it has not exectued yet.
+ * @class Do.Halt
+ */
+Y.Do.Halt = function(msg, retVal) {
+ this.msg = msg;
+ this.retVal = retVal;
+};
+
+/**
+ * Return a Prevent object when you want to prevent the wrapped function
+ * from executing, but want the remaining listeners to execute
+ * @class Do.Prevent
+ */
+Y.Do.Prevent = function(msg) {
+ this.msg = msg;
+};
+
+/**
+ * Return an Error object when you want to terminate the execution
+ * of all subsequent method calls.
+ * @class Do.Error
+ * @deprecated use Y.Do.Halt or Y.Do.Prevent
+ */
+Y.Do.Error = Y.Do.Halt;
+
+//////////////////////////////////////////////////////////////////////////
+
+// Y["Event"] && Y.Event.addListener(window, "unload", Y.Do._unload, Y.Do);
+
+})();
+
+/**
+ * Custom event engine, DOM event listener abstraction layer, synthetic DOM
+ * events.
+ * @module event-custom
+ * @submodule event-custom-base
+ */
+
+/**
+ * Return value from all subscribe operations
+ * @class EventHandle
+ * @constructor
+ * @param evt {CustomEvent} the custom event
+ * @param sub {Subscriber} the subscriber
+ */
+
+// var onsubscribeType = "_event:onsub",
+var AFTER = 'after',
+ CONFIGS = [
+ 'broadcast',
+ 'bubbles',
+ 'context',
+ 'contextFn',
+ 'currentTarget',
+ 'defaultFn',
+ 'details',
+ 'emitFacade',
+ 'fireOnce',
+ 'host',
+ 'preventable',
+ 'preventedFn',
+ 'queuable',
+ 'silent',
+ 'stoppedFn',
+ 'target',
+ 'type'
+ ],
+
+
+ YUI3_SIGNATURE = 9,
+ YUI_LOG = 'yui:log';
+
+Y.EventHandle = function(evt, sub) {
+
+ /**
+ * The custom event
+ * @type CustomEvent
+ */
+ this.evt = evt;
+
+ /**
+ * The subscriber object
+ * @type Subscriber
+ */
+ this.sub = sub;
+};
+
+Y.EventHandle.prototype = {
+
+ /**
+ * Detaches this subscriber
+ * @method detach
+ */
+ detach: function() {
+ var evt = this.evt, i;
+ if (evt) {
+ // Y.log('EventHandle.detach: ' + this.sub, 'info', 'Event');
+ if (Y.Lang.isArray(evt)) {
+ for (i=0; i 2) {
+// this.log('CustomEvent context and silent are now in the config', 'warn', 'Event');
+ // }
+
+ o = o || {};
+
+ this.id = Y.stamp(this);
+
+ /**
+ * The type of event, returned to subscribers when the event fires
+ * @property type
+ * @type string
+ */
+ this.type = type;
+
+ /**
+ * The context the the event will fire from by default. Defaults to the YUI
+ * instance.
+ * @property context
+ * @type object
+ */
+ this.context = Y;
+
+ this.logSystem = (type == YUI_LOG);
+
+ /**
+ * If 0, this event does not broadcast. If 1, the YUI instance is notified
+ * every time this event fires. If 2, the YUI instance and the YUI global
+ * (if event is enabled on the global) are notified every time this event
+ * fires.
+ * @property broadcast
+ * @type int
+ */
+ // this.broadcast = 0;
+
+ /**
+ * By default all custom events are logged in the debug build, set silent
+ * to true to disable debug outpu for this event.
+ * @property silent
+ * @type boolean
+ */
+ this.silent = this.logSystem;
+
+ /**
+ * Specifies whether this event should be queued when the host is actively
+ * processing an event. This will effect exectution order of the callbacks
+ * for the various events.
+ * @property queuable
+ * @type boolean
+ * @default false
+ */
+ // this.queuable = false;
+
+ /**
+ * The subscribers to this event
+ * @property subscribers
+ * @type Subscriber{}
+ */
+ this.subscribers = {};
+
+ /**
+ * 'After' subscribers
+ * @property afters
+ * @type Subscriber{}
+ */
+ this.afters = {};
+
+ /**
+ * This event has fired if true
+ *
+ * @property fired
+ * @type boolean
+ * @default false;
+ */
+ // this.fired = false;
+
+ /**
+ * An array containing the arguments the custom event
+ * was last fired with.
+ * @property firedWith
+ * @type Array
+ */
+ // this.firedWith;
+
+ /**
+ * This event should only fire one time if true, and if
+ * it has fired, any new subscribers should be notified
+ * immediately.
+ *
+ * @property fireOnce
+ * @type boolean
+ * @default false;
+ */
+ // this.fireOnce = false;
+
+ /**
+ * Flag for stopPropagation that is modified during fire()
+ * 1 means to stop propagation to bubble targets. 2 means
+ * to also stop additional subscribers on this target.
+ * @property stopped
+ * @type int
+ */
+ // this.stopped = 0;
+
+ /**
+ * Flag for preventDefault that is modified during fire().
+ * if it is not 0, the default behavior for this event
+ * @property prevented
+ * @type int
+ */
+ // this.prevented = 0;
+
+ /**
+ * Specifies the host for this custom event. This is used
+ * to enable event bubbling
+ * @property host
+ * @type EventTarget
+ */
+ // this.host = null;
+
+ /**
+ * The default function to execute after event listeners
+ * have fire, but only if the default action was not
+ * prevented.
+ * @property defaultFn
+ * @type Function
+ */
+ // this.defaultFn = null;
+
+ /**
+ * The function to execute if a subscriber calls
+ * stopPropagation or stopImmediatePropagation
+ * @property stoppedFn
+ * @type Function
+ */
+ // this.stoppedFn = null;
+
+ /**
+ * The function to execute if a subscriber calls
+ * preventDefault
+ * @property preventedFn
+ * @type Function
+ */
+ // this.preventedFn = null;
+
+ /**
+ * Specifies whether or not this event's default function
+ * can be cancelled by a subscriber by executing preventDefault()
+ * on the event facade
+ * @property preventable
+ * @type boolean
+ * @default true
+ */
+ this.preventable = true;
+
+ /**
+ * Specifies whether or not a subscriber can stop the event propagation
+ * via stopPropagation(), stopImmediatePropagation(), or halt()
+ * @property bubbles
+ * @type boolean
+ * @default true
+ */
+ this.bubbles = true;
+
+ /**
+ * Supports multiple options for listener signatures in order to
+ * port YUI 2 apps.
+ * @property signature
+ * @type int
+ * @default 9
+ */
+ this.signature = YUI3_SIGNATURE;
+
+ // this.hasSubscribers = false;
+
+ // this.hasAfters = false;
+
+ /**
+ * If set to true, the custom event will deliver an EventFacade object
+ * that is similar to a DOM event object.
+ * @property emitFacade
+ * @type boolean
+ * @default false
+ */
+ // this.emitFacade = false;
+
+ this.applyConfig(o, true);
+
+ // this.log("Creating " + this.type);
+
+};
+
+Y.CustomEvent.prototype = {
+
+ /**
+ * Apply configuration properties. Only applies the CONFIG whitelist
+ * @method applyConfig
+ * @param o hash of properties to apply
+ * @param force {boolean} if true, properties that exist on the event
+ * will be overwritten.
+ */
+ applyConfig: function(o, force) {
+ if (o) {
+ Y.mix(this, o, force, CONFIGS);
+ }
+ },
+
+ _on: function(fn, context, args, when) {
+
+ if (!fn) {
+ this.log("Invalid callback for CE: " + this.type);
+ }
+
+ var s = new Y.Subscriber(fn, context, args, when);
+
+ if (this.fireOnce && this.fired) {
+ Y.later(0, this, Y.bind(this._notify, this, s, this.firedWith));
+ }
+
+ if (when == AFTER) {
+ this.afters[s.id] = s;
+ this.hasAfters = true;
+ } else {
+ this.subscribers[s.id] = s;
+ this.hasSubscribers = true;
+ }
+
+ return new Y.EventHandle(this, s);
+
+ },
+
+ /**
+ * Listen for this event
+ * @method subscribe
+ * @param {Function} fn The function to execute
+ * @return {EventHandle|EventTarget} unsubscribe handle or a
+ * chainable event target depending on the 'chain' config.
+ * @deprecated use on
+ */
+ subscribe: function(fn, context) {
+ Y.log('ce.subscribe deprecated, use "on"', 'warn', 'deprecated');
+ var a = (arguments.length > 2) ? Y.Array(arguments, 2, true): null;
+ return this._on(fn, context, a, true);
+ },
+
+ /**
+ * Listen for this event
+ * @method on
+ * @param {Function} fn The function to execute
+ * @return {EventHandle|EventTarget} unsubscribe handle or a
+ * chainable event target depending on the 'chain' config.
+ */
+ on: function(fn, context) {
+ var a = (arguments.length > 2) ? Y.Array(arguments, 2, true): null;
+ return this._on(fn, context, a, true);
+ },
+
+ /**
+ * Listen for this event after the normal subscribers have been notified and
+ * the default behavior has been applied. If a normal subscriber prevents the
+ * default behavior, it also prevents after listeners from firing.
+ * @method after
+ * @param {Function} fn The function to execute
+ * @return {EventHandle|EventTarget} unsubscribe handle or a
+ * chainable event target depending on the 'chain' config.
+ */
+ after: function(fn, context) {
+ var a = (arguments.length > 2) ? Y.Array(arguments, 2, true): null;
+ return this._on(fn, context, a, AFTER);
+ },
+
+ /**
+ * Detach listeners.
+ * @method detach
+ * @param {Function} fn The subscribed function to remove, if not supplied
+ * all will be removed
+ * @param {Object} context The context object passed to subscribe.
+ * @return {int|EventTarget} returns a chainable event target
+ * or the number of subscribers unsubscribed.
+ */
+ detach: function(fn, context) {
+ // unsubscribe handle
+ if (fn && fn.detach) {
+ return fn.detach();
+ }
+
+ var found = 0, subs = this.subscribers, i, s;
+
+ for (i in subs) {
+ if (subs.hasOwnProperty(i)) {
+ s = subs[i];
+ if (s && (!fn || fn === s.fn)) {
+ this._delete(s);
+ found++;
+ }
+ }
+ }
+
+ return found;
+ },
+
+ /**
+ * Detach listeners.
+ * @method unsubscribe
+ * @param {Function} fn The subscribed function to remove, if not supplied
+ * all will be removed
+ * @param {Object} context The context object passed to subscribe.
+ * @return {boolean|EventTarget} returns a chainable event target
+ * or a boolean for legacy detach support.
+ * @deprecated use detach
+ */
+ unsubscribe: function() {
+ return this.detach.apply(this, arguments);
+ },
+
+
+ /**
+ * Notify a single subscriber
+ * @method _notify
+ * @param s {Subscriber} the subscriber
+ * @param args {Array} the arguments array to apply to the listener
+ * @private
+ */
+ _notify: function(s, args, ef) {
+
+ this.log(this.type + "->" + "sub: " + s.id);
+
+ var ret;
+
+ ret = s.notify(args, this);
+
+ if (false === ret || this.stopped > 1) {
+ this.log(this.type + " cancelled by subscriber");
+ return false;
+ }
+
+ return true;
+ },
+
+ /**
+ * Logger abstraction to centralize the application of the silent flag
+ * @method log
+ * @param msg {string} message to log
+ * @param cat {string} log category
+ */
+ log: function(msg, cat) {
+ if (!this.silent) {
+ Y.log(this.id + ': ' + msg, cat || "info", "event");
+ }
+ },
+
+ /**
+ * Notifies the subscribers. The callback functions will be executed
+ * from the context specified when the event was created, and with the
+ * following parameters:
+ *
+ *
The type of event
+ *
All of the arguments fire() was executed with as an array
+ *
The custom object (if any) that was passed into the subscribe()
+ * method
+ *
+ * @method fire
+ * @param {Object*} arguments an arbitrary set of parameters to pass to
+ * the handler.
+ * @return {boolean} false if one of the subscribers returned false,
+ * true otherwise
+ *
+ */
+ fire: function() {
+ if (this.fireOnce && this.fired) {
+ this.log('fireOnce event: ' + this.type + ' already fired');
+ return true;
+ } else {
+
+ var args = Y.Array(arguments, 0, true);
+
+ this.fired = true;
+ this.firedWith = args;
+
+ if (this.emitFacade) {
+ return this.fireComplex(args);
+ } else {
+ return this.fireSimple(args);
+ }
+ }
+ },
+
+ fireSimple: function(args) {
+ if (this.hasSubscribers || this.hasAfters) {
+ this._procSubs(Y.merge(this.subscribers, this.afters), args);
+ }
+ this._broadcast(args);
+ return this.stopped ? false : true;
+ },
+
+ // Requires the event-custom-complex module for full funcitonality.
+ fireComplex: function(args) {
+ args[0] = args[0] || {};
+ return this.fireSimple(args);
+ },
+
+ _procSubs: function(subs, args, ef) {
+ var s, i;
+ for (i in subs) {
+ if (subs.hasOwnProperty(i)) {
+ s = subs[i];
+ if (s && s.fn) {
+ if (false === this._notify(s, args, ef)) {
+ this.stopped = 2;
+ }
+ if (this.stopped == 2) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ },
+
+ _broadcast: function(args) {
+ if (!this.stopped && this.broadcast) {
+
+ var a = Y.Array(args);
+ a.unshift(this.type);
+
+ if (this.host !== Y) {
+ Y.fire.apply(Y, a);
+ }
+
+ if (this.broadcast == 2) {
+ Y.Global.fire.apply(Y.Global, a);
+ }
+ }
+ },
+
+ /**
+ * Removes all listeners
+ * @method unsubscribeAll
+ * @return {int} The number of listeners unsubscribed
+ * @deprecated use detachAll
+ */
+ unsubscribeAll: function() {
+ return this.detachAll.apply(this, arguments);
+ },
+
+ /**
+ * Removes all listeners
+ * @method detachAll
+ * @return {int} The number of listeners unsubscribed
+ */
+ detachAll: function() {
+ return this.detach();
+ },
+
+ /**
+ * @method _delete
+ * @param subscriber object
+ * @private
+ */
+ _delete: function(s) {
+ if (s) {
+ delete s.fn;
+ delete s.context;
+ delete this.subscribers[s.id];
+ delete this.afters[s.id];
+ }
+ }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn The wrapped function to execute
+ * @param {Object} context The value of the keyword 'this' in the listener
+ * @param {Array} args* 0..n additional arguments to supply the listener
+ *
+ * @class Subscriber
+ * @constructor
+ */
+Y.Subscriber = function(fn, context, args) {
+
+ /**
+ * The callback that will be execute when the event fires
+ * This is wrapped by Y.rbind if obj was supplied.
+ * @property fn
+ * @type Function
+ */
+ this.fn = fn;
+
+ /**
+ * Optional 'this' keyword for the listener
+ * @property context
+ * @type Object
+ */
+ this.context = context;
+
+ /**
+ * Unique subscriber id
+ * @property id
+ * @type String
+ */
+ this.id = Y.stamp(this);
+
+ /**
+ * Additional arguments to propagate to the subscriber
+ * @property args
+ * @type Array
+ */
+ this.args = args;
+
+ /**
+ * Custom events for a given fire transaction.
+ * @property events
+ * @type {EventTarget}
+ */
+ this.events = null;
+
+};
+
+Y.Subscriber.prototype = {
+
+ _notify: function(c, args, ce) {
+ var a = this.args, ret;
+ switch (ce.signature) {
+ case 0:
+ ret = this.fn.call(c, ce.type, args, c);
+ break;
+ case 1:
+ ret = this.fn.call(c, args[0] || null, c);
+ break;
+ default:
+ if (a || args) {
+ args = args || [];
+ a = (a) ? args.concat(a) : args;
+ ret = this.fn.apply(c, a);
+ } else {
+ ret = this.fn.call(c);
+ }
+ }
+
+ return ret;
+ },
+
+ /**
+ * Executes the subscriber.
+ * @method notify
+ * @param args {Array} Arguments array for the subscriber
+ * @param ce {CustomEvent} The custom event that sent the notification
+ */
+ notify: function(args, ce) {
+ var c = this.context,
+ ret = true;
+
+ if (!c) {
+ c = (ce.contextFn) ? ce.contextFn() : ce.context;
+ }
+
+ // only catch errors if we will not re-throw them.
+ if (Y.config.throwFail) {
+ ret = this._notify(c, args, ce);
+ } else {
+ try {
+ ret = this._notify(c, args, ce);
+ } catch(e) {
+ Y.error(this + ' failed: ' + e.message, e);
+ }
+ }
+
+ return ret;
+ },
+
+ /**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} context optional 'this' keyword for the listener
+ * @return {boolean} true if the supplied arguments match this
+ * subscriber's signature.
+ */
+ contains: function(fn, context) {
+ if (context) {
+ return ((this.fn == fn) && this.context == context);
+ } else {
+ return (this.fn == fn);
+ }
+ }
+
+};
+
+/**
+ * Custom event engine, DOM event listener abstraction layer, synthetic DOM
+ * events.
+ * @module event-custom
+ * @submodule event-custom-base
+ */
+(function() {
+
+/**
+ * EventTarget provides the implementation for any object to
+ * publish, subscribe and fire to custom events, and also
+ * alows other EventTargets to target the object with events
+ * sourced from the other object.
+ * EventTarget is designed to be used with Y.augment to wrap
+ * EventCustom in an interface that allows events to be listened to
+ * and fired by name. This makes it possible for implementing code to
+ * subscribe to an event that either has not been created yet, or will
+ * not be created at all.
+ * @class EventTarget
+ * @param opts a configuration object
+ * @config emitFacade {boolean} if true, all events will emit event
+ * facade payloads by default (default false)
+ * @config prefix {string} the prefix to apply to non-prefixed event names
+ * @config chain {boolean} if true, on/after/detach return the host to allow
+ * chaining, otherwise they return an EventHandle (default false)
+ */
+
+var L = Y.Lang,
+ PREFIX_DELIMITER = ':',
+ CATEGORY_DELIMITER = '|',
+ AFTER_PREFIX = '~AFTER~',
+
+ /**
+ * If the instance has a prefix attribute and the
+ * event type is not prefixed, the instance prefix is
+ * applied to the supplied type.
+ * @method _getType
+ * @private
+ */
+ _getType = Y.cached(function(type, pre) {
+
+ if (!pre || !L.isString(type) || type.indexOf(PREFIX_DELIMITER) > -1) {
+ return type;
+ }
+
+ return pre + PREFIX_DELIMITER + type;
+ }),
+
+ /**
+ * Returns an array with the detach key (if provided),
+ * and the prefixed event name from _getType
+ * Y.on('detachcategory, menu:click', fn)
+ * @method _parseType
+ * @private
+ */
+ _parseType = Y.cached(function(type, pre) {
+
+ var t = type, detachcategory, after, i;
+
+ if (!L.isString(t)) {
+ return t;
+ }
+
+ i = t.indexOf(AFTER_PREFIX);
+
+ if (i > -1) {
+ after = true;
+ t = t.substr(AFTER_PREFIX.length);
+ // Y.log(t);
+ }
+
+ i = t.indexOf(CATEGORY_DELIMITER);
+
+ if (i > -1) {
+ detachcategory = t.substr(0, (i));
+ t = t.substr(i+1);
+ if (t == '*') {
+ t = null;
+ }
+ }
+
+ // detach category, full type with instance prefix, is this an after listener, short type
+ return [detachcategory, (pre) ? _getType(t, pre) : t, after, t];
+ }),
+
+ ET = function(opts) {
+
+ // Y.log('EventTarget constructor executed: ' + this._yuid);
+
+ var o = (L.isObject(opts)) ? opts : {};
+
+ this._yuievt = this._yuievt || {
+
+ id: Y.guid(),
+
+ events: {},
+
+ targets: {},
+
+ config: o,
+
+ chain: ('chain' in o) ? o.chain : Y.config.chain,
+
+ defaults: {
+ context: o.context || this,
+ host: this,
+ emitFacade: o.emitFacade,
+ fireOnce: o.fireOnce,
+ queuable: o.queuable,
+ broadcast: o.broadcast,
+ bubbles: ('bubbles' in o) ? o.bubbles : true
+ }
+ };
+
+ };
+
+
+ET.prototype = {
+
+ /**
+ * Subscribe to a custom event hosted by this object
+ * @method on
+ * @param type {string} The type of the event
+ * @param fn {Function} The callback
+ * @return the event target or a detach handle per 'chain' config
+ */
+ on: function(type, fn, context, x) {
+
+ var parts = _parseType(type, this._yuievt.config.prefix), f, c, args, ret, ce,
+ detachcategory, handle, store = Y.Env.evt.handles, after, adapt, shorttype,
+ Node = Y.Node, n, domevent;
+
+ if (L.isObject(type)) {
+
+ if (L.isFunction(type)) {
+ return Y.Do.before.apply(Y.Do, arguments);
+ }
+
+ f = fn;
+ c = context;
+ args = Y.Array(arguments, 0, true);
+ ret = {};
+ after = type._after;
+ delete type._after;
+
+ Y.each(type, function(v, k) {
+
+ if (v) {
+ f = v.fn || ((Y.Lang.isFunction(v)) ? v : f);
+ c = v.context || c;
+ }
+
+ args[0] = (after) ? AFTER_PREFIX + k : k;
+ args[1] = f;
+ args[2] = c;
+
+ ret[k] = this.on.apply(this, args);
+
+ }, this);
+
+ return (this._yuievt.chain) ? this : new Y.EventHandle(ret);
+
+ }
+
+ detachcategory = parts[0];
+ after = parts[2];
+ shorttype = parts[3];
+
+ // extra redirection so we catch adaptor events too. take a look at this.
+ if (Node && (this instanceof Node) && (shorttype in Node.DOM_EVENTS)) {
+ args = Y.Array(arguments, 0, true);
+ args.splice(2, 0, Node.getDOMNode(this));
+ // Y.log("Node detected, redirecting with these args: " + args);
+ return Y.on.apply(Y, args);
+ }
+
+ type = parts[1];
+
+ if (this instanceof YUI) {
+
+ adapt = Y.Env.evt.plugins[type];
+ args = Y.Array(arguments, 0, true);
+ args[0] = shorttype;
+
+ if (Node) {
+ n = args[2];
+
+ if (n instanceof Y.NodeList) {
+ n = Y.NodeList.getDOMNodes(n);
+ } else if (n instanceof Node) {
+ n = Node.getDOMNode(n);
+ }
+
+ domevent = (shorttype in Node.DOM_EVENTS);
+
+ // Captures both DOM events and event plugins.
+ if (domevent) {
+ args[2] = n;
+ }
+ }
+
+ // check for the existance of an event adaptor
+ if (adapt) {
+ Y.log('Using adaptor for ' + shorttype + ', ' + n, 'info', 'event');
+ handle = adapt.on.apply(Y, args);
+ } else if ((!type) || domevent) {
+ handle = Y.Event._attach(args);
+ }
+
+ }
+
+ if (!handle) {
+ ce = this._yuievt.events[type] || this.publish(type);
+ handle = ce._on(fn, context, (arguments.length > 3) ? Y.Array(arguments, 3, true) : null, (after) ? 'after' : true);
+ }
+
+ if (detachcategory) {
+ store[detachcategory] = store[detachcategory] || {};
+ store[detachcategory][type] = store[detachcategory][type] || [];
+ store[detachcategory][type].push(handle);
+ }
+
+ return (this._yuievt.chain) ? this : handle;
+
+ },
+
+ /**
+ * subscribe to an event
+ * @method subscribe
+ * @deprecated use on
+ */
+ subscribe: function() {
+ Y.log('EventTarget subscribe() is deprecated, use on()', 'warn', 'deprecated');
+ return this.on.apply(this, arguments);
+ },
+
+ /**
+ * Detach one or more listeners the from the specified event
+ * @method detach
+ * @param type {string|Object} Either the handle to the subscriber or the
+ * type of event. If the type
+ * is not specified, it will attempt to remove
+ * the listener from all hosted events.
+ * @param fn {Function} The subscribed function to unsubscribe, if not
+ * supplied, all subscribers will be removed.
+ * @param context {Object} The custom object passed to subscribe. This is
+ * optional, but if supplied will be used to
+ * disambiguate multiple listeners that are the same
+ * (e.g., you subscribe many object using a function
+ * that lives on the prototype)
+ * @return {EventTarget} the host
+ */
+ detach: function(type, fn, context) {
+ var evts = this._yuievt.events, i, ret,
+ Node = Y.Node, isNode = (this instanceof Node);
+
+ // detachAll disabled on the Y instance.
+ if (!type && (this !== Y)) {
+ for (i in evts) {
+ if (evts.hasOwnProperty(i)) {
+ ret = evts[i].detach(fn, context);
+ }
+ }
+ if (isNode) {
+
+ Y.Event.purgeElement(Node.getDOMNode(this));
+ }
+
+ return ret;
+ }
+
+ var parts = _parseType(type, this._yuievt.config.prefix),
+ detachcategory = L.isArray(parts) ? parts[0] : null,
+ shorttype = (parts) ? parts[3] : null,
+ handle, adapt, store = Y.Env.evt.handles, cat, args,
+ ce,
+
+ keyDetacher = function(lcat, ltype) {
+ var handles = lcat[ltype];
+ if (handles) {
+ while (handles.length) {
+ handle = handles.pop();
+ handle.detach();
+ }
+ }
+ };
+
+ if (detachcategory) {
+
+ cat = store[detachcategory];
+ type = parts[1];
+
+ if (cat) {
+ if (type) {
+ keyDetacher(cat, type);
+ } else {
+ for (i in cat) {
+ if (cat.hasOwnProperty(i)) {
+ keyDetacher(cat, i);
+ }
+ }
+ }
+
+ return (this._yuievt.chain) ? this : true;
+ }
+
+ // If this is an event handle, use it to detach
+ } else if (L.isObject(type) && type.detach) {
+ ret = type.detach();
+ return (this._yuievt.chain) ? this : ret;
+ // extra redirection so we catch adaptor events too. take a look at this.
+ } else if (isNode && ((!shorttype) || (shorttype in Node.DOM_EVENTS))) {
+ args = Y.Array(arguments, 0, true);
+ args[2] = Node.getDOMNode(this);
+ return Y.detach.apply(Y, args);
+ }
+
+ adapt = Y.Env.evt.plugins[shorttype];
+
+ // The YUI instance handles DOM events and adaptors
+ if (this instanceof YUI) {
+ args = Y.Array(arguments, 0, true);
+ // use the adaptor specific detach code if
+ if (adapt && adapt.detach) {
+ return adapt.detach.apply(Y, args);
+ // DOM event fork
+ } else if (!type || (!adapt && Node && (type in Node.DOM_EVENTS))) {
+ args[0] = type;
+ return Y.Event.detach.apply(Y.Event, args);
+ }
+ }
+
+ ce = evts[type];
+ if (ce) {
+ ret = ce.detach(fn, context);
+ }
+
+ return (this._yuievt.chain) ? this : ret;
+ },
+
+ /**
+ * detach a listener
+ * @method unsubscribe
+ * @deprecated use detach
+ */
+ unsubscribe: function() {
+ return this.detach.apply(this, arguments);
+ },
+
+ /**
+ * Removes all listeners from the specified event. If the event type
+ * is not specified, all listeners from all hosted custom events will
+ * be removed.
+ * @method detachAll
+ * @param type {string} The type, or name of the event
+ */
+ detachAll: function(type) {
+ return this.detach(type);
+ },
+
+ /**
+ * Removes all listeners from the specified event. If the event type
+ * is not specified, all listeners from all hosted custom events will
+ * be removed.
+ * @method unsubscribeAll
+ * @param type {string} The type, or name of the event
+ * @deprecated use detachAll
+ */
+ unsubscribeAll: function() {
+ return this.detachAll.apply(this, arguments);
+ },
+
+ /**
+ * Creates a new custom event of the specified type. If a custom event
+ * by that name already exists, it will not be re-created. In either
+ * case the custom event is returned.
+ *
+ * @method publish
+ *
+ * @param type {string} the type, or name of the event
+ * @param opts {object} optional config params. Valid properties are:
+ *
+ *
+ *
+ * 'broadcast': whether or not the YUI instance and YUI global are notified when the event is fired (false)
+ *
+ *
+ * 'bubbles': whether or not this event bubbles (true)
+ *
+ *
+ * 'context': the default execution context for the listeners (this)
+ *
+ *
+ * 'defaultFn': the default function to execute when this event fires if preventDefault was not called
+ *
+ *
+ * 'emitFacade': whether or not this event emits a facade (false)
+ *
+ *
+ * 'prefix': the prefix for this targets events, e.g., 'menu' in 'menu:click'
+ *
+ *
+ * 'fireOnce': if an event is configured to fire once, new subscribers after
+ * the fire will be notified immediately.
+ *
+ *
+ * 'preventable': whether or not preventDefault() has an effect (true)
+ *
+ *
+ * 'preventedFn': a function that is executed when preventDefault is called
+ *
+ *
+ * 'queuable': whether or not this event can be queued during bubbling (false)
+ *
+ *
+ * 'silent': if silent is true, debug messages are not provided for this event.
+ *
+ *
+ * 'stoppedFn': a function that is executed when stopPropagation is called
+ *
+ *
+ * 'type': the event type (valid option if not provided as the first parameter to publish)
+ *
+ *
+ *
+ * @return {Event.Custom} the custom event
+ *
+ */
+ publish: function(type, opts) {
+ var events, ce, ret, pre = this._yuievt.config.prefix;
+
+ type = (pre) ? _getType(type, pre) : type;
+
+
+ if (L.isObject(type)) {
+ ret = {};
+ Y.each(type, function(v, k) {
+ ret[k] = this.publish(k, v || opts);
+ }, this);
+
+ return ret;
+ }
+
+ events = this._yuievt.events;
+ ce = events[type];
+
+ if (ce) {
+// ce.log("publish applying new config to published event: '"+type+"' exists", 'info', 'event');
+ if (opts) {
+ ce.applyConfig(opts, true);
+ }
+ } else {
+ // apply defaults
+ ce = new Y.CustomEvent(type, (opts) ? Y.mix(opts, this._yuievt.defaults) : this._yuievt.defaults);
+ events[type] = ce;
+ }
+
+ // make sure we turn the broadcast flag off if this
+ // event was published as a result of bubbling
+ // if (opts instanceof Y.CustomEvent) {
+ // events[type].broadcast = false;
+ // }
+
+ return events[type];
+ },
+
+ /**
+ * Registers another EventTarget as a bubble target. Bubble order
+ * is determined by the order registered. Multiple targets can
+ * be specified.
+ * @method addTarget
+ * @param o {EventTarget} the target to add
+ */
+ addTarget: function(o) {
+ this._yuievt.targets[Y.stamp(o)] = o;
+ this._yuievt.hasTargets = true;
+ },
+
+ /**
+ * Removes a bubble target
+ * @method removeTarget
+ * @param o {EventTarget} the target to remove
+ */
+ removeTarget: function(o) {
+ delete this._yuievt.targets[Y.stamp(o)];
+ },
+
+ /**
+ * Fire a custom event by name. The callback functions will be executed
+ * from the context specified when the event was created, and with the
+ * following parameters.
+ *
+ * If the custom event object hasn't been created, then the event hasn't
+ * been published and it has no subscribers. For performance sake, we
+ * immediate exit in this case. This means the event won't bubble, so
+ * if the intention is that a bubble target be notified, the event must
+ * be published on this object first.
+ *
+ * The first argument is the event type, and any additional arguments are
+ * passed to the listeners as parameters. If the first of these is an
+ * object literal, and the event is configured to emit an event facade,
+ * that object is mixed into the event facade and the facade is provided
+ * in place of the original object.
+ *
+ * @method fire
+ * @param type {String|Object} The type of the event, or an object that contains
+ * a 'type' property.
+ * @param arguments {Object*} an arbitrary set of parameters to pass to
+ * the handler. If the first of these is an object literal and the event is
+ * configured to emit an event facade, the event facade will replace that
+ * parameter after the properties the object literal contains are copied to
+ * the event facade.
+ * @return {Event.Target} the event host
+ *
+ */
+ fire: function(type) {
+
+ var typeIncluded = L.isString(type),
+ t = (typeIncluded) ? type : (type && type.type),
+ ce, a, ret, pre=this._yuievt.config.prefix;
+
+ t = (pre) ? _getType(t, pre) : t;
+ ce = this.getEvent(t, true);
+
+ // this event has not been published or subscribed to
+ if (!ce) {
+
+ if (this._yuievt.hasTargets) {
+ a = (typeIncluded) ? arguments : Y.Array(arguments, 0, true).unshift(t);
+ return this.bubble(null, a, this);
+ }
+
+ // otherwise there is nothing to be done
+ ret = true;
+
+ } else {
+
+ a = Y.Array(arguments, (typeIncluded) ? 1 : 0, true);
+ ret = ce.fire.apply(ce, a);
+
+ // clear target for next fire()
+ ce.target = null;
+ }
+
+ return (this._yuievt.chain) ? this : ret;
+ },
+
+ /**
+ * Returns the custom event of the provided type has been created, a
+ * falsy value otherwise
+ * @method getEvent
+ * @param type {string} the type, or name of the event
+ * @param prefixed {string} if true, the type is prefixed already
+ * @return {Event.Custom} the custom event or null
+ */
+ getEvent: function(type, prefixed) {
+ var pre, e;
+ if (!prefixed) {
+ pre = this._yuievt.config.prefix;
+ type = (pre) ? _getType(type, pre) : type;
+ }
+ e = this._yuievt.events;
+ return (e && type in e) ? e[type] : null;
+ },
+
+ /**
+ * Subscribe to a custom event hosted by this object. The
+ * supplied callback will execute after any listeners add
+ * via the subscribe method, and after the default function,
+ * if configured for the event, has executed.
+ * @method after
+ * @param type {string} The type of the event
+ * @param fn {Function} The callback
+ * @return the event target or a detach handle per 'chain' config
+ */
+ after: function(type, fn) {
+
+ var a = Y.Array(arguments, 0, true);
+
+ switch (L.type(type)) {
+ case 'function':
+ return Y.Do.after.apply(Y.Do, arguments);
+ case 'object':
+ a[0]._after = true;
+ break;
+ default:
+ a[0] = AFTER_PREFIX + type;
+ }
+
+ return this.on.apply(this, a);
+
+ },
+
+ /**
+ * Executes the callback before a DOM event, custom event
+ * or method. If the first argument is a function, it
+ * is assumed the target is a method. For DOM and custom
+ * events, this is an alias for Y.on.
+ *
+ * For DOM and custom events:
+ * type, callback, context, 0-n arguments
+ *
+ * For methods:
+ * callback, object (method host), methodName, context, 0-n arguments
+ *
+ * @method before
+ * @return detach handle
+ * @deprecated use the on method
+ */
+ before: function() {
+ return this.on.apply(this, arguments);
+ }
+
+};
+
+Y.EventTarget = ET;
+
+// make Y an event target
+Y.mix(Y, ET.prototype, false, false, {
+ bubbles: false
+});
+
+ET.call(Y);
+
+YUI.Env.globalEvents = YUI.Env.globalEvents || new ET();
+
+/**
+ * Hosts YUI page level events. This is where events bubble to
+ * when the broadcast config is set to 2. This property is
+ * only available if the custom event module is loaded.
+ * @property Global
+ * @type EventTarget
+ * @for YUI
+ */
+Y.Global = YUI.Env.globalEvents;
+
+// @TODO implement a global namespace function on Y.Global?
+
+})();
+
+
+/**
+ * YUI's on method is a unified interface for subscribing to
+ * most events exposed by YUI. This includes custom events, DOM events, and
+ * function events. detach is also provided to remove listeners
+ * serviced by this function.
+ *
+ * The signature that on accepts varies depending on the type
+ * of event being consumed. Refer to the specific methods that will
+ * service a specific request for additional information about subscribing
+ * to that type of event.
+ *
+ *
+ *
Custom events. These events are defined by various
+ * modules in the library. This type of event is delegated to
+ * EventTarget's on method.
+ *
DOM events. These are moments reported by the browser related
+ * to browser functionality and user interaction.
+ * This type of event is delegated to Event's
+ * attach method.
+ *
+ *
The type of the event
+ *
The callback to execute
+ *
The specification for the Node(s) to attach the listener
+ * to. This can be a selector, collections, or Node/Element
+ * refereces.
Function events. These events can be used to react before or after a
+ * function is executed. This type of event is delegated to Event.Do's
+ * before method.
+ *
+ *
The callback to execute
+ *
The object that has the function that will be listened for.
+ *
The name of the function to listen for.
+ *
An optional context object
+ *
0..n additional arguments to supply the callback.
+ *
+ * Example Y.on(function(arg1, arg2, etc) { // obj.methodname was executed }, obj 'methodname');
+ *
+ *
+ *
+ * on corresponds to the moment before any default behavior of
+ * the event. after works the same way, but these listeners
+ * execute after the event's default behavior. before is an
+ * alias for on.
+ *
+ * @method on
+ * @param type** event type (this parameter does not apply for function events)
+ * @param fn the callback
+ * @param target** a descriptor for the target (applies to custom events only).
+ * For function events, this is the object that contains the function to
+ * execute.
+ * @param extra** 0..n Extra information a particular event may need. These
+ * will be documented with the event. In the case of function events, this
+ * is the name of the function to execute on the host. In the case of
+ * delegate listeners, this is the event delegation specification.
+ * @param context optionally change the value of 'this' in the callback
+ * @param args* 0..n additional arguments to pass to the callback.
+ * @return the event target or a detach handle per 'chain' config
+ * @for YUI
+ */
+
+/**
+ * after() is a unified interface for subscribing to
+ * most events exposed by YUI. This includes custom events,
+ * DOM events, and AOP events. This works the same way as
+ * the on() function, only it operates after any default
+ * behavior for the event has executed. @see on for more
+ * information.
+ * @method after
+ * @param type event type (this parameter does not apply for function events)
+ * @param fn the callback
+ * @param target a descriptor for the target (applies to custom events only).
+ * For function events, this is the object that contains the function to
+ * execute.
+ * @param extra 0..n Extra information a particular event may need. These
+ * will be documented with the event. In the case of function events, this
+ * is the name of the function to execute on the host. In the case of
+ * delegate listeners, this is the event delegation specification.
+ * @param context optionally change the value of 'this' in the callback
+ * @param args* 0..n additional arguments to pass to the callback.
+ * @return the event target or a detach handle per 'chain' config
+ * @for YUI
+ */
+
+
+}, '3.0.0' ,{requires:['oop']});
+YUI.add('event-custom-complex', function(Y) {
+
+
+/**
+ * Adds event facades, preventable default behavior, and bubbling.
+ * events.
+ * @module event-custom
+ * @submodule event-custom-complex
+ */
+
+(function() {
+
+var FACADE, FACADE_KEYS, CEProto = Y.CustomEvent.prototype;
+
+/**
+ * Wraps and protects a custom event for use when emitFacade is set to true.
+ * Requires the event-custom-complex module
+ * @class EventFacade
+ * @param e {Event} the custom event
+ * @param currentTarget {HTMLElement} the element the listener was attached to
+ */
+
+Y.EventFacade = function(e, currentTarget) {
+
+ e = e || {};
+
+ /**
+ * The arguments passed to fire
+ * @property details
+ * @type Array
+ */
+ this.details = e.details;
+
+ /**
+ * The event type
+ * @property type
+ * @type string
+ */
+ this.type = e.type;
+
+ //////////////////////////////////////////////////////
+
+ /**
+ * Node reference for the targeted eventtarget
+ * @propery target
+ * @type Node
+ */
+ this.target = e.target;
+
+ /**
+ * Node reference for the element that the listener was attached to.
+ * @propery currentTarget
+ * @type Node
+ */
+ this.currentTarget = currentTarget;
+
+ /**
+ * Node reference to the relatedTarget
+ * @propery relatedTarget
+ * @type Node
+ */
+ this.relatedTarget = e.relatedTarget;
+
+ /**
+ * Stops the propagation to the next bubble target
+ * @method stopPropagation
+ */
+ this.stopPropagation = function() {
+ e.stopPropagation();
+ };
+
+ /**
+ * Stops the propagation to the next bubble target and
+ * prevents any additional listeners from being exectued
+ * on the current target.
+ * @method stopImmediatePropagation
+ */
+ this.stopImmediatePropagation = function() {
+ e.stopImmediatePropagation();
+ };
+
+ /**
+ * Prevents the event's default behavior
+ * @method preventDefault
+ */
+ this.preventDefault = function() {
+ e.preventDefault();
+ };
+
+ /**
+ * Stops the event propagation and prevents the default
+ * event behavior.
+ * @method halt
+ * @param immediate {boolean} if true additional listeners
+ * on the current target will not be executed
+ */
+ this.halt = function(immediate) {
+ e.halt(immediate);
+ };
+
+};
+
+CEProto.fireComplex = function(args) {
+ var es = Y.Env._eventstack, ef, q, queue, ce, ret, events;
+
+ if (es) {
+ // queue this event if the current item in the queue bubbles
+ if (this.queuable && this.type != es.next.type) {
+ this.log('queue ' + this.type);
+ es.queue.push([this, args]);
+ return true;
+ }
+ } else {
+ Y.Env._eventstack = {
+ // id of the first event in the stack
+ id: this.id,
+ next: this,
+ silent: this.silent,
+ stopped: 0,
+ prevented: 0,
+ queue: []
+ };
+ es = Y.Env._eventstack;
+ }
+
+ this.stopped = 0;
+ this.prevented = 0;
+ this.target = this.target || this.host;
+
+ events = new Y.EventTarget({
+ fireOnce: true,
+ context: this.host
+ });
+
+ this.events = events;
+
+ if (this.preventedFn) {
+ events.on('prevented', this.preventedFn);
+ }
+
+ if (this.stoppedFn) {
+ events.on('stopped', this.stoppedFn);
+ }
+
+ this.currentTarget = this.host || this.currentTarget;
+
+ this.details = args.slice(); // original arguments in the details
+
+ // this.log("Firing " + this + ", " + "args: " + args);
+ this.log("Firing " + this.type);
+
+ this._facade = null; // kill facade to eliminate stale properties
+
+ ef = this._getFacade(args);
+
+ if (Y.Lang.isObject(args[0])) {
+ args[0] = ef;
+ } else {
+ args.unshift(ef);
+ }
+
+ if (this.hasSubscribers) {
+ this._procSubs(Y.merge(this.subscribers), args, ef);
+ }
+
+ // bubble if this is hosted in an event target and propagation has not been stopped
+ if (this.bubbles && this.host && this.host.bubble && !this.stopped) {
+ es.stopped = 0;
+ es.prevented = 0;
+ ret = this.host.bubble(this);
+
+ this.stopped = Math.max(this.stopped, es.stopped);
+ this.prevented = Math.max(this.prevented, es.prevented);
+
+ }
+
+ // execute the default behavior if not prevented
+ if (this.defaultFn && !this.prevented) {
+ this.defaultFn.apply(this.host || this, args);
+ }
+
+ // broadcast listeners are fired as discreet events on the
+ // YUI instance and potentially the YUI global.
+ this._broadcast(args);
+
+ // process after listeners. If the default behavior was
+ // prevented, the after events don't fire.
+ if (this.hasAfters && !this.prevented && this.stopped < 2) {
+ this._procSubs(Y.merge(this.afters), args, ef);
+ }
+
+ if (es.id === this.id) {
+ queue = es.queue;
+
+ while (queue.length) {
+ q = queue.pop();
+ ce = q[0];
+ es.stopped = 0;
+ es.prevented = 0;
+ // set up stack to allow the next item to be processed
+ es.next = ce;
+ ce.fire.apply(ce, q[1]);
+ }
+
+ Y.Env._eventstack = null;
+ }
+
+ return this.stopped ? false : true;
+};
+
+CEProto._getFacade = function() {
+
+ var ef = this._facade, o, o2,
+ args = this.details;
+
+ if (!ef) {
+ ef = new Y.EventFacade(this, this.currentTarget);
+ }
+
+ // if the first argument is an object literal, apply the
+ // properties to the event facade
+ o = args && args[0];
+
+ if (Y.Lang.isObject(o, true)) {
+
+ o2 = {};
+
+ // protect the event facade properties
+ Y.mix(o2, ef, true, FACADE_KEYS);
+
+ // mix the data
+ Y.mix(ef, o, true);
+
+ // restore ef
+ Y.mix(ef, o2, true, FACADE_KEYS);
+ }
+
+ // update the details field with the arguments
+ // ef.type = this.type;
+ ef.details = this.details;
+ ef.target = this.target;
+ ef.currentTarget = this.currentTarget;
+ ef.stopped = 0;
+ ef.prevented = 0;
+
+ this._facade = ef;
+
+ return this._facade;
+};
+
+/**
+ * Stop propagation to bubble targets
+ * @for CustomEvent
+ * @method stopPropagation
+ */
+CEProto.stopPropagation = function() {
+ this.stopped = 1;
+ Y.Env._eventstack.stopped = 1;
+ this.events.fire('stopped', this);
+};
+
+/**
+ * Stops propagation to bubble targets, and prevents any remaining
+ * subscribers on the current target from executing.
+ * @method stopImmediatePropagation
+ */
+CEProto.stopImmediatePropagation = function() {
+ this.stopped = 2;
+ Y.Env._eventstack.stopped = 2;
+ this.events.fire('stopped', this);
+};
+
+/**
+ * Prevents the execution of this event's defaultFn
+ * @method preventDefault
+ */
+CEProto.preventDefault = function() {
+ if (this.preventable) {
+ this.prevented = 1;
+ Y.Env._eventstack.prevented = 1;
+ this.events.fire('prevented', this);
+ }
+};
+
+/**
+ * Stops the event propagation and prevents the default
+ * event behavior.
+ * @method halt
+ * @param immediate {boolean} if true additional listeners
+ * on the current target will not be executed
+ */
+CEProto.halt = function(immediate) {
+ if (immediate) {
+ this.stopImmediatePropagation();
+ } else {
+ this.stopPropagation();
+ }
+ this.preventDefault();
+};
+
+/**
+ * Propagate an event. Requires the event-custom-complex module.
+ * @method bubble
+ * @param evt {Event.Custom} the custom event to propagate
+ * @return {boolean} the aggregated return value from Event.Custom.fire
+ * @for EventTarget
+ */
+Y.EventTarget.prototype.bubble = function(evt, args, target) {
+
+ var targs = this._yuievt.targets, ret = true,
+ t, type, ce, i, bc;
+
+ if (!evt || ((!evt.stopped) && targs)) {
+
+ // Y.log('Bubbling ' + evt.type);
+ for (i in targs) {
+ if (targs.hasOwnProperty(i)) {
+ t = targs[i];
+ type = evt && evt.type;
+ ce = t.getEvent(type, true);
+
+ // if this event was not published on the bubble target,
+ // publish it with sensible default properties
+ if (!ce) {
+
+ if (t._yuievt.hasTargets) {
+ t.bubble.call(t, evt, args, target);
+ }
+
+ } else {
+ ce.target = target || (evt && evt.target) || this;
+ ce.currentTarget = t;
+
+ bc = ce.broadcast;
+ ce.broadcast = false;
+ ret = ret && ce.fire.apply(ce, args || evt.details);
+ ce.broadcast = bc;
+
+ // stopPropagation() was called
+ if (ce.stopped) {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return ret;
+};
+
+FACADE = new Y.EventFacade();
+FACADE_KEYS = Y.Object.keys(FACADE);
+
+})();
+
+
+}, '3.0.0' ,{requires:['event-custom-base']});
+
+
+YUI.add('event-custom', function(Y){}, '3.0.0' ,{use:['event-custom-base', 'event-custom-complex']});
+
diff --git a/lib/yui/3.0.0/event-custom/event-custom-min.js b/lib/yui/3.0.0/event-custom/event-custom-min.js
new file mode 100644
index 0000000000..f3e1bda5b8
--- /dev/null
+++ b/lib/yui/3.0.0/event-custom/event-custom-min.js
@@ -0,0 +1,10 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("event-custom-base",function(E){E.Env.evt={handles:{},plugins:{}};(function(){var F=0,G=1;E.Do={objs:{},before:function(I,K,L,M){var J=I,H;if(M){H=[I,M].concat(E.Array(arguments,4,true));J=E.rbind.apply(E,H);}return this._inject(F,J,K,L);},after:function(I,K,L,M){var J=I,H;if(M){H=[I,M].concat(E.Array(arguments,4,true));J=E.rbind.apply(E,H);}return this._inject(G,J,K,L);},_inject:function(H,J,K,M){var N=E.stamp(K),L,I;if(!this.objs[N]){this.objs[N]={};}L=this.objs[N];if(!L[M]){L[M]=new E.Do.Method(K,M);K[M]=function(){return L[M].exec.apply(L[M],arguments);};}I=N+E.stamp(J)+M;L[M].register(I,J,H);return new E.EventHandle(L[M],I);},detach:function(H){if(H.detach){H.detach();}},_unload:function(I,H){}};E.Do.Method=function(H,I){this.obj=H;this.methodName=I;this.method=H[I];this.before={};this.after={};};E.Do.Method.prototype.register=function(I,J,H){if(H){this.after[I]=J;}else{this.before[I]=J;}};E.Do.Method.prototype._delete=function(H){delete this.before[H];delete this.after[H];};E.Do.Method.prototype.exec=function(){var J=E.Array(arguments,0,true),K,I,N,L=this.before,H=this.after,M=false;for(K in L){if(L.hasOwnProperty(K)){I=L[K].apply(this.obj,J);if(I){switch(I.constructor){case E.Do.Halt:return I.retVal;case E.Do.AlterArgs:J=I.newArgs;break;case E.Do.Prevent:M=true;break;default:}}}}if(!M){I=this.method.apply(this.obj,J);}for(K in H){if(H.hasOwnProperty(K)){N=H[K].apply(this.obj,J);if(N&&N.constructor==E.Do.Halt){return N.retVal;}else{if(N&&N.constructor==E.Do.AlterReturn){I=N.newRetVal;}}}}return I;};E.Do.AlterArgs=function(I,H){this.msg=I;this.newArgs=H;};E.Do.AlterReturn=function(I,H){this.msg=I;this.newRetVal=H;};E.Do.Halt=function(I,H){this.msg=I;this.retVal=H;};E.Do.Prevent=function(H){this.msg=H;};E.Do.Error=E.Do.Halt;})();var D="after",B=["broadcast","bubbles","context","contextFn","currentTarget","defaultFn","details","emitFacade","fireOnce","host","preventable","preventedFn","queuable","silent","stoppedFn","target","type"],C=9,A="yui:log";E.EventHandle=function(F,G){this.evt=F;this.sub=G;};E.EventHandle.prototype={detach:function(){var F=this.evt,G;if(F){if(E.Lang.isArray(F)){for(G=0;G2)?E.Array(arguments,2,true):null;return this._on(H,G,F,true);},on:function(H,G){var F=(arguments.length>2)?E.Array(arguments,2,true):null;return this._on(H,G,F,true);},after:function(H,G){var F=(arguments.length>2)?E.Array(arguments,2,true):null;return this._on(H,G,F,D);},detach:function(J,H){if(J&&J.detach){return J.detach();}var K=0,G=this.subscribers,F,I;for(F in G){if(G.hasOwnProperty(F)){I=G[F];if(I&&(!J||J===I.fn)){this._delete(I);K++;}}}return K;},unsubscribe:function(){return this.detach.apply(this,arguments);},_notify:function(I,H,F){this.log(this.type+"->"+"sub: "+I.id);var G;G=I.notify(H,this);if(false===G||this.stopped>1){this.log(this.type+" cancelled by subscriber");return false;}return true;},log:function(G,F){if(!this.silent){}},fire:function(){if(this.fireOnce&&this.fired){this.log("fireOnce event: "+this.type+" already fired");return true;}else{var F=E.Array(arguments,0,true);this.fired=true;this.firedWith=F;if(this.emitFacade){return this.fireComplex(F);}else{return this.fireSimple(F);}}},fireSimple:function(F){if(this.hasSubscribers||this.hasAfters){this._procSubs(E.merge(this.subscribers,this.afters),F);}this._broadcast(F);return this.stopped?false:true;},fireComplex:function(F){F[0]=F[0]||{};return this.fireSimple(F);},_procSubs:function(I,G,F){var J,H;for(H in I){if(I.hasOwnProperty(H)){J=I[H];if(J&&J.fn){if(false===this._notify(J,G,F)){this.stopped=2;}if(this.stopped==2){return false;}}}}return true;},_broadcast:function(G){if(!this.stopped&&this.broadcast){var F=E.Array(G);F.unshift(this.type);if(this.host!==E){E.fire.apply(E,F);}if(this.broadcast==2){E.Global.fire.apply(E.Global,F);}}},unsubscribeAll:function(){return this.detachAll.apply(this,arguments);},detachAll:function(){return this.detach();},_delete:function(F){if(F){delete F.fn;delete F.context;delete this.subscribers[F.id];delete this.afters[F.id];}}};E.Subscriber=function(H,G,F){this.fn=H;this.context=G;this.id=E.stamp(this);this.args=F;this.events=null;};E.Subscriber.prototype={_notify:function(J,H,I){var F=this.args,G;switch(I.signature){case 0:G=this.fn.call(J,I.type,H,J);break;case 1:G=this.fn.call(J,H[0]||null,J);break;default:if(F||H){H=H||[];F=(F)?H.concat(F):H;G=this.fn.apply(J,F);}else{G=this.fn.call(J);}}return G;},notify:function(G,I){var J=this.context,F=true;if(!J){J=(I.contextFn)?I.contextFn():I.context;}if(E.config.throwFail){F=this._notify(J,G,I);}else{try{F=this._notify(J,G,I);}catch(H){E.error(this+" failed: "+H.message,H);}}return F;},contains:function(G,F){if(F){return((this.fn==G)&&this.context==F);}else{return(this.fn==G);}}};(function(){var F=E.Lang,H=":",I="|",J="~AFTER~",K=E.cached(function(L,N){if(!N||!F.isString(L)||L.indexOf(H)>-1){return L;}return N+H+L;}),G=E.cached(function(O,Q){var N=O,P,R,L;if(!F.isString(N)){return N;}L=N.indexOf(J);if(L>-1){R=true;N=N.substr(J.length);}L=N.indexOf(I);if(L>-1){P=N.substr(0,(L));N=N.substr(L+1);if(N=="*"){N=null;}}return[P,(Q)?K(N,Q):N,R,N];}),M=function(L){var N=(F.isObject(L))?L:{};this._yuievt=this._yuievt||{id:E.guid(),events:{},targets:{},config:N,chain:("chain" in N)?N.chain:E.config.chain,defaults:{context:N.context||this,host:this,emitFacade:N.emitFacade,fireOnce:N.fireOnce,queuable:N.queuable,broadcast:N.broadcast,bubbles:("bubbles" in N)?N.bubbles:true}};
+};M.prototype={on:function(Q,U,O,V){var Z=G(Q,this._yuievt.config.prefix),a,b,N,g,X,W,d,R=E.Env.evt.handles,P,L,S,e=E.Node,Y,T;if(F.isObject(Q)){if(F.isFunction(Q)){return E.Do.before.apply(E.Do,arguments);}a=U;b=O;N=E.Array(arguments,0,true);g={};P=Q._after;delete Q._after;E.each(Q,function(f,c){if(f){a=f.fn||((E.Lang.isFunction(f))?f:a);b=f.context||b;}N[0]=(P)?J+c:c;N[1]=a;N[2]=b;g[c]=this.on.apply(this,N);},this);return(this._yuievt.chain)?this:new E.EventHandle(g);}W=Z[0];P=Z[2];S=Z[3];if(e&&(this instanceof e)&&(S in e.DOM_EVENTS)){N=E.Array(arguments,0,true);N.splice(2,0,e.getDOMNode(this));return E.on.apply(E,N);}Q=Z[1];if(this instanceof YUI){L=E.Env.evt.plugins[Q];N=E.Array(arguments,0,true);N[0]=S;if(e){Y=N[2];if(Y instanceof E.NodeList){Y=E.NodeList.getDOMNodes(Y);}else{if(Y instanceof e){Y=e.getDOMNode(Y);}}T=(S in e.DOM_EVENTS);if(T){N[2]=Y;}}if(L){d=L.on.apply(E,N);}else{if((!Q)||T){d=E.Event._attach(N);}}}if(!d){X=this._yuievt.events[Q]||this.publish(Q);d=X._on(U,O,(arguments.length>3)?E.Array(arguments,3,true):null,(P)?"after":true);}if(W){R[W]=R[W]||{};R[W][Q]=R[W][Q]||[];R[W][Q].push(d);}return(this._yuievt.chain)?this:d;},subscribe:function(){return this.on.apply(this,arguments);},detach:function(P,U,O){var T=this._yuievt.events,Z,d,c=E.Node,Y=(this instanceof c);if(!P&&(this!==E)){for(Z in T){if(T.hasOwnProperty(Z)){d=T[Z].detach(U,O);}}if(Y){E.Event.purgeElement(c.getDOMNode(this));}return d;}var X=G(P,this._yuievt.config.prefix),V=F.isArray(X)?X[0]:null,R=(X)?X[3]:null,b,L,Q=E.Env.evt.handles,S,N,W,a=function(g,f){var e=g[f];if(e){while(e.length){b=e.pop();b.detach();}}};if(V){S=Q[V];P=X[1];if(S){if(P){a(S,P);}else{for(Z in S){if(S.hasOwnProperty(Z)){a(S,Z);}}}return(this._yuievt.chain)?this:true;}}else{if(F.isObject(P)&&P.detach){d=P.detach();return(this._yuievt.chain)?this:d;}else{if(Y&&((!R)||(R in c.DOM_EVENTS))){N=E.Array(arguments,0,true);N[2]=c.getDOMNode(this);return E.detach.apply(E,N);}}}L=E.Env.evt.plugins[R];if(this instanceof YUI){N=E.Array(arguments,0,true);if(L&&L.detach){return L.detach.apply(E,N);}else{if(!P||(!L&&c&&(P in c.DOM_EVENTS))){N[0]=P;return E.Event.detach.apply(E.Event,N);}}}W=T[P];if(W){d=W.detach(U,O);}return(this._yuievt.chain)?this:d;},unsubscribe:function(){return this.detach.apply(this,arguments);},detachAll:function(L){return this.detach(L);},unsubscribeAll:function(){return this.detachAll.apply(this,arguments);},publish:function(O,P){var N,R,L,Q=this._yuievt.config.prefix;O=(Q)?K(O,Q):O;if(F.isObject(O)){L={};E.each(O,function(T,S){L[S]=this.publish(S,T||P);},this);return L;}N=this._yuievt.events;R=N[O];if(R){if(P){R.applyConfig(P,true);}}else{R=new E.CustomEvent(O,(P)?E.mix(P,this._yuievt.defaults):this._yuievt.defaults);N[O]=R;}return N[O];},addTarget:function(L){this._yuievt.targets[E.stamp(L)]=L;this._yuievt.hasTargets=true;},removeTarget:function(L){delete this._yuievt.targets[E.stamp(L)];},fire:function(P){var S=F.isString(P),O=(S)?P:(P&&P.type),R,L,N,Q=this._yuievt.config.prefix;O=(Q)?K(O,Q):O;R=this.getEvent(O,true);if(!R){if(this._yuievt.hasTargets){L=(S)?arguments:E.Array(arguments,0,true).unshift(O);return this.bubble(null,L,this);}N=true;}else{L=E.Array(arguments,(S)?1:0,true);N=R.fire.apply(R,L);R.target=null;}return(this._yuievt.chain)?this:N;},getEvent:function(N,L){var P,O;if(!L){P=this._yuievt.config.prefix;N=(P)?K(N,P):N;}O=this._yuievt.events;return(O&&N in O)?O[N]:null;},after:function(O,N){var L=E.Array(arguments,0,true);switch(F.type(O)){case"function":return E.Do.after.apply(E.Do,arguments);case"object":L[0]._after=true;break;default:L[0]=J+O;}return this.on.apply(this,L);},before:function(){return this.on.apply(this,arguments);}};E.EventTarget=M;E.mix(E,M.prototype,false,false,{bubbles:false});M.call(E);YUI.Env.globalEvents=YUI.Env.globalEvents||new M();E.Global=YUI.Env.globalEvents;})();},"3.0.0",{requires:["oop"]});YUI.add("event-custom-complex",function(A){(function(){var C,D,B=A.CustomEvent.prototype;A.EventFacade=function(F,E){F=F||{};this.details=F.details;this.type=F.type;this.target=F.target;this.currentTarget=E;this.relatedTarget=F.relatedTarget;this.stopPropagation=function(){F.stopPropagation();};this.stopImmediatePropagation=function(){F.stopImmediatePropagation();};this.preventDefault=function(){F.preventDefault();};this.halt=function(G){F.halt(G);};};B.fireComplex=function(H){var L=A.Env._eventstack,F,J,E,K,G,I;if(L){if(this.queuable&&this.type!=L.next.type){this.log("queue "+this.type);L.queue.push([this,H]);return true;}}else{A.Env._eventstack={id:this.id,next:this,silent:this.silent,stopped:0,prevented:0,queue:[]};L=A.Env._eventstack;}this.stopped=0;this.prevented=0;this.target=this.target||this.host;I=new A.EventTarget({fireOnce:true,context:this.host});this.events=I;if(this.preventedFn){I.on("prevented",this.preventedFn);}if(this.stoppedFn){I.on("stopped",this.stoppedFn);}this.currentTarget=this.host||this.currentTarget;this.details=H.slice();this.log("Firing "+this.type);this._facade=null;F=this._getFacade(H);if(A.Lang.isObject(H[0])){H[0]=F;}else{H.unshift(F);}if(this.hasSubscribers){this._procSubs(A.merge(this.subscribers),H,F);}if(this.bubbles&&this.host&&this.host.bubble&&!this.stopped){L.stopped=0;L.prevented=0;G=this.host.bubble(this);this.stopped=Math.max(this.stopped,L.stopped);this.prevented=Math.max(this.prevented,L.prevented);}if(this.defaultFn&&!this.prevented){this.defaultFn.apply(this.host||this,H);}this._broadcast(H);if(this.hasAfters&&!this.prevented&&this.stopped<2){this._procSubs(A.merge(this.afters),H,F);}if(L.id===this.id){E=L.queue;while(E.length){J=E.pop();K=J[0];L.stopped=0;L.prevented=0;L.next=K;K.fire.apply(K,J[1]);}A.Env._eventstack=null;}return this.stopped?false:true;};B._getFacade=function(){var E=this._facade,H,G,F=this.details;if(!E){E=new A.EventFacade(this,this.currentTarget);}H=F&&F[0];if(A.Lang.isObject(H,true)){G={};A.mix(G,E,true,D);A.mix(E,H,true);A.mix(E,G,true,D);}E.details=this.details;E.target=this.target;E.currentTarget=this.currentTarget;E.stopped=0;
+E.prevented=0;this._facade=E;return this._facade;};B.stopPropagation=function(){this.stopped=1;A.Env._eventstack.stopped=1;this.events.fire("stopped",this);};B.stopImmediatePropagation=function(){this.stopped=2;A.Env._eventstack.stopped=2;this.events.fire("stopped",this);};B.preventDefault=function(){if(this.preventable){this.prevented=1;A.Env._eventstack.prevented=1;this.events.fire("prevented",this);}};B.halt=function(E){if(E){this.stopImmediatePropagation();}else{this.stopPropagation();}this.preventDefault();};A.EventTarget.prototype.bubble=function(M,K,I){var G=this._yuievt.targets,J=true,N,L,E,F,H;if(!M||((!M.stopped)&&G)){for(F in G){if(G.hasOwnProperty(F)){N=G[F];L=M&&M.type;E=N.getEvent(L,true);if(!E){if(N._yuievt.hasTargets){N.bubble.call(N,M,K,I);}}else{E.target=I||(M&&M.target)||this;E.currentTarget=N;H=E.broadcast;E.broadcast=false;J=J&&E.fire.apply(E,K||M.details);E.broadcast=H;if(E.stopped){break;}}}}}return J;};C=new A.EventFacade();D=A.Object.keys(C);})();},"3.0.0",{requires:["event-custom-base"]});YUI.add("event-custom",function(A){},"3.0.0",{use:["event-custom-base","event-custom-complex"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/event-custom/event-custom.js b/lib/yui/3.0.0/event-custom/event-custom.js
new file mode 100644
index 0000000000..997a85d2a1
--- /dev/null
+++ b/lib/yui/3.0.0/event-custom/event-custom.js
@@ -0,0 +1,2082 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('event-custom-base', function(Y) {
+
+/**
+ * Custom event engine, DOM event listener abstraction layer, synthetic DOM
+ * events.
+ * @module event-custom
+ */
+
+Y.Env.evt = {
+ handles: {},
+ plugins: {}
+};
+
+
+/**
+ * Custom event engine, DOM event listener abstraction layer, synthetic DOM
+ * events.
+ * @module event-custom
+ * @submodule event-custom-base
+ */
+(function() {
+
+/**
+ * Allows for the insertion of methods that are executed before or after
+ * a specified method
+ * @class Do
+ * @static
+ */
+
+var BEFORE = 0,
+ AFTER = 1;
+
+Y.Do = {
+
+ /**
+ * Cache of objects touched by the utility
+ * @property objs
+ * @static
+ */
+ objs: {},
+
+ /**
+ * Execute the supplied method before the specified function
+ * @method before
+ * @param fn {Function} the function to execute
+ * @param obj the object hosting the method to displace
+ * @param sFn {string} the name of the method to displace
+ * @param c The execution context for fn
+ * @return {string} handle for the subscription
+ * @static
+ */
+ before: function(fn, obj, sFn, c) {
+ var f = fn, a;
+ if (c) {
+ a = [fn, c].concat(Y.Array(arguments, 4, true));
+ f = Y.rbind.apply(Y, a);
+ }
+
+ return this._inject(BEFORE, f, obj, sFn);
+ },
+
+ /**
+ * Execute the supplied method after the specified function
+ * @method after
+ * @param fn {Function} the function to execute
+ * @param obj the object hosting the method to displace
+ * @param sFn {string} the name of the method to displace
+ * @param c The execution context for fn
+ * @return {string} handle for the subscription
+ * @static
+ */
+ after: function(fn, obj, sFn, c) {
+ var f = fn, a;
+ if (c) {
+ a = [fn, c].concat(Y.Array(arguments, 4, true));
+ f = Y.rbind.apply(Y, a);
+ }
+
+ return this._inject(AFTER, f, obj, sFn);
+ },
+
+ /**
+ * Execute the supplied method after the specified function
+ * @method _inject
+ * @param when {string} before or after
+ * @param fn {Function} the function to execute
+ * @param obj the object hosting the method to displace
+ * @param sFn {string} the name of the method to displace
+ * @param c The execution context for fn
+ * @return {string} handle for the subscription
+ * @private
+ * @static
+ */
+ _inject: function(when, fn, obj, sFn) {
+
+ // object id
+ var id = Y.stamp(obj), o, sid;
+
+ if (! this.objs[id]) {
+ // create a map entry for the obj if it doesn't exist
+ this.objs[id] = {};
+ }
+
+ o = this.objs[id];
+
+ if (! o[sFn]) {
+ // create a map entry for the method if it doesn't exist
+ o[sFn] = new Y.Do.Method(obj, sFn);
+
+ // re-route the method to our wrapper
+ obj[sFn] =
+ function() {
+ return o[sFn].exec.apply(o[sFn], arguments);
+ };
+ }
+
+ // subscriber id
+ sid = id + Y.stamp(fn) + sFn;
+
+ // register the callback
+ o[sFn].register(sid, fn, when);
+
+ return new Y.EventHandle(o[sFn], sid);
+
+ },
+
+ /**
+ * Detach a before or after subscription
+ * @method detach
+ * @param handle {string} the subscription handle
+ */
+ detach: function(handle) {
+
+ if (handle.detach) {
+ handle.detach();
+ }
+
+ },
+
+ _unload: function(e, me) {
+
+ }
+};
+
+//////////////////////////////////////////////////////////////////////////
+
+/**
+ * Wrapper for a displaced method with aop enabled
+ * @class Do.Method
+ * @constructor
+ * @param obj The object to operate on
+ * @param sFn The name of the method to displace
+ */
+Y.Do.Method = function(obj, sFn) {
+ this.obj = obj;
+ this.methodName = sFn;
+ this.method = obj[sFn];
+ this.before = {};
+ this.after = {};
+};
+
+/**
+ * Register a aop subscriber
+ * @method register
+ * @param sid {string} the subscriber id
+ * @param fn {Function} the function to execute
+ * @param when {string} when to execute the function
+ */
+Y.Do.Method.prototype.register = function (sid, fn, when) {
+ if (when) {
+ this.after[sid] = fn;
+ } else {
+ this.before[sid] = fn;
+ }
+};
+
+/**
+ * Unregister a aop subscriber
+ * @method delete
+ * @param sid {string} the subscriber id
+ * @param fn {Function} the function to execute
+ * @param when {string} when to execute the function
+ */
+Y.Do.Method.prototype._delete = function (sid) {
+ delete this.before[sid];
+ delete this.after[sid];
+};
+
+/**
+ * Execute the wrapped method
+ * @method exec
+ */
+Y.Do.Method.prototype.exec = function () {
+
+ var args = Y.Array(arguments, 0, true),
+ i, ret, newRet,
+ bf = this.before,
+ af = this.after,
+ prevented = false;
+
+ // execute before
+ for (i in bf) {
+ if (bf.hasOwnProperty(i)) {
+ ret = bf[i].apply(this.obj, args);
+ if (ret) {
+ switch (ret.constructor) {
+ case Y.Do.Halt:
+ return ret.retVal;
+ case Y.Do.AlterArgs:
+ args = ret.newArgs;
+ break;
+ case Y.Do.Prevent:
+ prevented = true;
+ break;
+ default:
+ }
+ }
+ }
+ }
+
+ // execute method
+ if (!prevented) {
+ ret = this.method.apply(this.obj, args);
+ }
+
+ // execute after methods.
+ for (i in af) {
+ if (af.hasOwnProperty(i)) {
+ newRet = af[i].apply(this.obj, args);
+ // Stop processing if a Halt object is returned
+ if (newRet && newRet.constructor == Y.Do.Halt) {
+ return newRet.retVal;
+ // Check for a new return value
+ } else if (newRet && newRet.constructor == Y.Do.AlterReturn) {
+ ret = newRet.newRetVal;
+ }
+ }
+ }
+
+ return ret;
+};
+
+//////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * Return an AlterArgs object when you want to change the arguments that
+ * were passed into the function. An example would be a service that scrubs
+ * out illegal characters prior to executing the core business logic.
+ * @class Do.AlterArgs
+ */
+Y.Do.AlterArgs = function(msg, newArgs) {
+ this.msg = msg;
+ this.newArgs = newArgs;
+};
+
+/**
+ * Return an AlterReturn object when you want to change the result returned
+ * from the core method to the caller
+ * @class Do.AlterReturn
+ */
+Y.Do.AlterReturn = function(msg, newRetVal) {
+ this.msg = msg;
+ this.newRetVal = newRetVal;
+};
+
+/**
+ * Return a Halt object when you want to terminate the execution
+ * of all subsequent subscribers as well as the wrapped method
+ * if it has not exectued yet.
+ * @class Do.Halt
+ */
+Y.Do.Halt = function(msg, retVal) {
+ this.msg = msg;
+ this.retVal = retVal;
+};
+
+/**
+ * Return a Prevent object when you want to prevent the wrapped function
+ * from executing, but want the remaining listeners to execute
+ * @class Do.Prevent
+ */
+Y.Do.Prevent = function(msg) {
+ this.msg = msg;
+};
+
+/**
+ * Return an Error object when you want to terminate the execution
+ * of all subsequent method calls.
+ * @class Do.Error
+ * @deprecated use Y.Do.Halt or Y.Do.Prevent
+ */
+Y.Do.Error = Y.Do.Halt;
+
+//////////////////////////////////////////////////////////////////////////
+
+// Y["Event"] && Y.Event.addListener(window, "unload", Y.Do._unload, Y.Do);
+
+})();
+
+/**
+ * Custom event engine, DOM event listener abstraction layer, synthetic DOM
+ * events.
+ * @module event-custom
+ * @submodule event-custom-base
+ */
+
+/**
+ * Return value from all subscribe operations
+ * @class EventHandle
+ * @constructor
+ * @param evt {CustomEvent} the custom event
+ * @param sub {Subscriber} the subscriber
+ */
+
+// var onsubscribeType = "_event:onsub",
+var AFTER = 'after',
+ CONFIGS = [
+ 'broadcast',
+ 'bubbles',
+ 'context',
+ 'contextFn',
+ 'currentTarget',
+ 'defaultFn',
+ 'details',
+ 'emitFacade',
+ 'fireOnce',
+ 'host',
+ 'preventable',
+ 'preventedFn',
+ 'queuable',
+ 'silent',
+ 'stoppedFn',
+ 'target',
+ 'type'
+ ],
+
+
+ YUI3_SIGNATURE = 9,
+ YUI_LOG = 'yui:log';
+
+Y.EventHandle = function(evt, sub) {
+
+ /**
+ * The custom event
+ * @type CustomEvent
+ */
+ this.evt = evt;
+
+ /**
+ * The subscriber object
+ * @type Subscriber
+ */
+ this.sub = sub;
+};
+
+Y.EventHandle.prototype = {
+
+ /**
+ * Detaches this subscriber
+ * @method detach
+ */
+ detach: function() {
+ var evt = this.evt, i;
+ if (evt) {
+ if (Y.Lang.isArray(evt)) {
+ for (i=0; i 2) {
+// this.log('CustomEvent context and silent are now in the config', 'warn', 'Event');
+ // }
+
+ o = o || {};
+
+ this.id = Y.stamp(this);
+
+ /**
+ * The type of event, returned to subscribers when the event fires
+ * @property type
+ * @type string
+ */
+ this.type = type;
+
+ /**
+ * The context the the event will fire from by default. Defaults to the YUI
+ * instance.
+ * @property context
+ * @type object
+ */
+ this.context = Y;
+
+ this.logSystem = (type == YUI_LOG);
+
+ /**
+ * If 0, this event does not broadcast. If 1, the YUI instance is notified
+ * every time this event fires. If 2, the YUI instance and the YUI global
+ * (if event is enabled on the global) are notified every time this event
+ * fires.
+ * @property broadcast
+ * @type int
+ */
+ // this.broadcast = 0;
+
+ /**
+ * By default all custom events are logged in the debug build, set silent
+ * to true to disable debug outpu for this event.
+ * @property silent
+ * @type boolean
+ */
+ this.silent = this.logSystem;
+
+ /**
+ * Specifies whether this event should be queued when the host is actively
+ * processing an event. This will effect exectution order of the callbacks
+ * for the various events.
+ * @property queuable
+ * @type boolean
+ * @default false
+ */
+ // this.queuable = false;
+
+ /**
+ * The subscribers to this event
+ * @property subscribers
+ * @type Subscriber{}
+ */
+ this.subscribers = {};
+
+ /**
+ * 'After' subscribers
+ * @property afters
+ * @type Subscriber{}
+ */
+ this.afters = {};
+
+ /**
+ * This event has fired if true
+ *
+ * @property fired
+ * @type boolean
+ * @default false;
+ */
+ // this.fired = false;
+
+ /**
+ * An array containing the arguments the custom event
+ * was last fired with.
+ * @property firedWith
+ * @type Array
+ */
+ // this.firedWith;
+
+ /**
+ * This event should only fire one time if true, and if
+ * it has fired, any new subscribers should be notified
+ * immediately.
+ *
+ * @property fireOnce
+ * @type boolean
+ * @default false;
+ */
+ // this.fireOnce = false;
+
+ /**
+ * Flag for stopPropagation that is modified during fire()
+ * 1 means to stop propagation to bubble targets. 2 means
+ * to also stop additional subscribers on this target.
+ * @property stopped
+ * @type int
+ */
+ // this.stopped = 0;
+
+ /**
+ * Flag for preventDefault that is modified during fire().
+ * if it is not 0, the default behavior for this event
+ * @property prevented
+ * @type int
+ */
+ // this.prevented = 0;
+
+ /**
+ * Specifies the host for this custom event. This is used
+ * to enable event bubbling
+ * @property host
+ * @type EventTarget
+ */
+ // this.host = null;
+
+ /**
+ * The default function to execute after event listeners
+ * have fire, but only if the default action was not
+ * prevented.
+ * @property defaultFn
+ * @type Function
+ */
+ // this.defaultFn = null;
+
+ /**
+ * The function to execute if a subscriber calls
+ * stopPropagation or stopImmediatePropagation
+ * @property stoppedFn
+ * @type Function
+ */
+ // this.stoppedFn = null;
+
+ /**
+ * The function to execute if a subscriber calls
+ * preventDefault
+ * @property preventedFn
+ * @type Function
+ */
+ // this.preventedFn = null;
+
+ /**
+ * Specifies whether or not this event's default function
+ * can be cancelled by a subscriber by executing preventDefault()
+ * on the event facade
+ * @property preventable
+ * @type boolean
+ * @default true
+ */
+ this.preventable = true;
+
+ /**
+ * Specifies whether or not a subscriber can stop the event propagation
+ * via stopPropagation(), stopImmediatePropagation(), or halt()
+ * @property bubbles
+ * @type boolean
+ * @default true
+ */
+ this.bubbles = true;
+
+ /**
+ * Supports multiple options for listener signatures in order to
+ * port YUI 2 apps.
+ * @property signature
+ * @type int
+ * @default 9
+ */
+ this.signature = YUI3_SIGNATURE;
+
+ // this.hasSubscribers = false;
+
+ // this.hasAfters = false;
+
+ /**
+ * If set to true, the custom event will deliver an EventFacade object
+ * that is similar to a DOM event object.
+ * @property emitFacade
+ * @type boolean
+ * @default false
+ */
+ // this.emitFacade = false;
+
+ this.applyConfig(o, true);
+
+ // this.log("Creating " + this.type);
+
+};
+
+Y.CustomEvent.prototype = {
+
+ /**
+ * Apply configuration properties. Only applies the CONFIG whitelist
+ * @method applyConfig
+ * @param o hash of properties to apply
+ * @param force {boolean} if true, properties that exist on the event
+ * will be overwritten.
+ */
+ applyConfig: function(o, force) {
+ if (o) {
+ Y.mix(this, o, force, CONFIGS);
+ }
+ },
+
+ _on: function(fn, context, args, when) {
+
+ if (!fn) {
+ this.log("Invalid callback for CE: " + this.type);
+ }
+
+ var s = new Y.Subscriber(fn, context, args, when);
+
+ if (this.fireOnce && this.fired) {
+ Y.later(0, this, Y.bind(this._notify, this, s, this.firedWith));
+ }
+
+ if (when == AFTER) {
+ this.afters[s.id] = s;
+ this.hasAfters = true;
+ } else {
+ this.subscribers[s.id] = s;
+ this.hasSubscribers = true;
+ }
+
+ return new Y.EventHandle(this, s);
+
+ },
+
+ /**
+ * Listen for this event
+ * @method subscribe
+ * @param {Function} fn The function to execute
+ * @return {EventHandle|EventTarget} unsubscribe handle or a
+ * chainable event target depending on the 'chain' config.
+ * @deprecated use on
+ */
+ subscribe: function(fn, context) {
+ var a = (arguments.length > 2) ? Y.Array(arguments, 2, true): null;
+ return this._on(fn, context, a, true);
+ },
+
+ /**
+ * Listen for this event
+ * @method on
+ * @param {Function} fn The function to execute
+ * @return {EventHandle|EventTarget} unsubscribe handle or a
+ * chainable event target depending on the 'chain' config.
+ */
+ on: function(fn, context) {
+ var a = (arguments.length > 2) ? Y.Array(arguments, 2, true): null;
+ return this._on(fn, context, a, true);
+ },
+
+ /**
+ * Listen for this event after the normal subscribers have been notified and
+ * the default behavior has been applied. If a normal subscriber prevents the
+ * default behavior, it also prevents after listeners from firing.
+ * @method after
+ * @param {Function} fn The function to execute
+ * @return {EventHandle|EventTarget} unsubscribe handle or a
+ * chainable event target depending on the 'chain' config.
+ */
+ after: function(fn, context) {
+ var a = (arguments.length > 2) ? Y.Array(arguments, 2, true): null;
+ return this._on(fn, context, a, AFTER);
+ },
+
+ /**
+ * Detach listeners.
+ * @method detach
+ * @param {Function} fn The subscribed function to remove, if not supplied
+ * all will be removed
+ * @param {Object} context The context object passed to subscribe.
+ * @return {int|EventTarget} returns a chainable event target
+ * or the number of subscribers unsubscribed.
+ */
+ detach: function(fn, context) {
+ // unsubscribe handle
+ if (fn && fn.detach) {
+ return fn.detach();
+ }
+
+ var found = 0, subs = this.subscribers, i, s;
+
+ for (i in subs) {
+ if (subs.hasOwnProperty(i)) {
+ s = subs[i];
+ if (s && (!fn || fn === s.fn)) {
+ this._delete(s);
+ found++;
+ }
+ }
+ }
+
+ return found;
+ },
+
+ /**
+ * Detach listeners.
+ * @method unsubscribe
+ * @param {Function} fn The subscribed function to remove, if not supplied
+ * all will be removed
+ * @param {Object} context The context object passed to subscribe.
+ * @return {boolean|EventTarget} returns a chainable event target
+ * or a boolean for legacy detach support.
+ * @deprecated use detach
+ */
+ unsubscribe: function() {
+ return this.detach.apply(this, arguments);
+ },
+
+
+ /**
+ * Notify a single subscriber
+ * @method _notify
+ * @param s {Subscriber} the subscriber
+ * @param args {Array} the arguments array to apply to the listener
+ * @private
+ */
+ _notify: function(s, args, ef) {
+
+ this.log(this.type + "->" + "sub: " + s.id);
+
+ var ret;
+
+ ret = s.notify(args, this);
+
+ if (false === ret || this.stopped > 1) {
+ this.log(this.type + " cancelled by subscriber");
+ return false;
+ }
+
+ return true;
+ },
+
+ /**
+ * Logger abstraction to centralize the application of the silent flag
+ * @method log
+ * @param msg {string} message to log
+ * @param cat {string} log category
+ */
+ log: function(msg, cat) {
+ if (!this.silent) {
+ }
+ },
+
+ /**
+ * Notifies the subscribers. The callback functions will be executed
+ * from the context specified when the event was created, and with the
+ * following parameters:
+ *
+ *
The type of event
+ *
All of the arguments fire() was executed with as an array
+ *
The custom object (if any) that was passed into the subscribe()
+ * method
+ *
+ * @method fire
+ * @param {Object*} arguments an arbitrary set of parameters to pass to
+ * the handler.
+ * @return {boolean} false if one of the subscribers returned false,
+ * true otherwise
+ *
+ */
+ fire: function() {
+ if (this.fireOnce && this.fired) {
+ this.log('fireOnce event: ' + this.type + ' already fired');
+ return true;
+ } else {
+
+ var args = Y.Array(arguments, 0, true);
+
+ this.fired = true;
+ this.firedWith = args;
+
+ if (this.emitFacade) {
+ return this.fireComplex(args);
+ } else {
+ return this.fireSimple(args);
+ }
+ }
+ },
+
+ fireSimple: function(args) {
+ if (this.hasSubscribers || this.hasAfters) {
+ this._procSubs(Y.merge(this.subscribers, this.afters), args);
+ }
+ this._broadcast(args);
+ return this.stopped ? false : true;
+ },
+
+ // Requires the event-custom-complex module for full funcitonality.
+ fireComplex: function(args) {
+ args[0] = args[0] || {};
+ return this.fireSimple(args);
+ },
+
+ _procSubs: function(subs, args, ef) {
+ var s, i;
+ for (i in subs) {
+ if (subs.hasOwnProperty(i)) {
+ s = subs[i];
+ if (s && s.fn) {
+ if (false === this._notify(s, args, ef)) {
+ this.stopped = 2;
+ }
+ if (this.stopped == 2) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ },
+
+ _broadcast: function(args) {
+ if (!this.stopped && this.broadcast) {
+
+ var a = Y.Array(args);
+ a.unshift(this.type);
+
+ if (this.host !== Y) {
+ Y.fire.apply(Y, a);
+ }
+
+ if (this.broadcast == 2) {
+ Y.Global.fire.apply(Y.Global, a);
+ }
+ }
+ },
+
+ /**
+ * Removes all listeners
+ * @method unsubscribeAll
+ * @return {int} The number of listeners unsubscribed
+ * @deprecated use detachAll
+ */
+ unsubscribeAll: function() {
+ return this.detachAll.apply(this, arguments);
+ },
+
+ /**
+ * Removes all listeners
+ * @method detachAll
+ * @return {int} The number of listeners unsubscribed
+ */
+ detachAll: function() {
+ return this.detach();
+ },
+
+ /**
+ * @method _delete
+ * @param subscriber object
+ * @private
+ */
+ _delete: function(s) {
+ if (s) {
+ delete s.fn;
+ delete s.context;
+ delete this.subscribers[s.id];
+ delete this.afters[s.id];
+ }
+ }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn The wrapped function to execute
+ * @param {Object} context The value of the keyword 'this' in the listener
+ * @param {Array} args* 0..n additional arguments to supply the listener
+ *
+ * @class Subscriber
+ * @constructor
+ */
+Y.Subscriber = function(fn, context, args) {
+
+ /**
+ * The callback that will be execute when the event fires
+ * This is wrapped by Y.rbind if obj was supplied.
+ * @property fn
+ * @type Function
+ */
+ this.fn = fn;
+
+ /**
+ * Optional 'this' keyword for the listener
+ * @property context
+ * @type Object
+ */
+ this.context = context;
+
+ /**
+ * Unique subscriber id
+ * @property id
+ * @type String
+ */
+ this.id = Y.stamp(this);
+
+ /**
+ * Additional arguments to propagate to the subscriber
+ * @property args
+ * @type Array
+ */
+ this.args = args;
+
+ /**
+ * Custom events for a given fire transaction.
+ * @property events
+ * @type {EventTarget}
+ */
+ this.events = null;
+
+};
+
+Y.Subscriber.prototype = {
+
+ _notify: function(c, args, ce) {
+ var a = this.args, ret;
+ switch (ce.signature) {
+ case 0:
+ ret = this.fn.call(c, ce.type, args, c);
+ break;
+ case 1:
+ ret = this.fn.call(c, args[0] || null, c);
+ break;
+ default:
+ if (a || args) {
+ args = args || [];
+ a = (a) ? args.concat(a) : args;
+ ret = this.fn.apply(c, a);
+ } else {
+ ret = this.fn.call(c);
+ }
+ }
+
+ return ret;
+ },
+
+ /**
+ * Executes the subscriber.
+ * @method notify
+ * @param args {Array} Arguments array for the subscriber
+ * @param ce {CustomEvent} The custom event that sent the notification
+ */
+ notify: function(args, ce) {
+ var c = this.context,
+ ret = true;
+
+ if (!c) {
+ c = (ce.contextFn) ? ce.contextFn() : ce.context;
+ }
+
+ // only catch errors if we will not re-throw them.
+ if (Y.config.throwFail) {
+ ret = this._notify(c, args, ce);
+ } else {
+ try {
+ ret = this._notify(c, args, ce);
+ } catch(e) {
+ Y.error(this + ' failed: ' + e.message, e);
+ }
+ }
+
+ return ret;
+ },
+
+ /**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @param {Function} fn the function to execute
+ * @param {Object} context optional 'this' keyword for the listener
+ * @return {boolean} true if the supplied arguments match this
+ * subscriber's signature.
+ */
+ contains: function(fn, context) {
+ if (context) {
+ return ((this.fn == fn) && this.context == context);
+ } else {
+ return (this.fn == fn);
+ }
+ }
+
+};
+
+/**
+ * Custom event engine, DOM event listener abstraction layer, synthetic DOM
+ * events.
+ * @module event-custom
+ * @submodule event-custom-base
+ */
+(function() {
+
+/**
+ * EventTarget provides the implementation for any object to
+ * publish, subscribe and fire to custom events, and also
+ * alows other EventTargets to target the object with events
+ * sourced from the other object.
+ * EventTarget is designed to be used with Y.augment to wrap
+ * EventCustom in an interface that allows events to be listened to
+ * and fired by name. This makes it possible for implementing code to
+ * subscribe to an event that either has not been created yet, or will
+ * not be created at all.
+ * @class EventTarget
+ * @param opts a configuration object
+ * @config emitFacade {boolean} if true, all events will emit event
+ * facade payloads by default (default false)
+ * @config prefix {string} the prefix to apply to non-prefixed event names
+ * @config chain {boolean} if true, on/after/detach return the host to allow
+ * chaining, otherwise they return an EventHandle (default false)
+ */
+
+var L = Y.Lang,
+ PREFIX_DELIMITER = ':',
+ CATEGORY_DELIMITER = '|',
+ AFTER_PREFIX = '~AFTER~',
+
+ /**
+ * If the instance has a prefix attribute and the
+ * event type is not prefixed, the instance prefix is
+ * applied to the supplied type.
+ * @method _getType
+ * @private
+ */
+ _getType = Y.cached(function(type, pre) {
+
+ if (!pre || !L.isString(type) || type.indexOf(PREFIX_DELIMITER) > -1) {
+ return type;
+ }
+
+ return pre + PREFIX_DELIMITER + type;
+ }),
+
+ /**
+ * Returns an array with the detach key (if provided),
+ * and the prefixed event name from _getType
+ * Y.on('detachcategory, menu:click', fn)
+ * @method _parseType
+ * @private
+ */
+ _parseType = Y.cached(function(type, pre) {
+
+ var t = type, detachcategory, after, i;
+
+ if (!L.isString(t)) {
+ return t;
+ }
+
+ i = t.indexOf(AFTER_PREFIX);
+
+ if (i > -1) {
+ after = true;
+ t = t.substr(AFTER_PREFIX.length);
+ }
+
+ i = t.indexOf(CATEGORY_DELIMITER);
+
+ if (i > -1) {
+ detachcategory = t.substr(0, (i));
+ t = t.substr(i+1);
+ if (t == '*') {
+ t = null;
+ }
+ }
+
+ // detach category, full type with instance prefix, is this an after listener, short type
+ return [detachcategory, (pre) ? _getType(t, pre) : t, after, t];
+ }),
+
+ ET = function(opts) {
+
+
+ var o = (L.isObject(opts)) ? opts : {};
+
+ this._yuievt = this._yuievt || {
+
+ id: Y.guid(),
+
+ events: {},
+
+ targets: {},
+
+ config: o,
+
+ chain: ('chain' in o) ? o.chain : Y.config.chain,
+
+ defaults: {
+ context: o.context || this,
+ host: this,
+ emitFacade: o.emitFacade,
+ fireOnce: o.fireOnce,
+ queuable: o.queuable,
+ broadcast: o.broadcast,
+ bubbles: ('bubbles' in o) ? o.bubbles : true
+ }
+ };
+
+ };
+
+
+ET.prototype = {
+
+ /**
+ * Subscribe to a custom event hosted by this object
+ * @method on
+ * @param type {string} The type of the event
+ * @param fn {Function} The callback
+ * @return the event target or a detach handle per 'chain' config
+ */
+ on: function(type, fn, context, x) {
+
+ var parts = _parseType(type, this._yuievt.config.prefix), f, c, args, ret, ce,
+ detachcategory, handle, store = Y.Env.evt.handles, after, adapt, shorttype,
+ Node = Y.Node, n, domevent;
+
+ if (L.isObject(type)) {
+
+ if (L.isFunction(type)) {
+ return Y.Do.before.apply(Y.Do, arguments);
+ }
+
+ f = fn;
+ c = context;
+ args = Y.Array(arguments, 0, true);
+ ret = {};
+ after = type._after;
+ delete type._after;
+
+ Y.each(type, function(v, k) {
+
+ if (v) {
+ f = v.fn || ((Y.Lang.isFunction(v)) ? v : f);
+ c = v.context || c;
+ }
+
+ args[0] = (after) ? AFTER_PREFIX + k : k;
+ args[1] = f;
+ args[2] = c;
+
+ ret[k] = this.on.apply(this, args);
+
+ }, this);
+
+ return (this._yuievt.chain) ? this : new Y.EventHandle(ret);
+
+ }
+
+ detachcategory = parts[0];
+ after = parts[2];
+ shorttype = parts[3];
+
+ // extra redirection so we catch adaptor events too. take a look at this.
+ if (Node && (this instanceof Node) && (shorttype in Node.DOM_EVENTS)) {
+ args = Y.Array(arguments, 0, true);
+ args.splice(2, 0, Node.getDOMNode(this));
+ return Y.on.apply(Y, args);
+ }
+
+ type = parts[1];
+
+ if (this instanceof YUI) {
+
+ adapt = Y.Env.evt.plugins[type];
+ args = Y.Array(arguments, 0, true);
+ args[0] = shorttype;
+
+ if (Node) {
+ n = args[2];
+
+ if (n instanceof Y.NodeList) {
+ n = Y.NodeList.getDOMNodes(n);
+ } else if (n instanceof Node) {
+ n = Node.getDOMNode(n);
+ }
+
+ domevent = (shorttype in Node.DOM_EVENTS);
+
+ // Captures both DOM events and event plugins.
+ if (domevent) {
+ args[2] = n;
+ }
+ }
+
+ // check for the existance of an event adaptor
+ if (adapt) {
+ handle = adapt.on.apply(Y, args);
+ } else if ((!type) || domevent) {
+ handle = Y.Event._attach(args);
+ }
+
+ }
+
+ if (!handle) {
+ ce = this._yuievt.events[type] || this.publish(type);
+ handle = ce._on(fn, context, (arguments.length > 3) ? Y.Array(arguments, 3, true) : null, (after) ? 'after' : true);
+ }
+
+ if (detachcategory) {
+ store[detachcategory] = store[detachcategory] || {};
+ store[detachcategory][type] = store[detachcategory][type] || [];
+ store[detachcategory][type].push(handle);
+ }
+
+ return (this._yuievt.chain) ? this : handle;
+
+ },
+
+ /**
+ * subscribe to an event
+ * @method subscribe
+ * @deprecated use on
+ */
+ subscribe: function() {
+ return this.on.apply(this, arguments);
+ },
+
+ /**
+ * Detach one or more listeners the from the specified event
+ * @method detach
+ * @param type {string|Object} Either the handle to the subscriber or the
+ * type of event. If the type
+ * is not specified, it will attempt to remove
+ * the listener from all hosted events.
+ * @param fn {Function} The subscribed function to unsubscribe, if not
+ * supplied, all subscribers will be removed.
+ * @param context {Object} The custom object passed to subscribe. This is
+ * optional, but if supplied will be used to
+ * disambiguate multiple listeners that are the same
+ * (e.g., you subscribe many object using a function
+ * that lives on the prototype)
+ * @return {EventTarget} the host
+ */
+ detach: function(type, fn, context) {
+ var evts = this._yuievt.events, i, ret,
+ Node = Y.Node, isNode = (this instanceof Node);
+
+ // detachAll disabled on the Y instance.
+ if (!type && (this !== Y)) {
+ for (i in evts) {
+ if (evts.hasOwnProperty(i)) {
+ ret = evts[i].detach(fn, context);
+ }
+ }
+ if (isNode) {
+
+ Y.Event.purgeElement(Node.getDOMNode(this));
+ }
+
+ return ret;
+ }
+
+ var parts = _parseType(type, this._yuievt.config.prefix),
+ detachcategory = L.isArray(parts) ? parts[0] : null,
+ shorttype = (parts) ? parts[3] : null,
+ handle, adapt, store = Y.Env.evt.handles, cat, args,
+ ce,
+
+ keyDetacher = function(lcat, ltype) {
+ var handles = lcat[ltype];
+ if (handles) {
+ while (handles.length) {
+ handle = handles.pop();
+ handle.detach();
+ }
+ }
+ };
+
+ if (detachcategory) {
+
+ cat = store[detachcategory];
+ type = parts[1];
+
+ if (cat) {
+ if (type) {
+ keyDetacher(cat, type);
+ } else {
+ for (i in cat) {
+ if (cat.hasOwnProperty(i)) {
+ keyDetacher(cat, i);
+ }
+ }
+ }
+
+ return (this._yuievt.chain) ? this : true;
+ }
+
+ // If this is an event handle, use it to detach
+ } else if (L.isObject(type) && type.detach) {
+ ret = type.detach();
+ return (this._yuievt.chain) ? this : ret;
+ // extra redirection so we catch adaptor events too. take a look at this.
+ } else if (isNode && ((!shorttype) || (shorttype in Node.DOM_EVENTS))) {
+ args = Y.Array(arguments, 0, true);
+ args[2] = Node.getDOMNode(this);
+ return Y.detach.apply(Y, args);
+ }
+
+ adapt = Y.Env.evt.plugins[shorttype];
+
+ // The YUI instance handles DOM events and adaptors
+ if (this instanceof YUI) {
+ args = Y.Array(arguments, 0, true);
+ // use the adaptor specific detach code if
+ if (adapt && adapt.detach) {
+ return adapt.detach.apply(Y, args);
+ // DOM event fork
+ } else if (!type || (!adapt && Node && (type in Node.DOM_EVENTS))) {
+ args[0] = type;
+ return Y.Event.detach.apply(Y.Event, args);
+ }
+ }
+
+ ce = evts[type];
+ if (ce) {
+ ret = ce.detach(fn, context);
+ }
+
+ return (this._yuievt.chain) ? this : ret;
+ },
+
+ /**
+ * detach a listener
+ * @method unsubscribe
+ * @deprecated use detach
+ */
+ unsubscribe: function() {
+ return this.detach.apply(this, arguments);
+ },
+
+ /**
+ * Removes all listeners from the specified event. If the event type
+ * is not specified, all listeners from all hosted custom events will
+ * be removed.
+ * @method detachAll
+ * @param type {string} The type, or name of the event
+ */
+ detachAll: function(type) {
+ return this.detach(type);
+ },
+
+ /**
+ * Removes all listeners from the specified event. If the event type
+ * is not specified, all listeners from all hosted custom events will
+ * be removed.
+ * @method unsubscribeAll
+ * @param type {string} The type, or name of the event
+ * @deprecated use detachAll
+ */
+ unsubscribeAll: function() {
+ return this.detachAll.apply(this, arguments);
+ },
+
+ /**
+ * Creates a new custom event of the specified type. If a custom event
+ * by that name already exists, it will not be re-created. In either
+ * case the custom event is returned.
+ *
+ * @method publish
+ *
+ * @param type {string} the type, or name of the event
+ * @param opts {object} optional config params. Valid properties are:
+ *
+ *
+ *
+ * 'broadcast': whether or not the YUI instance and YUI global are notified when the event is fired (false)
+ *
+ *
+ * 'bubbles': whether or not this event bubbles (true)
+ *
+ *
+ * 'context': the default execution context for the listeners (this)
+ *
+ *
+ * 'defaultFn': the default function to execute when this event fires if preventDefault was not called
+ *
+ *
+ * 'emitFacade': whether or not this event emits a facade (false)
+ *
+ *
+ * 'prefix': the prefix for this targets events, e.g., 'menu' in 'menu:click'
+ *
+ *
+ * 'fireOnce': if an event is configured to fire once, new subscribers after
+ * the fire will be notified immediately.
+ *
+ *
+ * 'preventable': whether or not preventDefault() has an effect (true)
+ *
+ *
+ * 'preventedFn': a function that is executed when preventDefault is called
+ *
+ *
+ * 'queuable': whether or not this event can be queued during bubbling (false)
+ *
+ *
+ * 'silent': if silent is true, debug messages are not provided for this event.
+ *
+ *
+ * 'stoppedFn': a function that is executed when stopPropagation is called
+ *
+ *
+ * 'type': the event type (valid option if not provided as the first parameter to publish)
+ *
+ *
+ *
+ * @return {Event.Custom} the custom event
+ *
+ */
+ publish: function(type, opts) {
+ var events, ce, ret, pre = this._yuievt.config.prefix;
+
+ type = (pre) ? _getType(type, pre) : type;
+
+
+ if (L.isObject(type)) {
+ ret = {};
+ Y.each(type, function(v, k) {
+ ret[k] = this.publish(k, v || opts);
+ }, this);
+
+ return ret;
+ }
+
+ events = this._yuievt.events;
+ ce = events[type];
+
+ if (ce) {
+// ce.log("publish applying new config to published event: '"+type+"' exists", 'info', 'event');
+ if (opts) {
+ ce.applyConfig(opts, true);
+ }
+ } else {
+ // apply defaults
+ ce = new Y.CustomEvent(type, (opts) ? Y.mix(opts, this._yuievt.defaults) : this._yuievt.defaults);
+ events[type] = ce;
+ }
+
+ // make sure we turn the broadcast flag off if this
+ // event was published as a result of bubbling
+ // if (opts instanceof Y.CustomEvent) {
+ // events[type].broadcast = false;
+ // }
+
+ return events[type];
+ },
+
+ /**
+ * Registers another EventTarget as a bubble target. Bubble order
+ * is determined by the order registered. Multiple targets can
+ * be specified.
+ * @method addTarget
+ * @param o {EventTarget} the target to add
+ */
+ addTarget: function(o) {
+ this._yuievt.targets[Y.stamp(o)] = o;
+ this._yuievt.hasTargets = true;
+ },
+
+ /**
+ * Removes a bubble target
+ * @method removeTarget
+ * @param o {EventTarget} the target to remove
+ */
+ removeTarget: function(o) {
+ delete this._yuievt.targets[Y.stamp(o)];
+ },
+
+ /**
+ * Fire a custom event by name. The callback functions will be executed
+ * from the context specified when the event was created, and with the
+ * following parameters.
+ *
+ * If the custom event object hasn't been created, then the event hasn't
+ * been published and it has no subscribers. For performance sake, we
+ * immediate exit in this case. This means the event won't bubble, so
+ * if the intention is that a bubble target be notified, the event must
+ * be published on this object first.
+ *
+ * The first argument is the event type, and any additional arguments are
+ * passed to the listeners as parameters. If the first of these is an
+ * object literal, and the event is configured to emit an event facade,
+ * that object is mixed into the event facade and the facade is provided
+ * in place of the original object.
+ *
+ * @method fire
+ * @param type {String|Object} The type of the event, or an object that contains
+ * a 'type' property.
+ * @param arguments {Object*} an arbitrary set of parameters to pass to
+ * the handler. If the first of these is an object literal and the event is
+ * configured to emit an event facade, the event facade will replace that
+ * parameter after the properties the object literal contains are copied to
+ * the event facade.
+ * @return {Event.Target} the event host
+ *
+ */
+ fire: function(type) {
+
+ var typeIncluded = L.isString(type),
+ t = (typeIncluded) ? type : (type && type.type),
+ ce, a, ret, pre=this._yuievt.config.prefix;
+
+ t = (pre) ? _getType(t, pre) : t;
+ ce = this.getEvent(t, true);
+
+ // this event has not been published or subscribed to
+ if (!ce) {
+
+ if (this._yuievt.hasTargets) {
+ a = (typeIncluded) ? arguments : Y.Array(arguments, 0, true).unshift(t);
+ return this.bubble(null, a, this);
+ }
+
+ // otherwise there is nothing to be done
+ ret = true;
+
+ } else {
+
+ a = Y.Array(arguments, (typeIncluded) ? 1 : 0, true);
+ ret = ce.fire.apply(ce, a);
+
+ // clear target for next fire()
+ ce.target = null;
+ }
+
+ return (this._yuievt.chain) ? this : ret;
+ },
+
+ /**
+ * Returns the custom event of the provided type has been created, a
+ * falsy value otherwise
+ * @method getEvent
+ * @param type {string} the type, or name of the event
+ * @param prefixed {string} if true, the type is prefixed already
+ * @return {Event.Custom} the custom event or null
+ */
+ getEvent: function(type, prefixed) {
+ var pre, e;
+ if (!prefixed) {
+ pre = this._yuievt.config.prefix;
+ type = (pre) ? _getType(type, pre) : type;
+ }
+ e = this._yuievt.events;
+ return (e && type in e) ? e[type] : null;
+ },
+
+ /**
+ * Subscribe to a custom event hosted by this object. The
+ * supplied callback will execute after any listeners add
+ * via the subscribe method, and after the default function,
+ * if configured for the event, has executed.
+ * @method after
+ * @param type {string} The type of the event
+ * @param fn {Function} The callback
+ * @return the event target or a detach handle per 'chain' config
+ */
+ after: function(type, fn) {
+
+ var a = Y.Array(arguments, 0, true);
+
+ switch (L.type(type)) {
+ case 'function':
+ return Y.Do.after.apply(Y.Do, arguments);
+ case 'object':
+ a[0]._after = true;
+ break;
+ default:
+ a[0] = AFTER_PREFIX + type;
+ }
+
+ return this.on.apply(this, a);
+
+ },
+
+ /**
+ * Executes the callback before a DOM event, custom event
+ * or method. If the first argument is a function, it
+ * is assumed the target is a method. For DOM and custom
+ * events, this is an alias for Y.on.
+ *
+ * For DOM and custom events:
+ * type, callback, context, 0-n arguments
+ *
+ * For methods:
+ * callback, object (method host), methodName, context, 0-n arguments
+ *
+ * @method before
+ * @return detach handle
+ * @deprecated use the on method
+ */
+ before: function() {
+ return this.on.apply(this, arguments);
+ }
+
+};
+
+Y.EventTarget = ET;
+
+// make Y an event target
+Y.mix(Y, ET.prototype, false, false, {
+ bubbles: false
+});
+
+ET.call(Y);
+
+YUI.Env.globalEvents = YUI.Env.globalEvents || new ET();
+
+/**
+ * Hosts YUI page level events. This is where events bubble to
+ * when the broadcast config is set to 2. This property is
+ * only available if the custom event module is loaded.
+ * @property Global
+ * @type EventTarget
+ * @for YUI
+ */
+Y.Global = YUI.Env.globalEvents;
+
+// @TODO implement a global namespace function on Y.Global?
+
+})();
+
+
+/**
+ * YUI's on method is a unified interface for subscribing to
+ * most events exposed by YUI. This includes custom events, DOM events, and
+ * function events. detach is also provided to remove listeners
+ * serviced by this function.
+ *
+ * The signature that on accepts varies depending on the type
+ * of event being consumed. Refer to the specific methods that will
+ * service a specific request for additional information about subscribing
+ * to that type of event.
+ *
+ *
+ *
Custom events. These events are defined by various
+ * modules in the library. This type of event is delegated to
+ * EventTarget's on method.
+ *
DOM events. These are moments reported by the browser related
+ * to browser functionality and user interaction.
+ * This type of event is delegated to Event's
+ * attach method.
+ *
+ *
The type of the event
+ *
The callback to execute
+ *
The specification for the Node(s) to attach the listener
+ * to. This can be a selector, collections, or Node/Element
+ * refereces.
Function events. These events can be used to react before or after a
+ * function is executed. This type of event is delegated to Event.Do's
+ * before method.
+ *
+ *
The callback to execute
+ *
The object that has the function that will be listened for.
+ *
The name of the function to listen for.
+ *
An optional context object
+ *
0..n additional arguments to supply the callback.
+ *
+ * Example Y.on(function(arg1, arg2, etc) { // obj.methodname was executed }, obj 'methodname');
+ *
+ *
+ *
+ * on corresponds to the moment before any default behavior of
+ * the event. after works the same way, but these listeners
+ * execute after the event's default behavior. before is an
+ * alias for on.
+ *
+ * @method on
+ * @param type** event type (this parameter does not apply for function events)
+ * @param fn the callback
+ * @param target** a descriptor for the target (applies to custom events only).
+ * For function events, this is the object that contains the function to
+ * execute.
+ * @param extra** 0..n Extra information a particular event may need. These
+ * will be documented with the event. In the case of function events, this
+ * is the name of the function to execute on the host. In the case of
+ * delegate listeners, this is the event delegation specification.
+ * @param context optionally change the value of 'this' in the callback
+ * @param args* 0..n additional arguments to pass to the callback.
+ * @return the event target or a detach handle per 'chain' config
+ * @for YUI
+ */
+
+/**
+ * after() is a unified interface for subscribing to
+ * most events exposed by YUI. This includes custom events,
+ * DOM events, and AOP events. This works the same way as
+ * the on() function, only it operates after any default
+ * behavior for the event has executed. @see on for more
+ * information.
+ * @method after
+ * @param type event type (this parameter does not apply for function events)
+ * @param fn the callback
+ * @param target a descriptor for the target (applies to custom events only).
+ * For function events, this is the object that contains the function to
+ * execute.
+ * @param extra 0..n Extra information a particular event may need. These
+ * will be documented with the event. In the case of function events, this
+ * is the name of the function to execute on the host. In the case of
+ * delegate listeners, this is the event delegation specification.
+ * @param context optionally change the value of 'this' in the callback
+ * @param args* 0..n additional arguments to pass to the callback.
+ * @return the event target or a detach handle per 'chain' config
+ * @for YUI
+ */
+
+
+}, '3.0.0' ,{requires:['oop']});
+YUI.add('event-custom-complex', function(Y) {
+
+
+/**
+ * Adds event facades, preventable default behavior, and bubbling.
+ * events.
+ * @module event-custom
+ * @submodule event-custom-complex
+ */
+
+(function() {
+
+var FACADE, FACADE_KEYS, CEProto = Y.CustomEvent.prototype;
+
+/**
+ * Wraps and protects a custom event for use when emitFacade is set to true.
+ * Requires the event-custom-complex module
+ * @class EventFacade
+ * @param e {Event} the custom event
+ * @param currentTarget {HTMLElement} the element the listener was attached to
+ */
+
+Y.EventFacade = function(e, currentTarget) {
+
+ e = e || {};
+
+ /**
+ * The arguments passed to fire
+ * @property details
+ * @type Array
+ */
+ this.details = e.details;
+
+ /**
+ * The event type
+ * @property type
+ * @type string
+ */
+ this.type = e.type;
+
+ //////////////////////////////////////////////////////
+
+ /**
+ * Node reference for the targeted eventtarget
+ * @propery target
+ * @type Node
+ */
+ this.target = e.target;
+
+ /**
+ * Node reference for the element that the listener was attached to.
+ * @propery currentTarget
+ * @type Node
+ */
+ this.currentTarget = currentTarget;
+
+ /**
+ * Node reference to the relatedTarget
+ * @propery relatedTarget
+ * @type Node
+ */
+ this.relatedTarget = e.relatedTarget;
+
+ /**
+ * Stops the propagation to the next bubble target
+ * @method stopPropagation
+ */
+ this.stopPropagation = function() {
+ e.stopPropagation();
+ };
+
+ /**
+ * Stops the propagation to the next bubble target and
+ * prevents any additional listeners from being exectued
+ * on the current target.
+ * @method stopImmediatePropagation
+ */
+ this.stopImmediatePropagation = function() {
+ e.stopImmediatePropagation();
+ };
+
+ /**
+ * Prevents the event's default behavior
+ * @method preventDefault
+ */
+ this.preventDefault = function() {
+ e.preventDefault();
+ };
+
+ /**
+ * Stops the event propagation and prevents the default
+ * event behavior.
+ * @method halt
+ * @param immediate {boolean} if true additional listeners
+ * on the current target will not be executed
+ */
+ this.halt = function(immediate) {
+ e.halt(immediate);
+ };
+
+};
+
+CEProto.fireComplex = function(args) {
+ var es = Y.Env._eventstack, ef, q, queue, ce, ret, events;
+
+ if (es) {
+ // queue this event if the current item in the queue bubbles
+ if (this.queuable && this.type != es.next.type) {
+ this.log('queue ' + this.type);
+ es.queue.push([this, args]);
+ return true;
+ }
+ } else {
+ Y.Env._eventstack = {
+ // id of the first event in the stack
+ id: this.id,
+ next: this,
+ silent: this.silent,
+ stopped: 0,
+ prevented: 0,
+ queue: []
+ };
+ es = Y.Env._eventstack;
+ }
+
+ this.stopped = 0;
+ this.prevented = 0;
+ this.target = this.target || this.host;
+
+ events = new Y.EventTarget({
+ fireOnce: true,
+ context: this.host
+ });
+
+ this.events = events;
+
+ if (this.preventedFn) {
+ events.on('prevented', this.preventedFn);
+ }
+
+ if (this.stoppedFn) {
+ events.on('stopped', this.stoppedFn);
+ }
+
+ this.currentTarget = this.host || this.currentTarget;
+
+ this.details = args.slice(); // original arguments in the details
+
+ // this.log("Firing " + this + ", " + "args: " + args);
+ this.log("Firing " + this.type);
+
+ this._facade = null; // kill facade to eliminate stale properties
+
+ ef = this._getFacade(args);
+
+ if (Y.Lang.isObject(args[0])) {
+ args[0] = ef;
+ } else {
+ args.unshift(ef);
+ }
+
+ if (this.hasSubscribers) {
+ this._procSubs(Y.merge(this.subscribers), args, ef);
+ }
+
+ // bubble if this is hosted in an event target and propagation has not been stopped
+ if (this.bubbles && this.host && this.host.bubble && !this.stopped) {
+ es.stopped = 0;
+ es.prevented = 0;
+ ret = this.host.bubble(this);
+
+ this.stopped = Math.max(this.stopped, es.stopped);
+ this.prevented = Math.max(this.prevented, es.prevented);
+
+ }
+
+ // execute the default behavior if not prevented
+ if (this.defaultFn && !this.prevented) {
+ this.defaultFn.apply(this.host || this, args);
+ }
+
+ // broadcast listeners are fired as discreet events on the
+ // YUI instance and potentially the YUI global.
+ this._broadcast(args);
+
+ // process after listeners. If the default behavior was
+ // prevented, the after events don't fire.
+ if (this.hasAfters && !this.prevented && this.stopped < 2) {
+ this._procSubs(Y.merge(this.afters), args, ef);
+ }
+
+ if (es.id === this.id) {
+ queue = es.queue;
+
+ while (queue.length) {
+ q = queue.pop();
+ ce = q[0];
+ es.stopped = 0;
+ es.prevented = 0;
+ // set up stack to allow the next item to be processed
+ es.next = ce;
+ ce.fire.apply(ce, q[1]);
+ }
+
+ Y.Env._eventstack = null;
+ }
+
+ return this.stopped ? false : true;
+};
+
+CEProto._getFacade = function() {
+
+ var ef = this._facade, o, o2,
+ args = this.details;
+
+ if (!ef) {
+ ef = new Y.EventFacade(this, this.currentTarget);
+ }
+
+ // if the first argument is an object literal, apply the
+ // properties to the event facade
+ o = args && args[0];
+
+ if (Y.Lang.isObject(o, true)) {
+
+ o2 = {};
+
+ // protect the event facade properties
+ Y.mix(o2, ef, true, FACADE_KEYS);
+
+ // mix the data
+ Y.mix(ef, o, true);
+
+ // restore ef
+ Y.mix(ef, o2, true, FACADE_KEYS);
+ }
+
+ // update the details field with the arguments
+ // ef.type = this.type;
+ ef.details = this.details;
+ ef.target = this.target;
+ ef.currentTarget = this.currentTarget;
+ ef.stopped = 0;
+ ef.prevented = 0;
+
+ this._facade = ef;
+
+ return this._facade;
+};
+
+/**
+ * Stop propagation to bubble targets
+ * @for CustomEvent
+ * @method stopPropagation
+ */
+CEProto.stopPropagation = function() {
+ this.stopped = 1;
+ Y.Env._eventstack.stopped = 1;
+ this.events.fire('stopped', this);
+};
+
+/**
+ * Stops propagation to bubble targets, and prevents any remaining
+ * subscribers on the current target from executing.
+ * @method stopImmediatePropagation
+ */
+CEProto.stopImmediatePropagation = function() {
+ this.stopped = 2;
+ Y.Env._eventstack.stopped = 2;
+ this.events.fire('stopped', this);
+};
+
+/**
+ * Prevents the execution of this event's defaultFn
+ * @method preventDefault
+ */
+CEProto.preventDefault = function() {
+ if (this.preventable) {
+ this.prevented = 1;
+ Y.Env._eventstack.prevented = 1;
+ this.events.fire('prevented', this);
+ }
+};
+
+/**
+ * Stops the event propagation and prevents the default
+ * event behavior.
+ * @method halt
+ * @param immediate {boolean} if true additional listeners
+ * on the current target will not be executed
+ */
+CEProto.halt = function(immediate) {
+ if (immediate) {
+ this.stopImmediatePropagation();
+ } else {
+ this.stopPropagation();
+ }
+ this.preventDefault();
+};
+
+/**
+ * Propagate an event. Requires the event-custom-complex module.
+ * @method bubble
+ * @param evt {Event.Custom} the custom event to propagate
+ * @return {boolean} the aggregated return value from Event.Custom.fire
+ * @for EventTarget
+ */
+Y.EventTarget.prototype.bubble = function(evt, args, target) {
+
+ var targs = this._yuievt.targets, ret = true,
+ t, type, ce, i, bc;
+
+ if (!evt || ((!evt.stopped) && targs)) {
+
+ for (i in targs) {
+ if (targs.hasOwnProperty(i)) {
+ t = targs[i];
+ type = evt && evt.type;
+ ce = t.getEvent(type, true);
+
+ // if this event was not published on the bubble target,
+ // publish it with sensible default properties
+ if (!ce) {
+
+ if (t._yuievt.hasTargets) {
+ t.bubble.call(t, evt, args, target);
+ }
+
+ } else {
+ ce.target = target || (evt && evt.target) || this;
+ ce.currentTarget = t;
+
+ bc = ce.broadcast;
+ ce.broadcast = false;
+ ret = ret && ce.fire.apply(ce, args || evt.details);
+ ce.broadcast = bc;
+
+ // stopPropagation() was called
+ if (ce.stopped) {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return ret;
+};
+
+FACADE = new Y.EventFacade();
+FACADE_KEYS = Y.Object.keys(FACADE);
+
+})();
+
+
+}, '3.0.0' ,{requires:['event-custom-base']});
+
+
+YUI.add('event-custom', function(Y){}, '3.0.0' ,{use:['event-custom-base', 'event-custom-complex']});
+
diff --git a/lib/yui/3.0.0/event-simulate/event-simulate-debug.js b/lib/yui/3.0.0/event-simulate/event-simulate-debug.js
new file mode 100644
index 0000000000..ca052a80c8
--- /dev/null
+++ b/lib/yui/3.0.0/event-simulate/event-simulate-debug.js
@@ -0,0 +1,490 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('event-simulate', function(Y) {
+
+(function() {
+/**
+ * Synthetic DOM events
+ * @module event-simulate
+ * @requires event
+ */
+
+//shortcuts
+var L = Y.Lang,
+ array = Y.Array,
+ isFunction = L.isFunction,
+ isString = L.isString,
+ isBoolean = L.isBoolean,
+ isObject = L.isObject,
+ isNumber = L.isNumber,
+ doc = Y.config.doc,
+
+ //mouse events supported
+ mouseEvents = {
+ click: 1,
+ dblclick: 1,
+ mouseover: 1,
+ mouseout: 1,
+ mousedown: 1,
+ mouseup: 1,
+ mousemove: 1
+ },
+
+ //key events supported
+ keyEvents = {
+ keydown: 1,
+ keyup: 1,
+ keypress: 1
+ };
+
+/*
+ * Note: Intentionally not for YUIDoc generation.
+ * Simulates a key event using the given event information to populate
+ * the generated event object. This method does browser-equalizing
+ * calculations to account for differences in the DOM and IE event models
+ * as well as different browser quirks. Note: keydown causes Safari 2.x to
+ * crash.
+ * @method simulateKeyEvent
+ * @private
+ * @static
+ * @param {HTMLElement} target The target of the given event.
+ * @param {String} type The type of event to fire. This can be any one of
+ * the following: keyup, keydown, and keypress.
+ * @param {Boolean} bubbles (Optional) Indicates if the event can be
+ * bubbled up. DOM Level 3 specifies that all key events bubble by
+ * default. The default is true.
+ * @param {Boolean} cancelable (Optional) Indicates if the event can be
+ * canceled using preventDefault(). DOM Level 3 specifies that all
+ * key events can be cancelled. The default
+ * is true.
+ * @param {Window} view (Optional) The view containing the target. This is
+ * typically the window object. The default is window.
+ * @param {Boolean} ctrlKey (Optional) Indicates if one of the CTRL keys
+ * is pressed while the event is firing. The default is false.
+ * @param {Boolean} altKey (Optional) Indicates if one of the ALT keys
+ * is pressed while the event is firing. The default is false.
+ * @param {Boolean} shiftKey (Optional) Indicates if one of the SHIFT keys
+ * is pressed while the event is firing. The default is false.
+ * @param {Boolean} metaKey (Optional) Indicates if one of the META keys
+ * is pressed while the event is firing. The default is false.
+ * @param {int} keyCode (Optional) The code for the key that is in use.
+ * The default is 0.
+ * @param {int} charCode (Optional) The Unicode code for the character
+ * associated with the key being used. The default is 0.
+ */
+function simulateKeyEvent(target /*:HTMLElement*/, type /*:String*/,
+ bubbles /*:Boolean*/, cancelable /*:Boolean*/,
+ view /*:Window*/,
+ ctrlKey /*:Boolean*/, altKey /*:Boolean*/,
+ shiftKey /*:Boolean*/, metaKey /*:Boolean*/,
+ keyCode /*:int*/, charCode /*:int*/) /*:Void*/
+{
+ //check target
+ if (!target){
+ Y.error("simulateKeyEvent(): Invalid target.");
+ }
+
+ //check event type
+ if (isString(type)){
+ type = type.toLowerCase();
+ switch(type){
+ case "textevent": //DOM Level 3
+ type = "keypress";
+ break;
+ case "keyup":
+ case "keydown":
+ case "keypress":
+ break;
+ default:
+ Y.error("simulateKeyEvent(): Event type '" + type + "' not supported.");
+ }
+ } else {
+ Y.error("simulateKeyEvent(): Event type must be a string.");
+ }
+
+ //setup default values
+ if (!isBoolean(bubbles)){
+ bubbles = true; //all key events bubble
+ }
+ if (!isBoolean(cancelable)){
+ cancelable = true; //all key events can be cancelled
+ }
+ if (!isObject(view)){
+ view = window; //view is typically window
+ }
+ if (!isBoolean(ctrlKey)){
+ ctrlKey = false;
+ }
+ if (!isBoolean(altKey)){
+ altKey = false;
+ }
+ if (!isBoolean(shiftKey)){
+ shiftKey = false;
+ }
+ if (!isBoolean(metaKey)){
+ metaKey = false;
+ }
+ if (!isNumber(keyCode)){
+ keyCode = 0;
+ }
+ if (!isNumber(charCode)){
+ charCode = 0;
+ }
+
+ //try to create a mouse event
+ var customEvent /*:MouseEvent*/ = null;
+
+ //check for DOM-compliant browsers first
+ if (isFunction(doc.createEvent)){
+
+ try {
+
+ //try to create key event
+ customEvent = doc.createEvent("KeyEvents");
+
+ /*
+ * Interesting problem: Firefox implemented a non-standard
+ * version of initKeyEvent() based on DOM Level 2 specs.
+ * Key event was removed from DOM Level 2 and re-introduced
+ * in DOM Level 3 with a different interface. Firefox is the
+ * only browser with any implementation of Key Events, so for
+ * now, assume it's Firefox if the above line doesn't error.
+ */
+ // @TODO: Decipher between Firefox's implementation and a correct one.
+ customEvent.initKeyEvent(type, bubbles, cancelable, view, ctrlKey,
+ altKey, shiftKey, metaKey, keyCode, charCode);
+
+ } catch (ex /*:Error*/){
+
+ /*
+ * If it got here, that means key events aren't officially supported.
+ * Safari/WebKit is a real problem now. WebKit 522 won't let you
+ * set keyCode, charCode, or other properties if you use a
+ * UIEvent, so we first must try to create a generic event. The
+ * fun part is that this will throw an error on Safari 2.x. The
+ * end result is that we need another try...catch statement just to
+ * deal with this mess.
+ */
+ try {
+
+ //try to create generic event - will fail in Safari 2.x
+ customEvent = doc.createEvent("Events");
+
+ } catch (uierror /*:Error*/){
+
+ //the above failed, so create a UIEvent for Safari 2.x
+ customEvent = doc.createEvent("UIEvents");
+
+ } finally {
+
+ customEvent.initEvent(type, bubbles, cancelable);
+
+ //initialize
+ customEvent.view = view;
+ customEvent.altKey = altKey;
+ customEvent.ctrlKey = ctrlKey;
+ customEvent.shiftKey = shiftKey;
+ customEvent.metaKey = metaKey;
+ customEvent.keyCode = keyCode;
+ customEvent.charCode = charCode;
+
+ }
+
+ }
+
+ //fire the event
+ target.dispatchEvent(customEvent);
+
+ } else if (isObject(doc.createEventObject)){ //IE
+
+ //create an IE event object
+ customEvent = doc.createEventObject();
+
+ //assign available properties
+ customEvent.bubbles = bubbles;
+ customEvent.cancelable = cancelable;
+ customEvent.view = view;
+ customEvent.ctrlKey = ctrlKey;
+ customEvent.altKey = altKey;
+ customEvent.shiftKey = shiftKey;
+ customEvent.metaKey = metaKey;
+
+ /*
+ * IE doesn't support charCode explicitly. CharCode should
+ * take precedence over any keyCode value for accurate
+ * representation.
+ */
+ customEvent.keyCode = (charCode > 0) ? charCode : keyCode;
+
+ //fire the event
+ target.fireEvent("on" + type, customEvent);
+
+ } else {
+ Y.error("simulateKeyEvent(): No event simulation framework present.");
+ }
+}
+
+/*
+ * Note: Intentionally not for YUIDoc generation.
+ * Simulates a mouse event using the given event information to populate
+ * the generated event object. This method does browser-equalizing
+ * calculations to account for differences in the DOM and IE event models
+ * as well as different browser quirks.
+ * @method simulateMouseEvent
+ * @private
+ * @static
+ * @param {HTMLElement} target The target of the given event.
+ * @param {String} type The type of event to fire. This can be any one of
+ * the following: click, dblclick, mousedown, mouseup, mouseout,
+ * mouseover, and mousemove.
+ * @param {Boolean} bubbles (Optional) Indicates if the event can be
+ * bubbled up. DOM Level 2 specifies that all mouse events bubble by
+ * default. The default is true.
+ * @param {Boolean} cancelable (Optional) Indicates if the event can be
+ * canceled using preventDefault(). DOM Level 2 specifies that all
+ * mouse events except mousemove can be cancelled. The default
+ * is true for all events except mousemove, for which the default
+ * is false.
+ * @param {Window} view (Optional) The view containing the target. This is
+ * typically the window object. The default is window.
+ * @param {int} detail (Optional) The number of times the mouse button has
+ * been used. The default value is 1.
+ * @param {int} screenX (Optional) The x-coordinate on the screen at which
+ * point the event occured. The default is 0.
+ * @param {int} screenY (Optional) The y-coordinate on the screen at which
+ * point the event occured. The default is 0.
+ * @param {int} clientX (Optional) The x-coordinate on the client at which
+ * point the event occured. The default is 0.
+ * @param {int} clientY (Optional) The y-coordinate on the client at which
+ * point the event occured. The default is 0.
+ * @param {Boolean} ctrlKey (Optional) Indicates if one of the CTRL keys
+ * is pressed while the event is firing. The default is false.
+ * @param {Boolean} altKey (Optional) Indicates if one of the ALT keys
+ * is pressed while the event is firing. The default is false.
+ * @param {Boolean} shiftKey (Optional) Indicates if one of the SHIFT keys
+ * is pressed while the event is firing. The default is false.
+ * @param {Boolean} metaKey (Optional) Indicates if one of the META keys
+ * is pressed while the event is firing. The default is false.
+ * @param {int} button (Optional) The button being pressed while the event
+ * is executing. The value should be 0 for the primary mouse button
+ * (typically the left button), 1 for the terciary mouse button
+ * (typically the middle button), and 2 for the secondary mouse button
+ * (typically the right button). The default is 0.
+ * @param {HTMLElement} relatedTarget (Optional) For mouseout events,
+ * this is the element that the mouse has moved to. For mouseover
+ * events, this is the element that the mouse has moved from. This
+ * argument is ignored for all other events. The default is null.
+ */
+function simulateMouseEvent(target /*:HTMLElement*/, type /*:String*/,
+ bubbles /*:Boolean*/, cancelable /*:Boolean*/,
+ view /*:Window*/, detail /*:int*/,
+ screenX /*:int*/, screenY /*:int*/,
+ clientX /*:int*/, clientY /*:int*/,
+ ctrlKey /*:Boolean*/, altKey /*:Boolean*/,
+ shiftKey /*:Boolean*/, metaKey /*:Boolean*/,
+ button /*:int*/, relatedTarget /*:HTMLElement*/) /*:Void*/
+{
+
+ //check target
+ if (!target){
+ Y.error("simulateMouseEvent(): Invalid target.");
+ }
+
+ //check event type
+ if (isString(type)){
+ type = type.toLowerCase();
+
+ //make sure it's a supported mouse event
+ if (!mouseEvents[type]){
+ Y.error("simulateMouseEvent(): Event type '" + type + "' not supported.");
+ }
+ } else {
+ Y.error("simulateMouseEvent(): Event type must be a string.");
+ }
+
+ //setup default values
+ if (!isBoolean(bubbles)){
+ bubbles = true; //all mouse events bubble
+ }
+ if (!isBoolean(cancelable)){
+ cancelable = (type != "mousemove"); //mousemove is the only one that can't be cancelled
+ }
+ if (!isObject(view)){
+ view = window; //view is typically window
+ }
+ if (!isNumber(detail)){
+ detail = 1; //number of mouse clicks must be at least one
+ }
+ if (!isNumber(screenX)){
+ screenX = 0;
+ }
+ if (!isNumber(screenY)){
+ screenY = 0;
+ }
+ if (!isNumber(clientX)){
+ clientX = 0;
+ }
+ if (!isNumber(clientY)){
+ clientY = 0;
+ }
+ if (!isBoolean(ctrlKey)){
+ ctrlKey = false;
+ }
+ if (!isBoolean(altKey)){
+ altKey = false;
+ }
+ if (!isBoolean(shiftKey)){
+ shiftKey = false;
+ }
+ if (!isBoolean(metaKey)){
+ metaKey = false;
+ }
+ if (!isNumber(button)){
+ button = 0;
+ }
+
+ //try to create a mouse event
+ var customEvent /*:MouseEvent*/ = null;
+
+ //check for DOM-compliant browsers first
+ if (isFunction(doc.createEvent)){
+
+ customEvent = doc.createEvent("MouseEvents");
+
+ //Safari 2.x (WebKit 418) still doesn't implement initMouseEvent()
+ if (customEvent.initMouseEvent){
+ customEvent.initMouseEvent(type, bubbles, cancelable, view, detail,
+ screenX, screenY, clientX, clientY,
+ ctrlKey, altKey, shiftKey, metaKey,
+ button, relatedTarget);
+ } else { //Safari
+
+ //the closest thing available in Safari 2.x is UIEvents
+ customEvent = doc.createEvent("UIEvents");
+ customEvent.initEvent(type, bubbles, cancelable);
+ customEvent.view = view;
+ customEvent.detail = detail;
+ customEvent.screenX = screenX;
+ customEvent.screenY = screenY;
+ customEvent.clientX = clientX;
+ customEvent.clientY = clientY;
+ customEvent.ctrlKey = ctrlKey;
+ customEvent.altKey = altKey;
+ customEvent.metaKey = metaKey;
+ customEvent.shiftKey = shiftKey;
+ customEvent.button = button;
+ customEvent.relatedTarget = relatedTarget;
+ }
+
+ /*
+ * Check to see if relatedTarget has been assigned. Firefox
+ * versions less than 2.0 don't allow it to be assigned via
+ * initMouseEvent() and the property is readonly after event
+ * creation, so in order to keep YAHOO.util.getRelatedTarget()
+ * working, assign to the IE proprietary toElement property
+ * for mouseout event and fromElement property for mouseover
+ * event.
+ */
+ if (relatedTarget && !customEvent.relatedTarget){
+ if (type == "mouseout"){
+ customEvent.toElement = relatedTarget;
+ } else if (type == "mouseover"){
+ customEvent.fromElement = relatedTarget;
+ }
+ }
+
+ //fire the event
+ target.dispatchEvent(customEvent);
+
+ } else if (isObject(doc.createEventObject)){ //IE
+
+ //create an IE event object
+ customEvent = doc.createEventObject();
+
+ //assign available properties
+ customEvent.bubbles = bubbles;
+ customEvent.cancelable = cancelable;
+ customEvent.view = view;
+ customEvent.detail = detail;
+ customEvent.screenX = screenX;
+ customEvent.screenY = screenY;
+ customEvent.clientX = clientX;
+ customEvent.clientY = clientY;
+ customEvent.ctrlKey = ctrlKey;
+ customEvent.altKey = altKey;
+ customEvent.metaKey = metaKey;
+ customEvent.shiftKey = shiftKey;
+
+ //fix button property for IE's wacky implementation
+ switch(button){
+ case 0:
+ customEvent.button = 1;
+ break;
+ case 1:
+ customEvent.button = 4;
+ break;
+ case 2:
+ //leave as is
+ break;
+ default:
+ customEvent.button = 0;
+ }
+
+ /*
+ * Have to use relatedTarget because IE won't allow assignment
+ * to toElement or fromElement on generic events. This keeps
+ * YAHOO.util.customEvent.getRelatedTarget() functional.
+ */
+ customEvent.relatedTarget = relatedTarget;
+
+ //fire the event
+ target.fireEvent("on" + type, customEvent);
+
+ } else {
+ Y.error("simulateMouseEvent(): No event simulation framework present.");
+ }
+}
+
+
+/**
+ * Simulates the event with the given name on a target.
+ * @param {HTMLElement} target The DOM element that's the target of the event.
+ * @param {String} type The type of event to simulate (i.e., "click").
+ * @param {Object} options (Optional) Extra options to copy onto the event object.
+ * @return {void}
+ * @method simulate
+ * @static
+ */
+Y.Event.simulate = function(target, type, options){
+
+ options = options || {};
+
+ if (mouseEvents[type]){
+ simulateMouseEvent(target, type, options.bubbles,
+ options.cancelable, options.view, options.detail, options.screenX,
+ options.screenY, options.clientX, options.clientY, options.ctrlKey,
+ options.altKey, options.shiftKey, options.metaKey, options.button,
+ options.relatedTarget);
+ } else if (keyEvents[type]){
+ simulateKeyEvent(target, type, options.bubbles,
+ options.cancelable, options.view, options.ctrlKey,
+ options.altKey, options.shiftKey, options.metaKey,
+ options.keyCode, options.charCode);
+ } else {
+ Y.error("simulate(): Event '" + type + "' can't be simulated.");
+ }
+};
+
+/*
+ * @TODO: focus(), blur(), submit()
+ */
+
+})();
+
+
+}, '3.0.0' ,{requires:['event']});
diff --git a/lib/yui/3.0.0/event-simulate/event-simulate-min.js b/lib/yui/3.0.0/event-simulate/event-simulate-min.js
new file mode 100644
index 0000000000..ffde0c85c7
--- /dev/null
+++ b/lib/yui/3.0.0/event-simulate/event-simulate-min.js
@@ -0,0 +1,8 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add("event-simulate",function(A){(function(){var H=A.Lang,G=A.Array,D=H.isFunction,C=H.isString,E=H.isBoolean,M=H.isObject,K=H.isNumber,J=A.config.doc,N={click:1,dblclick:1,mouseover:1,mouseout:1,mousedown:1,mouseup:1,mousemove:1},I={keydown:1,keyup:1,keypress:1};function F(S,W,R,P,Y,O,L,X,U,a,Z){if(!S){A.error("simulateKeyEvent(): Invalid target.");}if(C(W)){W=W.toLowerCase();switch(W){case"textevent":W="keypress";break;case"keyup":case"keydown":case"keypress":break;default:A.error("simulateKeyEvent(): Event type '"+W+"' not supported.");}}else{A.error("simulateKeyEvent(): Event type must be a string.");}if(!E(R)){R=true;}if(!E(P)){P=true;}if(!M(Y)){Y=window;}if(!E(O)){O=false;}if(!E(L)){L=false;}if(!E(X)){X=false;}if(!E(U)){U=false;}if(!K(a)){a=0;}if(!K(Z)){Z=0;}var V=null;if(D(J.createEvent)){try{V=J.createEvent("KeyEvents");V.initKeyEvent(W,R,P,Y,O,L,X,U,a,Z);}catch(T){try{V=J.createEvent("Events");}catch(Q){V=J.createEvent("UIEvents");}finally{V.initEvent(W,R,P);V.view=Y;V.altKey=L;V.ctrlKey=O;V.shiftKey=X;V.metaKey=U;V.keyCode=a;V.charCode=Z;}}S.dispatchEvent(V);}else{if(M(J.createEventObject)){V=J.createEventObject();V.bubbles=R;V.cancelable=P;V.view=Y;V.ctrlKey=O;V.altKey=L;V.shiftKey=X;V.metaKey=U;V.keyCode=(Z>0)?Z:a;S.fireEvent("on"+W,V);}else{A.error("simulateKeyEvent(): No event simulation framework present.");}}}function B(X,c,U,R,d,W,T,S,Q,O,P,L,b,Z,V,Y){if(!X){A.error("simulateMouseEvent(): Invalid target.");}if(C(c)){c=c.toLowerCase();if(!N[c]){A.error("simulateMouseEvent(): Event type '"+c+"' not supported.");}}else{A.error("simulateMouseEvent(): Event type must be a string.");}if(!E(U)){U=true;}if(!E(R)){R=(c!="mousemove");}if(!M(d)){d=window;}if(!K(W)){W=1;}if(!K(T)){T=0;}if(!K(S)){S=0;}if(!K(Q)){Q=0;}if(!K(O)){O=0;}if(!E(P)){P=false;}if(!E(L)){L=false;}if(!E(b)){b=false;}if(!E(Z)){Z=false;}if(!K(V)){V=0;}var a=null;if(D(J.createEvent)){a=J.createEvent("MouseEvents");if(a.initMouseEvent){a.initMouseEvent(c,U,R,d,W,T,S,Q,O,P,L,b,Z,V,Y);}else{a=J.createEvent("UIEvents");a.initEvent(c,U,R);a.view=d;a.detail=W;a.screenX=T;a.screenY=S;a.clientX=Q;a.clientY=O;a.ctrlKey=P;a.altKey=L;a.metaKey=Z;a.shiftKey=b;a.button=V;a.relatedTarget=Y;}if(Y&&!a.relatedTarget){if(c=="mouseout"){a.toElement=Y;}else{if(c=="mouseover"){a.fromElement=Y;}}}X.dispatchEvent(a);}else{if(M(J.createEventObject)){a=J.createEventObject();a.bubbles=U;a.cancelable=R;a.view=d;a.detail=W;a.screenX=T;a.screenY=S;a.clientX=Q;a.clientY=O;a.ctrlKey=P;a.altKey=L;a.metaKey=Z;a.shiftKey=b;switch(V){case 0:a.button=1;break;case 1:a.button=4;break;case 2:break;default:a.button=0;}a.relatedTarget=Y;X.fireEvent("on"+c,a);}else{A.error("simulateMouseEvent(): No event simulation framework present.");}}}A.Event.simulate=function(P,O,L){L=L||{};if(N[O]){B(P,O,L.bubbles,L.cancelable,L.view,L.detail,L.screenX,L.screenY,L.clientX,L.clientY,L.ctrlKey,L.altKey,L.shiftKey,L.metaKey,L.button,L.relatedTarget);}else{if(I[O]){F(P,O,L.bubbles,L.cancelable,L.view,L.ctrlKey,L.altKey,L.shiftKey,L.metaKey,L.keyCode,L.charCode);}else{A.error("simulate(): Event '"+O+"' can't be simulated.");}}};})();},"3.0.0",{requires:["event"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/event-simulate/event-simulate.js b/lib/yui/3.0.0/event-simulate/event-simulate.js
new file mode 100644
index 0000000000..ca052a80c8
--- /dev/null
+++ b/lib/yui/3.0.0/event-simulate/event-simulate.js
@@ -0,0 +1,490 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+YUI.add('event-simulate', function(Y) {
+
+(function() {
+/**
+ * Synthetic DOM events
+ * @module event-simulate
+ * @requires event
+ */
+
+//shortcuts
+var L = Y.Lang,
+ array = Y.Array,
+ isFunction = L.isFunction,
+ isString = L.isString,
+ isBoolean = L.isBoolean,
+ isObject = L.isObject,
+ isNumber = L.isNumber,
+ doc = Y.config.doc,
+
+ //mouse events supported
+ mouseEvents = {
+ click: 1,
+ dblclick: 1,
+ mouseover: 1,
+ mouseout: 1,
+ mousedown: 1,
+ mouseup: 1,
+ mousemove: 1
+ },
+
+ //key events supported
+ keyEvents = {
+ keydown: 1,
+ keyup: 1,
+ keypress: 1
+ };
+
+/*
+ * Note: Intentionally not for YUIDoc generation.
+ * Simulates a key event using the given event information to populate
+ * the generated event object. This method does browser-equalizing
+ * calculations to account for differences in the DOM and IE event models
+ * as well as different browser quirks. Note: keydown causes Safari 2.x to
+ * crash.
+ * @method simulateKeyEvent
+ * @private
+ * @static
+ * @param {HTMLElement} target The target of the given event.
+ * @param {String} type The type of event to fire. This can be any one of
+ * the following: keyup, keydown, and keypress.
+ * @param {Boolean} bubbles (Optional) Indicates if the event can be
+ * bubbled up. DOM Level 3 specifies that all key events bubble by
+ * default. The default is true.
+ * @param {Boolean} cancelable (Optional) Indicates if the event can be
+ * canceled using preventDefault(). DOM Level 3 specifies that all
+ * key events can be cancelled. The default
+ * is true.
+ * @param {Window} view (Optional) The view containing the target. This is
+ * typically the window object. The default is window.
+ * @param {Boolean} ctrlKey (Optional) Indicates if one of the CTRL keys
+ * is pressed while the event is firing. The default is false.
+ * @param {Boolean} altKey (Optional) Indicates if one of the ALT keys
+ * is pressed while the event is firing. The default is false.
+ * @param {Boolean} shiftKey (Optional) Indicates if one of the SHIFT keys
+ * is pressed while the event is firing. The default is false.
+ * @param {Boolean} metaKey (Optional) Indicates if one of the META keys
+ * is pressed while the event is firing. The default is false.
+ * @param {int} keyCode (Optional) The code for the key that is in use.
+ * The default is 0.
+ * @param {int} charCode (Optional) The Unicode code for the character
+ * associated with the key being used. The default is 0.
+ */
+function simulateKeyEvent(target /*:HTMLElement*/, type /*:String*/,
+ bubbles /*:Boolean*/, cancelable /*:Boolean*/,
+ view /*:Window*/,
+ ctrlKey /*:Boolean*/, altKey /*:Boolean*/,
+ shiftKey /*:Boolean*/, metaKey /*:Boolean*/,
+ keyCode /*:int*/, charCode /*:int*/) /*:Void*/
+{
+ //check target
+ if (!target){
+ Y.error("simulateKeyEvent(): Invalid target.");
+ }
+
+ //check event type
+ if (isString(type)){
+ type = type.toLowerCase();
+ switch(type){
+ case "textevent": //DOM Level 3
+ type = "keypress";
+ break;
+ case "keyup":
+ case "keydown":
+ case "keypress":
+ break;
+ default:
+ Y.error("simulateKeyEvent(): Event type '" + type + "' not supported.");
+ }
+ } else {
+ Y.error("simulateKeyEvent(): Event type must be a string.");
+ }
+
+ //setup default values
+ if (!isBoolean(bubbles)){
+ bubbles = true; //all key events bubble
+ }
+ if (!isBoolean(cancelable)){
+ cancelable = true; //all key events can be cancelled
+ }
+ if (!isObject(view)){
+ view = window; //view is typically window
+ }
+ if (!isBoolean(ctrlKey)){
+ ctrlKey = false;
+ }
+ if (!isBoolean(altKey)){
+ altKey = false;
+ }
+ if (!isBoolean(shiftKey)){
+ shiftKey = false;
+ }
+ if (!isBoolean(metaKey)){
+ metaKey = false;
+ }
+ if (!isNumber(keyCode)){
+ keyCode = 0;
+ }
+ if (!isNumber(charCode)){
+ charCode = 0;
+ }
+
+ //try to create a mouse event
+ var customEvent /*:MouseEvent*/ = null;
+
+ //check for DOM-compliant browsers first
+ if (isFunction(doc.createEvent)){
+
+ try {
+
+ //try to create key event
+ customEvent = doc.createEvent("KeyEvents");
+
+ /*
+ * Interesting problem: Firefox implemented a non-standard
+ * version of initKeyEvent() based on DOM Level 2 specs.
+ * Key event was removed from DOM Level 2 and re-introduced
+ * in DOM Level 3 with a different interface. Firefox is the
+ * only browser with any implementation of Key Events, so for
+ * now, assume it's Firefox if the above line doesn't error.
+ */
+ // @TODO: Decipher between Firefox's implementation and a correct one.
+ customEvent.initKeyEvent(type, bubbles, cancelable, view, ctrlKey,
+ altKey, shiftKey, metaKey, keyCode, charCode);
+
+ } catch (ex /*:Error*/){
+
+ /*
+ * If it got here, that means key events aren't officially supported.
+ * Safari/WebKit is a real problem now. WebKit 522 won't let you
+ * set keyCode, charCode, or other properties if you use a
+ * UIEvent, so we first must try to create a generic event. The
+ * fun part is that this will throw an error on Safari 2.x. The
+ * end result is that we need another try...catch statement just to
+ * deal with this mess.
+ */
+ try {
+
+ //try to create generic event - will fail in Safari 2.x
+ customEvent = doc.createEvent("Events");
+
+ } catch (uierror /*:Error*/){
+
+ //the above failed, so create a UIEvent for Safari 2.x
+ customEvent = doc.createEvent("UIEvents");
+
+ } finally {
+
+ customEvent.initEvent(type, bubbles, cancelable);
+
+ //initialize
+ customEvent.view = view;
+ customEvent.altKey = altKey;
+ customEvent.ctrlKey = ctrlKey;
+ customEvent.shiftKey = shiftKey;
+ customEvent.metaKey = metaKey;
+ customEvent.keyCode = keyCode;
+ customEvent.charCode = charCode;
+
+ }
+
+ }
+
+ //fire the event
+ target.dispatchEvent(customEvent);
+
+ } else if (isObject(doc.createEventObject)){ //IE
+
+ //create an IE event object
+ customEvent = doc.createEventObject();
+
+ //assign available properties
+ customEvent.bubbles = bubbles;
+ customEvent.cancelable = cancelable;
+ customEvent.view = view;
+ customEvent.ctrlKey = ctrlKey;
+ customEvent.altKey = altKey;
+ customEvent.shiftKey = shiftKey;
+ customEvent.metaKey = metaKey;
+
+ /*
+ * IE doesn't support charCode explicitly. CharCode should
+ * take precedence over any keyCode value for accurate
+ * representation.
+ */
+ customEvent.keyCode = (charCode > 0) ? charCode : keyCode;
+
+ //fire the event
+ target.fireEvent("on" + type, customEvent);
+
+ } else {
+ Y.error("simulateKeyEvent(): No event simulation framework present.");
+ }
+}
+
+/*
+ * Note: Intentionally not for YUIDoc generation.
+ * Simulates a mouse event using the given event information to populate
+ * the generated event object. This method does browser-equalizing
+ * calculations to account for differences in the DOM and IE event models
+ * as well as different browser quirks.
+ * @method simulateMouseEvent
+ * @private
+ * @static
+ * @param {HTMLElement} target The target of the given event.
+ * @param {String} type The type of event to fire. This can be any one of
+ * the following: click, dblclick, mousedown, mouseup, mouseout,
+ * mouseover, and mousemove.
+ * @param {Boolean} bubbles (Optional) Indicates if the event can be
+ * bubbled up. DOM Level 2 specifies that all mouse events bubble by
+ * default. The default is true.
+ * @param {Boolean} cancelable (Optional) Indicates if the event can be
+ * canceled using preventDefault(). DOM Level 2 specifies that all
+ * mouse events except mousemove can be cancelled. The default
+ * is true for all events except mousemove, for which the default
+ * is false.
+ * @param {Window} view (Optional) The view containing the target. This is
+ * typically the window object. The default is window.
+ * @param {int} detail (Optional) The number of times the mouse button has
+ * been used. The default value is 1.
+ * @param {int} screenX (Optional) The x-coordinate on the screen at which
+ * point the event occured. The default is 0.
+ * @param {int} screenY (Optional) The y-coordinate on the screen at which
+ * point the event occured. The default is 0.
+ * @param {int} clientX (Optional) The x-coordinate on the client at which
+ * point the event occured. The default is 0.
+ * @param {int} clientY (Optional) The y-coordinate on the client at which
+ * point the event occured. The default is 0.
+ * @param {Boolean} ctrlKey (Optional) Indicates if one of the CTRL keys
+ * is pressed while the event is firing. The default is false.
+ * @param {Boolean} altKey (Optional) Indicates if one of the ALT keys
+ * is pressed while the event is firing. The default is false.
+ * @param {Boolean} shiftKey (Optional) Indicates if one of the SHIFT keys
+ * is pressed while the event is firing. The default is false.
+ * @param {Boolean} metaKey (Optional) Indicates if one of the META keys
+ * is pressed while the event is firing. The default is false.
+ * @param {int} button (Optional) The button being pressed while the event
+ * is executing. The value should be 0 for the primary mouse button
+ * (typically the left button), 1 for the terciary mouse button
+ * (typically the middle button), and 2 for the secondary mouse button
+ * (typically the right button). The default is 0.
+ * @param {HTMLElement} relatedTarget (Optional) For mouseout events,
+ * this is the element that the mouse has moved to. For mouseover
+ * events, this is the element that the mouse has moved from. This
+ * argument is ignored for all other events. The default is null.
+ */
+function simulateMouseEvent(target /*:HTMLElement*/, type /*:String*/,
+ bubbles /*:Boolean*/, cancelable /*:Boolean*/,
+ view /*:Window*/, detail /*:int*/,
+ screenX /*:int*/, screenY /*:int*/,
+ clientX /*:int*/, clientY /*:int*/,
+ ctrlKey /*:Boolean*/, altKey /*:Boolean*/,
+ shiftKey /*:Boolean*/, metaKey /*:Boolean*/,
+ button /*:int*/, relatedTarget /*:HTMLElement*/) /*:Void*/
+{
+
+ //check target
+ if (!target){
+ Y.error("simulateMouseEvent(): Invalid target.");
+ }
+
+ //check event type
+ if (isString(type)){
+ type = type.toLowerCase();
+
+ //make sure it's a supported mouse event
+ if (!mouseEvents[type]){
+ Y.error("simulateMouseEvent(): Event type '" + type + "' not supported.");
+ }
+ } else {
+ Y.error("simulateMouseEvent(): Event type must be a string.");
+ }
+
+ //setup default values
+ if (!isBoolean(bubbles)){
+ bubbles = true; //all mouse events bubble
+ }
+ if (!isBoolean(cancelable)){
+ cancelable = (type != "mousemove"); //mousemove is the only one that can't be cancelled
+ }
+ if (!isObject(view)){
+ view = window; //view is typically window
+ }
+ if (!isNumber(detail)){
+ detail = 1; //number of mouse clicks must be at least one
+ }
+ if (!isNumber(screenX)){
+ screenX = 0;
+ }
+ if (!isNumber(screenY)){
+ screenY = 0;
+ }
+ if (!isNumber(clientX)){
+ clientX = 0;
+ }
+ if (!isNumber(clientY)){
+ clientY = 0;
+ }
+ if (!isBoolean(ctrlKey)){
+ ctrlKey = false;
+ }
+ if (!isBoolean(altKey)){
+ altKey = false;
+ }
+ if (!isBoolean(shiftKey)){
+ shiftKey = false;
+ }
+ if (!isBoolean(metaKey)){
+ metaKey = false;
+ }
+ if (!isNumber(button)){
+ button = 0;
+ }
+
+ //try to create a mouse event
+ var customEvent /*:MouseEvent*/ = null;
+
+ //check for DOM-compliant browsers first
+ if (isFunction(doc.createEvent)){
+
+ customEvent = doc.createEvent("MouseEvents");
+
+ //Safari 2.x (WebKit 418) still doesn't implement initMouseEvent()
+ if (customEvent.initMouseEvent){
+ customEvent.initMouseEvent(type, bubbles, cancelable, view, detail,
+ screenX, screenY, clientX, clientY,
+ ctrlKey, altKey, shiftKey, metaKey,
+ button, relatedTarget);
+ } else { //Safari
+
+ //the closest thing available in Safari 2.x is UIEvents
+ customEvent = doc.createEvent("UIEvents");
+ customEvent.initEvent(type, bubbles, cancelable);
+ customEvent.view = view;
+ customEvent.detail = detail;
+ customEvent.screenX = screenX;
+ customEvent.screenY = screenY;
+ customEvent.clientX = clientX;
+ customEvent.clientY = clientY;
+ customEvent.ctrlKey = ctrlKey;
+ customEvent.altKey = altKey;
+ customEvent.metaKey = metaKey;
+ customEvent.shiftKey = shiftKey;
+ customEvent.button = button;
+ customEvent.relatedTarget = relatedTarget;
+ }
+
+ /*
+ * Check to see if relatedTarget has been assigned. Firefox
+ * versions less than 2.0 don't allow it to be assigned via
+ * initMouseEvent() and the property is readonly after event
+ * creation, so in order to keep YAHOO.util.getRelatedTarget()
+ * working, assign to the IE proprietary toElement property
+ * for mouseout event and fromElement property for mouseover
+ * event.
+ */
+ if (relatedTarget && !customEvent.relatedTarget){
+ if (type == "mouseout"){
+ customEvent.toElement = relatedTarget;
+ } else if (type == "mouseover"){
+ customEvent.fromElement = relatedTarget;
+ }
+ }
+
+ //fire the event
+ target.dispatchEvent(customEvent);
+
+ } else if (isObject(doc.createEventObject)){ //IE
+
+ //create an IE event object
+ customEvent = doc.createEventObject();
+
+ //assign available properties
+ customEvent.bubbles = bubbles;
+ customEvent.cancelable = cancelable;
+ customEvent.view = view;
+ customEvent.detail = detail;
+ customEvent.screenX = screenX;
+ customEvent.screenY = screenY;
+ customEvent.clientX = clientX;
+ customEvent.clientY = clientY;
+ customEvent.ctrlKey = ctrlKey;
+ customEvent.altKey = altKey;
+ customEvent.metaKey = metaKey;
+ customEvent.shiftKey = shiftKey;
+
+ //fix button property for IE's wacky implementation
+ switch(button){
+ case 0:
+ customEvent.button = 1;
+ break;
+ case 1:
+ customEvent.button = 4;
+ break;
+ case 2:
+ //leave as is
+ break;
+ default:
+ customEvent.button = 0;
+ }
+
+ /*
+ * Have to use relatedTarget because IE won't allow assignment
+ * to toElement or fromElement on generic events. This keeps
+ * YAHOO.util.customEvent.getRelatedTarget() functional.
+ */
+ customEvent.relatedTarget = relatedTarget;
+
+ //fire the event
+ target.fireEvent("on" + type, customEvent);
+
+ } else {
+ Y.error("simulateMouseEvent(): No event simulation framework present.");
+ }
+}
+
+
+/**
+ * Simulates the event with the given name on a target.
+ * @param {HTMLElement} target The DOM element that's the target of the event.
+ * @param {String} type The type of event to simulate (i.e., "click").
+ * @param {Object} options (Optional) Extra options to copy onto the event object.
+ * @return {void}
+ * @method simulate
+ * @static
+ */
+Y.Event.simulate = function(target, type, options){
+
+ options = options || {};
+
+ if (mouseEvents[type]){
+ simulateMouseEvent(target, type, options.bubbles,
+ options.cancelable, options.view, options.detail, options.screenX,
+ options.screenY, options.clientX, options.clientY, options.ctrlKey,
+ options.altKey, options.shiftKey, options.metaKey, options.button,
+ options.relatedTarget);
+ } else if (keyEvents[type]){
+ simulateKeyEvent(target, type, options.bubbles,
+ options.cancelable, options.view, options.ctrlKey,
+ options.altKey, options.shiftKey, options.metaKey,
+ options.keyCode, options.charCode);
+ } else {
+ Y.error("simulate(): Event '" + type + "' can't be simulated.");
+ }
+};
+
+/*
+ * @TODO: focus(), blur(), submit()
+ */
+
+})();
+
+
+}, '3.0.0' ,{requires:['event']});
diff --git a/lib/yui/3.0.0/event/event-base-debug.js b/lib/yui/3.0.0/event/event-base-debug.js
new file mode 100644
index 0000000000..a7905852bd
--- /dev/null
+++ b/lib/yui/3.0.0/event/event-base-debug.js
@@ -0,0 +1,1388 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+/*
+ * DOM event listener abstraction layer
+ * @module event
+ * @submodule event-base
+ */
+
+(function() {
+
+
+// Unlike most of the library, this code has to be executed as soon as it is
+// introduced into the page -- and it should only be executed one time
+// regardless of the number of instances that use it.
+
+var GLOBAL_ENV = YUI.Env,
+
+ C = YUI.config,
+
+ D = C.doc,
+
+ POLL_INTERVAL = C.pollInterval || 40,
+
+ _ready = function(e) {
+ GLOBAL_ENV._ready();
+ };
+
+ if (!GLOBAL_ENV._ready) {
+
+ GLOBAL_ENV._ready = function() {
+ if (!GLOBAL_ENV.DOMReady) {
+ GLOBAL_ENV.DOMReady=true;
+
+ // Remove the DOMContentLoaded (FF/Opera/Safari)
+ if (D.removeEventListener) {
+ D.removeEventListener("DOMContentLoaded", _ready, false);
+ }
+ }
+ };
+
+ // create custom event
+
+/*! DOMReady: based on work by: Dean Edwards/John Resig/Matthias Miller/Diego Perini */
+
+ // Internet Explorer: use the readyState of a defered script.
+ // This isolates what appears to be a safe moment to manipulate
+ // the DOM prior to when the document's readyState suggests
+ // it is safe to do so.
+ if (navigator.userAgent.match(/MSIE/)) {
+
+ if (self !== self.top) {
+ document.onreadystatechange = function() {
+ if (document.readyState == 'complete') {
+ document.onreadystatechange = null;
+ _ready();
+ }
+ };
+ } else {
+
+ GLOBAL_ENV._dri = setInterval(function() {
+ try {
+ // throws an error if doc is not ready
+ document.documentElement.doScroll('left');
+ clearInterval(GLOBAL_ENV._dri);
+ GLOBAL_ENV._dri = null;
+ _ready();
+ } catch (ex) {
+ }
+ }, POLL_INTERVAL);
+ }
+
+ // FireFox, Opera, Safari 3+: These browsers provide a event for this
+ // moment.
+ } else {
+ D.addEventListener("DOMContentLoaded", _ready, false);
+ }
+
+ /////////////////////////////////////////////////////////////
+ }
+
+})();
+YUI.add('event-base', function(Y) {
+
+(function() {
+/*
+ * DOM event listener abstraction layer
+ * @module event
+ * @submodule event-base
+ */
+
+var GLOBAL_ENV = YUI.Env,
+
+ yready = function() {
+ Y.fire('domready');
+ };
+
+Y.publish('domready', {
+ fireOnce: true
+});
+
+if (GLOBAL_ENV.DOMReady) {
+ // console.log('DOMReady already fired', 'info', 'event');
+ yready();
+} else {
+ // console.log('setting up before listener', 'info', 'event');
+ // console.log('env: ' + YUI.Env.windowLoaded, 'info', 'event');
+ Y.before(yready, GLOBAL_ENV, "_ready");
+}
+
+})();
+(function() {
+
+/**
+ * Custom event engine, DOM event listener abstraction layer, synthetic DOM
+ * events.
+ * @module event
+ * @submodule event-base
+ */
+
+/**
+ * Wraps a DOM event, properties requiring browser abstraction are
+ * fixed here. Provids a security layer when required.
+ * @class DOMEventFacade
+ * @param ev {Event} the DOM event
+ * @param currentTarget {HTMLElement} the element the listener was attached to
+ * @param wrapper {Event.Custom} the custom event wrapper for this DOM event
+ */
+
+/*
+ * @TODO constants? LEFTBUTTON, MIDDLEBUTTON, RIGHTBUTTON, keys
+ */
+
+/*
+
+var whitelist = {
+ altKey : 1,
+ // "button" : 1, // we supply
+ // "bubbles" : 1, // needed?
+ // "cancelable" : 1, // needed?
+ // "charCode" : 1, // we supply
+ cancelBubble : 1,
+ // "currentTarget" : 1, // we supply
+ ctrlKey : 1,
+ clientX : 1, // needed?
+ clientY : 1, // needed?
+ detail : 1, // not fully implemented
+ // "fromElement" : 1,
+ keyCode : 1,
+ // "height" : 1, // needed?
+ // "initEvent" : 1, // need the init events?
+ // "initMouseEvent" : 1,
+ // "initUIEvent" : 1,
+ // "layerX" : 1, // needed?
+ // "layerY" : 1, // needed?
+ metaKey : 1,
+ // "modifiers" : 1, // needed?
+ // "offsetX" : 1, // needed?
+ // "offsetY" : 1, // needed?
+ // "preventDefault" : 1, // we supply
+ // "reason" : 1, // IE proprietary
+ // "relatedTarget" : 1,
+ // "returnValue" : 1, // needed?
+ shiftKey : 1,
+ // "srcUrn" : 1, // IE proprietary
+ // "srcElement" : 1,
+ // "srcFilter" : 1, IE proprietary
+ // "stopPropagation" : 1, // we supply
+ // "target" : 1,
+ // "timeStamp" : 1, // needed?
+ // "toElement" : 1,
+ type : 1,
+ // "view" : 1,
+ // "which" : 1, // we supply
+ // "width" : 1, // needed?
+ x : 1,
+ y : 1
+},
+
+*/
+
+ var ua = Y.UA,
+
+ /**
+ * webkit key remapping required for Safari < 3.1
+ * @property webkitKeymap
+ * @private
+ */
+ webkitKeymap = {
+ 63232: 38, // up
+ 63233: 40, // down
+ 63234: 37, // left
+ 63235: 39, // right
+ 63276: 33, // page up
+ 63277: 34, // page down
+ 25: 9, // SHIFT-TAB (Safari provides a different key code in
+ // this case, even though the shiftKey modifier is set)
+ 63272: 46, // delete
+ 63273: 36, // home
+ 63275: 35 // end
+ },
+
+ /**
+ * Returns a wrapped node. Intended to be used on event targets,
+ * so it will return the node's parent if the target is a text
+ * node.
+ *
+ * If accessing a property of the node throws an error, this is
+ * probably the anonymous div wrapper Gecko adds inside text
+ * nodes. This likely will only occur when attempting to access
+ * the relatedTarget. In this case, we now return null because
+ * the anonymous div is completely useless and we do not know
+ * what the related target was because we can't even get to
+ * the element's parent node.
+ *
+ * @method resolve
+ * @private
+ */
+ resolve = function(n) {
+ try {
+ if (n && 3 == n.nodeType) {
+ n = n.parentNode;
+ }
+ } catch(e) {
+ return null;
+ }
+
+ return Y.one(n);
+ };
+
+
+// provide a single event with browser abstractions resolved
+//
+// include all properties for both browers?
+// include only DOM2 spec properties?
+// provide browser-specific facade?
+
+Y.DOMEventFacade = function(ev, currentTarget, wrapper) {
+
+ wrapper = wrapper || {};
+
+ var e = ev, ot = currentTarget, d = Y.config.doc, b = d.body,
+ x = e.pageX, y = e.pageY, c, t;
+
+ this.altKey = e.altKey;
+ this.ctrlKey = e.ctrlKey;
+ this.metaKey = e.metaKey;
+ this.shiftKey = e.shiftKey;
+ this.type = e.type;
+ this.clientX = e.clientX;
+ this.clientY = e.clientY;
+
+ //////////////////////////////////////////////////////
+
+ if (!x && 0 !== x) {
+ x = e.clientX || 0;
+ y = e.clientY || 0;
+
+ if (ua.ie) {
+ x += Math.max(d.documentElement.scrollLeft, b.scrollLeft);
+ y += Math.max(d.documentElement.scrollTop, b.scrollTop);
+ }
+ }
+
+ this._yuifacade = true;
+
+ /**
+ * The native event
+ * @property _event
+ */
+ this._event = e;
+
+ /**
+ * The X location of the event on the page (including scroll)
+ * @property pageX
+ * @type int
+ */
+ this.pageX = x;
+
+ /**
+ * The Y location of the event on the page (including scroll)
+ * @property pageY
+ * @type int
+ */
+ this.pageY = y;
+
+ //////////////////////////////////////////////////////
+
+ c = e.keyCode || e.charCode || 0;
+
+ if (ua.webkit && (c in webkitKeymap)) {
+ c = webkitKeymap[c];
+ }
+
+ /**
+ * The keyCode for key events. Uses charCode if keyCode is not available
+ * @property keyCode
+ * @type int
+ */
+ this.keyCode = c;
+
+ /**
+ * The charCode for key events. Same as keyCode
+ * @property charCode
+ * @type int
+ */
+ this.charCode = c;
+
+ //////////////////////////////////////////////////////
+
+ /**
+ * The button that was pushed.
+ * @property button
+ * @type int
+ */
+ this.button = e.which || e.button;
+
+ /**
+ * The button that was pushed. Same as button.
+ * @property which
+ * @type int
+ */
+ this.which = this.button;
+
+ //////////////////////////////////////////////////////
+
+ /**
+ * Node reference for the targeted element
+ * @propery target
+ * @type Node
+ */
+ this.target = resolve(e.target || e.srcElement);
+
+ /**
+ * Node reference for the element that the listener was attached to.
+ * @propery currentTarget
+ * @type Node
+ */
+ this.currentTarget = resolve(ot);
+
+ t = e.relatedTarget;
+
+ if (!t) {
+ if (e.type == "mouseout") {
+ t = e.toElement;
+ } else if (e.type == "mouseover") {
+ t = e.fromElement;
+ }
+ }
+
+ /**
+ * Node reference to the relatedTarget
+ * @propery relatedTarget
+ * @type Node
+ */
+ this.relatedTarget = resolve(t);
+
+ /**
+ * Number representing the direction and velocity of the movement of the mousewheel.
+ * Negative is down, the higher the number, the faster. Applies to the mousewheel event.
+ * @property wheelDelta
+ * @type int
+ */
+ if (e.type == "mousewheel" || e.type == "DOMMouseScroll") {
+ this.wheelDelta = (e.detail) ? (e.detail * -1) : Math.round(e.wheelDelta / 80) || ((e.wheelDelta < 0) ? -1 : 1);
+ }
+
+ //////////////////////////////////////////////////////
+ // methods
+
+ /**
+ * Stops the propagation to the next bubble target
+ * @method stopPropagation
+ */
+ this.stopPropagation = function() {
+ if (e.stopPropagation) {
+ e.stopPropagation();
+ } else {
+ e.cancelBubble = true;
+ }
+ wrapper.stopped = 1;
+ };
+
+ /**
+ * Stops the propagation to the next bubble target and
+ * prevents any additional listeners from being exectued
+ * on the current target.
+ * @method stopImmediatePropagation
+ */
+ this.stopImmediatePropagation = function() {
+ if (e.stopImmediatePropagation) {
+ e.stopImmediatePropagation();
+ } else {
+ this.stopPropagation();
+ }
+ wrapper.stopped = 2;
+ };
+
+ /**
+ * Prevents the event's default behavior
+ * @method preventDefault
+ * @param returnValue {string} sets the returnValue of the event to this value
+ * (rather than the default false value). This can be used to add a customized
+ * confirmation query to the beforeunload event).
+ */
+ this.preventDefault = function(returnValue) {
+ if (e.preventDefault) {
+ e.preventDefault();
+ }
+ e.returnValue = returnValue || false;
+ wrapper.prevented = 1;
+ };
+
+ /**
+ * Stops the event propagation and prevents the default
+ * event behavior.
+ * @method halt
+ * @param immediate {boolean} if true additional listeners
+ * on the current target will not be executed
+ */
+ this.halt = function(immediate) {
+ if (immediate) {
+ this.stopImmediatePropagation();
+ } else {
+ this.stopPropagation();
+ }
+
+ this.preventDefault();
+ };
+
+};
+
+})();
+(function() {
+/**
+ * DOM event listener abstraction layer
+ * @module event
+ * @submodule event-base
+ */
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing. It also tries to automatically remove listeners it
+ * registers during the unload event.
+ *
+ * @class Event
+ * @static
+ */
+
+Y.Env.evt.dom_wrappers = {};
+Y.Env.evt.dom_map = {};
+
+var _eventenv = Y.Env.evt,
+add = YUI.Env.add,
+remove = YUI.Env.remove,
+
+onLoad = function() {
+ YUI.Env.windowLoaded = true;
+ Y.Event._load();
+ remove(window, "load", onLoad);
+},
+
+onUnload = function() {
+ Y.Event._unload();
+ remove(window, "unload", onUnload);
+},
+
+EVENT_READY = 'domready',
+
+COMPAT_ARG = '~yui|2|compat~',
+
+shouldIterate = function(o) {
+ try {
+ return (o && typeof o !== "string" && Y.Lang.isNumber(o.length) && !o.tagName && !o.alert);
+ } catch(ex) {
+ Y.log("collection check failure", "warn", "event");
+ return false;
+ }
+
+},
+
+Event = function() {
+
+ /**
+ * True after the onload event has fired
+ * @property _loadComplete
+ * @type boolean
+ * @static
+ * @private
+ */
+ var _loadComplete = false,
+
+ /**
+ * The number of times to poll after window.onload. This number is
+ * increased if additional late-bound handlers are requested after
+ * the page load.
+ * @property _retryCount
+ * @static
+ * @private
+ */
+ _retryCount = 0,
+
+ /**
+ * onAvailable listeners
+ * @property _avail
+ * @static
+ * @private
+ */
+ _avail = [],
+
+ /**
+ * Custom event wrappers for DOM events. Key is
+ * 'event:' + Element uid stamp + event type
+ * @property _wrappers
+ * @type Y.Event.Custom
+ * @static
+ * @private
+ */
+ _wrappers = _eventenv.dom_wrappers,
+
+ _windowLoadKey = null,
+
+ /**
+ * Custom event wrapper map DOM events. Key is
+ * Element uid stamp. Each item is a hash of custom event
+ * wrappers as provided in the _wrappers collection. This
+ * provides the infrastructure for getListeners.
+ * @property _el_events
+ * @static
+ * @private
+ */
+ _el_events = _eventenv.dom_map;
+
+ return {
+
+ /**
+ * The number of times we should look for elements that are not
+ * in the DOM at the time the event is requested after the document
+ * has been loaded. The default is 1000@amp;40 ms, so it will poll
+ * for 40 seconds or until all outstanding handlers are bound
+ * (whichever comes first).
+ * @property POLL_RETRYS
+ * @type int
+ * @static
+ * @final
+ */
+ POLL_RETRYS: 1000,
+
+ /**
+ * The poll interval in milliseconds
+ * @property POLL_INTERVAL
+ * @type int
+ * @static
+ * @final
+ */
+ POLL_INTERVAL: 40,
+
+ /**
+ * addListener/removeListener can throw errors in unexpected scenarios.
+ * These errors are suppressed, the method returns false, and this property
+ * is set
+ * @property lastError
+ * @static
+ * @type Error
+ */
+ lastError: null,
+
+
+ /**
+ * poll handle
+ * @property _interval
+ * @static
+ * @private
+ */
+ _interval: null,
+
+ /**
+ * document readystate poll handle
+ * @property _dri
+ * @static
+ * @private
+ */
+ _dri: null,
+
+ /**
+ * True when the document is initially usable
+ * @property DOMReady
+ * @type boolean
+ * @static
+ */
+ DOMReady: false,
+
+ /**
+ * @method startInterval
+ * @static
+ * @private
+ */
+ startInterval: function() {
+ var E = Y.Event;
+
+ if (!E._interval) {
+E._interval = setInterval(Y.bind(E._poll, E), E.POLL_INTERVAL);
+ }
+ },
+
+ /**
+ * Executes the supplied callback when the item with the supplied
+ * id is found. This is meant to be used to execute behavior as
+ * soon as possible as the page loads. If you use this after the
+ * initial page load it will poll for a fixed time for the element.
+ * The number of times it will poll and the frequency are
+ * configurable. By default it will poll for 10 seconds.
+ *
+ *
The callback is executed with a single parameter:
+ * the custom object parameter, if provided.
+ *
+ * @method onAvailable
+ *
+ * @param {string||string[]} id the id of the element, or an array
+ * of ids to look for.
+ * @param {function} fn what to execute when the element is found.
+ * @param {object} p_obj an optional object to be passed back as
+ * a parameter to fn.
+ * @param {boolean|object} p_override If set to true, fn will execute
+ * in the context of p_obj, if set to an object it
+ * will execute in the context of that object
+ * @param checkContent {boolean} check child node readiness (onContentReady)
+ * @static
+ * @deprecated Use Y.on("available")
+ */
+ // @TODO fix arguments
+ onAvailable: function(id, fn, p_obj, p_override, checkContent, compat) {
+
+ var a = Y.Array(id), i, availHandle;
+
+ // Y.log('onAvailable registered for: ' + id);
+
+ for (i=0; iThe callback is executed with a single parameter:
+ * the custom object parameter, if provided.
+ *
+ * @method onContentReady
+ *
+ * @param {string} id the id of the element to look for.
+ * @param {function} fn what to execute when the element is ready.
+ * @param {object} p_obj an optional object to be passed back as
+ * a parameter to fn.
+ * @param {boolean|object} p_override If set to true, fn will execute
+ * in the context of p_obj. If an object, fn will
+ * exectute in the context of that object
+ *
+ * @static
+ * @deprecated Use Y.on("contentready")
+ */
+ // @TODO fix arguments
+ onContentReady: function(id, fn, p_obj, p_override, compat) {
+ return this.onAvailable(id, fn, p_obj, p_override, true, compat);
+ },
+
+ /**
+ * Adds an event listener
+ *
+ * @method attach
+ *
+ * @param {String} type The type of event to append
+ * @param {Function} fn The method the event invokes
+ * @param {String|HTMLElement|Array|NodeList} el An id, an element
+ * reference, or a collection of ids and/or elements to assign the
+ * listener to.
+ * @param {Object} context optional context object
+ * @param {Boolean|object} args 0..n arguments to pass to the callback
+ * @return {EventHandle} an object to that can be used to detach the listener
+ *
+ * @static
+ */
+
+ attach: function(type, fn, el, context) {
+ return Y.Event._attach(Y.Array(arguments, 0, true));
+ },
+
+ _createWrapper: function (el, type, capture, compat, facade) {
+
+ var ek = Y.stamp(el),
+ key = 'event:' + ek + type,
+ cewrapper;
+
+
+ if (false === facade) {
+ key += 'native';
+ }
+ if (capture) {
+ key += 'capture';
+ }
+
+
+ cewrapper = _wrappers[key];
+
+
+ if (!cewrapper) {
+ // create CE wrapper
+ cewrapper = Y.publish(key, {
+ silent: true,
+ bubbles: false,
+ contextFn: function() {
+ cewrapper.nodeRef = cewrapper.nodeRef || Y.one(cewrapper.el);
+ return cewrapper.nodeRef;
+ }
+ });
+
+ // for later removeListener calls
+ cewrapper.el = el;
+ cewrapper.key = key;
+ cewrapper.domkey = ek;
+ cewrapper.type = type;
+ cewrapper.fn = function(e) {
+ cewrapper.fire(Y.Event.getEvent(e, el, (compat || (false === facade))));
+ };
+ cewrapper.capture = capture;
+
+ if (el == Y.config.win && type == "load") {
+ // window load happens once
+ cewrapper.fireOnce = true;
+ _windowLoadKey = key;
+ }
+
+ _wrappers[key] = cewrapper;
+ _el_events[ek] = _el_events[ek] || {};
+ _el_events[ek][key] = cewrapper;
+
+ add(el, type, cewrapper.fn, capture);
+ }
+
+ return cewrapper;
+
+ },
+
+ _attach: function(args, config) {
+
+ var compat, E=Y.Event,
+ handles, oEl, cewrapper, context,
+ fireNow = false, ret,
+ type = args[0],
+ fn = args[1],
+ el = args[2] || Y.config.win,
+ facade = config && config.facade,
+ capture = config && config.capture;
+
+ if (args[args.length-1] === COMPAT_ARG) {
+ compat = true;
+ // trimmedArgs.pop();
+ }
+
+ if (!fn || !fn.call) {
+// throw new TypeError(type + " attach call failed, callback undefined");
+Y.log(type + " attach call failed, invalid callback", "error", "event");
+ return false;
+ }
+
+ // The el argument can be an array of elements or element ids.
+ if (shouldIterate(el)) {
+
+ handles=[];
+
+ Y.each(el, function(v, k) {
+ args[2] = v;
+ handles.push(E._attach(args, config));
+ });
+
+ // return (handles.length === 1) ? handles[0] : handles;
+ return new Y.EventHandle(handles);
+
+ // If the el argument is a string, we assume it is
+ // actually the id of the element. If the page is loaded
+ // we convert el to the actual element, otherwise we
+ // defer attaching the event until the element is
+ // ready
+ } else if (Y.Lang.isString(el)) {
+
+ // oEl = (compat) ? Y.DOM.byId(el) : Y.Selector.query(el);
+
+ if (compat) {
+ oEl = Y.DOM.byId(el);
+ } else {
+
+ oEl = Y.Selector.query(el);
+
+ switch (oEl.length) {
+ case 0:
+ oEl = null;
+ break;
+ case 1:
+ oEl = oEl[0];
+ break;
+ default:
+ args[2] = oEl;
+ return E._attach(args, config);
+ }
+ }
+
+ if (oEl) {
+
+ el = oEl;
+
+ // Not found = defer adding the event until the element is available
+ } else {
+
+ // Y.log(el + ' not found');
+ ret = this.onAvailable(el, function() {
+ // Y.log('lazy attach: ' + args);
+
+ ret.handle = E._attach(args, config);
+
+ }, E, true, false, compat);
+
+ return ret;
+
+ }
+ }
+
+ // Element should be an html element or node
+ if (!el) {
+ Y.log("unable to attach event " + type, "warn", "event");
+ return false;
+ }
+
+ if (Y.Node && el instanceof Y.Node) {
+ el = Y.Node.getDOMNode(el);
+ }
+
+ cewrapper = this._createWrapper(el, type, capture, compat, facade);
+
+ if (el == Y.config.win && type == "load") {
+
+ // if the load is complete, fire immediately.
+ // all subscribers, including the current one
+ // will be notified.
+ if (YUI.Env.windowLoaded) {
+ fireNow = true;
+ }
+ }
+
+ if (compat) {
+ args.pop();
+ }
+
+ context = args[3];
+
+ // set context to the Node if not specified
+ // ret = cewrapper.on.apply(cewrapper, trimmedArgs);
+ ret = cewrapper._on(fn, context, (args.length > 4) ? args.slice(4) : null);
+
+ if (fireNow) {
+ cewrapper.fire();
+ }
+
+ return ret;
+
+ },
+
+ /**
+ * Removes an event listener. Supports the signature the event was bound
+ * with, but the preferred way to remove listeners is using the handle
+ * that is returned when using Y.on
+ *
+ * @method detach
+ *
+ * @param {String} type the type of event to remove.
+ * @param {Function} fn the method the event invokes. If fn is
+ * undefined, then all event handlers for the type of event are
+ * removed.
+ * @param {String|HTMLElement|Array|NodeList|EventHandle} el An
+ * event handle, an id, an element reference, or a collection
+ * of ids and/or elements to remove the listener from.
+ * @return {boolean} true if the unbind was successful, false otherwise.
+ * @static
+ */
+ detach: function(type, fn, el, obj) {
+
+ var args=Y.Array(arguments, 0, true), compat, i, l, ok,
+ id, ce;
+
+ if (args[args.length-1] === COMPAT_ARG) {
+ compat = true;
+ // args.pop();
+ }
+
+ if (type && type.detach) {
+ return type.detach();
+ }
+
+ // The el argument can be a string
+ if (typeof el == "string") {
+
+ // el = (compat) ? Y.DOM.byId(el) : Y.all(el);
+ if (compat) {
+ el = Y.DOM.byId(el);
+ } else {
+ el = Y.Selector.query(el);
+ l = el.length;
+ if (l < 1) {
+ el = null;
+ } else if (l == 1) {
+ el = el[0];
+ }
+ }
+ // return Y.Event.detach.apply(Y.Event, args);
+
+ // The el argument can be an array of elements or element ids.
+ }
+
+ if (!el) {
+ return false;
+ }
+
+ if (shouldIterate(el)) {
+
+ ok = true;
+ for (i=0, l=el.length; i 0);
+ }
+
+ // onAvailable
+ notAvail = [];
+
+ executeItem = function (el, item) {
+
+ var context, ov = item.override;
+
+ if (item.compat) {
+
+ if (item.override) {
+ if (ov === true) {
+ context = item.obj;
+ } else {
+ context = ov;
+ }
+ } else {
+ context = el;
+ }
+
+ item.fn.call(context, item.obj);
+
+ } else {
+ context = item.obj || Y.one(el);
+ item.fn.apply(context, (Y.Lang.isArray(ov)) ? ov : []);
+ }
+
+ };
+
+
+ // onAvailable
+ for (i=0,len=_avail.length; i 4 ? Y.Array(arguments, 4, true) : [];
+ return Y.Event.onAvailable.call(Y.Event, id, fn, o, a);
+ }
+};
+
+/**
+ * Executes the callback as soon as the specified element
+ * is detected in the DOM with a nextSibling property
+ * (indicating that the element's children are available)
+ * @event contentready
+ * @param type {string} 'contentready'
+ * @param fn {function} the callback function to execute.
+ * @param el {string|HTMLElement|collection} the element(s) to attach
+ * @param context optional argument that specifies what 'this' refers to.
+ * @param args* 0..n additional arguments to pass on to the callback function.
+ * These arguments will be added after the event object.
+ * @return {EventHandle} the detach handle
+ * @for YUI
+ */
+Y.Env.evt.plugins.contentready = {
+ on: function(type, fn, id, o) {
+ var a = arguments.length > 4 ? Y.Array(arguments, 4, true) : [];
+ return Y.Event.onContentReady.call(Y.Event, id, fn, o, a);
+ }
+};
+
+
+}, '3.0.0' ,{requires:['event-custom-base']});
diff --git a/lib/yui/3.0.0/event/event-base-min.js b/lib/yui/3.0.0/event/event-base-min.js
new file mode 100644
index 0000000000..863aa7e7f0
--- /dev/null
+++ b/lib/yui/3.0.0/event/event-base-min.js
@@ -0,0 +1,11 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+(function(){var GLOBAL_ENV=YUI.Env,C=YUI.config,D=C.doc,POLL_INTERVAL=C.pollInterval||40,_ready=function(e){GLOBAL_ENV._ready();};if(!GLOBAL_ENV._ready){GLOBAL_ENV._ready=function(){if(!GLOBAL_ENV.DOMReady){GLOBAL_ENV.DOMReady=true;if(D.removeEventListener){D.removeEventListener("DOMContentLoaded",_ready,false);}}};
+/* DOMReady: based on work by: Dean Edwards/John Resig/Matthias Miller/Diego Perini */
+if(navigator.userAgent.match(/MSIE/)){if(self!==self.top){document.onreadystatechange=function(){if(document.readyState=="complete"){document.onreadystatechange=null;_ready();}};}else{GLOBAL_ENV._dri=setInterval(function(){try{document.documentElement.doScroll("left");clearInterval(GLOBAL_ENV._dri);GLOBAL_ENV._dri=null;_ready();}catch(ex){}},POLL_INTERVAL);}}else{D.addEventListener("DOMContentLoaded",_ready,false);}}})();YUI.add("event-base",function(A){(function(){var C=YUI.Env,B=function(){A.fire("domready");};A.publish("domready",{fireOnce:true});if(C.DOMReady){B();}else{A.before(B,C,"_ready");}})();(function(){var C=A.UA,B={63232:38,63233:40,63234:37,63235:39,63276:33,63277:34,25:9,63272:46,63273:36,63275:35},D=function(F){try{if(F&&3==F.nodeType){F=F.parentNode;}}catch(E){return null;}return A.one(F);};A.DOMEventFacade=function(L,F,E){E=E||{};var H=L,G=F,I=A.config.doc,M=I.body,N=H.pageX,K=H.pageY,J,O;this.altKey=H.altKey;this.ctrlKey=H.ctrlKey;this.metaKey=H.metaKey;this.shiftKey=H.shiftKey;this.type=H.type;this.clientX=H.clientX;this.clientY=H.clientY;if(!N&&0!==N){N=H.clientX||0;K=H.clientY||0;if(C.ie){N+=Math.max(I.documentElement.scrollLeft,M.scrollLeft);K+=Math.max(I.documentElement.scrollTop,M.scrollTop);}}this._yuifacade=true;this._event=H;this.pageX=N;this.pageY=K;J=H.keyCode||H.charCode||0;if(C.webkit&&(J in B)){J=B[J];}this.keyCode=J;this.charCode=J;this.button=H.which||H.button;this.which=this.button;this.target=D(H.target||H.srcElement);this.currentTarget=D(G);O=H.relatedTarget;if(!O){if(H.type=="mouseout"){O=H.toElement;}else{if(H.type=="mouseover"){O=H.fromElement;}}}this.relatedTarget=D(O);if(H.type=="mousewheel"||H.type=="DOMMouseScroll"){this.wheelDelta=(H.detail)?(H.detail*-1):Math.round(H.wheelDelta/80)||((H.wheelDelta<0)?-1:1);}this.stopPropagation=function(){if(H.stopPropagation){H.stopPropagation();}else{H.cancelBubble=true;}E.stopped=1;};this.stopImmediatePropagation=function(){if(H.stopImmediatePropagation){H.stopImmediatePropagation();}else{this.stopPropagation();}E.stopped=2;};this.preventDefault=function(P){if(H.preventDefault){H.preventDefault();}H.returnValue=P||false;E.prevented=1;};this.halt=function(P){if(P){this.stopImmediatePropagation();}else{this.stopPropagation();}this.preventDefault();};};})();(function(){A.Env.evt.dom_wrappers={};A.Env.evt.dom_map={};var H=A.Env.evt,J=YUI.Env.add,D=YUI.Env.remove,G=function(){YUI.Env.windowLoaded=true;A.Event._load();D(window,"load",G);},B=function(){A.Event._unload();D(window,"unload",B);},C="domready",E="~yui|2|compat~",F=function(L){try{return(L&&typeof L!=="string"&&A.Lang.isNumber(L.length)&&!L.tagName&&!L.alert);}catch(K){return false;}},I=function(){var M=false,N=0,L=[],O=H.dom_wrappers,K=null,P=H.dom_map;return{POLL_RETRYS:1000,POLL_INTERVAL:40,lastError:null,_interval:null,_dri:null,DOMReady:false,startInterval:function(){var Q=A.Event;if(!Q._interval){Q._interval=setInterval(A.bind(Q._poll,Q),Q.POLL_INTERVAL);}},onAvailable:function(Q,U,Y,R,V,X){var W=A.Array(Q),S,T;for(S=0;S4)?W.slice(4):null);if(T){Z.fire();}return V;},detach:function(X,Z,S,U){var W=A.Array(arguments,0,true),a,V,T,Y,Q,R;if(W[W.length-1]===E){a=true;}if(X&&X.detach){return X.detach();}if(typeof S=="string"){if(a){S=A.DOM.byId(S);}else{S=A.Selector.query(S);T=S.length;if(T<1){S=null;}else{if(T==1){S=S[0];}}}}if(!S){return false;}if(F(S)){Y=true;for(V=0,T=S.length;V0);}U=[];W=function(Z,a){var Y,X=a.override;if(a.compat){if(a.override){if(X===true){Y=a.obj;}else{Y=X;}}else{Y=Z;}a.fn.call(Y,a.obj);}else{Y=a.obj||A.one(Z);a.fn.apply(Y,(A.Lang.isArray(X))?X:[]);}};for(R=0,Q=L.length;R4?A.Array(arguments,4,true):[];return A.Event.onAvailable.call(A.Event,F,C,E,B);}};A.Env.evt.plugins.contentready={on:function(D,C,F,E){var B=arguments.length>4?A.Array(arguments,4,true):[];return A.Event.onContentReady.call(A.Event,F,C,E,B);}};},"3.0.0",{requires:["event-custom-base"]});
\ No newline at end of file
diff --git a/lib/yui/3.0.0/event/event-base.js b/lib/yui/3.0.0/event/event-base.js
new file mode 100644
index 0000000000..43cf77db31
--- /dev/null
+++ b/lib/yui/3.0.0/event/event-base.js
@@ -0,0 +1,1378 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+/*
+ * DOM event listener abstraction layer
+ * @module event
+ * @submodule event-base
+ */
+
+(function() {
+
+
+// Unlike most of the library, this code has to be executed as soon as it is
+// introduced into the page -- and it should only be executed one time
+// regardless of the number of instances that use it.
+
+var GLOBAL_ENV = YUI.Env,
+
+ C = YUI.config,
+
+ D = C.doc,
+
+ POLL_INTERVAL = C.pollInterval || 40,
+
+ _ready = function(e) {
+ GLOBAL_ENV._ready();
+ };
+
+ if (!GLOBAL_ENV._ready) {
+
+ GLOBAL_ENV._ready = function() {
+ if (!GLOBAL_ENV.DOMReady) {
+ GLOBAL_ENV.DOMReady=true;
+
+ // Remove the DOMContentLoaded (FF/Opera/Safari)
+ if (D.removeEventListener) {
+ D.removeEventListener("DOMContentLoaded", _ready, false);
+ }
+ }
+ };
+
+ // create custom event
+
+/*! DOMReady: based on work by: Dean Edwards/John Resig/Matthias Miller/Diego Perini */
+
+ // Internet Explorer: use the readyState of a defered script.
+ // This isolates what appears to be a safe moment to manipulate
+ // the DOM prior to when the document's readyState suggests
+ // it is safe to do so.
+ if (navigator.userAgent.match(/MSIE/)) {
+
+ if (self !== self.top) {
+ document.onreadystatechange = function() {
+ if (document.readyState == 'complete') {
+ document.onreadystatechange = null;
+ _ready();
+ }
+ };
+ } else {
+
+ GLOBAL_ENV._dri = setInterval(function() {
+ try {
+ // throws an error if doc is not ready
+ document.documentElement.doScroll('left');
+ clearInterval(GLOBAL_ENV._dri);
+ GLOBAL_ENV._dri = null;
+ _ready();
+ } catch (ex) {
+ }
+ }, POLL_INTERVAL);
+ }
+
+ // FireFox, Opera, Safari 3+: These browsers provide a event for this
+ // moment.
+ } else {
+ D.addEventListener("DOMContentLoaded", _ready, false);
+ }
+
+ /////////////////////////////////////////////////////////////
+ }
+
+})();
+YUI.add('event-base', function(Y) {
+
+(function() {
+/*
+ * DOM event listener abstraction layer
+ * @module event
+ * @submodule event-base
+ */
+
+var GLOBAL_ENV = YUI.Env,
+
+ yready = function() {
+ Y.fire('domready');
+ };
+
+Y.publish('domready', {
+ fireOnce: true
+});
+
+if (GLOBAL_ENV.DOMReady) {
+ // console.log('DOMReady already fired', 'info', 'event');
+ yready();
+} else {
+ // console.log('setting up before listener', 'info', 'event');
+ // console.log('env: ' + YUI.Env.windowLoaded, 'info', 'event');
+ Y.before(yready, GLOBAL_ENV, "_ready");
+}
+
+})();
+(function() {
+
+/**
+ * Custom event engine, DOM event listener abstraction layer, synthetic DOM
+ * events.
+ * @module event
+ * @submodule event-base
+ */
+
+/**
+ * Wraps a DOM event, properties requiring browser abstraction are
+ * fixed here. Provids a security layer when required.
+ * @class DOMEventFacade
+ * @param ev {Event} the DOM event
+ * @param currentTarget {HTMLElement} the element the listener was attached to
+ * @param wrapper {Event.Custom} the custom event wrapper for this DOM event
+ */
+
+/*
+ * @TODO constants? LEFTBUTTON, MIDDLEBUTTON, RIGHTBUTTON, keys
+ */
+
+/*
+
+var whitelist = {
+ altKey : 1,
+ // "button" : 1, // we supply
+ // "bubbles" : 1, // needed?
+ // "cancelable" : 1, // needed?
+ // "charCode" : 1, // we supply
+ cancelBubble : 1,
+ // "currentTarget" : 1, // we supply
+ ctrlKey : 1,
+ clientX : 1, // needed?
+ clientY : 1, // needed?
+ detail : 1, // not fully implemented
+ // "fromElement" : 1,
+ keyCode : 1,
+ // "height" : 1, // needed?
+ // "initEvent" : 1, // need the init events?
+ // "initMouseEvent" : 1,
+ // "initUIEvent" : 1,
+ // "layerX" : 1, // needed?
+ // "layerY" : 1, // needed?
+ metaKey : 1,
+ // "modifiers" : 1, // needed?
+ // "offsetX" : 1, // needed?
+ // "offsetY" : 1, // needed?
+ // "preventDefault" : 1, // we supply
+ // "reason" : 1, // IE proprietary
+ // "relatedTarget" : 1,
+ // "returnValue" : 1, // needed?
+ shiftKey : 1,
+ // "srcUrn" : 1, // IE proprietary
+ // "srcElement" : 1,
+ // "srcFilter" : 1, IE proprietary
+ // "stopPropagation" : 1, // we supply
+ // "target" : 1,
+ // "timeStamp" : 1, // needed?
+ // "toElement" : 1,
+ type : 1,
+ // "view" : 1,
+ // "which" : 1, // we supply
+ // "width" : 1, // needed?
+ x : 1,
+ y : 1
+},
+
+*/
+
+ var ua = Y.UA,
+
+ /**
+ * webkit key remapping required for Safari < 3.1
+ * @property webkitKeymap
+ * @private
+ */
+ webkitKeymap = {
+ 63232: 38, // up
+ 63233: 40, // down
+ 63234: 37, // left
+ 63235: 39, // right
+ 63276: 33, // page up
+ 63277: 34, // page down
+ 25: 9, // SHIFT-TAB (Safari provides a different key code in
+ // this case, even though the shiftKey modifier is set)
+ 63272: 46, // delete
+ 63273: 36, // home
+ 63275: 35 // end
+ },
+
+ /**
+ * Returns a wrapped node. Intended to be used on event targets,
+ * so it will return the node's parent if the target is a text
+ * node.
+ *
+ * If accessing a property of the node throws an error, this is
+ * probably the anonymous div wrapper Gecko adds inside text
+ * nodes. This likely will only occur when attempting to access
+ * the relatedTarget. In this case, we now return null because
+ * the anonymous div is completely useless and we do not know
+ * what the related target was because we can't even get to
+ * the element's parent node.
+ *
+ * @method resolve
+ * @private
+ */
+ resolve = function(n) {
+ try {
+ if (n && 3 == n.nodeType) {
+ n = n.parentNode;
+ }
+ } catch(e) {
+ return null;
+ }
+
+ return Y.one(n);
+ };
+
+
+// provide a single event with browser abstractions resolved
+//
+// include all properties for both browers?
+// include only DOM2 spec properties?
+// provide browser-specific facade?
+
+Y.DOMEventFacade = function(ev, currentTarget, wrapper) {
+
+ wrapper = wrapper || {};
+
+ var e = ev, ot = currentTarget, d = Y.config.doc, b = d.body,
+ x = e.pageX, y = e.pageY, c, t;
+
+ this.altKey = e.altKey;
+ this.ctrlKey = e.ctrlKey;
+ this.metaKey = e.metaKey;
+ this.shiftKey = e.shiftKey;
+ this.type = e.type;
+ this.clientX = e.clientX;
+ this.clientY = e.clientY;
+
+ //////////////////////////////////////////////////////
+
+ if (!x && 0 !== x) {
+ x = e.clientX || 0;
+ y = e.clientY || 0;
+
+ if (ua.ie) {
+ x += Math.max(d.documentElement.scrollLeft, b.scrollLeft);
+ y += Math.max(d.documentElement.scrollTop, b.scrollTop);
+ }
+ }
+
+ this._yuifacade = true;
+
+ /**
+ * The native event
+ * @property _event
+ */
+ this._event = e;
+
+ /**
+ * The X location of the event on the page (including scroll)
+ * @property pageX
+ * @type int
+ */
+ this.pageX = x;
+
+ /**
+ * The Y location of the event on the page (including scroll)
+ * @property pageY
+ * @type int
+ */
+ this.pageY = y;
+
+ //////////////////////////////////////////////////////
+
+ c = e.keyCode || e.charCode || 0;
+
+ if (ua.webkit && (c in webkitKeymap)) {
+ c = webkitKeymap[c];
+ }
+
+ /**
+ * The keyCode for key events. Uses charCode if keyCode is not available
+ * @property keyCode
+ * @type int
+ */
+ this.keyCode = c;
+
+ /**
+ * The charCode for key events. Same as keyCode
+ * @property charCode
+ * @type int
+ */
+ this.charCode = c;
+
+ //////////////////////////////////////////////////////
+
+ /**
+ * The button that was pushed.
+ * @property button
+ * @type int
+ */
+ this.button = e.which || e.button;
+
+ /**
+ * The button that was pushed. Same as button.
+ * @property which
+ * @type int
+ */
+ this.which = this.button;
+
+ //////////////////////////////////////////////////////
+
+ /**
+ * Node reference for the targeted element
+ * @propery target
+ * @type Node
+ */
+ this.target = resolve(e.target || e.srcElement);
+
+ /**
+ * Node reference for the element that the listener was attached to.
+ * @propery currentTarget
+ * @type Node
+ */
+ this.currentTarget = resolve(ot);
+
+ t = e.relatedTarget;
+
+ if (!t) {
+ if (e.type == "mouseout") {
+ t = e.toElement;
+ } else if (e.type == "mouseover") {
+ t = e.fromElement;
+ }
+ }
+
+ /**
+ * Node reference to the relatedTarget
+ * @propery relatedTarget
+ * @type Node
+ */
+ this.relatedTarget = resolve(t);
+
+ /**
+ * Number representing the direction and velocity of the movement of the mousewheel.
+ * Negative is down, the higher the number, the faster. Applies to the mousewheel event.
+ * @property wheelDelta
+ * @type int
+ */
+ if (e.type == "mousewheel" || e.type == "DOMMouseScroll") {
+ this.wheelDelta = (e.detail) ? (e.detail * -1) : Math.round(e.wheelDelta / 80) || ((e.wheelDelta < 0) ? -1 : 1);
+ }
+
+ //////////////////////////////////////////////////////
+ // methods
+
+ /**
+ * Stops the propagation to the next bubble target
+ * @method stopPropagation
+ */
+ this.stopPropagation = function() {
+ if (e.stopPropagation) {
+ e.stopPropagation();
+ } else {
+ e.cancelBubble = true;
+ }
+ wrapper.stopped = 1;
+ };
+
+ /**
+ * Stops the propagation to the next bubble target and
+ * prevents any additional listeners from being exectued
+ * on the current target.
+ * @method stopImmediatePropagation
+ */
+ this.stopImmediatePropagation = function() {
+ if (e.stopImmediatePropagation) {
+ e.stopImmediatePropagation();
+ } else {
+ this.stopPropagation();
+ }
+ wrapper.stopped = 2;
+ };
+
+ /**
+ * Prevents the event's default behavior
+ * @method preventDefault
+ * @param returnValue {string} sets the returnValue of the event to this value
+ * (rather than the default false value). This can be used to add a customized
+ * confirmation query to the beforeunload event).
+ */
+ this.preventDefault = function(returnValue) {
+ if (e.preventDefault) {
+ e.preventDefault();
+ }
+ e.returnValue = returnValue || false;
+ wrapper.prevented = 1;
+ };
+
+ /**
+ * Stops the event propagation and prevents the default
+ * event behavior.
+ * @method halt
+ * @param immediate {boolean} if true additional listeners
+ * on the current target will not be executed
+ */
+ this.halt = function(immediate) {
+ if (immediate) {
+ this.stopImmediatePropagation();
+ } else {
+ this.stopPropagation();
+ }
+
+ this.preventDefault();
+ };
+
+};
+
+})();
+(function() {
+/**
+ * DOM event listener abstraction layer
+ * @module event
+ * @submodule event-base
+ */
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing. It also tries to automatically remove listeners it
+ * registers during the unload event.
+ *
+ * @class Event
+ * @static
+ */
+
+Y.Env.evt.dom_wrappers = {};
+Y.Env.evt.dom_map = {};
+
+var _eventenv = Y.Env.evt,
+add = YUI.Env.add,
+remove = YUI.Env.remove,
+
+onLoad = function() {
+ YUI.Env.windowLoaded = true;
+ Y.Event._load();
+ remove(window, "load", onLoad);
+},
+
+onUnload = function() {
+ Y.Event._unload();
+ remove(window, "unload", onUnload);
+},
+
+EVENT_READY = 'domready',
+
+COMPAT_ARG = '~yui|2|compat~',
+
+shouldIterate = function(o) {
+ try {
+ return (o && typeof o !== "string" && Y.Lang.isNumber(o.length) && !o.tagName && !o.alert);
+ } catch(ex) {
+ return false;
+ }
+
+},
+
+Event = function() {
+
+ /**
+ * True after the onload event has fired
+ * @property _loadComplete
+ * @type boolean
+ * @static
+ * @private
+ */
+ var _loadComplete = false,
+
+ /**
+ * The number of times to poll after window.onload. This number is
+ * increased if additional late-bound handlers are requested after
+ * the page load.
+ * @property _retryCount
+ * @static
+ * @private
+ */
+ _retryCount = 0,
+
+ /**
+ * onAvailable listeners
+ * @property _avail
+ * @static
+ * @private
+ */
+ _avail = [],
+
+ /**
+ * Custom event wrappers for DOM events. Key is
+ * 'event:' + Element uid stamp + event type
+ * @property _wrappers
+ * @type Y.Event.Custom
+ * @static
+ * @private
+ */
+ _wrappers = _eventenv.dom_wrappers,
+
+ _windowLoadKey = null,
+
+ /**
+ * Custom event wrapper map DOM events. Key is
+ * Element uid stamp. Each item is a hash of custom event
+ * wrappers as provided in the _wrappers collection. This
+ * provides the infrastructure for getListeners.
+ * @property _el_events
+ * @static
+ * @private
+ */
+ _el_events = _eventenv.dom_map;
+
+ return {
+
+ /**
+ * The number of times we should look for elements that are not
+ * in the DOM at the time the event is requested after the document
+ * has been loaded. The default is 1000@amp;40 ms, so it will poll
+ * for 40 seconds or until all outstanding handlers are bound
+ * (whichever comes first).
+ * @property POLL_RETRYS
+ * @type int
+ * @static
+ * @final
+ */
+ POLL_RETRYS: 1000,
+
+ /**
+ * The poll interval in milliseconds
+ * @property POLL_INTERVAL
+ * @type int
+ * @static
+ * @final
+ */
+ POLL_INTERVAL: 40,
+
+ /**
+ * addListener/removeListener can throw errors in unexpected scenarios.
+ * These errors are suppressed, the method returns false, and this property
+ * is set
+ * @property lastError
+ * @static
+ * @type Error
+ */
+ lastError: null,
+
+
+ /**
+ * poll handle
+ * @property _interval
+ * @static
+ * @private
+ */
+ _interval: null,
+
+ /**
+ * document readystate poll handle
+ * @property _dri
+ * @static
+ * @private
+ */
+ _dri: null,
+
+ /**
+ * True when the document is initially usable
+ * @property DOMReady
+ * @type boolean
+ * @static
+ */
+ DOMReady: false,
+
+ /**
+ * @method startInterval
+ * @static
+ * @private
+ */
+ startInterval: function() {
+ var E = Y.Event;
+
+ if (!E._interval) {
+E._interval = setInterval(Y.bind(E._poll, E), E.POLL_INTERVAL);
+ }
+ },
+
+ /**
+ * Executes the supplied callback when the item with the supplied
+ * id is found. This is meant to be used to execute behavior as
+ * soon as possible as the page loads. If you use this after the
+ * initial page load it will poll for a fixed time for the element.
+ * The number of times it will poll and the frequency are
+ * configurable. By default it will poll for 10 seconds.
+ *
+ *
The callback is executed with a single parameter:
+ * the custom object parameter, if provided.
+ *
+ * @method onAvailable
+ *
+ * @param {string||string[]} id the id of the element, or an array
+ * of ids to look for.
+ * @param {function} fn what to execute when the element is found.
+ * @param {object} p_obj an optional object to be passed back as
+ * a parameter to fn.
+ * @param {boolean|object} p_override If set to true, fn will execute
+ * in the context of p_obj, if set to an object it
+ * will execute in the context of that object
+ * @param checkContent {boolean} check child node readiness (onContentReady)
+ * @static
+ * @deprecated Use Y.on("available")
+ */
+ // @TODO fix arguments
+ onAvailable: function(id, fn, p_obj, p_override, checkContent, compat) {
+
+ var a = Y.Array(id), i, availHandle;
+
+
+ for (i=0; iThe callback is executed with a single parameter:
+ * the custom object parameter, if provided.
+ *
+ * @method onContentReady
+ *
+ * @param {string} id the id of the element to look for.
+ * @param {function} fn what to execute when the element is ready.
+ * @param {object} p_obj an optional object to be passed back as
+ * a parameter to fn.
+ * @param {boolean|object} p_override If set to true, fn will execute
+ * in the context of p_obj. If an object, fn will
+ * exectute in the context of that object
+ *
+ * @static
+ * @deprecated Use Y.on("contentready")
+ */
+ // @TODO fix arguments
+ onContentReady: function(id, fn, p_obj, p_override, compat) {
+ return this.onAvailable(id, fn, p_obj, p_override, true, compat);
+ },
+
+ /**
+ * Adds an event listener
+ *
+ * @method attach
+ *
+ * @param {String} type The type of event to append
+ * @param {Function} fn The method the event invokes
+ * @param {String|HTMLElement|Array|NodeList} el An id, an element
+ * reference, or a collection of ids and/or elements to assign the
+ * listener to.
+ * @param {Object} context optional context object
+ * @param {Boolean|object} args 0..n arguments to pass to the callback
+ * @return {EventHandle} an object to that can be used to detach the listener
+ *
+ * @static
+ */
+
+ attach: function(type, fn, el, context) {
+ return Y.Event._attach(Y.Array(arguments, 0, true));
+ },
+
+ _createWrapper: function (el, type, capture, compat, facade) {
+
+ var ek = Y.stamp(el),
+ key = 'event:' + ek + type,
+ cewrapper;
+
+
+ if (false === facade) {
+ key += 'native';
+ }
+ if (capture) {
+ key += 'capture';
+ }
+
+
+ cewrapper = _wrappers[key];
+
+
+ if (!cewrapper) {
+ // create CE wrapper
+ cewrapper = Y.publish(key, {
+ silent: true,
+ bubbles: false,
+ contextFn: function() {
+ cewrapper.nodeRef = cewrapper.nodeRef || Y.one(cewrapper.el);
+ return cewrapper.nodeRef;
+ }
+ });
+
+ // for later removeListener calls
+ cewrapper.el = el;
+ cewrapper.key = key;
+ cewrapper.domkey = ek;
+ cewrapper.type = type;
+ cewrapper.fn = function(e) {
+ cewrapper.fire(Y.Event.getEvent(e, el, (compat || (false === facade))));
+ };
+ cewrapper.capture = capture;
+
+ if (el == Y.config.win && type == "load") {
+ // window load happens once
+ cewrapper.fireOnce = true;
+ _windowLoadKey = key;
+ }
+
+ _wrappers[key] = cewrapper;
+ _el_events[ek] = _el_events[ek] || {};
+ _el_events[ek][key] = cewrapper;
+
+ add(el, type, cewrapper.fn, capture);
+ }
+
+ return cewrapper;
+
+ },
+
+ _attach: function(args, config) {
+
+ var compat, E=Y.Event,
+ handles, oEl, cewrapper, context,
+ fireNow = false, ret,
+ type = args[0],
+ fn = args[1],
+ el = args[2] || Y.config.win,
+ facade = config && config.facade,
+ capture = config && config.capture;
+
+ if (args[args.length-1] === COMPAT_ARG) {
+ compat = true;
+ // trimmedArgs.pop();
+ }
+
+ if (!fn || !fn.call) {
+// throw new TypeError(type + " attach call failed, callback undefined");
+ return false;
+ }
+
+ // The el argument can be an array of elements or element ids.
+ if (shouldIterate(el)) {
+
+ handles=[];
+
+ Y.each(el, function(v, k) {
+ args[2] = v;
+ handles.push(E._attach(args, config));
+ });
+
+ // return (handles.length === 1) ? handles[0] : handles;
+ return new Y.EventHandle(handles);
+
+ // If the el argument is a string, we assume it is
+ // actually the id of the element. If the page is loaded
+ // we convert el to the actual element, otherwise we
+ // defer attaching the event until the element is
+ // ready
+ } else if (Y.Lang.isString(el)) {
+
+ // oEl = (compat) ? Y.DOM.byId(el) : Y.Selector.query(el);
+
+ if (compat) {
+ oEl = Y.DOM.byId(el);
+ } else {
+
+ oEl = Y.Selector.query(el);
+
+ switch (oEl.length) {
+ case 0:
+ oEl = null;
+ break;
+ case 1:
+ oEl = oEl[0];
+ break;
+ default:
+ args[2] = oEl;
+ return E._attach(args, config);
+ }
+ }
+
+ if (oEl) {
+
+ el = oEl;
+
+ // Not found = defer adding the event until the element is available
+ } else {
+
+ ret = this.onAvailable(el, function() {
+
+ ret.handle = E._attach(args, config);
+
+ }, E, true, false, compat);
+
+ return ret;
+
+ }
+ }
+
+ // Element should be an html element or node
+ if (!el) {
+ return false;
+ }
+
+ if (Y.Node && el instanceof Y.Node) {
+ el = Y.Node.getDOMNode(el);
+ }
+
+ cewrapper = this._createWrapper(el, type, capture, compat, facade);
+
+ if (el == Y.config.win && type == "load") {
+
+ // if the load is complete, fire immediately.
+ // all subscribers, including the current one
+ // will be notified.
+ if (YUI.Env.windowLoaded) {
+ fireNow = true;
+ }
+ }
+
+ if (compat) {
+ args.pop();
+ }
+
+ context = args[3];
+
+ // set context to the Node if not specified
+ // ret = cewrapper.on.apply(cewrapper, trimmedArgs);
+ ret = cewrapper._on(fn, context, (args.length > 4) ? args.slice(4) : null);
+
+ if (fireNow) {
+ cewrapper.fire();
+ }
+
+ return ret;
+
+ },
+
+ /**
+ * Removes an event listener. Supports the signature the event was bound
+ * with, but the preferred way to remove listeners is using the handle
+ * that is returned when using Y.on
+ *
+ * @method detach
+ *
+ * @param {String} type the type of event to remove.
+ * @param {Function} fn the method the event invokes. If fn is
+ * undefined, then all event handlers for the type of event are
+ * removed.
+ * @param {String|HTMLElement|Array|NodeList|EventHandle} el An
+ * event handle, an id, an element reference, or a collection
+ * of ids and/or elements to remove the listener from.
+ * @return {boolean} true if the unbind was successful, false otherwise.
+ * @static
+ */
+ detach: function(type, fn, el, obj) {
+
+ var args=Y.Array(arguments, 0, true), compat, i, l, ok,
+ id, ce;
+
+ if (args[args.length-1] === COMPAT_ARG) {
+ compat = true;
+ // args.pop();
+ }
+
+ if (type && type.detach) {
+ return type.detach();
+ }
+
+ // The el argument can be a string
+ if (typeof el == "string") {
+
+ // el = (compat) ? Y.DOM.byId(el) : Y.all(el);
+ if (compat) {
+ el = Y.DOM.byId(el);
+ } else {
+ el = Y.Selector.query(el);
+ l = el.length;
+ if (l < 1) {
+ el = null;
+ } else if (l == 1) {
+ el = el[0];
+ }
+ }
+ // return Y.Event.detach.apply(Y.Event, args);
+
+ // The el argument can be an array of elements or element ids.
+ }
+
+ if (!el) {
+ return false;
+ }
+
+ if (shouldIterate(el)) {
+
+ ok = true;
+ for (i=0, l=el.length; i 0);
+ }
+
+ // onAvailable
+ notAvail = [];
+
+ executeItem = function (el, item) {
+
+ var context, ov = item.override;
+
+ if (item.compat) {
+
+ if (item.override) {
+ if (ov === true) {
+ context = item.obj;
+ } else {
+ context = ov;
+ }
+ } else {
+ context = el;
+ }
+
+ item.fn.call(context, item.obj);
+
+ } else {
+ context = item.obj || Y.one(el);
+ item.fn.apply(context, (Y.Lang.isArray(ov)) ? ov : []);
+ }
+
+ };
+
+
+ // onAvailable
+ for (i=0,len=_avail.length; i 4 ? Y.Array(arguments, 4, true) : [];
+ return Y.Event.onAvailable.call(Y.Event, id, fn, o, a);
+ }
+};
+
+/**
+ * Executes the callback as soon as the specified element
+ * is detected in the DOM with a nextSibling property
+ * (indicating that the element's children are available)
+ * @event contentready
+ * @param type {string} 'contentready'
+ * @param fn {function} the callback function to execute.
+ * @param el {string|HTMLElement|collection} the element(s) to attach
+ * @param context optional argument that specifies what 'this' refers to.
+ * @param args* 0..n additional arguments to pass on to the callback function.
+ * These arguments will be added after the event object.
+ * @return {EventHandle} the detach handle
+ * @for YUI
+ */
+Y.Env.evt.plugins.contentready = {
+ on: function(type, fn, id, o) {
+ var a = arguments.length > 4 ? Y.Array(arguments, 4, true) : [];
+ return Y.Event.onContentReady.call(Y.Event, id, fn, o, a);
+ }
+};
+
+
+}, '3.0.0' ,{requires:['event-custom-base']});
diff --git a/lib/yui/3.0.0/event/event-debug.js b/lib/yui/3.0.0/event/event-debug.js
new file mode 100644
index 0000000000..9202179e22
--- /dev/null
+++ b/lib/yui/3.0.0/event/event-debug.js
@@ -0,0 +1,2242 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 3.0.0
+build: 1549
+*/
+/*
+ * DOM event listener abstraction layer
+ * @module event
+ * @submodule event-base
+ */
+
+(function() {
+
+
+// Unlike most of the library, this code has to be executed as soon as it is
+// introduced into the page -- and it should only be executed one time
+// regardless of the number of instances that use it.
+
+var GLOBAL_ENV = YUI.Env,
+
+ C = YUI.config,
+
+ D = C.doc,
+
+ POLL_INTERVAL = C.pollInterval || 40,
+
+ _ready = function(e) {
+ GLOBAL_ENV._ready();
+ };
+
+ if (!GLOBAL_ENV._ready) {
+
+ GLOBAL_ENV._ready = function() {
+ if (!GLOBAL_ENV.DOMReady) {
+ GLOBAL_ENV.DOMReady=true;
+
+ // Remove the DOMContentLoaded (FF/Opera/Safari)
+ if (D.removeEventListener) {
+ D.removeEventListener("DOMContentLoaded", _ready, false);
+ }
+ }
+ };
+
+ // create custom event
+
+/*! DOMReady: based on work by: Dean Edwards/John Resig/Matthias Miller/Diego Perini */
+
+ // Internet Explorer: use the readyState of a defered script.
+ // This isolates what appears to be a safe moment to manipulate
+ // the DOM prior to when the document's readyState suggests
+ // it is safe to do so.
+ if (navigator.userAgent.match(/MSIE/)) {
+
+ if (self !== self.top) {
+ document.onreadystatechange = function() {
+ if (document.readyState == 'complete') {
+ document.onreadystatechange = null;
+ _ready();
+ }
+ };
+ } else {
+
+ GLOBAL_ENV._dri = setInterval(function() {
+ try {
+ // throws an error if doc is not ready
+ document.documentElement.doScroll('left');
+ clearInterval(GLOBAL_ENV._dri);
+ GLOBAL_ENV._dri = null;
+ _ready();
+ } catch (ex) {
+ }
+ }, POLL_INTERVAL);
+ }
+
+ // FireFox, Opera, Safari 3+: These browsers provide a event for this
+ // moment.
+ } else {
+ D.addEventListener("DOMContentLoaded", _ready, false);
+ }
+
+ /////////////////////////////////////////////////////////////
+ }
+
+})();
+YUI.add('event-base', function(Y) {
+
+(function() {
+/*
+ * DOM event listener abstraction layer
+ * @module event
+ * @submodule event-base
+ */
+
+var GLOBAL_ENV = YUI.Env,
+
+ yready = function() {
+ Y.fire('domready');
+ };
+
+Y.publish('domready', {
+ fireOnce: true
+});
+
+if (GLOBAL_ENV.DOMReady) {
+ // console.log('DOMReady already fired', 'info', 'event');
+ yready();
+} else {
+ // console.log('setting up before listener', 'info', 'event');
+ // console.log('env: ' + YUI.Env.windowLoaded, 'info', 'event');
+ Y.before(yready, GLOBAL_ENV, "_ready");
+}
+
+})();
+(function() {
+
+/**
+ * Custom event engine, DOM event listener abstraction layer, synthetic DOM
+ * events.
+ * @module event
+ * @submodule event-base
+ */
+
+/**
+ * Wraps a DOM event, properties requiring browser abstraction are
+ * fixed here. Provids a security layer when required.
+ * @class DOMEventFacade
+ * @param ev {Event} the DOM event
+ * @param currentTarget {HTMLElement} the element the listener was attached to
+ * @param wrapper {Event.Custom} the custom event wrapper for this DOM event
+ */
+
+/*
+ * @TODO constants? LEFTBUTTON, MIDDLEBUTTON, RIGHTBUTTON, keys
+ */
+
+/*
+
+var whitelist = {
+ altKey : 1,
+ // "button" : 1, // we supply
+ // "bubbles" : 1, // needed?
+ // "cancelable" : 1, // needed?
+ // "charCode" : 1, // we supply
+ cancelBubble : 1,
+ // "currentTarget" : 1, // we supply
+ ctrlKey : 1,
+ clientX : 1, // needed?
+ clientY : 1, // needed?
+ detail : 1, // not fully implemented
+ // "fromElement" : 1,
+ keyCode : 1,
+ // "height" : 1, // needed?
+ // "initEvent" : 1, // need the init events?
+ // "initMouseEvent" : 1,
+ // "initUIEvent" : 1,
+ // "layerX" : 1, // needed?
+ // "layerY" : 1, // needed?
+ metaKey : 1,
+ // "modifiers" : 1, // needed?
+ // "offsetX" : 1, // needed?
+ // "offsetY" : 1, // needed?
+ // "preventDefault" : 1, // we supply
+ // "reason" : 1, // IE proprietary
+ // "relatedTarget" : 1,
+ // "returnValue" : 1, // needed?
+ shiftKey : 1,
+ // "srcUrn" : 1, // IE proprietary
+ // "srcElement" : 1,
+ // "srcFilter" : 1, IE proprietary
+ // "stopPropagation" : 1, // we supply
+ // "target" : 1,
+ // "timeStamp" : 1, // needed?
+ // "toElement" : 1,
+ type : 1,
+ // "view" : 1,
+ // "which" : 1, // we supply
+ // "width" : 1, // needed?
+ x : 1,
+ y : 1
+},
+
+*/
+
+ var ua = Y.UA,
+
+ /**
+ * webkit key remapping required for Safari < 3.1
+ * @property webkitKeymap
+ * @private
+ */
+ webkitKeymap = {
+ 63232: 38, // up
+ 63233: 40, // down
+ 63234: 37, // left
+ 63235: 39, // right
+ 63276: 33, // page up
+ 63277: 34, // page down
+ 25: 9, // SHIFT-TAB (Safari provides a different key code in
+ // this case, even though the shiftKey modifier is set)
+ 63272: 46, // delete
+ 63273: 36, // home
+ 63275: 35 // end
+ },
+
+ /**
+ * Returns a wrapped node. Intended to be used on event targets,
+ * so it will return the node's parent if the target is a text
+ * node.
+ *
+ * If accessing a property of the node throws an error, this is
+ * probably the anonymous div wrapper Gecko adds inside text
+ * nodes. This likely will only occur when attempting to access
+ * the relatedTarget. In this case, we now return null because
+ * the anonymous div is completely useless and we do not know
+ * what the related target was because we can't even get to
+ * the element's parent node.
+ *
+ * @method resolve
+ * @private
+ */
+ resolve = function(n) {
+ try {
+ if (n && 3 == n.nodeType) {
+ n = n.parentNode;
+ }
+ } catch(e) {
+ return null;
+ }
+
+ return Y.one(n);
+ };
+
+
+// provide a single event with browser abstractions resolved
+//
+// include all properties for both browers?
+// include only DOM2 spec properties?
+// provide browser-specific facade?
+
+Y.DOMEventFacade = function(ev, currentTarget, wrapper) {
+
+ wrapper = wrapper || {};
+
+ var e = ev, ot = currentTarget, d = Y.config.doc, b = d.body,
+ x = e.pageX, y = e.pageY, c, t;
+
+ this.altKey = e.altKey;
+ this.ctrlKey = e.ctrlKey;
+ this.metaKey = e.metaKey;
+ this.shiftKey = e.shiftKey;
+ this.type = e.type;
+ this.clientX = e.clientX;
+ this.clientY = e.clientY;
+
+ //////////////////////////////////////////////////////
+
+ if (!x && 0 !== x) {
+ x = e.clientX || 0;
+ y = e.clientY || 0;
+
+ if (ua.ie) {
+ x += Math.max(d.documentElement.scrollLeft, b.scrollLeft);
+ y += Math.max(d.documentElement.scrollTop, b.scrollTop);
+ }
+ }
+
+ this._yuifacade = true;
+
+ /**
+ * The native event
+ * @property _event
+ */
+ this._event = e;
+
+ /**
+ * The X location of the event on the page (including scroll)
+ * @property pageX
+ * @type int
+ */
+ this.pageX = x;
+
+ /**
+ * The Y location of the event on the page (including scroll)
+ * @property pageY
+ * @type int
+ */
+ this.pageY = y;
+
+ //////////////////////////////////////////////////////
+
+ c = e.keyCode || e.charCode || 0;
+
+ if (ua.webkit && (c in webkitKeymap)) {
+ c = webkitKeymap[c];
+ }
+
+ /**
+ * The keyCode for key events. Uses charCode if keyCode is not available
+ * @property keyCode
+ * @type int
+ */
+ this.keyCode = c;
+
+ /**
+ * The charCode for key events. Same as keyCode
+ * @property charCode
+ * @type int
+ */
+ this.charCode = c;
+
+ //////////////////////////////////////////////////////
+
+ /**
+ * The button that was pushed.
+ * @property button
+ * @type int
+ */
+ this.button = e.which || e.button;
+
+ /**
+ * The button that was pushed. Same as button.
+ * @property which
+ * @type int
+ */
+ this.which = this.button;
+
+ //////////////////////////////////////////////////////
+
+ /**
+ * Node reference for the targeted element
+ * @propery target
+ * @type Node
+ */
+ this.target = resolve(e.target || e.srcElement);
+
+ /**
+ * Node reference for the element that the listener was attached to.
+ * @propery currentTarget
+ * @type Node
+ */
+ this.currentTarget = resolve(ot);
+
+ t = e.relatedTarget;
+
+ if (!t) {
+ if (e.type == "mouseout") {
+ t = e.toElement;
+ } else if (e.type == "mouseover") {
+ t = e.fromElement;
+ }
+ }
+
+ /**
+ * Node reference to the relatedTarget
+ * @propery relatedTarget
+ * @type Node
+ */
+ this.relatedTarget = resolve(t);
+
+ /**
+ * Number representing the direction and velocity of the movement of the mousewheel.
+ * Negative is down, the higher the number, the faster. Applies to the mousewheel event.
+ * @property wheelDelta
+ * @type int
+ */
+ if (e.type == "mousewheel" || e.type == "DOMMouseScroll") {
+ this.wheelDelta = (e.detail) ? (e.detail * -1) : Math.round(e.wheelDelta / 80) || ((e.wheelDelta < 0) ? -1 : 1);
+ }
+
+ //////////////////////////////////////////////////////
+ // methods
+
+ /**
+ * Stops the propagation to the next bubble target
+ * @method stopPropagation
+ */
+ this.stopPropagation = function() {
+ if (e.stopPropagation) {
+ e.stopPropagation();
+ } else {
+ e.cancelBubble = true;
+ }
+ wrapper.stopped = 1;
+ };
+
+ /**
+ * Stops the propagation to the next bubble target and
+ * prevents any additional listeners from being exectued
+ * on the current target.
+ * @method stopImmediatePropagation
+ */
+ this.stopImmediatePropagation = function() {
+ if (e.stopImmediatePropagation) {
+ e.stopImmediatePropagation();
+ } else {
+ this.stopPropagation();
+ }
+ wrapper.stopped = 2;
+ };
+
+ /**
+ * Prevents the event's default behavior
+ * @method preventDefault
+ * @param returnValue {string} sets the returnValue of the event to this value
+ * (rather than the default false value). This can be used to add a customized
+ * confirmation query to the beforeunload event).
+ */
+ this.preventDefault = function(returnValue) {
+ if (e.preventDefault) {
+ e.preventDefault();
+ }
+ e.returnValue = returnValue || false;
+ wrapper.prevented = 1;
+ };
+
+ /**
+ * Stops the event propagation and prevents the default
+ * event behavior.
+ * @method halt
+ * @param immediate {boolean} if true additional listeners
+ * on the current target will not be executed
+ */
+ this.halt = function(immediate) {
+ if (immediate) {
+ this.stopImmediatePropagation();
+ } else {
+ this.stopPropagation();
+ }
+
+ this.preventDefault();
+ };
+
+};
+
+})();
+(function() {
+/**
+ * DOM event listener abstraction layer
+ * @module event
+ * @submodule event-base
+ */
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing. It also tries to automatically remove listeners it
+ * registers during the unload event.
+ *
+ * @class Event
+ * @static
+ */
+
+Y.Env.evt.dom_wrappers = {};
+Y.Env.evt.dom_map = {};
+
+var _eventenv = Y.Env.evt,
+add = YUI.Env.add,
+remove = YUI.Env.remove,
+
+onLoad = function() {
+ YUI.Env.windowLoaded = true;
+ Y.Event._load();
+ remove(window, "load", onLoad);
+},
+
+onUnload = function() {
+ Y.Event._unload();
+ remove(window, "unload", onUnload);
+},
+
+EVENT_READY = 'domready',
+
+COMPAT_ARG = '~yui|2|compat~',
+
+shouldIterate = function(o) {
+ try {
+ return (o && typeof o !== "string" && Y.Lang.isNumber(o.length) && !o.tagName && !o.alert);
+ } catch(ex) {
+ Y.log("collection check failure", "warn", "event");
+ return false;
+ }
+
+},
+
+Event = function() {
+
+ /**
+ * True after the onload event has fired
+ * @property _loadComplete
+ * @type boolean
+ * @static
+ * @private
+ */
+ var _loadComplete = false,
+
+ /**
+ * The number of times to poll after window.onload. This number is
+ * increased if additional late-bound handlers are requested after
+ * the page load.
+ * @property _retryCount
+ * @static
+ * @private
+ */
+ _retryCount = 0,
+
+ /**
+ * onAvailable listeners
+ * @property _avail
+ * @static
+ * @private
+ */
+ _avail = [],
+
+ /**
+ * Custom event wrappers for DOM events. Key is
+ * 'event:' + Element uid stamp + event type
+ * @property _wrappers
+ * @type Y.Event.Custom
+ * @static
+ * @private
+ */
+ _wrappers = _eventenv.dom_wrappers,
+
+ _windowLoadKey = null,
+
+ /**
+ * Custom event wrapper map DOM events. Key is
+ * Element uid stamp. Each item is a hash of custom event
+ * wrappers as provided in the _wrappers collection. This
+ * provides the infrastructure for getListeners.
+ * @property _el_events
+ * @static
+ * @private
+ */
+ _el_events = _eventenv.dom_map;
+
+ return {
+
+ /**
+ * The number of times we should look for elements that are not
+ * in the DOM at the time the event is requested after the document
+ * has been loaded. The default is 1000@amp;40 ms, so it will poll
+ * for 40 seconds or until all outstanding handlers are bound
+ * (whichever comes first).
+ * @property POLL_RETRYS
+ * @type int
+ * @static
+ * @final
+ */
+ POLL_RETRYS: 1000,
+
+ /**
+ * The poll interval in milliseconds
+ * @property POLL_INTERVAL
+ * @type int
+ * @static
+ * @final
+ */
+ POLL_INTERVAL: 40,
+
+ /**
+ * addListener/removeListener can throw errors in unexpected scenarios.
+ * These errors are suppressed, the method returns false, and this property
+ * is set
+ * @property lastError
+ * @static
+ * @type Error
+ */
+ lastError: null,
+
+
+ /**
+ * poll handle
+ * @property _interval
+ * @static
+ * @private
+ */
+ _interval: null,
+
+ /**
+ * document readystate poll handle
+ * @property _dri
+ * @static
+ * @private
+ */
+ _dri: null,
+
+ /**
+ * True when the document is initially usable
+ * @property DOMReady
+ * @type boolean
+ * @static
+ */
+ DOMReady: false,
+
+ /**
+ * @method startInterval
+ * @static
+ * @private
+ */
+ startInterval: function() {
+ var E = Y.Event;
+
+ if (!E._interval) {
+E._interval = setInterval(Y.bind(E._poll, E), E.POLL_INTERVAL);
+ }
+ },
+
+ /**
+ * Executes the supplied callback when the item with the supplied
+ * id is found. This is meant to be used to execute behavior as
+ * soon as possible as the page loads. If you use this after the
+ * initial page load it will poll for a fixed time for the element.
+ * The number of times it will poll and the frequency are
+ * configurable. By default it will poll for 10 seconds.
+ *
+ *
The callback is executed with a single parameter:
+ * the custom object parameter, if provided.
+ *
+ * @method onAvailable
+ *
+ * @param {string||string[]} id the id of the element, or an array
+ * of ids to look for.
+ * @param {function} fn what to execute when the element is found.
+ * @param {object} p_obj an optional object to be passed back as
+ * a parameter to fn.
+ * @param {boolean|object} p_override If set to true, fn will execute
+ * in the context of p_obj, if set to an object it
+ * will execute in the context of that object
+ * @param checkContent {boolean} check child node readiness (onContentReady)
+ * @static
+ * @deprecated Use Y.on("available")
+ */
+ // @TODO fix arguments
+ onAvailable: function(id, fn, p_obj, p_override, checkContent, compat) {
+
+ var a = Y.Array(id), i, availHandle;
+
+ // Y.log('onAvailable registered for: ' + id);
+
+ for (i=0; iThe callback is executed with a single parameter:
+ * the custom object parameter, if provided.
+ *
+ * @method onContentReady
+ *
+ * @param {string} id the id of the element to look for.
+ * @param {function} fn what to execute when the element is ready.
+ * @param {object} p_obj an optional object to be passed back as
+ * a parameter to fn.
+ * @param {boolean|object} p_override If set to true, fn will execute
+ * in the context of p_obj. If an object, fn will
+ * exectute in the context of that object
+ *
+ * @static
+ * @deprecated Use Y.on("contentready")
+ */
+ // @TODO fix arguments
+ onContentReady: function(id, fn, p_obj, p_override, compat) {
+ return this.onAvailable(id, fn, p_obj, p_override, true, compat);
+ },
+
+ /**
+ * Adds an event listener
+ *
+ * @method attach
+ *
+ * @param {String} type The type of event to append
+ * @param {Function} fn The method the event invokes
+ * @param {String|HTMLElement|Array|NodeList} el An id, an element
+ * reference, or a collection of ids and/or elements to assign the
+ * listener to.
+ * @param {Object} context optional context object
+ * @param {Boolean|object} args 0..n arguments to pass to the callback
+ * @return {EventHandle} an object to that can be used to detach the listener
+ *
+ * @static
+ */
+
+ attach: function(type, fn, el, context) {
+ return Y.Event._attach(Y.Array(arguments, 0, true));
+ },
+
+ _createWrapper: function (el, type, capture, compat, facade) {
+
+ var ek = Y.stamp(el),
+ key = 'event:' + ek + type,
+ cewrapper;
+
+
+ if (false === facade) {
+ key += 'native';
+ }
+ if (capture) {
+ key += 'capture';
+ }
+
+
+ cewrapper = _wrappers[key];
+
+
+ if (!cewrapper) {
+ // create CE wrapper
+ cewrapper = Y.publish(key, {
+ silent: true,
+ bubbles: false,
+ contextFn: function() {
+ cewrapper.nodeRef = cewrapper.nodeRef || Y.one(cewrapper.el);
+ return cewrapper.nodeRef;
+ }
+ });
+
+ // for later removeListener calls
+ cewrapper.el = el;
+ cewrapper.key = key;
+ cewrapper.domkey = ek;
+ cewrapper.type = type;
+ cewrapper.fn = function(e) {
+ cewrapper.fire(Y.Event.getEvent(e, el, (compat || (false === facade))));
+ };
+ cewrapper.capture = capture;
+
+ if (el == Y.config.win && type == "load") {
+ // window load happens once
+ cewrapper.fireOnce = true;
+ _windowLoadKey = key;
+ }
+
+ _wrappers[key] = cewrapper;
+ _el_events[ek] = _el_events[ek] || {};
+ _el_events[ek][key] = cewrapper;
+
+ add(el, type, cewrapper.fn, capture);
+ }
+
+ return cewrapper;
+
+ },
+
+ _attach: function(args, config) {
+
+ var compat, E=Y.Event,
+ handles, oEl, cewrapper, context,
+ fireNow = false, ret,
+ type = args[0],
+ fn = args[1],
+ el = args[2] || Y.config.win,
+ facade = config && config.facade,
+ capture = config && config.capture;
+
+ if (args[args.length-1] === COMPAT_ARG) {
+ compat = true;
+ // trimmedArgs.pop();
+ }
+
+ if (!fn || !fn.call) {
+// throw new TypeError(type + " attach call failed, callback undefined");
+Y.log(type + " attach call failed, invalid callback", "error", "event");
+ return false;
+ }
+
+ // The el argument can be an array of elements or element ids.
+ if (shouldIterate(el)) {
+
+ handles=[];
+
+ Y.each(el, function(v, k) {
+ args[2] = v;
+ handles.push(E._attach(args, config));
+ });
+
+ // return (handles.length === 1) ? handles[0] : handles;
+ return new Y.EventHandle(handles);
+
+ // If the el argument is a string, we assume it is
+ // actually the id of the element. If the page is loaded
+ // we convert el to the actual element, otherwise we
+ // defer attaching the event until the element is
+ // ready
+ } else if (Y.Lang.isString(el)) {
+
+ // oEl = (compat) ? Y.DOM.byId(el) : Y.Selector.query(el);
+
+ if (compat) {
+ oEl = Y.DOM.byId(el);
+ } else {
+
+ oEl = Y.Selector.query(el);
+
+ switch (oEl.length) {
+ case 0:
+ oEl = null;
+ break;
+ case 1:
+ oEl = oEl[0];
+ break;
+ default:
+ args[2] = oEl;
+ return E._attach(args, config);
+ }
+ }
+
+ if (oEl) {
+
+ el = oEl;
+
+ // Not found = defer adding the event until the element is available
+ } else {
+
+ // Y.log(el + ' not found');
+ ret = this.onAvailable(el, function() {
+ // Y.log('lazy attach: ' + args);
+
+ ret.handle = E._attach(args, config);
+
+ }, E, true, false, compat);
+
+ return ret;
+
+ }
+ }
+
+ // Element should be an html element or node
+ if (!el) {
+ Y.log("unable to attach event " + type, "warn", "event");
+ return false;
+ }
+
+ if (Y.Node && el instanceof Y.Node) {
+ el = Y.Node.getDOMNode(el);
+ }
+
+ cewrapper = this._createWrapper(el, type, capture, compat, facade);
+
+ if (el == Y.config.win && type == "load") {
+
+ // if the load is complete, fire immediately.
+ // all subscribers, including the current one
+ // will be notified.
+ if (YUI.Env.windowLoaded) {
+ fireNow = true;
+ }
+ }
+
+ if (compat) {
+ args.pop();
+ }
+
+ context = args[3];
+
+ // set context to the Node if not specified
+ // ret = cewrapper.on.apply(cewrapper, trimmedArgs);
+ ret = cewrapper._on(fn, context, (args.length > 4) ? args.slice(4) : null);
+
+ if (fireNow) {
+ cewrapper.fire();
+ }
+
+ return ret;
+
+ },
+
+ /**
+ * Removes an event listener. Supports the signature the event was bound
+ * with, but the preferred way to remove listeners is using the handle
+ * that is returned when using Y.on
+ *
+ * @method detach
+ *
+ * @param {String} type the type of event to remove.
+ * @param {Function} fn the method the event invokes. If fn is
+ * undefined, then all event handlers for the type of event are
+ * removed.
+ * @param {String|HTMLElement|Array|NodeList|EventHandle} el An
+ * event handle, an id, an element reference, or a collection
+ * of ids and/or elements to remove the listener from.
+ * @return {boolean} true if the unbind was successful, false otherwise.
+ * @static
+ */
+ detach: function(type, fn, el, obj) {
+
+ var args=Y.Array(arguments, 0, true), compat, i, l, ok,
+ id, ce;
+
+ if (args[args.length-1] === COMPAT_ARG) {
+ compat = true;
+ // args.pop();
+ }
+
+ if (type && type.detach) {
+ return type.detach();
+ }
+
+ // The el argument can be a string
+ if (typeof el == "string") {
+
+ // el = (compat) ? Y.DOM.byId(el) : Y.all(el);
+ if (compat) {
+ el = Y.DOM.byId(el);
+ } else {
+ el = Y.Selector.query(el);
+ l = el.length;
+ if (l < 1) {
+ el = null;
+ } else if (l == 1) {
+ el = el[0];
+ }
+ }
+ // return Y.Event.detach.apply(Y.Event, args);
+
+ // The el argument can be an array of elements or element ids.
+ }
+
+ if (!el) {
+ return false;
+ }
+
+ if (shouldIterate(el)) {
+
+ ok = true;
+ for (i=0, l=el.length; i 0);
+ }
+
+ // onAvailable
+ notAvail = [];
+
+ executeItem = function (el, item) {
+
+ var context, ov = item.override;
+
+ if (item.compat) {
+
+ if (item.override) {
+ if (ov === true) {
+ context = item.obj;
+ } else {
+ context = ov;
+ }
+ } else {
+ context = el;
+ }
+
+ item.fn.call(context, item.obj);
+
+ } else {
+ context = item.obj || Y.one(el);
+ item.fn.apply(context, (Y.Lang.isArray(ov)) ? ov : []);
+ }
+
+ };
+
+
+ // onAvailable
+ for (i=0,len=_avail.length; i 4 ? Y.Array(arguments, 4, true) : [];
+ return Y.Event.onAvailable.call(Y.Event, id, fn, o, a);
+ }
+};
+
+/**
+ * Executes the callback as soon as the specified element
+ * is detected in the DOM with a nextSibling property
+ * (indicating that the element's children are available)
+ * @event contentready
+ * @param type {string} 'contentready'
+ * @param fn {function} the callback function to execute.
+ * @param el {string|HTMLElement|collection} the element(s) to attach
+ * @param context optional argument that specifies what 'this' refers to.
+ * @param args* 0..n additional arguments to pass on to the callback function.
+ * These arguments will be added after the event object.
+ * @return {EventHandle} the detach handle
+ * @for YUI
+ */
+Y.Env.evt.plugins.contentready = {
+ on: function(type, fn, id, o) {
+ var a = arguments.length > 4 ? Y.Array(arguments, 4, true) : [];
+ return Y.Event.onContentReady.call(Y.Event, id, fn, o, a);
+ }
+};
+
+
+}, '3.0.0' ,{requires:['event-custom-base']});
+YUI.add('event-delegate', function(Y) {
+
+/**
+ * Adds event delegation support to the library.
+ *
+ * @module event
+ * @submodule event-delegate
+ */
+
+var Event = Y.Event,
+ Lang = Y.Lang,
+
+ delegates = {},
+
+ specialTypes = {
+ mouseenter: "mouseover",
+ mouseleave: "mouseout"
+ },
+
+ resolveTextNode = function(n) {
+ try {
+ if (n && 3 == n.nodeType) {
+ return n.parentNode;
+ }
+ } catch(e) { }
+ return n;
+ },
+
+ delegateHandler = function(delegateKey, e, el) {
+
+ var target = resolveTextNode((e.target || e.srcElement)),
+ tests = delegates[delegateKey],
+ spec,
+ ename,
+ matched,
+ fn,
+ ev;
+
+
+ var getMatch = function(el, selector, container) {
+
+ var returnVal;
+
+ if (!el || el === container) {
+ returnVal = false;
+ }
+ else {
+ returnVal = Y.Selector.test(el, selector) ? el: getMatch(el.parentNode, selector, container);
+ }
+
+ return returnVal;
+
+ };
+
+
+ for (spec in tests) {
+
+ if (tests.hasOwnProperty(spec)) {
+
+ ename = tests[spec];
+ fn = tests.fn;
+ matched = null;
+
+
+ if (Y.Selector.test(target, spec, el)) {
+ matched = target;
+ }
+ else if (Y.Selector.test(target, ((spec.replace(/,/gi, " *,")) + " *"), el)) {
+
+ // The target is a descendant of an element matching
+ // the selector, so crawl up to find the ancestor that
+ // matches the selector
+
+ matched = getMatch(target, spec, el);
+
+ }
+
+
+ if (matched) {
+
+ if (!ev) {
+ ev = new Y.DOMEventFacade(e, el);
+ ev.container = ev.currentTarget;
+ }
+
+ ev.currentTarget = Y.Node.get(matched);
+
+ Y.publish(ename, {
+ contextFn: function() {
+ return ev.currentTarget;
+ }
+ });
+
+ if (fn) {
+ fn(ev, ename);
+ }
+ else {
+ Y.fire(ename, ev);
+ }
+
+ }
+
+ }
+ }
+
+ },
+
+ attach = function (type, key, element) {
+
+ var focusMethods = {
+ focus: Event._attachFocus,
+ blur: Event._attachBlur
+ },
+
+ attachFn = focusMethods[type],
+
+ args = [type,
+ function (e) {
+ delegateHandler(key, (e || window.event), element);
+ },
+ element];
+
+
+ if (attachFn) {
+ return attachFn(args, { capture: true, facade: false });
+ }
+ else {
+ return Event._attach(args, { facade: false });
+ }
+
+ },
+
+ sanitize = Y.cached(function(str) {
+ return str.replace(/[|,:]/g, '~');
+ });
+
+/**
+ * Sets up event delegation on a container element. The delegated event
+ * will use a supplied selector to test if the target or one of the
+ * descendants of the target match it. The supplied callback function
+ * will only be executed if a match was encountered, and, in fact,
+ * will be executed for each element that matches if you supply an
+ * ambiguous selector.
+ *
+ * The event object for the delegated event is supplied to the callback
+ * function. It is modified slightly in order to support all properties
+ * that may be needed for event delegation. 'currentTarget' is set to
+ * the element that matched the delegation specifcation. 'container' is
+ * set to the element that the listener is bound to (this normally would
+ * be the 'currentTarget').
+ *
+ * @event delegate
+ * @param type {string} 'delegate'
+ * @param fn {function} the callback function to execute. This function
+ * will be provided the event object for the delegated event.
+ * @param el {string|node} the element that is the delegation container
+ * @param delegateType {string} the event type to delegate
+ * @param spec {string} a selector that must match the target of the
+ * event.
+ * @param context optional argument that specifies what 'this' refers to.
+ * @param args* 0..n additional arguments to pass on to the callback function.
+ * These arguments will be added after the event object.
+ * @return {EventHandle} the detach handle
+ * @for YUI
+ * @deprecated use Y.delegate
+ */
+Y.Env.evt.plugins.delegate = {
+
+ on: function(type, fn, el, delegateType, spec) {
+
+ Y.log('delegate event is deprecated, use Y.delegate()', 'warn', 'deprecated');
+
+ var args = Y.Array(arguments, 0, true);
+
+ args.splice(3, 1);
+
+ args[0] = delegateType;
+
+ return Y.delegate.apply(Y, args);
+
+ }
+
+};
+
+
+/**
+ * Sets up event delegation on a container element. The delegated event
+ * will use a supplied selector to test if the target or one of the
+ * descendants of the target match it. The supplied callback function
+ * will only be executed if a match was encountered, and, in fact,
+ * will be executed for each element that matches if you supply an
+ * ambiguous selector.
+ *
+ * The event object for the delegated event is supplied to the callback
+ * function. It is modified slightly in order to support all properties
+ * that may be needed for event delegation. 'currentTarget' is set to
+ * the element that matched the delegation specifcation. 'container' is
+ * set to the element that the listener is bound to (this normally would
+ * be the 'currentTarget').
+ *
+ * @method delegate
+ * @param type {string} the event type to delegate
+ * @param fn {function} the callback function to execute. This function
+ * will be provided the event object for the delegated event.
+ * @param el {string|node} the element that is the delegation container
+ * @param spec {string} a selector that must match the target of the
+ * event.
+ * @param context optional argument that specifies what 'this' refers to.
+ * @param args* 0..n additional arguments to pass on to the callback function.
+ * These arguments will be added after the event object.
+ * @return {EventHandle} the detach handle
+ * @for YUI
+ */
+Event.delegate = function (type, fn, el, spec) {
+
+ if (!spec) {
+ Y.log('delegate: no spec, nothing to do', 'warn', 'event');
+ return false;
+ }
+
+
+ var args = Y.Array(arguments, 0, true),
+ element = el, // HTML element serving as the delegation container
+ availHandle;
+
+
+ if (Lang.isString(el)) {
+
+ // Y.Selector.query returns an array of matches unless specified
+ // to return just the first match. Since the primary use case for
+ // event delegation is to use a single event handler on a container,
+ // Y.delegate doesn't currently support being able to bind a
+ // single listener to multiple containers.
+
+ element = Y.Selector.query(el, null, true);
+
+ if (!element) { // Not found, check using onAvailable
+
+ availHandle = Event.onAvailable(el, function() {
+
+ availHandle.handle = Event.delegate.apply(Event, args);
+
+ }, Event, true, false);
+
+ return availHandle;
+
+ }
+
+ }
+
+
+ element = Y.Node.getDOMNode(element);
+
+
+ var guid = Y.stamp(element),
+
+ // The Custom Event for the delegation spec
+ ename = 'delegate:' + guid + type + sanitize(spec),
+
+ // The key to the listener for the event type and container
+ delegateKey = type + guid,
+
+ delegate = delegates[delegateKey],
+
+ domEventHandle,
+
+ ceHandle,
+
+ listeners;
+
+
+ if (!delegate) {
+
+ delegate = {};
+
+ if (specialTypes[type]) {
+
+ if (!Event._fireMouseEnter) {
+ Y.log("Delegating a " + type + " event requires the event-mouseenter submodule.", "error", "Event");
+ return false;
+ }
+
+ type = specialTypes[type];
+ delegate.fn = Event._fireMouseEnter;
+
+ }
+
+ // Create the DOM Event wrapper that will fire the Custom Event
+
+ domEventHandle = attach(type, delegateKey, element);
+
+
+ // Hook into the _delete method for the Custom Event wrapper of this
+ // DOM Event in order to clean up the 'delegates' map and unsubscribe
+ // the associated Custom Event listeners fired by this DOM event
+ // listener if/when the user calls "purgeElement" OR removes all
+ // listeners of the Custom Event.
+
+ Y.after(function (sub) {
+
+ if (domEventHandle.sub == sub) {
+
+ // Delete this event from the map of known delegates
+ delete delegates[delegateKey];
+
+ Y.log("DOM event listener associated with the " + ename + " Custom Event removed. Removing all " + ename + " listeners.", "info", "Event");
+
+ // Unsubscribe all listeners of the Custom Event fired
+ // by this DOM event.
+ Y.detachAll(ename);
+
+ }
+
+ }, domEventHandle.evt, "_delete");
+
+ delegate.handle = domEventHandle;
+
+ delegates[delegateKey] = delegate;
+
+ }
+
+
+ listeners = delegate.listeners;
+
+ delegate.listeners = listeners ? (listeners + 1) : 1;
+ delegate[spec] = ename;
+
+
+ args[0] = ename;
+
+ // Remove element, delegation spec
+ args.splice(2, 2);
+
+
+ // Subscribe to the Custom Event for the delegation spec
+
+ ceHandle = Y.on.apply(Y, args);
+
+
+ // Hook into the detach method of the handle in order to clean up the
+ // 'delegates' map and remove the associated DOM event handler
+ // responsible for firing this Custom Event if all listener for this
+ // event have been removed.
+
+ Y.after(function () {
+
+ delegate.listeners = (delegate.listeners - 1);
+
+ if (delegate.listeners === 0) {
+ Y.log("No more listeners for the " + ename + " Custom Event. Removing its associated DOM event listener.", "info", "Event");
+ delegate.handle.detach();
+ }
+
+ }, ceHandle, "detach");
+
+ return ceHandle;
+
+};
+
+Y.delegate = Event.delegate;
+
+
+}, '3.0.0' ,{requires:['node-base']});
+YUI.add('event-mousewheel', function(Y) {
+
+/**
+ * Adds mousewheel event support
+ * @module event
+ * @submodule event-mousewheel
+ */
+var DOM_MOUSE_SCROLL = 'DOMMouseScroll',
+ fixArgs = function(args) {
+ var a = Y.Array(args, 0, true), target;
+ if (Y.UA.gecko) {
+ a[0] = DOM_MOUSE_SCROLL;
+ target = Y.config.win;
+ } else {
+ target = Y.config.doc;
+ }
+
+ if (a.length < 3) {
+ a[2] = target;
+ } else {
+ a.splice(2, 0, target);
+ }
+
+ return a;
+ };
+
+/**
+ * Mousewheel event. This listener is automatically attached to the
+ * correct target, so one should not be supplied. Mouse wheel
+ * direction and velocity is stored in the 'mouseDelta' field.
+ * @event mousewheel
+ * @param type {string} 'mousewheel'
+ * @param fn {function} the callback to execute
+ * @param context optional context object
+ * @param args 0..n additional arguments to provide to the listener.
+ * @return {EventHandle} the detach handle
+ * @for YUI
+ */
+Y.Env.evt.plugins.mousewheel = {
+ on: function() {
+ return Y.Event._attach(fixArgs(arguments));
+ },
+
+ detach: function() {
+ return Y.Event.detach.apply(Y.Event, fixArgs(arguments));
+ }
+};
+
+
+}, '3.0.0' ,{requires:['node-base']});
+YUI.add('event-mouseenter', function(Y) {
+
+/**
+ * Adds support for mouseenter/mouseleave events
+ * @module event
+ * @submodule event-mouseenter
+ */
+var Event = Y.Event,
+ Lang = Y.Lang,
+
+ plugins = Y.Env.evt.plugins,
+
+ listeners = {},
+
+ eventConfig = {
+
+ on: function(type, fn, el) {
+
+ var args = Y.Array(arguments, 0, true),
+ element = el,
+ availHandle;
+
+
+ if (Lang.isString(el)) {
+
+ // Need to use Y.all because if el is a string it could be a
+ // selector that returns a NodeList
+
+ element = Y.all(el);
+
+ if (element.size() === 0) { // Not found, check using onAvailable
+
+ availHandle = Event.onAvailable(el, function() {
+
+ availHandle.handle = Y.on.apply(Y, args);
+
+ }, Event, true, false);
+
+ return availHandle;
+
+ }
+
+ }
+
+
+ var sDOMEvent = (type === "mouseenter") ? "mouseover" : "mouseout",
+
+ // The name of the custom event
+ sEventName = type + ":" + Y.stamp(element) + sDOMEvent,
+
+ listener = listeners[sEventName],
+
+ domEventHandle,
+
+ ceHandle,
+
+ nListeners;
+
+
+ // Bind an actual DOM event listener that will call the
+ // the custom event
+ if (!listener) {
+
+ domEventHandle = Y.on(sDOMEvent, Y.rbind(Event._fireMouseEnter, Y, sEventName), element);
+
+ // Hook into the _delete method for the Custom Event wrapper of this
+ // DOM Event in order to clean up the 'listeners' map and unsubscribe
+ // the associated Custom Event listeners fired by this DOM event
+ // listener if/when the user calls "purgeElement" OR removes all
+ // listeners of the Custom Event.
+
+ Y.after(function (sub) {
+
+ if (domEventHandle.sub == sub) {
+
+ // Delete this event from the map of known mouseenter
+ // and mouseleave listeners
+ delete listeners[sEventName];
+
+ Y.log("DOM event listener associated with the " + sEventName + " Custom Event removed. Removing all " + sEventName + " listeners.", "info", "Event");
+
+ // Unsubscribe all listeners of the Custom Event fired
+ // by this DOM event.
+ Y.detachAll(sEventName);
+
+ }
+
+ }, domEventHandle.evt, "_delete");
+
+
+ listener = {};
+ listener.handle = domEventHandle;
+
+ listeners[sEventName] = listener;
+
+ }
+
+ nListeners = listener.count;
+
+ listener.count = nListeners ? (nListeners + 1) : 1;
+
+ args[0] = sEventName;
+
+ // Remove the element from the args
+ args.splice(2, 1);
+
+ // Subscribe to the custom event
+ ceHandle = Y.on.apply(Y, args);
+
+ // Hook into the detach method of the handle in order to clean up the
+ // 'listeners' map and remove the associated DOM event handler
+ // responsible for firing this Custom Event if all listener for this
+ // event have been removed.
+
+ Y.after(function () {
+
+ listener.count = (listener.count - 1);
+
+ if (listener.count === 0) {
+ Y.log("No more listeners for the " + sEventName + " Custom Event. Removing its associated DOM event listener.", "info", "Event");
+ listener.handle.detach();
+ }
+
+ }, ceHandle, "detach");
+
+
+ return ceHandle;
+
+ }
+
+ };
+
+
+Event._fireMouseEnter = function (e, eventName) {
+
+ var relatedTarget = e.relatedTarget,
+ currentTarget = e.currentTarget;
+
+ if (currentTarget !== relatedTarget &&
+ !currentTarget.contains(relatedTarget)) {
+
+ Y.publish(eventName, {
+ contextFn: function() {
+ return currentTarget;
+ }
+ });
+
+ Y.fire(eventName, e);
+
+ }
+
+};
+
+
+/**
+ * Sets up a "mouseenter" listenera listener that is called the first time
+ * the user's mouse enters the specified element(s).
+ *
+ * @event mouseenter
+ * @param type {string} "mouseenter"
+ * @param fn {function} The method the event invokes.
+ * @param el {string|node} The element(s) to assign the listener to.
+ * @param spec {string} Optional. String representing a selector that must
+ * match the target of the event in order for the listener to be called.
+ * @return {EventHandle} the detach handle
+ * @for YUI
+ */
+plugins.mouseenter = eventConfig;
+
+/**
+* Sets up a "mouseleave" listenera listener that is called the first time
+* the user's mouse leaves the specified element(s).
+*
+* @event mouseleave
+* @param type {string} "mouseleave"
+* @param fn {function} The method the event invokes.
+* @param el {string|node} The element(s) to assign the listener to.
+* @param spec {string} Optional. String representing a selector that must
+* match the target of the event in order for the listener to be called.
+* @return {EventHandle} the detach handle
+* @for YUI
+ */
+plugins.mouseleave = eventConfig;
+
+
+}, '3.0.0' ,{requires:['node-base']});
+YUI.add('event-key', function(Y) {
+
+/**
+ * Functionality to listen for one or more specific key combinations.
+ * @module event
+ * @submodule event-key
+ */
+
+/**
+ * Add a key listener. The listener will only be notified if the
+ * keystroke detected meets the supplied specification. The
+ * spec consists of the key event type, followed by a colon,
+ * followed by zero or more comma separated key codes, followed
+ * by zero or more modifiers delimited by a plus sign. Ex:
+ * press:12,65+shift+ctrl
+ * @event key
+ * @for YUI
+ * @param type {string} 'key'
+ * @param fn {function} the function to execute
+ * @param id {string|HTMLElement|collection} the element(s) to bind
+ * @param spec {string} the keyCode and modifier specification
+ * @param o optional context object
+ * @param args 0..n additional arguments to provide to the listener.
+ * @return {Event.Handle} the detach handle
+ */
+Y.Env.evt.plugins.key = {
+
+ on: function(type, fn, id, spec, o) {
+ var a = Y.Array(arguments, 0, true), parsed, etype, criteria, ename;
+
+ parsed = spec && spec.split(':');
+
+ if (!spec || spec.indexOf(':') == -1 || !parsed[1]) {
+Y.log('Illegal key spec, creating a regular keypress listener instead.', 'info', 'event');
+ a[0] = 'key' + ((parsed && parsed[0]) || 'press');
+ return Y.on.apply(Y, a);
+ }
+
+ // key event type: 'down', 'up', or 'press'
+ etype = parsed[0];
+
+ // list of key codes optionally followed by modifiers
+ criteria = (parsed[1]) ? parsed[1].split(/,|\+/) : null;
+
+ // the name of the custom event that will be created for the spec
+ ename = (Y.Lang.isString(id) ? id : Y.stamp(id)) + spec;
+
+ ename = ename.replace(/,/g, '_');
+
+ if (!Y.getEvent(ename)) {
+
+ // subscribe spec validator to the DOM event
+ Y.on(type + etype, function(e) {
+
+ // Y.log('keylistener: ' + e.keyCode);
+
+ var passed = false, failed = false, i, crit, critInt;
+
+ for (i=0; i4)?W.slice(4):null);if(T){Z.fire();}return V;},detach:function(X,Z,S,U){var W=A.Array(arguments,0,true),a,V,T,Y,Q,R;if(W[W.length-1]===E){a=true;}if(X&&X.detach){return X.detach();}if(typeof S=="string"){if(a){S=A.DOM.byId(S);}else{S=A.Selector.query(S);T=S.length;if(T<1){S=null;}else{if(T==1){S=S[0];}}}}if(!S){return false;}if(F(S)){Y=true;for(V=0,T=S.length;V0);}U=[];W=function(Z,a){var Y,X=a.override;if(a.compat){if(a.override){if(X===true){Y=a.obj;}else{Y=X;}}else{Y=Z;}a.fn.call(Y,a.obj);}else{Y=a.obj||A.one(Z);a.fn.apply(Y,(A.Lang.isArray(X))?X:[]);}};for(R=0,Q=L.length;R4?A.Array(arguments,4,true):[];return A.Event.onAvailable.call(A.Event,F,C,E,B);}};A.Env.evt.plugins.contentready={on:function(D,C,F,E){var B=arguments.length>4?A.Array(arguments,4,true):[];return A.Event.onContentReady.call(A.Event,F,C,E,B);}};},"3.0.0",{requires:["event-custom-base"]});YUI.add("event-delegate",function(B){var I=B.Event,F=B.Lang,E={},A={mouseenter:"mouseover",mouseleave:"mouseout"},H=function(K){try{if(K&&3==K.nodeType){return K.parentNode;}}catch(J){}return K;},D=function(K,P,M){var Q=H((P.target||P.srcElement)),N=E[K],T,O,L,S,R;var J=function(X,U,V){var W;if(!X||X===V){W=false;}else{W=B.Selector.test(X,U)?X:J(X.parentNode,U,V);}return W;};for(T in N){if(N.hasOwnProperty(T)){O=N[T];S=N.fn;L=null;if(B.Selector.test(Q,T,M)){L=Q;}else{if(B.Selector.test(Q,((T.replace(/,/gi," *,"))+" *"),M)){L=J(Q,T,M);}}if(L){if(!R){R=new B.DOMEventFacade(P,M);R.container=R.currentTarget;}R.currentTarget=B.Node.get(L);B.publish(O,{contextFn:function(){return R.currentTarget;}});if(S){S(R,O);}else{B.fire(O,R);}}}}},G=function(M,L,K){var O={focus:I._attachFocus,blur:I._attachBlur},N=O[M],J=[M,function(P){D(L,(P||window.event),K);},K];if(N){return N(J,{capture:true,facade:false});}else{return I._attach(J,{facade:false});}},C=B.cached(function(J){return J.replace(/[|,:]/g,"~");});B.Env.evt.plugins.delegate={on:function(O,N,M,J,K){var L=B.Array(arguments,0,true);L.splice(3,1);L[0]=J;return B.delegate.apply(B,L);}};I.delegate=function(R,U,K,W){if(!W){return false;}var O=B.Array(arguments,0,true),M=K,N;if(F.isString(K)){M=B.Selector.query(K,null,true);if(!M){N=I.onAvailable(K,function(){N.handle=I.delegate.apply(I,O);},I,true,false);return N;}}M=B.Node.getDOMNode(M);var S=B.stamp(M),L="delegate:"+S+R+C(W),J=R+S,Q=E[J],T,V,P;if(!Q){Q={};if(A[R]){if(!I._fireMouseEnter){return false;}R=A[R];Q.fn=I._fireMouseEnter;}T=G(R,J,M);B.after(function(X){if(T.sub==X){delete E[J];B.detachAll(L);}},T.evt,"_delete");Q.handle=T;E[J]=Q;}P=Q.listeners;Q.listeners=P?(P+1):1;Q[W]=L;O[0]=L;O.splice(2,2);V=B.on.apply(B,O);B.after(function(){Q.listeners=(Q.listeners-1);if(Q.listeners===0){Q.handle.detach();}},V,"detach");return V;};B.delegate=I.delegate;},"3.0.0",{requires:["node-base"]});YUI.add("event-mousewheel",function(C){var B="DOMMouseScroll",A=function(E){var D=C.Array(E,0,true),F;if(C.UA.gecko){D[0]=B;F=C.config.win;}else{F=C.config.doc;}if(D.length<3){D[2]=F;}else{D.splice(2,0,F);}return D;};C.Env.evt.plugins.mousewheel={on:function(){return C.Event._attach(A(arguments));},detach:function(){return C.Event.detach.apply(C.Event,A(arguments));}};},"3.0.0",{requires:["node-base"]});YUI.add("event-mouseenter",function(F){var C=F.Event,E=F.Lang,B=F.Env.evt.plugins,D={},A={on:function(M,O,H){var L=F.Array(arguments,0,true),J=H,K;if(E.isString(H)){J=F.all(H);if(J.size()===0){K=C.onAvailable(H,function(){K.handle=F.on.apply(F,L);},C,true,false);return K;}}var R=(M==="mouseenter")?"mouseover":"mouseout",Q=M+":"+F.stamp(J)+R,I=D[Q],N,P,G;if(!I){N=F.on(R,F.rbind(C._fireMouseEnter,F,Q),J);F.after(function(S){if(N.sub==S){delete D[Q];F.detachAll(Q);}},N.evt,"_delete");I={};I.handle=N;D[Q]=I;}G=I.count;I.count=G?(G+1):1;L[0]=Q;L.splice(2,1);P=F.on.apply(F,L);F.after(function(){I.count=(I.count-1);if(I.count===0){I.handle.detach();}},P,"detach");return P;}};C._fireMouseEnter=function(J,H){var G=J.relatedTarget,I=J.currentTarget;if(I!==G&&!I.contains(G)){F.publish(H,{contextFn:function(){return I;}});F.fire(H,J);}};B.mouseenter=A;B.mouseleave=A;},"3.0.0",{requires:["node-base"]});YUI.add("event-key",function(A){A.Env.evt.plugins.key={on:function(E,G,B,K,C){var I=A.Array(arguments,0,true),F,J,H,D;F=K&&K.split(":");if(!K||K.indexOf(":")==-1||!F[1]){I[0]="key"+((F&&F[0])||"press");return A.on.apply(A,I);}J=F[0];H=(F[1])?F[1].split(/,|\+/):null;D=(A.Lang.isString(B)?B:A.stamp(B))+K;D=D.replace(/,/g,"_");if(!A.getEvent(D)){A.on(E+J,function(P){var Q=false,M=false,N,L,O;for(N=0;NThe callback is executed with a single parameter:
+ * the custom object parameter, if provided.
+ *
+ * @method onAvailable
+ *
+ * @param {string||string[]} id the id of the element, or an array
+ * of ids to look for.
+ * @param {function} fn what to execute when the element is found.
+ * @param {object} p_obj an optional object to be passed back as
+ * a parameter to fn.
+ * @param {boolean|object} p_override If set to true, fn will execute
+ * in the context of p_obj, if set to an object it
+ * will execute in the context of that object
+ * @param checkContent {boolean} check child node readiness (onContentReady)
+ * @static
+ * @deprecated Use Y.on("available")
+ */
+ // @TODO fix arguments
+ onAvailable: function(id, fn, p_obj, p_override, checkContent, compat) {
+
+ var a = Y.Array(id), i, availHandle;
+
+
+ for (i=0; iThe callback is executed with a single parameter:
+ * the custom object parameter, if provided.
+ *
+ * @method onContentReady
+ *
+ * @param {string} id the id of the element to look for.
+ * @param {function} fn what to execute when the element is ready.
+ * @param {object} p_obj an optional object to be passed back as
+ * a parameter to fn.
+ * @param {boolean|object} p_override If set to true, fn will execute
+ * in the context of p_obj. If an object, fn will
+ * exectute in the context of that object
+ *
+ * @static
+ * @deprecated Use Y.on("contentready")
+ */
+ // @TODO fix arguments
+ onContentReady: function(id, fn, p_obj, p_override, compat) {
+ return this.onAvailable(id, fn, p_obj, p_override, true, compat);
+ },
+
+ /**
+ * Adds an event listener
+ *
+ * @method attach
+ *
+ * @param {String} type The type of event to append
+ * @param {Function} fn The method the event invokes
+ * @param {String|HTMLElement|Array|NodeList} el An id, an element
+ * reference, or a collection of ids and/or elements to assign the
+ * listener to.
+ * @param {Object} context optional context object
+ * @param {Boolean|object} args 0..n arguments to pass to the callback
+ * @return {EventHandle} an object to that can be used to detach the listener
+ *
+ * @static
+ */
+
+ attach: function(type, fn, el, context) {
+ return Y.Event._attach(Y.Array(arguments, 0, true));
+ },
+
+ _createWrapper: function (el, type, capture, compat, facade) {
+
+ var ek = Y.stamp(el),
+ key = 'event:' + ek + type,
+ cewrapper;
+
+
+ if (false === facade) {
+ key += 'native';
+ }
+ if (capture) {
+ key += 'capture';
+ }
+
+
+ cewrapper = _wrappers[key];
+
+
+ if (!cewrapper) {
+ // create CE wrapper
+ cewrapper = Y.publish(key, {
+ silent: true,
+ bubbles: false,
+ contextFn: function() {
+ cewrapper.nodeRef = cewrapper.nodeRef || Y.one(cewrapper.el);
+ return cewrapper.nodeRef;
+ }
+ });
+
+ // for later removeListener calls
+ cewrapper.el = el;
+ cewrapper.key = key;
+ cewrapper.domkey = ek;
+ cewrapper.type = type;
+ cewrapper.fn = function(e) {
+ cewrapper.fire(Y.Event.getEvent(e, el, (compat || (false === facade))));
+ };
+ cewrapper.capture = capture;
+
+ if (el == Y.config.win && type == "load") {
+ // window load happens once
+ cewrapper.fireOnce = true;
+ _windowLoadKey = key;
+ }
+
+ _wrappers[key] = cewrapper;
+ _el_events[ek] = _el_events[ek] || {};
+ _el_events[ek][key] = cewrapper;
+
+ add(el, type, cewrapper.fn, capture);
+ }
+
+ return cewrapper;
+
+ },
+
+ _attach: function(args, config) {
+
+ var compat, E=Y.Event,
+ handles, oEl, cewrapper, context,
+ fireNow = false, ret,
+ type = args[0],
+ fn = args[1],
+ el = args[2] || Y.config.win,
+ facade = config && config.facade,
+ capture = config && config.capture;
+
+ if (args[args.length-1] === COMPAT_ARG) {
+ compat = true;
+ // trimmedArgs.pop();
+ }
+
+ if (!fn || !fn.call) {
+// throw new TypeError(type + " attach call failed, callback undefined");
+ return false;
+ }
+
+ // The el argument can be an array of elements or element ids.
+ if (shouldIterate(el)) {
+
+ handles=[];
+
+ Y.each(el, function(v, k) {
+ args[2] = v;
+ handles.push(E._attach(args, config));
+ });
+
+ // return (handles.length === 1) ? handles[0] : handles;
+ return new Y.EventHandle(handles);
+
+ // If the el argument is a string, we assume it is
+ // actually the id of the element. If the page is loaded
+ // we convert el to the actual element, otherwise we
+ // defer attaching the event until the element is
+ // ready
+ } else if (Y.Lang.isString(el)) {
+
+ // oEl = (compat) ? Y.DOM.byId(el) : Y.Selector.query(el);
+
+ if (compat) {
+ oEl = Y.DOM.byId(el);
+ } else {
+
+ oEl = Y.Selector.query(el);
+
+ switch (oEl.length) {
+ case 0:
+ oEl = null;
+ break;
+ case 1:
+ oEl = oEl[0];
+ break;
+ default:
+ args[2] = oEl;
+ return E._attach(args, config);
+ }
+ }
+
+ if (oEl) {
+
+ el = oEl;
+
+ // Not found = defer adding the event until the element is available
+ } else {
+
+ ret = this.onAvailable(el, function() {
+
+ ret.handle = E._attach(args, config);
+
+ }, E, true, false, compat);
+
+ return ret;
+
+ }
+ }
+
+ // Element should be an html element or node
+ if (!el) {
+ return false;
+ }
+
+ if (Y.Node && el instanceof Y.Node) {
+ el = Y.Node.getDOMNode(el);
+ }
+
+ cewrapper = this._createWrapper(el, type, capture, compat, facade);
+
+ if (el == Y.config.win && type == "load") {
+
+ // if the load is complete, fire immediately.
+ // all subscribers, including the current one
+ // will be notified.
+ if (YUI.Env.windowLoaded) {
+ fireNow = true;
+ }
+ }
+
+ if (compat) {
+ args.pop();
+ }
+
+ context = args[3];
+
+ // set context to the Node if not specified
+ // ret = cewrapper.on.apply(cewrapper, trimmedArgs);
+ ret = cewrapper._on(fn, context, (args.length > 4) ? args.slice(4) : null);
+
+ if (fireNow) {
+ cewrapper.fire();
+ }
+
+ return ret;
+
+ },
+
+ /**
+ * Removes an event listener. Supports the signature the event was bound
+ * with, but the preferred way to remove listeners is using the handle
+ * that is returned when using Y.on
+ *
+ * @method detach
+ *
+ * @param {String} type the type of event to remove.
+ * @param {Function} fn the method the event invokes. If fn is
+ * undefined, then all event handlers for the type of event are
+ * removed.
+ * @param {String|HTMLElement|Array|NodeList|EventHandle} el An
+ * event handle, an id, an element reference, or a collection
+ * of ids and/or elements to remove the listener from.
+ * @return {boolean} true if the unbind was successful, false otherwise.
+ * @static
+ */
+ detach: function(type, fn, el, obj) {
+
+ var args=Y.Array(arguments, 0, true), compat, i, l, ok,
+ id, ce;
+
+ if (args[args.length-1] === COMPAT_ARG) {
+ compat = true;
+ // args.pop();
+ }
+
+ if (type && type.detach) {
+ return type.detach();
+ }
+
+ // The el argument can be a string
+ if (typeof el == "string") {
+
+ // el = (compat) ? Y.DOM.byId(el) : Y.all(el);
+ if (compat) {
+ el = Y.DOM.byId(el);
+ } else {
+ el = Y.Selector.query(el);
+ l = el.length;
+ if (l < 1) {
+ el = null;
+ } else if (l == 1) {
+ el = el[0];
+ }
+ }
+ // return Y.Event.detach.apply(Y.Event, args);
+
+ // The el argument can be an array of elements or element ids.
+ }
+
+ if (!el) {
+ return false;
+ }
+
+ if (shouldIterate(el)) {
+
+ ok = true;
+ for (i=0, l=el.length; i 0);
+ }
+
+ // onAvailable
+ notAvail = [];
+
+ executeItem = function (el, item) {
+
+ var context, ov = item.override;
+
+ if (item.compat) {
+
+ if (item.override) {
+ if (ov === true) {
+ context = item.obj;
+ } else {
+ context = ov;
+ }
+ } else {
+ context = el;
+ }
+
+ item.fn.call(context, item.obj);
+
+ } else {
+ context = item.obj || Y.one(el);
+ item.fn.apply(context, (Y.Lang.isArray(ov)) ? ov : []);
+ }
+
+ };
+
+
+ // onAvailable
+ for (i=0,len=_avail.length; i 4 ? Y.Array(arguments, 4, true) : [];
+ return Y.Event.onAvailable.call(Y.Event, id, fn, o, a);
+ }
+};
+
+/**
+ * Executes the callback as soon as the specified element
+ * is detected in the DOM with a nextSibling property
+ * (indicating that the element's children are available)
+ * @event contentready
+ * @param type {string} 'contentready'
+ * @param fn {function} the callback function to execute.
+ * @param el {string|HTMLElement|collection} the element(s) to attach
+ * @param context optional argument that specifies what 'this' refers to.
+ * @param args* 0..n additional arguments to pass on to the callback function.
+ * These arguments will be added after the event object.
+ * @return {EventHandle} the detach handle
+ * @for YUI
+ */
+Y.Env.evt.plugins.contentready = {
+ on: function(type, fn, id, o) {
+ var a = arguments.length > 4 ? Y.Array(arguments, 4, true) : [];
+ return Y.Event.onContentReady.call(Y.Event, id, fn, o, a);
+ }
+};
+
+
+}, '3.0.0' ,{requires:['event-custom-base']});
+YUI.add('event-delegate', function(Y) {
+
+/**
+ * Adds event delegation support to the library.
+ *
+ * @module event
+ * @submodule event-delegate
+ */
+
+var Event = Y.Event,
+ Lang = Y.Lang,
+
+ delegates = {},
+
+ specialTypes = {
+ mouseenter: "mouseover",
+ mouseleave: "mouseout"
+ },
+
+ resolveTextNode = function(n) {
+ try {
+ if (n && 3 == n.nodeType) {
+ return n.parentNode;
+ }
+ } catch(e) { }
+ return n;
+ },
+
+ delegateHandler = function(delegateKey, e, el) {
+
+ var target = resolveTextNode((e.target || e.srcElement)),
+ tests = delegates[delegateKey],
+ spec,
+ ename,
+ matched,
+ fn,
+ ev;
+
+
+ var getMatch = function(el, selector, container) {
+
+ var returnVal;
+
+ if (!el || el === container) {
+ returnVal = false;
+ }
+ else {
+ returnVal = Y.Selector.test(el, selector) ? el: getMatch(el.parentNode, selector, container);
+ }
+
+ return returnVal;
+
+ };
+
+
+ for (spec in tests) {
+
+ if (tests.hasOwnProperty(spec)) {
+
+ ename = tests[spec];
+ fn = tests.fn;
+ matched = null;
+
+
+ if (Y.Selector.test(target, spec, el)) {
+ matched = target;
+ }
+ else if (Y.Selector.test(target, ((spec.replace(/,/gi, " *,")) + " *"), el)) {
+
+ // The target is a descendant of an element matching
+ // the selector, so crawl up to find the ancestor that
+ // matches the selector
+
+ matched = getMatch(target, spec, el);
+
+ }
+
+
+ if (matched) {
+
+ if (!ev) {
+ ev = new Y.DOMEventFacade(e, el);
+ ev.container = ev.currentTarget;
+ }
+
+ ev.currentTarget = Y.Node.get(matched);
+
+ Y.publish(ename, {
+ contextFn: function() {
+ return ev.currentTarget;
+ }
+ });
+
+ if (fn) {
+ fn(ev, ename);
+ }
+ else {
+ Y.fire(ename, ev);
+ }
+
+ }
+
+ }
+ }
+
+ },
+
+ attach = function (type, key, element) {
+
+ var focusMethods = {
+ focus: Event._attachFocus,
+ blur: Event._attachBlur
+ },
+
+ attachFn = focusMethods[type],
+
+ args = [type,
+ function (e) {
+ delegateHandler(key, (e || window.event), element);
+ },
+ element];
+
+
+ if (attachFn) {
+ return attachFn(args, { capture: true, facade: false });
+ }
+ else {
+ return Event._attach(args, { facade: false });
+ }
+
+ },
+
+ sanitize = Y.cached(function(str) {
+ return str.replace(/[|,:]/g, '~');
+ });
+
+/**
+ * Sets up event delegation on a container element. The delegated event
+ * will use a supplied selector to test if the target or one of the
+ * descendants of the target match it. The supplied callback function
+ * will only be executed if a match was encountered, and, in fact,
+ * will be executed for each element that matches if you supply an
+ * ambiguous selector.
+ *
+ * The event object for the delegated event is supplied to the callback
+ * function. It is modified slightly in order to support all properties
+ * that may be needed for event delegation. 'currentTarget' is set to
+ * the element that matched the delegation specifcation. 'container' is
+ * set to the element that the listener is bound to (this normally would
+ * be the 'currentTarget').
+ *
+ * @event delegate
+ * @param type {string} 'delegate'
+ * @param fn {function} the callback function to execute. This function
+ * will be provided the event object for the delegated event.
+ * @param el {string|node} the element that is the delegation container
+ * @param delegateType {string} the event type to delegate
+ * @param spec {string} a selector that must match the target of the
+ * event.
+ * @param context optional argument that specifies what 'this' refers to.
+ * @param args* 0..n additional arguments to pass on to the callback function.
+ * These arguments will be added after the event object.
+ * @return {EventHandle} the detach handle
+ * @for YUI
+ * @deprecated use Y.delegate
+ */
+Y.Env.evt.plugins.delegate = {
+
+ on: function(type, fn, el, delegateType, spec) {
+
+
+ var args = Y.Array(arguments, 0, true);
+
+ args.splice(3, 1);
+
+ args[0] = delegateType;
+
+ return Y.delegate.apply(Y, args);
+
+ }
+
+};
+
+
+/**
+ * Sets up event delegation on a container element. The delegated event
+ * will use a supplied selector to test if the target or one of the
+ * descendants of the target match it. The supplied callback function
+ * will only be executed if a match was encountered, and, in fact,
+ * will be executed for each element that matches if you supply an
+ * ambiguous selector.
+ *
+ * The event object for the delegated event is supplied to the callback
+ * function. It is modified slightly in order to support all properties
+ * that may be needed for event delegation. 'currentTarget' is set to
+ * the element that matched the delegation specifcation. 'container' is
+ * set to the element that the listener is bound to (this normally would
+ * be the 'currentTarget').
+ *
+ * @method delegate
+ * @param type {string} the event type to delegate
+ * @param fn {function} the callback function to execute. This function
+ * will be provided the event object for the delegated event.
+ * @param el {string|node} the element that is the delegation container
+ * @param spec {string} a selector that must match the target of the
+ * event.
+ * @param context optional argument that specifies what 'this' refers to.
+ * @param args* 0..n additional arguments to pass on to the callback function.
+ * These arguments will be added after the event object.
+ * @return {EventHandle} the detach handle
+ * @for YUI
+ */
+Event.delegate = function (type, fn, el, spec) {
+
+ if (!spec) {
+ return false;
+ }
+
+
+ var args = Y.Array(arguments, 0, true),
+ element = el, // HTML element serving as the delegation container
+ availHandle;
+
+
+ if (Lang.isString(el)) {
+
+ // Y.Selector.query returns an array of matches unless specified
+ // to return just the first match. Since the primary use case for
+ // event delegation is to use a single event handler on a container,
+ // Y.delegate doesn't currently support being able to bind a
+ // single listener to multiple containers.
+
+ element = Y.Selector.query(el, null, true);
+
+ if (!element) { // Not found, check using onAvailable
+
+ availHandle = Event.onAvailable(el, function() {
+
+ availHandle.handle = Event.delegate.apply(Event, args);
+
+ }, Event, true, false);
+
+ return availHandle;
+
+ }
+
+ }
+
+
+ element = Y.Node.getDOMNode(element);
+
+
+ var guid = Y.stamp(element),
+
+ // The Custom Event for the delegation spec
+ ename = 'delegate:' + guid + type + sanitize(spec),
+
+ // The key to the listener for the event type and container
+ delegateKey = type + guid,
+
+ delegate = delegates[delegateKey],
+
+ domEventHandle,
+
+ ceHandle,
+
+ listeners;
+
+
+ if (!delegate) {
+
+ delegate = {};
+
+ if (specialTypes[type]) {
+
+ if (!Event._fireMouseEnter) {
+ return false;
+ }
+
+ type = specialTypes[type];
+ delegate.fn = Event._fireMouseEnter;
+
+ }
+
+ // Create the DOM Event wrapper that will fire the Custom Event
+
+ domEventHandle = attach(type, delegateKey, element);
+
+
+ // Hook into the _delete method for the Custom Event wrapper of this
+ // DOM Event in order to clean up the 'delegates' map and unsubscribe
+ // the associated Custom Event listeners fired by this DOM event
+ // listener if/when the user calls "purgeElement" OR removes all
+ // listeners of the Custom Event.
+
+ Y.after(function (sub) {
+
+ if (domEventHandle.sub == sub) {
+
+ // Delete this event from the map of known delegates
+ delete delegates[delegateKey];
+
+
+ // Unsubscribe all listeners of the Custom Event fired
+ // by this DOM event.
+ Y.detachAll(ename);
+
+ }
+
+ }, domEventHandle.evt, "_delete");
+
+ delegate.handle = domEventHandle;
+
+ delegates[delegateKey] = delegate;
+
+ }
+
+
+ listeners = delegate.listeners;
+
+ delegate.listeners = listeners ? (listeners + 1) : 1;
+ delegate[spec] = ename;
+
+
+ args[0] = ename;
+
+ // Remove element, delegation spec
+ args.splice(2, 2);
+
+
+ // Subscribe to the Custom Event for the delegation spec
+
+ ceHandle = Y.on.apply(Y, args);
+
+
+ // Hook into the detach method of the handle in order to clean up the
+ // 'delegates' map and remove the associated DOM event handler
+ // responsible for firing this Custom Event if all listener for this
+ // event have been removed.
+
+ Y.after(function () {
+
+ delegate.listeners = (delegate.listeners - 1);
+
+ if (delegate.listeners === 0) {
+ delegate.handle.detach();
+ }
+
+ }, ceHandle, "detach");
+
+ return ceHandle;
+
+};
+
+Y.delegate = Event.delegate;
+
+
+}, '3.0.0' ,{requires:['node-base']});
+YUI.add('event-mousewheel', function(Y) {
+
+/**
+ * Adds mousewheel event support
+ * @module event
+ * @submodule event-mousewheel
+ */
+var DOM_MOUSE_SCROLL = 'DOMMouseScroll',
+ fixArgs = function(args) {
+ var a = Y.Array(args, 0, true), target;
+ if (Y.UA.gecko) {
+ a[0] = DOM_MOUSE_SCROLL;
+ target = Y.config.win;
+ } else {
+ target = Y.config.doc;
+ }
+
+ if (a.length < 3) {
+ a[2] = target;
+ } else {
+ a.splice(2, 0, target);
+ }
+
+ return a;
+ };
+
+/**
+ * Mousewheel event. This listener is automatically attached to the
+ * correct target, so one should not be supplied. Mouse wheel
+ * direction and velocity is stored in the 'mouseDelta' field.
+ * @event mousewheel
+ * @param type {string} 'mousewheel'
+ * @param fn {function} the callback to execute
+ * @param context optional context object
+ * @param args 0..n additional arguments to provide to the listener.
+ * @return {EventHandle} the detach handle
+ * @for YUI
+ */
+Y.Env.evt.plugins.mousewheel = {
+ on: function() {
+ return Y.Event._attach(fixArgs(arguments));
+ },
+
+ detach: function() {
+ return Y.Event.detach.apply(Y.Event, fixArgs(arguments));
+ }
+};
+
+
+}, '3.0.0' ,{requires:['node-base']});
+YUI.add('event-mouseenter', function(Y) {
+
+/**
+ * Adds support for mouseenter/mouseleave events
+ * @module event
+ * @submodule event-mouseenter
+ */
+var Event = Y.Event,
+ Lang = Y.Lang,
+
+ plugins = Y.Env.evt.plugins,
+
+ listeners = {},
+
+ eventConfig = {
+
+ on: function(type, fn, el) {
+
+ var args = Y.Array(arguments, 0, true),
+ element = el,
+ availHandle;
+
+
+ if (Lang.isString(el)) {
+
+ // Need to use Y.all because if el is a string it could be a
+ // selector that returns a NodeList
+
+ element = Y.all(el);
+
+ if (element.size() === 0) { // Not found, check using onAvailable
+
+ availHandle = Event.onAvailable(el, function() {
+
+ availHandle.handle = Y.on.apply(Y, args);
+
+ }, Event, true, false);
+
+ return availHandle;
+
+ }
+
+ }
+
+
+ var sDOMEvent = (type === "mouseenter") ? "mouseover" : "mouseout",
+
+ // The name of the custom event
+ sEventName = type + ":" + Y.stamp(element) + sDOMEvent,
+
+ listener = listeners[sEventName],
+
+ domEventHandle,
+
+ ceHandle,
+
+ nListeners;
+
+
+ // Bind an actual DOM event listener that will call the
+ // the custom event
+ if (!listener) {
+
+ domEventHandle = Y.on(sDOMEvent, Y.rbind(Event._fireMouseEnter, Y, sEventName), element);
+
+ // Hook into the _delete method for the Custom Event wrapper of this
+ // DOM Event in order to clean up the 'listeners' map and unsubscribe
+ // the associated Custom Event listeners fired by this DOM event
+ // listener if/when the user calls "purgeElement" OR removes all
+ // listeners of the Custom Event.
+
+ Y.after(function (sub) {
+
+ if (domEventHandle.sub == sub) {
+
+ // Delete this event from the map of known mouseenter
+ // and mouseleave listeners
+ delete listeners[sEventName];
+
+
+ // Unsubscribe all listeners of the Custom Event fired
+ // by this DOM event.
+ Y.detachAll(sEventName);
+
+ }
+
+ }, domEventHandle.evt, "_delete");
+
+
+ listener = {};
+ listener.handle = domEventHandle;
+
+ listeners[sEventName] = listener;
+
+ }
+
+ nListeners = listener.count;
+
+ listener.count = nListeners ? (nListeners + 1) : 1;
+
+ args[0] = sEventName;
+
+ // Remove the element from the args
+ args.splice(2, 1);
+
+ // Subscribe to the custom event
+ ceHandle = Y.on.apply(Y, args);
+
+ // Hook into the detach method of the handle in order to clean up the
+ // 'listeners' map and remove the associated DOM event handler
+ // responsible for firing this Custom Event if all listener for this
+ // event have been removed.
+
+ Y.after(function () {
+
+ listener.count = (listener.count - 1);
+
+ if (listener.count === 0) {
+ listener.handle.detach();
+ }
+
+ }, ceHandle, "detach");
+
+
+ return ceHandle;
+
+ }
+
+ };
+
+
+Event._fireMouseEnter = function (e, eventName) {
+
+ var relatedTarget = e.relatedTarget,
+ currentTarget = e.currentTarget;
+
+ if (currentTarget !== relatedTarget &&
+ !currentTarget.contains(relatedTarget)) {
+
+ Y.publish(eventName, {
+ contextFn: function() {
+ return currentTarget;
+ }
+ });
+
+ Y.fire(eventName, e);
+
+ }
+
+};
+
+
+/**
+ * Sets up a "mouseenter" listenera listener that is called the first time
+ * the user's mouse enters the specified element(s).
+ *
+ * @event mouseenter
+ * @param type {string} "mouseenter"
+ * @param fn {function} The method the event invokes.
+ * @param el {string|node} The element(s) to assign the listener to.
+ * @param spec {string} Optional. String representing a selector that must
+ * match the target of the event in order for the listener to be called.
+ * @return {EventHandle} the detach handle
+ * @for YUI
+ */
+plugins.mouseenter = eventConfig;
+
+/**
+* Sets up a "mouseleave" listenera listener that is called the first time
+* the user's mouse leaves the specified element(s).
+*
+* @event mouseleave
+* @param type {string} "mouseleave"
+* @param fn {function} The method the event invokes.
+* @param el {string|node} The element(s) to assign the listener to.
+* @param spec {string} Optional. String representing a selector that must
+* match the target of the event in order for the listener to be called.
+* @return {EventHandle} the detach handle
+* @for YUI
+ */
+plugins.mouseleave = eventConfig;
+
+
+}, '3.0.0' ,{requires:['node-base']});
+YUI.add('event-key', function(Y) {
+
+/**
+ * Functionality to listen for one or more specific key combinations.
+ * @module event
+ * @submodule event-key
+ */
+
+/**
+ * Add a key listener. The listener will only be notified if the
+ * keystroke detected meets the supplied specification. The
+ * spec consists of the key event type, followed by a colon,
+ * followed by zero or more comma separated key codes, followed
+ * by zero or more modifiers delimited by a plus sign. Ex:
+ * press:12,65+shift+ctrl
+ * @event key
+ * @for YUI
+ * @param type {string} 'key'
+ * @param fn {function} the function to execute
+ * @param id {string|HTMLElement|collection} the element(s) to bind
+ * @param spec {string} the keyCode and modifier specification
+ * @param o optional context object
+ * @param args 0..n additional arguments to provide to the listener.
+ * @return {Event.Handle} the detach handle
+ */
+Y.Env.evt.plugins.key = {
+
+ on: function(type, fn, id, spec, o) {
+ var a = Y.Array(arguments, 0, true), parsed, etype, criteria, ename;
+
+ parsed = spec && spec.split(':');
+
+ if (!spec || spec.indexOf(':') == -1 || !parsed[1]) {
+ a[0] = 'key' + ((parsed && parsed[0]) || 'press');
+ return Y.on.apply(Y, a);
+ }
+
+ // key event type: 'down', 'up', or 'press'
+ etype = parsed[0];
+
+ // list of key codes optionally followed by modifiers
+ criteria = (parsed[1]) ? parsed[1].split(/,|\+/) : null;
+
+ // the name of the custom event that will be created for the spec
+ ename = (Y.Lang.isString(id) ? id : Y.stamp(id)) + spec;
+
+ ename = ename.replace(/,/g, '_');
+
+ if (!Y.getEvent(ename)) {
+
+ // subscribe spec validator to the DOM event
+ Y.on(type + etype, function(e) {
+
+
+ var passed = false, failed = false, i, crit, critInt;
+
+ for (i=0; i
+ *
onSuccess
+ *
+ * callback to execute when the script(s) are finished loading
+ * The callback receives an object back with the following
+ * data:
+ *
+ *
win
+ *
the window the script(s) were inserted into
+ *
data
+ *
the data object passed in when the request was made
+ *
nodes
+ *
An array containing references to the nodes that were
+ * inserted
+ *
purge
+ *
A function that, when executed, will remove the nodes
+ * that were inserted
+ *
+ *
+ *
+ *
onTimeout
+ *
+ * callback to execute when a timeout occurs.
+ * The callback receives an object back with the following
+ * data:
+ *
+ *
win
+ *
the window the script(s) were inserted into
+ *
data
+ *
the data object passed in when the request was made
+ *
nodes
+ *
An array containing references to the nodes that were
+ * inserted
+ *
purge
+ *
A function that, when executed, will remove the nodes
+ * that were inserted
+ *
+ *
+ *
+ *
onEnd
+ *
a function that executes when the transaction finishes, regardless of the exit path
+ *
onFailure
+ *
+ * callback to execute when the script load operation fails
+ * The callback receives an object back with the following
+ * data:
+ *
+ *
win
+ *
the window the script(s) were inserted into
+ *
data
+ *
the data object passed in when the request was made
+ *
nodes
+ *
An array containing references to the nodes that were
+ * inserted successfully
+ *
purge
+ *
A function that, when executed, will remove any nodes
+ * that were inserted
+ *
+ *
+ *
+ *
context
+ *
the execution context for the callbacks
+ *
win
+ *
a window other than the one the utility occupies
+ *
autopurge
+ *
+ * setting to true will let the utilities cleanup routine purge
+ * the script once loaded
+ *
+ *
purgethreshold
+ *
+ * The number of transaction before autopurge should be initiated
+ *
+ *
data
+ *
+ * data that is supplied to the callback when the script(s) are
+ * loaded.
+ *
+ *
insertBefore
+ *
node or node id that will become the new node's nextSibling
+ *
+ *
charset
+ *
Node charset, default utf-8 (deprecated, use the attributes config)
+ *
attributes
+ *
An object literal containing additional attributes to add to the link tags
+ *
timeout
+ *
Number of milliseconds to wait before aborting and firing the timeout event
+ *
+ * Y.Get.script(
+ * ["http://yui.yahooapis.com/2.5.2/build/yahoo/yahoo-min.js",
+ * "http://yui.yahooapis.com/2.5.2/build/event/event-min.js"], {
+ * onSuccess: function(o) {
+ * this.log("won't cause error because Y is the context");
+ * Y.log(o.data); // foo
+ * Y.log(o.nodes.length === 2) // true
+ * // o.purge(); // optionally remove the script nodes immediately
+ * },
+ * onFailure: function(o) {
+ * Y.log("transaction failed");
+ * },
+ * onTimeout: function(o) {
+ * Y.log("transaction timed out");
+ * },
+ * data: "foo",
+ * timeout: 10000, // 10 second timeout
+ * context: Y, // make the YUI instance
+ * // win: otherframe // target another window/frame
+ * autopurge: true // allow the utility to choose when to remove the nodes
+ * purgetheshold: 1 // purge previous transaction before next transaction
+ * });
+ *
+ * @return {tId: string} an object containing info about the transaction
+ */
+ script: function(url, opts) {
+ return _queue("script", url, opts);
+ },
+
+ /**
+ * Fetches and inserts one or more css link nodes into the
+ * head of the current document or the document in a specified
+ * window.
+ * @method css
+ * @static
+ * @param url {string} the url or urls to the css file(s)
+ * @param opts Options:
+ *
+ *
onSuccess
+ *
+ * callback to execute when the css file(s) are finished loading
+ * The callback receives an object back with the following
+ * data:
+ *
win
+ *
the window the link nodes(s) were inserted into
+ *
data
+ *
the data object passed in when the request was made
+ *
nodes
+ *
An array containing references to the nodes that were
+ * inserted
+ *
purge
+ *
A function that, when executed, will remove the nodes
+ * that were inserted
+ *
+ *
+ *
+ *
context
+ *
the execution context for the callbacks
+ *
win
+ *
a window other than the one the utility occupies
+ *
data
+ *
+ * data that is supplied to the callbacks when the nodes(s) are
+ * loaded.
+ *
+ *
insertBefore
+ *
node or node id that will become the new node's nextSibling
+ *
charset
+ *
Node charset, default utf-8 (deprecated, use the attributes config)
+ *
attributes
+ *
An object literal containing additional attributes to add to the link tags
+*
+* @module node-focusmanager
+*/
+
+ // Frequently used strings
+
+var ACTIVE_DESCENDANT = "activeDescendant",
+ ID = "id",
+ DISABLED = "disabled",
+ TAB_INDEX = "tabIndex",
+ FOCUSED = "focused",
+ FOCUS_CLASS = "focusClass",
+ CIRCULAR = "circular",
+ UI = "UI",
+ KEY = "key",
+ ACTIVE_DESCENDANT_CHANGE = ACTIVE_DESCENDANT + "Change",
+ HOST = "host",
+
+ // Collection of keys that, when pressed, cause the browser viewport
+ // to scroll.
+ scrollKeys = {
+ 37: true,
+ 38: true,
+ 39: true,
+ 40: true
+ },
+
+ clickableElements = {
+ "a": true,
+ "button": true,
+ "input": true,
+ "object": true
+ },
+
+ // Library shortcuts
+
+ Lang = Y.Lang,
+ UA = Y.UA,
+
+ /**
+ * The NodeFocusManager class is a plugin for a Node instance. The class is used
+ * via the plug method of Node
+ * and should not be instantiated directly.
+ * @namespace plugin
+ * @class NodeFocusManager
+ */
+ NodeFocusManager = function () {
+
+ NodeFocusManager.superclass.constructor.apply(this, arguments);
+
+ };
+
+
+NodeFocusManager.ATTRS = {
+
+ /**
+ * Boolean indicating that one of the descendants is focused.
+ *
+ * @attribute focused
+ * @readOnly
+ * @default false
+ * @type boolean
+ */
+ focused: {
+
+ value: false,
+ readOnly: true
+
+ },
+
+
+ /**
+ * String representing the CSS selector used to define the descendant Nodes
+ * whose focus should be managed.
+ *
+ * @attribute descendants
+ * @type Y.NodeList
+ */
+ descendants: {
+
+ getter: function (value) {
+
+ return this.get(HOST).all(value);
+
+ }
+
+ },
+
+
+ /**
+ *
Node, or index of the Node, representing the descendant that is either
+ * focused or is focusable (tabIndex attribute is set to 0).
+ * The value cannot represent a disabled descendant Node. Use a value of -1
+ * to remove all descendant Nodes from the default tab flow.
+ * If no value is specified, the active descendant will be inferred using
+ * the following criteria:
+ *
+ *
Examining the tabIndex attribute of each descendant and
+ * using the first descendant whose tabIndex attribute is set
+ * to 0
+ *
If no default can be inferred then the value is set to either 0 or
+ * the index of the first enabled descendant.
+ *
+ *
+ * @attribute activeDescendant
+ * @type Number
+ */
+ activeDescendant: {
+
+ setter: function (value) {
+
+ var isNumber = Lang.isNumber,
+ INVALID_VALUE = Y.Attribute.INVALID_VALUE,
+ descendantsMap = this._descendantsMap,
+ descendants = this._descendants,
+ nodeIndex,
+ returnValue,
+ oNode;
+
+
+ if (isNumber(value)) {
+ nodeIndex = value;
+ returnValue = nodeIndex;
+ }
+ else if ((value instanceof Y.Node) && descendantsMap) {
+
+ nodeIndex = descendantsMap[value.get(ID)];
+
+ if (isNumber(nodeIndex)) {
+ returnValue = nodeIndex;
+ }
+ else {
+
+ // The user passed a reference to a Node that wasn't one
+ // of the descendants.
+ returnValue = INVALID_VALUE;
+
+ }
+
+ }
+ else {
+ returnValue = INVALID_VALUE;
+ }
+
+
+ if (descendants) {
+
+ oNode = descendants.item(nodeIndex);
+
+ if (oNode && oNode.get("disabled")) {
+
+ // Setting the "activeDescendant" attribute to the index
+ // of a disabled descendant is invalid.
+ returnValue = INVALID_VALUE;
+
+ }
+
+ }
+
+ return returnValue;
+
+ }
+
+ },
+
+
+ /**
+ * Object literal representing the keys to be used to navigate between the
+ * next/previous descendant. The format for the attribute's value is
+ * { next: "down:40", previous: "down:38" }. The value for the
+ * "next" and "previous" properties are used to attach
+ * key event listeners. See
+ * the Using the key Event section of
+ * the Event documentation for more information on "key" event listeners.
+ *
+ * @attribute keys
+ * @type Object
+ */
+ keys: {
+
+ value: {
+
+ next: null,
+ previous: null
+
+ }
+
+
+ },
+
+
+ /**
+ * String representing the name of class applied to the focused active
+ * descendant Node. Can also be an object literal used to define both the
+ * class name, and the Node to which the class should be applied. If using
+ * an object literal, the format is:
+ * { className: "focus", fn: myFunction }. The function
+ * referenced by the fn property in the object literal will be
+ * passed a reference to the currently focused active descendant Node.
+ *
+ * @attribute focusClass
+ * @type String|Object
+ */
+ focusClass: { },
+
+
+ /**
+ * Boolean indicating if focus should be set to the first/last descendant
+ * when the end or beginning of the descendants has been reached.
+ *
+ * @attribute circular
+ * @type Boolean
+ */
+ circular: {
+ value: true
+ }
+
+};
+
+Y.extend(NodeFocusManager, Y.Plugin.Base, {
+
+ // Protected properties
+
+ // Boolean indicating if the NodeFocusManager is active.
+ _stopped: true,
+
+ // NodeList representing the descendants selected via the
+ // "descendants" attribute.
+ _descendants: null,
+
+ // Object literal mapping the IDs of each descendant to its index in the
+ // "_descendants" NodeList.
+ _descendantsMap: null,
+
+ // Reference to the Node instance to which the focused class (defined
+ // by the "focusClass" attribute) is currently applied.
+ _focusedNode: null,
+
+ // Number representing the index of the last descendant Node.
+ _lastNodeIndex: 0,
+
+ // Array of handles for event handlers used for a NodeFocusManager instance.
+ _eventHandlers: null,
+
+
+
+ // Protected methods
+
+ /**
+ * @method _initDescendants
+ * @description Sets the tabIndex attribute of all of the
+ * descendants to -1, except the active descendant, whose
+ * tabIndex attribute is set to 0.
+ * @protected
+ */
+ _initDescendants: function () {
+
+ var descendants = this.get("descendants"),
+ descendantsMap = {},
+ nFirstEnabled = -1,
+ nDescendants,
+ nActiveDescendant = this.get(ACTIVE_DESCENDANT),
+ oNode,
+ sID,
+ i = 0;
+
+
+
+ if (Lang.isUndefined(nActiveDescendant)) {
+ nActiveDescendant = -1;
+ }
+
+
+ if (descendants) {
+
+ nDescendants = descendants.size();
+
+
+ if (nDescendants > 1) {
+
+ for (i = 0; i < nDescendants; i++) {
+
+ oNode = descendants.item(i);
+
+ if (nFirstEnabled === -1 && !oNode.get(DISABLED)) {
+ nFirstEnabled = i;
+ }
+
+
+ // If the user didn't specify a value for the
+ // "activeDescendant" attribute try to infer it from
+ // the markup.
+
+ // Need to pass "2" when using "getAttribute" for IE to get
+ // the attribute value as it is set in the markup.
+ // Need to use "parseInt" because IE always returns the
+ // value as a number, whereas all other browsers return
+ // the attribute as a string when accessed
+ // via "getAttribute".
+
+ if (nActiveDescendant < 0 &&
+ parseInt(oNode.getAttribute(TAB_INDEX, 2), 10) === 0) {
+
+ nActiveDescendant = i;
+
+ }
+
+ oNode.set(TAB_INDEX, -1);
+
+ sID = oNode.get(ID);
+
+ if (!sID) {
+ sID = Y.guid();
+ oNode.set(ID, sID);
+ }
+
+ descendantsMap[sID] = i;
+
+ }
+
+
+ // If the user didn't specify a value for the
+ // "activeDescendant" attribute and no default value could be
+ // determined from the markup, then default to 0.
+
+ if (nActiveDescendant < 0) {
+ nActiveDescendant = 0;
+ }
+
+
+ oNode = descendants.item(nActiveDescendant);
+
+ // Check to make sure the active descendant isn't disabled,
+ // and fall back to the first enabled descendant if it is.
+
+ if (!oNode || oNode.get(DISABLED)) {
+ oNode = descendants.item(nFirstEnabled);
+ nActiveDescendant = nFirstEnabled;
+ }
+
+ this._lastNodeIndex = nDescendants - 1;
+ this._descendants = descendants;
+ this._descendantsMap = descendantsMap;
+
+ this.set(ACTIVE_DESCENDANT, nActiveDescendant);
+
+ // Need to set the "tabIndex" attribute here, since the
+ // "activeDescendantChange" event handler used to manage
+ // the setting of the "tabIndex" attribute isn't wired up yet.
+
+ oNode.set(TAB_INDEX, 0);
+
+ }
+
+ }
+
+ },
+
+
+ /**
+ * @method _isDescendant
+ * @description Determines if the specified Node instance is a descendant
+ * managed by the Focus Manager.
+ * @param node {Node} Node instance to be checked.
+ * @return {Boolean} Boolean indicating if the specified Node instance is a
+ * descendant managed by the Focus Manager.
+ * @protected
+ */
+ _isDescendant: function (node) {
+
+ return (node.get(ID) in this._descendantsMap);
+
+ },
+
+
+ /**
+ * @method _removeFocusClass
+ * @description Removes the class name representing focus (as specified by
+ * the "focusClass" attribute) from the Node instance to which it is
+ * currently applied.
+ * @protected
+ */
+ _removeFocusClass: function () {
+
+ var oFocusedNode = this._focusedNode,
+ focusClass = this.get(FOCUS_CLASS),
+ sClassName;
+
+ if (focusClass) {
+ sClassName = Lang.isString(focusClass) ?
+ focusClass : focusClass.className;
+ }
+
+ if (oFocusedNode && sClassName) {
+ oFocusedNode.removeClass(sClassName);
+ }
+
+ },
+
+
+ /**
+ * @method _detachKeyHandler
+ * @description Detaches the "key" event handlers used to support the "keys"
+ * attribute.
+ * @protected
+ */
+ _detachKeyHandler: function () {
+
+ var prevKeyHandler = this._prevKeyHandler,
+ nextKeyHandler = this._nextKeyHandler;
+
+ if (prevKeyHandler) {
+ prevKeyHandler.detach();
+ }
+
+ if (nextKeyHandler) {
+ nextKeyHandler.detach();
+ }
+
+ },
+
+
+ /**
+ * @method _preventScroll
+ * @description Prevents the viewport from scolling when the user presses
+ * the up, down, left, or right key.
+ * @protected
+ */
+ _preventScroll: function (event) {
+
+ if (scrollKeys[event.keyCode]) {
+ event.preventDefault();
+ }
+
+ },
+
+
+ /**
+ * @method _preventScroll
+ * @description Fires the click event if the enter key is pressed while
+ * focused on an HTML element that is not natively clickable.
+ * @protected
+ */
+ _fireClick: function (event) {
+
+ var oTarget = event.target,
+ sNodeName = oTarget.get("nodeName").toLowerCase();
+
+ if (event.keyCode === 13 && (!clickableElements[sNodeName] ||
+ (sNodeName === "a" && !oTarget.getAttribute("href")))) {
+
+ Y.log(("Firing click event for node:" + oTarget.get("id")), "info", "nodeFocusManager");
+
+ oTarget.simulate("click");
+
+ }
+
+ },
+
+
+ /**
+ * @method _attachKeyHandler
+ * @description Attaches the "key" event handlers used to support the "keys"
+ * attribute.
+ * @protected
+ */
+ _attachKeyHandler: function () {
+
+ this._detachKeyHandler();
+
+ var sNextKey = this.get("keys.next"),
+ sPrevKey = this.get("keys.previous"),
+ oNode = this.get(HOST),
+ aHandlers = this._eventHandlers;
+
+ if (sPrevKey) {
+ this._prevKeyHandler =
+ Y.on(KEY, Y.bind(this._focusPrevious, this), oNode, sPrevKey);
+ }
+
+ if (sNextKey) {
+ this._nextKeyHandler =
+ Y.on(KEY, Y.bind(this._focusNext, this), oNode, sNextKey);
+ }
+
+
+ // In Opera it is necessary to call the "preventDefault" method in
+ // response to the user pressing the arrow keys in order to prevent
+ // the viewport from scrolling when the user is moving focus among
+ // the focusable descendants.
+
+ if (UA.opera) {
+ aHandlers.push(oNode.on("keypress", this._preventScroll, this));
+ }
+
+
+ // For all browsers except Opera: HTML elements that are not natively
+ // focusable but made focusable via the tabIndex attribute don't
+ // fire a click event when the user presses the enter key. It is
+ // possible to work around this problem by simplying dispatching a
+ // click event in response to the user pressing the enter key.
+
+ if (!UA.opera) {
+ aHandlers.push(oNode.on("keypress", this._fireClick, this));
+ }
+
+ },
+
+
+ /**
+ * @method _detachEventHandlers
+ * @description Detaches all event handlers used by the Focus Manager.
+ * @protected
+ */
+ _detachEventHandlers: function () {
+
+ this._detachKeyHandler();
+
+ var aHandlers = this._eventHandlers;
+
+ if (aHandlers) {
+
+ Y.Array.each(aHandlers, function (handle) {
+ handle.detach();
+ });
+
+ this._eventHandlers = null;
+
+ }
+
+ },
+
+
+ /**
+ * @method _detachEventHandlers
+ * @description Attaches all event handlers used by the Focus Manager.
+ * @protected
+ */
+ _attachEventHandlers: function () {
+
+ var descendants = this._descendants,
+ aHandlers,
+ oDocument,
+ handle;
+
+ if (descendants && descendants.size() > 1) {
+
+ aHandlers = this._eventHandlers || [];
+ oDocument = this.get(HOST).get("ownerDocument");
+
+
+ if (aHandlers.length === 0) {
+
+ Y.log("Attaching base set of event handlers.", "info", "nodeFocusManager");
+
+ aHandlers.push(oDocument.on("focus", this._onDocFocus, this));
+
+ aHandlers.push(oDocument.on("mousedown",
+ this._onDocMouseDown, this));
+
+ aHandlers.push(
+ this.after("keysChange", this._attachKeyHandler));
+
+ aHandlers.push(
+ this.after("descendantsChange", this._initDescendants));
+
+ aHandlers.push(
+ this.after(ACTIVE_DESCENDANT_CHANGE,
+ this._afterActiveDescendantChange));
+
+
+ // For performance: defer attaching all key-related event
+ // handlers until the first time one of the specified
+ // descendants receives focus.
+
+ handle = this.after("focusedChange", Y.bind(function (event) {
+
+ if (event.newVal) {
+
+ Y.log("Attaching key event handlers.", "info", "nodeFocusManager");
+
+ this._attachKeyHandler();
+
+ // Detach this "focusedChange" handler so that the
+ // key-related handlers only get attached once.
+
+ handle.detach();
+
+ }
+
+ }, this));
+
+ aHandlers.push(handle);
+
+ }
+
+
+ this._eventHandlers = aHandlers;
+
+ }
+
+ },
+
+
+ // Protected event handlers
+
+ /**
+ * @method _onDocMouseDown
+ * @description "mousedown" event handler for the owner document of the
+ * Focus Manager's Node.
+ * @protected
+ * @param event {Object} Object representing the DOM event.
+ */
+ _onDocMouseDown: function (event) {
+
+ var oHost = this.get(HOST),
+ oTarget = event.target,
+ bChildNode = oHost.contains(oTarget),
+ node,
+
+ getFocusable = function (node) {
+
+ var returnVal = false;
+
+ if (!node.compareTo(oHost)) {
+
+ returnVal = this._isDescendant(node) ? node :
+ getFocusable.call(this, node.get("parentNode"));
+
+ }
+
+ return returnVal;
+
+ };
+
+
+ if (bChildNode) {
+
+ // Check to make sure that the target isn't a child node of one
+ // of the focusable descendants.
+
+ node = getFocusable.call(this, oTarget);
+
+ if (node) {
+ oTarget = node;
+ }
+ else if (!node && this.get(FOCUSED)) {
+
+ // The target was a non-focusable descendant of the root
+ // node, so the "focused" attribute should be set to false.
+
+ this._set(FOCUSED, false);
+ this._onDocFocus(event);
+
+ }
+
+ }
+
+
+ if (bChildNode && this._isDescendant(oTarget)) {
+
+ // Fix general problem in Webkit: mousing down on a button or an
+ // anchor element doesn't focus it.
+
+ // For all browsers: makes sure that the descendant that
+ // was the target of the mousedown event is now considered the
+ // active descendant.
+
+ this.focus(oTarget);
+ }
+ else if (UA.webkit && this.get(FOCUSED) &&
+ (!bChildNode || (bChildNode && !this._isDescendant(oTarget)))) {
+
+ // Fix for Webkit:
+
+ // Document doesn't receive focus in Webkit when the user mouses
+ // down on it, so the "focused" attribute won't get set to the
+ // correct value.
+
+ // The goal is to force a blur if the user moused down on
+ // either: 1) A descendant node, but not one that managed by
+ // the FocusManager, or 2) an element outside of the
+ // FocusManager
+
+ this._set(FOCUSED, false);
+ this._onDocFocus(event);
+
+ }
+
+ },
+
+
+ /**
+ * @method _onDocFocus
+ * @description "focus" event handler for the owner document of the
+ * Focus Manager's Node.
+ * @protected
+ * @param event {Object} Object representing the DOM event.
+ */
+ _onDocFocus: function (event) {
+
+ var oTarget = this._focusTarget || event.target,
+ bFocused = this.get(FOCUSED),
+ focusClass = this.get(FOCUS_CLASS),
+ oFocusedNode = this._focusedNode,
+ bInCollection;
+
+ if (this._focusTarget) {
+ this._focusTarget = null;
+ }
+
+
+ if (this.get(HOST).contains(oTarget)) {
+
+ // The target is a descendant of the root Node.
+
+ bInCollection = this._isDescendant(oTarget);
+
+ if (!bFocused && bInCollection) {
+
+ // The user has focused a focusable descendant.
+
+ bFocused = true;
+
+ }
+ else if (bFocused && !bInCollection) {
+
+ // The user has focused a child of the root Node that is
+ // not one of the descendants managed by this Focus Manager
+ // so clear the currently focused descendant.
+
+ bFocused = false;
+
+ }
+
+ }
+ else {
+
+ // The target is some other node in the document.
+
+ bFocused = false;
+
+ }
+
+
+ if (focusClass) {
+
+ if (oFocusedNode && (!oFocusedNode.compareTo(oTarget) || !bFocused)) {
+ this._removeFocusClass();
+ }
+
+ if (bInCollection && bFocused) {
+
+ if (focusClass.fn) {
+ oTarget = focusClass.fn(oTarget);
+ oTarget.addClass(focusClass.className);
+ }
+ else {
+ oTarget.addClass(focusClass);
+ }
+
+ this._focusedNode = oTarget;
+
+ }
+
+ }
+
+
+ this._set(FOCUSED, bFocused);
+
+ },
+
+
+ /**
+ * @method _focusNext
+ * @description Keydown event handler that moves focus to the next
+ * enabled descendant.
+ * @protected
+ * @param event {Object} Object representing the DOM event.
+ * @param activeDescendant {Number} Number representing the index of the
+ * next descendant to be focused
+ */
+ _focusNext: function (event, activeDescendant) {
+
+ var nActiveDescendant = activeDescendant || this.get(ACTIVE_DESCENDANT),
+ oNode;
+
+
+ if (this._isDescendant(event.target) &&
+ (nActiveDescendant <= this._lastNodeIndex)) {
+
+ nActiveDescendant = nActiveDescendant + 1;
+
+ if (nActiveDescendant === (this._lastNodeIndex + 1) &&
+ this.get(CIRCULAR)) {
+
+ nActiveDescendant = 0;
+
+ }
+
+ oNode = this._descendants.item(nActiveDescendant);
+
+ if (oNode.get(DISABLED)) {
+ this._focusNext(event, nActiveDescendant);
+ }
+ else {
+ this.focus(nActiveDescendant);
+ }
+
+ }
+
+ this._preventScroll(event);
+
+ },
+
+
+ /**
+ * @method _focusPrevious
+ * @description Keydown event handler that moves focus to the previous
+ * enabled descendant.
+ * @protected
+ * @param event {Object} Object representing the DOM event.
+ * @param activeDescendant {Number} Number representing the index of the
+ * next descendant to be focused.
+ */
+ _focusPrevious: function (event, activeDescendant) {
+
+ var nActiveDescendant = activeDescendant || this.get(ACTIVE_DESCENDANT),
+ oNode;
+
+ if (this._isDescendant(event.target) && nActiveDescendant >= 0) {
+
+ nActiveDescendant = nActiveDescendant - 1;
+
+ if (nActiveDescendant === -1 && this.get(CIRCULAR)) {
+ nActiveDescendant = this._lastNodeIndex;
+ }
+
+ oNode = this._descendants.item(nActiveDescendant);
+
+ if (oNode.get(DISABLED)) {
+ this._focusPrevious(event, nActiveDescendant);
+ }
+ else {
+ this.focus(nActiveDescendant);
+ }
+
+ }
+
+ this._preventScroll(event);
+
+ },
+
+
+ /**
+ * @method _afterActiveDescendantChange
+ * @description afterChange event handler for the
+ * "activeDescendant" attribute.
+ * @protected
+ * @param event {Object} Object representing the change event.
+ */
+ _afterActiveDescendantChange: function (event) {
+
+ var oNode = this._descendants.item(event.prevVal);
+
+ if (oNode) {
+ oNode.set(TAB_INDEX, -1);
+ }
+
+ oNode = this._descendants.item(event.newVal);
+
+ if (oNode) {
+ oNode.set(TAB_INDEX, 0);
+ }
+
+ },
+
+
+
+ // Public methods
+
+ initializer: function (config) {
+
+ this.start();
+
+ },
+
+ destructor: function () {
+
+ this.stop();
+ this.get(HOST).focusManager = null;
+
+ },
+
+
+ /**
+ * @method focus
+ * @description Focuses the active descendant and sets the
+ * focused attribute to true.
+ * @param index {Number} Optional. Number representing the index of the
+ * descendant to be set as the active descendant.
+ * @param index {Node} Optional. Node instance representing the
+ * descendant to be set as the active descendant.
+ */
+ focus: function (index) {
+
+ if (Lang.isUndefined(index)) {
+ index = this.get(ACTIVE_DESCENDANT);
+ }
+
+ this.set(ACTIVE_DESCENDANT, index, { src: UI });
+
+ var oNode = this._descendants.item(this.get(ACTIVE_DESCENDANT));
+
+ if (oNode) {
+
+ oNode.focus();
+
+ // In Opera focusing a