@ckeditor/ckeditor5-utils 47.6.1 → 48.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/LICENSE.md +1 -1
  2. package/{src → dist}/dom/global.d.ts +1 -1
  3. package/{src → dist}/dom/rect.d.ts +8 -0
  4. package/dist/index.css +3 -0
  5. package/dist/index.css.map +1 -0
  6. package/dist/index.js +24 -5
  7. package/dist/index.js.map +1 -1
  8. package/{src → dist}/version.d.ts +1 -1
  9. package/package.json +20 -38
  10. package/src/abortabledebounce.js +0 -22
  11. package/src/areconnectedthroughproperties.js +0 -71
  12. package/src/ckeditorerror.js +0 -187
  13. package/src/collection.js +0 -620
  14. package/src/collectstylesheets.js +0 -52
  15. package/src/comparearrays.js +0 -47
  16. package/src/config.js +0 -167
  17. package/src/count.js +0 -25
  18. package/src/crc32.js +0 -61
  19. package/src/decodelicensekey.js +0 -30
  20. package/src/delay.js +0 -25
  21. package/src/diff.js +0 -115
  22. package/src/difftochanges.js +0 -79
  23. package/src/dom/createelement.js +0 -40
  24. package/src/dom/emittermixin.js +0 -237
  25. package/src/dom/findclosestscrollableancestor.js +0 -31
  26. package/src/dom/getancestors.js +0 -26
  27. package/src/dom/getborderwidths.js +0 -24
  28. package/src/dom/getcommonancestor.js +0 -25
  29. package/src/dom/getdatafromelement.js +0 -19
  30. package/src/dom/getpositionedancestor.js +0 -22
  31. package/src/dom/getrangefrommouseevent.js +0 -33
  32. package/src/dom/getvisualviewportoffset.js +0 -21
  33. package/src/dom/global.js +0 -35
  34. package/src/dom/indexof.js +0 -21
  35. package/src/dom/insertat.js +0 -17
  36. package/src/dom/iscomment.js +0 -13
  37. package/src/dom/isnode.js +0 -21
  38. package/src/dom/isrange.js +0 -13
  39. package/src/dom/istext.js +0 -13
  40. package/src/dom/isvalidattributename.js +0 -22
  41. package/src/dom/isvisible.js +0 -30
  42. package/src/dom/iswindow.js +0 -22
  43. package/src/dom/position.js +0 -322
  44. package/src/dom/rect.js +0 -498
  45. package/src/dom/remove.js +0 -18
  46. package/src/dom/resizeobserver.js +0 -134
  47. package/src/dom/scroll.js +0 -406
  48. package/src/dom/setdatainelement.js +0 -19
  49. package/src/dom/tounit.js +0 -16
  50. package/src/elementreplacer.js +0 -47
  51. package/src/emittermixin.js +0 -443
  52. package/src/env.js +0 -158
  53. package/src/eventinfo.js +0 -63
  54. package/src/fastdiff.js +0 -248
  55. package/src/first.js +0 -17
  56. package/src/focustracker.js +0 -329
  57. package/src/formathtml.js +0 -164
  58. package/src/index.js +0 -78
  59. package/src/inserttopriorityarray.js +0 -28
  60. package/src/isfeatureblockedbylicensekey.js +0 -17
  61. package/src/isiterable.js +0 -16
  62. package/src/keyboard.js +0 -256
  63. package/src/keystrokehandler.js +0 -126
  64. package/src/language.js +0 -21
  65. package/src/legacyerrors.js +0 -18
  66. package/src/locale.js +0 -135
  67. package/src/mapsequal.js +0 -27
  68. package/src/mix.js +0 -5
  69. package/src/nth.js +0 -24
  70. package/src/objecttomap.js +0 -27
  71. package/src/observablemixin.js +0 -575
  72. package/src/parsebase64encodedobject.js +0 -22
  73. package/src/priorities.js +0 -22
  74. package/src/retry.js +0 -48
  75. package/src/splicearray.js +0 -37
  76. package/src/spy.js +0 -21
  77. package/src/toarray.js +0 -7
  78. package/src/tomap.js +0 -29
  79. package/src/translation-service.js +0 -209
  80. package/src/uid.js +0 -45
  81. package/src/unicode.js +0 -85
  82. package/src/version.js +0 -177
  83. package/src/wait.js +0 -29
  84. /package/{src → dist}/abortabledebounce.d.ts +0 -0
  85. /package/{src → dist}/areconnectedthroughproperties.d.ts +0 -0
  86. /package/{src → dist}/ckeditorerror.d.ts +0 -0
  87. /package/{src → dist}/collection.d.ts +0 -0
  88. /package/{src → dist}/collectstylesheets.d.ts +0 -0
  89. /package/{src → dist}/comparearrays.d.ts +0 -0
  90. /package/{src → dist}/config.d.ts +0 -0
  91. /package/{src → dist}/count.d.ts +0 -0
  92. /package/{src → dist}/crc32.d.ts +0 -0
  93. /package/{src → dist}/decodelicensekey.d.ts +0 -0
  94. /package/{src → dist}/delay.d.ts +0 -0
  95. /package/{src → dist}/diff.d.ts +0 -0
  96. /package/{src → dist}/difftochanges.d.ts +0 -0
  97. /package/{src → dist}/dom/createelement.d.ts +0 -0
  98. /package/{src → dist}/dom/emittermixin.d.ts +0 -0
  99. /package/{src → dist}/dom/findclosestscrollableancestor.d.ts +0 -0
  100. /package/{src → dist}/dom/getancestors.d.ts +0 -0
  101. /package/{src → dist}/dom/getborderwidths.d.ts +0 -0
  102. /package/{src → dist}/dom/getcommonancestor.d.ts +0 -0
  103. /package/{src → dist}/dom/getdatafromelement.d.ts +0 -0
  104. /package/{src → dist}/dom/getpositionedancestor.d.ts +0 -0
  105. /package/{src → dist}/dom/getrangefrommouseevent.d.ts +0 -0
  106. /package/{src → dist}/dom/getvisualviewportoffset.d.ts +0 -0
  107. /package/{src → dist}/dom/indexof.d.ts +0 -0
  108. /package/{src → dist}/dom/insertat.d.ts +0 -0
  109. /package/{src → dist}/dom/iscomment.d.ts +0 -0
  110. /package/{src → dist}/dom/isnode.d.ts +0 -0
  111. /package/{src → dist}/dom/isrange.d.ts +0 -0
  112. /package/{src → dist}/dom/istext.d.ts +0 -0
  113. /package/{src → dist}/dom/isvalidattributename.d.ts +0 -0
  114. /package/{src → dist}/dom/isvisible.d.ts +0 -0
  115. /package/{src → dist}/dom/iswindow.d.ts +0 -0
  116. /package/{src → dist}/dom/position.d.ts +0 -0
  117. /package/{src → dist}/dom/remove.d.ts +0 -0
  118. /package/{src → dist}/dom/resizeobserver.d.ts +0 -0
  119. /package/{src → dist}/dom/scroll.d.ts +0 -0
  120. /package/{src → dist}/dom/setdatainelement.d.ts +0 -0
  121. /package/{src → dist}/dom/tounit.d.ts +0 -0
  122. /package/{src → dist}/elementreplacer.d.ts +0 -0
  123. /package/{src → dist}/emittermixin.d.ts +0 -0
  124. /package/{src → dist}/env.d.ts +0 -0
  125. /package/{src → dist}/eventinfo.d.ts +0 -0
  126. /package/{src → dist}/fastdiff.d.ts +0 -0
  127. /package/{src → dist}/first.d.ts +0 -0
  128. /package/{src → dist}/focustracker.d.ts +0 -0
  129. /package/{src → dist}/formathtml.d.ts +0 -0
  130. /package/{src → dist}/index.d.ts +0 -0
  131. /package/{src → dist}/inserttopriorityarray.d.ts +0 -0
  132. /package/{src → dist}/isfeatureblockedbylicensekey.d.ts +0 -0
  133. /package/{src → dist}/isiterable.d.ts +0 -0
  134. /package/{src → dist}/keyboard.d.ts +0 -0
  135. /package/{src → dist}/keystrokehandler.d.ts +0 -0
  136. /package/{src → dist}/language.d.ts +0 -0
  137. /package/{src → dist}/legacyerrors.d.ts +0 -0
  138. /package/{src → dist}/locale.d.ts +0 -0
  139. /package/{src → dist}/mapsequal.d.ts +0 -0
  140. /package/{src → dist}/mix.d.ts +0 -0
  141. /package/{src → dist}/nth.d.ts +0 -0
  142. /package/{src → dist}/objecttomap.d.ts +0 -0
  143. /package/{src → dist}/observablemixin.d.ts +0 -0
  144. /package/{src → dist}/parsebase64encodedobject.d.ts +0 -0
  145. /package/{src → dist}/priorities.d.ts +0 -0
  146. /package/{src → dist}/retry.d.ts +0 -0
  147. /package/{src → dist}/splicearray.d.ts +0 -0
  148. /package/{src → dist}/spy.d.ts +0 -0
  149. /package/{src → dist}/toarray.d.ts +0 -0
  150. /package/{src → dist}/tomap.d.ts +0 -0
  151. /package/{src → dist}/translation-service.d.ts +0 -0
  152. /package/{src → dist}/uid.d.ts +0 -0
  153. /package/{src → dist}/unicode.d.ts +0 -0
  154. /package/{src → dist}/wait.d.ts +0 -0
