@getdraft/plugin 1.17.5 → 1.19.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.es.js","names":[],"sources":["../src/routes.ts","../src/types.ts","../src/utils.ts","../package.json","../src/plugin.ts","../src/index.ts"],"sourcesContent":["export const LOCAL_ENDPOINT = 'http://localhost:5174';\nexport const PROD_ENDPOINT = 'https://seplugin.sendsay.ru';\n","export enum EditorMenu {\n Audit = 'audit',\n Guide = 'guide',\n Style = 'style',\n Blocks = 'blocks',\n}\n\nexport enum ViewMode {\n Desktop = 'desktop',\n Mobile = 'mobile',\n}\n\nexport interface Notification {\n intent: 'error' | 'info' | 'success' | 'warning';\n errorDetails?: object;\n message?: string;\n title: string;\n}\n\ntype PersonalizationDictionaryEntry =\n | { name: string; value: string }\n | { groupName: string; items: Array<{ name: string; value: string }> };\n\nexport type PersonalizationDictionaryItems = PersonalizationDictionaryEntry[];\n\nexport interface SerializedTemplate {\n [key: string]: unknown;\n parentId: string | null;\n id: string;\n parameters: object;\n layer: string;\n type: string;\n children?: SerializedTemplate[];\n meta?: { [key: string]: unknown; version: string };\n}\n\nexport type EventHandler<T> = (data: T) => void;\n\nexport type AsyncEventHandler<P, R> = (params: P) => Promise<R>;\n\nexport class DraftError extends Error {\n public readonly code: string;\n\n constructor(code: string, message: string) {\n super(message);\n this.name = 'DraftError';\n this.code = code;\n }\n}\n\nexport type MessageData = {\n source: string;\n event: string;\n ok?: boolean;\n code?: string;\n message?: string;\n action?: string;\n};\n\nexport interface ExportAsFileParams {\n blob: Blob;\n fileName: string;\n}\n\nexport interface SaveParams {\n json: TemplateJSON;\n html: string;\n}\n\nexport type OnInitParams = MessageEvent<{\n source: string;\n event: 'loaded' | unknown;\n}>;\n\nexport interface ReadyParams extends SaveParams {\n lastSavedTemplate?: {\n template: TemplateJSON;\n date: Date;\n };\n}\n\nexport interface ErrorParams {\n message: string;\n code?: string;\n details?: unknown;\n}\n\nexport interface ExitParams extends SaveParams {}\n\nexport type NotificationParams = Notification;\n\nexport interface OpenGalleryParams {\n id: string;\n}\n\nexport interface UploadImageParams {\n file: string;\n name: string;\n}\n\nexport interface ImageParams {\n url: string;\n originalWidth: number;\n originalHeight: number;\n ratio: number;\n fileSize: number;\n}\n\nexport interface AutosaveParams {\n json: TemplateJSON;\n}\n\ninterface ToggleParams {\n state: boolean;\n}\n\nexport interface ToggleGridParams extends ToggleParams {}\n\nexport interface ToggleInvisibleCharactersParams extends ToggleParams {}\n\nexport interface TogglePreviewParams extends ToggleParams {\n json: TemplateJSON;\n html: string;\n darkHTML: string;\n}\n\nexport interface ToggleViewModeParams {\n mode: ViewMode;\n}\n\nexport interface ToggleMenuParams {\n menu: EditorMenu | null;\n}\n\nexport interface HistoryParams {\n hasUndos: boolean;\n hasRedos: boolean;\n currentStep: number;\n}\n\nexport type TemplateJSON = SerializedTemplate;\n\nexport type PersonalizationDictionary = PersonalizationDictionaryItems;\n\nexport type ToolbarActionName =\n | 'duplicate'\n | 'destroy'\n | 'edit'\n | 'up'\n | 'down';\nexport type HotkeyContext = 'hotkey';\nexport type OverlayContext = 'overlay-click' | 'overlay-double-click';\nexport type ToolbarContext = 'toolbar';\nexport type UnitSettingsContext = 'unit-settings';\nexport type BlockType = 'system' | 'user';\nexport type DndDragContext = 'canvas' | 'list' | 'palette';\nexport type DndDropContext = 'dropline' | 'placeholder' | 'empty-placeholder';\nexport type DndDropTarget = 'root' | 'section' | 'column' | 'element';\n\nexport interface DuplicateEvent {\n name: 'duplicate';\n context: HotkeyContext | ToolbarContext | UnitSettingsContext;\n unitType: string;\n}\n\nexport interface DestroyEvent {\n name: 'destroy';\n context: HotkeyContext | ToolbarContext | UnitSettingsContext;\n unitType: string;\n}\n\nexport interface EditEvent {\n name: 'edit';\n context: OverlayContext | ToolbarContext;\n unitType: string;\n}\n\nexport interface HistoryEvent {\n name: 'history';\n type: 'undo' | 'redo';\n context: HotkeyContext;\n}\n\nexport interface PreviewEvent {\n name: 'preview';\n context: HotkeyContext;\n}\n\nexport interface ToolbarMoveEvent {\n name: 'up' | 'down';\n context: ToolbarContext;\n unitType: string;\n}\n\nexport interface BlockInsertEvent {\n name: 'block-insert';\n context: 'double-click';\n blockType: BlockType;\n blockName: string;\n blockCategory: string | number;\n blockId: string | number;\n}\n\nexport interface BlockSaveEvent {\n name: 'block-save';\n blockType: 'user';\n blockName: string;\n blockCategory: string | number;\n blockId: string | number;\n elements: Record<string, number> & { sum: number };\n}\n\nexport interface BlockDestroyEvent {\n name: 'block-destroy';\n}\n\nexport interface DropEventDragMeta {\n context?: DndDragContext;\n layer?: 'element' | 'section' | 'column' | 'root';\n type?: string | string[];\n blockCategory?: string | number;\n blockId?: string | number;\n blockName?: string;\n blockType?: BlockType;\n alt?: boolean;\n dropKind?: 'create' | 'move';\n}\n\nexport interface DropEventDropzoneMeta {\n context?: DndDropContext;\n dropTarget?: DndDropTarget;\n}\n\nexport interface DropEvent {\n name: 'drop';\n drag?: DropEventDragMeta;\n dropzone?: DropEventDropzoneMeta;\n}\n\nexport type AnalyticsParams =\n | DuplicateEvent\n | DestroyEvent\n | EditEvent\n | HistoryEvent\n | PreviewEvent\n | ToolbarMoveEvent\n | BlockInsertEvent\n | BlockSaveEvent\n | BlockDestroyEvent\n | DropEvent;\n\nexport interface Handlers {\n ready: EventHandler<ReadyParams>;\n error: EventHandler<ErrorParams>;\n save: EventHandler<SaveParams>;\n exit: EventHandler<ExitParams>;\n notification: EventHandler<NotificationParams>;\n autosave: EventHandler<AutosaveParams>;\n toggleGrid: EventHandler<ToggleGridParams>;\n toggleInvisibleCharacters: EventHandler<ToggleInvisibleCharactersParams>;\n togglePreview: EventHandler<TogglePreviewParams>;\n toggleViewMode: EventHandler<ToggleViewModeParams>;\n toggleMenu: EventHandler<ToggleMenuParams>;\n history: EventHandler<HistoryParams>;\n analytics: EventHandler<AnalyticsParams>;\n openGallery: EventHandler<(url?: string) => Promise<void>>;\n uploadImage: AsyncEventHandler<UploadImageParams, string>;\n loadPersonalization: AsyncEventHandler<void, PersonalizationDictionary>;\n}\n\nexport type HandlerParams<H> = H extends\n | EventHandler<infer P>\n | AsyncEventHandler<infer P, unknown>\n ? P\n : never;\n\nexport interface PluginConfig {\n container: string;\n locale?: string;\n autosave?:\n | boolean\n | {\n interval: number;\n };\n token: string;\n authData?: {\n orgId: number;\n projectId?: number;\n };\n pluginId: string;\n apiUrl: string;\n disableHotkeysPassing?: boolean;\n __config?: object;\n on: Partial<Handlers>;\n}\n","import { ImageParams } from './types';\n\nconst getImageFileSize = async (imageUrl: string) => {\n try {\n const response = await fetch(imageUrl, { method: 'HEAD' });\n\n if (!response.ok) {\n return null;\n }\n\n const contentLength = response.headers.get('Content-Length');\n\n if (contentLength) {\n return parseInt(contentLength, 10);\n } else {\n return null;\n }\n } catch (error) {\n return null;\n }\n};\n\nexport const getImageParamsFromFileUrl = (imgSrc: string) =>\n new Promise<Omit<ImageParams, 'url'>>((resolve, reject) => {\n const img = new Image();\n\n img.onload = async () => {\n const fileSize = (await getImageFileSize(imgSrc)) ?? 0;\n\n resolve({\n originalWidth: img.width,\n originalHeight: img.height,\n ratio: img.width / img.height,\n fileSize,\n });\n };\n\n img.onerror = (error) => {\n reject(error);\n };\n\n img.src = imgSrc;\n });\n\nconst getLatinKey = (key: string, code: string) => {\n if (key.length !== 1) {\n return key;\n }\n\n const capitalHetaCode = 880;\n const isNonLatin = key.charCodeAt(0) >= capitalHetaCode;\n\n if (isNonLatin) {\n if (code.indexOf('Key') === 0 && code.length === 4) {\n return code.charAt(3);\n }\n\n if (code.indexOf('Digit') === 0 && code.length === 6) {\n return code.charAt(5);\n }\n }\n\n return key;\n};\n\nexport const constructKeyCode = (event: KeyboardEvent) => {\n let keyCode =\n `${getLatinKey(event.key, event.code)}`.toLowerCase() || event.key;\n const macOs = navigator.userAgent.includes('Mac OS');\n\n if (keyCode === 'backspace' && macOs) {\n keyCode = 'delete';\n }\n\n const prefix = [];\n\n if ((macOs && event.metaKey) || (!macOs && event.ctrlKey)) {\n prefix.push('mod');\n }\n\n if (event.shiftKey) {\n prefix.push('shift');\n }\n\n if (prefix.length > 0) {\n keyCode = `${prefix.join('-')}-${getLatinKey(keyCode, event.code)}`;\n }\n\n return keyCode;\n};\n\nexport const CORE_HOTKEYS = new Set([\n 'escape',\n 'mod-c',\n 'mod-d',\n 'mod-z',\n 'mod-y',\n 'mod-shift-z',\n 'mod-v',\n 'delete',\n 'mod-g',\n 'mod-p',\n 'mod-s',\n]);\n","{\n \"name\": \"@getdraft/plugin\",\n \"version\": \"1.17.5\",\n \"main\": \"dist/index.cjs.js\",\n \"module\": \"dist/index.es.js\",\n \"types\": \"dist/types/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/types/index.d.ts\",\n \"import\": \"./dist/index.es.js\",\n \"require\": \"./dist/index.cjs.js\"\n }\n },\n \"scripts\": {\n \"prebuild\": \"rm -rf dist\",\n \"build\": \"vite build\",\n \"dev-tsc\": \"tsc-check\",\n \"eslint\": \"npx eslint src\",\n \"eslint:fix\": \"pnpm eslint --fix\",\n \"prettify\": \"npx prettier --check src\",\n \"prettify:fix\": \"npx prettier -w src\",\n \"prepublish\": \"pnpm build\",\n \"watch\": \"NODE_ENV=development vite build --watch\",\n \"start\": \"NODE_ENV=development npx vite\"\n },\n \"dependencies\": {},\n \"devDependencies\": {\n \"@getdraft/types\": \"workspace:^\",\n \"@getdraft/eslint-config-ts\": \"workspace:^\",\n \"@getdraft/prettier\": \"workspace:^\",\n \"vite-plugin-dts\": \"4.5.4\"\n },\n \"license\": \"MIT\"\n}\n","import { LOCAL_ENDPOINT, PROD_ENDPOINT } from './routes';\nimport {\n DraftError,\n EditorMenu,\n ExitParams,\n OnInitParams,\n OpenGalleryParams,\n Handlers,\n PluginConfig,\n SaveParams,\n TemplateJSON,\n UploadImageParams,\n ViewMode,\n HandlerParams,\n MessageData,\n ExportAsFileParams,\n} from './types';\nimport {\n getImageParamsFromFileUrl,\n constructKeyCode,\n CORE_HOTKEYS,\n} from './utils';\nimport pkg from '../package.json';\n\nconst getDeployLink = () => {\n const regex = new RegExp(`(^| )seplugin-dev=([^;]+)`);\n const match = document.cookie.match(regex);\n const value = match?.[2].toLowerCase?.();\n\n if (value === 'true') {\n return LOCAL_ENDPOINT;\n }\n\n if (value?.startsWith('https://')) {\n return value;\n }\n\n const [major, mid] = pkg.version.split('.');\n\n return `${PROD_ENDPOINT}/v${major}.${mid}`;\n};\n\nconst verifyConfig = ({ token, pluginId, apiUrl }: PluginConfig) => {\n if (!token) {\n throw new Error('No [token] was provided');\n }\n\n if (!pluginId) {\n throw new Error('No [pluginId] was provided');\n }\n\n if (!apiUrl) {\n throw new Error('No [apiUrl] was provided');\n }\n};\n\nconst createIframe = (parentOrigin: string) => {\n const iframe = document.createElement('iframe');\n const url = new URL(getDeployLink());\n url.searchParams.set('parentOrigin', parentOrigin);\n iframe.src = url.toString();\n iframe.setAttribute(\n 'style',\n 'height:100%;width:100%;min-width:960px;border:0px;',\n );\n iframe.setAttribute('allow', 'clipboard-read; clipboard-write');\n iframe.setAttribute(\n 'sandbox',\n 'allow-scripts allow-same-origin allow-forms allow-popups allow-downloads',\n );\n\n return iframe;\n};\n\nexport class PluginInstance {\n public iframe: HTMLIFrameElement | null = null;\n private hotkeysAttached = false;\n private iframeOrigin: string | null = null;\n constructor(public config: PluginConfig) {}\n\n private captureHotkeysEnabled() {\n return this.config.disableHotkeysPassing !== true;\n }\n\n private onHostHotkey = (event: KeyboardEvent) => {\n if (!this.captureHotkeysEnabled() || !this.iframe?.contentWindow) {\n return;\n }\n\n const keyCode = constructKeyCode(event);\n\n if (!CORE_HOTKEYS.has(keyCode)) {\n return;\n }\n\n const target = event.target as HTMLElement | null;\n\n if (\n target &&\n (target.isContentEditable ||\n ['INPUT', 'TEXTAREA', 'SELECT'].includes(target.tagName))\n ) {\n return;\n }\n\n event.preventDefault();\n\n const { key, ctrlKey, metaKey, shiftKey, altKey } = event;\n\n this.postEvent('hostHotkey', {\n key,\n code: event.code,\n metaKey,\n ctrlKey,\n shiftKey,\n altKey,\n keyCode,\n });\n };\n\n private static HEARTBEAT_TIMEOUT = 4000;\n\n private promisedIframeMethod<T>(eventName: string) {\n let timer: Timeout | null = null;\n let listener: ((e: MessageEvent<MessageData>) => void) | null = null;\n\n const cleanup = () => {\n if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n\n if (listener) {\n window.removeEventListener('message', listener, true);\n listener = null;\n }\n };\n\n const res = new Promise<T>((resolve, reject) => {\n const resetTimer = () => {\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => {\n cleanup();\n reject(\n new DraftError('timeout_error', `Action \"${eventName}\" timed out`),\n );\n }, PluginInstance.HEARTBEAT_TIMEOUT);\n };\n\n listener = (e: MessageEvent<MessageData>) => {\n if (e.source !== this.iframe?.contentWindow) return;\n\n const { data } = e;\n if (data.source !== 'DraftPlugin') return;\n\n if (data.event === 'actionPing' && data.action === eventName) {\n e.stopPropagation();\n resetTimer();\n\n return;\n }\n\n if (data.event === eventName) {\n e.stopPropagation();\n cleanup();\n\n const { source: _1, event: _2, ok, code, message, ...rest } = data;\n\n if (ok === false) {\n reject(\n new DraftError(\n code || 'unknown_error',\n message || 'Unknown error',\n ),\n );\n } else {\n resolve(rest as T);\n }\n }\n };\n\n window.addEventListener('message', listener, true);\n resetTimer();\n });\n\n this.postEvent(eventName);\n\n return res;\n }\n\n private postEvent(event: string, data: object = {}) {\n if (this.iframe && this.iframe.contentWindow && this.iframeOrigin) {\n this.iframe.contentWindow.postMessage(\n {\n ...data,\n event,\n source: 'DraftPlugin',\n },\n this.iframeOrigin,\n );\n } else if (!this.iframeOrigin) {\n throw new Error('Iframe origin is not initialized');\n }\n }\n\n private onImageUpload = async ({\n id,\n ...data\n }: UploadImageParams & { id: string }) => {\n try {\n const url = await this.config.on.uploadImage?.(data);\n let params = {};\n\n if (url) {\n params = await getImageParamsFromFileUrl(url);\n }\n\n this.postEvent('imageUploaded', { id, img: { ...params, url } });\n } catch (e) {\n this.postEvent('imageUploaded', { id });\n }\n };\n\n private onLoadPersonalization = async () => {\n try {\n if (!this.config.on.loadPersonalization) {\n throw new Error('No personalization loader provided');\n }\n\n const personalizationDictionary =\n await this.config.on.loadPersonalization();\n\n this.postEvent('loadPersonalization', {\n items: personalizationDictionary,\n });\n } catch (e) {\n this.postEvent('loadPersonalization', {});\n }\n };\n\n private onGalleryOpen = async ({ id }: { id: string }) => {\n const applyImage = async (url?: string) => {\n const imgParams = { url };\n\n if (url) {\n const params = await getImageParamsFromFileUrl(url);\n Object.assign(imgParams, params);\n }\n\n this.postEvent('imageUploaded', {\n id,\n img: imgParams,\n });\n };\n\n this.config.on.openGallery?.(applyImage);\n };\n\n private triggerEvent<H extends CallableFunction | undefined>(\n handler: H,\n params: HandlerParams<H>,\n ) {\n if (!handler) {\n return;\n }\n\n return handler(params);\n }\n\n private onMessage = (\n ev: MessageEvent<{ source: string; event: keyof Handlers }>,\n ) => {\n if (ev.source !== this.iframe?.contentWindow) {\n return;\n }\n\n const {\n data: { source, event, ...data },\n } = ev;\n\n if (source === 'DraftPlugin') {\n if (event === 'openGallery') {\n this.onGalleryOpen(data as OpenGalleryParams);\n } else if (event === 'uploadImage') {\n this.onImageUpload(data as UploadImageParams & { id: string });\n } else if (event === 'loadPersonalization') {\n this.onLoadPersonalization();\n } else {\n this.triggerEvent(\n this.config.on[event],\n data as HandlerParams<Handlers[typeof event]>,\n );\n }\n }\n };\n\n start({\n template,\n templateName,\n uid,\n }: {\n template: string | TemplateJSON;\n uid: string | number;\n templateName?: string;\n }) {\n const containerEl = document.querySelector(this.config.container);\n\n if (!containerEl) {\n throw new Error('Specified container not found');\n } else {\n const onInit = (msg: OnInitParams) => {\n const {\n data: { source, event },\n } = msg;\n if (source === 'DraftPlugin' && event === 'loaded') {\n if (msg.source !== this.iframe?.contentWindow) return;\n\n this.iframeOrigin = msg.origin;\n\n const {\n on,\n container,\n locale,\n autosave,\n token,\n apiUrl,\n pluginId,\n authData,\n __config,\n } = this.config;\n\n verifyConfig(this.config);\n\n if (this.iframe && this.iframe.contentWindow) {\n this.postEvent('init', {\n container,\n locale,\n uid,\n autosave,\n token,\n pluginId,\n authData,\n apiUrl,\n __config,\n enabledListeners: Object.keys(on),\n template,\n templateName,\n });\n }\n\n window.addEventListener('message', this.onMessage);\n window.removeEventListener('message', onInit);\n }\n };\n\n this.iframe = createIframe(window.location.origin);\n window.addEventListener('message', onInit);\n containerEl.appendChild(this.iframe);\n\n if (this.captureHotkeysEnabled() && !this.hotkeysAttached) {\n window.addEventListener('keydown', this.onHostHotkey);\n this.hotkeysAttached = true;\n }\n }\n }\n\n destroy = () => {\n this.iframe?.remove();\n this.iframe = null;\n window.removeEventListener('message', this.onMessage);\n\n if (this.hotkeysAttached) {\n window.removeEventListener('keydown', this.onHostHotkey);\n this.hotkeysAttached = false;\n }\n };\n\n changeTemplate(\n template: string | TemplateJSON,\n options: {\n templateName?: string;\n uid?: string;\n } = {},\n ) {\n this.postEvent('changeTemplate', { ...options, template });\n }\n\n toggleGrid(state?: boolean) {\n this.postEvent('toggleGrid', { state });\n }\n\n toggleInvisibleCharacters(state?: boolean) {\n this.postEvent('toggleInvisibleCharacters', { state });\n }\n\n async isInvisibleCharactersVisible() {\n const { state } = await this.promisedIframeMethod<{ state: boolean }>(\n 'getInvisibleCharactersVisibility',\n );\n\n return state;\n }\n\n togglePreview(state?: boolean) {\n this.postEvent('togglePreview', { state });\n }\n\n toggleMenu(menu: EditorMenu | null = null) {\n this.postEvent('toggleMenu', { menu });\n }\n\n toggleViewMode(viewMode: ViewMode) {\n this.postEvent('toggleViewMode', { viewMode });\n }\n\n undo() {\n this.postEvent('undo');\n }\n\n undoToStep(targetStep: number) {\n this.postEvent('undoToStep', { targetStep });\n }\n\n redo() {\n this.postEvent('redo');\n }\n\n save() {\n return this.promisedIframeMethod<SaveParams>('saveAction');\n }\n\n exit() {\n return this.promisedIframeMethod<ExitParams>('exitAction');\n }\n\n exportContent() {\n return this.promisedIframeMethod<SaveParams>('exportContent');\n }\n\n exportAsFile() {\n return this.promisedIframeMethod<ExportAsFileParams>('exportAsFile');\n }\n}\n","import { PluginInstance } from './plugin';\nimport { PluginConfig } from './types';\nimport { version } from '../package.json';\n\nconst DEFAULT_CONFIG: Partial<PluginConfig> = {\n container: '#draft-plugin-container',\n disableHotkeysPassing: false,\n locale: 'ru',\n on: {},\n};\n\nclass PluginWrapper {\n public version = version;\n\n create(config: PluginConfig) {\n return new PluginInstance({\n ...DEFAULT_CONFIG,\n ...config,\n });\n }\n}\n\nconst DraftPlugin = new PluginWrapper();\n\ndeclare global {\n interface Window {\n DraftPlugin: PluginWrapper;\n }\n}\n\nwindow.DraftPlugin = DraftPlugin;\n\nexport default DraftPlugin;\nexport type { PluginInstance } from './plugin';\nexport * from './types';\n"],"mappings":";AAAA,IAAa,IAAiB,yBACjB,IAAgB,+BCDjB,IAAL,yBAAA,GAAA;QACL,EAAA,QAAA,SACA,EAAA,QAAA,SACA,EAAA,QAAA,SACA,EAAA,SAAA;KACD,EAEW,IAAL,yBAAA,GAAA;QACL,EAAA,UAAA,WACA,EAAA,SAAA;KACD,EA8BY,IAAb,cAAgC,MAAM;CACpC;CAEA,YAAY,GAAc,GAAiB;AAGzC,EAFA,MAAM,EAAQ,EACd,KAAK,OAAO,cACZ,KAAK,OAAO;;GC5CV,IAAmB,OAAO,MAAqB;AACnD,KAAI;EACF,IAAM,IAAW,MAAM,MAAM,GAAU,EAAE,QAAQ,QAAQ,CAAC;AAE1D,MAAI,CAAC,EAAS,GACZ,QAAO;EAGT,IAAM,IAAgB,EAAS,QAAQ,IAAI,iBAAiB;AAK1D,SAHE,IACK,SAAS,GAAe,GAAG,GAE3B;SAEK;AACd,SAAO;;GAIE,KAA6B,MACxC,IAAI,SAAmC,GAAS,MAAW;CACzD,IAAM,IAAM,IAAI,OAAO;AAiBvB,CAfA,EAAI,SAAS,YAAY;EACvB,IAAM,IAAY,MAAM,EAAiB,EAAO,IAAK;AAErD,IAAQ;GACN,eAAe,EAAI;GACnB,gBAAgB,EAAI;GACpB,OAAO,EAAI,QAAQ,EAAI;GACvB;GACD,CAAC;IAGJ,EAAI,WAAW,MAAU;AACvB,IAAO,EAAM;IAGf,EAAI,MAAM;EACV,EAEE,KAAe,GAAa,MAAiB;AACjD,KAAI,EAAI,WAAW,EACjB,QAAO;AAMT,KAFmB,EAAI,WAAW,EAAE,IADZ,KAGR;AACd,MAAI,EAAK,QAAQ,MAAM,KAAK,KAAK,EAAK,WAAW,EAC/C,QAAO,EAAK,OAAO,EAAE;AAGvB,MAAI,EAAK,QAAQ,QAAQ,KAAK,KAAK,EAAK,WAAW,EACjD,QAAO,EAAK,OAAO,EAAE;;AAIzB,QAAO;GAGI,KAAoB,MAAyB;CACxD,IAAI,IACF,GAAG,EAAY,EAAM,KAAK,EAAM,KAAK,GAAG,aAAa,IAAI,EAAM,KAC3D,IAAQ,UAAU,UAAU,SAAS,SAAS;AAEpD,CAAI,MAAY,eAAe,MAC7B,IAAU;CAGZ,IAAM,IAAS,EAAE;AAcjB,SAZK,KAAS,EAAM,WAAa,CAAC,KAAS,EAAM,YAC/C,EAAO,KAAK,MAAM,EAGhB,EAAM,YACR,EAAO,KAAK,QAAQ,EAGlB,EAAO,SAAS,MAClB,IAAU,GAAG,EAAO,KAAK,IAAI,CAAC,GAAG,EAAY,GAAS,EAAM,KAAK,KAG5D;GAGI,IAAe,IAAI,IAAI;CAClC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GE/EI,UAAsB;CAC1B,IAAM,IAAY,OAAO,4BAA4B,EAE/C,IADQ,SAAS,OAAO,MAAM,EAAM,GACpB,GAAG,eAAe;AAExC,KAAI,MAAU,OACZ,QAAO;AAGT,KAAI,GAAO,WAAW,WAAW,CAC/B,QAAO;CAGT,IAAM,CAAC,GAAO,KAAO,EAAI,QAAQ,MAAM,IAAI;AAE3C,QAAO,GAAG,EAAc,IAAI,EAAM,GAAG;GAGjC,KAAgB,EAAE,UAAO,aAAU,gBAA2B;AAClE,KAAI,CAAC,EACH,OAAU,MAAM,0BAA0B;AAG5C,KAAI,CAAC,EACH,OAAU,MAAM,6BAA6B;AAG/C,KAAI,CAAC,EACH,OAAU,MAAM,2BAA2B;GAIzC,KAAgB,MAAyB;CAC7C,IAAM,IAAS,SAAS,cAAc,SAAS,EACzC,IAAM,IAAI,IAAI,GAAe,CAAC;AAapC,QAZA,EAAI,aAAa,IAAI,gBAAgB,EAAa,EAClD,EAAO,MAAM,EAAI,UAAU,EAC3B,EAAO,aACL,SACA,qDACD,EACD,EAAO,aAAa,SAAS,kCAAkC,EAC/D,EAAO,aACL,WACA,2EACD,EAEM;GAGI,IAAb,MAAa,EAAe;CAC1B,SAA0C;CAC1C,kBAA0B;CAC1B,eAAsC;CACtC,YAAY,GAA6B;AAAtB,OAAA,SAAA;;CAEnB,wBAAgC;AAC9B,SAAO,KAAK,OAAO,0BAA0B;;CAG/C,gBAAwB,MAAyB;AAC/C,MAAI,CAAC,KAAK,uBAAuB,IAAI,CAAC,KAAK,QAAQ,cACjD;EAGF,IAAM,IAAU,EAAiB,EAAM;AAEvC,MAAI,CAAC,EAAa,IAAI,EAAQ,CAC5B;EAGF,IAAM,IAAS,EAAM;AAErB,MACE,MACC,EAAO,qBACN;GAAC;GAAS;GAAY;GAAS,CAAC,SAAS,EAAO,QAAQ,EAE1D;AAGF,IAAM,gBAAgB;EAEtB,IAAM,EAAE,QAAK,YAAS,YAAS,aAAU,cAAW;AAEpD,OAAK,UAAU,cAAc;GAC3B;GACA,MAAM,EAAM;GACZ;GACA;GACA;GACA;GACA;GACD,CAAC;;CAGJ,OAAe,oBAAoB;CAEnC,qBAAgC,GAAmB;EACjD,IAAI,IAAwB,MACxB,IAA4D,MAE1D,UAAgB;AAMpB,GALA,AAEE,OADA,aAAa,EAAM,EACX,OAGV,AAEE,OADA,OAAO,oBAAoB,WAAW,GAAU,GAAK,EAC1C;KAIT,IAAM,IAAI,SAAY,GAAS,MAAW;GAC9C,IAAM,UAAmB;AAEvB,IADI,KAAO,aAAa,EAAM,EAC9B,IAAQ,iBAAiB;AAEvB,KADA,GAAS,EACT,EACE,IAAI,EAAW,iBAAiB,WAAW,EAAU,aAAa,CACnE;OACA,EAAe,kBAAkB;;AAoCtC,GAjCA,KAAY,MAAiC;AAC3C,QAAI,EAAE,WAAW,KAAK,QAAQ,cAAe;IAE7C,IAAM,EAAE,YAAS;AACb,UAAK,WAAW,eAEpB;SAAI,EAAK,UAAU,gBAAgB,EAAK,WAAW,GAAW;AAE5D,MADA,EAAE,iBAAiB,EACnB,GAAY;AAEZ;;AAGF,SAAI,EAAK,UAAU,GAAW;AAE5B,MADA,EAAE,iBAAiB,EACnB,GAAS;MAET,IAAM,EAAE,QAAQ,GAAI,OAAO,GAAI,OAAI,SAAM,YAAS,GAAG,MAAS;AAE9D,MAAI,MAAO,KACT,EACE,IAAI,EACF,KAAQ,iBACR,KAAW,gBACZ,CACF,GAED,EAAQ,EAAU;;;MAKxB,OAAO,iBAAiB,WAAW,GAAU,GAAK,EAClD,GAAY;IACZ;AAIF,SAFA,KAAK,UAAU,EAAU,EAElB;;CAGT,UAAkB,GAAe,IAAe,EAAE,EAAE;AAClD,MAAI,KAAK,UAAU,KAAK,OAAO,iBAAiB,KAAK,aACnD,MAAK,OAAO,cAAc,YACxB;GACE,GAAG;GACH;GACA,QAAQ;GACT,EACD,KAAK,aACN;WACQ,CAAC,KAAK,aACf,OAAU,MAAM,mCAAmC;;CAIvD,gBAAwB,OAAO,EAC7B,OACA,GAAG,QACqC;AACxC,MAAI;GACF,IAAM,IAAM,MAAM,KAAK,OAAO,GAAG,cAAc,EAAK,EAChD,IAAS,EAAE;AAMf,GAJI,MACF,IAAS,MAAM,EAA0B,EAAI,GAG/C,KAAK,UAAU,iBAAiB;IAAE;IAAI,KAAK;KAAE,GAAG;KAAQ;KAAK;IAAE,CAAC;UACtD;AACV,QAAK,UAAU,iBAAiB,EAAE,OAAI,CAAC;;;CAI3C,wBAAgC,YAAY;AAC1C,MAAI;AACF,OAAI,CAAC,KAAK,OAAO,GAAG,oBAClB,OAAU,MAAM,qCAAqC;GAGvD,IAAM,IACJ,MAAM,KAAK,OAAO,GAAG,qBAAqB;AAE5C,QAAK,UAAU,uBAAuB,EACpC,OAAO,GACR,CAAC;UACQ;AACV,QAAK,UAAU,uBAAuB,EAAE,CAAC;;;CAI7C,gBAAwB,OAAO,EAAE,YAAyB;AAexD,OAAK,OAAO,GAAG,cAdI,OAAO,MAAiB;GACzC,IAAM,IAAY,EAAE,QAAK;AAEzB,OAAI,GAAK;IACP,IAAM,IAAS,MAAM,EAA0B,EAAI;AACnD,WAAO,OAAO,GAAW,EAAO;;AAGlC,QAAK,UAAU,iBAAiB;IAC9B;IACA,KAAK;IACN,CAAC;IAGoC;;CAG1C,aACE,GACA,GACA;AACK,QAIL,QAAO,EAAQ,EAAO;;CAGxB,aACE,MACG;AACH,MAAI,EAAG,WAAW,KAAK,QAAQ,cAC7B;EAGF,IAAM,EACJ,MAAM,EAAE,WAAQ,UAAO,GAAG,QACxB;AAEJ,EAAI,MAAW,kBACT,MAAU,gBACZ,KAAK,cAAc,EAA0B,GACpC,MAAU,gBACnB,KAAK,cAAc,EAA2C,GACrD,MAAU,wBACnB,KAAK,uBAAuB,GAE5B,KAAK,aACH,KAAK,OAAO,GAAG,IACf,EACD;;CAKP,MAAM,EACJ,aACA,iBACA,UAKC;EACD,IAAM,IAAc,SAAS,cAAc,KAAK,OAAO,UAAU;AAEjE,MAAK,GAEE;GACL,IAAM,KAAU,MAAsB;IACpC,IAAM,EACJ,MAAM,EAAE,WAAQ,eACd;AACJ,QAAI,MAAW,iBAAiB,MAAU,UAAU;AAClD,SAAI,EAAI,WAAW,KAAK,QAAQ,cAAe;AAE/C,UAAK,eAAe,EAAI;KAExB,IAAM,EACJ,OACA,cACA,WACA,aACA,UACA,WACA,aACA,aACA,gBACE,KAAK;AAsBT,KApBA,EAAa,KAAK,OAAO,EAErB,KAAK,UAAU,KAAK,OAAO,iBAC7B,KAAK,UAAU,QAAQ;MACrB;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA,kBAAkB,OAAO,KAAK,EAAG;MACjC;MACA;MACD,CAAC,EAGJ,OAAO,iBAAiB,WAAW,KAAK,UAAU,EAClD,OAAO,oBAAoB,WAAW,EAAO;;;AAQjD,GAJA,KAAK,SAAS,EAAa,OAAO,SAAS,OAAO,EAClD,OAAO,iBAAiB,WAAW,EAAO,EAC1C,EAAY,YAAY,KAAK,OAAO,EAEhC,KAAK,uBAAuB,IAAI,CAAC,KAAK,oBACxC,OAAO,iBAAiB,WAAW,KAAK,aAAa,EACrD,KAAK,kBAAkB;QArDzB,OAAU,MAAM,gCAAgC;;CA0DpD,gBAAgB;AAKd,EAJA,KAAK,QAAQ,QAAQ,EACrB,KAAK,SAAS,MACd,OAAO,oBAAoB,WAAW,KAAK,UAAU,EAErD,AAEE,KAAK,qBADL,OAAO,oBAAoB,WAAW,KAAK,aAAa,EACjC;;CAI3B,eACE,GACA,IAGI,EAAE,EACN;AACA,OAAK,UAAU,kBAAkB;GAAE,GAAG;GAAS;GAAU,CAAC;;CAG5D,WAAW,GAAiB;AAC1B,OAAK,UAAU,cAAc,EAAE,UAAO,CAAC;;CAGzC,0BAA0B,GAAiB;AACzC,OAAK,UAAU,6BAA6B,EAAE,UAAO,CAAC;;CAGxD,MAAM,+BAA+B;EACnC,IAAM,EAAE,aAAU,MAAM,KAAK,qBAC3B,mCACD;AAED,SAAO;;CAGT,cAAc,GAAiB;AAC7B,OAAK,UAAU,iBAAiB,EAAE,UAAO,CAAC;;CAG5C,WAAW,IAA0B,MAAM;AACzC,OAAK,UAAU,cAAc,EAAE,SAAM,CAAC;;CAGxC,eAAe,GAAoB;AACjC,OAAK,UAAU,kBAAkB,EAAE,aAAU,CAAC;;CAGhD,OAAO;AACL,OAAK,UAAU,OAAO;;CAGxB,WAAW,GAAoB;AAC7B,OAAK,UAAU,cAAc,EAAE,eAAY,CAAC;;CAG9C,OAAO;AACL,OAAK,UAAU,OAAO;;CAGxB,OAAO;AACL,SAAO,KAAK,qBAAiC,aAAa;;CAG5D,OAAO;AACL,SAAO,KAAK,qBAAiC,aAAa;;CAG5D,gBAAgB;AACd,SAAO,KAAK,qBAAiC,gBAAgB;;CAG/D,eAAe;AACb,SAAO,KAAK,qBAAyC,eAAe;;GCpblE,IAAwC;CAC5C,WAAW;CACX,uBAAuB;CACvB,QAAQ;CACR,IAAI,EAAE;CACP,EAaK,IAAc,IAXpB,MAAoB;CAClB,UAAiB;CAEjB,OAAO,GAAsB;AAC3B,SAAO,IAAI,EAAe;GACxB,GAAG;GACH,GAAG;GACJ,CAAC;;GAIiC;AAQvC,OAAO,cAAc"}
1
+ {"version":3,"file":"index.es.js","names":[],"sources":["../src/routes.ts","../src/types.ts","../src/utils.ts","../package.json","../src/plugin.ts","../src/index.ts"],"sourcesContent":["export const LOCAL_ENDPOINT = 'http://localhost:5174';\nexport const PROD_ENDPOINT = 'https://seplugin.sendsay.ru';\n","export enum EditorMenu {\n Audit = 'audit',\n Guide = 'guide',\n Style = 'style',\n Blocks = 'blocks',\n}\n\nexport enum ViewMode {\n Desktop = 'desktop',\n Mobile = 'mobile',\n}\n\nexport interface Notification {\n intent: 'error' | 'info' | 'success' | 'warning';\n errorDetails?: object;\n message?: string;\n title: string;\n}\n\ntype PersonalizationDictionaryEntry =\n | { name: string; value: string }\n | { groupName: string; items: Array<{ name: string; value: string }> };\n\nexport type PersonalizationDictionaryItems = PersonalizationDictionaryEntry[];\n\nexport type SectionPersonalizationValue = string | number | boolean | null;\n\nexport interface SectionPersonalizationField {\n id: string;\n operatorId: 'equals';\n}\n\nexport interface SectionPersonalizationCatalogOption {\n label: string;\n value: Exclude<SectionPersonalizationValue, null>;\n}\n\nexport interface SectionPersonalizationCatalogGroup {\n type: 'group';\n id: string;\n label: string;\n children: SectionPersonalizationCatalogNode[];\n}\n\nexport interface SectionPersonalizationCatalogField {\n type: 'field';\n id: string;\n label: string;\n valueType?: 'string' | 'number' | 'boolean' | 'date';\n options?: SectionPersonalizationCatalogOption[];\n}\n\nexport type SectionPersonalizationCatalogNode =\n | SectionPersonalizationCatalogGroup\n | SectionPersonalizationCatalogField;\n\nexport interface SectionPersonalizationConfig {\n enabled: boolean;\n aboutUrl?: string;\n}\n\nexport interface RenderSectionPersonalizationGroupInput {\n groupId: string;\n fields: SectionPersonalizationField[];\n variants: Array<{\n id: string;\n values: Record<string, SectionPersonalizationValue>;\n html: string;\n }>;\n fallback?: {\n id: string;\n html: string;\n };\n}\n\nexport interface SerializedTemplate {\n [key: string]: unknown;\n parentId: string | null;\n id: string;\n parameters: object;\n layer: string;\n type: string;\n children?: SerializedTemplate[];\n meta?: { [key: string]: unknown; version: string };\n}\n\nexport type EventHandler<T> = (data: T) => void;\n\nexport type AsyncEventHandler<P, R> = (params: P) => Promise<R>;\n\nexport class DraftError extends Error {\n public readonly code: string;\n\n constructor(code: string, message: string) {\n super(message);\n this.name = 'DraftError';\n this.code = code;\n }\n}\n\nexport type MessageData = {\n source: string;\n event: string;\n ok?: boolean;\n code?: string;\n message?: string;\n action?: string;\n requestId?: string;\n};\n\nexport interface ExportAsFileParams {\n blob: Blob;\n fileName: string;\n}\n\nexport interface SaveParams {\n json: TemplateJSON;\n html: string;\n}\n\nexport type OnInitParams = MessageEvent<{\n source: string;\n event: 'loaded' | unknown;\n}>;\n\nexport interface ReadyParams extends SaveParams {\n lastSavedTemplate?: {\n template: TemplateJSON;\n date: Date;\n };\n}\n\nexport interface ErrorParams {\n message: string;\n code?: string;\n details?: unknown;\n}\n\nexport interface ExitParams extends SaveParams {}\n\nexport type NotificationParams = Notification;\n\nexport interface OpenGalleryParams {\n id: string;\n}\n\nexport interface UploadImageParams {\n file: string;\n name: string;\n}\n\nexport interface ImageParams {\n url: string;\n originalWidth: number;\n originalHeight: number;\n ratio: number;\n fileSize: number;\n}\n\nexport interface AutosaveParams {\n json: TemplateJSON;\n}\n\ninterface ToggleParams {\n state: boolean;\n}\n\nexport interface ToggleGridParams extends ToggleParams {}\n\nexport interface ToggleInvisibleCharactersParams extends ToggleParams {}\n\nexport interface TogglePreviewParams extends ToggleParams {\n json: TemplateJSON;\n html: string;\n darkHTML: string;\n}\n\nexport interface ToggleViewModeParams {\n mode: ViewMode;\n}\n\nexport interface ToggleMenuParams {\n menu: EditorMenu | null;\n}\n\nexport interface HistoryParams {\n hasUndos: boolean;\n hasRedos: boolean;\n currentStep: number;\n}\n\nexport type TemplateJSON = SerializedTemplate;\n\nexport type PersonalizationDictionary = PersonalizationDictionaryItems;\n\nexport type ToolbarActionName =\n | 'duplicate'\n | 'destroy'\n | 'edit'\n | 'up'\n | 'down';\nexport type HotkeyContext = 'hotkey';\nexport type OverlayContext = 'overlay-click' | 'overlay-double-click';\nexport type ToolbarContext = 'toolbar';\nexport type UnitSettingsContext = 'unit-settings';\nexport type BlockType = 'system' | 'user';\nexport type DndDragContext = 'canvas' | 'list' | 'palette';\nexport type DndDropContext = 'dropline' | 'placeholder' | 'empty-placeholder';\nexport type DndDropTarget = 'root' | 'section' | 'column' | 'element';\n\nexport interface DuplicateEvent {\n name: 'duplicate';\n context: HotkeyContext | ToolbarContext | UnitSettingsContext;\n unitType: string;\n}\n\nexport interface DestroyEvent {\n name: 'destroy';\n context: HotkeyContext | ToolbarContext | UnitSettingsContext;\n unitType: string;\n}\n\nexport interface EditEvent {\n name: 'edit';\n context: OverlayContext | ToolbarContext;\n unitType: string;\n}\n\nexport interface HistoryEvent {\n name: 'history';\n type: 'undo' | 'redo';\n context: HotkeyContext;\n}\n\nexport interface PreviewEvent {\n name: 'preview';\n context: HotkeyContext;\n}\n\nexport interface ToolbarMoveEvent {\n name: 'up' | 'down';\n context: ToolbarContext;\n unitType: string;\n}\n\nexport interface BlockInsertEvent {\n name: 'block-insert';\n context: 'double-click';\n blockType: BlockType;\n blockName: string;\n blockCategory: string | number;\n blockId: string | number;\n}\n\nexport interface BlockSaveEvent {\n name: 'block-save';\n blockType: 'user';\n blockName: string;\n blockCategory: string | number;\n blockId: string | number;\n elements: Record<string, number> & { sum: number };\n}\n\nexport interface BlockDestroyEvent {\n name: 'block-destroy';\n}\n\nexport interface DropEventDragMeta {\n context?: DndDragContext;\n layer?: 'element' | 'section' | 'column' | 'root';\n type?: string | string[];\n blockCategory?: string | number;\n blockId?: string | number;\n blockName?: string;\n blockType?: BlockType;\n alt?: boolean;\n dropKind?: 'create' | 'move';\n}\n\nexport interface DropEventDropzoneMeta {\n context?: DndDropContext;\n dropTarget?: DndDropTarget;\n}\n\nexport interface DropEvent {\n name: 'drop';\n drag?: DropEventDragMeta;\n dropzone?: DropEventDropzoneMeta;\n}\n\nexport type AnalyticsParams =\n | DuplicateEvent\n | DestroyEvent\n | EditEvent\n | HistoryEvent\n | PreviewEvent\n | ToolbarMoveEvent\n | BlockInsertEvent\n | BlockSaveEvent\n | BlockDestroyEvent\n | DropEvent;\n\nexport interface Handlers {\n ready: EventHandler<ReadyParams>;\n error: EventHandler<ErrorParams>;\n save: EventHandler<SaveParams>;\n exit: EventHandler<ExitParams>;\n notification: EventHandler<NotificationParams>;\n autosave: EventHandler<AutosaveParams>;\n toggleGrid: EventHandler<ToggleGridParams>;\n toggleInvisibleCharacters: EventHandler<ToggleInvisibleCharactersParams>;\n togglePreview: EventHandler<TogglePreviewParams>;\n toggleViewMode: EventHandler<ToggleViewModeParams>;\n toggleMenu: EventHandler<ToggleMenuParams>;\n history: EventHandler<HistoryParams>;\n analytics: EventHandler<AnalyticsParams>;\n openGallery: EventHandler<(url?: string) => Promise<void>>;\n uploadImage: AsyncEventHandler<UploadImageParams, string>;\n loadPersonalization: AsyncEventHandler<void, PersonalizationDictionary>;\n loadSectionPersonalizationCatalog: AsyncEventHandler<\n void,\n SectionPersonalizationCatalogNode[]\n >;\n renderSectionPersonalizationGroup: AsyncEventHandler<\n RenderSectionPersonalizationGroupInput,\n string\n >;\n}\n\nexport type HandlerParams<H> = H extends\n | EventHandler<infer P>\n | AsyncEventHandler<infer P, unknown>\n ? P\n : never;\n\nexport interface PluginConfig {\n container: string;\n locale?: string;\n autosave?:\n | boolean\n | {\n interval: number;\n };\n token: string;\n authData?: {\n orgId: number;\n projectId?: number;\n };\n pluginId: string;\n apiUrl: string;\n disableHotkeysPassing?: boolean;\n sectionPersonalization?: SectionPersonalizationConfig;\n __config?: object;\n on: Partial<Handlers>;\n}\n","import { ImageParams } from './types';\n\nconst getImageFileSize = async (imageUrl: string) => {\n try {\n const response = await fetch(imageUrl, { method: 'HEAD' });\n\n if (!response.ok) {\n return null;\n }\n\n const contentLength = response.headers.get('Content-Length');\n\n if (contentLength) {\n return parseInt(contentLength, 10);\n } else {\n return null;\n }\n } catch (error) {\n return null;\n }\n};\n\nexport const getImageParamsFromFileUrl = (imgSrc: string) =>\n new Promise<Omit<ImageParams, 'url'>>((resolve, reject) => {\n const img = new Image();\n\n img.onload = async () => {\n const fileSize = (await getImageFileSize(imgSrc)) ?? 0;\n\n resolve({\n originalWidth: img.width,\n originalHeight: img.height,\n ratio: img.width / img.height,\n fileSize,\n });\n };\n\n img.onerror = (error) => {\n reject(error);\n };\n\n img.src = imgSrc;\n });\n\nconst getLatinKey = (key: string, code: string) => {\n if (key.length !== 1) {\n return key;\n }\n\n const capitalHetaCode = 880;\n const isNonLatin = key.charCodeAt(0) >= capitalHetaCode;\n\n if (isNonLatin) {\n if (code.indexOf('Key') === 0 && code.length === 4) {\n return code.charAt(3);\n }\n\n if (code.indexOf('Digit') === 0 && code.length === 6) {\n return code.charAt(5);\n }\n }\n\n return key;\n};\n\nexport const constructKeyCode = (event: KeyboardEvent) => {\n let keyCode =\n `${getLatinKey(event.key, event.code)}`.toLowerCase() || event.key;\n const macOs = navigator.userAgent.includes('Mac OS');\n\n if (keyCode === 'backspace' && macOs) {\n keyCode = 'delete';\n }\n\n const prefix = [];\n\n if ((macOs && event.metaKey) || (!macOs && event.ctrlKey)) {\n prefix.push('mod');\n }\n\n if (event.shiftKey) {\n prefix.push('shift');\n }\n\n if (prefix.length > 0) {\n keyCode = `${prefix.join('-')}-${getLatinKey(keyCode, event.code)}`;\n }\n\n return keyCode;\n};\n\nexport const CORE_HOTKEYS = new Set([\n 'escape',\n 'mod-c',\n 'mod-d',\n 'mod-z',\n 'mod-y',\n 'mod-shift-z',\n 'mod-v',\n 'delete',\n 'mod-g',\n 'mod-p',\n 'mod-s',\n]);\n","{\n \"name\": \"@getdraft/plugin\",\n \"version\": \"1.19.0-alpha.0\",\n \"main\": \"dist/index.cjs.js\",\n \"module\": \"dist/index.es.js\",\n \"types\": \"dist/types/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/types/index.d.ts\",\n \"import\": \"./dist/index.es.js\",\n \"require\": \"./dist/index.cjs.js\"\n }\n },\n \"scripts\": {\n \"prebuild\": \"rm -rf dist\",\n \"build\": \"vite build\",\n \"dev-tsc\": \"tsc-check\",\n \"eslint\": \"npx eslint src\",\n \"eslint:fix\": \"pnpm eslint --fix\",\n \"prettify\": \"npx prettier --check src\",\n \"prettify:fix\": \"npx prettier -w src\",\n \"prepublish\": \"pnpm build\",\n \"watch\": \"NODE_ENV=development vite build --watch\",\n \"start\": \"NODE_ENV=development npx vite\"\n },\n \"dependencies\": {},\n \"devDependencies\": {\n \"@getdraft/types\": \"workspace:^\",\n \"@getdraft/eslint-config-ts\": \"workspace:^\",\n \"@getdraft/prettier\": \"workspace:^\",\n \"vite-plugin-dts\": \"4.5.4\"\n },\n \"license\": \"MIT\"\n}\n","import { LOCAL_ENDPOINT, PROD_ENDPOINT } from './routes';\nimport {\n DraftError,\n EditorMenu,\n ExitParams,\n OnInitParams,\n OpenGalleryParams,\n Handlers,\n PluginConfig,\n SaveParams,\n TemplateJSON,\n UploadImageParams,\n ViewMode,\n HandlerParams,\n MessageData,\n ExportAsFileParams,\n RenderSectionPersonalizationGroupInput,\n} from './types';\nimport {\n getImageParamsFromFileUrl,\n constructKeyCode,\n CORE_HOTKEYS,\n} from './utils';\nimport pkg from '../package.json';\n\nconst UNKNOWN_ERROR_MESSAGE = 'Unknown error';\n\nconst getDeployLink = () => {\n const regex = new RegExp(`(^| )seplugin-dev=([^;]+)`);\n const match = document.cookie.match(regex);\n const value = match?.[2].toLowerCase?.();\n\n if (value === 'true') {\n return LOCAL_ENDPOINT;\n }\n\n if (value?.startsWith('https://')) {\n return value;\n }\n\n const [major, mid] = pkg.version.split('.');\n\n return `${PROD_ENDPOINT}/v${major}.${mid}`;\n};\n\nconst verifyConfig = ({ token, pluginId, apiUrl }: PluginConfig) => {\n if (!token) {\n throw new Error('No [token] was provided');\n }\n\n if (!pluginId) {\n throw new Error('No [pluginId] was provided');\n }\n\n if (!apiUrl) {\n throw new Error('No [apiUrl] was provided');\n }\n};\n\nconst createIframe = (parentOrigin: string) => {\n const iframe = document.createElement('iframe');\n const url = new URL(getDeployLink());\n url.searchParams.set('parentOrigin', parentOrigin);\n iframe.src = url.toString();\n iframe.setAttribute(\n 'style',\n 'height:100%;width:100%;min-width:960px;border:0px;',\n );\n iframe.setAttribute('allow', 'clipboard-read; clipboard-write');\n iframe.setAttribute(\n 'sandbox',\n 'allow-scripts allow-same-origin allow-forms allow-popups allow-downloads',\n );\n\n return iframe;\n};\n\nexport class PluginInstance {\n public iframe: HTMLIFrameElement | null = null;\n private hotkeysAttached = false;\n private iframeOrigin: string | null = null;\n constructor(public config: PluginConfig) {}\n\n private captureHotkeysEnabled() {\n return this.config.disableHotkeysPassing !== true;\n }\n\n private onHostHotkey = (event: KeyboardEvent) => {\n if (!this.captureHotkeysEnabled() || !this.iframe?.contentWindow) {\n return;\n }\n\n const keyCode = constructKeyCode(event);\n\n if (!CORE_HOTKEYS.has(keyCode)) {\n return;\n }\n\n const target = event.target as HTMLElement | null;\n\n if (\n target &&\n (target.isContentEditable ||\n ['INPUT', 'TEXTAREA', 'SELECT'].includes(target.tagName))\n ) {\n return;\n }\n\n event.preventDefault();\n\n const { key, ctrlKey, metaKey, shiftKey, altKey } = event;\n\n this.postEvent('hostHotkey', {\n key,\n code: event.code,\n metaKey,\n ctrlKey,\n shiftKey,\n altKey,\n keyCode,\n });\n };\n\n private static HEARTBEAT_TIMEOUT = 4000;\n\n private promisedIframeMethod<T>(eventName: string) {\n let timer: Timeout | null = null;\n let listener: ((e: MessageEvent<MessageData>) => void) | null = null;\n\n const cleanup = () => {\n if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n\n if (listener) {\n window.removeEventListener('message', listener, true);\n listener = null;\n }\n };\n\n const res = new Promise<T>((resolve, reject) => {\n const resetTimer = () => {\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => {\n cleanup();\n reject(\n new DraftError('timeout_error', `Action \"${eventName}\" timed out`),\n );\n }, PluginInstance.HEARTBEAT_TIMEOUT);\n };\n\n listener = (e: MessageEvent<MessageData>) => {\n if (e.source !== this.iframe?.contentWindow) return;\n\n const { data } = e;\n if (data.source !== 'DraftPlugin') return;\n\n if (data.event === 'actionPing' && data.action === eventName) {\n e.stopPropagation();\n resetTimer();\n\n return;\n }\n\n if (data.event === eventName) {\n e.stopPropagation();\n cleanup();\n\n const { source: _1, event: _2, ok, code, message, ...rest } = data;\n\n if (ok === false) {\n reject(\n new DraftError(\n code || 'unknown_error',\n message || UNKNOWN_ERROR_MESSAGE,\n ),\n );\n } else {\n resolve(rest as T);\n }\n }\n };\n\n window.addEventListener('message', listener, true);\n resetTimer();\n });\n\n this.postEvent(eventName);\n\n return res;\n }\n\n private postEvent(event: string, data: object = {}) {\n if (this.iframe && this.iframe.contentWindow && this.iframeOrigin) {\n this.iframe.contentWindow.postMessage(\n {\n ...data,\n event,\n source: 'DraftPlugin',\n },\n this.iframeOrigin,\n );\n } else if (!this.iframeOrigin) {\n throw new Error('Iframe origin is not initialized');\n }\n }\n\n private onImageUpload = async ({\n id,\n ...data\n }: UploadImageParams & { id: string }) => {\n try {\n const url = await this.config.on.uploadImage?.(data);\n let params = {};\n\n if (url) {\n params = await getImageParamsFromFileUrl(url);\n }\n\n this.postEvent('imageUploaded', { id, img: { ...params, url } });\n } catch (e) {\n this.postEvent('imageUploaded', { id });\n }\n };\n\n private onLoadPersonalization = async (requestId?: string) => {\n try {\n if (!this.config.on.loadPersonalization) {\n throw new Error('No personalization loader provided');\n }\n\n const personalizationDictionary =\n await this.config.on.loadPersonalization();\n\n this.postEvent('loadPersonalization', {\n items: personalizationDictionary,\n requestId,\n });\n } catch (e) {\n this.postEvent('loadPersonalization', { requestId });\n }\n };\n\n private onLoadSectionPersonalizationCatalog = async (requestId?: string) => {\n try {\n const handler = this.config.on.loadSectionPersonalizationCatalog;\n\n if (!handler) {\n throw new Error('No section personalization catalog loader provided');\n }\n\n const catalog = await handler();\n\n this.postEvent('loadSectionPersonalizationCatalog', {\n ok: true,\n requestId,\n catalog,\n });\n } catch (error) {\n this.postEvent('loadSectionPersonalizationCatalog', {\n ok: false,\n requestId,\n message: error instanceof Error ? error.message : UNKNOWN_ERROR_MESSAGE,\n });\n }\n };\n\n private onRenderSectionPersonalizationGroup = async (\n data: RenderSectionPersonalizationGroupInput & { requestId?: string },\n ) => {\n const { requestId, ...input } = data;\n\n try {\n const handler = this.config.on.renderSectionPersonalizationGroup;\n\n if (!handler) {\n throw new Error('No section personalization renderer provided');\n }\n\n const renderedHtml = await handler(input);\n\n this.postEvent('renderSectionPersonalizationGroup', {\n ok: true,\n requestId,\n html: renderedHtml,\n });\n } catch (error) {\n this.postEvent('renderSectionPersonalizationGroup', {\n ok: false,\n requestId,\n message: error instanceof Error ? error.message : UNKNOWN_ERROR_MESSAGE,\n });\n }\n };\n\n private onGalleryOpen = async ({ id }: { id: string }) => {\n const applyImage = async (url?: string) => {\n const imgParams = { url };\n\n if (url) {\n const params = await getImageParamsFromFileUrl(url);\n Object.assign(imgParams, params);\n }\n\n this.postEvent('imageUploaded', {\n id,\n img: imgParams,\n });\n };\n\n this.config.on.openGallery?.(applyImage);\n };\n\n private triggerEvent<H extends CallableFunction | undefined>(\n handler: H,\n params: HandlerParams<H>,\n ) {\n if (!handler) {\n return;\n }\n\n return handler(params);\n }\n\n private onMessage = (\n ev: MessageEvent<{ source: string; event: keyof Handlers }>,\n ) => {\n if (ev.source !== this.iframe?.contentWindow) {\n return;\n }\n\n const {\n data: { source, event, ...data },\n } = ev;\n\n if (source === 'DraftPlugin') {\n if (event === 'openGallery') {\n this.onGalleryOpen(data as OpenGalleryParams);\n } else if (event === 'uploadImage') {\n this.onImageUpload(data as UploadImageParams & { id: string });\n } else if (event === 'loadPersonalization') {\n this.onLoadPersonalization((data as { requestId?: string }).requestId);\n } else if (event === 'loadSectionPersonalizationCatalog') {\n this.onLoadSectionPersonalizationCatalog(\n (data as { requestId?: string }).requestId,\n );\n } else if (event === 'renderSectionPersonalizationGroup') {\n this.onRenderSectionPersonalizationGroup(\n data as RenderSectionPersonalizationGroupInput & {\n requestId?: string;\n },\n );\n } else {\n this.triggerEvent(\n this.config.on[event],\n data as HandlerParams<Handlers[typeof event]>,\n );\n }\n }\n };\n\n start({\n template,\n templateName,\n uid,\n }: {\n template: string | TemplateJSON;\n uid: string | number;\n templateName?: string;\n }) {\n const containerEl = document.querySelector(this.config.container);\n\n if (!containerEl) {\n throw new Error('Specified container not found');\n } else {\n const onInit = (msg: OnInitParams) => {\n const {\n data: { source, event },\n } = msg;\n if (source === 'DraftPlugin' && event === 'loaded') {\n if (msg.source !== this.iframe?.contentWindow) return;\n\n this.iframeOrigin = msg.origin;\n\n const {\n on,\n container,\n locale,\n autosave,\n token,\n apiUrl,\n pluginId,\n authData,\n sectionPersonalization,\n __config,\n } = this.config;\n\n verifyConfig(this.config);\n\n if (this.iframe && this.iframe.contentWindow) {\n const resolvedSectionPersonalization = {\n ...sectionPersonalization,\n enabled:\n sectionPersonalization?.enabled === true &&\n !!on.loadSectionPersonalizationCatalog &&\n !!on.renderSectionPersonalizationGroup,\n };\n\n this.postEvent('init', {\n container,\n locale,\n uid,\n autosave,\n token,\n pluginId,\n authData,\n sectionPersonalization: resolvedSectionPersonalization,\n apiUrl,\n __config,\n enabledListeners: Object.keys(on),\n template,\n templateName,\n });\n }\n\n window.addEventListener('message', this.onMessage);\n window.removeEventListener('message', onInit);\n }\n };\n\n this.iframe = createIframe(window.location.origin);\n window.addEventListener('message', onInit);\n containerEl.appendChild(this.iframe);\n\n if (this.captureHotkeysEnabled() && !this.hotkeysAttached) {\n window.addEventListener('keydown', this.onHostHotkey);\n this.hotkeysAttached = true;\n }\n }\n }\n\n destroy = () => {\n this.iframe?.remove();\n this.iframe = null;\n window.removeEventListener('message', this.onMessage);\n\n if (this.hotkeysAttached) {\n window.removeEventListener('keydown', this.onHostHotkey);\n this.hotkeysAttached = false;\n }\n };\n\n changeTemplate(\n template: string | TemplateJSON,\n options: {\n templateName?: string;\n uid?: string;\n } = {},\n ) {\n this.postEvent('changeTemplate', { ...options, template });\n }\n\n toggleGrid(state?: boolean) {\n this.postEvent('toggleGrid', { state });\n }\n\n toggleInvisibleCharacters(state?: boolean) {\n this.postEvent('toggleInvisibleCharacters', { state });\n }\n\n async isInvisibleCharactersVisible() {\n const { state } = await this.promisedIframeMethod<{ state: boolean }>(\n 'getInvisibleCharactersVisibility',\n );\n\n return state;\n }\n\n togglePreview(state?: boolean) {\n this.postEvent('togglePreview', { state });\n }\n\n toggleMenu(menu: EditorMenu | null = null) {\n this.postEvent('toggleMenu', { menu });\n }\n\n toggleViewMode(viewMode: ViewMode) {\n this.postEvent('toggleViewMode', { viewMode });\n }\n\n undo() {\n this.postEvent('undo');\n }\n\n undoToStep(targetStep: number) {\n this.postEvent('undoToStep', { targetStep });\n }\n\n redo() {\n this.postEvent('redo');\n }\n\n save() {\n return this.promisedIframeMethod<SaveParams>('saveAction');\n }\n\n exit() {\n return this.promisedIframeMethod<ExitParams>('exitAction');\n }\n\n exportContent() {\n return this.promisedIframeMethod<SaveParams>('exportContent');\n }\n\n exportAsFile() {\n return this.promisedIframeMethod<ExportAsFileParams>('exportAsFile');\n }\n}\n","import { PluginInstance } from './plugin';\nimport { PluginConfig } from './types';\nimport { version } from '../package.json';\n\nconst DEFAULT_CONFIG: Partial<PluginConfig> = {\n container: '#draft-plugin-container',\n disableHotkeysPassing: false,\n locale: 'ru',\n on: {},\n};\n\nclass PluginWrapper {\n public version = version;\n\n create(config: PluginConfig) {\n return new PluginInstance({\n ...DEFAULT_CONFIG,\n ...config,\n });\n }\n}\n\nconst DraftPlugin = new PluginWrapper();\n\ndeclare global {\n interface Window {\n DraftPlugin: PluginWrapper;\n }\n}\n\nwindow.DraftPlugin = DraftPlugin;\n\nexport default DraftPlugin;\nexport type { PluginInstance } from './plugin';\nexport * from './types';\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- var DraftPlugin=(function(e){Object.defineProperties(e,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});var t=`http://localhost:5174`,n=`https://seplugin.sendsay.ru`,r=function(e){return e.Audit=`audit`,e.Guide=`guide`,e.Style=`style`,e.Blocks=`blocks`,e}({}),i=function(e){return e.Desktop=`desktop`,e.Mobile=`mobile`,e}({}),a=class extends Error{code;constructor(e,t){super(t),this.name=`DraftError`,this.code=e}},o=async e=>{try{let t=await fetch(e,{method:`HEAD`});if(!t.ok)return null;let n=t.headers.get(`Content-Length`);return n?parseInt(n,10):null}catch{return null}},s=e=>new Promise((t,n)=>{let r=new Image;r.onload=async()=>{let n=await o(e)??0;t({originalWidth:r.width,originalHeight:r.height,ratio:r.width/r.height,fileSize:n})},r.onerror=e=>{n(e)},r.src=e}),c=(e,t)=>{if(e.length!==1)return e;if(e.charCodeAt(0)>=880){if(t.indexOf(`Key`)===0&&t.length===4)return t.charAt(3);if(t.indexOf(`Digit`)===0&&t.length===6)return t.charAt(5)}return e},l=e=>{let t=`${c(e.key,e.code)}`.toLowerCase()||e.key,n=navigator.userAgent.includes(`Mac OS`);t===`backspace`&&n&&(t=`delete`);let r=[];return(n&&e.metaKey||!n&&e.ctrlKey)&&r.push(`mod`),e.shiftKey&&r.push(`shift`),r.length>0&&(t=`${r.join(`-`)}-${c(t,e.code)}`),t},u=new Set([`escape`,`mod-c`,`mod-d`,`mod-z`,`mod-y`,`mod-shift-z`,`mod-v`,`delete`,`mod-g`,`mod-p`,`mod-s`]),d=`@getdraft/plugin`,f=`1.17.5`,p={name:d,version:f,main:`dist/index.cjs.js`,module:`dist/index.es.js`,types:`dist/types/index.d.ts`,exports:{".":{types:`./dist/types/index.d.ts`,import:`./dist/index.es.js`,require:`./dist/index.cjs.js`}},scripts:{prebuild:`rm -rf dist`,build:`vite build`,"dev-tsc":`tsc-check`,eslint:`npx eslint src`,"eslint:fix":`pnpm eslint --fix`,prettify:`npx prettier --check src`,"prettify:fix":`npx prettier -w src`,prepublish:`pnpm build`,watch:`NODE_ENV=development vite build --watch`,start:`NODE_ENV=development npx vite`},dependencies:{},devDependencies:{"@getdraft/types":`workspace:^`,"@getdraft/eslint-config-ts":`workspace:^`,"@getdraft/prettier":`workspace:^`,"vite-plugin-dts":`4.5.4`},license:`MIT`},m=()=>{let e=RegExp(`(^| )seplugin-dev=([^;]+)`),r=document.cookie.match(e)?.[2].toLowerCase?.();if(r===`true`)return t;if(r?.startsWith(`https://`))return r;let[i,a]=p.version.split(`.`);return`${n}/v${i}.${a}`},h=({token:e,pluginId:t,apiUrl:n})=>{if(!e)throw Error(`No [token] was provided`);if(!t)throw Error(`No [pluginId] was provided`);if(!n)throw Error(`No [apiUrl] was provided`)},g=e=>{let t=document.createElement(`iframe`),n=new URL(m());return n.searchParams.set(`parentOrigin`,e),t.src=n.toString(),t.setAttribute(`style`,`height:100%;width:100%;min-width:960px;border:0px;`),t.setAttribute(`allow`,`clipboard-read; clipboard-write`),t.setAttribute(`sandbox`,`allow-scripts allow-same-origin allow-forms allow-popups allow-downloads`),t},_=class e{iframe=null;hotkeysAttached=!1;iframeOrigin=null;constructor(e){this.config=e}captureHotkeysEnabled(){return this.config.disableHotkeysPassing!==!0}onHostHotkey=e=>{if(!this.captureHotkeysEnabled()||!this.iframe?.contentWindow)return;let t=l(e);if(!u.has(t))return;let n=e.target;if(n&&(n.isContentEditable||[`INPUT`,`TEXTAREA`,`SELECT`].includes(n.tagName)))return;e.preventDefault();let{key:r,ctrlKey:i,metaKey:a,shiftKey:o,altKey:s}=e;this.postEvent(`hostHotkey`,{key:r,code:e.code,metaKey:a,ctrlKey:i,shiftKey:o,altKey:s,keyCode:t})};static HEARTBEAT_TIMEOUT=4e3;promisedIframeMethod(t){let n=null,r=null,i=()=>{n&&=(clearTimeout(n),null),r&&=(window.removeEventListener(`message`,r,!0),null)},o=new Promise((o,s)=>{let c=()=>{n&&clearTimeout(n),n=setTimeout(()=>{i(),s(new a(`timeout_error`,`Action "${t}" timed out`))},e.HEARTBEAT_TIMEOUT)};r=e=>{if(e.source!==this.iframe?.contentWindow)return;let{data:n}=e;if(n.source===`DraftPlugin`){if(n.event===`actionPing`&&n.action===t){e.stopPropagation(),c();return}if(n.event===t){e.stopPropagation(),i();let{source:t,event:r,ok:c,code:l,message:u,...d}=n;c===!1?s(new a(l||`unknown_error`,u||`Unknown error`)):o(d)}}},window.addEventListener(`message`,r,!0),c()});return this.postEvent(t),o}postEvent(e,t={}){if(this.iframe&&this.iframe.contentWindow&&this.iframeOrigin)this.iframe.contentWindow.postMessage({...t,event:e,source:`DraftPlugin`},this.iframeOrigin);else if(!this.iframeOrigin)throw Error(`Iframe origin is not initialized`)}onImageUpload=async({id:e,...t})=>{try{let n=await this.config.on.uploadImage?.(t),r={};n&&(r=await s(n)),this.postEvent(`imageUploaded`,{id:e,img:{...r,url:n}})}catch{this.postEvent(`imageUploaded`,{id:e})}};onLoadPersonalization=async()=>{try{if(!this.config.on.loadPersonalization)throw Error(`No personalization loader provided`);let e=await this.config.on.loadPersonalization();this.postEvent(`loadPersonalization`,{items:e})}catch{this.postEvent(`loadPersonalization`,{})}};onGalleryOpen=async({id:e})=>{this.config.on.openGallery?.(async t=>{let n={url:t};if(t){let e=await s(t);Object.assign(n,e)}this.postEvent(`imageUploaded`,{id:e,img:n})})};triggerEvent(e,t){if(e)return e(t)}onMessage=e=>{if(e.source!==this.iframe?.contentWindow)return;let{data:{source:t,event:n,...r}}=e;t===`DraftPlugin`&&(n===`openGallery`?this.onGalleryOpen(r):n===`uploadImage`?this.onImageUpload(r):n===`loadPersonalization`?this.onLoadPersonalization():this.triggerEvent(this.config.on[n],r))};start({template:e,templateName:t,uid:n}){let r=document.querySelector(this.config.container);if(r){let i=r=>{let{data:{source:a,event:o}}=r;if(a===`DraftPlugin`&&o===`loaded`){if(r.source!==this.iframe?.contentWindow)return;this.iframeOrigin=r.origin;let{on:a,container:o,locale:s,autosave:c,token:l,apiUrl:u,pluginId:d,authData:f,__config:p}=this.config;h(this.config),this.iframe&&this.iframe.contentWindow&&this.postEvent(`init`,{container:o,locale:s,uid:n,autosave:c,token:l,pluginId:d,authData:f,apiUrl:u,__config:p,enabledListeners:Object.keys(a),template:e,templateName:t}),window.addEventListener(`message`,this.onMessage),window.removeEventListener(`message`,i)}};this.iframe=g(window.location.origin),window.addEventListener(`message`,i),r.appendChild(this.iframe),this.captureHotkeysEnabled()&&!this.hotkeysAttached&&(window.addEventListener(`keydown`,this.onHostHotkey),this.hotkeysAttached=!0)}else throw Error(`Specified container not found`)}destroy=()=>{this.iframe?.remove(),this.iframe=null,window.removeEventListener(`message`,this.onMessage),this.hotkeysAttached&&=(window.removeEventListener(`keydown`,this.onHostHotkey),!1)};changeTemplate(e,t={}){this.postEvent(`changeTemplate`,{...t,template:e})}toggleGrid(e){this.postEvent(`toggleGrid`,{state:e})}toggleInvisibleCharacters(e){this.postEvent(`toggleInvisibleCharacters`,{state:e})}async isInvisibleCharactersVisible(){let{state:e}=await this.promisedIframeMethod(`getInvisibleCharactersVisibility`);return e}togglePreview(e){this.postEvent(`togglePreview`,{state:e})}toggleMenu(e=null){this.postEvent(`toggleMenu`,{menu:e})}toggleViewMode(e){this.postEvent(`toggleViewMode`,{viewMode:e})}undo(){this.postEvent(`undo`)}undoToStep(e){this.postEvent(`undoToStep`,{targetStep:e})}redo(){this.postEvent(`redo`)}save(){return this.promisedIframeMethod(`saveAction`)}exit(){return this.promisedIframeMethod(`exitAction`)}exportContent(){return this.promisedIframeMethod(`exportContent`)}exportAsFile(){return this.promisedIframeMethod(`exportAsFile`)}},v={container:`#draft-plugin-container`,disableHotkeysPassing:!1,locale:`ru`,on:{}},y=new class{version=f;create(e){return new _({...v,...e})}};return window.DraftPlugin=y,e.DraftError=a,e.EditorMenu=r,e.ViewMode=i,e.default=y,e})({});
1
+ var DraftPlugin=(function(e){Object.defineProperties(e,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});var t=`http://localhost:5174`,n=`https://seplugin.sendsay.ru`,r=function(e){return e.Audit=`audit`,e.Guide=`guide`,e.Style=`style`,e.Blocks=`blocks`,e}({}),i=function(e){return e.Desktop=`desktop`,e.Mobile=`mobile`,e}({}),a=class extends Error{code;constructor(e,t){super(t),this.name=`DraftError`,this.code=e}},o=async e=>{try{let t=await fetch(e,{method:`HEAD`});if(!t.ok)return null;let n=t.headers.get(`Content-Length`);return n?parseInt(n,10):null}catch{return null}},s=e=>new Promise((t,n)=>{let r=new Image;r.onload=async()=>{let n=await o(e)??0;t({originalWidth:r.width,originalHeight:r.height,ratio:r.width/r.height,fileSize:n})},r.onerror=e=>{n(e)},r.src=e}),c=(e,t)=>{if(e.length!==1)return e;if(e.charCodeAt(0)>=880){if(t.indexOf(`Key`)===0&&t.length===4)return t.charAt(3);if(t.indexOf(`Digit`)===0&&t.length===6)return t.charAt(5)}return e},l=e=>{let t=`${c(e.key,e.code)}`.toLowerCase()||e.key,n=navigator.userAgent.includes(`Mac OS`);t===`backspace`&&n&&(t=`delete`);let r=[];return(n&&e.metaKey||!n&&e.ctrlKey)&&r.push(`mod`),e.shiftKey&&r.push(`shift`),r.length>0&&(t=`${r.join(`-`)}-${c(t,e.code)}`),t},u=new Set([`escape`,`mod-c`,`mod-d`,`mod-z`,`mod-y`,`mod-shift-z`,`mod-v`,`delete`,`mod-g`,`mod-p`,`mod-s`]),d=`@getdraft/plugin`,f=`1.19.0-alpha.0`,p={name:d,version:f,main:`dist/index.cjs.js`,module:`dist/index.es.js`,types:`dist/types/index.d.ts`,exports:{".":{types:`./dist/types/index.d.ts`,import:`./dist/index.es.js`,require:`./dist/index.cjs.js`}},scripts:{prebuild:`rm -rf dist`,build:`vite build`,"dev-tsc":`tsc-check`,eslint:`npx eslint src`,"eslint:fix":`pnpm eslint --fix`,prettify:`npx prettier --check src`,"prettify:fix":`npx prettier -w src`,prepublish:`pnpm build`,watch:`NODE_ENV=development vite build --watch`,start:`NODE_ENV=development npx vite`},dependencies:{},devDependencies:{"@getdraft/types":`workspace:^`,"@getdraft/eslint-config-ts":`workspace:^`,"@getdraft/prettier":`workspace:^`,"vite-plugin-dts":`4.5.4`},license:`MIT`},m=`Unknown error`,h=()=>{let e=RegExp(`(^| )seplugin-dev=([^;]+)`),r=document.cookie.match(e)?.[2].toLowerCase?.();if(r===`true`)return t;if(r?.startsWith(`https://`))return r;let[i,a]=p.version.split(`.`);return`${n}/v${i}.${a}`},g=({token:e,pluginId:t,apiUrl:n})=>{if(!e)throw Error(`No [token] was provided`);if(!t)throw Error(`No [pluginId] was provided`);if(!n)throw Error(`No [apiUrl] was provided`)},_=e=>{let t=document.createElement(`iframe`),n=new URL(h());return n.searchParams.set(`parentOrigin`,e),t.src=n.toString(),t.setAttribute(`style`,`height:100%;width:100%;min-width:960px;border:0px;`),t.setAttribute(`allow`,`clipboard-read; clipboard-write`),t.setAttribute(`sandbox`,`allow-scripts allow-same-origin allow-forms allow-popups allow-downloads`),t},v=class e{iframe=null;hotkeysAttached=!1;iframeOrigin=null;constructor(e){this.config=e}captureHotkeysEnabled(){return this.config.disableHotkeysPassing!==!0}onHostHotkey=e=>{if(!this.captureHotkeysEnabled()||!this.iframe?.contentWindow)return;let t=l(e);if(!u.has(t))return;let n=e.target;if(n&&(n.isContentEditable||[`INPUT`,`TEXTAREA`,`SELECT`].includes(n.tagName)))return;e.preventDefault();let{key:r,ctrlKey:i,metaKey:a,shiftKey:o,altKey:s}=e;this.postEvent(`hostHotkey`,{key:r,code:e.code,metaKey:a,ctrlKey:i,shiftKey:o,altKey:s,keyCode:t})};static HEARTBEAT_TIMEOUT=4e3;promisedIframeMethod(t){let n=null,r=null,i=()=>{n&&=(clearTimeout(n),null),r&&=(window.removeEventListener(`message`,r,!0),null)},o=new Promise((o,s)=>{let c=()=>{n&&clearTimeout(n),n=setTimeout(()=>{i(),s(new a(`timeout_error`,`Action "${t}" timed out`))},e.HEARTBEAT_TIMEOUT)};r=e=>{if(e.source!==this.iframe?.contentWindow)return;let{data:n}=e;if(n.source===`DraftPlugin`){if(n.event===`actionPing`&&n.action===t){e.stopPropagation(),c();return}if(n.event===t){e.stopPropagation(),i();let{source:t,event:r,ok:c,code:l,message:u,...d}=n;c===!1?s(new a(l||`unknown_error`,u||m)):o(d)}}},window.addEventListener(`message`,r,!0),c()});return this.postEvent(t),o}postEvent(e,t={}){if(this.iframe&&this.iframe.contentWindow&&this.iframeOrigin)this.iframe.contentWindow.postMessage({...t,event:e,source:`DraftPlugin`},this.iframeOrigin);else if(!this.iframeOrigin)throw Error(`Iframe origin is not initialized`)}onImageUpload=async({id:e,...t})=>{try{let n=await this.config.on.uploadImage?.(t),r={};n&&(r=await s(n)),this.postEvent(`imageUploaded`,{id:e,img:{...r,url:n}})}catch{this.postEvent(`imageUploaded`,{id:e})}};onLoadPersonalization=async e=>{try{if(!this.config.on.loadPersonalization)throw Error(`No personalization loader provided`);let t=await this.config.on.loadPersonalization();this.postEvent(`loadPersonalization`,{items:t,requestId:e})}catch{this.postEvent(`loadPersonalization`,{requestId:e})}};onLoadSectionPersonalizationCatalog=async e=>{try{let t=this.config.on.loadSectionPersonalizationCatalog;if(!t)throw Error(`No section personalization catalog loader provided`);let n=await t();this.postEvent(`loadSectionPersonalizationCatalog`,{ok:!0,requestId:e,catalog:n})}catch(t){this.postEvent(`loadSectionPersonalizationCatalog`,{ok:!1,requestId:e,message:t instanceof Error?t.message:m})}};onRenderSectionPersonalizationGroup=async e=>{let{requestId:t,...n}=e;try{let e=this.config.on.renderSectionPersonalizationGroup;if(!e)throw Error(`No section personalization renderer provided`);let r=await e(n);this.postEvent(`renderSectionPersonalizationGroup`,{ok:!0,requestId:t,html:r})}catch(e){this.postEvent(`renderSectionPersonalizationGroup`,{ok:!1,requestId:t,message:e instanceof Error?e.message:m})}};onGalleryOpen=async({id:e})=>{this.config.on.openGallery?.(async t=>{let n={url:t};if(t){let e=await s(t);Object.assign(n,e)}this.postEvent(`imageUploaded`,{id:e,img:n})})};triggerEvent(e,t){if(e)return e(t)}onMessage=e=>{if(e.source!==this.iframe?.contentWindow)return;let{data:{source:t,event:n,...r}}=e;t===`DraftPlugin`&&(n===`openGallery`?this.onGalleryOpen(r):n===`uploadImage`?this.onImageUpload(r):n===`loadPersonalization`?this.onLoadPersonalization(r.requestId):n===`loadSectionPersonalizationCatalog`?this.onLoadSectionPersonalizationCatalog(r.requestId):n===`renderSectionPersonalizationGroup`?this.onRenderSectionPersonalizationGroup(r):this.triggerEvent(this.config.on[n],r))};start({template:e,templateName:t,uid:n}){let r=document.querySelector(this.config.container);if(r){let i=r=>{let{data:{source:a,event:o}}=r;if(a===`DraftPlugin`&&o===`loaded`){if(r.source!==this.iframe?.contentWindow)return;this.iframeOrigin=r.origin;let{on:a,container:o,locale:s,autosave:c,token:l,apiUrl:u,pluginId:d,authData:f,sectionPersonalization:p,__config:m}=this.config;if(g(this.config),this.iframe&&this.iframe.contentWindow){let r={...p,enabled:p?.enabled===!0&&!!a.loadSectionPersonalizationCatalog&&!!a.renderSectionPersonalizationGroup};this.postEvent(`init`,{container:o,locale:s,uid:n,autosave:c,token:l,pluginId:d,authData:f,sectionPersonalization:r,apiUrl:u,__config:m,enabledListeners:Object.keys(a),template:e,templateName:t})}window.addEventListener(`message`,this.onMessage),window.removeEventListener(`message`,i)}};this.iframe=_(window.location.origin),window.addEventListener(`message`,i),r.appendChild(this.iframe),this.captureHotkeysEnabled()&&!this.hotkeysAttached&&(window.addEventListener(`keydown`,this.onHostHotkey),this.hotkeysAttached=!0)}else throw Error(`Specified container not found`)}destroy=()=>{this.iframe?.remove(),this.iframe=null,window.removeEventListener(`message`,this.onMessage),this.hotkeysAttached&&=(window.removeEventListener(`keydown`,this.onHostHotkey),!1)};changeTemplate(e,t={}){this.postEvent(`changeTemplate`,{...t,template:e})}toggleGrid(e){this.postEvent(`toggleGrid`,{state:e})}toggleInvisibleCharacters(e){this.postEvent(`toggleInvisibleCharacters`,{state:e})}async isInvisibleCharactersVisible(){let{state:e}=await this.promisedIframeMethod(`getInvisibleCharactersVisibility`);return e}togglePreview(e){this.postEvent(`togglePreview`,{state:e})}toggleMenu(e=null){this.postEvent(`toggleMenu`,{menu:e})}toggleViewMode(e){this.postEvent(`toggleViewMode`,{viewMode:e})}undo(){this.postEvent(`undo`)}undoToStep(e){this.postEvent(`undoToStep`,{targetStep:e})}redo(){this.postEvent(`redo`)}save(){return this.promisedIframeMethod(`saveAction`)}exit(){return this.promisedIframeMethod(`exitAction`)}exportContent(){return this.promisedIframeMethod(`exportContent`)}exportAsFile(){return this.promisedIframeMethod(`exportAsFile`)}},y={container:`#draft-plugin-container`,disableHotkeysPassing:!1,locale:`ru`,on:{}},b=new class{version=f;create(e){return new v({...y,...e})}};return window.DraftPlugin=b,e.DraftError=a,e.EditorMenu=r,e.ViewMode=i,e.default=b,e})({});
2
2
  //# sourceMappingURL=index.iife.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.iife.js","names":[],"sources":["../src/routes.ts","../src/types.ts","../src/utils.ts","../package.json","../src/plugin.ts","../src/index.ts"],"sourcesContent":["export const LOCAL_ENDPOINT = 'http://localhost:5174';\nexport const PROD_ENDPOINT = 'https://seplugin.sendsay.ru';\n","export enum EditorMenu {\n Audit = 'audit',\n Guide = 'guide',\n Style = 'style',\n Blocks = 'blocks',\n}\n\nexport enum ViewMode {\n Desktop = 'desktop',\n Mobile = 'mobile',\n}\n\nexport interface Notification {\n intent: 'error' | 'info' | 'success' | 'warning';\n errorDetails?: object;\n message?: string;\n title: string;\n}\n\ntype PersonalizationDictionaryEntry =\n | { name: string; value: string }\n | { groupName: string; items: Array<{ name: string; value: string }> };\n\nexport type PersonalizationDictionaryItems = PersonalizationDictionaryEntry[];\n\nexport interface SerializedTemplate {\n [key: string]: unknown;\n parentId: string | null;\n id: string;\n parameters: object;\n layer: string;\n type: string;\n children?: SerializedTemplate[];\n meta?: { [key: string]: unknown; version: string };\n}\n\nexport type EventHandler<T> = (data: T) => void;\n\nexport type AsyncEventHandler<P, R> = (params: P) => Promise<R>;\n\nexport class DraftError extends Error {\n public readonly code: string;\n\n constructor(code: string, message: string) {\n super(message);\n this.name = 'DraftError';\n this.code = code;\n }\n}\n\nexport type MessageData = {\n source: string;\n event: string;\n ok?: boolean;\n code?: string;\n message?: string;\n action?: string;\n};\n\nexport interface ExportAsFileParams {\n blob: Blob;\n fileName: string;\n}\n\nexport interface SaveParams {\n json: TemplateJSON;\n html: string;\n}\n\nexport type OnInitParams = MessageEvent<{\n source: string;\n event: 'loaded' | unknown;\n}>;\n\nexport interface ReadyParams extends SaveParams {\n lastSavedTemplate?: {\n template: TemplateJSON;\n date: Date;\n };\n}\n\nexport interface ErrorParams {\n message: string;\n code?: string;\n details?: unknown;\n}\n\nexport interface ExitParams extends SaveParams {}\n\nexport type NotificationParams = Notification;\n\nexport interface OpenGalleryParams {\n id: string;\n}\n\nexport interface UploadImageParams {\n file: string;\n name: string;\n}\n\nexport interface ImageParams {\n url: string;\n originalWidth: number;\n originalHeight: number;\n ratio: number;\n fileSize: number;\n}\n\nexport interface AutosaveParams {\n json: TemplateJSON;\n}\n\ninterface ToggleParams {\n state: boolean;\n}\n\nexport interface ToggleGridParams extends ToggleParams {}\n\nexport interface ToggleInvisibleCharactersParams extends ToggleParams {}\n\nexport interface TogglePreviewParams extends ToggleParams {\n json: TemplateJSON;\n html: string;\n darkHTML: string;\n}\n\nexport interface ToggleViewModeParams {\n mode: ViewMode;\n}\n\nexport interface ToggleMenuParams {\n menu: EditorMenu | null;\n}\n\nexport interface HistoryParams {\n hasUndos: boolean;\n hasRedos: boolean;\n currentStep: number;\n}\n\nexport type TemplateJSON = SerializedTemplate;\n\nexport type PersonalizationDictionary = PersonalizationDictionaryItems;\n\nexport type ToolbarActionName =\n | 'duplicate'\n | 'destroy'\n | 'edit'\n | 'up'\n | 'down';\nexport type HotkeyContext = 'hotkey';\nexport type OverlayContext = 'overlay-click' | 'overlay-double-click';\nexport type ToolbarContext = 'toolbar';\nexport type UnitSettingsContext = 'unit-settings';\nexport type BlockType = 'system' | 'user';\nexport type DndDragContext = 'canvas' | 'list' | 'palette';\nexport type DndDropContext = 'dropline' | 'placeholder' | 'empty-placeholder';\nexport type DndDropTarget = 'root' | 'section' | 'column' | 'element';\n\nexport interface DuplicateEvent {\n name: 'duplicate';\n context: HotkeyContext | ToolbarContext | UnitSettingsContext;\n unitType: string;\n}\n\nexport interface DestroyEvent {\n name: 'destroy';\n context: HotkeyContext | ToolbarContext | UnitSettingsContext;\n unitType: string;\n}\n\nexport interface EditEvent {\n name: 'edit';\n context: OverlayContext | ToolbarContext;\n unitType: string;\n}\n\nexport interface HistoryEvent {\n name: 'history';\n type: 'undo' | 'redo';\n context: HotkeyContext;\n}\n\nexport interface PreviewEvent {\n name: 'preview';\n context: HotkeyContext;\n}\n\nexport interface ToolbarMoveEvent {\n name: 'up' | 'down';\n context: ToolbarContext;\n unitType: string;\n}\n\nexport interface BlockInsertEvent {\n name: 'block-insert';\n context: 'double-click';\n blockType: BlockType;\n blockName: string;\n blockCategory: string | number;\n blockId: string | number;\n}\n\nexport interface BlockSaveEvent {\n name: 'block-save';\n blockType: 'user';\n blockName: string;\n blockCategory: string | number;\n blockId: string | number;\n elements: Record<string, number> & { sum: number };\n}\n\nexport interface BlockDestroyEvent {\n name: 'block-destroy';\n}\n\nexport interface DropEventDragMeta {\n context?: DndDragContext;\n layer?: 'element' | 'section' | 'column' | 'root';\n type?: string | string[];\n blockCategory?: string | number;\n blockId?: string | number;\n blockName?: string;\n blockType?: BlockType;\n alt?: boolean;\n dropKind?: 'create' | 'move';\n}\n\nexport interface DropEventDropzoneMeta {\n context?: DndDropContext;\n dropTarget?: DndDropTarget;\n}\n\nexport interface DropEvent {\n name: 'drop';\n drag?: DropEventDragMeta;\n dropzone?: DropEventDropzoneMeta;\n}\n\nexport type AnalyticsParams =\n | DuplicateEvent\n | DestroyEvent\n | EditEvent\n | HistoryEvent\n | PreviewEvent\n | ToolbarMoveEvent\n | BlockInsertEvent\n | BlockSaveEvent\n | BlockDestroyEvent\n | DropEvent;\n\nexport interface Handlers {\n ready: EventHandler<ReadyParams>;\n error: EventHandler<ErrorParams>;\n save: EventHandler<SaveParams>;\n exit: EventHandler<ExitParams>;\n notification: EventHandler<NotificationParams>;\n autosave: EventHandler<AutosaveParams>;\n toggleGrid: EventHandler<ToggleGridParams>;\n toggleInvisibleCharacters: EventHandler<ToggleInvisibleCharactersParams>;\n togglePreview: EventHandler<TogglePreviewParams>;\n toggleViewMode: EventHandler<ToggleViewModeParams>;\n toggleMenu: EventHandler<ToggleMenuParams>;\n history: EventHandler<HistoryParams>;\n analytics: EventHandler<AnalyticsParams>;\n openGallery: EventHandler<(url?: string) => Promise<void>>;\n uploadImage: AsyncEventHandler<UploadImageParams, string>;\n loadPersonalization: AsyncEventHandler<void, PersonalizationDictionary>;\n}\n\nexport type HandlerParams<H> = H extends\n | EventHandler<infer P>\n | AsyncEventHandler<infer P, unknown>\n ? P\n : never;\n\nexport interface PluginConfig {\n container: string;\n locale?: string;\n autosave?:\n | boolean\n | {\n interval: number;\n };\n token: string;\n authData?: {\n orgId: number;\n projectId?: number;\n };\n pluginId: string;\n apiUrl: string;\n disableHotkeysPassing?: boolean;\n __config?: object;\n on: Partial<Handlers>;\n}\n","import { ImageParams } from './types';\n\nconst getImageFileSize = async (imageUrl: string) => {\n try {\n const response = await fetch(imageUrl, { method: 'HEAD' });\n\n if (!response.ok) {\n return null;\n }\n\n const contentLength = response.headers.get('Content-Length');\n\n if (contentLength) {\n return parseInt(contentLength, 10);\n } else {\n return null;\n }\n } catch (error) {\n return null;\n }\n};\n\nexport const getImageParamsFromFileUrl = (imgSrc: string) =>\n new Promise<Omit<ImageParams, 'url'>>((resolve, reject) => {\n const img = new Image();\n\n img.onload = async () => {\n const fileSize = (await getImageFileSize(imgSrc)) ?? 0;\n\n resolve({\n originalWidth: img.width,\n originalHeight: img.height,\n ratio: img.width / img.height,\n fileSize,\n });\n };\n\n img.onerror = (error) => {\n reject(error);\n };\n\n img.src = imgSrc;\n });\n\nconst getLatinKey = (key: string, code: string) => {\n if (key.length !== 1) {\n return key;\n }\n\n const capitalHetaCode = 880;\n const isNonLatin = key.charCodeAt(0) >= capitalHetaCode;\n\n if (isNonLatin) {\n if (code.indexOf('Key') === 0 && code.length === 4) {\n return code.charAt(3);\n }\n\n if (code.indexOf('Digit') === 0 && code.length === 6) {\n return code.charAt(5);\n }\n }\n\n return key;\n};\n\nexport const constructKeyCode = (event: KeyboardEvent) => {\n let keyCode =\n `${getLatinKey(event.key, event.code)}`.toLowerCase() || event.key;\n const macOs = navigator.userAgent.includes('Mac OS');\n\n if (keyCode === 'backspace' && macOs) {\n keyCode = 'delete';\n }\n\n const prefix = [];\n\n if ((macOs && event.metaKey) || (!macOs && event.ctrlKey)) {\n prefix.push('mod');\n }\n\n if (event.shiftKey) {\n prefix.push('shift');\n }\n\n if (prefix.length > 0) {\n keyCode = `${prefix.join('-')}-${getLatinKey(keyCode, event.code)}`;\n }\n\n return keyCode;\n};\n\nexport const CORE_HOTKEYS = new Set([\n 'escape',\n 'mod-c',\n 'mod-d',\n 'mod-z',\n 'mod-y',\n 'mod-shift-z',\n 'mod-v',\n 'delete',\n 'mod-g',\n 'mod-p',\n 'mod-s',\n]);\n","{\n \"name\": \"@getdraft/plugin\",\n \"version\": \"1.17.5\",\n \"main\": \"dist/index.cjs.js\",\n \"module\": \"dist/index.es.js\",\n \"types\": \"dist/types/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/types/index.d.ts\",\n \"import\": \"./dist/index.es.js\",\n \"require\": \"./dist/index.cjs.js\"\n }\n },\n \"scripts\": {\n \"prebuild\": \"rm -rf dist\",\n \"build\": \"vite build\",\n \"dev-tsc\": \"tsc-check\",\n \"eslint\": \"npx eslint src\",\n \"eslint:fix\": \"pnpm eslint --fix\",\n \"prettify\": \"npx prettier --check src\",\n \"prettify:fix\": \"npx prettier -w src\",\n \"prepublish\": \"pnpm build\",\n \"watch\": \"NODE_ENV=development vite build --watch\",\n \"start\": \"NODE_ENV=development npx vite\"\n },\n \"dependencies\": {},\n \"devDependencies\": {\n \"@getdraft/types\": \"workspace:^\",\n \"@getdraft/eslint-config-ts\": \"workspace:^\",\n \"@getdraft/prettier\": \"workspace:^\",\n \"vite-plugin-dts\": \"4.5.4\"\n },\n \"license\": \"MIT\"\n}\n","import { LOCAL_ENDPOINT, PROD_ENDPOINT } from './routes';\nimport {\n DraftError,\n EditorMenu,\n ExitParams,\n OnInitParams,\n OpenGalleryParams,\n Handlers,\n PluginConfig,\n SaveParams,\n TemplateJSON,\n UploadImageParams,\n ViewMode,\n HandlerParams,\n MessageData,\n ExportAsFileParams,\n} from './types';\nimport {\n getImageParamsFromFileUrl,\n constructKeyCode,\n CORE_HOTKEYS,\n} from './utils';\nimport pkg from '../package.json';\n\nconst getDeployLink = () => {\n const regex = new RegExp(`(^| )seplugin-dev=([^;]+)`);\n const match = document.cookie.match(regex);\n const value = match?.[2].toLowerCase?.();\n\n if (value === 'true') {\n return LOCAL_ENDPOINT;\n }\n\n if (value?.startsWith('https://')) {\n return value;\n }\n\n const [major, mid] = pkg.version.split('.');\n\n return `${PROD_ENDPOINT}/v${major}.${mid}`;\n};\n\nconst verifyConfig = ({ token, pluginId, apiUrl }: PluginConfig) => {\n if (!token) {\n throw new Error('No [token] was provided');\n }\n\n if (!pluginId) {\n throw new Error('No [pluginId] was provided');\n }\n\n if (!apiUrl) {\n throw new Error('No [apiUrl] was provided');\n }\n};\n\nconst createIframe = (parentOrigin: string) => {\n const iframe = document.createElement('iframe');\n const url = new URL(getDeployLink());\n url.searchParams.set('parentOrigin', parentOrigin);\n iframe.src = url.toString();\n iframe.setAttribute(\n 'style',\n 'height:100%;width:100%;min-width:960px;border:0px;',\n );\n iframe.setAttribute('allow', 'clipboard-read; clipboard-write');\n iframe.setAttribute(\n 'sandbox',\n 'allow-scripts allow-same-origin allow-forms allow-popups allow-downloads',\n );\n\n return iframe;\n};\n\nexport class PluginInstance {\n public iframe: HTMLIFrameElement | null = null;\n private hotkeysAttached = false;\n private iframeOrigin: string | null = null;\n constructor(public config: PluginConfig) {}\n\n private captureHotkeysEnabled() {\n return this.config.disableHotkeysPassing !== true;\n }\n\n private onHostHotkey = (event: KeyboardEvent) => {\n if (!this.captureHotkeysEnabled() || !this.iframe?.contentWindow) {\n return;\n }\n\n const keyCode = constructKeyCode(event);\n\n if (!CORE_HOTKEYS.has(keyCode)) {\n return;\n }\n\n const target = event.target as HTMLElement | null;\n\n if (\n target &&\n (target.isContentEditable ||\n ['INPUT', 'TEXTAREA', 'SELECT'].includes(target.tagName))\n ) {\n return;\n }\n\n event.preventDefault();\n\n const { key, ctrlKey, metaKey, shiftKey, altKey } = event;\n\n this.postEvent('hostHotkey', {\n key,\n code: event.code,\n metaKey,\n ctrlKey,\n shiftKey,\n altKey,\n keyCode,\n });\n };\n\n private static HEARTBEAT_TIMEOUT = 4000;\n\n private promisedIframeMethod<T>(eventName: string) {\n let timer: Timeout | null = null;\n let listener: ((e: MessageEvent<MessageData>) => void) | null = null;\n\n const cleanup = () => {\n if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n\n if (listener) {\n window.removeEventListener('message', listener, true);\n listener = null;\n }\n };\n\n const res = new Promise<T>((resolve, reject) => {\n const resetTimer = () => {\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => {\n cleanup();\n reject(\n new DraftError('timeout_error', `Action \"${eventName}\" timed out`),\n );\n }, PluginInstance.HEARTBEAT_TIMEOUT);\n };\n\n listener = (e: MessageEvent<MessageData>) => {\n if (e.source !== this.iframe?.contentWindow) return;\n\n const { data } = e;\n if (data.source !== 'DraftPlugin') return;\n\n if (data.event === 'actionPing' && data.action === eventName) {\n e.stopPropagation();\n resetTimer();\n\n return;\n }\n\n if (data.event === eventName) {\n e.stopPropagation();\n cleanup();\n\n const { source: _1, event: _2, ok, code, message, ...rest } = data;\n\n if (ok === false) {\n reject(\n new DraftError(\n code || 'unknown_error',\n message || 'Unknown error',\n ),\n );\n } else {\n resolve(rest as T);\n }\n }\n };\n\n window.addEventListener('message', listener, true);\n resetTimer();\n });\n\n this.postEvent(eventName);\n\n return res;\n }\n\n private postEvent(event: string, data: object = {}) {\n if (this.iframe && this.iframe.contentWindow && this.iframeOrigin) {\n this.iframe.contentWindow.postMessage(\n {\n ...data,\n event,\n source: 'DraftPlugin',\n },\n this.iframeOrigin,\n );\n } else if (!this.iframeOrigin) {\n throw new Error('Iframe origin is not initialized');\n }\n }\n\n private onImageUpload = async ({\n id,\n ...data\n }: UploadImageParams & { id: string }) => {\n try {\n const url = await this.config.on.uploadImage?.(data);\n let params = {};\n\n if (url) {\n params = await getImageParamsFromFileUrl(url);\n }\n\n this.postEvent('imageUploaded', { id, img: { ...params, url } });\n } catch (e) {\n this.postEvent('imageUploaded', { id });\n }\n };\n\n private onLoadPersonalization = async () => {\n try {\n if (!this.config.on.loadPersonalization) {\n throw new Error('No personalization loader provided');\n }\n\n const personalizationDictionary =\n await this.config.on.loadPersonalization();\n\n this.postEvent('loadPersonalization', {\n items: personalizationDictionary,\n });\n } catch (e) {\n this.postEvent('loadPersonalization', {});\n }\n };\n\n private onGalleryOpen = async ({ id }: { id: string }) => {\n const applyImage = async (url?: string) => {\n const imgParams = { url };\n\n if (url) {\n const params = await getImageParamsFromFileUrl(url);\n Object.assign(imgParams, params);\n }\n\n this.postEvent('imageUploaded', {\n id,\n img: imgParams,\n });\n };\n\n this.config.on.openGallery?.(applyImage);\n };\n\n private triggerEvent<H extends CallableFunction | undefined>(\n handler: H,\n params: HandlerParams<H>,\n ) {\n if (!handler) {\n return;\n }\n\n return handler(params);\n }\n\n private onMessage = (\n ev: MessageEvent<{ source: string; event: keyof Handlers }>,\n ) => {\n if (ev.source !== this.iframe?.contentWindow) {\n return;\n }\n\n const {\n data: { source, event, ...data },\n } = ev;\n\n if (source === 'DraftPlugin') {\n if (event === 'openGallery') {\n this.onGalleryOpen(data as OpenGalleryParams);\n } else if (event === 'uploadImage') {\n this.onImageUpload(data as UploadImageParams & { id: string });\n } else if (event === 'loadPersonalization') {\n this.onLoadPersonalization();\n } else {\n this.triggerEvent(\n this.config.on[event],\n data as HandlerParams<Handlers[typeof event]>,\n );\n }\n }\n };\n\n start({\n template,\n templateName,\n uid,\n }: {\n template: string | TemplateJSON;\n uid: string | number;\n templateName?: string;\n }) {\n const containerEl = document.querySelector(this.config.container);\n\n if (!containerEl) {\n throw new Error('Specified container not found');\n } else {\n const onInit = (msg: OnInitParams) => {\n const {\n data: { source, event },\n } = msg;\n if (source === 'DraftPlugin' && event === 'loaded') {\n if (msg.source !== this.iframe?.contentWindow) return;\n\n this.iframeOrigin = msg.origin;\n\n const {\n on,\n container,\n locale,\n autosave,\n token,\n apiUrl,\n pluginId,\n authData,\n __config,\n } = this.config;\n\n verifyConfig(this.config);\n\n if (this.iframe && this.iframe.contentWindow) {\n this.postEvent('init', {\n container,\n locale,\n uid,\n autosave,\n token,\n pluginId,\n authData,\n apiUrl,\n __config,\n enabledListeners: Object.keys(on),\n template,\n templateName,\n });\n }\n\n window.addEventListener('message', this.onMessage);\n window.removeEventListener('message', onInit);\n }\n };\n\n this.iframe = createIframe(window.location.origin);\n window.addEventListener('message', onInit);\n containerEl.appendChild(this.iframe);\n\n if (this.captureHotkeysEnabled() && !this.hotkeysAttached) {\n window.addEventListener('keydown', this.onHostHotkey);\n this.hotkeysAttached = true;\n }\n }\n }\n\n destroy = () => {\n this.iframe?.remove();\n this.iframe = null;\n window.removeEventListener('message', this.onMessage);\n\n if (this.hotkeysAttached) {\n window.removeEventListener('keydown', this.onHostHotkey);\n this.hotkeysAttached = false;\n }\n };\n\n changeTemplate(\n template: string | TemplateJSON,\n options: {\n templateName?: string;\n uid?: string;\n } = {},\n ) {\n this.postEvent('changeTemplate', { ...options, template });\n }\n\n toggleGrid(state?: boolean) {\n this.postEvent('toggleGrid', { state });\n }\n\n toggleInvisibleCharacters(state?: boolean) {\n this.postEvent('toggleInvisibleCharacters', { state });\n }\n\n async isInvisibleCharactersVisible() {\n const { state } = await this.promisedIframeMethod<{ state: boolean }>(\n 'getInvisibleCharactersVisibility',\n );\n\n return state;\n }\n\n togglePreview(state?: boolean) {\n this.postEvent('togglePreview', { state });\n }\n\n toggleMenu(menu: EditorMenu | null = null) {\n this.postEvent('toggleMenu', { menu });\n }\n\n toggleViewMode(viewMode: ViewMode) {\n this.postEvent('toggleViewMode', { viewMode });\n }\n\n undo() {\n this.postEvent('undo');\n }\n\n undoToStep(targetStep: number) {\n this.postEvent('undoToStep', { targetStep });\n }\n\n redo() {\n this.postEvent('redo');\n }\n\n save() {\n return this.promisedIframeMethod<SaveParams>('saveAction');\n }\n\n exit() {\n return this.promisedIframeMethod<ExitParams>('exitAction');\n }\n\n exportContent() {\n return this.promisedIframeMethod<SaveParams>('exportContent');\n }\n\n exportAsFile() {\n return this.promisedIframeMethod<ExportAsFileParams>('exportAsFile');\n }\n}\n","import { PluginInstance } from './plugin';\nimport { PluginConfig } from './types';\nimport { version } from '../package.json';\n\nconst DEFAULT_CONFIG: Partial<PluginConfig> = {\n container: '#draft-plugin-container',\n disableHotkeysPassing: false,\n locale: 'ru',\n on: {},\n};\n\nclass PluginWrapper {\n public version = version;\n\n create(config: PluginConfig) {\n return new PluginInstance({\n ...DEFAULT_CONFIG,\n ...config,\n });\n }\n}\n\nconst DraftPlugin = new PluginWrapper();\n\ndeclare global {\n interface Window {\n DraftPlugin: PluginWrapper;\n }\n}\n\nwindow.DraftPlugin = DraftPlugin;\n\nexport default DraftPlugin;\nexport type { PluginInstance } from './plugin';\nexport * from './types';\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.iife.js","names":[],"sources":["../src/routes.ts","../src/types.ts","../src/utils.ts","../package.json","../src/plugin.ts","../src/index.ts"],"sourcesContent":["export const LOCAL_ENDPOINT = 'http://localhost:5174';\nexport const PROD_ENDPOINT = 'https://seplugin.sendsay.ru';\n","export enum EditorMenu {\n Audit = 'audit',\n Guide = 'guide',\n Style = 'style',\n Blocks = 'blocks',\n}\n\nexport enum ViewMode {\n Desktop = 'desktop',\n Mobile = 'mobile',\n}\n\nexport interface Notification {\n intent: 'error' | 'info' | 'success' | 'warning';\n errorDetails?: object;\n message?: string;\n title: string;\n}\n\ntype PersonalizationDictionaryEntry =\n | { name: string; value: string }\n | { groupName: string; items: Array<{ name: string; value: string }> };\n\nexport type PersonalizationDictionaryItems = PersonalizationDictionaryEntry[];\n\nexport type SectionPersonalizationValue = string | number | boolean | null;\n\nexport interface SectionPersonalizationField {\n id: string;\n operatorId: 'equals';\n}\n\nexport interface SectionPersonalizationCatalogOption {\n label: string;\n value: Exclude<SectionPersonalizationValue, null>;\n}\n\nexport interface SectionPersonalizationCatalogGroup {\n type: 'group';\n id: string;\n label: string;\n children: SectionPersonalizationCatalogNode[];\n}\n\nexport interface SectionPersonalizationCatalogField {\n type: 'field';\n id: string;\n label: string;\n valueType?: 'string' | 'number' | 'boolean' | 'date';\n options?: SectionPersonalizationCatalogOption[];\n}\n\nexport type SectionPersonalizationCatalogNode =\n | SectionPersonalizationCatalogGroup\n | SectionPersonalizationCatalogField;\n\nexport interface SectionPersonalizationConfig {\n enabled: boolean;\n aboutUrl?: string;\n}\n\nexport interface RenderSectionPersonalizationGroupInput {\n groupId: string;\n fields: SectionPersonalizationField[];\n variants: Array<{\n id: string;\n values: Record<string, SectionPersonalizationValue>;\n html: string;\n }>;\n fallback?: {\n id: string;\n html: string;\n };\n}\n\nexport interface SerializedTemplate {\n [key: string]: unknown;\n parentId: string | null;\n id: string;\n parameters: object;\n layer: string;\n type: string;\n children?: SerializedTemplate[];\n meta?: { [key: string]: unknown; version: string };\n}\n\nexport type EventHandler<T> = (data: T) => void;\n\nexport type AsyncEventHandler<P, R> = (params: P) => Promise<R>;\n\nexport class DraftError extends Error {\n public readonly code: string;\n\n constructor(code: string, message: string) {\n super(message);\n this.name = 'DraftError';\n this.code = code;\n }\n}\n\nexport type MessageData = {\n source: string;\n event: string;\n ok?: boolean;\n code?: string;\n message?: string;\n action?: string;\n requestId?: string;\n};\n\nexport interface ExportAsFileParams {\n blob: Blob;\n fileName: string;\n}\n\nexport interface SaveParams {\n json: TemplateJSON;\n html: string;\n}\n\nexport type OnInitParams = MessageEvent<{\n source: string;\n event: 'loaded' | unknown;\n}>;\n\nexport interface ReadyParams extends SaveParams {\n lastSavedTemplate?: {\n template: TemplateJSON;\n date: Date;\n };\n}\n\nexport interface ErrorParams {\n message: string;\n code?: string;\n details?: unknown;\n}\n\nexport interface ExitParams extends SaveParams {}\n\nexport type NotificationParams = Notification;\n\nexport interface OpenGalleryParams {\n id: string;\n}\n\nexport interface UploadImageParams {\n file: string;\n name: string;\n}\n\nexport interface ImageParams {\n url: string;\n originalWidth: number;\n originalHeight: number;\n ratio: number;\n fileSize: number;\n}\n\nexport interface AutosaveParams {\n json: TemplateJSON;\n}\n\ninterface ToggleParams {\n state: boolean;\n}\n\nexport interface ToggleGridParams extends ToggleParams {}\n\nexport interface ToggleInvisibleCharactersParams extends ToggleParams {}\n\nexport interface TogglePreviewParams extends ToggleParams {\n json: TemplateJSON;\n html: string;\n darkHTML: string;\n}\n\nexport interface ToggleViewModeParams {\n mode: ViewMode;\n}\n\nexport interface ToggleMenuParams {\n menu: EditorMenu | null;\n}\n\nexport interface HistoryParams {\n hasUndos: boolean;\n hasRedos: boolean;\n currentStep: number;\n}\n\nexport type TemplateJSON = SerializedTemplate;\n\nexport type PersonalizationDictionary = PersonalizationDictionaryItems;\n\nexport type ToolbarActionName =\n | 'duplicate'\n | 'destroy'\n | 'edit'\n | 'up'\n | 'down';\nexport type HotkeyContext = 'hotkey';\nexport type OverlayContext = 'overlay-click' | 'overlay-double-click';\nexport type ToolbarContext = 'toolbar';\nexport type UnitSettingsContext = 'unit-settings';\nexport type BlockType = 'system' | 'user';\nexport type DndDragContext = 'canvas' | 'list' | 'palette';\nexport type DndDropContext = 'dropline' | 'placeholder' | 'empty-placeholder';\nexport type DndDropTarget = 'root' | 'section' | 'column' | 'element';\n\nexport interface DuplicateEvent {\n name: 'duplicate';\n context: HotkeyContext | ToolbarContext | UnitSettingsContext;\n unitType: string;\n}\n\nexport interface DestroyEvent {\n name: 'destroy';\n context: HotkeyContext | ToolbarContext | UnitSettingsContext;\n unitType: string;\n}\n\nexport interface EditEvent {\n name: 'edit';\n context: OverlayContext | ToolbarContext;\n unitType: string;\n}\n\nexport interface HistoryEvent {\n name: 'history';\n type: 'undo' | 'redo';\n context: HotkeyContext;\n}\n\nexport interface PreviewEvent {\n name: 'preview';\n context: HotkeyContext;\n}\n\nexport interface ToolbarMoveEvent {\n name: 'up' | 'down';\n context: ToolbarContext;\n unitType: string;\n}\n\nexport interface BlockInsertEvent {\n name: 'block-insert';\n context: 'double-click';\n blockType: BlockType;\n blockName: string;\n blockCategory: string | number;\n blockId: string | number;\n}\n\nexport interface BlockSaveEvent {\n name: 'block-save';\n blockType: 'user';\n blockName: string;\n blockCategory: string | number;\n blockId: string | number;\n elements: Record<string, number> & { sum: number };\n}\n\nexport interface BlockDestroyEvent {\n name: 'block-destroy';\n}\n\nexport interface DropEventDragMeta {\n context?: DndDragContext;\n layer?: 'element' | 'section' | 'column' | 'root';\n type?: string | string[];\n blockCategory?: string | number;\n blockId?: string | number;\n blockName?: string;\n blockType?: BlockType;\n alt?: boolean;\n dropKind?: 'create' | 'move';\n}\n\nexport interface DropEventDropzoneMeta {\n context?: DndDropContext;\n dropTarget?: DndDropTarget;\n}\n\nexport interface DropEvent {\n name: 'drop';\n drag?: DropEventDragMeta;\n dropzone?: DropEventDropzoneMeta;\n}\n\nexport type AnalyticsParams =\n | DuplicateEvent\n | DestroyEvent\n | EditEvent\n | HistoryEvent\n | PreviewEvent\n | ToolbarMoveEvent\n | BlockInsertEvent\n | BlockSaveEvent\n | BlockDestroyEvent\n | DropEvent;\n\nexport interface Handlers {\n ready: EventHandler<ReadyParams>;\n error: EventHandler<ErrorParams>;\n save: EventHandler<SaveParams>;\n exit: EventHandler<ExitParams>;\n notification: EventHandler<NotificationParams>;\n autosave: EventHandler<AutosaveParams>;\n toggleGrid: EventHandler<ToggleGridParams>;\n toggleInvisibleCharacters: EventHandler<ToggleInvisibleCharactersParams>;\n togglePreview: EventHandler<TogglePreviewParams>;\n toggleViewMode: EventHandler<ToggleViewModeParams>;\n toggleMenu: EventHandler<ToggleMenuParams>;\n history: EventHandler<HistoryParams>;\n analytics: EventHandler<AnalyticsParams>;\n openGallery: EventHandler<(url?: string) => Promise<void>>;\n uploadImage: AsyncEventHandler<UploadImageParams, string>;\n loadPersonalization: AsyncEventHandler<void, PersonalizationDictionary>;\n loadSectionPersonalizationCatalog: AsyncEventHandler<\n void,\n SectionPersonalizationCatalogNode[]\n >;\n renderSectionPersonalizationGroup: AsyncEventHandler<\n RenderSectionPersonalizationGroupInput,\n string\n >;\n}\n\nexport type HandlerParams<H> = H extends\n | EventHandler<infer P>\n | AsyncEventHandler<infer P, unknown>\n ? P\n : never;\n\nexport interface PluginConfig {\n container: string;\n locale?: string;\n autosave?:\n | boolean\n | {\n interval: number;\n };\n token: string;\n authData?: {\n orgId: number;\n projectId?: number;\n };\n pluginId: string;\n apiUrl: string;\n disableHotkeysPassing?: boolean;\n sectionPersonalization?: SectionPersonalizationConfig;\n __config?: object;\n on: Partial<Handlers>;\n}\n","import { ImageParams } from './types';\n\nconst getImageFileSize = async (imageUrl: string) => {\n try {\n const response = await fetch(imageUrl, { method: 'HEAD' });\n\n if (!response.ok) {\n return null;\n }\n\n const contentLength = response.headers.get('Content-Length');\n\n if (contentLength) {\n return parseInt(contentLength, 10);\n } else {\n return null;\n }\n } catch (error) {\n return null;\n }\n};\n\nexport const getImageParamsFromFileUrl = (imgSrc: string) =>\n new Promise<Omit<ImageParams, 'url'>>((resolve, reject) => {\n const img = new Image();\n\n img.onload = async () => {\n const fileSize = (await getImageFileSize(imgSrc)) ?? 0;\n\n resolve({\n originalWidth: img.width,\n originalHeight: img.height,\n ratio: img.width / img.height,\n fileSize,\n });\n };\n\n img.onerror = (error) => {\n reject(error);\n };\n\n img.src = imgSrc;\n });\n\nconst getLatinKey = (key: string, code: string) => {\n if (key.length !== 1) {\n return key;\n }\n\n const capitalHetaCode = 880;\n const isNonLatin = key.charCodeAt(0) >= capitalHetaCode;\n\n if (isNonLatin) {\n if (code.indexOf('Key') === 0 && code.length === 4) {\n return code.charAt(3);\n }\n\n if (code.indexOf('Digit') === 0 && code.length === 6) {\n return code.charAt(5);\n }\n }\n\n return key;\n};\n\nexport const constructKeyCode = (event: KeyboardEvent) => {\n let keyCode =\n `${getLatinKey(event.key, event.code)}`.toLowerCase() || event.key;\n const macOs = navigator.userAgent.includes('Mac OS');\n\n if (keyCode === 'backspace' && macOs) {\n keyCode = 'delete';\n }\n\n const prefix = [];\n\n if ((macOs && event.metaKey) || (!macOs && event.ctrlKey)) {\n prefix.push('mod');\n }\n\n if (event.shiftKey) {\n prefix.push('shift');\n }\n\n if (prefix.length > 0) {\n keyCode = `${prefix.join('-')}-${getLatinKey(keyCode, event.code)}`;\n }\n\n return keyCode;\n};\n\nexport const CORE_HOTKEYS = new Set([\n 'escape',\n 'mod-c',\n 'mod-d',\n 'mod-z',\n 'mod-y',\n 'mod-shift-z',\n 'mod-v',\n 'delete',\n 'mod-g',\n 'mod-p',\n 'mod-s',\n]);\n","{\n \"name\": \"@getdraft/plugin\",\n \"version\": \"1.19.0-alpha.0\",\n \"main\": \"dist/index.cjs.js\",\n \"module\": \"dist/index.es.js\",\n \"types\": \"dist/types/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/types/index.d.ts\",\n \"import\": \"./dist/index.es.js\",\n \"require\": \"./dist/index.cjs.js\"\n }\n },\n \"scripts\": {\n \"prebuild\": \"rm -rf dist\",\n \"build\": \"vite build\",\n \"dev-tsc\": \"tsc-check\",\n \"eslint\": \"npx eslint src\",\n \"eslint:fix\": \"pnpm eslint --fix\",\n \"prettify\": \"npx prettier --check src\",\n \"prettify:fix\": \"npx prettier -w src\",\n \"prepublish\": \"pnpm build\",\n \"watch\": \"NODE_ENV=development vite build --watch\",\n \"start\": \"NODE_ENV=development npx vite\"\n },\n \"dependencies\": {},\n \"devDependencies\": {\n \"@getdraft/types\": \"workspace:^\",\n \"@getdraft/eslint-config-ts\": \"workspace:^\",\n \"@getdraft/prettier\": \"workspace:^\",\n \"vite-plugin-dts\": \"4.5.4\"\n },\n \"license\": \"MIT\"\n}\n","import { LOCAL_ENDPOINT, PROD_ENDPOINT } from './routes';\nimport {\n DraftError,\n EditorMenu,\n ExitParams,\n OnInitParams,\n OpenGalleryParams,\n Handlers,\n PluginConfig,\n SaveParams,\n TemplateJSON,\n UploadImageParams,\n ViewMode,\n HandlerParams,\n MessageData,\n ExportAsFileParams,\n RenderSectionPersonalizationGroupInput,\n} from './types';\nimport {\n getImageParamsFromFileUrl,\n constructKeyCode,\n CORE_HOTKEYS,\n} from './utils';\nimport pkg from '../package.json';\n\nconst UNKNOWN_ERROR_MESSAGE = 'Unknown error';\n\nconst getDeployLink = () => {\n const regex = new RegExp(`(^| )seplugin-dev=([^;]+)`);\n const match = document.cookie.match(regex);\n const value = match?.[2].toLowerCase?.();\n\n if (value === 'true') {\n return LOCAL_ENDPOINT;\n }\n\n if (value?.startsWith('https://')) {\n return value;\n }\n\n const [major, mid] = pkg.version.split('.');\n\n return `${PROD_ENDPOINT}/v${major}.${mid}`;\n};\n\nconst verifyConfig = ({ token, pluginId, apiUrl }: PluginConfig) => {\n if (!token) {\n throw new Error('No [token] was provided');\n }\n\n if (!pluginId) {\n throw new Error('No [pluginId] was provided');\n }\n\n if (!apiUrl) {\n throw new Error('No [apiUrl] was provided');\n }\n};\n\nconst createIframe = (parentOrigin: string) => {\n const iframe = document.createElement('iframe');\n const url = new URL(getDeployLink());\n url.searchParams.set('parentOrigin', parentOrigin);\n iframe.src = url.toString();\n iframe.setAttribute(\n 'style',\n 'height:100%;width:100%;min-width:960px;border:0px;',\n );\n iframe.setAttribute('allow', 'clipboard-read; clipboard-write');\n iframe.setAttribute(\n 'sandbox',\n 'allow-scripts allow-same-origin allow-forms allow-popups allow-downloads',\n );\n\n return iframe;\n};\n\nexport class PluginInstance {\n public iframe: HTMLIFrameElement | null = null;\n private hotkeysAttached = false;\n private iframeOrigin: string | null = null;\n constructor(public config: PluginConfig) {}\n\n private captureHotkeysEnabled() {\n return this.config.disableHotkeysPassing !== true;\n }\n\n private onHostHotkey = (event: KeyboardEvent) => {\n if (!this.captureHotkeysEnabled() || !this.iframe?.contentWindow) {\n return;\n }\n\n const keyCode = constructKeyCode(event);\n\n if (!CORE_HOTKEYS.has(keyCode)) {\n return;\n }\n\n const target = event.target as HTMLElement | null;\n\n if (\n target &&\n (target.isContentEditable ||\n ['INPUT', 'TEXTAREA', 'SELECT'].includes(target.tagName))\n ) {\n return;\n }\n\n event.preventDefault();\n\n const { key, ctrlKey, metaKey, shiftKey, altKey } = event;\n\n this.postEvent('hostHotkey', {\n key,\n code: event.code,\n metaKey,\n ctrlKey,\n shiftKey,\n altKey,\n keyCode,\n });\n };\n\n private static HEARTBEAT_TIMEOUT = 4000;\n\n private promisedIframeMethod<T>(eventName: string) {\n let timer: Timeout | null = null;\n let listener: ((e: MessageEvent<MessageData>) => void) | null = null;\n\n const cleanup = () => {\n if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n\n if (listener) {\n window.removeEventListener('message', listener, true);\n listener = null;\n }\n };\n\n const res = new Promise<T>((resolve, reject) => {\n const resetTimer = () => {\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => {\n cleanup();\n reject(\n new DraftError('timeout_error', `Action \"${eventName}\" timed out`),\n );\n }, PluginInstance.HEARTBEAT_TIMEOUT);\n };\n\n listener = (e: MessageEvent<MessageData>) => {\n if (e.source !== this.iframe?.contentWindow) return;\n\n const { data } = e;\n if (data.source !== 'DraftPlugin') return;\n\n if (data.event === 'actionPing' && data.action === eventName) {\n e.stopPropagation();\n resetTimer();\n\n return;\n }\n\n if (data.event === eventName) {\n e.stopPropagation();\n cleanup();\n\n const { source: _1, event: _2, ok, code, message, ...rest } = data;\n\n if (ok === false) {\n reject(\n new DraftError(\n code || 'unknown_error',\n message || UNKNOWN_ERROR_MESSAGE,\n ),\n );\n } else {\n resolve(rest as T);\n }\n }\n };\n\n window.addEventListener('message', listener, true);\n resetTimer();\n });\n\n this.postEvent(eventName);\n\n return res;\n }\n\n private postEvent(event: string, data: object = {}) {\n if (this.iframe && this.iframe.contentWindow && this.iframeOrigin) {\n this.iframe.contentWindow.postMessage(\n {\n ...data,\n event,\n source: 'DraftPlugin',\n },\n this.iframeOrigin,\n );\n } else if (!this.iframeOrigin) {\n throw new Error('Iframe origin is not initialized');\n }\n }\n\n private onImageUpload = async ({\n id,\n ...data\n }: UploadImageParams & { id: string }) => {\n try {\n const url = await this.config.on.uploadImage?.(data);\n let params = {};\n\n if (url) {\n params = await getImageParamsFromFileUrl(url);\n }\n\n this.postEvent('imageUploaded', { id, img: { ...params, url } });\n } catch (e) {\n this.postEvent('imageUploaded', { id });\n }\n };\n\n private onLoadPersonalization = async (requestId?: string) => {\n try {\n if (!this.config.on.loadPersonalization) {\n throw new Error('No personalization loader provided');\n }\n\n const personalizationDictionary =\n await this.config.on.loadPersonalization();\n\n this.postEvent('loadPersonalization', {\n items: personalizationDictionary,\n requestId,\n });\n } catch (e) {\n this.postEvent('loadPersonalization', { requestId });\n }\n };\n\n private onLoadSectionPersonalizationCatalog = async (requestId?: string) => {\n try {\n const handler = this.config.on.loadSectionPersonalizationCatalog;\n\n if (!handler) {\n throw new Error('No section personalization catalog loader provided');\n }\n\n const catalog = await handler();\n\n this.postEvent('loadSectionPersonalizationCatalog', {\n ok: true,\n requestId,\n catalog,\n });\n } catch (error) {\n this.postEvent('loadSectionPersonalizationCatalog', {\n ok: false,\n requestId,\n message: error instanceof Error ? error.message : UNKNOWN_ERROR_MESSAGE,\n });\n }\n };\n\n private onRenderSectionPersonalizationGroup = async (\n data: RenderSectionPersonalizationGroupInput & { requestId?: string },\n ) => {\n const { requestId, ...input } = data;\n\n try {\n const handler = this.config.on.renderSectionPersonalizationGroup;\n\n if (!handler) {\n throw new Error('No section personalization renderer provided');\n }\n\n const renderedHtml = await handler(input);\n\n this.postEvent('renderSectionPersonalizationGroup', {\n ok: true,\n requestId,\n html: renderedHtml,\n });\n } catch (error) {\n this.postEvent('renderSectionPersonalizationGroup', {\n ok: false,\n requestId,\n message: error instanceof Error ? error.message : UNKNOWN_ERROR_MESSAGE,\n });\n }\n };\n\n private onGalleryOpen = async ({ id }: { id: string }) => {\n const applyImage = async (url?: string) => {\n const imgParams = { url };\n\n if (url) {\n const params = await getImageParamsFromFileUrl(url);\n Object.assign(imgParams, params);\n }\n\n this.postEvent('imageUploaded', {\n id,\n img: imgParams,\n });\n };\n\n this.config.on.openGallery?.(applyImage);\n };\n\n private triggerEvent<H extends CallableFunction | undefined>(\n handler: H,\n params: HandlerParams<H>,\n ) {\n if (!handler) {\n return;\n }\n\n return handler(params);\n }\n\n private onMessage = (\n ev: MessageEvent<{ source: string; event: keyof Handlers }>,\n ) => {\n if (ev.source !== this.iframe?.contentWindow) {\n return;\n }\n\n const {\n data: { source, event, ...data },\n } = ev;\n\n if (source === 'DraftPlugin') {\n if (event === 'openGallery') {\n this.onGalleryOpen(data as OpenGalleryParams);\n } else if (event === 'uploadImage') {\n this.onImageUpload(data as UploadImageParams & { id: string });\n } else if (event === 'loadPersonalization') {\n this.onLoadPersonalization((data as { requestId?: string }).requestId);\n } else if (event === 'loadSectionPersonalizationCatalog') {\n this.onLoadSectionPersonalizationCatalog(\n (data as { requestId?: string }).requestId,\n );\n } else if (event === 'renderSectionPersonalizationGroup') {\n this.onRenderSectionPersonalizationGroup(\n data as RenderSectionPersonalizationGroupInput & {\n requestId?: string;\n },\n );\n } else {\n this.triggerEvent(\n this.config.on[event],\n data as HandlerParams<Handlers[typeof event]>,\n );\n }\n }\n };\n\n start({\n template,\n templateName,\n uid,\n }: {\n template: string | TemplateJSON;\n uid: string | number;\n templateName?: string;\n }) {\n const containerEl = document.querySelector(this.config.container);\n\n if (!containerEl) {\n throw new Error('Specified container not found');\n } else {\n const onInit = (msg: OnInitParams) => {\n const {\n data: { source, event },\n } = msg;\n if (source === 'DraftPlugin' && event === 'loaded') {\n if (msg.source !== this.iframe?.contentWindow) return;\n\n this.iframeOrigin = msg.origin;\n\n const {\n on,\n container,\n locale,\n autosave,\n token,\n apiUrl,\n pluginId,\n authData,\n sectionPersonalization,\n __config,\n } = this.config;\n\n verifyConfig(this.config);\n\n if (this.iframe && this.iframe.contentWindow) {\n const resolvedSectionPersonalization = {\n ...sectionPersonalization,\n enabled:\n sectionPersonalization?.enabled === true &&\n !!on.loadSectionPersonalizationCatalog &&\n !!on.renderSectionPersonalizationGroup,\n };\n\n this.postEvent('init', {\n container,\n locale,\n uid,\n autosave,\n token,\n pluginId,\n authData,\n sectionPersonalization: resolvedSectionPersonalization,\n apiUrl,\n __config,\n enabledListeners: Object.keys(on),\n template,\n templateName,\n });\n }\n\n window.addEventListener('message', this.onMessage);\n window.removeEventListener('message', onInit);\n }\n };\n\n this.iframe = createIframe(window.location.origin);\n window.addEventListener('message', onInit);\n containerEl.appendChild(this.iframe);\n\n if (this.captureHotkeysEnabled() && !this.hotkeysAttached) {\n window.addEventListener('keydown', this.onHostHotkey);\n this.hotkeysAttached = true;\n }\n }\n }\n\n destroy = () => {\n this.iframe?.remove();\n this.iframe = null;\n window.removeEventListener('message', this.onMessage);\n\n if (this.hotkeysAttached) {\n window.removeEventListener('keydown', this.onHostHotkey);\n this.hotkeysAttached = false;\n }\n };\n\n changeTemplate(\n template: string | TemplateJSON,\n options: {\n templateName?: string;\n uid?: string;\n } = {},\n ) {\n this.postEvent('changeTemplate', { ...options, template });\n }\n\n toggleGrid(state?: boolean) {\n this.postEvent('toggleGrid', { state });\n }\n\n toggleInvisibleCharacters(state?: boolean) {\n this.postEvent('toggleInvisibleCharacters', { state });\n }\n\n async isInvisibleCharactersVisible() {\n const { state } = await this.promisedIframeMethod<{ state: boolean }>(\n 'getInvisibleCharactersVisibility',\n );\n\n return state;\n }\n\n togglePreview(state?: boolean) {\n this.postEvent('togglePreview', { state });\n }\n\n toggleMenu(menu: EditorMenu | null = null) {\n this.postEvent('toggleMenu', { menu });\n }\n\n toggleViewMode(viewMode: ViewMode) {\n this.postEvent('toggleViewMode', { viewMode });\n }\n\n undo() {\n this.postEvent('undo');\n }\n\n undoToStep(targetStep: number) {\n this.postEvent('undoToStep', { targetStep });\n }\n\n redo() {\n this.postEvent('redo');\n }\n\n save() {\n return this.promisedIframeMethod<SaveParams>('saveAction');\n }\n\n exit() {\n return this.promisedIframeMethod<ExitParams>('exitAction');\n }\n\n exportContent() {\n return this.promisedIframeMethod<SaveParams>('exportContent');\n }\n\n exportAsFile() {\n return this.promisedIframeMethod<ExportAsFileParams>('exportAsFile');\n }\n}\n","import { PluginInstance } from './plugin';\nimport { PluginConfig } from './types';\nimport { version } from '../package.json';\n\nconst DEFAULT_CONFIG: Partial<PluginConfig> = {\n container: '#draft-plugin-container',\n disableHotkeysPassing: false,\n locale: 'ru',\n on: {},\n};\n\nclass PluginWrapper {\n public version = version;\n\n create(config: PluginConfig) {\n return new PluginInstance({\n ...DEFAULT_CONFIG,\n ...config,\n });\n }\n}\n\nconst DraftPlugin = new PluginWrapper();\n\ndeclare global {\n interface Window {\n DraftPlugin: PluginWrapper;\n }\n}\n\nwindow.DraftPlugin = DraftPlugin;\n\nexport default DraftPlugin;\nexport type { PluginInstance } from './plugin';\nexport * from './types';\n"],"mappings":"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"}
@@ -129,6 +129,8 @@ export declare interface Handlers {
129
129
  openGallery: EventHandler<(url?: string) => Promise<void>>;
130
130
  uploadImage: AsyncEventHandler<UploadImageParams, string>;
131
131
  loadPersonalization: AsyncEventHandler<void, PersonalizationDictionary>;
132
+ loadSectionPersonalizationCatalog: AsyncEventHandler<void, SectionPersonalizationCatalogNode[]>;
133
+ renderSectionPersonalizationGroup: AsyncEventHandler<RenderSectionPersonalizationGroupInput, string>;
132
134
  }
133
135
 
134
136
  export declare interface HistoryEvent {
@@ -160,6 +162,7 @@ export declare type MessageData = {
160
162
  code?: string;
161
163
  message?: string;
162
164
  action?: string;
165
+ requestId?: string;
163
166
  };
164
167
 
165
168
  declare interface Notification_2 {
@@ -212,6 +215,7 @@ export declare interface PluginConfig {
212
215
  pluginId: string;
213
216
  apiUrl: string;
214
217
  disableHotkeysPassing?: boolean;
218
+ sectionPersonalization?: SectionPersonalizationConfig;
215
219
  __config?: object;
216
220
  on: Partial<Handlers>;
217
221
  }
@@ -229,6 +233,8 @@ export declare class PluginInstance {
229
233
  private postEvent;
230
234
  private onImageUpload;
231
235
  private onLoadPersonalization;
236
+ private onLoadSectionPersonalizationCatalog;
237
+ private onRenderSectionPersonalizationGroup;
232
238
  private onGalleryOpen;
233
239
  private triggerEvent;
234
240
  private onMessage;
@@ -274,11 +280,59 @@ export declare interface ReadyParams extends SaveParams {
274
280
  };
275
281
  }
276
282
 
283
+ export declare interface RenderSectionPersonalizationGroupInput {
284
+ groupId: string;
285
+ fields: SectionPersonalizationField[];
286
+ variants: Array<{
287
+ id: string;
288
+ values: Record<string, SectionPersonalizationValue>;
289
+ html: string;
290
+ }>;
291
+ fallback?: {
292
+ id: string;
293
+ html: string;
294
+ };
295
+ }
296
+
277
297
  export declare interface SaveParams {
278
298
  json: TemplateJSON;
279
299
  html: string;
280
300
  }
281
301
 
302
+ export declare interface SectionPersonalizationCatalogField {
303
+ type: 'field';
304
+ id: string;
305
+ label: string;
306
+ valueType?: 'string' | 'number' | 'boolean' | 'date';
307
+ options?: SectionPersonalizationCatalogOption[];
308
+ }
309
+
310
+ export declare interface SectionPersonalizationCatalogGroup {
311
+ type: 'group';
312
+ id: string;
313
+ label: string;
314
+ children: SectionPersonalizationCatalogNode[];
315
+ }
316
+
317
+ export declare type SectionPersonalizationCatalogNode = SectionPersonalizationCatalogGroup | SectionPersonalizationCatalogField;
318
+
319
+ export declare interface SectionPersonalizationCatalogOption {
320
+ label: string;
321
+ value: Exclude<SectionPersonalizationValue, null>;
322
+ }
323
+
324
+ export declare interface SectionPersonalizationConfig {
325
+ enabled: boolean;
326
+ aboutUrl?: string;
327
+ }
328
+
329
+ export declare interface SectionPersonalizationField {
330
+ id: string;
331
+ operatorId: 'equals';
332
+ }
333
+
334
+ export declare type SectionPersonalizationValue = string | number | boolean | null;
335
+
282
336
  export declare interface SerializedTemplate {
283
337
  [key: string]: unknown;
284
338
  parentId: string | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getdraft/plugin",
3
- "version": "1.17.5",
3
+ "version": "1.19.0-alpha.0",
4
4
  "main": "dist/index.cjs.js",
5
5
  "module": "dist/index.es.js",
6
6
  "types": "dist/types/index.d.ts",
@@ -11,6 +11,14 @@
11
11
  "require": "./dist/index.cjs.js"
12
12
  }
13
13
  },
14
+ "dependencies": {},
15
+ "devDependencies": {
16
+ "vite-plugin-dts": "4.5.4",
17
+ "@getdraft/types": "^1.0.0",
18
+ "@getdraft/prettier": "^1.0.0",
19
+ "@getdraft/eslint-config-ts": "^1.0.0"
20
+ },
21
+ "license": "MIT",
14
22
  "scripts": {
15
23
  "prebuild": "rm -rf dist",
16
24
  "build": "vite build",
@@ -22,13 +30,5 @@
22
30
  "prepublish": "pnpm build",
23
31
  "watch": "NODE_ENV=development vite build --watch",
24
32
  "start": "NODE_ENV=development npx vite"
25
- },
26
- "dependencies": {},
27
- "devDependencies": {
28
- "@getdraft/types": "workspace:^",
29
- "@getdraft/eslint-config-ts": "workspace:^",
30
- "@getdraft/prettier": "workspace:^",
31
- "vite-plugin-dts": "4.5.4"
32
- },
33
- "license": "MIT"
34
- }
33
+ }
34
+ }
package/src/plugin.ts CHANGED
@@ -14,6 +14,7 @@ import {
14
14
  HandlerParams,
15
15
  MessageData,
16
16
  ExportAsFileParams,
17
+ RenderSectionPersonalizationGroupInput,
17
18
  } from './types';
