@getdraft/plugin 1.16.1 → 1.17.5

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.
package/README.md CHANGED
@@ -25,7 +25,7 @@ yarn add @draft-email/plugin --exact
25
25
  Подключите плагин напрямую через CDN:
26
26
 
27
27
  ```html
28
- <script src="https://eimage.sendsay.ru/app/se/draft/plugin-v1.14.js"></script>
28
+ <script src="https://eimage.sendsay.ru/app/se/draft/plugin-v1.17.js"></script>
29
29
  ```
30
30
 
31
31
  ## Инициализация
@@ -166,6 +166,7 @@ draft.start({
166
166
  | `save` | Произошло сохранение<br>_(Вызывается, в случае если используется внутренняя шапка редактора)_ | <code>{<br>&nbsp;json: TemplateJSON;<br>&nbsp;}</code> |
167
167
  | `exit` | Попытка выхода из редактора<br>_(Вызывается, в случае если используется внутренняя шапка редактора)_ | <code>{<br>&nbsp;json: TemplateJSON;<br>&nbsp;}</code> |
168
168
  | `toggleGrid` | Включена подсветка сетки | <code>{<br>&nbsp;state: boolean;<br>&nbsp;}</code> |
169
+ | `toggleInvisibleCharacters` | Включено отображение служебных символов | <code>{<br>&nbsp;state: boolean;<br>&nbsp;}</code> |
169
170
  | `togglePreview` | Включен предпросмотр | <code>{<br>&nbsp;state: boolean;<br>&nbsp;json: TemplateJSON;<br>&nbsp;html: string;<br>&nbsp;darkHTML: string;<br>&nbsp;}</code> |
170
171
  | `toggleMenu` | Включено меню | <code>{<br>&nbsp;menu: [EditorMenu](#EditorMenu) \| null;<br>&nbsp;}</code> |
171
172
  | `history` | Добавлено изменение/Произошло перемещение по истории | <code>{<br>&nbsp;hasUndos: boolean;<br>&nbsp;hasRedos: boolean;<br>&nbsp;type: 'change'\|'undo'\|'redo'<br>&nbsp;}</code> |
@@ -224,6 +225,24 @@ Id элемента в котором будет развернут iframe с р
224
225
  ) => void
225
226
  ```
226
227
 
228
+ ### `toggleInvisibleCharacters` - переключить отображение служебных символов
229
+
230
+ Вызывает ивент `toggleInvisibleCharacters`
231
+
232
+ ```typescript
233
+ (
234
+ state?: boolean, // Состояние отображения служебных символов. Если значение отсутствует, то выставляется противоположное текущему
235
+ ) => void
236
+ ```
237
+
238
+ ### `isInvisibleCharactersVisible` - проверить отображение служебных символов
239
+
240
+ Возвращает текущее состояние отображения служебных символов.
241
+
242
+ ```typescript
243
+ () => Promise<boolean>
244
+ ```
245
+
227
246
  ### `togglePreview` - Переключить отображение предпросмотра
228
247
 
229
248
  Вызывает ивент `togglePreview`
package/dist/index.cjs.js CHANGED
@@ -1,2 +1,2 @@
1
- Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});var e=`http://localhost:5174`,t=`https://seplugin.sendsay.ru`,n=function(e){return e.Audit=`audit`,e.Guide=`guide`,e.Style=`style`,e.Blocks=`blocks`,e}({}),r=function(e){return e.Desktop=`desktop`,e.Mobile=`mobile`,e}({}),i=class extends Error{code;constructor(e,t){super(t),this.name=`DraftError`,this.code=e}},a=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}},o=e=>new Promise((t,n)=>{let r=new Image;r.onload=async()=>{let n=await a(e)??0;t({originalWidth:r.width,originalHeight:r.height,ratio:r.width/r.height,fileSize:n})},r.onerror=e=>{n(e)},r.src=e}),s=(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},c=e=>{let t=`${s(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(`-`)}-${s(t,e.code)}`),t},l=new Set([`escape`,`mod-c`,`mod-d`,`mod-z`,`mod-y`,`mod-shift-z`,`mod-v`,`delete`,`mod-g`,`mod-p`,`mod-s`]),u=`@getdraft/plugin`,d=`1.16.1`,f={name:u,version:d,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 -w ./`,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`},p=()=>{let n=RegExp(`(^| )seplugin-dev=([^;]+)`),r=document.cookie.match(n)?.[2].toLowerCase?.();if(r===`true`)return e;if(r?.startsWith(`https://`))return r;let[i,a]=f.version.split(`.`);return`${t}/v${i}.${a}`},m=({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`)},h=e=>{let t=document.createElement(`iframe`),n=new URL(p());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},g=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=c(e);if(!l.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,a=()=>{n&&=(clearTimeout(n),null),r&&=(window.removeEventListener(`message`,r,!0),null)},o=new Promise((o,s)=>{let c=()=>{n&&clearTimeout(n),n=setTimeout(()=>{a(),s(new i(`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(),a();let{source:t,event:r,ok:c,code:l,message:u,...d}=n;c===!1?s(new i(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 o(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 o(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;m(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=h(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})}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`)}redo(){this.postEvent(`redo`)}save(){return this.promisedIframeMethod(`saveAction`)}exit(){return this.promisedIframeMethod(`exitAction`)}exportContent(){return this.promisedIframeMethod(`exportContent`)}exportAsFile(){return this.promisedIframeMethod(`exportAsFile`)}},_={container:`#draft-plugin-container`,disableHotkeysPassing:!1,locale:`ru`,on:{}},v=new class{version=d;create(e){return new g({..._,...e})}};window.DraftPlugin=v,exports.DraftError=i,exports.EditorMenu=n,exports.ViewMode=r,exports.default=v;
1
+ Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});var e=`http://localhost:5174`,t=`https://seplugin.sendsay.ru`,n=function(e){return e.Audit=`audit`,e.Guide=`guide`,e.Style=`style`,e.Blocks=`blocks`,e}({}),r=function(e){return e.Desktop=`desktop`,e.Mobile=`mobile`,e}({}),i=class extends Error{code;constructor(e,t){super(t),this.name=`DraftError`,this.code=e}},a=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}},o=e=>new Promise((t,n)=>{let r=new Image;r.onload=async()=>{let n=await a(e)??0;t({originalWidth:r.width,originalHeight:r.height,ratio:r.width/r.height,fileSize:n})},r.onerror=e=>{n(e)},r.src=e}),s=(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},c=e=>{let t=`${s(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(`-`)}-${s(t,e.code)}`),t},l=new Set([`escape`,`mod-c`,`mod-d`,`mod-z`,`mod-y`,`mod-shift-z`,`mod-v`,`delete`,`mod-g`,`mod-p`,`mod-s`]),u=`@getdraft/plugin`,d=`1.17.5`,f={name:u,version:d,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`},p=()=>{let n=RegExp(`(^| )seplugin-dev=([^;]+)`),r=document.cookie.match(n)?.[2].toLowerCase?.();if(r===`true`)return e;if(r?.startsWith(`https://`))return r;let[i,a]=f.version.split(`.`);return`${t}/v${i}.${a}`},m=({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`)},h=e=>{let t=document.createElement(`iframe`),n=new URL(p());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},g=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=c(e);if(!l.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,a=()=>{n&&=(clearTimeout(n),null),r&&=(window.removeEventListener(`message`,r,!0),null)},o=new Promise((o,s)=>{let c=()=>{n&&clearTimeout(n),n=setTimeout(()=>{a(),s(new i(`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(),a();let{source:t,event:r,ok:c,code:l,message:u,...d}=n;c===!1?s(new i(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 o(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 o(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;m(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=h(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`)}},_={container:`#draft-plugin-container`,disableHotkeysPassing:!1,locale:`ru`,on:{}},v=new class{version=d;create(e){return new g({..._,...e})}};window.DraftPlugin=v,exports.DraftError=i,exports.EditorMenu=n,exports.ViewMode=r,exports.default=v;
2
2
  //# sourceMappingURL=index.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.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 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 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.16.1\",\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 -w ./\",\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 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 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.cjs.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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"}
package/dist/index.es.js CHANGED
@@ -54,7 +54,7 @@ var e = "http://localhost:5174", t = "https://seplugin.sendsay.ru", n = /* @__PU
54
54
  "mod-g",
55
55
  "mod-p",
56
56
  "mod-s"
57
- ]), u = "@getdraft/plugin", d = "1.16.1", f = {
57
+ ]), u = "@getdraft/plugin", d = "1.17.5", f = {
58
58
  name: u,
59
59
  version: d,
60
60
  main: "dist/index.cjs.js",
@@ -71,7 +71,8 @@ var e = "http://localhost:5174", t = "https://seplugin.sendsay.ru", n = /* @__PU
71
71
  "dev-tsc": "tsc-check",
72
72
  eslint: "npx eslint src",
73
73
  "eslint:fix": "pnpm eslint --fix",
74
- prettify: "npx prettier -w ./",
74
+ prettify: "npx prettier --check src",
75
+ "prettify:fix": "npx prettier -w src",
75
76
  prepublish: "pnpm build",
76
77
  watch: "NODE_ENV=development vite build --watch",
77
78
  start: "NODE_ENV=development npx vite"
@@ -249,6 +250,13 @@ var e = "http://localhost:5174", t = "https://seplugin.sendsay.ru", n = /* @__PU
249
250
  toggleGrid(e) {
250
251
  this.postEvent("toggleGrid", { state: e });
251
252
  }
253
+ toggleInvisibleCharacters(e) {
254
+ this.postEvent("toggleInvisibleCharacters", { state: e });
255
+ }
256
+ async isInvisibleCharactersVisible() {
257
+ let { state: e } = await this.promisedIframeMethod("getInvisibleCharactersVisibility");
258
+ return e;
259
+ }
252
260
  togglePreview(e) {
253
261
  this.postEvent("togglePreview", { state: e });
254
262
  }
@@ -261,6 +269,9 @@ var e = "http://localhost:5174", t = "https://seplugin.sendsay.ru", n = /* @__PU
261
269
  undo() {
262
270
  this.postEvent("undo");
263
271
  }
272
+ undoToStep(e) {
273
+ this.postEvent("undoToStep", { targetStep: e });
274
+ }
264
275
  redo() {
265
276
  this.postEvent("redo");
266
277
  }
@@ -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 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 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.16.1\",\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 -w ./\",\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 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 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,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,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;;GCpalE,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 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,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.16.1`,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 -w ./`,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})}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`)}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.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})({});
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 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 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.16.1\",\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 -w ./\",\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 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 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 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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"}