@ckeditor/ckeditor5-engine 44.0.0-alpha.9 → 44.1.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 (364) hide show
  1. package/dist/controller/datacontroller.d.ts +1 -1
  2. package/dist/controller/editingcontroller.d.ts +1 -1
  3. package/dist/conversion/conversion.d.ts +1 -1
  4. package/dist/conversion/conversionhelpers.d.ts +1 -1
  5. package/dist/conversion/downcastdispatcher.d.ts +1 -1
  6. package/dist/conversion/downcasthelpers.d.ts +1 -1
  7. package/dist/conversion/mapper.d.ts +1 -1
  8. package/dist/conversion/modelconsumable.d.ts +1 -1
  9. package/dist/conversion/upcastdispatcher.d.ts +1 -1
  10. package/dist/conversion/upcasthelpers.d.ts +1 -1
  11. package/dist/conversion/viewconsumable.d.ts +1 -1
  12. package/dist/dataprocessor/basichtmlwriter.d.ts +1 -1
  13. package/dist/dataprocessor/dataprocessor.d.ts +1 -1
  14. package/dist/dataprocessor/htmldataprocessor.d.ts +1 -1
  15. package/dist/dataprocessor/htmlwriter.d.ts +1 -1
  16. package/dist/dataprocessor/xmldataprocessor.d.ts +1 -1
  17. package/dist/dev-utils/model.d.ts +1 -1
  18. package/dist/dev-utils/operationreplayer.d.ts +1 -1
  19. package/dist/dev-utils/utils.d.ts +1 -1
  20. package/dist/dev-utils/view.d.ts +1 -1
  21. package/dist/index.css +2 -2
  22. package/dist/index.css.map +1 -1
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.js +1073 -974
  25. package/dist/index.js.map +1 -1
  26. package/dist/model/batch.d.ts +1 -1
  27. package/dist/model/differ.d.ts +1 -1
  28. package/dist/model/document.d.ts +1 -1
  29. package/dist/model/documentfragment.d.ts +13 -1
  30. package/dist/model/documentselection.d.ts +1 -1
  31. package/dist/model/element.d.ts +13 -1
  32. package/dist/model/history.d.ts +1 -1
  33. package/dist/model/item.d.ts +1 -1
  34. package/dist/model/liveposition.d.ts +1 -1
  35. package/dist/model/liverange.d.ts +1 -1
  36. package/dist/model/markercollection.d.ts +1 -1
  37. package/dist/model/model.d.ts +1 -1
  38. package/dist/model/node.d.ts +1 -1
  39. package/dist/model/nodelist.d.ts +10 -1
  40. package/dist/model/operation/attributeoperation.d.ts +1 -1
  41. package/dist/model/operation/detachoperation.d.ts +1 -1
  42. package/dist/model/operation/insertoperation.d.ts +1 -1
  43. package/dist/model/operation/markeroperation.d.ts +1 -1
  44. package/dist/model/operation/mergeoperation.d.ts +1 -1
  45. package/dist/model/operation/moveoperation.d.ts +1 -1
  46. package/dist/model/operation/nooperation.d.ts +1 -1
  47. package/dist/model/operation/operation.d.ts +1 -1
  48. package/dist/model/operation/operationfactory.d.ts +1 -1
  49. package/dist/model/operation/renameoperation.d.ts +1 -1
  50. package/dist/model/operation/rootattributeoperation.d.ts +1 -1
  51. package/dist/model/operation/rootoperation.d.ts +1 -1
  52. package/dist/model/operation/splitoperation.d.ts +1 -1
  53. package/dist/model/operation/transform.d.ts +1 -1
  54. package/dist/model/operation/utils.d.ts +1 -1
  55. package/dist/model/position.d.ts +1 -1
  56. package/dist/model/range.d.ts +1 -1
  57. package/dist/model/rootelement.d.ts +1 -1
  58. package/dist/model/schema.d.ts +1 -1
  59. package/dist/model/selection.d.ts +1 -1
  60. package/dist/model/text.d.ts +1 -1
  61. package/dist/model/textproxy.d.ts +1 -1
  62. package/dist/model/treewalker.d.ts +1 -1
  63. package/dist/model/typecheckable.d.ts +1 -1
  64. package/dist/model/utils/autoparagraphing.d.ts +1 -1
  65. package/dist/model/utils/deletecontent.d.ts +1 -1
  66. package/dist/model/utils/getselectedcontent.d.ts +1 -1
  67. package/dist/model/utils/insertcontent.d.ts +1 -1
  68. package/dist/model/utils/insertobject.d.ts +1 -1
  69. package/dist/model/utils/modifyselection.d.ts +1 -1
  70. package/dist/model/utils/selection-post-fixer.d.ts +1 -1
  71. package/dist/model/writer.d.ts +1 -1
  72. package/dist/view/attributeelement.d.ts +1 -1
  73. package/dist/view/containerelement.d.ts +1 -1
  74. package/dist/view/datatransfer.d.ts +1 -1
  75. package/dist/view/document.d.ts +1 -1
  76. package/dist/view/documentfragment.d.ts +1 -1
  77. package/dist/view/documentselection.d.ts +1 -1
  78. package/dist/view/domconverter.d.ts +1 -1
  79. package/dist/view/downcastwriter.d.ts +1 -1
  80. package/dist/view/editableelement.d.ts +1 -1
  81. package/dist/view/element.d.ts +1 -1
  82. package/dist/view/elementdefinition.d.ts +1 -1
  83. package/dist/view/emptyelement.d.ts +1 -1
  84. package/dist/view/filler.d.ts +1 -1
  85. package/dist/view/item.d.ts +1 -1
  86. package/dist/view/matcher.d.ts +1 -1
  87. package/dist/view/node.d.ts +1 -1
  88. package/dist/view/observer/arrowkeysobserver.d.ts +1 -1
  89. package/dist/view/observer/bubblingemittermixin.d.ts +1 -1
  90. package/dist/view/observer/bubblingeventinfo.d.ts +1 -1
  91. package/dist/view/observer/clickobserver.d.ts +1 -1
  92. package/dist/view/observer/compositionobserver.d.ts +1 -1
  93. package/dist/view/observer/domeventdata.d.ts +1 -1
  94. package/dist/view/observer/domeventobserver.d.ts +1 -1
  95. package/dist/view/observer/fakeselectionobserver.d.ts +1 -1
  96. package/dist/view/observer/focusobserver.d.ts +1 -1
  97. package/dist/view/observer/inputobserver.d.ts +1 -1
  98. package/dist/view/observer/keyobserver.d.ts +1 -1
  99. package/dist/view/observer/mouseobserver.d.ts +1 -1
  100. package/dist/view/observer/mutationobserver.d.ts +1 -1
  101. package/dist/view/observer/observer.d.ts +1 -1
  102. package/dist/view/observer/selectionobserver.d.ts +1 -1
  103. package/dist/view/observer/tabobserver.d.ts +1 -1
  104. package/dist/view/placeholder.d.ts +1 -1
  105. package/dist/view/position.d.ts +1 -1
  106. package/dist/view/range.d.ts +1 -1
  107. package/dist/view/rawelement.d.ts +1 -1
  108. package/dist/view/renderer.d.ts +1 -1
  109. package/dist/view/rooteditableelement.d.ts +1 -1
  110. package/dist/view/selection.d.ts +1 -1
  111. package/dist/view/styles/background.d.ts +1 -1
  112. package/dist/view/styles/border.d.ts +1 -1
  113. package/dist/view/styles/margin.d.ts +1 -1
  114. package/dist/view/styles/padding.d.ts +1 -1
  115. package/dist/view/styles/utils.d.ts +1 -1
  116. package/dist/view/stylesmap.d.ts +9 -1
  117. package/dist/view/text.d.ts +1 -1
  118. package/dist/view/textproxy.d.ts +1 -1
  119. package/dist/view/treewalker.d.ts +1 -1
  120. package/dist/view/typecheckable.d.ts +1 -1
  121. package/dist/view/uielement.d.ts +1 -1
  122. package/dist/view/upcastwriter.d.ts +1 -1
  123. package/dist/view/view.d.ts +1 -1
  124. package/package.json +2 -2
  125. package/src/controller/datacontroller.d.ts +1 -1
  126. package/src/controller/datacontroller.js +1 -1
  127. package/src/controller/editingcontroller.d.ts +1 -1
  128. package/src/controller/editingcontroller.js +1 -1
  129. package/src/conversion/conversion.d.ts +1 -1
  130. package/src/conversion/conversion.js +1 -1
  131. package/src/conversion/conversionhelpers.d.ts +1 -1
  132. package/src/conversion/conversionhelpers.js +1 -1
  133. package/src/conversion/downcastdispatcher.d.ts +1 -1
  134. package/src/conversion/downcastdispatcher.js +5 -7
  135. package/src/conversion/downcasthelpers.d.ts +1 -1
  136. package/src/conversion/downcasthelpers.js +1 -1
  137. package/src/conversion/mapper.d.ts +1 -1
  138. package/src/conversion/mapper.js +27 -22
  139. package/src/conversion/modelconsumable.d.ts +1 -1
  140. package/src/conversion/modelconsumable.js +1 -1
  141. package/src/conversion/upcastdispatcher.d.ts +1 -1
  142. package/src/conversion/upcastdispatcher.js +14 -8
  143. package/src/conversion/upcasthelpers.d.ts +1 -1
  144. package/src/conversion/upcasthelpers.js +1 -1
  145. package/src/conversion/viewconsumable.d.ts +1 -1
  146. package/src/conversion/viewconsumable.js +1 -1
  147. package/src/dataprocessor/basichtmlwriter.d.ts +1 -1
  148. package/src/dataprocessor/basichtmlwriter.js +1 -1
  149. package/src/dataprocessor/dataprocessor.d.ts +1 -1
  150. package/src/dataprocessor/dataprocessor.js +1 -1
  151. package/src/dataprocessor/htmldataprocessor.d.ts +1 -1
  152. package/src/dataprocessor/htmldataprocessor.js +1 -1
  153. package/src/dataprocessor/htmlwriter.d.ts +1 -1
  154. package/src/dataprocessor/htmlwriter.js +1 -1
  155. package/src/dataprocessor/xmldataprocessor.d.ts +1 -1
  156. package/src/dataprocessor/xmldataprocessor.js +1 -1
  157. package/src/dev-utils/model.d.ts +1 -1
  158. package/src/dev-utils/model.js +1 -1
  159. package/src/dev-utils/operationreplayer.d.ts +1 -1
  160. package/src/dev-utils/operationreplayer.js +1 -1
  161. package/src/dev-utils/utils.d.ts +1 -1
  162. package/src/dev-utils/utils.js +1 -1
  163. package/src/dev-utils/view.d.ts +1 -1
  164. package/src/dev-utils/view.js +1 -1
  165. package/src/index.d.ts +1 -1
  166. package/src/index.js +1 -1
  167. package/src/model/batch.d.ts +1 -1
  168. package/src/model/batch.js +1 -1
  169. package/src/model/differ.d.ts +1 -1
  170. package/src/model/differ.js +1 -1
  171. package/src/model/document.d.ts +1 -1
  172. package/src/model/document.js +1 -1
  173. package/src/model/documentfragment.d.ts +13 -1
  174. package/src/model/documentfragment.js +18 -1
  175. package/src/model/documentselection.d.ts +1 -1
  176. package/src/model/documentselection.js +1 -1
  177. package/src/model/element.d.ts +13 -1
  178. package/src/model/element.js +36 -10
  179. package/src/model/history.d.ts +1 -1
  180. package/src/model/history.js +1 -1
  181. package/src/model/item.d.ts +1 -1
  182. package/src/model/item.js +1 -1
  183. package/src/model/liveposition.d.ts +1 -1
  184. package/src/model/liveposition.js +1 -1
  185. package/src/model/liverange.d.ts +1 -1
  186. package/src/model/liverange.js +1 -1
  187. package/src/model/markercollection.d.ts +1 -1
  188. package/src/model/markercollection.js +1 -1
  189. package/src/model/model.d.ts +1 -1
  190. package/src/model/model.js +1 -1
  191. package/src/model/node.d.ts +1 -1
  192. package/src/model/node.js +1 -1
  193. package/src/model/nodelist.d.ts +10 -1
  194. package/src/model/nodelist.js +34 -8
  195. package/src/model/operation/attributeoperation.d.ts +1 -1
  196. package/src/model/operation/attributeoperation.js +1 -1
  197. package/src/model/operation/detachoperation.d.ts +1 -1
  198. package/src/model/operation/detachoperation.js +1 -1
  199. package/src/model/operation/insertoperation.d.ts +1 -1
  200. package/src/model/operation/insertoperation.js +1 -1
  201. package/src/model/operation/markeroperation.d.ts +1 -1
  202. package/src/model/operation/markeroperation.js +1 -1
  203. package/src/model/operation/mergeoperation.d.ts +1 -1
  204. package/src/model/operation/mergeoperation.js +1 -1
  205. package/src/model/operation/moveoperation.d.ts +1 -1
  206. package/src/model/operation/moveoperation.js +1 -1
  207. package/src/model/operation/nooperation.d.ts +1 -1
  208. package/src/model/operation/nooperation.js +1 -1
  209. package/src/model/operation/operation.d.ts +1 -1
  210. package/src/model/operation/operation.js +1 -1
  211. package/src/model/operation/operationfactory.d.ts +1 -1
  212. package/src/model/operation/operationfactory.js +1 -1
  213. package/src/model/operation/renameoperation.d.ts +1 -1
  214. package/src/model/operation/renameoperation.js +1 -1
  215. package/src/model/operation/rootattributeoperation.d.ts +1 -1
  216. package/src/model/operation/rootattributeoperation.js +1 -1
  217. package/src/model/operation/rootoperation.d.ts +1 -1
  218. package/src/model/operation/rootoperation.js +1 -1
  219. package/src/model/operation/splitoperation.d.ts +1 -1
  220. package/src/model/operation/splitoperation.js +1 -1
  221. package/src/model/operation/transform.d.ts +1 -1
  222. package/src/model/operation/transform.js +1 -1
  223. package/src/model/operation/utils.d.ts +1 -1
  224. package/src/model/operation/utils.js +1 -1
  225. package/src/model/position.d.ts +1 -1
  226. package/src/model/position.js +3 -3
  227. package/src/model/range.d.ts +1 -1
  228. package/src/model/range.js +1 -1
  229. package/src/model/rootelement.d.ts +1 -1
  230. package/src/model/rootelement.js +1 -1
  231. package/src/model/schema.d.ts +1 -1
  232. package/src/model/schema.js +1 -1
  233. package/src/model/selection.d.ts +1 -1
  234. package/src/model/selection.js +1 -1
  235. package/src/model/text.d.ts +1 -1
  236. package/src/model/text.js +1 -1
  237. package/src/model/textproxy.d.ts +1 -1
  238. package/src/model/textproxy.js +1 -1
  239. package/src/model/treewalker.d.ts +1 -1
  240. package/src/model/treewalker.js +5 -10
  241. package/src/model/typecheckable.d.ts +1 -1
  242. package/src/model/typecheckable.js +1 -1
  243. package/src/model/utils/autoparagraphing.d.ts +1 -1
  244. package/src/model/utils/autoparagraphing.js +1 -1
  245. package/src/model/utils/deletecontent.d.ts +1 -1
  246. package/src/model/utils/deletecontent.js +1 -1
  247. package/src/model/utils/getselectedcontent.d.ts +1 -1
  248. package/src/model/utils/getselectedcontent.js +1 -1
  249. package/src/model/utils/insertcontent.d.ts +1 -1
  250. package/src/model/utils/insertcontent.js +1 -1
  251. package/src/model/utils/insertobject.d.ts +1 -1
  252. package/src/model/utils/insertobject.js +1 -1
  253. package/src/model/utils/modifyselection.d.ts +1 -1
  254. package/src/model/utils/modifyselection.js +1 -1
  255. package/src/model/utils/selection-post-fixer.d.ts +1 -1
  256. package/src/model/utils/selection-post-fixer.js +1 -1
  257. package/src/model/writer.d.ts +1 -1
  258. package/src/model/writer.js +5 -2
  259. package/src/view/attributeelement.d.ts +1 -1
  260. package/src/view/attributeelement.js +1 -1
  261. package/src/view/containerelement.d.ts +1 -1
  262. package/src/view/containerelement.js +1 -1
  263. package/src/view/datatransfer.d.ts +1 -1
  264. package/src/view/datatransfer.js +1 -1
  265. package/src/view/document.d.ts +1 -1
  266. package/src/view/document.js +1 -1
  267. package/src/view/documentfragment.d.ts +1 -1
  268. package/src/view/documentfragment.js +1 -1
  269. package/src/view/documentselection.d.ts +1 -1
  270. package/src/view/documentselection.js +1 -1
  271. package/src/view/domconverter.d.ts +1 -1
  272. package/src/view/domconverter.js +1 -1
  273. package/src/view/downcastwriter.d.ts +1 -1
  274. package/src/view/downcastwriter.js +3 -3
  275. package/src/view/editableelement.d.ts +1 -1
  276. package/src/view/editableelement.js +1 -1
  277. package/src/view/element.d.ts +1 -1
  278. package/src/view/element.js +11 -9
  279. package/src/view/elementdefinition.d.ts +1 -1
  280. package/src/view/elementdefinition.js +1 -1
  281. package/src/view/emptyelement.d.ts +1 -1
  282. package/src/view/emptyelement.js +1 -1
  283. package/src/view/filler.d.ts +1 -1
  284. package/src/view/filler.js +1 -1
  285. package/src/view/item.d.ts +1 -1
  286. package/src/view/item.js +1 -1
  287. package/src/view/matcher.d.ts +1 -1
  288. package/src/view/matcher.js +21 -16
  289. package/src/view/node.d.ts +1 -1
  290. package/src/view/node.js +1 -1
  291. package/src/view/observer/arrowkeysobserver.d.ts +1 -1
  292. package/src/view/observer/arrowkeysobserver.js +1 -1
  293. package/src/view/observer/bubblingemittermixin.d.ts +1 -1
  294. package/src/view/observer/bubblingemittermixin.js +1 -1
  295. package/src/view/observer/bubblingeventinfo.d.ts +1 -1
  296. package/src/view/observer/bubblingeventinfo.js +1 -1
  297. package/src/view/observer/clickobserver.d.ts +1 -1
  298. package/src/view/observer/clickobserver.js +1 -1
  299. package/src/view/observer/compositionobserver.d.ts +1 -1
  300. package/src/view/observer/compositionobserver.js +1 -1
  301. package/src/view/observer/domeventdata.d.ts +1 -1
  302. package/src/view/observer/domeventdata.js +1 -1
  303. package/src/view/observer/domeventobserver.d.ts +1 -1
  304. package/src/view/observer/domeventobserver.js +1 -1
  305. package/src/view/observer/fakeselectionobserver.d.ts +1 -1
  306. package/src/view/observer/fakeselectionobserver.js +1 -1
  307. package/src/view/observer/focusobserver.d.ts +1 -1
  308. package/src/view/observer/focusobserver.js +1 -1
  309. package/src/view/observer/inputobserver.d.ts +1 -1
  310. package/src/view/observer/inputobserver.js +1 -1
  311. package/src/view/observer/keyobserver.d.ts +1 -1
  312. package/src/view/observer/keyobserver.js +1 -1
  313. package/src/view/observer/mouseobserver.d.ts +1 -1
  314. package/src/view/observer/mouseobserver.js +1 -1
  315. package/src/view/observer/mutationobserver.d.ts +1 -1
  316. package/src/view/observer/mutationobserver.js +1 -1
  317. package/src/view/observer/observer.d.ts +1 -1
  318. package/src/view/observer/observer.js +1 -1
  319. package/src/view/observer/selectionobserver.d.ts +1 -1
  320. package/src/view/observer/selectionobserver.js +1 -1
  321. package/src/view/observer/tabobserver.d.ts +1 -1
  322. package/src/view/observer/tabobserver.js +1 -1
  323. package/src/view/placeholder.d.ts +1 -1
  324. package/src/view/placeholder.js +1 -1
  325. package/src/view/position.d.ts +1 -1
  326. package/src/view/position.js +1 -1
  327. package/src/view/range.d.ts +1 -1
  328. package/src/view/range.js +1 -1
  329. package/src/view/rawelement.d.ts +1 -1
  330. package/src/view/rawelement.js +1 -1
  331. package/src/view/renderer.d.ts +1 -1
  332. package/src/view/renderer.js +1 -1
  333. package/src/view/rooteditableelement.d.ts +1 -1
  334. package/src/view/rooteditableelement.js +1 -1
  335. package/src/view/selection.d.ts +1 -1
  336. package/src/view/selection.js +1 -1
  337. package/src/view/styles/background.d.ts +1 -1
  338. package/src/view/styles/background.js +1 -1
  339. package/src/view/styles/border.d.ts +1 -1
  340. package/src/view/styles/border.js +1 -1
  341. package/src/view/styles/margin.d.ts +1 -1
  342. package/src/view/styles/margin.js +1 -1
  343. package/src/view/styles/padding.d.ts +1 -1
  344. package/src/view/styles/padding.js +1 -1
  345. package/src/view/styles/utils.d.ts +1 -1
  346. package/src/view/styles/utils.js +1 -1
  347. package/src/view/stylesmap.d.ts +9 -1
  348. package/src/view/stylesmap.js +19 -4
  349. package/src/view/text.d.ts +1 -1
  350. package/src/view/text.js +1 -1
  351. package/src/view/textproxy.d.ts +1 -1
  352. package/src/view/textproxy.js +1 -1
  353. package/src/view/treewalker.d.ts +1 -1
  354. package/src/view/treewalker.js +38 -43
  355. package/src/view/typecheckable.d.ts +1 -1
  356. package/src/view/typecheckable.js +1 -1
  357. package/src/view/uielement.d.ts +1 -1
  358. package/src/view/uielement.js +1 -1
  359. package/src/view/upcastwriter.d.ts +1 -1
  360. package/src/view/upcastwriter.js +1 -1
  361. package/src/view/view.d.ts +1 -1
  362. package/src/view/view.js +1 -1
  363. package/theme/placeholder.css +1 -1
  364. package/theme/renderer.css +1 -1
