303 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			HTML
		
	
	
	
			
		
		
	
	
			303 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			HTML
		
	
	
	
<!--
 | 
						|
@license
 | 
						|
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
 | 
						|
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
 | 
						|
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
 | 
						|
The complete set of contributors may be found at http://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 http://polymer.github.io/PATENTS.txt
 | 
						|
-->
 | 
						|
 | 
						|
<link rel="import" href="../polymer/polymer.html">
 | 
						|
<link rel="import" href="../iron-resizable-behavior/iron-resizable-behavior.html">
 | 
						|
 | 
						|
<!--
 | 
						|
`iron-collapse` creates a collapsible block of content.  By default, the content
 | 
						|
will be collapsed.  Use `opened` or `toggle()` to show/hide the content.
 | 
						|
 | 
						|
    <button on-click="toggle">toggle collapse</button>
 | 
						|
 | 
						|
    <iron-collapse id="collapse">
 | 
						|
      <div>Content goes here...</div>
 | 
						|
    </iron-collapse>
 | 
						|
 | 
						|
    ...
 | 
						|
 | 
						|
    toggle: function() {
 | 
						|
      this.$.collapse.toggle();
 | 
						|
    }
 | 
						|
 | 
						|
`iron-collapse` adjusts the max-height/max-width of the collapsible element to show/hide
 | 
						|
the content.  So avoid putting padding/margin/border on the collapsible directly,
 | 
						|
and instead put a div inside and style that.
 | 
						|
 | 
						|
    <style>
 | 
						|
      .collapse-content {
 | 
						|
        padding: 15px;
 | 
						|
        border: 1px solid #dedede;
 | 
						|
      }
 | 
						|
    </style>
 | 
						|
 | 
						|
    <iron-collapse>
 | 
						|
      <div class="collapse-content">
 | 
						|
        <div>Content goes here...</div>
 | 
						|
      </div>
 | 
						|
    </iron-collapse>
 | 
						|
 | 
						|
### Styling
 | 
						|
 | 
						|
The following custom properties and mixins are available for styling:
 | 
						|
 | 
						|
Custom property | Description | Default
 | 
						|
----------------|-------------|----------
 | 
						|
`--iron-collapse-transition-duration` | Animation transition duration | `300ms`
 | 
						|
 | 
						|
@group Iron Elements
 | 
						|
@hero hero.svg
 | 
						|
@demo demo/index.html
 | 
						|
@element iron-collapse
 | 
						|
-->
 | 
						|
 | 
						|
<dom-module id="iron-collapse">
 | 
						|
 | 
						|
  <template>
 | 
						|
 | 
						|
    <style>
 | 
						|
      :host {
 | 
						|
        display: block;
 | 
						|
        transition-duration: var(--iron-collapse-transition-duration, 300ms);
 | 
						|
        overflow: visible;
 | 
						|
      }
 | 
						|
 | 
						|
      :host(.iron-collapse-closed) {
 | 
						|
        display: none;
 | 
						|
      }
 | 
						|
 | 
						|
      :host(:not(.iron-collapse-opened)) {
 | 
						|
        overflow: hidden;
 | 
						|
      }
 | 
						|
    </style>
 | 
						|
 | 
						|
    <content></content>
 | 
						|
 | 
						|
  </template>
 | 
						|
 | 
						|
</dom-module>
 | 
						|
 | 
						|
