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.
- checksums.yaml +7 -0
- data/README.md +73 -0
- data/Rakefile +7 -0
- data/app/assets/builds/panda.cms.css +2808 -0
- data/app/assets/config/panda_cms_manifest.js +4 -0
- data/app/assets/stylesheets/panda/cms/application.tailwind.css +162 -0
- data/app/assets/stylesheets/panda/cms/editor.css +120 -0
- data/app/builders/panda/cms/form_builder.rb +234 -0
- data/app/components/panda/cms/admin/button_component.rb +70 -0
- data/app/components/panda/cms/admin/container_component.html.erb +13 -0
- data/app/components/panda/cms/admin/container_component.rb +13 -0
- data/app/components/panda/cms/admin/flash_message_component.html.erb +31 -0
- data/app/components/panda/cms/admin/flash_message_component.rb +47 -0
- data/app/components/panda/cms/admin/heading_component.rb +45 -0
- data/app/components/panda/cms/admin/panel_component.html.erb +7 -0
- data/app/components/panda/cms/admin/panel_component.rb +13 -0
- data/app/components/panda/cms/admin/slideover_component.html.erb +9 -0
- data/app/components/panda/cms/admin/slideover_component.rb +15 -0
- data/app/components/panda/cms/admin/statistics_component.html.erb +4 -0
- data/app/components/panda/cms/admin/statistics_component.rb +17 -0
- data/app/components/panda/cms/admin/tab_bar_component.html.erb +35 -0
- data/app/components/panda/cms/admin/tab_bar_component.rb +15 -0
- data/app/components/panda/cms/admin/table_component.html.erb +29 -0
- data/app/components/panda/cms/admin/table_component.rb +46 -0
- data/app/components/panda/cms/admin/tag_component.rb +35 -0
- data/app/components/panda/cms/admin/user_activity_component.html.erb +5 -0
- data/app/components/panda/cms/admin/user_activity_component.rb +33 -0
- data/app/components/panda/cms/admin/user_display_component.html.erb +17 -0
- data/app/components/panda/cms/admin/user_display_component.rb +21 -0
- data/app/components/panda/cms/code_component.rb +64 -0
- data/app/components/panda/cms/grid_component.html.erb +6 -0
- data/app/components/panda/cms/grid_component.rb +15 -0
- data/app/components/panda/cms/menu_component.html.erb +6 -0
- data/app/components/panda/cms/menu_component.rb +58 -0
- data/app/components/panda/cms/page_menu_component.html.erb +21 -0
- data/app/components/panda/cms/page_menu_component.rb +38 -0
- data/app/components/panda/cms/rich_text_component.html.erb +6 -0
- data/app/components/panda/cms/rich_text_component.rb +84 -0
- data/app/components/panda/cms/text_component.rb +72 -0
- data/app/constraints/panda/cms/admin_constraint.rb +18 -0
- data/app/controllers/panda/cms/admin/block_contents_controller.rb +52 -0
- data/app/controllers/panda/cms/admin/dashboard_controller.rb +20 -0
- data/app/controllers/panda/cms/admin/files_controller.rb +21 -0
- data/app/controllers/panda/cms/admin/forms_controller.rb +53 -0
- data/app/controllers/panda/cms/admin/menus_controller.rb +30 -0
- data/app/controllers/panda/cms/admin/pages_controller.rb +91 -0
- data/app/controllers/panda/cms/admin/posts_controller.rb +146 -0
- data/app/controllers/panda/cms/admin/sessions_controller.rb +94 -0
- data/app/controllers/panda/cms/admin/settings/bulk_editor_controller.rb +37 -0
- data/app/controllers/panda/cms/admin/settings_controller.rb +20 -0
- data/app/controllers/panda/cms/application_controller.rb +57 -0
- data/app/controllers/panda/cms/errors_controller.rb +33 -0
- data/app/controllers/panda/cms/form_submissions_controller.rb +23 -0
- data/app/controllers/panda/cms/pages_controller.rb +72 -0
- data/app/controllers/panda/cms/posts_controller.rb +13 -0
- data/app/helpers/panda/cms/admin/files_helper.rb +6 -0
- data/app/helpers/panda/cms/admin/pages_helper.rb +6 -0
- data/app/helpers/panda/cms/admin/posts_helper.rb +48 -0
- data/app/helpers/panda/cms/application_helper.rb +120 -0
- data/app/helpers/panda/cms/pages_helper.rb +6 -0
- data/app/helpers/panda/cms/theme_helper.rb +18 -0
- data/app/javascript/panda/cms/@editorjs--editorjs.js +2577 -0
- data/app/javascript/panda/cms/@hotwired--stimulus.js +4 -0
- data/app/javascript/panda/cms/@hotwired--turbo.js +160 -0
- data/app/javascript/panda/cms/@rails--actioncable--src.js +4 -0
- data/app/javascript/panda/cms/application_panda_cms.js +39 -0
- data/app/javascript/panda/cms/controllers/dashboard_controller.js +7 -0
- data/app/javascript/panda/cms/controllers/editor_form_controller.js +77 -0
- data/app/javascript/panda/cms/controllers/editor_iframe_controller.js +320 -0
- data/app/javascript/panda/cms/controllers/index.js +48 -0
- data/app/javascript/panda/cms/controllers/slug_controller.js +87 -0
- data/app/javascript/panda/cms/editor/css_extractor.js +80 -0
- data/app/javascript/panda/cms/editor/editor_js_config.js +177 -0
- data/app/javascript/panda/cms/editor/editor_js_initializer.js +285 -0
- data/app/javascript/panda/cms/editor/plain_text_editor.js +110 -0
- data/app/javascript/panda/cms/editor/resource_loader.js +115 -0
- data/app/javascript/panda/cms/tailwindcss-stimulus-components.js +4 -0
- data/app/jobs/panda/cms/application_job.rb +6 -0
- data/app/jobs/panda/cms/record_visit_job.rb +31 -0
- data/app/mailers/panda/cms/application_mailer.rb +8 -0
- data/app/mailers/panda/cms/form_mailer.rb +21 -0
- data/app/models/action_text/rich_text_version.rb +6 -0
- data/app/models/panda/cms/application_record.rb +7 -0
- data/app/models/panda/cms/block.rb +34 -0
- data/app/models/panda/cms/block_content.rb +18 -0
- data/app/models/panda/cms/block_content_version.rb +8 -0
- data/app/models/panda/cms/breadcrumb.rb +12 -0
- data/app/models/panda/cms/current.rb +17 -0
- data/app/models/panda/cms/form.rb +9 -0
- data/app/models/panda/cms/form_submission.rb +7 -0
- data/app/models/panda/cms/menu.rb +52 -0
- data/app/models/panda/cms/menu_item.rb +58 -0
- data/app/models/panda/cms/page.rb +96 -0
- data/app/models/panda/cms/page_version.rb +8 -0
- data/app/models/panda/cms/post.rb +60 -0
- data/app/models/panda/cms/post_version.rb +8 -0
- data/app/models/panda/cms/redirect.rb +11 -0
- data/app/models/panda/cms/template.rb +124 -0
- data/app/models/panda/cms/template_version.rb +8 -0
- data/app/models/panda/cms/user.rb +31 -0
- data/app/models/panda/cms/version.rb +8 -0
- data/app/models/panda/cms/visit.rb +9 -0
- data/app/services/panda/cms/html_to_editor_js_converter.rb +200 -0
- data/app/views/active_storage/blobs/blobs/_blob.html.erb +14 -0
- data/app/views/layouts/action_text/contents/_content.html.erb +3 -0
- data/app/views/layouts/panda/cms/application.html.erb +41 -0
- data/app/views/layouts/panda/cms/public.html.erb +3 -0
- data/app/views/panda/cms/admin/dashboard/show.html.erb +12 -0
- data/app/views/panda/cms/admin/files/index.html.erb +124 -0
- data/app/views/panda/cms/admin/files/show.html.erb +2 -0
- data/app/views/panda/cms/admin/forms/edit.html.erb +0 -0
- data/app/views/panda/cms/admin/forms/index.html.erb +13 -0
- data/app/views/panda/cms/admin/forms/new.html.erb +15 -0
- data/app/views/panda/cms/admin/forms/show.html.erb +35 -0
- data/app/views/panda/cms/admin/menus/index.html.erb +8 -0
- data/app/views/panda/cms/admin/pages/edit.html.erb +36 -0
- data/app/views/panda/cms/admin/pages/index.html.erb +22 -0
- data/app/views/panda/cms/admin/pages/new.html.erb +15 -0
- data/app/views/panda/cms/admin/pages/show.html.erb +1 -0
- data/app/views/panda/cms/admin/posts/_form.html.erb +29 -0
- data/app/views/panda/cms/admin/posts/edit.html.erb +6 -0
- data/app/views/panda/cms/admin/posts/index.html.erb +18 -0
- data/app/views/panda/cms/admin/posts/new.html.erb +6 -0
- data/app/views/panda/cms/admin/sessions/new.html.erb +17 -0
- data/app/views/panda/cms/admin/settings/bulk_editor/new.html.erb +68 -0
- data/app/views/panda/cms/admin/settings/index.html.erb +21 -0
- data/app/views/panda/cms/admin/settings/insta.html +4 -0
- data/app/views/panda/cms/admin/shared/_breadcrumbs.html.erb +28 -0
- data/app/views/panda/cms/admin/shared/_flash.html.erb +5 -0
- data/app/views/panda/cms/admin/shared/_sidebar.html.erb +41 -0
- data/app/views/panda/cms/form_mailer/notification_email.html.erb +11 -0
- data/app/views/panda/cms/shared/_editor.html.erb +0 -0
- data/app/views/panda/cms/shared/_favicons.html.erb +9 -0
- data/app/views/panda/cms/shared/_footer.html.erb +2 -0
- data/app/views/panda/cms/shared/_header.html.erb +15 -0
- data/app/views/panda/cms/shared/_importmap.html.erb +33 -0
- data/config/importmap.rb +13 -0
- data/config/initializers/inflections.rb +3 -0
- data/config/initializers/panda/cms/form_errors.rb +38 -0
- data/config/initializers/panda/cms/healthcheck_log_silencer.rb +11 -0
- data/config/initializers/panda/cms/paper_trail.rb +7 -0
- data/config/initializers/panda/cms.rb +10 -0
- data/config/initializers/zeitwork.rb +3 -0
- data/config/locales/en.yml +49 -0
- data/config/puma/test.rb +9 -0
- data/config/routes.rb +48 -0
- data/config/tailwind.config.js +37 -0
- data/db/migrate/20240205223709_create_panda_cms_pages.rb +9 -0
- data/db/migrate/20240219213327_create_panda_cms_page_versions.rb +14 -0
- data/db/migrate/20240303002805_create_panda_cms_templates.rb +11 -0
- data/db/migrate/20240303003434_create_panda_cms_template_versions.rb +14 -0
- data/db/migrate/20240303022441_create_panda_cms_blocks.rb +13 -0
- data/db/migrate/20240303024256_create_panda_cms_block_contents.rb +10 -0
- data/db/migrate/20240303024746_create_panda_cms_block_content_versions.rb +14 -0
- data/db/migrate/20240303233238_add_panda_cms_menu_table.rb +10 -0
- data/db/migrate/20240303234724_add_panda_cms_menu_item_table.rb +12 -0
- data/db/migrate/20240304134343_add_parent_id_to_panda_cms_pages.rb +5 -0
- data/db/migrate/20240305000000_convert_html_content_to_editor_js.rb +82 -0
- data/db/migrate/20240315125411_add_status_to_panda_cms_pages.rb +9 -0
- data/db/migrate/20240315125421_add_nested_sets_to_panda_cms_pages.rb +16 -0
- data/db/migrate/20240316212822_add_kind_to_panda_cms_menus.rb +6 -0
- data/db/migrate/20240316221425_add_start_page_to_panda_cms_menus.rb +5 -0
- data/db/migrate/20240316230706_add_nested_to_panda_cms_menu_items.rb +24 -0
- data/db/migrate/20240317010532_create_panda_cms_users.rb +12 -0
- data/db/migrate/20240317161534_add_max_uses_to_panda_cms_template.rb +7 -0
- data/db/migrate/20240317163053_reset_counter_cache_on_panda_cms_template.rb +5 -0
- data/db/migrate/20240317214827_create_panda_cms_redirects.rb +14 -0
- data/db/migrate/20240317230622_create_panda_cms_visits.rb +13 -0
- data/db/migrate/20240324205703_create_active_storage_tables.active_storage.rb +58 -0
- data/db/migrate/20240408084718_default_panda_cms_users_admin_to_false.rb +5 -0
- data/db/migrate/20240701225422_add_service_name_to_active_storage_blobs.active_storage.rb +22 -0
- data/db/migrate/20240701225423_create_active_storage_variant_records.active_storage.rb +28 -0
- data/db/migrate/20240701225424_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb +8 -0
- data/db/migrate/20240804235210_create_panda_cms_forms.rb +11 -0
- data/db/migrate/20240805013612_create_panda_cms_form_submissions.rb +9 -0
- data/db/migrate/20240805121123_create_panda_cms_posts.rb +27 -0
- data/db/migrate/20240805123104_create_panda_cms_post_versions.rb +14 -0
- data/db/migrate/20240806112735_fix_panda_cms_visits_column_names.rb +13 -0
- data/db/migrate/20240806204412_add_completion_path_to_panda_cms_forms.rb +5 -0
- data/db/migrate/20240820081917_change_form_submissions_to_submission_count.rb +5 -0
- data/db/migrate/20240904200605_create_action_text_tables.action_text.rb +24 -0
- data/db/migrate/20240923234535_add_depth_to_panda_cms_menus.rb +11 -0
- data/db/migrate/20241031205109_add_cached_content_to_panda_cms_block_contents.rb +5 -0
- data/db/migrate/20241119214548_convert_post_content_to_editor_js.rb +35 -0
- data/db/migrate/20241119214549_remove_action_text_from_posts.rb +9 -0
- data/db/migrate/20241120000419_remove_post_tag_references.rb +19 -0
- data/db/migrate/20241120110943_add_editor_js_to_posts.rb +27 -0
- data/db/migrate/20241120113859_add_cached_content_to_panda_cms_posts.rb +5 -0
- data/db/migrate/20241123234140_remove_post_tag_id_from_posts.rb +5 -0
- data/db/migrate/migrate +1 -0
- data/db/seeds.rb +5 -0
- data/lib/generators/panda/cms/install_generator.rb +29 -0
- data/lib/panda/cms/bulk_editor.rb +171 -0
- data/lib/panda/cms/demo_site_generator.rb +67 -0
- data/lib/panda/cms/editor_js/blocks/alert.rb +34 -0
- data/lib/panda/cms/editor_js/blocks/base.rb +33 -0
- data/lib/panda/cms/editor_js/blocks/header.rb +15 -0
- data/lib/panda/cms/editor_js/blocks/image.rb +36 -0
- data/lib/panda/cms/editor_js/blocks/list.rb +32 -0
- data/lib/panda/cms/editor_js/blocks/paragraph.rb +15 -0
- data/lib/panda/cms/editor_js/blocks/quote.rb +41 -0
- data/lib/panda/cms/editor_js/blocks/table.rb +50 -0
- data/lib/panda/cms/editor_js/renderer.rb +124 -0
- data/lib/panda/cms/editor_js.rb +16 -0
- data/lib/panda/cms/editor_js_content.rb +21 -0
- data/lib/panda/cms/engine.rb +257 -0
- data/lib/panda/cms/exceptions_app.rb +26 -0
- data/lib/panda/cms/railtie.rb +11 -0
- data/lib/panda/cms/slug.rb +24 -0
- data/lib/panda/cms.rb +0 -0
- data/lib/panda-cms/version.rb +5 -0
- data/lib/panda-cms.rb +81 -0
- data/lib/tasks/panda_cms.rake +54 -0
- data/lib/templates/erb/scaffold/_form.html.erb.tt +43 -0
- data/lib/templates/erb/scaffold/edit.html.erb.tt +8 -0
- data/lib/templates/erb/scaffold/index.html.erb.tt +14 -0
- data/lib/templates/erb/scaffold/new.html.erb.tt +7 -0
- data/lib/templates/erb/scaffold/partial.html.erb.tt +22 -0
- data/lib/templates/erb/scaffold/show.html.erb.tt +15 -0
- data/public/panda-cms-assets/favicons/android-chrome-192x192.png +0 -0
- data/public/panda-cms-assets/favicons/android-chrome-512x512.png +0 -0
- data/public/panda-cms-assets/favicons/apple-touch-icon.png +0 -0
- data/public/panda-cms-assets/favicons/browserconfig.xml +9 -0
- data/public/panda-cms-assets/favicons/favicon-16x16.png +0 -0
- data/public/panda-cms-assets/favicons/favicon-32x32.png +0 -0
- data/public/panda-cms-assets/favicons/favicon.ico +0 -0
- data/public/panda-cms-assets/favicons/mstile-150x150.png +0 -0
- data/public/panda-cms-assets/favicons/safari-pinned-tab.svg +61 -0
- data/public/panda-cms-assets/favicons/site.webmanifest +14 -0
- data/public/panda-cms-assets/panda-logo-screenprint.png +0 -0
- data/public/panda-cms-assets/panda-nav.png +0 -0
- data/public/panda-cms-assets/rich_text_editor.css +568 -0
- 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
|
+
|