@ckeditor/ckeditor5-alignment 35.4.0 → 36.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md CHANGED
@@ -2,7 +2,7 @@ Software License Agreement
2
2
  ==========================
3
3
 
4
4
  **CKEditor 5 text alignment feature** – https://github.com/ckeditor/ckeditor5-alignment <br>
5
- Copyright (c) 2003-2022, [CKSource Holding sp. z o.o.](https://cksource.com) All rights reserved.
5
+ Copyright (c) 2003-2023, [CKSource Holding sp. z o.o.](https://cksource.com) All rights reserved.
6
6
 
7
7
  Licensed under the terms of [GNU General Public License Version 2 or later](http://www.gnu.org/licenses/gpl.html).
8
8
 
@@ -1,5 +1,5 @@
1
1
  !function(t){const e=t.en=t.en||{};e.dictionary=Object.assign(e.dictionary||{},{"Align center":"Align center","Align left":"Align left","Align right":"Align right",Justify:"Justify","Text alignment":"Text alignment","Text alignment toolbar":"Text alignment toolbar"})}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={})),
2
2
  /*!
3
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
3
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
4
4
  * For licensing, see LICENSE.md.
5
- */(()=>{var t={704:(t,e,n)=>{t.exports=n(79)("./src/core.js")},273:(t,e,n)=>{t.exports=n(79)("./src/ui.js")},209:(t,e,n)=>{t.exports=n(79)("./src/utils.js")},79:t=>{"use strict";t.exports=CKEditor5.dll}},e={};function n(i){var o=e[i];if(void 0!==o)return o.exports;var r=e[i]={exports:{}};return t[i](r,r.exports,n),r.exports}n.d=(t,e)=>{for(var i in e)n.o(e,i)&&!n.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:e[i]})},n.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),n.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var i={};(()=>{"use strict";n.r(i),n.d(i,{Alignment:()=>f,AlignmentEditing:()=>g,AlignmentUI:()=>d});var t=n(704),e=n(209);const o=["left","right","center","justify"];function r(t){return o.includes(t)}function a(t,e){return"rtl"==e.contentLanguageDirection?"right"===t:"left"===t}function s(t){const n=t.map((t=>{let e;return e="string"==typeof t?{name:t}:t,e})).filter((t=>{const n=!!o.includes(t.name);return n||(0,e.logWarning)("alignment-config-name-not-recognized",{option:t}),n})),i=n.filter((t=>!!t.className)).length;if(i&&i<n.length)throw new e.CKEditorError("alignment-config-classnames-are-missing",{configuredOptions:t});return n.forEach(((n,i,o)=>{const r=o.slice(i+1);if(r.some((t=>t.name==n.name)))throw new e.CKEditorError("alignment-config-name-already-defined",{option:n,configuredOptions:t});if(n.className){if(r.some((t=>t.className==n.className)))throw new e.CKEditorError("alignment-config-classname-already-defined",{option:n,configuredOptions:t})}})),n}const l="alignment";class c extends t.Command{refresh(){const t=this.editor.locale,n=(0,e.first)(this.editor.model.document.selection.getSelectedBlocks());this.isEnabled=!!n&&this._canBeAligned(n),this.isEnabled&&n.hasAttribute("alignment")?this.value=n.getAttribute("alignment"):this.value="rtl"===t.contentLanguageDirection?"right":"left"}execute(t={}){const e=this.editor,n=e.locale,i=e.model,o=i.document,r=t.value;i.change((t=>{const e=Array.from(o.selection.getSelectedBlocks()).filter((t=>this._canBeAligned(t))),i=e[0].getAttribute("alignment");a(r,n)||i===r||!r?function(t,e){for(const n of t)e.removeAttribute(l,n)}(e,t):function(t,e,n){for(const i of t)e.setAttribute(l,n,i)}(e,t,r)}))}_canBeAligned(t){return this.editor.model.schema.checkAttribute(t,l)}}class g extends t.Plugin{static get pluginName(){return"AlignmentEditing"}constructor(t){super(t),t.config.define("alignment",{options:[...o.map((t=>({name:t})))]})}init(){const t=this.editor,e=t.locale,n=t.model.schema,i=s(t.config.get("alignment.options")).filter((t=>r(t.name)&&!a(t.name,e))),o=i.some((t=>!!t.className));n.extend("$block",{allowAttributes:"alignment"}),t.model.schema.setAttributeProperties("alignment",{isFormatting:!0}),o?t.conversion.attributeToAttribute(function(t){const e={model:{key:"alignment",values:t.map((t=>t.name))},view:{}};for(const n of t)e.view[n.name]={key:"class",value:n.className};return e}(i)):t.conversion.for("downcast").attributeToAttribute(function(t){const e={model:{key:"alignment",values:t.map((t=>t.name))},view:{}};for(const{name:n}of t)e.view[n]={key:"style",value:{"text-align":n}};return e}(i));const l=function(t){const e=[];for(const{name:n}of t)e.push({view:{key:"style",value:{"text-align":n}},model:{key:"alignment",value:n}});return e}(i);for(const e of l)t.conversion.for("upcast").attributeToAttribute(e);const g=function(t){const e=[];for(const{name:n}of t)e.push({view:{key:"align",value:n},model:{key:"alignment",value:n}});return e}(i);for(const e of g)t.conversion.for("upcast").attributeToAttribute(e);t.commands.add("alignment",new c(t))}}var u=n(273);const m=new Map([["left",t.icons.alignLeft],["right",t.icons.alignRight],["center",t.icons.alignCenter],["justify",t.icons.alignJustify]]);class d extends t.Plugin{get localizedOptionTitles(){const t=this.editor.t;return{left:t("Align left"),right:t("Align right"),center:t("Align center"),justify:t("Justify")}}static get pluginName(){return"AlignmentUI"}init(){const t=this.editor,e=t.ui.componentFactory,n=t.t,i=s(t.config.get("alignment.options"));i.map((t=>t.name)).filter(r).forEach((t=>this._addButton(t))),e.add("alignment",(o=>{const r=(0,u.createDropdown)(o),a=i.map((t=>e.create(`alignment:${t.name}`)));(0,u.addToolbarToDropdown)(r,a,{enableActiveItemFocusOnDropdownOpen:!0}),r.buttonView.set({label:n("Text alignment"),tooltip:!0}),r.toolbarView.isVertical=!0,r.toolbarView.ariaLabel=n("Text alignment toolbar"),r.extendTemplate({attributes:{class:"ck-alignment-dropdown"}});const s="rtl"===o.contentLanguageDirection?m.get("right"):m.get("left");return r.buttonView.bind("icon").toMany(a,"isOn",((...t)=>{const e=t.findIndex((t=>t));return e<0?s:a[e].icon})),r.bind("isEnabled").toMany(a,"isEnabled",((...t)=>t.some((t=>t)))),this.listenTo(r,"execute",(()=>{t.editing.view.focus()})),r}))}_addButton(t){const e=this.editor;e.ui.componentFactory.add(`alignment:${t}`,(n=>{const i=e.commands.get("alignment"),o=new u.ButtonView(n);return o.set({label:this.localizedOptionTitles[t],icon:m.get(t),tooltip:!0,isToggleable:!0}),o.bind("isEnabled").to(i),o.bind("isOn").to(i,"value",(e=>e===t)),this.listenTo(o,"execute",(()=>{e.execute("alignment",{value:t}),e.editing.view.focus()})),o}))}}class f extends t.Plugin{static get requires(){return[g,d]}static get pluginName(){return"Alignment"}}})(),(window.CKEditor5=window.CKEditor5||{}).alignment=i})();
5
+ */(()=>{var t={704:(t,e,n)=>{t.exports=n(79)("./src/core.js")},273:(t,e,n)=>{t.exports=n(79)("./src/ui.js")},209:(t,e,n)=>{t.exports=n(79)("./src/utils.js")},79:t=>{"use strict";t.exports=CKEditor5.dll}},e={};function n(i){var o=e[i];if(void 0!==o)return o.exports;var r=e[i]={exports:{}};return t[i](r,r.exports,n),r.exports}n.d=(t,e)=>{for(var i in e)n.o(e,i)&&!n.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:e[i]})},n.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),n.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var i={};(()=>{"use strict";n.r(i),n.d(i,{Alignment:()=>f,AlignmentEditing:()=>g,AlignmentUI:()=>d});var t=n(704),e=n(209);const o=["left","right","center","justify"];function r(t){return o.includes(t)}function a(t,e){return"rtl"==e.contentLanguageDirection?"right"===t:"left"===t}function s(t){const n=t.map((t=>{let e;return e="string"==typeof t?{name:t}:t,e})).filter((t=>{const n=o.includes(t.name);return n||(0,e.logWarning)("alignment-config-name-not-recognized",{option:t}),n})),i=n.filter((t=>Boolean(t.className))).length;if(i&&i<n.length)throw new e.CKEditorError("alignment-config-classnames-are-missing",{configuredOptions:t});return n.forEach(((n,i,o)=>{const r=o.slice(i+1);if(r.some((t=>t.name==n.name)))throw new e.CKEditorError("alignment-config-name-already-defined",{option:n,configuredOptions:t});if(n.className){if(r.some((t=>t.className==n.className)))throw new e.CKEditorError("alignment-config-classname-already-defined",{option:n,configuredOptions:t})}})),n}const l="alignment";class c extends t.Command{refresh(){const t=this.editor.locale,n=(0,e.first)(this.editor.model.document.selection.getSelectedBlocks());this.isEnabled=Boolean(n)&&this._canBeAligned(n),this.isEnabled&&n.hasAttribute("alignment")?this.value=n.getAttribute("alignment"):this.value="rtl"===t.contentLanguageDirection?"right":"left"}execute(t={}){const e=this.editor,n=e.locale,i=e.model,o=i.document,r=t.value;i.change((t=>{const e=Array.from(o.selection.getSelectedBlocks()).filter((t=>this._canBeAligned(t))),i=e[0].getAttribute("alignment");a(r,n)||i===r||!r?function(t,e){for(const n of t)e.removeAttribute(l,n)}(e,t):function(t,e,n){for(const i of t)e.setAttribute(l,n,i)}(e,t,r)}))}_canBeAligned(t){return this.editor.model.schema.checkAttribute(t,l)}}class g extends t.Plugin{static get pluginName(){return"AlignmentEditing"}constructor(t){super(t),t.config.define("alignment",{options:o.map((t=>({name:t})))})}init(){const t=this.editor,e=t.locale,n=t.model.schema,i=s(t.config.get("alignment.options")).filter((t=>r(t.name)&&!a(t.name,e))),o=i.some((t=>!!t.className));n.extend("$block",{allowAttributes:"alignment"}),t.model.schema.setAttributeProperties("alignment",{isFormatting:!0}),o?t.conversion.attributeToAttribute(function(t){const e={};for(const n of t)e[n.name]={key:"class",value:n.className};const n={model:{key:"alignment",values:t.map((t=>t.name))},view:e};return n}(i)):t.conversion.for("downcast").attributeToAttribute(function(t){const e={};for(const{name:n}of t)e[n]={key:"style",value:{"text-align":n}};const n={model:{key:"alignment",values:t.map((t=>t.name))},view:e};return n}(i));const l=function(t){const e=[];for(const{name:n}of t)e.push({view:{key:"style",value:{"text-align":n}},model:{key:"alignment",value:n}});return e}(i);for(const e of l)t.conversion.for("upcast").attributeToAttribute(e);const g=function(t){const e=[];for(const{name:n}of t)e.push({view:{key:"align",value:n},model:{key:"alignment",value:n}});return e}(i);for(const e of g)t.conversion.for("upcast").attributeToAttribute(e);t.commands.add("alignment",new c(t))}}var u=n(273);const m=new Map([["left",t.icons.alignLeft],["right",t.icons.alignRight],["center",t.icons.alignCenter],["justify",t.icons.alignJustify]]);class d extends t.Plugin{get localizedOptionTitles(){const t=this.editor.t;return{left:t("Align left"),right:t("Align right"),center:t("Align center"),justify:t("Justify")}}static get pluginName(){return"AlignmentUI"}init(){const t=this.editor,e=t.ui.componentFactory,n=t.t,i=s(t.config.get("alignment.options"));i.map((t=>t.name)).filter(r).forEach((t=>this._addButton(t))),e.add("alignment",(o=>{const r=(0,u.createDropdown)(o);(0,u.addToolbarToDropdown)(r,(()=>i.map((t=>e.create(`alignment:${t.name}`)))),{enableActiveItemFocusOnDropdownOpen:!0,isVertical:!0,ariaLabel:n("Text alignment toolbar")}),r.buttonView.set({label:n("Text alignment"),tooltip:!0}),r.extendTemplate({attributes:{class:"ck-alignment-dropdown"}});const a="rtl"===o.contentLanguageDirection?m.get("right"):m.get("left"),s=t.commands.get("alignment");return r.buttonView.bind("icon").to(s,"value",(t=>m.get(t)||a)),r.bind("isEnabled").to(s,"isEnabled"),this.listenTo(r,"execute",(()=>{t.editing.view.focus()})),r}))}_addButton(t){const e=this.editor;e.ui.componentFactory.add(`alignment:${t}`,(n=>{const i=e.commands.get("alignment"),o=new u.ButtonView(n);return o.set({label:this.localizedOptionTitles[t],icon:m.get(t),tooltip:!0,isToggleable:!0}),o.bind("isEnabled").to(i),o.bind("isOn").to(i,"value",(e=>e===t)),this.listenTo(o,"execute",(()=>{e.execute("alignment",{value:t}),e.editing.view.focus()})),o}))}}class f extends t.Plugin{static get requires(){return[g,d]}static get pluginName(){return"Alignment"}}})(),(window.CKEditor5=window.CKEditor5||{}).alignment=i})();
@@ -1 +1 @@
1
- !function(n){const i=n.ug=n.ug||{};i.dictionary=Object.assign(i.dictionary||{},{"Align center":"ئوتتۇرىغا توغرىلاش","Align left":"سولغا توغرىلاش","Align right":"ئوڭغا توغرىلاش",Justify:"تەكشىلەش","Text alignment":"تېكىست توغرىلاش","Text alignment toolbar":"تېكىست توغرىلاش قورالبالدىقى"})}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={}));
1
+ !function(n){const i=n.ug=n.ug||{};i.dictionary=Object.assign(i.dictionary||{},{"Align center":"ئوتتۇرىغا توغرىلاش","Align left":"سولغا توغرىلاش","Align right":"ئوڭغا توغرىلاش",Justify:"ئوڭ سولدىن توغرىلا","Text alignment":"تېكىست توغرىلاش","Text alignment toolbar":"تېكىست توغرىلاش قورالبالدىقى"})}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={}));
@@ -30,7 +30,7 @@ msgstr "ئوتتۇرىغا توغرىلاش"
30
30
 
