@ckeditor/ckeditor5-restricted-editing 47.6.1-alpha.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 (184) hide show
  1. package/ckeditor5-metadata.json +6 -6
  2. package/dist/index-editor.css +59 -0
  3. package/dist/index.css +61 -0
  4. package/dist/index.css.map +1 -0
  5. package/dist/index.js.map +1 -1
  6. package/{src → dist}/restrictededitingexceptionautocommand.d.ts +1 -1
  7. package/{src → dist}/restrictededitingexceptionblockcommand.d.ts +1 -1
  8. package/{src → dist}/restrictededitingexceptioncommand.d.ts +1 -1
  9. package/{src → dist}/restrictededitingmode/converters.d.ts +2 -2
  10. package/{src → dist}/restrictededitingmode/utils.d.ts +2 -2
  11. package/{src → dist}/restrictededitingmode.d.ts +1 -1
  12. package/{src → dist}/restrictededitingmodeediting.d.ts +1 -1
  13. package/{src → dist}/restrictededitingmodenavigationcommand.d.ts +1 -1
  14. package/{src → dist}/restrictededitingmodeui.d.ts +1 -1
  15. package/{src → dist}/standardeditingmode.d.ts +1 -1
  16. package/{src → dist}/standardeditingmodeediting.d.ts +1 -1
  17. package/{src → dist}/standardeditingmodeui.d.ts +1 -1
  18. package/package.json +25 -47
  19. package/build/restricted-editing.js +0 -5
  20. package/build/translations/af.js +0 -1
  21. package/build/translations/ar.js +0 -1
  22. package/build/translations/ast.js +0 -1
  23. package/build/translations/az.js +0 -1
  24. package/build/translations/be.js +0 -1
  25. package/build/translations/bg.js +0 -1
  26. package/build/translations/bn.js +0 -1
  27. package/build/translations/bs.js +0 -1
  28. package/build/translations/ca.js +0 -1
  29. package/build/translations/cs.js +0 -1
  30. package/build/translations/da.js +0 -1
  31. package/build/translations/de-ch.js +0 -1
  32. package/build/translations/de.js +0 -1
  33. package/build/translations/el.js +0 -1
  34. package/build/translations/en-au.js +0 -1
  35. package/build/translations/en-gb.js +0 -1
  36. package/build/translations/eo.js +0 -1
  37. package/build/translations/es-co.js +0 -1
  38. package/build/translations/es.js +0 -1
  39. package/build/translations/et.js +0 -1
  40. package/build/translations/eu.js +0 -1
  41. package/build/translations/fa.js +0 -1
  42. package/build/translations/fi.js +0 -1
  43. package/build/translations/fr.js +0 -1
  44. package/build/translations/gl.js +0 -1
  45. package/build/translations/gu.js +0 -1
  46. package/build/translations/he.js +0 -1
  47. package/build/translations/hi.js +0 -1
  48. package/build/translations/hr.js +0 -1
  49. package/build/translations/hu.js +0 -1
  50. package/build/translations/hy.js +0 -1
  51. package/build/translations/id.js +0 -1
  52. package/build/translations/it.js +0 -1
  53. package/build/translations/ja.js +0 -1
  54. package/build/translations/jv.js +0 -1
  55. package/build/translations/kk.js +0 -1
  56. package/build/translations/km.js +0 -1
  57. package/build/translations/kn.js +0 -1
  58. package/build/translations/ko.js +0 -1
  59. package/build/translations/ku.js +0 -1
  60. package/build/translations/lt.js +0 -1
  61. package/build/translations/lv.js +0 -1
  62. package/build/translations/ms.js +0 -1
  63. package/build/translations/nb.js +0 -1
  64. package/build/translations/ne.js +0 -1
  65. package/build/translations/nl.js +0 -1
  66. package/build/translations/no.js +0 -1
  67. package/build/translations/oc.js +0 -1
  68. package/build/translations/pl.js +0 -1
  69. package/build/translations/pt-br.js +0 -1
  70. package/build/translations/pt.js +0 -1
  71. package/build/translations/ro.js +0 -1
  72. package/build/translations/ru.js +0 -1
  73. package/build/translations/si.js +0 -1
  74. package/build/translations/sk.js +0 -1
  75. package/build/translations/sl.js +0 -1
  76. package/build/translations/sq.js +0 -1
  77. package/build/translations/sr-latn.js +0 -1
  78. package/build/translations/sr.js +0 -1
  79. package/build/translations/sv.js +0 -1
  80. package/build/translations/th.js +0 -1
  81. package/build/translations/ti.js +0 -1
  82. package/build/translations/tk.js +0 -1
  83. package/build/translations/tr.js +0 -1
  84. package/build/translations/tt.js +0 -1
  85. package/build/translations/ug.js +0 -1
  86. package/build/translations/uk.js +0 -1
  87. package/build/translations/ur.js +0 -1
  88. package/build/translations/uz.js +0 -1
  89. package/build/translations/vi.js +0 -1
  90. package/build/translations/zh-cn.js +0 -1
  91. package/build/translations/zh.js +0 -1
  92. package/lang/contexts.json +0 -11
  93. package/lang/translations/af.po +0 -48
  94. package/lang/translations/ar.po +0 -48
  95. package/lang/translations/ast.po +0 -48
  96. package/lang/translations/az.po +0 -48
  97. package/lang/translations/be.po +0 -48
  98. package/lang/translations/bg.po +0 -48
  99. package/lang/translations/bn.po +0 -48
  100. package/lang/translations/bs.po +0 -48
  101. package/lang/translations/ca.po +0 -48
  102. package/lang/translations/cs.po +0 -48
  103. package/lang/translations/da.po +0 -48
  104. package/lang/translations/de-ch.po +0 -48
  105. package/lang/translations/de.po +0 -48
  106. package/lang/translations/el.po +0 -48
  107. package/lang/translations/en-au.po +0 -48
  108. package/lang/translations/en-gb.po +0 -48
  109. package/lang/translations/en.po +0 -48
  110. package/lang/translations/eo.po +0 -48
  111. package/lang/translations/es-co.po +0 -48
  112. package/lang/translations/es.po +0 -48
  113. package/lang/translations/et.po +0 -48
  114. package/lang/translations/eu.po +0 -48
  115. package/lang/translations/fa.po +0 -48
  116. package/lang/translations/fi.po +0 -48
  117. package/lang/translations/fr.po +0 -48
  118. package/lang/translations/gl.po +0 -48
  119. package/lang/translations/gu.po +0 -48
  120. package/lang/translations/he.po +0 -48
  121. package/lang/translations/hi.po +0 -48
  122. package/lang/translations/hr.po +0 -48
  123. package/lang/translations/hu.po +0 -48
  124. package/lang/translations/hy.po +0 -48
  125. package/lang/translations/id.po +0 -48
  126. package/lang/translations/it.po +0 -48
  127. package/lang/translations/ja.po +0 -48
  128. package/lang/translations/jv.po +0 -48
  129. package/lang/translations/kk.po +0 -48
  130. package/lang/translations/km.po +0 -48
  131. package/lang/translations/kn.po +0 -48
  132. package/lang/translations/ko.po +0 -48
  133. package/lang/translations/ku.po +0 -48
  134. package/lang/translations/lt.po +0 -48
  135. package/lang/translations/lv.po +0 -48
  136. package/lang/translations/ms.po +0 -48
  137. package/lang/translations/nb.po +0 -48
  138. package/lang/translations/ne.po +0 -48
  139. package/lang/translations/nl.po +0 -48
  140. package/lang/translations/no.po +0 -48
  141. package/lang/translations/oc.po +0 -48
  142. package/lang/translations/pl.po +0 -48
  143. package/lang/translations/pt-br.po +0 -48
  144. package/lang/translations/pt.po +0 -48
  145. package/lang/translations/ro.po +0 -48
  146. package/lang/translations/ru.po +0 -48
  147. package/lang/translations/si.po +0 -48
  148. package/lang/translations/sk.po +0 -48
  149. package/lang/translations/sl.po +0 -48
  150. package/lang/translations/sq.po +0 -48
  151. package/lang/translations/sr-latn.po +0 -48
  152. package/lang/translations/sr.po +0 -48
  153. package/lang/translations/sv.po +0 -48
  154. package/lang/translations/th.po +0 -48
  155. package/lang/translations/ti.po +0 -48
  156. package/lang/translations/tk.po +0 -48
  157. package/lang/translations/tr.po +0 -48
  158. package/lang/translations/tt.po +0 -48
  159. package/lang/translations/ug.po +0 -48
  160. package/lang/translations/uk.po +0 -48
  161. package/lang/translations/ur.po +0 -48
  162. package/lang/translations/uz.po +0 -48
  163. package/lang/translations/vi.po +0 -48
  164. package/lang/translations/zh-cn.po +0 -48
  165. package/lang/translations/zh.po +0 -48
  166. package/src/augmentation.js +0 -5
  167. package/src/index.js +0 -20
  168. package/src/restrictededitingconfig.js +0 -5
  169. package/src/restrictededitingexceptionautocommand.js +0 -73
  170. package/src/restrictededitingexceptionblockcommand.js +0 -203
  171. package/src/restrictededitingexceptioncommand.js +0 -61
  172. package/src/restrictededitingmode/converters.js +0 -177
  173. package/src/restrictededitingmode/utils.js +0 -69
  174. package/src/restrictededitingmode.js +0 -39
  175. package/src/restrictededitingmodeediting.js +0 -512
  176. package/src/restrictededitingmodenavigationcommand.js +0 -99
  177. package/src/restrictededitingmodeui.js +0 -139
  178. package/src/standardeditingmode.js +0 -36
  179. package/src/standardeditingmodeediting.js +0 -193
  180. package/src/standardeditingmodeui.js +0 -150
  181. package/theme/restrictedediting.css +0 -10
  182. /package/{src → dist}/augmentation.d.ts +0 -0
  183. /package/{src → dist}/index.d.ts +0 -0
  184. /package/{src → dist}/restrictededitingconfig.d.ts +0 -0
