@umbraco-cms/backoffice 14.0.0--preview004-4ed648fc → 14.0.0--preview004-d48a2224
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/dist-cms/custom-elements.json +4 -7
- package/dist-cms/packages/core/components/input-tiny-mce/input-tiny-mce.defaults.d.ts +0 -3
- package/dist-cms/packages/core/components/input-tiny-mce/input-tiny-mce.defaults.js +30 -24
- package/dist-cms/packages/core/components/input-tiny-mce/input-tiny-mce.element.d.ts +0 -1
- package/dist-cms/packages/core/components/input-tiny-mce/input-tiny-mce.element.js +56 -97
- package/dist-cms/packages/core/components/input-tiny-mce/input-tiny-mce.handlers.d.ts +0 -1
- package/dist-cms/packages/core/components/input-tiny-mce/input-tiny-mce.handlers.js +0 -30
- package/dist-cms/packages/core/index.d.ts +1 -0
- package/dist-cms/packages/core/index.js +1 -0
- package/dist-cms/packages/core/meta/index.d.ts +5 -0
- package/dist-cms/packages/core/meta/index.js +6 -0
- package/dist-cms/packages/core/property-editor/uis/tiny-mce/plugins/tiny-mce-mediapicker.plugin.js +57 -4
- package/dist-cms/packages/core/property-editor/uis/tiny-mce/property-editor-ui-tiny-mce.element.d.ts +5 -1
- package/dist-cms/packages/core/property-editor/uis/tiny-mce/property-editor-ui-tiny-mce.element.js +10 -4
- package/dist-cms/shared/utils/media-helper.service.d.ts +6 -19
- package/dist-cms/shared/utils/media-helper.service.js +11 -35
- package/dist-cms/tsconfig.build.tsbuildinfo +1 -1
- package/dist-cms/vscode-html-custom-data.json +4 -7
- package/package.json +2 -1
|
@@ -1823,9 +1823,6 @@
|
|
|
1823
1823
|
},
|
|
1824
1824
|
{
|
|
1825
1825
|
"name": "umb-rte-blur"
|
|
1826
|
-
},
|
|
1827
|
-
{
|
|
1828
|
-
"name": "change"
|
|
1829
1826
|
}
|
|
1830
1827
|
]
|
|
1831
1828
|
},
|
|
@@ -4657,16 +4654,16 @@
|
|
|
4657
4654
|
"attributes": [
|
|
4658
4655
|
{
|
|
4659
4656
|
"name": "value",
|
|
4660
|
-
"type": "
|
|
4661
|
-
"default": "\"\""
|
|
4657
|
+
"type": "RichTextEditorValue | undefined",
|
|
4658
|
+
"default": "{\"blocks\":{},\"markup\":\"\"}"
|
|
4662
4659
|
}
|
|
4663
4660
|
],
|
|
4664
4661
|
"properties": [
|
|
4665
4662
|
{
|
|
4666
4663
|
"name": "value",
|
|
4667
4664
|
"attribute": "value",
|
|
4668
|
-
"type": "
|
|
4669
|
-
"default": "\"\""
|
|
4665
|
+
"type": "RichTextEditorValue | undefined",
|
|
4666
|
+
"default": "{\"blocks\":{},\"markup\":\"\"}"
|
|
4670
4667
|
},
|
|
4671
4668
|
{
|
|
4672
4669
|
"name": "config"
|
|
@@ -1,5 +1,2 @@
|
|
|
1
1
|
import type { RawEditorOptions } from '../../../../external/tinymce/index.js';
|
|
2
|
-
export type TinyStyleSheet = RawEditorOptions['style_formats'];
|
|
3
|
-
export declare const defaultStyleFormats: TinyStyleSheet;
|
|
4
|
-
export declare const defaultExtendedValidElements = "@[id|class|style],-div[id|dir|class|align|style],ins[datetime|cite],-ul[class|style],-li[class|style],-h1[id|dir|class|align|style],-h2[id|dir|class|align|style],-h3[id|dir|class|align|style],-h4[id|dir|class|align|style],-h5[id|dir|class|align|style],-h6[id|style|dir|class|align],span[id|class|style|lang],figure,figcaption";
|
|
5
2
|
export declare const defaultFallbackConfig: RawEditorOptions;
|
|
@@ -1,28 +1,11 @@
|
|
|
1
|
-
export const defaultStyleFormats = [
|
|
2
|
-
{
|
|
3
|
-
title: 'Headers',
|
|
4
|
-
items: [
|
|
5
|
-
{ title: 'Page header', block: 'h2' },
|
|
6
|
-
{ title: 'Section header', block: 'h3' },
|
|
7
|
-
{ title: 'Paragraph header', block: 'h4' },
|
|
8
|
-
],
|
|
9
|
-
},
|
|
10
|
-
{
|
|
11
|
-
title: 'Blocks',
|
|
12
|
-
items: [{ title: 'Normal', block: 'p' }],
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
title: 'Containers',
|
|
16
|
-
items: [
|
|
17
|
-
{ title: 'Quote', block: 'blockquote' },
|
|
18
|
-
{ title: 'Code', block: 'code' },
|
|
19
|
-
],
|
|
20
|
-
},
|
|
21
|
-
];
|
|
22
1
|
//These are absolutely required in order for the macros to render inline
|
|
23
2
|
//we put these as extended elements because they get merged on top of the normal allowed elements by tiny mce
|
|
24
|
-
|
|
3
|
+
//so we don't have to specify all the normal elements again
|
|
25
4
|
export const defaultFallbackConfig = {
|
|
5
|
+
plugins: ['anchor', 'charmap', 'table', 'lists', 'advlist', 'autolink', 'directionality', 'searchreplace'],
|
|
6
|
+
valid_elements: '+a[id|style|rel|data-id|data-udi|rev|charset|hreflang|dir|lang|tabindex|accesskey|type|name|href|target|title|class|onfocus|onblur|onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup],-strong/-b[class|style],-em/-i[class|style],-strike[class|style],-s[class|style],-u[class|style],#p[id|style|dir|class|align],-ol[class|reversed|start|style|type],-ul[class|style],-li[class|style],br[class],img[id|dir|lang|longdesc|usemap|style|class|src|onmouseover|onmouseout|border|alt=|title|hspace|vspace|width|height|align|umbracoorgwidth|umbracoorgheight|onresize|onresizestart|onresizeend|rel|data-id],-sub[style|class],-sup[style|class],-blockquote[dir|style|class],-table[border=0|cellspacing|cellpadding|width|height|class|align|summary|style|dir|id|lang|bgcolor|background|bordercolor],-tr[id|lang|dir|class|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor],tbody[id|class],thead[id|class],tfoot[id|class],#td[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor|scope],-th[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|scope],caption[id|lang|dir|class|style],-div[id|dir|class|align|style],-span[class|align|style],-pre[class|align|style],address[class|align|style],-h1[id|dir|class|align|style],-h2[id|dir|class|align|style],-h3[id|dir|class|align|style],-h4[id|dir|class|align|style],-h5[id|dir|class|align|style],-h6[id|style|dir|class|align|style],hr[class|style],small[class|style],dd[id|class|title|style|dir|lang],dl[id|class|title|style|dir|lang],dt[id|class|title|style|dir|lang],object[class|id|width|height|codebase|*],param[name|value|_value|class],embed[type|width|height|src|class|*],map[name|class],area[shape|coords|href|alt|target|class],bdo[class],button[class],iframe[*],figure,figcaption,cite,video[*],audio[*],picture[*],source[*],canvas[*]',
|
|
7
|
+
invalid_elements: 'font',
|
|
8
|
+
extended_valid_elements: '@[id|class|style],-div[id|dir|class|align|style],ins[datetime|cite],-ul[class|style],-li[class|style],-h1[id|dir|class|align|style],-h2[id|dir|class|align|style],-h3[id|dir|class|align|style],-h4[id|dir|class|align|style],-h5[id|dir|class|align|style],-h6[id|style|dir|class|align],span[id|class|style|lang],figure,figcaption',
|
|
26
9
|
toolbar: [
|
|
27
10
|
'styles',
|
|
28
11
|
'bold',
|
|
@@ -39,7 +22,30 @@ export const defaultFallbackConfig = {
|
|
|
39
22
|
'umbmacro',
|
|
40
23
|
'umbembeddialog',
|
|
41
24
|
],
|
|
42
|
-
|
|
43
|
-
|
|
25
|
+
style_formats: [
|
|
26
|
+
{
|
|
27
|
+
title: 'Headers',
|
|
28
|
+
items: [
|
|
29
|
+
{ title: 'Page header', block: 'h2' },
|
|
30
|
+
{ title: 'Section header', block: 'h3' },
|
|
31
|
+
{ title: 'Paragraph header', block: 'h4' },
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
title: 'Blocks',
|
|
36
|
+
items: [{ title: 'Normal', block: 'p' }],
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
title: 'Containers',
|
|
40
|
+
items: [
|
|
41
|
+
{ title: 'Quote', block: 'blockquote' },
|
|
42
|
+
{ title: 'Code', block: 'code' },
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
/**
|
|
47
|
+
* @description The maximum image size in pixels that can be inserted into the editor.
|
|
48
|
+
* @remarks This is registered and used by the UmbMediaPicker plugin
|
|
49
|
+
*/
|
|
44
50
|
maxImageSize: 500,
|
|
45
51
|
};
|
|
@@ -15,7 +15,6 @@ export declare class UmbInputTinyMceElement extends UmbInputTinyMceElement_base
|
|
|
15
15
|
/**
|
|
16
16
|
* Nothing rendered by default - TinyMCE initialisation creates
|
|
17
17
|
* a target div and binds the RTE to that element
|
|
18
|
-
* @returns
|
|
19
18
|
*/
|
|
20
19
|
render(): import("lit-html").TemplateResult<1>;
|
|
21
20
|
static styles: import("@lit/reactive-element/css-tag.js").CSSResult[];
|
|
@@ -15,13 +15,14 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
15
15
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
16
16
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
17
17
|
};
|
|
18
|
-
var _UmbInputTinyMceElement_instances, _UmbInputTinyMceElement_mediaHelper,
|
|
19
|
-
import {
|
|
20
|
-
import { pastePreProcessHandler
|
|
18
|
+
var _UmbInputTinyMceElement_instances, _UmbInputTinyMceElement_mediaHelper, _UmbInputTinyMceElement_plugins, _UmbInputTinyMceElement_editorRef, _UmbInputTinyMceElement_stylesheetRepository, _UmbInputTinyMceElement_serverUrl, _UmbInputTinyMceElement_loadPlugins, _UmbInputTinyMceElement_setTinyConfig, _UmbInputTinyMceElement_setLanguage, _UmbInputTinyMceElement_editorSetup, _UmbInputTinyMceElement_onInit, _UmbInputTinyMceElement_onChange;
|
|
19
|
+
import { defaultFallbackConfig } from './input-tiny-mce.defaults.js';
|
|
20
|
+
import { pastePreProcessHandler } from './input-tiny-mce.handlers.js';
|
|
21
21
|
import { availableLanguages } from './input-tiny-mce.languages.js';
|
|
22
22
|
import { uriAttributeSanitizer } from './input-tiny-mce.sanitizer.js';
|
|
23
|
+
import { umbMeta } from '../../meta/index.js';
|
|
23
24
|
import { FormControlMixin } from '../../../../external/uui/index.js';
|
|
24
|
-
import { renderEditor
|
|
25
|
+
import { renderEditor } from '../../../../external/tinymce/index.js';
|
|
25
26
|
import { loadManifestApi } from '../../../../libs/extension-api/index.js';
|
|
26
27
|
import { umbExtensionsRegistry } from '../../extension-registry/index.js';
|
|
27
28
|
import { css, customElement, html, property, query, state, } from '../../../../external/lit/index.js';
|
|
@@ -30,7 +31,7 @@ import { UmbMediaHelper } from '../../../../shared/utils/index.js';
|
|
|
30
31
|
import { UmbLitElement } from '../../../../shared/lit-element/index.js';
|
|
31
32
|
import { UMB_APP_CONTEXT } from '../../../../apps/app/index.js';
|
|
32
33
|
import { UmbStylesheetRepository } from '../../../templating/stylesheets/index.js';
|
|
33
|
-
|
|
34
|
+
import { UmbChangeEvent } from '../../event/index.js';
|
|
34
35
|
let UmbInputTinyMceElement = class UmbInputTinyMceElement extends FormControlMixin(UmbLitElement) {
|
|
35
36
|
getFormElement() {
|
|
36
37
|
return this._editorElement?.querySelector('iframe') ?? undefined;
|
|
@@ -40,8 +41,6 @@ let UmbInputTinyMceElement = class UmbInputTinyMceElement extends FormControlMix
|
|
|
40
41
|
_UmbInputTinyMceElement_instances.add(this);
|
|
41
42
|
this._tinyConfig = {};
|
|
42
43
|
_UmbInputTinyMceElement_mediaHelper.set(this, new UmbMediaHelper());
|
|
43
|
-
_UmbInputTinyMceElement_currentUser.set(this, void 0);
|
|
44
|
-
_UmbInputTinyMceElement_currentUserContext.set(this, void 0);
|
|
45
44
|
_UmbInputTinyMceElement_plugins.set(this, []);
|
|
46
45
|
_UmbInputTinyMceElement_editorRef.set(this, null);
|
|
47
46
|
_UmbInputTinyMceElement_stylesheetRepository.set(this, void 0);
|
|
@@ -50,12 +49,6 @@ let UmbInputTinyMceElement = class UmbInputTinyMceElement extends FormControlMix
|
|
|
50
49
|
__classPrivateFieldSet(this, _UmbInputTinyMceElement_serverUrl, instance.getServerUrl(), "f");
|
|
51
50
|
});
|
|
52
51
|
__classPrivateFieldSet(this, _UmbInputTinyMceElement_stylesheetRepository, new UmbStylesheetRepository(this), "f");
|
|
53
|
-
// TODO => this breaks tests, removing for now will ignore user language
|
|
54
|
-
// and fall back to tinymce default language
|
|
55
|
-
// this.consumeContext(UMB_AUTH, (instance) => {
|
|
56
|
-
// this.#auth = instance;
|
|
57
|
-
// this.#observeCurrentUser();
|
|
58
|
-
// });
|
|
59
52
|
}
|
|
60
53
|
async firstUpdated(_changedProperties) {
|
|
61
54
|
super.firstUpdated(_changedProperties);
|
|
@@ -72,17 +65,6 @@ let UmbInputTinyMceElement = class UmbInputTinyMceElement extends FormControlMix
|
|
|
72
65
|
async getFormatStyles(stylesheetPath) {
|
|
73
66
|
const rules = [];
|
|
74
67
|
stylesheetPath.forEach((path) => {
|
|
75
|
-
//TODO => Legacy path?
|
|
76
|
-
/**
|
|
77
|
-
* if (val.indexOf(Umbraco.Sys.ServerVariables.umbracoSettings.cssPath + "/") === 0) {
|
|
78
|
-
// current format (full path to stylesheet)
|
|
79
|
-
stylesheets.push(val);
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
// legacy format (stylesheet name only) - must prefix with stylesheet folder and postfix with ".css"
|
|
83
|
-
stylesheets.push(Umbraco.Sys.ServerVariables.umbracoSettings.cssPath + "/" + val + ".css");
|
|
84
|
-
}
|
|
85
|
-
*/
|
|
86
68
|
__classPrivateFieldGet(this, _UmbInputTinyMceElement_stylesheetRepository, "f")?.getStylesheetRules(path).then(({ data }) => {
|
|
87
69
|
data?.rules?.forEach((rule) => {
|
|
88
70
|
const r = {
|
|
@@ -120,25 +102,17 @@ let UmbInputTinyMceElement = class UmbInputTinyMceElement extends FormControlMix
|
|
|
120
102
|
/**
|
|
121
103
|
* Nothing rendered by default - TinyMCE initialisation creates
|
|
122
104
|
* a target div and binds the RTE to that element
|
|
123
|
-
* @returns
|
|
124
105
|
*/
|
|
125
106
|
render() {
|
|
126
107
|
return html `<div id="editor"></div>`;
|
|
127
108
|
}
|
|
128
109
|
};
|
|
129
110
|
_UmbInputTinyMceElement_mediaHelper = new WeakMap();
|
|
130
|
-
_UmbInputTinyMceElement_currentUser = new WeakMap();
|
|
131
|
-
_UmbInputTinyMceElement_currentUserContext = new WeakMap();
|
|
132
111
|
_UmbInputTinyMceElement_plugins = new WeakMap();
|
|
133
112
|
_UmbInputTinyMceElement_editorRef = new WeakMap();
|
|
134
113
|
_UmbInputTinyMceElement_stylesheetRepository = new WeakMap();
|
|
135
114
|
_UmbInputTinyMceElement_serverUrl = new WeakMap();
|
|
136
115
|
_UmbInputTinyMceElement_instances = new WeakSet();
|
|
137
|
-
_UmbInputTinyMceElement_observeCurrentUser = async function _UmbInputTinyMceElement_observeCurrentUser() {
|
|
138
|
-
if (!__classPrivateFieldGet(this, _UmbInputTinyMceElement_currentUserContext, "f"))
|
|
139
|
-
return;
|
|
140
|
-
this.observe(__classPrivateFieldGet(this, _UmbInputTinyMceElement_currentUserContext, "f").currentUser, (currentUser) => (__classPrivateFieldSet(this, _UmbInputTinyMceElement_currentUser, currentUser, "f")));
|
|
141
|
-
};
|
|
142
116
|
_UmbInputTinyMceElement_loadPlugins =
|
|
143
117
|
/**
|
|
144
118
|
* Load all custom plugins - need to split loading and instantiating as these
|
|
@@ -161,26 +135,47 @@ async function _UmbInputTinyMceElement_loadPlugins() {
|
|
|
161
135
|
}
|
|
162
136
|
};
|
|
163
137
|
_UmbInputTinyMceElement_setTinyConfig = async function _UmbInputTinyMceElement_setTinyConfig() {
|
|
138
|
+
const dimensions = this.configuration?.getValueByAlias('dimensions');
|
|
139
|
+
// Map the stylesheets with server url
|
|
140
|
+
const stylesheets = this.configuration
|
|
141
|
+
?.getValueByAlias('stylesheets')
|
|
142
|
+
?.map((stylesheetPath) => `${__classPrivateFieldGet(this, _UmbInputTinyMceElement_serverUrl, "f")}/css/${stylesheetPath.replace(/\\/g, '/')}`) ?? [];
|
|
143
|
+
const styleFormats = await this.getFormatStyles(stylesheets);
|
|
164
144
|
// create an object by merging the configuration onto the fallback config
|
|
165
|
-
// TODO: Seems like a too tight coupling between DataTypeConfigCollection and TinyMceConfig, I would love it begin more explicit what we take from DataTypeConfigCollection and parse on, but I understand that this gives some flexibility. Is this flexibility on purpose?
|
|
166
145
|
const configurationOptions = {
|
|
167
146
|
...defaultFallbackConfig,
|
|
168
|
-
|
|
147
|
+
height: dimensions?.height,
|
|
148
|
+
width: dimensions?.width,
|
|
149
|
+
content_css: stylesheets,
|
|
150
|
+
style_formats: styleFormats,
|
|
169
151
|
};
|
|
170
|
-
// Map the stylesheets with server url
|
|
171
|
-
const stylesheets = configurationOptions.stylesheets.map((stylesheetPath) => `${__classPrivateFieldGet(this, _UmbInputTinyMceElement_serverUrl, "f")}/css/${stylesheetPath.replace(/\\/g, '/')}`);
|
|
172
|
-
const styleFormats = await this.getFormatStyles(configurationOptions.stylesheets);
|
|
173
152
|
// no auto resize when a fixed height is set
|
|
174
|
-
if (!configurationOptions.
|
|
175
|
-
configurationOptions.plugins
|
|
176
|
-
|
|
153
|
+
if (!configurationOptions.height) {
|
|
154
|
+
if (Array.isArray(configurationOptions.plugins) && configurationOptions.plugins.includes('autoresize')) {
|
|
155
|
+
configurationOptions.plugins.splice(configurationOptions.plugins.indexOf('autoresize'), 1);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// set the configured toolbar if any
|
|
159
|
+
const toolbar = this.configuration?.getValueByAlias('toolbar');
|
|
160
|
+
if (toolbar) {
|
|
161
|
+
configurationOptions.toolbar = toolbar.join(' ');
|
|
162
|
+
}
|
|
163
|
+
// set the configured inline mode
|
|
164
|
+
const mode = this.configuration?.getValueByAlias('mode');
|
|
165
|
+
if (mode?.toLocaleLowerCase() === 'inline') {
|
|
166
|
+
configurationOptions.inline = true;
|
|
167
|
+
}
|
|
168
|
+
// set the maximum image size
|
|
169
|
+
const maxImageSize = this.configuration?.getValueByAlias('maxImageSize');
|
|
170
|
+
if (maxImageSize !== undefined) {
|
|
171
|
+
configurationOptions.maxImageSize = maxImageSize;
|
|
177
172
|
}
|
|
178
173
|
// set the default values that will not be modified via configuration
|
|
179
174
|
this._tinyConfig = {
|
|
180
175
|
autoresize_bottom_margin: 10,
|
|
181
176
|
body_class: 'umb-rte',
|
|
182
177
|
//see https://www.tiny.cloud/docs/tinymce/6/editor-important-options/#cache_suffix
|
|
183
|
-
cache_suffix:
|
|
178
|
+
cache_suffix: `?umb__rnd=${umbMeta.clientVersion}`,
|
|
184
179
|
contextMenu: false,
|
|
185
180
|
inline_boundaries_selector: 'a[href],code,.mce-annotation,.umb-embed-holder,.umb-macro-holder',
|
|
186
181
|
menubar: false,
|
|
@@ -191,33 +186,10 @@ _UmbInputTinyMceElement_setTinyConfig = async function _UmbInputTinyMceElement_s
|
|
|
191
186
|
statusbar: false,
|
|
192
187
|
setup: (editor) => __classPrivateFieldGet(this, _UmbInputTinyMceElement_instances, "m", _UmbInputTinyMceElement_editorSetup).call(this, editor),
|
|
193
188
|
target: this._editorElement,
|
|
189
|
+
paste_data_images: false,
|
|
190
|
+
// Extend with configuration options
|
|
191
|
+
...configurationOptions,
|
|
194
192
|
};
|
|
195
|
-
// extend with configuration values
|
|
196
|
-
this._tinyConfig = {
|
|
197
|
-
...this._tinyConfig,
|
|
198
|
-
content_css: stylesheets,
|
|
199
|
-
style_formats: styleFormats || defaultStyleFormats,
|
|
200
|
-
extended_valid_elements: defaultExtendedValidElements,
|
|
201
|
-
height: configurationOptions.height ?? 500,
|
|
202
|
-
invalid_elements: configurationOptions.invalidElements,
|
|
203
|
-
plugins: configurationOptions.plugins.map((x) => x.name),
|
|
204
|
-
toolbar: configurationOptions.toolbar.join(' '),
|
|
205
|
-
valid_elements: configurationOptions.validElements,
|
|
206
|
-
width: configurationOptions.width,
|
|
207
|
-
};
|
|
208
|
-
// Need to check if we are allowed to UPLOAD images
|
|
209
|
-
// This is done by checking if the insert image toolbar button is available
|
|
210
|
-
if (__classPrivateFieldGet(this, _UmbInputTinyMceElement_instances, "m", _UmbInputTinyMceElement_isMediaPickerEnabled).call(this)) {
|
|
211
|
-
this._tinyConfig = {
|
|
212
|
-
...this._tinyConfig,
|
|
213
|
-
// Update the TinyMCE Config object to allow pasting
|
|
214
|
-
images_upload_handler: uploadImageHandler,
|
|
215
|
-
automatic_uploads: false,
|
|
216
|
-
images_replace_blob_uris: false,
|
|
217
|
-
// This allows images to be pasted in & stored as Base64 until they get uploaded to server
|
|
218
|
-
paste_data_images: true,
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
193
|
__classPrivateFieldGet(this, _UmbInputTinyMceElement_instances, "m", _UmbInputTinyMceElement_setLanguage).call(this);
|
|
222
194
|
if (__classPrivateFieldGet(this, _UmbInputTinyMceElement_editorRef, "f")) {
|
|
223
195
|
__classPrivateFieldGet(this, _UmbInputTinyMceElement_editorRef, "f").destroy();
|
|
@@ -226,7 +198,7 @@ _UmbInputTinyMceElement_setTinyConfig = async function _UmbInputTinyMceElement_s
|
|
|
226
198
|
__classPrivateFieldSet(this, _UmbInputTinyMceElement_editorRef, editors.pop(), "f");
|
|
227
199
|
};
|
|
228
200
|
_UmbInputTinyMceElement_setLanguage = function _UmbInputTinyMceElement_setLanguage() {
|
|
229
|
-
const localeId =
|
|
201
|
+
const localeId = this.localize.lang();
|
|
230
202
|
//try matching the language using full locale format
|
|
231
203
|
let languageMatch = availableLanguages.find((x) => localeId?.localeCompare(x) === 0);
|
|
232
204
|
//if no matches, try matching using only the language
|
|
@@ -243,8 +215,6 @@ _UmbInputTinyMceElement_setLanguage = function _UmbInputTinyMceElement_setLangua
|
|
|
243
215
|
};
|
|
244
216
|
_UmbInputTinyMceElement_editorSetup = function _UmbInputTinyMceElement_editorSetup(editor) {
|
|
245
217
|
editor.suffix = '.min';
|
|
246
|
-
// register custom option maxImageSize
|
|
247
|
-
editor.options.register('maxImageSize', { processor: 'number', default: defaultFallbackConfig.maxImageSize });
|
|
248
218
|
// instantiate plugins - these are already loaded in this.#loadPlugins
|
|
249
219
|
// to ensure they are available before setting up the editor.
|
|
250
220
|
// Plugins require a reference to the current editor as a param, so can not
|
|
@@ -260,7 +230,6 @@ _UmbInputTinyMceElement_editorSetup = function _UmbInputTinyMceElement_editorSet
|
|
|
260
230
|
editor.on('Change', () => __classPrivateFieldGet(this, _UmbInputTinyMceElement_instances, "m", _UmbInputTinyMceElement_onChange).call(this, editor.getContent()));
|
|
261
231
|
editor.on('Dirty', () => __classPrivateFieldGet(this, _UmbInputTinyMceElement_instances, "m", _UmbInputTinyMceElement_onChange).call(this, editor.getContent()));
|
|
262
232
|
editor.on('Keyup', () => __classPrivateFieldGet(this, _UmbInputTinyMceElement_instances, "m", _UmbInputTinyMceElement_onChange).call(this, editor.getContent()));
|
|
263
|
-
editor.on('SetContent', () => __classPrivateFieldGet(this, _UmbInputTinyMceElement_mediaHelper, "f").uploadBlobImages(editor));
|
|
264
233
|
editor.on('focus', () => this.dispatchEvent(new CustomEvent('umb-rte-focus', { composed: true, bubbles: true })));
|
|
265
234
|
editor.on('blur', () => {
|
|
266
235
|
__classPrivateFieldGet(this, _UmbInputTinyMceElement_instances, "m", _UmbInputTinyMceElement_onChange).call(this, editor.getContent());
|
|
@@ -270,22 +239,22 @@ _UmbInputTinyMceElement_editorSetup = function _UmbInputTinyMceElement_editorSet
|
|
|
270
239
|
__classPrivateFieldGet(this, _UmbInputTinyMceElement_mediaHelper, "f").onResize(e);
|
|
271
240
|
__classPrivateFieldGet(this, _UmbInputTinyMceElement_instances, "m", _UmbInputTinyMceElement_onChange).call(this, editor.getContent());
|
|
272
241
|
});
|
|
273
|
-
editor.on('
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
242
|
+
editor.on('SetContent', (e) => {
|
|
243
|
+
/**
|
|
244
|
+
* Prevent injecting arbitrary JavaScript execution in on-attributes.
|
|
245
|
+
*
|
|
246
|
+
* TODO: This used to be toggleable through server variables with window.Umbraco?.Sys.ServerVariables.umbracoSettings.sanitizeTinyMce
|
|
247
|
+
*/
|
|
248
|
+
const allNodes = Array.from(editor.dom.doc.getElementsByTagName('*'));
|
|
249
|
+
allNodes.forEach((node) => {
|
|
250
|
+
for (let i = 0; i < node.attributes.length; i++) {
|
|
251
|
+
if (node.attributes[i].name.startsWith('on')) {
|
|
252
|
+
node.removeAttribute(node.attributes[i].name);
|
|
253
|
+
}
|
|
285
254
|
}
|
|
286
|
-
e.stopPropagation();
|
|
287
255
|
});
|
|
288
|
-
}
|
|
256
|
+
});
|
|
257
|
+
editor.on('init', () => editor.setContent(this.value?.toString() ?? ''));
|
|
289
258
|
};
|
|
290
259
|
_UmbInputTinyMceElement_onInit = function _UmbInputTinyMceElement_onInit(editor) {
|
|
291
260
|
//enable browser based spell checking
|
|
@@ -293,18 +262,8 @@ _UmbInputTinyMceElement_onInit = function _UmbInputTinyMceElement_onInit(editor)
|
|
|
293
262
|
uriAttributeSanitizer(editor);
|
|
294
263
|
};
|
|
295
264
|
_UmbInputTinyMceElement_onChange = function _UmbInputTinyMceElement_onChange(value) {
|
|
296
|
-
|
|
297
|
-
this.dispatchEvent(new
|
|
298
|
-
};
|
|
299
|
-
_UmbInputTinyMceElement_isMediaPickerEnabled = function _UmbInputTinyMceElement_isMediaPickerEnabled() {
|
|
300
|
-
const toolbar = this._tinyConfig.toolbar;
|
|
301
|
-
if (Array.isArray(toolbar) && toolbar.includes('umbmediapicker')) {
|
|
302
|
-
return true;
|
|
303
|
-
}
|
|
304
|
-
else if (typeof toolbar === 'string' && toolbar.includes('umbmediapicker')) {
|
|
305
|
-
return true;
|
|
306
|
-
}
|
|
307
|
-
return false;
|
|
265
|
+
this.value = value;
|
|
266
|
+
this.dispatchEvent(new UmbChangeEvent());
|
|
308
267
|
};
|
|
309
268
|
UmbInputTinyMceElement.styles = [
|
|
310
269
|
css `
|
|
@@ -6,33 +6,3 @@ export const pastePreProcessHandler = (_editor, args) => {
|
|
|
6
6
|
// convert i to em
|
|
7
7
|
args.content = args.content.replace(/<\s*i([^>]*)>(.*?)<\s*\/\s*i([^>]*)>/g, '<em$1>$2</em$3>');
|
|
8
8
|
};
|
|
9
|
-
export const uploadImageHandler = (blobInfo, progress) => {
|
|
10
|
-
return new Promise((resolve, reject) => {
|
|
11
|
-
const xhr = new XMLHttpRequest();
|
|
12
|
-
xhr.open('POST', window.Umbraco?.Sys.ServerVariables.umbracoUrls.tinyMceApiBaseUrl + 'UploadImage');
|
|
13
|
-
xhr.onloadstart = () => document.dispatchEvent(new CustomEvent('rte.file.uploading', { composed: true, bubbles: true }));
|
|
14
|
-
xhr.onloadend = () => document.dispatchEvent(new CustomEvent('rte.file.uploaded', { composed: true, bubbles: true }));
|
|
15
|
-
xhr.upload.onprogress = (e) => progress((e.loaded / e.total) * 100);
|
|
16
|
-
xhr.onerror = () => reject('Image upload failed due to a XHR Transport error. Code: ' + xhr.status);
|
|
17
|
-
xhr.onload = () => {
|
|
18
|
-
if (xhr.status < 200 || xhr.status >= 300) {
|
|
19
|
-
reject('HTTP Error: ' + xhr.status);
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
const json = JSON.parse(xhr.responseText);
|
|
23
|
-
if (!json || typeof json.tmpLocation !== 'string') {
|
|
24
|
-
reject('Invalid JSON: ' + xhr.responseText);
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
// Put temp location into localstorage (used to update the img with data-tmpimg later on)
|
|
28
|
-
localStorage.set(`tinymce__${blobInfo.blobUri()}`, json.tmpLocation);
|
|
29
|
-
// We set the img src url to be the same as we started
|
|
30
|
-
// The Blob URI is stored in TinyMce's cache
|
|
31
|
-
// so the img still shows in the editor
|
|
32
|
-
resolve(blobInfo.blobUri());
|
|
33
|
-
};
|
|
34
|
-
const formData = new FormData();
|
|
35
|
-
formData.append('file', blobInfo.blob(), blobInfo.filename());
|
|
36
|
-
xhr.send(formData);
|
|
37
|
-
});
|
|
38
|
-
};
|
|
@@ -11,6 +11,7 @@ export * from './extension-registry/index.js';
|
|
|
11
11
|
export * from './id/index.js';
|
|
12
12
|
export * from './macro/index.js';
|
|
13
13
|
export * from './menu/index.js';
|
|
14
|
+
export * from './meta/index.js';
|
|
14
15
|
export * from './modal/index.js';
|
|
15
16
|
export * from './notification/index.js';
|
|
16
17
|
export * from './picker-input/index.js';
|
|
@@ -26,6 +26,7 @@ export * from './extension-registry/index.js';
|
|
|
26
26
|
export * from './id/index.js';
|
|
27
27
|
export * from './macro/index.js';
|
|
28
28
|
export * from './menu/index.js';
|
|
29
|
+
export * from './meta/index.js';
|
|
29
30
|
export * from './modal/index.js';
|
|
30
31
|
export * from './notification/index.js';
|
|
31
32
|
export * from './picker-input/index.js';
|
package/dist-cms/packages/core/property-editor/uis/tiny-mce/plugins/tiny-mce-mediapicker.plugin.js
CHANGED
|
@@ -9,10 +9,12 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
9
9
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
11
|
};
|
|
12
|
-
var _UmbTinyMceMediaPickerPlugin_instances, _UmbTinyMceMediaPickerPlugin_mediaHelper, _UmbTinyMceMediaPickerPlugin_currentUser, _UmbTinyMceMediaPickerPlugin_modalContext, _UmbTinyMceMediaPickerPlugin_currentUserContext, _UmbTinyMceMediaPickerPlugin_onAction, _UmbTinyMceMediaPickerPlugin_showMediaPicker, _UmbTinyMceMediaPickerPlugin_insertInEditor;
|
|
12
|
+
var _UmbTinyMceMediaPickerPlugin_instances, _UmbTinyMceMediaPickerPlugin_mediaHelper, _UmbTinyMceMediaPickerPlugin_currentUser, _UmbTinyMceMediaPickerPlugin_modalContext, _UmbTinyMceMediaPickerPlugin_currentUserContext, _UmbTinyMceMediaPickerPlugin_temporaryFileRepository, _UmbTinyMceMediaPickerPlugin_onAction, _UmbTinyMceMediaPickerPlugin_showMediaPicker, _UmbTinyMceMediaPickerPlugin_insertInEditor, _UmbTinyMceMediaPickerPlugin_uploadImageHandler;
|
|
13
13
|
import { UmbTinyMcePluginBase } from '../../../../components/index.js';
|
|
14
14
|
import { UmbMediaHelper } from '../../../../../../shared/utils/index.js';
|
|
15
15
|
import { UMB_MEDIA_TREE_PICKER_MODAL, UMB_MODAL_MANAGER_CONTEXT_TOKEN, } from '../../../../modal/index.js';
|
|
16
|
+
import { UmbTemporaryFileRepository } from '../../../../temporary-file/index.js';
|
|
17
|
+
import { UmbId } from '../../../../id/index.js';
|
|
16
18
|
class UmbTinyMceMediaPickerPlugin extends UmbTinyMcePluginBase {
|
|
17
19
|
constructor(args) {
|
|
18
20
|
super(args);
|
|
@@ -21,7 +23,37 @@ class UmbTinyMceMediaPickerPlugin extends UmbTinyMcePluginBase {
|
|
|
21
23
|
_UmbTinyMceMediaPickerPlugin_currentUser.set(this, void 0);
|
|
22
24
|
_UmbTinyMceMediaPickerPlugin_modalContext.set(this, void 0);
|
|
23
25
|
_UmbTinyMceMediaPickerPlugin_currentUserContext.set(this, void 0);
|
|
26
|
+
_UmbTinyMceMediaPickerPlugin_temporaryFileRepository.set(this, void 0);
|
|
27
|
+
_UmbTinyMceMediaPickerPlugin_uploadImageHandler.set(this, (blobInfo, progress) => {
|
|
28
|
+
return new Promise((resolve, reject) => {
|
|
29
|
+
// Fetch does not support progress, so we need to fake it.
|
|
30
|
+
progress(0);
|
|
31
|
+
const id = UmbId.new();
|
|
32
|
+
const fileBlob = blobInfo.blob();
|
|
33
|
+
const file = new File([fileBlob], blobInfo.filename(), { type: fileBlob.type });
|
|
34
|
+
progress(50);
|
|
35
|
+
document.dispatchEvent(new CustomEvent('rte.file.uploading', { composed: true, bubbles: true }));
|
|
36
|
+
__classPrivateFieldGet(this, _UmbTinyMceMediaPickerPlugin_temporaryFileRepository, "f")
|
|
37
|
+
.upload(id, file)
|
|
38
|
+
.then((response) => {
|
|
39
|
+
if (response.error) {
|
|
40
|
+
reject(response.error);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
// Put temp location into localstorage (used to update the img with data-tmpimg later on)
|
|
44
|
+
const blobUri = window.URL.createObjectURL(fileBlob);
|
|
45
|
+
sessionStorage.setItem(`tinymce__${blobUri}`, id);
|
|
46
|
+
resolve(blobUri);
|
|
47
|
+
})
|
|
48
|
+
.catch(reject)
|
|
49
|
+
.finally(() => {
|
|
50
|
+
progress(100);
|
|
51
|
+
document.dispatchEvent(new CustomEvent('rte.file.uploaded', { composed: true, bubbles: true }));
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
});
|
|
24
55
|
__classPrivateFieldSet(this, _UmbTinyMceMediaPickerPlugin_mediaHelper, new UmbMediaHelper(), "f");
|
|
56
|
+
__classPrivateFieldSet(this, _UmbTinyMceMediaPickerPlugin_temporaryFileRepository, new UmbTemporaryFileRepository(args.host), "f");
|
|
25
57
|
this.consumeContext(UMB_MODAL_MANAGER_CONTEXT_TOKEN, (modalContext) => {
|
|
26
58
|
__classPrivateFieldSet(this, _UmbTinyMceMediaPickerPlugin_modalContext, modalContext, "f");
|
|
27
59
|
});
|
|
@@ -31,15 +63,36 @@ class UmbTinyMceMediaPickerPlugin extends UmbTinyMcePluginBase {
|
|
|
31
63
|
// this.#currentUserContext = instance;
|
|
32
64
|
// this.#observeCurrentUser();
|
|
33
65
|
// });
|
|
34
|
-
this.editor.ui.registry.
|
|
66
|
+
this.editor.ui.registry.addToggleButton('umbmediapicker', {
|
|
35
67
|
icon: 'image',
|
|
36
68
|
tooltip: 'Media Picker',
|
|
37
|
-
//stateSelector: 'img[data-udi]', TODO => Investigate where stateselector has gone, or if it is still needed
|
|
38
69
|
onAction: () => __classPrivateFieldGet(this, _UmbTinyMceMediaPickerPlugin_instances, "m", _UmbTinyMceMediaPickerPlugin_onAction).call(this),
|
|
70
|
+
onSetup: (api) => {
|
|
71
|
+
const changed = this.editor.selection.selectorChangedWithUnbind('img[data-udi]', (state) => api.setActive(state));
|
|
72
|
+
return () => changed.unbind();
|
|
73
|
+
},
|
|
39
74
|
});
|
|
75
|
+
// Register global options for the editor
|
|
76
|
+
this.editor.options.register('maxImageSize', { processor: 'number', default: 500 });
|
|
77
|
+
// Adjust Editor settings to allow pasting images
|
|
78
|
+
// but only if the umbmediapicker button is present
|
|
79
|
+
const toolbar = this.configuration?.getValueByAlias('toolbar');
|
|
80
|
+
if (toolbar?.includes('umbmediapicker')) {
|
|
81
|
+
this.editor.options.set('paste_data_images', true);
|
|
82
|
+
this.editor.options.set('automatic_uploads', false);
|
|
83
|
+
this.editor.options.set('images_upload_handler', __classPrivateFieldGet(this, _UmbTinyMceMediaPickerPlugin_uploadImageHandler, "f"));
|
|
84
|
+
// This allows images to be pasted in & stored as Base64 until they get uploaded to server
|
|
85
|
+
this.editor.options.set('images_replace_blob_uris', true);
|
|
86
|
+
// Listen for SetContent to update images
|
|
87
|
+
this.editor.on('SetContent', async (e) => {
|
|
88
|
+
const content = e.content;
|
|
89
|
+
// Handle images that are pasted in
|
|
90
|
+
__classPrivateFieldGet(this, _UmbTinyMceMediaPickerPlugin_mediaHelper, "f").uploadBlobImages(this.editor, content);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
40
93
|
}
|
|
41
94
|
}
|
|
42
|
-
_UmbTinyMceMediaPickerPlugin_mediaHelper = new WeakMap(), _UmbTinyMceMediaPickerPlugin_currentUser = new WeakMap(), _UmbTinyMceMediaPickerPlugin_modalContext = new WeakMap(), _UmbTinyMceMediaPickerPlugin_currentUserContext = new WeakMap(), _UmbTinyMceMediaPickerPlugin_instances = new WeakSet(), _UmbTinyMceMediaPickerPlugin_onAction =
|
|
95
|
+
_UmbTinyMceMediaPickerPlugin_mediaHelper = new WeakMap(), _UmbTinyMceMediaPickerPlugin_currentUser = new WeakMap(), _UmbTinyMceMediaPickerPlugin_modalContext = new WeakMap(), _UmbTinyMceMediaPickerPlugin_currentUserContext = new WeakMap(), _UmbTinyMceMediaPickerPlugin_temporaryFileRepository = new WeakMap(), _UmbTinyMceMediaPickerPlugin_uploadImageHandler = new WeakMap(), _UmbTinyMceMediaPickerPlugin_instances = new WeakSet(), _UmbTinyMceMediaPickerPlugin_onAction =
|
|
43
96
|
/*
|
|
44
97
|
async #observeCurrentUser() {
|
|
45
98
|
if (!this.#currentUserContext) return;
|
package/dist-cms/packages/core/property-editor/uis/tiny-mce/property-editor-ui-tiny-mce.element.d.ts
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { UmbPropertyEditorUiElement } from '../../../extension-registry/index.js';
|
|
2
2
|
import { UmbLitElement } from '../../../../../shared/lit-element/index.js';
|
|
3
3
|
import { UmbPropertyEditorConfigCollection } from '../../index.js';
|
|
4
|
+
type RichTextEditorValue = {
|
|
5
|
+
blocks: object;
|
|
6
|
+
markup: string;
|
|
7
|
+
};
|
|
4
8
|
/**
|
|
5
9
|
* @element umb-property-editor-ui-tiny-mce
|
|
6
10
|
*/
|
|
7
11
|
export declare class UmbPropertyEditorUITinyMceElement extends UmbLitElement implements UmbPropertyEditorUiElement {
|
|
8
12
|
#private;
|
|
9
|
-
value
|
|
13
|
+
value?: RichTextEditorValue;
|
|
10
14
|
set config(config: UmbPropertyEditorConfigCollection | undefined);
|
|
11
15
|
render(): import("lit-html").TemplateResult<1>;
|
|
12
16
|
static styles: import("@lit/reactive-element/css-tag.js").CSSResult[];
|
package/dist-cms/packages/core/property-editor/uis/tiny-mce/property-editor-ui-tiny-mce.element.js
CHANGED
|
@@ -27,7 +27,10 @@ let UmbPropertyEditorUITinyMceElement = class UmbPropertyEditorUITinyMceElement
|
|
|
27
27
|
super(...arguments);
|
|
28
28
|
_UmbPropertyEditorUITinyMceElement_instances.add(this);
|
|
29
29
|
_UmbPropertyEditorUITinyMceElement_configuration.set(this, void 0);
|
|
30
|
-
this.value =
|
|
30
|
+
this.value = {
|
|
31
|
+
blocks: {},
|
|
32
|
+
markup: '',
|
|
33
|
+
};
|
|
31
34
|
}
|
|
32
35
|
set config(config) {
|
|
33
36
|
__classPrivateFieldSet(this, _UmbPropertyEditorUITinyMceElement_configuration, config, "f");
|
|
@@ -36,18 +39,21 @@ let UmbPropertyEditorUITinyMceElement = class UmbPropertyEditorUITinyMceElement
|
|
|
36
39
|
return html `<umb-input-tiny-mce
|
|
37
40
|
@change=${__classPrivateFieldGet(this, _UmbPropertyEditorUITinyMceElement_instances, "m", _UmbPropertyEditorUITinyMceElement_onChange)}
|
|
38
41
|
.configuration=${__classPrivateFieldGet(this, _UmbPropertyEditorUITinyMceElement_configuration, "f")}
|
|
39
|
-
.value=${this.value}></umb-input-tiny-mce>`;
|
|
42
|
+
.value=${this.value?.markup ?? ''}></umb-input-tiny-mce>`;
|
|
40
43
|
}
|
|
41
44
|
};
|
|
42
45
|
_UmbPropertyEditorUITinyMceElement_configuration = new WeakMap();
|
|
43
46
|
_UmbPropertyEditorUITinyMceElement_instances = new WeakSet();
|
|
44
47
|
_UmbPropertyEditorUITinyMceElement_onChange = function _UmbPropertyEditorUITinyMceElement_onChange(event) {
|
|
45
|
-
this.value =
|
|
48
|
+
this.value = {
|
|
49
|
+
blocks: {},
|
|
50
|
+
markup: event.target.value,
|
|
51
|
+
};
|
|
46
52
|
this.dispatchEvent(new CustomEvent('property-value-change'));
|
|
47
53
|
};
|
|
48
54
|
UmbPropertyEditorUITinyMceElement.styles = [UmbTextStyles];
|
|
49
55
|
__decorate([
|
|
50
|
-
property({ type:
|
|
56
|
+
property({ type: Object })
|
|
51
57
|
], UmbPropertyEditorUITinyMceElement.prototype, "value", void 0);
|
|
52
58
|
__decorate([
|
|
53
59
|
property({ attribute: false })
|