{"version":3,"file":"objectEnlive.mjs","sources":["../../../../src/util/misc/objectEnlive.ts"],"sourcesContent":["import { noop } from '../../constants';\nimport type { FabricObject } from '../../shapes/Object/FabricObject';\nimport type {\n  Abortable,\n  Constructor,\n  TCrossOrigin,\n  TFiller,\n} from '../../typedefs';\nimport { createImage } from './dom';\nimport { classRegistry } from '../../ClassRegistry';\nimport type { BaseFilter } from '../../filters/BaseFilter';\nimport type { FabricObject as BaseFabricObject } from '../../shapes/Object/Object';\nimport { FabricError, SignalAbortedError, log } from '../internals/console';\nimport type { Shadow } from '../../Shadow';\n\nexport type LoadImageOptions = Abortable & {\n  /**\n   * cors value for the image loading, default to anonymous\n   */\n  crossOrigin?: TCrossOrigin;\n\n  /**\n   * Resolve with an empty image instead of rejecting when the image fails to load.\n   * Useful for deserialization flows where one bad asset should not fail the entire document.\n   */\n  fallbackToEmptyImage?: boolean;\n};\n\n/**\n * Loads image element from given url and resolve it, or catch.\n * @param {String} url URL representing an image\n * @param {LoadImageOptions} [options] image loading options\n * @returns {Promise<HTMLImageElement>} the loaded image.\n */\nexport const loadImage = (\n  url: string,\n  {\n    signal,\n    crossOrigin = null,\n    fallbackToEmptyImage = false,\n  }: LoadImageOptions = {},\n) =>\n  new Promise<HTMLImageElement>(function (resolve, reject) {\n    if (signal && signal.aborted) {\n      return reject(new SignalAbortedError('loadImage'));\n    }\n    const img = createImage();\n    let abort: EventListenerOrEventListenerObject;\n    if (signal) {\n      abort = function (err: Event) {\n        img.src = '';\n        reject(err);\n      };\n      signal.addEventListener('abort', abort, { once: true });\n    }\n    const cleanup = function () {\n      img.onload = img.onerror = null;\n      abort && signal?.removeEventListener('abort', abort);\n    };\n    const done = function () {\n      cleanup();\n      resolve(img);\n    };\n    if (!url) {\n      done();\n      return;\n    }\n    img.onload = done;\n    img.onerror = function () {\n      const failedSrc = img.src;\n      cleanup();\n      if (fallbackToEmptyImage) {\n        log(\n          'warn',\n          'Image failed to load, continuing with an empty image source',\n          failedSrc,\n        );\n        img.src = '';\n        resolve(img);\n        return;\n      }\n      reject(new FabricError(`Error loading ${failedSrc}`));\n    };\n    crossOrigin && (img.crossOrigin = crossOrigin);\n    img.src = url;\n  });\n\nexport type EnlivenObjectOptions = Abortable & {\n  /**\n   * Method for further parsing of object elements,\n   * called after each fabric object created.\n   */\n  reviver?: <\n    T extends\n      | BaseFabricObject\n      | FabricObject\n      | BaseFilter<string>\n      | Shadow\n      | TFiller,\n  >(\n    serializedObj: Record<string, any>,\n    instance: T,\n  ) => void;\n};\n\n/**\n * @TODO type this correctly.\n * Creates corresponding fabric instances from their object representations\n * @param {Object[]} objects Objects to enliven\n * @param {EnlivenObjectOptions} [options]\n * @param {(serializedObj: object, instance: FabricObject) => any} [options.reviver] Method for further parsing of object elements,\n * called after each fabric object created.\n * @param {AbortSignal} [options.signal] handle aborting, see https://developer.mozilla.org/en-US/docs/Web/API/AbortController/signal\n * @returns {Promise<FabricObject[]>}\n */\nexport const enlivenObjects = <\n  T extends\n    | BaseFabricObject\n    | FabricObject\n    | BaseFilter<string>\n    | Shadow\n    | TFiller,\n>(\n  objects: any[],\n  { signal, reviver = noop }: EnlivenObjectOptions = {},\n) =>\n  new Promise<T[]>((resolve, reject) => {\n    const instances: T[] = [];\n    signal && signal.addEventListener('abort', reject, { once: true });\n    Promise.all(\n      objects.map((obj) =>\n        classRegistry\n          .getClass<\n            Constructor<T> & {\n              fromObject(options: any, context: Abortable): Promise<T>;\n            }\n          >(obj.type)\n          .fromObject(obj, { signal })\n          .then((fabricInstance) => {\n            reviver(obj, fabricInstance);\n            instances.push(fabricInstance);\n            return fabricInstance;\n          }),\n      ),\n    )\n      .then(resolve)\n      .catch((error) => {\n        // cleanup\n        instances.forEach((instance) => {\n          (instance as FabricObject).dispose &&\n            (instance as FabricObject).dispose();\n        });\n        reject(error);\n      })\n      .finally(() => {\n        signal && signal.removeEventListener('abort', reject);\n      });\n  });\n\n/**\n * Creates corresponding fabric instances residing in an object, e.g. `clipPath`\n * @param {Object} object with properties to enlive ( fill, stroke, clipPath, path )\n * @param {object} [options]\n * @param {AbortSignal} [options.signal] handle aborting, see https://developer.mozilla.org/en-US/docs/Web/API/AbortController/signal\n * @returns {Promise<Record<string, FabricObject | TFiller | null>>} the input object with enlived values\n */\nexport const enlivenObjectEnlivables = <\n  R = Record<string, FabricObject | TFiller | null>,\n>(\n  serializedObject: any,\n  { signal }: Abortable = {},\n) =>\n  new Promise<R>((resolve, reject) => {\n    const instances: (FabricObject | TFiller | Shadow)[] = [];\n    signal && signal.addEventListener('abort', reject, { once: true });\n    // enlive every possible property\n    const promises = Object.values(serializedObject).map((value: any) => {\n      if (!value) {\n        return value;\n      }\n      /**\n       * clipPath or shadow or gradient or text on a path or a pattern,\n       * or the backgroundImage or overlayImage of canvas\n       * If we have a type and there is a classe registered for it, we enlive it.\n       * If there is no class registered for it we return the value as is\n       * */\n      if (value.type && classRegistry.has(value.type)) {\n        return enlivenObjects<FabricObject | Shadow | TFiller>([value], {\n          signal,\n        }).then(([enlived]) => {\n          instances.push(enlived);\n          return enlived;\n        });\n      }\n      return value;\n    });\n    const keys = Object.keys(serializedObject);\n    Promise.all(promises)\n      .then((enlived) => {\n        return enlived.reduce((acc, instance, index) => {\n          acc[keys[index]] = instance;\n          return acc;\n        }, {});\n      })\n      .then(resolve)\n      .catch((error) => {\n        // cleanup\n        instances.forEach((instance: any) => {\n          instance.dispose && instance.dispose();\n        });\n        reject(error);\n      })\n      .finally(() => {\n        signal && signal.removeEventListener('abort', reject);\n      });\n  });\n"],"names":["loadImage","url","signal","crossOrigin","fallbackToEmptyImage","arguments","length","undefined","Promise","resolve","reject","aborted","SignalAbortedError","img","createImage","abort","err","src","addEventListener","once","cleanup","onload","onerror","removeEventListener","done","failedSrc","log","FabricError","enlivenObjects","objects","reviver","noop","instances","all","map","obj","classRegistry","getClass","type","fromObject","then","fabricInstance","push","catch","error","forEach","instance","dispose","finally","enlivenObjectEnlivables","serializedObject","promises","Object","values","value","has","_ref","enlived","keys","reduce","acc","index"],"mappings":"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"}