Update wmts-hidpi, add nicer-api-docs

This commit is contained in:
Andreas Hocevar
2014-05-06 13:02:46 -05:00
parent b3ac1afd00
commit 1e25fc5585
2239 changed files with 3726515 additions and 37010 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,210 @@
// Copyright 2006 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Basic animation controls.
*
*/
goog.provide('goog.fx.anim');
goog.provide('goog.fx.anim.Animated');
goog.require('goog.async.AnimationDelay');
goog.require('goog.async.Delay');
goog.require('goog.object');
/**
* An interface for programatically animated objects. I.e. rendered in
* javascript frame by frame.
*
* @interface
*/
goog.fx.anim.Animated = function() {};
/**
* Function called when a frame is requested for the animation.
*
* @param {number} now Current time in milliseconds.
*/
goog.fx.anim.Animated.prototype.onAnimationFrame;
/**
* Default wait timeout for animations (in milliseconds). Only used for timed
* animation, which uses a timer (setTimeout) to schedule animation.
*
* @type {number}
* @const
*/
goog.fx.anim.TIMEOUT = goog.async.AnimationDelay.TIMEOUT;
/**
* A map of animations which should be cycled on the global timer.
*
* @type {Object.<number, goog.fx.anim.Animated>}
* @private
*/
goog.fx.anim.activeAnimations_ = {};
/**
* An optional animation window.
* @type {Window}
* @private
*/
goog.fx.anim.animationWindow_ = null;
/**
* An interval ID for the global timer or event handler uid.
* @type {goog.async.Delay|goog.async.AnimationDelay}
* @private
*/
goog.fx.anim.animationDelay_ = null;
/**
* Registers an animation to be cycled on the global timer.
* @param {goog.fx.anim.Animated} animation The animation to register.
*/
goog.fx.anim.registerAnimation = function(animation) {
var uid = goog.getUid(animation);
if (!(uid in goog.fx.anim.activeAnimations_)) {
goog.fx.anim.activeAnimations_[uid] = animation;
}
// If the timer is not already started, start it now.
goog.fx.anim.requestAnimationFrame_();
};
/**
* Removes an animation from the list of animations which are cycled on the
* global timer.
* @param {goog.fx.anim.Animated} animation The animation to unregister.
*/
goog.fx.anim.unregisterAnimation = function(animation) {
var uid = goog.getUid(animation);
delete goog.fx.anim.activeAnimations_[uid];
// If a timer is running and we no longer have any active timers we stop the
// timers.
if (goog.object.isEmpty(goog.fx.anim.activeAnimations_)) {
goog.fx.anim.cancelAnimationFrame_();
}
};
/**
* Tears down this module. Useful for testing.
*/
// TODO(nicksantos): Wow, this api is pretty broken. This should be fixed.
goog.fx.anim.tearDown = function() {
goog.fx.anim.animationWindow_ = null;
goog.dispose(goog.fx.anim.animationDelay_);
goog.fx.anim.animationDelay_ = null;
goog.fx.anim.activeAnimations_ = {};
};
/**
* Registers an animation window. This allows usage of the timing control API
* for animations. Note that this window must be visible, as non-visible
* windows can potentially stop animating. This window does not necessarily
* need to be the window inside which animation occurs, but must remain visible.
* See: https://developer.mozilla.org/en/DOM/window.mozRequestAnimationFrame.
*
* @param {Window} animationWindow The window in which to animate elements.
*/
goog.fx.anim.setAnimationWindow = function(animationWindow) {
// If a timer is currently running, reset it and restart with new functions
// after a timeout. This is to avoid mismatching timer UIDs if we change the
// animation window during a running animation.
//
// In practice this cannot happen before some animation window and timer
// control functions has already been set.
var hasTimer =
goog.fx.anim.animationDelay_ && goog.fx.anim.animationDelay_.isActive();
goog.dispose(goog.fx.anim.animationDelay_);
goog.fx.anim.animationDelay_ = null;
goog.fx.anim.animationWindow_ = animationWindow;
// If the timer was running, start it again.
if (hasTimer) {
goog.fx.anim.requestAnimationFrame_();
}
};
/**
* Requests an animation frame based on the requestAnimationFrame and
* cancelRequestAnimationFrame function pair.
* @private
*/
goog.fx.anim.requestAnimationFrame_ = function() {
if (!goog.fx.anim.animationDelay_) {
// We cannot guarantee that the global window will be one that fires
// requestAnimationFrame events (consider off-screen chrome extension
// windows). Default to use goog.async.Delay, unless
// the client has explicitly set an animation window.
if (goog.fx.anim.animationWindow_) {
// requestAnimationFrame will call cycleAnimations_ with the current
// time in ms, as returned from goog.now().
goog.fx.anim.animationDelay_ = new goog.async.AnimationDelay(
function(now) {
goog.fx.anim.cycleAnimations_(now);
}, goog.fx.anim.animationWindow_);
} else {
goog.fx.anim.animationDelay_ = new goog.async.Delay(function() {
goog.fx.anim.cycleAnimations_(goog.now());
}, goog.fx.anim.TIMEOUT);
}
}
var delay = goog.fx.anim.animationDelay_;
if (!delay.isActive()) {
delay.start();
}
};
/**
* Cancels an animation frame created by requestAnimationFrame_().
* @private
*/
goog.fx.anim.cancelAnimationFrame_ = function() {
if (goog.fx.anim.animationDelay_) {
goog.fx.anim.animationDelay_.stop();
}
};
/**
* Cycles through all registered animations.
* @param {number} now Current time in milliseconds.
* @private
*/
goog.fx.anim.cycleAnimations_ = function(now) {
goog.object.forEach(goog.fx.anim.activeAnimations_, function(anim) {
anim.onAnimationFrame(now);
});
if (!goog.object.isEmpty(goog.fx.anim.activeAnimations_)) {
goog.fx.anim.requestAnimationFrame_();
}
};

View File

