suneditor 2.46.1 → 3.0.0-alpha.1

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 (290) hide show
  1. package/.eslintignore +7 -0
  2. package/.eslintrc.json +64 -0
  3. package/CONTRIBUTING.md +36 -0
  4. package/LICENSE.txt +1 -1
  5. package/README.md +174 -805
  6. package/dist/suneditor.min.css +1 -0
  7. package/dist/suneditor.min.js +1 -2
  8. package/package.json +96 -70
  9. package/src/assets/icons/_default.js +194 -0
  10. package/src/assets/suneditor-content.css +646 -0
  11. package/src/assets/suneditor.css +3378 -0
  12. package/src/core/base/eventHandlers/handler_toolbar.js +114 -0
  13. package/src/core/base/eventHandlers/handler_ww_clipboard.js +31 -0
  14. package/src/core/base/eventHandlers/handler_ww_dragDrop.js +69 -0
  15. package/src/core/base/eventHandlers/handler_ww_key_input.js +975 -0
  16. package/src/core/base/eventHandlers/handler_ww_mouse.js +118 -0
  17. package/src/core/base/eventManager.js +1115 -0
  18. package/src/core/base/events.js +320 -0
  19. package/src/core/base/history.js +301 -0
  20. package/src/core/class/char.js +146 -0
  21. package/src/core/class/component.js +627 -0
  22. package/src/core/class/format.js +3255 -0
  23. package/src/core/class/html.js +1621 -0
  24. package/src/core/class/menu.js +260 -0
  25. package/src/core/class/nodeTransform.js +379 -0
  26. package/src/core/class/notice.js +42 -0
  27. package/src/core/class/offset.js +578 -0
  28. package/src/core/class/selection.js +508 -0
  29. package/src/core/class/shortcuts.js +38 -0
  30. package/src/core/class/toolbar.js +440 -0
  31. package/src/core/class/viewer.js +646 -0
  32. package/src/core/editor.js +1593 -0
  33. package/src/core/section/actives.js +107 -0
  34. package/src/core/section/constructor.js +1237 -0
  35. package/src/core/section/context.js +97 -0
  36. package/src/editorInjector/_classes.js +22 -0
  37. package/src/editorInjector/_core.js +28 -0
  38. package/src/editorInjector/index.js +13 -0
  39. package/src/helper/converter.js +313 -0
  40. package/src/helper/domUtils.js +1177 -0
  41. package/src/helper/env.js +250 -0
  42. package/src/helper/index.js +19 -0
  43. package/src/helper/numbers.js +68 -0
  44. package/src/helper/unicode.js +43 -0
  45. package/src/langs/ckb.js +161 -0
  46. package/src/langs/cs.js +161 -0
  47. package/src/langs/da.js +161 -0
  48. package/src/langs/de.js +162 -0
  49. package/src/langs/en.js +199 -0
  50. package/src/langs/es.js +162 -0
  51. package/src/langs/fa.js +159 -0
  52. package/src/langs/fr.js +161 -0
  53. package/src/langs/he.js +162 -0
  54. package/src/{lang → langs}/index.js +0 -2
  55. package/src/langs/it.js +162 -0
  56. package/src/langs/ja.js +162 -0
  57. package/src/langs/ko.js +162 -0
  58. package/src/langs/lv.js +162 -0
  59. package/src/langs/nl.js +162 -0
  60. package/src/langs/pl.js +162 -0
  61. package/src/langs/pt_br.js +162 -0
  62. package/src/langs/ro.js +162 -0
  63. package/src/langs/ru.js +162 -0
  64. package/src/langs/se.js +162 -0
  65. package/src/langs/tr.js +159 -0
  66. package/src/langs/ua.js +162 -0
  67. package/src/langs/ur.js +162 -0
  68. package/src/langs/zh_cn.js +162 -0
  69. package/src/modules/ApiManager.js +168 -0
  70. package/src/modules/ColorPicker.js +302 -0
  71. package/src/modules/Controller.js +315 -0
  72. package/src/modules/Figure.js +1160 -0
  73. package/src/modules/FileBrowser.js +271 -0
  74. package/src/modules/FileManager.js +290 -0
  75. package/src/modules/HueSlider.js +513 -0
  76. package/src/modules/Modal.js +177 -0
  77. package/src/modules/ModalAnchorEditor.js +494 -0
  78. package/src/modules/SelectMenu.js +447 -0
  79. package/src/modules/_DragHandle.js +16 -0
  80. package/src/modules/index.js +14 -0
  81. package/src/plugins/command/blockquote.js +47 -47
  82. package/src/plugins/command/exportPdf.js +168 -0
  83. package/src/plugins/command/fileUpload.js +389 -0
  84. package/src/plugins/command/list_bulleted.js +112 -0
  85. package/src/plugins/command/list_numbered.js +115 -0
  86. package/src/plugins/dropdown/align.js +143 -0
  87. package/src/plugins/dropdown/backgroundColor.js +73 -0
  88. package/src/plugins/dropdown/font.js +113 -0
  89. package/src/plugins/dropdown/fontColor.js +73 -0
  90. package/src/plugins/dropdown/formatBlock.js +141 -0
  91. package/src/plugins/dropdown/hr.js +111 -0
  92. package/src/plugins/dropdown/layout.js +72 -0
  93. package/src/plugins/dropdown/lineHeight.js +114 -0
  94. package/src/plugins/dropdown/list.js +107 -0
  95. package/src/plugins/dropdown/paragraphStyle.js +117 -0
  96. package/src/plugins/dropdown/table.js +2810 -0
  97. package/src/plugins/dropdown/template.js +71 -0
  98. package/src/plugins/dropdown/textStyle.js +137 -0
  99. package/src/plugins/field/mention.js +172 -0
  100. package/src/plugins/fileBrowser/imageGallery.js +76 -59
  101. package/src/plugins/index.js +86 -24
  102. package/src/plugins/input/fontSize.js +357 -0
  103. package/src/plugins/modal/audio.js +510 -0
  104. package/src/plugins/modal/image.js +1062 -0
  105. package/src/plugins/modal/link.js +211 -0
  106. package/src/plugins/modal/math.js +347 -0
  107. package/src/plugins/modal/video.js +870 -0
  108. package/src/suneditor.js +62 -67
  109. package/src/themes/test.css +61 -0
  110. package/typings/CommandPlugin.d.ts +8 -0
  111. package/typings/DialogPlugin.d.ts +20 -0
  112. package/typings/FileBrowserPlugin.d.ts +30 -0
  113. package/typings/Lang.d.ts +124 -0
  114. package/typings/Module.d.ts +15 -0
  115. package/typings/Plugin.d.ts +42 -0
  116. package/typings/SubmenuPlugin.d.ts +8 -0
  117. package/typings/_classes.d.ts +17 -0
  118. package/typings/_colorPicker.d.ts +60 -0
  119. package/typings/_core.d.ts +55 -0
  120. package/typings/align.d.ts +5 -0
  121. package/{src/plugins/dialog → typings}/audio.d.ts +1 -1
  122. package/typings/backgroundColor.d.ts +5 -0
  123. package/{src/plugins/command → typings}/blockquote.d.ts +1 -1
  124. package/typings/char.d.ts +39 -0
  125. package/typings/component.d.ts +38 -0
  126. package/typings/context.d.ts +39 -0
  127. package/typings/converter.d.ts +33 -0
  128. package/typings/dialog.d.ts +28 -0
  129. package/typings/domUtils.d.ts +361 -0
  130. package/typings/editor.d.ts +7 -0
  131. package/typings/editor.ts +542 -0
  132. package/typings/env.d.ts +70 -0
  133. package/typings/eventManager.d.ts +37 -0
  134. package/typings/events.d.ts +262 -0
  135. package/typings/fileBrowser.d.ts +42 -0
  136. package/typings/fileManager.d.ts +67 -0
  137. package/typings/font.d.ts +5 -0
  138. package/typings/fontColor.d.ts +5 -0
  139. package/typings/fontSize.d.ts +5 -0
  140. package/typings/format.d.ts +191 -0
  141. package/typings/formatBlock.d.ts +5 -0
  142. package/typings/history.d.ts +48 -0
  143. package/typings/horizontalRule.d.ts +5 -0
  144. package/{src/plugins/dialog → typings}/image.d.ts +1 -1
  145. package/{src/plugins/fileBrowser → typings}/imageGallery.d.ts +1 -1
  146. package/typings/index.d.ts +21 -0
  147. package/{src/plugins/modules/index.d.ts → typings/index.modules.d.ts} +3 -3
  148. package/typings/index.plugins.d.ts +58 -0
  149. package/typings/lineHeight.d.ts +5 -0
  150. package/{src/plugins/dialog → typings}/link.d.ts +1 -1
  151. package/typings/list.d.ts +5 -0
  152. package/{src/plugins/dialog → typings}/math.d.ts +1 -1
  153. package/typings/mediaContainer.d.ts +25 -0
  154. package/typings/node.d.ts +57 -0
  155. package/typings/notice.d.ts +16 -0
  156. package/typings/numbers.d.ts +29 -0
  157. package/typings/offset.d.ts +24 -0
  158. package/typings/options.d.ts +589 -0
  159. package/typings/paragraphStyle.d.ts +5 -0
  160. package/typings/resizing.d.ts +141 -0
  161. package/typings/selection.d.ts +94 -0
  162. package/typings/shortcuts.d.ts +13 -0
  163. package/typings/suneditor.d.ts +9 -0
  164. package/typings/table.d.ts +5 -0
  165. package/typings/template.d.ts +5 -0
  166. package/typings/textStyle.d.ts +5 -0
  167. package/typings/toolbar.d.ts +32 -0
  168. package/typings/unicode.d.ts +25 -0
  169. package/{src/plugins/dialog → typings}/video.d.ts +1 -1
  170. package/dist/css/suneditor.min.css +0 -1
  171. package/src/assets/css/suneditor-contents.css +0 -562
  172. package/src/assets/css/suneditor.css +0 -566
  173. package/src/assets/defaultIcons.js +0 -103
  174. package/src/lang/Lang.d.ts +0 -144
  175. package/src/lang/ckb.d.ts +0 -5
  176. package/src/lang/ckb.js +0 -188
  177. package/src/lang/cs.d.ts +0 -5
  178. package/src/lang/cs.js +0 -188
  179. package/src/lang/da.d.ts +0 -5
  180. package/src/lang/da.js +0 -191
  181. package/src/lang/de.d.ts +0 -5
  182. package/src/lang/de.js +0 -188
  183. package/src/lang/en.d.ts +0 -5
  184. package/src/lang/en.js +0 -188
  185. package/src/lang/es.d.ts +0 -5
  186. package/src/lang/es.js +0 -188
  187. package/src/lang/fa.d.ts +0 -5
  188. package/src/lang/fa.js +0 -188
  189. package/src/lang/fr.d.ts +0 -5
  190. package/src/lang/fr.js +0 -188
  191. package/src/lang/he.d.ts +0 -5
  192. package/src/lang/he.js +0 -188
  193. package/src/lang/index.d.ts +0 -23
  194. package/src/lang/it.d.ts +0 -5
  195. package/src/lang/it.js +0 -188
  196. package/src/lang/ja.d.ts +0 -5
  197. package/src/lang/ja.js +0 -188
  198. package/src/lang/ko.d.ts +0 -5
  199. package/src/lang/ko.js +0 -188
  200. package/src/lang/lv.d.ts +0 -5
  201. package/src/lang/lv.js +0 -188
  202. package/src/lang/nl.d.ts +0 -5
  203. package/src/lang/nl.js +0 -188
  204. package/src/lang/pl.d.ts +0 -5
  205. package/src/lang/pl.js +0 -188
  206. package/src/lang/pt_br.d.ts +0 -5
  207. package/src/lang/pt_br.js +0 -189
  208. package/src/lang/ro.d.ts +0 -5
  209. package/src/lang/ro.js +0 -188
  210. package/src/lang/ru.d.ts +0 -5
  211. package/src/lang/ru.js +0 -188
  212. package/src/lang/se.d.ts +0 -5
  213. package/src/lang/se.js +0 -191
  214. package/src/lang/tr.d.ts +0 -5
  215. package/src/lang/tr.js +0 -191
  216. package/src/lang/ua.d.ts +0 -5
  217. package/src/lang/ua.js +0 -188
  218. package/src/lang/ur.d.ts +0 -5
  219. package/src/lang/ur.js +0 -188
  220. package/src/lang/zh_cn.d.ts +0 -5
  221. package/src/lang/zh_cn.js +0 -187
  222. package/src/lib/constructor.js +0 -954
  223. package/src/lib/context.d.ts +0 -42
  224. package/src/lib/context.js +0 -71
  225. package/src/lib/core.d.ts +0 -1135
  226. package/src/lib/core.js +0 -9395
  227. package/src/lib/history.d.ts +0 -48
  228. package/src/lib/history.js +0 -219
  229. package/src/lib/util.d.ts +0 -678
  230. package/src/lib/util.js +0 -2131
  231. package/src/options.d.ts +0 -608
  232. package/src/plugins/CommandPlugin.d.ts +0 -8
  233. package/src/plugins/DialogPlugin.d.ts +0 -20
  234. package/src/plugins/FileBrowserPlugin.d.ts +0 -30
  235. package/src/plugins/Module.d.ts +0 -15
  236. package/src/plugins/Plugin.d.ts +0 -42
  237. package/src/plugins/SubmenuPlugin.d.ts +0 -8
  238. package/src/plugins/dialog/audio.js +0 -559
  239. package/src/plugins/dialog/image.js +0 -1126
  240. package/src/plugins/dialog/link.js +0 -223
  241. package/src/plugins/dialog/math.js +0 -295
  242. package/src/plugins/dialog/mention.js +0 -242
  243. package/src/plugins/dialog/video.js +0 -979
  244. package/src/plugins/index.d.ts +0 -79
  245. package/src/plugins/modules/_anchor.js +0 -461
  246. package/src/plugins/modules/_colorPicker.d.ts +0 -60
  247. package/src/plugins/modules/_colorPicker.js +0 -201
  248. package/src/plugins/modules/_notice.d.ts +0 -21
  249. package/src/plugins/modules/_notice.js +0 -72
  250. package/src/plugins/modules/_selectMenu.js +0 -119
  251. package/src/plugins/modules/component.d.ts +0 -25
  252. package/src/plugins/modules/component.js +0 -81
  253. package/src/plugins/modules/dialog.d.ts +0 -28
  254. package/src/plugins/modules/dialog.js +0 -175
  255. package/src/plugins/modules/fileBrowser.d.ts +0 -42
  256. package/src/plugins/modules/fileBrowser.js +0 -374
  257. package/src/plugins/modules/fileManager.d.ts +0 -67
  258. package/src/plugins/modules/fileManager.js +0 -326
  259. package/src/plugins/modules/index.js +0 -9
  260. package/src/plugins/modules/resizing.d.ts +0 -154
  261. package/src/plugins/modules/resizing.js +0 -903
  262. package/src/plugins/submenu/align.d.ts +0 -5
  263. package/src/plugins/submenu/align.js +0 -160
  264. package/src/plugins/submenu/font.d.ts +0 -5
  265. package/src/plugins/submenu/font.js +0 -123
  266. package/src/plugins/submenu/fontColor.d.ts +0 -5
  267. package/src/plugins/submenu/fontColor.js +0 -101
  268. package/src/plugins/submenu/fontSize.d.ts +0 -5
  269. package/src/plugins/submenu/fontSize.js +0 -112
  270. package/src/plugins/submenu/formatBlock.d.ts +0 -5
  271. package/src/plugins/submenu/formatBlock.js +0 -273
  272. package/src/plugins/submenu/hiliteColor.d.ts +0 -5
  273. package/src/plugins/submenu/hiliteColor.js +0 -102
  274. package/src/plugins/submenu/horizontalRule.d.ts +0 -5
  275. package/src/plugins/submenu/horizontalRule.js +0 -98
  276. package/src/plugins/submenu/lineHeight.d.ts +0 -5
  277. package/src/plugins/submenu/lineHeight.js +0 -104
  278. package/src/plugins/submenu/list.d.ts +0 -5
  279. package/src/plugins/submenu/list.js +0 -456
  280. package/src/plugins/submenu/paragraphStyle.d.ts +0 -5
  281. package/src/plugins/submenu/paragraphStyle.js +0 -135
  282. package/src/plugins/submenu/table.d.ts +0 -5
  283. package/src/plugins/submenu/table.js +0 -1431
  284. package/src/plugins/submenu/template.d.ts +0 -5
  285. package/src/plugins/submenu/template.js +0 -72
  286. package/src/plugins/submenu/textStyle.d.ts +0 -5
  287. package/src/plugins/submenu/textStyle.js +0 -167
  288. package/src/suneditor.d.ts +0 -9
  289. package/src/suneditor_build.js +0 -18
  290. /package/{src/plugins/dialog → typings}/mention.d.ts +0 -0
