@ckeditor/ckeditor5-style
Advanced tools
Comparing version 36.0.1 to 37.0.0-alpha.0
@@ -5,2 +5,2 @@ !function(e){const t=e.en=e.en||{};t.dictionary=Object.assign(t.dictionary||{},{"Block styles":"Block styles","Multiple styles":"Multiple styles",Styles:"Styles","Text styles":"Text styles"})}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={})), | ||
* For licensing, see LICENSE.md. | ||
*/(()=>{var e={529:(e,t,s)=>{"use strict";s.d(t,{Z:()=>l});var i=s(609),n=s.n(i)()((function(e){return e[1]}));n.push([e.id,".ck.ck-dropdown.ck-style-dropdown.ck-style-dropdown_multiple-active>.ck-button>.ck-button__label{font-style:italic}",""]);const l=n},945:(e,t,s)=>{"use strict";s.d(t,{Z:()=>l});var i=s(609),n=s.n(i)()((function(e){return e[1]}));n.push([e.id,":root{--ck-style-panel-columns:3}.ck.ck-style-panel .ck-style-grid{display:grid;grid-template-columns:repeat(var(--ck-style-panel-columns),auto);justify-content:start}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button{display:flex;flex-direction:column;justify-content:space-between}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button .ck-style-grid__button__preview{align-content:center;align-items:center;display:flex;flex-basis:100%;flex-grow:1;justify-content:flex-start}:root{--ck-style-panel-button-width:120px;--ck-style-panel-button-height:80px;--ck-style-panel-button-label-background:#f0f0f0;--ck-style-panel-button-hover-label-background:#ebebeb;--ck-style-panel-button-hover-border-color:#b3b3b3}.ck.ck-style-panel .ck-style-grid{column-gap:var(--ck-spacing-large);row-gap:var(--ck-spacing-large)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button{--ck-color-button-default-hover-background:var(--ck-color-base-background);--ck-color-button-default-active-background:var(--ck-color-base-background);height:var(--ck-style-panel-button-height);padding:0;width:var(--ck-style-panel-button-width)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button:not(:focus){border:1px solid var(--ck-color-base-border)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button .ck-button__label{flex-shrink:0;height:22px;line-height:22px;overflow:hidden;padding:0 var(--ck-spacing-medium);text-overflow:ellipsis;width:100%}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button .ck-style-grid__button__preview{background:var(--ck-color-base-background);border:2px solid var(--ck-color-base-background);opacity:.9;overflow:hidden;padding:var(--ck-spacing-medium);width:100%}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button.ck-disabled{--ck-color-button-default-disabled-background:var(--ck-color-base-foreground)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button.ck-disabled:not(:focus){border-color:var(--ck-style-panel-button-label-background)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button.ck-disabled .ck-style-grid__button__preview{border-color:var(--ck-color-base-foreground);filter:saturate(.3);opacity:.4}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button.ck-on{border-color:var(--ck-color-base-active)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button.ck-on .ck-button__label{box-shadow:0 -1px 0 var(--ck-color-base-active);z-index:1}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button.ck-on:hover{border-color:var(--ck-color-base-active-focus)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button:not(.ck-on) .ck-button__label{background:var(--ck-style-panel-button-label-background)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button:not(.ck-on):hover .ck-button__label{background:var(--ck-style-panel-button-hover-label-background)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button:hover:not(.ck-disabled):not(.ck-on){border-color:var(--ck-style-panel-button-hover-border-color)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button:hover:not(.ck-disabled):not(.ck-on) .ck-style-grid__button__preview{opacity:1}",""]);const l=n},561:(e,t,s)=>{"use strict";s.d(t,{Z:()=>l});var i=s(609),n=s.n(i)()((function(e){return e[1]}));n.push([e.id,".ck.ck-style-panel .ck-style-panel__style-group>.ck-label{margin:var(--ck-spacing-large) 0}.ck.ck-style-panel .ck-style-panel__style-group:first-child>.ck-label{margin-top:0}",""]);const l=n},662:(e,t,s)=>{"use strict";s.d(t,{Z:()=>l});var i=s(609),n=s.n(i)()((function(e){return e[1]}));n.push([e.id,":root{--ck-style-panel-max-height:470px}.ck.ck-style-panel{max-height:var(--ck-style-panel-max-height);overflow-y:auto;padding:var(--ck-spacing-large)}",""]);const l=n},609:e=>{"use strict";e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var s=e(t);return t[2]?"@media ".concat(t[2]," {").concat(s,"}"):s})).join("")},t.i=function(e,s,i){"string"==typeof e&&(e=[[null,e,""]]);var n={};if(i)for(var l=0;l<this.length;l++){var o=this[l][0];null!=o&&(n[o]=!0)}for(var r=0;r<e.length;r++){var c=[].concat(e[r]);i&&n[c[0]]||(s&&(c[2]?c[2]="".concat(s," and ").concat(c[2]):c[2]=s),t.push(c))}},t}},62:(e,t,s)=>{"use strict";var i,n=function(){return void 0===i&&(i=Boolean(window&&document&&document.all&&!window.atob)),i},l=function(){var e={};return function(t){if(void 0===e[t]){var s=document.querySelector(t);if(window.HTMLIFrameElement&&s instanceof window.HTMLIFrameElement)try{s=s.contentDocument.head}catch(e){s=null}e[t]=s}return e[t]}}(),o=[];function r(e){for(var t=-1,s=0;s<o.length;s++)if(o[s].identifier===e){t=s;break}return t}function c(e,t){for(var s={},i=[],n=0;n<e.length;n++){var l=e[n],c=t.base?l[0]+t.base:l[0],a=s[c]||0,d="".concat(c," ").concat(a);s[c]=a+1;var u=r(d),h={css:l[1],media:l[2],sourceMap:l[3]};-1!==u?(o[u].references++,o[u].updater(h)):o.push({identifier:d,updater:g(h,t),references:1}),i.push(d)}return i}function a(e){var t=document.createElement("style"),i=e.attributes||{};if(void 0===i.nonce){var n=s.nc;n&&(i.nonce=n)}if(Object.keys(i).forEach((function(e){t.setAttribute(e,i[e])})),"function"==typeof e.insert)e.insert(t);else{var o=l(e.insert||"head");if(!o)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");o.appendChild(t)}return t}var d,u=(d=[],function(e,t){return d[e]=t,d.filter(Boolean).join("\n")});function h(e,t,s,i){var n=s?"":i.media?"@media ".concat(i.media," {").concat(i.css,"}"):i.css;if(e.styleSheet)e.styleSheet.cssText=u(t,n);else{var l=document.createTextNode(n),o=e.childNodes;o[t]&&e.removeChild(o[t]),o.length?e.insertBefore(l,o[t]):e.appendChild(l)}}function k(e,t,s){var i=s.css,n=s.media,l=s.sourceMap;if(n?e.setAttribute("media",n):e.removeAttribute("media"),l&&"undefined"!=typeof btoa&&(i+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(l))))," */")),e.styleSheet)e.styleSheet.cssText=i;else{for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(i))}}var y=null,b=0;function g(e,t){var s,i,n;if(t.singleton){var l=b++;s=y||(y=a(t)),i=h.bind(null,s,l,!1),n=h.bind(null,s,l,!0)}else s=a(t),i=k.bind(null,s,t),n=function(){!function(e){if(null===e.parentNode)return!1;e.parentNode.removeChild(e)}(s)};return i(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap)return;i(e=t)}else n()}}e.exports=function(e,t){(t=t||{}).singleton||"boolean"==typeof t.singleton||(t.singleton=n());var s=c(e=e||[],t);return function(e){if(e=e||[],"[object Array]"===Object.prototype.toString.call(e)){for(var i=0;i<s.length;i++){var n=r(s[i]);o[n].references--}for(var l=c(e,t),a=0;a<s.length;a++){var d=r(s[a]);0===o[d].references&&(o[d].updater(),o.splice(d,1))}s=l}}}},704:(e,t,s)=>{e.exports=s(79)("./src/core.js")},273:(e,t,s)=>{e.exports=s(79)("./src/ui.js")},209:(e,t,s)=>{e.exports=s(79)("./src/utils.js")},79:e=>{"use strict";e.exports=CKEditor5.dll}},t={};function s(i){var n=t[i];if(void 0!==n)return n.exports;var l=t[i]={id:i,exports:{}};return e[i](l,l.exports,s),l.exports}s.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return s.d(t,{a:t}),t},s.d=(e,t)=>{for(var i in t)s.o(t,i)&&!s.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:t[i]})},s.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),s.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},s.nc=void 0;var i={};(()=>{"use strict";s.r(i),s.d(i,{Style:()=>V,StyleEditing:()=>x,StyleUI:()=>w});var e=s(704),t=s(273),n=s(209);const l=["caption","colgroup","dd","dt","figcaption","legend","li","optgroup","option","rp","rt","summary","tbody","td","tfoot","th","thead","tr"];class o extends t.ButtonView{constructor(e,t){super(e),this.styleDefinition=t,this.previewView=this._createPreview(),this.set({label:t.name,class:"ck-style-grid__button",withText:!0}),this.extendTemplate({attributes:{role:"option"}}),this.children.add(this.previewView,0)}_createPreview(){const{element:e,classes:s}=this.styleDefinition,i=new t.View(this.locale);return i.setTemplate({tag:"div",attributes:{class:["ck","ck-reset_all-excluded","ck-style-grid__button__preview","ck-content"],"aria-hidden":"true"},children:[{tag:this._isPreviewable(e)?e:"div",attributes:{class:s},children:[{text:"AaBbCcDdEeFfGgHhIiJj"}]}]}),i}_isPreviewable(e){return!l.includes(e)}}var r=s(62),c=s.n(r),a=s(945),d={injectType:"singletonStyleTag",attributes:{"data-cke":!0},insert:"head",singleton:!0};c()(a.Z,d);a.Z.locals;class u extends t.View{constructor(e,t){super(e),this.focusTracker=new n.FocusTracker,this.keystrokes=new n.KeystrokeHandler,this.set("activeStyles",[]),this.set("enabledStyles",[]),this.children=this.createCollection(),this.children.delegate("execute").to(this);for(const s of t){const t=new o(e,s);this.children.add(t)}this.on("change:activeStyles",(()=>{for(const e of this.children)e.isOn=this.activeStyles.includes(e.styleDefinition.name)})),this.on("change:enabledStyles",(()=>{for(const e of this.children)e.isEnabled=this.enabledStyles.includes(e.styleDefinition.name)})),this.setTemplate({tag:"div",attributes:{class:["ck","ck-style-grid"],role:"listbox"},children:this.children})}render(){super.render();for(const e of this.children)this.focusTracker.add(e.element);(0,t.addKeyboardHandlingForGrid)({keystrokeHandler:this.keystrokes,focusTracker:this.focusTracker,gridItems:this.children,numberOfColumns:3,uiLanguageDirection:this.locale&&this.locale.uiLanguageDirection}),this.keystrokes.listenTo(this.element)}focus(){this.children.first.focus()}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}}var h=s(561),k={injectType:"singletonStyleTag",attributes:{"data-cke":!0},insert:"head",singleton:!0};c()(h.Z,k);h.Z.locals;class y extends t.View{constructor(e,s,i){super(e),this.labelView=new t.LabelView(e),this.labelView.text=s,this.gridView=new u(e,i),this.setTemplate({tag:"div",attributes:{class:["ck","ck-style-panel__style-group"],role:"group","aria-labelledby":this.labelView.id},children:[this.labelView,this.gridView]})}}var b=s(662),g={injectType:"singletonStyleTag",attributes:{"data-cke":!0},insert:"head",singleton:!0};c()(b.Z,g);b.Z.locals;class p extends t.View{constructor(e,s){super(e);const i=e.t;this.focusTracker=new n.FocusTracker,this.keystrokes=new n.KeystrokeHandler,this.children=this.createCollection(),this.blockStylesGroupView=new y(e,i("Block styles"),s.block),this.inlineStylesGroupView=new y(e,i("Text styles"),s.inline),this.set("activeStyles",[]),this.set("enabledStyles",[]),this._focusables=new t.ViewCollection,this._focusCycler=new t.FocusCycler({focusables:this._focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:["shift + tab"],focusNext:["tab"]}}),s.block.length&&this.children.add(this.blockStylesGroupView),s.inline.length&&this.children.add(this.inlineStylesGroupView),this.blockStylesGroupView.gridView.delegate("execute").to(this),this.inlineStylesGroupView.gridView.delegate("execute").to(this),this.blockStylesGroupView.gridView.bind("activeStyles","enabledStyles").to(this),this.inlineStylesGroupView.gridView.bind("activeStyles","enabledStyles").to(this),this.setTemplate({tag:"div",attributes:{class:["ck","ck-style-panel"]},children:this.children})}render(){super.render(),this._focusables.add(this.blockStylesGroupView.gridView),this._focusables.add(this.inlineStylesGroupView.gridView),this.focusTracker.add(this.blockStylesGroupView.gridView.element),this.focusTracker.add(this.inlineStylesGroupView.gridView.element),this.keystrokes.listenTo(this.element)}focus(){this._focusCycler.focusFirst()}focusLast(){this._focusCycler.focusLast()}}function f(e,t=[]){const s={block:[],inline:[]};for(const i of t){const t=[],n=[];for(const s of e.getDefinitionsForView(i.element))s.isBlock?t.push(s.model):n.push(s.model);t.length?s.block.push({...i,modelElements:t,isBlock:!0}):s.inline.push({...i,ghsAttributes:n})}return s}var m=s(529),v={injectType:"singletonStyleTag",attributes:{"data-cke":!0},insert:"head",singleton:!0};c()(m.Z,v);m.Z.locals;class w extends e.Plugin{static get pluginName(){return"StyleUI"}init(){const e=this.editor,s=f(e.plugins.get("DataSchema"),e.config.get("style.definitions"));e.ui.componentFactory.add("style",(i=>{const n=i.t,l=(0,t.createDropdown)(i),o=e.commands.get("style");return l.once("change:isOpen",(()=>{const e=new p(i,s);l.panelView.children.add(e),e.delegate("execute").to(l),e.bind("activeStyles").to(o,"value"),e.bind("enabledStyles").to(o,"enabledStyles")})),l.bind("isEnabled").to(o),l.buttonView.withText=!0,l.buttonView.bind("label").to(o,"value",(e=>e.length>1?n("Multiple styles"):1===e.length?e[0]:n("Styles"))),l.bind("class").to(o,"value",(e=>{const t=["ck-style-dropdown"];return e.length>1&&t.push("ck-style-dropdown_multiple-active"),t.join(" ")})),l.on("execute",(t=>{e.execute("style",{styleName:t.source.styleDefinition.name}),e.editing.view.focus()})),l}))}}class _ extends e.Command{constructor(e,t){super(e),this.set("value",[]),this.set("enabledStyles",[]),this._styleDefinitions=t}refresh(){const e=this.editor.model,t=e.document.selection,s=new Set,i=new Set;for(const n of this._styleDefinitions.inline)for(const l of n.ghsAttributes){e.schema.checkAttributeInSelection(t,l)&&i.add(n.name);S(this._getValueFromFirstAllowedNode(l),n.classes)&&s.add(n.name)}const l=(0,n.first)(t.getSelectedBlocks());if(l){const t=l.getAncestors({includeSelf:!0,parentFirst:!0});for(const n of t){if(e.schema.isLimit(n))break;if(e.schema.checkAttribute(n,"htmlAttributes"))for(const e of this._styleDefinitions.block){if(!e.modelElements.includes(n.name))continue;i.add(e.name);S(n.getAttribute("htmlAttributes"),e.classes)&&s.add(e.name)}}}this.enabledStyles=Array.from(i).sort(),this.isEnabled=this.enabledStyles.length>0,this.value=this.isEnabled?Array.from(s).sort():[]}execute({styleName:e,forceValue:t}){if(!this.enabledStyles.includes(e))return void(0,n.logWarning)("style-command-executed-with-incorrect-style-name");const s=this.editor.model,i=s.document.selection,l=this.editor.plugins.get("GeneralHtmlSupport"),o=[...this._styleDefinitions.inline,...this._styleDefinitions.block].find((({name:t})=>t==e)),r=void 0===t?!this.value.includes(o.name):t;s.change((()=>{let e;e=o.isBlock?function(e,t,s){const i=new Set;for(const n of e){const e=n.getAncestors({includeSelf:!0,parentFirst:!0});for(const n of e){if(s.isLimit(n))break;if(t.includes(n.name)){i.add(n);break}}}return i}(i.getSelectedBlocks(),o.modelElements,s.schema):[i];for(const t of e)r?l.addModelHtmlClass(o.element,o.classes,t):l.removeModelHtmlClass(o.element,o.classes,t)}))}_getValueFromFirstAllowedNode(e){const t=this.editor.model,s=t.schema,i=t.document.selection;if(i.isCollapsed)return i.getAttribute(e);for(const t of i.getRanges())for(const i of t.getItems())if(s.checkAttribute(i,e))return i.getAttribute(e);return null}}function S(e,t){return!(!e||!e.classes)&&t.every((t=>e.classes.includes(t)))}class x extends e.Plugin{static get pluginName(){return"StyleEditing"}static get requires(){return["GeneralHtmlSupport"]}init(){const e=this.editor,t=f(e.plugins.get("DataSchema"),e.config.get("style.definitions"));e.commands.add("style",new _(e,t)),this._configureGHSDataFilter(t)}_configureGHSDataFilter({block:e,inline:t}){const s=this.editor.plugins.get("DataFilter");s.loadAllowedConfig(e.map(T)),s.loadAllowedConfig(t.map(T))}}function T({element:e,classes:t}){return{name:e,classes:t}}class V extends e.Plugin{static get pluginName(){return"Style"}static get requires(){return[x,w]}}})(),(window.CKEditor5=window.CKEditor5||{}).style=i})(); | ||
*/(()=>{var e={529:(e,t,s)=>{"use strict";s.d(t,{Z:()=>l});var n=s(609),i=s.n(n)()((function(e){return e[1]}));i.push([e.id,".ck.ck-dropdown.ck-style-dropdown.ck-style-dropdown_multiple-active>.ck-button>.ck-button__label{font-style:italic}",""]);const l=i},945:(e,t,s)=>{"use strict";s.d(t,{Z:()=>l});var n=s(609),i=s.n(n)()((function(e){return e[1]}));i.push([e.id,":root{--ck-style-panel-columns:3}.ck.ck-style-panel .ck-style-grid{display:grid;grid-template-columns:repeat(var(--ck-style-panel-columns),auto);justify-content:start}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button{display:flex;flex-direction:column;justify-content:space-between}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button .ck-style-grid__button__preview{align-content:center;align-items:center;display:flex;flex-basis:100%;flex-grow:1;justify-content:flex-start}:root{--ck-style-panel-button-width:120px;--ck-style-panel-button-height:80px;--ck-style-panel-button-label-background:#f0f0f0;--ck-style-panel-button-hover-label-background:#ebebeb;--ck-style-panel-button-hover-border-color:#b3b3b3}.ck.ck-style-panel .ck-style-grid{column-gap:var(--ck-spacing-large);row-gap:var(--ck-spacing-large)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button{--ck-color-button-default-hover-background:var(--ck-color-base-background);--ck-color-button-default-active-background:var(--ck-color-base-background);height:var(--ck-style-panel-button-height);padding:0;width:var(--ck-style-panel-button-width)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button:not(:focus){border:1px solid var(--ck-color-base-border)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button .ck-button__label{flex-shrink:0;height:22px;line-height:22px;overflow:hidden;padding:0 var(--ck-spacing-medium);text-overflow:ellipsis;width:100%}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button .ck-style-grid__button__preview{background:var(--ck-color-base-background);border:2px solid var(--ck-color-base-background);opacity:.9;overflow:hidden;padding:var(--ck-spacing-medium);width:100%}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button.ck-disabled{--ck-color-button-default-disabled-background:var(--ck-color-base-foreground)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button.ck-disabled:not(:focus){border-color:var(--ck-style-panel-button-label-background)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button.ck-disabled .ck-style-grid__button__preview{border-color:var(--ck-color-base-foreground);filter:saturate(.3);opacity:.4}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button.ck-on{border-color:var(--ck-color-base-active)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button.ck-on .ck-button__label{box-shadow:0 -1px 0 var(--ck-color-base-active);z-index:1}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button.ck-on:hover{border-color:var(--ck-color-base-active-focus)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button:not(.ck-on) .ck-button__label{background:var(--ck-style-panel-button-label-background)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button:not(.ck-on):hover .ck-button__label{background:var(--ck-style-panel-button-hover-label-background)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button:hover:not(.ck-disabled):not(.ck-on){border-color:var(--ck-style-panel-button-hover-border-color)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button:hover:not(.ck-disabled):not(.ck-on) .ck-style-grid__button__preview{opacity:1}",""]);const l=i},561:(e,t,s)=>{"use strict";s.d(t,{Z:()=>l});var n=s(609),i=s.n(n)()((function(e){return e[1]}));i.push([e.id,".ck.ck-style-panel .ck-style-panel__style-group>.ck-label{margin:var(--ck-spacing-large) 0}.ck.ck-style-panel .ck-style-panel__style-group:first-child>.ck-label{margin-top:0}",""]);const l=i},662:(e,t,s)=>{"use strict";s.d(t,{Z:()=>l});var n=s(609),i=s.n(n)()((function(e){return e[1]}));i.push([e.id,":root{--ck-style-panel-max-height:470px}.ck.ck-style-panel{max-height:var(--ck-style-panel-max-height);overflow-y:auto;padding:var(--ck-spacing-large)}",""]);const l=i},609:e=>{"use strict";e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var s=e(t);return t[2]?"@media ".concat(t[2]," {").concat(s,"}"):s})).join("")},t.i=function(e,s,n){"string"==typeof e&&(e=[[null,e,""]]);var i={};if(n)for(var l=0;l<this.length;l++){var r=this[l][0];null!=r&&(i[r]=!0)}for(var o=0;o<e.length;o++){var c=[].concat(e[o]);n&&i[c[0]]||(s&&(c[2]?c[2]="".concat(s," and ").concat(c[2]):c[2]=s),t.push(c))}},t}},62:(e,t,s)=>{"use strict";var n,i=function(){return void 0===n&&(n=Boolean(window&&document&&document.all&&!window.atob)),n},l=function(){var e={};return function(t){if(void 0===e[t]){var s=document.querySelector(t);if(window.HTMLIFrameElement&&s instanceof window.HTMLIFrameElement)try{s=s.contentDocument.head}catch(e){s=null}e[t]=s}return e[t]}}(),r=[];function o(e){for(var t=-1,s=0;s<r.length;s++)if(r[s].identifier===e){t=s;break}return t}function c(e,t){for(var s={},n=[],i=0;i<e.length;i++){var l=e[i],c=t.base?l[0]+t.base:l[0],a=s[c]||0,d="".concat(c," ").concat(a);s[c]=a+1;var u=o(d),h={css:l[1],media:l[2],sourceMap:l[3]};-1!==u?(r[u].references++,r[u].updater(h)):r.push({identifier:d,updater:b(h,t),references:1}),n.push(d)}return n}function a(e){var t=document.createElement("style"),n=e.attributes||{};if(void 0===n.nonce){var i=s.nc;i&&(n.nonce=i)}if(Object.keys(n).forEach((function(e){t.setAttribute(e,n[e])})),"function"==typeof e.insert)e.insert(t);else{var r=l(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 d,u=(d=[],function(e,t){return d[e]=t,d.filter(Boolean).join("\n")});function h(e,t,s,n){var i=s?"":n.media?"@media ".concat(n.media," {").concat(n.css,"}"):n.css;if(e.styleSheet)e.styleSheet.cssText=u(t,i);else{var l=document.createTextNode(i),r=e.childNodes;r[t]&&e.removeChild(r[t]),r.length?e.insertBefore(l,r[t]):e.appendChild(l)}}function y(e,t,s){var n=s.css,i=s.media,l=s.sourceMap;if(i?e.setAttribute("media",i):e.removeAttribute("media"),l&&"undefined"!=typeof btoa&&(n+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(l))))," */")),e.styleSheet)e.styleSheet.cssText=n;else{for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(n))}}var k=null,g=0;function b(e,t){var s,n,i;if(t.singleton){var l=g++;s=k||(k=a(t)),n=h.bind(null,s,l,!1),i=h.bind(null,s,l,!0)}else s=a(t),n=y.bind(null,s,t),i=function(){!function(e){if(null===e.parentNode)return!1;e.parentNode.removeChild(e)}(s)};return n(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap)return;n(e=t)}else i()}}e.exports=function(e,t){(t=t||{}).singleton||"boolean"==typeof t.singleton||(t.singleton=i());var s=c(e=e||[],t);return function(e){if(e=e||[],"[object Array]"===Object.prototype.toString.call(e)){for(var n=0;n<s.length;n++){var i=o(s[n]);r[i].references--}for(var l=c(e,t),a=0;a<s.length;a++){var d=o(s[a]);0===r[d].references&&(r[d].updater(),r.splice(d,1))}s=l}}}},704:(e,t,s)=>{e.exports=s(79)("./src/core.js")},273:(e,t,s)=>{e.exports=s(79)("./src/ui.js")},209:(e,t,s)=>{e.exports=s(79)("./src/utils.js")},79:e=>{"use strict";e.exports=CKEditor5.dll}},t={};function s(n){var i=t[n];if(void 0!==i)return i.exports;var l=t[n]={id:n,exports:{}};return e[n](l,l.exports,s),l.exports}s.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return s.d(t,{a:t}),t},s.d=(e,t)=>{for(var n in t)s.o(t,n)&&!s.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},s.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),s.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},s.nc=void 0;var n={};(()=>{"use strict";s.r(n),s.d(n,{Style:()=>C,StyleEditing:()=>T,StyleUI:()=>w,StyleUtils:()=>p});var e=s(704),t=s(273),i=s(209);const l=["caption","colgroup","dd","dt","figcaption","legend","li","optgroup","option","rp","rt","summary","tbody","td","tfoot","th","thead","tr"];class r extends t.ButtonView{constructor(e,t){super(e),this.styleDefinition=t,this.previewView=this._createPreview(),this.set({label:t.name,class:"ck-style-grid__button",withText:!0}),this.extendTemplate({attributes:{role:"option"}}),this.children.add(this.previewView,0)}_createPreview(){const{element:e,classes:s}=this.styleDefinition,n=new t.View(this.locale);return n.setTemplate({tag:"div",attributes:{class:["ck","ck-reset_all-excluded","ck-style-grid__button__preview","ck-content"],"aria-hidden":"true"},children:[{tag:this._isPreviewable(e)?e:"div",attributes:{class:s},children:[{text:"AaBbCcDdEeFfGgHhIiJj"}]}]}),n}_isPreviewable(e){return!l.includes(e)}}var o=s(62),c=s.n(o),a=s(945),d={injectType:"singletonStyleTag",attributes:{"data-cke":!0},insert:"head",singleton:!0};c()(a.Z,d);a.Z.locals;class u extends t.View{constructor(e,t){super(e),this.focusTracker=new i.FocusTracker,this.keystrokes=new i.KeystrokeHandler,this.set("activeStyles",[]),this.set("enabledStyles",[]),this.children=this.createCollection(),this.children.delegate("execute").to(this);for(const s of t){const t=new r(e,s);this.children.add(t)}this.on("change:activeStyles",(()=>{for(const e of this.children)e.isOn=this.activeStyles.includes(e.styleDefinition.name)})),this.on("change:enabledStyles",(()=>{for(const e of this.children)e.isEnabled=this.enabledStyles.includes(e.styleDefinition.name)})),this.setTemplate({tag:"div",attributes:{class:["ck","ck-style-grid"],role:"listbox"},children:this.children})}render(){super.render();for(const e of this.children)this.focusTracker.add(e.element);(0,t.addKeyboardHandlingForGrid)({keystrokeHandler:this.keystrokes,focusTracker:this.focusTracker,gridItems:this.children,numberOfColumns:3,uiLanguageDirection:this.locale&&this.locale.uiLanguageDirection}),this.keystrokes.listenTo(this.element)}focus(){this.children.first.focus()}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}}var h=s(561),y={injectType:"singletonStyleTag",attributes:{"data-cke":!0},insert:"head",singleton:!0};c()(h.Z,y);h.Z.locals;class k extends t.View{constructor(e,s,n){super(e),this.labelView=new t.LabelView(e),this.labelView.text=s,this.gridView=new u(e,n),this.setTemplate({tag:"div",attributes:{class:["ck","ck-style-panel__style-group"],role:"group","aria-labelledby":this.labelView.id},children:[this.labelView,this.gridView]})}}var g=s(662),b={injectType:"singletonStyleTag",attributes:{"data-cke":!0},insert:"head",singleton:!0};c()(g.Z,b);g.Z.locals;class f extends t.View{constructor(e,s){super(e);const n=e.t;this.focusTracker=new i.FocusTracker,this.keystrokes=new i.KeystrokeHandler,this.children=this.createCollection(),this.blockStylesGroupView=new k(e,n("Block styles"),s.block),this.inlineStylesGroupView=new k(e,n("Text styles"),s.inline),this.set("activeStyles",[]),this.set("enabledStyles",[]),this._focusables=new t.ViewCollection,this._focusCycler=new t.FocusCycler({focusables:this._focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:["shift + tab"],focusNext:["tab"]}}),s.block.length&&this.children.add(this.blockStylesGroupView),s.inline.length&&this.children.add(this.inlineStylesGroupView),this.blockStylesGroupView.gridView.delegate("execute").to(this),this.inlineStylesGroupView.gridView.delegate("execute").to(this),this.blockStylesGroupView.gridView.bind("activeStyles","enabledStyles").to(this,"activeStyles","enabledStyles"),this.inlineStylesGroupView.gridView.bind("activeStyles","enabledStyles").to(this,"activeStyles","enabledStyles"),this.setTemplate({tag:"div",attributes:{class:["ck","ck-style-panel"]},children:this.children})}render(){super.render(),this._focusables.add(this.blockStylesGroupView.gridView),this._focusables.add(this.inlineStylesGroupView.gridView),this.focusTracker.add(this.blockStylesGroupView.gridView.element),this.focusTracker.add(this.inlineStylesGroupView.gridView.element),this.keystrokes.listenTo(this.element)}focus(){this._focusCycler.focusFirst()}focusLast(){this._focusCycler.focusLast()}}class p extends e.Plugin{static get pluginName(){return"StyleUtils"}normalizeConfig(e,t=[]){const s={block:[],inline:[]};for(const n of t){const t=[],i=[];for(const s of e.getDefinitionsForView(n.element))s.isBlock?t.push(s.model):i.push(s.model);t.length?s.block.push({...n,modelElements:t,isBlock:!0}):s.inline.push({...n,ghsAttributes:i})}return s}}var m=s(529),v={injectType:"singletonStyleTag",attributes:{"data-cke":!0},insert:"head",singleton:!0};c()(m.Z,v);m.Z.locals;class w extends e.Plugin{static get pluginName(){return"StyleUI"}static get requires(){return[p]}init(){const e=this.editor,s=e.plugins.get("DataSchema"),n=e.plugins.get("StyleUtils"),i=e.config.get("style.definitions"),l=n.normalizeConfig(s,i);e.ui.componentFactory.add("style",(s=>{const n=s.t,i=(0,t.createDropdown)(s),r=e.commands.get("style");return i.once("change:isOpen",(()=>{const e=new f(s,l);i.panelView.children.add(e),e.delegate("execute").to(i),e.bind("activeStyles").to(r,"value"),e.bind("enabledStyles").to(r,"enabledStyles")})),i.bind("isEnabled").to(r),i.buttonView.withText=!0,i.buttonView.bind("label").to(r,"value",(e=>e.length>1?n("Multiple styles"):1===e.length?e[0]:n("Styles"))),i.bind("class").to(r,"value",(e=>{const t=["ck-style-dropdown"];return e.length>1&&t.push("ck-style-dropdown_multiple-active"),t.join(" ")})),i.on("execute",(t=>{e.execute("style",{styleName:t.source.styleDefinition.name}),e.editing.view.focus()})),i}))}}const _=function(e){var t=typeof e;return null!=e&&("object"==t||"function"==t)};class S extends e.Command{constructor(e,t){super(e),this.set("value",[]),this.set("enabledStyles",[]),this._styleDefinitions=t}refresh(){const e=this.editor.model,t=e.document.selection,s=new Set,n=new Set;for(const i of this._styleDefinitions.inline)for(const l of i.ghsAttributes){e.schema.checkAttributeInSelection(t,l)&&n.add(i.name);x(this._getValueFromFirstAllowedNode(l),i.classes)&&s.add(i.name)}const l=(0,i.first)(t.getSelectedBlocks());if(l){const t=l.getAncestors({includeSelf:!0,parentFirst:!0});for(const i of t){if(e.schema.isLimit(i))break;if(e.schema.checkAttribute(i,"htmlAttributes"))for(const e of this._styleDefinitions.block){if(!e.modelElements.includes(i.name))continue;n.add(e.name);x(i.getAttribute("htmlAttributes"),e.classes)&&s.add(e.name)}}}this.enabledStyles=Array.from(n).sort(),this.isEnabled=this.enabledStyles.length>0,this.value=this.isEnabled?Array.from(s).sort():[]}execute({styleName:e,forceValue:t}){if(!this.enabledStyles.includes(e))return void(0,i.logWarning)("style-command-executed-with-incorrect-style-name");const s=this.editor.model,n=s.document.selection,l=this.editor.plugins.get("GeneralHtmlSupport"),r=[...this._styleDefinitions.inline,...this._styleDefinitions.block].find((({name:t})=>t==e)),o=void 0===t?!this.value.includes(r.name):t;s.change((()=>{let e;e=function(e){return"isBlock"in e}(r)?function(e,t,s){const n=new Set;for(const i of e){const e=i.getAncestors({includeSelf:!0,parentFirst:!0});for(const i of e){if(s.isLimit(i))break;if(t.includes(i.name)){n.add(i);break}}}return n}(n.getSelectedBlocks(),r.modelElements,s.schema):[n];for(const t of e)o?l.addModelHtmlClass(r.element,r.classes,t):l.removeModelHtmlClass(r.element,r.classes,t)}))}_getValueFromFirstAllowedNode(e){const t=this.editor.model,s=t.schema,n=t.document.selection;if(n.isCollapsed)return n.getAttribute(e);for(const t of n.getRanges())for(const n of t.getItems())if(s.checkAttribute(n,e))return n.getAttribute(e);return null}}function x(e,t){return _(e)&&(s=e,Boolean(s.classes)&&Array.isArray(s.classes))&&t.every((t=>e.classes.includes(t)));var s}class T extends e.Plugin{static get pluginName(){return"StyleEditing"}static get requires(){return["GeneralHtmlSupport",p]}init(){const e=this.editor,t=e.plugins.get("DataSchema"),s=e.plugins.get("StyleUtils"),n=e.config.get("style.definitions"),i=s.normalizeConfig(t,n);e.commands.add("style",new S(e,i)),this._configureGHSDataFilter(i)}_configureGHSDataFilter({block:e,inline:t}){const s=this.editor.plugins.get("DataFilter");s.loadAllowedConfig(e.map(V)),s.loadAllowedConfig(t.map(V))}}function V({element:e,classes:t}){return{name:e,classes:t}}class C extends e.Plugin{static get pluginName(){return"Style"}static get requires(){return[T,w]}}})(),(window.CKEditor5=window.CKEditor5||{}).style=n})(); |
{ | ||
"name": "@ckeditor/ckeditor5-style", | ||
"version": "36.0.1", | ||
"version": "37.0.0-alpha.0", | ||
"description": "Style feature for CKEditor 5.", | ||
@@ -15,38 +15,40 @@ "keywords": [ | ||
"dependencies": { | ||
"ckeditor5": "^36.0.1" | ||
"ckeditor5": "^37.0.0-alpha.0", | ||
"lodash-es": "^4.17.15" | ||
}, | ||
"devDependencies": { | ||
"@ckeditor/ckeditor5-alignment": "^36.0.1", | ||
"@ckeditor/ckeditor5-basic-styles": "^36.0.1", | ||
"@ckeditor/ckeditor5-block-quote": "^36.0.1", | ||
"@ckeditor/ckeditor5-cloud-services": "^36.0.1", | ||
"@ckeditor/ckeditor5-code-block": "^36.0.1", | ||
"@ckeditor/ckeditor5-core": "^36.0.1", | ||
"@ckeditor/ckeditor5-dev-utils": "^32.0.0", | ||
"@ckeditor/ckeditor5-easy-image": "^36.0.1", | ||
"@ckeditor/ckeditor5-editor-classic": "^36.0.1", | ||
"@ckeditor/ckeditor5-engine": "^36.0.1", | ||
"@ckeditor/ckeditor5-font": "^36.0.1", | ||
"@ckeditor/ckeditor5-heading": "^36.0.1", | ||
"@ckeditor/ckeditor5-highlight": "^36.0.1", | ||
"@ckeditor/ckeditor5-horizontal-line": "^36.0.1", | ||
"@ckeditor/ckeditor5-html-embed": "^36.0.1", | ||
"@ckeditor/ckeditor5-html-support": "^36.0.1", | ||
"@ckeditor/ckeditor5-image": "^36.0.1", | ||
"@ckeditor/ckeditor5-indent": "^36.0.1", | ||
"@ckeditor/ckeditor5-language": "^36.0.1", | ||
"@ckeditor/ckeditor5-link": "^36.0.1", | ||
"@ckeditor/ckeditor5-list": "^36.0.1", | ||
"@ckeditor/ckeditor5-mention": "^36.0.1", | ||
"@ckeditor/ckeditor5-page-break": "^36.0.1", | ||
"@ckeditor/ckeditor5-paragraph": "^36.0.1", | ||
"@ckeditor/ckeditor5-paste-from-office": "^36.0.1", | ||
"@ckeditor/ckeditor5-remove-format": "^36.0.1", | ||
"@ckeditor/ckeditor5-source-editing": "^36.0.1", | ||
"@ckeditor/ckeditor5-table": "^36.0.1", | ||
"@ckeditor/ckeditor5-theme-lark": "^36.0.1", | ||
"@ckeditor/ckeditor5-typing": "^36.0.1", | ||
"@ckeditor/ckeditor5-ui": "^36.0.1", | ||
"@ckeditor/ckeditor5-utils": "^36.0.1", | ||
"@ckeditor/ckeditor5-word-count": "^36.0.1", | ||
"@ckeditor/ckeditor5-alignment": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-basic-styles": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-block-quote": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-cloud-services": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-code-block": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-core": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-dev-utils": "^34.0.0", | ||
"@ckeditor/ckeditor5-easy-image": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-editor-classic": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-engine": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-font": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-heading": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-highlight": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-horizontal-line": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-html-embed": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-html-support": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-image": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-indent": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-language": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-link": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-list": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-mention": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-page-break": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-paragraph": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-paste-from-office": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-remove-format": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-source-editing": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-table": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-theme-lark": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-typing": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-ui": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-utils": "^37.0.0-alpha.0", | ||
"@ckeditor/ckeditor5-word-count": "^37.0.0-alpha.0", | ||
"typescript": "^4.8.4", | ||
"webpack": "^5.58.1", | ||
@@ -70,3 +72,4 @@ "webpack-cli": "^4.9.0" | ||
"lang", | ||
"src", | ||
"src/**/*.js", | ||
"src/**/*.d.ts", | ||
"theme", | ||
@@ -78,4 +81,7 @@ "build", | ||
"scripts": { | ||
"dll:build": "webpack" | ||
} | ||
"dll:build": "webpack", | ||
"build": "tsc -p ./tsconfig.release.json", | ||
"postversion": "npm run build" | ||
}, | ||
"types": "src/index.d.ts" | ||
} |
@@ -5,9 +5,8 @@ /** | ||
*/ | ||
/** | ||
* @module style | ||
*/ | ||
export { default as Style } from './style'; | ||
export { default as StyleEditing } from './styleediting'; | ||
export { default as StyleUI } from './styleui'; | ||
export { default as StyleUtils } from './styleutils'; |
113
src/style.js
@@ -5,12 +5,8 @@ /** | ||
*/ | ||
/** | ||
* @module style/style | ||
*/ | ||
import { Plugin } from 'ckeditor5/src/core'; | ||
import StyleUI from './styleui'; | ||
import StyleEditing from './styleediting'; | ||
/** | ||
@@ -21,101 +17,16 @@ * The style plugin. | ||
* and {@link module:style/styleui~StyleUI style UI feature}. | ||
* | ||
* @extends module:core/plugin~Plugin | ||
*/ | ||
export default class Style extends Plugin { | ||
/** | ||
* @inheritDoc | ||
*/ | ||
static get pluginName() { | ||
return 'Style'; | ||
} | ||
/** | ||
* @inheritDoc | ||
*/ | ||
static get requires() { | ||
return [ StyleEditing, StyleUI ]; | ||
} | ||
/** | ||
* @inheritDoc | ||
*/ | ||
static get pluginName() { | ||
return 'Style'; | ||
} | ||
/** | ||
* @inheritDoc | ||
*/ | ||
static get requires() { | ||
return [StyleEditing, StyleUI]; | ||
} | ||
} | ||
/** | ||
* The configuration of the {@link module:style/style~Style} feature. | ||
* | ||
* Read more in {@link module:style/style~StyleConfig}. | ||
* | ||
* @member {module:style/style~StyleConfig} module:core/editor/editorconfig~EditorConfig#style | ||
*/ | ||
/** | ||
* The configuration of the style feature. | ||
* | ||
* ClassicEditor | ||
* .create( { | ||
* style: ... // Style feature config. | ||
* } ) | ||
* .then( ... ) | ||
* .catch( ... ); | ||
* | ||
* See {@link module:core/editor/editorconfig~EditorConfig all editor options}. | ||
* | ||
* @interface StyleConfig | ||
*/ | ||
/** | ||
* The available style definitions. | ||
* | ||
* Style definitions are displayed in the `'style'` UI dropdown and get applied by the | ||
* {@link module:style/stylecommand~StyleCommand style command} to the content of the document. | ||
* | ||
* In the `'style'` UI dropdown, definitions are automatically grouped into two categories based on the of the `element` property: | ||
* | ||
* * **Block styles**: Can be applied to entire {@link module:html-support/dataschema~DataSchema#registerBlockElement block elements} | ||
* only (e.g. headings, paragraphs, divs). | ||
* * **Text styles**: Can by applied to any {@link module:html-support/dataschema~DataSchema#registerInlineElement text} in any element | ||
* in the document. | ||
* | ||
* An example configuration: | ||
* | ||
* [ | ||
* // Definitions of block styles. | ||
* { | ||
* name: 'Red heading', | ||
* element: 'h2', | ||
* classes: [ 'red-heading' ] | ||
* }, | ||
* { | ||
* name: 'Vibrant code', | ||
* element: 'pre', | ||
* classes: [ 'vibrant-code' ] | ||
* }, | ||
* | ||
* // Definitions of text (inline) styles. | ||
* { | ||
* name: 'Marker', | ||
* element: 'span', | ||
* classes: [ 'marker' ] | ||
* }, | ||
* // ... | ||
* ] | ||
* | ||
* **Note**: Configuring style definitions will automatically configure the | ||
* {@glink features/general-html-support General HTML Support feature}. **You do not need to repeat the configuration in | ||
* {@link module:html-support/generalhtmlsupport~GeneralHtmlSupportConfig}**. | ||
* | ||
* @member {Array.<module:style/style~StyleDefinition>} module:style/style~StyleConfig#definitions | ||
*/ | ||
/** | ||
* Style definition. | ||
* | ||
* An object describing a style definition. It contains the style `name`, `element` name and an array of CSS `classes`. | ||
* | ||
* // This style will create <h2 class="foo">...</h2> in the document data. | ||
* { | ||
* name: 'Example style', | ||
* element: 'h2', | ||
* classes: [ 'foo' ] | ||
* } | ||
* | ||
* @typedef {Object} module:style/style~StyleDefinition | ||
*/ |
@@ -5,10 +5,5 @@ /** | ||
*/ | ||
/** | ||
* @module style/stylecommand | ||
*/ | ||
import { Command } from 'ckeditor5/src/core'; | ||
import { logWarning, first } from 'ckeditor5/src/utils'; | ||
import { isObject } from 'lodash-es'; | ||
/** | ||
@@ -18,249 +13,199 @@ * Style command. | ||
* Applies and removes styles from selection and elements. | ||
* | ||
* @extends module:core/command~Command | ||
*/ | ||
export default class StyleCommand extends Command { | ||
/** | ||
* Creates an instance of the command. | ||
* | ||
* @param {module:core/editor/editor~Editor} editor Editor on which this command will be used. | ||
* @param {Object} styleDefinitions Normalized definitions of the styles. | ||
* @param {Array.<module:style/style~StyleDefinition>} styleDefinitions.block Definitions of block styles. | ||
* @param {Array.<module:style/style~StyleDefinition>} styleDefinitions.inline Definitions of inline styles. | ||
*/ | ||
constructor( editor, styleDefinitions ) { | ||
super( editor ); | ||
/** | ||
* Set of currently applied styles on the current selection. | ||
* | ||
* Names of styles correspond to the `name` property of | ||
* {@link module:style/style~StyleDefinition configured definitions}. | ||
* | ||
* @readonly | ||
* @observable | ||
* @member {Array.<String>} #value | ||
*/ | ||
this.set( 'value', [] ); | ||
/** | ||
* Names of enabled styles (styles that can be applied to the current selection). | ||
* | ||
* Names of enabled styles correspond to the `name` property of | ||
* {@link module:style/style~StyleDefinition configured definitions}. | ||
* | ||
* @readonly | ||
* @observable | ||
* @member {Array.<String>} #enabledStyles | ||
*/ | ||
this.set( 'enabledStyles', [] ); | ||
/** | ||
* Normalized definitions of the styles. | ||
* | ||
* @private | ||
* @readonly | ||
* @member {Object} #styleDefinitions | ||
*/ | ||
this._styleDefinitions = styleDefinitions; | ||
} | ||
/** | ||
* @inheritDoc | ||
*/ | ||
refresh() { | ||
const model = this.editor.model; | ||
const selection = model.document.selection; | ||
const value = new Set(); | ||
const enabledStyles = new Set(); | ||
// Inline styles. | ||
for ( const definition of this._styleDefinitions.inline ) { | ||
for ( const ghsAttributeName of definition.ghsAttributes ) { | ||
// Check if this inline style is enabled. | ||
if ( model.schema.checkAttributeInSelection( selection, ghsAttributeName ) ) { | ||
enabledStyles.add( definition.name ); | ||
} | ||
// Check if this inline style is active. | ||
const ghsAttributeValue = this._getValueFromFirstAllowedNode( ghsAttributeName ); | ||
if ( hasAllClasses( ghsAttributeValue, definition.classes ) ) { | ||
value.add( definition.name ); | ||
} | ||
} | ||
} | ||
// Block styles. | ||
const firstBlock = first( selection.getSelectedBlocks() ); | ||
if ( firstBlock ) { | ||
const ancestorBlocks = firstBlock.getAncestors( { includeSelf: true, parentFirst: true } ); | ||
for ( const block of ancestorBlocks ) { | ||
// E.g. reached a model table when the selection is in a cell. The command should not modify | ||
// ancestors of a table. | ||
if ( model.schema.isLimit( block ) ) { | ||
break; | ||
} | ||
if ( !model.schema.checkAttribute( block, 'htmlAttributes' ) ) { | ||
continue; | ||
} | ||
for ( const definition of this._styleDefinitions.block ) { | ||
// Check if this block style is enabled. | ||
if ( !definition.modelElements.includes( block.name ) ) { | ||
continue; | ||
} | ||
enabledStyles.add( definition.name ); | ||
// Check if this block style is active. | ||
const ghsAttributeValue = block.getAttribute( 'htmlAttributes' ); | ||
if ( hasAllClasses( ghsAttributeValue, definition.classes ) ) { | ||
value.add( definition.name ); | ||
} | ||
} | ||
} | ||
} | ||
this.enabledStyles = Array.from( enabledStyles ).sort(); | ||
this.isEnabled = this.enabledStyles.length > 0; | ||
this.value = this.isEnabled ? Array.from( value ).sort() : []; | ||
} | ||
/** | ||
* Executes the command — applies the style classes to the selection or removes it from the selection. | ||
* | ||
* If the command value already contains the requested style, it will remove the style classes. Otherwise, it will set it. | ||
* | ||
* The execution result differs, depending on the {@link module:engine/model/document~Document#selection} and the | ||
* style type (inline or block): | ||
* | ||
* * When applying inline styles: | ||
* * If the selection is on a range, the command applies the style classes to all nodes in that range. | ||
* * If the selection is collapsed in a non-empty node, the command applies the style classes to the | ||
* {@link module:engine/model/document~Document#selection}. | ||
* | ||
* * When applying block styles: | ||
* * If the selection is on a range, the command applies the style classes to the nearest block parent element. | ||
* | ||
* @fires execute | ||
* @param {Object} [options] Command options. | ||
* @param {String} options.styleName Style name matching the one defined in the | ||
* {@link module:style/style~StyleConfig#definitions configuration}. | ||
* @param {Boolean} [options.forceValue] Whether the command should add given style (`true`) or remove it (`false`) from the selection. | ||
* If not set (default), the command will toggle the style basing on the first selected node. Note, that this will not force | ||
* setting a style on an element that cannot receive given style. | ||
*/ | ||
execute( { styleName, forceValue } ) { | ||
if ( !this.enabledStyles.includes( styleName ) ) { | ||
/** | ||
* Style command can be executed only with a correct style name. | ||
* | ||
* This warning may be caused by: | ||
* | ||
* * passing a name that is not specified in the {@link module:style/style~StyleConfig#definitions configuration} | ||
* (e.g. a CSS class name), | ||
* * when trying to apply a style that is not allowed on a given element. | ||
* | ||
* @error style-command-executed-with-incorrect-style-name | ||
*/ | ||
logWarning( 'style-command-executed-with-incorrect-style-name' ); | ||
return; | ||
} | ||
const model = this.editor.model; | ||
const selection = model.document.selection; | ||
const htmlSupport = this.editor.plugins.get( 'GeneralHtmlSupport' ); | ||
const definition = [ | ||
...this._styleDefinitions.inline, | ||
...this._styleDefinitions.block | ||
].find( ( { name } ) => name == styleName ); | ||
const shouldAddStyle = forceValue === undefined ? !this.value.includes( definition.name ) : forceValue; | ||
model.change( () => { | ||
let selectables; | ||
if ( definition.isBlock ) { | ||
selectables = getAffectedBlocks( selection.getSelectedBlocks(), definition.modelElements, model.schema ); | ||
} else { | ||
selectables = [ selection ]; | ||
} | ||
for ( const selectable of selectables ) { | ||
if ( shouldAddStyle ) { | ||
htmlSupport.addModelHtmlClass( definition.element, definition.classes, selectable ); | ||
} else { | ||
htmlSupport.removeModelHtmlClass( definition.element, definition.classes, selectable ); | ||
} | ||
} | ||
} ); | ||
} | ||
/** | ||
* Checks the attribute value of the first node in the selection that allows the attribute. | ||
* For the collapsed selection, returns the selection attribute. | ||
* | ||
* @private | ||
* @param {String} attributeName Name of the GHS attribute. | ||
* @returns {Object|null} The attribute value. | ||
*/ | ||
_getValueFromFirstAllowedNode( attributeName ) { | ||
const model = this.editor.model; | ||
const schema = model.schema; | ||
const selection = model.document.selection; | ||
if ( selection.isCollapsed ) { | ||
return selection.getAttribute( attributeName ); | ||
} | ||
for ( const range of selection.getRanges() ) { | ||
for ( const item of range.getItems() ) { | ||
if ( schema.checkAttribute( item, attributeName ) ) { | ||
return item.getAttribute( attributeName ); | ||
} | ||
} | ||
} | ||
return null; | ||
} | ||
/** | ||
* Creates an instance of the command. | ||
* | ||
* @param editor Editor on which this command will be used. | ||
* @param styleDefinitions Normalized definitions of the styles. | ||
*/ | ||
constructor(editor, styleDefinitions) { | ||
super(editor); | ||
this.set('value', []); | ||
this.set('enabledStyles', []); | ||
this._styleDefinitions = styleDefinitions; | ||
} | ||
/** | ||
* @inheritDoc | ||
*/ | ||
refresh() { | ||
const model = this.editor.model; | ||
const selection = model.document.selection; | ||
const value = new Set(); | ||
const enabledStyles = new Set(); | ||
// Inline styles. | ||
for (const definition of this._styleDefinitions.inline) { | ||
for (const ghsAttributeName of definition.ghsAttributes) { | ||
// Check if this inline style is enabled. | ||
if (model.schema.checkAttributeInSelection(selection, ghsAttributeName)) { | ||
enabledStyles.add(definition.name); | ||
} | ||
// Check if this inline style is active. | ||
const ghsAttributeValue = this._getValueFromFirstAllowedNode(ghsAttributeName); | ||
if (hasAllClasses(ghsAttributeValue, definition.classes)) { | ||
value.add(definition.name); | ||
} | ||
} | ||
} | ||
// Block styles. | ||
const firstBlock = first(selection.getSelectedBlocks()); | ||
if (firstBlock) { | ||
const ancestorBlocks = firstBlock.getAncestors({ includeSelf: true, parentFirst: true }); | ||
for (const block of ancestorBlocks) { | ||
// E.g. reached a model table when the selection is in a cell. The command should not modify | ||
// ancestors of a table. | ||
if (model.schema.isLimit(block)) { | ||
break; | ||
} | ||
if (!model.schema.checkAttribute(block, 'htmlAttributes')) { | ||
continue; | ||
} | ||
for (const definition of this._styleDefinitions.block) { | ||
// Check if this block style is enabled. | ||
if (!definition.modelElements.includes(block.name)) { | ||
continue; | ||
} | ||
enabledStyles.add(definition.name); | ||
// Check if this block style is active. | ||
const ghsAttributeValue = block.getAttribute('htmlAttributes'); | ||
if (hasAllClasses(ghsAttributeValue, definition.classes)) { | ||
value.add(definition.name); | ||
} | ||
} | ||
} | ||
} | ||
this.enabledStyles = Array.from(enabledStyles).sort(); | ||
this.isEnabled = this.enabledStyles.length > 0; | ||
this.value = this.isEnabled ? Array.from(value).sort() : []; | ||
} | ||
/** | ||
* Executes the command — applies the style classes to the selection or removes it from the selection. | ||
* | ||
* If the command value already contains the requested style, it will remove the style classes. Otherwise, it will set it. | ||
* | ||
* The execution result differs, depending on the {@link module:engine/model/document~Document#selection} and the | ||
* style type (inline or block): | ||
* | ||
* * When applying inline styles: | ||
* * If the selection is on a range, the command applies the style classes to all nodes in that range. | ||
* * If the selection is collapsed in a non-empty node, the command applies the style classes to the | ||
* {@link module:engine/model/document~Document#selection}. | ||
* | ||
* * When applying block styles: | ||
* * If the selection is on a range, the command applies the style classes to the nearest block parent element. | ||
* | ||
* @fires execute | ||
* @param options Command options. | ||
* @param options.styleName Style name matching the one defined in the | ||
* {@link module:style/styleconfig~StyleConfig#definitions configuration}. | ||
* @param options.forceValue Whether the command should add given style (`true`) or remove it (`false`) from the selection. | ||
* If not set (default), the command will toggle the style basing on the first selected node. Note, that this will not force | ||
* setting a style on an element that cannot receive given style. | ||
*/ | ||
execute({ styleName, forceValue }) { | ||
if (!this.enabledStyles.includes(styleName)) { | ||
/** | ||
* Style command can be executed only with a correct style name. | ||
* | ||
* This warning may be caused by: | ||
* | ||
* * passing a name that is not specified in the {@link module:style/styleconfig~StyleConfig#definitions configuration} | ||
* (e.g. a CSS class name), | ||
* * when trying to apply a style that is not allowed on a given element. | ||
* | ||
* @error style-command-executed-with-incorrect-style-name | ||
*/ | ||
logWarning('style-command-executed-with-incorrect-style-name'); | ||
return; | ||
} | ||
const model = this.editor.model; | ||
const selection = model.document.selection; | ||
const htmlSupport = this.editor.plugins.get('GeneralHtmlSupport'); | ||
const definition = [ | ||
...this._styleDefinitions.inline, | ||
...this._styleDefinitions.block | ||
].find(({ name }) => name == styleName); | ||
const shouldAddStyle = forceValue === undefined ? !this.value.includes(definition.name) : forceValue; | ||
model.change(() => { | ||
let selectables; | ||
if (isBlockStyleDefinition(definition)) { | ||
selectables = getAffectedBlocks(selection.getSelectedBlocks(), definition.modelElements, model.schema); | ||
} | ||
else { | ||
selectables = [selection]; | ||
} | ||
for (const selectable of selectables) { | ||
if (shouldAddStyle) { | ||
htmlSupport.addModelHtmlClass(definition.element, definition.classes, selectable); | ||
} | ||
else { | ||
htmlSupport.removeModelHtmlClass(definition.element, definition.classes, selectable); | ||
} | ||
} | ||
}); | ||
} | ||
/** | ||
* Checks the attribute value of the first node in the selection that allows the attribute. | ||
* For the collapsed selection, returns the selection attribute. | ||
* | ||
* @param attributeName Name of the GHS attribute. | ||
* @returns The attribute value. | ||
*/ | ||
_getValueFromFirstAllowedNode(attributeName) { | ||
const model = this.editor.model; | ||
const schema = model.schema; | ||
const selection = model.document.selection; | ||
if (selection.isCollapsed) { | ||
return selection.getAttribute(attributeName); | ||
} | ||
for (const range of selection.getRanges()) { | ||
for (const item of range.getItems()) { | ||
if (schema.checkAttribute(item, attributeName)) { | ||
return item.getAttribute(attributeName); | ||
} | ||
} | ||
} | ||
return null; | ||
} | ||
} | ||
// Verifies if all classes are present in the given GHS attribute. | ||
function hasAllClasses( ghsAttributeValue, classes ) { | ||
if ( !ghsAttributeValue || !ghsAttributeValue.classes ) { | ||
return false; | ||
} | ||
return classes.every( className => ghsAttributeValue.classes.includes( className ) ); | ||
/** | ||
* Verifies if all classes are present in the given GHS attribute. | ||
*/ | ||
function hasAllClasses(ghsAttributeValue, classes) { | ||
return isObject(ghsAttributeValue) && | ||
hasClassesProperty(ghsAttributeValue) && | ||
classes.every(className => ghsAttributeValue.classes.includes(className)); | ||
} | ||
// Returns a set of elements that should be affected by the block-style change. | ||
function getAffectedBlocks( selectedBlocks, elementNames, schema ) { | ||
const blocks = new Set(); | ||
for ( const selectedBlock of selectedBlocks ) { | ||
const ancestorBlocks = selectedBlock.getAncestors( { includeSelf: true, parentFirst: true } ); | ||
for ( const block of ancestorBlocks ) { | ||
if ( schema.isLimit( block ) ) { | ||
break; | ||
} | ||
if ( elementNames.includes( block.name ) ) { | ||
blocks.add( block ); | ||
break; | ||
} | ||
} | ||
} | ||
return blocks; | ||
/** | ||
* Returns a set of elements that should be affected by the block-style change. | ||
*/ | ||
function getAffectedBlocks(selectedBlocks, elementNames, schema) { | ||
const blocks = new Set(); | ||
for (const selectedBlock of selectedBlocks) { | ||
const ancestorBlocks = selectedBlock.getAncestors({ includeSelf: true, parentFirst: true }); | ||
for (const block of ancestorBlocks) { | ||
if (schema.isLimit(block)) { | ||
break; | ||
} | ||
if (elementNames.includes(block.name)) { | ||
blocks.add(block); | ||
break; | ||
} | ||
} | ||
} | ||
return blocks; | ||
} | ||
/** | ||
* Checks if provided style definition is of type block. | ||
*/ | ||
function isBlockStyleDefinition(definition) { | ||
return 'isBlock' in definition; | ||
} | ||
/** | ||
* Checks if given object has `classes` property which is an array. | ||
* | ||
* @param obj Object to check. | ||
*/ | ||
function hasClassesProperty(obj) { | ||
return Boolean(obj.classes) && Array.isArray(obj.classes); | ||
} |
@@ -5,12 +5,8 @@ /** | ||
*/ | ||
/** | ||
* @module style/styleediting | ||
*/ | ||
import { Plugin } from 'ckeditor5/src/core'; | ||
import { normalizeConfig } from './utils'; | ||
import StyleCommand from './stylecommand'; | ||
import StyleUtils from './styleutils'; | ||
/** | ||
@@ -20,60 +16,50 @@ * The style engine feature. | ||
* It configures the {@glink features/general-html-support General HTML Support feature} based on | ||
* {@link module:style/style~StyleConfig#definitions configured style definitions} and introduces the | ||
* {@link module:style/styleconfig~StyleConfig#definitions configured style definitions} and introduces the | ||
* {@link module:style/stylecommand~StyleCommand style command} that applies styles to the content of the document. | ||
* | ||
* @extends module:core/plugin~Plugin | ||
*/ | ||
export default class StyleEditing extends Plugin { | ||
/** | ||
* @inheritDoc | ||
*/ | ||
static get pluginName() { | ||
return 'StyleEditing'; | ||
} | ||
/** | ||
* @inheritDoc | ||
*/ | ||
static get requires() { | ||
return [ 'GeneralHtmlSupport' ]; | ||
} | ||
/** | ||
* @inheritDoc | ||
*/ | ||
init() { | ||
const editor = this.editor; | ||
const dataSchema = editor.plugins.get( 'DataSchema' ); | ||
const normalizedStyleDefinitions = normalizeConfig( dataSchema, editor.config.get( 'style.definitions' ) ); | ||
editor.commands.add( 'style', new StyleCommand( editor, normalizedStyleDefinitions ) ); | ||
this._configureGHSDataFilter( normalizedStyleDefinitions ); | ||
} | ||
/** | ||
* This is where the styles feature configures the GHS feature. This method translates normalized | ||
* {@link module:style/style~StyleDefinition style definitions} to {@link module:engine/view/matcher~MatcherPattern matcher patterns} | ||
* and feeds them to the GHS {@link module:html-support/datafilter~DataFilter} plugin. | ||
* | ||
* @private | ||
* @param {Object} normalizedStyleDefinitions | ||
*/ | ||
_configureGHSDataFilter( { block: blockDefinitions, inline: inlineDefinitions } ) { | ||
const ghsDataFilter = this.editor.plugins.get( 'DataFilter' ); | ||
ghsDataFilter.loadAllowedConfig( blockDefinitions.map( normalizedStyleDefinitionToMatcherPattern ) ); | ||
ghsDataFilter.loadAllowedConfig( inlineDefinitions.map( normalizedStyleDefinitionToMatcherPattern ) ); | ||
} | ||
/** | ||
* @inheritDoc | ||
*/ | ||
static get pluginName() { | ||
return 'StyleEditing'; | ||
} | ||
/** | ||
* @inheritDoc | ||
*/ | ||
static get requires() { | ||
return ['GeneralHtmlSupport', StyleUtils]; | ||
} | ||
/** | ||
* @inheritDoc | ||
*/ | ||
init() { | ||
const editor = this.editor; | ||
const dataSchema = editor.plugins.get('DataSchema'); | ||
const styleUtils = editor.plugins.get('StyleUtils'); | ||
const styleDefinitions = editor.config.get('style.definitions'); | ||
const normalizedStyleDefinitions = styleUtils.normalizeConfig(dataSchema, styleDefinitions); | ||
editor.commands.add('style', new StyleCommand(editor, normalizedStyleDefinitions)); | ||
this._configureGHSDataFilter(normalizedStyleDefinitions); | ||
} | ||
/** | ||
* This is where the styles feature configures the GHS feature. This method translates normalized | ||
* {@link module:style/styleconfig~StyleDefinition style definitions} to | ||
* {@link module:engine/view/matcher~MatcherPattern matcher patterns} and feeds them to the GHS | ||
* {@link module:html-support/datafilter~DataFilter} plugin. | ||
*/ | ||
_configureGHSDataFilter({ block, inline }) { | ||
const ghsDataFilter = this.editor.plugins.get('DataFilter'); | ||
ghsDataFilter.loadAllowedConfig(block.map(normalizedStyleDefinitionToMatcherPattern)); | ||
ghsDataFilter.loadAllowedConfig(inline.map(normalizedStyleDefinitionToMatcherPattern)); | ||
} | ||
} | ||
// Translates a normalized style definition to a view matcher pattern. | ||
// | ||
// @param {Object} definition A normalized style definition. | ||
// @returns {module:engine/view/matcher~MatcherPattern} | ||
function normalizedStyleDefinitionToMatcherPattern( { element, classes } ) { | ||
return { | ||
name: element, | ||
classes | ||
}; | ||
/** | ||
* Translates a normalized style definition to a view matcher pattern. | ||
*/ | ||
function normalizedStyleDefinitionToMatcherPattern({ element, classes }) { | ||
return { | ||
name: element, | ||
classes | ||
}; | ||
} |
@@ -5,15 +5,11 @@ /** | ||
*/ | ||
/** | ||
* @module style/styleui | ||
*/ | ||
import { Plugin } from 'ckeditor5/src/core'; | ||
import { createDropdown } from 'ckeditor5/src/ui'; | ||
import StylePanelView from './ui/stylepanelview'; | ||
import { normalizeConfig } from './utils'; | ||
import StyleUtils from './styleutils'; | ||
import '../theme/style.css'; | ||
import './styleconfig'; | ||
/** | ||
@@ -24,84 +20,78 @@ * The UI plugin of the style feature . | ||
* that displays a grid of styles and allows changing styles of the content. | ||
* | ||
* @extends module:core/plugin~Plugin | ||
*/ | ||
export default class StyleUI extends Plugin { | ||
/** | ||
* @inheritDoc | ||
*/ | ||
static get pluginName() { | ||
return 'StyleUI'; | ||
} | ||
/** | ||
* @inheritDoc | ||
*/ | ||
init() { | ||
const editor = this.editor; | ||
const dataSchema = editor.plugins.get( 'DataSchema' ); | ||
const normalizedStyleDefinitions = normalizeConfig( dataSchema, editor.config.get( 'style.definitions' ) ); | ||
// Add the dropdown to the component factory. | ||
editor.ui.componentFactory.add( 'style', locale => { | ||
const t = locale.t; | ||
const dropdown = createDropdown( locale ); | ||
const styleCommand = editor.commands.get( 'style' ); | ||
dropdown.once( 'change:isOpen', () => { | ||
const panelView = new StylePanelView( locale, normalizedStyleDefinitions ); | ||
// Put the styles panel is the dropdown. | ||
dropdown.panelView.children.add( panelView ); | ||
// Close the dropdown when a style is selected in the styles panel. | ||
panelView.delegate( 'execute' ).to( dropdown ); | ||
// Bind the state of the styles panel to the command. | ||
panelView.bind( 'activeStyles' ).to( styleCommand, 'value' ); | ||
panelView.bind( 'enabledStyles' ).to( styleCommand, 'enabledStyles' ); | ||
} ); | ||
// The entire dropdown will be disabled together with the command (e.g. when the editor goes read-only). | ||
dropdown.bind( 'isEnabled' ).to( styleCommand ); | ||
// This dropdown has no icon. It displays text label depending on the selection. | ||
dropdown.buttonView.withText = true; | ||
// The label of the dropdown is dynamic and depends on how many styles are active at a time. | ||
dropdown.buttonView.bind( 'label' ).to( styleCommand, 'value', value => { | ||
if ( value.length > 1 ) { | ||
return t( 'Multiple styles' ); | ||
} else if ( value.length === 1 ) { | ||
return value[ 0 ]; | ||
} else { | ||
return t( 'Styles' ); | ||
} | ||
} ); | ||
// The dropdown has a static CSS class for easy customization. There's another CSS class | ||
// that gets displayed when multiple styles are active at a time allowing visual customization of | ||
// the label. | ||
dropdown.bind( 'class' ).to( styleCommand, 'value', value => { | ||
const classes = [ | ||
'ck-style-dropdown' | ||
]; | ||
if ( value.length > 1 ) { | ||
classes.push( 'ck-style-dropdown_multiple-active' ); | ||
} | ||
return classes.join( ' ' ); | ||
} ); | ||
// Execute the command when a style is selected in the styles panel. | ||
// Also focus the editable after executing the command. | ||
// It overrides a default behaviour where the focus is moved to the dropdown button (#12125). | ||
dropdown.on( 'execute', evt => { | ||
editor.execute( 'style', { styleName: evt.source.styleDefinition.name } ); | ||
editor.editing.view.focus(); | ||
} ); | ||
return dropdown; | ||
} ); | ||
} | ||
/** | ||
* @inheritDoc | ||
*/ | ||
static get pluginName() { | ||
return 'StyleUI'; | ||
} | ||
/** | ||
* @inheritDoc | ||
*/ | ||
static get requires() { | ||
return [StyleUtils]; | ||
} | ||
/** | ||
* @inheritDoc | ||
*/ | ||
init() { | ||
const editor = this.editor; | ||
const dataSchema = editor.plugins.get('DataSchema'); | ||
const styleUtils = editor.plugins.get('StyleUtils'); | ||
const styleDefinitions = editor.config.get('style.definitions'); | ||
const normalizedStyleDefinitions = styleUtils.normalizeConfig(dataSchema, styleDefinitions); | ||
// Add the dropdown to the component factory. | ||
editor.ui.componentFactory.add('style', locale => { | ||
const t = locale.t; | ||
const dropdown = createDropdown(locale); | ||
const styleCommand = editor.commands.get('style'); | ||
dropdown.once('change:isOpen', () => { | ||
const panelView = new StylePanelView(locale, normalizedStyleDefinitions); | ||
// Put the styles panel is the dropdown. | ||
dropdown.panelView.children.add(panelView); | ||
// Close the dropdown when a style is selected in the styles panel. | ||
panelView.delegate('execute').to(dropdown); | ||
// Bind the state of the styles panel to the command. | ||
panelView.bind('activeStyles').to(styleCommand, 'value'); | ||
panelView.bind('enabledStyles').to(styleCommand, 'enabledStyles'); | ||
}); | ||
// The entire dropdown will be disabled together with the command (e.g. when the editor goes read-only). | ||
dropdown.bind('isEnabled').to(styleCommand); | ||
// This dropdown has no icon. It displays text label depending on the selection. | ||
dropdown.buttonView.withText = true; | ||
// The label of the dropdown is dynamic and depends on how many styles are active at a time. | ||
dropdown.buttonView.bind('label').to(styleCommand, 'value', value => { | ||
if (value.length > 1) { | ||
return t('Multiple styles'); | ||
} | ||
else if (value.length === 1) { | ||
return value[0]; | ||
} | ||
else { | ||
return t('Styles'); | ||
} | ||
}); | ||
// The dropdown has a static CSS class for easy customization. There's another CSS class | ||
// that gets displayed when multiple styles are active at a time allowing visual customization of | ||
// the label. | ||
dropdown.bind('class').to(styleCommand, 'value', value => { | ||
const classes = [ | ||
'ck-style-dropdown' | ||
]; | ||
if (value.length > 1) { | ||
classes.push('ck-style-dropdown_multiple-active'); | ||
} | ||
return classes.join(' '); | ||
}); | ||
// Execute the command when a style is selected in the styles panel. | ||
// Also focus the editable after executing the command. | ||
// It overrides a default behaviour where the focus is moved to the dropdown button (#12125). | ||
dropdown.on('execute', evt => { | ||
editor.execute('style', { styleName: evt.source.styleDefinition.name }); | ||
editor.editing.view.focus(); | ||
}); | ||
return dropdown; | ||
}); | ||
} | ||
} |
@@ -5,117 +5,76 @@ /** | ||
*/ | ||
/** | ||
* @module style/ui/stylegridbuttonview | ||
*/ | ||
import { | ||
ButtonView, | ||
View | ||
} from 'ckeditor5/src/ui'; | ||
import { ButtonView, View } from 'ckeditor5/src/ui'; | ||
// These are intermediate element names that can't be rendered as style preview because they don't make sense standalone. | ||
const NON_PREVIEWABLE_ELEMENT_NAMES = [ | ||
'caption', 'colgroup', 'dd', 'dt', 'figcaption', 'legend', 'li', 'optgroup', 'option', 'rp', | ||
'rt', 'summary', 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr' | ||
'caption', 'colgroup', 'dd', 'dt', 'figcaption', 'legend', 'li', 'optgroup', 'option', 'rp', | ||
'rt', 'summary', 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr' | ||
]; | ||
/** | ||
* A class representing an individual button (style) in the grid. Renders a rich preview of the style. | ||
* | ||
* @protected | ||
* @extends {module:ui/button/buttonview~ButtonView} | ||
*/ | ||
export default class StyleGridButtonView extends ButtonView { | ||
/** | ||
* Creates an instance of the {@link module:style/ui/stylegridbuttonview~StyleGridButtonView} class. | ||
* | ||
* @param {module:utils/locale~Locale} locale The localization services instance. | ||
* @param {module:style/style~StyleDefinition} styleDefinition Definition of the style. | ||
*/ | ||
constructor( locale, styleDefinition ) { | ||
super( locale ); | ||
/** | ||
* Definition of the style the button will apply when executed. | ||
* | ||
* @readonly | ||
* @member {module:style/style~StyleDefinition} #styleDefinition | ||
*/ | ||
this.styleDefinition = styleDefinition; | ||
/** | ||
* The view rendering the preview of the style. | ||
* | ||
* @protected | ||
* @readonly | ||
* @member {module:ui/view~View} #previewView | ||
*/ | ||
this.previewView = this._createPreview(); | ||
this.set( { | ||
label: styleDefinition.name, | ||
class: 'ck-style-grid__button', | ||
withText: true | ||
} ); | ||
this.extendTemplate( { | ||
attributes: { | ||
role: 'option' | ||
} | ||
} ); | ||
this.children.add( this.previewView, 0 ); | ||
} | ||
/** | ||
* Creates the view representing the preview of the style. | ||
* | ||
* @private | ||
* @returns {module:ui/view~View} | ||
*/ | ||
_createPreview() { | ||
const { element, classes } = this.styleDefinition; | ||
const previewView = new View( this.locale ); | ||
previewView.setTemplate( { | ||
tag: 'div', | ||
attributes: { | ||
class: [ | ||
'ck', | ||
'ck-reset_all-excluded', | ||
'ck-style-grid__button__preview', | ||
'ck-content' | ||
], | ||
// The preview "AaBbCcDdEeFfGgHhIiJj" should not be read by screen readers because it is purely presentational. | ||
'aria-hidden': 'true' | ||
}, | ||
children: [ | ||
{ | ||
tag: this._isPreviewable( element ) ? element : 'div', | ||
attributes: { | ||
class: classes | ||
}, | ||
children: [ | ||
{ text: 'AaBbCcDdEeFfGgHhIiJj' } | ||
] | ||
} | ||
] | ||
} ); | ||
return previewView; | ||
} | ||
/** | ||
* Decides whether an element should be created in the preview or a substitute `<div>` should | ||
* be used instead. This avoids previewing a standalone `<td>`, `<li>`, etc. without a parent. | ||
* | ||
* @private | ||
* @param {String} elementName | ||
* @returns {Boolean} `true` when the element can be rendered. `false` otherwise. | ||
*/ | ||
_isPreviewable( elementName ) { | ||
return !NON_PREVIEWABLE_ELEMENT_NAMES.includes( elementName ); | ||
} | ||
/** | ||
* Creates an instance of the {@link module:style/ui/stylegridbuttonview~StyleGridButtonView} class. | ||
* | ||
* @param locale The localization services instance. | ||
* @param styleDefinition Definition of the style. | ||
*/ | ||
constructor(locale, styleDefinition) { | ||
super(locale); | ||
this.styleDefinition = styleDefinition; | ||
this.previewView = this._createPreview(); | ||
this.set({ | ||
label: styleDefinition.name, | ||
class: 'ck-style-grid__button', | ||
withText: true | ||
}); | ||
this.extendTemplate({ | ||
attributes: { | ||
role: 'option' | ||
} | ||
}); | ||
this.children.add(this.previewView, 0); | ||
} | ||
/** | ||
* Creates the view representing the preview of the style. | ||
*/ | ||
_createPreview() { | ||
const { element, classes } = this.styleDefinition; | ||
const previewView = new View(this.locale); | ||
previewView.setTemplate({ | ||
tag: 'div', | ||
attributes: { | ||
class: [ | ||
'ck', | ||
'ck-reset_all-excluded', | ||
'ck-style-grid__button__preview', | ||
'ck-content' | ||
], | ||
// The preview "AaBbCcDdEeFfGgHhIiJj" should not be read by screen readers because it is purely presentational. | ||
'aria-hidden': 'true' | ||
}, | ||
children: [ | ||
{ | ||
tag: this._isPreviewable(element) ? element : 'div', | ||
attributes: { | ||
class: classes | ||
}, | ||
children: [ | ||
{ text: 'AaBbCcDdEeFfGgHhIiJj' } | ||
] | ||
} | ||
] | ||
}); | ||
return previewView; | ||
} | ||
/** | ||
* Decides whether an element should be created in the preview or a substitute `<div>` should | ||
* be used instead. This avoids previewing a standalone `<td>`, `<li>`, etc. without a parent. | ||
* | ||
* @param elementName Name of the element | ||
* @returns Boolean indicating whether the element can be rendered. | ||
*/ | ||
_isPreviewable(elementName) { | ||
return !NON_PREVIEWABLE_ELEMENT_NAMES.includes(elementName); | ||
} | ||
} |
@@ -5,154 +5,91 @@ /** | ||
*/ | ||
/** | ||
* @module style/ui/stylegridview | ||
*/ | ||
import { View, addKeyboardHandlingForGrid } from 'ckeditor5/src/ui'; | ||
import { FocusTracker, KeystrokeHandler } from 'ckeditor5/src/utils'; | ||
import StyleGridButtonView from './stylegridbuttonview'; | ||
import '../../theme/stylegrid.css'; | ||
/** | ||
* A class representing a grid of styles ({@link module:style/ui/stylegridbuttonview~StyleGridButtonView buttons}). | ||
* Allows users to select a style. | ||
* | ||
* @protected | ||
* @extends module:ui/view~View | ||
*/ | ||
export default class StyleGridView extends View { | ||
/** | ||
* Creates an instance of the {@link module:style/ui/stylegridview~StyleGridView} class. | ||
* | ||
* @param {module:utils/locale~Locale} locale The localization services instance. | ||
* @param {Array.<module:style/style~StyleDefinition>} styleDefinitions Definitions of the styles. | ||
*/ | ||
constructor( locale, styleDefinitions ) { | ||
super( locale ); | ||
/** | ||
* Tracks information about the DOM focus in the view. | ||
* | ||
* @readonly | ||
* @member {module:utils/focustracker~FocusTracker} | ||
*/ | ||
this.focusTracker = new FocusTracker(); | ||
/** | ||
* An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}. | ||
* | ||
* @readonly | ||
* @member {module:utils/keystrokehandler~KeystrokeHandler} | ||
*/ | ||
this.keystrokes = new KeystrokeHandler(); | ||
/** | ||
* Array of active style names. They must correspond to the names of styles from | ||
* definitions passed to the {@link #constructor}. | ||
* | ||
* @observable | ||
* @readonly | ||
* @default [] | ||
* @member {Array.<String>} #activeStyles | ||
*/ | ||
this.set( 'activeStyles', [] ); | ||
/** | ||
* Array of enabled style names. They must correspond to the names of styles from | ||
* definitions passed to the {@link #constructor}. | ||
* | ||
* @observable | ||
* @readonly | ||
* @default [] | ||
* @member {Array.<String>} #enabledStyles | ||
*/ | ||
this.set( 'enabledStyles', [] ); | ||
/** | ||
* A collection of style {@link module:style/ui/stylegridbuttonview~StyleGridButtonView buttons}. | ||
* | ||
* @readonly | ||
* @member {module:ui/viewcollection~ViewCollection} | ||
*/ | ||
this.children = this.createCollection(); | ||
this.children.delegate( 'execute' ).to( this ); | ||
for ( const definition of styleDefinitions ) { | ||
const gridTileView = new StyleGridButtonView( locale, definition ); | ||
this.children.add( gridTileView ); | ||
} | ||
this.on( 'change:activeStyles', () => { | ||
for ( const child of this.children ) { | ||
child.isOn = this.activeStyles.includes( child.styleDefinition.name ); | ||
} | ||
} ); | ||
this.on( 'change:enabledStyles', () => { | ||
for ( const child of this.children ) { | ||
child.isEnabled = this.enabledStyles.includes( child.styleDefinition.name ); | ||
} | ||
} ); | ||
this.setTemplate( { | ||
tag: 'div', | ||
attributes: { | ||
class: [ | ||
'ck', | ||
'ck-style-grid' | ||
], | ||
role: 'listbox' | ||
}, | ||
children: this.children | ||
} ); | ||
/** | ||
* Fired when a {@link module:style/ui/stylegridbuttonview~StyleGridButtonView style} was selected (clicked) by the user. | ||
* | ||
* @event execute | ||
*/ | ||
} | ||
/** | ||
* @inheritDoc | ||
*/ | ||
render() { | ||
super.render(); | ||
for ( const child of this.children ) { | ||
this.focusTracker.add( child.element ); | ||
} | ||
addKeyboardHandlingForGrid( { | ||
keystrokeHandler: this.keystrokes, | ||
focusTracker: this.focusTracker, | ||
gridItems: this.children, | ||
numberOfColumns: 3, | ||
uiLanguageDirection: this.locale && this.locale.uiLanguageDirection | ||
} ); | ||
// Start listening for the keystrokes coming from the grid view. | ||
this.keystrokes.listenTo( this.element ); | ||
} | ||
/** | ||
* Focuses the first style button in the grid. | ||
*/ | ||
focus() { | ||
this.children.first.focus(); | ||
} | ||
/** | ||
* @inheritDoc | ||
*/ | ||
destroy() { | ||
super.destroy(); | ||
this.focusTracker.destroy(); | ||
this.keystrokes.destroy(); | ||
} | ||
/** | ||
* Creates an instance of the {@link module:style/ui/stylegridview~StyleGridView} class. | ||
* | ||
* @param locale The localization services instance. | ||
* @param styleDefinitions Definitions of the styles. | ||
*/ | ||
constructor(locale, styleDefinitions) { | ||
super(locale); | ||
this.focusTracker = new FocusTracker(); | ||
this.keystrokes = new KeystrokeHandler(); | ||
this.set('activeStyles', []); | ||
this.set('enabledStyles', []); | ||
this.children = this.createCollection(); | ||
this.children.delegate('execute').to(this); | ||
for (const definition of styleDefinitions) { | ||
const gridTileView = new StyleGridButtonView(locale, definition); | ||
this.children.add(gridTileView); | ||
} | ||
this.on('change:activeStyles', () => { | ||
for (const child of this.children) { | ||
child.isOn = this.activeStyles.includes(child.styleDefinition.name); | ||
} | ||
}); | ||
this.on('change:enabledStyles', () => { | ||
for (const child of this.children) { | ||
child.isEnabled = this.enabledStyles.includes(child.styleDefinition.name); | ||
} | ||
}); | ||
this.setTemplate({ | ||
tag: 'div', | ||
attributes: { | ||
class: [ | ||
'ck', | ||
'ck-style-grid' | ||
], | ||
role: 'listbox' | ||
}, | ||
children: this.children | ||
}); | ||
/** | ||
* Fired when a {@link module:style/ui/stylegridbuttonview~StyleGridButtonView style} was selected (clicked) by the user. | ||
* | ||
* @event execute | ||
*/ | ||
} | ||
/** | ||
* @inheritDoc | ||
*/ | ||
render() { | ||
super.render(); | ||
for (const child of this.children) { | ||
this.focusTracker.add(child.element); | ||
} | ||
addKeyboardHandlingForGrid({ | ||
keystrokeHandler: this.keystrokes, | ||
focusTracker: this.focusTracker, | ||
gridItems: this.children, | ||
numberOfColumns: 3, | ||
uiLanguageDirection: this.locale && this.locale.uiLanguageDirection | ||
}); | ||
// Start listening for the keystrokes coming from the grid view. | ||
this.keystrokes.listenTo(this.element); | ||
} | ||
/** | ||
* Focuses the first style button in the grid. | ||
*/ | ||
focus() { | ||
this.children.first.focus(); | ||
} | ||
/** | ||
* @inheritDoc | ||
*/ | ||
destroy() { | ||
super.destroy(); | ||
this.focusTracker.destroy(); | ||
this.keystrokes.destroy(); | ||
} | ||
} |
@@ -5,15 +5,8 @@ /** | ||
*/ | ||
/** | ||
* @module style/ui/stylegroupview | ||
*/ | ||
import { | ||
LabelView, | ||
View | ||
} from 'ckeditor5/src/ui'; | ||
import { LabelView, View } from 'ckeditor5/src/ui'; | ||
import StyleGridView from './stylegridview'; | ||
import '../../theme/stylegroup.css'; | ||
/** | ||
@@ -23,53 +16,32 @@ * A class representing a group of styles (e.g. "block" or "inline"). | ||
* Renders a {@link module:style/ui/stylegridview~StyleGridView style grid} and a label. | ||
* | ||
* @protected | ||
* @extends module:ui/view~View | ||
*/ | ||
export default class StyleGroupView extends View { | ||
/** | ||
* Creates an instance of the {@link module:style/ui/stylegroupview~StyleGroupView} class. | ||
* | ||
* @param {module:utils/locale~Locale} locale The localization services instance. | ||
* @param {String} label The localized label of the group. | ||
* @param {Array.<module:style/style~StyleDefinition>} styleDefinitions Definitions of the styles in the group. | ||
*/ | ||
constructor( locale, label, styleDefinitions ) { | ||
super( locale ); | ||
/** | ||
* The label of the group. | ||
* | ||
* @protected | ||
* @readonly | ||
* @member {module:ui/label~LabelView} #labelView | ||
*/ | ||
this.labelView = new LabelView( locale ); | ||
this.labelView.text = label; | ||
/** | ||
* The styles grid of the group. | ||
* | ||
* @readonly | ||
* @member {module:style/ui/stylegridview~StyleGridView} #gridView | ||
*/ | ||
this.gridView = new StyleGridView( locale, styleDefinitions ); | ||
this.setTemplate( { | ||
tag: 'div', | ||
attributes: { | ||
class: [ | ||
'ck', | ||
'ck-style-panel__style-group' | ||
], | ||
role: 'group', | ||
'aria-labelledby': this.labelView.id | ||
}, | ||
children: [ | ||
this.labelView, | ||
this.gridView | ||
] | ||
} ); | ||
} | ||
/** | ||
* Creates an instance of the {@link module:style/ui/stylegroupview~StyleGroupView} class. | ||
* | ||
* @param locale The localization services instance. | ||
* @param label The localized label of the group. | ||
* @param styleDefinitions Definitions of the styles in the group. | ||
*/ | ||
constructor(locale, label, styleDefinitions) { | ||
super(locale); | ||
this.labelView = new LabelView(locale); | ||
this.labelView.text = label; | ||
this.gridView = new StyleGridView(locale, styleDefinitions); | ||
this.setTemplate({ | ||
tag: 'div', | ||
attributes: { | ||
class: [ | ||
'ck', | ||
'ck-style-panel__style-group' | ||
], | ||
role: 'group', | ||
'aria-labelledby': this.labelView.id | ||
}, | ||
children: [ | ||
this.labelView, | ||
this.gridView | ||
] | ||
}); | ||
} | ||
} |
@@ -5,193 +5,97 @@ /** | ||
*/ | ||
/** | ||
* @module style/ui/stylepanelview | ||
*/ | ||
import { | ||
FocusCycler, | ||
View, | ||
ViewCollection | ||
} from 'ckeditor5/src/ui'; | ||
import { FocusCycler, View, ViewCollection } from 'ckeditor5/src/ui'; | ||
import { FocusTracker, KeystrokeHandler } from 'ckeditor5/src/utils'; | ||
import StyleGroupView from './stylegroupview'; | ||
import '../../theme/stylepanel.css'; | ||
/** | ||
* A class representing a panel with available content styles. It renders styles in button grids, grouped | ||
* in categories. | ||
* | ||
* @protected | ||
* @extends module:ui/view~View | ||
*/ | ||
export default class StylePanelView extends View { | ||
/** | ||
* Creates an instance of the {@link module:style/ui/stylegroupview~StyleGroupView} class. | ||
* | ||
* @param {module:utils/locale~Locale} locale The localization services instance. | ||
* @param {Object} styleDefinitions Normalized definitions of the styles. | ||
* @param {Array.<module:style/style~StyleDefinition>} styleDefinitions.block Definitions of block styles. | ||
* @param {Array.<module:style/style~StyleDefinition>} styleDefinitions.inline Definitions of inline styles. | ||
*/ | ||
constructor( locale, styleDefinitions ) { | ||
super( locale ); | ||
const t = locale.t; | ||
/** | ||
* Tracks information about DOM focus in the panel. | ||
* | ||
* @readonly | ||
* @member {module:utils/focustracker~FocusTracker} | ||
*/ | ||
this.focusTracker = new FocusTracker(); | ||
/** | ||
* An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}. | ||
* | ||
* @readonly | ||
* @member {module:utils/keystrokehandler~KeystrokeHandler} | ||
*/ | ||
this.keystrokes = new KeystrokeHandler(); | ||
/** | ||
* A collection of panel children. | ||
* | ||
* @readonly | ||
* @member {module:ui/viewcollection~ViewCollection} | ||
*/ | ||
this.children = this.createCollection(); | ||
/** | ||
* A view representing block styles group. | ||
* | ||
* @readonly | ||
* @member {module:style/ui/stylegroupview~StyleGroupView} | ||
*/ | ||
this.blockStylesGroupView = new StyleGroupView( locale, t( 'Block styles' ), styleDefinitions.block ); | ||
/** | ||
* A view representing inline styles group. | ||
* | ||
* @readonly | ||
* @member {module:style/ui/stylegroupview~StyleGroupView} | ||
*/ | ||
this.inlineStylesGroupView = new StyleGroupView( locale, t( 'Text styles' ), styleDefinitions.inline ); | ||
/** | ||
* Array of active style names. They must correspond to the names of styles from | ||
* definitions passed to the {@link #constructor}. | ||
* | ||
* @observable | ||
* @readonly | ||
* @default [] | ||
* @member {Array.<String>} #activeStyles | ||
*/ | ||
this.set( 'activeStyles', [] ); | ||
/** | ||
* Array of enabled style names. They must correspond to the names of styles from | ||
* definitions passed to the {@link #constructor}. | ||
* | ||
* @observable | ||
* @readonly | ||
* @default [] | ||
* @member {Array.<String>} #enabledStyles | ||
*/ | ||
this.set( 'enabledStyles', [] ); | ||
/** | ||
* A collection of views that can be focused in the panel. | ||
* | ||
* @readonly | ||
* @protected | ||
* @member {module:ui/viewcollection~ViewCollection} | ||
*/ | ||
this._focusables = new ViewCollection(); | ||
/** | ||
* Helps cycling over {@link #_focusables} in the panel. | ||
* | ||
* @readonly | ||
* @protected | ||
* @member {module:ui/focuscycler~FocusCycler} | ||
*/ | ||
this._focusCycler = new FocusCycler( { | ||
focusables: this._focusables, | ||
focusTracker: this.focusTracker, | ||
keystrokeHandler: this.keystrokes, | ||
actions: { | ||
// Navigate style groups backwards using the <kbd>Shift</kbd> + <kbd>Tab</kbd> keystroke. | ||
focusPrevious: [ 'shift + tab' ], | ||
// Navigate style groups forward using the <kbd>Tab</kbd> key. | ||
focusNext: [ 'tab' ] | ||
} | ||
} ); | ||
if ( styleDefinitions.block.length ) { | ||
this.children.add( this.blockStylesGroupView ); | ||
} | ||
if ( styleDefinitions.inline.length ) { | ||
this.children.add( this.inlineStylesGroupView ); | ||
} | ||
this.blockStylesGroupView.gridView.delegate( 'execute' ).to( this ); | ||
this.inlineStylesGroupView.gridView.delegate( 'execute' ).to( this ); | ||
this.blockStylesGroupView.gridView.bind( 'activeStyles', 'enabledStyles' ).to( this ); | ||
this.inlineStylesGroupView.gridView.bind( 'activeStyles', 'enabledStyles' ).to( this ); | ||
this.setTemplate( { | ||
tag: 'div', | ||
attributes: { | ||
class: [ | ||
'ck', | ||
'ck-style-panel' | ||
] | ||
}, | ||
children: this.children | ||
} ); | ||
/** | ||
* Fired when a style was selected (clicked) by the user. | ||
* | ||
* @event execute | ||
*/ | ||
} | ||
/** | ||
* @inheritDoc | ||
*/ | ||
render() { | ||
super.render(); | ||
// Register the views as focusable. | ||
this._focusables.add( this.blockStylesGroupView.gridView ); | ||
this._focusables.add( this.inlineStylesGroupView.gridView ); | ||
// Register the views in the focus tracker. | ||
this.focusTracker.add( this.blockStylesGroupView.gridView.element ); | ||
this.focusTracker.add( this.inlineStylesGroupView.gridView.element ); | ||
this.keystrokes.listenTo( this.element ); | ||
} | ||
/** | ||
* Focuses the first focusable element in the panel. | ||
*/ | ||
focus() { | ||
this._focusCycler.focusFirst(); | ||
} | ||
/** | ||
* Focuses the last focusable element in the panel. | ||
*/ | ||
focusLast() { | ||
this._focusCycler.focusLast(); | ||
} | ||
/** | ||
* Creates an instance of the {@link module:style/ui/stylegroupview~StyleGroupView} class. | ||
* | ||
* @param locale The localization services instance. | ||
* @param styleDefinitions Normalized definitions of the styles. | ||
*/ | ||
constructor(locale, styleDefinitions) { | ||
super(locale); | ||
const t = locale.t; | ||
this.focusTracker = new FocusTracker(); | ||
this.keystrokes = new KeystrokeHandler(); | ||
this.children = this.createCollection(); | ||
this.blockStylesGroupView = new StyleGroupView(locale, t('Block styles'), styleDefinitions.block); | ||
this.inlineStylesGroupView = new StyleGroupView(locale, t('Text styles'), styleDefinitions.inline); | ||
this.set('activeStyles', []); | ||
this.set('enabledStyles', []); | ||
this._focusables = new ViewCollection(); | ||
this._focusCycler = new FocusCycler({ | ||
focusables: this._focusables, | ||
focusTracker: this.focusTracker, | ||
keystrokeHandler: this.keystrokes, | ||
actions: { | ||
// Navigate style groups backwards using the <kbd>Shift</kbd> + <kbd>Tab</kbd> keystroke. | ||
focusPrevious: ['shift + tab'], | ||
// Navigate style groups forward using the <kbd>Tab</kbd> key. | ||
focusNext: ['tab'] | ||
} | ||
}); | ||
if (styleDefinitions.block.length) { | ||
this.children.add(this.blockStylesGroupView); | ||
} | ||
if (styleDefinitions.inline.length) { | ||
this.children.add(this.inlineStylesGroupView); | ||
} | ||
this.blockStylesGroupView.gridView.delegate('execute').to(this); | ||
this.inlineStylesGroupView.gridView.delegate('execute').to(this); | ||
this.blockStylesGroupView.gridView | ||
.bind('activeStyles', 'enabledStyles') | ||
.to(this, 'activeStyles', 'enabledStyles'); | ||
this.inlineStylesGroupView.gridView | ||
.bind('activeStyles', 'enabledStyles') | ||
.to(this, 'activeStyles', 'enabledStyles'); | ||
this.setTemplate({ | ||
tag: 'div', | ||
attributes: { | ||
class: [ | ||
'ck', | ||
'ck-style-panel' | ||
] | ||
}, | ||
children: this.children | ||
}); | ||
/** | ||
* Fired when a style was selected (clicked) by the user. | ||
* | ||
* @event execute | ||
*/ | ||
} | ||
/** | ||
* @inheritDoc | ||
*/ | ||
render() { | ||
super.render(); | ||
// Register the views as focusable. | ||
this._focusables.add(this.blockStylesGroupView.gridView); | ||
this._focusables.add(this.inlineStylesGroupView.gridView); | ||
// Register the views in the focus tracker. | ||
this.focusTracker.add(this.blockStylesGroupView.gridView.element); | ||
this.focusTracker.add(this.inlineStylesGroupView.gridView.element); | ||
this.keystrokes.listenTo(this.element); | ||
} | ||
/** | ||
* Focuses the first focusable element in the panel. | ||
*/ | ||
focus() { | ||
this._focusCycler.focusFirst(); | ||
} | ||
/** | ||
* Focuses the last focusable element in the panel. | ||
*/ | ||
focusLast() { | ||
this._focusCycler.focusLast(); | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
148335
120
1442
2
36
1
1
+ Addedlodash-es@^4.17.15
+ Added@ckeditor/ckeditor5-clipboard@37.1.0(transitive)
+ Added@ckeditor/ckeditor5-core@37.1.0(transitive)
+ Added@ckeditor/ckeditor5-engine@37.1.0(transitive)
+ Added@ckeditor/ckeditor5-enter@37.1.0(transitive)
+ Added@ckeditor/ckeditor5-paragraph@37.1.0(transitive)
+ Added@ckeditor/ckeditor5-select-all@37.1.0(transitive)
+ Added@ckeditor/ckeditor5-typing@37.1.0(transitive)
+ Added@ckeditor/ckeditor5-ui@37.1.0(transitive)
+ Added@ckeditor/ckeditor5-undo@37.1.0(transitive)
+ Added@ckeditor/ckeditor5-upload@37.1.0(transitive)
+ Added@ckeditor/ckeditor5-utils@37.1.0(transitive)
+ Added@ckeditor/ckeditor5-watchdog@37.1.0(transitive)
+ Added@ckeditor/ckeditor5-widget@37.1.0(transitive)
+ Addedckeditor5@37.1.0(transitive)
- Removed@ckeditor/ckeditor5-clipboard@36.0.1(transitive)
- Removed@ckeditor/ckeditor5-core@36.0.1(transitive)
- Removed@ckeditor/ckeditor5-engine@36.0.1(transitive)
- Removed@ckeditor/ckeditor5-enter@36.0.1(transitive)
- Removed@ckeditor/ckeditor5-paragraph@36.0.1(transitive)
- Removed@ckeditor/ckeditor5-select-all@36.0.1(transitive)
- Removed@ckeditor/ckeditor5-typing@36.0.1(transitive)
- Removed@ckeditor/ckeditor5-ui@36.0.1(transitive)
- Removed@ckeditor/ckeditor5-undo@36.0.1(transitive)
- Removed@ckeditor/ckeditor5-upload@36.0.1(transitive)
- Removed@ckeditor/ckeditor5-utils@36.0.1(transitive)
- Removed@ckeditor/ckeditor5-widget@36.0.1(transitive)
- Removedckeditor5@36.0.1(transitive)
Updatedckeditor5@^37.0.0-alpha.0