From c521c72c9f2b1928191ea32b2296011bafeae78c Mon Sep 17 00:00:00 2001 From: Aleksandr Grenishin Date: Fri, 6 May 2022 13:17:04 +0300 Subject: [PATCH] fix: pass `cdnUrlModifiers` to the output (#125) * fix: pass `cdnUrlModifiers` to the output * chore: replace module type import with jsdoc type import * chore: rename local variable * chore: update todo comment --- abstract/Block.js | 14 +++++++-- abstract/uploadEntrySchema.js | 33 +++++++++++++++++++-- blocks/CloudImageEditor/CloudImageEditor.js | 8 +++-- blocks/CloudImageEditor/src/lib/cdnUtils.js | 16 ++++++++-- blocks/CloudImageEditor/src/state.js | 25 ++++++++++------ blocks/CloudImageEditor/src/types.js | 8 +++++ blocks/FileItem/FileItem.js | 6 ++-- blocks/UploadDetails/UploadDetails.js | 12 ++++---- 8 files changed, 95 insertions(+), 27 deletions(-) diff --git a/abstract/Block.js b/abstract/Block.js index 043c3e4c2..ba04c58cb 100644 --- a/abstract/Block.js +++ b/abstract/Block.js @@ -380,8 +380,18 @@ export class Block extends BaseComponent { let items = this.uploadCollection.items(); items.forEach((itemId) => { let uploadEntryData = Data.getNamedCtx(itemId).store; - let info = uploadEntryData.fileInfo; - data.push(info); + /** @type {import('../submodules/upload-client/upload-client.js').UploadcareFile} */ + let fileInfo = uploadEntryData.fileInfo; + // TODO: remove `cdnUrlModifiers` from fileInfo object returned by upload-client, `cdnUrl` should not contain modifiers + // TODO: create OutputItem instance instead of creating inline object, + // fileInfo should be returned as is along with the other data + // TODO: pass editorTransformations to the user + let outputItem = { + ...fileInfo, + cdnUrlModifiers: uploadEntryData.cdnUrlModifiers || fileInfo.cdnUrlModifiers, + cdnUrl: uploadEntryData.cdnUrl || fileInfo.cdnUrl, + }; + data.push(outputItem); }); this.$['*outputData'] = data; } diff --git a/abstract/uploadEntrySchema.js b/abstract/uploadEntrySchema.js index 966b8174d..aedb04770 100644 --- a/abstract/uploadEntrySchema.js +++ b/abstract/uploadEntrySchema.js @@ -1,6 +1,27 @@ import { UploadcareFile, UploadClientError } from '../submodules/upload-client/upload-client.js'; -/** @enum {{ type; value; nullable?: Boolean }} */ +/** + * @typedef {Object} UploadEntry + * @property {File} file + * @property {String} externalUrl + * @property {String} fileName + * @property {number} fileSize + * @property {number} lastModified + * @property {number} uploadProgress + * @property {String} uuid + * @property {Boolean} isImage + * @property {String} mimeType + * @property {UploadClientError} uploadError + * @property {String} validationErrorMsg + * @property {String} ctxName + * @property {String} cdnUrl + * @property {String} cdnUrlModifiers + * @property {import('../blocks/CloudImageEditor/src/types.js').Transformations} editorTransformations + * @property {UploadcareFile} fileInfo + * @property {Boolean} isUploading + */ + +/** @type {{ [key in keyof UploadEntry]: { type; value; nullable?: Boolean } }} */ export const uploadEntrySchema = Object.freeze({ file: { type: File, @@ -52,10 +73,18 @@ export const uploadEntrySchema = Object.freeze({ type: String, value: null, }, - transformationsUrl: { + cdnUrl: { + type: String, + value: null, + }, + cdnUrlModifiers: { type: String, value: null, }, + editorTransformations: { + type: Object, + value: null, + }, fileInfo: { type: UploadcareFile, value: null, diff --git a/blocks/CloudImageEditor/CloudImageEditor.js b/blocks/CloudImageEditor/CloudImageEditor.js index ba10f53c6..3f533ce36 100644 --- a/blocks/CloudImageEditor/CloudImageEditor.js +++ b/blocks/CloudImageEditor/CloudImageEditor.js @@ -33,10 +33,14 @@ export class CloudImageEditor extends Block { }); } + /** @param {CustomEvent} e */ handleApply(e) { let result = e.detail; - let { transformationsUrl } = result; - this.entry.setValue('transformationsUrl', transformationsUrl); + this.entry.setMultipleValues({ + cdnUrl: result.cdnUrl, + cdnUrlModifiers: result.cdnUrlModifiers, + editorTransformations: result.transformations + }) this.historyBack(); } diff --git a/blocks/CloudImageEditor/src/lib/cdnUtils.js b/blocks/CloudImageEditor/src/lib/cdnUtils.js index 2d429cb39..fe3511bf8 100644 --- a/blocks/CloudImageEditor/src/lib/cdnUtils.js +++ b/blocks/CloudImageEditor/src/lib/cdnUtils.js @@ -1,3 +1,5 @@ +// TODO: add tests for the all this stuff + export const OPERATIONS_ZEROS = { brightness: 0, exposure: 0, @@ -45,11 +47,16 @@ function operationToStr(operation, options) { } /** + * TODO: obviously, not using regexps will be faster, consider to get rid of it + * * @param {String[]} list * @returns {String} */ export function joinCdnOperations(...list) { - return list.join('/-/').replace(/\/\//g, '/'); + return list.map(str => { + str = str.replace(/^-\//g, ''); // remove leading '-/' + return str + }).join('/-/').replace(/\/\//g, '/'); } const ORDER = [ @@ -81,7 +88,7 @@ export function transformationsToString(transformations) { let options = transformations[operation]; return operationToStr(operation, options); }) - .filter((str) => str && str.length > 0) + .filter((str) => !!str) ); } @@ -91,8 +98,11 @@ export function transformationsToString(transformations) { * @returns {String} */ export function constructCdnUrl(originalUrl, ...list) { + if (originalUrl && originalUrl[originalUrl.length - 1] !== '/') { + originalUrl += '/'; + } return ( - originalUrl.replace(/\/$/g, '') + '/-/' + joinCdnOperations(...list.filter((str) => str && str.length > 0)) + '/' + (originalUrl?.replace(/\/$/g, '') || '') + '-/' + joinCdnOperations(...list.filter((str) => !!str).map(str => str.trim())) + '/' ); } diff --git a/blocks/CloudImageEditor/src/state.js b/blocks/CloudImageEditor/src/state.js index d070d9ea7..f180dc131 100644 --- a/blocks/CloudImageEditor/src/state.js +++ b/blocks/CloudImageEditor/src/state.js @@ -42,18 +42,25 @@ export function initState(fnCtx) { if (!transformations) { return; } - let transformationsUrl = constructCdnUrl( - fnCtx.$['*originalUrl'], - transformationsToString(transformations), + let originalUrl = fnCtx.$['*originalUrl'] + let cdnUrlModifiers = constructCdnUrl(null, transformationsToString(transformations)); + + let cdnUrl = constructCdnUrl( + originalUrl, + cdnUrlModifiers, 'preview' - ); + ) + + /** @type {import('./types.js').ApplyResult} */ + let eventData = { + originalUrl, + cdnUrlModifiers, + cdnUrl, + transformations, + } fnCtx.dispatchEvent( new CustomEvent('apply', { - detail: { - originalUrl: fnCtx.$['*originalUrl'], - transformationsUrl, - transformations, - }, + detail: eventData, }) ); fnCtx.remove(); diff --git a/blocks/CloudImageEditor/src/types.js b/blocks/CloudImageEditor/src/types.js index f08f4b864..6f80d2f80 100644 --- a/blocks/CloudImageEditor/src/types.js +++ b/blocks/CloudImageEditor/src/types.js @@ -35,4 +35,12 @@ * @property {{ dimensions: [number, number]; coords: [number, number] }} [crop] */ +/** + * @typedef {Object} ApplyResult + * @property {string} originalUrl + * @property {string} cdnUrlModifiers + * @property {string} cdnUrl + * @property {Transformations} transformations + */ + export {}; diff --git a/blocks/FileItem/FileItem.js b/blocks/FileItem/FileItem.js index b162d183d..20806a5b3 100644 --- a/blocks/FileItem/FileItem.js +++ b/blocks/FileItem/FileItem.js @@ -116,14 +116,14 @@ export class FileItem extends Block { } }); - this.entry.subscribe('transformationsUrl', (transformationsUrl) => { - if (!transformationsUrl) { + this.entry.subscribe('cdnUrl', (cdnUrl) => { + if (!cdnUrl) { return; } if (this.entry.getValue('isImage')) { this._revokeThumbUrl(); let size = this.$['*--cfg-thumb-size'] || 76; - this.$.thumbUrl = `url(${transformationsUrl}-/scale_crop/${size}x${size}/center/)`; + this.$.thumbUrl = `url(${cdnUrl}-/scale_crop/${size}x${size}/center/)`; } }); diff --git a/blocks/UploadDetails/UploadDetails.js b/blocks/UploadDetails/UploadDetails.js index d98ecdfd2..96e5f799c 100644 --- a/blocks/UploadDetails/UploadDetails.js +++ b/blocks/UploadDetails/UploadDetails.js @@ -86,7 +86,7 @@ export class UploadDetails extends Block { */ this._file = file; let isImage = this._file.type.includes('image'); - if (isImage && !entry.getValue('transformationsUrl')) { + if (isImage && !entry.getValue('cdnUrl')) { this.eCanvas.setImageFile(this._file); this.set$({ checkerboard: true, @@ -103,19 +103,19 @@ export class UploadDetails extends Block { tmpSub('fileName', (name) => { this.$.fileName = name; this.$.onNameInput = () => { - let name = this.ref.file_name_input['value']; + let value = this.ref.file_name_input['value']; Object.defineProperty(this._file, 'name', { writable: true, - value: name, + value: value, }); - this.entry.setValue('fileName', name); + this.entry.setValue('fileName', value); }; }); tmpSub('fileSize', (size) => { this.$.fileSize = Number.isFinite(size) ? this.fileSizeFmt(size) : this.l10n('file-size-unknown'); }); tmpSub('uuid', (uuid) => { - if (uuid && !this.entry.getValue('transformationsUrl')) { + if (uuid && !this.entry.getValue('cdnUrl')) { this.eCanvas.clear(); this.set$({ imageUrl: `https://ucarecdn.com/${uuid}/`, @@ -139,7 +139,7 @@ export class UploadDetails extends Block { this.showNonImageThumb(); } }); - tmpSub('transformationsUrl', (url) => { + tmpSub('cdnUrl', (url) => { if (!url) { return; }