UNPKG

16.9 kBJavaScriptView Raw
1/*!
2 * Accordion v2.0.0-alpha.1 (https://github.com/quark-dev/Phonon-Framework)
3 * Copyright 2015-2019 qathom
4 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
5 */
6'use strict';
7
8function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
9
10var Util = _interopDefault(require('../util.js'));
11
12/*! *****************************************************************************
13Copyright (c) Microsoft Corporation. All rights reserved.
14Licensed under the Apache License, Version 2.0 (the "License"); you may not use
15this file except in compliance with the License. You may obtain a copy of the
16License at http://www.apache.org/licenses/LICENSE-2.0
17
18THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
20WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
21MERCHANTABLITY OR NON-INFRINGEMENT.
22
23See the Apache Version 2.0 License for specific language governing permissions
24and limitations under the License.
25***************************************************************************** */
26/* global Reflect, Promise */
27
28var extendStatics = function(d, b) {
29 extendStatics = Object.setPrototypeOf ||
30 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
31 function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
32 return extendStatics(d, b);
33};
34
35function __extends(d, b) {
36 extendStatics(d, b);
37 function __() { this.constructor = d; }
38 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
39}
40
41var Component = (function () {
42 function Component(name, defaultProps, props) {
43 var _this = this;
44 this.template = '';
45 this.id = null;
46 this.eventHandlers = [];
47 this.registeredElements = [];
48 this.name = name;
49 var element = typeof props.element === 'string'
50 ? document.querySelector(props.element) : props.element;
51 var config = {};
52 if (element) {
53 var dataConfig = Util.Selector.attrConfig(element);
54 if (dataConfig) {
55 config = dataConfig;
56 }
57 }
58 this.defaultProps = defaultProps;
59 this.props = Object.assign(defaultProps, config, props, { element: element });
60 this.id = this.uid();
61 this.elementListener = function (event) { return _this.onBeforeElementEvent(event); };
62 this.setEventsHandler();
63 }
64 Component.prototype.setTemplate = function (template) {
65 this.template = template;
66 };
67 Component.prototype.getTemplate = function () {
68 return this.template;
69 };
70 Component.prototype.getElement = function () {
71 return this.getProp('element') || null;
72 };
73 Component.prototype.setElement = function (element) {
74 this.props.element = element;
75 };
76 Component.prototype.getId = function () {
77 return this.id;
78 };
79 Component.prototype.uid = function () {
80 return Math.random().toString(36).substr(2, 10);
81 };
82 Component.prototype.getName = function () {
83 return this.name;
84 };
85 Component.prototype.getProps = function () {
86 return this.props;
87 };
88 Component.prototype.getProp = function (name) {
89 var defaultValue = this.defaultProps[name];
90 return typeof this.props[name] !== 'undefined' ? this.props[name] : defaultValue;
91 };
92 Component.prototype.setProps = function (props) {
93 var componentProps = Object.assign({}, props);
94 this.props = Object.assign(this.props, componentProps);
95 };
96 Component.prototype.setProp = function (name, value) {
97 if (typeof this.props[name] === 'undefined') {
98 throw new Error('Cannot set an invalid prop');
99 }
100 this.props[name] = value;
101 };
102 Component.prototype.registerElements = function (elements) {
103 var _this = this;
104 elements.forEach(function (element) { return _this.registerElement(element); });
105 };
106 Component.prototype.registerElement = function (element) {
107 element.target.addEventListener(element.event, this.elementListener);
108 this.registeredElements.push(element);
109 };
110 Component.prototype.unregisterElements = function () {
111 var _this = this;
112 this.registeredElements.forEach(function (element) {
113 _this.unregisterElement(element);
114 });
115 };
116 Component.prototype.unregisterElement = function (element) {
117 var registeredElementIndex = this.registeredElements
118 .findIndex(function (el) { return el.target === element.target && el.event === element.event; });
119 if (registeredElementIndex > -1) {
120 element.target.removeEventListener(element.event, this.elementListener);
121 this.registeredElements.splice(registeredElementIndex, 1);
122 }
123 else {
124 console.error('Warning! Could not remove element:'
125 + ' ' + (element.target + " with event: " + element.event + "."));
126 }
127 };
128 Component.prototype.triggerEvent = function (eventName, detail, objectEventOnly) {
129 var _this = this;
130 if (detail === void 0) { detail = {}; }
131 if (objectEventOnly === void 0) { objectEventOnly = false; }
132 var eventNameObject = eventName.split('.').reduce(function (acc, current, index) {
133 if (index === 0) {
134 return current;
135 }
136 return acc + current.charAt(0).toUpperCase() + current.slice(1);
137 });
138 var eventNameAlias = "on" + eventNameObject
139 .charAt(0).toUpperCase() + eventNameObject.slice(1);
140 var props = this.getProps();
141 this.eventHandlers.forEach(function (scope) {
142 if (typeof scope[eventNameObject] === 'function') {
143 scope[eventNameObject].apply(_this, [detail]);
144 }
145 if (typeof scope[eventNameAlias] === 'function') {
146 props[eventNameAlias].apply(_this, [detail]);
147 }
148 });
149 if (objectEventOnly) {
150 return;
151 }
152 var element = this.getElement();
153 if (element) {
154 Util.Dispatch.elementEvent(element, eventName, this.name, detail);
155 }
156 else {
157 Util.Dispatch.winDocEvent(eventName, this.name, detail);
158 }
159 };
160 Component.prototype.preventClosable = function () {
161 return false;
162 };
163 Component.prototype.destroy = function () {
164 this.unregisterElements();
165 };
166 Component.prototype.onElementEvent = function (event) {
167 };
168 Component.prototype.setEventsHandler = function () {
169 var props = this.getProps();
170 var scope = Object.keys(props).reduce(function (cur, key) {
171 if (typeof props[key] === 'function') {
172 cur[key] = props[key];
173 }
174 return cur;
175 }, {});
176 if (Object.keys(scope).length > 0) {
177 this.eventHandlers.push(scope);
178 }
179 };
180 Component.prototype.onBeforeElementEvent = function (event) {
181 if (this.preventClosable()) {
182 return;
183 }
184 this.onElementEvent(event);
185 };
186 return Component;
187}());
188
189var Collapse = (function (_super) {
190 __extends(Collapse, _super);
191 function Collapse(props) {
192 if (props === void 0) { props = { toggle: false }; }
193 var _this = _super.call(this, 'collapse', { toggle: false }, props) || this;
194 var toggle = _this.getProp('toggle');
195 if (toggle) {
196 _this.toggle();
197 }
198 return _this;
199 }
200 Collapse.attachDOM = function () {
201 var className = 'collapse';
202 Util.Observer.subscribe({
203 componentClass: className,
204 onAdded: function (element, create) {
205 create(new Collapse({ element: element }));
206 },
207 onRemoved: function (element, remove) {
208 remove('Collapse', element);
209 },
210 });
211 document.addEventListener(Util.Event.CLICK, function (event) {
212 if (!event.target) {
213 return;
214 }
215 var target = Util.Selector.closest(event.target, '[data-toggle]');
216 if (!target) {
217 return;
218 }
219 var dataToggleAttr = target.getAttribute('data-toggle');
220 if (dataToggleAttr && dataToggleAttr === className) {
221 var id = target.getAttribute('data-target') || target.getAttribute('href');
222 if (!id) {
223 return;
224 }
225 event.preventDefault();
226 var collapse = document.querySelector(id);
227 if (!collapse) {
228 return;
229 }
230 var collapseComponent = Util.Observer.getComponent(className, { element: collapse });
231 if (!collapseComponent) {
232 return;
233 }
234 collapseComponent.toggle({ element: collapse, toggle: true });
235 }
236 });
237 };
238 Collapse.prototype.getHeight = function () {
239 return this.getElement().getBoundingClientRect(this.getElement()).height;
240 };
241 Collapse.prototype.toggle = function () {
242 if (this.isVisible()) {
243 return this.hide();
244 }
245 return this.show();
246 };
247 Collapse.prototype.show = function () {
248 var _this = this;
249 var element = this.getElement();
250 if (element.classList.contains('collapsing') || this.isVisible()) {
251 return false;
252 }
253 this.triggerEvent(Util.Event.SHOW);
254 var onCollapsed = function () {
255 _this.triggerEvent(Util.Event.SHOWN);
256 element.classList.add('show');
257 element.classList.remove('collapsing');
258 element.removeEventListener(Util.Event.TRANSITION_END, onCollapsed);
259 element.setAttribute('aria-expanded', true);
260 element.style.height = 'auto';
261 };
262 if (!element.classList.contains('collapsing')) {
263 element.classList.add('collapsing');
264 }
265 element.addEventListener(Util.Event.TRANSITION_END, onCollapsed);
266 var height = this.getHeight();
267 element.style.height = '0px';
268 setTimeout(function () {
269 element.style.height = height + "px";
270 }, 20);
271 return true;
272 };
273 Collapse.prototype.hide = function () {
274 var _this = this;
275 var element = this.getElement();
276 if (element.classList.contains('collapsing')) {
277 return false;
278 }
279 if (!element.classList.contains('show')) {
280 return false;
281 }
282 this.triggerEvent(Util.Event.HIDE);
283 var onCollapsed = function () {
284 _this.triggerEvent(Util.Event.HIDDEN);
285 element.classList.remove('collapsing');
286 element.style.height = 'auto';
287 element.removeEventListener(Util.Event.TRANSITION_END, onCollapsed);
288 element.setAttribute('aria-expanded', false);
289 };
290 element.style.height = element.offsetHeight + "px";
291 setTimeout(function () {
292 element.style.height = '0px';
293 }, 20);
294 element.addEventListener(Util.Event.TRANSITION_END, onCollapsed);
295 if (!element.classList.contains('collapsing')) {
296 element.classList.add('collapsing');
297 }
298 element.classList.remove('show');
299 return true;
300 };
301 Collapse.prototype.isVisible = function () {
302 return this.getElement().classList.contains('show');
303 };
304 return Collapse;
305}(Component));
306Collapse.attachDOM();
307
308var Accordion = (function (_super) {
309 __extends(Accordion, _super);
310 function Accordion(props) {
311 var _this = _super.call(this, 'accordion', { multiple: false }, props) || this;
312 _this.collapses = [];
313 var element = _this.getElement();
314 var toggles = Array
315 .from(element.querySelectorAll('[data-toggle="accordion"]') || []);
316 toggles.forEach(function (toggle) {
317 var collapseId = toggle.getAttribute('href') || toggle.getAttribute('data-target');
318 if (collapseId === null) {
319 throw new Error('Accordion: collapse is missing href or data-target attribute');
320 }
321 var collapse = document.querySelector(collapseId);
322 if (collapse) {
323 _this.addCollapse(collapse);
324 }
325 });
326 _this.registerElement({ target: element, event: Util.Event.CLICK });
327 return _this;
328 }
329 Accordion.attachDOM = function () {
330 Util.Observer.subscribe({
331 componentClass: 'accordion',
332 onAdded: function (element, create) {
333 create(new Accordion({ element: element }));
334 },
335 onRemoved: function (element, remove) {
336 remove('Accordion', element);
337 },
338 });
339 };
340 Accordion.prototype.addCollapse = function (element) {
341 var collapse = new Collapse({
342 element: element,
343 });
344 this.collapses.push(collapse);
345 return collapse;
346 };
347 Accordion.prototype.getCollapse = function (element) {
348 var el = this.getElement();
349 var collapse = this.collapses.find(function (c) { return el.getAttribute('id') === element.getAttribute('id'); });
350 if (!collapse) {
351 collapse = this.addCollapse(element);
352 }
353 return collapse;
354 };
355 Accordion.prototype.getCollapses = function () {
356 return this.collapses;
357 };
358 Accordion.prototype.setCollapses = function (showCollapse) {
359 var _this = this;
360 var element = this.getElement();
361 var collapse = this.getCollapse(showCollapse);
362 var multipleOpen = this.getProp('multiple');
363 if (!multipleOpen) {
364 this.collapses.filter(function (c) { return c.getElement() !== collapse.getElement(); }).forEach(function (c) {
365 _this.toggleIcon(c.getElement(), 'icon-minus', 'icon-plus');
366 c.hide();
367 });
368 }
369 var v = collapse.isVisible();
370 this.toggleIcon(collapse.getElement(), v ? 'icon-minus' : 'icon-plus', v ? 'icon-plus' : 'icon-minus');
371 collapse.toggle();
372 };
373 Accordion.prototype.onElementEvent = function (event) {
374 var target = event.target;
375 var toggleEl = Util.Selector.closest(target, '[data-toggle="accordion"]');
376 if (!toggleEl) {
377 return;
378 }
379 var collapseId = toggleEl.getAttribute('data-target') || toggleEl.getAttribute('href');
380 if (!collapseId) {
381 return;
382 }
383 var collapseEl = document.querySelector(collapseId);
384 var accordion = Util.Selector.closest(toggleEl, '.accordion');
385 if (!accordion || !collapseEl) {
386 return;
387 }
388 event.preventDefault();
389 this.show(collapseEl);
390 };
391 Accordion.prototype.toggleIcon = function (collapse, remove, add) {
392 var id = collapse.getAttribute('id');
393 var selector = "[data-toggle=\"accordion\"][href=\"#" + id + "\"] .collapse-toggle";
394 var iconEl = document.querySelector(selector);
395 if (!iconEl) {
396 return;
397 }
398 if (iconEl.classList.contains(remove)) {
399 iconEl.classList.remove(remove);
400 iconEl.classList.add(add);
401 }
402 };
403 Accordion.prototype.show = function (collapseEl) {
404 var collapse = collapseEl;
405 if (typeof collapseEl === 'string') {
406 collapse = document.querySelector(collapseEl);
407 }
408 if (!collapse) {
409 throw new Error("The collapsible " + collapseEl + " is an invalid HTMLElement.");
410 }
411 this.setCollapses(collapse);
412 return true;
413 };
414 Accordion.prototype.hide = function (collapseEl) {
415 var collapse = collapseEl;
416 if (typeof collapseEl === 'string') {
417 collapse = document.querySelector(collapseEl);
418 }
419 if (!collapse) {
420 throw new Error("The collapsible " + collapseEl + " is an invalid HTMLElement.");
421 }
422 var collapseObj = this.getCollapse(collapse);
423 return collapseObj.hide();
424 };
425 return Accordion;
426}(Component));
427Accordion.attachDOM();
428
429module.exports = Accordion;
430//# sourceMappingURL=accordion.js.map