<!– @license Copyright © 2015 The Polymer Project Authors. All rights reserved. This code may only be used under the BSD style license found at polymer.github.io/LICENSE.txt The complete set of authors may be found at polymer.github.io/AUTHORS.txt The complete set of contributors may be found at polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as part of the polymer project is also subject to an additional IP rights grant found at polymer.github.io/PATENTS.txt –>

<link rel=“import” href=“../../polymer/polymer.html”> <link rel=“import” href=“../../iron-flex-layout/iron-flex-layout.html”> <link rel=“import” href=“../../iron-resizable-behavior/iron-resizable-behavior.html”> <link rel=“import” href=“../app-scroll-effects/app-scroll-effects-behavior.html”>

<!– app-box is a container element that can have scroll effects - visual effects based on scroll position. For example, the parallax effect can be used to move an image at a slower rate than the foreground.

“`html <app-box style=“height: 100px;” effects=“parallax-background”>

<img background src="picture.png" style="width: 100%; height: 600px;">

</app-box> “`

Notice the `background` attribute in the `img` element; this attribute specifies that that image is used as the background. By adding the background to the light dom, you can compose backgrounds that can change dynamically. Alternatively, the mixin `–app-box-background-front-layer` allows to style the background. For example:

“`css

.parallaxAppBox {
  --app-box-background-front-layer: {
    background-image: url(picture.png);
  };
}

“`

Finally, app-box can have content inside. For example:

“`html <app-box effects=“parallax-background”>

<h2>Sub title</h2>

</app-box> “`

#### Importing the effects

To use the scroll effects, you must explicitly import them in addition to `app-box`:

“`html <link rel=“import” href=“/bower_components/app-layout/app-scroll-effects/app-scroll-effects.html”> “`

#### List of effects

A simple parallax effect that vertically translates the backgrounds based on a fraction of the scroll position. For example:

“`css app-header {

--app-header-background-front-layer: {
  background-image: url(...);
};

} “` “`html <app-header style=“height: 300px;” effects=“parallax-background”>

<app-toolbar>App name</app-toolbar>

</app-header> “`

The fraction determines how far the background moves relative to the scroll position. This value can be assigned via the `scalar` config value and it is typically a value between 0 and 1 inclusive. If `scalar=0`, the background doesn't move away from the header.

## Styling

Mixin | Description | Default —————-|————-|———- `–app-box-background-front-layer` | Applies to the front layer of the background | {}

@group App Elements @element app-box @demo app-box/demo/document-scroll.html Document Scroll @demo app-box/demo/scrolling-region.html Scrolling Region –>

<dom-module id=“app-box”>

<template>
  <style>
    :host {
      position: relative;
      display: block;
    }

    #background {
      @apply(--layout-fit);
      overflow: hidden;
      height: 100%;
    }

    #backgroundFrontLayer {
      min-height: 100%;
      pointer-events: none;
      background-size: cover;
      @apply(--app-box-background-front-layer);
    }

    #contentContainer {
      position: relative;
      width: 100%;
      height: 100%;
    }

    :host([disabled]),
    :host([disabled]) #backgroundFrontLayer {
      transition: none !important;
    }
  </style>

  <div id="background">
    <div id="backgroundFrontLayer">
      <content select="[background]"></content>
    </div>
  </div>
  <div id="contentContainer">
    <content id="content"></content>
  </div>
</template>

<script>
  Polymer({
    is: 'app-box',

    behaviors: [
      Polymer.AppScrollEffectsBehavior,
      Polymer.IronResizableBehavior
    ],

    listeners: {
      'iron-resize': '_resizeHandler'
    },

    /**
     * The current scroll progress.
     *
     * @type {number}
     */
    _progress: 0,

    attached: function() {
      this.resetLayout();
    },

    /**
     * Resets the layout. This method is automatically called when the element is attached to the DOM.
     *
     * @method resetLayout
     */
    resetLayout: function() {
      this.debounce('_resetLayout', function() {
        // noop if the box isn't in the rendered tree
        if (this.offsetWidth === 0 && this.offsetHeight === 0) {
          return;
        }

        var scrollTop = this._clampedScrollTop;
        var savedDisabled = this.disabled;

        this.disabled = true;
        this._elementTop = this._getElementTop();
        this._elementHeight = this.offsetHeight;
        this._cachedScrollTargetHeight = this._scrollTargetHeight;
        this._setUpEffect();
        this._updateScrollState(scrollTop);
        this.disabled = savedDisabled;
      }, 1);
    },

    _getElementTop: function() {
      var currentNode = this;
      var top = 0;

      while (currentNode && currentNode !== this.scrollTarget) {
        top += currentNode.offsetTop;
        currentNode = currentNode.offsetParent;
      }
      return top;
    },

    _updateScrollState: function(scrollTop) {
      if (this.isOnScreen()) {
        var viewportTop = this._elementTop - scrollTop;
        this._progress = 1 - (viewportTop + this._elementHeight) / this._cachedScrollTargetHeight;
        this._runEffects(this._progress, scrollTop);
      }
    },

    /**
     * Returns true if this app-box is on the screen.
     * That is, visible in the current viewport.
     *
     * @method isOnScreen
     * @return {boolean}
     */
    isOnScreen: function() {
      return this._elementTop < this._scrollTop + this._cachedScrollTargetHeight
          && this._elementTop + this._elementHeight > this._scrollTop;
    },

    _resizeHandler: function() {
      this.resetLayout();
    },

    _getDOMRef: function(id) {
      if (id === 'background') {
        return this.$.background;
      }
      if (id === 'backgroundFrontLayer') {
        return this.$.backgroundFrontLayer;
      }
    },

    /**
     * Returns an object containing the progress value of the scroll effects.
     *
     * @method getScrollState
     * @return {Object}
     */
    getScrollState: function() {
      return { progress: this._progress };
    }
  });
</script>

</dom-module>