From 1e542ac0e5765a9f12097c2295092c07d52a0402 Mon Sep 17 00:00:00 2001 From: tpoisseau <22891227+tpoisseau@users.noreply.github.com> Date: Thu, 25 Jul 2024 10:06:43 +0200 Subject: [PATCH] chore: continue implem of custom element --- .../init/canvas_editor_element.js | 156 ++++++++++++++++-- lib/canvas_editor/init/index.js | 7 +- 2 files changed, 144 insertions(+), 19 deletions(-) diff --git a/lib/canvas_editor/init/canvas_editor_element.js b/lib/canvas_editor/init/canvas_editor_element.js index ada86299..9ebfcaca 100644 --- a/lib/canvas_editor/init/canvas_editor_element.js +++ b/lib/canvas_editor/init/canvas_editor_element.js @@ -1,6 +1,25 @@ 'use strict'; -function initCanvasEditorElement(CanvasEditor, Molecule) { +function initCanvasEditorElement(CanvasEditor, Molecule, ReactionEncoder) { + /** + * `` support 4 observable attributes : + * + * - idcode: init molecule with `Molecule.fromIDCode(idcode)` or reaction with `ReactionEncoder.decode(this.idcode)`. + * fallback to an empty string if not defined. + * - fragment: enable or disable fragment on Molecule / Reaction. + * fallback to false if not defined. + * - mode: can be either `'molecule'` or `'reaction'`. `CanvasEditorElement.MODE` map these values for enum style. + * fallback to `CanvasEditorElement.MODE.MOLECULE` if not defined. + * - readonly: if enable, it do not add toolbar and don't handle user interactions. + * fallback to false. + * + * @example + * + * Empty editor: + * ```html + * + * ``` + */ class CanvasEditorElement extends HTMLElement { /** @type {{MOLECULE: 'molecule', REACTION: 'reaction'}} */ static MODE = Object.freeze( @@ -23,42 +42,121 @@ function initCanvasEditorElement(CanvasEditor, Molecule) { CanvasEditorElement.MODE.MOLECULE; /** @type {boolean} */ readonly = false; - /** @type {CanvasEditor} */ #editor; + /* --- custom element api --- */ + /** + * @param {Molecule} molecule + */ + setMolecule(molecule) { + this.fragment = molecule.isFragment(); + this.idcode = molecule.getIDCode(); + + this.#editor.setMolecule(molecule); + } /** - * Custom element added to page. + * @return {Molecule} */ - connectedCallback() { - const root = this.attachShadow({ mode: 'open' }); - root.adoptedStyleSheets = [new CSSStyleSheet()]; + getMolecule() { + return this.#editor.getMolecule(); + } + + /** + * @param {Reaction} reaction + */ + setReaction(reaction) { + this.fragment = reaction.isFragment(); + this.idcode = ReactionEncoder.encode(reaction); - this.#editor = new CanvasEditor(root, { + this.#editor.setReaction(reaction); + } + + /** + * @return {Reaction} + */ + getReaction() { + return this.#editor.getReaction(); + } + + clearAll() { + this.#editor.clearAll(); + this.idcode = ''; + } + + /* --- internals --- */ + /** @type {CanvasEditor} */ #editor; + + #initEditor() { + this.#editor = new CanvasEditor(this.shadowRoot, { readOnly: this.readonly, initialMode: this.mode, }); + this.#editor.setOnChangeListener(this.#handleChange); + this.#initIdCode(); + } + + #initIdCode() { switch (this.mode) { case this.constructor.MODE.MOLECULE: { - const molecule = Molecule.fromIDCode(this.idcode || ''); - molecule.setFragment(this.fragment); - - return this.#editor.setMolecule(molecule); + return this.#initMolecule(); } case this.constructor.MODE.REACTION: { - throw new Error( - 'Unsupported because `Reaction.fromIDCode` do not exists', - ); + return this.#initReaction(); } default: throw new Error(`Mode ${this.mode} is not supported`); } } + #initMolecule() { + const molecule = Molecule.fromIDCode(this.idcode); + molecule.setFragment(this.fragment); + + this.#editor.setMolecule(molecule); + } + + #initReaction() { + const reaction = ReactionEncoder.decode(this.idcode); + reaction.setFragment(this.fragment); + + this.#editor.setReaction(reaction); + } + + #handleChange = (editorEventOnChange) => { + const domEvent = new CustomEvent('change', { + detail: editorEventOnChange, + }); + this.dispatchEvent(domEvent); + }; + + #destroyEditor() { + this.#editor.destroy(); + this.#editor = undefined; + } + + #resetEditor() { + this.#destroyEditor(); + this.#initEditor(); + } + + /* --- lifecycle hooks --- */ + /** + * Custom element added to page. + */ + connectedCallback() { + this.attachShadow({ mode: 'open' }); + this.shadowRoot.adoptedStyleSheets = [new CSSStyleSheet()]; + this.#initEditor(); + } + /** * Custom element removed from page. */ - // eslint-disable-next-line no-empty-function - disconnectedCallback() {} + disconnectedCallback() { + if (!this.#editor) return; + this.#editor.destroy(); + this.#editor = undefined; + } /** * Custom element moved to new page. @@ -69,8 +167,30 @@ function initCanvasEditorElement(CanvasEditor, Molecule) { /** * Attribute ${name} has changed from ${oldValue} to ${newValue} */ - // eslint-disable-next-line no-unused-vars,no-empty-function - attributeChangedCallback(name, oldValue, newValue) {} + attributeChangedCallback(name, oldValue, newValue) { + switch (name) { + case 'idcode': { + this.idcode = newValue; + return void this.#initIdCode(); + } + case 'fragment': { + this.fragment = newValue; + const molecule = this.#editor.getMolecule(); + molecule.setFragment(this.fragment); + return void this.#editor.setMolecule(molecule); + } + case 'mode': { + this.mode = newValue; + return void this.#resetEditor(); + } + case 'readonly': { + this.readonly = newValue; + return void this.#resetEditor(); + } + default: + throw new Error('unsupported attribute change'); + } + } } return CanvasEditorElement; diff --git a/lib/canvas_editor/init/index.js b/lib/canvas_editor/init/index.js index c655d79b..df802297 100644 --- a/lib/canvas_editor/init/index.js +++ b/lib/canvas_editor/init/index.js @@ -9,6 +9,7 @@ function init(OCL) { GenericEditorToolbar: JavaEditorToolbar, GenericUIHelper: JavaUIHelper, Molecule, + ReactionEncoder, } = OCL; const CanvasEditor = initCanvasEditor( @@ -18,7 +19,11 @@ function init(OCL) { ); function registerCustomElement() { - const CanvasEditorElement = initCanvasEditorElement(CanvasEditor, Molecule); + const CanvasEditorElement = initCanvasEditorElement( + CanvasEditor, + Molecule, + ReactionEncoder, + ); customElements.define('openchemlib-editor', CanvasEditorElement); }