@ckeditor/ckeditor5-code-block 0.0.0-internal-20241017.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 (326) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/LICENSE.md +21 -0
  3. package/README.md +26 -0
  4. package/build/code-block.js +5 -0
  5. package/build/translations/af.js +1 -0
  6. package/build/translations/ar.js +1 -0
  7. package/build/translations/az.js +1 -0
  8. package/build/translations/bg.js +1 -0
  9. package/build/translations/bn.js +1 -0
  10. package/build/translations/bs.js +1 -0
  11. package/build/translations/ca.js +1 -0
  12. package/build/translations/cs.js +1 -0
  13. package/build/translations/da.js +1 -0
  14. package/build/translations/de-ch.js +1 -0
  15. package/build/translations/de.js +1 -0
  16. package/build/translations/el.js +1 -0
  17. package/build/translations/en-au.js +1 -0
  18. package/build/translations/es-co.js +1 -0
  19. package/build/translations/es.js +1 -0
  20. package/build/translations/et.js +1 -0
  21. package/build/translations/fa.js +1 -0
  22. package/build/translations/fi.js +1 -0
  23. package/build/translations/fr.js +1 -0
  24. package/build/translations/gl.js +1 -0
  25. package/build/translations/he.js +1 -0
  26. package/build/translations/hi.js +1 -0
  27. package/build/translations/hr.js +1 -0
  28. package/build/translations/hu.js +1 -0
  29. package/build/translations/id.js +1 -0
  30. package/build/translations/it.js +1 -0
  31. package/build/translations/ja.js +1 -0
  32. package/build/translations/jv.js +1 -0
  33. package/build/translations/ko.js +1 -0
  34. package/build/translations/ku.js +1 -0
  35. package/build/translations/lt.js +1 -0
  36. package/build/translations/lv.js +1 -0
  37. package/build/translations/ms.js +1 -0
  38. package/build/translations/nl.js +1 -0
  39. package/build/translations/no.js +1 -0
  40. package/build/translations/pl.js +1 -0
  41. package/build/translations/pt-br.js +1 -0
  42. package/build/translations/pt.js +1 -0
  43. package/build/translations/ro.js +1 -0
  44. package/build/translations/ru.js +1 -0
  45. package/build/translations/sk.js +1 -0
  46. package/build/translations/sq.js +1 -0
  47. package/build/translations/sr-latn.js +1 -0
  48. package/build/translations/sr.js +1 -0
  49. package/build/translations/sv.js +1 -0
  50. package/build/translations/th.js +1 -0
  51. package/build/translations/tk.js +1 -0
  52. package/build/translations/tr.js +1 -0
  53. package/build/translations/ug.js +1 -0
  54. package/build/translations/uk.js +1 -0
  55. package/build/translations/ur.js +1 -0
  56. package/build/translations/uz.js +1 -0
  57. package/build/translations/vi.js +1 -0
  58. package/build/translations/zh-cn.js +1 -0
  59. package/build/translations/zh.js +1 -0
  60. package/ckeditor5-metadata.json +34 -0
  61. package/dist/augmentation.d.ts +29 -0
  62. package/dist/codeblock.d.ts +37 -0
  63. package/dist/codeblockcommand.d.ts +64 -0
  64. package/dist/codeblockconfig.d.ts +150 -0
  65. package/dist/codeblockediting.d.ts +51 -0
  66. package/dist/codeblockui.d.ts +37 -0
  67. package/dist/converters.d.ts +130 -0
  68. package/dist/indentcodeblockcommand.d.ts +37 -0
  69. package/dist/index-content.css +24 -0
  70. package/dist/index-editor.css +12 -0
  71. package/dist/index.css +46 -0
  72. package/dist/index.css.map +1 -0
  73. package/dist/index.d.ts +19 -0
  74. package/dist/index.js +1455 -0
  75. package/dist/index.js.map +1 -0
  76. package/dist/outdentcodeblockcommand.d.ts +37 -0
  77. package/dist/translations/af.d.ts +8 -0
  78. package/dist/translations/af.js +5 -0
  79. package/dist/translations/af.umd.js +11 -0
  80. package/dist/translations/ar.d.ts +8 -0
  81. package/dist/translations/ar.js +5 -0
  82. package/dist/translations/ar.umd.js +11 -0
  83. package/dist/translations/az.d.ts +8 -0
  84. package/dist/translations/az.js +5 -0
  85. package/dist/translations/az.umd.js +11 -0
  86. package/dist/translations/bg.d.ts +8 -0
  87. package/dist/translations/bg.js +5 -0
  88. package/dist/translations/bg.umd.js +11 -0
  89. package/dist/translations/bn.d.ts +8 -0
  90. package/dist/translations/bn.js +5 -0
  91. package/dist/translations/bn.umd.js +11 -0
  92. package/dist/translations/bs.d.ts +8 -0
  93. package/dist/translations/bs.js +5 -0
  94. package/dist/translations/bs.umd.js +11 -0
  95. package/dist/translations/ca.d.ts +8 -0
  96. package/dist/translations/ca.js +5 -0
  97. package/dist/translations/ca.umd.js +11 -0
  98. package/dist/translations/cs.d.ts +8 -0
  99. package/dist/translations/cs.js +5 -0
  100. package/dist/translations/cs.umd.js +11 -0
  101. package/dist/translations/da.d.ts +8 -0
  102. package/dist/translations/da.js +5 -0
  103. package/dist/translations/da.umd.js +11 -0
  104. package/dist/translations/de-ch.d.ts +8 -0
  105. package/dist/translations/de-ch.js +5 -0
  106. package/dist/translations/de-ch.umd.js +11 -0
  107. package/dist/translations/de.d.ts +8 -0
  108. package/dist/translations/de.js +5 -0
  109. package/dist/translations/de.umd.js +11 -0
  110. package/dist/translations/el.d.ts +8 -0
  111. package/dist/translations/el.js +5 -0
  112. package/dist/translations/el.umd.js +11 -0
  113. package/dist/translations/en-au.d.ts +8 -0
  114. package/dist/translations/en-au.js +5 -0
  115. package/dist/translations/en-au.umd.js +11 -0
  116. package/dist/translations/en.d.ts +8 -0
  117. package/dist/translations/en.js +5 -0
  118. package/dist/translations/en.umd.js +11 -0
  119. package/dist/translations/es-co.d.ts +8 -0
  120. package/dist/translations/es-co.js +5 -0
  121. package/dist/translations/es-co.umd.js +11 -0
  122. package/dist/translations/es.d.ts +8 -0
  123. package/dist/translations/es.js +5 -0
  124. package/dist/translations/es.umd.js +11 -0
  125. package/dist/translations/et.d.ts +8 -0
  126. package/dist/translations/et.js +5 -0
  127. package/dist/translations/et.umd.js +11 -0
  128. package/dist/translations/fa.d.ts +8 -0
  129. package/dist/translations/fa.js +5 -0
  130. package/dist/translations/fa.umd.js +11 -0
  131. package/dist/translations/fi.d.ts +8 -0
  132. package/dist/translations/fi.js +5 -0
  133. package/dist/translations/fi.umd.js +11 -0
  134. package/dist/translations/fr.d.ts +8 -0
  135. package/dist/translations/fr.js +5 -0
  136. package/dist/translations/fr.umd.js +11 -0
  137. package/dist/translations/gl.d.ts +8 -0
  138. package/dist/translations/gl.js +5 -0
  139. package/dist/translations/gl.umd.js +11 -0
  140. package/dist/translations/he.d.ts +8 -0
  141. package/dist/translations/he.js +5 -0
  142. package/dist/translations/he.umd.js +11 -0
  143. package/dist/translations/hi.d.ts +8 -0
  144. package/dist/translations/hi.js +5 -0
  145. package/dist/translations/hi.umd.js +11 -0
  146. package/dist/translations/hr.d.ts +8 -0
  147. package/dist/translations/hr.js +5 -0
  148. package/dist/translations/hr.umd.js +11 -0
  149. package/dist/translations/hu.d.ts +8 -0
  150. package/dist/translations/hu.js +5 -0
  151. package/dist/translations/hu.umd.js +11 -0
  152. package/dist/translations/id.d.ts +8 -0
  153. package/dist/translations/id.js +5 -0
  154. package/dist/translations/id.umd.js +11 -0
  155. package/dist/translations/it.d.ts +8 -0
  156. package/dist/translations/it.js +5 -0
  157. package/dist/translations/it.umd.js +11 -0
  158. package/dist/translations/ja.d.ts +8 -0
  159. package/dist/translations/ja.js +5 -0
  160. package/dist/translations/ja.umd.js +11 -0
  161. package/dist/translations/jv.d.ts +8 -0
  162. package/dist/translations/jv.js +5 -0
  163. package/dist/translations/jv.umd.js +11 -0
  164. package/dist/translations/ko.d.ts +8 -0
  165. package/dist/translations/ko.js +5 -0
  166. package/dist/translations/ko.umd.js +11 -0
  167. package/dist/translations/ku.d.ts +8 -0
  168. package/dist/translations/ku.js +5 -0
  169. package/dist/translations/ku.umd.js +11 -0
  170. package/dist/translations/lt.d.ts +8 -0
  171. package/dist/translations/lt.js +5 -0
  172. package/dist/translations/lt.umd.js +11 -0
  173. package/dist/translations/lv.d.ts +8 -0
  174. package/dist/translations/lv.js +5 -0
  175. package/dist/translations/lv.umd.js +11 -0
  176. package/dist/translations/ms.d.ts +8 -0
  177. package/dist/translations/ms.js +5 -0
  178. package/dist/translations/ms.umd.js +11 -0
  179. package/dist/translations/nl.d.ts +8 -0
  180. package/dist/translations/nl.js +5 -0
  181. package/dist/translations/nl.umd.js +11 -0
  182. package/dist/translations/no.d.ts +8 -0
  183. package/dist/translations/no.js +5 -0
  184. package/dist/translations/no.umd.js +11 -0
  185. package/dist/translations/pl.d.ts +8 -0
  186. package/dist/translations/pl.js +5 -0
  187. package/dist/translations/pl.umd.js +11 -0
  188. package/dist/translations/pt-br.d.ts +8 -0
  189. package/dist/translations/pt-br.js +5 -0
  190. package/dist/translations/pt-br.umd.js +11 -0
  191. package/dist/translations/pt.d.ts +8 -0
  192. package/dist/translations/pt.js +5 -0
  193. package/dist/translations/pt.umd.js +11 -0
  194. package/dist/translations/ro.d.ts +8 -0
  195. package/dist/translations/ro.js +5 -0
  196. package/dist/translations/ro.umd.js +11 -0
  197. package/dist/translations/ru.d.ts +8 -0
  198. package/dist/translations/ru.js +5 -0
  199. package/dist/translations/ru.umd.js +11 -0
  200. package/dist/translations/sk.d.ts +8 -0
  201. package/dist/translations/sk.js +5 -0
  202. package/dist/translations/sk.umd.js +11 -0
  203. package/dist/translations/sq.d.ts +8 -0
  204. package/dist/translations/sq.js +5 -0
  205. package/dist/translations/sq.umd.js +11 -0
  206. package/dist/translations/sr-latn.d.ts +8 -0
  207. package/dist/translations/sr-latn.js +5 -0
  208. package/dist/translations/sr-latn.umd.js +11 -0
  209. package/dist/translations/sr.d.ts +8 -0
  210. package/dist/translations/sr.js +5 -0
  211. package/dist/translations/sr.umd.js +11 -0
  212. package/dist/translations/sv.d.ts +8 -0
  213. package/dist/translations/sv.js +5 -0
  214. package/dist/translations/sv.umd.js +11 -0
  215. package/dist/translations/th.d.ts +8 -0
  216. package/dist/translations/th.js +5 -0
  217. package/dist/translations/th.umd.js +11 -0
  218. package/dist/translations/tk.d.ts +8 -0
  219. package/dist/translations/tk.js +5 -0
  220. package/dist/translations/tk.umd.js +11 -0
  221. package/dist/translations/tr.d.ts +8 -0
  222. package/dist/translations/tr.js +5 -0
  223. package/dist/translations/tr.umd.js +11 -0
  224. package/dist/translations/ug.d.ts +8 -0
  225. package/dist/translations/ug.js +5 -0
  226. package/dist/translations/ug.umd.js +11 -0
  227. package/dist/translations/uk.d.ts +8 -0
  228. package/dist/translations/uk.js +5 -0
  229. package/dist/translations/uk.umd.js +11 -0
  230. package/dist/translations/ur.d.ts +8 -0
  231. package/dist/translations/ur.js +5 -0
  232. package/dist/translations/ur.umd.js +11 -0
  233. package/dist/translations/uz.d.ts +8 -0
  234. package/dist/translations/uz.js +5 -0
  235. package/dist/translations/uz.umd.js +11 -0
  236. package/dist/translations/vi.d.ts +8 -0
  237. package/dist/translations/vi.js +5 -0
  238. package/dist/translations/vi.umd.js +11 -0
  239. package/dist/translations/zh-cn.d.ts +8 -0
  240. package/dist/translations/zh-cn.js +5 -0
  241. package/dist/translations/zh-cn.umd.js +11 -0
  242. package/dist/translations/zh.d.ts +8 -0
  243. package/dist/translations/zh.js +5 -0
  244. package/dist/translations/zh.umd.js +11 -0
  245. package/dist/utils.d.ts +181 -0
  246. package/lang/contexts.json +9 -0
  247. package/lang/translations/af.po +46 -0
  248. package/lang/translations/ar.po +46 -0
  249. package/lang/translations/az.po +46 -0
  250. package/lang/translations/bg.po +46 -0
  251. package/lang/translations/bn.po +46 -0
  252. package/lang/translations/bs.po +46 -0
  253. package/lang/translations/ca.po +46 -0
  254. package/lang/translations/cs.po +46 -0
  255. package/lang/translations/da.po +46 -0
  256. package/lang/translations/de-ch.po +46 -0
  257. package/lang/translations/de.po +46 -0
  258. package/lang/translations/el.po +46 -0
  259. package/lang/translations/en-au.po +46 -0
  260. package/lang/translations/en.po +46 -0
  261. package/lang/translations/es-co.po +46 -0
  262. package/lang/translations/es.po +46 -0
  263. package/lang/translations/et.po +46 -0
  264. package/lang/translations/fa.po +46 -0
  265. package/lang/translations/fi.po +46 -0
  266. package/lang/translations/fr.po +46 -0
  267. package/lang/translations/gl.po +46 -0
  268. package/lang/translations/he.po +46 -0
  269. package/lang/translations/hi.po +46 -0
  270. package/lang/translations/hr.po +46 -0
  271. package/lang/translations/hu.po +46 -0
  272. package/lang/translations/id.po +46 -0
  273. package/lang/translations/it.po +46 -0
  274. package/lang/translations/ja.po +46 -0
  275. package/lang/translations/jv.po +46 -0
  276. package/lang/translations/ko.po +46 -0
  277. package/lang/translations/ku.po +46 -0
  278. package/lang/translations/lt.po +46 -0
  279. package/lang/translations/lv.po +46 -0
  280. package/lang/translations/ms.po +46 -0
  281. package/lang/translations/nl.po +46 -0
  282. package/lang/translations/no.po +46 -0
  283. package/lang/translations/pl.po +46 -0
  284. package/lang/translations/pt-br.po +46 -0
  285. package/lang/translations/pt.po +46 -0
  286. package/lang/translations/ro.po +46 -0
  287. package/lang/translations/ru.po +46 -0
  288. package/lang/translations/sk.po +46 -0
  289. package/lang/translations/sq.po +46 -0
  290. package/lang/translations/sr-latn.po +46 -0
  291. package/lang/translations/sr.po +46 -0
  292. package/lang/translations/sv.po +46 -0
  293. package/lang/translations/th.po +46 -0
  294. package/lang/translations/tk.po +46 -0
  295. package/lang/translations/tr.po +46 -0
  296. package/lang/translations/ug.po +46 -0
  297. package/lang/translations/uk.po +46 -0
  298. package/lang/translations/ur.po +46 -0
  299. package/lang/translations/uz.po +46 -0
  300. package/lang/translations/vi.po +46 -0
  301. package/lang/translations/zh-cn.po +46 -0
  302. package/lang/translations/zh.po +46 -0
  303. package/package.json +44 -0
  304. package/src/augmentation.d.ts +25 -0
  305. package/src/augmentation.js +5 -0
  306. package/src/codeblock.d.ts +33 -0
  307. package/src/codeblock.js +39 -0
  308. package/src/codeblockcommand.d.ts +60 -0
  309. package/src/codeblockcommand.js +138 -0
  310. package/src/codeblockconfig.d.ts +146 -0
  311. package/src/codeblockconfig.js +5 -0
  312. package/src/codeblockediting.d.ts +47 -0
  313. package/src/codeblockediting.js +429 -0
  314. package/src/codeblockui.d.ts +33 -0
  315. package/src/codeblockui.js +133 -0
  316. package/src/converters.d.ts +126 -0
  317. package/src/converters.js +277 -0
  318. package/src/indentcodeblockcommand.d.ts +33 -0
  319. package/src/indentcodeblockcommand.js +78 -0
  320. package/src/index.d.ts +15 -0
  321. package/src/index.js +11 -0
  322. package/src/outdentcodeblockcommand.d.ts +33 -0
  323. package/src/outdentcodeblockcommand.js +133 -0
  324. package/src/utils.d.ts +177 -0
  325. package/src/utils.js +280 -0
  326. package/theme/codeblock.css +40 -0
