This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch v4
in repository https://gitbox.apache.org/repos/asf/causeway.git
The following commit(s) were added to refs/heads/v4 by this push:
new f41101af4e2 CAUSEWAY-3904: select2 with object icons (embedded + fa)
f41101af4e2 is described below
commit f41101af4e2107fa83dff0d65b233cb91e878b7a
Author: Andi Huber <[email protected]>
AuthorDate: Thu Sep 18 22:08:47 2025 +0200
CAUSEWAY-3904: select2 with object icons (embedded + fa)
- resource based icons not yet supported
---
.../causeway/applib/annotation/ObjectSupport.java | 3 +-
.../objectmanager/memento/ObjectDisplayDto.java | 57 ++++++++++
.../objectmanager/memento/ObjectMemento.java | 122 ++++++++++++++-------
.../objectmanager/memento/ObjectMementoEmpty.java | 16 +--
.../memento/ObjectMementoSingular.java | 37 ++-----
.../select2/ChoiceProviderForReferencesTest.java | 3 +-
.../select2/ChoiceProviderForValuesTest.java | 2 +-
.../select2/ChoiceProviderTestAbstract.java | 1 +
.../object/icontitle/ObjectIconAndTitlePanel.html | 2 +-
.../components/widgets/select2/ChoiceProvider.java | 51 ++-------
.../ui/components/widgets/select2/MultiChoice.java | 2 -
.../widgets/select2/OnSelectBehavior.java | 6 +-
.../ui/components/widgets/select2/Select2.java | 35 ++++--
.../components/widgets/select2/SingleChoice.java | 2 -
.../ConverterForObjectAdapterMemento.java | 69 ------------
.../wicketapp/CausewayWicketApplication.java | 3 -
16 files changed, 195 insertions(+), 216 deletions(-)
diff --git
a/api/applib/src/main/java/org/apache/causeway/applib/annotation/ObjectSupport.java
b/api/applib/src/main/java/org/apache/causeway/applib/annotation/ObjectSupport.java
index 12099207260..345ea50ff95 100644
---
a/api/applib/src/main/java/org/apache/causeway/applib/annotation/ObjectSupport.java
+++
b/api/applib/src/main/java/org/apache/causeway/applib/annotation/ObjectSupport.java
@@ -18,6 +18,7 @@
*/
package org.apache.causeway.applib.annotation;
+import java.io.Serializable;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
@@ -60,7 +61,7 @@ public enum IconWhere {
TABLE_ROW //TODO also TREE_NODE and SELECT_DROPDOWN
}
- public sealed interface IconResource
+ public sealed interface IconResource extends Serializable
permits ClassPathIconResource, FontAwesomeIconResource,
EmbeddedIconResource {
}
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectDisplayDto.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectDisplayDto.java
new file mode 100644
index 00000000000..569fd231eef
--- /dev/null
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectDisplayDto.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.causeway.core.metamodel.objectmanager.memento;
+
+import java.io.Serializable;
+import org.jspecify.annotations.Nullable;
+
+import org.apache.causeway.commons.internal.base._Strings;
+import org.apache.causeway.commons.io.JsonUtils;
+
+/**
+ * Provides a summary of the domain object for rendering,
+ * having (translated) title and icon.
+ *
+ * @implSpec works hand in hand with select2 (third-party) java-script
+ * and
org.apache.causeway.viewer.wicket.ui.components.widgets.select2.Select2
template configuration.
+ */
+public record ObjectDisplayDto(
+ Class<?> correspondingClass,
+ String bookmark,
+ String title,
+ @Nullable String iconHtml) implements Serializable {
+
+ public static ObjectDisplayDto fromJson(String json) {
+ return JsonUtils.tryRead(ObjectDisplayDto.class, json)
+ .valueAsNonNullElseFail();
+ }
+
+ public static ObjectDisplayDto fromJsonBase64(String base64EncodedJson) {
+ return fromJson(_Strings.base64UrlDecode(base64EncodedJson));
+ }
+
+ public String toJson() {
+ return JsonUtils.toStringUtf8(this);
+ }
+
+ public String toJsonBase64() {
+ return _Strings.base64UrlEncode(toJson());
+ }
+
+}
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMemento.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMemento.java
index b23f5d5a818..d53678f7578 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMemento.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMemento.java
@@ -19,22 +19,31 @@
package org.apache.causeway.core.metamodel.objectmanager.memento;
import java.io.Serializable;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Optional;
import org.jspecify.annotations.Nullable;
+import org.springframework.util.StringUtils;
+
+import org.apache.causeway.applib.annotation.ObjectSupport.IconWhere;
import org.apache.causeway.applib.id.LogicalType;
import org.apache.causeway.applib.services.bookmark.Bookmark;
-import org.apache.causeway.commons.internal.base._Bytes;
-import org.apache.causeway.commons.internal.base._Strings;
+import org.apache.causeway.applib.services.i18n.TranslationContext;
+import
org.apache.causeway.applib.services.placeholder.PlaceholderRenderService;
+import
org.apache.causeway.applib.services.placeholder.PlaceholderRenderService.PlaceholderLiteral;
+import org.apache.causeway.commons.internal.assertions._Assert;
import org.apache.causeway.commons.internal.collections._Lists;
-import org.apache.causeway.commons.internal.resources._Serializables;
+import org.apache.causeway.commons.internal.exceptions._Exceptions;
+import org.apache.causeway.core.metamodel.facets.object.icon.ObjectIcon;
+import
org.apache.causeway.core.metamodel.facets.object.icon.ObjectIconEmbedded;
+import org.apache.causeway.core.metamodel.facets.object.icon.ObjectIconFa;
import org.apache.causeway.core.metamodel.object.ManagedObject;
import org.apache.causeway.core.metamodel.object.ManagedObjects;
import org.apache.causeway.core.metamodel.object.MmAssertionUtils;
+import org.apache.causeway.core.metamodel.object.MmHintUtils;
+import org.apache.causeway.core.metamodel.object.MmTitleUtils;
/**
* @since 2.0
@@ -43,41 +52,59 @@ public sealed interface ObjectMemento
extends Serializable
permits ObjectMementoEmpty, ObjectMementoSingular, ObjectMementoPacked {
- /** arbitrary/random string */
- static final String NULL_ID = "VGN6r6zKTiLhUsA0WkdQ17LvMU1IYdb0";
-
LogicalType logicalType();
Bookmark bookmark();
/**
* The object's title for rendering (before translation).
* Corresponds to {@link ManagedObject#getTitle()}.
- * <p>
- * Directly support choice rendering, without the need to (re-)fetch
entire object graphs.
- * (TODO translated or not?)
+ *
+ * <p>Directly support choice rendering, without the need to (re-)fetch
entire object graphs.
+ * (pre-translated)
*/
String title();
// -- FACTORIES
static ObjectMemento empty(final LogicalType logicalType) {
- return new ObjectMementoEmpty(logicalType);
+ return new ObjectMementoEmpty(
+ logicalType,
+
PlaceholderRenderService.fallback().asText(PlaceholderLiteral.NULL_REPRESENTATION));
}
- static Optional<ObjectMemento> singular(final @Nullable ManagedObject
adapter) {
- return ManagedObjects.isNullOrUnspecifiedOrEmpty(adapter)
- ? Optional.empty()
- : Optional.of(ObjectMementoSingular.create(adapter));
+
+ static Optional<ObjectMemento> singular(
+ final @Nullable ManagedObject adapter) {
+ if(ManagedObjects.isNullOrUnspecifiedOrEmpty(adapter))
+ return Optional.empty();
+
+ var spec = adapter.objSpec();
+
+ _Assert.assertTrue(spec.isIdentifiable()
+ || spec.isParented()
+ || spec.isValue(), ()->"Don't know how to create an
ObjectMemento for a type "
+ + "with ObjectSpecification %s. "
+ + "All other strategies failed. Type is neither "
+ + "identifiable (isManagedBean() || isViewModel() ||
isEntity()), "
+ + "nor is a 'parented' Collection, "
+ + "nor has 'encodable' semantics, nor is (Serializable
|| Externalizable)"
+ .formatted(spec));
+
+ return Optional.ofNullable(new ObjectMementoSingular(
+ adapter.logicalType(),
+ MmHintUtils.bookmarkElseFail(adapter),
+
adapter.getTranslationService().translate(TranslationContext.empty(),
MmTitleUtils.titleOf(adapter)),
+ iconToHtml(adapter.getIcon(IconWhere.TABLE_ROW))));
}
/**
* returns null for null
*/
- @Nullable static ObjectMemento singularOrEmpty(final @Nullable
ManagedObject adapter) {
+ @Nullable static ObjectMemento singularOrEmpty(
+ final @Nullable ManagedObject adapter) {
MmAssertionUtils.assertPojoIsScalar(adapter);
- return !ManagedObjects.isNullOrUnspecifiedOrEmpty(adapter)
- ? ObjectMementoSingular.create(adapter)
- : ManagedObjects.isSpecified(adapter)
+ return singular(adapter)
+ .orElseGet(()->ManagedObjects.isSpecified(adapter)
? ObjectMemento.empty(adapter.logicalType())
- : null;
+ : null);
}
static ObjectMemento packed(
final LogicalType logicalType,
@@ -93,36 +120,51 @@ static ObjectMemento packed(
? orig
: _Lists.newArrayList(container);
return new ObjectMementoPacked(logicalType, arrayList);
-
}
// -- UTILITY
- @Nullable
- static String enstringToUrlBase64(final @Nullable ObjectMemento memento) {
- var base64UrlEncodedMemento = memento!=null
- ? _Strings.ofBytes(
- _Bytes.asUrlBase64.apply(
- _Serializables.write(memento)),
- StandardCharsets.US_ASCII)
- : null;
- return base64UrlEncodedMemento;
+ private static String iconToHtml(@Nullable ObjectIcon objectIcon) {
+ //if(true) return "<i class=\"%s\"></i>".formatted("fa-solid
fa-thumbs-up");
+
+ //TODO not supported yet as requires resource caching from wicket
+// if(objectIcon instanceof ObjectIconUrlBased urlBased)
+// return "<img src=\"" + urlBased.url().toExternalForm() + "\"/>";
+ if(objectIcon instanceof ObjectIconEmbedded embedded)
+ return "<img src=\"" + embedded.dataUri().toExternalForm() +
"\"/>";
+ if(objectIcon instanceof ObjectIconFa fa)
+ return fa.fontAwesomeLayers().toHtml();
+
+ return null;
}
- @Nullable
- static ObjectMemento destringFromUrlBase64(final @Nullable String
base64UrlEncodedMemento) {
+ static ObjectMemento fromDto(final ObjectDisplayDto dto) {
+ var bookmark = Bookmark.parse(dto.bookmark()).orElseThrow();
+ var logicalType = new LogicalType(bookmark.logicalTypeName(),
dto.correspondingClass());
+ return bookmark.isEmpty()
+ ? new ObjectMementoEmpty(logicalType, dto.title())
+ : new ObjectMementoSingular(logicalType, bookmark, dto.title(),
dto.iconHtml());
+ }
+
+ static String enstringToBase64(final ObjectMemento memento) {
+ if(memento instanceof ObjectMementoEmpty objectMementoEmpty)
+ return objectMementoEmpty.toDto().toJsonBase64();
+ if(memento instanceof ObjectMementoSingular objectMementoSingular)
+ return objectMementoSingular.toDto().toJsonBase64();
+
+ throw _Exceptions.unexpectedCodeReach();
+ }
+
+ static ObjectMemento destringFromBase64(final String base64EncodedDto) {
+ if(!StringUtils.hasLength(base64EncodedDto))
+ throw _Exceptions.unexpectedCodeReach();
+
try {
- return _Strings.isNotEmpty(base64UrlEncodedMemento)
- && !NULL_ID.equals(base64UrlEncodedMemento)
- ? _Serializables.read(
- ObjectMemento.class,
- _Bytes.ofUrlBase64.apply(
-
base64UrlEncodedMemento.getBytes(StandardCharsets.US_ASCII)))
- : null;
+ return fromDto(ObjectDisplayDto.fromJsonBase64(base64EncodedDto));
} catch (Exception e) {
+ e.printStackTrace();
return null; // map to null if anything goes wrong
}
-
}
default boolean isEmpty() {
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMementoEmpty.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMementoEmpty.java
index 7d4953d98fc..967f346b545 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMementoEmpty.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMementoEmpty.java
@@ -20,23 +20,19 @@
import org.apache.causeway.applib.id.LogicalType;
import org.apache.causeway.applib.services.bookmark.Bookmark;
-import
org.apache.causeway.applib.services.placeholder.PlaceholderRenderService;
-import
org.apache.causeway.applib.services.placeholder.PlaceholderRenderService.PlaceholderLiteral;
-
-import org.jspecify.annotations.NonNull;
record ObjectMementoEmpty(
- @NonNull LogicalType logicalType)
+ LogicalType logicalType,
+ String title)
implements ObjectMemento {
- @Override
- public String title() {
- return
PlaceholderRenderService.fallback().asText(PlaceholderLiteral.NULL_REPRESENTATION);
- }
-
@Override
public Bookmark bookmark() {
return Bookmark.empty(logicalType);
}
+ public ObjectDisplayDto toDto() {
+ return new ObjectDisplayDto(logicalType.correspondingClass(),
bookmark().stringify(), title, null);
+ }
+
}
diff --git
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMementoSingular.java
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMementoSingular.java
index 8cf9f03b4a7..7f3980bbf47 100644
---
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMementoSingular.java
+++
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMementoSingular.java
@@ -18,43 +18,24 @@
*/
package org.apache.causeway.core.metamodel.objectmanager.memento;
+import org.jspecify.annotations.Nullable;
+
import org.apache.causeway.applib.id.LogicalType;
import org.apache.causeway.applib.services.bookmark.Bookmark;
-import org.apache.causeway.commons.internal.assertions._Assert;
-import org.apache.causeway.core.metamodel.object.MmHintUtils;
-import org.apache.causeway.core.metamodel.object.ManagedObject;
-import org.apache.causeway.core.metamodel.object.MmTitleUtils;
-
-import org.jspecify.annotations.NonNull;
record ObjectMementoSingular(
- @NonNull LogicalType logicalType,
- @NonNull Bookmark bookmark,
- String title)
+ LogicalType logicalType,
+ Bookmark bookmark,
+ String title,
+ @Nullable String iconHtml)
implements ObjectMemento {
- // -- FACTORIES
-
- static ObjectMementoSingular create(final @NonNull ManagedObject adapter) {
- var spec = adapter.objSpec();
-
- _Assert.assertTrue(spec.isIdentifiable()
- || spec.isParented()
- || spec.isValue(), ()->"Don't know how to create an
ObjectMemento for a type "
- + "with ObjectSpecification %s. "
- + "All other strategies failed. Type is neither "
- + "identifiable (isManagedBean() || isViewModel() ||
isEntity()), "
- + "nor is a 'parented' Collection, "
- + "nor has 'encodable' semantics, nor is (Serializable
|| Externalizable)"
- .formatted(spec));
-
- return new ObjectMementoSingular(
- adapter.logicalType(),
- MmHintUtils.bookmarkElseFail(adapter),
- MmTitleUtils.titleOf(adapter));
+ public ObjectDisplayDto toDto() {
+ return new ObjectDisplayDto(logicalType.correspondingClass(),
bookmark.stringify(), title, iconHtml);
}
@Override public int hashCode() { return bookmark.hashCode(); }
+
@Override public boolean equals(final Object o) {
return (o instanceof ObjectMementoSingular other)
? this.bookmark.equals(other.bookmark)
diff --git
a/viewers/wicket/ui-test/src/test/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/ChoiceProviderForReferencesTest.java
b/viewers/wicket/ui-test/src/test/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/ChoiceProviderForReferencesTest.java
index 625c5b31f49..51f1859e7ca 100644
---
a/viewers/wicket/ui-test/src/test/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/ChoiceProviderForReferencesTest.java
+++
b/viewers/wicket/ui-test/src/test/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/ChoiceProviderForReferencesTest.java
@@ -65,7 +65,8 @@ void roundtrip() {
System.err.printf("displayValue: %s%n",
choiceProvider.getDisplayValue(memento));
});*/
- var asIds = mementos.map(choiceProvider::getIdValue);
+
+ var asIds =
mementos.map(choiceProvider.toSelect2ChoiceProvider()::getIdValue);
var recoveredMementos =
Can.ofCollection(choiceProvider.toChoices(asIds.toList()));
diff --git
a/viewers/wicket/ui-test/src/test/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/ChoiceProviderForValuesTest.java
b/viewers/wicket/ui-test/src/test/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/ChoiceProviderForValuesTest.java
index aa215979379..ec58bdb82f0 100644
---
a/viewers/wicket/ui-test/src/test/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/ChoiceProviderForValuesTest.java
+++
b/viewers/wicket/ui-test/src/test/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/ChoiceProviderForValuesTest.java
@@ -68,7 +68,7 @@ void roundtrip() {
// System.err.printf("displayValue: %s%n",
choiceProvider.getDisplayValue(memento));
// });
- var asIds = mementos.map(choiceProvider::getIdValue);
+ var asIds =
mementos.map(choiceProvider.toSelect2ChoiceProvider()::getIdValue);
var recoveredMementos =
Can.ofCollection(choiceProvider.toChoices(asIds.toList()));
diff --git
a/viewers/wicket/ui-test/src/test/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/ChoiceProviderTestAbstract.java
b/viewers/wicket/ui-test/src/test/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/ChoiceProviderTestAbstract.java
index ff32c17d8f4..995a36b8575 100644
---
a/viewers/wicket/ui-test/src/test/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/ChoiceProviderTestAbstract.java
+++
b/viewers/wicket/ui-test/src/test/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/ChoiceProviderTestAbstract.java
@@ -38,6 +38,7 @@ abstract class ChoiceProviderTestAbstract {
protected void setUp() {
mmc = MetaModelContext_forTesting.builder()
.memberExecutor(mock(MemberExecutorService.class))
+ .objectIconService((managedObject, iconWhere) -> null)
.build()
.withValueSemantics(new BigDecimalValueSemantics())
.withValueSemantics(new IntValueSemantics())
diff --git
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/object/icontitle/ObjectIconAndTitlePanel.html
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/object/icontitle/ObjectIconAndTitlePanel.html
index 63fb3a1d88e..8eb166fb6a6 100644
---
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/object/icontitle/ObjectIconAndTitlePanel.html
+++
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/object/icontitle/ObjectIconAndTitlePanel.html
@@ -20,7 +20,7 @@
<html xmlns:wicket="http://wicket.apache.org">
<body>
<wicket:panel>
- <span wicket:id="objectLinkWrapper"
class="objectIconAndTitlePanel objectIconAndTitleComponentType">
+ <span wicket:id="objectLinkWrapper"
class="objectIconAndTitlePanel">
<a href="#" wicket:id="objectLink" class="objectUrlSource">
<span wicket:id="objectIconFaLeft"></span>
<img wicket:id="objectIcon"/>
diff --git
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/ChoiceProvider.java
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/ChoiceProvider.java
index 36b912e9e2f..4b57528c2a6 100644
---
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/ChoiceProvider.java
+++
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/ChoiceProvider.java
@@ -26,8 +26,6 @@
import org.jspecify.annotations.Nullable;
import org.wicketstuff.select2.Response;
-import org.apache.causeway.applib.services.i18n.TranslationContext;
-import
org.apache.causeway.applib.services.placeholder.PlaceholderRenderService.PlaceholderLiteral;
import org.apache.causeway.commons.collections.Can;
import org.apache.causeway.commons.internal.base._NullSafe;
import org.apache.causeway.core.metamodel.context.HasMetaModelContext;
@@ -48,31 +46,6 @@ public ChoiceProvider(
this(attributeModel,
UiAttribute.ChoiceProviderSort.valueOf(attributeModel));
}
- /**
- * Get the value for displaying to an end user.
- */
- public String getDisplayValue(final ObjectMemento choiceMemento) {
- if (choiceMemento == null
- || choiceMemento.isEmpty()) {
- return
getPlaceholderRenderService().asText(PlaceholderLiteral.NULL_REPRESENTATION);
- }
- return translate(choiceMemento.title());
- }
-
- /**
- * This method is called to get the id value of an object (used as the
value attribute of a
- * choice element) The id can be extracted from the object like a primary
key, or if the list is
- * stable you could just return a toString of the index.
- * <p>
- * Note that the given index can be {@code -1} if the object in question
is not contained in the
- * available choices.
- */
- public String getIdValue(final ObjectMemento choiceMemento) {
- if (choiceMemento == null) return ObjectMemento.NULL_ID;
-
- return ObjectMemento.enstringToUrlBase64(choiceMemento);
- }
-
/**
* Queries application for choices that match the search {@code term} and
adds them to the
* {@code response}
@@ -91,7 +64,7 @@ public void query(
// else, if not mandatory, prepend null
var mementosIncludingNull = mementosFiltered.toArrayList();
- mementosIncludingNull.add(0, null);
+ mementosIncludingNull.add(0,
ObjectMemento.empty(attributeModel.getElementType().logicalType()));
response.addAll(mementosIncludingNull);
}
@@ -103,7 +76,7 @@ public void query(
*/
public Collection<ObjectMemento> toChoices(final Collection<String> ids) {
return _NullSafe.stream(ids)
- .map(this::mementoFromIdWithNullHandling)
+ .map(this::mementoFromId)
.collect(Collectors.toList());
}
@@ -122,10 +95,10 @@ org.wicketstuff.select2.ChoiceProvider<ObjectMemento>
toSelect2ChoiceProvider()
delegate.query(term, page, response);
}
@Override public String getIdValue(final ObjectMemento object) {
- return delegate.getIdValue(object);
+ return ObjectMemento.enstringToBase64(object);
}
@Override public String getDisplayValue(final ObjectMemento
object) {
- return delegate.getDisplayValue(object);
+ return null; // not needed, already encoded into the 'id'
}
};
}
@@ -177,12 +150,6 @@ private Can<ManagedObject> reconstructPendingArgs(
return pendingArgsList;
}
- private @Nullable ObjectMemento mementoFromIdWithNullHandling(final String
id) {
- if(ObjectMemento.NULL_ID.equals(id)) return null;
-
- return mementoFromId(id);
- }
-
/**
* Whether to not prepend <code>null</code> as choice candidate.
*/
@@ -216,18 +183,14 @@ private Can<ObjectMemento> filter(
if (Strings.isEmpty(term)) return choiceMementos;
- var translationContext = TranslationContext.empty();
- var translator = getTranslationService();
var termLower = term.toLowerCase();
- return choiceMementos.filter((final ObjectMemento candidateMemento)->{
- var title = translator.translate(translationContext,
candidateMemento.title());
- return title.toLowerCase().contains(termLower);
- });
+ return choiceMementos.filter((final ObjectMemento candidateMemento)->
+ candidateMemento.title().toLowerCase().contains(termLower));
}
private @Nullable ObjectMemento mementoFromId(final @Nullable String id) {
- return ObjectMemento.destringFromUrlBase64(id);
+ return ObjectMemento.destringFromBase64(id);
}
}
diff --git
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/MultiChoice.java
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/MultiChoice.java
index 007d96dbba6..d5ae9b4a437 100644
---
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/MultiChoice.java
+++
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/MultiChoice.java
@@ -63,8 +63,6 @@ record MultiChoice(
// --
});
-
setDelay(Math.toIntExact(getConfiguration().viewer().wicket().select2AjaxDelay().toMillis()));
- component().setRequired(attributeModel.isRequired());
}
@Override
diff --git
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/OnSelectBehavior.java
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/OnSelectBehavior.java
index 134d0fac404..0d048685459 100644
---
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/OnSelectBehavior.java
+++
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/OnSelectBehavior.java
@@ -111,7 +111,7 @@ private void updatePendingModels() {
Event.valueOf(pair)
.ifPresent(event->{
if(getComponent() instanceof Select2MultiChoice
select2MultiChoice) {
- var objectMementoFromEvent =
ObjectMemento.destringFromUrlBase64(pair.getValue());
+ var objectMementoFromEvent =
ObjectMemento.destringFromBase64(pair.getValue());
if(objectMementoFromEvent==null) return; // add or remove
nothing is a no-op
var component =
_Casts.<Select2MultiChoice<ObjectMemento>>uncheckedCast(select2MultiChoice);
@@ -141,7 +141,7 @@ private void updatePendingModels() {
var component =
_Casts.<Select2Choice<ObjectMemento>>uncheckedCast(select2Choice);
switch(event) {
case SELECT:
- var objectMementoFromEvent =
ObjectMemento.destringFromUrlBase64(pair.getValue());
+ var objectMementoFromEvent =
ObjectMemento.destringFromBase64(pair.getValue());
if(objectMementoFromEvent==null) {
// select nothing is rather a CLEAR operation
component.clearInput();
@@ -161,7 +161,7 @@ private void updatePendingModels() {
} else return;
if(XrayUi.isXrayEnabled()) {
- var objectMementoFromEvent =
ObjectMemento.destringFromUrlBase64(pair.getValue());
+ var objectMementoFromEvent =
ObjectMemento.destringFromBase64(pair.getValue());
if(objectMementoFromEvent!=null) {
_XrayEvent.event("Select2 event: %s %s", event,
objectMementoFromEvent.bookmark());
} else {
diff --git
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/Select2.java
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/Select2.java
index b33e1de6a20..e049d9e7698 100644
---
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/Select2.java
+++
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/Select2.java
@@ -34,7 +34,8 @@
import org.apache.causeway.viewer.wicket.model.models.UiAttributeWkt;
import
org.apache.causeway.viewer.wicket.ui.components.attributes.AttributeModelChangeDispatcher;
-public interface Select2 extends Serializable {
+public sealed interface Select2 extends Serializable
+permits SingleChoice, MultiChoice {
static Select2 create(
final String id,
@@ -56,6 +57,23 @@ static Select2 create(
settings.setDropdownAutoWidth(true);
settings.setWidth("100%");
settings.setPlaceholder(attributeModel.getFriendlyName());
+ // the id string is url-safe base64 encoded JSON coming from
ObjectDisplayDto
+ var template = """
+ function(opt) {
+ if(!opt) return "undefined";
+ if(!opt.id) return "undefined";
+ var base64 = opt.id.replace(/-/g, '+').replace(/_/g, '/')
+ var dto = JSON.parse(atob(base64));
+ if(!dto) return "undefined";
+ if(!dto.title) return "undefined";
+ if(dto.iconHtml) {
+ return $('<span>' + dto.iconHtml + ' ' + dto.title +
'</span>');
+ }
+ return dto.title;
+ }""";
+
+ settings.setTemplateResult(template);
+ settings.setTemplateSelection(template);
switch(attributeModel.getChoiceProviderSort()) {
case
AUTO_COMPLETE->settings.setMinimumInputLength(attributeModel.getAutoCompleteMinLength());
@@ -64,6 +82,11 @@ static Select2 create(
case CHOICES, NO_CHOICES->{}
}
+ component.setRequired(attributeModel.isRequired());
+ // time to wait for the user to stop typing before issuing the ajax
request.
+ component.getSettings().getAjax(true)
+
.setDelay(Math.toIntExact(attributeModel.getConfiguration().viewer().wicket().select2AjaxDelay().toMillis()));
+
component.setOutputMarkupPlaceholderTag(true);
component.setLabel(Model.of(attributeModel.getFriendlyName()));
@@ -100,14 +123,4 @@ default void setMutable(final boolean mutability) {
component().setEnabled(mutability);
}
- /**
- * The number of milliseconds to wait for the user to stop typing before
- * issuing the ajax request.
- * @param millis
- */
- default void setDelay(final int millis) {
- var ajaxSettings = component().getSettings().getAjax(true);
- ajaxSettings.setDelay(millis);
- }
-
}
diff --git
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/SingleChoice.java
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/SingleChoice.java
index 30f15d6b71b..c84408c06c7 100644
---
a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/SingleChoice.java
+++
b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/select2/SingleChoice.java
@@ -35,8 +35,6 @@ record SingleChoice(Select2Choice<ObjectMemento> component)
final UiAttributeWkt attributeModel,
final ChoiceProvider choiceProvider) {
this(new Select2Choice<>(id, model,
choiceProvider.toSelect2ChoiceProvider()));
-
setDelay(Math.toIntExact(getConfiguration().viewer().wicket().select2AjaxDelay().toMillis()));
- component().setRequired(attributeModel.isRequired());
}
@Override
diff --git
a/viewers/wicket/viewer/src/main/java/org/apache/causeway/viewer/wicket/viewer/integration/ConverterForObjectAdapterMemento.java
b/viewers/wicket/viewer/src/main/java/org/apache/causeway/viewer/wicket/viewer/integration/ConverterForObjectAdapterMemento.java
deleted file mode 100644
index 880ae61a7ad..00000000000
---
a/viewers/wicket/viewer/src/main/java/org/apache/causeway/viewer/wicket/viewer/integration/ConverterForObjectAdapterMemento.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.causeway.viewer.wicket.viewer.integration;
-
-import java.util.Locale;
-
-import org.apache.wicket.util.convert.IConverter;
-
-import org.apache.causeway.applib.services.bookmark.Bookmark;
-import org.apache.causeway.applib.services.bookmark.Oid;
-import org.apache.causeway.core.metamodel.objectmanager.memento.ObjectMemento;
-
-import lombok.RequiredArgsConstructor;
-
-/**
- * Implementation of a Wicket {@link IConverter} for
- * {@link ObjectMemento}s, converting to-and-from their stringified {@link
Bookmark}s.
- */
-@RequiredArgsConstructor
-public class ConverterForObjectAdapterMemento implements
IConverter<ObjectMemento> {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * Converts string representation of {@link Oid} to
- * {@link ObjectMemento}.
- */
- @Override
- public ObjectMemento convertToObject(
- final String base64UrlEncodedMemento, final Locale locale) {
- var obj = ObjectMemento.destringFromUrlBase64(base64UrlEncodedMemento);
-
- //XXX ever used ?
- System.err.printf("ConverterForObjectAdapterMemento: convertTo
ObjectMemento %s->%s%n", base64UrlEncodedMemento, obj);
-
- return obj;
- }
-
- /**
- * Converts {@link ObjectMemento} to string representation of
- * {@link Bookmark}.
- */
- @Override
- public String convertToString(final ObjectMemento memento, final Locale
locale) {
- var string = ObjectMemento.enstringToUrlBase64(memento);
-
- //XXX ever used ?
- System.err.printf("ConverterForObjectAdapterMemento: convertFrom
ObjectMemento %s->%s%n", memento.bookmark(), string);
-
- return string;
- }
-
-}
diff --git
a/viewers/wicket/viewer/src/main/java/org/apache/causeway/viewer/wicket/viewer/wicketapp/CausewayWicketApplication.java
b/viewers/wicket/viewer/src/main/java/org/apache/causeway/viewer/wicket/viewer/wicketapp/CausewayWicketApplication.java
index 59e90a558ac..6dbfe9c7d07 100644
---
a/viewers/wicket/viewer/src/main/java/org/apache/causeway/viewer/wicket/viewer/wicketapp/CausewayWicketApplication.java
+++
b/viewers/wicket/viewer/src/main/java/org/apache/causeway/viewer/wicket/viewer/wicketapp/CausewayWicketApplication.java
@@ -56,7 +56,6 @@
import org.apache.causeway.core.config.environment.CausewaySystemEnvironment;
import org.apache.causeway.core.metamodel.context.MetaModelContext;
import org.apache.causeway.core.metamodel.object.ManagedObject;
-import org.apache.causeway.core.metamodel.objectmanager.memento.ObjectMemento;
import
org.apache.causeway.viewer.wicket.model.causeway.WicketApplicationInitializer;
import org.apache.causeway.viewer.wicket.model.models.PageType;
import org.apache.causeway.viewer.wicket.ui.ComponentFactory;
@@ -69,7 +68,6 @@
import
org.apache.causeway.viewer.wicket.viewer.integration.AuthenticatedWebSessionForCauseway;
import
org.apache.causeway.viewer.wicket.viewer.integration.CausewayResourceSettings;
import
org.apache.causeway.viewer.wicket.viewer.integration.ConverterForObjectAdapter;
-import
org.apache.causeway.viewer.wicket.viewer.integration.ConverterForObjectAdapterMemento;
import
org.apache.causeway.viewer.wicket.viewer.integration.WebRequestCycleForCauseway;
import lombok.Getter;
@@ -373,7 +371,6 @@ protected Class<? extends AuthenticatedWebSession>
getWebSessionClass() {
protected IConverterLocator newConverterLocator() {
final ConverterLocator converterLocator = new ConverterLocator();
converterLocator.set(ManagedObject.class, new
ConverterForObjectAdapter());
- converterLocator.set(ObjectMemento.class, new
ConverterForObjectAdapterMemento());
return converterLocator;
}