You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2017/04/21 18:16:27 UTC

[5/5] isis git commit: ISIS-1603: working on validation, not there yet

ISIS-1603: working on validation, not there yet


Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/341037c1
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/341037c1
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/341037c1

Branch: refs/heads/ISIS-1603-reapply
Commit: 341037c13bf747bc384d325ffcd1fbf63c74b073
Parents: 634ea9b
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Fri Apr 21 19:15:51 2017 +0100
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Fri Apr 21 19:15:51 2017 +0100

----------------------------------------------------------------------
 .../scalars/ScalarPanelTextFieldAbstract.html   |  42 ++++-
 .../scalars/ScalarPanelTextFieldAbstract.java   | 173 +++++++++++++++++--
 .../components/scalars/XEditableBehavior2.java  |  84 +++++++++
 3 files changed, 285 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/341037c1/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.html
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.html b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.html
index 7bbfcf0..a05f536 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.html
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.html
@@ -27,16 +27,52 @@
             <wicket:container wicket:id="scalarValueContainer"/>
 
             <wicket:fragment wicket:id="text">
-                <input type="text" name="scalarValue" class="form-control input-sm scalarValue" wicket:id="scalarValue" />
+                <input
+                        type="text"
+                        name="scalarValue"
+                        class="form-control input-sm scalarValue"
+                        wicket:id="scalarValue" />
+                <a
+                        href="#"
+                        data-type="text"
+                        name="scalarValueEditInline"
+                        class="form-control input-sm scalarValueEditInline"
+                        wicket:id="scalarValueEditInline">
+                    <span wicket:id="scalarValueEditInlineLabel"></span>
+                </a>
             </wicket:fragment>
 
             <wicket:fragment wicket:id="textarea">
-                <textarea name="scalarValue" class="form-control scalarValue" wicket:id="scalarValue"></textarea>
+                <textarea
+                        name="scalarValue"
+                        class="form-control scalarValue"
+                        wicket:id="scalarValue">
+                </textarea>
+                <a
+                        href="#"
+                        data-type="textarea"
+                        name="scalarValueEditInline"
+                        class="form-control input-sm scalarValueEditInline"
+                        wicket:id="scalarValueEditInline"
+                        style="height: auto"
+                ><span wicket:id="scalarValueEditInlineLabel"></span></a>
             </wicket:fragment>
 
             <wicket:fragment wicket:id="date">
                 <div class="date">
-                    <input type="text" name="scalarValue" wicket:id="scalarValue" class="form-control input-sm scalarValue"/>
+                    <input
+                            type="text"
+                            name="scalarValue"
+                            class="form-control input-sm scalarValue"
+                            wicket:id="scalarValue"/>
+                    <a
+                            data-type="combodate"
+                            href="#"
+                            name="scalarValueEditInline"
+                            class="form-control input-sm scalarValueEditInline"
+                            wicket:id="scalarValueEditInline">
+                        <span wicket:id="scalarValueEditInlineLabel"></span>
+                    </a>
                 </div>
             </wicket:fragment>
 

http://git-wip-us.apache.org/repos/asf/isis/blob/341037c1/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java
index fd371d6..7dea2c3 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java
@@ -27,6 +27,10 @@ import com.google.common.base.Strings;
 import org.apache.wicket.AttributeModifier;
 import org.apache.wicket.Component;
 import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.ajax.AjaxEventBehavior;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.attributes.AjaxCallListener;
+import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
 import org.apache.wicket.behavior.Behavior;
 import org.apache.wicket.markup.ComponentTag;
 import org.apache.wicket.markup.html.WebMarkupContainer;
@@ -36,17 +40,19 @@ import org.apache.wicket.markup.html.form.TextField;
 import org.apache.wicket.markup.html.panel.Fragment;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.Model;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.util.string.StringValue;
 import org.apache.wicket.validation.IValidatable;
 import org.apache.wicket.validation.IValidator;
 import org.apache.wicket.validation.ValidationError;
-import org.apache.wicket.validation.validator.StringValidator;
 