@@ -0,0 +1,530 @@
// Copyright 2006 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Classes for doing animations and visual effects.
*
* (Based loosly on my animation code for 13thparallel.org, with extra
* inspiration from the DojoToolkit's modifications to my code)
*/
goog.provide('goog.fx.Animation');
goog.provide('goog.fx.Animation.EventType');
goog.provide('goog.fx.Animation.State');
goog.provide('goog.fx.AnimationEvent');
goog.require('goog.array');
goog.require('goog.events.Event');
goog.require('goog.fx.Transition'); // Unreferenced: interface
goog.require('goog.fx.Transition.EventType');
goog.require('goog.fx.TransitionBase.State');
goog.require('goog.fx.anim');
goog.require('goog.fx.anim.Animated'); // Unreferenced: interface
/**
* Constructor for an animation object.
* @param {Array.<number>} start Array for start coordinates.
* @param {Array.<number>} end Array for end coordinates.
* @param {number} duration Length of animation in milliseconds.
* @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
* @constructor
* @implements {goog.fx.anim.Animated}
* @implements {goog.fx.Transition}
* @extends {goog.fx.TransitionBase}
*/
goog.fx.Animation = function(start, end, duration, opt_acc) {
goog.base(this);
if (!goog.isArray(start) || !goog.isArray(end)) {
throw Error('Start and end parameters must be arrays');
}
if (start.length != end.length) {
throw Error('Start and end points must be the same length');
}
/**
* Start point.
* @type {Array.<number>}
* @protected
*/
this.startPoint = start;
/**
* End point.
* @type {Array.<number>}
* @protected
*/
this.endPoint = end;
/**
* Duration of animation in milliseconds.
* @type {number}
* @protected
*/
this.duration = duration;
/**
* Acceleration function, which must return a number between 0 and 1 for
* inputs between 0 and 1.
* @type {Function|undefined}
* @private
*/
this.accel_ = opt_acc;
/**
* Current coordinate for animation.
* @type {Array.<number>}
* @protected
*/
this.coords = [];
/**
* Whether the animation should use "right" rather than "left" to position
* elements in RTL. This is a temporary flag to allow clients to transition
* to the new behavior at their convenience. At some point it will be the
* default.
* @type {boolean}
* @private
*/
this.useRightPositioningForRtl_ = false;
};
goog.inherits(goog.fx.Animation, goog.fx.TransitionBase);
/**
* Sets whether the animation should use "right" rather than "left" to position
* elements. This is a temporary flag to allow clients to transition
* to the new component at their convenience. At some point "right" will be
* used for RTL elements by default.
* @param {boolean} useRightPositioningForRtl True if "right" should be used for
* positioning, false if "left" should be used for positioning.
*/
goog.fx.Animation.prototype.enableRightPositioningForRtl =
function(useRightPositioningForRtl) {
this.useRightPositioningForRtl_ = useRightPositioningForRtl;
};
/**
* Whether the animation should use "right" rather than "left" to position
* elements. This is a temporary flag to allow clients to transition
* to the new component at their convenience. At some point "right" will be
* used for RTL elements by default.
* @return {boolean} True if "right" should be used for positioning, false if
* "left" should be used for positioning.
*/
goog.fx.Animation.prototype.isRightPositioningForRtlEnabled = function() {
return this.useRightPositioningForRtl_;
};
/**
* Events fired by the animation.
* @enum {string}
*/
goog.fx.Animation.EventType = {
/**
* Dispatched when played for the first time OR when it is resumed.
* @deprecated Use goog.fx.Transition.EventType.PLAY.
*/
PLAY: goog.fx.Transition.EventType.PLAY,
/**
* Dispatched only when the animation starts from the beginning.
* @deprecated Use goog.fx.Transition.EventType.BEGIN.
*/
BEGIN: goog.fx.Transition.EventType.BEGIN,
/**
* Dispatched only when animation is restarted after a pause.
* @deprecated Use goog.fx.Transition.EventType.RESUME.
*/
RESUME: goog.fx.Transition.EventType.RESUME,
/**
* Dispatched when animation comes to the end of its duration OR stop
* is called.
* @deprecated Use goog.fx.Transition.EventType.END.
*/
END: goog.fx.Transition.EventType.END,
/**
* Dispatched only when stop is called.
* @deprecated Use goog.fx.Transition.EventType.STOP.
*/
STOP: goog.fx.Transition.EventType.STOP,
/**
* Dispatched only when animation comes to its end naturally.
* @deprecated Use goog.fx.Transition.EventType.FINISH.
*/
FINISH: goog.fx.Transition.EventType.FINISH,
/**
* Dispatched when an animation is paused.
* @deprecated Use goog.fx.Transition.EventType.PAUSE.
*/
PAUSE: goog.fx.Transition.EventType.PAUSE,
/**
* Dispatched each frame of the animation. This is where the actual animator
* will listen.
*/
ANIMATE: 'animate',
/**
* Dispatched when the animation is destroyed.
*/
DESTROY: 'destroy'
};
/**
* @deprecated Use goog.fx.anim.TIMEOUT.
*/
goog.fx.Animation.TIMEOUT = goog.fx.anim.TIMEOUT;
/**
* Enum for the possible states of an animation.
* @deprecated Use goog.fx.Transition.State instead.
* @enum {number}
*/
goog.fx.Animation.State = goog.fx.TransitionBase.State;
/**
* @deprecated Use goog.fx.anim.setAnimationWindow.
* @param {Window} animationWindow The window in which to animate elements.
*/
goog.fx.Animation.setAnimationWindow = function(animationWindow) {
goog.fx.anim.setAnimationWindow(animationWindow);
};
/**
* Current frame rate.
* @type {number}
* @private
*/
goog.fx.Animation.prototype.fps_ = 0;
/**
* Percent of the way through the animation.
* @type {number}
* @protected
*/
goog.fx.Animation.prototype.progress = 0;
/**
* Timestamp for when last frame was run.
* @type {?number}
* @protected
*/
goog.fx.Animation.prototype.lastFrame = null;
/**
* Starts or resumes an animation.
* @param {boolean=} opt_restart Whether to restart the
* animation from the beginning if it has been paused.
* @return {boolean} Whether animation was started.
* @override
*/
goog.fx.Animation.prototype.play = function(opt_restart) {
if (opt_restart || this.isStopped()) {
this.progress = 0;
this.coords = this.startPoint;
} else if (this.isPlaying()) {
return false;
}
goog.fx.anim.unregisterAnimation(this);
var now = /** @type {number} */ (goog.now());
this.startTime = now;
if (this.isPaused()) {
this.startTime -= this.duration * this.progress;
}
this.endTime = this.startTime + this.duration;
this.lastFrame = this.startTime;
if (!this.progress) {
this.onBegin();
}
this.onPlay();
if (this.isPaused()) {
this.onResume();
}
this.setStatePlaying();
goog.fx.anim.registerAnimation(this);
this.cycle(now);
return true;
};
/**
* Stops the animation.
* @param {boolean=} opt_gotoEnd If true the animation will move to the
* end coords.
* @override
*/
goog.fx.Animation.prototype.stop = function(opt_gotoEnd) {
goog.fx.anim.unregisterAnimation(this);
this.setStateStopped();
if (!!opt_gotoEnd) {
this.progress = 1;
}
this.updateCoords_(this.progress);
this.onStop();
this.onEnd();
};
/**
* Pauses the animation (iff it's playing).
* @override
*/
goog.fx.Animation.prototype.pause = function() {
if (this.isPlaying()) {
goog.fx.anim.unregisterAnimation(this);
this.setStatePaused();
this.onPause();
}
};
/**
* @return {number} The current progress of the animation, the number
* is between 0 and 1 inclusive.
*/
goog.fx.Animation.prototype.getProgress = function() {
return this.progress;
};
/**
* Sets the progress of the animation.
* @param {number} progress The new progress of the animation.
*/
goog.fx.Animation.prototype.setProgress = function(progress) {
this.progress = progress;
if (this.isPlaying()) {
var now = goog.now();
// If the animation is already playing, we recompute startTime and endTime
// such that the animation plays consistently, that is:
// now = startTime + progress * duration.
this.startTime = now - this.duration * this.progress;
this.endTime = this.startTime + this.duration;
}
};
/**
* Disposes of the animation. Stops an animation, fires a 'destroy' event and
* then removes all the event handlers to clean up memory.
* @override
* @protected
*/
goog.fx.Animation.prototype.disposeInternal = function() {
if (!this.isStopped()) {
this.stop(false);
}
this.onDestroy();
goog.base(this, 'disposeInternal');
};
/**
* Stops an animation, fires a 'destroy' event and then removes all the event
* handlers to clean up memory.
* @deprecated Use dispose() instead.
*/
goog.fx.Animation.prototype.destroy = function() {
this.dispose();
};
/** @override */
goog.fx.Animation.prototype.onAnimationFrame = function(now) {
this.cycle(now);
};
/**
* Handles the actual iteration of the animation in a timeout
* @param {number} now The current time.
*/
goog.fx.Animation.prototype.cycle = function(now) {
this.progress = (now - this.startTime) / (this.endTime - this.startTime);
if (this.progress >= 1) {
this.progress = 1;
}
this.fps_ = 1000 / (now - this.lastFrame);
this.lastFrame = now;
this.updateCoords_(this.progress);
// Animation has finished.
if (this.progress == 1) {
this.setStateStopped();
goog.fx.anim.unregisterAnimation(this);
this.onFinish();
this.onEnd();
// Animation is still under way.
} else if (this.isPlaying()) {
this.onAnimate();
}
};
/**
* Calculates current coordinates, based on the current state. Applies
* the accelleration function if it exists.
* @param {number} t Percentage of the way through the animation as a decimal.
* @private
*/
goog.fx.Animation.prototype.updateCoords_ = function(t) {
if (goog.isFunction(this.accel_)) {
t = this.accel_(t);
}
this.coords = new Array(this.startPoint.length);
for (var i = 0; i < this.startPoint.length; i++) {
this.coords[i] = (this.endPoint[i] - this.startPoint[i]) * t +
this.startPoint[i];
}
};
/**
* Dispatches the ANIMATE event. Sub classes should override this instead
* of listening to the event.
* @protected
*/
goog.fx.Animation.prototype.onAnimate = function() {
this.dispatchAnimationEvent(goog.fx.Animation.EventType.ANIMATE);
};
/**
* Dispatches the DESTROY event. Sub classes should override this instead
* of listening to the event.
* @protected
*/
goog.fx.Animation.prototype.onDestroy = function() {
this.dispatchAnimationEvent(goog.fx.Animation.EventType.DESTROY);
};
/** @override */
goog.fx.Animation.prototype.dispatchAnimationEvent = function(type) {
this.dispatchEvent(new goog.fx.AnimationEvent(type, this));
};
/**
* Class for an animation event object.
* @param {string} type Event type.
* @param {goog.fx.Animation} anim An animation object.
* @constructor
* @extends {goog.events.Event}
*/
goog.fx.AnimationEvent = function(type, anim) {
goog.base(this, type);
/**
* The current coordinates.
* @type {Array.<number>}
*/
this.coords = anim.coords;
/**
* The x coordinate.
* @type {number}
*/
this.x = anim.coords[0];
/**
* The y coordinate.
* @type {number}
*/
this.y = anim.coords[1];
/**
* The z coordinate.
* @type {number}
*/
this.z = anim.coords[2];
/**
* The current duration.
* @type {number}
*/
this.duration = anim.duration;
/**
* The current progress.
* @type {number}
*/
this.progress = anim.getProgress();
/**
* Frames per second so far.
*/
this.fps = anim.fps_;
/**
* The state of the animation.
* @type {number}
*/
this.state = anim.getStateInternal();
/**
* The animation object.
* @type {goog.fx.Animation}
*/
// TODO(arv): This can be removed as this is the same as the target
this.anim = anim;
};
goog.inherits(goog.fx.AnimationEvent, goog.events.Event);
/**
* Returns the coordinates as integers (rounded to nearest integer).
* @return {Array.<number>} An array of the coordinates rounded to
* the nearest integer.
*/
goog.fx.AnimationEvent.prototype.coordsAsInts = function() {
return goog.array.map(this.coords, Math.round);
};

View File

@@ -0,0 +1,307 @@
// Copyright 2007 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview A class which automatically plays through a queue of
* animations. AnimationParallelQueue and AnimationSerialQueue provide
* specific implementations of the abstract class AnimationQueue.
*
* @see ../demos/animationqueue.html
*/
goog.provide('goog.fx.AnimationParallelQueue');
goog.provide('goog.fx.AnimationQueue');
goog.provide('goog.fx.AnimationSerialQueue');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.events.EventHandler');
goog.require('goog.fx.Transition.EventType');
goog.require('goog.fx.TransitionBase');
goog.require('goog.fx.TransitionBase.State');
/**
* Constructor for AnimationQueue object.
*
* @constructor
* @extends {goog.fx.TransitionBase}
*/
goog.fx.AnimationQueue = function() {
goog.base(this);
/**
* An array holding all animations in the queue.
* @type {Array.<goog.fx.TransitionBase>}
* @protected
*/
this.queue = [];
};
goog.inherits(goog.fx.AnimationQueue, goog.fx.TransitionBase);
/**
* Pushes an Animation to the end of the queue.
* @param {goog.fx.TransitionBase} animation The animation to add to the queue.
*/
goog.fx.AnimationQueue.prototype.add = function(animation) {
goog.asserts.assert(this.isStopped(),
'Not allowed to add animations to a running animation queue.');
if (goog.array.contains(this.queue, animation)) {
return;
}
this.queue.push(animation);
goog.events.listen(animation, goog.fx.Transition.EventType.FINISH,
this.onAnimationFinish, false, this);
};
/**
* Removes an Animation from the queue.
* @param {goog.fx.Animation} animation The animation to remove.
*/
goog.fx.AnimationQueue.prototype.remove = function(animation) {
goog.asserts.assert(this.isStopped(),
'Not allowed to remove animations from a running animation queue.');
if (goog.array.remove(this.queue, animation)) {
goog.events.unlisten(animation, goog.fx.Transition.EventType.FINISH,
this.onAnimationFinish, false, this);
}
};
/**
* Handles the event that an animation has finished.
* @param {goog.events.Event} e The finishing event.
* @protected
*/
goog.fx.AnimationQueue.prototype.onAnimationFinish = goog.abstractMethod;
/**
* Disposes of the animations.
* @override
*/
goog.fx.AnimationQueue.prototype.disposeInternal = function() {
goog.array.forEach(this.queue, function(animation) {
animation.dispose();
});
this.queue.length = 0;
goog.base(this, 'disposeInternal');
};
/**
* Constructor for AnimationParallelQueue object.
* @constructor
* @extends {goog.fx.AnimationQueue}
*/
goog.fx.AnimationParallelQueue = function() {
goog.base(this);
/**
* Number of finished animations.
* @type {number}
* @private
*/
this.finishedCounter_ = 0;
};
goog.inherits(goog.fx.AnimationParallelQueue, goog.fx.AnimationQueue);
/** @override */
goog.fx.AnimationParallelQueue.prototype.play = function(opt_restart) {
if (this.queue.length == 0) {
return false;
}
if (opt_restart || this.isStopped()) {
this.finishedCounter_ = 0;
this.onBegin();
} else if (this.isPlaying()) {
return false;
}
this.onPlay();
if (this.isPaused()) {
this.onResume();
}
var resuming = this.isPaused() && !opt_restart;
this.startTime = goog.now();
this.endTime = null;
this.setStatePlaying();
goog.array.forEach(this.queue, function(anim) {
if (!resuming || anim.isPaused()) {
anim.play(opt_restart);
}
});
return true;
};
/** @override */
goog.fx.AnimationParallelQueue.prototype.pause = function() {
if (this.isPlaying()) {
goog.array.forEach(this.queue, function(anim) {
if (anim.isPlaying()) {
anim.pause();
}
});
this.setStatePaused();
this.onPause();
}
};
/** @override */
goog.fx.AnimationParallelQueue.prototype.stop = function(opt_gotoEnd) {
goog.array.forEach(this.queue, function(anim) {
if (!anim.isStopped()) {
anim.stop(opt_gotoEnd);
}
});
this.setStateStopped();
this.endTime = goog.now();
this.onStop();
this.onEnd();
};
/** @override */
goog.fx.AnimationParallelQueue.prototype.onAnimationFinish = function(e) {
this.finishedCounter_++;
if (this.finishedCounter_ == this.queue.length) {
this.endTime = goog.now();
this.setStateStopped();
this.onFinish();
this.onEnd();
}
};
/**
* Constructor for AnimationSerialQueue object.
* @constructor
* @extends {goog.fx.AnimationQueue}
*/
goog.fx.AnimationSerialQueue = function() {
goog.base(this);
/**
* Current animation in queue currently active.
* @type {number}
* @private
*/
this.current_ = 0;
};
goog.inherits(goog.fx.AnimationSerialQueue, goog.fx.AnimationQueue);
/** @override */
goog.fx.AnimationSerialQueue.prototype.play = function(opt_restart) {
if (this.queue.length == 0) {
return false;
}
if (opt_restart || this.isStopped()) {
if (this.current_ < this.queue.length &&
!this.queue[this.current_].isStopped()) {
this.queue[this.current_].stop(false);
}
this.current_ = 0;
this.onBegin();
} else if (this.isPlaying()) {
return false;
}
this.onPlay();
if (this.isPaused()) {
this.onResume();
}
this.startTime = goog.now();
this.endTime = null;
this.setStatePlaying();
this.queue[this.current_].play(opt_restart);
return true;
};
/** @override */
goog.fx.AnimationSerialQueue.prototype.pause = function() {
if (this.isPlaying()) {
this.queue[this.current_].pause();
this.setStatePaused();
this.onPause();
}
};
/** @override */
goog.fx.AnimationSerialQueue.prototype.stop = function(opt_gotoEnd) {
this.setStateStopped();
this.endTime = goog.now();
if (opt_gotoEnd) {
for (var i = this.current_; i < this.queue.length; ++i) {
var anim = this.queue[i];
// If the animation is stopped, start it to initiate rendering. This
// might be needed to make the next line work.
if (anim.isStopped()) anim.play();
// If the animation is not done, stop it and go to the end state of the
// animation.
if (!anim.isStopped()) anim.stop(true);
}
} else if (this.current_ < this.queue.length) {
this.queue[this.current_].stop(false);
}
this.onStop();
this.onEnd();
};
/** @override */
goog.fx.AnimationSerialQueue.prototype.onAnimationFinish = function(e) {
if (this.isPlaying()) {
this.current_++;
if (this.current_ < this.queue.length) {
this.queue[this.current_].play();
} else {
this.endTime = goog.now();
this.setStateStopped();
this.onFinish();
this.onEnd();
}
}
};

View File

@@ -0,0 +1,62 @@
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview A collection of CSS3 targeted animation, based on
* {@code goog.fx.css3.Transition}.
*
*/
goog.provide('goog.fx.css3');
goog.require('goog.fx.css3.Transition');
/**
* Creates a transition to fade the element.
* @param {Element} element The element to fade.
* @param {number} duration Duration in seconds.
* @param {string} timing The CSS3 timing function.
* @param {number} startOpacity Starting opacity.
* @param {number} endOpacity Ending opacity.
* @return {!goog.fx.css3.Transition} The transition object.
*/
goog.fx.css3.fade = function(
element, duration, timing, startOpacity, endOpacity) {
return new goog.fx.css3.Transition(
element, duration, {'opacity': startOpacity}, {'opacity': endOpacity},
{property: 'opacity', duration: duration, timing: timing, delay: 0});
};
/**
* Creates a transition to fade in the element.
* @param {Element} element The element to fade in.
* @param {number} duration Duration in seconds.
* @return {!goog.fx.css3.Transition} The transition object.
*/
goog.fx.css3.fadeIn = function(element, duration) {
return goog.fx.css3.fade(element, duration, 'ease-out', 0, 1);
};
/**
* Creates a transition to fade out the element.
* @param {Element} element The element to fade out.
* @param {number} duration Duration in seconds.
* @return {!goog.fx.css3.Transition} The transition object.
*/
goog.fx.css3.fadeOut = function(element, duration) {
return goog.fx.css3.fade(element, duration, 'ease-in', 1, 0);
};

View File

@@ -0,0 +1,196 @@
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview CSS3 transition base library.
*
*/
goog.provide('goog.fx.css3.Transition');
goog.require('goog.Timer');
goog.require('goog.fx.TransitionBase');
goog.require('goog.style');
goog.require('goog.style.transition');
/**
* A class to handle targeted CSS3 transition. This class
* handles common features required for targeted CSS3 transition.
*
* Browser that does not support CSS3 transition will still receive all
* the events fired by the transition object, but will not have any transition
* played. If the browser supports the final state as set in setFinalState
* method, the element will ends in the final state.
*
* Transitioning multiple properties with the same setting is possible
* by setting Css3Property's property to 'all'. Performing multiple
* transitions can be done via setting multiple initialStyle,
* finalStyle and transitions. Css3Property's delay can be used to
* delay one of the transition. Here is an example for a transition
* that expands on the width and then followed by the height:
*
* <pre>
* initialStyle: {width: 10px, height: 10px}
* finalStyle: {width: 100px, height: 100px}
* transitions: [
* {property: width, duration: 1, timing: 'ease-in', delay: 0},
* {property: height, duration: 1, timing: 'ease-in', delay: 1}
* ]
* </pre>
*
* @param {Element} element The element to be transitioned.
* @param {number} duration The duration of the transition in seconds.
* This should be the longest of all transitions.
* @param {Object} initialStyle Initial style properties of the element before
* animating. Set using {@code goog.style.setStyle}.
* @param {Object} finalStyle Final style properties of the element after
* animating. Set using {@code goog.style.setStyle}.
* @param {goog.style.transition.Css3Property|
* Array.<goog.style.transition.Css3Property>} transitions A single CSS3
* transition property or an array of it.
* @extends {goog.fx.TransitionBase}
* @constructor
*/
goog.fx.css3.Transition = function(
element, duration, initialStyle, finalStyle, transitions) {
goog.base(this);
/**
* @type {Element}
* @private
*/
this.element_ = element;
/**
* @type {number}
* @private
*/
this.duration_ = duration;
/**
* @type {Object}
* @private
*/
this.initialStyle_ = initialStyle;
/**
* @type {Object}
* @private
*/
this.finalStyle_ = finalStyle;
/**
* @type {Array.<goog.style.transition.Css3Property>}
* @private
*/
this.transitions_ = goog.isArray(transitions) ? transitions : [transitions];
};
goog.inherits(goog.fx.css3.Transition, goog.fx.TransitionBase);
/**
* Timer id to be used to cancel animation part-way.
* @type {number}
* @private
*/
goog.fx.css3.Transition.prototype.timerId_;
/** @override */
goog.fx.css3.Transition.prototype.play = function() {
if (this.isPlaying()) {
return false;
}
this.onBegin();
this.onPlay();
this.startTime = goog.now();
this.setStatePlaying();
if (goog.style.transition.isSupported()) {
goog.style.setStyle(this.element_, this.initialStyle_);
// Allow element to get updated to its initial state before installing
// CSS3 transition.
this.timerId_ = goog.Timer.callOnce(this.play_, undefined, this);
return true;
} else {
this.stop_(false);
return false;
}
};
/**
* Helper method for play method. This needs to be executed on a timer.
* @private
*/
goog.fx.css3.Transition.prototype.play_ = function() {
goog.style.transition.set(this.element_, this.transitions_);
goog.style.setStyle(this.element_, this.finalStyle_);
this.timerId_ = goog.Timer.callOnce(
goog.bind(this.stop_, this, false), this.duration_ * 1000);
};
/** @override */
goog.fx.css3.Transition.prototype.stop = function() {
if (!this.isPlaying()) return;
this.stop_(true);
};
/**
* Helper method for stop method.
* @param {boolean} stopped If the transition was stopped.
* @private
*/
goog.fx.css3.Transition.prototype.stop_ = function(stopped) {
goog.style.transition.removeAll(this.element_);
// Clear the timer.
goog.Timer.clear(this.timerId_);
// Make sure that we have reached the final style.
goog.style.setStyle(this.element_, this.finalStyle_);
this.endTime = goog.now();
this.setStateStopped();
if (stopped) {
this.onStop();
} else {
this.onFinish();
}
this.onEnd();
};
/** @override */
goog.fx.css3.Transition.prototype.disposeInternal = function() {
this.stop();
goog.base(this, 'disposeInternal');
};
/**
* Pausing CSS3 Transitions in not supported.
* @override
*/
goog.fx.css3.Transition.prototype.pause = function() {
goog.asserts.assert(false, 'Css3 transitions does not support pause action.');
};

View File

@@ -0,0 +1,113 @@
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview An animation class that animates CSS sprites by changing the
* CSS background-position.
*
* @author arv@google.com (Erik Arvidsson)
* @see ../demos/cssspriteanimation.html
*/
goog.provide('goog.fx.CssSpriteAnimation');
goog.require('goog.fx.Animation');
/**
* This animation class is used to animate a CSS sprite (moving a background
* image). This moves through a series of images in a single image sprite and
* loops the animation when done. You should set up the
* {@code background-image} and size in a CSS rule for the relevant element.
*
* @param {Element} element The HTML element to animate the background for.
* @param {goog.math.Size} size The size of one image in the image sprite.
* @param {goog.math.Box} box The box describing the layout of the sprites to
* use in the large image. The sprites can be position horizontally or
* vertically and using a box here allows the implementation to know which
* way to go.
* @param {number} time The duration in milliseconds for one iteration of the
* animation. For example, if the sprite contains 4 images and the duration
* is set to 400ms then each sprite will be displayed for 100ms.
* @param {function(number) : number=} opt_acc Acceleration function,
* returns 0-1 for inputs 0-1. This can be used to make certain frames be
* shown for a longer period of time.
*
* @constructor
* @extends {goog.fx.Animation}
*/
goog.fx.CssSpriteAnimation = function(element, size, box, time, opt_acc) {
var start = [box.left, box.top];
// We never draw for the end so we do not need to subtract for the size
var end = [box.right, box.bottom];
goog.base(this, start, end, time, opt_acc);
/**
* HTML element that will be used in the animation.
* @type {Element}
* @private
*/
this.element_ = element;
/**
* The size of an individual sprite in the image sprite.
* @type {goog.math.Size}
* @private
*/
this.size_ = size;
};
goog.inherits(goog.fx.CssSpriteAnimation, goog.fx.Animation);
/** @override */
goog.fx.CssSpriteAnimation.prototype.onAnimate = function() {
// Round to nearest sprite.
var x = -Math.floor(this.coords[0] / this.size_.width) * this.size_.width;
var y = -Math.floor(this.coords[1] / this.size_.height) * this.size_.height;
this.element_.style.backgroundPosition = x + 'px ' + y + 'px';
goog.base(this, 'onAnimate');
};
/** @override */
goog.fx.CssSpriteAnimation.prototype.onFinish = function() {
this.play(true);
goog.base(this, 'onFinish');
};
/**
* Clears the background position style set directly on the element
* by the animation. Allows to apply CSS styling for background position on the
* same element when the sprite animation is not runniing.
*/
goog.fx.CssSpriteAnimation.prototype.clearSpritePosition = function() {
var style = this.element_.style;
style.backgroundPosition = '';
if (typeof style.backgroundPositionX != 'undefined') {
// IE needs to clear x and y to actually clear the position
style.backgroundPositionX = '';
style.backgroundPositionY = '';
}
};
/** @override */
goog.fx.CssSpriteAnimation.prototype.disposeInternal = function() {
goog.fx.CssSpriteAnimation.superClass_.disposeInternal.call(this);
this.element_ = null;
};

View File

@@ -0,0 +1,653 @@
// Copyright 2005 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Predefined DHTML animations such as slide, resize and fade.
*
* @see ../demos/effects.html
*/
goog.provide('goog.fx.dom');
goog.provide('goog.fx.dom.BgColorTransform');
goog.provide('goog.fx.dom.ColorTransform');
goog.provide('goog.fx.dom.Fade');
goog.provide('goog.fx.dom.FadeIn');
goog.provide('goog.fx.dom.FadeInAndShow');
goog.provide('goog.fx.dom.FadeOut');
goog.provide('goog.fx.dom.FadeOutAndHide');
goog.provide('goog.fx.dom.PredefinedEffect');
goog.provide('goog.fx.dom.Resize');
goog.provide('goog.fx.dom.ResizeHeight');
goog.provide('goog.fx.dom.ResizeWidth');
goog.provide('goog.fx.dom.Scroll');
goog.provide('goog.fx.dom.Slide');
goog.provide('goog.fx.dom.SlideFrom');
goog.provide('goog.fx.dom.Swipe');
goog.require('goog.color');
goog.require('goog.events');
goog.require('goog.fx.Animation');
goog.require('goog.fx.Transition.EventType');
goog.require('goog.style');
goog.require('goog.style.bidi');
/**
* Abstract class that provides reusable functionality for predefined animations
* that manipulate a single DOM element
*
* @param {Element} element Dom Node to be used in the animation.
* @param {Array.<number>} start Array for start coordinates.
* @param {Array.<number>} end Array for end coordinates.
* @param {number} time Length of animation in milliseconds.
* @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
* @extends {goog.fx.Animation}
* @constructor
*/
goog.fx.dom.PredefinedEffect = function(element, start, end, time, opt_acc) {
goog.fx.Animation.call(this, start, end, time, opt_acc);
/**
* DOM Node that will be used in the animation
* @type {Element}
*/
this.element = element;
/**
* Whether the element is rendered right-to-left. We cache this here for
* efficiency.
* @type {boolean|undefined}
* @private
*/
this.rightToLeft_;
};
goog.inherits(goog.fx.dom.PredefinedEffect, goog.fx.Animation);
/**
* Called to update the style of the element.
* @protected
*/
goog.fx.dom.PredefinedEffect.prototype.updateStyle = goog.nullFunction;
/**
* Whether the element is rendered right-to-left. We initialize this lazily.
* @type {boolean|undefined}
* @private
*/
goog.fx.dom.PredefinedEffect.prototype.rightToLeft_;
/**
* Whether the DOM element being manipulated is rendered right-to-left.
* @return {boolean} True if the DOM element is rendered right-to-left, false
* otherwise.
*/
goog.fx.dom.PredefinedEffect.prototype.isRightToLeft = function() {
if (!goog.isDef(this.rightToLeft_)) {
this.rightToLeft_ = goog.style.isRightToLeft(this.element);
}
return this.rightToLeft_;
};
/** @override */
goog.fx.dom.PredefinedEffect.prototype.onAnimate = function() {
this.updateStyle();
goog.fx.dom.PredefinedEffect.superClass_.onAnimate.call(this);
};
/** @override */
goog.fx.dom.PredefinedEffect.prototype.onEnd = function() {
this.updateStyle();
goog.fx.dom.PredefinedEffect.superClass_.onEnd.call(this);
};
/** @override */
goog.fx.dom.PredefinedEffect.prototype.onBegin = function() {
this.updateStyle();
goog.fx.dom.PredefinedEffect.superClass_.onBegin.call(this);
};
/**
* Creates an animation object that will slide an element from A to B. (This
* in effect automatically sets up the onanimate event for an Animation object)
*
* Start and End should be 2 dimensional arrays
*
* @param {Element} element Dom Node to be used in the animation.
* @param {Array.<number>} start 2D array for start coordinates (X, Y).
* @param {Array.<number>} end 2D array for end coordinates (X, Y).
* @param {number} time Length of animation in milliseconds.
* @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
* @extends {goog.fx.dom.PredefinedEffect}
* @constructor
*/
goog.fx.dom.Slide = function(element, start, end, time, opt_acc) {
if (start.length != 2 || end.length != 2) {
throw Error('Start and end points must be 2D');
}
goog.fx.dom.PredefinedEffect.apply(this, arguments);
};
goog.inherits(goog.fx.dom.Slide, goog.fx.dom.PredefinedEffect);
/** @override */
goog.fx.dom.Slide.prototype.updateStyle = function() {
var pos = (this.isRightPositioningForRtlEnabled() && this.isRightToLeft()) ?
'right' : 'left';
this.element.style[pos] = Math.round(this.coords[0]) + 'px';
this.element.style.top = Math.round(this.coords[1]) + 'px';
};
/**
* Slides an element from its current position.
*
* @param {Element} element DOM node to be used in the animation.
* @param {Array.<number>} end 2D array for end coordinates (X, Y).
* @param {number} time Length of animation in milliseconds.
* @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
* @extends {goog.fx.dom.Slide}
* @constructor
*/
goog.fx.dom.SlideFrom = function(element, end, time, opt_acc) {
var offsetLeft = this.isRightPositioningForRtlEnabled() ?
goog.style.bidi.getOffsetStart(element) : element.offsetLeft;
var start = [offsetLeft, element.offsetTop];
goog.fx.dom.Slide.call(this, element, start, end, time, opt_acc);
};
goog.inherits(goog.fx.dom.SlideFrom, goog.fx.dom.Slide);
/** @override */
goog.fx.dom.SlideFrom.prototype.onBegin = function() {
var offsetLeft = this.isRightPositioningForRtlEnabled() ?
goog.style.bidi.getOffsetStart(this.element) : this.element.offsetLeft;
this.startPoint = [offsetLeft, this.element.offsetTop];
goog.fx.dom.SlideFrom.superClass_.onBegin.call(this);
};
/**
* Creates an animation object that will slide an element into its final size.
* Requires that the element is absolutely positioned.
*
* @param {Element} element Dom Node to be used in the animation.
* @param {Array.<number>} start 2D array for start size (W, H).
* @param {Array.<number>} end 2D array for end size (W, H).
* @param {number} time Length of animation in milliseconds.
* @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
* @extends {goog.fx.dom.PredefinedEffect}
* @constructor
*/
goog.fx.dom.Swipe = function(element, start, end, time, opt_acc) {
if (start.length != 2 || end.length != 2) {
throw Error('Start and end points must be 2D');
}
goog.fx.dom.PredefinedEffect.apply(this, arguments);
/**
* Maximum width for element.
* @type {number}
* @private
*/
this.maxWidth_ = Math.max(this.endPoint[0], this.startPoint[0]);
/**
* Maximum height for element.
* @type {number}
* @private
*/
this.maxHeight_ = Math.max(this.endPoint[1], this.startPoint[1]);
};
goog.inherits(goog.fx.dom.Swipe, goog.fx.dom.PredefinedEffect);
/**
* Animation event handler that will resize an element by setting its width,
* height and clipping.
* @protected
* @override
*/
goog.fx.dom.Swipe.prototype.updateStyle = function() {
var x = this.coords[0];
var y = this.coords[1];
this.clip_(Math.round(x), Math.round(y), this.maxWidth_, this.maxHeight_);
this.element.style.width = Math.round(x) + 'px';
var marginX = (this.isRightPositioningForRtlEnabled() &&
this.isRightToLeft()) ? 'marginRight' : 'marginLeft';
this.element.style[marginX] = Math.round(x) - this.maxWidth_ + 'px';
this.element.style.marginTop = Math.round(y) - this.maxHeight_ + 'px';
};
/**
* Helper function for setting element clipping.
* @param {number} x Current element width.
* @param {number} y Current element height.
* @param {number} w Maximum element width.
* @param {number} h Maximum element height.
* @private
*/
goog.fx.dom.Swipe.prototype.clip_ = function(x, y, w, h) {
this.element.style.clip =
'rect(' + (h - y) + 'px ' + w + 'px ' + h + 'px ' + (w - x) + 'px)';
};
/**
* Creates an animation object that will scroll an element from A to B.
*
* Start and End should be 2 dimensional arrays
*
* @param {Element} element Dom Node to be used in the animation.
* @param {Array.<number>} start 2D array for start scroll left and top.
* @param {Array.<number>} end 2D array for end scroll left and top.
* @param {number} time Length of animation in milliseconds.
* @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
* @extends {goog.fx.dom.PredefinedEffect}
* @constructor
*/
goog.fx.dom.Scroll = function(element, start, end, time, opt_acc) {
if (start.length != 2 || end.length != 2) {
throw Error('Start and end points must be 2D');
}
goog.fx.dom.PredefinedEffect.apply(this, arguments);
};
goog.inherits(goog.fx.dom.Scroll, goog.fx.dom.PredefinedEffect);
/**
* Animation event handler that will set the scroll posiiton of an element
* @protected
* @override
*/
goog.fx.dom.Scroll.prototype.updateStyle = function() {
if (this.isRightPositioningForRtlEnabled()) {
goog.style.bidi.setScrollOffset(this.element, Math.round(this.coords[0]));
} else {
this.element.scrollLeft = Math.round(this.coords[0]);
}
this.element.scrollTop = Math.round(this.coords[1]);
};
/**
* Creates an animation object that will resize an element between two widths
* and heights.
*
* Start and End should be 2 dimensional arrays
*
* @param {Element} element Dom Node to be used in the animation.
* @param {Array.<number>} start 2D array for start width and height.
* @param {Array.<number>} end 2D array for end width and height.
* @param {number} time Length of animation in milliseconds.
* @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
* @extends {goog.fx.dom.PredefinedEffect}
* @constructor
*/
goog.fx.dom.Resize = function(element, start, end, time, opt_acc) {
if (start.length != 2 || end.length != 2) {
throw Error('Start and end points must be 2D');
}
goog.fx.dom.PredefinedEffect.apply(this, arguments);
};
goog.inherits(goog.fx.dom.Resize, goog.fx.dom.PredefinedEffect);
/**
* Animation event handler that will resize an element by setting its width and
* height.
* @protected
* @override
*/
goog.fx.dom.Resize.prototype.updateStyle = function() {
this.element.style.width = Math.round(this.coords[0]) + 'px';
this.element.style.height = Math.round(this.coords[1]) + 'px';
};
/**
* Creates an animation object that will resize an element between two widths
*
* Start and End should be numbers
*
* @param {Element} element Dom Node to be used in the animation.
* @param {number} start Start width.
* @param {number} end End width.
* @param {number} time Length of animation in milliseconds.
* @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
* @extends {goog.fx.dom.PredefinedEffect}
* @constructor
*/
goog.fx.dom.ResizeWidth = function(element, start, end, time, opt_acc) {
goog.fx.dom.PredefinedEffect.call(this, element, [start],
[end], time, opt_acc);
};
goog.inherits(goog.fx.dom.ResizeWidth, goog.fx.dom.PredefinedEffect);
/**
* Animation event handler that will resize an element by setting its width.
* @protected
* @override
*/
goog.fx.dom.ResizeWidth.prototype.updateStyle = function() {
this.element.style.width = Math.round(this.coords[0]) + 'px';
};
/**
* Creates an animation object that will resize an element between two heights
*
* Start and End should be numbers
*
* @param {Element} element Dom Node to be used in the animation.
* @param {number} start Start height.
* @param {number} end End height.
* @param {number} time Length of animation in milliseconds.
* @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
* @extends {goog.fx.dom.PredefinedEffect}
* @constructor
*/
goog.fx.dom.ResizeHeight = function(element, start, end, time, opt_acc) {
goog.fx.dom.PredefinedEffect.call(this, element, [start],
[end], time, opt_acc);
};
goog.inherits(goog.fx.dom.ResizeHeight, goog.fx.dom.PredefinedEffect);
/**
* Animation event handler that will resize an element by setting its height.
* @protected
* @override
*/
goog.fx.dom.ResizeHeight.prototype.updateStyle = function() {
this.element.style.height = Math.round(this.coords[0]) + 'px';
};
/**
* Creates an animation object that fades the opacity of an element between two
* limits.
*
* Start and End should be floats between 0 and 1
*
* @param {Element} element Dom Node to be used in the animation.
* @param {Array.<number>|number} start 1D Array or Number with start opacity.
* @param {Array.<number>|number} end 1D Array or Number for end opacity.
* @param {number} time Length of animation in milliseconds.
* @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
* @extends {goog.fx.dom.PredefinedEffect}
* @constructor
*/
goog.fx.dom.Fade = function(element, start, end, time, opt_acc) {
if (goog.isNumber(start)) start = [start];
if (goog.isNumber(end)) end = [end];
goog.fx.dom.PredefinedEffect.call(this, element, start, end, time, opt_acc);
if (start.length != 1 || end.length != 1) {
throw Error('Start and end points must be 1D');
}
};
goog.inherits(goog.fx.dom.Fade, goog.fx.dom.PredefinedEffect);
/**
* Animation event handler that will set the opacity of an element.
* @protected
* @override
*/
goog.fx.dom.Fade.prototype.updateStyle = function() {
goog.style.setOpacity(this.element, this.coords[0]);
};
/**
* Animation event handler that will show the element.
*/
goog.fx.dom.Fade.prototype.show = function() {
this.element.style.display = '';
};
/**
* Animation event handler that will hide the element
*/
goog.fx.dom.Fade.prototype.hide = function() {
this.element.style.display = 'none';
};
/**
* Fades an element out from full opacity to completely transparent.
*
* @param {Element} element Dom Node to be used in the animation.
* @param {number} time Length of animation in milliseconds.
* @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
* @extends {goog.fx.dom.Fade}
* @constructor
*/
goog.fx.dom.FadeOut = function(element, time, opt_acc) {
goog.fx.dom.Fade.call(this, element, 1, 0, time, opt_acc);
};
goog.inherits(goog.fx.dom.FadeOut, goog.fx.dom.Fade);
/**
* Fades an element in from completely transparent to fully opacity.
*
* @param {Element} element Dom Node to be used in the animation.
* @param {number} time Length of animation in milliseconds.
* @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
* @extends {goog.fx.dom.Fade}
* @constructor
*/
goog.fx.dom.FadeIn = function(element, time, opt_acc) {
goog.fx.dom.Fade.call(this, element, 0, 1, time, opt_acc);
};
goog.inherits(goog.fx.dom.FadeIn, goog.fx.dom.Fade);
/**
* Fades an element out from full opacity to completely transparent and then
* sets the display to 'none'
*
* @param {Element} element Dom Node to be used in the animation.
* @param {number} time Length of animation in milliseconds.
* @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
* @extends {goog.fx.dom.Fade}
* @constructor
*/
goog.fx.dom.FadeOutAndHide = function(element, time, opt_acc) {
goog.fx.dom.Fade.call(this, element, 1, 0, time, opt_acc);
};
goog.inherits(goog.fx.dom.FadeOutAndHide, goog.fx.dom.Fade);
/** @override */
goog.fx.dom.FadeOutAndHide.prototype.onBegin = function() {
this.show();
goog.fx.dom.FadeOutAndHide.superClass_.onBegin.call(this);
};
/** @override */
goog.fx.dom.FadeOutAndHide.prototype.onEnd = function() {
this.hide();
goog.fx.dom.FadeOutAndHide.superClass_.onEnd.call(this);
};
/**
* Sets an element's display to be visible and then fades an element in from
* completely transparent to fully opacity
*
* @param {Element} element Dom Node to be used in the animation.
* @param {number} time Length of animation in milliseconds.
* @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
* @extends {goog.fx.dom.Fade}
* @constructor
*/
goog.fx.dom.FadeInAndShow = function(element, time, opt_acc) {
goog.fx.dom.Fade.call(this, element, 0, 1, time, opt_acc);
};
goog.inherits(goog.fx.dom.FadeInAndShow, goog.fx.dom.Fade);
/** @override */
goog.fx.dom.FadeInAndShow.prototype.onBegin = function() {
this.show();
goog.fx.dom.FadeInAndShow.superClass_.onBegin.call(this);
};
/**
* Provides a transformation of an elements background-color.
*
* Start and End should be 3D arrays representing R,G,B
*
* @param {Element} element Dom Node to be used in the animation.
* @param {Array.<number>} start 3D Array for RGB of start color.
* @param {Array.<number>} end 3D Array for RGB of end color.
* @param {number} time Length of animation in milliseconds.
* @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
* @extends {goog.fx.dom.PredefinedEffect}
* @constructor
*/
goog.fx.dom.BgColorTransform = function(element, start, end, time, opt_acc) {
if (start.length != 3 || end.length != 3) {
throw Error('Start and end points must be 3D');
}
goog.fx.dom.PredefinedEffect.apply(this, arguments);
};
goog.inherits(goog.fx.dom.BgColorTransform, goog.fx.dom.PredefinedEffect);
/**
* Animation event handler that will set the background-color of an element
*/
goog.fx.dom.BgColorTransform.prototype.setColor = function() {
var coordsAsInts = [];
for (var i = 0; i < this.coords.length; i++) {
coordsAsInts[i] = Math.round(this.coords[i]);
}
var color = 'rgb(' + coordsAsInts.join(',') + ')';
this.element.style.backgroundColor = color;
};
/** @override */
goog.fx.dom.BgColorTransform.prototype.updateStyle = function() {
this.setColor();
};
/**
* Fade elements background color from start color to the element's current
* background color.
*
* Start should be a 3D array representing R,G,B
*
* @param {Element} element Dom Node to be used in the animation.
* @param {Array.<number>} start 3D Array for RGB of start color.
* @param {number} time Length of animation in milliseconds.
* @param {goog.events.EventHandler=} opt_eventHandler Optional event handler
* to use when listening for events.
*/
goog.fx.dom.bgColorFadeIn = function(element, start, time, opt_eventHandler) {
var initialBgColor = element.style.backgroundColor || '';
var computedBgColor = goog.style.getBackgroundColor(element);
var end;
if (computedBgColor && computedBgColor != 'transparent' &&
computedBgColor != 'rgba(0, 0, 0, 0)') {
end = goog.color.hexToRgb(goog.color.parse(computedBgColor).hex);
} else {
end = [255, 255, 255];
}
var anim = new goog.fx.dom.BgColorTransform(element, start, end, time);
function setBgColor() {
element.style.backgroundColor = initialBgColor;
}
if (opt_eventHandler) {
opt_eventHandler.listen(
anim, goog.fx.Transition.EventType.END, setBgColor);
} else {
goog.events.listen(
anim, goog.fx.Transition.EventType.END, setBgColor);
}
anim.play();
};
/**
* Provides a transformation of an elements color.
*
* @param {Element} element Dom Node to be used in the animation.
* @param {Array.<number>} start 3D Array representing R,G,B.
* @param {Array.<number>} end 3D Array representing R,G,B.
* @param {number} time Length of animation in milliseconds.
* @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
* @constructor
* @extends {goog.fx.dom.PredefinedEffect}
*/
goog.fx.dom.ColorTransform = function(element, start, end, time, opt_acc) {
if (start.length != 3 || end.length != 3) {
throw Error('Start and end points must be 3D');
}
goog.fx.dom.PredefinedEffect.apply(this, arguments);
};
goog.inherits(goog.fx.dom.ColorTransform, goog.fx.dom.PredefinedEffect);
/**
* Animation event handler that will set the color of an element.
* @protected
* @override
*/
goog.fx.dom.ColorTransform.prototype.updateStyle = function() {
var coordsAsInts = [];
for (var i = 0; i < this.coords.length; i++) {
coordsAsInts[i] = Math.round(this.coords[i]);
}
var color = 'rgb(' + coordsAsInts.join(',') + ')';
this.element.style.color = color;
};

View File

@@ -0,0 +1,50 @@
// Copyright 2006 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Single Element Drag and Drop.
*
* Drag and drop implementation for sources/targets consisting of a single
* element.
*
* @author eae@google.com (Emil A Eklund)
* @see ../demos/dragdrop.html
*/
goog.provide('goog.fx.DragDrop');
goog.require('goog.fx.AbstractDragDrop');
goog.require('goog.fx.DragDropItem');
/**
* Drag/drop implementation for creating drag sources/drop targets consisting of
* a single HTML Element.
*
* @param {Element|string} element Dom Node, or string representation of node
* id, to be used as drag source/drop target.
* @param {Object=} opt_data Data associated with the source/target.
* @throws Error If no element argument is provided or if the type is invalid
* @extends {goog.fx.AbstractDragDrop}
* @constructor
*/
goog.fx.DragDrop = function(element, opt_data) {
goog.fx.AbstractDragDrop.call(this);
var item = new goog.fx.DragDropItem(element, opt_data);
item.setParent(this);
this.items_.push(item);
};
goog.inherits(goog.fx.DragDrop, goog.fx.AbstractDragDrop);

View File

@@ -0,0 +1,109 @@
// Copyright 2006 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Multiple Element Drag and Drop.
*
* Drag and drop implementation for sources/targets consisting of multiple
* elements.
*
* @author eae@google.com (Emil A Eklund)
* @see ../demos/dragdrop.html
*/
goog.provide('goog.fx.DragDropGroup');
goog.require('goog.dom');
goog.require('goog.fx.AbstractDragDrop');
goog.require('goog.fx.DragDropItem');
/**
* Drag/drop implementation for creating drag sources/drop targets consisting of
* multiple HTML Elements (items). All items share the same drop target(s) but
* can be dragged individually.
*
* @extends {goog.fx.AbstractDragDrop}
* @constructor
*/
goog.fx.DragDropGroup = function() {
goog.fx.AbstractDragDrop.call(this);
};
goog.inherits(goog.fx.DragDropGroup, goog.fx.AbstractDragDrop);
/**
* Add item to drag object.
*
* @param {Element|string} element Dom Node, or string representation of node
* id, to be used as drag source/drop target.
* @param {Object=} opt_data Data associated with the source/target.
* @throws Error If no element argument is provided or if the type is
* invalid
* @override
*/
goog.fx.DragDropGroup.prototype.addItem = function(element, opt_data) {
var item = new goog.fx.DragDropItem(element, opt_data);
this.addDragDropItem(item);
};
/**
* Add DragDropItem to drag object.
*
* @param {goog.fx.DragDropItem} item DragDropItem being added to the
* drag object.
* @throws Error If no element argument is provided or if the type is
* invalid
*/
goog.fx.DragDropGroup.prototype.addDragDropItem = function(item) {
item.setParent(this);
this.items_.push(item);
if (this.isInitialized()) {
this.initItem(item);
}
};
/**
* Remove item from drag object.
*
* @param {Element|string} element Dom Node, or string representation of node
* id, that was previously added with addItem().
*/
goog.fx.DragDropGroup.prototype.removeItem = function(element) {
element = goog.dom.getElement(element);
for (var item, i = 0; item = this.items_[i]; i++) {
if (item.element == element) {
this.items_.splice(i, 1);
this.disposeItem(item);
break;
}
}
};
/**
* Marks the supplied list of items as selected. A drag operation for any of the
* selected items will affect all of them.
*
* @param {Array.<goog.fx.DragDropItem>} list List of items to select or null to
* clear selection.
*
* TODO(eae): Not yet implemented.
*/
goog.fx.DragDropGroup.prototype.setSelection = function(list) {
};

View File

@@ -0,0 +1,795 @@
// Copyright 2006 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Drag Utilities.
*
* Provides extensible functionality for drag & drop behaviour.
*
* @see ../demos/drag.html
* @see ../demos/dragger.html
*/
goog.provide('goog.fx.DragEvent');
goog.provide('goog.fx.Dragger');
goog.provide('goog.fx.Dragger.EventType');
goog.require('goog.dom');
goog.require('goog.events');
goog.require('goog.events.Event');
goog.require('goog.events.EventHandler');
goog.require('goog.events.EventTarget');
goog.require('goog.events.EventType');
goog.require('goog.math.Coordinate');
goog.require('goog.math.Rect');
goog.require('goog.style');
goog.require('goog.style.bidi');
goog.require('goog.userAgent');
/**
* A class that allows mouse or touch-based dragging (moving) of an element
*
* @param {Element} target The element that will be dragged.
* @param {Element=} opt_handle An optional handle to control the drag, if null
* the target is used.
* @param {goog.math.Rect=} opt_limits Object containing left, top, width,
* and height.
*
* @extends {goog.events.EventTarget}
* @constructor
*/
goog.fx.Dragger = function(target, opt_handle, opt_limits) {
goog.events.EventTarget.call(this);
this.target = target;
this.handle = opt_handle || target;
this.limits = opt_limits || new goog.math.Rect(NaN, NaN, NaN, NaN);
this.document_ = goog.dom.getOwnerDocument(target);
this.eventHandler_ = new goog.events.EventHandler(this);
this.registerDisposable(this.eventHandler_);
// Add listener. Do not use the event handler here since the event handler is
// used for listeners added and removed during the drag operation.
goog.events.listen(this.handle,
[goog.events.EventType.TOUCHSTART, goog.events.EventType.MOUSEDOWN],
this.startDrag, false, this);
};
goog.inherits(goog.fx.Dragger, goog.events.EventTarget);
/**
* Whether setCapture is supported by the browser.
* @type {boolean}
* @private
*/
goog.fx.Dragger.HAS_SET_CAPTURE_ =
// IE and Gecko after 1.9.3 has setCapture
// WebKit does not yet: https://bugs.webkit.org/show_bug.cgi?id=27330
goog.userAgent.IE ||
goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.9.3');
/**
* Constants for event names.
* @enum {string}
*/
goog.fx.Dragger.EventType = {
// The drag action was canceled before the START event. Possible reasons:
// disabled dragger, dragging with the right mouse button or releasing the
// button before reaching the hysteresis distance.
EARLY_CANCEL: 'earlycancel',
START: 'start',
BEFOREDRAG: 'beforedrag',
DRAG: 'drag',
END: 'end'
};
/**
* Reference to drag target element.
* @type {Element}
*/
goog.fx.Dragger.prototype.target;
/**
* Reference to the handler that initiates the drag.
* @type {Element}
*/
goog.fx.Dragger.prototype.handle;
/**
* Object representing the limits of the drag region.
* @type {goog.math.Rect}
*/
goog.fx.Dragger.prototype.limits;
/**
* Whether the element is rendered right-to-left. We initialize this lazily.
* @type {boolean|undefined}}
* @private
*/
goog.fx.Dragger.prototype.rightToLeft_;
/**
* Current x position of mouse or touch relative to viewport.
* @type {number}
*/
goog.fx.Dragger.prototype.clientX = 0;
/**
* Current y position of mouse or touch relative to viewport.
* @type {number}
*/
goog.fx.Dragger.prototype.clientY = 0;
/**
* Current x position of mouse or touch relative to screen. Deprecated because
* it doesn't take into affect zoom level or pixel density.
* @type {number}
* @deprecated Consider switching to clientX instead.
*/
goog.fx.Dragger.prototype.screenX = 0;
/**
* Current y position of mouse or touch relative to screen. Deprecated because
* it doesn't take into affect zoom level or pixel density.
* @type {number}
* @deprecated Consider switching to clientY instead.
*/
goog.fx.Dragger.prototype.screenY = 0;
/**
* The x position where the first mousedown or touchstart occurred.
* @type {number}
*/
goog.fx.Dragger.prototype.startX = 0;
/**
* The y position where the first mousedown or touchstart occurred.
* @type {number}
*/
goog.fx.Dragger.prototype.startY = 0;
/**
* Current x position of drag relative to target's parent.
* @type {number}
*/
goog.fx.Dragger.prototype.deltaX = 0;
/**
* Current y position of drag relative to target's parent.
* @type {number}
*/
goog.fx.Dragger.prototype.deltaY = 0;
/**
* The current page scroll value.
* @type {goog.math.Coordinate}
*/
goog.fx.Dragger.prototype.pageScroll;
/**
* Whether dragging is currently enabled.
* @type {boolean}
* @private
*/
goog.fx.Dragger.prototype.enabled_ = true;
/**
* Whether object is currently being dragged.
* @type {boolean}
* @private
*/
goog.fx.Dragger.prototype.dragging_ = false;
/**
* The amount of distance, in pixels, after which a mousedown or touchstart is
* considered a drag.
* @type {number}
* @private
*/
goog.fx.Dragger.prototype.hysteresisDistanceSquared_ = 0;
/**
* Timestamp of when the mousedown or touchstart occurred.
* @type {number}
* @private
*/
goog.fx.Dragger.prototype.mouseDownTime_ = 0;
/**
* Reference to a document object to use for the events.
* @type {Document}
* @private
*/
goog.fx.Dragger.prototype.document_;
/**
* The SCROLL event target used to make drag element follow scrolling.
* @type {EventTarget}
* @private
*/
goog.fx.Dragger.prototype.scrollTarget_;
/**
* Whether IE drag events cancelling is on.
* @type {boolean}
* @private
*/
goog.fx.Dragger.prototype.ieDragStartCancellingOn_ = false;
/**
* Whether the dragger implements the changes described in http://b/6324964,
* making it truly RTL. This is a temporary flag to allow clients to transition
* to the new behavior at their convenience. At some point it will be the
* default.
* @type {boolean}
* @private
*/
goog.fx.Dragger.prototype.useRightPositioningForRtl_ = false;
/**
* Turns on/off true RTL behavior. This should be called immediately after
* construction. This is a temporary flag to allow clients to transition
* to the new component at their convenience. At some point true will be the
* default.
* @param {boolean} useRightPositioningForRtl True if "right" should be used for
* positioning, false if "left" should be used for positioning.
*/
goog.fx.Dragger.prototype.enableRightPositioningForRtl =
function(useRightPositioningForRtl) {
this.useRightPositioningForRtl_ = useRightPositioningForRtl;
};
/**
* Returns the event handler, intended for subclass use.
* @return {goog.events.EventHandler} The event handler.
*/
goog.fx.Dragger.prototype.getHandler = function() {
return this.eventHandler_;
};
/**
* Sets (or reset) the Drag limits after a Dragger is created.
* @param {goog.math.Rect?} limits Object containing left, top, width,
* height for new Dragger limits. If target is right-to-left and
* enableRightPositioningForRtl(true) is called, then rect is interpreted as
* right, top, width, and height.
*/
goog.fx.Dragger.prototype.setLimits = function(limits) {
this.limits = limits || new goog.math.Rect(NaN, NaN, NaN, NaN);
};
/**
* Sets the distance the user has to drag the element before a drag operation is
* started.
* @param {number} distance The number of pixels after which a mousedown and
* move is considered a drag.
*/
goog.fx.Dragger.prototype.setHysteresis = function(distance) {
this.hysteresisDistanceSquared_ = Math.pow(distance, 2);
};
/**
* Gets the distance the user has to drag the element before a drag operation is
* started.
* @return {number} distance The number of pixels after which a mousedown and
* move is considered a drag.
*/
goog.fx.Dragger.prototype.getHysteresis = function() {
return Math.sqrt(this.hysteresisDistanceSquared_);
};
/**
* Sets the SCROLL event target to make drag element follow scrolling.
*
* @param {EventTarget} scrollTarget The event target that dispatches SCROLL
* events.
*/
goog.fx.Dragger.prototype.setScrollTarget = function(scrollTarget) {
this.scrollTarget_ = scrollTarget;
};
/**
* Enables cancelling of built-in IE drag events.
* @param {boolean} cancelIeDragStart Whether to enable cancelling of IE
* dragstart event.
*/
goog.fx.Dragger.prototype.setCancelIeDragStart = function(cancelIeDragStart) {
this.ieDragStartCancellingOn_ = cancelIeDragStart;
};
/**
* @return {boolean} Whether the dragger is enabled.
*/
goog.fx.Dragger.prototype.getEnabled = function() {
return this.enabled_;
};
/**
* Set whether dragger is enabled
* @param {boolean} enabled Whether dragger is enabled.
*/
goog.fx.Dragger.prototype.setEnabled = function(enabled) {
this.enabled_ = enabled;
};
/** @override */
goog.fx.Dragger.prototype.disposeInternal = function() {
goog.fx.Dragger.superClass_.disposeInternal.call(this);
goog.events.unlisten(this.handle,
[goog.events.EventType.TOUCHSTART, goog.events.EventType.MOUSEDOWN],
this.startDrag, false, this);
this.cleanUpAfterDragging_();
this.target = null;
this.handle = null;
};
/**
* Whether the DOM element being manipulated is rendered right-to-left.
* @return {boolean} True if the DOM element is rendered right-to-left, false
* otherwise.
* @private
*/
goog.fx.Dragger.prototype.isRightToLeft_ = function() {
if (!goog.isDef(this.rightToLeft_)) {
this.rightToLeft_ = goog.style.isRightToLeft(this.target);
}
return this.rightToLeft_;
};
/**
* Event handler that is used to start the drag
* @param {goog.events.BrowserEvent} e Event object.
*/
goog.fx.Dragger.prototype.startDrag = function(e) {
var isMouseDown = e.type == goog.events.EventType.MOUSEDOWN;
// Dragger.startDrag() can be called by AbstractDragDrop with a mousemove
// event and IE does not report pressed mouse buttons on mousemove. Also,
// it does not make sense to check for the button if the user is already
// dragging.
if (this.enabled_ && !this.dragging_ &&
(!isMouseDown || e.isMouseActionButton())) {
this.maybeReinitTouchEvent_(e);
if (this.hysteresisDistanceSquared_ == 0) {
if (this.fireDragStart_(e)) {
this.dragging_ = true;
e.preventDefault();
} else {
// If the start drag is cancelled, don't setup for a drag.
return;
}
} else {
// Need to preventDefault for hysteresis to prevent page getting selected.
e.preventDefault();
}
this.setupDragHandlers();
this.clientX = this.startX = e.clientX;
this.clientY = this.startY = e.clientY;
this.screenX = e.screenX;
this.screenY = e.screenY;
this.deltaX = this.useRightPositioningForRtl_ ?
goog.style.bidi.getOffsetStart(this.target) : this.target.offsetLeft;
this.deltaY = this.target.offsetTop;
this.pageScroll = goog.dom.getDomHelper(this.document_).getDocumentScroll();
this.mouseDownTime_ = goog.now();
} else {
this.dispatchEvent(goog.fx.Dragger.EventType.EARLY_CANCEL);
}
};
/**
* Sets up event handlers when dragging starts.
* @protected
*/
goog.fx.Dragger.prototype.setupDragHandlers = function() {
var doc = this.document_;
var docEl = doc.documentElement;
// Use bubbling when we have setCapture since we got reports that IE has
// problems with the capturing events in combination with setCapture.
var useCapture = !goog.fx.Dragger.HAS_SET_CAPTURE_;
this.eventHandler_.listen(doc,
[goog.events.EventType.TOUCHMOVE, goog.events.EventType.MOUSEMOVE],
this.handleMove_, useCapture);
this.eventHandler_.listen(doc,
[goog.events.EventType.TOUCHEND, goog.events.EventType.MOUSEUP],
this.endDrag, useCapture);
if (goog.fx.Dragger.HAS_SET_CAPTURE_) {
docEl.setCapture(false);
this.eventHandler_.listen(docEl,
goog.events.EventType.LOSECAPTURE,
this.endDrag);
} else {
// Make sure we stop the dragging if the window loses focus.
// Don't use capture in this listener because we only want to end the drag
// if the actual window loses focus. Since blur events do not bubble we use
// a bubbling listener on the window.
this.eventHandler_.listen(goog.dom.getWindow(doc),
goog.events.EventType.BLUR,
this.endDrag);
}
if (goog.userAgent.IE && this.ieDragStartCancellingOn_) {
// Cancel IE's 'ondragstart' event.
this.eventHandler_.listen(doc, goog.events.EventType.DRAGSTART,
goog.events.Event.preventDefault);
}
if (this.scrollTarget_) {
this.eventHandler_.listen(this.scrollTarget_, goog.events.EventType.SCROLL,
this.onScroll_, useCapture);
}
};
/**
* Fires a goog.fx.Dragger.EventType.START event.
* @param {goog.events.BrowserEvent} e Browser event that triggered the drag.
* @return {boolean} False iff preventDefault was called on the DragEvent.
* @private
*/
goog.fx.Dragger.prototype.fireDragStart_ = function(e) {
return this.dispatchEvent(new goog.fx.DragEvent(
goog.fx.Dragger.EventType.START, this, e.clientX, e.clientY, e));
};
/**
* Unregisters the event handlers that are only active during dragging, and
* releases mouse capture.
* @private
*/
goog.fx.Dragger.prototype.cleanUpAfterDragging_ = function() {
this.eventHandler_.removeAll();
if (goog.fx.Dragger.HAS_SET_CAPTURE_) {
this.document_.releaseCapture();
}
};
/**
* Event handler that is used to end the drag.
* @param {goog.events.BrowserEvent} e Event object.
* @param {boolean=} opt_dragCanceled Whether the drag has been canceled.
*/
goog.fx.Dragger.prototype.endDrag = function(e, opt_dragCanceled) {
this.cleanUpAfterDragging_();
if (this.dragging_) {
this.maybeReinitTouchEvent_(e);
this.dragging_ = false;
var x = this.limitX(this.deltaX);
var y = this.limitY(this.deltaY);
var dragCanceled = opt_dragCanceled ||
e.type == goog.events.EventType.TOUCHCANCEL;
this.dispatchEvent(new goog.fx.DragEvent(
goog.fx.Dragger.EventType.END, this, e.clientX, e.clientY, e, x, y,
dragCanceled));
} else {
this.dispatchEvent(goog.fx.Dragger.EventType.EARLY_CANCEL);
}
};
/**
* Event handler that is used to end the drag by cancelling it.
* @param {goog.events.BrowserEvent} e Event object.
*/
goog.fx.Dragger.prototype.endDragCancel = function(e) {
this.endDrag(e, true);
};
/**
* Re-initializes the event with the first target touch event or, in the case
* of a stop event, the last changed touch.
* @param {goog.events.BrowserEvent} e A TOUCH... event.
* @private
*/
goog.fx.Dragger.prototype.maybeReinitTouchEvent_ = function(e) {
var type = e.type;
if (type == goog.events.EventType.TOUCHSTART ||
type == goog.events.EventType.TOUCHMOVE) {
e.init(e.getBrowserEvent().targetTouches[0], e.currentTarget);
} else if (type == goog.events.EventType.TOUCHEND ||
type == goog.events.EventType.TOUCHCANCEL) {
e.init(e.getBrowserEvent().changedTouches[0], e.currentTarget);
}
};
/**
* Event handler that is used on mouse / touch move to update the drag
* @param {goog.events.BrowserEvent} e Event object.
* @private
*/
goog.fx.Dragger.prototype.handleMove_ = function(e) {
if (this.enabled_) {
this.maybeReinitTouchEvent_(e);
// dx in right-to-left cases is relative to the right.
var sign = this.useRightPositioningForRtl_ &&
this.isRightToLeft_() ? -1 : 1;
var dx = sign * (e.clientX - this.clientX);
var dy = e.clientY - this.clientY;
this.clientX = e.clientX;
this.clientY = e.clientY;
this.screenX = e.screenX;
this.screenY = e.screenY;
if (!this.dragging_) {
var diffX = this.startX - this.clientX;
var diffY = this.startY - this.clientY;
var distance = diffX * diffX + diffY * diffY;
if (distance > this.hysteresisDistanceSquared_) {
if (this.fireDragStart_(e)) {
this.dragging_ = true;
} else {
// DragListGroup disposes of the dragger if BEFOREDRAGSTART is
// canceled.
if (!this.isDisposed()) {
this.endDrag(e);
}
return;
}
}
}
var pos = this.calculatePosition_(dx, dy);
var x = pos.x;
var y = pos.y;
if (this.dragging_) {
var rv = this.dispatchEvent(new goog.fx.DragEvent(
goog.fx.Dragger.EventType.BEFOREDRAG, this, e.clientX, e.clientY,
e, x, y));
// Only do the defaultAction and dispatch drag event if predrag didn't
// prevent default
if (rv) {
this.doDrag(e, x, y, false);
e.preventDefault();
}
}
}
};
/**
* Calculates the drag position.
*
* @param {number} dx The horizontal movement delta.
* @param {number} dy The vertical movement delta.
* @return {goog.math.Coordinate} The newly calculated drag element position.
* @private
*/
goog.fx.Dragger.prototype.calculatePosition_ = function(dx, dy) {
// Update the position for any change in body scrolling
var pageScroll = goog.dom.getDomHelper(this.document_).getDocumentScroll();
dx += pageScroll.x - this.pageScroll.x;
dy += pageScroll.y - this.pageScroll.y;
this.pageScroll = pageScroll;
this.deltaX += dx;
this.deltaY += dy;
var x = this.limitX(this.deltaX);
var y = this.limitY(this.deltaY);
return new goog.math.Coordinate(x, y);
};
/**
* Event handler for scroll target scrolling.
* @param {goog.events.BrowserEvent} e The event.
* @private
*/
goog.fx.Dragger.prototype.onScroll_ = function(e) {
var pos = this.calculatePosition_(0, 0);
e.clientX = this.clientX;
e.clientY = this.clientY;
this.doDrag(e, pos.x, pos.y, true);
};
/**
* @param {goog.events.BrowserEvent} e The closure object
* representing the browser event that caused a drag event.
* @param {number} x The new horizontal position for the drag element.
* @param {number} y The new vertical position for the drag element.
* @param {boolean} dragFromScroll Whether dragging was caused by scrolling
* the associated scroll target.
* @protected
*/
goog.fx.Dragger.prototype.doDrag = function(e, x, y, dragFromScroll) {
this.defaultAction(x, y);
this.dispatchEvent(new goog.fx.DragEvent(
goog.fx.Dragger.EventType.DRAG, this, e.clientX, e.clientY, e, x, y));
};
/**
* Returns the 'real' x after limits are applied (allows for some
* limits to be undefined).
* @param {number} x X-coordinate to limit.
* @return {number} The 'real' X-coordinate after limits are applied.
*/
goog.fx.Dragger.prototype.limitX = function(x) {
var rect = this.limits;
var left = !isNaN(rect.left) ? rect.left : null;
var width = !isNaN(rect.width) ? rect.width : 0;
var maxX = left != null ? left + width : Infinity;
var minX = left != null ? left : -Infinity;
return Math.min(maxX, Math.max(minX, x));
};
/**
* Returns the 'real' y after limits are applied (allows for some
* limits to be undefined).
* @param {number} y Y-coordinate to limit.
* @return {number} The 'real' Y-coordinate after limits are applied.
*/
goog.fx.Dragger.prototype.limitY = function(y) {
var rect = this.limits;
var top = !isNaN(rect.top) ? rect.top : null;
var height = !isNaN(rect.height) ? rect.height : 0;
var maxY = top != null ? top + height : Infinity;
var minY = top != null ? top : -Infinity;
return Math.min(maxY, Math.max(minY, y));
};
/**
* Overridable function for handling the default action of the drag behaviour.
* Normally this is simply moving the element to x,y though in some cases it
* might be used to resize the layer. This is basically a shortcut to
* implementing a default ondrag event handler.
* @param {number} x X-coordinate for target element. In right-to-left, x this
* is the number of pixels the target should be moved to from the right.
* @param {number} y Y-coordinate for target element.
*/
goog.fx.Dragger.prototype.defaultAction = function(x, y) {
if (this.useRightPositioningForRtl_ && this.isRightToLeft_()) {
this.target.style.right = x + 'px';
} else {
this.target.style.left = x + 'px';
}
this.target.style.top = y + 'px';
};
/**
* @return {boolean} Whether the dragger is currently in the midst of a drag.
*/
goog.fx.Dragger.prototype.isDragging = function() {
return this.dragging_;
};
/**
* Object representing a drag event
* @param {string} type Event type.
* @param {goog.fx.Dragger} dragobj Drag object initiating event.
* @param {number} clientX X-coordinate relative to the viewport.
* @param {number} clientY Y-coordinate relative to the viewport.
* @param {goog.events.BrowserEvent} browserEvent The closure object
* representing the browser event that caused this drag event.
* @param {number=} opt_actX Optional actual x for drag if it has been limited.
* @param {number=} opt_actY Optional actual y for drag if it has been limited.
* @param {boolean=} opt_dragCanceled Whether the drag has been canceled.
* @constructor
* @extends {goog.events.Event}
*/
goog.fx.DragEvent = function(type, dragobj, clientX, clientY, browserEvent,
opt_actX, opt_actY, opt_dragCanceled) {
goog.events.Event.call(this, type);
/**
* X-coordinate relative to the viewport
* @type {number}
*/
this.clientX = clientX;
/**
* Y-coordinate relative to the viewport
* @type {number}
*/
this.clientY = clientY;
/**
* The closure object representing the browser event that caused this drag
* event.
* @type {goog.events.BrowserEvent}
*/
this.browserEvent = browserEvent;
/**
* The real x-position of the drag if it has been limited
* @type {number}
*/
this.left = goog.isDef(opt_actX) ? opt_actX : dragobj.deltaX;
/**
* The real y-position of the drag if it has been limited
* @type {number}
*/
this.top = goog.isDef(opt_actY) ? opt_actY : dragobj.deltaY;
/**
* Reference to the drag object for this event
* @type {goog.fx.Dragger}
*/
this.dragger = dragobj;
/**
* Whether drag was canceled with this event. Used to differentiate between
* a legitimate drag END that can result in an action and a drag END which is
* a result of a drag cancelation. For now it can happen 1) with drag END
* event on FireFox when user drags the mouse out of the window, 2) with
* drag END event on IE7 which is generated on MOUSEMOVE event when user
* moves the mouse into the document after the mouse button has been
* released, 3) when TOUCHCANCEL is raised instead of TOUCHEND (on touch
* events).
* @type {boolean}
*/
this.dragCanceled = !!opt_dragCanceled;
};
goog.inherits(goog.fx.DragEvent, goog.events.Event);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,299 @@
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Class to support scrollable containers for drag and drop.
*
*/
goog.provide('goog.fx.DragScrollSupport');
goog.require('goog.Disposable');
goog.require('goog.Timer');
goog.require('goog.dom');
goog.require('goog.events.EventHandler');
goog.require('goog.events.EventType');
goog.require('goog.math.Coordinate');
goog.require('goog.style');
/**
* A scroll support class. Currently this class will automatically scroll
* a scrollable container node and scroll it by a fixed amount at a timed
* interval when the mouse is moved above or below the container or in vertical
* margin areas. Intended for use in drag and drop. This could potentially be
* made more general and could support horizontal scrolling.
*
* @param {Element} containerNode A container that can be scrolled.
* @param {number=} opt_margin Optional margin to use while scrolling.
* @param {boolean=} opt_externalMouseMoveTracking Whether mouse move events
* are tracked externally by the client object which calls the mouse move
* event handler, useful when events are generated for more than one source
* element and/or are not real mousemove events.
* @constructor
* @extends {goog.Disposable}
* @see ../demos/dragscrollsupport.html
*/
goog.fx.DragScrollSupport = function(containerNode, opt_margin,
opt_externalMouseMoveTracking) {
goog.Disposable.call(this);
/**
* The container to be scrolled.
* @type {Element}
* @private
*/
this.containerNode_ = containerNode;
/**
* Scroll timer that will scroll the container until it is stopped.
* It will scroll when the mouse is outside the scrolling area of the
* container.
*
* @type {goog.Timer}
* @private
*/
this.scrollTimer_ = new goog.Timer(goog.fx.DragScrollSupport.TIMER_STEP_);
/**
* EventHandler used to set up and tear down listeners.
* @type {goog.events.EventHandler}
* @private
*/
this.eventHandler_ = new goog.events.EventHandler(this);
/**
* The current scroll delta.
* @type {goog.math.Coordinate}
* @private
*/
this.scrollDelta_ = new goog.math.Coordinate();
/**
* The container bounds.
* @type {goog.math.Rect}
* @private
*/
this.containerBounds_ = goog.style.getBounds(containerNode);
/**
* The margin for triggering a scroll.
* @type {number}
* @private
*/
this.margin_ = opt_margin || 0;
/**
* The bounding rectangle which if left triggers scrolling.
* @type {goog.math.Rect}
* @private
*/
this.scrollBounds_ = opt_margin ?
this.constrainBounds_(this.containerBounds_.clone()) :
this.containerBounds_;
this.setupListeners_(!!opt_externalMouseMoveTracking);
};
goog.inherits(goog.fx.DragScrollSupport, goog.Disposable);
/**
* The scroll timer step in ms.
* @type {number}
* @private
*/
goog.fx.DragScrollSupport.TIMER_STEP_ = 50;
/**
* The scroll step in pixels.
* @type {number}
* @private
*/
goog.fx.DragScrollSupport.SCROLL_STEP_ = 8;
/**
* The suggested scrolling margin.
* @type {number}
*/
goog.fx.DragScrollSupport.MARGIN = 32;
/**
* Whether scrolling should be constrained to happen only when the cursor is
* inside the container node.
* @type {boolean}
* @private
*/
goog.fx.DragScrollSupport.prototype.constrainScroll_ = false;
/**
* Whether horizontal scrolling is allowed.
* @type {boolean}
* @private
*/
goog.fx.DragScrollSupport.prototype.horizontalScrolling_ = true;
/**
* Sets whether scrolling should be constrained to happen only when the cursor
* is inside the container node.
* NOTE: If a margin is not set, then it does not make sense to
* contain the scroll, because in that case scroll will never be triggered.
* @param {boolean} constrain Whether scrolling should be constrained to happen
* only when the cursor is inside the container node.
*/
goog.fx.DragScrollSupport.prototype.setConstrainScroll = function(constrain) {
this.constrainScroll_ = !!this.margin_ && constrain;
};
/**
* Sets whether horizontal scrolling is allowed.
* @param {boolean} scrolling Whether horizontal scrolling is allowed.
*/
goog.fx.DragScrollSupport.prototype.setHorizontalScrolling =
function(scrolling) {
this.horizontalScrolling_ = scrolling;
};
/**
* Constrains the container bounds with respect to the margin.
*
* @param {goog.math.Rect} bounds The container element.
* @return {goog.math.Rect} The bounding rectangle used to calculate scrolling
* direction.
* @private
*/
goog.fx.DragScrollSupport.prototype.constrainBounds_ = function(bounds) {
var margin = this.margin_;
if (margin) {
var quarterHeight = bounds.height * 0.25;
var yMargin = Math.min(margin, quarterHeight);
bounds.top += yMargin;
bounds.height -= 2 * yMargin;
var quarterWidth = bounds.width * 0.25;
var xMargin = Math.min(margin, quarterWidth);
bounds.top += xMargin;
bounds.height -= 2 * xMargin;
}
return bounds;
};
/**
* Attaches listeners and activates automatic scrolling.
* @param {boolean} externalMouseMoveTracking Whether to enable internal
* mouse move event handling.
* @private
*/
goog.fx.DragScrollSupport.prototype.setupListeners_ = function(
externalMouseMoveTracking) {
if (!externalMouseMoveTracking) {
// Track mouse pointer position to determine scroll direction.
this.eventHandler_.listen(goog.dom.getOwnerDocument(this.containerNode_),
goog.events.EventType.MOUSEMOVE, this.onMouseMove);
}
// Scroll with a constant speed.
this.eventHandler_.listen(this.scrollTimer_, goog.Timer.TICK, this.onTick_);
};
/**
* Handler for timer tick event, scrolls the container by one scroll step if
* needed.
* @param {goog.events.Event} event Timer tick event.
* @private
*/
goog.fx.DragScrollSupport.prototype.onTick_ = function(event) {
this.containerNode_.scrollTop += this.scrollDelta_.y;
this.containerNode_.scrollLeft += this.scrollDelta_.x;
};
/**
* Handler for mouse moves events.
* @param {goog.events.Event} event Mouse move event.
*/
goog.fx.DragScrollSupport.prototype.onMouseMove = function(event) {
var deltaX = this.horizontalScrolling_ ? this.calculateScrollDelta(
event.clientX, this.scrollBounds_.left, this.scrollBounds_.width) : 0;
var deltaY = this.calculateScrollDelta(event.clientY,
this.scrollBounds_.top, this.scrollBounds_.height);
this.scrollDelta_.x = deltaX;
this.scrollDelta_.y = deltaY;
// If the scroll data is 0 or the event fired outside of the
// bounds of the container node.
if ((!deltaX && !deltaY) ||
(this.constrainScroll_ &&
!this.isInContainerBounds_(event.clientX, event.clientY))) {
this.scrollTimer_.stop();
} else if (!this.scrollTimer_.enabled) {
this.scrollTimer_.start();
}
};
/**
* Gets whether the input coordinate is in the container bounds.
* @param {number} x The x coordinate.
* @param {number} y The y coordinate.
* @return {boolean} Whether the input coordinate is in the container bounds.
* @private
*/
goog.fx.DragScrollSupport.prototype.isInContainerBounds_ = function(x, y) {
var containerBounds = this.containerBounds_;
return containerBounds.left <= x &&
containerBounds.left + containerBounds.width >= x &&
containerBounds.top <= y &&
containerBounds.top + containerBounds.height >= y;
};
/**
* Calculates scroll delta.
*
* @param {number} coordinate Current mouse pointer coordinate.
* @param {number} min The coordinate value below which scrolling up should be
* started.
* @param {number} rangeLength The length of the range in which scrolling should
* be disabled and above which scrolling down should be started.
* @return {number} The calculated scroll delta.
* @protected
*/
goog.fx.DragScrollSupport.prototype.calculateScrollDelta = function(
coordinate, min, rangeLength) {
var delta = 0;
if (coordinate < min) {
delta = -goog.fx.DragScrollSupport.SCROLL_STEP_;
} else if (coordinate > min + rangeLength) {
delta = goog.fx.DragScrollSupport.SCROLL_STEP_;
}
return delta;
};
/** @override */
goog.fx.DragScrollSupport.prototype.disposeInternal = function() {
goog.fx.DragScrollSupport.superClass_.disposeInternal.call(this);
this.eventHandler_.dispose();
this.scrollTimer_.dispose();
};

View File

@@ -0,0 +1,50 @@
// Copyright 2006 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Easing functions for animations.
*
*/
goog.provide('goog.fx.easing');
/**
* Ease in - Start slow and speed up.
* @param {number} t Input between 0 and 1.
* @return {number} Output between 0 and 1.
*/
goog.fx.easing.easeIn = function(t) {
return t * t * t;
};
/**
* Ease out - Start fastest and slows to a stop.
* @param {number} t Input between 0 and 1.
* @return {number} Output between 0 and 1.
*/
goog.fx.easing.easeOut = function(t) {
return 1 - Math.pow(1 - t, 3);
};
/**
* Ease in and out - Start slow, speed up, then slow down.
* @param {number} t Input between 0 and 1.
* @return {number} Output between 0 and 1.
*/
goog.fx.easing.inAndOut = function(t) {
return 3 * t * t - 2 * t * t * t;
};

View File

@@ -0,0 +1,32 @@
// Copyright 2010 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Legacy stub for the goog.fx namespace. Requires the moved
* namespaces. Animation and easing have been moved to animation.js and
* easing.js. Users of this stub should move off so we may remove it in the
* future.
*
* @author nnaze@google.com (Nathan Naze)
*/
goog.provide('goog.fx');
goog.require('goog.asserts');
goog.require('goog.fx.Animation');
goog.require('goog.fx.Animation.EventType');
goog.require('goog.fx.Animation.State');
goog.require('goog.fx.AnimationEvent');
goog.require('goog.fx.Transition.EventType');
goog.require('goog.fx.easing');

View File

@@ -0,0 +1,75 @@
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview An interface for transition animation. This is a simple
* interface that allows for playing and stopping a transition. It adds
* a simple event model with BEGIN and END event.
*
*/
goog.provide('goog.fx.Transition');
goog.provide('goog.fx.Transition.EventType');
/**
* An interface for programmatic transition. Must extend
* {@code goog.events.EventTarget}.
* @interface
*/
goog.fx.Transition = function() {};
/**
* Transition event types.
* @enum {string}
*/
goog.fx.Transition.EventType = {
/** Dispatched when played for the first time OR when it is resumed. */
PLAY: 'play',
/** Dispatched only when the animation starts from the beginning. */
BEGIN: 'begin',
/** Dispatched only when animation is restarted after a pause. */
RESUME: 'resume',
/**
* Dispatched when animation comes to the end of its duration OR stop
* is called.
*/
END: 'end',
/** Dispatched only when stop is called. */
STOP: 'stop',
/** Dispatched only when animation comes to its end naturally. */
FINISH: 'finish',
/** Dispatched when an animation is paused. */
PAUSE: 'pause'
};
/**
* Plays the transition.
*/
goog.fx.Transition.prototype.play;
/**
* Stops the transition.
*/
goog.fx.Transition.prototype.stop;

View File

@@ -0,0 +1,237 @@
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview An abstract base class for transitions. This is a simple
* interface that allows for playing, pausing and stopping an animation. It adds
* a simple event model, and animation status.
*/
goog.provide('goog.fx.TransitionBase');
goog.provide('goog.fx.TransitionBase.State');
goog.require('goog.events.EventTarget');
goog.require('goog.fx.Transition'); // Unreferenced: interface
goog.require('goog.fx.Transition.EventType');
/**
* Constructor for a transition object.
*
* @constructor
* @implements {goog.fx.Transition}
* @extends {goog.events.EventTarget}
*/
goog.fx.TransitionBase = function() {
goog.base(this);
/**
* The internal state of the animation.
* @type {goog.fx.TransitionBase.State}
* @private
*/
this.state_ = goog.fx.TransitionBase.State.STOPPED;
/**
* Timestamp for when the animation was started.
* @type {?number}
* @protected
*/
this.startTime = null;
/**
* Timestamp for when the animation finished or was stopped.
* @type {?number}
* @protected
*/
this.endTime = null;
};
goog.inherits(goog.fx.TransitionBase, goog.events.EventTarget);
/**
* Enum for the possible states of an animation.
* @enum {number}
*/
goog.fx.TransitionBase.State = {
STOPPED: 0,
PAUSED: -1,
PLAYING: 1
};
/**
* Plays the animation.
*
* @param {boolean=} opt_restart Optional parameter to restart the animation.
* @return {boolean} True iff the animation was started.
* @override
*/
goog.fx.TransitionBase.prototype.play = goog.abstractMethod;
/**
* Stops the animation.
*
* @param {boolean=} opt_gotoEnd Optional boolean parameter to go the the end of
* the animation.
* @override
*/
goog.fx.TransitionBase.prototype.stop = goog.abstractMethod;
/**
* Pauses the animation.
*/
goog.fx.TransitionBase.prototype.pause = goog.abstractMethod;
/**
* Returns the current state of the animation.
* @return {goog.fx.TransitionBase.State} State of the animation.
*/
goog.fx.TransitionBase.prototype.getStateInternal = function() {
return this.state_;
};
/**
* Sets the current state of the animation to playing.
* @protected
*/
goog.fx.TransitionBase.prototype.setStatePlaying = function() {
this.state_ = goog.fx.TransitionBase.State.PLAYING;
};
/**
* Sets the current state of the animation to paused.
* @protected
*/
goog.fx.TransitionBase.prototype.setStatePaused = function() {
this.state_ = goog.fx.TransitionBase.State.PAUSED;
};
/**
* Sets the current state of the animation to stopped.
* @protected
*/
goog.fx.TransitionBase.prototype.setStateStopped = function() {
this.state_ = goog.fx.TransitionBase.State.STOPPED;
};
/**
* @return {boolean} True iff the current state of the animation is playing.
*/
goog.fx.TransitionBase.prototype.isPlaying = function() {
return this.state_ == goog.fx.TransitionBase.State.PLAYING;
};
/**
* @return {boolean} True iff the current state of the animation is paused.
*/
goog.fx.TransitionBase.prototype.isPaused = function() {
return this.state_ == goog.fx.TransitionBase.State.PAUSED;
};
/**
* @return {boolean} True iff the current state of the animation is stopped.
*/
goog.fx.TransitionBase.prototype.isStopped = function() {
return this.state_ == goog.fx.TransitionBase.State.STOPPED;
};
/**
* Dispatches the BEGIN event. Sub classes should override this instead
* of listening to the event, and call this instead of dispatching the event.
* @protected
*/
goog.fx.TransitionBase.prototype.onBegin = function() {
this.dispatchAnimationEvent(goog.fx.Transition.EventType.BEGIN);
};
/**
* Dispatches the END event. Sub classes should override this instead
* of listening to the event, and call this instead of dispatching the event.
* @protected
*/
goog.fx.TransitionBase.prototype.onEnd = function() {
this.dispatchAnimationEvent(goog.fx.Transition.EventType.END);
};
/**
* Dispatches the FINISH event. Sub classes should override this instead
* of listening to the event, and call this instead of dispatching the event.
* @protected
*/
goog.fx.TransitionBase.prototype.onFinish = function() {
this.dispatchAnimationEvent(goog.fx.Transition.EventType.FINISH);
};
/**
* Dispatches the PAUSE event. Sub classes should override this instead
* of listening to the event, and call this instead of dispatching the event.
* @protected
*/
goog.fx.TransitionBase.prototype.onPause = function() {
this.dispatchAnimationEvent(goog.fx.Transition.EventType.PAUSE);
};
/**
* Dispatches the PLAY event. Sub classes should override this instead
* of listening to the event, and call this instead of dispatching the event.
* @protected
*/
goog.fx.TransitionBase.prototype.onPlay = function() {
this.dispatchAnimationEvent(goog.fx.Transition.EventType.PLAY);
};
/**
* Dispatches the RESUME event. Sub classes should override this instead
* of listening to the event, and call this instead of dispatching the event.
* @protected
*/
goog.fx.TransitionBase.prototype.onResume = function() {
this.dispatchAnimationEvent(goog.fx.Transition.EventType.RESUME);
};
/**
* Dispatches the STOP event. Sub classes should override this instead
* of listening to the event, and call this instead of dispatching the event.
* @protected
*/
goog.fx.TransitionBase.prototype.onStop = function() {
this.dispatchAnimationEvent(goog.fx.Transition.EventType.STOP);
};
/**
* Dispatches an event object for the current animation.
* @param {string} type Event type that will be dispatched.
* @protected
*/
goog.fx.TransitionBase.prototype.dispatchAnimationEvent = function(type) {
this.dispatchEvent(type);
};