You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2022/03/04 09:49:31 UTC
[isis] branch master updated: ISIS-2877: refact. around IsisBlobOrClobPanelAbstract
This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git
The following commit(s) were added to refs/heads/master by this push:
new d4fff87 ISIS-2877: refact. around IsisBlobOrClobPanelAbstract
d4fff87 is described below
commit d4fff87fbaf0e8e43b32dc54b0f8ecb61b27da58
Author: Andi Huber <ah...@apache.org>
AuthorDate: Fri Mar 4 10:49:20 2022 +0100
ISIS-2877: refact. around IsisBlobOrClobPanelAbstract
---
.../isis/commons/internal/base/_Optionals.java | 1 -
.../commons/internal/functions/_Functions.java | 10 +
.../isis/core/metamodel/commons/Wormhole.java | 46 ----
.../core/metamodel/render/ScalarRenderMode.java | 56 +++++
.../wicket/model/models/FileUploadModels.java | 99 +++++++++
.../wicket/model/models}/HasScalarModel.java | 6 +-
.../wicket/model/models/ScalarConvertingModel.java | 74 +++++++
.../viewer/wicket/model/models/ScalarModel.java | 7 +-
.../model/models/ScalarUnwrappingModel.java} | 41 ++--
.../ui/components/scalars/ScalarPanelAbstract.java | 1 +
.../scalars/ScalarPanelTextFieldAbstract.java | 8 +-
.../scalars/ScalarPanelTextFieldNumeric.java | 2 +-
.../ScalarPanelTextFieldWithTemporalPicker.java | 2 +-
.../blobclob/IsisBlobOrClobPanelAbstract.java | 236 +++++++--------------
.../components/scalars/blobclob/IsisBlobPanel.java | 14 +-
.../components/scalars/blobclob/IsisClobPanel.java | 18 +-
.../scalars/passwd/IsisPasswordPanel.java | 2 +-
.../blobclob => util}/ResourceLinkVolatile.java | 2 +-
.../org/apache/isis/viewer/wicket/ui/util/Wkt.java | 26 +++
19 files changed, 392 insertions(+), 259 deletions(-)
diff --git a/commons/src/main/java/org/apache/isis/commons/internal/base/_Optionals.java b/commons/src/main/java/org/apache/isis/commons/internal/base/_Optionals.java
index ec1e8b2..cf083e9 100644
--- a/commons/src/main/java/org/apache/isis/commons/internal/base/_Optionals.java
+++ b/commons/src/main/java/org/apache/isis/commons/internal/base/_Optionals.java
@@ -43,7 +43,6 @@ public class _Optionals {
return orNullable(orNullable(a, b), c);
}
-
public <T> OptionalInt toInt(
final Optional<T> optional,
final ToIntFunction<? super T> mapper) {
diff --git a/commons/src/main/java/org/apache/isis/commons/internal/functions/_Functions.java b/commons/src/main/java/org/apache/isis/commons/internal/functions/_Functions.java
index 409dff6..e9da1b0 100644
--- a/commons/src/main/java/org/apache/isis/commons/internal/functions/_Functions.java
+++ b/commons/src/main/java/org/apache/isis/commons/internal/functions/_Functions.java
@@ -23,6 +23,7 @@ import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
+import java.util.function.UnaryOperator;
/**
* <h1>- internal use only -</h1>
@@ -44,6 +45,15 @@ public final class _Functions {
return t->{};
}
+ // -- PEEK
+
+ public static <T> UnaryOperator<T> peek(final Consumer<T> c) {
+ return x -> {
+ c.accept(x);
+ return x;
+ };
+ }
+
// --
@FunctionalInterface
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/commons/Wormhole.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/commons/Wormhole.java
deleted file mode 100644
index 9607f95..0000000
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/commons/Wormhole.java
+++ /dev/null
@@ -1,46 +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.isis.core.metamodel.commons;
-
-/**
- * Provides a mechanism to avoid infinite loops
- * whereby method A -> method B -> method C -> method A and so on.
- */
-public final class Wormhole {
-
- private Wormhole(){}
-
- private ThreadLocal<Boolean> inWormhole = ThreadLocal.<Boolean>withInitial(()->Boolean.FALSE);
-
- public void run(final Runnable runnable) {
- try {
- if(inWormhole.get()) {
- return;
- }
- inWormhole.set(true);
- runnable.run();
- } finally {
- inWormhole.remove();
- }
- }
-
- public static void invoke(final Runnable runnable) {
- new Wormhole().run(runnable);
- }
-}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/render/ScalarRenderMode.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/render/ScalarRenderMode.java
new file mode 100644
index 0000000..9b778bc
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/render/ScalarRenderMode.java
@@ -0,0 +1,56 @@
+/*
+ * 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.isis.core.metamodel.render;
+
+import org.apache.isis.applib.value.semantics.Parser;
+import org.apache.isis.applib.value.semantics.Renderer;
+
+/**
+ * Mode of representation for a Scalar within the UI.
+ */
+public enum ScalarRenderMode {
+
+ /**
+ * Hiding mode, corresponds to hidden UI components.
+ */
+ HIDING,
+
+ /**
+ * Viewing (HTML-rendering) mode, corresponds to 'compact' UI components.
+ * <p>
+ * In case of value-types, indicates that for value-type to {@link String} conversion,
+ * a {@link Renderer} is required.
+ */
+ VIEWING,
+
+ /**
+ * Editing (text-parsing) mode, corresponds to 'regular' UI components.
+ * <p>
+ * In case of value-types, indicates that for value-type to {@link String} conversion,
+ * and vice versa, a {@link Parser} is required.
+ */
+ EDITING;
+
+ public boolean isHiding() { return this == HIDING; }
+ public boolean isVisible() { return this != HIDING; }
+
+ public boolean isViewing() { return this == VIEWING; }
+ public boolean isEditing() { return this == EDITING; }
+
+}
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/FileUploadModels.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/FileUploadModels.java
new file mode 100644
index 0000000..5619150
--- /dev/null
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/FileUploadModels.java
@@ -0,0 +1,99 @@
+/*
+ * 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.isis.viewer.wicket.model.models;
+
+import java.nio.charset.Charset;
+import java.util.List;
+
+import org.apache.wicket.markup.html.form.upload.FileUpload;
+import org.springframework.lang.Nullable;
+
+import org.apache.isis.applib.value.Blob;
+import org.apache.isis.applib.value.Clob;
+
+import lombok.NonNull;
+import lombok.experimental.UtilityClass;
+
+@UtilityClass
+public class FileUploadModels {
+
+ public ScalarConvertingModel<List<FileUpload>, Blob> blob(final @NonNull ScalarModel scalarModel) {
+ return new ScalarConvertingModel<List<FileUpload>, Blob>(scalarModel) {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected Blob toScalarValue(final @Nullable List<FileUpload> fileUploads) {
+
+ if(fileUploads==null
+ || fileUploads.isEmpty()) {
+ return null;
+ }
+
+ final FileUpload fileUpload = fileUploads.get(0);
+ final String contentType = fileUpload.getContentType();
+ final String clientFileName = fileUpload.getClientFileName();
+ final byte[] bytes = fileUpload.getBytes();
+ final Blob blob = new Blob(clientFileName, contentType, bytes);
+ return blob;
+ }
+
+ @Override
+ protected List<FileUpload> fromScalarValue(final Blob blob) {
+ // not used
+ return null;
+ }
+
+ };
+ }
+
+ public ScalarConvertingModel<List<FileUpload>, Clob> clob(
+ final @NonNull ScalarModel scalarModel,
+ final @NonNull Charset charset) {
+
+ return new ScalarConvertingModel<List<FileUpload>, Clob>(scalarModel) {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected Clob toScalarValue(final @Nullable List<FileUpload> fileUploads) {
+
+ if(fileUploads==null
+ || fileUploads.isEmpty()) {
+ return null;
+ }
+
+ final FileUpload fileUpload = fileUploads.get(0);
+ final String contentType = fileUpload.getContentType();
+ final String clientFileName = fileUpload.getClientFileName();
+ final String str = new String(fileUpload.getBytes(), charset);
+ final Clob clob = new Clob(clientFileName, contentType, str);
+ return clob;
+ }
+
+ @Override
+ protected List<FileUpload> fromScalarValue(final Clob clob) {
+ // not used
+ return null;
+ }
+
+ };
+ }
+
+}
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/HasScalarModel.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/HasScalarModel.java
similarity index 84%
rename from viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/HasScalarModel.java
rename to viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/HasScalarModel.java
index 6f35a01..bbfaf70 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/HasScalarModel.java
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/HasScalarModel.java
@@ -16,12 +16,12 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.isis.viewer.wicket.ui.components.scalars;
+package org.apache.isis.viewer.wicket.model.models;
-import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import java.io.Serializable;
@FunctionalInterface
-public interface HasScalarModel {
+public interface HasScalarModel extends Serializable {
ScalarModel scalarModel();
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarConvertingModel.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarConvertingModel.java
new file mode 100644
index 0000000..a11b861
--- /dev/null
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarConvertingModel.java
@@ -0,0 +1,74 @@
+/*
+ * 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.isis.viewer.wicket.model.models;
+
+import org.apache.wicket.model.ChainingModel;
+import org.springframework.lang.Nullable;
+
+import org.apache.isis.commons.internal.base._Casts;
+import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
+
+import lombok.NonNull;
+import lombok.val;
+
+/**
+ * @param <T> foreign type
+ * @param <V> scalar value type
+ */
+public abstract class ScalarConvertingModel<T, V>
+extends ChainingModel<T> {
+
+ private static final long serialVersionUID = 1L;
+
+ protected ScalarConvertingModel(final @NonNull ScalarModel scalarModel) {
+ super(scalarModel);
+ }
+
+ @Override
+ public void setObject(final T modelValue) {
+ val scalarModel = scalarModel();
+ val value = toScalarValue(modelValue);
+ val objectAdapter = value != null
+ ? scalarModel().getCommonContext().getObjectManager().adapt(value)
+ : ManagedObject.empty(scalarModel.getScalarTypeSpec());
+ scalarModel.setObject(objectAdapter);
+ }
+
+ @Override
+ public T getObject() {
+ val adapter = scalarModel().getObject();
+ final V scalarValue = !ManagedObjects.isNullOrUnspecifiedOrEmpty(adapter)
+ ? _Casts.uncheckedCast(adapter.getPojo())
+ : null;
+ return fromScalarValue(scalarValue);
+ }
+
+ // -- HOOKS
+
+ protected abstract V toScalarValue(@Nullable T t);
+ protected abstract T fromScalarValue(@Nullable V value);
+
+ // -- HELPER
+
+ protected ScalarModel scalarModel() {
+ return (ScalarModel) super.getTarget();
+ }
+
+}
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java
index f4ee515..e2152d8 100644
--- a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java
@@ -22,6 +22,7 @@ import java.util.List;
import java.util.Optional;
import org.apache.wicket.model.ChainingModel;
+import org.apache.wicket.model.IModel;
import org.apache.isis.applib.annotation.PromptStyle;
import org.apache.isis.commons.collections.Can;
@@ -137,6 +138,10 @@ implements HasRenderingHints, ScalarUiModel, LinksProvider, FormExecutorContext
return proposedValue().getValue().getValue();
}
+ public <T> IModel<T> unwrapped(final Class<T> type) {
+ return new ScalarUnwrappingModel<T>(type, this);
+ }
+
/**
* Sets given ManagedObject as new proposed value.
* (override, so we don't return the target model, we are chained to)
@@ -349,6 +354,4 @@ implements HasRenderingHints, ScalarUiModel, LinksProvider, FormExecutorContext
//getPendingPropertyModel().getValue().setValue(null);
}
-
-
}
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/TextFieldValueModel.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarUnwrappingModel.java
similarity index 64%
rename from viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/TextFieldValueModel.java
rename to viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarUnwrappingModel.java
index 1005ff4..73a8459 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/TextFieldValueModel.java
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarUnwrappingModel.java
@@ -16,31 +16,35 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.isis.viewer.wicket.ui.components.scalars;
+package org.apache.isis.viewer.wicket.model.models;
-import java.io.Serializable;
-
-import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.model.ChainingModel;
-import org.apache.wicket.model.Model;
+import org.springframework.util.ClassUtils;
+import org.apache.isis.commons.internal.base._Casts;
import org.apache.isis.core.metamodel.spec.ManagedObject;
import org.apache.isis.core.metamodel.spec.ManagedObjects;
-import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import lombok.Getter;
+import lombok.NonNull;
import lombok.val;
/**
- * For custom {@link ScalarPanelTextFieldAbstract}s to use as the {@link Model}
- * of their {@link TextField} (as constructed in {@link ScalarPanelTextFieldAbstract#createTextField(String)}).
+ * Wraps and unwraps the contained value within {@link ManagedObject},
+ * as provided by a {@link ScalarModel}.
*/
-public class TextFieldValueModel<T extends Serializable>
+public class ScalarUnwrappingModel<T>
extends ChainingModel<T> {
private static final long serialVersionUID = 1L;
- public TextFieldValueModel(final HasScalarModel scalarModelHolder) {
- super(scalarModelHolder);
+ @Getter @NonNull private final Class<T> type;
+
+ public ScalarUnwrappingModel(
+ final @NonNull Class<T> type,
+ final @NonNull ScalarModel scalarModel) {
+ super(scalarModel);
+ this.type = type;
}
@Override
@@ -51,9 +55,7 @@ extends ChainingModel<T> {
@Override
public void setObject(final T object) {
-
val scalarModel = scalarModel();
-
if (object == null) {
scalarModel.setObject(null);
} else {
@@ -64,15 +66,18 @@ extends ChainingModel<T> {
// -- HELPER
- @SuppressWarnings("unchecked")
private T unwrap(final ManagedObject objectAdapter) {
- return (T) ManagedObjects.UnwrapUtil.single(objectAdapter);
+ val pojo = ManagedObjects.UnwrapUtil.single(objectAdapter);
+ if(pojo==null
+ || !ClassUtils.resolvePrimitiveIfNecessary(type)
+ .isAssignableFrom(ClassUtils.resolvePrimitiveIfNecessary(pojo.getClass()))) {
+ return null;
+ }
+ return _Casts.uncheckedCast(pojo);
}
private ScalarModel scalarModel() {
- return ((HasScalarModel) super.getTarget())
- .scalarModel();
+ return (ScalarModel) super.getTarget();
}
-
}
\ No newline at end of file
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java
index bceb653..e0c4070 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java
@@ -54,6 +54,7 @@ import org.apache.isis.viewer.common.model.feature.ParameterUiModel;
import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
import org.apache.isis.viewer.wicket.model.models.ActionPrompt;
import org.apache.isis.viewer.wicket.model.models.ActionPromptProvider;
+import org.apache.isis.viewer.wicket.model.models.HasScalarModel;
import org.apache.isis.viewer.wicket.model.models.InlinePromptContext;
import org.apache.isis.viewer.wicket.model.models.ScalarModel;
import org.apache.isis.viewer.wicket.model.models.ScalarPropertyModel;
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java
index 300716a..e9931f1 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java
@@ -112,13 +112,13 @@ extends ScalarPanelWithFormFieldAbstract<T> {
val converter = getConverter(scalarModel());
return getTextFieldVariant().isSingleLine()
? Wkt.textFieldWithConverter(
- id, newTextFieldValueModel(), type, converter)
+ id, unwrappedModel(), type, converter)
: setRowsAndMaxLengthAttributesOn(Wkt.textAreaWithConverter(
- id, newTextFieldValueModel(), type, converter));
+ id, unwrappedModel(), type, converter));
}
- protected final TextFieldValueModel<T> newTextFieldValueModel() {
- return new TextFieldValueModel<>(this);
+ protected final IModel<T> unwrappedModel() {
+ return scalarModel().unwrapped(type);
}
// --
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldNumeric.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldNumeric.java
index 53147c3..0bed33f 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldNumeric.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldNumeric.java
@@ -46,7 +46,7 @@ extends ScalarPanelTextFieldWithValueSemantics<T> {
protected final Component createComponentForCompact() {
val label = Wkt.labelAddWithConverter(
getCompactFragment(CompactType.SPAN),
- ID_SCALAR_IF_COMPACT, newTextFieldValueModel(), type, getConverter(scalarModel()));
+ ID_SCALAR_IF_COMPACT, unwrappedModel(), type, getConverter(scalarModel()));
label.setEnabled(false);
return label;
}
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldWithTemporalPicker.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldWithTemporalPicker.java
index 166c5e1..c4966db 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldWithTemporalPicker.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldWithTemporalPicker.java
@@ -48,7 +48,7 @@ extends ScalarPanelTextFieldWithValueSemantics<T> {
@Override
protected final TextField<T> createTextField(final String id) {
return new TextFieldWithDateTimePicker<T>(
- super.getCommonContext(), id, newTextFieldValueModel(), type, getConverter(scalarModel()));
+ super.getCommonContext(), id, unwrappedModel(), type, getConverter(scalarModel()));
}
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/blobclob/IsisBlobOrClobPanelAbstract.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/blobclob/IsisBlobOrClobPanelAbstract.java
index 4943c46..743bc1d 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/blobclob/IsisBlobOrClobPanelAbstract.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/blobclob/IsisBlobOrClobPanelAbstract.java
@@ -21,7 +21,6 @@ package org.apache.isis.viewer.wicket.ui.components.scalars.blobclob;
import java.util.List;
import java.util.Optional;
-import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Component;
import org.apache.wicket.MarkupContainer;
import org.apache.wicket.ajax.AjaxRequestTarget;
@@ -33,11 +32,12 @@ import org.apache.wicket.markup.html.form.upload.FileUpload;
import org.apache.wicket.markup.html.form.upload.FileUploadField;
import org.apache.wicket.markup.html.image.Image;
import org.apache.wicket.model.IModel;
-import org.apache.wicket.model.Model;
import org.apache.wicket.request.resource.IResource;
+import org.springframework.lang.Nullable;
import org.apache.isis.applib.value.Blob;
import org.apache.isis.applib.value.NamedWithMimeType;
+import org.apache.isis.core.metamodel.render.ScalarRenderMode;
import org.apache.isis.core.metamodel.spec.ManagedObjects;
import org.apache.isis.viewer.wicket.model.models.ScalarModel;
import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelWithFormFieldAbstract;
@@ -47,6 +47,9 @@ import org.apache.isis.viewer.wicket.ui.util.Components;
import org.apache.isis.viewer.wicket.ui.util.Tooltips;
import org.apache.isis.viewer.wicket.ui.util.Wkt;
+import static org.apache.isis.commons.internal.functions._Functions.peek;
+
+import lombok.NonNull;
import lombok.val;
import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.fileinput.BootstrapFileInputField;
@@ -63,15 +66,11 @@ extends ScalarPanelWithFormFieldAbstract<T> {
private static final String ID_SCALAR_IF_COMPACT_DOWNLOAD = "scalarIfCompactDownload";
private Image wicketImage;
-
private FileUploadField fileUploadField;
private Label fileNameLabel;
- protected enum InputFieldVisibility {
- VISIBLE, NOT_VISIBLE
- }
- protected enum InputFieldEditability{
- EDITABLE, NOT_EDITABLE
+ protected IsisBlobOrClobPanelAbstract(final String id, final ScalarModel scalarModel, final Class<T> type) {
+ super(id, scalarModel, type);
}
// generic type mismatch; no issue as long as we don't use conversion
@@ -91,8 +90,8 @@ extends ScalarPanelWithFormFieldAbstract<T> {
} else {
Components.permanentlyHide(formGroup, ID_IMAGE);
}
- updateFileNameLabel(ID_FILE_NAME, formGroup);
- updateDownloadLink(ID_SCALAR_IF_REGULAR_DOWNLOAD, formGroup);
+ createFileNameLabel(ID_FILE_NAME, formGroup);
+ createDownloadLink(ID_SCALAR_IF_REGULAR_DOWNLOAD, formGroup);
}
// //////////////////////////////////////
@@ -105,7 +104,6 @@ extends ScalarPanelWithFormFieldAbstract<T> {
return InlinePromptConfig.notSupported();
}
-
// //////////////////////////////////////
@Override
@@ -120,7 +118,7 @@ extends ScalarPanelWithFormFieldAbstract<T> {
@Override
protected Component createComponentForCompact() {
final MarkupContainer scalarIfCompact = new WebMarkupContainer(ID_SCALAR_IF_COMPACT);
- updateDownloadLink(ID_SCALAR_IF_COMPACT_DOWNLOAD, scalarIfCompact);
+ createDownloadLink(ID_SCALAR_IF_COMPACT_DOWNLOAD, scalarIfCompact);
// if(downloadLink != null) {
// updateFileNameLabel(ID_FILE_NAME_IF_COMPACT, downloadLink);
// Components.permanentlyHide(downloadLink, ID_FILE_NAME_IF_COMPACT);
@@ -128,71 +126,27 @@ extends ScalarPanelWithFormFieldAbstract<T> {
return scalarIfCompact;
}
-
- // //////////////////////////////////////
-
- private Image asWicketImage(final String id) {
-
- val adapter = getModel().getObject();
- if(adapter == null) {
- return null;
- }
-
- val object = adapter.getPojo();
- if(!(object instanceof Blob)) {
- return null;
- }
-
- val blob = (Blob)object;
-
- return WicketImageUtil.asWicketImage(id, blob).orElse(null);
- }
-
-
// //////////////////////////////////////
@Override
protected void onInitializeNotEditable() {
- updateRegularFormComponents(InputFieldVisibility.VISIBLE, InputFieldEditability.NOT_EDITABLE, null, Optional.empty());
+ updateRegularFormComponents(ScalarRenderMode.VIEWING, null, Optional.empty());
}
@Override
protected void onInitializeReadonly(final String disableReason) {
- updateRegularFormComponents(InputFieldVisibility.VISIBLE, InputFieldEditability.NOT_EDITABLE, null, Optional.empty());
+ updateRegularFormComponents(ScalarRenderMode.VIEWING, null, Optional.empty());
}
@Override
protected void onInitializeEditable() {
- updateRegularFormComponents(InputFieldVisibility.VISIBLE, InputFieldEditability.EDITABLE, null, Optional.empty());
+ updateRegularFormComponents(ScalarRenderMode.EDITING, null, Optional.empty());
}
private FileUploadField createFileUploadField(final String componentId) {
- final BootstrapFileInputField fileUploadField = new BootstrapFileInputField(
- componentId, new IModel<List<FileUpload>>() {
-
- private static final long serialVersionUID = 1L;
-
- @Override
- public void setObject(final List<FileUpload> fileUploads) {
- if (fileUploads == null || fileUploads.isEmpty()) {
- return;
- }
+ val fileUploadField = new BootstrapFileInputField(
+ componentId, fileUploadModel());
- val blob = getBlobOrClobFrom(fileUploads);
- val objectAdapter = scalarModel().getCommonContext().getObjectManager().adapt(blob);
- getModel().setObject(objectAdapter);
- }
-
- @Override
- public void detach() {
- }
-
- @Override
- public List<FileUpload> getObject() {
- return null;
- }
-
- });
fileUploadField.getConfig().showUpload(false).mainClass("input-group-sm");
return fileUploadField;
}
@@ -200,19 +154,17 @@ extends ScalarPanelWithFormFieldAbstract<T> {
@Override
protected void onNotEditable(final String disableReason, final Optional<AjaxRequestTarget> target) {
updateRegularFormComponents(
- InputFieldVisibility.VISIBLE, InputFieldEditability.NOT_EDITABLE,
+ ScalarRenderMode.VIEWING,
disableReason, target);
}
@Override
protected void onEditable(final Optional<AjaxRequestTarget> target) {
updateRegularFormComponents(
- InputFieldVisibility.VISIBLE, InputFieldEditability.EDITABLE,
+ ScalarRenderMode.VIEWING,
null, target);
}
- protected abstract T getBlobOrClobFrom(final List<FileUpload> fileUploads);
-
@SuppressWarnings("unchecked")
private Optional<T> getBlobOrClob(final ScalarModel model) {
val adapter = model.getObject();
@@ -220,100 +172,74 @@ extends ScalarPanelWithFormFieldAbstract<T> {
return Optional.ofNullable((T)pojo);
}
- protected IsisBlobOrClobPanelAbstract(final String id, final ScalarModel scalarModel, final Class<T> type) {
- super(id, scalarModel, type);
- }
+ protected abstract IModel<List<FileUpload>> fileUploadModel();
+ protected abstract IResource newResource(final T namedWithMimeType);
+
+ // -- HELPER
private void updateRegularFormComponents(
- final InputFieldVisibility visibility,
- final InputFieldEditability editability,
+ final ScalarRenderMode renderMode,
final String disabledReason,
final Optional<AjaxRequestTarget> target) {
final MarkupContainer formComponent = getComponentForRegular();
- sync(formComponent, visibility, editability, disabledReason, target);
+ setRenderModeOn(formComponent, renderMode, disabledReason, target);
- // sonar-ignore-on (detects potential NPE, which is a false positive here)
- final Component component = formComponent.get(ID_SCALAR_VALUE);
- // sonar-ignore-off
- final InputFieldVisibility editingWidgetVisibility = editability == InputFieldEditability.EDITABLE
- ? InputFieldVisibility.VISIBLE
- : InputFieldVisibility.NOT_VISIBLE;
- sync(component, editingWidgetVisibility, null, disabledReason, target);
+ final Component scalarValueComponent = formComponent.get(ID_SCALAR_VALUE);
+ final ScalarRenderMode editingWidgetVisibility = renderMode.isEditing()
+ ? ScalarRenderMode.EDITING
+ : ScalarRenderMode.HIDING;
+ setRenderModeOn(scalarValueComponent, editingWidgetVisibility, disabledReason, target);
- addAcceptFilterTo(component);
- fileNameLabel = updateFileNameLabel(ID_FILE_NAME, formComponent);
+ addAcceptFilterTo(scalarValueComponent);
+ fileNameLabel = createFileNameLabel(ID_FILE_NAME, formComponent);
- updateClearLink(editingWidgetVisibility, null, target);
+ updateClearLink(editingWidgetVisibility, target);
// the visibility of download link is intentionally 'backwards';
// if in edit mode then do NOT show
- final MarkupContainer downloadLink = updateDownloadLink(ID_SCALAR_IF_REGULAR_DOWNLOAD, formComponent);
- sync(downloadLink, visibility, editability, disabledReason, target);
+ final MarkupContainer downloadLink = createDownloadLink(ID_SCALAR_IF_REGULAR_DOWNLOAD, formComponent);
+ setRenderModeOn(downloadLink, renderMode, disabledReason, target);
// ditto any image
- sync(wicketImage, visibility, editability, disabledReason, target);
+ setRenderModeOn(wicketImage, renderMode, disabledReason, target);
}
- private void sync(
- final Component component,
- final InputFieldVisibility visibility,
- final InputFieldEditability editability,
- final String disabledReason,
- final Optional<AjaxRequestTarget> target) {
-
- if(component == null) {
- return;
- }
- component.setOutputMarkupId(true); // enable ajax link
-
- if(visibility != null) {
- component.setVisible(visibility == InputFieldVisibility.VISIBLE);
- target.ifPresent(ajax->{
- Components.addToAjaxRequest(ajax, component);
- });
-
- }
-
+ private void setRenderModeOn(
+ final @Nullable Component component,
+ final @NonNull ScalarRenderMode renderMode,
+ final @Nullable String disabledReason,
+ final @NonNull Optional<AjaxRequestTarget> target) {
- if(editability != null) {
+ if(component==null) return;
- // // dynamic disablement doesn't yet work, this exception is thrown when form is submitted:
- // //
- // // Caused by: java.lang.IllegalStateException: ServletRequest does not contain multipart content.
- // // One possible solution is to explicitly call Form.setMultipart(true), Wicket tries its best to
- // // auto-detect multipart forms but there are certain situation where it cannot.
- //
- // component.setEnabled(editability == InputFieldEditability.EDITABLE);
- //
- // final AttributeModifier title = new AttributeModifier("title", Model.of(disabledReason != null ? disabledReason : ""));
- // component.add(title);
- //
- // if (target != null) {
- // target.add(component);
- // }
+ component.setOutputMarkupId(true); // enable ajax link
+ component.setVisible(renderMode.isVisible());
+ target.ifPresent(ajax->{
+ Components.addToAjaxRequest(ajax, component);
+ });
- }
- }
+// // dynamic disablement doesn't yet work, this exception is thrown when form is submitted:
+// //
+// // Caused by: java.lang.IllegalStateException: ServletRequest does not contain multipart content.
+// // One possible solution is to explicitly call Form.setMultipart(true), Wicket tries its best to
+// // auto-detect multipart forms but there are certain situation where it cannot.
+//
+// component.setEnabled(editability == InputFieldEditability.EDITABLE);
+//
+// final AttributeModifier title = new AttributeModifier("title", Model.of(disabledReason != null ? disabledReason : ""));
+// component.add(title);
+//
+// if (target != null) {
+// target.add(component);
+// }
- private String getAcceptFilter(){
- return scalarModel().getFileAccept();
}
private void addAcceptFilterTo(final Component component){
- final String filter = getAcceptFilter();
- if(component==null || filter==null || filter.isEmpty())
- return; // ignore
- class AcceptAttributeModel extends Model<String> {
- private static final long serialVersionUID = 1L;
- @Override
- public String getObject() {
- return filter;
- }
- }
- component.add(new AttributeModifier("accept", new AcceptAttributeModel()));
+ Wkt.attributeAppend(component, "accept", scalarModel().getFileAccept());
}
- private Label updateFileNameLabel(final String idFileName, final MarkupContainer formComponent) {
+ private Label createFileNameLabel(final String idFileName, final MarkupContainer formComponent) {
val fileNameLabel = Wkt.labelAdd(formComponent, idFileName, ()->
getBlobOrClobFromModel()
@@ -325,12 +251,10 @@ extends ScalarPanelWithFormFieldAbstract<T> {
}
private void updateClearLink(
- final InputFieldVisibility visibility,
- final InputFieldEditability editability,
+ final ScalarRenderMode renderMode,
final Optional<AjaxRequestTarget> target) {
final MarkupContainer formComponent = getComponentForRegular();
- formComponent.setOutputMarkupId(true); // enable ajax link
final AjaxLink<Void> ajaxLink = Wkt.linkAdd(formComponent, ID_SCALAR_IF_REGULAR_CLEAR, ajaxTarget->{
setEnabled(false);
@@ -343,7 +267,7 @@ extends ScalarPanelWithFormFieldAbstract<T> {
final Optional<T> blobOrClob = getBlobOrClobFromModel();
final Component clearButton = formComponent.get(ID_SCALAR_IF_REGULAR_CLEAR);
- clearButton.setVisible(blobOrClob.isPresent() && visibility == InputFieldVisibility.VISIBLE);
+ clearButton.setVisible(blobOrClob.isPresent() && renderMode.isVisible());
clearButton.setEnabled(blobOrClob.isPresent());
target.ifPresent(ajax->{
@@ -354,33 +278,27 @@ extends ScalarPanelWithFormFieldAbstract<T> {
}
- private MarkupContainer updateDownloadLink(final String downloadId, final MarkupContainer parent) {
- val resourceLink = createResourceLink(downloadId);
- if(resourceLink != null) {
- parent.addOrReplace(resourceLink);
- Tooltips.addTooltip(resourceLink, "download");
- } else {
- Components.permanentlyHide(parent, downloadId);
- }
- return resourceLink;
- }
-
- private ResourceLinkVolatile createResourceLink(final String id) {
+ private MarkupContainer createDownloadLink(final String id, final MarkupContainer parent) {
return getBlobOrClobFromModel()
.map(this::newResource)
- .map(resource->new ResourceLinkVolatile(id, resource))
- .orElse(null);
+ .map(resource->Wkt.downloadLinkNoCache(id, resource))
+ .map(peek(downloadLink->{
+ parent.addOrReplace(downloadLink);
+ Tooltips.addTooltip(downloadLink, "download");
+ }))
+ .orElseGet(()->{
+ Components.permanentlyHide(parent, id);
+ return null;
+ });
}
private Optional<T> getBlobOrClobFromModel() {
return getBlobOrClob(getModel());
}
-
- /**
- * Mandatory hook method.
- */
- protected abstract IResource newResource(final T namedWithMimeType);
-
+ private Image asWicketImage(final String id) {
+ val blob = scalarModel().unwrapped(Blob.class).getObject();
+ return WicketImageUtil.asWicketImage(id, blob).orElse(null);
+ }
}
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/blobclob/IsisBlobPanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/blobclob/IsisBlobPanel.java
index 9f27f73..583ccc9 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/blobclob/IsisBlobPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/blobclob/IsisBlobPanel.java
@@ -22,10 +22,12 @@ package org.apache.isis.viewer.wicket.ui.components.scalars.blobclob;
import java.util.List;
import org.apache.wicket.markup.html.form.upload.FileUpload;
+import org.apache.wicket.model.IModel;
import org.apache.wicket.request.resource.ByteArrayResource;
import org.apache.wicket.request.resource.IResource;
import org.apache.isis.applib.value.Blob;
+import org.apache.isis.viewer.wicket.model.models.FileUploadModels;
import org.apache.isis.viewer.wicket.model.models.ScalarModel;
/**
@@ -39,15 +41,9 @@ public class IsisBlobPanel extends IsisBlobOrClobPanelAbstract<Blob> {
super(id, model, Blob.class);
}
-
@Override
- protected Blob getBlobOrClobFrom(final List<FileUpload> fileUploads) {
- final FileUpload fileUpload = fileUploads.get(0);
- final String contentType = fileUpload.getContentType();
- final String clientFileName = fileUpload.getClientFileName();
- final byte[] bytes = fileUpload.getBytes();
- final Blob blob = new Blob(clientFileName, contentType, bytes);
- return blob;
+ protected IModel<List<FileUpload>> fileUploadModel() {
+ return FileUploadModels.blob(scalarModel());
}
@Override
@@ -55,6 +51,4 @@ public class IsisBlobPanel extends IsisBlobOrClobPanelAbstract<Blob> {
return new ByteArrayResource(blob.getMimeType().getBaseType(), blob.getBytes(), blob.getName());
}
-
-
}
\ No newline at end of file
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/blobclob/IsisClobPanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/blobclob/IsisClobPanel.java
index f6c5aca..e41fb3b 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/blobclob/IsisClobPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/blobclob/IsisClobPanel.java
@@ -19,22 +19,23 @@
package org.apache.isis.viewer.wicket.ui.components.scalars.blobclob;
-import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;
import org.apache.wicket.markup.html.form.upload.FileUpload;
+import org.apache.wicket.model.IModel;
import org.apache.wicket.request.resource.CharSequenceResource;
import org.apache.wicket.request.resource.IResource;
import org.apache.isis.applib.value.Clob;
+import org.apache.isis.viewer.wicket.model.models.FileUploadModels;
import org.apache.isis.viewer.wicket.model.models.ScalarModel;
/**
- * Panel for rendering scalars of type {@link Clob Isis' applib.Clob}.
+ * Panel for rendering scalars of type {@link Clob}.
*
* <p>
- * TODO: for now, this only handles CLOBs encoded as UTF-8.
+ * TODO: for now, this only handles {@link Clob}s encoded as UTF-8.
* One option might be to 'guess' the character encoding, eg akin to cpdetector?
* </p>
*/
@@ -42,20 +43,13 @@ public class IsisClobPanel extends IsisBlobOrClobPanelAbstract<Clob> {
private static final long serialVersionUID = 1L;
- private static final Charset CHARSET = StandardCharsets.UTF_8;
-
public IsisClobPanel(final String id, final ScalarModel model) {
super(id, model, Clob.class);
}
@Override
- protected Clob getBlobOrClobFrom(final List<FileUpload> fileUploads) {
- final FileUpload fileUpload = fileUploads.get(0);
- final String contentType = fileUpload.getContentType();
- final String clientFileName = fileUpload.getClientFileName();
- final String str = new String(fileUpload.getBytes(), CHARSET);
- final Clob blob = new Clob(clientFileName, contentType, str);
- return blob;
+ protected IModel<List<FileUpload>> fileUploadModel() {
+ return FileUploadModels.clob(scalarModel(), StandardCharsets.UTF_8);
}
@Override
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/passwd/IsisPasswordPanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/passwd/IsisPasswordPanel.java
index 33ba480..c81a7fb 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/passwd/IsisPasswordPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/passwd/IsisPasswordPanel.java
@@ -40,7 +40,7 @@ extends ScalarPanelTextFieldWithValueSemantics<Password> {
@Override
protected AbstractTextComponent<Password> createTextField(final String id) {
return Wkt.passwordFieldWithConverter(
- id, newTextFieldValueModel(), type, getConverter(getModel()));
+ id, unwrappedModel(), type, getConverter(scalarModel()));
}
}
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/blobclob/ResourceLinkVolatile.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/util/ResourceLinkVolatile.java
similarity index 97%
rename from viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/blobclob/ResourceLinkVolatile.java
rename to viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/util/ResourceLinkVolatile.java
index 02147f3..ee77e44 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/blobclob/ResourceLinkVolatile.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/util/ResourceLinkVolatile.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.isis.viewer.wicket.ui.components.scalars.blobclob;
+package org.apache.isis.viewer.wicket.ui.util;
import java.util.UUID;
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/util/Wkt.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/util/Wkt.java
index 36e3123..4623bc0 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/util/Wkt.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/util/Wkt.java
@@ -47,6 +47,7 @@ import org.apache.wicket.markup.html.panel.Fragment;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.markup.repeater.OddEvenItem;
import org.apache.wicket.model.IModel;
+import org.apache.wicket.request.resource.IResource;
import org.apache.wicket.request.resource.ResourceReference;
import org.apache.wicket.util.convert.IConverter;
import org.apache.wicket.validation.IValidationError;
@@ -92,6 +93,24 @@ public class Wkt {
return component;
}
+ // -- ATTRIBUTES
+
+ /**
+ * If any argument is null or empty, does nothing.
+ */
+ public <T extends Component> T attributeAppend(
+ final @Nullable T component,
+ final @Nullable String attributeName,
+ final @Nullable String attributeValue) {
+ if(component==null
+ || _Strings.isEmpty(attributeName)
+ || _Strings.isEmpty(attributeValue)) {
+ return component;
+ }
+ component.add(new AttributeModifier(attributeName, attributeValue));
+ return component;
+ }
+
// -- BEHAVIOR
public Behavior behaviorOnClick(final SerializableConsumer<AjaxRequestTarget> onClick) {
@@ -373,6 +392,12 @@ public class Wkt {
: cssClass.replaceAll("\\.", "-").replaceAll("[^A-Za-z0-9- ]", "").replaceAll("\\s+", "-");
}
+ // -- DOWNLOAD (RESOURCE LINK)
+
+ public ResourceLinkVolatile downloadLinkNoCache(final String id, final IResource resourceModel) {
+ return new ResourceLinkVolatile(id, resourceModel);
+ }
+
// -- FRAGMENT
/**
@@ -709,4 +734,5 @@ public class Wkt {
}
}
+
}