forked from enviPath/enviPy
Current Dev State
This commit is contained in:
156
static/js/ketcher2/script/ui/state/hotkeys.js
Normal file
156
static/js/ketcher2/script/ui/state/hotkeys.js
Normal file
@ -0,0 +1,156 @@
|
||||
/****************************************************************************
|
||||
* 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;
|
||||
}
|
||||
Reference in New Issue
Block a user