Files
mixly3-server/mixly/common/modules/mixly-modules/common/file-tree.js
2026-01-24 16:12:04 +08:00

998 lines
32 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
goog.loadJs('common', () => {
goog.require('XScrollbar');
goog.require('path');
goog.require('$.jstree');
goog.require('Mixly.Env');
goog.require('Mixly.Msg');
goog.require('Mixly.Config');
goog.require('Mixly.Events');
goog.require('Mixly.Menu');
goog.require('Mixly.ContextMenu');
goog.require('Mixly.Registry');
goog.require('Mixly.IdGenerator');
goog.require('Mixly.Debug');
goog.require('Mixly.Component');
goog.require('Mixly.HTMLTemplate');
goog.provide('Mixly.FileTree');
const {
Env,
Msg,
Config,
Menu,
Events,
ContextMenu,
Registry,
IdGenerator,
Debug,
Component,
HTMLTemplate
} = Mixly;
const { USER } = Config;
class FileTree extends Component {
static {
this.FILE_ICON_MAP = goog.readJsonSync(path.join(Env.templatePath, 'json/file-icons.json'));
this.FOLDER_ICON_MAP = goog.readJsonSync(path.join(Env.templatePath, 'json/folder-icons.json'));
HTMLTemplate.add(
'html/file-tree.html',
new HTMLTemplate(goog.readFileSync(path.join(Env.templatePath, 'html/file-tree.html')))
);
}
#$openFolderContent_ = null;
#$folderContent_ = null;
#$rootFolder_ = null;
#$iconTriangle_ = null;
#$iconFolder_ = null;
#$name_ = null;
#$children_ = null;
#$progress_ = null;
#$mask_ = null;
#$fileTree_ = null;
#mprogress_ = null;
#rootFolderOpened_ = false;
#rootPath_ = '';
#rootName_ = '';
#rootTitle_ = '';
#fs_ = null;
#contextMenu_ = null;
#selected_ = null;
#jstree_ = null;
#scrollbar_ = null;
constructor(fs) {
super();
const $content = $(HTMLTemplate.get('html/file-tree.html').render());
this.setContent($content);
this.#$rootFolder_ = $content.find('.folder-title');
this.#$iconTriangle_ = this.#$rootFolder_.find('.triangle');
this.#$iconFolder_ = this.#$rootFolder_.find('.folder');
this.#$name_ = this.#$rootFolder_.find('.name');
this.#$children_ = $content.find('.children');
this.#$progress_ = $content.children('.progress');
this.#$mask_ = $content.children('.mask');
this.#fs_ = fs;
this.#rootPath_ = '';
this.#scrollbar_ = new XScrollbar(this.#$children_[0], {
onlyHorizontal: false,
thumbSize: '4px',
thumbRadius: '1px',
thumbBackground: USER.theme === 'dark'? '#b0b0b0' : '#5f5f5f'
});
this.#$fileTree_ = $(this.#scrollbar_.$content);
this.#$fileTree_.jstree({
core: {
strings: {
'Loading ...': Msg.Lang['fileTree.loading'] + '...'
},
multiple: false,
animation: false,
worker: false,
dblclick_toggle: false,
check_callback: function(operation, node, parent, position, more) {
if(operation === 'copy_node' || operation === 'move_node') {
if(parent.id === '#') {
return false;
}
}
return true;
},
data: (node, cb) => {
if (!this.#rootPath_) {
cb([]);
return;
}
this.showProgress();
let folderPath = this.#rootPath_;
if(node.id !== '#') {
let $li = this.#jstree_.get_node(node, true);
let $i = $li.find('.jstree-anchor > .jstree-icon');
$i.addClass('layui-anim layui-anim-fadein layui-anim-fadeout layui-anim-loop');
folderPath = node.id;
}
this.#getChildren_(folderPath)
.then((data) => {
cb(data);
})
.catch(Debug.error)
.finally(() => this.hideProgress());
},
themes: {
dots: true,
name: USER.theme === 'light'? 'default' : 'default-dark',
responsive: false,
ellipsis: true
}
},
plugins: ['wholerow', 'unique']
});
this.#jstree_ = this.#$fileTree_.jstree(true);
this.addEventsType([
'beforeSelectLeaf', 'afterSelectLeaf', 'afterOpenNode', 'afterCloseNode', 'afterRefreshNode',
'afterCreateNode', 'afterDeleteNode', 'afterRenameNode'
]);
this.#addEventsListener_();
this.#addContextMenu_();
this.nodeAliveRegistry = new Registry();
this.delayRefreshRegistry = new Registry();
this.watchRegistry = new Registry();
}
#addEventsListener_() {
this.#$fileTree_
.on('click.jstree', '.jstree-open>a', ({ target }) => {
setTimeout(() => {
$(target).parent().removeClass('jstree-leaf').addClass('jstree-opened');
this.#jstree_.close_node(target);
});
})
.on('click.jstree', '.jstree-closed>a', ({ target }) => {
setTimeout(() => {
$(target).parent().removeClass('jstree-leaf').addClass('jstree-closed');
this.#jstree_.open_node(target);
});
})
.on('open_node.jstree', (e, data) => {
const { id } = data.node;
let elem = document.getElementById(id);
let $i = $(elem).children('.jstree-anchor').children('.jstree-icon');
$i.addClass('opened');
})
.on('close_node.jstree', (e, data) => {
const { id } = data.node;
let elem = document.getElementById(id);
let $i = $(elem).children('.jstree-anchor').children('.jstree-icon');
$i.removeClass('opened');
})
.on('after_open.jstree', (e, data) => {
const { id } = data.node;
const eventId = this.nodeAliveRegistry.getItem(id);
if (eventId) {
clearTimeout(eventId);
this.nodeAliveRegistry.unregister(id);
} else {
this.watchFolder(id);
}
this.runEvent('afterOpenNode', data);
this.reselect();
})
.on('after_close.jstree', (e, data) => {
const { id } = data.node;
const eventId = setTimeout(() => {
this.unwatchFolder(id);
}, 60 * 1000);
if (!this.nodeAliveRegistry.getItem(id)) {
this.nodeAliveRegistry.register(id, eventId);
}
this.runEvent('afterCloseNode', data);
this.reselect();
})
.on('changed.jstree', (e, data) => {
const selected = data.instance.get_selected(true);
if (!selected.length) {
// this.#selected_ = null;
return;
}
if ((selected[0].icon || '').indexOf('foldericon') !== -1) {
this.reselect();
return;
}
if (selected[0].id === this.#selected_) {
return;
}
const result = this.runEvent('beforeSelectLeaf', selected);
if ((result.length && result[0]) || !result.length) {
this.#selected_ = selected[0].id;
this.runEvent('afterSelectLeaf', selected);
} else {
this.deselect(selected[0].id);
this.reselect();
}
})
.on('refresh.jstree', (e, data) => {
this.runEvent('afterRefreshNode', data.node);
})
.on('refresh_node.jstree', (e, data) => {
this.runEvent('afterRefreshNode', data.node);
});
this.#$rootFolder_.click(() => {
if (this.isRootFolderOpened()) {
this.closeRootFolder();
} else {
this.openRootFolder();
this.reselect();
}
});
}
#addContextMenu_() {
const selector = `div[page-id="${this.getId()}"] .jstree-node, div[page-id="${this.getId()}"] > button`;
this.#contextMenu_ = new ContextMenu(selector, {
zIndex: 300,
events: {
hide: ({ $trigger }) => {
$trigger.removeClass('active');
},
activated: ({ $trigger }) => {
$trigger.addClass('active');
}
}
});
this.#addFileContextMenuItems_();
this.#contextMenu_.bind('getMenu', () => 'menu');
}
#addFileContextMenuItems_() {
let menu = new Menu();
menu.add({
weight: 0,
id: 'new_folder',
preconditionFn: ($trigger) => {
const type = $trigger.attr('type');
return ['root', 'folder'].includes(type);
},
data: {
isHtmlName: true,
name: Menu.getItem(Msg.Lang['fileTree.newFolder'], ''),
callback: (_, { $trigger }) => {
const type = $trigger.attr('type');
if (type === 'root') {
this.openRootFolder();
this.createRootChildFolderNode();
} else {
const id = $trigger.attr('id');
this.createFolderNode(id);
}
}
}
});
menu.add({
weight: 1,
id: 'new_file',
preconditionFn: ($trigger) => {
const type = $trigger.attr('type');
return ['root', 'folder'].includes(type);
},
data: {
isHtmlName: true,
name: Menu.getItem(Msg.Lang['fileTree.newFile'], ''),
callback: (_, { $trigger }) => {
const type = $trigger.attr('type');
if (type === 'root') {
this.openRootFolder();
this.createRootChildFileNode();
} else {
const id = $trigger.attr('id');
this.createFileNode(id);
}
}
}
});
menu.add({
weight: 2,
id: 'sep1',
preconditionFn: ($trigger) => {
const type = $trigger.attr('type');
return ['root', 'folder'].includes(type);
},
data: '---------'
});
menu.add({
weight: 3,
id: 'cut',
preconditionFn: ($trigger) => {
const type = $trigger.attr('type');
return ['file', 'folder'].includes(type);
},
data: {
isHtmlName: true,
name: Menu.getItem(Msg.Lang['editor.contextMenu.cut'], ''),
callback: (_, { $trigger }) => {
const id = $trigger.attr('id');
this.cutNode(id);
}
}
});
menu.add({
weight: 4,
id: 'copy',
preconditionFn: ($trigger) => {
const type = $trigger.attr('type');
return ['file', 'folder'].includes(type);
},
data: {
isHtmlName: true,
name: Menu.getItem(Msg.Lang['editor.contextMenu.copy'], ''),
callback: (_, { $trigger }) => {
const id = $trigger.attr('id');
this.copyNode(id);
}
}
});
menu.add({
weight: 5,
id: 'paste',
preconditionFn: ($trigger) => {
const type = $trigger.attr('type');
return ['root', 'folder'].includes(type);
},
data: {
isHtmlName: true,
name: Menu.getItem(Msg.Lang['editor.contextMenu.paste'], ''),
callback: (_, { $trigger }) => {
const type = $trigger.attr('type');
if (type === 'root') {
this.openRootFolder();
this.pasteNode('/');
} else {
const id = $trigger.attr('id');
this.pasteNode(id);
}
}
}
});
menu.add({
weight: 6,
id: 'sep2',
data: '---------'
});
menu.add({
weight: 7,
id: 'copy_path',
data: {
isHtmlName: true,
name: Menu.getItem(Msg.Lang['fileTree.copyPath'], ''),
callback: (_, { $trigger }) => {
let outPath = null;
const type = $trigger.attr('type');
if (type === 'root') {
outPath = this.#rootPath_;
} else {
outPath = $trigger.attr('id');
}
navigator.clipboard.writeText(outPath)
.catch(Debug.error);
}
}
});
menu.add({
weight: 8,
id: 'rename',
preconditionFn: ($trigger) => {
const type = $trigger.attr('type');
return ['file', 'folder'].includes(type);
},
data: {
isHtmlName: true,
name: Menu.getItem(Msg.Lang['fileTree.rename'], ''),
callback: (_, { $trigger }) => {
const type = $trigger.attr('type');
const id = $trigger.attr('id');
if (type === 'folder') {
this.renameFolderNode(id);
} else {
this.renameFileNode(id);
}
}
}
});
menu.add({
weight: 9,
id: 'del',
preconditionFn: ($trigger) => {
const type = $trigger.attr('type');
return ['file', 'folder'].includes(type);
},
data: {
isHtmlName: true,
name: Menu.getItem(Msg.Lang['fileTree.delete'], ''),
callback: (_, { $trigger }) => {
const type = $trigger.attr('type');
const id = $trigger.attr('id');
if (type === 'folder') {
if (this.#selected_) {
const relative = path.relative(id, this.#selected_);
if (relative.indexOf('../') !== 0) {
this.deselect(this.#selected_);
}
}
this.deleteFolderNode(id);
} else {
if (this.#selected_ === id) {
this.deselect(id);
}
this.deleteFileNode(id);
}
}
}
});
this.#contextMenu_.register('menu', menu);
}
getContextMenu() {
return this.#contextMenu_;
}
openRootFolder() {
if (this.isRootFolderOpened()) {
return;
}
this.#$iconTriangle_.removeClass('codicon-chevron-right');
this.#$iconTriangle_.addClass('codicon-chevron-down');
this.#$iconFolder_.addClass('opened');
this.#$rootFolder_.addClass('opened');
this.#$children_.css('display', 'block');
this.#rootFolderOpened_ = true;
}
closeRootFolder() {
if (!this.isRootFolderOpened()) {
return;
}
this.#$iconTriangle_.removeClass('codicon-chevron-down');
this.#$iconTriangle_.addClass('codicon-chevron-right');
this.#$iconFolder_.removeClass('opened');
this.#$rootFolder_.removeClass('opened');
this.#$children_.css('display', 'none');
const selected = this.#selected_;
this.deselectAll();
this.#selected_ = selected;
this.#rootFolderOpened_ = false;
}
isRootFolderOpened() {
return this.#rootFolderOpened_;
}
setFolderPath(folderPath) {
let newFolderPath = path.join(folderPath);
if (newFolderPath === this.#rootPath_) {
this.#jstree_.refresh();
return;
}
if (this.#rootPath_) {
this.unwatchFolder(this.#rootPath_);
}
this.#rootPath_ = newFolderPath;
this.nodeAliveRegistry.reset();
this.#jstree_.refresh();
this.watchFolder(this.#rootPath_);
this.setRootFolderTitle(this.#rootPath_);
const rootNodeName = path.basename(folderPath).toUpperCase();
this.setRootFolderName(rootNodeName);
}
getFolderPath() {
return this.#rootPath_;
}
setRootFolderName(name) {
this.#rootName_ = name;
this.#$name_.text(name);
}
getRootFolderName() {
return this.#rootName_;
}
setRootFolderTitle(name) {
this.#rootTitle_ = name;
this.#$rootFolder_.attr('title', name);
}
getRootFolderTitle() {
return this.#rootTitle_;
}
refreshFolder(folderPath) {
// 延迟刷新节点防止过于频繁的IO操作
let eventId = this.delayRefreshRegistry.getItem(folderPath);
if (eventId) {
clearTimeout(eventId);
this.delayRefreshRegistry.unregister(folderPath);
}
eventId = setTimeout(() => {
if (folderPath === this.#rootPath_) {
this.#jstree_.refresh();
return;
}
const node = this.#jstree_.get_node(folderPath);
const nodeIsOpened = node && !this.isClosed(folderPath);
if (nodeIsOpened) {
this.watchFolder(folderPath);
this.clearFolderTemp(folderPath);
this.#jstree_.refresh_node(folderPath);
} else {
this.unwatchFolder(folderPath);
}
}, 500);
this.delayRefreshRegistry.register(folderPath, eventId);
}
clearFolderTemp(folderPath) {
const node = this.#jstree_.get_node(folderPath);
if (!node) {
return;
}
node.state.loaded = false;
}
watchFolder(folderPath) {
if (this.isWatched(folderPath)) {
return;
}
this.watchRegistry.register(folderPath, 'folder');
}
unwatchFolder(folderPath) {
if (!this.isWatched(folderPath)) {
return;
}
this.clearFolderTemp(folderPath);
const keys = this.nodeAliveRegistry.keys();
for (let key of keys) {
if (key.indexOf(folderPath) === -1) {
continue;
}
const eventId = this.nodeAliveRegistry.getItem(key);
if (eventId) {
clearTimeout(eventId);
this.nodeAliveRegistry.unregister(key);
}
}
this.watchRegistry.unregister(folderPath);
}
watchFile(filePath) {}
unwatchFile(filePath) {}
isWatched(inPath) {
return !!this.watchRegistry.getItem(inPath);
}
isClosed(inPath) {
return this.#jstree_.is_closed(inPath);
}
select(inPath) {
let elem = document.getElementById(inPath);
if (!elem) {
this.#selected_ = null;
return;
}
this.#selected_ = inPath;
this.#jstree_.select_node(inPath, true, true);
$(elem).children('.jstree-wholerow').addClass('jstree-wholerow-clicked');
}
reselect() {
if (!this.#selected_) {
return;
}
let elem = document.getElementById(this.#selected_);
if (!elem) {
return;
}
this.#jstree_.select_node(this.#selected_, true, true);
$(elem).children('.jstree-wholerow').addClass('jstree-wholerow-clicked');
}
deselect(inPath) {
if (this.#selected_ === inPath) {
this.#selected_ = null;
}
let elem = document.getElementById(inPath);
if (!elem) {
return;
}
this.#jstree_.deselect_node(elem, true);
$(elem).children('.jstree-wholerow').removeClass('jstree-wholerow-clicked');
}
deselectAll() {
this.#selected_ = null;
this.#jstree_.deselect_all();
}
getSelectedNodeId() {
return this.#selected_;
}
getNode(inPath) {
return this.#jstree_.get_node(inPath);
}
getSelectedNodes() {
return this.#jstree_.get_selected(true);
}
async #getChildren_(inPath) {
let output = [];
const content = await this.readFolder(inPath);
for (let item of content) {
const { type, id, title, children } = item;
const text = item.text ?? path.basename(id);
let icon = item.icon ?? 'icon-doc';
if (!item.icon) {
if (type === 'folder') {
icon = this.#getFolderIcon_(text);
} else {
icon = this.#getFileIcon_(text);
}
}
output.push({
text,
id,
children,
li_attr: {
type,
name: text,
title: title ?? id
},
icon
});
}
return output;
}
async readFolder(inPath) {
return [];
}
#getFileIcon_(filename) {
const prefix = 'fileicon-';
if (FileTree.FILE_ICON_MAP[filename]) {
return prefix + FileTree.FILE_ICON_MAP[filename];
}
const extname = path.extname(filename).toLowerCase();
if (FileTree.FILE_ICON_MAP[extname]) {
return prefix + FileTree.FILE_ICON_MAP[extname];
}
return prefix + FileTree.FILE_ICON_MAP['default'];
}
#getFolderIcon_(foldername) {
const prefix = 'foldericon-';
if (FileTree.FOLDER_ICON_MAP[foldername]) {
return prefix + FileTree.FOLDER_ICON_MAP[foldername];
}
return prefix + FileTree.FOLDER_ICON_MAP['default'];
}
createRootChildNode(type) {
this.showProgress();
this.hideMask();
const node = this.#jstree_.get_node('#');
const children = false;
let icon = 'foldericon-default';
if (type === 'file') {
icon = 'fileicon-mix';
}
const folderPath = this.#rootPath_;
this.#jstree_.create_node(node, { children, icon }, 'first', (childNode) => {
this.#jstree_.edit(childNode, '', (newNode) => {
this.showMask();
const desPath = path.join(folderPath, newNode.text);
this.#jstree_.delete_node(newNode);
const oldNode = this.#jstree_.get_node(desPath);
if (oldNode || !newNode.text) {
this.hideProgress();
return;
}
let createPromise = null;
if (type === 'file') {
createPromise = this.#fs_.createFile(desPath);
} else {
createPromise = this.#fs_.createDirectory(desPath);
}
createPromise
.catch(Debug.error)
.finally(() => {
this.hideProgress();
this.runEvent('afterCreateNode', folderPath);
});
});
});
}
createRootChildFileNode() {
this.createRootChildNode('file');
}
createRootChildFolderNode() {
this.createRootChildNode('folder');
}
createNode(type, folderPath) {
this.showProgress();
this.hideMask();
const node = this.#jstree_.get_node(folderPath);
const children = false;
let icon = 'foldericon-default';
if (type === 'file') {
icon = 'fileicon-mix';
}
if (folderPath === '#') {
folderPath = this.#rootPath_;
}
this.#jstree_.open_node(node, () => {
this.#jstree_.create_node(node, { children, icon }, 'first', (childNode) => {
this.#jstree_.edit(childNode, '', (newNode) => {
this.showMask();
this.#jstree_.delete_node(newNode);
if (!newNode.text) {
this.hideProgress();
return;
}
const desPath = path.join(folderPath, newNode.text);
const parentNode = this.#jstree_.get_node(folderPath) ?? {};
for (let nodeId of parentNode.children ?? []) {
if (nodeId !== desPath) {
continue;
}
this.hideProgress();
return;
}
let createPromise = null;
if (type === 'file') {
createPromise = this.#fs_.createFile(desPath);
} else {
createPromise = this.#fs_.createDirectory(desPath);
}
createPromise
.catch(Debug.error)
.finally(() => {
this.hideProgress();
this.runEvent('afterCreateNode', folderPath);
});
});
});
});
}
createFileNode(folderPath) {
this.createNode('file', folderPath);
}
createFolderNode(folderPath) {
this.createNode('folder', folderPath);
}
renameNode(type, inPath) {
this.showProgress();
this.hideMask();
const node = this.#jstree_.get_node(inPath);
const oldNodeName = node.text;
this.#jstree_.edit(node, oldNodeName, (newNode) => {
this.showMask();
const folderPath = path.join(inPath, '..');
const desPath = path.join(folderPath, newNode.text);
this.#jstree_.close_node(newNode);
if (oldNodeName === newNode.text) {
this.hideProgress();
return;
}
this.#jstree_.rename_node(newNode, oldNodeName);
const parentNode = this.#jstree_.get_node(folderPath) ?? {};
for (let nodeId of parentNode.children ?? []) {
if (nodeId !== desPath) {
continue;
}
this.hideProgress();
return;
}
let renamePromise = null;
if (type === 'file') {
renamePromise = this.#fs_.renameFile(inPath, desPath);
} else {
renamePromise = this.#fs_.renameDirectory(inPath, desPath);
}
renamePromise
.catch(Debug.error)
.finally(() => {
this.hideProgress();
this.runEvent('afterRenameNode', path.join(inPath, '..'));
});
});
}
renameFileNode(filePath) {
this.renameNode('file', filePath);
}
renameFolderNode(folderPath) {
this.renameNode('folder', folderPath);
}
deleteNode(type, inPath) {
this.showProgress();
let deletePromise = null;
if (type === 'file') {
deletePromise = this.#fs_.deleteFile(inPath);
} else {
deletePromise = this.#fs_.deleteDirectory(inPath);
}
deletePromise
.catch(Debug.error)
.finally(() => {
this.hideProgress();
this.runEvent('afterDeleteNode', path.join(inPath, '..'));
});
}
deleteFileNode(filePath) {
this.deleteNode('file', filePath);
}
deleteFolderNode(folderPath) {
this.deleteNode('folder', folderPath);
}
copyNode(inPath) {
const node = this.#jstree_.get_node(inPath);
this.#jstree_.copy(node);
}
cutNode(inPath) {
const node = this.#jstree_.get_node(inPath);
this.#jstree_.cut(node);
}
pasteNode(folderPath) {
if (!this.#jstree_.can_paste()) {
return;
}
this.showProgress();
const oldNodes = this.#jstree_.get_buffer();
const oldNode = oldNodes.node[0];
const { mode } = oldNodes;
const { type } = oldNode.li_attr;
let pastePromise = null;
let startPath = oldNode.id;
let endPath = path.join(folderPath, oldNode.text);
if (mode === 'move_node') {
const relativePath = path.relative(startPath, endPath);
if (relativePath.indexOf('..') === -1) {
pastePromise = Promise.resolve();
} else {
if (type === 'file') {
pastePromise = this.#fs_.moveFile(startPath, endPath);
} else {
pastePromise = this.#fs_.createDirectory(endPath)
.then(() => {
return this.#fs_.moveDirectory(startPath, endPath);
});
}
}
} else if (mode === 'copy_node') {
if (type === 'file') {
pastePromise = this.#fs_.copyFile(startPath, endPath);
} else {
pastePromise = this.#fs_.createDirectory(endPath)
.then(() => {
return this.#fs_.copyDirectory(startPath, endPath);
});
}
}
pastePromise
.then(async () => {
if (mode === 'move_node') {
const temp = path.join(startPath, '..');
const relativePath = path.relative(temp, endPath);
if (relativePath.indexOf('..') === -1) {
this.clearFolderTemp(temp);
await this.loadNode(temp);
await this.openNode(temp);
this.clearFolderTemp(folderPath);
await this.loadNode(folderPath);
await this.openNode(folderPath);
} else {
this.clearFolderTemp(folderPath);
await this.loadNode(folderPath);
await this.openNode(folderPath);
this.clearFolderTemp(temp);
await this.loadNode(temp);
await this.openNode(temp);
}
} else {
this.clearFolderTemp(folderPath);
this.#jstree_.refresh_node(folderPath);
this.openNode(folderPath);
}
})
.catch(Debug.error)
.finally(() => {
this.hideProgress();
});
}
loadNode(inPath) {
return new Promise((resolve, reject) => {
if (inPath === '/') {
inPath = '#';
}
const node = this.#jstree_.get_node(inPath);
if (!node) {
resolve();
}
this.#jstree_.load_node(node, () => {
resolve();
});
});
}
openNode(folderPath) {
return new Promise((resolve, reject) => {
const node = this.#jstree_.get_node(folderPath);
if (!node) {
resolve();
}
this.#jstree_.open_node(node, () => {
resolve();
});
});
}
dispose() {
this.#jstree_.destroy();
this.#scrollbar_.destroy();
this.#contextMenu_.dispose();
super.dispose();
}
getFS() {
return this.#fs_;
}
setFS(fs) {
this.#fs_ = fs;
}
showProgress() {
this.#$progress_.css('display', 'block');
this.showMask();
}
hideProgress() {
this.#$progress_.css('display', 'none');
this.hideMask();
}
showMask() {
this.#$mask_.css('display', 'block');
}
hideMask() {
this.#$mask_.css('display', 'none');
}
}
Mixly.FileTree = FileTree;
});