From 1503dcd6c8cc8a0418354891efd5895d8c19b8b4 Mon Sep 17 00:00:00 2001 From: nd0ut Date: Thu, 20 Jun 2024 22:51:04 +0300 Subject: [PATCH] chore: fix all biome warnings --- .lintstagedrc.json | 2 +- CHANGELOG.md | 3 +- abstract/ActivityBlock.js | 12 +- abstract/Block.js | 36 ++-- abstract/LocaleManager.js | 4 +- abstract/SolutionBlock.js | 6 +- abstract/TypedCollection.js | 38 ++-- abstract/TypedData.js | 8 +- abstract/UploaderBlock.js | 44 ++--- abstract/ValidationManager.js | 4 +- abstract/connectBlocksFrom.js | 4 +- abstract/l10nProcessor.js | 19 +- abstract/registerBlocks.js | 8 +- biome.json | 28 +-- blocks/CameraSource/CameraSource.js | 20 +- .../src/CloudImageEditorBlock.js | 10 +- blocks/CloudImageEditor/src/CropFrame.js | 134 ++++++------- .../src/EditorButtonControl.js | 4 +- .../src/EditorCropButtonControl.js | 6 +- .../src/EditorFilterControl.js | 36 ++-- .../src/EditorImageCropper.js | 176 +++++++++--------- .../CloudImageEditor/src/EditorImageFader.js | 121 ++++++------ .../src/EditorOperationControl.js | 8 +- blocks/CloudImageEditor/src/EditorScroller.js | 4 +- blocks/CloudImageEditor/src/EditorSlider.js | 14 +- blocks/CloudImageEditor/src/EditorToolbar.js | 81 ++++---- blocks/CloudImageEditor/src/crop-utils.js | 46 ++--- .../src/elements/line-loader/LineLoaderUi.js | 12 +- .../presence-toggle/PresenceToggle.js | 4 +- .../src/elements/slider/SliderUi.js | 50 ++--- .../CloudImageEditor/src/lib/FocusVisible.js | 5 +- .../src/lib/applyFocusVisiblePolyfill.js | 2 +- blocks/CloudImageEditor/src/lib/classNames.js | 8 +- blocks/CloudImageEditor/src/lib/linspace.js | 8 +- blocks/CloudImageEditor/src/lib/pick.js | 8 +- .../CloudImageEditor/src/lib/preloadImage.js | 22 +-- .../src/lib/transformationUtils.js | 4 +- blocks/CloudImageEditor/src/state.js | 14 +- blocks/CloudImageEditor/src/util.js | 6 +- .../CloudImageEditorActivity.js | 2 +- blocks/CloudImageEditorActivity/test.js | 2 +- blocks/Color/Color.js | 2 +- blocks/Config/Config.js | 12 +- .../ConfirmationDialog/ConfirmationDialog.js | 2 +- blocks/DropArea/DropArea.js | 12 +- blocks/DropArea/addDropzone.js | 58 +++--- blocks/DropArea/getDropItems.js | 12 +- blocks/EditableCanvas/CanMan.js | 23 +-- blocks/EditableCanvas/EditableCanvas.js | 8 +- .../EditableCanvas/EditableCanvasToolbar.js | 13 +- blocks/EditableCanvas/buttons.js | 2 + blocks/ExternalSource/ExternalSource.js | 8 +- blocks/ExternalSource/buildStyles.js | 16 +- blocks/ExternalSource/messages.js | 10 +- blocks/ExternalSource/query-string.js | 4 +- blocks/FileItem/FileItem.js | 46 ++--- blocks/FilePreview/FilePreview.js | 8 +- blocks/FormInput/FormInput.js | 2 +- blocks/Img/ImgBase.js | 95 +++++----- blocks/Img/ImgConfig.js | 24 +-- blocks/LiveHtml/LiveHtml.js | 28 +-- blocks/Modal/Modal.js | 2 +- blocks/ProgressBarCommon/ProgressBarCommon.js | 4 +- blocks/Range/Range.js | 10 +- blocks/Select/Select.js | 10 +- blocks/SourceBtn/SourceBtn.js | 6 +- blocks/SourceList/SourceList.js | 6 +- blocks/Tabs/Tabs.js | 18 +- blocks/UrlSource/UrlSource.js | 8 +- blocks/Video/Video.js | 64 ++++--- blocks/svg-backgrounds/svg-backgrounds.js | 2 +- blocks/utils/resizeImage.js | 12 +- blocks/utils/userAgent.js | 2 +- build-ssr-stubs.js | 21 ++- build-svg-sprite.js | 14 +- build.js | 35 ++-- demo/preview-proxy/secure-delivery-proxy.js | 14 +- package.json | 8 +- ship.config.mjs | 8 +- .../inline/FileUploaderInline.js | 2 +- .../regular/FileUploaderRegular.js | 2 +- stylelint-force-app-name-prefix.cjs | 130 +++++++------ test-locales.js | 4 +- types/events.d.ts | 2 +- types/exported.d.ts | 120 ++++++------ types/global.d.ts | 2 +- types/index.d.ts | 4 +- types/jsx.d.ts | 69 +++---- types/test/lr-config.test-d.tsx | 26 ++- types/test/lr-form-input.test-d.tsx | 2 +- types/test/lr-upload-ctx-provider.test-d.tsx | 24 +-- utils/WindowHeightTracker.js | 19 +- utils/cdn-utils.js | 46 ++--- utils/cdn-utils.test.js | 14 +- utils/fileTypes.js | 11 +- utils/fileTypes.test.js | 2 +- utils/getPluralForm.test.js | 2 +- utils/isSecureTokenExpired.test.js | 2 +- utils/memoize.test.js | 2 +- utils/parseCdnUrl.test.js | 2 +- utils/parseShrink.test.js | 2 +- utils/prettyBytes.test.js | 2 +- utils/template-utils.js | 8 +- utils/template-utils.test.js | 8 +- utils/wildcardRegexp.js | 8 +- 105 files changed, 1083 insertions(+), 1084 deletions(-) diff --git a/.lintstagedrc.json b/.lintstagedrc.json index 94d1d5acc..b8277fcbd 100644 --- a/.lintstagedrc.json +++ b/.lintstagedrc.json @@ -1,5 +1,5 @@ { - "*.{js,cjs}": ["biome format --write", "git add"], + "*.{js,cjs}": ["biome check --write", "git add"], "*.css": ["stylelint --fix", "prettier --write --parser css", "git add"], "*.json": ["prettier --write --parser json", "git add"], "*.md": ["prettier --write --parser markdown", "git add"] diff --git a/CHANGELOG.md b/CHANGELOG.md index 6aafccbb5..a36b0c793 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,7 @@ ### Features -- added `collectionValidators` and `fileValidators`: Custom validators are now supported for collections and files. This enhancement allows for the addition of necessary checks for uploaded files and collections, providing flexibility and control over compliance with requirements ([#667](https://github.com/uploadcare/blocks/issues/667)) ([d3260b0](https://github.com/uploadcare/blocks/commit/d3260b0cce5ac6ca7cfd0aeb8aff0c9fc35036ed)). See docs [here](https://uploadcare.com/docs/file-uploader/validators). - +- added `collectionValidators` and `fileValidators`: Custom validators are now supported for collections and files. This enhancement allows for the addition of necessary checks for uploaded files and collections, providing flexibility and control over compliance with requirements ([#667](https://github.com/uploadcare/blocks/issues/667)) ([d3260b0](https://github.com/uploadcare/blocks/commit/d3260b0cce5ac6ca7cfd0aeb8aff0c9fc35036ed)). See docs [here](https://uploadcare.com/docs/file-uploader/validators). ## [0.42.1](https://github.com/uploadcare/blocks/compare/v0.42.0...v0.42.1) (2024-05-30) diff --git a/abstract/ActivityBlock.js b/abstract/ActivityBlock.js index 99e0c453d..7e6b742bf 100644 --- a/abstract/ActivityBlock.js +++ b/abstract/ActivityBlock.js @@ -1,6 +1,6 @@ +import { EventType } from '../blocks/UploadCtxProvider/EventEmitter.js'; // @ts-check import { debounce } from '../blocks/utils/debounce.js'; -import { EventType } from '../blocks/UploadCtxProvider/EventEmitter.js'; import { Block } from './Block.js'; import { activityBlockCtx } from './CTX.js'; @@ -15,7 +15,7 @@ export class ActivityBlock extends Block { /** @private */ _deactivate() { - let actDesc = ActivityBlock._activityCallbacks.get(this); + const actDesc = ActivityBlock._activityCallbacks.get(this); this[ACTIVE_PROP] = false; this.removeAttribute(ACTIVE_ATTR); actDesc?.deactivateCallback?.(); @@ -23,7 +23,7 @@ export class ActivityBlock extends Block { /** @private */ _activate() { - let actDesc = ActivityBlock._activityCallbacks.get(this); + const actDesc = ActivityBlock._activityCallbacks.get(this); this.$['*historyBack'] = this.historyBack.bind(this); /** @private */ this[ACTIVE_PROP] = true; @@ -139,7 +139,7 @@ export class ActivityBlock extends Block { const currentActivity = this.$['*currentActivity']; /** @type {Set} */ - let blocksRegistry = this.$['*blocksRegistry']; + const blocksRegistry = this.$['*blocksRegistry']; const hasCurrentActivityInCtx = !![...blocksRegistry].find( (block) => block instanceof ActivityBlock && block.activityType === currentActivity, ); @@ -169,7 +169,7 @@ export class ActivityBlock extends Block { historyBack() { /** @type {String[]} */ - let history = this.$['*history']; + const history = this.$['*history']; if (history) { let nextActivity = history.pop(); while (nextActivity === this.activityType) { @@ -178,7 +178,7 @@ export class ActivityBlock extends Block { let couldOpenActivity = !!nextActivity; if (nextActivity) { /** @type {Set} */ - let blocksRegistry = this.$['*blocksRegistry']; + const blocksRegistry = this.$['*blocksRegistry']; const nextActivityBlock = [...blocksRegistry].find((block) => block.activityType === nextActivity); couldOpenActivity = nextActivityBlock?.couldOpenActivity ?? false; } diff --git a/abstract/Block.js b/abstract/Block.js index 1546c8a5c..44e68d399 100644 --- a/abstract/Block.js +++ b/abstract/Block.js @@ -3,7 +3,7 @@ import { BaseComponent, Data } from '@symbiotejs/symbiote'; import { initialConfig } from '../blocks/Config/initialConfig.js'; import { EventEmitter } from '../blocks/UploadCtxProvider/EventEmitter.js'; import { WindowHeightTracker } from '../utils/WindowHeightTracker.js'; -import { extractFilename, extractCdnUrlModifiers, extractUuid } from '../utils/cdn-utils.js'; +import { extractCdnUrlModifiers, extractFilename, extractUuid } from '../utils/cdn-utils.js'; import { getLocaleDirection } from '../utils/getLocaleDirection.js'; import { getPluralForm } from '../utils/getPluralForm.js'; import { applyTemplateData, getPluralObjects } from '../utils/template-utils.js'; @@ -36,15 +36,15 @@ export class Block extends BaseComponent { if (!str) { return ''; } - let template = this.$[localeStateKey(str)] || str; - let pluralObjects = getPluralObjects(template); - for (let pluralObject of pluralObjects) { + const template = this.$[localeStateKey(str)] || str; + const pluralObjects = getPluralObjects(template); + for (const pluralObject of pluralObjects) { variables[pluralObject.variable] = this.pluralize( pluralObject.pluralKey, Number(variables[pluralObject.countVariable]), ); } - let result = applyTemplateData(template, variables); + const result = applyTemplateData(template, variables); return result; } @@ -96,8 +96,8 @@ export class Block extends BaseComponent { hasBlockInCtx(callback) { // @ts-ignore TODO: fix this /** @type {Set} */ - let blocksRegistry = this.$['*blocksRegistry']; - for (let block of blocksRegistry) { + const blocksRegistry = this.$['*blocksRegistry']; + for (const block of blocksRegistry) { if (callback(block)) { return true; } @@ -135,7 +135,7 @@ export class Block extends BaseComponent { if (this.hasAttribute('retpl')) { // @ts-ignore TODO: fix this - this.constructor['template'] = null; + this.constructor.template = null; this.processInnerHtml = true; } if (this.requireCtxName) { @@ -168,7 +168,7 @@ export class Block extends BaseComponent { this.add('*blocksRegistry', new Set()); } - let blocksRegistry = this.$['*blocksRegistry']; + const blocksRegistry = this.$['*blocksRegistry']; blocksRegistry.add(this); if (!this.has('*eventEmitter')) { @@ -190,7 +190,7 @@ export class Block extends BaseComponent { destroyCallback() { /** @type {Set} */ - let blocksRegistry = this.$['*blocksRegistry']; + const blocksRegistry = this.$['*blocksRegistry']; blocksRegistry.delete(this); this.localeManager?.destroyL10nBindings(this); @@ -224,7 +224,7 @@ export class Block extends BaseComponent { * @param {Number} [decimals] */ fileSizeFmt(bytes, decimals = 2) { - let units = ['B', 'KB', 'MB', 'GB', 'TB']; + const units = ['B', 'KB', 'MB', 'GB', 'TB']; /** * @param {String} str * @returns {String} @@ -232,10 +232,10 @@ export class Block extends BaseComponent { if (bytes === 0) { return `0 ${units[0]}`; } - let k = 1024; - let dm = decimals < 0 ? 0 : decimals; - let i = Math.floor(Math.log(bytes) / Math.log(k)); - return parseFloat((bytes / k ** i).toFixed(dm)) + ' ' + units[i]; + const k = 1024; + const dm = decimals < 0 ? 0 : decimals; + const i = Math.floor(Math.log(bytes) / Math.log(k)); + return `${Number.parseFloat((bytes / k ** i).toFixed(dm))} ${units[i]}`; } /** @@ -268,7 +268,7 @@ export class Block extends BaseComponent { /** @returns {import('../types').ConfigType} } */ get cfg() { if (!this.__cfgProxy) { - let o = Object.create(null); + const o = Object.create(null); /** @private */ this.__cfgProxy = new Proxy(o, { set: (obj, key, value) => { @@ -327,10 +327,10 @@ export class Block extends BaseComponent { /** @param {String} [name] */ static reg(name) { if (!name) { - super.reg(); + Block.reg(); return; } - super.reg(name.startsWith(TAG_PREFIX) ? name : TAG_PREFIX + name); + Block.reg(name.startsWith(TAG_PREFIX) ? name : TAG_PREFIX + name); } } diff --git a/abstract/LocaleManager.js b/abstract/LocaleManager.js index 93054dec0..4815bcdc7 100644 --- a/abstract/LocaleManager.js +++ b/abstract/LocaleManager.js @@ -1,7 +1,7 @@ // @ts-check import { debounce } from '../blocks/utils/debounce.js'; -import { resolveLocaleDefinition } from './localeRegistry.js'; import { default as en } from '../locales/file-uploader/en.js'; +import { resolveLocaleDefinition } from './localeRegistry.js'; /** @param {string} key */ export const localeStateKey = (key) => `*l10n/${key}`; @@ -33,7 +33,7 @@ export class LocaleManager { constructor(blockInstance) { this._blockInstance = blockInstance; - for (let [key, value] of Object.entries(en)) { + for (const [key, value] of Object.entries(en)) { this._blockInstance.add(localeStateKey(key), value, false); } diff --git a/abstract/SolutionBlock.js b/abstract/SolutionBlock.js index d0d5ed423..112ed3dd2 100644 --- a/abstract/SolutionBlock.js +++ b/abstract/SolutionBlock.js @@ -1,6 +1,6 @@ -import { uploaderBlockCtx } from './CTX.js'; import svgIconsSprite from '../blocks/themes/lr-basic/svg-sprite.js'; import { Block } from './Block.js'; +import { uploaderBlockCtx } from './CTX.js'; export class SolutionBlock extends Block { requireCtxName = true; @@ -8,10 +8,10 @@ export class SolutionBlock extends Block { _template = null; static set template(value) { - this._template = svgIconsSprite + value + /** HTML */ ``; + SolutionBlock._template = `${svgIconsSprite + value}`; } static get template() { - return this._template; + return SolutionBlock._template; } } diff --git a/abstract/TypedCollection.js b/abstract/TypedCollection.js index a5a871529..9020870c6 100644 --- a/abstract/TypedCollection.js +++ b/abstract/TypedCollection.js @@ -81,9 +81,9 @@ export class TypedCollection { if (Object.keys(changeMap).length === 0) { return; } - this.__propertyObservers.forEach((handler) => { + for (const handler of this.__propertyObservers) { handler({ ...changeMap }); - }); + } changeMap = Object.create(null); }); }; @@ -95,8 +95,8 @@ export class TypedCollection { } /** @private */ this.__notifyTimeout = window.setTimeout(() => { - let added = new Set(this.__added); - let removed = new Set(this.__removed); + const added = new Set(this.__added); + const removed = new Set(this.__removed); this.__added.clear(); this.__removed.clear(); for (const handler of this.__collectionObservers) { @@ -128,8 +128,8 @@ export class TypedCollection { * @returns {string} */ add(init) { - let item = new TypedData(this.__typedSchema); - for (let prop in init) { + const item = new TypedData(this.__typedSchema); + for (const prop in init) { item.setValue(prop, init[prop]); } this.__items.add(item.uid); @@ -137,7 +137,7 @@ export class TypedCollection { this.__data.add(item.uid, item); this.__added.add(item); - this.__watchList.forEach((propName) => { + for (const propName of this.__watchList) { if (!this.__subsMap[item.uid]) { this.__subsMap[item.uid] = []; } @@ -146,7 +146,7 @@ export class TypedCollection { this.__notifyObservers(propName, item.uid); }), ); - }); + } return item.uid; } @@ -164,7 +164,7 @@ export class TypedCollection { * @returns {any} */ readProp(id, propName) { - let item = this.read(id); + const item = this.read(id); return item.getValue(propName); } @@ -175,7 +175,7 @@ export class TypedCollection { * @param {T} value */ publishProp(id, propName, value) { - let item = this.read(id); + const item = this.read(id); item.setValue(propName, value); } @@ -189,9 +189,9 @@ export class TypedCollection { } clearAll() { - this.__items.forEach((id) => { + for (const id of this.__items) { this.remove(id); - }); + } } /** @param {Function} handler */ @@ -213,13 +213,13 @@ export class TypedCollection { * @returns {String[]} */ findItems(checkFn) { - let result = []; - this.__items.forEach((id) => { - let item = this.read(id); + const result = []; + for (const id of this.__items) { + const item = this.read(id); if (checkFn(item)) { result.push(id); } - }); + } return result; } @@ -235,10 +235,10 @@ export class TypedCollection { Data.deleteCtx(this.__ctxId); this.__propertyObservers = null; this.__collectionObservers = null; - for (let id in this.__subsMap) { - this.__subsMap[id].forEach((sub) => { + for (const id in this.__subsMap) { + for (const sub of this.__subsMap[id]) { sub.remove(); - }); + } delete this.__subsMap[id]; } } diff --git a/abstract/TypedData.js b/abstract/TypedData.js index af7f1039f..a10e2ff24 100644 --- a/abstract/TypedData.js +++ b/abstract/TypedData.js @@ -35,11 +35,11 @@ export class TypedData { * @param {any} value */ setValue(prop, value) { - if (!this.__typedSchema.hasOwnProperty(prop)) { + if (!Object.hasOwn(this.__typedSchema, prop)) { console.warn(MSG_NAME + prop); return; } - let pDesc = this.__typedSchema[prop]; + const pDesc = this.__typedSchema[prop]; if (value?.constructor === pDesc.type || value instanceof pDesc.type || (pDesc.nullable && value === null)) { this.__data.pub(prop, value); return; @@ -49,14 +49,14 @@ export class TypedData { /** @param {Object} updObj */ setMultipleValues(updObj) { - for (let prop in updObj) { + for (const prop in updObj) { this.setValue(prop, updObj[prop]); } } /** @param {String} prop */ getValue(prop) { - if (!this.__typedSchema.hasOwnProperty(prop)) { + if (!Object.hasOwn(this.__typedSchema, prop)) { console.warn(MSG_NAME + prop); return undefined; } diff --git a/abstract/UploaderBlock.js b/abstract/UploaderBlock.js index fadb23975..ed7efbb72 100644 --- a/abstract/UploaderBlock.js +++ b/abstract/UploaderBlock.js @@ -12,15 +12,15 @@ import { debounce } from '../blocks/utils/debounce.js'; import { customUserAgent } from '../blocks/utils/userAgent.js'; import { createCdnUrl, createCdnUrlModifiers } from '../utils/cdn-utils.js'; import { IMAGE_ACCEPT_LIST, fileIsImage, mergeFileTypes } from '../utils/fileTypes.js'; +import { parseCdnUrl } from '../utils/parseCdnUrl.js'; import { stringToArray } from '../utils/stringToArray.js'; import { warnOnce } from '../utils/warnOnce.js'; import { uploaderBlockCtx } from './CTX.js'; +import { SecureUploadsManager } from './SecureUploadsManager.js'; import { TypedCollection } from './TypedCollection.js'; +import { ValidationManager } from './ValidationManager.js'; import { buildOutputCollectionState } from './buildOutputCollectionState.js'; import { uploadEntrySchema } from './uploadEntrySchema.js'; -import { parseCdnUrl } from '../utils/parseCdnUrl.js'; -import { SecureUploadsManager } from './SecureUploadsManager.js'; -import { ValidationManager } from './ValidationManager.js'; export class UploaderBlock extends ActivityBlock { couldBeCtxOwner = false; @@ -67,7 +67,7 @@ export class UploaderBlock extends ActivityBlock { super.initCallback(); if (!this.$['*uploadCollection']) { - let uploadCollection = new TypedCollection({ + const uploadCollection = new TypedCollection({ typedSchema: uploadEntrySchema, watchList: ['uploadProgress', 'uploadError', 'fileInfo', 'errors', 'cdnUrl', 'isUploading'], }); @@ -246,7 +246,9 @@ export class UploaderBlock extends ActivityBlock { /** @param {{ captureCamera?: boolean }} options */ openSystemDialog(options = {}) { - let accept = serializeCsv(mergeFileTypes([this.cfg.accept ?? '', ...(this.cfg.imgOnly ? IMAGE_ACCEPT_LIST : [])])); + const accept = serializeCsv( + mergeFileTypes([this.cfg.accept ?? '', ...(this.cfg.imgOnly ? IMAGE_ACCEPT_LIST : [])]), + ); if (this.cfg.accept && !!this.cfg.imgOnly) { console.warn( @@ -267,14 +269,15 @@ export class UploaderBlock extends ActivityBlock { this.fileInput.dispatchEvent(new MouseEvent('click')); this.fileInput.onchange = () => { // @ts-ignore TODO: fix this - [...this.fileInput['files']].forEach((file) => - this.addFileFromObject(file, { source: options.captureCamera ? UploadSource.CAMERA : UploadSource.LOCAL }), - ); + for (const file of [...this.fileInput.files]) { + this.addFileFromObject(file, { source: options.captureCamera ? UploadSource.CAMERA : UploadSource.LOCAL }); + } + // To call uploadTrigger UploadList should draw file items first: this.$['*currentActivity'] = ActivityBlock.activities.UPLOAD_LIST; this.setOrAddState('*modalActive', true); // @ts-ignore TODO: fix this - this.fileInput['value'] = ''; + this.fileInput.value = ''; this.fileInput = null; }; } @@ -304,7 +307,7 @@ export class UploaderBlock extends ActivityBlock { // TODO: We should refactor those handlers if (srcKey === 'local') { this.$['*currentActivity'] = ActivityBlock.activities.UPLOAD_LIST; - this?.['openSystemDialog'](); + this?.openSystemDialog(); return; } @@ -439,8 +442,7 @@ export class UploaderBlock extends ActivityBlock { ...new Set( Object.entries(changeMap) .filter(([key]) => ['uploadError', 'fileInfo'].includes(key)) - .map(([, ids]) => [...ids]) - .flat(), + .flatMap(([, ids]) => [...ids]), ), ]; @@ -478,10 +480,10 @@ export class UploaderBlock extends ActivityBlock { if (this.cfg.cropPreset) { this.setInitialCrop(); } - let loadedItems = uploadCollection.findItems((entry) => { + const loadedItems = uploadCollection.findItems((entry) => { return !!entry.getValue('fileInfo'); }); - let errorItems = uploadCollection.findItems((entry) => { + const errorItems = uploadCollection.findItems((entry) => { return entry.getValue('errors').length > 0; }); if (errorItems.length === 0 && uploadCollection.size === loadedItems.length) { @@ -508,9 +510,9 @@ export class UploaderBlock extends ActivityBlock { const uids = [...changeMap.cdnUrl].filter((uid) => { return !!this.uploadCollection.read(uid)?.getValue('cdnUrl'); }); - uids.forEach((uid) => { + for (const uid of uids) { this.emit(EventType.FILE_URL_CHANGED, this.getOutputItem(uid)); - }); + } this.$['*groupInfo'] = null; } @@ -522,10 +524,10 @@ export class UploaderBlock extends ActivityBlock { /** @type {Set} */ const uploadTrigger = this.$['*uploadTrigger']; const items = [...uploadTrigger].filter((id) => !!this.uploadCollection.read(id)); - items.forEach((id) => { + for (const id of items) { const uploadProgress = this.uploadCollection.readProp(id, 'uploadProgress'); commonProgress += uploadProgress; - }); + } const progress = items.length ? Math.round(commonProgress / items.length) : 0; if (this.$['*commonProgress'] === progress) { @@ -599,7 +601,7 @@ export class UploaderBlock extends ActivityBlock { const secureUploadsManager = this.$['*secureUploadsManager']; const secureToken = await secureUploadsManager.getSecureToken().catch(() => null); - let options = { + const options = { store: this.cfg.store, publicKey: this.cfg.pubkey, baseCDN: this.cfg.cdnCname, @@ -632,11 +634,11 @@ export class UploaderBlock extends ActivityBlock { const fileInfo = uploadEntryData.fileInfo; /** @type {import('../types').OutputFileEntry['status']} */ - let status = uploadEntryData.isRemoved + const status = uploadEntryData.isRemoved ? 'removed' : uploadEntryData.errors.length > 0 ? 'failed' - : !!uploadEntryData.fileInfo + : uploadEntryData.fileInfo ? 'success' : uploadEntryData.isUploading ? 'uploading' diff --git a/abstract/ValidationManager.js b/abstract/ValidationManager.js index 045573bfa..584bfadb1 100644 --- a/abstract/ValidationManager.js +++ b/abstract/ValidationManager.js @@ -1,12 +1,12 @@ // @ts-check import { EventType } from '../blocks/UploadCtxProvider/EventEmitter.js'; +import { validateCollectionUploadError, validateMultiple } from '../utils/validators/collection/index.js'; import { - validateIsImage, validateFileType, + validateIsImage, validateMaxSizeLimit, validateUploadError, } from '../utils/validators/file/index.js'; -import { validateMultiple, validateCollectionUploadError } from '../utils/validators/collection/index.js'; /** * @typedef {( diff --git a/abstract/connectBlocksFrom.js b/abstract/connectBlocksFrom.js index 43101596b..9efed34cb 100644 --- a/abstract/connectBlocksFrom.js +++ b/abstract/connectBlocksFrom.js @@ -17,7 +17,7 @@ export async function connectBlocksFrom(url, register = false) { resolve(window[LR_WINDOW_KEY]); return; } - let script = document.createElement('script'); + const script = document.createElement('script'); script.async = true; script.src = url; script.onerror = () => { @@ -25,7 +25,7 @@ export async function connectBlocksFrom(url, register = false) { }; script.onload = () => { /** @type {import('../index.js')} */ - let blocks = window[LR_WINDOW_KEY]; + const blocks = window[LR_WINDOW_KEY]; register && registerBlocks(blocks); resolve(blocks); }; diff --git a/abstract/l10nProcessor.js b/abstract/l10nProcessor.js index 43076a19f..380eded2c 100644 --- a/abstract/l10nProcessor.js +++ b/abstract/l10nProcessor.js @@ -8,7 +8,7 @@ import { localeStateKey } from './LocaleManager.js'; * @param {T} fnCtx */ export function l10nProcessor(fr, fnCtx) { - [...fr.querySelectorAll('[l10n]')].forEach((el) => { + for (const el of fr.querySelectorAll('[l10n]')) { let key = el.getAttribute('l10n'); if (!key) { return; @@ -36,15 +36,12 @@ export function l10nProcessor(fr, fnCtx) { if (!fnCtx.l10nProcessorSubs.has(localCtxKey)) { fnCtx.l10nProcessorSubs.set(localCtxKey, new Set()); } - const keySubs = fnCtx.l10nProcessorSubs.get(localCtxKey); - keySubs?.forEach( - /** @param {{ remove: () => void }} sub */ - (sub) => { - sub.remove(); - keySubs.delete(sub); - fnCtx.allSubs.delete(sub); - }, - ); + const keySubs = fnCtx.l10nProcessorSubs.get(localCtxKey) ?? new Set(); + for (const sub of keySubs) { + sub.remove(); + keySubs.delete(sub); + fnCtx.allSubs.delete(sub); + } // We don't need the leading * in the key because we use the key as a local context key relative to the global state const nodeStateKey = localeStateKey(mappedKey).replace('*', ''); // If the key is not present in the node context, add it @@ -76,5 +73,5 @@ export function l10nProcessor(fr, fnCtx) { } }); el.removeAttribute('l10n'); - }); + } } diff --git a/abstract/registerBlocks.js b/abstract/registerBlocks.js index 44d0cb2ac..f8201a85f 100644 --- a/abstract/registerBlocks.js +++ b/abstract/registerBlocks.js @@ -1,17 +1,17 @@ /** @param {Object} blockExports */ export function registerBlocks(blockExports) { - for (let blockName in blockExports) { + for (const blockName in blockExports) { let tagName = [...blockName].reduce((name, char) => { if (char.toUpperCase() === char) { - char = '-' + char.toLowerCase(); + return `${name}-${char.toLowerCase()}`; } - return (name += char); + return `${name}${char}`; }, ''); if (tagName.startsWith('-')) { tagName = tagName.replace('-', ''); } if (!tagName.startsWith('lr-')) { - tagName = 'lr-' + tagName; + tagName = `lr-${tagName}`; } if (blockExports[blockName].reg) { blockExports[blockName].reg(tagName); diff --git a/biome.json b/biome.json index 8786af293..e6f7a2f8c 100644 --- a/biome.json +++ b/biome.json @@ -10,27 +10,15 @@ "attributePosition": "auto", "ignore": ["**/web", "**/package-lock.json"] }, - "organizeImports": { "enabled": true }, + "organizeImports": { + "enabled": true + }, "linter": { "enabled": true, "rules": { - "recommended": false, - "complexity": { "useLiteralKeys": "off" }, - "correctness": { "noUnusedVariables": "warn" }, - "style": { - "noParameterAssign": "off", - "useBlockStatements": "off", - "useConst": "off", - "useSingleVarDeclarator": "off", - "useTemplate": "off" - }, - "suspicious": { - "noConsoleLog": "off", - "noDuplicateObjectKeys": "error", - "noPrototypeBuiltins": "off" - } + "recommended": true }, - "ignore": ["**/web"] + "ignore": ["**/web", "index.ssr.js"] }, "javascript": { "formatter": { @@ -45,5 +33,9 @@ "attributePosition": "auto" } }, - "overrides": [{ "include": ["*.js"] }] + "overrides": [ + { + "include": ["*.js"] + } + ] } diff --git a/blocks/CameraSource/CameraSource.js b/blocks/CameraSource/CameraSource.js index af01923aa..616baec9a 100644 --- a/blocks/CameraSource/CameraSource.js +++ b/blocks/CameraSource/CameraSource.js @@ -1,8 +1,8 @@ -import { UploaderBlock } from '../../abstract/UploaderBlock.js'; import { ActivityBlock } from '../../abstract/ActivityBlock.js'; +import { UploaderBlock } from '../../abstract/UploaderBlock.js'; +import { UploadSource } from '../utils/UploadSource.js'; import { canUsePermissionsApi } from '../utils/abilities.js'; import { debounce } from '../utils/debounce.js'; -import { UploadSource } from '../utils/UploadSource.js'; export class CameraSource extends UploaderBlock { couldBeCtxOwner = true; @@ -98,7 +98,7 @@ export class CameraSource extends UploaderBlock { async _subscribePermissions() { try { // @ts-ignore - let permissionsResponse = await navigator.permissions.query({ name: 'camera' }); + const permissionsResponse = await navigator.permissions.query({ name: 'camera' }); permissionsResponse.addEventListener('change', this._handlePermissionsChange); } catch (err) { console.log('Failed to use permissions API. Fallback to manual request mode.', err); @@ -108,7 +108,7 @@ export class CameraSource extends UploaderBlock { /** @private */ async _capture() { - let constr = { + const constr = { video: { width: { ideal: 1920, @@ -134,7 +134,7 @@ export class CameraSource extends UploaderBlock { try { this._setPermissionsState('prompt'); - let stream = await navigator.mediaDevices.getUserMedia(constr); + const stream = await navigator.mediaDevices.getUserMedia(constr); stream.addEventListener('inactive', () => { this._setPermissionsState('denied'); }); @@ -159,15 +159,15 @@ export class CameraSource extends UploaderBlock { /** @private */ _shot() { - this._canvas.height = this.ref.video['videoHeight']; - this._canvas.width = this.ref.video['videoWidth']; + this._canvas.height = this.ref.video.videoHeight; + this._canvas.width = this.ref.video.videoWidth; // @ts-ignore this._ctx.drawImage(this.ref.video, 0, 0); const date = Date.now(); const name = `camera-${date}.jpeg`; const format = 'image/jpeg'; this._canvas.toBlob((blob) => { - let file = new File([blob], name, { + const file = new File([blob], name, { lastModified: date, type: format, }); @@ -190,8 +190,8 @@ export class CameraSource extends UploaderBlock { }); try { - let deviceList = await navigator.mediaDevices.enumerateDevices(); - let cameraSelectOptions = deviceList + const deviceList = await navigator.mediaDevices.enumerateDevices(); + const cameraSelectOptions = deviceList .filter((info) => { return info.kind === 'videoinput'; }) diff --git a/blocks/CloudImageEditor/src/CloudImageEditorBlock.js b/blocks/CloudImageEditor/src/CloudImageEditorBlock.js index e99f38acc..46c340647 100644 --- a/blocks/CloudImageEditor/src/CloudImageEditorBlock.js +++ b/blocks/CloudImageEditor/src/CloudImageEditorBlock.js @@ -154,7 +154,7 @@ export class CloudImageEditorBlock extends Block { }); this.sub('src', (src) => { - let el = this.ref['img-el']; + const el = this.ref['img-el']; if (el.src !== src) { this._imgLoading = true; el.src = src || TRANSPARENT_PIXEL_SRC; @@ -192,12 +192,12 @@ export class CloudImageEditorBlock extends Block { if (Object.keys(transformations).length === 0) { return; } - let originalUrl = this.$['*originalUrl']; - let cdnUrlModifiers = createCdnUrlModifiers(transformationsToOperations(transformations), 'preview'); - let cdnUrl = createCdnUrl(originalUrl, cdnUrlModifiers); + const originalUrl = this.$['*originalUrl']; + const cdnUrlModifiers = createCdnUrlModifiers(transformationsToOperations(transformations), 'preview'); + const cdnUrl = createCdnUrl(originalUrl, cdnUrlModifiers); /** @type {import('./types.js').ApplyResult} */ - let eventData = { + const eventData = { originalUrl, cdnUrlModifiers, cdnUrl, diff --git a/blocks/CloudImageEditor/src/CropFrame.js b/blocks/CloudImageEditor/src/CropFrame.js index 26e483216..d001184c7 100644 --- a/blocks/CloudImageEditor/src/CropFrame.js +++ b/blocks/CloudImageEditor/src/CropFrame.js @@ -49,7 +49,7 @@ export class CropFrame extends Block { * @param {import('./types.js').Direction} direction */ _shouldThumbBeDisabled(direction) { - let imageBox = this.$['*imageBox']; + const imageBox = this.$['*imageBox']; if (!imageBox) { return; } @@ -58,30 +58,30 @@ export class CropFrame extends Block { return true; } - let tooHigh = imageBox.height <= MIN_CROP_SIZE && (direction.includes('n') || direction.includes('s')); - let tooWide = imageBox.width <= MIN_CROP_SIZE && (direction.includes('e') || direction.includes('w')); + const tooHigh = imageBox.height <= MIN_CROP_SIZE && (direction.includes('n') || direction.includes('s')); + const tooWide = imageBox.width <= MIN_CROP_SIZE && (direction.includes('e') || direction.includes('w')); return tooHigh || tooWide; } /** @private */ _createBackdrop() { /** @type {import('./types.js').Rectangle} */ - let cropBox = this.$['*cropBox']; + const cropBox = this.$['*cropBox']; if (!cropBox) { return; } - let { x, y, width, height } = cropBox; - let svg = this.ref['svg-el']; + const { x, y, width, height } = cropBox; + const svg = this.ref['svg-el']; - let mask = createSvgNode('mask', { id: 'backdrop-mask' }); - let maskRectOuter = createSvgNode('rect', { + const mask = createSvgNode('mask', { id: 'backdrop-mask' }); + const maskRectOuter = createSvgNode('rect', { x: 0, y: 0, width: '100%', height: '100%', fill: 'white', }); - let maskRectInner = createSvgNode('rect', { + const maskRectInner = createSvgNode('rect', { x, y, width, @@ -91,7 +91,7 @@ export class CropFrame extends Block { mask.appendChild(maskRectOuter); mask.appendChild(maskRectInner); - let backdropRect = createSvgNode('rect', { + const backdropRect = createSvgNode('rect', { x: 0, y: 0, width: '100%', @@ -126,11 +126,11 @@ export class CropFrame extends Block { /** @private */ _updateBackdrop() { /** @type {import('./types.js').Rectangle} */ - let cropBox = this.$['*cropBox']; + const cropBox = this.$['*cropBox']; if (!cropBox) { return; } - let { x, y, width, height } = cropBox; + const { x, y, width, height } = cropBox; this._backdropMaskInner && setSvgNodeAttrs(this._backdropMaskInner, { x, y, width, height }); } @@ -138,16 +138,16 @@ export class CropFrame extends Block { /** @private */ _updateFrame() { /** @type {import('./types.js').Rectangle} */ - let cropBox = this.$['*cropBox']; + const cropBox = this.$['*cropBox']; if (!cropBox || !this._frameGuides || !this._frameThumbs) { return; } - for (let thumb of Object.values(this._frameThumbs)) { - let { direction, pathNode, interactionNode, groupNode } = thumb; - let isCenter = direction === ''; - let isCorner = direction.length === 2; - let { x, y, width, height } = cropBox; + for (const thumb of Object.values(this._frameThumbs)) { + const { direction, pathNode, interactionNode, groupNode } = thumb; + const isCenter = direction === ''; + const isCorner = direction.length === 2; + const { x, y, width, height } = cropBox; if (isCenter) { const moveThumbRect = { @@ -164,7 +164,7 @@ export class CropFrame extends Block { 1, ); - let { d, center } = isCorner + const { d, center } = isCorner ? cornerPath(cropBox, direction, thumbSizeMultiplier) : sidePath( cropBox, @@ -184,7 +184,7 @@ export class CropFrame extends Block { setSvgNodeAttrs(pathNode, { d }); } - let disableThumb = this._shouldThumbBeDisabled(direction); + const disableThumb = this._shouldThumbBeDisabled(direction); groupNode.setAttribute( 'class', classNames('thumb', { @@ -218,14 +218,14 @@ export class CropFrame extends Block { for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { - let direction = /** @type {import('./types.js').Direction} */ (`${['n', '', 's'][i]}${['w', '', 'e'][j]}`); - let groupNode = createSvgNode('g'); + const direction = /** @type {import('./types.js').Direction} */ (`${['n', '', 's'][i]}${['w', '', 'e'][j]}`); + const groupNode = createSvgNode('g'); groupNode.classList.add('thumb'); groupNode.setAttribute('with-effects', ''); - let interactionNode = createSvgNode('rect', { + const interactionNode = createSvgNode('rect', { fill: 'transparent', }); - let pathNode = createSvgNode('path', { + const pathNode = createSvgNode('path', { stroke: 'currentColor', fill: 'none', 'stroke-width': THUMB_STROKE_WIDTH, @@ -248,9 +248,9 @@ export class CropFrame extends Block { /** @private */ _createGuides() { - let svg = createSvgNode('svg'); + const svg = createSvgNode('svg'); - let rect = createSvgNode('rect', { + const rect = createSvgNode('rect', { x: 0, y: 0, width: '100%', @@ -263,11 +263,11 @@ export class CropFrame extends Block { svg.appendChild(rect); for (let i = 1; i <= 2; i++) { - let line = createSvgNode('line', { + const line = createSvgNode('line', { x1: `${GUIDE_THIRD * i}%`, - y1: `0%`, + y1: '0%', x2: `${GUIDE_THIRD * i}%`, - y2: `100%`, + y2: '100%', stroke: '#000000', 'stroke-width': GUIDE_STROKE_WIDTH, 'stroke-opacity': 0.3, @@ -276,10 +276,10 @@ export class CropFrame extends Block { } for (let i = 1; i <= 2; i++) { - let line = createSvgNode('line', { - x1: `0%`, + const line = createSvgNode('line', { + x1: '0%', y1: `${GUIDE_THIRD * i}%`, - x2: `100%`, + x2: '100%', y2: `${GUIDE_THIRD * i}%`, stroke: '#000000', 'stroke-width': GUIDE_STROKE_WIDTH, @@ -295,14 +295,14 @@ export class CropFrame extends Block { /** @private */ _createFrame() { - let svg = this.ref['svg-el']; - let fr = document.createDocumentFragment(); + const svg = this.ref['svg-el']; + const fr = document.createDocumentFragment(); - let frameGuides = this._createGuides(); + const frameGuides = this._createGuides(); fr.appendChild(frameGuides); - let frameThumbs = this._createThumbs(); - for (let { groupNode } of Object.values(frameThumbs)) { + const frameThumbs = this._createThumbs(); + for (const { groupNode } of Object.values(frameThumbs)) { fr.appendChild(groupNode); } @@ -318,15 +318,15 @@ export class CropFrame extends Block { */ _handlePointerDown(direction, e) { if (!this._frameThumbs) return; - let thumb = this._frameThumbs[direction]; + const thumb = this._frameThumbs[direction]; if (this._shouldThumbBeDisabled(direction)) { return; } - let cropBox = this.$['*cropBox']; - let { x: svgX, y: svgY } = this.ref['svg-el'].getBoundingClientRect(); - let x = e.x - svgX; - let y = e.y - svgY; + const cropBox = this.$['*cropBox']; + const { x: svgX, y: svgY } = this.ref['svg-el'].getBoundingClientRect(); + const x = e.x - svgX; + const y = e.y - svgY; this.$.dragging = true; this._draggingThumb = thumb; @@ -362,13 +362,13 @@ export class CropFrame extends Block { e.stopPropagation(); e.preventDefault(); - let svg = this.ref['svg-el']; - let { x: svgX, y: svgY } = svg.getBoundingClientRect(); - let x = e.x - svgX; - let y = e.y - svgY; - let dx = x - this._dragStartPoint[0]; - let dy = y - this._dragStartPoint[1]; - let { direction } = this._draggingThumb; + const svg = this.ref['svg-el']; + const { x: svgX, y: svgY } = svg.getBoundingClientRect(); + const x = e.x - svgX; + const y = e.y - svgY; + const dx = x - this._dragStartPoint[0]; + const dy = y - this._dragStartPoint[1]; + const { direction } = this._draggingThumb; const movedCropBox = this._calcCropBox(direction, [dx, dy]); if (movedCropBox) { @@ -384,7 +384,7 @@ export class CropFrame extends Block { _calcCropBox(direction, delta) { const [dx, dy] = delta; /** @type {import('./types.js').Rectangle} */ - let imageBox = this.$['*imageBox']; + const imageBox = this.$['*imageBox']; let rect = /** @type {import('./types.js').Rectangle} */ (this._dragStartCrop) ?? this.$['*cropBox']; /** @type {import('./types.js').CropPresetList[0]} */ const cropPreset = this.$['*cropPresetList']?.[0]; @@ -412,19 +412,19 @@ export class CropFrame extends Block { _handleSvgPointerMove_(e) { if (!this._frameThumbs) return; - let hoverThumb = Object.values(this._frameThumbs).find((thumb) => { + const hoverThumb = Object.values(this._frameThumbs).find((thumb) => { if (this._shouldThumbBeDisabled(thumb.direction)) { return false; } - let node = thumb.interactionNode; - let bounds = node.getBoundingClientRect(); - let rect = { + const node = thumb.interactionNode; + const bounds = node.getBoundingClientRect(); + const rect = { x: bounds.x, y: bounds.y, width: bounds.width, height: bounds.height, }; - let hover = rectContainsPoint(rect, [e.x, e.y]); + const hover = rectContainsPoint(rect, [e.x, e.y]); return hover; }); @@ -434,7 +434,7 @@ export class CropFrame extends Block { /** @private */ _updateCursor() { - let hoverThumb = this._hoverThumb; + const hoverThumb = this._hoverThumb; this.ref['svg-el'].style.cursor = hoverThumb ? thumbCursor(hoverThumb.direction) : 'initial'; } @@ -447,17 +447,17 @@ export class CropFrame extends Block { /** @param {boolean} visible */ toggleThumbs(visible) { if (!this._frameThumbs) return; - Object.values(this._frameThumbs) - .map(({ groupNode }) => groupNode) - .forEach((groupNode) => { - groupNode.setAttribute( - 'class', - classNames('thumb', { - 'thumb--hidden': !visible, - 'thumb--visible': visible, - }), - ); - }); + + for (const thumb of Object.values(this._frameThumbs)) { + const { groupNode } = thumb; + groupNode.setAttribute( + 'class', + classNames('thumb', { + 'thumb--hidden': !visible, + 'thumb--visible': visible, + }), + ); + } } initCallback() { diff --git a/blocks/CloudImageEditor/src/EditorButtonControl.js b/blocks/CloudImageEditor/src/EditorButtonControl.js index e8cf27665..287b2fa25 100644 --- a/blocks/CloudImageEditor/src/EditorButtonControl.js +++ b/blocks/CloudImageEditor/src/EditorButtonControl.js @@ -1,5 +1,5 @@ -import { classNames } from './lib/classNames.js'; import { Block } from '../../../abstract/Block.js'; +import { classNames } from './lib/classNames.js'; export class EditorButtonControl extends Block { init$ = { @@ -22,7 +22,7 @@ export class EditorButtonControl extends Block { } this.sub('title', (title) => { - let titleEl = this._titleEl; + const titleEl = this._titleEl; if (titleEl) { this._titleEl.style.display = title ? 'block' : 'none'; } diff --git a/blocks/CloudImageEditor/src/EditorCropButtonControl.js b/blocks/CloudImageEditor/src/EditorCropButtonControl.js index 22767ae95..63ffac021 100644 --- a/blocks/CloudImageEditor/src/EditorCropButtonControl.js +++ b/blocks/CloudImageEditor/src/EditorCropButtonControl.js @@ -27,12 +27,12 @@ export class EditorCropButtonControl extends EditorButtonControl { /** @private */ this._operation = operation; - this.$['icon'] = operation; + this.$.icon = operation; }); this.$['on.click'] = (e) => { - let prev = this.$['*cropperEl'].getValue(this._operation); - let next = nextValue(this._operation, prev); + const prev = this.$['*cropperEl'].getValue(this._operation); + const next = nextValue(this._operation, prev); this.$['*cropperEl'].setValue(this._operation, next); }; } diff --git a/blocks/CloudImageEditor/src/EditorFilterControl.js b/blocks/CloudImageEditor/src/EditorFilterControl.js index b027af778..a15a88784 100644 --- a/blocks/CloudImageEditor/src/EditorFilterControl.js +++ b/blocks/CloudImageEditor/src/EditorFilterControl.js @@ -1,8 +1,8 @@ import { createCdnUrl, createCdnUrlModifiers } from '../../../utils/cdn-utils.js'; import { EditorButtonControl } from './EditorButtonControl.js'; import { FAKE_ORIGINAL_FILTER } from './EditorSlider.js'; -import { COMMON_OPERATIONS, transformationsToOperations } from './lib/transformationUtils.js'; import { preloadImage } from './lib/preloadImage.js'; +import { COMMON_OPERATIONS, transformationsToOperations } from './lib/transformationUtils.js'; export class EditorFilterControl extends EditorButtonControl { init$ = { @@ -16,14 +16,14 @@ export class EditorFilterControl extends EditorButtonControl { }; _previewSrc() { - let previewSize = parseInt(window.getComputedStyle(this).getPropertyValue('--l-base-min-width'), 10); - let dpr = window.devicePixelRatio; - let size = Math.ceil(dpr * previewSize); - let quality = dpr >= 2 ? 'lightest' : 'normal'; - let filterValue = 100; + const previewSize = Number.parseInt(window.getComputedStyle(this).getPropertyValue('--l-base-min-width'), 10); + const dpr = window.devicePixelRatio; + const size = Math.ceil(dpr * previewSize); + const quality = dpr >= 2 ? 'lightest' : 'normal'; + const filterValue = 100; /** @type {import('./types.js').Transformations} */ - let transformations = { ...this.$['*editorTransformations'] }; + const transformations = { ...this.$['*editorTransformations'] }; transformations[this._operation] = this._filter !== FAKE_ORIGINAL_FILTER ? { @@ -48,11 +48,11 @@ export class EditorFilterControl extends EditorButtonControl { * @param {IntersectionObserver} observer */ _observerCallback(entries, observer) { - let intersectionEntry = entries[0]; + const intersectionEntry = entries[0]; if (intersectionEntry.isIntersecting) { - let src = this.proxyUrl(this._previewSrc()); - let previewEl = this.ref['preview-el']; - let { promise, cancel } = preloadImage(src); + const src = this.proxyUrl(this._previewSrc()); + const previewEl = this.ref['preview-el']; + const { promise, cancel } = preloadImage(src); this._cancelPreload = cancel; promise .catch((err) => { @@ -66,7 +66,7 @@ export class EditorFilterControl extends EditorButtonControl { observer.unobserve(this); }); } else { - this._cancelPreload && this._cancelPreload(); + this._cancelPreload?.(); } } @@ -96,7 +96,7 @@ export class EditorFilterControl extends EditorButtonControl { threshold: [0, 1], }); - let originalUrl = this.$['*originalUrl']; + const originalUrl = this.$['*originalUrl']; this._originalUrl = originalUrl; if (this.$.isOriginal) { @@ -117,10 +117,10 @@ export class EditorFilterControl extends EditorButtonControl { if (this.$.isOriginal) { return; } - let iconEl = this.ref['icon-el']; + const iconEl = this.ref['icon-el']; iconEl.style.opacity = active ? '1' : '0'; - let previewEl = this.ref['preview-el']; + const previewEl = this.ref['preview-el']; if (active) { previewEl.style.opacity = '0'; } else if (previewEl.style.backgroundImage) { @@ -130,8 +130,8 @@ export class EditorFilterControl extends EditorButtonControl { this.sub('*networkProblems', (networkProblems) => { if (!networkProblems) { - let src = this.proxyUrl(this._previewSrc()); - let previewEl = this.ref['preview-el']; + const src = this.proxyUrl(this._previewSrc()); + const previewEl = this.ref['preview-el']; if (previewEl.style.backgroundImage) { previewEl.style.backgroundImage = 'none'; previewEl.style.backgroundImage = `url(${src})`; @@ -143,7 +143,7 @@ export class EditorFilterControl extends EditorButtonControl { destroyCallback() { super.destroyCallback(); this._observer?.disconnect(); - this._cancelPreload && this._cancelPreload(); + this._cancelPreload?.(); } } diff --git a/blocks/CloudImageEditor/src/EditorImageCropper.js b/blocks/CloudImageEditor/src/EditorImageCropper.js index 37f4bad0a..daedb9684 100644 --- a/blocks/CloudImageEditor/src/EditorImageCropper.js +++ b/blocks/CloudImageEditor/src/EditorImageCropper.js @@ -33,7 +33,7 @@ function validateCrop(crop) { return true; } /** @type {((arg: NonNullable) => boolean)[]} */ - let shouldMatch = [ + const shouldMatch = [ ({ dimensions, coords }) => [...dimensions, ...coords].every((number) => Number.isInteger(number) && Number.isFinite(number)), ({ dimensions, coords }) => dimensions.every((d) => d > 0) && coords.every((c) => c >= 0), @@ -95,21 +95,21 @@ export class EditorImageCropper extends Block { /** @private */ _syncTransformations() { - let transformations = this.$['*editorTransformations']; - let pickedTransformations = pick(transformations, Object.keys(this.$['*operations'])); - let operations = { ...this.$['*operations'], ...pickedTransformations }; + const transformations = this.$['*editorTransformations']; + const pickedTransformations = pick(transformations, Object.keys(this.$['*operations'])); + const operations = { ...this.$['*operations'], ...pickedTransformations }; this.$['*operations'] = operations; } /** @private */ _initCanvas() { /** @type {HTMLCanvasElement} */ - let canvas = this.ref['canvas-el']; - let ctx = canvas.getContext('2d'); + const canvas = this.ref['canvas-el']; + const ctx = canvas.getContext('2d'); - let width = this.offsetWidth; - let height = this.offsetHeight; - let dpr = window.devicePixelRatio; + const width = this.offsetWidth; + const height = this.offsetHeight; + const dpr = window.devicePixelRatio; canvas.style.width = `${width}px`; canvas.style.height = `${height}px`; canvas.width = width * dpr; @@ -126,36 +126,36 @@ export class EditorImageCropper extends Block { return; } - let image = this.$.image; - let padding = this.$['*padding']; - let operations = this.$['*operations']; - let { rotate } = operations; + const image = this.$.image; + const padding = this.$['*padding']; + const operations = this.$['*operations']; + const { rotate } = operations; - let bounds = { width: this.offsetWidth, height: this.offsetHeight }; - let naturalSize = rotateSize({ width: image.naturalWidth, height: image.naturalHeight }, rotate); + const bounds = { width: this.offsetWidth, height: this.offsetHeight }; + const naturalSize = rotateSize({ width: image.naturalWidth, height: image.naturalHeight }, rotate); let imageBox; if (naturalSize.width > bounds.width - padding * 2 || naturalSize.height > bounds.height - padding * 2) { - let imageAspectRatio = naturalSize.width / naturalSize.height; - let viewportAspectRatio = bounds.width / bounds.height; + const imageAspectRatio = naturalSize.width / naturalSize.height; + const viewportAspectRatio = bounds.width / bounds.height; if (imageAspectRatio > viewportAspectRatio) { - let width = bounds.width - padding * 2; - let height = width / imageAspectRatio; - let x = 0 + padding; - let y = padding + (bounds.height - padding * 2) / 2 - height / 2; + const width = bounds.width - padding * 2; + const height = width / imageAspectRatio; + const x = 0 + padding; + const y = padding + (bounds.height - padding * 2) / 2 - height / 2; imageBox = { x, y, width, height }; } else { - let height = bounds.height - padding * 2; - let width = height * imageAspectRatio; - let x = padding + (bounds.width - padding * 2) / 2 - width / 2; - let y = 0 + padding; + const height = bounds.height - padding * 2; + const width = height * imageAspectRatio; + const x = padding + (bounds.width - padding * 2) / 2 - width / 2; + const y = 0 + padding; imageBox = { x, y, width, height }; } } else { - let { width, height } = naturalSize; - let x = padding + (bounds.width - padding * 2) / 2 - width / 2; - let y = padding + (bounds.height - padding * 2) / 2 - height / 2; + const { width, height } = naturalSize; + const x = padding + (bounds.width - padding * 2) / 2 - width / 2; + const y = padding + (bounds.height - padding * 2) / 2 - height / 2; imageBox = { x, y, width, height }; } @@ -165,19 +165,19 @@ export class EditorImageCropper extends Block { /** @private */ _alignCrop() { let cropBox = this.$['*cropBox']; - let imageBox = this.$['*imageBox']; - let operations = this.$['*operations']; - let { rotate } = operations; - let cropTransformation = this.$['*editorTransformations']['crop']; - let { width: previewWidth, x: previewX, y: previewY } = this.$['*imageBox']; + const imageBox = this.$['*imageBox']; + const operations = this.$['*operations']; + const { rotate } = operations; + const cropTransformation = this.$['*editorTransformations'].crop; + const { width: previewWidth, x: previewX, y: previewY } = this.$['*imageBox']; if (cropTransformation) { - let { + const { dimensions: [width, height], coords: [x, y], } = cropTransformation; - let { width: sourceWidth } = rotateSize(this._imageSize, rotate); - let ratio = previewWidth / sourceWidth; + const { width: sourceWidth } = rotateSize(this._imageSize, rotate); + const ratio = previewWidth / sourceWidth; cropBox = constraintRect( roundRect({ x: previewX + x * ratio, @@ -220,13 +220,13 @@ export class EditorImageCropper extends Block { /** @private */ _drawImage() { - let ctx = this._ctx; + const ctx = this._ctx; if (!ctx) return; - let image = this.$.image; - let imageBox = this.$['*imageBox']; - let operations = this.$['*operations']; - let { mirror, flip, rotate } = operations; - let rotated = rotateSize({ width: imageBox.width, height: imageBox.height }, rotate); + const image = this.$.image; + const imageBox = this.$['*imageBox']; + const operations = this.$['*operations']; + const { mirror, flip, rotate } = operations; + const rotated = rotateSize({ width: imageBox.width, height: imageBox.height }, rotate); ctx.save(); ctx.translate(imageBox.x + imageBox.width / 2, imageBox.y + imageBox.height / 2); ctx.rotate((rotate * Math.PI * -1) / 180); @@ -240,8 +240,8 @@ export class EditorImageCropper extends Block { if (!this._isActive || !this.$.image || !this._canvas || !this._ctx) { return; } - let canvas = this._canvas; - let ctx = this._ctx; + const canvas = this._canvas; + const ctx = this._ctx; ctx.clearRect(0, 0, canvas.width, canvas.height); @@ -271,18 +271,18 @@ export class EditorImageCropper extends Block { * @returns {NonNullable['dimensions']} */ _getCropDimensions() { - let cropBox = this.$['*cropBox']; - let imageBox = this.$['*imageBox']; - let operations = this.$['*operations']; - let { rotate } = operations; - let { width: previewWidth, height: previewHeight } = imageBox; - let { width: sourceWidth, height: sourceHeight } = rotateSize(this._imageSize, rotate); - let { width: cropWidth, height: cropHeight } = cropBox; - let ratioW = previewWidth / sourceWidth; - let ratioH = previewHeight / sourceHeight; + const cropBox = this.$['*cropBox']; + const imageBox = this.$['*imageBox']; + const operations = this.$['*operations']; + const { rotate } = operations; + const { width: previewWidth, height: previewHeight } = imageBox; + const { width: sourceWidth, height: sourceHeight } = rotateSize(this._imageSize, rotate); + const { width: cropWidth, height: cropHeight } = cropBox; + const ratioW = previewWidth / sourceWidth; + const ratioH = previewHeight / sourceHeight; /** @type {[Number, Number]} */ - let dimensions = [ + const dimensions = [ clamp(Math.round(cropWidth / ratioW), 1, sourceWidth), clamp(Math.round(cropHeight / ratioH), 1, sourceHeight), ]; @@ -295,18 +295,18 @@ export class EditorImageCropper extends Block { * @returns {import('./types.js').Transformations['crop']} */ _getCropTransformation() { - let cropBox = this.$['*cropBox']; - let imageBox = this.$['*imageBox']; - let operations = this.$['*operations']; - let { rotate } = operations; - let { width: previewWidth, height: previewHeight, x: previewX, y: previewY } = imageBox; - let { width: sourceWidth, height: sourceHeight } = rotateSize(this._imageSize, rotate); - let { x: cropX, y: cropY } = cropBox; - let ratioW = previewWidth / sourceWidth; - let ratioH = previewHeight / sourceHeight; - - let dimensions = this._getCropDimensions(); - let crop = { + const cropBox = this.$['*cropBox']; + const imageBox = this.$['*imageBox']; + const operations = this.$['*operations']; + const { rotate } = operations; + const { width: previewWidth, height: previewHeight, x: previewX, y: previewY } = imageBox; + const { width: sourceWidth, height: sourceHeight } = rotateSize(this._imageSize, rotate); + const { x: cropX, y: cropY } = cropBox; + const ratioW = previewWidth / sourceWidth; + const ratioH = previewHeight / sourceHeight; + + const dimensions = this._getCropDimensions(); + const crop = { dimensions, coords: /** @type {[Number, Number]} */ ([ clamp(Math.round((cropX - previewX) / ratioW), 0, sourceWidth - dimensions[0]), @@ -331,12 +331,12 @@ export class EditorImageCropper extends Block { if (!this.isConnected || !this._imageSize) { return; } - let operations = this.$['*operations']; - let { rotate, mirror, flip } = operations; - let crop = this._getCropTransformation(); + const operations = this.$['*operations']; + const { rotate, mirror, flip } = operations; + const crop = this._getCropTransformation(); /** @type {import('./types.js').Transformations} */ - let editorTransformations = this.$['*editorTransformations']; - let transformations = { + const editorTransformations = this.$['*editorTransformations']; + const transformations = { ...editorTransformations, crop, rotate, @@ -425,12 +425,12 @@ export class EditorImageCropper extends Block { /** @private */ _transitionToCrop() { - let dimensions = this._getCropDimensions(); - let scaleX = Math.min(this.offsetWidth, dimensions[0]) / this.$['*cropBox'].width; - let scaleY = Math.min(this.offsetHeight, dimensions[1]) / this.$['*cropBox'].height; - let scale = Math.min(scaleX, scaleY); - let cropCenterX = this.$['*cropBox'].x + this.$['*cropBox'].width / 2; - let cropCenterY = this.$['*cropBox'].y + this.$['*cropBox'].height / 2; + const dimensions = this._getCropDimensions(); + const scaleX = Math.min(this.offsetWidth, dimensions[0]) / this.$['*cropBox'].width; + const scaleY = Math.min(this.offsetHeight, dimensions[1]) / this.$['*cropBox'].height; + const scale = Math.min(scaleX, scaleY); + const cropCenterX = this.$['*cropBox'].x + this.$['*cropBox'].width / 2; + const cropCenterY = this.$['*cropBox'].y + this.$['*cropBox'].height / 2; this.style.transform = `scale(${scale}) translate(${(this.offsetWidth / 2 - cropCenterX) / scale}px, ${ (this.offsetHeight / 2 - cropCenterY) / scale @@ -440,10 +440,10 @@ export class EditorImageCropper extends Block { /** @private */ _transitionToImage() { - let cropCenterX = this.$['*cropBox'].x + this.$['*cropBox'].width / 2; - let cropCenterY = this.$['*cropBox'].y + this.$['*cropBox'].height / 2; + const cropCenterX = this.$['*cropBox'].x + this.$['*cropBox'].width / 2; + const cropCenterY = this.$['*cropBox'].y + this.$['*cropBox'].height / 2; - this.style.transform = `scale(1)`; + this.style.transform = 'scale(1)'; this.style.transformOrigin = `${cropCenterX}px ${cropCenterY}px`; } @@ -462,21 +462,21 @@ export class EditorImageCropper extends Block { * @returns {Promise} */ _waitForImage(originalUrl, transformations) { - let width = this.offsetWidth; - transformations = { + const width = this.offsetWidth; + const appendedTransformations = { ...transformations, crop: undefined, rotate: undefined, flip: undefined, mirror: undefined, }; - let src = this.proxyUrl(viewerImageSrc(originalUrl, width, transformations)); - let { promise, cancel, image } = preloadImage(src); + const src = this.proxyUrl(viewerImageSrc(originalUrl, width, appendedTransformations)); + const { promise, cancel, image } = preloadImage(src); - let stop = this._handleImageLoading(src); + const stop = this._handleImageLoading(src); image.addEventListener('load', stop, { once: true }); image.addEventListener('error', stop, { once: true }); - this._cancelPreload && this._cancelPreload(); + this._cancelPreload?.(); this._cancelPreload = cancel; return promise @@ -494,8 +494,8 @@ export class EditorImageCropper extends Block { * @returns {() => void} Destructor */ _handleImageLoading(src) { - let operation = 'crop'; - let loadingOperations = this.$['*loadingOperations']; + const operation = 'crop'; + const loadingOperations = this.$['*loadingOperations']; if (!loadingOperations.get(operation)) { loadingOperations.set(operation, new Map()); } diff --git a/blocks/CloudImageEditor/src/EditorImageFader.js b/blocks/CloudImageEditor/src/EditorImageFader.js index 4148169e7..5d543e21c 100644 --- a/blocks/CloudImageEditor/src/EditorImageFader.js +++ b/blocks/CloudImageEditor/src/EditorImageFader.js @@ -1,5 +1,5 @@ -import { debounce } from '../../utils/debounce.js'; import { Block } from '../../../abstract/Block.js'; +import { debounce } from '../../utils/debounce.js'; import { classNames } from './lib/classNames.js'; import { linspace } from './lib/linspace.js'; import { batchPreloadImages } from './lib/preloadImage.js'; @@ -11,10 +11,13 @@ import { viewerImageSrc } from './util.js'; * @returns {[Number, Number][]} */ function splitBySections(numbers) { - return numbers.reduce( - (acc, point, idx) => (idx < numbers.length - 1 ? [...acc, [point, numbers[idx + 1]]] : acc), - [], - ); + return numbers.reduce((acc, point, idx) => { + if (idx < numbers.length - 1) { + acc.push([point, numbers[idx + 1]]); + return acc; + } + return acc; + }, []); } /** @@ -23,10 +26,10 @@ function splitBySections(numbers) { * @param {Number} zero */ function calculateOpacities(keypoints, value, zero) { - let section = splitBySections(keypoints).find(([left, right]) => left <= value && value <= right); + const section = splitBySections(keypoints).find(([left, right]) => left <= value && value <= right); return keypoints.map((point) => { - let distance = Math.abs(section[0] - section[1]); - let relation = Math.abs(value - section[0]) / distance; + const distance = Math.abs(section[0] - section[1]); + const relation = Math.abs(value - section[0]) / distance; if (section[0] === point) { return value > zero ? 1 : 1 - relation; @@ -52,8 +55,8 @@ function calculateZIndices(keypoints, zero) { * @returns {Number[]} */ function keypointsRange(operation, value) { - let n = COLOR_OPERATIONS_CONFIG[operation].keypointsNumber; - let { range, zero } = COLOR_OPERATIONS_CONFIG[operation]; + const n = COLOR_OPERATIONS_CONFIG[operation].keypointsNumber; + const { range, zero } = COLOR_OPERATIONS_CONFIG[operation]; return [...new Set([...linspace(range[0], zero, n + 1), ...linspace(zero, range[1], n + 1), zero, value])].sort( (a, b) => a - b, @@ -97,9 +100,9 @@ export class EditorImageFader extends Block { * @returns {() => void} Destructor */ _handleImageLoading(src) { - let operation = this._operation; + const operation = this._operation; - let loadingOperations = this.$['*loadingOperations']; + const loadingOperations = this.$['*loadingOperations']; if (!loadingOperations.get(operation)) { loadingOperations.set(operation, new Map()); } @@ -121,8 +124,8 @@ export class EditorImageFader extends Block { _flush() { window.cancelAnimationFrame(this._raf); this._raf = window.requestAnimationFrame(() => { - for (let kp of this._keypoints) { - let { image } = kp; + for (const kp of this._keypoints) { + const { image } = kp; if (image) { image.style.opacity = kp.opacity.toString(); image.style.zIndex = kp.zIndex.toString(); @@ -141,14 +144,14 @@ export class EditorImageFader extends Block { * @returns {String} */ _imageSrc({ url = this._url, filter = this._filter, operation, value } = {}) { - let transformations = { ...this._transformations }; + const transformations = { ...this._transformations }; if (operation) { transformations[operation] = filter ? { name: filter, amount: value } : value; } // do not use getBoundingClientRect because scale transform affects it - let width = this.offsetWidth; + const width = this.offsetWidth; return this.proxyUrl(viewerImageSrc(url, width, transformations)); } @@ -159,7 +162,7 @@ export class EditorImageFader extends Block { * @returns {Keypoint} */ _constructKeypoint(operation, value) { - let src = this._imageSrc({ operation, value }); + const src = this._imageSrc({ operation, value }); return { src, image: null, @@ -188,16 +191,16 @@ export class EditorImageFader extends Block { * @param {Number} value */ _addKeypoint(operation, filter, value) { - let shouldSkip = () => + const shouldSkip = () => !this._isSame(operation, filter) || this._value !== value || !!this._keypoints.find((kp) => kp.value === value); if (shouldSkip()) { return; } - let keypoint = this._constructKeypoint(operation, value); - let image = new Image(); + const keypoint = this._constructKeypoint(operation, value); + const image = new Image(); image.src = keypoint.src; - let stop = this._handleImageLoading(keypoint.src); + const stop = this._handleImageLoading(keypoint.src); image.addEventListener('load', stop, { once: true }); image.addEventListener('error', stop, { once: true }); keypoint.image = image; @@ -209,9 +212,9 @@ export class EditorImageFader extends Block { if (shouldSkip()) { return; } - let keypoints = this._keypoints; - let idx = keypoints.findIndex((kp) => kp.value > value); - let insertBeforeNode = idx < keypoints.length ? keypoints[idx].image : null; + const keypoints = this._keypoints; + const idx = keypoints.findIndex((kp) => kp.value > value); + const insertBeforeNode = idx < keypoints.length ? keypoints[idx].image : null; if (!this._container || (insertBeforeNode && !this._container.contains(insertBeforeNode))) { return; } @@ -233,9 +236,9 @@ export class EditorImageFader extends Block { /** @param {String | Number} value */ set(value) { - value = typeof value === 'string' ? parseInt(value, 10) : value; - this._update(this._operation, value); - this._addKeypointDebounced(this._operation, this._filter, value); + const normalizedValue = typeof value === 'string' ? Number.parseInt(value, 10) : value; + this._update(this._operation, normalizedValue); + this._addKeypointDebounced(this._operation, this._filter, normalizedValue); } /** @@ -247,13 +250,13 @@ export class EditorImageFader extends Block { this._operation = operation; this._value = value; - let { zero } = COLOR_OPERATIONS_CONFIG[operation]; + const { zero } = COLOR_OPERATIONS_CONFIG[operation]; - let keypointValues = this._keypoints.map((kp) => kp.value); - let opacities = calculateOpacities(keypointValues, value, zero); - let zIndices = calculateZIndices(keypointValues, zero); + const keypointValues = this._keypoints.map((kp) => kp.value); + const opacities = calculateOpacities(keypointValues, value, zero); + const zIndices = calculateZIndices(keypointValues, zero); - for (let [idx, kp] of Object.entries(this._keypoints)) { + for (const [idx, kp] of Object.entries(this._keypoints)) { kp.opacity = opacities[idx]; kp.zIndex = zIndices[idx]; } @@ -263,7 +266,7 @@ export class EditorImageFader extends Block { /** @private */ _createPreviewImage() { - let image = new Image(); + const image = new Image(); image.classList.add('fader-image', 'fader-image--preview'); image.style.opacity = '0'; return image; @@ -271,33 +274,33 @@ export class EditorImageFader extends Block { /** @private */ async _initNodes() { - let fr = document.createDocumentFragment(); + const fr = document.createDocumentFragment(); this._previewImage = this._previewImage || this._createPreviewImage(); !this.contains(this._previewImage) && fr.appendChild(this._previewImage); - let container = document.createElement('div'); + const container = document.createElement('div'); fr.appendChild(container); - let srcList = this._keypoints.map((kp) => kp.src); + const srcList = this._keypoints.map((kp) => kp.src); - let { images, promise, cancel } = batchPreloadImages(srcList); - images.forEach((node) => { - let stop = this._handleImageLoading(node.src); + const { images, promise, cancel } = batchPreloadImages(srcList); + for (const node of images) { + const stop = this._handleImageLoading(node.src); node.addEventListener('load', stop); node.addEventListener('error', stop); - }); + } this._cancelLastImages = () => { cancel(); this._cancelLastImages = undefined; }; - let operation = this._operation; - let filter = this._filter; + const operation = this._operation; + const filter = this._filter; await promise; if (this._isActive && this._isSame(operation, filter)) { - this._container && this._container.remove(); + this._container?.remove(); this._container = container; this._keypoints.forEach((kp, idx) => { - let kpImage = images[idx]; + const kpImage = images[idx]; kpImage.classList.add('fader-image'); kp.image = kpImage; this._container.appendChild(kpImage); @@ -311,8 +314,8 @@ export class EditorImageFader extends Block { setTransformations(transformations) { this._transformations = transformations; if (this._previewImage) { - let src = this._imageSrc(); - let stop = this._handleImageLoading(src); + const src = this._imageSrc(); + const stop = this._handleImageLoading(src); this._previewImage.src = src; this._previewImage.addEventListener('load', stop, { once: true }); this._previewImage.addEventListener('error', stop, { once: true }); @@ -336,18 +339,18 @@ export class EditorImageFader extends Block { * @param {String} [options.filter] */ preload({ url, filter, operation, value }) { - this._cancelBatchPreload && this._cancelBatchPreload(); + this._cancelBatchPreload?.(); - let keypoints = keypointsRange(operation, value); - let srcList = keypoints.map((kp) => this._imageSrc({ url, filter, operation, value: kp })); - let { cancel } = batchPreloadImages(srcList); + const keypoints = keypointsRange(operation, value); + const srcList = keypoints.map((kp) => this._imageSrc({ url, filter, operation, value: kp })); + const { cancel } = batchPreloadImages(srcList); this._cancelBatchPreload = cancel; } /** @private */ _setOriginalSrc(src) { - let image = this._previewImage || this._createPreviewImage(); + const image = this._previewImage || this._createPreviewImage(); !this.contains(image) && this.appendChild(image); this._previewImage = image; @@ -362,7 +365,7 @@ export class EditorImageFader extends Block { return; } image.style.opacity = '0'; - let stop = this._handleImageLoading(src); + const stop = this._handleImageLoading(src); image.addEventListener('error', stop, { once: true }); image.src = src; image.addEventListener( @@ -407,11 +410,11 @@ export class EditorImageFader extends Block { this._filter = filter; this._fromViewer = fromViewer; - let isOriginal = typeof value !== 'number' && !filter; + const isOriginal = typeof value !== 'number' && !filter; if (isOriginal) { - let src = this._imageSrc({ operation, value }); + const src = this._imageSrc({ operation, value }); this._setOriginalSrc(src); - this._container && this._container.remove(); + this._container?.remove(); return; } this._keypoints = keypointsRange(operation, value).map((keyValue) => this._constructKeypoint(operation, keyValue)); @@ -424,8 +427,8 @@ export class EditorImageFader extends Block { deactivate({ hide = true } = {}) { this._isActive = false; - this._cancelLastImages && this._cancelLastImages(); - this._cancelBatchPreload && this._cancelBatchPreload(); + this._cancelLastImages?.(); + this._cancelBatchPreload?.(); if (hide && !this._hidden) { this._hidden = true; @@ -440,12 +443,12 @@ export class EditorImageFader extends Block { this.addEventListener( 'transitionend', () => { - this._container && this._container.remove(); + this._container?.remove(); }, { once: true }, ); } else { - this._container && this._container.remove(); + this._container?.remove(); } } } diff --git a/blocks/CloudImageEditor/src/EditorOperationControl.js b/blocks/CloudImageEditor/src/EditorOperationControl.js index 91df9b282..1b72a4118 100644 --- a/blocks/CloudImageEditor/src/EditorOperationControl.js +++ b/blocks/CloudImageEditor/src/EditorOperationControl.js @@ -20,7 +20,7 @@ export class EditorOperationControl extends EditorButtonControl { this.defineAccessor('operation', (operation) => { if (operation) { this._operation = operation; - this.$['icon'] = operation; + this.$.icon = operation; this.bindL10n('title', () => this.l10n(operation)); } }); @@ -30,9 +30,9 @@ export class EditorOperationControl extends EditorButtonControl { return; } - let { zero } = COLOR_OPERATIONS_CONFIG[this._operation]; - let value = editorTransformations[this._operation]; - let isActive = typeof value !== 'undefined' ? value !== zero : false; + const { zero } = COLOR_OPERATIONS_CONFIG[this._operation]; + const value = editorTransformations[this._operation]; + const isActive = typeof value !== 'undefined' ? value !== zero : false; this.$.active = isActive; }); } diff --git a/blocks/CloudImageEditor/src/EditorScroller.js b/blocks/CloudImageEditor/src/EditorScroller.js index 8338f417e..d4bccaff2 100644 --- a/blocks/CloudImageEditor/src/EditorScroller.js +++ b/blocks/CloudImageEditor/src/EditorScroller.js @@ -8,7 +8,7 @@ export class EditorScroller extends Block { this.addEventListener('wheel', (e) => { e.preventDefault(); - let { deltaY, deltaX } = e; + const { deltaY, deltaX } = e; if (Math.abs(deltaX) > X_THRESHOLD) { this.scrollLeft += deltaX; } else { @@ -18,4 +18,4 @@ export class EditorScroller extends Block { } } -EditorScroller.template = /* HTML */ ` `; +EditorScroller.template = /* HTML */ ' '; diff --git a/blocks/CloudImageEditor/src/EditorSlider.js b/blocks/CloudImageEditor/src/EditorSlider.js index 52c0dc2cc..a9f04f85f 100644 --- a/blocks/CloudImageEditor/src/EditorSlider.js +++ b/blocks/CloudImageEditor/src/EditorSlider.js @@ -47,25 +47,25 @@ export class EditorSlider extends Block { /** @private */ _initializeValues() { - let { range, zero } = COLOR_OPERATIONS_CONFIG[this._operation]; - let [min, max] = range; + const { range, zero } = COLOR_OPERATIONS_CONFIG[this._operation]; + const [min, max] = range; this.$.min = min; this.$.max = max; this.$.zero = zero; - let transformation = this.$['*editorTransformations'][this._operation]; + const transformation = this.$['*editorTransformations'][this._operation]; if (this._controlType === ControlType.FILTER) { let value = max; if (transformation) { - let { name, amount } = transformation; + const { name, amount } = transformation; value = name === this._filter ? amount : max; } this.$.value = value; this.$.defaultValue = value; } if (this._controlType === ControlType.COLOR_OPERATION) { - let value = typeof transformation !== 'undefined' ? transformation : zero; + const value = typeof transformation !== 'undefined' ? transformation : zero; this.$.value = value; this.$.defaultValue = value; } @@ -84,7 +84,7 @@ export class EditorSlider extends Block { } /** @type {import('./types.js').Transformations} */ - let transformations = { + const transformations = { ...this.$['*editorTransformations'], [this._operation]: operationValue, }; @@ -104,7 +104,7 @@ export class EditorSlider extends Block { }); this.sub('value', (value) => { - let tooltip = `${this._filter || this._operation} ${value}`; + const tooltip = `${this._filter || this._operation} ${value}`; this.$['*operationTooltip'] = tooltip; }); } diff --git a/blocks/CloudImageEditor/src/EditorToolbar.js b/blocks/CloudImageEditor/src/EditorToolbar.js index f757661f1..7297c04c3 100644 --- a/blocks/CloudImageEditor/src/EditorToolbar.js +++ b/blocks/CloudImageEditor/src/EditorToolbar.js @@ -1,6 +1,6 @@ +import { Block } from '../../../abstract/Block.js'; // @ts-check import { debounce } from '../../utils/debounce.js'; -import { Block } from '../../../abstract/Block.js'; import { EditorCropButtonControl } from './EditorCropButtonControl.js'; import { EditorFilterControl } from './EditorFilterControl.js'; import { EditorOperationControl } from './EditorOperationControl.js'; @@ -94,7 +94,7 @@ export class EditorToolbar extends Block { visible: 'tab-toggles--visible', }, 'on.cancel': () => { - this._cancelPreload && this._cancelPreload(); + this._cancelPreload?.(); this.$['*on.cancel'](); }, 'on.apply': () => { @@ -135,7 +135,7 @@ export class EditorToolbar extends Block { * @param {String} operation */ _createOperationControl(operation) { - let el = new EditorOperationControl(); + const el = new EditorOperationControl(); // @ts-expect-error TODO: fix el.operation = operation; return el; @@ -146,7 +146,7 @@ export class EditorToolbar extends Block { * @param {String} filter */ _createFilterControl(filter) { - let el = new EditorFilterControl(); + const el = new EditorFilterControl(); // @ts-expect-error TODO: fix el.filter = filter; return el; @@ -157,7 +157,7 @@ export class EditorToolbar extends Block { * @param {String} operation */ _createToggleControl(operation) { - let el = new EditorCropButtonControl(); + const el = new EditorCropButtonControl(); // @ts-expect-error TODO: fix el.operation = operation; return el; @@ -168,31 +168,26 @@ export class EditorToolbar extends Block { * @param {String} tabId */ _renderControlsList(tabId) { - let listEl = this.ref[`controls-list-${tabId}`]; - let fr = document.createDocumentFragment(); + const listEl = this.ref[`controls-list-${tabId}`]; + const fr = document.createDocumentFragment(); if (tabId === TabId.CROP) { - this.$.cropOperations.forEach( - /** @param {string} operation */ (operation) => { - let el = this._createToggleControl(operation); - // @ts-ignore - fr.appendChild(el); - }, - ); + this.$.cropOperations.forEach(); + for (const operation of /** @type {string[]} */ (this.$.cropOperations)) { + const el = this._createToggleControl(operation); + fr.appendChild(el); + } } else if (tabId === TabId.FILTERS) { - [FAKE_ORIGINAL_FILTER, ...this.$.filters].forEach((filterId) => { - let el = this._createFilterControl(filterId); - // @ts-ignore + for (const filterId of [FAKE_ORIGINAL_FILTER, ...this.$.filters]) { + const el = this._createFilterControl(filterId); fr.appendChild(el); - }); + } } else if (tabId === TabId.TUNING) { - this.$.colorOperations.forEach( - /** @param {string} operation */ (operation) => { - let el = this._createOperationControl(operation); - // @ts-ignore - fr.appendChild(el); - }, - ); + for (const operation of /** @type {string[]} */ (this.$.colorOperations)) { + const el = this._createOperationControl(operation); + // @ts-ignore + fr.appendChild(el); + } } [...fr.children].forEach((el, idx) => { @@ -221,10 +216,10 @@ export class EditorToolbar extends Block { this.$['*cropperEl'].deactivate(); } - for (let tabId of ALL_TABS) { - let isCurrentTab = tabId === id; + for (const tabId of ALL_TABS) { + const isCurrentTab = tabId === id; - let tabToggleEl = this.ref[`tab-toggle-${tabId}`]; + const tabToggleEl = this.ref[`tab-toggle-${tabId}`]; tabToggleEl.active = isCurrentTab; if (isCurrentTab) { @@ -242,7 +237,7 @@ export class EditorToolbar extends Block { * @param {String} tabId */ _unmountTabControls(tabId) { - let listEl = this.ref[`controls-list-${tabId}`]; + const listEl = this.ref[`controls-list-${tabId}`]; if (listEl) { listEl.innerHTML = ''; } @@ -250,18 +245,18 @@ export class EditorToolbar extends Block { /** @private */ _syncTabIndicator() { - let tabToggleEl = this.ref[`tab-toggle-${this.$['*tabId']}`]; - let indicatorEl = this.ref['tabs-indicator']; + const tabToggleEl = this.ref[`tab-toggle-${this.$['*tabId']}`]; + const indicatorEl = this.ref['tabs-indicator']; indicatorEl.style.transform = `translateX(${tabToggleEl.offsetLeft}px)`; } /** @private */ _preloadEditedImage() { if (this.$['*imgContainerEl'] && this.$['*originalUrl']) { - let width = this.$['*imgContainerEl'].offsetWidth; - let src = this.proxyUrl(viewerImageSrc(this.$['*originalUrl'], width, this.$['*editorTransformations'])); - this._cancelPreload && this._cancelPreload(); - let { cancel } = batchPreloadImages([src]); + const width = this.$['*imgContainerEl'].offsetWidth; + const src = this.proxyUrl(viewerImageSrc(this.$['*originalUrl'], width, this.$['*editorTransformations'])); + this._cancelPreload?.(); + const { cancel } = batchPreloadImages([src]); this._cancelPreload = () => { cancel(); this._cancelPreload = undefined; @@ -287,15 +282,15 @@ export class EditorToolbar extends Block { if (this.$['*tabId'] === TabId.FILTERS) { visible = true; if (this.$['*currentFilter'] && transformations?.filter?.name === this.$['*currentFilter']) { - let value = transformations?.filter?.amount || 100; - text = this.$['*currentFilter'] + ' ' + value; + const value = transformations?.filter?.amount || 100; + text = `${this.$['*currentFilter']} ${value}`; } else { text = this.l10n(FAKE_ORIGINAL_FILTER); } } else if (this.$['*tabId'] === TabId.TUNING && currentOperation) { visible = true; - let value = transformations?.[currentOperation] || COLOR_OPERATIONS_CONFIG[currentOperation].zero; - text = this.l10n(currentOperation) + ' ' + value; + const value = transformations?.[currentOperation] || COLOR_OPERATIONS_CONFIG[currentOperation].zero; + text = `${this.l10n(currentOperation)} ${value}`; } if (visible) { this.$['*operationTooltip'] = text; @@ -317,7 +312,7 @@ export class EditorToolbar extends Block { }); this.sub('*editorTransformations', (editorTransformations) => { - let appliedFilter = editorTransformations?.filter?.name; + const appliedFilter = editorTransformations?.filter?.name; if (this.$['*currentFilter'] !== appliedFilter) { this.$['*currentFilter'] = appliedFilter; } @@ -336,7 +331,7 @@ export class EditorToolbar extends Block { }); this.sub('*originalUrl', () => { - this.$['*faderEl'] && this.$['*faderEl'].deactivate(); + this.$['*faderEl']?.deactivate(); }); this.sub('*editorTransformations', (transformations) => { @@ -348,11 +343,11 @@ export class EditorToolbar extends Block { this.sub('*loadingOperations', (/** @type {import('./types.js').LoadingOperations} */ loadingOperations) => { let anyLoading = false; - for (let [, mapping] of loadingOperations.entries()) { + for (const [, mapping] of loadingOperations.entries()) { if (anyLoading) { break; } - for (let [, loading] of mapping.entries()) { + for (const [, loading] of mapping.entries()) { if (loading) { anyLoading = true; break; diff --git a/blocks/CloudImageEditor/src/crop-utils.js b/blocks/CloudImageEditor/src/crop-utils.js index 81b5239bc..b3c84a574 100644 --- a/blocks/CloudImageEditor/src/crop-utils.js +++ b/blocks/CloudImageEditor/src/crop-utils.js @@ -6,7 +6,7 @@ import { MIN_CROP_SIZE, THUMB_CORNER_SIZE, THUMB_OFFSET, THUMB_SIDE_SIZE } from * @param {{ [key: String]: String | Number }} attrs */ export function setSvgNodeAttrs(node, attrs) { - for (let p in attrs) node.setAttributeNS(null, p, attrs[p].toString()); + for (const p in attrs) node.setAttributeNS(null, p, attrs[p].toString()); } /** @@ -15,7 +15,7 @@ export function setSvgNodeAttrs(node, attrs) { * @returns {SVGElement} */ export function createSvgNode(name, attrs = {}) { - let node = document.createElementNS('http://www.w3.org/2000/svg', name); + const node = document.createElementNS('http://www.w3.org/2000/svg', name); setSvgNodeAttrs(node, attrs); return node; } @@ -26,25 +26,25 @@ export function createSvgNode(name, attrs = {}) { * @param {number} sizeMultiplier */ export function cornerPath(rect, direction, sizeMultiplier) { - let { x, y, width, height } = rect; + const { x, y, width, height } = rect; - let wMul = direction.includes('w') ? 0 : 1; - let hMul = direction.includes('n') ? 0 : 1; - let xSide = [-1, 1][wMul]; - let ySide = [-1, 1][hMul]; + const wMul = direction.includes('w') ? 0 : 1; + const hMul = direction.includes('n') ? 0 : 1; + const xSide = [-1, 1][wMul]; + const ySide = [-1, 1][hMul]; - let p1 = [ + const p1 = [ x + wMul * width + THUMB_OFFSET * xSide, y + hMul * height + THUMB_OFFSET * ySide - THUMB_CORNER_SIZE * sizeMultiplier * ySide, ]; - let p2 = [x + wMul * width + THUMB_OFFSET * xSide, y + hMul * height + THUMB_OFFSET * ySide]; - let p3 = [ + const p2 = [x + wMul * width + THUMB_OFFSET * xSide, y + hMul * height + THUMB_OFFSET * ySide]; + const p3 = [ x + wMul * width - THUMB_CORNER_SIZE * sizeMultiplier * xSide + THUMB_OFFSET * xSide, y + hMul * height + THUMB_OFFSET * ySide, ]; - let path = `M ${p1[0]} ${p1[1]} L ${p2[0]} ${p2[1]} L ${p3[0]} ${p3[1]}`; - let center = p2; + const path = `M ${p1[0]} ${p1[1]} L ${p2[0]} ${p2[1]} L ${p3[0]} ${p3[1]}`; + const center = p2; return { d: path, @@ -58,18 +58,19 @@ export function cornerPath(rect, direction, sizeMultiplier) { * @param {number} sizeMultiplier */ export function sidePath(rect, direction, sizeMultiplier) { - let { x, y, width, height } = rect; + const { x, y, width, height } = rect; - let wMul = ['n', 's'].includes(direction) + const wMul = ['n', 's'].includes(direction) ? 0.5 : { w: 0, e: 1 }[/** @type {Extract} */ (direction)]; - let hMul = ['w', 'e'].includes(direction) + const hMul = ['w', 'e'].includes(direction) ? 0.5 : { n: 0, s: 1 }[/** @type {Extract} */ (direction)]; - let xSide = [-1, 1][wMul]; - let ySide = [-1, 1][hMul]; + const xSide = [-1, 1][wMul]; + const ySide = [-1, 1][hMul]; - let p1, p2; + let p1; + let p2; if (['n', 's'].includes(direction)) { p1 = [x + wMul * width - (THUMB_SIDE_SIZE * sizeMultiplier) / 2, y + hMul * height + THUMB_OFFSET * ySide]; p2 = [x + wMul * width + (THUMB_SIDE_SIZE * sizeMultiplier) / 2, y + hMul * height + THUMB_OFFSET * ySide]; @@ -77,8 +78,8 @@ export function sidePath(rect, direction, sizeMultiplier) { p1 = [x + wMul * width + THUMB_OFFSET * xSide, y + hMul * height - (THUMB_SIDE_SIZE * sizeMultiplier) / 2]; p2 = [x + wMul * width + THUMB_OFFSET * xSide, y + hMul * height + (THUMB_SIDE_SIZE * sizeMultiplier) / 2]; } - let path = `M ${p1[0]} ${p1[1]} L ${p2[0]} ${p2[1]}`; - let center = [p2[0] - (p2[0] - p1[0]) / 2, p2[1] - (p2[1] - p1[1]) / 2]; + const path = `M ${p1[0]} ${p1[1]} L ${p2[0]} ${p2[1]}`; + const center = [p2[0] - (p2[0] - p1[0]) / 2, p2[1] - (p2[1] - p1[1]) / 2]; return { d: path, center }; } @@ -671,7 +672,7 @@ export function isRectMatchesAspectRatio(rect, aspectRatio) { * @returns {import('./types.js').ImageSize} */ export function rotateSize({ width, height }, angle) { - let swap = (angle / 90) % 2 !== 0; + const swap = (angle / 90) % 2 !== 0; return { width: swap ? height : width, height: swap ? width : height }; } @@ -682,7 +683,8 @@ export function rotateSize({ width, height }, angle) { */ export function calculateMaxCenteredCropFrame(width, height, aspectRatio) { const imageAspectRatio = width / height; - let cropWidth, cropHeight; + let cropWidth; + let cropHeight; if (imageAspectRatio > aspectRatio) { cropWidth = Math.round(height * aspectRatio); diff --git a/blocks/CloudImageEditor/src/elements/line-loader/LineLoaderUi.js b/blocks/CloudImageEditor/src/elements/line-loader/LineLoaderUi.js index e66cadfb3..9d95ed151 100644 --- a/blocks/CloudImageEditor/src/elements/line-loader/LineLoaderUi.js +++ b/blocks/CloudImageEditor/src/elements/line-loader/LineLoaderUi.js @@ -7,10 +7,10 @@ export class LineLoaderUi extends Block { this._active = false; this._handleTransitionEndRight = () => { - let lineEl = this.ref['line-el']; - lineEl.style.transition = `initial`; + const lineEl = this.ref['line-el']; + lineEl.style.transition = 'initial'; lineEl.style.opacity = '0'; - lineEl.style.transform = `translateX(-101%)`; + lineEl.style.transform = 'translateX(-101%)'; this._active && this._start(); }; } @@ -30,9 +30,9 @@ export class LineLoaderUi extends Block { _start() { this._active = true; - let { width } = this.getBoundingClientRect(); - let lineEl = this.ref['line-el']; - lineEl.style.transition = `transform 1s`; + const { width } = this.getBoundingClientRect(); + const lineEl = this.ref['line-el']; + lineEl.style.transition = 'transform 1s'; lineEl.style.opacity = '1'; lineEl.style.transform = `translateX(${width}px)`; lineEl.addEventListener('transitionend', this._handleTransitionEndRight, { diff --git a/blocks/CloudImageEditor/src/elements/presence-toggle/PresenceToggle.js b/blocks/CloudImageEditor/src/elements/presence-toggle/PresenceToggle.js index 35b16e57c..c516afc0a 100644 --- a/blocks/CloudImageEditor/src/elements/presence-toggle/PresenceToggle.js +++ b/blocks/CloudImageEditor/src/elements/presence-toggle/PresenceToggle.js @@ -1,5 +1,5 @@ -import { applyClassNames } from '../../lib/classNames.js'; import { Block } from '../../../../../abstract/Block.js'; +import { applyClassNames } from '../../lib/classNames.js'; /** * @typedef {Object} Style @@ -65,4 +65,4 @@ export class PresenceToggle extends Block { setTimeout(() => this.removeAttribute('hidden'), 0); } } -PresenceToggle.template = /* HTML */ ` `; +PresenceToggle.template = /* HTML */ ' '; diff --git a/blocks/CloudImageEditor/src/elements/slider/SliderUi.js b/blocks/CloudImageEditor/src/elements/slider/SliderUi.js index bab0180bc..0cd02cfb8 100644 --- a/blocks/CloudImageEditor/src/elements/slider/SliderUi.js +++ b/blocks/CloudImageEditor/src/elements/slider/SliderUi.js @@ -10,13 +10,13 @@ export class SliderUi extends Block { onChange: null, defaultValue: null, 'on.sliderInput': () => { - let value = parseInt(this.ref['input-el'].value, 10); + const value = Number.parseInt(this.ref['input-el'].value, 10); this._updateValue(value); - this.$.onInput && this.$.onInput(value); + this.$.onInput?.(value); }, 'on.sliderChange': () => { - let value = parseInt(this.ref['input-el'].value, 10); - this.$.onChange && this.$.onChange(value); + const value = Number.parseInt(this.ref['input-el'].value, 10); + this.$.onChange?.(value); }, }; @@ -64,20 +64,20 @@ export class SliderUi extends Block { this._observer = new ResizeObserver(() => { this._updateSteps(); - let value = parseInt(this.ref['input-el'].value, 10); + const value = Number.parseInt(this.ref['input-el'].value, 10); this._updateValue(value); }); this._observer.observe(this); - this._thumbSize = parseInt(window.getComputedStyle(this).getPropertyValue('--l-thumb-size'), 10); + this._thumbSize = Number.parseInt(window.getComputedStyle(this).getPropertyValue('--l-thumb-size'), 10); setTimeout(() => { - let value = parseInt(this.ref['input-el'].value, 10); + const value = Number.parseInt(this.ref['input-el'].value, 10); this._updateValue(value); }, 0); this.sub('disabled', (disabled) => { - let el = this.ref['input-el']; + const el = this.ref['input-el']; if (disabled) { el.setAttribute('disabled', 'disabled'); } else { @@ -85,7 +85,7 @@ export class SliderUi extends Block { } }); - let inputEl = this.ref['input-el']; + const inputEl = this.ref['input-el']; inputEl.addEventListener('focus', () => { this.style.setProperty('--color-effect', 'var(--hover-color-rgb)'); }); @@ -97,10 +97,10 @@ export class SliderUi extends Block { _updateValue(value) { this._updateZeroDot(value); - let { width } = this.getBoundingClientRect(); - let slope = 100 / (this.$.max - this.$.min); - let mappedValue = slope * (value - this.$.min); - let offset = (mappedValue * (width - this._thumbSize)) / 100; + const { width } = this.getBoundingClientRect(); + const slope = 100 / (this.$.max - this.$.min); + const mappedValue = slope * (value - this.$.min); + const offset = (mappedValue * (width - this._thumbSize)) / 100; window.requestAnimationFrame(() => { this.ref['thumb-el'].style.transform = `translateX(${offset}px)`; @@ -116,10 +116,10 @@ export class SliderUi extends Block { } else { this._zeroDotEl.style.opacity = '0.2'; } - let { width } = this.getBoundingClientRect(); - let slope = 100 / (this.$.max - this.$.min); - let mappedValue = slope * (this._zero - this.$.min); - let offset = (mappedValue * (width - this._thumbSize)) / 100; + const { width } = this.getBoundingClientRect(); + const slope = 100 / (this.$.max - this.$.min); + const mappedValue = slope * (this._zero - this.$.min); + const offset = (mappedValue * (width - this._thumbSize)) / 100; window.requestAnimationFrame(() => { this._zeroDotEl.style.transform = `translateX(${offset}px)`; }); @@ -128,18 +128,18 @@ export class SliderUi extends Block { _updateSteps() { const STEP_GAP = 15; - let stepsEl = this.ref['steps-el']; - let { width } = stepsEl.getBoundingClientRect(); - let half = Math.ceil(width / 2); - let count = Math.ceil(half / STEP_GAP) - 2; + const stepsEl = this.ref['steps-el']; + const { width } = stepsEl.getBoundingClientRect(); + const half = Math.ceil(width / 2); + const count = Math.ceil(half / STEP_GAP) - 2; if (this._stepsCount === count) { return; } - let fr = document.createDocumentFragment(); - let minorStepEl = document.createElement('div'); - let borderStepEl = document.createElement('div'); + const fr = document.createDocumentFragment(); + const minorStepEl = document.createElement('div'); + const borderStepEl = document.createElement('div'); minorStepEl.className = 'minor-step'; borderStepEl.className = 'border-step'; fr.appendChild(borderStepEl); @@ -152,7 +152,7 @@ export class SliderUi extends Block { } fr.appendChild(borderStepEl.cloneNode()); - let zeroDotEl = document.createElement('div'); + const zeroDotEl = document.createElement('div'); zeroDotEl.className = 'zero-dot'; fr.appendChild(zeroDotEl); this._zeroDotEl = zeroDotEl; diff --git a/blocks/CloudImageEditor/src/lib/FocusVisible.js b/blocks/CloudImageEditor/src/lib/FocusVisible.js index 4badd96a9..6188d666b 100644 --- a/blocks/CloudImageEditor/src/lib/FocusVisible.js +++ b/blocks/CloudImageEditor/src/lib/FocusVisible.js @@ -1,5 +1,6 @@ import { applyFocusVisiblePolyfill } from './applyFocusVisiblePolyfill.js'; +// biome-ignore lint/complexity/noStaticOnlyClass: It will be removed soon export class FocusVisible { /** * @param {boolean} focusVisible @@ -7,7 +8,7 @@ export class FocusVisible { */ static handleFocusVisible(focusVisible, element) { if (focusVisible) { - let customOutline = element.style.getPropertyValue('--focus-visible-outline'); + const customOutline = element.style.getPropertyValue('--focus-visible-outline'); element.style.outline = customOutline || '2px solid var(--color-focus-ring)'; } else { element.style.outline = 'none'; @@ -24,7 +25,7 @@ export class FocusVisible { if (!FocusVisible._destructors.has(scope)) { return; } - let removeFocusVisiblePolyfill = FocusVisible._destructors.get(scope); + const removeFocusVisiblePolyfill = FocusVisible._destructors.get(scope); removeFocusVisiblePolyfill(); FocusVisible._destructors.delete(scope); } diff --git a/blocks/CloudImageEditor/src/lib/applyFocusVisiblePolyfill.js b/blocks/CloudImageEditor/src/lib/applyFocusVisiblePolyfill.js index e55422457..4fc7d46d4 100644 --- a/blocks/CloudImageEditor/src/lib/applyFocusVisiblePolyfill.js +++ b/blocks/CloudImageEditor/src/lib/applyFocusVisiblePolyfill.js @@ -26,7 +26,7 @@ function isValidFocusTarget(el) { * @returns {boolean} */ function focusTriggersKeyboardModality(el) { - let { tagName } = /** @type {Element} */ (el); + const { tagName } = /** @type {Element} */ (el); if (tagName === 'INPUT' && !(/** @type {HTMLInputElement} */ (el).readOnly)) { return true; diff --git a/blocks/CloudImageEditor/src/lib/classNames.js b/blocks/CloudImageEditor/src/lib/classNames.js index e9cf816ec..4aee19ff5 100644 --- a/blocks/CloudImageEditor/src/lib/classNames.js +++ b/blocks/CloudImageEditor/src/lib/classNames.js @@ -5,7 +5,7 @@ function normalize(...args) { return result; } - for (let token of Object.keys(arg)) { + for (const token of Object.keys(arg)) { result[token] = arg[token]; } @@ -14,7 +14,7 @@ function normalize(...args) { } export function classNames(...args) { - let mapping = normalize(...args); + const mapping = normalize(...args); return Object.keys(mapping) .reduce((result, token) => { if (mapping[token]) { @@ -27,8 +27,8 @@ export function classNames(...args) { } export function applyClassNames(element, ...args) { - let mapping = normalize(...args); - for (let token of Object.keys(mapping)) { + const mapping = normalize(...args); + for (const token of Object.keys(mapping)) { element.classList.toggle(token, mapping[token]); } } diff --git a/blocks/CloudImageEditor/src/lib/linspace.js b/blocks/CloudImageEditor/src/lib/linspace.js index efa94aca0..69ec04b70 100644 --- a/blocks/CloudImageEditor/src/lib/linspace.js +++ b/blocks/CloudImageEditor/src/lib/linspace.js @@ -5,10 +5,10 @@ * @returns {Number[]} */ export function linspace(a, b, n) { - let ret = Array(n); - n--; - for (let i = n; i >= 0; i--) { - ret[i] = Math.ceil((i * b + (n - i) * a) / n); + const ret = Array(n); + const startN = n - 1; + for (let i = startN; i >= 0; i--) { + ret[i] = Math.ceil((i * b + (startN - i) * a) / startN); } return ret; } diff --git a/blocks/CloudImageEditor/src/lib/pick.js b/blocks/CloudImageEditor/src/lib/pick.js index fe3b617ff..f207d17f8 100644 --- a/blocks/CloudImageEditor/src/lib/pick.js +++ b/blocks/CloudImageEditor/src/lib/pick.js @@ -4,10 +4,10 @@ * @returns {{}} */ export function pick(obj, keys) { - let result = {}; - for (let key of keys) { - let value = obj[key]; - if (obj.hasOwnProperty(key) || value !== undefined) { + const result = {}; + for (const key of keys) { + const value = obj[key]; + if (Object.hasOwn(obj, key) || value !== undefined) { result[key] = value; } } diff --git a/blocks/CloudImageEditor/src/lib/preloadImage.js b/blocks/CloudImageEditor/src/lib/preloadImage.js index 022775feb..bed30a25a 100644 --- a/blocks/CloudImageEditor/src/lib/preloadImage.js +++ b/blocks/CloudImageEditor/src/lib/preloadImage.js @@ -1,15 +1,15 @@ import { TRANSPARENT_PIXEL_SRC } from '../../../../utils/transparentPixelSrc.js'; export function preloadImage(src) { - let image = new Image(); + const image = new Image(); - let promise = new Promise((resolve, reject) => { + const promise = new Promise((resolve, reject) => { image.src = src; image.onload = resolve; image.onerror = reject; }); - let cancel = () => { + const cancel = () => { if (image.naturalWidth === 0) { image.src = TRANSPARENT_PIXEL_SRC; } @@ -19,19 +19,19 @@ export function preloadImage(src) { } export function batchPreloadImages(list) { - let preloaders = []; + const preloaders = []; - for (let src of list) { - let preload = preloadImage(src); + for (const src of list) { + const preload = preloadImage(src); preloaders.push(preload); } - let images = preloaders.map((preload) => preload.image); - let promise = Promise.allSettled(preloaders.map((preload) => preload.promise)); - let cancel = () => { - preloaders.forEach((preload) => { + const images = preloaders.map((preload) => preload.image); + const promise = Promise.allSettled(preloaders.map((preload) => preload.promise)); + const cancel = () => { + for (const preload of preloaders) { preload.cancel(); - }); + } }; return { promise, images, cancel }; diff --git a/blocks/CloudImageEditor/src/lib/transformationUtils.js b/blocks/CloudImageEditor/src/lib/transformationUtils.js index 654363828..3a5114a23 100644 --- a/blocks/CloudImageEditor/src/lib/transformationUtils.js +++ b/blocks/CloudImageEditor/src/lib/transformationUtils.js @@ -61,7 +61,7 @@ function transformationToStr(operation, options) { } if (operation === 'crop' && options) { - let { dimensions, coords } = /** @type {NonNullable} */ (options); + const { dimensions, coords } = /** @type {NonNullable} */ (options); return `${operation}/${dimensions.join('x')}/${coords.join(',')}`; } @@ -78,7 +78,7 @@ export function transformationsToOperations(transformations) { (operation) => typeof transformations[operation] !== 'undefined' && transformations[operation] !== null, ) .map((operation) => { - let options = transformations[operation]; + const options = transformations[operation]; return transformationToStr(operation, options); }) .filter((str) => !!str), diff --git a/blocks/CloudImageEditor/src/state.js b/blocks/CloudImageEditor/src/state.js index f86743a86..6360dd10c 100644 --- a/blocks/CloudImageEditor/src/state.js +++ b/blocks/CloudImageEditor/src/state.js @@ -45,9 +45,9 @@ export function initState(fnCtx) { 'presence.viewerToolbar': true, // TODO: beware of wrong ctx in case of element re-creation: '*on.retryNetwork': () => { - let images = fnCtx.querySelectorAll('img'); - for (let img of images) { - let originalSrc = img.src; + const images = fnCtx.querySelectorAll('img'); + for (const img of images) { + const originalSrc = img.src; img.src = TRANSPARENT_PIXEL_SRC; img.src = originalSrc; } @@ -58,12 +58,12 @@ export function initState(fnCtx) { if (!transformations) { return; } - let originalUrl = fnCtx.$['*originalUrl']; - let cdnUrlModifiers = createCdnUrlModifiers(transformationsToOperations(transformations), 'preview'); - let cdnUrl = createCdnUrl(originalUrl, cdnUrlModifiers); + const originalUrl = fnCtx.$['*originalUrl']; + const cdnUrlModifiers = createCdnUrlModifiers(transformationsToOperations(transformations), 'preview'); + const cdnUrl = createCdnUrl(originalUrl, cdnUrlModifiers); /** @type {import('./types.js').ApplyResult} */ - let eventData = { + const eventData = { originalUrl, cdnUrlModifiers, cdnUrl, diff --git a/blocks/CloudImageEditor/src/util.js b/blocks/CloudImageEditor/src/util.js index b8d298d41..4b1f0120b 100644 --- a/blocks/CloudImageEditor/src/util.js +++ b/blocks/CloudImageEditor/src/util.js @@ -3,9 +3,9 @@ import { COMMON_OPERATIONS, transformationsToOperations } from './lib/transforma export function viewerImageSrc(originalUrl, width, transformations) { const MAX_CDN_DIMENSION = 3000; - let dpr = window.devicePixelRatio; - let size = Math.min(Math.ceil(width * dpr), MAX_CDN_DIMENSION); - let quality = dpr >= 2 ? 'lightest' : 'normal'; + const dpr = window.devicePixelRatio; + const size = Math.min(Math.ceil(width * dpr), MAX_CDN_DIMENSION); + const quality = dpr >= 2 ? 'lightest' : 'normal'; return createCdnUrl( originalUrl, diff --git a/blocks/CloudImageEditorActivity/CloudImageEditorActivity.js b/blocks/CloudImageEditorActivity/CloudImageEditorActivity.js index 000e17552..908b711e0 100644 --- a/blocks/CloudImageEditorActivity/CloudImageEditorActivity.js +++ b/blocks/CloudImageEditorActivity/CloudImageEditorActivity.js @@ -55,7 +55,7 @@ export class CloudImageEditorActivity extends UploaderBlock { if (!this.entry) { return; } - let result = e.detail; + const result = e.detail; this.entry.setMultipleValues({ cdnUrl: result.cdnUrl, cdnUrlModifiers: result.cdnUrlModifiers, diff --git a/blocks/CloudImageEditorActivity/test.js b/blocks/CloudImageEditorActivity/test.js index 6c575f00f..929fb19d9 100644 --- a/blocks/CloudImageEditorActivity/test.js +++ b/blocks/CloudImageEditorActivity/test.js @@ -1,5 +1,5 @@ -import { ifRef } from '../../utils/ifRef.js'; import * as blocks from '../../index.js'; +import { ifRef } from '../../utils/ifRef.js'; ifRef(() => { blocks.registerBlocks(blocks); diff --git a/blocks/Color/Color.js b/blocks/Color/Color.js index 479d30d0e..6410f84f3 100644 --- a/blocks/Color/Color.js +++ b/blocks/Color/Color.js @@ -6,7 +6,7 @@ export class Color extends Block { inputOpacity: 0, '*selectedColor': '#f00', onChange: () => { - this.$['*selectedColor'] = this.ref.input['value']; + this.$['*selectedColor'] = this.ref.input.value; }, }; } diff --git a/blocks/Config/Config.js b/blocks/Config/Config.js index e3585dd81..5a8ac288c 100644 --- a/blocks/Config/Config.js +++ b/blocks/Config/Config.js @@ -1,8 +1,8 @@ // @ts-check import { Block } from '../../abstract/Block.js'; -import { initialConfig } from './initialConfig.js'; import { sharedConfigKey } from '../../abstract/sharedConfigKey.js'; import { toKebabCase } from '../../utils/toKebabCase.js'; +import { initialConfig } from './initialConfig.js'; import { normalizeConfigValue } from './normalizeConfigValue.js'; const allConfigKeys = /** @type {(keyof import('../../types').ConfigType)[]} */ ([ @@ -30,7 +30,7 @@ export const complexConfigKeys = [ 'secureDeliveryProxyUrlResolver', 'iconHrefResolver', 'fileValidators', - 'collectionValidators' + 'collectionValidators', ]; /** @type {(key: keyof import('../../types').ConfigType) => key is keyof import('../../types').ConfigComplexType} */ @@ -58,7 +58,7 @@ const attrStateMapping = /** @type {Record '__' + key; +const getLocalPropName = (key) => `__${key}`; class ConfigClass extends Block { requireCtxName = true; @@ -118,6 +118,7 @@ class ConfigClass extends Block { * @param {unknown} value */ _setValue(key, value) { + // biome-ignore lint/complexity/noUselessThisAlias: const anyThis = /** @type {typeof this & any} */ (this); const normalizedValue = normalizeConfigValue(key, value); @@ -141,6 +142,7 @@ class ConfigClass extends Block { * @param {keyof import('../../types').ConfigType} key */ _getValue(key) { + // biome-ignore lint/complexity/noUselessThisAlias: const anyThis = /** @type {typeof this & any} */ (this); const localPropName = getLocalPropName(key); return anyThis[localPropName]; @@ -163,7 +165,7 @@ class ConfigClass extends Block { `[lr-config] Option "${key}" value is the same as the previous one but the reference is different`, ); console.warn( - `[lr-config] You should avoid changing the reference of the object to prevent unnecessary calculations`, + '[lr-config] You should avoid changing the reference of the object to prevent unnecessary calculations', ); console.warn(`[lr-config] "${key}" previous value:`, previousValue); console.warn(`[lr-config] "${key}" new value:`, nextValue); @@ -173,6 +175,7 @@ class ConfigClass extends Block { initCallback() { super.initCallback(); + // biome-ignore lint/complexity/noUselessThisAlias: const anyThis = /** @type {typeof this & any} */ (this); // Subscribe to the state changes and update the local properties and attributes. @@ -219,6 +222,7 @@ class ConfigClass extends Block { attributeChangedCallback(name, oldVal, newVal) { if (oldVal === newVal) return; + // biome-ignore lint/complexity/noUselessThisAlias: const anyThis = /** @type {typeof this & any} */ (this); const key = attrKeyMapping[name]; // attributeChangedCallback could be called before the initCallback diff --git a/blocks/ConfirmationDialog/ConfirmationDialog.js b/blocks/ConfirmationDialog/ConfirmationDialog.js index 8391f9028..626fb32da 100644 --- a/blocks/ConfirmationDialog/ConfirmationDialog.js +++ b/blocks/ConfirmationDialog/ConfirmationDialog.js @@ -9,7 +9,7 @@ export class UiConfirmation { console.log('Confirmed'); } denyAction() { - this['historyBack'](); + this.historyBack(); } } diff --git a/blocks/DropArea/DropArea.js b/blocks/DropArea/DropArea.js index 01225a655..4c5197168 100644 --- a/blocks/DropArea/DropArea.js +++ b/blocks/DropArea/DropArea.js @@ -106,13 +106,13 @@ export class DropArea extends UploaderBlock { return; } - items.forEach((/** @type {import('./getDropItems.js').DropItem} */ item) => { + for (const item of items) { if (item.type === 'url') { this.addFileFromUrl(item.url, { source: UploadSource.DROP_AREA }); } else if (item.type === 'file') { this.addFileFromObject(item.file, { source: UploadSource.DROP_AREA, fullPath: item.fullPath }); } - }); + } if (this.uploadCollection.size) { this.set$({ '*currentActivity': ActivityBlock.activities.UPLOAD_LIST, @@ -122,7 +122,7 @@ export class DropArea extends UploaderBlock { }, }); - let contentWrapperEl = this.ref['content-wrapper']; + const contentWrapperEl = this.ref['content-wrapper']; if (contentWrapperEl) { this._destroyContentWrapperDropzone = addDropzone({ element: contentWrapperEl, @@ -197,9 +197,9 @@ export class DropArea extends UploaderBlock { /** @private */ _couldHandleFiles() { - let isMultiple = this.cfg.multiple; - let multipleMax = this.cfg.multipleMax; - let currentFilesCount = this.uploadCollection.size; + const isMultiple = this.cfg.multiple; + const multipleMax = this.cfg.multipleMax; + const currentFilesCount = this.uploadCollection.size; if (isMultiple && multipleMax && currentFilesCount >= multipleMax) { return false; diff --git a/blocks/DropArea/addDropzone.js b/blocks/DropArea/addDropzone.js index 42a2042c0..eaf13975e 100644 --- a/blocks/DropArea/addDropzone.js +++ b/blocks/DropArea/addDropzone.js @@ -8,9 +8,9 @@ export const DropzoneState = { OVER: 3, }; -let RESET_EVENTS = ['focus']; -let NEAR_OFFSET = 100; -let nearnessRegistry = new Map(); +const RESET_EVENTS = ['focus']; +const NEAR_OFFSET = 100; +const nearnessRegistry = new Map(); /** * @param {[x: number, y: number]} p @@ -18,8 +18,8 @@ let nearnessRegistry = new Map(); * @returns {number} */ function distance(p, r) { - let cx = Math.max(Math.min(p[0], r.x + r.width), r.x); - let cy = Math.max(Math.min(p[1], r.y + r.height), r.y); + const cx = Math.max(Math.min(p[0], r.x + r.width), r.x); + const cy = Math.max(Math.min(p[1], r.y + r.height), r.y); return Math.sqrt((p[0] - cx) * (p[0] - cx) + (p[1] - cy) * (p[1] - cy)); } @@ -34,48 +34,50 @@ function distance(p, r) { export function addDropzone(desc) { let eventCounter = 0; - let body = document.body; - let switchHandlers = new Set(); - let handleSwitch = (fn) => switchHandlers.add(fn); + const body = document.body; + const switchHandlers = new Set(); + const handleSwitch = (fn) => switchHandlers.add(fn); let state = DropzoneState.INACTIVE; - let setState = (newState) => { + const setState = (newState) => { if (desc.shouldIgnore() && newState !== DropzoneState.INACTIVE) { return; } if (state !== newState) { - switchHandlers.forEach((fn) => fn(newState)); + for (const fn of switchHandlers) { + fn(newState); + } } state = newState; }; - let isDragging = () => eventCounter > 0; + const isDragging = () => eventCounter > 0; handleSwitch((newState) => desc.onChange(newState)); - let onResetEvent = () => { + const onResetEvent = () => { eventCounter = 0; setState(DropzoneState.INACTIVE); }; - let onDragEnter = () => { + const onDragEnter = () => { eventCounter += 1; if (state === DropzoneState.INACTIVE) { setState(DropzoneState.ACTIVE); } }; - let onDragLeave = () => { + const onDragLeave = () => { eventCounter -= 1; if (!isDragging()) { setState(DropzoneState.INACTIVE); } }; - let onDrop = (e) => { + const onDrop = (e) => { e.preventDefault(); eventCounter = 0; setState(DropzoneState.INACTIVE); }; - let onDragOver = (e) => { + const onDragOver = (e) => { if (desc.shouldIgnore()) { return; } @@ -85,14 +87,14 @@ export function addDropzone(desc) { } /** @type {[Number, Number]} */ - let dragPoint = [e.x, e.y]; - let targetRect = desc.element.getBoundingClientRect(); - let nearness = Math.floor(distance(dragPoint, targetRect)); - let isNear = nearness < NEAR_OFFSET; - let isOver = e.composedPath().includes(desc.element); + const dragPoint = [e.x, e.y]; + const targetRect = desc.element.getBoundingClientRect(); + const nearness = Math.floor(distance(dragPoint, targetRect)); + const isNear = nearness < NEAR_OFFSET; + const isOver = e.composedPath().includes(desc.element); nearnessRegistry.set(desc.element, nearness); - let isNearest = Math.min(...nearnessRegistry.values()) === nearness; + const isNearest = Math.min(...nearnessRegistry.values()) === nearness; if (isOver && isNearest) { e.preventDefault(); @@ -104,12 +106,12 @@ export function addDropzone(desc) { } }; - let onElementDrop = async (e) => { + const onElementDrop = async (e) => { if (desc.shouldIgnore()) { return; } e.preventDefault(); - let items = await getDropItems(e.dataTransfer); + const items = await getDropItems(e.dataTransfer); desc.onItems(items); setState(DropzoneState.INACTIVE); }; @@ -119,9 +121,9 @@ export function addDropzone(desc) { body.addEventListener('dragenter', onDragEnter); body.addEventListener('dragover', onDragOver); desc.element.addEventListener('drop', onElementDrop); - RESET_EVENTS.forEach((eventName) => { + for (const eventName of RESET_EVENTS) { window.addEventListener(eventName, onResetEvent); - }); + } return () => { nearnessRegistry.delete(desc.element); @@ -130,8 +132,8 @@ export function addDropzone(desc) { body.removeEventListener('dragenter', onDragEnter); body.removeEventListener('dragover', onDragOver); desc.element.removeEventListener('drop', onElementDrop); - RESET_EVENTS.forEach((eventName) => { + for (const eventName of RESET_EVENTS) { window.removeEventListener(eventName, onResetEvent); - }); + } }; } diff --git a/blocks/DropArea/getDropItems.js b/blocks/DropArea/getDropItems.js index a917e0ee6..f0697766a 100644 --- a/blocks/DropArea/getDropItems.js +++ b/blocks/DropArea/getDropItems.js @@ -23,12 +23,12 @@ function checkIsDirectory(file) { } try { - let reader = new FileReader(); + const reader = new FileReader(); reader.onerror = () => { resolve(true); }; /** @param {Event} e */ - let onLoad = (e) => { + const onLoad = (e) => { if (e.type !== 'loadend') { reader.abort(); } @@ -83,12 +83,12 @@ function readEntryContentAsync(webkitEntry, dataTransferItemType) { }; /** @param {FileSystemDirectoryReader} reader */ - let readReaderContent = (reader) => { + const readReaderContent = (reader) => { reading++; reader.readEntries((entries) => { reading--; - for (let entry of entries) { + for (const entry of entries) { readEntry(entry); } @@ -113,14 +113,14 @@ export function getDropItems(dataTransfer) { const dropItems = []; const promises = []; for (let i = 0; i < dataTransfer.items.length; i++) { - let item = dataTransfer.items[i]; + const item = dataTransfer.items[i]; if (!item) { continue; } if (item.kind === 'file') { const itemType = item.type; if (typeof item.webkitGetAsEntry === 'function' || typeof (/** @type {any} */ (item).getAsEntry) === 'function') { - let entry = + const entry = typeof item.webkitGetAsEntry === 'function' ? item.webkitGetAsEntry() : /** @type {any} */ (item).getAsEntry(); diff --git a/blocks/EditableCanvas/CanMan.js b/blocks/EditableCanvas/CanMan.js index 2918f76c4..613c261f4 100644 --- a/blocks/EditableCanvas/CanMan.js +++ b/blocks/EditableCanvas/CanMan.js @@ -1,10 +1,10 @@ // Canvas Manipulator -import { applyStyles, applyAttributes } from '@symbiotejs/symbiote'; +import { applyAttributes, applyStyles } from '@symbiotejs/symbiote'; const SVGNS = 'http://www.w3.org/2000/svg'; export class CanMan { _syncSvgSize() { - let rect = this.svgGroupEl.getBoundingClientRect(); + const rect = this.svgGroupEl.getBoundingClientRect(); applyAttributes(this.svgEl, { viewBox: `0, 0, ${rect.width}, ${rect.height}`, width: rect.width, @@ -14,7 +14,7 @@ export class CanMan { _syncCanvas() { return new Promise((resolve, reject) => { - let url = URL.createObjectURL( + const url = URL.createObjectURL( new Blob([this.svgEl.outerHTML], { type: 'image/svg+xml', }), @@ -45,9 +45,9 @@ export class CanMan { width: this.can.width, height: this.can.height, }); - this._addedObjects.forEach((obj) => { + for (const obj of this._addedObjects) { obj.remove(); - }); + } return new Promise((resolve, reject) => { this.svgImgEl.onload = () => { resolve(); @@ -90,7 +90,7 @@ export class CanMan { } getImg() { - let img = new Image(); + const img = new Image(); img.src = this.can.toDataURL('image/png'); return new Promise((resolve, reject) => { img.onload = () => { @@ -142,15 +142,16 @@ export class CanMan { } startText() { - let onStart = (e) => { - let text = document.createElementNS(SVGNS, 'text'); + const onStart = (e) => { + const text = document.createElementNS(SVGNS, 'text'); // @ts-ignore applyAttributes(text, { fill: this.currentColor, x: e.offsetX, y: e.offsetY, }); - (text.textContent = 'TEXT'), this.svgGroupEl.appendChild(text); + text.textContent = 'TEXT'; + this.svgGroupEl.appendChild(text); this._addedObjects.add(text); text.focus(); this.svgEl.removeEventListener('mousedown', onStart); @@ -164,7 +165,7 @@ export class CanMan { startDraw() { this.svgEl.addEventListener('mousedown', (e) => { - let pLine = document.createElementNS(SVGNS, 'polyline'); + const pLine = document.createElementNS(SVGNS, 'polyline'); // @ts-ignore applyAttributes(pLine, { fill: 'none', @@ -173,7 +174,7 @@ export class CanMan { }); this.svgGroupEl.appendChild(pLine); this._addedObjects.add(pLine); - let points = []; + const points = []; this.svgEl.onmousemove = (e) => { points.push(`${e.offsetX},${e.offsetY}`); pLine.setAttribute('points', points.join(' ')); diff --git a/blocks/EditableCanvas/EditableCanvas.js b/blocks/EditableCanvas/EditableCanvas.js index d42b76ea5..efcf18918 100644 --- a/blocks/EditableCanvas/EditableCanvas.js +++ b/blocks/EditableCanvas/EditableCanvas.js @@ -1,5 +1,5 @@ -import { Block } from '../../abstract/Block.js'; import { applyStyles } from '@symbiotejs/symbiote'; +import { Block } from '../../abstract/Block.js'; import { checkerboardCssBg } from '../svg-backgrounds/svg-backgrounds.js'; /** @@ -70,15 +70,15 @@ export class EditableCanvas extends Block { /** @param {File} imgFile */ setImageFile(imgFile) { - let img = new Image(); - let url = URL.createObjectURL(imgFile); + const img = new Image(); + const url = URL.createObjectURL(imgFile); img.src = url; this.setImage(img); } /** @param {String} url */ setImageUrl(url) { - let img = new Image(); + const img = new Image(); img.src = url; this.setImage(img); } diff --git a/blocks/EditableCanvas/EditableCanvasToolbar.js b/blocks/EditableCanvas/EditableCanvasToolbar.js index da4151b6f..5f8073749 100644 --- a/blocks/EditableCanvas/EditableCanvasToolbar.js +++ b/blocks/EditableCanvas/EditableCanvasToolbar.js @@ -1,7 +1,7 @@ import { Block } from '../../abstract/Block.js'; -import { CanMan } from './CanMan.js'; -import { Range } from '../Range/Range.js'; import { Color } from '../Color/Color.js'; +import { Range } from '../Range/Range.js'; +import { CanMan } from './CanMan.js'; import { getButtons } from './buttons.js'; @@ -93,18 +93,19 @@ export class EditorToolbar extends Block { '*rangeValue': 100, }); /** @type {HTMLButtonElement} */ - let btnEl = /** @type {Element} */ (e.target).closest('[action]'); + const btnEl = /** @type {Element} */ (e.target).closest('[action]'); if (btnEl) { this.buttons.add(btnEl); - this.buttons.forEach((btn) => { + + for (const btn of this.buttons) { if (btn === btnEl) { btn.setAttribute('current', ''); } else { btn.removeAttribute('current', ''); } - }); + } } - let action = btnEl.getAttribute('action'); + const action = btnEl.getAttribute('action'); console.log(action); if (!action) { return; diff --git a/blocks/EditableCanvas/buttons.js b/blocks/EditableCanvas/buttons.js index 1abdfb725..4638323f9 100644 --- a/blocks/EditableCanvas/buttons.js +++ b/blocks/EditableCanvas/buttons.js @@ -104,6 +104,8 @@ const clrHtml = /* HTML */ ` { + // biome-ignore lint/suspicious/noAssignInExpressions: It will be removed soon + // biome-ignore lint/style/noParameterAssign: It will be removed soon return (acc += btn.clr ? clrHtml : getBthHtml(btn)); }, ''); } diff --git a/blocks/ExternalSource/ExternalSource.js b/blocks/ExternalSource/ExternalSource.js index 136e4f5c2..7d2953137 100644 --- a/blocks/ExternalSource/ExternalSource.js +++ b/blocks/ExternalSource/ExternalSource.js @@ -70,7 +70,7 @@ export class ExternalSource extends UploaderBlock { super.initCallback(); this.registerActivity(this.activityType, { onActivate: () => { - let { externalSourceType } = /** @type {ActivityParams} */ (this.activityParams); + const { externalSourceType } = /** @type {ActivityParams} */ (this.activityParams); this.set$({ activityCaption: `${externalSourceType?.[0].toUpperCase()}${externalSourceType?.slice(1)}`, @@ -147,13 +147,13 @@ export class ExternalSource extends UploaderBlock { * @param {string} propName */ getCssValue(propName) { - let style = window.getComputedStyle(this); + const style = window.getComputedStyle(this); return style.getPropertyValue(propName).trim(); } /** @private */ applyStyles() { - let colors = { + const colors = { backgroundColor: this.getCssValue('--clr-background-light'), textColor: this.getCssValue('--clr-txt'), shadeColor: this.getCssValue('--clr-shade-lv1'), @@ -188,7 +188,7 @@ export class ExternalSource extends UploaderBlock { mountIframe() { /** @type {HTMLIFrameElement} */ // @ts-ignore - let iframe = create({ + const iframe = create({ tag: 'iframe', attributes: { src: this.remoteUrl(), diff --git a/blocks/ExternalSource/buildStyles.js b/blocks/ExternalSource/buildStyles.js index 7ebb7af1a..3fc43f3f3 100644 --- a/blocks/ExternalSource/buildStyles.js +++ b/blocks/ExternalSource/buildStyles.js @@ -1,17 +1,17 @@ -let styleToCss = (style) => { - let css = Object.keys(style).reduce((acc, selector) => { - let propertiesObj = style[selector]; - let propertiesStr = Object.keys(propertiesObj).reduce((acc, prop) => { - let value = propertiesObj[prop]; - return acc + `${prop}: ${value};`; +const styleToCss = (style) => { + const css = Object.keys(style).reduce((acc, selector) => { + const propertiesObj = style[selector]; + const propertiesStr = Object.keys(propertiesObj).reduce((acc, prop) => { + const value = propertiesObj[prop]; + return `${acc}${prop}: ${value};`; }, ''); - return acc + `${selector}{${propertiesStr}}`; + return `${acc}${selector}{${propertiesStr}}`; }, ''); return css; }; export function buildStyles({ textColor, backgroundColor, linkColor, linkColorHover, shadeColor }) { - let border = `solid 1px ${shadeColor}`; + const border = `solid 1px ${shadeColor}`; // TODO: we need to update source source styles, add css custom properties to control theme return styleToCss({ diff --git a/blocks/ExternalSource/messages.js b/blocks/ExternalSource/messages.js index 290a7440e..afbe300b3 100644 --- a/blocks/ExternalSource/messages.js +++ b/blocks/ExternalSource/messages.js @@ -1,4 +1,4 @@ -let cbMapping = {}; +const cbMapping = {}; window.addEventListener('message', (e) => { let message; @@ -9,8 +9,8 @@ window.addEventListener('message', (e) => { } if (message?.type in cbMapping) { - let cbList = cbMapping[message.type]; - for (let [sender, callback] of cbList) { + const cbList = cbMapping[message.type]; + for (const [sender, callback] of cbList) { if (e.source === sender) { callback(message); } @@ -18,7 +18,7 @@ window.addEventListener('message', (e) => { } }); -const registerMessage = function (type, sender, callback) { +const registerMessage = (type, sender, callback) => { if (!(type in cbMapping)) { cbMapping[type] = []; } @@ -26,7 +26,7 @@ const registerMessage = function (type, sender, callback) { cbMapping[type].push([sender, callback]); }; -const unregisterMessage = function (type, sender) { +const unregisterMessage = (type, sender) => { if (type in cbMapping) { cbMapping[type] = cbMapping[type].filter((item) => item[0] !== sender); } diff --git a/blocks/ExternalSource/query-string.js b/blocks/ExternalSource/query-string.js index 988003938..f8ec08cca 100644 --- a/blocks/ExternalSource/query-string.js +++ b/blocks/ExternalSource/query-string.js @@ -3,8 +3,8 @@ * @returns {string} */ export function queryString(params) { - let list = []; - for (let [key, value] of Object.entries(params)) { + const list = []; + for (const [key, value] of Object.entries(params)) { if (value === undefined || value === null || (typeof value === 'string' && value.length === 0)) { continue; } diff --git a/blocks/FileItem/FileItem.js b/blocks/FileItem/FileItem.js index d9ca7ad3c..e0337f26d 100644 --- a/blocks/FileItem/FileItem.js +++ b/blocks/FileItem/FileItem.js @@ -1,13 +1,13 @@ +import { shrinkFile } from '@uploadcare/image-shrink'; // @ts-check import { CancelError, uploadFile } from '@uploadcare/upload-client'; -import { shrinkFile } from '@uploadcare/image-shrink'; import { ActivityBlock } from '../../abstract/ActivityBlock.js'; import { UploaderBlock } from '../../abstract/UploaderBlock.js'; import { createCdnUrl, createCdnUrlModifiers, createOriginalUrl } from '../../utils/cdn-utils.js'; +import { parseShrink } from '../../utils/parseShrink.js'; import { fileCssBg } from '../svg-backgrounds/svg-backgrounds.js'; import { debounce } from '../utils/debounce.js'; import { generateThumb } from '../utils/resizeImage.js'; -import { parseShrink } from '../../utils/parseShrink.js'; const FileItemState = Object.freeze({ FINISHED: Symbol(0), @@ -75,7 +75,7 @@ export class FileItem extends UploaderBlock { } _reset() { - for (let sub of this._entrySubs) { + for (const sub of this._entrySubs) { sub.remove(); } @@ -90,7 +90,7 @@ export class FileItem extends UploaderBlock { * @param {IntersectionObserverEntry[]} entries */ _observerCallback(entries) { - let [entry] = entries; + const [entry] = entries; this._isIntersecting = entry.isIntersecting; if (entry.isIntersecting && !this._renderedOnce) { @@ -109,7 +109,7 @@ export class FileItem extends UploaderBlock { if (!this._entry) { return; } - let entry = this._entry; + const entry = this._entry; let state = FileItemState.IDLE; if (entry.getValue('errors').length > 0) { @@ -128,17 +128,17 @@ export class FileItem extends UploaderBlock { if (!this._entry) { return; } - let entry = this._entry; + const entry = this._entry; if (entry.getValue('fileInfo') && entry.getValue('isImage')) { - let size = this.cfg.thumbSize; - let thumbUrl = this.proxyUrl( + const size = this.cfg.thumbSize; + const thumbUrl = this.proxyUrl( createCdnUrl( createOriginalUrl(this.cfg.cdnCname, this._entry.getValue('uuid')), createCdnUrlModifiers(entry.getValue('cdnUrlModifiers'), `scale_crop/${size}x${size}/center`), ), ); - let currentThumbUrl = entry.getValue('thumbUrl'); + const currentThumbUrl = entry.getValue('thumbUrl'); if (currentThumbUrl !== thumbUrl) { entry.setValue('thumbUrl', thumbUrl); currentThumbUrl?.startsWith('blob:') && URL.revokeObjectURL(currentThumbUrl); @@ -152,14 +152,14 @@ export class FileItem extends UploaderBlock { if (entry.getValue('file')?.type.includes('image')) { try { - let thumbUrl = await generateThumb(entry.getValue('file'), this.cfg.thumbSize); + const thumbUrl = await generateThumb(entry.getValue('file'), this.cfg.thumbSize); entry.setValue('thumbUrl', thumbUrl); } catch (err) { - let color = window.getComputedStyle(this).getPropertyValue('--clr-generic-file-icon'); + const color = window.getComputedStyle(this).getPropertyValue('--clr-generic-file-icon'); entry.setValue('thumbUrl', fileCssBg(color)); } } else { - let color = window.getComputedStyle(this).getPropertyValue('--clr-generic-file-icon'); + const color = window.getComputedStyle(this).getPropertyValue('--clr-generic-file-icon'); entry.setValue('thumbUrl', fileCssBg(color)); } } @@ -170,7 +170,7 @@ export class FileItem extends UploaderBlock { * @param {(value: any) => void} handler */ _subEntry(prop, handler) { - let sub = this._entry.subscribe( + const sub = this._entry.subscribe( prop, /** @param {any} value */ (value) => { if (this.isConnected) { @@ -189,7 +189,7 @@ export class FileItem extends UploaderBlock { this._reset(); /** @type {import('../../abstract/TypedData.js').TypedData} */ - let entry = this.uploadCollection?.read(id); + const entry = this.uploadCollection?.read(id); this._entry = entry; if (!entry) { @@ -251,13 +251,13 @@ export class FileItem extends UploaderBlock { this.subConfigValue('useCloudImageEditor', () => this._debouncedCalculateState()); this.onclick = () => { - FileItem.activeInstances.forEach((inst) => { - if (inst === this) { - inst.setAttribute('focused', ''); + for (const instance of FileItem.activeInstances) { + if (instance === this) { + instance.setAttribute('focused', ''); } else { - inst.removeAttribute('focused'); + instance.removeAttribute('focused'); } - }); + } }; this.sub( @@ -337,7 +337,7 @@ export class FileItem extends UploaderBlock { } async upload() { - let entry = this._entry; + const entry = this._entry; if (!this.uploadCollection.read(entry.uid)) { return; @@ -356,7 +356,7 @@ export class FileItem extends UploaderBlock { entry.setValue('errors', []); try { - let abortController = new AbortController(); + const abortController = new AbortController(); entry.setValue('abortController', abortController); const uploadTask = async () => { @@ -374,7 +374,7 @@ export class FileItem extends UploaderBlock { source: entry.getValue('source'), onProgress: (progress) => { if (progress.isComputable) { - let percentage = progress.value * 100; + const percentage = progress.value * 100; entry.setValue('uploadProgress', percentage); } }, @@ -386,7 +386,7 @@ export class FileItem extends UploaderBlock { }; /** @type {import('@uploadcare/upload-client').UploadcareFile} */ - let fileInfo = await this.$['*uploadQueue'].add(uploadTask); + const fileInfo = await this.$['*uploadQueue'].add(uploadTask); entry.setMultipleValues({ fileInfo, isUploading: false, diff --git a/blocks/FilePreview/FilePreview.js b/blocks/FilePreview/FilePreview.js index 1bcfef193..b21963313 100644 --- a/blocks/FilePreview/FilePreview.js +++ b/blocks/FilePreview/FilePreview.js @@ -1,6 +1,6 @@ import { Block } from '../../abstract/Block.js'; -import { checkerboardCssBg } from '../svg-backgrounds/svg-backgrounds.js'; import { TRANSPARENT_PIXEL_SRC } from '../../utils/transparentPixelSrc.js'; +import { checkerboardCssBg } from '../svg-backgrounds/svg-backgrounds.js'; export class FilePreview extends Block { init$ = { @@ -9,10 +9,6 @@ export class FilePreview extends Block { src: TRANSPARENT_PIXEL_SRC, }; - constructor() { - super(); - } - initCallback() { super.initCallback(); this.sub('checkerboard', () => { @@ -32,7 +28,7 @@ export class FilePreview extends Block { /** @param {File} imgFile */ setImageFile(imgFile) { - let url = URL.createObjectURL(imgFile); + const url = URL.createObjectURL(imgFile); this.$.src = url; this._lastObjectUrl = url; } diff --git a/blocks/FormInput/FormInput.js b/blocks/FormInput/FormInput.js index 5a65b49ef..f992ee19b 100644 --- a/blocks/FormInput/FormInput.js +++ b/blocks/FormInput/FormInput.js @@ -75,7 +75,7 @@ export class FormInput extends UploaderBlock { const fr = new DocumentFragment(); - for (let value of cdnUrls) { + for (const value of cdnUrls) { const input = document.createElement('input'); input.type = 'hidden'; input.name = `${this.ctxName}[]`; diff --git a/blocks/Img/ImgBase.js b/blocks/Img/ImgBase.js index a095e0662..42c6c665d 100644 --- a/blocks/Img/ImgBase.js +++ b/blocks/Img/ImgBase.js @@ -1,18 +1,18 @@ -import { applyTemplateData } from '../../utils/template-utils.js'; import { createCdnUrl, createCdnUrlModifiers, createOriginalUrl } from '../../utils/cdn-utils.js'; import { stringToArray } from '../../utils/stringToArray.js'; +import { applyTemplateData } from '../../utils/template-utils.js'; import { uniqueArray } from '../../utils/uniqueArray.js'; -import { parseObjectToString } from './utils/parseObjectToString.js'; import { ImgConfig } from './ImgConfig.js'; import { DEV_MODE, HI_RES_K, - ULTRA_RES_K, - UNRESOLVED_ATTR, + ImgTypeEnum, MAX_WIDTH, MAX_WIDTH_JPG, - ImgTypeEnum, + ULTRA_RES_K, + UNRESOLVED_ATTR, } from './configurations.js'; +import { parseObjectToString } from './utils/parseObjectToString.js'; export class ImgBase extends ImgConfig { _img = new Image(); @@ -23,9 +23,9 @@ export class ImgBase extends ImgConfig { * @param {String} src */ _fmtAbs(src) { - let isRel = !src.includes('//'); + const isRel = !src.includes('//'); if (isRel && !DEV_MODE) { - src = new URL(src, document.baseURI).href; + return new URL(src, document.baseURI).href; } return src; } @@ -39,16 +39,17 @@ export class ImgBase extends ImgConfig { _validateSize(size) { if (size?.trim() !== '') { // Extract numeric part - let numericPart = size.match(/\d+/)[0]; + const numericPart = size.match(/\d+/)[0]; // Extract alphabetic part - let alphabeticPart = size.match(/[a-zA-Z]+/)[0]; + const alphabeticPart = size.match(/[a-zA-Z]+/)[0]; - const bp = parseInt(numericPart, 10); + const bp = Number.parseInt(numericPart, 10); if (Number(bp) > MAX_WIDTH_JPG && this.hasFormatJPG) { return MAX_WIDTH_JPG + alphabeticPart; - } else if (Number(bp) > MAX_WIDTH && !this.hasFormatJPG) { + } + if (Number(bp) > MAX_WIDTH && !this.hasFormatJPG) { return MAX_WIDTH + alphabeticPart; } } @@ -91,7 +92,7 @@ export class ImgBase extends ImgConfig { return this._proxyUrl(this.$$('src')); } - let cdnModifiers = this._getCdnModifiers(size, blur); + const cdnModifiers = this._getCdnModifiers(size, blur); if (this.$$('src').startsWith(this.$$('cdn-cname'))) { return createCdnUrl(this.$$('src'), cdnModifiers); @@ -103,8 +104,8 @@ export class ImgBase extends ImgConfig { createCdnUrl( // createOriginalUrl(this.$$('cdn-cname'), this.$$('uuid')), - cdnModifiers - ) + cdnModifiers, + ), ); } @@ -114,8 +115,8 @@ export class ImgBase extends ImgConfig { createCdnUrl( // createOriginalUrl(this.$$('cdn-cname'), this.$$('uuid')), - cdnModifiers - ) + cdnModifiers, + ), ); } @@ -126,8 +127,8 @@ export class ImgBase extends ImgConfig { // this.$$('proxy-cname'), cdnModifiers, - this._fmtAbs(this.$$('src')) - ) + this._fmtAbs(this.$$('src')), + ), ); } @@ -138,8 +139,8 @@ export class ImgBase extends ImgConfig { // `https://${this.$$('pubkey')}.ucr.io/`, cdnModifiers, - this._fmtAbs(this.$$('src')) - ) + this._fmtAbs(this.$$('src')), + ), ); } } @@ -150,14 +151,14 @@ export class ImgBase extends ImgConfig { * @returns {String} */ _proxyUrl(url) { - let previewProxy = this.$$('secure-delivery-proxy'); + const previewProxy = this.$$('secure-delivery-proxy'); if (!previewProxy) { return url; } return applyTemplateData( this.$$('secure-delivery-proxy'), { previewUrl: url }, - { transform: (value) => window.encodeURIComponent(value) } + { transform: (value) => window.encodeURIComponent(value) }, ); } @@ -167,27 +168,26 @@ export class ImgBase extends ImgConfig { * @param {Boolean} [wOnly] */ _getElSize(el, k = 1, wOnly = true) { - let rect = el.getBoundingClientRect(); - let w = k * Math.round(rect.width); - let h = wOnly ? '' : k * Math.round(rect.height); + const rect = el.getBoundingClientRect(); + const w = k * Math.round(rect.width); + const h = wOnly ? '' : k * Math.round(rect.height); if (w || h) { return `${w ? w : ''}x${h ? h : ''}`; - } else { - return null; } + return null; } /** @param {HTMLImageElement} img */ _setupEventProxy(img) { /** @param {Event} e */ - let proxifyEvent = (e) => { + const proxifyEvent = (e) => { e.stopPropagation(); - let event = new Event(e.type, e); + const event = new Event(e.type, e); this.dispatchEvent(event); }; - let EVENTS = ['load', 'error']; - for (let event of EVENTS) { + const EVENTS = ['load', 'error']; + for (const event of EVENTS) { img.addEventListener(event, proxifyEvent); } } @@ -224,10 +224,9 @@ export class ImgBase extends ImgConfig { get breakpoints() { if (this.$$('breakpoints')) { const list = stringToArray(this.$$('breakpoints')); - return uniqueArray(list.map((bp) => parseInt(bp, 10))); - } else { - return null; + return uniqueArray(list.map((bp) => Number.parseInt(bp, 10))); } + return null; } get hasFormatJPG() { @@ -236,7 +235,7 @@ export class ImgBase extends ImgConfig { /** @param {HTMLElement} el */ renderBg(el) { - let imgSet = new Set(); + const imgSet = new Set(); imgSet.add(`url("${this._getUrlBase(this._getElSize(el))}") 1x`); if (this.$$('hi-res-support')) { @@ -247,30 +246,30 @@ export class ImgBase extends ImgConfig { imgSet.add(`url("${this._getUrlBase(this._getElSize(el, ULTRA_RES_K))}") ${ULTRA_RES_K}x`); } - let iSet = `image-set(${[...imgSet].join(', ')})`; + const iSet = `image-set(${[...imgSet].join(', ')})`; el.style.setProperty('background-image', iSet); - el.style.setProperty('background-image', '-webkit-' + iSet); + el.style.setProperty('background-image', `-webkit-${iSet}`); } getSrcset() { - let srcset = new Set(); + const srcset = new Set(); if (this.breakpoints) { - this.breakpoints.forEach((bp) => { - srcset.add(this._getUrlBase(bp + 'x') + ` ${this._validateSize(bp + 'w')}`); + for (const bp of this.breakpoints) { + srcset.add(`${this._getUrlBase(`${bp}x`)} ${this._validateSize(`${bp}w`)}`); if (this.$$('hi-res-support')) { - srcset.add(this._getUrlBase(bp * HI_RES_K + 'x') + ` ${this._validateSize(bp * HI_RES_K + 'w')}`); + srcset.add(`${this._getUrlBase(`${bp * HI_RES_K}x`)} ${this._validateSize(`${bp * HI_RES_K}w`)}`); } if (this.$$('ultra-res-support')) { - srcset.add(this._getUrlBase(bp * ULTRA_RES_K + 'x') + ` ${this._validateSize(bp * ULTRA_RES_K + 'w')}`); + srcset.add(`${this._getUrlBase(`${bp * ULTRA_RES_K}x`)} ${this._validateSize(`${bp * ULTRA_RES_K}w`)}`); } - }); + } } else { - srcset.add(this._getUrlBase(this._getElSize(this.currentImg.img)) + ' 1x'); + srcset.add(`${this._getUrlBase(this._getElSize(this.currentImg.img))} 1x`); if (this.$$('hi-res-support')) { - srcset.add(this._getUrlBase(this._getElSize(this.currentImg.img, 2)) + ' 2x'); + srcset.add(`${this._getUrlBase(this._getElSize(this.currentImg.img, 2))} 2x`); } if (this.$$('ultra-res-support')) { - srcset.add(this._getUrlBase(this._getElSize(this.currentImg.img, 3)) + ' 3x'); + srcset.add(`${this._getUrlBase(this._getElSize(this.currentImg.img, 3))} 3x`); } } return [...srcset].join(); @@ -285,7 +284,7 @@ export class ImgBase extends ImgConfig { } renderBackground() { - [...document.querySelectorAll(this.bgSelector)].forEach((el) => { + for (const el of document.querySelectorAll(this.bgSelector)) { if (this.$$('intersection')) { this.initIntersection(el, () => { this.renderBg(el); @@ -293,7 +292,7 @@ export class ImgBase extends ImgConfig { } else { this.renderBg(el); } - }); + } } _appendURL({ elNode, src, srcset }) { diff --git a/blocks/Img/ImgConfig.js b/blocks/Img/ImgConfig.js index 4d01f5ec9..5ff67e4bb 100644 --- a/blocks/Img/ImgConfig.js +++ b/blocks/Img/ImgConfig.js @@ -1,10 +1,10 @@ import { BaseComponent, Data } from '@symbiotejs/symbiote'; -import { PROPS_MAP } from './props-map.js'; -import { CSS_PREF } from './configurations.js'; import { PACKAGE_NAME, PACKAGE_VERSION } from '../../env.js'; +import { CSS_PREF } from './configurations.js'; +import { PROPS_MAP } from './props-map.js'; const CSS_PROPS = Object.create(null); -for (let prop in PROPS_MAP) { +for (const prop in PROPS_MAP) { CSS_PROPS[CSS_PREF + prop] = PROPS_MAP[prop]?.default || ''; } @@ -21,7 +21,7 @@ export class ImgConfig extends BaseComponent { /** @param {Object} kvObj */ set$$(kvObj) { - for (let key in kvObj) { + for (const key in kvObj) { this.$[CSS_PREF + key] = kvObj[key]; } } @@ -46,11 +46,11 @@ export class ImgConfig extends BaseComponent { } initAttributes(el) { - [...this.attributes].forEach((attr) => { + for (const attr of this.attributes) { if (!PROPS_MAP[attr.name]) { el.setAttribute(attr.name, attr.value); } - }); + } } /** @@ -58,18 +58,18 @@ export class ImgConfig extends BaseComponent { * @param {() => void} cbkFn */ initIntersection(el, cbkFn) { - let opts = { + const opts = { root: null, rootMargin: '0px', }; /** @private */ this._isnObserver = new IntersectionObserver((entries) => { - entries.forEach((ent) => { - if (ent.isIntersecting) { + for (const entry of entries) { + if (entry.isIntersecting) { cbkFn(); this._isnObserver.unobserve(el); } - }); + } }, opts); this._isnObserver.observe(el); if (!this._observed) { @@ -82,9 +82,9 @@ export class ImgConfig extends BaseComponent { destroyCallback() { super.destroyCallback(); if (this._isnObserver) { - this._observed.forEach((el) => { + for (const el of this._observed) { this._isnObserver.unobserve(el); - }); + } this._isnObserver = null; } Data.deleteCtx(this); diff --git a/blocks/LiveHtml/LiveHtml.js b/blocks/LiveHtml/LiveHtml.js index 6b0c52c70..8386e40c3 100644 --- a/blocks/LiveHtml/LiveHtml.js +++ b/blocks/LiveHtml/LiveHtml.js @@ -15,9 +15,10 @@ const INIT_HTML = /* HTML */ ` `.trim(); +// biome-ignore lint/complexity/noStaticOnlyClass: It will be removed soon class Caret { static getPosition(parentElement) { - let selection = window.getSelection(); + const selection = window.getSelection(); let charCount = -1; let node; @@ -47,9 +48,9 @@ class Caret { static setPosition(chars, element) { if (chars >= 0) { - let selection = window.getSelection(); + const selection = window.getSelection(); - let range = Caret._createRange(element, { + const range = Caret._createRange(element, { count: chars, }); @@ -63,6 +64,7 @@ class Caret { static _createRange(node, chars, range) { if (!range) { + // biome-ignore lint/style/noParameterAssign: It will be removed soon range = document.createRange(); range.selectNode(node); range.setStart(node, 0); @@ -80,6 +82,7 @@ class Caret { } } else { for (let lp = 0; lp < node.childNodes.length; lp++) { + // biome-ignore lint/style/noParameterAssign: It will be removed soon range = Caret._createRange(node.childNodes[lp], chars, range); if (chars.count === 0) { @@ -96,6 +99,7 @@ class Caret { if (node === parentElement) { return true; } + // biome-ignore lint/style/noParameterAssign: It will be removed soon node = node.parentNode; } return false; @@ -119,12 +123,12 @@ const headerHtml = /* HTML */ ` export class LiveHtml extends Block { async hl() { - let offset = Caret.getPosition(this.ref.editor); + const offset = Caret.getPosition(this.ref.editor); this.ref.editor.textContent = this.ref.editor.textContent; let html = this.ref.editor.textContent; - let hljs = await import( + const hljs = await import( 'https://cdn.skypack.dev/pin/highlight.js@v11.6.0-4W1e4sNTmpsDP0C1l7xy/mode=imports,min/optimized/highlightjs.js' ); // @ts-ignore @@ -146,7 +150,7 @@ export class LiveHtml extends Block { if (this.hasAttribute('console-output')) { /** @type {Window} */ // @ts-ignore - let docWin = this.ref.vp.contentWindow; + const docWin = this.ref.vp.contentWindow; this.ref.vp.onload = () => { console.dirxml(docWin.document.body); }; @@ -196,8 +200,9 @@ ${this.ref.vp.srcdoc} connectedCallback() { if (this.innerHTML.trim()) { - let lines = this.innerHTML.split('\n'); + const lines = this.innerHTML.split('\n'); let commonTabSize = 1000; + // biome-ignore lint/complexity/noForEach: It will be removed soon lines.forEach((line) => { if (!line.trim()) { return; @@ -206,7 +211,7 @@ ${this.ref.vp.srcdoc} commonTabSize = 0; return; } - let tabs = line.match(/^ +/); + const tabs = line.match(/^ +/); if (tabs) { commonTabSize = Math.min(commonTabSize, tabs[0].length); } @@ -216,6 +221,7 @@ ${this.ref.vp.srcdoc} .map((line) => { for (let i = 0; i < commonTabSize; i++) { if (line.startsWith(' ')) { + // biome-ignore lint/style/noParameterAssign: It will be removed soon line = line.replace(' ', ''); } } @@ -228,10 +234,10 @@ ${this.ref.vp.srcdoc} } initCallback() { - let docImportMap = document.querySelector('script[type="importmap"]'); + const docImportMap = document.querySelector('script[type="importmap"]'); if (docImportMap) { let shimScriptHtml = ''; - let shimScriptEl = document.querySelector('script[src*="es-module-shims.js"]'); + const shimScriptEl = document.querySelector('script[src*="es-module-shims.js"]'); if (shimScriptEl) { shimScriptHtml = shimScriptEl.outerHTML; } @@ -241,7 +247,7 @@ ${this.ref.vp.srcdoc} this.sub('src', (val) => { if (val) { window.fetch(val).then(async (resp) => { - let code = await resp.text(); + const code = await resp.text(); this.$.code = code; this.sync(); }); diff --git a/blocks/Modal/Modal.js b/blocks/Modal/Modal.js index cd7e96c20..e911c564a 100644 --- a/blocks/Modal/Modal.js +++ b/blocks/Modal/Modal.js @@ -63,7 +63,7 @@ export class Modal extends Block { this.ref.dialog.addEventListener('mouseup', this._handleDialogMouseUp); } else { this.setAttribute('dialog-fallback', ''); - let backdrop = document.createElement('div'); + const backdrop = document.createElement('div'); backdrop.className = 'backdrop'; this.appendChild(backdrop); backdrop.addEventListener('click', this._handleBackdropClick); diff --git a/blocks/ProgressBarCommon/ProgressBarCommon.js b/blocks/ProgressBarCommon/ProgressBarCommon.js index 19f8945f1..8a41325ea 100644 --- a/blocks/ProgressBarCommon/ProgressBarCommon.js +++ b/blocks/ProgressBarCommon/ProgressBarCommon.js @@ -13,8 +13,8 @@ export class ProgressBarCommon extends UploaderBlock { super.initCallback(); /** @private */ this._unobserveCollection = this.uploadCollection.observeProperties(() => { - let anyUploading = this.uploadCollection.items().some((id) => { - let item = this.uploadCollection.read(id); + const anyUploading = this.uploadCollection.items().some((id) => { + const item = this.uploadCollection.read(id); return item.getValue('isUploading'); }); diff --git a/blocks/Range/Range.js b/blocks/Range/Range.js index 3c89a4f07..4e39577ca 100644 --- a/blocks/Range/Range.js +++ b/blocks/Range/Range.js @@ -8,7 +8,7 @@ export class Range extends BaseComponent { onChange: (e) => { e.preventDefault(); e.stopPropagation(); - this.$.value = parseFloat(this._range.value); + this.$.value = Number.parseFloat(this._range.value); this.dispatchEvent(new Event('change')); }, }; @@ -17,14 +17,14 @@ export class Range extends BaseComponent { super.initCallback(); /** @type {HTMLInputElement} */ this._range = this.ref.range; - [...this.attributes].forEach((attr) => { - let exclude = ['style', 'ref']; + for (const attr of this.attributes) { + const exclude = ['style', 'ref']; if (!exclude.includes(attr.name)) { this.ref.range.setAttribute(attr.name, attr.value); } - }); + } this.sub('value', (val) => { - let pcnt = (val / 100) * 100; + const pcnt = (val / 100) * 100; this.$.cssLeft = `${pcnt}%`; }); this.defineAccessor('value', (val) => { diff --git a/blocks/Select/Select.js b/blocks/Select/Select.js index 695de6509..036e32a13 100644 --- a/blocks/Select/Select.js +++ b/blocks/Select/Select.js @@ -12,7 +12,7 @@ export class Select extends Block { this.value = this.ref.select.value; this.$.currentText = this.$.options.find((opt) => { - return opt.value == this.value; + return opt.value === this.value; })?.text || ''; this.dispatchEvent(new Event('change')); }, @@ -24,9 +24,11 @@ export class Select extends Block { this.sub('options', (/** @type {{ text: String; value: String }[]} */ options) => { this.$.currentText = options?.[0]?.text || ''; let html = ''; - options?.forEach((opt) => { - html += /* HTML */ ``; - }); + if (options) { + for (const opt of options) { + html += /* HTML */ ``; + } + } this.$.selectHtml = html; }); } diff --git a/blocks/SourceBtn/SourceBtn.js b/blocks/SourceBtn/SourceBtn.js index 3eeeddddb..929d0d1f9 100644 --- a/blocks/SourceBtn/SourceBtn.js +++ b/blocks/SourceBtn/SourceBtn.js @@ -1,6 +1,6 @@ +import { ActivityBlock } from '../../abstract/ActivityBlock.js'; // @ts-check import { UploaderBlock } from '../../abstract/UploaderBlock.js'; -import { ActivityBlock } from '../../abstract/ActivityBlock.js'; const L10N_PREFIX = 'src-type-'; @@ -65,7 +65,7 @@ export class SourceBtn extends UploaderBlock { icon: 'edit-draw', }); - for (let externalSourceType of Object.values(UploaderBlock.extSrcList)) { + for (const externalSourceType of Object.values(UploaderBlock.extSrcList)) { this.registerType({ type: externalSourceType, activity: ActivityBlock.activities.EXTERNAL, @@ -121,7 +121,7 @@ export class SourceBtn extends UploaderBlock { applyType(type) { const configType = this._registeredTypes[type]; if (!configType) { - console.warn('Unsupported source type: ' + type); + console.warn(`Unsupported source type: ${type}`); return; } const { textKey = type, icon = type } = configType; diff --git a/blocks/SourceList/SourceList.js b/blocks/SourceList/SourceList.js index cde4080f5..9b082c999 100644 --- a/blocks/SourceList/SourceList.js +++ b/blocks/SourceList/SourceList.js @@ -5,11 +5,11 @@ export class SourceList extends Block { initCallback() { super.initCallback(); this.subConfigValue('sourceList', (/** @type {String} */ val) => { - let list = stringToArray(val); + const list = stringToArray(val); let html = ''; - list.forEach((srcName) => { + for (const srcName of list) { html += /* HTML */ ``; - }); + } if (this.cfg.sourceListWrap) { this.innerHTML = html; } else { diff --git a/blocks/Tabs/Tabs.js b/blocks/Tabs/Tabs.js index a5b1e6790..a1b676b03 100644 --- a/blocks/Tabs/Tabs.js +++ b/blocks/Tabs/Tabs.js @@ -1,5 +1,5 @@ -import { Block } from '../../abstract/Block.js'; import { create } from '@symbiotejs/symbiote'; +import { Block } from '../../abstract/Block.js'; import { stringToArray } from '../../utils/stringToArray.js'; export class Tabs extends Block { @@ -8,15 +8,15 @@ export class Tabs extends Block { if (!tabL10nStr) { return; } - let ctxList = [...this.ref.context.querySelectorAll('[tab-ctx]')]; - ctxList.forEach((ctxEl) => { + const ctxList = [...this.ref.context.querySelectorAll('[tab-ctx]')]; + for (const ctxEl of ctxList) { if (ctxEl.getAttribute('tab-ctx') === tabL10nStr) { ctxEl.removeAttribute('hidden'); } else { ctxEl.setAttribute('hidden', ''); } - }); - for (let lStr in this._tabMap) { + } + for (const lStr in this._tabMap) { if (lStr === tabL10nStr) { this._tabMap[lStr].setAttribute('current', ''); } else { @@ -36,9 +36,9 @@ export class Tabs extends Block { if (!val) { return; } - let tabList = stringToArray(val); - tabList.forEach((tabL10nStr) => { - let tabEl = create({ + const tabList = stringToArray(val); + for (const tabL10nStr of tabList) { + const tabEl = create({ tag: 'div', attributes: { class: 'tab', @@ -52,7 +52,7 @@ export class Tabs extends Block { tabEl.textContent = this.l10n(tabL10nStr); this.ref.row.appendChild(tabEl); this._tabMap[tabL10nStr] = tabEl; - }); + } }); this.defineAccessor('default', (val) => { diff --git a/blocks/UrlSource/UrlSource.js b/blocks/UrlSource/UrlSource.js index d71d79008..f98e89f9e 100644 --- a/blocks/UrlSource/UrlSource.js +++ b/blocks/UrlSource/UrlSource.js @@ -1,5 +1,5 @@ -import { UploaderBlock } from '../../abstract/UploaderBlock.js'; import { ActivityBlock } from '../../abstract/ActivityBlock.js'; +import { UploaderBlock } from '../../abstract/UploaderBlock.js'; import { UploadSource } from '../utils/UploadSource.js'; export class UrlSource extends UploaderBlock { @@ -12,7 +12,7 @@ export class UrlSource extends UploaderBlock { onUpload: (e) => { e.preventDefault(); - let url = this.ref.input['value']; + const url = this.ref.input.value; this.addFileFromUrl(url, { source: UploadSource.URL_TAB }); this.$['*currentActivity'] = ActivityBlock.activities.UPLOAD_LIST; }, @@ -20,7 +20,7 @@ export class UrlSource extends UploaderBlock { this.historyBack(); }, onInput: (e) => { - let value = /** @type {HTMLInputElement} */ (e.target).value; + const value = /** @type {HTMLInputElement} */ (e.target).value; this.set$({ importDisabled: !value }); }, }; @@ -29,7 +29,7 @@ export class UrlSource extends UploaderBlock { super.initCallback(); this.registerActivity(this.activityType, { onActivate: () => { - this.ref.input['value'] = ''; + this.ref.input.value = ''; this.ref.input.focus(); }, }); diff --git a/blocks/Video/Video.js b/blocks/Video/Video.js index 93f9539a1..1168217bf 100644 --- a/blocks/Video/Video.js +++ b/blocks/Video/Video.js @@ -24,8 +24,8 @@ const FSAPI = { exitFullscreen: () => { if (document.exitFullscreen) { document.exitFullscreen(); - } else if (document['webkitExitFullscreen']) { - document['webkitExitFullscreen'](); + } else if (document.webkitExitFullscreen) { + document.webkitExitFullscreen(); } }, }; @@ -40,7 +40,7 @@ export class Video extends Block { } toggleFullscreen() { - if ((document.fullscreenElement || document['webkitFullscreenElement']) === this) { + if ((document.fullscreenElement || document.webkitFullscreenElement) === this) { FSAPI.exitFullscreen(); } else { FSAPI.requestFullscreen(this); @@ -51,11 +51,11 @@ export class Video extends Block { if (this.$.capIcon === ICO_MAP.CAP_OFF) { this.$.capIcon = ICO_MAP.CAP_ON; this._video.textTracks[0].mode = 'showing'; - window.localStorage.setItem(Video.is + ':captions', '1'); + window.localStorage.setItem(`${Video.is}:captions`, '1'); } else { this.$.capIcon = ICO_MAP.CAP_OFF; this._video.textTracks[0].mode = 'hidden'; - window.localStorage.removeItem(Video.is + ':captions'); + window.localStorage.removeItem(`${Video.is}:captions`); } } @@ -72,8 +72,8 @@ export class Video extends Block { } setVolume(val) { - window.localStorage.setItem(Video.is + ':volume', val); - let volume = val ? val / 100 : 0; + window.localStorage.setItem(`${Video.is}:volume`, val); + const volume = val ? val / 100 : 0; this._video.volume = volume; } @@ -109,11 +109,11 @@ export class Video extends Block { }, onVolChange: (e) => { // TODO: cast range.value instead of range.$.value - let val = parseFloat(e.currentTarget.$.value); + const val = Number.parseFloat(e.currentTarget.$.value); this.setVolume(val); }, progressClicked: (e) => { - let progressRect = this.progress.getBoundingClientRect(); + const progressRect = this.progress.getBoundingClientRect(); this._video.currentTime = this._video.duration * (e.offsetX / progressRect.width); }, }; @@ -131,9 +131,9 @@ export class Video extends Block { * @param {Object} desc */ _desc2attrs(desc) { - let attrs = []; - for (let attr in desc) { - let val = attr === 'src' ? this._getUrl(desc[attr]) : desc[attr]; + const attrs = []; + for (const attr in desc) { + const val = attr === 'src' ? this._getUrl(desc[attr]) : desc[attr]; attrs.push(`${attr}="${val}"`); } return attrs.join(' '); @@ -145,32 +145,32 @@ export class Video extends Block { */ _timeFmt(seconds) { // TODO: add hours - let date = new Date(Math.round(seconds) * 1000); + const date = new Date(Math.round(seconds) * 1000); return [date.getMinutes(), date.getSeconds()] .map((n) => { - return n < 10 ? '0' + n : n; + return n < 10 ? `0${n}` : n; }) .join(':'); } /** @private */ _initTracks() { - [...this._video.textTracks].forEach((track) => { + for (const track of this._video.textTracks) { track.mode = 'hidden'; - }); - if (window.localStorage.getItem(Video.is + ':captions')) { + } + if (window.localStorage.getItem(`${Video.is}:captions`)) { this.toggleCaptions(); } } /** @private */ _castAttributes() { - let toCast = ['autoplay', 'loop', 'muted']; - [...this.attributes].forEach((attr) => { + const toCast = ['autoplay', 'loop', 'muted']; + for (const attr of this.attributes) { if (toCast.includes(attr.name)) { this._video.setAttribute(attr.name, attr.value); } - }); + } } initCallback() { @@ -206,7 +206,7 @@ export class Video extends Block { if (!src) { return; } - let url = this._getUrl(src); + const url = this._getUrl(src); this._video.src = url; }); @@ -214,21 +214,23 @@ export class Video extends Block { if (!descPath) { return; } - let desc = await (await window.fetch(this._getUrl(descPath))).json(); + const desc = await (await window.fetch(this._getUrl(descPath))).json(); if (desc.poster) { this._video.poster = this._getUrl(desc.poster); } let html = ''; - desc?.sources.forEach((srcDesc) => { - html += /* HTML */ ``; - }); + if (desc.sources) { + for (const srcDesc of desc.sources) { + html += /* HTML */ ``; + } + } if (desc.tracks) { - desc.tracks.forEach((trackDesc) => { + for (const trackDesc of desc.tracks) { html += /* HTML */ ``; - }); + } this.$.hasSubtitles = true; } @@ -244,14 +246,14 @@ export class Video extends Block { }); this._video.addEventListener('timeupdate', (e) => { - let perc = Math.round(100 * (this._video.currentTime / this._video.duration)); - this.$.progressCssWidth = perc + '%'; + const perc = Math.round(100 * (this._video.currentTime / this._video.duration)); + this.$.progressCssWidth = `${perc}%`; this.$.currentTime = this._timeFmt(this._video.currentTime); }); - let volume = window.localStorage.getItem(Video.is + ':volume'); + const volume = window.localStorage.getItem(`${Video.is}:volume`); if (volume) { - let vol = parseFloat(volume); + const vol = Number.parseFloat(volume); this.setVolume(vol); this.$.volumeValue = vol; } diff --git a/blocks/svg-backgrounds/svg-backgrounds.js b/blocks/svg-backgrounds/svg-backgrounds.js index 5d35812f7..ec4aa7477 100644 --- a/blocks/svg-backgrounds/svg-backgrounds.js +++ b/blocks/svg-backgrounds/svg-backgrounds.js @@ -3,7 +3,7 @@ * @returns {String} */ function createSvgBlobUrl(svg) { - let blob = new Blob([svg], { + const blob = new Blob([svg], { type: 'image/svg+xml', }); return URL.createObjectURL(blob); diff --git a/blocks/utils/resizeImage.js b/blocks/utils/resizeImage.js index 17ba1d9aa..29c4e7741 100644 --- a/blocks/utils/resizeImage.js +++ b/blocks/utils/resizeImage.js @@ -6,12 +6,12 @@ export function generateThumb(imgFile, size = 40) { if (imgFile.type === 'image/svg+xml') { return URL.createObjectURL(imgFile); } - let canvas = document.createElement('canvas'); - let ctx = canvas.getContext('2d'); - let img = new Image(); - let promise = new Promise((resolve, reject) => { + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + const img = new Image(); + const promise = new Promise((resolve, reject) => { img.onload = () => { - let ratio = img.height / img.width; + const ratio = img.height / img.width; if (ratio > 1) { canvas.width = size; canvas.height = size * ratio; @@ -27,7 +27,7 @@ export function generateThumb(imgFile, size = 40) { reject(); return; } - let url = URL.createObjectURL(blob); + const url = URL.createObjectURL(blob); resolve(url); }); }; diff --git a/blocks/utils/userAgent.js b/blocks/utils/userAgent.js index d879072a0..4ee1508ea 100644 --- a/blocks/utils/userAgent.js +++ b/blocks/utils/userAgent.js @@ -1,5 +1,5 @@ import { getUserAgent } from '@uploadcare/upload-client'; -import { PACKAGE_VERSION, PACKAGE_NAME } from '../../env.js'; +import { PACKAGE_NAME, PACKAGE_VERSION } from '../../env.js'; /** * @param {import('@uploadcare/upload-client').CustomUserAgentOptions} options diff --git a/build-ssr-stubs.js b/build-ssr-stubs.js index 0c382c729..eec8616ea 100644 --- a/build-ssr-stubs.js +++ b/build-ssr-stubs.js @@ -1,4 +1,4 @@ -import { writeFileSync } from 'fs'; +import { writeFileSync } from 'node:fs'; import { GlobalRegistrator } from '@happy-dom/global-registrator'; import prettier from 'prettier'; @@ -22,16 +22,17 @@ const getClassStaticProperties = (klass) => { if (proto === HTMLElement || proto === HTMLElement.prototype) { return; } - Object.getOwnPropertyNames(proto) - .filter((name) => { - const isPublic = !name.startsWith('_'); - const isOwn = !['arguments', 'prototype', 'caller', 'constructor', 'name', 'length'].includes(name); - const isDefined = isOwn && !!proto[name]; - return isPublic && isOwn && isDefined; - }) - .forEach((name) => { + + for (const name of Object.getOwnPropertySymbols(proto)) { + const isPublic = !name.startsWith('_'); + const isOwn = !['arguments', 'prototype', 'caller', 'constructor', 'name', 'length'].includes(name); + const isDefined = isOwn && !!proto[name]; + + if (isPublic && isOwn && isDefined) { extractedProperties[name] = proto[name]; - }); + } + } + extract(Object.getPrototypeOf(proto)); }; extract(klass); diff --git a/build-svg-sprite.js b/build-svg-sprite.js index 64d3580f1..2c5da84fe 100644 --- a/build-svg-sprite.js +++ b/build-svg-sprite.js @@ -1,7 +1,7 @@ -import fs from 'fs'; -import path from 'path'; +import fs from 'node:fs'; +import path from 'node:path'; +import url from 'node:url'; import SVGSpriter from 'svg-sprite'; -import url from 'url'; const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); @@ -50,7 +50,7 @@ const spriter = new SVGSpriter(config); console.log('Generating SVG sprite...'); -DATA.forEach((item) => { +for (const item of DATA) { fs.readdir(item.input, (err, files) => { if (err) { throw err; @@ -58,11 +58,11 @@ DATA.forEach((item) => { console.log(`Processing ${item.input}...`); - files.forEach((file) => { + for (const file of files) { const filePath = path.resolve(item.input, file); console.log(`Icon processed: ${filePath}`); spriter.add(filePath, null, fs.readFileSync(filePath, { encoding: 'utf-8' })); - }); + } spriter.compile((error, result) => { if (error) { @@ -74,4 +74,4 @@ DATA.forEach((item) => { fs.writeFileSync(item.output, jsTemplate); }); }); -}); +} diff --git a/build.js b/build.js index 3200297e9..6ffadde12 100644 --- a/build.js +++ b/build.js @@ -1,24 +1,19 @@ +import fs from 'node:fs'; +import path, { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; // @ts-check import esbuild from 'esbuild'; -import fs from 'fs'; -import path, { dirname } from 'path'; -import { fileURLToPath } from 'url'; import { buildItems } from './build-items.js'; -let __dirname = dirname(fileURLToPath(import.meta.url)); -let packageRootPath = __dirname; +const __dirname = dirname(fileURLToPath(import.meta.url)); +const packageRootPath = __dirname; function jsBanner() { - let license = fs.readFileSync(path.join(packageRootPath, './LICENSE')).toString(); - return ( - '/**\n' + - ' * @license\n' + - license - .split('\n') - .map((line) => ` * ${line}`) - .join('\n') + - '\n */' - ); + const license = fs.readFileSync(path.join(packageRootPath, './LICENSE')).toString(); + return `/**\n * @license\n${license + .split('\n') + .map((line) => ` * ${line}`) + .join('\n')}\n */`; } /** @param {import('./build-items.js').BuildItem} buildItem */ @@ -42,13 +37,13 @@ function build(buildItem) { if (!buildItem.minifyHtml) { return; } - let js = fs.readFileSync(buildItem.out).toString(); + const js = fs.readFileSync(buildItem.out).toString(); /** @param {string} str */ - let checkIfHtml = (str) => { + const checkIfHtml = (str) => { return str.includes('<') && (str.includes('')); }; /** @param {string} ch */ - let processChunk = (ch) => { + const processChunk = (ch) => { if (checkIfHtml(ch)) { let htmlMin = ch.split('\n').join(' '); while (htmlMin.includes(' ')) { @@ -59,7 +54,7 @@ function build(buildItem) { } return ch; }; - let result = js + const result = js .split('`') .map((chunk) => processChunk(chunk)) .join('`') @@ -70,6 +65,6 @@ function build(buildItem) { }); } -for (let buildItem of buildItems) { +for (const buildItem of buildItems) { build(buildItem); } diff --git a/demo/preview-proxy/secure-delivery-proxy.js b/demo/preview-proxy/secure-delivery-proxy.js index 4847ad689..03541ec74 100644 --- a/demo/preview-proxy/secure-delivery-proxy.js +++ b/demo/preview-proxy/secure-delivery-proxy.js @@ -1,20 +1,20 @@ -import http from 'http'; +import http from 'node:http'; const PORT = 3000; http - .createServer(function (request, response) { + .createServer((request, response) => { if (request.method !== 'GET') { return response.end('Only GET requests are supported'); } - let url = new URL(request.url, `http://localhost:${PORT}`); - let path = url.pathname.replace(/([^\/])$/, '$1/'); + const url = new URL(request.url, `http://localhost:${PORT}`); + const path = url.pathname.replace(/([^\/])$/, '$1/'); if (path !== '/preview/') { return response.end('Only `/preview/` path is supported'); } - let searchParams = url.searchParams; - let fileUrl = searchParams.get('url'); - let size = searchParams.get('size'); + const searchParams = url.searchParams; + const fileUrl = searchParams.get('url'); + const size = searchParams.get('size'); console.log(`Got request. Url: "${fileUrl}". Size: "${size}"`); if (!fileUrl) { return response.end('`url` parameter is required'); diff --git a/package.json b/package.json index dacdec9cc..004e0c0e5 100644 --- a/package.json +++ b/package.json @@ -76,18 +76,18 @@ "build:svg-sprites": "node ./build-svg-sprite.js", "build": "run-s build:svg-sprites build:ssr-stubs build:web build:types build:jsx:types", "tsc": "tsc --project tsconfig.json", - "lint:js": "biome lint ./", - "lint:js:fix": "biome format --write ./", + "lint:js": "biome check ./", + "lint:js:fix": "biome check --write ./", "lint:css": "stylelint './**/*.css'", "lint:css:fix": "stylelint './**/*.css' --fix", "lint": "run-s lint:js lint:css", "clean:web": "rimraf -g './web/**/*.{js,css}'", "clean:types": "rimraf -g './{abstract,blocks,solutions,web,utils,test,locales}/**/*.{d.ts,d.ts.map}' && rimraf -g './*.{d.ts,d.ts.map}'", "clean": "run-s clean:*", - "format:js": "biome format --write './**/*.{js,cjs}'", + "format:js": "biome check --write './'", "format:css": "prettier --write --parser css './**/*.css'", "format:html": "prettier --write --parser html './**/*.html'", - "format:json": "biome format --write --parser json './**/*.json'", + "format:json": "biome check --write './'", "format:md": "prettier --write --parser markdown './**/*.md'", "format": "run-s lint:js:fix lint:css:fix format:js format:css format:json format:md", "prepare": "husky install" diff --git a/ship.config.mjs b/ship.config.mjs index 4c4c45e8c..dc97bf9d5 100644 --- a/ship.config.mjs +++ b/ship.config.mjs @@ -1,5 +1,5 @@ -import fs from 'fs'; -import path from 'path'; +import fs from 'node:fs'; +import path from 'node:path'; export default { buildCommand: () => 'npm run build', @@ -7,10 +7,10 @@ export default { versionUpdated: ({ version, dir }) => { function generateEnvFile(variables) { let template = fs.readFileSync(path.join(dir, './env.template.js')).toString(); - template = template.replaceAll(/{{(.+?)}}/g, (match, p1) => { + template = template.replaceAll(/{{(.+?)}}/g, (_, p1) => { return variables[p1]; }); - template = `/** Do not edit this file manually. It's generated during build process. */\n` + template; + template = `/** Do not edit this file manually. It's generated during build process. */\n${template}`; fs.writeFileSync(path.join(dir, './env.js'), template); } diff --git a/solutions/file-uploader/inline/FileUploaderInline.js b/solutions/file-uploader/inline/FileUploaderInline.js index def7a33b1..e437ddf95 100644 --- a/solutions/file-uploader/inline/FileUploaderInline.js +++ b/solutions/file-uploader/inline/FileUploaderInline.js @@ -49,7 +49,7 @@ export class FileUploaderInline extends SolutionBlock { }); this.sub('*history', () => { - this.$['couldCancel'] = this.couldHistoryBack || this.couldShowList; + this.$.couldCancel = this.couldHistoryBack || this.couldShowList; }); } } diff --git a/solutions/file-uploader/regular/FileUploaderRegular.js b/solutions/file-uploader/regular/FileUploaderRegular.js index cfb8a1e4d..8012bc4f7 100644 --- a/solutions/file-uploader/regular/FileUploaderRegular.js +++ b/solutions/file-uploader/regular/FileUploaderRegular.js @@ -1,7 +1,7 @@ // @ts-check import { SolutionBlock } from '../../../abstract/SolutionBlock.js'; -import { EventType } from '../../../blocks/UploadCtxProvider/EventEmitter.js'; import { asBoolean } from '../../../blocks/Config/normalizeConfigValue.js'; +import { EventType } from '../../../blocks/UploadCtxProvider/EventEmitter.js'; export class FileUploaderRegular extends SolutionBlock { constructor() { diff --git a/stylelint-force-app-name-prefix.cjs b/stylelint-force-app-name-prefix.cjs index 2be735e10..545afbc63 100644 --- a/stylelint-force-app-name-prefix.cjs +++ b/stylelint-force-app-name-prefix.cjs @@ -6,109 +6,105 @@ * - Use `.lr-` prefix instead of `.lr ` * - Add support for tag prefixes: `lr-` */ -var _ = require('lodash'); -var stylelint = require('stylelint'); +const _ = require('lodash'); +const stylelint = require('stylelint'); -var ruleName = 'plugin/stylelint-force-app-name-prefix'; +const ruleName = 'plugin/stylelint-force-app-name-prefix'; -var optionsSchema = { +const optionsSchema = { appName: _.isString, }; const messages = stylelint.utils.ruleMessages(ruleName, { - invalid: (selector, appName) => 'Selector "' + selector + '" is out of control, please wrap within .' + appName, + invalid: (selector, appName) => `Selector "${selector}" is out of control, please wrap within .${appName}`, invalidKeyFrames: (keyframesName, appName) => - 'Keyframes name "' + keyframesName + '" is out of control, please prefix with ' + appName + '-', + `Keyframes name "${keyframesName}" is out of control, please prefix with ${appName}-`, invalidFontFace: (fontFamily, appName) => - 'Custom font-family "' + fontFamily + '" is out of control, please prefix with ' + appName + '-', + `Custom font-family "${fontFamily}" is out of control, please prefix with ${appName}-`, }); function findTopParentSelector(node) { if (node.parent.type === 'root' || node.parent.type === 'atrule') { return node.selector; - } else { - return findTopParentSelector(node.parent); } + return findTopParentSelector(node.parent); } function isInsideAtRule(node) { if (node.parent.type === 'atrule') { return true; - } else if (node.parent.type === 'root') { + } + if (node.parent.type === 'root') { return false; - } else { - return findTopParentSelector(node.parent); } + return findTopParentSelector(node.parent); } -module.exports = stylelint.createPlugin(ruleName, function (options) { - return function (root, result) { - if (!options) return; - var validOptions = stylelint.utils.validateOptions(result, ruleName, { - actual: options, - possible: optionsSchema, - }); - if (!validOptions) return; +module.exports = stylelint.createPlugin(ruleName, (options) => (root, result) => { + if (!options) return; + const validOptions = stylelint.utils.validateOptions(result, ruleName, { + actual: options, + possible: optionsSchema, + }); + if (!validOptions) return; - const whiteList = ['.' + options.appName, /^:.*/]; + const whiteList = [`.${options.appName}`, /^:.*/]; - root.walkAtRules('keyframes', (rule) => { - const keyframesName = rule.params; + root.walkAtRules('keyframes', (rule) => { + const keyframesName = rule.params; + + if (keyframesName.indexOf(`${options.appName}-`) === -1) { + stylelint.utils.report({ + ruleName: ruleName, + result: result, + node: rule, + message: messages.invalidKeyFrames(keyframesName, options.appName), + }); + } + }); - if (keyframesName.indexOf(options.appName + '-') === -1) { + root.walkAtRules('font-face', (rule) => { + rule.walkDecls('font-family', (decl) => { + if (decl.value.indexOf(`${options.appName}-`) === -1) { stylelint.utils.report({ ruleName: ruleName, result: result, node: rule, - message: messages.invalidKeyFrames(keyframesName, options.appName), + message: messages.invalidFontFace(decl.value, options.appName), }); } }); + }); - root.walkAtRules('font-face', (rule) => { - rule.walkDecls('font-family', (decl) => { - if (decl.value.indexOf(options.appName + '-') === -1) { - stylelint.utils.report({ - ruleName: ruleName, - result: result, - node: rule, - message: messages.invalidFontFace(decl.value, options.appName), - }); + root.walkRules((rule) => { + if (isInsideAtRule(rule)) return; + const topParentSelector = findTopParentSelector(rule); + if ( + whiteList.find((whiteRule) => { + if (whiteRule instanceof RegExp) { + return whiteRule.test(topParentSelector); } - }); - }); - - root.walkRules((rule) => { - if (isInsideAtRule(rule)) return; - const topParentSelector = findTopParentSelector(rule); - if ( - whiteList.find(function (whiteRule) { - if (whiteRule instanceof RegExp) { - return whiteRule.test(topParentSelector); - } else { - return whiteRule === topParentSelector; - } - }) - ) { - // in white list, skipped - return; - } + return whiteRule === topParentSelector; + }) + ) { + // in white list, skipped + return; + } - if ( - topParentSelector.indexOf('.' + options.appName + '-') === 0 || - topParentSelector.indexOf(options.appName + '-') === 0 - ) { - // good - } else { - stylelint.utils.report({ - ruleName: ruleName, - result: result, - node: rule, - message: messages.invalid(rule.selector, options.appName), - }); - } - }); - }; + if ( + topParentSelector.indexOf(`.${options.appName}-`) === 0 || + topParentSelector.indexOf(`${options.appName}-`) === 0 + ) { + // good + } else { + stylelint.utils.report({ + ruleName: ruleName, + result: result, + node: rule, + message: messages.invalid(rule.selector, options.appName), + }); + } + }); }); module.exports.ruleName = ruleName; diff --git a/test-locales.js b/test-locales.js index ec10e4b77..580ad5cfc 100644 --- a/test-locales.js +++ b/test-locales.js @@ -1,6 +1,6 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; import { chromium } from 'playwright'; -import fs from 'fs/promises'; -import path from 'path'; const REFERENCE_LOCALE = 'en'; const SOCIAL_SOURCE_LANGS = ['de', 'en', 'es', 'fr', 'he', 'it', 'nl', 'pl', 'pt', 'ru', 'tr', 'uk', 'zh-TW', 'zh']; diff --git a/types/events.d.ts b/types/events.d.ts index 5e1ca1a30..050dcafc8 100644 --- a/types/events.d.ts +++ b/types/events.d.ts @@ -2,4 +2,4 @@ import type { EventPayload } from '../blocks/UploadCtxProvider/EventEmitter'; export type EventMap = { [T in keyof EventPayload]: CustomEvent; -}; \ No newline at end of file +}; diff --git a/types/exported.d.ts b/types/exported.d.ts index ba034a1d6..d83e6b4a0 100644 --- a/types/exported.d.ts +++ b/types/exported.d.ts @@ -1,6 +1,6 @@ +import type { FuncCollectionValidator, FuncFileValidator } from '../abstract/ValidationManager'; import type { LocaleDefinition } from '../abstract/localeRegistry'; import type { complexConfigKeys } from '../blocks/Config/Config'; -import type { FuncFileValidator, FuncCollectionValidator } from '../abstract/ValidationManager'; export type { FuncFileValidator, FuncCollectionValidator } from '../abstract/ValidationManager'; @@ -83,8 +83,8 @@ export type ConfigAttributesType = KebabCaseKeys & LowerCaseKey export type KebabCase = S extends `${infer C}${infer T}` ? T extends Uncapitalize - ? `${Uncapitalize}${KebabCase}` - : `${Uncapitalize}-${KebabCase}` + ? `${Uncapitalize}${KebabCase}` + : `${Uncapitalize}-${KebabCase}` : S; export type KebabCaseKeys> = { [Key in keyof T as KebabCase]: T[Key] }; export type LowerCase = Lowercase; @@ -92,9 +92,10 @@ export type LowerCaseKeys> = { [Key in keyof T export type OutputFileStatus = 'idle' | 'uploading' | 'success' | 'failed' | 'removed'; -export type OutputCustomErrorType = 'CUSTOM_ERROR' +export type OutputCustomErrorType = 'CUSTOM_ERROR'; -export type OutputFileErrorType = OutputCustomErrorType +export type OutputFileErrorType = + | OutputCustomErrorType | 'NOT_AN_IMAGE' | 'FORBIDDEN_FILE_TYPE' | 'FILE_SIZE_EXCEEDED' @@ -102,7 +103,11 @@ export type OutputFileErrorType = OutputCustomErrorType | 'NETWORK_ERROR' | 'UNKNOWN_ERROR'; -export type OutputCollectionErrorType = OutputCustomErrorType | 'SOME_FILES_HAS_ERRORS' | 'TOO_MANY_FILES' | 'TOO_FEW_FILES'; +export type OutputCollectionErrorType = + | OutputCustomErrorType + | 'SOME_FILES_HAS_ERRORS' + | 'TOO_MANY_FILES' + | 'TOO_FEW_FILES'; export type OutputFileErrorPayload = { entry: OutputFileEntry; @@ -113,7 +118,7 @@ export type OutputErrorTypePayload = { FORBIDDEN_FILE_TYPE: OutputFileErrorPayload; FILE_SIZE_EXCEEDED: OutputFileErrorPayload; - SOME_FILES_HAS_ERRORS: {}; + SOME_FILES_HAS_ERRORS: Record; TOO_MANY_FILES: { min: number; max: number; @@ -136,22 +141,23 @@ export type OutputErrorTypePayload = { CUSTOM_ERROR: Record; }; -export type OutputError = - T extends OutputCustomErrorType +export type OutputError = T extends OutputCustomErrorType ? { - type?: T; - message: string; - payload?: OutputErrorTypePayload[T]; - } - : T extends keyof OutputErrorTypePayload ? { - type: T; - message: string; - payload?: OutputErrorTypePayload[T]; - } : never + type?: T; + message: string; + payload?: OutputErrorTypePayload[T]; + } + : T extends keyof OutputErrorTypePayload + ? { + type: T; + message: string; + payload?: OutputErrorTypePayload[T]; + } + : never; -export type OutputErrorFile = OutputError +export type OutputErrorFile = OutputError; -export type OutputErrorCollection = OutputError +export type OutputErrorCollection = OutputError; export type OutputFileEntry = { status: TStatus; @@ -168,7 +174,7 @@ export type OutputFileEntry uploadProgress: number; fullPath: string | null; } & ( - | { + | { status: 'success'; fileInfo: UploadcareFile; uuid: string; @@ -180,7 +186,7 @@ export type OutputFileEntry isRemoved: false; errors: []; } - | { + | { status: 'failed'; fileInfo: UploadcareFile | null; uuid: string | null; @@ -192,7 +198,7 @@ export type OutputFileEntry isRemoved: false; errors: OutputError[]; } - | { + | { status: 'uploading'; fileInfo: null; uuid: null; @@ -204,7 +210,7 @@ export type OutputFileEntry isRemoved: false; errors: []; } - | { + | { status: 'removed'; fileInfo: UploadcareFile | null; uuid: string | null; @@ -216,7 +222,7 @@ export type OutputFileEntry isRemoved: true; errors: OutputError[]; } - | { + | { status: 'idle'; fileInfo: null; uuid: null; @@ -228,7 +234,7 @@ export type OutputFileEntry isRemoved: false; errors: []; } - ); +); export type OutputCollectionStatus = 'idle' | 'uploading' | 'success' | 'failed'; @@ -252,43 +258,41 @@ export type OutputCollectionState< } & (TGroupFlag extends 'has-group' ? { group: UploadcareGroup } : TGroupFlag extends 'maybe-has-group' - ? { group: UploadcareGroup | null } - : never) & + ? { group: UploadcareGroup | null } + : never) & ( | { - status: 'idle'; - isFailed: false; - isUploading: false; - isSuccess: false; - errors: []; - allEntries: OutputFileEntry<'idle' | 'success'>[]; - } + status: 'idle'; + isFailed: false; + isUploading: false; + isSuccess: false; + errors: []; + allEntries: OutputFileEntry<'idle' | 'success'>[]; + } | { - status: 'uploading'; - isFailed: false; - isUploading: true; - isSuccess: false; - errors: []; - allEntries: OutputFileEntry[]; - } + status: 'uploading'; + isFailed: false; + isUploading: true; + isSuccess: false; + errors: []; + allEntries: OutputFileEntry[]; + } | { - status: 'success'; - isFailed: false; - isUploading: false; - isSuccess: true; - errors: []; - allEntries: OutputFileEntry<'success'>[]; - } + status: 'success'; + isFailed: false; + isUploading: false; + isSuccess: true; + errors: []; + allEntries: OutputFileEntry<'success'>[]; + } | { - status: 'failed'; - isFailed: true; - isUploading: false; - isSuccess: false; - errors: OutputError[]; - allEntries: OutputFileEntry[]; - } + status: 'failed'; + isFailed: true; + isUploading: false; + isSuccess: false; + errors: OutputError[]; + allEntries: OutputFileEntry[]; + } ); export { EventType, EventPayload } from '../blocks/UploadCtxProvider/EventEmitter'; - -export { }; diff --git a/types/global.d.ts b/types/global.d.ts index 8b3d08dca..2ca9f08f2 100644 --- a/types/global.d.ts +++ b/types/global.d.ts @@ -1,5 +1,5 @@ import { LR_WINDOW_KEY } from '../abstract/connectBlocksFrom.js'; -import * as blocks from '../index.js'; +import type * as blocks from '../index.js'; declare global { interface Window { diff --git a/types/index.d.ts b/types/index.d.ts index aa5d590dc..14b006d18 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,2 +1,2 @@ -export * from "./events.js"; -export * from "./exported.js"; +export * from './events.js'; +export * from './exported.js'; diff --git a/types/jsx.d.ts b/types/jsx.d.ts index a0993ed44..0c8563162 100644 --- a/types/jsx.d.ts +++ b/types/jsx.d.ts @@ -15,42 +15,45 @@ type CommonHtmlAttributes = Partial< Pick, 'id' | 'children' | 'hidden'> & { class: React.HTMLAttributes['className'] } >; -type CustomElement = React.DetailedHTMLProps, C> & A; +type CustomElement = React.DetailedHTMLProps, C> & A; + +// biome-ignore lint/suspicious/noExplicitAny: +type UntypedElement = any; declare namespace JSX { interface IntrinsicElements { - 'lr-crop-frame': any; - 'lr-editor-crop-button-control': any; - 'lr-editor-filter-control': any; - 'lr-editor-operation-control': any; - 'lr-editor-image-cropper': any; - 'lr-editor-image-fader': any; - 'lr-editor-scroller': any; - 'lr-editor-slider': any; - 'lr-editor-toolbar': any; - 'lr-lr-btn-ui': any; - 'lr-line-loader-ui': any; - 'lr-presence-toggle': any; - 'lr-slider-ui': any; - 'lr-icon': any; - 'lr-img': any; - 'lr-simple-btn': any; - 'lr-start-from': any; - 'lr-drop-area': any; - 'lr-source-btn': any; - 'lr-source-list': any; - 'lr-file-item': any; - 'lr-modal': any; - 'lr-upload-list': any; - 'lr-url-source': any; - 'lr-camera-source': any; - 'lr-confirmation-dialog': any; - 'lr-progress-bar-common': any; - 'lr-progress-bar': any; - 'lr-editable-canvas': any; - 'lr-external-source': any; - 'lr-tabs': any; - 'lr-cloud-image-editor-activity': any; + 'lr-crop-frame': UntypedElement; + 'lr-editor-crop-button-control': UntypedElement; + 'lr-editor-filter-control': UntypedElement; + 'lr-editor-operation-control': UntypedElement; + 'lr-editor-image-cropper': UntypedElement; + 'lr-editor-image-fader': UntypedElement; + 'lr-editor-scroller': UntypedElement; + 'lr-editor-slider': UntypedElement; + 'lr-editor-toolbar': UntypedElement; + 'lr-lr-btn-ui': UntypedElement; + 'lr-line-loader-ui': UntypedElement; + 'lr-presence-toggle': UntypedElement; + 'lr-slider-ui': UntypedElement; + 'lr-icon': UntypedElement; + 'lr-img': UntypedElement; + 'lr-simple-btn': UntypedElement; + 'lr-start-from': UntypedElement; + 'lr-drop-area': UntypedElement; + 'lr-source-btn': UntypedElement; + 'lr-source-list': UntypedElement; + 'lr-file-item': UntypedElement; + 'lr-modal': UntypedElement; + 'lr-upload-list': UntypedElement; + 'lr-url-source': UntypedElement; + 'lr-camera-source': UntypedElement; + 'lr-confirmation-dialog': UntypedElement; + 'lr-progress-bar-common': UntypedElement; + 'lr-progress-bar': UntypedElement; + 'lr-editable-canvas': UntypedElement; + 'lr-external-source': UntypedElement; + 'lr-tabs': UntypedElement; + 'lr-cloud-image-editor-activity': UntypedElement; 'lr-cloud-image-editor-block': CustomElement< CloudImageEditorBlock, CtxAttributes & ({ uuid: string } | { 'cdn-url': string }) & Partial<{ tabs: string; 'crop-preset': string }> diff --git a/types/test/lr-config.test-d.tsx b/types/test/lr-config.test-d.tsx index f5e8ca914..b17a3a629 100644 --- a/types/test/lr-config.test-d.tsx +++ b/types/test/lr-config.test-d.tsx @@ -1,25 +1,25 @@ import React from 'react'; import { expectType } from 'tsd'; import '../jsx.js'; -import { OutputFileEntry, FuncCollectionValidator, FuncFileValidator } from '../index.js'; +import type { FuncCollectionValidator, FuncFileValidator, OutputFileEntry } from '../index.js'; // @ts-expect-error untyped props -() => ; +() => ; // @ts-expect-error missing ctx-name -() => ; +() => ; // allow common html attributes and required ctx-name -() => ; +() =>