diff --git a/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts b/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts index 0c75c70637..47c4e72a23 100644 --- a/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts +++ b/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts @@ -3,11 +3,15 @@ import { BehaviorSubject, map, Observable } from 'rxjs'; // TODO: how do we want to type extensions? export type UmbExtensionType = 'startUp' | 'section' | 'propertyEditorUI' | 'dashboard'; +export type UmbExtensionManifestJSModel = { + elementName?: string; +} + export type UmbExtensionManifestBase = { //type: string; alias: string; name: string; - js?: string | (() => Promise); + js?: string | (() => Promise); elementName?: string; //meta: undefined; } diff --git a/src/Umbraco.Web.UI.Client/src/core/extension/load-extension.function.ts b/src/Umbraco.Web.UI.Client/src/core/extension/load-extension.function.ts new file mode 100644 index 0000000000..38bbc9c1f9 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/core/extension/load-extension.function.ts @@ -0,0 +1,30 @@ +import { UmbExtensionManifest, UmbExtensionManifestJSModel } from './extension.registry'; + +export function loadExtension(manifest: UmbExtensionManifest): Promise | Promise | null { + + + if (typeof manifest.js === 'function') { + return manifest.js() as Promise; + } + + // TODO: verify if this is acceptable solution. + if (typeof manifest.js === 'string') { + return new Promise((resolve, reject) => { + const script = document.createElement('script'); + script .type = 'text/javascript'; + //script.charset = 'utf-8'; + script.async = true; + script.src = manifest.js as string; + script.onload = function () { + resolve(null); + }; + script.onerror = function () { + reject(new Error(`Script load error for ${manifest.js}`)) + }; + document.body.appendChild(script); + }) as Promise; + } + + console.log('-- Extension does not have any referenced JS') + return Promise.resolve(null); +} \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/index.ts b/src/Umbraco.Web.UI.Client/src/index.ts index 53004ad3a6..e94a42637f 100644 --- a/src/Umbraco.Web.UI.Client/src/index.ts +++ b/src/Umbraco.Web.UI.Client/src/index.ts @@ -94,6 +94,17 @@ const registerInternalManifests = async () => { group: 'common', } }, + { + type: 'propertyEditorUI', + alias: 'External.PropertyEditorUI.Test', + name: 'Text', + elementName: 'external-property-editor-test', //Gets the element name from JS file. + js: '/src/property-editors/external-property-editor-test.js', + meta: { + icon: 'document', + group: 'common', + } + }, { type: 'propertyEditorUI', alias: 'Umb.PropertyEditorUI.Textarea', diff --git a/src/Umbraco.Web.UI.Client/src/node-editor/node-property-data-type.element.ts b/src/Umbraco.Web.UI.Client/src/node-editor/node-property-data-type.element.ts index 4ca7afec1c..f4139aefc3 100644 --- a/src/Umbraco.Web.UI.Client/src/node-editor/node-property-data-type.element.ts +++ b/src/Umbraco.Web.UI.Client/src/node-editor/node-property-data-type.element.ts @@ -6,6 +6,7 @@ import { UmbDataTypeStore } from '../core/stores/data-type.store'; import { mergeMap, Subscription, map, switchMap } from 'rxjs'; import { DataTypeEntity } from '../mocks/data/content.data'; import { UmbExtensionManifest, UmbExtensionRegistry } from '../core/extension'; +import { loadExtension } from '../core/extension/load-extension.function'; @customElement('umb-node-property-data-type') class UmbNodePropertyDataType extends UmbContextConsumerMixin(LitElement) { @@ -96,28 +97,30 @@ class UmbNodePropertyDataType extends UmbContextConsumerMixin(LitElement) { const oldValue = this._element; - if (typeof _propertyEditorUI.js === 'function') { - this._element = _propertyEditorUI.js(); - // TODO: Niels: I guess this is not the element returned but a Promise of loading the JS, which hopefully exports the Class or maybe an ElementName prop? - } - if (typeof _propertyEditorUI.js === 'string') { - // const loadJsPromise = (() => import(_propertyEditorUI.js as string))(); - // TODO: show a loader until JS is loaded? - } + loadExtension(_propertyEditorUI)?.then(js => { - if (_propertyEditorUI.elementName) { - this._element = document.createElement(_propertyEditorUI.elementName); - } + // TODO: something with JS + console.log('ext js', js); + // IF we got a JS file loaded, we can use its elementName prop. + const elementName = _propertyEditorUI.elementName || js?.elementName; - // TODO: Set/Parse Data-Type-UI-configuration + if (elementName) { + this._element = document.createElement(elementName); + } + + // TODO: Set/Parse Data-Type-UI-configuration + + if(oldValue) { + oldValue.removeEventListener('property-editor-change', this._onPropertyEditorChange); + } + this._element.addEventListener('property-editor-change', this._onPropertyEditorChange); + + this._element.value = this.value;// Be aware its duplicated code + this.requestUpdate('element', oldValue); + }).catch(() => { + // TODO: loading JS failed so we should do some nice UI. (This does only happen if extension has a js prop, otherwise we concluded that no source was needed resolved the load.) + }); - if(oldValue) { - oldValue.removeEventListener('property-editor-change', this._onPropertyEditorChange); - } - this._element.addEventListener('property-editor-change', this._onPropertyEditorChange); - - this._element.value = this.value;// Be aware its duplicated code - this.requestUpdate('element', oldValue); } private _onPropertyEditorChange = ( e:CustomEvent) => { diff --git a/src/Umbraco.Web.UI.Client/src/property-editors/external-property-editor-test.js b/src/Umbraco.Web.UI.Client/src/property-editors/external-property-editor-test.js new file mode 100644 index 0000000000..943239e765 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/property-editors/external-property-editor-test.js @@ -0,0 +1,11 @@ +class ExternalPropertyEditorTest extends HTMLElement { + + constructor() { + super(); + this.attachShadow({mode: 'open'}); // sets and returns 'this.shadowRoot' + const wrapper = document.createElement('span'); + wrapper.textContent = 'hello world'; + this.shadowRoot.append(wrapper); + } +} +customElements.define('external-property-editor-test', ExternalPropertyEditorTest); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/property-editors/property-editor-text.element.ts b/src/Umbraco.Web.UI.Client/src/property-editors/property-editor-text.element.ts index fa198fd4bd..8b8e8702d1 100644 --- a/src/Umbraco.Web.UI.Client/src/property-editors/property-editor-text.element.ts +++ b/src/Umbraco.Web.UI.Client/src/property-editors/property-editor-text.element.ts @@ -26,6 +26,8 @@ class UmbPropertyEditorText extends LitElement { } } +export const elementName = 'umb-property-editor-text'; + declare global { interface HTMLElementTagNameMap { 'umb-property-editor-text': UmbPropertyEditorText;