@shelamkoff/rector 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -23
- package/dist/core/clipboard/Clipboard.d.ts +2 -0
- package/dist/core/clipboard/Clipboard.js +52 -24
- package/dist/core/index.js +195 -194
- package/dist/core/locale/en.d.ts +1 -0
- package/dist/core/locale/en.js +1 -0
- package/dist/core/locale/ru.d.ts +1 -0
- package/dist/core/locale/ru.js +1 -0
- package/dist/core/themes/light.css +1 -1
- package/dist/core/themes/variables.css +72 -10
- package/dist/inline-plugins/mention/index.js +1 -2
- package/dist/locale/en.d.ts +41 -0
- package/dist/locale/ru.d.ts +41 -0
- package/dist/plugins/attaches/attaches.css +16 -14
- package/dist/plugins/attaches/index.js +997 -921
- package/dist/plugins/attaches/locale/en.d.ts +9 -0
- package/dist/plugins/attaches/locale/en.js +11 -2
- package/dist/plugins/attaches/locale/ru.d.ts +9 -0
- package/dist/plugins/attaches/locale/ru.js +11 -2
- package/dist/plugins/carousel/carousel.css +213 -49
- package/dist/plugins/carousel/index.js +918 -859
- package/dist/plugins/carousel/locale/en.d.ts +15 -0
- package/dist/plugins/carousel/locale/en.js +18 -3
- package/dist/plugins/carousel/locale/ru.d.ts +15 -0
- package/dist/plugins/carousel/locale/ru.js +18 -3
- package/dist/plugins/checklist/index.js +1 -2
- package/dist/plugins/code/index.js +1 -2
- package/dist/plugins/columns/index.js +1 -2
- package/dist/plugins/delimiter/index.js +1 -2
- package/dist/plugins/embed/index.js +1 -2
- package/dist/plugins/gallery/gallery.css +6 -1
- package/dist/plugins/gallery/index.js +375 -355
- package/dist/plugins/gallery/locale/en.d.ts +8 -0
- package/dist/plugins/gallery/locale/en.js +11 -3
- package/dist/plugins/gallery/locale/ru.d.ts +8 -0
- package/dist/plugins/gallery/locale/ru.js +11 -3
- package/dist/plugins/gallery/view-empty.d.ts +2 -0
- package/dist/plugins/gallery/view-empty.js +21 -15
- package/dist/plugins/gallery/view-filled.d.ts +2 -2
- package/dist/plugins/gallery/view-filled.js +61 -56
- package/dist/plugins/heading/index.js +1 -2
- package/dist/plugins/image/image.css +7 -2
- package/dist/plugins/image/index.js +365 -346
- package/dist/plugins/image/locale/en.d.ts +8 -0
- package/dist/plugins/image/locale/en.js +11 -3
- package/dist/plugins/image/locale/ru.d.ts +8 -0
- package/dist/plugins/image/locale/ru.js +11 -3
- package/dist/plugins/image/view-empty.d.ts +2 -0
- package/dist/plugins/image/view-empty.js +21 -15
- package/dist/plugins/image/view-filled.d.ts +2 -2
- package/dist/plugins/image/view-filled.js +77 -72
- package/dist/plugins/link-preview/index.js +1 -2
- package/dist/plugins/list/index.js +1 -2
- package/dist/plugins/paragraph/index.js +1 -2
- package/dist/plugins/person/index.js +1 -2
- package/dist/plugins/poll/index.js +1 -2
- package/dist/plugins/quote/index.js +1 -2
- package/dist/plugins/raw/index.js +1 -2
- package/dist/plugins/shared/dropzone.d.ts +6 -0
- package/dist/plugins/shared/dropzone.js +47 -36
- package/dist/plugins/shared/layer.d.ts +13 -0
- package/dist/plugins/shared/layer.js +45 -0
- package/dist/plugins/shared/sourceEditor.css +165 -0
- package/dist/plugins/shared/sourceEditor.d.ts +97 -0
- package/dist/plugins/shared/sourceEditor.js +260 -0
- package/dist/plugins/spoiler/index.js +1 -2
- package/dist/plugins/table/index.js +1 -2
- package/dist/plugins/toggle/index.js +1 -2
- package/dist/plugins/warning/index.js +1 -2
- package/dist/renderer/index.js +1 -2
- package/dist/renderer/renderers/attaches/index.js +1 -2
- package/dist/renderer/renderers/carousel/index.js +24 -24
- package/dist/renderer/renderers/carousel/styles.css +8 -2
- package/dist/renderer/renderers/checklist/index.js +1 -2
- package/dist/renderer/renderers/code/index.js +1 -2
- package/dist/renderer/renderers/columns/index.js +1 -2
- package/dist/renderer/renderers/delimiter/index.js +1 -2
- package/dist/renderer/renderers/embed/index.js +1 -2
- package/dist/renderer/renderers/gallery/index.js +1 -2
- package/dist/renderer/renderers/heading/index.js +1 -2
- package/dist/renderer/renderers/image/index.js +1 -2
- package/dist/renderer/renderers/link-preview/index.js +1 -2
- package/dist/renderer/renderers/list/index.js +1 -2
- package/dist/renderer/renderers/paragraph/index.js +1 -2
- package/dist/renderer/renderers/person/index.js +1 -2
- package/dist/renderer/renderers/poll/index.js +1 -2
- package/dist/renderer/renderers/quote/index.js +1 -2
- package/dist/renderer/renderers/spoiler/index.js +1 -2
- package/dist/renderer/renderers/table/index.js +1 -2
- package/dist/renderer/renderers/toggle/index.js +1 -2
- package/dist/renderer/renderers/warning/index.js +1 -2
- package/package.json +27 -29
- package/dist/shared/resolvePath.d.ts +0 -8
- package/dist/shared/resolvePath.js +0 -10
|
@@ -6,6 +6,14 @@ declare const _default: {
|
|
|
6
6
|
'plugin.gallery.dropzone': string;
|
|
7
7
|
'plugin.gallery.dropzoneUpload': string;
|
|
8
8
|
'plugin.gallery.dropzoneText': string;
|
|
9
|
+
'plugin.gallery.dropzoneUrlPrefix': string;
|
|
10
|
+
'plugin.gallery.dropzoneUrl': string;
|
|
11
|
+
'plugin.gallery.urlEditorTitle': string;
|
|
12
|
+
'plugin.gallery.urlEditorLabel': string;
|
|
13
|
+
'plugin.gallery.urlEditorPlaceholder': string;
|
|
14
|
+
'plugin.gallery.sourceSubmit': string;
|
|
15
|
+
'plugin.gallery.sourceCancel': string;
|
|
16
|
+
'plugin.gallery.invalidUrl': string;
|
|
9
17
|
'plugin.gallery.addMore': string;
|
|
10
18
|
'plugin.gallery.delete': string;
|
|
11
19
|
'plugin.gallery.deleteAll': string;
|
|
@@ -6,6 +6,14 @@ export default {
|
|
|
6
6
|
'plugin.gallery.dropzone': 'or drag and drop files here',
|
|
7
7
|
'plugin.gallery.dropzoneUpload': 'Upload',
|
|
8
8
|
'plugin.gallery.dropzoneText': 'images from your device or drag and drop them here',
|
|
9
|
+
'plugin.gallery.dropzoneUrlPrefix': 'or',
|
|
10
|
+
'plugin.gallery.dropzoneUrl': 'insert by URL',
|
|
11
|
+
'plugin.gallery.urlEditorTitle': 'Insert image by URL',
|
|
12
|
+
'plugin.gallery.urlEditorLabel': 'Image URL',
|
|
13
|
+
'plugin.gallery.urlEditorPlaceholder': 'https://example.com/image.jpg',
|
|
14
|
+
'plugin.gallery.sourceSubmit': 'Insert',
|
|
15
|
+
'plugin.gallery.sourceCancel': 'Cancel',
|
|
16
|
+
'plugin.gallery.invalidUrl': 'Enter a valid image URL.',
|
|
9
17
|
'plugin.gallery.addMore': 'Add more',
|
|
10
18
|
'plugin.gallery.delete': 'Delete',
|
|
11
19
|
'plugin.gallery.deleteAll': 'Delete all',
|
|
@@ -30,6 +38,6 @@ export default {
|
|
|
30
38
|
'plugin.gallery.layoutAuto': 'Automatic layout',
|
|
31
39
|
'plugin.gallery.layoutMasonry': 'Masonry layout',
|
|
32
40
|
'plugin.gallery.layoutTriptych': 'Triptych layout',
|
|
33
|
-
'plugin.gallery.layoutTemplate': 'Layout template',
|
|
34
|
-
'plugin.gallery.emptyReadonly': 'No images',
|
|
35
|
-
}
|
|
41
|
+
'plugin.gallery.layoutTemplate': 'Layout template',
|
|
42
|
+
'plugin.gallery.emptyReadonly': 'No images',
|
|
43
|
+
}
|
|
@@ -6,6 +6,14 @@ declare const _default: {
|
|
|
6
6
|
'plugin.gallery.dropzone': string;
|
|
7
7
|
'plugin.gallery.dropzoneUpload': string;
|
|
8
8
|
'plugin.gallery.dropzoneText': string;
|
|
9
|
+
'plugin.gallery.dropzoneUrlPrefix': string;
|
|
10
|
+
'plugin.gallery.dropzoneUrl': string;
|
|
11
|
+
'plugin.gallery.urlEditorTitle': string;
|
|
12
|
+
'plugin.gallery.urlEditorLabel': string;
|
|
13
|
+
'plugin.gallery.urlEditorPlaceholder': string;
|
|
14
|
+
'plugin.gallery.sourceSubmit': string;
|
|
15
|
+
'plugin.gallery.sourceCancel': string;
|
|
16
|
+
'plugin.gallery.invalidUrl': string;
|
|
9
17
|
'plugin.gallery.addMore': string;
|
|
10
18
|
'plugin.gallery.delete': string;
|
|
11
19
|
'plugin.gallery.deleteAll': string;
|
|
@@ -6,6 +6,14 @@ export default {
|
|
|
6
6
|
'plugin.gallery.dropzone': 'или перетащите файлы сюда',
|
|
7
7
|
'plugin.gallery.dropzoneUpload': 'Загрузите',
|
|
8
8
|
'plugin.gallery.dropzoneText': 'изображения с устройства или перетащите их сюда',
|
|
9
|
+
'plugin.gallery.dropzoneUrlPrefix': 'или',
|
|
10
|
+
'plugin.gallery.dropzoneUrl': 'вставьте по URL',
|
|
11
|
+
'plugin.gallery.urlEditorTitle': 'Вставка изображения по URL',
|
|
12
|
+
'plugin.gallery.urlEditorLabel': 'URL изображения',
|
|
13
|
+
'plugin.gallery.urlEditorPlaceholder': 'https://example.com/image.jpg',
|
|
14
|
+
'plugin.gallery.sourceSubmit': 'Вставить',
|
|
15
|
+
'plugin.gallery.sourceCancel': 'Отмена',
|
|
16
|
+
'plugin.gallery.invalidUrl': 'Введите корректный URL изображения.',
|
|
9
17
|
'plugin.gallery.addMore': 'Добавить ещё',
|
|
10
18
|
'plugin.gallery.delete': 'Удалить',
|
|
11
19
|
'plugin.gallery.deleteAll': 'Удалить всё',
|
|
@@ -30,6 +38,6 @@ export default {
|
|
|
30
38
|
'plugin.gallery.layoutAuto': 'Автоматический макет',
|
|
31
39
|
'plugin.gallery.layoutMasonry': 'Кладочный макет',
|
|
32
40
|
'plugin.gallery.layoutTriptych': 'Триптих',
|
|
33
|
-
'plugin.gallery.layoutTemplate': 'Шаблон макета',
|
|
34
|
-
'plugin.gallery.emptyReadonly': 'Нет изображений',
|
|
35
|
-
}
|
|
41
|
+
'plugin.gallery.layoutTemplate': 'Шаблон макета',
|
|
42
|
+
'plugin.gallery.emptyReadonly': 'Нет изображений',
|
|
43
|
+
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* @property {(key: string, fallback: string) => string} t
|
|
4
4
|
* @property {boolean} readOnly
|
|
5
5
|
* @property {() => void} onUploadClick
|
|
6
|
+
* @property {() => void} onOpenUrlEditor
|
|
6
7
|
* @property {Array<{ icon?: string, label: string, handler: (context: { signal: AbortSignal }) => Promise<Array<{url: string, alt?: string}> | null> }>} customActions
|
|
7
8
|
* @property {(handler: (context: { signal: AbortSignal }) => Promise<Array<{url: string, alt?: string}> | null>) => Promise<void>} runCustomAction
|
|
8
9
|
* @property {(files: File[]) => void} onFilesDropped
|
|
@@ -21,6 +22,7 @@ export type EmptyViewDeps = {
|
|
|
21
22
|
t: (key: string, fallback: string) => string;
|
|
22
23
|
readOnly: boolean;
|
|
23
24
|
onUploadClick: () => void;
|
|
25
|
+
onOpenUrlEditor: () => void;
|
|
24
26
|
customActions: Array<{
|
|
25
27
|
icon?: string;
|
|
26
28
|
label: string;
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { renderDropzone } from '../shared/dropzone.js'
|
|
2
|
-
import { isSupportedImageFile } from '../shared/fileInput.js'
|
|
1
|
+
import { renderDropzone } from '../shared/dropzone.js'
|
|
2
|
+
import { isSupportedImageFile } from '../shared/fileInput.js'
|
|
3
3
|
import { CSS } from './css.js'
|
|
4
4
|
import { ICON_SELECT } from './icons.js'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* @typedef {Object} EmptyViewDeps
|
|
8
|
-
* @property {(key: string, fallback: string) => string} t
|
|
9
|
-
* @property {boolean} readOnly
|
|
7
|
+
* @typedef {Object} EmptyViewDeps
|
|
8
|
+
* @property {(key: string, fallback: string) => string} t
|
|
9
|
+
* @property {boolean} readOnly
|
|
10
10
|
* @property {() => void} onUploadClick
|
|
11
|
+
* @property {() => void} onOpenUrlEditor
|
|
11
12
|
* @property {Array<{ icon?: string, label: string, handler: (context: { signal: AbortSignal }) => Promise<Array<{url: string, alt?: string}> | null> }>} customActions
|
|
12
13
|
* @property {(handler: (context: { signal: AbortSignal }) => Promise<Array<{url: string, alt?: string}> | null>) => Promise<void>} runCustomAction
|
|
13
14
|
* @property {(files: File[]) => void} onFilesDropped
|
|
@@ -17,11 +18,11 @@ import { ICON_SELECT } from './icons.js'
|
|
|
17
18
|
* Render the empty-state dropzone for the Gallery plugin.
|
|
18
19
|
* Replaces wrapper contents and removes the `filled` class.
|
|
19
20
|
*
|
|
20
|
-
* @param {HTMLElement} wrapper
|
|
21
|
-
* @param {import('./state.js').GalleryState} state
|
|
22
|
-
* @param {EmptyViewDeps} deps
|
|
23
|
-
* @returns {void}
|
|
24
|
-
*/
|
|
21
|
+
* @param {HTMLElement} wrapper
|
|
22
|
+
* @param {import('./state.js').GalleryState} state
|
|
23
|
+
* @param {EmptyViewDeps} deps
|
|
24
|
+
* @returns {void}
|
|
25
|
+
*/
|
|
25
26
|
export function renderEmptyView(wrapper, state, deps) {
|
|
26
27
|
state.resetTransient()
|
|
27
28
|
|
|
@@ -38,18 +39,23 @@ export function renderEmptyView(wrapper, state, deps) {
|
|
|
38
39
|
filled: CSS.filled,
|
|
39
40
|
}, {
|
|
40
41
|
iconHtml: ICON_SELECT,
|
|
41
|
-
uploadText: deps.t('dropzoneUpload', 'Upload'),
|
|
42
|
-
afterText: deps.t('dropzoneText', 'images from your device or drag and drop them here'),
|
|
43
|
-
readOnly: deps.readOnly,
|
|
44
|
-
emptyText: deps.t('emptyReadonly', 'No images'),
|
|
42
|
+
uploadText: deps.t('dropzoneUpload', 'Upload'),
|
|
43
|
+
afterText: deps.t('dropzoneText', 'images from your device or drag and drop them here'),
|
|
44
|
+
readOnly: deps.readOnly,
|
|
45
|
+
emptyText: deps.t('emptyReadonly', 'No images'),
|
|
45
46
|
onUploadClick: deps.onUploadClick,
|
|
47
|
+
inlineActions: [{
|
|
48
|
+
prefix: deps.t('dropzoneUrlPrefix', 'or'),
|
|
49
|
+
label: deps.t('dropzoneUrl', 'insert by URL'),
|
|
50
|
+
onSelect: deps.onOpenUrlEditor,
|
|
51
|
+
}],
|
|
46
52
|
actions: deps.customActions.map(action => ({
|
|
47
53
|
icon: action.icon,
|
|
48
54
|
label: action.label,
|
|
49
55
|
onSelect: () => { void deps.runCustomAction(action.handler) },
|
|
50
56
|
})),
|
|
51
57
|
onDrop: (dt) => {
|
|
52
|
-
const files = [...(dt.files || [])].filter(isSupportedImageFile)
|
|
58
|
+
const files = [...(dt.files || [])].filter(isSupportedImageFile)
|
|
53
59
|
if (files.length > 0) deps.onFilesDropped(files)
|
|
54
60
|
},
|
|
55
61
|
})
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* @property {(operation: () => void) => void} mutate
|
|
10
10
|
* @property {(files: File[]) => void} onFilesDropped
|
|
11
11
|
* @property {() => void} onTriggerFileInput
|
|
12
|
-
* @property {() => void}
|
|
12
|
+
* @property {() => void} onOpenUrlEditor
|
|
13
13
|
* @property {() => void} onDeleteAll
|
|
14
14
|
* @property {Array<{ icon?: string, label: string, handler: (context: { signal: AbortSignal }) => Promise<Array<{url: string, alt?: string}> | null> }>} customActions
|
|
15
15
|
* @property {(handler: (context: { signal: AbortSignal }) => Promise<Array<{url: string, alt?: string}> | null>) => Promise<void>} runCustomAction
|
|
@@ -34,7 +34,7 @@ export type FilledViewDeps = {
|
|
|
34
34
|
mutate: (operation: () => void) => void;
|
|
35
35
|
onFilesDropped: (files: File[]) => void;
|
|
36
36
|
onTriggerFileInput: () => void;
|
|
37
|
-
|
|
37
|
+
onOpenUrlEditor: () => void;
|
|
38
38
|
onDeleteAll: () => void;
|
|
39
39
|
customActions: Array<{
|
|
40
40
|
icon?: string;
|
|
@@ -13,11 +13,12 @@ import { buildSettingsPanel } from './settings.js'
|
|
|
13
13
|
import {
|
|
14
14
|
attachExternalDrop, createEmptySlot, createFilledSlot, createOverflowItem,
|
|
15
15
|
} from './slot.js'
|
|
16
|
+
import { createPluginLayer } from '../shared/layer.js'
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
|
-
* @typedef {Object} FilledViewDeps
|
|
19
|
-
* @property {(key: string, fallback: string) => string} t
|
|
20
|
-
* @property {boolean} readOnly
|
|
19
|
+
* @typedef {Object} FilledViewDeps
|
|
20
|
+
* @property {(key: string, fallback: string) => string} t
|
|
21
|
+
* @property {boolean} readOnly
|
|
21
22
|
* @property {() => void} syncCaptions
|
|
22
23
|
* @property {() => import('./state.js').GalleryState | undefined} getState
|
|
23
24
|
* @property {() => void} reRender
|
|
@@ -25,7 +26,7 @@ import {
|
|
|
25
26
|
* @property {(operation: () => void) => void} mutate
|
|
26
27
|
* @property {(files: File[]) => void} onFilesDropped
|
|
27
28
|
* @property {() => void} onTriggerFileInput
|
|
28
|
-
* @property {() => void}
|
|
29
|
+
* @property {() => void} onOpenUrlEditor
|
|
29
30
|
* @property {() => void} onDeleteAll
|
|
30
31
|
* @property {Array<{ icon?: string, label: string, handler: (context: { signal: AbortSignal }) => Promise<Array<{url: string, alt?: string}> | null> }>} customActions
|
|
31
32
|
* @property {(handler: (context: { signal: AbortSignal }) => Promise<Array<{url: string, alt?: string}> | null>) => Promise<void>} runCustomAction
|
|
@@ -35,11 +36,11 @@ import {
|
|
|
35
36
|
* Render the filled-state Gallery view: template grid (or masonry) +
|
|
36
37
|
* optional overflow row + action bar.
|
|
37
38
|
*
|
|
38
|
-
* @param {HTMLElement} wrapper
|
|
39
|
-
* @param {import('./state.js').GalleryState} state
|
|
40
|
-
* @param {FilledViewDeps} deps
|
|
41
|
-
* @returns {void}
|
|
42
|
-
*/
|
|
39
|
+
* @param {HTMLElement} wrapper
|
|
40
|
+
* @param {import('./state.js').GalleryState} state
|
|
41
|
+
* @param {FilledViewDeps} deps
|
|
42
|
+
* @returns {void}
|
|
43
|
+
*/
|
|
43
44
|
export function renderFilledView(wrapper, state, deps) {
|
|
44
45
|
state.resetTransient()
|
|
45
46
|
wrapper.innerHTML = ''
|
|
@@ -54,7 +55,7 @@ export function renderFilledView(wrapper, state, deps) {
|
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
applyGalleryStyles(wrapper, state)
|
|
57
|
-
if (!deps.readOnly) wrapper.appendChild(renderActions(wrapper, state, deps, signal))
|
|
58
|
+
if (!deps.readOnly) wrapper.appendChild(renderActions(wrapper, state, deps, signal))
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
/**
|
|
@@ -77,7 +78,7 @@ function renderMasonry(wrapper, state, deps, signal) {
|
|
|
77
78
|
grid.appendChild(slot)
|
|
78
79
|
})
|
|
79
80
|
|
|
80
|
-
if (!deps.readOnly) attachExternalDrop(grid, signal, deps.onFilesDropped)
|
|
81
|
+
if (!deps.readOnly) attachExternalDrop(grid, signal, deps.onFilesDropped)
|
|
81
82
|
wrapper.appendChild(grid)
|
|
82
83
|
}
|
|
83
84
|
|
|
@@ -125,20 +126,20 @@ function renderSlotBased(wrapper, state, deps, signal) {
|
|
|
125
126
|
const slot = createFilledSlot(img, idx, signal, slotDeps)
|
|
126
127
|
slot.dataset.slot = String(idx)
|
|
127
128
|
|
|
128
|
-
const imgEl = /** @type {HTMLImageElement | null} */ (slot.querySelector(`.${CSS.slotImg}`))
|
|
129
|
-
if (imgEl) {
|
|
130
|
-
let ready = false
|
|
131
|
-
const onReady = () => {
|
|
132
|
-
if (ready) return
|
|
133
|
-
ready = true
|
|
134
|
-
orientations[idx] = classifyOrientation(imgEl.naturalWidth, imgEl.naturalHeight)
|
|
135
|
-
loadedCount++
|
|
136
|
-
if (loadedCount >= slotCount) onAllLoaded()
|
|
137
|
-
}
|
|
138
|
-
imgEl.addEventListener('load', onReady, { once: true, signal })
|
|
139
|
-
imgEl.addEventListener('error', onReady, { once: true, signal })
|
|
140
|
-
if (imgEl.complete) queueMicrotask(onReady)
|
|
141
|
-
}
|
|
129
|
+
const imgEl = /** @type {HTMLImageElement | null} */ (slot.querySelector(`.${CSS.slotImg}`))
|
|
130
|
+
if (imgEl) {
|
|
131
|
+
let ready = false
|
|
132
|
+
const onReady = () => {
|
|
133
|
+
if (ready) return
|
|
134
|
+
ready = true
|
|
135
|
+
orientations[idx] = classifyOrientation(imgEl.naturalWidth, imgEl.naturalHeight)
|
|
136
|
+
loadedCount++
|
|
137
|
+
if (loadedCount >= slotCount) onAllLoaded()
|
|
138
|
+
}
|
|
139
|
+
imgEl.addEventListener('load', onReady, { once: true, signal })
|
|
140
|
+
imgEl.addEventListener('error', onReady, { once: true, signal })
|
|
141
|
+
if (imgEl.complete) queueMicrotask(onReady)
|
|
142
|
+
}
|
|
142
143
|
grid.appendChild(slot)
|
|
143
144
|
}
|
|
144
145
|
} else {
|
|
@@ -155,7 +156,7 @@ function renderSlotBased(wrapper, state, deps, signal) {
|
|
|
155
156
|
}
|
|
156
157
|
}
|
|
157
158
|
|
|
158
|
-
if (!deps.readOnly) attachExternalDrop(grid, signal, deps.onFilesDropped)
|
|
159
|
+
if (!deps.readOnly) attachExternalDrop(grid, signal, deps.onFilesDropped)
|
|
159
160
|
wrapper.appendChild(grid)
|
|
160
161
|
|
|
161
162
|
if (overflowImages.length > 0) {
|
|
@@ -167,7 +168,7 @@ function renderSlotBased(wrapper, state, deps, signal) {
|
|
|
167
168
|
overflow.appendChild(createOverflowItem(img, globalIdx, signal, slotDeps))
|
|
168
169
|
})
|
|
169
170
|
|
|
170
|
-
if (!deps.readOnly) attachExternalDrop(overflow, signal, deps.onFilesDropped)
|
|
171
|
+
if (!deps.readOnly) attachExternalDrop(overflow, signal, deps.onFilesDropped)
|
|
171
172
|
wrapper.appendChild(overflow)
|
|
172
173
|
}
|
|
173
174
|
}
|
|
@@ -180,9 +181,9 @@ function renderSlotBased(wrapper, state, deps, signal) {
|
|
|
180
181
|
* @returns {import('./slot.js').SlotDeps}
|
|
181
182
|
*/
|
|
182
183
|
function makeSlotDeps(deps) {
|
|
183
|
-
return {
|
|
184
|
-
t: deps.t,
|
|
185
|
-
readOnly: deps.readOnly,
|
|
184
|
+
return {
|
|
185
|
+
t: deps.t,
|
|
186
|
+
readOnly: deps.readOnly,
|
|
186
187
|
syncCaptions: deps.syncCaptions,
|
|
187
188
|
getState: deps.getState,
|
|
188
189
|
onRemoveImage: (index) => {
|
|
@@ -229,37 +230,41 @@ function renderActions(wrapper, state, deps, signal) {
|
|
|
229
230
|
dropdown.className = CSS.dropdown
|
|
230
231
|
|
|
231
232
|
const settingsBtn = document.createElement('button')
|
|
232
|
-
settingsBtn.type = 'button'
|
|
233
|
-
settingsBtn.className = CSS.actionBtn
|
|
234
|
-
settingsBtn.innerHTML = `${ICON_SETTINGS} ${deps.t('settings', 'Settings')}`
|
|
235
|
-
settingsBtn.setAttribute('aria-haspopup', 'true')
|
|
236
|
-
settingsBtn.setAttribute('aria-expanded', 'false')
|
|
237
|
-
|
|
238
|
-
const panel = buildSettingsPanel(wrapper, state, settingsDeps)
|
|
239
|
-
panel.setAttribute('role', 'group')
|
|
240
|
-
panel.setAttribute('aria-label', deps.t('settings', 'Settings'))
|
|
233
|
+
settingsBtn.type = 'button'
|
|
234
|
+
settingsBtn.className = CSS.actionBtn
|
|
235
|
+
settingsBtn.innerHTML = `${ICON_SETTINGS} ${deps.t('settings', 'Settings')}`
|
|
236
|
+
settingsBtn.setAttribute('aria-haspopup', 'true')
|
|
237
|
+
settingsBtn.setAttribute('aria-expanded', 'false')
|
|
238
|
+
|
|
239
|
+
const panel = buildSettingsPanel(wrapper, state, settingsDeps)
|
|
240
|
+
panel.setAttribute('role', 'group')
|
|
241
|
+
panel.setAttribute('aria-label', deps.t('settings', 'Settings'))
|
|
242
|
+
const settingsLayer = createPluginLayer(wrapper, signal)
|
|
243
|
+
const setSettingsOpen = (open) => {
|
|
244
|
+
dropdown.classList.toggle(CSS.dropdownOpen, open)
|
|
245
|
+
settingsBtn.setAttribute('aria-expanded', String(open))
|
|
246
|
+
if (open) settingsLayer.open()
|
|
247
|
+
else settingsLayer.close()
|
|
248
|
+
}
|
|
241
249
|
|
|
242
250
|
settingsBtn.addEventListener('click', (e) => {
|
|
243
251
|
e.stopPropagation()
|
|
244
|
-
|
|
245
|
-
settingsBtn.setAttribute('aria-expanded', String(open))
|
|
252
|
+
setSettingsOpen(!dropdown.classList.contains(CSS.dropdownOpen))
|
|
246
253
|
}, { signal })
|
|
247
254
|
|
|
248
255
|
dropdown.append(settingsBtn, panel)
|
|
249
256
|
|
|
250
257
|
document.addEventListener('click', (e) => {
|
|
251
258
|
if (!dropdown.contains(/** @type {Node} */ (e.target))) {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
settingsBtn.focus()
|
|
262
|
-
}, { signal })
|
|
259
|
+
setSettingsOpen(false)
|
|
260
|
+
}
|
|
261
|
+
}, { signal })
|
|
262
|
+
dropdown.addEventListener('keydown', (event) => {
|
|
263
|
+
if (event.key !== 'Escape' || !dropdown.classList.contains(CSS.dropdownOpen)) return
|
|
264
|
+
event.preventDefault()
|
|
265
|
+
setSettingsOpen(false)
|
|
266
|
+
settingsBtn.focus()
|
|
267
|
+
}, { signal })
|
|
263
268
|
|
|
264
269
|
// Main view container (for drill-down hide/show)
|
|
265
270
|
const mainView = document.createElement('div')
|
|
@@ -283,9 +288,9 @@ function renderActions(wrapper, state, deps, signal) {
|
|
|
283
288
|
// Delete all
|
|
284
289
|
const deleteAllBtn = document.createElement('button')
|
|
285
290
|
deleteAllBtn.type = 'button'
|
|
286
|
-
deleteAllBtn.className = `${CSS.actionBtn} ${CSS.actionBtnDanger}`
|
|
287
|
-
deleteAllBtn.innerHTML = ICON_TRASH
|
|
288
|
-
deleteAllBtn.setAttribute('aria-label', deps.t('deleteAll', 'Delete all'))
|
|
291
|
+
deleteAllBtn.className = `${CSS.actionBtn} ${CSS.actionBtnDanger}`
|
|
292
|
+
deleteAllBtn.innerHTML = ICON_TRASH
|
|
293
|
+
deleteAllBtn.setAttribute('aria-label', deps.t('deleteAll', 'Delete all'))
|
|
289
294
|
deleteAllBtn.addEventListener('mousedown', (e) => e.preventDefault(), { signal })
|
|
290
295
|
deleteAllBtn.addEventListener('click', (e) => {
|
|
291
296
|
e.stopPropagation()
|
|
@@ -335,7 +340,7 @@ function showAddView(actions, mainView, deps, signal) {
|
|
|
335
340
|
|
|
336
341
|
view.appendChild(makeActionBtn(
|
|
337
342
|
`${ICON_URL} URL`,
|
|
338
|
-
() => { deps.
|
|
343
|
+
() => { deps.onOpenUrlEditor(); restore() },
|
|
339
344
|
signal,
|
|
340
345
|
))
|
|
341
346
|
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { sanitizeHtml } from '../../core/sanitize.js'
|
|
2
|
-
import { resolvePath } from '../../shared/resolvePath.js'
|
|
3
2
|
import { BlockPluginAbstract } from '../BlockPluginAbstract.js'
|
|
4
3
|
import { createHeadingLevelSelect } from './HeadingLevelSelect.js'
|
|
5
4
|
import { mapTextFields } from './mapTextFields.js'
|
|
6
5
|
import { validateHeadingData } from '../../shared/blockDataValidators.js'
|
|
7
6
|
import { normalizeHeadingLevel, normalizeTextAlign, normalizeTextValue } from '../../shared/textFormat.js'
|
|
8
7
|
|
|
9
|
-
const editorStyles =
|
|
8
|
+
const editorStyles = new URL('./heading.css', import.meta.url).href
|
|
10
9
|
|
|
11
10
|
// Tabler icon: heading
|
|
12
11
|
const ICON = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 12h10"/><path d="M7 5v14"/><path d="M17 5v14"/><path d="M15 19h4"/><path d="M15 5h4"/><path d="M5 19h4"/><path d="M5 5h4"/></svg>'
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
.oe-image {
|
|
2
|
+
position: relative;
|
|
2
3
|
border-radius: 0.5rem;
|
|
3
4
|
overflow-anchor: none;
|
|
4
5
|
text-align: center;
|
|
@@ -239,7 +240,7 @@
|
|
|
239
240
|
border-radius: 8px;
|
|
240
241
|
box-shadow: var(--oe-toolbar-shadow, 0 8px 24px rgba(0, 0, 0, 0.4));
|
|
241
242
|
padding: 12px;
|
|
242
|
-
z-index:
|
|
243
|
+
z-index: var(--oe-plugin-panel-z-index, 1100);
|
|
243
244
|
}
|
|
244
245
|
|
|
245
246
|
.oe-image__dropdown--open .oe-image__dropdown-panel {
|
|
@@ -377,7 +378,7 @@
|
|
|
377
378
|
border: 1px solid var(--oe-border-hover, #2a2a2a);
|
|
378
379
|
border-radius: 6px;
|
|
379
380
|
box-shadow: var(--oe-toolbar-shadow, 0 8px 24px rgba(0, 0, 0, 0.4));
|
|
380
|
-
z-index:
|
|
381
|
+
z-index: var(--oe-plugin-popover-z-index, 1120);
|
|
381
382
|
padding: 3px;
|
|
382
383
|
max-height: 10rem;
|
|
383
384
|
overflow-y: auto;
|
|
@@ -516,6 +517,10 @@
|
|
|
516
517
|
color: var(--oe-text-1, #1a1a1a);
|
|
517
518
|
}
|
|
518
519
|
|
|
520
|
+
.oe-theme-light .oe-image__action-btn:hover {
|
|
521
|
+
color: var(--oe-text-on-accent, #fff);
|
|
522
|
+
}
|
|
523
|
+
|
|
519
524
|
.oe-theme-light .oe-image__dropdown-panel {
|
|
520
525
|
background: var(--oe-card, #fff);
|
|
521
526
|
border-color: var(--oe-border-hover, #d4d4d4);
|