| OLD | NEW | 
 | (Empty) | 
|    1 <!-- |  | 
|    2 @license |  | 
|    3 Copyright (c) 2015 The Polymer Project Authors. All rights reserved. |  | 
|    4 This code may only be used under the BSD style license found at http://polymer.g
     ithub.io/LICENSE.txt |  | 
|    5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt |  | 
|    6 The complete set of contributors may be found at http://polymer.github.io/CONTRI
     BUTORS.txt |  | 
|    7 Code distributed by Google as part of the polymer project is also |  | 
|    8 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
     TS.txt |  | 
|    9 --> |  | 
|   10  |  | 
|   11 <link rel="import" href="../polymer/polymer.html"> |  | 
|   12  |  | 
|   13 <script> |  | 
|   14  |  | 
|   15 /** |  | 
|   16 Polymer.IronFitBehavior fits an element in another element using `max-height` an
     d `max-width`, and |  | 
|   17 optionally centers it in the window or another element. |  | 
|   18  |  | 
|   19 The element will only be sized and/or positioned if it has not already been size
     d and/or positioned |  | 
|   20 by CSS. |  | 
|   21  |  | 
|   22 CSS properties               | Action |  | 
|   23 -----------------------------|------------------------------------------- |  | 
|   24 `position` set               | Element is not centered horizontally or verticall
     y |  | 
|   25 `top` or `bottom` set        | Element is not vertically centered |  | 
|   26 `left` or `right` set        | Element is not horizontally centered |  | 
|   27 `max-height` or `height` set | Element respects `max-height` or `height` |  | 
|   28 `max-width` or `width` set   | Element respects `max-width` or `width` |  | 
|   29  |  | 
|   30 @demo demo/index.html |  | 
|   31 @polymerBehavior |  | 
|   32 */ |  | 
|   33  |  | 
|   34   Polymer.IronFitBehavior = { |  | 
|   35  |  | 
|   36     properties: { |  | 
|   37  |  | 
|   38       /** |  | 
|   39        * The element that will receive a `max-height`/`width`. By default it is 
     the same as `this`, |  | 
|   40        * but it can be set to a child element. This is useful, for example, for 
     implementing a |  | 
|   41        * scrolling region inside the element. |  | 
|   42        * @type {!Element} |  | 
|   43        */ |  | 
|   44       sizingTarget: { |  | 
|   45         type: Object, |  | 
|   46         value: function() { |  | 
|   47           return this; |  | 
|   48         } |  | 
|   49       }, |  | 
|   50  |  | 
|   51       /** |  | 
|   52        * The element to fit `this` into. |  | 
|   53        */ |  | 
|   54       fitInto: { |  | 
|   55         type: Object, |  | 
|   56         value: window |  | 
|   57       }, |  | 
|   58  |  | 
|   59       /** |  | 
|   60        * Set to true to auto-fit on attach. |  | 
|   61        */ |  | 
|   62       autoFitOnAttach: { |  | 
|   63         type: Boolean, |  | 
|   64         value: false |  | 
|   65       }, |  | 
|   66  |  | 
|   67       /** @type {?Object} */ |  | 
|   68       _fitInfo: { |  | 
|   69         type: Object |  | 
|   70       } |  | 
|   71  |  | 
|   72     }, |  | 
|   73  |  | 
|   74     get _fitWidth() { |  | 
|   75       var fitWidth; |  | 
|   76       if (this.fitInto === window) { |  | 
|   77         fitWidth = this.fitInto.innerWidth; |  | 
|   78       } else { |  | 
|   79         fitWidth = this.fitInto.getBoundingClientRect().width; |  | 
|   80       } |  | 
|   81       return fitWidth; |  | 
|   82     }, |  | 
|   83  |  | 
|   84     get _fitHeight() { |  | 
|   85       var fitHeight; |  | 
|   86       if (this.fitInto === window) { |  | 
|   87         fitHeight = this.fitInto.innerHeight; |  | 
|   88       } else { |  | 
|   89         fitHeight = this.fitInto.getBoundingClientRect().height; |  | 
|   90       } |  | 
|   91       return fitHeight; |  | 
|   92     }, |  | 
|   93  |  | 
|   94     get _fitLeft() { |  | 
|   95       var fitLeft; |  | 
|   96       if (this.fitInto === window) { |  | 
|   97         fitLeft = 0; |  | 
|   98       } else { |  | 
|   99         fitLeft = this.fitInto.getBoundingClientRect().left; |  | 
|  100       } |  | 
|  101       return fitLeft; |  | 
|  102     }, |  | 
|  103  |  | 
|  104     get _fitTop() { |  | 
|  105       var fitTop; |  | 
|  106       if (this.fitInto === window) { |  | 
|  107         fitTop = 0; |  | 
|  108       } else { |  | 
|  109         fitTop = this.fitInto.getBoundingClientRect().top; |  | 
|  110       } |  | 
|  111       return fitTop; |  | 
|  112     }, |  | 
|  113  |  | 
|  114     attached: function() { |  | 
|  115       if (this.autoFitOnAttach) { |  | 
|  116         if (window.getComputedStyle(this).display === 'none') { |  | 
|  117           setTimeout(function() { |  | 
|  118             this.fit(); |  | 
|  119           }.bind(this)); |  | 
|  120         } else { |  | 
|  121           this.fit(); |  | 
|  122         } |  | 
|  123       } |  | 
|  124     }, |  | 
|  125  |  | 
|  126     /** |  | 
|  127      * Fits and optionally centers the element into the window, or `fitInfo` if 
     specified. |  | 
|  128      */ |  | 
|  129     fit: function() { |  | 
|  130       this._discoverInfo(); |  | 
|  131       this.constrain(); |  | 
|  132       this.center(); |  | 
|  133     }, |  | 
|  134  |  | 
|  135     /** |  | 
|  136      * Memoize information needed to position and size the target element. |  | 
|  137      */ |  | 
|  138     _discoverInfo: function() { |  | 
|  139       if (this._fitInfo) { |  | 
|  140         return; |  | 
|  141       } |  | 
|  142       var target = window.getComputedStyle(this); |  | 
|  143       var sizer = window.getComputedStyle(this.sizingTarget); |  | 
|  144       this._fitInfo = { |  | 
|  145         inlineStyle: { |  | 
|  146           top: this.style.top || '', |  | 
|  147           left: this.style.left || '' |  | 
|  148         }, |  | 
|  149         positionedBy: { |  | 
|  150           vertically: target.top !== 'auto' ? 'top' : (target.bottom !== 'auto' 
     ? |  | 
|  151             'bottom' : null), |  | 
|  152           horizontally: target.left !== 'auto' ? 'left' : (target.right !== 'aut
     o' ? |  | 
|  153             'right' : null), |  | 
|  154           css: target.position |  | 
|  155         }, |  | 
|  156         sizedBy: { |  | 
|  157           height: sizer.maxHeight !== 'none', |  | 
|  158           width: sizer.maxWidth !== 'none' |  | 
|  159         }, |  | 
|  160         margin: { |  | 
|  161           top: parseInt(target.marginTop, 10) || 0, |  | 
|  162           right: parseInt(target.marginRight, 10) || 0, |  | 
|  163           bottom: parseInt(target.marginBottom, 10) || 0, |  | 
|  164           left: parseInt(target.marginLeft, 10) || 0 |  | 
|  165         } |  | 
|  166       }; |  | 
|  167     }, |  | 
|  168  |  | 
|  169     /** |  | 
|  170      * Resets the target element's position and size constraints, and clear |  | 
|  171      * the memoized data. |  | 
|  172      */ |  | 
|  173     resetFit: function() { |  | 
|  174       if (!this._fitInfo || !this._fitInfo.sizedBy.height) { |  | 
|  175         this.sizingTarget.style.maxHeight = ''; |  | 
|  176         this.style.top = this._fitInfo ? this._fitInfo.inlineStyle.top : ''; |  | 
|  177       } |  | 
|  178       if (!this._fitInfo || !this._fitInfo.sizedBy.width) { |  | 
|  179         this.sizingTarget.style.maxWidth = ''; |  | 
|  180         this.style.left = this._fitInfo ? this._fitInfo.inlineStyle.left : ''; |  | 
|  181       } |  | 
|  182       if (this._fitInfo) { |  | 
|  183         this.style.position = this._fitInfo.positionedBy.css; |  | 
|  184       } |  | 
|  185       this._fitInfo = null; |  | 
|  186     }, |  | 
|  187  |  | 
|  188     /** |  | 
|  189      * Equivalent to calling `resetFit()` and `fit()`. Useful to call this after
      the element, |  | 
|  190      * the window, or the `fitInfo` element has been resized. |  | 
|  191      */ |  | 
|  192     refit: function() { |  | 
|  193       this.resetFit(); |  | 
|  194       this.fit(); |  | 
|  195     }, |  | 
|  196  |  | 
|  197     /** |  | 
|  198      * Constrains the size of the element to the window or `fitInfo` by setting 
     `max-height` |  | 
|  199      * and/or `max-width`. |  | 
|  200      */ |  | 
|  201     constrain: function() { |  | 
|  202       var info = this._fitInfo; |  | 
|  203       // position at (0px, 0px) if not already positioned, so we can measure the
      natural size. |  | 
|  204       if (!this._fitInfo.positionedBy.vertically) { |  | 
|  205         this.style.top = '0px'; |  | 
|  206       } |  | 
|  207       if (!this._fitInfo.positionedBy.horizontally) { |  | 
|  208         this.style.left = '0px'; |  | 
|  209       } |  | 
|  210       // need border-box for margin/padding |  | 
|  211       this.sizingTarget.style.boxSizing = 'border-box'; |  | 
|  212       // constrain the width and height if not already set |  | 
|  213       var rect = this.getBoundingClientRect(); |  | 
|  214       if (!info.sizedBy.height) { |  | 
|  215         this._sizeDimension(rect, info.positionedBy.vertically, 'top', 'bottom',
      'Height'); |  | 
|  216       } |  | 
|  217       if (!info.sizedBy.width) { |  | 
|  218         this._sizeDimension(rect, info.positionedBy.horizontally, 'left', 'right
     ', 'Width'); |  | 
|  219       } |  | 
|  220     }, |  | 
|  221  |  | 
|  222     _sizeDimension: function(rect, positionedBy, start, end, extent) { |  | 
|  223       var info = this._fitInfo; |  | 
|  224       var max = extent === 'Width' ? this._fitWidth : this._fitHeight; |  | 
|  225       var flip = (positionedBy === end); |  | 
|  226       var offset = flip ? max - rect[end] : rect[start]; |  | 
|  227       var margin = info.margin[flip ? start : end]; |  | 
|  228       var offsetExtent = 'offset' + extent; |  | 
|  229       var sizingOffset = this[offsetExtent] - this.sizingTarget[offsetExtent]; |  | 
|  230       this.sizingTarget.style['max' + extent] = (max - margin - offset - sizingO
     ffset) + 'px'; |  | 
|  231     }, |  | 
|  232  |  | 
|  233     /** |  | 
|  234      * Centers horizontally and vertically if not already positioned. This also 
     sets |  | 
|  235      * `position:fixed`. |  | 
|  236      */ |  | 
|  237     center: function() { |  | 
|  238       if (!this._fitInfo.positionedBy.vertically || !this._fitInfo.positionedBy.
     horizontally) { |  | 
|  239         // need position:fixed to center |  | 
|  240         this.style.position = 'fixed'; |  | 
|  241       } |  | 
|  242       if (!this._fitInfo.positionedBy.vertically) { |  | 
|  243         var top = (this._fitHeight - this.offsetHeight) / 2 + this._fitTop; |  | 
|  244         top -= this._fitInfo.margin.top; |  | 
|  245         this.style.top = top + 'px'; |  | 
|  246       } |  | 
|  247       if (!this._fitInfo.positionedBy.horizontally) { |  | 
|  248         var left = (this._fitWidth - this.offsetWidth) / 2 + this._fitLeft; |  | 
|  249         left -= this._fitInfo.margin.left; |  | 
|  250         this.style.left = left + 'px'; |  | 
|  251       } |  | 
|  252     } |  | 
|  253  |  | 
|  254   }; |  | 
|  255  |  | 
|  256 </script> |  | 
| OLD | NEW |