forked from enviPath/enviPy
157 lines
4.3 KiB
JavaScript
157 lines
4.3 KiB
JavaScript
/****************************************************************************
|
|
* Copyright 2017 EPAM Systems
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
***************************************************************************/
|
|
|
|
import { isEqual, debounce } from 'lodash/fp';
|
|
|
|
import molfile from '../../chem/molfile';
|
|
import keyNorm from '../keynorm';
|
|
import actions from '../action';
|
|
|
|
import * as clipArea from '../component/cliparea';
|
|
import * as structFormat from '../structformat';
|
|
import { onAction, openDialog, load } from './';
|
|
|
|
export function initKeydownListener(element) {
|
|
return function (dispatch, getState) {
|
|
const hotKeys = initHotKeys();
|
|
element.addEventListener('keydown', (event) => keyHandle(dispatch, getState, hotKeys, event));
|
|
}
|
|
}
|
|
|
|
/* HotKeys */
|
|
function keyHandle(dispatch, getState, hotKeys, event) {
|
|
const state = getState();
|
|
if (state.modal) return;
|
|
|
|
const editor = state.editor;
|
|
const actionState = state.actionState;
|
|
const actionTool = actionState.activeTool;
|
|
|
|
const key = keyNorm(event);
|
|
const atomsSelected = editor.selection() && editor.selection().atoms;
|
|
|
|
let group = null;
|
|
|
|
if (key && key.length === 1 && atomsSelected && key.match(/\w/)) {
|
|
console.assert(atomsSelected.length > 0);
|
|
openDialog(dispatch, 'labelEdit', { letter: key }).then(res => {
|
|
dispatch(onAction({ tool: 'atom', opts: res }));
|
|
});
|
|
event.preventDefault();
|
|
} else if (group = keyNorm.lookup(hotKeys, event)) {
|
|
let index = checkGroupOnTool(group, actionTool); // index currentTool in group || -1
|
|
index = (index + 1) % group.length;
|
|
|
|
let actName = group[index];
|
|
if (actionState[actName] && actionState[actName].disabled === true)
|
|
return event.preventDefault();
|
|
|
|
if (clipArea.actions.indexOf(actName) === -1) {
|
|
let newAction = actions[actName].action;
|
|
dispatch(onAction(newAction));
|
|
event.preventDefault();
|
|
} else if (window.clipboardData) // IE support
|
|
clipArea.exec(event);
|
|
}
|
|
}
|
|
|
|
function setHotKey(key, actName, hotKeys) {
|
|
if (Array.isArray(hotKeys[key]))
|
|
hotKeys[key].push(actName);
|
|
else
|
|
hotKeys[key] = [actName];
|
|
}
|
|
|
|
function initHotKeys() {
|
|
const hotKeys = {};
|
|
let act;
|
|
|
|
for (let actName in actions) {
|
|
act = actions[actName];
|
|
if (!act.shortcut) continue;
|
|
|
|
if (Array.isArray(act.shortcut))
|
|
act.shortcut.forEach(key => setHotKey(key, actName, hotKeys));
|
|
else
|
|
setHotKey(act.shortcut, actName, hotKeys);
|
|
}
|
|
|
|
return keyNorm(hotKeys);
|
|
}
|
|
|
|
function checkGroupOnTool(group, actionTool) {
|
|
let index = group.indexOf(actionTool.tool);
|
|
|
|
group.forEach((actName, i) => {
|
|
if (isEqual(actions[actName].action, actionTool))
|
|
index = i;
|
|
});
|
|
|
|
return index;
|
|
}
|
|
|
|
/* ClipArea */
|
|
export function initClipboard(dispatch, getState) {
|
|
const formats = Object.keys(structFormat.map).map(function (fmt) {
|
|
return structFormat.map[fmt].mime;
|
|
});
|
|
|
|
const debAction = debounce(0, (action) => dispatch( onAction(action) ));
|
|
const loadStruct = debounce(0, (structStr, opts) => dispatch( load(structStr, opts) ));
|
|
|
|
return {
|
|
formats: formats,
|
|
focused: function () {
|
|
return !getState().modal;
|
|
},
|
|
onCut: function () {
|
|
let data = clipData(getState().editor);
|
|
debAction({ tool: 'eraser', opts: 1 });
|
|
return data;
|
|
},
|
|
onCopy: function () {
|
|
let editor = getState().editor;
|
|
let data = clipData(editor);
|
|
editor.selection(null);
|
|
return data;
|
|
},
|
|
onPaste: function (data) {
|
|
const structStr = data['chemical/x-mdl-molfile'] ||
|
|
data['chemical/x-mdl-rxnfile'] ||
|
|
data['text/plain'];
|
|
|
|
if (structStr)
|
|
loadStruct(structStr, { fragment: true });
|
|
}
|
|
};
|
|
}
|
|
|
|
function clipData(editor) {
|
|
const res = {};
|
|
const struct = editor.structSelected();
|
|
|
|
if (struct.isBlank())
|
|
return null;
|
|
|
|
const type = struct.isReaction ?
|
|
'chemical/x-mdl-molfile' : 'chemical/x-mdl-rxnfile';
|
|
|
|
res['text/plain'] = res[type] = molfile.stringify(struct);
|
|
// res['chemical/x-daylight-smiles'] =
|
|
// smiles.stringify(struct);
|
|
return res;
|
|
}
|