+import org.apache.isis.applib.annotation.PropertyEditStyle;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
 import org.apache.isis.core.metamodel.facets.SingleIntValueFacet;
 import org.apache.isis.core.metamodel.facets.all.named.NamedFacet;
 import org.apache.isis.core.metamodel.facets.objectvalue.maxlen.MaxLengthFacet;
 import org.apache.isis.core.metamodel.facets.objectvalue.typicallen.TypicalLengthFacet;
-import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.viewer.wicket.model.isis.WicketViewerSettings;
 import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
@@ -54,6 +60,11 @@ import org.apache.isis.viewer.wicket.ui.components.actionmenu.entityactions.Enti
 import org.apache.isis.viewer.wicket.ui.components.widgets.bootstrap.FormGroup;
 import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;
 
+import de.agilecoders.wicket.extensions.markup.html.bootstrap.xeditable.XEditableBehavior;
+import de.agilecoders.wicket.extensions.markup.html.bootstrap.xeditable.XEditableOptions;
+import de.agilecoders.wicket.jquery.Key;
+import de.agilecoders.wicket.jquery.util.Json;
+
 /**
  * Adapter for {@link ScalarPanelAbstract scalar panel}s that are implemented
  * using a simple {@link TextField}.
@@ -79,6 +90,7 @@ public abstract class ScalarPanelTextFieldAbstract<T extends Serializable> exten
 
     protected WebMarkupContainer scalarTypeContainer;
     private AbstractTextComponent<T> textField;
+    private WebMarkupContainer editInlineLink;
 
     public ScalarPanelTextFieldAbstract(final String id, final ScalarModel scalarModel, final Class<T> cls) {
         super(id, scalarModel);
@@ -95,6 +107,13 @@ public abstract class ScalarPanelTextFieldAbstract<T extends Serializable> exten
 
     }
 
+    private Component getEditComponent() {
+        return textField.isVisibilityAllowed()
+                ? textField
+                : editInlineLink;
+    }
+
+
     AbstractTextComponent<T> getTextField() {
         return textField;
     }
@@ -113,8 +132,132 @@ public abstract class ScalarPanelTextFieldAbstract<T extends Serializable> exten
 
     @Override
     protected MarkupContainer addComponentForRegular() {
+
+        // even though only one of textField and editInlineLink will ever be visible,
+        // am instantiating both to avoid NPEs
+        // elsewhere can use Component#isVisibilityAllowed or ScalarModel.getEditStyle() to check whichis visible.
+
         textField = createTextFieldForRegular(ID_SCALAR_VALUE);
         textField.setOutputMarkupId(true);
+        editInlineLink = new WebMarkupContainer(ID_SCALAR_VALUE_EDIT_INLINE);
+        editInlineLink.setOutputMarkupId(true);
+
+        final IModel<T> textFieldModel = textField.getModel();
+
+        final Label editInlineLinkLabel = new Label(ID_SCALAR_VALUE_EDIT_INLINE_LABEL, textFieldModel);
+        editInlineLink.add(editInlineLinkLabel);
+
+        if(scalarModel.getEditStyle() == PropertyEditStyle.INLINE) {
+            textField.setVisibilityAllowed(false);
+
+            final XEditableOptions options = new XEditableOptions() {
+                {
+                    put(new Key<String>("toggle"), "click");
+                    if(scalarModel.isRequired()) {
+                        put(new Key<Json.RawValue>("validate"), new Json.RawValue(
+                                "function (value) { if (value == '') { return 'Required field'; } }"));
+                    }
+//                    put(new Key<Json.RawValue>("error"), new Json.RawValue(
+//                            "function(response, newValue) {\n"
+//                                    + "    if(response.status === 500) {\n"
+//                                    + "        return 'Service unavailable. Please try later.';\n"
+//                                    + "    } else {\n"
+//                                    + "        return response.responseText;\n"
+//                                    + "    }\n"
+//                                    + "}"));
+
+                }
+            }.withMode("inline");
+
+            options.withDefaultValue(asString(textFieldModel));
+
+            XEditableBehavior xEditable = new XEditableBehavior(options) {
+                @Override
+                protected void onSave(final AjaxRequestTarget target, final String value) {
+
+                    scalarModel.setObjectAsString(value);
+
+                    ObjectAdapter adapter = scalarModel.getParentObjectAdapterMemento()
+                            .getObjectAdapter(AdapterManager.ConcurrencyChecking.NO_CHECK, getPersistenceSession(),
+                                    getSpecificationLoader());
+
+                    scalarModel.applyValue(adapter);
+
+                    target.add(editInlineLink);
+
+                    options.withDefaultValue(asString(textFieldModel));
+                }
+
+                protected AjaxEventBehavior newSaveListener() {
+                    return new AjaxEventBehavior("save") {
+                        @Override
+                        protected void onEvent(AjaxRequestTarget target) {
+
+                            final ObjectAdapter currentValue = scalarModel.getObject();
+                            StringValue newValue = RequestCycle.get().getRequest().getRequestParameters().getParameterValue("newValue");
+
+                            try {
+                                onSave(target, newValue.toString());
+                            } catch (Exception ex) {
+                                scalarModel.setObject(currentValue);
+
+                                final String value = asString(textFieldModel);
+                                options.withDefaultValue(value);
+
+                                //
+                                // hmmm... thought had this working, but turns out that can't rely on the .control-group to exist
+                                //
+                                // also: even if get going, still need to reset the value of the inline edit, and also
+                                // to handle updates to the title (eg Wicket event bus, I think)
+                                //
+                                final String message = ex.getMessage();
+                                target.appendJavaScript(
+                                        "( function() { "
+                                                + "var component = $(\"#" + editInlineLink.getMarkupId() + "\"); "
+                                                + "var parent = $(component).parent(); "
+
+                                                + "var controlGroup = $(parent).find(\".control-group\"); "
+                                                + "var errorBlock = $(parent).find(\".editable-error-block\"); "
+
+                                                + "$(component).editable(\"show\"); "
+                                                + "$(controlGroup).addClass(\"has-error\"); "
+                                                + "$(errorBlock).css(\"display\", \"block\"); "
+                                                + "$(errorBlock).text(\"" + message + "\"); "
+
+                                        + "} )();");
+                            }
+
+                        }
+
+                        @Override
+                        protected void updateAjaxAttributes(AjaxRequestAttributes attributes) {
+                            super.updateAjaxAttributes(attributes);
+                            attributes.getDynamicExtraParameters().add("return [{'name':'newValue', 'value': attrs.event.extraData.newValue}]");
+
+                            AjaxCallListener myAjaxCallListener = new AjaxCallListener() {
+
+                                @Override
+                                public CharSequence getBeforeHandler(Component component) {
+                                    return ""; // "var myEl = $(\"#" + component.getMarkupId() + "\"); console.log(myEl);";
+                                }
+
+                                @Override public CharSequence getFailureHandler(final Component component) {
+                                    return "alert(\"failure!!!\")";
+                                }
+                            };
+                            attributes.getAjaxCallListeners().add(myAjaxCallListener);
+
+                        }
+                    };
+                }
+
+            };
+
+
+            editInlineLink.add(xEditable);
+        } else {
+            editInlineLink.setVisibilityAllowed(false);
+        }
 
         addStandardSemantics();
 
@@ -147,7 +290,8 @@ public abstract class ScalarPanelTextFieldAbstract<T extends Serializable> exten
             labelIfRegular.add(new AttributeModifier("title", Model.of(describedAs)));
         }
 
-        addFeedbackOnlyTo(labelIfRegular, textField);
+        addFeedbackOnlyTo(labelIfRegular, getEditComponent());
+
         addEditPropertyTo(labelIfRegular);
 
         // ... add entity links to panel (below and to right)
@@ -156,6 +300,10 @@ public abstract class ScalarPanelTextFieldAbstract<T extends Serializable> exten
         return labelIfRegular;
     }
 
+    private String asString(final IModel<T> textFieldModel) {
+        return textFieldModel != null && textFieldModel.getObject() != null ? textFieldModel.getObject().toString() : null;
+    }
+
     protected abstract IModel<String> getScalarPanelType();
 
     private void addReplaceDisabledTagWithReadonlyTagBehaviourIfRequired(final Component component) {
@@ -181,6 +329,8 @@ public abstract class ScalarPanelTextFieldAbstract<T extends Serializable> exten
         textFieldFragment.add(this.textField);
         scalarNameAndValue.add(textFieldFragment);
 
+        textFieldFragment.add(this.editInlineLink);
+
         return scalarNameAndValue;
     }
 
@@ -265,12 +415,6 @@ public abstract class ScalarPanelTextFieldAbstract<T extends Serializable> exten
         textField.setEnabled(false);
         addReplaceDisabledTagWithReadonlyTagBehaviourIfRequired(textField);
 
-        final String disableReasonIfAny = scalarModel.disable(getRendering().getWhere());
-        if(disableReasonIfAny == null) {
-            CssClassAppender.appendCssClassTo(this, "editable");
-        }
-
-
         setTitleAttribute("");
     }
 
@@ -278,6 +422,7 @@ public abstract class ScalarPanelTextFieldAbstract<T extends Serializable> exten
     protected void onBeforeRenderWhenDisabled(final String disableReason) {
         super.onBeforeRenderWhenDisabled(disableReason);
         textField.setEnabled(false);
+        editInlineLink.setEnabled(false);
         addReplaceDisabledTagWithReadonlyTagBehaviourIfRequired(textField);
         setTitleAttribute(disableReason);
     }
@@ -286,16 +431,22 @@ public abstract class ScalarPanelTextFieldAbstract<T extends Serializable> exten
     protected void onBeforeRenderWhenEnabled() {
         super.onBeforeRenderWhenEnabled();
         textField.setEnabled(true);
+        editInlineLink.setEnabled(true);
         setTitleAttribute("");
     }
 
     private void setTitleAttribute(final String titleAttribute) {
-        textField.add(new AttributeModifier("title", Model.of(titleAttribute)));
+        AttributeModifier title = new AttributeModifier("title", Model.of(titleAttribute));
+        textField.add(title);
+        editInlineLink.add(title);
     }
 
     @Override
     protected void addFormComponentBehavior(Behavior behavior) {
-        textField.add(behavior);
+
+        // some behaviours can only be attached to one component
+        // so we check as to which will actually be visible.
+        getEditComponent().add(behavior);
     }
 
 

http://git-wip-us.apache.org/repos/asf/isis/blob/341037c1/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/XEditableBehavior2.java
----------------------------------------------------------------------
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/XEditableBehavior2.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/XEditableBehavior2.java
new file mode 100644
index 0000000..d8bf40b
--- /dev/null
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/XEditableBehavior2.java
@@ -0,0 +1,84 @@
+/*
+ *  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.ui.components.scalars;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.ajax.AjaxEventBehavior;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.util.string.StringValue;
+
+import de.agilecoders.wicket.extensions.markup.html.bootstrap.xeditable.XEditableBehavior;
+
+public class XEditableBehavior2 extends XEditableBehavior {
+
+    private AjaxEventBehavior validateListener;
+
+    /**
+     * Fired when new value for validation.
+     */
+    protected void onValidate(AjaxRequestTarget target, String value) {
+
+    }
+
+
+    @Override
+    public void bind(Component component) {
+        super.bind(component);
+        validateListener = newSaveListener();
+        component.add(validateListener);
+    }
+
+    @Override
+    public void unbind(Component component) {
+        component.remove(validateListener);
+        validateListener = null;
+
+        super.unbind(component);
+    }
+
+    protected AjaxEventBehavior newValidateListener() {
+        return new AjaxEventBehavior("validate") {
+
+            /**
+             * what's bound to "validate" event in Javascript, and sent to the server
+             */
+            @Override
+            protected void updateAjaxAttributes(AjaxRequestAttributes attributes) {
+                super.updateAjaxAttributes(attributes);
+                attributes.getDynamicExtraParameters().add("return [{'name':'newValue', 'value': attrs.event.extraData.newValue}]");
+            }
+
+            /**
+             * What's received at the server
+             */
+            @Override
+            protected void onEvent(AjaxRequestTarget target) {
+                StringValue newValue = RequestCycle.get().getRequest().getRequestParameters().getParameterValue("newValue");
+                onValidate(target, newValue.toString());
+            }
+
+        };
+    }
+
+
+
+}