package/dist/index.js CHANGED
@@ -2,8 +2,8 @@
2
2
  * @license Copyright (c) 2003-2024, 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
- import { logWarning, EmitterMixin, CKEditorError, compareArrays, toArray, toMap, isIterable, ObservableMixin, count, EventInfo, Collection, keyCodes, isText, env, remove as remove$1, insertAt, diff, fastDiff, isNode, isComment, indexOf, global, isValidAttributeName, first, getAncestors, DomEmitterMixin, getCode, isArrowKeyCode, scrollViewportToShowTarget, spliceArray, uid, priorities, isInsideSurrogatePair, isInsideCombinedSymbol, isInsideEmojiSequence } from '@ckeditor/ckeditor5-utils/dist/index.js';
6
- import { clone, isPlainObject, isObject, unset, get, merge, set, extend, debounce, isEqualWith, cloneDeep, isEqual } from 'lodash-es';
5
+ import { logWarning, EmitterMixin, CKEditorError, compareArrays, toArray, toMap, isIterable, ObservableMixin, count, EventInfo, Collection, keyCodes, isText, env, remove as remove$1, insertAt, diff, fastDiff, isNode, isComment, indexOf, global, isValidAttributeName, first, getAncestors, DomEmitterMixin, getCode, isArrowKeyCode, scrollViewportToShowTarget, uid, spliceArray, priorities, isInsideSurrogatePair, isInsideCombinedSymbol, isInsideEmojiSequence } from '@ckeditor/ckeditor5-utils/dist/index.js';
6
+ import { clone, isObject, unset, get, merge, set, isPlainObject, extend, debounce, isEqualWith, cloneDeep, isEqual } from 'lodash-es';
7
7
 
8
8
  // Each document stores information about its placeholder elements and check functions.
9
9
  const documentPlaceholders = new WeakMap();
@@ -255,7 +255,7 @@ let hasDisplayedPlaceholderDeprecationWarning = false;
255
255
 
