Skip to content

Commit

Permalink
chore: continue implem of custom element
Browse files Browse the repository at this point in the history
  • Loading branch information
tpoisseau committed Jul 25, 2024
1 parent f5422f0 commit 1e542ac
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 19 deletions.
156 changes: 138 additions & 18 deletions lib/canvas_editor/init/canvas_editor_element.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
'use strict';

function initCanvasEditorElement(CanvasEditor, Molecule) {
function initCanvasEditorElement(CanvasEditor, Molecule, ReactionEncoder) {
/**
* `<openchemlib-editor>` 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
* <openchemlib-editor></openchemlib-editor>
* ```
*/
class CanvasEditorElement extends HTMLElement {
/** @type {{MOLECULE: 'molecule', REACTION: 'reaction'}} */
static MODE = Object.freeze(
Expand All @@ -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.
Expand All @@ -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;
Expand Down
7 changes: 6 additions & 1 deletion lib/canvas_editor/init/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ function init(OCL) {
GenericEditorToolbar: JavaEditorToolbar,
GenericUIHelper: JavaUIHelper,
Molecule,
ReactionEncoder,
} = OCL;

const CanvasEditor = initCanvasEditor(
Expand All @@ -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);
}

Expand Down

0 comments on commit 1e542ac

Please sign in to comment.