31
31
  msgctxt "Toolbar button tooltip for making the text justified."
32
32
  msgid "Justify"
33
- msgstr "تەكشىلەش"
33
+ msgstr "ئوڭ سولدىن توغرىلا"
34
34
 
35
35
  msgctxt "Dropdown button tooltip for the text alignment feature."
36
36
  msgid "Text alignment"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ckeditor/ckeditor5-alignment",
3
- "version": "35.4.0",
3
+ "version": "36.0.0",
4
4
  "description": "Text alignment feature for CKEditor 5.",
5
5
  "keywords": [
6
6
  "ckeditor",
@@ -12,21 +12,22 @@
12
12
  ],
13
13
  "main": "src/index.js",
14
14
  "dependencies": {
15
- "ckeditor5": "^35.4.0"
15
+ "ckeditor5": "^36.0.0"
16
16
  },
17
17
  "devDependencies": {
18
- "@ckeditor/ckeditor5-block-quote": "^35.4.0",
19
- "@ckeditor/ckeditor5-core": "^35.4.0",
20
- "@ckeditor/ckeditor5-dev-utils": "^31.0.0",
21
- "@ckeditor/ckeditor5-editor-classic": "^35.4.0",
22
- "@ckeditor/ckeditor5-engine": "^35.4.0",
23
- "@ckeditor/ckeditor5-enter": "^35.4.0",
24
- "@ckeditor/ckeditor5-heading": "^35.4.0",
25
- "@ckeditor/ckeditor5-image": "^35.4.0",
26
- "@ckeditor/ckeditor5-list": "^35.4.0",
27
- "@ckeditor/ckeditor5-paragraph": "^35.4.0",
28
- "@ckeditor/ckeditor5-theme-lark": "^35.4.0",
29
- "@ckeditor/ckeditor5-typing": "^35.4.0",
18
+ "@ckeditor/ckeditor5-block-quote": "^36.0.0",
19
+ "@ckeditor/ckeditor5-core": "^36.0.0",
20
+ "@ckeditor/ckeditor5-dev-utils": "^32.0.0",
21
+ "@ckeditor/ckeditor5-editor-classic": "^36.0.0",
22
+ "@ckeditor/ckeditor5-engine": "^36.0.0",
23
+ "@ckeditor/ckeditor5-enter": "^36.0.0",
24
+ "@ckeditor/ckeditor5-heading": "^36.0.0",
25
+ "@ckeditor/ckeditor5-image": "^36.0.0",
26
+ "@ckeditor/ckeditor5-list": "^36.0.0",
27
+ "@ckeditor/ckeditor5-paragraph": "^36.0.0",
28
+ "@ckeditor/ckeditor5-theme-lark": "^36.0.0",
29
+ "@ckeditor/ckeditor5-typing": "^36.0.0",
30
+ "typescript": "^4.8.4",
30
31
  "webpack": "^5.58.1",
31
32
  "webpack-cli": "^4.9.0"
32
33
  },
