diff --git a/static/js/editor.js b/static/js/editor.js index 2c1af85..216d05d 100644 --- a/static/js/editor.js +++ b/static/js/editor.js @@ -266,6 +266,12 @@ var editors = { "Ctrl-E": "deleteLine", "Ctrl-D": "doNothing", // 取消默认的 deleteLine "Ctrl-B": "jumpToDecl", + "Ctrl-S": function () { + wide.saveFile(); + }, + "Alt-Shift-F": function () { + wide.fmt(); + }, "Alt-F7": "findUsages" } }); diff --git a/static/js/hotkeys.js b/static/js/hotkeys.js new file mode 100644 index 0000000..cc27fa2 --- /dev/null +++ b/static/js/hotkeys.js @@ -0,0 +1,165 @@ +var hotkeys = { + defaultKeyMap: { + // Ctrl+1 焦点切换到文件树 + goFileTree: { + ctrlKey: true, + altKey: false, + shiftKey: false, + which: 49 + }, + // Ctrl+4 焦点切换到输出窗口 + goOutPut: { + ctrlKey: true, + altKey: false, + shiftKey: false, + which: 52 + }, + // F6 构建并运行 + buildRun: { + ctrlKey: false, + altKey: false, + shiftKey: false, + which: 117 + } + }, + _bindFileTree: function() { + // TODO: 滚动处理 + $("#files").keydown(function(event) { + switch (event.which) { + case 13: // 回车 + if (!wide.curNode) { + return false; + } + + if (wide.curNode.iconSkin === "ico-ztree-dir ") { // 选中节点是目录 + // 不做任何处理 + return false; + } + + // 模拟点击:打开文件 + tree._onClick(wide.curNode); + + break; + case 38: // 上 + var node = {}; + + if (!wide.curNode) { // 没有选中节点时,默认选中第一个 + 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 && preNode.iconSkin === "ico-ztree-dir " + && preNode.open) { + // 当前节点的上一个节点是目录且打开时 + node = preNode.children[preNode.children.length - 1]; + } + } + + wide.curNode = node; + tree.fileTree.selectNode(node); + $("#files").focus(); + break; + case 40: // 下 + var node = {}; + + if (!wide.curNode) { // 没有选中节点时,默认选中第一个 + node = tree.fileTree.getNodeByTId("files_1"); + } else { + if (wide.curNode && wide.curNode.isLastNode && !wide.curNode.open + && wide.curNode.getParentNode().isLastNode) { + // 当前节点为最底部的节点 + return false; + } + + node = wide.curNode.getNextNode(); + if (wide.curNode.iconSkin === "ico-ztree-dir " && wide.curNode.open) { + // 当前节点是目录且打开时 + node = wide.curNode.children[0]; + } + + if (wide.curNode.isLastNode && wide.curNode.level !== 0 + && wide.curNode.getParentNode().getNextNode()) { + // 当前节点为最后一个节点,但其父节点还有下一个节点 + node = wide.curNode.getParentNode().getNextNode(); + } + } + + wide.curNode = node; + tree.fileTree.selectNode(node); + $("#files").focus(); + break; + case 37: // 左 + if (!wide.curNode) { + wide.curNode = tree.fileTree.getNodeByTId("files_1"); + tree.fileTree.selectNode(wide.curNode); + $("#files").focus(); + return false; + } + + if (wide.curNode.iconSkin !== "ico-ztree-dir " || !wide.curNode.open) { + return false; + } + + tree.fileTree.expandNode(wide.curNode, false, false, true); + $("#files").focus(); + break; + case 39: // 右 + if (!wide.curNode) { + wide.curNode = tree.fileTree.getNodeByTId("files_1"); + tree.fileTree.selectNode(wide.curNode); + $("#files").focus(); + return false; + } + + if (wide.curNode.iconSkin !== "ico-ztree-dir " || wide.curNode.open) { + return false; + } + + tree.fileTree.expandNode(wide.curNode, true, false, true); + $("#files").focus(); + + break; + } + }); + }, + init: function() { + this._bindFileTree(); + + var hotKeys = this.defaultKeyMap; + $(document).keydown(function(event) { + if (event.ctrlKey === hotKeys.goFileTree.ctrlKey + && event.which === hotKeys.goFileTree.which) { // Ctrl+1 焦点切换到文件树 + // 有些元素需设置 tabindex 为 -1 时才可以 focus + $("#files").focus(); + event.preventDefault(); + + return; + } + + if (event.ctrlKey === hotKeys.goOutPut.ctrlKey + && event.which === hotKeys.goOutPut.which) { // Ctrl+4 焦点切换到输出窗口 + $("#output").focus(); + event.preventDefault(); + + return; + } + + if (event.which === hotKeys.buildRun.which) { // F6 构建并运行 + wide.run(); + event.preventDefault(); + + return; + } + }); + } +}; \ No newline at end of file diff --git a/static/js/wide.js b/static/js/wide.js index e2feff3..2359e83 100644 --- a/static/js/wide.js +++ b/static/js/wide.js @@ -1,9 +1,9 @@ var outputWS = new WebSocket(config.channel.output + '/output/ws'); -outputWS.onopen = function () { +outputWS.onopen = function() { console.log('[output onopen] connected'); }; -outputWS.onmessage = function (e) { +outputWS.onmessage = function(e) { console.log('[output onmessage]' + e.data); var data = JSON.parse(e.data); @@ -43,37 +43,37 @@ outputWS.onmessage = function (e) { url: '/run', data: JSON.stringify(request), dataType: "json", - beforeSend: function (data) { + beforeSend: function(data) { $('#output').text(''); }, - success: function (data) { + success: function(data) { } }); } } }; -outputWS.onclose = function (e) { +outputWS.onclose = function(e) { console.log('[output onclose] disconnected (' + e.code + ')'); delete outputWS; }; -outputWS.onerror = function (e) { +outputWS.onerror = function(e) { console.log('[output onerror] ' + e); }; var wide = { curNode: undefined, curEditor: undefined, - _initLayout: function () { + _initLayout: function() { var mainH = $(window).height() - $(".menu").height() - $(".footer").height() - 2; $(".content, .ztree").height(mainH); $(".edit-panel").height(mainH - $(".output").height()); }, - init: function () { + init: function() { this._initLayout(); - $("body").bind("mousedown", function (event) { + $("body").bind("mousedown", function(event) { if (!(event.target.id === "dirRMenu" || $(event.target).closest("#dirRMenu").length > 0)) { $("#dirRMenu").hide(); } @@ -89,9 +89,8 @@ var wide = { } }); - this._bindKey(); }, - saveFile: function () { + saveFile: function() { var request = { file: $(".edit-header .current span:eq(0)").attr("title"), code: wide.curEditor.getValue() @@ -101,23 +100,23 @@ var wide = { url: '/file/save', data: JSON.stringify(request), dataType: "json", - success: function (data) { + success: function(data) { } }); }, - saveAllFiles: function () { + saveAllFiles: function() { // TODO: save all files }, - closeFile: function () { + closeFile: function() { // TODO: close file }, - closeAllFiles: function () { + closeAllFiles: function() { // TODO: close all files }, - exit: function () { + exit: function() { // TODO: exit }, - run: function () { + run: function() { var request = { file: $(".edit-header .current span:eq(0)").attr("title"), code: wide.curEditor.getValue() @@ -128,14 +127,14 @@ var wide = { url: '/build', data: JSON.stringify(request), dataType: "json", - beforeSend: function (data) { + beforeSend: function(data) { $('#output').text(''); }, - success: function (data) { + success: function(data) { } }); }, - goget: function () { + goget: function() { var request = { file: $(".edit-header .current span:eq(0)").attr("title") }; @@ -145,14 +144,14 @@ var wide = { url: '/go/get', data: JSON.stringify(request), dataType: "json", - beforeSend: function (data) { + beforeSend: function(data) { $('#output').text(''); }, - success: function (data) { + success: function(data) { } }); }, - goinstall: function () { + goinstall: function() { var request = { file: $(".edit-header .current span:eq(0)").attr("title"), code: wide.curEditor.getValue() @@ -163,14 +162,14 @@ var wide = { url: '/go/install', data: JSON.stringify(request), dataType: "json", - beforeSend: function (data) { + beforeSend: function(data) { $('#output').text(''); }, - success: function (data) { + success: function(data) { } }); }, - fmt: function () { + fmt: function() { var path = $(".edit-header .current span:eq(0)").attr("title"); var mode = wide.curNode.mode; @@ -188,7 +187,7 @@ var wide = { url: '/go/fmt', data: JSON.stringify(request), dataType: "json", - success: function (data) { + success: function(data) { if (data.succ) { wide.curEditor.setValue(data.code); } @@ -202,7 +201,7 @@ var wide = { url: '/html/fmt', data: JSON.stringify(request), dataType: "json", - success: function (data) { + success: function(data) { if (data.succ) { wide.curEditor.setValue(data.code); } @@ -226,92 +225,12 @@ var wide = { // TODO: XML/JSON 格式化处理 break; } - }, - _bindKey: function () { - $("#files").keydown(function (event) { - switch (event.which) { - case 13: // 回车 - if (!wide.curNode) { - return false; - } - - if (wide.curNode.iconSkin === "ico-ztree-dir ") { // 选中节点是目录 - // 不做任何处理 - return false; - } - - // 模拟点击:打开文件 - tree._onClick(wide.curNode); - - break; - case 38: // 上 - if (!wide.curNode) { - return false; - } - - tree.fileTree.selectNode(wide.curNode.getPreNode()); - wide.curNode = wide.curNode.getPreNode(); - $("#files").focus(); - break; - case 40: // 下 - if (!wide.curNode) { - return false; - } - - // TODO: 处理滚动条,递归获取下一个 - tree.fileTree.selectNode(wide.curNode.getNextNode()); - wide.curNode = wide.curNode.getNextNode(); - $("#files").focus(); - break; - } - }); - - $(document).keydown(function (event) { - if (event.ctrlKey && event.which === 49) { // Ctrl+1 焦点切换到文件树 - // 有些元素需设置 tabindex 为 -1 时才可以 focus - $("#files").focus(); - event.preventDefault(); - - return; - } - - if (event.ctrlKey && event.which === 52) { // Ctrl+4 焦点切换到输出窗口 - $("#output").focus(); - event.preventDefault(); - - return; - } - - if (event.ctrlKey && event.which === 83) { // Ctrl+S 保存当前编辑器文件 - wide.saveFile(); - event.preventDefault(); - - return; - } - - if (event.altKey && event.shiftKey && event.which === 70) { // Alt+Shift+F 格式化当前编辑器文件 - if (!wide.curNode) { - return false; - } - - wide.fmt(); - event.preventDefault(); - - return; - } - - if (event.which === 117) { // F6 构建并运行 - wide.run(); - event.preventDefault(); - - return; - } - }); } }; -$(document).ready(function () { +$(document).ready(function() { wide.init(); tree.init(); menu.init(); + hotkeys.init(); }); \ No newline at end of file diff --git a/view/index.html b/view/index.html index 48f4677..709b09f 100644 --- a/view/index.html +++ b/view/index.html @@ -199,5 +199,6 @@ +