From 11eb1ae187d655dc378435dd725d48acc09df01c Mon Sep 17 00:00:00 2001 From: dixso Date: Thu, 29 Dec 2016 07:53:17 +0100 Subject: [PATCH] Add loader --- src/custombox.scss | 30 ++++++++- src/custombox.spec.ts | 141 ++++++++++++++++++++++++++++++++++++++++++ src/custombox.ts | 44 ++++++++++++- 3 files changed, 213 insertions(+), 2 deletions(-) diff --git a/src/custombox.scss b/src/custombox.scss index 31bf80e..5ba55c9 100644 --- a/src/custombox.scss +++ b/src/custombox.scss @@ -4,6 +4,7 @@ $overlay: #{$cb}-overlay; $content: #{$cb}-content; $container: #{$cb}-container; $perspective: #{$cb}-perspective; +$index: 9997; // Actions $open: #{$cb}-open; @@ -64,7 +65,6 @@ $effect23: #{$cb}-flash; top: 0; width: 100%; height: 100%; - z-index: 9999; } .#{$content}, @@ -72,12 +72,14 @@ $effect23: #{$cb}-flash; @include fixed(); } .#{$overlay} { + z-index: $index; opacity: 0; transition-delay: 0s; transition-timing-function: linear; transition-property: opacity; } .#{$content} { + z-index: $index + 2; display: flex; flex-direction: row; flex-wrap: nowrap; @@ -1809,4 +1811,30 @@ $effect23: #{$cb}-flash; @include animation(flashClose, ease-out); } } +} + +/* + ---------------------------- + Loader + ---------------------------- + */ +@keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} +.#{$cb}-loader { + border: #999 solid 5px; + border-radius: 50%; + width: 40px; + height: 40px; + animation: spin 1.5s linear infinite; + position: fixed; + top: 50%; + left: 50%; + margin: -25px 0 0 -25px; + z-index: $index + 1; } \ No newline at end of file diff --git a/src/custombox.spec.ts b/src/custombox.spec.ts index b098a76..1bce360 100644 --- a/src/custombox.spec.ts +++ b/src/custombox.spec.ts @@ -37,6 +37,12 @@ describe('Custombox', () => { overlays[i].parentNode.removeChild(overlays[i]); } + // custombox-loader + let loaders = document.querySelectorAll('.custombox-loader'); + for (let i = 0, t = loaders.length; i < t; i++) { + loaders[i].parentNode.removeChild(loaders[i]); + } + delete Custombox; jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; @@ -214,6 +220,12 @@ describe('Custombox', () => { overlays[i].parentNode.removeChild(overlays[i]); } + // custombox-loader + let loaders = document.querySelectorAll('.custombox-loader'); + for (let i = 0, t = loaders.length; i < t; i++) { + loaders[i].parentNode.removeChild(loaders[i]); + } + delete Custombox; jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; @@ -433,6 +445,12 @@ describe('Custombox', () => { overlays[i].parentNode.removeChild(overlays[i]); } + // custombox-loader + let loaders = document.querySelectorAll('.custombox-loader'); + for (let i = 0, t = loaders.length; i < t; i++) { + loaders[i].parentNode.removeChild(loaders[i]); + } + delete Custombox; jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; @@ -682,6 +700,12 @@ describe('Custombox', () => { overlays[i].parentNode.removeChild(overlays[i]); } + // custombox-loader + let loaders = document.querySelectorAll('.custombox-loader'); + for (let i = 0, t = loaders.length; i < t; i++) { + loaders[i].parentNode.removeChild(loaders[i]); + } + delete Custombox; jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; @@ -720,4 +744,121 @@ describe('Custombox', () => { }, 200); }); }); + + describe('Loader', () => { + let originalTimeout; + beforeEach(() => { + originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL; + jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; + }); + + beforeEach(() => { + for (let i = 1; i < 3; i++) { + let div = document.createElement('div'); + div.innerHTML = `Lorem ipmsum (${i}) ...`; + div.setAttribute('id', `foo-${i}`); + document.body.appendChild(div); + } + }); + + afterEach(()=> { + for (let i = 1; i < 3; i++) { + let elem = document.getElementById(`foo-${i}`); + elem.parentNode.removeChild(elem); + } + + // custombox-content + let contents = document.querySelectorAll('.custombox-content'); + for (let i = 0, t = contents.length; i < t; i++) { + contents[i].parentNode.removeChild(contents[i]); + } + + // custombox-overlay + let overlays = document.querySelectorAll('.custombox-overlay'); + for (let i = 0, t = overlays.length; i < t; i++) { + overlays[i].parentNode.removeChild(overlays[i]); + } + + // custombox-loader + let loaders = document.querySelectorAll('.custombox-loader'); + for (let i = 0, t = loaders.length; i < t; i++) { + loaders[i].parentNode.removeChild(loaders[i]); + } + + delete Custombox; + + jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; + }); + + it('should show loader', (done) => { + new (Custombox as any).modal({ + content: { + effect: 'fadein', + target: '#foo-1', + }, + loader: { + color: '#F00' + } + }).open(); + + setTimeout(() => { + expect(hasElement('.custombox-loader')).toBe(true); + let loader: any = document.querySelector('.custombox-loader'); + expect(loader.style.borderTopColor).toEqual('rgb(255, 0, 0)'); + done(); + }, 200); + }); + + it('should show loader when the overlay is disabled', (done) => { + new (Custombox as any).modal({ + content: { + effect: 'fadein', + target: '#foo-1', + }, + overlay: { + active: false + }, + loader: { + active: true + } + }); + + setTimeout(() => { + expect(hasElement('.custombox-loader')).toBe(true); + done(); + }, 200); + }); + + it(`shouldn't show loader`, (done) => { + new (Custombox as any).modal({ + content: { + effect: 'fadein', + target: '#foo-1', + }, + loader: { + active: false + } + }).open(); + + setTimeout(() => { + expect(hasElement('.custombox-loader')).toBe(false); + done(); + }, 200); + }); + + it('should remove loader when the overlay is completed', (done) => { + new (Custombox as any).modal({ + content: { + effect: 'fadein', + target: '#foo-1', + }, + }).open(); + + setTimeout(() => { + Custombox.modal.close(); + expect(hasElement('.custombox-loader')).toBe(false); + done(); + }, 500); + }); + }); }); \ No newline at end of file diff --git a/src/custombox.ts b/src/custombox.ts index 936b1fc..2439d06 100644 --- a/src/custombox.ts +++ b/src/custombox.ts @@ -3,6 +3,7 @@ namespace Custombox { overlay: OverlaySchema; content: ContentSchema; container: ContainerSchema; + loader: LoaderSchema; } interface OverlaySchema extends Speed, Callback { @@ -30,6 +31,11 @@ namespace Custombox { target: string; } + interface LoaderSchema { + active: boolean; + color: string; + } + interface Speed { speedIn: number; speedOut: number; @@ -109,6 +115,10 @@ namespace Custombox { container = { target: null }; + loader = { + active: true, + color: '#000' + }; } class Options extends DefaultSchema { @@ -123,6 +133,22 @@ namespace Custombox { } } + class Loader { + element: HTMLElement; + + constructor(private options: OptionsSchema) { + this.element = document.createElement('div'); + this.element.classList.add(`${CB}-loader`); + this.element.style.borderTopColor = this.options.loader.color; + document.body.appendChild(this.element); + } + + // Public methods + destroy(): void { + this.element.parentElement.removeChild(this.element); + } + } + class Container { element: HTMLElement; @@ -412,6 +438,7 @@ namespace Custombox { private content: Content; private overlay: Overlay; private scroll: Scroll; + private loader: Loader; private action: EventListenerOrEventListenerObject = (event: KeyboardEvent) => { if (event.keyCode === 27) { this._close(); @@ -421,6 +448,11 @@ namespace Custombox { constructor(options: OptionsSchema) { this.options = new Options(options); + // Create loader + if (this.options.loader.active) { + this.loader = new Loader(this.options); + } + // Create container if (Snippet.check(containerValues, this.options.content.effect)) { this.container = new Container(this.options); @@ -448,7 +480,17 @@ namespace Custombox { // Overlay if (this.options.overlay.active) { this.dispatchEvent('overlay.onOpen'); - this.overlay.bind(OPEN).then(() => this.dispatchEvent('overlay.onComplete')); + this.overlay + .bind(OPEN) + .then(() => { + this.dispatchEvent('overlay.onComplete'); + if (this.options.loader.active) { + this.loader.destroy(); + } + } + ); + } else if (this.options.loader.active) { + this.loader.destroy(); } // Container