@@ -45,13 +46,16 @@
45
46
  },
46
47
  "files": [
47
48
  "lang",
48
- "src",
49
+ "src/**/*.js",
50
+ "src/**/*.d.ts",
49
51
  "theme",
50
52
  "build",
51
53
  "ckeditor5-metadata.json",
52
54
  "CHANGELOG.md"
53
55
  ],
54
56
  "scripts": {
55
- "dll:build": "webpack"
57
+ "dll:build": "webpack",
58
+ "build": "tsc -p ./tsconfig.release.json",
59
+ "postversion": "npm run build"
56
60
  }
57
61
  }
package/src/alignment.js CHANGED
@@ -1,17 +1,13 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
-
6
5
  /**
7
6
  * @module alignment/alignment
8
7
  */
9
-
10
8
  import { Plugin } from 'ckeditor5/src/core';
11
-
12
9
  import AlignmentEditing from './alignmentediting';
13
10
  import AlignmentUI from './alignmentui';
14
-
15
11
  /**
16
12
  * The text alignment plugin.
17
13
  *
@@ -20,86 +16,18 @@ import AlignmentUI from './alignmentui';
20
16
  *
21
17
  * This is a "glue" plugin which loads the {@link module:alignment/alignmentediting~AlignmentEditing} and
22
18
  * {@link module:alignment/alignmentui~AlignmentUI} plugins.
23
- *
24
- * @extends module:core/plugin~Plugin
25
19
  */
26
20
  export default class Alignment extends Plugin {
27
- /**
28
- * @inheritDoc
29
- */
30
- static get requires() {
31
- return [ AlignmentEditing, AlignmentUI ];
32
- }
33
-
34
- /**
35
- * @inheritDoc
36
- */
37
- static get pluginName() {
38
- return 'Alignment';
39
- }
21
+ /**
22
+ * @inheritDoc
23
+ */
24
+ static get requires() {
25
+ return [AlignmentEditing, AlignmentUI];
26
+ }
27
+ /**
28
+ * @inheritDoc
29
+ */
30
+ static get pluginName() {
31
+ return 'Alignment';
32
+ }
40
33
  }
41
-
42
- /**
43
- * The configuration of the {@link module:alignment/alignment~Alignment alignment feature}.
44
- *
45
- * Read more in {@link module:alignment/alignment~AlignmentConfig}.
46
- *
47
- * @member {module:alignment/alignment~AlignmentConfig} module:core/editor/editorconfig~EditorConfig#alignment
48
- */
49
-
50
- /**
51
- * The configuration of the {@link module:alignment/alignment~Alignment alignment feature}.
52
- *
53
- * ClassicEditor
54
- * .create( editorElement, {
55
- * alignment: {
56
- * options: [ 'left', 'right' ]
57
- * }
58
- * } )
59
- * .then( ... )
60
- * .catch( ... );
61
- *
62
- * See {@link module:core/editor/editorconfig~EditorConfig all editor configuration options}.
63
- *
64
- * @interface AlignmentConfig
65
- */
66
-
67
- /**
68
- * Available alignment options.
69
- *
70
- * The available options are: `'left'`, `'right'`, `'center'` and `'justify'`. Other values are ignored.
71
- *
72
- * **Note:** It is recommended to always use `'left'` or `'right'` as these are default values which the user should
73
- * normally be able to choose depending on the
74
- * {@glink features/ui-language#setting-the-language-of-the-content language of the editor content}.
75
- *
76
- * ClassicEditor
77
- * .create( editorElement, {
78
- * alignment: {
79
- * options: [ 'left', 'right' ]
80
- * }
81
- * } )
82
- * .then( ... )
83
- * .catch( ... );
84
- *
85
- * By default the alignment is set inline using the `text-align` CSS property. To further customize the alignment,
86
- * you can provide names of classes for each alignment option using the `className` property.
87
- *
88
- * **Note:** Once you define the `className` property for one option, you need to specify it for all other options.
89
- *
90
- * ClassicEditor
91
- * .create( editorElement, {
92
- * alignment: {
93
- * options: [
94
- * { name: 'left', className: 'my-align-left' },
95
- * { name: 'right', className: 'my-align-right' }
96
- * ]
97
- * }
98
- * } )
99
- * .then( ... )
100
- * .catch( ... );
101
- *
102
- * See the demo of {@glink features/text-alignment#configuring-alignment-options custom alignment options}.
103
- *
104
- * @member {Array.<String|module:alignment/alignmentediting~AlignmentFormat>} module:alignment/alignment~AlignmentConfig#options
105
- */
@@ -1,110 +1,88 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
-
6
5
  /**
7
6
  * @module alignment/alignmentcommand
8
7
  */
