Home | History | Annotate | Download | only in print_preview
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Counter used to give webkit animations unique names.
      6 var animationCounter = 0;
      7 
      8 function addAnimation(code) {
      9   var name = 'anim' + animationCounter;
     10   animationCounter++;
     11   var rules = document.createTextNode(
     12       '@-webkit-keyframes ' + name + ' {' + code + '}');
     13   var el = document.createElement('style');
     14   el.type = 'text/css';
     15   el.appendChild(rules);
     16   el.setAttribute('id', name);
     17   document.body.appendChild(el);
     18 
     19   return name;
     20 }
     21 
     22 /**
     23  * Generates css code for fading in an element by animating the height.
     24  * @param {number} targetHeight The desired height in pixels after the animation
     25  *     ends.
     26  * @return {string} The css code for the fade in animation.
     27  */
     28 function getFadeInAnimationCode(targetHeight) {
     29   return '0% { opacity: 0; height: 0; } ' +
     30       '80% { height: ' + (targetHeight + 4) + 'px; }' +
     31       '100% { opacity: 1; height: ' + targetHeight + 'px; }';
     32 }
     33 
     34 /**
     35  * Fades in an element. Used for both printing options and error messages
     36  * appearing underneath the textfields.
     37  * @param {HTMLElement} el The element to be faded in.
     38  */
     39 function fadeInElement(el) {
     40   if (el.classList.contains('visible'))
     41     return;
     42   el.classList.remove('closing');
     43   el.hidden = false;
     44   el.style.height = 'auto';
     45   var height = el.offsetHeight;
     46   el.style.height = height + 'px';
     47   var animName = addAnimation(getFadeInAnimationCode(height));
     48   var eventTracker = new EventTracker();
     49   eventTracker.add(el, 'webkitAnimationEnd',
     50                    onFadeInAnimationEnd.bind(el, eventTracker),
     51                    false);
     52   el.style.webkitAnimationName = animName;
     53   el.classList.add('visible');
     54 }
     55 
     56 /**
     57  * Fades out an element. Used for both printing options and error messages
     58  * appearing underneath the textfields.
     59  * @param {HTMLElement} el The element to be faded out.
     60  */
     61 function fadeOutElement(el) {
     62   if (!el.classList.contains('visible'))
     63     return;
     64   el.style.height = 'auto';
     65   var height = el.offsetHeight;
     66   el.style.height = height + 'px';
     67   var animName = addAnimation('');
     68   var eventTracker = new EventTracker();
     69   eventTracker.add(el, 'webkitTransitionEnd',
     70                    onFadeOutTransitionEnd.bind(el, animName, eventTracker),
     71                    false);
     72   el.classList.add('closing');
     73   el.classList.remove('visible');
     74 }
     75 
     76 /**
     77  * Executes when a fade out animation ends.
     78  * @param {string} animationName The name of the animation to be removed.
     79  * @param {EventTracker} eventTracker The |EventTracker| object that was used
     80  *     for adding this listener.
     81  * @param {WebkitTransitionEvent} event The event that triggered this listener.
     82  * @this {HTMLElement} The element where the transition occurred.
     83  */
     84 function onFadeOutTransitionEnd(animationName, eventTracker, event) {
     85   if (event.propertyName != 'height')
     86     return;
     87   fadeInOutCleanup(animationName);
     88   eventTracker.remove(this, 'webkitTransitionEnd');
     89   this.hidden = true;
     90 }
     91 
     92 /**
     93  * Executes when a fade in animation ends.
     94  * @param {EventTracker} eventTracker The |EventTracker| object that was used
     95  *     for adding this listener.
     96  * @param {WebkitAnimationEvent} event The event that triggered this listener.
     97  * @this {HTMLElement} The element where the transition occurred.
     98  */
     99 function onFadeInAnimationEnd(eventTracker, event) {
    100   this.style.height = '';
    101   this.style.webkitAnimationName = '';
    102   fadeInOutCleanup(event.animationName);
    103   eventTracker.remove(this, 'webkitAnimationEnd');
    104 }
    105 
    106 /**
    107  * Removes the <style> element corrsponding to |animationName| from the DOM.
    108  * @param {string} animationName The name of the animation to be removed.
    109  */
    110 function fadeInOutCleanup(animationName) {
    111   var animEl = document.getElementById(animationName);
    112   if (animEl)
    113     animEl.parentNode.removeChild(animEl);
    114 }
    115 
    116 /**
    117  * Fades in a printing option existing under |el|.
    118  * @param {HTMLElement} el The element to hide.
    119  */
    120 function fadeInOption(el) {
    121   if (el.classList.contains('visible'))
    122     return;
    123 
    124   wrapContentsInDiv(el.querySelector('h1'), ['invisible']);
    125   var rightColumn = el.querySelector('.right-column');
    126   wrapContentsInDiv(rightColumn, ['invisible']);
    127 
    128   var toAnimate = el.querySelectorAll('.collapsible');
    129   for (var i = 0; i < toAnimate.length; i++)
    130     fadeInElement(toAnimate[i]);
    131   el.classList.add('visible');
    132 }
    133 
    134 /**
    135  * Fades out a printing option existing under |el|.
    136  * @param {HTMLElement} el The element to hide.
    137  */
    138 function fadeOutOption(el) {
    139   if (!el.classList.contains('visible'))
    140     return;
    141 
    142   wrapContentsInDiv(el.querySelector('h1'), ['visible']);
    143   var rightColumn = el.querySelector('.right-column');
    144   wrapContentsInDiv(rightColumn, ['visible']);
    145 
    146   var toAnimate = el.querySelectorAll('.collapsible');
    147   for (var i = 0; i < toAnimate.length; i++)
    148     fadeOutElement(toAnimate[i]);
    149   el.classList.remove('visible');
    150 }
    151 
    152 /**
    153  * Wraps the contents of |el| in a div element and attaches css classes
    154  * |classes| in the new div, only if has not been already done. It is neccesary
    155  * for animating the height of table cells.
    156  * @param {HTMLElement} el The element to be processed.
    157  * @param {array} classes The css classes to add.
    158  */
    159 function wrapContentsInDiv(el, classes) {
    160   var div = el.querySelector('div');
    161   if (!div || !div.classList.contains('collapsible')) {
    162     div = document.createElement('div');
    163     while (el.childNodes.length > 0)
    164       div.appendChild(el.firstChild);
    165     el.appendChild(div);
    166   }
    167 
    168   div.className = '';
    169   div.classList.add('collapsible');
    170   for (var i = 0; i < classes.length; i++)
    171     div.classList.add(classes[i]);
    172 }
    173