200 lines
5.8 KiB
JavaScript
200 lines
5.8 KiB
JavaScript
// 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 Animated zippy widget implementation.
|
|
*
|
|
* @author eae@google.com (Emil A Eklund)
|
|
* @see ../demos/zippy.html
|
|
*/
|
|
|
|
goog.provide('goog.ui.AnimatedZippy');
|
|
|
|
goog.require('goog.dom');
|
|
goog.require('goog.events');
|
|
goog.require('goog.fx.Animation');
|
|
goog.require('goog.fx.Transition');
|
|
goog.require('goog.fx.easing');
|
|
goog.require('goog.ui.Zippy');
|
|
goog.require('goog.ui.ZippyEvent');
|
|
|
|
|
|
|
|
/**
|
|
* Zippy widget. Expandable/collapsible container, clicking the header toggles
|
|
* the visibility of the content.
|
|
*
|
|
* @param {Element|string|null} header Header element, either element
|
|
* reference, string id or null if no header exists.
|
|
* @param {Element|string} content Content element, either element reference or
|
|
* string id.
|
|
* @param {boolean=} opt_expanded Initial expanded/visibility state. Defaults to
|
|
* false.
|
|
* @param {goog.dom.DomHelper=} opt_domHelper An optional DOM helper.
|
|
* @constructor
|
|
* @extends {goog.ui.Zippy}
|
|
*/
|
|
goog.ui.AnimatedZippy = function(header, content, opt_expanded, opt_domHelper) {
|
|
var domHelper = opt_domHelper || goog.dom.getDomHelper();
|
|
|
|
// Create wrapper element and move content into it.
|
|
var elWrapper = domHelper.createDom('div', {'style': 'overflow:hidden'});
|
|
var elContent = domHelper.getElement(content);
|
|
elContent.parentNode.replaceChild(elWrapper, elContent);
|
|
elWrapper.appendChild(elContent);
|
|
|
|
/**
|
|
* Content wrapper, used for animation.
|
|
* @type {Element}
|
|
* @private
|
|
*/
|
|
this.elWrapper_ = elWrapper;
|
|
|
|
/**
|
|
* Reference to animation or null if animation is not active.
|
|
* @type {goog.fx.Animation}
|
|
* @private
|
|
*/
|
|
this.anim_ = null;
|
|
|
|
// Call constructor of super class.
|
|
goog.ui.Zippy.call(this, header, elContent, opt_expanded,
|
|
undefined, domHelper);
|
|
|
|
// Set initial state.
|
|
// NOTE: Set the class names as well otherwise animated zippys
|
|
// start with empty class names.
|
|
var expanded = this.isExpanded();
|
|
this.elWrapper_.style.display = expanded ? '' : 'none';
|
|
this.updateHeaderClassName(expanded);
|
|
};
|
|
goog.inherits(goog.ui.AnimatedZippy, goog.ui.Zippy);
|
|
|
|
|
|
/**
|
|
* Duration of expand/collapse animation, in milliseconds.
|
|
* @type {number}
|
|
*/
|
|
goog.ui.AnimatedZippy.prototype.animationDuration = 500;
|
|
|
|
|
|
/**
|
|
* Acceleration function for expand/collapse animation.
|
|
* @type {!Function}
|
|
*/
|
|
goog.ui.AnimatedZippy.prototype.animationAcceleration = goog.fx.easing.easeOut;
|
|
|
|
|
|
/**
|
|
* @return {boolean} Whether the zippy is in the process of being expanded or
|
|
* collapsed.
|
|
*/
|
|
goog.ui.AnimatedZippy.prototype.isBusy = function() {
|
|
return this.anim_ != null;
|
|
};
|
|
|
|
|
|
/**
|
|
* Sets expanded state.
|
|
*
|
|
* @param {boolean} expanded Expanded/visibility state.
|
|
* @override
|
|
*/
|
|
goog.ui.AnimatedZippy.prototype.setExpanded = function(expanded) {
|
|
if (this.isExpanded() == expanded && !this.anim_) {
|
|
return;
|
|
}
|
|
|
|
// Reset display property of wrapper to allow content element to be
|
|
// measured.
|
|
if (this.elWrapper_.style.display == 'none') {
|
|
this.elWrapper_.style.display = '';
|
|
}
|
|
|
|
// Measure content element.
|
|
var h = this.getContentElement().offsetHeight;
|
|
|
|
// Stop active animation (if any) and determine starting height.
|
|
var startH = 0;
|
|
if (this.anim_) {
|
|
expanded = this.isExpanded();
|
|
goog.events.removeAll(this.anim_);
|
|
this.anim_.stop(false);
|
|
|
|
var marginTop = parseInt(this.getContentElement().style.marginTop, 10);
|
|
startH = h - Math.abs(marginTop);
|
|
} else {
|
|
startH = expanded ? 0 : h;
|
|
}
|
|
|
|
// Updates header class name after the animation has been stopped.
|
|
this.updateHeaderClassName(expanded);
|
|
|
|
// Set up expand/collapse animation.
|
|
this.anim_ = new goog.fx.Animation([0, startH],
|
|
[0, expanded ? h : 0],
|
|
this.animationDuration,
|
|
this.animationAcceleration);
|
|
|
|
var events = [goog.fx.Transition.EventType.BEGIN,
|
|
goog.fx.Animation.EventType.ANIMATE,
|
|
goog.fx.Transition.EventType.END];
|
|
goog.events.listen(this.anim_, events, this.onAnimate_, false, this);
|
|
goog.events.listen(this.anim_,
|
|
goog.fx.Transition.EventType.END,
|
|
goog.bind(this.onAnimationCompleted_, this, expanded));
|
|
|
|
// Start animation.
|
|
this.anim_.play(false);
|
|
};
|
|
|
|
|
|
/**
|
|
* Called during animation
|
|
*
|
|
* @param {goog.events.Event} e The event.
|
|
* @private
|
|
*/
|
|
goog.ui.AnimatedZippy.prototype.onAnimate_ = function(e) {
|
|
var contentElement = this.getContentElement();
|
|
var h = contentElement.offsetHeight;
|
|
contentElement.style.marginTop = (e.y - h) + 'px';
|
|
};
|
|
|
|
|
|
/**
|
|
* Called once the expand/collapse animation has completed.
|
|
*
|
|
* @param {boolean} expanded Expanded/visibility state.
|
|
* @private
|
|
*/
|
|
goog.ui.AnimatedZippy.prototype.onAnimationCompleted_ = function(expanded) {
|
|
// Fix wrong end position if the content has changed during the animation.
|
|
if (expanded) {
|
|
this.getContentElement().style.marginTop = '0';
|
|
}
|
|
|
|
goog.events.removeAll(this.anim_);
|
|
this.setExpandedInternal(expanded);
|
|
this.anim_ = null;
|
|
|
|
if (!expanded) {
|
|
this.elWrapper_.style.display = 'none';
|
|
}
|
|
|
|
// Fire toggle event.
|
|
this.dispatchEvent(new goog.ui.ZippyEvent(goog.ui.Zippy.Events.TOGGLE,
|
|
this, expanded));
|
|
};
|