9
-
10
8
  import { Command } from 'ckeditor5/src/core';
11
9
  import { first } from 'ckeditor5/src/utils';
12
-
13
10
  import { isDefault } from './utils';
14
-
15
11
  const ALIGNMENT = 'alignment';
16
-
17
12
  /**
18
13
  * The alignment command plugin.
19
- *
20
- * @extends module:core/command~Command
21
14
  */
22
15
  export default class AlignmentCommand extends Command {
23
- /**
24
- * @inheritDoc
25
- */
26
- refresh() {
27
- const editor = this.editor;
28
- const locale = editor.locale;
29
- const firstBlock = first( this.editor.model.document.selection.getSelectedBlocks() );
30
-
31
- // As first check whether to enable or disable the command as the value will always be false if the command cannot be enabled.
32
- this.isEnabled = !!firstBlock && this._canBeAligned( firstBlock );
33
-
34
- /**
35
- * A value of the current block's alignment.
36
- *
37
- * @observable
38
- * @readonly
39
- * @member {String} #value
40
- */
41
- if ( this.isEnabled && firstBlock.hasAttribute( 'alignment' ) ) {
42
- this.value = firstBlock.getAttribute( 'alignment' );
43
- } else {
44
- this.value = locale.contentLanguageDirection === 'rtl' ? 'right' : 'left';
45
- }
46
- }
47
-
48
- /**
49
- * Executes the command. Applies the alignment `value` to the selected blocks.
50
- * If no `value` is passed, the `value` is the default one or it is equal to the currently selected block's alignment attribute,
51
- * the command will remove the attribute from the selected blocks.
52
- *
53
- * @param {Object} [options] Options for the executed command.
54
- * @param {String} [options.value] The value to apply.
55
- * @fires execute
56
- */
57
- execute( options = {} ) {
58
- const editor = this.editor;
59
- const locale = editor.locale;
60
- const model = editor.model;
61
- const doc = model.document;
62
-
63
- const value = options.value;
64
-
65
- model.change( writer => {
66
- // Get only those blocks from selected that can have alignment set
67
- const blocks = Array.from( doc.selection.getSelectedBlocks() ).filter( block => this._canBeAligned( block ) );
68
- const currentAlignment = blocks[ 0 ].getAttribute( 'alignment' );
69
-
70
- // Remove alignment attribute if current alignment is:
71
- // - default (should not be stored in model as it will bloat model data)
72
- // - equal to currently set
73
- // - or no value is passed - denotes default alignment.
74
- const removeAlignment = isDefault( value, locale ) || currentAlignment === value || !value;
75
-
76
- if ( removeAlignment ) {
77
- removeAlignmentFromSelection( blocks, writer );
78
- } else {
79
- setAlignmentOnSelection( blocks, writer, value );
80
- }
81
- } );
82
- }
83
-
84
- /**
85
- * Checks whether a block can have alignment set.
86
- *
87
- * @private
88
- * @param {module:engine/model/element~Element} block The block to be checked.
89
- * @returns {Boolean}
90
- */
91
- _canBeAligned( block ) {
92
- return this.editor.model.schema.checkAttribute( block, ALIGNMENT );
93
- }
16
+ /**
17
+ * @inheritDoc
18
+ */
19
+ refresh() {
20
+ const editor = this.editor;
21
+ const locale = editor.locale;
22
+ const firstBlock = first(this.editor.model.document.selection.getSelectedBlocks());
23
+ // As first check whether to enable or disable the command as the value will always be false if the command cannot be enabled.
24
+ this.isEnabled = Boolean(firstBlock) && this._canBeAligned(firstBlock);
25
+ if (this.isEnabled && firstBlock.hasAttribute('alignment')) {
26
+ this.value = firstBlock.getAttribute('alignment');
27
+ }
28
+ else {
29
+ this.value = locale.contentLanguageDirection === 'rtl' ? 'right' : 'left';
30
+ }
31
+ }
32
+ /**
33
+ * Executes the command. Applies the alignment `value` to the selected blocks.
34
+ * If no `value` is passed, the `value` is the default one or it is equal to the currently selected block's alignment attribute,
35
+ * the command will remove the attribute from the selected blocks.
36
+ *
37
+ * @param options Options for the executed command.
38
+ * @param options.value The value to apply.
39
+ * @fires execute
40
+ */
41
+ execute(options = {}) {
42
+ const editor = this.editor;
43
+ const locale = editor.locale;
44
+ const model = editor.model;
45
+ const doc = model.document;
46
+ const value = options.value;
47
+ model.change(writer => {
48
+ // Get only those blocks from selected that can have alignment set
49
+ const blocks = Array.from(doc.selection.getSelectedBlocks()).filter(block => this._canBeAligned(block));
50
+ const currentAlignment = blocks[0].getAttribute('alignment');
51
+ // Remove alignment attribute if current alignment is:
52
+ // - default (should not be stored in model as it will bloat model data)
53
+ // - equal to currently set
54
+ // - or no value is passed - denotes default alignment.
55
+ const removeAlignment = isDefault(value, locale) || currentAlignment === value || !value;
56
+ if (removeAlignment) {
57
+ removeAlignmentFromSelection(blocks, writer);
58
+ }
59
+ else {
60
+ setAlignmentOnSelection(blocks, writer, value);
61
+ }
62
+ });
63
+ }
64
+ /**
65
+ * Checks whether a block can have alignment set.
66
+ *
67
+ * @param block The block to be checked.
68
+ */
69
+ _canBeAligned(block) {
70
+ return this.editor.model.schema.checkAttribute(block, ALIGNMENT);
71
+ }
94
72
  }
