/* * Copyright (c) 2014-2018, 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 tree.js * * @author <a href="http://vanessa.b3log.org">Liyuan Li</a> * @author <a href="http://88250.b3log.org">Liang Ding</a> * @version 1.0.1.1, Dec 15, 2015 */ var tree = { fileTree: undefined, // 递归获取当前节点展开中的最后一个节点 getCurrentNodeLastNode: function (node) { var returnNode = node.children[node.children.length - 1]; if (returnNode.open) { return tree.getCurrentNodeLastNode(returnNode); } else { return returnNode; } }, // 按照树展现获取下一个节点 getNextShowNode: function (node) { if (node.level !== 0) { if (node.getParentNode().getNextNode()) { return node.getParentNode().getNextNode(); } else { return tree.getNextShowNode(node.getParentNode()); } } else { return node.getNextNode(); } }, isBottomNode: function (node) { if (node.open) { return false; } if (node.getParentNode()) { if (node.getParentNode().isLastNode) { return tree.isBottomNode(node.getParentNode()); } else { return false; } } else { if (node.isLastNode) { return true; } else { return false; } } }, getTIdByPath: function (path) { var nodes = tree.fileTree.transformToArray(tree.fileTree.getNodes()); for (var i = 0, ii = nodes.length; i < ii; i++) { if (nodes[i].path === path) { return nodes[i].tId; } } return undefined; }, getOpenPaths: function () { var nodes = tree.fileTree.transformToArray(tree.fileTree.getNodes()), paths = []; for (var i = 0, ii = nodes.length; i < ii; i++) { if (nodes[i].open) { paths.push(nodes[i].path); } } return paths; }, getAllParents: function (node, parents) { if (!parents) { parents = []; } if (!node || !node.parentTId) { return parents; } else { parents.push(node.getParentNode()); return tree.getAllParents(node.getParentNode(), parents); } }, isParents: function (tId, parentPath) { var node = tree.fileTree.getNodeByTId(tId); if (!node || !node.parentTId) { return false; } else { var parentNode = tree.fileTree.getNodeByTId(node.parentTId); if (node.path === parentPath) { return true; } else { return tree.isParents(parentNode.tId, parentPath); } } }, isDir: function () { if (wide.curNode.iconSkin.indexOf("ico-ztree-dir") === 0) { return true; } return false; }, newFile: function (it) { if ($(it).hasClass("disabled")) { return false; } $("#dialogNewFilePrompt").dialog("open"); }, newDir: function (it) { if ($(it).hasClass("disabled")) { return false; } $("#dialogNewDirPrompt").dialog("open"); }, removeIt: function (it) { if (it) { if ($(it).hasClass("disabled")) { return false; } } else { if (!wide.curNode.removable) { return false; } } $("#dialogRemoveConfirm").dialog("open"); }, rename: function (it) { if (it) { if ($(it).hasClass("disabled")) { return false; } } $("#dialogRenamePrompt").dialog("open"); }, export: function () { var request = newWideRequest(), isSucc = false; request.path = wide.curNode.path; $.ajax({ async: false, type: 'POST', url: config.context + '/file/zip/new', data: JSON.stringify(request), dataType: "json", success: function (result) { if (!result.succ) { $("#dialogAlert").dialog("open", result.msg); return false; } isSucc = true; } }); if (isSucc) { window.open(config.context + '/file/zip?path=' + wide.curNode.path + ".zip"); } }, crossCompile: function (platform) { var request = newWideRequest(); request.path = wide.curNode.path; request.platform = platform; $.ajax({ async: false, type: 'POST', url: config.context + '/cross', data: JSON.stringify(request), dataType: "json", success: function (result) { if (!result.succ) { $("#dialogAlert").dialog("open", result.msg); return false; } } }); }, decompress: function () { var request = newWideRequest(); request.path = wide.curNode.path; $.ajax({ async: false, type: 'POST', url: config.context + '/file/decompress', data: JSON.stringify(request), dataType: "json", success: function (result) { if (!result.succ) { $("#dialogAlert").dialog("open", result.msg); return false; } var dir = wide.curNode.getParentNode(); tree.fileTree.reAsyncChildNodes(dir, "refresh"); } }); }, refresh: function (it) { if (it) { if ($(it).hasClass("disabled")) { return false; } } tree.fileTree.reAsyncChildNodes(wide.curNode, "refresh", true); }, gitClone: function (it) { if (it) { if ($(it).hasClass("disabled")) { return false; } } $("#dialogGitClonePrompt").dialog('open'); }, import: function () { var request = newWideRequest(); request.path = wide.curNode.path; $('#importFileupload').fileupload({ url: "/file/upload?path=" + request.path, dataType: 'json', formData: request, done: function (e, result) { tree.fileTree.reAsyncChildNodes(wide.curNode, "refresh"); }, fail: function () { console.log(arguments); } }); }, init: function () { $("#file").click(function () { $(this).focus(); }); var request = newWideRequest(); $.ajax({ type: 'POST', url: config.context + '/files', data: JSON.stringify(request), dataType: "json", success: function (result) { if (result.succ) { var $dirRMenu = $("#dirRMenu"); var $fileRMenu = $("#fileRMenu"); var setting = { data: { key: { title: "path" } }, view: { showTitle: true, selectedMulti: false }, async: { enable: true, url: config.context + "/file/refresh", autoParam: ["path"] }, callback: { onDblClick: function (event, treeId, treeNode) { if (treeNode) { tree.openFile(treeNode); } }, onRightClick: function (event, treeId, treeNode) { if (treeNode && !treeNode.isGOAPI) { menu.undisabled(['import', 'export', 'git-clone']); wide.curNode = treeNode; tree.fileTree.selectNode(treeNode); if (!tree.isDir()) { // if right click on a file if (wide.curNode.removable) { $fileRMenu.find(".remove").removeClass("disabled"); } else { $fileRMenu.find(".remove").addClass("disabled"); } if (-1 === wide.curNode.path.indexOf("zip", wide.curNode.path.length - "zip".length)) { // !path.endsWith("zip") $fileRMenu.find(".decompress").hide(); } else { $fileRMenu.find(".decompress").show(); } if (-1 === wide.curNode.path.indexOf("go", wide.curNode.path.length - "go".length)) { // !path.endsWith("go") $fileRMenu.find(".linux64").hide(); } else { $fileRMenu.find(".linux64").show(); } var top = event.clientY - 10; if ($fileRMenu.height() + top > $('.content').height()) { top = top - $fileRMenu.height() - 25; } $fileRMenu.css({ "top": top + "px", "left": event.clientX + "px", "display": "block" }).show(); $dirRMenu.hide(); menu.disabled(['import', 'git-clone']); } else { // 右击了目录 if (wide.curNode.removable) { $dirRMenu.find(".remove").removeClass("disabled"); } else { $dirRMenu.find(".remove").addClass("disabled"); } if (wide.curNode.creatable) { $dirRMenu.find(".create").removeClass("disabled"); } else { $dirRMenu.find(".create").addClass("disabled"); } var top = event.clientY - 10; if ($dirRMenu.height() + top > $('.content').height()) { top = top - $dirRMenu.height() - 25; } $dirRMenu.css({ "top": top + "px", "left": event.clientX + "px", "display": "block" }).show(); $fileRMenu.hide(); } $("#files").focus(); } }, onClick: function (event, treeId, treeNode, clickFlag) { if (treeNode) { wide.curNode = treeNode; tree.fileTree.selectNode(treeNode); menu.undisabled(['import', 'export', 'git-clone']); if (!tree.isDir()) { menu.disabled(['import', 'git-clone']); } $("#files").focus(); } } } }; tree.fileTree = $.fn.zTree.init($("#files"), setting, result.data.children); session.restore(); } } }); this._initSearch(); this._initRename(); }, openFile: function (treeNode, cursor) { wide.curNode = treeNode; var tempCursor = cursor; for (var i = 0, ii = editors.data.length; i < ii; i++) { // 该节点文件已经打开 if (editors.data[i].id === treeNode.path) { editors.tabs.setCurrent(treeNode.path); wide.curEditor = editors.data[i].editor; if (!tempCursor) { tempCursor = wide.curEditor.getCursor(); } $(".footer .cursor").text('| ' + (tempCursor.line + 1) + ':' + (tempCursor.ch + 1) + ' |'); wide.curEditor.setCursor(tempCursor); var half = Math.floor(wide.curEditor.getScrollInfo().clientHeight / wide.curEditor.defaultTextHeight() / 2); var cursorCoords = wide.curEditor.cursorCoords({line: tempCursor.line - half, ch: 0}, "local"); wide.curEditor.scrollTo(0, cursorCoords.top); wide.curEditor.focus(); wide.refreshOutline(); return false; } } if (!tree.isDir()) { var request = newWideRequest(); request.path = treeNode.path; $.ajax({ async: false, type: 'POST', url: config.context + '/file', data: JSON.stringify(request), dataType: "json", success: function (result) { if (!result.succ) { $("#dialogAlert").dialog("open", result.msg); return false; } var data = result.data; if (!data.mode) { var mode = CodeMirror.findModeByFileName(treeNode.path); if (mode) { data.mode = mode.mime; } else { data.mode = 'text/plain'; } } if (!data.mode) { console.error("Can't find mode by file name [" + treeNode.path + "]"); } if ("img" === data.mode) { // 是图片文件的话新建 tab 打开 // 最好是开 tab,但这个最终取决于浏览器设置 var w = window.open(config.context + data.path); return false; } if (!tempCursor) { tempCursor = CodeMirror.Pos(0, 0); } editors.newEditor(data, tempCursor); wide.refreshOutline(); } }); } }, _initSearch: function () { $("#dialogSearchForm > input:eq(0)").keyup(function (event) { var $okBtn = $(this).closest(".dialog-main").find(".dialog-footer > button:eq(0)"); if (event.which === 13 && !$okBtn.prop("disabled")) { $okBtn.click(); } if ($.trim($(this).val()) === "") { $okBtn.prop("disabled", true); } else { $okBtn.prop("disabled", false); } }); $("#dialogSearchForm > input:eq(1)").keyup(function (event) { var $okBtn = $(this).closest(".dialog-main").find(".dialog-footer > button:eq(0)"); if (event.which === 13 && !$okBtn.prop("disabled")) { $okBtn.click(); } }); $("#dialogSearchForm").dialog({ "modal": true, "height": 80, "width": 260, "title": config.label.search, "okText": config.label.search, "cancelText": config.label.cancel, "afterOpen": function () { $("#dialogSearchForm > input:eq(0)").val('').focus(); $("#dialogSearchForm > input:eq(1)").val(''); $("#dialogSearchForm").closest(".dialog-main").find(".dialog-footer > button:eq(0)").prop("disabled", true); }, "ok": function () { var request = newWideRequest(); if (!wide.curNode) { request.dir = ""; } else { request.dir = wide.curNode.path; } request.text = $("#dialogSearchForm > input:eq(0)").val(); request.extension = $("#dialogSearchForm > input:eq(1)").val(); $.ajax({ type: 'POST', url: config.context + '/file/search/text', data: JSON.stringify(request), dataType: "json", success: function (result) { if (!result.succ) { return; } $("#dialogSearchForm").dialog("close"); editors.appendSearch(result.data, 'founds', request.text); } }); } }); }, _initRename: function () { $("#dialogRenamePrompt").dialog({ "modal": true, "height": 52, "width": 260, "title": config.label.rename, "okText": config.label.rename, "cancelText": config.label.cancel, "afterOpen": function () { $("#dialogRenamePrompt").closest(".dialog-main").find(".dialog-footer > button:eq(0)").prop("disabled", true); $("#dialogRenamePrompt > input").val(wide.curNode.name).select().focus(); }, "ok": function () { var name = $("#dialogRenamePrompt > input").val(), request = newWideRequest(); request.oldPath = wide.curNode.path; request.newPath = wide.curNode.path.substring(0, wide.curNode.path.lastIndexOf("/") + 1) + name; $.ajax({ type: 'POST', url: config.context + '/file/rename', data: JSON.stringify(request), dataType: "json", success: function (result) { if (!result.succ) { $("#dialogRenamePrompt").dialog("close"); bottomGroup.tabs.setCurrent("notification"); windows.flowBottom(); $(".bottom-window-group .notification").focus(); return false; } $("#dialogRenamePrompt").dialog("close"); } }); } }); } };