18
19
  import {
19
20
  getImageParamsFromFileUrl,
@@ -22,6 +23,8 @@ import {
22
23
  } from './utils';
23
24
  import pkg from '../package.json';
24
25
 
26
+ const UNKNOWN_ERROR_MESSAGE = 'Unknown error';
27
+
25
28
  const getDeployLink = () => {
26
29
  const regex = new RegExp(`(^| )seplugin-dev=([^;]+)`);
27
30
  const match = document.cookie.match(regex);
@@ -170,7 +173,7 @@ export class PluginInstance {
170
173
  reject(
171
174
  new DraftError(
172
175
  code || 'unknown_error',
173
- message || 'Unknown error',
176
+ message || UNKNOWN_ERROR_MESSAGE,
174
177
  ),
175
178
  );
176
179
  } else {
@@ -221,7 +224,7 @@ export class PluginInstance {
221
224
  }
222
225
  };
223
226
 
224
- private onLoadPersonalization = async () => {
227
+ private onLoadPersonalization = async (requestId?: string) => {
225
228
  try {
226
229
  if (!this.config.on.loadPersonalization) {
227
230
  throw new Error('No personalization loader provided');
@@ -232,9 +235,62 @@ export class PluginInstance {
232
235
 
233
236
  this.postEvent('loadPersonalization', {
234
237
  items: personalizationDictionary,
238
+ requestId,
235
239
  });
236
240
  } catch (e) {
237
- this.postEvent('loadPersonalization', {});
241
+ this.postEvent('loadPersonalization', { requestId });
242
+ }
243
+ };
244
+
245
+ private onLoadSectionPersonalizationCatalog = async (requestId?: string) => {
246
+ try {
247
+ const handler = this.config.on.loadSectionPersonalizationCatalog;
248
+
249
+ if (!handler) {
250
+ throw new Error('No section personalization catalog loader provided');
251
+ }
252
+
253
+ const catalog = await handler();
254
+
255
+ this.postEvent('loadSectionPersonalizationCatalog', {
256
+ ok: true,
257
+ requestId,
258
+ catalog,
259
+ });
260
+ } catch (error) {
261
+ this.postEvent('loadSectionPersonalizationCatalog', {
262
+ ok: false,
263
+ requestId,
264
+ message: error instanceof Error ? error.message : UNKNOWN_ERROR_MESSAGE,
265
+ });
266
+ }
267
+ };
268
+
269
+ private onRenderSectionPersonalizationGroup = async (
270
+ data: RenderSectionPersonalizationGroupInput & { requestId?: string },
271
+ ) => {
272
+ const { requestId, ...input } = data;
273
+
274
+ try {
275
+ const handler = this.config.on.renderSectionPersonalizationGroup;
276
+
277
+ if (!handler) {
278
+ throw new Error('No section personalization renderer provided');
279
+ }
280
+
281
+ const renderedHtml = await handler(input);
282
+
283
+ this.postEvent('renderSectionPersonalizationGroup', {
284
+ ok: true,
285
+ requestId,
286
+ html: renderedHtml,
287
+ });
288
+ } catch (error) {
289
+ this.postEvent('renderSectionPersonalizationGroup', {
290
+ ok: false,
291
+ requestId,
292
+ message: error instanceof Error ? error.message : UNKNOWN_ERROR_MESSAGE,
293
+ });
238
294
  }
239
295
  };
240
296
 
@@ -284,7 +340,17 @@ export class PluginInstance {
284
340
  } else if (event === 'uploadImage') {
285
341
  this.onImageUpload(data as UploadImageParams & { id: string });
286
342
  } else if (event === 'loadPersonalization') {
287
- this.onLoadPersonalization();
343
+ this.onLoadPersonalization((data as { requestId?: string }).requestId);
344
+ } else if (event === 'loadSectionPersonalizationCatalog') {
345
+ this.onLoadSectionPersonalizationCatalog(
346
+ (data as { requestId?: string }).requestId,
347
+ );
348
+ } else if (event === 'renderSectionPersonalizationGroup') {
349
+ this.onRenderSectionPersonalizationGroup(
350
+ data as RenderSectionPersonalizationGroupInput & {
351
+ requestId?: string;
352
+ },
353
+ );
288
354
  } else {
289
355
  this.triggerEvent(
290
356
  this.config.on[event],
@@ -326,12 +392,21 @@ export class PluginInstance {
326
392
  apiUrl,
327
393
  pluginId,
328
394
  authData,
395
+ sectionPersonalization,
329
396
  __config,
330
397
  } = this.config;
331
398
 
332
399
  verifyConfig(this.config);
333
400
 
334
401
  if (this.iframe && this.iframe.contentWindow) {
402
+ const resolvedSectionPersonalization = {
403
+ ...sectionPersonalization,
404
+ enabled:
405
+ sectionPersonalization?.enabled === true &&
406
+ !!on.loadSectionPersonalizationCatalog &&
407
+ !!on.renderSectionPersonalizationGroup,
408
+ };
409
+
335
410
  this.postEvent('init', {
336
411
  container,
337
412
  locale,
@@ -340,6 +415,7 @@ export class PluginInstance {
340
415
  token,
341
416
  pluginId,
342
417
  authData,
418
+ sectionPersonalization: resolvedSectionPersonalization,
343
419
  apiUrl,
344
420
  __config,
345
421
  enabledListeners: Object.keys(on),