95
-
96
- // Removes the alignment attribute from blocks.
97
- // @private
98
- function removeAlignmentFromSelection( blocks, writer ) {
99
- for ( const block of blocks ) {
100
- writer.removeAttribute( ALIGNMENT, block );
101
- }
73
+ /**
74
+ * Removes the alignment attribute from blocks.
75
+ */
76
+ function removeAlignmentFromSelection(blocks, writer) {
77
+ for (const block of blocks) {
78
+ writer.removeAttribute(ALIGNMENT, block);
79
+ }
102
80
  }
103
-
104
- // Sets the alignment attribute on blocks.
105
- // @private
106
- function setAlignmentOnSelection( blocks, writer, alignment ) {
107
- for ( const block of blocks ) {
108
- writer.setAttribute( ALIGNMENT, alignment, block );
109
- }
81
+ /**
82
+ * Sets the alignment attribute on blocks.
83
+ */
84
+ function setAlignmentOnSelection(blocks, writer, alignment) {
85
+ for (const block of blocks) {
86
+ writer.setAttribute(ALIGNMENT, alignment, block);
87
+ }
110
88
  }
@@ -1,188 +1,147 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
-
6
5
  /**
7
6
  * @module alignment/alignmentediting
8
7
  */
9
-
10
8
  import { Plugin } from 'ckeditor5/src/core';
11
-
12
9
  import AlignmentCommand from './alignmentcommand';
13
10
  import { isDefault, isSupported, normalizeAlignmentOptions, supportedOptions } from './utils';
14
-
15
11
  /**
16
12
  * The alignment editing feature. It introduces the {@link module:alignment/alignmentcommand~AlignmentCommand command} and adds
17
13
  * the `alignment` attribute for block elements in the {@link module:engine/model/model~Model model}.
18
- * @extends module:core/plugin~Plugin
19
14
  */
20
15
  export default class AlignmentEditing extends Plugin {
21
- /**
22
- * @inheritDoc
23
- */
24
- static get pluginName() {
25
- return 'AlignmentEditing';
26
- }
27
-
28
- /**
29
- * @inheritDoc
30
- */
31
- constructor( editor ) {
32
- super( editor );
33
-
34
- editor.config.define( 'alignment', {
35
- options: [ ...supportedOptions.map( option => ( { name: option } ) ) ]
36
- } );
37
- }
38
-
39
- /**
40
- * @inheritDoc
41
- */
42
- init() {
43
- const editor = this.editor;
44
- const locale = editor.locale;
45
- const schema = editor.model.schema;
46
-
47
- const options = normalizeAlignmentOptions( editor.config.get( 'alignment.options' ) );
48
-
49
- // Filter out unsupported options and those that are redundant, e.g. `left` in LTR / `right` in RTL mode.
50
- const optionsToConvert = options.filter(
51
- option => isSupported( option.name ) && !isDefault( option.name, locale )
52
- );
53
-
54
- // Once there is at least one `className` defined, we switch to alignment with classes.
55
- const shouldUseClasses = optionsToConvert.some( option => !!option.className );
56
-
57
- // Allow alignment attribute on all blocks.
58
- schema.extend( '$block', { allowAttributes: 'alignment' } );
59
- editor.model.schema.setAttributeProperties( 'alignment', { isFormatting: true } );
60
-
61
- if ( shouldUseClasses ) {
62
- editor.conversion.attributeToAttribute( buildClassDefinition( optionsToConvert ) );
63
- } else {
64
- // Downcast inline styles.
65
- editor.conversion.for( 'downcast' ).attributeToAttribute( buildDowncastInlineDefinition( optionsToConvert ) );
66
- }
67
-
68
- const upcastInlineDefinitions = buildUpcastInlineDefinitions( optionsToConvert );
69
-
70
- // Always upcast from inline styles.
71
- for ( const definition of upcastInlineDefinitions ) {
72
- editor.conversion.for( 'upcast' ).attributeToAttribute( definition );
73
- }
74
-
75
- const upcastCompatibilityDefinitions = buildUpcastCompatibilityDefinitions( optionsToConvert );
76
-
77
- // Always upcast from deprecated `align` attribute.
78
- for ( const definition of upcastCompatibilityDefinitions ) {
79
- editor.conversion.for( 'upcast' ).attributeToAttribute( definition );
80
- }
81
-
82
- editor.commands.add( 'alignment', new AlignmentCommand( editor ) );
83
- }
16
+ /**
17
+ * @inheritDoc
18
+ */
19
+ static get pluginName() {
20
+ return 'AlignmentEditing';
21
+ }
22
+ /**
23
+ * @inheritDoc
24
+ */
25
+ constructor(editor) {
26
+ super(editor);
27
+ editor.config.define('alignment', {
28
+ options: supportedOptions.map(option => ({ name: option }))
29
+ });
30
+ }
31
+ /**
32
+ * @inheritDoc
33
+ */
34
+ init() {
35
+ const editor = this.editor;
36
+ const locale = editor.locale;
37
+ const schema = editor.model.schema;
38
+ const options = normalizeAlignmentOptions(editor.config.get('alignment.options'));
39
+ // Filter out unsupported options and those that are redundant, e.g. `left` in LTR / `right` in RTL mode.
40
+ const optionsToConvert = options.filter(option => isSupported(option.name) && !isDefault(option.name, locale));
41
+ // Once there is at least one `className` defined, we switch to alignment with classes.
42
+ const shouldUseClasses = optionsToConvert.some(option => !!option.className);
43
+ // Allow alignment attribute on all blocks.
44
+ schema.extend('$block', { allowAttributes: 'alignment' });
45
+ editor.model.schema.setAttributeProperties('alignment', { isFormatting: true });
46
+ if (shouldUseClasses) {
47
+ editor.conversion.attributeToAttribute(buildClassDefinition(optionsToConvert));
48
+ }
49
+ else {
50
+ // Downcast inline styles.
51
+ editor.conversion.for('downcast').attributeToAttribute(buildDowncastInlineDefinition(optionsToConvert));
52
+ }
53
+ const upcastInlineDefinitions = buildUpcastInlineDefinitions(optionsToConvert);
54
+ // Always upcast from inline styles.
55
+ for (const definition of upcastInlineDefinitions) {
56
+ editor.conversion.for('upcast').attributeToAttribute(definition);
57
+ }
58
+ const upcastCompatibilityDefinitions = buildUpcastCompatibilityDefinitions(optionsToConvert);
59
+ // Always upcast from deprecated `align` attribute.
60
+ for (const definition of upcastCompatibilityDefinitions) {
61
+ editor.conversion.for('upcast').attributeToAttribute(definition);
62
+ }
63
+ editor.commands.add('alignment', new AlignmentCommand(editor));
64
+ }
84
65
  }
85
-
86
- // Prepare downcast conversion definition for inline alignment styling.
87
- // @private
88
- function buildDowncastInlineDefinition( options ) {
89
- const definition = {
90
- model: {
91
- key: 'alignment',
92
- values: options.map( option => option.name )
93
- },
94
- view: {}
95
- };
96
-
97
- for ( const { name } of options ) {
98
- definition.view[ name ] = {
99
- key: 'style',
100
- value: {
101
- 'text-align': name
102
- }
103
- };
104
- }
105
-
106
- return definition;
107
- }
108
-
109
- // Prepare upcast definitions for inline alignment styles.
110
- // @private
111
- function buildUpcastInlineDefinitions( options ) {
112
- const definitions = [];
113
-
114
- for ( const { name } of options ) {
115
- definitions.push( {
116
- view: {
117
- key: 'style',
118
- value: {
119
- 'text-align': name
120
- }
121
- },
122
- model: {
123
- key: 'alignment',
124
- value: name
125
- }
126
- } );
127
- }
128
-
129
- return definitions;
66
+ /**
67
+ * Prepare downcast conversion definition for inline alignment styling.
68
+ */
69
+ function buildDowncastInlineDefinition(options) {
70
+ const view = {};
71
+ for (const { name } of options) {
72
+ view[name] = {
73
+ key: 'style',
74
+ value: {
75
+ 'text-align': name
76
+ }
77
+ };
78
+ }
79
+ const definition = {
80
+ model: {
81
+ key: 'alignment',
82
+ values: options.map(option => option.name)
83
+ },
84
+ view
85
+ };
86
+ return definition;
130
87
  }
131
-
132
- // Prepare upcast definitions for deprecated `align` attribute.
133
- // @private
134
- function buildUpcastCompatibilityDefinitions( options ) {
135
- const definitions = [];
136
-
137
- for ( const { name } of options ) {
138
- definitions.push( {
139
- view: {
140
- key: 'align',
141
- value: name
142
- },
143
- model: {
144
- key: 'alignment',
145
- value: name
146
- }
147
- } );
148
- }
149
-
150
- return definitions;
88
+ /**
89
+ * Prepare upcast definitions for inline alignment styles.
90
+ */
91
+ function buildUpcastInlineDefinitions(options) {
92
+ const definitions = [];
93
+ for (const { name } of options) {
94
+ definitions.push({
95
+ view: {
96
+ key: 'style',
97
+ value: {
98
+ 'text-align': name
99
+ }
100
+ },
101
+ model: {
102
+ key: 'alignment',
103
+ value: name
104
+ }
105
+ });
106
+ }
107
+ return definitions;
151
108
  }
152
-
153
- // Prepare conversion definitions for upcast and downcast alignment with classes.
154
- // @private
155
- function buildClassDefinition( options ) {
156
- const definition = {
157
- model: {
158
- key: 'alignment',
159
- values: options.map( option => option.name )
160
- },
161
- view: {}
162
- };
163
-
164
- for ( const option of options ) {
165
- definition.view[ option.name ] = {
166
- key: 'class',
167
- value: option.className
168
- };
169
- }
170
-
171
- return definition;
109
+ /**
110
+ * Prepare upcast definitions for deprecated `align` attribute.
111
+ */
112
+ function buildUpcastCompatibilityDefinitions(options) {
113
+ const definitions = [];
114
+ for (const { name } of options) {
115
+ definitions.push({
116
+ view: {
117
+ key: 'align',
118
+ value: name
119
+ },
120
+ model: {
121
+ key: 'alignment',
122
+ value: name
123
+ }
124
+ });
125
+ }
126
+ return definitions;
172
127
  }
173
-
174
128
  /**
175
- * The alignment configuration format descriptor.
176
- *
177
- * const alignmentFormat = {
178
- * name: 'right',
179
- * className: 'my-align-right-class'
180
- * }
181
- *
182
- * @typedef {Object} module:alignment/alignmentediting~AlignmentFormat
183
- *
184
- * @property {'left'|'right'|'center'|'justify'} name One of the alignment names options.
185
- *
186
- * @property {String} className The CSS class used to represent the style in the view.
187
- * Used to override default, inline styling for alignment.
129
+ * Prepare conversion definitions for upcast and downcast alignment with classes.
188
130
  */
131
+ function buildClassDefinition(options) {
132
+ const view = {};
133
+ for (const option of options) {
134
+ view[option.name] = {
135
+ key: 'class',
136
+ value: option.className
137
+ };
138
+ }
139
+ const definition = {
140
+ model: {
141
+ key: 'alignment',
142
+ values: options.map(option => option.name)
143
+ },
144
+ view
145
+ };
146
+ return definition;
147
+ }
@@ -1,162 +1,124 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
-
6
5
  /**
7
6
  * @module alignment/alignmentui
8
7
  */
9
-
10
8
  import { Plugin, icons } from 'ckeditor5/src/core';
11
9
  import { ButtonView, createDropdown, addToolbarToDropdown } from 'ckeditor5/src/ui';
12
-
13
10
  import { isSupported, normalizeAlignmentOptions } from './utils';
14
-
15
- const iconsMap = new Map( [
16
- [ 'left', icons.alignLeft ],
17
- [ 'right', icons.alignRight ],
18
- [ 'center', icons.alignCenter ],
19
- [ 'justify', icons.alignJustify ]
20
- ] );
21
-
11
+ const iconsMap = new Map([
12
+ ['left', icons.alignLeft],
13
+ ['right', icons.alignRight],
14
+ ['center', icons.alignCenter],
15
+ ['justify', icons.alignJustify]
16
+ ]);
22
17
  /**
23
18
  * The default alignment UI plugin.
24
19
  *
25
20
  * It introduces the `'alignment:left'`, `'alignment:right'`, `'alignment:center'` and `'alignment:justify'` buttons
26
21
  * and the `'alignment'` dropdown.
27
- *
28
- * @extends module:core/plugin~Plugin
29
22
  */
30
23
  export default class AlignmentUI extends Plugin {
31
- /**
32
- * Returns the localized option titles provided by the plugin.
33
- *
34
- * The following localized titles corresponding with
35
- * {@link module:alignment/alignment~AlignmentConfig#options} are available:
36
- *
37
- * * `'left'`,
38
- * * `'right'`,
39
- * * `'center'`,
40
- * * `'justify'`.
41
- *
42
- * @readonly
43
- * @type {Object.<String,String>}
44
- */
45
- get localizedOptionTitles() {
46
- const t = this.editor.t;
47
-
48
- return {
49
- 'left': t( 'Align left' ),
50
- 'right': t( 'Align right' ),
51
- 'center': t( 'Align center' ),
52
- 'justify': t( 'Justify' )
53
- };
54
- }
55
-
56
- /**
57
- * @inheritDoc
58
- */
59
- static get pluginName() {
60
- return 'AlignmentUI';
61
- }
62
-
63
- /**
64
- * @inheritDoc
65
- */
66
- init() {
67
- const editor = this.editor;
68
- const componentFactory = editor.ui.componentFactory;
69
- const t = editor.t;
70
- const options = normalizeAlignmentOptions( editor.config.get( 'alignment.options' ) );
71
-
72
- options
73
- .map( option => option.name )
74
- .filter( isSupported )
75
- .forEach( option => this._addButton( option ) );
76
-
77
- componentFactory.add( 'alignment', locale => {
78
- const dropdownView = createDropdown( locale );
79
-
80
- // Add existing alignment buttons to dropdown's toolbar.
81
- const buttons = options.map( option => componentFactory.create( `alignment:${ option.name }` ) );
82
- addToolbarToDropdown( dropdownView, buttons, { enableActiveItemFocusOnDropdownOpen: true } );
83
-
84
- // Configure dropdown properties an behavior.
85
- dropdownView.buttonView.set( {
86
- label: t( 'Text alignment' ),
87
- tooltip: true
88
- } );
89
-
90
- dropdownView.toolbarView.isVertical = true;
91
- dropdownView.toolbarView.ariaLabel = t( 'Text alignment toolbar' );
92
-
93
- dropdownView.extendTemplate( {
94
- attributes: {
95
- class: 'ck-alignment-dropdown'
96
- }
97
- } );
98
-
99
- // The default icon depends on the direction of the content.
100
- const defaultIcon = locale.contentLanguageDirection === 'rtl' ? iconsMap.get( 'right' ) : iconsMap.get( 'left' );
101
-
102
- // Change icon to reflect current selection's alignment.
103
- dropdownView.buttonView.bind( 'icon' ).toMany( buttons, 'isOn', ( ...areActive ) => {
104
- // Get the index of an active button.
105
- const index = areActive.findIndex( value => value );
106
-
107
- // If none of the commands is active, display either defaultIcon or the first button's icon.
108
- if ( index < 0 ) {
109
- return defaultIcon;
110
- }
111
-
112
- // Return active button's icon.
113
- return buttons[ index ].icon;
114
- } );
115
-
116
- // Enable button if any of the buttons is enabled.
117
- dropdownView.bind( 'isEnabled' ).toMany( buttons, 'isEnabled', ( ...areEnabled ) => areEnabled.some( isEnabled => isEnabled ) );
118
-
119
- // Focus the editable after executing the command.
120
- // Overrides a default behaviour where the focus is moved to the dropdown button (#12125).
121
- this.listenTo( dropdownView, 'execute', () => {
122
- editor.editing.view.focus();
123
- } );
124
-
125
- return dropdownView;
126
- } );
127
- }
128
-
129
- /**
130
- * Helper method for initializing the button and linking it with an appropriate command.
131
- *
132
- * @private
133
- * @param {String} option The name of the alignment option for which the button is added.
134
- */
135
- _addButton( option ) {
136
- const editor = this.editor;
137
-
138
- editor.ui.componentFactory.add( `alignment:${ option }`, locale => {
139
- const command = editor.commands.get( 'alignment' );
140
- const buttonView = new ButtonView( locale );
141
-
142
- buttonView.set( {
143
- label: this.localizedOptionTitles[ option ],
144
- icon: iconsMap.get( option ),
145
- tooltip: true,
146
- isToggleable: true
147
- } );
148
-
149
- // Bind button model to command.
150
- buttonView.bind( 'isEnabled' ).to( command );
151
- buttonView.bind( 'isOn' ).to( command, 'value', value => value === option );
152
-
153
- // Execute command.
154
- this.listenTo( buttonView, 'execute', () => {
155
- editor.execute( 'alignment', { value: option } );
156
- editor.editing.view.focus();
157
- } );
158
-
159
- return buttonView;
160
- } );
161
- }
24
+ /**
25
+ * Returns the localized option titles provided by the plugin.
26
+ *
27
+ * The following localized titles corresponding with
28
+ * {@link module:alignment/alignment~AlignmentConfig#options} are available:
29
+ *
30
+ * * `'left'`,
31
+ * * `'right'`,
32
+ * * `'center'`,
33
+ * * `'justify'`.
34
+ *
35
+ * @readonly
36
+ */
37
+ get localizedOptionTitles() {
38
+ const t = this.editor.t;
39
+ return {
40
+ 'left': t('Align left'),
41
+ 'right': t('Align right'),
42
+ 'center': t('Align center'),
43
+ 'justify': t('Justify')
44
+ };
45
+ }
46
+ /**
47
+ * @inheritDoc
48
+ */
49
+ static get pluginName() {
50
+ return 'AlignmentUI';
51
+ }
52
+ /**
53
+ * @inheritDoc
54
+ */
55
+ init() {
56
+ const editor = this.editor;
57
+ const componentFactory = editor.ui.componentFactory;
58
+ const t = editor.t;
59
+ const options = normalizeAlignmentOptions(editor.config.get('alignment.options'));
60
+ options
61
+ .map(option => option.name)
62
+ .filter(isSupported)
63
+ .forEach(option => this._addButton(option));
64
+ componentFactory.add('alignment', locale => {
65
+ const dropdownView = createDropdown(locale);
66
+ // Add existing alignment buttons to dropdown's toolbar.
67
+ addToolbarToDropdown(dropdownView, () => options.map(option => componentFactory.create(`alignment:${option.name}`)), {
68
+ enableActiveItemFocusOnDropdownOpen: true,
69
+ isVertical: true,
70
+ ariaLabel: t('Text alignment toolbar')
71
+ });
72
+ // Configure dropdown properties an behavior.
73
+ dropdownView.buttonView.set({
74
+ label: t('Text alignment'),
75
+ tooltip: true
76
+ });
77
+ dropdownView.extendTemplate({
78
+ attributes: {
79
+ class: 'ck-alignment-dropdown'
80
+ }
81
+ });
82
+ // The default icon depends on the direction of the content.
83
+ const defaultIcon = locale.contentLanguageDirection === 'rtl' ? iconsMap.get('right') : iconsMap.get('left');
84
+ const command = editor.commands.get('alignment');
85
+ // Change icon to reflect current selection's alignment.
86
+ dropdownView.buttonView.bind('icon').to(command, 'value', value => iconsMap.get(value) || defaultIcon);
87
+ // Enable button if any of the buttons is enabled.
88
+ dropdownView.bind('isEnabled').to(command, 'isEnabled');
89
+ // Focus the editable after executing the command.
90
+ // Overrides a default behaviour where the focus is moved to the dropdown button (#12125).
91
+ this.listenTo(dropdownView, 'execute', () => {
92
+ editor.editing.view.focus();
93
+ });
94
+ return dropdownView;
95
+ });
96
+ }
97
+ /**
98
+ * Helper method for initializing the button and linking it with an appropriate command.
99
+ *
100
+ * @param option The name of the alignment option for which the button is added.
101
+ */
102
+ _addButton(option) {
103
+ const editor = this.editor;
104
+ editor.ui.componentFactory.add(`alignment:${option}`, locale => {
105
+ const command = editor.commands.get('alignment');
106
+ const buttonView = new ButtonView(locale);
107
+ buttonView.set({
108
+ label: this.localizedOptionTitles[option],
109
+ icon: iconsMap.get(option),
110
+ tooltip: true,
111
+ isToggleable: true
112
+ });
113
+ // Bind button model to command.
114
+ buttonView.bind('isEnabled').to(command);
115
+ buttonView.bind('isOn').to(command, 'value', value => value === option);
116
+ // Execute command.
117
+ this.listenTo(buttonView, 'execute', () => {
118
+ editor.execute('alignment', { value: option });
119
+ editor.editing.view.focus();
120
+ });
121
+ return buttonView;
122
+ });
123
+ }
162
124
  }
package/src/index.js CHANGED
@@ -1,12 +1,10 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
-
6
5
  /**
7
6
  * @module alignment
8
7
  */
9
-
10
8
  export { default as Alignment } from './alignment';
11
9
  export { default as AlignmentEditing } from './alignmentediting';
12
10
  export { default as AlignmentUI } from './alignmentui';
package/src/utils.js CHANGED
@@ -1,14 +1,11 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
-
6
5
  import { CKEditorError, logWarning } from 'ckeditor5/src/utils';
7
-
8
6
  /**
9
7
  * @module alignment/utils
10
8
  */
11
-
12
9
  /**
13
10
  * The list of supported alignment options:
14
11
  *
@@ -17,119 +14,105 @@ import { CKEditorError, logWarning } from 'ckeditor5/src/utils';
17
14
  * * `'center'`,
18
15
  * * `'justify'`
19
16
  */
20
- export const supportedOptions = [ 'left', 'right', 'center', 'justify' ];
21
-
17
+ export const supportedOptions = ['left', 'right', 'center', 'justify'];
22
18
  /**
23
19
  * Checks whether the passed option is supported by {@link module:alignment/alignmentediting~AlignmentEditing}.
24
20
  *
25
- * @param {String} option The option value to check.
26
- * @returns {Boolean}
21
+ * @param option The option value to check.
27
22
  */
28
- export function isSupported( option ) {
29
- return supportedOptions.includes( option );
23
+ export function isSupported(option) {
24
+ return supportedOptions.includes(option);
30
25
  }
31
-
32
26
  /**
33
27
  * Checks whether alignment is the default one considering the direction
34
28
  * of the editor content.
35
29
  *
36
- * @param {String} alignment The name of the alignment to check.
37
- * @param {module:utils/locale~Locale} locale The {@link module:core/editor/editor~Editor#locale} instance.
38
- * @returns {Boolean}
30
+ * @param alignment The name of the alignment to check.
31
+ * @param locale The {@link module:core/editor/editor~Editor#locale} instance.
39
32
  */
40
- export function isDefault( alignment, locale ) {
41
- // Right now only LTR is supported so the 'left' value is always the default one.
42
-
43
- if ( locale.contentLanguageDirection == 'rtl' ) {
44
- return alignment === 'right';
45
- } else {
46
- return alignment === 'left';
47
- }
33
+ export function isDefault(alignment, locale) {
34
+ // Right now only LTR is supported so the 'left' value is always the default one.
35
+ if (locale.contentLanguageDirection == 'rtl') {
36
+ return alignment === 'right';
37
+ }
38
+ else {
39
+ return alignment === 'left';
40
+ }
48
41
  }
49
-
50
42
  /**
51
43
  * Brings the configuration to the common form, an array of objects.
52
44
  *
53
- * @param {Array.<String|module:alignment/alignmentediting~AlignmentFormat>} configuredOptions Alignment plugin configuration.
54
- * @returns {Array.<module:alignment/alignmentediting~AlignmentFormat>} Normalized object holding the configuration.
45
+ * @param configuredOptions Alignment plugin configuration.
46
+ * @returns Normalized object holding the configuration.
55
47
  */
56
- export function normalizeAlignmentOptions( configuredOptions ) {
57
- const normalizedOptions = configuredOptions
58
- .map( option => {
59
- let result;
60
-
61
- if ( typeof option == 'string' ) {
62
- result = { name: option };
63
- } else {
64
- result = option;
65
- }
66
-
67
- return result;
68
- } )
69
- // Remove all unknown options.
70
- .filter( option => {
71
- const isNameValid = !!supportedOptions.includes( option.name );
72
- if ( !isNameValid ) {
73
- /**
74
- * The `name` in one of the `alignment.options` is not recognized.
75
- * The available options are: `'left'`, `'right'`, `'center'` and `'justify'`.
76
- *
77
- * @error alignment-config-name-not-recognized
78
- * @param {Object} option Options with unknown value of the `name` property.
79
- */
80
- logWarning( 'alignment-config-name-not-recognized', { option } );
81
- }
82
-
83
- return isNameValid;
84
- } );
85
-
86
- const classNameCount = normalizedOptions.filter( option => !!option.className ).length;
87
-
88
- // We either use classes for all styling options or for none.
89
- if ( classNameCount && classNameCount < normalizedOptions.length ) {
90
- /**
91
- * The `className` property has to be defined for all options once at least one option declares `className`.
92
- *
93
- * @error alignment-config-classnames-are-missing
94
- * @param {Array.<String|module:alignment/alignmentediting~AlignmentFormat>} configuredOptions Contents of `alignment.options`.
95
- */
96
- throw new CKEditorError( 'alignment-config-classnames-are-missing', { configuredOptions } );
97
- }
98
-
99
- // Validate resulting config.
100
- normalizedOptions.forEach( ( option, index, allOptions ) => {
101
- const succeedingOptions = allOptions.slice( index + 1 );
102
- const nameAlreadyExists = succeedingOptions.some( item => item.name == option.name );
103
-
104
- if ( nameAlreadyExists ) {
105
- /**
106
- * The same `name` in one of the `alignment.options` was already declared.
107
- * Each `name` representing one alignment option can be set exactly once.
108
- *
109
- * @error alignment-config-name-already-defined
110
- * @param {Object} option First option that declares given `name`.
111
- * @param {Array.<String|module:alignment/alignmentediting~AlignmentFormat>} configuredOptions Contents of `alignment.options`.
112
- */
113
- throw new CKEditorError( 'alignment-config-name-already-defined', { option, configuredOptions } );
114
- }
115
-
116
- // The `className` property is present. Check for duplicates then.
117
- if ( option.className ) {
118
- const classNameAlreadyExists = succeedingOptions.some( item => item.className == option.className );
119
-
120
- if ( classNameAlreadyExists ) {
121
- /**
122
- * The same `className` in one of the `alignment.options` was already declared.
123
- *
124
- * @error alignment-config-classname-already-defined
125
- * @param {Object} option First option that declares given `className`.
126
- * @param {Array.<String|module:alignment/alignmentediting~AlignmentFormat>} configuredOptions
127
- * Contents of `alignment.options`.
128
- */
129
- throw new CKEditorError( 'alignment-config-classname-already-defined', { option, configuredOptions } );
130
- }
131
- }
132
- } );
133
-
134
- return normalizedOptions;
48
+ export function normalizeAlignmentOptions(configuredOptions) {
49
+ const normalizedOptions = configuredOptions
50
+ .map(option => {
51
+ let result;
52
+ if (typeof option == 'string') {
53
+ result = { name: option };
54
+ }
55
+ else {
56
+ result = option;
57
+ }
58
+ return result;
59
+ })
60
+ // Remove all unknown options.
61
+ .filter(option => {
62
+ const isNameValid = supportedOptions.includes(option.name);
63
+ if (!isNameValid) {
64
+ /**
65
+ * The `name` in one of the `alignment.options` is not recognized.
66
+ * The available options are: `'left'`, `'right'`, `'center'` and `'justify'`.
67
+ *
68
+ * @error alignment-config-name-not-recognized
69
+ * @param option Options with unknown value of the `name` property.
70
+ */
71
+ logWarning('alignment-config-name-not-recognized', { option });
72
+ }
73
+ return isNameValid;
74
+ });
75
+ const classNameCount = normalizedOptions.filter(option => Boolean(option.className)).length;
76
+ // We either use classes for all styling options or for none.
77
+ if (classNameCount && classNameCount < normalizedOptions.length) {
78
+ /**
79
+ * The `className` property has to be defined for all options once at least one option declares `className`.
80
+ *
81
+ * @error alignment-config-classnames-are-missing
82
+ * @param configuredOptions Contents of `alignment.options`.
83
+ */
84
+ throw new CKEditorError('alignment-config-classnames-are-missing', { configuredOptions });
85
+ }
86
+ // Validate resulting config.
87
+ normalizedOptions.forEach((option, index, allOptions) => {
88
+ const succeedingOptions = allOptions.slice(index + 1);
89
+ const nameAlreadyExists = succeedingOptions.some(item => item.name == option.name);
90
+ if (nameAlreadyExists) {
91
+ /**
92
+ * The same `name` in one of the `alignment.options` was already declared.
93
+ * Each `name` representing one alignment option can be set exactly once.
94
+ *
95
+ * @error alignment-config-name-already-defined
96
+ * @param option First option that declares given `name`.
97
+ * @param configuredOptions Contents of `alignment.options`.
98
+ */
99
+ throw new CKEditorError('alignment-config-name-already-defined', { option, configuredOptions });
100
+ }
101
+ // The `className` property is present. Check for duplicates then.
102
+ if (option.className) {
103
+ const classNameAlreadyExists = succeedingOptions.some(item => item.className == option.className);
104
+ if (classNameAlreadyExists) {
105
+ /**
106
+ * The same `className` in one of the `alignment.options` was already declared.
107
+ *
108
+ * @error alignment-config-classname-already-defined
109
+ * @param option First option that declares given `className`.
110
+ * @param configuredOptions
111
+ * Contents of `alignment.options`.
112
+ */
113
+ throw new CKEditorError('alignment-config-classname-already-defined', { option, configuredOptions });
114
+ }
115
+ }
116
+ });
117
+ return normalizedOptions;
135
118
  }