UNPKG

23.3 kBJavaScriptView Raw
1/*!
2 * Selectbox 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 Selectbox = (function (_super) {
190 __extends(Selectbox, _super);
191 function Selectbox(props) {
192 var _this = _super.call(this, 'selectbox', {
193 name: null,
194 selectable: true,
195 filterItems: null,
196 multiple: false,
197 tag: false,
198 }, props) || this;
199 if (!_this.getProp('name')) {
200 var hiddenInput = _this.getElement().querySelector('input[type="hidden"]');
201 if (hiddenInput) {
202 _this.setProp('name', hiddenInput.getAttribute('name'));
203 }
204 }
205 _this.filterItemsHandler = function (event) {
206 var target = event.target;
207 if (!target) {
208 return;
209 }
210 var search = target.value;
211 if (search === '') {
212 _this.showItems();
213 return;
214 }
215 _this.getItems().forEach(function (item) {
216 var filterItems = _this.getProp('filterItems');
217 var fn = typeof filterItems === 'function' ? filterItems : _this.filterItems;
218 if (fn(search, item)) {
219 item.element.style.display = 'block';
220 }
221 else {
222 item.element.style.display = 'none';
223 }
224 });
225 };
226 _this.registerElement({ target: _this.getElement(), event: Util.Event.CLICK });
227 _this.searchInputInContainer = _this.getElement()
228 .querySelector('.selectbox-input-container .input-select-one') !== null;
229 var selectedItem = _this.getItemData(_this.getElement().querySelector('[data-selected]'));
230 if (selectedItem) {
231 _this.setSelected(selectedItem.value, selectedItem.text);
232 }
233 return _this;
234 }
235 Selectbox.attachDOM = function () {
236 Util.Observer.subscribe({
237 componentClass: 'selectbox',
238 onAdded: function (element, create) {
239 create(new Selectbox({ element: element }));
240 },
241 onRemoved: function (element, remove) {
242 remove('Selectbox', element);
243 },
244 });
245 };
246 Selectbox.prototype.getSearchInput = function () {
247 return this.getElement().querySelector('.input-select-one');
248 };
249 Selectbox.prototype.filterItems = function (search, item) {
250 if (search === void 0) { search = ''; }
251 return item.value.indexOf(search) > -1 || item.text.indexOf(search) > -1;
252 };
253 Selectbox.prototype.showItems = function () {
254 this.getItems().forEach(function (item) {
255 item.element.style.display = 'block';
256 });
257 };
258 Selectbox.prototype.getItems = function () {
259 var _this = this;
260 var items = Array
261 .from(this.getElement().querySelectorAll('.selectbox-menu-item') || []);
262 return items.map(function (item) {
263 var info = _this.getItemData(item);
264 return { text: info.text, value: info.value, element: item };
265 });
266 };
267 Selectbox.prototype.setSelected = function (value, text) {
268 if (value === void 0) { value = ''; }
269 if (text === void 0) { text = ''; }
270 var selectable = this.getProp('selectable');
271 if (!selectable) {
272 return false;
273 }
274 var element = this.getElement();
275 var multiple = this.getProp('multiple');
276 if (multiple) {
277 this.addItemSelection(value);
278 }
279 else {
280 var itemsSelected = Array
281 .from(element.querySelectorAll('.selectbox-item-selection .item-selected') || []);
282 if (itemsSelected.length === 0) {
283 this.addItemSelection(value);
284 }
285 }
286 var lastSelectedEl = element
287 .querySelector('.selectbox-item-selection .item-selected:last-child');
288 var spanEl = lastSelectedEl.querySelector('[data-value]');
289 if (spanEl) {
290 spanEl.innerHTML = text;
291 }
292 else {
293 lastSelectedEl.innerHTML = text;
294 }
295 var hiddenInputs = Array
296 .from(this.getElement().querySelectorAll('input[type="hidden"]') || []);
297 var lastInput = hiddenInputs.slice(-1).pop();
298 if (lastInput) {
299 lastInput.setAttribute('value', value);
300 }
301 this.updateActiveList();
302 this.setSearchInputWidth();
303 var searchInput = this.getSearchInput();
304 if (value === '') {
305 this.showPlaceholder();
306 }
307 else {
308 this.showPlaceholder(false);
309 }
310 return true;
311 };
312 Selectbox.prototype.getSelected = function () {
313 var hiddenInputs = Array
314 .from(this.getElement().querySelectorAll('input[type="hidden"]') || []);
315 if (!this.getProp('multiple')) {
316 return hiddenInputs.length > 0 ? hiddenInputs[0].value : '';
317 }
318 return hiddenInputs.map(function (input) { return input.value; });
319 };
320 Selectbox.prototype.setSearchInputWidth = function () {
321 if (!this.searchInputInContainer) {
322 return;
323 }
324 var selectbox = this.getElement();
325 var selection = selectbox.querySelector('.selectbox-item-selection');
326 var availableSpace = selectbox.offsetWidth - selection.offsetWidth;
327 var searchInput = this.getSearchInput();
328 if (!searchInput) {
329 throw new Error('Selectbox: search input is not defined');
330 }
331 var selectedItemWidth = Array
332 .from(selectbox.querySelectorAll('.item-selected') || [])
333 .reduce(function (total, el) { return (total + el.offsetWidth); }, 0);
334 if (availableSpace > 0) {
335 searchInput.style.width = "calc(100% - " + (selectedItemWidth + 15) + "px)";
336 }
337 searchInput.style.left = selectedItemWidth + "px";
338 };
339 Selectbox.prototype.getItemData = function (item) {
340 if (item === void 0) { item = null; }
341 var text = '';
342 var value = '';
343 if (item) {
344 text = item.getAttribute('data-text') || item.innerHTML;
345 var selectedTextNode = item.querySelector('.text');
346 if (selectedTextNode) {
347 text = selectedTextNode.innerHTML;
348 }
349 value = item.getAttribute('data-value') || '';
350 }
351 return { text: text, value: value };
352 };
353 Selectbox.prototype.onElementEvent = function (event) {
354 var target = event.target;
355 if (event.type === Util.Event.START) {
356 var selectbox = Util.Selector.closest(target, '.selectbox');
357 if (!selectbox || selectbox !== this.getElement()) {
358 this.hide();
359 }
360 }
361 else if (event.type === Util.Event.CLICK) {
362 var dataToggleAttr = target.getAttribute('data-toggle');
363 if (dataToggleAttr && dataToggleAttr === 'selectbox') {
364 this.toggle();
365 return;
366 }
367 var dismissButton = Util.Selector
368 .closest(target, '[data-dismiss="selectbox"]');
369 if (dismissButton) {
370 this.hide();
371 return;
372 }
373 var selectedTag = Util.Selector.closest(target, '.icon-close');
374 if (selectedTag) {
375 this.removeSelected(selectedTag.parentNode);
376 return;
377 }
378 var item = Util.Selector.closest(target, '.selectbox-menu-item');
379 if (item && !item.classList.contains('disabled')) {
380 var itemInfo = this.getItemData(item);
381 if (this.getSelected() !== itemInfo.value) {
382 this.setSelected(itemInfo.value, itemInfo.text);
383 var selectInput = this.getElement().querySelector('.input-select-one').value = '';
384 var detail = { item: item, text: itemInfo.text, value: itemInfo.value };
385 this.triggerEvent(Util.Event.ITEM_SELECTED, detail);
386 }
387 this.hide();
388 return;
389 }
390 var selectboxMenu = Util.Selector.closest(target, '.selectbox-menu');
391 if (selectboxMenu) {
392 return;
393 }
394 this.toggle();
395 }
396 else if (event.type === 'keyup' && event.keyCode === 8) {
397 var inputTarget = event.target;
398 if (inputTarget.value !== '') {
399 return;
400 }
401 if (!this.searchInputInContainer) {
402 return;
403 }
404 this.removeLastSelected();
405 }
406 };
407 Selectbox.prototype.addItemSelection = function (value) {
408 var itemSelectedEl = document.createElement('div');
409 itemSelectedEl.classList.add('item-selected');
410 if (this.getProp('tag')) {
411 itemSelectedEl.classList.add('tag');
412 var spanEl = document.createElement('span');
413 spanEl.setAttribute('data-value', 'true');
414 itemSelectedEl.appendChild(spanEl);
415 var closeEl = document.createElement('button');
416 closeEl.setAttribute('type', 'button');
417 closeEl.classList.add('icon-close');
418 var iconEl = document.createElement('span');
419 iconEl.setAttribute('class', 'icon');
420 iconEl.setAttribute('aria-hidden', 'true');
421 closeEl.appendChild(iconEl);
422 itemSelectedEl.appendChild(closeEl);
423 }
424 var element = this.getElement();
425 element.querySelector('.selectbox-item-selection').appendChild(itemSelectedEl);
426 var selectbox = this.getElement();
427 var hiddenInputs = Array.from(selectbox.querySelectorAll('input[type="hidden"]') || []);
428 var lastHiddenInput = hiddenInputs.length > 0 ? hiddenInputs[hiddenInputs.length - 1] : null;
429 if ((!this.getProp('multiple') && !lastHiddenInput) || this.getProp('multiple')) {
430 var hiddenInput = document.createElement('input');
431 hiddenInput.setAttribute('type', 'hidden');
432 var name_1 = this.getProp('name');
433 hiddenInput.setAttribute('name', this.getProp('multiple') ? name_1 + "[]" : name_1);
434 hiddenInput.setAttribute('value', value);
435 selectbox.insertBefore(hiddenInput, lastHiddenInput ? lastHiddenInput.nextSibling : selectbox.firstChild);
436 }
437 };
438 Selectbox.prototype.removeLastSelected = function () {
439 var selectbox = this.getElement();
440 var selectedItems = Array
441 .from(selectbox.querySelectorAll('.selectbox-item-selection .item-selected') || []);
442 if (selectedItems.length === 0) {
443 return;
444 }
445 var lastSelectedItem = selectedItems[selectedItems.length - 1];
446 this.removeSelected(lastSelectedItem);
447 };
448 Selectbox.prototype.removeSelected = function (selectedItem) {
449 var selectbox = this.getElement();
450 var selectedItems = Array
451 .from(selectbox.querySelectorAll('.selectbox-item-selection .item-selected') || []);
452 if (selectedItems.length === 0) {
453 return;
454 }
455 selectbox.querySelector('.selectbox-item-selection').removeChild(selectedItem);
456 if (this.getProp('multiple')) {
457 var values = this.getSelected();
458 var hiddenInput = selectbox
459 .querySelector("input[type=\"hidden\"][value=\"" + values.slice(-1).pop() + "\"]");
460 this.getElement().removeChild(hiddenInput);
461 }
462 else {
463 var hiddenInput = selectbox.querySelector('input[type="hidden"]');
464 if (!this.getProp('multiple') && hiddenInput) {
465 hiddenInput.setAttribute('value', '');
466 }
467 }
468 this.updateActiveList();
469 this.setSearchInputWidth();
470 if (selectedItems.length === 1) {
471 this.showPlaceholder();
472 }
473 };
474 Selectbox.prototype.showPlaceholder = function (show) {
475 if (show === void 0) { show = true; }
476 var searchInput = this.getSearchInput();
477 if (!searchInput) {
478 return;
479 }
480 if (show && searchInput.classList.contains('hide-placeholder')) {
481 searchInput.classList.remove('hide-placeholder');
482 }
483 else if (!show && !searchInput.classList.contains('hide-placeholder')) {
484 searchInput.classList.add('hide-placeholder');
485 }
486 };
487 Selectbox.prototype.updateActiveList = function () {
488 var _this = this;
489 var selected = this.getSelected();
490 var selectedItems = Array.isArray(selected) ? selected : [selected];
491 var items = Array
492 .from(this.getElement().querySelectorAll('.selectbox-menu-item') || []);
493 items.forEach(function (item) {
494 var data = _this.getItemData(item);
495 if (selectedItems.indexOf(data.value) > -1) {
496 if (!item.classList.contains('selected')) {
497 item.classList.add('selected');
498 }
499 }
500 else {
501 if (item.classList.contains('selected')) {
502 item.classList.remove('selected');
503 }
504 }
505 });
506 };
507 Selectbox.prototype.toggle = function () {
508 if (this.getElement().classList.contains('active')) {
509 return this.hide();
510 }
511 return this.show();
512 };
513 Selectbox.prototype.show = function () {
514 var element = this.getElement();
515 if (element.classList.contains('active')) {
516 return false;
517 }
518 element.classList.add('active');
519 var selectboxMenu = element.querySelector('.selectbox-menu');
520 var selectInput = this.getSearchInput();
521 selectboxMenu.scrollTop = 0;
522 this.triggerEvent(Util.Event.SHOW);
523 this.triggerEvent(Util.Event.SHOWN);
524 this.registerElement({ target: document.body, event: Util.Event.START });
525 if (selectInput) {
526 this.registerElement({ target: selectInput, event: 'keyup' });
527 selectInput.addEventListener('keyup', this.filterItemsHandler);
528 selectInput.focus();
529 }
530 var closeButton = element.querySelector('[data-dismiss="selectbox"]');
531 if (closeButton) {
532 this.registerElement({ target: closeButton, event: Util.Event.CLICK });
533 }
534 return true;
535 };
536 Selectbox.prototype.hide = function () {
537 var element = this.getElement();
538 if (!element.classList.contains('active')) {
539 return false;
540 }
541 element.classList.remove('active');
542 this.triggerEvent(Util.Event.HIDE);
543 this.triggerEvent(Util.Event.HIDDEN);
544 this.unregisterElement({ target: document.body, event: Util.Event.START });
545 var closeButton = element.querySelector('[data-dismiss="selectbox"]');
546 if (closeButton) {
547 this.unregisterElement({ target: closeButton, event: Util.Event.CLICK });
548 }
549 var selectInput = this.getSearchInput();
550 if (selectInput) {
551 selectInput.removeEventListener('keyup', this.filterItemsHandler);
552 selectInput.value = '';
553 this.unregisterElement({ target: selectInput, event: 'keyup' });
554 }
555 this.showItems();
556 return true;
557 };
558 return Selectbox;
559}(Component));
560Selectbox.attachDOM();
561
562module.exports = Selectbox;
563//# sourceMappingURL=selectbox.js.map