Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 43 additions & 16 deletions cms-api/src/main/java/com/condation/cms/api/utils/HTTPUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public static String appendPreviewParameter(String url, final FeatureContainer f

return url + fragment;
}

/**
* Adds the context according to the siteproperties and the preview to an
* url
Expand All @@ -77,33 +77,60 @@ public static String appendPreviewParameter(String url, final FeatureContainer f
*/
public static String modifyUrl(String url, final FeatureContainer featureContainer) {

// is external url
if (url.startsWith("http") || url.startsWith("https")) {
// Externe URL
if (url.startsWith("http://") || url.startsWith("https://")) {
return url;
}

// Fragment (#...) abtrennen, falls vorhanden
// Fragment (#...) abtrennen
String fragment = "";
int fragmentIndex = url.indexOf('#');
if (fragmentIndex >= 0) {
fragment = url.substring(fragmentIndex); // inkl. #
fragment = url.substring(fragmentIndex);
url = url.substring(0, fragmentIndex);
}

url = prependContext(url, featureContainer.get(SitePropertiesFeature.class).siteProperties());
url = prependContext(
url,
featureContainer.get(SitePropertiesFeature.class).siteProperties()
);

if (featureContainer.has(IsPreviewFeature.class)
&& !hasQueryParameter(url, "preview")) {

if (featureContainer.has(IsPreviewFeature.class)) {
var feature = featureContainer.get(IsPreviewFeature.class);
if (url.contains("?")) {
url += "&preview=" + feature.mode().getValue();
} else {
url += "?preview=" + feature.mode().getValue();
}

url += url.contains("?")
? "&preview=" + feature.mode().getValue()
: "?preview=" + feature.mode().getValue();
}

return url + fragment;
}

private static boolean hasQueryParameter(String url, String parameterName) {
int queryStart = url.indexOf('?');

if (queryStart < 0) {
return false;
}

String query = url.substring(queryStart + 1);

for (String parameter : query.split("&")) {
int equalsIndex = parameter.indexOf('=');
String name = equalsIndex >= 0
? parameter.substring(0, equalsIndex)
: parameter;

if (parameterName.equals(name)) {
return true;
}
}

return false;
}

/**
* Adds the context according to the siteproperties to an url
*
Expand All @@ -126,10 +153,10 @@ public static String prependContext(String url, final SiteProperties sitePropert
url = contextPath + url;
}

if (!url.startsWith("/")) {
url = "/" + url;
}
if (!url.startsWith("/")) {
url = "/" + url;
}

return url;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import { executeScriptAction } from '@cms/js/manager-globals.js';
import frameMessenger from '@cms/modules/frameMessenger.js';
import { getPreviewFrame, getPreviewUrl } from '@cms/modules/preview.utils.js';
import { getContentNode } from '@cms/modules/rpc/rpc-content.js';
import { getContentNode, setMetaBatch } from '@cms/modules/rpc/rpc-content.js';
const executeImageForm = (payload) => {
const cmd = {
"module": window.manager.baseUrl + "/actions/media/edit-media-form",
Expand Down Expand Up @@ -190,5 +190,8 @@ const initMessageHandlers = () => {
var previewFrame = getPreviewFrame();
frameMessenger.send(previewFrame.contentWindow, message);
});
frameMessenger.on('sort-sections', async (payload) => {
await setMetaBatch({ updates: payload.updates });
});
};
export { initMessageHandlers };
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ export declare const IMAGE_ICON = "\n<svg xmlns=\"http://www.w3.org/2000/svg\" w
export declare const SECTION_PUBLISHED_ICON = "\n<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-eye-fill\" viewBox=\"0 0 16 16\">\n <path d=\"M10.5 8a2.5 2.5 0 1 1-5 0 2.5 2.5 0 0 1 5 0\"/>\n <path d=\"M0 8s3-5.5 8-5.5S16 8 16 8s-3 5.5-8 5.5S0 8 0 8m8 3.5a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7\"/>\n</svg>\n";
export declare const SECTION_UNPUBLISHED_ICON = "\n<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-eye-slash-fill\" viewBox=\"0 0 16 16\">\n <path d=\"m10.79 12.912-1.614-1.615a3.5 3.5 0 0 1-4.474-4.474l-2.06-2.06C.938 6.278 0 8 0 8s3 5.5 8 5.5a7 7 0 0 0 2.79-.588M5.21 3.088A7 7 0 0 1 8 2.5c5 0 8 5.5 8 5.5s-.939 1.721-2.641 3.238l-2.062-2.062a3.5 3.5 0 0 0-4.474-4.474z\"/>\n <path d=\"M5.525 7.646a2.5 2.5 0 0 0 2.829 2.829zm4.95.708-2.829-2.83a2.5 2.5 0 0 1 2.829 2.829zm3.171 6-12-12 .708-.708 12 12z\"/>\n</svg>\n";
export declare const MEDIA_CROP_ICON = "\n<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-crop\" viewBox=\"0 0 16 16\">\n <path d=\"M3.5.5A.5.5 0 0 1 4 1v13h13a.5.5 0 0 1 0 1h-2v2a.5.5 0 0 1-1 0v-2H3.5a.5.5 0 0 1-.5-.5V4H1a.5.5 0 0 1 0-1h2V1a.5.5 0 0 1 .5-.5m2.5 3a.5.5 0 0 1 .5-.5h8a.5.5 0 0 1 .5.5v8a.5.5 0 0 1-1 0V4H6.5a.5.5 0 0 1-.5-.5\"/>\n</svg>\n";
export declare const MOVE_ICON = "\n<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-arrows-move\" viewBox=\"0 0 16 16\">\n <path fill-rule=\"evenodd\" d=\"M7.646.146a.5.5 0 0 1 .708 0l2 2a.5.5 0 0 1-.708.708L8.5 1.707V5.5a.5.5 0 0 1-1 0V1.707L6.354 2.854a.5.5 0 1 1-.708-.708zM8 10a.5.5 0 0 1 .5.5v3.793l1.146-1.147a.5.5 0 0 1 .708.708l-2 2a.5.5 0 0 1-.708 0l-2-2a.5.5 0 0 1 .708-.708L7.5 14.293V10.5A.5.5 0 0 1 8 10M.146 8.354a.5.5 0 0 1 0-.708l2-2a.5.5 0 1 1 .708.708L1.707 7.5H5.5a.5.5 0 0 1 0 1H1.707l1.147 1.146a.5.5 0 0 1-.708.708zM10 8a.5.5 0 0 1 .5-.5h3.793l-1.147-1.146a.5.5 0 0 1 .708-.708l2 2a.5.5 0 0 1 0 .708l-2 2a.5.5 0 0 1-.708-.708L14.293 8.5H10.5A.5.5 0 0 1 10 8\"/>\n</svg>\n";
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,8 @@ export const MEDIA_CROP_ICON = `
<path d="M3.5.5A.5.5 0 0 1 4 1v13h13a.5.5 0 0 1 0 1h-2v2a.5.5 0 0 1-1 0v-2H3.5a.5.5 0 0 1-.5-.5V4H1a.5.5 0 0 1 0-1h2V1a.5.5 0 0 1 .5-.5m2.5 3a.5.5 0 0 1 .5-.5h8a.5.5 0 0 1 .5.5v8a.5.5 0 0 1-1 0V4H6.5a.5.5 0 0 1-.5-.5"/>
</svg>
`;
export const MOVE_ICON = `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrows-move" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M7.646.146a.5.5 0 0 1 .708 0l2 2a.5.5 0 0 1-.708.708L8.5 1.707V5.5a.5.5 0 0 1-1 0V1.707L6.354 2.854a.5.5 0 1 1-.708-.708zM8 10a.5.5 0 0 1 .5.5v3.793l1.146-1.147a.5.5 0 0 1 .708.708l-2 2a.5.5 0 0 1-.708 0l-2-2a.5.5 0 0 1 .708-.708L7.5 14.293V10.5A.5.5 0 0 1 8 10M.146 8.354a.5.5 0 0 1 0-.708l2-2a.5.5 0 1 1 .708.708L1.707 7.5H5.5a.5.5 0 0 1 0 1H1.707l1.147 1.146a.5.5 0 0 1-.708.708zM10 8a.5.5 0 0 1 .5-.5h3.793l-1.147-1.146a.5.5 0 0 1 .708-.708l2 2a.5.5 0 0 1 0 .708l-2 2a.5.5 0 0 1-.708-.708L14.293 8.5H10.5A.5.5 0 0 1 10 8"/>
</svg>
`;
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
* #L%
*/
import frameMessenger from "@cms/modules/frameMessenger.js";
import { EDIT_ATTRIBUTES_ICON, EDIT_PAGE_ICON, SECTION_ADD_ICON, SECTION_DELETE_ICON, SECTION_SORT_ICON, SECTION_UNPUBLISHED_ICON } from "@cms/modules/manager/toolbar-icons";
import { EDIT_ATTRIBUTES_ICON, EDIT_PAGE_ICON, MOVE_ICON, SECTION_ADD_ICON, SECTION_DELETE_ICON, SECTION_SORT_ICON, SECTION_UNPUBLISHED_ICON } from "@cms/modules/manager/toolbar-icons";
const addSection = (event) => {
var toolbar = event.target.closest('[data-cms-toolbar]');
var toolbarDefinition = JSON.parse(toolbar.dataset.cmsToolbar || '{}');
Expand Down Expand Up @@ -115,6 +115,194 @@ const editAttributes = (event) => {
*/
frameMessenger.send(window.parent, command);
};
const initDragDrop = (container) => {
if (container.dataset.cmsDragDropInitialized === 'true') {
return;
}
const draggableItems = Array.from(container.querySelectorAll(':scope > .cms-ui-editable-sections'));
if (draggableItems.length === 0) {
return;
}
container.dataset.cmsDragDropInitialized = 'true';
let draggedEl = null;
let placeholder = null;
let dragItems = [];
let pendingDragPosition = null;
let dragOverFrame = 0;
const keepPlaceholderPosition = Symbol('keepPlaceholderPosition');
const createPlaceholder = (item) => {
const nextPlaceholder = document.createElement('div');
nextPlaceholder.setAttribute('data-cms-drag-placeholder', '');
const cs = getComputedStyle(item);
nextPlaceholder.style.width = item.offsetWidth + 'px';
nextPlaceholder.style.height = item.offsetHeight + 'px';
nextPlaceholder.style.margin = cs.margin;
nextPlaceholder.style.border = '2px dashed #aaa';
nextPlaceholder.style.boxSizing = 'border-box';
nextPlaceholder.style.opacity = '0.5';
nextPlaceholder.style.pointerEvents = 'none';
nextPlaceholder.style.flexShrink = cs.flexShrink;
nextPlaceholder.style.flexGrow = cs.flexGrow;
nextPlaceholder.style.flexBasis = cs.flexBasis;
return nextPlaceholder;
};
const resetDragState = () => {
if (dragOverFrame) {
cancelAnimationFrame(dragOverFrame);
dragOverFrame = 0;
}
if (draggedEl) {
draggedEl.style.display = '';
draggedEl.setAttribute('draggable', 'false');
}
placeholder?.remove();
placeholder = null;
draggedEl = null;
dragItems = [];
pendingDragPosition = null;
};
const getDirectChildSectionEntry = (element) => {
const item = element?.closest('.cms-ui-editable-sections');
if (!item || item.parentElement !== container || item === draggedEl) {
return null;
}
return item;
};
const getInsertBeforeElement = (position) => {
if (!draggedEl || !placeholder) {
return keepPlaceholderPosition;
}
const targetItem = getDirectChildSectionEntry(document.elementFromPoint(position.clientX, position.clientY));
if (targetItem) {
const children = Array.from(container.children);
const placeholderIndex = children.indexOf(placeholder);
const targetIndex = children.indexOf(targetItem);
if (placeholderIndex > -1 && targetIndex > -1 && placeholderIndex < targetIndex) {
return targetItem.nextElementSibling;
}
return targetItem;
}
return keepPlaceholderPosition;
};
const updatePlaceholderPosition = () => {
dragOverFrame = 0;
if (!placeholder || !pendingDragPosition) {
return;
}
const insertBeforeEl = getInsertBeforeElement(pendingDragPosition);
if (insertBeforeEl === keepPlaceholderPosition) {
return;
}
if (insertBeforeEl === null) {
if (placeholder.nextElementSibling !== null) {
container.appendChild(placeholder);
}
return;
}
if (insertBeforeEl !== placeholder && placeholder.nextElementSibling !== insertBeforeEl) {
container.insertBefore(placeholder, insertBeforeEl);
}
};
draggableItems.forEach((item) => {
if (item.dataset.cmsDragDropItemInitialized === 'true') {
return;
}
item.dataset.cmsDragDropItemInitialized = 'true';
item.setAttribute('draggable', 'false');
const itemToolbar = item.querySelector('.cms-ui-toolbar');
if (itemToolbar && !itemToolbar.querySelector('[data-cms-drag-handle]')) {
const handle = document.createElement('button');
handle.setAttribute('type', 'button');
handle.setAttribute('data-cms-drag-handle', '');
handle.setAttribute('title', 'Drag to reorder');
handle.setAttribute('aria-label', 'Drag to reorder');
handle.innerHTML = MOVE_ICON;
handle.style.cursor = 'grab';
handle.addEventListener('mousedown', (e) => {
if (e.button !== 0) {
return;
}
item.setAttribute('draggable', 'true');
document.addEventListener('mouseup', () => {
if (!draggedEl) {
item.setAttribute('draggable', 'false');
}
}, { once: true });
});
itemToolbar.appendChild(handle);
}
item.addEventListener('dragstart', (e) => {
if (item.getAttribute('draggable') !== 'true') {
e.preventDefault();
return;
}
draggedEl = item;
dragItems = Array.from(container.querySelectorAll(':scope > .cms-ui-editable-sections'));
e.dataTransfer?.setData('text/plain', '');
if (e.dataTransfer) {
e.dataTransfer.effectAllowed = 'move';
}
placeholder = createPlaceholder(item);
requestAnimationFrame(() => {
if (draggedEl && placeholder) {
container.insertBefore(placeholder, draggedEl);
draggedEl.style.display = 'none';
}
});
});
item.addEventListener('dragend', () => {
resetDragState();
});
});
container.addEventListener('dragover', (e) => {
e.preventDefault();
if (!draggedEl || !placeholder)
return;
pendingDragPosition = {
clientX: e.clientX,
clientY: e.clientY
};
if (!dragOverFrame) {
dragOverFrame = requestAnimationFrame(updatePlaceholderPosition);
}
});
container.addEventListener('drop', (e) => {
e.preventDefault();
if (!draggedEl || !placeholder)
return;
if (dragOverFrame) {
cancelAnimationFrame(dragOverFrame);
dragOverFrame = 0;
updatePlaceholderPosition();
}
const droppedEl = draggedEl;
container.insertBefore(draggedEl, placeholder);
placeholder.remove();
placeholder = null;
droppedEl.style.display = '';
droppedEl.setAttribute('draggable', 'false');
const items = Array.from(container.querySelectorAll(':scope > .cms-ui-editable-sections'));
const updates = items.map((el, index) => {
const toolbarData = el.dataset.cmsToolbar ? JSON.parse(el.dataset.cmsToolbar) : {};
return {
uri: toolbarData.uri,
meta: {
'layout.order': {
type: 'number',
value: index
}
}
};
}).filter(u => u.uri);
draggedEl = null;
dragItems = [];
pendingDragPosition = null;
frameMessenger.send(window.parent, {
type: 'sort-sections',
payload: { updates }
});
});
};
export const initToolbar = (container) => {
var toolbarDefinition = JSON.parse(container.dataset.cmsToolbar || '{}');
if (!toolbarDefinition.actions) {
Expand Down Expand Up @@ -184,6 +372,13 @@ export const initToolbar = (container) => {
button.addEventListener('click', deleteSection);
toolbar.appendChild(button);
}
else if (action === "dragSectionEntries") {
// Kein Button — DnD wird nach dem ersten Render-Frame initialisiert,
// damit alle sectionEntry-Toolbars bereits im DOM sind.
requestAnimationFrame(() => {
initDragDrop(container);
});
}
});
if (toolbarDefinition.type === "sectionEntry") {
const button = document.createElement('button');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import { executeScriptAction } from '@cms/js/manager-globals.js';
import frameMessenger from '@cms/modules/frameMessenger.js';
import { getPreviewFrame, getPreviewUrl } from '@cms/modules/preview.utils.js';
import { getContentNode } from '@cms/modules/rpc/rpc-content.js';
import { getContentNode, setMetaBatch } from '@cms/modules/rpc/rpc-content.js';
const executeImageForm = (payload) => {
const cmd = {
"module": window.manager.baseUrl + "/actions/media/edit-media-form",
Expand Down Expand Up @@ -190,5 +190,8 @@ const initMessageHandlers = () => {
var previewFrame = getPreviewFrame();
frameMessenger.send(previewFrame.contentWindow, message);
});
frameMessenger.on('sort-sections', async (payload) => {
await setMetaBatch({ updates: payload.updates });
});
};
export { initMessageHandlers };
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export declare const IMAGE_ICON = "\n<svg xmlns=\"http://www.w3.org/2000/svg\" w
export declare const SECTION_PUBLISHED_ICON = "\n<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-eye-fill\" viewBox=\"0 0 16 16\">\n <path d=\"M10.5 8a2.5 2.5 0 1 1-5 0 2.5 2.5 0 0 1 5 0\"/>\n <path d=\"M0 8s3-5.5 8-5.5S16 8 16 8s-3 5.5-8 5.5S0 8 0 8m8 3.5a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7\"/>\n</svg>\n";
export declare const SECTION_UNPUBLISHED_ICON = "\n<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-eye-slash-fill\" viewBox=\"0 0 16 16\">\n <path d=\"m10.79 12.912-1.614-1.615a3.5 3.5 0 0 1-4.474-4.474l-2.06-2.06C.938 6.278 0 8 0 8s3 5.5 8 5.5a7 7 0 0 0 2.79-.588M5.21 3.088A7 7 0 0 1 8 2.5c5 0 8 5.5 8 5.5s-.939 1.721-2.641 3.238l-2.062-2.062a3.5 3.5 0 0 0-4.474-4.474z\"/>\n <path d=\"M5.525 7.646a2.5 2.5 0 0 0 2.829 2.829zm4.95.708-2.829-2.83a2.5 2.5 0 0 1 2.829 2.829zm3.171 6-12-12 .708-.708 12 12z\"/>\n</svg>\n";
export declare const MEDIA_CROP_ICON = "\n<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-crop\" viewBox=\"0 0 16 16\">\n <path d=\"M3.5.5A.5.5 0 0 1 4 1v13h13a.5.5 0 0 1 0 1h-2v2a.5.5 0 0 1-1 0v-2H3.5a.5.5 0 0 1-.5-.5V4H1a.5.5 0 0 1 0-1h2V1a.5.5 0 0 1 .5-.5m2.5 3a.5.5 0 0 1 .5-.5h8a.5.5 0 0 1 .5.5v8a.5.5 0 0 1-1 0V4H6.5a.5.5 0 0 1-.5-.5\"/>\n</svg>\n";
export declare const MOVE_ICON = "\n<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-arrows-move\" viewBox=\"0 0 16 16\">\n <path fill-rule=\"evenodd\" d=\"M7.646.146a.5.5 0 0 1 .708 0l2 2a.5.5 0 0 1-.708.708L8.5 1.707V5.5a.5.5 0 0 1-1 0V1.707L6.354 2.854a.5.5 0 1 1-.708-.708zM8 10a.5.5 0 0 1 .5.5v3.793l1.146-1.147a.5.5 0 0 1 .708.708l-2 2a.5.5 0 0 1-.708 0l-2-2a.5.5 0 0 1 .708-.708L7.5 14.293V10.5A.5.5 0 0 1 8 10M.146 8.354a.5.5 0 0 1 0-.708l2-2a.5.5 0 1 1 .708.708L1.707 7.5H5.5a.5.5 0 0 1 0 1H1.707l1.147 1.146a.5.5 0 0 1-.708.708zM10 8a.5.5 0 0 1 .5-.5h3.793l-1.147-1.146a.5.5 0 0 1 .708-.708l2 2a.5.5 0 0 1 0 .708l-2 2a.5.5 0 0 1-.708-.708L14.293 8.5H10.5A.5.5 0 0 1 10 8\"/>\n</svg>\n";
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,8 @@ export const MEDIA_CROP_ICON = `
<path d="M3.5.5A.5.5 0 0 1 4 1v13h13a.5.5 0 0 1 0 1h-2v2a.5.5 0 0 1-1 0v-2H3.5a.5.5 0 0 1-.5-.5V4H1a.5.5 0 0 1 0-1h2V1a.5.5 0 0 1 .5-.5m2.5 3a.5.5 0 0 1 .5-.5h8a.5.5 0 0 1 .5.5v8a.5.5 0 0 1-1 0V4H6.5a.5.5 0 0 1-.5-.5"/>
</svg>
`;
export const MOVE_ICON = `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrows-move" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M7.646.146a.5.5 0 0 1 .708 0l2 2a.5.5 0 0 1-.708.708L8.5 1.707V5.5a.5.5 0 0 1-1 0V1.707L6.354 2.854a.5.5 0 1 1-.708-.708zM8 10a.5.5 0 0 1 .5.5v3.793l1.146-1.147a.5.5 0 0 1 .708.708l-2 2a.5.5 0 0 1-.708 0l-2-2a.5.5 0 0 1 .708-.708L7.5 14.293V10.5A.5.5 0 0 1 8 10M.146 8.354a.5.5 0 0 1 0-.708l2-2a.5.5 0 1 1 .708.708L1.707 7.5H5.5a.5.5 0 0 1 0 1H1.707l1.147 1.146a.5.5 0 0 1-.708.708zM10 8a.5.5 0 0 1 .5-.5h3.793l-1.147-1.146a.5.5 0 0 1 .708-.708l2 2a.5.5 0 0 1 0 .708l-2 2a.5.5 0 0 1-.708-.708L14.293 8.5H10.5A.5.5 0 0 1 10 8"/>
</svg>
`;
Loading
Loading