package/src/formathtml.js DELETED
@@ -1,164 +0,0 @@
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
- /**
6
- * @module utils/formathtml
7
- */
8
- /**
9
- * A simple (and naive) HTML code formatter that returns a formatted HTML markup that can be easily
10
- * parsed by human eyes. It beautifies the HTML code by adding new lines between elements that behave like block elements
11
- * (https://developer.mozilla.org/en-US/docs/Web/HTML/Block-level_elements
12
- * and a few more like `tr`, `td`, and similar ones) and inserting indents for nested content.
13
- *
14
- * WARNING: This function works only on a text that does not contain any indentations or new lines.
15
- * Calling this function on the already formatted text will damage the formatting.
16
- *
17
- * @param input An HTML string to format.
18
- */
19
- export function formatHtml(input) {
20
- // A list of block-like elements around which the new lines should be inserted, and within which
21
- // the indentation of their children should be increased.
22
- // The list is partially based on https://developer.mozilla.org/en-US/docs/Web/HTML/Block-level_elements that contains
23
- // a full list of HTML block-level elements.
24
- // A void element is an element that cannot have any child - https://html.spec.whatwg.org/multipage/syntax.html#void-elements.
25
- // Note that <pre> element is not listed on this list to avoid breaking whitespace formatting.
26
- // Note that <br> element is not listed and handled separately so no additional white spaces are injected.
27
- const elementsToFormat = [
28
- { name: 'address', isVoid: false },
29
- { name: 'article', isVoid: false },
30
- { name: 'aside', isVoid: false },
31
- { name: 'blockquote', isVoid: false },
32
- { name: 'details', isVoid: false },
33
- { name: 'dialog', isVoid: false },
34
- { name: 'dd', isVoid: false },
35
- { name: 'div', isVoid: false },
36
- { name: 'dl', isVoid: false },
37
- { name: 'dt', isVoid: false },
38
- { name: 'fieldset', isVoid: false },
39
- { name: 'figcaption', isVoid: false },
40
- { name: 'figure', isVoid: false },
41
- { name: 'footer', isVoid: false },
42
- { name: 'form', isVoid: false },
43
- { name: 'h1', isVoid: false },
44
- { name: 'h2', isVoid: false },
45
- { name: 'h3', isVoid: false },
46
- { name: 'h4', isVoid: false },
47
- { name: 'h5', isVoid: false },
48
- { name: 'h6', isVoid: false },
49
- { name: 'header', isVoid: false },
50
- { name: 'hgroup', isVoid: false },
51
- { name: 'hr', isVoid: true },
52
- { name: 'li', isVoid: false },
53
- { name: 'main', isVoid: false },
54
- { name: 'nav', isVoid: false },
55
- { name: 'ol', isVoid: false },
56
- { name: 'p', isVoid: false },
57
- { name: 'section', isVoid: false },
58
- { name: 'table', isVoid: false },
59
- { name: 'tbody', isVoid: false },
60
- { name: 'td', isVoid: false },
61
- { name: 'th', isVoid: false },
62
- { name: 'thead', isVoid: false },
63
- { name: 'tr', isVoid: false },
64
- { name: 'ul', isVoid: false }
65
- ];
66
- const elementNamesToFormat = elementsToFormat.map(element => element.name).join('|');
67
- // It is not the fastest way to format the HTML markup but the performance should be good enough.
68
- const lines = input
69
- // Add new line before and after `<tag>` and `</tag>`.
70
- // It may separate individual elements with two new lines, but this will be fixed below.
71
- .replace(new RegExp(`</?(${elementNamesToFormat})( .*?)?>`, 'g'), '\n$&\n')
72
- // Keep `<br>`s at the end of line to avoid adding additional whitespaces before `<br>`.
73
- .replace(/<br[^>]*>/g, '$&\n')
74
- // Divide input string into lines, which start with either an opening tag, a closing tag, or just a text.
75
- .split('\n');
76
- let indentCount = 0;
77
- let isPreformattedLine = false;
78
- return lines
79
- .map(line => {
80
- isPreformattedLine = isPreformattedBlockLine(line, isPreformattedLine);
81
- // Ignore empty lines outside a <pre> block.
82
- if (!line.length && !isPreformattedLine) {
83
- return '';
84
- }
85
- if (isNonVoidOpeningTag(line, elementsToFormat)) {
86
- return indentLine(line, indentCount++);
87
- }
88
- if (isClosingTag(line, elementsToFormat)) {
89
- return indentLine(line, --indentCount);
90
- }
91
- if (isPreformattedLine === 'middle' || isPreformattedLine === 'last') {
92
- return indentLine(line, 0);
93
- }
94
- return indentLine(line, indentCount);
95
- })
96
- .join('')
97
- .trimEnd();
98
- }
99
- /**
100
- * Checks, if an argument is an opening tag of a non-void element to be formatted.
101
- *
102
- * @param line String to check.
103
- * @param elementsToFormat Elements to be formatted.
104
- */
105
- function isNonVoidOpeningTag(line, elementsToFormat) {
106
- return elementsToFormat.some(element => {
107
- if (element.isVoid) {
108
- return false;
109
- }
110
- if (!new RegExp(`<${element.name}( .*?)?>`).test(line)) {
111
- return false;
112
- }
113
- return true;
114
- });
115
- }
116
- /**
117
- * Checks, if an argument is a closing tag.
118
- *
119
- * @param line String to check.
120
- * @param elementsToFormat Elements to be formatted.
121
- */
122
- function isClosingTag(line, elementsToFormat) {
123
- return elementsToFormat.some(element => {
124
- return new RegExp(`</${element.name}>`).test(line);
125
- });
126
- }
127
- /**
128
- * Indents a line by a specified number of characters.
129
- *
130
- * @param line Line to indent.
131
- * @param indentCount Number of characters to use for indentation.
132
- * @param indentChar Indentation character(s). 4 spaces by default.
133
- */
134
- function indentLine(line, indentCount, indentChar = ' ') {
135
- // More about Math.max() here in https://github.com/ckeditor/ckeditor5/issues/10698.
136
- return `${indentChar.repeat(Math.max(0, indentCount))}${line}\n`;
137
- }
138
- /**
139
- * Checks whether a line belongs to a preformatted (`<pre>`) block.
140
- *
141
- * @param line Line to check.
142
- * @param isPreviousLinePreFormatted Information on whether the previous line was preformatted (and how).
143
- */
144
- function isPreformattedBlockLine(line, isPreviousLinePreFormatted) {
145
- const isPreOpen = /<pre( .*?)?>/.test(line);
146
- const isPreClose = /<\/pre>/.test(line);
147
- if (isPreOpen && isPreClose) {
148
- // If both an opening and closing a <pre> tag, no special treatment needed.
149
- return false;
150
- }
151
- else if (isPreOpen) {
152
- return 'first';
153
- }
154
- else if (isPreClose) {
155
- return 'last';
156
- }
157
- else if (isPreviousLinePreFormatted === 'first' || isPreviousLinePreFormatted === 'middle') {
158
- // This line is just after a 'first' or 'middle' line of a multi-line pre-block.
159
- return 'middle';
160
- }
161
- else {
162
- return false;
163
- }
164
- }
package/src/index.js DELETED
@@ -1,78 +0,0 @@
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
- /**
6
- * @module utils/index
7
- */
8
- export { env, getUserAgent as _getUserAgent, isMac as _isMac, isWindows as _isWindows, isGecko as _isGecko, isSafari as _isSafari, isiOS as _isiOS, isAndroid as _isAndroid, isBlink as _isBlink, isRegExpUnicodePropertySupported as _isRegExpUnicodePropertySupported, isMediaForcedColors as _isMediaForcedColors, isMotionReduced as _isMotionReduced } from './env.js';
9
- export { diff } from './diff.js';
10
- export { fastDiff } from './fastdiff.js';
11
- export { diffToChanges } from './difftochanges.js';
12
- export { areConnectedThroughProperties } from './areconnectedthroughproperties.js';
13
- export { _getEmitterListenedTo, _setEmitterId, _getEmitterId, EmitterMixin } from './emittermixin.js';
14
- export { EventInfo } from './eventinfo.js';
15
- export { ObservableMixin } from './observablemixin.js';
16
- export { CKEditorError, logError, logWarning, DOCUMENTATION_URL } from './ckeditorerror.js';
17
- export { ElementReplacer } from './elementreplacer.js';
18
- export { abortableDebounce } from './abortabledebounce.js';
19
- export { count } from './count.js';
20
- export { compareArrays } from './comparearrays.js';
21
- export { createElement } from './dom/createelement.js';
22
- export { Config } from './config.js';
23
- export { isIterable } from './isiterable.js';
24
- export { DomEmitterMixin } from './dom/emittermixin.js';
25
- export { findClosestScrollableAncestor } from './dom/findclosestscrollableancestor.js';
26
- export { global } from './dom/global.js';
27
- export { getAncestors } from './dom/getancestors.js';
28
- export { getDataFromElement } from './dom/getdatafromelement.js';
29
- export { getBorderWidths } from './dom/getborderwidths.js';
30
- export { getRangeFromMouseEvent } from './dom/getrangefrommouseevent.js';
31
- export { getCommonAncestor } from './dom/getcommonancestor.js';
32
- export { getPositionedAncestor } from './dom/getpositionedancestor.js';
33
- export { isText } from './dom/istext.js';
34
- export { isWindow } from './dom/iswindow.js';
35
- export { Rect } from './dom/rect.js';
36
- export { ResizeObserver } from './dom/resizeobserver.js';
37
- export { setDataInElement } from './dom/setdatainelement.js';
38
- export { toUnit } from './dom/tounit.js';
39
- export { indexOf } from './dom/indexof.js';
40
- export { insertAt } from './dom/insertat.js';
41
- export { isComment } from './dom/iscomment.js';
42
- export { isNode } from './dom/isnode.js';
43
- export { isRange } from './dom/isrange.js';
44
- export { isValidAttributeName } from './dom/isvalidattributename.js';
45
- export { isVisible } from './dom/isvisible.js';
46
- export { getOptimalPosition, getConstrainedViewportRect } from './dom/position.js';
47
- export { remove } from './dom/remove.js';
48
- export { getVisualViewportOffset } from './dom/getvisualviewportoffset.js';
49
- export { scrollAncestorsToShowTarget, scrollViewportToShowTarget } from './dom/scroll.js';
50
- export { keyCodes, getCode, parseKeystroke, getEnvKeystrokeText, isArrowKeyCode, getLocalizedArrowKeyCodeDirection, isForwardArrowKeyCode } from './keyboard.js';
51
- export { getLanguageDirection } from './language.js';
52
- export { Locale } from './locale.js';
53
- export { Collection } from './collection.js';
54
- export { first } from './first.js';
55
- export { nth } from './nth.js';
56
- export { FocusTracker, isViewWithFocusTracker } from './focustracker.js';
57
- export { KeystrokeHandler } from './keystrokehandler.js';
58
- export { toArray } from './toarray.js';
59
- export { toMap } from './tomap.js';
60
- export { mapsEqual } from './mapsequal.js';
61
- export { objectToMap } from './objecttomap.js';
62
- export { add, _translate, _clear as _clearTranslations, _unifyTranslations } from './translation-service.js';
63
- export { priorities } from './priorities.js';
64
- export { retry, exponentialDelay } from './retry.js';
65
- export { insertToPriorityArray } from './inserttopriorityarray.js';
66
- export { spliceArray } from './splicearray.js';
67
- export { uid } from './uid.js';
68
- export { delay } from './delay.js';
69
- export { wait } from './wait.js';
70
- export { parseBase64EncodedObject } from './parsebase64encodedobject.js';
71
- export { crc32 } from './crc32.js';
72
- export { collectStylesheets } from './collectstylesheets.js';
73
- export { formatHtml } from './formathtml.js';
74
- export { spy } from './spy.js';
75
- export { isCombiningMark, isHighSurrogateHalf, isLowSurrogateHalf, isInsideSurrogatePair, isInsideCombinedSymbol, isInsideEmojiSequence } from './unicode.js';
76
- export { decodeLicenseKey } from './decodelicensekey.js';
77
- export { isFeatureBlockedByLicenseKey } from './isfeatureblockedbylicensekey.js';
78
- export { version, releaseDate } from './version.js';
@@ -1,28 +0,0 @@
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 { priorities } from './priorities.js';
6
- /**
7
- * Inserts any object with priority at correct index by priority so registered objects are always sorted from highest to lowest priority.
8
- *
9
- * @param objects Array of objects with priority to insert object to.
10
- * @param objectToInsert Object with `priority` property.
11
- */
12
- export function insertToPriorityArray(objects, objectToInsert) {
13
- const priority = priorities.get(objectToInsert.priority);
14
- // Binary search for better performance in large tables.
15
- let left = 0;
16
- let right = objects.length;
17
- while (left < right) {
18
- const mid = (left + right) >> 1; // Use bitwise operator for faster floor division by 2.
19
- const midPriority = priorities.get(objects[mid].priority);
20
- if (midPriority < priority) {
21
- right = mid;
22
- }
23
- else {
24
- left = mid + 1;
25
- }
26
- }
27
- objects.splice(left, 0, objectToInsert);
28
- }
@@ -1,17 +0,0 @@
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
- /**
6
- * @module utils/isfeatureblockedbylicensekey
7
- */
8
- /**
9
- * Checks whether a feature (represented by an unique id) is blocked by the provided license key.
10
- *
11
- * @param licensePayload Decoded license key.
12
- * @param licenseFeatureCode An unique feature id to check.
13
- */
14
- export function isFeatureBlockedByLicenseKey(licensePayload, licenseFeatureCode) {
15
- const blockedFeatures = licensePayload.removeFeatures || [];
16
- return blockedFeatures.includes(licenseFeatureCode);
17
- }
package/src/isiterable.js DELETED
@@ -1,16 +0,0 @@
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
- /**
6
- * @module utils/isiterable
7
- */
8
- /**
9
- * Checks if value implements iterator interface.
10
- *
11
- * @param value The value to check.
12
- * @returns True if value implements iterator interface.
13
- */
14
- export function isIterable(value) {
15
- return !!(value && value[Symbol.iterator]);
16
- }
package/src/keyboard.js DELETED
@@ -1,256 +0,0 @@
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 { CKEditorError } from './ckeditorerror.js';
6
- import { env } from './env.js';
7
- const modifiersToGlyphsMac = {
8
- ctrl: '⌃',
9
- cmd: '⌘',
10
- alt: '⌥',
11
- shift: '⇧'
12
- };
13
- const modifiersToGlyphsNonMac = {
14
- ctrl: 'Ctrl+',
15
- alt: 'Alt+',
16
- shift: 'Shift+'
17
- };
18
- const keyCodesToGlyphs = {
19
- 37: '←',
20
- 38: '↑',
21
- 39: '→',
22
- 40: '↓',
23
- 9: '⇥',
24
- 33: 'Page Up',
25
- 34: 'Page Down'
26
- };
27
- /**
28
- * An object with `keyName => keyCode` pairs for a set of known keys.
29
- *
30
- * Contains:
31
- *
32
- * * `a-z`,
33
- * * `0-9`,
34
- * * `f1-f12`,
35
- * * `` ` ``, `-`, `=`, `[`, `]`, `;`, `'`, `,`, `.`, `/`, `\`,
36
- * * `arrow(left|up|right|bottom)`,
37
- * * `backspace`, `delete`, `end`, `enter`, `esc`, `home`, `tab`,
38
- * * `ctrl`, `cmd`, `shift`, `alt`.
39
- */
40
- export const keyCodes = /* #__PURE__ */ generateKnownKeyCodes();
41
- const keyCodeNames = /* #__PURE__ */ Object.fromEntries(
42
- /* #__PURE__ */ Object.entries(keyCodes).map(([name, code]) => {
43
- let prettyKeyName;
44
- if (code in keyCodesToGlyphs) {
45
- prettyKeyName = keyCodesToGlyphs[code];
46
- }
47
- else {
48
- prettyKeyName = name.charAt(0).toUpperCase() + name.slice(1);
49
- }
50
- return [code, prettyKeyName];
51
- }));
52
- /**
53
- * Converts a key name or {@link module:utils/keyboard~KeystrokeInfo keystroke info} into a key code.
54
- *
55
- * Note: Key names are matched with {@link module:utils/keyboard#keyCodes} in a case-insensitive way.
56
- *
57
- * @param key A key name (see {@link module:utils/keyboard#keyCodes}) or a keystroke data object.
58
- * @returns Key or keystroke code.
59
- */
60
- export function getCode(key) {
61
- let keyCode;
62
- if (typeof key == 'string') {
63
- keyCode = keyCodes[key.toLowerCase()];
64
- if (!keyCode) {
65
- /**
66
- * Unknown key name. Only key names included in the {@link module:utils/keyboard#keyCodes} can be used.
67
- *
68
- * @error keyboard-unknown-key
69
- * @param {string} key Ths specified key name.
70
- */
71
- throw new CKEditorError('keyboard-unknown-key', null, { key });
72
- }
73
- }
74
- else {
75
- keyCode = key.keyCode +
76
- (key.altKey ? keyCodes.alt : 0) +
77
- (key.ctrlKey ? keyCodes.ctrl : 0) +
78
- (key.shiftKey ? keyCodes.shift : 0) +
79
- (key.metaKey ? keyCodes.cmd : 0);
80
- }
81
- return keyCode;
82
- }
83
- /**
84
- * Parses the keystroke and returns a keystroke code that will match the code returned by
85
- * {@link module:utils/keyboard~getCode} for the corresponding {@link module:utils/keyboard~KeystrokeInfo keystroke info}.
86
- *
87
- * The keystroke can be passed in two formats:
88
- *
89
- * * as a single string – e.g. `ctrl + A`,
90
- * * as an array of {@link module:utils/keyboard~keyCodes known key names} and key codes – e.g.:
91
- * * `[ 'ctrl', 32 ]` (ctrl + space),
92
- * * `[ 'ctrl', 'a' ]` (ctrl + A).
93
- *
94
- * Note: Key names are matched with {@link module:utils/keyboard#keyCodes} in a case-insensitive way.
95
- *
96
- * Note: Only keystrokes with a single non-modifier key are supported (e.g. `ctrl+A` is OK, but `ctrl+A+B` is not).
97
- *
98
- * Note: On macOS, keystroke handling is translating the `Ctrl` key to the `Cmd` key and handling only that keystroke.
99
- * For example, a registered keystroke `Ctrl+A` will be translated to `Cmd+A` on macOS. To disable the translation of some keystroke,
100
- * use the forced modifier: `Ctrl!+A` (note the exclamation mark).
101
- *
102
- * @param keystroke The keystroke definition.
103
- * @returns Keystroke code.
104
- */
105
- export function parseKeystroke(keystroke) {
106
- if (typeof keystroke == 'string') {
107
- keystroke = splitKeystrokeText(keystroke);
108
- }
109
- return keystroke
110
- .map(key => (typeof key == 'string') ? getEnvKeyCode(key) : key)
111
- .reduce((key, sum) => sum + key, 0);
112
- }
113
- /**
114
- * Translates any keystroke string text like `"Ctrl+A"` to an
115
- * environment–specific keystroke, i.e. `"⌘A"` on macOS.
116
- *
117
- * @param keystroke The keystroke text.
118
- * @param [forcedEnv] The environment to force the key translation to. If not provided, the current environment is used.
119
- * @returns The keystroke text specific for the environment.
120
- */
121
- export function getEnvKeystrokeText(keystroke, forcedEnv) {
122
- let keystrokeCode = parseKeystroke(keystroke);
123
- const isMac = forcedEnv ? forcedEnv === 'Mac' : env.isMac || env.isiOS;
124
- const modifiersToGlyphs = Object.entries(isMac ? modifiersToGlyphsMac : modifiersToGlyphsNonMac);
125
- const modifiers = modifiersToGlyphs.reduce((modifiers, [name, glyph]) => {
126
- // Modifier keys are stored as a bit mask so extract those from the keystroke code.
127
- if ((keystrokeCode & keyCodes[name]) != 0) {
128
- keystrokeCode &= ~keyCodes[name];
129
- modifiers += glyph;
130
- }
131
- return modifiers;
132
- }, '');
133
- return modifiers + (keystrokeCode ? keyCodeNames[keystrokeCode] : '');
134
- }
135
- /**
136
- * Returns `true` if the provided key code represents one of the arrow keys.
137
- *
138
- * @param keyCode A key code as in {@link module:utils/keyboard~KeystrokeInfo#keyCode}.
139
- */
140
- export function isArrowKeyCode(keyCode) {
141
- return keyCode == keyCodes.arrowright ||
142
- keyCode == keyCodes.arrowleft ||
143
- keyCode == keyCodes.arrowup ||
144
- keyCode == keyCodes.arrowdown;
145
- }
146
- /**
147
- * Returns the direction in which the {@link module:engine/model/documentselection~ModelDocumentSelection selection}
148
- * will move when the provided arrow key code is pressed considering the language direction of the editor content.
149
- *
150
- * For instance, in right–to–left (RTL) content languages, pressing the left arrow means moving the selection right (forward)
151
- * in the model structure. Similarly, pressing the right arrow moves the selection left (backward).
152
- *
153
- * @param keyCode A key code as in {@link module:utils/keyboard~KeystrokeInfo#keyCode}.
154
- * @param contentLanguageDirection The content language direction, corresponding to
155
- * {@link module:utils/locale~Locale#contentLanguageDirection}.
156
- * @returns Localized arrow direction or `undefined` for non-arrow key codes.
157
- */
158
- export function getLocalizedArrowKeyCodeDirection(keyCode, contentLanguageDirection) {
159
- const isLtrContent = contentLanguageDirection === 'ltr';
160
- switch (keyCode) {
161
- case keyCodes.arrowleft:
162
- return isLtrContent ? 'left' : 'right';
163
- case keyCodes.arrowright:
164
- return isLtrContent ? 'right' : 'left';
165
- case keyCodes.arrowup:
166
- return 'up';
167
- case keyCodes.arrowdown:
168
- return 'down';
169
- }
170
- }
171
- /**
172
- * Converts a key name to the key code with mapping based on the env.
173
- *
174
- * See: {@link module:utils/keyboard~getCode}.
175
- *
176
- * @param key The key name (see {@link module:utils/keyboard#keyCodes}).
177
- * @returns Key code.
178
- */
179
- function getEnvKeyCode(key) {
180
- // Don't remap modifier key for forced modifiers.
181
- if (key.endsWith('!')) {
182
- return getCode(key.slice(0, -1));
183
- }
184
- const code = getCode(key);
185
- return (env.isMac || env.isiOS) && code == keyCodes.ctrl ? keyCodes.cmd : code;
186
- }
187
- /**
188
- * Determines if the provided key code moves the {@link module:engine/model/documentselection~ModelDocumentSelection selection}
189
- * forward or backward considering the language direction of the editor content.
190
- *
191
- * For instance, in right–to–left (RTL) languages, pressing the left arrow means moving forward
192
- * in the model structure. Similarly, pressing the right arrow moves the selection backward.
193
- *
194
- * @param keyCode A key code as in {@link module:utils/keyboard~KeystrokeInfo#keyCode}.
195
- * @param contentLanguageDirection The content language direction, corresponding to
196
- * {@link module:utils/locale~Locale#contentLanguageDirection}.
197
- */
198
- export function isForwardArrowKeyCode(keyCode, contentLanguageDirection) {
199
- const localizedKeyCodeDirection = getLocalizedArrowKeyCodeDirection(keyCode, contentLanguageDirection);
200
- return localizedKeyCodeDirection === 'down' || localizedKeyCodeDirection === 'right';
201
- }
202
- function generateKnownKeyCodes() {
203
- const keyCodes = {
204
- pageup: 33,
205
- pagedown: 34,
206
- end: 35,
207
- home: 36,
208
- arrowleft: 37,
209
- arrowup: 38,
210
- arrowright: 39,
211
- arrowdown: 40,
212
- backspace: 8,
213
- delete: 46,
214
- enter: 13,
215
- space: 32,
216
- esc: 27,
217
- tab: 9,
218
- // The idea about these numbers is that they do not collide with any real key codes, so we can use them
219
- // like bit masks.
220
- ctrl: 0x110000,
221
- shift: 0x220000,
222
- alt: 0x440000,
223
- cmd: 0x880000
224
- };
225
- // a-z
226
- for (let code = 65; code <= 90; code++) {
227
- const letter = String.fromCharCode(code);
228
- keyCodes[letter.toLowerCase()] = code;
229
- }
230
- // 0-9
231
- for (let code = 48; code <= 57; code++) {
232
- keyCodes[code - 48] = code;
233
- }
234
- // F1-F12
235
- for (let code = 112; code <= 123; code++) {
236
- keyCodes['f' + (code - 111)] = code;
237
- }
238
- // other characters
239
- Object.assign(keyCodes, {
240
- '\'': 222,
241
- ',': 108,
242
- '-': 109,
243
- '.': 110,
244
- '/': 111,
245
- ';': 186,
246
- '=': 187,
247
- '[': 219,
248
- '\\': 220,
249
- ']': 221,
250
- '`': 223
251
- });
252
- return keyCodes;
253
- }
254
- function splitKeystrokeText(keystroke) {
255
- return keystroke.split('+').map(key => key.trim());
256
- }