From 9cebb2416fbd653c0f3d076a9eef2d5384430fba Mon Sep 17 00:00:00 2001 From: coderiaser Date: Sat, 17 Jan 2026 14:16:46 +0200 Subject: [PATCH] feature: client: dom: events: migrate to ESM --- client/dom/events/index.js | 198 ------------------------------ client/dom/events/index.mjs | 204 +++++++++++++++++++++++++++++++ client/dom/index.js | 2 +- client/key/index.js | 2 +- client/listeners/index.js | 13 +- client/modules/config/index.js | 2 +- client/modules/edit-file-vim.js | 2 +- client/modules/edit-names-vim.js | 2 +- client/modules/view/index.js | 2 +- package.json | 1 + 10 files changed, 215 insertions(+), 213 deletions(-) delete mode 100644 client/dom/events/index.js create mode 100644 client/dom/events/index.mjs 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..218d81b5 --- /dev/null +++ b/client/dom/events/index.mjs @@ -0,0 +1,204 @@ +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/index.js b/client/dom/index.js index 965f1972..0170b970 100644 --- a/client/dom/index.js +++ b/client/dom/index.js @@ -33,7 +33,7 @@ module.exports = DOM; DOM.uploadDirectory = require('./directory'); DOM.Buffer = require('./buffer'); -DOM.Events = require('./events'); +DOM.Events = require('./events/index.mjs'); const loadRemote = require('./load-remote'); const selectByPattern = require('./select-by-pattern'); diff --git a/client/key/index.js b/client/key/index.js index df55f035..45472061 100644 --- a/client/key/index.js +++ b/client/key/index.js @@ -5,7 +5,7 @@ const clipboard = require('@cloudcmd/clipboard'); const {fullstore} = require('fullstore'); const Buffer = require('../dom/buffer'); -const Events = require('../dom/events'); +const Events = require('../dom/events/index.mjs'); const KEY = require('./key'); const _vim = require('./vim'); diff --git a/client/listeners/index.js b/client/listeners/index.js index a953f1d7..1d5ad118 100644 --- a/client/listeners/index.js +++ b/client/listeners/index.js @@ -11,6 +11,7 @@ const clipboard = require('@cloudcmd/clipboard'); const getRange = require('./get-range'); const uploadFiles = require('../dom/upload-files'); const {FS} = require('../../common/cloudfunc.mjs'); +const Events = require('../dom/events/index.mjs'); const getIndex = currify(require('./get-index')); @@ -65,8 +66,6 @@ function header() { return /^js-(left|right)$/.test(el.dataset.name); }; - const {Events} = DOM; - Events.addClick(fm, (event) => { const el = event.target; const parent = el.parentElement; @@ -103,7 +102,6 @@ async function config() { } module.exports.initKeysPanel = () => { - const {Events} = DOM; const keysElement = DOM.getById('js-keyspanel'); if (!keysElement) @@ -150,7 +148,6 @@ const getPanel = (side) => { }; module.exports.setOnPanel = (side) => { - const {Events} = DOM; const panel = getPanel(side); const filesElement = DOM.getByDataName('js-files', panel); @@ -380,7 +377,6 @@ function getFilesRange(from, to) { } function contextMenu() { - const {Events} = DOM; const fm = DOM.getFM(); Events.addOnce('contextmenu', fm, (event) => { @@ -396,7 +392,6 @@ function contextMenu() { } function dragndrop() { - const {Events} = DOM; const panels = DOM.getByClassAll('panel'); const select = ({target}) => { target.classList.add('selected-panel'); @@ -457,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(); @@ -470,7 +465,7 @@ function unload() { } function pop() { - DOM.Events.add('popstate', async ({state}) => { + Events.add('popstate', async ({state}) => { const path = (state || '').replace(FS, ''); if (!path) @@ -485,7 +480,7 @@ function pop() { } function resize() { - DOM.Events.add('resize', () => { + Events.add('resize', () => { const Info = DOM.CurrentInfo; const is = globalThis.innerWidth < CloudCmd.MIN_ONE_PANEL_WIDTH; diff --git a/client/modules/config/index.js b/client/modules/config/index.js index a92594ef..ee4945cb 100644 --- a/client/modules/config/index.js +++ b/client/modules/config/index.js @@ -14,7 +14,7 @@ const createElement = require('@cloudcmd/create-element'); const input = require('./input'); const Images = require('../../dom/images'); -const Events = require('../../dom/events'); +const Events = require('../../dom/events/index.mjs'); const Files = require('../../dom/files'); const {getTitle} = require('../../../common/cloudfunc.mjs'); diff --git a/client/modules/edit-file-vim.js b/client/modules/edit-file-vim.js index 48cfd93e..227309b7 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/index.mjs'); const {Key} = CloudCmd; diff --git a/client/modules/edit-names-vim.js b/client/modules/edit-names-vim.js index 266dc9dc..55ad712a 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/index.mjs'); const {Key} = CloudCmd; const ConfigView = { diff --git a/client/modules/view/index.js b/client/modules/view/index.js index 5262f85a..94d492f1 100644 --- a/client/modules/view/index.js +++ b/client/modules/view/index.js @@ -26,7 +26,7 @@ const { } = require('./types'); const Files = require('../../dom/files'); -const Events = require('../../dom/events'); +const Events = require('../../dom/events/index.mjs'); const Images = require('../../dom/images'); const {encode} = require('../../../common/entity'); diff --git a/package.json b/package.json index 3cc979f3..2d142b68 100644 --- a/package.json +++ b/package.json @@ -180,6 +180,7 @@ "gunzip-maybe": "^1.3.1", "html-webpack-plugin": "^5.6.3", "inherits": "^2.0.3", + "itype": "^3.0.1", "just-capitalize": "^3.2.0", "just-pascal-case": "^3.2.0", "limier": "^3.0.0",