suneditor 3.0.0-beta.13 → 3.0.0-beta.15
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/README.md +9 -32
- package/dist/suneditor.min.css +1 -1
- package/dist/suneditor.min.js +1 -1
- package/package.json +5 -5
- package/src/assets/icons/defaultIcons.js +4 -1
- package/src/assets/suneditor-contents.css +1 -3
- package/src/assets/suneditor.css +5 -1
- package/src/core/base/eventManager.js +4 -4
- package/src/core/class/component.js +2 -2
- package/src/core/class/html.js +3 -0
- package/src/core/class/offset.js +69 -40
- package/src/core/class/toolbar.js +1 -1
- package/src/core/editor.js +2 -1
- package/src/core/section/constructor.js +2 -115
- package/src/core/section/documentType.js +44 -23
- package/src/core/section/options.js +116 -3
- package/src/modules/Controller.js +13 -13
- package/src/modules/Figure.js +12 -9
- package/src/modules/SelectMenu.js +1 -1
- package/src/plugins/dropdown/table.js +79 -24
- package/src/plugins/modal/image.js +17 -16
- package/src/suneditor.js +19 -12
- package/types/assets/icons/defaultIcons.d.ts +2 -0
- package/types/core/base/eventManager.d.ts +2 -2
- package/types/core/class/offset.d.ts +10 -1
- package/types/core/section/constructor.d.ts +3 -16
- package/types/core/section/documentType.d.ts +12 -2
- package/types/core/section/options.d.ts +228 -39
- package/types/modules/Controller.d.ts +8 -4
- package/types/modules/Figure.d.ts +2 -1
- package/types/modules/SelectMenu.d.ts +1 -1
- package/types/plugins/dropdown/table.d.ts +1 -0
- package/types/suneditor.d.ts +11 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "suneditor",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.15",
|
|
4
4
|
"description": "Vanilla javascript based WYSIWYG web editor",
|
|
5
5
|
"author": "Yi JiHong",
|
|
6
6
|
"license": "MIT",
|
|
@@ -81,11 +81,11 @@
|
|
|
81
81
|
},
|
|
82
82
|
"browserslist": [
|
|
83
83
|
"chrome >= 80",
|
|
84
|
+
"firefox >= 90",
|
|
85
|
+
"safari >= 14.1",
|
|
84
86
|
"edge >= 80",
|
|
85
|
-
"firefox >= 74",
|
|
86
|
-
"safari >= 13.1",
|
|
87
|
-
"ios >= 13.4",
|
|
88
87
|
"opera >= 67",
|
|
88
|
+
"ios >= 14.5",
|
|
89
89
|
"android >= 80",
|
|
90
90
|
"samsung >= 13",
|
|
91
91
|
"not IE <= 11",
|
|
@@ -121,4 +121,4 @@
|
|
|
121
121
|
"web editor",
|
|
122
122
|
"browser editor"
|
|
123
123
|
]
|
|
124
|
-
}
|
|
124
|
+
}
|
|
@@ -25,7 +25,7 @@ export default {
|
|
|
25
25
|
print: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18,3H6V7H18M19,12A1,1 0 0,1 18,11A1,1 0 0,1 19,10A1,1 0 0,1 20,11A1,1 0 0,1 19,12M16,19H8V14H16M19,8H5A3,3 0 0,0 2,11V17H6V21H18V17H22V11A3,3 0 0,0 19,8Z" /></svg>',
|
|
26
26
|
template:
|
|
27
27
|
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13,7.5H18V9.5H13V7.5M13,14.5H18V16.5H13V14.5M19,3A2,2 0 0,1 21,5V19A2,2 0 0,1 19,21H5A2,2 0 0,1 3,19V5A2,2 0 0,1 5,3H19M19,19V5H5V19H19M11,6V11H6V6H11M10,10V7H7V10H10M11,13V18H6V13H11M10,17V14H7V17H10Z" /></svg>',
|
|
28
|
-
layout: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="
|
|
28
|
+
layout: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M21 13H3A1 1 0 0 0 2 14V20A1 1 0 0 0 3 21H21A1 1 0 0 0 22 20V14A1 1 0 0 0 21 13M20 19H4V15H20M21 3H3A1 1 0 0 0 2 4V10A1 1 0 0 0 3 11H21A1 1 0 0 0 22 10V4A1 1 0 0 0 21 3M20 9H4V5H20Z" /></svg>',
|
|
29
29
|
new_document: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20Z" /></svg>',
|
|
30
30
|
select_all:
|
|
31
31
|
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9,9H15V15H9M7,17H17V7H7M15,5H17V3H15M15,21H17V19H15M19,17H21V15H19M19,9H21V7H19M19,21A2,2 0 0,0 21,19H19M19,13H21V11H19M11,21H13V19H11M9,3H7V5H9M3,17H5V15H3M5,21V19H3A2,2 0 0,0 5,21M19,3V5H21A2,2 0 0,0 19,3M13,3H11V5H13M3,9H5V7H3M7,21H9V19H7M3,13H5V11H3M3,5H5V3A2,2 0 0,0 3,5Z" /></svg>',
|
|
@@ -202,6 +202,9 @@ export default {
|
|
|
202
202
|
alert_outline:
|
|
203
203
|
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M11,15H13V17H11V15M11,7H13V13H11V7M12,2C6.47,2 2,6.5 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,20A8,8 0 0,1 4,12A8,8 0 0,1 12,4A8,8 0 0,1 20,12A8,8 0 0,1 12,20Z" /></svg>',
|
|
204
204
|
// More icons
|
|
205
|
+
more_media:
|
|
206
|
+
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9 13V5C9 3.9 9.9 3 11 3H20C21.1 3 22 3.9 22 5V11H18.57L17.29 9.26C17.23 9.17 17.11 9.17 17.05 9.26L15.06 12C15 12.06 14.88 12.07 14.82 12L13.39 10.25C13.33 10.18 13.22 10.18 13.16 10.25L11.05 12.91C10.97 13 11.04 13.15 11.16 13.15H17.5V15H11C9.89 15 9 14.11 9 13M6 22V21H4V22H2V2H4V3H6V2H8.39C7.54 2.74 7 3.8 7 5V13C7 15.21 8.79 17 11 17H15.7C14.67 17.83 14 19.08 14 20.5C14 21.03 14.11 21.53 14.28 22H6M4 7H6V5H4V7M4 11H6V9H4V11M4 15H6V13H4V15M6 19V17H4V19H6M23 13V15H21V20.5C21 21.88 19.88 23 18.5 23S16 21.88 16 20.5 17.12 18 18.5 18C18.86 18 19.19 18.07 19.5 18.21V13H23Z" /></svg>',
|
|
207
|
+
more_view: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 21H11V13H3M5 15H9V19H5M3 11H11V3H3M5 5H9V9H5M13 3V11H21V3M19 9H15V5H19M18 16H21V18H18V21H16V18H13V16H16V13H18Z" /></svg>',
|
|
205
208
|
more_text:
|
|
206
209
|
'<svg class="se-ci" xmlns="http://www.w3.org/2000/svg" viewBox="10 10 180 180"><g><path d="M49.711,142.188h49.027c2.328,0.002,4.394,1.492,5.129,3.699l9.742,29.252c0.363,1.092,1.385,1.828,2.537,1.83l15.883,0.01c0.859,0,1.667-0.412,2.17-1.109s0.641-1.594,0.37-2.41l-16.625-50.045L86.503,28.953c-0.36-1.097-1.383-1.839-2.537-1.842H64.532c-1.153-0.001-2.178,0.736-2.542,1.831L13.847,173.457c-0.271,0.816-0.135,1.713,0.369,2.412c0.503,0.697,1.311,1.109,2.171,1.109h15.872c1.151,0,2.173-0.736,2.537-1.828l9.793-29.287C45.325,143.66,47.39,142.18,49.711,142.188L49.711,142.188z M53.493,119.098l15.607-46.9c0.744-2.196,2.806-3.674,5.125-3.674s4.381,1.478,5.125,3.674l15.607,46.904c0.537,1.621,0.263,3.402-0.736,4.789c-1.018,1.408-2.649,2.24-4.386,2.24H58.615c-1.736,0-3.368-0.832-4.386-2.24C53.23,122.504,52.956,120.721,53.493,119.098L53.493,119.098z M190.465,63.32c0-2.919-1.015-5.396-3.059-7.428c-2.029-2.031-4.496-3.047-7.383-3.047c-2.889,0-5.355,1.016-7.388,3.047c-2.029,2.032-3.056,4.498-3.056,7.386c0,2.889,1.026,5.354,3.056,7.385c2.032,2.032,4.499,3.059,7.388,3.059c2.887,0,5.354-1.026,7.383-3.059C189.45,68.633,190.465,66.178,190.465,63.32L190.465,63.32z M190.465,101.994c0-2.858-1.015-5.313-3.059-7.333c-2.029-2.042-4.496-3.047-7.383-3.047c-2.889,0-5.355,1.005-7.388,3.047c-2.029,2.021-3.056,4.486-3.056,7.376c0,2.887,1.026,5.352,3.056,7.395c2.032,2.021,4.499,3.047,7.388,3.047c2.887,0,5.354-1.025,7.383-3.047C189.45,107.389,190.465,104.914,190.465,101.994L190.465,101.994z M190.465,140.76c0-2.918-1.015-5.395-3.059-7.438c-2.029-2.041-4.496-3.047-7.383-3.047c-2.889,0-5.355,1.006-7.388,3.047c-2.029,2.043-3.056,4.52-3.056,7.438c0,2.922,1.026,5.398,3.056,7.439c2.032,2.021,4.499,3.047,7.388,3.047c2.887,0,5.354-1.025,7.383-3.047C189.45,146.158,190.465,143.682,190.465,140.76L190.465,140.76z"/></g></svg>',
|
|
207
210
|
more_paragraph:
|
|
@@ -20,9 +20,7 @@
|
|
|
20
20
|
line-height: var(--se-edit-line-height);
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
.sun-editor-editable.se-type-document-editable
|
|
24
|
-
padding: var(--se-edit-inner-padding-doc-type);
|
|
25
|
-
}
|
|
23
|
+
.sun-editor .se-wrapper .se-wrapper-inner.sun-editor-editable.se-type-document-editable,
|
|
26
24
|
.sun-editor-editable.se-document-page-mirror-a4 {
|
|
27
25
|
width: 21cm;
|
|
28
26
|
padding: var(--se-edit-inner-padding-doc-type);
|
package/src/assets/suneditor.css
CHANGED
|
@@ -366,6 +366,7 @@
|
|
|
366
366
|
outline: 1px solid var(--se-active-dark5-color) !important;
|
|
367
367
|
box-shadow: 0 0 0 0.3rem var(--se-active-light5-color);
|
|
368
368
|
transition: box-shadow 0.1s ease-in-out;
|
|
369
|
+
z-index: 1;
|
|
369
370
|
}
|
|
370
371
|
|
|
371
372
|
/** --- primary button */
|
|
@@ -760,7 +761,7 @@
|
|
|
760
761
|
top: -12px;
|
|
761
762
|
content: ' ';
|
|
762
763
|
border-bottom-width: 0;
|
|
763
|
-
border-top-color: var(--se-
|
|
764
|
+
border-top-color: var(--se-controller-background-color);
|
|
764
765
|
}
|
|
765
766
|
|
|
766
767
|
/** --- container */
|
|
@@ -1652,6 +1653,9 @@
|
|
|
1652
1653
|
.sun-editor .se-wrapper .se-code-wrapper {
|
|
1653
1654
|
width: 100%;
|
|
1654
1655
|
}
|
|
1656
|
+
.sun-editor .se-wrapper .se-code-wrapper > div {
|
|
1657
|
+
width: 100%;
|
|
1658
|
+
}
|
|
1655
1659
|
.sun-editor .se-wrapper .se-code-wrapper .se-code-view-line {
|
|
1656
1660
|
background-color: var(--se-code-view-color);
|
|
1657
1661
|
color: var(--se-code-view-background-color);
|
|
@@ -986,11 +986,11 @@ EventManager.prototype = {
|
|
|
986
986
|
* @this {EventManagerThis}
|
|
987
987
|
* @description Adjusts the position of the editor's toolbar, controllers, and other floating elements based on scroll position.
|
|
988
988
|
* - Ensures UI elements maintain their intended relative positions when scrolling.
|
|
989
|
-
* @param {
|
|
989
|
+
* @param {*} eventWysiwyg The wysiwyg event object containing scroll data (Window or element)
|
|
990
990
|
*/
|
|
991
991
|
_moveContainer(eventWysiwyg) {
|
|
992
|
-
const y = eventWysiwyg.scrollTop || 0;
|
|
993
|
-
const x = eventWysiwyg.scrollLeft || 0;
|
|
992
|
+
const y = eventWysiwyg.scrollTop || eventWysiwyg.scrollY || 0;
|
|
993
|
+
const x = eventWysiwyg.scrollLeft || eventWysiwyg.scrollX || 0;
|
|
994
994
|
|
|
995
995
|
if (this.editor.isBalloon) {
|
|
996
996
|
this.context.get('toolbar.main').style.top = this.toolbar._balloonOffset.top - y + 'px';
|
|
@@ -1270,7 +1270,7 @@ EventManager.prototype = {
|
|
|
1270
1270
|
/**
|
|
1271
1271
|
* @this {EventManagerThis}
|
|
1272
1272
|
* @param {__se__FrameContext} frameContext - frame context object
|
|
1273
|
-
* @param {Element} eventWysiwyg - wysiwyg event object
|
|
1273
|
+
* @param {Element|Window} eventWysiwyg - wysiwyg event object
|
|
1274
1274
|
* @param {Event} e - Event object
|
|
1275
1275
|
*/
|
|
1276
1276
|
function OnScroll_wysiwyg(frameContext, eventWysiwyg, e) {
|
|
@@ -496,7 +496,7 @@ Component.prototype = {
|
|
|
496
496
|
componentTop = top;
|
|
497
497
|
w = target.offsetWidth / 2 / 2;
|
|
498
498
|
|
|
499
|
-
t_style.top = componentTop -
|
|
499
|
+
t_style.top = componentTop - cH / 2 + 'px';
|
|
500
500
|
t_style[dir[0]] = (isNonSelected ? sideOffset - cW / 2 : sideOffset + w) + 'px';
|
|
501
501
|
t_style[dir[1]] = '';
|
|
502
502
|
|
|
@@ -522,7 +522,7 @@ Component.prototype = {
|
|
|
522
522
|
w = target.offsetWidth / 2 / 2;
|
|
523
523
|
}
|
|
524
524
|
|
|
525
|
-
b_style.top = componentTop + target.offsetHeight -
|
|
525
|
+
b_style.top = componentTop + target.offsetHeight - cH / 2 + 'px';
|
|
526
526
|
b_style[dir[0]] = sideOffset + target.offsetWidth - (isNonSelected ? 0 : w) - (isNonSelected ? cW / 2 : cW) + 'px';
|
|
527
527
|
b_style[dir[1]] = '';
|
|
528
528
|
|
package/src/core/class/html.js
CHANGED
|
@@ -1091,6 +1091,7 @@ HTML.prototype = {
|
|
|
1091
1091
|
* @param {number|Array<number>} [options.rootKey=null] Root index
|
|
1092
1092
|
*/
|
|
1093
1093
|
set(html, { rootKey } = {}) {
|
|
1094
|
+
this.ui._offCurrentController();
|
|
1094
1095
|
this.selection.removeRange();
|
|
1095
1096
|
const convertValue = html === null || html === undefined ? '' : this.clean(html, { forceFormat: true, whitelist: null, blacklist: null });
|
|
1096
1097
|
|
|
@@ -1119,6 +1120,8 @@ HTML.prototype = {
|
|
|
1119
1120
|
* @param {number|Array<number>} [options.rootKey=null] Root index
|
|
1120
1121
|
*/
|
|
1121
1122
|
add(html, { rootKey } = {}) {
|
|
1123
|
+
this.ui._offCurrentController();
|
|
1124
|
+
|
|
1122
1125
|
if (!rootKey) rootKey = [this.status.rootKey];
|
|
1123
1126
|
else if (!Array.isArray(rootKey)) rootKey = [rootKey];
|
|
1124
1127
|
|
package/src/core/class/offset.js
CHANGED
|
@@ -149,8 +149,8 @@ Offset.prototype = {
|
|
|
149
149
|
left: offsetLeft,
|
|
150
150
|
top: offsetTop,
|
|
151
151
|
right: offsetElement?.offsetWidth ? offsetElement.offsetWidth - (offsetLeft - l + targetWidth) + r : 0,
|
|
152
|
-
scrollX: eventWysiwyg.
|
|
153
|
-
scrollY: eventWysiwyg.
|
|
152
|
+
scrollX: eventWysiwyg.scrollLeft || eventWysiwyg.scrollX || 0,
|
|
153
|
+
scrollY: eventWysiwyg.scrollTop || eventWysiwyg.scrollY || 0
|
|
154
154
|
};
|
|
155
155
|
},
|
|
156
156
|
|
|
@@ -349,13 +349,13 @@ Offset.prototype = {
|
|
|
349
349
|
getWWScroll() {
|
|
350
350
|
const eventWysiwyg = this.editor.frameContext.get('wysiwyg');
|
|
351
351
|
const rects = this.selection.getRects(eventWysiwyg, 'start').rects;
|
|
352
|
-
const top = eventWysiwyg.
|
|
353
|
-
const height = eventWysiwyg.scrollHeight || 0;
|
|
352
|
+
const top = eventWysiwyg.scrollTop || eventWysiwyg.scrollY || 0;
|
|
353
|
+
const height = eventWysiwyg.scrollHeight || eventWysiwyg.document?.documentElement.scrollHeight || 0;
|
|
354
354
|
|
|
355
355
|
return {
|
|
356
356
|
top,
|
|
357
|
-
left: eventWysiwyg.
|
|
358
|
-
width: eventWysiwyg.scrollWidth || 0,
|
|
357
|
+
left: eventWysiwyg.scrollLeft || eventWysiwyg.scrollX || 0,
|
|
358
|
+
width: eventWysiwyg.scrollWidth || eventWysiwyg.document?.documentElement.scrollWidth || 0,
|
|
359
359
|
height,
|
|
360
360
|
bottom: top + height,
|
|
361
361
|
rects
|
|
@@ -453,6 +453,7 @@ Offset.prototype = {
|
|
|
453
453
|
* @param {{left:number, top:number}} [params.addOffset={left:0, top:0}] Additional offset
|
|
454
454
|
* @param {"bottom"|"top"} [params.position="bottom"] Position ('bottom'|'top')
|
|
455
455
|
* @param {*} params.inst Instance object of caller
|
|
456
|
+
* @param {HTMLElement} [params.sibling] The sibling controller element
|
|
456
457
|
* @returns {{position: "top" | "bottom"} | undefined} Success -> {position: current position}
|
|
457
458
|
*/
|
|
458
459
|
setAbsPosition(element, target, params) {
|
|
@@ -469,55 +470,76 @@ Offset.prototype = {
|
|
|
469
470
|
addOffset.left *= -1;
|
|
470
471
|
}
|
|
471
472
|
|
|
472
|
-
const
|
|
473
|
-
const
|
|
473
|
+
const isIframe = this.editor.frameOptions.get('iframe');
|
|
474
|
+
const isWWTarget = this.editor.frameContext.get('wrapper').contains(target) || params.isWWTarget || (isIframe ? this.editor.frameContext.get('wysiwyg').contains(target) : false);
|
|
475
|
+
|
|
476
|
+
const isCtrlTarget = target.nodeType === 1;
|
|
474
477
|
const isTargetAbs = isWWTarget && !isCtrlTarget;
|
|
478
|
+
const isInlineTarget = isCtrlTarget && /inline/.test(_w.getComputedStyle(target).display);
|
|
475
479
|
const clientSize = getClientSize(_d);
|
|
476
480
|
const wwScroll = isTargetAbs ? this.getWWScroll() : this._getWindowScroll();
|
|
477
|
-
const targetRect = isCtrlTarget ? target.getBoundingClientRect() : this.selection.getRects(target, 'start').rects;
|
|
481
|
+
const targetRect = !isIframe && isCtrlTarget ? target.getBoundingClientRect() : this.selection.getRects(target, 'start').rects;
|
|
478
482
|
const targetOffset = this.getGlobal(target);
|
|
479
483
|
const arrow = /** @type {HTMLElement} */ (hasClass(element.firstElementChild, 'se-arrow') ? element.firstElementChild : null);
|
|
480
484
|
|
|
481
485
|
// top ----------------------------------------------------------------------------------------------------
|
|
486
|
+
const siblingH = params.sibling?.offsetHeight || 0;
|
|
482
487
|
const ah = arrow ? arrow.offsetHeight : 0;
|
|
483
488
|
const elH = element.offsetHeight;
|
|
484
489
|
const targetH = target.offsetHeight;
|
|
485
490
|
// margin
|
|
486
491
|
const tmtw = targetRect.top;
|
|
487
492
|
const tmbw = clientSize.h - targetRect.bottom;
|
|
488
|
-
const
|
|
493
|
+
const globalTop = this.getGlobal(this.editor.frameContext.get('topArea')).top;
|
|
494
|
+
const wScrollY = _w.scrollY;
|
|
495
|
+
const th = this.context.get('toolbar.main').offsetHeight;
|
|
496
|
+
const containerToolbar = this.options.get('toolbar_container');
|
|
497
|
+
const headLess = this.editor.isBalloon || this.editor.isInline || containerToolbar;
|
|
498
|
+
const toolbarH = (containerToolbar && globalTop - wScrollY - th > 0) || (!this.editor.toolbar._sticky && headLess) ? 0 : th;
|
|
489
499
|
|
|
490
500
|
// check margin
|
|
491
|
-
const { rmt, rmb, rt } = this._getVMargin(tmtw, tmbw, toolbarH, clientSize, targetRect, isTargetAbs, wwScroll);
|
|
492
|
-
if (isWWTarget && (rmb + targetH <= 0 || rmt + rt + targetH <= 0)) return;
|
|
501
|
+
const { rmt, rmb, bMargin, rt } = this._getVMargin(tmtw, tmbw, toolbarH, clientSize, targetRect, isTargetAbs, wwScroll);
|
|
502
|
+
if (isWWTarget && ((rmb > 0 ? bMargin : rmb) + targetH <= 0 || rmt + rt + targetH - (this.editor.toolbar._sticky && isInlineTarget ? toolbarH : 0) <= 0)) return;
|
|
493
503
|
|
|
504
|
+
const isSticky = this.editor.toolbar._sticky && this.context.get('toolbar.main').style.display !== 'none' && (!headLess || this.editor.frameContext.get('topArea').getBoundingClientRect().top <= th);
|
|
505
|
+
const statusBarH = this.editor.frameContext.get('statusbar')?.offsetHeight || 0;
|
|
494
506
|
let t = addOffset.top;
|
|
495
507
|
let y = 0;
|
|
496
508
|
let arrowDir = '';
|
|
509
|
+
|
|
510
|
+
// [bottom] position
|
|
497
511
|
if (position === 'bottom') {
|
|
512
|
+
let trmt = rmt - (isSticky && globalTop - wScrollY <= toolbarH ? toolbarH : 0);
|
|
513
|
+
if (isSticky && trmt + toolbarH < 0) trmt += toolbarH;
|
|
498
514
|
arrowDir = 'up';
|
|
499
|
-
t += targetRect.bottom + ah +
|
|
500
|
-
y = rmb - (elH + ah);
|
|
501
|
-
|
|
515
|
+
t += targetRect.bottom + ah + wScrollY;
|
|
516
|
+
y = rmb - (elH + ah) - statusBarH;
|
|
517
|
+
// change to <top> position
|
|
518
|
+
if (y - siblingH < 0) {
|
|
502
519
|
arrowDir = 'down';
|
|
503
520
|
t -= targetH + elH + ah * 2;
|
|
504
|
-
y =
|
|
505
|
-
|
|
521
|
+
y = trmt - (elH + ah);
|
|
522
|
+
// sticky the <top> position
|
|
523
|
+
if (y - siblingH < 0) {
|
|
506
524
|
arrowDir = '';
|
|
507
|
-
t -= y;
|
|
525
|
+
t -= y - siblingH - Math.max(1, y + elH + ah) + (!isSticky && trmt < 0 ? toolbarH : 0) - (isSticky ? this.context.get('toolbar.main').offsetTop : 0);
|
|
508
526
|
}
|
|
509
527
|
}
|
|
510
|
-
}
|
|
528
|
+
}
|
|
529
|
+
// <top> position
|
|
530
|
+
else {
|
|
511
531
|
arrowDir = 'down';
|
|
512
|
-
t += targetRect.top - elH - ah +
|
|
513
|
-
y = rmt -
|
|
514
|
-
|
|
532
|
+
t += targetRect.top - elH - ah + wScrollY;
|
|
533
|
+
y = (isSticky ? targetRect.top - toolbarH : rmt) - elH - ah;
|
|
534
|
+
// change to [bottom] position
|
|
535
|
+
if (y - siblingH < 0) {
|
|
515
536
|
arrowDir = 'up';
|
|
516
537
|
t += targetH + elH + ah * 2;
|
|
517
|
-
y = rmb - (elH + ah);
|
|
518
|
-
|
|
538
|
+
y = (rmb > 0 ? bMargin : rmb) - (elH + ah) - statusBarH;
|
|
539
|
+
// sticky the [bottom] position
|
|
540
|
+
if (y - siblingH < 0) {
|
|
519
541
|
arrowDir = '';
|
|
520
|
-
t += y;
|
|
542
|
+
t += y - 2;
|
|
521
543
|
}
|
|
522
544
|
}
|
|
523
545
|
}
|
|
@@ -734,24 +756,32 @@ Offset.prototype = {
|
|
|
734
756
|
* @param {RectsInfo} targetRect Target rect object
|
|
735
757
|
* @param {boolean} isTargetAbs Is target absolute position
|
|
736
758
|
* @param {OffsetWWScrollInfo} wwScroll WYSIWYG scroll info
|
|
737
|
-
* @returns {{rmt:number, rmb:number, rt:number
|
|
759
|
+
* @returns {{rmt:number, rmb:number, rt:number, tMargin:number, bMargin:number}} Margin values
|
|
760
|
+
* - rmt: top margin to frame
|
|
761
|
+
* - rmb: bottom margin to frame
|
|
762
|
+
* - rt: Toolbar height offset adjustment
|
|
763
|
+
* - tMargin: top margin
|
|
764
|
+
* - bMargin: bottom margin
|
|
738
765
|
*/
|
|
739
766
|
_getVMargin(tmtw, tmbw, toolbarH, clientSize, targetRect, isTargetAbs, wwScroll) {
|
|
740
767
|
let rmt = 0;
|
|
741
768
|
let rmb = 0;
|
|
742
769
|
let rt = 0;
|
|
770
|
+
let tMargin = 0;
|
|
771
|
+
let bMargin = 0;
|
|
772
|
+
|
|
743
773
|
if (this.editor.frameContext.get('isFullScreen')) {
|
|
744
774
|
rmt = tmtw - toolbarH;
|
|
745
775
|
rmb = tmbw;
|
|
746
776
|
} else {
|
|
747
|
-
const
|
|
748
|
-
|
|
749
|
-
|
|
777
|
+
const isIframeAbs = isTargetAbs && this.editor.frameOptions.get('iframe');
|
|
778
|
+
tMargin = targetRect.top;
|
|
779
|
+
bMargin = clientSize.h - targetRect.bottom;
|
|
750
780
|
const editorOffset = this.getGlobal();
|
|
751
781
|
const editorScroll = this.getGlobalScroll();
|
|
752
782
|
const statusBarH = this.editor.frameContext.get('statusbar')?.offsetHeight || 0;
|
|
753
783
|
|
|
754
|
-
if (
|
|
784
|
+
if (isIframeAbs) {
|
|
755
785
|
const emt = editorOffset.top - editorScroll.top - editorScroll.ts;
|
|
756
786
|
const editorH = this.editor.frameContext.get('topArea').offsetHeight;
|
|
757
787
|
rmt = targetRect.top - emt;
|
|
@@ -764,29 +794,28 @@ Offset.prototype = {
|
|
|
764
794
|
if (toolbarH > wst) {
|
|
765
795
|
if (this.editor.toolbar._sticky) {
|
|
766
796
|
st = toolbarH;
|
|
767
|
-
toolbarH = 0;
|
|
768
797
|
} else {
|
|
769
798
|
st = wst + toolbarH;
|
|
770
799
|
}
|
|
771
|
-
} else if (this.options.get('toolbar_container')) {
|
|
800
|
+
} else if (this.options.get('toolbar_container') && !this.editor.toolbar._sticky) {
|
|
772
801
|
toolbarH = 0;
|
|
773
802
|
} else {
|
|
774
|
-
st = wst +
|
|
803
|
+
st = wst + toolbarH;
|
|
775
804
|
}
|
|
776
805
|
|
|
777
|
-
rmt = targetRect.top - st;
|
|
778
|
-
rmb = wwScroll.rects.bottom - targetRect.bottom - wsb
|
|
806
|
+
rmt = targetRect.top - wwScroll.rects.top - st + toolbarH;
|
|
807
|
+
rmb = wwScroll.rects.bottom - targetRect.bottom - wsb;
|
|
808
|
+
// display margin
|
|
809
|
+
rmt = rmt > 0 ? rmt : rmt - toolbarH;
|
|
779
810
|
}
|
|
780
|
-
|
|
781
|
-
// display margin
|
|
782
|
-
rmt = (rmt > 0 ? tMargin : rmt) - toolbarH;
|
|
783
|
-
rmb = rmb > 0 ? bMargin : rmb;
|
|
784
811
|
}
|
|
785
812
|
|
|
786
813
|
return {
|
|
787
814
|
rmt,
|
|
788
815
|
rmb,
|
|
789
|
-
rt
|
|
816
|
+
rt,
|
|
817
|
+
tMargin,
|
|
818
|
+
bMargin
|
|
790
819
|
};
|
|
791
820
|
},
|
|
792
821
|
|
|
@@ -362,7 +362,7 @@ Toolbar.prototype = {
|
|
|
362
362
|
let left = container.offsetLeft;
|
|
363
363
|
let top = container.offsetTop;
|
|
364
364
|
|
|
365
|
-
while (!container.parentElement.contains(editorParent)
|
|
365
|
+
while (!container.parentElement.contains(editorParent) && !/^(BODY|HTML)$/i.test(container.parentElement.nodeName)) {
|
|
366
366
|
container = container.offsetParent;
|
|
367
367
|
left += container.offsetLeft;
|
|
368
368
|
top += container.offsetTop;
|
package/src/core/editor.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { env, converter, dom, numbers } from '../helper';
|
|
2
|
-
import Constructor, { InitOptions, UpdateButton, CreateShortcuts, CreateStatusbar
|
|
2
|
+
import Constructor, { InitOptions, UpdateButton, CreateShortcuts, CreateStatusbar } from './section/constructor';
|
|
3
|
+
import { OPTION_FRAME_FIXED_FLAG, OPTION_FIXED_FLAG } from './section/options';
|
|
3
4
|
import { UpdateStatusbarContext } from './section/context';
|
|
4
5
|
import { BASIC_COMMANDS, ACTIVE_EVENT_COMMANDS, SELECT_ALL, DIR_BTN_ACTIVE, SAVE, COPY_FORMAT, FONT_STYLE, PAGE_BREAK } from './section/actives';
|
|
5
6
|
import History from './base/history';
|
|
@@ -14,119 +14,6 @@ const _d = env._d;
|
|
|
14
14
|
* @typedef {import('./options').EditorInitOptions} EditorInitOptions
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
/** ------------- [OPTIONS FRAG] ------------- */
|
|
18
|
-
/**
|
|
19
|
-
* @description For all EditorInitOptions keys, only boolean | null values are allowed.
|
|
20
|
-
* - 'fixed' → Immutable / null → Resettable.
|
|
21
|
-
* @type {Partial<Record<keyof EditorInitOptions, "fixed" | true>>}
|
|
22
|
-
*/
|
|
23
|
-
export const OPTION_FRAME_FIXED_FLAG = {
|
|
24
|
-
value: 'fixed',
|
|
25
|
-
placeholder: true,
|
|
26
|
-
editableFrameAttributes: true,
|
|
27
|
-
width: true,
|
|
28
|
-
minWidth: true,
|
|
29
|
-
maxWidth: true,
|
|
30
|
-
height: true,
|
|
31
|
-
minHeight: true,
|
|
32
|
-
maxHeight: true,
|
|
33
|
-
editorStyle: true,
|
|
34
|
-
iframe: 'fixed',
|
|
35
|
-
iframe_fullPage: 'fixed',
|
|
36
|
-
iframe_attributes: true,
|
|
37
|
-
iframe_cssFileName: true,
|
|
38
|
-
statusbar: true,
|
|
39
|
-
statusbar_showPathLabel: true,
|
|
40
|
-
statusbar_resizeEnable: 'fixed',
|
|
41
|
-
charCounter: true,
|
|
42
|
-
charCounter_max: true,
|
|
43
|
-
charCounter_label: true,
|
|
44
|
-
charCounter_type: true
|
|
45
|
-
};
|
|
46
|
-
/**
|
|
47
|
-
* @description For all EditorInitOptions keys, only boolean | null values are allowed.
|
|
48
|
-
* - 'fixed' → Immutable / null → Resettable.
|
|
49
|
-
* @type {Partial<Record<keyof EditorInitOptions, "fixed" | true>>}
|
|
50
|
-
*/
|
|
51
|
-
export const OPTION_FIXED_FLAG = {
|
|
52
|
-
plugins: 'fixed',
|
|
53
|
-
excludedPlugins: 'fixed',
|
|
54
|
-
buttonList: 'fixed',
|
|
55
|
-
v2Migration: 'fixed',
|
|
56
|
-
strictMode: 'fixed',
|
|
57
|
-
mode: 'fixed',
|
|
58
|
-
type: 'fixed',
|
|
59
|
-
theme: true,
|
|
60
|
-
lang: 'fixed',
|
|
61
|
-
fontSizeUnits: 'fixed',
|
|
62
|
-
allowedClassName: 'fixed',
|
|
63
|
-
closeModalOutsideClick: 'fixed',
|
|
64
|
-
copyFormatKeepOn: true,
|
|
65
|
-
syncTabIndent: true,
|
|
66
|
-
tabDisable: true,
|
|
67
|
-
autoLinkify: true,
|
|
68
|
-
autoStyleify: true,
|
|
69
|
-
scrollToOptions: true,
|
|
70
|
-
componentScrollToOptions: true,
|
|
71
|
-
retainStyleMode: true,
|
|
72
|
-
allowedExtraTags: 'fixed',
|
|
73
|
-
events: true,
|
|
74
|
-
__textStyleTags: 'fixed',
|
|
75
|
-
textStyleTags: 'fixed',
|
|
76
|
-
convertTextTags: 'fixed',
|
|
77
|
-
__tagStyles: 'fixed',
|
|
78
|
-
tagStyles: 'fixed',
|
|
79
|
-
spanStyles: 'fixed',
|
|
80
|
-
lineStyles: 'fixed',
|
|
81
|
-
textDirection: true,
|
|
82
|
-
reverseButtons: 'fixed',
|
|
83
|
-
historyStackDelayTime: true,
|
|
84
|
-
lineAttrReset: true,
|
|
85
|
-
printClass: true,
|
|
86
|
-
defaultLine: 'fixed',
|
|
87
|
-
defaultLineBreakFormat: true,
|
|
88
|
-
scopeSelectionTags: true,
|
|
89
|
-
__defaultElementWhitelist: 'fixed',
|
|
90
|
-
elementWhitelist: 'fixed',
|
|
91
|
-
elementBlacklist: 'fixed',
|
|
92
|
-
__defaultAttributeWhitelist: 'fixed',
|
|
93
|
-
attributeWhitelist: 'fixed',
|
|
94
|
-
attributeBlacklist: 'fixed',
|
|
95
|
-
__defaultFormatLine: 'fixed',
|
|
96
|
-
formatLine: 'fixed',
|
|
97
|
-
__defaultFormatBrLine: 'fixed',
|
|
98
|
-
formatBrLine: 'fixed',
|
|
99
|
-
__defaultFormatClosureBrLine: 'fixed',
|
|
100
|
-
formatClosureBrLine: 'fixed',
|
|
101
|
-
__defaultFormatBlock: 'fixed',
|
|
102
|
-
formatBlock: 'fixed',
|
|
103
|
-
__defaultFormatClosureBlock: 'fixed',
|
|
104
|
-
formatClosureBlock: 'fixed',
|
|
105
|
-
allowedEmptyTags: true,
|
|
106
|
-
toolbar_width: true,
|
|
107
|
-
toolbar_container: 'fixed',
|
|
108
|
-
toolbar_sticky: true,
|
|
109
|
-
toolbar_hide: true,
|
|
110
|
-
subToolbar: 'fixed',
|
|
111
|
-
statusbar_container: 'fixed',
|
|
112
|
-
shortcutsHint: true,
|
|
113
|
-
shortcutsDisable: 'fixed',
|
|
114
|
-
shortcuts: 'fixed',
|
|
115
|
-
fullScreenOffset: true,
|
|
116
|
-
previewTemplate: true,
|
|
117
|
-
printTemplate: true,
|
|
118
|
-
componentAutoSelect: true,
|
|
119
|
-
defaultUrlProtocol: true,
|
|
120
|
-
allUsedStyles: 'fixed',
|
|
121
|
-
toastMessageTime: true,
|
|
122
|
-
icons: 'fixed',
|
|
123
|
-
freeCodeViewMode: true,
|
|
124
|
-
__lineFormatFilter: true,
|
|
125
|
-
__pluginRetainFilter: true,
|
|
126
|
-
__listCommonStyle: 'fixed',
|
|
127
|
-
externalLibs: 'fixed'
|
|
128
|
-
};
|
|
129
|
-
|
|
130
17
|
/**
|
|
131
18
|
* @description Creates a new SunEditor instance with specified options.
|
|
132
19
|
* @param {Array<{target: Element, key: *, options: EditorFrameOptions}>} editorTargets - Target element or multi-root object.
|
|
@@ -555,7 +442,7 @@ export function InitOptions(options, editorTargets, plugins) {
|
|
|
555
442
|
return _default;
|
|
556
443
|
}, {})
|
|
557
444
|
);
|
|
558
|
-
o.set('_textStylesRegExp', new RegExp(`\\s*[^-a-zA-Z](${DEFAULTS.
|
|
445
|
+
o.set('_textStylesRegExp', new RegExp(`\\s*[^-a-zA-Z](${DEFAULTS.SPAN_STYLES}${options.spanStyles ? '|' + options.spanStyles : ''})\\s*:[^;]+(?!;)*`, 'gi'));
|
|
559
446
|
o.set('_lineStylesRegExp', new RegExp(`\\s*[^-a-zA-Z](${DEFAULTS.LINE_STYLES}${options.lineStyles ? '|' + options.lineStyles : ''})\\s*:[^;]+(?!;)*`, 'gi'));
|
|
560
447
|
o.set('_defaultStyleTagMap', {
|
|
561
448
|
strong: textTags.bold,
|
|
@@ -788,7 +675,7 @@ export function InitOptions(options, editorTargets, plugins) {
|
|
|
788
675
|
const allUsedStyles = new Set(DEFAULTS.CONTENT_STYLES.split('|'));
|
|
789
676
|
const _ss = options.spanStyles?.split('|') || [];
|
|
790
677
|
const _ls = o.get('__listCommonStyle');
|
|
791
|
-
const _dts = DEFAULTS.
|
|
678
|
+
const _dts = DEFAULTS.SPAN_STYLES.split('|');
|
|
792
679
|
for (let i = 0, len = _dts.length; i < len; i++) {
|
|
793
680
|
allUsedStyles.add(_dts[i]);
|
|
794
681
|
}
|
|
@@ -130,9 +130,11 @@ DocumentType.prototype = {
|
|
|
130
130
|
this._rePageTimeout = _w.setTimeout(async () => {
|
|
131
131
|
await dom.utils.waitForMediaLoad(this._mirror, 1500);
|
|
132
132
|
|
|
133
|
-
const
|
|
133
|
+
const heightGap = this.ww.scrollHeight > this._mirror.scrollHeight ? this.ww.scrollHeight - this._mirror.scrollHeight : 0;
|
|
134
|
+
const mirrorHeight = this._mirror.scrollHeight + heightGap;
|
|
134
135
|
const pageBreaks = this._mirror.querySelectorAll('.se-page-break');
|
|
135
136
|
if (!force && this.pageHeight === mirrorHeight && this.pageBreaksCnt === pageBreaks.length) return;
|
|
137
|
+
|
|
136
138
|
this.pageHeight = mirrorHeight;
|
|
137
139
|
this.pageBreaksCnt = pageBreaks.length;
|
|
138
140
|
|
|
@@ -145,18 +147,12 @@ DocumentType.prototype = {
|
|
|
145
147
|
for (let i = 0; i < pageBreaks.length; i++) {
|
|
146
148
|
const breakPosition = pageBreaks[i].offsetTop;
|
|
147
149
|
const sectionHeight = breakPosition - lastBreakPosition;
|
|
148
|
-
|
|
149
|
-
if (sectionHeight % A4_PAGE_HEIGHT !== 0) {
|
|
150
|
-
additionalPages++;
|
|
151
|
-
}
|
|
152
|
-
|
|
150
|
+
if (sectionHeight % A4_PAGE_HEIGHT !== 0) additionalPages++;
|
|
153
151
|
lastBreakPosition = breakPosition;
|
|
154
152
|
}
|
|
155
153
|
|
|
156
154
|
const lastSectionHeight = mirrorHeight - lastBreakPosition;
|
|
157
|
-
if (lastSectionHeight > 0 && lastSectionHeight % A4_PAGE_HEIGHT !== 0)
|
|
158
|
-
additionalPages++;
|
|
159
|
-
}
|
|
155
|
+
if (lastSectionHeight > 0 && lastSectionHeight % A4_PAGE_HEIGHT !== 0) additionalPages++;
|
|
160
156
|
}
|
|
161
157
|
|
|
162
158
|
const scrollTop = this.isAutoHeight ? 0 : this._getWWScrollTop();
|
|
@@ -168,25 +164,18 @@ DocumentType.prototype = {
|
|
|
168
164
|
pages.push({ number: i, top: pageBreaks[i].offsetTop + pageBreakHeight - scrollTop });
|
|
169
165
|
}
|
|
170
166
|
|
|
171
|
-
// A4 position
|
|
172
167
|
this._mirrorCache = 0;
|
|
173
168
|
const chr = this.ww.children;
|
|
174
169
|
const mChr = this._mirror.children;
|
|
175
170
|
this._initializeCache(mChr);
|
|
171
|
+
|
|
176
172
|
pages.push({ number: 0, top: 0 });
|
|
173
|
+
|
|
177
174
|
for (let i = 1, t = 0; i < totalPages; i++) {
|
|
178
175
|
t += A4_PAGE_HEIGHT + (i === 1 ? this._paddingTop + this._paddingBottom : this._paddingTop);
|
|
179
|
-
if (!pages.some((p) => Math.abs(p.top - t) <
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
if (!el) break;
|
|
183
|
-
|
|
184
|
-
if (chr[this._mirrorCache]) {
|
|
185
|
-
t += numbers.get(_w.getComputedStyle(chr[this._mirrorCache]).marginBottom);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const elBottom = el.offsetTop + el.offsetHeight;
|
|
189
|
-
const top = elBottom + cm + (el.offsetHeight - ch);
|
|
176
|
+
if (!pages.some((p) => Math.abs(p.top - t) < 3)) {
|
|
177
|
+
const top = this._calcPageBreakTop(t, chr, mChr);
|
|
178
|
+
if (top === null) break;
|
|
190
179
|
pages.push({ number: i, top });
|
|
191
180
|
}
|
|
192
181
|
}
|
|
@@ -202,11 +191,21 @@ DocumentType.prototype = {
|
|
|
202
191
|
pages.sort((a, b) => a.top - b.top);
|
|
203
192
|
this.page.innerHTML = '';
|
|
204
193
|
this.pages = [];
|
|
194
|
+
|
|
205
195
|
for (let i = 0, t; i < totalPages; i++) {
|
|
206
196
|
if (!pages[i]) continue;
|
|
207
197
|
t = pages[i].top;
|
|
208
198
|
if (mirrorHeight < t) break;
|
|
209
|
-
|
|
199
|
+
|
|
200
|
+
const pageNumber = dom.utils.createElement(
|
|
201
|
+
'DIV',
|
|
202
|
+
{
|
|
203
|
+
style: `top:${t - scrollTop}px`,
|
|
204
|
+
innerHTML: String(i + 1)
|
|
205
|
+
},
|
|
206
|
+
`<div class="se-document-page-line" style="width: ${wwWidth}px;"></div>${i + 1}`
|
|
207
|
+
);
|
|
208
|
+
|
|
210
209
|
this.page.appendChild(pageNumber);
|
|
211
210
|
this.pages.push(pageNumber);
|
|
212
211
|
}
|
|
@@ -217,6 +216,28 @@ DocumentType.prototype = {
|
|
|
217
216
|
}, 400);
|
|
218
217
|
},
|
|
219
218
|
|
|
219
|
+
/**
|
|
220
|
+
* @private
|
|
221
|
+
* @description Calculates and compensates for the vertical gap between the rendered content (current page)
|
|
222
|
+
* - and the mirrored preview page due to differences in width and layout.
|
|
223
|
+
* @param {number} t - The initial top position value to be adjusted.
|
|
224
|
+
* @param {HTMLElement[]} chr - The elements array in the current (main) page.
|
|
225
|
+
* @param {HTMLElement[]} mChr - The elements array in the mirrored page.
|
|
226
|
+
* @returns {number|null} - The adjusted top value.
|
|
227
|
+
*/
|
|
228
|
+
_calcPageBreakTop(t, chr, mChr) {
|
|
229
|
+
const { ci } = this._getElementAtPosition(t, mChr);
|
|
230
|
+
const mel = mChr[ci];
|
|
231
|
+
const el = chr[ci];
|
|
232
|
+
if (!mel || !el) return null;
|
|
233
|
+
|
|
234
|
+
const offsetDiff = el.offsetTop - mel.offsetTop;
|
|
235
|
+
const heightDiff = el.offsetHeight - mel.offsetHeight;
|
|
236
|
+
|
|
237
|
+
const top = t + offsetDiff + heightDiff / 2;
|
|
238
|
+
return Math.round(top);
|
|
239
|
+
},
|
|
240
|
+
|
|
220
241
|
/**
|
|
221
242
|
* @private
|
|
222
243
|
* @description Initializes the cache for document elements.
|
|
@@ -242,7 +263,7 @@ DocumentType.prototype = {
|
|
|
242
263
|
* @private
|
|
243
264
|
* @description Retrieves the element at a given position.
|
|
244
265
|
* @param {number} pageTop - The vertical position to check.
|
|
245
|
-
* @param {
|
|
266
|
+
* @param {HTMLElement[]} mChr - List of mirrored elements.
|
|
246
267
|
* @returns {{ci: number, cm: number, ch: number}} The closest element and its related data.
|
|
247
268
|
* - ci: The index of the closest element.
|
|
248
269
|
* - cm: The distance between the top of the closest element and the given position.
|