@ckeditor/ckeditor5-word-count 48.2.0 → 48.3.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,19 +1,19 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
3
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
- */
5
- import type { WordCount, WordCountConfig } from './index.js';
6
- declare module '@ckeditor/ckeditor5-core' {
7
- interface EditorConfig {
8
- /**
9
- * The configuration of the word count feature.
10
- * It is introduced by the {@link module:word-count/wordcount~WordCount} feature.
11
- *
12
- * Read more in {@link module:word-count/wordcountconfig~WordCountConfig}.
13
- */
14
- wordCount?: WordCountConfig;
15
- }
16
- interface PluginsMap {
17
- [WordCount.pluginName]: WordCount;
18
- }
2
+ * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
+ */
5
+ import type { WordCount, WordCountConfig } from "./index.js";
6
+ declare module "@ckeditor/ckeditor5-core" {
7
+ interface EditorConfig {
8
+ /**
9
+ * The configuration of the word count feature.
10
+ * It is introduced by the {@link module:word-count/wordcount~WordCount} feature.
11
+ *
12
+ * Read more in {@link module:word-count/wordcountconfig~WordCountConfig}.
13
+ */
14
+ wordCount?: WordCountConfig;
15
+ }
16
+ interface PluginsMap {
17
+ [WordCount.pluginName]: WordCount;
18
+ }
19
19
  }
@@ -2,3 +2,4 @@
2
2
  * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
4
  */
5
+
@@ -2,3 +2,4 @@
2
2
  * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
4
  */
5
+
package/dist/index.css CHANGED
@@ -3,5 +3,3 @@
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
4
  */
5
5
 
6
-
7
- /*# sourceMappingURL=index.css.map */
package/dist/index.d.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
3
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
- */
2
+ * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
+ */
5
5
  /**
6
- * @module word-count
7
- */
8
- export { WordCount, type WordCountUpdateEvent } from './wordcount.js';
9
- export type { WordCountConfig } from './wordcountconfig.js';
10
- export { modelElementToPlainText as _modelElementToPlainText } from './utils.js';
11
- import './augmentation.js';
6
+ * @module word-count
7
+ */
8
+ export { WordCount, type WordCountUpdateEvent } from "./wordcount.js";
9
+ export type { WordCountConfig } from "./wordcountconfig.js";
10
+ export { modelElementToPlainText as _modelElementToPlainText } from "./utils.js";
11
+ import "./augmentation.js";
package/dist/index.js CHANGED
@@ -2,260 +2,238 @@
2
2
  * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
4
  */
5
- import { Plugin } from '@ckeditor/ckeditor5-core/dist/index.js';
6
- import { Template, View } from '@ckeditor/ckeditor5-ui/dist/index.js';
7
- import { env } from '@ckeditor/ckeditor5-utils/dist/index.js';
8
- import { throttle, isElement } from 'es-toolkit/compat';
5
+ import { Plugin } from "@ckeditor/ckeditor5-core";
6
+ import { Template, View } from "@ckeditor/ckeditor5-ui";
7
+ import { env } from "@ckeditor/ckeditor5-utils";
8
+ import { isElement, throttle } from "es-toolkit/compat";
9
9
 
10
10
  /**
11
- * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
12
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
13
- */ /**
14
- * @module word-count/utils
15
- */ /**
16
- * Returns a plain text representation of an element and its children.
17
- *
18
- * @internal
19
- * @returns Plain text representing the model's data.
20
- */ function modelElementToPlainText(item) {
21
- if (item.is('$text') || item.is('$textProxy')) {
22
- return item.data;
23
- }
24
- const element = item;
25
- let text = '';
26
- let prev = null;
27
- for (const child of element.getChildren()){
28
- const childText = modelElementToPlainText(child);
29
- // If last block was finish, start from new line.
30
- if (prev && prev.is('element')) {
31
- text += '\n';
32
- }
33
- text += childText;
34
- prev = child;
35
- }
36
- return text;
11
+ * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
12
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
13
+ */
14
+ /**
15
+ * Returns a plain text representation of an element and its children.
16
+ *
17
+ * @internal
18
+ * @returns Plain text representing the model's data.
19
+ */
20
+ function modelElementToPlainText(item) {
21
+ if (item.is("$text") || item.is("$textProxy")) return item.data;
22
+ const element = item;
23
+ let text = "";
24
+ let prev = null;
25
+ for (const child of element.getChildren()) {
26
+ const childText = modelElementToPlainText(child);
27
+ if (prev && prev.is("element")) text += "\n";
28
+ text += childText;
29
+ prev = child;
30
+ }
31
+ return text;
37
32
  }
38
33
 
39
34
  /**
40
- * The word count plugin.
41
- *
42
- * This plugin calculates all words and characters in all {@link module:engine/model/text~ModelText text nodes} available in the model.
43
- * It also provides an HTML element that updates its state whenever the editor content is changed.
44
- *
45
- * The model's data is first converted to plain text using {@link module:word-count/utils~modelElementToPlainText}.
46
- * The number of words and characters in your text are determined based on the created plain text. Please keep in mind
47
- * that every block in the editor is separated with a newline character, which is included in the calculation.
48
- *
49
- * Here are some examples of how the word and character calculations are made:
50
- *
51
- * ```html
52
- * <paragraph>foo</paragraph>
53
- * <paragraph>bar</paragraph>
54
- * // Words: 2, Characters: 7
55
- *
56
- * <paragraph><$text bold="true">foo</$text>bar</paragraph>
57
- * // Words: 1, Characters: 6
58
- *
59
- * <paragraph>*&^%)</paragraph>
60
- * // Words: 0, Characters: 5
61
- *
62
- * <paragraph>foo(bar)</paragraph>
63
- * //Words: 1, Characters: 8
64
- *
65
- * <paragraph>12345</paragraph>
66
- * // Words: 1, Characters: 5
67
- * ```
68
- */ class WordCount extends Plugin {
69
- /**
70
- * The configuration of this plugin.
71
- */ _config;
72
- /**
73
- * The reference to a {@link module:ui/view~View view object} that contains the self-updating HTML container.
74
- */ _outputView;
75
- /**
76
- * A regular expression used to recognize words in the editor's content.
77
- */ _wordsMatchRegExp;
78
- /**
79
- * @inheritDoc
80
- */ constructor(editor){
81
- super(editor);
82
- this.set('characters', 0);
83
- this.set('words', 0);
84
- // Don't wait for the #update event to set the value of the properties but obtain it right away.
85
- // This way, accessing the properties directly returns precise numbers, e.g. for validation, etc.
86
- // If not accessed directly, the properties will be refreshed upon #update anyway.
87
- Object.defineProperties(this, {
88
- characters: {
89
- get () {
90
- return this.characters = this._getCharacters(this._getText());
91
- }
92
- },
93
- words: {
94
- get () {
95
- return this.words = this._getWords(this._getText());
96
- }
97
- }
98
- });
99
- this.set('_wordsLabel', undefined);
100
- this.set('_charactersLabel', undefined);
101
- this._config = editor.config.get('wordCount') || {};
102
- this._outputView = undefined;
103
- this._wordsMatchRegExp = env.features.isRegExpUnicodePropertySupported ? // Usage of regular expression literal cause error during build (ckeditor/ckeditor5-dev#534).
104
- // Groups:
105
- // {L} - Any kind of letter from any language.
106
- // {N} - Any kind of numeric character in any script.
107
- new RegExp('([\\p{L}\\p{N}]+\\S?)+', 'gu') : /([a-zA-Z0-9À-ž]+\S?)+/gu;
108
- }
109
- /**
110
- * @inheritDoc
111
- */ static get pluginName() {
112
- return 'WordCount';
113
- }
114
- /**
115
- * @inheritDoc
116
- * @internal
117
- */ static get licenseFeatureCode() {
118
- return 'WC';
119
- }
120
- /**
121
- * @inheritDoc
122
- */ static get isOfficialPlugin() {
123
- return true;
124
- }
125
- /**
126
- * @inheritDoc
127
- */ static get isPremiumPlugin() {
128
- return true;
129
- }
130
- /**
131
- * @inheritDoc
132
- */ init() {
133
- const editor = this.editor;
134
- editor.model.document.on('change:data', throttle(this._refreshStats.bind(this), 250));
135
- if (typeof this._config.onUpdate == 'function') {
136
- this.on('update', (evt, data)=>{
137
- this._config.onUpdate(data);
138
- });
139
- }
140
- if (isElement(this._config.container)) {
141
- this._config.container.appendChild(this.wordCountContainer);
142
- }
143
- }
144
- /**
145
- * @inheritDoc
146
- */ destroy() {
147
- if (this._outputView) {
148
- this._outputView.element.remove();
149
- this._outputView.destroy();
150
- }
151
- super.destroy();
152
- }
153
- /**
154
- * Creates a self-updating HTML element. Repeated executions return the same element.
155
- * The returned element has the following HTML structure:
156
- *
157
- * ```html
158
- * <div class="ck ck-word-count">
159
- * <div class="ck-word-count__words">Words: 4</div>
160
- * <div class="ck-word-count__characters">Characters: 28</div>
161
- * </div>
162
- * ```
163
- */ get wordCountContainer() {
164
- const editor = this.editor;
165
- const t = editor.t;
166
- const displayWords = editor.config.get('wordCount.displayWords');
167
- const displayCharacters = editor.config.get('wordCount.displayCharacters');
168
- const bind = Template.bind(this, this);
169
- const children = [];
170
- if (!this._outputView) {
171
- this._outputView = new View();
172
- if (displayWords || displayWords === undefined) {
173
- this.bind('_wordsLabel').to(this, 'words', (words)=>{
174
- return t('Words: %0', words);
175
- });
176
- children.push({
177
- tag: 'div',
178
- children: [
179
- {
180
- text: [
181
- bind.to('_wordsLabel')
182
- ]
183
- }
184
- ],
185
- attributes: {
186
- class: 'ck-word-count__words'
187
- }
188
- });
189
- }
190
- if (displayCharacters || displayCharacters === undefined) {
191
- this.bind('_charactersLabel').to(this, 'characters', (words)=>{
192
- return t('Characters: %0', words);
193
- });
194
- children.push({
195
- tag: 'div',
196
- children: [
197
- {
198
- text: [
199
- bind.to('_charactersLabel')
200
- ]
201
- }
202
- ],
203
- attributes: {
204
- class: 'ck-word-count__characters'
205
- }
206
- });
207
- }
208
- this._outputView.setTemplate({
209
- tag: 'div',
210
- attributes: {
211
- class: [
212
- 'ck',
213
- 'ck-word-count'
214
- ]
215
- },
216
- children
217
- });
218
- this._outputView.render();
219
- }
220
- return this._outputView.element;
221
- }
222
- _getText() {
223
- let txt = '';
224
- for (const root of this.editor.model.document.getRoots()){
225
- if (txt !== '') {
226
- // Add a delimiter, so words from each root are treated independently.
227
- txt += '\n';
228
- }
229
- txt += modelElementToPlainText(root);
230
- }
231
- return txt;
232
- }
233
- /**
234
- * Determines the number of characters in the current editor's model.
235
- */ _getCharacters(txt) {
236
- return txt.replace(/\n/g, '').length;
237
- }
238
- /**
239
- * Determines the number of words in the current editor's model.
240
- */ _getWords(txt) {
241
- const detectedWords = txt.match(this._wordsMatchRegExp) || [];
242
- return detectedWords.length;
243
- }
244
- /**
245
- * Determines the number of words and characters in the current editor's model and assigns it to {@link #characters} and {@link #words}.
246
- * It also fires the {@link #event:update}.
247
- *
248
- * @fires update
249
- */ _refreshStats() {
250
- const txt = this._getText();
251
- const words = this.words = this._getWords(txt);
252
- const characters = this.characters = this._getCharacters(txt);
253
- this.fire('update', {
254
- words,
255
- characters
256
- });
257
- }
258
- }
35
+ * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
36
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
37
+ */
38
+ /**
39
+ * The word count plugin.
40
+ *
41
+ * This plugin calculates all words and characters in all {@link module:engine/model/text~ModelText text nodes} available in the model.
42
+ * It also provides an HTML element that updates its state whenever the editor content is changed.
43
+ *
44
+ * The model's data is first converted to plain text using {@link module:word-count/utils~modelElementToPlainText}.
45
+ * The number of words and characters in your text are determined based on the created plain text. Please keep in mind
46
+ * that every block in the editor is separated with a newline character, which is included in the calculation.
47
+ *
48
+ * Here are some examples of how the word and character calculations are made:
49
+ *
50
+ * ```html
51
+ * <paragraph>foo</paragraph>
52
+ * <paragraph>bar</paragraph>
53
+ * // Words: 2, Characters: 7
54
+ *
55
+ * <paragraph><$text bold="true">foo</$text>bar</paragraph>
56
+ * // Words: 1, Characters: 6
57
+ *
58
+ * <paragraph>*&^%)</paragraph>
59
+ * // Words: 0, Characters: 5
60
+ *
61
+ * <paragraph>foo(bar)</paragraph>
62
+ * //Words: 1, Characters: 8
63
+ *
64
+ * <paragraph>12345</paragraph>
65
+ * // Words: 1, Characters: 5
66
+ * ```
67
+ */
68
+ var WordCount = class extends Plugin {
69
+ /**
70
+ * The configuration of this plugin.
71
+ */
72
+ _config;
73
+ /**
74
+ * The reference to a {@link module:ui/view~View view object} that contains the self-updating HTML container.
75
+ */
76
+ _outputView;
77
+ /**
78
+ * A regular expression used to recognize words in the editor's content.
79
+ */
80
+ _wordsMatchRegExp;
81
+ /**
82
+ * @inheritDoc
83
+ */
84
+ constructor(editor) {
85
+ super(editor);
86
+ this.set("characters", 0);
87
+ this.set("words", 0);
88
+ Object.defineProperties(this, {
89
+ characters: { get() {
90
+ return this.characters = this._getCharacters(this._getText());
91
+ } },
92
+ words: { get() {
93
+ return this.words = this._getWords(this._getText());
94
+ } }
95
+ });
96
+ this.set("_wordsLabel", void 0);
97
+ this.set("_charactersLabel", void 0);
98
+ this._config = editor.config.get("wordCount") || {};
99
+ this._outputView = void 0;
100
+ this._wordsMatchRegExp = env.features.isRegExpUnicodePropertySupported ? /* @__PURE__ */ new RegExp("([\\p{L}\\p{N}]+\\S?)+", "gu") : /([a-zA-Z0-9À-ž]+\S?)+/gu;
101
+ }
102
+ /**
103
+ * @inheritDoc
104
+ */
105
+ static get pluginName() {
106
+ return "WordCount";
107
+ }
108
+ /**
109
+ * @inheritDoc
110
+ * @internal
111
+ */
112
+ static get licenseFeatureCode() {
113
+ return "WC";
114
+ }
115
+ /**
116
+ * @inheritDoc
117
+ */
118
+ static get isOfficialPlugin() {
119
+ return true;
120
+ }
121
+ /**
122
+ * @inheritDoc
123
+ */
124
+ static get isPremiumPlugin() {
125
+ return true;
126
+ }
127
+ /**
128
+ * @inheritDoc
129
+ */
130
+ init() {
131
+ this.editor.model.document.on("change:data", throttle(this._refreshStats.bind(this), 250));
132
+ if (typeof this._config.onUpdate == "function") this.on("update", (evt, data) => {
133
+ this._config.onUpdate(data);
134
+ });
135
+ if (isElement(this._config.container)) this._config.container.appendChild(this.wordCountContainer);
136
+ }
137
+ /**
138
+ * @inheritDoc
139
+ */
140
+ destroy() {
141
+ if (this._outputView) {
142
+ this._outputView.element.remove();
143
+ this._outputView.destroy();
144
+ }
145
+ super.destroy();
146
+ }
147
+ /**
148
+ * Creates a self-updating HTML element. Repeated executions return the same element.
149
+ * The returned element has the following HTML structure:
150
+ *
151
+ * ```html
152
+ * <div class="ck ck-word-count">
153
+ * <div class="ck-word-count__words">Words: 4</div>
154
+ * <div class="ck-word-count__characters">Characters: 28</div>
155
+ * </div>
156
+ * ```
157
+ */
158
+ get wordCountContainer() {
159
+ const editor = this.editor;
160
+ const t = editor.t;
161
+ const displayWords = editor.config.get("wordCount.displayWords");
162
+ const displayCharacters = editor.config.get("wordCount.displayCharacters");
163
+ const bind = Template.bind(this, this);
164
+ const children = [];
165
+ if (!this._outputView) {
166
+ this._outputView = new View();
167
+ if (displayWords || displayWords === void 0) {
168
+ this.bind("_wordsLabel").to(this, "words", (words) => {
169
+ return t("Words: %0", words);
170
+ });
171
+ children.push({
172
+ tag: "div",
173
+ children: [{ text: [bind.to("_wordsLabel")] }],
174
+ attributes: { class: "ck-word-count__words" }
175
+ });
176
+ }
177
+ if (displayCharacters || displayCharacters === void 0) {
178
+ this.bind("_charactersLabel").to(this, "characters", (words) => {
179
+ return t("Characters: %0", words);
180
+ });
181
+ children.push({
182
+ tag: "div",
183
+ children: [{ text: [bind.to("_charactersLabel")] }],
184
+ attributes: { class: "ck-word-count__characters" }
185
+ });
186
+ }
187
+ this._outputView.setTemplate({
188
+ tag: "div",
189
+ attributes: { class: ["ck", "ck-word-count"] },
190
+ children
191
+ });
192
+ this._outputView.render();
193
+ }
194
+ return this._outputView.element;
195
+ }
196
+ _getText() {
197
+ let txt = "";
198
+ for (const root of this.editor.model.document.getRoots()) {
199
+ if (txt !== "") txt += "\n";
200
+ txt += modelElementToPlainText(root);
201
+ }
202
+ return txt;
203
+ }
204
+ /**
205
+ * Determines the number of characters in the current editor's model.
206
+ */
207
+ _getCharacters(txt) {
208
+ return txt.replace(/\n/g, "").length;
209
+ }
210
+ /**
211
+ * Determines the number of words in the current editor's model.
212
+ */
213
+ _getWords(txt) {
214
+ return (txt.match(this._wordsMatchRegExp) || []).length;
215
+ }
216
+ /**
217
+ * Determines the number of words and characters in the current editor's model and assigns it to {@link #characters} and {@link #words}.
218
+ * It also fires the {@link #event:update}.
219
+ *
220
+ * @fires update
221
+ */
222
+ _refreshStats() {
223
+ const txt = this._getText();
224
+ const words = this.words = this._getWords(txt);
225
+ const characters = this.characters = this._getCharacters(txt);
226
+ this.fire("update", {
227
+ words,
228
+ characters
229
+ });
230
+ }
231
+ };
232
+
233
+ /**
234
+ * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
235
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
236
+ */
259
237
 
260
238
  export { WordCount, modelElementToPlainText as _modelElementToPlainText };
261
- //# sourceMappingURL=index.js.map
239
+ //# sourceMappingURL=index.js.map