{"version":3,"file":"objectEnlive.min.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":"mPAkCaA,MAAAA,EAAY,SACvBC,GAAW,IACXC,OACEA,EAAMC,YACNA,EAAc,KAAIC,qBAClBA,GAAuB,GACNC,UAAAC,OAAAD,QAAAE,IAAAF,UAAAE,GAAAF,UAAG,GAAA,CAAE,EAAA,OAExB,IAAIG,SAA0B,SAAUC,EAASC,GAC/C,GAAIR,GAAUA,EAAOS,QACnB,OAAOD,EAAO,IAAIE,EAAmB,cAEvC,MAAMC,EAAMC,IACZ,IAAIC,EACAb,IACFa,EAAQ,SAAUC,GAChBH,EAAII,IAAM,GACVP,EAAOM,EACR,EACDd,EAAOgB,iBAAiB,QAASH,EAAO,CAAEI,MAAM,KAElD,MAAMC,EAAU,WACdP,EAAIQ,OAASR,EAAIS,QAAU,KAC3BP,IAASb,SAAAA,EAAQqB,oBAAoB,QAASR,GAC/C,EACKS,EAAO,WACXJ,IACAX,EAAQI,EACT,EACIZ,GAILY,EAAIQ,OAASG,EACbX,EAAIS,QAAU,WACZ,MAAMG,EAAYZ,EAAII,IAEtB,GADAG,IACIhB,EAQF,OAPAsB,EACE,OACA,8DACAD,GAEFZ,EAAII,IAAM,QACVR,EAAQI,GAGVH,EAAO,IAAIiB,EAAY,iBAAiBF,KACzC,EACDtB,IAAgBU,EAAIV,YAAcA,GAClCU,EAAII,IAAMhB,GApBRuB,GAqBJ,GAAE,EA8BSI,EAAiB,SAQ5BC,GAAc,IACd3B,OAAEA,EAAM4B,QAAEA,EAAUC,GAA4B1B,UAAAC,OAAAD,QAAAE,IAAAF,UAAAE,GAAAF,UAAG,GAAA,CAAE,EAAA,OAErD,IAAIG,SAAa,CAACC,EAASC,KACzB,MAAMsB,EAAiB,GACvB9B,GAAUA,EAAOgB,iBAAiB,QAASR,EAAQ,CAAES,MAAM,IAC3DX,QAAQyB,IACNJ,EAAQK,KAAKC,GACXC,EACGC,SAICF,EAAIG,MACLC,WAAWJ,EAAK,CAAEjC,WAClBsC,MAAMC,IACLX,EAAQK,EAAKM,GACbT,EAAUU,KAAKD,GACRA,QAIZD,KAAK/B,GACLkC,OAAOC,IAENZ,EAAUa,SAASC,IAChBA,EAA0BC,SACxBD,EAA0BC,SAAS,IAExCrC,EAAOkC,EAAM,IAEdI,SAAQ,KACP9C,GAAUA,EAAOqB,oBAAoB,QAASb,EAAO,GACrD,GACJ,EASSuC,EAA0B,SAGrCC,GAAqB,IACrBhD,OAAEA,GAAmBG,UAAAC,OAAAD,QAAAE,IAAAF,UAAAE,GAAAF,UAAG,GAAA,CAAE,EAAA,OAE1B,IAAIG,SAAW,CAACC,EAASC,KACvB,MAAMsB,EAAiD,GACvD9B,GAAUA,EAAOgB,iBAAiB,QAASR,EAAQ,CAAES,MAAM,IAE3D,MAAMgC,EAAWC,OAAOC,OAAOH,GAAkBhB,KAAKoB,GAC/CA,GASDA,EAAMhB,MAAQF,EAAcmB,IAAID,EAAMhB,MACjCV,EAAgD,CAAC0B,GAAQ,CAC9DpD,WACCsC,MAAKgB,IAAe,IAAbC,GAAQD,EAEhB,OADAxB,EAAUU,KAAKe,GACRA,CAAO,IAbTH,IAkBLI,EAAON,OAAOM,KAAKR,GACzB1C,QAAQyB,IAAIkB,GACTX,MAAMiB,GACEA,EAAQE,QAAO,CAACC,EAAKd,EAAUe,KACpCD,EAAIF,EAAKG,IAAUf,EACZc,IACN,MAEJpB,KAAK/B,GACLkC,OAAOC,IAENZ,EAAUa,SAASC,IACjBA,EAASC,SAAWD,EAASC,SAAS,IAExCrC,EAAOkC,EAAM,IAEdI,SAAQ,KACP9C,GAAUA,EAAOqB,oBAAoB,QAASb,EAAO,GACrD,GACJ"}