diff --git a/README.md b/README.md index 4ef1e485bc..966e9961e2 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,7 @@ Parameters: * `backgroundColor` – image background color * `bondThickness` – thickness of bonds in output structure -`updateMonomersLibrary(monomersData: string | JSON): void` – given the monomers data, perform upsert operation for the built-in monomers library in the macromolecules editor. Might be invoked only when macromolecules editor is turned on. Update (replace) operation is performed for the particular monomer if its alias and class are matching with the existing one. Otherwise, insert operation is performed. +`updateMonomersLibrary(monomersData: string | JSON): void` – given the monomers data, perform upsert operation for the built-in monomers library in the macromolecules editor. Update (replace) operation is performed for the particular monomer if its alias and class are matching with the existing one. Otherwise, insert operation is performed. Parameters: `monomersData: string | JSON` – monomers description in KET format being formatted as either JSON notation or this JSON being stringified to be more concise. ## Settings diff --git a/packages/ketcher-core/src/application/editor/Editor.ts b/packages/ketcher-core/src/application/editor/Editor.ts index 21882e9d77..9d72f9ff20 100644 --- a/packages/ketcher-core/src/application/editor/Editor.ts +++ b/packages/ketcher-core/src/application/editor/Editor.ts @@ -61,6 +61,7 @@ interface ICoreEditorConstructorParams { theme; canvas: SVGSVGElement; mode?: BaseMode; + // Raw monomers data in KET format that has to be applied as library update ahead of time on Ketcher initialization – check `updateMonomersLibrary` method of Ketcher API monomersLibraryUpdate?: string | JSON; } @@ -71,6 +72,7 @@ function isMouseMainButtonPressed(event: MouseEvent) { let persistentMonomersLibrary: MonomerItemType[] = []; let persistentMonomersLibraryParsedJson: IKetMacromoleculesContent | null = null; +let storedMonomersLibraryUpdates: Array = []; let editor; export class CoreEditor { @@ -118,11 +120,7 @@ export class CoreEditor { this.mode = mode ?? new SequenceMode(); resetEditorEvents(); this.events = editorEvents; - this.setMonomersLibrary(monomersDataRaw); - this._monomersLibraryParsedJson = JSON.parse(monomersDataRaw); - if (monomersLibraryUpdate) { - this.updateMonomersLibrary(monomersLibraryUpdate); - } + this.setMonomersLibrary(monomersDataRaw, monomersLibraryUpdate); this.subscribeEvents(); this.renderersContainer = new RenderersManager({ theme }); this.drawingEntitiesManager = new DrawingEntitiesManager(); @@ -158,7 +156,10 @@ export class CoreEditor { return { monomersLibraryParsedJson, monomersLibrary }; } - private setMonomersLibrary(monomersDataRaw: string) { + private setMonomersLibrary( + monomersDataRaw: string, + initialMonomersLibraryUpdate?: string | JSON, + ) { if ( persistentMonomersLibrary.length !== 0 && persistentMonomersLibraryParsedJson !== undefined @@ -172,8 +173,21 @@ export class CoreEditor { this.parseMonomersLibrary(monomersDataRaw); this._monomersLibrary = monomersLibrary; this._monomersLibraryParsedJson = monomersLibraryParsedJson; - persistentMonomersLibrary = monomersLibrary; - persistentMonomersLibraryParsedJson = monomersLibraryParsedJson; + + if (initialMonomersLibraryUpdate) { + this.updateMonomersLibrary(initialMonomersLibraryUpdate); + } + storedMonomersLibraryUpdates.forEach((storedMonomersLibraryUpdate) => { + this.updateMonomersLibrary(storedMonomersLibraryUpdate); + }); + storedMonomersLibraryUpdates = []; + + persistentMonomersLibrary = this._monomersLibrary; + persistentMonomersLibraryParsedJson = this._monomersLibraryParsedJson; + } + + static storeMonomersLibraryUpdate(monomersDataRaw: string | JSON) { + storedMonomersLibraryUpdates.push(monomersDataRaw); } public updateMonomersLibrary(monomersDataRaw: string | JSON) { @@ -183,6 +197,10 @@ export class CoreEditor { } = this.parseMonomersLibrary(monomersDataRaw); newMonomersLibraryChunk.forEach((newMonomer) => { + if (!this._monomersLibraryParsedJson) { + return; + } + const existingMonomerIndex = this._monomersLibrary.findIndex( (monomer) => { return ( @@ -202,35 +220,27 @@ export class CoreEditor { this._monomersLibrary[existingMonomerIndex].props; const existingMonomerIdToUse = existingMonomerProps.id || existingMonomerProps.MonomerName; - // It's safe to use non-null assertion here and below because we already specified monomers library and parsed JSON before const existingMonomerRefIndex = - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - this._monomersLibraryParsedJson!.root.templates.findIndex( + this._monomersLibraryParsedJson.root.templates.findIndex( (template) => template.$ref === existingMonomerIdToUse, ); if (existingMonomerRefIndex && existingMonomerRefIndex !== -1) { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - delete this._monomersLibraryParsedJson!.root.templates[ + delete this._monomersLibraryParsedJson.root.templates[ existingMonomerRefIndex ]; - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - delete this._monomersLibraryParsedJson![existingMonomerIdToUse]; - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - this._monomersLibraryParsedJson!.root.templates.push({ + delete this._monomersLibraryParsedJson[existingMonomerIdToUse]; + this._monomersLibraryParsedJson.root.templates.push({ $ref: monomerIdToUse, }); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - this._monomersLibraryParsedJson![monomerIdToUse] = + this._monomersLibraryParsedJson[monomerIdToUse] = newMonomersLibraryChunkParsedJson[monomerIdToUse]; } } else { this._monomersLibrary.push(newMonomer); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - this._monomersLibraryParsedJson!.root.templates.push({ + this._monomersLibraryParsedJson.root.templates.push({ $ref: monomerIdToUse, }); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - this._monomersLibraryParsedJson![monomerIdToUse] = + this._monomersLibraryParsedJson[monomerIdToUse] = newMonomersLibraryChunkParsedJson[monomerIdToUse]; } }); diff --git a/packages/ketcher-core/src/application/ketcher.ts b/packages/ketcher-core/src/application/ketcher.ts index 7e6d600686..fa4695d58c 100644 --- a/packages/ketcher-core/src/application/ketcher.ts +++ b/packages/ketcher-core/src/application/ketcher.ts @@ -40,7 +40,6 @@ import { import { deleteAllEntitiesOnCanvas, getStructure, - ketcherProvider, parseAndAddMacromoleculesOnCanvas, prepareStructToRender, } from './utils'; @@ -542,14 +541,10 @@ export class Ketcher { public updateMonomersLibrary(rawMonomersData: string | JSON) { const editor = CoreEditor.provideEditorInstance(); - ketcherProvider.getKetcher(); - if (!editor) { - throw new Error( - 'Updating monomer library in small molecules mode is not allowed, please switch to macromolecules mode', - ); + CoreEditor.storeMonomersLibraryUpdate(rawMonomersData); + } else { + editor.updateMonomersLibrary(rawMonomersData); } - - editor.updateMonomersLibrary(rawMonomersData); } }