Skip to content

Commit

Permalink
Deploying to gh-pages from @ c2623d4 🚀
Browse files Browse the repository at this point in the history
  • Loading branch information
nd0ut committed Oct 26, 2023
1 parent 878fe3e commit 22ccc84
Show file tree
Hide file tree
Showing 21 changed files with 281 additions and 158 deletions.
52 changes: 31 additions & 21 deletions abstract/TypedCollection.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,19 @@ export class TypedCollection {
this.__watchList = options.watchList || [];
/**
* @private
* @type {(list: string[], added: Set<any>, removed: Set<any>) => void}
* @type {Object<string, any>}
*/
this.__handler = options.handler || null;
this.__subsMap = Object.create(null);
/**
* @private
* @type {Object<string, any>}
* @type {Set<Function>}
*/
this.__subsMap = Object.create(null);
this.__propertyObservers = new Set();
/**
* @private
* @type {Set}
* @type {Set<(list: string[], added: Set<any>, removed: Set<any>) => void>}
*/
this.__observers = new Set();
this.__collectionObservers = new Set();
/**
* @private
* @type {Set<string>}
Expand Down Expand Up @@ -78,7 +78,10 @@ export class TypedCollection {
changeMap[propName].add(ctxId);
/** @private */
this.__observeTimeout = window.setTimeout(() => {
this.__observers.forEach((handler) => {
if (Object.keys(changeMap).length === 0) {
return;
}
this.__propertyObservers.forEach((handler) => {
handler({ ...changeMap });
});
changeMap = Object.create(null);
Expand All @@ -96,22 +99,25 @@ export class TypedCollection {
let removed = new Set(this.__removed);
this.__added.clear();
this.__removed.clear();
this.__handler?.([...this.__items], added, removed);
for (const handler of this.__collectionObservers) {
handler?.([...this.__items], added, removed);
}
});
}

/** @param {(list: string[], added: Set<any>, removed: Set<any>) => void} handler */
setHandler(handler) {
this.__handler = handler;
observeCollection(handler) {
this.__collectionObservers.add(handler);
this.notify();
}

getHandler() {
return this.__handler;
return () => {
this.unobserveCollection(handler);
};
}

removeHandler() {
this.__handler = null;
/** @param {Function} handler */
unobserveCollection(handler) {
this.__collectionObservers.delete(handler);
}

/**
Expand Down Expand Up @@ -185,13 +191,17 @@ export class TypedCollection {
}

/** @param {Function} handler */
observe(handler) {
this.__observers.add(handler);
observeProperties(handler) {
this.__propertyObservers.add(handler);

return () => {
this.unobserveProperties(handler);
};
}

/** @param {Function} handler */
unobserve(handler) {
this.__observers.delete(handler);
unobserveProperties(handler) {
this.__propertyObservers.delete(handler);
}

/**
Expand Down Expand Up @@ -219,8 +229,8 @@ export class TypedCollection {

destroy() {
Data.deleteCtx(this.__data);
this.__observers = null;
this.__handler = null;
this.__propertyObservers = null;
this.__collectionObservers = null;
for (let id in this.__subsMap) {
this.__subsMap[id].forEach((sub) => {
sub.remove();
Expand Down
146 changes: 71 additions & 75 deletions abstract/UploaderBlock.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { ActivityBlock } from './ActivityBlock.js';
import { Data } from '@symbiotejs/symbiote';
import { calculateMaxCenteredCropFrame } from '../blocks/CloudImageEditor/src/crop-utils.js';
import { parseCropPreset } from '../blocks/CloudImageEditor/src/lib/parseCropPreset.js';
import { Modal } from '../blocks/Modal/Modal.js';
import { UploadSource } from '../blocks/utils/UploadSource.js';
import { serializeCsv } from '../blocks/utils/comma-separated.js';
import { debounce } from '../blocks/utils/debounce.js';
import { customUserAgent } from '../blocks/utils/userAgent.js';
import { createCdnUrl, createCdnUrlModifiers } from '../utils/cdn-utils.js';
Expand All @@ -17,7 +17,6 @@ import { uploaderBlockCtx } from './CTX.js';
import { EVENT_TYPES, EventData, EventManager } from './EventManager.js';
import { TypedCollection } from './TypedCollection.js';
import { uploadEntrySchema } from './uploadEntrySchema.js';
import { serializeCsv } from '../blocks/utils/comma-separated.js';

export class UploaderBlock extends ActivityBlock {
couldBeUploadCollectionOwner = false;
Expand Down Expand Up @@ -88,25 +87,13 @@ export class UploaderBlock extends ActivityBlock {
if (this.couldBeUploadCollectionOwner && !hasUploadCollectionOwner()) {
this.isUploadCollectionOwner = true;

/**
* @private
* @type {Parameters<import('./TypedCollection.js').TypedCollection['setHandler']>[0]}
*/
this.__uploadCollectionHandler = (entries, added, removed) => {
this._runValidators();

for (let entry of removed) {
entry?.getValue('abortController')?.abort();
entry?.setValue('abortController', null);
URL.revokeObjectURL(entry?.getValue('thumbUrl'));
}
this.$['*uploadList'] = entries.map((uid) => {
return { uid };
});
};
this.uploadCollection.setHandler(this.__uploadCollectionHandler);
/** @private */
this._unobserveCollection = this.uploadCollection.observeCollection(this._handleCollectonUpdate);

this.uploadCollection.observe(this._handleCollectionUpdate);
/** @private */
this._unobserveCollectionProperties = this.uploadCollection.observeProperties(
this._handleCollectionPropertiesUpdate
);

this.subConfigValue('maxLocalFileSizeBytes', () => this._debouncedRunValidators());
this.subConfigValue('multipleMin', () => this._debouncedRunValidators());
Expand All @@ -128,10 +115,8 @@ export class UploaderBlock extends ActivityBlock {
destroyCallback() {
super.destroyCallback();
if (this.isUploadCollectionOwner) {
this.uploadCollection.unobserve(this._handleCollectionUpdate);
if (this.uploadCollection.getHandler() === this.__uploadCollectionHandler) {
this.uploadCollection.removeHandler();
}
this._unobserveCollectionProperties?.();
this._unobserveCollection?.();
}
}

Expand Down Expand Up @@ -362,8 +347,16 @@ export class UploaderBlock extends ActivityBlock {
_validateMultipleLimit(entry) {
const entryIds = this.uploadCollection.items();
const entryIdx = entryIds.indexOf(entry.uid);
const multipleMin = this.cfg.multiple ? this.cfg.multipleMin : 1;
const multipleMax = this.cfg.multiple ? this.cfg.multipleMax : 1;

if (multipleMin && entryIds.length < multipleMin) {
const message = this.l10n('files-count-minimum', {
count: multipleMin,
});
return message;
}

if (multipleMax && entryIdx >= multipleMax) {
const message = this.l10n('files-count-allowed', {
count: multipleMax,
Expand Down Expand Up @@ -421,11 +414,50 @@ export class UploaderBlock extends ActivityBlock {
}
}

/** @private */
_flushOutputItems = debounce(() => {
const data = this.getOutputData();
if (data.length !== this.uploadCollection.size) {
return;
}
EventManager.emit(
new EventData({
type: EVENT_TYPES.DATA_OUTPUT,
// @ts-ignore TODO: fix this
ctx: this.ctxName,
// @ts-ignore TODO: fix this
data,
})
);
// @ts-ignore TODO: fix this
this.$['*outputData'] = data;
}, 100);

/**
* @private
* @type {Parameters<import('./TypedCollection.js').TypedCollection['observeCollection']>[0]}
*/
_handleCollectonUpdate = (entries, added, removed) => {
this._runValidators();

for (let entry of removed) {
entry?.getValue('abortController')?.abort();
entry?.setValue('abortController', null);
URL.revokeObjectURL(entry?.getValue('thumbUrl'));
}
this.$['*uploadList'] = entries.map((uid) => {
return { uid };
});
this._flushOutputItems();
};

/**
* @private
* @param {Record<string, any>} changeMap
*/
_handleCollectionUpdate = (changeMap) => {
_handleCollectionPropertiesUpdate = (changeMap) => {
this._flushOutputItems();

const uploadCollection = this.uploadCollection;
const updatedEntries = [
...new Set(
Expand Down Expand Up @@ -611,24 +643,34 @@ export class UploaderBlock extends ActivityBlock {
return options;
}

/** @param {(item: import('./TypedData.js').TypedData) => Boolean} checkFn */
/**
* @param {(item: import('./TypedData.js').TypedData) => Boolean} [checkFn]
* @returns {import('../types/exported.js').OutputFileEntry[]}
*/
getOutputData(checkFn) {
// @ts-ignore TODO: fix this
let data = [];
let items = this.uploadCollection.findItems(checkFn);
let items = checkFn ? this.uploadCollection.findItems(checkFn) : this.uploadCollection.items();
items.forEach((itemId) => {
let uploadEntryData = Data.getCtx(itemId).store;
/** @type {import('@uploadcare/upload-client').UploadcareFile} */
let fileInfo = uploadEntryData.fileInfo || {
name: uploadEntryData.fileName,
fileSize: uploadEntryData.fileSize,
originalFilename: uploadEntryData.fileName,
size: uploadEntryData.fileSize,
isImage: uploadEntryData.isImage,
mimeType: uploadEntryData.mimeType,
};
let outputItem = {
...fileInfo,
file: uploadEntryData.file,
externalUrl: uploadEntryData.externalUrl,
cdnUrlModifiers: uploadEntryData.cdnUrlModifiers,
cdnUrl: uploadEntryData.cdnUrl || fileInfo.cdnUrl,
cdnUrl: uploadEntryData.cdnUrl ?? fileInfo.cdnUrl ?? null,
validationErrorMessage: uploadEntryData.validationErrorMsg,
uploadError: uploadEntryData.uploadError,
isUploaded: !!uploadEntryData.uuid && !!uploadEntryData.fileInfo,
isValid: !uploadEntryData.validationErrorMsg && !uploadEntryData.uploadError,
};
data.push(outputItem);
});
Expand Down Expand Up @@ -660,49 +702,3 @@ UploaderBlock.sourceTypes = Object.freeze({
DRAW: 'draw',
...UploaderBlock.extSrcList,
});

Object.values(EVENT_TYPES).forEach((eType) => {
const eName = EventManager.eName(eType);
const cb = debounce(
/** @param {CustomEvent} e */
(e) => {
let outputTypes = [EVENT_TYPES.UPLOAD_FINISH, EVENT_TYPES.REMOVE, EVENT_TYPES.CLOUD_MODIFICATION];
// @ts-ignore TODO: fix this
if (outputTypes.includes(e.detail.type)) {
// @ts-ignore TODO: fix this
let dataCtx = Data.getCtx(e.detail.ctx);
/** @type {TypedCollection} */
let uploadCollection = dataCtx.read('uploadCollection');
// @ts-ignore TODO: fix this
let data = [];
uploadCollection.items().forEach((id) => {
let uploadEntryData = Data.getCtx(id).store;
/** @type {import('@uploadcare/upload-client').UploadcareFile} */
let fileInfo = uploadEntryData.fileInfo;
if (fileInfo) {
let outputItem = {
...fileInfo,
cdnUrlModifiers: uploadEntryData.cdnUrlModifiers,
cdnUrl: uploadEntryData.cdnUrl || fileInfo.cdnUrl,
};
data.push(outputItem);
}
});
EventManager.emit(
new EventData({
type: EVENT_TYPES.DATA_OUTPUT,
// @ts-ignore TODO: fix this
ctx: e.detail.ctx,
// @ts-ignore TODO: fix this
data,
})
);
// @ts-ignore TODO: fix this
dataCtx.pub('outputData', data);
}
},
0
);
// @ts-ignore TODO: fix this
window.addEventListener(eName, cb);
});
25 changes: 21 additions & 4 deletions blocks/Config/normalizeConfigValue.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,37 @@
// @ts-check

import { initialConfig } from './initialConfig.js';

/** @param {unknown} value */
const asString = (value) => String(value);
/** @param {unknown} value */
const asNumber = (value) => Number(value);
const asNumber = (value) => {
const number = Number(value);
if (Number.isNaN(number)) {
throw new Error(`Invalid number: "${value}"`);
}
return number;
};
/** @param {unknown} value */
export const asBoolean = (value) => {
if (typeof value === 'undefined' || value === null) return false;
if (typeof value === 'boolean') return value;
// for attr like multiple="true" (react will pass it as string)
if (value === 'true') return true;
// for attr flags like multiple="" (some other libs will pass it as empty string)
if (value === '') return true;
// for attr like multiple="false" (react will pass it as string)
if (value === 'false') return false;
return Boolean(value);
throw new Error(`Invalid boolean: "${value}"`);
};
/** @param {unknown} value */
const asStore = (value) => (value === 'auto' ? value : asBoolean(value));

/**
* @type {{
* [Key in keyof import('../../types').ConfigPlainType]: (value: unknown) => import('../../types').ConfigType[Key];
* [Key in keyof import('../../types').ConfigPlainType]: (
* value: unknown
* ) => import('../../types').ConfigType[Key] | undefined;
* }}
*/
const mapping = {
Expand Down Expand Up @@ -80,5 +91,11 @@ export const normalizeConfigValue = (key, value) => {
if (typeof value === 'undefined' || value === null) {
return undefined;
}
return mapping[key](value);

try {
return mapping[key](value);
} catch (reason) {
console.error(`Invalid value for config key "${key}".`, reason);
return initialConfig[key];
}
};
Loading

0 comments on commit 22ccc84

Please sign in to comment.