@ckeditor/ckeditor5-heading 41.4.1 → 42.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,6 +15,12 @@ Check out the [demo in the heading feature guide](https://ckeditor.com/docs/cked
15
15
 
16
16
  See the [`@ckeditor/ckeditor5-heading` package](https://ckeditor.com/docs/ckeditor5/latest/api/heading.html) page in [CKEditor 5 documentation](https://ckeditor.com/docs/ckeditor5/latest/).
17
17
 
18
+ ## Installation
19
+
20
+ ```bash
21
+ npm install ckeditor5
22
+ ```
23
+
18
24
  ## License
19
25
 
20
26
  Licensed under the terms of [GNU General Public License Version 2 or later](http://www.gnu.org/licenses/gpl.html). For full details about the license, please check the `LICENSE.md` file or [https://ckeditor.com/legal/ckeditor-oss-license](https://ckeditor.com/legal/ckeditor-oss-license).
package/build/heading.js CHANGED
@@ -2,4 +2,4 @@
2
2
  /*!
3
3
  * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
4
4
  * For licensing, see LICENSE.md.
5
- */(()=>{var e={707:(e,t,n)=>{"use strict";n.d(t,{A:()=>a});var o=n(935),i=n.n(o)()((function(e){return e[1]}));i.push([e.id,".ck.ck-heading_heading1{font-size:20px}.ck.ck-heading_heading2{font-size:17px}.ck.ck-heading_heading3{font-size:14px}.ck[class*=ck-heading_heading]{font-weight:700}.ck.ck-dropdown.ck-heading-dropdown .ck-dropdown__button .ck-button__label{width:8em}.ck.ck-dropdown.ck-heading-dropdown .ck-dropdown__panel .ck-list__item{min-width:18em}",""]);const a=i},935:e=>{"use strict";e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var n=e(t);return t[2]?"@media ".concat(t[2]," {").concat(n,"}"):n})).join("")},t.i=function(e,n,o){"string"==typeof e&&(e=[[null,e,""]]);var i={};if(o)for(var a=0;a<this.length;a++){var r=this[a][0];null!=r&&(i[r]=!0)}for(var s=0;s<e.length;s++){var d=[].concat(e[s]);o&&i[d[0]]||(n&&(d[2]?d[2]="".concat(n," and ").concat(d[2]):d[2]=n),t.push(d))}},t}},591:(e,t,n)=>{"use strict";var o,i=function(){return void 0===o&&(o=Boolean(window&&document&&document.all&&!window.atob)),o},a=function(){var e={};return function(t){if(void 0===e[t]){var n=document.querySelector(t);if(window.HTMLIFrameElement&&n instanceof window.HTMLIFrameElement)try{n=n.contentDocument.head}catch(e){n=null}e[t]=n}return e[t]}}(),r=[];function s(e){for(var t=-1,n=0;n<r.length;n++)if(r[n].identifier===e){t=n;break}return t}function d(e,t){for(var n={},o=[],i=0;i<e.length;i++){var a=e[i],d=t.base?a[0]+t.base:a[0],c=n[d]||0,l="".concat(d," ").concat(c);n[d]=c+1;var u=s(l),m={css:a[1],media:a[2],sourceMap:a[3]};-1!==u?(r[u].references++,r[u].updater(m)):r.push({identifier:l,updater:f(m,t),references:1}),o.push(l)}return o}function c(e){var t=document.createElement("style"),o=e.attributes||{};if(void 0===o.nonce){var i=n.nc;i&&(o.nonce=i)}if(Object.keys(o).forEach((function(e){t.setAttribute(e,o[e])})),"function"==typeof e.insert)e.insert(t);else{var r=a(e.insert||"head");if(!r)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");r.appendChild(t)}return t}var l,u=(l=[],function(e,t){return l[e]=t,l.filter(Boolean).join("\n")});function m(e,t,n,o){var i=n?"":o.media?"@media ".concat(o.media," {").concat(o.css,"}"):o.css;if(e.styleSheet)e.styleSheet.cssText=u(t,i);else{var a=document.createTextNode(i),r=e.childNodes;r[t]&&e.removeChild(r[t]),r.length?e.insertBefore(a,r[t]):e.appendChild(a)}}function g(e,t,n){var o=n.css,i=n.media,a=n.sourceMap;if(i?e.setAttribute("media",i):e.removeAttribute("media"),a&&"undefined"!=typeof btoa&&(o+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(a))))," */")),e.styleSheet)e.styleSheet.cssText=o;else{for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(o))}}var h=null,p=0;function f(e,t){var n,o,i;if(t.singleton){var a=p++;n=h||(h=c(t)),o=m.bind(null,n,a,!1),i=m.bind(null,n,a,!0)}else n=c(t),o=g.bind(null,n,t),i=function(){!function(e){if(null===e.parentNode)return!1;e.parentNode.removeChild(e)}(n)};return o(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap)return;o(e=t)}else i()}}e.exports=function(e,t){(t=t||{}).singleton||"boolean"==typeof t.singleton||(t.singleton=i());var n=d(e=e||[],t);return function(e){if(e=e||[],"[object Array]"===Object.prototype.toString.call(e)){for(var o=0;o<n.length;o++){var i=s(n[o]);r[i].references--}for(var a=d(e,t),c=0;c<n.length;c++){var l=s(n[c]);0===r[l].references&&(r[l].updater(),r.splice(l,1))}n=a}}}},782:(e,t,n)=>{e.exports=n(237)("./src/core.js")},783:(e,t,n)=>{e.exports=n(237)("./src/engine.js")},179:(e,t,n)=>{e.exports=n(237)("./src/paragraph.js")},311:(e,t,n)=>{e.exports=n(237)("./src/ui.js")},584:(e,t,n)=>{e.exports=n(237)("./src/utils.js")},237:e=>{"use strict";e.exports=CKEditor5.dll}},t={};function n(o){var i=t[o];if(void 0!==i)return i.exports;var a=t[o]={id:o,exports:{}};return e[o](a,a.exports,n),a.exports}n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var o in t)n.o(t,o)&&!n.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.nc=void 0;var o={};(()=>{"use strict";n.r(o),n.d(o,{Heading:()=>f,HeadingButtonsUI:()=>w,HeadingEditing:()=>d,HeadingUI:()=>p,Title:()=>x});var e=n(782),t=n(179),i=n(584);class a extends e.Command{constructor(e,t){super(e),this.modelElements=t}refresh(){const e=(0,i.first)(this.editor.model.document.selection.getSelectedBlocks());this.value=!!e&&this.modelElements.includes(e.name)&&e.name,this.isEnabled=!!e&&this.modelElements.some((t=>r(e,t,this.editor.model.schema)))}execute(e){const t=this.editor.model,n=t.document,o=e.value;t.change((e=>{const i=Array.from(n.selection.getSelectedBlocks()).filter((e=>r(e,o,t.schema)));for(const t of i)t.is("element",o)||e.rename(t,o)}))}}function r(e,t,n){return n.checkChild(e.parent,t)&&!n.isObject(e)}const s="paragraph";class d extends e.Plugin{static get pluginName(){return"HeadingEditing"}constructor(e){super(e),e.config.define("heading",{options:[{model:"paragraph",title:"Paragraph",class:"ck-heading_paragraph"},{model:"heading1",view:"h2",title:"Heading 1",class:"ck-heading_heading1"},{model:"heading2",view:"h3",title:"Heading 2",class:"ck-heading_heading2"},{model:"heading3",view:"h4",title:"Heading 3",class:"ck-heading_heading3"}]})}static get requires(){return[t.Paragraph]}init(){const e=this.editor,t=e.config.get("heading.options"),n=[];for(const o of t)"paragraph"!==o.model&&(e.model.schema.register(o.model,{inheritAllFrom:"$block"}),e.conversion.elementToElement(o),n.push(o.model));this._addDefaultH1Conversion(e),e.commands.add("heading",new a(e,n))}afterInit(){const e=this.editor,t=e.commands.get("enter"),n=e.config.get("heading.options");t&&this.listenTo(t,"afterExecute",((t,o)=>{const i=e.model.document.selection.getFirstPosition().parent;n.some((e=>i.is("element",e.model)))&&!i.is("element",s)&&0===i.childCount&&o.writer.rename(i,s)}))}_addDefaultH1Conversion(e){e.conversion.for("upcast").elementToElement({model:"heading1",view:"h1",converterPriority:i.priorities.low+1})}}var c=n(311);function l(e){const t=e.t,n={Paragraph:t("Paragraph"),"Heading 1":t("Heading 1"),"Heading 2":t("Heading 2"),"Heading 3":t("Heading 3"),"Heading 4":t("Heading 4"),"Heading 5":t("Heading 5"),"Heading 6":t("Heading 6")};return e.config.get("heading.options").map((e=>{const t=n[e.title];return t&&t!=e.title&&(e.title=t),e}))}var u=n(591),m=n.n(u),g=n(707),h={injectType:"singletonStyleTag",attributes:{"data-cke":!0},insert:"head",singleton:!0};m()(g.A,h);g.A.locals;class p extends e.Plugin{static get pluginName(){return"HeadingUI"}init(){const e=this.editor,t=e.t,n=l(e),o=t("Choose heading"),a=t("Heading");e.ui.componentFactory.add("heading",(t=>{const r={},s=new i.Collection,d=e.commands.get("heading"),l=e.commands.get("paragraph"),u=[d];for(const e of n){const t={type:"button",model:new c.ViewModel({label:e.title,class:e.class,role:"menuitemradio",withText:!0})};"paragraph"===e.model?(t.model.bind("isOn").to(l,"value"),t.model.set("commandName","paragraph"),u.push(l)):(t.model.bind("isOn").to(d,"value",(t=>t===e.model)),t.model.set({commandName:"heading",commandValue:e.model})),s.add(t),r[e.model]=e.title}const m=(0,c.createDropdown)(t);return(0,c.addListToDropdown)(m,s,{ariaLabel:a,role:"menu"}),m.buttonView.set({ariaLabel:a,ariaLabelledBy:void 0,isOn:!1,withText:!0,tooltip:a}),m.extendTemplate({attributes:{class:["ck-heading-dropdown"]}}),m.bind("isEnabled").toMany(u,"isEnabled",((...e)=>e.some((e=>e)))),m.buttonView.bind("label").to(d,"value",l,"value",((e,t)=>{const n=t?"paragraph":e;return"boolean"==typeof n?o:r[n]?r[n]:o})),m.buttonView.bind("ariaLabel").to(d,"value",l,"value",((e,t)=>{const n=t?"paragraph":e;return"boolean"==typeof n?a:r[n]?`${r[n]}, ${a}`:a})),this.listenTo(m,"execute",(t=>{const{commandName:n,commandValue:o}=t.source;e.execute(n,o?{value:o}:void 0),e.editing.view.focus()})),m})),e.ui.componentFactory.add("menuBar:heading",(o=>{const i=new c.MenuBarMenuView(o),a=e.commands.get("heading"),r=e.commands.get("paragraph"),s=[a],d=new c.MenuBarMenuListView(o);i.set({class:"ck-heading-dropdown"}),d.set({ariaLabel:t("Heading"),role:"menu"}),i.buttonView.set({label:t("Heading")}),i.panelView.children.add(d);for(const t of n){const n=new c.MenuBarMenuListItemView(o,i),l=new c.MenuBarMenuListItemButtonView(o);n.children.add(l),d.items.add(n),l.set({label:t.title,role:"menuitemradio",class:t.class}),l.bind("ariaChecked").to(l,"isOn"),l.delegate("execute").to(i),l.on("execute",(()=>{const n="paragraph"===t.model?"paragraph":"heading";e.execute(n,{value:t.model}),e.editing.view.focus()})),"paragraph"===t.model?(l.bind("isOn").to(r,"value"),s.push(r)):l.bind("isOn").to(a,"value",(e=>e===t.model))}return i.bind("isEnabled").toMany(s,"isEnabled",((...e)=>e.some((e=>e)))),i}))}}class f extends e.Plugin{static get requires(){return[d,p]}static get pluginName(){return"Heading"}}const v={heading1:e.icons.heading1,heading2:e.icons.heading2,heading3:e.icons.heading3,heading4:e.icons.heading4,heading5:e.icons.heading5,heading6:e.icons.heading6};class w extends e.Plugin{init(){l(this.editor).filter((e=>"paragraph"!==e.model)).map((e=>this._createButton(e)))}_createButton(e){const t=this.editor;t.ui.componentFactory.add(e.model,(n=>{const o=new c.ButtonView(n),i=t.commands.get("heading");return o.label=e.title,o.icon=e.icon||v[e.model],o.tooltip=!0,o.isToggleable=!0,o.bind("isEnabled").to(i),o.bind("isOn").to(i,"value",(t=>t==e.model)),o.on("execute",(()=>{t.execute("heading",{value:e.model}),t.editing.view.focus()})),o}))}}var b=n(783);const y=new Set(["paragraph","heading1","heading2","heading3","heading4","heading5","heading6"]);class x extends e.Plugin{constructor(){super(...arguments),this._bodyPlaceholder=new Map}static get pluginName(){return"Title"}static get requires(){return["Paragraph"]}init(){const e=this.editor,t=e.model;t.schema.register("title",{isBlock:!0,allowIn:"$root"}),t.schema.register("title-content",{isBlock:!0,allowIn:"title",allowAttributes:["alignment"]}),t.schema.extend("$text",{allowIn:"title-content"}),t.schema.addAttributeCheck((e=>{if(e.endsWith("title-content $text"))return!1})),e.editing.mapper.on("modelToViewPosition",T(e.editing.view)),e.data.mapper.on("modelToViewPosition",T(e.editing.view)),e.conversion.for("downcast").elementToElement({model:"title-content",view:"h1"}),e.conversion.for("downcast").add((e=>e.on("insert:title",((e,t,n)=>{n.consumable.consume(t.item,e.name)})))),e.data.upcastDispatcher.on("element:h1",C,{priority:"high"}),e.data.upcastDispatcher.on("element:h2",C,{priority:"high"}),e.data.upcastDispatcher.on("element:h3",C,{priority:"high"}),t.document.registerPostFixer((e=>this._fixTitleContent(e))),t.document.registerPostFixer((e=>this._fixTitleElement(e))),t.document.registerPostFixer((e=>this._fixBodyElement(e))),t.document.registerPostFixer((e=>this._fixExtraParagraph(e))),this._attachPlaceholders(),this._attachTabPressHandling()}getTitle(e={}){const t=e.rootName?e.rootName:void 0,n=this._getTitleElement(t).getChild(0);return this.editor.data.stringify(n,e)}getBody(e={}){const t=this.editor,n=t.data,o=t.model,i=e.rootName?e.rootName:void 0,a=t.model.document.getRoot(i),r=t.editing.view,s=new b.DowncastWriter(r.document),d=o.createRangeIn(a),c=s.createDocumentFragment(),l=o.createPositionAfter(a.getChild(0)),u=o.createRange(l,o.createPositionAt(a,"end")),m=new Map;for(const e of o.markers){const t=u.getIntersection(e.getRange());t&&m.set(e.name,t)}return n.mapper.clearBindings(),n.mapper.bindElements(a,c),n.downcastDispatcher.convert(d,m,s,e),s.remove(s.createRangeOn(c.getChild(0))),t.data.processor.toData(c)}_getTitleElement(e){const t=this.editor.model.document.getRoot(e);for(const e of t.getChildren())if(P(e))return e}_fixTitleContent(e){let t=!1;for(const n of this.editor.model.document.getRootNames()){const o=this._getTitleElement(n);if(!o||1===o.maxOffset)continue;const i=Array.from(o.getChildren());i.shift();for(const t of i)e.move(e.createRangeOn(t),o,"after"),e.rename(t,"paragraph");t=!0}return t}_fixTitleElement(e){let t=!1;const n=this.editor.model;for(const o of this.editor.model.document.getRoots()){const i=Array.from(o.getChildren()).filter(P),a=i[0],r=o.getChild(0);if(r.is("element","title"))i.length>1&&(H(i,e,n),t=!0);else if(a||y.has(r.name))y.has(r.name)?E(r,e,n):e.move(e.createRangeOn(a),o,0),H(i,e,n),t=!0;else{const n=e.createElement("title");e.insert(n,o),e.insertElement("title-content",n),t=!0}}return t}_fixBodyElement(e){let t=!1;for(const n of this.editor.model.document.getRootNames()){const o=this.editor.model.document.getRoot(n);if(o.childCount<2){const i=e.createElement("paragraph");e.insert(i,o,1),this._bodyPlaceholder.set(n,i),t=!0}}return t}_fixExtraParagraph(e){let t=!1;for(const n of this.editor.model.document.getRootNames()){const o=this.editor.model.document.getRoot(n),i=this._bodyPlaceholder.get(n);k(i,o)&&(this._bodyPlaceholder.delete(n),e.remove(i),t=!0)}return t}_attachPlaceholders(){const e=this.editor,t=e.t,n=e.editing.view,o=e.sourceElement,i=e.config.get("title.placeholder")||t("Type your title"),a=e.config.get("placeholder")||o&&"textarea"===o.tagName.toLowerCase()&&o.getAttribute("placeholder")||t("Type or paste your content here.");e.editing.downcastDispatcher.on("insert:title-content",((e,t,o)=>{const a=o.mapper.toViewElement(t.item);a.placeholder=i,(0,b.enablePlaceholder)({view:n,element:a,keepOnFocus:!0})}));const r=new Map;n.document.registerPostFixer((e=>{let t=!1;for(const o of n.document.roots){if(o.isEmpty)continue;const n=o.getChild(1),i=r.get(o.rootName);n!==i&&(i&&((0,b.hidePlaceholder)(e,i),e.removeAttribute("data-placeholder",i)),e.setAttribute("data-placeholder",a,n),r.set(o.rootName,n),t=!0),t=(0,b.needsPlaceholder)(n,!0)&&2===o.childCount&&"p"===n.name?!!(0,b.showPlaceholder)(e,n)||t:!!(0,b.hidePlaceholder)(e,n)||t}return t}))}_attachTabPressHandling(){const e=this.editor,t=e.model;e.keystrokes.set("TAB",((e,n)=>{t.change((e=>{const o=t.document.selection,i=Array.from(o.getSelectedBlocks());if(1===i.length&&i[0].is("element","title-content")){const t=o.getFirstPosition().root.getChild(1);e.setSelection(t,0),n()}}))})),e.keystrokes.set("SHIFT + TAB",((n,o)=>{t.change((n=>{const a=t.document.selection;if(!a.isCollapsed)return;const r=(0,i.first)(a.getSelectedBlocks()),s=a.getFirstPosition(),d=e.model.document.getRoot(s.root.rootName),c=d.getChild(0);r===d.getChild(1)&&s.isAtStart&&(n.setSelection(c.getChild(0),0),o())}))}))}}function C(e,t,n){const o=t.modelCursor,i=t.viewItem;if(!o.isAtStart||!o.parent.is("element","$root"))return;if(!n.consumable.consume(i,{name:!0}))return;const a=n.writer,r=a.createElement("title"),s=a.createElement("title-content");a.append(s,r),a.insert(r,o),n.convertChildren(i,s),n.updateConversionResult(r,t)}function T(e){return(t,n)=>{const o=n.modelPosition.parent;if(!o.is("element","title"))return;const i=o.parent,a=n.mapper.toViewElement(i);n.viewPosition=e.createPositionAt(a,0),t.stop()}}function P(e){return e.is("element","title")}function E(e,t,n){const o=t.createElement("title");t.insert(o,e,"before"),t.insert(e,o,0),t.rename(e,"title-content"),n.schema.removeDisallowedAttributes([e],t)}function H(e,t,n){let o=!1;for(const i of e)0!==i.index&&(_(i,t,n),o=!0);return o}function _(e,t,n){const o=e.getChild(0);o.isEmpty?t.remove(e):(t.move(t.createRangeOn(o),e,"before"),t.rename(o,"paragraph"),t.remove(e),n.schema.removeDisallowedAttributes([o],t))}function k(e,t){return!(!e||!e.is("element","paragraph")||e.childCount)&&!(t.childCount<=2||t.getChild(t.childCount-1)!==e)}})(),(window.CKEditor5=window.CKEditor5||{}).heading=o})();
5
+ */(()=>{var e={707:(e,t,n)=>{"use strict";n.d(t,{A:()=>a});var o=n(935),i=n.n(o)()((function(e){return e[1]}));i.push([e.id,".ck.ck-heading_heading1{font-size:20px}.ck.ck-heading_heading2{font-size:17px}.ck.ck-heading_heading3{font-size:14px}.ck[class*=ck-heading_heading]{font-weight:700}.ck.ck-dropdown.ck-heading-dropdown .ck-dropdown__button .ck-button__label{width:8em}.ck.ck-dropdown.ck-heading-dropdown .ck-dropdown__panel .ck-list__item{min-width:18em}",""]);const a=i},935:e=>{"use strict";e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var n=e(t);return t[2]?"@media ".concat(t[2]," {").concat(n,"}"):n})).join("")},t.i=function(e,n,o){"string"==typeof e&&(e=[[null,e,""]]);var i={};if(o)for(var a=0;a<this.length;a++){var r=this[a][0];null!=r&&(i[r]=!0)}for(var s=0;s<e.length;s++){var d=[].concat(e[s]);o&&i[d[0]]||(n&&(d[2]?d[2]="".concat(n," and ").concat(d[2]):d[2]=n),t.push(d))}},t}},591:(e,t,n)=>{"use strict";var o,i=function(){return void 0===o&&(o=Boolean(window&&document&&document.all&&!window.atob)),o},a=function(){var e={};return function(t){if(void 0===e[t]){var n=document.querySelector(t);if(window.HTMLIFrameElement&&n instanceof window.HTMLIFrameElement)try{n=n.contentDocument.head}catch(e){n=null}e[t]=n}return e[t]}}(),r=[];function s(e){for(var t=-1,n=0;n<r.length;n++)if(r[n].identifier===e){t=n;break}return t}function d(e,t){for(var n={},o=[],i=0;i<e.length;i++){var a=e[i],d=t.base?a[0]+t.base:a[0],c=n[d]||0,l="".concat(d," ").concat(c);n[d]=c+1;var u=s(l),m={css:a[1],media:a[2],sourceMap:a[3]};-1!==u?(r[u].references++,r[u].updater(m)):r.push({identifier:l,updater:f(m,t),references:1}),o.push(l)}return o}function c(e){var t=document.createElement("style"),o=e.attributes||{};if(void 0===o.nonce){var i=n.nc;i&&(o.nonce=i)}if(Object.keys(o).forEach((function(e){t.setAttribute(e,o[e])})),"function"==typeof e.insert)e.insert(t);else{var r=a(e.insert||"head");if(!r)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");r.appendChild(t)}return t}var l,u=(l=[],function(e,t){return l[e]=t,l.filter(Boolean).join("\n")});function m(e,t,n,o){var i=n?"":o.media?"@media ".concat(o.media," {").concat(o.css,"}"):o.css;if(e.styleSheet)e.styleSheet.cssText=u(t,i);else{var a=document.createTextNode(i),r=e.childNodes;r[t]&&e.removeChild(r[t]),r.length?e.insertBefore(a,r[t]):e.appendChild(a)}}function g(e,t,n){var o=n.css,i=n.media,a=n.sourceMap;if(i?e.setAttribute("media",i):e.removeAttribute("media"),a&&"undefined"!=typeof btoa&&(o+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(a))))," */")),e.styleSheet)e.styleSheet.cssText=o;else{for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(o))}}var h=null,p=0;function f(e,t){var n,o,i;if(t.singleton){var a=p++;n=h||(h=c(t)),o=m.bind(null,n,a,!1),i=m.bind(null,n,a,!0)}else n=c(t),o=g.bind(null,n,t),i=function(){!function(e){if(null===e.parentNode)return!1;e.parentNode.removeChild(e)}(n)};return o(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap)return;o(e=t)}else i()}}e.exports=function(e,t){(t=t||{}).singleton||"boolean"==typeof t.singleton||(t.singleton=i());var n=d(e=e||[],t);return function(e){if(e=e||[],"[object Array]"===Object.prototype.toString.call(e)){for(var o=0;o<n.length;o++){var i=s(n[o]);r[i].references--}for(var a=d(e,t),c=0;c<n.length;c++){var l=s(n[c]);0===r[l].references&&(r[l].updater(),r.splice(l,1))}n=a}}}},782:(e,t,n)=>{e.exports=n(237)("./src/core.js")},783:(e,t,n)=>{e.exports=n(237)("./src/engine.js")},179:(e,t,n)=>{e.exports=n(237)("./src/paragraph.js")},311:(e,t,n)=>{e.exports=n(237)("./src/ui.js")},584:(e,t,n)=>{e.exports=n(237)("./src/utils.js")},237:e=>{"use strict";e.exports=CKEditor5.dll}},t={};function n(o){var i=t[o];if(void 0!==i)return i.exports;var a=t[o]={id:o,exports:{}};return e[o](a,a.exports,n),a.exports}n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var o in t)n.o(t,o)&&!n.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.nc=void 0;var o={};(()=>{"use strict";n.r(o),n.d(o,{Heading:()=>f,HeadingButtonsUI:()=>w,HeadingEditing:()=>d,HeadingUI:()=>p,Title:()=>x});var e=n(782),t=n(179),i=n(584);class a extends e.Command{constructor(e,t){super(e),this.modelElements=t}refresh(){const e=(0,i.first)(this.editor.model.document.selection.getSelectedBlocks());this.value=!!e&&this.modelElements.includes(e.name)&&e.name,this.isEnabled=!!e&&this.modelElements.some((t=>r(e,t,this.editor.model.schema)))}execute(e){const t=this.editor.model,n=t.document,o=e.value;t.change((e=>{const i=Array.from(n.selection.getSelectedBlocks()).filter((e=>r(e,o,t.schema)));for(const t of i)t.is("element",o)||e.rename(t,o)}))}}function r(e,t,n){return n.checkChild(e.parent,t)&&!n.isObject(e)}const s="paragraph";class d extends e.Plugin{static get pluginName(){return"HeadingEditing"}constructor(e){super(e),e.config.define("heading",{options:[{model:"paragraph",title:"Paragraph",class:"ck-heading_paragraph"},{model:"heading1",view:"h2",title:"Heading 1",class:"ck-heading_heading1"},{model:"heading2",view:"h3",title:"Heading 2",class:"ck-heading_heading2"},{model:"heading3",view:"h4",title:"Heading 3",class:"ck-heading_heading3"}]})}static get requires(){return[t.Paragraph]}init(){const e=this.editor,t=e.config.get("heading.options"),n=[];for(const o of t)"paragraph"!==o.model&&(e.model.schema.register(o.model,{inheritAllFrom:"$block"}),e.conversion.elementToElement(o),n.push(o.model));this._addDefaultH1Conversion(e),e.commands.add("heading",new a(e,n))}afterInit(){const e=this.editor,t=e.commands.get("enter"),n=e.config.get("heading.options");t&&this.listenTo(t,"afterExecute",((t,o)=>{const i=e.model.document.selection.getFirstPosition().parent;n.some((e=>i.is("element",e.model)))&&!i.is("element",s)&&0===i.childCount&&o.writer.rename(i,s)}))}_addDefaultH1Conversion(e){e.conversion.for("upcast").elementToElement({model:"heading1",view:"h1",converterPriority:i.priorities.low+1})}}var c=n(311);function l(e){const t=e.t,n={Paragraph:t("Paragraph"),"Heading 1":t("Heading 1"),"Heading 2":t("Heading 2"),"Heading 3":t("Heading 3"),"Heading 4":t("Heading 4"),"Heading 5":t("Heading 5"),"Heading 6":t("Heading 6")};return e.config.get("heading.options").map((e=>{const t=n[e.title];return t&&t!=e.title&&(e.title=t),e}))}var u=n(591),m=n.n(u),g=n(707),h={injectType:"singletonStyleTag",attributes:{"data-cke":!0},insert:"head",singleton:!0};m()(g.A,h);g.A.locals;class p extends e.Plugin{static get pluginName(){return"HeadingUI"}init(){const e=this.editor,t=e.t,n=l(e),o=t("Choose heading"),a=t("Heading");e.ui.componentFactory.add("heading",(t=>{const r={},s=new i.Collection,d=e.commands.get("heading"),l=e.commands.get("paragraph"),u=[d];for(const e of n){const t={type:"button",model:new c.ViewModel({label:e.title,class:e.class,role:"menuitemradio",withText:!0})};"paragraph"===e.model?(t.model.bind("isOn").to(l,"value"),t.model.set("commandName","paragraph"),u.push(l)):(t.model.bind("isOn").to(d,"value",(t=>t===e.model)),t.model.set({commandName:"heading",commandValue:e.model})),s.add(t),r[e.model]=e.title}const m=(0,c.createDropdown)(t);return(0,c.addListToDropdown)(m,s,{ariaLabel:a,role:"menu"}),m.buttonView.set({ariaLabel:a,ariaLabelledBy:void 0,isOn:!1,withText:!0,tooltip:a}),m.extendTemplate({attributes:{class:["ck-heading-dropdown"]}}),m.bind("isEnabled").toMany(u,"isEnabled",((...e)=>e.some((e=>e)))),m.buttonView.bind("label").to(d,"value",l,"value",((e,t)=>{const n=t?"paragraph":e;return"boolean"==typeof n?o:r[n]?r[n]:o})),m.buttonView.bind("ariaLabel").to(d,"value",l,"value",((e,t)=>{const n=t?"paragraph":e;return"boolean"==typeof n?a:r[n]?`${r[n]}, ${a}`:a})),this.listenTo(m,"execute",(t=>{const{commandName:n,commandValue:o}=t.source;e.execute(n,o?{value:o}:void 0),e.editing.view.focus()})),m})),e.ui.componentFactory.add("menuBar:heading",(o=>{const i=new c.MenuBarMenuView(o),a=e.commands.get("heading"),r=e.commands.get("paragraph"),s=[a],d=new c.MenuBarMenuListView(o);i.set({class:"ck-heading-dropdown"}),d.set({ariaLabel:t("Heading"),role:"menu"}),i.buttonView.set({label:t("Heading")}),i.panelView.children.add(d);for(const t of n){const n=new c.MenuBarMenuListItemView(o,i),l=new c.MenuBarMenuListItemButtonView(o);n.children.add(l),d.items.add(n),l.set({label:t.title,role:"menuitemradio",class:t.class}),l.bind("ariaChecked").to(l,"isOn"),l.delegate("execute").to(i),l.on("execute",(()=>{const n="paragraph"===t.model?"paragraph":"heading";e.execute(n,{value:t.model}),e.editing.view.focus()})),"paragraph"===t.model?(l.bind("isOn").to(r,"value"),s.push(r)):l.bind("isOn").to(a,"value",(e=>e===t.model))}return i.bind("isEnabled").toMany(s,"isEnabled",((...e)=>e.some((e=>e)))),i}))}}class f extends e.Plugin{static get requires(){return[d,p]}static get pluginName(){return"Heading"}}const v=(()=>({heading1:e.icons.heading1,heading2:e.icons.heading2,heading3:e.icons.heading3,heading4:e.icons.heading4,heading5:e.icons.heading5,heading6:e.icons.heading6}))();class w extends e.Plugin{init(){l(this.editor).filter((e=>"paragraph"!==e.model)).map((e=>this._createButton(e)))}_createButton(e){const t=this.editor;t.ui.componentFactory.add(e.model,(n=>{const o=new c.ButtonView(n),i=t.commands.get("heading");return o.label=e.title,o.icon=e.icon||v[e.model],o.tooltip=!0,o.isToggleable=!0,o.bind("isEnabled").to(i),o.bind("isOn").to(i,"value",(t=>t==e.model)),o.on("execute",(()=>{t.execute("heading",{value:e.model}),t.editing.view.focus()})),o}))}}var b=n(783);const y=new Set(["paragraph","heading1","heading2","heading3","heading4","heading5","heading6"]);class x extends e.Plugin{constructor(){super(...arguments),this._bodyPlaceholder=new Map}static get pluginName(){return"Title"}static get requires(){return["Paragraph"]}init(){const e=this.editor,t=e.model;t.schema.register("title",{isBlock:!0,allowIn:"$root"}),t.schema.register("title-content",{isBlock:!0,allowIn:"title",allowAttributes:["alignment"]}),t.schema.extend("$text",{allowIn:"title-content"}),t.schema.addAttributeCheck((e=>{if(e.endsWith("title-content $text"))return!1})),e.editing.mapper.on("modelToViewPosition",T(e.editing.view)),e.data.mapper.on("modelToViewPosition",T(e.editing.view)),e.conversion.for("downcast").elementToElement({model:"title-content",view:"h1"}),e.conversion.for("downcast").add((e=>e.on("insert:title",((e,t,n)=>{n.consumable.consume(t.item,e.name)})))),e.data.upcastDispatcher.on("element:h1",C,{priority:"high"}),e.data.upcastDispatcher.on("element:h2",C,{priority:"high"}),e.data.upcastDispatcher.on("element:h3",C,{priority:"high"}),t.document.registerPostFixer((e=>this._fixTitleContent(e))),t.document.registerPostFixer((e=>this._fixTitleElement(e))),t.document.registerPostFixer((e=>this._fixBodyElement(e))),t.document.registerPostFixer((e=>this._fixExtraParagraph(e))),this._attachPlaceholders(),this._attachTabPressHandling()}getTitle(e={}){const t=e.rootName?e.rootName:void 0,n=this._getTitleElement(t).getChild(0);return this.editor.data.stringify(n,e)}getBody(e={}){const t=this.editor,n=t.data,o=t.model,i=e.rootName?e.rootName:void 0,a=t.model.document.getRoot(i),r=t.editing.view,s=new b.DowncastWriter(r.document),d=o.createRangeIn(a),c=s.createDocumentFragment(),l=o.createPositionAfter(a.getChild(0)),u=o.createRange(l,o.createPositionAt(a,"end")),m=new Map;for(const e of o.markers){const t=u.getIntersection(e.getRange());t&&m.set(e.name,t)}return n.mapper.clearBindings(),n.mapper.bindElements(a,c),n.downcastDispatcher.convert(d,m,s,e),s.remove(s.createRangeOn(c.getChild(0))),t.data.processor.toData(c)}_getTitleElement(e){const t=this.editor.model.document.getRoot(e);for(const e of t.getChildren())if(P(e))return e}_fixTitleContent(e){let t=!1;for(const n of this.editor.model.document.getRootNames()){const o=this._getTitleElement(n);if(!o||1===o.maxOffset)continue;const i=Array.from(o.getChildren());i.shift();for(const t of i)e.move(e.createRangeOn(t),o,"after"),e.rename(t,"paragraph");t=!0}return t}_fixTitleElement(e){let t=!1;const n=this.editor.model;for(const o of this.editor.model.document.getRoots()){const i=Array.from(o.getChildren()).filter(P),a=i[0],r=o.getChild(0);if(r.is("element","title"))i.length>1&&(H(i,e,n),t=!0);else if(a||y.has(r.name))y.has(r.name)?E(r,e,n):e.move(e.createRangeOn(a),o,0),H(i,e,n),t=!0;else{const n=e.createElement("title");e.insert(n,o),e.insertElement("title-content",n),t=!0}}return t}_fixBodyElement(e){let t=!1;for(const n of this.editor.model.document.getRootNames()){const o=this.editor.model.document.getRoot(n);if(o.childCount<2){const i=e.createElement("paragraph");e.insert(i,o,1),this._bodyPlaceholder.set(n,i),t=!0}}return t}_fixExtraParagraph(e){let t=!1;for(const n of this.editor.model.document.getRootNames()){const o=this.editor.model.document.getRoot(n),i=this._bodyPlaceholder.get(n);k(i,o)&&(this._bodyPlaceholder.delete(n),e.remove(i),t=!0)}return t}_attachPlaceholders(){const e=this.editor,t=e.t,n=e.editing.view,o=e.sourceElement,i=e.config.get("title.placeholder")||t("Type your title"),a=e.config.get("placeholder")||o&&"textarea"===o.tagName.toLowerCase()&&o.getAttribute("placeholder")||t("Type or paste your content here.");e.editing.downcastDispatcher.on("insert:title-content",((e,t,o)=>{const a=o.mapper.toViewElement(t.item);a.placeholder=i,(0,b.enablePlaceholder)({view:n,element:a,keepOnFocus:!0})}));const r=new Map;n.document.registerPostFixer((e=>{let t=!1;for(const o of n.document.roots){if(o.isEmpty)continue;const n=o.getChild(1),i=r.get(o.rootName);n!==i&&(i&&((0,b.hidePlaceholder)(e,i),e.removeAttribute("data-placeholder",i)),e.setAttribute("data-placeholder",a,n),r.set(o.rootName,n),t=!0),t=(0,b.needsPlaceholder)(n,!0)&&2===o.childCount&&"p"===n.name?!!(0,b.showPlaceholder)(e,n)||t:!!(0,b.hidePlaceholder)(e,n)||t}return t}))}_attachTabPressHandling(){const e=this.editor,t=e.model;e.keystrokes.set("TAB",((e,n)=>{t.change((e=>{const o=t.document.selection,i=Array.from(o.getSelectedBlocks());if(1===i.length&&i[0].is("element","title-content")){const t=o.getFirstPosition().root.getChild(1);e.setSelection(t,0),n()}}))})),e.keystrokes.set("SHIFT + TAB",((n,o)=>{t.change((n=>{const a=t.document.selection;if(!a.isCollapsed)return;const r=(0,i.first)(a.getSelectedBlocks()),s=a.getFirstPosition(),d=e.model.document.getRoot(s.root.rootName),c=d.getChild(0);r===d.getChild(1)&&s.isAtStart&&(n.setSelection(c.getChild(0),0),o())}))}))}}function C(e,t,n){const o=t.modelCursor,i=t.viewItem;if(!o.isAtStart||!o.parent.is("element","$root"))return;if(!n.consumable.consume(i,{name:!0}))return;const a=n.writer,r=a.createElement("title"),s=a.createElement("title-content");a.append(s,r),a.insert(r,o),n.convertChildren(i,s),n.updateConversionResult(r,t)}function T(e){return(t,n)=>{const o=n.modelPosition.parent;if(!o.is("element","title"))return;const i=o.parent,a=n.mapper.toViewElement(i);n.viewPosition=e.createPositionAt(a,0),t.stop()}}function P(e){return e.is("element","title")}function E(e,t,n){const o=t.createElement("title");t.insert(o,e,"before"),t.insert(e,o,0),t.rename(e,"title-content"),n.schema.removeDisallowedAttributes([e],t)}function H(e,t,n){let o=!1;for(const i of e)0!==i.index&&(_(i,t,n),o=!0);return o}function _(e,t,n){const o=e.getChild(0);o.isEmpty?t.remove(e):(t.move(t.createRangeOn(o),e,"before"),t.rename(o,"paragraph"),t.remove(e),n.schema.removeDisallowedAttributes([o],t))}function k(e,t){return!(!e||!e.is("element","paragraph")||e.childCount)&&!(t.childCount<=2||t.getChild(t.childCount-1)!==e)}})(),(window.CKEditor5=window.CKEditor5||{}).heading=o})();
package/dist/index.js CHANGED
@@ -8,21 +8,36 @@ import { first, priorities, Collection } from '@ckeditor/ckeditor5-utils/dist/in
8
8
  import { ViewModel, createDropdown, addListToDropdown, MenuBarMenuView, MenuBarMenuListView, MenuBarMenuListItemView, MenuBarMenuListItemButtonView, ButtonView } from '@ckeditor/ckeditor5-ui/dist/index.js';
9
9
  import { DowncastWriter, enablePlaceholder, hidePlaceholder, needsPlaceholder, showPlaceholder } from '@ckeditor/ckeditor5-engine/dist/index.js';
10
10
 
11
- class HeadingCommand extends Command {
11
+ /**
12
+ * The heading command. It is used by the {@link module:heading/heading~Heading heading feature} to apply headings.
13
+ */ class HeadingCommand extends Command {
14
+ /**
15
+ * Set of defined model's elements names that this command support.
16
+ * See {@link module:heading/headingconfig~HeadingOption}.
17
+ */ modelElements;
18
+ /**
19
+ * Creates an instance of the command.
20
+ *
21
+ * @param editor Editor instance.
22
+ * @param modelElements Names of the element which this command can apply in the model.
23
+ */ constructor(editor, modelElements){
24
+ super(editor);
25
+ this.modelElements = modelElements;
26
+ }
12
27
  /**
13
- * @inheritDoc
14
- */ refresh() {
28
+ * @inheritDoc
29
+ */ refresh() {
15
30
  const block = first(this.editor.model.document.selection.getSelectedBlocks());
16
31
  this.value = !!block && this.modelElements.includes(block.name) && block.name;
17
32
  this.isEnabled = !!block && this.modelElements.some((heading)=>checkCanBecomeHeading(block, heading, this.editor.model.schema));
18
33
  }
19
34
  /**
20
- * Executes the command. Applies the heading to the selected blocks or, if the first selected
21
- * block is a heading already, turns selected headings (of this level only) to paragraphs.
22
- *
23
- * @param options.value Name of the element which this command will apply in the model.
24
- * @fires execute
25
- */ execute(options) {
35
+ * Executes the command. Applies the heading to the selected blocks or, if the first selected
36
+ * block is a heading already, turns selected headings (of this level only) to paragraphs.
37
+ *
38
+ * @param options.value Name of the element which this command will apply in the model.
39
+ * @fires execute
40
+ */ execute(options) {
26
41
  const model = this.editor.model;
27
42
  const document = model.document;
28
43
  const modelElement = options.value;
@@ -37,15 +52,6 @@ class HeadingCommand extends Command {
37
52
  }
38
53
  });
39
54
  }
40
- /**
41
- * Creates an instance of the command.
42
- *
43
- * @param editor Editor instance.
44
- * @param modelElements Names of the element which this command can apply in the model.
45
- */ constructor(editor, modelElements){
46
- super(editor);
47
- this.modelElements = modelElements;
48
- }
49
55
  }
50
56
  /**
51
57
  * Checks whether the given block can be replaced by a specific heading.
@@ -58,22 +64,58 @@ class HeadingCommand extends Command {
58
64
  }
59
65
 
60
66
  const defaultModelElement = 'paragraph';
61
- class HeadingEditing extends Plugin {
67
+ /**
68
+ * The headings engine feature. It handles switching between block formats &ndash; headings and paragraph.
69
+ * This class represents the engine part of the heading feature. See also {@link module:heading/heading~Heading}.
70
+ * It introduces `heading1`-`headingN` commands which allow to convert paragraphs into headings.
71
+ */ class HeadingEditing extends Plugin {
62
72
  /**
63
- * @inheritDoc
64
- */ static get pluginName() {
73
+ * @inheritDoc
74
+ */ static get pluginName() {
65
75
  return 'HeadingEditing';
66
76
  }
67
77
  /**
68
- * @inheritDoc
69
- */ static get requires() {
78
+ * @inheritDoc
79
+ */ constructor(editor){
80
+ super(editor);
81
+ editor.config.define('heading', {
82
+ options: [
83
+ {
84
+ model: 'paragraph',
85
+ title: 'Paragraph',
86
+ class: 'ck-heading_paragraph'
87
+ },
88
+ {
89
+ model: 'heading1',
90
+ view: 'h2',
91
+ title: 'Heading 1',
92
+ class: 'ck-heading_heading1'
93
+ },
94
+ {
95
+ model: 'heading2',
96
+ view: 'h3',
97
+ title: 'Heading 2',
98
+ class: 'ck-heading_heading2'
99
+ },
100
+ {
101
+ model: 'heading3',
102
+ view: 'h4',
103
+ title: 'Heading 3',
104
+ class: 'ck-heading_heading3'
105
+ }
106
+ ]
107
+ });
108
+ }
109
+ /**
110
+ * @inheritDoc
111
+ */ static get requires() {
70
112
  return [
71
113
  Paragraph
72
114
  ];
73
115
  }
74
116
  /**
75
- * @inheritDoc
76
- */ init() {
117
+ * @inheritDoc
118
+ */ init() {
77
119
  const editor = this.editor;
78
120
  const options = editor.config.get('heading.options');
79
121
  const modelElements = [];
@@ -94,8 +136,8 @@ class HeadingEditing extends Plugin {
94
136
  editor.commands.add('heading', new HeadingCommand(editor, modelElements));
95
137
  }
96
138
  /**
97
- * @inheritDoc
98
- */ afterInit() {
139
+ * @inheritDoc
140
+ */ afterInit() {
99
141
  // If the enter command is added to the editor, alter its behavior.
100
142
  // Enter at the end of a heading element should create a paragraph.
101
143
  const editor = this.editor;
@@ -112,10 +154,10 @@ class HeadingEditing extends Plugin {
112
154
  }
113
155
  }
114
156
  /**
115
- * Adds default conversion for `h1` -> `heading1` with a low priority.
116
- *
117
- * @param editor Editor instance on which to add the `h1` conversion.
118
- */ _addDefaultH1Conversion(editor) {
157
+ * Adds default conversion for `h1` -> `heading1` with a low priority.
158
+ *
159
+ * @param editor Editor instance on which to add the `h1` conversion.
160
+ */ _addDefaultH1Conversion(editor) {
119
161
  editor.conversion.for('upcast').elementToElement({
120
162
  model: 'heading1',
121
163
  view: 'h1',
@@ -124,44 +166,14 @@ class HeadingEditing extends Plugin {
124
166
  converterPriority: priorities.low + 1
125
167
  });
126
168
  }
127
- /**
128
- * @inheritDoc
129
- */ constructor(editor){
130
- super(editor);
131
- editor.config.define('heading', {
132
- options: [
133
- {
134
- model: 'paragraph',
135
- title: 'Paragraph',
136
- class: 'ck-heading_paragraph'
137
- },
138
- {
139
- model: 'heading1',
140
- view: 'h2',
141
- title: 'Heading 1',
142
- class: 'ck-heading_heading1'
143
- },
144
- {
145
- model: 'heading2',
146
- view: 'h3',
147
- title: 'Heading 2',
148
- class: 'ck-heading_heading2'
149
- },
150
- {
151
- model: 'heading3',
152
- view: 'h4',
153
- title: 'Heading 3',
154
- class: 'ck-heading_heading3'
155
- }
156
- ]
157
- });
158
- }
159
169
  }
160
170
 
161
171
  /**
162
172
  * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
163
173
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
164
174
  */ /**
175
+ * @module heading/utils
176
+ */ /**
165
177
  * Returns heading options as defined in `config.heading.options` but processed to consider
166
178
  * the editor localization, i.e. to display {@link module:heading/headingconfig~HeadingOption}
167
179
  * in the correct language.
@@ -188,15 +200,17 @@ class HeadingEditing extends Plugin {
188
200
  });
189
201
  }
190
202
 
191
- class HeadingUI extends Plugin {
203
+ /**
204
+ * The headings UI feature. It introduces the `headings` dropdown.
205
+ */ class HeadingUI extends Plugin {
192
206
  /**
193
- * @inheritDoc
194
- */ static get pluginName() {
207
+ * @inheritDoc
208
+ */ static get pluginName() {
195
209
  return 'HeadingUI';
196
210
  }
197
211
  /**
198
- * @inheritDoc
199
- */ init() {
212
+ * @inheritDoc
213
+ */ init() {
200
214
  const editor = this.editor;
201
215
  const t = editor.t;
202
216
  const options = getLocalizedOptions(editor);
@@ -343,40 +357,82 @@ class HeadingUI extends Plugin {
343
357
  }
344
358
  }
345
359
 
346
- class Heading extends Plugin {
360
+ /**
361
+ * The headings feature.
362
+ *
363
+ * For a detailed overview, check the {@glink features/headings Headings feature} guide
364
+ * and the {@glink api/heading package page}.
365
+ *
366
+ * This is a "glue" plugin which loads the {@link module:heading/headingediting~HeadingEditing heading editing feature}
367
+ * and {@link module:heading/headingui~HeadingUI heading UI feature}.
368
+ *
369
+ * @extends module:core/plugin~Plugin
370
+ */ class Heading extends Plugin {
347
371
  /**
348
- * @inheritDoc
349
- */ static get requires() {
372
+ * @inheritDoc
373
+ */ static get requires() {
350
374
  return [
351
375
  HeadingEditing,
352
376
  HeadingUI
353
377
  ];
354
378
  }
355
379
  /**
356
- * @inheritDoc
357
- */ static get pluginName() {
380
+ * @inheritDoc
381
+ */ static get pluginName() {
358
382
  return 'Heading';
359
383
  }
360
384
  }
361
385
 
362
- const defaultIcons = {
363
- heading1: icons.heading1,
364
- heading2: icons.heading2,
365
- heading3: icons.heading3,
366
- heading4: icons.heading4,
367
- heading5: icons.heading5,
368
- heading6: icons.heading6
369
- };
370
- class HeadingButtonsUI extends Plugin {
386
+ const defaultIcons = /* #__PURE__ */ (()=>({
387
+ heading1: icons.heading1,
388
+ heading2: icons.heading2,
389
+ heading3: icons.heading3,
390
+ heading4: icons.heading4,
391
+ heading5: icons.heading5,
392
+ heading6: icons.heading6
393
+ }))();
394
+ /**
395
+ * The `HeadingButtonsUI` plugin defines a set of UI buttons that can be used instead of the
396
+ * standard drop down component.
397
+ *
398
+ * This feature is not enabled by default by the {@link module:heading/heading~Heading} plugin and needs to be
399
+ * installed manually to the editor configuration.
400
+ *
401
+ * Plugin introduces button UI elements, which names are same as `model` property from {@link module:heading/headingconfig~HeadingOption}.
402
+ *
403
+ * ```ts
404
+ * ClassicEditor
405
+ * .create( {
406
+ * plugins: [ ..., Heading, Paragraph, HeadingButtonsUI, ParagraphButtonUI ]
407
+ * heading: {
408
+ * options: [
409
+ * { model: 'paragraph', title: 'Paragraph', class: 'ck-heading_paragraph' },
410
+ * { model: 'heading1', view: 'h2', title: 'Heading 1', class: 'ck-heading_heading1' },
411
+ * { model: 'heading2', view: 'h3', title: 'Heading 2', class: 'ck-heading_heading2' },
412
+ * { model: 'heading3', view: 'h4', title: 'Heading 3', class: 'ck-heading_heading3' }
413
+ * ]
414
+ * },
415
+ * toolbar: [ 'paragraph', 'heading1', 'heading2', 'heading3' ]
416
+ * } )
417
+ * .then( ... )
418
+ * .catch( ... );
419
+ * ```
420
+ *
421
+ * NOTE: The `'paragraph'` button is defined in by the {@link module:paragraph/paragraphbuttonui~ParagraphButtonUI} plugin
422
+ * which needs to be loaded manually as well.
423
+ *
424
+ * It is possible to use custom icons by providing `icon` config option in {@link module:heading/headingconfig~HeadingOption}.
425
+ * For the default configuration standard icons are used.
426
+ */ class HeadingButtonsUI extends Plugin {
371
427
  /**
372
- * @inheritDoc
373
- */ init() {
428
+ * @inheritDoc
429
+ */ init() {
374
430
  const options = getLocalizedOptions(this.editor);
375
431
  options.filter((item)=>item.model !== 'paragraph').map((item)=>this._createButton(item));
376
432
  }
377
433
  /**
378
- * Creates single button view from provided configuration option.
379
- */ _createButton(option) {
434
+ * Creates single button view from provided configuration option.
435
+ */ _createButton(option) {
380
436
  const editor = this.editor;
381
437
  editor.ui.componentFactory.add(option.model, (locale)=>{
382
438
  const view = new ButtonView(locale);
@@ -410,22 +466,30 @@ const titleLikeElements = new Set([
410
466
  'heading5',
411
467
  'heading6'
412
468
  ]);
413
- class Title extends Plugin {
469
+ /**
470
+ * The Title plugin.
471
+ *
472
+ * It splits the document into `Title` and `Body` sections.
473
+ */ class Title extends Plugin {
414
474
  /**
415
- * @inheritDoc
416
- */ static get pluginName() {
475
+ * A reference to an empty paragraph in the body
476
+ * created when there is no element in the body for the placeholder purposes.
477
+ */ _bodyPlaceholder = new Map();
478
+ /**
479
+ * @inheritDoc
480
+ */ static get pluginName() {
417
481
  return 'Title';
418
482
  }
419
483
  /**
420
- * @inheritDoc
421
- */ static get requires() {
484
+ * @inheritDoc
485
+ */ static get requires() {
422
486
  return [
423
487
  'Paragraph'
424
488
  ];
425
489
  }
426
490
  /**
427
- * @inheritDoc
428
- */ init() {
491
+ * @inheritDoc
492
+ */ init() {
429
493
  const editor = this.editor;
430
494
  const model = editor.model;
431
495
  // To use the schema for disabling some features when the selection is inside the title element
@@ -493,33 +557,33 @@ class Title extends Plugin {
493
557
  this._attachTabPressHandling();
494
558
  }
495
559
  /**
496
- * Returns the title of the document. Note that because this plugin does not allow any formatting inside
497
- * the title element, the output of this method will be a plain text, with no HTML tags.
498
- *
499
- * It is not recommended to use this method together with features that insert markers to the
500
- * data output, like comments or track changes features. If such markers start in the title and end in the
501
- * body, the result of this method might be incorrect.
502
- *
503
- * @param options Additional configuration passed to the conversion process.
504
- * See {@link module:engine/controller/datacontroller~DataController#get `DataController#get`}.
505
- * @returns The title of the document.
506
- */ getTitle(options = {}) {
560
+ * Returns the title of the document. Note that because this plugin does not allow any formatting inside
561
+ * the title element, the output of this method will be a plain text, with no HTML tags.
562
+ *
563
+ * It is not recommended to use this method together with features that insert markers to the
564
+ * data output, like comments or track changes features. If such markers start in the title and end in the
565
+ * body, the result of this method might be incorrect.
566
+ *
567
+ * @param options Additional configuration passed to the conversion process.
568
+ * See {@link module:engine/controller/datacontroller~DataController#get `DataController#get`}.
569
+ * @returns The title of the document.
570
+ */ getTitle(options = {}) {
507
571
  const rootName = options.rootName ? options.rootName : undefined;
508
572
  const titleElement = this._getTitleElement(rootName);
509
573
  const titleContentElement = titleElement.getChild(0);
510
574
  return this.editor.data.stringify(titleContentElement, options);
511
575
  }
512
576
  /**
513
- * Returns the body of the document.
514
- *
515
- * Note that it is not recommended to use this method together with features that insert markers to the
516
- * data output, like comments or track changes features. If such markers start in the title and end in the
517
- * body, the result of this method might be incorrect.
518
- *
519
- * @param options Additional configuration passed to the conversion process.
520
- * See {@link module:engine/controller/datacontroller~DataController#get `DataController#get`}.
521
- * @returns The body of the document.
522
- */ getBody(options = {}) {
577
+ * Returns the body of the document.
578
+ *
579
+ * Note that it is not recommended to use this method together with features that insert markers to the
580
+ * data output, like comments or track changes features. If such markers start in the title and end in the
581
+ * body, the result of this method might be incorrect.
582
+ *
583
+ * @param options Additional configuration passed to the conversion process.
584
+ * See {@link module:engine/controller/datacontroller~DataController#get `DataController#get`}.
585
+ * @returns The body of the document.
586
+ */ getBody(options = {}) {
523
587
  const editor = this.editor;
524
588
  const data = editor.data;
525
589
  const model = editor.model;
@@ -549,8 +613,8 @@ class Title extends Plugin {
549
613
  return editor.data.processor.toData(viewDocumentFragment);
550
614
  }
551
615
  /**
552
- * Returns the `title` element when it is in the document. Returns `undefined` otherwise.
553
- */ _getTitleElement(rootName) {
616
+ * Returns the `title` element when it is in the document. Returns `undefined` otherwise.
617
+ */ _getTitleElement(rootName) {
554
618
  const root = this.editor.model.document.getRoot(rootName);
555
619
  for (const child of root.getChildren()){
556
620
  if (isTitle(child)) {
@@ -559,9 +623,9 @@ class Title extends Plugin {
559
623
  }
560
624
  }
561
625
  /**
562
- * Model post-fixer callback that ensures that `title` has only one `title-content` child.
563
- * All additional children should be moved after the `title` element and renamed to a paragraph.
564
- */ _fixTitleContent(writer) {
626
+ * Model post-fixer callback that ensures that `title` has only one `title-content` child.
627
+ * All additional children should be moved after the `title` element and renamed to a paragraph.
628
+ */ _fixTitleContent(writer) {
565
629
  let changed = false;
566
630
  for (const rootName of this.editor.model.document.getRootNames()){
567
631
  const title = this._getTitleElement(rootName);
@@ -582,9 +646,9 @@ class Title extends Plugin {
582
646
  return changed;
583
647
  }
584
648
  /**
585
- * Model post-fixer callback that creates a title element when it is missing,
586
- * takes care of the correct position of it and removes additional title elements.
587
- */ _fixTitleElement(writer) {
649
+ * Model post-fixer callback that creates a title element when it is missing,
650
+ * takes care of the correct position of it and removes additional title elements.
651
+ */ _fixTitleElement(writer) {
588
652
  let changed = false;
589
653
  const model = this.editor.model;
590
654
  for (const modelRoot of this.editor.model.document.getRoots()){
@@ -621,9 +685,9 @@ class Title extends Plugin {
621
685
  return changed;
622
686
  }
623
687
  /**
624
- * Model post-fixer callback that adds an empty paragraph at the end of the document
625
- * when it is needed for the placeholder purposes.
626
- */ _fixBodyElement(writer) {
688
+ * Model post-fixer callback that adds an empty paragraph at the end of the document
689
+ * when it is needed for the placeholder purposes.
690
+ */ _fixBodyElement(writer) {
627
691
  let changed = false;
628
692
  for (const rootName of this.editor.model.document.getRootNames()){
629
693
  const modelRoot = this.editor.model.document.getRoot(rootName);
@@ -637,9 +701,9 @@ class Title extends Plugin {
637
701
  return changed;
638
702
  }
639
703
  /**
640
- * Model post-fixer callback that removes a paragraph from the end of the document
641
- * if it was created for the placeholder purposes and is not needed anymore.
642
- */ _fixExtraParagraph(writer) {
704
+ * Model post-fixer callback that removes a paragraph from the end of the document
705
+ * if it was created for the placeholder purposes and is not needed anymore.
706
+ */ _fixExtraParagraph(writer) {
643
707
  let changed = false;
644
708
  for (const rootName of this.editor.model.document.getRootNames()){
645
709
  const root = this.editor.model.document.getRoot(rootName);
@@ -653,8 +717,8 @@ class Title extends Plugin {
653
717
  return changed;
654
718
  }
655
719
  /**
656
- * Attaches the `Title` and `Body` placeholders to the title and/or content.
657
- */ _attachPlaceholders() {
720
+ * Attaches the `Title` and `Body` placeholders to the title and/or content.
721
+ */ _attachPlaceholders() {
658
722
  const editor = this.editor;
659
723
  const t = editor.t;
660
724
  const view = editor.editing.view;
@@ -708,8 +772,8 @@ class Title extends Plugin {
708
772
  });
709
773
  }
710
774
  /**
711
- * Creates navigation between the title and body sections using <kbd>Tab</kbd> and <kbd>Shift</kbd>+<kbd>Tab</kbd> keys.
712
- */ _attachTabPressHandling() {
775
+ * Creates navigation between the title and body sections using <kbd>Tab</kbd> and <kbd>Shift</kbd>+<kbd>Tab</kbd> keys.
776
+ */ _attachTabPressHandling() {
713
777
  const editor = this.editor;
714
778
  const model = editor.model;
715
779
  // Pressing <kbd>Tab</kbd> inside the title should move the caret to the body.
@@ -744,13 +808,6 @@ class Title extends Plugin {
744
808
  });
745
809
  });
746
810
  }
747
- constructor(){
748
- super(...arguments);
749
- /**
750
- * A reference to an empty paragraph in the body
751
- * created when there is no element in the body for the placeholder purposes.
752
- */ this._bodyPlaceholder = new Map();
753
- }
754
811
  }
755
812
  /**
756
813
  * A view-to-model converter for the h1 that appears at the beginning of the document (a title element).