diff --git a/packages/ketcher-core/src/application/render/restruct/reatom.ts b/packages/ketcher-core/src/application/render/restruct/reatom.ts index 0bcbf828c4..b0bf9560ed 100644 --- a/packages/ketcher-core/src/application/render/restruct/reatom.ts +++ b/packages/ketcher-core/src/application/render/restruct/reatom.ts @@ -413,17 +413,26 @@ class ReAtom extends ReObject { // TODO: fragment should not be null const fragment = restruct.molecule.frags.get(fragmentId); - const text = - (shouldDisplayStereoLabel( - stereoLabel, - options.stereoLabelStyle, - options.ignoreChiralFlag, - fragment?.enhancedStereoFlag, - ) - ? `${stereoLabel}\n` - : '') + - (queryAttrsText.length > 0 ? `${queryAttrsText}\n` : '') + - (aamText.length > 0 ? `.${aamText}.` : ''); + const displayStereoLabel = shouldDisplayStereoLabel( + stereoLabel, + options.stereoLabelStyle, + options.ignoreChiralFlag, + fragment?.enhancedStereoFlag, + ); + + let text = ''; + + if (displayStereoLabel) { + text = `${stereoLabel}\n`; + } + + if (queryAttrsText.length > 0) { + text += `${queryAttrsText}\n`; + } + + if (aamText.length > 0) { + text += `.${aamText}.`; + } if (text.length > 0) { const elem = Elements.get(this.a.label); @@ -574,12 +583,19 @@ function shouldDisplayStereoLabel( ignoreChiralFlag, flag: StereoFlag | undefined, ): boolean { - if (!stereoLabel || ignoreChiralFlag) { + if (!stereoLabel) { return false; } const stereoLabelType = stereoLabel.match(/\D+/g)[0]; + if (ignoreChiralFlag && stereoLabelType === StereoLabel.Abs) { + return false; + } + if (ignoreChiralFlag && stereoLabelType !== StereoLabel.Abs) { + return true; + } + switch (labelStyle) { case StereLabelStyleType.Off: return false; diff --git a/packages/ketcher-core/src/application/render/restruct/reenhancedFlag.ts b/packages/ketcher-core/src/application/render/restruct/reenhancedFlag.ts index 4ba5d04c44..9540efe260 100644 --- a/packages/ketcher-core/src/application/render/restruct/reenhancedFlag.ts +++ b/packages/ketcher-core/src/application/render/restruct/reenhancedFlag.ts @@ -57,15 +57,8 @@ class ReEnhancedFlag extends ReObject { show(restruct: ReStruct, fragmentId: number, options: any): void { const render = restruct.render; const fragment = restruct.molecule.frags.get(fragmentId); - const stereoFlag = fragment?.enhancedStereoFlag; - if (!stereoFlag) { - return; - } - - // We don't want to show the ovarall label (flag) in case there are different types - // of stereo labels inside the structure ("mixed" and "or" stereo flags indicate that) - if (stereoFlag === StereoFlag.Mixed || stereoFlag === StereoFlag.Or) { + if (!fragment?.enhancedStereoFlag) { return; } @@ -85,7 +78,13 @@ class ReEnhancedFlag extends ReObject { if (options.showStereoFlags && !options.ignoreChiralFlag) { this.#path = paper - .text(ps.x, ps.y, stereoFlag ? stereoFlagMap[stereoFlag] : '') + .text( + ps.x, + ps.y, + fragment.enhancedStereoFlag + ? stereoFlagMap[fragment.enhancedStereoFlag] + : '', + ) .attr({ font: options.font, 'font-size': options.fontsz, diff --git a/packages/ketcher-core/src/domain/serializers/mol/mol.types.ts b/packages/ketcher-core/src/domain/serializers/mol/mol.types.ts index f07d512531..6dedae8bdd 100644 --- a/packages/ketcher-core/src/domain/serializers/mol/mol.types.ts +++ b/packages/ketcher-core/src/domain/serializers/mol/mol.types.ts @@ -15,11 +15,11 @@ ***************************************************************************/ export interface MolSerializerOptions { - reactionRelayout: boolean; - badHeaderRecover: boolean; - ignoreErrors: boolean; - noRgroups: boolean; - preserveIndigoDesc: boolean; + reactionRelayout?: boolean; + badHeaderRecover?: boolean; + ignoreErrors?: boolean; + noRgroups?: boolean; + preserveIndigoDesc?: boolean; ignoreChiralFlag?: boolean; } diff --git a/packages/ketcher-core/src/domain/serializers/sdf/sdfSerializer.ts b/packages/ketcher-core/src/domain/serializers/sdf/sdfSerializer.ts index 31bdb0830c..47000a48c7 100644 --- a/packages/ketcher-core/src/domain/serializers/sdf/sdfSerializer.ts +++ b/packages/ketcher-core/src/domain/serializers/sdf/sdfSerializer.ts @@ -18,13 +18,20 @@ import { SdfItem, StructAssociatedData } from './sdf.types'; import { MolSerializer } from '../mol/molSerializer'; import { Serializer } from '../serializers.types'; +import { MolSerializerOptions } from '../mol'; const DelimeterRegex = /^[^]+?\$\$\$\$$/gm; export class SdfSerializer implements Serializer> { + private readonly molSerializerOptions?: MolSerializerOptions; + + constructor(options?: MolSerializerOptions) { + this.molSerializerOptions = options; + } + deserialize(content: string): Array { let m: any; const result: Array = []; - const molSerializer = new MolSerializer(); + const molSerializer = new MolSerializer(this.molSerializerOptions); while ((m = DelimeterRegex.exec(content)) !== null) { const chunk = m[0].replace(/\r/g, '').trim(); // TODO: normalize newline? const end = chunk.indexOf('M END'); @@ -55,7 +62,7 @@ export class SdfSerializer implements Serializer> { } serialize(sdfItems: Array): string { - const molSerializer = new MolSerializer(); + const molSerializer = new MolSerializer(this.molSerializerOptions); return sdfItems.reduce((res, item) => { res += molSerializer.serialize(item.struct); diff --git a/packages/ketcher-react/src/constants.ts b/packages/ketcher-react/src/constants.ts index 24535daee2..0f19471a76 100644 --- a/packages/ketcher-react/src/constants.ts +++ b/packages/ketcher-react/src/constants.ts @@ -18,6 +18,8 @@ export const KETCHER_INIT_EVENT_NAME = 'ketcher-init'; export const KETCHER_SAVED_SETTINGS_KEY = 'ketcher_editor_saved_settings'; +export const KETCHER_SAVED_OPTIONS_KEY = 'ketcher-opts'; + export const MODES = { FG: 'fg', }; diff --git a/packages/ketcher-react/src/script/ui/state/options/index.js b/packages/ketcher-react/src/script/ui/state/options/index.js index 0d12ebec15..feb84ac80d 100644 --- a/packages/ketcher-react/src/script/ui/state/options/index.js +++ b/packages/ketcher-react/src/script/ui/state/options/index.js @@ -22,6 +22,8 @@ import { import { pick } from 'lodash/fp'; import { storage } from '../../storage-ext'; +import { reinitializeTemplateLibrary } from '../templates/init-lib'; +import { KETCHER_SAVED_OPTIONS_KEY } from 'src/constants'; export const initOptionsState = { app: { @@ -59,7 +61,7 @@ export const initOptionsState = { }, settings: Object.assign( getDefaultOptions(), - validation(storage.getItem('ketcher-opts')), + validation(storage.getItem(KETCHER_SAVED_OPTIONS_KEY)), ), getServerSettings() { return pick(SERVER_OPTIONS, this.settings); @@ -75,7 +77,9 @@ export function appUpdate(data) { /* SETTINGS */ export function saveSettings(newSettings) { - storage.setItem('ketcher-opts', newSettings); + storage.setItem(KETCHER_SAVED_OPTIONS_KEY, newSettings); + reinitializeTemplateLibrary(); + return { type: 'SAVE_SETTINGS', data: newSettings, diff --git a/packages/ketcher-react/src/script/ui/state/templates/init-lib.js b/packages/ketcher-react/src/script/ui/state/templates/init-lib.ts similarity index 84% rename from packages/ketcher-react/src/script/ui/state/templates/init-lib.js rename to packages/ketcher-react/src/script/ui/state/templates/init-lib.ts index bebb50850a..c947a711ee 100644 --- a/packages/ketcher-react/src/script/ui/state/templates/init-lib.js +++ b/packages/ketcher-react/src/script/ui/state/templates/init-lib.ts @@ -19,6 +19,9 @@ import { KetSerializer, SdfSerializer } from 'ketcher-core'; import { appUpdate } from '../options'; import { storage } from '../../storage-ext'; import templatesRawData from '../../../../templates/library.sdf'; +import { OptionsManager } from '../../utils/optionsManager'; + +let cachedInitData: [unknown, unknown, unknown]; export function initLib(lib) { return { @@ -28,7 +31,11 @@ export function initLib(lib) { } const deserializeSdfTemplates = (baseUrl, cacheEl, _fileName) => { - const sdfSerializer = new SdfSerializer(); + const options = { + ignoreChiralFlag: OptionsManager.ignoreChiralFlag, + }; + + const sdfSerializer = new SdfSerializer(options); const tmpls = sdfSerializer.deserialize(templatesRawData); const prefetch = prefetchRender(tmpls, baseUrl + '/templates/', cacheEl); @@ -45,14 +52,27 @@ const deserializeSdfTemplates = (baseUrl, cacheEl, _fileName) => { }; export default function initTmplLib(dispatch, baseUrl, cacheEl) { + cachedInitData = [dispatch, baseUrl, cacheEl]; + const fileName = 'library.sdf'; + return deserializeSdfTemplates(baseUrl, cacheEl, fileName).then((res) => { - const lib = res.concat(userTmpls()); + const lib = res.concat(userTmpls() as []); dispatch(initLib(lib)); dispatch(appUpdate({ templates: true })); }); } +export function reinitializeTemplateLibrary() { + if (!cachedInitData) { + throw new Error( + 'The template library must be initialized before it can be reinitialized', + ); + } + + initTmplLib(...cachedInitData); +} + function userTmpls() { const userLib = storage.getItem('ketcher-tmpls'); if (!Array.isArray(userLib) || userLib.length === 0) return []; diff --git a/packages/ketcher-react/src/script/ui/utils/optionsManager.ts b/packages/ketcher-react/src/script/ui/utils/optionsManager.ts new file mode 100644 index 0000000000..c9b21d2a0b --- /dev/null +++ b/packages/ketcher-react/src/script/ui/utils/optionsManager.ts @@ -0,0 +1,38 @@ +import { KETCHER_SAVED_OPTIONS_KEY } from 'src/constants'; +import { storage } from '../storage-ext'; + +interface SavedOptions { + ignoreChiralFlag?: boolean; +} + +export class OptionsManager { + static getOptions(): SavedOptions { + try { + return JSON.parse(storage.getItem(KETCHER_SAVED_OPTIONS_KEY) || '{}'); + } catch (e) { + return {} as SavedOptions; + } + } + + static saveSettings(settings: SavedOptions) { + if (!settings) { + return; + } + storage.setItem(KETCHER_SAVED_OPTIONS_KEY, JSON.stringify(settings)); + } + + static get ignoreChiralFlag() { + const { ignoreChiralFlag } = this.getOptions(); + + return ignoreChiralFlag; + } + + static set ignoreChiralFlag(ignoreChiralFlag: boolean | undefined) { + const settings = this.getOptions(); + + this.saveSettings({ + ...settings, + ignoreChiralFlag, + }); + } +} diff --git a/packages/ketcher-react/src/script/ui/utils/settingsManager.ts b/packages/ketcher-react/src/script/ui/utils/settingsManager.ts index 7e9d165b80..832d96d2a5 100644 --- a/packages/ketcher-react/src/script/ui/utils/settingsManager.ts +++ b/packages/ketcher-react/src/script/ui/utils/settingsManager.ts @@ -15,6 +15,7 @@ ***************************************************************************/ import { KETCHER_SAVED_SETTINGS_KEY } from 'src/constants'; +import { storage } from '../storage-ext'; interface SavedSettings { selectionTool?: any; @@ -23,9 +24,7 @@ interface SavedSettings { export class SettingsManager { static getSettings(): SavedSettings { try { - return JSON.parse( - localStorage.getItem(KETCHER_SAVED_SETTINGS_KEY) || '{}', - ); + return JSON.parse(storage.getItem(KETCHER_SAVED_SETTINGS_KEY) || '{}'); } catch (e) { return {} as SavedSettings; } @@ -35,7 +34,7 @@ export class SettingsManager { if (!settings) { return; } - localStorage.setItem(KETCHER_SAVED_SETTINGS_KEY, JSON.stringify(settings)); + storage.setItem(KETCHER_SAVED_SETTINGS_KEY, JSON.stringify(settings)); } static get selectionTool() {