UNPKG

@naturalcycles/js-lib

Version:

Standard library for universal (browser + Node.js) javascript

100 lines (99 loc) 3.37 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AdminService = void 0; const tslib_1 = require("tslib"); const memo_decorator_1 = require("../decorators/memo.decorator"); const env_1 = require("../env"); const stringify_1 = require("../string/stringify"); const RED_DOT_ID = '__red-dot__'; const NOOP = () => { }; /** * @experimental * * Allows to listen for AdminMode keypress combination (Ctrl+Shift+L by default) to toggle AdminMode, * indicated by RedDot DOM element. * * todo: help with Authentication */ class AdminService { constructor(cfg) { this.cfg = { predicate: e => e.ctrlKey && e.key === 'L', persistToLocalStorage: true, localStorageKey: '__adminMode__', onRedDotClick: NOOP, onChange: NOOP, beforeEnter: () => true, beforeExit: () => true, ...cfg, }; } cfg; adminMode = false; listening = false; /** * Start listening to keyboard events to toggle AdminMode when detected. */ startListening() { if (this.listening || (0, env_1.isServerSide)()) return; this.adminMode = !!localStorage.getItem(this.cfg.localStorageKey); if (this.adminMode) this.toggleRedDotVisibility(); document.addEventListener('keydown', this.keydownListener.bind(this), { passive: true }); this.listening = true; } stopListening() { if ((0, env_1.isServerSide)()) return; document.removeEventListener('keydown', this.keydownListener); this.listening = false; } async keydownListener(e) { // console.log(e) if (!this.cfg.predicate(e)) return; await this.toggleRedDot(); } async toggleRedDot() { try { const allow = await this.cfg[this.adminMode ? 'beforeExit' : 'beforeEnter'](); if (!allow) return; // no change } catch (err) { console.error(err); // ok to show alert to Admins, it's not user-facing alert((0, stringify_1._stringify)(err)); return; // treat as "not allowed" } this.adminMode = !this.adminMode; this.toggleRedDotVisibility(); if (this.cfg.persistToLocalStorage) { const { localStorageKey } = this.cfg; if (this.adminMode) { localStorage.setItem(localStorageKey, '1'); } else { localStorage.removeItem(localStorageKey); } } this.cfg.onChange(this.adminMode); } toggleRedDotVisibility() { this.getRedDotElement().style.display = this.adminMode ? 'block' : 'none'; } getRedDotElement() { const el = document.createElement('div'); el.id = RED_DOT_ID; el.style.cssText = 'position:fixed;width:24px;height:24px;margin-top:-12px;background-color:red;opacity:0.5;top:50%;left:0;z-index:9999999;cursor:pointer;border-radius:0 3px 3px 0'; el.addEventListener('click', () => this.cfg.onRedDotClick()); document.body.append(el); return el; } } exports.AdminService = AdminService; tslib_1.__decorate([ (0, memo_decorator_1._Memo)() ], AdminService.prototype, "getRedDotElement", null);