/* * Copyright (c) 2014-2019, b3log.org & hacpai.com * * 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 * * https://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. */ /* * @file hotkeys.js * * @author Liyuan Li * @author Liang Ding * @version 1.0.0.2, Dec 15, 2015 */ var hotkeys = { defaultKeyMap: { // Ctrl-0 goEditor: { ctrlKey: true, altKey: false, shiftKey: false, which: 48, fun: function () { if (wide.curEditor) { wide.curEditor.focus(); } } }, // Ctrl-1 goFileTree: { ctrlKey: true, altKey: false, shiftKey: false, which: 49, fun: function () { // 有些元素需设置 tabindex 为 -1 时才可以 focus if (windows.outerLayout.west.state.isClosed) { windows.outerLayout.slideOpen('west'); } $("#files").focus(); } }, // Ctrl-2 goOutline: { ctrlKey: true, altKey: false, shiftKey: false, which: 50, fun: function () { if (windows.innerLayout.east.state.isClosed) { windows.innerLayout.slideOpen('east'); } $("#outline").focus(); } }, // Ctrl-4 goOutput: { ctrlKey: true, altKey: false, shiftKey: false, which: 52, fun: function () { bottomGroup.tabs.setCurrent("output"); windows.flowBottom(); $(".bottom-window-group .output").focus(); } }, // Ctrl-5 goSearch: { ctrlKey: true, altKey: false, shiftKey: false, which: 53, fun: function () { bottomGroup.tabs.setCurrent("search"); windows.flowBottom(); $(".bottom-window-group .search").focus(); } }, // Ctrl-6 goNotification: { ctrlKey: true, altKey: false, shiftKey: false, which: 54, fun: function () { bottomGroup.tabs.setCurrent("notification"); windows.flowBottom(); $(".bottom-window-group .notification").focus(); } }, // Alt-C clearWindow: { ctrlKey: false, altKey: true, shiftKey: false, which: 67 }, // Ctrl-D 窗口组切换 changeEditor: { ctrlKey: true, altKey: false, shiftKey: false, which: 68 }, // Ctrl-F search search: { ctrlKey: true, altKey: false, shiftKey: false, which: 70 }, // Ctrl-Q close current editor closeCurEditor: { ctrlKey: true, altKey: false, shiftKey: false, which: 81 }, // Ctrl-R rename: { ctrlKey: true, altKey: false, shiftKey: false, which: 82 }, // Shift-Alt-O 跳转到文件 goFile: { ctrlKey: false, altKey: true, shiftKey: true, which: 79 }, // F5 Build build: { ctrlKey: false, altKey: false, shiftKey: false, which: 116 }, // F6 Build & Run buildRun: { ctrlKey: false, altKey: false, shiftKey: false, which: 117 } }, bindList: function ($source, $list, enterFun) { $list.data("index", 0); $source.keydown(function (event) { var index = $list.data("index"), count = $list.find("li").length; if (count === 0) { return true; } if (event.which === 38) { // up index--; if (index < 0) { index = count - 1; } } if (event.which === 40) { // down index++; if (index > count - 1) { index = 0; } } var $selected = $list.find("li:eq(" + index + ")"); if (event.which === 13) { // enter enterFun($selected); } $list.find("li").removeClass("selected"); $list.data("index", index); $selected.addClass("selected"); if (index === 0) { $list.scrollTop(0); } else { if ($selected[0].offsetTop + $list.scrollTop() > $list.height()) { if (event.which === 40) { $list.scrollTop($list.scrollTop() + $selected.height()); } else { $list.scrollTop($selected[0].offsetTop); } } else { $list.scrollTop(0); } } // 阻止上下键改变光标位置 if (event.which === 38 || event.which === 40 || event.which === 13) { return false; } }); }, _bindOutput: function () { $(".bottom-window-group .output").keydown(function (event) { var hotKeys = hotkeys.defaultKeyMap; if (event.altKey === hotKeys.clearWindow.altKey && event.which === hotKeys.clearWindow.which) { // Alt-C clear output bottomGroup.clear('output'); event.preventDefault(); return; } }); }, _bindFileTree: function () { $("#files").keydown(function (event) { event.preventDefault(); var hotKeys = hotkeys.defaultKeyMap; if (event.ctrlKey === hotKeys.search.ctrlKey && event.which === hotKeys.search.which) { // Ctrl-F 搜索 $("#dialogSearchForm").dialog("open"); return; } if (event.ctrlKey === hotKeys.rename.ctrlKey && event.which === hotKeys.rename.which) { // Ctrl-R 重命名 if (wide.curNode.removable) { $("#dialogRenamePrompt").dialog("open"); } return; } switch (event.which) { case 46: // delete tree.removeIt(); break; case 13: // enter if (!wide.curNode) { return false; } if (tree.isDir()) { if (wide.curNode.open) { return false; } tree.fileTree.expandNode(wide.curNode, true, false, true); $("#files").focus(); break; } tree.openFile(wide.curNode); break; case 38: // up var node = {}; if (!wide.curNode) { // select the first one if no node been selected node = tree.fileTree.getNodeByTId("files_1"); } else { if (wide.curNode && wide.curNode.isFirstNode && wide.curNode.level === 0) { return false; } node = wide.curNode.getPreNode(); if (wide.curNode.isFirstNode && wide.curNode.getParentNode()) { node = wide.curNode.getParentNode(); } var preNode = wide.curNode.getPreNode(); if (preNode && tree.isDir() && preNode.open) { node = tree.getCurrentNodeLastNode(preNode); } } wide.curNode = node; tree.fileTree.selectNode(node); $("#files").focus(); break; case 40: // down var node = {}; if (!wide.curNode) { // select the first one if no node been selected node = tree.fileTree.getNodeByTId("files_1"); } else { if (wide.curNode && tree.isBottomNode(wide.curNode)) { return false; } node = wide.curNode.getNextNode(); if (tree.isDir() && wide.curNode.open) { node = wide.curNode.children[0]; } var nextShowNode = tree.getNextShowNode(wide.curNode); if (wide.curNode.isLastNode && wide.curNode.level !== 0 && !wide.curNode.open && nextShowNode) { node = nextShowNode; } } if (node) { wide.curNode = node; tree.fileTree.selectNode(node); } $("#files").focus(); break; case 37: // left if (!wide.curNode) { wide.curNode = tree.fileTree.getNodeByTId("files_1"); tree.fileTree.selectNode(wide.curNode); $("#files").focus(); return false; } if (!tree.isDir() || !wide.curNode.open) { return false; } tree.fileTree.expandNode(wide.curNode, false, false, true); $("#files").focus(); break; case 39: // right if (!wide.curNode) { wide.curNode = tree.fileTree.getNodeByTId("files_1"); tree.fileTree.selectNode(wide.curNode); $("#files").focus(); return false; } if (!tree.isDir() || wide.curNode.open) { return false; } tree.fileTree.expandNode(wide.curNode, true, false, true); $("#files").focus(); break; case 116: // F5 if (!wide.curNode || !tree.isDir()) { return false; } tree.refresh(wide.curNode); break; } }); }, _bindDocument: function () { var hotKeys = this.defaultKeyMap; $(document).keydown(function (event) { if (event.ctrlKey === hotKeys.goEditor.ctrlKey && event.which === hotKeys.goEditor.which) { // Ctrl-0 焦点切换到当前编辑器 hotKeys.goEditor.fun(); event.preventDefault(); return; } if (event.ctrlKey === hotKeys.goFileTree.ctrlKey && event.which === hotKeys.goFileTree.which) { // Ctrl-1 焦点切换到文件树 hotKeys.goFileTree.fun(); event.preventDefault(); return; } if (event.ctrlKey === hotKeys.goOutline.ctrlKey && event.which === hotKeys.goOutline.which) { // Ctrl-2 焦点切换到大纲 hotKeys.goOutline.fun(); event.preventDefault(); return; } if (event.ctrlKey === hotKeys.goOutput.ctrlKey && event.which === hotKeys.goOutput.which) { // Ctrl-4 焦点切换到输出窗口 hotKeys.goOutput.fun(); event.preventDefault(); return; } if (event.ctrlKey === hotKeys.goSearch.ctrlKey && event.which === hotKeys.goSearch.which) { // Ctrl-5 焦点切换到搜索窗口 hotKeys.goSearch.fun(); event.preventDefault(); return; } if (event.ctrlKey === hotKeys.goNotification.ctrlKey && event.which === hotKeys.goNotification.which) { // Ctrl-6 焦点切换到通知窗口 hotKeys.goNotification.fun(); event.preventDefault(); return; } if (event.ctrlKey === hotKeys.closeCurEditor.ctrlKey && event.which === hotKeys.closeCurEditor.which) { // Ctrl-Q 关闭当前编辑器 $(".edit-panel .tabs > div.current").find(".ico-close").click(); event.preventDefault(); return; } if (event.ctrlKey === hotKeys.changeEditor.ctrlKey && event.which === hotKeys.changeEditor.which) { // Ctrl-D 窗口组切换 if (document.activeElement.className === "notification" || document.activeElement.className === "output" || document.activeElement.className === "search") { // 焦点在底部窗口组时,对底部进行切换 var tabs = ["output", "search", "notification"], nextPath = ""; for (var i = 0, ii = tabs.length; i < ii; i++) { if (bottomGroup.tabs.getCurrentId() === tabs[i]) { if (i < ii - 1) { nextPath = tabs[i + 1]; } else { nextPath = tabs[0]; } break; } } bottomGroup.tabs.setCurrent(nextPath); $(".bottom-window-group ." + nextPath).focus(); event.preventDefault(); return false; } if (editors.data.length > 1) { var nextPath = ""; for (var i = 0, ii = editors.data.length; i < ii; i++) { var currentId = editors.getCurrentId(); if (currentId) { if (currentId === editors.data[i].id) { if (i < ii - 1) { nextPath = editors.data[i + 1].id; wide.curEditor = editors.data[i + 1].editor; } else { nextPath = editors.data[0].id; wide.curEditor = editors.data[0].editor; } break; } } } editors.tabs.setCurrent(nextPath); var nextTId = tree.getTIdByPath(nextPath); wide.curNode = tree.fileTree.getNodeByTId(nextTId); tree.fileTree.selectNode(wide.curNode); wide.refreshOutline(); var cursor = wide.curEditor.getCursor(); $(".footer .cursor").text('| ' + (cursor.line + 1) + ':' + (cursor.ch + 1) + ' |'); wide.curEditor.focus(); } event.preventDefault(); return false; } if (event.which === hotKeys.build.which) { // F5 Build menu.build(); event.preventDefault(); return; } if (event.which === hotKeys.buildRun.which) { // F6 Build & Run menu.run(); event.preventDefault(); return; } if (event.ctrlKey === hotKeys.goFile.ctrlKey && event.altKey === hotKeys.goFile.altKey && event.shiftKey === hotKeys.goFile.shiftKey && event.which === hotKeys.goFile.which) { // Shift-Alt-O 跳转到文件 $("#dialogGoFilePrompt").dialog("open"); } }); }, init: function () { this._bindFileTree(); this._bindOutput(); this._bindDocument(); } };