@@ -1,203 +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 restricted-editing/restrictededitingexceptionblockcommand
7
- */
8
- import { Command } from 'ckeditor5/src/core.js';
9
- import { first } from 'ckeditor5/src/utils.js';
10
- /**
11
- * The command that toggles exception blocks for the restricted editing.
12
- */
13
- export class RestrictedEditingExceptionBlockCommand extends Command {
14
- /**
15
- * @inheritDoc
16
- */
17
- refresh() {
18
- this.value = this._getValue();
19
- this.isEnabled = this._checkEnabled();
20
- }
21
- /**
22
- * Wraps or unwraps the selected blocks with non-restricted area.
23
- *
24
- * @fires execute
25
- * @param options Command options.
26
- * @param options.forceValue If set, it will force the command behavior. If `true`, the command will apply a block exception,
27
- * otherwise the command will remove the block exception. If not set, the command will act basing on its current value.
28
- */
29
- execute(options = {}) {
30
- const model = this.editor.model;
31
- const schema = model.schema;
32
- const selection = model.document.selection;
33
- const blocks = Array.from(selection.getSelectedBlocks());
34
- const value = (options.forceValue === undefined) ? !this.value : options.forceValue;
35
- model.change(writer => {
36
- if (!value) {
37
- const blocksToUnwrap = blocks.map(block => {
38
- // Find blocks directly nested inside an exception.
39
- return findExceptionContentBlock(block);
40
- }).filter((exception) => !!exception);
41
- this._removeException(writer, blocksToUnwrap);
42
- }
43
- else {
44
- const blocksToWrap = blocks.filter(block => {
45
- // Already wrapped blocks needs to be considered while wrapping too
46
- // in order to reuse their wrapper elements.
47
- return findException(block) || checkCanBeWrapped(schema, block);
48
- });
49
- this._applyException(writer, blocksToWrap);
50
- }
51
- });
52
- }
53
- /**
54
- * Checks the command's {@link #value}.
55
- */
56
- _getValue() {
57
- const selection = this.editor.model.document.selection;
58
- const firstBlock = first(selection.getSelectedBlocks());
59
- return !!(firstBlock && findException(firstBlock));
60
- }
61
- /**
62
- * Checks whether the command can be enabled in the current context.
63
- *
64
- * @returns Whether the command should be enabled.
65
- */
66
- _checkEnabled() {
67
- if (this.value) {
68
- return true;
69
- }
70
- const selection = this.editor.model.document.selection;
71
- const schema = this.editor.model.schema;
72
- const firstBlock = first(selection.getSelectedBlocks());
73
- if (!firstBlock) {
74
- return false;
75
- }
76
- return checkCanBeWrapped(schema, firstBlock);
77
- }
78
- /**
79
- * Unwraps the exception from given blocks.
80
- *
81
- * If blocks which are supposed to be unwrapped are in the middle of an exception,
82
- * start it or end it, then the exception will be split (if needed) and the blocks
83
- * will be moved out of it, so other exception blocks remained wrapped.
84
- */
85
- _removeException(writer, blocks) {
86
- // Unwrap all groups of block. Iterate in the reverse order to not break following ranges.
87
- getRangesOfBlockGroups(writer, blocks).reverse().forEach(groupRange => {
88
- if (groupRange.start.isAtStart && groupRange.end.isAtEnd) {
89
- writer.unwrap(groupRange.start.parent);
90
- return;
91
- }
92
- // The group of blocks are at the beginning of an exception so let's move them left (out of the exception).
93
- if (groupRange.start.isAtStart) {
94
- const positionBefore = writer.createPositionBefore(groupRange.start.parent);
95
- writer.move(groupRange, positionBefore);
96
- return;
97
- }
98
- // The blocks are in the middle of an exception so we need to split the exception after the last block
99
- // so we move the items there.
100
- if (!groupRange.end.isAtEnd) {
101
- writer.split(groupRange.end);
102
- }
103
- // Now we are sure that groupRange.end.isAtEnd is true, so let's move the blocks right.
104
- const positionAfter = writer.createPositionAfter(groupRange.end.parent);
105
- writer.move(groupRange, positionAfter);
106
- });
107
- }
108
- /**
109
- * Applies the exception to given blocks.
110
- */
111
- _applyException(writer, blocks) {
112
- const schema = this.editor.model.schema;
113
- const exceptionsToMerge = [];
114
- // Wrap all groups of block. Iterate in the reverse order to not break following ranges.
115
- getRangesOfBlockGroups(writer, blocks).reverse().forEach(groupRange => {
116
- let exception = findException(groupRange.start);
117
- if (!exception) {
118
- exception = writer.createElement('restrictedEditingException');
119
- writer.wrap(groupRange, exception);
120
- }
121
- exceptionsToMerge.push(exception);
122
- });
123
- // Merge subsequent exception elements. Reverse the order again because this time we want to go through
124
- // the exception elements in the source order (due to how merge works – it moves the right element's content
125
- // to the first element and removes the right one. Since we may need to merge a couple of subsequent exception elements
126
- // we want to keep the reference to the first (furthest left) one.
127
- exceptionsToMerge.reverse();
128
- // But first add any neighbouring block exceptions to the list.
129
- if (exceptionsToMerge.length) {
130
- const previousSibling = exceptionsToMerge.at(0).previousSibling;
131
- const nextSibling = exceptionsToMerge.at(-1).nextSibling;
132
- if (previousSibling?.is('element', 'restrictedEditingException')) {
133
- exceptionsToMerge.unshift(previousSibling);
134
- }
135
- if (nextSibling?.is('element', 'restrictedEditingException')) {
136
- exceptionsToMerge.push(nextSibling);
137
- }
138
- }
139
- // Merge subsequent exceptions.
140
- exceptionsToMerge.reduce((currentException, nextException) => {
141
- if (currentException.nextSibling == nextException) {
142
- writer.merge(writer.createPositionAfter(currentException));
143
- return currentException;
144
- }
145
- return nextException;
146
- });
147
- // Remove inline exceptions from block exception.
148
- schema.removeDisallowedAttributes(blocks, writer);
149
- }
150
- }
151
- function findException(elementOrPosition) {
152
- return elementOrPosition.findAncestor('restrictedEditingException', { includeSelf: true });
153
- }
154
- function findExceptionContentBlock(element) {
155
- let node = element;
156
- while (node.parent) {
157
- if (node.parent.name == 'restrictedEditingException') {
158
- return node;
159
- }
160
- node = node.parent;
161
- }
162
- return null;
163
- }
164
- /**
165
- * Returns a minimal array of ranges containing groups of subsequent blocks.
166
- *
167
- * content: abcdefgh
168
- * blocks: [ a, b, d, f, g, h ]
169
- * output ranges: [ab]c[d]e[fgh]
170
- */
171
- function getRangesOfBlockGroups(writer, blocks) {
172
- let startPosition;
173
- let i = 0;
174
- const ranges = [];
175
- while (i < blocks.length) {
176
- const block = blocks[i];
177
- const nextBlock = blocks[i + 1];
178
- if (!startPosition) {
179
- startPosition = writer.createPositionBefore(block);
180
- }
181
- if (!nextBlock || block.nextSibling != nextBlock) {
182
- ranges.push(writer.createRange(startPosition, writer.createPositionAfter(block)));
183
- startPosition = null;
184
- }
185
- i++;
186
- }
187
- return ranges;
188
- }
189
- /**
190
- * Checks whether exception can wrap the block.
191
- */
192
- function checkCanBeWrapped(schema, block) {
193
- const parentContext = schema.createContext(block.parent);
194
- // Is block exception allowed in parent of block.
195
- if (!schema.checkChild(parentContext, 'restrictedEditingException')) {
196
- return false;
197
- }
198
- // Is block allowed inside block exception.
199
- if (!schema.checkChild(parentContext.push('restrictedEditingException'), block)) {
200
- return false;
201
- }
202
- return true;
203
- }
@@ -1,61 +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 restricted-editing/restrictededitingexceptioncommand
7
- */
8
- import { Command } from 'ckeditor5/src/core.js';
9
- /**
10
- * The command that toggles exceptions from the restricted editing on text.
11
- */
12
- export class RestrictedEditingExceptionCommand extends Command {
13
- /**
14
- * @inheritDoc
15
- */
16
- refresh() {
17
- const model = this.editor.model;
18
- const doc = model.document;
19
- this.value = !!doc.selection.getAttribute('restrictedEditingException');
20
- this.isEnabled = model.schema.checkAttributeInSelection(doc.selection, 'restrictedEditingException');
21
- }
22
- /**
23
- * @inheritDoc
24
- */
25
- execute(options = {}) {
26
- const model = this.editor.model;
27
- const document = model.document;
28
- const selection = document.selection;
29
- const valueToSet = (options.forceValue === undefined) ? !this.value : options.forceValue;
30
- model.change(writer => {
31
- const ranges = model.schema.getValidRanges(selection.getRanges(), 'restrictedEditingException');
32
- if (selection.isCollapsed) {
33
- if (valueToSet) {
34
- writer.setSelectionAttribute('restrictedEditingException', valueToSet);
35
- }
36
- else {
37
- const isSameException = (value) => {
38
- return value.item.getAttribute('restrictedEditingException') === this.value;
39
- };
40
- const focus = selection.focus;
41
- const exceptionStart = focus.getLastMatchingPosition(isSameException, { direction: 'backward' });
42
- const exceptionEnd = focus.getLastMatchingPosition(isSameException);
43
- writer.removeSelectionAttribute('restrictedEditingException');
44
- if (!(focus.isEqual(exceptionStart) || focus.isEqual(exceptionEnd))) {
45
- writer.removeAttribute('restrictedEditingException', writer.createRange(exceptionStart, exceptionEnd));
46
- }
47
- }
48
- }
49
- else {
50
- for (const range of ranges) {
51
- if (valueToSet) {
52
- writer.setAttribute('restrictedEditingException', valueToSet, range);
53
- }
54
- else {
55
- writer.removeAttribute('restrictedEditingException', range);
56
- }
57
- }
58
- }
59
- });
60
- }
61
- }
@@ -1,177 +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 { Matcher } from 'ckeditor5/src/engine.js';
6
- import { getMarkerAtPosition } from './utils.js';
7
- const HIGHLIGHT_CLASS = 'restricted-editing-exception_selected';
8
- /**
9
- * Adds a visual highlight style to a restricted editing exception that the selection is anchored to.
10
- *
11
- * The highlight is turned on by adding the `.restricted-editing-exception_selected` class to the
12
- * exception in the view:
13
- *
14
- * * The class is removed before the conversion starts, as callbacks added with the `'highest'` priority
15
- * to {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher} events.
16
- * * The class is added in the view post-fixer, after other changes in the model tree are converted to the view.
17
- *
18
- * This way, adding and removing the highlight does not interfere with conversion.
19
- *
20
- * @internal
21
- */
22
- export function setupExceptionHighlighting(editor) {
23
- const view = editor.editing.view;
24
- const model = editor.model;
25
- const highlightedMarkers = new Set();
26
- // Adding the class.
27
- view.document.registerPostFixer((writer) => {
28
- const modelSelection = model.document.selection;
29
- const marker = getMarkerAtPosition(editor, modelSelection.anchor);
30
- if (!marker) {
31
- return false;
32
- }
33
- const modelWrapperElement = marker.getRange().getContainedElement();
34
- if (modelWrapperElement && modelWrapperElement.is('element', 'restrictedEditingException')) {
35
- const viewElement = editor.editing.mapper.toViewElement(modelWrapperElement);
36
- writer.addClass(HIGHLIGHT_CLASS, viewElement);
37
- highlightedMarkers.add(viewElement);
38
- }
39
- else {
40
- for (const viewElement of editor.editing.mapper.markerNameToElements(marker.name)) {
41
- writer.addClass(HIGHLIGHT_CLASS, viewElement);
42
- highlightedMarkers.add(viewElement);
43
- }
44
- }
45
- return false;
46
- });
47
- // Removing the class.
48
- editor.conversion.for('editingDowncast').add(dispatcher => {
49
- // Make sure the highlight is removed on every possible event, before conversion is started.
50
- dispatcher.on('insert', removeHighlight, { priority: 'highest' });
51
- dispatcher.on('remove', removeHighlight, { priority: 'highest' });
52
- dispatcher.on('attribute', removeHighlight, { priority: 'highest' });
53
- dispatcher.on('cleanSelection', removeHighlight);
54
- function removeHighlight() {
55
- view.change(writer => {
56
- for (const item of highlightedMarkers.values()) {
57
- writer.removeClass(HIGHLIGHT_CLASS, item);
58
- highlightedMarkers.delete(item);
59
- }
60
- });
61
- }
62
- });
63
- }
64
- /**
65
- * A post-fixer that prevents removing a collapsed marker from the document.
66
- *
67
- * @internal
68
- */
69
- export function resurrectCollapsedMarkerPostFixer(editor) {
70
- // This post-fixer shouldn't be necessary after https://github.com/ckeditor/ckeditor5/issues/5778.
71
- return writer => {
72
- let changeApplied = false;
73
- for (const { name, data } of editor.model.document.differ.getChangedMarkers()) {
74
- if (name.startsWith('restrictedEditingException') && data.newRange && data.newRange.root.rootName == '$graveyard') {
75
- writer.updateMarker(name, {
76
- range: writer.createRange(writer.createPositionAt(data.oldRange.start))
77
- });
78
- changeApplied = true;
79
- }
80
- }
81
- return changeApplied;
82
- };
83
- }
84
- /**
85
- * A post-fixer that extends a marker when the user types on its boundaries.
86
- *
87
- * @internal
88
- */
89
- export function extendMarkerOnTypingPostFixer(editor) {
90
- // This post-fixer shouldn't be necessary after https://github.com/ckeditor/ckeditor5/issues/5778.
91
- return writer => {
92
- let changeApplied = false;
93
- const schema = editor.model.schema;
94
- for (const change of editor.model.document.differ.getChanges()) {
95
- if (change.type == 'insert' && schema.checkChild('$block', change.name)) {
96
- changeApplied = _tryExtendMarkerStart(editor, change.position, change.length, writer) || changeApplied;
97
- changeApplied = _tryExtendMarkedEnd(editor, change.position, change.length, writer) || changeApplied;
98
- }
99
- }
100
- return changeApplied;
101
- };
102
- }
103
- /**
104
- * A view highlight-to-marker conversion helper.
105
- *
106
- * @param config Conversion configuration.
107
- * @internal
108
- */
109
- export function upcastHighlightToMarker(config) {
110
- return (dispatcher) => dispatcher.on('element', (evt, data, conversionApi) => {
111
- const { writer } = conversionApi;
112
- const matcher = new Matcher(config.view);
113
- const matcherResult = matcher.match(data.viewItem);
114
- // If there is no match, this callback should not do anything.
115
- if (!matcherResult) {
116
- return;
117
- }
118
- const match = matcherResult.match;
119
- // Force consuming element's name (taken from upcast helpers elementToElement converter).
120
- match.name = true;
121
- if (!conversionApi.consumable.test(data.viewItem, match)) {
122
- return;
123
- }
124
- let position = data.modelCursor;
125
- let wrapperElement = null;
126
- if (config.useWrapperElement) {
127
- if (!conversionApi.schema.checkChild(position, 'restrictedEditingException')) {
128
- return;
129
- }
130
- wrapperElement = writer.createElement('restrictedEditingException');
131
- writer.insert(wrapperElement, position);
132
- position = writer.createPositionAt(wrapperElement, 0);
133
- }
134
- const { modelRange: convertedChildrenRange } = conversionApi.convertChildren(data.viewItem, position);
135
- conversionApi.consumable.consume(data.viewItem, match);
136
- const markerName = config.model();
137
- const fakeMarkerStart = writer.createElement('$marker', { 'data-name': markerName });
138
- const fakeMarkerEnd = writer.createElement('$marker', { 'data-name': markerName });
139
- if (wrapperElement) {
140
- writer.insert(fakeMarkerStart, writer.createPositionBefore(wrapperElement));
141
- writer.insert(fakeMarkerEnd, writer.createPositionAfter(wrapperElement));
142
- }
143
- else {
144
- // Insert in reverse order to use converter content positions directly (without recalculating).
145
- writer.insert(fakeMarkerEnd, convertedChildrenRange.end);
146
- writer.insert(fakeMarkerStart, convertedChildrenRange.start);
147
- }
148
- data.modelRange = writer.createRange(writer.createPositionBefore(fakeMarkerStart), writer.createPositionAfter(fakeMarkerEnd));
149
- data.modelCursor = data.modelRange.end;
150
- });
151
- }
152
- /**
153
- * Extend marker if change detected on marker's start position.
154
- */
155
- function _tryExtendMarkerStart(editor, position, length, writer) {
156
- const markerAtStart = getMarkerAtPosition(editor, position.getShiftedBy(length));
157
- if (markerAtStart && markerAtStart.getStart().isEqual(position.getShiftedBy(length))) {
158
- writer.updateMarker(markerAtStart, {
159
- range: writer.createRange(markerAtStart.getStart().getShiftedBy(-length), markerAtStart.getEnd())
160
- });
161
- return true;
162
- }
163
- return false;
164
- }
165
- /**
166
- * Extend marker if change detected on marker's end position.
167
- */
168
- function _tryExtendMarkedEnd(editor, position, length, writer) {
169
- const markerAtEnd = getMarkerAtPosition(editor, position);
170
- if (markerAtEnd && markerAtEnd.getEnd().isEqual(position)) {
171
- writer.updateMarker(markerAtEnd, {
172
- range: writer.createRange(markerAtEnd.getStart(), markerAtEnd.getEnd().getShiftedBy(length))
173
- });
174
- return true;
175
- }
176
- return false;
177
- }
@@ -1,69 +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 restricted-editing/restrictededitingmode/utils
7
- */
8
- /**
9
- * Returns a single "restricted-editing-exception" marker at a given position. Contrary to
10
- * {@link module:engine/model/markercollection~MarkerCollection#getMarkersAtPosition}, it returnd a marker also when the postion is
11
- * equal to one of the marker's start or end positions.
12
- *
13
- * @internal
14
- */
15
- export function getMarkerAtPosition(editor, position) {
16
- for (const marker of editor.model.markers) {
17
- const markerRange = getExceptionRange(marker, editor.model);
18
- if (isPositionInRangeBoundaries(markerRange, position)) {
19
- if (marker.name.startsWith('restrictedEditingException:')) {
20
- return marker;
21
- }
22
- }
23
- }
24
- }
25
- /**
26
- * Checks if the position is fully contained in the range. Positions equal to range start or end are considered "in".
27
- *
28
- * @internal
29
- */
30
- export function isPositionInRangeBoundaries(range, position) {
31
- return (range.containsPosition(position) ||
32
- range.end.isEqual(position) ||
33
- range.start.isEqual(position));
34
- }
35
- /**
36
- * Checks if the selection is fully contained in the marker. Positions on marker boundaries are considered "in".
37
- *
38
- * ```xml
39
- * <marker>[]foo</marker> -> true
40
- * <marker>f[oo]</marker> -> true
41
- * <marker>f[oo</marker> ba]r -> false
42
- * <marker>foo</marker> []bar -> false
43
- * ```
44
- *
45
- * @internal
46
- */
47
- export function isSelectionInMarker(selection, model, marker) {
48
- if (!marker) {
49
- return false;
50
- }
51
- const markerRange = getExceptionRange(marker, model);
52
- if (selection.isCollapsed) {
53
- return isPositionInRangeBoundaries(markerRange, selection.focus);
54
- }
55
- return markerRange.containsRange(selection.getFirstRange(), true);
56
- }
57
- /**
58
- * Returns the marker range asjusted to the inside of exception wrapper element if needed.
59
- *
60
- * @internal
61
- */
62
- export function getExceptionRange(marker, model) {
63
- const markerRange = marker.getRange();
64
- const wrapperElement = markerRange.getContainedElement();
65
- if (wrapperElement && wrapperElement.is('element', 'restrictedEditingException')) {
66
- return model.createRangeIn(wrapperElement);
67
- }
68
- return markerRange;
69
- }
@@ -1,39 +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 restricted-editing/restrictededitingmode
7
- */
8
- import { Plugin } from 'ckeditor5/src/core.js';
9
- import { RestrictedEditingModeEditing } from './restrictededitingmodeediting.js';
10
- import { RestrictedEditingModeUI } from './restrictededitingmodeui.js';
11
- import '../theme/restrictedediting.css';
12
- /**
13
- * The restricted editing mode plugin.
14
- *
15
- * This is a "glue" plugin which loads the following plugins:
16
- *
17
- * * The {@link module:restricted-editing/restrictededitingmodeediting~RestrictedEditingModeEditing restricted mode editing feature}.
18
- * * The {@link module:restricted-editing/restrictededitingmodeui~RestrictedEditingModeUI restricted mode UI feature}.
19
- */
20
- export class RestrictedEditingMode extends Plugin {
21
- /**
22
- * @inheritDoc
23
- */
24
- static get pluginName() {
25
- return 'RestrictedEditingMode';
26
- }
27
- /**
28
- * @inheritDoc
29
- */
30
- static get isOfficialPlugin() {
31
- return true;
32
- }
33
- /**
34
- * @inheritDoc
35
- */
36
- static get requires() {
37
- return [RestrictedEditingModeEditing, RestrictedEditingModeUI];
38
- }
39
- }