diff --git a/src/Umbraco.Web.UI.Client/src/content/content-editor.element.ts b/src/Umbraco.Web.UI.Client/src/content/content-editor.element.ts
index 9bd38fdc79..c3aff9e9ab 100644
--- a/src/Umbraco.Web.UI.Client/src/content/content-editor.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/content/content-editor.element.ts
@@ -51,30 +51,34 @@ class UmbContentEditor extends UmbContextConsumerMixin(LitElement) {
@state()
_node?: DocumentNode;
- private _contentService?: UmbNodeStore;
+ private _nodeStore?: UmbNodeStore;
private _nodeSubscription?: Subscription;
constructor () {
super();
- this.consumeContext('umbNodeStore', (contentService: UmbNodeStore) => {
- this._contentService = contentService;
+ this.consumeContext('umbNodeStore', (nodeStore: UmbNodeStore) => {
+ this._nodeStore = nodeStore;
this._useNode();
});
}
- private _onPropertyDataTypeChange(e: CustomEvent) {
- const target = (e.target as any)
- console.log(target.value)
+ private _onPropertyValueChange(e: CustomEvent) {
+ const target = (e.target as any);
// TODO: Set value.
- //this.nodeData.properties.find(x => x.propertyAlias === target.propertyAlias)?.tempValue = target.value;
+ const property = this._node?.properties.find(x => x.alias === target.property.alias);
+ if(property) {
+ property.tempValue = target.value;
+ } else {
+ console.error('property was not found', target.property.alias);
+ }
}
private _useNode() {
this._nodeSubscription?.unsubscribe();
- this._nodeSubscription = this._contentService?.getById(parseInt(this.id)).subscribe(node => {
+ this._nodeSubscription = this._nodeStore?.getById(parseInt(this.id)).subscribe(node => {
if (!node) return; // TODO: Handle nicely if there is no node.
this._node = node;
});
@@ -85,7 +89,10 @@ class UmbContentEditor extends UmbContextConsumerMixin(LitElement) {
}
private _onSave() {
- console.log('Save');
+ // TODO: What if store is not present, what if node is not loaded....
+ if(this._node) {
+ this._nodeStore?.save([this._node]);
+ }
}
private _onSaveAndPreview() {
@@ -95,6 +102,7 @@ class UmbContentEditor extends UmbContextConsumerMixin(LitElement) {
disconnectedCallback(): void {
super.disconnectedCallback();
this._nodeSubscription?.unsubscribe();
+ delete this._node;
}
render() {
@@ -114,7 +122,7 @@ class UmbContentEditor extends UmbContextConsumerMixin(LitElement) {
+ @property-value-change=${this._onPropertyValueChange}>
`)}
diff --git a/src/Umbraco.Web.UI.Client/src/content/content-section.element.ts b/src/Umbraco.Web.UI.Client/src/content/content-section.element.ts
index 54f7128bf1..aea51ccbd1 100644
--- a/src/Umbraco.Web.UI.Client/src/content/content-section.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/content/content-section.element.ts
@@ -3,7 +3,6 @@ import { css, html, LitElement } from 'lit';
import { customElement } from 'lit/decorators.js';
import { UmbContextConsumerMixin, UmbContextProviderMixin } from '../core/context';
import { UmbRouteLocation, UmbRouter } from '../core/router';
-import { UmbNodeStore as UmbNodeStore } from '../core/stores/node.store';
import { Subscription } from 'rxjs';
import './content-tree.element';
@@ -44,6 +43,8 @@ export class UmbContentSection extends UmbContextProviderMixin(UmbContextConsume
// TODO: temp outlet solution
const nodeId = location.params.nodeId;
+ this._outlet?.parentNode?.removeChild(this._outlet);
+
if (nodeId !== undefined) {
const contentEditor = document.createElement('umb-content-editor');
contentEditor.id = nodeId;
diff --git a/src/Umbraco.Web.UI.Client/src/core/stores/node.store.ts b/src/Umbraco.Web.UI.Client/src/core/stores/node.store.ts
index 14dbebccc6..3a84161e56 100644
--- a/src/Umbraco.Web.UI.Client/src/core/stores/node.store.ts
+++ b/src/Umbraco.Web.UI.Client/src/core/stores/node.store.ts
@@ -17,9 +17,39 @@ export class UmbNodeStore {
return this.nodes.pipe(map(((nodes: Array) => nodes.find((node: DocumentNode) => node.id === id) || null)));
}
+ // TODO: Use Node type, to not be specific about Document.
+ // TODO: make sure UI somehow can follow the status of this action.
+ save(data: DocumentNode[]) {
+ // fetch from server and update store
+ // TODO: use Fetcher API.
+ let body:string;
+
+ try {
+ body = JSON.stringify(data);
+ } catch (error) {
+ console.error(error);
+ return;
+ }
+
+ // TODO: Use node type to hit the right API, or have a general Node API?
+ fetch('/umbraco/backoffice/content/save',
+ {
+ method: 'POST',
+ body: body,
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ }
+ )
+ .then(res => res.json())
+ .then(data => {
+ this._updateStore(data);
+ });
+ }
+
private _updateStore (fetchedNodes: Array) {
const storedNodes = this._nodes.getValue();
- let updated: any = [...storedNodes];
+ const updated: DocumentNode[] = [...storedNodes];
fetchedNodes.forEach(fetchedNode => {
const index = storedNodes.map(storedNode => storedNode.id).indexOf(fetchedNode.id);
@@ -29,7 +59,7 @@ export class UmbNodeStore {
updated[index] = fetchedNode;
} else {
// If the node is not in the store, add it
- updated = [...updated, fetchedNode];
+ updated.push(fetchedNode);
}
})
diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/content.data.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/content.data.ts
index 30078f0a73..0d436fc663 100644
--- a/src/Umbraco.Web.UI.Client/src/mocks/data/content.data.ts
+++ b/src/Umbraco.Web.UI.Client/src/mocks/data/content.data.ts
@@ -5,8 +5,8 @@ export interface DocumentNode {
alias: string;
icon: string; // TODO: should come from the doc type?
properties: NodeProperty[];
- data: any; // TODO: define data type
- layout?: any; // TODO: define layout type - make it non-optional
+ //data: any; // TODO: define data type
+ //layout?: any; // TODO: define layout type - make it non-optional
}
export interface DataTypeEntity {
@@ -27,29 +27,32 @@ export interface NodeProperty {
tempValue: string; // TODO: remove this - only used for testing
}
-export const data = [
+
+export const data: Array = [
{
id: 1,
- key: '74e4008a-ea4f-4793-b924-15e02fd380d3',
+ key: '74e4008a-ea4f-4793-b924-15e02fd380d1',
name: 'Document 1',
alias: 'document1',
icon: 'document',
properties: [
{
alias: 'myHeadline',
- label: 'Textarea label',
+ label: 'Textarea label 1',
description: 'this is a textarea property',
dataTypeKey: 'dt-1',
tempValue: 'hello world 1'
},
{
alias: 'myDescription',
- label: 'Text string label',
+ label: 'Text string label 1',
description: 'This is the a text string property',
dataTypeKey: 'dt-2',
tempValue: 'Tex areaaaa 1'
},
],
+ /*
+ // Concept for stored values, better approach for variants, separating data from structure/configuration
data: [
{
alias: 'myHeadline',
@@ -60,7 +63,9 @@ export const data = [
value: 'Teeeeexxxt areaaaaaa',
},
],
+ */
/*
+ // Concept for node layout, separation of design from config and data.
layout: [
{
type: 'group',
@@ -80,53 +85,26 @@ export const data = [
},
{
id: 2,
- key: '74e4008a-ea4f-4793-b924-15e02fd380d3',
+ key: '74e4008a-ea4f-4793-b924-15e02fd380d2',
name: 'Document 2',
alias: 'document2',
icon: 'favorite',
properties: [
{
alias: 'myHeadline',
- label: 'Textarea label',
+ label: 'Textarea label 2',
description: 'this is a textarea property',
dataTypeKey: 'dt-1',
tempValue: 'hello world 2'
},
{
alias: 'myDescription',
- label: 'Text string label',
+ label: 'Text string label 2',
description: 'This is the a text string property',
dataTypeKey: 'dt-2',
tempValue: 'Tex areaaaa 2'
},
],
- data: [
- {
- alias: 'myHeadline',
- value: 'hello world',
- },
- {
- alias: 'myDescription',
- value: 'Teeeeexxxt areaaaaaa',
- },
- ],
- /*
- layout: [
- {
- type: 'group',
- children: [
- {
- type: 'property',
- alias: 'myHeadline'
- },
- {
- type: 'property',
- alias: 'myDescription'
- }
- ]
- }
- ],
- */
}
];
@@ -141,6 +119,21 @@ class UmbContentData {
getById (id: number) {
return this._data.find(item => item.id === id);
}
+
+ save(nodes: DocumentNode[]) {
+ nodes.forEach( node => {
+ const foundIndex = this._data.findIndex(item => item.id === node.id);
+ if(foundIndex !== -1) {
+ // replace
+ this._data[foundIndex] = node;
+ } else {
+ // new
+ this._data.push(node);
+ }
+ });
+ //console.log('save:', nodes);
+ return nodes;
+ }
}
export const umbContentData = new UmbContentData();
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/mocks/domains/content.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/domains/content.handlers.ts
index 8354a74589..1663e7af82 100644
--- a/src/Umbraco.Web.UI.Client/src/mocks/domains/content.handlers.ts
+++ b/src/Umbraco.Web.UI.Client/src/mocks/domains/content.handlers.ts
@@ -1,5 +1,6 @@
import { rest } from 'msw';
-import { umbContentData } from '../data/content.data';
+import { DocumentNode, umbContentData } from '../data/content.data';
+
// TODO: add schema
export const handlers = [
@@ -9,9 +10,23 @@ export const handlers = [
const int = parseInt(id);
const document = umbContentData.getById(int);
+
return res(
ctx.status(200),
ctx.json([document])
);
}),
+
+ rest.post('/umbraco/backoffice/content/save', (req, res, ctx) => {
+ const data = req.body as any;
+ if (!data) return;
+
+
+ umbContentData.save(data);
+
+ return res(
+ ctx.status(200),
+ ctx.json(data)
+ );
+ }),
];
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/node-editor/node-property.element.ts b/src/Umbraco.Web.UI.Client/src/node-editor/node-property.element.ts
index 19a9e876f9..c5d8a83113 100644
--- a/src/Umbraco.Web.UI.Client/src/node-editor/node-property.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/node-editor/node-property.element.ts
@@ -32,8 +32,11 @@ class UmbNodeProperty extends LitElement {
value?:string;
// TODO: maybe a bit messy with all the event listeners on the different levels:
- private _onPropertyDataTypeChange = (e :CustomEvent) => {
+ private _onPropertyDataTypeChange = ( e:CustomEvent) => {
this.value = (e.target as any).value;
+ this.dispatchEvent(new CustomEvent('property-value-change', { bubbles: true, composed: true }));
+ // No need for this event to leave scope.
+ e.stopPropagation();
}
render() {
diff --git a/src/Umbraco.Web.UI.Client/src/property-editors/property-editor-textarea.element.ts b/src/Umbraco.Web.UI.Client/src/property-editors/property-editor-textarea.element.ts
index 30cc3e34d8..90e5ba71da 100644
--- a/src/Umbraco.Web.UI.Client/src/property-editors/property-editor-textarea.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/property-editors/property-editor-textarea.element.ts
@@ -16,8 +16,13 @@ class UmbPropertyEditorTextarea extends LitElement {
@property()
value = '';
+ private onInput(e: InputEvent) {
+ this.value = (e.target as HTMLInputElement).value;
+ this.dispatchEvent(new CustomEvent('property-editor-change', { bubbles: true, composed: true }));
+ }
+
render() {
- return html``;
+ return html``;
}
}
diff --git a/src/Umbraco.Web.UI.Client/src/section.context.ts b/src/Umbraco.Web.UI.Client/src/section.context.ts
index 5ca94e7179..ff6be9e81f 100644
--- a/src/Umbraco.Web.UI.Client/src/section.context.ts
+++ b/src/Umbraco.Web.UI.Client/src/section.context.ts
@@ -1,5 +1,5 @@
import { firstValueFrom, map, Observable, ReplaySubject } from 'rxjs';
-import { UmbExtensionManifest, UmbExtensionRegistry, UmbManifestSectionMeta } from './core/extension';
+import { UmbExtensionManifest, UmbExtensionRegistry } from './core/extension';
export class UmbSectionContext {
private _extensionRegistry!: UmbExtensionRegistry;