Общие правила кастомизации File Manager читайте здесь.

Чтобы добавить нижнюю панель, создайте класс и опишите в нём интерфейс панели и её поведение:
// новые компоненты наследуются от JetView
class BottomBar extends fileManager.views.JetView {
config() {
const info = {
view: "button", value: "Info", width: 100,
click: () => this.ShowInfo()
};
return { view: "toolbar", cols: [info, {}] };
}
ShowInfo() {
webix.message("Custom button clicked");
}
}
Затем вставьте этот компонент в основной лейаут (fileManager.views.top) в качестве последнего ряда:
class CustomTopView extends fileManager.views.top {
config() {
const ui = super.config();
ui.rows.push(BottomBar);
return ui;
}
}
Не забудьте переопределить класс по умолчанию с помощью свойства override:
{
view: "filemanager",
url: "https://docs.webix.com/filemanager-backend/",
override: new Map([[fileManager.views.topbar, CustomTopBar]]),
}
Related sample: File Manager: Bottom Bar
Чтобы показывать определённую вкладку ("cards", "grid", "double") без возможности переключения между ними, скройте компонент Tabbar у класса fileManager.views.topbar:
class CustomTopBar extends fileManager.views.topbar {
init() {
// логика по умолчанию
super.init();
/* удаление компонента может привести к ошибкам
скрыть компонент безопаснее, чем удалить его */
this.$$("modes").hide();
}
}
После этого замените класс по умолчанию новым классом с помощью свойства override:
{
view:"filemanager",
mode: "cards", // показываем любую вкладку (кроме "grid")
override: new Map([[fileManager.views.topbar, CustomTopBar]]),
}
Related sample: File Manager: Single Mode

Чтобы добавить ещё один режим для работы с директориями, вам необходимо:
1. Описать интерфейс.
2. Добавить опцию в кнопку Segmented на тулбаре.
3. Показать вкладку при клике по опции.
1. Опишите метод config(), так чтобы он возвращал компонент Treemap.
2. Опишите метод init() для загрузки файлов в Treemap:
// новые компоненты наследуются от JetView
class SpaceChartView extends fileManager.views.JetView {
config() {
return {
view: "treemap",
localId: "space",
template: a => a.value,
value: a => a.size,
};
}
}
init(){
// парсим файлы из текущей директории в Treemap
const state = this.getParam("state");
this.on(state.$changes, "path", v => {
this.app
.getService("local")
.files(v)
.then(fs => this.$$("space").sync(fs));
});
}
3. Чтобы добавить новый компонент в File Manager, используйте свойство views:
{
view:"filemanager",
mode: "space",
views: { "custom.space": SpaceChartView }
}
Прежде всего добавьте ещё одну опцию в кнопку segmented на тулбаре:
class CustomTopBar extends fileManager.views.topbar {
config(value, old) {
const ui = super.config();
const modes = ui.cols[ui.cols.length - 1];
modes.width += 42;
modes.options.push({
value: "<span class='space_option'>S</span>",
id: "space" // id опции
});
return ui;
}
}
Затем обработайте клик по опции в компоненте fileManager.views.top, переопределив метод ShowMode:
class CustomTop extends fileManager.views.top {
ShowMode(value, old) {
const state = this.getParam("state");
if (value === "space") { // обработка лика по опции с ID "space"
this.Tree.show();
this.show("custom.space", {
target: "center",
params: { state },
});
} else {
super.ShowMode(value, old);
}
}
}
Не забудьте переопределить классы по умолчанию с помощью свойства override:
{
view:"filemanager"
override: new Map([
[fileManager.views.top, CustomTop],
[fileManager.views.topbar, CustomTopBar],
])
}
Related sample: File Manager: Custom Mode
По умолчанию файлы и папки в File Manager можно перетаскивать. Чтобы отключить это поведение, необходимо вернуть false внутри обработчика событий onBeforeDrag.
Чтобы подписаться на это событие, необходимо создать новый класс, унаследовав его от класса по умолчанию ( fileManager.views.list or fileManager.views.cards ).
Отключение ДнД в режиме "Cards"
class MyCards extends fileManager.views.cards {
init() {
super.init();
// отключение ДнД
this.on(this.$$("cards"), "onBeforeDrag", () => false);
}
}
После этого необходимо заменить класс по умолчанию новым классом:
{
view: "filemanager",
override: new Map([
[fileManager.views.cards, MyCards]
])
}
Related sample: Disabling DnD in grids/cards

