From c19de37338994bb629c9ec55a463aaf99c4e25dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mauro=20Mascarenhas=20de=20Ara=C3=BAjo?= Date: Fri, 9 Jun 2023 16:31:34 -0300 Subject: [PATCH 1/3] style(components): fix indentation and whitespaces - Removed unnecessary whitespaces on line ending; - Fixed indentation for every component. --- src/autocomplete.ts | 7 +- src/buttons.ts | 488 +++++++------- src/cards.ts | 11 +- src/carousel.ts | 1074 +++++++++++++++--------------- src/chips.ts | 2 +- src/collapsible.ts | 2 +- src/datepicker.ts | 1506 +++++++++++++++++++++---------------------- src/dropdown.ts | 964 +++++++++++++-------------- src/forms.ts | 18 +- src/global.ts | 30 +- src/materialbox.ts | 590 ++++++++--------- src/modal.ts | 418 ++++++------ src/parallax.ts | 201 +++--- src/pushpin.ts | 198 +++--- src/range.ts | 295 +++++---- src/scrollspy.ts | 343 +++++----- src/select.ts | 784 +++++++++++----------- src/sidenav.ts | 756 +++++++++++----------- src/slider.ts | 717 ++++++++++---------- src/tabs.ts | 464 ++++++------- src/tapTarget.ts | 415 ++++++------ src/timepicker.ts | 1217 +++++++++++++++++----------------- src/toasts.ts | 456 ++++++------- src/tooltip.ts | 489 +++++++------- src/waves.ts | 20 +- 25 files changed, 5716 insertions(+), 5749 deletions(-) diff --git a/src/autocomplete.ts b/src/autocomplete.ts index 5920444e9b..511ded0555 100644 --- a/src/autocomplete.ts +++ b/src/autocomplete.ts @@ -134,7 +134,7 @@ export class Autocomplete extends Component { } } - _setupDropdown() { + _setupDropdown() { this.container = document.createElement('ul'); this.container.style.maxHeight = this.options.maxDropDownHeight; this.container.id = `autocomplete-options-${M.guid()}`; @@ -142,7 +142,7 @@ export class Autocomplete extends Component { this.el.setAttribute('data-target', this.container.id); // ! Issue in Component Dropdown: _placeDropdown moves dom-position - this.el.parentElement.appendChild(this.container); + this.el.parentElement.appendChild(this.container); // Initialize dropdown let dropdownOptions = { @@ -174,7 +174,7 @@ export class Autocomplete extends Component { 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.el.parentElement.appendChild(div); this._updateSelectedInfo(); } @@ -456,4 +456,3 @@ export class Autocomplete extends Component { this._triggerChanged(); } } - diff --git a/src/buttons.ts b/src/buttons.ts index d960e64797..424ad90efd 100644 --- a/src/buttons.ts +++ b/src/buttons.ts @@ -1,295 +1,293 @@ import { Component } from "./component"; import anim from "animejs"; - let _defaults = { - direction: 'top', - hoverEnabled: true, - toolbarEnabled: false - }; - - export class FloatingActionButton extends Component { - el: HTMLElement; - isOpen: boolean; - private _anchor: HTMLAnchorElement; - private _menu: HTMLElement|null; - private _floatingBtns: HTMLElement[]; - private _floatingBtnsReverse: HTMLElement[]; - offsetY: number; - offsetX: number; - private _handleFABClickBound: any; - private _handleOpenBound: any; - private _handleCloseBound: any; - private _handleDocumentClickBound: (this: HTMLElement, ev: MouseEvent) => any; - btnBottom: number; - btnLeft: number; - btnWidth: number; - - constructor(el, options) { - super(FloatingActionButton, el, options); - - (this.el as any).M_FloatingActionButton = this; - - this.options = {...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(); - } +let _defaults = { + direction: 'top', + hoverEnabled: true, + toolbarEnabled: false +}; + +export class FloatingActionButton extends Component { + el: HTMLElement; + isOpen: boolean; + private _anchor: HTMLAnchorElement; + private _menu: HTMLElement|null; + private _floatingBtns: HTMLElement[]; + private _floatingBtnsReverse: HTMLElement[]; + offsetY: number; + offsetX: number; + private _handleFABClickBound: any; + private _handleOpenBound: any; + private _handleCloseBound: any; + private _handleDocumentClickBound: (this: HTMLElement, ev: MouseEvent) => any; + btnBottom: number; + btnLeft: number; + btnWidth: number; + + constructor(el, options) { + super(FloatingActionButton, el, options); + + (this.el as any).M_FloatingActionButton = this; + + this.options = {...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; - } + static get defaults() { + return _defaults; + } - static init(els, options) { - return super.init(this, els, options); - } + static init(els, options) { + return super.init(this, els, options); + } - static getInstance(el) { - let domElem = !!el.jquery ? el[0] : el; - return domElem.M_FloatingActionButton; - } + static getInstance(el) { + let domElem = !!el.jquery ? el[0] : el; + return domElem.M_FloatingActionButton; + } - destroy() { - this._removeEventHandlers(); - (this.el as any).M_FloatingActionButton = undefined; - } + destroy() { + this._removeEventHandlers(); + (this.el as any).M_FloatingActionButton = undefined; + } - _setupEventHandlers() { - this._handleFABClickBound = this._handleFABClick.bind(this); - this._handleOpenBound = this.open.bind(this); - this._handleCloseBound = this.close.bind(this); - - if (this.options.hoverEnabled && !this.options.toolbarEnabled) { - this.el.addEventListener('mouseenter', this._handleOpenBound); - this.el.addEventListener('mouseleave', this._handleCloseBound); - } else { - this.el.addEventListener('click', this._handleFABClickBound); - } - } + _setupEventHandlers() { + this._handleFABClickBound = this._handleFABClick.bind(this); + this._handleOpenBound = this.open.bind(this); + this._handleCloseBound = this.close.bind(this); - _removeEventHandlers() { - if (this.options.hoverEnabled && !this.options.toolbarEnabled) { - this.el.removeEventListener('mouseenter', this._handleOpenBound); - this.el.removeEventListener('mouseleave', this._handleCloseBound); - } else { - this.el.removeEventListener('click', this._handleFABClickBound); - } + if (this.options.hoverEnabled && !this.options.toolbarEnabled) { + this.el.addEventListener('mouseenter', this._handleOpenBound); + this.el.addEventListener('mouseleave', this._handleCloseBound); + } else { + this.el.addEventListener('click', this._handleFABClickBound); } + } - _handleFABClick() { - if (this.isOpen) { - this.close(); - } else { - this.open(); - } + _removeEventHandlers() { + if (this.options.hoverEnabled && !this.options.toolbarEnabled) { + this.el.removeEventListener('mouseenter', this._handleOpenBound); + this.el.removeEventListener('mouseleave', this._handleCloseBound); + } else { + this.el.removeEventListener('click', this._handleFABClickBound); } + } - _handleDocumentClick(e) { - const elem = e.target; - if (elem !== this._menu) this.close; - /* - if (!elem.closest(this.$menu)) { - this.close(); - }*/ + _handleFABClick() { + if (this.isOpen) { + this.close(); + } else { + this.open(); } + } - open() { - if (this.isOpen) return; - if (this.options.toolbarEnabled) - this._animateInToolbar(); - else - this._animateInFAB(); - this.isOpen = true; - } + _handleDocumentClick(e) { + const elem = e.target; + if (elem !== this._menu) this.close; + /* + if (!elem.closest(this.$menu)) { + this.close(); + }*/ + } - close() { - if (!this.isOpen) return; - if (this.options.toolbarEnabled) { - window.removeEventListener('scroll', this._handleCloseBound, true); - document.body.removeEventListener('click', this._handleDocumentClickBound, true); - this._animateOutToolbar(); - } - else { - this._animateOutFAB(); - } - this.isOpen = false; - } + open() { + if (this.isOpen) return; + if (this.options.toolbarEnabled) + this._animateInToolbar(); + else + this._animateInFAB(); + this.isOpen = true; + } - _animateInFAB() { - this.el.classList.add('active'); - let time = 0; - this._floatingBtnsReverse.forEach((el) => { - anim({ - targets: el, - opacity: 1, - scale: [0.4, 1], - translateY: [this.offsetY, 0], - translateX: [this.offsetX, 0], - duration: 275, - delay: time, - easing: 'easeInOutQuad' - }); - time += 40; - }); + close() { + if (!this.isOpen) return; + if (this.options.toolbarEnabled) { + window.removeEventListener('scroll', this._handleCloseBound, true); + document.body.removeEventListener('click', this._handleDocumentClickBound, true); + this._animateOutToolbar(); } - - _animateOutFAB() { - this._floatingBtnsReverse.forEach((el) => { - anim.remove(el); - anim({ - targets: el, - opacity: 0, - scale: 0.4, - translateY: this.offsetY, - translateX: this.offsetX, - duration: 175, - easing: 'easeOutQuad', - complete: () => { - this.el.classList.remove('active'); - } - }); - }); + else { + this._animateOutFAB(); } + this.isOpen = false; + } - _animateInToolbar() { - let scaleFactor; - let windowWidth = window.innerWidth; - let windowHeight = window.innerHeight; - let btnRect = this.el.getBoundingClientRect(); + _animateInFAB() { + this.el.classList.add('active'); + let time = 0; + this._floatingBtnsReverse.forEach((el) => { + anim({ + targets: el, + opacity: 1, + scale: [0.4, 1], + translateY: [this.offsetY, 0], + translateX: [this.offsetX, 0], + duration: 275, + delay: time, + easing: 'easeInOutQuad' + }); + time += 40; + }); + } - const backdrop = document.createElement('div'); - backdrop.classList.add('fab-backdrop'); // $('
'); + _animateOutFAB() { + this._floatingBtnsReverse.forEach((el) => { + anim.remove(el); + anim({ + targets: el, + opacity: 0, + scale: 0.4, + translateY: this.offsetY, + translateX: this.offsetX, + duration: 175, + easing: 'easeOutQuad', + complete: () => { + this.el.classList.remove('active'); + } + }); + }); + } - const fabColor = getComputedStyle(this._anchor).backgroundColor; // css('background-color'); + _animateInToolbar() { + let scaleFactor; + let windowWidth = window.innerWidth; + let windowHeight = window.innerHeight; + let btnRect = this.el.getBoundingClientRect(); - this._anchor.append(backdrop); + const backdrop = document.createElement('div'); + backdrop.classList.add('fab-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; + const fabColor = getComputedStyle(this._anchor).backgroundColor; // css('background-color'); - // 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.append(backdrop); - this._anchor.style.transform = `translateY(${this.offsetY}px`; - this._anchor.style.transition = 'none'; + 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; - (backdrop).style.backgroundColor = fabColor; + // 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'; - 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.transform = `translateY(${this.offsetY}px`; + this._anchor.style.transition = 'none'; - this._anchor.style.overflow = 'visible'; - this._anchor.style.transform = ''; - this._anchor.style.transition = 'transform .2s'; + (backdrop).style.backgroundColor = fabColor; - setTimeout(() => { - this.el.style.overflow = 'hidden'; - this.el.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'; - backdrop.style.transform = 'scale(' + scaleFactor + ')'; - backdrop.style.transition = 'transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)'; + this._anchor.style.overflow = 'visible'; + this._anchor.style.transform = ''; + this._anchor.style.transition = 'transform .2s'; - this._menu.querySelectorAll('li > a').forEach((a: HTMLAnchorElement) => a.style.opacity = '1'); + setTimeout(() => { + this.el.style.overflow = 'hidden'; + this.el.style.backgroundColor = fabColor; - // Scroll to close. - this._handleDocumentClickBound = this._handleDocumentClick.bind(this); - window.addEventListener('scroll', this._handleCloseBound, true); - document.body.addEventListener('click', this._handleDocumentClickBound, true); - }, 100); - }, 0); - } + 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: HTMLAnchorElement) => a.style.opacity = '1'); + // Scroll to close. + this._handleDocumentClickBound = this._handleDocumentClick.bind(this); + window.addEventListener('scroll', this._handleCloseBound, true); + document.body.addEventListener('click', this._handleDocumentClickBound, true); + }, 100); + }, 0); + } - _animateOutToolbar() { - return; - /* - let windowWidth = window.innerWidth; - let windowHeight = window.innerHeight; - let backdrop = this.$el.find('.fab-backdrop'); - let fabColor = this.$anchor.css('background-color'); - this.offsetX = this.btnLeft - windowWidth / 2 + this.btnWidth / 2; - this.offsetY = windowHeight - this.btnBottom; - // Hide backdrop - this.$el.removeClass('active'); + _animateOutToolbar() { + return; + /* + let windowWidth = window.innerWidth; + let windowHeight = window.innerHeight; + let backdrop = this.$el.find('.fab-backdrop'); + let fabColor = this.$anchor.css('background-color'); + + this.offsetX = this.btnLeft - windowWidth / 2 + this.btnWidth / 2; + this.offsetY = windowHeight - this.btnBottom; + + // Hide backdrop + this.$el.removeClass('active'); + this.$el.css({ + 'background-color': 'transparent', + transition: 'none' + }); + // this.$anchor.css({ + // transition: 'none' + // }); + backdrop.css({ + transform: 'scale(0)', + 'background-color': fabColor + }); + + // this.$menu + // .children('li') + // .children('a') + // .css({ + // opacity: '' + // }); + + setTimeout(() => { + backdrop.remove(); + + // Set initial state. this.$el.css({ - 'background-color': 'transparent', - transition: 'none' + 'text-align': '', + width: '', + bottom: '', + left: '', + overflow: '', + 'background-color': '', + transform: 'translate3d(' + -this.offsetX + 'px,0,0)' }); // this.$anchor.css({ - // transition: 'none' + // overflow: '', + // transform: 'translate3d(0,' + this.offsetY + 'px,0)' // }); - backdrop.css({ - transform: 'scale(0)', - 'background-color': fabColor - }); - - // this.$menu - // .children('li') - // .children('a') - // .css({ - // opacity: '' - // }); setTimeout(() => { - backdrop.remove(); - - // Set initial state. this.$el.css({ - 'text-align': '', - width: '', - bottom: '', - left: '', - overflow: '', - 'background-color': '', - transform: 'translate3d(' + -this.offsetX + 'px,0,0)' + transform: 'translate3d(0,0,0)', + transition: 'transform .2s' }); // this.$anchor.css({ - // overflow: '', - // transform: 'translate3d(0,' + this.offsetY + 'px,0)' + // transform: 'translate3d(0,0,0)', + // transition: 'transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)' // }); - - setTimeout(() => { - this.$el.css({ - transform: 'translate3d(0,0,0)', - transition: 'transform .2s' - }); - // this.$anchor.css({ - // transform: 'translate3d(0,0,0)', - // transition: 'transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)' - // }); - }, 20); - }, 200); - */ - } + }, 20); + }, 200); + */ } - - \ No newline at end of file +} diff --git a/src/cards.ts b/src/cards.ts index 5cf3af0469..bc2171a6ba 100644 --- a/src/cards.ts +++ b/src/cards.ts @@ -15,7 +15,7 @@ export class Cards { if (!cardReveal) return; const initialOverflow = getComputedStyle(card).overflow; - // Close Card + // Close Card const closeArea = cardReveal.querySelector('.card-reveal .card-title'); if (trigger === closeArea || closeArea.contains(trigger)) { anim({ @@ -29,7 +29,7 @@ export class Cards { } }); }; - + // Reveal Card const activators = card.querySelectorAll('.activator'); activators.forEach(activator => { @@ -44,11 +44,10 @@ export class Cards { }); } }); - - }); + + }); }); - } + } } - \ No newline at end of file diff --git a/src/carousel.ts b/src/carousel.ts index 1e57a5639e..23962e6388 100644 --- a/src/carousel.ts +++ b/src/carousel.ts @@ -1,607 +1,607 @@ import { Component } from "./component"; import { M } from "./global"; - 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. - }; - - export class Carousel extends Component { - el: HTMLElement; - hasMultipleSlides: boolean; - showIndicators: boolean; - noWrap: any; - pressed: boolean; - dragged: boolean; - offset: number; - target: number; - images: HTMLElement[]; - itemWidth: any; - itemHeight: any; - dim: number; - _autoScrollBound: any; - _trackBound: any; - _indicators: any; - count: number; - xform: string; - private _handleCarouselTapBound: any; - private _handleCarouselDragBound: any; - private _handleCarouselReleaseBound: any; - private _handleCarouselClickBound: any; - _handleIndicatorClickBound: any; - _handleThrottledResizeBound: any; - verticalDragged: boolean; - reference: any; - referenceY: any; - velocity: number; - frame: number; - timestamp: number; - ticker: NodeJS.Timer; - amplitude: number; - center: number = 0; - imageHeight: any; - scrollingTimeout: any; - oneTimeCallback: any; - - constructor(el: Element, options: Object) { - super(Carousel, el, options); - (this.el as any).M_Carousel = this; - this.options = {...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. - this._autoScrollBound = this._autoScroll.bind(this); - this._trackBound = this._track.bind(this); +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. +}; + +export class Carousel extends Component { + el: HTMLElement; + hasMultipleSlides: boolean; + showIndicators: boolean; + noWrap: any; + pressed: boolean; + dragged: boolean; + offset: number; + target: number; + images: HTMLElement[]; + itemWidth: any; + itemHeight: any; + dim: number; + _autoScrollBound: any; + _trackBound: any; + _indicators: any; + count: number; + xform: string; + private _handleCarouselTapBound: any; + private _handleCarouselDragBound: any; + private _handleCarouselReleaseBound: any; + private _handleCarouselClickBound: any; + _handleIndicatorClickBound: any; + _handleThrottledResizeBound: any; + verticalDragged: boolean; + reference: any; + referenceY: any; + velocity: number; + frame: number; + timestamp: number; + ticker: NodeJS.Timer; + amplitude: number; + center: number = 0; + imageHeight: any; + scrollingTimeout: any; + oneTimeCallback: any; + + constructor(el: Element, options: Object) { + super(Carousel, el, options); + (this.el as any).M_Carousel = this; + this.options = {...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. + this._autoScrollBound = this._autoScroll.bind(this); + this._trackBound = this._track.bind(this); + + // Full Width carousel setup + if (this.options.fullWidth) { + this.options.dist = 0; + this._setCarouselHeight(); + + // Offset fixed items when indicators. + if (this.showIndicators) { + this.el.querySelector('.carousel-fixed-item')?.classList.add('with-indicators'); + } + } - // Full Width carousel setup - if (this.options.fullWidth) { - this.options.dist = 0; - this._setCarouselHeight(); + // Iterate through slides + this._indicators = document.createElement('ul'); + this._indicators.classList.add('indicators'); - // Offset fixed items when indicators. - if (this.showIndicators) { - this.el.querySelector('.carousel-fixed-item')?.classList.add('with-indicators'); + this.el.querySelectorAll('.carousel-item').forEach((item: HTMLElement, 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); } + }); - // Iterate through slides - this._indicators = document.createElement('ul'); - this._indicators.classList.add('indicators'); - - this.el.querySelectorAll('.carousel-item').forEach((item: HTMLElement, 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); + if (this.showIndicators) + this.el.appendChild(this._indicators); - this.count = this.images.length; + this.count = this.images.length; - // Cap numVisible at count - this.options.numVisible = Math.min(this.count, this.options.numVisible); + // 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; - } - - static init(els, options) { - return super.init(this, els, options); + // 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; + } + + static init(els, options) { + return super.init(this, els, options); + } + + static getInstance(el) { + let domElem = !!el.jquery ? el[0] : el; + return domElem.M_Carousel; + } + + destroy() { + this._removeEventHandlers(); + (this.el as any).M_Carousel = undefined; + } + + _setupEventHandlers() { + this._handleCarouselTapBound = this._handleCarouselTap.bind(this); + this._handleCarouselDragBound = this._handleCarouselDrag.bind(this); + this._handleCarouselReleaseBound = this._handleCarouselRelease.bind(this); + this._handleCarouselClickBound = this._handleCarouselClick.bind(this); + if (typeof window.ontouchstart !== 'undefined') { + this.el.addEventListener('touchstart', this._handleCarouselTapBound); + this.el.addEventListener('touchmove', this._handleCarouselDragBound); + this.el.addEventListener('touchend', this._handleCarouselReleaseBound); } - - static getInstance(el) { - let domElem = !!el.jquery ? el[0] : el; - return domElem.M_Carousel; + this.el.addEventListener('mousedown', this._handleCarouselTapBound); + this.el.addEventListener('mousemove', this._handleCarouselDragBound); + this.el.addEventListener('mouseup', this._handleCarouselReleaseBound); + this.el.addEventListener('mouseleave', this._handleCarouselReleaseBound); + this.el.addEventListener('click', this._handleCarouselClickBound); + if (this.showIndicators && this._indicators) { + this._handleIndicatorClickBound = this._handleIndicatorClick.bind(this); + this._indicators.querySelectorAll('.indicator-item').forEach((el) => { + el.addEventListener('click', this._handleIndicatorClickBound); + }); } - - destroy() { - this._removeEventHandlers(); - (this.el as any).M_Carousel = undefined; + // Resize + let throttledResize = M.throttle(this._handleResize, 200, null); + this._handleThrottledResizeBound = throttledResize.bind(this); + window.addEventListener('resize', this._handleThrottledResizeBound); + } + + _removeEventHandlers() { + if (typeof window.ontouchstart !== 'undefined') { + this.el.removeEventListener('touchstart', this._handleCarouselTapBound); + this.el.removeEventListener('touchmove', this._handleCarouselDragBound); + this.el.removeEventListener('touchend', this._handleCarouselReleaseBound); } - - _setupEventHandlers() { - this._handleCarouselTapBound = this._handleCarouselTap.bind(this); - this._handleCarouselDragBound = this._handleCarouselDrag.bind(this); - this._handleCarouselReleaseBound = this._handleCarouselRelease.bind(this); - this._handleCarouselClickBound = this._handleCarouselClick.bind(this); - if (typeof window.ontouchstart !== 'undefined') { - this.el.addEventListener('touchstart', this._handleCarouselTapBound); - this.el.addEventListener('touchmove', this._handleCarouselDragBound); - this.el.addEventListener('touchend', this._handleCarouselReleaseBound); - } - this.el.addEventListener('mousedown', this._handleCarouselTapBound); - this.el.addEventListener('mousemove', this._handleCarouselDragBound); - this.el.addEventListener('mouseup', this._handleCarouselReleaseBound); - this.el.addEventListener('mouseleave', this._handleCarouselReleaseBound); - this.el.addEventListener('click', this._handleCarouselClickBound); - if (this.showIndicators && this._indicators) { - this._handleIndicatorClickBound = this._handleIndicatorClick.bind(this); - this._indicators.querySelectorAll('.indicator-item').forEach((el) => { - el.addEventListener('click', this._handleIndicatorClickBound); - }); - } - // Resize - let throttledResize = M.throttle(this._handleResize, 200, null); - this._handleThrottledResizeBound = throttledResize.bind(this); - window.addEventListener('resize', this._handleThrottledResizeBound); + this.el.removeEventListener('mousedown', this._handleCarouselTapBound); + this.el.removeEventListener('mousemove', this._handleCarouselDragBound); + this.el.removeEventListener('mouseup', this._handleCarouselReleaseBound); + this.el.removeEventListener('mouseleave', this._handleCarouselReleaseBound); + this.el.removeEventListener('click', this._handleCarouselClickBound); + if (this.showIndicators && this._indicators) { + this._indicators.querySelectorAll('.indicator-item').forEach((el) => { + el.removeEventListener('click', this._handleIndicatorClickBound); + }); } + window.removeEventListener('resize', this._handleThrottledResizeBound); + } - _removeEventHandlers() { - if (typeof window.ontouchstart !== 'undefined') { - this.el.removeEventListener('touchstart', this._handleCarouselTapBound); - this.el.removeEventListener('touchmove', this._handleCarouselDragBound); - this.el.removeEventListener('touchend', this._handleCarouselReleaseBound); - } - this.el.removeEventListener('mousedown', this._handleCarouselTapBound); - this.el.removeEventListener('mousemove', this._handleCarouselDragBound); - this.el.removeEventListener('mouseup', this._handleCarouselReleaseBound); - this.el.removeEventListener('mouseleave', this._handleCarouselReleaseBound); - this.el.removeEventListener('click', this._handleCarouselClickBound); - if (this.showIndicators && this._indicators) { - this._indicators.querySelectorAll('.indicator-item').forEach((el) => { - el.removeEventListener('click', this._handleIndicatorClickBound); - }); - } - window.removeEventListener('resize', this._handleThrottledResizeBound); + _handleCarouselTap(e) { + // Fixes firefox draggable image bug + if (e.type === 'mousedown' && (e.target).tagName === 'IMG') { + e.preventDefault(); } - - _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._trackBound, 100); - } - - _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; + 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._trackBound, 100); + } + + _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); } - } - if (this.dragged) { + } 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; + } + } - _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._autoScrollBound); - if (this.dragged) { - e.preventDefault(); - e.stopPropagation(); + _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; } - return false; } + this.amplitude = this.target - this.offset; + this.timestamp = Date.now(); + requestAnimationFrame(this._autoScrollBound); + if (this.dragged) { + e.preventDefault(); + e.stopPropagation(); + } + return false; + } - _handleCarouselClick(e) { - // Disable clicks if carousel was dragged. - if (this.dragged) { + _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'); + 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(); - return false; } - else if (!this.options.fullWidth) { - const clickedElem = (e.target).closest('.carousel-item'); - 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(); - } + // 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._cycleTo(clickedIndex); + this.prev(); } + } else { + this._cycleTo(clickedIndex); } } + } - _handleIndicatorClick(e: Event) { - e.stopPropagation(); - const indicator = (e.target).closest('.indicator-item'); - if (indicator) { - const index = [...indicator.parentNode.children].indexOf(indicator); - this._cycleTo(index); - } + _handleIndicatorClick(e: Event) { + e.stopPropagation(); + const indicator = (e.target).closest('.indicator-item'); + if (indicator) { + const index = [...indicator.parentNode.children].indexOf(indicator); + this._cycleTo(index); } + } - _handleResize(e) { - 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(); - } + _handleResize(e) { + 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); } - - _setCarouselHeight(imageOnly: boolean = 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 { + this._scroll(); + } + } + + _setCarouselHeight(imageOnly: boolean = 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 (!imageOnly) { - const slideHeight = firstSlide.clientHeight; - this.el.style.height = slideHeight+'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.targetTouches && e.targetTouches.length >= 1) { - return e.targetTouches[0].clientX; + _xpos(e) { + // touch event + if (e.targetTouches && e.targetTouches.length >= 1) { + return e.targetTouches[0].clientX; + } + // mouse event + return e.clientX; + } + + _ypos(e) { + // touch event + if (e.targetTouches && e.targetTouches.length >= 1) { + return e.targetTouches[0].clientY; + } + // mouse event + return e.clientY; + } + + _wrap(x: number) { + return x >= this.count + ? x % this.count + : x < 0 + ? this._wrap(this.count + (x % this.count)) + : x; + } + + _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; + } + + _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._autoScrollBound); + } else { + this._scroll(this.target); } - // mouse event - return e.clientX; } + } - _ypos(e) { - // touch event - if (e.targetTouches && e.targetTouches.length >= 1) { - return e.targetTouches[0].clientY; - } - // mouse event - return e.clientY; - } - - _wrap(x: number) { - return x >= this.count - ? x % this.count - : x < 0 - ? this._wrap(this.count + (x % this.count)) - : x; - } - - _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; - } - - _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._autoScrollBound); - } else { - this._scroll(this.target); - } - } + _scroll(x: number = 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; } - _scroll(x: number = 0) { - // Track scrolling state - if (!this.el.classList.contains('scrolling')) { - this.el.classList.add('scrolling'); - } - if (this.scrollingTimeout != null) { - window.clearTimeout(this.scrollingTimeout); + // 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'); } - 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; - } + // center + // Don't show wrapped items. + if (!this.noWrap || (this.center >= 0 && this.center < this.count)) { + el = this.images[this._wrap(this.center)]; - // 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'); - } + // Add active class to center item. + if (!el.classList.contains('active')) { + this.el.querySelector('.carousel-item').classList.remove('active'); + el.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); - } + 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); - } + 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); } - // 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); + 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); } - // 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); + // 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); } - // One time callback - if (typeof this.oneTimeCallback === 'function') { - this.oneTimeCallback.call(this, _currItem, this.dragged); - this.oneTimeCallback = null; + // 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)]; - _updateItemStyle(el: HTMLElement, opacity: number, zIndex: number, transform: string) { - el.style[this.xform] = transform; - el.style.zIndex = zIndex.toString(); - el.style.opacity = opacity.toString(); - el.style.visibility = 'visible'; - } - - _cycleTo(n: number, callback: Function = 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 (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: HTMLElement, opacity: number, zIndex: number, transform: string) { + el.style[this.xform] = transform; + el.style.zIndex = zIndex.toString(); + el.style.opacity = opacity.toString(); + el.style.visibility = 'visible'; + } + + _cycleTo(n: number, callback: Function = null) { + let diff = (this.center % this.count) - n; + // Account for wraparound. + if (!this.noWrap) { 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._autoScrollBound); + 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._autoScrollBound); + } + } - next(n: number = 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); + next(n: number = 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); + } - prev(n: number = 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); + prev(n: number = 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); + } - set(n: number, callback: Function) { - 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); + set(n: number, callback: Function) { + if (n === undefined || isNaN(n)) { + n = 0; + } + if (n > this.count || n < 0) { + if (this.noWrap) return; + n = this._wrap(n); } - } \ No newline at end of file + this._cycleTo(n, callback); + } +} diff --git a/src/chips.ts b/src/chips.ts index e56ef0777a..340737c05f 100644 --- a/src/chips.ts +++ b/src/chips.ts @@ -142,7 +142,7 @@ export class Chips extends Component { // Don't handle keydown inputs on input and textarea const tag = (e.target).tagName; if (tag === 'INPUT' || tag === 'TEXTAREA' || !chipsKeydown) return; - + const currChips: Chips = (chips as any).M_Chips; // backspace and delete if (e.keyCode === 8 || e.keyCode === 46) { diff --git a/src/collapsible.ts b/src/collapsible.ts index e6956d1b88..40c9a7f681 100644 --- a/src/collapsible.ts +++ b/src/collapsible.ts @@ -29,7 +29,7 @@ export class Collapsible extends Component { if (this.options.accordion) if (activeBodies.length > 0) activeBodies[0].style.display = 'block'; // Accordion - else + else activeBodies.forEach(el => el.style.display = 'block'); // Expandables } diff --git a/src/datepicker.ts b/src/datepicker.ts index 8e05e2bd2a..e12ce9d6d9 100644 --- a/src/datepicker.ts +++ b/src/datepicker.ts @@ -88,810 +88,810 @@ let _defaults = { onDraw: null }; - export class Datepicker extends Component { - el: HTMLInputElement - id: string; - isOpen: boolean; - modal: Modal; - calendarEl: HTMLElement; - clearBtn: HTMLElement; - doneBtn: HTMLElement; - cancelBtn: HTMLElement; - modalEl: HTMLElement; - yearTextEl: HTMLElement; - dateTextEl: HTMLElement; - date: any; - formats: any; - calendars: any; - private _y: any; - private _m: any; - private _handleInputKeydownBound: any; - private _handleInputClickBound: any; - private _handleInputChangeBound: any; - private _handleCalendarClickBound: any; - private _finishSelectionBound: any; - private _closeBound: any; - private _handleClearClickBound: any; - static _template: string; - - constructor(el, options) { - super(Datepicker, el, options); - (this.el as any).M_Datepicker = this; - this.options = {...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 = {...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 = M.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); - } +export class Datepicker extends Component { + el: HTMLInputElement + id: string; + isOpen: boolean; + modal: Modal; + calendarEl: HTMLElement; + clearBtn: HTMLElement; + doneBtn: HTMLElement; + cancelBtn: HTMLElement; + modalEl: HTMLElement; + yearTextEl: HTMLElement; + dateTextEl: HTMLElement; + date: any; + formats: any; + calendars: any; + private _y: any; + private _m: any; + private _handleInputKeydownBound: any; + private _handleInputClickBound: any; + private _handleInputChangeBound: any; + private _handleCalendarClickBound: any; + private _finishSelectionBound: any; + private _closeBound: any; + private _handleClearClickBound: any; + static _template: string; + + constructor(el, options) { + super(Datepicker, el, options); + (this.el as any).M_Datepicker = this; + this.options = {...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 = {...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 = M.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(new Date()); - } - this.isOpen = false; - } - - static get defaults() { - return _defaults; - } - - static init(els, options) { - return super.init(this, els, options); - } - - 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 + this.gotoDate(defDate); + } + } + else { + this.gotoDate(new Date()); + } + this.isOpen = false; + } + + static get defaults() { + return _defaults; + } + + static init(els, options) { + return super.init(this, els, options); + } + + 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) { + let domElem = !!el.jquery ? el[0] : el; + return domElem.M_Datepicker; + } + + destroy() { + this._removeEventHandlers(); + this.modal.destroy(); + this.modalEl.remove(); + this.destroySelects(); + (this.el as any).M_Datepicker = undefined; + } + + destroySelects() { + let oldYearSelect = this.calendarEl.querySelector('.orig-select-year'); + if (oldYearSelect) { + FormSelect.getInstance(oldYearSelect).destroy(); + } + let oldMonthSelect = this.calendarEl.querySelector('.orig-select-month'); + if (oldMonthSelect) { + 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.init(this.modalEl, { + onCloseEnd: () => { + this.isOpen = false; + } + }); + } + + toString(format: string | ((d: Date) => string) = null): string { + 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; + } + + setDate(date, preventOnSelect: boolean = 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); + } + } + + setInputValue() { + this.el.value = this.toString(); + this.el.dispatchEvent(new CustomEvent('change', {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(); + this.dateTextEl.innerHTML = `${day}, ${month} ${date}`; + } + + 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() + } ]; } - - 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) { - let domElem = !!el.jquery ? el[0] : el; - return domElem.M_Datepicker; - } - - destroy() { - this._removeEventHandlers(); - this.modal.destroy(); - this.modalEl.remove(); - this.destroySelects(); - (this.el as any).M_Datepicker = undefined; - } - - destroySelects() { - let oldYearSelect = this.calendarEl.querySelector('.orig-select-year'); - if (oldYearSelect) { - FormSelect.getInstance(oldYearSelect).destroy(); - } - let oldMonthSelect = this.calendarEl.querySelector('.orig-select-month'); - if (oldMonthSelect) { - 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.init(this.modalEl, { - onCloseEnd: () => { - this.isOpen = false; + 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; } - }); - } - - toString(format: string | ((d: Date) => string) = null): string { - 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; - } - - setDate(date, preventOnSelect: boolean = 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); - } - } - setInputValue() { - this.el.value = this.toString(); - this.el.dispatchEvent(new CustomEvent('change', {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(); - this.dateTextEl.innerHTML = `${day}, ${month} ${date}`; - } - - 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(); - } + 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 + }; - prevMonth() { - this.calendars[0].month--; - this.adjustCalendars(); - } + row.push(this.renderDay(dayConfig)); - render(year, month, randId) { - let opts = this.options, - now = new Date(), - days = Datepicker._getDaysInMonth(year, month), - before = new Date(year, month, 1).getDay(), - data = [], + if (++r === 7) { + data.push(this.renderRow(row, opts.isRTL, isWeekSelected)); 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; - } + r = 0; + isWeekSelected = false; } - return this.renderTable(opts, data, randId); } + 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('') + - '' + 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 + )}` ); } - - renderTable(opts, data, randId) { - return ( - '
' + - this.renderHead(opts) + - this.renderBody(data) + - '
' + '" class="datepicker-controls" role="heading" aria-live="assertive">', + monthHtml, + yearHtml, + prev = true, + next = true; + + for (arr = [], i = 0; i < 12; i++) { + arr.push( + '' ); } - 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; - } + monthHtml = ''; - for (arr = []; i < j && i <= opts.maxYear; i++) { - if (i >= opts.minYear) { - arr.push(``); - } - } - if (opts.yearRangeReverse) arr.reverse(); - - yearHtml = ``; - - let leftArrow = - ''; - html += ``; + if (Array.isArray(opts.yearRange)) { + i = opts.yearRange[0]; + j = opts.yearRange[1] + 1; + } + else { + i = year - opts.yearRange; + j = 1 + year + opts.yearRange; + } - html += '
'; - if (opts.showMonthAfterYear) { - html += yearHtml + monthHtml; - } else { - html += monthHtml + yearHtml; + for (arr = []; i < j && i <= opts.maxYear; i++) { + if (i >= opts.minYear) { + arr.push(``); } - html += '
'; + } + if (opts.yearRangeReverse) arr.reverse(); - if (isMinYear && (month === 0 || opts.minMonth >= month)) { - prev = false; - } + yearHtml = ``; - if (isMaxYear && (month === 11 || opts.maxMonth <= month)) { - next = false; - } + let leftArrow = + ''; + html += ``; - let rightArrow = - ''; - html += ``; - - return (html += '
'); - } - - // refresh HTML - draw(force: boolean = 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; - } - } + html += '
'; + if (opts.showMonthAfterYear) { + html += yearHtml + monthHtml; + } else { + html += monthHtml + yearHtml; + } + html += '
'; - 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); - } + if (isMinYear && (month === 0 || opts.minMonth >= month)) { + prev = false; + } - this.destroySelects(); + if (isMaxYear && (month === 11 || opts.maxMonth <= month)) { + next = false; + } - this.calendarEl.innerHTML = html; + let rightArrow = + ''; + html += ``; - // Init Materialize Select - let yearSelect = this.calendarEl.querySelector('.orig-select-year'); - let monthSelect = this.calendarEl.querySelector('.orig-select-month'); - FormSelect.init(yearSelect, { - classes: 'select-year', - dropdownOptions: { container: document.body, constrainWidth: false } - }); - FormSelect.init(monthSelect, { - classes: 'select-month', - dropdownOptions: { container: document.body, constrainWidth: false } - }); + return (html += ''); + } - // Add change handlers for select - yearSelect.addEventListener('change', this._handleYearChange.bind(this)); - monthSelect.addEventListener('change', this._handleMonthChange.bind(this)); + // refresh HTML + draw(force: boolean = 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 (typeof this.options.onDraw === 'function') { - this.options.onDraw(this); + if (this._y <= minYear) { + this._y = minYear; + if (!isNaN(minMonth) && this._m < minMonth) { + this._m = minMonth; } } - - _setupEventHandlers() { - this._handleInputKeydownBound = this._handleInputKeydown.bind(this); - this._handleInputClickBound = this._handleInputClick.bind(this); - this._handleInputChangeBound = this._handleInputChange.bind(this); - this._handleCalendarClickBound = this._handleCalendarClick.bind(this); - this._finishSelectionBound = this._finishSelection.bind(this); - this._handleMonthChange = this._handleMonthChange.bind(this); - this._closeBound = this.close.bind(this); - - this.el.addEventListener('click', this._handleInputClickBound); - this.el.addEventListener('keydown', this._handleInputKeydownBound); - this.el.addEventListener('change', this._handleInputChangeBound); - this.calendarEl.addEventListener('click', this._handleCalendarClickBound); - this.doneBtn.addEventListener('click', this._finishSelectionBound); - this.cancelBtn.addEventListener('click', this._closeBound); - - if (this.options.showClearBtn) { - this._handleClearClickBound = this._handleClearClick.bind(this); - this.clearBtn.addEventListener('click', this._handleClearClickBound); + if (this._y >= maxYear) { + this._y = maxYear; + if (!isNaN(maxMonth) && this._m > maxMonth) { + this._m = maxMonth; } } - _setupVariables() { - const template = document.createElement('template'); - template.innerHTML = Datepicker._template.trim(); - this.modalEl = template.content.firstChild; + randId = + 'datepicker-title-' + + Math.random() + .toString(36) + .replace(/[^a-z]+/g, '') + .substr(0, 2); - 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._handleInputClickBound); - this.el.removeEventListener('keydown', this._handleInputKeydownBound); - this.el.removeEventListener('change', this._handleInputChangeBound); - this.calendarEl.removeEventListener('click', this._handleCalendarClickBound); - } - - _handleInputClick() { + 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'); + FormSelect.init(yearSelect, { + classes: 'select-year', + dropdownOptions: { container: document.body, constrainWidth: false } + }); + FormSelect.init(monthSelect, { + classes: 'select-month', + dropdownOptions: { container: document.body, constrainWidth: false } + }); + + // Add change handlers for select + yearSelect.addEventListener('change', this._handleYearChange.bind(this)); + monthSelect.addEventListener('change', this._handleMonthChange.bind(this)); + + if (typeof this.options.onDraw === 'function') { + this.options.onDraw(this); + } + } + + _setupEventHandlers() { + this._handleInputKeydownBound = this._handleInputKeydown.bind(this); + this._handleInputClickBound = this._handleInputClick.bind(this); + this._handleInputChangeBound = this._handleInputChange.bind(this); + this._handleCalendarClickBound = this._handleCalendarClick.bind(this); + this._finishSelectionBound = this._finishSelection.bind(this); + this._handleMonthChange = this._handleMonthChange.bind(this); + this._closeBound = this.close.bind(this); + + this.el.addEventListener('click', this._handleInputClickBound); + this.el.addEventListener('keydown', this._handleInputKeydownBound); + this.el.addEventListener('change', this._handleInputChangeBound); + this.calendarEl.addEventListener('click', this._handleCalendarClickBound); + this.doneBtn.addEventListener('click', this._finishSelectionBound); + this.cancelBtn.addEventListener('click', this._closeBound); + + if (this.options.showClearBtn) { + this._handleClearClickBound = this._handleClearClick.bind(this); + this.clearBtn.addEventListener('click', this._handleClearClickBound); + } + } + + _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._handleInputClickBound); + this.el.removeEventListener('keydown', this._handleInputKeydownBound); + this.el.removeEventListener('change', this._handleInputChangeBound); + this.calendarEl.removeEventListener('click', this._handleCalendarClickBound); + } + + _handleInputClick() { + this.open(); + } + + _handleInputKeydown(e) { + if (e.which === M.keys.ENTER) { + e.preventDefault(); this.open(); } - - _handleInputKeydown(e) { - if (e.which === M.keys.ENTER) { - e.preventDefault(); - this.open(); - } - } - - _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(); + } + + _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(); } } - } - - _handleClearClick() { - this.date = null; - this.setInputValue(); - this.close(); - } - - _handleMonthChange(e) { - this.gotoMonth(e.target.value); - } - - _handleYearChange(e) { - this.gotoYear(e.target.value); - } - - // 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(); + else if (target.closest('.month-prev')) { + this.prevMonth(); } - } - - // change view to a specific full year (e.g. "2012") - gotoYear(year) { - if (!isNaN(year)) { - this.calendars[0].year = parseInt(year, 10); - this.adjustCalendars(); + else if (target.closest('.month-next')) { + this.nextMonth(); } } + } - _handleInputChange(e: Event) { - let date; - // Prevent change event from being fired when triggered by the plugin - if (e['detail']?.firedBy === this) return; - if (this.options.parse) { - date = this.options.parse(this.el.value, this.options.format); - } - else { - date = new Date(Date.parse(this.el.value)); - } - if (Datepicker._isDate(date)) this.setDate(date); - } + _handleClearClick() { + this.date = null; + this.setInputValue(); + this.close(); + } - renderDayName(opts, day, abbr: boolean = false) { - day += opts.firstDay; - while (day >= 7) { - day -= 7; - } - return abbr ? opts.i18n.weekdaysAbbrev[day] : opts.i18n.weekdays[day]; - } + _handleMonthChange(e) { + this.gotoMonth(e.target.value); + } - // Set input value to the selected date and close Datepicker - _finishSelection() { - this.setInputValue(); - this.close(); - } + _handleYearChange(e) { + this.gotoYear(e.target.value); + } - 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; + // 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(); } + } - close() { - if (!this.isOpen) return; - this.isOpen = false; - if (typeof this.options.onClose === 'function') { - this.options.onClose.call(this); - } - this.modal.close(); - return this; + // change view to a specific full year (e.g. "2012") + gotoYear(year) { + if (!isNaN(year)) { + this.calendars[0].year = parseInt(year, 10); + this.adjustCalendars(); } - - static { - Datepicker._template = ` -