'use strict';

Liferay.Loader.define("frontend-taglib-clay$clay-collapse@2.24.1/lib/ClayCollapse", ['module', 'exports', 'require', 'frontend-js-metal-web$metal-state', 'frontend-taglib-clay$metal-anim', 'frontend-js-metal-web$metal-dom', 'frontend-js-metal-web$metal-events'], function (module, exports, require) {
	var define = undefined;
	var global = window;
	{
		Object.defineProperty(exports, "__esModule", {
			value: true
		});
		exports.ClayCollapse = undefined;

		var _createClass = function () {
			function defineProperties(target, props) {
				for (var i = 0; i < props.length; i++) {
					var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor);
				}
			}return function (Constructor, protoProps, staticProps) {
				if (protoProps) defineProperties(Constructor.prototype, protoProps);if (staticProps) defineProperties(Constructor, staticProps);return Constructor;
			};
		}();

		var _get = function get(object, property, receiver) {
			if (object === null) object = Function.prototype;var desc = Object.getOwnPropertyDescriptor(object, property);if (desc === undefined) {
				var parent = Object.getPrototypeOf(object);if (parent === null) {
					return undefined;
				} else {
					return get(parent, property, receiver);
				}
			} else if ("value" in desc) {
				return desc.value;
			} else {
				var getter = desc.get;if (getter === undefined) {
					return undefined;
				}return getter.call(receiver);
			}
		};

		var _metalState = require("frontend-js-metal-web$metal-state");

		var _metalState2 = _interopRequireDefault(_metalState);

		var _metalAnim = require("frontend-taglib-clay$metal-anim");

		var _metalAnim2 = _interopRequireDefault(_metalAnim);

		var _metalDom = require("frontend-js-metal-web$metal-dom");

		var _metalDom2 = _interopRequireDefault(_metalDom);

		var _metalEvents = require("frontend-js-metal-web$metal-events");

		function _interopRequireDefault(obj) {
			return obj && obj.__esModule ? obj : { default: obj };
		}

		function _classCallCheck(instance, Constructor) {
			if (!(instance instanceof Constructor)) {
				throw new TypeError("Cannot call a class as a function");
			}
		}

		function _possibleConstructorReturn(self, call) {
			if (!self) {
				throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
			}return call && (typeof call === "object" || typeof call === "function") ? call : self;
		}

		function _inherits(subClass, superClass) {
			if (typeof superClass !== "function" && superClass !== null) {
				throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
			}subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } });if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
		}

		var KEY_CODE_ENTER = 13;
		var KEY_CODE_SPACE = 32;

		/**
   * Collapse Metal Clay component.
   * @extends State
   */

		var ClayCollapse = function (_State) {
			_inherits(ClayCollapse, _State);

			/**
    * @inheritDoc
    */
			function ClayCollapse(config) {
				_classCallCheck(this, ClayCollapse);

				var _this = _possibleConstructorReturn(this, (ClayCollapse.__proto__ || Object.getPrototypeOf(ClayCollapse)).call(this, config));

				_this._eventHandler = new _metalEvents.EventHandler();

				var transitionEnd = _this._getTransitionEndEvent();

				_this.supportsTransitionEnd = transitionEnd !== false;
				_this.transitionEnd = transitionEnd || 'transitionend';

				_this.on('headersChanged', _this._handleHeadersChanged);
				_this._syncHeaderListeners();

				_this.on('collapsedChanged', _this._handleCollapsedChanged);

				if (_this.content) {
					_this.collapsed ? _this._close() : _this._open();
				}
				return _this;
			}

			/**
    * @inheritDoc
    */

			_createClass(ClayCollapse, [{
				key: 'disposeInternal',
				value: function disposeInternal() {
					_get(ClayCollapse.prototype.__proto__ || Object.getPrototypeOf(ClayCollapse.prototype), 'disposeInternal', this).call(this);
					this._eventHandler.removeAllListeners();
				}

				/**
     * Animates close when `collapsed` is true
     * @protected
     */

			}, {
				key: '_animateClose',
				value: function _animateClose() {
					var content = this.content,
					    openClasses = this.openClasses,
					    transitionClasses = this.transitionClasses;

					content.transitionType = 0;

					this._updateContentHeight();

					_metalDom2.default.addClasses(content, transitionClasses);
					_metalDom2.default.removeClasses(content, openClasses);

					content.offsetHeight;
					content.style.removeProperty('height');

					this._shimUnsupportedTransition(content);
				}

				/**
     * Animates open when `collapsed` is false
     * @protected
     */

			}, {
				key: '_animateOpen',
				value: function _animateOpen() {
					var closedClasses = this.closedClasses,
					    content = this.content,
					    transitionClasses = this.transitionClasses;

					content.transitionType = 1;

					_metalDom2.default.removeClasses(content, closedClasses);
					_metalDom2.default.addClasses(content, transitionClasses);

					this._updateContentHeight();

					this._shimUnsupportedTransition(content);
				}

				/**
     * Attaches click and keydown listeners to header.
     * @param {!Element|!string} header
     * @protected
     */

			}, {
				key: '_attachHeaderListeners',
				value: function _attachHeaderListeners(header) {
					this._eventHandler.add(_metalDom2.default.on(header, 'click', this._handleClick.bind(this)), _metalDom2.default.on(header, 'keydown', this._handleKeydown.bind(this)));
				}

				/**
     * Adds CSS classes and properties to the `content` and `headers` elements when
     * `collapsed` is true
     * @protected
     */

			}, {
				key: '_close',
				value: function _close() {
					var closedClasses = this.closedClasses,
					    content = this.content,
					    headers = this.headers,
					    openClasses = this.openClasses,
					    transitionClasses = this.transitionClasses;

					_metalDom2.default.removeClasses(content, openClasses + ' ' + transitionClasses);
					_metalDom2.default.addClasses(content, closedClasses);
					content.setAttribute('aria-expanded', false);
					content.style.removeProperty('height');

					if (Array.isArray(headers)) {
						headers.forEach(function (header) {
							_metalDom2.default.addClasses(header, 'collapsed');
							(0, _metalDom.toElement)(header).setAttribute('aria-expanded', false);
						});
					} else {
						_metalDom2.default.addClasses(headers, 'collapsed');
						(0, _metalDom.toElement)(headers).setAttribute('aria-expanded', false);
					}
				}

				/**
     * Checks to see if browser supports CSS3 Transitions and returns the name
     * of the transitionend event; returns false if it's not supported
     * @protected
     * @return {string|boolean} The name of the transitionend event or false
     * if not supported
     */

			}, {
				key: '_getTransitionEndEvent',
				value: function _getTransitionEndEvent() {
					var el = document.createElement('metalClayTransitionEnd');

					var transitionEndEvents = {
						transition: 'transitionend',
						WebkitTransition: 'webkitTransitionEnd',
						MozTransition: 'transitionend',
						OTransition: 'oTransitionEnd otransitionend'
					};

					for (var name in transitionEndEvents) {
						if (el.style[name] !== undefined) {
							return transitionEndEvents[name];
						}
					}

					return false;
				}

				/**
     * Handles a `click` event on the headers.
     * @protected
     */

			}, {
				key: '_handleClick',
				value: function _handleClick() {
					this.toggle();
				}

				/**
     * Syncs the `content` element according to the value of the `collapsed`
     * state, attaching and removing css properties and classes needed to open
     * and close the element.
     */

			}, {
				key: '_handleCollapsedChanged',
				value: function _handleCollapsedChanged() {
					this.collapsed ? this._animateClose() : this._animateOpen();
				}

				/**
     * Handles `changed` event of `headers` and attaches listeners.
     */

			}, {
				key: '_handleHeadersChanged',
				value: function _handleHeadersChanged() {
					this._syncHeaderListeners();
				}

				/**
     * Handles a `keydown` event on the headers.
     * @param {!Event} event
     * @protected
     */

			}, {
				key: '_handleKeydown',
				value: function _handleKeydown(event) {
					// eslint-disable-next-line
					if (event.keyCode === KEY_CODE_ENTER || event.keyCode === KEY_CODE_SPACE) {
						this.toggle();
						event.preventDefault();
					}
				}

				/**
     * Handles the `transitionend` event on the content.
     * @protected
     */

			}, {
				key: '_handleTransitionEnd',
				value: function _handleTransitionEnd() {
					this.content.transitionType ? this._open() : this._close();
				}

				/**
     * Adds CSS classes and properties to the `content` and `headers` elements when
     * `collapsed` is false
     * @protected
     */

			}, {
				key: '_open',
				value: function _open() {
					var content = this.content,
					    headers = this.headers,
					    openClasses = this.openClasses,
					    transitionClasses = this.transitionClasses;

					_metalDom2.default.addClasses(content, openClasses);
					_metalDom2.default.removeClasses(content, transitionClasses);
					content.setAttribute('aria-expanded', true);
					content.style.removeProperty('height');

					if (Array.isArray(headers)) {
						headers.forEach(function (header) {
							_metalDom2.default.removeClasses(header, 'collapsed');
							(0, _metalDom.toElement)(header).setAttribute('aria-expanded', true);
						});
					} else {
						_metalDom2.default.removeClasses(headers, 'collapsed');
						(0, _metalDom.toElement)(headers).setAttribute('aria-expanded', true);
					}
				}

				/**
     * Fires a synthetic `transitionend` event for browsers that don't support
     * CSS3 transitions
     * @param {!Element} element
     * @protected
     */

			}, {
				key: '_shimUnsupportedTransition',
				value: function _shimUnsupportedTransition(element) {
					if (!this.supportsTransitionEnd) {
						_metalAnim2.default.emulateTransitionEnd(element);
					}
				}

				/**
     * Syncs the component according to the value of the `headers` state,
     * attaching events to the new element and detaching from any previous one.
     * @protected
     */

			}, {
				key: '_syncHeaderListeners',
				value: function _syncHeaderListeners() {
					var _this2 = this;

					var headers = this.headers;

					this._eventHandler.removeAllListeners();

					if (Array.isArray(headers)) {
						headers.forEach(function (header) {
							_this2._attachHeaderListeners(header);
						});
					} else {
						this._attachHeaderListeners(headers);
					}
				}

				/**
     * Toggles the content's visibility.
     * @public
     */

			}, {
				key: 'toggle',
				value: function toggle() {
					var collapsed = this.collapsed,
					    content = this.content,
					    transitionEnd = this.transitionEnd;

					_metalDom2.default.once(content, transitionEnd, this._handleTransitionEnd.bind(this));

					this.collapsed = !collapsed;
				}

				/**
     * Calculates what the content height should be and sets it.
     * @protected
     */

			}, {
				key: '_updateContentHeight',
				value: function _updateContentHeight() {
					var content = this.content;

					content.setAttribute('style', 'height: ' + content.firstElementChild.offsetHeight + 'px;');
				}
			}]);

			return ClayCollapse;
		}(_metalState2.default);

		/**
   * State definition.
   * @static
   * @type {!Object}
   */

		ClayCollapse.STATE = {
			/**
    * The CSS class added to `content` when it's collapsed.
    * @type {!string}
    */
			closedClasses: {
				validator: _metalState.validators.string,
				value: 'collapse'
			},

			/**
    * The open or closed state of the `content` element, false and true
    * respectively.
    * @type {boolean}
    */
			collapsed: {
				validator: _metalState.validators.bool,
				value: true
			},

			/**
    * The element or selector that should collapse.
    * @type {!(string|Element)}
    */
			content: {
				setter: _metalDom2.default.toElement,
				validator: _metalState.validators.oneOfType([_metalState.validators.string, _metalState.validators.object])
			},

			/**
    * The element that should trigger the toggling. If you pass in a
    * core.isElement value you will lose reference to the element once it is
    * removed from the dom. If you pass in a selector it will delegate it on
    * the document across all headers matching that selector.
    * @type {!(string|Array<string>|Element)}
    */
			headers: {
				validator: _metalState.validators.oneOfType([_metalState.validators.string, _metalState.validators.array, _metalState.validators.object])
			},

			/**
    * The CSS class added to `content` when it's open.
    * @type {!string}
    */
			openClasses: {
				validator: _metalState.validators.string,
				value: 'collapse show'
			},

			/**
    * The CSS class added to `content` when it's transitioning.
    * @type {!string}
    */
			transitionClasses: {
				validator: _metalState.validators.string,
				value: 'collapsing'
			}
		};

		exports.ClayCollapse = ClayCollapse;
		exports.default = ClayCollapse;
		//# sourceMappingURL=ClayCollapse.js.map
	}
});
//# sourceMappingURL=ClayCollapse.js.map