blob: 7455a385f5c860924fa1563252c3e7d2ad6edb7b [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Counter used to give webkit animations unique names.
var animationCounter = 0;
function addAnimation(code) {
var name = 'anim' + animationCounter;
animationCounter++;
var rules = document.createTextNode(
'@-webkit-keyframes ' + name + ' {' + code + '}');
var el = document.createElement('style');
el.type = 'text/css';
el.appendChild(rules);
el.setAttribute('id', name);
document.body.appendChild(el);
return name;
}
/**
* Generates css code for fading in an element by animating the height.
* @param {number} targetHeight The desired height in pixels after the animation
* ends.
* @return {string} The css code for the fade in animation.
*/
function getFadeInAnimationCode(targetHeight) {
return '0% { opacity: 0; height: 0; } ' +
'80% { height: ' + (targetHeight + 4) + 'px; }' +
'100% { opacity: 1; height: ' + targetHeight + 'px; }';
}
/**
* Fades in an element. Used for both printing options and error messages
* appearing underneath the textfields.
* @param {HTMLElement} el The element to be faded in.
*/
function fadeInElement(el) {
if (el.classList.contains('visible'))
return;
el.classList.remove('closing');
el.hidden = false;
el.style.height = 'auto';
var height = el.offsetHeight;
el.style.height = height + 'px';
var animName = addAnimation(getFadeInAnimationCode(height));
var eventTracker = new EventTracker();
eventTracker.add(el, 'webkitAnimationEnd',
onFadeInAnimationEnd.bind(el, eventTracker),
false);
el.style.webkitAnimationName = animName;
el.classList.add('visible');
}
/**
* Fades out an element. Used for both printing options and error messages
* appearing underneath the textfields.
* @param {HTMLElement} el The element to be faded out.
*/
function fadeOutElement(el) {
if (!el.classList.contains('visible'))
return;
el.style.height = 'auto';
var height = el.offsetHeight;
el.style.height = height + 'px';
var animName = addAnimation('');
var eventTracker = new EventTracker();
eventTracker.add(el, 'webkitTransitionEnd',
onFadeOutTransitionEnd.bind(el, animName, eventTracker),
false);
el.classList.add('closing');
el.classList.remove('visible');
}
/**
* Executes when a fade out animation ends.
* @param {string} animationName The name of the animation to be removed.
* @param {EventTracker} eventTracker The |EventTracker| object that was used
* for adding this listener.
* @param {WebkitTransitionEvent} event The event that triggered this listener.
* @this {HTMLElement} The element where the transition occurred.
*/
function onFadeOutTransitionEnd(animationName, eventTracker, event) {
if (event.propertyName != 'height')
return;
fadeInOutCleanup(animationName);
eventTracker.remove(this, 'webkitTransitionEnd');
this.hidden = true;
}
/**
* Executes when a fade in animation ends.
* @param {EventTracker} eventTracker The |EventTracker| object that was used
* for adding this listener.
* @param {WebkitAnimationEvent} event The event that triggered this listener.
* @this {HTMLElement} The element where the transition occurred.
*/
function onFadeInAnimationEnd(eventTracker, event) {
this.style.height = '';
this.style.webkitAnimationName = '';
fadeInOutCleanup(event.animationName);
eventTracker.remove(this, 'webkitAnimationEnd');
}
/**
* Removes the <style> element corrsponding to |animationName| from the DOM.
* @param {string} animationName The name of the animation to be removed.
*/
function fadeInOutCleanup(animationName) {
var animEl = document.getElementById(animationName);
if (animEl)
animEl.parentNode.removeChild(animEl);
}
/**
* Fades in a printing option existing under |el|.
* @param {HTMLElement} el The element to hide.
*/
function fadeInOption(el) {
if (el.classList.contains('visible'))
return;
wrapContentsInDiv(el.querySelector('h1'), ['invisible']);
var rightColumn = el.querySelector('.right-column');
wrapContentsInDiv(rightColumn, ['invisible']);
var toAnimate = el.querySelectorAll('.collapsible');
for (var i = 0; i < toAnimate.length; i++)
fadeInElement(toAnimate[i]);
el.classList.add('visible');
}
/**
* Fades out a printing option existing under |el|.
* @param {HTMLElement} el The element to hide.
*/
function fadeOutOption(el) {
if (!el.classList.contains('visible'))
return;
wrapContentsInDiv(el.querySelector('h1'), ['visible']);
var rightColumn = el.querySelector('.right-column');
wrapContentsInDiv(rightColumn, ['visible']);
var toAnimate = el.querySelectorAll('.collapsible');
for (var i = 0; i < toAnimate.length; i++)
fadeOutElement(toAnimate[i]);
el.classList.remove('visible');
}
/**
* Wraps the contents of |el| in a div element and attaches css classes
* |classes| in the new div, only if has not been already done. It is neccesary
* for animating the height of table cells.
* @param {HTMLElement} el The element to be processed.
* @param {array} classes The css classes to add.
*/
function wrapContentsInDiv(el, classes) {
var div = el.querySelector('div');
if (!div || !div.classList.contains('collapsible')) {
div = document.createElement('div');
while (el.childNodes.length > 0)
div.appendChild(el.firstChild);
el.appendChild(div);
}
div.className = '';
div.classList.add('collapsible');
for (var i = 0; i < classes.length; i++)
div.classList.add(classes[i]);
}