suneditor 3.0.0-alpha.9 → 3.0.0-beta.2
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.
- package/CONTRIBUTING.md +170 -22
- package/{LICENSE.txt → LICENSE} +9 -9
- package/README.md +168 -30
- package/dist/suneditor.min.css +1 -1
- package/dist/suneditor.min.js +1 -1
- package/package.json +47 -21
- package/src/assets/design/color.css +121 -0
- package/src/assets/design/index.css +3 -0
- package/src/assets/design/size.css +35 -0
- package/src/assets/design/typography.css +37 -0
- package/src/assets/icons/defaultIcons.js +232 -0
- package/src/assets/suneditor-contents.css +181 -46
- package/src/assets/suneditor.css +1403 -650
- package/src/core/base/eventHandlers/handler_toolbar.js +35 -14
- package/src/core/base/eventHandlers/handler_ww_clipboard.js +23 -4
- package/src/core/base/eventHandlers/handler_ww_dragDrop.js +49 -10
- package/src/core/base/eventHandlers/handler_ww_key_input.js +422 -224
- package/src/core/base/eventHandlers/handler_ww_mouse.js +83 -36
- package/src/core/base/eventManager.js +520 -179
- package/src/core/base/history.js +95 -41
- package/src/core/class/char.js +26 -11
- package/src/core/class/component.js +345 -137
- package/src/core/class/format.js +683 -519
- package/src/core/class/html.js +485 -305
- package/src/core/class/menu.js +133 -47
- package/src/core/class/nodeTransform.js +90 -71
- package/src/core/class/offset.js +408 -92
- package/src/core/class/selection.js +216 -106
- package/src/core/class/shortcuts.js +68 -8
- package/src/core/class/toolbar.js +106 -116
- package/src/core/class/ui.js +422 -0
- package/src/core/class/viewer.js +178 -74
- package/src/core/editor.js +496 -389
- package/src/core/section/actives.js +123 -27
- package/src/core/section/constructor.js +615 -206
- package/src/core/section/context.js +28 -23
- package/src/core/section/documentType.js +561 -0
- package/src/editorInjector/_classes.js +19 -5
- package/src/editorInjector/_core.js +71 -7
- package/src/editorInjector/index.js +63 -1
- package/src/events.js +622 -0
- package/src/helper/clipboard.js +59 -0
- package/src/helper/converter.js +202 -26
- package/src/helper/dom/domCheck.js +304 -0
- package/src/helper/dom/domQuery.js +669 -0
- package/src/helper/dom/domUtils.js +557 -0
- package/src/helper/dom/index.js +12 -0
- package/src/helper/env.js +46 -56
- package/src/helper/index.js +10 -4
- package/src/helper/keyCodeMap.js +183 -0
- package/src/helper/numbers.js +12 -8
- package/src/helper/unicode.js +9 -5
- package/src/langs/ckb.js +74 -4
- package/src/langs/cs.js +72 -2
- package/src/langs/da.js +73 -3
- package/src/langs/de.js +73 -4
- package/src/langs/en.js +23 -3
- package/src/langs/es.js +73 -4
- package/src/langs/fa.js +75 -3
- package/src/langs/fr.js +73 -3
- package/src/langs/he.js +73 -4
- package/src/langs/hu.js +230 -0
- package/src/langs/index.js +7 -3
- package/src/langs/it.js +70 -1
- package/src/langs/ja.js +72 -4
- package/src/langs/km.js +230 -0
- package/src/langs/ko.js +22 -2
- package/src/langs/lv.js +74 -5
- package/src/langs/nl.js +73 -4
- package/src/langs/pl.js +73 -4
- package/src/langs/pt_br.js +70 -1
- package/src/langs/ro.js +74 -5
- package/src/langs/ru.js +73 -4
- package/src/langs/se.js +73 -4
- package/src/langs/tr.js +73 -1
- package/src/langs/{ua.js → uk.js} +75 -6
- package/src/langs/ur.js +77 -8
- package/src/langs/zh_cn.js +74 -5
- package/src/modules/ApiManager.js +77 -54
- package/src/modules/Browser.js +667 -0
- package/src/modules/ColorPicker.js +162 -102
- package/src/modules/Controller.js +273 -142
- package/src/modules/Figure.js +925 -484
- package/src/modules/FileManager.js +121 -69
- package/src/modules/HueSlider.js +113 -61
- package/src/modules/Modal.js +291 -122
- package/src/modules/ModalAnchorEditor.js +383 -234
- package/src/modules/SelectMenu.js +270 -168
- package/src/modules/_DragHandle.js +2 -1
- package/src/modules/index.js +3 -3
- package/src/plugins/browser/audioGallery.js +83 -0
- package/src/plugins/browser/fileBrowser.js +103 -0
- package/src/plugins/browser/fileGallery.js +83 -0
- package/src/plugins/browser/imageGallery.js +81 -0
- package/src/plugins/browser/videoGallery.js +103 -0
- package/src/plugins/command/blockquote.js +40 -27
- package/src/plugins/command/exportPDF.js +134 -0
- package/src/plugins/command/fileUpload.js +229 -162
- package/src/plugins/command/list_bulleted.js +83 -47
- package/src/plugins/command/list_numbered.js +83 -47
- package/src/plugins/dropdown/align.js +66 -54
- package/src/plugins/dropdown/backgroundColor.js +63 -49
- package/src/plugins/dropdown/font.js +71 -47
- package/src/plugins/dropdown/fontColor.js +63 -48
- package/src/plugins/dropdown/formatBlock.js +70 -33
- package/src/plugins/dropdown/hr.js +92 -51
- package/src/plugins/dropdown/layout.js +37 -26
- package/src/plugins/dropdown/lineHeight.js +54 -38
- package/src/plugins/dropdown/list.js +60 -45
- package/src/plugins/dropdown/paragraphStyle.js +51 -30
- package/src/plugins/dropdown/table.js +2003 -813
- package/src/plugins/dropdown/template.js +38 -26
- package/src/plugins/dropdown/textStyle.js +43 -31
- package/src/plugins/field/mention.js +147 -86
- package/src/plugins/index.js +32 -6
- package/src/plugins/input/fontSize.js +161 -108
- package/src/plugins/input/pageNavigator.js +70 -0
- package/src/plugins/modal/audio.js +358 -173
- package/src/plugins/modal/drawing.js +531 -0
- package/src/plugins/modal/embed.js +886 -0
- package/src/plugins/modal/image.js +674 -362
- package/src/plugins/modal/link.js +100 -71
- package/src/plugins/modal/math.js +367 -167
- package/src/plugins/modal/video.js +691 -335
- package/src/plugins/popup/anchor.js +222 -0
- package/src/suneditor.js +50 -13
- package/src/themes/dark.css +122 -0
- package/src/typedef.js +130 -0
- package/types/assets/icons/defaultIcons.d.ts +153 -0
- package/types/core/base/eventHandlers/handler_toolbar.d.ts +41 -0
- package/types/core/base/eventHandlers/handler_ww_clipboard.d.ts +40 -0
- package/types/core/base/eventHandlers/handler_ww_dragDrop.d.ts +35 -0
- package/types/core/base/eventHandlers/handler_ww_key_input.d.ts +45 -0
- package/types/core/base/eventHandlers/handler_ww_mouse.d.ts +39 -0
- package/types/core/base/eventManager.d.ts +385 -0
- package/types/core/base/history.d.ts +81 -0
- package/types/core/class/char.d.ts +60 -0
- package/types/core/class/component.d.ts +212 -0
- package/types/core/class/format.d.ts +616 -0
- package/types/core/class/html.d.ts +422 -0
- package/types/core/class/menu.d.ts +126 -0
- package/types/core/class/nodeTransform.d.ts +93 -0
- package/types/core/class/offset.d.ts +522 -0
- package/types/core/class/selection.d.ts +188 -0
- package/types/core/class/shortcuts.d.ts +142 -0
- package/types/core/class/toolbar.d.ts +189 -0
- package/types/core/class/ui.d.ts +164 -0
- package/types/core/class/viewer.d.ts +140 -0
- package/types/core/editor.d.ts +610 -0
- package/types/core/section/actives.d.ts +46 -0
- package/types/core/section/constructor.d.ts +777 -0
- package/types/core/section/context.d.ts +45 -0
- package/types/core/section/documentType.d.ts +178 -0
- package/types/editorInjector/_classes.d.ts +41 -0
- package/types/editorInjector/_core.d.ts +92 -0
- package/types/editorInjector/index.d.ts +71 -0
- package/types/events.d.ts +273 -0
- package/types/helper/clipboard.d.ts +12 -0
- package/types/helper/converter.d.ts +197 -0
- package/types/helper/dom/domCheck.d.ts +189 -0
- package/types/helper/dom/domQuery.d.ts +223 -0
- package/types/helper/dom/domUtils.d.ts +226 -0
- package/types/helper/dom/index.d.ts +9 -0
- package/types/helper/env.d.ts +132 -0
- package/types/helper/index.d.ts +174 -0
- package/types/helper/keyCodeMap.d.ts +110 -0
- package/types/helper/numbers.d.ts +46 -0
- package/types/helper/unicode.d.ts +28 -0
- package/types/index.d.ts +120 -0
- package/{typings/Lang.d.ts → types/langs/_Lang.d.ts} +173 -103
- package/types/langs/ckb.d.ts +3 -0
- package/types/langs/cs.d.ts +3 -0
- package/types/langs/da.d.ts +3 -0
- package/types/langs/de.d.ts +3 -0
- package/types/langs/en.d.ts +3 -0
- package/types/langs/es.d.ts +3 -0
- package/types/langs/fa.d.ts +3 -0
- package/types/langs/fr.d.ts +3 -0
- package/types/langs/he.d.ts +3 -0
- package/types/langs/hu.d.ts +3 -0
- package/types/langs/index.d.ts +54 -0
- package/types/langs/it.d.ts +3 -0
- package/types/langs/ja.d.ts +3 -0
- package/types/langs/km.d.ts +3 -0
- package/types/langs/ko.d.ts +3 -0
- package/types/langs/lv.d.ts +3 -0
- package/types/langs/nl.d.ts +3 -0
- package/types/langs/pl.d.ts +3 -0
- package/types/langs/pt_br.d.ts +3 -0
- package/types/langs/ro.d.ts +3 -0
- package/types/langs/ru.d.ts +3 -0
- package/types/langs/se.d.ts +3 -0
- package/types/langs/tr.d.ts +3 -0
- package/types/langs/uk.d.ts +3 -0
- package/types/langs/ur.d.ts +3 -0
- package/types/langs/zh_cn.d.ts +3 -0
- package/types/modules/ApiManager.d.ts +125 -0
- package/types/modules/Browser.d.ts +326 -0
- package/types/modules/ColorPicker.d.ts +131 -0
- package/types/modules/Controller.d.ts +251 -0
- package/types/modules/Figure.d.ts +517 -0
- package/types/modules/FileManager.d.ts +202 -0
- package/types/modules/HueSlider.d.ts +136 -0
- package/types/modules/Modal.d.ts +111 -0
- package/types/modules/ModalAnchorEditor.d.ts +236 -0
- package/types/modules/SelectMenu.d.ts +194 -0
- package/types/modules/_DragHandle.d.ts +7 -0
- package/types/modules/index.d.ts +26 -0
- package/types/plugins/browser/audioGallery.d.ts +55 -0
- package/types/plugins/browser/fileBrowser.d.ts +64 -0
- package/types/plugins/browser/fileGallery.d.ts +55 -0
- package/types/plugins/browser/imageGallery.d.ts +51 -0
- package/types/plugins/browser/videoGallery.d.ts +57 -0
- package/types/plugins/command/blockquote.d.ts +28 -0
- package/types/plugins/command/exportPDF.d.ts +46 -0
- package/types/plugins/command/fileUpload.d.ts +156 -0
- package/types/plugins/command/list_bulleted.d.ts +46 -0
- package/types/plugins/command/list_numbered.d.ts +46 -0
- package/types/plugins/dropdown/align.d.ts +60 -0
- package/types/plugins/dropdown/backgroundColor.d.ts +63 -0
- package/types/plugins/dropdown/font.d.ts +54 -0
- package/types/plugins/dropdown/fontColor.d.ts +63 -0
- package/types/plugins/dropdown/formatBlock.d.ts +54 -0
- package/types/plugins/dropdown/hr.d.ts +71 -0
- package/types/plugins/dropdown/layout.d.ts +40 -0
- package/types/plugins/dropdown/lineHeight.d.ts +50 -0
- package/types/plugins/dropdown/list.d.ts +39 -0
- package/types/plugins/dropdown/paragraphStyle.d.ts +54 -0
- package/types/plugins/dropdown/table.d.ts +627 -0
- package/types/plugins/dropdown/template.d.ts +40 -0
- package/types/plugins/dropdown/textStyle.d.ts +41 -0
- package/types/plugins/field/mention.d.ts +102 -0
- package/types/plugins/index.d.ts +107 -0
- package/types/plugins/input/fontSize.d.ts +170 -0
- package/types/plugins/input/pageNavigator.d.ts +28 -0
- package/types/plugins/modal/audio.d.ts +269 -0
- package/types/plugins/modal/drawing.d.ts +246 -0
- package/types/plugins/modal/embed.d.ts +387 -0
- package/types/plugins/modal/image.d.ts +451 -0
- package/types/plugins/modal/link.d.ts +128 -0
- package/types/plugins/modal/math.d.ts +193 -0
- package/types/plugins/modal/video.d.ts +485 -0
- package/types/plugins/popup/anchor.d.ts +56 -0
- package/types/suneditor.d.ts +51 -0
- package/types/typedef.d.ts +233 -0
- package/.eslintignore +0 -7
- package/.eslintrc.json +0 -64
- package/src/assets/icons/_default.js +0 -194
- package/src/core/base/events.js +0 -320
- package/src/core/class/notice.js +0 -42
- package/src/helper/domUtils.js +0 -1177
- package/src/modules/FileBrowser.js +0 -271
- package/src/plugins/command/exportPdf.js +0 -168
- package/src/plugins/fileBrowser/imageGallery.js +0 -81
- package/src/themes/test.css +0 -61
- package/typings/CommandPlugin.d.ts +0 -8
- package/typings/DialogPlugin.d.ts +0 -20
- package/typings/FileBrowserPlugin.d.ts +0 -30
- package/typings/Module.d.ts +0 -15
- package/typings/Plugin.d.ts +0 -42
- package/typings/SubmenuPlugin.d.ts +0 -8
- package/typings/_classes.d.ts +0 -17
- package/typings/_colorPicker.d.ts +0 -60
- package/typings/_core.d.ts +0 -55
- package/typings/align.d.ts +0 -5
- package/typings/audio.d.ts +0 -5
- package/typings/backgroundColor.d.ts +0 -5
- package/typings/blockquote.d.ts +0 -5
- package/typings/char.d.ts +0 -39
- package/typings/component.d.ts +0 -38
- package/typings/context.d.ts +0 -39
- package/typings/converter.d.ts +0 -33
- package/typings/dialog.d.ts +0 -28
- package/typings/domUtils.d.ts +0 -361
- package/typings/editor.d.ts +0 -7
- package/typings/editor.ts +0 -542
- package/typings/env.d.ts +0 -70
- package/typings/eventManager.d.ts +0 -37
- package/typings/events.d.ts +0 -262
- package/typings/fileBrowser.d.ts +0 -42
- package/typings/fileManager.d.ts +0 -67
- package/typings/font.d.ts +0 -5
- package/typings/fontColor.d.ts +0 -5
- package/typings/fontSize.d.ts +0 -5
- package/typings/format.d.ts +0 -191
- package/typings/formatBlock.d.ts +0 -5
- package/typings/history.d.ts +0 -48
- package/typings/horizontalRule.d.ts +0 -5
- package/typings/image.d.ts +0 -5
- package/typings/imageGallery.d.ts +0 -5
- package/typings/index.d.ts +0 -21
- package/typings/index.modules.d.ts +0 -11
- package/typings/index.plugins.d.ts +0 -58
- package/typings/lineHeight.d.ts +0 -5
- package/typings/link.d.ts +0 -5
- package/typings/list.d.ts +0 -5
- package/typings/math.d.ts +0 -5
- package/typings/mediaContainer.d.ts +0 -25
- package/typings/mention.d.ts +0 -5
- package/typings/node.d.ts +0 -57
- package/typings/notice.d.ts +0 -16
- package/typings/numbers.d.ts +0 -29
- package/typings/offset.d.ts +0 -24
- package/typings/options.d.ts +0 -589
- package/typings/paragraphStyle.d.ts +0 -5
- package/typings/resizing.d.ts +0 -141
- package/typings/selection.d.ts +0 -94
- package/typings/shortcuts.d.ts +0 -13
- package/typings/suneditor.d.ts +0 -9
- package/typings/table.d.ts +0 -5
- package/typings/template.d.ts +0 -5
- package/typings/textStyle.d.ts +0 -5
- package/typings/toolbar.d.ts +0 -32
- package/typings/unicode.d.ts +0 -25
- package/typings/video.d.ts +0 -5
package/src/core/class/format.js
CHANGED
|
@@ -3,26 +3,47 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import CoreInjector from '../../editorInjector/_core';
|
|
6
|
-
import {
|
|
6
|
+
import { dom, unicode, numbers, converter } from '../../helper';
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
|
+
* @typedef {Omit<Format & Partial<__se__EditorInjector>, 'format'>} FormatThis
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @typedef {Object} NodeStyleContainerType
|
|
14
|
+
* @property {?Node=} ancestor
|
|
15
|
+
* @property {?number=} offset
|
|
16
|
+
* @property {?Node=} container
|
|
17
|
+
* @property {?Node=} endContainer
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @constructor
|
|
22
|
+
* @this {FormatThis}
|
|
23
|
+
* @description Classes related to editor formats such as line creation, line retrieval from selected range, etc.
|
|
24
|
+
* @param {__se__EditorCore} editor - The root editor instance
|
|
25
|
+
*/
|
|
26
|
+
function Format(editor) {
|
|
9
27
|
CoreInjector.call(this, editor);
|
|
10
28
|
|
|
11
29
|
// members
|
|
12
30
|
this._listCamel = this.options.get('__listCommonStyle');
|
|
13
|
-
this._listKebab =
|
|
31
|
+
this._listKebab = converter.camelToKebabCase(this.options.get('__listCommonStyle'));
|
|
14
32
|
this._formatLineCheck = this.options.get('formatLine').reg;
|
|
15
33
|
this._formatBrLineCheck = this.options.get('formatBrLine').reg;
|
|
16
34
|
this._formatBlockCheck = this.options.get('formatBlock').reg;
|
|
17
35
|
this._formatClosureBlockCheck = this.options.get('formatClosureBlock').reg;
|
|
18
36
|
this._formatClosureBrLineCheck = this.options.get('formatClosureBrLine').reg;
|
|
19
37
|
this._textStyleTagsCheck = new RegExp('^(' + this.options.get('textStyleTags') + ')$', 'i');
|
|
20
|
-
|
|
38
|
+
// members - _defaultBrLineBreak
|
|
39
|
+
this._brLineBreak = this.options.get('_defaultBrLineBreak');
|
|
40
|
+
}
|
|
21
41
|
|
|
22
42
|
Format.prototype = {
|
|
23
43
|
/**
|
|
44
|
+
* @this {FormatThis}
|
|
24
45
|
* @description Replace the line tag of the current selection.
|
|
25
|
-
* @param {
|
|
46
|
+
* @param {Node} element Line element (P, DIV..)
|
|
26
47
|
*/
|
|
27
48
|
setLine(element) {
|
|
28
49
|
if (!this.isLine(element)) {
|
|
@@ -40,8 +61,8 @@ Format.prototype = {
|
|
|
40
61
|
node = lines[i];
|
|
41
62
|
|
|
42
63
|
if ((node.nodeName !== value || (node.className.match(/(\s|^)__se__format__[^\s]+/) || [''])[0].trim() !== className) && !this.component.is(node)) {
|
|
43
|
-
newFormat = element.cloneNode(false);
|
|
44
|
-
|
|
64
|
+
newFormat = /** @type {HTMLElement} */ (element.cloneNode(false));
|
|
65
|
+
dom.utils.copyFormatAttributes(newFormat, node);
|
|
45
66
|
newFormat.innerHTML = node.innerHTML;
|
|
46
67
|
|
|
47
68
|
node.parentNode.replaceChild(newFormat, node);
|
|
@@ -52,15 +73,21 @@ Format.prototype = {
|
|
|
52
73
|
newFormat = null;
|
|
53
74
|
}
|
|
54
75
|
|
|
55
|
-
this.selection.setRange(
|
|
76
|
+
this.selection.setRange(dom.query.getNodeFromPath(info.firstPath, first), info.startOffset, dom.query.getNodeFromPath(info.lastPath, last), info.endOffset);
|
|
56
77
|
this.history.push(false);
|
|
78
|
+
|
|
79
|
+
// document type
|
|
80
|
+
if (this.editor.frameContext.has('documentType-use-header')) {
|
|
81
|
+
this.editor.frameContext.get('documentType').reHeader();
|
|
82
|
+
}
|
|
57
83
|
},
|
|
58
84
|
|
|
59
85
|
/**
|
|
86
|
+
* @this {FormatThis}
|
|
60
87
|
* @description If a parent node that contains an argument node finds a format node (format.isLine), it returns that node.
|
|
61
88
|
* @param {Node} node Reference node.
|
|
62
|
-
* @param {
|
|
63
|
-
* @returns {
|
|
89
|
+
* @param {?(current: Node) => boolean=} validation Additional validation function.
|
|
90
|
+
* @returns {HTMLElement|null}
|
|
64
91
|
*/
|
|
65
92
|
getLine(node, validation) {
|
|
66
93
|
if (!node) return null;
|
|
@@ -71,9 +98,9 @@ Format.prototype = {
|
|
|
71
98
|
}
|
|
72
99
|
|
|
73
100
|
while (node) {
|
|
74
|
-
if (
|
|
75
|
-
if (this.isBlock(node)) return node.firstElementChild;
|
|
76
|
-
if (this.isLine(node) && validation(node)) return node;
|
|
101
|
+
if (dom.check.isWysiwygFrame(node)) return null;
|
|
102
|
+
if (this.isBlock(node)) return /** @type {HTMLElement} */ (node.firstElementChild);
|
|
103
|
+
if (this.isLine(node) && validation(node)) return /** @type {HTMLElement} */ (node);
|
|
77
104
|
|
|
78
105
|
node = node.parentNode;
|
|
79
106
|
}
|
|
@@ -82,8 +109,9 @@ Format.prototype = {
|
|
|
82
109
|
},
|
|
83
110
|
|
|
84
111
|
/**
|
|
112
|
+
* @this {FormatThis}
|
|
85
113
|
* @description Replace the br-line tag of the current selection.
|
|
86
|
-
* @param {
|
|
114
|
+
* @param {Node} element BR-Line element (PRE..)
|
|
87
115
|
*/
|
|
88
116
|
setBrLine(element) {
|
|
89
117
|
if (!this.isBrLine(element)) {
|
|
@@ -93,7 +121,7 @@ Format.prototype = {
|
|
|
93
121
|
const lines = this._lineWork().lines;
|
|
94
122
|
const len = lines.length - 1;
|
|
95
123
|
let parentNode = lines[len].parentNode;
|
|
96
|
-
let freeElement = element.cloneNode(false);
|
|
124
|
+
let freeElement = /** @type {HTMLElement} */ (element.cloneNode(false));
|
|
97
125
|
const focusElement = freeElement;
|
|
98
126
|
|
|
99
127
|
for (let i = len, f, html, before, next, inner, isComp, first = true; i >= 0; i--) {
|
|
@@ -102,7 +130,7 @@ Format.prototype = {
|
|
|
102
130
|
|
|
103
131
|
isComp = this.component.is(f);
|
|
104
132
|
html = isComp ? '' : f.innerHTML.replace(/(?!>)\s+(?=<)|\n/g, ' ');
|
|
105
|
-
before =
|
|
133
|
+
before = dom.query.getParentElement(f, (current) => current.parentNode === parentNode);
|
|
106
134
|
|
|
107
135
|
if (parentNode !== f.parentNode || isComp) {
|
|
108
136
|
if (this.isLine(parentNode)) {
|
|
@@ -113,13 +141,13 @@ Format.prototype = {
|
|
|
113
141
|
parentNode = f.parentNode;
|
|
114
142
|
}
|
|
115
143
|
|
|
116
|
-
next = freeElement.nextSibling;
|
|
117
|
-
if (next && freeElement.nodeName === next.nodeName &&
|
|
144
|
+
next = /** @type {HTMLElement} */ (freeElement.nextSibling);
|
|
145
|
+
if (next && freeElement.nodeName === next.nodeName && dom.check.isSameAttributes(freeElement, next)) {
|
|
118
146
|
freeElement.innerHTML += '<BR>' + next.innerHTML;
|
|
119
|
-
|
|
147
|
+
dom.utils.removeItem(next);
|
|
120
148
|
}
|
|
121
149
|
|
|
122
|
-
freeElement = element.cloneNode(false);
|
|
150
|
+
freeElement = /** @type {HTMLElement} */ (element.cloneNode(false));
|
|
123
151
|
first = true;
|
|
124
152
|
}
|
|
125
153
|
|
|
@@ -128,20 +156,20 @@ Format.prototype = {
|
|
|
128
156
|
|
|
129
157
|
if (i === 0) {
|
|
130
158
|
parentNode.insertBefore(freeElement, f);
|
|
131
|
-
next = f.nextSibling;
|
|
132
|
-
if (next && freeElement.nodeName === next.nodeName &&
|
|
159
|
+
next = /** @type {HTMLElement} */ (f.nextSibling);
|
|
160
|
+
if (next && freeElement.nodeName === next.nodeName && dom.check.isSameAttributes(freeElement, next)) {
|
|
133
161
|
freeElement.innerHTML += '<BR>' + next.innerHTML;
|
|
134
|
-
|
|
162
|
+
dom.utils.removeItem(next);
|
|
135
163
|
}
|
|
136
164
|
|
|
137
|
-
const prev = freeElement.previousSibling;
|
|
138
|
-
if (prev && freeElement.nodeName === prev.nodeName &&
|
|
165
|
+
const prev = /** @type {HTMLElement} */ (freeElement.previousSibling);
|
|
166
|
+
if (prev && freeElement.nodeName === prev.nodeName && dom.check.isSameAttributes(freeElement, prev)) {
|
|
139
167
|
prev.innerHTML += '<BR>' + freeElement.innerHTML;
|
|
140
|
-
|
|
168
|
+
dom.utils.removeItem(freeElement);
|
|
141
169
|
}
|
|
142
170
|
}
|
|
143
171
|
|
|
144
|
-
if (!isComp)
|
|
172
|
+
if (!isComp) dom.utils.removeItem(f);
|
|
145
173
|
if (html) first = false;
|
|
146
174
|
}
|
|
147
175
|
|
|
@@ -150,10 +178,11 @@ Format.prototype = {
|
|
|
150
178
|
},
|
|
151
179
|
|
|
152
180
|
/**
|
|
153
|
-
* @
|
|
181
|
+
* @this {FormatThis}
|
|
182
|
+
* @description If a parent node that contains an argument node finds a "brLine" (format.isBrLine), it returns that node.
|
|
154
183
|
* @param {Node} element Reference node.
|
|
155
|
-
* @param {
|
|
156
|
-
* @returns {
|
|
184
|
+
* @param {?(current: Node) => boolean=} validation Additional validation function.
|
|
185
|
+
* @returns {HTMLBRElement|null}
|
|
157
186
|
*/
|
|
158
187
|
getBrLine(element, validation) {
|
|
159
188
|
if (!element) return null;
|
|
@@ -164,8 +193,8 @@ Format.prototype = {
|
|
|
164
193
|
}
|
|
165
194
|
|
|
166
195
|
while (element) {
|
|
167
|
-
if (
|
|
168
|
-
if (this.isBrLine(element) && validation(element)) return element;
|
|
196
|
+
if (dom.check.isWysiwygFrame(element)) return null;
|
|
197
|
+
if (this.isBrLine(element) && validation(element)) return /** @type {HTMLBRElement} */ (element);
|
|
169
198
|
|
|
170
199
|
element = element.parentNode;
|
|
171
200
|
}
|
|
@@ -174,45 +203,41 @@ Format.prototype = {
|
|
|
174
203
|
},
|
|
175
204
|
|
|
176
205
|
/**
|
|
177
|
-
* @
|
|
178
|
-
*
|
|
179
|
-
* If
|
|
180
|
-
*
|
|
181
|
-
* @param {
|
|
182
|
-
* @
|
|
206
|
+
* @this {FormatThis}
|
|
207
|
+
* @description Append "line" element to sibling node of argument element.
|
|
208
|
+
* - If the "lineNode" argument value is present, the tag of that argument value is inserted,
|
|
209
|
+
* - If not, the currently selected format tag is inserted.
|
|
210
|
+
* @param {Node} element Insert as siblings of that element
|
|
211
|
+
* @param {?string|Node=} lineNode Node name or node obejct to be inserted
|
|
212
|
+
* @returns {HTMLElement}
|
|
183
213
|
*/
|
|
184
214
|
addLine(element, lineNode) {
|
|
185
215
|
if (!element || !element.parentNode) return null;
|
|
186
216
|
|
|
187
217
|
const currentFormatEl = this.getLine(this.selection.getNode(), null);
|
|
188
218
|
let oFormat = null;
|
|
189
|
-
if (!this.isBrLine(element) && this.isBrLine(currentFormatEl || element.parentNode)) {
|
|
190
|
-
oFormat =
|
|
219
|
+
if (!this.isBrLine(element) && this.isBrLine(currentFormatEl || element.parentNode) && !this.component.is(element)) {
|
|
220
|
+
oFormat = dom.utils.createElement('BR');
|
|
191
221
|
} else {
|
|
192
|
-
const oFormatName = lineNode
|
|
193
|
-
|
|
194
|
-
? lineNode
|
|
195
|
-
: lineNode.nodeName
|
|
196
|
-
: this.isLine(currentFormatEl) && !this.isBlock(currentFormatEl) && !this.isBrLine(currentFormatEl)
|
|
197
|
-
? currentFormatEl.nodeName
|
|
198
|
-
: this.options.get('defaultLine');
|
|
199
|
-
oFormat = domUtils.createElement(oFormatName, null, '<br>');
|
|
222
|
+
const oFormatName = lineNode ? (typeof lineNode === 'string' ? lineNode : lineNode.nodeName) : this.isLineOnly(currentFormatEl) ? currentFormatEl.nodeName : this.options.get('defaultLine');
|
|
223
|
+
oFormat = dom.utils.createElement(oFormatName, null, '<br>');
|
|
200
224
|
if ((lineNode && typeof lineNode !== 'string') || (!lineNode && this.isLine(currentFormatEl))) {
|
|
201
|
-
|
|
225
|
+
dom.utils.copyTagAttributes(oFormat, /** @type {Node} */ (lineNode || currentFormatEl), ['id']);
|
|
202
226
|
}
|
|
203
227
|
}
|
|
204
228
|
|
|
205
|
-
if (
|
|
206
|
-
else element.parentNode.insertBefore(oFormat, element.nextElementSibling);
|
|
229
|
+
if (dom.check.isTableCell(element)) element.insertBefore(oFormat, element.nextElementSibling);
|
|
230
|
+
else element.parentNode.insertBefore(oFormat, /** @type {HTMLElement} */ (element).nextElementSibling);
|
|
207
231
|
|
|
208
232
|
return oFormat;
|
|
209
233
|
},
|
|
210
234
|
|
|
211
235
|
/**
|
|
236
|
+
* @this {FormatThis}
|
|
212
237
|
* @description If a parent node that contains an argument node finds a format node (format.isBlock), it returns that node.
|
|
213
238
|
* @param {Node} element Reference node.
|
|
214
|
-
* @param {
|
|
215
|
-
* @returns {
|
|
239
|
+
* @param {?(current: Node) => boolean=} validation Additional validation function.
|
|
240
|
+
* @returns {HTMLElement|null}
|
|
216
241
|
*/
|
|
217
242
|
getBlock(element, validation) {
|
|
218
243
|
if (!element) return null;
|
|
@@ -223,7 +248,7 @@ Format.prototype = {
|
|
|
223
248
|
}
|
|
224
249
|
|
|
225
250
|
while (element) {
|
|
226
|
-
if (
|
|
251
|
+
if (dom.check.isWysiwygFrame(element)) return null;
|
|
227
252
|
if (this.isBlock(element) && !/^(THEAD|TBODY|TR)$/i.test(element.nodeName) && validation(element)) return element;
|
|
228
253
|
element = element.parentNode;
|
|
229
254
|
}
|
|
@@ -232,25 +257,26 @@ Format.prototype = {
|
|
|
232
257
|
},
|
|
233
258
|
|
|
234
259
|
/**
|
|
235
|
-
* @
|
|
236
|
-
* @
|
|
260
|
+
* @this {FormatThis}
|
|
261
|
+
* @description Appended all selected "line" element to the argument element("block") and insert
|
|
262
|
+
* @param {Node} blockElement Element of wrap the arguments (BLOCKQUOTE...)
|
|
237
263
|
*/
|
|
238
|
-
applyBlock(
|
|
264
|
+
applyBlock(blockElement) {
|
|
239
265
|
this.selection.getRangeAndAddLine(this.selection.getRange(), null);
|
|
240
|
-
const rangeLines = this.getLinesAndComponents(false);
|
|
266
|
+
const rangeLines = /** @type {Element[]} */ (this.getLinesAndComponents(false));
|
|
241
267
|
if (!rangeLines || rangeLines.length === 0) return;
|
|
242
268
|
|
|
243
269
|
linesLoop: for (let i = 0, len = rangeLines.length, line, nested, fEl, lEl, f, l; i < len; i++) {
|
|
244
270
|
line = rangeLines[i];
|
|
245
|
-
if (!
|
|
271
|
+
if (!dom.check.isListCell(line)) continue;
|
|
246
272
|
|
|
247
273
|
nested = line.lastElementChild;
|
|
248
|
-
if (nested &&
|
|
274
|
+
if (nested && dom.check.isListCell(line.nextElementSibling) && rangeLines.includes(line.nextElementSibling)) {
|
|
249
275
|
lEl = nested.lastElementChild;
|
|
250
276
|
if (rangeLines.includes(lEl)) {
|
|
251
277
|
let list = null;
|
|
252
278
|
while ((list = lEl.lastElementChild)) {
|
|
253
|
-
if (
|
|
279
|
+
if (dom.check.isList(list)) {
|
|
254
280
|
if (rangeLines.includes(list.lastElementChild)) {
|
|
255
281
|
lEl = list.lastElementChild;
|
|
256
282
|
} else {
|
|
@@ -278,7 +304,7 @@ Format.prototype = {
|
|
|
278
304
|
standTag = this.getBlock(last, null) || this.getLine(last, null);
|
|
279
305
|
}
|
|
280
306
|
|
|
281
|
-
if (
|
|
307
|
+
if (dom.check.isTableCell(standTag)) {
|
|
282
308
|
beforeTag = null;
|
|
283
309
|
pElement = standTag;
|
|
284
310
|
} else {
|
|
@@ -286,14 +312,14 @@ Format.prototype = {
|
|
|
286
312
|
pElement = standTag.parentNode;
|
|
287
313
|
}
|
|
288
314
|
|
|
289
|
-
block =
|
|
290
|
-
let parentDepth =
|
|
315
|
+
const block = /** @type {HTMLElement} */ (blockElement.cloneNode(false));
|
|
316
|
+
let parentDepth = dom.query.getNodeDepth(standTag);
|
|
291
317
|
let listParent = null;
|
|
292
318
|
const lineArr = [];
|
|
293
319
|
const removeItems = (parent, origin, before) => {
|
|
294
320
|
let cc = null;
|
|
295
|
-
if (parent !== origin && !
|
|
296
|
-
if (origin &&
|
|
321
|
+
if (parent !== origin && !dom.check.isTableElements(origin)) {
|
|
322
|
+
if (origin && dom.query.getNodeDepth(parent) === dom.query.getNodeDepth(origin)) return before;
|
|
297
323
|
cc = this.nodeTransform.removeAllParents(origin, null, parent);
|
|
298
324
|
}
|
|
299
325
|
|
|
@@ -305,9 +331,9 @@ Format.prototype = {
|
|
|
305
331
|
originParent = line.parentNode;
|
|
306
332
|
if (!originParent || block.contains(originParent)) continue;
|
|
307
333
|
|
|
308
|
-
depth =
|
|
334
|
+
depth = dom.query.getNodeDepth(line);
|
|
309
335
|
|
|
310
|
-
if (
|
|
336
|
+
if (dom.check.isList(originParent)) {
|
|
311
337
|
if (listParent === null) {
|
|
312
338
|
if (nextList) {
|
|
313
339
|
listParent = nextList;
|
|
@@ -329,14 +355,14 @@ Format.prototype = {
|
|
|
329
355
|
|
|
330
356
|
let list = originParent.parentNode,
|
|
331
357
|
p;
|
|
332
|
-
while (
|
|
333
|
-
p =
|
|
358
|
+
while (dom.check.isList(list)) {
|
|
359
|
+
p = dom.utils.createElement(list.nodeName);
|
|
334
360
|
p.appendChild(listParent);
|
|
335
361
|
listParent = p;
|
|
336
362
|
list = list.parentNode;
|
|
337
363
|
}
|
|
338
364
|
|
|
339
|
-
const edge = this.removeBlock(originParent, lineArr, null, true, true);
|
|
365
|
+
const edge = this.removeBlock(originParent, { selectedFormats: lineArr, newBlockElement: null, shouldDelete: true, skipHistory: true });
|
|
340
366
|
|
|
341
367
|
if (parentDepth >= depth) {
|
|
342
368
|
parentDepth = depth;
|
|
@@ -380,12 +406,12 @@ Format.prototype = {
|
|
|
380
406
|
|
|
381
407
|
this.editor.effectNode = null;
|
|
382
408
|
this.nodeTransform.mergeSameTags(block, null, false);
|
|
383
|
-
this.nodeTransform.mergeNestedTags(block, (current) =>
|
|
409
|
+
this.nodeTransform.mergeNestedTags(block, (current) => dom.check.isList(current));
|
|
384
410
|
|
|
385
411
|
// Nested list
|
|
386
|
-
if (beforeTag &&
|
|
387
|
-
const depthFormat =
|
|
388
|
-
const splitRange = this.nodeTransform.split(beforeTag, null, !depthFormat ? 0 :
|
|
412
|
+
if (beforeTag && dom.query.getNodeDepth(beforeTag) > 0 && (dom.check.isList(beforeTag.parentNode) || dom.check.isList(beforeTag.parentNode.parentNode))) {
|
|
413
|
+
const depthFormat = dom.query.getParentElement(beforeTag, (current) => this.isBlock(current) && !dom.check.isList(current));
|
|
414
|
+
const splitRange = this.nodeTransform.split(beforeTag, null, !depthFormat ? 0 : dom.query.getNodeDepth(depthFormat) + 1);
|
|
389
415
|
splitRange.parentNode.insertBefore(block, splitRange);
|
|
390
416
|
} else {
|
|
391
417
|
// basic
|
|
@@ -393,7 +419,7 @@ Format.prototype = {
|
|
|
393
419
|
removeItems(block, beforeTag);
|
|
394
420
|
}
|
|
395
421
|
|
|
396
|
-
const edge =
|
|
422
|
+
const edge = dom.query.getEdgeChildNodes(block.firstElementChild, block.lastElementChild);
|
|
397
423
|
if (rangeLines.length > 1) {
|
|
398
424
|
this.selection.setRange(edge.sc, 0, edge.ec, edge.ec.textContent.length);
|
|
399
425
|
} else {
|
|
@@ -404,35 +430,43 @@ Format.prototype = {
|
|
|
404
430
|
},
|
|
405
431
|
|
|
406
432
|
/**
|
|
407
|
-
* @
|
|
408
|
-
*
|
|
409
|
-
*
|
|
410
|
-
* @param {
|
|
411
|
-
*
|
|
412
|
-
* @param {
|
|
413
|
-
*
|
|
414
|
-
* @param {
|
|
415
|
-
* @
|
|
433
|
+
* @this {FormatThis}
|
|
434
|
+
* @description The elements of the "selectedFormats" array are detached from the "blockElement" element. ("LI" tags are converted to "P" tags)
|
|
435
|
+
* - When "selectedFormats" is null, all elements are detached and return {cc: parentNode, sc: nextSibling, ec: previousSibling, removeArray: [Array of removed elements]}.
|
|
436
|
+
* @param {Node} blockElement "block" element (PRE, BLOCKQUOTE, OL, UL...)
|
|
437
|
+
* @param {Object} [options] Options
|
|
438
|
+
* @param {Array<Node>} [options.selectedFormats=null] Array of "line" elements (P, DIV, LI...) to remove.
|
|
439
|
+
* - If null, Applies to all elements and return {cc: parentNode, sc: nextSibling, ec: previousSibling}
|
|
440
|
+
* @param {Node} [options.newBlockElement=null] The node(blockElement) to replace the currently wrapped node.
|
|
441
|
+
* @param {boolean} [options.shouldDelete=false] If true, deleted without detached.
|
|
442
|
+
* @param {boolean} [options.skipHistory=false] When true, it does not update the history stack and the selection object and return EdgeNodes (dom-query-GetEdgeChildNodes)
|
|
443
|
+
* @returns {{cc: Node, sc: Node, so: number, ec: Node, eo: number, removeArray: Array<Node>|null}} Node information after deletion
|
|
444
|
+
* - cc: Common parent container node
|
|
445
|
+
* - sc: Start container node
|
|
446
|
+
* - so: Start offset
|
|
447
|
+
* - ec: End container node
|
|
448
|
+
* - eo: End offset
|
|
449
|
+
* - removeArray: Array of removed elements
|
|
416
450
|
*/
|
|
417
|
-
removeBlock(
|
|
451
|
+
removeBlock(blockElement, { selectedFormats, newBlockElement, shouldDelete, skipHistory } = {}) {
|
|
418
452
|
const range = this.selection.getRange();
|
|
419
453
|
let so = range.startOffset;
|
|
420
454
|
let eo = range.endOffset;
|
|
421
455
|
|
|
422
|
-
let children =
|
|
423
|
-
let parent =
|
|
456
|
+
let children = dom.query.getListChildNodes(blockElement, (current) => current.parentNode === blockElement);
|
|
457
|
+
let parent = blockElement.parentNode;
|
|
424
458
|
let firstNode = null;
|
|
425
459
|
let lastNode = null;
|
|
426
|
-
let rangeEl =
|
|
460
|
+
let rangeEl = /** @type {HTMLElement} */ (blockElement.cloneNode(false));
|
|
427
461
|
|
|
428
462
|
const removeArray = [];
|
|
429
|
-
const newList =
|
|
463
|
+
const newList = dom.check.isList(newBlockElement);
|
|
430
464
|
let insertedNew = false;
|
|
431
465
|
let reset = false;
|
|
432
466
|
let moveComplete = false;
|
|
433
467
|
|
|
434
468
|
const appendNode = (parentEl, insNode, sibling, originNode) => {
|
|
435
|
-
if (
|
|
469
|
+
if (dom.check.isZeroWidth(insNode)) {
|
|
436
470
|
insNode.innerHTML = unicode.zeroWidthSpace;
|
|
437
471
|
so = eo = 1;
|
|
438
472
|
}
|
|
@@ -449,7 +483,7 @@ Format.prototype = {
|
|
|
449
483
|
|
|
450
484
|
while (insChildren[0]) {
|
|
451
485
|
c = insChildren[0];
|
|
452
|
-
if (this._notTextNode(c) && !
|
|
486
|
+
if (this._notTextNode(c) && !dom.check.isBreak(c) && !dom.check.isListCell(format)) {
|
|
453
487
|
if (format.childNodes.length > 0) {
|
|
454
488
|
if (!first) first = format;
|
|
455
489
|
parentEl.insertBefore(format, sibling);
|
|
@@ -463,7 +497,7 @@ Format.prototype = {
|
|
|
463
497
|
}
|
|
464
498
|
|
|
465
499
|
if (format.childNodes.length > 0) {
|
|
466
|
-
if (
|
|
500
|
+
if (dom.check.isListCell(parentEl) && dom.check.isListCell(format) && dom.check.isList(sibling)) {
|
|
467
501
|
if (newList) {
|
|
468
502
|
first = sibling;
|
|
469
503
|
while (sibling) {
|
|
@@ -474,13 +508,13 @@ Format.prototype = {
|
|
|
474
508
|
} else {
|
|
475
509
|
const originNext = originNode.nextElementSibling;
|
|
476
510
|
const detachRange = this._removeNestedList(originNode, false);
|
|
477
|
-
if (
|
|
511
|
+
if (blockElement !== detachRange || originNext !== originNode.nextElementSibling) {
|
|
478
512
|
const fChildren = format.childNodes;
|
|
479
513
|
while (fChildren[0]) {
|
|
480
514
|
originNode.appendChild(fChildren[0]);
|
|
481
515
|
}
|
|
482
516
|
|
|
483
|
-
|
|
517
|
+
blockElement = detachRange;
|
|
484
518
|
reset = true;
|
|
485
519
|
}
|
|
486
520
|
}
|
|
@@ -497,12 +531,12 @@ Format.prototype = {
|
|
|
497
531
|
// detach loop
|
|
498
532
|
for (let i = 0, len = children.length, insNode, lineIndex, next; i < len; i++) {
|
|
499
533
|
insNode = children[i];
|
|
500
|
-
if (insNode.nodeType === 3 &&
|
|
534
|
+
if (insNode.nodeType === 3 && dom.check.isList(rangeEl)) continue;
|
|
501
535
|
|
|
502
536
|
moveComplete = false;
|
|
503
|
-
if (
|
|
537
|
+
if (shouldDelete && i === 0) {
|
|
504
538
|
if (!selectedFormats || selectedFormats.length === len || selectedFormats[0] === insNode) {
|
|
505
|
-
firstNode =
|
|
539
|
+
firstNode = blockElement.previousSibling;
|
|
506
540
|
} else {
|
|
507
541
|
firstNode = rangeEl;
|
|
508
542
|
}
|
|
@@ -510,35 +544,41 @@ Format.prototype = {
|
|
|
510
544
|
|
|
511
545
|
if (selectedFormats) lineIndex = selectedFormats.indexOf(insNode);
|
|
512
546
|
if (selectedFormats && lineIndex === -1) {
|
|
513
|
-
if (!rangeEl) rangeEl =
|
|
547
|
+
if (!rangeEl) rangeEl = /** @type {HTMLElement} */ (blockElement.cloneNode(false));
|
|
514
548
|
rangeEl.appendChild(insNode);
|
|
515
549
|
} else {
|
|
516
550
|
if (selectedFormats) next = selectedFormats[lineIndex + 1];
|
|
517
551
|
if (rangeEl && rangeEl.children.length > 0) {
|
|
518
|
-
parent.insertBefore(rangeEl,
|
|
552
|
+
parent.insertBefore(rangeEl, blockElement);
|
|
519
553
|
rangeEl = null;
|
|
520
554
|
}
|
|
521
555
|
|
|
522
|
-
if (!newList &&
|
|
523
|
-
if (next &&
|
|
556
|
+
if (!newList && dom.check.isListCell(insNode)) {
|
|
557
|
+
if (next && dom.query.getNodeDepth(insNode) !== dom.query.getNodeDepth(next) && (dom.check.isListCell(parent) || dom.utils.arrayFind(insNode.children, dom.check.isList))) {
|
|
524
558
|
const insNext = insNode.nextElementSibling;
|
|
525
559
|
const detachRange = this._removeNestedList(insNode, false);
|
|
526
|
-
if (
|
|
527
|
-
|
|
560
|
+
if (blockElement !== detachRange || insNext !== insNode.nextElementSibling) {
|
|
561
|
+
blockElement = detachRange;
|
|
528
562
|
reset = true;
|
|
529
563
|
}
|
|
530
564
|
} else {
|
|
531
565
|
const inner = insNode;
|
|
532
|
-
insNode =
|
|
533
|
-
|
|
566
|
+
insNode = dom.utils.createElement(
|
|
567
|
+
shouldDelete
|
|
568
|
+
? inner.nodeName
|
|
569
|
+
: dom.check.isList(blockElement.parentNode) || dom.check.isListCell(blockElement.parentNode)
|
|
570
|
+
? 'LI'
|
|
571
|
+
: dom.check.isTableCell(blockElement.parentNode)
|
|
572
|
+
? 'DIV'
|
|
573
|
+
: this.options.get('defaultLine')
|
|
534
574
|
);
|
|
535
|
-
const isCell =
|
|
575
|
+
const isCell = dom.check.isListCell(insNode);
|
|
536
576
|
const innerChildren = inner.childNodes;
|
|
537
577
|
while (innerChildren[0]) {
|
|
538
|
-
if (
|
|
578
|
+
if (dom.check.isList(innerChildren[0]) && !isCell) break;
|
|
539
579
|
insNode.appendChild(innerChildren[0]);
|
|
540
580
|
}
|
|
541
|
-
|
|
581
|
+
dom.utils.copyFormatAttributes(insNode, inner);
|
|
542
582
|
moveComplete = true;
|
|
543
583
|
}
|
|
544
584
|
} else {
|
|
@@ -546,15 +586,15 @@ Format.prototype = {
|
|
|
546
586
|
}
|
|
547
587
|
|
|
548
588
|
if (!reset) {
|
|
549
|
-
if (!
|
|
550
|
-
if (
|
|
589
|
+
if (!shouldDelete) {
|
|
590
|
+
if (newBlockElement) {
|
|
551
591
|
if (!insertedNew) {
|
|
552
|
-
parent.insertBefore(
|
|
592
|
+
parent.insertBefore(newBlockElement, blockElement);
|
|
553
593
|
insertedNew = true;
|
|
554
594
|
}
|
|
555
|
-
insNode = appendNode(
|
|
595
|
+
insNode = appendNode(newBlockElement, insNode, null, children[i]);
|
|
556
596
|
} else {
|
|
557
|
-
insNode = appendNode(parent, insNode,
|
|
597
|
+
insNode = appendNode(parent, insNode, blockElement, children[i]);
|
|
558
598
|
}
|
|
559
599
|
|
|
560
600
|
if (!reset) {
|
|
@@ -569,14 +609,14 @@ Format.prototype = {
|
|
|
569
609
|
}
|
|
570
610
|
} else {
|
|
571
611
|
removeArray.push(insNode);
|
|
572
|
-
|
|
612
|
+
dom.utils.removeItem(children[i]);
|
|
573
613
|
}
|
|
574
614
|
|
|
575
615
|
if (reset) {
|
|
576
616
|
reset = moveComplete = false;
|
|
577
|
-
children =
|
|
578
|
-
rangeEl =
|
|
579
|
-
parent =
|
|
617
|
+
children = dom.query.getListChildNodes(blockElement, (current) => current.parentNode === blockElement);
|
|
618
|
+
rangeEl = /** @type {HTMLElement} */ (blockElement.cloneNode(false));
|
|
619
|
+
parent = blockElement.parentNode;
|
|
580
620
|
i = -1;
|
|
581
621
|
len = children.length;
|
|
582
622
|
continue;
|
|
@@ -585,24 +625,24 @@ Format.prototype = {
|
|
|
585
625
|
}
|
|
586
626
|
}
|
|
587
627
|
|
|
588
|
-
const rangeParent =
|
|
589
|
-
let rangeRight =
|
|
628
|
+
const rangeParent = blockElement.parentNode;
|
|
629
|
+
let rangeRight = blockElement.nextSibling;
|
|
590
630
|
if (rangeEl?.children.length > 0) {
|
|
591
631
|
rangeParent.insertBefore(rangeEl, rangeRight);
|
|
592
632
|
}
|
|
593
633
|
|
|
594
|
-
if (
|
|
595
|
-
else if (!firstNode) firstNode =
|
|
596
|
-
rangeRight =
|
|
634
|
+
if (newBlockElement) firstNode = newBlockElement.previousSibling;
|
|
635
|
+
else if (!firstNode) firstNode = blockElement.previousSibling;
|
|
636
|
+
rangeRight = blockElement.nextSibling !== rangeEl ? blockElement.nextSibling : rangeEl ? rangeEl.nextSibling : null;
|
|
597
637
|
|
|
598
|
-
if (
|
|
599
|
-
|
|
638
|
+
if (/** @type {HTMLElement} */ (blockElement).children.length === 0 || blockElement.textContent.length === 0) {
|
|
639
|
+
dom.utils.removeItem(blockElement);
|
|
600
640
|
} else {
|
|
601
|
-
this.nodeTransform.removeEmptyNode(
|
|
641
|
+
this.nodeTransform.removeEmptyNode(blockElement, null, false);
|
|
602
642
|
}
|
|
603
643
|
|
|
604
644
|
let edge = null;
|
|
605
|
-
if (
|
|
645
|
+
if (shouldDelete) {
|
|
606
646
|
edge = {
|
|
607
647
|
cc: rangeParent,
|
|
608
648
|
sc: firstNode,
|
|
@@ -614,7 +654,7 @@ Format.prototype = {
|
|
|
614
654
|
} else {
|
|
615
655
|
if (!firstNode) firstNode = lastNode;
|
|
616
656
|
if (!lastNode) lastNode = firstNode;
|
|
617
|
-
const childEdge =
|
|
657
|
+
const childEdge = dom.query.getEdgeChildNodes(firstNode, lastNode.parentNode ? firstNode : lastNode);
|
|
618
658
|
edge = {
|
|
619
659
|
cc: (childEdge.sc || childEdge.ec).parentNode,
|
|
620
660
|
sc: childEdge.sc,
|
|
@@ -626,9 +666,9 @@ Format.prototype = {
|
|
|
626
666
|
}
|
|
627
667
|
|
|
628
668
|
this.editor.effectNode = null;
|
|
629
|
-
if (
|
|
669
|
+
if (skipHistory) return edge;
|
|
630
670
|
|
|
631
|
-
if (!
|
|
671
|
+
if (!shouldDelete && edge) {
|
|
632
672
|
if (!selectedFormats) {
|
|
633
673
|
this.selection.setRange(edge.sc, 0, edge.sc, 0);
|
|
634
674
|
} else {
|
|
@@ -640,9 +680,10 @@ Format.prototype = {
|
|
|
640
680
|
},
|
|
641
681
|
|
|
642
682
|
/**
|
|
643
|
-
* @
|
|
683
|
+
* @this {FormatThis}
|
|
684
|
+
* @description Append all selected "line" element to the list and insert.
|
|
644
685
|
* @param {string} type List type. (ol | ul):[listStyleType]
|
|
645
|
-
* @param {
|
|
686
|
+
* @param {Array<Node>} selectedCells "line" elements or list cells.
|
|
646
687
|
* @param {boolean} nested If true, indenting existing list cells.
|
|
647
688
|
*/
|
|
648
689
|
applyList(type, selectedCells, nested) {
|
|
@@ -650,7 +691,7 @@ Format.prototype = {
|
|
|
650
691
|
const listStyle = type.split(':')[1] || '';
|
|
651
692
|
|
|
652
693
|
let range = this.selection.getRange();
|
|
653
|
-
let selectedFormats = !selectedCells ? this.getLinesAndComponents(false) : selectedCells;
|
|
694
|
+
let selectedFormats = /** @type {Array<HTMLElement>} */ (!selectedCells ? this.getLinesAndComponents(false) : selectedCells);
|
|
654
695
|
|
|
655
696
|
if (selectedFormats.length === 0) {
|
|
656
697
|
if (selectedCells) return;
|
|
@@ -659,18 +700,18 @@ Format.prototype = {
|
|
|
659
700
|
if (selectedFormats.length === 0) return;
|
|
660
701
|
}
|
|
661
702
|
|
|
662
|
-
|
|
703
|
+
dom.query.sortNodeByDepth(selectedFormats, true);
|
|
663
704
|
|
|
664
705
|
// merge
|
|
665
706
|
const firstSel = selectedFormats[0];
|
|
666
707
|
const lastSel = selectedFormats[selectedFormats.length - 1];
|
|
667
|
-
let topEl = (
|
|
668
|
-
let bottomEl = (
|
|
708
|
+
let topEl = (dom.check.isListCell(firstSel) || this.component.is(firstSel)) && !firstSel.previousElementSibling ? firstSel.parentElement.previousElementSibling : firstSel.previousElementSibling;
|
|
709
|
+
let bottomEl = (dom.check.isListCell(lastSel) || this.component.is(lastSel)) && !lastSel.nextElementSibling ? lastSel.parentElement.nextElementSibling : lastSel.nextElementSibling;
|
|
669
710
|
|
|
670
711
|
const isCollapsed = range.collapsed;
|
|
671
712
|
const originRange = {
|
|
672
713
|
sc: range.startContainer,
|
|
673
|
-
so: range.startContainer === range.endContainer &&
|
|
714
|
+
so: range.startContainer === range.endContainer && dom.check.isZeroWidth(range.startContainer) && range.startOffset === 0 && range.endOffset === 1 ? range.endOffset : range.startOffset,
|
|
674
715
|
ec: range.endContainer,
|
|
675
716
|
eo: range.endOffset
|
|
676
717
|
};
|
|
@@ -678,7 +719,7 @@ Format.prototype = {
|
|
|
678
719
|
let isRemove = true;
|
|
679
720
|
|
|
680
721
|
for (let i = 0, len = selectedFormats.length; i < len; i++) {
|
|
681
|
-
if (!
|
|
722
|
+
if (!dom.check.isList(this.getBlock(selectedFormats[i], (current) => this.getBlock(current) && current !== selectedFormats[i]))) {
|
|
682
723
|
isRemove = false;
|
|
683
724
|
break;
|
|
684
725
|
}
|
|
@@ -706,85 +747,85 @@ Format.prototype = {
|
|
|
706
747
|
};
|
|
707
748
|
|
|
708
749
|
if (!cancel) {
|
|
709
|
-
tempList =
|
|
750
|
+
tempList = dom.utils.createElement(listTag, { style: 'list-style-type: ' + listStyle });
|
|
710
751
|
}
|
|
711
752
|
|
|
712
753
|
for (let i = 0, len = selectedFormats.length, r, o; i < len; i++) {
|
|
713
754
|
o = this.getBlock(selectedFormats[i], passComponent);
|
|
714
|
-
if (!o || !
|
|
755
|
+
if (!o || !dom.check.isList(o)) continue;
|
|
715
756
|
|
|
716
757
|
if (!r) {
|
|
717
758
|
r = o;
|
|
718
759
|
rangeArr = {
|
|
719
760
|
r: r,
|
|
720
|
-
f: [
|
|
761
|
+
f: [dom.query.getParentElement(selectedFormats[i], 'LI')]
|
|
721
762
|
};
|
|
722
763
|
} else {
|
|
723
764
|
if (r !== o) {
|
|
724
|
-
if (nested &&
|
|
765
|
+
if (nested && dom.check.isListCell(o.parentNode)) {
|
|
725
766
|
this._detachNested(rangeArr.f);
|
|
726
767
|
} else {
|
|
727
|
-
afterRange = this.removeBlock(rangeArr.f[0].
|
|
768
|
+
afterRange = this.removeBlock(rangeArr.f[0].parentElement, { selectedFormats: rangeArr.f, newBlockElement: tempList, shouldDelete: false, skipHistory: true });
|
|
728
769
|
}
|
|
729
770
|
|
|
730
771
|
o = selectedFormats[i].parentNode;
|
|
731
772
|
if (!cancel) {
|
|
732
|
-
tempList =
|
|
773
|
+
tempList = dom.utils.createElement(listTag, { style: 'list-style-type: ' + listStyle });
|
|
733
774
|
}
|
|
734
775
|
|
|
735
776
|
r = o;
|
|
736
777
|
rangeArr = {
|
|
737
778
|
r: r,
|
|
738
|
-
f: [
|
|
779
|
+
f: [dom.query.getParentElement(selectedFormats[i], 'LI')]
|
|
739
780
|
};
|
|
740
781
|
} else {
|
|
741
|
-
rangeArr.f.push(
|
|
782
|
+
rangeArr.f.push(dom.query.getParentElement(selectedFormats[i], 'LI'));
|
|
742
783
|
}
|
|
743
784
|
}
|
|
744
785
|
|
|
745
786
|
if (i === len - 1) {
|
|
746
|
-
if (nested &&
|
|
787
|
+
if (nested && dom.check.isListCell(o.parentNode)) {
|
|
747
788
|
this._detachNested(rangeArr.f);
|
|
748
789
|
} else {
|
|
749
|
-
afterRange = this.removeBlock(rangeArr.f[0].
|
|
790
|
+
afterRange = this.removeBlock(rangeArr.f[0].parentElement, { selectedFormats: rangeArr.f, newBlockElement: tempList, shouldDelete: false, skipHistory: true });
|
|
750
791
|
}
|
|
751
792
|
}
|
|
752
793
|
}
|
|
753
794
|
} else {
|
|
754
795
|
const topElParent = topEl ? topEl.parentNode : topEl;
|
|
755
796
|
const bottomElParent = bottomEl ? bottomEl.parentNode : bottomEl;
|
|
756
|
-
topEl = topElParent && !
|
|
757
|
-
bottomEl = bottomElParent && !
|
|
797
|
+
topEl = /** @type {HTMLElement} */ (topElParent && !dom.check.isWysiwygFrame(topElParent) && topElParent.nodeName === listTag ? topElParent : topEl);
|
|
798
|
+
bottomEl = /** @type {HTMLElement} */ (bottomElParent && !dom.check.isWysiwygFrame(bottomElParent) && bottomElParent.nodeName === listTag ? bottomElParent : bottomEl);
|
|
758
799
|
|
|
759
800
|
const mergeTop = topEl?.tagName === listTag;
|
|
760
801
|
const mergeBottom = bottomEl?.tagName === listTag;
|
|
761
802
|
|
|
762
|
-
let list = mergeTop ? topEl :
|
|
803
|
+
let list = mergeTop ? topEl : dom.utils.createElement(listTag, { style: 'list-style-type: ' + listStyle });
|
|
763
804
|
let firstList = null;
|
|
764
805
|
let topNumber = null;
|
|
765
806
|
// let lastList = null;
|
|
766
807
|
// let bottomNumber = null;
|
|
767
808
|
|
|
768
809
|
const passComponent = (current) => {
|
|
769
|
-
return !this.component.is(current) && !
|
|
810
|
+
return !this.component.is(current) && !dom.check.isList(current);
|
|
770
811
|
};
|
|
771
812
|
|
|
772
813
|
for (let i = 0, len = selectedFormats.length, newCell, fTag, isCell, next, originParent, nextParent, parentTag, siblingTag, rangeTag; i < len; i++) {
|
|
773
814
|
fTag = selectedFormats[i];
|
|
774
815
|
if (fTag.childNodes.length === 0 && !this._isIgnoreNodeChange(fTag)) {
|
|
775
|
-
|
|
816
|
+
dom.utils.removeItem(fTag);
|
|
776
817
|
continue;
|
|
777
818
|
}
|
|
778
819
|
next = selectedFormats[i + 1];
|
|
779
820
|
originParent = fTag.parentNode;
|
|
780
821
|
nextParent = next ? next.parentNode : null;
|
|
781
|
-
isCell =
|
|
822
|
+
isCell = dom.check.isListCell(fTag);
|
|
782
823
|
rangeTag = this.isBlock(originParent) ? originParent : null;
|
|
783
|
-
parentTag = isCell && !
|
|
784
|
-
siblingTag = isCell && !
|
|
824
|
+
parentTag = isCell && !dom.check.isWysiwygFrame(originParent) ? originParent.parentNode : originParent;
|
|
825
|
+
siblingTag = isCell && !dom.check.isWysiwygFrame(originParent) ? (!next || dom.check.isListCell(parentTag) ? originParent : originParent.nextSibling) : fTag.nextSibling;
|
|
785
826
|
|
|
786
|
-
newCell =
|
|
787
|
-
|
|
827
|
+
newCell = dom.utils.createElement('LI');
|
|
828
|
+
dom.utils.copyFormatAttributes(newCell, fTag);
|
|
788
829
|
if (this.component.is(fTag)) {
|
|
789
830
|
const isHR = /^HR$/i.test(fTag.nodeName);
|
|
790
831
|
if (!isHR) newCell.innerHTML = '<br>';
|
|
@@ -801,22 +842,22 @@ Format.prototype = {
|
|
|
801
842
|
// if (!next) lastList = list;
|
|
802
843
|
if (!next || parentTag !== nextParent || this.isBlock(siblingTag)) {
|
|
803
844
|
if (!firstList) firstList = list;
|
|
804
|
-
if ((!mergeTop || !next || parentTag !== nextParent) && !(next &&
|
|
845
|
+
if ((!mergeTop || !next || parentTag !== nextParent) && !(next && dom.check.isList(nextParent) && nextParent === originParent)) {
|
|
805
846
|
if (list.parentNode !== parentTag) parentTag.insertBefore(list, siblingTag);
|
|
806
847
|
}
|
|
807
848
|
}
|
|
808
849
|
|
|
809
|
-
|
|
850
|
+
dom.utils.removeItem(fTag);
|
|
810
851
|
if (mergeTop && topNumber === null) topNumber = list.children.length - 1;
|
|
811
852
|
if (
|
|
812
853
|
next &&
|
|
813
854
|
(this.getBlock(nextParent, passComponent) !== this.getBlock(originParent, passComponent) ||
|
|
814
|
-
(
|
|
855
|
+
(dom.check.isList(nextParent) && dom.check.isList(originParent) && dom.query.getNodeDepth(nextParent) !== dom.query.getNodeDepth(originParent)))
|
|
815
856
|
) {
|
|
816
|
-
list =
|
|
857
|
+
list = dom.utils.createElement(listTag, { style: 'list-style-type: ' + listStyle });
|
|
817
858
|
}
|
|
818
859
|
|
|
819
|
-
if (rangeTag?.children.length === 0)
|
|
860
|
+
if (rangeTag?.children.length === 0) dom.utils.removeItem(rangeTag);
|
|
820
861
|
}
|
|
821
862
|
|
|
822
863
|
if (topNumber) {
|
|
@@ -827,22 +868,25 @@ Format.prototype = {
|
|
|
827
868
|
// bottomNumber = list.children.length - 1;
|
|
828
869
|
list.innerHTML += bottomEl.innerHTML;
|
|
829
870
|
// lastList = list.children[bottomNumber] || lastList;
|
|
830
|
-
|
|
871
|
+
dom.utils.removeItem(bottomEl);
|
|
831
872
|
}
|
|
832
873
|
}
|
|
833
874
|
|
|
834
875
|
this.editor.effectNode = null;
|
|
835
|
-
return !isRemove || !isCollapsed ? originRange : afterRange;
|
|
876
|
+
return !isRemove || !isCollapsed ? originRange : afterRange || originRange;
|
|
836
877
|
},
|
|
837
878
|
|
|
838
879
|
/**
|
|
880
|
+
* @this {FormatThis}
|
|
839
881
|
* @description "selectedCells" array are detached from the list element.
|
|
840
|
-
* The return value is applied when the first and last lines of "selectedFormats" are "LI" respectively.
|
|
841
|
-
* @param {Array} selectedCells Array of
|
|
842
|
-
* @param {boolean}
|
|
843
|
-
* @returns {
|
|
882
|
+
* - The return value is applied when the first and last lines of "selectedFormats" are "LI" respectively.
|
|
883
|
+
* @param {Array<Node>} selectedCells Array of ["line", li] elements(LI, P...) to remove.
|
|
884
|
+
* @param {boolean} shouldDelete If true, It does not just remove the list, it deletes the content.
|
|
885
|
+
* @returns {{sc: Node, ec: Node}} Node information after deletion
|
|
886
|
+
* - sc: Start container node
|
|
887
|
+
* - ec: End container node
|
|
844
888
|
*/
|
|
845
|
-
removeList(selectedCells,
|
|
889
|
+
removeList(selectedCells, shouldDelete) {
|
|
846
890
|
let rangeArr = {};
|
|
847
891
|
let listFirst = false;
|
|
848
892
|
let listLast = false;
|
|
@@ -855,17 +899,17 @@ Format.prototype = {
|
|
|
855
899
|
for (let i = 0, len = selectedCells.length, r, o, lastIndex, isList; i < len; i++) {
|
|
856
900
|
lastIndex = i === len - 1;
|
|
857
901
|
o = this.getBlock(selectedCells[i], passComponent);
|
|
858
|
-
isList =
|
|
902
|
+
isList = dom.check.isList(o);
|
|
859
903
|
if (!r && isList) {
|
|
860
904
|
r = o;
|
|
861
905
|
rangeArr = {
|
|
862
906
|
r: r,
|
|
863
|
-
f: [
|
|
907
|
+
f: [dom.query.getParentElement(selectedCells[i], 'LI')]
|
|
864
908
|
};
|
|
865
909
|
if (i === 0) listFirst = true;
|
|
866
910
|
} else if (r && isList) {
|
|
867
911
|
if (r !== o) {
|
|
868
|
-
const edge = this.
|
|
912
|
+
const edge = this.removeBlock(rangeArr.f[0].parentNode, { selectedFormats: rangeArr.f, newBlockElement: null, shouldDelete, skipHistory: true });
|
|
869
913
|
o = selectedCells[i].parentNode;
|
|
870
914
|
if (listFirst) {
|
|
871
915
|
first = edge.sc;
|
|
@@ -877,20 +921,20 @@ Format.prototype = {
|
|
|
877
921
|
r = o;
|
|
878
922
|
rangeArr = {
|
|
879
923
|
r: r,
|
|
880
|
-
f: [
|
|
924
|
+
f: [dom.query.getParentElement(selectedCells[i], 'LI')]
|
|
881
925
|
};
|
|
882
926
|
if (lastIndex) listLast = true;
|
|
883
927
|
} else {
|
|
884
928
|
r = null;
|
|
885
929
|
}
|
|
886
930
|
} else {
|
|
887
|
-
rangeArr.f.push(
|
|
931
|
+
rangeArr.f.push(dom.query.getParentElement(selectedCells[i], 'LI'));
|
|
888
932
|
if (lastIndex) listLast = true;
|
|
889
933
|
}
|
|
890
934
|
}
|
|
891
935
|
|
|
892
|
-
if (lastIndex &&
|
|
893
|
-
const edge = this.
|
|
936
|
+
if (lastIndex && dom.check.isList(r)) {
|
|
937
|
+
const edge = this.removeBlock(rangeArr.f[0].parentNode, { selectedFormats: rangeArr.f, newBlockElement: null, shouldDelete, skipHistory: true });
|
|
894
938
|
if (listLast || len === 1) last = edge.ec;
|
|
895
939
|
if (listFirst) first = edge.sc || last;
|
|
896
940
|
}
|
|
@@ -903,8 +947,9 @@ Format.prototype = {
|
|
|
903
947
|
},
|
|
904
948
|
|
|
905
949
|
/**
|
|
950
|
+
* @this {FormatThis}
|
|
906
951
|
* @description Indent more the selected lines.
|
|
907
|
-
* margin size
|
|
952
|
+
* - margin size : 'status.indentSize'px
|
|
908
953
|
*/
|
|
909
954
|
indent() {
|
|
910
955
|
const range = this.selection.getRange();
|
|
@@ -927,8 +972,9 @@ Format.prototype = {
|
|
|
927
972
|
},
|
|
928
973
|
|
|
929
974
|
/**
|
|
975
|
+
* @this {FormatThis}
|
|
930
976
|
* @description Indent less the selected lines.
|
|
931
|
-
* margin size - "status.indentSize"px
|
|
977
|
+
* - margin size - "status.indentSize"px
|
|
932
978
|
*/
|
|
933
979
|
outdent() {
|
|
934
980
|
const range = this.selection.getRange();
|
|
@@ -951,46 +997,51 @@ Format.prototype = {
|
|
|
951
997
|
},
|
|
952
998
|
|
|
953
999
|
/**
|
|
954
|
-
* @
|
|
955
|
-
*
|
|
956
|
-
*
|
|
957
|
-
*
|
|
958
|
-
*
|
|
959
|
-
*
|
|
960
|
-
*
|
|
961
|
-
*
|
|
962
|
-
*
|
|
963
|
-
*
|
|
964
|
-
*
|
|
965
|
-
*
|
|
966
|
-
*
|
|
967
|
-
*
|
|
968
|
-
*
|
|
969
|
-
*
|
|
970
|
-
*
|
|
971
|
-
*
|
|
972
|
-
*
|
|
1000
|
+
* @this {FormatThis}
|
|
1001
|
+
* @description Adds, updates, or deletes style nodes from selected text (a, span, strong, etc.).
|
|
1002
|
+
* @param {?Node} styleNode The element to be added to the selection. If null, only existing nodes are modified or removed.
|
|
1003
|
+
* @param {Object} [options] Options
|
|
1004
|
+
* @param {Array<string>} [options.stylesToModify=null] Array of style or class names to check and modify.
|
|
1005
|
+
* (e.g., ['font-size'], ['.className'], ['font-family', 'color', '.className'])
|
|
1006
|
+
* @param {Array<string>} [options.nodesToRemove=null] Array of node names to remove.
|
|
1007
|
+
* If empty array or null when styleNode is null, all formats are removed.
|
|
1008
|
+
* (e.g., ['span'], ['strong', 'em'])
|
|
1009
|
+
* @param {boolean} [options.strictRemove=false] If true, only removes nodes from nodesToRemove if all styles and classes are removed.
|
|
1010
|
+
* @returns {HTMLElement} The element that was added to or modified in the selection.
|
|
1011
|
+
*
|
|
1012
|
+
* @details
|
|
1013
|
+
* 1. If styleNode is provided, a node with the same tags and attributes is added to the selected text.
|
|
1014
|
+
* 2. If the same tag already exists, only its attributes are updated.
|
|
1015
|
+
* 3. If styleNode is null, existing nodes are updated or removed without adding new ones.
|
|
1016
|
+
* 4. Styles matching those in stylesToModify are removed. (Use CSS attribute names, e.g., "background-color")
|
|
1017
|
+
* 5. Classes matching those in stylesToModify (prefixed with ".") are removed.
|
|
1018
|
+
* 6. stylesToModify is used to avoid duplicate property values from styleNode.
|
|
1019
|
+
* 7. Nodes with all styles and classes removed are deleted if they match styleNode, are in nodesToRemove, or if styleNode is null.
|
|
1020
|
+
* 8. Tags matching names in nodesToRemove are deleted regardless of their style and class.
|
|
1021
|
+
* 9. If strictRemove is true, nodes in nodesToRemove are only removed if all their styles and classes are removed.
|
|
1022
|
+
* 10. The function won't modify nodes if the parent has the same class and style values.
|
|
1023
|
+
* - However, if nodesToRemove has values, it will work and separate text nodes even if there's no node to replace.
|
|
973
1024
|
*/
|
|
974
|
-
|
|
975
|
-
if (
|
|
1025
|
+
applyInlineElement(styleNode, { stylesToModify, nodesToRemove, strictRemove } = {}) {
|
|
1026
|
+
if (dom.query.getParentElement(this.selection.getNode(), dom.check.isNonEditable)) return;
|
|
976
1027
|
|
|
977
1028
|
this.selection._resetRangeToTextNode();
|
|
978
1029
|
let range = this.selection.getRangeAndAddLine(this.selection.getRange(), null);
|
|
979
|
-
|
|
980
|
-
|
|
1030
|
+
stylesToModify = stylesToModify?.length > 0 ? stylesToModify : null;
|
|
1031
|
+
nodesToRemove = nodesToRemove?.length > 0 ? nodesToRemove : null;
|
|
981
1032
|
|
|
982
1033
|
const isRemoveNode = !styleNode;
|
|
983
|
-
const isRemoveFormat = isRemoveNode && !
|
|
1034
|
+
const isRemoveFormat = isRemoveNode && !nodesToRemove && !stylesToModify;
|
|
984
1035
|
let startCon = range.startContainer;
|
|
985
1036
|
let startOff = range.startOffset;
|
|
986
1037
|
let endCon = range.endContainer;
|
|
987
1038
|
let endOff = range.endOffset;
|
|
988
1039
|
|
|
989
|
-
if ((isRemoveFormat && range.collapsed && this.isLine(startCon.parentNode) && this.isLine(endCon.parentNode)) || (startCon === endCon && startCon.nodeType === 1 &&
|
|
1040
|
+
if ((isRemoveFormat && range.collapsed && this.isLine(startCon.parentNode) && this.isLine(endCon.parentNode)) || (startCon === endCon && startCon.nodeType === 1 && dom.check.isNonEditable(startCon))) {
|
|
990
1041
|
const format = startCon.parentNode;
|
|
991
1042
|
if (
|
|
992
|
-
!
|
|
993
|
-
!
|
|
1043
|
+
!dom.check.isListCell(format) ||
|
|
1044
|
+
!converter.getValues(format.style).some((k) => {
|
|
994
1045
|
return this._listKebab.includes(k);
|
|
995
1046
|
})
|
|
996
1047
|
)
|
|
@@ -999,7 +1050,7 @@ Format.prototype = {
|
|
|
999
1050
|
}
|
|
1000
1051
|
|
|
1001
1052
|
if (range.collapsed && !isRemoveFormat) {
|
|
1002
|
-
if (startCon.nodeType === 1 && !
|
|
1053
|
+
if (startCon.nodeType === 1 && !dom.check.isBreak(startCon) && !this.component.is(startCon)) {
|
|
1003
1054
|
let afterNode = null;
|
|
1004
1055
|
const focusNode = startCon.childNodes[startOff];
|
|
1005
1056
|
|
|
@@ -1007,11 +1058,11 @@ Format.prototype = {
|
|
|
1007
1058
|
if (!focusNode.nextSibling) {
|
|
1008
1059
|
afterNode = null;
|
|
1009
1060
|
} else {
|
|
1010
|
-
afterNode =
|
|
1061
|
+
afterNode = dom.check.isBreak(focusNode) ? focusNode : focusNode.nextSibling;
|
|
1011
1062
|
}
|
|
1012
1063
|
}
|
|
1013
1064
|
|
|
1014
|
-
const zeroWidth =
|
|
1065
|
+
const zeroWidth = dom.utils.createTextNode(unicode.zeroWidthSpace);
|
|
1015
1066
|
startCon.insertBefore(zeroWidth, afterNode);
|
|
1016
1067
|
this.selection.setRange(zeroWidth, 1, zeroWidth, 1);
|
|
1017
1068
|
|
|
@@ -1033,37 +1084,40 @@ Format.prototype = {
|
|
|
1033
1084
|
}
|
|
1034
1085
|
|
|
1035
1086
|
if (isRemoveNode) {
|
|
1036
|
-
styleNode =
|
|
1087
|
+
styleNode = dom.utils.createElement('DIV');
|
|
1037
1088
|
}
|
|
1038
1089
|
|
|
1039
1090
|
const wRegExp = RegExp;
|
|
1040
1091
|
const newNodeName = styleNode.nodeName;
|
|
1041
1092
|
|
|
1042
1093
|
/* checked same style property */
|
|
1043
|
-
if (!isRemoveFormat && startCon === endCon && !
|
|
1094
|
+
if (!isRemoveFormat && startCon === endCon && !nodesToRemove && styleNode) {
|
|
1044
1095
|
let sNode = startCon;
|
|
1045
1096
|
let checkCnt = 0;
|
|
1046
1097
|
const checkAttrs = [];
|
|
1047
1098
|
|
|
1048
|
-
const checkStyles = styleNode.style;
|
|
1099
|
+
const checkStyles = /** @type {HTMLElement} */ (styleNode).style;
|
|
1049
1100
|
for (let i = 0, len = checkStyles.length; i < len; i++) {
|
|
1050
1101
|
checkAttrs.push(checkStyles[i]);
|
|
1051
1102
|
}
|
|
1052
1103
|
|
|
1053
|
-
const
|
|
1104
|
+
const checkClassName = /** @type {HTMLElement} */ (styleNode).className;
|
|
1105
|
+
const ckeckClasses = /** @type {HTMLElement} */ (styleNode).classList;
|
|
1054
1106
|
for (let i = 0, len = ckeckClasses.length; i < len; i++) {
|
|
1055
1107
|
checkAttrs.push('.' + ckeckClasses[i]);
|
|
1056
1108
|
}
|
|
1057
1109
|
|
|
1058
1110
|
if (checkAttrs.length > 0) {
|
|
1059
|
-
while (!this.isLine(sNode) && !
|
|
1111
|
+
while (!this.isLine(sNode) && !dom.check.isWysiwygFrame(sNode)) {
|
|
1060
1112
|
for (let i = 0; i < checkAttrs.length; i++) {
|
|
1061
1113
|
if (sNode.nodeType === 1) {
|
|
1062
1114
|
const s = checkAttrs[i];
|
|
1063
1115
|
const classReg = /^\./.test(s) ? new wRegExp('\\s*' + s.replace(/^\./, '') + '(\\s+|$)', 'ig') : false;
|
|
1116
|
+
const sNodeStyle = /** @type {HTMLElement} */ (sNode).style;
|
|
1117
|
+
const sNodeClassName = /** @type {HTMLElement} */ (sNode).className;
|
|
1064
1118
|
|
|
1065
|
-
const styleCheck = isRemoveNode ? !!
|
|
1066
|
-
const classCheck = classReg === false ? false : isRemoveNode ? !!
|
|
1119
|
+
const styleCheck = isRemoveNode ? !!sNodeStyle[s] : !!sNodeStyle[s] && !!checkStyles[s] && sNodeStyle[s] === checkStyles[s];
|
|
1120
|
+
const classCheck = classReg === false ? false : isRemoveNode ? !!sNodeClassName.match(classReg) : !!sNodeClassName.match(classReg) && !!checkClassName.match(classReg);
|
|
1067
1121
|
if (styleCheck || classCheck) {
|
|
1068
1122
|
checkCnt++;
|
|
1069
1123
|
}
|
|
@@ -1076,16 +1130,22 @@ Format.prototype = {
|
|
|
1076
1130
|
}
|
|
1077
1131
|
}
|
|
1078
1132
|
|
|
1079
|
-
let
|
|
1080
|
-
|
|
1081
|
-
let
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1133
|
+
let newNode;
|
|
1134
|
+
/** @type {NodeStyleContainerType} */
|
|
1135
|
+
let start = {};
|
|
1136
|
+
/** @type {NodeStyleContainerType} */
|
|
1137
|
+
let end = {};
|
|
1138
|
+
|
|
1139
|
+
/** @type {string|RegExp} */
|
|
1140
|
+
let styleRegExp;
|
|
1141
|
+
/** @type {string|RegExp} */
|
|
1142
|
+
let classRegExp;
|
|
1143
|
+
/** @type {string|RegExp} */
|
|
1144
|
+
let removeNodeRegExp;
|
|
1085
1145
|
|
|
1086
|
-
if (
|
|
1087
|
-
for (let i = 0, len =
|
|
1088
|
-
s =
|
|
1146
|
+
if (stylesToModify) {
|
|
1147
|
+
for (let i = 0, len = stylesToModify.length, s; i < len; i++) {
|
|
1148
|
+
s = stylesToModify[i];
|
|
1089
1149
|
if (/^\./.test(s)) {
|
|
1090
1150
|
classRegExp += (classRegExp ? '|' : '\\s*(?:') + s.replace(/^\./, '');
|
|
1091
1151
|
} else {
|
|
@@ -1104,17 +1164,16 @@ Format.prototype = {
|
|
|
1104
1164
|
}
|
|
1105
1165
|
}
|
|
1106
1166
|
|
|
1107
|
-
if (
|
|
1108
|
-
removeNodeRegExp = '^(?:' +
|
|
1109
|
-
for (let i = 1; i <
|
|
1110
|
-
removeNodeRegExp += '|' +
|
|
1167
|
+
if (nodesToRemove) {
|
|
1168
|
+
removeNodeRegExp = '^(?:' + nodesToRemove[0];
|
|
1169
|
+
for (let i = 1; i < nodesToRemove.length; i++) {
|
|
1170
|
+
removeNodeRegExp += '|' + nodesToRemove[i];
|
|
1111
1171
|
}
|
|
1112
1172
|
removeNodeRegExp += ')$';
|
|
1113
1173
|
removeNodeRegExp = new wRegExp(removeNodeRegExp, 'i');
|
|
1114
1174
|
}
|
|
1115
1175
|
|
|
1116
1176
|
/** validation check function*/
|
|
1117
|
-
const wBoolean = Boolean;
|
|
1118
1177
|
const _removeCheck = {
|
|
1119
1178
|
v: false
|
|
1120
1179
|
};
|
|
@@ -1122,12 +1181,12 @@ Format.prototype = {
|
|
|
1122
1181
|
const vNode = checkNode.cloneNode(false);
|
|
1123
1182
|
|
|
1124
1183
|
// all path
|
|
1125
|
-
if (vNode.nodeType === 3 ||
|
|
1184
|
+
if (vNode.nodeType === 3 || dom.check.isBreak(vNode)) return vNode;
|
|
1126
1185
|
// all remove
|
|
1127
1186
|
if (isRemoveFormat) return null;
|
|
1128
1187
|
|
|
1129
1188
|
// remove node check
|
|
1130
|
-
const tagRemove = (!removeNodeRegExp && isRemoveNode) || removeNodeRegExp?.test(vNode.nodeName);
|
|
1189
|
+
const tagRemove = (!removeNodeRegExp && isRemoveNode) || /** @type {RegExp} */ (removeNodeRegExp)?.test(vNode.nodeName);
|
|
1131
1190
|
|
|
1132
1191
|
// tag remove
|
|
1133
1192
|
if (tagRemove && !strictRemove) {
|
|
@@ -1160,7 +1219,7 @@ Format.prototype = {
|
|
|
1160
1219
|
}
|
|
1161
1220
|
|
|
1162
1221
|
// change
|
|
1163
|
-
if (style || classes || vNode.nodeName !== newNodeName ||
|
|
1222
|
+
if (style || classes || vNode.nodeName !== newNodeName || Boolean(styleRegExp) !== Boolean(originStyle) || Boolean(classRegExp) !== Boolean(originClasses)) {
|
|
1164
1223
|
if (styleRegExp && originStyle.length > 0) vNode.style.cssText = style;
|
|
1165
1224
|
if (!vNode.style.cssText) {
|
|
1166
1225
|
vNode.removeAttribute('style');
|
|
@@ -1192,7 +1251,7 @@ Format.prototype = {
|
|
|
1192
1251
|
endOff = range.endOffset;
|
|
1193
1252
|
|
|
1194
1253
|
if (!this.getLine(startCon, null)) {
|
|
1195
|
-
startCon =
|
|
1254
|
+
startCon = dom.query.getEdgeChild(
|
|
1196
1255
|
lineNodes[0],
|
|
1197
1256
|
function (current) {
|
|
1198
1257
|
return current.nodeType === 3;
|
|
@@ -1203,7 +1262,7 @@ Format.prototype = {
|
|
|
1203
1262
|
}
|
|
1204
1263
|
|
|
1205
1264
|
if (!this.getLine(endCon, null)) {
|
|
1206
|
-
endCon =
|
|
1265
|
+
endCon = dom.query.getEdgeChild(
|
|
1207
1266
|
lineNodes[lineNodes.length - 1],
|
|
1208
1267
|
function (current) {
|
|
1209
1268
|
return current.nodeType === 3;
|
|
@@ -1224,10 +1283,10 @@ Format.prototype = {
|
|
|
1224
1283
|
(isRemoveNode &&
|
|
1225
1284
|
(function (inst, arr) {
|
|
1226
1285
|
for (let n = 0, len = arr.length; n < len; n++) {
|
|
1227
|
-
if (inst._isNonSplitNode(arr[n])
|
|
1286
|
+
if (inst._isNonSplitNode(arr[n])) return true;
|
|
1228
1287
|
}
|
|
1229
1288
|
return false;
|
|
1230
|
-
})(this,
|
|
1289
|
+
})(this, nodesToRemove));
|
|
1231
1290
|
|
|
1232
1291
|
const isSizeNode = isRemoveNode || this._sn_isSizeNode(newNode);
|
|
1233
1292
|
const _getMaintainedNode = this._sn_getMaintainedNode.bind(this, isRemoveAnchor, isSizeNode);
|
|
@@ -1235,7 +1294,7 @@ Format.prototype = {
|
|
|
1235
1294
|
|
|
1236
1295
|
// one line
|
|
1237
1296
|
if (oneLine) {
|
|
1238
|
-
if (this._sn_resetCommonListCell(lineNodes[0],
|
|
1297
|
+
if (this._sn_resetCommonListCell(lineNodes[0], stylesToModify)) range = this.selection.setRange(startCon, startOff, endCon, endOff);
|
|
1239
1298
|
|
|
1240
1299
|
const newRange = this._setNode_oneLine(lineNodes[0], newNode, validation, startCon, startOff, endCon, endOff, isRemoveFormat, isRemoveNode, range.collapsed, _removeCheck, _getMaintainedNode, _isMaintainedNode);
|
|
1241
1300
|
start.container = newRange.startContainer;
|
|
@@ -1243,15 +1302,15 @@ Format.prototype = {
|
|
|
1243
1302
|
end.container = newRange.endContainer;
|
|
1244
1303
|
end.offset = newRange.endOffset;
|
|
1245
1304
|
|
|
1246
|
-
if (start.container === end.container &&
|
|
1305
|
+
if (start.container === end.container && dom.check.isZeroWidth(start.container)) {
|
|
1247
1306
|
start.offset = end.offset = 1;
|
|
1248
1307
|
}
|
|
1249
1308
|
this._sn_setCommonListStyle(newRange.ancestor, null);
|
|
1250
1309
|
} else {
|
|
1251
1310
|
// multi line
|
|
1252
1311
|
let appliedCommonList = false;
|
|
1253
|
-
if (endLength > 0 && this._sn_resetCommonListCell(lineNodes[endLength],
|
|
1254
|
-
if (this._sn_resetCommonListCell(lineNodes[0],
|
|
1312
|
+
if (endLength > 0 && this._sn_resetCommonListCell(lineNodes[endLength], stylesToModify)) appliedCommonList = true;
|
|
1313
|
+
if (this._sn_resetCommonListCell(lineNodes[0], stylesToModify)) appliedCommonList = true;
|
|
1255
1314
|
if (appliedCommonList) this.selection.setRange(startCon, startOff, endCon, endOff);
|
|
1256
1315
|
|
|
1257
1316
|
// end
|
|
@@ -1262,7 +1321,7 @@ Format.prototype = {
|
|
|
1262
1321
|
|
|
1263
1322
|
// mid
|
|
1264
1323
|
for (let i = endLength - 1, newRange; i > 0; i--) {
|
|
1265
|
-
this._sn_resetCommonListCell(lineNodes[i],
|
|
1324
|
+
this._sn_resetCommonListCell(lineNodes[i], stylesToModify);
|
|
1266
1325
|
newNode = styleNode.cloneNode(false);
|
|
1267
1326
|
newRange = this._setNode_middleLine(lineNodes[i], newNode, validation, isRemoveFormat, isRemoveNode, _removeCheck, end.container);
|
|
1268
1327
|
if (newRange.endContainer && newRange.ancestor.contains(newRange.endContainer)) {
|
|
@@ -1294,38 +1353,40 @@ Format.prototype = {
|
|
|
1294
1353
|
}
|
|
1295
1354
|
|
|
1296
1355
|
// set range
|
|
1297
|
-
this.
|
|
1356
|
+
this.ui._offCurrentController();
|
|
1298
1357
|
this.selection.setRange(start.container, start.offset, end.container, end.offset);
|
|
1299
1358
|
this.history.push(false);
|
|
1300
1359
|
|
|
1301
|
-
return newNode;
|
|
1360
|
+
return /** @type {HTMLElement} */ (newNode);
|
|
1302
1361
|
},
|
|
1303
1362
|
|
|
1304
1363
|
/**
|
|
1364
|
+
* @this {FormatThis}
|
|
1305
1365
|
* @description Remove format of the currently selected text.
|
|
1306
1366
|
*/
|
|
1307
|
-
|
|
1308
|
-
this.
|
|
1367
|
+
removeInlineElement() {
|
|
1368
|
+
this.applyInlineElement(null, { stylesToModify: null, nodesToRemove: null, strictRemove: null });
|
|
1309
1369
|
},
|
|
1310
1370
|
|
|
1311
1371
|
/**
|
|
1372
|
+
* @this {FormatThis}
|
|
1312
1373
|
* @description Check if the container and offset values are the edges of the "line"
|
|
1313
|
-
* @param {Node}
|
|
1374
|
+
* @param {Node} node The node of the selection object. (range.startContainer..)
|
|
1314
1375
|
* @param {number} offset The offset of the selection object. (selection.getRange().startOffset...)
|
|
1315
|
-
* @param {
|
|
1316
|
-
* @returns {
|
|
1376
|
+
* @param {"front"|"end"} dir Select check point - "front": Front edge, "end": End edge, undefined: Both edge.
|
|
1377
|
+
* @returns {node is HTMLElement}
|
|
1317
1378
|
*/
|
|
1318
1379
|
isEdgeLine(node, offset, dir) {
|
|
1319
|
-
if (!
|
|
1380
|
+
if (!dom.check.isEdgePoint(node, offset, dir)) return false;
|
|
1320
1381
|
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
while (node && !this.isLine(node) && !
|
|
1324
|
-
if (!node[
|
|
1325
|
-
|
|
1382
|
+
let result = false;
|
|
1383
|
+
const siblingType = dir === 'front' ? 'previousSibling' : 'nextSibling';
|
|
1384
|
+
while (node && !this.isLine(node) && !dom.check.isWysiwygFrame(node)) {
|
|
1385
|
+
if (!node[siblingType] || (dom.check.isBreak(node[siblingType]) && !node[siblingType][siblingType])) {
|
|
1386
|
+
result = true;
|
|
1326
1387
|
node = node.parentNode;
|
|
1327
1388
|
} else {
|
|
1328
|
-
return
|
|
1389
|
+
return false;
|
|
1329
1390
|
}
|
|
1330
1391
|
}
|
|
1331
1392
|
|
|
@@ -1333,102 +1394,118 @@ Format.prototype = {
|
|
|
1333
1394
|
},
|
|
1334
1395
|
|
|
1335
1396
|
/**
|
|
1397
|
+
* @this {FormatThis}
|
|
1336
1398
|
* @description It is judged whether it is a node related to the text style.
|
|
1337
1399
|
* @param {Node|string} element The node to check
|
|
1338
|
-
* @returns {
|
|
1400
|
+
* @returns {element is HTMLElement}
|
|
1339
1401
|
*/
|
|
1340
1402
|
isTextStyleNode(element) {
|
|
1341
1403
|
return typeof element === 'string' ? this._textStyleTagsCheck.test(element) : element && element.nodeType === 1 && this._textStyleTagsCheck.test(element.nodeName);
|
|
1342
1404
|
},
|
|
1343
1405
|
|
|
1344
1406
|
/**
|
|
1345
|
-
* @
|
|
1346
|
-
*
|
|
1407
|
+
* @this {FormatThis}
|
|
1408
|
+
* @description It is judged whether it is the "line" element.
|
|
1409
|
+
* - (P, DIV, H[1-6], PRE, LI | class="__se__format__line_xxx")
|
|
1410
|
+
* - "line" element also contain "brLine" element
|
|
1347
1411
|
* @param {Node|string} element The node to check
|
|
1348
|
-
* @returns {
|
|
1412
|
+
* @returns {element is HTMLElement}
|
|
1349
1413
|
*/
|
|
1350
1414
|
isLine(element) {
|
|
1415
|
+
if (this.isBlock(element)) return false;
|
|
1351
1416
|
return typeof element === 'string'
|
|
1352
1417
|
? this._formatLineCheck.test(element)
|
|
1353
|
-
: element && element.nodeType === 1 && (this._formatLineCheck.test(element.nodeName) ||
|
|
1418
|
+
: element && element.nodeType === 1 && (this._formatLineCheck.test(element.nodeName) || dom.utils.hasClass(element, '__se__format__line_.+|__se__format__br_line_.+')) && !this._nonFormat(element);
|
|
1354
1419
|
},
|
|
1355
1420
|
|
|
1356
1421
|
/**
|
|
1357
|
-
* @
|
|
1358
|
-
*
|
|
1422
|
+
* @this {FormatThis}
|
|
1423
|
+
* @description It is judged whether it is the only "line" element, not "brLine".
|
|
1359
1424
|
* @param {Node|string} element The node to check
|
|
1360
|
-
* @returns {
|
|
1425
|
+
* @returns {element is HTMLElement}
|
|
1361
1426
|
*/
|
|
1362
1427
|
isLineOnly(element) {
|
|
1363
|
-
return this.
|
|
1428
|
+
return this.isLine(element) && (this._brLineBreak || !this.isBrLine(element));
|
|
1364
1429
|
},
|
|
1365
1430
|
|
|
1366
1431
|
/**
|
|
1367
|
-
* @
|
|
1368
|
-
*
|
|
1369
|
-
*
|
|
1370
|
-
*
|
|
1432
|
+
* @this {FormatThis}
|
|
1433
|
+
* @description It is judged whether it is the "brLine" element.
|
|
1434
|
+
* - (PRE | class="__se__format__br_line_xxx")
|
|
1435
|
+
* - "brLine" elements is included in the "line" element.
|
|
1436
|
+
* - "brLine" elements's line break is "BR" tag.
|
|
1437
|
+
* ※ Entering the Enter key in the space on the last line ends "brLine" and appends "line".
|
|
1371
1438
|
* @param {Node|string} element The node to check
|
|
1372
|
-
* @returns {
|
|
1439
|
+
* @returns {element is HTMLElement}
|
|
1373
1440
|
*/
|
|
1374
1441
|
isBrLine(element) {
|
|
1375
|
-
return
|
|
1376
|
-
|
|
1377
|
-
|
|
1442
|
+
return (
|
|
1443
|
+
(this._brLineBreak && this.isLine(element)) ||
|
|
1444
|
+
(typeof element === 'string'
|
|
1445
|
+
? this._formatBrLineCheck.test(element)
|
|
1446
|
+
: element && element.nodeType === 1 && (this._formatBrLineCheck.test(element.nodeName) || dom.utils.hasClass(element, '__se__format__br_line_.+')) && !this._nonFormat(element))
|
|
1447
|
+
);
|
|
1378
1448
|
},
|
|
1379
1449
|
|
|
1380
1450
|
/**
|
|
1381
|
-
* @
|
|
1382
|
-
*
|
|
1451
|
+
* @this {FormatThis}
|
|
1452
|
+
* @description It is judged whether it is the "block" element.
|
|
1453
|
+
* - (BLOCKQUOTE, OL, UL, FIGCAPTION, TABLE, THEAD, TBODY, TR, TH, TD | class="__se__format__block_xxx")
|
|
1454
|
+
* - "block" is wrap the "line" and "component"
|
|
1383
1455
|
* @param {Node|string} element The node to check
|
|
1384
|
-
* @returns {
|
|
1456
|
+
* @returns {element is HTMLElement}
|
|
1385
1457
|
*/
|
|
1386
1458
|
isBlock(element) {
|
|
1387
1459
|
return typeof element === 'string'
|
|
1388
1460
|
? this._formatBlockCheck.test(element)
|
|
1389
|
-
: element && element.nodeType === 1 && (this._formatBlockCheck.test(element.nodeName) ||
|
|
1461
|
+
: element && element.nodeType === 1 && (this._formatBlockCheck.test(element.nodeName) || dom.utils.hasClass(element, '__se__format__block_.+')) && !this._nonFormat(element);
|
|
1390
1462
|
},
|
|
1391
1463
|
|
|
1392
1464
|
/**
|
|
1393
|
-
* @
|
|
1394
|
-
*
|
|
1395
|
-
*
|
|
1396
|
-
*
|
|
1397
|
-
*
|
|
1465
|
+
* @this {FormatThis}
|
|
1466
|
+
* @description It is judged whether it is the "closureBlock" element.
|
|
1467
|
+
* - (TH, TD | class="__se__format__block_closure_xxx")
|
|
1468
|
+
* - "closureBlock" elements is included in the "block".
|
|
1469
|
+
* - "closureBlock" element is wrap the "line" and "component"
|
|
1470
|
+
* - ※ You cannot exit this format with the Enter key or Backspace key.
|
|
1471
|
+
* - ※ Use it only in special cases. ([ex] format of table cells)
|
|
1398
1472
|
* @param {Node|string} element The node to check
|
|
1399
|
-
* @returns {
|
|
1473
|
+
* @returns {element is HTMLElement}
|
|
1400
1474
|
*/
|
|
1401
1475
|
isClosureBlock(element) {
|
|
1402
1476
|
return typeof element === 'string'
|
|
1403
1477
|
? this._formatClosureBlockCheck.test(element)
|
|
1404
|
-
: element && element.nodeType === 1 && (this._formatClosureBlockCheck.test(element.nodeName) ||
|
|
1478
|
+
: element && element.nodeType === 1 && (this._formatClosureBlockCheck.test(element.nodeName) || dom.utils.hasClass(element, '__se__format__block_closure_.+')) && !this._nonFormat(element);
|
|
1405
1479
|
},
|
|
1406
1480
|
|
|
1407
1481
|
/**
|
|
1408
|
-
* @
|
|
1409
|
-
*
|
|
1410
|
-
*
|
|
1411
|
-
*
|
|
1412
|
-
*
|
|
1482
|
+
* @this {FormatThis}
|
|
1483
|
+
* @description It is judged whether it is the "closureBrLine" element.
|
|
1484
|
+
* - (class="__se__format__br_line__closure_xxx")
|
|
1485
|
+
* - "closureBrLine" elements is included in the "brLine".
|
|
1486
|
+
* - "closureBrLine" elements's line break is "BR" tag.
|
|
1487
|
+
* - ※ You cannot exit this format with the Enter key or Backspace key.
|
|
1488
|
+
* - ※ Use it only in special cases. ([ex] format of table cells)
|
|
1413
1489
|
* @param {Node|string} element The node to check
|
|
1414
|
-
* @returns {
|
|
1490
|
+
* @returns {element is HTMLElement}
|
|
1415
1491
|
*/
|
|
1416
1492
|
isClosureBrLine(element) {
|
|
1417
1493
|
return typeof element === 'string'
|
|
1418
1494
|
? this._formatClosureBrLineCheck.test(element)
|
|
1419
|
-
: element && element.nodeType === 1 && (this._formatClosureBrLineCheck.test(element.nodeName) ||
|
|
1495
|
+
: element && element.nodeType === 1 && (this._formatClosureBrLineCheck.test(element.nodeName) || dom.utils.hasClass(element, '__se__format__br_line__closure_.+')) && !this._nonFormat(element);
|
|
1420
1496
|
},
|
|
1421
1497
|
|
|
1422
1498
|
/**
|
|
1499
|
+
* @this {FormatThis}
|
|
1423
1500
|
* @description Returns a "line" array from selected range.
|
|
1424
|
-
* @param {
|
|
1425
|
-
* @returns {Array}
|
|
1501
|
+
* @param {?(current: Node) => boolean=} validation The validation function. (Replaces the default validation format.isLine(current))
|
|
1502
|
+
* @returns {Array<HTMLElement>}
|
|
1426
1503
|
*/
|
|
1427
1504
|
getLines(validation) {
|
|
1428
1505
|
if (!this.selection._resetRangeToTextNode()) return [];
|
|
1429
1506
|
let range = this.selection.getRange();
|
|
1430
1507
|
|
|
1431
|
-
if (
|
|
1508
|
+
if (dom.check.isWysiwygFrame(range.startContainer)) {
|
|
1432
1509
|
const children = this.editor.frameContext.get('wysiwyg').children;
|
|
1433
1510
|
if (children.length === 0) return [];
|
|
1434
1511
|
|
|
@@ -1441,11 +1518,11 @@ Format.prototype = {
|
|
|
1441
1518
|
const commonCon = range.commonAncestorContainer;
|
|
1442
1519
|
|
|
1443
1520
|
// get line nodes
|
|
1444
|
-
const lineNodes =
|
|
1521
|
+
const lineNodes = dom.query.getListChildren(commonCon, (current) => {
|
|
1445
1522
|
return validation ? validation(current) : this.isLine(current);
|
|
1446
1523
|
});
|
|
1447
1524
|
|
|
1448
|
-
if (!
|
|
1525
|
+
if (!dom.check.isWysiwygFrame(commonCon) && !this.isBlock(commonCon)) lineNodes.unshift(this.getLine(commonCon, null));
|
|
1449
1526
|
if (startCon === endCon || lineNodes.length === 1) return lineNodes;
|
|
1450
1527
|
|
|
1451
1528
|
const startLine = this.getLine(startCon, null);
|
|
@@ -1454,13 +1531,13 @@ Format.prototype = {
|
|
|
1454
1531
|
let endIdx = null;
|
|
1455
1532
|
|
|
1456
1533
|
const onlyTable = function (current) {
|
|
1457
|
-
return
|
|
1534
|
+
return dom.check.isTableElements(current) ? /^TABLE$/i.test(current.nodeName) : true;
|
|
1458
1535
|
};
|
|
1459
1536
|
|
|
1460
1537
|
let startRangeEl = this.getBlock(startLine, onlyTable);
|
|
1461
1538
|
let endRangeEl = this.getBlock(endLine, onlyTable);
|
|
1462
|
-
if (
|
|
1463
|
-
if (
|
|
1539
|
+
if (dom.check.isTableElements(startRangeEl) && dom.check.isListCell(startRangeEl.parentNode)) startRangeEl = startRangeEl.parentNode;
|
|
1540
|
+
if (dom.check.isTableElements(endRangeEl) && dom.check.isListCell(endRangeEl.parentNode)) endRangeEl = endRangeEl.parentNode;
|
|
1464
1541
|
|
|
1465
1542
|
const sameRange = startRangeEl === endRangeEl;
|
|
1466
1543
|
for (let i = 0, len = lineNodes.length, line; i < len; i++) {
|
|
@@ -1484,18 +1561,19 @@ Format.prototype = {
|
|
|
1484
1561
|
},
|
|
1485
1562
|
|
|
1486
1563
|
/**
|
|
1564
|
+
* @this {FormatThis}
|
|
1487
1565
|
* @description Get lines and components from the selected range. (P, DIV, H[1-6], OL, UL, TABLE..)
|
|
1488
|
-
* If some of the component are included in the selection, get the entire that component.
|
|
1566
|
+
* - If some of the component are included in the selection, get the entire that component.
|
|
1489
1567
|
* @param {boolean} removeDuplicate If true, if there is a parent and child tag among the selected elements, the child tag is excluded.
|
|
1490
|
-
* @returns {Array}
|
|
1568
|
+
* @returns {Array<HTMLElement>}
|
|
1491
1569
|
*/
|
|
1492
1570
|
getLinesAndComponents(removeDuplicate) {
|
|
1493
1571
|
const commonCon = this.selection.getRange().commonAncestorContainer;
|
|
1494
|
-
const myComponent =
|
|
1495
|
-
const selectedLines =
|
|
1572
|
+
const myComponent = dom.query.getParentElement(commonCon, this.component.is.bind(this.component));
|
|
1573
|
+
const selectedLines = dom.check.isTableElements(commonCon)
|
|
1496
1574
|
? this.getLines(null)
|
|
1497
1575
|
: this.getLines((current) => {
|
|
1498
|
-
const component =
|
|
1576
|
+
const component = dom.query.getParentElement(current, this.component.is.bind(this.component));
|
|
1499
1577
|
return (this.isLine(current) && (!component || component === myComponent)) || (this.component.is(current) && !this.getLine(current));
|
|
1500
1578
|
});
|
|
1501
1579
|
|
|
@@ -1516,59 +1594,71 @@ Format.prototype = {
|
|
|
1516
1594
|
},
|
|
1517
1595
|
|
|
1518
1596
|
/**
|
|
1597
|
+
* @private
|
|
1598
|
+
* @this {FormatThis}
|
|
1519
1599
|
* @description A function that distinguishes areas where "selection" should not be placed
|
|
1520
|
-
* @param {
|
|
1600
|
+
* @param {Node} element Element
|
|
1521
1601
|
* @returns {boolean}
|
|
1522
|
-
* @private
|
|
1523
1602
|
*/
|
|
1524
1603
|
_isExcludeSelectionElement(element) {
|
|
1525
1604
|
return !/FIGCAPTION/i.test(element.nodeName) && (this.component.is(element) || /FIGURE/i.test(element.nodeName));
|
|
1526
1605
|
},
|
|
1527
1606
|
|
|
1528
1607
|
/**
|
|
1608
|
+
* @private
|
|
1609
|
+
* @this {FormatThis}
|
|
1529
1610
|
* @description A function that distinguishes non-formatting HTML elements or tags from formatting ones.
|
|
1530
|
-
* @param {
|
|
1611
|
+
* @param {Node} element Element
|
|
1531
1612
|
* @returns {boolean}
|
|
1532
|
-
* @private
|
|
1533
1613
|
*/
|
|
1534
1614
|
_nonFormat(element) {
|
|
1535
|
-
return
|
|
1615
|
+
return dom.check.isExcludeFormat(element) || this.component.is(element) || dom.check.isWysiwygFrame(element);
|
|
1536
1616
|
},
|
|
1537
1617
|
|
|
1538
1618
|
/**
|
|
1619
|
+
* @private
|
|
1620
|
+
* @this {FormatThis}
|
|
1539
1621
|
* @description Nodes that must remain undetached when changing text nodes (A, Label, Code, Span:font-size)
|
|
1540
|
-
* @param {Node|
|
|
1622
|
+
* @param {Node|string} element Element to check
|
|
1541
1623
|
* @returns {boolean}
|
|
1542
|
-
* @private
|
|
1543
1624
|
*/
|
|
1544
1625
|
_isNonSplitNode(element) {
|
|
1545
|
-
|
|
1626
|
+
if (!element) return false;
|
|
1627
|
+
const checkRegExp = /^(a|label|code|summary)$/i;
|
|
1628
|
+
if (typeof element === 'string') return checkRegExp.test(element);
|
|
1629
|
+
return element.nodeType === 1 && checkRegExp.test(element.nodeName);
|
|
1546
1630
|
},
|
|
1547
1631
|
|
|
1548
1632
|
/**
|
|
1633
|
+
* @private
|
|
1634
|
+
* @this {FormatThis}
|
|
1549
1635
|
* @description Nodes without text
|
|
1550
|
-
* @param {Node} element Element to check
|
|
1636
|
+
* @param {Node|string} element Element to check
|
|
1551
1637
|
* @returns {boolean}
|
|
1552
|
-
* @private
|
|
1553
1638
|
*/
|
|
1554
1639
|
_notTextNode(element) {
|
|
1555
|
-
|
|
1640
|
+
if (!element) return false;
|
|
1641
|
+
const checkRegExp = /^(br|input|select|canvas|img|iframe|audio|video)$/i;
|
|
1642
|
+
if (typeof element === 'string') return checkRegExp.test(element);
|
|
1643
|
+
return element.nodeType === 1 && (this.component.is(element) || checkRegExp.test(element.nodeName));
|
|
1556
1644
|
},
|
|
1557
1645
|
|
|
1558
1646
|
/**
|
|
1647
|
+
* @private
|
|
1648
|
+
* @this {FormatThis}
|
|
1559
1649
|
* @description Nodes that need to be added without modification when changing text nodes
|
|
1560
1650
|
* @param {Node} element Element to check
|
|
1561
1651
|
* @returns {boolean}
|
|
1562
|
-
* @private
|
|
1563
1652
|
*/
|
|
1564
1653
|
_isIgnoreNodeChange(element) {
|
|
1565
|
-
return element && element.nodeType
|
|
1654
|
+
return element && element.nodeType === 1 && (dom.check.isNonEditable(element) || !this.isTextStyleNode(element) || this.component.is(element));
|
|
1566
1655
|
},
|
|
1567
1656
|
|
|
1568
1657
|
/**
|
|
1569
|
-
* @description Get current selected lines and selected node info.
|
|
1570
|
-
* @returns { lines: Array.<Element>, firstNode: Node, lastNode: Node, firstPath: Array.<number>, lastPath: Array.<number>, startOffset: number, endOffset: number }
|
|
1571
1658
|
* @private
|
|
1659
|
+
* @this {FormatThis}
|
|
1660
|
+
* @description Get current selected lines and selected node info.
|
|
1661
|
+
* @returns {{lines: Array<HTMLElement>, firstNode: Node, lastNode: Node, firstPath: Array<number>, lastPath: Array<number>, startOffset: number, endOffset: number}}
|
|
1572
1662
|
*/
|
|
1573
1663
|
_lineWork() {
|
|
1574
1664
|
let range = this.selection.getRange();
|
|
@@ -1583,10 +1673,10 @@ Format.prototype = {
|
|
|
1583
1673
|
const startOffset = range.startOffset;
|
|
1584
1674
|
const endOffset = range.endOffset;
|
|
1585
1675
|
|
|
1586
|
-
let first = selectedFormsts[0];
|
|
1587
|
-
let last = selectedFormsts[selectedFormsts.length - 1];
|
|
1588
|
-
const firstPath =
|
|
1589
|
-
const lastPath =
|
|
1676
|
+
let first = /** @type {Node} */ (selectedFormsts[0]);
|
|
1677
|
+
let last = /** @type {Node} */ (selectedFormsts[selectedFormsts.length - 1]);
|
|
1678
|
+
const firstPath = dom.query.getNodePath(range.startContainer, first, null);
|
|
1679
|
+
const lastPath = dom.query.getNodePath(range.endContainer, last, null);
|
|
1590
1680
|
|
|
1591
1681
|
// remove selected list
|
|
1592
1682
|
const rlist = this.removeList(selectedFormsts, false);
|
|
@@ -1594,7 +1684,7 @@ Format.prototype = {
|
|
|
1594
1684
|
if (rlist.ec) last = rlist.ec;
|
|
1595
1685
|
|
|
1596
1686
|
// change format tag
|
|
1597
|
-
this.selection.setRange(
|
|
1687
|
+
this.selection.setRange(dom.query.getNodeFromPath(firstPath, first), startOffset, dom.query.getNodeFromPath(lastPath, last), endOffset);
|
|
1598
1688
|
|
|
1599
1689
|
return {
|
|
1600
1690
|
lines: this.getLinesAndComponents(false),
|
|
@@ -1607,6 +1697,22 @@ Format.prototype = {
|
|
|
1607
1697
|
};
|
|
1608
1698
|
},
|
|
1609
1699
|
|
|
1700
|
+
/**
|
|
1701
|
+
* @private
|
|
1702
|
+
* @this {FormatThis}
|
|
1703
|
+
* @description Attaches a nested list structure by merging adjacent lists if applicable.
|
|
1704
|
+
* - Ensures that the nested list is placed correctly in the document structure.
|
|
1705
|
+
* @param {Element} originList The original list element where the nested list is inserted.
|
|
1706
|
+
* @param {Element} innerList The nested list element.
|
|
1707
|
+
* @param {Element} prev The previous sibling element.
|
|
1708
|
+
* @param {Element} next The next sibling element.
|
|
1709
|
+
* @param {{s: Array<number> | null, e: Array<number> | null, sl: Node | null, el: Node | null}} nodePath Object storing the start and end node paths.
|
|
1710
|
+
* - s : Start node path.
|
|
1711
|
+
* - e : End node path.
|
|
1712
|
+
* - sl : Start node's parent element.
|
|
1713
|
+
* - el : End node's parent element.
|
|
1714
|
+
* @returns {Node} The attached inner list.
|
|
1715
|
+
*/
|
|
1610
1716
|
_attachNested(originList, innerList, prev, next, nodePath) {
|
|
1611
1717
|
let insertPrev = false;
|
|
1612
1718
|
|
|
@@ -1632,7 +1738,7 @@ Format.prototype = {
|
|
|
1632
1738
|
}
|
|
1633
1739
|
|
|
1634
1740
|
if (!insertPrev) {
|
|
1635
|
-
if (
|
|
1741
|
+
if (dom.check.isListCell(prev)) {
|
|
1636
1742
|
originList = prev;
|
|
1637
1743
|
next = null;
|
|
1638
1744
|
}
|
|
@@ -1640,29 +1746,40 @@ Format.prototype = {
|
|
|
1640
1746
|
originList.insertBefore(innerList, next);
|
|
1641
1747
|
|
|
1642
1748
|
if (!nodePath.s) {
|
|
1643
|
-
nodePath.s =
|
|
1749
|
+
nodePath.s = dom.query.getNodePath(innerList.firstElementChild.firstChild, originList, null);
|
|
1644
1750
|
nodePath.sl = originList;
|
|
1645
1751
|
}
|
|
1646
1752
|
|
|
1647
|
-
const slPath = originList.contains(nodePath.sl) ?
|
|
1648
|
-
nodePath.e =
|
|
1753
|
+
const slPath = originList.contains(nodePath.sl) ? dom.query.getNodePath(nodePath.sl, originList) : null;
|
|
1754
|
+
nodePath.e = dom.query.getNodePath(innerList.lastElementChild.firstChild, originList, null);
|
|
1649
1755
|
nodePath.el = originList;
|
|
1650
1756
|
|
|
1651
1757
|
this.nodeTransform.mergeSameTags(originList, [nodePath.s, nodePath.e, slPath], false);
|
|
1652
1758
|
this.nodeTransform.mergeNestedTags(originList);
|
|
1653
|
-
if (slPath) nodePath.sl =
|
|
1759
|
+
if (slPath) nodePath.sl = dom.query.getNodeFromPath(slPath, originList);
|
|
1654
1760
|
}
|
|
1655
1761
|
|
|
1656
1762
|
return innerList;
|
|
1657
1763
|
},
|
|
1658
1764
|
|
|
1765
|
+
/**
|
|
1766
|
+
* @private
|
|
1767
|
+
* @this {FormatThis}
|
|
1768
|
+
* @description Detaches a nested list structure by extracting list items from their parent list.
|
|
1769
|
+
* - Ensures proper restructuring of the list elements.
|
|
1770
|
+
* @param {Array<HTMLElement>} cells The list items to be detached.
|
|
1771
|
+
* @returns {{cc: Node, sc: Node, ec: Node}} An object containing reference nodes for repositioning.
|
|
1772
|
+
* - cc : The parent node of the first list item.
|
|
1773
|
+
* - sc : The first list item.
|
|
1774
|
+
* - ec : The last list item.
|
|
1775
|
+
*/
|
|
1659
1776
|
_detachNested(cells) {
|
|
1660
1777
|
const first = cells[0];
|
|
1661
1778
|
const last = cells[cells.length - 1];
|
|
1662
1779
|
const next = last.nextElementSibling;
|
|
1663
|
-
const originList = first.
|
|
1664
|
-
const sibling = originList.
|
|
1665
|
-
const parentNode = originList.
|
|
1780
|
+
const originList = first.parentElement;
|
|
1781
|
+
const sibling = originList.parentElement.nextElementSibling;
|
|
1782
|
+
const parentNode = originList.parentElement.parentElement;
|
|
1666
1783
|
|
|
1667
1784
|
for (let c = 0, cLen = cells.length; c < cLen; c++) {
|
|
1668
1785
|
parentNode.insertBefore(cells[c], sibling);
|
|
@@ -1671,17 +1788,17 @@ Format.prototype = {
|
|
|
1671
1788
|
if (next && originList.children.length > 0) {
|
|
1672
1789
|
const newList = originList.cloneNode(false);
|
|
1673
1790
|
const children = originList.childNodes;
|
|
1674
|
-
const index =
|
|
1791
|
+
const index = dom.query.getPositionIndex(next);
|
|
1675
1792
|
while (children[index]) {
|
|
1676
1793
|
newList.appendChild(children[index]);
|
|
1677
1794
|
}
|
|
1678
1795
|
last.appendChild(newList);
|
|
1679
1796
|
}
|
|
1680
1797
|
|
|
1681
|
-
if (originList.children.length === 0)
|
|
1798
|
+
if (originList.children.length === 0) dom.utils.removeItem(originList);
|
|
1682
1799
|
this.nodeTransform.mergeSameTags(parentNode);
|
|
1683
1800
|
|
|
1684
|
-
const edge =
|
|
1801
|
+
const edge = dom.query.getEdgeChildNodes(first, last);
|
|
1685
1802
|
|
|
1686
1803
|
return {
|
|
1687
1804
|
cc: first.parentNode,
|
|
@@ -1691,19 +1808,20 @@ Format.prototype = {
|
|
|
1691
1808
|
},
|
|
1692
1809
|
|
|
1693
1810
|
/**
|
|
1811
|
+
* @private
|
|
1812
|
+
* @this {FormatThis}
|
|
1694
1813
|
* @description Nest list cells or cancel nested cells.
|
|
1695
1814
|
* @param selectedCells List cells.
|
|
1696
1815
|
* @param nested Nested or cancel nested.
|
|
1697
|
-
* @private
|
|
1698
1816
|
*/
|
|
1699
1817
|
_applyNestedList(selectedCells, nested) {
|
|
1700
1818
|
selectedCells = !selectedCells
|
|
1701
1819
|
? this.getLines().filter(function (el) {
|
|
1702
|
-
return
|
|
1820
|
+
return dom.check.isListCell(el);
|
|
1703
1821
|
})
|
|
1704
1822
|
: selectedCells;
|
|
1705
1823
|
const cellsLen = selectedCells.length;
|
|
1706
|
-
if (cellsLen === 0 || (!nested && !
|
|
1824
|
+
if (cellsLen === 0 || (!nested && !dom.check.isListCell(selectedCells[0].previousElementSibling) && !dom.check.isListCell(selectedCells[cellsLen - 1].nextElementSibling))) {
|
|
1707
1825
|
return {
|
|
1708
1826
|
sc: selectedCells[0],
|
|
1709
1827
|
so: 0,
|
|
@@ -1717,7 +1835,7 @@ Format.prototype = {
|
|
|
1717
1835
|
let range = null;
|
|
1718
1836
|
|
|
1719
1837
|
if (nested) {
|
|
1720
|
-
if (originList !== lastCell.parentNode &&
|
|
1838
|
+
if (originList !== lastCell.parentNode && dom.check.isList(lastCell.parentNode.parentNode) && lastCell.nextElementSibling) {
|
|
1721
1839
|
lastCell = lastCell.nextElementSibling;
|
|
1722
1840
|
while (lastCell) {
|
|
1723
1841
|
selectedCells.push(lastCell);
|
|
@@ -1726,7 +1844,7 @@ Format.prototype = {
|
|
|
1726
1844
|
}
|
|
1727
1845
|
range = this.applyList(originList.nodeName + ':' + originList.style.listStyleType, selectedCells, true);
|
|
1728
1846
|
} else {
|
|
1729
|
-
let innerList =
|
|
1847
|
+
let innerList = dom.utils.createElement(originList.nodeName);
|
|
1730
1848
|
let prev = selectedCells[0].previousElementSibling;
|
|
1731
1849
|
let next = lastCell.nextElementSibling;
|
|
1732
1850
|
const nodePath = {
|
|
@@ -1741,7 +1859,7 @@ Format.prototype = {
|
|
|
1741
1859
|
if (c.parentNode !== originList) {
|
|
1742
1860
|
this._attachNested(originList, innerList, prev, next, nodePath);
|
|
1743
1861
|
originList = c.parentNode;
|
|
1744
|
-
innerList =
|
|
1862
|
+
innerList = dom.utils.createElement(originList.nodeName);
|
|
1745
1863
|
}
|
|
1746
1864
|
|
|
1747
1865
|
prev = c.previousElementSibling;
|
|
@@ -1751,8 +1869,8 @@ Format.prototype = {
|
|
|
1751
1869
|
|
|
1752
1870
|
this._attachNested(originList, innerList, prev, next, nodePath);
|
|
1753
1871
|
|
|
1754
|
-
const sc =
|
|
1755
|
-
const ec =
|
|
1872
|
+
const sc = dom.query.getNodeFromPath(nodePath.s, nodePath.sl);
|
|
1873
|
+
const ec = dom.query.getNodeFromPath(nodePath.e, nodePath.el);
|
|
1756
1874
|
range = {
|
|
1757
1875
|
sc: sc,
|
|
1758
1876
|
so: 0,
|
|
@@ -1765,12 +1883,13 @@ Format.prototype = {
|
|
|
1765
1883
|
},
|
|
1766
1884
|
|
|
1767
1885
|
/**
|
|
1886
|
+
* @private
|
|
1887
|
+
* @this {FormatThis}
|
|
1768
1888
|
* @description Detach Nested all nested lists under the "baseNode".
|
|
1769
|
-
* Returns a list with nested removed.
|
|
1770
|
-
* @param {
|
|
1889
|
+
* - Returns a list with nested removed.
|
|
1890
|
+
* @param {HTMLElement} baseNode Element on which to base.
|
|
1771
1891
|
* @param {boolean} all If true, it also detach all nested lists of a returned list.
|
|
1772
|
-
* @returns {
|
|
1773
|
-
* @private
|
|
1892
|
+
* @returns {Node} Result element
|
|
1774
1893
|
*/
|
|
1775
1894
|
_removeNestedList(baseNode, all) {
|
|
1776
1895
|
const rNode = DeleteNestedList(baseNode);
|
|
@@ -1779,7 +1898,7 @@ Format.prototype = {
|
|
|
1779
1898
|
if (rNode) {
|
|
1780
1899
|
rangeElement = rNode.cloneNode(false);
|
|
1781
1900
|
cNodes = rNode.childNodes;
|
|
1782
|
-
const index =
|
|
1901
|
+
const index = dom.query.getPositionIndex(baseNode);
|
|
1783
1902
|
while (cNodes[index]) {
|
|
1784
1903
|
rangeElement.appendChild(cNodes[index]);
|
|
1785
1904
|
}
|
|
@@ -1789,13 +1908,13 @@ Format.prototype = {
|
|
|
1789
1908
|
|
|
1790
1909
|
let rChildren;
|
|
1791
1910
|
if (!all) {
|
|
1792
|
-
const depth =
|
|
1793
|
-
rChildren =
|
|
1794
|
-
return
|
|
1911
|
+
const depth = dom.query.getNodeDepth(baseNode) + 2;
|
|
1912
|
+
rChildren = dom.query.getListChildren(baseNode, (current) => {
|
|
1913
|
+
return dom.check.isListCell(current) && !current.previousElementSibling && dom.query.getNodeDepth(current) === depth;
|
|
1795
1914
|
});
|
|
1796
1915
|
} else {
|
|
1797
|
-
rChildren =
|
|
1798
|
-
return
|
|
1916
|
+
rChildren = dom.query.getListChildren(rangeElement, (current) => {
|
|
1917
|
+
return dom.check.isListCell(current) && !current.previousElementSibling;
|
|
1799
1918
|
});
|
|
1800
1919
|
}
|
|
1801
1920
|
|
|
@@ -1805,17 +1924,19 @@ Format.prototype = {
|
|
|
1805
1924
|
|
|
1806
1925
|
if (rNode) {
|
|
1807
1926
|
rNode.parentNode.insertBefore(rangeElement, rNode.nextSibling);
|
|
1808
|
-
if (cNodes?.length === 0)
|
|
1927
|
+
if (cNodes?.length === 0) dom.utils.removeItem(rNode);
|
|
1809
1928
|
}
|
|
1810
1929
|
|
|
1811
1930
|
return rangeElement === baseNode ? rangeElement.parentNode : rangeElement;
|
|
1812
1931
|
},
|
|
1813
1932
|
|
|
1814
1933
|
/**
|
|
1934
|
+
* @private
|
|
1935
|
+
* @this {FormatThis}
|
|
1815
1936
|
* @description wraps text nodes of line selected text.
|
|
1816
|
-
* @param {
|
|
1817
|
-
* @param {
|
|
1818
|
-
* @param {
|
|
1937
|
+
* @param {Node} element The node of the line that contains the selected text node.
|
|
1938
|
+
* @param {Node} newInnerNode The dom that will wrap the selected text area
|
|
1939
|
+
* @param {(current: Node) => Node|null} validation Check if the node should be stripped.
|
|
1819
1940
|
* @param {Node} startCon The startContainer property of the selection object.
|
|
1820
1941
|
* @param {number} startOff The startOffset property of the selection object.
|
|
1821
1942
|
* @param {Node} endCon The endContainer property of the selection object.
|
|
@@ -1824,24 +1945,23 @@ Format.prototype = {
|
|
|
1824
1945
|
* @param {boolean} isRemoveNode "newInnerNode" is remove node?
|
|
1825
1946
|
* @param {boolean} collapsed range.collapsed
|
|
1826
1947
|
* @returns {{ancestor: *, startContainer: *, startOffset: *, endContainer: *, endOffset: *}}
|
|
1827
|
-
* @private
|
|
1828
1948
|
*/
|
|
1829
1949
|
_setNode_oneLine(element, newInnerNode, validation, startCon, startOff, endCon, endOff, isRemoveFormat, isRemoveNode, collapsed, _removeCheck, _getMaintainedNode, _isMaintainedNode) {
|
|
1830
1950
|
// not add tag
|
|
1831
1951
|
let parentCon = startCon.parentNode;
|
|
1832
|
-
while (!parentCon.nextSibling && !parentCon.previousSibling && !this.isLine(parentCon.parentNode) && !
|
|
1952
|
+
while (!parentCon.nextSibling && !parentCon.previousSibling && !this.isLine(parentCon.parentNode) && !dom.check.isWysiwygFrame(parentCon.parentNode)) {
|
|
1833
1953
|
if (parentCon.nodeName === newInnerNode.nodeName) break;
|
|
1834
1954
|
parentCon = parentCon.parentNode;
|
|
1835
1955
|
}
|
|
1836
1956
|
|
|
1837
1957
|
if (!isRemoveNode && parentCon === endCon.parentNode && parentCon.nodeName === newInnerNode.nodeName) {
|
|
1838
|
-
if (
|
|
1958
|
+
if (dom.check.isZeroWidth(startCon.textContent.slice(0, startOff)) && dom.check.isZeroWidth(endCon.textContent.slice(endOff))) {
|
|
1839
1959
|
const children = parentCon.childNodes;
|
|
1840
1960
|
let sameTag = false;
|
|
1841
1961
|
|
|
1842
1962
|
for (let i = 0, len = children.length, c, s, e, z; i < len; i++) {
|
|
1843
1963
|
c = children[i];
|
|
1844
|
-
z = !
|
|
1964
|
+
z = !dom.check.isZeroWidth(c);
|
|
1845
1965
|
if (c === startCon) {
|
|
1846
1966
|
s = true;
|
|
1847
1967
|
continue;
|
|
@@ -1857,7 +1977,7 @@ Format.prototype = {
|
|
|
1857
1977
|
}
|
|
1858
1978
|
|
|
1859
1979
|
if (sameTag) {
|
|
1860
|
-
|
|
1980
|
+
dom.utils.copyTagAttributes(parentCon, newInnerNode);
|
|
1861
1981
|
|
|
1862
1982
|
return {
|
|
1863
1983
|
ancestor: element,
|
|
@@ -1889,7 +2009,7 @@ Format.prototype = {
|
|
|
1889
2009
|
const wRegExp = RegExp;
|
|
1890
2010
|
function checkCss(vNode) {
|
|
1891
2011
|
const regExp = new wRegExp('(?:;|^|\\s)(?:' + cssText + 'null)\\s*:[^;]*\\s*(?:;|$)', 'ig');
|
|
1892
|
-
let style =
|
|
2012
|
+
let style = false;
|
|
1893
2013
|
|
|
1894
2014
|
if (regExp && vNode.style.cssText.length > 0) {
|
|
1895
2015
|
style = regExp.test(vNode.style.cssText);
|
|
@@ -1911,12 +2031,17 @@ Format.prototype = {
|
|
|
1911
2031
|
if (!startPass && child === startContainer) {
|
|
1912
2032
|
let line = pNode;
|
|
1913
2033
|
anchorNode = _getMaintainedNode(child);
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
2034
|
+
|
|
2035
|
+
let _prevText = '';
|
|
2036
|
+
let _nextText = '';
|
|
2037
|
+
if (startContainer.nodeType === 3) {
|
|
2038
|
+
const sText = /** @type {Text} */ (startContainer);
|
|
2039
|
+
_prevText = sText.substringData(0, startOffset);
|
|
2040
|
+
_nextText = sText.substringData(startOffset, isSameNode ? (endOffset >= startOffset ? endOffset - startOffset : sText.data.length - startOffset) : sText.data.length - startOffset);
|
|
2041
|
+
}
|
|
2042
|
+
|
|
2043
|
+
const prevNode = dom.utils.createTextNode(_prevText);
|
|
2044
|
+
const textNode = dom.utils.createTextNode(_nextText);
|
|
1920
2045
|
|
|
1921
2046
|
if (anchorNode) {
|
|
1922
2047
|
const a = _getMaintainedNode(ancestor);
|
|
@@ -1936,7 +2061,7 @@ Format.prototype = {
|
|
|
1936
2061
|
anchorNode = anchorNode.cloneNode(false);
|
|
1937
2062
|
}
|
|
1938
2063
|
|
|
1939
|
-
if (!
|
|
2064
|
+
if (!dom.check.isZeroWidth(prevNode)) {
|
|
1940
2065
|
ancestor.appendChild(prevNode);
|
|
1941
2066
|
}
|
|
1942
2067
|
|
|
@@ -1944,16 +2069,16 @@ Format.prototype = {
|
|
|
1944
2069
|
if (prevAnchorNode) anchorNode = prevAnchorNode;
|
|
1945
2070
|
if (anchorNode) line = anchorNode;
|
|
1946
2071
|
|
|
1947
|
-
newNode = child;
|
|
2072
|
+
newNode = /** @type {HTMLElement} */ (child);
|
|
1948
2073
|
pCurrent = [];
|
|
1949
2074
|
cssText = '';
|
|
1950
2075
|
while (newNode !== line && newNode !== el && newNode !== null) {
|
|
1951
2076
|
vNode = _isMaintainedNode(newNode) ? null : validation(newNode);
|
|
1952
2077
|
if (vNode && newNode.nodeType === 1 && checkCss(newNode)) {
|
|
1953
2078
|
pCurrent.push(vNode);
|
|
1954
|
-
cssText += newNode.style.cssText.
|
|
2079
|
+
cssText += newNode.style.cssText.substring(0, newNode.style.cssText.indexOf(':')) + '|';
|
|
1955
2080
|
}
|
|
1956
|
-
newNode = newNode.
|
|
2081
|
+
newNode = newNode.parentElement;
|
|
1957
2082
|
}
|
|
1958
2083
|
|
|
1959
2084
|
const childNode = pCurrent.pop() || textNode;
|
|
@@ -1984,8 +2109,17 @@ Format.prototype = {
|
|
|
1984
2109
|
// endContainer
|
|
1985
2110
|
if (!endPass && child === endContainer) {
|
|
1986
2111
|
anchorNode = _getMaintainedNode(child);
|
|
1987
|
-
|
|
1988
|
-
|
|
2112
|
+
|
|
2113
|
+
let _prevText = '';
|
|
2114
|
+
let _nextText = '';
|
|
2115
|
+
if (endContainer.nodeType === 3) {
|
|
2116
|
+
const eText = /** @type {Text} */ (endContainer);
|
|
2117
|
+
_prevText = eText.substringData(endOffset, eText.length - endOffset);
|
|
2118
|
+
_nextText = isSameNode ? '' : eText.substringData(0, endOffset);
|
|
2119
|
+
}
|
|
2120
|
+
|
|
2121
|
+
const afterNode = dom.utils.createTextNode(_prevText);
|
|
2122
|
+
const textNode = dom.utils.createTextNode(_nextText);
|
|
1989
2123
|
|
|
1990
2124
|
if (anchorNode) {
|
|
1991
2125
|
anchorNode = anchorNode.cloneNode(false);
|
|
@@ -1995,8 +2129,8 @@ Format.prototype = {
|
|
|
1995
2129
|
nNodeArray.push(newInnerNode);
|
|
1996
2130
|
}
|
|
1997
2131
|
|
|
1998
|
-
if (!
|
|
1999
|
-
newNode = child;
|
|
2132
|
+
if (!dom.check.isZeroWidth(afterNode)) {
|
|
2133
|
+
newNode = /** @type {HTMLElement} */ (child);
|
|
2000
2134
|
cssText = '';
|
|
2001
2135
|
pCurrent = [];
|
|
2002
2136
|
const anchors = [];
|
|
@@ -2004,9 +2138,9 @@ Format.prototype = {
|
|
|
2004
2138
|
if (newNode.nodeType === 1 && checkCss(newNode)) {
|
|
2005
2139
|
if (_isMaintainedNode(newNode)) anchors.push(newNode.cloneNode(false));
|
|
2006
2140
|
else pCurrent.push(newNode.cloneNode(false));
|
|
2007
|
-
cssText += newNode.style.cssText.
|
|
2141
|
+
cssText += newNode.style.cssText.substring(0, newNode.style.cssText.indexOf(':')) + '|';
|
|
2008
2142
|
}
|
|
2009
|
-
newNode = newNode.
|
|
2143
|
+
newNode = newNode.parentElement;
|
|
2010
2144
|
}
|
|
2011
2145
|
pCurrent = pCurrent.concat(anchors);
|
|
2012
2146
|
|
|
@@ -2028,16 +2162,16 @@ Format.prototype = {
|
|
|
2028
2162
|
}
|
|
2029
2163
|
}
|
|
2030
2164
|
|
|
2031
|
-
newNode = child;
|
|
2165
|
+
newNode = /** @type {HTMLElement} */ (child);
|
|
2032
2166
|
pCurrent = [];
|
|
2033
2167
|
cssText = '';
|
|
2034
2168
|
while (newNode !== pNode && newNode !== el && newNode !== null) {
|
|
2035
2169
|
vNode = _isMaintainedNode(newNode) ? null : validation(newNode);
|
|
2036
2170
|
if (vNode && newNode.nodeType === 1 && checkCss(newNode)) {
|
|
2037
2171
|
pCurrent.push(vNode);
|
|
2038
|
-
cssText += newNode.style.cssText.
|
|
2172
|
+
cssText += newNode.style.cssText.substring(0, newNode.style.cssText.indexOf(':')) + '|';
|
|
2039
2173
|
}
|
|
2040
|
-
newNode = newNode.
|
|
2174
|
+
newNode = newNode.parentElement;
|
|
2041
2175
|
}
|
|
2042
2176
|
|
|
2043
2177
|
const childNode = pCurrent.pop() || textNode;
|
|
@@ -2074,7 +2208,7 @@ Format.prototype = {
|
|
|
2074
2208
|
|
|
2075
2209
|
// other
|
|
2076
2210
|
if (startPass) {
|
|
2077
|
-
if (child.nodeType === 1 && !
|
|
2211
|
+
if (child.nodeType === 1 && !dom.check.isBreak(child)) {
|
|
2078
2212
|
if (inst._isIgnoreNodeChange(child)) {
|
|
2079
2213
|
pNode.appendChild(child.cloneNode(true));
|
|
2080
2214
|
if (!collapsed) {
|
|
@@ -2088,21 +2222,21 @@ Format.prototype = {
|
|
|
2088
2222
|
continue;
|
|
2089
2223
|
}
|
|
2090
2224
|
|
|
2091
|
-
newNode = child;
|
|
2225
|
+
newNode = /** @type {HTMLElement} */ (child);
|
|
2092
2226
|
pCurrent = [];
|
|
2093
2227
|
cssText = '';
|
|
2094
2228
|
const anchors = [];
|
|
2095
2229
|
while (newNode.parentNode !== null && newNode !== el && newNode !== newInnerNode) {
|
|
2096
2230
|
vNode = endPass ? newNode.cloneNode(false) : validation(newNode);
|
|
2097
|
-
if (newNode.nodeType === 1 && !
|
|
2231
|
+
if (newNode.nodeType === 1 && !dom.check.isBreak(child) && vNode && checkCss(newNode)) {
|
|
2098
2232
|
if (_isMaintainedNode(newNode)) {
|
|
2099
2233
|
if (!anchorNode) anchors.push(vNode);
|
|
2100
2234
|
} else {
|
|
2101
2235
|
pCurrent.push(vNode);
|
|
2102
2236
|
}
|
|
2103
|
-
cssText += newNode.style.cssText.
|
|
2237
|
+
cssText += newNode.style.cssText.substring(0, newNode.style.cssText.indexOf(':')) + '|';
|
|
2104
2238
|
}
|
|
2105
|
-
newNode = newNode.
|
|
2239
|
+
newNode = newNode.parentElement;
|
|
2106
2240
|
}
|
|
2107
2241
|
pCurrent = pCurrent.concat(anchors);
|
|
2108
2242
|
|
|
@@ -2114,7 +2248,7 @@ Format.prototype = {
|
|
|
2114
2248
|
appendNode = newNode;
|
|
2115
2249
|
}
|
|
2116
2250
|
|
|
2117
|
-
if (_isMaintainedNode(newInnerNode.parentNode) && !_isMaintainedNode(childNode) && !
|
|
2251
|
+
if (_isMaintainedNode(newInnerNode.parentNode) && !_isMaintainedNode(childNode) && !dom.check.isZeroWidth(newInnerNode)) {
|
|
2118
2252
|
newInnerNode = newInnerNode.cloneNode(false);
|
|
2119
2253
|
pNode.appendChild(newInnerNode);
|
|
2120
2254
|
nNodeArray.push(newInnerNode);
|
|
@@ -2129,7 +2263,7 @@ Format.prototype = {
|
|
|
2129
2263
|
childNode.appendChild(newInnerNode);
|
|
2130
2264
|
pNode.appendChild(childNode);
|
|
2131
2265
|
nNodeArray.push(newInnerNode);
|
|
2132
|
-
if (newInnerNode.children.length > 0) ancestor = newNode;
|
|
2266
|
+
if (/** @type {HTMLElement} */ (newInnerNode).children.length > 0) ancestor = newNode;
|
|
2133
2267
|
else ancestor = newInnerNode;
|
|
2134
2268
|
} else if (childNode === child) {
|
|
2135
2269
|
if (!endPass) ancestor = newInnerNode;
|
|
@@ -2144,7 +2278,7 @@ Format.prototype = {
|
|
|
2144
2278
|
|
|
2145
2279
|
if (anchorNode && child.nodeType === 3) {
|
|
2146
2280
|
if (_getMaintainedNode(child)) {
|
|
2147
|
-
const ancestorAnchorNode =
|
|
2281
|
+
const ancestorAnchorNode = dom.query.getParentElement(ancestor, (c) => {
|
|
2148
2282
|
return inst._isNonSplitNode(c.parentNode) || c.parentNode === pNode;
|
|
2149
2283
|
});
|
|
2150
2284
|
anchorNode.appendChild(ancestorAnchorNode);
|
|
@@ -2159,7 +2293,7 @@ Format.prototype = {
|
|
|
2159
2293
|
|
|
2160
2294
|
cloneNode = child.cloneNode(false);
|
|
2161
2295
|
ancestor.appendChild(cloneNode);
|
|
2162
|
-
if (child.nodeType === 1 && !
|
|
2296
|
+
if (child.nodeType === 1 && !dom.check.isBreak(child)) coverNode = cloneNode;
|
|
2163
2297
|
|
|
2164
2298
|
recursionFunc(child, coverNode);
|
|
2165
2299
|
}
|
|
@@ -2184,7 +2318,7 @@ Format.prototype = {
|
|
|
2184
2318
|
let textNode, textNode_s, textNode_e;
|
|
2185
2319
|
|
|
2186
2320
|
if (collapsed) {
|
|
2187
|
-
textNode =
|
|
2321
|
+
textNode = dom.utils.createTextNode(unicode.zeroWidthSpace);
|
|
2188
2322
|
pNode.replaceChild(textNode, removeNode);
|
|
2189
2323
|
} else {
|
|
2190
2324
|
const rChildren = removeNode.childNodes;
|
|
@@ -2193,7 +2327,7 @@ Format.prototype = {
|
|
|
2193
2327
|
textNode_e = rChildren[0];
|
|
2194
2328
|
pNode.insertBefore(textNode_e, removeNode);
|
|
2195
2329
|
}
|
|
2196
|
-
|
|
2330
|
+
dom.utils.removeItem(removeNode);
|
|
2197
2331
|
}
|
|
2198
2332
|
|
|
2199
2333
|
if (i === 0) {
|
|
@@ -2227,8 +2361,8 @@ Format.prototype = {
|
|
|
2227
2361
|
// endContainer reset
|
|
2228
2362
|
const endConReset = isRemoveFormat || endContainer.textContent.length === 0;
|
|
2229
2363
|
|
|
2230
|
-
if (!
|
|
2231
|
-
|
|
2364
|
+
if (!dom.check.isBreak(endContainer) && endContainer.textContent.length === 0) {
|
|
2365
|
+
dom.utils.removeItem(endContainer);
|
|
2232
2366
|
endContainer = startContainer;
|
|
2233
2367
|
}
|
|
2234
2368
|
endOffset = endConReset ? endContainer.textContent.length : endOffset;
|
|
@@ -2238,7 +2372,7 @@ Format.prototype = {
|
|
|
2238
2372
|
s: 0,
|
|
2239
2373
|
e: 0
|
|
2240
2374
|
};
|
|
2241
|
-
const startPath =
|
|
2375
|
+
const startPath = dom.query.getNodePath(startContainer, pNode, newStartOffset);
|
|
2242
2376
|
|
|
2243
2377
|
const mergeEndCon = !endContainer.parentNode;
|
|
2244
2378
|
if (mergeEndCon) endContainer = startContainer;
|
|
@@ -2246,7 +2380,7 @@ Format.prototype = {
|
|
|
2246
2380
|
s: 0,
|
|
2247
2381
|
e: 0
|
|
2248
2382
|
};
|
|
2249
|
-
const endPath =
|
|
2383
|
+
const endPath = dom.query.getNodePath(endContainer, pNode, !mergeEndCon && !endConReset ? newEndOffset : null);
|
|
2250
2384
|
|
|
2251
2385
|
startOffset += newStartOffset.s;
|
|
2252
2386
|
endOffset = collapsed ? startOffset : mergeEndCon ? startContainer.textContent.length : endConReset ? endOffset + newStartOffset.s : endOffset + newEndOffset.s;
|
|
@@ -2256,8 +2390,8 @@ Format.prototype = {
|
|
|
2256
2390
|
|
|
2257
2391
|
element.parentNode.replaceChild(pNode, element);
|
|
2258
2392
|
|
|
2259
|
-
startContainer =
|
|
2260
|
-
endContainer =
|
|
2393
|
+
startContainer = dom.query.getNodeFromPath(startPath, pNode);
|
|
2394
|
+
endContainer = dom.query.getNodeFromPath(endPath, pNode);
|
|
2261
2395
|
|
|
2262
2396
|
return {
|
|
2263
2397
|
ancestor: pNode,
|
|
@@ -2269,31 +2403,31 @@ Format.prototype = {
|
|
|
2269
2403
|
},
|
|
2270
2404
|
|
|
2271
2405
|
/**
|
|
2406
|
+
* @private
|
|
2407
|
+
* @this {FormatThis}
|
|
2272
2408
|
* @description wraps first line selected text.
|
|
2273
|
-
* @param {
|
|
2274
|
-
* @param {
|
|
2275
|
-
* @param {
|
|
2409
|
+
* @param {Node} element The node of the line that contains the selected text node.
|
|
2410
|
+
* @param {Node} newInnerNode The dom that will wrap the selected text area
|
|
2411
|
+
* @param {(current: Node) => Node|null} validation Check if the node should be stripped.
|
|
2276
2412
|
* @param {Node} startCon The startContainer property of the selection object.
|
|
2277
2413
|
* @param {number} startOff The startOffset property of the selection object.
|
|
2278
2414
|
* @param {boolean} isRemoveFormat Is the remove all formats command?
|
|
2279
2415
|
* @param {boolean} isRemoveNode "newInnerNode" is remove node?
|
|
2280
|
-
* @returns {
|
|
2281
|
-
* @returns {Object} { ancestor, container, offset, endContainer }
|
|
2282
|
-
* @private
|
|
2416
|
+
* @returns {NodeStyleContainerType} { ancestor, container, offset, endContainer }
|
|
2283
2417
|
*/
|
|
2284
2418
|
_setNode_startLine(element, newInnerNode, validation, startCon, startOff, isRemoveFormat, isRemoveNode, _removeCheck, _getMaintainedNode, _isMaintainedNode, _endContainer) {
|
|
2285
2419
|
// not add tag
|
|
2286
2420
|
let parentCon = startCon.parentNode;
|
|
2287
|
-
while (!parentCon.nextSibling && !parentCon.previousSibling && !this.isLine(parentCon.parentNode) && !
|
|
2421
|
+
while (!parentCon.nextSibling && !parentCon.previousSibling && !this.isLine(parentCon.parentNode) && !dom.check.isWysiwygFrame(parentCon.parentNode)) {
|
|
2288
2422
|
if (parentCon.nodeName === newInnerNode.nodeName) break;
|
|
2289
2423
|
parentCon = parentCon.parentNode;
|
|
2290
2424
|
}
|
|
2291
2425
|
|
|
2292
|
-
if (!isRemoveNode && parentCon.nodeName === newInnerNode.nodeName && !this.isLine(parentCon) && !parentCon.nextSibling &&
|
|
2426
|
+
if (!isRemoveNode && parentCon.nodeName === newInnerNode.nodeName && !this.isLine(parentCon) && !parentCon.nextSibling && dom.check.isZeroWidth(startCon.textContent.slice(0, startOff))) {
|
|
2293
2427
|
let sameTag = false;
|
|
2294
2428
|
let s = startCon.previousSibling;
|
|
2295
2429
|
while (s) {
|
|
2296
|
-
if (!
|
|
2430
|
+
if (!dom.check.isZeroWidth(s)) {
|
|
2297
2431
|
sameTag = false;
|
|
2298
2432
|
break;
|
|
2299
2433
|
}
|
|
@@ -2301,7 +2435,7 @@ Format.prototype = {
|
|
|
2301
2435
|
}
|
|
2302
2436
|
|
|
2303
2437
|
if (sameTag) {
|
|
2304
|
-
|
|
2438
|
+
dom.utils.copyTagAttributes(parentCon, newInnerNode);
|
|
2305
2439
|
|
|
2306
2440
|
return {
|
|
2307
2441
|
ancestor: element,
|
|
@@ -2328,11 +2462,11 @@ Format.prototype = {
|
|
|
2328
2462
|
const childNodes = current.childNodes;
|
|
2329
2463
|
|
|
2330
2464
|
for (let i = 0, len = childNodes.length, vNode, cloneChild; i < len; i++) {
|
|
2331
|
-
const child = childNodes[i];
|
|
2465
|
+
const child = /** @type {HTMLElement} */ (childNodes[i]);
|
|
2332
2466
|
if (!child) continue;
|
|
2333
2467
|
let coverNode = ancestor;
|
|
2334
2468
|
|
|
2335
|
-
if (passNode && !
|
|
2469
|
+
if (passNode && !dom.check.isBreak(child)) {
|
|
2336
2470
|
if (child.nodeType === 1) {
|
|
2337
2471
|
if (inst._isIgnoreNodeChange(child)) {
|
|
2338
2472
|
newInnerNode = newInnerNode.cloneNode(false);
|
|
@@ -2343,8 +2477,8 @@ Format.prototype = {
|
|
|
2343
2477
|
|
|
2344
2478
|
// end container
|
|
2345
2479
|
if (_endContainer && child.contains(_endContainer)) {
|
|
2346
|
-
const endPath =
|
|
2347
|
-
_endContainer =
|
|
2480
|
+
const endPath = dom.query.getNodePath(_endContainer, child);
|
|
2481
|
+
_endContainer = dom.query.getNodeFromPath(endPath, cloneChild);
|
|
2348
2482
|
}
|
|
2349
2483
|
} else {
|
|
2350
2484
|
recursionFunc(child, child);
|
|
@@ -2402,7 +2536,7 @@ Format.prototype = {
|
|
|
2402
2536
|
|
|
2403
2537
|
if (anchorNode && child.nodeType === 3) {
|
|
2404
2538
|
if (_getMaintainedNode(child)) {
|
|
2405
|
-
const ancestorAnchorNode =
|
|
2539
|
+
const ancestorAnchorNode = dom.query.getParentElement(ancestor, (c) => {
|
|
2406
2540
|
return inst._isNonSplitNode(c.parentNode) || c.parentNode === pNode;
|
|
2407
2541
|
});
|
|
2408
2542
|
anchorNode.appendChild(ancestorAnchorNode);
|
|
@@ -2419,8 +2553,17 @@ Format.prototype = {
|
|
|
2419
2553
|
if (!passNode && child === container) {
|
|
2420
2554
|
let line = pNode;
|
|
2421
2555
|
anchorNode = _getMaintainedNode(child);
|
|
2422
|
-
|
|
2423
|
-
|
|
2556
|
+
|
|
2557
|
+
let _prevText = '';
|
|
2558
|
+
let _nextText = '';
|
|
2559
|
+
if (container.nodeType === 3) {
|
|
2560
|
+
const cText = /** @type {Text} */ (container);
|
|
2561
|
+
_prevText = cText.substringData(0, offset);
|
|
2562
|
+
_nextText = cText.substringData(offset, cText.length - offset);
|
|
2563
|
+
}
|
|
2564
|
+
|
|
2565
|
+
const prevNode = dom.utils.createTextNode(_prevText);
|
|
2566
|
+
const textNode = dom.utils.createTextNode(_nextText);
|
|
2424
2567
|
|
|
2425
2568
|
if (anchorNode) {
|
|
2426
2569
|
const a = _getMaintainedNode(ancestor);
|
|
@@ -2440,7 +2583,7 @@ Format.prototype = {
|
|
|
2440
2583
|
anchorNode = anchorNode.cloneNode(false);
|
|
2441
2584
|
}
|
|
2442
2585
|
|
|
2443
|
-
if (!
|
|
2586
|
+
if (!dom.check.isZeroWidth(prevNode)) {
|
|
2444
2587
|
ancestor.appendChild(prevNode);
|
|
2445
2588
|
}
|
|
2446
2589
|
|
|
@@ -2473,7 +2616,7 @@ Format.prototype = {
|
|
|
2473
2616
|
ancestor = newInnerNode;
|
|
2474
2617
|
}
|
|
2475
2618
|
|
|
2476
|
-
if (
|
|
2619
|
+
if (dom.check.isBreak(child)) newInnerNode.appendChild(child.cloneNode(false));
|
|
2477
2620
|
line.appendChild(newInnerNode);
|
|
2478
2621
|
|
|
2479
2622
|
container = textNode;
|
|
@@ -2487,7 +2630,7 @@ Format.prototype = {
|
|
|
2487
2630
|
vNode = !passNode ? child.cloneNode(false) : validation(child);
|
|
2488
2631
|
if (vNode) {
|
|
2489
2632
|
ancestor.appendChild(vNode);
|
|
2490
|
-
if (child.nodeType === 1 && !
|
|
2633
|
+
if (child.nodeType === 1 && !dom.check.isBreak(child)) coverNode = vNode;
|
|
2491
2634
|
}
|
|
2492
2635
|
|
|
2493
2636
|
recursionFunc(child, coverNode);
|
|
@@ -2515,7 +2658,7 @@ Format.prototype = {
|
|
|
2515
2658
|
while (rChildren[0]) {
|
|
2516
2659
|
pNode.insertBefore(rChildren[0], removeNode);
|
|
2517
2660
|
}
|
|
2518
|
-
|
|
2661
|
+
dom.utils.removeItem(removeNode);
|
|
2519
2662
|
|
|
2520
2663
|
if (i === 0) container = textNode;
|
|
2521
2664
|
}
|
|
@@ -2530,13 +2673,13 @@ Format.prototype = {
|
|
|
2530
2673
|
if (element.childNodes) {
|
|
2531
2674
|
container = element.childNodes[0];
|
|
2532
2675
|
} else {
|
|
2533
|
-
container =
|
|
2676
|
+
container = dom.utils.createTextNode(unicode.zeroWidthSpace);
|
|
2534
2677
|
element.appendChild(container);
|
|
2535
2678
|
}
|
|
2536
2679
|
} else {
|
|
2537
2680
|
this.nodeTransform.removeEmptyNode(pNode, newInnerNode, false);
|
|
2538
2681
|
|
|
2539
|
-
if (
|
|
2682
|
+
if (dom.check.isZeroWidth(pNode.textContent)) {
|
|
2540
2683
|
container = pNode.firstChild;
|
|
2541
2684
|
offset = 0;
|
|
2542
2685
|
}
|
|
@@ -2546,7 +2689,7 @@ Format.prototype = {
|
|
|
2546
2689
|
s: 0,
|
|
2547
2690
|
e: 0
|
|
2548
2691
|
};
|
|
2549
|
-
const path =
|
|
2692
|
+
const path = dom.query.getNodePath(container, pNode, offsets);
|
|
2550
2693
|
offset += offsets.s;
|
|
2551
2694
|
|
|
2552
2695
|
// tag merge
|
|
@@ -2554,7 +2697,7 @@ Format.prototype = {
|
|
|
2554
2697
|
|
|
2555
2698
|
element.parentNode.replaceChild(pNode, element);
|
|
2556
2699
|
|
|
2557
|
-
container =
|
|
2700
|
+
container = dom.query.getNodeFromPath(path, pNode);
|
|
2558
2701
|
offset += newOffsets[0];
|
|
2559
2702
|
}
|
|
2560
2703
|
|
|
@@ -2567,38 +2710,39 @@ Format.prototype = {
|
|
|
2567
2710
|
},
|
|
2568
2711
|
|
|
2569
2712
|
/**
|
|
2713
|
+
* @private
|
|
2714
|
+
* @this {FormatThis}
|
|
2570
2715
|
* @description wraps mid lines selected text.
|
|
2571
|
-
* @param {
|
|
2572
|
-
* @param {
|
|
2573
|
-
* @param {
|
|
2716
|
+
* @param {HTMLElement} element The node of the line that contains the selected text node.
|
|
2717
|
+
* @param {Node} newInnerNode The dom that will wrap the selected text area
|
|
2718
|
+
* @param {(current: Node) => Node|null} validation Check if the node should be stripped.
|
|
2574
2719
|
* @param {boolean} isRemoveFormat Is the remove all formats command?
|
|
2575
2720
|
* @param {boolean} isRemoveNode "newInnerNode" is remove node?
|
|
2576
2721
|
* @param {Node} _endContainer Offset node of last line already modified (end.container)
|
|
2577
|
-
* @returns {
|
|
2578
|
-
* @private
|
|
2722
|
+
* @returns {NodeStyleContainerType} { ancestor, endContainer: "If end container is renewed, returned renewed node" }
|
|
2579
2723
|
*/
|
|
2580
2724
|
_setNode_middleLine(element, newInnerNode, validation, isRemoveFormat, isRemoveNode, _removeCheck, _endContainer) {
|
|
2581
2725
|
// not add tag
|
|
2582
2726
|
if (!isRemoveNode) {
|
|
2583
2727
|
// end container path
|
|
2584
2728
|
let endPath = null;
|
|
2585
|
-
if (_endContainer && element.contains(_endContainer)) endPath =
|
|
2729
|
+
if (_endContainer && element.contains(_endContainer)) endPath = dom.query.getNodePath(_endContainer, element);
|
|
2586
2730
|
|
|
2587
2731
|
const tempNode = element.cloneNode(true);
|
|
2588
|
-
const newNodeName = newInnerNode.nodeName;
|
|
2589
|
-
const newCssText = newInnerNode.style.cssText;
|
|
2590
|
-
const newClass = newInnerNode.className;
|
|
2732
|
+
const newNodeName = /** @type {HTMLElement} */ (newInnerNode).nodeName;
|
|
2733
|
+
const newCssText = /** @type {HTMLElement} */ (newInnerNode).style.cssText;
|
|
2734
|
+
const newClass = /** @type {HTMLElement} */ (newInnerNode).className;
|
|
2591
2735
|
|
|
2592
2736
|
let children = tempNode.childNodes;
|
|
2593
2737
|
let i = 0,
|
|
2594
2738
|
len = children.length;
|
|
2595
2739
|
for (let child; i < len; i++) {
|
|
2596
|
-
child = children[i];
|
|
2740
|
+
child = /** @type {HTMLElement} */ (children[i]);
|
|
2597
2741
|
if (child.nodeType === 3) break;
|
|
2598
2742
|
if (child.nodeName === newNodeName) {
|
|
2599
2743
|
child.style.cssText += newCssText;
|
|
2600
|
-
|
|
2601
|
-
} else if (!
|
|
2744
|
+
dom.utils.addClass(child, newClass);
|
|
2745
|
+
} else if (!dom.check.isBreak(child) && this._isIgnoreNodeChange(child)) {
|
|
2602
2746
|
continue;
|
|
2603
2747
|
} else if (len === 1) {
|
|
2604
2748
|
children = child.childNodes;
|
|
@@ -2611,10 +2755,10 @@ Format.prototype = {
|
|
|
2611
2755
|
}
|
|
2612
2756
|
|
|
2613
2757
|
if (len > 0 && i === len) {
|
|
2614
|
-
element.innerHTML = tempNode.innerHTML;
|
|
2758
|
+
element.innerHTML = /** @type {HTMLElement} */ (tempNode).innerHTML;
|
|
2615
2759
|
return {
|
|
2616
2760
|
ancestor: element,
|
|
2617
|
-
endContainer: endPath ?
|
|
2761
|
+
endContainer: endPath ? dom.query.getNodeFromPath(endPath, element) : null
|
|
2618
2762
|
};
|
|
2619
2763
|
}
|
|
2620
2764
|
}
|
|
@@ -2631,11 +2775,11 @@ Format.prototype = {
|
|
|
2631
2775
|
const childNodes = current.childNodes;
|
|
2632
2776
|
|
|
2633
2777
|
for (let i = 0, len = childNodes.length, vNode, cloneChild; i < len; i++) {
|
|
2634
|
-
const child = childNodes[i];
|
|
2778
|
+
const child = /** @type {HTMLElement} */ (childNodes[i]);
|
|
2635
2779
|
if (!child) continue;
|
|
2636
2780
|
let coverNode = ancestor;
|
|
2637
2781
|
|
|
2638
|
-
if (!
|
|
2782
|
+
if (!dom.check.isBreak(child) && inst._isIgnoreNodeChange(child)) {
|
|
2639
2783
|
if (newInnerNode.childNodes.length > 0) {
|
|
2640
2784
|
pNode.appendChild(newInnerNode);
|
|
2641
2785
|
newInnerNode = newInnerNode.cloneNode(false);
|
|
@@ -2649,8 +2793,8 @@ Format.prototype = {
|
|
|
2649
2793
|
|
|
2650
2794
|
// end container
|
|
2651
2795
|
if (_endContainer && child.contains(_endContainer)) {
|
|
2652
|
-
const endPath =
|
|
2653
|
-
_endContainer =
|
|
2796
|
+
const endPath = dom.query.getNodePath(_endContainer, child);
|
|
2797
|
+
_endContainer = dom.query.getNodeFromPath(endPath, cloneChild);
|
|
2654
2798
|
}
|
|
2655
2799
|
|
|
2656
2800
|
continue;
|
|
@@ -2663,7 +2807,7 @@ Format.prototype = {
|
|
|
2663
2807
|
}
|
|
2664
2808
|
}
|
|
2665
2809
|
|
|
2666
|
-
if (!
|
|
2810
|
+
if (!dom.check.isBreak(child)) recursionFunc(child, coverNode);
|
|
2667
2811
|
}
|
|
2668
2812
|
})(element, newInnerNode);
|
|
2669
2813
|
|
|
@@ -2684,7 +2828,7 @@ Format.prototype = {
|
|
|
2684
2828
|
while (rChildren[0]) {
|
|
2685
2829
|
pNode.insertBefore(rChildren[0], removeNode);
|
|
2686
2830
|
}
|
|
2687
|
-
|
|
2831
|
+
dom.utils.removeItem(removeNode);
|
|
2688
2832
|
}
|
|
2689
2833
|
} else if (isRemoveNode) {
|
|
2690
2834
|
newInnerNode = newInnerNode.firstChild;
|
|
@@ -2705,30 +2849,31 @@ Format.prototype = {
|
|
|
2705
2849
|
},
|
|
2706
2850
|
|
|
2707
2851
|
/**
|
|
2852
|
+
* @private
|
|
2853
|
+
* @this {FormatThis}
|
|
2708
2854
|
* @description wraps last line selected text.
|
|
2709
|
-
* @param {
|
|
2710
|
-
* @param {
|
|
2711
|
-
* @param {
|
|
2855
|
+
* @param {Node} element The node of the line that contains the selected text node.
|
|
2856
|
+
* @param {Node} newInnerNode The dom that will wrap the selected text area
|
|
2857
|
+
* @param {(current: Node) => Node|null} validation Check if the node should be stripped.
|
|
2712
2858
|
* @param {Node} endCon The endContainer property of the selection object.
|
|
2713
2859
|
* @param {number} endOff The endOffset property of the selection object.
|
|
2714
2860
|
* @param {boolean} isRemoveFormat Is the remove all formats command?
|
|
2715
2861
|
* @param {boolean} isRemoveNode "newInnerNode" is remove node?
|
|
2716
|
-
* @returns {
|
|
2717
|
-
* @private
|
|
2862
|
+
* @returns {NodeStyleContainerType} { ancestor, container, offset }
|
|
2718
2863
|
*/
|
|
2719
2864
|
_setNode_endLine(element, newInnerNode, validation, endCon, endOff, isRemoveFormat, isRemoveNode, _removeCheck, _getMaintainedNode, _isMaintainedNode) {
|
|
2720
2865
|
// not add tag
|
|
2721
2866
|
let parentCon = endCon.parentNode;
|
|
2722
|
-
while (!parentCon.nextSibling && !parentCon.previousSibling && !this.isLine(parentCon.parentNode) && !
|
|
2867
|
+
while (!parentCon.nextSibling && !parentCon.previousSibling && !this.isLine(parentCon.parentNode) && !dom.check.isWysiwygFrame(parentCon.parentNode)) {
|
|
2723
2868
|
if (parentCon.nodeName === newInnerNode.nodeName) break;
|
|
2724
2869
|
parentCon = parentCon.parentNode;
|
|
2725
2870
|
}
|
|
2726
2871
|
|
|
2727
|
-
if (!isRemoveNode && parentCon.nodeName === newInnerNode.nodeName && !this.isLine(parentCon) && !parentCon.previousSibling &&
|
|
2872
|
+
if (!isRemoveNode && parentCon.nodeName === newInnerNode.nodeName && !this.isLine(parentCon) && !parentCon.previousSibling && dom.check.isZeroWidth(endCon.textContent.slice(endOff))) {
|
|
2728
2873
|
let sameTag = false;
|
|
2729
2874
|
let e = endCon.nextSibling;
|
|
2730
2875
|
while (e) {
|
|
2731
|
-
if (!
|
|
2876
|
+
if (!dom.check.isZeroWidth(e)) {
|
|
2732
2877
|
sameTag = false;
|
|
2733
2878
|
break;
|
|
2734
2879
|
}
|
|
@@ -2736,7 +2881,7 @@ Format.prototype = {
|
|
|
2736
2881
|
}
|
|
2737
2882
|
|
|
2738
2883
|
if (sameTag) {
|
|
2739
|
-
|
|
2884
|
+
dom.utils.copyTagAttributes(parentCon, newInnerNode);
|
|
2740
2885
|
|
|
2741
2886
|
return {
|
|
2742
2887
|
ancestor: element,
|
|
@@ -2767,7 +2912,7 @@ Format.prototype = {
|
|
|
2767
2912
|
if (!child) continue;
|
|
2768
2913
|
let coverNode = ancestor;
|
|
2769
2914
|
|
|
2770
|
-
if (passNode && !
|
|
2915
|
+
if (passNode && !dom.check.isBreak(child)) {
|
|
2771
2916
|
if (child.nodeType === 1) {
|
|
2772
2917
|
if (inst._isIgnoreNodeChange(child)) {
|
|
2773
2918
|
newInnerNode = newInnerNode.cloneNode(false);
|
|
@@ -2821,7 +2966,7 @@ Format.prototype = {
|
|
|
2821
2966
|
childNode.appendChild(newInnerNode);
|
|
2822
2967
|
pNode.insertBefore(childNode, pNode.firstChild);
|
|
2823
2968
|
nNodeArray.push(newInnerNode);
|
|
2824
|
-
if (newInnerNode.children.length > 0) ancestor = newNode;
|
|
2969
|
+
if (/** @type {HTMLElement} */ (newInnerNode).children.length > 0) ancestor = newNode;
|
|
2825
2970
|
else ancestor = newInnerNode;
|
|
2826
2971
|
} else if (isTopNode) {
|
|
2827
2972
|
newInnerNode.insertBefore(childNode, newInnerNode.firstChild);
|
|
@@ -2832,7 +2977,7 @@ Format.prototype = {
|
|
|
2832
2977
|
|
|
2833
2978
|
if (anchorNode && child.nodeType === 3) {
|
|
2834
2979
|
if (_getMaintainedNode(child)) {
|
|
2835
|
-
const ancestorAnchorNode =
|
|
2980
|
+
const ancestorAnchorNode = dom.query.getParentElement(ancestor, (c) => {
|
|
2836
2981
|
return inst._isNonSplitNode(c.parentNode) || c.parentNode === pNode;
|
|
2837
2982
|
});
|
|
2838
2983
|
anchorNode.appendChild(ancestorAnchorNode);
|
|
@@ -2848,8 +2993,17 @@ Format.prototype = {
|
|
|
2848
2993
|
// endContainer
|
|
2849
2994
|
if (!passNode && child === container) {
|
|
2850
2995
|
anchorNode = _getMaintainedNode(child);
|
|
2851
|
-
|
|
2852
|
-
|
|
2996
|
+
|
|
2997
|
+
let _prevText = '';
|
|
2998
|
+
let _nextText = '';
|
|
2999
|
+
if (container.nodeType === 3) {
|
|
3000
|
+
const cText = /** @type {Text} */ (container);
|
|
3001
|
+
_prevText = cText.substringData(offset, cText.length - offset);
|
|
3002
|
+
_nextText = cText.substringData(0, offset);
|
|
3003
|
+
}
|
|
3004
|
+
|
|
3005
|
+
const afterNode = dom.utils.createTextNode(_prevText);
|
|
3006
|
+
const textNode = dom.utils.createTextNode(_nextText);
|
|
2853
3007
|
|
|
2854
3008
|
if (anchorNode) {
|
|
2855
3009
|
anchorNode = anchorNode.cloneNode(false);
|
|
@@ -2874,7 +3028,7 @@ Format.prototype = {
|
|
|
2874
3028
|
nNodeArray.push(newInnerNode);
|
|
2875
3029
|
}
|
|
2876
3030
|
|
|
2877
|
-
if (!
|
|
3031
|
+
if (!dom.check.isZeroWidth(afterNode)) {
|
|
2878
3032
|
ancestor.insertBefore(afterNode, ancestor.firstChild);
|
|
2879
3033
|
}
|
|
2880
3034
|
|
|
@@ -2903,7 +3057,7 @@ Format.prototype = {
|
|
|
2903
3057
|
ancestor = newInnerNode;
|
|
2904
3058
|
}
|
|
2905
3059
|
|
|
2906
|
-
if (
|
|
3060
|
+
if (dom.check.isBreak(child)) newInnerNode.appendChild(child.cloneNode(false));
|
|
2907
3061
|
|
|
2908
3062
|
if (anchorNode) {
|
|
2909
3063
|
anchorNode.insertBefore(newInnerNode, anchorNode.firstChild);
|
|
@@ -2924,7 +3078,7 @@ Format.prototype = {
|
|
|
2924
3078
|
vNode = !passNode ? child.cloneNode(false) : validation(child);
|
|
2925
3079
|
if (vNode) {
|
|
2926
3080
|
ancestor.insertBefore(vNode, ancestor.firstChild);
|
|
2927
|
-
if (child.nodeType === 1 && !
|
|
3081
|
+
if (child.nodeType === 1 && !dom.check.isBreak(child)) coverNode = vNode;
|
|
2928
3082
|
}
|
|
2929
3083
|
|
|
2930
3084
|
recursionFunc(child, coverNode);
|
|
@@ -2952,7 +3106,7 @@ Format.prototype = {
|
|
|
2952
3106
|
textNode = rChildren[0];
|
|
2953
3107
|
pNode.insertBefore(textNode, removeNode);
|
|
2954
3108
|
}
|
|
2955
|
-
|
|
3109
|
+
dom.utils.removeItem(removeNode);
|
|
2956
3110
|
|
|
2957
3111
|
if (i === nNodeArray.length - 1) {
|
|
2958
3112
|
container = textNode;
|
|
@@ -2970,7 +3124,7 @@ Format.prototype = {
|
|
|
2970
3124
|
if (element.childNodes) {
|
|
2971
3125
|
container = element.childNodes[0];
|
|
2972
3126
|
} else {
|
|
2973
|
-
container =
|
|
3127
|
+
container = dom.utils.createTextNode(unicode.zeroWidthSpace);
|
|
2974
3128
|
element.appendChild(container);
|
|
2975
3129
|
}
|
|
2976
3130
|
} else {
|
|
@@ -2985,10 +3139,10 @@ Format.prototype = {
|
|
|
2985
3139
|
|
|
2986
3140
|
this.nodeTransform.removeEmptyNode(pNode, newInnerNode, false);
|
|
2987
3141
|
|
|
2988
|
-
if (
|
|
3142
|
+
if (dom.check.isZeroWidth(pNode.textContent)) {
|
|
2989
3143
|
container = pNode.firstChild;
|
|
2990
3144
|
offset = container.textContent.length;
|
|
2991
|
-
} else if (
|
|
3145
|
+
} else if (dom.check.isZeroWidth(container)) {
|
|
2992
3146
|
container = newInnerNode;
|
|
2993
3147
|
offset = 1;
|
|
2994
3148
|
}
|
|
@@ -2998,7 +3152,7 @@ Format.prototype = {
|
|
|
2998
3152
|
s: 0,
|
|
2999
3153
|
e: 0
|
|
3000
3154
|
};
|
|
3001
|
-
const path =
|
|
3155
|
+
const path = dom.query.getNodePath(container, pNode, offsets);
|
|
3002
3156
|
offset += offsets.s;
|
|
3003
3157
|
|
|
3004
3158
|
// tag merge
|
|
@@ -3006,7 +3160,7 @@ Format.prototype = {
|
|
|
3006
3160
|
|
|
3007
3161
|
element.parentNode.replaceChild(pNode, element);
|
|
3008
3162
|
|
|
3009
|
-
container =
|
|
3163
|
+
container = dom.query.getNodeFromPath(path, pNode);
|
|
3010
3164
|
offset += newOffsets[0];
|
|
3011
3165
|
}
|
|
3012
3166
|
|
|
@@ -3018,57 +3172,59 @@ Format.prototype = {
|
|
|
3018
3172
|
},
|
|
3019
3173
|
|
|
3020
3174
|
/**
|
|
3175
|
+
* @private
|
|
3176
|
+
* @this {FormatThis}
|
|
3021
3177
|
* @description Node with font-size style
|
|
3022
3178
|
* @param {Node} element Element to check
|
|
3023
3179
|
* @returns {boolean}
|
|
3024
|
-
* @private
|
|
3025
3180
|
*/
|
|
3026
3181
|
_sn_isSizeNode(element) {
|
|
3027
|
-
return element && typeof element !== 'string' && element.nodeType !== 3 && this.isTextStyleNode(element) && element.style.fontSize;
|
|
3182
|
+
return element && typeof element !== 'string' && element.nodeType !== 3 && this.isTextStyleNode(element) && !!element.style.fontSize;
|
|
3028
3183
|
},
|
|
3029
3184
|
|
|
3030
3185
|
/**
|
|
3031
|
-
* @description Return the parent maintained tag. (bind and use a util object)
|
|
3032
|
-
* @param {Element} element Element
|
|
3033
|
-
* @returns {Element}
|
|
3034
3186
|
* @private
|
|
3187
|
+
* @this {FormatThis}
|
|
3188
|
+
* @description Return the parent maintained tag. (bind and use a util object)
|
|
3189
|
+
* @param {boolean} _isRemove is remove anchor
|
|
3190
|
+
* @param {boolean} _isSizeNode is size span node
|
|
3191
|
+
* @param {Node} element Element
|
|
3192
|
+
* @returns {Node|null}
|
|
3035
3193
|
*/
|
|
3036
3194
|
_sn_getMaintainedNode(_isRemove, _isSizeNode, element) {
|
|
3037
3195
|
if (!element || _isRemove) return null;
|
|
3038
|
-
return
|
|
3196
|
+
return dom.query.getParentElement(element, this._isNonSplitNode.bind(this)) || (!_isSizeNode ? dom.query.getParentElement(element, this._sn_isSizeNode.bind(this)) : null);
|
|
3039
3197
|
},
|
|
3040
3198
|
|
|
3041
3199
|
/**
|
|
3042
|
-
* @description Check if element is a tag that should be persisted. (bind and use a util object)
|
|
3043
|
-
* @param {Element} element Element
|
|
3044
|
-
* @returns {Element}
|
|
3045
3200
|
* @private
|
|
3201
|
+
* @this {FormatThis}
|
|
3202
|
+
* @description Check if element is a tag that should be persisted. (bind and use a util object)
|
|
3203
|
+
* @param {boolean} _isRemove is remove anchor
|
|
3204
|
+
* @param {boolean} _isSizeNode is size span node
|
|
3205
|
+
* @param {Node} element Element
|
|
3206
|
+
* @returns {boolean}
|
|
3046
3207
|
*/
|
|
3047
3208
|
_sn_isMaintainedNode(_isRemove, _isSizeNode, element) {
|
|
3048
3209
|
if (!element || _isRemove || element.nodeType !== 1) return false;
|
|
3049
3210
|
const anchor = this._isNonSplitNode(element);
|
|
3050
|
-
return
|
|
3211
|
+
return dom.query.getParentElement(element, this._isNonSplitNode.bind(this)) ? anchor : anchor || (!_isSizeNode ? this._sn_isSizeNode(element) : false);
|
|
3051
3212
|
},
|
|
3052
3213
|
|
|
3053
3214
|
/**
|
|
3054
|
-
* @description If certain styles are applied to all child nodes of the list cell, the style of the list cell is also changed. (bold, color, size)
|
|
3055
|
-
* @param {Element} el List cell element. <li>
|
|
3056
|
-
* @param {Element|null} child Variable for recursive call. ("null" on the first call)
|
|
3057
3215
|
* @private
|
|
3216
|
+
* @this {FormatThis}
|
|
3217
|
+
* @description If certain styles are applied to all child nodes of the list cell, the style of the list cell is also changed. (bold, color, size)
|
|
3218
|
+
* @param {Node} el List cell element. <li>
|
|
3219
|
+
* @param {?Node} child Variable for recursive call. ("null" on the first call)
|
|
3058
3220
|
*/
|
|
3059
3221
|
_sn_setCommonListStyle(el, child) {
|
|
3060
|
-
if (!
|
|
3061
|
-
|
|
3062
|
-
const children =
|
|
3063
|
-
(child || el).childNodes,
|
|
3064
|
-
function (current) {
|
|
3065
|
-
return !domUtils.isBreak(current);
|
|
3066
|
-
},
|
|
3067
|
-
true
|
|
3068
|
-
);
|
|
3222
|
+
if (!dom.check.isListCell(el)) return;
|
|
3223
|
+
|
|
3224
|
+
const children = dom.utils.arrayFilter((child || el).childNodes, (current) => !dom.check.isBreak(current));
|
|
3069
3225
|
child = children[0];
|
|
3070
3226
|
|
|
3071
|
-
if (!child || children.length > 1
|
|
3227
|
+
if (!dom.check.isElement(child) || children.length > 1) return;
|
|
3072
3228
|
|
|
3073
3229
|
// set cell style---
|
|
3074
3230
|
const childStyle = child.style;
|
|
@@ -3081,7 +3237,7 @@ Format.prototype = {
|
|
|
3081
3237
|
if (this.options.get('_defaultStyleTagMap')[nodeName] === this.options.get('_defaultTagCommand').italic.toLowerCase()) elStyle.fontStyle = 'italic';
|
|
3082
3238
|
|
|
3083
3239
|
// styles
|
|
3084
|
-
const cKeys =
|
|
3240
|
+
const cKeys = converter.getValues(childStyle);
|
|
3085
3241
|
if (cKeys.length > 0) {
|
|
3086
3242
|
for (let i = 0, len = this._listCamel.length; i < len; i++) {
|
|
3087
3243
|
if (cKeys.includes(this._listKebab[i])) {
|
|
@@ -3103,32 +3259,27 @@ Format.prototype = {
|
|
|
3103
3259
|
while (ch.length > 0) {
|
|
3104
3260
|
p.insertBefore(ch[0], n);
|
|
3105
3261
|
}
|
|
3106
|
-
|
|
3262
|
+
dom.utils.removeItem(child);
|
|
3107
3263
|
}
|
|
3108
3264
|
},
|
|
3109
3265
|
|
|
3110
3266
|
/**
|
|
3267
|
+
* @private
|
|
3268
|
+
* @this {FormatThis}
|
|
3111
3269
|
* @description Watch the applied text nodes and adjust the common styles of the list.
|
|
3112
|
-
* @param {
|
|
3270
|
+
* @param {Node} el "LI" element
|
|
3113
3271
|
* @param {Array|null} styleArray Refer style array
|
|
3114
|
-
* @private
|
|
3115
3272
|
*/
|
|
3116
3273
|
_sn_resetCommonListCell(el, styleArray) {
|
|
3117
|
-
if (!
|
|
3274
|
+
if (!dom.check.isListCell(el)) return;
|
|
3118
3275
|
if (!styleArray) styleArray = this._listKebab;
|
|
3119
3276
|
|
|
3120
|
-
const children =
|
|
3121
|
-
el.childNodes,
|
|
3122
|
-
function (current) {
|
|
3123
|
-
return !domUtils.isBreak(current);
|
|
3124
|
-
},
|
|
3125
|
-
true
|
|
3126
|
-
);
|
|
3277
|
+
const children = dom.utils.arrayFilter(el.childNodes, (current) => !dom.check.isBreak(current));
|
|
3127
3278
|
const elStyles = el.style;
|
|
3128
3279
|
|
|
3129
3280
|
const ec = [],
|
|
3130
3281
|
ek = [],
|
|
3131
|
-
elKeys =
|
|
3282
|
+
elKeys = converter.getValues(elStyles);
|
|
3132
3283
|
for (let i = 0, len = this._listKebab.length; i < len; i++) {
|
|
3133
3284
|
if (elKeys.includes(this._listKebab[i]) && styleArray.includes(this._listKebab[i])) {
|
|
3134
3285
|
ec.push(this._listCamel[i]);
|
|
@@ -3139,7 +3290,7 @@ Format.prototype = {
|
|
|
3139
3290
|
if (!ec.length) return;
|
|
3140
3291
|
|
|
3141
3292
|
// reset cell style---
|
|
3142
|
-
const refer =
|
|
3293
|
+
const refer = dom.utils.createElement('SPAN');
|
|
3143
3294
|
for (let i = 0, len = ec.length; i < len; i++) {
|
|
3144
3295
|
refer.style[ec[i]] = elStyles[ek[i]];
|
|
3145
3296
|
elStyles.removeProperty(ek[i]);
|
|
@@ -3149,10 +3300,10 @@ Format.prototype = {
|
|
|
3149
3300
|
let r = null,
|
|
3150
3301
|
appliedEl = false;
|
|
3151
3302
|
for (let i = 0, len = children.length, c, s; i < len; i++) {
|
|
3152
|
-
c = children[i];
|
|
3303
|
+
c = /** @type {HTMLElement} */ (children[i]);
|
|
3153
3304
|
if (this.options.get('_defaultStyleTagMap')[c.nodeName.toLowerCase()]) continue;
|
|
3154
3305
|
|
|
3155
|
-
s =
|
|
3306
|
+
s = converter.getValues(c.style);
|
|
3156
3307
|
if (
|
|
3157
3308
|
s.length === 0 ||
|
|
3158
3309
|
(ec.some(function (k) {
|
|
@@ -3186,48 +3337,60 @@ Format.prototype = {
|
|
|
3186
3337
|
constructor: Format
|
|
3187
3338
|
};
|
|
3188
3339
|
|
|
3340
|
+
/**
|
|
3341
|
+
* @private
|
|
3342
|
+
* @param {Node} baseNode Node
|
|
3343
|
+
*/
|
|
3189
3344
|
function DeleteNestedList(baseNode) {
|
|
3190
3345
|
const baseParent = baseNode.parentNode;
|
|
3191
|
-
let
|
|
3192
|
-
let
|
|
3346
|
+
let parent = baseParent.parentNode;
|
|
3347
|
+
let siblingNode = /** @type {*} */ (baseParent);
|
|
3193
3348
|
let liSibling, liParent, child, index, c;
|
|
3194
3349
|
|
|
3195
|
-
while (
|
|
3196
|
-
index =
|
|
3350
|
+
while (dom.check.isListCell(parent)) {
|
|
3351
|
+
index = dom.query.getPositionIndex(baseNode);
|
|
3197
3352
|
liSibling = parent.nextElementSibling;
|
|
3198
3353
|
liParent = parent.parentNode;
|
|
3199
|
-
child =
|
|
3354
|
+
child = siblingNode;
|
|
3355
|
+
|
|
3200
3356
|
while (child) {
|
|
3201
|
-
|
|
3202
|
-
if (
|
|
3357
|
+
siblingNode = siblingNode.nextSibling;
|
|
3358
|
+
if (dom.check.isList(child)) {
|
|
3203
3359
|
c = child.childNodes;
|
|
3204
3360
|
while (c[index]) {
|
|
3205
3361
|
liParent.insertBefore(c[index], liSibling);
|
|
3206
3362
|
}
|
|
3207
|
-
if (c.length === 0)
|
|
3363
|
+
if (c.length === 0) dom.utils.removeItem(child);
|
|
3208
3364
|
} else {
|
|
3209
3365
|
liParent.appendChild(child);
|
|
3210
3366
|
}
|
|
3211
|
-
child =
|
|
3367
|
+
child = siblingNode;
|
|
3212
3368
|
}
|
|
3213
|
-
|
|
3369
|
+
|
|
3214
3370
|
parent = liParent.parentNode;
|
|
3215
3371
|
}
|
|
3216
3372
|
|
|
3217
|
-
if (baseParent.children.length === 0)
|
|
3373
|
+
if (baseParent.children.length === 0) dom.utils.removeItem(baseParent);
|
|
3218
3374
|
|
|
3219
3375
|
return liParent;
|
|
3220
3376
|
}
|
|
3221
3377
|
|
|
3378
|
+
/**
|
|
3379
|
+
* @private
|
|
3380
|
+
* @param {Array<HTMLElement>} lines - Line elements
|
|
3381
|
+
* @param {number} size - Margin size
|
|
3382
|
+
* @param {string} dir - Direction
|
|
3383
|
+
* @returns
|
|
3384
|
+
*/
|
|
3222
3385
|
function SetLineMargin(lines, size, dir) {
|
|
3223
3386
|
const cells = [];
|
|
3224
3387
|
|
|
3225
3388
|
for (let i = 0, len = lines.length, f, margin; i < len; i++) {
|
|
3226
3389
|
f = lines[i];
|
|
3227
|
-
if (!
|
|
3390
|
+
if (!dom.check.isListCell(f)) {
|
|
3228
3391
|
margin = /\d+/.test(f.style[dir]) ? numbers.get(f.style[dir], 0) : 0;
|
|
3229
3392
|
margin += size;
|
|
3230
|
-
|
|
3393
|
+
dom.utils.setStyle(f, dir, margin <= 0 ? '' : margin + 'px');
|
|
3231
3394
|
} else {
|
|
3232
3395
|
if (size < 0 || f.previousElementSibling) {
|
|
3233
3396
|
cells.push(f);
|
|
@@ -3239,6 +3402,7 @@ function SetLineMargin(lines, size, dir) {
|
|
|
3239
3402
|
}
|
|
3240
3403
|
|
|
3241
3404
|
/**
|
|
3405
|
+
* @private
|
|
3242
3406
|
* @description Strip remove node
|
|
3243
3407
|
* @param {Node} removeNode The remove node
|
|
3244
3408
|
* @private
|