suneditor 3.0.0-rc.4 → 3.0.0
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 +4 -3
- package/dist/suneditor-contents.min.css +1 -1
- package/dist/suneditor.min.css +1 -1
- package/dist/suneditor.min.js +1 -1
- package/package.json +10 -6
- package/src/assets/design/color.css +14 -2
- package/src/assets/design/typography.css +5 -0
- package/src/assets/icons/defaultIcons.js +22 -4
- package/src/assets/suneditor-contents.css +1 -1
- package/src/assets/suneditor.css +312 -18
- package/src/core/config/eventManager.js +6 -9
- package/src/core/editor.js +1 -1
- package/src/core/event/actions/index.js +5 -0
- package/src/core/event/effects/keydown.registry.js +25 -0
- package/src/core/event/eventOrchestrator.js +69 -2
- package/src/core/event/handlers/handler_ww_mouse.js +1 -0
- package/src/core/event/rules/keydown.rule.backspace.js +9 -1
- package/src/core/kernel/coreKernel.js +4 -0
- package/src/core/kernel/store.js +2 -0
- package/src/core/logic/dom/char.js +11 -0
- package/src/core/logic/dom/format.js +22 -0
- package/src/core/logic/dom/html.js +126 -11
- package/src/core/logic/dom/nodeTransform.js +13 -0
- package/src/core/logic/dom/offset.js +100 -37
- package/src/core/logic/dom/selection.js +54 -22
- package/src/core/logic/panel/finder.js +982 -0
- package/src/core/logic/panel/menu.js +8 -6
- package/src/core/logic/panel/toolbar.js +112 -19
- package/src/core/logic/panel/viewer.js +214 -43
- package/src/core/logic/shell/_commandExecutor.js +7 -1
- package/src/core/logic/shell/commandDispatcher.js +1 -1
- package/src/core/logic/shell/component.js +5 -7
- package/src/core/logic/shell/history.js +24 -0
- package/src/core/logic/shell/shortcuts.js +3 -3
- package/src/core/logic/shell/ui.js +25 -26
- package/src/core/schema/frameContext.js +15 -1
- package/src/core/schema/options.js +180 -39
- package/src/core/section/constructor.js +61 -20
- package/src/core/section/documentType.js +2 -2
- package/src/events.js +12 -0
- package/src/helper/clipboard.js +1 -1
- package/src/helper/converter.js +15 -0
- package/src/helper/dom/domQuery.js +12 -0
- package/src/helper/dom/domUtils.js +26 -14
- package/src/helper/index.js +3 -0
- package/src/helper/markdown.js +876 -0
- package/src/interfaces/plugins.js +7 -5
- package/src/langs/ckb.js +9 -0
- package/src/langs/cs.js +9 -0
- package/src/langs/da.js +9 -0
- package/src/langs/de.js +9 -0
- package/src/langs/en.js +9 -0
- package/src/langs/es.js +9 -0
- package/src/langs/fa.js +9 -0
- package/src/langs/fr.js +9 -0
- package/src/langs/he.js +9 -0
- package/src/langs/hu.js +9 -0
- package/src/langs/it.js +9 -0
- package/src/langs/ja.js +9 -0
- package/src/langs/km.js +9 -0
- package/src/langs/ko.js +9 -0
- package/src/langs/lv.js +9 -0
- package/src/langs/nl.js +9 -0
- package/src/langs/pl.js +9 -0
- package/src/langs/pt_br.js +9 -0
- package/src/langs/ro.js +9 -0
- package/src/langs/ru.js +9 -0
- package/src/langs/se.js +9 -0
- package/src/langs/tr.js +9 -0
- package/src/langs/uk.js +9 -0
- package/src/langs/ur.js +9 -0
- package/src/langs/zh_cn.js +9 -0
- package/src/modules/contract/Browser.js +31 -1
- package/src/modules/contract/ColorPicker.js +6 -0
- package/src/modules/contract/Controller.js +77 -39
- package/src/modules/contract/Figure.js +57 -0
- package/src/modules/contract/Modal.js +6 -0
- package/src/modules/manager/ApiManager.js +53 -4
- package/src/modules/manager/FileManager.js +18 -1
- package/src/modules/ui/ModalAnchorEditor.js +35 -2
- package/src/modules/ui/SelectMenu.js +44 -12
- package/src/plugins/browser/fileBrowser.js +5 -2
- package/src/plugins/command/codeBlock.js +324 -0
- package/src/plugins/command/exportPDF.js +15 -3
- package/src/plugins/command/fileUpload.js +4 -1
- package/src/plugins/dropdown/backgroundColor.js +5 -1
- package/src/plugins/dropdown/blockStyle.js +8 -2
- package/src/plugins/dropdown/fontColor.js +5 -1
- package/src/plugins/dropdown/hr.js +6 -0
- package/src/plugins/dropdown/layout.js +4 -1
- package/src/plugins/dropdown/lineHeight.js +3 -0
- package/src/plugins/dropdown/paragraphStyle.js +5 -5
- package/src/plugins/dropdown/table/index.js +4 -1
- package/src/plugins/dropdown/table/render/table.html.js +1 -1
- package/src/plugins/dropdown/table/services/table.grid.js +16 -8
- package/src/plugins/dropdown/table/services/table.style.js +5 -9
- package/src/plugins/dropdown/template.js +3 -0
- package/src/plugins/dropdown/textStyle.js +5 -1
- package/src/plugins/field/mention.js +5 -1
- package/src/plugins/index.js +3 -0
- package/src/plugins/input/fontSize.js +10 -3
- package/src/plugins/modal/audio.js +7 -3
- package/src/plugins/modal/embed.js +23 -20
- package/src/plugins/modal/image/index.js +5 -1
- package/src/plugins/modal/math.js +7 -2
- package/src/plugins/modal/video/index.js +21 -4
- package/src/themes/cobalt.css +13 -4
- package/src/themes/cream.css +11 -2
- package/src/themes/dark.css +13 -4
- package/src/themes/midnight.css +13 -4
- package/src/typedef.js +4 -4
- package/types/assets/icons/defaultIcons.d.ts +12 -1
- package/types/assets/suneditor.css.d.ts +1 -1
- package/types/core/config/eventManager.d.ts +6 -8
- package/types/core/event/actions/index.d.ts +1 -0
- package/types/core/event/effects/keydown.registry.d.ts +2 -0
- package/types/core/event/eventOrchestrator.d.ts +2 -1
- package/types/core/kernel/coreKernel.d.ts +5 -0
- package/types/core/kernel/store.d.ts +5 -0
- package/types/core/logic/dom/char.d.ts +11 -0
- package/types/core/logic/dom/format.d.ts +22 -0
- package/types/core/logic/dom/html.d.ts +16 -0
- package/types/core/logic/dom/nodeTransform.d.ts +13 -0
- package/types/core/logic/dom/offset.d.ts +23 -2
- package/types/core/logic/dom/selection.d.ts +9 -3
- package/types/core/logic/panel/finder.d.ts +83 -0
- package/types/core/logic/panel/toolbar.d.ts +14 -1
- package/types/core/logic/panel/viewer.d.ts +22 -2
- package/types/core/logic/shell/shortcuts.d.ts +1 -1
- package/types/core/schema/frameContext.d.ts +22 -0
- package/types/core/schema/options.d.ts +362 -79
- package/types/events.d.ts +11 -0
- package/types/helper/converter.d.ts +15 -0
- package/types/helper/dom/domQuery.d.ts +12 -0
- package/types/helper/dom/domUtils.d.ts +23 -2
- package/types/helper/index.d.ts +5 -0
- package/types/helper/markdown.d.ts +27 -0
- package/types/interfaces/plugins.d.ts +7 -5
- package/types/langs/_Lang.d.ts +9 -0
- package/types/modules/contract/Browser.d.ts +36 -2
- package/types/modules/contract/ColorPicker.d.ts +6 -0
- package/types/modules/contract/Controller.d.ts +35 -1
- package/types/modules/contract/Figure.d.ts +57 -0
- package/types/modules/contract/Modal.d.ts +6 -0
- package/types/modules/manager/ApiManager.d.ts +26 -0
- package/types/modules/manager/FileManager.d.ts +17 -0
- package/types/modules/ui/ModalAnchorEditor.d.ts +41 -4
- package/types/modules/ui/SelectMenu.d.ts +40 -2
- package/types/plugins/browser/fileBrowser.d.ts +10 -4
- package/types/plugins/command/codeBlock.d.ts +53 -0
- package/types/plugins/command/fileUpload.d.ts +8 -2
- package/types/plugins/dropdown/backgroundColor.d.ts +10 -2
- package/types/plugins/dropdown/blockStyle.d.ts +14 -2
- package/types/plugins/dropdown/fontColor.d.ts +10 -2
- package/types/plugins/dropdown/hr.d.ts +12 -0
- package/types/plugins/dropdown/layout.d.ts +8 -2
- package/types/plugins/dropdown/lineHeight.d.ts +6 -0
- package/types/plugins/dropdown/paragraphStyle.d.ts +14 -3
- package/types/plugins/dropdown/table/index.d.ts +9 -3
- package/types/plugins/dropdown/template.d.ts +6 -0
- package/types/plugins/dropdown/textStyle.d.ts +10 -2
- package/types/plugins/field/mention.d.ts +10 -2
- package/types/plugins/index.d.ts +3 -0
- package/types/plugins/input/fontSize.d.ts +18 -4
- package/types/plugins/modal/audio.d.ts +14 -6
- package/types/plugins/modal/embed.d.ts +44 -38
- package/types/plugins/modal/image/index.d.ts +9 -1
- package/types/plugins/modal/link.d.ts +6 -2
- package/types/plugins/modal/math.d.ts +23 -5
- package/types/plugins/modal/video/index.d.ts +49 -9
- package/types/typedef.d.ts +5 -2
|
@@ -35,7 +35,7 @@ class FileManager {
|
|
|
35
35
|
this.uploadFileLength = 0;
|
|
36
36
|
this.__updateTags = [];
|
|
37
37
|
// api manager
|
|
38
|
-
this.apiManager = new ApiManager(this,
|
|
38
|
+
this.apiManager = new ApiManager(this, $);
|
|
39
39
|
|
|
40
40
|
// se-ts-ignore - call by editor
|
|
41
41
|
void this._resetInfo;
|
|
@@ -49,6 +49,15 @@ class FileManager {
|
|
|
49
49
|
* @param {FileList|File[]|{formData: FormData, size: number}} data FormData in body or Files array
|
|
50
50
|
* @param {?(xmlHttp: XMLHttpRequest) => boolean} [callBack] Success call back function
|
|
51
51
|
* @param {?(res: *, xmlHttp: XMLHttpRequest) => string} [errorCallBack] Error call back function
|
|
52
|
+
* @example
|
|
53
|
+
* // Upload with a File array
|
|
54
|
+
* const files = [new File(['content'], 'photo.jpg', { type: 'image/jpeg' })];
|
|
55
|
+
* fileManager.upload('/api/upload', { Authorization: 'Bearer token' }, files, onSuccess, onError);
|
|
56
|
+
*
|
|
57
|
+
* // Upload with a pre-built FormData
|
|
58
|
+
* const formData = new FormData();
|
|
59
|
+
* formData.append('file-0', myFile);
|
|
60
|
+
* fileManager.upload('/api/upload', null, { formData, size: 1 }, onSuccess, onError);
|
|
52
61
|
*/
|
|
53
62
|
upload(uploadUrl, uploadHeader, data, callBack, errorCallBack) {
|
|
54
63
|
this.#$.ui.showLoading();
|
|
@@ -75,6 +84,10 @@ class FileManager {
|
|
|
75
84
|
* @param {?Object<string, string>} uploadHeader Request header
|
|
76
85
|
* @param {FileList|File[]|{formData: FormData, size: number}} data FormData in body or Files array
|
|
77
86
|
* @returns {Promise<XMLHttpRequest>}
|
|
87
|
+
* @example
|
|
88
|
+
* const files = [new File(['content'], 'photo.jpg')];
|
|
89
|
+
* const xmlHttp = await fileManager.asyncUpload('/api/upload', { Authorization: 'Bearer token' }, files);
|
|
90
|
+
* const response = JSON.parse(xmlHttp.responseText);
|
|
78
91
|
*/
|
|
79
92
|
async asyncUpload(uploadUrl, uploadHeader, data) {
|
|
80
93
|
this.#$.ui.showLoading();
|
|
@@ -102,6 +115,10 @@ class FileManager {
|
|
|
102
115
|
* @param {string} params.name File name
|
|
103
116
|
* @param {number} params.size File size
|
|
104
117
|
* @returns
|
|
118
|
+
* @example
|
|
119
|
+
* const imgElement = document.createElement('img');
|
|
120
|
+
* imgElement.src = 'https://example.com/photo.jpg';
|
|
121
|
+
* fileManager.setFileData(imgElement, { name: 'photo.jpg', size: 2048 });
|
|
105
122
|
*/
|
|
106
123
|
setFileData(element, { name, size }) {
|
|
107
124
|
if (!element) return;
|
|
@@ -9,8 +9,12 @@ const { _w, NO_EVENT } = env;
|
|
|
9
9
|
* @property {boolean} [textToDisplay=''] - Create Text to display input.
|
|
10
10
|
* @property {boolean} [openNewWindow=false] - Default checked value of the "Open in new window" checkbox.
|
|
11
11
|
* @property {boolean} [noAutoPrefix=false] - If `true`, disables the automatic prefixing of the host URL to the value of the link.
|
|
12
|
-
* @property {Array<string>} [relList=[]] -
|
|
13
|
-
* @property {{default?: string, check_new_window?: string, check_bookmark?: string}} [defaultRel={}] - Default `rel`
|
|
12
|
+
* @property {Array<string>} [relList=[]] - Available `rel` attribute values shown as checkboxes in the link modal.
|
|
13
|
+
* @property {{default?: string, check_new_window?: string, check_bookmark?: string}} [defaultRel={}] - Default `rel` values auto-applied by condition.
|
|
14
|
+
* `default` is always applied, `check_new_window` when "Open in new window" is checked, `check_bookmark` for bookmark links.
|
|
15
|
+
* ```js
|
|
16
|
+
* { relList: ['nofollow', 'noreferrer', 'noopener'], defaultRel: { default: 'noopener', check_new_window: 'noreferrer' } }
|
|
17
|
+
* ```
|
|
14
18
|
* @property {string} [uploadUrl] - File upload URL.
|
|
15
19
|
* @property {Object<string, string>} [uploadHeaders] - File upload headers.
|
|
16
20
|
* @property {number} [uploadSizeLimit] - File upload size limit.
|
|
@@ -37,6 +41,17 @@ class ModalAnchorEditor {
|
|
|
37
41
|
* @param {SunEditor.Deps} $ Kernel dependencies
|
|
38
42
|
* @param {HTMLElement} modalForm Modal <form>
|
|
39
43
|
* @param {ModalAnchorEditorParams} params ModalAnchorEditor options
|
|
44
|
+
* @example
|
|
45
|
+
* // In a link plugin (text anchor):
|
|
46
|
+
* this.anchor = new ModalAnchorEditor(this.$, modalEl, this.pluginOptions);
|
|
47
|
+
*
|
|
48
|
+
* // In an image plugin (non-text anchor with custom options):
|
|
49
|
+
* const linkOptions = this.$.plugins.link ? this.$.plugins.link.pluginOptions : {};
|
|
50
|
+
* this.anchor = new ModalAnchorEditor(this.$, modalEl.html, {
|
|
51
|
+
* ...linkOptions,
|
|
52
|
+
* textToDisplay: false,
|
|
53
|
+
* title: true,
|
|
54
|
+
* });
|
|
40
55
|
*/
|
|
41
56
|
constructor($, modalForm, params) {
|
|
42
57
|
this.#$ = $;
|
|
@@ -149,6 +164,13 @@ class ModalAnchorEditor {
|
|
|
149
164
|
/**
|
|
150
165
|
* @description Opens the anchor editor modal and populates it with data.
|
|
151
166
|
* @param {boolean} isUpdate - Indicates whether an existing anchor is being updated (`true`) or a new one is being created (`false`).
|
|
167
|
+
* @example
|
|
168
|
+
* // Called from modalOn() — populate form for a new link:
|
|
169
|
+
* this.anchor.on(false);
|
|
170
|
+
*
|
|
171
|
+
* // Populate form to edit an existing link (call set() first):
|
|
172
|
+
* this.anchor.set(existingAnchorElement);
|
|
173
|
+
* this.anchor.on(true);
|
|
152
174
|
*/
|
|
153
175
|
on(isUpdate) {
|
|
154
176
|
if (!isUpdate) {
|
|
@@ -173,6 +195,17 @@ class ModalAnchorEditor {
|
|
|
173
195
|
* @description Creates an anchor (`<a>`) element with the specified attributes.
|
|
174
196
|
* @param {boolean} notText - If `true`, the anchor will not contain text content.
|
|
175
197
|
* @returns {HTMLElement|null} - The newly created anchor element, or `null` if the URL is empty.
|
|
198
|
+
* @example
|
|
199
|
+
* // In a link plugin — create anchor with text content:
|
|
200
|
+
* const oA = this.anchor.create(false);
|
|
201
|
+
* if (oA === null) return false;
|
|
202
|
+
* this.$.html.insertNode(oA);
|
|
203
|
+
*
|
|
204
|
+
* // In an image plugin — create anchor without text (wraps an image):
|
|
205
|
+
* const anchor = this.anchor.create(true);
|
|
206
|
+
* if (anchor) {
|
|
207
|
+
* anchor.appendChild(imgElement);
|
|
208
|
+
* }
|
|
176
209
|
*/
|
|
177
210
|
create(notText) {
|
|
178
211
|
if (this.linkValue.length === 0) return null;
|
|
@@ -5,12 +5,19 @@ const MENU_MIN_HEIGHT = 38;
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* @typedef {Object} SelectMenuParams
|
|
8
|
-
* @property {string} position Position of the select menu, specified as `"[left|right]-[middle|top|bottom]"` or `"[top|bottom]-[center|left|right]"
|
|
8
|
+
* @property {string} position Position of the select menu, specified as `"[left|right]-[middle|top|bottom]"` or `"[top|bottom]-[center|left|right]"`.
|
|
9
|
+
* ```js
|
|
10
|
+
* // position
|
|
11
|
+
* 'left-bottom' // menu appears below, aligned to the left
|
|
12
|
+
* 'top-center' // menu appears above, centered
|
|
13
|
+
* ```
|
|
9
14
|
* @property {boolean} [checkList=false] Flag to determine if the checklist is enabled (`true` or `false`)
|
|
10
15
|
* @property {"rtl" | "ltr"} [dir="ltr"] Optional text direction: `"rtl"` for right-to-left, `"ltr"` for left-to-right
|
|
11
16
|
* @property {number} [splitNum=0] Optional split number for horizontal positioning; defines how many items per row
|
|
12
17
|
* @property {() => void} [openMethod] Optional method to call when the menu is opened
|
|
13
18
|
* @property {() => void} [closeMethod] Optional method to call when the menu is closed
|
|
19
|
+
* @property {string} [maxHeight] Optional max-height CSS value (e.g. `"200px"`). Enables scrolling when items exceed this height.
|
|
20
|
+
* @property {string} [minWidth] Optional min-width CSS value (e.g. `"130px"`).
|
|
14
21
|
*/
|
|
15
22
|
|
|
16
23
|
/**
|
|
@@ -59,6 +66,8 @@ class SelectMenu {
|
|
|
59
66
|
this.horizontal = !!this.splitNum;
|
|
60
67
|
this.openMethod = params.openMethod;
|
|
61
68
|
this.closeMethod = params.closeMethod;
|
|
69
|
+
this.maxHeight = params.maxHeight || '';
|
|
70
|
+
this.minWidth = params.minWidth || '';
|
|
62
71
|
|
|
63
72
|
this.#dirPosition = /^(left|right)$/.test(this.position) ? (this.position === 'left' ? 'right' : 'left') : this.position;
|
|
64
73
|
this.#dirSubPosition = /^(left|right)$/.test(this.subPosition) ? (this.subPosition === 'left' ? 'right' : 'left') : this.subPosition;
|
|
@@ -101,26 +110,48 @@ class SelectMenu {
|
|
|
101
110
|
* @param {Node} referElement - The element that triggers the select menu.
|
|
102
111
|
* @param {(command: string) => void} selectMethod - The function to execute when an item is selected.
|
|
103
112
|
* @param {{class?: string, style?: string}} [attr={}] - Additional attributes for the select menu container.
|
|
113
|
+
* @example
|
|
114
|
+
* // Basic: attach menu to a button with a selection callback
|
|
115
|
+
* selectMenu.on(this.alignButton, this.onAlignSelect.bind(this));
|
|
116
|
+
*
|
|
117
|
+
* // With custom attributes for styling
|
|
118
|
+
* selectMenu.on(this.alignButton, this.onAlignSelect.bind(this), { class: 'se-figure-select-list' });
|
|
104
119
|
*/
|
|
105
120
|
on(referElement, selectMethod, attr = {}) {
|
|
106
121
|
this.#refer = /** @type {HTMLElement} */ (referElement);
|
|
107
122
|
this.#keydownTarget = dom.check.isInputElement(referElement) ? referElement : this.#$.frameContext.get('_ww');
|
|
108
123
|
this.#selectMethod = selectMethod;
|
|
124
|
+
|
|
125
|
+
let innerStyle = '';
|
|
126
|
+
if (this.maxHeight) innerStyle += 'max-height:' + this.maxHeight + ';overflow-y:auto;';
|
|
127
|
+
if (this.minWidth) innerStyle += 'min-width:' + this.minWidth + ';';
|
|
128
|
+
|
|
109
129
|
this.form = dom.utils.createElement(
|
|
110
130
|
'DIV',
|
|
111
131
|
{
|
|
112
132
|
class: 'se-select-menu' + (attr.class ? ' ' + attr.class : ''),
|
|
113
133
|
style: attr.style || '',
|
|
114
134
|
},
|
|
115
|
-
'<div class="se-list-inner"></div>',
|
|
135
|
+
'<div class="se-list-inner"' + (innerStyle ? ' style="' + innerStyle + '"' : '') + '></div>',
|
|
116
136
|
);
|
|
137
|
+
|
|
117
138
|
referElement.parentNode.insertBefore(this.form, referElement);
|
|
118
139
|
}
|
|
119
140
|
|
|
120
141
|
/**
|
|
121
142
|
* @description Select menu open
|
|
122
143
|
* @param {?string} [position] `"[left|right]-[middle|top|bottom] | [top|bottom]-[center|left|right]"`
|
|
144
|
+
* Always specify in LTR orientation. In RTL environments, left/right are automatically swapped.
|
|
123
145
|
* @param {?string} [onItemQuerySelector] The querySelector string of the menu to be activated
|
|
146
|
+
* @example
|
|
147
|
+
* // Open with default position (uses constructor's position param)
|
|
148
|
+
* selectMenu.open();
|
|
149
|
+
*
|
|
150
|
+
* // Open at a specific position (always use LTR basis; RTL is auto-mirrored)
|
|
151
|
+
* selectMenu.open('bottom-left');
|
|
152
|
+
*
|
|
153
|
+
* // Open with an active item highlighted via querySelector
|
|
154
|
+
* selectMenu.open('', '[data-command="' + this.align + '"]');
|
|
124
155
|
*/
|
|
125
156
|
open(position, onItemQuerySelector) {
|
|
126
157
|
this.#$.ui.selectMenuOn = true;
|
|
@@ -386,11 +417,12 @@ class SelectMenu {
|
|
|
386
417
|
*/
|
|
387
418
|
#addEvents() {
|
|
388
419
|
this.#removeEvents();
|
|
389
|
-
this.#events =
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
420
|
+
this.#events = {
|
|
421
|
+
mousedown: this.#$.eventManager.addEvent(this.form, 'mousedown', this.#eventHandlers.mousedown),
|
|
422
|
+
mousemove: this.#$.eventManager.addEvent(this.form, 'mousemove', this.#eventHandlers.mousemove),
|
|
423
|
+
click: this.#$.eventManager.addEvent(this.form, 'click', this.#eventHandlers.click),
|
|
424
|
+
keydown: this.#$.eventManager.addEvent(this.#keydownTarget, 'keydown', this.#eventHandlers.keydown),
|
|
425
|
+
};
|
|
394
426
|
}
|
|
395
427
|
|
|
396
428
|
/**
|
|
@@ -398,10 +430,10 @@ class SelectMenu {
|
|
|
398
430
|
*/
|
|
399
431
|
#removeEvents() {
|
|
400
432
|
if (!this.#events) return;
|
|
401
|
-
this.
|
|
402
|
-
this.
|
|
403
|
-
this.
|
|
404
|
-
this
|
|
433
|
+
this.#$.eventManager.removeEvent(this.#events.mousedown);
|
|
434
|
+
this.#$.eventManager.removeEvent(this.#events.mousemove);
|
|
435
|
+
this.#$.eventManager.removeEvent(this.#events.click);
|
|
436
|
+
this.#$.eventManager.removeEvent(this.#events.keydown);
|
|
405
437
|
this.#events = null;
|
|
406
438
|
}
|
|
407
439
|
|
|
@@ -526,7 +558,7 @@ class SelectMenu {
|
|
|
526
558
|
#CloseListener_mousedown(e) {
|
|
527
559
|
const eventTarget = dom.query.getEventTarget(e);
|
|
528
560
|
if (this.form.contains(eventTarget)) return;
|
|
529
|
-
if (
|
|
561
|
+
if (!this.#refer.contains(eventTarget)) {
|
|
530
562
|
this.close();
|
|
531
563
|
} else if (!dom.check.isInputElement(eventTarget)) {
|
|
532
564
|
this.#bindClose_click = this.#$.eventManager.addGlobalEvent('click', this.#globalEventHandlers.click, true);
|
|
@@ -3,11 +3,14 @@ import { Browser } from '../../modules/contract';
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* @typedef {Object} FileBrowserPluginOptions
|
|
6
|
-
* @property {Object<string, *>|Array<*>} [data] - Direct data without server calls
|
|
6
|
+
* @property {Object<string, *>|Array<*>} [data] - Direct data without server calls (bypasses URL fetch).
|
|
7
7
|
* @property {string} [url] - Server request URL
|
|
8
8
|
* @property {Object<string, string>} [headers] - Server request headers
|
|
9
|
-
* @property {string|((item: SunEditor.Module.Browser.File) => string)} [thumbnail] - Default thumbnail
|
|
9
|
+
* @property {string|((item: SunEditor.Module.Browser.File) => string)} [thumbnail] - Default thumbnail URL or a function that returns a thumbnail URL per item.
|
|
10
10
|
* @property {Array<string>} [props] - Additional tag names
|
|
11
|
+
* ```js
|
|
12
|
+
* { url: '/api/files', headers: { Authorization: 'Bearer token' }, thumbnail: (item) => item.thumbUrl }
|
|
13
|
+
* ```
|
|
11
14
|
*/
|
|
12
15
|
|
|
13
16
|
/**
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import { PluginCommand, PluginDropdown } from '../../interfaces';
|
|
2
|
+
import { converter, dom } from '../../helper';
|
|
3
|
+
import { Controller } from '../../modules/contract';
|
|
4
|
+
import { SelectMenu } from '../../modules/ui';
|
|
5
|
+
|
|
6
|
+
void PluginDropdown;
|
|
7
|
+
|
|
8
|
+
const DEFAULT_LANGS = ['javascript', 'typescript', 'html', 'css', 'json', 'python', 'java', 'c', 'cpp', 'csharp', 'go', 'rust', 'ruby', 'php', 'swift', 'kotlin', 'sql', 'bash', 'markdown', 'xml', 'yaml'];
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @typedef {Object} CodeBlockPluginOptions
|
|
12
|
+
* @property {Array<string>} [langs] - List of selectable programming languages for code blocks.
|
|
13
|
+
* - Defaults to 21 common languages
|
|
14
|
+
* - [javascript, typescript, html, css, json, python, java, c, cpp, csharp, go, rust, ruby, php, swift, kotlin, sql, bash, markdown, xml, yaml].
|
|
15
|
+
* - Set to empty array `[]` to disable language selection UI entirely.
|
|
16
|
+
* ```js
|
|
17
|
+
* { codeBlock: { langs: ['javascript', 'python', 'html', 'css'] } }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @class
|
|
23
|
+
* @implements {PluginDropdown}
|
|
24
|
+
* @description Code block plugin — toggles `<pre>` formatting with language selection.
|
|
25
|
+
* - Toolbar: command button (toggle `<pre>`) + optional dropdown (language list)
|
|
26
|
+
* - Hover UI: shows language selector on `<pre>` hover (Controller + SelectMenu)
|
|
27
|
+
* - I/O conversion: `<pre class="language-xxx">` ↔ `<pre><code class="language-xxx">`
|
|
28
|
+
*/
|
|
29
|
+
class CodeBlock extends PluginCommand {
|
|
30
|
+
static key = 'codeBlock';
|
|
31
|
+
static className = '';
|
|
32
|
+
|
|
33
|
+
#preTag;
|
|
34
|
+
#langItems;
|
|
35
|
+
#langs;
|
|
36
|
+
|
|
37
|
+
// hover UI
|
|
38
|
+
#hoverButton;
|
|
39
|
+
#hoverSelectMenu;
|
|
40
|
+
#hoverController;
|
|
41
|
+
#hoverCurrentPre;
|
|
42
|
+
#mouseLeaveEvent;
|
|
43
|
+
#removeEventFunc;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @constructor
|
|
47
|
+
* @param {SunEditor.Kernel} kernel - The Kernel instance
|
|
48
|
+
* @param {CodeBlockPluginOptions} pluginOptions - Configuration options for the CodeBlock plugin.
|
|
49
|
+
*/
|
|
50
|
+
constructor(kernel, pluginOptions) {
|
|
51
|
+
super(kernel);
|
|
52
|
+
this.title = this.$.lang.codeBlock || 'Code Block';
|
|
53
|
+
this.icon = 'code_block';
|
|
54
|
+
|
|
55
|
+
this.#preTag = dom.utils.createElement('PRE');
|
|
56
|
+
this.#langs = pluginOptions?.langs ?? DEFAULT_LANGS;
|
|
57
|
+
|
|
58
|
+
if (!this.#langs.length) return;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* ──────────────────────────────────
|
|
62
|
+
* [[ langs select ]]
|
|
63
|
+
* ──────────────────────────────────
|
|
64
|
+
*/
|
|
65
|
+
|
|
66
|
+
// ───────────────── [[toolbar dropdown type]] ─────────────────
|
|
67
|
+
this.afterItem = dom.utils.createElement(
|
|
68
|
+
'button',
|
|
69
|
+
{ class: 'se-btn se-tooltip se-sub-arrow-btn', 'data-command': CodeBlock.key, 'data-type': 'dropdown' },
|
|
70
|
+
`${this.$.icons.arrow_down}<span class="se-tooltip-inner"><span class="se-tooltip-text">${this.$.lang.codeLanguage || 'Language'}</span></span>`,
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
const menu = CreateDropdownHTML(this.$, this.#langs);
|
|
74
|
+
this.#langItems = menu.querySelectorAll('li button');
|
|
75
|
+
this.$.menu.initDropdownTarget({ key: CodeBlock.key, type: 'dropdown' }, menu);
|
|
76
|
+
|
|
77
|
+
// ───────────────── [hover UI] ─────────────────
|
|
78
|
+
// controller
|
|
79
|
+
const containerEl = dom.utils.createElement('DIV', { class: 'se-controller se-code-lang' });
|
|
80
|
+
this.#hoverButton = dom.utils.createElement('DIV', { class: 'se-code-lang-button' });
|
|
81
|
+
this.#updateHoverButtonText('');
|
|
82
|
+
containerEl.appendChild(this.#hoverButton);
|
|
83
|
+
|
|
84
|
+
this.#hoverController = new Controller(this, this.$, containerEl, { position: 'top', isWWTarget: true });
|
|
85
|
+
|
|
86
|
+
// mouseleave handler
|
|
87
|
+
this.#removeEventFunc = converter.debounce((e) => {
|
|
88
|
+
this.#mouseLeaveEvent = this.$.eventManager.removeEvent(this.#mouseLeaveEvent);
|
|
89
|
+
|
|
90
|
+
if (e && containerEl.contains(e.relatedTarget)) {
|
|
91
|
+
this.#addCtrlLeaveEvent();
|
|
92
|
+
} else {
|
|
93
|
+
this.#hideHover();
|
|
94
|
+
}
|
|
95
|
+
}, 0);
|
|
96
|
+
|
|
97
|
+
// SelectMenu
|
|
98
|
+
this.#hoverSelectMenu = new SelectMenu(this.$, {
|
|
99
|
+
position: 'bottom-right',
|
|
100
|
+
dir: this.$.options.get('_rtl') ? 'rtl' : 'ltr',
|
|
101
|
+
maxHeight: '214px',
|
|
102
|
+
minWidth: '132px',
|
|
103
|
+
closeMethod: this.#removeEventFunc,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
this.#hoverSelectMenu.on(this.#hoverButton, this.#onHoverSelect.bind(this));
|
|
107
|
+
this.#buildHoverMenu('');
|
|
108
|
+
|
|
109
|
+
// selectMenu
|
|
110
|
+
this.$.eventManager.addEvent(this.#hoverButton, 'click', (e) => {
|
|
111
|
+
e.preventDefault();
|
|
112
|
+
e.stopPropagation();
|
|
113
|
+
if (this.#hoverSelectMenu.isOpen) {
|
|
114
|
+
this.#hoverSelectMenu.close();
|
|
115
|
+
} else {
|
|
116
|
+
const currentLang = this.#getPreLang(this.#hoverCurrentPre);
|
|
117
|
+
this.#buildHoverMenu(currentLang);
|
|
118
|
+
const items = this.#hoverSelectMenu.items;
|
|
119
|
+
const idx = currentLang ? items.indexOf(currentLang) : 0;
|
|
120
|
+
this.#hoverSelectMenu.open(null, idx >= 0 ? `[data-index="${idx}"]` : null);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* @hook Editor.EventManager
|
|
127
|
+
* @type {SunEditor.Hook.Event.OnMouseMove}
|
|
128
|
+
*/
|
|
129
|
+
onMouseMove({ event }) {
|
|
130
|
+
if (!this.#hoverController) return;
|
|
131
|
+
const eventTarget = dom.query.getEventTarget(event);
|
|
132
|
+
const pre = eventTarget.closest('pre');
|
|
133
|
+
|
|
134
|
+
if (pre && !this.#isHoverOpen() && this.$.ui.opendControllers.length === 0) {
|
|
135
|
+
this.#showHover(pre);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* @hook Editor.EventManager
|
|
141
|
+
* @type {SunEditor.Hook.Event.Active}
|
|
142
|
+
*/
|
|
143
|
+
active(element, target) {
|
|
144
|
+
if (/^PRE$/i.test(element?.nodeName)) {
|
|
145
|
+
dom.utils.addClass(target, 'active');
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
dom.utils.removeClass(target, 'active');
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* @override
|
|
155
|
+
* @type {PluginCommand['action']}
|
|
156
|
+
*/
|
|
157
|
+
action(target) {
|
|
158
|
+
const lang = target?.getAttribute('data-value') || '';
|
|
159
|
+
const selNode = this.$.selection.getNode();
|
|
160
|
+
const currentPre = dom.query.getParentElement(selNode, (el) => /^PRE$/i.test(el.nodeName));
|
|
161
|
+
|
|
162
|
+
if (currentPre && !lang) {
|
|
163
|
+
// toggle off: convert <pre> to default line
|
|
164
|
+
this.$.format.setLine(dom.utils.createElement(this.$.options.get('defaultLine')));
|
|
165
|
+
} else {
|
|
166
|
+
// toggle on or change language
|
|
167
|
+
if (!currentPre) {
|
|
168
|
+
this.$.format.setBrLine(this.#preTag.cloneNode(false));
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (lang) {
|
|
172
|
+
const pre = dom.query.getParentElement(this.$.selection.getNode(), (el) => /^PRE$/i.test(el.nodeName));
|
|
173
|
+
if (pre) this.#setLang(pre, lang);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
this.$.menu.dropdownOff();
|
|
178
|
+
this.$.focusManager.focus();
|
|
179
|
+
this.$.history.push(false);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* @impl Dropdown
|
|
184
|
+
* @type {PluginDropdown['on']}
|
|
185
|
+
*/
|
|
186
|
+
on() {
|
|
187
|
+
if (!this.#langItems) return;
|
|
188
|
+
const currentLang = this.#getPreLang(this.$.selection.getNode());
|
|
189
|
+
|
|
190
|
+
for (let i = 0, len = this.#langItems.length; i < len; i++) {
|
|
191
|
+
const item = this.#langItems[i];
|
|
192
|
+
dom.utils.toggleClass(item, 'active', item.getAttribute('data-value') === currentLang);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* @description Shows the hover language selector over the given pre element.
|
|
198
|
+
* @param {HTMLElement} preElement
|
|
199
|
+
*/
|
|
200
|
+
#showHover(preElement) {
|
|
201
|
+
if (this.#hoverCurrentPre === preElement && this.#hoverController.isOpen) return;
|
|
202
|
+
|
|
203
|
+
if (this.#hoverCurrentPre && this.#hoverCurrentPre !== preElement) {
|
|
204
|
+
dom.utils.removeClass(this.#hoverCurrentPre, 'se-pre-code-focus');
|
|
205
|
+
}
|
|
206
|
+
this.#hoverCurrentPre = preElement;
|
|
207
|
+
dom.utils.addClass(preElement, 'se-pre-code-focus');
|
|
208
|
+
|
|
209
|
+
this.#hoverController.open(preElement, null, { passive: true, addOffset: { right: preElement.offsetWidth } });
|
|
210
|
+
this.#updateHoverButtonText(this.#getPreLang(preElement));
|
|
211
|
+
|
|
212
|
+
this.#addPreLeaveEvent();
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
#hideHover() {
|
|
216
|
+
if (this.#hoverSelectMenu?.isOpen) return;
|
|
217
|
+
this.#closeHover();
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
#closeHover() {
|
|
221
|
+
if (this.#hoverSelectMenu?.isOpen) this.#hoverSelectMenu.close();
|
|
222
|
+
dom.utils.removeClass(this.#hoverCurrentPre, 'se-pre-code-focus');
|
|
223
|
+
this.#hoverController.close(true);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/** @hook Module.Controller */
|
|
227
|
+
controllerClose() {
|
|
228
|
+
if (this.#hoverCurrentPre) {
|
|
229
|
+
dom.utils.removeClass(this.#hoverCurrentPre, 'se-pre-code-focus');
|
|
230
|
+
this.#hoverCurrentPre = null;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
#onHoverSelect(langValue) {
|
|
235
|
+
if (!this.#hoverCurrentPre) return;
|
|
236
|
+
this.#setLang(this.#hoverCurrentPre, langValue);
|
|
237
|
+
this.#updateHoverButtonText(langValue);
|
|
238
|
+
this.#hoverSelectMenu.close();
|
|
239
|
+
this.#hideHover();
|
|
240
|
+
this.$.focusManager.focus();
|
|
241
|
+
this.$.history.push(false);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
#addPreLeaveEvent() {
|
|
245
|
+
this.#mouseLeaveEvent ??= this.$.eventManager.addEvent(this.#hoverCurrentPre, 'mouseleave', this.#removeEventFunc);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
#addCtrlLeaveEvent() {
|
|
249
|
+
this.#mouseLeaveEvent ??= this.$.eventManager.addEvent(this.#hoverController.form, 'mouseleave', this.#removeEventFunc);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
#buildHoverMenu(currentLang) {
|
|
253
|
+
const noneLabel = this.$.lang.codeLanguage_none || 'None';
|
|
254
|
+
const hasExtra = currentLang && !this.#langs.includes(currentLang);
|
|
255
|
+
const items = hasExtra ? ['', currentLang, ...this.#langs] : ['', ...this.#langs];
|
|
256
|
+
const menus = hasExtra ? [noneLabel, currentLang, ...this.#langs] : [noneLabel, ...this.#langs];
|
|
257
|
+
this.#hoverSelectMenu.create(items, menus);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
#updateHoverButtonText(lang) {
|
|
261
|
+
this.#hoverButton.innerHTML = /* html */ `<span class="se-code-lang-icon"></></span><span class="se-code-lang-text">${lang || this.$.lang.codeLanguage || 'Language'}</span>`;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
#isHoverOpen() {
|
|
265
|
+
return this.#hoverSelectMenu?.isOpen || this.#hoverController?.isOpen;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* @description Get the language from a pre element's class.
|
|
270
|
+
* @param {?Node} preOrChild - The pre element or a node inside it
|
|
271
|
+
* @returns {string}
|
|
272
|
+
*/
|
|
273
|
+
#getPreLang(preOrChild) {
|
|
274
|
+
const pre = preOrChild?.nodeName === 'PRE' ? preOrChild : dom.query.getParentElement(preOrChild, (el) => /^PRE$/i.test(el.nodeName));
|
|
275
|
+
if (!pre) return '';
|
|
276
|
+
return /** @type {HTMLElement} */ (pre).className.match(/language-(\S+)/)?.[1] || '';
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* @description Set language class on a pre element.
|
|
281
|
+
* @param {HTMLElement} pre
|
|
282
|
+
* @param {string} lang
|
|
283
|
+
*/
|
|
284
|
+
#setLang(pre, lang) {
|
|
285
|
+
pre.className = pre.className.replace(/\s*language-\S+/g, '').trim();
|
|
286
|
+
if (lang) {
|
|
287
|
+
dom.utils.addClass(pre, 'language-' + lang);
|
|
288
|
+
pre.setAttribute('data-se-lang', lang);
|
|
289
|
+
} else {
|
|
290
|
+
pre.removeAttribute('data-se-lang');
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* @description Cleans up resources.
|
|
296
|
+
*/
|
|
297
|
+
destroy() {
|
|
298
|
+
if (this.#hoverCurrentPre) {
|
|
299
|
+
dom.utils.removeClass(this.#hoverCurrentPre, 'se-pre-code-focus');
|
|
300
|
+
}
|
|
301
|
+
this.#hoverController?.form?.parentNode?.removeChild(this.#hoverController.form);
|
|
302
|
+
this.#hoverCurrentPre = null;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* @param {SunEditor.Deps} $
|
|
308
|
+
* @param {string[]} langs
|
|
309
|
+
* @returns {HTMLElement}
|
|
310
|
+
*/
|
|
311
|
+
function CreateDropdownHTML($, langs) {
|
|
312
|
+
const noneLabel = $.lang.codeLanguage_none || 'None';
|
|
313
|
+
let list = '<div class="se-list-inner"><ul class="se-list-basic">';
|
|
314
|
+
|
|
315
|
+
list += `<li><button type="button" class="se-btn se-btn-list" data-command="codeBlock" data-value="" title="${noneLabel}">${noneLabel}</button></li>`;
|
|
316
|
+
for (const lang of langs) {
|
|
317
|
+
list += `<li><button type="button" class="se-btn se-btn-list" data-command="codeBlock" data-value="${lang}" title="${lang}">${lang}</button></li>`;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
list += '</ul></div>';
|
|
321
|
+
return dom.utils.createElement('DIV', { class: 'se-dropdown se-list-layer se-list-code-block' }, list);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
export default CodeBlock;
|
|
@@ -63,12 +63,17 @@ class ExportPDF extends PluginCommand {
|
|
|
63
63
|
|
|
64
64
|
try {
|
|
65
65
|
const standardWW = this.$.frameContext.get('documentTypePageMirror') || this.$.frameContext.get('wysiwygFrame');
|
|
66
|
-
|
|
66
|
+
|
|
67
|
+
// Strip theme class so getComputedStyle resolves default (light) colors for borders, shadows, etc.
|
|
68
|
+
const themeClass = (this.$.options.get('_themeClass') || '').trim();
|
|
69
|
+
const wwClassName = themeClass ? standardWW.className.replace(themeClass, '').trim() : standardWW.className;
|
|
70
|
+
const editableDiv = dom.utils.createElement('div', { class: wwClassName }, standardWW.innerHTML);
|
|
67
71
|
ww = dom.utils.createElement('div', { style: `position: absolute; top: -10000px; left: -10000px; width: 21cm; columns: 21cm; height: auto;` }, editableDiv);
|
|
68
72
|
|
|
69
73
|
const innerPadding = _w.getComputedStyle(standardWW).padding;
|
|
70
74
|
const inlineWW = dom.utils.applyInlineStylesAll(editableDiv, true, this.$.options.get('allUsedStyles'));
|
|
71
75
|
inlineWW.style.padding = inlineWW.style.paddingTop = inlineWW.style.paddingBottom = inlineWW.style.paddingLeft = inlineWW.style.paddingRight = '0';
|
|
76
|
+
|
|
72
77
|
ww.innerHTML = `
|
|
73
78
|
<style>
|
|
74
79
|
@page {
|
|
@@ -109,8 +114,15 @@ class ExportPDF extends PluginCommand {
|
|
|
109
114
|
const xhr = await this.apiManager.asyncCall({ data: JSON.stringify(data) });
|
|
110
115
|
|
|
111
116
|
if (xhr.status !== 200) {
|
|
112
|
-
|
|
113
|
-
|
|
117
|
+
let errorMessage;
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
errorMessage = JSON.parse(xhr.responseText).errorMessage;
|
|
121
|
+
} catch {
|
|
122
|
+
// ignore
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
throw Error(`[SUNEDITOR.plugins.exportPDF.error] ${errorMessage || xhr.statusText}`);
|
|
114
126
|
}
|
|
115
127
|
|
|
116
128
|
const blob = new Blob([xhr.response], { type: 'application/pdf' });
|
|
@@ -12,7 +12,10 @@ const { NO_EVENT } = env;
|
|
|
12
12
|
* @property {number} [uploadSizeLimit] - Total upload size limit in bytes
|
|
13
13
|
* @property {number} [uploadSingleSizeLimit] - Single file size limit in bytes
|
|
14
14
|
* @property {boolean} [allowMultiple=false] - Allow multiple file uploads
|
|
15
|
-
* @property {string} [acceptedFormats="*"] - Accepted file formats
|
|
15
|
+
* @property {string} [acceptedFormats="*"] - Accepted file formats.
|
|
16
|
+
* ```js
|
|
17
|
+
* { acceptedFormats: 'image/*, .pdf, .docx' }
|
|
18
|
+
* ```
|
|
16
19
|
* @property {string} [as="box"] - Specify the default form of the file component as `box` or `link`
|
|
17
20
|
* @property {Array<string>} [controls] - Additional controls to be added to the figure
|
|
18
21
|
* @property {SunEditor.ComponentInsertType} [insertBehavior] - Component insertion behavior for selection and cursor placement.
|
|
@@ -4,9 +4,13 @@ import { dom } from '../../helper';
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @typedef {Object} BackgroundColorPluginOptions
|
|
7
|
-
* @property {Array<string|{value: string, name: string}>} [items] - Color list
|
|
7
|
+
* @property {Array<string|{value: string, name: string}>} [items] - Color list.
|
|
8
|
+
* Use HEX strings or objects with `value`/`name` for labeled colors.
|
|
8
9
|
* @property {number} [splitNum] - Number of colors per line
|
|
9
10
|
* @property {boolean} [disableHEXInput] - Disable HEX input
|
|
11
|
+
* ```js
|
|
12
|
+
* { items: ['#ff0000', '#00ff00', { value: '#0000ff', name: 'Blue' }], splitNum: 6 }
|
|
13
|
+
* ```
|
|
10
14
|
*/
|
|
11
15
|
|
|
12
16
|
/**
|
|
@@ -7,7 +7,13 @@ import { dom } from '../../helper';
|
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @typedef {Object} BlockStylePluginOptions
|
|
10
|
-
* @property {Array<"p"|"div"|"blockquote"|"pre"|"h1"|"h2"|"h3"|"h4"|"h5"|"h6"|string|BlockStyleItem>} [items] - Format list
|
|
10
|
+
* @property {Array<"p"|"div"|"blockquote"|"pre"|"h1"|"h2"|"h3"|"h4"|"h5"|"h6"|string|BlockStyleItem>} [items] - Format list.
|
|
11
|
+
* Use string shortcuts for built-in tags, or `BlockStyleItem` objects for custom block styles.
|
|
12
|
+
* - `command` — `"line"`: single line block, `"br-line"`: br-separated block, `"block"`: container block.
|
|
13
|
+
* ```js
|
|
14
|
+
* // string shortcuts + custom item
|
|
15
|
+
* ['p', 'h1', 'h2', 'blockquote', { tag: 'div', command: 'block', name: 'Custom Block', class: 'my-block' }]
|
|
16
|
+
* ```
|
|
11
17
|
*/
|
|
12
18
|
|
|
13
19
|
/**
|
|
@@ -133,7 +139,7 @@ class BlockStyle extends PluginDropdown {
|
|
|
133
139
|
* @returns {HTMLElement}
|
|
134
140
|
*/
|
|
135
141
|
function CreateHTML({ lang }, items) {
|
|
136
|
-
const defaultFormats = ['p', 'blockquote', '
|
|
142
|
+
const defaultFormats = ['p', 'blockquote', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
|
|
137
143
|
const formatList = !items || items.length === 0 ? defaultFormats : items;
|
|
138
144
|
|
|
139
145
|
let list = /*html*/ `
|