UNPKG

@blinkk/editor

Version:

Structured content editor with live previews.

172 lines 7.15 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.LiveEditor = void 0; const dataStorage_1 = require("../utility/dataStorage"); const events_1 = require("./events"); const selective_edit_1 = require("@blinkk/selective-edit"); const api_1 = require("./api"); const amagakiProjectType_1 = require("../projectType/amagaki/amagakiProjectType"); const content_1 = require("./parts/content"); const empty_1 = require("./parts/empty"); const growProjectType_1 = require("../projectType/grow/growProjectType"); const menu_1 = require("./parts/menu"); const modals_1 = require("./parts/modals"); const notifications_1 = require("./parts/notifications"); const overview_1 = require("./parts/overview"); const preview_1 = require("./parts/preview"); const events_2 = require("@blinkk/selective-edit/dist/src/selective/events"); const javascript_time_ago_1 = __importDefault(require("javascript-time-ago")); const toasts_1 = require("./parts/toasts"); const en_1 = __importDefault(require("javascript-time-ago/locale/en")); // Set the default locale for the time ago globally. javascript_time_ago_1.default.addDefaultLocale(en_1.default); class LiveEditor { constructor(config, container) { this.config = config; this.container = container; this.isRendering = false; this.isPendingRender = false; this.storage = new dataStorage_1.LocalDataStorage(); this.state = this.config.state; this.parts = { content: new content_1.ContentPart({ selectiveConfig: this.config.selectiveConfig, state: this.state, storage: this.storage, }), empty: new empty_1.EmptyPart({ state: this.state, }), menu: new menu_1.MenuPart({ state: this.state, storage: this.storage, }), modals: new modals_1.ModalsPart(), notifications: new notifications_1.NotificationsPart(), overview: new overview_1.OverviewPart({ state: this.state, }), preview: new preview_1.PreviewPart({ state: this.state, storage: this.storage, }), toasts: new toasts_1.ToastsPart(), }; // Bind the editor to the global selective config. if (this.config.selectiveConfig.global) { this.config.selectiveConfig.global.editor = this; } // Update the project type when the project changes. this.state.addListener('getProject', () => { if (this.state.project?.type === api_1.ProjectTypes.Grow) { this.updateProjectType(new growProjectType_1.GrowProjectType()); } else if (this.state.project?.type === api_1.ProjectTypes.Amagaki) { this.updateProjectType(new amagakiProjectType_1.AmagakiProjectType()); } // Pull in the UI labels. if (this.state.project?.ui?.labels) { this.config.labels = Object.assign({}, this.config.labels || {}, this.state.project?.ui?.labels); } }); // Automatically re-render after the window resizes. window.addEventListener('resize', () => { this.render(); }); // Handle the global key bindings. container.addEventListener('keydown', (evt) => { if (evt.ctrlKey || evt.metaKey) { switch (evt.key) { case 's': evt.preventDefault(); document.dispatchEvent(new CustomEvent(events_1.EVENT_SAVE)); break; } } }); // Bind to the custom event to re-render the editor. document.addEventListener(events_1.EVENT_RENDER, () => { this.render(); }); // Bind to the selective event for rendering as well. document.addEventListener(events_2.EVENT_RENDER, () => { this.render(); }); } classesForEditor() { return { le: true, 'le--docked-menu': this.parts.menu.isDocked, }; } render() { if (this.isRendering) { this.isPendingRender = true; return; } this.isPendingRender = false; this.isRendering = true; selective_edit_1.render(this.template(this), this.container); this.isRendering = false; document.dispatchEvent(new CustomEvent(events_1.EVENT_RENDER_COMPLETE)); if (this.isPendingRender) { this.render(); } } template(editor) { return selective_edit_1.html `<div class=${selective_edit_1.classMap(this.classesForEditor())}> ${this.parts.menu.template(editor)} <div class="le__structure__content"> <div class="le__structure__content_header"> ${this.parts.overview.template(editor)} </div> ${this.templateContentStructure(editor)} </div> ${this.parts.modals.template(editor)} ${this.parts.toasts.template(editor)} </div>`; } templateContentStructure(editor) { if (!this.state.file) { return this.parts.empty.template(editor); } // Not having a url also qualifies to not show the preview. if (this.parts.content.isExpanded || !this.state.file.url) { return selective_edit_1.html `<div class="le__structure__content_only"> ${this.parts.content.template(editor)} </div>`; } if (this.parts.preview.isExpanded) { return selective_edit_1.html `<div class="le__structure__preview_only"> ${this.parts.preview.template(editor)} </div>`; } return selective_edit_1.html `<div class="le__structure__content_panes"> ${this.parts.content.template(editor)} ${this.parts.preview.template(editor)} </div>`; } updateProjectType(projectType) { this.projectType = projectType; this.config.selectiveConfig = this.config.selectiveConfig || {}; // Update selective fields available. this.config.selectiveConfig.fieldTypes = this.config.selectiveConfig.fieldTypes || {}; for (const [key, value] of Object.entries(this.projectType.fieldTypes || {})) { this.config.selectiveConfig.fieldTypes[key] = value; } // Update selective validation rules available. this.config.selectiveConfig.ruleTypes = this.config.selectiveConfig.ruleTypes || {}; for (const [key, value] of Object.entries(this.projectType.ruleTypes || {})) { this.config.selectiveConfig.ruleTypes[key] = value; } // Event to allow existing selective editors to reset. document.dispatchEvent(new CustomEvent(events_1.EVENT_PROJECT_TYPE_UPDATE)); } } exports.LiveEditor = LiveEditor; //# sourceMappingURL=editor.js.map