From 16862719b24008d4fdca8c069b0dba5b88113073 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 30 Jan 2023 12:58:21 +0200 Subject: [PATCH] feature: migrate to esbuild --- build.mjs | 51 ++++++++ client/client.js | 202 +++++++++++++++--------------- client/cloudcmd.js | 3 +- client/load-module.js | 30 ++--- client/modules/menu.js | 114 +++++++++-------- client/modules/user-menu/index.js | 62 ++++----- client/modules/view/index.js | 126 +++++++++---------- css/icons.css | 2 +- html/index.html | 7 +- package.json | 1 + server/cloudcmd.js | 2 +- server/columns.js | 2 +- 12 files changed, 331 insertions(+), 271 deletions(-) create mode 100644 build.mjs diff --git a/build.mjs b/build.mjs new file mode 100644 index 00000000..f08d7bd4 --- /dev/null +++ b/build.mjs @@ -0,0 +1,51 @@ +import * as esbuild from 'esbuild' + +const dir = './client'; +const dirModules = './client/modules'; + +await esbuild.build({ + entryPoints: [ + `${dir}/cloudcmd.js`, + `${dirModules}/edit.js`, + `${dirModules}/edit-file.js`, + `${dirModules}/edit-file-vim.js`, + `${dirModules}/edit-names.js`, + `${dirModules}/edit-names-vim.js`, + `${dirModules}/menu.js`, + `${dirModules}/view/index.js`, + `${dirModules}/help.js`, + `${dirModules}/markdown.js`, + `${dirModules}/config/index.js`, + `${dirModules}/contact.js`, + `${dirModules}/upload.js`, + `${dirModules}/operation/index.js`, + `${dirModules}/konsole.js`, + `${dirModules}/terminal.js`, + `${dirModules}/terminal-run.js`, + `${dirModules}/cloud.js`, + `${dirModules}/user-menu/index.js`, + `${dirModules}/polyfill.js`, + `${dirModules}/command-line.js`, + + 'css/columns/name-size-date.css', + 'css/columns/name-size.css', + ], + entryNames: '[dir]', + bundle: true, + minify: true, + sourcemap: true, + target: ['chrome100'], + alias: { + path: 'path-browserify', + }, + outdir: 'dist', + loader: { + '.png': 'dataurl', + '.gif': 'dataurl', + '.woff': 'dataurl', + '.woff2': 'dataurl', + '.ttf': 'dataurl', + '.eot': 'dataurl', + '.svg': 'text', + } +}) diff --git a/client/client.js b/client/client.js index f779cf83..3deced21 100644 --- a/client/client.js +++ b/client/client.js @@ -39,60 +39,60 @@ load.addErrorListener((e, src) => { function CloudCmdProto(DOM) { let Listeners; - + Emitify.call(this); - + const CloudCmd = this; const Info = DOM.CurrentInfo; - + const { Storage, Files, } = DOM; - + this.log = (...a) => { if (!isDev) return; - + console.log(...a); }; this.prefix = ''; this.prefixSocket = ''; this.prefixURL = ''; - this.DIRCLIENT = '/dist/'; - this.DIRCLIENT_MODULES = this.DIRCLIENT + 'modules/'; - + this.DIR_CLIENT = '/dist/client'; + this.DIR_CLIENT_MODULES = this.DIR_CLIENT + '/modules'; + this.MIN_ONE_PANEL_WIDTH = 1155; this.HOST = location.origin || location.protocol + '//' + location.host; - + this.TITLE = 'Cloud Commander'; - + this.sort = { left: 'name', right: 'name', }; - + this.order = { left: 'asc', right: 'asc', }; - + this.changeDir = async (path, {isRefresh, panel, history = true, noCurrent, currentName} = {}) => { const refresh = isRefresh; let panelChanged; - + if (!noCurrent && panel && panel !== Info.panel) { DOM.changePanel(); panelChanged = true; } - + let imgPosition; - + if (panelChanged || refresh || !history) imgPosition = 'top'; - + Images.show.load(imgPosition, panel); - + /* загружаем содержимое каталога */ await ajaxLoad(addSlashToEnd(path), { refresh, @@ -101,7 +101,7 @@ function CloudCmdProto(DOM) { currentName, }, panel); }; - + /** * Конструктор CloudClient, который * выполняет весь функционал по @@ -111,7 +111,7 @@ function CloudCmdProto(DOM) { CloudCmd.prefix = prefix; CloudCmd.prefixURL = `${prefix}${apiURL}`; CloudCmd.prefixSocket = config.prefixSocket; - + CloudCmd.config = (key) => config[key]; CloudCmd.config.if = currify((key, fn, a) => config[key] && fn(a)); CloudCmd._config = (key, value) => { @@ -119,61 +119,63 @@ function CloudCmdProto(DOM) { * should be called from config.js only * after successful update on server */ - + if (key === 'password') return; - + config[key] = value; }; - + if (config.oneFilePanel) CloudCmd.MIN_ONE_PANEL_WIDTH = Infinity; - + if (!document.body.scrollIntoViewIfNeeded) - await load.js(prefix + CloudCmd.DIRCLIENT_MODULES + 'polyfill.js'); - + await load.js(`${prefix}${CloudCmd.DIR_CLIENT_MODULES}/polyfill.js`); + await initModules(); await baseInit(); - await loadStyle(); - + //await loadStyle(); + CloudCmd.route(location.hash); }; - + + /* async function loadStyle() { const {prefix} = CloudCmd; - const name = prefix + '/dist/cloudcmd.common.css'; - + const name = prefix + '/build/cloudcmd.css'; + await load.css(name); } - + */ + this.route = (path) => { const query = path.split('/'); - + if (!path) return; - + const [kebabModule] = query; const module = noJS(pascalCase(kebabModule.slice(1))); - + const file = query[1]; const current = DOM.getCurrentByName(file); - + if (file && !current) { const msg = formatMsg('set current file', file, 'error'); CloudCmd.log(msg); - + return; } - + DOM.setCurrentFile(current); CloudCmd.execFromModule(module, 'show'); }; - + this.logOut = async () => { const url = CloudCmd.prefix + '/logout'; const error = () => document.location.reload(); const {prefix} = CloudCmd; - + await DOM.Storage.clear(); unregisterSW(prefix); DOM.load.ajax({ @@ -181,19 +183,19 @@ function CloudCmdProto(DOM) { error, }); }; - + const initModules = async () => { CloudCmd.Key = Key; CloudCmd.Key.bind(); - + const [, modules] = await tryToCatch(Files.get, 'modules'); const showLoad = Images.show.load; - + const doBefore = { edit: showLoad, menu: showLoad, }; - + const load = (name, path, dobefore) => { loadModule({ name, @@ -201,28 +203,28 @@ function CloudCmdProto(DOM) { dobefore, }); }; - + if (!modules) return; - + for (const module of modules.local) { load(null, module, doBefore[module]); } }; - + async function saveCurrentName(currentName) { await Storage.set('current-name', currentName); } - + async function baseInit() { const files = DOM.getFiles(); - + CloudCmd.on('current-file', DOM.updateCurrentInfo); CloudCmd.on('current-name', saveCurrentName); - + const name = await Storage.get('current-name'); const currentFile = name && DOM.getCurrentByName(name) || files[0]; - + /* выделяем строку с первым файлом */ if (files) DOM.setCurrentFile(currentFile, { @@ -231,56 +233,56 @@ function CloudCmdProto(DOM) { // overwre otherwise history: !location.hash, }); - + const dirPath = DOM.getCurrentDirPath(); Listeners = CloudCmd.Listeners; Listeners.init(); - + const panels = getPanels(); panels.forEach(Listeners.setOnPanel); - + Listeners.initKeysPanel(); - + if (!CloudCmd.config('dirStorage')) return; - + const data = await Storage.get(dirPath); - + if (!data) await Storage.setJson(dirPath, getJsonFromFileTable()); } - + function getPanels() { const panels = ['left']; - + if (CloudCmd.config('oneFilePanel')) return panels; - + return [ ...panels, 'right', ]; } - + this.execFromModule = async (moduleName, funcName, ...args) => { await CloudCmd[moduleName](); - + const func = CloudCmd[moduleName][funcName]; func(...args); }; - + this.refresh = async (options = {}) => { const { panel = Info.panel, currentName, } = options; - + const path = DOM.getCurrentDirPath(panel); - + const isRefresh = true; const history = false; const noCurrent = options ? options.noCurrent : false; - + await CloudCmd.changeDir(path, { isRefresh, history, @@ -289,7 +291,7 @@ function CloudCmdProto(DOM) { currentName, }); }; - + /** * Функция загружает json-данные о Файловой Системе * через ajax-запрос. @@ -302,49 +304,49 @@ function CloudCmdProto(DOM) { */ async function ajaxLoad(path, options = {}, panel) { const {RESTful} = DOM; - + CloudCmd.log('reading dir: "' + path + '";'); - + const dirStorage = CloudCmd.config('dirStorage'); const json = dirStorage && await Storage.getJson(path); - + const name = options.currentName || Info.name; const { noCurrent, refresh, } = options; - + if (!refresh && json) return await createFileTable(json, panel, options); - + const position = DOM.getPanelPosition(panel); const sort = CloudCmd.sort[position]; const order = CloudCmd.order[position]; - + const query = rendy('?sort={{ sort }}&order={{ order }}', { sort, order, }); - + const [, newObj] = await RESTful.read(path + query, 'json'); - + if (!newObj) return; // that's OK, error handled by RESTful - + options.sort = sort; options.order = order; - + await createFileTable(newObj, panel, options); - + if (refresh && !noCurrent) DOM.setCurrentByName(name); - + if (!CloudCmd.config('dirStorage')) return; - + Storage.setJson(path, newObj); } - + /** * Функция строит файловую таблицу * @param json - данные о файлах @@ -357,36 +359,36 @@ function CloudCmdProto(DOM) { history, noCurrent, } = options; - + const names = [ 'file', 'path', 'link', 'pathLink', ]; - + const [ error, [file, path, link, pathLink], ] = await tryToCatch(Files.get, names); - + if (error) return DOM.Dialog.alert(error.responseText); - + const panel = panelParam || DOM.getPanel(); const {prefix} = CloudCmd; - + const { dir, name, } = Info; - + const {childNodes} = panel; let i = childNodes.length; - + while (i--) panel.removeChild(panel.lastChild); - + panel.innerHTML = buildFromJSON({ sort : options.sort, order : options.order, @@ -400,26 +402,26 @@ function CloudCmdProto(DOM) { link, }, }); - + Listeners.setOnPanel(panel); - + if (!noCurrent) { let current; - + if (name === '..' && dir !== '/') current = DOM.getCurrentByName(dir); - + if (!current) [current] = DOM.getFiles(panel); - + DOM.setCurrentFile(current, { history, }); - + CloudCmd.emit('active-dir', Info.dirPath); } } - + this.goToParentDir = async () => { const { dir, @@ -427,17 +429,17 @@ function CloudCmdProto(DOM) { parentDirPath, panel, } = Info; - + if (dirPath === parentDirPath) return; - + const path = parentDirPath; - + await CloudCmd.changeDir(path); - + const current = DOM.getCurrentByName(dir); const [first] = DOM.getFiles(panel); - + DOM.setCurrentFile(current || first, { history, }); diff --git a/client/cloudcmd.js b/client/cloudcmd.js index 58363958..e5614367 100644 --- a/client/cloudcmd.js +++ b/client/cloudcmd.js @@ -50,8 +50,7 @@ const onUpdateFound = wraptile(async (config) => { const {DOM} = window; const prefix = getPrefix(config.prefix); - await load.js(`${prefix}/dist/cloudcmd.common.js`); - await load.js(`${prefix}/dist/cloudcmd.js`); + await load.js(`${prefix}/dist/client/cloudcmd.js`); console.log('cloudcmd: sw: updated'); diff --git a/client/load-module.js b/client/load-module.js index 0bc6eef6..b71cdbe8 100644 --- a/client/load-module.js +++ b/client/load-module.js @@ -16,45 +16,45 @@ const noJS = (a) => a.replace(/.js$/, ''); module.exports = function loadModule(params) { if (!params) return; - + const {path} = params; - + const name = path && noJS(pascalCase(path)); const doBefore = params.dobefore; - + if (CloudCmd[name]) return; - + CloudCmd[name] = () => { exec(doBefore); - + const {prefix} = CloudCmd; - const pathFull = prefix + CloudCmd.DIRCLIENT_MODULES + path + '.js'; - + const pathFull = `${prefix}${CloudCmd.DIR_CLIENT_MODULES}/${path}.js`; + return loadJS(pathFull).then(async () => { const newModule = async (f) => f && f(); const module = CloudCmd[name]; - + Object.assign(newModule, module); - + CloudCmd[name] = newModule; - + CloudCmd.log('init', name); await module.init(); - + return newModule; }); }; - + CloudCmd[name].show = async (...args) => { CloudCmd.log('show', name, args); const m = CloudCmd[name]; - + const [e, a] = await tryToCatch(m); - + if (e) return console.error(e); - + return await a.show(...args); }; }; diff --git a/client/modules/menu.js b/client/modules/menu.js index 4ecc17cb..3a759a0e 100644 --- a/client/modules/menu.js +++ b/client/modules/menu.js @@ -1,19 +1,21 @@ -/* global CloudCmd, DOM */ - 'use strict'; +/* global CloudCmd, DOM */ + const exec = require('execon'); const wrap = require('wraptile'); const supermenu = require('supermenu'); const createElement = require('@cloudcmd/create-element'); +const load = require('load.js'); const {FS} = require('../../common/cloudfunc'); const {getIdBySrc} = require('../dom/load'); const RESTful = require('../dom/rest'); - const { config, Key, + prefix, + DIR_CLIENT_MODULES, } = CloudCmd; const { @@ -35,23 +37,24 @@ module.exports.ENABLED = false; CloudCmd.Menu = exports; -module.exports.init = () => { +module.exports.init = async () => { + await load.css(`${prefix}${DIR_CLIENT_MODULES}/menu.css`); const { isAuth, menuDataFile, } = getFileMenuData(); - + const fm = DOM.getFM(); const menuData = getMenuData(isAuth); const options = getOptions({type: 'context'}); const optionsFile = getOptions({type: 'file'}); - + MenuContext = supermenu(fm, options, menuData); MenuContextFile = supermenu(fm, optionsFile, menuDataFile); - + MenuContext.addContextMenuListener(); MenuContextFile.addContextMenuListener(); - + Events.addKey(listener); }; @@ -64,10 +67,10 @@ function hide() { module.exports.show = (position) => { const {x, y} = getPosition(position); - + MenuContext.show(x, y); MenuContextFile.show(x, y); - + Images.hide(); }; @@ -77,33 +80,33 @@ function getPosition(position) { x: position.x, y: position.y, }; - + return getCurrentPosition(); } function getMenuNameByEl(el) { if (!el) return 'context'; - + const name = DOM.getCurrentName(el); - + if (name === '..') return 'context'; - + return 'contextFile'; } function getOptions({type}) { let name; let func; - + if (type === 'context') { name = 'context'; func = Key.unsetBind; } else if (type === 'file') { name = 'contextFile'; } - + const options = { icon : true, beforeClose : Key.setBind, @@ -111,7 +114,7 @@ function getOptions({type}) { beforeClick, name, }; - + return options; } @@ -128,16 +131,16 @@ function getMenuData(isAuth) { 'Upload From Cloud': uploadFromCloud, '(Un)Select All': DOM.toggleAllSelectedFiles, }; - + if (isAuth) menu['Log Out'] = CloudCmd.logOut; - + return menu; } function getFileMenuData() { const isAuth = CloudCmd.config('auth'); - + const menuBottom = getMenuData(isAuth); const menuTop = { 'View': () => { @@ -168,12 +171,12 @@ function getFileMenuData() { isCurrent(Buffer.copy, alertNoFiles); }, }; - + const menuDataFile = { ...menuTop, ...menuBottom, }; - + return { isAuth, menuDataFile, @@ -183,21 +186,21 @@ function getFileMenuData() { function isCurrent(yesFn, noFn) { if (Info.name !== '..') return yesFn(); - + noFn(); } function isPath(x, y) { const {panel} = Info; const isEmptyRoot = !panel; - + if (isEmptyRoot) return false; - + const el = document.elementFromPoint(x, y); const elements = panel.querySelectorAll('[data-name="js-path"] *'); const is = ~[].indexOf.call(elements, el); - + return is; } @@ -207,22 +210,22 @@ function beforeShow(callback, params) { x: params.x, y: params.y, }); - + const menuName = getMenuNameByEl(el); - + let isShow = menuName !== 'contextFile'; - + if (params.name === 'contextFile') isShow = !isShow; - + if (isShow) MenuShowedName = name; - + exec(callback); - + if (isShow) isShow = isPath(params.x, params.y); - + return isShow; } @@ -232,26 +235,26 @@ function beforeClick(name) { async function _uploadTo(nameModule) { const [error, data] = await Info.getData(); - + if (error) return; - + const {name} = Info; - + CloudCmd.execFromModule(nameModule, 'uploadFile', name, data); CloudCmd.log('Uploading to ' + name + '...'); } function uploadFromCloud() { Images.show.load('top'); - + CloudCmd.execFromModule('Cloud', 'saveFile', async (currentName, data) => { const path = DOM.getCurrentDirPath() + currentName; const [e] = await RESTful.write(path, data); - + if (e) return; - + await CloudCmd.refresh({currentName}); }); } @@ -266,15 +269,15 @@ function download(type) { const PACK = '/pack'; const date = Date.now(); const files = DOM.getActiveFiles(); - + if (!files.length) return alertNoFiles(); - + for (const file of files) { const selected = DOM.isSelected(file); const isDir = DOM.isCurrentIsDir(file); const path = DOM.getCurrentPath(file); - + CloudCmd.log('downloading file ' + path + '...'); /* * if we send ajax request - @@ -283,26 +286,26 @@ function download(type) { */ const encodedPath = encodeURI(path).replace(/#/g, '%23'); const id = getIdBySrc(path); - + let src; - + if (isDir) src = prefixURL + PACK + encodedPath + DOM.getPackerExt(type); else src = prefixURL + FS + encodedPath + '?download'; - + const element = createElement('iframe', { id : id + '-' + date, async: false, className: 'hidden', src, }); - + const {body} = document; const removeChild = body.removeChild.bind(body, element); - + setTimeout(removeChild, TIME); - + if (selected) DOM.toggleSelectedFile(file); } @@ -311,12 +314,12 @@ function download(type) { function getCurrentPosition() { const current = Info.element; const rect = current.getBoundingClientRect(); - + const position = { x: Math.round(rect.left + rect.width / 3), y: Math.round(rect.top), }; - + return position; } @@ -325,20 +328,21 @@ function listener(event) { F9, ESC, } = Key; - + const key = event.keyCode; const isBind = Key.isBind(); - + if (!isBind) return; - + if (key === ESC) return hide(); - + if (key === F9) { const position = getCurrentPosition(); MenuContext.show(position.x, position.y); - + event.preventDefault(); } } + diff --git a/client/modules/user-menu/index.js b/client/modules/user-menu/index.js index 19f9e5ab..045a402f 100644 --- a/client/modules/user-menu/index.js +++ b/client/modules/user-menu/index.js @@ -27,11 +27,15 @@ const sourceStore = fullstore(); const Name = 'UserMenu'; CloudCmd[Name] = module.exports; -const {Key} = CloudCmd; +const { + Key, + prefix, + DIR_CLIENT_MODULES, +} = CloudCmd; module.exports.init = async () => { await Promise.all([ - loadCSS(`${CloudCmd.prefix}/dist/user-menu.css`), + loadCSS(`${prefix}${DIR_CLIENT_MODULES}/user-menu/index.css`), CloudCmd.View(), ]); }; @@ -43,52 +47,52 @@ const {CurrentInfo} = DOM; async function show() { Images.show.load('top'); - + const {dirPath} = CurrentInfo; const res = await fetch(`${CloudCmd.prefix}/api/v1/user-menu?dir=${dirPath}`); const source = await res.text(); const [error, userMenu] = tryCatch(getUserMenu, source); - + Images.hide(); - + if (error) return Dialog.alert(getCodeFrame({error, source})); - + sourceStore(source); - + const { names, keys, items, settings, } = parseUserMenu(userMenu); - + if (settings.run) return runSelected(settings.select, items, runUserMenu); - + const button = createElement('button', { className: 'cloudcmd-user-menu-button', innerText: 'User Menu', notAppend: true, }); - + const select = createElement('select', { className: 'cloudcmd-user-menu', innerHTML: fillTemplate(names), notAppend: true, size: 10, }); - + button.addEventListener('click', onButtonClick(userMenu, select)); select.addEventListener('dblclick', onDblClick(userMenu)); select.addEventListener('keydown', onKeyDown({ keys, userMenu, })); - + const afterShow = () => select.focus(); const autoSize = true; - + CloudCmd.View.show([button, select], { autoSize, afterShow, @@ -97,10 +101,10 @@ async function show() { function fillTemplate(options) { const result = []; - + for (const option of options) result.push(``); - + return result.join(''); } @@ -122,39 +126,39 @@ const onKeyDown = currify(async ({keys, userMenu}, e) => { keyCode, target, } = e; - + const keyName = e.key.toUpperCase(); - + e.preventDefault(); e.stopPropagation(); - + let value; - + if (keyCode === Key.ESC) return hide(); - + if (keyCode === Key.ENTER) value = userMenu[target.value]; else if (keys[keyName]) value = keys[keyName]; else return navigate(target, e); - + await runUserMenu(value); }); const runUserMenu = async (fn) => { hide(); - + const [error] = await tryToCatch(fn, { DOM, CloudCmd, tryToCatch, }); - + if (!error) return; - + const source = sourceStore(); return Dialog.alert(getCodeFrame({ error, @@ -164,25 +168,25 @@ const runUserMenu = async (fn) => { function getCodeFrame({error, source}) { const {code} = error; - + if (!code || code === 'frame') return error.message; - + const [line, column] = parseError(error); const start = { line, column, }; - + const location = { start, }; - + const frame = codeFrameColumns(source, location, { message: error.message, highlightCode: false, }); - + return `
${frame}
`; } diff --git a/client/modules/view/index.js b/client/modules/view/index.js index be765bd4..063ffce7 100644 --- a/client/modules/view/index.js +++ b/client/modules/view/index.js @@ -64,20 +64,20 @@ const Config = { Images.hide(); Key.unsetBind(); }, - + beforeClose: () => { Events.rmKey(listener); Key.setBind(); }, - + afterShow: () => { El.focus(); }, - + onOverlayClick, afterClose: noop, autoSize: false, - + helpers: { title: {}, }, @@ -86,62 +86,62 @@ module.exports._Config = Config; module.exports.init = async () => { await loadAll(); - + const events = [ 'click', 'contextmenu', ]; - + events.forEach(addEvent(Overlay, onOverlayClick)); }; async function show(data, options = {}) { const prefixURL = CloudCmd.prefixURL + FS; - + if (Loading) return; - + if (!options || options.bindKeys !== false) Events.addKey(listener); - + El = createElement('div', { className: 'view', notAppend: true, }); - + El.tabIndex = 0; - + if (data) { if (isArray(data)) El.append(...data); else El.append(data); - + modal.open(El, initConfig(options)); return; } - + Images.show.load(); - + const path = prefixURL + Info.path; const type = options.raw ? '' : await getType(path); - + switch(type) { default: return await viewFile(); - + case 'markdown': return await CloudCmd.Markdown.show(Info.path); - + case 'html': return viewHtml(path); - + case 'image': return viewImage(Info.path, prefixURL); - + case 'media': return await viewMedia(path); - + case 'pdf': return viewPDF(path); } @@ -154,11 +154,11 @@ function createIframe(src) { width: '100%', height: '100%', }); - + element.addEventListener('load', () => { element.contentWindow.addEventListener('keydown', listener); }); - + return element; } @@ -169,21 +169,21 @@ function viewHtml(src) { function viewPDF(src) { const element = createIframe(src); - + const options = assign({}, Config); - + if (CloudCmd.config('showFileName')) options.title = Info.name; - + modal.open(element, options); } async function viewMedia(path) { const [e, element] = await getMediaElement(path); - + if (e) return alert(e); - + const allConfig = { ...Config, ...{ @@ -195,22 +195,22 @@ async function viewMedia(path) { }, }, }; - + modal.open(element, allConfig); } async function viewFile() { const [error, data] = await Info.getData(); - + if (error) return Images.hide(); - + const element = document.createTextNode(data); const options = Config; - + if (CloudCmd.config('showFileName')) options.title = Info.name; - + El.append(element); modal.open(El, options); } @@ -220,25 +220,25 @@ const copy = (a) => assign({}, a); module.exports._initConfig = initConfig; function initConfig(options) { const config = copy(Config); - + if (!options) return config; - + const names = Object.keys(options); - + for (const name of names) { const isConfig = Boolean(config[name]); const item = options[name]; - + if (!isFn(item) || !isConfig) { config[name] = options[name]; continue; } - + const fn = config[name]; config[name] = series(fn, item); } - + return config; } @@ -252,14 +252,14 @@ function viewImage(path, prefixURL) { href: `${prefixURL}${path}`, title: encode(basename(path)), }); - + const names = Info.files .map(DOM.getCurrentPath) .filter(isSupportedImage); - + const titles = names .map(makeTitle); - + const index = names.indexOf(Info.path); const imageConfig = { index, @@ -270,41 +270,41 @@ function viewImage(path, prefixURL) { title : {}, }, }; - + const config = { ...Config, ...imageConfig, }; - + modal.open(titles, config); } async function getMediaElement(src) { check(src); - + const [error, template] = await tryToCatch(Files.get, 'view/media-tmpl'); - + if (error) return [error]; - + const {name} = Info; - + if (!TemplateAudio) TemplateAudio = template; - + const is = isAudio(name); const type = is ? 'audio' : 'video'; - + const innerHTML = rendy(TemplateAudio, { src, type, name, }); - + const element = createElement('div', { innerHTML, }); - + return [null, element]; } @@ -318,12 +318,12 @@ function check(src) { * @callback - executes, when everything loaded */ async function loadAll() { - const {prefix} = CloudCmd; - + const {DIRCLIENT_MODULES} = CloudCmd; + time(Name + ' load'); - + Loading = true; - await loadCSS(`${prefix}/dist/view.css`); + await loadCSS(`${DIRCLIENT_MODULES}view/index.css`); Loading = false; } @@ -332,32 +332,32 @@ function onOverlayClick(event) { x: event.clientX, y: event.clientY, }; - + setCurrentByPosition(position); } function setCurrentByPosition(position) { const element = DOM.getCurrentByPosition(position); - + if (!element) return; - + const { files, filesPassive, } = Info; - + const isFiles = files.includes(element); const isFilesPassive = filesPassive.includes(element); - + if (!isFiles && !isFilesPassive) return; - + const isCurrent = DOM.isCurrentFile(element); - + if (isCurrent) return; - + DOM.setCurrentFile(element); } diff --git a/css/icons.css b/css/icons.css index eda3c688..6e306e52 100644 --- a/css/icons.css +++ b/css/icons.css @@ -58,7 +58,7 @@ content : '\e80c '; } -.icon-file::before, { +.icon-file::before { font-family : 'Fontello'; content : '\e80d '; } diff --git a/html/index.html b/html/index.html index 00ae977e..982dd2cf 100644 --- a/html/index.html +++ b/html/index.html @@ -8,9 +8,9 @@ - +