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
|
@@ -66,7 +66,7 @@ export const DEFAULTS = {
|
|
|
66
66
|
col: 'width',
|
|
67
67
|
'ol|ul': 'list-style-type'
|
|
68
68
|
},
|
|
69
|
-
|
|
69
|
+
SPAN_STYLES: 'font-family|font-size|color|background-color|width|height',
|
|
70
70
|
LINE_STYLES: 'text-align|margin-left|margin-right|line-height',
|
|
71
71
|
|
|
72
72
|
RETAIN_STYLE_MODE: ['repeat', 'always', 'none']
|
|
@@ -145,8 +145,8 @@ export const DEFAULTS = {
|
|
|
145
145
|
* @property {Object<string, string>} [__tagStyles=CONSTANTS.TAG_STYLES] - The basic tags that serves as the base for "tagStyles"
|
|
146
146
|
* - The default follows {@link DEFAULTS.TAG_STYLES}
|
|
147
147
|
* @property {Object<string, string>} [tagStyles={}] - Specifies allowed styles for HTML tags.
|
|
148
|
-
* @property {string} [spanStyles=CONSTANTS.
|
|
149
|
-
* - The default follows {@link DEFAULTS.
|
|
148
|
+
* @property {string} [spanStyles=CONSTANTS.SPAN_STYLES] - Specifies allowed styles for the "span" tag.
|
|
149
|
+
* - The default follows {@link DEFAULTS.SPAN_STYLES}
|
|
150
150
|
* @property {string} [lineStyles=CONSTANTS.LINE_STYLES] - Specifies allowed styles for the "line" element (p..).
|
|
151
151
|
* - The default follows {@link DEFAULTS.LINE_STYLES}
|
|
152
152
|
* @property {string} [textDirection="ltr"] - Text direction: "ltr" or "rtl".
|
|
@@ -256,3 +256,116 @@ export const DEFAULTS = {
|
|
|
256
256
|
/**
|
|
257
257
|
* @typedef {EditorBaseOptions & EditorFrameOptions} EditorInitOptions
|
|
258
258
|
*/
|
|
259
|
+
|
|
260
|
+
/** ------------- [OPTIONS FRAG] ------------- */
|
|
261
|
+
/**
|
|
262
|
+
* @description For all EditorInitOptions keys, only boolean | null values are allowed.
|
|
263
|
+
* - 'fixed' → Immutable / null → Resettable.
|
|
264
|
+
* @type {Partial<Record<keyof EditorInitOptions, "fixed" | true>>}
|
|
265
|
+
*/
|
|
266
|
+
export const OPTION_FRAME_FIXED_FLAG = {
|
|
267
|
+
value: 'fixed',
|
|
268
|
+
placeholder: true,
|
|
269
|
+
editableFrameAttributes: true,
|
|
270
|
+
width: true,
|
|
271
|
+
minWidth: true,
|
|
272
|
+
maxWidth: true,
|
|
273
|
+
height: true,
|
|
274
|
+
minHeight: true,
|
|
275
|
+
maxHeight: true,
|
|
276
|
+
editorStyle: true,
|
|
277
|
+
iframe: 'fixed',
|
|
278
|
+
iframe_fullPage: 'fixed',
|
|
279
|
+
iframe_attributes: true,
|
|
280
|
+
iframe_cssFileName: true,
|
|
281
|
+
statusbar: true,
|
|
282
|
+
statusbar_showPathLabel: true,
|
|
283
|
+
statusbar_resizeEnable: 'fixed',
|
|
284
|
+
charCounter: true,
|
|
285
|
+
charCounter_max: true,
|
|
286
|
+
charCounter_label: true,
|
|
287
|
+
charCounter_type: true
|
|
288
|
+
};
|
|
289
|
+
/**
|
|
290
|
+
* @description For all EditorInitOptions keys, only boolean | null values are allowed.
|
|
291
|
+
* - 'fixed' → Immutable / null → Resettable.
|
|
292
|
+
* @type {Partial<Record<keyof EditorInitOptions, "fixed" | true>>}
|
|
293
|
+
*/
|
|
294
|
+
export const OPTION_FIXED_FLAG = {
|
|
295
|
+
plugins: 'fixed',
|
|
296
|
+
excludedPlugins: 'fixed',
|
|
297
|
+
buttonList: 'fixed',
|
|
298
|
+
v2Migration: 'fixed',
|
|
299
|
+
strictMode: 'fixed',
|
|
300
|
+
mode: 'fixed',
|
|
301
|
+
type: 'fixed',
|
|
302
|
+
theme: true,
|
|
303
|
+
lang: 'fixed',
|
|
304
|
+
fontSizeUnits: 'fixed',
|
|
305
|
+
allowedClassName: 'fixed',
|
|
306
|
+
closeModalOutsideClick: 'fixed',
|
|
307
|
+
copyFormatKeepOn: true,
|
|
308
|
+
syncTabIndent: true,
|
|
309
|
+
tabDisable: true,
|
|
310
|
+
autoLinkify: true,
|
|
311
|
+
autoStyleify: true,
|
|
312
|
+
scrollToOptions: true,
|
|
313
|
+
componentScrollToOptions: true,
|
|
314
|
+
retainStyleMode: true,
|
|
315
|
+
allowedExtraTags: 'fixed',
|
|
316
|
+
events: true,
|
|
317
|
+
__textStyleTags: 'fixed',
|
|
318
|
+
textStyleTags: 'fixed',
|
|
319
|
+
convertTextTags: 'fixed',
|
|
320
|
+
__tagStyles: 'fixed',
|
|
321
|
+
tagStyles: 'fixed',
|
|
322
|
+
spanStyles: 'fixed',
|
|
323
|
+
lineStyles: 'fixed',
|
|
324
|
+
textDirection: true,
|
|
325
|
+
reverseButtons: 'fixed',
|
|
326
|
+
historyStackDelayTime: true,
|
|
327
|
+
lineAttrReset: true,
|
|
328
|
+
printClass: true,
|
|
329
|
+
defaultLine: 'fixed',
|
|
330
|
+
defaultLineBreakFormat: true,
|
|
331
|
+
scopeSelectionTags: true,
|
|
332
|
+
__defaultElementWhitelist: 'fixed',
|
|
333
|
+
elementWhitelist: 'fixed',
|
|
334
|
+
elementBlacklist: 'fixed',
|
|
335
|
+
__defaultAttributeWhitelist: 'fixed',
|
|
336
|
+
attributeWhitelist: 'fixed',
|
|
337
|
+
attributeBlacklist: 'fixed',
|
|
338
|
+
__defaultFormatLine: 'fixed',
|
|
339
|
+
formatLine: 'fixed',
|
|
340
|
+
__defaultFormatBrLine: 'fixed',
|
|
341
|
+
formatBrLine: 'fixed',
|
|
342
|
+
__defaultFormatClosureBrLine: 'fixed',
|
|
343
|
+
formatClosureBrLine: 'fixed',
|
|
344
|
+
__defaultFormatBlock: 'fixed',
|
|
345
|
+
formatBlock: 'fixed',
|
|
346
|
+
__defaultFormatClosureBlock: 'fixed',
|
|
347
|
+
formatClosureBlock: 'fixed',
|
|
348
|
+
allowedEmptyTags: true,
|
|
349
|
+
toolbar_width: true,
|
|
350
|
+
toolbar_container: 'fixed',
|
|
351
|
+
toolbar_sticky: true,
|
|
352
|
+
toolbar_hide: true,
|
|
353
|
+
subToolbar: 'fixed',
|
|
354
|
+
statusbar_container: 'fixed',
|
|
355
|
+
shortcutsHint: true,
|
|
356
|
+
shortcutsDisable: 'fixed',
|
|
357
|
+
shortcuts: 'fixed',
|
|
358
|
+
fullScreenOffset: true,
|
|
359
|
+
previewTemplate: true,
|
|
360
|
+
printTemplate: true,
|
|
361
|
+
componentAutoSelect: true,
|
|
362
|
+
defaultUrlProtocol: true,
|
|
363
|
+
allUsedStyles: 'fixed',
|
|
364
|
+
toastMessageTime: true,
|
|
365
|
+
icons: 'fixed',
|
|
366
|
+
freeCodeViewMode: true,
|
|
367
|
+
__lineFormatFilter: true,
|
|
368
|
+
__pluginRetainFilter: true,
|
|
369
|
+
__listCommonStyle: 'fixed',
|
|
370
|
+
externalLibs: 'fixed'
|
|
371
|
+
};
|
|
@@ -28,7 +28,9 @@ const INDEX_1 = '2147483640';
|
|
|
28
28
|
* @property {Array<HTMLElement>=} [parents=[]] The parent "controller" array when "controller" is opened nested.
|
|
29
29
|
* @property {boolean=} [parentsHide=false] If true, the parent element is hidden when the controller is opened.
|
|
30
30
|
* @property {HTMLElement=} [sibling=null] The related sibling controller element that this controller is positioned relative to.
|
|
31
|
-
*
|
|
31
|
+
* - e.g.) table plugin :: 118
|
|
32
|
+
* @property {boolean=} [siblingMain=false] If true, This sibling controller is the main controller.
|
|
33
|
+
* - You must specify this option, if use "sibling"
|
|
32
34
|
* @property {boolean=} [isInsideForm=false] If the controller is inside a form, set it to true.
|
|
33
35
|
* @property {boolean=} [isOutsideForm=false] If the controller is outside a form, set it to true.
|
|
34
36
|
*/
|
|
@@ -61,7 +63,7 @@ class Controller extends EditorInjector {
|
|
|
61
63
|
this.parents = /** @type {Array<HTMLElement>} */ (params.parents || []);
|
|
62
64
|
this.parentsHide = !!params.parentsHide;
|
|
63
65
|
this.sibling = /** @type {HTMLElement} */ (params.sibling || null);
|
|
64
|
-
this.
|
|
66
|
+
this.siblingMain = !!params.siblingMain;
|
|
65
67
|
this.isInsideForm = !!params.isInsideForm;
|
|
66
68
|
this.isOutsideForm = !!params.isOutsideForm;
|
|
67
69
|
this.toTop = false;
|
|
@@ -137,14 +139,6 @@ class Controller extends EditorInjector {
|
|
|
137
139
|
|
|
138
140
|
this.__addGlobalEvent();
|
|
139
141
|
|
|
140
|
-
// add sibling offset
|
|
141
|
-
if (this.sibling) {
|
|
142
|
-
if (this.siblingPosition === 'top') {
|
|
143
|
-
this.__addOffset.top += -this.sibling.offsetHeight + 1;
|
|
144
|
-
} else {
|
|
145
|
-
this.__addOffset.left += this.form.offsetWidth + this.sibling.offsetWidth - 1;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
142
|
// display controller
|
|
149
143
|
this._setControllerPosition(this.form, this.currentPositionTarget, false);
|
|
150
144
|
|
|
@@ -290,6 +284,11 @@ class Controller extends EditorInjector {
|
|
|
290
284
|
controller.style.visibility = 'hidden';
|
|
291
285
|
controller.style.display = 'block';
|
|
292
286
|
|
|
287
|
+
if (this.sibling && this.sibling.style.display !== 'block') {
|
|
288
|
+
this.sibling.style.visibility = 'hidden';
|
|
289
|
+
this.sibling.style.display = 'block';
|
|
290
|
+
}
|
|
291
|
+
|
|
293
292
|
if (this.selection.isRange(refer)) {
|
|
294
293
|
if (!this.offset.setRangePosition(this.form, /** @type {Range} */ (refer), { position: 'bottom' })) {
|
|
295
294
|
this.hide();
|
|
@@ -297,18 +296,19 @@ class Controller extends EditorInjector {
|
|
|
297
296
|
}
|
|
298
297
|
} else {
|
|
299
298
|
if (refer) {
|
|
300
|
-
const positionResult = this.offset.setAbsPosition(controller, /** @type {HTMLElement} */ (refer), { addOffset: this.__addOffset, position: this.position, isWWTarget: this.isWWTarget, inst: this });
|
|
299
|
+
const positionResult = this.offset.setAbsPosition(controller, /** @type {HTMLElement} */ (refer), { addOffset: this.__addOffset, position: this.position, isWWTarget: this.isWWTarget, inst: this, sibling: this.sibling });
|
|
301
300
|
if (!positionResult) {
|
|
302
301
|
this.hide();
|
|
303
302
|
return;
|
|
304
303
|
}
|
|
305
304
|
|
|
306
|
-
if (!skipAutoReposition && this.sibling && this.
|
|
305
|
+
if (!skipAutoReposition && this.sibling && !this.siblingMain) {
|
|
307
306
|
const resetPosition = controller.offsetTop - this.__addOffset.top;
|
|
308
307
|
if (positionResult.position === 'bottom') {
|
|
309
308
|
this._reserveIndex = true;
|
|
310
|
-
controller.style.top = resetPosition + this.sibling.offsetHeight -
|
|
309
|
+
controller.style.top = resetPosition + this.sibling.offsetHeight - 1 + 'px';
|
|
311
310
|
} else {
|
|
311
|
+
this._reserveIndex = false;
|
|
312
312
|
controller.style.top = resetPosition - this.sibling.offsetHeight + 2 + 'px';
|
|
313
313
|
}
|
|
314
314
|
} else {
|
package/src/modules/Figure.js
CHANGED
|
@@ -308,9 +308,7 @@ class Figure extends EditorInjector {
|
|
|
308
308
|
return;
|
|
309
309
|
}
|
|
310
310
|
|
|
311
|
-
if (_DragHandle.get('__overInfo')
|
|
312
|
-
this.ui._offCurrentController();
|
|
313
|
-
} else {
|
|
311
|
+
if (_DragHandle.get('__overInfo') === ON_OVER_COMPONENT) {
|
|
314
312
|
nonBorder = true;
|
|
315
313
|
}
|
|
316
314
|
|
|
@@ -523,7 +521,7 @@ class Figure extends EditorInjector {
|
|
|
523
521
|
|
|
524
522
|
const w = !/%$/.test(target.style.width) ? target.style.width : ((figure.container && numbers.get(figure.container.style.width, 2)) || 100) + '%';
|
|
525
523
|
const h = figure.inlineCover
|
|
526
|
-
? figure.inlineCover.style.height
|
|
524
|
+
? figure.inlineCover.style.height || /** @type {HTMLElement} */ (targetNode).style.height || String(/** @type {HTMLImageElement} */ (targetNode).height || '')
|
|
527
525
|
: numbers.get(figure.cover.style.paddingBottom, 0) > 0 && !this.isVertical
|
|
528
526
|
? figure.cover.style.height
|
|
529
527
|
: !/%$/.test(target.style.height) || !/%$/.test(target.style.width)
|
|
@@ -575,6 +573,7 @@ class Figure extends EditorInjector {
|
|
|
575
573
|
* @description As style[block, inline] the component
|
|
576
574
|
* @param {?Node} targetNode Target element
|
|
577
575
|
* @param {"block"|"inline"} formatStyle Format style
|
|
576
|
+
* @returns {HTMLElement} New target element after conversion
|
|
578
577
|
*/
|
|
579
578
|
convertAsFormat(targetNode, formatStyle) {
|
|
580
579
|
if (!targetNode) targetNode = this._element;
|
|
@@ -583,6 +582,10 @@ class Figure extends EditorInjector {
|
|
|
583
582
|
const { w, h } = this.getSize(target);
|
|
584
583
|
|
|
585
584
|
const newTarget = /** @type {HTMLElement} */ (target.cloneNode(false));
|
|
585
|
+
newTarget.style.width = '';
|
|
586
|
+
newTarget.style.height = '';
|
|
587
|
+
newTarget.removeAttribute('width');
|
|
588
|
+
newTarget.removeAttribute('height');
|
|
586
589
|
|
|
587
590
|
switch (formatStyle) {
|
|
588
591
|
case 'inline': {
|
|
@@ -592,8 +595,6 @@ class Figure extends EditorInjector {
|
|
|
592
595
|
const next = container.nextElementSibling;
|
|
593
596
|
const parent = container.parentElement;
|
|
594
597
|
|
|
595
|
-
newTarget.style.width = '';
|
|
596
|
-
newTarget.style.height = '';
|
|
597
598
|
const figure = Figure.CreateInlineContainer(newTarget);
|
|
598
599
|
dom.utils.addClass(
|
|
599
600
|
figure.container,
|
|
@@ -623,8 +624,6 @@ class Figure extends EditorInjector {
|
|
|
623
624
|
dom.utils.removeItem(s.previousElementSibling);
|
|
624
625
|
}
|
|
625
626
|
|
|
626
|
-
newTarget.style.width = '';
|
|
627
|
-
newTarget.style.height = '';
|
|
628
627
|
const figure = Figure.CreateContainer(newTarget);
|
|
629
628
|
dom.utils.addClass(
|
|
630
629
|
figure.container,
|
|
@@ -641,6 +640,8 @@ class Figure extends EditorInjector {
|
|
|
641
640
|
break;
|
|
642
641
|
}
|
|
643
642
|
}
|
|
643
|
+
|
|
644
|
+
return newTarget;
|
|
644
645
|
}
|
|
645
646
|
|
|
646
647
|
/**
|
|
@@ -1208,8 +1209,10 @@ class Figure extends EditorInjector {
|
|
|
1208
1209
|
e.stopPropagation();
|
|
1209
1210
|
e.preventDefault();
|
|
1210
1211
|
|
|
1211
|
-
const eventTarget = dom.query.getEventTarget(e);
|
|
1212
1212
|
const inst = _DragHandle.get('__figureInst');
|
|
1213
|
+
if (!inst) return;
|
|
1214
|
+
|
|
1215
|
+
const eventTarget = dom.query.getEventTarget(e);
|
|
1213
1216
|
const direction = (inst._resize_direction = eventTarget.classList[0]);
|
|
1214
1217
|
inst._resizeClientX = e.clientX;
|
|
1215
1218
|
inst._resizeClientY = e.clientY;
|
|
@@ -98,7 +98,7 @@ class SelectMenu extends CoreInjector {
|
|
|
98
98
|
on(referElement, selectMethod, attr) {
|
|
99
99
|
if (!attr) attr = {};
|
|
100
100
|
this._refer = /** @type {HTMLElement} */ (referElement);
|
|
101
|
-
this._keydownTarget = dom.check.isInputElement(referElement) ? referElement : this.
|
|
101
|
+
this._keydownTarget = dom.check.isInputElement(referElement) ? referElement : this.editor.frameContext.get('_ww');
|
|
102
102
|
this._selectMethod = selectMethod;
|
|
103
103
|
this.form = dom.utils.createElement(
|
|
104
104
|
'DIV',
|
|
@@ -4,8 +4,8 @@ import { Controller, SelectMenu, ColorPicker, Figure, _DragHandle } from '../../
|
|
|
4
4
|
|
|
5
5
|
const { _w, ON_OVER_COMPONENT } = env;
|
|
6
6
|
|
|
7
|
-
const ROW_SELECT_MARGIN =
|
|
8
|
-
const CELL_SELECT_MARGIN =
|
|
7
|
+
const ROW_SELECT_MARGIN = 6;
|
|
8
|
+
const CELL_SELECT_MARGIN = 6;
|
|
9
9
|
const CELL_DECIMAL_END = 0;
|
|
10
10
|
|
|
11
11
|
const RESIZE_CELL_CLASS = '.se-table-resize-line';
|
|
@@ -115,12 +115,17 @@ class Table extends EditorInjector {
|
|
|
115
115
|
});
|
|
116
116
|
|
|
117
117
|
// members - Controller
|
|
118
|
-
this.controller_cell = new Controller(this, controller_cell.html, { position: this.cellControllerTop ? 'top' : 'bottom' });
|
|
119
|
-
this.controller_table = new Controller(this, controller_table, { position: 'top' });
|
|
120
118
|
if (this.cellControllerTop) {
|
|
119
|
+
this.controller_cell = new Controller(this, controller_cell.html, { position: 'top' });
|
|
120
|
+
this.controller_table = new Controller(this, controller_table, { position: 'top' });
|
|
121
121
|
this.controller_cell.sibling = this.controller_table.form;
|
|
122
|
-
this.
|
|
122
|
+
this.controller_table.sibling = this.controller_cell.form;
|
|
123
|
+
this.controller_table.siblingMain = true;
|
|
124
|
+
} else {
|
|
125
|
+
this.controller_table = new Controller(this, controller_table, { position: 'top' });
|
|
126
|
+
this.controller_cell = new Controller(this, controller_cell.html, { position: 'bottom' });
|
|
123
127
|
}
|
|
128
|
+
|
|
124
129
|
// props
|
|
125
130
|
const propsTargetForms = [this.controller_table.form, this.controller_cell.form];
|
|
126
131
|
this.controller_props = new Controller(this, controller_props.html, { position: 'bottom', parents: propsTargetForms, isInsideForm: true });
|
|
@@ -428,24 +433,69 @@ class Table extends EditorInjector {
|
|
|
428
433
|
// create colgroup
|
|
429
434
|
if (!ColgroupEl) {
|
|
430
435
|
const rows = element.rows;
|
|
431
|
-
const
|
|
432
|
-
const
|
|
433
|
-
|
|
436
|
+
const maxColumnCount = GetMaxColumns(element);
|
|
437
|
+
const colWidths = new Array(maxColumnCount).fill(null);
|
|
438
|
+
|
|
439
|
+
for (let r = 0, rLen = rows.length, cellsCount; r < rLen; r++) {
|
|
440
|
+
const cellsInRow = rows[r].cells;
|
|
441
|
+
cellsCount = cellsInRow.length;
|
|
442
|
+
let currentLogicalCol = 0;
|
|
443
|
+
const rowColOccupancy = new Array(maxColumnCount).fill(false);
|
|
444
|
+
|
|
445
|
+
for (let c = 0; c < cellsCount; c++) {
|
|
446
|
+
const cell = cellsInRow[c];
|
|
447
|
+
const cellWidth = cell.style.width;
|
|
448
|
+
const colSpan = cell.colSpan || 1;
|
|
449
|
+
|
|
450
|
+
while (currentLogicalCol < maxColumnCount && rowColOccupancy[currentLogicalCol]) {
|
|
451
|
+
currentLogicalCol++;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
if (currentLogicalCol >= maxColumnCount) break;
|
|
455
|
+
if (cellWidth && !colWidths[currentLogicalCol]) colWidths[currentLogicalCol] = cellWidth;
|
|
434
456
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
457
|
+
for (let i = 0; i < colSpan; i++) {
|
|
458
|
+
if (currentLogicalCol + i >= maxColumnCount || !cellWidth) continue;
|
|
459
|
+
|
|
460
|
+
rowColOccupancy[currentLogicalCol + i] = true;
|
|
461
|
+
const currentPxWidth = parseFloat(cellWidth);
|
|
462
|
+
|
|
463
|
+
for (let j = 0; j < colSpan; j++) {
|
|
464
|
+
const targetColIndex = currentLogicalCol + j;
|
|
465
|
+
if (targetColIndex >= maxColumnCount) continue;
|
|
466
|
+
|
|
467
|
+
const existingWidth = colWidths[targetColIndex];
|
|
468
|
+
if (existingWidth === null) {
|
|
469
|
+
colWidths[targetColIndex] = `width: ${cellWidth};`;
|
|
470
|
+
} else {
|
|
471
|
+
const existingPxWidth = parseFloat(existingWidth.replace('width: ', '').replace(';', ''));
|
|
472
|
+
if (colSpan === 1 && currentPxWidth !== existingPxWidth) {
|
|
473
|
+
colWidths[targetColIndex] = `width: ${cellWidth};`;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
442
477
|
}
|
|
478
|
+
currentLogicalCol += colSpan;
|
|
443
479
|
}
|
|
480
|
+
|
|
481
|
+
if (cellsCount === maxColumnCount) break;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
const colHTML = [];
|
|
485
|
+
for (let i = 0; i < maxColumnCount; i++) {
|
|
486
|
+
const colStyle = colWidths[i] ? ` style="${colWidths[i]}"` : '';
|
|
444
487
|
colHTML.push(`<col${colStyle}>`);
|
|
445
488
|
}
|
|
446
489
|
|
|
447
490
|
const colGroup = dom.utils.createElement('colgroup', null, colHTML.join(''));
|
|
448
491
|
element.insertBefore(colGroup, element.firstElementChild);
|
|
492
|
+
|
|
493
|
+
for (let r = 0; r < rows.length; r++) {
|
|
494
|
+
const cellsInRow = rows[r].cells;
|
|
495
|
+
for (let c = 0; c < cellsInRow.length; c++) {
|
|
496
|
+
dom.utils.setStyle(cellsInRow[c], 'width', '');
|
|
497
|
+
}
|
|
498
|
+
}
|
|
449
499
|
}
|
|
450
500
|
|
|
451
501
|
// figure
|
|
@@ -860,13 +910,17 @@ class Table extends EditorInjector {
|
|
|
860
910
|
this._maxWidth = !this._maxWidth;
|
|
861
911
|
this._setTableStyle('width', false);
|
|
862
912
|
this._historyPush();
|
|
863
|
-
|
|
913
|
+
_w.setTimeout(() => {
|
|
914
|
+
this.component.select(this._element, Table.key, { isInput: true });
|
|
915
|
+
}, 0);
|
|
864
916
|
break;
|
|
865
917
|
case 'layout':
|
|
866
918
|
this._fixedColumn = !this._fixedColumn;
|
|
867
919
|
this._setTableStyle('column', false);
|
|
868
920
|
this._historyPush();
|
|
869
|
-
|
|
921
|
+
_w.setTimeout(() => {
|
|
922
|
+
this.component.select(this._element, Table.key, { isInput: true });
|
|
923
|
+
}, 0);
|
|
870
924
|
break;
|
|
871
925
|
case 'copy':
|
|
872
926
|
this.component.copy(this._figure);
|
|
@@ -2141,16 +2195,17 @@ class Table extends EditorInjector {
|
|
|
2141
2195
|
/**
|
|
2142
2196
|
* @private
|
|
2143
2197
|
* @description Converts the width of <col> elements to percentages.
|
|
2198
|
+
* @param {HTMLTableElement} target - The target table element.
|
|
2144
2199
|
*/
|
|
2145
|
-
_resizePercentCol() {
|
|
2146
|
-
const cols =
|
|
2147
|
-
const tableTotalWidth =
|
|
2200
|
+
_resizePercentCol(target) {
|
|
2201
|
+
const cols = target.querySelector('colgroup').querySelectorAll('col');
|
|
2202
|
+
const tableTotalWidth = target.offsetWidth;
|
|
2148
2203
|
|
|
2149
2204
|
cols.forEach((col) => {
|
|
2150
|
-
const colWidthString =
|
|
2205
|
+
const colWidthString = col.style.width;
|
|
2151
2206
|
|
|
2152
2207
|
if (!colWidthString.endsWith('%')) {
|
|
2153
|
-
const pixelWidth = numbers.get(colWidthString,
|
|
2208
|
+
const pixelWidth = col.offsetWidth || numbers.get(colWidthString, CELL_DECIMAL_END);
|
|
2154
2209
|
const percentage = (pixelWidth / tableTotalWidth) * 100;
|
|
2155
2210
|
col.style.width = percentage + '%';
|
|
2156
2211
|
}
|
|
@@ -2166,7 +2221,7 @@ class Table extends EditorInjector {
|
|
|
2166
2221
|
* @param {boolean} isLeftEdge Whether the resizing is on the left edge.
|
|
2167
2222
|
*/
|
|
2168
2223
|
_startCellResizing(col, startX, startWidth, isLeftEdge) {
|
|
2169
|
-
this._resizePercentCol();
|
|
2224
|
+
this._resizePercentCol(this._element);
|
|
2170
2225
|
this._setResizeLinePosition(this._figure, this._tdElement, this._resizeLinePrev, isLeftEdge);
|
|
2171
2226
|
this._resizeLinePrev.style.display = 'block';
|
|
2172
2227
|
const prevValue = col.style.width;
|
|
@@ -2192,7 +2247,7 @@ class Table extends EditorInjector {
|
|
|
2192
2247
|
),
|
|
2193
2248
|
() => {
|
|
2194
2249
|
this.__removeGlobalEvents();
|
|
2195
|
-
this._resizePercentCol();
|
|
2250
|
+
this._resizePercentCol(this._element);
|
|
2196
2251
|
this.history.push(true);
|
|
2197
2252
|
this.component.select(this._element, Table.key, { isInput: true });
|
|
2198
2253
|
},
|
|
@@ -91,7 +91,7 @@ class Image_ extends EditorInjector {
|
|
|
91
91
|
? [[ctrlAs, 'mirror_h', 'mirror_v', 'align', 'caption', 'edit', 'revert', 'copy', 'remove']]
|
|
92
92
|
: [
|
|
93
93
|
[ctrlAs, 'resize_auto,100,75,50', 'rotate_l', 'rotate_r', 'mirror_h', 'mirror_v'],
|
|
94
|
-
['
|
|
94
|
+
['edit', 'align', 'caption', 'revert', 'copy', 'remove']
|
|
95
95
|
];
|
|
96
96
|
|
|
97
97
|
// show align
|
|
@@ -276,7 +276,7 @@ class Image_ extends EditorInjector {
|
|
|
276
276
|
query: 'img',
|
|
277
277
|
method: (element) => {
|
|
278
278
|
const figureInfo = Figure.GetContainer(element);
|
|
279
|
-
if (figureInfo && figureInfo.container && figureInfo.cover) return;
|
|
279
|
+
if (figureInfo && figureInfo.container && (figureInfo.cover || figureInfo.inlineCover)) return;
|
|
280
280
|
|
|
281
281
|
this._ready(element);
|
|
282
282
|
this._fileCheck(this._origin_w, this._origin_h);
|
|
@@ -585,6 +585,13 @@ class Image_ extends EditorInjector {
|
|
|
585
585
|
if (!height) height = this.inputY?.value || 'auto';
|
|
586
586
|
|
|
587
587
|
let imageEl = this._element;
|
|
588
|
+
|
|
589
|
+
// as (block | inline)
|
|
590
|
+
if ((this.as === 'block' && !this._cover) || (this.as === 'inline' && this._cover)) {
|
|
591
|
+
imageEl = this.figure.convertAsFormat(imageEl, this.as);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// --- update image ---
|
|
588
595
|
const cover = this._cover;
|
|
589
596
|
const container = this._container === this._cover ? null : this._container;
|
|
590
597
|
|
|
@@ -661,6 +668,8 @@ class Image_ extends EditorInjector {
|
|
|
661
668
|
imageEl.onload = () => {
|
|
662
669
|
this.select(imageEl);
|
|
663
670
|
};
|
|
671
|
+
|
|
672
|
+
this._ready(imageEl);
|
|
664
673
|
}
|
|
665
674
|
|
|
666
675
|
/**
|
|
@@ -692,16 +701,6 @@ class Image_ extends EditorInjector {
|
|
|
692
701
|
this.figure.open(imageEl, { nonResizing: true, nonSizeInfo: false, nonBorder: false, figureTarget: false, __fileManagerInfo: true });
|
|
693
702
|
}
|
|
694
703
|
|
|
695
|
-
// check size
|
|
696
|
-
let changeSize;
|
|
697
|
-
const x = numbers.is(width) ? width + this.sizeUnit : width;
|
|
698
|
-
const y = numbers.is(height) ? height + this.sizeUnit : height;
|
|
699
|
-
if (/%$/.test(imageEl.style.width)) {
|
|
700
|
-
changeSize = x !== container.style.width || y !== container.style.height;
|
|
701
|
-
} else {
|
|
702
|
-
changeSize = x !== imageEl.style.width || y !== imageEl.style.height;
|
|
703
|
-
}
|
|
704
|
-
|
|
705
704
|
// alt
|
|
706
705
|
imageEl.alt = this.altText.value;
|
|
707
706
|
|
|
@@ -749,9 +748,11 @@ class Image_ extends EditorInjector {
|
|
|
749
748
|
}
|
|
750
749
|
|
|
751
750
|
// size
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
751
|
+
imageEl.style.width = '';
|
|
752
|
+
imageEl.style.height = '';
|
|
753
|
+
imageEl.removeAttribute('width');
|
|
754
|
+
imageEl.removeAttribute('height');
|
|
755
|
+
this._applySize(width, height);
|
|
755
756
|
|
|
756
757
|
if (isNewAnchor) {
|
|
757
758
|
if (!isNewContainer) {
|
|
@@ -765,7 +766,7 @@ class Image_ extends EditorInjector {
|
|
|
765
766
|
}
|
|
766
767
|
|
|
767
768
|
// transform
|
|
768
|
-
if (modifiedCaption ||
|
|
769
|
+
if (modifiedCaption || !this._onlyPercentage) {
|
|
769
770
|
if (/\d+/.test(imageEl.style.height) || (this.figure.isVertical && this.captionCheckEl.checked)) {
|
|
770
771
|
if (/auto|%$/.test(width) || /auto|%$/.test(height)) {
|
|
771
772
|
this.figure.deleteTransform(imageEl);
|
package/src/suneditor.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import Editor from './core/editor';
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
3
|
+
import editorInjector from './editorInjector';
|
|
4
|
+
import plugins from './plugins';
|
|
5
|
+
import langs from './langs';
|
|
6
|
+
import modules from './modules';
|
|
7
|
+
import helper from './helper';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* @module SunEditorExports
|
|
@@ -21,27 +21,27 @@ import Helper from './helper';
|
|
|
21
21
|
/**
|
|
22
22
|
* Editor Injector module, Inject "editor" and basic frequently used objects by calling it with "call(this, editor)".
|
|
23
23
|
*/
|
|
24
|
-
export {
|
|
24
|
+
export { editorInjector };
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* Available editor plugins
|
|
28
28
|
*/
|
|
29
|
-
export {
|
|
29
|
+
export { plugins };
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
32
|
* Editor modules
|
|
33
33
|
*/
|
|
34
|
-
export {
|
|
34
|
+
export { modules };
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
37
|
* Language packs for the editor
|
|
38
38
|
*/
|
|
39
|
-
export {
|
|
39
|
+
export { langs };
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
42
|
* Helper functions for the editor
|
|
43
43
|
*/
|
|
44
|
-
export {
|
|
44
|
+
export { helper };
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
47
|
* SunEditor Factory Object
|
|
@@ -62,7 +62,10 @@ export default {
|
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
64
|
* Creates a new instance of the SunEditor
|
|
65
|
-
* @param {Element|Object<string, {target: Element, options: EditorFrameOptions_suneditor}>} target
|
|
65
|
+
* @param {Element|string|Object<string, {target: Element, options: EditorFrameOptions_suneditor}>} target
|
|
66
|
+
* - Element: The direct DOM element to initialize the editor on.
|
|
67
|
+
* - string: A CSS selector string. The corresponding element is selected using `document.querySelector`.
|
|
68
|
+
* - Object: For multi-root setup. Each key maps to a config with `{target, options}`.
|
|
66
69
|
* @param {EditorInitOptions_suneditor} options - Initialization options
|
|
67
70
|
* @param {EditorInitOptions_suneditor} [_init_options] - Optional preset initialization options
|
|
68
71
|
* @returns {Editor} - Instance of the SunEditor
|
|
@@ -90,7 +93,11 @@ export default {
|
|
|
90
93
|
if (!target) throw Error("[SUNEDITOR.create.fail] suneditor requires textarea's element");
|
|
91
94
|
|
|
92
95
|
const multiTargets = [];
|
|
93
|
-
if (target
|
|
96
|
+
if (typeof target === 'string') {
|
|
97
|
+
const t = document.querySelector(target);
|
|
98
|
+
if (!t) throw Error(`[SUNEDITOR.create.fail]-[document.querySelector(${target})] Cannot find target element. Make sure "${target}" is a valid selector and exists in the document.`);
|
|
99
|
+
multiTargets.push({ key: null, target: t });
|
|
100
|
+
} else if (target.nodeType === 1) {
|
|
94
101
|
multiTargets.push({ key: null, target: target });
|
|
95
102
|
} else {
|
|
96
103
|
let props;
|
|
@@ -134,6 +134,8 @@ declare namespace _default {
|
|
|
134
134
|
export let side_menu_item: string;
|
|
135
135
|
export let side_menu_folder_plus: string;
|
|
136
136
|
export let alert_outline: string;
|
|
137
|
+
export let more_media: string;
|
|
138
|
+
export let more_view: string;
|
|
137
139
|
export let more_text: string;
|
|
138
140
|
export let more_paragraph: string;
|
|
139
141
|
export let more_plus: string;
|
|
@@ -283,9 +283,9 @@ declare class EventManager {
|
|
|
283
283
|
* @this {EventManagerThis}
|
|
284
284
|
* @description Adjusts the position of the editor's toolbar, controllers, and other floating elements based on scroll position.
|
|
285
285
|
* - Ensures UI elements maintain their intended relative positions when scrolling.
|
|
286
|
-
* @param {
|
|
286
|
+
* @param {*} eventWysiwyg The wysiwyg event object containing scroll data (Window or element)
|
|
287
287
|
*/
|
|
288
|
-
_moveContainer(this: Omit<EventManager & Partial<import('../../editorInjector').default>, 'eventManager'>, eventWysiwyg:
|
|
288
|
+
_moveContainer(this: Omit<EventManager & Partial<import('../../editorInjector').default>, 'eventManager'>, eventWysiwyg: any): void;
|
|
289
289
|
/**
|
|
290
290
|
* @private
|
|
291
291
|
* @this {EventManagerThis}
|
|
@@ -370,6 +370,7 @@ declare class Offset {
|
|
|
370
370
|
* @param {{left:number, top:number}} [params.addOffset={left:0, top:0}] Additional offset
|
|
371
371
|
* @param {"bottom"|"top"} [params.position="bottom"] Position ('bottom'|'top')
|
|
372
372
|
* @param {*} params.inst Instance object of caller
|
|
373
|
+
* @param {HTMLElement} [params.sibling] The sibling controller element
|
|
373
374
|
* @returns {{position: "top" | "bottom"} | undefined} Success -> {position: current position}
|
|
374
375
|
*/
|
|
375
376
|
setAbsPosition(
|
|
@@ -384,6 +385,7 @@ declare class Offset {
|
|
|
384
385
|
};
|
|
385
386
|
position?: 'bottom' | 'top';
|
|
386
387
|
inst: any;
|
|
388
|
+
sibling?: HTMLElement;
|
|
387
389
|
}
|
|
388
390
|
):
|
|
389
391
|
| {
|
|
@@ -459,7 +461,12 @@ declare class Offset {
|
|
|
459
461
|
* @param {RectsInfo} targetRect Target rect object
|
|
460
462
|
* @param {boolean} isTargetAbs Is target absolute position
|
|
461
463
|
* @param {OffsetWWScrollInfo} wwScroll WYSIWYG scroll info
|
|
462
|
-
* @returns {{rmt:number, rmb:number, rt:number
|
|
464
|
+
* @returns {{rmt:number, rmb:number, rt:number, tMargin:number, bMargin:number}} Margin values
|
|
465
|
+
* - rmt: top margin to frame
|
|
466
|
+
* - rmb: bottom margin to frame
|
|
467
|
+
* - rt: Toolbar height offset adjustment
|
|
468
|
+
* - tMargin: top margin
|
|
469
|
+
* - bMargin: bottom margin
|
|
463
470
|
*/
|
|
464
471
|
_getVMargin(
|
|
465
472
|
this: Omit<Offset & Partial<import('../../editorInjector').default>, 'offset'>,
|
|
@@ -477,6 +484,8 @@ declare class Offset {
|
|
|
477
484
|
rmt: number;
|
|
478
485
|
rmb: number;
|
|
479
486
|
rt: number;
|
|
487
|
+
tMargin: number;
|
|
488
|
+
bMargin: number;
|
|
480
489
|
};
|
|
481
490
|
/**
|
|
482
491
|
* @private
|