<!– @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”>

<!– app-header-layout is a wrapper element that positions an app-header and other content. This element uses the document scroll by default, but it can also define its own scrolling region.

Using the document scroll:

“`html <app-header-layout>

<app-header fixed condenses effects="waterfall">
  <app-toolbar>
    <div main-title>App name</div>
  </app-toolbar>
</app-header>
<div>
  main content
</div>

</app-header-layout> “`

Using an own scrolling region:

“`html <app-header-layout has-scrolling-region style=“width: 300px; height: 400px;”>

<app-header fixed condenses effects="waterfall">
  <app-toolbar>
    <div main-title>App name</div>
  </app-toolbar>
</app-header>
<div>
  main content
</div>

</app-header-layout> “`

Add the `fullbleed` attribute to app-header-layout to make it fit the size of its container:

“`html <app-header-layout fullbleed>

...

</app-header-layout> “`

@group App Elements @element app-header-layout @demo app-header-layout/demo/simple.html Simple Demo @demo app-header-layout/demo/scrolling-region.html Scrolling Region @demo app-header-layout/demo/music.html Music Demo @demo app-header-layout/demo/footer.html Footer Demo –>

<dom-module id=“app-header-layout”>

<template>
  <style>
    :host {
      display: block;
      /**
       * Force app-header-layout to have its own stacking context so that its parent can
       * control the stacking of it relative to other elements (e.g. app-drawer-layout).
       * This could be done using `isolation: isolate`, but that's not well supported
       * across browsers.
       */
      position: relative;
      z-index: 0;
    }

    :host > ::content > app-header {
      @apply(--layout-fixed-top);
      z-index: 1;
    }

    :host([has-scrolling-region]) {
      height: 100%;
    }

    :host([has-scrolling-region]) > ::content > app-header {
      position: absolute;
    }

    :host([has-scrolling-region]) > #contentContainer {
      @apply(--layout-fit);
      overflow-y: auto;
      -webkit-overflow-scrolling: touch;
    }

    :host([fullbleed]) {
      @apply(--layout-vertical);
      @apply(--layout-fit);
    }

    :host([fullbleed]) > #contentContainer {
      @apply(--layout-vertical);
      @apply(--layout-flex);
    }

    #contentContainer {
      /* Create a stacking context here so that all children appear below the header. */
      position: relative;
      z-index: 0;
    }

  </style>

  <content id="header" select="app-header"></content>

  <div id="contentContainer">
    <content></content>
  </div>

</template>

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

    behaviors: [
      Polymer.IronResizableBehavior
    ],

    properties: {
      /**
       * If true, the current element will have its own scrolling region.
       * Otherwise, it will use the document scroll to control the header.
       */
      hasScrollingRegion: {
        type: Boolean,
        value: false,
        reflectToAttribute: true
      }
    },

    listeners: {
      'iron-resize': '_resizeHandler',
      'app-header-reset-layout': '_resetLayoutHandler'
    },

    observers: [
      'resetLayout(isAttached, hasScrollingRegion)'
    ],

    /**
     * A reference to the app-header element.
     *
     * @property header
     */
    get header() {
      return Polymer.dom(this.$.header).getDistributedNodes()[0];
    },

    /**
     * Resets the layout. This method is automatically called when the element is attached
     * to the DOM.
     *
     * @method resetLayout
     */
    resetLayout: function() {
      this._updateScroller();
      this.debounce('_resetLayout', this._updateContentPosition);
    },

    _updateContentPosition: function() {
      var header = this.header;
      if (!this.isAttached || !header) {
        return;
      }
      // Get header height here so that style reads are batched together before style writes
      // (i.e. getBoundingClientRect() below).
      var headerHeight = header.offsetHeight;
      // Update the header position.
      if (!this.hasScrollingRegion) {
        var rect = this.getBoundingClientRect();
        var rightOffset = document.documentElement.clientWidth - rect.right;
        header.style.left = rect.left + 'px';
        header.style.right = rightOffset + 'px';
      } else {
        header.style.left = '';
        header.style.right = '';
      }
      // Update the content container position.
      var containerStyle = this.$.contentContainer.style;
      if (header.fixed && !header.willCondense() && this.hasScrollingRegion) {
        // If the header size does not change and we're using a scrolling region, exclude
        // the header area from the scrolling region so that the header doesn't overlap
        // the scrollbar.
        containerStyle.marginTop = headerHeight + 'px';
        containerStyle.paddingTop = '';
      } else {
        containerStyle.paddingTop = headerHeight + 'px';
        containerStyle.marginTop = '';
      }
    },

    _updateScroller: function() {
      if (!this.isAttached) {
        return;
      }
      var header = this.header;
      if (header) {
        header.scrollTarget = this.hasScrollingRegion ?
            this.$.contentContainer : this.ownerDocument.documentElement;
      }
    },

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

    _resetLayoutHandler: function(e) {
      this.resetLayout();
      e.stopPropagation();
    }

  });
</script>

</dom-module>