256
256
  /**
257
257
  * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
258
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
258
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
259
259
  */ /**
260
260
  * @module engine/view/typecheckable
261
261
  */ let TypeCheckable$1 = class TypeCheckable {
@@ -1005,33 +1005,42 @@ TextProxy$1.prototype.is = function(type) {
1005
1005
  */ function normalizePatterns(patterns) {
1006
1006
  if (Array.isArray(patterns)) {
1007
1007
  return patterns.map((pattern)=>{
1008
- if (isPlainObject(pattern)) {
1009
- if (pattern.key === undefined || pattern.value === undefined) {
1010
- // Documented at the end of matcher.js.
1011
- logWarning('matcher-pattern-missing-key-or-value', pattern);
1012
- }
1008
+ if (typeof pattern !== 'object' || pattern instanceof RegExp) {
1013
1009
  return [
1014
- pattern.key,
1015
- pattern.value
1010
+ pattern,
1011
+ true
1016
1012
  ];
1017
1013
  }
1018
- // Assume the pattern is either String or RegExp.
1014
+ if (pattern.key === undefined || pattern.value === undefined) {
1015
+ // Documented at the end of matcher.js.
1016
+ logWarning('matcher-pattern-missing-key-or-value', pattern);
1017
+ }
1019
1018
  return [
1020
- pattern,
1021
- true
1019
+ pattern.key,
1020
+ pattern.value
1022
1021
  ];
1023
1022
  });
1024
1023
  }
1025
- if (isPlainObject(patterns)) {
1026
- return Object.entries(patterns);
1024
+ if (typeof patterns !== 'object' || patterns instanceof RegExp) {
1025
+ return [
1026
+ [
1027
+ patterns,
1028
+ true
1029
+ ]
1030
+ ];
1027
1031
  }
1028
- // Other cases (true, string or regexp).
1029
- return [
1030
- [
1031
- patterns,
1032
- true
1033
- ]
1034
- ];
1032
+ // Below we do what Object.entries() does, but faster.
1033
+ const normalizedPatterns = [];
1034
+ for(const key in patterns){
1035
+ // Replace with Object.hasOwn() when we upgrade to es2022.
1036
+ if (Object.prototype.hasOwnProperty.call(patterns, key)) {
1037
+ normalizedPatterns.push([
1038
+ key,
1039
+ patterns[key]
1040
+ ]);
1041
+ }
1042
+ }
1043
+ return normalizedPatterns;
1035
1044
  }
1036
1045
  /**
1037
1046
  * @param patternKey A pattern representing a key we want to match.
@@ -1064,7 +1073,7 @@ TextProxy$1.prototype.is = function(type) {
1064
1073
  const attributeKeys = new Set(element.getAttributeKeys());
1065
1074
  // `style` and `class` attribute keys are deprecated. Only allow them in object pattern
1066
1075
  // for backward compatibility.
1067
- if (isPlainObject(patterns)) {
1076
+ if (typeof patterns === 'object' && !(patterns instanceof RegExp) && !Array.isArray(patterns)) {
1068
1077
  if (patterns.style !== undefined) {
1069
1078
  // Documented at the end of matcher.js.
1070
1079
  logWarning('matcher-pattern-deprecated-attributes-style-key', patterns);
@@ -1176,6 +1185,12 @@ TextProxy$1.prototype.is = function(type) {
1176
1185
  *
1177
1186
  * When no style processor rules are defined it acts as simple key-value storage.
1178
1187
  */ _styles;
1188
+ /**
1189
+ * Cached list of style names for faster access.
1190
+ */ _cachedStyleNames = null;
1191
+ /**
1192
+ * Cached list of expanded style names for faster access.
1193
+ */ _cachedExpandedStyleNames = null;
1179
1194
  /**
1180
1195
  * An instance of the {@link module:engine/view/stylesmap~StylesProcessor}.
1181
1196
  */ _styleProcessor;
@@ -1252,6 +1267,8 @@ TextProxy$1.prototype.is = function(type) {
1252
1267
  return Array.isArray(propertyDescriptor);
1253
1268
  }
1254
1269
  set(nameOrObject, valueOrObject) {
1270
+ this._cachedStyleNames = null;
1271
+ this._cachedExpandedStyleNames = null;
1255
1272
  if (isObject(nameOrObject)) {
1256
1273
  for (const [key, value] of Object.entries(nameOrObject)){
1257
1274
  this._styleProcessor.toNormalizedForm(key, value, this._styles);
@@ -1288,6 +1305,8 @@ TextProxy$1.prototype.is = function(type) {
1288
1305
  *
1289
1306
  * @param name Style name.
1290
1307
  */ remove(name) {
1308
+ this._cachedStyleNames = null;
1309
+ this._cachedExpandedStyleNames = null;
1291
1310
  const path = toPath(name);
1292
1311
  unset(this._styles, path);
1293
1312
  delete this._styles[name];
@@ -1441,15 +1460,18 @@ TextProxy$1.prototype.is = function(type) {
1441
1460
  return [];
1442
1461
  }
1443
1462
  if (expand) {
1444
- return this._styleProcessor.getStyleNames(this._styles);
1463
+ this._cachedExpandedStyleNames = this._cachedExpandedStyleNames || this._styleProcessor.getStyleNames(this._styles);
1464
+ return this._cachedExpandedStyleNames;
1445
1465
  }
1446
- const entries = this.getStylesEntries();
1447
- return entries.map(([key])=>key);
1466
+ this._cachedStyleNames = this._cachedStyleNames || this.getStylesEntries().map(([key])=>key);
1467
+ return this._cachedStyleNames;
1448
1468
  }
1449
1469
  /**
1450
1470
  * Removes all styles.
1451
1471
  */ clear() {
1452
1472
  this._styles = {};
1473
+ this._cachedStyleNames = null;
1474
+ this._cachedExpandedStyleNames = null;
1453
1475
  }
1454
1476
  /**
1455
1477
  * Returns normalized styles entries for further processing.
@@ -2584,16 +2606,17 @@ Element$1.prototype.is = function(type, name) {
2584
2606
  nodes
2585
2607
  ];
2586
2608
  }
2587
- // Array.from to enable .map() on non-arrays.
2588
- return Array.from(nodes).map((node)=>{
2609
+ const normalizedNodes = [];
2610
+ for (const node of nodes){
2589
2611
  if (typeof node == 'string') {
2590
- return new Text$1(document, node);
2591
- }
2592
- if (node instanceof TextProxy$1) {
2593
- return new Text$1(document, node.data);
2612
+ normalizedNodes.push(new Text$1(document, node));
2613
+ } else if (node instanceof TextProxy$1) {
2614
+ normalizedNodes.push(new Text$1(document, node.data));
2615
+ } else {
2616
+ normalizedNodes.push(node);
2594
2617
  }
2595
- return node;
2596
- });
2618
+ }
2619
+ return normalizedNodes;
2597
2620
  }
2598
2621
 
2599
2622
  /**
@@ -2901,7 +2924,7 @@ RootEditableElement.prototype.is = function(type, name) {
2901
2924
  // Get node just after current position.
2902
2925
  let node;
2903
2926
  // Text is a specific parent because it contains string instead of child nodes.
2904
- if (parent instanceof Text$1) {
2927
+ if (parent && parent.is('view:$text')) {
2905
2928
  if (position.isAtEnd) {
2906
2929
  // Prevent returning "elementEnd" for Text node. Skip that value and return the next walker step.
2907
2930
  this._position = Position$1._createAfter(parent);
@@ -2911,7 +2934,21 @@ RootEditableElement.prototype.is = function(type, name) {
2911
2934
  } else {
2912
2935
  node = parent.getChild(position.offset);
2913
2936
  }
2914
- if (node instanceof Element$1) {
2937
+ if (typeof node == 'string') {
2938
+ let textLength;
2939
+ if (this.singleCharacters) {
2940
+ textLength = 1;
2941
+ } else {
2942
+ // Check if text stick out of walker range.
2943
+ const endOffset = parent === this._boundaryEndParent ? this.boundaries.end.offset : parent.data.length;
2944
+ textLength = endOffset - position.offset;
2945
+ }
2946
+ const textProxy = new TextProxy$1(parent, position.offset, textLength);
2947
+ position.offset += textLength;
2948
+ this._position = position;
2949
+ return this._formatReturnValue('text', textProxy, previousPosition, position, textLength);
2950
+ }
2951
+ if (node && node.is('view:element')) {
2915
2952
  if (!this.shallow) {
2916
2953
  position = new Position$1(node, 0);
2917
2954
  } else {
@@ -2927,7 +2964,7 @@ RootEditableElement.prototype.is = function(type, name) {
2927
2964
  this._position = position;
2928
2965
  return this._formatReturnValue('elementStart', node, previousPosition, position, 1);
2929
2966
  }
2930
- if (node instanceof Text$1) {
2967
+ if (node && node.is('view:$text')) {
2931
2968
  if (this.singleCharacters) {
2932
2969
  position = new Position$1(node, 0);
2933
2970
  this._position = position;
@@ -2948,20 +2985,6 @@ RootEditableElement.prototype.is = function(type, name) {
2948
2985
  this._position = position;
2949
2986
  return this._formatReturnValue('text', item, previousPosition, position, charactersCount);
2950
2987
  }
2951
- if (typeof node == 'string') {
2952
- let textLength;
2953
- if (this.singleCharacters) {
2954
- textLength = 1;
2955
- } else {
2956
- // Check if text stick out of walker range.
2957
- const endOffset = parent === this._boundaryEndParent ? this.boundaries.end.offset : parent.data.length;
2958
- textLength = endOffset - position.offset;
2959
- }
2960
- const textProxy = new TextProxy$1(parent, position.offset, textLength);
2961
- position.offset += textLength;
2962
- this._position = position;
2963
- return this._formatReturnValue('text', textProxy, previousPosition, position, textLength);
2964
- }
2965
2988
  // `node` is not set, we reached the end of current `parent`.
2966
2989
  position = Position$1._createAfter(parent);
2967
2990
  this._position = position;
@@ -2993,7 +3016,7 @@ RootEditableElement.prototype.is = function(type, name) {
2993
3016
  // Get node just before current position.
2994
3017
  let node;
2995
3018
  // Text {@link module:engine/view/text~Text} element is a specific parent because contains string instead of child nodes.
2996
- if (parent instanceof Text$1) {
3019
+ if (parent.is('view:$text')) {
2997
3020
  if (position.isAtStart) {
2998
3021
  // Prevent returning "elementStart" for Text node. Skip that value and return the next walker step.
2999
3022
  this._position = Position$1._createBefore(parent);
@@ -3003,7 +3026,21 @@ RootEditableElement.prototype.is = function(type, name) {
3003
3026
  } else {
3004
3027
  node = parent.getChild(position.offset - 1);
3005
3028
  }
3006
- if (node instanceof Element$1) {
3029
+ if (typeof node == 'string') {
3030
+ let textLength;
3031
+ if (!this.singleCharacters) {
3032
+ // Check if text stick out of walker range.
3033
+ const startOffset = parent === this._boundaryStartParent ? this.boundaries.start.offset : 0;
3034
+ textLength = position.offset - startOffset;
3035
+ } else {
3036
+ textLength = 1;
3037
+ }
3038
+ position.offset -= textLength;
3039
+ const textProxy = new TextProxy$1(parent, position.offset, textLength);
3040
+ this._position = position;
3041
+ return this._formatReturnValue('text', textProxy, previousPosition, position, textLength);
3042
+ }
3043
+ if (node && node.is('view:element')) {
3007
3044
  if (this.shallow) {
3008
3045
  position.offset--;
3009
3046
  this._position = position;
@@ -3016,7 +3053,7 @@ RootEditableElement.prototype.is = function(type, name) {
3016
3053
  }
3017
3054
  return this._formatReturnValue('elementEnd', node, previousPosition, position);
3018
3055
  }
3019
- if (node instanceof Text$1) {
3056
+ if (node && node.is('view:$text')) {
3020
3057
  if (this.singleCharacters) {
3021
3058
  position = new Position$1(node, node.data.length);
3022
3059
  this._position = position;
@@ -3038,20 +3075,6 @@ RootEditableElement.prototype.is = function(type, name) {
3038
3075
  this._position = position;
3039
3076
  return this._formatReturnValue('text', item, previousPosition, position, charactersCount);
3040
3077
  }
3041
- if (typeof node == 'string') {
3042
- let textLength;
3043
- if (!this.singleCharacters) {
3044
- // Check if text stick out of walker range.
3045
- const startOffset = parent === this._boundaryStartParent ? this.boundaries.start.offset : 0;
3046
- textLength = position.offset - startOffset;
3047
- } else {
3048
- textLength = 1;
3049
- }
3050
- position.offset -= textLength;
3051
- const textProxy = new TextProxy$1(parent, position.offset, textLength);
3052
- this._position = position;
3053
- return this._formatReturnValue('text', textProxy, previousPosition, position, textLength);
3054
- }
3055
3078
  // `node` is not set, we reached the beginning of current `parent`.
3056
3079
  position = Position$1._createBefore(parent);
3057
3080
  this._position = position;
@@ -3070,7 +3093,7 @@ RootEditableElement.prototype.is = function(type, name) {
3070
3093
  // Walker doesn't enter to the Text except situations when walker is iterating over every single character,
3071
3094
  // or the bound starts/ends inside the Text. So when the position is at the beginning or at the end of the Text
3072
3095
  // we move it just before or just after Text.
3073
- if (item instanceof TextProxy$1) {
3096
+ if (item.is('view:$textProxy')) {
3074
3097
  // Position is at the end of Text.
3075
3098
  if (item.offsetInText + item.data.length == item.textNode.data.length) {
3076
3099
  if (this.direction == 'forward' && !(this.boundaries && this.boundaries.end.isEqual(this.position))) {
@@ -6669,7 +6692,7 @@ DocumentFragment$1.prototype.is = function(type) {
6669
6692
  // If position is placed between text nodes - merge them and return position inside.
6670
6693
  const nodeBefore = newPosition.nodeBefore;
6671
6694
  const nodeAfter = newPosition.nodeAfter;
6672
- if (nodeBefore instanceof Text$1 && nodeAfter instanceof Text$1) {
6695
+ if (nodeBefore && nodeBefore.is('view:$text') && nodeAfter && nodeAfter.is('view:$text')) {
6673
6696
  return mergeTextNodes(nodeBefore, nodeAfter);
6674
6697
  }
6675
6698
  // If position is next to text node - move position inside.
@@ -10699,7 +10722,7 @@ function sameNodes(child1, child2) {
10699
10722
 
10700
10723
  /**
10701
10724
  * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
10702
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
10725
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
10703
10726
  */ /**
10704
10727
  * @module engine/view/datatransfer
10705
10728
  */ /**
@@ -11516,7 +11539,7 @@ function getFiles(nativeDataTransfer) {
11516
11539
 
11517
11540
  /**
11518
11541
  * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
11519
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
11542
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
11520
11543
  */ /**
11521
11544
  * @module engine/model/typecheckable
11522
11545
  */ class TypeCheckable {
@@ -11531,601 +11554,6 @@ function getFiles(nativeDataTransfer) {
11531
11554
  }
11532
11555
  }
11533
11556
 
11534
- /**
11535
- * Model node. Most basic structure of model tree.
11536
- *
11537
- * This is an abstract class that is a base for other classes representing different nodes in model.
11538
- *
11539
- * **Note:** If a node is detached from the model tree, you can manipulate it using it's API.
11540
- * However, it is **very important** that nodes already attached to model tree should be only changed through
11541
- * {@link module:engine/model/writer~Writer Writer API}.
11542
- *
11543
- * Changes done by `Node` methods, like {@link module:engine/model/element~Element#_insertChild _insertChild} or
11544
- * {@link module:engine/model/node~Node#_setAttribute _setAttribute}
11545
- * do not generate {@link module:engine/model/operation/operation~Operation operations}
11546
- * which are essential for correct editor work if you modify nodes in {@link module:engine/model/document~Document document} root.
11547
- *
11548
- * The flow of working on `Node` (and classes that inherits from it) is as such:
11549
- * 1. You can create a `Node` instance, modify it using it's API.
11550
- * 2. Add `Node` to the model using `Batch` API.
11551
- * 3. Change `Node` that was already added to the model using `Batch` API.
11552
- *
11553
- * Similarly, you cannot use `Batch` API on a node that has not been added to the model tree, with the exception
11554
- * of {@link module:engine/model/writer~Writer#insert inserting} that node to the model tree.
11555
- *
11556
- * Be aware that using {@link module:engine/model/writer~Writer#remove remove from Batch API} does not allow to use `Node` API because
11557
- * the information about `Node` is still kept in model document.
11558
- *
11559
- * In case of {@link module:engine/model/element~Element element node}, adding and removing children also counts as changing a node and
11560
- * follows same rules.
11561
- */ let Node$1 = class Node extends TypeCheckable {
11562
- /**
11563
- * Parent of this node. It could be {@link module:engine/model/element~Element}
11564
- * or {@link module:engine/model/documentfragment~DocumentFragment}.
11565
- * Equals to `null` if the node has no parent.
11566
- */ parent = null;
11567
- /**
11568
- * Attributes set on this node.
11569
- */ _attrs;
11570
- /**
11571
- * Index of this node in its parent or `null` if the node has no parent.
11572
- *
11573
- * @internal
11574
- */ _index = null;
11575
- /**
11576
- * Offset at which this node starts in its parent or `null` if the node has no parent.
11577
- *
11578
- * @internal
11579
- */ _startOffset = null;
11580
- /**
11581
- * Creates a model node.
11582
- *
11583
- * This is an abstract class, so this constructor should not be used directly.
11584
- *
11585
- * @param attrs Node's attributes. See {@link module:utils/tomap~toMap} for a list of accepted values.
11586
- */ constructor(attrs){
11587
- super();
11588
- this._attrs = toMap(attrs);
11589
- }
11590
- /**
11591
- * {@link module:engine/model/document~Document Document} that owns this root element.
11592
- */ get document() {
11593
- return null;
11594
- }
11595
- /**
11596
- * Index of this node in its parent or `null` if the node has no parent.
11597
- */ get index() {
11598
- return this._index;
11599
- }
11600
- /**
11601
- * Offset at which this node starts in its parent. It is equal to the sum of {@link #offsetSize offsetSize}
11602
- * of all its previous siblings. Equals to `null` if node has no parent.
11603
- */ get startOffset() {
11604
- return this._startOffset;
11605
- }
11606
- /**
11607
- * Offset size of this node.
11608
- *
11609
- * Represents how much "offset space" is occupied by the node in its parent. It is important for
11610
- * {@link module:engine/model/position~Position position}. When node has `offsetSize` greater than `1`, position can be placed between
11611
- * that node start and end. `offsetSize` greater than `1` is for nodes that represents more than one entity, i.e.
11612
- * a {@link module:engine/model/text~Text text node}.
11613
- */ get offsetSize() {
11614
- return 1;
11615
- }
11616
- /**
11617
- * Offset at which this node ends in its parent. It is equal to the sum of this node's
11618
- * {@link module:engine/model/node~Node#startOffset start offset} and {@link #offsetSize offset size}.
11619
- * Equals to `null` if the node has no parent.
11620
- */ get endOffset() {
11621
- if (this.startOffset === null) {
11622
- return null;
11623
- }
11624
- return this.startOffset + this.offsetSize;
11625
- }
11626
- /**
11627
- * Node's next sibling or `null` if the node is a last child of it's parent or if the node has no parent.
11628
- */ get nextSibling() {
11629
- const index = this.index;
11630
- return index !== null && this.parent.getChild(index + 1) || null;
11631
- }
11632
- /**
11633
- * Node's previous sibling or `null` if the node is a first child of it's parent or if the node has no parent.
11634
- */ get previousSibling() {
11635
- const index = this.index;
11636
- return index !== null && this.parent.getChild(index - 1) || null;
11637
- }
11638
- /**
11639
- * The top-most ancestor of the node. If node has no parent it is the root itself. If the node is a part
11640
- * of {@link module:engine/model/documentfragment~DocumentFragment}, it's `root` is equal to that `DocumentFragment`.
11641
- */ get root() {
11642
- // eslint-disable-next-line @typescript-eslint/no-this-alias, consistent-this
11643
- let root = this;
11644
- while(root.parent){
11645
- root = root.parent;
11646
- }
11647
- return root;
11648
- }
11649
- /**
11650
- * Returns `true` if the node is inside a document root that is attached to the document.
11651
- */ isAttached() {
11652
- // If the node has no parent it means that it is a root.
11653
- // But this is not a `RootElement`, so it means that it is not attached.
11654
- //
11655
- // If this is not the root, check if this element's root is attached.
11656
- return this.parent === null ? false : this.root.isAttached();
11657
- }
11658
- /**
11659
- * Gets path to the node. The path is an array containing starting offsets of consecutive ancestors of this node,
11660
- * beginning from {@link module:engine/model/node~Node#root root}, down to this node's starting offset. The path can be used to
11661
- * create {@link module:engine/model/position~Position Position} instance.
11662
- *
11663
- * ```ts
11664
- * const abc = new Text( 'abc' );
11665
- * const foo = new Text( 'foo' );
11666
- * const h1 = new Element( 'h1', null, new Text( 'header' ) );
11667
- * const p = new Element( 'p', null, [ abc, foo ] );
11668
- * const div = new Element( 'div', null, [ h1, p ] );
11669
- * foo.getPath(); // Returns [ 1, 3 ]. `foo` is in `p` which is in `div`. `p` starts at offset 1, while `foo` at 3.
11670
- * h1.getPath(); // Returns [ 0 ].
11671
- * div.getPath(); // Returns [].
11672
- * ```
11673
- */ getPath() {
11674
- const path = [];
11675
- // eslint-disable-next-line @typescript-eslint/no-this-alias, consistent-this
11676
- let node = this;
11677
- while(node.parent){
11678
- path.unshift(node.startOffset);
11679
- node = node.parent;
11680
- }
11681
- return path;
11682
- }
11683
- /**
11684
- * Returns ancestors array of this node.
11685
- *
11686
- * @param options Options object.
11687
- * @param options.includeSelf When set to `true` this node will be also included in parent's array.
11688
- * @param options.parentFirst When set to `true`, array will be sorted from node's parent to root element,
11689
- * otherwise root element will be the first item in the array.
11690
- * @returns Array with ancestors.
11691
- */ getAncestors(options = {}) {
11692
- const ancestors = [];
11693
- let parent = options.includeSelf ? this : this.parent;
11694
- while(parent){
11695
- ancestors[options.parentFirst ? 'push' : 'unshift'](parent);
11696
- parent = parent.parent;
11697
- }
11698
- return ancestors;
11699
- }
11700
- /**
11701
- * Returns a {@link module:engine/model/element~Element} or {@link module:engine/model/documentfragment~DocumentFragment}
11702
- * which is a common ancestor of both nodes.
11703
- *
11704
- * @param node The second node.
11705
- * @param options Options object.
11706
- * @param options.includeSelf When set to `true` both nodes will be considered "ancestors" too.
11707
- * Which means that if e.g. node A is inside B, then their common ancestor will be B.
11708
- */ getCommonAncestor(node, options = {}) {
11709
- const ancestorsA = this.getAncestors(options);
11710
- const ancestorsB = node.getAncestors(options);
11711
- let i = 0;
11712
- while(ancestorsA[i] == ancestorsB[i] && ancestorsA[i]){
11713
- i++;
11714
- }
11715
- return i === 0 ? null : ancestorsA[i - 1];
11716
- }
11717
- /**
11718
- * Returns whether this node is before given node. `false` is returned if nodes are in different trees (for example,
11719
- * in different {@link module:engine/model/documentfragment~DocumentFragment}s).
11720
- *
11721
- * @param node Node to compare with.
11722
- */ isBefore(node) {
11723
- // Given node is not before this node if they are same.
11724
- if (this == node) {
11725
- return false;
11726
- }
11727
- // Return `false` if it is impossible to compare nodes.
11728
- if (this.root !== node.root) {
11729
- return false;
11730
- }
11731
- const thisPath = this.getPath();
11732
- const nodePath = node.getPath();
11733
- const result = compareArrays(thisPath, nodePath);
11734
- switch(result){
11735
- case 'prefix':
11736
- return true;
11737
- case 'extension':
11738
- return false;
11739
- default:
11740
- return thisPath[result] < nodePath[result];
11741
- }
11742
- }
11743
- /**
11744
- * Returns whether this node is after given node. `false` is returned if nodes are in different trees (for example,
11745
- * in different {@link module:engine/model/documentfragment~DocumentFragment}s).
11746
- *
11747
- * @param node Node to compare with.
11748
- */ isAfter(node) {
11749
- // Given node is not before this node if they are same.
11750
- if (this == node) {
11751
- return false;
11752
- }
11753
- // Return `false` if it is impossible to compare nodes.
11754
- if (this.root !== node.root) {
11755
- return false;
11756
- }
11757
- // In other cases, just check if the `node` is before, and return the opposite.
11758
- return !this.isBefore(node);
11759
- }
11760
- /**
11761
- * Checks if the node has an attribute with given key.
11762
- *
11763
- * @param key Key of attribute to check.
11764
- * @returns `true` if attribute with given key is set on node, `false` otherwise.
11765
- */ hasAttribute(key) {
11766
- return this._attrs.has(key);
11767
- }
11768
- /**
11769
- * Gets an attribute value for given key or `undefined` if that attribute is not set on node.
11770
- *
11771
- * @param key Key of attribute to look for.
11772
- * @returns Attribute value or `undefined`.
11773
- */ getAttribute(key) {
11774
- return this._attrs.get(key);
11775
- }
11776
- /**
11777
- * Returns iterator that iterates over this node's attributes.
11778
- *
11779
- * Attributes are returned as arrays containing two items. First one is attribute key and second is attribute value.
11780
- * This format is accepted by native `Map` object and also can be passed in `Node` constructor.
11781
- */ getAttributes() {
11782
- return this._attrs.entries();
11783
- }
11784
- /**
11785
- * Returns iterator that iterates over this node's attribute keys.
11786
- */ getAttributeKeys() {
11787
- return this._attrs.keys();
11788
- }
11789
- /**
11790
- * Converts `Node` to plain object and returns it.
11791
- *
11792
- * @returns `Node` converted to plain object.
11793
- */ toJSON() {
11794
- const json = {};
11795
- // Serializes attributes to the object.
11796
- // attributes = { a: 'foo', b: 1, c: true }.
11797
- if (this._attrs.size) {
11798
- json.attributes = Array.from(this._attrs).reduce((result, attr)=>{
11799
- result[attr[0]] = attr[1];
11800
- return result;
11801
- }, {});
11802
- }
11803
- return json;
11804
- }
11805
- /**
11806
- * Creates a copy of this node, that is a node with exactly same attributes, and returns it.
11807
- *
11808
- * @internal
11809
- * @returns Node with same attributes as this node.
11810
- */ _clone(_deep) {
11811
- return new this.constructor(this._attrs);
11812
- }
11813
- /**
11814
- * Removes this node from its parent.
11815
- *
11816
- * @internal
11817
- * @see module:engine/model/writer~Writer#remove
11818
- */ _remove() {
11819
- this.parent._removeChildren(this.index);
11820
- }
11821
- /**
11822
- * Sets attribute on the node. If attribute with the same key already is set, it's value is overwritten.
11823
- *
11824
- * @see module:engine/model/writer~Writer#setAttribute
11825
- * @internal
11826
- * @param key Key of attribute to set.
11827
- * @param value Attribute value.
11828
- */ _setAttribute(key, value) {
11829
- this._attrs.set(key, value);
11830
- }
11831
- /**
11832
- * Removes all attributes from the node and sets given attributes.
11833
- *
11834
- * @see module:engine/model/writer~Writer#setAttributes
11835
- * @internal
11836
- * @param attrs Attributes to set. See {@link module:utils/tomap~toMap} for a list of accepted values.
11837
- */ _setAttributesTo(attrs) {
11838
- this._attrs = toMap(attrs);
11839
- }
11840
- /**
11841
- * Removes an attribute with given key from the node.
11842
- *
11843
- * @see module:engine/model/writer~Writer#removeAttribute
11844
- * @internal
11845
- * @param key Key of attribute to remove.
11846
- * @returns `true` if the attribute was set on the element, `false` otherwise.
11847
- */ _removeAttribute(key) {
11848
- return this._attrs.delete(key);
11849
- }
11850
- /**
11851
- * Removes all attributes from the node.
11852
- *
11853
- * @see module:engine/model/writer~Writer#clearAttributes
11854
- * @internal
11855
- */ _clearAttributes() {
11856
- this._attrs.clear();
11857
- }
11858
- };
11859
- // The magic of type inference using `is` method is centralized in `TypeCheckable` class.
11860
- // Proper overload would interfere with that.
11861
- Node$1.prototype.is = function(type) {
11862
- return type === 'node' || type === 'model:node';
11863
- };
11864
-
11865
- /**
11866
- * Provides an interface to operate on a list of {@link module:engine/model/node~Node nodes}. `NodeList` is used internally
11867
- * in classes like {@link module:engine/model/element~Element Element}
11868
- * or {@link module:engine/model/documentfragment~DocumentFragment DocumentFragment}.
11869
- */ class NodeList {
11870
- /**
11871
- * Nodes contained in this node list.
11872
- */ _nodes = [];
11873
- /**
11874
- * This array maps numbers (offsets) to node that is placed at that offset.
11875
- *
11876
- * This array is similar to `_nodes` with the difference that one node may occupy multiple consecutive items in the array.
11877
- *
11878
- * This array is needed to quickly retrieve a node that is placed at given offset.
11879
- */ _offsetToNode = [];
11880
- /**
11881
- * Creates a node list.
11882
- *
11883
- * @internal
11884
- * @param nodes Nodes contained in this node list.
11885
- */ constructor(nodes){
11886
- if (nodes) {
11887
- this._insertNodes(0, nodes);
11888
- }
11889
- }
11890
- /**
11891
- * Iterable interface.
11892
- *
11893
- * Iterates over all nodes contained inside this node list.
11894
- */ [Symbol.iterator]() {
11895
- return this._nodes[Symbol.iterator]();
11896
- }
11897
- /**
11898
- * Number of nodes contained inside this node list.
11899
- */ get length() {
11900
- return this._nodes.length;
11901
- }
11902
- /**
11903
- * Sum of {@link module:engine/model/node~Node#offsetSize offset sizes} of all nodes contained inside this node list.
11904
- */ get maxOffset() {
11905
- return this._offsetToNode.length;
11906
- }
11907
- /**
11908
- * Gets the node at the given index. Returns `null` if incorrect index was passed.
11909
- */ getNode(index) {
11910
- return this._nodes[index] || null;
11911
- }
11912
- /**
11913
- * Gets the node at the given offset. Returns `null` if incorrect offset was passed.
11914
- */ getNodeAtOffset(offset) {
11915
- return this._offsetToNode[offset] || null;
11916
- }
11917
- /**
11918
- * Returns an index of the given node or `null` if given node does not have a parent.
11919
- *
11920
- * This is an alias to {@link module:engine/model/node~Node#index}.
11921
- */ getNodeIndex(node) {
11922
- return node.index;
11923
- }
11924
- /**
11925
- * Returns the offset at which given node is placed in its parent or `null` if given node does not have a parent.
11926
- *
11927
- * This is an alias to {@link module:engine/model/node~Node#startOffset}.
11928
- */ getNodeStartOffset(node) {
11929
- return node.startOffset;
11930
- }
11931
- /**
11932
- * Converts index to offset in node list.
11933
- *
11934
- * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `model-nodelist-index-out-of-bounds` if given index is less
11935
- * than `0` or more than {@link #length}.
11936
- */ indexToOffset(index) {
11937
- if (index == this._nodes.length) {
11938
- return this.maxOffset;
11939
- }
11940
- const node = this._nodes[index];
11941
- if (!node) {
11942
- /**
11943
- * Given index cannot be found in the node list.
11944
- *
11945
- * @error model-nodelist-index-out-of-bounds
11946
- */ throw new CKEditorError('model-nodelist-index-out-of-bounds', this);
11947
- }
11948
- return this.getNodeStartOffset(node);
11949
- }
11950
- /**
11951
- * Converts offset in node list to index.
11952
- *
11953
- * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `model-nodelist-offset-out-of-bounds` if given offset is less
11954
- * than `0` or more than {@link #maxOffset}.
11955
- */ offsetToIndex(offset) {
11956
- if (offset == this._offsetToNode.length) {
11957
- return this._nodes.length;
11958
- }
11959
- const node = this._offsetToNode[offset];
11960
- if (!node) {
11961
- /**
11962
- * Given offset cannot be found in the node list.
11963
- *
11964
- * @error model-nodelist-offset-out-of-bounds
11965
- * @param offset
11966
- * @param nodeList Stringified node list.
11967
- */ throw new CKEditorError('model-nodelist-offset-out-of-bounds', this, {
11968
- offset,
11969
- nodeList: this
11970
- });
11971
- }
11972
- return this.getNodeIndex(node);
11973
- }
11974
- /**
11975
- * Inserts given nodes at given index.
11976
- *
11977
- * @internal
11978
- * @param index Index at which nodes should be inserted.
11979
- * @param nodes Nodes to be inserted.
11980
- */ _insertNodes(index, nodes) {
11981
- // Validation.
11982
- for (const node of nodes){
11983
- if (!(node instanceof Node$1)) {
11984
- /**
11985
- * Trying to insert an object which is not a Node instance.
11986
- *
11987
- * @error model-nodelist-insertnodes-not-node
11988
- */ throw new CKEditorError('model-nodelist-insertnodes-not-node', this);
11989
- }
11990
- }
11991
- const nodesArray = Array.from(nodes);
11992
- const offsetsArray = makeOffsetsArray(nodesArray);
11993
- let offset = this.indexToOffset(index);
11994
- // Splice nodes array and offsets array into the nodelist.
11995
- this._nodes = spliceArray(this._nodes, nodesArray, index, 0);
11996
- this._offsetToNode = spliceArray(this._offsetToNode, offsetsArray, offset, 0);
11997
- // Refresh indexes and offsets for nodes inside this node list. We need to do this for all inserted nodes and all nodes after them.
11998
- for(let i = index; i < this._nodes.length; i++){
11999
- this._nodes[i]._index = i;
12000
- this._nodes[i]._startOffset = offset;
12001
- offset += this._nodes[i].offsetSize;
12002
- }
12003
- }
12004
- /**
12005
- * Removes one or more nodes starting at the given index.
12006
- *
12007
- * @internal
12008
- * @param indexStart Index of the first node to remove.
12009
- * @param howMany Number of nodes to remove.
12010
- * @returns Array containing removed nodes.
12011
- */ _removeNodes(indexStart, howMany = 1) {
12012
- if (howMany == 0) {
12013
- return [];
12014
- }
12015
- // Remove nodes from this nodelist.
12016
- let offset = this.indexToOffset(indexStart);
12017
- const nodes = this._nodes.splice(indexStart, howMany);
12018
- const lastNode = nodes[nodes.length - 1];
12019
- const removedOffsetSum = lastNode.startOffset + lastNode.offsetSize - offset;
12020
- this._offsetToNode.splice(offset, removedOffsetSum);
12021
- // Reset index and start offset properties for the removed nodes -- they do not have a parent anymore.
12022
- for (const node of nodes){
12023
- node._index = null;
12024
- node._startOffset = null;
12025
- }
12026
- for(let i = indexStart; i < this._nodes.length; i++){
12027
- this._nodes[i]._index = i;
12028
- this._nodes[i]._startOffset = offset;
12029
- offset += this._nodes[i].offsetSize;
12030
- }
12031
- return nodes;
12032
- }
12033
- /**
12034
- * Converts `NodeList` instance to an array containing nodes that were inserted in the node list. Nodes
12035
- * are also converted to their plain object representation.
12036
- *
12037
- * @returns `NodeList` instance converted to `Array`.
12038
- */ toJSON() {
12039
- return this._nodes.map((node)=>node.toJSON());
12040
- }
12041
- }
12042
- /**
12043
- * Creates an array of nodes in the format as in {@link module:engine/model/nodelist~NodeList#_offsetToNode}, i.e. one node will
12044
- * occupy multiple items if its offset size is greater than one.
12045
- */ function makeOffsetsArray(nodes) {
12046
- const offsets = [];
12047
- for (const node of nodes){
12048
- const start = offsets.length;
12049
- offsets.length += node.offsetSize;
12050
- offsets.fill(node, start);
12051
- }
12052
- return offsets;
12053
- }
12054
-
12055
- // @if CK_DEBUG_ENGINE // const { convertMapToStringifiedObject } = require( '../dev-utils/utils' );
12056
- /**
12057
- * Model text node. Type of {@link module:engine/model/node~Node node} that contains {@link module:engine/model/text~Text#data text data}.
12058
- *
12059
- * **Important:** see {@link module:engine/model/node~Node} to read about restrictions using `Text` and `Node` API.
12060
- *
12061
- * **Note:** keep in mind that `Text` instances might indirectly got removed from model tree when model is changed.
12062
- * This happens when {@link module:engine/model/writer~Writer model writer} is used to change model and the text node is merged with
12063
- * another text node. Then, both text nodes are removed and a new text node is inserted into the model. Because of
12064
- * this behavior, keeping references to `Text` is not recommended. Instead, consider creating
12065
- * {@link module:engine/model/liveposition~LivePosition live position} placed before the text node.
12066
- */ class Text extends Node$1 {
12067
- /**
12068
- * Text data contained in this text node.
12069
- *
12070
- * @internal
12071
- */ _data;
12072
- /**
12073
- * Creates a text node.
12074
- *
12075
- * **Note:** Constructor of this class shouldn't be used directly in the code.
12076
- * Use the {@link module:engine/model/writer~Writer#createText} method instead.
12077
- *
12078
- * @internal
12079
- * @param data Node's text.
12080
- * @param attrs Node's attributes. See {@link module:utils/tomap~toMap} for a list of accepted values.
12081
- */ constructor(data, attrs){
12082
- super(attrs);
12083
- this._data = data || '';
12084
- }
12085
- /**
12086
- * @inheritDoc
12087
- */ get offsetSize() {
12088
- return this.data.length;
12089
- }
12090
- /**
12091
- * Returns a text data contained in the node.
12092
- */ get data() {
12093
- return this._data;
12094
- }
12095
- /**
12096
- * Converts `Text` instance to plain object and returns it.
12097
- *
12098
- * @returns`Text` instance converted to plain object.
12099
- */ toJSON() {
12100
- const json = super.toJSON();
12101
- json.data = this.data;
12102
- return json;
12103
- }
12104
- /**
12105
- * Creates a copy of this text node and returns it. Created text node has same text data and attributes as original text node.
12106
- *
12107
- * @internal
12108
- * @returns `Text` instance created using given plain object.
12109
- */ _clone() {
12110
- return new Text(this.data, this.getAttributes());
12111
- }
12112
- /**
12113
- * Creates a `Text` instance from given plain object (i.e. parsed JSON string).
12114
- *
12115
- * @param json Plain object to be converted to `Text`.
12116
- * @returns `Text` instance created using given plain object.
12117
- */ static fromJSON(json) {
12118
- return new Text(json.data, json.attributes);
12119
- }
12120
- }
12121
- // The magic of type inference using `is` method is centralized in `TypeCheckable` class.
12122
- // Proper overload would interfere with that.
12123
- Text.prototype.is = function(type) {
12124
- return type === '$text' || type === 'model:$text' || // This are legacy values kept for backward compatibility.
12125
- type === 'text' || type === 'model:text' || // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
12126
- type === 'node' || type === 'model:node';
12127
- };
12128
-
12129
11557
  // @if CK_DEBUG_ENGINE // const { convertMapToStringifiedObject } = require( '../dev-utils/utils' );
12130
11558
  /**
12131
11559
  * `TextProxy` represents a part of {@link module:engine/model/text~Text text node}.
@@ -12299,271 +11727,6 @@ TextProxy.prototype.is = function(type) {
12299
11727
  type === 'textProxy' || type === 'model:textProxy';
12300
11728
  };
12301
11729
 
12302
- // @if CK_DEBUG_ENGINE // const { stringifyMap, convertMapToStringifiedObject, convertMapToTags } = require( '../dev-utils/utils' );
12303
- /**
12304
- * Model element. Type of {@link module:engine/model/node~Node node} that has a {@link module:engine/model/element~Element#name name} and
12305
- * {@link module:engine/model/element~Element#getChildren child nodes}.
12306
- *
12307
- * **Important**: see {@link module:engine/model/node~Node} to read about restrictions using `Element` and `Node` API.
12308
- */ class Element extends Node$1 {
12309
- /**
12310
- * Element name.
12311
- */ name;
12312
- /**
12313
- * List of children nodes.
12314
- */ _children = new NodeList();
12315
- /**
12316
- * Creates a model element.
12317
- *
12318
- * **Note:** Constructor of this class shouldn't be used directly in the code.
12319
- * Use the {@link module:engine/model/writer~Writer#createElement} method instead.
12320
- *
12321
- * @internal
12322
- * @param name Element's name.
12323
- * @param attrs Element's attributes. See {@link module:utils/tomap~toMap} for a list of accepted values.
12324
- * @param children One or more nodes to be inserted as children of created element.
12325
- */ constructor(name, attrs, children){
12326
- super(attrs);
12327
- this.name = name;
12328
- if (children) {
12329
- this._insertChild(0, children);
12330
- }
12331
- }
12332
- /**
12333
- * Number of this element's children.
12334
- */ get childCount() {
12335
- return this._children.length;
12336
- }
12337
- /**
12338
- * Sum of {@link module:engine/model/node~Node#offsetSize offset sizes} of all of this element's children.
12339
- */ get maxOffset() {
12340
- return this._children.maxOffset;
12341
- }
12342
- /**
12343
- * Is `true` if there are no nodes inside this element, `false` otherwise.
12344
- */ get isEmpty() {
12345
- return this.childCount === 0;
12346
- }
12347
- /**
12348
- * Gets the child at the given index. Returns `null` if incorrect index was passed.
12349
- *
12350
- * @param index Index in this element.
12351
- * @returns Child node.
12352
- */ getChild(index) {
12353
- return this._children.getNode(index);
12354
- }
12355
- /**
12356
- * Gets the child at the given offset. Returns `null` if incorrect index was passed.
12357
- *
12358
- * @param offset Offset in this element.
12359
- * @returns Child node.
12360
- */ getChildAtOffset(offset) {
12361
- return this._children.getNodeAtOffset(offset);
12362
- }
12363
- /**
12364
- * Returns an iterator that iterates over all of this element's children.
12365
- */ getChildren() {
12366
- return this._children[Symbol.iterator]();
12367
- }
12368
- /**
12369
- * Returns an index of the given child node. Returns `null` if given node is not a child of this element.
12370
- *
12371
- * @param node Child node to look for.
12372
- * @returns Child node's index in this element.
12373
- */ getChildIndex(node) {
12374
- return this._children.getNodeIndex(node);
12375
- }
12376
- /**
12377
- * Returns the starting offset of given child. Starting offset is equal to the sum of
12378
- * {@link module:engine/model/node~Node#offsetSize offset sizes} of all node's siblings that are before it. Returns `null` if
12379
- * given node is not a child of this element.
12380
- *
12381
- * @param node Child node to look for.
12382
- * @returns Child node's starting offset.
12383
- */ getChildStartOffset(node) {
12384
- return this._children.getNodeStartOffset(node);
12385
- }
12386
- /**
12387
- * Returns index of a node that occupies given offset. If given offset is too low, returns `0`. If given offset is
12388
- * too high, returns {@link module:engine/model/element~Element#getChildIndex index after last child}.
12389
- *
12390
- * ```ts
12391
- * const textNode = new Text( 'foo' );
12392
- * const pElement = new Element( 'p' );
12393
- * const divElement = new Element( [ textNode, pElement ] );
12394
- * divElement.offsetToIndex( -1 ); // Returns 0, because offset is too low.
12395
- * divElement.offsetToIndex( 0 ); // Returns 0, because offset 0 is taken by `textNode` which is at index 0.
12396
- * divElement.offsetToIndex( 1 ); // Returns 0, because `textNode` has `offsetSize` equal to 3, so it occupies offset 1 too.
12397
- * divElement.offsetToIndex( 2 ); // Returns 0.
12398
- * divElement.offsetToIndex( 3 ); // Returns 1.
12399
- * divElement.offsetToIndex( 4 ); // Returns 2. There are no nodes at offset 4, so last available index is returned.
12400
- * ```
12401
- */ offsetToIndex(offset) {
12402
- return this._children.offsetToIndex(offset);
12403
- }
12404
- /**
12405
- * Returns a descendant node by its path relative to this element.
12406
- *
12407
- * ```ts
12408
- * // <this>a<b>c</b></this>
12409
- * this.getNodeByPath( [ 0 ] ); // -> "a"
12410
- * this.getNodeByPath( [ 1 ] ); // -> <b>
12411
- * this.getNodeByPath( [ 1, 0 ] ); // -> "c"
12412
- * ```
12413
- *
12414
- * @param relativePath Path of the node to find, relative to this element.
12415
- */ getNodeByPath(relativePath) {
12416
- // eslint-disable-next-line @typescript-eslint/no-this-alias, consistent-this
12417
- let node = this;
12418
- for (const offset of relativePath){
12419
- node = node.getChildAtOffset(offset);
12420
- }
12421
- return node;
12422
- }
12423
- /**
12424
- * Returns the parent element of the given name. Returns null if the element is not inside the desired parent.
12425
- *
12426
- * @param parentName The name of the parent element to find.
12427
- * @param options Options object.
12428
- * @param options.includeSelf When set to `true` this node will be also included while searching.
12429
- */ findAncestor(parentName, options = {}) {
12430
- let parent = options.includeSelf ? this : this.parent;
12431
- while(parent){
12432
- if (parent.name === parentName) {
12433
- return parent;
12434
- }
12435
- parent = parent.parent;
12436
- }
12437
- return null;
12438
- }
12439
- /**
12440
- * Converts `Element` instance to plain object and returns it. Takes care of converting all of this element's children.
12441
- *
12442
- * @returns `Element` instance converted to plain object.
12443
- */ toJSON() {
12444
- const json = super.toJSON();
12445
- json.name = this.name;
12446
- if (this._children.length > 0) {
12447
- json.children = [];
12448
- for (const node of this._children){
12449
- json.children.push(node.toJSON());
12450
- }
12451
- }
12452
- return json;
12453
- }
12454
- /**
12455
- * Creates a copy of this element and returns it. Created element has the same name and attributes as the original element.
12456
- * If clone is deep, the original element's children are also cloned. If not, then empty element is returned.
12457
- *
12458
- * @internal
12459
- * @param deep If set to `true` clones element and all its children recursively. When set to `false`,
12460
- * element will be cloned without any child.
12461
- */ _clone(deep = false) {
12462
- const children = deep ? Array.from(this._children).map((node)=>node._clone(true)) : undefined;
12463
- return new Element(this.name, this.getAttributes(), children);
12464
- }
12465
- /**
12466
- * {@link module:engine/model/element~Element#_insertChild Inserts} one or more nodes at the end of this element.
12467
- *
12468
- * @see module:engine/model/writer~Writer#append
12469
- * @internal
12470
- * @param nodes Nodes to be inserted.
12471
- */ _appendChild(nodes) {
12472
- this._insertChild(this.childCount, nodes);
12473
- }
12474
- /**
12475
- * Inserts one or more nodes at the given index and sets {@link module:engine/model/node~Node#parent parent} of these nodes
12476
- * to this element.
12477
- *
12478
- * @see module:engine/model/writer~Writer#insert
12479
- * @internal
12480
- * @param index Index at which nodes should be inserted.
12481
- * @param items Items to be inserted.
12482
- */ _insertChild(index, items) {
12483
- const nodes = normalize$1(items);
12484
- for (const node of nodes){
12485
- // If node that is being added to this element is already inside another element, first remove it from the old parent.
12486
- if (node.parent !== null) {
12487
- node._remove();
12488
- }
12489
- node.parent = this;
12490
- }
12491
- this._children._insertNodes(index, nodes);
12492
- }
12493
- /**
12494
- * Removes one or more nodes starting at the given index and sets
12495
- * {@link module:engine/model/node~Node#parent parent} of these nodes to `null`.
12496
- *
12497
- * @see module:engine/model/writer~Writer#remove
12498
- * @internal
12499
- * @param index Index of the first node to remove.
12500
- * @param howMany Number of nodes to remove.
12501
- * @returns Array containing removed nodes.
12502
- */ _removeChildren(index, howMany = 1) {
12503
- const nodes = this._children._removeNodes(index, howMany);
12504
- for (const node of nodes){
12505
- node.parent = null;
12506
- }
12507
- return nodes;
12508
- }
12509
- /**
12510
- * Creates an `Element` instance from given plain object (i.e. parsed JSON string).
12511
- * Converts `Element` children to proper nodes.
12512
- *
12513
- * @param json Plain object to be converted to `Element`.
12514
- * @returns `Element` instance created using given plain object.
12515
- */ static fromJSON(json) {
12516
- let children;
12517
- if (json.children) {
12518
- children = [];
12519
- for (const child of json.children){
12520
- if (child.name) {
12521
- // If child has name property, it is an Element.
12522
- children.push(Element.fromJSON(child));
12523
- } else {
12524
- // Otherwise, it is a Text node.
12525
- children.push(Text.fromJSON(child));
12526
- }
12527
- }
12528
- }
12529
- return new Element(json.name, json.attributes, children);
12530
- }
12531
- }
12532
- // The magic of type inference using `is` method is centralized in `TypeCheckable` class.
12533
- // Proper overload would interfere with that.
12534
- Element.prototype.is = function(type, name) {
12535
- if (!name) {
12536
- return type === 'element' || type === 'model:element' || // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
12537
- type === 'node' || type === 'model:node';
12538
- }
12539
- return name === this.name && (type === 'element' || type === 'model:element');
12540
- };
12541
- /**
12542
- * Converts strings to Text and non-iterables to arrays.
12543
- */ function normalize$1(nodes) {
12544
- // Separate condition because string is iterable.
12545
- if (typeof nodes == 'string') {
12546
- return [
12547
- new Text(nodes)
12548
- ];
12549
- }
12550
- if (!isIterable(nodes)) {
12551
- nodes = [
12552
- nodes
12553
- ];
12554
- }
12555
- // Array.from to enable .map() on non-arrays.
12556
- return Array.from(nodes).map((node)=>{
12557
- if (typeof node == 'string') {
12558
- return new Text(node);
12559
- }
12560
- if (node instanceof TextProxy) {
12561
- return new Text(node.data, node.getAttributes());
12562
- }
12563
- return node;
12564
- });
12565
- }
12566
-
12567
11730
  /**
12568
11731
  * Position iterator class. It allows to iterate forward and backward over the document.
12569
11732
  */ class TreeWalker {
@@ -12718,7 +11881,7 @@ Element.prototype.is = function(type, name) {
12718
11881
  // Use a highly optimized version instead of checking the text node first and then getting the node after. See #6582.
12719
11882
  const textNodeAtPosition = getTextNodeAtPosition(position, parent);
12720
11883
  const node = textNodeAtPosition || getNodeAfterPosition(position, parent, textNodeAtPosition);
12721
- if (node instanceof Element) {
11884
+ if (node && node.is('model:element')) {
12722
11885
  if (!this.shallow) {
12723
11886
  // Manual operations on path internals for optimization purposes. Here and in the rest of the method.
12724
11887
  position.path.push(0);
@@ -12736,7 +11899,7 @@ Element.prototype.is = function(type, name) {
12736
11899
  this._position = position;
12737
11900
  return formatReturnValue('elementStart', node, previousPosition, position, 1);
12738
11901
  }
12739
- if (node instanceof Text) {
11902
+ if (node && node.is('model:$text')) {
12740
11903
  let charactersCount;
12741
11904
  if (this.singleCharacters) {
12742
11905
  charactersCount = 1;
@@ -12788,7 +11951,7 @@ Element.prototype.is = function(type, name) {
12788
11951
  const positionParent = position.parent;
12789
11952
  const textNodeAtPosition = getTextNodeAtPosition(position, positionParent);
12790
11953
  const node = textNodeAtPosition || getNodeBeforePosition(position, positionParent, textNodeAtPosition);
12791
- if (node instanceof Element) {
11954
+ if (node && node.is('model:element')) {
12792
11955
  position.offset--;
12793
11956
  if (this.shallow) {
12794
11957
  this._position = position;
@@ -12802,7 +11965,7 @@ Element.prototype.is = function(type, name) {
12802
11965
  }
12803
11966
  return formatReturnValue('elementEnd', node, previousPosition, position);
12804
11967
  }
12805
- if (node instanceof Text) {
11968
+ if (node && node.is('model:$text')) {
12806
11969
  let charactersCount;
12807
11970
  if (this.singleCharacters) {
12808
11971
  charactersCount = 1;
@@ -12920,7 +12083,7 @@ function formatReturnValue(type, item, previousPosition, nextPosition, length) {
12920
12083
  * @error model-position-root-invalid
12921
12084
  */ throw new CKEditorError('model-position-root-invalid', root);
12922
12085
  }
12923
- if (!(path instanceof Array) || path.length === 0) {
12086
+ if (!Array.isArray(path) || path.length === 0) {
12924
12087
  /**
12925
12088
  * Position path must be an array with at least one item.
12926
12089
  *
@@ -13560,7 +12723,7 @@ function formatReturnValue(type, item, previousPosition, nextPosition, length) {
13560
12723
  * @param offset Offset or one of the flags. Used only when the first parameter is a {@link module:engine/model/item~Item model item}.
13561
12724
  * @param stickiness Position stickiness. Used only when the first parameter is a {@link module:engine/model/item~Item model item}.
13562
12725
  */ static _createAt(itemOrPosition, offset, stickiness = 'toNone') {
13563
- if (itemOrPosition instanceof Position) {
12726
+ if (itemOrPosition.is('model:position')) {
13564
12727
  return new Position(itemOrPosition.root, itemOrPosition.path, itemOrPosition.stickiness);
13565
12728
  } else {
13566
12729
  const node = itemOrPosition;
@@ -15046,22 +14209,28 @@ Range.prototype.is = function(type) {
15046
14209
  * @param viewNode View node.
15047
14210
  * @returns Length of the node in the tree model.
15048
14211
  */ getModelLength(viewNode) {
15049
- if (this._viewToModelLengthCallbacks.get(viewNode.name)) {
15050
- const callback = this._viewToModelLengthCallbacks.get(viewNode.name);
15051
- return callback(viewNode);
15052
- } else if (this._viewToModelMapping.has(viewNode)) {
15053
- return 1;
15054
- } else if (viewNode.is('$text')) {
15055
- return viewNode.data.length;
15056
- } else if (viewNode.is('uiElement')) {
15057
- return 0;
15058
- } else {
15059
- let len = 0;
15060
- for (const child of viewNode.getChildren()){
15061
- len += this.getModelLength(child);
14212
+ const stack = [
14213
+ viewNode
14214
+ ];
14215
+ let len = 0;
14216
+ while(stack.length > 0){
14217
+ const node = stack.pop();
14218
+ const callback = node.name && this._viewToModelLengthCallbacks.size > 0 && this._viewToModelLengthCallbacks.get(node.name);
14219
+ if (callback) {
14220
+ len += callback(node);
14221
+ } else if (this._viewToModelMapping.has(node)) {
14222
+ len += 1;
14223
+ } else if (node.is('$text')) {
14224
+ len += node.data.length;
14225
+ } else if (node.is('uiElement')) {
14226
+ continue;
14227
+ } else {
14228
+ for (const child of node.getChildren()){
14229
+ stack.push(child);
14230
+ }
15062
14231
  }
15063
- return len;
15064
14232
  }
14233
+ return len;
15065
14234
  }
15066
14235
  /**
15067
14236
  * Finds the position in the view node (or in its children) with the expected model offset.
@@ -15133,9 +14302,9 @@ Range.prototype.is = function(type) {
15133
14302
  // If the position is just before a text node, put it at the beginning of that text node.
15134
14303
  const nodeBefore = viewPosition.nodeBefore;
15135
14304
  const nodeAfter = viewPosition.nodeAfter;
15136
- if (nodeBefore instanceof Text$1) {
14305
+ if (nodeBefore && nodeBefore.is('view:$text')) {
15137
14306
  return new Position$1(nodeBefore, nodeBefore.data.length);
15138
- } else if (nodeAfter instanceof Text$1) {
14307
+ } else if (nodeAfter && nodeAfter.is('view:$text')) {
15139
14308
  return new Position$1(nodeAfter, 0);
15140
14309
  }
15141
14310
  // Otherwise, just return the given position.
@@ -15714,10 +14883,10 @@ Range.prototype.is = function(type) {
15714
14883
  this._addConsumablesForInsert(conversionApi.consumable, range);
15715
14884
  }
15716
14885
  // Fire a separate insert event for each node and text fragment contained in the range.
15717
- for (const data of Array.from(range.getWalker({
14886
+ for (const data of range.getWalker({
15718
14887
  shallow: true
15719
- })).map(walkerValueToEventData)){
15720
- this._testAndFire('insert', data, conversionApi);
14888
+ })){
14889
+ this._testAndFire('insert', walkerValueToEventData(data), conversionApi);
15721
14890
  }
15722
14891
  }
15723
14892
  /**
@@ -16003,14 +15172,343 @@ function getEventName(type, data) {
16003
15172
  return `${type}:${name}`;
16004
15173
  }
16005
15174
  function walkerValueToEventData(value) {
16006
- const item = value.item;
16007
- const itemRange = Range._createFromPositionAndShift(value.previousPosition, value.length);
16008
15175
  return {
16009
- item,
16010
- range: itemRange
15176
+ item: value.item,
15177
+ range: Range._createFromPositionAndShift(value.previousPosition, value.length)
16011
15178
  };
16012
15179
  }
16013
15180
 
15181
+ /**
15182
+ * Model node. Most basic structure of model tree.
15183
+ *
15184
+ * This is an abstract class that is a base for other classes representing different nodes in model.
15185
+ *
15186
+ * **Note:** If a node is detached from the model tree, you can manipulate it using it's API.
15187
+ * However, it is **very important** that nodes already attached to model tree should be only changed through
15188
+ * {@link module:engine/model/writer~Writer Writer API}.
15189
+ *
15190
+ * Changes done by `Node` methods, like {@link module:engine/model/element~Element#_insertChild _insertChild} or
15191
+ * {@link module:engine/model/node~Node#_setAttribute _setAttribute}
15192
+ * do not generate {@link module:engine/model/operation/operation~Operation operations}
15193
+ * which are essential for correct editor work if you modify nodes in {@link module:engine/model/document~Document document} root.
15194
+ *
15195
+ * The flow of working on `Node` (and classes that inherits from it) is as such:
15196
+ * 1. You can create a `Node` instance, modify it using it's API.
15197
+ * 2. Add `Node` to the model using `Batch` API.
15198
+ * 3. Change `Node` that was already added to the model using `Batch` API.
15199
+ *
15200
+ * Similarly, you cannot use `Batch` API on a node that has not been added to the model tree, with the exception
15201
+ * of {@link module:engine/model/writer~Writer#insert inserting} that node to the model tree.
15202
+ *
15203
+ * Be aware that using {@link module:engine/model/writer~Writer#remove remove from Batch API} does not allow to use `Node` API because
15204
+ * the information about `Node` is still kept in model document.
15205
+ *
15206
+ * In case of {@link module:engine/model/element~Element element node}, adding and removing children also counts as changing a node and
15207
+ * follows same rules.
15208
+ */ let Node$1 = class Node extends TypeCheckable {
15209
+ /**
15210
+ * Parent of this node. It could be {@link module:engine/model/element~Element}
15211
+ * or {@link module:engine/model/documentfragment~DocumentFragment}.
15212
+ * Equals to `null` if the node has no parent.
15213
+ */ parent = null;
15214
+ /**
15215
+ * Attributes set on this node.
15216
+ */ _attrs;
15217
+ /**
15218
+ * Index of this node in its parent or `null` if the node has no parent.
15219
+ *
15220
+ * @internal
15221
+ */ _index = null;
15222
+ /**
15223
+ * Offset at which this node starts in its parent or `null` if the node has no parent.
15224
+ *
15225
+ * @internal
15226
+ */ _startOffset = null;
15227
+ /**
15228
+ * Creates a model node.
15229
+ *
15230
+ * This is an abstract class, so this constructor should not be used directly.
15231
+ *
15232
+ * @param attrs Node's attributes. See {@link module:utils/tomap~toMap} for a list of accepted values.
15233
+ */ constructor(attrs){
15234
+ super();
15235
+ this._attrs = toMap(attrs);
15236
+ }
15237
+ /**
15238
+ * {@link module:engine/model/document~Document Document} that owns this root element.
15239
+ */ get document() {
15240
+ return null;
15241
+ }
15242
+ /**
15243
+ * Index of this node in its parent or `null` if the node has no parent.
15244
+ */ get index() {
15245
+ return this._index;
15246
+ }
15247
+ /**
15248
+ * Offset at which this node starts in its parent. It is equal to the sum of {@link #offsetSize offsetSize}
15249
+ * of all its previous siblings. Equals to `null` if node has no parent.
15250
+ */ get startOffset() {
15251
+ return this._startOffset;
15252
+ }
15253
+ /**
15254
+ * Offset size of this node.
15255
+ *
15256
+ * Represents how much "offset space" is occupied by the node in its parent. It is important for
15257
+ * {@link module:engine/model/position~Position position}. When node has `offsetSize` greater than `1`, position can be placed between
15258
+ * that node start and end. `offsetSize` greater than `1` is for nodes that represents more than one entity, i.e.
15259
+ * a {@link module:engine/model/text~Text text node}.
15260
+ */ get offsetSize() {
15261
+ return 1;
15262
+ }
15263
+ /**
15264
+ * Offset at which this node ends in its parent. It is equal to the sum of this node's
15265
+ * {@link module:engine/model/node~Node#startOffset start offset} and {@link #offsetSize offset size}.
15266
+ * Equals to `null` if the node has no parent.
15267
+ */ get endOffset() {
15268
+ if (this.startOffset === null) {
15269
+ return null;
15270
+ }
15271
+ return this.startOffset + this.offsetSize;
15272
+ }
15273
+ /**
15274
+ * Node's next sibling or `null` if the node is a last child of it's parent or if the node has no parent.
15275
+ */ get nextSibling() {
15276
+ const index = this.index;
15277
+ return index !== null && this.parent.getChild(index + 1) || null;
15278
+ }
15279
+ /**
15280
+ * Node's previous sibling or `null` if the node is a first child of it's parent or if the node has no parent.
15281
+ */ get previousSibling() {
15282
+ const index = this.index;
15283
+ return index !== null && this.parent.getChild(index - 1) || null;
15284
+ }
15285
+ /**
15286
+ * The top-most ancestor of the node. If node has no parent it is the root itself. If the node is a part
15287
+ * of {@link module:engine/model/documentfragment~DocumentFragment}, it's `root` is equal to that `DocumentFragment`.
15288
+ */ get root() {
15289
+ // eslint-disable-next-line @typescript-eslint/no-this-alias, consistent-this
15290
+ let root = this;
15291
+ while(root.parent){
15292
+ root = root.parent;
15293
+ }
15294
+ return root;
15295
+ }
15296
+ /**
15297
+ * Returns `true` if the node is inside a document root that is attached to the document.
15298
+ */ isAttached() {
15299
+ // If the node has no parent it means that it is a root.
15300
+ // But this is not a `RootElement`, so it means that it is not attached.
15301
+ //
15302
+ // If this is not the root, check if this element's root is attached.
15303
+ return this.parent === null ? false : this.root.isAttached();
15304
+ }
15305
+ /**
15306
+ * Gets path to the node. The path is an array containing starting offsets of consecutive ancestors of this node,
15307
+ * beginning from {@link module:engine/model/node~Node#root root}, down to this node's starting offset. The path can be used to
15308
+ * create {@link module:engine/model/position~Position Position} instance.
15309
+ *
15310
+ * ```ts
15311
+ * const abc = new Text( 'abc' );
15312
+ * const foo = new Text( 'foo' );
15313
+ * const h1 = new Element( 'h1', null, new Text( 'header' ) );
15314
+ * const p = new Element( 'p', null, [ abc, foo ] );
15315
+ * const div = new Element( 'div', null, [ h1, p ] );
15316
+ * foo.getPath(); // Returns [ 1, 3 ]. `foo` is in `p` which is in `div`. `p` starts at offset 1, while `foo` at 3.
15317
+ * h1.getPath(); // Returns [ 0 ].
15318
+ * div.getPath(); // Returns [].
15319
+ * ```
15320
+ */ getPath() {
15321
+ const path = [];
15322
+ // eslint-disable-next-line @typescript-eslint/no-this-alias, consistent-this
15323
+ let node = this;
15324
+ while(node.parent){
15325
+ path.unshift(node.startOffset);
15326
+ node = node.parent;
15327
+ }
15328
+ return path;
15329
+ }
15330
+ /**
15331
+ * Returns ancestors array of this node.
15332
+ *
15333
+ * @param options Options object.
15334
+ * @param options.includeSelf When set to `true` this node will be also included in parent's array.
15335
+ * @param options.parentFirst When set to `true`, array will be sorted from node's parent to root element,
15336
+ * otherwise root element will be the first item in the array.
15337
+ * @returns Array with ancestors.
15338
+ */ getAncestors(options = {}) {
15339
+ const ancestors = [];
15340
+ let parent = options.includeSelf ? this : this.parent;
15341
+ while(parent){
15342
+ ancestors[options.parentFirst ? 'push' : 'unshift'](parent);
15343
+ parent = parent.parent;
15344
+ }
15345
+ return ancestors;
15346
+ }
15347
+ /**
15348
+ * Returns a {@link module:engine/model/element~Element} or {@link module:engine/model/documentfragment~DocumentFragment}
15349
+ * which is a common ancestor of both nodes.
15350
+ *
15351
+ * @param node The second node.
15352
+ * @param options Options object.
15353
+ * @param options.includeSelf When set to `true` both nodes will be considered "ancestors" too.
15354
+ * Which means that if e.g. node A is inside B, then their common ancestor will be B.
15355
+ */ getCommonAncestor(node, options = {}) {
15356
+ const ancestorsA = this.getAncestors(options);
15357
+ const ancestorsB = node.getAncestors(options);
15358
+ let i = 0;
15359
+ while(ancestorsA[i] == ancestorsB[i] && ancestorsA[i]){
15360
+ i++;
15361
+ }
15362
+ return i === 0 ? null : ancestorsA[i - 1];
15363
+ }
15364
+ /**
15365
+ * Returns whether this node is before given node. `false` is returned if nodes are in different trees (for example,
15366
+ * in different {@link module:engine/model/documentfragment~DocumentFragment}s).
15367
+ *
15368
+ * @param node Node to compare with.
15369
+ */ isBefore(node) {
15370
+ // Given node is not before this node if they are same.
15371
+ if (this == node) {
15372
+ return false;
15373
+ }
15374
+ // Return `false` if it is impossible to compare nodes.
15375
+ if (this.root !== node.root) {
15376
+ return false;
15377
+ }
15378
+ const thisPath = this.getPath();
15379
+ const nodePath = node.getPath();
15380
+ const result = compareArrays(thisPath, nodePath);
15381
+ switch(result){
15382
+ case 'prefix':
15383
+ return true;
15384
+ case 'extension':
15385
+ return false;
15386
+ default:
15387
+ return thisPath[result] < nodePath[result];
15388
+ }
15389
+ }
15390
+ /**
15391
+ * Returns whether this node is after given node. `false` is returned if nodes are in different trees (for example,
15392
+ * in different {@link module:engine/model/documentfragment~DocumentFragment}s).
15393
+ *
15394
+ * @param node Node to compare with.
15395
+ */ isAfter(node) {
15396
+ // Given node is not before this node if they are same.
15397
+ if (this == node) {
15398
+ return false;
15399
+ }
15400
+ // Return `false` if it is impossible to compare nodes.
15401
+ if (this.root !== node.root) {
15402
+ return false;
15403
+ }
15404
+ // In other cases, just check if the `node` is before, and return the opposite.
15405
+ return !this.isBefore(node);
15406
+ }
15407
+ /**
15408
+ * Checks if the node has an attribute with given key.
15409
+ *
15410
+ * @param key Key of attribute to check.
15411
+ * @returns `true` if attribute with given key is set on node, `false` otherwise.
15412
+ */ hasAttribute(key) {
15413
+ return this._attrs.has(key);
15414
+ }
15415
+ /**
15416
+ * Gets an attribute value for given key or `undefined` if that attribute is not set on node.
15417
+ *
15418
+ * @param key Key of attribute to look for.
15419
+ * @returns Attribute value or `undefined`.
15420
+ */ getAttribute(key) {
15421
+ return this._attrs.get(key);
15422
+ }
15423
+ /**
15424
+ * Returns iterator that iterates over this node's attributes.
15425
+ *
15426
+ * Attributes are returned as arrays containing two items. First one is attribute key and second is attribute value.
15427
+ * This format is accepted by native `Map` object and also can be passed in `Node` constructor.
15428
+ */ getAttributes() {
15429
+ return this._attrs.entries();
15430
+ }
15431
+ /**
15432
+ * Returns iterator that iterates over this node's attribute keys.
15433
+ */ getAttributeKeys() {
15434
+ return this._attrs.keys();
15435
+ }
15436
+ /**
15437
+ * Converts `Node` to plain object and returns it.
15438
+ *
15439
+ * @returns `Node` converted to plain object.
15440
+ */ toJSON() {
15441
+ const json = {};
15442
+ // Serializes attributes to the object.
15443
+ // attributes = { a: 'foo', b: 1, c: true }.
15444
+ if (this._attrs.size) {
15445
+ json.attributes = Array.from(this._attrs).reduce((result, attr)=>{
15446
+ result[attr[0]] = attr[1];
15447
+ return result;
15448
+ }, {});
15449
+ }
15450
+ return json;
15451
+ }
15452
+ /**
15453
+ * Creates a copy of this node, that is a node with exactly same attributes, and returns it.
15454
+ *
15455
+ * @internal
15456
+ * @returns Node with same attributes as this node.
15457
+ */ _clone(_deep) {
15458
+ return new this.constructor(this._attrs);
15459
+ }
15460
+ /**
15461
+ * Removes this node from its parent.
15462
+ *
15463
+ * @internal
15464
+ * @see module:engine/model/writer~Writer#remove
15465
+ */ _remove() {
15466
+ this.parent._removeChildren(this.index);
15467
+ }
15468
+ /**
15469
+ * Sets attribute on the node. If attribute with the same key already is set, it's value is overwritten.
15470
+ *
15471
+ * @see module:engine/model/writer~Writer#setAttribute
15472
+ * @internal
15473
+ * @param key Key of attribute to set.
15474
+ * @param value Attribute value.
15475
+ */ _setAttribute(key, value) {
15476
+ this._attrs.set(key, value);
15477
+ }
15478
+ /**
15479
+ * Removes all attributes from the node and sets given attributes.
15480
+ *
15481
+ * @see module:engine/model/writer~Writer#setAttributes
15482
+ * @internal
15483
+ * @param attrs Attributes to set. See {@link module:utils/tomap~toMap} for a list of accepted values.
15484
+ */ _setAttributesTo(attrs) {
15485
+ this._attrs = toMap(attrs);
15486
+ }
15487
+ /**
15488
+ * Removes an attribute with given key from the node.
15489
+ *
15490
+ * @see module:engine/model/writer~Writer#removeAttribute
15491
+ * @internal
15492
+ * @param key Key of attribute to remove.
15493
+ * @returns `true` if the attribute was set on the element, `false` otherwise.
15494
+ */ _removeAttribute(key) {
15495
+ return this._attrs.delete(key);
15496
+ }
15497
+ /**
15498
+ * Removes all attributes from the node.
15499
+ *
15500
+ * @see module:engine/model/writer~Writer#clearAttributes
15501
+ * @internal
15502
+ */ _clearAttributes() {
15503
+ this._attrs.clear();
15504
+ }
15505
+ };
15506
+ // The magic of type inference using `is` method is centralized in `TypeCheckable` class.
15507
+ // Proper overload would interfere with that.
15508
+ Node$1.prototype.is = function(type) {
15509
+ return type === 'node' || type === 'model:node';
15510
+ };
15511
+
16014
15512
  /**
16015
15513
  * Selection is a set of {@link module:engine/model/range~Range ranges}. It has a direction specified by its
16016
15514
  * {@link module:engine/model/selection~Selection#anchor anchor} and {@link module:engine/model/selection~Selection#focus focus}
@@ -16876,6 +16374,80 @@ LiveRange.prototype.is = function(type) {
16876
16374
  return false;
16877
16375
  }
16878
16376
 
16377
+ // @if CK_DEBUG_ENGINE // const { convertMapToStringifiedObject } = require( '../dev-utils/utils' );
16378
+ /**
16379
+ * Model text node. Type of {@link module:engine/model/node~Node node} that contains {@link module:engine/model/text~Text#data text data}.
16380
+ *
16381
+ * **Important:** see {@link module:engine/model/node~Node} to read about restrictions using `Text` and `Node` API.
16382
+ *
16383
+ * **Note:** keep in mind that `Text` instances might indirectly got removed from model tree when model is changed.
16384
+ * This happens when {@link module:engine/model/writer~Writer model writer} is used to change model and the text node is merged with
16385
+ * another text node. Then, both text nodes are removed and a new text node is inserted into the model. Because of
16386
+ * this behavior, keeping references to `Text` is not recommended. Instead, consider creating
16387
+ * {@link module:engine/model/liveposition~LivePosition live position} placed before the text node.
16388
+ */ class Text extends Node$1 {
16389
+ /**
16390
+ * Text data contained in this text node.
16391
+ *
16392
+ * @internal
16393
+ */ _data;
16394
+ /**
16395
+ * Creates a text node.
16396
+ *
16397
+ * **Note:** Constructor of this class shouldn't be used directly in the code.
16398
+ * Use the {@link module:engine/model/writer~Writer#createText} method instead.
16399
+ *
16400
+ * @internal
16401
+ * @param data Node's text.
16402
+ * @param attrs Node's attributes. See {@link module:utils/tomap~toMap} for a list of accepted values.
16403
+ */ constructor(data, attrs){
16404
+ super(attrs);
16405
+ this._data = data || '';
16406
+ }
16407
+ /**
16408
+ * @inheritDoc
16409
+ */ get offsetSize() {
16410
+ return this.data.length;
16411
+ }
16412
+ /**
16413
+ * Returns a text data contained in the node.
16414
+ */ get data() {
16415
+ return this._data;
16416
+ }
16417
+ /**
16418
+ * Converts `Text` instance to plain object and returns it.
16419
+ *
16420
+ * @returns`Text` instance converted to plain object.
16421
+ */ toJSON() {
16422
+ const json = super.toJSON();
16423
+ json.data = this.data;
16424
+ return json;
16425
+ }
16426
+ /**
16427
+ * Creates a copy of this text node and returns it. Created text node has same text data and attributes as original text node.
16428
+ *
16429
+ * @internal
16430
+ * @returns `Text` instance created using given plain object.
16431
+ */ _clone() {
16432
+ return new Text(this.data, this.getAttributes());
16433
+ }
16434
+ /**
16435
+ * Creates a `Text` instance from given plain object (i.e. parsed JSON string).
16436
+ *
16437
+ * @param json Plain object to be converted to `Text`.
16438
+ * @returns `Text` instance created using given plain object.
16439
+ */ static fromJSON(json) {
16440
+ return new Text(json.data, json.attributes);
16441
+ }
16442
+ }
16443
+ // The magic of type inference using `is` method is centralized in `TypeCheckable` class.
16444
+ // Proper overload would interfere with that.
16445
+ Text.prototype.is = function(type) {
16446
+ return type === '$text' || type === 'model:$text' || // This are legacy values kept for backward compatibility.
16447
+ type === 'text' || type === 'model:text' || // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
16448
+ type === 'node' || type === 'model:node';
16449
+ };
16450
+
16879
16451
  const storePrefix = 'selection:';
16880
16452
  /**
16881
16453
  * `DocumentSelection` is a special selection which is used as the
@@ -17833,9 +17405,513 @@ DocumentSelection.prototype.is = function(type) {
17833
17405
  }
17834
17406
  }
17835
17407
 
17408
+ /**
17409
+ * Provides an interface to operate on a list of {@link module:engine/model/node~Node nodes}. `NodeList` is used internally
17410
+ * in classes like {@link module:engine/model/element~Element Element}
17411
+ * or {@link module:engine/model/documentfragment~DocumentFragment DocumentFragment}.
17412
+ */ class NodeList {
17413
+ /**
17414
+ * Nodes contained in this node list.
17415
+ */ _nodes = [];
17416
+ /**
17417
+ * This array maps numbers (offsets) to node that is placed at that offset.
17418
+ *
17419
+ * This array is similar to `_nodes` with the difference that one node may occupy multiple consecutive items in the array.
17420
+ *
17421
+ * This array is needed to quickly retrieve a node that is placed at given offset.
17422
+ */ _offsetToNode = [];
17423
+ /**
17424
+ * Creates a node list.
17425
+ *
17426
+ * @internal
17427
+ * @param nodes Nodes contained in this node list.
17428
+ */ constructor(nodes){
17429
+ if (nodes) {
17430
+ this._insertNodes(0, nodes);
17431
+ }
17432
+ }
17433
+ /**
17434
+ * Iterable interface.
17435
+ *
17436
+ * Iterates over all nodes contained inside this node list.
17437
+ */ [Symbol.iterator]() {
17438
+ return this._nodes[Symbol.iterator]();
17439
+ }
17440
+ /**
17441
+ * Number of nodes contained inside this node list.
17442
+ */ get length() {
17443
+ return this._nodes.length;
17444
+ }
17445
+ /**
17446
+ * Sum of {@link module:engine/model/node~Node#offsetSize offset sizes} of all nodes contained inside this node list.
17447
+ */ get maxOffset() {
17448
+ return this._offsetToNode.length;
17449
+ }
17450
+ /**
17451
+ * Gets the node at the given index. Returns `null` if incorrect index was passed.
17452
+ */ getNode(index) {
17453
+ return this._nodes[index] || null;
17454
+ }
17455
+ /**
17456
+ * Gets the node at the given offset. Returns `null` if incorrect offset was passed.
17457
+ */ getNodeAtOffset(offset) {
17458
+ return this._offsetToNode[offset] || null;
17459
+ }
17460
+ /**
17461
+ * Returns an index of the given node or `null` if given node does not have a parent.
17462
+ *
17463
+ * This is an alias to {@link module:engine/model/node~Node#index}.
17464
+ */ getNodeIndex(node) {
17465
+ return node.index;
17466
+ }
17467
+ /**
17468
+ * Returns the offset at which given node is placed in its parent or `null` if given node does not have a parent.
17469
+ *
17470
+ * This is an alias to {@link module:engine/model/node~Node#startOffset}.
17471
+ */ getNodeStartOffset(node) {
17472
+ return node.startOffset;
17473
+ }
17474
+ /**
17475
+ * Converts index to offset in node list.
17476
+ *
17477
+ * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `model-nodelist-index-out-of-bounds` if given index is less
17478
+ * than `0` or more than {@link #length}.
17479
+ */ indexToOffset(index) {
17480
+ if (index == this._nodes.length) {
17481
+ return this.maxOffset;
17482
+ }
17483
+ const node = this._nodes[index];
17484
+ if (!node) {
17485
+ /**
17486
+ * Given index cannot be found in the node list.
17487
+ *
17488
+ * @error model-nodelist-index-out-of-bounds
17489
+ */ throw new CKEditorError('model-nodelist-index-out-of-bounds', this);
17490
+ }
17491
+ return this.getNodeStartOffset(node);
17492
+ }
17493
+ /**
17494
+ * Converts offset in node list to index.
17495
+ *
17496
+ * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `model-nodelist-offset-out-of-bounds` if given offset is less
17497
+ * than `0` or more than {@link #maxOffset}.
17498
+ */ offsetToIndex(offset) {
17499
+ if (offset == this._offsetToNode.length) {
17500
+ return this._nodes.length;
17501
+ }
17502
+ const node = this._offsetToNode[offset];
17503
+ if (!node) {
17504
+ /**
17505
+ * Given offset cannot be found in the node list.
17506
+ *
17507
+ * @error model-nodelist-offset-out-of-bounds
17508
+ * @param offset
17509
+ * @param nodeList Stringified node list.
17510
+ */ throw new CKEditorError('model-nodelist-offset-out-of-bounds', this, {
17511
+ offset,
17512
+ nodeList: this
17513
+ });
17514
+ }
17515
+ return this.getNodeIndex(node);
17516
+ }
17517
+ /**
17518
+ * Inserts given nodes at given index.
17519
+ *
17520
+ * @internal
17521
+ * @param index Index at which nodes should be inserted.
17522
+ * @param nodes Nodes to be inserted.
17523
+ */ _insertNodes(index, nodes) {
17524
+ const nodesArray = [];
17525
+ // Validation.
17526
+ for (const node of nodes){
17527
+ if (!(node instanceof Node$1)) {
17528
+ /**
17529
+ * Trying to insert an object which is not a Node instance.
17530
+ *
17531
+ * @error model-nodelist-insertnodes-not-node
17532
+ */ throw new CKEditorError('model-nodelist-insertnodes-not-node', this);
17533
+ }
17534
+ nodesArray.push(node);
17535
+ }
17536
+ let offset = this.indexToOffset(index);
17537
+ // Splice nodes array and offsets array into the nodelist.
17538
+ spliceArray(this._nodes, nodesArray, index);
17539
+ spliceArray(this._offsetToNode, makeOffsetsArray(nodesArray), offset);
17540
+ // Refresh indexes and offsets for nodes inside this node list. We need to do this for all inserted nodes and all nodes after them.
17541
+ for(let i = index; i < this._nodes.length; i++){
17542
+ this._nodes[i]._index = i;
17543
+ this._nodes[i]._startOffset = offset;
17544
+ offset += this._nodes[i].offsetSize;
17545
+ }
17546
+ }
17547
+ /**
17548
+ * Removes one or more nodes starting at the given index.
17549
+ *
17550
+ * @internal
17551
+ * @param indexStart Index of the first node to remove.
17552
+ * @param howMany Number of nodes to remove.
17553
+ * @returns Array containing removed nodes.
17554
+ */ _removeNodes(indexStart, howMany = 1) {
17555
+ if (howMany == 0) {
17556
+ return [];
17557
+ }
17558
+ // Remove nodes from this nodelist.
17559
+ let offset = this.indexToOffset(indexStart);
17560
+ const nodes = this._nodes.splice(indexStart, howMany);
17561
+ const lastNode = nodes[nodes.length - 1];
17562
+ const removedOffsetSum = lastNode.startOffset + lastNode.offsetSize - offset;
17563
+ this._offsetToNode.splice(offset, removedOffsetSum);
17564
+ // Reset index and start offset properties for the removed nodes -- they do not have a parent anymore.
17565
+ for (const node of nodes){
17566
+ node._index = null;
17567
+ node._startOffset = null;
17568
+ }
17569
+ for(let i = indexStart; i < this._nodes.length; i++){
17570
+ this._nodes[i]._index = i;
17571
+ this._nodes[i]._startOffset = offset;
17572
+ offset += this._nodes[i].offsetSize;
17573
+ }
17574
+ return nodes;
17575
+ }
17576
+ /**
17577
+ * Removes children nodes provided as an array. These nodes do not need to be direct siblings.
17578
+ *
17579
+ * This method is faster than removing nodes one by one, as it recalculates offsets only once.
17580
+ *
17581
+ * @internal
17582
+ * @param nodes Array of nodes.
17583
+ */ _removeNodesArray(nodes) {
17584
+ if (nodes.length == 0) {
17585
+ return;
17586
+ }
17587
+ for (const node of nodes){
17588
+ node._index = null;
17589
+ node._startOffset = null;
17590
+ }
17591
+ this._nodes = this._nodes.filter((node)=>node.index !== null);
17592
+ this._offsetToNode = this._offsetToNode.filter((node)=>node.index !== null);
17593
+ let offset = 0;
17594
+ for(let i = 0; i < this._nodes.length; i++){
17595
+ this._nodes[i]._index = i;
17596
+ this._nodes[i]._startOffset = offset;
17597
+ offset += this._nodes[i].offsetSize;
17598
+ }
17599
+ }
17600
+ /**
17601
+ * Converts `NodeList` instance to an array containing nodes that were inserted in the node list. Nodes
17602
+ * are also converted to their plain object representation.
17603
+ *
17604
+ * @returns `NodeList` instance converted to `Array`.
17605
+ */ toJSON() {
17606
+ return this._nodes.map((node)=>node.toJSON());
17607
+ }
17608
+ }
17609
+ /**
17610
+ * Creates an array of nodes in the format as in {@link module:engine/model/nodelist~NodeList#_offsetToNode}, i.e. one node will
17611
+ * occupy multiple items if its offset size is greater than one.
17612
+ */ function makeOffsetsArray(nodes) {
17613
+ const offsets = [];
17614
+ let index = 0;
17615
+ for (const node of nodes){
17616
+ for(let i = 0; i < node.offsetSize; i++){
17617
+ offsets[index++] = node;
17618
+ }
17619
+ }
17620
+ return offsets;
17621
+ }
17622
+
17623
+ // @if CK_DEBUG_ENGINE // const { stringifyMap, convertMapToStringifiedObject, convertMapToTags } = require( '../dev-utils/utils' );
17624
+ /**
17625
+ * Model element. Type of {@link module:engine/model/node~Node node} that has a {@link module:engine/model/element~Element#name name} and
17626
+ * {@link module:engine/model/element~Element#getChildren child nodes}.
17627
+ *
17628
+ * **Important**: see {@link module:engine/model/node~Node} to read about restrictions using `Element` and `Node` API.
17629
+ */ class Element extends Node$1 {
17630
+ /**
17631
+ * Element name.
17632
+ */ name;
17633
+ /**
17634
+ * List of children nodes.
17635
+ */ _children = new NodeList();
17636
+ /**
17637
+ * Creates a model element.
17638
+ *
17639
+ * **Note:** Constructor of this class shouldn't be used directly in the code.
17640
+ * Use the {@link module:engine/model/writer~Writer#createElement} method instead.
17641
+ *
17642
+ * @internal
17643
+ * @param name Element's name.
17644
+ * @param attrs Element's attributes. See {@link module:utils/tomap~toMap} for a list of accepted values.
17645
+ * @param children One or more nodes to be inserted as children of created element.
17646
+ */ constructor(name, attrs, children){
17647
+ super(attrs);
17648
+ this.name = name;
17649
+ if (children) {
17650
+ this._insertChild(0, children);
17651
+ }
17652
+ }
17653
+ /**
17654
+ * Number of this element's children.
17655
+ */ get childCount() {
17656
+ return this._children.length;
17657
+ }
17658
+ /**
17659
+ * Sum of {@link module:engine/model/node~Node#offsetSize offset sizes} of all of this element's children.
17660
+ */ get maxOffset() {
17661
+ return this._children.maxOffset;
17662
+ }
17663
+ /**
17664
+ * Is `true` if there are no nodes inside this element, `false` otherwise.
17665
+ */ get isEmpty() {
17666
+ return this.childCount === 0;
17667
+ }
17668
+ /**
17669
+ * Gets the child at the given index. Returns `null` if incorrect index was passed.
17670
+ *
17671
+ * @param index Index in this element.
17672
+ * @returns Child node.
17673
+ */ getChild(index) {
17674
+ return this._children.getNode(index);
17675
+ }
17676
+ /**
17677
+ * Gets the child at the given offset. Returns `null` if incorrect index was passed.
17678
+ *
17679
+ * @param offset Offset in this element.
17680
+ * @returns Child node.
17681
+ */ getChildAtOffset(offset) {
17682
+ return this._children.getNodeAtOffset(offset);
17683
+ }
17684
+ /**
17685
+ * Returns an iterator that iterates over all of this element's children.
17686
+ */ getChildren() {
17687
+ return this._children[Symbol.iterator]();
17688
+ }
17689
+ /**
17690
+ * Returns an index of the given child node. Returns `null` if given node is not a child of this element.
17691
+ *
17692
+ * @param node Child node to look for.
17693
+ * @returns Child node's index in this element.
17694
+ */ getChildIndex(node) {
17695
+ return this._children.getNodeIndex(node);
17696
+ }
17697
+ /**
17698
+ * Returns the starting offset of given child. Starting offset is equal to the sum of
17699
+ * {@link module:engine/model/node~Node#offsetSize offset sizes} of all node's siblings that are before it. Returns `null` if
17700
+ * given node is not a child of this element.
17701
+ *
17702
+ * @param node Child node to look for.
17703
+ * @returns Child node's starting offset.
17704
+ */ getChildStartOffset(node) {
17705
+ return this._children.getNodeStartOffset(node);
17706
+ }
17707
+ /**
17708
+ * Returns index of a node that occupies given offset. If given offset is too low, returns `0`. If given offset is
17709
+ * too high, returns {@link module:engine/model/element~Element#getChildIndex index after last child}.
17710
+ *
17711
+ * ```ts
17712
+ * const textNode = new Text( 'foo' );
17713
+ * const pElement = new Element( 'p' );
17714
+ * const divElement = new Element( [ textNode, pElement ] );
17715
+ * divElement.offsetToIndex( -1 ); // Returns 0, because offset is too low.
17716
+ * divElement.offsetToIndex( 0 ); // Returns 0, because offset 0 is taken by `textNode` which is at index 0.
17717
+ * divElement.offsetToIndex( 1 ); // Returns 0, because `textNode` has `offsetSize` equal to 3, so it occupies offset 1 too.
17718
+ * divElement.offsetToIndex( 2 ); // Returns 0.
17719
+ * divElement.offsetToIndex( 3 ); // Returns 1.
17720
+ * divElement.offsetToIndex( 4 ); // Returns 2. There are no nodes at offset 4, so last available index is returned.
17721
+ * ```
17722
+ */ offsetToIndex(offset) {
17723
+ return this._children.offsetToIndex(offset);
17724
+ }
17725
+ /**
17726
+ * Returns a descendant node by its path relative to this element.
17727
+ *
17728
+ * ```ts
17729
+ * // <this>a<b>c</b></this>
17730
+ * this.getNodeByPath( [ 0 ] ); // -> "a"
17731
+ * this.getNodeByPath( [ 1 ] ); // -> <b>
17732
+ * this.getNodeByPath( [ 1, 0 ] ); // -> "c"
17733
+ * ```
17734
+ *
17735
+ * @param relativePath Path of the node to find, relative to this element.
17736
+ */ getNodeByPath(relativePath) {
17737
+ // eslint-disable-next-line @typescript-eslint/no-this-alias, consistent-this
17738
+ let node = this;
17739
+ for (const offset of relativePath){
17740
+ node = node.getChildAtOffset(offset);
17741
+ }
17742
+ return node;
17743
+ }
17744
+ /**
17745
+ * Returns the parent element of the given name. Returns null if the element is not inside the desired parent.
17746
+ *
17747
+ * @param parentName The name of the parent element to find.
17748
+ * @param options Options object.
17749
+ * @param options.includeSelf When set to `true` this node will be also included while searching.
17750
+ */ findAncestor(parentName, options = {}) {
17751
+ let parent = options.includeSelf ? this : this.parent;
17752
+ while(parent){
17753
+ if (parent.name === parentName) {
17754
+ return parent;
17755
+ }
17756
+ parent = parent.parent;
17757
+ }
17758
+ return null;
17759
+ }
17760
+ /**
17761
+ * Converts `Element` instance to plain object and returns it. Takes care of converting all of this element's children.
17762
+ *
17763
+ * @returns `Element` instance converted to plain object.
17764
+ */ toJSON() {
17765
+ const json = super.toJSON();
17766
+ json.name = this.name;
17767
+ if (this._children.length > 0) {
17768
+ json.children = [];
17769
+ for (const node of this._children){
17770
+ json.children.push(node.toJSON());
17771
+ }
17772
+ }
17773
+ return json;
17774
+ }
17775
+ /**
17776
+ * Creates a copy of this element and returns it. Created element has the same name and attributes as the original element.
17777
+ * If clone is deep, the original element's children are also cloned. If not, then empty element is returned.
17778
+ *
17779
+ * @internal
17780
+ * @param deep If set to `true` clones element and all its children recursively. When set to `false`,
17781
+ * element will be cloned without any child.
17782
+ */ _clone(deep = false) {
17783
+ const children = deep ? cloneNodes(this._children) : undefined;
17784
+ return new Element(this.name, this.getAttributes(), children);
17785
+ }
17786
+ /**
17787
+ * {@link module:engine/model/element~Element#_insertChild Inserts} one or more nodes at the end of this element.
17788
+ *
17789
+ * @see module:engine/model/writer~Writer#append
17790
+ * @internal
17791
+ * @param nodes Nodes to be inserted.
17792
+ */ _appendChild(nodes) {
17793
+ this._insertChild(this.childCount, nodes);
17794
+ }
17795
+ /**
17796
+ * Inserts one or more nodes at the given index and sets {@link module:engine/model/node~Node#parent parent} of these nodes
17797
+ * to this element.
17798
+ *
17799
+ * @see module:engine/model/writer~Writer#insert
17800
+ * @internal
17801
+ * @param index Index at which nodes should be inserted.
17802
+ * @param items Items to be inserted.
17803
+ */ _insertChild(index, items) {
17804
+ const nodes = normalize$1(items);
17805
+ for (const node of nodes){
17806
+ // If node that is being added to this element is already inside another element, first remove it from the old parent.
17807
+ if (node.parent !== null) {
17808
+ node._remove();
17809
+ }
17810
+ node.parent = this;
17811
+ }
17812
+ this._children._insertNodes(index, nodes);
17813
+ }
17814
+ /**
17815
+ * Removes one or more nodes starting at the given index and sets
17816
+ * {@link module:engine/model/node~Node#parent parent} of these nodes to `null`.
17817
+ *
17818
+ * @see module:engine/model/writer~Writer#remove
17819
+ * @internal
17820
+ * @param index Index of the first node to remove.
17821
+ * @param howMany Number of nodes to remove.
17822
+ * @returns Array containing removed nodes.
17823
+ */ _removeChildren(index, howMany = 1) {
17824
+ const nodes = this._children._removeNodes(index, howMany);
17825
+ for (const node of nodes){
17826
+ node.parent = null;
17827
+ }
17828
+ return nodes;
17829
+ }
17830
+ /**
17831
+ * Removes children nodes provided as an array and sets
17832
+ * the {@link module:engine/model/node~Node#parent parent} of these nodes to `null`.
17833
+ *
17834
+ * These nodes do not need to be direct siblings.
17835
+ *
17836
+ * This method is faster than removing nodes one by one, as it recalculates offsets only once.
17837
+ *
17838
+ * @internal
17839
+ * @param nodes Array of nodes.
17840
+ */ _removeChildrenArray(nodes) {
17841
+ this._children._removeNodesArray(nodes);
17842
+ for (const node of nodes){
17843
+ node.parent = null;
17844
+ }
17845
+ }
17846
+ /**
17847
+ * Creates an `Element` instance from given plain object (i.e. parsed JSON string).
17848
+ * Converts `Element` children to proper nodes.
17849
+ *
17850
+ * @param json Plain object to be converted to `Element`.
17851
+ * @returns `Element` instance created using given plain object.
17852
+ */ static fromJSON(json) {
17853
+ let children;
17854
+ if (json.children) {
17855
+ children = [];
17856
+ for (const child of json.children){
17857
+ if (child.name) {
17858
+ // If child has name property, it is an Element.
17859
+ children.push(Element.fromJSON(child));
17860
+ } else {
17861
+ // Otherwise, it is a Text node.
17862
+ children.push(Text.fromJSON(child));
17863
+ }
17864
+ }
17865
+ }
17866
+ return new Element(json.name, json.attributes, children);
17867
+ }
17868
+ }
17869
+ // The magic of type inference using `is` method is centralized in `TypeCheckable` class.
17870
+ // Proper overload would interfere with that.
17871
+ Element.prototype.is = function(type, name) {
17872
+ if (!name) {
17873
+ return type === 'element' || type === 'model:element' || // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
17874
+ type === 'node' || type === 'model:node';
17875
+ }
17876
+ return name === this.name && (type === 'element' || type === 'model:element');
17877
+ };
17878
+ /**
17879
+ * Converts strings to Text and non-iterables to arrays.
17880
+ */ function normalize$1(nodes) {
17881
+ // Separate condition because string is iterable.
17882
+ if (typeof nodes == 'string') {
17883
+ return [
17884
+ new Text(nodes)
17885
+ ];
17886
+ }
17887
+ if (!isIterable(nodes)) {
17888
+ nodes = [
17889
+ nodes
17890
+ ];
17891
+ }
17892
+ const normalizedNodes = [];
17893
+ for (const node of nodes){
17894
+ if (typeof node == 'string') {
17895
+ normalizedNodes.push(new Text(node));
17896
+ } else if (node instanceof TextProxy) {
17897
+ normalizedNodes.push(new Text(node.data, node.getAttributes()));
17898
+ } else {
17899
+ normalizedNodes.push(node);
17900
+ }
17901
+ }
17902
+ return normalizedNodes;
17903
+ }
17904
+ function cloneNodes(nodes) {
17905
+ const clonedNodes = [];
17906
+ for (const node of nodes){
17907
+ clonedNodes.push(node._clone(true));
17908
+ }
17909
+ return clonedNodes;
17910
+ }
17911
+
17836
17912
  /**
17837
17913
  * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
17838
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
17914
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
17839
17915
  */ /**
17840
17916
  * @module engine/conversion/conversionhelpers
17841
17917
  */ /**
@@ -19989,7 +20065,7 @@ function getFromAttributeCreator(config) {
19989
20065
 
19990
20066
  /**
19991
20067
  * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
19992
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
20068
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
19993
20069
  */ /**
19994
20070
  * @module engine/model/utils/autoparagraphing
19995
20071
  */ /**
@@ -23608,9 +23684,9 @@ function removeDisallowedAttributeFromNode(schema, node, writer) {
23608
23684
  // Remove all empty elements that were created while splitting.
23609
23685
  this._removeEmptyElements();
23610
23686
  // Move all items that were converted in context tree to the document fragment.
23611
- for (const item of Array.from(this._modelCursor.parent.getChildren())){
23612
- writer.append(item, documentFragment);
23613
- }
23687
+ const parent = this._modelCursor.parent;
23688
+ const children = parent._removeChildren(0, parent.childCount);
23689
+ documentFragment._insertChild(0, children);
23614
23690
  // Extract temporary markers elements from model and set as static markers collection.
23615
23691
  documentFragment.markers = extractMarkersFromModelFragment(documentFragment, writer);
23616
23692
  }
@@ -23809,15 +23885,21 @@ function removeDisallowedAttributeFromNode(schema, node, writer) {
23809
23885
  * This method works recursively to re-check empty elements again after at least one element was removed in the initial call,
23810
23886
  * as some elements might have become empty after other empty elements were removed from them.
23811
23887
  */ _removeEmptyElements() {
23812
- let anyRemoved = false;
23888
+ // For every parent, prepare an array of children (empty elements) to remove from it.
23889
+ // Then, in next step, we will remove all children together, which is faster than removing them one by one.
23890
+ const toRemove = new Map();
23813
23891
  for (const element of this._splitParts.keys()){
23814
23892
  if (element.isEmpty && !this._emptyElementsToKeep.has(element)) {
23815
- this.conversionApi.writer.remove(element);
23893
+ const children = toRemove.get(element.parent) || [];
23894
+ children.push(element);
23816
23895
  this._splitParts.delete(element);
23817
- anyRemoved = true;
23896
+ toRemove.set(element.parent, children);
23818
23897
  }
23819
23898
  }
23820
- if (anyRemoved) {
23899
+ for (const [parent, children] of toRemove){
23900
+ parent._removeChildrenArray(children);
23901
+ }
23902
+ if (toRemove.size) {
23821
23903
  this._removeEmptyElements();
23822
23904
  }
23823
23905
  }
@@ -25187,7 +25269,7 @@ function* _getUpcastDefinition(model, view, upcastAlso) {
25187
25269
 
25188
25270
  /**
25189
25271
  * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
25190
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
25272
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
25191
25273
  */ /* eslint-disable @typescript-eslint/no-unused-vars */ /**
25192
25274
  * @module engine/model/operation/operation
25193
25275
  */ /**
@@ -31625,6 +31707,22 @@ Marker.prototype.is = function(type) {
31625
31707
  }
31626
31708
  return nodes;
31627
31709
  }
31710
+ /**
31711
+ * Removes children nodes provided as an array and sets
31712
+ * the {@link module:engine/model/node~Node#parent parent} of these nodes to `null`.
31713
+ *
31714
+ * These nodes do not need to be direct siblings.
31715
+ *
31716
+ * This method is faster than removing nodes one by one, as it recalculates offsets only once.
31717
+ *
31718
+ * @internal
31719
+ * @param nodes Array of nodes.
31720
+ */ _removeChildrenArray(nodes) {
31721
+ this._children._removeNodesArray(nodes);
31722
+ for (const node of nodes){
31723
+ node.parent = null;
31724
+ }
31725
+ }
31628
31726
  }
31629
31727
  // The magic of type inference using `is` method is centralized in `TypeCheckable` class.
31630
31728
  // Proper overload would interfere with that.
@@ -31815,7 +31913,8 @@ DocumentFragment.prototype.is = function(type) {
31815
31913
  }
31816
31914
  }
31817
31915
  const version = position.root.document ? position.root.document.version : null;
31818
- const insert = new InsertOperation(position, item, version);
31916
+ const children = item instanceof DocumentFragment ? item._removeChildren(0, item.childCount) : item;
31917
+ const insert = new InsertOperation(position, children, version);
31819
31918
  if (item instanceof Text) {
31820
31919
  insert.shouldReceiveAttributes = true;
31821
31920
  }
@@ -33348,7 +33447,7 @@ function replaceEntireContentWithParagraph(writer, selection) {
33348
33447
 
33349
33448
  /**
33350
33449
  * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
33351
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
33450
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
33352
33451
  */ /**
33353
33452
  * @module engine/model/utils/getselectedcontent
33354
33453
  */ /**
@@ -35592,7 +35691,7 @@ function getSearchRange(start, isForward) {
35592
35691
 
35593
35692
  /**
35594
35693
  * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
35595
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
35694
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
35596
35695
  */ /**
35597
35696
  * @module engine/view/styles/utils
35598
35697
  */ const HEX_COLOR_REGEXP = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;