panda-cms 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (233) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +73 -0
  3. data/Rakefile +7 -0
  4. data/app/assets/builds/panda.cms.css +2808 -0
  5. data/app/assets/config/panda_cms_manifest.js +4 -0
  6. data/app/assets/stylesheets/panda/cms/application.tailwind.css +162 -0
  7. data/app/assets/stylesheets/panda/cms/editor.css +120 -0
  8. data/app/builders/panda/cms/form_builder.rb +234 -0
  9. data/app/components/panda/cms/admin/button_component.rb +70 -0
  10. data/app/components/panda/cms/admin/container_component.html.erb +13 -0
  11. data/app/components/panda/cms/admin/container_component.rb +13 -0
  12. data/app/components/panda/cms/admin/flash_message_component.html.erb +31 -0
  13. data/app/components/panda/cms/admin/flash_message_component.rb +47 -0
  14. data/app/components/panda/cms/admin/heading_component.rb +45 -0
  15. data/app/components/panda/cms/admin/panel_component.html.erb +7 -0
  16. data/app/components/panda/cms/admin/panel_component.rb +13 -0
  17. data/app/components/panda/cms/admin/slideover_component.html.erb +9 -0
  18. data/app/components/panda/cms/admin/slideover_component.rb +15 -0
  19. data/app/components/panda/cms/admin/statistics_component.html.erb +4 -0
  20. data/app/components/panda/cms/admin/statistics_component.rb +17 -0
  21. data/app/components/panda/cms/admin/tab_bar_component.html.erb +35 -0
  22. data/app/components/panda/cms/admin/tab_bar_component.rb +15 -0
  23. data/app/components/panda/cms/admin/table_component.html.erb +29 -0
  24. data/app/components/panda/cms/admin/table_component.rb +46 -0
  25. data/app/components/panda/cms/admin/tag_component.rb +35 -0
  26. data/app/components/panda/cms/admin/user_activity_component.html.erb +5 -0
  27. data/app/components/panda/cms/admin/user_activity_component.rb +33 -0
  28. data/app/components/panda/cms/admin/user_display_component.html.erb +17 -0
  29. data/app/components/panda/cms/admin/user_display_component.rb +21 -0
  30. data/app/components/panda/cms/code_component.rb +64 -0
  31. data/app/components/panda/cms/grid_component.html.erb +6 -0
  32. data/app/components/panda/cms/grid_component.rb +15 -0
  33. data/app/components/panda/cms/menu_component.html.erb +6 -0
  34. data/app/components/panda/cms/menu_component.rb +58 -0
  35. data/app/components/panda/cms/page_menu_component.html.erb +21 -0
  36. data/app/components/panda/cms/page_menu_component.rb +38 -0
  37. data/app/components/panda/cms/rich_text_component.html.erb +6 -0
  38. data/app/components/panda/cms/rich_text_component.rb +84 -0
  39. data/app/components/panda/cms/text_component.rb +72 -0
  40. data/app/constraints/panda/cms/admin_constraint.rb +18 -0
  41. data/app/controllers/panda/cms/admin/block_contents_controller.rb +52 -0
  42. data/app/controllers/panda/cms/admin/dashboard_controller.rb +20 -0
  43. data/app/controllers/panda/cms/admin/files_controller.rb +21 -0
  44. data/app/controllers/panda/cms/admin/forms_controller.rb +53 -0
  45. data/app/controllers/panda/cms/admin/menus_controller.rb +30 -0
  46. data/app/controllers/panda/cms/admin/pages_controller.rb +91 -0
  47. data/app/controllers/panda/cms/admin/posts_controller.rb +146 -0
  48. data/app/controllers/panda/cms/admin/sessions_controller.rb +94 -0
  49. data/app/controllers/panda/cms/admin/settings/bulk_editor_controller.rb +37 -0
  50. data/app/controllers/panda/cms/admin/settings_controller.rb +20 -0
  51. data/app/controllers/panda/cms/application_controller.rb +57 -0
  52. data/app/controllers/panda/cms/errors_controller.rb +33 -0
  53. data/app/controllers/panda/cms/form_submissions_controller.rb +23 -0
  54. data/app/controllers/panda/cms/pages_controller.rb +72 -0
  55. data/app/controllers/panda/cms/posts_controller.rb +13 -0
  56. data/app/helpers/panda/cms/admin/files_helper.rb +6 -0
  57. data/app/helpers/panda/cms/admin/pages_helper.rb +6 -0
  58. data/app/helpers/panda/cms/admin/posts_helper.rb +48 -0
  59. data/app/helpers/panda/cms/application_helper.rb +120 -0
  60. data/app/helpers/panda/cms/pages_helper.rb +6 -0
  61. data/app/helpers/panda/cms/theme_helper.rb +18 -0
  62. data/app/javascript/panda/cms/@editorjs--editorjs.js +2577 -0
  63. data/app/javascript/panda/cms/@hotwired--stimulus.js +4 -0
  64. data/app/javascript/panda/cms/@hotwired--turbo.js +160 -0
  65. data/app/javascript/panda/cms/@rails--actioncable--src.js +4 -0
  66. data/app/javascript/panda/cms/application_panda_cms.js +39 -0
  67. data/app/javascript/panda/cms/controllers/dashboard_controller.js +7 -0
  68. data/app/javascript/panda/cms/controllers/editor_form_controller.js +77 -0
  69. data/app/javascript/panda/cms/controllers/editor_iframe_controller.js +320 -0
  70. data/app/javascript/panda/cms/controllers/index.js +48 -0
  71. data/app/javascript/panda/cms/controllers/slug_controller.js +87 -0
  72. data/app/javascript/panda/cms/editor/css_extractor.js +80 -0
  73. data/app/javascript/panda/cms/editor/editor_js_config.js +177 -0
  74. data/app/javascript/panda/cms/editor/editor_js_initializer.js +285 -0
  75. data/app/javascript/panda/cms/editor/plain_text_editor.js +110 -0
  76. data/app/javascript/panda/cms/editor/resource_loader.js +115 -0
  77. data/app/javascript/panda/cms/tailwindcss-stimulus-components.js +4 -0
  78. data/app/jobs/panda/cms/application_job.rb +6 -0
  79. data/app/jobs/panda/cms/record_visit_job.rb +31 -0
  80. data/app/mailers/panda/cms/application_mailer.rb +8 -0
  81. data/app/mailers/panda/cms/form_mailer.rb +21 -0
  82. data/app/models/action_text/rich_text_version.rb +6 -0
  83. data/app/models/panda/cms/application_record.rb +7 -0
  84. data/app/models/panda/cms/block.rb +34 -0
  85. data/app/models/panda/cms/block_content.rb +18 -0
  86. data/app/models/panda/cms/block_content_version.rb +8 -0
  87. data/app/models/panda/cms/breadcrumb.rb +12 -0
  88. data/app/models/panda/cms/current.rb +17 -0
  89. data/app/models/panda/cms/form.rb +9 -0
  90. data/app/models/panda/cms/form_submission.rb +7 -0
  91. data/app/models/panda/cms/menu.rb +52 -0
  92. data/app/models/panda/cms/menu_item.rb +58 -0
  93. data/app/models/panda/cms/page.rb +96 -0
  94. data/app/models/panda/cms/page_version.rb +8 -0
  95. data/app/models/panda/cms/post.rb +60 -0
  96. data/app/models/panda/cms/post_version.rb +8 -0
  97. data/app/models/panda/cms/redirect.rb +11 -0
  98. data/app/models/panda/cms/template.rb +124 -0
  99. data/app/models/panda/cms/template_version.rb +8 -0
  100. data/app/models/panda/cms/user.rb +31 -0
  101. data/app/models/panda/cms/version.rb +8 -0
  102. data/app/models/panda/cms/visit.rb +9 -0
  103. data/app/services/panda/cms/html_to_editor_js_converter.rb +200 -0
  104. data/app/views/active_storage/blobs/blobs/_blob.html.erb +14 -0
  105. data/app/views/layouts/action_text/contents/_content.html.erb +3 -0
  106. data/app/views/layouts/panda/cms/application.html.erb +41 -0
  107. data/app/views/layouts/panda/cms/public.html.erb +3 -0
  108. data/app/views/panda/cms/admin/dashboard/show.html.erb +12 -0
  109. data/app/views/panda/cms/admin/files/index.html.erb +124 -0
  110. data/app/views/panda/cms/admin/files/show.html.erb +2 -0
  111. data/app/views/panda/cms/admin/forms/edit.html.erb +0 -0
  112. data/app/views/panda/cms/admin/forms/index.html.erb +13 -0
  113. data/app/views/panda/cms/admin/forms/new.html.erb +15 -0
  114. data/app/views/panda/cms/admin/forms/show.html.erb +35 -0
  115. data/app/views/panda/cms/admin/menus/index.html.erb +8 -0
  116. data/app/views/panda/cms/admin/pages/edit.html.erb +36 -0
  117. data/app/views/panda/cms/admin/pages/index.html.erb +22 -0
  118. data/app/views/panda/cms/admin/pages/new.html.erb +15 -0
  119. data/app/views/panda/cms/admin/pages/show.html.erb +1 -0
  120. data/app/views/panda/cms/admin/posts/_form.html.erb +29 -0
  121. data/app/views/panda/cms/admin/posts/edit.html.erb +6 -0
  122. data/app/views/panda/cms/admin/posts/index.html.erb +18 -0
  123. data/app/views/panda/cms/admin/posts/new.html.erb +6 -0
  124. data/app/views/panda/cms/admin/sessions/new.html.erb +17 -0
  125. data/app/views/panda/cms/admin/settings/bulk_editor/new.html.erb +68 -0
  126. data/app/views/panda/cms/admin/settings/index.html.erb +21 -0
  127. data/app/views/panda/cms/admin/settings/insta.html +4 -0
  128. data/app/views/panda/cms/admin/shared/_breadcrumbs.html.erb +28 -0
  129. data/app/views/panda/cms/admin/shared/_flash.html.erb +5 -0
  130. data/app/views/panda/cms/admin/shared/_sidebar.html.erb +41 -0
  131. data/app/views/panda/cms/form_mailer/notification_email.html.erb +11 -0
  132. data/app/views/panda/cms/shared/_editor.html.erb +0 -0
  133. data/app/views/panda/cms/shared/_favicons.html.erb +9 -0
  134. data/app/views/panda/cms/shared/_footer.html.erb +2 -0
  135. data/app/views/panda/cms/shared/_header.html.erb +15 -0
  136. data/app/views/panda/cms/shared/_importmap.html.erb +33 -0
  137. data/config/importmap.rb +13 -0
  138. data/config/initializers/inflections.rb +3 -0
  139. data/config/initializers/panda/cms/form_errors.rb +38 -0
  140. data/config/initializers/panda/cms/healthcheck_log_silencer.rb +11 -0
  141. data/config/initializers/panda/cms/paper_trail.rb +7 -0
  142. data/config/initializers/panda/cms.rb +10 -0
  143. data/config/initializers/zeitwork.rb +3 -0
  144. data/config/locales/en.yml +49 -0
  145. data/config/puma/test.rb +9 -0
  146. data/config/routes.rb +48 -0
  147. data/config/tailwind.config.js +37 -0
  148. data/db/migrate/20240205223709_create_panda_cms_pages.rb +9 -0
  149. data/db/migrate/20240219213327_create_panda_cms_page_versions.rb +14 -0
  150. data/db/migrate/20240303002805_create_panda_cms_templates.rb +11 -0
  151. data/db/migrate/20240303003434_create_panda_cms_template_versions.rb +14 -0
  152. data/db/migrate/20240303022441_create_panda_cms_blocks.rb +13 -0
  153. data/db/migrate/20240303024256_create_panda_cms_block_contents.rb +10 -0
  154. data/db/migrate/20240303024746_create_panda_cms_block_content_versions.rb +14 -0
  155. data/db/migrate/20240303233238_add_panda_cms_menu_table.rb +10 -0
  156. data/db/migrate/20240303234724_add_panda_cms_menu_item_table.rb +12 -0
  157. data/db/migrate/20240304134343_add_parent_id_to_panda_cms_pages.rb +5 -0
  158. data/db/migrate/20240305000000_convert_html_content_to_editor_js.rb +82 -0
  159. data/db/migrate/20240315125411_add_status_to_panda_cms_pages.rb +9 -0
  160. data/db/migrate/20240315125421_add_nested_sets_to_panda_cms_pages.rb +16 -0
  161. data/db/migrate/20240316212822_add_kind_to_panda_cms_menus.rb +6 -0
  162. data/db/migrate/20240316221425_add_start_page_to_panda_cms_menus.rb +5 -0
  163. data/db/migrate/20240316230706_add_nested_to_panda_cms_menu_items.rb +24 -0
  164. data/db/migrate/20240317010532_create_panda_cms_users.rb +12 -0
  165. data/db/migrate/20240317161534_add_max_uses_to_panda_cms_template.rb +7 -0
  166. data/db/migrate/20240317163053_reset_counter_cache_on_panda_cms_template.rb +5 -0
  167. data/db/migrate/20240317214827_create_panda_cms_redirects.rb +14 -0
  168. data/db/migrate/20240317230622_create_panda_cms_visits.rb +13 -0
  169. data/db/migrate/20240324205703_create_active_storage_tables.active_storage.rb +58 -0
  170. data/db/migrate/20240408084718_default_panda_cms_users_admin_to_false.rb +5 -0
  171. data/db/migrate/20240701225422_add_service_name_to_active_storage_blobs.active_storage.rb +22 -0
  172. data/db/migrate/20240701225423_create_active_storage_variant_records.active_storage.rb +28 -0
  173. data/db/migrate/20240701225424_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb +8 -0
  174. data/db/migrate/20240804235210_create_panda_cms_forms.rb +11 -0
  175. data/db/migrate/20240805013612_create_panda_cms_form_submissions.rb +9 -0
  176. data/db/migrate/20240805121123_create_panda_cms_posts.rb +27 -0
  177. data/db/migrate/20240805123104_create_panda_cms_post_versions.rb +14 -0
  178. data/db/migrate/20240806112735_fix_panda_cms_visits_column_names.rb +13 -0
  179. data/db/migrate/20240806204412_add_completion_path_to_panda_cms_forms.rb +5 -0
  180. data/db/migrate/20240820081917_change_form_submissions_to_submission_count.rb +5 -0
  181. data/db/migrate/20240904200605_create_action_text_tables.action_text.rb +24 -0
  182. data/db/migrate/20240923234535_add_depth_to_panda_cms_menus.rb +11 -0
  183. data/db/migrate/20241031205109_add_cached_content_to_panda_cms_block_contents.rb +5 -0
  184. data/db/migrate/20241119214548_convert_post_content_to_editor_js.rb +35 -0
  185. data/db/migrate/20241119214549_remove_action_text_from_posts.rb +9 -0
  186. data/db/migrate/20241120000419_remove_post_tag_references.rb +19 -0
  187. data/db/migrate/20241120110943_add_editor_js_to_posts.rb +27 -0
  188. data/db/migrate/20241120113859_add_cached_content_to_panda_cms_posts.rb +5 -0
  189. data/db/migrate/20241123234140_remove_post_tag_id_from_posts.rb +5 -0
  190. data/db/migrate/migrate +1 -0
  191. data/db/seeds.rb +5 -0
  192. data/lib/generators/panda/cms/install_generator.rb +29 -0
  193. data/lib/panda/cms/bulk_editor.rb +171 -0
  194. data/lib/panda/cms/demo_site_generator.rb +67 -0
  195. data/lib/panda/cms/editor_js/blocks/alert.rb +34 -0
  196. data/lib/panda/cms/editor_js/blocks/base.rb +33 -0
  197. data/lib/panda/cms/editor_js/blocks/header.rb +15 -0
  198. data/lib/panda/cms/editor_js/blocks/image.rb +36 -0
  199. data/lib/panda/cms/editor_js/blocks/list.rb +32 -0
  200. data/lib/panda/cms/editor_js/blocks/paragraph.rb +15 -0
  201. data/lib/panda/cms/editor_js/blocks/quote.rb +41 -0
  202. data/lib/panda/cms/editor_js/blocks/table.rb +50 -0
  203. data/lib/panda/cms/editor_js/renderer.rb +124 -0
  204. data/lib/panda/cms/editor_js.rb +16 -0
  205. data/lib/panda/cms/editor_js_content.rb +21 -0
  206. data/lib/panda/cms/engine.rb +257 -0
  207. data/lib/panda/cms/exceptions_app.rb +26 -0
  208. data/lib/panda/cms/railtie.rb +11 -0
  209. data/lib/panda/cms/slug.rb +24 -0
  210. data/lib/panda/cms.rb +0 -0
  211. data/lib/panda-cms/version.rb +5 -0
  212. data/lib/panda-cms.rb +81 -0
  213. data/lib/tasks/panda_cms.rake +54 -0
  214. data/lib/templates/erb/scaffold/_form.html.erb.tt +43 -0
  215. data/lib/templates/erb/scaffold/edit.html.erb.tt +8 -0
  216. data/lib/templates/erb/scaffold/index.html.erb.tt +14 -0
  217. data/lib/templates/erb/scaffold/new.html.erb.tt +7 -0
  218. data/lib/templates/erb/scaffold/partial.html.erb.tt +22 -0
  219. data/lib/templates/erb/scaffold/show.html.erb.tt +15 -0
  220. data/public/panda-cms-assets/favicons/android-chrome-192x192.png +0 -0
  221. data/public/panda-cms-assets/favicons/android-chrome-512x512.png +0 -0
  222. data/public/panda-cms-assets/favicons/apple-touch-icon.png +0 -0
  223. data/public/panda-cms-assets/favicons/browserconfig.xml +9 -0
  224. data/public/panda-cms-assets/favicons/favicon-16x16.png +0 -0
  225. data/public/panda-cms-assets/favicons/favicon-32x32.png +0 -0
  226. data/public/panda-cms-assets/favicons/favicon.ico +0 -0
  227. data/public/panda-cms-assets/favicons/mstile-150x150.png +0 -0
  228. data/public/panda-cms-assets/favicons/safari-pinned-tab.svg +61 -0
  229. data/public/panda-cms-assets/favicons/site.webmanifest +14 -0
  230. data/public/panda-cms-assets/panda-logo-screenprint.png +0 -0
  231. data/public/panda-cms-assets/panda-nav.png +0 -0
  232. data/public/panda-cms-assets/rich_text_editor.css +568 -0
  233. metadata +654 -0
@@ -0,0 +1,2577 @@
1
+ // @editorjs/editorjs@2.30.6 downloaded from https://ga.jspm.io/npm:@editorjs/editorjs@2.30.6/dist/editorjs.mjs
2
+
3
+ (function(){try{if(typeof document<"u"){var n=document.createElement("style");n.appendChild(document.createTextNode(".ce-hint--align-start{text-align:left}.ce-hint--align-center{text-align:center}.ce-hint__description{opacity:.6;margin-top:3px}")),document.head.appendChild(n)}}catch(n){console.error("vite-plugin-css-injected-by-js",n)}})();typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"&&self;function Fe(n){return n&&n.__esModule&&Object.prototype.hasOwnProperty.call(n,"default")?n.default:n}function ze(){}Object.assign(ze,{default:ze,register:ze,revert:function(){},__esModule:!0});Element.prototype.matches||(Element.prototype.matches=Element.prototype.matchesSelector||Element.prototype.mozMatchesSelector||Element.prototype.msMatchesSelector||Element.prototype.oMatchesSelector||Element.prototype.webkitMatchesSelector||function(n){const h=(this.document||this.ownerDocument).querySelectorAll(n);let p=h.length;for(;--p>=0&&h.item(p)!==this;);return p>-1});Element.prototype.closest||(Element.prototype.closest=function(n){let h=this;if(!document.documentElement.contains(h))return null;do{if(h.matches(n))return h;h=h.parentElement||h.parentNode}while(h!==null);return null});Element.prototype.prepend||(Element.prototype.prepend=function(n){const h=document.createDocumentFragment();Array.isArray(n)||(n=[n]),n.forEach((n=>{const p=n instanceof Node;h.appendChild(p?n:document.createTextNode(n))})),this.insertBefore(h,this.firstChild)});Element.prototype.scrollIntoViewIfNeeded||(Element.prototype.scrollIntoViewIfNeeded=function(n){n=arguments.length===0||!!n;const h=this.parentNode,p=window.getComputedStyle(h,null),g=parseInt(p.getPropertyValue("border-top-width")),m=parseInt(p.getPropertyValue("border-left-width")),v=this.offsetTop-h.offsetTop<h.scrollTop,x=this.offsetTop-h.offsetTop+this.clientHeight-g>h.scrollTop+h.clientHeight,w=this.offsetLeft-h.offsetLeft<h.scrollLeft,E=this.offsetLeft-h.offsetLeft+this.clientWidth-m>h.scrollLeft+h.clientWidth,B=v&&!x;(v||x)&&n&&(h.scrollTop=this.offsetTop-h.offsetTop-h.clientHeight/2-g+this.clientHeight/2),(w||E)&&n&&(h.scrollLeft=this.offsetLeft-h.offsetLeft-h.clientWidth/2-m+this.clientWidth/2),(v||x||w||E)&&!n&&this.scrollIntoView(B)});window.requestIdleCallback=window.requestIdleCallback||function(n){const h=Date.now();return setTimeout((function(){n({didTimeout:!1,timeRemaining:function(){return Math.max(0,50-(Date.now()-h))}})}),1)};window.cancelIdleCallback=window.cancelIdleCallback||function(n){clearTimeout(n)};let vo=(n=21)=>crypto.getRandomValues(new Uint8Array(n)).reduce(((n,h)=>(h&=63,n+=h<36?h.toString(36):h<62?(h-26).toString(36).toUpperCase():h>62?"-":"_",n)),"");var n=(n=>(n.VERBOSE="VERBOSE",n.INFO="INFO",n.WARN="WARN",n.ERROR="ERROR",n))(n||{});const h={BACKSPACE:8,TAB:9,ENTER:13,SHIFT:16,CTRL:17,ALT:18,ESC:27,SPACE:32,LEFT:37,UP:38,DOWN:40,RIGHT:39,DELETE:46,META:91,SLASH:191},p={LEFT:0,WHEEL:1,RIGHT:2,BACKWARD:3,FORWARD:4};function Be(n,h,p="log",g,m="color: inherit"){if(!("console"in window)||!window.console[p])return;const v=["info","log","warn","error"].includes(p),x=[];switch(Be.logLevel){case"ERROR":if(p!=="error")return;break;case"WARN":if(!["error","warn"].includes(p))return;break;case"INFO":if(!v||n)return;break}g&&x.push(g);const w="Editor.js 2.30.6",E="line-height: 1em;\n color: #006FEA;\n display: inline-block;\n font-size: 11px;\n line-height: 1em;\n background-color: #fff;\n padding: 4px 9px;\n border-radius: 30px;\n border: 1px solid rgba(56, 138, 229, 0.16);\n margin: 4px 5px 4px 0;";n&&(v?(x.unshift(E,m),h=`%c${w}%c ${h}`):h=`( ${w} )${h}`);try{v?g?console[p](`${h} %o`,...x):console[p](h,...x):console[p](h)}catch{}}Be.logLevel="VERBOSE";function xo(n){Be.logLevel=n}const g=Be.bind(window,!1),m=Be.bind(window,!0);function re(n){return Object.prototype.toString.call(n).match(/\s([a-zA-Z]+)/)[1].toLowerCase()}function O(n){return re(n)==="function"||re(n)==="asyncfunction"}function R(n){return re(n)==="object"}function Q(n){return re(n)==="string"}function yo(n){return re(n)==="boolean"}function bt(n){return re(n)==="number"}function kt(n){return re(n)==="undefined"}function V(n){return!n||Object.keys(n).length===0&&n.constructor===Object}function Mt(n){return n>47&&n<58||n===32||n===13||n===229||n>64&&n<91||n>95&&n<112||n>185&&n<193||n>218&&n<223}async function Eo(n,h=(()=>{}),p=(()=>{})){async function o(n,h,p){try{await n.function(n.data),await h(kt(n.data)?{}:n.data)}catch{p(kt(n.data)?{}:n.data)}}return n.reduce((async(n,g)=>(await n,o(g,h,p))),Promise.resolve())}function At(n){return Array.prototype.slice.call(n)}function Oe(n,h){return function(){const p=this,g=arguments;window.setTimeout((()=>n.apply(p,g)),h)}}function Bo(n){return n.name.split(".").pop()}function To(n){return/^[-\w]+\/([-+\w]+|\*)$/.test(n)}function vt(n,h,p){let g;return(...m)=>{const v=this,r=()=>{g=null,p||n.apply(v,m)},x=p&&!g;window.clearTimeout(g),g=window.setTimeout(r,h),x&&n.apply(v,m)}}function Ve(n,h,p=void 0){let g,m,v,x=null,w=0;p||(p={});const a=function(){w=p.leading===!1?0:Date.now(),x=null,v=n.apply(g,m),x||(g=m=null)};return function(){const E=Date.now();!w&&p.leading===!1&&(w=E);const B=h-(E-w);return g=this,m=arguments,B<=0||B>h?(x&&(clearTimeout(x),x=null),w=E,v=n.apply(g,m),x||(g=m=null)):!x&&p.trailing!==!1&&(x=setTimeout(a,B)),v}}function Co(){const n={win:!1,mac:!1,x11:!1,linux:!1},h=Object.keys(n).find((n=>window.navigator.appVersion.toLowerCase().indexOf(n)!==-1));return h&&(n[h]=!0),n}function Le(n){return n[0].toUpperCase()+n.slice(1)}function qe(n,...h){if(!h.length)return n;const p=h.shift();if(R(n)&&R(p))for(const h in p)R(p[h])?(n[h]||Object.assign(n,{[h]:{}}),qe(n[h],p[h])):Object.assign(n,{[h]:p[h]});return qe(n,...h)}function tt(n){const h=Co();return n=n.replace(/shift/gi,"⇧").replace(/backspace/gi,"⌫").replace(/enter/gi,"⏎").replace(/up/gi,"↑").replace(/left/gi,"→").replace(/down/gi,"↓").replace(/right/gi,"←").replace(/escape/gi,"⎋").replace(/insert/gi,"Ins").replace(/delete/gi,"␡").replace(/\+/gi," + "),n=h.mac?n.replace(/ctrl|cmd/gi,"⌘").replace(/alt/gi,"⌥"):n.replace(/cmd/gi,"Ctrl").replace(/windows/gi,"WIN"),n}function So(n){try{return new URL(n).href}catch{}return n.substring(0,2)==="//"?window.location.protocol+n:window.location.origin+n}function Io(){return vo(10)}function Mo(n){window.open(n,"_blank")}function Ao(n=""){return`${n}${Math.floor(Math.random()*1e8).toString(16)}`}function Ze(n,h,p){const g=`«${h}» is deprecated and will be removed in the next major release. Please use the «${p}» instead.`;n&&m(g,"warn")}function ue(n,h,p){const g=p.value?"value":"get",m=p[g],v=`#${h}Cache`;if(p[g]=function(...n){return this[v]===void 0&&(this[v]=m.apply(this,...n)),this[v]},g==="get"&&p.set){const h=p.set;p.set=function(p){delete n[v],h.apply(this,p)}}return p}const v=650;function pe(){return window.matchMedia(`(max-width: ${v}px)`).matches}const x=typeof window<"u"&&window.navigator&&window.navigator.platform&&(/iP(ad|hone|od)/.test(window.navigator.platform)||window.navigator.platform==="MacIntel"&&window.navigator.maxTouchPoints>1);function Oo(n,h){const p=Array.isArray(n)||R(n),g=Array.isArray(h)||R(h);return p||g?JSON.stringify(n)===JSON.stringify(h):n===h}class d{
4
+ /**
5
+ * Check if passed tag has no closed tag
6
+ *
7
+ * @param {HTMLElement} tag - element to check
8
+ * @returns {boolean}
9
+ */
10
+ static isSingleTag(n){return n.tagName&&["AREA","BASE","BR","COL","COMMAND","EMBED","HR","IMG","INPUT","KEYGEN","LINK","META","PARAM","SOURCE","TRACK","WBR"].includes(n.tagName)}
11
+ /**
12
+ * Check if element is BR or WBR
13
+ *
14
+ * @param {HTMLElement} element - element to check
15
+ * @returns {boolean}
16
+ */static isLineBreakTag(n){return n&&n.tagName&&["BR","WBR"].includes(n.tagName)}
17
+ /**
18
+ * Helper for making Elements with class name and attributes
19
+ *
20
+ * @param {string} tagName - new Element tag name
21
+ * @param {string[]|string} [classNames] - list or name of CSS class name(s)
22
+ * @param {object} [attributes] - any attributes
23
+ * @returns {HTMLElement}
24
+ */static make(n,h=null,p={}){const g=document.createElement(n);if(Array.isArray(h)){const n=h.filter((n=>n!==void 0));g.classList.add(...n)}else h&&g.classList.add(h);for(const n in p)Object.prototype.hasOwnProperty.call(p,n)&&(g[n]=p[n]);return g}
25
+ /**
26
+ * Creates Text Node with the passed content
27
+ *
28
+ * @param {string} content - text content
29
+ * @returns {Text}
30
+ */static text(n){return document.createTextNode(n)}
31
+ /**
32
+ * Append one or several elements to the parent
33
+ *
34
+ * @param {Element|DocumentFragment} parent - where to append
35
+ * @param {Element|Element[]|DocumentFragment|Text|Text[]} elements - element or elements list
36
+ */static append(n,h){Array.isArray(h)?h.forEach((h=>n.appendChild(h))):n.appendChild(h)}
37
+ /**
38
+ * Append element or a couple to the beginning of the parent elements
39
+ *
40
+ * @param {Element} parent - where to append
41
+ * @param {Element|Element[]} elements - element or elements list
42
+ */static prepend(n,h){Array.isArray(h)?(h=h.reverse(),h.forEach((h=>n.prepend(h)))):n.prepend(h)}
43
+ /**
44
+ * Swap two elements in parent
45
+ *
46
+ * @param {HTMLElement} el1 - from
47
+ * @param {HTMLElement} el2 - to
48
+ * @deprecated
49
+ */static swap(n,h){const p=document.createElement("div"),g=n.parentNode;g.insertBefore(p,n),g.insertBefore(n,h),g.insertBefore(h,p),g.removeChild(p)
50
+ /**
51
+ * Selector Decorator
52
+ *
53
+ * Returns first match
54
+ *
55
+ * @param {Element} el - element we searching inside. Default - DOM Document
56
+ * @param {string} selector - searching string
57
+ * @returns {Element}
58
+ */}static find(n=document,h){return n.querySelector(h)}
59
+ /**
60
+ * Get Element by Id
61
+ *
62
+ * @param {string} id - id to find
63
+ * @returns {HTMLElement | null}
64
+ */static get(n){return document.getElementById(n)}
65
+ /**
66
+ * Selector Decorator.
67
+ *
68
+ * Returns all matches
69
+ *
70
+ * @param {Element|Document} el - element we searching inside. Default - DOM Document
71
+ * @param {string} selector - searching string
72
+ * @returns {NodeList}
73
+ */static findAll(n=document,h){return n.querySelectorAll(h)}static get allInputsSelector(){return"[contenteditable=true], textarea, input:not([type]), "+["text","password","email","number","search","tel","url"].map((n=>`input[type="${n}"]`)).join(", ")}
74
+ /**
75
+ * Find all contenteditable, textarea and editable input elements passed holder contains
76
+ *
77
+ * @param holder - element where to find inputs
78
+ */static findAllInputs(n){return At(n.querySelectorAll(d.allInputsSelector)).reduce(((n,h)=>d.isNativeInput(h)||d.containsOnlyInlineElements(h)?[...n,h]:[...n,...d.getDeepestBlockElements(h)]),[])}
79
+ /**
80
+ * Search for deepest node which is Leaf.
81
+ * Leaf is the vertex that doesn't have any child nodes
82
+ *
83
+ * @description Method recursively goes throw the all Node until it finds the Leaf
84
+ * @param {Node} node - root Node. From this vertex we start Deep-first search
85
+ * {@link https://en.wikipedia.org/wiki/Depth-first_search}
86
+ * @param {boolean} [atLast] - find last text node
87
+ * @returns - it can be text Node or Element Node, so that caret will able to work with it
88
+ * Can return null if node is Document or DocumentFragment, or node is not attached to the DOM
89
+ */static getDeepestNode(n,h=!1){const p=h?"lastChild":"firstChild",g=h?"previousSibling":"nextSibling";if(n&&n.nodeType===Node.ELEMENT_NODE&&n[p]){let m=n[p];if(d.isSingleTag(m)&&!d.isNativeInput(m)&&!d.isLineBreakTag(m))if(m[g])m=m[g];else{if(!m.parentNode[g])return m.parentNode;m=m.parentNode[g]}return this.getDeepestNode(m,h)}return n}
90
+ /**
91
+ * Check if object is DOM node
92
+ *
93
+ * @param {*} node - object to check
94
+ * @returns {boolean}
95
+ */
96
+ static isElement(n){return!bt(n)&&(n&&n.nodeType&&n.nodeType===Node.ELEMENT_NODE)}
97
+ /**
98
+ * Check if object is DocumentFragment node
99
+ *
100
+ * @param {object} node - object to check
101
+ * @returns {boolean}
102
+ */
103
+ static isFragment(n){return!bt(n)&&(n&&n.nodeType&&n.nodeType===Node.DOCUMENT_FRAGMENT_NODE)}
104
+ /**
105
+ * Check if passed element is contenteditable
106
+ *
107
+ * @param {HTMLElement} element - html element to check
108
+ * @returns {boolean}
109
+ */static isContentEditable(n){return n.contentEditable==="true"}
110
+ /**
111
+ * Checks target if it is native input
112
+ *
113
+ * @param {*} target - HTML element or string
114
+ * @returns {boolean}
115
+ */
116
+ static isNativeInput(n){const h=["INPUT","TEXTAREA"];return!(!n||!n.tagName)&&h.includes(n.tagName)}
117
+ /**
118
+ * Checks if we can set caret
119
+ *
120
+ * @param {HTMLElement} target - target to check
121
+ * @returns {boolean}
122
+ */static canSetCaret(n){let h=!0;if(d.isNativeInput(n))switch(n.type){case"file":case"checkbox":case"radio":case"hidden":case"submit":case"button":case"image":case"reset":h=!1;break}else h=d.isContentEditable(n);return h}
123
+ /**
124
+ * Checks node if it is empty
125
+ *
126
+ * @description Method checks simple Node without any childs for emptiness
127
+ * If you have Node with 2 or more children id depth, you better use {@link Dom#isEmpty} method
128
+ * @param {Node} node - node to check
129
+ * @param {string} [ignoreChars] - char or substring to treat as empty
130
+ * @returns {boolean} true if it is empty
131
+ */static isNodeEmpty(n,h){let p;return!(this.isSingleTag(n)&&!this.isLineBreakTag(n))&&(p=this.isElement(n)&&this.isNativeInput(n)?n.value:n.textContent.replace("​",""),h&&(p=p.replace(new RegExp(h,"g"),"")),p.trim().length===0
132
+ /**
133
+ * checks node if it is doesn't have any child nodes
134
+ *
135
+ * @param {Node} node - node to check
136
+ * @returns {boolean}
137
+ */)}static isLeaf(n){return!!n&&n.childNodes.length===0}
138
+ /**
139
+ * breadth-first search (BFS)
140
+ * {@link https://en.wikipedia.org/wiki/Breadth-first_search}
141
+ *
142
+ * @description Pushes to stack all DOM leafs and checks for emptiness
143
+ * @param {Node} node - node to check
144
+ * @param {string} [ignoreChars] - char or substring to treat as empty
145
+ * @returns {boolean}
146
+ */static isEmpty(n,h){n.normalize();const p=[n];for(;p.length>0;)if(n=p.shift(),!!n){if(this.isLeaf(n)&&!this.isNodeEmpty(n,h))return!1;n.childNodes&&p.push(...Array.from(n.childNodes))}return!0}
147
+ /**
148
+ * Check if string contains html elements
149
+ *
150
+ * @param {string} str - string to check
151
+ * @returns {boolean}
152
+ */static isHTMLString(n){const h=d.make("div");return h.innerHTML=n,h.childElementCount>0
153
+ /**
154
+ * Return length of node`s text content
155
+ *
156
+ * @param {Node} node - node with content
157
+ * @returns {number}
158
+ */}static getContentLength(n){return d.isNativeInput(n)?n.value.length:n.nodeType===Node.TEXT_NODE?n.length:n.textContent.length}
159
+ /**
160
+ * Return array of names of block html elements
161
+ *
162
+ * @returns {string[]}
163
+ */static get blockElements(){return["address","article","aside","blockquote","canvas","div","dl","dt","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","hr","li","main","nav","noscript","ol","output","p","pre","ruby","section","table","tbody","thead","tr","tfoot","ul","video"]}
164
+ /**
165
+ * Check if passed content includes only inline elements
166
+ *
167
+ * @param {string|HTMLElement} data - element or html string
168
+ * @returns {boolean}
169
+ */static containsOnlyInlineElements(n){let h;Q(n)?(h=document.createElement("div"),h.innerHTML=n):h=n;const o=n=>!d.blockElements.includes(n.tagName.toLowerCase())&&Array.from(n.children).every(o);return Array.from(h.children).every(o)}
170
+ /**
171
+ * Find and return all block elements in the passed parent (including subtree)
172
+ *
173
+ * @param {HTMLElement} parent - root element
174
+ * @returns {HTMLElement[]}
175
+ */static getDeepestBlockElements(n){return d.containsOnlyInlineElements(n)?[n]:Array.from(n.children).reduce(((n,h)=>[...n,...d.getDeepestBlockElements(h)]),[])}
176
+ /**
177
+ * Helper for get holder from {string} or return HTMLElement
178
+ *
179
+ * @param {string | HTMLElement} element - holder's id or holder's HTML Element
180
+ * @returns {HTMLElement}
181
+ */static getHolder(n){return Q(n)?document.getElementById(n):n}
182
+ /**
183
+ * Returns true if element is anchor (is A tag)
184
+ *
185
+ * @param {Element} element - element to check
186
+ * @returns {boolean}
187
+ */static isAnchor(n){return n.tagName.toLowerCase()==="a"}
188
+ /**
189
+ * Return element's offset related to the document
190
+ *
191
+ * @todo handle case when editor initialized in scrollable popup
192
+ * @param el - element to compute offset
193
+ */static offset(n){const h=n.getBoundingClientRect(),p=window.pageXOffset||document.documentElement.scrollLeft,g=window.pageYOffset||document.documentElement.scrollTop,m=h.top+g,v=h.left+p;return{top:m,left:v,bottom:m+h.height,right:v+h.width}}}function Lo(n){return!/[^\t\n\r ]/.test(n)}function _o(n){const h=window.getComputedStyle(n),p=parseFloat(h.fontSize),g=parseFloat(h.lineHeight)||p*1.2,m=parseFloat(h.paddingTop),v=parseFloat(h.borderTopWidth),x=parseFloat(h.marginTop),w=p*.8,E=(g-p)/2;return x+v+m+E+w}function Lt(n){n.dataset.empty=d.isEmpty(n)?"true":"false"}const w={blockTunes:{toggler:{"Click to tune":"","or drag to move":""}},inlineToolbar:{converter:{"Convert to":""}},toolbar:{toolbox:{Add:""}},popover:{Filter:"","Nothing found":"","Convert to":""}},E={Text:"",Link:"",Bold:"",Italic:""},B={link:{"Add a link":""},stub:{"The block can not be displayed correctly.":""}},T={delete:{Delete:"","Click to delete":""},moveUp:{"Move up":""},moveDown:{"Move down":""}},I={ui:w,toolNames:E,tools:B,blockTunes:T},M=class ae{
194
+ /**
195
+ * Type-safe translation for internal UI texts:
196
+ * Perform translation of the string by namespace and a key
197
+ *
198
+ * @example I18n.ui(I18nInternalNS.ui.blockTunes.toggler, 'Click to tune')
199
+ * @param internalNamespace - path to translated string in dictionary
200
+ * @param dictKey - dictionary key. Better to use default locale original text
201
+ */
202
+ static ui(n,h){return ae._t(n,h)}
203
+ /**
204
+ * Translate for external strings that is not presented in default dictionary.
205
+ * For example, for user-specified tool names
206
+ *
207
+ * @param namespace - path to translated string in dictionary
208
+ * @param dictKey - dictionary key. Better to use default locale original text
209
+ */static t(n,h){return ae._t(n,h)}
210
+ /**
211
+ * Adjust module for using external dictionary
212
+ *
213
+ * @param dictionary - new messages list to override default
214
+ */static setDictionary(n){ae.currentDictionary=n}
215
+ /**
216
+ * Perform translation both for internal and external namespaces
217
+ * If there is no translation found, returns passed key as a translated message
218
+ *
219
+ * @param namespace - path to translated string in dictionary
220
+ * @param dictKey - dictionary key. Better to use default locale original text
221
+ */static _t(n,h){const p=ae.getNamespace(n);return p&&p[h]?p[h]:h}
222
+ /**
223
+ * Find messages section by namespace path
224
+ *
225
+ * @param namespace - path to section
226
+ */static getNamespace(n){return n.split(".").reduce(((n,h)=>n&&Object.keys(n).length?n[h]:{}),ae.currentDictionary)}};M.currentDictionary=I;let A=M;class Pt extends Error{}class Te{constructor(){this.subscribers={}}
227
+ /**
228
+ * Subscribe any event on callback
229
+ *
230
+ * @param eventName - event name
231
+ * @param callback - subscriber
232
+ */on(n,h){n in this.subscribers||(this.subscribers[n]=[]),this.subscribers[n].push(h)
233
+ /**
234
+ * Subscribe any event on callback. Callback will be called once and be removed from subscribers array after call.
235
+ *
236
+ * @param eventName - event name
237
+ * @param callback - subscriber
238
+ */}once(n,h){n in this.subscribers||(this.subscribers[n]=[]);const o=p=>{const g=h(p),m=this.subscribers[n].indexOf(o);return m!==-1&&this.subscribers[n].splice(m,1),g};this.subscribers[n].push(o)}
239
+ /**
240
+ * Emit callbacks with passed data
241
+ *
242
+ * @param eventName - event name
243
+ * @param data - subscribers get this data when they were fired
244
+ */emit(n,h){V(this.subscribers)||!this.subscribers[n]||this.subscribers[n].reduce(((n,h)=>{const p=h(n);return p!==void 0?p:n}),h)}
245
+ /**
246
+ * Unsubscribe callback from event
247
+ *
248
+ * @param eventName - event name
249
+ * @param callback - event handler
250
+ */off(n,h){if(this.subscribers[n]!==void 0){for(let p=0;p<this.subscribers[n].length;p++)if(this.subscribers[n][p]===h){delete this.subscribers[n][p];break}}else console.warn(`EventDispatcher .off(): there is no subscribers for event "${n.toString()}". Probably, .off() called before .on()`)}destroy(){this.subscribers={}}}function G(n){Object.setPrototypeOf(this,{
251
+ /**
252
+ * Block id
253
+ *
254
+ * @returns {string}
255
+ */
256
+ get id(){return n.id},
257
+ /**
258
+ * Tool name
259
+ *
260
+ * @returns {string}
261
+ */
262
+ get name(){return n.name},
263
+ /**
264
+ * Tool config passed on Editor's initialization
265
+ *
266
+ * @returns {ToolConfig}
267
+ */
268
+ get config(){return n.config},
269
+ /**
270
+ * .ce-block element, that wraps plugin contents
271
+ *
272
+ * @returns {HTMLElement}
273
+ */
274
+ get holder(){return n.holder},
275
+ /**
276
+ * True if Block content is empty
277
+ *
278
+ * @returns {boolean}
279
+ */
280
+ get isEmpty(){return n.isEmpty},
281
+ /**
282
+ * True if Block is selected with Cross-Block selection
283
+ *
284
+ * @returns {boolean}
285
+ */
286
+ get selected(){return n.selected},
287
+ /**
288
+ * Set Block's stretch state
289
+ *
290
+ * @param {boolean} state — state to set
291
+ */
292
+ set stretched(h){n.stretched=h},
293
+ /**
294
+ * True if Block is stretched
295
+ *
296
+ * @returns {boolean}
297
+ */
298
+ get stretched(){return n.stretched},get focusable(){return n.focusable},
299
+ /**
300
+ * Call Tool method with errors handler under-the-hood
301
+ *
302
+ * @param {string} methodName - method to call
303
+ * @param {object} param - object with parameters
304
+ * @returns {unknown}
305
+ */
306
+ call(h,p){return n.call(h,p)},
307
+ /**
308
+ * Save Block content
309
+ *
310
+ * @returns {Promise<void|SavedData>}
311
+ */
312
+ save(){return n.save()},
313
+ /**
314
+ * Validate Block data
315
+ *
316
+ * @param {BlockToolData} data - data to validate
317
+ * @returns {Promise<boolean>}
318
+ */
319
+ validate(h){return n.validate(h)},dispatchChange(){n.dispatchChange()},getActiveToolboxEntry(){return n.getActiveToolboxEntry()}})}class Ce{constructor(){this.allListeners=[]}
320
+ /**
321
+ * Assigns event listener on element and returns unique identifier
322
+ *
323
+ * @param {EventTarget} element - DOM element that needs to be listened
324
+ * @param {string} eventType - event type
325
+ * @param {Function} handler - method that will be fired on event
326
+ * @param {boolean|AddEventListenerOptions} options - useCapture or {capture, passive, once}
327
+ */on(n,h,p,g=!1){const m=Ao("l"),v={id:m,element:n,eventType:h,handler:p,options:g};if(!this.findOne(n,h,p))return this.allListeners.push(v),n.addEventListener(h,p,g),m
328
+ /**
329
+ * Removes event listener from element
330
+ *
331
+ * @param {EventTarget} element - DOM element that we removing listener
332
+ * @param {string} eventType - event type
333
+ * @param {Function} handler - remove handler, if element listens several handlers on the same event type
334
+ * @param {boolean|AddEventListenerOptions} options - useCapture or {capture, passive, once}
335
+ */}off(n,h,p,g){const m=this.findAll(n,h,p);m.forEach(((n,h)=>{const p=this.allListeners.indexOf(m[h]);p>-1&&(this.allListeners.splice(p,1),n.element.removeEventListener(n.eventType,n.handler,n.options))}))}
336
+ /**
337
+ * Removes listener by id
338
+ *
339
+ * @param {string} id - listener identifier
340
+ */offById(n){const h=this.findById(n);h&&h.element.removeEventListener(h.eventType,h.handler,h.options)}
341
+ /**
342
+ * Finds and returns first listener by passed params
343
+ *
344
+ * @param {EventTarget} element - event target
345
+ * @param {string} [eventType] - event type
346
+ * @param {Function} [handler] - event handler
347
+ * @returns {ListenerData|null}
348
+ */findOne(n,h,p){const g=this.findAll(n,h,p);return g.length>0?g[0]:null}
349
+ /**
350
+ * Return all stored listeners by passed params
351
+ *
352
+ * @param {EventTarget} element - event target
353
+ * @param {string} eventType - event type
354
+ * @param {Function} handler - event handler
355
+ * @returns {ListenerData[]}
356
+ */findAll(n,h,p){let g;const m=n?this.findByEventTarget(n):[];return g=n&&h&&p?m.filter((n=>n.eventType===h&&n.handler===p)):n&&h?m.filter((n=>n.eventType===h)):m,g}removeAll(){this.allListeners.map((n=>{n.element.removeEventListener(n.eventType,n.handler,n.options)})),this.allListeners=[]}destroy(){this.removeAll()}
357
+ /**
358
+ * Search method: looks for listener by passed element
359
+ *
360
+ * @param {EventTarget} element - searching element
361
+ * @returns {Array} listeners that found on element
362
+ */findByEventTarget(n){return this.allListeners.filter((h=>{if(h.element===n)return h}))}
363
+ /**
364
+ * Search method: looks for listener by passed event type
365
+ *
366
+ * @param {string} eventType - event type
367
+ * @returns {ListenerData[]} listeners that found on element
368
+ */findByType(n){return this.allListeners.filter((h=>{if(h.eventType===n)return h}))}
369
+ /**
370
+ * Search method: looks for listener by passed handler
371
+ *
372
+ * @param {Function} handler - event handler
373
+ * @returns {ListenerData[]} listeners that found on element
374
+ */findByHandler(n){return this.allListeners.filter((h=>{if(h.handler===n)return h}))}
375
+ /**
376
+ * Returns listener data found by id
377
+ *
378
+ * @param {string} id - listener identifier
379
+ * @returns {ListenerData}
380
+ */findById(n){return this.allListeners.find((h=>h.id===n))}}class y{
381
+ /**
382
+ * @class
383
+ * @param options - Module options
384
+ * @param options.config - Module config
385
+ * @param options.eventsDispatcher - Common event bus
386
+ */
387
+ constructor({config:n,eventsDispatcher:h}){if(this.nodes={},this.listeners=new Ce,this.readOnlyMutableListeners={
388
+ /**
389
+ * Assigns event listener on DOM element and pushes into special array that might be removed
390
+ *
391
+ * @param {EventTarget} element - DOM Element
392
+ * @param {string} eventType - Event name
393
+ * @param {Function} handler - Event handler
394
+ * @param {boolean|AddEventListenerOptions} options - Listening options
395
+ */
396
+ on:(n,h,p,g=!1)=>{this.mutableListenerIds.push(this.listeners.on(n,h,p,g))},clearAll:()=>{for(const n of this.mutableListenerIds)this.listeners.offById(n);this.mutableListenerIds=[]}},this.mutableListenerIds=[],new.target===y)throw new TypeError("Constructors for abstract class Module are not allowed.");this.config=n,this.eventsDispatcher=h
397
+ /**
398
+ * Editor modules setter
399
+ *
400
+ * @param {EditorModules} Editor - Editor's Modules
401
+ */}set state(n){this.Editor=n}removeAllNodes(){for(const n in this.nodes){const h=this.nodes[n];h instanceof HTMLElement&&h.remove()}}get isRtl(){return this.config.i18n.direction==="rtl"}}class b{constructor(){this.instance=null,this.selection=null,this.savedSelectionRange=null,this.isFakeBackgroundEnabled=!1,this.commandBackground="backColor",this.commandRemoveFormat="removeFormat"
402
+ /**
403
+ * Editor styles
404
+ *
405
+ * @returns {{editorWrapper: string, editorZone: string}}
406
+ */}static get CSS(){return{editorWrapper:"codex-editor",editorZone:"codex-editor__redactor"}}
407
+ /**
408
+ * Returns selected anchor
409
+ * {@link https://developer.mozilla.org/ru/docs/Web/API/Selection/anchorNode}
410
+ *
411
+ * @returns {Node|null}
412
+ */static get anchorNode(){const n=window.getSelection();return n?n.anchorNode:null}
413
+ /**
414
+ * Returns selected anchor element
415
+ *
416
+ * @returns {Element|null}
417
+ */static get anchorElement(){const n=window.getSelection();if(!n)return null;const h=n.anchorNode;return h?d.isElement(h)?h:h.parentElement:null}
418
+ /**
419
+ * Returns selection offset according to the anchor node
420
+ * {@link https://developer.mozilla.org/ru/docs/Web/API/Selection/anchorOffset}
421
+ *
422
+ * @returns {number|null}
423
+ */static get anchorOffset(){const n=window.getSelection();return n?n.anchorOffset:null}
424
+ /**
425
+ * Is current selection range collapsed
426
+ *
427
+ * @returns {boolean|null}
428
+ */static get isCollapsed(){const n=window.getSelection();return n?n.isCollapsed:null}
429
+ /**
430
+ * Check current selection if it is at Editor's zone
431
+ *
432
+ * @returns {boolean}
433
+ */static get isAtEditor(){return this.isSelectionAtEditor(b.get())}
434
+ /**
435
+ * Check if passed selection is at Editor's zone
436
+ *
437
+ * @param selection - Selection object to check
438
+ */static isSelectionAtEditor(n){if(!n)return!1;let h=n.anchorNode||n.focusNode;h&&h.nodeType===Node.TEXT_NODE&&(h=h.parentNode);let p=null;return h&&h instanceof Element&&(p=h.closest(`.${b.CSS.editorZone}`)),!!p&&p.nodeType===Node.ELEMENT_NODE
439
+ /**
440
+ * Check if passed range at Editor zone
441
+ *
442
+ * @param range - range to check
443
+ */}static isRangeAtEditor(n){if(!n)return;let h=n.startContainer;h&&h.nodeType===Node.TEXT_NODE&&(h=h.parentNode);let p=null;return h&&h instanceof Element&&(p=h.closest(`.${b.CSS.editorZone}`)),!!p&&p.nodeType===Node.ELEMENT_NODE}static get isSelectionExists(){return!!b.get().anchorNode}
444
+ /**
445
+ * Return first range
446
+ *
447
+ * @returns {Range|null}
448
+ */static get range(){return this.getRangeFromSelection(this.get())}
449
+ /**
450
+ * Returns range from passed Selection object
451
+ *
452
+ * @param selection - Selection object to get Range from
453
+ */static getRangeFromSelection(n){return n&&n.rangeCount?n.getRangeAt(0):null}
454
+ /**
455
+ * Calculates position and size of selected text
456
+ *
457
+ * @returns {DOMRect | ClientRect}
458
+ */static get rect(){let n,h=document.selection,p={x:0,y:0,width:0,height:0};if(h&&h.type!=="Control")return h,n=h.createRange(),p.x=n.boundingLeft,p.y=n.boundingTop,p.width=n.boundingWidth,p.height=n.boundingHeight,p;if(!window.getSelection)return g("Method window.getSelection is not supported","warn"),p;if(h=window.getSelection(),h.rangeCount===null||isNaN(h.rangeCount))return g("Method SelectionUtils.rangeCount is not supported","warn"),p;if(h.rangeCount===0)return p;if(n=h.getRangeAt(0).cloneRange(),n.getBoundingClientRect&&(p=n.getBoundingClientRect()),p.x===0&&p.y===0){const h=document.createElement("span");if(h.getBoundingClientRect){h.appendChild(document.createTextNode("​")),n.insertNode(h),p=h.getBoundingClientRect();const g=h.parentNode;g.removeChild(h),g.normalize()}}return p}
459
+ /**
460
+ * Returns selected text as String
461
+ *
462
+ * @returns {string}
463
+ */static get text(){return window.getSelection?window.getSelection().toString():""}
464
+ /**
465
+ * Returns window SelectionUtils
466
+ * {@link https://developer.mozilla.org/ru/docs/Web/API/Window/getSelection}
467
+ *
468
+ * @returns {Selection}
469
+ */static get(){return window.getSelection()}
470
+ /**
471
+ * Set focus to contenteditable or native input element
472
+ *
473
+ * @param element - element where to set focus
474
+ * @param offset - offset of cursor
475
+ */static setCursor(n,h=0){const p=document.createRange(),g=window.getSelection();return d.isNativeInput(n)?d.canSetCaret(n)?(n.focus(),n.selectionStart=n.selectionEnd=h,n.getBoundingClientRect()):void 0:(p.setStart(n,h),p.setEnd(n,h),g.removeAllRanges(),g.addRange(p),p.getBoundingClientRect()
476
+ /**
477
+ * Check if current range exists and belongs to container
478
+ *
479
+ * @param container - where range should be
480
+ */)}static isRangeInsideContainer(n){const h=b.range;return h!==null&&n.contains(h.startContainer)}static addFakeCursor(){const n=b.range;if(n===null)return;const h=d.make("span","codex-editor__fake-cursor");h.dataset.mutationFree="true",n.collapse(),n.insertNode(h)
481
+ /**
482
+ * Check if passed element contains a fake cursor
483
+ *
484
+ * @param el - where to check
485
+ */}static isFakeCursorInsideContainer(n){return d.find(n,".codex-editor__fake-cursor")!==null}
486
+ /**
487
+ * Removes fake cursor from a container
488
+ *
489
+ * @param container - container to look for
490
+ */static removeFakeCursor(n=document.body){const h=d.find(n,".codex-editor__fake-cursor");h&&h.remove()}removeFakeBackground(){this.isFakeBackgroundEnabled&&(this.isFakeBackgroundEnabled=!1,document.execCommand(this.commandRemoveFormat))}setFakeBackground(){document.execCommand(this.commandBackground,!1,"#a8d6ff"),this.isFakeBackgroundEnabled=!0}save(){this.savedSelectionRange=b.range}restore(){if(!this.savedSelectionRange)return;const n=window.getSelection();n.removeAllRanges(),n.addRange(this.savedSelectionRange)}clearSaved(){this.savedSelectionRange=null}collapseToEnd(){const n=window.getSelection(),h=document.createRange();h.selectNodeContents(n.focusNode),h.collapse(!1),n.removeAllRanges(),n.addRange(h)
491
+ /**
492
+ * Looks ahead to find passed tag from current selection
493
+ *
494
+ * @param {string} tagName - tag to found
495
+ * @param {string} [className] - tag's class name
496
+ * @param {number} [searchDepth] - count of tags that can be included. For better performance.
497
+ * @returns {HTMLElement|null}
498
+ */}findParentTag(n,h,p=10){const g=window.getSelection();let m=null;return g&&g.anchorNode&&g.focusNode?([g.anchorNode,g.focusNode].forEach((g=>{let v=p;for(;v>0&&g.parentNode&&!(g.tagName===n&&(m=g,h&&g.classList&&!g.classList.contains(h)&&(m=null),m));)g=g.parentNode,v--})),m
499
+ /**
500
+ * Expands selection range to the passed parent node
501
+ *
502
+ * @param {HTMLElement} element - element which contents should be selected
503
+ */):null}expandToTag(n){const h=window.getSelection();h.removeAllRanges();const p=document.createRange();p.selectNodeContents(n),h.addRange(p)}}function Fo(n,h){const{type:p,target:g,addedNodes:m,removedNodes:v}=n;return(n.type!=="attributes"||n.attributeName!=="data-empty")&&!!(h.contains(g)||p==="childList"&&(Array.from(m).some((n=>n===h))||Array.from(v).some((n=>n===h))))}const L="redactor dom changed",N="block changed",P="fake cursor is about to be toggled",H="fake cursor have been set",z="editor mobile layout toggled";function Qe(n,h){if(!n.conversionConfig)return!1;const p=n.conversionConfig[h];return O(p)||Q(p)}function _e(n,h){return Qe(n.tool,h)}function Ht(n,h){return Object.entries(n).some((([n,p])=>h[n]&&Oo(h[n],p)))}async function zt(n,h){const p=(await n.save()).data,g=h.find((h=>h.name===n.name));return g===void 0||Qe(g,"export")?h.reduce(((h,g)=>{if(!Qe(g,"import")||g.toolbox===void 0)return h;const m=g.toolbox.filter((h=>{if(V(h)||h.icon===void 0)return!1;if(h.data!==void 0){if(Ht(h.data,p))return!1}else if(g.name===n.name)return!1;return!0}));return h.push({...g,toolbox:m}),h}),[]):[]}function wt(n,h){return!!n.mergeable&&(n.name===h.name||_e(h,"export")&&_e(n,"import"))}function Ho(n,h){const p=h==null?void 0:h.export;return O(p)?p(n):Q(p)?n[p]:(p!==void 0&&g("Conversion «export» property must be a string or function. String means key of saved data object to export. Function should export processed string to export."),"")}function xt(n,h){const p=h==null?void 0:h.import;return O(p)?p(n):Q(p)?{[p]:n}:(p!==void 0&&g("Conversion «import» property must be a string or function. String means key of tool data to import. Function accepts a imported string and return composed tool data."),{})}var U=(n=>(n.Default="default",n.Separator="separator",n.Html="html",n))(U||{}),$=(n=>(n.APPEND_CALLBACK="appendCallback",n.RENDERED="rendered",n.MOVED="moved",n.UPDATED="updated",n.REMOVED="removed",n.ON_PASTE="onPaste",n))($||{});class D extends Te{
504
+ /**
505
+ * @param options - block constructor options
506
+ * @param [options.id] - block's id. Will be generated if omitted.
507
+ * @param options.data - Tool's initial data
508
+ * @param options.tool — block's tool
509
+ * @param options.api - Editor API module for pass it to the Block Tunes
510
+ * @param options.readOnly - Read-Only flag
511
+ * @param [eventBus] - Editor common event bus. Allows to subscribe on some Editor events. Could be omitted when "virtual" Block is created. See BlocksAPI@composeBlockData.
512
+ */
513
+ constructor({id:n=Io(),data:h,tool:p,readOnly:g,tunesData:m},v){super(),this.cachedInputs=[],this.toolRenderedElement=null,this.tunesInstances=new Map,this.defaultTunesInstances=new Map,this.unavailableTunesData={},this.inputIndex=0,this.editorEventBus=null,this.handleFocus=()=>{this.dropInputsCache(),this.updateCurrentInput()},this.didMutated=(n=void 0)=>{const h=n===void 0,p=n instanceof InputEvent;!h&&!p&&this.detectToolRootChange(n);let g;g=!(!h&&!p)||!(n.length>0&&n.every((n=>{const{addedNodes:h,removedNodes:p,target:g}=n;return[...Array.from(h),...Array.from(p),g].some((n=>(d.isElement(n)||(n=n.parentElement),n&&n.closest('[data-mutation-free="true"]')!==null)))}))),g&&(this.dropInputsCache(),this.updateCurrentInput(),this.toggleInputsEmptyMark(),this.call("updated"),this.emit("didMutated",this))},this.name=p.name,this.id=n,this.settings=p.settings,this.config=p.settings.config||{},this.editorEventBus=v||null,this.blockAPI=new G(this),this.tool=p,this.toolInstance=p.create(h,this.blockAPI,g),this.tunes=p.tunes,this.composeTunes(m),this.holder=this.compose(),window.requestIdleCallback((()=>{this.watchBlockMutations(),this.addInputEvents(),this.toggleInputsEmptyMark()}))
514
+ /**
515
+ * CSS classes for the Block
516
+ *
517
+ * @returns {{wrapper: string, content: string}}
518
+ */}static get CSS(){return{wrapper:"ce-block",wrapperStretched:"ce-block--stretched",content:"ce-block__content",selected:"ce-block--selected",dropTarget:"ce-block--drop-target"}}get inputs(){if(this.cachedInputs.length!==0)return this.cachedInputs;const n=d.findAllInputs(this.holder);return this.inputIndex>n.length-1&&(this.inputIndex=n.length-1),this.cachedInputs=n,n}get currentInput(){return this.inputs[this.inputIndex]}
519
+ /**
520
+ * Set input index to the passed element
521
+ *
522
+ * @param element - HTML Element to set as current input
523
+ */set currentInput(n){const h=this.inputs.findIndex((h=>h===n||h.contains(n)));h!==-1&&(this.inputIndex=h)}get firstInput(){return this.inputs[0]}get lastInput(){const n=this.inputs;return n[n.length-1]}get nextInput(){return this.inputs[this.inputIndex+1]}get previousInput(){return this.inputs[this.inputIndex-1]}
524
+ /**
525
+ * Get Block's JSON data
526
+ *
527
+ * @returns {object}
528
+ */get data(){return this.save().then((n=>n&&!V(n.data)?n.data:{}))}
529
+ /**
530
+ * Returns tool's sanitizer config
531
+ *
532
+ * @returns {object}
533
+ */get sanitize(){return this.tool.sanitizeConfig}
534
+ /**
535
+ * is block mergeable
536
+ * We plugin have merge function then we call it mergeable
537
+ *
538
+ * @returns {boolean}
539
+ */get mergeable(){return O(this.toolInstance.merge)}get focusable(){return this.inputs.length!==0}
540
+ /**
541
+ * Check block for emptiness
542
+ *
543
+ * @returns {boolean}
544
+ */get isEmpty(){const n=d.isEmpty(this.pluginsContent,"/"),h=!this.hasMedia;return n&&h}
545
+ /**
546
+ * Check if block has a media content such as images, iframe and other
547
+ *
548
+ * @returns {boolean}
549
+ */get hasMedia(){const n=["img","iframe","video","audio","source","input","textarea","twitterwidget"];return!!this.holder.querySelector(n.join(","))}
550
+ /**
551
+ * Set selected state
552
+ * We don't need to mark Block as Selected when it is empty
553
+ *
554
+ * @param {boolean} state - 'true' to select, 'false' to remove selection
555
+ */set selected(n){var h,p;this.holder.classList.toggle(D.CSS.selected,n);const g=n===!0&&b.isRangeInsideContainer(this.holder),m=n===!1&&b.isFakeCursorInsideContainer(this.holder);(g||m)&&((h=this.editorEventBus)==null||h.emit(P,{state:n}),g?b.addFakeCursor():b.removeFakeCursor(this.holder),(p=this.editorEventBus)==null||p.emit(H,{state:n})
556
+ /**
557
+ * Returns True if it is Selected
558
+ *
559
+ * @returns {boolean}
560
+ */)}get selected(){return this.holder.classList.contains(D.CSS.selected)}
561
+ /**
562
+ * Set stretched state
563
+ *
564
+ * @param {boolean} state - 'true' to enable, 'false' to disable stretched state
565
+ */set stretched(n){this.holder.classList.toggle(D.CSS.wrapperStretched,n)}
566
+ /**
567
+ * Return Block's stretched state
568
+ *
569
+ * @returns {boolean}
570
+ */get stretched(){return this.holder.classList.contains(D.CSS.wrapperStretched)}
571
+ /**
572
+ * Toggle drop target state
573
+ *
574
+ * @param {boolean} state - 'true' if block is drop target, false otherwise
575
+ */set dropTarget(n){this.holder.classList.toggle(D.CSS.dropTarget,n)}
576
+ /**
577
+ * Returns Plugins content
578
+ *
579
+ * @returns {HTMLElement}
580
+ */get pluginsContent(){return this.toolRenderedElement}
581
+ /**
582
+ * Calls Tool's method
583
+ *
584
+ * Method checks tool property {MethodName}. Fires method with passes params If it is instance of Function
585
+ *
586
+ * @param {string} methodName - method to call
587
+ * @param {object} params - method argument
588
+ */call(n,h){if(O(this.toolInstance[n])){n==="appendCallback"&&g("`appendCallback` hook is deprecated and will be removed in the next major release. Use `rendered` hook instead","warn");try{this.toolInstance[n].call(this.toolInstance,h)}catch(h){g(`Error during '${n}' call: ${h.message}`,"error")}}}
589
+ /**
590
+ * Call plugins merge method
591
+ *
592
+ * @param {BlockToolData} data - data to merge
593
+ */async mergeWith(n){await this.toolInstance.merge(n)}
594
+ /**
595
+ * Extracts data from Block
596
+ * Groups Tool's save processing time
597
+ *
598
+ * @returns {object}
599
+ */async save(){const n=await this.toolInstance.save(this.pluginsContent),h=this.unavailableTunesData;[...this.tunesInstances.entries(),...this.defaultTunesInstances.entries()].forEach((([n,p])=>{if(O(p.save))try{h[n]=p.save()}catch(n){g(`Tune ${p.constructor.name} save method throws an Error %o`,"warn",n)}}));const p=window.performance.now();let m;return Promise.resolve(n).then((n=>(m=window.performance.now(),{id:this.id,tool:this.name,data:n,tunes:h,time:m-p}))).catch((n=>{g(`Saving process for ${this.name} tool failed due to the ${n}`,"log","red")}))}
600
+ /**
601
+ * Uses Tool's validation method to check the correctness of output data
602
+ * Tool's validation method is optional
603
+ *
604
+ * @description Method returns true|false whether data passed the validation or not
605
+ * @param {BlockToolData} data - data to validate
606
+ * @returns {Promise<boolean>} valid
607
+ */async validate(n){let h=!0;return this.toolInstance.validate instanceof Function&&(h=await this.toolInstance.validate(n)),h}getTunes(){const n=[],h=[],p=typeof this.toolInstance.renderSettings=="function"?this.toolInstance.renderSettings():[];return d.isElement(p)?n.push({type:U.Html,element:p}):Array.isArray(p)?n.push(...p):n.push(p),[...this.tunesInstances.values(),...this.defaultTunesInstances.values()].map((n=>n.render())).forEach((n=>{d.isElement(n)?h.push({type:U.Html,element:n}):Array.isArray(n)?h.push(...n):h.push(n)})),{toolTunes:n,commonTunes:h}}updateCurrentInput(){this.currentInput=d.isNativeInput(document.activeElement)||!b.anchorNode?document.activeElement:b.anchorNode}dispatchChange(){this.didMutated()}destroy(){this.unwatchBlockMutations(),this.removeInputEvents(),super.destroy(),O(this.toolInstance.destroy)&&this.toolInstance.destroy()}async getActiveToolboxEntry(){const n=this.tool.toolbox;if(n.length===1)return Promise.resolve(this.tool.toolbox[0]);const h=await this.data,p=n;return p==null?void 0:p.find((n=>Ht(n.data,h)))}async exportDataAsString(){const n=await this.data;return Ho(n,this.tool.conversionConfig)}
608
+ /**
609
+ * Make default Block wrappers and put Tool`s content there
610
+ *
611
+ * @returns {HTMLDivElement}
612
+ */compose(){const n=d.make("div",D.CSS.wrapper),h=d.make("div",D.CSS.content),p=this.toolInstance.render();n.dataset.id=this.id,this.toolRenderedElement=p,h.appendChild(this.toolRenderedElement);let m=h;return[...this.tunesInstances.values(),...this.defaultTunesInstances.values()].forEach((n=>{if(O(n.wrap))try{m=n.wrap(m)}catch(h){g(`Tune ${n.constructor.name} wrap method throws an Error %o`,"warn",h)}})),n.appendChild(m),n
613
+ /**
614
+ * Instantiate Block Tunes
615
+ *
616
+ * @param tunesData - current Block tunes data
617
+ * @private
618
+ */}composeTunes(n){Array.from(this.tunes.values()).forEach((h=>{(h.isInternal?this.defaultTunesInstances:this.tunesInstances).set(h.name,h.create(n[h.name],this.blockAPI))})),Object.entries(n).forEach((([n,h])=>{this.tunesInstances.has(n)||(this.unavailableTunesData[n]=h)}))}addInputEvents(){this.inputs.forEach((n=>{n.addEventListener("focus",this.handleFocus),d.isNativeInput(n)&&n.addEventListener("input",this.didMutated)}))}removeInputEvents(){this.inputs.forEach((n=>{n.removeEventListener("focus",this.handleFocus),d.isNativeInput(n)&&n.removeEventListener("input",this.didMutated)}))}watchBlockMutations(){var n;this.redactorDomChangedCallback=n=>{const{mutations:h}=n;h.some((n=>Fo(n,this.toolRenderedElement)))&&this.didMutated(h)},(n=this.editorEventBus)==null||n.on(L,this.redactorDomChangedCallback)}unwatchBlockMutations(){var n;(n=this.editorEventBus)==null||n.off(L,this.redactorDomChangedCallback)}
619
+ /**
620
+ * Sometimes Tool can replace own main element, for example H2 -> H4 or UL -> OL
621
+ * We need to detect such changes and update a link to tools main element with the new one
622
+ *
623
+ * @param mutations - records of block content mutations
624
+ */detectToolRootChange(n){n.forEach((n=>{if(Array.from(n.removedNodes).includes(this.toolRenderedElement)){const h=n.addedNodes[n.addedNodes.length-1];this.toolRenderedElement=h}}))}dropInputsCache(){this.cachedInputs=[]}toggleInputsEmptyMark(){this.inputs.forEach(Lt)}}class zo extends y{constructor(){super(...arguments),this.insert=(n=this.config.defaultBlock,h={},p={},g,m,v,x)=>{const w=this.Editor.BlockManager.insert({id:x,tool:n,data:h,index:g,needToFocus:m,replace:v});return new G(w)},this.composeBlockData=async n=>{const h=this.Editor.Tools.blockTools.get(n);return new D({tool:h,api:this.Editor.API,readOnly:!0,data:{},tunesData:{}}).data},this.update=async(n,h,p)=>{const{BlockManager:g}=this.Editor,m=g.getBlockById(n);if(m===void 0)throw new Error(`Block with id "${n}" not found`);const v=await g.update(m,h,p);return new G(v)},this.convert=async(n,h,p)=>{var g,m;const{BlockManager:v,Tools:x}=this.Editor,w=v.getBlockById(n);if(!w)throw new Error(`Block with id "${n}" not found`);const E=x.blockTools.get(w.name),B=x.blockTools.get(h);if(!B)throw new Error(`Block Tool with type "${h}" not found`);const T=((g=E==null?void 0:E.conversionConfig)==null?void 0:g.export)!==void 0,I=((m=B.conversionConfig)==null?void 0:m.import)!==void 0;if(T&&I){const n=await v.convert(w,h,p);return new G(n)}{const n=[!T&&Le(w.name),!I&&Le(h)].filter(Boolean).join(" and ");throw new Error(`Conversion from "${w.name}" to "${h}" is not possible. ${n} tool(s) should provide a "conversionConfig"`)}},this.insertMany=(n,h=this.Editor.BlockManager.blocks.length-1)=>{this.validateIndex(h);const p=n.map((({id:n,type:h,data:p})=>this.Editor.BlockManager.composeBlock({id:n,tool:h||this.config.defaultBlock,data:p})));return this.Editor.BlockManager.insertMany(p,h),p.map((n=>new G(n)))}
625
+ /**
626
+ * Available methods
627
+ *
628
+ * @returns {Blocks}
629
+ */}get methods(){return{clear:()=>this.clear(),render:n=>this.render(n),renderFromHTML:n=>this.renderFromHTML(n),delete:n=>this.delete(n),swap:(n,h)=>this.swap(n,h),move:(n,h)=>this.move(n,h),getBlockByIndex:n=>this.getBlockByIndex(n),getById:n=>this.getById(n),getCurrentBlockIndex:()=>this.getCurrentBlockIndex(),getBlockIndex:n=>this.getBlockIndex(n),getBlocksCount:()=>this.getBlocksCount(),getBlockByElement:n=>this.getBlockByElement(n),stretchBlock:(n,h=!0)=>this.stretchBlock(n,h),insertNewBlock:()=>this.insertNewBlock(),insert:this.insert,insertMany:this.insertMany,update:this.update,composeBlockData:this.composeBlockData,convert:this.convert}}
630
+ /**
631
+ * Returns Blocks count
632
+ *
633
+ * @returns {number}
634
+ */getBlocksCount(){return this.Editor.BlockManager.blocks.length}
635
+ /**
636
+ * Returns current block index
637
+ *
638
+ * @returns {number}
639
+ */getCurrentBlockIndex(){return this.Editor.BlockManager.currentBlockIndex}
640
+ /**
641
+ * Returns the index of Block by id;
642
+ *
643
+ * @param id - block id
644
+ */getBlockIndex(n){const h=this.Editor.BlockManager.getBlockById(n);if(h)return this.Editor.BlockManager.getBlockIndex(h);m("There is no block with id `"+n+"`","warn")}
645
+ /**
646
+ * Returns BlockAPI object by Block index
647
+ *
648
+ * @param {number} index - index to get
649
+ */getBlockByIndex(n){const h=this.Editor.BlockManager.getBlockByIndex(n);if(h!==void 0)return new G(h);m("There is no block at index `"+n+"`","warn")}
650
+ /**
651
+ * Returns BlockAPI object by Block id
652
+ *
653
+ * @param id - id of block to get
654
+ */getById(n){const h=this.Editor.BlockManager.getBlockById(n);return h===void 0?(m("There is no block with id `"+n+"`","warn"),null):new G(h)}
655
+ /**
656
+ * Get Block API object by any child html element
657
+ *
658
+ * @param element - html element to get Block by
659
+ */getBlockByElement(n){const h=this.Editor.BlockManager.getBlock(n);if(h!==void 0)return new G(h);m("There is no block corresponding to element `"+n+"`","warn")}
660
+ /**
661
+ * Call Block Manager method that swap Blocks
662
+ *
663
+ * @param {number} fromIndex - position of first Block
664
+ * @param {number} toIndex - position of second Block
665
+ * @deprecated — use 'move' instead
666
+ */swap(n,h){g("`blocks.swap()` method is deprecated and will be removed in the next major release. Use `block.move()` method instead","info"),this.Editor.BlockManager.swap(n,h)
667
+ /**
668
+ * Move block from one index to another
669
+ *
670
+ * @param {number} toIndex - index to move to
671
+ * @param {number} fromIndex - index to move from
672
+ */}move(n,h){this.Editor.BlockManager.move(n,h)}
673
+ /**
674
+ * Deletes Block
675
+ *
676
+ * @param {number} blockIndex - index of Block to delete
677
+ */delete(n=this.Editor.BlockManager.currentBlockIndex){try{const h=this.Editor.BlockManager.getBlockByIndex(n);this.Editor.BlockManager.removeBlock(h)}catch(n){m(n,"warn");return}this.Editor.BlockManager.blocks.length===0&&this.Editor.BlockManager.insert(),this.Editor.BlockManager.currentBlock&&this.Editor.Caret.setToBlock(this.Editor.BlockManager.currentBlock,this.Editor.Caret.positions.END),this.Editor.Toolbar.close()}async clear(){await this.Editor.BlockManager.clear(!0),this.Editor.InlineToolbar.close()
678
+ /**
679
+ * Fills Editor with Blocks data
680
+ *
681
+ * @param {OutputData} data — Saved Editor data
682
+ */}async render(n){if(n===void 0||n.blocks===void 0)throw new Error("Incorrect data passed to the render() method");this.Editor.ModificationsObserver.disable(),await this.Editor.BlockManager.clear(),await this.Editor.Renderer.render(n.blocks),this.Editor.ModificationsObserver.enable()
683
+ /**
684
+ * Render passed HTML string
685
+ *
686
+ * @param {string} data - HTML string to render
687
+ * @returns {Promise<void>}
688
+ */}renderFromHTML(n){return this.Editor.BlockManager.clear(),this.Editor.Paste.processText(n,!0)
689
+ /**
690
+ * Stretch Block's content
691
+ *
692
+ * @param {number} index - index of Block to stretch
693
+ * @param {boolean} status - true to enable, false to disable
694
+ * @deprecated Use BlockAPI interface to stretch Blocks
695
+ */}stretchBlock(n,h=!0){Ze(!0,"blocks.stretchBlock()","BlockAPI");const p=this.Editor.BlockManager.getBlockByIndex(n);p&&(p.stretched=h)}
696
+ /**
697
+ * Insert new Block
698
+ * After set caret to this Block
699
+ *
700
+ * @todo remove in 3.0.0
701
+ * @deprecated with insert() method
702
+ */insertNewBlock(){g("Method blocks.insertNewBlock() is deprecated and it will be removed in the next major release. Use blocks.insert() instead.","warn"),this.insert()
703
+ /**
704
+ * Validated block index and throws an error if it's invalid
705
+ *
706
+ * @param index - index to validate
707
+ */}validateIndex(n){if(typeof n!="number")throw new Error("Index should be a number");if(n<0)throw new Error("Index should be greater than or equal to 0");if(n===null)throw new Error("Index should be greater than or equal to 0")}}function Uo(n,h){return typeof n=="number"?h.BlockManager.getBlockByIndex(n):typeof n=="string"?h.BlockManager.getBlockById(n):h.BlockManager.getBlockById(n.id)}class jo extends y{constructor(){super(...arguments),this.setToFirstBlock=(n=this.Editor.Caret.positions.DEFAULT,h=0)=>!!this.Editor.BlockManager.firstBlock&&(this.Editor.Caret.setToBlock(this.Editor.BlockManager.firstBlock,n,h),!0),this.setToLastBlock=(n=this.Editor.Caret.positions.DEFAULT,h=0)=>!!this.Editor.BlockManager.lastBlock&&(this.Editor.Caret.setToBlock(this.Editor.BlockManager.lastBlock,n,h),!0),this.setToPreviousBlock=(n=this.Editor.Caret.positions.DEFAULT,h=0)=>!!this.Editor.BlockManager.previousBlock&&(this.Editor.Caret.setToBlock(this.Editor.BlockManager.previousBlock,n,h),!0),this.setToNextBlock=(n=this.Editor.Caret.positions.DEFAULT,h=0)=>!!this.Editor.BlockManager.nextBlock&&(this.Editor.Caret.setToBlock(this.Editor.BlockManager.nextBlock,n,h),!0),this.setToBlock=(n,h=this.Editor.Caret.positions.DEFAULT,p=0)=>{const g=Uo(n,this.Editor);return g!==void 0&&(this.Editor.Caret.setToBlock(g,h,p),!0)},this.focus=(n=!1)=>n?this.setToLastBlock(this.Editor.Caret.positions.END):this.setToFirstBlock(this.Editor.Caret.positions.START)
708
+ /**
709
+ * Available methods
710
+ *
711
+ * @returns {Caret}
712
+ */}get methods(){return{setToFirstBlock:this.setToFirstBlock,setToLastBlock:this.setToLastBlock,setToPreviousBlock:this.setToPreviousBlock,setToNextBlock:this.setToNextBlock,setToBlock:this.setToBlock,focus:this.focus}}}class $o extends y{
713
+ /**
714
+ * Available methods
715
+ *
716
+ * @returns {Events}
717
+ */
718
+ get methods(){return{emit:(n,h)=>this.emit(n,h),off:(n,h)=>this.off(n,h),on:(n,h)=>this.on(n,h)}}
719
+ /**
720
+ * Subscribe on Events
721
+ *
722
+ * @param {string} eventName - event name to subscribe
723
+ * @param {Function} callback - event handler
724
+ */on(n,h){this.eventsDispatcher.on(n,h)}
725
+ /**
726
+ * Emit event with data
727
+ *
728
+ * @param {string} eventName - event to emit
729
+ * @param {object} data - event's data
730
+ */emit(n,h){this.eventsDispatcher.emit(n,h)}
731
+ /**
732
+ * Unsubscribe from Event
733
+ *
734
+ * @param {string} eventName - event to unsubscribe
735
+ * @param {Function} callback - event handler
736
+ */off(n,h){this.eventsDispatcher.off(n,h)}}class ot extends y{
737
+ /**
738
+ * Return namespace section for tool or block tune
739
+ *
740
+ * @param toolName - tool name
741
+ * @param isTune - is tool a block tune
742
+ */
743
+ static getNamespace(n,h){return h?`blockTunes.${n}`:`tools.${n}`}get methods(){return{t:()=>{m("I18n.t() method can be accessed only from Tools","warn")}}}
744
+ /**
745
+ * Return I18n API methods with tool namespaced dictionary
746
+ *
747
+ * @param toolName - tool name
748
+ * @param isTune - is tool a block tune
749
+ */getMethodsForTool(n,h){return Object.assign(this.methods,{t:p=>A.t(ot.getNamespace(n,h),p)})}}class Yo extends y{get methods(){return{blocks:this.Editor.BlocksAPI.methods,caret:this.Editor.CaretAPI.methods,tools:this.Editor.ToolsAPI.methods,events:this.Editor.EventsAPI.methods,listeners:this.Editor.ListenersAPI.methods,notifier:this.Editor.NotifierAPI.methods,sanitizer:this.Editor.SanitizerAPI.methods,saver:this.Editor.SaverAPI.methods,selection:this.Editor.SelectionAPI.methods,styles:this.Editor.StylesAPI.classes,toolbar:this.Editor.ToolbarAPI.methods,inlineToolbar:this.Editor.InlineToolbarAPI.methods,tooltip:this.Editor.TooltipAPI.methods,i18n:this.Editor.I18nAPI.methods,readOnly:this.Editor.ReadOnlyAPI.methods,ui:this.Editor.UiAPI.methods}}
750
+ /**
751
+ * Returns Editor.js Core API methods for passed tool
752
+ *
753
+ * @param toolName - tool name
754
+ * @param isTune - is tool a block tune
755
+ */getMethodsForTool(n,h){return Object.assign(this.methods,{i18n:this.Editor.I18nAPI.getMethodsForTool(n,h)})}}class Wo extends y{
756
+ /**
757
+ * Available methods
758
+ *
759
+ * @returns {InlineToolbar}
760
+ */
761
+ get methods(){return{close:()=>this.close(),open:()=>this.open()}}open(){this.Editor.InlineToolbar.tryToShow()}close(){this.Editor.InlineToolbar.close()}}class Ko extends y{
762
+ /**
763
+ * Available methods
764
+ *
765
+ * @returns {Listeners}
766
+ */
767
+ get methods(){return{on:(n,h,p,g)=>this.on(n,h,p,g),off:(n,h,p,g)=>this.off(n,h,p,g),offById:n=>this.offById(n)}}
768
+ /**
769
+ * Ads a DOM event listener. Return it's id.
770
+ *
771
+ * @param {HTMLElement} element - Element to set handler to
772
+ * @param {string} eventType - event type
773
+ * @param {() => void} handler - event handler
774
+ * @param {boolean} useCapture - capture event or not
775
+ */on(n,h,p,g){return this.listeners.on(n,h,p,g)}
776
+ /**
777
+ * Removes DOM listener from element
778
+ *
779
+ * @param {Element} element - Element to remove handler from
780
+ * @param eventType - event type
781
+ * @param handler - event handler
782
+ * @param {boolean} useCapture - capture event or not
783
+ */off(n,h,p,g){this.listeners.off(n,h,p,g)}
784
+ /**
785
+ * Removes DOM listener by the listener id
786
+ *
787
+ * @param id - id of the listener to remove
788
+ */offById(n){this.listeners.offById(n)}}var Y={exports:{}};(function(n,h){(function(h,p){n.exports=p()})(window,(function(){return function(n){var h={};function i(p){if(h[p])return h[p].exports;var g=h[p]={i:p,l:!1,exports:{}};return n[p].call(g.exports,g,g.exports,i),g.l=!0,g.exports}return i.m=n,i.c=h,i.d=function(n,h,p){i.o(n,h)||Object.defineProperty(n,h,{enumerable:!0,get:p})},i.r=function(n){typeof Symbol<"u"&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},i.t=function(n,h){if(1&h&&(n=i(n)),8&h||4&h&&typeof n=="object"&&n&&n.__esModule)return n;var p=Object.create(null);if(i.r(p),Object.defineProperty(p,"default",{enumerable:!0,value:n}),2&h&&typeof n!="string")for(var g in n)i.d(p,g,function(h){return n[h]}.bind(null,g));return p},i.n=function(n){var h=n&&n.__esModule?function(){return n.default}:function(){return n};return i.d(h,"a",h),h},i.o=function(n,h){return Object.prototype.hasOwnProperty.call(n,h)},i.p="/",i(i.s=0)}([function(n,h,p){p(1),n.exports=function(){var n=p(6),h="cdx-notify--bounce-in",g=null;return{show:function(p){if(p.message){(function(){if(g)return!0;g=n.getWrapper(),document.body.appendChild(g)})();var m=null,v=p.time||8e3;switch(p.type){case"confirm":m=n.confirm(p);break;case"prompt":m=n.prompt(p);break;default:m=n.alert(p),window.setTimeout((function(){m.remove()}),v)}g.appendChild(m),m.classList.add(h)}}}}()},function(n,h,p){var g=p(2);typeof g=="string"&&(g=[[n.i,g,""]]);var m={hmr:!0,transform:void 0,insertInto:void 0};p(4)(g,m),g.locals&&(n.exports=g.locals)},function(n,h,p){(n.exports=p(3)(!1)).push([n.i,'.cdx-notify--error{background:#fffbfb!important}.cdx-notify--error::before{background:#fb5d5d!important}.cdx-notify__input{max-width:130px;padding:5px 10px;background:#f7f7f7;border:0;border-radius:3px;font-size:13px;color:#656b7c;outline:0}.cdx-notify__input:-ms-input-placeholder{color:#656b7c}.cdx-notify__input::placeholder{color:#656b7c}.cdx-notify__input:focus:-ms-input-placeholder{color:rgba(101,107,124,.3)}.cdx-notify__input:focus::placeholder{color:rgba(101,107,124,.3)}.cdx-notify__button{border:none;border-radius:3px;font-size:13px;padding:5px 10px;cursor:pointer}.cdx-notify__button:last-child{margin-left:10px}.cdx-notify__button--cancel{background:#f2f5f7;box-shadow:0 2px 1px 0 rgba(16,19,29,0);color:#656b7c}.cdx-notify__button--cancel:hover{background:#eee}.cdx-notify__button--confirm{background:#34c992;box-shadow:0 1px 1px 0 rgba(18,49,35,.05);color:#fff}.cdx-notify__button--confirm:hover{background:#33b082}.cdx-notify__btns-wrapper{display:-ms-flexbox;display:flex;-ms-flex-flow:row nowrap;flex-flow:row nowrap;margin-top:5px}.cdx-notify__cross{position:absolute;top:5px;right:5px;width:10px;height:10px;padding:5px;opacity:.54;cursor:pointer}.cdx-notify__cross::after,.cdx-notify__cross::before{content:\'\';position:absolute;left:9px;top:5px;height:12px;width:2px;background:#575d67}.cdx-notify__cross::before{transform:rotate(-45deg)}.cdx-notify__cross::after{transform:rotate(45deg)}.cdx-notify__cross:hover{opacity:1}.cdx-notifies{position:fixed;z-index:2;bottom:20px;left:20px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Fira Sans","Droid Sans","Helvetica Neue",sans-serif}.cdx-notify{position:relative;width:220px;margin-top:15px;padding:13px 16px;background:#fff;box-shadow:0 11px 17px 0 rgba(23,32,61,.13);border-radius:5px;font-size:14px;line-height:1.4em;word-wrap:break-word}.cdx-notify::before{content:\'\';position:absolute;display:block;top:0;left:0;width:3px;height:calc(100% - 6px);margin:3px;border-radius:5px;background:0 0}@keyframes bounceIn{0%{opacity:0;transform:scale(.3)}50%{opacity:1;transform:scale(1.05)}70%{transform:scale(.9)}100%{transform:scale(1)}}.cdx-notify--bounce-in{animation-name:bounceIn;animation-duration:.6s;animation-iteration-count:1}.cdx-notify--success{background:#fafffe!important}.cdx-notify--success::before{background:#41ffb1!important}',""])},function(n,h){n.exports=function(n){var h=[];return h.toString=function(){return this.map((function(h){var p=function(n,h){var p=n[1]||"",g=n[3];if(!g)return p;if(h&&typeof btoa=="function"){var m=(x=g,"/*# sourceMappingURL=data:application/json;charset=utf-8;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(x))))+" */"),v=g.sources.map((function(n){return"/*# sourceURL="+g.sourceRoot+n+" */"}));return[p].concat(v).concat([m]).join("\n")}var x;return[p].join("\n")}(h,n);return h[2]?"@media "+h[2]+"{"+p+"}":p})).join("")},h.i=function(n,p){typeof n=="string"&&(n=[[null,n,""]]);for(var g={},m=0;m<this.length;m++){var v=this[m][0];typeof v=="number"&&(g[v]=!0)}for(m=0;m<n.length;m++){var x=n[m];typeof x[0]=="number"&&g[x[0]]||(p&&!x[2]?x[2]=p:p&&(x[2]="("+x[2]+") and ("+p+")"),h.push(x))}},h}},function(n,h,p){var g,m,v={},x=(g=function(){return window&&document&&document.all&&!window.atob},function(){return m===void 0&&(m=g.apply(this,arguments)),m}),w=function(n){var h={};return function(n){if(typeof n=="function")return n();if(h[n]===void 0){var p=function(n){return document.querySelector(n)}.call(this,n);if(window.HTMLIFrameElement&&p instanceof window.HTMLIFrameElement)try{p=p.contentDocument.head}catch{p=null}h[n]=p}return h[n]}}(),E=null,B=0,T=[],I=p(5);function f(n,h){for(var p=0;p<n.length;p++){var g=n[p],m=v[g.id];if(m){m.refs++;for(var x=0;x<m.parts.length;x++)m.parts[x](g.parts[x]);for(;x<g.parts.length;x++)m.parts.push(j(g.parts[x],h))}else{var w=[];for(x=0;x<g.parts.length;x++)w.push(j(g.parts[x],h));v[g.id]={id:g.id,refs:1,parts:w}}}}function k(n,h){for(var p=[],g={},m=0;m<n.length;m++){var v=n[m],x=h.base?v[0]+h.base:v[0],w={css:v[1],media:v[2],sourceMap:v[3]};g[x]?g[x].parts.push(w):p.push(g[x]={id:x,parts:[w]})}return p}function C(n,h){var p=w(n.insertInto);if(!p)throw new Error("Couldn't find a style target. This probably means that the value for the 'insertInto' parameter is invalid.");var g=T[T.length-1];if(n.insertAt==="top")g?g.nextSibling?p.insertBefore(h,g.nextSibling):p.appendChild(h):p.insertBefore(h,p.firstChild),T.push(h);else if(n.insertAt==="bottom")p.appendChild(h);else{if(typeof n.insertAt!="object"||!n.insertAt.before)throw new Error("[Style Loader]\n\n Invalid value for parameter 'insertAt' ('options.insertAt') found.\n Must be 'top', 'bottom', or Object.\n (https://github.com/webpack-contrib/style-loader#insertat)\n");var m=w(n.insertInto+" "+n.insertAt.before);p.insertBefore(h,m)}}function S(n){if(n.parentNode===null)return!1;n.parentNode.removeChild(n);var h=T.indexOf(n);h>=0&&T.splice(h,1)}function _(n){var h=document.createElement("style");return n.attrs.type===void 0&&(n.attrs.type="text/css"),ee(h,n.attrs),C(n,h),h}function ee(n,h){Object.keys(h).forEach((function(p){n.setAttribute(p,h[p])}))}function j(n,h){var p,g,m,v;if(h.transform&&n.css){if(!(v=h.transform(n.css)))return function(){};n.css=v}if(h.singleton){var x=B++;p=E||(E=_(h)),g=fe.bind(null,p,x,!1),m=fe.bind(null,p,x,!0)}else n.sourceMap&&typeof URL=="function"&&typeof URL.createObjectURL=="function"&&typeof URL.revokeObjectURL=="function"&&typeof Blob=="function"&&typeof btoa=="function"?(p=function(n){var h=document.createElement("link");return n.attrs.type===void 0&&(n.attrs.type="text/css"),n.attrs.rel="stylesheet",ee(h,n.attrs),C(n,h),h}(h),g=function(n,h,p){var g=p.css,m=p.sourceMap,v=h.convertToAbsoluteUrls===void 0&&m;(h.convertToAbsoluteUrls||v)&&(g=I(g)),m&&(g+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(m))))+" */");var x=new Blob([g],{type:"text/css"}),w=n.href;n.href=URL.createObjectURL(x),w&&URL.revokeObjectURL(w)}.bind(null,p,h),m=function(){S(p),p.href&&URL.revokeObjectURL(p.href)}):(p=_(h),g=function(n,h){var p=h.css,g=h.media;if(g&&n.setAttribute("media",g),n.styleSheet)n.styleSheet.cssText=p;else{for(;n.firstChild;)n.removeChild(n.firstChild);n.appendChild(document.createTextNode(p))}}.bind(null,p),m=function(){S(p)});return g(n),function(h){if(h){if(h.css===n.css&&h.media===n.media&&h.sourceMap===n.sourceMap)return;g(n=h)}else m()}}n.exports=function(n,h){if(typeof DEBUG<"u"&&DEBUG&&typeof document!="object")throw new Error("The style-loader cannot be used in a non-browser environment");(h=h||{}).attrs=typeof h.attrs=="object"?h.attrs:{},h.singleton||typeof h.singleton=="boolean"||(h.singleton=x()),h.insertInto||(h.insertInto="head"),h.insertAt||(h.insertAt="bottom");var p=k(n,h);return f(p,h),function(n){for(var g=[],m=0;m<p.length;m++){var x=p[m];(w=v[x.id]).refs--,g.push(w)}for(n&&f(k(n,h),h),m=0;m<g.length;m++){var w;if((w=g[m]).refs===0){for(var E=0;E<w.parts.length;E++)w.parts[E]();delete v[w.id]}}}};var M,A=(M=[],function(n,h){return M[n]=h,M.filter(Boolean).join("\n")});function fe(n,h,p,g){var m=p?"":g.css;if(n.styleSheet)n.styleSheet.cssText=A(h,m);else{var v=document.createTextNode(m),x=n.childNodes;x[h]&&n.removeChild(x[h]),x.length?n.insertBefore(v,x[h]):n.appendChild(v)}}},function(n,h){n.exports=function(n){var h=typeof window<"u"&&window.location;if(!h)throw new Error("fixUrls requires window.location");if(!n||typeof n!="string")return n;var p=h.protocol+"//"+h.host,g=p+h.pathname.replace(/\/[^\/]*$/,"/");return n.replace(/url\s*\(((?:[^)(]|\((?:[^)(]+|\([^)(]*\))*\))*)\)/gi,(function(n,h){var m,v=h.trim().replace(/^"(.*)"$/,(function(n,h){return h})).replace(/^'(.*)'$/,(function(n,h){return h}));return/^(#|data:|http:\/\/|https:\/\/|file:\/\/\/|\s*$)/i.test(v)?n:(m=v.indexOf("//")===0?v:v.indexOf("/")===0?p+v:g+v.replace(/^\.\//,""),"url("+JSON.stringify(m)+")")}))}},function(n,h,p){var g,m,v,x,w,E,B,T,I;n.exports=(g="cdx-notifies",m="cdx-notify",v="cdx-notify__cross",x="cdx-notify__button--confirm",w="cdx-notify__button--cancel",E="cdx-notify__input",B="cdx-notify__button",T="cdx-notify__btns-wrapper",{alert:I=function(n){var h=document.createElement("DIV"),p=document.createElement("DIV"),g=n.message,x=n.style;return h.classList.add(m),x&&h.classList.add(m+"--"+x),h.innerHTML=g,p.classList.add(v),p.addEventListener("click",h.remove.bind(h)),h.appendChild(p),h},confirm:function(n){var h=I(n),p=document.createElement("div"),g=document.createElement("button"),m=document.createElement("button"),E=h.querySelector("."+v),M=n.cancelHandler,A=n.okHandler;return p.classList.add(T),g.innerHTML=n.okText||"Confirm",m.innerHTML=n.cancelText||"Cancel",g.classList.add(B),m.classList.add(B),g.classList.add(x),m.classList.add(w),M&&typeof M=="function"&&(m.addEventListener("click",M),E.addEventListener("click",M)),A&&typeof A=="function"&&g.addEventListener("click",A),g.addEventListener("click",h.remove.bind(h)),m.addEventListener("click",h.remove.bind(h)),p.appendChild(g),p.appendChild(m),h.appendChild(p),h},prompt:function(n){var h=I(n),p=document.createElement("div"),g=document.createElement("button"),m=document.createElement("input"),w=h.querySelector("."+v),M=n.cancelHandler,A=n.okHandler;return p.classList.add(T),g.innerHTML=n.okText||"Ok",g.classList.add(B),g.classList.add(x),m.classList.add(E),n.placeholder&&m.setAttribute("placeholder",n.placeholder),n.default&&(m.value=n.default),n.inputType&&(m.type=n.inputType),M&&typeof M=="function"&&w.addEventListener("click",M),A&&typeof A=="function"&&g.addEventListener("click",(function(){A(m.value)})),g.addEventListener("click",h.remove.bind(h)),p.appendChild(m),p.appendChild(g),h.appendChild(p),h},getWrapper:function(){var n=document.createElement("DIV");return n.classList.add(g),n}})}])}))})(Y);var K=Y.exports;const W=Fe(K);class qo{
789
+ /**
790
+ * Show web notification
791
+ *
792
+ * @param {NotifierOptions | ConfirmNotifierOptions | PromptNotifierOptions} options - notification options
793
+ */
794
+ show(n){W.show(n)}}class Zo extends y{
795
+ /**
796
+ * @param moduleConfiguration - Module Configuration
797
+ * @param moduleConfiguration.config - Editor's config
798
+ * @param moduleConfiguration.eventsDispatcher - Editor's event dispatcher
799
+ */
800
+ constructor({config:n,eventsDispatcher:h}){super({config:n,eventsDispatcher:h}),this.notifier=new qo}get methods(){return{show:n=>this.show(n)}}
801
+ /**
802
+ * Show notification
803
+ *
804
+ * @param {NotifierOptions} options - message option
805
+ */show(n){return this.notifier.show(n)}}class Go extends y{get methods(){const e=()=>this.isEnabled;return{toggle:n=>this.toggle(n),get isEnabled(){return e()}}}
806
+ /**
807
+ * Set or toggle read-only state
808
+ *
809
+ * @param {boolean|undefined} state - set or toggle state
810
+ * @returns {boolean} current value
811
+ */toggle(n){return this.Editor.ReadOnly.toggle(n)}get isEnabled(){return this.Editor.ReadOnly.isEnabled}}var X={exports:{}};(function(n,h){(function(h,p){n.exports=p()})(0,(function(){function t(n){var h=n.tags,p=Object.keys(h),g=p.map((function(n){return typeof h[n]})).every((function(n){return n==="object"||n==="boolean"||n==="function"}));if(!g)throw new Error("The configuration was invalid");this.config=n}var n=["P","LI","TD","TH","DIV","H1","H2","H3","H4","H5","H6","PRE"];function i(h){return n.indexOf(h.nodeName)!==-1}var h=["A","B","STRONG","I","EM","SUB","SUP","U","STRIKE"];function r(n){return h.indexOf(n.nodeName)!==-1}t.prototype.clean=function(n){const h=document.implementation.createHTMLDocument(),p=h.createElement("div");return p.innerHTML=n,this._sanitize(h,p),p.innerHTML},t.prototype._sanitize=function(n,h){var p=l(n,h),g=p.firstChild();if(g)do{if(g.nodeType!==Node.TEXT_NODE){if(g.nodeType===Node.COMMENT_NODE){h.removeChild(g),this._sanitize(n,h);break}var m,v=r(g);v&&(m=Array.prototype.some.call(g.childNodes,i));var x=!!h.parentNode,w=i(h)&&i(g)&&x,E=g.nodeName.toLowerCase(),B=a(this.config,E,g),T=v&&m;if(T||c(g,B)||!this.config.keepNestedBlockElements&&w){if(!(g.nodeName==="SCRIPT"||g.nodeName==="STYLE"))for(;g.childNodes.length>0;)h.insertBefore(g.childNodes[0],g);h.removeChild(g),this._sanitize(n,h);break}for(var I=0;I<g.attributes.length;I+=1){var M=g.attributes[I];u(M,B,g)&&(g.removeAttribute(M.name),I-=1)}this._sanitize(n,g)}else if(g.data.trim()===""&&(g.previousElementSibling&&i(g.previousElementSibling)||g.nextElementSibling&&i(g.nextElementSibling))){h.removeChild(g),this._sanitize(n,h);break}}while(g=p.nextSibling())};function l(n,h){return n.createTreeWalker(h,NodeFilter.SHOW_TEXT|NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_COMMENT,null,!1)}function a(n,h,p){return typeof n.tags[h]=="function"?n.tags[h](p):n.tags[h]}function c(n,h){return typeof h>"u"||typeof h=="boolean"&&!h}function u(n,h,p){var g=n.name.toLowerCase();return h!==!0&&(typeof h[g]=="function"?!h[g](n.value,p):typeof h[g]>"u"||h[g]===!1||typeof h[g]=="string"&&h[g]!==n.value)}return t}))})(X);var Z=X.exports;const J=Fe(Z);function it(n,h){return n.map((n=>{const p=O(h)?h(n.tool):h;return V(p)||(n.data=st(n.data,p)),n}))}function q(n,h={}){const p={tags:h};return new J(p).clean(n)}function st(n,h){return Array.isArray(n)?ei(n,h):R(n)?ti(n,h):Q(n)?oi(n,h):n}function ei(n,h){return n.map((n=>st(n,h)))}function ti(n,h){const p={};for(const g in n){if(!Object.prototype.hasOwnProperty.call(n,g))continue;const m=n[g],v=ii(h[g])?h[g]:h;p[g]=st(m,v)}return p}function oi(n,h){return R(h)?q(n,h):h===!1?q(n,{}):n}function ii(n){return R(n)||yo(n)||O(n)}class si extends y{
812
+ /**
813
+ * Available methods
814
+ *
815
+ * @returns {SanitizerConfig}
816
+ */
817
+ get methods(){return{clean:(n,h)=>this.clean(n,h)}}
818
+ /**
819
+ * Perform sanitizing of a string
820
+ *
821
+ * @param {string} taintString - what to sanitize
822
+ * @param {SanitizerConfig} config - sanitizer config
823
+ * @returns {string}
824
+ */clean(n,h){return q(n,h)}}class ni extends y{
825
+ /**
826
+ * Available methods
827
+ *
828
+ * @returns {Saver}
829
+ */
830
+ get methods(){return{save:()=>this.save()}}
831
+ /**
832
+ * Return Editor's data
833
+ *
834
+ * @returns {OutputData}
835
+ */save(){const n="Editor's content can not be saved in read-only mode";return this.Editor.ReadOnly.isEnabled?(m(n,"warn"),Promise.reject(new Error(n))):this.Editor.Saver.save()}}class ri extends y{constructor(){super(...arguments),this.selectionUtils=new b
836
+ /**
837
+ * Available methods
838
+ *
839
+ * @returns {SelectionAPIInterface}
840
+ */}get methods(){return{findParentTag:(n,h)=>this.findParentTag(n,h),expandToTag:n=>this.expandToTag(n),save:()=>this.selectionUtils.save(),restore:()=>this.selectionUtils.restore(),setFakeBackground:()=>this.selectionUtils.setFakeBackground(),removeFakeBackground:()=>this.selectionUtils.removeFakeBackground()}}
841
+ /**
842
+ * Looks ahead from selection and find passed tag with class name
843
+ *
844
+ * @param {string} tagName - tag to find
845
+ * @param {string} className - tag's class name
846
+ * @returns {HTMLElement|null}
847
+ */findParentTag(n,h){return this.selectionUtils.findParentTag(n,h)}
848
+ /**
849
+ * Expand selection to passed tag
850
+ *
851
+ * @param {HTMLElement} node - tag that should contain selection
852
+ */expandToTag(n){this.selectionUtils.expandToTag(n)}}class li extends y{get methods(){return{getBlockTools:()=>Array.from(this.Editor.Tools.blockTools.values())}}}class ai extends y{get classes(){return{block:"cdx-block",inlineToolButton:"ce-inline-tool",inlineToolButtonActive:"ce-inline-tool--active",input:"cdx-input",loader:"cdx-loader",button:"cdx-button",settingsButton:"cdx-settings-button",settingsButtonActive:"cdx-settings-button--active"}}}class ci extends y{
853
+ /**
854
+ * Available methods
855
+ *
856
+ * @returns {Toolbar}
857
+ */
858
+ get methods(){return{close:()=>this.close(),open:()=>this.open(),toggleBlockSettings:n=>this.toggleBlockSettings(n),toggleToolbox:n=>this.toggleToolbox(n)}}open(){this.Editor.Toolbar.moveAndOpen()}close(){this.Editor.Toolbar.close()}
859
+ /**
860
+ * Toggles Block Setting of the current block
861
+ *
862
+ * @param {boolean} openingState — opening state of Block Setting
863
+ */toggleBlockSettings(n){this.Editor.BlockManager.currentBlockIndex!==-1?n??!this.Editor.BlockSettings.opened?(this.Editor.Toolbar.moveAndOpen(),this.Editor.BlockSettings.open()):this.Editor.BlockSettings.close():m("Could't toggle the Toolbar because there is no block selected ","warn")}
864
+ /**
865
+ * Open toolbox
866
+ *
867
+ * @param {boolean} openingState - Opening state of toolbox
868
+ */toggleToolbox(n){this.Editor.BlockManager.currentBlockIndex!==-1?n??!this.Editor.Toolbar.toolbox.opened?(this.Editor.Toolbar.moveAndOpen(),this.Editor.Toolbar.toolbox.open()):this.Editor.Toolbar.toolbox.close():m("Could't toggle the Toolbox because there is no block selected ","warn")}}var oe={exports:{}};(function(n,h){(function(h,p){n.exports=p()})(window,(function(){return function(n){var h={};function i(p){if(h[p])return h[p].exports;var g=h[p]={i:p,l:!1,exports:{}};return n[p].call(g.exports,g,g.exports,i),g.l=!0,g.exports}return i.m=n,i.c=h,i.d=function(n,h,p){i.o(n,h)||Object.defineProperty(n,h,{enumerable:!0,get:p})},i.r=function(n){typeof Symbol<"u"&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},i.t=function(n,h){if(1&h&&(n=i(n)),8&h||4&h&&typeof n=="object"&&n&&n.__esModule)return n;var p=Object.create(null);if(i.r(p),Object.defineProperty(p,"default",{enumerable:!0,value:n}),2&h&&typeof n!="string")for(var g in n)i.d(p,g,function(h){return n[h]}.bind(null,g));return p},i.n=function(n){var h=n&&n.__esModule?function(){return n.default}:function(){return n};return i.d(h,"a",h),h},i.o=function(n,h){return Object.prototype.hasOwnProperty.call(n,h)},i.p="",i(i.s=0)}([function(n,h,p){n.exports=p(1)},function(n,h,p){p.r(h),p.d(h,"default",(function(){return s}));class s{constructor(){this.nodes={wrapper:null,content:null},this.showed=!1,this.offsetTop=10,this.offsetLeft=10,this.offsetRight=10,this.hidingDelay=0,this.handleWindowScroll=()=>{this.showed&&this.hide(!0)},this.loadStyles(),this.prepare(),window.addEventListener("scroll",this.handleWindowScroll,{passive:!0})}get CSS(){return{tooltip:"ct",tooltipContent:"ct__content",tooltipShown:"ct--shown",placement:{left:"ct--left",bottom:"ct--bottom",right:"ct--right",top:"ct--top"}}}show(n,h,p){this.nodes.wrapper||this.prepare(),this.hidingTimeout&&clearTimeout(this.hidingTimeout);const g=Object.assign({placement:"bottom",marginTop:0,marginLeft:0,marginRight:0,marginBottom:0,delay:70,hidingDelay:0},p);if(g.hidingDelay&&(this.hidingDelay=g.hidingDelay),this.nodes.content.innerHTML="",typeof h=="string")this.nodes.content.appendChild(document.createTextNode(h));else{if(!(h instanceof Node))throw Error("[CodeX Tooltip] Wrong type of «content» passed. It should be an instance of Node or String. But "+typeof h+" given.");this.nodes.content.appendChild(h)}switch(this.nodes.wrapper.classList.remove(...Object.values(this.CSS.placement)),g.placement){case"top":this.placeTop(n,g);break;case"left":this.placeLeft(n,g);break;case"right":this.placeRight(n,g);break;case"bottom":default:this.placeBottom(n,g)}g&&g.delay?this.showingTimeout=setTimeout((()=>{this.nodes.wrapper.classList.add(this.CSS.tooltipShown),this.showed=!0}),g.delay):(this.nodes.wrapper.classList.add(this.CSS.tooltipShown),this.showed=!0)}hide(n=!1){if(this.hidingDelay&&!n)return this.hidingTimeout&&clearTimeout(this.hidingTimeout),void(this.hidingTimeout=setTimeout((()=>{this.hide(!0)}),this.hidingDelay));this.nodes.wrapper.classList.remove(this.CSS.tooltipShown),this.showed=!1,this.showingTimeout&&clearTimeout(this.showingTimeout)}onHover(n,h,p){n.addEventListener("mouseenter",(()=>{this.show(n,h,p)})),n.addEventListener("mouseleave",(()=>{this.hide()}))}destroy(){this.nodes.wrapper.remove(),window.removeEventListener("scroll",this.handleWindowScroll)}prepare(){this.nodes.wrapper=this.make("div",this.CSS.tooltip),this.nodes.content=this.make("div",this.CSS.tooltipContent),this.append(this.nodes.wrapper,this.nodes.content),this.append(document.body,this.nodes.wrapper)}loadStyles(){const n="codex-tooltips-style";if(document.getElementById(n))return;const h=p(2),g=this.make("style",null,{textContent:h.toString(),id:n});this.prepend(document.head,g)}placeBottom(n,h){const p=n.getBoundingClientRect(),g=p.left+n.clientWidth/2-this.nodes.wrapper.offsetWidth/2,m=p.bottom+window.pageYOffset+this.offsetTop+h.marginTop;this.applyPlacement("bottom",g,m)}placeTop(n,h){const p=n.getBoundingClientRect(),g=p.left+n.clientWidth/2-this.nodes.wrapper.offsetWidth/2,m=p.top+window.pageYOffset-this.nodes.wrapper.clientHeight-this.offsetTop;this.applyPlacement("top",g,m)}placeLeft(n,h){const p=n.getBoundingClientRect(),g=p.left-this.nodes.wrapper.offsetWidth-this.offsetLeft-h.marginLeft,m=p.top+window.pageYOffset+n.clientHeight/2-this.nodes.wrapper.offsetHeight/2;this.applyPlacement("left",g,m)}placeRight(n,h){const p=n.getBoundingClientRect(),g=p.right+this.offsetRight+h.marginRight,m=p.top+window.pageYOffset+n.clientHeight/2-this.nodes.wrapper.offsetHeight/2;this.applyPlacement("right",g,m)}applyPlacement(n,h,p){this.nodes.wrapper.classList.add(this.CSS.placement[n]),this.nodes.wrapper.style.left=h+"px",this.nodes.wrapper.style.top=p+"px"}make(n,h=null,p={}){const g=document.createElement(n);Array.isArray(h)?g.classList.add(...h):h&&g.classList.add(h);for(const n in p)p.hasOwnProperty(n)&&(g[n]=p[n]);return g}append(n,h){Array.isArray(h)?h.forEach((h=>n.appendChild(h))):n.appendChild(h)}prepend(n,h){Array.isArray(h)?(h=h.reverse()).forEach((h=>n.prepend(h))):n.prepend(h)}}},function(n,h){n.exports='.ct{z-index:999;opacity:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;pointer-events:none;-webkit-transition:opacity 50ms ease-in,-webkit-transform 70ms cubic-bezier(.215,.61,.355,1);transition:opacity 50ms ease-in,-webkit-transform 70ms cubic-bezier(.215,.61,.355,1);transition:opacity 50ms ease-in,transform 70ms cubic-bezier(.215,.61,.355,1);transition:opacity 50ms ease-in,transform 70ms cubic-bezier(.215,.61,.355,1),-webkit-transform 70ms cubic-bezier(.215,.61,.355,1);will-change:opacity,top,left;-webkit-box-shadow:0 8px 12px 0 rgba(29,32,43,.17),0 4px 5px -3px rgba(5,6,12,.49);box-shadow:0 8px 12px 0 rgba(29,32,43,.17),0 4px 5px -3px rgba(5,6,12,.49);border-radius:9px}.ct,.ct:before{position:absolute;top:0;left:0}.ct:before{content:"";bottom:0;right:0;background-color:#1d202b;z-index:-1;border-radius:4px}@supports(-webkit-mask-box-image:url("")){.ct:before{border-radius:0;-webkit-mask-box-image:url(\'data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path d="M10.71 0h2.58c3.02 0 4.64.42 6.1 1.2a8.18 8.18 0 013.4 3.4C23.6 6.07 24 7.7 24 10.71v2.58c0 3.02-.42 4.64-1.2 6.1a8.18 8.18 0 01-3.4 3.4c-1.47.8-3.1 1.21-6.11 1.21H10.7c-3.02 0-4.64-.42-6.1-1.2a8.18 8.18 0 01-3.4-3.4C.4 17.93 0 16.3 0 13.29V10.7c0-3.02.42-4.64 1.2-6.1a8.18 8.18 0 013.4-3.4C6.07.4 7.7 0 10.71 0z"/></svg>\') 48% 41% 37.9% 53.3%}}@media (--mobile){.ct{display:none}}.ct__content{padding:6px 10px;color:#cdd1e0;font-size:12px;text-align:center;letter-spacing:.02em;line-height:1em}.ct:after{content:"";width:8px;height:8px;position:absolute;background-color:#1d202b;z-index:-1}.ct--bottom{-webkit-transform:translateY(5px);transform:translateY(5px)}.ct--bottom:after{top:-3px;left:50%;-webkit-transform:translateX(-50%) rotate(-45deg);transform:translateX(-50%) rotate(-45deg)}.ct--top{-webkit-transform:translateY(-5px);transform:translateY(-5px)}.ct--top:after{top:auto;bottom:-3px;left:50%;-webkit-transform:translateX(-50%) rotate(-45deg);transform:translateX(-50%) rotate(-45deg)}.ct--left{-webkit-transform:translateX(-5px);transform:translateX(-5px)}.ct--left:after{top:50%;left:auto;right:0;-webkit-transform:translate(41.6%,-50%) rotate(-45deg);transform:translate(41.6%,-50%) rotate(-45deg)}.ct--right{-webkit-transform:translateX(5px);transform:translateX(5px)}.ct--right:after{top:50%;left:0;-webkit-transform:translate(-41.6%,-50%) rotate(-45deg);transform:translate(-41.6%,-50%) rotate(-45deg)}.ct--shown{opacity:1;-webkit-transform:none;transform:none}'}]).default}))})(oe);var ie=oe.exports;const ne=Fe(ie);let ce=null;function nt(){ce||(ce=new ne)}function ui(n,h,p){nt(),ce==null||ce.show(n,h,p)}function Ne(n=!1){nt(),ce==null||ce.hide(n)}function Pe(n,h,p){nt(),ce==null||ce.onHover(n,h,p)}function pi(){ce==null||ce.destroy(),ce=null}class fi extends y{
869
+ /**
870
+ * @class
871
+ * @param moduleConfiguration - Module Configuration
872
+ * @param moduleConfiguration.config - Editor's config
873
+ * @param moduleConfiguration.eventsDispatcher - Editor's event dispatcher
874
+ */
875
+ constructor({config:n,eventsDispatcher:h}){super({config:n,eventsDispatcher:h})}get methods(){return{show:(n,h,p)=>this.show(n,h,p),hide:()=>this.hide(),onHover:(n,h,p)=>this.onHover(n,h,p)}}
876
+ /**
877
+ * Method show tooltip on element with passed HTML content
878
+ *
879
+ * @param {HTMLElement} element - element on which tooltip should be shown
880
+ * @param {TooltipContent} content - tooltip content
881
+ * @param {TooltipOptions} options - tooltip options
882
+ */show(n,h,p){ui(n,h,p)}hide(){Ne()}
883
+ /**
884
+ * Decorator for showing Tooltip by mouseenter/mouseleave
885
+ *
886
+ * @param {HTMLElement} element - element on which tooltip should be shown
887
+ * @param {TooltipContent} content - tooltip content
888
+ * @param {TooltipOptions} options - tooltip options
889
+ */onHover(n,h,p){Pe(n,h,p)}}class gi extends y{get methods(){return{nodes:this.editorNodes}}get editorNodes(){return{wrapper:this.Editor.UI.nodes.wrapper,redactor:this.Editor.UI.nodes.redactor}}}function Yt(n,h){const p={};return Object.entries(n).forEach((([n,g])=>{if(R(g)){const m=h?`${h}.${n}`:n;Object.values(g).every((n=>Q(n)))?p[n]=m:p[n]=Yt(g,m)}else p[n]=g})),p}const de=Yt(I);function mi(n,h){const p={};return Object.keys(n).forEach((g=>{const m=h[g];m!==void 0?p[m]=n[g]:p[g]=n[g]})),p}const he=class ve{
890
+ /**
891
+ * @param {HTMLElement[]} nodeList — the list of iterable HTML-items
892
+ * @param {string} focusedCssClass - user-provided CSS-class that will be set in flipping process
893
+ */
894
+ constructor(n,h){this.cursor=-1,this.items=[],this.items=n||[],this.focusedCssClass=h
895
+ /**
896
+ * Returns Focused button Node
897
+ *
898
+ * @returns {HTMLElement}
899
+ */}get currentItem(){return this.cursor===-1?null:this.items[this.cursor]}
900
+ /**
901
+ * Sets cursor to specified position
902
+ *
903
+ * @param cursorPosition - new cursor position
904
+ */setCursor(n){n<this.items.length&&n>=-1&&(this.dropCursor(),this.cursor=n,this.items[this.cursor].classList.add(this.focusedCssClass)
905
+ /**
906
+ * Sets items. Can be used when iterable items changed dynamically
907
+ *
908
+ * @param {HTMLElement[]} nodeList - nodes to iterate
909
+ */)}setItems(n){this.items=n}next(){this.cursor=this.leafNodesAndReturnIndex(ve.directions.RIGHT)}previous(){this.cursor=this.leafNodesAndReturnIndex(ve.directions.LEFT)}dropCursor(){this.cursor!==-1&&(this.items[this.cursor].classList.remove(this.focusedCssClass),this.cursor=-1
910
+ /**
911
+ * Leafs nodes inside the target list from active element
912
+ *
913
+ * @param {string} direction - leaf direction. Can be 'left' or 'right'
914
+ * @returns {number} index of focused node
915
+ */)}leafNodesAndReturnIndex(n){if(this.items.length===0)return this.cursor;let h=this.cursor;return h===-1?h=n===ve.directions.RIGHT?-1:0:this.items[h].classList.remove(this.focusedCssClass),h=n===ve.directions.RIGHT?(h+1)%this.items.length:(this.items.length+h-1)%this.items.length,d.canSetCaret(this.items[h])&&Oe((()=>b.setCursor(this.items[h])),50)(),this.items[h].classList.add(this.focusedCssClass),h}};he.directions={RIGHT:"right",LEFT:"left"};let ge=he;class le{
916
+ /**
917
+ * @param options - different constructing settings
918
+ */
919
+ constructor(n){this.iterator=null,this.activated=!1,this.flipCallbacks=[],this.onKeyDown=n=>{if(this.isEventReadyForHandling(n))switch(le.usedKeys.includes(n.keyCode)&&n.preventDefault(),n.keyCode){case h.TAB:this.handleTabPress(n);break;case h.LEFT:case h.UP:this.flipLeft();break;case h.RIGHT:case h.DOWN:this.flipRight();break;case h.ENTER:this.handleEnterPress(n);break}},this.iterator=new ge(n.items,n.focusedItemClass),this.activateCallback=n.activateCallback,this.allowedKeys=n.allowedKeys||le.usedKeys}get isActivated(){return this.activated}static get usedKeys(){return[h.TAB,h.LEFT,h.RIGHT,h.ENTER,h.UP,h.DOWN]}
920
+ /**
921
+ * Active tab/arrows handling by flipper
922
+ *
923
+ * @param items - Some modules (like, InlineToolbar, BlockSettings) might refresh buttons dynamically
924
+ * @param cursorPosition - index of the item that should be focused once flipper is activated
925
+ */activate(n,h){this.activated=!0,n&&this.iterator.setItems(n),h!==void 0&&this.iterator.setCursor(h),document.addEventListener("keydown",this.onKeyDown,!0)}deactivate(){this.activated=!1,this.dropCursor(),document.removeEventListener("keydown",this.onKeyDown)}focusFirst(){this.dropCursor(),this.flipRight()}flipLeft(){this.iterator.previous(),this.flipCallback()}flipRight(){this.iterator.next(),this.flipCallback()}hasFocus(){return!!this.iterator.currentItem}
926
+ /**
927
+ * Registeres function that should be executed on each navigation action
928
+ *
929
+ * @param cb - function to execute
930
+ */onFlip(n){this.flipCallbacks.push(n)}
931
+ /**
932
+ * Unregisteres function that is executed on each navigation action
933
+ *
934
+ * @param cb - function to stop executing
935
+ */removeOnFlip(n){this.flipCallbacks=this.flipCallbacks.filter((h=>h!==n))}dropCursor(){this.iterator.dropCursor()}
936
+ /**
937
+ * This function is fired before handling flipper keycodes
938
+ * The result of this function defines if it is need to be handled or not
939
+ *
940
+ * @param {KeyboardEvent} event - keydown keyboard event
941
+ * @returns {boolean}
942
+ */isEventReadyForHandling(n){return this.activated&&this.allowedKeys.includes(n.keyCode)}
943
+ /**
944
+ * When flipper is activated tab press will leaf the items
945
+ *
946
+ * @param {KeyboardEvent} event - tab keydown event
947
+ */handleTabPress(n){switch(n.shiftKey?ge.directions.LEFT:ge.directions.RIGHT){case ge.directions.RIGHT:this.flipRight();break;case ge.directions.LEFT:this.flipLeft();break}}
948
+ /**
949
+ * Enter press will click current item if flipper is activated
950
+ *
951
+ * @param {KeyboardEvent} event - enter keydown event
952
+ */handleEnterPress(n){this.activated&&(this.iterator.currentItem&&(n.stopPropagation(),n.preventDefault(),this.iterator.currentItem.click()),O(this.activateCallback)&&this.activateCallback(this.iterator.currentItem))}flipCallback(){this.iterator.currentItem&&this.iterator.currentItem.scrollIntoViewIfNeeded(),this.flipCallbacks.forEach((n=>n()))}}const me='<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M9 12L9 7.1C9 7.04477 9.04477 7 9.1 7H10.4C11.5 7 14 7.1 14 9.5C14 9.5 14 12 11 12M9 12V16.8C9 16.9105 9.08954 17 9.2 17H12.5C14 17 15 16 15 14.5C15 11.7046 11 12 11 12M9 12H11"/></svg>',be='<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M7 10L11.8586 14.8586C11.9367 14.9367 12.0633 14.9367 12.1414 14.8586L17 10"/></svg>',ke='<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M14.5 17.5L9.64142 12.6414C9.56331 12.5633 9.56331 12.4367 9.64142 12.3586L14.5 7.5"/></svg>',ye='<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M9.58284 17.5L14.4414 12.6414C14.5195 12.5633 14.5195 12.4367 14.4414 12.3586L9.58284 7.5"/></svg>',Se='<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M7 15L11.8586 10.1414C11.9367 10.0633 12.0633 10.0633 12.1414 10.1414L17 15"/></svg>',Ie='<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M8 8L12 12M12 12L16 16M12 12L16 8M12 12L8 16"/></svg>',De='<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><circle cx="12" cy="12" r="4" stroke="currentColor" stroke-width="2"/></svg>',He='<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M13.34 10C12.4223 12.7337 11 17 11 17"/><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M14.21 7H14.2"/></svg>',Ue='<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M7.69998 12.6L7.67896 12.62C6.53993 13.7048 6.52012 15.5155 7.63516 16.625V16.625C8.72293 17.7073 10.4799 17.7102 11.5712 16.6314L13.0263 15.193C14.0703 14.1609 14.2141 12.525 13.3662 11.3266L13.22 11.12"/><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M16.22 11.12L16.3564 10.9805C17.2895 10.0265 17.3478 8.5207 16.4914 7.49733V7.49733C15.5691 6.39509 13.9269 6.25143 12.8271 7.17675L11.3901 8.38588C10.0935 9.47674 9.95706 11.4241 11.0888 12.6852L11.12 12.72"/></svg>',je='<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-width="2.6" d="M9.40999 7.29999H9.4"/><path stroke="currentColor" stroke-linecap="round" stroke-width="2.6" d="M14.6 7.29999H14.59"/><path stroke="currentColor" stroke-linecap="round" stroke-width="2.6" d="M9.30999 12H9.3"/><path stroke="currentColor" stroke-linecap="round" stroke-width="2.6" d="M14.6 12H14.59"/><path stroke="currentColor" stroke-linecap="round" stroke-width="2.6" d="M9.40999 16.7H9.4"/><path stroke="currentColor" stroke-linecap="round" stroke-width="2.6" d="M14.6 16.7H14.59"/></svg>',$e='<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M12 7V12M12 17V12M17 12H12M12 12H7"/></svg>',Ye='<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M11.5 17.5L5 11M5 11V15.5M5 11H9.5"/><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M12.5 6.5L19 13M19 13V8.5M19 13H14.5"/></svg>',Ke='<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><circle cx="10.5" cy="10.5" r="5.5" stroke="currentColor" stroke-width="2"/><line x1="15.4142" x2="19" y1="15" y2="18.5858" stroke="currentColor" stroke-linecap="round" stroke-width="2"/></svg>',We='<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M15.7795 11.5C15.7795 11.5 16.053 11.1962 16.5497 10.6722C17.4442 9.72856 17.4701 8.2475 16.5781 7.30145V7.30145C15.6482 6.31522 14.0873 6.29227 13.1288 7.25073L11.8796 8.49999"/><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M8.24517 12.3883C8.24517 12.3883 7.97171 12.6922 7.47504 13.2161C6.58051 14.1598 6.55467 15.6408 7.44666 16.5869V16.5869C8.37653 17.5731 9.93744 17.5961 10.8959 16.6376L12.1452 15.3883"/><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M17.7802 15.1032L16.597 14.9422C16.0109 14.8624 15.4841 15.3059 15.4627 15.8969L15.4199 17.0818"/><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M6.39064 9.03238L7.58432 9.06668C8.17551 9.08366 8.6522 8.58665 8.61056 7.99669L8.5271 6.81397"/><line x1="12.1142" x2="11.7" y1="12.2" y2="11.7858" stroke="currentColor" stroke-linecap="round" stroke-width="2"/></svg>',Ge='<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><rect width="14" height="14" x="5" y="5" stroke="currentColor" stroke-width="2" rx="4"/><line x1="12" x2="12" y1="9" y2="12" stroke="currentColor" stroke-linecap="round" stroke-width="2"/><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M12 15.02V15.01"/></svg>',Je="__",et="--";function te(n){return(h,p)=>[[n,h].filter((n=>!!n)).join(Je),p].filter((n=>!!n)).join(et)}const at=te("ce-hint"),lt={root:at(),alignedStart:at(null,"align-left"),alignedCenter:at(null,"align-center"),title:at("title"),description:at("description")};class Li{
953
+ /**
954
+ * Constructs the hint content instance
955
+ *
956
+ * @param params - hint content parameters
957
+ */
958
+ constructor(n){this.nodes={root:d.make("div",[lt.root,n.alignment==="center"?lt.alignedCenter:lt.alignedStart]),title:d.make("div",lt.title,{textContent:n.title})},this.nodes.root.appendChild(this.nodes.title),n.description!==void 0&&(this.nodes.description=d.make("div",lt.description,{textContent:n.description}),this.nodes.root.appendChild(this.nodes.description))}getElement(){return this.nodes.root}}class rt{
959
+ /**
960
+ * Constructs the instance
961
+ *
962
+ * @param params - instance parameters
963
+ */
964
+ constructor(n){this.params=n}get name(){if(this.params!==void 0&&"name"in this.params)return this.params.name}destroy(){Ne()}onChildrenOpen(){var n;this.params!==void 0&&"children"in this.params&&typeof((n=this.params.children)==null?void 0:n.onOpen)=="function"&&this.params.children.onOpen()}onChildrenClose(){var n;this.params!==void 0&&"children"in this.params&&typeof((n=this.params.children)==null?void 0:n.onClose)=="function"&&this.params.children.onClose()}handleClick(){var n,h;this.params!==void 0&&"onActivate"in this.params&&((h=(n=this.params).onActivate)==null||h.call(n,this.params))}
965
+ /**
966
+ * Adds hint to the item element if hint data is provided
967
+ *
968
+ * @param itemElement - popover item root element to add hint to
969
+ * @param hintData - hint data
970
+ */addHint(n,h){const p=new Li(h);Pe(n,p.getElement(),{placement:h.position,hidingDelay:100})}get children(){var n;return this.params!==void 0&&"children"in this.params&&((n=this.params.children)==null?void 0:n.items)!==void 0?this.params.children.items:[]}get hasChildren(){return this.children.length>0}get isChildrenOpen(){var n;return this.params!==void 0&&"children"in this.params&&((n=this.params.children)==null?void 0:n.isOpen)===!0}get isChildrenFlippable(){var n;return!(this.params===void 0||!("children"in this.params)||((n=this.params.children)==null?void 0:n.isFlippable)===!1)}get isChildrenSearchable(){var n;return this.params!==void 0&&"children"in this.params&&((n=this.params.children)==null?void 0:n.searchable)===!0}get closeOnActivate(){return this.params!==void 0&&"closeOnActivate"in this.params&&this.params.closeOnActivate}get isActive(){return this.params!==void 0&&"isActive"in this.params&&(typeof this.params.isActive=="function"?this.params.isActive():this.params.isActive===!0)}}const ct=te("ce-popover-item"),mt={container:ct(),active:ct(null,"active"),disabled:ct(null,"disabled"),focused:ct(null,"focused"),hidden:ct(null,"hidden"),confirmationState:ct(null,"confirmation"),noHover:ct(null,"no-hover"),noFocus:ct(null,"no-focus"),title:ct("title"),secondaryTitle:ct("secondary-title"),icon:ct("icon"),iconTool:ct("icon","tool"),iconChevronRight:ct("icon","chevron-right"),wobbleAnimation:te("wobble")()};class se extends rt{
971
+ /**
972
+ * Constructs popover item instance
973
+ *
974
+ * @param params - popover item construction params
975
+ * @param renderParams - popover item render params.
976
+ * The parameters that are not set by user via popover api but rather depend on technical implementation
977
+ */
978
+ constructor(n,h){super(n),this.params=n,this.nodes={root:null,icon:null},this.confirmationState=null,this.removeSpecialFocusBehavior=()=>{var n;(n=this.nodes.root)==null||n.classList.remove(mt.noFocus)},this.removeSpecialHoverBehavior=()=>{var n;(n=this.nodes.root)==null||n.classList.remove(mt.noHover)},this.onErrorAnimationEnd=()=>{var n,h;(n=this.nodes.icon)==null||n.classList.remove(mt.wobbleAnimation),(h=this.nodes.icon)==null||h.removeEventListener("animationend",this.onErrorAnimationEnd)},this.nodes.root=this.make(n,h)}get isDisabled(){return this.params.isDisabled===!0}get toggle(){return this.params.toggle}get title(){return this.params.title}get isConfirmationStateEnabled(){return this.confirmationState!==null}get isFocused(){return this.nodes.root!==null&&this.nodes.root.classList.contains(mt.focused)}getElement(){return this.nodes.root}handleClick(){this.isConfirmationStateEnabled&&this.confirmationState!==null?this.activateOrEnableConfirmationMode(this.confirmationState):this.activateOrEnableConfirmationMode(this.params)}
979
+ /**
980
+ * Toggles item active state
981
+ *
982
+ * @param isActive - true if item should strictly should become active
983
+ */toggleActive(n){var h;(h=this.nodes.root)==null||h.classList.toggle(mt.active,n)}
984
+ /**
985
+ * Toggles item hidden state
986
+ *
987
+ * @param isHidden - true if item should be hidden
988
+ */toggleHidden(n){var h;(h=this.nodes.root)==null||h.classList.toggle(mt.hidden,n)}reset(){this.isConfirmationStateEnabled&&this.disableConfirmationMode()}onFocus(){this.disableSpecialHoverAndFocusBehavior()}
989
+ /**
990
+ * Constructs HTML element corresponding to popover item params
991
+ *
992
+ * @param params - item construction params
993
+ * @param renderParams - popover item render params
994
+ */make(n,h){var p,g;const m=(h==null?void 0:h.wrapperTag)||"div",v=d.make(m,mt.container,{type:m==="button"?"button":void 0});return n.name&&(v.dataset.itemName=n.name),this.nodes.icon=d.make("div",[mt.icon,mt.iconTool],{innerHTML:n.icon||De}),v.appendChild(this.nodes.icon),n.title!==void 0&&v.appendChild(d.make("div",mt.title,{innerHTML:n.title||""})),n.secondaryLabel&&v.appendChild(d.make("div",mt.secondaryTitle,{textContent:n.secondaryLabel})),this.hasChildren&&v.appendChild(d.make("div",[mt.icon,mt.iconChevronRight],{innerHTML:ye})),this.isActive&&v.classList.add(mt.active),n.isDisabled&&v.classList.add(mt.disabled),n.hint!==void 0&&((p=h==null?void 0:h.hint)==null?void 0:p.enabled)!==!1&&this.addHint(v,{...n.hint,position:((g=h==null?void 0:h.hint)==null?void 0:g.position)||"right"}),v
995
+ /**
996
+ * Activates confirmation mode for the item.
997
+ *
998
+ * @param newState - new popover item params that should be applied
999
+ */}enableConfirmationMode(n){if(this.nodes.root===null)return;const h={...this.params,...n,confirmation:"confirmation"in n?n.confirmation:void 0},p=this.make(h);this.nodes.root.innerHTML=p.innerHTML,this.nodes.root.classList.add(mt.confirmationState),this.confirmationState=n,this.enableSpecialHoverAndFocusBehavior()}disableConfirmationMode(){if(this.nodes.root===null)return;const n=this.make(this.params);this.nodes.root.innerHTML=n.innerHTML,this.nodes.root.classList.remove(mt.confirmationState),this.confirmationState=null,this.disableSpecialHoverAndFocusBehavior()}enableSpecialHoverAndFocusBehavior(){var n,h,p;(n=this.nodes.root)==null||n.classList.add(mt.noHover),(h=this.nodes.root)==null||h.classList.add(mt.noFocus),(p=this.nodes.root)==null||p.addEventListener("mouseleave",this.removeSpecialHoverBehavior,{once:!0})}disableSpecialHoverAndFocusBehavior(){var n;this.removeSpecialFocusBehavior(),this.removeSpecialHoverBehavior(),(n=this.nodes.root)==null||n.removeEventListener("mouseleave",this.removeSpecialHoverBehavior)
1000
+ /**
1001
+ * Executes item's onActivate callback if the item has no confirmation configured
1002
+ *
1003
+ * @param item - item to activate or bring to confirmation mode
1004
+ */}activateOrEnableConfirmationMode(n){var h;if("confirmation"in n&&n.confirmation!==void 0)this.enableConfirmationMode(n.confirmation);else try{(h=n.onActivate)==null||h.call(n,n),this.disableConfirmationMode()}catch{this.animateError()}}animateError(){var n,h,p;(n=this.nodes.icon)!=null&&n.classList.contains(mt.wobbleAnimation)||((h=this.nodes.icon)==null||h.classList.add(mt.wobbleAnimation),(p=this.nodes.icon)==null||p.addEventListener("animationend",this.onErrorAnimationEnd))}}const yt=te("ce-popover-item-separator"),Et={container:yt(),line:yt("line"),hidden:yt(null,"hidden")};class Xt extends rt{constructor(){super(),this.nodes={root:d.make("div",Et.container),line:d.make("div",Et.line)},this.nodes.root.appendChild(this.nodes.line)}getElement(){return this.nodes.root}
1005
+ /**
1006
+ * Toggles item hidden state
1007
+ *
1008
+ * @param isHidden - true if item should be hidden
1009
+ */toggleHidden(n){var h;(h=this.nodes.root)==null||h.classList.toggle(Et.hidden,n)}}var Bt=(n=>(n.Closed="closed",n.ClosedOnActivate="closed-on-activate",n))(Bt||{});const Ct=te("ce-popover"),Tt={popover:Ct(),popoverContainer:Ct("container"),popoverOpenTop:Ct(null,"open-top"),popoverOpenLeft:Ct(null,"open-left"),popoverOpened:Ct(null,"opened"),search:Ct("search"),nothingFoundMessage:Ct("nothing-found-message"),nothingFoundMessageDisplayed:Ct("nothing-found-message","displayed"),items:Ct("items"),overlay:Ct("overlay"),overlayHidden:Ct("overlay","hidden"),popoverNested:Ct(null,"nested"),getPopoverNestedClass:n=>Ct(null,`nested-level-${n.toString()}`),popoverInline:Ct(null,"inline"),popoverHeader:Ct("header")};var St=(n=>(n.NestingLevel="--nesting-level",n.PopoverHeight="--popover-height",n.InlinePopoverWidth="--inline-popover-width",n.TriggerItemLeft="--trigger-item-left",n.TriggerItemTop="--trigger-item-top",n))(St||{});const It=te("ce-popover-item-html"),Ot={root:It(),hidden:It(null,"hidden")};class Ee extends rt{
1010
+ /**
1011
+ * Constructs the instance
1012
+ *
1013
+ * @param params – instance parameters
1014
+ * @param renderParams – popover item render params.
1015
+ * The parameters that are not set by user via popover api but rather depend on technical implementation
1016
+ */
1017
+ constructor(n,h){var p,g;super(n),this.nodes={root:d.make("div",Ot.root)},this.nodes.root.appendChild(n.element),n.name&&(this.nodes.root.dataset.itemName=n.name),n.hint!==void 0&&((p=h==null?void 0:h.hint)==null?void 0:p.enabled)!==!1&&this.addHint(this.nodes.root,{...n.hint,position:((g=h==null?void 0:h.hint)==null?void 0:g.position)||"right"})}getElement(){return this.nodes.root}
1018
+ /**
1019
+ * Toggles item hidden state
1020
+ *
1021
+ * @param isHidden - true if item should be hidden
1022
+ */toggleHidden(n){var h;(h=this.nodes.root)==null||h.classList.toggle(Ot.hidden,n)}getControls(){const n=this.nodes.root.querySelectorAll(`button, ${d.allInputsSelector}`);return Array.from(n)}}class Vt extends Te{
1023
+ /**
1024
+ * Constructs the instance
1025
+ *
1026
+ * @param params - popover construction params
1027
+ * @param itemsRenderParams - popover item render params.
1028
+ * The parameters that are not set by user via popover api but rather depend on technical implementation
1029
+ */
1030
+ constructor(n,h={}){super(),this.params=n,this.itemsRenderParams=h,this.listeners=new Ce,this.messages={nothingFound:"Nothing found",search:"Search"},this.items=this.buildItems(n.items),n.messages&&(this.messages={...this.messages,...n.messages}),this.nodes={},this.nodes.popoverContainer=d.make("div",[Tt.popoverContainer]),this.nodes.nothingFoundMessage=d.make("div",[Tt.nothingFoundMessage],{textContent:this.messages.nothingFound}),this.nodes.popoverContainer.appendChild(this.nodes.nothingFoundMessage),this.nodes.items=d.make("div",[Tt.items]),this.items.forEach((n=>{const h=n.getElement();h!==null&&this.nodes.items.appendChild(h)})),this.nodes.popoverContainer.appendChild(this.nodes.items),this.listeners.on(this.nodes.popoverContainer,"click",(n=>this.handleClick(n))),this.nodes.popover=d.make("div",[Tt.popover,this.params.class]),this.nodes.popover.appendChild(this.nodes.popoverContainer)}get itemsDefault(){return this.items.filter((n=>n instanceof se))}getElement(){return this.nodes.popover}show(){this.nodes.popover.classList.add(Tt.popoverOpened),this.search!==void 0&&this.search.focus()}hide(){this.nodes.popover.classList.remove(Tt.popoverOpened),this.nodes.popover.classList.remove(Tt.popoverOpenTop),this.itemsDefault.forEach((n=>n.reset())),this.search!==void 0&&this.search.clear(),this.emit(Bt.Closed)}destroy(){var n;this.items.forEach((n=>n.destroy())),this.nodes.popover.remove(),this.listeners.removeAll(),(n=this.search)==null||n.destroy()
1031
+ /**
1032
+ * Looks for the item by name and imitates click on it
1033
+ *
1034
+ * @param name - name of the item to activate
1035
+ */}activateItemByName(n){const h=this.items.find((h=>h.name===n));this.handleItemClick(h)}
1036
+ /**
1037
+ * Factory method for creating popover items
1038
+ *
1039
+ * @param items - list of items params
1040
+ */buildItems(n){return n.map((n=>{switch(n.type){case U.Separator:return new Xt;case U.Html:return new Ee(n,this.itemsRenderParams[U.Html]);default:return new se(n,this.itemsRenderParams[U.Default])}}))}
1041
+ /**
1042
+ * Retrieves popover item that is the target of the specified event
1043
+ *
1044
+ * @param event - event to retrieve popover item from
1045
+ */getTargetItem(n){return this.items.filter((n=>n instanceof se||n instanceof Ee)).find((h=>{const p=h.getElement();return p!==null&&n.composedPath().includes(p)}))}
1046
+ /**
1047
+ * Handles popover item click
1048
+ *
1049
+ * @param item - item to handle click of
1050
+ */handleItemClick(n){if(!("isDisabled"in n&&n.isDisabled)){if(n.hasChildren){this.showNestedItems(n),"handleClick"in n&&typeof n.handleClick=="function"&&n.handleClick();return}this.itemsDefault.filter((h=>h!==n)).forEach((n=>n.reset())),"handleClick"in n&&typeof n.handleClick=="function"&&n.handleClick(),this.toggleItemActivenessIfNeeded(n),n.closeOnActivate&&(this.hide(),this.emit(Bt.ClosedOnActivate))}}
1051
+ /**
1052
+ * Handles clicks inside popover
1053
+ *
1054
+ * @param event - item to handle click of
1055
+ */handleClick(n){const h=this.getTargetItem(n);h!==void 0&&this.handleItemClick(h)}
1056
+ /**
1057
+ * - Toggles item active state, if clicked popover item has property 'toggle' set to true.
1058
+ *
1059
+ * - Performs radiobutton-like behavior if the item has property 'toggle' set to string key.
1060
+ * (All the other items with the same key get inactive, and the item gets active)
1061
+ *
1062
+ * @param clickedItem - popover item that was clicked
1063
+ */toggleItemActivenessIfNeeded(n){if(n instanceof se&&(n.toggle===!0&&n.toggleActive(),typeof n.toggle=="string")){const h=this.itemsDefault.filter((h=>h.toggle===n.toggle));if(h.length===1){n.toggleActive();return}h.forEach((h=>{h.toggleActive(h===n)}))}}}var _t=(n=>(n.Search="search",n))(_t||{});const Nt=te("cdx-search-field"),Dt={wrapper:Nt(),icon:Nt("icon"),input:Nt("input")};class _i extends Te{
1064
+ /**
1065
+ * @param options - available config
1066
+ * @param options.items - searchable items list
1067
+ * @param options.placeholder - input placeholder
1068
+ */
1069
+ constructor({items:n,placeholder:h}){super(),this.listeners=new Ce,this.items=n,this.wrapper=d.make("div",Dt.wrapper);const p=d.make("div",Dt.icon,{innerHTML:Ke});this.input=d.make("input",Dt.input,{placeholder:h,tabIndex:-1}),this.wrapper.appendChild(p),this.wrapper.appendChild(this.input),this.listeners.on(this.input,"input",(()=>{this.searchQuery=this.input.value,this.emit(_t.Search,{query:this.searchQuery,items:this.foundItems})}))}getElement(){return this.wrapper}focus(){this.input.focus()}clear(){this.input.value="",this.searchQuery="",this.emit(_t.Search,{query:"",items:this.foundItems})}destroy(){this.listeners.removeAll()}get foundItems(){return this.items.filter((n=>this.checkItem(n)))}
1070
+ /**
1071
+ * Contains logic for checking whether passed item conforms the search query
1072
+ *
1073
+ * @param item - item to be checked
1074
+ */checkItem(n){var h,p;const g=((h=n.title)==null?void 0:h.toLowerCase())||"",m=(p=this.searchQuery)==null?void 0:p.toLowerCase();return m!==void 0&&g.includes(m)}}var Rt=Object.defineProperty,Ft=Object.getOwnPropertyDescriptor,Di=(n,h,p,g)=>{for(var m,v=g>1?void 0:g?Ft(h,p):h,x=n.length-1;x>=0;x--)(m=n[x])&&(v=(g?m(h,p,v):m(v))||v);return g&&v&&Rt(h,p,v),v};const Ut=class Zt extends Vt{
1075
+ /**
1076
+ * Construct the instance
1077
+ *
1078
+ * @param params - popover params
1079
+ * @param itemsRenderParams – popover item render params.
1080
+ * The parameters that are not set by user via popover api but rather depend on technical implementation
1081
+ */
1082
+ constructor(n,p){super(n,p),this.nestingLevel=0,this.nestedPopoverTriggerItem=null,this.previouslyHoveredItem=null,this.scopeElement=document.body,this.hide=()=>{var n;super.hide(),this.destroyNestedPopoverIfExists(),(n=this.flipper)==null||n.deactivate(),this.previouslyHoveredItem=null},this.onFlip=()=>{const n=this.itemsDefault.find((n=>n.isFocused));n==null||n.onFocus()},this.onSearch=n=>{var h;const p=n.query==="",g=n.items.length===0;this.items.forEach((h=>{let m=!1;h instanceof se?m=!n.items.includes(h):(h instanceof Xt||h instanceof Ee)&&(m=g||!p),h.toggleHidden(m)})),this.toggleNothingFoundMessage(g);const m=n.query===""?this.flippableElements:n.items.map((n=>n.getElement()));(h=this.flipper)!=null&&h.isActivated&&(this.flipper.deactivate(),this.flipper.activate(m))},n.nestingLevel!==void 0&&(this.nestingLevel=n.nestingLevel),this.nestingLevel>0&&this.nodes.popover.classList.add(Tt.popoverNested),n.scopeElement!==void 0&&(this.scopeElement=n.scopeElement),this.nodes.popoverContainer!==null&&this.listeners.on(this.nodes.popoverContainer,"mouseover",(n=>this.handleHover(n))),n.searchable&&this.addSearch(),n.flippable!==!1&&(this.flipper=new le({items:this.flippableElements,focusedItemClass:mt.focused,allowedKeys:[h.TAB,h.UP,h.DOWN,h.ENTER]}),this.flipper.onFlip(this.onFlip))}hasFocus(){return this.flipper!==void 0&&this.flipper.hasFocus()}get scrollTop(){return this.nodes.items===null?0:this.nodes.items.scrollTop}get offsetTop(){return this.nodes.popoverContainer===null?0:this.nodes.popoverContainer.offsetTop}show(){var n;this.nodes.popover.style.setProperty(St.PopoverHeight,this.size.height+"px"),this.shouldOpenBottom||this.nodes.popover.classList.add(Tt.popoverOpenTop),this.shouldOpenRight||this.nodes.popover.classList.add(Tt.popoverOpenLeft),super.show(),(n=this.flipper)==null||n.activate(this.flippableElements)}destroy(){this.hide(),super.destroy()
1083
+ /**
1084
+ * Handles displaying nested items for the item.
1085
+ *
1086
+ * @param item – item to show nested popover for
1087
+ */}showNestedItems(n){this.nestedPopover!==null&&this.nestedPopover!==void 0||(this.nestedPopoverTriggerItem=n,this.showNestedPopoverForItem(n)
1088
+ /**
1089
+ * Handles hover events inside popover items container
1090
+ *
1091
+ * @param event - hover event data
1092
+ */)}handleHover(n){const h=this.getTargetItem(n);h!==void 0&&this.previouslyHoveredItem!==h&&(this.destroyNestedPopoverIfExists(),this.previouslyHoveredItem=h,h.hasChildren&&this.showNestedPopoverForItem(h)
1093
+ /**
1094
+ * Sets CSS variable with position of item near which nested popover should be displayed.
1095
+ * Is used for correct positioning of the nested popover
1096
+ *
1097
+ * @param nestedPopoverEl - nested popover element
1098
+ * @param item – item near which nested popover should be displayed
1099
+ */)}setTriggerItemPosition(n,h){const p=h.getElement(),g=(p?p.offsetTop:0)-this.scrollTop,m=this.offsetTop+g;n.style.setProperty(St.TriggerItemTop,m+"px")}destroyNestedPopoverIfExists(){var n,h;this.nestedPopover===void 0||this.nestedPopover===null||(this.nestedPopover.off(Bt.ClosedOnActivate,this.hide),this.nestedPopover.hide(),this.nestedPopover.destroy(),this.nestedPopover.getElement().remove(),this.nestedPopover=null,(n=this.flipper)==null||n.activate(this.flippableElements),(h=this.nestedPopoverTriggerItem)==null||h.onChildrenClose()
1100
+ /**
1101
+ * Creates and displays nested popover for specified item.
1102
+ * Is used only on desktop
1103
+ *
1104
+ * @param item - item to display nested popover by
1105
+ */)}showNestedPopoverForItem(n){var h;this.nestedPopover=new Zt({searchable:n.isChildrenSearchable,items:n.children,nestingLevel:this.nestingLevel+1,flippable:n.isChildrenFlippable,messages:this.messages}),n.onChildrenOpen(),this.nestedPopover.on(Bt.ClosedOnActivate,this.hide);const p=this.nestedPopover.getElement();return this.nodes.popover.appendChild(p),this.setTriggerItemPosition(p,n),p.style.setProperty(St.NestingLevel,this.nestedPopover.nestingLevel.toString()),this.nestedPopover.show(),(h=this.flipper)==null||h.deactivate(),this.nestedPopover}get shouldOpenBottom(){if(this.nodes.popover===void 0||this.nodes.popover===null)return!1;const n=this.nodes.popoverContainer.getBoundingClientRect(),h=this.scopeElement.getBoundingClientRect(),p=this.size.height,g=n.top+p,m=n.top-p,v=Math.min(window.innerHeight,h.bottom);return m<h.top||g<=v}get shouldOpenRight(){if(this.nodes.popover===void 0||this.nodes.popover===null)return!1;const n=this.nodes.popover.getBoundingClientRect(),h=this.scopeElement.getBoundingClientRect(),p=this.size.width,g=n.right+p,m=n.left-p,v=Math.min(window.innerWidth,h.right);return m<h.left||g<=v}get size(){var n;const h={height:0,width:0};if(this.nodes.popover===null)return h;const p=this.nodes.popover.cloneNode(!0);p.style.visibility="hidden",p.style.position="absolute",p.style.top="-1000px",p.classList.add(Tt.popoverOpened),(n=p.querySelector("."+Tt.popoverNested))==null||n.remove(),document.body.appendChild(p);const g=p.querySelector("."+Tt.popoverContainer);return h.height=g.offsetHeight,h.width=g.offsetWidth,p.remove(),h}get flippableElements(){return this.items.map((n=>n instanceof se?n.getElement():n instanceof Ee?n.getControls():void 0)).flat().filter((n=>n!=null))}addSearch(){this.search=new _i({items:this.itemsDefault,placeholder:this.messages.search}),this.search.on(_t.Search,this.onSearch);const n=this.search.getElement();n.classList.add(Tt.search),this.nodes.popoverContainer.insertBefore(n,this.nodes.popoverContainer.firstChild)
1106
+ /**
1107
+ * Toggles nothing found message visibility
1108
+ *
1109
+ * @param isDisplayed - true if the message should be displayed
1110
+ */}toggleNothingFoundMessage(n){this.nodes.nothingFoundMessage.classList.toggle(Tt.nothingFoundMessageDisplayed,n)}};Di([ue],Ut.prototype,"size",1);let jt=Ut;class Ri extends jt{
1111
+ /**
1112
+ * Constructs the instance
1113
+ *
1114
+ * @param params - instance parameters
1115
+ */
1116
+ constructor(n){const h=!pe();super({...n,class:Tt.popoverInline},{[U.Default]:{wrapperTag:"button",hint:{position:"top",alignment:"center",enabled:h}},[U.Html]:{hint:{position:"top",alignment:"center",enabled:h}}}),this.items.forEach((n=>{!(n instanceof se)&&!(n instanceof Ee)||n.hasChildren&&n.isChildrenOpen&&this.showNestedItems(n)}))}get offsetLeft(){return this.nodes.popoverContainer===null?0:this.nodes.popoverContainer.offsetLeft}show(){this.nestingLevel===0&&this.nodes.popover.style.setProperty(St.InlinePopoverWidth,this.size.width+"px"),super.show()}handleHover(){}
1117
+ /**
1118
+ * Sets CSS variable with position of item near which nested popover should be displayed.
1119
+ * Is used to position nested popover right below clicked item
1120
+ *
1121
+ * @param nestedPopoverEl - nested popover element
1122
+ * @param item – item near which nested popover should be displayed
1123
+ */setTriggerItemPosition(n,h){const p=h.getElement(),g=p?p.offsetLeft:0,m=this.offsetLeft+g;n.style.setProperty(St.TriggerItemLeft,m+"px")}
1124
+ /**
1125
+ * Handles displaying nested items for the item.
1126
+ * Overriding in order to add toggling behaviour
1127
+ *
1128
+ * @param item – item to toggle nested popover for
1129
+ */showNestedItems(n){this.nestedPopoverTriggerItem!==n?super.showNestedItems(n):(this.destroyNestedPopoverIfExists(),this.nestedPopoverTriggerItem=null)}
1130
+ /**
1131
+ * Creates and displays nested popover for specified item.
1132
+ * Is used only on desktop
1133
+ *
1134
+ * @param item - item to display nested popover by
1135
+ */showNestedPopoverForItem(n){const h=super.showNestedPopoverForItem(n);return h.getElement().classList.add(Tt.getPopoverNestedClass(h.nestingLevel)),h
1136
+ /**
1137
+ * Overrides default item click handling.
1138
+ * Helps to close nested popover once other item is clicked.
1139
+ *
1140
+ * @param item - clicked item
1141
+ */}handleItemClick(n){var h;n!==this.nestedPopoverTriggerItem&&((h=this.nestedPopoverTriggerItem)==null||h.handleClick(),super.destroyNestedPopoverIfExists()),super.handleItemClick(n)}}const $t=class we{constructor(){this.scrollPosition=null}lock(){x?this.lockHard():document.body.classList.add(we.CSS.scrollLocked)}unlock(){x?this.unlockHard():document.body.classList.remove(we.CSS.scrollLocked)}lockHard(){this.scrollPosition=window.pageYOffset,document.documentElement.style.setProperty("--window-scroll-offset",`${this.scrollPosition}px`),document.body.classList.add(we.CSS.scrollLockedHard)}unlockHard(){document.body.classList.remove(we.CSS.scrollLockedHard),this.scrollPosition!==null&&window.scrollTo(0,this.scrollPosition),this.scrollPosition=null}};$t.CSS={scrollLocked:"ce-scroll-locked",scrollLockedHard:"ce-scroll-locked--hard"};let Kt=$t;const Wt=te("ce-popover-header"),qt={root:Wt(),text:Wt("text"),backButton:Wt("back-button")};class Hi{
1142
+ /**
1143
+ * Constructs the instance
1144
+ *
1145
+ * @param params - popover header params
1146
+ */
1147
+ constructor({text:n,onBackButtonClick:h}){this.listeners=new Ce,this.text=n,this.onBackButtonClick=h,this.nodes={root:d.make("div",[qt.root]),backButton:d.make("button",[qt.backButton]),text:d.make("div",[qt.text])},this.nodes.backButton.innerHTML=ke,this.nodes.root.appendChild(this.nodes.backButton),this.listeners.on(this.nodes.backButton,"click",this.onBackButtonClick),this.nodes.text.innerText=this.text,this.nodes.root.appendChild(this.nodes.text)}getElement(){return this.nodes.root}destroy(){this.nodes.root.remove(),this.listeners.destroy()}}class zi{constructor(){this.history=[]}
1148
+ /**
1149
+ * Push new popover state
1150
+ *
1151
+ * @param state - new state
1152
+ */push(n){this.history.push(n)}pop(){return this.history.pop()}get currentTitle(){return this.history.length===0?"":this.history[this.history.length-1].title}get currentItems(){return this.history.length===0?[]:this.history[this.history.length-1].items}reset(){for(;this.history.length>1;)this.pop()}}class Jt extends Vt{
1153
+ /**
1154
+ * Construct the instance
1155
+ *
1156
+ * @param params - popover params
1157
+ */
1158
+ constructor(n){super(n,{[U.Default]:{hint:{enabled:!1}},[U.Html]:{hint:{enabled:!1}}}),this.scrollLocker=new Kt,this.history=new zi,this.isHidden=!0,this.nodes.overlay=d.make("div",[Tt.overlay,Tt.overlayHidden]),this.nodes.popover.insertBefore(this.nodes.overlay,this.nodes.popover.firstChild),this.listeners.on(this.nodes.overlay,"click",(()=>{this.hide()})),this.history.push({items:n.items})}show(){this.nodes.overlay.classList.remove(Tt.overlayHidden),super.show(),this.scrollLocker.lock(),this.isHidden=!1}hide(){this.isHidden||(super.hide(),this.nodes.overlay.classList.add(Tt.overlayHidden),this.scrollLocker.unlock(),this.history.reset(),this.isHidden=!0)}destroy(){super.destroy(),this.scrollLocker.unlock()
1159
+ /**
1160
+ * Handles displaying nested items for the item
1161
+ *
1162
+ * @param item – item to show nested popover for
1163
+ */}showNestedItems(n){this.updateItemsAndHeader(n.children,n.title),this.history.push({title:n.title,items:n.children})
1164
+ /**
1165
+ * Removes rendered popover items and header and displays new ones
1166
+ *
1167
+ * @param items - new popover items
1168
+ * @param title - new popover header text
1169
+ */}updateItemsAndHeader(n,h){if(this.header!==null&&this.header!==void 0&&(this.header.destroy(),this.header=null),h!==void 0){this.header=new Hi({text:h,onBackButtonClick:()=>{this.history.pop(),this.updateItemsAndHeader(this.history.currentItems,this.history.currentTitle)}});const n=this.header.getElement();n!==null&&this.nodes.popoverContainer.insertBefore(n,this.nodes.popoverContainer.firstChild)}this.items.forEach((n=>{var h;return(h=n.getElement())==null?void 0:h.remove()})),this.items=this.buildItems(n),this.items.forEach((n=>{var h;const p=n.getElement();p!==null&&((h=this.nodes.items)==null||h.appendChild(p))}))}}class Ui extends y{constructor(){super(...arguments),this.opened=!1,this.selection=new b,this.popover=null,this.close=()=>{this.opened&&(this.opened=!1,b.isAtEditor||this.selection.restore(),this.selection.clearSaved(),!this.Editor.CrossBlockSelection.isCrossBlockSelectionStarted&&this.Editor.BlockManager.currentBlock&&this.Editor.BlockSelection.unselectBlock(this.Editor.BlockManager.currentBlock),this.eventsDispatcher.emit(this.events.closed),this.popover&&(this.popover.off(Bt.Closed,this.onPopoverClose),this.popover.destroy(),this.popover.getElement().remove(),this.popover=null))},this.onPopoverClose=()=>{this.close()}}get events(){return{opened:"block-settings-opened",closed:"block-settings-closed"}}get CSS(){return{settings:"ce-settings"}}get flipper(){var n;if(this.popover!==null)return"flipper"in this.popover?(n=this.popover)==null?void 0:n.flipper:void 0}make(){this.nodes.wrapper=d.make("div",[this.CSS.settings]),this.eventsDispatcher.on(z,this.close)}destroy(){this.removeAllNodes(),this.listeners.destroy(),this.eventsDispatcher.off(z,this.close)
1170
+ /**
1171
+ * Open Block Settings pane
1172
+ *
1173
+ * @param targetBlock - near which Block we should open BlockSettings
1174
+ */}async open(n=this.Editor.BlockManager.currentBlock){var h;this.opened=!0,this.selection.save(),this.Editor.BlockSelection.selectBlock(n),this.Editor.BlockSelection.clearCache();const{toolTunes:p,commonTunes:g}=n.getTunes();this.eventsDispatcher.emit(this.events.opened);const m=pe()?Jt:jt;this.popover=new m({searchable:!0,items:await this.getTunesItems(n,g,p),scopeElement:this.Editor.API.methods.ui.nodes.redactor,messages:{nothingFound:A.ui(de.ui.popover,"Nothing found"),search:A.ui(de.ui.popover,"Filter")}}),this.popover.on(Bt.Closed,this.onPopoverClose),(h=this.nodes.wrapper)==null||h.append(this.popover.getElement()),this.popover.show()}getElement(){return this.nodes.wrapper}
1175
+ /**
1176
+ * Returns list of items to be displayed in block tunes menu.
1177
+ * Merges tool specific tunes, conversion menu and common tunes in one list in predefined order
1178
+ *
1179
+ * @param currentBlock – block we are about to open block tunes for
1180
+ * @param commonTunes – common tunes
1181
+ * @param toolTunes - tool specific tunes
1182
+ */async getTunesItems(n,h,p){const g=[];p!==void 0&&p.length>0&&(g.push(...p),g.push({type:U.Separator}));const m=Array.from(this.Editor.Tools.blockTools.values()),v=(await zt(n,m)).reduce(((h,p)=>(p.toolbox.forEach((g=>{h.push({icon:g.icon,title:A.t(de.toolNames,g.title),name:p.name,closeOnActivate:!0,onActivate:async()=>{const{BlockManager:h,Caret:m,Toolbar:v}=this.Editor,x=await h.convert(n,p.name,g.data);v.close(),m.setToBlock(x,m.positions.END)}})})),h)),[]);return v.length>0&&(g.push({icon:Ye,name:"convert-to",title:A.ui(de.ui.popover,"Convert to"),children:{searchable:!0,items:v}}),g.push({type:U.Separator})),g.push(...h),g.map((n=>this.resolveTuneAliases(n)))
1183
+ /**
1184
+ * Resolves aliases in tunes menu items
1185
+ *
1186
+ * @param item - item with resolved aliases
1187
+ */}resolveTuneAliases(n){if(n.type===U.Separator||n.type===U.Html)return n;const h=mi(n,{label:"title"});return n.confirmation&&(h.confirmation=this.resolveTuneAliases(n.confirmation)),h}}var Gt={exports:{}};
1188
+ /*!
1189
+ * Library for handling keyboard shortcuts
1190
+ * @copyright CodeX (https://codex.so)
1191
+ * @license MIT
1192
+ * @author CodeX (https://codex.so)
1193
+ * @version 1.2.0
1194
+ */(function(n,h){(function(h,p){n.exports=p()})(window,(function(){return function(n){var h={};function i(p){if(h[p])return h[p].exports;var g=h[p]={i:p,l:!1,exports:{}};return n[p].call(g.exports,g,g.exports,i),g.l=!0,g.exports}return i.m=n,i.c=h,i.d=function(n,h,p){i.o(n,h)||Object.defineProperty(n,h,{enumerable:!0,get:p})},i.r=function(n){typeof Symbol<"u"&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},i.t=function(n,h){if(1&h&&(n=i(n)),8&h||4&h&&typeof n=="object"&&n&&n.__esModule)return n;var p=Object.create(null);if(i.r(p),Object.defineProperty(p,"default",{enumerable:!0,value:n}),2&h&&typeof n!="string")for(var g in n)i.d(p,g,function(h){return n[h]}.bind(null,g));return p},i.n=function(n){var h=n&&n.__esModule?function(){return n.default}:function(){return n};return i.d(h,"a",h),h},i.o=function(n,h){return Object.prototype.hasOwnProperty.call(n,h)},i.p="",i(i.s=0)}([function(n,h,p){function s(n,h){for(var p=0;p<h.length;p++){var g=h[p];g.enumerable=g.enumerable||!1,g.configurable=!0,"value"in g&&(g.writable=!0),Object.defineProperty(n,g.key,g)}}function r(n,h,p){return h&&s(n.prototype,h),p&&s(n,p),n}p.r(h);var g=function(){function a(n){var h=this;(function(n,h){if(!(n instanceof h))throw new TypeError("Cannot call a class as a function")})(this,a),this.commands={},this.keys={},this.name=n.name,this.parseShortcutName(n.name),this.element=n.on,this.callback=n.callback,this.executeShortcut=function(n){h.execute(n)},this.element.addEventListener("keydown",this.executeShortcut,!1)}return r(a,null,[{key:"supportedCommands",get:function(){return{SHIFT:["SHIFT"],CMD:["CMD","CONTROL","COMMAND","WINDOWS","CTRL"],ALT:["ALT","OPTION"]}}},{key:"keyCodes",get:function(){return{0:48,1:49,2:50,3:51,4:52,5:53,6:54,7:55,8:56,9:57,A:65,B:66,C:67,D:68,E:69,F:70,G:71,H:72,I:73,J:74,K:75,L:76,M:77,N:78,O:79,P:80,Q:81,R:82,S:83,T:84,U:85,V:86,W:87,X:88,Y:89,Z:90,BACKSPACE:8,ENTER:13,ESCAPE:27,LEFT:37,UP:38,RIGHT:39,DOWN:40,INSERT:45,DELETE:46,".":190}}}]),r(a,[{key:"parseShortcutName",value:function(n){n=n.split("+");for(var h=0;h<n.length;h++){n[h]=n[h].toUpperCase();var p=!1;for(var g in a.supportedCommands)if(a.supportedCommands[g].includes(n[h])){p=this.commands[g]=!0;break}p||(this.keys[n[h]]=!0)}for(var m in a.supportedCommands)this.commands[m]||(this.commands[m]=!1)}},{key:"execute",value:function(n){var h,p={CMD:n.ctrlKey||n.metaKey,SHIFT:n.shiftKey,ALT:n.altKey},g=!0;for(h in this.commands)this.commands[h]!==p[h]&&(g=!1);var m,v=!0;for(m in this.keys)v=v&&n.keyCode===a.keyCodes[m];g&&v&&this.callback(n)}},{key:"remove",value:function(){this.element.removeEventListener("keydown",this.executeShortcut)}}]),a}();h.default=g}]).default}))})(Gt);var Qt=Gt.exports;const oo=Fe(Qt);class Yi{constructor(){this.registeredShortcuts=new Map}
1195
+ /**
1196
+ * Register shortcut
1197
+ *
1198
+ * @param shortcut - shortcut options
1199
+ */add(n){if(this.findShortcut(n.on,n.name))throw Error(`Shortcut ${n.name} is already registered for ${n.on}. Please remove it before add a new handler.`);const h=new oo({name:n.name,on:n.on,callback:n.handler}),p=this.registeredShortcuts.get(n.on)||[];this.registeredShortcuts.set(n.on,[...p,h])}
1200
+ /**
1201
+ * Remove shortcut
1202
+ *
1203
+ * @param element - Element shortcut is set for
1204
+ * @param name - shortcut name
1205
+ */remove(n,h){const p=this.findShortcut(n,h);if(!p)return;p.remove();const g=this.registeredShortcuts.get(n);this.registeredShortcuts.set(n,g.filter((n=>n!==p)))}
1206
+ /**
1207
+ * Get Shortcut instance if exist
1208
+ *
1209
+ * @param element - Element shorcut is set for
1210
+ * @param shortcut - shortcut name
1211
+ * @returns {number} index - shortcut index if exist
1212
+ */findShortcut(n,h){return(this.registeredShortcuts.get(n)||[]).find((({name:n})=>n===h))}}const io=new Yi;var ro=Object.defineProperty,mo=Object.getOwnPropertyDescriptor,eo=(n,h,p,g)=>{for(var m,v=g>1?void 0:g?mo(h,p):h,x=n.length-1;x>=0;x--)(m=n[x])&&(v=(g?m(h,p,v):m(v))||v);return g&&v&&ro(h,p,v),v},bo=(n=>(n.Opened="toolbox-opened",n.Closed="toolbox-closed",n.BlockAdded="toolbox-block-added",n))(bo||{});const ko=class to extends Te{
1213
+ /**
1214
+ * Toolbox constructor
1215
+ *
1216
+ * @param options - available parameters
1217
+ * @param options.api - Editor API methods
1218
+ * @param options.tools - Tools available to check whether some of them should be displayed at the Toolbox or not
1219
+ */
1220
+ constructor({api:n,tools:h,i18nLabels:p}){super(),this.opened=!1,this.listeners=new Ce,this.popover=null,this.handleMobileLayoutToggle=()=>{this.destroyPopover(),this.initPopover()},this.onPopoverClose=()=>{this.opened=!1,this.emit("toolbox-closed")},this.api=n,this.tools=h,this.i18nLabels=p,this.enableShortcuts(),this.nodes={toolbox:d.make("div",to.CSS.toolbox)},this.initPopover(),this.api.events.on(z,this.handleMobileLayoutToggle)
1221
+ /**
1222
+ * Returns True if Toolbox is Empty and nothing to show
1223
+ *
1224
+ * @returns {boolean}
1225
+ */}get isEmpty(){return this.toolsToBeDisplayed.length===0}static get CSS(){return{toolbox:"ce-toolbox"}}getElement(){return this.nodes.toolbox}hasFocus(){if(this.popover!==null)return"hasFocus"in this.popover?this.popover.hasFocus():void 0}destroy(){var n;super.destroy(),this.nodes&&this.nodes.toolbox&&this.nodes.toolbox.remove(),this.removeAllShortcuts(),(n=this.popover)==null||n.off(Bt.Closed,this.onPopoverClose),this.listeners.destroy(),this.api.events.off(z,this.handleMobileLayoutToggle)
1226
+ /**
1227
+ * Toolbox Tool's button click handler
1228
+ *
1229
+ * @param toolName - tool type to be activated
1230
+ * @param blockDataOverrides - Block data predefined by the activated Toolbox item
1231
+ */}toolButtonActivated(n,h){this.insertNewBlock(n,h)}open(){var n;this.isEmpty||((n=this.popover)==null||n.show(),this.opened=!0,this.emit("toolbox-opened"))}close(){var n;(n=this.popover)==null||n.hide(),this.opened=!1,this.emit("toolbox-closed")}toggle(){this.opened?this.close():this.open()}initPopover(){var n;const h=pe()?Jt:jt;this.popover=new h({scopeElement:this.api.ui.nodes.redactor,searchable:!0,messages:{nothingFound:this.i18nLabels.nothingFound,search:this.i18nLabels.filter},items:this.toolboxItemsToBeDisplayed}),this.popover.on(Bt.Closed,this.onPopoverClose),(n=this.nodes.toolbox)==null||n.append(this.popover.getElement())}destroyPopover(){this.popover!==null&&(this.popover.hide(),this.popover.off(Bt.Closed,this.onPopoverClose),this.popover.destroy(),this.popover=null),this.nodes.toolbox!==null&&(this.nodes.toolbox.innerHTML="")}get toolsToBeDisplayed(){const n=[];return this.tools.forEach((h=>{h.toolbox&&n.push(h)})),n}get toolboxItemsToBeDisplayed(){const e=(n,h)=>({icon:n.icon,title:A.t(de.toolNames,n.title||Le(h.name)),name:h.name,onActivate:()=>{this.toolButtonActivated(h.name,n.data)},secondaryLabel:h.shortcut?tt(h.shortcut):""});return this.toolsToBeDisplayed.reduce(((n,h)=>(Array.isArray(h.toolbox)?h.toolbox.forEach((p=>{n.push(e(p,h))})):h.toolbox!==void 0&&n.push(e(h.toolbox,h)),n)),[])}enableShortcuts(){this.toolsToBeDisplayed.forEach((n=>{const h=n.shortcut;h&&this.enableShortcutForTool(n.name,h)}))}
1232
+ /**
1233
+ * Enable shortcut Block Tool implemented shortcut
1234
+ *
1235
+ * @param {string} toolName - Tool name
1236
+ * @param {string} shortcut - shortcut according to the ShortcutData Module format
1237
+ */enableShortcutForTool(n,h){io.add({name:h,on:this.api.ui.nodes.redactor,handler:async h=>{h.preventDefault();const p=this.api.blocks.getCurrentBlockIndex(),g=this.api.blocks.getBlockByIndex(p);if(g)try{const h=await this.api.blocks.convert(g.id,n);this.api.caret.setToBlock(h,"end");return}catch{}this.insertNewBlock(n)}})}removeAllShortcuts(){this.toolsToBeDisplayed.forEach((n=>{const h=n.shortcut;h&&io.remove(this.api.ui.nodes.redactor,h)}))}
1238
+ /**
1239
+ * Inserts new block
1240
+ * Can be called when button clicked on Toolbox or by ShortcutData
1241
+ *
1242
+ * @param {string} toolName - Tool name
1243
+ * @param blockDataOverrides - predefined Block data
1244
+ */async insertNewBlock(n,h){const p=this.api.blocks.getCurrentBlockIndex(),g=this.api.blocks.getBlockByIndex(p);if(!g)return;const m=g.isEmpty?p:p+1;let v;if(h){const p=await this.api.blocks.composeBlockData(n);v=Object.assign(p,h)}const x=this.api.blocks.insert(n,v,void 0,m,void 0,g.isEmpty);x.call($.APPEND_CALLBACK),this.api.caret.setToBlock(m),this.emit("toolbox-block-added",{block:x}),this.api.toolbar.close()}};eo([ue],ko.prototype,"toolsToBeDisplayed",1);eo([ue],ko.prototype,"toolboxItemsToBeDisplayed",1);let wo=ko;const No="block hovered";async function Vi(n,h){const p=navigator.keyboard;if(!p)return h;try{return(await p.getLayoutMap()).get(n)||h}catch(n){return console.error(n),h}}class qi extends y{
1245
+ /**
1246
+ * @class
1247
+ * @param moduleConfiguration - Module Configuration
1248
+ * @param moduleConfiguration.config - Editor's config
1249
+ * @param moduleConfiguration.eventsDispatcher - Editor's event dispatcher
1250
+ */
1251
+ constructor({config:n,eventsDispatcher:h}){super({config:n,eventsDispatcher:h}),this.toolboxInstance=null
1252
+ /**
1253
+ * CSS styles
1254
+ *
1255
+ * @returns {object}
1256
+ */}get CSS(){return{toolbar:"ce-toolbar",content:"ce-toolbar__content",actions:"ce-toolbar__actions",actionsOpened:"ce-toolbar__actions--opened",toolbarOpened:"ce-toolbar--opened",openedToolboxHolderModifier:"codex-editor--toolbox-opened",plusButton:"ce-toolbar__plus",plusButtonShortcut:"ce-toolbar__plus-shortcut",settingsToggler:"ce-toolbar__settings-btn",settingsTogglerHidden:"ce-toolbar__settings-btn--hidden"}}
1257
+ /**
1258
+ * Returns the Toolbar opening state
1259
+ *
1260
+ * @returns {boolean}
1261
+ */get opened(){return this.nodes.wrapper.classList.contains(this.CSS.toolbarOpened)}get toolbox(){var n;return{opened:(n=this.toolboxInstance)==null?void 0:n.opened,close:()=>{var n;(n=this.toolboxInstance)==null||n.close()},open:()=>{this.toolboxInstance!==null?(this.Editor.BlockManager.currentBlock=this.hoveredBlock,this.toolboxInstance.open()):g("toolbox.open() called before initialization is finished","warn")},toggle:()=>{this.toolboxInstance!==null?this.toolboxInstance.toggle():g("toolbox.toggle() called before initialization is finished","warn")},hasFocus:()=>{var n;return(n=this.toolboxInstance)==null?void 0:n.hasFocus()}}}get blockActions(){return{hide:()=>{this.nodes.actions.classList.remove(this.CSS.actionsOpened)},show:()=>{this.nodes.actions.classList.add(this.CSS.actionsOpened)}}}get blockTunesToggler(){return{hide:()=>this.nodes.settingsToggler.classList.add(this.CSS.settingsTogglerHidden),show:()=>this.nodes.settingsToggler.classList.remove(this.CSS.settingsTogglerHidden)}}
1262
+ /**
1263
+ * Toggles read-only mode
1264
+ *
1265
+ * @param {boolean} readOnlyEnabled - read-only mode
1266
+ */toggleReadOnly(n){n?(this.destroy(),this.Editor.BlockSettings.destroy(),this.disableModuleBindings()):window.requestIdleCallback((()=>{this.drawUI(),this.enableModuleBindings()}),{timeout:2e3})}
1267
+ /**
1268
+ * Move Toolbar to the passed (or current) Block
1269
+ *
1270
+ * @param block - block to move Toolbar near it
1271
+ */moveAndOpen(n=this.Editor.BlockManager.currentBlock){if(this.toolboxInstance===null){g("Can't open Toolbar since Editor initialization is not finished yet","warn");return}if(this.toolboxInstance.opened&&this.toolboxInstance.close(),this.Editor.BlockSettings.opened&&this.Editor.BlockSettings.close(),!n)return;this.hoveredBlock=n;const h=n.holder,{isMobile:p}=this.Editor.UI;let m;const v=20,x=n.firstInput,w=h.getBoundingClientRect(),E=x!==void 0?x.getBoundingClientRect():null,B=E!==null?E.top-w.top:null,T=B!==null?B>v:void 0;if(p)m=h.offsetTop+h.offsetHeight;else if(x===void 0||T){const p=parseInt(window.getComputedStyle(n.pluginsContent).paddingTop);m=h.offsetTop+p}else{const n=_o(x),p=parseInt(window.getComputedStyle(this.nodes.plusButton).height,10),g=8;m=h.offsetTop+n-p+g+B}this.nodes.wrapper.style.top=`${Math.floor(m)}px`,this.Editor.BlockManager.blocks.length===1&&n.isEmpty?this.blockTunesToggler.hide():this.blockTunesToggler.show(),this.open()}close(){var n,h;this.Editor.ReadOnly.isEnabled||((n=this.nodes.wrapper)==null||n.classList.remove(this.CSS.toolbarOpened),this.blockActions.hide(),(h=this.toolboxInstance)==null||h.close(),this.Editor.BlockSettings.close(),this.reset())}reset(){this.nodes.wrapper.style.top="unset"}
1272
+ /**
1273
+ * Open Toolbar with Plus Button and Actions
1274
+ *
1275
+ * @param {boolean} withBlockActions - by default, Toolbar opens with Block Actions.
1276
+ * This flag allows to open Toolbar without Actions.
1277
+ */open(n=!0){this.nodes.wrapper.classList.add(this.CSS.toolbarOpened),n?this.blockActions.show():this.blockActions.hide()}async make(){this.nodes.wrapper=d.make("div",this.CSS.toolbar),["content","actions"].forEach((n=>{this.nodes[n]=d.make("div",this.CSS[n])})),d.append(this.nodes.wrapper,this.nodes.content),d.append(this.nodes.content,this.nodes.actions),this.nodes.plusButton=d.make("div",this.CSS.plusButton,{innerHTML:$e}),d.append(this.nodes.actions,this.nodes.plusButton),this.readOnlyMutableListeners.on(this.nodes.plusButton,"click",(()=>{Ne(!0),this.plusButtonClicked()}),!1);const n=d.make("div");n.appendChild(document.createTextNode(A.ui(de.ui.toolbar.toolbox,"Add"))),n.appendChild(d.make("div",this.CSS.plusButtonShortcut,{textContent:"/"})),Pe(this.nodes.plusButton,n,{hidingDelay:400}),this.nodes.settingsToggler=d.make("span",this.CSS.settingsToggler,{innerHTML:je}),d.append(this.nodes.actions,this.nodes.settingsToggler);const h=d.make("div"),p=d.text(A.ui(de.ui.blockTunes.toggler,"Click to tune")),g=await Vi("Slash","/");h.appendChild(p),h.appendChild(d.make("div",this.CSS.plusButtonShortcut,{textContent:tt(`CMD + ${g}`)})),Pe(this.nodes.settingsToggler,h,{hidingDelay:400}),d.append(this.nodes.actions,this.makeToolbox()),d.append(this.nodes.actions,this.Editor.BlockSettings.getElement()),d.append(this.Editor.UI.nodes.wrapper,this.nodes.wrapper)}makeToolbox(){return this.toolboxInstance=new wo({api:this.Editor.API.methods,tools:this.Editor.Tools.blockTools,i18nLabels:{filter:A.ui(de.ui.popover,"Filter"),nothingFound:A.ui(de.ui.popover,"Nothing found")}}),this.toolboxInstance.on(bo.Opened,(()=>{this.Editor.UI.nodes.wrapper.classList.add(this.CSS.openedToolboxHolderModifier)})),this.toolboxInstance.on(bo.Closed,(()=>{this.Editor.UI.nodes.wrapper.classList.remove(this.CSS.openedToolboxHolderModifier)})),this.toolboxInstance.on(bo.BlockAdded,(({block:n})=>{const{BlockManager:h,Caret:p}=this.Editor,g=h.getBlockById(n.id);g.inputs.length===0&&(g===h.lastBlock?(h.insertAtEnd(),p.setToBlock(h.lastBlock)):p.setToBlock(h.nextBlock))})),this.toolboxInstance.getElement()}plusButtonClicked(){var n;this.Editor.BlockManager.currentBlock=this.hoveredBlock,(n=this.toolboxInstance)==null||n.toggle()}enableModuleBindings(){this.readOnlyMutableListeners.on(this.nodes.settingsToggler,"mousedown",(n=>{var h;n.stopPropagation(),this.settingsTogglerClicked(),(h=this.toolboxInstance)!=null&&h.opened&&this.toolboxInstance.close(),Ne(!0)}),!0),pe()||this.eventsDispatcher.on(No,(n=>{var h;this.Editor.BlockSettings.opened||(h=this.toolboxInstance)!=null&&h.opened||this.moveAndOpen(n.block)}))}disableModuleBindings(){this.readOnlyMutableListeners.clearAll()}settingsTogglerClicked(){this.Editor.BlockManager.currentBlock=this.hoveredBlock,this.Editor.BlockSettings.opened?this.Editor.BlockSettings.close():this.Editor.BlockSettings.open(this.hoveredBlock)}drawUI(){this.Editor.BlockSettings.make(),this.make()}destroy(){this.removeAllNodes(),this.toolboxInstance&&this.toolboxInstance.destroy()}}var Po=(n=>(n[n.Block=0]="Block",n[n.Inline=1]="Inline",n[n.Tune=2]="Tune",n))(Po||{}),Do=(n=>(n.Shortcut="shortcut",n.Toolbox="toolbox",n.EnabledInlineTools="inlineToolbar",n.EnabledBlockTunes="tunes",n.Config="config",n))(Do||{}),Ro=(n=>(n.Shortcut="shortcut",n.SanitizeConfig="sanitize",n))(Ro||{}),Vo=(n=>(n.IsEnabledLineBreaks="enableLineBreaks",n.Toolbox="toolbox",n.ConversionConfig="conversionConfig",n.IsReadOnlySupported="isReadOnlySupported",n.PasteConfig="pasteConfig",n))(Vo||{}),Xo=(n=>(n.IsInline="isInline",n.Title="title",n))(Xo||{}),Qo=(n=>(n.IsTune="isTune",n))(Qo||{});class dt{
1278
+ /**
1279
+ * @class
1280
+ * @param {ConstructorOptions} options - Constructor options
1281
+ */
1282
+ constructor({name:n,constructable:h,config:p,api:g,isDefault:m,isInternal:v=!1,defaultPlaceholder:x}){this.api=g,this.name=n,this.constructable=h,this.config=p,this.isDefault=m,this.isInternal=v,this.defaultPlaceholder=x}get settings(){const n=this.config.config||{};return this.isDefault&&!("placeholder"in n)&&this.defaultPlaceholder&&(n.placeholder=this.defaultPlaceholder),n}reset(){if(O(this.constructable.reset))return this.constructable.reset()}prepare(){if(O(this.constructable.prepare))return this.constructable.prepare({toolName:this.name,config:this.settings})}get shortcut(){const n=this.constructable.shortcut;return this.config.shortcut||n}get sanitizeConfig(){return this.constructable.sanitize||{}}isInline(){return this.type===Po.Inline}isBlock(){return this.type===Po.Block}isTune(){return this.type===Po.Tune}}class Zi extends y{
1283
+ /**
1284
+ * @param moduleConfiguration - Module Configuration
1285
+ * @param moduleConfiguration.config - Editor's config
1286
+ * @param moduleConfiguration.eventsDispatcher - Editor's event dispatcher
1287
+ */
1288
+ constructor({config:n,eventsDispatcher:h}){super({config:n,eventsDispatcher:h}),this.CSS={inlineToolbar:"ce-inline-toolbar"},this.opened=!1,this.popover=null,this.toolbarVerticalMargin=pe()?20:6,this.toolsInstances=new Map
1289
+ /**
1290
+ * Toggles read-only mode
1291
+ *
1292
+ * @param {boolean} readOnlyEnabled - read-only mode
1293
+ */}toggleReadOnly(n){n?this.destroy():window.requestIdleCallback((()=>{this.make()}),{timeout:2e3})}
1294
+ /**
1295
+ * Shows Inline Toolbar if something is selected
1296
+ *
1297
+ * @param [needToClose] - pass true to close toolbar if it is not allowed.
1298
+ * Avoid to use it just for closing IT, better call .close() clearly.
1299
+ */async tryToShow(n=!1){n&&this.close(),this.allowedToShow()&&(await this.open(),this.Editor.Toolbar.close())}close(){var n,h;this.opened&&(this.Editor.ReadOnly.isEnabled||(Array.from(this.toolsInstances.entries()).forEach((([n,h])=>{const p=this.getToolShortcut(n);p&&io.remove(this.Editor.UI.nodes.redactor,p),O(h.clear)&&h.clear()})),this.toolsInstances=null,this.reset(),this.opened=!1,(n=this.popover)==null||n.hide(),(h=this.popover)==null||h.destroy(),this.popover=null))}
1300
+ /**
1301
+ * Check if node is contained by Inline Toolbar
1302
+ *
1303
+ * @param {Node} node — node to check
1304
+ */containsNode(n){return this.nodes.wrapper!==void 0&&this.nodes.wrapper.contains(n)}destroy(){var n;this.removeAllNodes(),(n=this.popover)==null||n.destroy(),this.popover=null}make(){this.nodes.wrapper=d.make("div",[this.CSS.inlineToolbar,...this.isRtl?[this.Editor.UI.CSS.editorRtlFix]:[]]),d.append(this.Editor.UI.nodes.wrapper,this.nodes.wrapper)}async open(){var n;if(this.opened)return;this.opened=!0,this.popover!==null&&this.popover.destroy();const h=await this.getInlineTools();this.popover=new Ri({items:h,scopeElement:this.Editor.API.methods.ui.nodes.redactor,messages:{nothingFound:A.ui(de.ui.popover,"Nothing found"),search:A.ui(de.ui.popover,"Filter")}}),this.move(this.popover.size.width),(n=this.nodes.wrapper)==null||n.append(this.popover.getElement()),this.popover.show()
1305
+ /**
1306
+ * Move Toolbar to the selected text
1307
+ *
1308
+ * @param popoverWidth - width of the toolbar popover
1309
+ */}move(n){const h=b.rect,p=this.Editor.UI.nodes.wrapper.getBoundingClientRect(),g={x:h.x-p.x,y:h.y+h.height-p.top+this.toolbarVerticalMargin};g.x+n+p.x>this.Editor.UI.contentRect.right&&(g.x=this.Editor.UI.contentRect.right-n-p.x),this.nodes.wrapper.style.left=Math.floor(g.x)+"px",this.nodes.wrapper.style.top=Math.floor(g.y)+"px"}reset(){this.nodes.wrapper.style.left="0",this.nodes.wrapper.style.top="0"}allowedToShow(){const n=["IMG","INPUT"],h=b.get(),p=b.text;if(!h||!h.anchorNode||h.isCollapsed||p.length<1)return!1;const g=d.isElement(h.anchorNode)?h.anchorNode:h.anchorNode.parentElement;if(g===null||h&&n.includes(g.tagName)||g.closest('[contenteditable="true"]')===null)return!1;const m=this.Editor.BlockManager.getBlock(h.anchorNode);return!!m&&m.tool.inlineTools.size!==0}async getInlineTools(){const n=b.get(),h=this.Editor.BlockManager.getBlock(n.anchorNode),p=Array.from(h.tool.inlineTools.values()),g=[];this.toolsInstances===null&&(this.toolsInstances=new Map);for(let n=0;n<p.length;n++){const h=p[n],m=h.create(),v=await m.render();this.toolsInstances.set(h.name,m);const x=this.getToolShortcut(h.name);if(x)try{this.enableShortcuts(h.name,x)}catch{}const w=x!==void 0?tt(x):void 0,E=A.t(de.toolNames,h.title||Le(h.name));[v].flat().forEach((v=>{var x,B;const T={name:h.name,onActivate:()=>{this.toolClicked(m)},hint:{title:E,description:w}};if(d.isElement(v)){const n={...T,element:v,type:U.Html};if(O(m.renderActions)){const h=m.renderActions();n.children={isOpen:(x=m.checkState)==null?void 0:x.call(m,b.get()),isFlippable:!1,items:[{type:U.Html,element:h}]}}else(B=m.checkState)==null||B.call(m,b.get());g.push(n)}else if(v.type===U.Html)g.push({...T,...v,type:U.Html});else if(v.type===U.Separator)g.push({type:U.Separator});else{const h={...T,...v,type:U.Default};"children"in h&&n!==0&&g.push({type:U.Separator}),g.push(h),"children"in h&&n<p.length-1&&g.push({type:U.Separator})}}))}return g}
1310
+ /**
1311
+ * Get shortcut name for tool
1312
+ *
1313
+ * @param toolName — Tool name
1314
+ */getToolShortcut(n){const{Tools:h}=this.Editor,p=h.inlineTools.get(n),g=h.internal.inlineTools;return Array.from(g.keys()).includes(n)?this.inlineTools[n][Ro.Shortcut]:p==null?void 0:p.shortcut}
1315
+ /**
1316
+ * Enable Tool shortcut with Editor Shortcuts Module
1317
+ *
1318
+ * @param toolName - tool name
1319
+ * @param shortcut - shortcut according to the ShortcutData Module format
1320
+ */enableShortcuts(n,h){io.add({name:h,handler:h=>{var p;const{currentBlock:g}=this.Editor.BlockManager;g&&g.tool.enabledInlineTools&&(h.preventDefault(),(p=this.popover)==null||p.activateItemByName(n))},on:this.Editor.UI.nodes.redactor})}
1321
+ /**
1322
+ * Inline Tool button clicks
1323
+ *
1324
+ * @param tool - Tool's instance
1325
+ */toolClicked(n){var h;const p=b.range;(h=n.surround)==null||h.call(n,p),this.checkToolsState()}checkToolsState(){var n;(n=this.toolsInstances)==null||n.forEach((n=>{var h;(h=n.checkState)==null||h.call(n,b.get())}))}get inlineTools(){const n={};return Array.from(this.Editor.Tools.inlineTools.entries()).forEach((([h,p])=>{n[h]=p.create()})),n}}function so(){const n=window.getSelection();if(n===null)return[null,0];let h=n.focusNode,p=n.focusOffset;return h===null?[null,0]:(h.nodeType!==Node.TEXT_NODE&&h.childNodes.length>0&&(h.childNodes[p]?(h=h.childNodes[p],p=0):(h=h.childNodes[p-1],p=h.textContent.length)),[h,p])}function no(n,h,p,g){const m=document.createRange();g==="left"?(m.setStart(n,0),m.setEnd(h,p)):(m.setStart(h,p),m.setEnd(n,n.childNodes.length));const v=m.cloneContents(),x=document.createElement("div");x.appendChild(v);const w=x.textContent||"";return Lo(w)}function Me(n){const h=d.getDeepestNode(n);if(h===null||d.isEmpty(n))return!0;if(d.isNativeInput(h))return h.selectionEnd===0;if(d.isEmpty(n))return!0;const[p,g]=so();return p!==null&&no(n,p,g,"left")}function Ae(n){const h=d.getDeepestNode(n,!0);if(h===null)return!0;if(d.isNativeInput(h))return h.selectionEnd===h.value.length;const[p,g]=so();return p!==null&&no(n,p,g,"right")}class Gi extends y{
1326
+ /**
1327
+ * All keydowns on Block
1328
+ *
1329
+ * @param {KeyboardEvent} event - keydown
1330
+ */
1331
+ keydown(n){switch(this.beforeKeydownProcessing(n),n.keyCode){case h.BACKSPACE:this.backspace(n);break;case h.DELETE:this.delete(n);break;case h.ENTER:this.enter(n);break;case h.DOWN:case h.RIGHT:this.arrowRightAndDown(n);break;case h.UP:case h.LEFT:this.arrowLeftAndUp(n);break;case h.TAB:this.tabPressed(n);break}n.key==="/"&&!n.ctrlKey&&!n.metaKey&&this.slashPressed(n),n.code==="Slash"&&(n.ctrlKey||n.metaKey)&&(n.preventDefault(),this.commandSlashPressed()
1332
+ /**
1333
+ * Fires on keydown before event processing
1334
+ *
1335
+ * @param {KeyboardEvent} event - keydown
1336
+ */)}beforeKeydownProcessing(n){this.needToolbarClosing(n)&&Mt(n.keyCode)&&(this.Editor.Toolbar.close(),n.ctrlKey||n.metaKey||n.altKey||n.shiftKey||this.Editor.BlockSelection.clearSelection(n)
1337
+ /**
1338
+ * Key up on Block:
1339
+ * - shows Inline Toolbar if something selected
1340
+ * - shows conversion toolbar with 85% of block selection
1341
+ *
1342
+ * @param {KeyboardEvent} event - keyup event
1343
+ */)}keyup(n){n.shiftKey||this.Editor.UI.checkEmptiness()}
1344
+ /**
1345
+ * Add drop target styles
1346
+ *
1347
+ * @param {DragEvent} event - drag over event
1348
+ */dragOver(n){const h=this.Editor.BlockManager.getBlockByChildNode(n.target);h.dropTarget=!0}
1349
+ /**
1350
+ * Remove drop target style
1351
+ *
1352
+ * @param {DragEvent} event - drag leave event
1353
+ */dragLeave(n){const h=this.Editor.BlockManager.getBlockByChildNode(n.target);h.dropTarget=!1}
1354
+ /**
1355
+ * Copying selected blocks
1356
+ * Before putting to the clipboard we sanitize all blocks and then copy to the clipboard
1357
+ *
1358
+ * @param {ClipboardEvent} event - clipboard event
1359
+ */handleCommandC(n){const{BlockSelection:h}=this.Editor;h.anyBlockSelected&&h.copySelectedBlocks(n)}
1360
+ /**
1361
+ * Copy and Delete selected Blocks
1362
+ *
1363
+ * @param {ClipboardEvent} event - clipboard event
1364
+ */handleCommandX(n){const{BlockSelection:h,BlockManager:p,Caret:g}=this.Editor;h.anyBlockSelected&&h.copySelectedBlocks(n).then((()=>{const m=p.removeSelectedBlocks(),v=p.insertDefaultBlockAtIndex(m,!0);g.setToBlock(v,g.positions.START),h.clearSelection(n)}))}
1365
+ /**
1366
+ * Tab pressed inside a Block.
1367
+ *
1368
+ * @param {KeyboardEvent} event - keydown
1369
+ */tabPressed(n){const{InlineToolbar:h,Caret:p}=this.Editor;h.opened||(n.shiftKey?p.navigatePrevious(!0):p.navigateNext(!0))&&n.preventDefault()}commandSlashPressed(){this.Editor.BlockSelection.selectedBlocks.length>1||this.activateBlockSettings()}
1370
+ /**
1371
+ * '/' keydown inside a Block
1372
+ *
1373
+ * @param event - keydown
1374
+ */slashPressed(n){this.Editor.BlockManager.currentBlock.isEmpty&&(n.preventDefault(),this.Editor.Caret.insertContentAtCaretPosition("/"),this.activateToolbox()
1375
+ /**
1376
+ * ENTER pressed on block
1377
+ *
1378
+ * @param {KeyboardEvent} event - keydown
1379
+ */)}enter(n){const{BlockManager:h,UI:p}=this.Editor,g=h.currentBlock;if(g===void 0||g.tool.isLineBreaksEnabled||p.someToolbarOpened&&p.someFlipperButtonFocused||n.shiftKey&&!x)return;let m=g;g.currentInput!==void 0&&Me(g.currentInput)&&!g.hasMedia?this.Editor.BlockManager.insertDefaultBlockAtIndex(this.Editor.BlockManager.currentBlockIndex):m=g.currentInput&&Ae(g.currentInput)?this.Editor.BlockManager.insertDefaultBlockAtIndex(this.Editor.BlockManager.currentBlockIndex+1):this.Editor.BlockManager.split(),this.Editor.Caret.setToBlock(m),this.Editor.Toolbar.moveAndOpen(m),n.preventDefault()
1380
+ /**
1381
+ * Handle backspace keydown on Block
1382
+ *
1383
+ * @param {KeyboardEvent} event - keydown
1384
+ */}backspace(n){const{BlockManager:h,Caret:p}=this.Editor,{currentBlock:g,previousBlock:m}=h;if(g!==void 0&&b.isCollapsed&&g.currentInput&&Me(g.currentInput))if(n.preventDefault(),this.Editor.Toolbar.close(),g.currentInput===g.firstInput){if(m!==null)if(m.isEmpty)h.removeBlock(m);else if(g.isEmpty){h.removeBlock(g);const n=h.currentBlock;p.setToBlock(n,p.positions.END)}else wt(m,g)?this.mergeBlocks(m,g):p.setToBlock(m,p.positions.END)}else p.navigatePrevious()}
1385
+ /**
1386
+ * Handles delete keydown on Block
1387
+ * Removes char after the caret.
1388
+ * If caret is at the end of the block, merge next block with current
1389
+ *
1390
+ * @param {KeyboardEvent} event - keydown
1391
+ */delete(n){const{BlockManager:h,Caret:p}=this.Editor,{currentBlock:g,nextBlock:m}=h;b.isCollapsed&&Ae(g.currentInput)&&(n.preventDefault(),this.Editor.Toolbar.close(),g.currentInput===g.lastInput?m!==null&&(m.isEmpty?h.removeBlock(m):g.isEmpty?(h.removeBlock(g),p.setToBlock(m,p.positions.START)):wt(g,m)?this.mergeBlocks(g,m):p.setToBlock(m,p.positions.START)):p.navigateNext())}
1392
+ /**
1393
+ * Merge passed Blocks
1394
+ *
1395
+ * @param targetBlock - to which Block we want to merge
1396
+ * @param blockToMerge - what Block we want to merge
1397
+ */mergeBlocks(n,h){const{BlockManager:p,Caret:g,Toolbar:m}=this.Editor;g.createShadow(n.lastInput),p.mergeBlocks(n,h).then((()=>{g.restoreCaret(n.pluginsContent),m.close()}))
1398
+ /**
1399
+ * Handle right and down keyboard keys
1400
+ *
1401
+ * @param {KeyboardEvent} event - keyboard event
1402
+ */}arrowRightAndDown(n){const p=le.usedKeys.includes(n.keyCode)&&(!n.shiftKey||n.keyCode===h.TAB);if(this.Editor.UI.someToolbarOpened&&p)return;this.Editor.Toolbar.close();const{currentBlock:g}=this.Editor.BlockManager,m=((g==null?void 0:g.currentInput)!==void 0?Ae(g.currentInput):void 0)||this.Editor.BlockSelection.anyBlockSelected;n.shiftKey&&n.keyCode===h.DOWN&&m?this.Editor.CrossBlockSelection.toggleBlockSelectedState():(n.keyCode===h.DOWN||n.keyCode===h.RIGHT&&!this.isRtl?this.Editor.Caret.navigateNext():this.Editor.Caret.navigatePrevious())?n.preventDefault():(Oe((()=>{this.Editor.BlockManager.currentBlock&&this.Editor.BlockManager.currentBlock.updateCurrentInput()}),20)(),this.Editor.BlockSelection.clearSelection(n)
1403
+ /**
1404
+ * Handle left and up keyboard keys
1405
+ *
1406
+ * @param {KeyboardEvent} event - keyboard event
1407
+ */)}arrowLeftAndUp(n){if(this.Editor.UI.someToolbarOpened){if(le.usedKeys.includes(n.keyCode)&&(!n.shiftKey||n.keyCode===h.TAB))return;this.Editor.UI.closeAllToolbars()}this.Editor.Toolbar.close();const{currentBlock:p}=this.Editor.BlockManager,g=((p==null?void 0:p.currentInput)!==void 0?Me(p.currentInput):void 0)||this.Editor.BlockSelection.anyBlockSelected;n.shiftKey&&n.keyCode===h.UP&&g?this.Editor.CrossBlockSelection.toggleBlockSelectedState(!1):(n.keyCode===h.UP||n.keyCode===h.LEFT&&!this.isRtl?this.Editor.Caret.navigatePrevious():this.Editor.Caret.navigateNext())?n.preventDefault():(Oe((()=>{this.Editor.BlockManager.currentBlock&&this.Editor.BlockManager.currentBlock.updateCurrentInput()}),20)(),this.Editor.BlockSelection.clearSelection(n)
1408
+ /**
1409
+ * Cases when we need to close Toolbar
1410
+ *
1411
+ * @param {KeyboardEvent} event - keyboard event
1412
+ */)}needToolbarClosing(n){const p=n.keyCode===h.ENTER&&this.Editor.Toolbar.toolbox.opened,g=n.keyCode===h.ENTER&&this.Editor.BlockSettings.opened,m=n.keyCode===h.ENTER&&this.Editor.InlineToolbar.opened,v=n.keyCode===h.TAB;return!(n.shiftKey||v||p||g||m)}activateToolbox(){this.Editor.Toolbar.opened||this.Editor.Toolbar.moveAndOpen(),this.Editor.Toolbar.toolbox.open()}activateBlockSettings(){this.Editor.Toolbar.opened||this.Editor.Toolbar.moveAndOpen(),this.Editor.BlockSettings.opened||this.Editor.BlockSettings.open()}}class Xe{
1413
+ /**
1414
+ * @class
1415
+ * @param {HTMLElement} workingArea — editor`s working node
1416
+ */
1417
+ constructor(n){this.blocks=[],this.workingArea=n
1418
+ /**
1419
+ * Get length of Block instances array
1420
+ *
1421
+ * @returns {number}
1422
+ */}get length(){return this.blocks.length}
1423
+ /**
1424
+ * Get Block instances array
1425
+ *
1426
+ * @returns {Block[]}
1427
+ */get array(){return this.blocks}
1428
+ /**
1429
+ * Get blocks html elements array
1430
+ *
1431
+ * @returns {HTMLElement[]}
1432
+ */get nodes(){return At(this.workingArea.children)}
1433
+ /**
1434
+ * Proxy trap to implement array-like setter
1435
+ *
1436
+ * @example
1437
+ * blocks[0] = new Block(...)
1438
+ * @param {Blocks} instance — Blocks instance
1439
+ * @param {PropertyKey} property — block index or any Blocks class property key to set
1440
+ * @param {Block} value — value to set
1441
+ * @returns {boolean}
1442
+ */static set(n,h,p){return isNaN(Number(h))?(Reflect.set(n,h,p),!0):(n.insert(+h,p),!0
1443
+ /**
1444
+ * Proxy trap to implement array-like getter
1445
+ *
1446
+ * @param {Blocks} instance — Blocks instance
1447
+ * @param {PropertyKey} property — Blocks class property key
1448
+ * @returns {Block|*}
1449
+ */)}static get(n,h){return isNaN(Number(h))?Reflect.get(n,h):n.get(+h)}
1450
+ /**
1451
+ * Push new Block to the blocks array and append it to working area
1452
+ *
1453
+ * @param {Block} block - Block to add
1454
+ */push(n){this.blocks.push(n),this.insertToDOM(n)
1455
+ /**
1456
+ * Swaps blocks with indexes first and second
1457
+ *
1458
+ * @param {number} first - first block index
1459
+ * @param {number} second - second block index
1460
+ * @deprecated — use 'move' instead
1461
+ */}swap(n,h){const p=this.blocks[h];d.swap(this.blocks[n].holder,p.holder),this.blocks[h]=this.blocks[n],this.blocks[n]=p
1462
+ /**
1463
+ * Move a block from one to another index
1464
+ *
1465
+ * @param {number} toIndex - new index of the block
1466
+ * @param {number} fromIndex - block to move
1467
+ */}move(n,h){const p=this.blocks.splice(h,1)[0],g=n-1,m=Math.max(0,g),v=this.blocks[m];n>0?this.insertToDOM(p,"afterend",v):this.insertToDOM(p,"beforebegin",v),this.blocks.splice(n,0,p);const x=this.composeBlockEvent("move",{fromIndex:h,toIndex:n});p.call($.MOVED,x)}
1468
+ /**
1469
+ * Insert new Block at passed index
1470
+ *
1471
+ * @param {number} index — index to insert Block
1472
+ * @param {Block} block — Block to insert
1473
+ * @param {boolean} replace — it true, replace block on given index
1474
+ */insert(n,h,p=!1){if(!this.length){this.push(h);return}n>this.length&&(n=this.length),p&&(this.blocks[n].holder.remove(),this.blocks[n].call($.REMOVED));const g=p?1:0;if(this.blocks.splice(n,g,h),n>0){const p=this.blocks[n-1];this.insertToDOM(h,"afterend",p)}else{const p=this.blocks[n+1];p?this.insertToDOM(h,"beforebegin",p):this.insertToDOM(h)}}
1475
+ /**
1476
+ * Replaces block under passed index with passed block
1477
+ *
1478
+ * @param index - index of existed block
1479
+ * @param block - new block
1480
+ */replace(n,h){if(this.blocks[n]===void 0)throw Error("Incorrect index");this.blocks[n].holder.replaceWith(h.holder),this.blocks[n]=h
1481
+ /**
1482
+ * Inserts several blocks at once
1483
+ *
1484
+ * @param blocks - blocks to insert
1485
+ * @param index - index to insert blocks at
1486
+ */}insertMany(n,h){const p=new DocumentFragment;for(const h of n)p.appendChild(h.holder);if(this.length>0){if(h>0){const n=Math.min(h-1,this.length-1);this.blocks[n].holder.after(p)}else h===0&&this.workingArea.prepend(p);this.blocks.splice(h,0,...n)}else this.blocks.push(...n),this.workingArea.appendChild(p);n.forEach((n=>n.call($.RENDERED)))}
1487
+ /**
1488
+ * Remove block
1489
+ *
1490
+ * @param {number} index - index of Block to remove
1491
+ */remove(n){isNaN(n)&&(n=this.length-1),this.blocks[n].holder.remove(),this.blocks[n].call($.REMOVED),this.blocks.splice(n,1)}removeAll(){this.workingArea.innerHTML="",this.blocks.forEach((n=>n.call($.REMOVED))),this.blocks.length=0
1492
+ /**
1493
+ * Insert Block after passed target
1494
+ *
1495
+ * @todo decide if this method is necessary
1496
+ * @param {Block} targetBlock — target after which Block should be inserted
1497
+ * @param {Block} newBlock — Block to insert
1498
+ */}insertAfter(n,h){const p=this.blocks.indexOf(n);this.insert(p+1,h)}
1499
+ /**
1500
+ * Get Block by index
1501
+ *
1502
+ * @param {number} index — Block index
1503
+ * @returns {Block}
1504
+ */get(n){return this.blocks[n]}
1505
+ /**
1506
+ * Return index of passed Block
1507
+ *
1508
+ * @param {Block} block - Block to find
1509
+ * @returns {number}
1510
+ */indexOf(n){return this.blocks.indexOf(n)}
1511
+ /**
1512
+ * Insert new Block into DOM
1513
+ *
1514
+ * @param {Block} block - Block to insert
1515
+ * @param {InsertPosition} position — insert position (if set, will use insertAdjacentElement)
1516
+ * @param {Block} target — Block related to position
1517
+ */insertToDOM(n,h,p){h?p.holder.insertAdjacentElement(h,n.holder):this.workingArea.appendChild(n.holder),n.call($.RENDERED)
1518
+ /**
1519
+ * Composes Block event with passed type and details
1520
+ *
1521
+ * @param {string} type - event type
1522
+ * @param {object} detail - event detail
1523
+ */}composeBlockEvent(n,h){return new CustomEvent(n,{detail:h})}}const Jo="block-removed",di="block-added",hi="block-moved",bi="block-changed";class Qi{constructor(){this.completed=Promise.resolve()}
1524
+ /**
1525
+ * Add new promise to queue
1526
+ *
1527
+ * @param operation - promise should be added to queue
1528
+ */add(n){return new Promise(((h,p)=>{this.completed=this.completed.then(n).then(h).catch(p)}))}}class es extends y{constructor(){super(...arguments),this._currentBlockIndex=-1,this._blocks=null
1529
+ /**
1530
+ * Returns current Block index
1531
+ *
1532
+ * @returns {number}
1533
+ */}get currentBlockIndex(){return this._currentBlockIndex}
1534
+ /**
1535
+ * Set current Block index and fire Block lifecycle callbacks
1536
+ *
1537
+ * @param {number} newIndex - index of Block to set as current
1538
+ */set currentBlockIndex(n){this._currentBlockIndex=n}
1539
+ /**
1540
+ * returns first Block
1541
+ *
1542
+ * @returns {Block}
1543
+ */get firstBlock(){return this._blocks[0]}
1544
+ /**
1545
+ * returns last Block
1546
+ *
1547
+ * @returns {Block}
1548
+ */get lastBlock(){return this._blocks[this._blocks.length-1]}
1549
+ /**
1550
+ * Get current Block instance
1551
+ *
1552
+ * @returns {Block}
1553
+ */get currentBlock(){return this._blocks[this.currentBlockIndex]}
1554
+ /**
1555
+ * Set passed Block as a current
1556
+ *
1557
+ * @param block - block to set as a current
1558
+ */set currentBlock(n){this.currentBlockIndex=this.getBlockIndex(n)}
1559
+ /**
1560
+ * Returns next Block instance
1561
+ *
1562
+ * @returns {Block|null}
1563
+ */get nextBlock(){return this.currentBlockIndex===this._blocks.length-1?null:this._blocks[this.currentBlockIndex+1]}
1564
+ /**
1565
+ * Return first Block with inputs after current Block
1566
+ *
1567
+ * @returns {Block | undefined}
1568
+ */get nextContentfulBlock(){return this.blocks.slice(this.currentBlockIndex+1).find((n=>!!n.inputs.length))}
1569
+ /**
1570
+ * Return first Block with inputs before current Block
1571
+ *
1572
+ * @returns {Block | undefined}
1573
+ */get previousContentfulBlock(){return this.blocks.slice(0,this.currentBlockIndex).reverse().find((n=>!!n.inputs.length))}
1574
+ /**
1575
+ * Returns previous Block instance
1576
+ *
1577
+ * @returns {Block|null}
1578
+ */get previousBlock(){return this.currentBlockIndex===0?null:this._blocks[this.currentBlockIndex-1]}
1579
+ /**
1580
+ * Get array of Block instances
1581
+ *
1582
+ * @returns {Block[]} {@link Blocks#array}
1583
+ */get blocks(){return this._blocks.array}
1584
+ /**
1585
+ * Check if each Block is empty
1586
+ *
1587
+ * @returns {boolean}
1588
+ */get isEditorEmpty(){return this.blocks.every((n=>n.isEmpty))}prepare(){const n=new Xe(this.Editor.UI.nodes.redactor);this._blocks=new Proxy(n,{set:Xe.set,get:Xe.get}),this.listeners.on(document,"copy",(n=>this.Editor.BlockEvents.handleCommandC(n)))
1589
+ /**
1590
+ * Toggle read-only state
1591
+ *
1592
+ * If readOnly is true:
1593
+ * - Unbind event handlers from created Blocks
1594
+ *
1595
+ * if readOnly is false:
1596
+ * - Bind event handlers to all existing Blocks
1597
+ *
1598
+ * @param {boolean} readOnlyEnabled - "read only" state
1599
+ */}toggleReadOnly(n){n?this.disableModuleBindings():this.enableModuleBindings()}
1600
+ /**
1601
+ * Creates Block instance by tool name
1602
+ *
1603
+ * @param {object} options - block creation options
1604
+ * @param {string} options.tool - tools passed in editor config {@link EditorConfig#tools}
1605
+ * @param {string} [options.id] - unique id for this block
1606
+ * @param {BlockToolData} [options.data] - constructor params
1607
+ * @returns {Block}
1608
+ */composeBlock({tool:n,data:h={},id:p,tunes:g={}}){const m=this.Editor.ReadOnly.isEnabled,v=this.Editor.Tools.blockTools.get(n),x=new D({id:p,data:h,tool:v,api:this.Editor.API,readOnly:m,tunesData:g},this.eventsDispatcher);return m||window.requestIdleCallback((()=>{this.bindBlockEvents(x)}),{timeout:2e3}),x
1609
+ /**
1610
+ * Insert new block into _blocks
1611
+ *
1612
+ * @param {object} options - insert options
1613
+ * @param {string} [options.id] - block's unique id
1614
+ * @param {string} [options.tool] - plugin name, by default method inserts the default block type
1615
+ * @param {object} [options.data] - plugin data
1616
+ * @param {number} [options.index] - index where to insert new Block
1617
+ * @param {boolean} [options.needToFocus] - flag shows if needed to update current Block index
1618
+ * @param {boolean} [options.replace] - flag shows if block by passed index should be replaced with inserted one
1619
+ * @returns {Block}
1620
+ */}insert({id:n,tool:h=this.config.defaultBlock,data:p={},index:g,needToFocus:m=!0,replace:v=!1,tunes:x={}}={}){let w=g;w===void 0&&(w=this.currentBlockIndex+(v?0:1));const E=this.composeBlock({id:n,tool:h,data:p,tunes:x});return v&&this.blockDidMutated(Jo,this.getBlockByIndex(w),{index:w}),this._blocks.insert(w,E,v),this.blockDidMutated(di,E,{index:w}),m?this.currentBlockIndex=w:w<=this.currentBlockIndex&&this.currentBlockIndex++,E
1621
+ /**
1622
+ * Inserts several blocks at once
1623
+ *
1624
+ * @param blocks - blocks to insert
1625
+ * @param index - index where to insert
1626
+ */}insertMany(n,h=0){this._blocks.insertMany(n,h)}
1627
+ /**
1628
+ * Update Block data.
1629
+ *
1630
+ * Currently we don't have an 'update' method in the Tools API, so we just create a new block with the same id and type
1631
+ * Should not trigger 'block-removed' or 'block-added' events.
1632
+ *
1633
+ * If neither data nor tunes is provided, return the provided block instead.
1634
+ *
1635
+ * @param block - block to update
1636
+ * @param data - (optional) new data
1637
+ * @param tunes - (optional) tune data
1638
+ */async update(n,h,p){if(!h&&!p)return n;const g=await n.data,m=this.composeBlock({id:n.id,tool:n.name,data:Object.assign({},g,h??{}),tunes:p??n.tunes}),v=this.getBlockIndex(n);return this._blocks.replace(v,m),this.blockDidMutated(bi,m,{index:v}),m
1639
+ /**
1640
+ * Replace passed Block with the new one with specified Tool and data
1641
+ *
1642
+ * @param block - block to replace
1643
+ * @param newTool - new Tool name
1644
+ * @param data - new Tool data
1645
+ */}replace(n,h,p){const g=this.getBlockIndex(n);return this.insert({tool:h,data:p,index:g,replace:!0})}
1646
+ /**
1647
+ * Insert pasted content. Call onPaste callback after insert.
1648
+ *
1649
+ * @param {string} toolName - name of Tool to insert
1650
+ * @param {PasteEvent} pasteEvent - pasted data
1651
+ * @param {boolean} replace - should replace current block
1652
+ */paste(n,h,p=!1){const m=this.insert({tool:n,replace:p});try{window.requestIdleCallback((()=>{m.call($.ON_PASTE,h)}))}catch(h){g(`${n}: onPaste callback call is failed`,"error",h)}return m}
1653
+ /**
1654
+ * Insert new default block at passed index
1655
+ *
1656
+ * @param {number} index - index where Block should be inserted
1657
+ * @param {boolean} needToFocus - if true, updates current Block index
1658
+ *
1659
+ * TODO: Remove method and use insert() with index instead (?)
1660
+ * @returns {Block} inserted Block
1661
+ */insertDefaultBlockAtIndex(n,h=!1){const p=this.composeBlock({tool:this.config.defaultBlock});return this._blocks[n]=p,this.blockDidMutated(di,p,{index:n}),h?this.currentBlockIndex=n:n<=this.currentBlockIndex&&this.currentBlockIndex++,p
1662
+ /**
1663
+ * Always inserts at the end
1664
+ *
1665
+ * @returns {Block}
1666
+ */}insertAtEnd(){return this.currentBlockIndex=this.blocks.length-1,this.insert()
1667
+ /**
1668
+ * Merge two blocks
1669
+ *
1670
+ * @param {Block} targetBlock - previous block will be append to this block
1671
+ * @param {Block} blockToMerge - block that will be merged with target block
1672
+ * @returns {Promise} - the sequence that can be continued
1673
+ */}async mergeBlocks(n,h){let p;if(n.name===h.name&&n.mergeable){const g=await h.data;if(V(g)){console.error("Could not merge Block. Failed to extract original Block data.");return}const[m]=it([g],n.tool.sanitizeConfig);p=m}else if(n.mergeable&&_e(h,"export")&&_e(n,"import")){const g=await h.exportDataAsString(),m=q(g,n.tool.sanitizeConfig);p=xt(m,n.tool.conversionConfig)}p!==void 0&&(await n.mergeWith(p),this.removeBlock(h),this.currentBlockIndex=this._blocks.indexOf(n)
1674
+ /**
1675
+ * Remove passed Block
1676
+ *
1677
+ * @param block - Block to remove
1678
+ * @param addLastBlock - if true, adds new default block at the end. @todo remove this logic and use event-bus instead
1679
+ */)}removeBlock(n,h=!0){return new Promise((p=>{const g=this._blocks.indexOf(n);if(!this.validateIndex(g))throw new Error("Can't find a Block to remove");n.destroy(),this._blocks.remove(g),this.blockDidMutated(Jo,n,{index:g}),this.currentBlockIndex>=g&&this.currentBlockIndex--,this.blocks.length?g===0&&(this.currentBlockIndex=0):(this.unsetCurrentBlock(),h&&this.insert()),p()}))}
1680
+ /**
1681
+ * Remove only selected Blocks
1682
+ * and returns first Block index where started removing...
1683
+ *
1684
+ * @returns {number|undefined}
1685
+ */removeSelectedBlocks(){let n;for(let h=this.blocks.length-1;h>=0;h--)this.blocks[h].selected&&(this.removeBlock(this.blocks[h]),n=h);return n}removeAllBlocks(){for(let n=this.blocks.length-1;n>=0;n--)this._blocks.remove(n);this.unsetCurrentBlock(),this.insert(),this.currentBlock.firstInput.focus()
1686
+ /**
1687
+ * Split current Block
1688
+ * 1. Extract content from Caret position to the Block`s end
1689
+ * 2. Insert a new Block below current one with extracted content
1690
+ *
1691
+ * @returns {Block}
1692
+ */}split(){const n=this.Editor.Caret.extractFragmentFromCaretPosition(),h=d.make("div");h.appendChild(n);const p={text:d.isEmpty(h)?"":h.innerHTML};return this.insert({data:p})}
1693
+ /**
1694
+ * Returns Block by passed index
1695
+ *
1696
+ * @param {number} index - index to get. -1 to get last
1697
+ * @returns {Block}
1698
+ */getBlockByIndex(n){return n===-1&&(n=this._blocks.length-1),this._blocks[n]
1699
+ /**
1700
+ * Returns an index for passed Block
1701
+ *
1702
+ * @param block - block to find index
1703
+ */}getBlockIndex(n){return this._blocks.indexOf(n)}
1704
+ /**
1705
+ * Returns the Block by passed id
1706
+ *
1707
+ * @param id - id of block to get
1708
+ * @returns {Block}
1709
+ */getBlockById(n){return this._blocks.array.find((h=>h.id===n))}
1710
+ /**
1711
+ * Get Block instance by html element
1712
+ *
1713
+ * @param {Node} element - html element to get Block by
1714
+ */getBlock(n){d.isElement(n)||(n=n.parentNode);const h=this._blocks.nodes,p=n.closest(`.${D.CSS.wrapper}`),g=h.indexOf(p);if(g>=0)return this._blocks[g]}
1715
+ /**
1716
+ * 1) Find first-level Block from passed child Node
1717
+ * 2) Mark it as current
1718
+ *
1719
+ * @param {Node} childNode - look ahead from this node.
1720
+ * @returns {Block | undefined} can return undefined in case when the passed child note is not a part of the current editor instance
1721
+ */setCurrentBlockByChildNode(n){d.isElement(n)||(n=n.parentNode);const h=n.closest(`.${D.CSS.wrapper}`);if(!h)return;const p=h.closest(`.${this.Editor.UI.CSS.editorWrapper}`);return p!=null&&p.isEqualNode(this.Editor.UI.nodes.wrapper)?(this.currentBlockIndex=this._blocks.nodes.indexOf(h),this.currentBlock.updateCurrentInput(),this.currentBlock
1722
+ /**
1723
+ * Return block which contents passed node
1724
+ *
1725
+ * @param {Node} childNode - node to get Block by
1726
+ * @returns {Block}
1727
+ */):void 0}getBlockByChildNode(n){if(!n||!(n instanceof Node))return;d.isElement(n)||(n=n.parentNode);const h=n.closest(`.${D.CSS.wrapper}`);return this.blocks.find((n=>n.holder===h))}
1728
+ /**
1729
+ * Swap Blocks Position
1730
+ *
1731
+ * @param {number} fromIndex - index of first block
1732
+ * @param {number} toIndex - index of second block
1733
+ * @deprecated — use 'move' instead
1734
+ */swap(n,h){this._blocks.swap(n,h),this.currentBlockIndex=h
1735
+ /**
1736
+ * Move a block to a new index
1737
+ *
1738
+ * @param {number} toIndex - index where to move Block
1739
+ * @param {number} fromIndex - index of Block to move
1740
+ */}move(n,h=this.currentBlockIndex){isNaN(n)||isNaN(h)?g("Warning during 'move' call: incorrect indices provided.","warn"):this.validateIndex(n)&&this.validateIndex(h)?(this._blocks.move(n,h),this.currentBlockIndex=n,this.blockDidMutated(hi,this.currentBlock,{fromIndex:h,toIndex:n})
1741
+ /**
1742
+ * Converts passed Block to the new Tool
1743
+ * Uses Conversion Config
1744
+ *
1745
+ * @param blockToConvert - Block that should be converted
1746
+ * @param targetToolName - name of the Tool to convert to
1747
+ * @param blockDataOverrides - optional new Block data overrides
1748
+ */):g("Warning during 'move' call: indices cannot be lower than 0 or greater than the amount of blocks.","warn")}async convert(n,h,p){if(!await n.save())throw new Error("Could not convert Block. Failed to extract original Block data.");const g=this.Editor.Tools.blockTools.get(h);if(!g)throw new Error(`Could not convert Block. Tool «${h}» not found.`);const m=await n.exportDataAsString(),v=q(m,g.sanitizeConfig);let x=xt(v,g.conversionConfig);return p&&(x=Object.assign(x,p)),this.replace(n,g.name,x)}unsetCurrentBlock(){this.currentBlockIndex=-1}
1749
+ /**
1750
+ * Clears Editor
1751
+ *
1752
+ * @param {boolean} needToAddDefaultBlock - 1) in internal calls (for example, in api.blocks.render)
1753
+ * we don't need to add an empty default block
1754
+ * 2) in api.blocks.clear we should add empty block
1755
+ */async clear(n=!1){const h=new Qi;this.blocks.forEach((n=>{h.add((async()=>{await this.removeBlock(n,!1)}))})),await h.completed,this.unsetCurrentBlock(),n&&this.insert(),this.Editor.UI.checkEmptiness()}async destroy(){await Promise.all(this.blocks.map((n=>n.destroy())))}
1756
+ /**
1757
+ * Bind Block events
1758
+ *
1759
+ * @param {Block} block - Block to which event should be bound
1760
+ */bindBlockEvents(n){const{BlockEvents:h}=this.Editor;this.readOnlyMutableListeners.on(n.holder,"keydown",(n=>{h.keydown(n)})),this.readOnlyMutableListeners.on(n.holder,"keyup",(n=>{h.keyup(n)})),this.readOnlyMutableListeners.on(n.holder,"dragover",(n=>{h.dragOver(n)})),this.readOnlyMutableListeners.on(n.holder,"dragleave",(n=>{h.dragLeave(n)})),n.on("didMutated",(n=>this.blockDidMutated(bi,n,{index:this.getBlockIndex(n)})))}disableModuleBindings(){this.readOnlyMutableListeners.clearAll()}enableModuleBindings(){this.readOnlyMutableListeners.on(document,"cut",(n=>this.Editor.BlockEvents.handleCommandX(n))),this.blocks.forEach((n=>{this.bindBlockEvents(n)}))
1761
+ /**
1762
+ * Validates that the given index is not lower than 0 or higher than the amount of blocks
1763
+ *
1764
+ * @param {number} index - index of blocks array to validate
1765
+ * @returns {boolean}
1766
+ */}validateIndex(n){return!(n<0||n>=this._blocks.length)}
1767
+ /**
1768
+ * Block mutation callback
1769
+ *
1770
+ * @param mutationType - what happened with block
1771
+ * @param block - mutated block
1772
+ * @param detailData - additional data to pass with change event
1773
+ */blockDidMutated(n,h,p){const g=new CustomEvent(n,{detail:{target:new G(h),...p}});return this.eventsDispatcher.emit(N,{event:g}),h}}class ts extends y{constructor(){super(...arguments),this.anyBlockSelectedCache=null,this.needToSelectAll=!1,this.nativeInputSelected=!1,this.readyToBlockSelection=!1
1774
+ /**
1775
+ * Sanitizer Config
1776
+ *
1777
+ * @returns {SanitizerConfig}
1778
+ */}get sanitizerConfig(){return{p:{},h1:{},h2:{},h3:{},h4:{},h5:{},h6:{},ol:{},ul:{},li:{},br:!0,img:{src:!0,width:!0,height:!0},a:{href:!0},b:{},i:{},u:{}}}
1779
+ /**
1780
+ * Flag that identifies all Blocks selection
1781
+ *
1782
+ * @returns {boolean}
1783
+ */get allBlocksSelected(){const{BlockManager:n}=this.Editor;return n.blocks.every((n=>n.selected===!0))}
1784
+ /**
1785
+ * Set selected all blocks
1786
+ *
1787
+ * @param {boolean} state - state to set
1788
+ */set allBlocksSelected(n){const{BlockManager:h}=this.Editor;h.blocks.forEach((h=>{h.selected=n})),this.clearCache()
1789
+ /**
1790
+ * Flag that identifies any Block selection
1791
+ *
1792
+ * @returns {boolean}
1793
+ */}get anyBlockSelected(){const{BlockManager:n}=this.Editor;return this.anyBlockSelectedCache===null&&(this.anyBlockSelectedCache=n.blocks.some((n=>n.selected===!0))),this.anyBlockSelectedCache
1794
+ /**
1795
+ * Return selected Blocks array
1796
+ *
1797
+ * @returns {Block[]}
1798
+ */}get selectedBlocks(){return this.Editor.BlockManager.blocks.filter((n=>n.selected))}prepare(){this.selection=new b,io.add({name:"CMD+A",handler:n=>{const{BlockManager:h,ReadOnly:p}=this.Editor;p.isEnabled?(n.preventDefault(),this.selectAllBlocks()):h.currentBlock&&this.handleCommandA(n)},on:this.Editor.UI.nodes.redactor})}toggleReadOnly(){b.get().removeAllRanges(),this.allBlocksSelected=!1
1799
+ /**
1800
+ * Remove selection of Block
1801
+ *
1802
+ * @param {number?} index - Block index according to the BlockManager's indexes
1803
+ */}unSelectBlockByIndex(n){const{BlockManager:h}=this.Editor;let p;p=isNaN(n)?h.currentBlock:h.getBlockByIndex(n),p.selected=!1,this.clearCache()
1804
+ /**
1805
+ * Clear selection from Blocks
1806
+ *
1807
+ * @param {Event} reason - event caused clear of selection
1808
+ * @param {boolean} restoreSelection - if true, restore saved selection
1809
+ */}clearSelection(n,h=!1){const{BlockManager:p,Caret:g,RectangleSelection:m}=this.Editor;this.needToSelectAll=!1,this.nativeInputSelected=!1,this.readyToBlockSelection=!1;const v=n&&n instanceof KeyboardEvent,x=v&&Mt(n.keyCode);if(this.anyBlockSelected&&v&&x&&!b.isSelectionExists){const h=p.removeSelectedBlocks();p.insertDefaultBlockAtIndex(h,!0),g.setToBlock(p.currentBlock),Oe((()=>{const h=n.key;g.insertContentAtCaretPosition(h.length>1?"":h)}),20)()}this.Editor.CrossBlockSelection.clear(n),this.anyBlockSelected&&!m.isRectActivated()?(h&&this.selection.restore(),this.allBlocksSelected=!1
1810
+ /**
1811
+ * Reduce each Block and copy its content
1812
+ *
1813
+ * @param {ClipboardEvent} e - copy/cut event
1814
+ * @returns {Promise<void>}
1815
+ */):this.Editor.RectangleSelection.clearSelection()}copySelectedBlocks(n){n.preventDefault();const h=d.make("div");this.selectedBlocks.forEach((n=>{const p=q(n.holder.innerHTML,this.sanitizerConfig),g=d.make("p");g.innerHTML=p,h.appendChild(g)}));const p=Array.from(h.childNodes).map((n=>n.textContent)).join("\n\n"),g=h.innerHTML;return n.clipboardData.setData("text/plain",p),n.clipboardData.setData("text/html",g),Promise.all(this.selectedBlocks.map((n=>n.save()))).then((h=>{try{n.clipboardData.setData(this.Editor.Paste.MIME_TYPE,JSON.stringify(h))}catch{}}))
1816
+ /**
1817
+ * Select Block by its index
1818
+ *
1819
+ * @param {number?} index - Block index according to the BlockManager's indexes
1820
+ */}selectBlockByIndex(n){const{BlockManager:h}=this.Editor,p=h.getBlockByIndex(n);p!==void 0&&this.selectBlock(p)}
1821
+ /**
1822
+ * Select passed Block
1823
+ *
1824
+ * @param {Block} block - Block to select
1825
+ */selectBlock(n){this.selection.save(),b.get().removeAllRanges(),n.selected=!0,this.clearCache(),this.Editor.InlineToolbar.close()
1826
+ /**
1827
+ * Remove selection from passed Block
1828
+ *
1829
+ * @param {Block} block - Block to unselect
1830
+ */}unselectBlock(n){n.selected=!1,this.clearCache()}clearCache(){this.anyBlockSelectedCache=null}destroy(){io.remove(this.Editor.UI.nodes.redactor,"CMD+A")}
1831
+ /**
1832
+ * First CMD+A selects all input content by native behaviour,
1833
+ * next CMD+A keypress selects all blocks
1834
+ *
1835
+ * @param {KeyboardEvent} event - keyboard event
1836
+ */handleCommandA(n){if(this.Editor.RectangleSelection.clearSelection(),d.isNativeInput(n.target)&&!this.readyToBlockSelection){this.readyToBlockSelection=!0;return}const h=this.Editor.BlockManager.getBlock(n.target),p=h.inputs;p.length>1&&!this.readyToBlockSelection?this.readyToBlockSelection=!0:p.length!==1||this.needToSelectAll?this.needToSelectAll?(n.preventDefault(),this.selectAllBlocks(),this.needToSelectAll=!1,this.readyToBlockSelection=!1):this.readyToBlockSelection&&(n.preventDefault(),this.selectBlock(h),this.needToSelectAll=!0):this.needToSelectAll=!0}selectAllBlocks(){this.selection.save(),b.get().removeAllRanges(),this.allBlocksSelected=!0,this.Editor.InlineToolbar.close()}}class Re extends y{
1837
+ /**
1838
+ * Allowed caret positions in input
1839
+ *
1840
+ * @static
1841
+ * @returns {{START: string, END: string, DEFAULT: string}}
1842
+ */
1843
+ get positions(){return{START:"start",END:"end",DEFAULT:"default"}}static get CSS(){return{shadowCaret:"cdx-shadow-caret"}}
1844
+ /**
1845
+ * Method gets Block instance and puts caret to the text node with offset
1846
+ * There two ways that method applies caret position:
1847
+ * - first found text node: sets at the beginning, but you can pass an offset
1848
+ * - last found text node: sets at the end of the node. Also, you can customize the behaviour
1849
+ *
1850
+ * @param {Block} block - Block class
1851
+ * @param {string} position - position where to set caret.
1852
+ * If default - leave default behaviour and apply offset if it's passed
1853
+ * @param {number} offset - caret offset regarding to the text node
1854
+ */setToBlock(n,h=this.positions.DEFAULT,p=0){var g;const{BlockManager:m,BlockSelection:v}=this.Editor;if(v.clearSelection(),!n.focusable){(g=window.getSelection())==null||g.removeAllRanges(),v.selectBlock(n),m.currentBlock=n;return}let x;switch(h){case this.positions.START:x=n.firstInput;break;case this.positions.END:x=n.lastInput;break;default:x=n.currentInput}if(!x)return;const w=d.getDeepestNode(x,h===this.positions.END),E=d.getContentLength(w);switch(!0){case h===this.positions.START:p=0;break;case h===this.positions.END:case p>E:p=E;break}this.set(w,p),m.setCurrentBlockByChildNode(n.holder),m.currentBlock.currentInput=x
1855
+ /**
1856
+ * Set caret to the current input of current Block.
1857
+ *
1858
+ * @param {HTMLElement} input - input where caret should be set
1859
+ * @param {string} position - position of the caret.
1860
+ * If default - leave default behaviour and apply offset if it's passed
1861
+ * @param {number} offset - caret offset regarding to the text node
1862
+ */}setToInput(n,h=this.positions.DEFAULT,p=0){const{currentBlock:g}=this.Editor.BlockManager,m=d.getDeepestNode(n);switch(h){case this.positions.START:this.set(m,0);break;case this.positions.END:this.set(m,d.getContentLength(m));break;default:p&&this.set(m,p)}g.currentInput=n}
1863
+ /**
1864
+ * Creates Document Range and sets caret to the element with offset
1865
+ *
1866
+ * @param {HTMLElement} element - target node.
1867
+ * @param {number} offset - offset
1868
+ */set(n,h=0){const{top:p,bottom:g}=b.setCursor(n,h),{innerHeight:m}=window;p<0?window.scrollBy(0,p-30):g>m&&window.scrollBy(0,g-m+30)}setToTheLastBlock(){const n=this.Editor.BlockManager.lastBlock;if(n)if(n.tool.isDefault&&n.isEmpty)this.setToBlock(n);else{const n=this.Editor.BlockManager.insertAtEnd();this.setToBlock(n)}}extractFragmentFromCaretPosition(){const n=b.get();if(n.rangeCount){const h=n.getRangeAt(0),p=this.Editor.BlockManager.currentBlock.currentInput;if(h.deleteContents(),p){if(d.isNativeInput(p)){const n=p,h=document.createDocumentFragment(),g=n.value.substring(0,n.selectionStart),m=n.value.substring(n.selectionStart);return h.textContent=m,n.value=g,h}{const n=h.cloneRange();return n.selectNodeContents(p),n.setStart(h.endContainer,h.endOffset),n.extractContents()}}}}
1869
+ /**
1870
+ * Set's caret to the next Block or Tool`s input
1871
+ * Before moving caret, we should check if caret position is at the end of Plugins node
1872
+ * Using {@link Dom#getDeepestNode} to get a last node and match with current selection
1873
+ *
1874
+ * @param {boolean} force - pass true to skip check for caret position
1875
+ */navigateNext(n=!1){const{BlockManager:h}=this.Editor,{currentBlock:p,nextBlock:g}=h;if(p===void 0)return!1;const{nextInput:m,currentInput:v}=p,x=v!==void 0?Ae(v):void 0;let w=g;const E=n||x||!p.focusable;if(m&&E)return this.setToInput(m,this.positions.START),!0;if(w===null){if(p.tool.isDefault||!E)return!1;w=h.insertAtEnd()}return!!E&&(this.setToBlock(w,this.positions.START),!0)}
1876
+ /**
1877
+ * Set's caret to the previous Tool`s input or Block
1878
+ * Before moving caret, we should check if caret position is start of the Plugins node
1879
+ * Using {@link Dom#getDeepestNode} to get a last node and match with current selection
1880
+ *
1881
+ * @param {boolean} force - pass true to skip check for caret position
1882
+ */navigatePrevious(n=!1){const{currentBlock:h,previousBlock:p}=this.Editor.BlockManager;if(!h)return!1;const{previousInput:g,currentInput:m}=h,v=m!==void 0?Me(m):void 0,x=n||v||!h.focusable;return g&&x?(this.setToInput(g,this.positions.END),!0):!(p===null||!x)&&(this.setToBlock(p,this.positions.END),!0)}
1883
+ /**
1884
+ * Inserts shadow element after passed element where caret can be placed
1885
+ *
1886
+ * @param {Element} element - element after which shadow caret should be inserted
1887
+ */createShadow(n){const h=document.createElement("span");h.classList.add(Re.CSS.shadowCaret),n.insertAdjacentElement("beforeend",h)
1888
+ /**
1889
+ * Restores caret position
1890
+ *
1891
+ * @param {HTMLElement} element - element where caret should be restored
1892
+ */}restoreCaret(n){const h=n.querySelector(`.${Re.CSS.shadowCaret}`);if(!h)return;(new b).expandToTag(h);const p=document.createRange();p.selectNode(h),p.extractContents()
1893
+ /**
1894
+ * Inserts passed content at caret position
1895
+ *
1896
+ * @param {string} content - content to insert
1897
+ */}insertContentAtCaretPosition(n){const h=document.createDocumentFragment(),p=document.createElement("div"),g=b.get(),m=b.range;p.innerHTML=n,Array.from(p.childNodes).forEach((n=>h.appendChild(n))),h.childNodes.length===0&&h.appendChild(new Text);const v=h.lastChild;m.deleteContents(),m.insertNode(h);const x=document.createRange(),w=v.nodeType===Node.TEXT_NODE?v:v.firstChild;w!==null&&w.textContent!==null&&x.setStart(w,w.textContent.length),g.removeAllRanges(),g.addRange(x)}}class os extends y{constructor(){super(...arguments),this.onMouseUp=()=>{this.listeners.off(document,"mouseover",this.onMouseOver),this.listeners.off(document,"mouseup",this.onMouseUp)},this.onMouseOver=n=>{const{BlockManager:h,BlockSelection:p}=this.Editor;if(n.relatedTarget===null&&n.target===null)return;const g=h.getBlockByChildNode(n.relatedTarget)||this.lastSelectedBlock,m=h.getBlockByChildNode(n.target);if(!(!g||!m)&&m!==g){if(g===this.firstSelectedBlock){b.get().removeAllRanges(),g.selected=!0,m.selected=!0,p.clearCache();return}if(m===this.firstSelectedBlock){g.selected=!1,m.selected=!1,p.clearCache();return}this.Editor.InlineToolbar.close(),this.toggleBlocksSelectedState(g,m),this.lastSelectedBlock=m}}
1898
+ /**
1899
+ * Module preparation
1900
+ *
1901
+ * @returns {Promise}
1902
+ */}async prepare(){this.listeners.on(document,"mousedown",(n=>{this.enableCrossBlockSelection(n)}))}
1903
+ /**
1904
+ * Sets up listeners
1905
+ *
1906
+ * @param {MouseEvent} event - mouse down event
1907
+ */watchSelection(n){if(n.button!==p.LEFT)return;const{BlockManager:h}=this.Editor;this.firstSelectedBlock=h.getBlock(n.target),this.lastSelectedBlock=this.firstSelectedBlock,this.listeners.on(document,"mouseover",this.onMouseOver),this.listeners.on(document,"mouseup",this.onMouseUp)}get isCrossBlockSelectionStarted(){return!!this.firstSelectedBlock&&!!this.lastSelectedBlock&&this.firstSelectedBlock!==this.lastSelectedBlock}
1908
+ /**
1909
+ * Change selection state of the next Block
1910
+ * Used for CBS via Shift + arrow keys
1911
+ *
1912
+ * @param {boolean} next - if true, toggle next block. Previous otherwise
1913
+ */toggleBlockSelectedState(n=!0){const{BlockManager:h,BlockSelection:p}=this.Editor;this.lastSelectedBlock||(this.lastSelectedBlock=this.firstSelectedBlock=h.currentBlock),this.firstSelectedBlock===this.lastSelectedBlock&&(this.firstSelectedBlock.selected=!0,p.clearCache(),b.get().removeAllRanges());const g=h.blocks.indexOf(this.lastSelectedBlock)+(n?1:-1),m=h.blocks[g];m&&(this.lastSelectedBlock.selected!==m.selected?(m.selected=!0,p.clearCache()):(this.lastSelectedBlock.selected=!1,p.clearCache()),this.lastSelectedBlock=m,this.Editor.InlineToolbar.close(),m.holder.scrollIntoView({block:"nearest"})
1914
+ /**
1915
+ * Clear saved state
1916
+ *
1917
+ * @param {Event} reason - event caused clear of selection
1918
+ */)}clear(n){const{BlockManager:p,BlockSelection:g,Caret:m}=this.Editor,v=p.blocks.indexOf(this.firstSelectedBlock),x=p.blocks.indexOf(this.lastSelectedBlock);if(g.anyBlockSelected&&v>-1&&x>-1&&n&&n instanceof KeyboardEvent)switch(n.keyCode){case h.DOWN:case h.RIGHT:m.setToBlock(p.blocks[Math.max(v,x)],m.positions.END);break;case h.UP:case h.LEFT:m.setToBlock(p.blocks[Math.min(v,x)],m.positions.START);break;default:m.setToBlock(p.blocks[Math.max(v,x)],m.positions.END)}this.firstSelectedBlock=this.lastSelectedBlock=null}
1919
+ /**
1920
+ * Enables Cross Block Selection
1921
+ *
1922
+ * @param {MouseEvent} event - mouse down event
1923
+ */enableCrossBlockSelection(n){const{UI:h}=this.Editor;b.isCollapsed||this.Editor.BlockSelection.clearSelection(n),h.nodes.redactor.contains(n.target)?this.watchSelection(n):this.Editor.BlockSelection.clearSelection(n)
1924
+ /**
1925
+ * Change blocks selection state between passed two blocks.
1926
+ *
1927
+ * @param {Block} firstBlock - first block in range
1928
+ * @param {Block} lastBlock - last block in range
1929
+ */}toggleBlocksSelectedState(n,h){const{BlockManager:p,BlockSelection:g}=this.Editor,m=p.blocks.indexOf(n),v=p.blocks.indexOf(h),x=n.selected!==h.selected;for(let w=Math.min(m,v);w<=Math.max(m,v);w++){const m=p.blocks[w];m!==this.firstSelectedBlock&&m!==(x?n:h)&&(p.blocks[w].selected=!p.blocks[w].selected,g.clearCache())}}}class is extends y{constructor(){super(...arguments),this.isStartedAtEditor=!1
1930
+ /**
1931
+ * Toggle read-only state
1932
+ *
1933
+ * if state is true:
1934
+ * - disable all drag-n-drop event handlers
1935
+ *
1936
+ * if state is false:
1937
+ * - restore drag-n-drop event handlers
1938
+ *
1939
+ * @param {boolean} readOnlyEnabled - "read only" state
1940
+ */}toggleReadOnly(n){n?this.disableModuleBindings():this.enableModuleBindings()}enableModuleBindings(){const{UI:n}=this.Editor;this.readOnlyMutableListeners.on(n.nodes.holder,"drop",(async n=>{await this.processDrop(n)}),!0),this.readOnlyMutableListeners.on(n.nodes.holder,"dragstart",(()=>{this.processDragStart()})),this.readOnlyMutableListeners.on(n.nodes.holder,"dragover",(n=>{this.processDragOver(n)}),!0)}disableModuleBindings(){this.readOnlyMutableListeners.clearAll()}
1941
+ /**
1942
+ * Handle drop event
1943
+ *
1944
+ * @param {DragEvent} dropEvent - drop event
1945
+ */async processDrop(n){const{BlockManager:h,Paste:p,Caret:g}=this.Editor;n.preventDefault(),h.blocks.forEach((n=>{n.dropTarget=!1})),b.isAtEditor&&!b.isCollapsed&&this.isStartedAtEditor&&document.execCommand("delete"),this.isStartedAtEditor=!1;const m=h.setCurrentBlockByChildNode(n.target);if(m)this.Editor.Caret.setToBlock(m,g.positions.END);else{const n=h.setCurrentBlockByChildNode(h.lastBlock.holder);this.Editor.Caret.setToBlock(n,g.positions.END)}await p.processDataTransfer(n.dataTransfer,!0)}processDragStart(){b.isAtEditor&&!b.isCollapsed&&(this.isStartedAtEditor=!0),this.Editor.InlineToolbar.close()
1946
+ /**
1947
+ * @param {DragEvent} dragEvent - drag event
1948
+ */}processDragOver(n){n.preventDefault()}}const vi=180,ki=400;class rs extends y{
1949
+ /**
1950
+ * Prepare the module
1951
+ *
1952
+ * @param options - options used by the modification observer module
1953
+ * @param options.config - Editor configuration object
1954
+ * @param options.eventsDispatcher - common Editor event bus
1955
+ */
1956
+ constructor({config:n,eventsDispatcher:h}){super({config:n,eventsDispatcher:h}),this.disabled=!1,this.batchingTimeout=null,this.batchingOnChangeQueue=new Map,this.batchTime=ki,this.mutationObserver=new MutationObserver((n=>{this.redactorChanged(n)})),this.eventsDispatcher.on(N,(n=>{this.particularBlockChanged(n.event)})),this.eventsDispatcher.on(P,(()=>{this.disable()})),this.eventsDispatcher.on(H,(()=>{this.enable()}))}enable(){this.mutationObserver.observe(this.Editor.UI.nodes.redactor,{childList:!0,subtree:!0,characterData:!0,attributes:!0}),this.disabled=!1}disable(){this.mutationObserver.disconnect(),this.disabled=!0
1957
+ /**
1958
+ * Call onChange event passed to Editor.js configuration
1959
+ *
1960
+ * @param event - some of our custom change events
1961
+ */}particularBlockChanged(n){this.disabled||!O(this.config.onChange)||(this.batchingOnChangeQueue.set(`block:${n.detail.target.id}:event:${n.type}`,n),this.batchingTimeout&&clearTimeout(this.batchingTimeout),this.batchingTimeout=setTimeout((()=>{let n;n=this.batchingOnChangeQueue.size===1?this.batchingOnChangeQueue.values().next().value:Array.from(this.batchingOnChangeQueue.values()),this.config.onChange&&this.config.onChange(this.Editor.API.methods,n),this.batchingOnChangeQueue.clear()}),this.batchTime)
1962
+ /**
1963
+ * Fired on every blocks wrapper dom change
1964
+ *
1965
+ * @param mutations - mutations happened
1966
+ */)}redactorChanged(n){this.eventsDispatcher.emit(L,{mutations:n})}}const yi=class lo extends y{constructor(){super(...arguments),this.MIME_TYPE="application/x-editor-js",this.toolsTags={},this.tagsByTool={},this.toolsPatterns=[],this.toolsFiles={},this.exceptionList=[],this.processTool=n=>{try{const h=n.create({},{},!1);if(n.pasteConfig===!1){this.exceptionList.push(n.name);return}if(!O(h.onPaste))return;this.getTagsConfig(n),this.getFilesConfig(n),this.getPatternsConfig(n)}catch(h){g(`Paste handling for «${n.name}» Tool hasn't been set up because of the error`,"warn",h)}},this.handlePasteEvent=async n=>{const{BlockManager:h,Toolbar:p}=this.Editor,g=h.setCurrentBlockByChildNode(n.target);!g||this.isNativeBehaviour(n.target)&&!n.clipboardData.types.includes("Files")||g&&this.exceptionList.includes(g.name)||(n.preventDefault(),this.processDataTransfer(n.clipboardData),p.close())}}async prepare(){this.processTools()}
1967
+ /**
1968
+ * Set read-only state
1969
+ *
1970
+ * @param {boolean} readOnlyEnabled - read only flag value
1971
+ */toggleReadOnly(n){n?this.unsetCallback():this.setCallback()}
1972
+ /**
1973
+ * Handle pasted or dropped data transfer object
1974
+ *
1975
+ * @param {DataTransfer} dataTransfer - pasted or dropped data transfer object
1976
+ * @param {boolean} isDragNDrop - true if data transfer comes from drag'n'drop events
1977
+ */async processDataTransfer(n,h=!1){const{Tools:p}=this.Editor,g=n.types;if((g.includes?g.includes("Files"):g.contains("Files"))&&!V(this.toolsFiles)){await this.processFiles(n.files);return}const m=n.getData(this.MIME_TYPE),v=n.getData("text/plain");let x=n.getData("text/html");if(m)try{this.insertEditorJSData(JSON.parse(m));return}catch{}h&&v.trim()&&x.trim()&&(x="<p>"+(x.trim()?x:v)+"</p>");const w=Object.keys(this.toolsTags).reduce(((n,h)=>(n[h.toLowerCase()]=this.toolsTags[h].sanitizationConfig??{},n)),{}),E=Object.assign({},w,p.getAllInlineToolsSanitizeConfig(),{br:{}}),B=q(x,E);B.trim()&&B.trim()!==v&&d.isHTMLString(B)?await this.processText(B,!0):await this.processText(v)}
1978
+ /**
1979
+ * Process pasted text and divide them into Blocks
1980
+ *
1981
+ * @param {string} data - text to process. Can be HTML or plain.
1982
+ * @param {boolean} isHTML - if passed string is HTML, this parameter should be true
1983
+ */async processText(n,h=!1){const{Caret:p,BlockManager:g}=this.Editor,m=h?this.processHTML(n):this.processPlain(n);if(!m.length)return;if(m.length===1){m[0].isBlock?this.processSingleBlock(m.pop()):this.processInlinePaste(m.pop());return}const v=g.currentBlock&&g.currentBlock.tool.isDefault&&g.currentBlock.isEmpty;m.map((async(n,h)=>this.insertBlock(n,h===0&&v))),g.currentBlock&&p.setToBlock(g.currentBlock,p.positions.END)}setCallback(){this.listeners.on(this.Editor.UI.nodes.holder,"paste",this.handlePasteEvent)}unsetCallback(){this.listeners.off(this.Editor.UI.nodes.holder,"paste",this.handlePasteEvent)}processTools(){const n=this.Editor.Tools.blockTools;Array.from(n.values()).forEach(this.processTool)}
1984
+ /**
1985
+ * Get tags name list from either tag name or sanitization config.
1986
+ *
1987
+ * @param {string | object} tagOrSanitizeConfig - tag name or sanitize config object.
1988
+ * @returns {string[]} array of tags.
1989
+ */collectTagNames(n){return Q(n)?[n]:R(n)?Object.keys(n):[]}
1990
+ /**
1991
+ * Get tags to substitute by Tool
1992
+ *
1993
+ * @param tool - BlockTool object
1994
+ */getTagsConfig(n){if(n.pasteConfig===!1)return;const h=n.pasteConfig.tags||[],p=[];h.forEach((h=>{const m=this.collectTagNames(h);p.push(...m),m.forEach((p=>{if(Object.prototype.hasOwnProperty.call(this.toolsTags,p)){g(`Paste handler for «${n.name}» Tool on «${p}» tag is skipped because it is already used by «${this.toolsTags[p].tool.name}» Tool.`,"warn");return}const m=R(h)?h[p]:null;this.toolsTags[p.toUpperCase()]={tool:n,sanitizationConfig:m}}))})),this.tagsByTool[n.name]=p.map((n=>n.toUpperCase()))
1995
+ /**
1996
+ * Get files` types and extensions to substitute by Tool
1997
+ *
1998
+ * @param tool - BlockTool object
1999
+ */}getFilesConfig(n){if(n.pasteConfig===!1)return;const{files:h={}}=n.pasteConfig;let{extensions:p,mimeTypes:m}=h;!p&&!m||(p&&!Array.isArray(p)&&(g(`«extensions» property of the onDrop config for «${n.name}» Tool should be an array`),p=[]),m&&!Array.isArray(m)&&(g(`«mimeTypes» property of the onDrop config for «${n.name}» Tool should be an array`),m=[]),m&&(m=m.filter((h=>!!To(h)||(g(`MIME type value «${h}» for the «${n.name}» Tool is not a valid MIME type`,"warn"),!1)))),this.toolsFiles[n.name]={extensions:p||[],mimeTypes:m||[]}
2000
+ /**
2001
+ * Get RegExp patterns to substitute by Tool
2002
+ *
2003
+ * @param tool - BlockTool object
2004
+ */)}getPatternsConfig(n){n.pasteConfig===!1||!n.pasteConfig.patterns||V(n.pasteConfig.patterns)||Object.entries(n.pasteConfig.patterns).forEach((([h,p])=>{p instanceof RegExp||g(`Pattern ${p} for «${n.name}» Tool is skipped because it should be a Regexp instance.`,"warn"),this.toolsPatterns.push({key:h,pattern:p,tool:n})}))}
2005
+ /**
2006
+ * Check if browser behavior suits better
2007
+ *
2008
+ * @param {EventTarget} element - element where content has been pasted
2009
+ * @returns {boolean}
2010
+ */isNativeBehaviour(n){return d.isNativeInput(n)}
2011
+ /**
2012
+ * Get files from data transfer object and insert related Tools
2013
+ *
2014
+ * @param {FileList} items - pasted or dropped items
2015
+ */async processFiles(n){const{BlockManager:h}=this.Editor;let p;p=await Promise.all(Array.from(n).map((n=>this.processFile(n)))),p=p.filter((n=>!!n));const g=h.currentBlock.tool.isDefault&&h.currentBlock.isEmpty;p.forEach(((n,p)=>{h.paste(n.type,n.event,p===0&&g)}))}
2016
+ /**
2017
+ * Get information about file and find Tool to handle it
2018
+ *
2019
+ * @param {File} file - file to process
2020
+ */async processFile(n){const h=Bo(n),p=Object.entries(this.toolsFiles).find((([p,{mimeTypes:g,extensions:m}])=>{const[v,x]=n.type.split("/"),w=m.find((n=>n.toLowerCase()===h.toLowerCase())),E=g.find((n=>{const[h,p]=n.split("/");return h===v&&(p===x||p==="*")}));return!!w||!!E}));if(!p)return;const[g]=p;return{event:this.composePasteEvent("file",{file:n}),type:g}}
2021
+ /**
2022
+ * Split HTML string to blocks and return it as array of Block data
2023
+ *
2024
+ * @param {string} innerHTML - html string to process
2025
+ * @returns {PasteData[]}
2026
+ */processHTML(n){const{Tools:h}=this.Editor,p=d.make("DIV");return p.innerHTML=n,this.getNodes(p).map((n=>{let p,g=h.defaultTool,m=!1;switch(n.nodeType){case Node.DOCUMENT_FRAGMENT_NODE:p=d.make("div"),p.appendChild(n);break;case Node.ELEMENT_NODE:p=n,m=!0,this.toolsTags[p.tagName]&&(g=this.toolsTags[p.tagName].tool);break}const{tags:v}=g.pasteConfig||{tags:[]},x=v.reduce(((n,h)=>(this.collectTagNames(h).forEach((p=>{const g=R(h)?h[p]:null;n[p.toLowerCase()]=g||{}})),n)),{}),w=Object.assign({},x,g.baseSanitizeConfig);if(p.tagName.toLowerCase()==="table"){const n=q(p.outerHTML,w);p=d.make("div",void 0,{innerHTML:n}).firstChild}else p.innerHTML=q(p.innerHTML,w);const E=this.composePasteEvent("tag",{data:p});return{content:p,isBlock:m,tool:g.name,event:E}})).filter((n=>{const h=d.isEmpty(n.content),p=d.isSingleTag(n.content);return!h||p}))
2027
+ /**
2028
+ * Split plain text by new line symbols and return it as array of Block data
2029
+ *
2030
+ * @param {string} plain - string to process
2031
+ * @returns {PasteData[]}
2032
+ */}processPlain(n){const{defaultBlock:h}=this.config;if(!n)return[];const p=h;return n.split(/\r?\n/).filter((n=>n.trim())).map((n=>{const h=d.make("div");h.textContent=n;const g=this.composePasteEvent("tag",{data:h});return{content:h,tool:p,isBlock:!1,event:g}}))}
2033
+ /**
2034
+ * Process paste of single Block tool content
2035
+ *
2036
+ * @param {PasteData} dataToInsert - data of Block to insert
2037
+ */async processSingleBlock(n){const{Caret:h,BlockManager:p}=this.Editor,{currentBlock:g}=p;g&&n.tool===g.name&&d.containsOnlyInlineElements(n.content.innerHTML)?h.insertContentAtCaretPosition(n.content.innerHTML):this.insertBlock(n,(g==null?void 0:g.tool.isDefault)&&g.isEmpty)}
2038
+ /**
2039
+ * Process paste to single Block:
2040
+ * 1. Find patterns` matches
2041
+ * 2. Insert new block if it is not the same type as current one
2042
+ * 3. Just insert text if there is no substitutions
2043
+ *
2044
+ * @param {PasteData} dataToInsert - data of Block to insert
2045
+ */async processInlinePaste(n){const{BlockManager:h,Caret:p}=this.Editor,{content:g}=n;if(h.currentBlock&&h.currentBlock.tool.isDefault&&g.textContent.length<lo.PATTERN_PROCESSING_MAX_LENGTH){const n=await this.processPattern(g.textContent);if(n){const g=h.currentBlock&&h.currentBlock.tool.isDefault&&h.currentBlock.isEmpty,m=h.paste(n.tool,n.event,g);p.setToBlock(m,p.positions.END);return}}if(h.currentBlock&&h.currentBlock.currentInput){const n=h.currentBlock.tool.baseSanitizeConfig;document.execCommand("insertHTML",!1,q(g.innerHTML,n))}else this.insertBlock(n)}
2046
+ /**
2047
+ * Get patterns` matches
2048
+ *
2049
+ * @param {string} text - text to process
2050
+ * @returns {Promise<{event: PasteEvent, tool: string}>}
2051
+ */async processPattern(n){const h=this.toolsPatterns.find((h=>{const p=h.pattern.exec(n);return!!p&&n===p.shift()}));return h?{event:this.composePasteEvent("pattern",{key:h.key,data:n}),tool:h.tool.name}:void 0}
2052
+ /**
2053
+ * Insert pasted Block content to Editor
2054
+ *
2055
+ * @param {PasteData} data - data to insert
2056
+ * @param {boolean} canReplaceCurrentBlock - if true and is current Block is empty, will replace current Block
2057
+ * @returns {void}
2058
+ */insertBlock(n,h=!1){const{BlockManager:p,Caret:g}=this.Editor,{currentBlock:m}=p;let v;h&&m&&m.isEmpty?(v=p.paste(n.tool,n.event,!0),g.setToBlock(v,g.positions.END)):(v=p.paste(n.tool,n.event),g.setToBlock(v,g.positions.END)
2059
+ /**
2060
+ * Insert data passed as application/x-editor-js JSON
2061
+ *
2062
+ * @param {Array} blocks — Blocks' data to insert
2063
+ * @returns {void}
2064
+ */)}insertEditorJSData(n){const{BlockManager:h,Caret:p,Tools:g}=this.Editor;it(n,(n=>g.blockTools.get(n).sanitizeConfig)).forEach((({tool:n,data:g},m)=>{let v=!1;m===0&&(v=h.currentBlock&&h.currentBlock.tool.isDefault&&h.currentBlock.isEmpty);const x=h.insert({tool:n,data:g,replace:v});p.setToBlock(x,p.positions.END)}))}
2065
+ /**
2066
+ * Fetch nodes from Element node
2067
+ *
2068
+ * @param {Node} node - current node
2069
+ * @param {Node[]} nodes - processed nodes
2070
+ * @param {Node} destNode - destination node
2071
+ */processElementNode(n,h,p){const g=Object.keys(this.toolsTags),m=n,{tool:v}=this.toolsTags[m.tagName]||{},x=this.tagsByTool[v==null?void 0:v.name]||[],w=g.includes(m.tagName),E=d.blockElements.includes(m.tagName.toLowerCase()),B=Array.from(m.children).some((({tagName:n})=>g.includes(n)&&!x.includes(n))),T=Array.from(m.children).some((({tagName:n})=>d.blockElements.includes(n.toLowerCase())));return E||w||B?w&&!B||E&&!T&&!B?[...h,p,m]:void 0:(p.appendChild(m),[...h,p])}
2072
+ /**
2073
+ * Recursively divide HTML string to two types of nodes:
2074
+ * 1. Block element
2075
+ * 2. Document Fragments contained text and markup tags like a, b, i etc.
2076
+ *
2077
+ * @param {Node} wrapper - wrapper of paster HTML content
2078
+ * @returns {Node[]}
2079
+ */getNodes(n){const h=Array.from(n.childNodes);let p;const i=(n,h)=>{if(d.isEmpty(h)&&!d.isSingleTag(h))return n;const g=n[n.length-1];let m=new DocumentFragment;switch(g&&d.isFragment(g)&&(m=n.pop()),h.nodeType){case Node.ELEMENT_NODE:if(p=this.processElementNode(h,n,m),p)return p;break;case Node.TEXT_NODE:return m.appendChild(h),[...n,m];default:return[...n,m]}return[...n,...Array.from(h.childNodes).reduce(i,[])]};return h.reduce(i,[])}
2080
+ /**
2081
+ * Compose paste event with passed type and detail
2082
+ *
2083
+ * @param {string} type - event type
2084
+ * @param {PasteEventDetail} detail - event detail
2085
+ */composePasteEvent(n,h){return new CustomEvent(n,{detail:h})}};yi.PATTERN_PROCESSING_MAX_LENGTH=450;let xi=yi;class as extends y{constructor(){super(...arguments),this.toolsDontSupportReadOnly=[],this.readOnlyEnabled=!1}get isEnabled(){return this.readOnlyEnabled}async prepare(){const{Tools:n}=this.Editor,{blockTools:h}=n,p=[];Array.from(h.entries()).forEach((([n,h])=>{h.isReadOnlySupported||p.push(n)})),this.toolsDontSupportReadOnly=p,this.config.readOnly&&p.length>0&&this.throwCriticalError(),this.toggle(this.config.readOnly,!0)
2086
+ /**
2087
+ * Set read-only mode or toggle current state
2088
+ * Call all Modules `toggleReadOnly` method and re-render Editor
2089
+ *
2090
+ * @param state - (optional) read-only state or toggle
2091
+ * @param isInitial - (optional) true when editor is initializing
2092
+ */}async toggle(n=!this.readOnlyEnabled,h=!1){n&&this.toolsDontSupportReadOnly.length>0&&this.throwCriticalError();const p=this.readOnlyEnabled;this.readOnlyEnabled=n;for(const h in this.Editor)this.Editor[h].toggleReadOnly&&this.Editor[h].toggleReadOnly(n);if(p===n)return this.readOnlyEnabled;if(h)return this.readOnlyEnabled;this.Editor.ModificationsObserver.disable();const g=await this.Editor.Saver.save();return await this.Editor.BlockManager.clear(),await this.Editor.Renderer.render(g.blocks),this.Editor.ModificationsObserver.enable(),this.readOnlyEnabled}throwCriticalError(){throw new Pt(`To enable read-only mode all connected tools should support it. Tools ${this.toolsDontSupportReadOnly.join(", ")} don't support read-only mode.`)}}class xe extends y{constructor(){super(...arguments),this.isRectSelectionActivated=!1,this.SCROLL_SPEED=3,this.HEIGHT_OF_SCROLL_ZONE=40,this.BOTTOM_SCROLL_ZONE=1,this.TOP_SCROLL_ZONE=2,this.MAIN_MOUSE_BUTTON=0,this.mousedown=!1,this.isScrolling=!1,this.inScrollZone=null,this.startX=0,this.startY=0,this.mouseX=0,this.mouseY=0,this.stackOfSelected=[],this.listenerIds=[]
2093
+ /**
2094
+ * CSS classes for the Block
2095
+ *
2096
+ * @returns {{wrapper: string, content: string}}
2097
+ */}static get CSS(){return{overlay:"codex-editor-overlay",overlayContainer:"codex-editor-overlay__container",rect:"codex-editor-overlay__rectangle",topScrollZone:"codex-editor-overlay__scroll-zone--top",bottomScrollZone:"codex-editor-overlay__scroll-zone--bottom"}}prepare(){this.enableModuleBindings()}
2098
+ /**
2099
+ * Init rect params
2100
+ *
2101
+ * @param {number} pageX - X coord of mouse
2102
+ * @param {number} pageY - Y coord of mouse
2103
+ */startSelection(n,h){const p=document.elementFromPoint(n-window.pageXOffset,h-window.pageYOffset);p.closest(`.${this.Editor.Toolbar.CSS.toolbar}`)||(this.Editor.BlockSelection.allBlocksSelected=!1,this.clearSelection(),this.stackOfSelected=[]);const g=[`.${D.CSS.content}`,`.${this.Editor.Toolbar.CSS.toolbar}`,`.${this.Editor.InlineToolbar.CSS.inlineToolbar}`],m=p.closest("."+this.Editor.UI.CSS.editorWrapper),v=g.some((n=>!!p.closest(n)));!m||v||(this.mousedown=!0,this.startX=n,this.startY=h)}endSelection(){this.mousedown=!1,this.startX=0,this.startY=0,this.overlayRectangle.style.display="none"}isRectActivated(){return this.isRectSelectionActivated}clearSelection(){this.isRectSelectionActivated=!1}enableModuleBindings(){const{container:n}=this.genHTML();this.listeners.on(n,"mousedown",(n=>{this.processMouseDown(n)}),!1),this.listeners.on(document.body,"mousemove",Ve((n=>{this.processMouseMove(n)}),10),{passive:!0}),this.listeners.on(document.body,"mouseleave",(()=>{this.processMouseLeave()})),this.listeners.on(window,"scroll",Ve((n=>{this.processScroll(n)}),10),{passive:!0}),this.listeners.on(document.body,"mouseup",(()=>{this.processMouseUp()}),!1)
2104
+ /**
2105
+ * Handle mouse down events
2106
+ *
2107
+ * @param {MouseEvent} mouseEvent - mouse event payload
2108
+ */}processMouseDown(n){n.button===this.MAIN_MOUSE_BUTTON&&(n.target.closest(d.allInputsSelector)!==null||this.startSelection(n.pageX,n.pageY))}
2109
+ /**
2110
+ * Handle mouse move events
2111
+ *
2112
+ * @param {MouseEvent} mouseEvent - mouse event payload
2113
+ */processMouseMove(n){this.changingRectangle(n),this.scrollByZones(n.clientY)}processMouseLeave(){this.clearSelection(),this.endSelection()
2114
+ /**
2115
+ * @param {MouseEvent} mouseEvent - mouse event payload
2116
+ */}processScroll(n){this.changingRectangle(n)}processMouseUp(){this.clearSelection(),this.endSelection()
2117
+ /**
2118
+ * Scroll If mouse in scroll zone
2119
+ *
2120
+ * @param {number} clientY - Y coord of mouse
2121
+ */}scrollByZones(n){this.inScrollZone=null,n<=this.HEIGHT_OF_SCROLL_ZONE&&(this.inScrollZone=this.TOP_SCROLL_ZONE),document.documentElement.clientHeight-n<=this.HEIGHT_OF_SCROLL_ZONE&&(this.inScrollZone=this.BOTTOM_SCROLL_ZONE),this.inScrollZone?this.isScrolling||(this.scrollVertical(this.inScrollZone===this.TOP_SCROLL_ZONE?-this.SCROLL_SPEED:this.SCROLL_SPEED),this.isScrolling=!0
2122
+ /**
2123
+ * Generates required HTML elements
2124
+ *
2125
+ * @returns {Object<string, Element>}
2126
+ */):this.isScrolling=!1}genHTML(){const{UI:n}=this.Editor,h=n.nodes.holder.querySelector("."+n.CSS.editorWrapper),p=d.make("div",xe.CSS.overlay,{}),g=d.make("div",xe.CSS.overlayContainer,{}),m=d.make("div",xe.CSS.rect,{});return g.appendChild(m),p.appendChild(g),h.appendChild(p),this.overlayRectangle=m,{container:h,overlay:p}
2127
+ /**
2128
+ * Activates scrolling if blockSelection is active and mouse is in scroll zone
2129
+ *
2130
+ * @param {number} speed - speed of scrolling
2131
+ */}scrollVertical(n){if(!(this.inScrollZone&&this.mousedown))return;const h=window.pageYOffset;window.scrollBy(0,n),this.mouseY+=window.pageYOffset-h,setTimeout((()=>{this.scrollVertical(n)}),0)
2132
+ /**
2133
+ * Handles the change in the rectangle and its effect
2134
+ *
2135
+ * @param {MouseEvent} event - mouse event
2136
+ */}changingRectangle(n){if(!this.mousedown)return;n.pageY!==void 0&&(this.mouseX=n.pageX,this.mouseY=n.pageY);const{rightPos:h,leftPos:p,index:g}=this.genInfoForMouseSelection(),m=this.startX>h&&this.mouseX>h,v=this.startX<p&&this.mouseX<p;this.rectCrossesBlocks=!(m||v),this.isRectSelectionActivated||(this.rectCrossesBlocks=!1,this.isRectSelectionActivated=!0,this.shrinkRectangleToPoint(),this.overlayRectangle.style.display="block"),this.updateRectangleSize(),this.Editor.Toolbar.close(),g!==void 0&&(this.trySelectNextBlock(g),this.inverseSelection(),b.get().removeAllRanges())}shrinkRectangleToPoint(){this.overlayRectangle.style.left=this.startX-window.pageXOffset+"px",this.overlayRectangle.style.top=this.startY-window.pageYOffset+"px",this.overlayRectangle.style.bottom=`calc(100% - ${this.startY-window.pageYOffset}px`,this.overlayRectangle.style.right=`calc(100% - ${this.startX-window.pageXOffset}px`}inverseSelection(){const n=this.Editor.BlockManager.getBlockByIndex(this.stackOfSelected[0]).selected;if(this.rectCrossesBlocks&&!n)for(const n of this.stackOfSelected)this.Editor.BlockSelection.selectBlockByIndex(n);if(!this.rectCrossesBlocks&&n)for(const n of this.stackOfSelected)this.Editor.BlockSelection.unSelectBlockByIndex(n)}updateRectangleSize(){this.mouseY>=this.startY?(this.overlayRectangle.style.top=this.startY-window.pageYOffset+"px",this.overlayRectangle.style.bottom=`calc(100% - ${this.mouseY-window.pageYOffset}px`):(this.overlayRectangle.style.bottom=`calc(100% - ${this.startY-window.pageYOffset}px`,this.overlayRectangle.style.top=this.mouseY-window.pageYOffset+"px"),this.mouseX>=this.startX?(this.overlayRectangle.style.left=this.startX-window.pageXOffset+"px",this.overlayRectangle.style.right=`calc(100% - ${this.mouseX-window.pageXOffset}px`):(this.overlayRectangle.style.right=`calc(100% - ${this.startX-window.pageXOffset}px`,this.overlayRectangle.style.left=this.mouseX-window.pageXOffset+"px"
2137
+ /**
2138
+ * Collects information needed to determine the behavior of the rectangle
2139
+ *
2140
+ * @returns {object} index - index next Block, leftPos - start of left border of Block, rightPos - right border
2141
+ */)}genInfoForMouseSelection(){const n=document.body.offsetWidth/2,h=this.mouseY-window.pageYOffset,p=document.elementFromPoint(n,h),g=this.Editor.BlockManager.getBlockByChildNode(p);let m;g!==void 0&&(m=this.Editor.BlockManager.blocks.findIndex((n=>n.holder===g.holder)));const v=this.Editor.BlockManager.lastBlock.holder.querySelector("."+D.CSS.content),x=Number.parseInt(window.getComputedStyle(v).width,10)/2,w=n-x,E=n+x;return{index:m,leftPos:w,rightPos:E}}
2142
+ /**
2143
+ * Select block with index index
2144
+ *
2145
+ * @param index - index of block in redactor
2146
+ */addBlockInSelection(n){this.rectCrossesBlocks&&this.Editor.BlockSelection.selectBlockByIndex(n),this.stackOfSelected.push(n)
2147
+ /**
2148
+ * Adds a block to the selection and determines which blocks should be selected
2149
+ *
2150
+ * @param {object} index - index of new block in the reactor
2151
+ */}trySelectNextBlock(n){const h=this.stackOfSelected[this.stackOfSelected.length-1]===n,p=this.stackOfSelected.length,g=1,m=-1,v=0;if(h)return;const x=this.stackOfSelected[p-1]-this.stackOfSelected[p-2]>0;let w=v;p>1&&(w=x?g:m);const E=n>this.stackOfSelected[p-1]&&w===g,B=n<this.stackOfSelected[p-1]&&w===m,T=!(E||B||w===v);if(!T&&(n>this.stackOfSelected[p-1]||this.stackOfSelected[p-1]===void 0)){let h=this.stackOfSelected[p-1]+1||n;for(h;h<=n;h++)this.addBlockInSelection(h);return}if(!T&&n<this.stackOfSelected[p-1]){for(let h=this.stackOfSelected[p-1]-1;h>=n;h--)this.addBlockInSelection(h);return}if(!T)return;let I,M=p-1;for(I=n>this.stackOfSelected[p-1]?()=>n>this.stackOfSelected[M]:()=>n<this.stackOfSelected[M];I();)this.rectCrossesBlocks&&this.Editor.BlockSelection.unSelectBlockByIndex(this.stackOfSelected[M]),this.stackOfSelected.pop(),M--}}class cs extends y{
2152
+ /**
2153
+ * Renders passed blocks as one batch
2154
+ *
2155
+ * @param blocksData - blocks to render
2156
+ */
2157
+ async render(n){return new Promise((h=>{const{Tools:p,BlockManager:v}=this.Editor;if(n.length===0)v.insert();else{const h=n.map((({type:n,data:h,tunes:x,id:w})=>{p.available.has(n)===!1&&(m(`Tool «${n}» is not found. Check 'tools' property at the Editor.js config.`,"warn"),h=this.composeStubDataForTool(n,h,w),n=p.stubTool);let E;try{E=v.composeBlock({id:w,tool:n,data:h,tunes:x})}catch(m){g(`Block «${n}» skipped because of plugins error`,"error",{data:h,error:m}),h=this.composeStubDataForTool(n,h,w),n=p.stubTool,E=v.composeBlock({id:w,tool:n,data:h,tunes:x})}return E}));v.insertMany(h)}window.requestIdleCallback((()=>{h()}),{timeout:2e3})}))}
2158
+ /**
2159
+ * Create data for the Stub Tool that will be used instead of unavailable tool
2160
+ *
2161
+ * @param tool - unavailable tool name to stub
2162
+ * @param data - data of unavailable block
2163
+ * @param [id] - id of unavailable block
2164
+ */composeStubDataForTool(n,h,p){const{Tools:g}=this.Editor;let m=n;if(g.unavailable.has(n)){const h=g.unavailable.get(n).toolbox;h!==void 0&&h[0].title!==void 0&&(m=h[0].title)}return{savedData:{id:p,type:n,data:h},title:m}}}class ds extends y{
2165
+ /**
2166
+ * Composes new chain of Promises to fire them alternatelly
2167
+ *
2168
+ * @returns {OutputData}
2169
+ */
2170
+ async save(){const{BlockManager:n,Tools:h}=this.Editor,p=n.blocks,g=[];try{p.forEach((n=>{g.push(this.getSavedData(n))}));const n=await Promise.all(g),m=await it(n,(n=>h.blockTools.get(n).sanitizeConfig));return this.makeOutput(m)}catch(n){m("Saving failed due to the Error %o","error",n)}}
2171
+ /**
2172
+ * Saves and validates
2173
+ *
2174
+ * @param {Block} block - Editor's Tool
2175
+ * @returns {ValidatedData} - Tool's validated data
2176
+ */async getSavedData(n){const h=await n.save(),p=h&&await n.validate(h.data);return{...h,isValid:p}}
2177
+ /**
2178
+ * Creates output object with saved data, time and version of editor
2179
+ *
2180
+ * @param {ValidatedData} allExtractedData - data extracted from Blocks
2181
+ * @returns {OutputData}
2182
+ */makeOutput(n){const h=[];return n.forEach((({id:n,tool:p,data:m,tunes:v,isValid:x})=>{if(!x){g(`Block «${p}» skipped because saved data is invalid`);return}if(p===this.Editor.Tools.stubTool){h.push(m);return}const w={id:n,type:p,data:m,...!V(v)&&{tunes:v}};h.push(w)})),{time:+new Date,blocks:h,version:"2.30.6"}}}(function(){try{if(typeof document<"u"){var n=document.createElement("style");n.appendChild(document.createTextNode(".ce-paragraph{line-height:1.6em;outline:none}.ce-block:only-of-type .ce-paragraph[data-placeholder-active]:empty:before,.ce-block:only-of-type .ce-paragraph[data-placeholder-active][data-empty=true]:before{content:attr(data-placeholder-active)}.ce-paragraph p:first-of-type{margin-top:0}.ce-paragraph p:last-of-type{margin-bottom:0}")),document.head.appendChild(n)}}catch(n){console.error("vite-plugin-css-injected-by-js",n)}})();const wi='<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M8 9V7.2C8 7.08954 8.08954 7 8.2 7L12 7M16 9V7.2C16 7.08954 15.9105 7 15.8 7L12 7M12 7L12 17M12 17H10M12 17H14"/></svg>';function us(n){const h=document.createElement("div");h.innerHTML=n.trim();const p=document.createDocumentFragment();return p.append(...Array.from(h.childNodes)),p
2183
+ /**
2184
+ * Base Paragraph Block for the Editor.js.
2185
+ * Represents a regular text block
2186
+ *
2187
+ * @author CodeX (team@codex.so)
2188
+ * @copyright CodeX 2018
2189
+ * @license The MIT License (MIT)
2190
+ */}class ht{
2191
+ /**
2192
+ * Default placeholder for Paragraph Tool
2193
+ *
2194
+ * @returns {string}
2195
+ * @class
2196
+ */
2197
+ static get DEFAULT_PLACEHOLDER(){return""}
2198
+ /**
2199
+ * Render plugin`s main Element and fill it with saved data
2200
+ *
2201
+ * @param {object} params - constructor params
2202
+ * @param {ParagraphData} params.data - previously saved data
2203
+ * @param {ParagraphConfig} params.config - user config for Tool
2204
+ * @param {object} params.api - editor.js api
2205
+ * @param {boolean} readOnly - read only mode flag
2206
+ */constructor({data:n,config:h,api:p,readOnly:g}){this.api=p,this.readOnly=g,this._CSS={block:this.api.styles.block,wrapper:"ce-paragraph"},this.readOnly||(this.onKeyUp=this.onKeyUp.bind(this)),this._placeholder=h.placeholder?h.placeholder:ht.DEFAULT_PLACEHOLDER,this._data=n??{},this._element=null,this._preserveBlank=h.preserveBlank??!1
2207
+ /**
2208
+ * Check if text content is empty and set empty string to inner html.
2209
+ * We need this because some browsers (e.g. Safari) insert <br> into empty contenteditanle elements
2210
+ *
2211
+ * @param {KeyboardEvent} e - key up event
2212
+ */}onKeyUp(n){if(n.code!=="Backspace"&&n.code!=="Delete"||!this._element)return;const{textContent:h}=this._element;h===""&&(this._element.innerHTML="")}
2213
+ /**
2214
+ * Create Tool's view
2215
+ *
2216
+ * @returns {HTMLDivElement}
2217
+ * @private
2218
+ */drawView(){const n=document.createElement("DIV");return n.classList.add(this._CSS.wrapper,this._CSS.block),n.contentEditable="false",n.dataset.placeholderActive=this.api.i18n.t(this._placeholder),this._data.text&&(n.innerHTML=this._data.text),this.readOnly||(n.contentEditable="true",n.addEventListener("keyup",this.onKeyUp)),n
2219
+ /**
2220
+ * Return Tool's view
2221
+ *
2222
+ * @returns {HTMLDivElement}
2223
+ */}render(){return this._element=this.drawView(),this._element
2224
+ /**
2225
+ * Method that specified how to merge two Text blocks.
2226
+ * Called by Editor.js by backspace at the beginning of the Block
2227
+ *
2228
+ * @param {ParagraphData} data
2229
+ * @public
2230
+ */}merge(n){if(!this._element)return;this._data.text+=n.text;const h=us(n.text);this._element.appendChild(h),this._element.normalize()
2231
+ /**
2232
+ * Validate Paragraph block data:
2233
+ * - check for emptiness
2234
+ *
2235
+ * @param {ParagraphData} savedData — data received after saving
2236
+ * @returns {boolean} false if saved data is not correct, otherwise true
2237
+ * @public
2238
+ */}validate(n){return!(n.text.trim()===""&&!this._preserveBlank)}
2239
+ /**
2240
+ * Extract Tool's data from the view
2241
+ *
2242
+ * @param {HTMLDivElement} toolsContent - Paragraph tools rendered view
2243
+ * @returns {ParagraphData} - saved data
2244
+ * @public
2245
+ */save(n){return{text:n.innerHTML}}
2246
+ /**
2247
+ * On paste callback fired from Editor.
2248
+ *
2249
+ * @param {HTMLPasteEvent} event - event with pasted data
2250
+ */onPaste(n){const h={text:n.detail.data.innerHTML};this._data=h,window.requestAnimationFrame((()=>{this._element&&(this._element.innerHTML=this._data.text||"")}))
2251
+ /**
2252
+ * Enable Conversion Toolbar. Paragraph can be converted to/from other tools
2253
+ * @returns {ConversionConfig}
2254
+ */}static get conversionConfig(){return{export:"text",import:"text"}}
2255
+ /**
2256
+ * Sanitizer rules
2257
+ * @returns {SanitizerConfig} - Edtior.js sanitizer config
2258
+ */static get sanitize(){return{text:{br:!0}}}
2259
+ /**
2260
+ * Returns true to notify the core that read-only mode is supported
2261
+ *
2262
+ * @returns {boolean}
2263
+ */static get isReadOnlySupported(){return!0}
2264
+ /**
2265
+ * Used by Editor paste handling API.
2266
+ * Provides configuration to handle P tags.
2267
+ *
2268
+ * @returns {PasteConfig} - Paragraph Paste Setting
2269
+ */static get pasteConfig(){return{tags:["P"]}}
2270
+ /**
2271
+ * Icon and title for displaying at the Toolbox
2272
+ *
2273
+ * @returns {ToolboxConfig} - Paragraph Toolbox Setting
2274
+ */static get toolbox(){return{icon:wi,title:"Text"}}}class ut{constructor(){this.commandName="bold"}
2275
+ /**
2276
+ * Sanitizer Rule
2277
+ * Leave <b> tags
2278
+ *
2279
+ * @returns {object}
2280
+ */static get sanitize(){return{b:{}}}render(){return{icon:me,name:"bold",onActivate:()=>{document.execCommand(this.commandName)},isActive:()=>document.queryCommandState(this.commandName)}}
2281
+ /**
2282
+ * Set a shortcut
2283
+ *
2284
+ * @returns {boolean}
2285
+ */get shortcut(){return"CMD+B"}}ut.isInline=!0;ut.title="Bold";class pt{constructor(){this.commandName="italic",this.CSS={button:"ce-inline-tool",buttonActive:"ce-inline-tool--active",buttonModifier:"ce-inline-tool--italic"},this.nodes={button:null}
2286
+ /**
2287
+ * Sanitizer Rule
2288
+ * Leave <i> tags
2289
+ *
2290
+ * @returns {object}
2291
+ */}static get sanitize(){return{i:{}}}render(){return this.nodes.button=document.createElement("button"),this.nodes.button.type="button",this.nodes.button.classList.add(this.CSS.button,this.CSS.buttonModifier),this.nodes.button.innerHTML=He,this.nodes.button}surround(){document.execCommand(this.commandName)}checkState(){const n=document.queryCommandState(this.commandName);return this.nodes.button.classList.toggle(this.CSS.buttonActive,n),n}get shortcut(){return"CMD+I"}}pt.isInline=!0;pt.title="Italic";class ft{
2292
+ /**
2293
+ * @param api - Editor.js API
2294
+ */
2295
+ constructor({api:n}){this.commandLink="createLink",this.commandUnlink="unlink",this.ENTER_KEY=13,this.CSS={button:"ce-inline-tool",buttonActive:"ce-inline-tool--active",buttonModifier:"ce-inline-tool--link",buttonUnlink:"ce-inline-tool--unlink",input:"ce-inline-tool-input",inputShowed:"ce-inline-tool-input--showed"},this.nodes={button:null,input:null},this.inputOpened=!1,this.toolbar=n.toolbar,this.inlineToolbar=n.inlineToolbar,this.notifier=n.notifier,this.i18n=n.i18n,this.selection=new b
2296
+ /**
2297
+ * Sanitizer Rule
2298
+ * Leave <a> tags
2299
+ *
2300
+ * @returns {object}
2301
+ */}static get sanitize(){return{a:{href:!0,target:"_blank",rel:"nofollow"}}}render(){return this.nodes.button=document.createElement("button"),this.nodes.button.type="button",this.nodes.button.classList.add(this.CSS.button,this.CSS.buttonModifier),this.nodes.button.innerHTML=Ue,this.nodes.button}renderActions(){return this.nodes.input=document.createElement("input"),this.nodes.input.placeholder=this.i18n.t("Add a link"),this.nodes.input.enterKeyHint="done",this.nodes.input.classList.add(this.CSS.input),this.nodes.input.addEventListener("keydown",(n=>{n.keyCode===this.ENTER_KEY&&this.enterPressed(n)})),this.nodes.input
2302
+ /**
2303
+ * Handle clicks on the Inline Toolbar icon
2304
+ *
2305
+ * @param {Range} range - range to wrap with link
2306
+ */}surround(n){if(n){this.inputOpened?(this.selection.restore(),this.selection.removeFakeBackground()):(this.selection.setFakeBackground(),this.selection.save());const n=this.selection.findParentTag("A");if(n){this.selection.expandToTag(n),this.unlink(),this.closeActions(),this.checkState(),this.toolbar.close();return}}this.toggleActions()}checkState(){const n=this.selection.findParentTag("A");if(n){this.nodes.button.innerHTML=We,this.nodes.button.classList.add(this.CSS.buttonUnlink),this.nodes.button.classList.add(this.CSS.buttonActive),this.openActions();const h=n.getAttribute("href");this.nodes.input.value=h!=="null"?h:"",this.selection.save()}else this.nodes.button.innerHTML=Ue,this.nodes.button.classList.remove(this.CSS.buttonUnlink),this.nodes.button.classList.remove(this.CSS.buttonActive);return!!n}clear(){this.closeActions()}get shortcut(){return"CMD+K"}toggleActions(){this.inputOpened?this.closeActions(!1):this.openActions(!0)}
2307
+ /**
2308
+ * @param {boolean} needFocus - on link creation we need to focus input. On editing - nope.
2309
+ */openActions(n=!1){this.nodes.input.classList.add(this.CSS.inputShowed),n&&this.nodes.input.focus(),this.inputOpened=!0
2310
+ /**
2311
+ * Close input
2312
+ *
2313
+ * @param {boolean} clearSavedSelection — we don't need to clear saved selection
2314
+ * on toggle-clicks on the icon of opened Toolbar
2315
+ */}closeActions(n=!0){if(this.selection.isFakeBackgroundEnabled){const n=new b;n.save(),this.selection.restore(),this.selection.removeFakeBackground(),n.restore()}this.nodes.input.classList.remove(this.CSS.inputShowed),this.nodes.input.value="",n&&this.selection.clearSaved(),this.inputOpened=!1
2316
+ /**
2317
+ * Enter pressed on input
2318
+ *
2319
+ * @param {KeyboardEvent} event - enter keydown event
2320
+ */}enterPressed(n){let h=this.nodes.input.value||"";h.trim()?this.validateURL(h)?(h=this.prepareLink(h),this.selection.restore(),this.selection.removeFakeBackground(),this.insertLink(h),n.preventDefault(),n.stopPropagation(),n.stopImmediatePropagation(),this.selection.collapseToEnd(),this.inlineToolbar.close()
2321
+ /**
2322
+ * Detects if passed string is URL
2323
+ *
2324
+ * @param {string} str - string to validate
2325
+ * @returns {boolean}
2326
+ */):(this.notifier.show({message:"Pasted link is not valid.",style:"error"}),g("Incorrect Link pasted","warn",h)):(this.selection.restore(),this.unlink(),n.preventDefault(),this.closeActions())}validateURL(n){return!/\s/.test(n)}
2327
+ /**
2328
+ * Process link before injection
2329
+ * - sanitize
2330
+ * - add protocol for links like 'google.com'
2331
+ *
2332
+ * @param {string} link - raw user input
2333
+ */prepareLink(n){return n=n.trim(),n=this.addProtocol(n),n
2334
+ /**
2335
+ * Add 'http' protocol to the links like 'vc.ru', 'google.com'
2336
+ *
2337
+ * @param {string} link - string to process
2338
+ */}addProtocol(n){if(/^(\w+):(\/\/)?/.test(n))return n;const h=/^\/[^/\s]/.test(n),p=n.substring(0,1)==="#",g=/^\/\/[^/\s]/.test(n);return!h&&!p&&!g&&(n="http://"+n),n
2339
+ /**
2340
+ * Inserts <a> tag with "href"
2341
+ *
2342
+ * @param {string} link - "href" value
2343
+ */}insertLink(n){const h=this.selection.findParentTag("A");h&&this.selection.expandToTag(h),document.execCommand(this.commandLink,!1,n)}unlink(){document.execCommand(this.commandUnlink)}}ft.isInline=!0;ft.title="Link";class ao{
2344
+ /**
2345
+ * @param api - Editor.js API
2346
+ */
2347
+ constructor({api:n}){this.i18nAPI=n.i18n,this.blocksAPI=n.blocks,this.selectionAPI=n.selection,this.toolsAPI=n.tools,this.caretAPI=n.caret}async render(){const n=b.get(),h=this.blocksAPI.getBlockByElement(n.anchorNode);if(h===void 0)return[];const p=this.toolsAPI.getBlockTools(),g=await zt(h,p);if(g.length===0)return[];const m=g.reduce(((n,p)=>{var g;return(g=p.toolbox)==null||g.forEach((g=>{n.push({icon:g.icon,title:A.t(de.toolNames,g.title),name:p.name,closeOnActivate:!0,onActivate:async()=>{const n=await this.blocksAPI.convert(h.id,p.name,g.data);this.caretAPI.setToBlock(n,"end")}})})),n}),[]),v=await h.getActiveToolboxEntry(),x=v!==void 0?v.icon:Ye,w=!pe();return{icon:x,name:"convert-to",hint:{title:this.i18nAPI.t("Convert to")},children:{searchable:w,items:m,onOpen:()=>{w&&(this.selectionAPI.setFakeBackground(),this.selectionAPI.save())},onClose:()=>{w&&(this.selectionAPI.restore(),this.selectionAPI.removeFakeBackground())}}}}}ao.isInline=!0;class co{
2348
+ /**
2349
+ * @param options - constructor options
2350
+ * @param options.data - stub tool data
2351
+ * @param options.api - Editor.js API
2352
+ */
2353
+ constructor({data:n,api:h}){this.CSS={wrapper:"ce-stub",info:"ce-stub__info",title:"ce-stub__title",subtitle:"ce-stub__subtitle"},this.api=h,this.title=n.title||this.api.i18n.t("Error"),this.subtitle=this.api.i18n.t("The block can not be displayed correctly."),this.savedData=n.savedData,this.wrapper=this.make()
2354
+ /**
2355
+ * Returns stub holder
2356
+ *
2357
+ * @returns {HTMLElement}
2358
+ */}render(){return this.wrapper}
2359
+ /**
2360
+ * Return original Tool data
2361
+ *
2362
+ * @returns {BlockToolData}
2363
+ */save(){return this.savedData}
2364
+ /**
2365
+ * Create Tool html markup
2366
+ *
2367
+ * @returns {HTMLElement}
2368
+ */make(){const n=d.make("div",this.CSS.wrapper),h=Ge,p=d.make("div",this.CSS.info),g=d.make("div",this.CSS.title,{textContent:this.title}),m=d.make("div",this.CSS.subtitle,{textContent:this.subtitle});return n.innerHTML=h,p.appendChild(g),p.appendChild(m),n.appendChild(p),n}}co.isReadOnlySupported=!0;class ps extends dt{constructor(){super(...arguments),this.type=Po.Inline}get title(){return this.constructable[Xo.Title]}create(){return new this.constructable({api:this.api,config:this.settings})}}class fs extends dt{constructor(){super(...arguments),this.type=Po.Tune
2369
+ /**
2370
+ * Constructs new BlockTune instance from constructable
2371
+ *
2372
+ * @param data - Tune data
2373
+ * @param block - Block API object
2374
+ */}create(n,h){return new this.constructable({api:this.api,config:this.settings,block:h,data:n})}}class F extends Map{get blockTools(){const n=Array.from(this.entries()).filter((([,n])=>n.isBlock()));return new F(n)}get inlineTools(){const n=Array.from(this.entries()).filter((([,n])=>n.isInline()));return new F(n)}get blockTunes(){const n=Array.from(this.entries()).filter((([,n])=>n.isTune()));return new F(n)}get internalTools(){const n=Array.from(this.entries()).filter((([,n])=>n.isInternal));return new F(n)}get externalTools(){const n=Array.from(this.entries()).filter((([,n])=>!n.isInternal));return new F(n)}}var Ei=Object.defineProperty,Bi=Object.getOwnPropertyDescriptor,ho=(n,h,p,g)=>{for(var m,v=g>1?void 0:g?Bi(h,p):h,x=n.length-1;x>=0;x--)(m=n[x])&&(v=(g?m(h,p,v):m(v))||v);return g&&v&&Ei(h,p,v),v};class gt extends dt{constructor(){super(...arguments),this.type=Po.Block,this.inlineTools=new F,this.tunes=new F
2375
+ /**
2376
+ * Creates new Tool instance
2377
+ *
2378
+ * @param data - Tool data
2379
+ * @param block - BlockAPI for current Block
2380
+ * @param readOnly - True if Editor is in read-only mode
2381
+ */}create(n,h,p){return new this.constructable({data:n,block:h,readOnly:p,api:this.api,config:this.settings})}get isReadOnlySupported(){return this.constructable[Vo.IsReadOnlySupported]===!0}get isLineBreaksEnabled(){return this.constructable[Vo.IsEnabledLineBreaks]}get toolbox(){const n=this.constructable[Vo.Toolbox],h=this.config[Do.Toolbox];if(!V(n)&&h!==!1)return h?Array.isArray(n)?Array.isArray(h)?h.map(((h,p)=>{const g=n[p];return g?{...g,...h}:h})):[h]:Array.isArray(h)?h:[{...n,...h}]:Array.isArray(n)?n:[n]}get conversionConfig(){return this.constructable[Vo.ConversionConfig]}get enabledInlineTools(){return this.config[Do.EnabledInlineTools]||!1}get enabledBlockTunes(){return this.config[Do.EnabledBlockTunes]}get pasteConfig(){return this.constructable[Vo.PasteConfig]??{}}get sanitizeConfig(){const n=super.sanitizeConfig,h=this.baseSanitizeConfig;if(V(n))return h;const p={};for(const g in n)if(Object.prototype.hasOwnProperty.call(n,g)){const m=n[g];R(m)?p[g]=Object.assign({},h,m):p[g]=m}return p}get baseSanitizeConfig(){const n={};return Array.from(this.inlineTools.values()).forEach((h=>Object.assign(n,h.sanitizeConfig))),Array.from(this.tunes.values()).forEach((h=>Object.assign(n,h.sanitizeConfig))),n}}ho([ue],gt.prototype,"sanitizeConfig",1);ho([ue],gt.prototype,"baseSanitizeConfig",1);class bs{
2382
+ /**
2383
+ * @class
2384
+ * @param config - tools config
2385
+ * @param editorConfig - EditorJS config
2386
+ * @param api - EditorJS API module
2387
+ */
2388
+ constructor(n,h,p){this.api=p,this.config=n,this.editorConfig=h
2389
+ /**
2390
+ * Returns Tool object based on it's type
2391
+ *
2392
+ * @param name - tool name
2393
+ */}get(n){const{class:h,isInternal:p=!1,...g}=this.config[n],m=this.getConstructor(h),v=h[Qo.IsTune];return new m({name:n,constructable:h,config:g,api:this.api.getMethodsForTool(n,v),isDefault:n===this.editorConfig.defaultBlock,defaultPlaceholder:this.editorConfig.placeholder,isInternal:p})}
2394
+ /**
2395
+ * Find appropriate Tool object constructor for Tool constructable
2396
+ *
2397
+ * @param constructable - Tools constructable
2398
+ */getConstructor(n){switch(!0){case n[Xo.IsInline]:return ps;case n[Qo.IsTune]:return fs;default:return gt}}}class uo{
2399
+ /**
2400
+ * MoveDownTune constructor
2401
+ *
2402
+ * @param {API} api — Editor's API
2403
+ */
2404
+ constructor({api:n}){this.CSS={animation:"wobble"},this.api=n}render(){return{icon:be,title:this.api.i18n.t("Move down"),onActivate:()=>this.handleClick(),name:"move-down"}}handleClick(){const n=this.api.blocks.getCurrentBlockIndex(),h=this.api.blocks.getBlockByIndex(n+1);if(!h)throw new Error("Unable to move Block down since it is already the last");const p=h.holder,g=p.getBoundingClientRect();let m=Math.abs(window.innerHeight-p.offsetHeight);g.top<window.innerHeight&&(m=window.scrollY+p.offsetHeight),window.scrollTo(0,m),this.api.blocks.move(n+1),this.api.toolbar.toggleBlockSettings(!0)}}uo.isTune=!0;class po{
2405
+ /**
2406
+ * DeleteTune constructor
2407
+ *
2408
+ * @param {API} api - Editor's API
2409
+ */
2410
+ constructor({api:n}){this.api=n}render(){return{icon:Ie,title:this.api.i18n.t("Delete"),name:"delete",confirmation:{title:this.api.i18n.t("Click to delete"),onActivate:()=>this.handleClick()}}}handleClick(){this.api.blocks.delete()}}po.isTune=!0;class fo{
2411
+ /**
2412
+ * MoveUpTune constructor
2413
+ *
2414
+ * @param {API} api - Editor's API
2415
+ */
2416
+ constructor({api:n}){this.CSS={animation:"wobble"},this.api=n}render(){return{icon:Se,title:this.api.i18n.t("Move up"),onActivate:()=>this.handleClick(),name:"move-up"}}handleClick(){const n=this.api.blocks.getCurrentBlockIndex(),h=this.api.blocks.getBlockByIndex(n),p=this.api.blocks.getBlockByIndex(n-1);if(n===0||!h||!p)throw new Error("Unable to move Block up since it is already the first");const g=h.holder,m=p.holder,v=g.getBoundingClientRect(),x=m.getBoundingClientRect();let w;w=x.top>0?Math.abs(v.top)-Math.abs(x.top):Math.abs(v.top)+x.height,window.scrollBy(0,-1*w),this.api.blocks.move(n-1),this.api.toolbar.toggleBlockSettings(!0)}}fo.isTune=!0;var Ci=Object.defineProperty,Ti=Object.getOwnPropertyDescriptor,ws=(n,h,p,g)=>{for(var m,v=g>1?void 0:g?Ti(h,p):h,x=n.length-1;x>=0;x--)(m=n[x])&&(v=(g?m(h,p,v):m(v))||v);return g&&v&&Ci(h,p,v),v};class go extends y{constructor(){super(...arguments),this.stubTool="stub",this.toolsAvailable=new F,this.toolsUnavailable=new F}get available(){return this.toolsAvailable}get unavailable(){return this.toolsUnavailable}get inlineTools(){return this.available.inlineTools}get blockTools(){return this.available.blockTools}
2417
+ /**
2418
+ * Return available Block Tunes
2419
+ *
2420
+ * @returns {object} - object of Inline Tool's classes
2421
+ */get blockTunes(){return this.available.blockTunes}get defaultTool(){return this.blockTools.get(this.config.defaultBlock)}get internal(){return this.available.internalTools}
2422
+ /**
2423
+ * Creates instances via passed or default configuration
2424
+ *
2425
+ * @returns {Promise<void>}
2426
+ */async prepare(){if(this.validateTools(),this.config.tools=qe({},this.internalTools,this.config.tools),!Object.prototype.hasOwnProperty.call(this.config,"tools")||Object.keys(this.config.tools).length===0)throw Error("Can't start without tools");const n=this.prepareConfig();this.factory=new bs(n,this.config,this.Editor.API);const h=this.getListOfPrepareFunctions(n);if(h.length===0)return Promise.resolve();await Eo(h,(n=>{this.toolPrepareMethodSuccess(n)}),(n=>{this.toolPrepareMethodFallback(n)})),this.prepareBlockTools()}getAllInlineToolsSanitizeConfig(){const n={};return Array.from(this.inlineTools.values()).forEach((h=>{Object.assign(n,h.sanitizeConfig)})),n}destroy(){Object.values(this.available).forEach((async n=>{O(n.reset)&&await n.reset()}))}get internalTools(){return{convertTo:{class:ao,isInternal:!0},link:{class:ft,isInternal:!0},bold:{class:ut,isInternal:!0},italic:{class:pt,isInternal:!0},paragraph:{class:ht,inlineToolbar:!0,isInternal:!0},stub:{class:co,isInternal:!0},moveUp:{class:fo,isInternal:!0},delete:{class:po,isInternal:!0},moveDown:{class:uo,isInternal:!0}}}
2427
+ /**
2428
+ * Tool prepare method success callback
2429
+ *
2430
+ * @param {object} data - append tool to available list
2431
+ */toolPrepareMethodSuccess(n){const h=this.factory.get(n.toolName);if(h.isInline()){const n=["render"].filter((n=>!h.create()[n]));if(n.length){g(`Incorrect Inline Tool: ${h.name}. Some of required methods is not implemented %o`,"warn",n),this.toolsUnavailable.set(h.name,h);return}}this.toolsAvailable.set(h.name,h)}
2432
+ /**
2433
+ * Tool prepare method fail callback
2434
+ *
2435
+ * @param {object} data - append tool to unavailable list
2436
+ */toolPrepareMethodFallback(n){this.toolsUnavailable.set(n.toolName,this.factory.get(n.toolName))}
2437
+ /**
2438
+ * Binds prepare function of plugins with user or default config
2439
+ *
2440
+ * @returns {Array} list of functions that needs to be fired sequentially
2441
+ * @param config - tools config
2442
+ */getListOfPrepareFunctions(n){const h=[];return Object.entries(n).forEach((([n,p])=>{h.push({function:O(p.class.prepare)?p.class.prepare:()=>{},data:{toolName:n,config:p.config}})})),h}prepareBlockTools(){Array.from(this.blockTools.values()).forEach((n=>{this.assignInlineToolsToBlockTool(n),this.assignBlockTunesToBlockTool(n)}))}
2443
+ /**
2444
+ * Assign enabled Inline Tools for Block Tool
2445
+ *
2446
+ * @param tool - Block Tool
2447
+ */assignInlineToolsToBlockTool(n){if(this.config.inlineToolbar!==!1){if(n.enabledInlineTools===!0){n.inlineTools=new F(Array.isArray(this.config.inlineToolbar)?this.config.inlineToolbar.map((n=>[n,this.inlineTools.get(n)])):Array.from(this.inlineTools.entries()));return}Array.isArray(n.enabledInlineTools)&&(n.inlineTools=new F(["convertTo",...n.enabledInlineTools].map((n=>[n,this.inlineTools.get(n)]))))}}
2448
+ /**
2449
+ * Assign enabled Block Tunes for Block Tool
2450
+ *
2451
+ * @param tool — Block Tool
2452
+ */assignBlockTunesToBlockTool(n){if(n.enabledBlockTunes!==!1){if(Array.isArray(n.enabledBlockTunes)){const h=new F(n.enabledBlockTunes.map((n=>[n,this.blockTunes.get(n)])));n.tunes=new F([...h,...this.blockTunes.internalTools]);return}if(Array.isArray(this.config.tunes)){const h=new F(this.config.tunes.map((n=>[n,this.blockTunes.get(n)])));n.tunes=new F([...h,...this.blockTunes.internalTools]);return}n.tunes=this.blockTunes.internalTools}}validateTools(){for(const n in this.config.tools)if(Object.prototype.hasOwnProperty.call(this.config.tools,n)){if(n in this.internalTools)return;const h=this.config.tools[n];if(!O(h)&&!O(h.class))throw Error(`Tool «${n}» must be a constructor function or an object with function in the «class» property`)}}prepareConfig(){const n={};for(const h in this.config.tools)R(this.config.tools[h])?n[h]=this.config.tools[h]:n[h]={class:this.config.tools[h]};return n}}ws([ue],go.prototype,"getAllInlineToolsSanitizeConfig",1);const Si=':root{--selectionColor: #e1f2ff;--inlineSelectionColor: #d4ecff;--bg-light: #eff2f5;--grayText: #707684;--color-dark: #1D202B;--color-active-icon: #388AE5;--color-gray-border: rgba(201, 201, 204, .48);--content-width: 650px;--narrow-mode-right-padding: 50px;--toolbox-buttons-size: 26px;--toolbox-buttons-size--mobile: 36px;--icon-size: 20px;--icon-size--mobile: 28px;--block-padding-vertical: .4em;--color-line-gray: #EFF0F1 }.codex-editor{position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;z-index:1}.codex-editor .hide{display:none}.codex-editor__redactor [contenteditable]:empty:after{content:"\\feff"}@media (min-width: 651px){.codex-editor--narrow .codex-editor__redactor{margin-right:50px}}@media (min-width: 651px){.codex-editor--narrow.codex-editor--rtl .codex-editor__redactor{margin-left:50px;margin-right:0}}@media (min-width: 651px){.codex-editor--narrow .ce-toolbar__actions{right:-5px}}.codex-editor-copyable{position:absolute;height:1px;width:1px;top:-400%;opacity:.001}.codex-editor-overlay{position:fixed;top:0;left:0;right:0;bottom:0;z-index:999;pointer-events:none;overflow:hidden}.codex-editor-overlay__container{position:relative;pointer-events:auto;z-index:0}.codex-editor-overlay__rectangle{position:absolute;pointer-events:none;background-color:#2eaadc33;border:1px solid transparent}.codex-editor svg{max-height:100%}.codex-editor path{stroke:currentColor}.codex-editor ::-moz-selection{background-color:#d4ecff}.codex-editor ::selection{background-color:#d4ecff}.codex-editor--toolbox-opened [contentEditable=true][data-placeholder]:focus:before{opacity:0!important}.ce-scroll-locked{overflow:hidden}.ce-scroll-locked--hard{overflow:hidden;top:calc(-1 * var(--window-scroll-offset));position:fixed;width:100%}.ce-toolbar{position:absolute;left:0;right:0;top:0;-webkit-transition:opacity .1s ease;transition:opacity .1s ease;will-change:opacity,top;display:none}.ce-toolbar--opened{display:block}.ce-toolbar__content{max-width:650px;margin:0 auto;position:relative}.ce-toolbar__plus{color:#1d202b;cursor:pointer;width:26px;height:26px;border-radius:7px;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-ms-flex-negative:0;flex-shrink:0}@media (max-width: 650px){.ce-toolbar__plus{width:36px;height:36px}}@media (hover: hover){.ce-toolbar__plus:hover{background-color:#eff2f5}}.ce-toolbar__plus--active{background-color:#eff2f5;-webkit-animation:bounceIn .75s 1;animation:bounceIn .75s 1;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}.ce-toolbar__plus-shortcut{opacity:.6;word-spacing:-2px;margin-top:5px}@media (max-width: 650px){.ce-toolbar__plus{position:absolute;background-color:#fff;border:1px solid #E8E8EB;-webkit-box-shadow:0 3px 15px -3px rgba(13,20,33,.13);box-shadow:0 3px 15px -3px #0d142121;border-radius:6px;z-index:2;position:static}.ce-toolbar__plus--left-oriented:before{left:15px;margin-left:0}.ce-toolbar__plus--right-oriented:before{left:auto;right:15px;margin-left:0}}.ce-toolbar__actions{position:absolute;right:100%;opacity:0;display:-webkit-box;display:-ms-flexbox;display:flex;padding-right:5px}.ce-toolbar__actions--opened{opacity:1}@media (max-width: 650px){.ce-toolbar__actions{right:auto}}.ce-toolbar__settings-btn{color:#1d202b;width:26px;height:26px;border-radius:7px;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;margin-left:3px;cursor:pointer;user-select:none}@media (max-width: 650px){.ce-toolbar__settings-btn{width:36px;height:36px}}@media (hover: hover){.ce-toolbar__settings-btn:hover{background-color:#eff2f5}}.ce-toolbar__settings-btn--active{background-color:#eff2f5;-webkit-animation:bounceIn .75s 1;animation:bounceIn .75s 1;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}@media (min-width: 651px){.ce-toolbar__settings-btn{width:24px}}.ce-toolbar__settings-btn--hidden{display:none}@media (max-width: 650px){.ce-toolbar__settings-btn{position:absolute;background-color:#fff;border:1px solid #E8E8EB;-webkit-box-shadow:0 3px 15px -3px rgba(13,20,33,.13);box-shadow:0 3px 15px -3px #0d142121;border-radius:6px;z-index:2;position:static}.ce-toolbar__settings-btn--left-oriented:before{left:15px;margin-left:0}.ce-toolbar__settings-btn--right-oriented:before{left:auto;right:15px;margin-left:0}}.ce-toolbar__plus svg,.ce-toolbar__settings-btn svg{width:24px;height:24px}@media (min-width: 651px){.codex-editor--narrow .ce-toolbar__plus{left:5px}}@media (min-width: 651px){.codex-editor--narrow .ce-toolbox .ce-popover{right:0;left:auto;left:initial}}.ce-inline-toolbar{--y-offset: 8px;--color-background-icon-active: rgba(56, 138, 229, .1);--color-text-icon-active: #388AE5;--color-text-primary: black;position:absolute;visibility:hidden;-webkit-transition:opacity .25s ease;transition:opacity .25s ease;will-change:opacity,left,top;top:0;left:0;z-index:3;opacity:1;visibility:visible}.ce-inline-toolbar [hidden]{display:none!important}.ce-inline-toolbar__toggler-and-button-wrapper{display:-webkit-box;display:-ms-flexbox;display:flex;width:100%;padding:0 6px}.ce-inline-toolbar__buttons{display:-webkit-box;display:-ms-flexbox;display:flex}.ce-inline-toolbar__dropdown{display:-webkit-box;display:-ms-flexbox;display:flex;padding:6px;margin:0 6px 0 -6px;-webkit-box-align:center;-ms-flex-align:center;align-items:center;cursor:pointer;border-right:1px solid rgba(201,201,204,.48);-webkit-box-sizing:border-box;box-sizing:border-box}@media (hover: hover){.ce-inline-toolbar__dropdown:hover{background:#eff2f5}}.ce-inline-toolbar__dropdown--hidden{display:none}.ce-inline-toolbar__dropdown-content,.ce-inline-toolbar__dropdown-arrow{display:-webkit-box;display:-ms-flexbox;display:flex}.ce-inline-toolbar__dropdown-content svg,.ce-inline-toolbar__dropdown-arrow svg{width:20px;height:20px}.ce-inline-toolbar__shortcut{opacity:.6;word-spacing:-3px;margin-top:3px}.ce-inline-tool{color:var(--color-text-primary);display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;border:0;border-radius:4px;line-height:normal;height:100%;padding:0;width:28px;background-color:transparent;cursor:pointer}@media (max-width: 650px){.ce-inline-tool{width:36px;height:36px}}@media (hover: hover){.ce-inline-tool:hover{background-color:#f8f8f8}}.ce-inline-tool svg{display:block;width:20px;height:20px}@media (max-width: 650px){.ce-inline-tool svg{width:28px;height:28px}}.ce-inline-tool--link .icon--unlink,.ce-inline-tool--unlink .icon--link{display:none}.ce-inline-tool--unlink .icon--unlink{display:inline-block;margin-bottom:-1px}.ce-inline-tool-input{background:#F8F8F8;border:1px solid rgba(226,226,229,.2);border-radius:6px;padding:4px 8px;font-size:14px;line-height:22px;outline:none;margin:0;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box;display:none;font-weight:500;-webkit-appearance:none;font-family:inherit}@media (max-width: 650px){.ce-inline-tool-input{font-size:15px;font-weight:500}}.ce-inline-tool-input::-webkit-input-placeholder{color:#707684}.ce-inline-tool-input::-moz-placeholder{color:#707684}.ce-inline-tool-input:-ms-input-placeholder{color:#707684}.ce-inline-tool-input::-ms-input-placeholder{color:#707684}.ce-inline-tool-input::placeholder{color:#707684}.ce-inline-tool-input--showed{display:block}.ce-inline-tool--active{background:var(--color-background-icon-active);color:var(--color-text-icon-active)}@-webkit-keyframes fade-in{0%{opacity:0}to{opacity:1}}@keyframes fade-in{0%{opacity:0}to{opacity:1}}.ce-block{-webkit-animation:fade-in .3s ease;animation:fade-in .3s ease;-webkit-animation-fill-mode:none;animation-fill-mode:none;-webkit-animation-fill-mode:initial;animation-fill-mode:initial}.ce-block:first-of-type{margin-top:0}.ce-block--selected .ce-block__content{background:#e1f2ff}.ce-block--selected .ce-block__content [contenteditable]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ce-block--selected .ce-block__content img,.ce-block--selected .ce-block__content .ce-stub{opacity:.55}.ce-block--stretched .ce-block__content{max-width:none}.ce-block__content{position:relative;max-width:650px;margin:0 auto;-webkit-transition:background-color .15s ease;transition:background-color .15s ease}.ce-block--drop-target .ce-block__content:before{content:"";position:absolute;top:100%;left:-20px;margin-top:-1px;height:8px;width:8px;border:solid #388AE5;border-width:1px 1px 0 0;-webkit-transform-origin:right;transform-origin:right;-webkit-transform:rotate(45deg);transform:rotate(45deg)}.ce-block--drop-target .ce-block__content:after{content:"";position:absolute;top:100%;height:1px;width:100%;color:#388ae5;background:repeating-linear-gradient(90deg,#388AE5,#388AE5 1px,#fff 1px,#fff 6px)}.ce-block a{cursor:pointer;-webkit-text-decoration:underline;text-decoration:underline}.ce-block b{font-weight:700}.ce-block i{font-style:italic}@-webkit-keyframes bounceIn{0%,20%,40%,60%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}20%{-webkit-transform:scale3d(1.03,1.03,1.03);transform:scale3d(1.03,1.03,1.03)}60%{-webkit-transform:scale3d(1,1,1);transform:scaleZ(1)}}@keyframes bounceIn{0%,20%,40%,60%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}20%{-webkit-transform:scale3d(1.03,1.03,1.03);transform:scale3d(1.03,1.03,1.03)}60%{-webkit-transform:scale3d(1,1,1);transform:scaleZ(1)}}@-webkit-keyframes selectionBounce{0%,20%,40%,60%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}50%{-webkit-transform:scale3d(1.01,1.01,1.01);transform:scale3d(1.01,1.01,1.01)}70%{-webkit-transform:scale3d(1,1,1);transform:scaleZ(1)}}@keyframes selectionBounce{0%,20%,40%,60%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}50%{-webkit-transform:scale3d(1.01,1.01,1.01);transform:scale3d(1.01,1.01,1.01)}70%{-webkit-transform:scale3d(1,1,1);transform:scaleZ(1)}}@-webkit-keyframes buttonClicked{0%,20%,40%,60%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:scale3d(.95,.95,.95);transform:scale3d(.95,.95,.95)}60%{-webkit-transform:scale3d(1.02,1.02,1.02);transform:scale3d(1.02,1.02,1.02)}80%{-webkit-transform:scale3d(1,1,1);transform:scaleZ(1)}}@keyframes buttonClicked{0%,20%,40%,60%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:scale3d(.95,.95,.95);transform:scale3d(.95,.95,.95)}60%{-webkit-transform:scale3d(1.02,1.02,1.02);transform:scale3d(1.02,1.02,1.02)}80%{-webkit-transform:scale3d(1,1,1);transform:scaleZ(1)}}.cdx-block{padding:.4em 0}.cdx-block::-webkit-input-placeholder{line-height:normal!important}.cdx-input{border:1px solid rgba(201,201,204,.48);-webkit-box-shadow:inset 0 1px 2px 0 rgba(35,44,72,.06);box-shadow:inset 0 1px 2px #232c480f;border-radius:3px;padding:10px 12px;outline:none;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}.cdx-input[data-placeholder]:before{position:static!important}.cdx-input[data-placeholder]:before{display:inline-block;width:0;white-space:nowrap;pointer-events:none}.cdx-settings-button{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;border-radius:3px;cursor:pointer;border:0;outline:none;background-color:transparent;vertical-align:bottom;color:inherit;margin:0;min-width:26px;min-height:26px}.cdx-settings-button--focused{background:rgba(34,186,255,.08)!important}.cdx-settings-button--focused{-webkit-box-shadow:inset 0 0 0px 1px rgba(7,161,227,.08);box-shadow:inset 0 0 0 1px #07a1e314}.cdx-settings-button--focused-animated{-webkit-animation-name:buttonClicked;animation-name:buttonClicked;-webkit-animation-duration:.25s;animation-duration:.25s}.cdx-settings-button--active{color:#388ae5}.cdx-settings-button svg{width:auto;height:auto}@media (max-width: 650px){.cdx-settings-button svg{width:28px;height:28px}}@media (max-width: 650px){.cdx-settings-button{width:36px;height:36px;border-radius:8px}}@media (hover: hover){.cdx-settings-button:hover{background-color:#eff2f5}}.cdx-loader{position:relative;border:1px solid rgba(201,201,204,.48)}.cdx-loader:before{content:"";position:absolute;left:50%;top:50%;width:18px;height:18px;margin:-11px 0 0 -11px;border:2px solid rgba(201,201,204,.48);border-left-color:#388ae5;border-radius:50%;-webkit-animation:cdxRotation 1.2s infinite linear;animation:cdxRotation 1.2s infinite linear}@-webkit-keyframes cdxRotation{0%{-webkit-transform:rotate(0deg);transform:rotate(0)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes cdxRotation{0%{-webkit-transform:rotate(0deg);transform:rotate(0)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.cdx-button{padding:13px;border-radius:3px;border:1px solid rgba(201,201,204,.48);font-size:14.9px;background:#fff;-webkit-box-shadow:0 2px 2px 0 rgba(18,30,57,.04);box-shadow:0 2px 2px #121e390a;color:#707684;text-align:center;cursor:pointer}@media (hover: hover){.cdx-button:hover{background:#FBFCFE;-webkit-box-shadow:0 1px 3px 0 rgba(18,30,57,.08);box-shadow:0 1px 3px #121e3914}}.cdx-button svg{height:20px;margin-right:.2em;margin-top:-2px}.ce-stub{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:12px 18px;margin:10px 0;border-radius:10px;background:#eff2f5;border:1px solid #EFF0F1;color:#707684;font-size:14px}.ce-stub svg{width:20px;height:20px}.ce-stub__info{margin-left:14px}.ce-stub__title{font-weight:500;text-transform:capitalize}.codex-editor.codex-editor--rtl{direction:rtl}.codex-editor.codex-editor--rtl .cdx-list{padding-left:0;padding-right:40px}.codex-editor.codex-editor--rtl .ce-toolbar__plus{right:-26px;left:auto}.codex-editor.codex-editor--rtl .ce-toolbar__actions{right:auto;left:-26px}@media (max-width: 650px){.codex-editor.codex-editor--rtl .ce-toolbar__actions{margin-left:0;margin-right:auto;padding-right:0;padding-left:10px}}.codex-editor.codex-editor--rtl .ce-settings{left:5px;right:auto}.codex-editor.codex-editor--rtl .ce-settings:before{right:auto;left:25px}.codex-editor.codex-editor--rtl .ce-settings__button:not(:nth-child(3n+3)){margin-left:3px;margin-right:0}.codex-editor.codex-editor--rtl .ce-conversion-tool__icon{margin-right:0;margin-left:10px}.codex-editor.codex-editor--rtl .ce-inline-toolbar__dropdown{border-right:0px solid transparent;border-left:1px solid rgba(201,201,204,.48);margin:0 -6px 0 6px}.codex-editor.codex-editor--rtl .ce-inline-toolbar__dropdown .icon--toggler-down{margin-left:0;margin-right:4px}@media (min-width: 651px){.codex-editor--narrow.codex-editor--rtl .ce-toolbar__plus{left:0;right:5px}}@media (min-width: 651px){.codex-editor--narrow.codex-editor--rtl .ce-toolbar__actions{left:-5px}}.cdx-search-field{--icon-margin-right: 10px;background:#F8F8F8;border:1px solid rgba(226,226,229,.2);border-radius:6px;padding:2px;display:grid;grid-template-columns:auto auto 1fr;grid-template-rows:auto}.cdx-search-field__icon{width:26px;height:26px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;margin-right:var(--icon-margin-right)}.cdx-search-field__icon svg{width:20px;height:20px;color:#707684}.cdx-search-field__input{font-size:14px;outline:none;font-weight:500;font-family:inherit;border:0;background:transparent;margin:0;padding:0;line-height:22px;min-width:calc(100% - 26px - var(--icon-margin-right))}.cdx-search-field__input::-webkit-input-placeholder{color:#707684;font-weight:500}.cdx-search-field__input::-moz-placeholder{color:#707684;font-weight:500}.cdx-search-field__input:-ms-input-placeholder{color:#707684;font-weight:500}.cdx-search-field__input::-ms-input-placeholder{color:#707684;font-weight:500}.cdx-search-field__input::placeholder{color:#707684;font-weight:500}.ce-popover{--border-radius: 6px;--width: 200px;--max-height: 270px;--padding: 6px;--offset-from-target: 8px;--color-border: #EFF0F1;--color-shadow: rgba(13, 20, 33, .1);--color-background: white;--color-text-primary: black;--color-text-secondary: #707684;--color-border-icon: rgba(201, 201, 204, .48);--color-border-icon-disabled: #EFF0F1;--color-text-icon-active: #388AE5;--color-background-icon-active: rgba(56, 138, 229, .1);--color-background-item-focus: rgba(34, 186, 255, .08);--color-shadow-item-focus: rgba(7, 161, 227, .08);--color-background-item-hover: #F8F8F8;--color-background-item-confirm: #E24A4A;--color-background-item-confirm-hover: #CE4343;--popover-top: calc(100% + var(--offset-from-target));--popover-left: 0;--nested-popover-overlap: 4px;--icon-size: 20px;--item-padding: 3px;--item-height: calc(var(--icon-size) + 2 * var(--item-padding))}.ce-popover__container{min-width:var(--width);width:var(--width);max-height:var(--max-height);border-radius:var(--border-radius);overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-box-shadow:0px 3px 15px -3px var(--color-shadow);box-shadow:0 3px 15px -3px var(--color-shadow);position:absolute;left:var(--popover-left);top:var(--popover-top);background:var(--color-background);display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;z-index:4;opacity:0;max-height:0;pointer-events:none;padding:0;border:none}.ce-popover--opened>.ce-popover__container{opacity:1;padding:var(--padding);max-height:var(--max-height);pointer-events:auto;-webkit-animation:panelShowing .1s ease;animation:panelShowing .1s ease;border:1px solid var(--color-border)}@media (max-width: 650px){.ce-popover--opened>.ce-popover__container{-webkit-animation:panelShowingMobile .25s ease;animation:panelShowingMobile .25s ease}}.ce-popover--open-top .ce-popover__container{--popover-top: calc(-1 * (var(--offset-from-target) + var(--popover-height)))}.ce-popover--open-left .ce-popover__container{--popover-left: calc(-1 * var(--width) + 100%)}.ce-popover__items{overflow-y:auto;-ms-scroll-chaining:none;overscroll-behavior:contain}@media (max-width: 650px){.ce-popover__overlay{position:fixed;top:0;bottom:0;left:0;right:0;background:#1D202B;z-index:3;opacity:.5;-webkit-transition:opacity .12s ease-in;transition:opacity .12s ease-in;will-change:opacity;visibility:visible}}.ce-popover__overlay--hidden{display:none}@media (max-width: 650px){.ce-popover .ce-popover__container{--offset: 5px;position:fixed;max-width:none;min-width:calc(100% - var(--offset) * 2);left:var(--offset);right:var(--offset);bottom:calc(var(--offset) + env(safe-area-inset-bottom));top:auto;border-radius:10px}}.ce-popover__search{margin-bottom:5px}.ce-popover__nothing-found-message{color:#707684;display:none;cursor:default;padding:3px;font-size:14px;line-height:20px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ce-popover__nothing-found-message--displayed{display:block}.ce-popover--nested .ce-popover__container{--popover-left: calc(var(--nesting-level) * (var(--width) - var(--nested-popover-overlap)));top:calc(var(--trigger-item-top) - var(--nested-popover-overlap));position:absolute}.ce-popover--open-top.ce-popover--nested .ce-popover__container{top:calc(var(--trigger-item-top) - var(--popover-height) + var(--item-height) + var(--offset-from-target) + var(--nested-popover-overlap))}.ce-popover--open-left .ce-popover--nested .ce-popover__container{--popover-left: calc(-1 * (var(--nesting-level) + 1) * var(--width) + 100%)}.ce-popover-item-separator{padding:4px 3px}.ce-popover-item-separator--hidden{display:none}.ce-popover-item-separator__line{height:1px;background:var(--color-border);width:100%}.ce-popover-item-html--hidden{display:none}.ce-popover-item{--border-radius: 6px;border-radius:var(--border-radius);display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:var(--item-padding);color:var(--color-text-primary);-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border:none;background:transparent}@media (max-width: 650px){.ce-popover-item{padding:4px}}.ce-popover-item:not(:last-of-type){margin-bottom:1px}.ce-popover-item__icon{width:26px;height:26px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.ce-popover-item__icon svg{width:20px;height:20px}@media (max-width: 650px){.ce-popover-item__icon{width:36px;height:36px;border-radius:8px}.ce-popover-item__icon svg{width:28px;height:28px}}.ce-popover-item__icon--tool{margin-right:4px}.ce-popover-item__title{font-size:14px;line-height:20px;font-weight:500;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;margin-right:auto}@media (max-width: 650px){.ce-popover-item__title{font-size:16px}}.ce-popover-item__secondary-title{color:var(--color-text-secondary);font-size:12px;white-space:nowrap;letter-spacing:-.1em;padding-right:5px;opacity:.6}@media (max-width: 650px){.ce-popover-item__secondary-title{display:none}}.ce-popover-item--active{background:var(--color-background-icon-active);color:var(--color-text-icon-active)}.ce-popover-item--disabled{color:var(--color-text-secondary);cursor:default;pointer-events:none}.ce-popover-item--focused:not(.ce-popover-item--no-focus){background:var(--color-background-item-focus)!important}.ce-popover-item--hidden{display:none}@media (hover: hover){.ce-popover-item:hover{cursor:pointer}.ce-popover-item:hover:not(.ce-popover-item--no-hover){background-color:var(--color-background-item-hover)}}.ce-popover-item--confirmation{background:var(--color-background-item-confirm)}.ce-popover-item--confirmation .ce-popover-item__title,.ce-popover-item--confirmation .ce-popover-item__icon{color:#fff}@media (hover: hover){.ce-popover-item--confirmation:not(.ce-popover-item--no-hover):hover{background:var(--color-background-item-confirm-hover)}}.ce-popover-item--confirmation:not(.ce-popover-item--no-focus).ce-popover-item--focused{background:var(--color-background-item-confirm-hover)!important}@-webkit-keyframes panelShowing{0%{opacity:0;-webkit-transform:translateY(-8px) scale(.9);transform:translateY(-8px) scale(.9)}70%{opacity:1;-webkit-transform:translateY(2px);transform:translateY(2px)}to{-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes panelShowing{0%{opacity:0;-webkit-transform:translateY(-8px) scale(.9);transform:translateY(-8px) scale(.9)}70%{opacity:1;-webkit-transform:translateY(2px);transform:translateY(2px)}to{-webkit-transform:translateY(0);transform:translateY(0)}}@-webkit-keyframes panelShowingMobile{0%{opacity:0;-webkit-transform:translateY(14px) scale(.98);transform:translateY(14px) scale(.98)}70%{opacity:1;-webkit-transform:translateY(-4px);transform:translateY(-4px)}to{-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes panelShowingMobile{0%{opacity:0;-webkit-transform:translateY(14px) scale(.98);transform:translateY(14px) scale(.98)}70%{opacity:1;-webkit-transform:translateY(-4px);transform:translateY(-4px)}to{-webkit-transform:translateY(0);transform:translateY(0)}}.wobble{-webkit-animation-name:wobble;animation-name:wobble;-webkit-animation-duration:.4s;animation-duration:.4s}@-webkit-keyframes wobble{0%{-webkit-transform:translate3d(0,0,0);transform:translateZ(0)}15%{-webkit-transform:translate3d(-9%,0,0);transform:translate3d(-9%,0,0)}30%{-webkit-transform:translate3d(9%,0,0);transform:translate3d(9%,0,0)}45%{-webkit-transform:translate3d(-4%,0,0);transform:translate3d(-4%,0,0)}60%{-webkit-transform:translate3d(4%,0,0);transform:translate3d(4%,0,0)}75%{-webkit-transform:translate3d(-1%,0,0);transform:translate3d(-1%,0,0)}to{-webkit-transform:translate3d(0,0,0);transform:translateZ(0)}}@keyframes wobble{0%{-webkit-transform:translate3d(0,0,0);transform:translateZ(0)}15%{-webkit-transform:translate3d(-9%,0,0);transform:translate3d(-9%,0,0)}30%{-webkit-transform:translate3d(9%,0,0);transform:translate3d(9%,0,0)}45%{-webkit-transform:translate3d(-4%,0,0);transform:translate3d(-4%,0,0)}60%{-webkit-transform:translate3d(4%,0,0);transform:translate3d(4%,0,0)}75%{-webkit-transform:translate3d(-1%,0,0);transform:translate3d(-1%,0,0)}to{-webkit-transform:translate3d(0,0,0);transform:translateZ(0)}}.ce-popover-header{margin-bottom:8px;margin-top:4px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.ce-popover-header__text{font-size:18px;font-weight:600}.ce-popover-header__back-button{border:0;background:transparent;width:36px;height:36px;color:var(--color-text-primary)}.ce-popover-header__back-button svg{display:block;width:28px;height:28px}.ce-popover--inline{--height: 38px;--height-mobile: 46px;--container-padding: 4px;position:relative}.ce-popover--inline .ce-popover__custom-content{margin-bottom:0}.ce-popover--inline .ce-popover__items{display:-webkit-box;display:-ms-flexbox;display:flex}.ce-popover--inline .ce-popover__container{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;padding:var(--container-padding);height:var(--height);top:0;min-width:-webkit-max-content;min-width:-moz-max-content;min-width:max-content;width:-webkit-max-content;width:-moz-max-content;width:max-content;-webkit-animation:none;animation:none}@media (max-width: 650px){.ce-popover--inline .ce-popover__container{height:var(--height-mobile);position:absolute}}.ce-popover--inline .ce-popover-item-separator{padding:0 4px}.ce-popover--inline .ce-popover-item-separator__line{height:100%;width:1px}.ce-popover--inline .ce-popover-item{border-radius:4px;padding:4px}.ce-popover--inline .ce-popover-item__icon--tool{-webkit-box-shadow:none;box-shadow:none;background:transparent;margin-right:0}.ce-popover--inline .ce-popover-item__icon{width:auto;width:initial;height:auto;height:initial}.ce-popover--inline .ce-popover-item__icon svg{width:20px;height:20px}@media (max-width: 650px){.ce-popover--inline .ce-popover-item__icon svg{width:28px;height:28px}}.ce-popover--inline .ce-popover-item:not(:last-of-type){margin-bottom:0;margin-bottom:initial}.ce-popover--inline .ce-popover-item-html{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.ce-popover--inline .ce-popover-item__icon--chevron-right{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.ce-popover--inline .ce-popover--nested-level-1 .ce-popover__container{--offset: 3px;left:0;top:calc(var(--height) + var(--offset))}@media (max-width: 650px){.ce-popover--inline .ce-popover--nested-level-1 .ce-popover__container{top:calc(var(--height-mobile) + var(--offset))}}.ce-popover--inline .ce-popover--nested .ce-popover__container{min-width:var(--width);width:var(--width);height:-webkit-fit-content;height:-moz-fit-content;height:fit-content;padding:6px;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.ce-popover--inline .ce-popover--nested .ce-popover__items{display:block;width:100%}.ce-popover--inline .ce-popover--nested .ce-popover-item{border-radius:6px;padding:3px}@media (max-width: 650px){.ce-popover--inline .ce-popover--nested .ce-popover-item{padding:4px}}.ce-popover--inline .ce-popover--nested .ce-popover-item__icon--tool{margin-right:4px}.ce-popover--inline .ce-popover--nested .ce-popover-item__icon{width:26px;height:26px}.ce-popover--inline .ce-popover--nested .ce-popover-item-separator{padding:4px 3px}.ce-popover--inline .ce-popover--nested .ce-popover-item-separator__line{width:100%;height:1px}.codex-editor [data-placeholder]:empty:before,.codex-editor [data-placeholder][data-empty=true]:before{pointer-events:none;color:#707684;cursor:text;content:attr(data-placeholder)}.codex-editor [data-placeholder-active]:empty:before,.codex-editor [data-placeholder-active][data-empty=true]:before{pointer-events:none;color:#707684;cursor:text}.codex-editor [data-placeholder-active]:empty:focus:before,.codex-editor [data-placeholder-active][data-empty=true]:focus:before{content:attr(data-placeholder-active)}\n';class ys extends y{constructor(){super(...arguments),this.isMobile=!1,this.contentRectCache=void 0,this.resizeDebouncer=vt((()=>{this.windowResize()}),200)
2453
+ /**
2454
+ * Editor.js UI CSS class names
2455
+ *
2456
+ * @returns {{editorWrapper: string, editorZone: string}}
2457
+ */}get CSS(){return{editorWrapper:"codex-editor",editorWrapperNarrow:"codex-editor--narrow",editorZone:"codex-editor__redactor",editorZoneHidden:"codex-editor__redactor--hidden",editorEmpty:"codex-editor--empty",editorRtlFix:"codex-editor--rtl"}}
2458
+ /**
2459
+ * Return Width of center column of Editor
2460
+ *
2461
+ * @returns {DOMRect}
2462
+ */get contentRect(){if(this.contentRectCache)return this.contentRectCache;const n=this.nodes.wrapper.querySelector(`.${D.CSS.content}`);return n?(this.contentRectCache=n.getBoundingClientRect(),this.contentRectCache):{width:650,left:0,right:0}}async prepare(){this.setIsMobile(),this.make(),this.loadStyles()
2463
+ /**
2464
+ * Toggle read-only state
2465
+ *
2466
+ * If readOnly is true:
2467
+ * - removes all listeners from main UI module elements
2468
+ *
2469
+ * if readOnly is false:
2470
+ * - enables all listeners to UI module elements
2471
+ *
2472
+ * @param {boolean} readOnlyEnabled - "read only" state
2473
+ */}toggleReadOnly(n){n?this.disableModuleBindings():window.requestIdleCallback((()=>{this.enableModuleBindings()}),{timeout:2e3})}checkEmptiness(){const{BlockManager:n}=this.Editor;this.nodes.wrapper.classList.toggle(this.CSS.editorEmpty,n.isEditorEmpty)}
2474
+ /**
2475
+ * Check if one of Toolbar is opened
2476
+ * Used to prevent global keydowns (for example, Enter) conflicts with Enter-on-toolbar
2477
+ *
2478
+ * @returns {boolean}
2479
+ */get someToolbarOpened(){const{Toolbar:n,BlockSettings:h,InlineToolbar:p}=this.Editor;return!!(h.opened||p.opened||n.toolbox.opened)}get someFlipperButtonFocused(){return!!this.Editor.Toolbar.toolbox.hasFocus()||Object.entries(this.Editor).filter((([n,h])=>h.flipper instanceof le)).some((([n,h])=>h.flipper.hasFocus()))}destroy(){this.nodes.holder.innerHTML=""}closeAllToolbars(){const{Toolbar:n,BlockSettings:h,InlineToolbar:p}=this.Editor;h.close(),p.close(),n.toolbox.close()}setIsMobile(){const n=window.innerWidth<v;n!==this.isMobile&&this.eventsDispatcher.emit(z,{isEnabled:this.isMobile}),this.isMobile=n}make(){this.nodes.holder=d.getHolder(this.config.holder),this.nodes.wrapper=d.make("div",[this.CSS.editorWrapper,...this.isRtl?[this.CSS.editorRtlFix]:[]]),this.nodes.redactor=d.make("div",this.CSS.editorZone),this.nodes.holder.offsetWidth<this.contentRect.width&&this.nodes.wrapper.classList.add(this.CSS.editorWrapperNarrow),this.nodes.redactor.style.paddingBottom=this.config.minHeight+"px",this.nodes.wrapper.appendChild(this.nodes.redactor),this.nodes.holder.appendChild(this.nodes.wrapper)}loadStyles(){const n="editor-js-styles";if(d.get(n))return;const h=d.make("style",null,{id:n,textContent:Si.toString()});this.config.style&&!V(this.config.style)&&this.config.style.nonce&&h.setAttribute("nonce",this.config.style.nonce),d.prepend(document.head,h)}enableModuleBindings(){this.readOnlyMutableListeners.on(this.nodes.redactor,"click",(n=>{this.redactorClicked(n)}),!1),this.readOnlyMutableListeners.on(this.nodes.redactor,"mousedown",(n=>{this.documentTouched(n)}),{capture:!0,passive:!0}),this.readOnlyMutableListeners.on(this.nodes.redactor,"touchstart",(n=>{this.documentTouched(n)}),{capture:!0,passive:!0}),this.readOnlyMutableListeners.on(document,"keydown",(n=>{this.documentKeydown(n)}),!0),this.readOnlyMutableListeners.on(document,"mousedown",(n=>{this.documentClicked(n)}),!0);const n=vt((()=>{this.selectionChanged()}),vi);this.readOnlyMutableListeners.on(document,"selectionchange",n,!0),this.readOnlyMutableListeners.on(window,"resize",(()=>{this.resizeDebouncer()}),{passive:!0}),this.watchBlockHoveredEvents(),this.enableInputsEmptyMark()}watchBlockHoveredEvents(){let n;this.readOnlyMutableListeners.on(this.nodes.redactor,"mousemove",Ve((h=>{const p=h.target.closest(".ce-block");this.Editor.BlockSelection.anyBlockSelected||p&&n!==p&&(n=p,this.eventsDispatcher.emit(No,{block:this.Editor.BlockManager.getBlockByChildNode(p)}))}),20),{passive:!0})}disableModuleBindings(){this.readOnlyMutableListeners.clearAll()}windowResize(){this.contentRectCache=null,this.setIsMobile()
2480
+ /**
2481
+ * All keydowns on document
2482
+ *
2483
+ * @param {KeyboardEvent} event - keyboard event
2484
+ */}documentKeydown(n){switch(n.keyCode){case h.ENTER:this.enterPressed(n);break;case h.BACKSPACE:case h.DELETE:this.backspacePressed(n);break;case h.ESC:this.escapePressed(n);break;default:this.defaultBehaviour(n);break}}
2485
+ /**
2486
+ * Ignore all other document's keydown events
2487
+ *
2488
+ * @param {KeyboardEvent} event - keyboard event
2489
+ */defaultBehaviour(n){const{currentBlock:h}=this.Editor.BlockManager,p=n.target.closest(`.${this.CSS.editorWrapper}`),g=n.altKey||n.ctrlKey||n.metaKey||n.shiftKey;h===void 0||p!==null?p||h&&g||(this.Editor.BlockManager.unsetCurrentBlock(),this.Editor.Toolbar.close()
2490
+ /**
2491
+ * @param {KeyboardEvent} event - keyboard event
2492
+ */):this.Editor.BlockEvents.keydown(n)}backspacePressed(n){const{BlockManager:h,BlockSelection:p,Caret:g}=this.Editor;if(p.anyBlockSelected&&!b.isSelectionExists){const m=h.removeSelectedBlocks(),v=h.insertDefaultBlockAtIndex(m,!0);g.setToBlock(v,g.positions.START),p.clearSelection(n),n.preventDefault(),n.stopPropagation(),n.stopImmediatePropagation()}}
2493
+ /**
2494
+ * Escape pressed
2495
+ * If some of Toolbar components are opened, then close it otherwise close Toolbar
2496
+ *
2497
+ * @param {Event} event - escape keydown event
2498
+ */escapePressed(n){this.Editor.BlockSelection.clearSelection(n),this.Editor.Toolbar.toolbox.opened?(this.Editor.Toolbar.toolbox.close(),this.Editor.Caret.setToBlock(this.Editor.BlockManager.currentBlock,this.Editor.Caret.positions.END)):this.Editor.BlockSettings.opened?this.Editor.BlockSettings.close():this.Editor.InlineToolbar.opened?this.Editor.InlineToolbar.close():this.Editor.Toolbar.close()
2499
+ /**
2500
+ * Enter pressed on document
2501
+ *
2502
+ * @param {KeyboardEvent} event - keyboard event
2503
+ */}enterPressed(n){const{BlockManager:h,BlockSelection:p}=this.Editor;if(this.someToolbarOpened)return;const g=h.currentBlockIndex>=0;if(!p.anyBlockSelected||b.isSelectionExists){if(!this.someToolbarOpened&&g&&n.target.tagName==="BODY"){const h=this.Editor.BlockManager.insert();n.preventDefault(),this.Editor.Caret.setToBlock(h),this.Editor.Toolbar.moveAndOpen(h)}this.Editor.BlockSelection.clearSelection(n)}else p.clearSelection(n),n.preventDefault(),n.stopImmediatePropagation(),n.stopPropagation()}
2504
+ /**
2505
+ * All clicks on document
2506
+ *
2507
+ * @param {MouseEvent} event - Click event
2508
+ */documentClicked(n){var h,p;if(!n.isTrusted)return;const g=n.target;this.nodes.holder.contains(g)||b.isAtEditor||(this.Editor.BlockManager.unsetCurrentBlock(),this.Editor.Toolbar.close());const m=(h=this.Editor.BlockSettings.nodes.wrapper)==null?void 0:h.contains(g),v=(p=this.Editor.Toolbar.nodes.settingsToggler)==null?void 0:p.contains(g),x=m||v;if(this.Editor.BlockSettings.opened&&!x){this.Editor.BlockSettings.close();const n=this.Editor.BlockManager.getBlockByChildNode(g);this.Editor.Toolbar.moveAndOpen(n)}this.Editor.BlockSelection.clearSelection(n)}
2509
+ /**
2510
+ * First touch on editor
2511
+ * Fired before click
2512
+ *
2513
+ * Used to change current block — we need to do it before 'selectionChange' event.
2514
+ * Also:
2515
+ * - Move and show the Toolbar
2516
+ * - Set a Caret
2517
+ *
2518
+ * @param {MouseEvent | TouchEvent} event - touch or mouse event
2519
+ */documentTouched(n){let h=n.target;if(h===this.nodes.redactor){const p=n instanceof MouseEvent?n.clientX:n.touches[0].clientX,g=n instanceof MouseEvent?n.clientY:n.touches[0].clientY;h=document.elementFromPoint(p,g)}try{this.Editor.BlockManager.setCurrentBlockByChildNode(h)}catch{this.Editor.RectangleSelection.isRectActivated()||this.Editor.Caret.setToTheLastBlock()}this.Editor.Toolbar.moveAndOpen()}
2520
+ /**
2521
+ * All clicks on the redactor zone
2522
+ *
2523
+ * @param {MouseEvent} event - click event
2524
+ * @description
2525
+ * - By clicks on the Editor's bottom zone:
2526
+ * - if last Block is empty, set a Caret to this
2527
+ * - otherwise, add a new empty Block and set a Caret to that
2528
+ */redactorClicked(n){if(!b.isCollapsed)return;const h=n.target,p=n.metaKey||n.ctrlKey;if(d.isAnchor(h)&&p){n.stopImmediatePropagation(),n.stopPropagation();const p=h.getAttribute("href"),g=So(p);Mo(g)}else this.processBottomZoneClick(n)}
2529
+ /**
2530
+ * Check if user clicks on the Editor's bottom zone:
2531
+ * - set caret to the last block
2532
+ * - or add new empty block
2533
+ *
2534
+ * @param event - click event
2535
+ */processBottomZoneClick(n){const h=this.Editor.BlockManager.getBlockByIndex(-1),p=d.offset(h.holder).bottom,g=n.pageY,{BlockSelection:m}=this.Editor;if(n.target instanceof Element&&n.target.isEqualNode(this.nodes.redactor)&&!m.anyBlockSelected&&p<g){n.stopImmediatePropagation(),n.stopPropagation();const{BlockManager:h,Caret:p,Toolbar:g}=this.Editor;(!h.lastBlock.tool.isDefault||!h.lastBlock.isEmpty)&&h.insertAtEnd(),p.setToTheLastBlock(),g.moveAndOpen(h.lastBlock)}}selectionChanged(){const{CrossBlockSelection:n,BlockSelection:h}=this.Editor,p=b.anchorElement;if(n.isCrossBlockSelectionStarted&&h.anyBlockSelected&&b.get().removeAllRanges(),!p){b.range||this.Editor.InlineToolbar.close();return}const g=p.closest(`.${D.CSS.content}`);(g===null||g.closest(`.${b.CSS.editorWrapper}`)!==this.nodes.wrapper)&&(this.Editor.InlineToolbar.containsNode(p)||this.Editor.InlineToolbar.close(),!(p.dataset.inlineToolbar==="true"))||(this.Editor.BlockManager.currentBlock||this.Editor.BlockManager.setCurrentBlockByChildNode(p),this.Editor.InlineToolbar.tryToShow(!0))}enableInputsEmptyMark(){function e(n){const h=n.target;Lt(h)}this.readOnlyMutableListeners.on(this.nodes.wrapper,"input",e),this.readOnlyMutableListeners.on(this.nodes.wrapper,"focusin",e),this.readOnlyMutableListeners.on(this.nodes.wrapper,"focusout",e)}}const Ii={BlocksAPI:zo,CaretAPI:jo,EventsAPI:$o,I18nAPI:ot,API:Yo,InlineToolbarAPI:Wo,ListenersAPI:Ko,NotifierAPI:Zo,ReadOnlyAPI:Go,SanitizerAPI:si,SaverAPI:ni,SelectionAPI:ri,ToolsAPI:li,StylesAPI:ai,ToolbarAPI:ci,TooltipAPI:fi,UiAPI:gi,BlockSettings:Ui,Toolbar:qi,InlineToolbar:Zi,BlockEvents:Gi,BlockManager:es,BlockSelection:ts,Caret:Re,CrossBlockSelection:os,DragNDrop:is,ModificationsObserver:rs,Paste:xi,ReadOnly:as,RectangleSelection:xe,Renderer:cs,Saver:ds,Tools:go,UI:ys};class Bs{
2536
+ /**
2537
+ * @param {EditorConfig} config - user configuration
2538
+ */
2539
+ constructor(n){this.moduleInstances={},this.eventsDispatcher=new Te;let h,p;this.isReady=new Promise(((n,g)=>{h=n,p=g})),Promise.resolve().then((async()=>{this.configuration=n,this.validate(),this.init(),await this.start(),await this.render();const{BlockManager:p,Caret:g,UI:m,ModificationsObserver:v}=this.moduleInstances;m.checkEmptiness(),v.enable(),this.configuration.autofocus&&g.setToBlock(p.blocks[0],g.positions.START),h()})).catch((n=>{g(`Editor.js is not ready because of ${n}`,"error"),p(n)}))
2540
+ /**
2541
+ * Setting for configuration
2542
+ *
2543
+ * @param {EditorConfig|string} config - Editor's config to set
2544
+ */}set configuration(h){var p,g;R(h)?this.config={...h}:this.config={holder:h},Ze(!!this.config.holderId,"config.holderId","config.holder"),this.config.holderId&&!this.config.holder&&(this.config.holder=this.config.holderId,this.config.holderId=null),this.config.holder==null&&(this.config.holder="editorjs"),this.config.logLevel||(this.config.logLevel=n.VERBOSE),xo(this.config.logLevel),Ze(!!this.config.initialBlock,"config.initialBlock","config.defaultBlock"),this.config.defaultBlock=this.config.defaultBlock||this.config.initialBlock||"paragraph",this.config.minHeight=this.config.minHeight!==void 0?this.config.minHeight:300;const m={type:this.config.defaultBlock,data:{}};this.config.placeholder=this.config.placeholder||!1,this.config.sanitizer=this.config.sanitizer||{p:!0,b:!0,a:!0},this.config.hideToolbar=!!this.config.hideToolbar&&this.config.hideToolbar,this.config.tools=this.config.tools||{},this.config.i18n=this.config.i18n||{},this.config.data=this.config.data||{blocks:[]},this.config.onReady=this.config.onReady||(()=>{}),this.config.onChange=this.config.onChange||(()=>{}),this.config.inlineToolbar=this.config.inlineToolbar===void 0||this.config.inlineToolbar,(V(this.config.data)||!this.config.data.blocks||this.config.data.blocks.length===0)&&(this.config.data={blocks:[m]}),this.config.readOnly=this.config.readOnly||!1,(p=this.config.i18n)!=null&&p.messages&&A.setDictionary(this.config.i18n.messages),this.config.i18n.direction=((g=this.config.i18n)==null?void 0:g.direction)||"ltr"
2545
+ /**
2546
+ * Returns private property
2547
+ *
2548
+ * @returns {EditorConfig}
2549
+ */}get configuration(){return this.config}validate(){const{holderId:n,holder:h}=this.config;if(n&&h)throw Error("«holderId» and «holder» param can't assign at the same time.");if(Q(h)&&!d.get(h))throw Error(`element with ID «${h}» is missing. Pass correct holder's ID.`);if(h&&R(h)&&!d.isElement(h))throw Error("«holder» value must be an Element node")}init(){this.constructModules(),this.configureModules()
2550
+ /**
2551
+ * Start Editor!
2552
+ *
2553
+ * Get list of modules that needs to be prepared and return a sequence (Promise)
2554
+ *
2555
+ * @returns {Promise<void>}
2556
+ */}async start(){await["Tools","UI","BlockManager","Paste","BlockSelection","RectangleSelection","CrossBlockSelection","ReadOnly"].reduce(((n,h)=>n.then((async()=>{try{await this.moduleInstances[h].prepare()}catch(n){if(n instanceof Pt)throw new Error(n.message);g(`Module ${h} was skipped because of %o`,"warn",n)}}))),Promise.resolve())}render(){return this.moduleInstances.Renderer.render(this.config.data.blocks)}constructModules(){Object.entries(Ii).forEach((([n,h])=>{try{this.moduleInstances[n]=new h({config:this.configuration,eventsDispatcher:this.eventsDispatcher})}catch(h){g("[constructModules]",`Module ${n} skipped because`,"error",h)}}))}configureModules(){for(const n in this.moduleInstances)Object.prototype.hasOwnProperty.call(this.moduleInstances,n)&&(this.moduleInstances[n].state=this.getModulesDiff(n))}
2557
+ /**
2558
+ * Return modules without passed name
2559
+ *
2560
+ * @param {string} name - module for witch modules difference should be calculated
2561
+ */getModulesDiff(n){const h={};for(const p in this.moduleInstances)p!==n&&(h[p]=this.moduleInstances[p]);return h}}
2562
+ /**
2563
+ * Editor.js
2564
+ *
2565
+ * @license Apache-2.0
2566
+ * @see Editor.js <https://editorjs.io>
2567
+ * @author CodeX Team <https://codex.so>
2568
+ */class Ts{static get version(){return"2.30.6"}
2569
+ /**
2570
+ * @param {EditorConfig|string|undefined} [configuration] - user configuration
2571
+ */constructor(n){let t=()=>{};R(n)&&O(n.onReady)&&(t=n.onReady);const h=new Bs(n);this.isReady=h.isReady.then((()=>{this.exportAPI(h),t()}))}
2572
+ /**
2573
+ * Export external API methods
2574
+ *
2575
+ * @param {Core} editor — Editor's instance
2576
+ */exportAPI(n){const h=["configuration"],o=()=>{Object.values(n.moduleInstances).forEach((n=>{O(n.destroy)&&n.destroy(),n.listeners.removeAll()})),pi(),n=null;for(const n in this)Object.prototype.hasOwnProperty.call(this,n)&&delete this[n];Object.setPrototypeOf(this,null)};h.forEach((h=>{this[h]=n[h]})),this.destroy=o,Object.setPrototypeOf(this,n.moduleInstances.API.methods),delete this.exportAPI,Object.entries({blocks:{clear:"clear",render:"render"},caret:{focus:"focus"},events:{on:"on",off:"off",emit:"emit"},saver:{save:"save"}}).forEach((([h,p])=>{Object.entries(p).forEach((([p,g])=>{this[g]=n.moduleInstances.API.methods[h][p]}))}))}}export{Ts as default};
2577
+