/*! * Materialize v2.1.0 (https://materializeweb.com) * Copyright 2014-2024 Materialize * MIT License (https://raw.githubusercontent.com/materializecss/materialize/master/LICENSE) */ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else { var a = factory(); for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; } })(this, function() { return /******/ (function() { // webpackBootstrap /******/ "use strict"; /******/ var __webpack_modules__ = ({ /***/ "./src/autocomplete.ts": /*!*****************************!*\ !*** ./src/autocomplete.ts ***! \*****************************/ /***/ (function(__unused_webpack_module, exports, __webpack_require__) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.Autocomplete = void 0; const utils_1 = __webpack_require__(/*! ./utils */ "./src/utils.ts"); const dropdown_1 = __webpack_require__(/*! ./dropdown */ "./src/dropdown.ts"); const component_1 = __webpack_require__(/*! ./component */ "./src/component.ts"); ; let _defaults = { data: [], // Autocomplete data set onAutocomplete: null, // Callback for when autocompleted dropdownOptions: { // Default dropdown options autoFocus: false, closeOnClick: false, coverTrigger: false }, minLength: 1, // Min characters before autocomplete starts isMultiSelect: false, onSearch: (text, autocomplete) => { const normSearch = text.toLocaleLowerCase(); autocomplete.setMenuItems(autocomplete.options.data.filter((option) => { var _a; return option.id.toString().toLocaleLowerCase().includes(normSearch) || ((_a = option.text) === null || _a === void 0 ? void 0 : _a.toLocaleLowerCase().includes(normSearch)); })); }, maxDropDownHeight: '300px', allowUnsafeHTML: false }; class Autocomplete extends component_1.Component { constructor(el, options) { super(el, options, Autocomplete); this._handleInputBlur = () => { if (!this._mousedown) { this.close(); this._resetAutocomplete(); } }; this._handleInputKeyupAndFocus = (e) => { if (e.type === 'keyup') Autocomplete._keydown = false; this.count = 0; const actualValue = this.el.value.toLocaleLowerCase(); // Don't capture enter or arrow key usage. if (utils_1.Utils.keys.ENTER.includes(e.key) || utils_1.Utils.keys.ARROW_UP.includes(e.key) || utils_1.Utils.keys.ARROW_DOWN.includes(e.key)) return; // Check if the input isn't empty // Check if focus triggered by tab if (this.oldVal !== actualValue && (utils_1.Utils.tabPressed || e.type !== 'focus')) { this.open(); } // Value has changed! if (this.oldVal !== actualValue) { this._setStatusLoading(); this.options.onSearch(this.el.value, this); } // Reset Single-Select when Input cleared if (!this.options.isMultiSelect && this.el.value.length === 0) { this.selectedValues = []; this._triggerChanged(); } this.oldVal = actualValue; }; this._handleInputKeydown = (e) => { var _a, _b; Autocomplete._keydown = true; // Arrow keys and enter key usage const numItems = this.container.querySelectorAll('li').length; // select element on Enter if (utils_1.Utils.keys.ENTER.includes(e.key) && this.activeIndex >= 0) { const liElement = this.container.querySelectorAll('li')[this.activeIndex]; if (liElement) { this.selectOption(liElement.getAttribute('data-id')); e.preventDefault(); } return; } // Capture up and down key if (utils_1.Utils.keys.ARROW_UP.includes(e.key) || utils_1.Utils.keys.ARROW_DOWN.includes(e.key)) { e.preventDefault(); if (utils_1.Utils.keys.ARROW_UP.includes(e.key) && this.activeIndex > 0) this.activeIndex--; if (utils_1.Utils.keys.ARROW_DOWN.includes(e.key) && this.activeIndex < numItems - 1) this.activeIndex++; (_a = this.$active) === null || _a === void 0 ? void 0 : _a.classList.remove('active'); if (this.activeIndex >= 0) { this.$active = this.container.querySelectorAll('li')[this.activeIndex]; (_b = this.$active) === null || _b === void 0 ? void 0 : _b.classList.add('active'); // Focus selected this.container.children[this.activeIndex].scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' }); } } }; this._handleInputClick = () => { this.open(); }; this._handleContainerMousedownAndTouchstart = () => { this._mousedown = true; }; this._handleContainerMouseupAndTouchend = () => { this._mousedown = false; }; /** * Show autocomplete. */ this.open = () => { const inputText = this.el.value.toLocaleLowerCase(); this._resetAutocomplete(); if (inputText.length >= this.options.minLength) { this.isOpen = true; this._renderDropdown(); } // Open dropdown if (!this.dropdown.isOpen) { setTimeout(() => { this.dropdown.open(); }, 100); } else this.dropdown.recalculateDimensions(); // Recalculate dropdown when its already open }; /** * Hide autocomplete. */ this.close = () => { this.dropdown.close(); }; this.el.M_Autocomplete = this; this.options = Object.assign(Object.assign({}, Autocomplete.defaults), options); this.isOpen = false; this.count = 0; this.activeIndex = -1; this.oldVal = ""; this.selectedValues = []; this.menuItems = []; this.$active = null; this._mousedown = false; this._setupDropdown(); this._setupEventHandlers(); } static get defaults() { return _defaults; } /** * Initializes instances of Autocomplete. * @param els HTML elements. * @param options Component options. */ static init(els, options = {}) { return super.init(els, options, Autocomplete); } static getInstance(el) { return el.M_Autocomplete; } destroy() { this._removeEventHandlers(); this._removeDropdown(); this.el.M_Autocomplete = undefined; } _setupEventHandlers() { this.el.addEventListener('blur', this._handleInputBlur); this.el.addEventListener('keyup', this._handleInputKeyupAndFocus); this.el.addEventListener('focus', this._handleInputKeyupAndFocus); this.el.addEventListener('keydown', this._handleInputKeydown); this.el.addEventListener('click', this._handleInputClick); this.container.addEventListener('mousedown', this._handleContainerMousedownAndTouchstart); this.container.addEventListener('mouseup', this._handleContainerMouseupAndTouchend); if (typeof window.ontouchstart !== 'undefined') { this.container.addEventListener('touchstart', this._handleContainerMousedownAndTouchstart); this.container.addEventListener('touchend', this._handleContainerMouseupAndTouchend); } } _removeEventHandlers() { this.el.removeEventListener('blur', this._handleInputBlur); this.el.removeEventListener('keyup', this._handleInputKeyupAndFocus); this.el.removeEventListener('focus', this._handleInputKeyupAndFocus); this.el.removeEventListener('keydown', this._handleInputKeydown); this.el.removeEventListener('click', this._handleInputClick); this.container.removeEventListener('mousedown', this._handleContainerMousedownAndTouchstart); this.container.removeEventListener('mouseup', this._handleContainerMouseupAndTouchend); if (typeof window.ontouchstart !== 'undefined') { this.container.removeEventListener('touchstart', this._handleContainerMousedownAndTouchstart); this.container.removeEventListener('touchend', this._handleContainerMouseupAndTouchend); } } _setupDropdown() { this.container = document.createElement('ul'); this.container.style.maxHeight = this.options.maxDropDownHeight; this.container.id = `autocomplete-options-${utils_1.Utils.guid()}`; this.container.classList.add('autocomplete-content', 'dropdown-content'); this.el.setAttribute('data-target', this.container.id); // ! Issue in Component Dropdown: _placeDropdown moves dom-position this.el.parentElement.appendChild(this.container); // Initialize dropdown let dropdownOptions = Object.assign(Object.assign({}, Autocomplete.defaults.dropdownOptions), this.options.dropdownOptions); let userOnItemClick = dropdownOptions.onItemClick; // Ensuring the select Option call when user passes custom onItemClick function to dropdown dropdownOptions.onItemClick = (li) => { if (!li) return; const entryID = li.getAttribute('data-id'); this.selectOption(entryID); // Handle user declared onItemClick if needed if (userOnItemClick && typeof userOnItemClick === 'function') userOnItemClick.call(this.dropdown, this.el); }; this.dropdown = dropdown_1.Dropdown.init(this.el, dropdownOptions); // ! Workaround for Label: move label up again // TODO: Just use PopperJS in future! const label = this.el.parentElement.querySelector('label'); if (label) this.el.after(label); // Sketchy removal of dropdown click handler this.el.removeEventListener('click', this.dropdown._handleClick); // Set Value if already set in HTML if (this.el.value) this.selectOption(this.el.value); // Add StatusInfo const div = document.createElement('div'); div.classList.add('status-info'); div.setAttribute('style', 'position: absolute;right:0;top:0;'); this.el.parentElement.appendChild(div); this._updateSelectedInfo(); } _removeDropdown() { this.container.parentNode.removeChild(this.container); } _resetCurrentElementPosition() { var _a; this.activeIndex = -1; (_a = this.$active) === null || _a === void 0 ? void 0 : _a.classList.remove('active'); } _resetAutocomplete() { this.container.replaceChildren(); this._resetCurrentElementPosition(); this.oldVal = null; this.isOpen = false; this._mousedown = false; } _highlightPartialText(input, label) { const start = label.toLocaleLowerCase().indexOf('' + input.toLocaleLowerCase() + ''); const end = start + input.length - 1; //custom filters may return results where the string does not match any part if (start == -1 || end == -1) { return [label, '', '']; } return [label.slice(0, start), label.slice(start, end + 1), label.slice(end + 1)]; } _createDropdownItem(entry) { const item = document.createElement('li'); item.setAttribute('data-id', entry.id); item.setAttribute('style', 'display:grid; grid-auto-flow: column; user-select: none; align-items: center;'); // Checkbox if (this.options.isMultiSelect) { item.innerHTML = `
sel.id === entry.id) ? ' checked="checked"' : ''}>
`; } // Image if (entry.image) { const img = document.createElement('img'); img.classList.add('circle'); img.src = entry.image; item.appendChild(img); } // Text const inputText = this.el.value.toLocaleLowerCase(); const parts = this._highlightPartialText(inputText, (entry.text || entry.id).toString()); const div = document.createElement('div'); div.setAttribute('style', 'line-height:1.2;font-weight:500;'); if (this.options.allowUnsafeHTML) { div.innerHTML = parts[0] + '' + parts[1] + '' + parts[2]; } else { div.appendChild(document.createTextNode(parts[0])); if (parts[1]) { const highlight = document.createElement('span'); highlight.textContent = parts[1]; highlight.classList.add('highlight'); div.appendChild(highlight); div.appendChild(document.createTextNode(parts[2])); } } const itemText = document.createElement('div'); itemText.classList.add('item-text'); itemText.setAttribute('style', 'padding:5px;overflow:hidden;'); item.appendChild(itemText); item.querySelector('.item-text').appendChild(div); // Description if (typeof entry.description === 'string' || (typeof entry.description === 'number' && !isNaN(entry.description))) { const description = document.createElement('small'); description.setAttribute('style', 'line-height:1.3;color:grey;white-space:nowrap;text-overflow:ellipsis;display:block;width:90%;overflow:hidden;'); description.innerText = entry.description; item.querySelector('.item-text').appendChild(description); } // Set Grid const getGridConfig = () => { if (this.options.isMultiSelect) { if (entry.image) return '40px min-content auto'; // cb-img-txt return '40px auto'; // cb-txt } if (entry.image) return 'min-content auto'; // img-txt return 'auto'; // txt }; item.style.gridTemplateColumns = getGridConfig(); return item; } _renderDropdown() { this._resetAutocomplete(); // Check if Data is empty if (this.menuItems.length === 0) { this.menuItems = this.selectedValues; // Show selected Items } for (let i = 0; i < this.menuItems.length; i++) { const item = this._createDropdownItem(this.menuItems[i]); this.container.append(item); } } _setStatusLoading() { this.el.parentElement.querySelector('.status-info').innerHTML = `
`; } _updateSelectedInfo() { const statusElement = this.el.parentElement.querySelector('.status-info'); if (statusElement) { if (this.options.isMultiSelect) statusElement.innerHTML = this.selectedValues.length.toString(); else statusElement.innerHTML = ''; } } _refreshInputText() { if (this.selectedValues.length === 1) { const entry = this.selectedValues[0]; this.el.value = entry.text || entry.id; // Write Text to Input } } _triggerChanged() { this.el.dispatchEvent(new Event('change')); // Trigger Autocomplete Event if (typeof this.options.onAutocomplete === 'function') this.options.onAutocomplete.call(this, this.selectedValues); } /** * Updates the visible or selectable items shown in the menu. * @param menuItems Items to be available. */ setMenuItems(menuItems) { this.menuItems = menuItems; this.open(); this._updateSelectedInfo(); } /** * Sets selected values. * @param entries */ setValues(entries) { this.selectedValues = entries; this._updateSelectedInfo(); if (!this.options.isMultiSelect) { this._refreshInputText(); } this._triggerChanged(); } /** * Select a specific autocomplete option via id-property. * @param id The id of a data-entry. */ selectOption(id) { const entry = this.menuItems.find((item) => item.id == id); if (!entry) return; // Toggle Checkbox const li = this.container.querySelector('li[data-id="' + id + '"]'); if (!li) return; if (this.options.isMultiSelect) { const checkbox = li.querySelector('input[type="checkbox"]'); checkbox.checked = !checkbox.checked; if (checkbox.checked) this.selectedValues.push(entry); else this.selectedValues = this.selectedValues.filter((selectedEntry) => selectedEntry.id !== entry.id); this.el.focus(); } else { // Single-Select this.selectedValues = [entry]; this._refreshInputText(); this._resetAutocomplete(); this.close(); } this._updateSelectedInfo(); this._triggerChanged(); } } exports.Autocomplete = Autocomplete; /***/ }), /***/ "./src/buttons.ts": /*!************************!*\ !*** ./src/buttons.ts ***! \************************/ /***/ (function(__unused_webpack_module, exports, __webpack_require__) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.FloatingActionButton = void 0; const component_1 = __webpack_require__(/*! ./component */ "./src/component.ts"); ; let _defaults = { direction: 'top', hoverEnabled: true, toolbarEnabled: false }; class FloatingActionButton extends component_1.Component { constructor(el, options) { super(el, options, FloatingActionButton); this._handleFABClick = () => { if (this.isOpen) { this.close(); } else { this.open(); } }; this._handleDocumentClick = (e) => { const elem = e.target; if (elem !== this._menu) this.close; }; /** * Open FAB. */ this.open = () => { if (this.isOpen) return; if (this.options.toolbarEnabled) this._animateInToolbar(); else this._animateInFAB(); this.isOpen = true; }; /** * Close FAB. */ this.close = () => { if (!this.isOpen) return; if (this.options.toolbarEnabled) { window.removeEventListener('scroll', this.close, true); document.body.removeEventListener('click', this._handleDocumentClick, true); } else { this._animateOutFAB(); } this.isOpen = false; }; this.el.M_FloatingActionButton = this; this.options = Object.assign(Object.assign({}, FloatingActionButton.defaults), options); this.isOpen = false; this._anchor = this.el.querySelector('a'); this._menu = this.el.querySelector('ul'); this._floatingBtns = Array.from(this.el.querySelectorAll('ul .btn-floating')); this._floatingBtnsReverse = this._floatingBtns.reverse(); this.offsetY = 0; this.offsetX = 0; this.el.classList.add(`direction-${this.options.direction}`); if (this.options.direction === 'top') this.offsetY = 40; else if (this.options.direction === 'right') this.offsetX = -40; else if (this.options.direction === 'bottom') this.offsetY = -40; else this.offsetX = 40; this._setupEventHandlers(); } static get defaults() { return _defaults; } /** * Initializes instances of FloatingActionButton. * @param els HTML elements. * @param options Component options. */ static init(els, options = {}) { return super.init(els, options, FloatingActionButton); } static getInstance(el) { return el.M_FloatingActionButton; } destroy() { this._removeEventHandlers(); this.el.M_FloatingActionButton = undefined; } _setupEventHandlers() { if (this.options.hoverEnabled && !this.options.toolbarEnabled) { this.el.addEventListener('mouseenter', this.open); this.el.addEventListener('mouseleave', this.close); } else { this.el.addEventListener('click', this._handleFABClick); } } _removeEventHandlers() { if (this.options.hoverEnabled && !this.options.toolbarEnabled) { this.el.removeEventListener('mouseenter', this.open); this.el.removeEventListener('mouseleave', this.close); } else { this.el.removeEventListener('click', this._handleFABClick); } } _animateInFAB() { this.el.classList.add('active'); const delayIncrement = 40; const duration = 275; this._floatingBtnsReverse.forEach((el, index) => { const delay = delayIncrement * index; el.style.transition = 'none'; el.style.opacity = '0'; el.style.transform = `translate(${this.offsetX}px, ${this.offsetY}px) scale(0.4)`; setTimeout(() => { // from: el.style.opacity = '0.4'; // easeInOutQuad setTimeout(() => { // to: el.style.transition = `opacity ${duration}ms ease, transform ${duration}ms ease`; el.style.opacity = '1'; el.style.transform = 'translate(0, 0) scale(1)'; }, 1); }, delay); }); } _animateOutFAB() { const duration = 175; setTimeout(() => this.el.classList.remove('active'), duration); this._floatingBtnsReverse.forEach((el) => { el.style.transition = `opacity ${duration}ms ease, transform ${duration}ms ease`; // to el.style.opacity = '0'; el.style.transform = `translate(${this.offsetX}px, ${this.offsetY}px) scale(0.4)`; }); } _animateInToolbar() { let scaleFactor; let windowWidth = window.innerWidth; let windowHeight = window.innerHeight; let btnRect = this.el.getBoundingClientRect(); const backdrop = document.createElement('div'); backdrop.classList.add('fab-backdrop'); // $('
'); const fabColor = getComputedStyle(this._anchor).backgroundColor; // css('background-color'); this._anchor.append(backdrop); this.offsetX = btnRect.left - windowWidth / 2 + btnRect.width / 2; this.offsetY = windowHeight - btnRect.bottom; scaleFactor = windowWidth / backdrop[0].clientWidth; this.btnBottom = btnRect.bottom; this.btnLeft = btnRect.left; this.btnWidth = btnRect.width; // Set initial state this.el.classList.add('active'); this.el.style.textAlign = 'center'; this.el.style.width = '100%'; this.el.style.bottom = '0'; this.el.style.left = '0'; this.el.style.transform = 'translateX(' + this.offsetX + 'px)'; this.el.style.transition = 'none'; this._anchor.style.transform = `translateY(${this.offsetY}px`; this._anchor.style.transition = 'none'; backdrop.style.backgroundColor = fabColor; setTimeout(() => { this.el.style.transform = ''; this.el.style.transition = 'transform .2s cubic-bezier(0.550, 0.085, 0.680, 0.530), background-color 0s linear .2s'; this._anchor.style.overflow = 'visible'; this._anchor.style.transform = ''; this._anchor.style.transition = 'transform .2s'; setTimeout(() => { this.el.style.overflow = 'hidden'; this.el.style.backgroundColor = fabColor; backdrop.style.transform = 'scale(' + scaleFactor + ')'; backdrop.style.transition = 'transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)'; this._menu.querySelectorAll('li > a').forEach((a) => a.style.opacity = '1'); // Scroll to close. window.addEventListener('scroll', this.close, true); document.body.addEventListener('click', this._handleDocumentClick, true); }, 100); }, 0); } } exports.FloatingActionButton = FloatingActionButton; /***/ }), /***/ "./src/cards.ts": /*!**********************!*\ !*** ./src/cards.ts ***! \**********************/ /***/ (function(__unused_webpack_module, exports) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.Cards = void 0; class Cards { static Init() { document.addEventListener("DOMContentLoaded", () => { document.body.addEventListener('click', e => { const trigger = e.target; const card = trigger.closest('.card'); if (!card) return; const cardReveal = Array.from(card.children).find(elem => elem.classList.contains('card-reveal')); if (!cardReveal) return; const initialOverflow = getComputedStyle(card).overflow; // Close Card const closeArea = cardReveal.querySelector('.card-reveal .card-title'); if (trigger === closeArea || closeArea.contains(trigger)) { const duration = 225; cardReveal.style.transition = `transform ${duration}ms ease`; //easeInOutQuad cardReveal.style.transform = 'translateY(0)'; setTimeout(() => { cardReveal.style.display = 'none'; card.style.overflow = initialOverflow; }, duration); } ; // Reveal Card const activators = card.querySelectorAll('.activator'); activators.forEach(activator => { if (trigger === activator || activator.contains(trigger)) { card.style.overflow = 'hidden'; cardReveal.style.display = 'block'; setTimeout(() => { const duration = 300; cardReveal.style.transition = `transform ${duration}ms ease`; //easeInOutQuad cardReveal.style.transform = 'translateY(-100%)'; }, 1); } }); }); }); } } exports.Cards = Cards; /***/ }), /***/ "./src/carousel.ts": /*!*************************!*\ !*** ./src/carousel.ts ***! \*************************/ /***/ (function(__unused_webpack_module, exports, __webpack_require__) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.Carousel = void 0; const utils_1 = __webpack_require__(/*! ./utils */ "./src/utils.ts"); const component_1 = __webpack_require__(/*! ./component */ "./src/component.ts"); let _defaults = { duration: 200, // ms dist: -100, // zoom scale TODO: make this more intuitive as an option shift: 0, // spacing for center image padding: 0, // Padding between non center items numVisible: 5, // Number of visible items in carousel fullWidth: false, // Change to full width styles indicators: false, // Toggle indicators noWrap: false, // Don't wrap around and cycle through items. onCycleTo: null // Callback for when a new slide is cycled to. }; class Carousel extends component_1.Component { constructor(el, options) { var _a; super(el, options, Carousel); /** The index of the center carousel item. */ this.center = 0; this._handleThrottledResize = utils_1.Utils.throttle(function () { this._handleResize(); }, 200, null).bind(this); this._handleCarouselTap = (e) => { // Fixes firefox draggable image bug if (e.type === 'mousedown' && e.target.tagName === 'IMG') { e.preventDefault(); } this.pressed = true; this.dragged = false; this.verticalDragged = false; this.reference = this._xpos(e); this.referenceY = this._ypos(e); this.velocity = this.amplitude = 0; this.frame = this.offset; this.timestamp = Date.now(); clearInterval(this.ticker); this.ticker = setInterval(this._track, 100); }; this._handleCarouselDrag = (e) => { let x, y, delta, deltaY; if (this.pressed) { x = this._xpos(e); y = this._ypos(e); delta = this.reference - x; deltaY = Math.abs(this.referenceY - y); if (deltaY < 30 && !this.verticalDragged) { // If vertical scrolling don't allow dragging. if (delta > 2 || delta < -2) { this.dragged = true; this.reference = x; this._scroll(this.offset + delta); } } else if (this.dragged) { // If dragging don't allow vertical scroll. e.preventDefault(); e.stopPropagation(); return false; } else { // Vertical scrolling. this.verticalDragged = true; } } if (this.dragged) { // If dragging don't allow vertical scroll. e.preventDefault(); e.stopPropagation(); return false; } }; this._handleCarouselRelease = (e) => { if (this.pressed) { this.pressed = false; } else { return; } clearInterval(this.ticker); this.target = this.offset; if (this.velocity > 10 || this.velocity < -10) { this.amplitude = 0.9 * this.velocity; this.target = this.offset + this.amplitude; } this.target = Math.round(this.target / this.dim) * this.dim; // No wrap of items. if (this.noWrap) { if (this.target >= this.dim * (this.count - 1)) { this.target = this.dim * (this.count - 1); } else if (this.target < 0) { this.target = 0; } } this.amplitude = this.target - this.offset; this.timestamp = Date.now(); requestAnimationFrame(this._autoScroll); if (this.dragged) { e.preventDefault(); e.stopPropagation(); } return false; }; this._handleCarouselClick = (e) => { // Disable clicks if carousel was dragged. if (this.dragged) { e.preventDefault(); e.stopPropagation(); return false; } else if (!this.options.fullWidth) { const clickedElem = e.target.closest('.carousel-item'); if (!clickedElem) return; const clickedIndex = [...clickedElem.parentNode.children].indexOf(clickedElem); const diff = this._wrap(this.center) - clickedIndex; // Disable clicks if carousel was shifted by click if (diff !== 0) { e.preventDefault(); e.stopPropagation(); } // fixes https://github.com/materializecss/materialize/issues/180 if (clickedIndex < 0) { // relative X position > center of carousel = clicked at the right part of the carousel if (e.clientX - e.target.getBoundingClientRect().left > this.el.clientWidth / 2) { this.next(); } else { this.prev(); } } else { this._cycleTo(clickedIndex); } } }; this._handleIndicatorClick = (e) => { e.stopPropagation(); const indicator = e.target.closest('.indicator-item'); if (indicator) { const index = [...indicator.parentNode.children].indexOf(indicator); this._cycleTo(index); } }; this._handleResize = () => { if (this.options.fullWidth) { this.itemWidth = this.el.querySelector('.carousel-item').clientWidth; this.imageHeight = this.el.querySelector('.carousel-item.active').clientHeight; this.dim = this.itemWidth * 2 + this.options.padding; this.offset = this.center * 2 * this.itemWidth; this.target = this.offset; this._setCarouselHeight(true); } else { this._scroll(); } }; this._track = () => { let now, elapsed, delta, v; now = Date.now(); elapsed = now - this.timestamp; this.timestamp = now; delta = this.offset - this.frame; this.frame = this.offset; v = (1000 * delta) / (1 + elapsed); this.velocity = 0.8 * v + 0.2 * this.velocity; }; this._autoScroll = () => { let elapsed, delta; if (this.amplitude) { elapsed = Date.now() - this.timestamp; delta = this.amplitude * Math.exp(-elapsed / this.options.duration); if (delta > 2 || delta < -2) { this._scroll(this.target - delta); requestAnimationFrame(this._autoScroll); } else { this._scroll(this.target); } } }; this.el.M_Carousel = this; this.options = Object.assign(Object.assign({}, Carousel.defaults), options); // Setup this.hasMultipleSlides = this.el.querySelectorAll('.carousel-item').length > 1; this.showIndicators = this.options.indicators && this.hasMultipleSlides; this.noWrap = this.options.noWrap || !this.hasMultipleSlides; this.pressed = false; this.dragged = false; this.offset = this.target = 0; this.images = []; this.itemWidth = this.el.querySelector('.carousel-item').clientWidth; this.itemHeight = this.el.querySelector('.carousel-item').clientHeight; this.dim = this.itemWidth * 2 + this.options.padding || 1; // Make sure dim is non zero for divisions. // Full Width carousel setup if (this.options.fullWidth) { this.options.dist = 0; this._setCarouselHeight(); // Offset fixed items when indicators. if (this.showIndicators) { (_a = this.el.querySelector('.carousel-fixed-item')) === null || _a === void 0 ? void 0 : _a.classList.add('with-indicators'); } } // Iterate through slides this._indicators = document.createElement('ul'); this._indicators.classList.add('indicators'); this.el.querySelectorAll('.carousel-item').forEach((item, i) => { this.images.push(item); if (this.showIndicators) { const indicator = document.createElement('li'); indicator.classList.add('indicator-item'); if (i === 0) { indicator.classList.add('active'); } this._indicators.appendChild(indicator); } }); if (this.showIndicators) this.el.appendChild(this._indicators); this.count = this.images.length; // Cap numVisible at count this.options.numVisible = Math.min(this.count, this.options.numVisible); // Setup cross browser string this.xform = 'transform'; ['webkit', 'Moz', 'O', 'ms'].every((prefix) => { var e = prefix + 'Transform'; if (typeof document.body.style[e] !== 'undefined') { this.xform = e; return false; } return true; }); this._setupEventHandlers(); this._scroll(this.offset); } static get defaults() { return _defaults; } /** * Initializes instances of Carousel. * @param els HTML elements. * @param options Component options. */ static init(els, options = {}) { return super.init(els, options, Carousel); } static getInstance(el) { return el.M_Carousel; } destroy() { this._removeEventHandlers(); this.el.M_Carousel = undefined; } _setupEventHandlers() { if (typeof window.ontouchstart !== 'undefined') { this.el.addEventListener('touchstart', this._handleCarouselTap); this.el.addEventListener('touchmove', this._handleCarouselDrag); this.el.addEventListener('touchend', this._handleCarouselRelease); } this.el.addEventListener('mousedown', this._handleCarouselTap); this.el.addEventListener('mousemove', this._handleCarouselDrag); this.el.addEventListener('mouseup', this._handleCarouselRelease); this.el.addEventListener('mouseleave', this._handleCarouselRelease); this.el.addEventListener('click', this._handleCarouselClick); if (this.showIndicators && this._indicators) { this._indicators.querySelectorAll('.indicator-item').forEach((el) => { el.addEventListener('click', this._handleIndicatorClick); }); } // Resize window.addEventListener('resize', this._handleThrottledResize); } _removeEventHandlers() { if (typeof window.ontouchstart !== 'undefined') { this.el.removeEventListener('touchstart', this._handleCarouselTap); this.el.removeEventListener('touchmove', this._handleCarouselDrag); this.el.removeEventListener('touchend', this._handleCarouselRelease); } this.el.removeEventListener('mousedown', this._handleCarouselTap); this.el.removeEventListener('mousemove', this._handleCarouselDrag); this.el.removeEventListener('mouseup', this._handleCarouselRelease); this.el.removeEventListener('mouseleave', this._handleCarouselRelease); this.el.removeEventListener('click', this._handleCarouselClick); if (this.showIndicators && this._indicators) { this._indicators.querySelectorAll('.indicator-item').forEach((el) => { el.removeEventListener('click', this._handleIndicatorClick); }); } window.removeEventListener('resize', this._handleThrottledResize); } _setCarouselHeight(imageOnly = false) { const firstSlide = this.el.querySelector('.carousel-item.active') ? this.el.querySelector('.carousel-item.active') : this.el.querySelector('.carousel-item'); const firstImage = firstSlide.querySelector('img'); if (firstImage) { if (firstImage.complete) { // If image won't trigger the load event const imageHeight = firstImage.clientHeight; if (imageHeight > 0) { this.el.style.height = imageHeight + 'px'; } else { // If image still has no height, use the natural dimensions to calculate const naturalWidth = firstImage.naturalWidth; const naturalHeight = firstImage.naturalHeight; const adjustedHeight = (this.el.clientWidth / naturalWidth) * naturalHeight; this.el.style.height = adjustedHeight + 'px'; } } else { // Get height when image is loaded normally firstImage.addEventListener('load', () => { this.el.style.height = firstImage.offsetHeight + 'px'; }); } } else if (!imageOnly) { const slideHeight = firstSlide.clientHeight; this.el.style.height = slideHeight + 'px'; } } _xpos(e) { // touch event if (e.type.startsWith("touch") && e.targetTouches.length >= 1) { return e.targetTouches[0].clientX; } // mouse event return e.clientX; } _ypos(e) { // touch event if (e.type.startsWith("touch") && e.targetTouches.length >= 1) { return e.targetTouches[0].clientY; } // mouse event return e.clientY; } _wrap(x) { return x >= this.count ? x % this.count : x < 0 ? this._wrap(this.count + (x % this.count)) : x; } _scroll(x = 0) { // Track scrolling state if (!this.el.classList.contains('scrolling')) { this.el.classList.add('scrolling'); } if (this.scrollingTimeout != null) { window.clearTimeout(this.scrollingTimeout); } this.scrollingTimeout = window.setTimeout(() => { this.el.classList.remove('scrolling'); }, this.options.duration); // Start actual scroll let i, half, delta, dir, tween, el, alignment, zTranslation, tweenedOpacity, centerTweenedOpacity; let lastCenter = this.center; let numVisibleOffset = 1 / this.options.numVisible; this.offset = typeof x === 'number' ? x : this.offset; this.center = Math.floor((this.offset + this.dim / 2) / this.dim); delta = this.offset - this.center * this.dim; dir = delta < 0 ? 1 : -1; tween = (-dir * delta * 2) / this.dim; half = this.count >> 1; if (this.options.fullWidth) { alignment = 'translateX(0)'; centerTweenedOpacity = 1; } else { alignment = 'translateX(' + (this.el.clientWidth - this.itemWidth) / 2 + 'px) '; alignment += 'translateY(' + (this.el.clientHeight - this.itemHeight) / 2 + 'px)'; centerTweenedOpacity = 1 - numVisibleOffset * tween; } // Set indicator active if (this.showIndicators) { const diff = this.center % this.count; const activeIndicator = this._indicators.querySelector('.indicator-item.active'); const activeIndicatorIndex = [...activeIndicator.parentNode.children].indexOf(activeIndicator); if (activeIndicatorIndex !== diff) { activeIndicator.classList.remove('active'); const pos = diff < 0 ? this.count + diff : diff; this._indicators.querySelectorAll('.indicator-item')[pos].classList.add('active'); } } // center // Don't show wrapped items. if (!this.noWrap || (this.center >= 0 && this.center < this.count)) { el = this.images[this._wrap(this.center)]; // Add active class to center item. if (!el.classList.contains('active')) { this.el.querySelector('.carousel-item').classList.remove('active'); el.classList.add('active'); } let transformString = `${alignment} translateX(${-delta / 2}px) translateX(${dir * this.options.shift * tween * i}px) translateZ(${this.options.dist * tween}px)`; this._updateItemStyle(el, centerTweenedOpacity, 0, transformString); } for (i = 1; i <= half; ++i) { // right side if (this.options.fullWidth) { zTranslation = this.options.dist; tweenedOpacity = i === half && delta < 0 ? 1 - tween : 1; } else { zTranslation = this.options.dist * (i * 2 + tween * dir); tweenedOpacity = 1 - numVisibleOffset * (i * 2 + tween * dir); } // Don't show wrapped items. if (!this.noWrap || this.center + i < this.count) { el = this.images[this._wrap(this.center + i)]; let transformString = `${alignment} translateX(${this.options.shift + (this.dim * i - delta) / 2}px) translateZ(${zTranslation}px)`; this._updateItemStyle(el, tweenedOpacity, -i, transformString); } // left side if (this.options.fullWidth) { zTranslation = this.options.dist; tweenedOpacity = i === half && delta > 0 ? 1 - tween : 1; } else { zTranslation = this.options.dist * (i * 2 - tween * dir); tweenedOpacity = 1 - numVisibleOffset * (i * 2 - tween * dir); } // Don't show wrapped items. if (!this.noWrap || this.center - i >= 0) { el = this.images[this._wrap(this.center - i)]; let transformString = `${alignment} translateX(${-this.options.shift + (-this.dim * i - delta) / 2}px) translateZ(${zTranslation}px)`; this._updateItemStyle(el, tweenedOpacity, -i, transformString); } } // center // Don't show wrapped items. if (!this.noWrap || (this.center >= 0 && this.center < this.count)) { el = this.images[this._wrap(this.center)]; let transformString = `${alignment} translateX(${-delta / 2}px) translateX(${dir * this.options.shift * tween}px) translateZ(${this.options.dist * tween}px)`; this._updateItemStyle(el, centerTweenedOpacity, 0, transformString); } // onCycleTo callback const _currItem = this.el.querySelectorAll('.carousel-item')[this._wrap(this.center)]; if (lastCenter !== this.center && typeof this.options.onCycleTo === 'function') { this.options.onCycleTo.call(this, _currItem, this.dragged); } // One time callback if (typeof this.oneTimeCallback === 'function') { this.oneTimeCallback.call(this, _currItem, this.dragged); this.oneTimeCallback = null; } } _updateItemStyle(el, opacity, zIndex, transform) { el.style[this.xform] = transform; el.style.zIndex = zIndex.toString(); el.style.opacity = opacity.toString(); el.style.visibility = 'visible'; } _cycleTo(n, callback = null) { let diff = (this.center % this.count) - n; // Account for wraparound. if (!this.noWrap) { if (diff < 0) { if (Math.abs(diff + this.count) < Math.abs(diff)) { diff += this.count; } } else if (diff > 0) { if (Math.abs(diff - this.count) < diff) { diff -= this.count; } } } this.target = this.dim * Math.round(this.offset / this.dim); // Next if (diff < 0) { this.target += this.dim * Math.abs(diff); } // Prev else if (diff > 0) { this.target -= this.dim * diff; } // Set one time callback if (typeof callback === 'function') { this.oneTimeCallback = callback; } // Scroll if (this.offset !== this.target) { this.amplitude = this.target - this.offset; this.timestamp = Date.now(); requestAnimationFrame(this._autoScroll); } } /** * Move carousel to next slide or go forward a given amount of slides. * @param n How many times the carousel slides. */ next(n = 1) { if (n === undefined || isNaN(n)) { n = 1; } let index = this.center + n; if (index >= this.count || index < 0) { if (this.noWrap) return; index = this._wrap(index); } this._cycleTo(index); } /** * Move carousel to previous slide or go back a given amount of slides. * @param n How many times the carousel slides. */ prev(n = 1) { if (n === undefined || isNaN(n)) { n = 1; } let index = this.center - n; if (index >= this.count || index < 0) { if (this.noWrap) return; index = this._wrap(index); } this._cycleTo(index); } /** * Move carousel to nth slide. * @param n Index of slide. * @param callback "onCycleTo" optional callback. */ set(n, callback) { if (n === undefined || isNaN(n)) { n = 0; } if (n > this.count || n < 0) { if (this.noWrap) return; n = this._wrap(n); } this._cycleTo(n, callback); } } exports.Carousel = Carousel; /***/ }), /***/ "./src/characterCounter.ts": /*!*********************************!*\ !*** ./src/characterCounter.ts ***! \*********************************/ /***/ (function(__unused_webpack_module, exports, __webpack_require__) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CharacterCounter = void 0; const component_1 = __webpack_require__(/*! ./component */ "./src/component.ts"); ; const _defaults = Object.freeze({}); class CharacterCounter extends component_1.Component { constructor(el, options) { super(el, {}, CharacterCounter); this.updateCounter = () => { let maxLength = parseInt(this.el.getAttribute('maxlength')), actualLength = this.el.value.length; this.isValidLength = actualLength <= maxLength; let counterString = actualLength.toString(); if (maxLength) { counterString += '/' + maxLength; this._validateInput(); } this.counterEl.innerHTML = counterString; }; this.el.M_CharacterCounter = this; this.options = Object.assign(Object.assign({}, CharacterCounter.defaults), options); this.isInvalid = false; this.isValidLength = false; this._setupCounter(); this._setupEventHandlers(); } static get defaults() { return _defaults; } /** * Initializes instances of CharacterCounter. * @param els HTML elements. * @param options Component options. */ static init(els, options = {}) { return super.init(els, options, CharacterCounter); } static getInstance(el) { return el.M_CharacterCounter; } destroy() { this._removeEventHandlers(); this.el.CharacterCounter = undefined; this._removeCounter(); } _setupEventHandlers() { this.el.addEventListener('focus', this.updateCounter, true); this.el.addEventListener('input', this.updateCounter, true); } _removeEventHandlers() { this.el.removeEventListener('focus', this.updateCounter, true); this.el.removeEventListener('input', this.updateCounter, true); } _setupCounter() { this.counterEl = document.createElement('span'); this.counterEl.classList.add('character-counter'); this.counterEl.style.float = 'right'; this.counterEl.style.fontSize = '12px'; this.counterEl.style.height = '1'; this.el.parentElement.appendChild(this.counterEl); } _removeCounter() { this.counterEl.remove(); } _validateInput() { if (this.isValidLength && this.isInvalid) { this.isInvalid = false; this.el.classList.remove('invalid'); } else if (!this.isValidLength && !this.isInvalid) { this.isInvalid = true; this.el.classList.remove('valid'); this.el.classList.add('invalid'); } } } exports.CharacterCounter = CharacterCounter; /***/ }), /***/ "./src/chips.ts": /*!**********************!*\ !*** ./src/chips.ts ***! \**********************/ /***/ (function(__unused_webpack_module, exports, __webpack_require__) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.Chips = void 0; const utils_1 = __webpack_require__(/*! ./utils */ "./src/utils.ts"); const autocomplete_1 = __webpack_require__(/*! ./autocomplete */ "./src/autocomplete.ts"); const component_1 = __webpack_require__(/*! ./component */ "./src/component.ts"); let _defaults = { data: [], placeholder: '', secondaryPlaceholder: '', closeIconClass: 'material-icons', autocompleteOptions: {}, autocompleteOnly: false, limit: Infinity, onChipAdd: null, onChipSelect: null, onChipDelete: null }; function gGetIndex(el) { return [...el.parentNode.children].indexOf(el); } class Chips extends component_1.Component { constructor(el, options) { super(el, options, Chips); this._handleChipClick = (e) => { const _chip = e.target.closest('.chip'); const clickedClose = e.target.classList.contains('close'); if (_chip) { const index = [..._chip.parentNode.children].indexOf(_chip); if (clickedClose) { this.deleteChip(index); this._input.focus(); } else { this.selectChip(index); } // Default handle click to focus on input } else { this._input.focus(); } }; this._handleInputFocus = () => { this.el.classList.add('focus'); }; this._handleInputBlur = () => { this.el.classList.remove('focus'); }; this._handleInputKeydown = (e) => { Chips._keydown = true; if (utils_1.Utils.keys.ENTER.includes(e.key)) { // Override enter if autocompleting. if (this.hasAutocomplete && this.autocomplete && this.autocomplete.isOpen) { return; } e.preventDefault(); if (!this.hasAutocomplete || (this.hasAutocomplete && !this.options.autocompleteOnly)) { this.addChip({ id: this._input.value }); } this._input.value = ''; } else if ((utils_1.Utils.keys.BACKSPACE.includes(e.key) || utils_1.Utils.keys.ARROW_LEFT.includes(e.key)) && this._input.value === '' && this.chipsData.length) { e.preventDefault(); this.selectChip(this.chipsData.length - 1); } }; this.el.M_Chips = this; this.options = Object.assign(Object.assign({}, Chips.defaults), options); this.el.classList.add('chips', 'input-field'); this.chipsData = []; this._chips = []; this._setupInput(); this.hasAutocomplete = Object.keys(this.options.autocompleteOptions).length > 0; // Set input id if (!this._input.getAttribute('id')) this._input.setAttribute('id', utils_1.Utils.guid()); // Render initial chips if (this.options.data.length) { this.chipsData = this.options.data; this._renderChips(); } // Setup autocomplete if needed if (this.hasAutocomplete) this._setupAutocomplete(); this._setPlaceholder(); this._setupLabel(); this._setupEventHandlers(); } static get defaults() { return _defaults; } /** * Initializes instances of Chips. * @param els HTML elements. * @param options Component options. */ static init(els, options = {}) { return super.init(els, options, Chips); } static getInstance(el) { return el.M_Chips; } getData() { return this.chipsData; } destroy() { this._removeEventHandlers(); this._chips.forEach(c => c.remove()); this._chips = []; this.el.M_Chips = undefined; } _setupEventHandlers() { this.el.addEventListener('click', this._handleChipClick); document.addEventListener('keydown', Chips._handleChipsKeydown); document.addEventListener('keyup', Chips._handleChipsKeyup); this.el.addEventListener('blur', Chips._handleChipsBlur, true); this._input.addEventListener('focus', this._handleInputFocus); this._input.addEventListener('blur', this._handleInputBlur); this._input.addEventListener('keydown', this._handleInputKeydown); } _removeEventHandlers() { this.el.removeEventListener('click', this._handleChipClick); document.removeEventListener('keydown', Chips._handleChipsKeydown); document.removeEventListener('keyup', Chips._handleChipsKeyup); this.el.removeEventListener('blur', Chips._handleChipsBlur, true); this._input.removeEventListener('focus', this._handleInputFocus); this._input.removeEventListener('blur', this._handleInputBlur); this._input.removeEventListener('keydown', this._handleInputKeydown); } static _handleChipsKeydown(e) { Chips._keydown = true; const chips = e.target.closest('.chips'); const chipsKeydown = e.target && chips; // Don't handle keydown inputs on input and textarea const tag = e.target.tagName; if (tag === 'INPUT' || tag === 'TEXTAREA' || !chipsKeydown) return; const currChips = chips.M_Chips; if (utils_1.Utils.keys.BACKSPACE.includes(e.key) || utils_1.Utils.keys.DELETE.includes(e.key)) { e.preventDefault(); let selectIndex = currChips.chipsData.length; if (currChips._selectedChip) { const index = gGetIndex(currChips._selectedChip); currChips.deleteChip(index); currChips._selectedChip = null; // Make sure selectIndex doesn't go negative selectIndex = Math.max(index - 1, 0); } if (currChips.chipsData.length) currChips.selectChip(selectIndex); else currChips._input.focus(); } else if (utils_1.Utils.keys.ARROW_LEFT.includes(e.key)) { if (currChips._selectedChip) { const selectIndex = gGetIndex(currChips._selectedChip) - 1; if (selectIndex < 0) return; currChips.selectChip(selectIndex); } } else if (utils_1.Utils.keys.ARROW_RIGHT.includes(e.key)) { if (currChips._selectedChip) { const selectIndex = gGetIndex(currChips._selectedChip) + 1; if (selectIndex >= currChips.chipsData.length) currChips._input.focus(); else currChips.selectChip(selectIndex); } } } static _handleChipsKeyup(e) { Chips._keydown = false; } static _handleChipsBlur(e) { if (!Chips._keydown && document.hidden) { const chips = e.target.closest('.chips'); const currChips = chips.M_Chips; currChips._selectedChip = null; } } _renderChip(chip) { if (!chip.id) return; const renderedChip = document.createElement('div'); renderedChip.classList.add('chip'); renderedChip.innerText = chip.text || chip.id; renderedChip.setAttribute('tabindex', "0"); const closeIcon = document.createElement('i'); closeIcon.classList.add(this.options.closeIconClass, 'close'); closeIcon.innerText = 'close'; // attach image if needed if (chip.image) { const img = document.createElement('img'); img.setAttribute('src', chip.image); renderedChip.insertBefore(img, renderedChip.firstChild); } renderedChip.appendChild(closeIcon); return renderedChip; } _renderChips() { this._chips = []; //.remove(); for (let i = 0; i < this.chipsData.length; i++) { const chipElem = this._renderChip(this.chipsData[i]); this.el.appendChild(chipElem); this._chips.push(chipElem); } // move input to end this.el.append(this._input); } _setupAutocomplete() { this.options.autocompleteOptions.onAutocomplete = (items) => { if (items.length > 0) this.addChip({ id: items[0].id, text: items[0].text, image: items[0].image }); this._input.value = ''; this._input.focus(); }; this.autocomplete = autocomplete_1.Autocomplete.init(this._input, this.options.autocompleteOptions); } _setupInput() { this._input = this.el.querySelector('input'); if (!this._input) { this._input = document.createElement('input'); this.el.append(this._input); } this._input.classList.add('input'); } _setupLabel() { this._label = this.el.querySelector('label'); if (this._label) this._label.setAttribute('for', this._input.getAttribute('id')); } _setPlaceholder() { if (this.chipsData !== undefined && !this.chipsData.length && this.options.placeholder) { this._input.placeholder = this.options.placeholder; } else if ((this.chipsData === undefined || !!this.chipsData.length) && this.options.secondaryPlaceholder) { this._input.placeholder = this.options.secondaryPlaceholder; } } _isValidAndNotExist(chip) { const isValid = !!chip.id; const doesNotExist = !this.chipsData.some(item => item.id == chip.id); return isValid && doesNotExist; } /** * Add chip to input. * @param chip Chip data object */ addChip(chip) { if (!this._isValidAndNotExist(chip) || this.chipsData.length >= this.options.limit) return; const renderedChip = this._renderChip(chip); this._chips.push(renderedChip); this.chipsData.push(chip); //$(this._input).before(renderedChip); this._input.before(renderedChip); this._setPlaceholder(); // fire chipAdd callback if (typeof this.options.onChipAdd === 'function') { this.options.onChipAdd(this.el, renderedChip); } } /** * Delete nth chip. * @param chipIndex Index of chip */ deleteChip(chipIndex) { const chip = this._chips[chipIndex]; this._chips[chipIndex].remove(); this._chips.splice(chipIndex, 1); this.chipsData.splice(chipIndex, 1); this._setPlaceholder(); // fire chipDelete callback if (typeof this.options.onChipDelete === 'function') { this.options.onChipDelete(this.el, chip); } } /** * Select nth chip. * @param chipIndex Index of chip */ selectChip(chipIndex) { const chip = this._chips[chipIndex]; this._selectedChip = chip; chip.focus(); // fire chipSelect callback if (typeof this.options.onChipSelect === 'function') { this.options.onChipSelect(this.el, chip); } } static Init() { document.addEventListener("DOMContentLoaded", () => { // Handle removal of static chips. document.body.addEventListener('click', e => { if (e.target.closest('.chip .close')) { const chips = e.target.closest('.chips'); if (chips && chips.M_Chips == undefined) return; e.target.closest('.chip').remove(); } }); }); } } exports.Chips = Chips; (() => { Chips._keydown = false; })(); /***/ }), /***/ "./src/collapsible.ts": /*!****************************!*\ !*** ./src/collapsible.ts ***! \****************************/ /***/ (function(__unused_webpack_module, exports, __webpack_require__) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.Collapsible = void 0; const utils_1 = __webpack_require__(/*! ./utils */ "./src/utils.ts"); const component_1 = __webpack_require__(/*! ./component */ "./src/component.ts"); const _defaults = { accordion: true, onOpenStart: null, onOpenEnd: null, onCloseStart: null, onCloseEnd: null, inDuration: 300, outDuration: 300 }; class Collapsible extends component_1.Component { constructor(el, options) { super(el, options, Collapsible); this._handleCollapsibleClick = (e) => { const header = e.target.closest('.collapsible-header'); if (e.target && header) { const collapsible = header.closest('.collapsible'); if (collapsible !== this.el) return; const li = header.closest('li'); const isActive = li.classList.contains('active'); const index = [...li.parentNode.children].indexOf(li); if (isActive) this.close(index); else this.open(index); } }; this._handleCollapsibleKeydown = (e) => { if (utils_1.Utils.keys.ENTER.includes(e.key)) { this._handleCollapsibleClick(e); } }; /** * Open collapsible section. * @param n Nth section to open. */ this.open = (index) => { const listItems = Array.from(this.el.children).filter(c => c.tagName === 'LI'); const li = listItems[index]; if (li && !li.classList.contains('active')) { // onOpenStart callback if (typeof this.options.onOpenStart === 'function') { this.options.onOpenStart.call(this, li); } // Handle accordion behavior if (this.options.accordion) { const activeLis = listItems.filter(li => li.classList.contains('active')); activeLis.forEach(activeLi => { const index = listItems.indexOf(activeLi); this.close(index); }); } // Animate in li.classList.add('active'); this._animateIn(index); } }; /** * Close collapsible section. * @param n Nth section to close. */ this.close = (index) => { const li = Array.from(this.el.children).filter(c => c.tagName === 'LI')[index]; if (li && li.classList.contains('active')) { // onCloseStart callback if (typeof this.options.onCloseStart === 'function') { this.options.onCloseStart.call(this, li); } // Animate out li.classList.remove('active'); this._animateOut(index); } }; this.el.M_Collapsible = this; this.options = Object.assign(Object.assign({}, Collapsible.defaults), options); // Setup tab indices this._headers = Array.from(this.el.querySelectorAll('li > .collapsible-header')); this._headers.forEach(el => el.tabIndex = 0); this._setupEventHandlers(); // Open active const activeBodies = Array.from(this.el.querySelectorAll('li.active > .collapsible-body')); if (this.options.accordion) { if (activeBodies.length > 0) { // Accordion => open first active only this._setExpanded(activeBodies[0]); } } else { // Expandables => all active activeBodies.forEach(el => this._setExpanded(el)); } } static get defaults() { return _defaults; } /** * Initializes instances of Collapsible. * @param els HTML elements. * @param options Component options. */ static init(els, options = {}) { return super.init(els, options, Collapsible); } static getInstance(el) { return el.M_Collapsible; } destroy() { this._removeEventHandlers(); this.el.M_Collapsible = undefined; } _setupEventHandlers() { this.el.addEventListener('click', this._handleCollapsibleClick); this._headers.forEach(header => header.addEventListener('keydown', this._handleCollapsibleKeydown)); } _removeEventHandlers() { this.el.removeEventListener('click', this._handleCollapsibleClick); this._headers.forEach(header => header.removeEventListener('keydown', this._handleCollapsibleKeydown)); } _setExpanded(li) { li.style.maxHeight = li.scrollHeight + "px"; } _animateIn(index) { const li = this.el.children[index]; if (!li) return; const body = li.querySelector('.collapsible-body'); const duration = this.options.inDuration; // easeInOutCubic body.style.transition = `max-height ${duration}ms ease-out`; this._setExpanded(body); setTimeout(() => { if (typeof this.options.onOpenEnd === 'function') { this.options.onOpenEnd.call(this, li); } }, duration); } _animateOut(index) { const li = this.el.children[index]; if (!li) return; const body = li.querySelector('.collapsible-body'); const duration = this.options.outDuration; // easeInOutCubic body.style.transition = `max-height ${duration}ms ease-out`; body.style.maxHeight = "0"; setTimeout(() => { if (typeof this.options.onCloseEnd === 'function') { this.options.onCloseEnd.call(this, li); } }, duration); } } exports.Collapsible = Collapsible; /***/ }), /***/ "./src/component.ts": /*!**************************!*\ !*** ./src/component.ts ***! \**************************/ /***/ (function(__unused_webpack_module, exports) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.Component = void 0; ; ; /** * Base class implementation for Materialize components. */ class Component { /** * Constructs component instance and set everything up. */ constructor(el, options, classDef) { // Display error if el is not a valid HTML Element if (!(el instanceof HTMLElement)) { console.error(Error(el + ' is not an HTML Element')); } // If exists, destroy and reinitialize in child let ins = classDef.getInstance(el); if (!!ins) { ins.destroy(); } this.el = el; } /** * Initializes component instances. * @param els HTML elements. * @param options Component options. * @param classDef Class definition. */ static init(els, options, classDef) { let instances = null; if (els instanceof Element) { instances = new classDef(els, options); } else if (!!els && els.length) { instances = []; for (let i = 0; i < els.length; i++) { instances.push(new classDef(els[i], options)); } } return instances; } /** * @returns default options for component instance. */ static get defaults() { return {}; } /** * Retrieves component instance for the given element. * @param el Associated HTML Element. */ static getInstance(el) { throw new Error("This method must be implemented."); } /** * Destroy plugin instance and teardown. */ destroy() { throw new Error("This method must be implemented."); } } exports.Component = Component; /***/ }), /***/ "./src/datepicker.ts": /*!***************************!*\ !*** ./src/datepicker.ts ***! \***************************/ /***/ (function(__unused_webpack_module, exports, __webpack_require__) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.Datepicker = void 0; const modal_1 = __webpack_require__(/*! ./modal */ "./src/modal.ts"); const utils_1 = __webpack_require__(/*! ./utils */ "./src/utils.ts"); const select_1 = __webpack_require__(/*! ./select */ "./src/select.ts"); const component_1 = __webpack_require__(/*! ./component */ "./src/component.ts"); ; let _defaults = { // Close when date is selected autoClose: false, // the default output format for the input field value format: 'mmm dd, yyyy', // Used to create date object from current input string parse: null, // The initial date to view when first opened defaultDate: null, // Make the `defaultDate` the initial selected value setDefaultDate: false, disableWeekends: false, disableDayFn: null, // First day of week (0: Sunday, 1: Monday etc) firstDay: 0, // The earliest date that can be selected minDate: null, // Thelatest date that can be selected maxDate: null, // Number of years either side, or array of upper/lower range yearRange: 10, // used internally (don't config outside) minYear: 0, maxYear: 9999, minMonth: undefined, maxMonth: undefined, startRange: null, endRange: null, isRTL: false, yearRangeReverse: false, // Render the month after year in the calendar title showMonthAfterYear: false, // Render days of the calendar grid that fall in the next or previous month showDaysInNextAndPreviousMonths: false, // Specify a DOM element to render the calendar in container: null, // Show clear button showClearBtn: false, // internationalization i18n: { cancel: 'Cancel', clear: 'Clear', done: 'Ok', previousMonth: '‹', nextMonth: '›', months: [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ], monthsShort: [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ], weekdays: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], weekdaysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], weekdaysAbbrev: ['S', 'M', 'T', 'W', 'T', 'F', 'S'] }, // events array events: [], // callback function onSelect: null, onOpen: null, onClose: null, onDraw: null }; class Datepicker extends component_1.Component { constructor(el, options) { super(el, options, Datepicker); this._handleInputClick = () => { this.open(); }; this._handleInputKeydown = (e) => { if (utils_1.Utils.keys.ENTER.includes(e.key)) { e.preventDefault(); this.open(); } }; this._handleCalendarClick = (e) => { if (!this.isOpen) return; const target = (e.target); if (!target.classList.contains('is-disabled')) { if (target.classList.contains('datepicker-day-button') && !target.classList.contains('is-empty') && !target.parentElement.classList.contains('is-disabled')) { this.setDate(new Date(e.target.getAttribute('data-year'), e.target.getAttribute('data-month'), e.target.getAttribute('data-day'))); if (this.options.autoClose) { this._finishSelection(); } } else if (target.closest('.month-prev')) { this.prevMonth(); } else if (target.closest('.month-next')) { this.nextMonth(); } } }; this._handleClearClick = () => { this.date = null; this.setInputValue(); this.close(); }; this._handleMonthChange = (e) => { this.gotoMonth(e.target.value); }; this._handleYearChange = (e) => { this.gotoYear(e.target.value); }; this._handleInputChange = (e) => { var _a; let date; // Prevent change event from being fired when triggered by the plugin if (((_a = e['detail']) === null || _a === void 0 ? void 0 : _a.firedBy) === this) return; if (this.options.parse) { date = this.options.parse(this.el.value, typeof this.options.format === "function" ? this.options.format(new Date(this.el.value)) : this.options.format); } else { date = new Date(Date.parse(this.el.value)); } if (Datepicker._isDate(date)) this.setDate(date); }; // Set input value to the selected date and close Datepicker this._finishSelection = () => { this.setInputValue(); this.close(); }; /** * Open datepicker. */ this.open = () => { if (this.isOpen) return; this.isOpen = true; if (typeof this.options.onOpen === 'function') { this.options.onOpen.call(this); } this.draw(); this.modal.open(undefined); return this; }; /** * Close datepicker. */ this.close = () => { if (!this.isOpen) return; this.isOpen = false; if (typeof this.options.onClose === 'function') { this.options.onClose.call(this); } this.modal.close(); return this; }; this.el.M_Datepicker = this; this.options = Object.assign(Object.assign({}, Datepicker.defaults), options); // make sure i18n defaults are not lost when only few i18n option properties are passed if (!!options && options.hasOwnProperty('i18n') && typeof options.i18n === 'object') { this.options.i18n = Object.assign(Object.assign({}, Datepicker.defaults.i18n), options.i18n); } // Remove time component from minDate and maxDate options if (this.options.minDate) this.options.minDate.setHours(0, 0, 0, 0); if (this.options.maxDate) this.options.maxDate.setHours(0, 0, 0, 0); this.id = utils_1.Utils.guid(); this._setupVariables(); this._insertHTMLIntoDOM(); this._setupModal(); this._setupEventHandlers(); if (!this.options.defaultDate) { this.options.defaultDate = new Date(Date.parse(this.el.value)); } let defDate = this.options.defaultDate; if (Datepicker._isDate(defDate)) { if (this.options.setDefaultDate) { this.setDate(defDate, true); this.setInputValue(); } else { this.gotoDate(defDate); } } else { this.gotoDate(new Date()); } this.isOpen = false; } static get defaults() { return _defaults; } /** * Initializes instances of Datepicker. * @param els HTML elements. * @param options Component options. */ static init(els, options = {}) { return super.init(els, options, Datepicker); } static _isDate(obj) { return /Date/.test(Object.prototype.toString.call(obj)) && !isNaN(obj.getTime()); } static _isWeekend(date) { let day = date.getDay(); return day === 0 || day === 6; } static _setToStartOfDay(date) { if (Datepicker._isDate(date)) date.setHours(0, 0, 0, 0); } static _getDaysInMonth(year, month) { return [31, Datepicker._isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; } static _isLeapYear(year) { // solution by Matti Virkkunen: http://stackoverflow.com/a/4881951 return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; } static _compareDates(a, b) { // weak date comparison (use setToStartOfDay(date) to ensure correct result) return a.getTime() === b.getTime(); } static getInstance(el) { return el.M_Datepicker; } destroy() { this._removeEventHandlers(); this.modal.destroy(); this.modalEl.remove(); this.destroySelects(); this.el.M_Datepicker = undefined; } destroySelects() { let oldYearSelect = this.calendarEl.querySelector('.orig-select-year'); if (oldYearSelect) { select_1.FormSelect.getInstance(oldYearSelect).destroy(); } let oldMonthSelect = this.calendarEl.querySelector('.orig-select-month'); if (oldMonthSelect) { select_1.FormSelect.getInstance(oldMonthSelect).destroy(); } } _insertHTMLIntoDOM() { if (this.options.showClearBtn) { this.clearBtn.style.visibility = ''; this.clearBtn.innerText = this.options.i18n.clear; } this.doneBtn.innerText = this.options.i18n.done; this.cancelBtn.innerText = this.options.i18n.cancel; if (this.options.container) { const optEl = this.options.container; this.options.container = optEl instanceof HTMLElement ? optEl : document.querySelector(optEl); this.options.container.append(this.modalEl); } else { //this.modalEl.before(this.el); this.el.parentElement.appendChild(this.modalEl); } } _setupModal() { this.modalEl.id = 'modal-' + this.id; this.modal = modal_1.Modal.init(this.modalEl, { onCloseEnd: () => { this.isOpen = false; } }); } /** * Gets a string representation of the selected date. */ toString(format = null) { format = format || this.options.format; if (typeof format === 'function') return format(this.date); if (!Datepicker._isDate(this.date)) return ''; // String Format const formatArray = format.split(/(d{1,4}|m{1,4}|y{4}|yy|!.)/g); const formattedDate = formatArray .map(label => this.formats[label] ? this.formats[label]() : label) .join(''); return formattedDate; } /** * Set a date on the datepicker. * @param date Date to set on the datepicker. * @param preventOnSelect Undocumented as of 5 March 2018. */ setDate(date = null, preventOnSelect = false) { if (!date) { this.date = null; this._renderDateDisplay(); return this.draw(); } if (typeof date === 'string') { date = new Date(Date.parse(date)); } if (!Datepicker._isDate(date)) { return; } let min = this.options.minDate, max = this.options.maxDate; if (Datepicker._isDate(min) && date < min) { date = min; } else if (Datepicker._isDate(max) && date > max) { date = max; } this.date = new Date(date.getTime()); this._renderDateDisplay(); Datepicker._setToStartOfDay(this.date); this.gotoDate(this.date); if (!preventOnSelect && typeof this.options.onSelect === 'function') { this.options.onSelect.call(this, this.date); } } /** * Sets current date as the input value. */ setInputValue() { this.el.value = this.toString(); this.el.dispatchEvent(new CustomEvent('change', { bubbles: true, cancelable: true, composed: true, detail: { firedBy: this } })); } _renderDateDisplay() { let displayDate = Datepicker._isDate(this.date) ? this.date : new Date(); let i18n = this.options.i18n; let day = i18n.weekdaysShort[displayDate.getDay()]; let month = i18n.monthsShort[displayDate.getMonth()]; let date = displayDate.getDate(); this.yearTextEl.innerHTML = displayDate.getFullYear().toString(); this.dateTextEl.innerHTML = `${day}, ${month} ${date}`; } /** * Change date view to a specific date on the datepicker. * @param date Date to show on the datepicker. */ gotoDate(date) { let newCalendar = true; if (!Datepicker._isDate(date)) { return; } if (this.calendars) { let firstVisibleDate = new Date(this.calendars[0].year, this.calendars[0].month, 1), lastVisibleDate = new Date(this.calendars[this.calendars.length - 1].year, this.calendars[this.calendars.length - 1].month, 1), visibleDate = date.getTime(); // get the end of the month lastVisibleDate.setMonth(lastVisibleDate.getMonth() + 1); lastVisibleDate.setDate(lastVisibleDate.getDate() - 1); newCalendar = visibleDate < firstVisibleDate.getTime() || lastVisibleDate.getTime() < visibleDate; } if (newCalendar) { this.calendars = [ { month: date.getMonth(), year: date.getFullYear() } ]; } this.adjustCalendars(); } adjustCalendars() { this.calendars[0] = this.adjustCalendar(this.calendars[0]); this.draw(); } adjustCalendar(calendar) { if (calendar.month < 0) { calendar.year -= Math.ceil(Math.abs(calendar.month) / 12); calendar.month += 12; } if (calendar.month > 11) { calendar.year += Math.floor(Math.abs(calendar.month) / 12); calendar.month -= 12; } return calendar; } nextMonth() { this.calendars[0].month++; this.adjustCalendars(); } prevMonth() { this.calendars[0].month--; this.adjustCalendars(); } render(year, month, randId) { let opts = this.options, now = new Date(), days = Datepicker._getDaysInMonth(year, month), before = new Date(year, month, 1).getDay(), data = [], row = []; Datepicker._setToStartOfDay(now); if (opts.firstDay > 0) { before -= opts.firstDay; if (before < 0) { before += 7; } } let previousMonth = month === 0 ? 11 : month - 1, nextMonth = month === 11 ? 0 : month + 1, yearOfPreviousMonth = month === 0 ? year - 1 : year, yearOfNextMonth = month === 11 ? year + 1 : year, daysInPreviousMonth = Datepicker._getDaysInMonth(yearOfPreviousMonth, previousMonth); let cells = days + before, after = cells; while (after > 7) { after -= 7; } cells += 7 - after; let isWeekSelected = false; for (let i = 0, r = 0; i < cells; i++) { let day = new Date(year, month, 1 + (i - before)), isSelected = Datepicker._isDate(this.date) ? Datepicker._compareDates(day, this.date) : false, isToday = Datepicker._compareDates(day, now), hasEvent = opts.events.indexOf(day.toDateString()) !== -1 ? true : false, isEmpty = i < before || i >= days + before, dayNumber = 1 + (i - before), monthNumber = month, yearNumber = year, isStartRange = opts.startRange && Datepicker._compareDates(opts.startRange, day), isEndRange = opts.endRange && Datepicker._compareDates(opts.endRange, day), isInRange = opts.startRange && opts.endRange && opts.startRange < day && day < opts.endRange, isDisabled = (opts.minDate && day < opts.minDate) || (opts.maxDate && day > opts.maxDate) || (opts.disableWeekends && Datepicker._isWeekend(day)) || (opts.disableDayFn && opts.disableDayFn(day)); if (isEmpty) { if (i < before) { dayNumber = daysInPreviousMonth + dayNumber; monthNumber = previousMonth; yearNumber = yearOfPreviousMonth; } else { dayNumber = dayNumber - days; monthNumber = nextMonth; yearNumber = yearOfNextMonth; } } let dayConfig = { day: dayNumber, month: monthNumber, year: yearNumber, hasEvent: hasEvent, isSelected: isSelected, isToday: isToday, isDisabled: isDisabled, isEmpty: isEmpty, isStartRange: isStartRange, isEndRange: isEndRange, isInRange: isInRange, showDaysInNextAndPreviousMonths: opts.showDaysInNextAndPreviousMonths }; row.push(this.renderDay(dayConfig)); if (++r === 7) { data.push(this.renderRow(row, opts.isRTL, isWeekSelected)); row = []; r = 0; isWeekSelected = false; } } return this.renderTable(opts, data, randId); } renderDay(opts) { let arr = []; let ariaSelected = 'false'; if (opts.isEmpty) { if (opts.showDaysInNextAndPreviousMonths) { arr.push('is-outside-current-month'); arr.push('is-selection-disabled'); } else { return ''; } } if (opts.isDisabled) { arr.push('is-disabled'); } if (opts.isToday) { arr.push('is-today'); } if (opts.isSelected) { arr.push('is-selected'); ariaSelected = 'true'; } if (opts.hasEvent) { arr.push('has-event'); } if (opts.isInRange) { arr.push('is-inrange'); } if (opts.isStartRange) { arr.push('is-startrange'); } if (opts.isEndRange) { arr.push('is-endrange'); } return (`` + `` + ''); } renderRow(days, isRTL, isRowSelected) { return ('' + (isRTL ? days.reverse() : days).join('') + ''); } renderTable(opts, data, randId) { return ('
' + this.renderHead(opts) + this.renderBody(data) + '
'); } renderHead(opts) { let i, arr = []; for (i = 0; i < 7; i++) { arr.push(`${this.renderDayName(opts, i, true)}`); } return '' + (opts.isRTL ? arr.reverse() : arr).join('') + ''; } renderBody(rows) { return '' + rows.join('') + ''; } renderTitle(instance, c, year, month, refYear, randId) { let i, j, arr, opts = this.options, isMinYear = year === opts.minYear, isMaxYear = year === opts.maxYear, html = '
', monthHtml, yearHtml, prev = true, next = true; for (arr = [], i = 0; i < 12; i++) { arr.push(''); } monthHtml = ''; if (Array.isArray(opts.yearRange)) { i = opts.yearRange[0]; j = opts.yearRange[1] + 1; } else { i = year - opts.yearRange; j = 1 + year + opts.yearRange; } for (arr = []; i < j && i <= opts.maxYear; i++) { if (i >= opts.minYear) { arr.push(``); } } if (opts.yearRangeReverse) arr.reverse(); yearHtml = ``; let leftArrow = ''; html += ``; html += '
'; if (opts.showMonthAfterYear) { html += yearHtml + monthHtml; } else { html += monthHtml + yearHtml; } html += '
'; if (isMinYear && (month === 0 || opts.minMonth >= month)) { prev = false; } if (isMaxYear && (month === 11 || opts.maxMonth <= month)) { next = false; } let rightArrow = ''; html += ``; return (html += '
'); } // refresh HTML draw(force = false) { if (!this.isOpen && !force) return; let opts = this.options, minYear = opts.minYear, maxYear = opts.maxYear, minMonth = opts.minMonth, maxMonth = opts.maxMonth, html = '', randId; if (this._y <= minYear) { this._y = minYear; if (!isNaN(minMonth) && this._m < minMonth) { this._m = minMonth; } } if (this._y >= maxYear) { this._y = maxYear; if (!isNaN(maxMonth) && this._m > maxMonth) { this._m = maxMonth; } } randId = 'datepicker-title-' + Math.random() .toString(36) .replace(/[^a-z]+/g, '') .substr(0, 2); for (let c = 0; c < 1; c++) { this._renderDateDisplay(); html += this.renderTitle(this, c, this.calendars[c].year, this.calendars[c].month, this.calendars[0].year, randId) + this.render(this.calendars[c].year, this.calendars[c].month, randId); } this.destroySelects(); this.calendarEl.innerHTML = html; // Init Materialize Select let yearSelect = this.calendarEl.querySelector('.orig-select-year'); let monthSelect = this.calendarEl.querySelector('.orig-select-month'); select_1.FormSelect.init(yearSelect, { classes: 'select-year', dropdownOptions: { container: document.body, constrainWidth: false } }); select_1.FormSelect.init(monthSelect, { classes: 'select-month', dropdownOptions: { container: document.body, constrainWidth: false } }); // Add change handlers for select yearSelect.addEventListener('change', this._handleYearChange); monthSelect.addEventListener('change', this._handleMonthChange); if (typeof this.options.onDraw === 'function') { this.options.onDraw.call(this); } } _setupEventHandlers() { this.el.addEventListener('click', this._handleInputClick); this.el.addEventListener('keydown', this._handleInputKeydown); this.el.addEventListener('change', this._handleInputChange); this.calendarEl.addEventListener('click', this._handleCalendarClick); this.doneBtn.addEventListener('click', this._finishSelection); this.cancelBtn.addEventListener('click', this.close); if (this.options.showClearBtn) { this.clearBtn.addEventListener('click', this._handleClearClick); } } _setupVariables() { const template = document.createElement('template'); template.innerHTML = Datepicker._template.trim(); this.modalEl = template.content.firstChild; this.calendarEl = this.modalEl.querySelector('.datepicker-calendar'); this.yearTextEl = this.modalEl.querySelector('.year-text'); this.dateTextEl = this.modalEl.querySelector('.date-text'); if (this.options.showClearBtn) { this.clearBtn = this.modalEl.querySelector('.datepicker-clear'); } this.doneBtn = this.modalEl.querySelector('.datepicker-done'); this.cancelBtn = this.modalEl.querySelector('.datepicker-cancel'); this.formats = { d: () => { return this.date.getDate(); }, dd: () => { let d = this.date.getDate(); return (d < 10 ? '0' : '') + d; }, ddd: () => { return this.options.i18n.weekdaysShort[this.date.getDay()]; }, dddd: () => { return this.options.i18n.weekdays[this.date.getDay()]; }, m: () => { return this.date.getMonth() + 1; }, mm: () => { let m = this.date.getMonth() + 1; return (m < 10 ? '0' : '') + m; }, mmm: () => { return this.options.i18n.monthsShort[this.date.getMonth()]; }, mmmm: () => { return this.options.i18n.months[this.date.getMonth()]; }, yy: () => { return ('' + this.date.getFullYear()).slice(2); }, yyyy: () => { return this.date.getFullYear(); } }; } _removeEventHandlers() { this.el.removeEventListener('click', this._handleInputClick); this.el.removeEventListener('keydown', this._handleInputKeydown); this.el.removeEventListener('change', this._handleInputChange); this.calendarEl.removeEventListener('click', this._handleCalendarClick); } // change view to a specific month (zero-index, e.g. 0: January) gotoMonth(month) { if (!isNaN(month)) { this.calendars[0].month = parseInt(month, 10); this.adjustCalendars(); } } // change view to a specific full year (e.g. "2012") gotoYear(year) { if (!isNaN(year)) { this.calendars[0].year = parseInt(year, 10); this.adjustCalendars(); } } renderDayName(opts, day, abbr = false) { day += opts.firstDay; while (day >= 7) { day -= 7; } return abbr ? opts.i18n.weekdaysAbbrev[day] : opts.i18n.weekdays[day]; } } exports.Datepicker = Datepicker; (() => { Datepicker._template = ` `; })(); /***/ }), /***/ "./src/dropdown.ts": /*!*************************!*\ !*** ./src/dropdown.ts ***! \*************************/ /***/ (function(__unused_webpack_module, exports, __webpack_require__) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.Dropdown = void 0; const utils_1 = __webpack_require__(/*! ./utils */ "./src/utils.ts"); const component_1 = __webpack_require__(/*! ./component */ "./src/component.ts"); ; const _defaults = { alignment: 'left', autoFocus: true, constrainWidth: true, container: null, coverTrigger: true, closeOnClick: true, hover: false, inDuration: 150, outDuration: 250, onOpenStart: null, onOpenEnd: null, onCloseStart: null, onCloseEnd: null, onItemClick: null }; class Dropdown extends component_1.Component { constructor(el, options) { super(el, options, Dropdown); this._handleClick = (e) => { e.preventDefault(); if (this.isOpen) { this.close(); } else { this.open(); } }; this._handleMouseEnter = () => { this.open(); }; this._handleMouseLeave = (e) => { const toEl = e.relatedTarget; const leaveToDropdownContent = !!toEl.closest('.dropdown-content'); let leaveToActiveDropdownTrigger = false; const closestTrigger = toEl.closest('.dropdown-trigger'); if (closestTrigger && !!closestTrigger.M_Dropdown && closestTrigger.M_Dropdown.isOpen) { leaveToActiveDropdownTrigger = true; } // Close hover dropdown if mouse did not leave to either active dropdown-trigger or dropdown-content if (!leaveToActiveDropdownTrigger && !leaveToDropdownContent) { this.close(); } }; this._handleDocumentClick = (e) => { const target = e.target; if (this.options.closeOnClick && target.closest('.dropdown-content') && !this.isTouchMoving) { // isTouchMoving to check if scrolling on mobile. this.close(); } else if (!target.closest('.dropdown-content')) { // Do this one frame later so that if the element clicked also triggers _handleClick // For example, if a label for a select was clicked, that we don't close/open the dropdown setTimeout(() => { if (this.isOpen) { this.close(); } }, 0); } this.isTouchMoving = false; }; this._handleTriggerKeydown = (e) => { // ARROW DOWN OR ENTER WHEN SELECT IS CLOSED - open Dropdown const arrowDownOrEnter = utils_1.Utils.keys.ARROW_DOWN.includes(e.key) || utils_1.Utils.keys.ENTER.includes(e.key); if (arrowDownOrEnter && !this.isOpen) { e.preventDefault(); this.open(); } }; this._handleDocumentTouchmove = (e) => { const target = e.target; if (target.closest('.dropdown-content')) { this.isTouchMoving = true; } }; this._handleDropdownClick = (e) => { // onItemClick callback if (typeof this.options.onItemClick === 'function') { const itemEl = e.target.closest('li'); this.options.onItemClick.call(this, itemEl); } }; this._handleDropdownKeydown = (e) => { const arrowUpOrDown = utils_1.Utils.keys.ARROW_DOWN.includes(e.key) || utils_1.Utils.keys.ARROW_UP.includes(e.key); if (utils_1.Utils.keys.TAB.includes(e.key)) { e.preventDefault(); this.close(); } // Navigate down dropdown list else if (arrowUpOrDown && this.isOpen) { e.preventDefault(); const direction = utils_1.Utils.keys.ARROW_DOWN.includes(e.key) ? 1 : -1; let newFocusedIndex = this.focusedIndex; let hasFoundNewIndex = false; do { newFocusedIndex = newFocusedIndex + direction; if (!!this.dropdownEl.children[newFocusedIndex] && this.dropdownEl.children[newFocusedIndex].tabIndex !== -1) { hasFoundNewIndex = true; break; } } while (newFocusedIndex < this.dropdownEl.children.length && newFocusedIndex >= 0); if (hasFoundNewIndex) { // Remove active class from old element if (this.focusedIndex >= 0) this.dropdownEl.children[this.focusedIndex].classList.remove('active'); this.focusedIndex = newFocusedIndex; this._focusFocusedItem(); } } // ENTER selects choice on focused item else if (utils_1.Utils.keys.ENTER.includes(e.key) && this.isOpen) { // Search for and `; arrLi.push(li); ul.append(li); }); this.el.append(ul); this._indicators = arrLi; } } _removeIndicators() { this.el.querySelector('ul.indicators').remove(); //find('ul.indicators').remove(); } set(index) { // Wrap around indices. if (index >= this._slides.length) index = 0; else if (index < 0) index = this._slides.length - 1; // Only do if index changes if (this.activeIndex === index) return; this._activeSlide = this._slides[this.activeIndex]; const _caption = this._activeSlide.querySelector('.caption'); this._activeSlide.classList.remove('active'); // Enables every slide this._slides.forEach(slide => slide.style.visibility = 'visible'); //--- Hide active Slide + Caption this._activeSlide.style.opacity = '0'; setTimeout(() => { this._slides.forEach(slide => { if (slide.classList.contains('active')) return; slide.style.opacity = '0'; slide.style.transform = 'translate(0, 0)'; // Disables invisible slides (for assistive technologies) slide.style.visibility = 'hidden'; }); }, this.options.duration); // Hide active Caption //this._animateCaptionIn(_caption, this.options.duration); _caption.style.opacity = '0'; // Update indicators if (this.options.indicators) { const activeIndicator = this._indicators[this.activeIndex].children[0]; const nextIndicator = this._indicators[index].children[0]; activeIndicator.classList.remove('active'); nextIndicator.classList.add('active'); if (typeof this.options.indicatorLabelFunc === "function") { activeIndicator.ariaLabel = this.options.indicatorLabelFunc.call(this, this.activeIndex, false); nextIndicator.ariaLabel = this.options.indicatorLabelFunc.call(this, index, true); } } //--- Show new Slide + Caption this._animateSlide(this._slides[index], true); this._slides[index].classList.add('active'); this.activeIndex = index; // Reset interval, if allowed. This check prevents autostart // when slider is paused, since it can be changed though indicators. if (this.interval != null) { this.start(); } } _pause(fromEvent) { clearInterval(this.interval); this.eventPause = fromEvent; this.interval = null; } } exports.Slider = Slider; /***/ }), /***/ "./src/tabs.ts": /*!*********************!*\ !*** ./src/tabs.ts ***! \*********************/ /***/ (function(__unused_webpack_module, exports, __webpack_require__) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.Tabs = void 0; const carousel_1 = __webpack_require__(/*! ./carousel */ "./src/carousel.ts"); const component_1 = __webpack_require__(/*! ./component */ "./src/component.ts"); ; let _defaults = { duration: 300, onShow: null, swipeable: false, responsiveThreshold: Infinity // breakpoint for swipeable }; class Tabs extends component_1.Component { constructor(el, options) { super(el, options, Tabs); this._handleWindowResize = () => { this._setTabsAndTabWidth(); if (this._tabWidth !== 0 && this._tabsWidth !== 0) { this._indicator.style.left = this._calcLeftPos(this._activeTabLink) + 'px'; this._indicator.style.right = this._calcRightPos(this._activeTabLink) + 'px'; } }; this._handleTabClick = (e) => { const tabLink = e.target; const tab = tabLink.parentElement; // Handle click on tab link only if (!tabLink || !tab.classList.contains('tab')) return; // is disabled? if (tab.classList.contains('disabled')) { e.preventDefault(); return; } // Act as regular link if target attribute is specified. if (tabLink.hasAttribute('target')) return; // Make the old tab inactive. this._activeTabLink.classList.remove('active'); const _oldContent = this._content; // Update the variables with the new link and content this._activeTabLink = tabLink; if (tabLink.hash) this._content = document.querySelector(tabLink.hash); this._tabLinks = this.el.querySelectorAll('li.tab > a'); // Make the tab active this._activeTabLink.classList.add('active'); const prevIndex = this._index; this._index = Math.max(Array.from(this._tabLinks).indexOf(tabLink), 0); // Swap content if (this.options.swipeable) { if (this._tabsCarousel) { this._tabsCarousel.set(this._index, () => { if (typeof this.options.onShow === 'function') this.options.onShow.call(this, this._content); }); } } else { if (this._content) { this._content.style.display = 'block'; this._content.classList.add('active'); if (typeof this.options.onShow === 'function') this.options.onShow.call(this, this._content); if (_oldContent && _oldContent !== this._content) { _oldContent.style.display = 'none'; _oldContent.classList.remove('active'); } } } // Update widths after content is swapped (scrollbar bugfix) this._setTabsAndTabWidth(); this._animateIndicator(prevIndex); e.preventDefault(); }; this.el.M_Tabs = this; this.options = Object.assign(Object.assign({}, Tabs.defaults), options); this._tabLinks = this.el.querySelectorAll('li.tab > a'); this._index = 0; this._setupActiveTabLink(); if (this.options.swipeable) { this._setupSwipeableTabs(); } else { this._setupNormalTabs(); } // Setup tabs indicator after content to ensure accurate widths this._setTabsAndTabWidth(); this._createIndicator(); this._setupEventHandlers(); } static get defaults() { return _defaults; } /** * Initializes instances of Tabs. * @param els HTML elements. * @param options Component options. */ static init(els, options = {}) { return super.init(els, options, Tabs); } static getInstance(el) { return el.M_Tabs; } destroy() { this._removeEventHandlers(); this._indicator.parentNode.removeChild(this._indicator); if (this.options.swipeable) { this._teardownSwipeableTabs(); } else { this._teardownNormalTabs(); } this.el.M_Tabs = undefined; } /** * The index of tab that is currently shown. */ get index() { return this._index; } _setupEventHandlers() { window.addEventListener('resize', this._handleWindowResize); this.el.addEventListener('click', this._handleTabClick); } _removeEventHandlers() { window.removeEventListener('resize', this._handleWindowResize); this.el.removeEventListener('click', this._handleTabClick); } _createIndicator() { const indicator = document.createElement('li'); indicator.classList.add('indicator'); this.el.appendChild(indicator); this._indicator = indicator; this._indicator.style.left = this._calcLeftPos(this._activeTabLink) + 'px'; this._indicator.style.right = this._calcRightPos(this._activeTabLink) + 'px'; } _setupActiveTabLink() { // If the location.hash matches one of the links, use that as the active tab. this._activeTabLink = Array.from(this._tabLinks).find((a) => a.getAttribute('href') === location.hash); // If no match is found, use the first link or any with class 'active' as the initial active tab. if (!this._activeTabLink) { this._activeTabLink = this.el.querySelector('li.tab a.active'); } if (this._activeTabLink.length === 0) { this._activeTabLink = this.el.querySelector('li.tab a'); } Array.from(this._tabLinks).forEach((a) => a.classList.remove('active')); this._activeTabLink.classList.add('active'); this._index = Math.max(Array.from(this._tabLinks).indexOf(this._activeTabLink), 0); if (this._activeTabLink && this._activeTabLink.hash) { this._content = document.querySelector(this._activeTabLink.hash); if (this._content) this._content.classList.add('active'); } } _setupSwipeableTabs() { // Change swipeable according to responsive threshold if (window.innerWidth > this.options.responsiveThreshold) this.options.swipeable = false; const tabsContent = []; this._tabLinks.forEach(a => { if (a.hash) { const currContent = document.querySelector(a.hash); currContent.classList.add('carousel-item'); tabsContent.push(currContent); } }); // Create Carousel-Wrapper around Tab-Contents const tabsWrapper = document.createElement('div'); tabsWrapper.classList.add('tabs-content', 'carousel', 'carousel-slider'); // Wrap around tabsContent[0].parentElement.insertBefore(tabsWrapper, tabsContent[0]); tabsContent.forEach(tabContent => { tabsWrapper.appendChild(tabContent); tabContent.style.display = ''; }); // Keep active tab index to set initial carousel slide const tab = this._activeTabLink.parentElement; const activeTabIndex = Array.from(tab.parentNode.children).indexOf(tab); this._tabsCarousel = carousel_1.Carousel.init(tabsWrapper, { fullWidth: true, noWrap: true, onCycleTo: (item) => { const prevIndex = this._index; this._index = Array.from(item.parentNode.children).indexOf(item); this._activeTabLink.classList.remove('active'); this._activeTabLink = Array.from(this._tabLinks)[this._index]; this._activeTabLink.classList.add('active'); this._animateIndicator(prevIndex); if (typeof this.options.onShow === 'function') this.options.onShow.call(this, this._content); } }); // Set initial carousel slide to active tab this._tabsCarousel.set(activeTabIndex); } _teardownSwipeableTabs() { const tabsWrapper = this._tabsCarousel.el; this._tabsCarousel.destroy(); // Unwrap tabsWrapper.after(tabsWrapper.children); tabsWrapper.remove(); } _setupNormalTabs() { // Hide Tabs Content Array.from(this._tabLinks).forEach((a) => { if (a === this._activeTabLink) return; if (a.hash) { const currContent = document.querySelector(a.hash); if (currContent) currContent.style.display = 'none'; } }); } _teardownNormalTabs() { // show Tabs Content this._tabLinks.forEach((a) => { if (a.hash) { const currContent = document.querySelector(a.hash); if (currContent) currContent.style.display = ''; } }); } _setTabsAndTabWidth() { this._tabsWidth = this.el.getBoundingClientRect().width; this._tabWidth = Math.max(this._tabsWidth, this.el.scrollWidth) / this._tabLinks.length; } _calcRightPos(el) { return Math.ceil(this._tabsWidth - el.offsetLeft - el.getBoundingClientRect().width); } _calcLeftPos(el) { return Math.floor(el.offsetLeft); } /** * Recalculate tab indicator position. This is useful when * the indicator position is not correct. */ updateTabIndicator() { this._setTabsAndTabWidth(); this._animateIndicator(this._index); } _animateIndicator(prevIndex) { let leftDelay = 0, rightDelay = 0; const isMovingLeftOrStaying = (this._index - prevIndex >= 0); if (isMovingLeftOrStaying) leftDelay = 90; else rightDelay = 90; // in v1: easeOutQuad this._indicator.style.transition = ` left ${this.options.duration}ms ease-out ${leftDelay}ms, right ${this.options.duration}ms ease-out ${rightDelay}ms`; this._indicator.style.left = this._calcLeftPos(this._activeTabLink) + 'px'; this._indicator.style.right = this._calcRightPos(this._activeTabLink) + 'px'; } /** * Show tab content that corresponds to the tab with the id. * @param tabId The id of the tab that you want to switch to. */ select(tabId) { const tab = Array.from(this._tabLinks).find((a) => a.getAttribute('href') === '#' + tabId); if (tab) tab.click(); } } exports.Tabs = Tabs; /***/ }), /***/ "./src/tapTarget.ts": /*!**************************!*\ !*** ./src/tapTarget.ts ***! \**************************/ /***/ (function(__unused_webpack_module, exports, __webpack_require__) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.TapTarget = void 0; const utils_1 = __webpack_require__(/*! ./utils */ "./src/utils.ts"); const component_1 = __webpack_require__(/*! ./component */ "./src/component.ts"); ; let _defaults = { onOpen: null, onClose: null }; class TapTarget extends component_1.Component { constructor(el, options) { super(el, options, TapTarget); this._handleThrottledResize = utils_1.Utils.throttle(function () { this._handleResize(); }, 200).bind(this); this._handleTargetClick = () => { this.open(); }; this._handleOriginClick = () => { this.close(); }; this._handleResize = () => { this._calculatePositioning(); }; this._handleDocumentClick = (e) => { if (!e.target.closest('.tap-target-wrapper')) { this.close(); e.preventDefault(); e.stopPropagation(); } }; /** * Open Tap Target. */ this.open = () => { if (this.isOpen) return; // onOpen callback if (typeof this.options.onOpen === 'function') { this.options.onOpen.call(this, this._origin); } this.isOpen = true; this.wrapper.classList.add('open'); document.body.addEventListener('click', this._handleDocumentClick, true); document.body.addEventListener('touchend', this._handleDocumentClick); }; /** * Close Tap Target. */ this.close = () => { if (!this.isOpen) return; // onClose callback if (typeof this.options.onClose === 'function') { this.options.onClose.call(this, this._origin); } this.isOpen = false; this.wrapper.classList.remove('open'); document.body.removeEventListener('click', this._handleDocumentClick, true); document.body.removeEventListener('touchend', this._handleDocumentClick); }; this.el.M_TapTarget = this; this.options = Object.assign(Object.assign({}, TapTarget.defaults), options); this.isOpen = false; // setup this._origin = document.querySelector(`#${el.dataset.target}`); this._setup(); this._calculatePositioning(); this._setupEventHandlers(); } static get defaults() { return _defaults; } /** * Initializes instances of TapTarget. * @param els HTML elements. * @param options Component options. */ static init(els, options = {}) { return super.init(els, options, TapTarget); } static getInstance(el) { return el.M_TapTarget; } destroy() { this._removeEventHandlers(); this.el.TapTarget = undefined; } _setupEventHandlers() { this.el.addEventListener('click', this._handleTargetClick); this.originEl.addEventListener('click', this._handleOriginClick); // Resize window.addEventListener('resize', this._handleThrottledResize); } _removeEventHandlers() { this.el.removeEventListener('click', this._handleTargetClick); this.originEl.removeEventListener('click', this._handleOriginClick); window.removeEventListener('resize', this._handleThrottledResize); } _setup() { // Creating tap target this.wrapper = this.el.parentElement; this.waveEl = this.wrapper.querySelector('.tap-target-wave'); this.originEl = this.wrapper.querySelector('.tap-target-origin'); this.contentEl = this.el.querySelector('.tap-target-content'); // Creating wrapper if (!this.wrapper.classList.contains('.tap-target-wrapper')) { this.wrapper = document.createElement('div'); this.wrapper.classList.add('tap-target-wrapper'); this.el.before(this.wrapper); this.wrapper.append(this.el); } // Creating content if (!this.contentEl) { this.contentEl = document.createElement('div'); this.contentEl.classList.add('tap-target-content'); this.el.append(this.contentEl); } // Creating foreground wave if (!this.waveEl) { this.waveEl = document.createElement('div'); this.waveEl.classList.add('tap-target-wave'); // Creating origin if (!this.originEl) { this.originEl = this._origin.cloneNode(true); // .clone(true, true); this.originEl.classList.add('tap-target-origin'); this.originEl.removeAttribute('id'); this.originEl.removeAttribute('style'); this.waveEl.append(this.originEl); } this.wrapper.append(this.waveEl); } } _offset(el) { const box = el.getBoundingClientRect(); const docElem = document.documentElement; return { top: box.top + window.pageYOffset - docElem.clientTop, left: box.left + window.pageXOffset - docElem.clientLeft }; } _calculatePositioning() { // Element or parent is fixed position? let isFixed = getComputedStyle(this._origin).position === 'fixed'; if (!isFixed) { let currentElem = this._origin; const parents = []; while ((currentElem = currentElem.parentNode) && currentElem !== document) parents.push(currentElem); for (let i = 0; i < parents.length; i++) { isFixed = getComputedStyle(parents[i]).position === 'fixed'; if (isFixed) break; } } // Calculating origin const originWidth = this._origin.offsetWidth; const originHeight = this._origin.offsetHeight; const originTop = isFixed ? this._offset(this._origin).top - utils_1.Utils.getDocumentScrollTop() : this._offset(this._origin).top; const originLeft = isFixed ? this._offset(this._origin).left - utils_1.Utils.getDocumentScrollLeft() : this._offset(this._origin).left; // Calculating screen const windowWidth = window.innerWidth; const windowHeight = window.innerHeight; const scrollBarWidth = windowWidth - document.documentElement.clientWidth; const centerX = windowWidth / 2; const centerY = windowHeight / 2; const isLeft = originLeft <= centerX; const isRight = originLeft > centerX; const isTop = originTop <= centerY; const isBottom = originTop > centerY; const isCenterX = originLeft >= windowWidth * 0.25 && originLeft <= windowWidth * 0.75; // Calculating tap target const tapTargetWidth = this.el.offsetWidth; const tapTargetHeight = this.el.offsetHeight; const tapTargetTop = originTop + originHeight / 2 - tapTargetHeight / 2; const tapTargetLeft = originLeft + originWidth / 2 - tapTargetWidth / 2; const tapTargetPosition = isFixed ? 'fixed' : 'absolute'; // Calculating content const tapTargetTextWidth = isCenterX ? tapTargetWidth : tapTargetWidth / 2 + originWidth; const tapTargetTextHeight = tapTargetHeight / 2; const tapTargetTextTop = isTop ? tapTargetHeight / 2 : 0; const tapTargetTextBottom = 0; const tapTargetTextLeft = isLeft && !isCenterX ? tapTargetWidth / 2 - originWidth : 0; const tapTargetTextRight = 0; const tapTargetTextPadding = originWidth; const tapTargetTextAlign = isBottom ? 'bottom' : 'top'; // Calculating wave const tapTargetWaveWidth = originWidth > originHeight ? originWidth * 2 : originWidth * 2; const tapTargetWaveHeight = tapTargetWaveWidth; const tapTargetWaveTop = tapTargetHeight / 2 - tapTargetWaveHeight / 2; const tapTargetWaveLeft = tapTargetWidth / 2 - tapTargetWaveWidth / 2; // Setting tap target this.wrapper.style.top = isTop ? tapTargetTop + 'px' : ''; this.wrapper.style.right = isRight ? windowWidth - tapTargetLeft - tapTargetWidth - scrollBarWidth + 'px' : ''; this.wrapper.style.bottom = isBottom ? windowHeight - tapTargetTop - tapTargetHeight + 'px' : ''; this.wrapper.style.left = isLeft ? tapTargetLeft + 'px' : ''; this.wrapper.style.position = tapTargetPosition; // Setting content this.contentEl.style.width = tapTargetTextWidth + 'px'; this.contentEl.style.height = tapTargetTextHeight + 'px'; this.contentEl.style.top = tapTargetTextTop + 'px'; this.contentEl.style.right = tapTargetTextRight + 'px'; this.contentEl.style.bottom = tapTargetTextBottom + 'px'; this.contentEl.style.left = tapTargetTextLeft + 'px'; this.contentEl.style.padding = tapTargetTextPadding + 'px'; this.contentEl.style.verticalAlign = tapTargetTextAlign; // Setting wave this.waveEl.style.top = tapTargetWaveTop + 'px'; this.waveEl.style.left = tapTargetWaveLeft + 'px'; this.waveEl.style.width = tapTargetWaveWidth + 'px'; this.waveEl.style.height = tapTargetWaveHeight + 'px'; } } exports.TapTarget = TapTarget; /***/ }), /***/ "./src/timepicker.ts": /*!***************************!*\ !*** ./src/timepicker.ts ***! \***************************/ /***/ (function(__unused_webpack_module, exports, __webpack_require__) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.Timepicker = void 0; const modal_1 = __webpack_require__(/*! ./modal */ "./src/modal.ts"); const utils_1 = __webpack_require__(/*! ./utils */ "./src/utils.ts"); const component_1 = __webpack_require__(/*! ./component */ "./src/component.ts"); let _defaults = { dialRadius: 135, outerRadius: 105, innerRadius: 70, tickRadius: 20, duration: 350, container: null, defaultTime: 'now', // default time, 'now' or '13:14' e.g. fromNow: 0, // Millisecond offset from the defaultTime showClearBtn: false, // internationalization i18n: { cancel: 'Cancel', clear: 'Clear', done: 'Ok' }, autoClose: false, // auto close when minute is selected twelveHour: true, // change to 12 hour AM/PM clock from 24 hour vibrate: true, // vibrate the device when dragging clock hand // Callbacks onOpenStart: null, onOpenEnd: null, onCloseStart: null, onCloseEnd: null, onSelect: null }; class Timepicker extends component_1.Component { constructor(el, options) { super(el, options, Timepicker); this._handleInputClick = () => { this.open(); }; this._handleInputKeydown = (e) => { if (utils_1.Utils.keys.ENTER.includes(e.key)) { e.preventDefault(); this.open(); } }; this._handleTimeInputEnterKey = (e) => { if (utils_1.Utils.keys.ENTER.includes(e.key)) { e.preventDefault(); this._inputFromTextField(); } }; this._handleClockClickStart = (e) => { e.preventDefault(); let clockPlateBR = this.plate.getBoundingClientRect(); let offset = { x: clockPlateBR.left, y: clockPlateBR.top }; this.x0 = offset.x + this.options.dialRadius; this.y0 = offset.y + this.options.dialRadius; this.moved = false; let clickPos = Timepicker._Pos(e); this.dx = clickPos.x - this.x0; this.dy = clickPos.y - this.y0; // Set clock hands this.setHand(this.dx, this.dy, false); // Mousemove on document document.addEventListener('mousemove', this._handleDocumentClickMove); document.addEventListener('touchmove', this._handleDocumentClickMove); // Mouseup on document document.addEventListener('mouseup', this._handleDocumentClickEnd); document.addEventListener('touchend', this._handleDocumentClickEnd); }; this._handleDocumentClickMove = (e) => { e.preventDefault(); let clickPos = Timepicker._Pos(e); let x = clickPos.x - this.x0; let y = clickPos.y - this.y0; this.moved = true; this.setHand(x, y, false); }; this._handleDocumentClickEnd = (e) => { e.preventDefault(); document.removeEventListener('mouseup', this._handleDocumentClickEnd); document.removeEventListener('touchend', this._handleDocumentClickEnd); let clickPos = Timepicker._Pos(e); let x = clickPos.x - this.x0; let y = clickPos.y - this.y0; if (this.moved && x === this.dx && y === this.dy) { this.setHand(x, y); } if (this.currentView === 'hours') { this.showView('minutes', this.options.duration / 2); } else if (this.options.autoClose) { this.minutesView.classList.add('timepicker-dial-out'); setTimeout(() => { this.done(); }, this.options.duration / 2); } if (typeof this.options.onSelect === 'function') { this.options.onSelect.call(this, this.hours, this.minutes); } // Unbind mousemove event document.removeEventListener('mousemove', this._handleDocumentClickMove); document.removeEventListener('touchmove', this._handleDocumentClickMove); }; this._handleAmPmClick = (e) => { const btnClicked = e.target; this.amOrPm = btnClicked.classList.contains('am-btn') ? 'AM' : 'PM'; this._updateAmPmView(); }; /** * Show hours or minutes view on timepicker. * @param view The name of the view you want to switch to, 'hours' or 'minutes'. */ this.showView = (view, delay = null) => { if (view === 'minutes' && getComputedStyle(this.hoursView).visibility === 'visible') { // raiseCallback(this.options.beforeHourSelect); } let isHours = view === 'hours', nextView = isHours ? this.hoursView : this.minutesView, hideView = isHours ? this.minutesView : this.hoursView; this.currentView = view; if (isHours) { this.inputHours.classList.add('text-primary'); this.inputMinutes.classList.remove('text-primary'); } else { this.inputHours.classList.remove('text-primary'); this.inputMinutes.classList.add('text-primary'); } // Transition view hideView.classList.add('timepicker-dial-out'); nextView.style.visibility = 'visible'; nextView.classList.remove('timepicker-dial-out'); // Reset clock hand this.resetClock(delay); // After transitions ended clearTimeout(this.toggleViewTimer); this.toggleViewTimer = setTimeout(() => { hideView.style.visibility = 'hidden'; }, this.options.duration); }; this._inputFromTextField = () => { const isHours = this.currentView === 'hours'; if (isHours) { const value = parseInt(this.inputHours.value); if (value > 0 && value < 13) { this.drawClockFromTimeInput(value, isHours); this.showView('minutes', this.options.duration / 2); this.hours = value; this.inputMinutes.focus(); } else { const hour = new Date().getHours(); this.inputHours.value = (hour % 12).toString(); } } else { const value = parseInt(this.inputMinutes.value); if (value >= 0 && value < 60) { this.inputMinutes.value = Timepicker._addLeadingZero(value); this.drawClockFromTimeInput(value, isHours); this.minutes = value; this.modalEl.querySelector('.confirmation-btns :nth-child(2)').focus(); } else { const minutes = new Date().getMinutes(); this.inputMinutes.value = Timepicker._addLeadingZero(minutes); } } }; /** * Open timepicker. */ this.open = () => { if (this.isOpen) return; this.isOpen = true; this._updateTimeFromInput(); this.showView('hours'); this.modal.open(undefined); }; /** * Close timepicker. */ this.close = () => { if (!this.isOpen) return; this.isOpen = false; this.modal.close(); }; this.done = (e = null, clearValue = null) => { // Set input value let last = this.el.value; let value = clearValue ? '' : Timepicker._addLeadingZero(this.hours) + ':' + Timepicker._addLeadingZero(this.minutes); this.time = value; if (!clearValue && this.options.twelveHour) { value = `${value} ${this.amOrPm}`; } this.el.value = value; // Trigger change event if (value !== last) { this.el.dispatchEvent(new Event('change', { bubbles: true, cancelable: true, composed: true })); } this.close(); this.el.focus(); }; this.clear = () => { this.done(null, true); }; this.el.M_Timepicker = this; this.options = Object.assign(Object.assign({}, Timepicker.defaults), options); this.id = utils_1.Utils.guid(); this._insertHTMLIntoDOM(); this._setupModal(); this._setupVariables(); this._setupEventHandlers(); this._clockSetup(); this._pickerSetup(); } static get defaults() { return _defaults; } /** * Initializes instances of Timepicker. * @param els HTML elements. * @param options Component options. */ static init(els, options = {}) { return super.init(els, options, Timepicker); } static _addLeadingZero(num) { return (num < 10 ? '0' : '') + num; } static _createSVGEl(name) { let svgNS = 'http://www.w3.org/2000/svg'; return document.createElementNS(svgNS, name); } static _Pos(e) { if (e.type.startsWith("touch") && e.targetTouches.length >= 1) { return { x: e.targetTouches[0].clientX, y: e.targetTouches[0].clientY }; } // mouse event return { x: e.clientX, y: e.clientY }; } static getInstance(el) { return el.M_Timepicker; } destroy() { this._removeEventHandlers(); this.modal.destroy(); this.modalEl.remove(); this.el.M_Timepicker = undefined; } _setupEventHandlers() { this.el.addEventListener('click', this._handleInputClick); this.el.addEventListener('keydown', this._handleInputKeydown); this.plate.addEventListener('mousedown', this._handleClockClickStart); this.plate.addEventListener('touchstart', this._handleClockClickStart); this.digitalClock.addEventListener('keyup', this._inputFromTextField); this.inputHours.addEventListener('click', () => this.showView('hours')); this.inputMinutes.addEventListener('click', () => this.showView('minutes')); } _removeEventHandlers() { this.el.removeEventListener('click', this._handleInputClick); this.el.removeEventListener('keydown', this._handleInputKeydown); } _insertHTMLIntoDOM() { const template = document.createElement('template'); template.innerHTML = Timepicker._template.trim(); this.modalEl = template.content.firstChild; this.modalEl.id = 'modal-' + this.id; // Append popover to input by default const optEl = this.options.container; const containerEl = optEl instanceof HTMLElement ? optEl : document.querySelector(optEl); if (this.options.container && !!containerEl) { containerEl.append(this.modalEl); } else { this.el.parentElement.appendChild(this.modalEl); } } _setupModal() { this.modal = modal_1.Modal.init(this.modalEl, { onOpenStart: this.options.onOpenStart, onOpenEnd: this.options.onOpenEnd, onCloseStart: this.options.onCloseStart, onCloseEnd: () => { if (typeof this.options.onCloseEnd === 'function') { this.options.onCloseEnd.call(this); } this.isOpen = false; } }); } _setupVariables() { this.currentView = 'hours'; this.vibrate = navigator.vibrate ? 'vibrate' : navigator.webkitVibrate ? 'webkitVibrate' : null; this._canvas = this.modalEl.querySelector('.timepicker-canvas'); this.plate = this.modalEl.querySelector('.timepicker-plate'); this.digitalClock = this.modalEl.querySelector('.timepicker-display-column'); this.hoursView = this.modalEl.querySelector('.timepicker-hours'); this.minutesView = this.modalEl.querySelector('.timepicker-minutes'); this.inputHours = this.modalEl.querySelector('.timepicker-input-hours'); this.inputMinutes = this.modalEl.querySelector('.timepicker-input-minutes'); this.spanAmPm = this.modalEl.querySelector('.timepicker-span-am-pm'); this.footer = this.modalEl.querySelector('.timepicker-footer'); this.amOrPm = 'PM'; } _createButton(text, visibility) { const button = document.createElement('button'); button.classList.add('btn-flat', 'waves-effect'); button.style.visibility = visibility; button.type = 'button'; button.tabIndex = this.options.twelveHour ? 3 : 1; button.innerText = text; return button; } _pickerSetup() { const clearButton = this._createButton(this.options.i18n.clear, this.options.showClearBtn ? '' : 'hidden'); clearButton.classList.add('timepicker-clear'); clearButton.addEventListener('click', this.clear); this.footer.appendChild(clearButton); const confirmationBtnsContainer = document.createElement('div'); confirmationBtnsContainer.classList.add('confirmation-btns'); this.footer.append(confirmationBtnsContainer); const cancelButton = this._createButton(this.options.i18n.cancel, ''); cancelButton.classList.add('timepicker-close'); cancelButton.addEventListener('click', this.close); confirmationBtnsContainer.appendChild(cancelButton); const doneButton = this._createButton(this.options.i18n.done, ''); doneButton.classList.add('timepicker-close'); doneButton.addEventListener('click', this.done); confirmationBtnsContainer.appendChild(doneButton); } _clockSetup() { if (this.options.twelveHour) { // AM Button this._amBtn = document.createElement('div'); this._amBtn.classList.add('am-btn'); this._amBtn.innerText = 'AM'; this._amBtn.addEventListener('click', this._handleAmPmClick); this.spanAmPm.appendChild(this._amBtn); // PM Button this._pmBtn = document.createElement('div'); this._pmBtn.classList.add('pm-btn'); this._pmBtn.innerText = 'PM'; this._pmBtn.addEventListener('click', this._handleAmPmClick); this.spanAmPm.appendChild(this._pmBtn); } this._buildHoursView(); this._buildMinutesView(); this._buildSVGClock(); } _buildSVGClock() { // Draw clock hands and others let dialRadius = this.options.dialRadius; let tickRadius = this.options.tickRadius; let diameter = dialRadius * 2; let svg = Timepicker._createSVGEl('svg'); svg.setAttribute('class', 'timepicker-svg'); svg.setAttribute('width', diameter.toString()); svg.setAttribute('height', diameter.toString()); let g = Timepicker._createSVGEl('g'); g.setAttribute('transform', 'translate(' + dialRadius + ',' + dialRadius + ')'); let bearing = Timepicker._createSVGEl('circle'); bearing.setAttribute('class', 'timepicker-canvas-bearing'); bearing.setAttribute('cx', '0'); bearing.setAttribute('cy', '0'); bearing.setAttribute('r', '4'); let hand = Timepicker._createSVGEl('line'); hand.setAttribute('x1', '0'); hand.setAttribute('y1', '0'); let bg = Timepicker._createSVGEl('circle'); bg.setAttribute('class', 'timepicker-canvas-bg'); bg.setAttribute('r', tickRadius.toString()); g.appendChild(hand); g.appendChild(bg); g.appendChild(bearing); svg.appendChild(g); this._canvas.appendChild(svg); this.hand = hand; this.bg = bg; this.bearing = bearing; this.g = g; } _buildHoursView() { const $tick = document.createElement('div'); $tick.classList.add('timepicker-tick'); // Hours view if (this.options.twelveHour) { for (let i = 1; i < 13; i += 1) { const tick = $tick.cloneNode(true); const radian = (i / 6) * Math.PI; const radius = this.options.outerRadius; tick.style.left = this.options.dialRadius + Math.sin(radian) * radius - this.options.tickRadius + 'px'; tick.style.top = this.options.dialRadius - Math.cos(radian) * radius - this.options.tickRadius + 'px'; tick.innerHTML = i === 0 ? '00' : i.toString(); this.hoursView.appendChild(tick); // tick.on(mousedownEvent, mousedown); } } else { for (let i = 0; i < 24; i += 1) { const tick = $tick.cloneNode(true); const radian = (i / 6) * Math.PI; const inner = i > 0 && i < 13; const radius = inner ? this.options.innerRadius : this.options.outerRadius; tick.style.left = this.options.dialRadius + Math.sin(radian) * radius - this.options.tickRadius + 'px'; tick.style.top = this.options.dialRadius - Math.cos(radian) * radius - this.options.tickRadius + 'px'; tick.innerHTML = i === 0 ? '00' : i.toString(); this.hoursView.appendChild(tick); // tick.on(mousedownEvent, mousedown); } } } _buildMinutesView() { const _tick = document.createElement('div'); _tick.classList.add('timepicker-tick'); // Minutes view for (let i = 0; i < 60; i += 5) { const tick = _tick.cloneNode(true); const radian = (i / 30) * Math.PI; tick.style.left = this.options.dialRadius + Math.sin(radian) * this.options.outerRadius - this.options.tickRadius + 'px'; tick.style.top = this.options.dialRadius - Math.cos(radian) * this.options.outerRadius - this.options.tickRadius + 'px'; tick.innerHTML = Timepicker._addLeadingZero(i); this.minutesView.appendChild(tick); } } _updateAmPmView() { if (this.options.twelveHour) { if (this.amOrPm === 'PM') { this._amBtn.classList.remove('text-primary'); this._pmBtn.classList.add('text-primary'); } else if (this.amOrPm === 'AM') { this._amBtn.classList.add('text-primary'); this._pmBtn.classList.remove('text-primary'); } } } _updateTimeFromInput() { // Get the time let value = ((this.el.value || this.options.defaultTime || '') + '').split(':'); if (this.options.twelveHour && !(typeof value[1] === 'undefined')) { if (value[1].toUpperCase().indexOf('AM') > 0) { this.amOrPm = 'AM'; } else { this.amOrPm = 'PM'; } value[1] = value[1].replace('AM', '').replace('PM', ''); } if (value[0] === 'now') { let now = new Date(+new Date() + this.options.fromNow); value = [now.getHours().toString(), now.getMinutes().toString()]; if (this.options.twelveHour) { this.amOrPm = parseInt(value[0]) >= 12 && parseInt(value[0]) < 24 ? 'PM' : 'AM'; } } this.hours = +value[0] || 0; this.minutes = +value[1] || 0; this.inputHours.value = this.hours; this.inputMinutes.value = Timepicker._addLeadingZero(this.minutes); this._updateAmPmView(); } resetClock(delay) { var _a; let view = this.currentView, value = this[view], isHours = view === 'hours', unit = Math.PI / (isHours ? 6 : 30), radian = value * unit, radius = isHours && value > 0 && value < 13 ? this.options.innerRadius : this.options.outerRadius, x = Math.sin(radian) * radius, y = -Math.cos(radian) * radius, self = this; if (delay) { (_a = this.canvas) === null || _a === void 0 ? void 0 : _a.classList.add('timepicker-canvas-out'); setTimeout(() => { var _a; (_a = self.canvas) === null || _a === void 0 ? void 0 : _a.classList.remove('timepicker-canvas-out'); self.setHand(x, y); }, delay); } else { this.setHand(x, y); } } drawClockFromTimeInput(value, isHours) { const unit = Math.PI / (isHours ? 6 : 30); const radian = value * unit; let radius; if (this.options.twelveHour) { radius = this.options.outerRadius; } let cx1 = Math.sin(radian) * (radius - this.options.tickRadius), cy1 = -Math.cos(radian) * (radius - this.options.tickRadius), cx2 = Math.sin(radian) * radius, cy2 = -Math.cos(radian) * radius; this.hand.setAttribute('x2', cx1.toString()); this.hand.setAttribute('y2', cy1.toString()); this.bg.setAttribute('cx', cx2.toString()); this.bg.setAttribute('cy', cy2.toString()); } setHand(x, y, roundBy5 = false) { let radian = Math.atan2(x, -y), isHours = this.currentView === 'hours', unit = Math.PI / (isHours || roundBy5 ? 6 : 30), z = Math.sqrt(x * x + y * y), inner = isHours && z < (this.options.outerRadius + this.options.innerRadius) / 2, radius = inner ? this.options.innerRadius : this.options.outerRadius; if (this.options.twelveHour) { radius = this.options.outerRadius; } // Radian should in range [0, 2PI] if (radian < 0) { radian = Math.PI * 2 + radian; } // Get the round value let value = Math.round(radian / unit); // Get the round radian radian = value * unit; // Correct the hours or minutes if (this.options.twelveHour) { if (isHours) { if (value === 0) value = 12; } else { if (roundBy5) value *= 5; if (value === 60) value = 0; } } else { if (isHours) { if (value === 12) { value = 0; } value = inner ? (value === 0 ? 12 : value) : value === 0 ? 0 : value + 12; } else { if (roundBy5) { value *= 5; } if (value === 60) { value = 0; } } } // Once hours or minutes changed, vibrate the device if (this[this.currentView] !== value) { if (this.vibrate && this.options.vibrate) { // Do not vibrate too frequently if (!this.vibrateTimer) { navigator[this.vibrate](10); this.vibrateTimer = setTimeout(() => { this.vibrateTimer = null; }, 100); } } } this[this.currentView] = value; if (isHours) { this.inputHours.value = value.toString(); } else { this.inputMinutes.value = Timepicker._addLeadingZero(value); } // Set clock hand and others' position let cx1 = Math.sin(radian) * (radius - this.options.tickRadius), cy1 = -Math.cos(radian) * (radius - this.options.tickRadius), cx2 = Math.sin(radian) * radius, cy2 = -Math.cos(radian) * radius; this.hand.setAttribute('x2', cx1.toString()); this.hand.setAttribute('y2', cy1.toString()); this.bg.setAttribute('cx', cx2.toString()); this.bg.setAttribute('cy', cy2.toString()); } } exports.Timepicker = Timepicker; (() => { Timepicker._template = `