@@ -0,0 +1,211 @@
1
+ import EditorInjector from '../../editorInjector';
2
+ import { Modal, Controller, ModalAnchorEditor } from '../../modules';
3
+ import { domUtils, numbers } from '../../helper';
4
+
5
+ const Link = function (editor, pluginOptions) {
6
+ // plugin bisic properties
7
+ EditorInjector.call(this, editor);
8
+ this.title = this.lang.link;
9
+ this.icon = 'link';
10
+
11
+ // define plugin options
12
+ pluginOptions.textToDisplay = true;
13
+ pluginOptions.title = true;
14
+
15
+ // create HTML
16
+ const modalEl = CreateHTML_modal(editor);
17
+ const controllerEl = CreateHTML_controller(editor);
18
+
19
+ // members
20
+ const uploadUrl = typeof pluginOptions.uploadUrl === 'string' ? pluginOptions.uploadUrl : null;
21
+ this.isUpdateState = false;
22
+ this.pluginOptions = {
23
+ ...pluginOptions,
24
+ uploadUrl,
25
+ uploadHeaders: pluginOptions.uploadHeaders || null,
26
+ uploadSizeLimit: /\d+/.test(pluginOptions.uploadSizeLimit) ? numbers.get(pluginOptions.uploadSizeLimit, 0) : null,
27
+ uploadSingleSizeLimit: /\d+/.test(pluginOptions.uploadSingleSizeLimit) ? numbers.get(pluginOptions.uploadSingleSizeLimit, 0) : null,
28
+ acceptedFormats: typeof pluginOptions.acceptedFormats === 'string' ? pluginOptions.acceptedFormats.trim() : null,
29
+ enableFileUpload: !!uploadUrl
30
+ };
31
+
32
+ // modules
33
+ this.anchor = new ModalAnchorEditor(this, modalEl, this.pluginOptions);
34
+ this.modal = new Modal(this, modalEl);
35
+ this.controller = new Controller(this, controllerEl, { position: 'bottom', disabled: false });
36
+ };
37
+
38
+ Link.key = 'link';
39
+ Link.type = 'modal';
40
+ Link.className = 'se-icon-flip-rtl';
41
+ Link.prototype = {
42
+ /**
43
+ * @override core
44
+ */
45
+ active(element) {
46
+ if (domUtils.isAnchor(element) && !element.hasAttribute('data-se-non-link')) {
47
+ const tempLink = this.controller.form.querySelector('a');
48
+ tempLink.href = element.href;
49
+ tempLink.title = element.textContent;
50
+ tempLink.textContent = element.textContent;
51
+
52
+ domUtils.addClass(element, 'on');
53
+
54
+ this.anchor.set(element);
55
+ this.controller.open(element, null, { isWWTarget: false, initMethod: null, addOffset: null });
56
+
57
+ return true;
58
+ }
59
+
60
+ this.controller.close();
61
+
62
+ return false;
63
+ },
64
+
65
+ /**
66
+ * @override type = "modal"
67
+ */
68
+ open() {
69
+ this.modal.open();
70
+ },
71
+
72
+ /**
73
+ * @override modal
74
+ * @param {boolean} isUpdate open state is update
75
+ */
76
+ on(isUpdate) {
77
+ this.isUpdateState = isUpdate;
78
+ this.anchor.on(isUpdate);
79
+ },
80
+
81
+ /**
82
+ * @override modal
83
+ * @returns {boolean | undefined}
84
+ */
85
+ modalAction() {
86
+ const oA = this.anchor.create(false);
87
+ if (oA === null) return false;
88
+
89
+ if (!this.isUpdateState) {
90
+ const selectedFormats = this.format.getLines();
91
+ if (selectedFormats.length > 1) {
92
+ if (!this.html.insertNode(domUtils.createElement(selectedFormats[0].nodeName, null, oA), null, false)) return true;
93
+ } else {
94
+ if (!this.html.insertNode(oA, null, false)) return true;
95
+ }
96
+
97
+ this.selection.setRange(oA.childNodes[0], 0, oA.childNodes[0], oA.textContent.length);
98
+ } else {
99
+ // set range
100
+ const textNode = this.controller.currentTarget.childNodes[0];
101
+ this.selection.setRange(textNode, 0, textNode, textNode.textContent.length);
102
+ }
103
+
104
+ return true;
105
+ },
106
+
107
+ /**
108
+ * @override modal
109
+ */
110
+ init() {
111
+ this.controller.close();
112
+ this.anchor.init();
113
+ },
114
+
115
+ /**
116
+ * @override controller
117
+ * @param {Element} target Target button element
118
+ * @returns
119
+ */
120
+ controllerAction(target) {
121
+ const command = target.getAttribute('data-command');
122
+
123
+ if (/update/.test(command)) {
124
+ this.modal.open();
125
+ } else if (/unlink/.test(command)) {
126
+ const sc = domUtils.getEdgeChild(
127
+ this.controller.currentTarget,
128
+ function (current) {
129
+ return current.childNodes.length === 0 || current.nodeType === 3;
130
+ },
131
+ false
132
+ );
133
+ const ec = domUtils.getEdgeChild(
134
+ this.controller.currentTarget,
135
+ function (current) {
136
+ return current.childNodes.length === 0 || current.nodeType === 3;
137
+ },
138
+ true
139
+ );
140
+ this.selection.setRange(sc, 0, ec, ec.textContent.length);
141
+ this.format.applyTextStyle(null, null, ['A'], false);
142
+ } else {
143
+ /** delete */
144
+ domUtils.removeItem(this.controller.currentTarget);
145
+ this.controller.currentTarget = null;
146
+ this.editor.focus();
147
+ this.history.push(false);
148
+ }
149
+ },
150
+
151
+ /**
152
+ * @override controller
153
+ */
154
+ close() {
155
+ domUtils.removeClass(this.controller.currentTarget, 'on');
156
+ },
157
+
158
+ constructor: Link
159
+ };
160
+
161
+ function CreateHTML_modal({ lang, icons }) {
162
+ const html = /*html*/ `
163
+ <form>
164
+ <div class="se-modal-header">
165
+ <button type="button" data-command="close" class="se-btn se-close-btn" title="${lang.close}" aria-label="${lang.close}">
166
+ ${icons.cancel}
167
+ </button>
168
+ <span class="se-modal-title">${lang.link_modal_title}</span>
169
+ </div>
170
+ <div class="se-anchor-editor"></div>
171
+ <div class="se-modal-footer">
172
+ <button type="submit" class="se-btn-primary" title="${lang.submitButton}" aria-label="${lang.submitButton}">
173
+ <span>${lang.submitButton}</span>
174
+ </button>
175
+ </div>
176
+ </form>`;
177
+
178
+ return domUtils.createElement('DIV', { class: 'se-modal-content' }, html);
179
+ }
180
+
181
+ function CreateHTML_controller({ lang, icons }) {
182
+ const html = /*html*/ `
183
+ <div class="se-arrow se-arrow-up"></div>
184
+ <div class="link-content">
185
+ <span><a target="_blank" href=""></a>&nbsp;</span>
186
+ <div class="se-btn-group">
187
+ <button type="button" data-command="update" tabindex="-1" class="se-btn se-tooltip">
188
+ ${icons.edit}
189
+ <span class="se-tooltip-inner">
190
+ <span class="se-tooltip-text">${lang.edit}</span>
191
+ </span>
192
+ </button>
193
+ <button type="button" data-command="unlink" tabindex="-1" class="se-btn se-tooltip se-icon-flip-rtl">
194
+ ${icons.unlink}
195
+ <span class="se-tooltip-inner">
196
+ <span class="se-tooltip-text">${lang.unlink}</span>
197
+ </span>
198
+ </button>
199
+ <button type="button" data-command="delete" tabindex="-1" class="se-btn se-tooltip">
200
+ ${icons.delete}
201
+ <span class="se-tooltip-inner">
202
+ <span class="se-tooltip-text">${lang.remove}</span>
203
+ </span>
204
+ </button>
205
+ </div>
206
+ </div>`;
207
+
208
+ return domUtils.createElement('DIV', { class: 'se-controller se-controller-link' }, html);
209
+ }
210
+
211
+ export default Link;
@@ -0,0 +1,347 @@
1
+ import EditorInjector from '../../editorInjector';
2
+ import { Modal, Controller } from '../../modules';
3
+ import { domUtils, env, converter } from '../../helper';
4
+
5
+ const Math_ = function (editor, pluginOptions) {
6
+ // exception
7
+ if (!(this.katex = CheckKatex(editor.options.get('externalLibs').katex))) {
8
+ console.warn('[SUNEDITOR.plugins.math.warn] The math plugin must need the "KaTeX" library, Please add the katex option.');
9
+ }
10
+
11
+ // plugin bisic properties
12
+ EditorInjector.call(this, editor);
13
+ this.title = this.lang.math;
14
+ this.icon = 'math';
15
+
16
+ // create HTML
17
+ const modalEl = CreateHTML_modal(editor, this, pluginOptions.fontSizeList);
18
+ const controllerEl = CreateHTML_controller(editor);
19
+
20
+ // modules
21
+ this.modal = new Modal(this, modalEl);
22
+ this.controller = new Controller(this, controllerEl, { position: 'bottom', disabled: true });
23
+
24
+ // members
25
+ this.textArea = modalEl.querySelector('.se-math-exp');
26
+ this.previewElement = modalEl.querySelector('.se-math-preview');
27
+ this.fontSizeElement = modalEl.querySelector('.se-math-size');
28
+ this.isUpdateState = false;
29
+ this._element = null;
30
+
31
+ // init
32
+ this.previewElement.style.fontSize = this.defaultFontSize;
33
+ this.eventManager.addEvent(this.textArea, 'input', RenderMathExp.bind(this));
34
+ this.eventManager.addEvent(
35
+ this.fontSizeElement,
36
+ 'change',
37
+ function (e) {
38
+ this.fontSize = e.target.value;
39
+ }.bind(this.previewElement.style)
40
+ );
41
+ };
42
+
43
+ Math_.key = 'math';
44
+ Math_.type = 'modal';
45
+ Math_.className = '';
46
+ Math_.component = function (node) {
47
+ return domUtils.hasClass(node, 'katex|se-component') ? node : null;
48
+ };
49
+ Math_.prototype = {
50
+ /**
51
+ * @override component, fileManager
52
+ * @description Called when a container is selected.
53
+ * @param {Element} element Target element
54
+ */
55
+ select(element) {
56
+ if (domUtils.hasClass(element, 'katex') && getValue(element)) {
57
+ this._element = element;
58
+ this.controller.open(element, null, { isWWTarget: false, initMethod: null, addOffset: null });
59
+ return;
60
+ }
61
+ },
62
+
63
+ /**
64
+ * @override controller
65
+ */
66
+ close() {
67
+ this._element = null;
68
+ },
69
+
70
+ /**
71
+ * @override core
72
+ */
73
+ retainFormat() {
74
+ return {
75
+ query: '.katex',
76
+ method: (element) => {
77
+ if (!this.katex) return;
78
+
79
+ const value = getValue(element);
80
+ if (!value) return;
81
+
82
+ const dom = this._d.createRange().createContextualFragment(this._renderer(converter.entityToHTML(this._escapeBackslashes(value, true))));
83
+ element.innerHTML = dom.querySelector('.katex').innerHTML;
84
+ element.setAttribute('contenteditable', false);
85
+ domUtils.addClass(element, 'se-component|se-inline-component|se-disable-pointer');
86
+ }
87
+ };
88
+ },
89
+
90
+ /**
91
+ * @override type = "modal"
92
+ */
93
+ open() {
94
+ this.modal.open();
95
+ },
96
+
97
+ /**
98
+ * @override modal
99
+ * @param {boolean} isUpdate open state is update
100
+ */
101
+ on(isUpdate) {
102
+ this.isUpdateState = isUpdate;
103
+ if (!isUpdate) {
104
+ this.init();
105
+ } else if (this.controller.currentTarget) {
106
+ const currentTarget = this.controller.currentTarget;
107
+ const exp = converter.entityToHTML(this._escapeBackslashes(getValue(currentTarget), true));
108
+ const fontSize = getType(currentTarget) || '1em';
109
+ this.textArea.value = exp;
110
+ this.fontSizeElement.value = fontSize;
111
+ this.previewElement.innerHTML = this._renderer(exp);
112
+ this.previewElement.style.fontSize = fontSize;
113
+ }
114
+ },
115
+
116
+ /**
117
+ * @override modal
118
+ * @returns {boolean | undefined}
119
+ */
120
+ modalAction() {
121
+ if (this.textArea.value.trim().length === 0) return false;
122
+
123
+ const mathExp = this.textArea.value;
124
+ const katexEl = this.previewElement.querySelector('.katex');
125
+
126
+ if (!katexEl) return false;
127
+ katexEl.className = 'se-component se-inline-component __se__katex ' + katexEl.className;
128
+ katexEl.setAttribute('contenteditable', false);
129
+ katexEl.setAttribute('data-se-value', converter.htmlToEntity(this._escapeBackslashes(mathExp, false)));
130
+ katexEl.setAttribute('data-se-type', this.fontSizeElement.value);
131
+ katexEl.style.fontSize = this.fontSizeElement.value;
132
+
133
+ if (!this.isUpdateState) {
134
+ const selectedFormats = this.format.getLines();
135
+
136
+ if (selectedFormats.length > 1) {
137
+ const oFormat = domUtils.createElement(selectedFormats[0].nodeName, null, katexEl);
138
+ this.component.insert(oFormat, false, false);
139
+ } else {
140
+ this.component.insert(katexEl, false, false);
141
+ }
142
+ } else {
143
+ const containerEl = domUtils.getParentElement(this.controller.currentTarget, '.katex');
144
+ containerEl.parentNode.replaceChild(katexEl, containerEl);
145
+ const compInfo = this.component.get(katexEl);
146
+ this.component.select(compInfo.target, compInfo.pluginName, false);
147
+ }
148
+
149
+ return true;
150
+ },
151
+
152
+ /**
153
+ * @override modal
154
+ */
155
+ init() {
156
+ this.textArea.value = '';
157
+ this.previewElement.innerHTML = '';
158
+ },
159
+
160
+ /**
161
+ * @override controller
162
+ * @param {Element} target Target button element
163
+ * @returns
164
+ */
165
+ controllerAction(target) {
166
+ const command = target.getAttribute('data-command');
167
+ switch (command) {
168
+ case 'update':
169
+ this.modal.open();
170
+ break;
171
+ case 'copy':
172
+ copyTextToClipboard(this._element);
173
+ break;
174
+ case 'delete':
175
+ this.destroy(this.controller.currentTarget);
176
+ }
177
+ },
178
+
179
+ destroy(element) {
180
+ domUtils.removeItem(element);
181
+ this.controller.close();
182
+ this.editor.focus();
183
+ this.history.push(false);
184
+ },
185
+
186
+ _renderer(exp) {
187
+ let result = '';
188
+ try {
189
+ domUtils.removeClass(this.textArea, 'se-error');
190
+ result = this.katex.src.renderToString(exp, { throwOnError: true, displayMode: true });
191
+ } catch (error) {
192
+ domUtils.addClass(this.textArea, 'se-error');
193
+ result = '<span class="se-math-katex-error">Katex syntax error. (Refer <a href="' + env.KATEX_WEBSITE + '" target="_blank">KaTeX</a>)</span>';
194
+ console.warn('[SUNEDITOR.math.Katex.error] ', error.message);
195
+ }
196
+ return result;
197
+ },
198
+
199
+ _escapeBackslashes(str, decode) {
200
+ return str.replace(/\\{2}/g, decode ? '\\' : '\\\\');
201
+ },
202
+
203
+ constructor: Math_
204
+ };
205
+
206
+ async function copyTextToClipboard(element) {
207
+ if (!navigator.clipboard || !element) return;
208
+
209
+ try {
210
+ const text = getValue(element);
211
+ await navigator.clipboard.writeText(text);
212
+ domUtils.addClass(element, 'se-copy');
213
+ // copy effect
214
+ env._w.setTimeout(() => {
215
+ domUtils.removeClass(element, 'se-copy');
216
+ }, 120);
217
+ } catch (err) {
218
+ console.error('[SUNEDITOR.math.copy.fail]', err);
219
+ }
220
+ }
221
+
222
+ function RenderMathExp(e) {
223
+ this.previewElement.innerHTML = this._renderer(e.target.value);
224
+ }
225
+
226
+ function CheckKatex(katex) {
227
+ if (!katex) return null;
228
+ if (!katex.src) {
229
+ console.warn('[SUNEDITOR.math.katex.fail] The katex option is set incorrectly.');
230
+ return null;
231
+ }
232
+
233
+ const katexOptions = [
234
+ {
235
+ throwOnError: false
236
+ },
237
+ katex.options || {}
238
+ ].reduce((init, option) => {
239
+ for (const key in option) {
240
+ init[key] = option[key];
241
+ }
242
+ return init;
243
+ }, {});
244
+
245
+ katex.options = katexOptions;
246
+ return katex;
247
+ }
248
+
249
+ function CreateHTML_modal({ lang, icons }, math, fontSizeList) {
250
+ const fontSize = fontSizeList || [
251
+ {
252
+ text: '1',
253
+ value: '1em'
254
+ },
255
+ {
256
+ text: '1.5',
257
+ value: '1.5em'
258
+ },
259
+ {
260
+ text: '2',
261
+ value: '2em'
262
+ },
263
+ {
264
+ text: '2.5',
265
+ value: '2.5em'
266
+ }
267
+ ];
268
+ let defaultFontSize = fontSize[0].value;
269
+ let html = /*html*/ `
270
+ <form>
271
+ <div class="se-modal-header">
272
+ <button type="button" data-command="close" class="se-btn se-close-btn" title="${lang.close}" aria-label="${lang.close}">
273
+ ${icons.cancel}
274
+ </button>
275
+ <span class="se-modal-title">${lang.math_modal_title}</span>
276
+ </div>
277
+ <div class="se-modal-body">
278
+ <div class="se-modal-form">
279
+ <label>${lang.math_modal_inputLabel} (<a href="${env.KATEX_WEBSITE}" target="_blank">KaTeX</a>)</label>
280
+ <textarea class="se-input-form se-math-exp" type="text" data-focus></textarea>
281
+ </div>
282
+ <div class="se-modal-form">
283
+ <label>${lang.math_modal_fontSizeLabel}</label>
284
+ <select class="se-input-select se-math-size">`;
285
+
286
+ for (let i = 0, len = fontSize.length, f; i < len; i++) {
287
+ f = fontSize[i];
288
+ if (f.default) defaultFontSize = f.value;
289
+ html += /*html*/ `<option value="${f.value}"${f.default ? ' selected' : ''}>${f.text}</option>`;
290
+ }
291
+
292
+ html += /*html*/ `</select>
293
+ </div>
294
+ <div class="se-modal-form">
295
+ <label>${lang.math_modal_previewLabel}</label>
296
+ <p class="se-math-preview"></p>
297
+ </div>
298
+ </div>
299
+ <div class="se-modal-footer">
300
+ <button type="submit" class="se-btn-primary" title="${lang.submitButton}" aria-label="${lang.submitButton}">
301
+ <span>${lang.submitButton}</span>
302
+ </button>
303
+ </div>
304
+ </form>`;
305
+
306
+ math.defaultFontSize = defaultFontSize;
307
+ return domUtils.createElement('DIV', { class: 'se-modal-content' }, html);
308
+ }
309
+
310
+ function CreateHTML_controller({ lang, icons }) {
311
+ const html = /*html*/ `
312
+ <div class="se-arrow se-arrow-up"></div>
313
+ <div class="link-content">
314
+ <div class="se-btn-group">
315
+ <button type="button" data-command="update" tabindex="-1" class="se-btn se-tooltip">
316
+ ${icons.edit}
317
+ <span class="se-tooltip-inner">
318
+ <span class="se-tooltip-text">${lang.edit}</span>
319
+ </span>
320
+ </button>
321
+ <button type="button" data-command="copy" tabindex="-1" class="se-btn se-tooltip">
322
+ ${icons.copy}
323
+ <span class="se-tooltip-inner">
324
+ <span class="se-tooltip-text">${lang.copy}</span>
325
+ </span>
326
+ </button>
327
+ <button type="button" data-command="delete" tabindex="-1" class="se-btn se-tooltip">
328
+ ${icons.delete}
329
+ <span class="se-tooltip-inner">
330
+ <span class="se-tooltip-text">${lang.remove}</span>
331
+ </span>
332
+ </button>
333
+ </div>
334
+ </div>`;
335
+
336
+ return domUtils.createElement('DIV', { class: 'se-controller se-controller-link' }, html);
337
+ }
338
+
339
+ function getValue(element) {
340
+ return !element ? null : element.getAttribute('data-se-value');
341
+ }
342
+
343
+ function getType(element) {
344
+ return !element ? null : element?.getAttribute('data-se-type');
345
+ }
346
+
347
+ export default Math_;