diff --git a/.eslintrc.js b/.eslintrc.js
deleted file mode 100644
index 13d9e227..00000000
--- a/.eslintrc.js
+++ /dev/null
@@ -1,38 +0,0 @@
-'use strict';
-
-module.exports = {
- extends: [
- 'plugin:putout/safe+align',
- ],
- plugins: [
- 'putout',
- 'n',
- ],
- rules: {
- 'key-spacing': 'off',
- 'n/prefer-node-protocol': 'error',
- },
- overrides: [{
- files: ['bin/release.js'],
- rules: {
- 'no-console': 'off',
- 'n/shebang': 'off',
- },
- }, {
- files: ['client/dom/index.js'],
- rules: {
- 'no-multi-spaces': 'off',
- },
- }, {
- files: ['bin/cloudcmd.js'],
- rules: {
- 'no-console': 'off',
- },
- }, {
- files: ['{client,common,static}/**/*.js'],
- env: {
- browser: true,
- },
- }],
- ignorePatterns: ['*.md{js}'],
-};
diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index e4877cb7..376b0f08 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -11,12 +11,12 @@ jobs:
packages: write
steps:
- name: Checkout
- uses: actions/checkout@v4
- - uses: oven-sh/setup-bun@v1
+ uses: actions/checkout@v5
+ - uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Use Node.js 22.x
- uses: actions/setup-node@v4
+ uses: actions/setup-node@v6
with:
node-version: 22.x
- name: Install Redrun
diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml
index 88fed4f0..1b392900 100644
--- a/.github/workflows/nodejs.yml
+++ b/.github/workflows/nodejs.yml
@@ -9,15 +9,16 @@ jobs:
strategy:
matrix:
node-version:
- - 20.x
- 22.x
+ - 24.x
+ - 25.x
steps:
- - uses: actions/checkout@v4
- - uses: oven-sh/setup-bun@v1
+ - uses: actions/checkout@v5
+ - uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v4
+ uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
- name: Install Redrun
diff --git a/.npmignore b/.npmignore
index 08137773..b668cf7f 100644
--- a/.npmignore
+++ b/.npmignore
@@ -18,6 +18,7 @@ now.json
app.json
bower.json
manifest.yml
+deno.json
bin/release.mjs
diff --git a/.putout.json b/.putout.json
index 239eb08d..b868f59d 100644
--- a/.putout.json
+++ b/.putout.json
@@ -7,6 +7,9 @@
"fontello.json",
"*.md"
],
+ "rules": {
+ "package-json/add-type": "off"
+ },
"match": {
"base64": {
"types/convert-typeof-to-is-type": "off"
@@ -26,9 +29,12 @@
"server/{server,exit,terminal,distribute/log}.{js,mjs}": {
"remove-console": "off"
},
- "client/{client,cloudcmd,load-module}.js": {
+ "client/{client,cloudcmd,load-module}.{js,mjs}": {
"remove-console": "off"
},
+ "client": {
+ "nodejs": "off"
+ },
"client/sw": {
"remove-console": "off"
},
@@ -43,6 +49,9 @@
},
"vim.js": {
"merge-duplicate-functions": "off"
+ },
+ "common": {
+ "nodejs/declare": "off"
}
}
}
diff --git a/.webpack/css.js b/.webpack/css.mjs
similarity index 71%
rename from .webpack/css.js
rename to .webpack/css.mjs
index 2d3faf55..338ae91b 100644
--- a/.webpack/css.js
+++ b/.webpack/css.mjs
@@ -1,9 +1,6 @@
-'use strict';
-
-const {env} = require('node:process');
-
-const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
-const MiniCssExtractPlugin = require('mini-css-extract-plugin');
+import {env} from 'node:process';
+import OptimizeCssAssetsPlugin from 'optimize-css-assets-webpack-plugin';
+import MiniCssExtractPlugin from 'mini-css-extract-plugin';
const isDev = env.NODE_ENV === 'development';
@@ -29,7 +26,7 @@ const rules = [{
type: 'asset/inline',
}];
-module.exports = {
+export default {
plugins,
module: {
rules,
diff --git a/.webpack/html.js b/.webpack/html.mjs
similarity index 85%
rename from .webpack/html.js
rename to .webpack/html.mjs
index 3717bcc9..e90038ac 100644
--- a/.webpack/html.js
+++ b/.webpack/html.mjs
@@ -1,11 +1,9 @@
-'use strict';
-
-const {env} = require('node:process');
-const HtmlWebpackPlugin = require('html-webpack-plugin');
+import {env} from 'node:process';
+import HtmlWebpackPlugin from 'html-webpack-plugin';
const isDev = env.NODE_ENV === 'development';
-const plugins = [
+export const plugins = [
new HtmlWebpackPlugin({
inject: false,
template: 'html/index.html',
@@ -13,10 +11,6 @@ const plugins = [
}),
];
-module.exports = {
- plugins,
-};
-
function getMinifyHtmlOptions() {
return {
removeComments: true,
diff --git a/.webpack/js.js b/.webpack/js.mjs
similarity index 90%
rename from .webpack/js.js
rename to .webpack/js.mjs
index d666780d..d52e0388 100644
--- a/.webpack/js.js
+++ b/.webpack/js.mjs
@@ -1,18 +1,12 @@
-'use strict';
+import {resolve, sep} from 'node:path';
+import {env} from 'node:process';
+import webpack from 'webpack';
+import WebpackBar from 'webpackbar';
-const {
- resolve,
- sep,
- join,
-} = require('node:path');
-
-const {env} = require('node:process');
const {
EnvironmentPlugin,
NormalModuleReplacementPlugin,
-} = require('webpack');
-
-const WebpackBar = require('webpackbar');
+} = webpack;
const modules = './modules';
const dirModules = './client/modules';
@@ -23,7 +17,7 @@ const dir = './client';
const {NODE_ENV} = env;
const isDev = NODE_ENV === 'development';
-const rootDir = join(__dirname, '..');
+const rootDir = new URL('..', import.meta.url).pathname;
const dist = resolve(rootDir, 'dist');
const distDev = resolve(rootDir, 'dist-dev');
const devtool = isDev ? 'eval' : 'source-map';
@@ -31,7 +25,7 @@ const devtool = isDev ? 'eval' : 'source-map';
const notEmpty = (a) => a;
const clean = (array) => array.filter(notEmpty);
-const noParse = (a) => /\.spec\.js$/.test(a);
+const noParse = (a) => a.endsWith('.spec.js');
const options = {
babelrc: true,
};
@@ -92,7 +86,7 @@ const splitChunks = {
},
};
-module.exports = {
+export default {
resolve: {
symlinks: false,
alias: {
@@ -100,8 +94,8 @@ module.exports = {
'node:path': 'path',
},
fallback: {
- path: require.resolve('path-browserify'),
- process: require.resolve('process/browser'),
+ path: import.meta.resolve('path-browserify'),
+ process: import.meta.resolve('process/browser'),
},
},
devtool,
@@ -120,7 +114,7 @@ module.exports = {
'terminal': `${dirCss}/terminal.css`,
'user-menu': `${dirCss}/user-menu.css`,
'sw': `${dir}/sw/sw.js`,
- 'cloudcmd': `${dir}/cloudcmd.js`,
+ 'cloudcmd': `${dir}/cloudcmd.mjs`,
[`${modules}/edit`]: `${dirModules}/edit.js`,
[`${modules}/edit-file`]: `${dirModules}/edit-file.js`,
[`${modules}/edit-file-vim`]: `${dirModules}/edit-file-vim.js`,
@@ -133,7 +127,7 @@ module.exports = {
[`${modules}/config`]: `${dirModules}/config/index.js`,
[`${modules}/contact`]: `${dirModules}/contact.js`,
[`${modules}/upload`]: `${dirModules}/upload.js`,
- [`${modules}/operation`]: `${dirModules}/operation/index.js`,
+ [`${modules}/operation`]: `${dirModules}/operation/index.mjs`,
[`${modules}/konsole`]: `${dirModules}/konsole.js`,
[`${modules}/terminal`]: `${dirModules}/terminal.js`,
[`${modules}/terminal-run`]: `${dirModules}/terminal-run.js`,
diff --git a/ChangeLog b/ChangeLog
index 8b41875d..edf5330e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,226 @@
+2026.01.21, v19.1.9
+
+feature:
+- 75ad4415 cloudcmd: @putout/eslint-flat v4.0.0
+- c5d9bd7c client: key: vim: get rid of mock-require
+- f437a52f client: images: migrate to EMS
+- 7192a56e client: dom: current-file: migrate to ESM
+
+2026.01.20, v19.1.8
+
+fix:
+- 8a769fd5 client: modules: operation: no update after copy
+
+feature:
+- d574a93d client: key: migrate to ESM
+- 3b409074 client: modules: operation: migrate to ESM
+- 3b6b0b5a client: buffer: migrate to ESM
+- 8876f050 cloudcmd: eslint-plugin-putout v30.0.0
+
+2026.01.17, v19.1.7
+
+feature:
+- 23a6a698 client: dom/events -> #dom/events
+- 9cebb241 client: dom: events: migrate to ESM
+- a94fa0d4 client: cloudcmd: migrate to ESM
+- 3bdf47a5 client: migrate to ESM
+
+2026.01.16, v19.1.6
+
+fix:
+- a523ef65 tests
+
+feature:
+- 64654e8d common: cloudfunc: migrate to ESM
+- add31607 common: cloudfunc: get rid of bas64
+- e36de00c modulas: migrate to ESM
+
+2026.01.16, v19.1.5
+
+feature:
+- 450f1461 client: improve testability
+- d979e949 server: env: migrate to ESM
+
+2026.01.15, v19.1.4
+
+feature:
+- 6e778a35 client: sort: migrate to ESM
+- e27ef51d client: sort: migrate to ESM
+- 917f5851 client: load-module: migrate to ESM
+- 9950caca client: get-json-from-file-table: migrate to ESM
+
+2026.01.15, v19.1.3
+
+feature:
+- f903c5c9 cloudcmd: multi-rename v3.0.0
+
+2026.01.14, v19.1.2
+
+fix:
+- 9e2c5ac6 client: edit-names: group rename not renaming (#453)
+- f0dcbe94 client: key: config
+
+feature:
+- 6856207d server: env -> env.parse
+- dc99417c client: key: get rid of mock-require
+- 4bb7d704 client: modules: view: get rid of mock-require
+
+2026.01.12, v19.1.1
+
+feature:
+- 5cc6f79d cloudcmd: @cloudcmd/stub v5.0.0
+- 024bc413 cloudcmd: fullstore v4.0.0
+- 53f6f9e7 cloudcmd: globals v17.0.0
+- 6d21c539 cloudcmd: madrun v12.1.0
+- 253389ea cloudcmd: supertape v12.0.0
+
+2025.12.31, v19.1.0
+
+feature:
+- 0ff16314 cloudcmd: redlint v5.0.0
+- 43edba8c cloudcmd: try-to-catch v4.0.0
+- 06f3b782 cloudcmd: try-catch v4.0.4
+- dfcd6557 deno config: add
+- ab20a462 server: bun support (oven-sh/bun#25674)
+
+2025.12.24, v19.0.17
+
+feature:
+- 0222d177 cloudcmd: gritty v9.0.0
+
+2025.12.05, v19.0.16
+
+feature:
+- 14ec19e8 cloudcmd: find-up v8.0.0
+- e6a00979 cloudcmd: eslint-plugin-putout v29.0.2
+- 5b5352c7 cloudcmd: putout v41.0.0
+
+2025.11.28, v19.0.15
+
+feature:
+- 00676531 cloudcmd: aleman v1.16.5
+
+2025.11.27, v19.0.14
+
+fix:
+- 2a525e9b aleman: copy paste in text editor (#449)
+
+feature:
+- 3ceb9a8c cloudcmd: open v11.0.0
+
+2025.09.26, v19.0.13
+
+feature:
+- 8477f3e4 cloudcmd: aleman v1.16.3 (#446)
+
+2025.09.25, v19.0.12
+
+feature:
+- 836e908e cloudcmd: aleman v1.16.2
+
+2025.09.24, v19.0.11
+
+feature:
+- f4386a6f cloudcmd: aleman v1.16.1
+
+2025.09.23, v19.0.10
+
+feature:
+- 2e667ba6 cloudcmd: aleman v1.15.0
+
+2025.09.22, v19.0.9
+
+feature:
+- 60c56164 cloudcmd: aleman v1.14.4
+
+2025.09.20, v19.0.8
+
+feature:
+- efe81320 cloudcmd: aleman v1.14.3
+
+2025.09.18, v19.0.7
+
+feature:
+- 5b972e2e cloudcmd: aleman v1.14.0
+
+2025.09.17, v19.0.6
+
+feature:
+- 39a24028 cloudcmd: aleman v1.13.0
+
+2025.09.16, v19.0.5
+
+fix:
+- 64df81bc cloudcmd: client: listeners: f9: stopPropagation
+
+feature:
+- 38dd5101 cloudcmd: aleman v1.12.4
+
+2025.09.15, v19.0.4
+
+feature:
+- 66db798c cloudcmd: aleman v1.12.3
+
+2025.09.15, v19.0.3
+
+feature:
+- c5aed16f cloudcmd: aleman v1.12.2
+
+2025.09.14, v19.0.2
+
+feature:
+- 511347d3 cloudcmd: aleman v1.11.0
+
+2025.09.14, v19.0.1
+
+fix:
+- fc6304a1 tmpl: config: aleman, supermenu
+
+feature:
+- a05ecdb4 cloudcmd: aleman v1.10.0
+
+2025.09.14, v19.0.0
+
+feature:
+- 50b19dcc cloudcmd: menu: default: supermenu -> aleman
+- 5970f10a cloudcmd: drop support of node < 22
+
+2025.09.14, v18.8.11
+
+feature:
+- b0360d8e cloudcmd: aleman v1.9.1
+- 00a20129 cloudcmd: html: importsmap: add
+
+2025.09.14, v18.8.10
+
+feature:
+- ddf9e455 cloudcmd: aleman v1.9.0
+
+2025.09.14, v18.8.9
+
+feature:
+- 2e7bdb8a cloudcmd: aleman v1.8.0
+
+2025.09.13, v18.8.8
+
+feature:
+- 03631d95 cloudcmd: aleman v1.7.0
+
+2025.09.12, v18.8.7
+
+feature:
+- 09408af5 cloudcmd: aleman v1.6.1
+
+2025.09.12, v18.8.6
+
+feature:
+- 4fcaf288 cloudcmd: aleman v1.6.0
+
+2025.09.10, v18.8.5
+
+feature:
+- c69ec16e cloudcmd: aleman v1.5.0
+
2025.09.09, v18.8.4
feature:
diff --git a/HELP.md b/HELP.md
index 47a6408c..68087875 100644
--- a/HELP.md
+++ b/HELP.md
@@ -1,4 +1,4 @@
-# Cloud Commander v18.8.4
+# Cloud Commander v19.1.9
### [Main][MainURL] [Blog][BlogURL] [Support][SupportURL] [Demo][DemoURL]
@@ -190,7 +190,8 @@ Then, start the server again with `cloudcmd` and reload the page.
| `Ctrl + F5` | sort by date
| `Ctrl + F6` | sort by size
| `Ctrl + Command + .` | show/hide dot files
-| `Up`, `Down` | file system navigation
+| `Up` | move cursor up
+| `Down` | move cursor down
| `Enter` | change directory/view file
| `Alt + Left/Right` | show content of directory under cursor in target panel
| `Alt + G` | go to directory
@@ -646,10 +647,20 @@ Right-mouse click to show a context menu with these items:
### Hot keys
-|Key |Operation
-|:----------------------|:--------------------------------------------
-| `F9` | open
-| `Esc` | close
+| Key | Operation |
+|:-------------|:------------------------|
+| `F9` | open |
+| `Esc` | close |
+| `Up`, `j` | move cursor up |
+| `Down`, `k` | move cursor down |
+| `Left`, `h` | close submenu |
+| `Right`, `l` | open submenu |
+| `G` or `$` | navigate to bottom |
+| `gg` or `^` | navigate to top |
+
+Commands can be joined, for example:
+
+- `5j` will navigate **5** items below current;
## One file panel
@@ -1100,6 +1111,41 @@ There are a lot of ways to be involved in `Cloud Commander` development:
## Version history
+- *2026.01.21*, **[v19.1.9](//github.com/coderaiser/cloudcmd/releases/tag/v19.1.9)**
+- *2026.01.20*, **[v19.1.8](//github.com/coderaiser/cloudcmd/releases/tag/v19.1.8)**
+- *2026.01.17*, **[v19.1.7](//github.com/coderaiser/cloudcmd/releases/tag/v19.1.7)**
+- *2026.01.16*, **[v19.1.6](//github.com/coderaiser/cloudcmd/releases/tag/v19.1.6)**
+- *2026.01.16*, **[v19.1.5](//github.com/coderaiser/cloudcmd/releases/tag/v19.1.5)**
+- *2026.01.15*, **[v19.1.4](//github.com/coderaiser/cloudcmd/releases/tag/v19.1.4)**
+- *2026.01.15*, **[v19.1.3](//github.com/coderaiser/cloudcmd/releases/tag/v19.1.3)**
+- *2026.01.14*, **[v19.1.2](//github.com/coderaiser/cloudcmd/releases/tag/v19.1.2)**
+- *2026.01.12*, **[v19.1.1](//github.com/coderaiser/cloudcmd/releases/tag/v19.1.1)**
+- *2025.12.31*, **[v19.1.0](//github.com/coderaiser/cloudcmd/releases/tag/v19.1.0)**
+- *2025.12.24*, **[v19.0.17](//github.com/coderaiser/cloudcmd/releases/tag/v19.0.17)**
+- *2025.12.05*, **[v19.0.16](//github.com/coderaiser/cloudcmd/releases/tag/v19.0.16)**
+- *2025.11.28*, **[v19.0.15](//github.com/coderaiser/cloudcmd/releases/tag/v19.0.15)**
+- *2025.11.27*, **[v19.0.14](//github.com/coderaiser/cloudcmd/releases/tag/v19.0.14)**
+- *2025.09.26*, **[v19.0.13](//github.com/coderaiser/cloudcmd/releases/tag/v19.0.13)**
+- *2025.09.25*, **[v19.0.12](//github.com/coderaiser/cloudcmd/releases/tag/v19.0.12)**
+- *2025.09.24*, **[v19.0.11](//github.com/coderaiser/cloudcmd/releases/tag/v19.0.11)**
+- *2025.09.23*, **[v19.0.10](//github.com/coderaiser/cloudcmd/releases/tag/v19.0.10)**
+- *2025.09.22*, **[v19.0.9](//github.com/coderaiser/cloudcmd/releases/tag/v19.0.9)**
+- *2025.09.20*, **[v19.0.8](//github.com/coderaiser/cloudcmd/releases/tag/v19.0.8)**
+- *2025.09.18*, **[v19.0.7](//github.com/coderaiser/cloudcmd/releases/tag/v19.0.7)**
+- *2025.09.17*, **[v19.0.6](//github.com/coderaiser/cloudcmd/releases/tag/v19.0.6)**
+- *2025.09.16*, **[v19.0.5](//github.com/coderaiser/cloudcmd/releases/tag/v19.0.5)**
+- *2025.09.15*, **[v19.0.4](//github.com/coderaiser/cloudcmd/releases/tag/v19.0.4)**
+- *2025.09.15*, **[v19.0.3](//github.com/coderaiser/cloudcmd/releases/tag/v19.0.3)**
+- *2025.09.14*, **[v19.0.2](//github.com/coderaiser/cloudcmd/releases/tag/v19.0.2)**
+- *2025.09.14*, **[v19.0.1](//github.com/coderaiser/cloudcmd/releases/tag/v19.0.1)**
+- *2025.09.14*, **[v19.0.0](//github.com/coderaiser/cloudcmd/releases/tag/v19.0.0)**
+- *2025.09.14*, **[v18.8.11](//github.com/coderaiser/cloudcmd/releases/tag/v18.8.11)**
+- *2025.09.14*, **[v18.8.10](//github.com/coderaiser/cloudcmd/releases/tag/v18.8.10)**
+- *2025.09.14*, **[v18.8.9](//github.com/coderaiser/cloudcmd/releases/tag/v18.8.9)**
+- *2025.09.13*, **[v18.8.8](//github.com/coderaiser/cloudcmd/releases/tag/v18.8.8)**
+- *2025.09.12*, **[v18.8.7](//github.com/coderaiser/cloudcmd/releases/tag/v18.8.7)**
+- *2025.09.12*, **[v18.8.6](//github.com/coderaiser/cloudcmd/releases/tag/v18.8.6)**
+- *2025.09.10*, **[v18.8.5](//github.com/coderaiser/cloudcmd/releases/tag/v18.8.5)**
- *2025.09.09*, **[v18.8.4](//github.com/coderaiser/cloudcmd/releases/tag/v18.8.4)**
- *2025.09.04*, **[v18.8.3](//github.com/coderaiser/cloudcmd/releases/tag/v18.8.3)**
- *2025.09.04*, **[v18.8.2](//github.com/coderaiser/cloudcmd/releases/tag/v18.8.2)**
diff --git a/README.md b/README.md
index 2f8726cd..8e510161 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Cloud Commander v18.8.4 [![Build Status][BuildStatusIMGURL]][BuildStatusURL] [![Codacy][CodacyIMG]][CodacyURL] [![Gitter][GitterIMGURL]][GitterURL]
+# Cloud Commander v19.1.9 [![Build Status][BuildStatusIMGURL]][BuildStatusURL] [![Codacy][CodacyIMG]][CodacyURL] [![Gitter][GitterIMGURL]][GitterURL]
### [Main][MainURL] [Blog][BlogURL] [Support][SupportURL] [Demo][DemoURL]
diff --git a/bin/cloudcmd.mjs b/bin/cloudcmd.mjs
index 11dabd3d..e1c358ed 100755
--- a/bin/cloudcmd.mjs
+++ b/bin/cloudcmd.mjs
@@ -3,12 +3,12 @@
import process from 'node:process';
import {createRequire} from 'node:module';
import {promisify} from 'node:util';
-import tryToCatch from 'try-to-catch';
+import {tryToCatch} from 'try-to-catch';
import {createSimport} from 'simport';
import parse from 'yargs-parser';
import exit from '../server/exit.js';
-import {createConfig, configPath} from '../server/config.js';
-import env from '../server/env.js';
+import {createConfig, configPath} from '../server/config.mjs';
+import * as env from '../server/env.mjs';
import prefixer from '../server/prefixer.js';
import * as validate from '../server/validate.mjs';
@@ -101,27 +101,27 @@ const yargsOptions = {
],
default: {
'server': true,
- 'name': choose(env('name'), config('name')),
+ 'name': choose(env.parse('name'), config('name')),
'auth': choose(env.bool('auth'), config('auth')),
'port': config('port'),
'online': config('online'),
'open': choose(env.bool('open'), config('open')),
- 'editor': env('editor') || config('editor'),
- 'menu': env('menu') || config('menu'),
+ 'editor': env.parse('editor') || config('editor'),
+ 'menu': env.parse('menu') || config('menu'),
'packer': config('packer') || 'tar',
'zip': config('zip'),
- 'username': env('username') || config('username'),
- 'root': choose(env('root'), config('root')),
- 'prefix': choose(env('prefix'), config('prefix')),
+ 'username': env.parse('username') || config('username'),
+ 'root': choose(env.parse('root'), config('root')),
+ 'prefix': choose(env.parse('prefix'), config('prefix')),
'console': choose(env.bool('console'), config('console')),
'contact': choose(env.bool('contact'), config('contact')),
'terminal': choose(env.bool('terminal'), config('terminal')),
- 'columns': env('columns') || config('columns') || '',
- 'theme': env('theme') || config('theme') || '',
+ 'columns': env.parse('columns') || config('columns') || '',
+ 'theme': env.parse('theme') || config('theme') || '',
'vim': choose(env.bool('vim'), config('vim')),
'log': config('log'),
- 'import-url': env('import_url') || config('importUrl'),
+ 'import-url': env.parse('import_url') || config('importUrl'),
'import-listen': choose(env.bool('import_listen'), config('importListen')),
'import': choose(env.bool('import'), config('import')),
'export': choose(env.bool('export'), config('export')),
@@ -132,15 +132,15 @@ const yargsOptions = {
'sync-console-path': choose(env.bool('sync_console_path'), config('syncConsolePath')),
'config-dialog': choose(env.bool('config_dialog'), config('configDialog')),
'config-auth': choose(env.bool('config_auth'), config('configAuth')),
- 'terminal-path': env('terminal_path') || config('terminalPath'),
- 'terminal-command': env('terminal_command') || config('terminalCommand'),
+ 'terminal-path': env.parse('terminal_path') || config('terminalPath'),
+ 'terminal-command': env.parse('terminal_command') || config('terminalCommand'),
'terminal-auto-restart': choose(env.bool('terminal_auto_restart'), config('terminalAutoRestart')),
'one-file-panel': choose(env.bool('one_file_panel'), config('oneFilePanel')),
'confirm-copy': choose(env.bool('confirm_copy'), config('confirmCopy')),
'confirm-move': choose(env.bool('confirm_move'), config('confirmMove')),
'keys-panel': env.bool('keys_panel') || config('keysPanel'),
- 'import-token': env('import_token') || config('importToken'),
- 'export-token': env('export_token') || config('exportToken'),
+ 'import-token': env.parse('import_token') || config('importToken'),
+ 'export-token': env.parse('export_token') || config('exportToken'),
'dropbox': config('dropbox'),
'dropbox-token': config('dropboxToken') || '',
@@ -238,7 +238,7 @@ async function main() {
menu: config('menu'),
};
- const password = env('password') || args.password;
+ const password = env.parse('password') || args.password;
if (password)
config('password', await getPassword(password));
diff --git a/bin/release.mjs b/bin/release.mjs
index 694eb7da..004b908e 100755
--- a/bin/release.mjs
+++ b/bin/release.mjs
@@ -2,7 +2,7 @@
import {promisify} from 'node:util';
import process from 'node:process';
-import tryToCatch from 'try-to-catch';
+import {tryToCatch} from 'try-to-catch';
import {createSimport} from 'simport';
import minor from 'minor';
import _place from 'place';
diff --git a/client/client.js b/client/client.mjs
similarity index 92%
rename from client/client.js
rename to client/client.mjs
index 5c547deb..b6c3a436 100644
--- a/client/client.js
+++ b/client/client.mjs
@@ -1,30 +1,24 @@
-'use strict';
-
-const process = require('node:process');
+import process from 'node:process';
/* global DOM */
-const Emitify = require('emitify');
-const inherits = require('inherits');
-const rendy = require('rendy');
-const load = require('load.js');
-const tryToCatch = require('try-to-catch');
-const {addSlashToEnd} = require('format-io');
-const pascalCase = require('just-pascal-case');
-const currify = require('currify');
-
-const Images = require('./dom/images');
-
-const {unregisterSW} = require('./sw/register');
-const getJsonFromFileTable = require('./get-json-from-file-table');
-const Key = require('./key');
-
-const {
+import Emitify from 'emitify';
+import inherits from 'inherits';
+import rendy from 'rendy';
+import load from 'load.js';
+import {tryToCatch} from 'try-to-catch';
+import {addSlashToEnd} from 'format-io';
+import pascalCase from 'just-pascal-case';
+import currify from 'currify';
+import * as Images from './dom/images.mjs';
+import {unregisterSW} from './sw/register.js';
+import {getJsonFromFileTable} from './get-json-from-file-table.mjs';
+import {Key} from './key/index.mjs';
+import {
apiURL,
formatMsg,
buildFromJSON,
-} = require('../common/cloudfunc');
-
-const loadModule = require('./load-module');
+} from '../common/cloudfunc.mjs';
+import {loadModule} from './load-module.mjs';
const noJS = (a) => a.replace(/.js$/, '');
@@ -32,16 +26,19 @@ const isDev = process.env.NODE_ENV === 'development';
inherits(CloudCmdProto, Emitify);
-module.exports = new CloudCmdProto(DOM);
+export const createCloudCmd = ({DOM, Listeners}) => {
+ return new CloudCmdProto({
+ DOM,
+ Listeners,
+ });
+};
load.addErrorListener((e, src) => {
const msg = `file ${src} could not be loaded`;
Images.show.error(msg);
});
-function CloudCmdProto(DOM) {
- let Listeners;
-
+function CloudCmdProto({DOM, Listeners}) {
Emitify.call(this);
const CloudCmd = this;
@@ -49,11 +46,9 @@ function CloudCmdProto(DOM) {
const {Storage, Files} = DOM;
- this.log = (...a) => {
+ this.log = () => {
if (!isDev)
return;
-
- console.log(...a);
};
this.prefix = '';
this.prefixSocket = '';
@@ -151,7 +146,7 @@ function CloudCmdProto(DOM) {
const [kebabModule] = query;
const module = noJS(pascalCase(kebabModule.slice(1)));
- const file = query[1];
+ const [, file] = query;
const current = DOM.getCurrentByName(file);
if (file && !current) {
@@ -230,7 +225,6 @@ function CloudCmdProto(DOM) {
const dirPath = DOM.getCurrentDirPath();
- ({Listeners} = CloudCmd);
Listeners.init();
const panels = getPanels();
diff --git a/client/cloudcmd.js b/client/cloudcmd.mjs
similarity index 50%
rename from client/cloudcmd.js
rename to client/cloudcmd.mjs
index d4bac384..0dac1a03 100644
--- a/client/cloudcmd.js
+++ b/client/cloudcmd.mjs
@@ -1,39 +1,44 @@
-'use strict';
-
-const process = require('node:process');
-require('../css/main.css');
-
-const wraptile = require('wraptile');
-const load = require('load.js');
-
-const {registerSW, listenSW} = require('./sw/register');
+import process from 'node:process';
+import wraptile from 'wraptile';
+import load from 'load.js';
+import '../css/main.css';
+import {registerSW, listenSW} from './sw/register.js';
+import {initSortPanel, sortPanel} from './sort.mjs';
+import Util from '../common/util.js';
+import * as CloudFunc from '../common/cloudfunc.mjs';
+import DOM from './dom/index.js';
+import {createCloudCmd} from './client.mjs';
+import * as Listeners from './listeners/index.js';
const isDev = process.env.NODE_ENV === 'development';
-module.exports = async (config) => {
- window.Util = require('../common/util');
- window.CloudFunc = require('../common/cloudfunc');
-
- window.DOM = require('./dom');
- window.CloudCmd = require('./client');
+export default init;
+
+globalThis.CloudCmd = init;
+
+async function init(config) {
+ globalThis.CloudCmd = createCloudCmd({
+ DOM,
+ Listeners,
+ });
+ globalThis.DOM = DOM;
+ globalThis.Util = Util;
+ globalThis.CloudFunc = CloudFunc;
await register(config);
- require('./listeners');
- require('./key');
- require('./sort');
-
+ initSortPanel();
+ globalThis.CloudCmd.sortPanel = sortPanel;
const prefix = getPrefix(config.prefix);
- window.CloudCmd.init(prefix, config);
+ globalThis.CloudCmd.init(prefix, config);
- if (window.CloudCmd.config('menu') === 'aleman')
+ if (globalThis.CloudCmd.config('menu') === 'aleman')
setTimeout(() => {
import('https://esm.sh/@putout/processor-html');
import('https://esm.sh/@putout/bundle');
}, 100);
-};
-window.CloudCmd = module.exports;
+}
function getPrefix(prefix) {
if (!prefix)
@@ -49,7 +54,7 @@ const onUpdateFound = wraptile(async (config) => {
if (isDev)
return;
- const {DOM} = window;
+ const {DOM} = globalThis;
const prefix = getPrefix(config.prefix);
await load.js(`${prefix}/dist/cloudcmd.common.js`);
@@ -58,7 +63,7 @@ const onUpdateFound = wraptile(async (config) => {
console.log('cloudcmd: sw: updated');
DOM.Events.removeAll();
- window.CloudCmd(config);
+ globalThis.CloudCmd(config);
});
async function register(config) {
diff --git a/client/dom/buffer.js b/client/dom/buffer.js
deleted file mode 100644
index afa78dd7..00000000
--- a/client/dom/buffer.js
+++ /dev/null
@@ -1,135 +0,0 @@
-'use strict';
-
-/* global CloudCmd */
-const tryToPromiseAll = require('../../common/try-to-promise-all');
-const Storage = require('./storage');
-const DOM = require('./');
-
-module.exports = new BufferProto();
-
-function BufferProto() {
- const Info = DOM.CurrentInfo;
- const CLASS = 'cut-file';
- const COPY = 'copy';
- const CUT = 'cut';
-
- const Buffer = {
- cut: callIfEnabled.bind(null, cut),
- copy: callIfEnabled.bind(null, copy),
- clear: callIfEnabled.bind(null, clear),
- paste: callIfEnabled.bind(null, paste),
- };
-
- function showMessage(msg) {
- DOM.Dialog.alert(msg);
- }
-
- function getNames() {
- const files = DOM.getActiveFiles();
-
- return DOM.getFilenames(files);
- }
-
- function addCutClass() {
- const files = DOM.getActiveFiles();
-
- for (const element of files) {
- element.classList.add(CLASS);
- }
- }
-
- function rmCutClass() {
- const files = DOM.getByClassAll(CLASS);
-
- for (const element of files) {
- element.classList.remove(CLASS);
- }
- }
-
- function callIfEnabled(callback) {
- const is = CloudCmd.config('buffer');
-
- if (is)
- return callback();
-
- showMessage('Buffer disabled in config!');
- }
-
- async function readBuffer() {
- const [e, cp, ct] = await tryToPromiseAll([
- Storage.getJson(COPY),
- Storage.getJson(CUT),
- ]);
-
- return [
- e,
- cp,
- ct,
- ];
- }
-
- async function copy() {
- const names = getNames();
- const from = Info.dirPath;
-
- await clear();
-
- if (!names.length)
- return;
-
- await Storage.remove(CUT);
- await Storage.setJson(COPY, {
- from,
- names,
- });
- }
-
- async function cut() {
- const names = getNames();
- const from = Info.dirPath;
-
- await clear();
-
- if (!names.length)
- return;
-
- addCutClass();
-
- await Storage.setJson(CUT, {
- from,
- names,
- });
- }
-
- async function clear() {
- await Storage.remove(COPY);
- await Storage.remove(CUT);
-
- rmCutClass();
- }
-
- async function paste() {
- const [error, cp, ct] = await readBuffer();
-
- if (error || !cp && !ct)
- return showMessage(error || 'Buffer is empty!');
-
- const opStr = cp ? 'copy' : 'move';
- const data = cp || ct;
- const {Operation} = CloudCmd;
- const msg = 'Path is same!';
- const to = Info.dirPath;
-
- if (data.from === to)
- return showMessage(msg);
-
- Operation.show(opStr, {
- ...data,
- to,
- });
-
- await clear();
- }
-
- return Buffer;
-}
diff --git a/client/dom/buffer.mjs b/client/dom/buffer.mjs
new file mode 100644
index 00000000..01e8142a
--- /dev/null
+++ b/client/dom/buffer.mjs
@@ -0,0 +1,124 @@
+/* global CloudCmd*/
+import tryToPromiseAll from '../../common/try-to-promise-all.js';
+import Storage from './storage.js';
+
+const CLASS = 'cut-file';
+const COPY = 'copy';
+const CUT = 'cut';
+
+function showMessage(msg) {
+ globalThis.DOM.Dialog.alert(msg);
+}
+
+function getNames() {
+ const {DOM} = globalThis;
+ const files = DOM.getActiveFiles();
+
+ return DOM.getFilenames(files);
+}
+
+function addCutClass() {
+ const {DOM} = globalThis;
+ const files = DOM.getActiveFiles();
+
+ for (const element of files) {
+ element.classList.add(CLASS);
+ }
+}
+
+function rmCutClass() {
+ const {DOM} = globalThis;
+ const files = DOM.getByClassAll(CLASS);
+
+ for (const element of files) {
+ element.classList.remove(CLASS);
+ }
+}
+
+const checkEnabled = (fn) => () => {
+ const is = CloudCmd.config('buffer');
+
+ if (is)
+ return fn();
+
+ showMessage('Buffer disabled in config!');
+};
+
+async function readBuffer() {
+ const [e, cp, ct] = await tryToPromiseAll([
+ Storage.getJson(COPY),
+ Storage.getJson(CUT),
+ ]);
+
+ return [
+ e,
+ cp,
+ ct,
+ ];
+}
+
+export const copy = checkEnabled(async () => {
+ const Info = globalThis.DOM.CurrentInfo;
+ const names = getNames();
+ const from = Info.dirPath;
+
+ await clear();
+
+ if (!names.length)
+ return;
+
+ await Storage.remove(CUT);
+ await Storage.setJson(COPY, {
+ from,
+ names,
+ });
+});
+
+export const cut = checkEnabled(async () => {
+ const Info = globalThis.DOM.CurrentInfo;
+ const names = getNames();
+ const from = Info.dirPath;
+
+ await clear();
+
+ if (!names.length)
+ return;
+
+ addCutClass();
+
+ await Storage.setJson(CUT, {
+ from,
+ names,
+ });
+});
+
+export const clear = checkEnabled(async () => {
+ await Storage.remove(COPY);
+ await Storage.remove(CUT);
+
+ rmCutClass();
+});
+
+export const paste = checkEnabled(async () => {
+ const Info = globalThis.DOM.CurrentInfo;
+ const [error, cp, ct] = await readBuffer();
+
+ if (error || !cp && !ct)
+ return showMessage(error || 'Buffer is empty!');
+
+ const opStr = cp ? 'copy' : 'move';
+ const data = cp || ct;
+ const {Operation} = CloudCmd;
+ const msg = 'Path is same!';
+ const to = Info.dirPath;
+
+ if (data.from === to)
+ return showMessage(msg);
+
+ Operation.show(opStr, {
+ ...data,
+ to,
+ });
+
+ await clear();
+});
diff --git a/client/dom/current-file.js b/client/dom/current-file.mjs
similarity index 83%
rename from client/dom/current-file.js
rename to client/dom/current-file.mjs
index 1150de2a..e55acbe9 100644
--- a/client/dom/current-file.js
+++ b/client/dom/current-file.mjs
@@ -1,13 +1,8 @@
-'use strict';
-
/* global DOM */
/* global CloudCmd */
-const createElement = require('@cloudcmd/create-element');
-const {atob, btoa} = require('../../common/base64');
-
-const {encode, decode} = require('../../common/entity');
-
-const {getTitle, FS} = require('../../common/cloudfunc');
+import createElement from '@cloudcmd/create-element';
+import {encode, decode} from '../../common/entity.js';
+import {getTitle, FS} from '../../common/cloudfunc.mjs';
let Title;
@@ -15,14 +10,15 @@ const CURRENT_FILE = 'current-file';
const encodeNBSP = (a) => a?.replace('\xa0', ' ');
const decodeNBSP = (a) => a?.replace(' ', '\xa0');
-module.exports._CURRENT_FILE = CURRENT_FILE;
+export const _CURRENT_FILE = CURRENT_FILE;
+
/**
* set name from current (or param) file
*
* @param name
* @param current
*/
-module.exports.setCurrentName = (name, current) => {
+export const setCurrentName = (name, current) => {
const Info = DOM.CurrentInfo;
const {link} = Info;
const {prefix} = CloudCmd;
@@ -44,7 +40,7 @@ module.exports.setCurrentName = (name, current) => {
*
* @param currentFile
*/
-module.exports.getCurrentName = (currentFile) => {
+export const getCurrentName = (currentFile) => {
const current = currentFile || DOM.getCurrentFile();
if (!current)
@@ -71,18 +67,19 @@ const parseNameAttribute = (attribute) => {
return decodeNBSP(decodeURI(atob(attribute)));
};
-module.exports._parseNameAttribute = parseNameAttribute;
+export const _parseNameAttribute = parseNameAttribute;
const parseHrefAttribute = (prefix, attribute) => {
attribute = attribute.replace(RegExp('^' + prefix + FS), '');
return decode(decodeNBSP(attribute));
};
-module.exports._parseHrefAttribute = parseHrefAttribute;
+export const _parseHrefAttribute = parseHrefAttribute;
+
/**
* get current direcotory path
*/
-module.exports.getCurrentDirPath = (panel = DOM.getPanel()) => {
+export const getCurrentDirPath = (panel = DOM.getPanel()) => {
const path = DOM.getByDataName('js-path', panel);
return path.textContent;
};
@@ -92,7 +89,7 @@ module.exports.getCurrentDirPath = (panel = DOM.getPanel()) => {
*
* @param currentFile - current file by default
*/
-module.exports.getCurrentPath = (currentFile) => {
+export const getCurrentPath = (currentFile) => {
const current = currentFile || DOM.getCurrentFile();
const [element] = DOM.getByTag('a', current);
const {prefix} = CloudCmd;
@@ -103,7 +100,7 @@ module.exports.getCurrentPath = (currentFile) => {
/**
* get current direcotory name
*/
-module.exports.getCurrentDirName = () => {
+export const getCurrentDirName = () => {
const href = DOM
.getCurrentDirPath()
.replace(/\/$/, '');
@@ -116,7 +113,7 @@ module.exports.getCurrentDirName = () => {
/**
* get current direcotory path
*/
-module.exports.getParentDirPath = (panel) => {
+export const getParentDirPath = (panel) => {
const path = DOM.getCurrentDirPath(panel);
const dirName = DOM.getCurrentDirName() + '/';
const index = path.lastIndexOf(dirName);
@@ -130,7 +127,7 @@ module.exports.getParentDirPath = (panel) => {
/**
* get not current direcotory path
*/
-module.exports.getNotCurrentDirPath = () => {
+export const getNotCurrentDirPath = () => {
const panel = DOM.getPanel({
active: false,
});
@@ -143,14 +140,14 @@ module.exports.getNotCurrentDirPath = () => {
*
* @currentFile
*/
-module.exports.getCurrentFile = () => {
+export const getCurrentFile = () => {
return DOM.getByClass(CURRENT_FILE);
};
/**
* get current file by name
*/
-module.exports.getCurrentByName = (name, panel = DOM.CurrentInfo.panel) => {
+export const getCurrentByName = (name, panel = DOM.CurrentInfo.panel) => {
const dataName = 'js-file-' + btoa(encodeURI(encodeNBSP(name)));
return DOM.getByDataName(dataName, panel);
};
@@ -172,7 +169,7 @@ function unsetCurrentFile(currentFile) {
/**
* unified way to set current file
*/
-module.exports.setCurrentFile = (currentFile, options) => {
+export const setCurrentFile = (currentFile, options) => {
const o = options;
const currentFileWas = DOM.getCurrentFile();
@@ -219,7 +216,7 @@ module.exports.setCurrentFile = (currentFile, options) => {
return DOM;
};
-this.setCurrentByName = (name) => {
+export const setCurrentByName = (name) => {
const current = DOM.getCurrentByName(name);
return DOM.setCurrentFile(current);
};
@@ -230,7 +227,7 @@ this.setCurrentByName = (name) => {
* @param layer - element
* @param - position {x, y}
*/
-module.exports.getCurrentByPosition = ({x, y}) => {
+export const getCurrentByPosition = ({x, y}) => {
const element = document.elementFromPoint(x, y);
const getEl = (el) => {
@@ -262,7 +259,7 @@ module.exports.getCurrentByPosition = ({x, y}) => {
*
* @param currentFile
*/
-module.exports.isCurrentFile = (currentFile) => {
+export const isCurrentFile = (currentFile) => {
if (!currentFile)
return false;
@@ -274,7 +271,7 @@ module.exports.isCurrentFile = (currentFile) => {
*
* @param name
*/
-module.exports.setTitle = (name) => {
+export const setTitle = (name) => {
if (!Title)
Title = DOM.getByTag('title')[0] || createElement('title', {
innerHTML: name,
@@ -291,18 +288,18 @@ module.exports.setTitle = (name) => {
*
* @param currentFile
*/
-module.exports.isCurrentIsDir = (currentFile) => {
+export const isCurrentIsDir = (currentFile) => {
const current = currentFile || DOM.getCurrentFile();
const path = DOM.getCurrentPath(current);
const fileType = DOM.getCurrentType(current);
- const isZip = /\.zip$/.test(path);
+ const isZip = path.endsWith('.zip');
const isDir = /^directory(-link)?/.test(fileType);
return isDir || isZip;
};
-module.exports.getCurrentType = (currentFile) => {
+export const getCurrentType = (currentFile) => {
const current = currentFile || DOM.getCurrentFile();
const el = DOM.getByDataName('js-type', current);
const type = el.className
diff --git a/client/dom/current-file.spec.js b/client/dom/current-file.spec.mjs
similarity index 68%
rename from client/dom/current-file.spec.js
rename to client/dom/current-file.spec.mjs
index de1ba2af..2a576dce 100644
--- a/client/dom/current-file.spec.js
+++ b/client/dom/current-file.spec.mjs
@@ -1,20 +1,18 @@
-'use strict';
+import {test, stub} from 'supertape';
+import {create} from 'auto-globals';
+import wraptile from 'wraptile';
+import * as currentFile from './current-file.mjs';
-const {test, stub} = require('supertape');
-
-const {create} = require('auto-globals');
-const wraptile = require('wraptile');
-const currentFile = require('./current-file');
const id = (a) => a;
const returns = wraptile(id);
const {_CURRENT_FILE} = currentFile;
test('current-file: setCurrentName: setAttribute', (t) => {
- const {DOM, CloudCmd} = global;
+ const {DOM, CloudCmd} = globalThis;
- global.DOM = getDOM();
- global.CloudCmd = getCloudCmd();
+ globalThis.DOM = getDOM();
+ globalThis.CloudCmd = getCloudCmd();
const current = create();
const {setAttribute} = current;
@@ -23,17 +21,17 @@ test('current-file: setCurrentName: setAttribute', (t) => {
t.calledWith(setAttribute, ['data-name', 'js-file-aGVsbG8='], 'should call setAttribute');
- global.DOM = DOM;
- global.CloudCmd = CloudCmd;
+ globalThis.DOM = DOM;
+ globalThis.CloudCmd = CloudCmd;
t.end();
});
test('current-file: setCurrentName: setAttribute: cyrillic', (t) => {
- const {DOM, CloudCmd} = global;
+ const {DOM, CloudCmd} = globalThis;
- global.DOM = getDOM();
- global.CloudCmd = getCloudCmd();
+ globalThis.DOM = getDOM();
+ globalThis.CloudCmd = getCloudCmd();
const current = create();
const {setAttribute} = current;
@@ -42,8 +40,8 @@ test('current-file: setCurrentName: setAttribute: cyrillic', (t) => {
t.calledWith(setAttribute, ['data-name', 'js-file-JUQwJUIwJUQwJUI5'], 'should call setAttribute');
- global.DOM = DOM;
- global.CloudCmd = CloudCmd;
+ globalThis.DOM = DOM;
+ globalThis.CloudCmd = CloudCmd;
t.end();
});
@@ -59,12 +57,12 @@ test('current-file: getCurrentName', (t) => {
});
test('current-file: emit', (t) => {
- const {DOM, CloudCmd} = global;
+ const {DOM, CloudCmd} = globalThis;
const emit = stub();
- global.DOM = getDOM();
- global.CloudCmd = getCloudCmd({
+ globalThis.DOM = getDOM();
+ globalThis.CloudCmd = getCloudCmd({
emit,
});
@@ -74,22 +72,22 @@ test('current-file: emit', (t) => {
t.calledWith(emit, ['current-file', current], 'should call emit');
- global.DOM = DOM;
- global.CloudCmd = CloudCmd;
+ globalThis.DOM = DOM;
+ globalThis.CloudCmd = CloudCmd;
t.end();
});
test('current-file: setCurrentName: return', (t) => {
- const {DOM, CloudCmd} = global;
+ const {DOM, CloudCmd} = globalThis;
const link = {};
- global.DOM = getDOM({
+ globalThis.DOM = getDOM({
link,
});
- global.CloudCmd = getCloudCmd();
+ globalThis.CloudCmd = getCloudCmd();
const current = create();
@@ -97,19 +95,19 @@ test('current-file: setCurrentName: return', (t) => {
t.equal(result, link, 'should return link');
- global.DOM = DOM;
- global.CloudCmd = CloudCmd;
+ globalThis.DOM = DOM;
+ globalThis.CloudCmd = CloudCmd;
t.end();
});
test('current-file: getParentDirPath: result', (t) => {
- const {DOM} = global;
+ const {DOM} = globalThis;
const getCurrentDirPath = returns('/D/Films/+++favorite films/');
const getCurrentDirName = returns('+++favorite films');
- global.DOM = getDOM({
+ globalThis.DOM = getDOM({
getCurrentDirPath,
getCurrentDirName,
});
@@ -117,55 +115,55 @@ test('current-file: getParentDirPath: result', (t) => {
const result = currentFile.getParentDirPath();
const expected = '/D/Films/';
- global.DOM = DOM;
+ globalThis.DOM = DOM;
t.equal(result, expected, 'should return parent dir path');
t.end();
});
test('current-file: isCurrentFile: no', (t) => {
- const {DOM, CloudCmd} = global;
+ const {DOM, CloudCmd} = globalThis;
- global.DOM = getDOM();
- global.CloudCmd = getCloudCmd();
+ globalThis.DOM = getDOM();
+ globalThis.CloudCmd = getCloudCmd();
const result = currentFile.isCurrentFile();
- global.DOM = DOM;
- global.CloudCmd = CloudCmd;
+ globalThis.DOM = DOM;
+ globalThis.CloudCmd = CloudCmd;
t.notOk(result);
t.end();
});
test('current-file: isCurrentFile', (t) => {
- const {DOM, CloudCmd} = global;
+ const {DOM, CloudCmd} = globalThis;
const isContainClass = stub();
- global.DOM = getDOM({
+ globalThis.DOM = getDOM({
isContainClass,
});
- global.CloudCmd = getCloudCmd();
+ globalThis.CloudCmd = getCloudCmd();
const current = {};
currentFile.isCurrentFile(current);
- global.DOM = DOM;
- global.CloudCmd = CloudCmd;
+ globalThis.DOM = DOM;
+ globalThis.CloudCmd = CloudCmd;
t.calledWith(isContainClass, [current, _CURRENT_FILE], 'should call isContainClass');
t.end();
});
test('current-file: getCurrentType', (t) => {
- const {DOM, CloudCmd} = global;
+ const {DOM, CloudCmd} = globalThis;
- global.DOM = getDOM();
- global.CloudCmd = getCloudCmd();
+ globalThis.DOM = getDOM();
+ globalThis.CloudCmd = getCloudCmd();
- const {getByDataName} = global.DOM;
+ const {getByDataName} = globalThis.DOM;
getByDataName.returns({
className: 'mini-icon directory',
@@ -175,87 +173,87 @@ test('current-file: getCurrentType', (t) => {
currentFile.getCurrentType(current);
- global.DOM = DOM;
- global.CloudCmd = CloudCmd;
+ globalThis.DOM = DOM;
+ globalThis.CloudCmd = CloudCmd;
t.calledWith(getByDataName, ['js-type', current]);
t.end();
});
test('current-file: isCurrentIsDir: getCurrentType', (t) => {
- const {DOM, CloudCmd} = global;
+ const {DOM, CloudCmd} = globalThis;
- global.DOM = getDOM();
- global.CloudCmd = getCloudCmd();
+ globalThis.DOM = getDOM();
+ globalThis.CloudCmd = getCloudCmd();
- const {getCurrentType} = global.DOM;
+ const {getCurrentType} = globalThis.DOM;
const current = create();
currentFile.isCurrentIsDir(current);
- global.DOM = DOM;
- global.CloudCmd = CloudCmd;
+ globalThis.DOM = DOM;
+ globalThis.CloudCmd = CloudCmd;
t.calledWith(getCurrentType, [current]);
t.end();
});
test('current-file: isCurrentIsDir: directory', (t) => {
- const {DOM, CloudCmd} = global;
+ const {DOM, CloudCmd} = globalThis;
- global.DOM = getDOM({
+ globalThis.DOM = getDOM({
getCurrentType: stub().returns('directory'),
});
- global.CloudCmd = getCloudCmd();
+ globalThis.CloudCmd = getCloudCmd();
const current = create();
const result = currentFile.isCurrentIsDir(current);
- global.DOM = DOM;
- global.CloudCmd = CloudCmd;
+ globalThis.DOM = DOM;
+ globalThis.CloudCmd = CloudCmd;
t.ok(result);
t.end();
});
test('current-file: isCurrentIsDir: directory-link', (t) => {
- const {DOM, CloudCmd} = global;
+ const {DOM, CloudCmd} = globalThis;
- global.DOM = getDOM({
+ globalThis.DOM = getDOM({
getCurrentType: stub().returns('directory-link'),
});
- global.CloudCmd = getCloudCmd();
+ globalThis.CloudCmd = getCloudCmd();
const current = create();
const result = currentFile.isCurrentIsDir(current);
- global.DOM = DOM;
- global.CloudCmd = CloudCmd;
+ globalThis.DOM = DOM;
+ globalThis.CloudCmd = CloudCmd;
t.ok(result);
t.end();
});
test('current-file: isCurrentIsDir: file', (t) => {
- const {DOM, CloudCmd} = global;
+ const {DOM, CloudCmd} = globalThis;
- global.DOM = getDOM({
+ globalThis.DOM = getDOM({
getCurrentType: stub().returns('file'),
});
- global.CloudCmd = getCloudCmd();
+ globalThis.CloudCmd = getCloudCmd();
const current = create();
const result = currentFile.isCurrentIsDir(current);
- global.DOM = DOM;
- global.CloudCmd = CloudCmd;
+ globalThis.DOM = DOM;
+ globalThis.CloudCmd = CloudCmd;
t.notOk(result);
t.end();
@@ -291,7 +289,7 @@ function getDOM(overrides = {}) {
getByDataName = stub(),
isContainClass = stub(),
getCurrentType = stub(),
- getCurrentPath = stub(),
+ getCurrentPath = stub().returns(''),
} = overrides;
return {
diff --git a/client/dom/dialog.js b/client/dom/dialog.js
index f4751456..eb342221 100644
--- a/client/dom/dialog.js
+++ b/client/dom/dialog.js
@@ -1,6 +1,6 @@
'use strict';
-const tryToCatch = require('try-to-catch');
+const {tryToCatch} = require('try-to-catch');
const {
alert,
diff --git a/client/dom/directory.js b/client/dom/directory.js
index c7cfa386..bedb7e95 100644
--- a/client/dom/directory.js
+++ b/client/dom/directory.js
@@ -3,8 +3,8 @@
/* global CloudCmd */
const philip = require('philip');
-const Images = require('./images');
-const {FS} = require('../../common/cloudfunc');
+const Images = require('./images.mjs');
+const {FS} = require('../../common/cloudfunc.mjs');
const DOM = require('.');
const Dialog = require('./dialog');
diff --git a/client/dom/dom-tree.spec.js b/client/dom/dom-tree.spec.js
index 044e97b0..606df179 100644
--- a/client/dom/dom-tree.spec.js
+++ b/client/dom/dom-tree.spec.js
@@ -2,7 +2,7 @@
const test = require('supertape');
const {create} = require('auto-globals');
-const tryCatch = require('try-catch');
+const {tryCatch} = require('try-catch');
const {isContainClass} = require('./dom-tree');
diff --git a/client/dom/events/index.js b/client/dom/events/index.js
deleted file mode 100644
index 22e9261e..00000000
--- a/client/dom/events/index.js
+++ /dev/null
@@ -1,198 +0,0 @@
-'use strict';
-
-const itype = require('itype');
-const EventStore = require('./event-store');
-
-module.exports = new EventsProto();
-
-function EventsProto() {
- const Events = this;
-
- const getEventOptions = (eventName) => {
- if (eventName !== 'touchstart')
- return false;
-
- return {
- passive: true,
- };
- };
-
- function parseArgs(eventName, element, listener, callback) {
- let isFunc;
- const args = [
- eventName,
- element,
- listener,
- callback,
- ];
-
- const EVENT_NAME = 1;
- const ELEMENT = 0;
- const type = itype(eventName);
-
- switch(type) {
- default:
- if (!type.endsWith('element'))
- throw Error(`unknown eventName: ${type}`);
-
- parseArgs(args[EVENT_NAME], args[ELEMENT], listener, callback);
- break;
-
- case 'string':
- isFunc = itype.function(element);
-
- if (isFunc) {
- listener = element;
- element = null;
- }
-
- if (!element)
- element = window;
-
- callback(element, [
- eventName,
- listener,
- getEventOptions(eventName),
- ]);
- break;
-
- case 'array':
-
- for (const name of eventName) {
- parseArgs(name, element, listener, callback);
- }
-
- break;
-
- case 'object':
-
- for (const name of Object.keys(eventName)) {
- const eventListener = eventName[name];
-
- parseArgs(name, element, eventListener, callback);
- }
-
- break;
- }
- }
-
- /**
- * safe add event listener
- *
- * @param type
- * @param element - document by default
- * @param listener
- */
- this.add = (type, element, listener) => {
- checkType(type);
-
- parseArgs(type, element, listener, (element, args) => {
- const [name, fn, options] = args;
-
- element.addEventListener(name, fn, options);
- EventStore.add(element, name, fn);
- });
-
- return Events;
- };
-
- /**
- * safe add event listener
- *
- * @param type
- * @param listener
- * @param element - document by default
- */
- this.addOnce = (type, element, listener) => {
- const once = (event) => {
- Events.remove(type, element, once);
- listener(event);
- };
-
- if (!listener) {
- listener = element;
- element = null;
- }
-
- this.add(type, element, once);
-
- return Events;
- };
-
- /**
- * safe remove event listener
- *
- * @param type
- * @param listener
- * @param element - document by default
- */
- this.remove = (type, element, listener) => {
- checkType(type);
-
- parseArgs(type, element, listener, (element, args) => {
- element.removeEventListener(...args);
- });
-
- return Events;
- };
-
- /**
- * remove all added event listeners
- */
- this.removeAll = () => {
- const events = EventStore.get();
-
- for (const [el, name, fn] of events)
- el.removeEventListener(name, fn);
-
- EventStore.clear();
- };
-
- /**
- * safe add event keydown listener
- *
- * @param args
- */
- this.addKey = function(...args) {
- return Events.add('keydown', ...args);
- };
-
- /**
- * safe remove event click listener
- *
- * @param args
- */
- this.rmKey = function(...args) {
- return Events.remove('keydown', ...args);
- };
-
- /**
- * safe add event click listener
- */
- this.addClick = function(...args) {
- return Events.add('click', ...args);
- };
-
- /**
- * safe remove event click listener
- */
- this.rmClick = function(...args) {
- return Events.remove('click', ...args);
- };
-
- this.addContextMenu = function(...args) {
- return Events.add('contextmenu', ...args);
- };
-
- /**
- * safe add load listener
- */
- this.addLoad = function(...args) {
- return Events.add('load', ...args);
- };
-
- function checkType(type) {
- if (!type)
- throw Error('type could not be empty!');
- }
-}
diff --git a/client/dom/events/index.mjs b/client/dom/events/index.mjs
new file mode 100644
index 00000000..0762d560
--- /dev/null
+++ b/client/dom/events/index.mjs
@@ -0,0 +1,203 @@
+import itype from 'itype';
+import EventStore from './event-store.js';
+
+/**
+ * safe add event listener
+ *
+ * @param type
+ * @param element - document by default
+ * @param listener
+ */
+export const add = (type, element, listener) => {
+ checkType(type);
+
+ parseArgs(type, element, listener, (element, args) => {
+ const [name, fn, options] = args;
+
+ element.addEventListener(name, fn, options);
+ EventStore.add(element, name, fn);
+ });
+
+ return Events;
+};
+
+/**
+ * safe add event listener
+ *
+ * @param type
+ * @param listener
+ * @param element - document by default
+ */
+export const addOnce = (type, element, listener) => {
+ const once = (event) => {
+ Events.remove(type, element, once);
+ listener(event);
+ };
+
+ if (!listener) {
+ listener = element;
+ element = null;
+ }
+
+ add(type, element, once);
+
+ return Events;
+};
+
+/**
+ * safe remove event listener
+ *
+ * @param type
+ * @param listener
+ * @param element - document by default
+ */
+export const remove = (type, element, listener) => {
+ checkType(type);
+
+ parseArgs(type, element, listener, (element, args) => {
+ element.removeEventListener(...args);
+ });
+
+ return Events;
+};
+
+/**
+ * remove all added event listeners
+ */
+export const removeAll = () => {
+ const events = EventStore.get();
+
+ for (const [el, name, fn] of events)
+ el.removeEventListener(name, fn);
+
+ EventStore.clear();
+};
+
+/**
+ * safe add event keydown listener
+ *
+ * @param args
+ */
+export const addKey = function(...args) {
+ return add('keydown', ...args);
+};
+
+/**
+ * safe remove event click listener
+ *
+ * @param args
+ */
+export const rmKey = function(...args) {
+ return Events.remove('keydown', ...args);
+};
+
+/**
+ * safe add event click listener
+ */
+export const addClick = function(...args) {
+ return Events.add('click', ...args);
+};
+
+/**
+ * safe remove event click listener
+ */
+export const rmClick = function(...args) {
+ return remove('click', ...args);
+};
+
+export const addContextMenu = function(...args) {
+ return add('contextmenu', ...args);
+};
+
+/**
+ * safe add load listener
+ */
+export const addLoad = function(...args) {
+ return add('load', ...args);
+};
+
+function checkType(type) {
+ if (!type)
+ throw Error('type could not be empty!');
+}
+
+const getEventOptions = (eventName) => {
+ if (eventName !== 'touchstart')
+ return false;
+
+ return {
+ passive: true,
+ };
+};
+
+function parseArgs(eventName, element, listener, callback) {
+ let isFunc;
+ const args = [
+ eventName,
+ element,
+ listener,
+ callback,
+ ];
+
+ const EVENT_NAME = 1;
+ const ELEMENT = 0;
+ const type = itype(eventName);
+
+ switch(type) {
+ default:
+ if (!type.endsWith('element'))
+ throw Error(`unknown eventName: ${type}`);
+
+ parseArgs(args[EVENT_NAME], args[ELEMENT], listener, callback);
+ break;
+
+ case 'string':
+ isFunc = itype.function(element);
+
+ if (isFunc) {
+ listener = element;
+ element = null;
+ }
+
+ if (!element)
+ element = window;
+
+ callback(element, [
+ eventName,
+ listener,
+ getEventOptions(eventName),
+ ]);
+ break;
+
+ case 'array':
+
+ for (const name of eventName) {
+ parseArgs(name, element, listener, callback);
+ }
+
+ break;
+
+ case 'object':
+
+ for (const name of Object.keys(eventName)) {
+ const eventListener = eventName[name];
+
+ parseArgs(name, element, eventListener, callback);
+ }
+
+ break;
+ }
+}
+
+const Events = {
+ add,
+ addClick,
+ addContextMenu,
+ addKey,
+ addLoad,
+ addOnce,
+ remove,
+ removeAll,
+ rmClick,
+ rmKey,
+};
diff --git a/client/dom/images.js b/client/dom/images.mjs
similarity index 84%
rename from client/dom/images.js
rename to client/dom/images.mjs
index bb5579c1..9682e666 100644
--- a/client/dom/images.js
+++ b/client/dom/images.mjs
@@ -1,10 +1,5 @@
/* global DOM */
-
-'use strict';
-
-const createElement = require('@cloudcmd/create-element');
-
-const Images = module.exports;
+import createElement from '@cloudcmd/create-element';
const LOADING = 'loading';
const HIDDEN = 'hidden';
@@ -12,7 +7,8 @@ const ERROR = 'error';
const getLoadingType = () => isSVG() ? '-svg' : '-gif';
-module.exports.get = getElement;
+export const get = getElement;
+
/**
* check SVG SMIL animation support
*/
@@ -40,7 +36,7 @@ function getElement() {
}
/* Функция создаёт картинку загрузки */
-module.exports.loading = () => {
+export const loading = () => {
const element = getElement();
const {classList} = element;
const loadingImage = LOADING + getLoadingType();
@@ -52,7 +48,7 @@ module.exports.loading = () => {
};
/* Функция создаёт картинку ошибки загрузки */
-module.exports.error = () => {
+export const error = () => {
const element = getElement();
const {classList} = element;
const loadingImage = LOADING + getLoadingType();
@@ -63,14 +59,21 @@ module.exports.error = () => {
return element;
};
-module.exports.show = show;
-module.exports.show.load = show;
-module.exports.show.error = error;
+show.load = show;
+show.error = (text) => {
+ const image = Images.error();
+
+ DOM.show(image);
+ image.title = text;
+
+ return image;
+};
+
/**
* Function shows loading spinner
* position = {top: true};
*/
-function show(position, panel) {
+export function show(position, panel) {
const image = Images.loading();
const parent = image.parentElement;
const refreshButton = DOM.getRefreshButton(panel);
@@ -96,19 +99,10 @@ function show(position, panel) {
return image;
}
-function error(text) {
- const image = Images.error();
-
- DOM.show(image);
- image.title = text;
-
- return image;
-}
-
/**
* hide load image
*/
-module.exports.hide = () => {
+export const hide = () => {
const element = Images.get();
DOM.hide(element);
@@ -116,7 +110,7 @@ module.exports.hide = () => {
return Images;
};
-module.exports.setProgress = (value, title) => {
+export const setProgress = (value, title) => {
const DATA = 'data-progress';
const element = Images.get();
@@ -131,7 +125,7 @@ module.exports.setProgress = (value, title) => {
return Images;
};
-module.exports.clearProgress = () => {
+export const clearProgress = () => {
const DATA = 'data-progress';
const element = Images.get();
@@ -143,3 +137,13 @@ module.exports.clearProgress = () => {
return Images;
};
+
+const Images = {
+ clearProgress,
+ setProgress,
+ show,
+ hide,
+ get,
+ error,
+ loading,
+};
diff --git a/client/dom/index.js b/client/dom/index.js
index bfb4386c..27a1a5c6 100644
--- a/client/dom/index.js
+++ b/client/dom/index.js
@@ -3,12 +3,12 @@
/* global CloudCmd */
const Util = require('../../common/util');
-const Images = require('./images');
+const Images = require('./images.mjs');
const RESTful = require('./rest');
const Storage = require('./storage');
const renameCurrent = require('./operations/rename-current');
-const CurrentFile = require('./current-file');
+const CurrentFile = require('./current-file.mjs');
const DOMTree = require('./dom-tree');
const Cmd = module.exports;
@@ -32,8 +32,8 @@ DOM.CurrentInfo = CurrentInfo;
module.exports = DOM;
DOM.uploadDirectory = require('./directory');
-DOM.Buffer = require('./buffer');
-DOM.Events = require('./events');
+DOM.Buffer = require('./buffer.mjs');
+DOM.Events = require('#dom/events');
const loadRemote = require('./load-remote');
const selectByPattern = require('./select-by-pattern');
@@ -416,7 +416,7 @@ module.exports.shrinkSelection = () => {
* setting history wrapper
*/
module.exports.setHistory = (data, title, url) => {
- const ret = window.history;
+ const ret = globalThis.history;
const {prefix} = CloudCmd;
url = prefix + url;
@@ -554,7 +554,7 @@ module.exports.getPanel = (options) => {
* then always work with passive
* panel
*/
- if (window.innerWidth < CloudCmd.MIN_ONE_PANEL_WIDTH)
+ if (globalThis.innerWidth < CloudCmd.MIN_ONE_PANEL_WIDTH)
panel = DOM.getByDataName('js-left');
if (!panel)
@@ -729,17 +729,19 @@ module.exports.getPackerExt = (type) => {
return '.tar.gz';
};
-module.exports.goToDirectory = async () => {
- const msg = 'Go to directory:';
+module.exports.goToDirectory = async (overrides = {}) => {
const {Dialog} = DOM;
+ const {prompt = Dialog.prompt, changeDir = CloudCmd.changeDir} = overrides;
+
+ const msg = 'Go to directory:';
const {dirPath} = CurrentInfo;
- const [cancel, path = dirPath] = await Dialog.prompt(msg, dirPath);
+ const [cancel, path = dirPath] = await prompt(msg, dirPath);
if (cancel)
return;
- await CloudCmd.changeDir(path);
+ await changeDir(path);
};
module.exports.duplicatePanel = async () => {
diff --git a/client/dom/index.spec.js b/client/dom/index.spec.js
index c5843d11..e3a4b4bc 100644
--- a/client/dom/index.spec.js
+++ b/client/dom/index.spec.js
@@ -3,30 +3,20 @@
require('css-modules-require-hook/preset');
const {test, stub} = require('supertape');
-const mockRequire = require('mock-require');
-const {getCSSVar} = require('./index');
-const {reRequire, stopAll} = mockRequire;
+const {getCSSVar, goToDirectory} = require('./index');
-global.CloudCmd = {};
+globalThis.CloudCmd = {};
test('cloudcmd: client: dom: goToDirectory', async (t) => {
const path = '';
- const {CloudCmd} = global;
const changeDir = stub();
const prompt = stub().returns([null, path]);
- CloudCmd.changeDir = changeDir;
-
- mockRequire('./dialog', {
+ await goToDirectory({
prompt,
+ changeDir,
});
- const {goToDirectory} = reRequire('.');
-
- await goToDirectory();
-
- stopAll();
-
t.calledWith(changeDir, [path]);
t.end();
});
@@ -35,14 +25,14 @@ test('cloudcmd: client: dom: getCSSVar', (t) => {
const body = {};
const getPropertyValue = stub().returns(0);
- global.getComputedStyle = stub().returns({
+ globalThis.getComputedStyle = stub().returns({
getPropertyValue,
});
const result = getCSSVar('hello', {
body,
});
- delete global.getComputedStyle;
+ delete globalThis.getComputedStyle;
t.notOk(result);
t.end();
@@ -52,14 +42,14 @@ test('cloudcmd: client: dom: getCSSVar: 1', (t) => {
const body = {};
const getPropertyValue = stub().returns(1);
- global.getComputedStyle = stub().returns({
+ globalThis.getComputedStyle = stub().returns({
getPropertyValue,
});
const result = getCSSVar('hello', {
body,
});
- delete global.getComputedStyle;
+ delete globalThis.getComputedStyle;
t.ok(result);
t.end();
diff --git a/client/dom/io/index.js b/client/dom/io/index.js
index 577c357a..a17360ae 100644
--- a/client/dom/io/index.js
+++ b/client/dom/io/index.js
@@ -1,14 +1,14 @@
'use strict';
-const {FS} = require('../../../common/cloudfunc');
-const sendRequest = require('./send-request');
+const {FS} = require('../../../common/cloudfunc.mjs');
+const _sendRequest = require('./send-request');
const imgPosition = {
top: true,
};
module.exports.delete = async (url, data) => {
- return await sendRequest({
+ return await _sendRequest({
method: 'DELETE',
url: FS + url,
data,
@@ -19,7 +19,7 @@ module.exports.delete = async (url, data) => {
};
module.exports.patch = async (url, data) => {
- return await sendRequest({
+ return await _sendRequest({
method: 'PATCH',
url: FS + url,
data,
@@ -28,7 +28,7 @@ module.exports.patch = async (url, data) => {
};
module.exports.write = async (url, data) => {
- return await sendRequest({
+ return await _sendRequest({
method: 'PUT',
url: FS + url,
data,
@@ -36,7 +36,11 @@ module.exports.write = async (url, data) => {
});
};
-module.exports.createDirectory = async (url) => {
+module.exports.createDirectory = async (url, overrides = {}) => {
+ const {
+ sendRequest = _sendRequest,
+ } = overrides;
+
return await sendRequest({
method: 'PUT',
url: `${FS}${url}?dir`,
@@ -47,7 +51,7 @@ module.exports.createDirectory = async (url) => {
module.exports.read = async (url, dataType = 'text') => {
const notLog = !url.includes('?');
- return await sendRequest({
+ return await _sendRequest({
method: 'GET',
url: FS + url,
notLog,
@@ -56,7 +60,7 @@ module.exports.read = async (url, dataType = 'text') => {
};
module.exports.copy = async (from, to, names) => {
- return await sendRequest({
+ return await _sendRequest({
method: 'PUT',
url: '/copy',
data: {
@@ -69,7 +73,7 @@ module.exports.copy = async (from, to, names) => {
};
module.exports.pack = async (data) => {
- return await sendRequest({
+ return await _sendRequest({
method: 'PUT',
url: '/pack',
data,
@@ -77,7 +81,7 @@ module.exports.pack = async (data) => {
};
module.exports.extract = async (data) => {
- return await sendRequest({
+ return await _sendRequest({
method: 'PUT',
url: '/extract',
data,
@@ -85,7 +89,7 @@ module.exports.extract = async (data) => {
};
module.exports.move = async (from, to, names) => {
- return await sendRequest({
+ return await _sendRequest({
method: 'PUT',
url: '/move',
data: {
@@ -98,7 +102,7 @@ module.exports.move = async (from, to, names) => {
};
module.exports.rename = async (from, to) => {
- return await sendRequest({
+ return await _sendRequest({
method: 'PUT',
url: '/rename',
data: {
@@ -111,7 +115,7 @@ module.exports.rename = async (from, to) => {
module.exports.Config = {
read: async () => {
- return await sendRequest({
+ return await _sendRequest({
method: 'GET',
url: '/config',
imgPosition,
@@ -120,7 +124,7 @@ module.exports.Config = {
},
write: async (data) => {
- return await sendRequest({
+ return await _sendRequest({
method: 'PATCH',
url: '/config',
data,
@@ -131,7 +135,7 @@ module.exports.Config = {
module.exports.Markdown = {
read: async (url) => {
- return await sendRequest({
+ return await _sendRequest({
method: 'GET',
url: `/markdown${url}`,
imgPosition,
@@ -140,7 +144,7 @@ module.exports.Markdown = {
},
render: async (data) => {
- return await sendRequest({
+ return await _sendRequest({
method: 'PUT',
url: '/markdown',
data,
diff --git a/client/dom/io/index.spec.js b/client/dom/io/index.spec.js
index 2212f91a..19ebe5bd 100644
--- a/client/dom/io/index.spec.js
+++ b/client/dom/io/index.spec.js
@@ -1,18 +1,14 @@
'use strict';
const {test, stub} = require('supertape');
-
-const mockRequire = require('mock-require');
-
-const {reRequire, stopAll} = mockRequire;
+const io = require('.');
test('client: dom: io', (t) => {
const sendRequest = stub();
- mockRequire('./send-request', sendRequest);
- const io = reRequire('.');
-
- io.createDirectory('/hello');
+ io.createDirectory('/hello', {
+ sendRequest,
+ });
const expected = {
imgPosition: {
@@ -22,8 +18,6 @@ test('client: dom: io', (t) => {
url: '/fs/hello?dir',
};
- stopAll();
-
t.calledWith(sendRequest, [expected]);
t.end();
});
diff --git a/client/dom/io/send-request.js b/client/dom/io/send-request.js
index bc52d667..c61544f1 100644
--- a/client/dom/io/send-request.js
+++ b/client/dom/io/send-request.js
@@ -3,7 +3,7 @@
/* global CloudCmd */
const {promisify} = require('es6-promisify');
-const Images = require('../images');
+const Images = require('../images.mjs');
const load = require('../load');
module.exports = promisify((params, callback) => {
diff --git a/client/dom/load-remote.js b/client/dom/load-remote.js
index 84c7e329..b1b798a8 100644
--- a/client/dom/load-remote.js
+++ b/client/dom/load-remote.js
@@ -4,7 +4,7 @@
const rendy = require('rendy');
const itype = require('itype');
const load = require('load.js');
-const tryToCatch = require('try-to-catch');
+const {tryToCatch} = require('try-to-catch');
const {findObjByNameInArr} = require('../../common/util');
diff --git a/client/dom/load.js b/client/dom/load.js
index 03c25d73..d060a92c 100644
--- a/client/dom/load.js
+++ b/client/dom/load.js
@@ -4,7 +4,7 @@ const itype = require('itype');
const jonny = require('jonny');
const Emitify = require('emitify');
const exec = require('execon');
-const Images = require('./images');
+const Images = require('./images.mjs');
module.exports.getIdBySrc = getIdBySrc;
/**
diff --git a/client/dom/operations/rename-current.js b/client/dom/operations/rename-current.js
index 5b2e0ff7..ab658edf 100644
--- a/client/dom/operations/rename-current.js
+++ b/client/dom/operations/rename-current.js
@@ -3,21 +3,29 @@
/* global CloudCmd */
const capitalize = require('just-capitalize');
-const Dialog = require('../dialog');
+const _Dialog = require('../dialog');
const Storage = require('../storage');
const RESTful = require('../rest');
-const {
- isCurrentFile,
- getCurrentName,
- getCurrentFile,
- getCurrentByName,
- getCurrentType,
- getCurrentDirPath,
- setCurrentName,
-} = require('../current-file');
+const _currentFile = require('../current-file.mjs');
-module.exports = async (current) => {
+module.exports = async (current, overrides = {}) => {
+ const {
+ refresh = CloudCmd.refresh,
+ Dialog = _Dialog,
+ currentFile = _currentFile,
+ } = overrides;
+
+ const {
+ isCurrentFile,
+ getCurrentName,
+ getCurrentFile,
+ getCurrentByName,
+ getCurrentType,
+ getCurrentDirPath,
+ setCurrentName,
+ } = currentFile;
+
if (!isCurrentFile(current))
current = getCurrentFile();
@@ -58,5 +66,5 @@ module.exports = async (current) => {
setCurrentName(to, current);
Storage.remove(dirPath);
- CloudCmd.refresh();
+ refresh();
};
diff --git a/client/dom/operations/rename-current.spec.js b/client/dom/operations/rename-current.spec.js
index f39ff6bf..4a3c7fec 100644
--- a/client/dom/operations/rename-current.spec.js
+++ b/client/dom/operations/rename-current.spec.js
@@ -2,23 +2,20 @@
const {test, stub} = require('supertape');
-const mockRequire = require('mock-require');
-
-const {reRequire, stopAll} = mockRequire;
+const renameCurrent = require('./rename-current');
test('cloudcmd: client: dom: renameCurrent: isCurrentFile', async (t) => {
const current = {};
const isCurrentFile = stub();
- mockRequire('../dialog', stubDialog());
- mockRequire('../current-file', stubCurrentFile({
+ const currentFile = stubCurrentFile({
isCurrentFile,
- }));
+ });
- const renameCurrent = reRequire('./rename-current');
- await renameCurrent(current);
-
- stopAll();
+ await renameCurrent(current, {
+ Dialog: stubDialog(),
+ currentFile,
+ });
t.calledWith(isCurrentFile, [current], 'should call isCurrentFile');
t.end();
@@ -27,11 +24,6 @@ test('cloudcmd: client: dom: renameCurrent: isCurrentFile', async (t) => {
test('cloudcmd: client: dom: renameCurrent: file exist', async (t) => {
const current = {};
const name = 'hello';
- const {CloudCmd} = global;
-
- global.CloudCmd = {
- refresh: stub(),
- };
const prompt = stub().returns([null, name]);
const confirm = stub().returns([true]);
@@ -39,25 +31,23 @@ test('cloudcmd: client: dom: renameCurrent: file exist', async (t) => {
const getCurrentByName = stub().returns(current);
const getCurrentType = stub().returns('directory');
- mockRequire('../dialog', stubDialog({
+ const Dialog = stubDialog({
confirm,
prompt,
- }));
+ });
- mockRequire('../current-file', stubCurrentFile({
+ const currentFile = stubCurrentFile({
getCurrentByName,
getCurrentType,
- }));
+ });
- const renameCurrent = reRequire('./rename-current');
- await renameCurrent();
+ await renameCurrent(null, {
+ Dialog,
+ currentFile,
+ });
const expected = 'Directory "hello" already exists. Proceed?';
- global.CloudCmd = CloudCmd;
-
- stopAll();
-
t.calledWith(confirm, [expected], 'should call confirm');
t.end();
});
diff --git a/client/dom/rest.js b/client/dom/rest.js
index 9c638446..7596f620 100644
--- a/client/dom/rest.js
+++ b/client/dom/rest.js
@@ -1,10 +1,10 @@
'use strict';
-const tryToCatch = require('try-to-catch');
+const {tryToCatch} = require('try-to-catch');
const {encode} = require('../../common/entity');
-const Images = require('./images');
+const Images = require('./images.mjs');
const IO = require('./io');
const Dialog = require('./dialog');
diff --git a/client/dom/storage.spec.js b/client/dom/storage.spec.js
index abd7258a..0b281ffc 100644
--- a/client/dom/storage.spec.js
+++ b/client/dom/storage.spec.js
@@ -7,58 +7,58 @@ const storage = require('./storage');
const {stringify} = JSON;
test('cloudcmd: client: storage: set', async (t) => {
- const {localStorage} = global;
+ const {localStorage} = globalThis;
const setItem = stub();
- global.localStorage = {
+ globalThis.localStorage = {
setItem,
};
await storage.set('hello', 'world');
- global.localStorage = localStorage;
+ globalThis.localStorage = localStorage;
t.calledWith(setItem, ['hello', 'world'], 'should call setItem');
t.end();
});
test('cloudcmd: client: storage: get', async (t) => {
- const {localStorage} = global;
+ const {localStorage} = globalThis;
const getItem = stub().returns('world');
- global.localStorage = {
+ globalThis.localStorage = {
getItem,
};
const result = await storage.get('hello');
- global.localStorage = localStorage;
+ globalThis.localStorage = localStorage;
t.equal(result, 'world');
t.end();
});
test('cloudcmd: client: storage: getJson', async (t) => {
- const {localStorage} = global;
+ const {localStorage} = globalThis;
const expected = {
hello: 'world',
};
const getItem = stub().returns(stringify(expected));
- global.localStorage = {
+ globalThis.localStorage = {
getItem,
};
const result = await storage.getJson('hello');
- global.localStorage = localStorage;
+ globalThis.localStorage = localStorage;
t.deepEqual(result, expected);
t.end();
});
test('cloudcmd: client: storage: setJson', async (t) => {
- const {localStorage} = global;
+ const {localStorage} = globalThis;
const data = {
hello: 'world',
};
@@ -66,42 +66,42 @@ test('cloudcmd: client: storage: setJson', async (t) => {
const expected = stringify(data);
const setItem = stub();
- global.localStorage = {
+ globalThis.localStorage = {
setItem,
};
await storage.setJson('hello', data);
- global.localStorage = localStorage;
+ globalThis.localStorage = localStorage;
t.calledWith(setItem, ['hello', expected]);
t.end();
});
test('cloudcmd: client: storage: remove', async (t) => {
- const {localStorage} = global;
+ const {localStorage} = globalThis;
const removeItem = stub();
- global.localStorage = {
+ globalThis.localStorage = {
removeItem,
};
await storage.remove('hello');
- global.localStorage = localStorage;
+ globalThis.localStorage = localStorage;
t.calledWith(removeItem, ['hello'], 'should call removeItem');
t.end();
});
test('cloudcmd: client: storage: clear', async (t) => {
- const {localStorage} = global;
+ const {localStorage} = globalThis;
const clear = stub();
- global.localStorage = {
+ globalThis.localStorage = {
clear,
};
await storage.clear();
- global.localStorage = localStorage;
+ globalThis.localStorage = localStorage;
t.calledWithNoArgs(clear, 'should call clear');
t.end();
diff --git a/client/dom/upload-files.js b/client/dom/upload-files.js
index 7ac460ea..a1206282 100644
--- a/client/dom/upload-files.js
+++ b/client/dom/upload-files.js
@@ -5,10 +5,10 @@ const {eachSeries} = require('execon');
const wraptile = require('wraptile');
const load = require('./load');
-const Images = require('./images');
+const Images = require('./images.mjs');
const {alert} = require('./dialog');
-const {FS} = require('../../common/cloudfunc');
+const {FS} = require('../../common/cloudfunc.mjs');
const {getCurrentDirPath: getPathWhenRootEmpty} = require('.');
const loadFile = wraptile(_loadFile);
diff --git a/client/get-json-from-file-table.js b/client/get-json-from-file-table.js
deleted file mode 100644
index e6fbc872..00000000
--- a/client/get-json-from-file-table.js
+++ /dev/null
@@ -1,47 +0,0 @@
-'use strict';
-
-/* global DOM */
-const Info = DOM.CurrentInfo;
-
-/**
- * Функция генерирует JSON из html-таблицы файлов и
- * используеться при первом заходе в корень
- */
-module.exports = () => {
- const path = DOM.getCurrentDirPath();
- const infoFiles = Info.files || [];
-
- const notParent = (current) => {
- const name = DOM.getCurrentName(current);
- return name !== '..';
- };
-
- const parse = (current) => {
- const name = DOM.getCurrentName(current);
- const size = DOM.getCurrentSize(current);
- const owner = DOM.getCurrentOwner(current);
- const mode = DOM.getCurrentMode(current);
- const date = DOM.getCurrentDate(current);
- const type = DOM.getCurrentType(current);
-
- return {
- name,
- size,
- mode,
- owner,
- date,
- type,
- };
- };
-
- const files = infoFiles
- .filter(notParent)
- .map(parse);
-
- const fileTable = {
- path,
- files,
- };
-
- return fileTable;
-};
diff --git a/client/get-json-from-file-table.mjs b/client/get-json-from-file-table.mjs
new file mode 100644
index 00000000..ea90f366
--- /dev/null
+++ b/client/get-json-from-file-table.mjs
@@ -0,0 +1,44 @@
+/* global DOM */
+/**
+ * Функция генерирует JSON из html-таблицы файлов и
+ * используеться при первом заходе в корень
+ */
+export const getJsonFromFileTable = () => {
+ const Info = DOM.CurrentInfo;
+ const path = DOM.getCurrentDirPath();
+ const infoFiles = Info.files || [];
+
+ const files = infoFiles
+ .filter(notParent)
+ .map(parse);
+
+ const fileTable = {
+ path,
+ files,
+ };
+
+ return fileTable;
+};
+
+const notParent = (current) => {
+ const name = DOM.getCurrentName(current);
+ return name !== '..';
+};
+
+const parse = (current) => {
+ const name = DOM.getCurrentName(current);
+ const size = DOM.getCurrentSize(current);
+ const owner = DOM.getCurrentOwner(current);
+ const mode = DOM.getCurrentMode(current);
+ const date = DOM.getCurrentDate(current);
+ const type = DOM.getCurrentType(current);
+
+ return {
+ name,
+ size,
+ mode,
+ owner,
+ date,
+ type,
+ };
+};
diff --git a/client/key/index.js b/client/key/index.mjs
similarity index 92%
rename from client/key/index.js
rename to client/key/index.mjs
index 403e81ff..64fd1bc3 100644
--- a/client/key/index.js
+++ b/client/key/index.mjs
@@ -1,22 +1,17 @@
-'use strict';
-
/* global CloudCmd, DOM */
-const clipboard = require('@cloudcmd/clipboard');
-const fullstore = require('fullstore');
+import clipboard from '@cloudcmd/clipboard';
+import {fullstore} from 'fullstore';
+import * as Events from '#dom/events';
+import * as Buffer from '../dom/buffer.mjs';
+import KEY from './key.js';
+import _vim from './vim/index.js';
+import setCurrentByChar from './set-current-by-char.js';
+import {createBinder} from './binder.js';
-const Buffer = require('../dom/buffer');
-const Events = require('../dom/events');
-const KEY = require('./key');
-
-const vim = require('./vim');
-const setCurrentByChar = require('./set-current-by-char');
-const {createBinder} = require('./binder');
-
-const Info = DOM.CurrentInfo;
const Chars = fullstore();
-const toggleVim = (keyCode) => {
- const {_config, config} = CloudCmd;
+const toggleVim = (keyCode, overrides = {}) => {
+ const {_config, config} = overrides;
if (keyCode === KEY.ESC)
_config('vim', !config('vim'));
@@ -29,13 +24,16 @@ Chars([]);
const {assign} = Object;
const binder = createBinder();
-module.exports = assign(binder, KEY);
-module.exports.bind = () => {
+const bind = () => {
Events.addKey(listener, true);
binder.setBind();
};
-module.exports._listener = listener;
+export const Key = assign(binder, KEY, {
+ bind,
+});
+
+export const _listener = listener;
function getChar(event) {
/*
@@ -55,7 +53,14 @@ function getChar(event) {
return [symbol, char];
}
-async function listener(event) {
+async function listener(event, overrides = {}) {
+ const {
+ config = CloudCmd.config,
+ _config = CloudCmd._config,
+ switchKey = _switchKey,
+ vim = _vim,
+ } = overrides;
+
const {keyCode} = event;
// strange chrome bug calles listener twice
@@ -74,8 +79,12 @@ async function listener(event) {
if (!binder.isBind())
return;
- toggleVim(keyCode);
- const isVim = CloudCmd.config('vim');
+ toggleVim(keyCode, {
+ config,
+ _config,
+ });
+
+ const isVim = config('vim');
if (!isVim && !isNumpad && !alt && !ctrl && !meta && (isBetween || symbol))
return setCurrentByChar(char, Chars);
@@ -112,7 +121,8 @@ function fromCharCode(keyIdentifier) {
return String.fromCharCode(hex);
}
-async function switchKey(event) {
+async function _switchKey(event) {
+ const Info = DOM.CurrentInfo;
let i;
let isSelected;
let prev;
diff --git a/client/key/index.spec.js b/client/key/index.spec.js
index 8ab7a960..d8167079 100644
--- a/client/key/index.spec.js
+++ b/client/key/index.spec.js
@@ -3,27 +3,23 @@
require('css-modules-require-hook/preset');
const autoGlobals = require('auto-globals');
-const mockRequire = require('mock-require');
const supertape = require('supertape');
const {ESC} = require('./key');
+
+const {Key, _listener} = require('./index.mjs');
+
const {getDOM, getCloudCmd} = require('./vim/globals.fixture');
const test = autoGlobals(supertape);
-const {reRequire, stopAll} = mockRequire;
const {stub} = supertape;
-global.DOM = getDOM();
-global.CloudCmd = getCloudCmd();
+globalThis.DOM = getDOM();
+globalThis.CloudCmd = getCloudCmd();
test('cloudcmd: client: key: enable vim', async (t) => {
const vim = stub();
- const {CloudCmd} = global;
- const {config} = CloudCmd;
-
- CloudCmd.config = stub().returns(true);
- CloudCmd._config = stub();
- mockRequire('./vim', vim);
- const {_listener, setBind} = reRequire('.');
+ const config = stub().returns(true);
+ const _config = stub();
const event = {
keyCode: ESC,
@@ -31,11 +27,14 @@ test('cloudcmd: client: key: enable vim', async (t) => {
altKey: false,
};
- setBind();
- await _listener(event);
+ Key.setBind();
- CloudCmd.config = config;
- stopAll();
+ await _listener(event, {
+ vim,
+ config,
+ _config,
+ switchKey: stub(),
+ });
t.calledWith(vim, ['Escape', event]);
t.end();
@@ -43,25 +42,20 @@ test('cloudcmd: client: key: enable vim', async (t) => {
test('cloudcmd: client: key: disable vim', async (t) => {
const _config = stub();
+ const config = stub();
const event = {
keyCode: ESC,
key: 'Escape',
altKey: false,
};
- const {CloudCmd} = global;
- const {config} = CloudCmd;
+ Key.setBind();
+ await _listener(event, {
+ config,
+ _config,
+ switchKey: stub(),
+ });
- global.CloudCmd.config = _config;
- global.CloudCmd._config = _config;
-
- const {_listener, setBind} = reRequire('.');
-
- setBind();
- await _listener(event);
-
- CloudCmd.config = config;
-
- t.calledWith(_config, ['vim']);
+ t.calledWith(_config, ['vim', true]);
t.end();
});
diff --git a/client/key/set-current-by-char.js b/client/key/set-current-by-char.js
index f54881a3..ab9329f3 100644
--- a/client/key/set-current-by-char.js
+++ b/client/key/set-current-by-char.js
@@ -3,9 +3,9 @@
'use strict';
const {escapeRegExp} = require('../../common/util');
-const Info = DOM.CurrentInfo;
module.exports = function setCurrentByChar(char, charStore) {
+ const Info = DOM.CurrentInfo;
let firstByName;
let skipCount = 0;
let setted = false;
diff --git a/client/key/vim/find.js b/client/key/vim/find.js
index 43b3d36a..d8b517c1 100644
--- a/client/key/vim/find.js
+++ b/client/key/vim/find.js
@@ -1,6 +1,6 @@
'use strict';
-const fullstore = require('fullstore');
+const {fullstore} = require('fullstore');
const limier = require('limier');
const searchStore = fullstore([]);
diff --git a/client/key/vim/find.spec.js b/client/key/vim/find.spec.js
index 1b36216b..74cc7fb1 100644
--- a/client/key/vim/find.spec.js
+++ b/client/key/vim/find.spec.js
@@ -5,7 +5,7 @@ const dir = './';
const {getDOM} = require('./globals.fixture');
-global.DOM = getDOM();
+globalThis.DOM = getDOM();
const {_next, _previous} = require(`${dir}find`);
diff --git a/client/key/vim/index.js b/client/key/vim/index.js
index 7c94f773..ddfe49c3 100644
--- a/client/key/vim/index.js
+++ b/client/key/vim/index.js
@@ -9,32 +9,43 @@ const {
selectFileNotParent,
} = require('./set-current');
-const {Dialog} = DOM;
-
-const DEPS = {
- ...DOM,
- ...CloudCmd,
-};
-
-module.exports = async (key, event, deps = DEPS) => {
+module.exports = (key, event, overrides = {}) => {
+ const defaults = {
+ ...globalThis.DOM,
+ ...globalThis.CloudCmd,
+ };
+
+ const deps = {
+ ...defaults,
+ ...overrides,
+ };
+
const operations = getOperations(event, deps);
- await vim(key, operations);
+
+ vim(key, operations, deps);
};
const getOperations = (event, deps) => {
const {
- Info = DOM.CurrentInfo,
+ Info = globalThis.DOM.CurrentInfo,
+ CloudCmd = globalThis.CloudCmd,
Operation,
unselectFiles,
setCurrentFile,
setCurrentByName,
getCurrentName,
+ prompt = globalThis.DOM.Dialog.prompt,
+ preventDefault = event?.preventDefault?.bind(event),
toggleSelectedFile,
Buffer = {},
+ createFindNext = _createFindNext,
} = deps;
return {
+ findNext: createFindNext({
+ setCurrentByName,
+ }),
escape: unselectFiles,
remove: () => {
@@ -100,8 +111,8 @@ const getOperations = (event, deps) => {
},
find: async () => {
- event.preventDefault();
- const [, value] = await Dialog.prompt('Find', '');
+ preventDefault();
+ const [, value] = await prompt('Find', '');
if (!value)
return;
@@ -112,11 +123,6 @@ const getOperations = (event, deps) => {
setCurrentByName(result);
},
- findNext: () => {
- const name = finder.findNext();
- setCurrentByName(name);
- },
-
findPrevious: () => {
const name = finder.findPrevious();
setCurrentByName(name);
@@ -125,3 +131,10 @@ const getOperations = (event, deps) => {
};
module.exports.selectFile = selectFileNotParent;
+
+const _createFindNext = (overrides = {}) => () => {
+ const {setCurrentByName} = overrides;
+ const name = finder.findNext();
+
+ setCurrentByName(name);
+};
diff --git a/client/key/vim/index.spec.js b/client/key/vim/index.spec.js
index 245e21cc..6fcad11e 100644
--- a/client/key/vim/index.spec.js
+++ b/client/key/vim/index.spec.js
@@ -10,13 +10,13 @@ const pathVim = join(dir, 'vim');
const {getDOM, getCloudCmd} = require('./globals.fixture');
-global.DOM = getDOM();
-global.CloudCmd = getCloudCmd();
+globalThis.DOM = getDOM();
+globalThis.CloudCmd = getCloudCmd();
-const vim = require(pathVim);
+const vim = require('./index.js');
const {assign} = Object;
-const {DOM} = global;
+const {DOM} = globalThis;
const {Buffer} = DOM;
const pathFind = join(dir, 'vim', 'find');
const {reRequire, stopAll} = mockRequire;
@@ -520,15 +520,26 @@ test('cloudcmd: client: key: Enter', async (t) => {
test('cloudcmd: client: key: /', (t) => {
const preventDefault = stub();
const element = {};
+ const Info = {
+ element,
+ files: [],
+ };
- DOM.CurrentInfo.element = element;
- DOM.getCurrentName = () => '';
+ const getCurrentName = stub().returns('');
- vim('/', {
+ const event = {
preventDefault,
+ };
+
+ const prompt = stub().returns([]);
+
+ vim('/', event, {
+ getCurrentName,
+ Info,
+ prompt,
});
- t.calledWithNoArgs(preventDefault, 'should call preventDefault');
+ t.calledWithNoArgs(preventDefault);
t.end();
});
@@ -559,17 +570,13 @@ test('cloudcmd: client: find', (t) => {
test('cloudcmd: client: key: n', (t) => {
const findNext = stub();
+ const createFindNext = stub().returns(findNext);
- mockRequire(pathFind, {
- findNext,
- });
-
- const vim = reRequire(pathVim);
const event = {};
- vim('n', event);
-
- stopAll();
+ vim('n', event, {
+ createFindNext,
+ });
t.calledWithNoArgs(findNext, 'should call findNext');
t.end();
@@ -595,7 +602,7 @@ test('cloudcmd: client: key: N', (t) => {
test('cloudcmd: client: key: make directory', async (t) => {
const vim = reRequire(pathVim);
- const {DOM} = global;
+ const {DOM} = globalThis;
assign(DOM, {
promptNewDir: stub(),
@@ -615,7 +622,7 @@ test('cloudcmd: client: key: make directory', async (t) => {
test('cloudcmd: client: key: make file', (t) => {
const vim = reRequire(pathVim);
- const {DOM} = global;
+ const {DOM} = globalThis;
assign(DOM, {
promptNewFile: stub(),
@@ -634,28 +641,30 @@ test('cloudcmd: client: key: make file', (t) => {
});
test('cloudcmd: client: vim: terminal', (t) => {
- const {CloudCmd} = global;
-
- assign(CloudCmd, {
+ const CloudCmd = {
Terminal: {
show: stub(),
},
- });
+ };
const event = {};
- vim('t', event);
- vim('t', event);
+ vim('t', event, {
+ CloudCmd,
+ });
+ vim('t', event, {
+ CloudCmd,
+ });
t.calledWithNoArgs(CloudCmd.Terminal.show);
t.end();
});
test('cloudcmd: client: vim: edit', async (t) => {
- global.DOM = getDOM();
- global.CloudCmd = getCloudCmd();
+ globalThis.DOM = getDOM();
+ globalThis.CloudCmd = getCloudCmd();
- const {CloudCmd} = global;
+ const {CloudCmd} = globalThis;
assign(CloudCmd, {
EditFileVim: {
diff --git a/client/key/vim/vim.js b/client/key/vim/vim.js
index 99fe2acf..175f36ac 100644
--- a/client/key/vim/vim.js
+++ b/client/key/vim/vim.js
@@ -1,6 +1,6 @@
'use strict';
-const fullstore = require('fullstore');
+const {fullstore} = require('fullstore');
const store = fullstore('');
const visual = fullstore(false);
diff --git a/client/listeners/index.js b/client/listeners/index.js
index 3e824a7b..c12c62ed 100644
--- a/client/listeners/index.js
+++ b/client/listeners/index.js
@@ -5,12 +5,13 @@
const exec = require('execon');
const itype = require('itype');
const currify = require('currify');
-const tryToCatch = require('try-to-catch');
+const {tryToCatch} = require('try-to-catch');
const clipboard = require('@cloudcmd/clipboard');
const getRange = require('./get-range');
const uploadFiles = require('../dom/upload-files');
-const {FS} = require('../../common/cloudfunc');
+const {FS} = require('../../common/cloudfunc.mjs');
+const Events = require('#dom/events');
const getIndex = currify(require('./get-index'));
@@ -29,10 +30,8 @@ module.exports.init = async () => {
]);
};
-CloudCmd.Listeners = module.exports;
-
const unselect = (event) => {
- const isMac = /Mac/.test(window.navigator.platform);
+ const isMac = /Mac/.test(globalThis.navigator.platform);
const {
shiftKey,
metaKey,
@@ -50,9 +49,6 @@ const execAll = currify((funcs, event) => {
fn(event);
});
-const Info = DOM.CurrentInfo;
-const {Events} = DOM;
-
const EventsFiles = {
mousedown: exec.with(execIfNotUL, setCurrentFileByEvent),
click: execAll([onClick, exec.with(execIfNotMobile, unselect)]),
@@ -112,8 +108,6 @@ module.exports.initKeysPanel = () => {
return;
Events.addClick(keysElement, (event) => {
- event.stopPropagation();
-
const {target} = event;
const {id} = target;
@@ -132,7 +126,10 @@ module.exports.initKeysPanel = () => {
'f6': operation('move'),
'f7': DOM.promptNewDir,
'f8': operation('delete'),
- 'f9': CloudCmd.Menu.show,
+ 'f9': () => {
+ event.stopPropagation();
+ CloudCmd.Menu.show();
+ },
'f10': CloudCmd.Config.show,
'~': CloudCmd.Konsole.show,
'shift~': CloudCmd.Terminal.show,
@@ -166,6 +163,7 @@ function getPathListener(panel) {
}
function isNoCurrent(panel) {
+ const Info = DOM.CurrentInfo;
const infoPanel = Info.panel;
if (!infoPanel)
@@ -190,6 +188,7 @@ function decodePath(path) {
}
async function onPathElementClick(panel, event) {
+ const Info = DOM.CurrentInfo;
event.preventDefault();
const element = event.target;
@@ -245,7 +244,7 @@ function onClick(event) {
}
function toggleSelect(key, files) {
- const isMac = /Mac/.test(window.navigator.platform);
+ const isMac = /Mac/.test(globalThis.navigator.platform);
if (!key)
throw Error('key should not be undefined!');
@@ -260,6 +259,7 @@ function toggleSelect(key, files) {
}
function changePanel(element) {
+ const Info = DOM.CurrentInfo;
const {panel} = Info;
const files = DOM.getByDataName('js-files', panel);
const ul = getULElement(element);
@@ -301,6 +301,7 @@ async function onTouch(event) {
* in Chrome (HTML5)
*/
function onDragStart(event) {
+ const Info = DOM.CurrentInfo;
const {prefixURL} = CloudCmd;
const element = getLIElement(event.target);
const {isDir} = Info;
@@ -337,6 +338,7 @@ function getULElement(element) {
}
function setCurrentFileByEvent(event) {
+ const Info = DOM.CurrentInfo;
const BUTTON_LEFT = 0;
const key = {
@@ -450,7 +452,7 @@ function dragndrop() {
}
function unload() {
- DOM.Events.add(['unload', 'beforeunload'], (event) => {
+ Events.add(['unload', 'beforeunload'], (event) => {
const {Key} = CloudCmd;
const isBind = Key?.isBind();
@@ -479,7 +481,8 @@ function pop() {
function resize() {
Events.add('resize', () => {
- const is = window.innerWidth < CloudCmd.MIN_ONE_PANEL_WIDTH;
+ const Info = DOM.CurrentInfo;
+ const is = globalThis.innerWidth < CloudCmd.MIN_ONE_PANEL_WIDTH;
if (!is)
return;
diff --git a/client/load-module.js b/client/load-module.mjs
similarity index 81%
rename from client/load-module.js
rename to client/load-module.mjs
index 0ce0cc64..7fc2c328 100644
--- a/client/load-module.js
+++ b/client/load-module.mjs
@@ -1,18 +1,16 @@
-'use strict';
-
/* global CloudCmd */
-const exec = require('execon');
-const tryToCatch = require('try-to-catch');
-const loadJS = require('load.js').js;
+import exec from 'execon';
+import {tryToCatch} from 'try-to-catch';
+import {js as loadJS} from 'load.js';
+import pascalCase from 'just-pascal-case';
-const pascalCase = require('just-pascal-case');
const noJS = (a) => a.replace(/.js$/, '');
/**
* function load modules
* @params = {name, path, func, dobefore, arg}
*/
-module.exports = function loadModule(params) {
+export const loadModule = (params) => {
if (!params)
return;
@@ -51,7 +49,7 @@ module.exports = function loadModule(params) {
const [e, a] = await tryToCatch(m);
if (e)
- return console.error(e);
+ return;
return await a.show(...args);
};
diff --git a/client/modules/cloud.js b/client/modules/cloud.js
index 81498c4b..53a6d9e9 100644
--- a/client/modules/cloud.js
+++ b/client/modules/cloud.js
@@ -9,7 +9,7 @@ const load = require('load.js');
const {ajax} = require('../dom/load');
const Files = require('../dom/files');
-const Images = require('../dom/images');
+const Images = require('../dom/images.mjs');
const {log} = CloudCmd;
const upload = currify(_upload);
diff --git a/client/modules/config/index.js b/client/modules/config/index.js
index 759ea85d..db778cbc 100644
--- a/client/modules/config/index.js
+++ b/client/modules/config/index.js
@@ -8,16 +8,16 @@ const currify = require('currify');
const wraptile = require('wraptile');
const squad = require('squad');
const {promisify} = require('es6-promisify');
-const tryToCatch = require('try-to-catch');
+const {tryToCatch} = require('try-to-catch');
const load = require('load.js');
const createElement = require('@cloudcmd/create-element');
const input = require('./input');
-const Images = require('../../dom/images');
-const Events = require('../../dom/events');
+const Images = require('../../dom/images.mjs');
+const Events = require('#dom/events');
const Files = require('../../dom/files');
-const {getTitle} = require('../../../common/cloudfunc');
+const {getTitle} = require('../../../common/cloudfunc.mjs');
const {Dialog, setTitle} = DOM;
const Name = 'Config';
diff --git a/client/modules/contact.js b/client/modules/contact.js
index 76a07d30..c6266de0 100644
--- a/client/modules/contact.js
+++ b/client/modules/contact.js
@@ -6,7 +6,7 @@
CloudCmd.Contact = exports;
const olark = require('@cloudcmd/olark');
-const Images = require('../dom/images');
+const Images = require('../dom/images.mjs');
const {Events} = DOM;
const {Key} = CloudCmd;
diff --git a/client/modules/edit-file-vim.js b/client/modules/edit-file-vim.js
index 48cfd93e..0edd203b 100644
--- a/client/modules/edit-file-vim.js
+++ b/client/modules/edit-file-vim.js
@@ -3,7 +3,7 @@
/* global CloudCmd */
CloudCmd.EditFileVim = exports;
-const Events = require('../dom/events');
+const Events = require('#dom/events');
const {Key} = CloudCmd;
diff --git a/client/modules/edit-file.js b/client/modules/edit-file.js
index f631351a..59050a3c 100644
--- a/client/modules/edit-file.js
+++ b/client/modules/edit-file.js
@@ -4,7 +4,7 @@
CloudCmd.EditFile = exports;
const Format = require('format-io');
-const fullstore = require('fullstore');
+const {fullstore} = require('fullstore');
const exec = require('execon');
const supermenu = require('supermenu');
diff --git a/client/modules/edit-names-vim.js b/client/modules/edit-names-vim.js
index 266dc9dc..0dbd92b2 100644
--- a/client/modules/edit-names-vim.js
+++ b/client/modules/edit-names-vim.js
@@ -3,7 +3,7 @@
/* global CloudCmd */
CloudCmd.EditNamesVim = exports;
-const Events = require('../dom/events');
+const Events = require('#dom/events');
const {Key} = CloudCmd;
const ConfigView = {
diff --git a/client/modules/edit-names.js b/client/modules/edit-names.js
index c2eaac12..710ed7ea 100644
--- a/client/modules/edit-names.js
+++ b/client/modules/edit-names.js
@@ -1,21 +1,17 @@
'use strict';
+const {tryToCatch} = require('try-to-catch');
+
/* global CloudCmd, DOM */
CloudCmd.EditNames = exports;
-const currify = require('currify');
const exec = require('execon');
const supermenu = require('supermenu');
-const multiRename = require('multi-rename');
-
-const reject = Promise.reject.bind(Promise);
+const {multiRename} = require('multi-rename');
const Info = DOM.CurrentInfo;
const {Dialog} = DOM;
-const refresh = currify(_refresh);
-const rename = currify(_rename);
-
let Menu;
const ConfigView = {
@@ -93,7 +89,7 @@ function setListeners() {
DOM.Events.addOnce('contextmenu', element, setMenu);
}
-function applyNames() {
+async function applyNames() {
const dir = Info.dirPath;
const from = getActiveNames();
const nameIndex = from.indexOf(Info.name);
@@ -105,18 +101,18 @@ function applyNames() {
const root = CloudCmd.config('root');
- Promise
- .resolve(root)
- .then(rename(dir, from, to))
- .then(refresh(to, nameIndex))
- .catch(alert);
+ const response = rename(dir, from, to, root);
+ const [error] = await tryToCatch(refresh, to, nameIndex, response);
+
+ if (error)
+ alert(error);
}
-function _refresh(to, nameIndex, res) {
- if (res.status === 404)
- return res
- .text()
- .then(reject);
+function refresh(to, nameIndex, res) {
+ if (res.status === 404) {
+ const error = res.text();
+ throw error;
+ }
const currentName = to[nameIndex];
@@ -132,7 +128,7 @@ function getDir(root, dir) {
return root + dir;
}
-function _rename(path, from, to, root) {
+function rename(path, from, to, root) {
const dir = getDir(root, path);
const {prefix} = CloudCmd;
@@ -172,8 +168,8 @@ function setMenu(event) {
};
const menuData = {
- 'Save Ctrl+S': () => {
- applyNames();
+ 'Save Ctrl+S': async () => {
+ await applyNames();
hide();
},
'Go To Line Ctrl+G': () => {
@@ -214,6 +210,7 @@ async function isChanged() {
if (!editor.isChanged())
return;
- const [, names] = await Dialog.confirm(msg);
- names && applyNames();
+ const [cancel] = await Dialog.confirm(msg);
+
+ !cancel && await applyNames();
}
diff --git a/client/modules/edit.js b/client/modules/edit.js
index 441aaf62..ecefaad8 100644
--- a/client/modules/edit.js
+++ b/client/modules/edit.js
@@ -5,10 +5,10 @@
const montag = require('montag');
const {promisify} = require('es6-promisify');
-const tryToCatch = require('try-to-catch');
+const {tryToCatch} = require('try-to-catch');
const createElement = require('@cloudcmd/create-element');
const load = require('load.js');
-const {MAX_FILE_SIZE: maxSize} = require('../../common/cloudfunc');
+const {MAX_FILE_SIZE: maxSize} = require('../../common/cloudfunc.mjs');
const {time, timeEnd} = require('../../common/util');
const getEditor = () => editor;
diff --git a/client/modules/help.js b/client/modules/help.js
index 785bb32c..242b7c16 100644
--- a/client/modules/help.js
+++ b/client/modules/help.js
@@ -3,7 +3,7 @@
/* global CloudCmd */
CloudCmd.Help = exports;
-const Images = require('../dom/images');
+const Images = require('../dom/images.mjs');
module.exports.init = () => {
Images.show.load('top');
diff --git a/client/modules/konsole.js b/client/modules/konsole.js
index 6993380d..ae5bc42c 100644
--- a/client/modules/konsole.js
+++ b/client/modules/konsole.js
@@ -8,11 +8,11 @@ CloudCmd.Konsole = exports;
const exec = require('execon');
const currify = require('currify');
-const tryToCatch = require('try-to-catch');
+const {tryToCatch} = require('try-to-catch');
const loadJS = require('load.js').js;
const createElement = require('@cloudcmd/create-element');
-const Images = require('../dom/images');
+const Images = require('../dom/images.mjs');
const {Dialog, CurrentInfo: Info} = DOM;
const rmLastSlash = (a) => a.replace(/\/$/, '') || '/';
diff --git a/client/modules/markdown.js b/client/modules/markdown.js
index 6c5c3282..9dc224af 100644
--- a/client/modules/markdown.js
+++ b/client/modules/markdown.js
@@ -5,7 +5,7 @@ CloudCmd.Markdown = exports;
const createElement = require('@cloudcmd/create-element');
-const Images = require('../dom/images');
+const Images = require('../dom/images.mjs');
const {Markdown} = require('../dom/rest');
const {alert} = require('../dom/dialog');
diff --git a/client/modules/menu/cloudmenu.mjs b/client/modules/menu/cloudmenu.mjs
index b36ca828..1fbe5165 100644
--- a/client/modules/menu/cloudmenu.mjs
+++ b/client/modules/menu/cloudmenu.mjs
@@ -14,7 +14,7 @@ export const createCloudMenu = async (fm, options, menuData) => {
async function loadMenu() {
if (CloudCmd.config('menu') === 'aleman') {
- const {host, protocol} = window.location;
+ const {host, protocol} = globalThis.location;
const url = `${protocol}//${host}/node_modules/aleman/menu/menu.js`;
const {createMenu} = await import(/* webpackIgnore: true */url);
diff --git a/client/modules/menu/index.js b/client/modules/menu/index.js
index bc2682f4..facb385a 100644
--- a/client/modules/menu/index.js
+++ b/client/modules/menu/index.js
@@ -6,7 +6,7 @@ const exec = require('execon');
const wrap = require('wraptile');
const createElement = require('@cloudcmd/create-element');
-const {FS} = require('../../../common/cloudfunc');
+const {FS} = require('../../../common/cloudfunc.mjs');
const {getIdBySrc} = require('../../dom/load');
const RESTful = require('../../dom/rest');
@@ -109,6 +109,7 @@ function getOptions({type}) {
const options = {
icon: true,
+ infiniteScroll: false,
beforeClose: Key.setBind,
beforeHide: Key.setBind,
beforeShow: exec.with(beforeShow, func),
diff --git a/client/modules/operation/index.js b/client/modules/operation/index.mjs
similarity index 93%
rename from client/modules/operation/index.js
rename to client/modules/operation/index.mjs
index bf19bda8..8e8149e5 100644
--- a/client/modules/operation/index.js
+++ b/client/modules/operation/index.mjs
@@ -1,28 +1,20 @@
-/* global CloudCmd */
-/* global Util */
-/* global DOM */
-/* global fileop */
+import currify from 'currify';
+import wraptile from 'wraptile';
+import {promisify} from 'es6-promisify';
+import exec from 'execon';
+import load from 'load.js';
+import {tryToCatch} from 'try-to-catch';
+import {encode} from '../../../common/entity.js';
+import removeExtension from './remove-extension.js';
+import {setListeners} from './set-listeners.mjs';
+import getNextCurrentName from './get-next-current-name.js';
-'use strict';
-
-const currify = require('currify');
-const wraptile = require('wraptile');
-const {promisify} = require('es6-promisify');
-const exec = require('execon');
-const load = require('load.js');
-const tryToCatch = require('try-to-catch');
-
-const {encode} = require('../../../common/entity');
-const removeExtension = require('./remove-extension');
-const setListeners = require('./set-listeners');
-const getNextCurrentName = require('./get-next-current-name');
+const {DOM, CloudCmd} = globalThis;
const removeQuery = (a) => a.replace(/\?.*/, '');
const Name = 'Operation';
-CloudCmd[Name] = exports;
-
const {config} = CloudCmd;
const {Dialog, Images} = DOM;
@@ -53,7 +45,7 @@ const noFilesCheck = () => {
return is;
};
-module.exports.init = promisify((callback) => {
+export const init = promisify((callback) => {
showLoad();
exec.series([
@@ -92,7 +84,7 @@ const onConnect = currify((fn, operator) => {
async function initOperations(prefix, socketPrefix, fn) {
socketPrefix = `${socketPrefix}/fileop`;
- const operator = await fileop({
+ const operator = await globalThis.fileop({
prefix,
socketPrefix,
});
@@ -198,11 +190,11 @@ function getPacker(type) {
return packTarFn;
}
-module.exports.hide = () => {
+export const hide = () => {
CloudCmd.View.hide();
};
-module.exports.show = (operation, data) => {
+export const show = (operation, data) => {
if (!Loaded)
return;
@@ -505,8 +497,14 @@ async function prompt(msg, to, names) {
return await Dialog.prompt(msg, to);
}
+globalThis.CloudCmd[Name] = {
+ init,
+ hide,
+ show,
+};
+
async function loadAll() {
- const {prefix} = CloudCmd;
+ const {prefix} = globalThis.CloudCmd;
const file = `${prefix}/fileop/fileop.js`;
const [error] = await tryToCatch(load.js, file);
diff --git a/client/modules/operation/remove-extension.js b/client/modules/operation/remove-extension.js
index a8389af3..5e98727d 100644
--- a/client/modules/operation/remove-extension.js
+++ b/client/modules/operation/remove-extension.js
@@ -9,10 +9,10 @@ module.exports = (name) => {
};
function getExtension(name) {
- if (/\.tar\.gz$/.test(name))
+ if (name.endsWith('.tar.gz'))
return '.tar.gz';
- if (/\.tar\.bz2$/.test(name))
+ if (name.endsWith('.tar.bz2'))
return '.tar.bz2';
return getExt(name);
diff --git a/client/modules/operation/set-listeners.js b/client/modules/operation/set-listeners.mjs
similarity index 85%
rename from client/modules/operation/set-listeners.js
rename to client/modules/operation/set-listeners.mjs
index 495cd04b..d5052cff 100644
--- a/client/modules/operation/set-listeners.js
+++ b/client/modules/operation/set-listeners.mjs
@@ -1,14 +1,11 @@
-'use strict';
-
/* global DOM */
-const forEachKey = require('for-each-key');
-
-const wraptile = require('wraptile');
-const format = require('./format');
+import forEachKey from 'for-each-key';
+import wraptile from 'wraptile';
+import format from './format.js';
const {Dialog, Images} = DOM;
-module.exports = (options) => (emitter) => {
+export const setListeners = (options) => (emitter) => {
const {
operation,
callback,
@@ -43,10 +40,13 @@ module.exports = (options) => (emitter) => {
operation,
}));
+ let noProgress = true;
+
const listeners = {
progress: (value) => {
done = value === 100;
progress.setProgress(value);
+ noProgress = false;
},
end: () => {
@@ -54,7 +54,7 @@ module.exports = (options) => (emitter) => {
forEachKey(removeListener, listeners);
progress.remove();
- if (lastError || done)
+ if (lastError || done || noProgress)
callback();
},
diff --git a/client/modules/polyfill.js b/client/modules/polyfill.js
index f5e7dc7a..ff0e59c5 100644
--- a/client/modules/polyfill.js
+++ b/client/modules/polyfill.js
@@ -1,10 +1,20 @@
'use strict';
-/* global DOM */
require('domtokenlist-shim');
-const scrollIntoViewIfNeeded = require('scroll-into-view-if-needed');
+const _scrollIntoViewIfNeeded = require('scroll-into-view-if-needed');
-DOM.scrollIntoViewIfNeeded = (el) => scrollIntoViewIfNeeded(el, {
- block: 'nearest',
-});
+globalThis.DOM = globalThis.DOM || {};
+
+const scrollIntoViewIfNeeded = (el, overrides = {}) => {
+ const {
+ scroll = _scrollIntoViewIfNeeded,
+ } = overrides;
+
+ return scroll(el, {
+ block: 'nearest',
+ });
+};
+
+globalThis.DOM.scrollIntoViewIfNeeded = scrollIntoViewIfNeeded;
+module.exports.scrollIntoViewIfNeeded = scrollIntoViewIfNeeded;
diff --git a/client/modules/polyfill.spec.js b/client/modules/polyfill.spec.js
index 67149e46..79d9dfda 100644
--- a/client/modules/polyfill.spec.js
+++ b/client/modules/polyfill.spec.js
@@ -1,24 +1,15 @@
'use strict';
const {test, stub} = require('supertape');
-
-const mockRequire = require('mock-require');
-
-const {stopAll} = mockRequire;
+const {scrollIntoViewIfNeeded} = require('./polyfill');
test('cloudcmd: client: polyfill: scrollIntoViewIfNeaded', (t) => {
- const {DOM} = global;
const scroll = stub();
const el = {};
- global.DOM = {};
-
- mockRequire('scroll-into-view-if-needed', scroll);
- mockRequire.reRequire('./polyfill');
-
- global.DOM.scrollIntoViewIfNeeded(el);
- mockRequire.stop('scroll-into-view-if-neaded');
- global.DOM = DOM;
+ scrollIntoViewIfNeeded(el, {
+ scroll,
+ });
const args = [
el, {
@@ -26,8 +17,6 @@ test('cloudcmd: client: polyfill: scrollIntoViewIfNeaded', (t) => {
},
];
- stopAll();
-
t.calledWith(scroll, args, 'should call scrollIntoViewIfNeaded');
t.end();
});
diff --git a/client/modules/terminal-run.js b/client/modules/terminal-run.js
index 3e4b857d..4dcf24ac 100644
--- a/client/modules/terminal-run.js
+++ b/client/modules/terminal-run.js
@@ -2,15 +2,15 @@
/* global CloudCmd, gritty */
const {promisify} = require('es6-promisify');
-const tryToCatch = require('try-to-catch');
-const fullstore = require('fullstore');
+const {tryToCatch} = require('try-to-catch');
+const {fullstore} = require('fullstore');
require('../../css/terminal.css');
const exec = require('execon');
const load = require('load.js');
const DOM = require('../dom');
-const Images = require('../dom/images');
+const Images = require('../dom/images.mjs');
const {Dialog} = DOM;
const {Key, config} = CloudCmd;
@@ -33,7 +33,7 @@ const loadAll = async () => {
const [e] = await tryToCatch(load.parallel, [js, css]);
if (e) {
- const src = e.target.src.replace(window.location.href, '');
+ const src = e.target.src.replace(globalThis.location.href, '');
return Dialog.alert(`file ${src} could not be loaded`);
}
diff --git a/client/modules/terminal.js b/client/modules/terminal.js
index d36b700a..6a355560 100644
--- a/client/modules/terminal.js
+++ b/client/modules/terminal.js
@@ -2,14 +2,14 @@
/* global CloudCmd */
/* global gritty */
-const tryToCatch = require('try-to-catch');
+const {tryToCatch} = require('try-to-catch');
require('../../css/terminal.css');
const exec = require('execon');
const load = require('load.js');
const DOM = require('../dom');
-const Images = require('../dom/images');
+const Images = require('../dom/images.mjs');
const loadParallel = load.parallel;
@@ -32,7 +32,7 @@ const loadAll = async () => {
const [e] = await tryToCatch(loadParallel, [js, css]);
if (e) {
- const src = e.target.src.replace(window.location.href, '');
+ const src = e.target.src.replace(globalThis.location.href, '');
return Dialog.alert(`file ${src} could not be loaded`);
}
diff --git a/client/modules/upload.js b/client/modules/upload.js
index 63a2cd0f..23fbdaf5 100644
--- a/client/modules/upload.js
+++ b/client/modules/upload.js
@@ -6,7 +6,7 @@ CloudCmd.Upload = exports;
const createElement = require('@cloudcmd/create-element');
const Files = require('../dom/files');
-const Images = require('../dom/images');
+const Images = require('../dom/images.mjs');
const uploadFiles = require('../dom/upload-files');
module.exports.init = async () => {
diff --git a/client/modules/user-menu/index.js b/client/modules/user-menu/index.js
index 47fbee39..1dba5d23 100644
--- a/client/modules/user-menu/index.js
+++ b/client/modules/user-menu/index.js
@@ -5,14 +5,14 @@ require('../../../css/user-menu.css');
const currify = require('currify');
const wraptile = require('wraptile');
-const fullstore = require('fullstore');
+const {fullstore} = require('fullstore');
const load = require('load.js');
const createElement = require('@cloudcmd/create-element');
-const tryCatch = require('try-catch');
-const tryToCatch = require('try-to-catch');
+const {tryCatch} = require('try-catch');
+const {tryToCatch} = require('try-to-catch');
const {codeFrameColumns} = require('@babel/code-frame');
-const Images = require('../../dom/images');
+const Images = require('../../dom/images.mjs');
const Dialog = require('../../dom/dialog');
const getUserMenu = require('./get-user-menu');
const navigate = require('./navigate');
diff --git a/client/modules/user-menu/navigate.js b/client/modules/user-menu/navigate.js
index 445d47d1..a87801ed 100644
--- a/client/modules/user-menu/navigate.js
+++ b/client/modules/user-menu/navigate.js
@@ -1,6 +1,6 @@
'use strict';
-const fullstore = require('fullstore');
+const {fullstore} = require('fullstore');
const {
J,
diff --git a/client/modules/view/get-type.js b/client/modules/view/get-type.js
index 3ac092e0..9fc1df1d 100644
--- a/client/modules/view/get-type.js
+++ b/client/modules/view/get-type.js
@@ -5,7 +5,7 @@ const testRegExp = currify((name, reg) => reg.test(name));
const getRegExp = (ext) => RegExp(`\\.${ext}$`, 'i');
const isPDF = (a) => /\.pdf$/i.test(a);
-const isHTML = (a) => /\.html$/.test(a);
+const isHTML = (a) => a.endsWith('.html');
const isMarkdown = (a) => /.\.md$/.test(a);
module.exports = (name) => {
diff --git a/client/modules/view/index.js b/client/modules/view/index.js
index c6d34d18..89d68ee4 100644
--- a/client/modules/view/index.js
+++ b/client/modules/view/index.js
@@ -2,19 +2,22 @@
'use strict';
+const CloudCmd = globalThis.CloudCmd || {};
+const DOM = globalThis.DOM || {};
+
require('../../../css/view.css');
const rendy = require('rendy');
const currify = require('currify');
const wraptile = require('wraptile');
-const tryToCatch = require('try-to-catch');
+const {tryToCatch} = require('try-to-catch');
const load = require('load.js');
-const modal = require('@cloudcmd/modal');
-const createElement = require('@cloudcmd/create-element');
+const _modal = require('@cloudcmd/modal');
+const _createElement = require('@cloudcmd/create-element');
const {time} = require('../../../common/util');
-const {FS} = require('../../../common/cloudfunc');
+const {FS} = require('../../../common/cloudfunc.mjs');
const {
isImage,
@@ -23,8 +26,8 @@ const {
} = require('./types');
const Files = require('../../dom/files');
-const Events = require('../../dom/events');
-const Images = require('../../dom/images');
+const Events = require('#dom/events');
+const Images = require('../../dom/images.mjs');
const {encode} = require('../../../common/entity');
const isString = (a) => typeof a === 'string';
@@ -113,7 +116,7 @@ async function show(data, options = {}) {
if (!options || options.bindKeys !== false)
Events.addKey(listener);
- El = createElement('div', {
+ El = _createElement('div', {
className: 'view',
notAppend: true,
});
@@ -126,7 +129,7 @@ async function show(data, options = {}) {
else
El.append(data);
- modal.open(El, initConfig(options));
+ _modal.open(El, initConfig(options));
return;
}
@@ -157,7 +160,11 @@ async function show(data, options = {}) {
}
module.exports._createIframe = createIframe;
-function createIframe(src) {
+function createIframe(src, overrides = {}) {
+ const {
+ createElement = _createElement,
+ } = overrides;
+
const element = createElement('iframe', {
src,
width: '100%',
@@ -172,7 +179,8 @@ function createIframe(src) {
}
module.exports._viewHtml = viewHtml;
-function viewHtml(src) {
+function viewHtml(src, overrides = {}) {
+ const {modal = _modal} = overrides;
modal.open(createIframe(src), Config);
}
@@ -184,7 +192,7 @@ function viewPDF(src) {
if (CloudCmd.config('showFileName'))
options.title = Info.name;
- modal.open(element, options);
+ _modal.open(element, options);
}
async function viewMedia(path) {
@@ -205,7 +213,7 @@ async function viewMedia(path) {
},
};
- modal.open(element, allConfig);
+ _modal.open(element, allConfig);
}
async function viewFile() {
@@ -221,7 +229,7 @@ async function viewFile() {
options.title = Info.name;
El.append(element);
- modal.open(El, options);
+ _modal.open(El, options);
}
const copy = (a) => assign({}, a);
@@ -253,7 +261,7 @@ function initConfig(options) {
}
function hide() {
- modal.close();
+ _modal.close();
}
function viewImage(path, prefixURL) {
@@ -286,7 +294,7 @@ function viewImage(path, prefixURL) {
...imageConfig,
};
- modal.open(titles, config);
+ _modal.open(titles, config);
}
async function getMediaElement(src) {
@@ -311,7 +319,7 @@ async function getMediaElement(src) {
name,
});
- const element = createElement('div', {
+ const element = _createElement('div', {
innerHTML,
});
diff --git a/client/modules/view/index.spec.js b/client/modules/view/index.spec.js
index 83e6b476..cc46d07d 100644
--- a/client/modules/view/index.spec.js
+++ b/client/modules/view/index.spec.js
@@ -3,22 +3,20 @@
require('css-modules-require-hook/preset');
const autoGlobals = require('auto-globals');
-const stub = require('@cloudcmd/stub');
-const mockRequire = require('mock-require');
+const {stub} = require('@cloudcmd/stub');
+
const test = autoGlobals(require('supertape'));
-const {reRequire, stopAll} = mockRequire;
+const {
+ _initConfig,
+ _viewHtml,
+ _Config,
+ _createIframe,
+} = require('.');
test('cloudcmd: client: view: initConfig', (t) => {
let config;
let i = 0;
- const {CloudCmd, DOM} = global;
-
- global.CloudCmd = {};
- global.DOM = {};
-
- const {_initConfig} = reRequire('.');
-
const afterClose = () => ++i;
const options = {
afterClose,
@@ -30,54 +28,32 @@ test('cloudcmd: client: view: initConfig', (t) => {
config = _initConfig(options);
config.afterClose();
- global.CloudCmd = CloudCmd;
- global.DOM = DOM;
-
t.equal(i, 2, 'should not change default config');
t.end();
});
test('cloudcmd: client: view: initConfig: no options', (t) => {
- const {CloudCmd, DOM} = global;
-
- global.CloudCmd = {};
- global.DOM = {};
-
- const {_initConfig} = reRequire('.');
const config = _initConfig();
- global.CloudCmd = CloudCmd;
- global.DOM = DOM;
-
t.equal(typeof config, 'object');
t.end();
});
test('cloudcmd: client: view: html', (t) => {
- const {CloudCmd, DOM} = global;
-
- global.CloudCmd = {};
- global.DOM = {};
const open = stub();
-
- mockRequire('@cloudcmd/modal', {
+ const modal = {
open,
- });
-
- const {_viewHtml, _Config} = reRequire('.');
+ };
const src = '/hello.html';
- _viewHtml(src);
-
- global.CloudCmd = CloudCmd;
- global.DOM = DOM;
+ _viewHtml(src, {
+ modal,
+ });
const [first] = open.args;
const [arg] = first;
- stopAll();
-
t.deepEqual(first, [arg, _Config]);
t.end();
});
@@ -89,12 +65,11 @@ test('cloudcmd: client: view: createIframe', (t) => {
};
const createElement = stub().returns(el);
-
- mockRequire('@cloudcmd/create-element', createElement);
- const {_createIframe} = reRequire('.');
-
const src = '/hello.html';
- _createIframe(src);
+
+ _createIframe(src, {
+ createElement,
+ });
const expected = {
src,
@@ -102,8 +77,6 @@ test('cloudcmd: client: view: createIframe', (t) => {
width: '100%',
};
- stopAll();
-
t.calledWith(createElement, ['iframe', expected]);
t.end();
});
@@ -116,13 +89,10 @@ test('cloudcmd: client: view: createIframe: returns', (t) => {
const createElement = stub().returns(el);
- mockRequire('@cloudcmd/create-element', createElement);
- const {_createIframe} = reRequire('.');
-
const src = '/hello.html';
- const result = _createIframe(src);
-
- stopAll();
+ const result = _createIframe(src, {
+ createElement,
+ });
t.equal(result, el);
t.end();
diff --git a/client/modules/view/types.js b/client/modules/view/types.js
index e36fec4d..d94dd971 100644
--- a/client/modules/view/types.js
+++ b/client/modules/view/types.js
@@ -7,7 +7,7 @@ const testRegExp = currify((name, reg) => reg.test(name));
const getRegExp = (ext) => RegExp(`\\.${ext}$`, 'i');
const isPDF = (a) => /\.pdf$/i.test(a);
-const isHTML = (a) => /\.html$/.test(a);
+const isHTML = (a) => a.endsWith('.html');
const isMarkdown = (a) => /.\.md$/.test(a);
module.exports.getType = async (path) => {
diff --git a/client/modules/view/types.spec.js b/client/modules/view/types.spec.js
index 52ed5bad..d8004f9e 100644
--- a/client/modules/view/types.spec.js
+++ b/client/modules/view/types.spec.js
@@ -22,12 +22,9 @@ test('cloudcmd: client: view: types: detectType', async (t) => {
headers: [],
});
- const originalFetch = global.fetch;
-
- global.fetch = fetch;
+ globalThis.fetch = fetch;
await _detectType('/hello');
- global.fetch = originalFetch;
const expected = ['/hello', {
method: 'HEAD',
}];
@@ -37,17 +34,13 @@ test('cloudcmd: client: view: types: detectType', async (t) => {
});
test('cloudcmd: client: view: types: detectType: found', async (t) => {
- const originalFetch = global.fetch;
-
- global.fetch = stub().returns({
+ globalThis.fetch = stub().returns({
headers: [
['content-type', 'image/png'],
],
});
const result = await _detectType('/hello');
- global.fetch = originalFetch;
-
t.equal(result, '.png');
t.end();
});
diff --git a/client/sort.js b/client/sort.js
deleted file mode 100644
index cf9fb4a4..00000000
--- a/client/sort.js
+++ /dev/null
@@ -1,31 +0,0 @@
-'use strict';
-
-/* global CloudCmd */
-const DOM = require('./dom');
-
-const Info = DOM.CurrentInfo;
-const {sort, order} = CloudCmd;
-const position = DOM.getPanelPosition();
-let sortPrevious = sort[position];
-
-const {getPanel} = DOM;
-
-CloudCmd.sortPanel = (name, panel = getPanel()) => {
- const position = panel.dataset.name.replace('js-', '');
-
- if (name !== sortPrevious)
- order[position] = 'asc';
- else if (order[position] === 'asc')
- order[position] = 'desc';
- else
- order[position] = 'asc';
-
- sortPrevious = name;
- sort[position] = name;
- const noCurrent = position !== Info.panelPosition;
-
- CloudCmd.refresh({
- panel,
- noCurrent,
- });
-};
diff --git a/client/sort.mjs b/client/sort.mjs
new file mode 100644
index 00000000..73539c81
--- /dev/null
+++ b/client/sort.mjs
@@ -0,0 +1,36 @@
+/* global CloudCmd */
+import {fullstore} from 'fullstore';
+import DOM from './dom/index.js';
+
+const sortPrevious = fullstore();
+
+const {getPanel} = DOM;
+
+export const initSortPanel = () => {
+ const {sort} = CloudCmd;
+ const position = DOM.getPanelPosition();
+
+ sortPrevious(sort[position]);
+};
+
+export const sortPanel = (name, panel = getPanel()) => {
+ const {sort, order} = CloudCmd;
+ const Info = DOM.CurrentInfo;
+ const position = panel.dataset.name.replace('js-', '');
+
+ if (name !== sortPrevious())
+ order[position] = 'asc';
+ else if (order[position] === 'asc')
+ order[position] = 'desc';
+ else
+ order[position] = 'asc';
+
+ sortPrevious(name);
+ sort[position] = name;
+ const noCurrent = position !== Info.panelPosition;
+
+ CloudCmd.refresh({
+ panel,
+ noCurrent,
+ });
+};
diff --git a/client/sw/register.js b/client/sw/register.js
index 12431a82..0e6db472 100644
--- a/client/sw/register.js
+++ b/client/sw/register.js
@@ -1,6 +1,6 @@
'use strict';
-const tryToCatch = require('try-to-catch');
+const {tryToCatch} = require('try-to-catch');
module.exports.registerSW = registerSW;
module.exports.unregisterSW = unregisterSW;
diff --git a/client/sw/register.spec.js b/client/sw/register.spec.js
index c4368c94..9b42a0e6 100644
--- a/client/sw/register.spec.js
+++ b/client/sw/register.spec.js
@@ -3,14 +3,18 @@
const autoGlobals = require('auto-globals');
const tape = require('supertape');
-const stub = require('@cloudcmd/stub');
+const {stub} = require('@cloudcmd/stub');
+
+const {tryCatch} = require('try-catch');
+const {
+ listenSW,
+ registerSW,
+ unregisterSW,
+} = require('./register');
-const tryCatch = require('try-catch');
-const {reRequire} = require('mock-require');
const test = autoGlobals(tape);
test('sw: listen', (t) => {
- const {listenSW} = reRequire('./register');
const addEventListener = stub();
const sw = {
addEventListener,
@@ -23,7 +27,6 @@ test('sw: listen', (t) => {
});
test('sw: lesten: no sw', (t) => {
- const {listenSW} = reRequire('./register');
const [e] = tryCatch(listenSW, null, 'hello', 'world');
t.notOk(e, 'should not throw');
@@ -31,8 +34,6 @@ test('sw: lesten: no sw', (t) => {
});
test('sw: register: registerSW: no serviceWorker', async (t, {navigator}) => {
- const {registerSW} = reRequire('./register');
-
delete navigator.serviceWorker;
await registerSW();
@@ -46,8 +47,6 @@ test('sw: register: registerSW: no https', async (t, {location, navigator}) => {
location.protocol = 'http:';
- const {registerSW} = reRequire('./register');
-
await registerSW();
t.notCalled(register, 'should not call register');
@@ -62,8 +61,6 @@ test('sw: register: registerSW: http', async (t, {location, navigator}) => {
const {register} = navigator.serviceWorker;
- const {registerSW} = reRequire('./register');
-
await registerSW();
t.notCalled(register, 'should not call register');
@@ -79,8 +76,6 @@ test('sw: register: registerSW: https self-signed', async (t, {location, navigat
const {register} = navigator.serviceWorker;
register.throws(Error('Cannot register service worker!'));
- const {registerSW} = reRequire('./register');
-
const result = await registerSW();
t.notOk(result, 'should not throw');
@@ -91,8 +86,6 @@ test('sw: register: registerSW', async (t, {location, navigator}) => {
location.hostname = 'localhost';
const {register} = navigator.serviceWorker;
- const {registerSW} = reRequire('./register');
-
await registerSW('/hello');
t.calledWith(register, ['/hello/sw.js'], 'should call register');
@@ -107,8 +100,6 @@ test('sw: register: unregisterSW', async (t, {location, navigator}) => {
register.returns(serviceWorker);
- const {unregisterSW} = reRequire('./register');
-
await unregisterSW('/hello');
t.calledWith(register, ['/hello/sw.js'], 'should call register');
diff --git a/client/sw/sw.js b/client/sw/sw.js
index 15f3e0ad..e4cad253 100644
--- a/client/sw/sw.js
+++ b/client/sw/sw.js
@@ -2,7 +2,7 @@
const process = require('node:process');
const codegen = require('codegen.macro');
-const tryToCatch = require('try-to-catch');
+const {tryToCatch} = require('try-to-catch');
const currify = require('currify');
const isDev = process.env.NODE_ENV === 'development';
@@ -50,14 +50,14 @@ const getRequest = (a, request) => {
return createRequest('/');
};
-self.addEventListener('install', wait(onInstall));
-self.addEventListener('fetch', respondWith(onFetch));
-self.addEventListener('activate', wait(onActivate));
+globalThis.addEventListener('install', wait(onInstall));
+globalThis.addEventListener('fetch', respondWith(onFetch));
+globalThis.addEventListener('activate', wait(onActivate));
async function onActivate() {
console.info(`cloudcmd: sw: activate: ${NAME}`);
- await self.clients.claim();
+ await globalThis.clients.claim();
const keys = await caches.keys();
const deleteCache = caches.delete.bind(caches);
@@ -67,7 +67,7 @@ async function onActivate() {
async function onInstall() {
console.info(`cloudcmd: sw: install: ${NAME}`);
- await self.skipWaiting();
+ await globalThis.skipWaiting();
}
async function onFetch(event) {
diff --git a/common/base64.js b/common/base64.js
deleted file mode 100644
index c1a82c17..00000000
--- a/common/base64.js
+++ /dev/null
@@ -1,19 +0,0 @@
-'use strict';
-
-module.exports.btoa = (str) => {
- if (typeof btoa === 'function')
- return btoa(str);
-
- return Buffer
- .from(str)
- .toString('base64');
-};
-
-module.exports.atob = (str) => {
- if (typeof atob === 'function')
- return atob(str);
-
- return Buffer
- .from(str, 'base64')
- .toString('binary');
-};
diff --git a/common/base64.spec.js b/common/base64.spec.js
deleted file mode 100644
index cc096ee2..00000000
--- a/common/base64.spec.js
+++ /dev/null
@@ -1,55 +0,0 @@
-'use strict';
-
-const {test, stub} = require('supertape');
-
-const {btoa, atob} = require('./base64');
-
-test('btoa: browser', (t) => {
- const btoaOriginal = global.btoa;
- const btoaStub = stub();
- const str = 'hello';
-
- global.btoa = btoaStub;
-
- btoa(str);
- global.btoa = btoaOriginal;
-
- t.calledWith(btoaStub, [str], 'should call global.btoa');
- t.end();
-});
-
-test('btoa: node', (t) => {
- const str = 'hello';
- const expected = 'aGVsbG8=';
-
- const result = btoa(str);
-
- t.equal(result, expected, 'should encode base64');
- t.end();
-});
-
-test('atob: browser', (t) => {
- const atobOriginal = global.atob;
- const atobStub = stub();
-
- const str = 'hello';
-
- global.atob = atobStub;
-
- atob(str);
-
- global.atob = atobOriginal;
-
- t.calledWith(atobStub, [str], 'should call global.btoa');
- t.end();
-});
-
-test('atob: node', (t) => {
- const str = 'aGVsbG8=';
- const expected = 'hello';
-
- const result = atob(str);
-
- t.equal(result, expected, 'should encode base64');
- t.end();
-});
diff --git a/common/callbackify.spec.js b/common/callbackify.spec.js
index 1b742169..0a46d9e9 100644
--- a/common/callbackify.spec.js
+++ b/common/callbackify.spec.js
@@ -1,7 +1,7 @@
'use strict';
const {promisify} = require('node:util');
-const tryToCatch = require('try-to-catch');
+const {tryToCatch} = require('try-to-catch');
const {test, stub} = require('supertape');
diff --git a/common/cloudfunc.js b/common/cloudfunc.mjs
similarity index 87%
rename from common/cloudfunc.js
rename to common/cloudfunc.mjs
index c906b548..00a48360 100644
--- a/common/cloudfunc.js
+++ b/common/cloudfunc.mjs
@@ -1,17 +1,16 @@
-'use strict';
+import rendy from 'rendy';
+import currify from 'currify';
+import store from 'fullstore';
+import {encode} from './entity.js';
-const rendy = require('rendy');
-const currify = require('currify');
-const store = require('fullstore');
-const {encode} = require('./entity');
-const {btoa} = require('./base64');
-
-const getHeaderField = currify(_getHeaderField);
+export const getHeaderField = currify(_getHeaderField);
/* КОНСТАНТЫ (общие для клиента и сервера)*/
/* название программы */
const NAME = 'Cloud Commander';
-const FS = '/fs';
+
+export const FS = '/fs';
+
const Path = store();
Path('/');
@@ -23,14 +22,10 @@ const filterOutDotFiles = ({showDotFiles}) => ({name}) => {
return !name.startsWith('.');
};
-module.exports.FS = FS;
-module.exports.apiURL = '/api/v1';
-module.exports.MAX_FILE_SIZE = 500 * 1024;
-module.exports.getHeaderField = getHeaderField;
-module.exports.getPathLink = getPathLink;
-module.exports.getDotDot = getDotDot;
+export const apiURL = '/api/v1';
+export const MAX_FILE_SIZE = 500 * 1024;
-module.exports.formatMsg = (msg, name, status) => {
+export const formatMsg = (msg, name, status) => {
status = status || 'ok';
name = name || '';
@@ -44,7 +39,7 @@ module.exports.formatMsg = (msg, name, status) => {
* Функция возвращает заголовок веб страницы
* @path
*/
-module.exports.getTitle = (options) => {
+export const getTitle = (options) => {
options = options || {};
const {path = Path(), name} = options;
@@ -63,7 +58,7 @@ module.exports.getTitle = (options) => {
* возвращаеться массив каталогов
* @param url - адрес каталога
*/
-function getPathLink(url, prefix, template) {
+export function getPathLink(url, prefix, template) {
if (!url)
throw Error('url could not be empty!');
@@ -109,17 +104,17 @@ function getPathLink(url, prefix, template) {
return lines.join('');
}
-const getDataName = (name) => {
+export function _getDataName(name) {
const encoded = btoa(encodeURI(name));
return `data-name="js-file-${encoded}" `;
-};
+}
/**
* Функция строит таблицу файлв из JSON-информации о файлах
* @param params - информация о файлах
*
*/
-module.exports.buildFromJSON = (params) => {
+export const buildFromJSON = (params) => {
const {
prefix,
template,
@@ -185,7 +180,7 @@ module.exports.buildFromJSON = (params) => {
name: '..',
});
- const dataName = getDataName('..');
+ const dataName = _getDataName('..');
const attribute = `draggable="true" ${dataName}`;
/* Сохраняем путь к каталогу верхнего уровня*/
@@ -226,7 +221,7 @@ module.exports.buildFromJSON = (params) => {
attribute: getAttribute(file.type),
});
- const dataName = getDataName(file.name);
+ const dataName = _getDataName(file.name);
const attribute = `draggable="true" ${dataName}`;
return rendy(templateFile, {
@@ -262,7 +257,8 @@ function getAttribute(type) {
return 'target="_blank" ';
}
-module.exports._getSize = getSize;
+export const _getSize = getSize;
+
function getSize({size, type}) {
if (type === 'directory')
return '<dir>';
@@ -285,7 +281,7 @@ function _getHeaderField(sort, order, name) {
return `${name}${arrow}`;
}
-function getDotDot(path) {
+export function getDotDot(path) {
// убираем последний слеш и каталог в котором мы сейчас находимся
const lastSlash = path.substr(path, path.lastIndexOf('/'));
const dotDot = lastSlash.substr(lastSlash, lastSlash.lastIndexOf('/'));
diff --git a/common/cloudfunc.spec.js b/common/cloudfunc.spec.mjs
similarity index 89%
rename from common/cloudfunc.spec.js
rename to common/cloudfunc.spec.mjs
index e4e06dd7..79ddfedf 100644
--- a/common/cloudfunc.spec.js
+++ b/common/cloudfunc.spec.mjs
@@ -1,19 +1,15 @@
-'use strict';
-
-const {join} = require('node:path');
-const {readFileSync} = require('node:fs');
-
-const test = require('supertape');
-const montag = require('montag');
-const cheerio = require('cheerio');
-
-const {
+import {readFileSync} from 'node:fs';
+import test from 'supertape';
+import montag from 'montag';
+import * as cheerio from 'cheerio';
+import {
_getSize,
getPathLink,
buildFromJSON,
-} = require('./cloudfunc');
+ _getDataName,
+} from './cloudfunc.mjs';
-const templatePath = join(__dirname, '../tmpl/fs');
+const templatePath = new URL('../tmpl/fs', import.meta.url).pathname;
const template = {
pathLink: readFileSync(`${templatePath}/pathLink.hbs`, 'utf8'),
@@ -175,3 +171,11 @@ test('cloudfunc: buildFromJSON: showDotFiles: false', (t) => {
t.equal(result, expected);
t.end();
});
+
+test('cloudfunc: _getDataName', (t) => {
+ const result = _getDataName('s');
+ const expected = 'data-name="js-file-cw==" ';
+
+ t.equal(result, expected);
+ t.end();
+});
diff --git a/common/datetime.spec.js b/common/datetime.spec.js
index db7a2483..cc321d8a 100644
--- a/common/datetime.spec.js
+++ b/common/datetime.spec.js
@@ -1,7 +1,7 @@
'use strict';
const test = require('supertape');
-const tryCatch = require('try-catch');
+const {tryCatch} = require('try-catch');
const datetime = require('./datetime');
@@ -16,11 +16,11 @@ test('common: datetime', (t) => {
});
test('common: datetime: no arg', (t) => {
- const {Date} = global;
+ const {Date} = globalThis;
let called = false;
- global.Date = class extends Date {
+ globalThis.Date = class extends Date {
constructor() {
super();
called = true;
@@ -29,7 +29,7 @@ test('common: datetime: no arg', (t) => {
datetime();
- global.Date = Date;
+ globalThis.Date = Date;
t.ok(called, 'should call new Date');
t.end();
diff --git a/common/try-to-promise-all.js b/common/try-to-promise-all.js
index 5c91b026..e839d27e 100644
--- a/common/try-to-promise-all.js
+++ b/common/try-to-promise-all.js
@@ -1,6 +1,6 @@
'use strict';
-const tryToCatch = require('try-to-catch');
+const {tryToCatch} = require('try-to-catch');
const all = Promise.all.bind(Promise);
module.exports = async (a) => {
diff --git a/common/util.spec.js b/common/util.spec.js
index ed15bd09..f62cb4ca 100644
--- a/common/util.spec.js
+++ b/common/util.spec.js
@@ -1,8 +1,7 @@
'use strict';
const test = require('supertape');
-const {reRequire} = require('mock-require');
-const tryCatch = require('try-catch');
+const {tryCatch} = require('try-catch');
const Util = require('./util');
const {
@@ -117,15 +116,3 @@ test('util: escapeRegExp', (t) => {
t.equal(escapeRegExp('#hello'), '\\#hello');
t.end();
});
-
-test('util: scope', (t) => {
- global.window = {};
-
- reRequire('./util');
-
- t.pass('should set window in scope');
-
- delete global.window;
-
- t.end();
-});
diff --git a/cssnano.config.js b/cssnano.config.mjs
similarity index 63%
rename from cssnano.config.js
rename to cssnano.config.mjs
index 91ae5f81..44abaeaf 100644
--- a/cssnano.config.js
+++ b/cssnano.config.mjs
@@ -1,9 +1,7 @@
-'use strict';
-
// used by OptimizeCssAssetsPlugin
-const defaultPreset = require('cssnano-preset-default');
+import defaultPreset from 'cssnano-preset-default';
-module.exports = defaultPreset({
+export default defaultPreset({
svgo: {
plugins: [{
convertPathData: false,
diff --git a/deno.json b/deno.json
new file mode 100644
index 00000000..64c1bde2
--- /dev/null
+++ b/deno.json
@@ -0,0 +1,14 @@
+{
+ "tasks": {
+ "start": "deno run -P=cloudcmd bin/cloudcmd.mjs"
+ },
+ "permissions": {
+ "cloudcmd": {
+ "env": true,
+ "read": true,
+ "sys": true,
+ "net": true,
+ "run": true
+ }
+ }
+}
diff --git a/eslint.config.mjs b/eslint.config.mjs
index ad22cf4a..cf7a6a2d 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -19,9 +19,6 @@ export const match = {
'bin/cloudcmd.js': {
'no-console': 'off',
},
- 'cssnano.config.js': {
- 'n/no-extraneous-require': 'off',
- },
};
export default defineConfig([
safeAlign, {
@@ -36,9 +33,7 @@ export default defineConfig([
}, {
files: ['{client,common,static}/**/*.js'],
languageOptions: {
- globals: {
- ...globals.browser,
- },
+ globals: globals.browser,
},
},
...matchToFlat(match),
diff --git a/html/index.html b/html/index.html
index 53429a06..0cfc73c5 100644
--- a/html/index.html
+++ b/html/index.html
@@ -42,5 +42,15 @@
+