diff --git a/cms-api/src/main/java/com/condation/cms/api/ui/elements/ContentTypes.java b/cms-api/src/main/java/com/condation/cms/api/ui/elements/ContentTypes.java index c76afd142..f9ae6e820 100644 --- a/cms-api/src/main/java/com/condation/cms/api/ui/elements/ContentTypes.java +++ b/cms-api/src/main/java/com/condation/cms/api/ui/elements/ContentTypes.java @@ -69,6 +69,9 @@ public Set getSectionTemplates (String section) { .filter(template -> template.section().equals(section)) .collect(Collectors.toSet()); } + public Set getSectionTemplates () { + return new HashSet<>(sectionTemplates); + } public static record PageTemplate(String name, String template, Map data) { diff --git a/modules/ui-module/src/main/java/com/condation/cms/modules/ui/extensionpoints/UiTemplateModelExtension.java b/modules/ui-module/src/main/java/com/condation/cms/modules/ui/extensionpoints/UiTemplateModelExtension.java index 042fad952..f0fb2949e 100644 --- a/modules/ui-module/src/main/java/com/condation/cms/modules/ui/extensionpoints/UiTemplateModelExtension.java +++ b/modules/ui-module/src/main/java/com/condation/cms/modules/ui/extensionpoints/UiTemplateModelExtension.java @@ -80,18 +80,9 @@ public String editMeta (String editor, String element, String uri, String toolba ); } + public String toolbar (String id, String type, String[] actions) { - if (!requestContext.has(IsPreviewFeature.class)) { - return ""; - } - Map toolbar = Map.of( - "id", id, - "type", type, - "actions", actions - ); - return " data-cms-toolbar='%s' ".formatted( - JSONUtil.toJson(toolbar) - ); + return toolbar(id, type, actions, Map.of()); } public String toolbar (String id, String type, String[] actions, Map additional) { if (!requestContext.has(IsPreviewFeature.class)) { @@ -109,16 +100,7 @@ public String toolbar (String id, String type, String[] actions, Map toolbar = Map.of( - "id", id, - "uri", uri - ); - return " data-cms-toolbar='%s' ".formatted( - JSONUtil.toJson(toolbar) - ); + return toolbar(id, uri, new String[0]); } public String mediaToolbar (String [] actions, Map options) { diff --git a/modules/ui-module/src/main/java/com/condation/cms/modules/ui/extensionpoints/remotemethods/RemoteManagerEnpoints.java b/modules/ui-module/src/main/java/com/condation/cms/modules/ui/extensionpoints/remotemethods/RemoteManagerEnpoints.java index 423ce6d94..db5c45f4c 100644 --- a/modules/ui-module/src/main/java/com/condation/cms/modules/ui/extensionpoints/remotemethods/RemoteManagerEnpoints.java +++ b/modules/ui-module/src/main/java/com/condation/cms/modules/ui/extensionpoints/remotemethods/RemoteManagerEnpoints.java @@ -33,6 +33,7 @@ import com.condation.cms.api.ui.rpc.RPCException; import com.condation.cms.content.RenderContext; import com.condation.cms.modules.ui.utils.TokenUtils; +import com.google.common.base.Strings; import java.time.Duration; /** @@ -69,7 +70,11 @@ public Object getMediaFormats (Map parameters) throws RPCExcepti public Object getSectionTemplates(Map parameters) throws RPCException { try { var section = (String) parameters.getOrDefault("section", ""); - return uiHooks().contentTypes().getSectionTemplates(section); + if (!Strings.isNullOrEmpty(section)) { + return uiHooks().contentTypes().getSectionTemplates(section); + } else { + return uiHooks().contentTypes().getSectionTemplates(); + } } catch (Exception e) { log.error("", e); throw new RPCException(0, e.getMessage()); diff --git a/modules/ui-module/src/main/java/com/condation/cms/modules/ui/services/RemoteMethodService.java b/modules/ui-module/src/main/java/com/condation/cms/modules/ui/services/RemoteMethodService.java index 2ffd2cc91..7fd860d5e 100644 --- a/modules/ui-module/src/main/java/com/condation/cms/modules/ui/services/RemoteMethodService.java +++ b/modules/ui-module/src/main/java/com/condation/cms/modules/ui/services/RemoteMethodService.java @@ -32,6 +32,7 @@ import com.condation.cms.api.ui.annotations.RemoteMethod; import com.condation.cms.auth.services.AuthorizationService; import com.condation.cms.auth.services.User; +import java.util.Collections; import java.util.function.Function; import lombok.RequiredArgsConstructor; @@ -76,7 +77,10 @@ public Object execute (final Map parameters, User user) { if (!RemoteMethodService.authorizationService.hasAnyPermission(user, remoteMethodAnnotation.permissions())) { throw new RemoteMethodException("access not allowed"); } - return function.apply(parameters); + if (parameters != null) { + return function.apply(parameters); + } + return function.apply(Collections.emptyMap()); }; } diff --git a/modules/ui-module/src/main/resources/manager/actions/page/edit-metaattribute-form.d.ts b/modules/ui-module/src/main/resources/manager/actions/page/edit-metaattribute-form.d.ts new file mode 100644 index 000000000..0fe4d169a --- /dev/null +++ b/modules/ui-module/src/main/resources/manager/actions/page/edit-metaattribute-form.d.ts @@ -0,0 +1,22 @@ +/*- + * #%L + * ui-module + * %% + * Copyright (C) 2023 - 2026 CondationCMS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ +export function runAction(params: any): Promise; diff --git a/modules/ui-module/src/main/resources/manager/actions/page/edit-metaattribute-form.js b/modules/ui-module/src/main/resources/manager/actions/page/edit-metaattribute-form.js new file mode 100644 index 000000000..24cd8bbaf --- /dev/null +++ b/modules/ui-module/src/main/resources/manager/actions/page/edit-metaattribute-form.js @@ -0,0 +1,89 @@ +/*- + * #%L + * ui-module + * %% + * Copyright (C) 2023 - 2025 CondationCMS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ +import { createForm } from '@cms/modules/form/forms.js'; +import { showToast } from '@cms/modules/toast.js'; +import { getPreviewUrl, reloadPreview } from '@cms/modules/preview.utils.js'; +import { buildValuesFromFields, getValueByPath } from '@cms/modules/node.js'; +import { getContentNode, getContent, setMeta } from '@cms/modules/rpc/rpc-content.js'; +import { i18n } from '@cms/modules/localization.js'; +import { openSidebar } from '@cms/modules/sidebar.js'; +import { getPageTemplates, getSectionTemplates } from '@cms/modules/rpc/rpc-manager'; +// hook.js +export async function runAction(params) { + var uri = null; + if (params.uri) { + uri = params.uri; + } + else { + const contentNode = await getContentNode({ + url: getPreviewUrl() + }); + uri = contentNode.result.uri; + } + const getContentResponse = await getContent({ + uri: uri + }); + var templates = null; + if (params.type === "section") { + templates = (await getSectionTemplates()).result; + } + else { + templates = (await getPageTemplates()).result; + } + var selected = templates.filter(item => item.template === getContentResponse?.result?.meta?.template); + var attrForm = []; + if (selected.length === 1) { + attrForm = selected[0].data?.forms[params.form] ? selected[0].data.forms[params.form].fields : []; + } + //const previewMetaForm = getMetaForm() + const fields = [ + ...attrForm + ]; + const values = { + ...buildValuesFromFields(attrForm, getContentResponse?.result?.meta) + }; + const form = createForm({ + fields: fields, + values: values + }); + openSidebar({ + title: 'Edit meta attribute', + body: 'modal body', + form: form, + resizable: true, + onCancel: (event) => { }, + onOk: async (event) => { + var updateData = form.getData(); + var setMetaResponse = await setMeta({ + uri: uri, + meta: updateData + }); + showToast({ + title: i18n.t('manager.actions.page.edit-metaattribute-list.toast.title', "MetaData updated"), + message: i18n.t('manager.actions.page.edit-metaattribute-list.toast.message', "The metadata has been updated successfully."), + type: 'success', // optional: info | success | warning | error + timeout: 3000 + }); + reloadPreview(); + } + }); +} diff --git a/modules/ui-module/src/main/resources/manager/actions/page/edit-page-settings.js b/modules/ui-module/src/main/resources/manager/actions/page/edit-page-settings.js index 137b52462..c82699cb9 100644 --- a/modules/ui-module/src/main/resources/manager/actions/page/edit-page-settings.js +++ b/modules/ui-module/src/main/resources/manager/actions/page/edit-page-settings.js @@ -66,7 +66,7 @@ export async function runAction(params) { var selected = pageTemplates.filter(pageTemplate => pageTemplate.template === getContentResponse?.result?.meta?.template); var pageSettingsForm = []; if (selected.length === 1) { - pageSettingsForm = selected[0].data?.forms?.settings ? selected[0].data.forms.settings : []; + pageSettingsForm = selected[0].data?.forms?.settings ? selected[0].data.forms.settings.fields : []; } //const previewMetaForm = getMetaForm() const fields = [ diff --git a/modules/ui-module/src/main/resources/manager/js/modules/form/field.list.js b/modules/ui-module/src/main/resources/manager/js/modules/form/field.list.js index 821bbb62b..df9fe8522 100644 --- a/modules/ui-module/src/main/resources/manager/js/modules/form/field.list.js +++ b/modules/ui-module/src/main/resources/manager/js/modules/form/field.list.js @@ -105,12 +105,12 @@ const getItemForm = async (el) => { const fieldName = listContainer?.getAttribute('name'); var itemForm = []; if (selected.length === 1) { - itemForm = (fieldName && selected[0].data?.forms[fieldName]) ? selected[0].data.forms[fieldName] : []; + itemForm = (fieldName && selected[0].data?.forms[fieldName]) ? selected[0].data.forms[fieldName].fields : []; } if (!itemForm || itemForm.length === 0) { let itemTypes = (await getListItemTypes({})).result; var selectedItemType = itemTypes.filter(itemType => itemType.name === fieldName); - itemForm = (selectedItemType.length === 1) ? selectedItemType[0].data?.form : []; + itemForm = (selectedItemType.length === 1) ? selectedItemType[0].data?.form.fields : []; } return itemForm; }; diff --git a/modules/ui-module/src/main/resources/manager/js/modules/form/field.markdown.js b/modules/ui-module/src/main/resources/manager/js/modules/form/field.markdown.js index 2062a839b..7075a136b 100644 --- a/modules/ui-module/src/main/resources/manager/js/modules/form/field.markdown.js +++ b/modules/ui-module/src/main/resources/manager/js/modules/form/field.markdown.js @@ -30,7 +30,7 @@ const createMarkdownField = (options, value = '') => { const key = "field." + options.name; const title = i18n.t(key, options.title); return ` -
+
diff --git a/modules/ui-module/src/main/resources/manager/js/modules/manager/manager.message.handlers.js b/modules/ui-module/src/main/resources/manager/js/modules/manager/manager.message.handlers.js index fbe71b4e0..4b8d27a50 100644 --- a/modules/ui-module/src/main/resources/manager/js/modules/manager/manager.message.handlers.js +++ b/modules/ui-module/src/main/resources/manager/js/modules/manager/manager.message.handlers.js @@ -68,12 +68,14 @@ const initMessageHandlers = () => { } else if (payload.element === "meta" && payload.editor === "form") { var cmd = { - "module": window.manager.baseUrl + "/actions/page/edit-metaattribute-list", + "module": window.manager.baseUrl + "/actions/page/edit-metaattribute-form", "function": "runAction", "parameters": { "editor": payload.editor, "attributes": payload.metaElements, - "options": payload.options ? payload.options : {} + "options": payload.options ? payload.options : {}, + "form": payload.form, + "type": payload.type } }; if (payload.uri) { diff --git a/modules/ui-module/src/main/resources/manager/js/modules/manager/toolbar.inject.js b/modules/ui-module/src/main/resources/manager/js/modules/manager/toolbar.inject.js index a23b834f3..d6578b436 100644 --- a/modules/ui-module/src/main/resources/manager/js/modules/manager/toolbar.inject.js +++ b/modules/ui-module/src/main/resources/manager/js/modules/manager/toolbar.inject.js @@ -89,25 +89,31 @@ const editAttributes = (event) => { type: 'edit', payload: { editor: "form", - element: "meta" + element: "meta", + form: toolbarDefinition.form ? toolbarDefinition.form : "attributes", + type: toolbarDefinition.type } }; if (toolbarDefinition.uri) { command.payload.uri = toolbarDefinition.uri; } - var elements = []; - toolbar.parentNode.querySelectorAll("[data-cms-editor]").forEach(($elem) => { + // legay old style to collect all meta elements for the form editor + /* + var elements = [] + toolbar.parentNode.querySelectorAll("[data-cms-editor]").forEach(($elem : HTMLElement) => { var toolbar = $elem.dataset.cmsToolbar ? JSON.parse($elem.dataset.cmsToolbar) : {}; if ($elem.dataset.cmsElement === "meta" - && (!toolbar.id || toolbar.id === toolbarDefinition.id)) { + && (!toolbar.id || toolbar.id === toolbarDefinition.id) + ) { elements.push({ name: $elem.dataset.cmsMetaElement, editor: $elem.dataset.cmsEditor, options: $elem.dataset.cmsEditorOptions ? JSON.parse($elem.dataset.cmsEditorOptions) : {} - }); + }) } - }); - command.payload.metaElements = elements; + }) + command.payload.metaElements = elements + */ frameMessenger.send(window.parent, command); }; export const initToolbar = (container) => { diff --git a/modules/ui-module/src/main/resources/manager/js/modules/rpc/rpc-manager.js b/modules/ui-module/src/main/resources/manager/js/modules/rpc/rpc-manager.js index 57b80c7c2..45ac86fc6 100644 --- a/modules/ui-module/src/main/resources/manager/js/modules/rpc/rpc-manager.js +++ b/modules/ui-module/src/main/resources/manager/js/modules/rpc/rpc-manager.js @@ -23,35 +23,35 @@ import { executeRemoteCall } from '@cms/modules/rpc/rpc.js'; const getSectionTemplates = async (options) => { var data = { method: "manager.contentTypes.sections", - parameters: options + parameters: options || {} }; return await executeRemoteCall(data); }; const getPageTemplates = async (options) => { var data = { method: "manager.contentTypes.pages", - parameters: options + parameters: options || {} }; return await executeRemoteCall(data); }; const getListItemTypes = async (options) => { var data = { method: "manager.contentTypes.listItemTypes", - parameters: options + parameters: options || {} }; return await executeRemoteCall(data); }; const getMediaForm = async (options) => { var data = { method: "manager.media.form", - parameters: options + parameters: options || {} }; return await executeRemoteCall(data); }; const createCSRFToken = async (options) => { var data = { method: "manager.token.createCSRF", - parameters: options + parameters: options || {} }; return await executeRemoteCall(data); }; diff --git a/modules/ui-module/src/main/ts/dist/actions/page/edit-metaattribute-form.d.ts b/modules/ui-module/src/main/ts/dist/actions/page/edit-metaattribute-form.d.ts new file mode 100644 index 000000000..6abc321a1 --- /dev/null +++ b/modules/ui-module/src/main/ts/dist/actions/page/edit-metaattribute-form.d.ts @@ -0,0 +1 @@ +export function runAction(params: any): Promise; diff --git a/modules/ui-module/src/main/ts/dist/actions/page/edit-metaattribute-form.js b/modules/ui-module/src/main/ts/dist/actions/page/edit-metaattribute-form.js new file mode 100644 index 000000000..24cd8bbaf --- /dev/null +++ b/modules/ui-module/src/main/ts/dist/actions/page/edit-metaattribute-form.js @@ -0,0 +1,89 @@ +/*- + * #%L + * ui-module + * %% + * Copyright (C) 2023 - 2025 CondationCMS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ +import { createForm } from '@cms/modules/form/forms.js'; +import { showToast } from '@cms/modules/toast.js'; +import { getPreviewUrl, reloadPreview } from '@cms/modules/preview.utils.js'; +import { buildValuesFromFields, getValueByPath } from '@cms/modules/node.js'; +import { getContentNode, getContent, setMeta } from '@cms/modules/rpc/rpc-content.js'; +import { i18n } from '@cms/modules/localization.js'; +import { openSidebar } from '@cms/modules/sidebar.js'; +import { getPageTemplates, getSectionTemplates } from '@cms/modules/rpc/rpc-manager'; +// hook.js +export async function runAction(params) { + var uri = null; + if (params.uri) { + uri = params.uri; + } + else { + const contentNode = await getContentNode({ + url: getPreviewUrl() + }); + uri = contentNode.result.uri; + } + const getContentResponse = await getContent({ + uri: uri + }); + var templates = null; + if (params.type === "section") { + templates = (await getSectionTemplates()).result; + } + else { + templates = (await getPageTemplates()).result; + } + var selected = templates.filter(item => item.template === getContentResponse?.result?.meta?.template); + var attrForm = []; + if (selected.length === 1) { + attrForm = selected[0].data?.forms[params.form] ? selected[0].data.forms[params.form].fields : []; + } + //const previewMetaForm = getMetaForm() + const fields = [ + ...attrForm + ]; + const values = { + ...buildValuesFromFields(attrForm, getContentResponse?.result?.meta) + }; + const form = createForm({ + fields: fields, + values: values + }); + openSidebar({ + title: 'Edit meta attribute', + body: 'modal body', + form: form, + resizable: true, + onCancel: (event) => { }, + onOk: async (event) => { + var updateData = form.getData(); + var setMetaResponse = await setMeta({ + uri: uri, + meta: updateData + }); + showToast({ + title: i18n.t('manager.actions.page.edit-metaattribute-list.toast.title', "MetaData updated"), + message: i18n.t('manager.actions.page.edit-metaattribute-list.toast.message', "The metadata has been updated successfully."), + type: 'success', // optional: info | success | warning | error + timeout: 3000 + }); + reloadPreview(); + } + }); +} diff --git a/modules/ui-module/src/main/ts/dist/actions/page/edit-page-settings.js b/modules/ui-module/src/main/ts/dist/actions/page/edit-page-settings.js index 137b52462..c82699cb9 100644 --- a/modules/ui-module/src/main/ts/dist/actions/page/edit-page-settings.js +++ b/modules/ui-module/src/main/ts/dist/actions/page/edit-page-settings.js @@ -66,7 +66,7 @@ export async function runAction(params) { var selected = pageTemplates.filter(pageTemplate => pageTemplate.template === getContentResponse?.result?.meta?.template); var pageSettingsForm = []; if (selected.length === 1) { - pageSettingsForm = selected[0].data?.forms?.settings ? selected[0].data.forms.settings : []; + pageSettingsForm = selected[0].data?.forms?.settings ? selected[0].data.forms.settings.fields : []; } //const previewMetaForm = getMetaForm() const fields = [ diff --git a/modules/ui-module/src/main/ts/dist/js/modules/form/field.list.js b/modules/ui-module/src/main/ts/dist/js/modules/form/field.list.js index 821bbb62b..df9fe8522 100644 --- a/modules/ui-module/src/main/ts/dist/js/modules/form/field.list.js +++ b/modules/ui-module/src/main/ts/dist/js/modules/form/field.list.js @@ -105,12 +105,12 @@ const getItemForm = async (el) => { const fieldName = listContainer?.getAttribute('name'); var itemForm = []; if (selected.length === 1) { - itemForm = (fieldName && selected[0].data?.forms[fieldName]) ? selected[0].data.forms[fieldName] : []; + itemForm = (fieldName && selected[0].data?.forms[fieldName]) ? selected[0].data.forms[fieldName].fields : []; } if (!itemForm || itemForm.length === 0) { let itemTypes = (await getListItemTypes({})).result; var selectedItemType = itemTypes.filter(itemType => itemType.name === fieldName); - itemForm = (selectedItemType.length === 1) ? selectedItemType[0].data?.form : []; + itemForm = (selectedItemType.length === 1) ? selectedItemType[0].data?.form.fields : []; } return itemForm; }; diff --git a/modules/ui-module/src/main/ts/dist/js/modules/form/field.markdown.js b/modules/ui-module/src/main/ts/dist/js/modules/form/field.markdown.js index 2062a839b..7075a136b 100644 --- a/modules/ui-module/src/main/ts/dist/js/modules/form/field.markdown.js +++ b/modules/ui-module/src/main/ts/dist/js/modules/form/field.markdown.js @@ -30,7 +30,7 @@ const createMarkdownField = (options, value = '') => { const key = "field." + options.name; const title = i18n.t(key, options.title); return ` -
+
diff --git a/modules/ui-module/src/main/ts/dist/js/modules/manager/manager.message.handlers.js b/modules/ui-module/src/main/ts/dist/js/modules/manager/manager.message.handlers.js index 56c78f683..9e84ad7ea 100644 --- a/modules/ui-module/src/main/ts/dist/js/modules/manager/manager.message.handlers.js +++ b/modules/ui-module/src/main/ts/dist/js/modules/manager/manager.message.handlers.js @@ -47,12 +47,14 @@ const initMessageHandlers = () => { } else if (payload.element === "meta" && payload.editor === "form") { var cmd = { - "module": window.manager.baseUrl + "/actions/page/edit-metaattribute-list", + "module": window.manager.baseUrl + "/actions/page/edit-metaattribute-form", "function": "runAction", "parameters": { "editor": payload.editor, "attributes": payload.metaElements, - "options": payload.options ? payload.options : {} + "options": payload.options ? payload.options : {}, + "form": payload.form, + "type": payload.type } }; if (payload.uri) { diff --git a/modules/ui-module/src/main/ts/dist/js/modules/manager/toolbar.inject.js b/modules/ui-module/src/main/ts/dist/js/modules/manager/toolbar.inject.js index 1add24372..a6b68dee4 100644 --- a/modules/ui-module/src/main/ts/dist/js/modules/manager/toolbar.inject.js +++ b/modules/ui-module/src/main/ts/dist/js/modules/manager/toolbar.inject.js @@ -68,25 +68,31 @@ const editAttributes = (event) => { type: 'edit', payload: { editor: "form", - element: "meta" + element: "meta", + form: toolbarDefinition.form ? toolbarDefinition.form : "attributes", + type: toolbarDefinition.type } }; if (toolbarDefinition.uri) { command.payload.uri = toolbarDefinition.uri; } - var elements = []; - toolbar.parentNode.querySelectorAll("[data-cms-editor]").forEach(($elem) => { + // legay old style to collect all meta elements for the form editor + /* + var elements = [] + toolbar.parentNode.querySelectorAll("[data-cms-editor]").forEach(($elem : HTMLElement) => { var toolbar = $elem.dataset.cmsToolbar ? JSON.parse($elem.dataset.cmsToolbar) : {}; if ($elem.dataset.cmsElement === "meta" - && (!toolbar.id || toolbar.id === toolbarDefinition.id)) { + && (!toolbar.id || toolbar.id === toolbarDefinition.id) + ) { elements.push({ name: $elem.dataset.cmsMetaElement, editor: $elem.dataset.cmsEditor, options: $elem.dataset.cmsEditorOptions ? JSON.parse($elem.dataset.cmsEditorOptions) : {} - }); + }) } - }); - command.payload.metaElements = elements; + }) + command.payload.metaElements = elements + */ frameMessenger.send(window.parent, command); }; export const initToolbar = (container) => { diff --git a/modules/ui-module/src/main/ts/dist/js/modules/rpc/rpc-manager.js b/modules/ui-module/src/main/ts/dist/js/modules/rpc/rpc-manager.js index 57b80c7c2..45ac86fc6 100644 --- a/modules/ui-module/src/main/ts/dist/js/modules/rpc/rpc-manager.js +++ b/modules/ui-module/src/main/ts/dist/js/modules/rpc/rpc-manager.js @@ -23,35 +23,35 @@ import { executeRemoteCall } from '@cms/modules/rpc/rpc.js'; const getSectionTemplates = async (options) => { var data = { method: "manager.contentTypes.sections", - parameters: options + parameters: options || {} }; return await executeRemoteCall(data); }; const getPageTemplates = async (options) => { var data = { method: "manager.contentTypes.pages", - parameters: options + parameters: options || {} }; return await executeRemoteCall(data); }; const getListItemTypes = async (options) => { var data = { method: "manager.contentTypes.listItemTypes", - parameters: options + parameters: options || {} }; return await executeRemoteCall(data); }; const getMediaForm = async (options) => { var data = { method: "manager.media.form", - parameters: options + parameters: options || {} }; return await executeRemoteCall(data); }; const createCSRFToken = async (options) => { var data = { method: "manager.token.createCSRF", - parameters: options + parameters: options || {} }; return await executeRemoteCall(data); }; diff --git a/modules/ui-module/src/main/ts/src/actions/page/edit-metaattribute-form.js b/modules/ui-module/src/main/ts/src/actions/page/edit-metaattribute-form.js new file mode 100644 index 000000000..f225bcd1f --- /dev/null +++ b/modules/ui-module/src/main/ts/src/actions/page/edit-metaattribute-form.js @@ -0,0 +1,100 @@ +/*- + * #%L + * ui-module + * %% + * Copyright (C) 2023 - 2025 CondationCMS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ +import {createForm} from '@cms/modules/form/forms.js' +import {showToast} from '@cms/modules/toast.js' +import {getPreviewUrl, reloadPreview} from '@cms/modules/preview.utils.js' +import { buildValuesFromFields, getValueByPath } from '@cms/modules/node.js' +import {getContentNode, getContent, setMeta} from '@cms/modules/rpc/rpc-content.js' +import { i18n } from '@cms/modules/localization.js' +import { openSidebar } from '@cms/modules/sidebar.js' +import { getPageTemplates, getSectionTemplates } from '@cms/modules/rpc/rpc-manager' + // hook.js +export async function runAction(params) { + + + var uri = null + if (params.uri) { + uri = params.uri + } else { + const contentNode = await getContentNode({ + url: getPreviewUrl() + }) + uri = contentNode.result.uri + } + + const getContentResponse = await getContent({ + uri: uri + }) + + var templates = null + + if (params.type === "section") { + templates = (await getSectionTemplates()).result + } else { + templates = (await getPageTemplates()).result + } + + var selected = templates.filter(item => item.template === getContentResponse?.result?.meta?.template) + + var attrForm = [] + if (selected.length === 1) { + attrForm = selected[0].data?.forms[params.form] ? selected[0].data.forms[params.form].fields : [] + } + + //const previewMetaForm = getMetaForm() + const fields = [ + ...attrForm + ] + + + const values = { + ...buildValuesFromFields(attrForm, getContentResponse?.result?.meta) + } + + + const form = createForm({ + fields: fields, + values: values + }); + + openSidebar({ + title: 'Edit meta attribute', + body: 'modal body', + form: form, + resizable: true, + onCancel: (event) => {}, + onOk: async (event) => { + var updateData = form.getData() + var setMetaResponse = await setMeta({ + uri: uri, + meta: updateData + }) + showToast({ + title: i18n.t('manager.actions.page.edit-metaattribute-list.toast.title', "MetaData updated"), + message: i18n.t('manager.actions.page.edit-metaattribute-list.toast.message', "The metadata has been updated successfully."), + type: 'success', // optional: info | success | warning | error + timeout: 3000 + }); + reloadPreview() + } + }); +} diff --git a/modules/ui-module/src/main/ts/src/actions/page/edit-page-settings.js b/modules/ui-module/src/main/ts/src/actions/page/edit-page-settings.js index 901ff3b78..7c95fb493 100644 --- a/modules/ui-module/src/main/ts/src/actions/page/edit-page-settings.js +++ b/modules/ui-module/src/main/ts/src/actions/page/edit-page-settings.js @@ -73,7 +73,7 @@ export async function runAction(params) { var pageSettingsForm = [] if (selected.length === 1) { - pageSettingsForm = selected[0].data?.forms?.settings ? selected[0].data.forms.settings : [] + pageSettingsForm = selected[0].data?.forms?.settings ? selected[0].data.forms.settings.fields : [] } //const previewMetaForm = getMetaForm() diff --git a/modules/ui-module/src/main/ts/src/js/modules/form/field.list.ts b/modules/ui-module/src/main/ts/src/js/modules/form/field.list.ts index 5f1fef524..bb8648aef 100644 --- a/modules/ui-module/src/main/ts/src/js/modules/form/field.list.ts +++ b/modules/ui-module/src/main/ts/src/js/modules/form/field.list.ts @@ -130,14 +130,14 @@ const getItemForm = async (el: HTMLElement) => { var itemForm = [] if (selected.length === 1) { - itemForm = (fieldName && selected[0].data?.forms[fieldName]) ? selected[0].data.forms[fieldName] : []; + itemForm = (fieldName && selected[0].data?.forms[fieldName]) ? selected[0].data.forms[fieldName].fields : []; } if (!itemForm || itemForm.length === 0) { let itemTypes = (await getListItemTypes({})).result var selectedItemType = itemTypes.filter(itemType => itemType.name === fieldName) - itemForm = (selectedItemType.length === 1) ? selectedItemType[0].data?.form : [] + itemForm = (selectedItemType.length === 1) ? selectedItemType[0].data?.form.fields : [] } return itemForm diff --git a/modules/ui-module/src/main/ts/src/js/modules/form/field.markdown.ts b/modules/ui-module/src/main/ts/src/js/modules/form/field.markdown.ts index ed228e452..277e62878 100644 --- a/modules/ui-module/src/main/ts/src/js/modules/form/field.markdown.ts +++ b/modules/ui-module/src/main/ts/src/js/modules/form/field.markdown.ts @@ -44,7 +44,7 @@ const createMarkdownField = (options: MarkdownFieldOptions, value: string = '') const key = "field." + options.name const title = i18n.t(key, options.title) return ` -
+
diff --git a/modules/ui-module/src/main/ts/src/js/modules/manager/manager.message.handlers.ts b/modules/ui-module/src/main/ts/src/js/modules/manager/manager.message.handlers.ts index bab710244..9b0d6cede 100644 --- a/modules/ui-module/src/main/ts/src/js/modules/manager/manager.message.handlers.ts +++ b/modules/ui-module/src/main/ts/src/js/modules/manager/manager.message.handlers.ts @@ -51,12 +51,14 @@ const initMessageHandlers = () => { executeScriptAction(cmd) } else if (payload.element === "meta" && payload.editor === "form") { var cmd: any = { - "module": window.manager.baseUrl + "/actions/page/edit-metaattribute-list", - "function": "runAction", - "parameters": { - "editor": payload.editor, - "attributes": payload.metaElements, - "options": payload.options ? payload.options : {} + "module" : window.manager.baseUrl + "/actions/page/edit-metaattribute-form", + "function" : "runAction", + "parameters" : { + "editor" : payload.editor, + "attributes" : payload.metaElements, + "options" : payload.options ? payload.options : {}, + "form" : payload.form, + "type" : payload.type } } if (payload.uri) { diff --git a/modules/ui-module/src/main/ts/src/js/modules/manager/toolbar.inject.ts b/modules/ui-module/src/main/ts/src/js/modules/manager/toolbar.inject.ts index bc28644b5..7ed81b955 100644 --- a/modules/ui-module/src/main/ts/src/js/modules/manager/toolbar.inject.ts +++ b/modules/ui-module/src/main/ts/src/js/modules/manager/toolbar.inject.ts @@ -83,12 +83,16 @@ const editAttributes = (event: Event) => { type: 'edit', payload: { editor: "form", - element: "meta" + element: "meta", + form: toolbarDefinition.form ? toolbarDefinition.form : "attributes", + type: toolbarDefinition.type } } if (toolbarDefinition.uri) { command.payload.uri = toolbarDefinition.uri; } + // legay old style to collect all meta elements for the form editor + /* var elements = [] toolbar.parentNode.querySelectorAll("[data-cms-editor]").forEach(($elem : HTMLElement) => { var toolbar = $elem.dataset.cmsToolbar ? JSON.parse($elem.dataset.cmsToolbar) : {}; @@ -103,6 +107,7 @@ const editAttributes = (event: Event) => { } }) command.payload.metaElements = elements + */ frameMessenger.send(window.parent, command); } diff --git a/modules/ui-module/src/main/ts/src/js/modules/rpc/rpc-manager.ts b/modules/ui-module/src/main/ts/src/js/modules/rpc/rpc-manager.ts index 2aa68bc3e..c43cf7e5f 100644 --- a/modules/ui-module/src/main/ts/src/js/modules/rpc/rpc-manager.ts +++ b/modules/ui-module/src/main/ts/src/js/modules/rpc/rpc-manager.ts @@ -25,7 +25,7 @@ import { executeRemoteCall } from '@cms/modules/rpc/rpc.js' const getSectionTemplates = async (options : any) => { var data = { method: "manager.contentTypes.sections", - parameters: options + parameters: options || {} } return await executeRemoteCall(data); }; @@ -33,7 +33,7 @@ const getSectionTemplates = async (options : any) => { const getPageTemplates = async (options : any) => { var data = { method: "manager.contentTypes.pages", - parameters: options + parameters: options || {} } return await executeRemoteCall(data); }; @@ -41,7 +41,7 @@ const getPageTemplates = async (options : any) => { const getListItemTypes = async (options : any) => { var data = { method: "manager.contentTypes.listItemTypes", - parameters: options + parameters: options || {} } return await executeRemoteCall(data); }; @@ -49,7 +49,7 @@ const getListItemTypes = async (options : any) => { const getMediaForm = async (options : any) => { var data = { method: "manager.media.form", - parameters: options + parameters: options || {} } return await executeRemoteCall(data); }; @@ -57,7 +57,7 @@ const getMediaForm = async (options : any) => { const createCSRFToken = async (options : any) => { var data = { method: "manager.token.createCSRF", - parameters: options + parameters: options || {} } return await executeRemoteCall(data); }; diff --git a/test-server/hosts/demo/content/index.asection.bla.md b/test-server/hosts/demo/content/index.asection.bla.md index 622c87dfb..fba0b7f06 100644 --- a/test-server/hosts/demo/content/index.asection.bla.md +++ b/test-server/hosts/demo/content/index.asection.bla.md @@ -3,7 +3,7 @@ title: Startseite template: section.html search: index: false -description: my new descritpion for that awesome section +description: my new descritpion for that awesome section-lol parent: text: text for a section layout: @@ -18,9 +18,10 @@ object: - title: New Item description: asdads features: export -about: '' +about: its all about content unpublish_date: null publish_date: null +about1: more content more better --- # This is a section: bla diff --git a/test-server/hosts/demo/content/index.md b/test-server/hosts/demo/content/index.md index a7de7ea04..6d604cc38 100644 --- a/test-server/hosts/demo/content/index.md +++ b/test-server/hosts/demo/content/index.md @@ -7,7 +7,7 @@ published: true description: Thats awesome 1234 parent: text: another text for the meta attribute , seems to work -count: 18 +count: 20 background_color: '#c2e0c6' range_test: 42 choose_color: green diff --git a/test-server/themes/demo/extensions/theme.manager.js b/test-server/themes/demo/extensions/theme.manager.js index 237d10f57..f7298e066 100644 --- a/test-server/themes/demo/extensions/theme.manager.js +++ b/test-server/themes/demo/extensions/theme.manager.js @@ -14,98 +14,154 @@ $hooks.registerFilter("manager/media/forms", (context) => { return mediaForms; }) +const TextField = (overrides = {}) => ({ + type: "text", + ...overrides +}); + +const TitleField = TextField({ + name: "title", + title: "Title", +}); +const DescriptionField = TextField({ + name: "description", + title: "Description", +}); +const PublishDateField = { + type: "datetime", + name: "publish_date", + title: "Publish Date", +}; +const UnPublishDateField = { + type: "datetime", + name: "unpublish_date", + title: "Unpublish Date", +}; + + $hooks.registerFilter("manager/contentTypes/register", (context) => { var contentTypes = context.value(); contentTypes.registerPageTemplate({ name: "StartPage", template: "start.html", forms: { - settings: [ - { - type: 'divider', - name: 'divider', - title: 'Custom attributes' - }, - { - type: "reference", - name: "linked_page", - title: "Verlinkte Seite" - }, - { - type: "textarea", - name: "seo.description", - title: "Seo Beschreibung" - }, - { - type: "media", - name: "media_url", - title: "Media" - }, - { - type: 'color', - name: 'background_color', - title: 'Background Color' - }, - { - type: "range", - name: "range_test", - title: "RangField" - }, - { - type: "radio", - name: "choose_color", - title: "Farbe wählen", - options: { - choices: [ - { label: "Rot", value: "red" }, - { label: "Grün", value: "green" }, - { label: "Blau", value: "blue" } - ] - } - }, - { - name: "features", - title: "Funktionen auswählen", - type: "checkbox", - options: { - choices: [ - { label: "Suche", value: "search" }, - { label: "Filter", value: "filter" }, - { label: "Export", value: "export" } - ] - } - }, - { - name: "object.values", - title: "Objekt-Liste", - type: "list" - } - ], + settings: { + fields: + + [ + { + type: 'divider', + name: 'divider', + title: 'Custom attributes' + }, + { + type: "reference", + name: "linked_page", + title: "Verlinkte Seite" + }, + { + type: "textarea", + name: "seo.description", + title: "Seo Beschreibung" + }, + { + type: "media", + name: "media_url", + title: "Media" + }, + { + type: 'color', + name: 'background_color', + title: 'Background Color' + }, + { + type: "range", + name: "range_test", + title: "RangField" + }, + { + type: "radio", + name: "choose_color", + title: "Farbe wählen", + options: { + choices: [ + { label: "Rot", value: "red" }, + { label: "Grün", value: "green" }, + { label: "Blau", value: "blue" } + ] + } + }, + { + name: "features", + title: "Funktionen auswählen", + type: "checkbox", + options: { + choices: [ + { label: "Suche", value: "search" }, + { label: "Filter", value: "filter" }, + { label: "Export", value: "export" } + ] + } + }, + { + name: "object.values", + title: "Objekt-Liste", + type: "list" + } + ] + }, // override global definition of ListItemTypes - 'object.values': [ - { - name: "title", - title: "Title", - type: "text" - }, - { - name: "description", - title: "Description", - type: "text" - }, - { - name: "features", - title: "Funktionen auswählen", - type: "select", - options: { - choices: [ - { label: "Suche", value: "search" }, - { label: "Filter", value: "filter" }, - { label: "Export", value: "export" } - ] + 'object.values': { + fields: [ + TitleField, + DescriptionField, + { + name: "features", + title: "Funktionen auswählen", + type: "select", + options: { + choices: [ + { label: "Suche", value: "search" }, + { label: "Filter", value: "filter" }, + { label: "Export", value: "export" } + ] + } + }, + ] + }, + 'attributes': { + fields: [ + { + name: "parent.text", + title: "Parent Text", + type: "text" } - }, - ] + ] + }, + 'top': { + fields: [ + { + name: "parent.text", + title: "Parent Text", + type: "text" + }, + { + name: "description", + title: "Description", + type: "text" + }, + { + name: "count", + type: "number", + title: "Anzahl", + options: { + min: 10, + max: 50, + step: 1 + } + } + ] + } } }); @@ -116,7 +172,44 @@ $hooks.registerFilter("manager/contentTypes/register", (context) => { contentTypes.registerSectionTemplate({ section: "asection", name: "SectionTemplate", - template: "section.html" + template: "section.html", + forms: { + attributes: { + fields: [ + TitleField, + DescriptionField, + PublishDateField, + UnPublishDateField, + { + type: "list", + name: "object.values", + title: "Object list", + options: { + nameField: "title" + } + }, + { + type: "text", + name: "parent.text", + title: "Parent Text" + }, + { + type: "markdown", + name: "about", + title: "About" + }, + { + type: "divider", + title: "Additional Information" + }, + { + type: "markdown", + name: "about1", + title: "About1" + } + ] + } + } }); /* @@ -124,18 +217,20 @@ $hooks.registerFilter("manager/contentTypes/register", (context) => { */ contentTypes.registerListItemType({ name: "object.values", - form: [ - { - name: "name", - title: "Name", - type: "text" - }, - { - name: "description", - title: "Description", - type: "text" - } - ] + form: { + fields: [ + { + name: "name", + title: "Name", + type: "text" + }, + { + name: "description", + title: "Description", + type: "text" + } + ] + } }); return contentTypes; diff --git a/test-server/themes/demo/templates/section.html b/test-server/themes/demo/templates/section.html index 1bc5d8d4e..cb525b24d 100644 --- a/test-server/themes/demo/templates/section.html +++ b/test-server/themes/demo/templates/section.html @@ -1,26 +1,21 @@
+ node.uri, "form": "attributes"}) | raw }}>
{{ node.content | default('your content here') | raw}}
-
-
-
-
-
-
+
{{ node.meta.getOrDefault('description', 'description here')}}
-
+
{{ node.meta.getOrDefault('parent.text', 'Parent.Text here')}}
-
+
{{ cms.markdown.render(node.meta.getOrDefault('about', '--about--')) | raw}}
-
+
{{ cms.markdown.render(node.meta.getOrDefault('about1', '--about1--')) | raw}}
diff --git a/test-server/themes/demo/templates/start.html b/test-server/themes/demo/templates/start.html index e2f6bfc21..371959b5d 100644 --- a/test-server/themes/demo/templates/start.html +++ b/test-server/themes/demo/templates/start.html @@ -17,7 +17,7 @@ {% include "libs/language_switcher.html" %}
{{ node.content | raw }}