Socket
Socket
Sign inDemoInstall

@ckeditor/ckeditor5-style

Package Overview
Dependencies
Maintainers
1
Versions
599
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ckeditor/ckeditor5-style - npm Package Compare versions

Comparing version 36.0.1 to 37.0.0-alpha.0

src/index.d.ts

2

build/style.js

@@ -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';

@@ -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 &mdash; 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 &mdash; 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();
}
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc