UNPKG

angular2-promise-buttons

Version:
306 lines (295 loc) 13.7 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core'), require('rxjs')) : typeof define === 'function' && define.amd ? define('angular2-promise-buttons', ['exports', '@angular/core', 'rxjs'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["angular2-promise-buttons"] = {}, global.ng.core, global.rxjs)); })(this, (function (exports, i0, rxjs) { 'use strict'; function _interopNamespace(e) { if (e && e.__esModule) return e; var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n["default"] = e; return Object.freeze(n); } var i0__namespace = /*#__PURE__*/_interopNamespace(i0); var DEFAULT_CFG = { spinnerTpl: '<span class="btn-spinner"></span>', disableBtn: true, btnLoadingClass: 'is-loading', handleCurrentBtnOnly: false, minDuration: null, }; var userCfg = new i0.InjectionToken('cfg'); var PromiseBtnDirective = /** @class */ (function () { function PromiseBtnDirective(el, cfg) { // provide configuration this.cfg = Object.assign({}, DEFAULT_CFG, cfg); // save element this.btnEl = el.nativeElement; } Object.defineProperty(PromiseBtnDirective.prototype, "isDisabledFromTheOutsideSetter", { // this is added to fix the overriding of the disabled state by the loading indicator button. // https://github.com/johannesjo/angular2-promise-buttons/issues/34 set: function (v) { this.isDisabledFromTheOutside = v; if (v) { // disabled means always disabled this.btnEl.setAttribute('disabled', 'disabled'); } else if (this.isPromiseDone || this.isPromiseDone === undefined) { this.btnEl.removeAttribute('disabled'); } // else the button is loading, so do not change the disabled loading state. }, enumerable: false, configurable: true }); Object.defineProperty(PromiseBtnDirective.prototype, "promiseBtn", { set: function (passedValue) { var isObservable = passedValue instanceof rxjs.Observable; var isSubscription = passedValue instanceof rxjs.Subscription; var isBoolean = typeof passedValue === 'boolean'; var isPromise = passedValue instanceof Promise || (passedValue !== null && typeof passedValue === 'object' && typeof passedValue.then === 'function' && typeof passedValue.catch === 'function'); if (isObservable) { throw new TypeError('promiseBtn must be an instance of Subscription, instance of Observable given'); } else if (isSubscription) { var sub_1 = passedValue; if (!sub_1.closed) { this.promise = new Promise(function (resolve) { sub_1.add(resolve); }); } } else if (isPromise) { this.promise = passedValue; } else if (isBoolean) { this.promise = this.createPromiseFromBoolean(passedValue); } this.checkAndInitPromiseHandler(this.btnEl); }, enumerable: false, configurable: true }); PromiseBtnDirective.prototype.ngAfterContentInit = function () { this.prepareBtnEl(this.btnEl); // trigger changes once to handle initial promises this.checkAndInitPromiseHandler(this.btnEl); }; PromiseBtnDirective.prototype.ngOnDestroy = function () { // cleanup if (this.minDurationTimeout) { clearTimeout(this.minDurationTimeout); } }; PromiseBtnDirective.prototype.createPromiseFromBoolean = function (val) { var _this = this; if (val) { return new Promise(function (resolve) { _this._fakePromiseResolve = resolve; }); } else { if (this._fakePromiseResolve) { this._fakePromiseResolve(); } return this.promise; } }; /** * Initializes all html and event handlers */ PromiseBtnDirective.prototype.prepareBtnEl = function (btnEl) { // handle promises passed via promiseBtn attribute this.appendSpinnerTpl(btnEl); }; /** * Checks if all required parameters are there and inits the promise handler */ PromiseBtnDirective.prototype.checkAndInitPromiseHandler = function (btnEl) { // check if element and promise is set if (btnEl && this.promise) { this.initPromiseHandler(btnEl); } }; /** * Helper FN to add class */ PromiseBtnDirective.prototype.addLoadingClass = function (el) { if (typeof this.cfg.btnLoadingClass === 'string') { el.classList.add(this.cfg.btnLoadingClass); } }; /** * Helper FN to remove classes */ PromiseBtnDirective.prototype.removeLoadingClass = function (el) { if (typeof this.cfg.btnLoadingClass === 'string') { el.classList.remove(this.cfg.btnLoadingClass); } }; /** * Handles everything to be triggered when the button is set * to loading state. */ PromiseBtnDirective.prototype.initLoadingState = function (btnEl) { this.addLoadingClass(btnEl); this.disableBtn(btnEl); }; /** * Handles everything to be triggered when loading is finished */ PromiseBtnDirective.prototype.cancelLoadingStateIfPromiseAndMinDurationDone = function (btnEl) { if ((!this.cfg.minDuration || this.isMinDurationTimeoutDone) && this.isPromiseDone) { this.removeLoadingClass(btnEl); this.enableBtn(btnEl); } }; PromiseBtnDirective.prototype.disableBtn = function (btnEl) { if (this.cfg.disableBtn) { btnEl.setAttribute('disabled', 'disabled'); } }; PromiseBtnDirective.prototype.enableBtn = function (btnEl) { if (this.cfg.disableBtn) { if (this.isDisabledFromTheOutside) { btnEl.setAttribute('disabled', 'disabled'); } else { btnEl.removeAttribute('disabled'); } } }; /** * Initializes a watcher for the promise. Also takes * this.cfg.minDuration into account if given. */ PromiseBtnDirective.prototype.initPromiseHandler = function (btnEl) { var _this = this; var promise = this.promise; // watch promise to resolve or fail this.isMinDurationTimeoutDone = false; this.isPromiseDone = false; // create timeout if option is set if (this.cfg.minDuration) { this.minDurationTimeout = window.setTimeout(function () { _this.isMinDurationTimeoutDone = true; _this.cancelLoadingStateIfPromiseAndMinDurationDone(btnEl); }, this.cfg.minDuration); } var resolveLoadingState = function () { _this.isPromiseDone = true; _this.cancelLoadingStateIfPromiseAndMinDurationDone(btnEl); }; if (!this.cfg.handleCurrentBtnOnly) { this.initLoadingState(btnEl); } // native Promise doesn't have finally if (promise.finally) { promise.finally(resolveLoadingState); } else { promise .then(resolveLoadingState) .catch(resolveLoadingState); } }; /** * $compile and append the spinner template to the button. */ PromiseBtnDirective.prototype.appendSpinnerTpl = function (btnEl) { // TODO add some kind of compilation later on btnEl.insertAdjacentHTML('beforeend', this.cfg.spinnerTpl); }; /** * Limit loading state to show only for the currently clicked button. * Executed only if this.cfg.handleCurrentBtnOnly is set */ PromiseBtnDirective.prototype.handleCurrentBtnOnly = function () { var _this = this; if (!this.cfg.handleCurrentBtnOnly) { return true; // return true for testing } // Click triggers @Input update // We need to use timeout to wait for @Input to update window.setTimeout(function () { // return if something else than a promise is passed if (!_this.promise) { return; } _this.initLoadingState(_this.btnEl); }, 0); }; return PromiseBtnDirective; }()); PromiseBtnDirective.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0__namespace, type: PromiseBtnDirective, deps: [{ token: i0__namespace.ElementRef }, { token: userCfg }], target: i0__namespace.ɵɵFactoryTarget.Directive }); PromiseBtnDirective.ɵdir = i0__namespace.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "12.2.17", type: PromiseBtnDirective, selector: "[promiseBtn]", inputs: { isDisabledFromTheOutsideSetter: ["disabled", "isDisabledFromTheOutsideSetter"], promiseBtn: "promiseBtn" }, host: { listeners: { "click": "handleCurrentBtnOnly()" } }, ngImport: i0__namespace }); i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0__namespace, type: PromiseBtnDirective, decorators: [{ type: i0.Directive, args: [{ selector: '[promiseBtn]' }] }], ctorParameters: function () { return [{ type: i0__namespace.ElementRef }, { type: undefined, decorators: [{ type: i0.Inject, args: [userCfg] }] }]; }, propDecorators: { isDisabledFromTheOutsideSetter: [{ type: i0.Input, args: ['disabled'] }], promiseBtn: [{ type: i0.Input }], handleCurrentBtnOnly: [{ type: i0.HostListener, args: ['click'] }] } }); var Angular2PromiseButtonModule = /** @class */ (function () { function Angular2PromiseButtonModule() { } // add forRoot to make it configurable Angular2PromiseButtonModule.forRoot = function (config) { // NOTE: this is never allowed to contain any conditional logic return { ngModule: Angular2PromiseButtonModule, providers: [{ provide: userCfg, useValue: config }] }; }; return Angular2PromiseButtonModule; }()); Angular2PromiseButtonModule.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0__namespace, type: Angular2PromiseButtonModule, deps: [], target: i0__namespace.ɵɵFactoryTarget.NgModule }); Angular2PromiseButtonModule.ɵmod = i0__namespace.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0__namespace, type: Angular2PromiseButtonModule, declarations: [PromiseBtnDirective], exports: [PromiseBtnDirective] }); Angular2PromiseButtonModule.ɵinj = i0__namespace.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0__namespace, type: Angular2PromiseButtonModule, providers: [], imports: [[]] }); i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0__namespace, type: Angular2PromiseButtonModule, decorators: [{ type: i0.NgModule, args: [{ declarations: [ PromiseBtnDirective, ], imports: [], exports: [ PromiseBtnDirective, ], providers: [] }] }] }); /** * Generated bundle index. Do not edit. */ exports.Angular2PromiseButtonModule = Angular2PromiseButtonModule; exports.PromiseBtnDirective = PromiseBtnDirective; Object.defineProperty(exports, '__esModule', { value: true }); })); //# sourceMappingURL=angular2-promise-buttons.umd.js.map