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