<script>
 | 
						|
 | 
						|
  Polymer({
 | 
						|
 | 
						|
    is: 'iron-collapse',
 | 
						|
 | 
						|
    behaviors: [
 | 
						|
      Polymer.IronResizableBehavior
 | 
						|
    ],
 | 
						|
 | 
						|
    properties: {
 | 
						|
 | 
						|
      /**
 | 
						|
       * If true, the orientation is horizontal; otherwise is vertical.
 | 
						|
       *
 | 
						|
       * @attribute horizontal
 | 
						|
       */
 | 
						|
      horizontal: {
 | 
						|
        type: Boolean,
 | 
						|
        value: false,
 | 
						|
        observer: '_horizontalChanged'
 | 
						|
      },
 | 
						|
 | 
						|
      /**
 | 
						|
       * Set opened to true to show the collapse element and to false to hide it.
 | 
						|
       *
 | 
						|
       * @attribute opened
 | 
						|
       */
 | 
						|
      opened: {
 | 
						|
        type: Boolean,
 | 
						|
        value: false,
 | 
						|
        notify: true,
 | 
						|
        observer: '_openedChanged'
 | 
						|
      },
 | 
						|
 | 
						|
      /**
 | 
						|
       * When true, the element is transitioning its opened state. When false,
 | 
						|
       * the element has finished opening/closing.
 | 
						|
       *
 | 
						|
       * @attribute transitioning
 | 
						|
       */
 | 
						|
      transitioning: {
 | 
						|
        type: Boolean,
 | 
						|
        notify: true,
 | 
						|
        readOnly: true
 | 
						|
      },
 | 
						|
 | 
						|
      /**
 | 
						|
       * Set noAnimation to true to disable animations.
 | 
						|
       *
 | 
						|
       * @attribute noAnimation
 | 
						|
       */
 | 
						|
      noAnimation: {
 | 
						|
        type: Boolean
 | 
						|
      },
 | 
						|
 | 
						|
      /**
 | 
						|
       * Stores the desired size of the collapse body.
 | 
						|
       * @private
 | 
						|
       */
 | 
						|
      _desiredSize: {
 | 
						|
        type: String,
 | 
						|
        value: ''
 | 
						|
      }
 | 
						|
    },
 | 
						|
 | 
						|
    get dimension() {
 | 
						|
      return this.horizontal ? 'width' : 'height';
 | 
						|
    },
 | 
						|
 | 
						|
    /**
 | 
						|
     * `maxWidth` or `maxHeight`.
 | 
						|
     * @private
 | 
						|
     */
 | 
						|
    get _dimensionMax() {
 | 
						|
      return this.horizontal ? 'maxWidth' : 'maxHeight';
 | 
						|
    },
 | 
						|
 | 
						|
    /**
 | 
						|
     * `max-width` or `max-height`.
 | 
						|
     * @private
 | 
						|
     */
 | 
						|
    get _dimensionMaxCss() {
 | 
						|
      return this.horizontal ? 'max-width' : 'max-height';
 | 
						|
    },
 | 
						|
 | 
						|
    hostAttributes: {
 | 
						|
      role: 'group',
 | 
						|
      'aria-hidden': 'true',
 | 
						|
      'aria-expanded': 'false'
 | 
						|
    },
 | 
						|
 | 
						|
    listeners: {
 | 
						|
      transitionend: '_onTransitionEnd'
 | 
						|
    },
 | 
						|
 | 
						|
    /**
 | 
						|
     * Toggle the opened state.
 | 
						|
     *
 | 
						|
     * @method toggle
 | 
						|
     */
 | 
						|
    toggle: function() {
 | 
						|
      this.opened = !this.opened;
 | 
						|
    },
 | 
						|
 | 
						|
    show: function() {
 | 
						|
      this.opened = true;
 | 
						|
    },
 | 
						|
 | 
						|
    hide: function() {
 | 
						|
      this.opened = false;
 | 
						|
    },
 | 
						|
 | 
						|
    /**
 | 
						|
     * Updates the size of the element.
 | 
						|
     * @param {string} size The new value for `maxWidth`/`maxHeight` as css property value, usually `auto` or `0px`.
 | 
						|
     * @param {boolean=} animated if `true` updates the size with an animation, otherwise without.
 | 
						|
     */
 | 
						|
    updateSize: function(size, animated) {
 | 
						|
      // Consider 'auto' as '', to take full size.
 | 
						|
      size = size === 'auto' ? '' : size;
 | 
						|
 | 
						|
      var willAnimate = animated && !this.noAnimation &&
 | 
						|
                        this.isAttached && this._desiredSize !== size;
 | 
						|
 | 
						|
      this._desiredSize = size;
 | 
						|
 | 
						|
      this._updateTransition(false);
 | 
						|
      // If we can animate, must do some prep work.
 | 
						|
      if (willAnimate) {
 | 
						|
        // Animation will start at the current size.
 | 
						|
        var startSize = this._calcSize();
 | 
						|
        // For `auto` we must calculate what is the final size for the animation.
 | 
						|
        // After the transition is done, _transitionEnd will set the size back to `auto`.
 | 
						|
        if (size === '') {
 | 
						|
          this.style[this._dimensionMax] = '';
 | 
						|
          size = this._calcSize();
 | 
						|
        }
 | 
						|
        // Go to startSize without animation.
 | 
						|
        this.style[this._dimensionMax] = startSize;
 | 
						|
        // Force layout to ensure transition will go. Set scrollTop to itself
 | 
						|
        // so that compilers won't remove it.
 | 
						|
        this.scrollTop = this.scrollTop;
 | 
						|
        // Enable animation.
 | 
						|
        this._updateTransition(true);
 | 
						|
        // If final size is the same as startSize it will not animate.
 | 
						|
        willAnimate = (size !== startSize);
 | 
						|
      }
 | 
						|
      // Set the final size.
 | 
						|
      this.style[this._dimensionMax] = size;
 | 
						|
      // If it won't animate, call transitionEnd to set correct classes.
 | 
						|
      if (!willAnimate) {
 | 
						|
        this._transitionEnd();
 | 
						|
      }
 | 
						|
    },
 | 
						|
 | 
						|
    /**
 | 
						|
     * enableTransition() is deprecated, but left over so it doesn't break existing code.
 | 
						|
     * Please use `noAnimation` property instead.
 | 
						|
     *
 | 
						|
     * @method enableTransition
 | 
						|
     * @deprecated since version 1.0.4
 | 
						|
     */
 | 
						|
    enableTransition: function(enabled) {
 | 
						|
      Polymer.Base._warn('`enableTransition()` is deprecated, use `noAnimation` instead.');
 | 
						|
      this.noAnimation = !enabled;
 | 
						|
    },
 | 
						|
 | 
						|
    _updateTransition: function(enabled) {
 | 
						|
      this.style.transitionDuration = (enabled && !this.noAnimation) ? '' : '0s';
 | 
						|
    },
 | 
						|
 | 
						|
    _horizontalChanged: function() {
 | 
						|
      this.style.transitionProperty = this._dimensionMaxCss;
 | 
						|
      var otherDimension = this._dimensionMax === 'maxWidth' ? 'maxHeight' : 'maxWidth';
 | 
						|
      this.style[otherDimension] = '';
 | 
						|
      this.updateSize(this.opened ? 'auto' : '0px', false);
 | 
						|
    },
 | 
						|
 | 
						|
    _openedChanged: function() {
 | 
						|
      this.setAttribute('aria-expanded', this.opened);
 | 
						|
      this.setAttribute('aria-hidden', !this.opened);
 | 
						|
 | 
						|
      this._setTransitioning(true);
 | 
						|
      this.toggleClass('iron-collapse-closed', false);
 | 
						|
      this.toggleClass('iron-collapse-opened', false);
 | 
						|
      this.updateSize(this.opened ? 'auto' : '0px', true);
 | 
						|
 | 
						|
      // Focus the current collapse.
 | 
						|
      if (this.opened) {
 | 
						|
        this.focus();
 | 
						|
      }
 | 
						|
    },
 | 
						|
 | 
						|
    _transitionEnd: function() {
 | 
						|
      this.style[this._dimensionMax] = this._desiredSize;
 | 
						|
      this.toggleClass('iron-collapse-closed', !this.opened);
 | 
						|
      this.toggleClass('iron-collapse-opened', this.opened);
 | 
						|
      this._updateTransition(false);
 | 
						|
      this.notifyResize();
 | 
						|
      this._setTransitioning(false);
 | 
						|
    },
 | 
						|
 | 
						|
    _onTransitionEnd: function(event) {
 | 
						|
      if (Polymer.dom(event).rootTarget === this) {
 | 
						|
        this._transitionEnd();
 | 
						|
      }
 | 
						|
    },
 | 
						|
 | 
						|
    _calcSize: function() {
 | 
						|
      return this.getBoundingClientRect()[this.dimension] + 'px';
 | 
						|
    }
 | 
						|
 | 
						|
  });
 | 
						|
 | 
						|
</script>
 |