in packages/ketcher-react/src/script/ui/state/editor/index.js [42:250]
export default function initEditor(dispatch, getState) {
const updateAction = debounce(100, () => dispatch({ type: 'UPDATE' }));
const sleep = (time) => new Promise((resolve) => setTimeout(resolve, time));
const resetToSelect =
(force = false) =>
(dispatch) => {
// eslint-disable-line no-shadow
const state = global.currentState;
const activeTool = state.actionState.activeTool.tool;
if (activeTool === 'select' && !force) return;
const selectMode = state.toolbar.visibleTools.select;
const resetOption = state.options.settings.resetToSelect;
if (resetOption === true || resetOption === activeTool || force === true)
// example: 'paste'
dispatch({ type: 'ACTION', action: acts[selectMode].action });
else updateAction();
};
return {
onInit: (editor) => {
dispatch({ type: 'INIT', editor });
},
onChange: (action) => {
if (action === undefined) sleep(0).then(() => dispatch(resetToSelect()));
// Editor switched to view only mode
if (action === 'force') dispatch(resetToSelect(true));
// new tool in reducer
else dispatch(resetToSelect());
},
onSelectionChange: () => {
updateAction();
},
onElementEdit: (selem) => {
if (isAtomsArray(selem)) {
const atomAttributes = generateCommonProperties(
selem,
fromAtom(selem[0]),
);
return openDialog(dispatch, 'atomProps', {
...atomAttributes,
isMultipleAtoms: true,
}).then(toElement);
}
const elem = selem.type === 'text' ? selem : fromElement(selem);
let dlg = null;
if (elem.type === 'text') {
// TODO: move textdialog opening logic to another place
return openDialog(dispatch, 'text', elem);
} else if (Elements.get(elem.label)) {
dlg = openDialog(dispatch, 'atomProps', elem);
} else if (Object.keys(elem).length === 1 && 'ap' in elem) {
dlg = openDialog(dispatch, 'attachmentPoints', elem.ap).then((res) => ({
ap: res,
}));
} else if (elem.type === 'list' || elem.type === 'not-list') {
dlg = openDialog(
dispatch,
!elem.pseudo ? 'period-table' : 'extended-table',
{ ...elem, pseudo: elem.pseudo },
);
} else if (elem.type === 'rlabel') {
const rgroups = getState().editor.struct().rgroups;
const params = {
type: 'atom',
values: elem.values,
disabledIds: Array.from(rgroups.entries()).reduce(
(acc, [rgid, rg]) => {
if (rg.frags.has(elem.fragId)) acc.push(rgid);
return acc;
},
[],
),
};
dlg = openDialog(dispatch, 'rgroup', params).then((res) => ({
values: res.values,
type: 'rlabel',
}));
} else {
dlg = openDialog(
dispatch,
!elem.pseudo ? 'period-table' : 'extended-table',
{ ...elem, pseudo: elem.pseudo },
);
}
return dlg.then(toElement);
},
// TODO: correct
onEnhancedStereoEdit: ({ ...init }) =>
sleep(0).then(() => {
init = fromStereoLabel(init.stereoLabel);
return openDialog(dispatch, 'enhancedStereo', {
init,
}).then(
(res) => toStereoLabel(res),
() => null,
);
}),
onQuickEdit: (atom) => openDialog(dispatch, 'labelEdit', atom),
onBondEdit: (bonds) => {
const bondsAttributes = generateCommonProperties(bonds, bonds[0]);
return openDialog(dispatch, 'bondProps', fromBond(bondsAttributes)).then(
toBond,
);
},
onRgroupEdit: (rgroup) => {
const struct = getState().editor.struct();
if (Object.keys(rgroup).length > 2) {
const rgroupLabels = Array.from(struct.rgroups.keys());
if (!rgroup.range) rgroup.range = '>0';
return openDialog(
dispatch,
'rgroupLogic',
Object.assign({ rgroupLabels }, rgroup),
);
}
const disabledIds = Array.from(struct.atoms.values()).reduce(
(acc, atom) => {
if (atom.fragment === rgroup.fragId && atom.rglabel !== null)
return acc.concat(fromElement(atom).values);
return acc;
},
[],
);
const params = {
type: 'fragment',
values: [rgroup.label],
disabledIds,
};
return openDialog(dispatch, 'rgroup', params).then((res) => ({
label: res.values[0],
}));
},
onSgroupEdit: (sgroup) =>
sleep(0) // huck to open dialog after dispatch sgroup tool action
.then(() => openDialog(dispatch, 'sgroup', fromSgroup(sgroup)))
.then(toSgroup),
onRemoveFG: (result) =>
sleep(0).then(() => openDialog(dispatch, 'removeFG', result)),
onMessage: (msg) => {
if (msg.error) {
// TODO: add error handler call
}
},
onAromatizeStruct: (struct) => {
const state = getState();
const serverOpts = state.options.getServerSettings();
return serverCall(
state.editor,
state.server,
'aromatize',
serverOpts,
struct,
).catch((e) => {
KetcherLogger.error('index.js::initEditor::onAromatizeStruct', e);
state.editor.errorHandler(e);
});
},
onDearomatizeStruct: (struct) => {
const state = getState();
const serverOpts = state.options.getServerSettings();
return serverCall(
state.editor,
state.server,
'dearomatize',
serverOpts,
struct,
).catch((e) => {
KetcherLogger.error('index.js::initEditor::onDearomatizeStruct', e);
state.editor.errorHandler(e);
});
},
onMouseDown: () => {
updateAction();
},
onConfirm: () => openDialog(dispatch, 'confirm'),
onShowInfo: (payload) => {
if (payload) {
const { groupStruct, event, sGroup } = payload;
highlightFG(dispatch, { groupStruct, event, sGroup });
} else {
highlightFG(dispatch, { groupStruct: null, sGroup: null });
}
},
onApiSettings: (payload) => dispatch(saveSettings(payload)),
onUpdateFloatingTools: memoizedDebounce(
/**
* @param {import('src/script/editor/Editor').FloatingToolsParams} payload
*/
(payload) => {
dispatch(updateFloatingTools(payload));
},
),
onZoomIn: updateAction,
onZoomOut: updateAction,
onShowMacromoleculesErrorMessage: (payload) =>
dispatch(openInfoModalWithCustomMessage(payload)),
};
}