Вы можете добавлять, удалять или изменять опции контекстного меню.
Чтобы убрать опцию из контекстного меню, достаточно вызвать метод remove у этого меню и передать в него ID опции в качестве параметра:
Удаление опции 'upload'
class CustomAddNewMenu extends fileManager.views["menus/addnewmenu"] {
init(view) {
// логика по умолчанию
super.init();
// убирает опцию из контекстного меню
view.queryView("menu").remove("upload");
}
}
Вы можете добавить свою опцию (например "clone") в массив опций по умолчанию.
Маска для фильтрации должна быть добавлена к опции как значение свойства show. Вы можете указать одну маску или объединить несколько с помощью "|".
Следующие маски поддерживаются File Manager и Document Manager:
Добавление опции
class CustomMenuBody extends fileManager.views["menus/menubody"] {
config() {
const menu = super.config();
const RIGHT = 0x80;
const ITEMS = 0x100;
// добавление опции в конфигурацию JS
menu.data.push({
id: "clone", value: "Clone",
show: RIGHT | ITEMS, icon: "wxi-plus",
});
return menu;
}
}
Затем нужно описать действие при клике на новую опцию:
class Operations extends fileManager.services.Operations {
initEvents() {
super.initEvents();
this.app.attachEvent("app:action", (name, info) => {
if (name === "clone") {
this.addToClipboard("copy");
this.paste();
}
});
}
}
Related sample: File Manager: Customizing menus
После этого переопределите сервисы и классы по умолчанию с помощью свойства override:
{
view: "filemanager",
override: new Map([
[fileManager.views["menus/menubody"], CustomMenuBody],
[fileManager.views["menus/addnewmenu"], CustomAddNewMenu],
[fileManager.services.Operations, Operations]
])
}
Вы можете настроить порядок сортировки по умолчанию. Для этого необходимо:
1. Переопределить метод RenderData у компонентов list и cards для сортировки директорий при их открытии.
2. Получить коллекцию файлов этой директории.
3. Отсортировать коллекцию как вам угодно - view отразит эти изменения.
Первоначальная сортировка по названиям
class MyGrid extends fileManager.views.list {
RenderData(data) {
super.RenderData(data);
// ждём данных от сервера/из кээша и сортируем их после
data.waitData.then(() => {
data.sort(/*..функция для сортировки*/);
this.$$("table").markSorting("value", dir);
});
}
}
// и переопределяем RenderData у fileManager.views.cards таким же образом
Related sample: File Manager: Initial sorting order
Для работы с File Manager наличие backend сервера необязательно. Вы можете работать с локальными данными в поддерживаемом формате.
Вы можете переопределить backend методы по умолчанию с помощью свойства override и вернуть промис с JSON данными.
Чтобы передать данные для дерева папок (в левой части экрана), необходимо переписать логику метода folders() у сервиса Backend.
class MyBackend extends fileManager.services.Backend {
folders() {
const data = [
{"value":"webinars","id":"/webinars","size":0,"date":1580820822,
"type":"folder","data":[
{"value":"lections","id":"/webinars/lections","size":0,
"date":1581677679,"type":"folder"},
]}
];
return webix.promise.resolve(data);
}
}
Чтобы загрузить файлы, необходимо переопределить метод files. Метод принимает ID директории в качестве параметра. Вы можете подгружать различные данные в зависимости от директории, в которой находитесь.
Загрузка локальных данных
class MyBackend extends fileManager.services.Backend {
files(id) {
let data = [];
if (path == "/") { // корневая директория
data = [
{"value":"videos","id":"/videos", "type":"folder"},
// остальные данные
];
}
return webix.promise.resolve(data);
}
}
Вернуть метаданные вашей файловой системы (свободное и использованное место на диске, общая вместимость; в байтах) с помощью метода getInfo:
Получение метаданных
class MyBackend extends fileManager.services.Backend {
getInfo() {
return webix.promise.resolve({
stats: {
free: 52 * 1000 * 1000,
total: 250 * 1000 * 1000,
used: 198.4 * 1000 * 1000,
}
});
}
}
Related sample: File Manager: Load Local Data
Предположим, вы не хотите, чтобы директории подгружались все и сразу:
Прежде всего необходимо переопределить метод folders у сервисов Backend и LocalData для того чтобы возвращать только первый уровень директорий. Обратите внимание, что мы иммитируем получение данных для примера. В реальных проектах вам не придётся переопределять сервис Backend для того, чтобы реализовать динамическую загрузку папок.
Переопределение Backend
class MyBackend extends fileManager.services.Backend {
folders() {
const data = totalFolders.serialize().map(f => {
if (f.data) delete f.data;
return f;
});
return webix.promise.resolve(data);
}
И для сервиса LocalData:
Переопределение LocalData
class MyLocal extends fileManager.services.LocalData{
folders(force, path) {
const hierarchy = this.hierarchy;
// без параметра *path* метод вернёт только первый уровень директорий
if ((force || !this.folders_ready) && !path) {
return this.app.getService("backend")
.folders()
.then(data => {
hierarchy.parse({ parent: "../files", data });
return hierarchy;
});
}
return Promise.resolve(hierarchy);
}
}
После этого можно создать обработчик событий, который будет динамически подгружать данные остальных директорий (при открытии директории):
Обработчик для динамической загрузки
class MyTree extends fileManager.views.folders{
init(){
super.init();
this.on(this.Tree, "onAfterSelect", id => {
if (id !== "../files")
this.app.getService("local").folders(false, id);
});
}
}
Related sample: File Manager: Dynamically loaded folders
Настройка редактора (файлы типа "code") следует общим правилам.
В этой секции мы поговорим о том, как заменить редактор по умолчанию CodeMirror на Ace редактор и достичь следующего результата:

Related sample: File Manager: Customizing code editor
Для того, чтобы изменить редактор по умолчанию, создайте новый класс, унаследовав его от fileManager.views.editor. Затем опишите конфигурацию нового редактора в методе config() и замените им редактор по умолчанию:
Переопределение конфига для редактора
class Editor extends fileManager.views.editor {
config() {
const ui = super.config();
let editor = { // конфиг для нового редактора
localId: "editor", // не меняйте локальный ID
view: "ace-editor",
theme: "dracula",
};
ui.rows[1] = editor; // заменяет редактор по умолчанию новым
return ui;
}
}
Чтобы добавить файлы, используя API другого редактора (в нашем случае - Ace), переопределите метод AddDoc. Создайте новую сессию с помощью new ace.EditSession и сохраните её в буфер редактора. После чего, вам необходимо указать тип файла для редактора:
AddDoc(file, text) {
this._oldValue[file.id] = text;
// используем api ace
this.Buffers[file.id] = new ace.EditSession(text);
this.Buffers[file.id].setMode(this.GetFileType(file));
}
Чтобы показывать содержимое файлов в редакторе, используя API Ace, вам необходимо переопределить метод OpenDoc:
OpenDoc(name) {
this.$$("editor")
.getEditor(true)
.then(editor => {
// используем api ace
editor.setSession(this.Buffers[name]);
// фокус области редактирования
editor.focus();
});
}
Не забудьте переопределить редактор по умолчанию с помощью свойства override:
Переопределяем редактор по умолчанию
const app = new fileManager.App({
override: new Map([[fileManager.views.editor, Editor]])
});
К этому моменту у вас должен получится следующий результат:

Добавить новые контролы в редактор можно следующими способами:
Переопределение верхней панели
class Editor extends fileManager.views.editor {
config() {
const ui = super.config();
// получает массив элементов панели и добавляет новый
const toolbarEls = ui.rows[0].cols;
toolbarEls.push({ /* новый элемент */ });
return ui;
}
}
Добавление нижней панели инструментов
class Editor extends fileManager.views.editor {
config() {
const ui = super.config();
const bottomBar = {
view: "toolbar",
cols: [
// ... контролы будут здесь
],
};
ui.rows.push(bottomBar);
return ui;
}
}
Related sample: File Manager: Customizing code editor
Так выглядит панель инструментов с новыми контролами:

Кроме того, у вас есть возможность добавить свои стили для редактора или применить тёмную тему Webix к панелям управления и кнопкам.
Наверх