Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ private List<ContainerRaw> populateContainers() throws DotDataException, DotSecu
this.widgetPreExecute(contentlet);
this.addAccrueTags(contentlet);
this.addRelationships(contentlet);
this.addStyles(contentlet, personalizedContentlet);

if (personalizedContentlet.getPersonalization().equals(includeContentFor)) {

Expand Down Expand Up @@ -525,6 +526,28 @@ private void widgetPreExecute(final Contentlet contentlet) {
}
}

/**
* Only applies when the FEATURE_FLAG_UVE_STYLE_EDITOR is enabled.
* Adds style properties from the MultiTree to the contentlet's data map.
* This ensures that contentlet styling metadata is properly scoped to its specific
* personalization and variant context.
*
* @param contentlet The {@link Contentlet} to add style properties to
* @param personalizedContentlet The {@link PersonalizedContentlet} containing the style
* properties from the MultiTree relationship
*/
private void addStyles(Contentlet contentlet, PersonalizedContentlet personalizedContentlet) {
if (!Config.getBooleanProperty("FEATURE_FLAG_UVE_STYLE_EDITOR", false)) {
return;
}

final Map<String, Object> styleProperties = personalizedContentlet.getStyleProperties();

if (UtilMethods.isSet(styleProperties) && !styleProperties.isEmpty()) {
contentlet.getMap().put("styleProperties", styleProperties);
}
}

private boolean needParseContainerPrefix(final Container container, final String uniqueId) {
return !ParseContainer.isParserContainerUUID(uniqueId) &&
(templateLayout == null || !templateLayout.existsContainer(container, uniqueId));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,35 +84,70 @@ public PageContainerForm deserialize(final JsonParser jsonParser,

// Parse styleProperties for each contentlet (optional field)
final JsonNode stylePropertiesNode = jsonElement.get(STYLE_PROPERTIES_ATTRIBUTE_NAME);
if (stylePropertiesNode != null && stylePropertiesNode.isObject()) {
stylePropertiesNode.fields().forEachRemaining(entry -> {
final String contentletId = entry.getKey();
final JsonNode styleProps = entry.getValue();
if (styleProps != null && styleProps.isObject()) {
final Map<String, Object> propsMap = new HashMap<>();
styleProps.fields().forEachRemaining(prop -> {
final JsonNode propValue = prop.getValue();
// Handle different JSON value types
if (propValue.isTextual()) {
propsMap.put(prop.getKey(), propValue.asText());
} else if (propValue.isNumber()) {
propsMap.put(prop.getKey(), propValue.numberValue());
} else if (propValue.isBoolean()) {
propsMap.put(prop.getKey(), propValue.asBoolean());
} else {
propsMap.put(prop.getKey(), propValue.toString());
}
});
containerEntry.setStyleProperties(contentletId, propsMap);
}
});
if (UtilMethods.isSet(stylePropertiesNode) && stylePropertiesNode.isObject()) {
processStyleProperties(stylePropertiesNode, containerEntry);
}

entries.add(containerEntry);
}

return new PageContainerForm(entries, jsonNode.toString());
}

/**
* Processes the style properties for the container entry.
* It converts the JSON node to a Map<String, Object> and sets it to the container entry.
* @param stylePropertiesNode The JSON node containing the style properties.
* @param containerEntry The container entry to set the style properties.
*/
private void processStyleProperties(final JsonNode stylePropertiesNode, final ContainerEntry containerEntry) {
stylePropertiesNode.fields().forEachRemaining(entry -> {
final String contentletId = entry.getKey();
final JsonNode styleProps = entry.getValue();
if (styleProps != null && styleProps.isObject()) {
final Map<String, Object> propsMap = new HashMap<>();
styleProps.fields().forEachRemaining(prop -> {
final JsonNode propValue = prop.getValue();
propsMap.put(prop.getKey(), convertJsonNodeToObject(propValue));
});
containerEntry.setStyleProperties(contentletId, propsMap);
}
});
}

/**
* Recursively converts a JsonNode to its corresponding Java object type.
* Handles all JSON types: primitives, objects, arrays, and null.
*
* @param node The JsonNode to convert
* @return The converted Java object (String, Number, Boolean, Map, List, or null)
*/
private Object convertJsonNodeToObject(final JsonNode node) {
if (node == null || node.isNull()) {
return null;
} else if (node.isBoolean()) {
return node.asBoolean();
} else if (node.isInt()) {
return node.asInt();
} else if (node.isLong()) {
return node.asLong();
} else if (node.isDouble() || node.isFloat()) {
return node.asDouble();
} else if (node.isArray()) {
final List<Object> list = new ArrayList<>();
node.forEach(element -> list.add(convertJsonNodeToObject(element)));
return list;
} else if (node.isObject()) {
final Map<String, Object> map = new HashMap<>();
node.fields().forEachRemaining(entry ->
map.put(entry.getKey(), convertJsonNodeToObject(entry.getValue()))
);
return map;
} else {
// Fallback for any other type and String values
return node.asText();
}
}
}

/**
Expand Down
3 changes: 2 additions & 1 deletion dotCMS/src/main/java/com/dotmarketing/beans/MultiTree.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.dotmarketing.portlets.containers.model.Container;
import com.dotmarketing.portlets.contentlet.model.Contentlet;
import com.dotmarketing.portlets.htmlpageasset.model.HTMLPageAsset;
import com.dotmarketing.util.UtilMethods;
import com.fasterxml.jackson.annotation.JsonIgnore;
import java.util.Map;
import org.apache.commons.lang.builder.EqualsBuilder;
Expand Down Expand Up @@ -75,7 +76,7 @@ public MultiTree(final String htmlPage,
this.treeOrder = Math.max(treeOrder, 0);
this.personalization = personalization;
this.variantId = variantId;
this.styleProperties = styleProperties;
this.styleProperties = UtilMethods.isSet(styleProperties) ? Map.copyOf(styleProperties) : null;
}

/** full constructor */
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.dotmarketing.factories;

import com.dotmarketing.util.UtilMethods;
import java.io.Serializable;
import java.util.Map;
import java.util.Objects;
Expand All @@ -22,14 +23,14 @@ public PersonalizedContentlet(final String contentletId, final String personaliz
this.contentletId = contentletId;
this.personalization = personalization;
this.treeOrder = treeOrder;
this.styleProperties = styleProperties;
this.styleProperties = UtilMethods.isSet(styleProperties) ? Map.copyOf(styleProperties) : Map.of();
}

public PersonalizedContentlet(final String contentletId, final String personalization) {
this.contentletId = contentletId;
this.personalization = personalization;
this.treeOrder = 0;
this.styleProperties = null;
this.styleProperties = Map.of();
}

public String getContentletId() {
Expand All @@ -44,6 +45,10 @@ public Object getTreeOrder() {
return treeOrder;
}

public Map<String, Object> getStyleProperties() {
return styleProperties;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
Expand Down
Loading