@@ -0,0 +1,33 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ import { Command, type Editor } from 'ckeditor5/src/core.js';
6
+ /**
7
+ * The code block indentation decrease command plugin.
8
+ */
9
+ export default class OutdentCodeBlockCommand extends Command {
10
+ /**
11
+ * A sequence of characters removed from the line when the command is executed.
12
+ */
13
+ private readonly _indentSequence;
14
+ constructor(editor: Editor);
15
+ /**
16
+ * @inheritDoc
17
+ */
18
+ refresh(): void;
19
+ /**
20
+ * Executes the command. When the command {@link #isEnabled is enabled}, the indentation of the
21
+ * code lines in the selection will be decreased.
22
+ *
23
+ * @fires execute
24
+ */
25
+ execute(): void;
26
+ /**
27
+ * Checks whether the command can be enabled in the current context.
28
+ *
29
+ * @private
30
+ * @returns {Boolean} Whether the command should be enabled.
31
+ */
32
+ private _checkEnabled;
33
+ }
@@ -0,0 +1,133 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ import { Command } from 'ckeditor5/src/core.js';
6
+ import { getLeadingWhiteSpaces, getIndentOutdentPositions, isModelSelectionInCodeBlock, getTextNodeAtLineStart } from './utils.js';
7
+ /**
8
+ * The code block indentation decrease command plugin.
9
+ */
10
+ export default class OutdentCodeBlockCommand extends Command {
11
+ constructor(editor) {
12
+ super(editor);
13
+ this._indentSequence = editor.config.get('codeBlock.indentSequence');
14
+ }
15
+ /**
16
+ * @inheritDoc
17
+ */
18
+ refresh() {
19
+ this.isEnabled = this._checkEnabled();
20
+ }
21
+ /**
22
+ * Executes the command. When the command {@link #isEnabled is enabled}, the indentation of the
23
+ * code lines in the selection will be decreased.
24
+ *
25
+ * @fires execute
26
+ */
27
+ execute() {
28
+ const editor = this.editor;
29
+ const model = editor.model;
30
+ model.change(() => {
31
+ const positions = getIndentOutdentPositions(model);
32
+ // Outdent all positions, for instance assuming the indent sequence is 4x space (" "):
33
+ //
34
+ // <codeBlock>^foo</codeBlock> -> <codeBlock>foo</codeBlock>
35
+ //
36
+ // <codeBlock> ^bar</codeBlock> -> <codeBlock>bar</codeBlock>
37
+ //
38
+ // Also, when there is more than one position:
39
+ //
40
+ // <codeBlock>
41
+ // ^foobar
42
+ // <softBreak></softBreak>
43
+ // ^bazqux
44
+ // </codeBlock>
45
+ //
46
+ // ->
47
+ //
48
+ // <codeBlock>
49
+ // foobar
50
+ // <softBreak></softBreak>
51
+ // bazqux
52
+ // </codeBlock>
53
+ for (const position of positions) {
54
+ const range = getLastOutdentableSequenceRange(model, position, this._indentSequence);
55
+ if (range) {
56
+ // Previously deletion was done by writer.remove(). It was changed to deleteContent() to enable
57
+ // integration of code block with track changes. It's the easiest way of integration because deleteContent()
58
+ // is already integrated with track changes, but if it ever cause any troubles it can be reverted, however
59
+ // some additional work will be required in track changes integration of code block.
60
+ model.deleteContent(model.createSelection(range));
61
+ }
62
+ }
63
+ });
64
+ }
65
+ /**
66
+ * Checks whether the command can be enabled in the current context.
67
+ *
68
+ * @private
69
+ * @returns {Boolean} Whether the command should be enabled.
70
+ */
71
+ _checkEnabled() {
72
+ if (!this._indentSequence) {
73
+ return false;
74
+ }
75
+ const model = this.editor.model;
76
+ if (!isModelSelectionInCodeBlock(model.document.selection)) {
77
+ return false;
78
+ }
79
+ // Outdent command can execute only when there is an indent character sequence
80
+ // in some of the lines.
81
+ return getIndentOutdentPositions(model).some(position => {
82
+ return getLastOutdentableSequenceRange(model, position, this._indentSequence);
83
+ });
84
+ }
85
+ }
86
+ // For a position coming from `getIndentOutdentPositions()`, it returns the range representing
87
+ // the last occurrence of the indent sequence among the leading whitespaces of the code line the
88
+ // position represents.
89
+ //
90
+ // For instance, assuming the indent sequence is 4x space (" "):
91
+ //
92
+ // <codeBlock>foo^</codeBlock> -> null
93
+ // <codeBlock>foo^<softBreak></softBreak>bar</codeBlock> -> null
94
+ // <codeBlock> ^foo</codeBlock> -> null
95
+ // <codeBlock> ^foo</codeBlock> -> <codeBlock> [ ]foo</codeBlock>
96
+ // <codeBlock> ^foo bar</codeBlock> -> <codeBlock>[ ]foo bar</codeBlock>
97
+ //
98
+ // @param {<module:engine/model/model~Model>} model
99
+ // @param {<module:engine/model/position~Position>} position
100
+ // @param {String} sequence
101
+ // @returns {<module:engine/model/range~Range>|null}
102
+ function getLastOutdentableSequenceRange(model, position, sequence) {
103
+ // Positions start before each text node (code line). Get the node corresponding to the position.
104
+ const nodeAtPosition = getTextNodeAtLineStart(position, model);
105
+ if (!nodeAtPosition) {
106
+ return null;
107
+ }
108
+ const leadingWhiteSpaces = getLeadingWhiteSpaces(nodeAtPosition);
109
+ const lastIndexOfSequence = leadingWhiteSpaces.lastIndexOf(sequence);
110
+ // For instance, assuming the indent sequence is 4x space (" "):
111
+ //
112
+ // <codeBlock> ^foo</codeBlock> -> null
113
+ //
114
+ if (lastIndexOfSequence + sequence.length !== leadingWhiteSpaces.length) {
115
+ return null;
116
+ }
117
+ // For instance, assuming the indent sequence is 4x space (" "):
118
+ //
119
+ // <codeBlock> ^foo</codeBlock> -> null
120
+ //
121
+ if (lastIndexOfSequence === -1) {
122
+ return null;
123
+ }
124
+ const { parent, startOffset } = nodeAtPosition;
125
+ // Create a range that contains the **last** indent sequence among the leading whitespaces
126
+ // of the line.
127
+ //
128
+ // For instance, assuming the indent sequence is 4x space (" "):
129
+ //
130
+ // <codeBlock> ^foo</codeBlock> -> <codeBlock> [ ]foo</codeBlock>
131
+ //
132
+ return model.createRange(model.createPositionAt(parent, startOffset + lastIndexOfSequence), model.createPositionAt(parent, startOffset + lastIndexOfSequence + sequence.length));
133
+ }
package/src/utils.d.ts ADDED
@@ -0,0 +1,177 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /**
6
+ * @module code-block/utils
7
+ */
8
+ import type { Editor } from 'ckeditor5/src/core.js';
9
+ import type { CodeBlockLanguageDefinition } from './codeblockconfig.js';
10
+ import type { DocumentSelection, Element, Model, Position, Schema, Text, UpcastWriter, ViewDocumentFragment } from 'ckeditor5/src/engine.js';
11
+ import { type LocaleTranslate } from 'ckeditor5/src/utils.js';
12
+ /**
13
+ * Returns code block languages as defined in `config.codeBlock.languages` but processed:
14
+ *
15
+ * * To consider the editor localization, i.e. to display {@link module:code-block/codeblockconfig~CodeBlockLanguageDefinition}
16
+ * in the correct language. There is no way to use {@link module:utils/locale~Locale#t} when the user
17
+ * configuration is defined because the editor does not exist yet.
18
+ * * To make sure each definition has a CSS class associated with it even if not specified
19
+ * in the original configuration.
20
+ */
21
+ export declare function getNormalizedAndLocalizedLanguageDefinitions(editor: Editor): Array<CodeBlockLanguageDefinition>;
22
+ /**
23
+ * Returns an object associating certain language definition properties with others. For instance:
24
+ *
25
+ * For:
26
+ *
27
+ * ```ts
28
+ * const definitions = {
29
+ * { language: 'php', class: 'language-php', label: 'PHP' },
30
+ * { language: 'javascript', class: 'js', label: 'JavaScript' },
31
+ * };
32
+ *
33
+ * getPropertyAssociation( definitions, 'class', 'language' );
34
+ * ```
35
+ *
36
+ * returns:
37
+ *
38
+ * ```ts
39
+ * {
40
+ * 'language-php': 'php',
41
+ * 'js': 'javascript'
42
+ * }
43
+ * ```
44
+ *
45
+ * and
46
+ *
47
+ * ```ts
48
+ * getPropertyAssociation( definitions, 'language', 'label' );
49
+ * ```
50
+ *
51
+ * returns:
52
+ *
53
+ * ```ts
54
+ * {
55
+ * 'php': 'PHP',
56
+ * 'javascript': 'JavaScript'
57
+ * }
58
+ * ```
59
+ */
60
+ export declare function getPropertyAssociation(languageDefs: Array<CodeBlockLanguageDefinition>, key: keyof CodeBlockLanguageDefinition, value: keyof CodeBlockLanguageDefinition): Record<string, string>;
61
+ /**
62
+ * For a given model text node, it returns white spaces that precede other characters in that node.
63
+ * This corresponds to the indentation part of the code block line.
64
+ */
65
+ export declare function getLeadingWhiteSpaces(textNode: Text): string;
66
+ /**
67
+ * For plain text containing the code (a snippet), it returns a document fragment containing
68
+ * view text nodes separated by `<br>` elements (in place of new line characters "\n"), for instance:
69
+ *
70
+ * Input:
71
+ *
72
+ * ```ts
73
+ * "foo()\n
74
+ * bar()"
75
+ * ```
76
+ *
77
+ * Output:
78
+ *
79
+ * ```html
80
+ * <DocumentFragment>
81
+ * "foo()"
82
+ * <br/>
83
+ * "bar()"
84
+ * </DocumentFragment>
85
+ * ```
86
+ *
87
+ * @param text The raw code text to be converted.
88
+ */
89
+ export declare function rawSnippetTextToViewDocumentFragment(writer: UpcastWriter, text: string): ViewDocumentFragment;
90
+ /**
91
+ * Returns an array of all model positions within the selection that represent code block lines.
92
+ *
93
+ * If the selection is collapsed, it returns the exact selection anchor position:
94
+ *
95
+ * ```html
96
+ * <codeBlock>[]foo</codeBlock> -> <codeBlock>^foo</codeBlock>
97
+ * <codeBlock>foo[]bar</codeBlock> -> <codeBlock>foo^bar</codeBlock>
98
+ * ```
99
+ *
100
+ * Otherwise, it returns positions **before** each text node belonging to all code blocks contained by the selection:
101
+ *
102
+ * ```html
103
+ * <codeBlock> <codeBlock>
104
+ * foo[bar ^foobar
105
+ * <softBreak></softBreak> -> <softBreak></softBreak>
106
+ * baz]qux ^bazqux
107
+ * </codeBlock> </codeBlock>
108
+ * ```
109
+ *
110
+ * It also works across other non–code blocks:
111
+ *
112
+ * ```html
113
+ * <codeBlock> <codeBlock>
114
+ * foo[bar ^foobar
115
+ * </codeBlock> </codeBlock>
116
+ * <paragraph>text</paragraph> -> <paragraph>text</paragraph>
117
+ * <codeBlock> <codeBlock>
118
+ * baz]qux ^bazqux
119
+ * </codeBlock> </codeBlock>
120
+ * ```
121
+ *
122
+ * **Note:** The positions are in reverse order so they do not get outdated when iterating over them and
123
+ * the writer inserts or removes elements at the same time.
124
+ *
125
+ * **Note:** The position is located after the leading white spaces in the text node.
126
+ */
127
+ export declare function getIndentOutdentPositions(model: Model): Array<Position>;
128
+ /**
129
+ * Checks if any of the blocks within the model selection is a code block.
130
+ */
131
+ export declare function isModelSelectionInCodeBlock(selection: DocumentSelection): boolean;
132
+ /**
133
+ * Checks if an {@link module:engine/model/element~Element Element} can become a code block.
134
+ *
135
+ * @param schema Model's schema.
136
+ * @param element The element to be checked.
137
+ * @returns Check result.
138
+ */
139
+ export declare function canBeCodeBlock(schema: Schema, element: Element): boolean;
140
+ /**
141
+ * Get the translated message read by the screen reader when you enter or exit an element with your cursor.
142
+ */
143
+ export declare function getCodeBlockAriaAnnouncement(t: LocaleTranslate, languageDefs: Array<CodeBlockLanguageDefinition>, element: Element, direction: 'enter' | 'leave'): string;
144
+ /**
145
+ * For given position, finds the closest position that is at the beginning of a line of code and returns a text node that is at the
146
+ * beginning of the line (or `null` if there's no text node at the beginning of a given line).
147
+ *
148
+ * Line beings at the start of a code block element and after each `softBreak` element.
149
+ *
150
+ * Note: even though code block doesn't allow inline elements other than `<softBreak>` by default, some features may overwrite this rule,
151
+ * so such inline elements are taken into account.
152
+ *
153
+ * Some examples of expected results:
154
+ *
155
+ * ```
156
+ * <codeBlock>^</codeBlock> -> null
157
+ * <codeBlock>^foobar</codeBlock> -> <codeBlock>[foobar]</codeBlock>
158
+ * <codeBlock>foobar^</codeBlock> -> <codeBlock>[foobar]</codeBlock>
159
+ * <codeBlock>foo^bar</codeBlock> -> <codeBlock>[foobar]</codeBlock>
160
+ * <codeBlock>foo^<softBreak />bar</codeBlock> -> <codeBlock>[foo]<softBreak />bar</codeBlock>
161
+ * <codeBlock>foo<softBreak />bar^</codeBlock> -> <codeBlock>foo<softBreak />[bar]</codeBlock>
162
+ * <codeBlock>foo<softBreak />b^ar</codeBlock> -> <codeBlock>foo<softBreak />[bar]</codeBlock>
163
+ * <codeBlock>foo<softBreak />^bar</codeBlock> -> <codeBlock>foo<softBreak />[bar]</codeBlock>
164
+ * <codeBlock>^<element /></codeBlock> -> null
165
+ * <codeBlock><element />^</codeBlock> -> null
166
+ * <codeBlock>foo^<element /></codeBlock> -> <codeBlock>[foo]<element /></codeBlock>
167
+ * <codeBlock>foo<element />^</codeBlock> -> <codeBlock>[foo]<element /></codeBlock>
168
+ * <codeBlock>foo<element />bar^</codeBlock> -> <codeBlock>[foo]<element />bar</codeBlock>
169
+ * <codeBlock><element />bar^</codeBlock> -> null
170
+ * <codeBlock>foo<softBreak />^<softBreak /></codeBlock> -> null
171
+ * <codeBlock>foo<softBreak />^<element /></codeBlock> -> null
172
+ * <codeBlock>foo<softBreak /><element />^</codeBlock> -> null
173
+ * <codeBlock>foo<softBreak />bar<element />^</codeBlock> -> <codeBlock>foo<softBreak />[bar]<element /></codeBlock>
174
+ * <codeBlock>foo<softBreak /><element />ba^r</codeBlock> -> null
175
+ * ```
176
+ */
177
+ export declare function getTextNodeAtLineStart(position: Position, model: Model): Text | null;
package/src/utils.js ADDED
@@ -0,0 +1,280 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ import { first } from 'ckeditor5/src/utils.js';
6
+ /**
7
+ * Returns code block languages as defined in `config.codeBlock.languages` but processed:
8
+ *
9
+ * * To consider the editor localization, i.e. to display {@link module:code-block/codeblockconfig~CodeBlockLanguageDefinition}
10
+ * in the correct language. There is no way to use {@link module:utils/locale~Locale#t} when the user
11
+ * configuration is defined because the editor does not exist yet.
12
+ * * To make sure each definition has a CSS class associated with it even if not specified
13
+ * in the original configuration.
14
+ */
15
+ export function getNormalizedAndLocalizedLanguageDefinitions(editor) {
16
+ const t = editor.t;
17
+ const languageDefs = editor.config.get('codeBlock.languages');
18
+ for (const def of languageDefs) {
19
+ if (def.label === 'Plain text') {
20
+ def.label = t('Plain text');
21
+ }
22
+ if (def.class === undefined) {
23
+ def.class = `language-${def.language}`;
24
+ }
25
+ }
26
+ return languageDefs;
27
+ }
28
+ /**
29
+ * Returns an object associating certain language definition properties with others. For instance:
30
+ *
31
+ * For:
32
+ *
33
+ * ```ts
34
+ * const definitions = {
35
+ * { language: 'php', class: 'language-php', label: 'PHP' },
36
+ * { language: 'javascript', class: 'js', label: 'JavaScript' },
37
+ * };
38
+ *
39
+ * getPropertyAssociation( definitions, 'class', 'language' );
40
+ * ```
41
+ *
42
+ * returns:
43
+ *
44
+ * ```ts
45
+ * {
46
+ * 'language-php': 'php',
47
+ * 'js': 'javascript'
48
+ * }
49
+ * ```
50
+ *
51
+ * and
52
+ *
53
+ * ```ts
54
+ * getPropertyAssociation( definitions, 'language', 'label' );
55
+ * ```
56
+ *
57
+ * returns:
58
+ *
59
+ * ```ts
60
+ * {
61
+ * 'php': 'PHP',
62
+ * 'javascript': 'JavaScript'
63
+ * }
64
+ * ```
65
+ */
66
+ export function getPropertyAssociation(languageDefs, key, value) {
67
+ const association = {};
68
+ for (const def of languageDefs) {
69
+ if (key === 'class') {
70
+ // Only the first class is considered.
71
+ const newKey = (def[key]).split(' ').shift();
72
+ association[newKey] = def[value];
73
+ }
74
+ else {
75
+ association[def[key]] = def[value];
76
+ }
77
+ }
78
+ return association;
79
+ }
80
+ /**
81
+ * For a given model text node, it returns white spaces that precede other characters in that node.
82
+ * This corresponds to the indentation part of the code block line.
83
+ */
84
+ export function getLeadingWhiteSpaces(textNode) {
85
+ return textNode.data.match(/^(\s*)/)[0];
86
+ }
87
+ /**
88
+ * For plain text containing the code (a snippet), it returns a document fragment containing
89
+ * view text nodes separated by `<br>` elements (in place of new line characters "\n"), for instance:
90
+ *
91
+ * Input:
92
+ *
93
+ * ```ts
94
+ * "foo()\n
95
+ * bar()"
96
+ * ```
97
+ *
98
+ * Output:
99
+ *
100
+ * ```html
101
+ * <DocumentFragment>
102
+ * "foo()"
103
+ * <br/>
104
+ * "bar()"
105
+ * </DocumentFragment>
106
+ * ```
107
+ *
108
+ * @param text The raw code text to be converted.
109
+ */
110
+ export function rawSnippetTextToViewDocumentFragment(writer, text) {
111
+ const fragment = writer.createDocumentFragment();
112
+ const textLines = text.split('\n');
113
+ const items = textLines.reduce((nodes, line, lineIndex) => {
114
+ nodes.push(line);
115
+ if (lineIndex < textLines.length - 1) {
116
+ nodes.push(writer.createElement('br'));
117
+ }
118
+ return nodes;
119
+ }, []);
120
+ writer.appendChild(items, fragment);
121
+ return fragment;
122
+ }
123
+ /**
124
+ * Returns an array of all model positions within the selection that represent code block lines.
125
+ *
126
+ * If the selection is collapsed, it returns the exact selection anchor position:
127
+ *
128
+ * ```html
129
+ * <codeBlock>[]foo</codeBlock> -> <codeBlock>^foo</codeBlock>
130
+ * <codeBlock>foo[]bar</codeBlock> -> <codeBlock>foo^bar</codeBlock>
131
+ * ```
132
+ *
133
+ * Otherwise, it returns positions **before** each text node belonging to all code blocks contained by the selection:
134
+ *
135
+ * ```html
136
+ * <codeBlock> <codeBlock>
137
+ * foo[bar ^foobar
138
+ * <softBreak></softBreak> -> <softBreak></softBreak>
139
+ * baz]qux ^bazqux
140
+ * </codeBlock> </codeBlock>
141
+ * ```
142
+ *
143
+ * It also works across other non–code blocks:
144
+ *
145
+ * ```html
146
+ * <codeBlock> <codeBlock>
147
+ * foo[bar ^foobar
148
+ * </codeBlock> </codeBlock>
149
+ * <paragraph>text</paragraph> -> <paragraph>text</paragraph>
150
+ * <codeBlock> <codeBlock>
151
+ * baz]qux ^bazqux
152
+ * </codeBlock> </codeBlock>
153
+ * ```
154
+ *
155
+ * **Note:** The positions are in reverse order so they do not get outdated when iterating over them and
156
+ * the writer inserts or removes elements at the same time.
157
+ *
158
+ * **Note:** The position is located after the leading white spaces in the text node.
159
+ */
160
+ export function getIndentOutdentPositions(model) {
161
+ const selection = model.document.selection;
162
+ const positions = [];
163
+ // When the selection is collapsed, there's only one position we can indent or outdent.
164
+ if (selection.isCollapsed) {
165
+ return [selection.anchor];
166
+ }
167
+ // When the selection is NOT collapsed, collect all positions starting before text nodes
168
+ // (code lines) in any <codeBlock> within the selection.
169
+ // Walk backward so positions we are about to collect here do not get outdated when
170
+ // inserting or deleting using the writer.
171
+ const walker = selection.getFirstRange().getWalker({
172
+ ignoreElementEnd: true,
173
+ direction: 'backward'
174
+ });
175
+ for (const { item } of walker) {
176
+ let node = item.is('$textProxy') ? item.textNode : item;
177
+ const parent = node.parent;
178
+ if (!parent.is('element', 'codeBlock') || node.is('element', 'softBreak')) {
179
+ continue;
180
+ }
181
+ // For each item in code block, move backwards until the beginning of the line it is in is found.
182
+ while (node.previousSibling && !node.previousSibling.is('element', 'softBreak')) {
183
+ node = node.previousSibling;
184
+ }
185
+ // Take the leading white spaces into account (only for text nodes).
186
+ const startOffset = !node.is('$text') ? node.startOffset : node.startOffset + getLeadingWhiteSpaces(node).length;
187
+ const position = model.createPositionAt(parent, startOffset);
188
+ // Do not add the same position twice. Unfortunately using set doesn't deduplicate positions because
189
+ // they are different objects.
190
+ if (positions.every(pos => !pos.isEqual(position))) {
191
+ positions.push(position);
192
+ }
193
+ }
194
+ return positions;
195
+ }
196
+ /**
197
+ * Checks if any of the blocks within the model selection is a code block.
198
+ */
199
+ export function isModelSelectionInCodeBlock(selection) {
200
+ const firstBlock = first(selection.getSelectedBlocks());
201
+ return !!firstBlock && firstBlock.is('element', 'codeBlock');
202
+ }
203
+ /**
204
+ * Checks if an {@link module:engine/model/element~Element Element} can become a code block.
205
+ *
206
+ * @param schema Model's schema.
207
+ * @param element The element to be checked.
208
+ * @returns Check result.
209
+ */
210
+ export function canBeCodeBlock(schema, element) {
211
+ if (element.is('rootElement') || schema.isLimit(element)) {
212
+ return false;
213
+ }
214
+ return schema.checkChild(element.parent, 'codeBlock');
215
+ }
216
+ /**
217
+ * Get the translated message read by the screen reader when you enter or exit an element with your cursor.
218
+ */
219
+ export function getCodeBlockAriaAnnouncement(t, languageDefs, element, direction) {
220
+ const languagesToLabels = getPropertyAssociation(languageDefs, 'language', 'label');
221
+ const codeBlockLanguage = element.getAttribute('language');
222
+ if (codeBlockLanguage in languagesToLabels) {
223
+ const language = languagesToLabels[codeBlockLanguage];
224
+ if (direction === 'enter') {
225
+ return t('Entering %0 code snippet', language);
226
+ }
227
+ return t('Leaving %0 code snippet', language);
228
+ }
229
+ if (direction === 'enter') {
230
+ return t('Entering code snippet');
231
+ }
232
+ return t('Leaving code snippet');
233
+ }
234
+ /**
235
+ * For given position, finds the closest position that is at the beginning of a line of code and returns a text node that is at the
236
+ * beginning of the line (or `null` if there's no text node at the beginning of a given line).
237
+ *
238
+ * Line beings at the start of a code block element and after each `softBreak` element.
239
+ *
240
+ * Note: even though code block doesn't allow inline elements other than `<softBreak>` by default, some features may overwrite this rule,
241
+ * so such inline elements are taken into account.
242
+ *
243
+ * Some examples of expected results:
244
+ *
245
+ * ```
246
+ * <codeBlock>^</codeBlock> -> null
247
+ * <codeBlock>^foobar</codeBlock> -> <codeBlock>[foobar]</codeBlock>
248
+ * <codeBlock>foobar^</codeBlock> -> <codeBlock>[foobar]</codeBlock>
249
+ * <codeBlock>foo^bar</codeBlock> -> <codeBlock>[foobar]</codeBlock>
250
+ * <codeBlock>foo^<softBreak />bar</codeBlock> -> <codeBlock>[foo]<softBreak />bar</codeBlock>
251
+ * <codeBlock>foo<softBreak />bar^</codeBlock> -> <codeBlock>foo<softBreak />[bar]</codeBlock>
252
+ * <codeBlock>foo<softBreak />b^ar</codeBlock> -> <codeBlock>foo<softBreak />[bar]</codeBlock>
253
+ * <codeBlock>foo<softBreak />^bar</codeBlock> -> <codeBlock>foo<softBreak />[bar]</codeBlock>
254
+ * <codeBlock>^<element /></codeBlock> -> null
255
+ * <codeBlock><element />^</codeBlock> -> null
256
+ * <codeBlock>foo^<element /></codeBlock> -> <codeBlock>[foo]<element /></codeBlock>
257
+ * <codeBlock>foo<element />^</codeBlock> -> <codeBlock>[foo]<element /></codeBlock>
258
+ * <codeBlock>foo<element />bar^</codeBlock> -> <codeBlock>[foo]<element />bar</codeBlock>
259
+ * <codeBlock><element />bar^</codeBlock> -> null
260
+ * <codeBlock>foo<softBreak />^<softBreak /></codeBlock> -> null
261
+ * <codeBlock>foo<softBreak />^<element /></codeBlock> -> null
262
+ * <codeBlock>foo<softBreak /><element />^</codeBlock> -> null
263
+ * <codeBlock>foo<softBreak />bar<element />^</codeBlock> -> <codeBlock>foo<softBreak />[bar]<element /></codeBlock>
264
+ * <codeBlock>foo<softBreak /><element />ba^r</codeBlock> -> null
265
+ * ```
266
+ */
267
+ export function getTextNodeAtLineStart(position, model) {
268
+ // First, move position before a text node, if it is inside a text node.
269
+ if (position.textNode) {
270
+ position = model.createPositionBefore(position.textNode);
271
+ }
272
+ // Then, jump-back the position until it is before a `softBreak` or at the beginning of the `codeBlock`.
273
+ while (position.nodeBefore && !position.nodeBefore.is('element', 'softBreak')) {
274
+ position = model.createPositionBefore(position.nodeBefore);
275
+ }
276
+ // Now, the position is at the beginning of a line.
277
+ // Return a text node after the position, if there is one.
278
+ const nodeAtStart = position.nodeAfter;
279
+ return nodeAtStart && nodeAtStart.is('$text') ? nodeAtStart : null;
280
+ }
@@ -0,0 +1,40 @@
1
+ /*
2
+ * Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+
6
+ .ck-content pre {
7
+ padding: 1em;
8
+ color: hsl(0, 0%, 20.8%);
9
+ background: hsla(0, 0%, 78%, 0.3);
10
+ border: 1px solid hsl(0, 0%, 77%);
11
+ border-radius: 2px;
12
+
13
+ /* Code block are language direction–agnostic. */
14
+ text-align: left;
15
+ direction: ltr;
16
+
17
+ tab-size: 4;
18
+ white-space: pre-wrap;
19
+
20
+ /* Don't inherit the style, e.g. when in a block quote. */
21
+ font-style: normal;
22
+
23
+ /* Don't let the code be squashed e.g. when in a table cell. */
24
+ min-width: 200px;
25
+
26
+ & code {
27
+ background: unset;
28
+ padding: 0;
29
+ border-radius: 0;
30
+ }
31
+ }
32
+
33
+ .ck.ck-editor__editable pre {
34
+ position: relative;
35
+
36
+ &[data-language]::after {
37
+ content: attr(data-language);
38
+ position: absolute;
39
+ }
40
+ }