You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by hn...@apache.org on 2021/01/22 12:19:38 UTC

[myfaces-tobago] 01/02: fix: SelectOneChoice inside input group

This is an automated email from the ASF dual-hosted git repository.

hnoeth pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git

commit 08b8dc3a743b78d07d6d15669b7280d71d1bf3dc
Author: Henning Noeth <hn...@apache.org>
AuthorDate: Mon Jan 18 15:28:30 2021 +0100

    fix: SelectOneChoice inside input group
    
    * add a getComponentCss() method for LabelLayoutRendererBase
    * selectOneChoice is now rendered with surrounding container (tobago-select-one-choice) inside input group
    * fix styling
    * adjust unit test
    * implement jasmine test
---
 tobago-core/npm/scss/_tobago.scss                  |  21 ++++
 .../renderer/LabelLayoutRendererBase.java          |  10 +-
 .../renderer/SelectOneChoiceRenderer.java          |  22 ++--
 .../renderer/in/input-group-choice-after.html      |  14 ++-
 .../010-input/50-input-group/Group.test.js         | 134 +++++++++------------
 5 files changed, 103 insertions(+), 98 deletions(-)

diff --git a/tobago-core/npm/scss/_tobago.scss b/tobago-core/npm/scss/_tobago.scss
index 10ad37d..12e9da7 100644
--- a/tobago-core/npm/scss/_tobago.scss
+++ b/tobago-core/npm/scss/_tobago.scss
@@ -452,6 +452,27 @@ tobago-header {
 /* in ----------------------------------------------------------- */
 tobago-in {
   display: block;
+
+  .input-group {
+
+    tobago-select-one-choice {
+      /* fix style for surrounding container (tobago-select-one-choice).
+      According to bootstrap docs, <select class=.form-select> should be rendered directly to .input-group. But tobago
+      renders the tobago-select-one-choice custom tag (which contain the select component) inside an input group. */
+
+      &.tobago-margin-bottom {
+        margin-bottom: 0;
+      }
+
+      &.form-select {
+        padding: 0;
+
+        > .form-select {
+          border: 0;
+        }
+      }
+    }
+  }
 }
 
 .tobago-in {
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LabelLayoutRendererBase.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LabelLayoutRendererBase.java
index 1ce106f..33ed746 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LabelLayoutRendererBase.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LabelLayoutRendererBase.java
@@ -29,6 +29,7 @@ import org.apache.myfaces.tobago.internal.util.HtmlRendererUtils;
 import org.apache.myfaces.tobago.internal.util.StringUtils;
 import org.apache.myfaces.tobago.renderkit.LabelWithAccessKey;
 import org.apache.myfaces.tobago.renderkit.css.BootstrapClass;
+import org.apache.myfaces.tobago.renderkit.css.CssItem;
 import org.apache.myfaces.tobago.renderkit.css.TobagoClass;
 import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
 import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
@@ -49,6 +50,10 @@ public abstract class LabelLayoutRendererBase<T extends UIComponent & SupportsLa
 
   public abstract HtmlElements getComponentTag();
 
+  protected CssItem[] getComponentCss(final FacesContext facesContext, final T command) {
+    return null;
+  }
+
   @Override
   public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
 
@@ -152,7 +157,8 @@ public abstract class LabelLayoutRendererBase<T extends UIComponent & SupportsLa
       writer.startElement(getComponentTag());
       writer.writeIdAttribute(clientId);
       writer.writeClassAttribute(
-          flex ? TobagoClass.LABEL__CONTAINER :  null,
+          flex ? TobagoClass.LABEL__CONTAINER : null,
+          getComponentCss(facesContext, component),
           TobagoClass.MARGIN__BOTTOM,
           ComponentUtils.getBooleanAttribute(component, Attributes.required) ? TobagoClass.REQUIRED : null,
           markup != null && markup.contains(Markup.SPREAD) ? TobagoClass.SPREAD : null);
@@ -224,7 +230,7 @@ public abstract class LabelLayoutRendererBase<T extends UIComponent & SupportsLa
   }
 
   protected void encodeLabel(final FacesContext facesContext, final T component,
-                             final TobagoResponseWriter writer, final LabelLayout labelLayout)
+      final TobagoResponseWriter writer, final LabelLayout labelLayout)
       throws IOException {
     // TBD: maybe use an interface for getLabel()
     final String label = ComponentUtils.getStringAttribute(component, Attributes.label);
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneChoiceRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneChoiceRenderer.java
index d839dd8..6804e79 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneChoiceRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneChoiceRenderer.java
@@ -24,6 +24,7 @@ import org.apache.myfaces.tobago.internal.component.AbstractUISelectOneChoice;
 import org.apache.myfaces.tobago.internal.util.HtmlRendererUtils;
 import org.apache.myfaces.tobago.internal.util.SelectItemUtils;
 import org.apache.myfaces.tobago.renderkit.css.BootstrapClass;
+import org.apache.myfaces.tobago.renderkit.css.CssItem;
 import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
 import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.util.ComponentUtils;
@@ -41,21 +42,18 @@ public class SelectOneChoiceRenderer<T extends AbstractUISelectOneChoice> extend
   }
 
   @Override
+  protected CssItem[] getComponentCss(final FacesContext facesContext, final T command) {
+    return isInside(facesContext, HtmlElements.TOBAGO_IN) ? new CssItem[]{BootstrapClass.FORM_SELECT} : null;
+  }
+
+  @Override
   public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
-    if (isInside(facesContext, HtmlElements.TOBAGO_IN)) {
-      encodeBeginField(facesContext, component);
-    } else {
-      super.encodeBeginInternal(facesContext, component);
-    }
+    super.encodeBeginInternal(facesContext, component);
   }
 
   @Override
   public void encodeEndInternal(final FacesContext facesContext, final T component) throws IOException {
-    if (isInside(facesContext, HtmlElements.TOBAGO_IN)) {
-      encodeEndField(facesContext, component);
-    } else {
-      super.encodeEndInternal(facesContext, component);
-    }
+    super.encodeEndInternal(facesContext, component);
   }
 
   @Override
@@ -105,8 +103,6 @@ public class SelectOneChoiceRenderer<T extends AbstractUISelectOneChoice> extend
 
   @Override
   protected String getFieldId(final FacesContext facesContext, final T component) {
-    return isInside(facesContext, HtmlElements.TOBAGO_IN)
-        ? component.getClientId(facesContext)
-        : component.getFieldId(facesContext);
+    return component.getFieldId(facesContext);
   }
 }
diff --git a/tobago-core/src/test/resources/renderer/in/input-group-choice-after.html b/tobago-core/src/test/resources/renderer/in/input-group-choice-after.html
index ee030ff..d85c6e7 100644
--- a/tobago-core/src/test/resources/renderer/in/input-group-choice-after.html
+++ b/tobago-core/src/test/resources/renderer/in/input-group-choice-after.html
@@ -19,11 +19,13 @@
   <div class='tobago-input-group-outer'>
     <div class='input-group'>
       <input type='text' name='id' id='id::field' class='tobago-in form-control'>
-      <select id='choice' name='choice' class='form-select'>
-        <option value=''>Stratocaster
-        </option>
-        <option value=''>Telecaster
-        </option></select>
+      <tobago-select-one-choice id='choice' class='form-select tobago-margin-bottom'>
+        <select id='choice::field' name='choice' class='form-select'>
+          <option value=''>Stratocaster
+          </option>
+          <option value=''>Telecaster
+          </option></select>
+      </tobago-select-one-choice>
     </div>
   </div>
-</tobago-in>
\ No newline at end of file
+</tobago-in>
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/010-input/50-input-group/Group.test.js b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/010-input/50-input-group/Group.test.js
index 10e7fad..851b425 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/010-input/50-input-group/Group.test.js
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/010-input/50-input-group/Group.test.js
@@ -16,51 +16,34 @@
  */
 
 import {JasmineTestTool} from "/tobago/test/tobago-test-tool.js";
-
-it("not implemented yet", function (done) {
-  let test = new JasmineTestTool(done);
-  test.do(() => fail("not implemented yet"));
-  test.start();
-});
-
-/*
 import {querySelectorAllFn, querySelectorFn} from "/script/tobago-test.js";
-import {TobagoTestTool} from "/tobago/test/tobago-test-tool.js";
 
-QUnit.test("ajax: chat send button", function (assert) {
+it("ajax: chat send button", function (done) {
   let chatlogFn = querySelectorFn("#page\\:mainForm\\:tachatlog\\:\\:field");
   let inputFn = querySelectorFn("#page\\:mainForm\\:inewmessage\\:\\:field");
   let sendButtonFn = querySelectorFn("#page\\:mainForm\\:sendButton");
 
-  let TTT = new TobagoTestTool(assert);
-  TTT.action(function () {
-    inputFn().value = "delete chat";
-    sendButtonFn().dispatchEvent(new Event("click", {bubbles: true}));
-  });
-  TTT.waitForResponse();
-  TTT.asserts(1, function () {
-    assert.equal(chatlogFn().textContent, "");
-  });
-  TTT.action(function () {
-    inputFn().value = "Hi Peter, how are you?";
-    sendButtonFn().dispatchEvent(new Event("click", {bubbles: true}));
-  });
-  TTT.waitForResponse();
-  TTT.asserts(1, function () {
-    assert.equal(chatlogFn().textContent, "User Two: Hi Peter, how are you?");
-  });
-  TTT.startTest();
+  const test = new JasmineTestTool(done);
+  test.setup(() => chatlogFn().textContent === "",
+      () => inputFn().value = "delete chat",
+      "click", sendButtonFn);
+  test.do(() => expect(chatlogFn().textContent).toBe(""));
+  test.do(() => inputFn().value = "Hi Peter, how are you?");
+  test.event("click", sendButtonFn, () => chatlogFn().textContent === "User Two: Hi Peter, how are you?");
+  test.do(() => expect(chatlogFn().textContent).toBe("User Two: Hi Peter, how are you?"));
+  test.start();
 });
 
-QUnit.test("ajax: dropdown button", function (assert) {
+it("ajax: dropdown button", function (done) {
   let buttonFn = querySelectorFn("#page\\:mainForm\\:lsendtoc\\:\\:command");
   let buttonLabelFn = querySelectorFn("#page\\:mainForm\\:lsendtoc\\:\\:command span");
   let sendToPeterFn = querySelectorFn("#page\\:mainForm\\:sendToPeter");
   let sendToBobFn = querySelectorFn("#page\\:mainForm\\:sendToBob");
   let sendToAllFn = querySelectorFn("#page\\:mainForm\\:sendToAll");
 
-  let TTT = new TobagoTestTool(assert);
-  TTT.action(function () {
+  const test = new JasmineTestTool(done);
+  test.do(() => fail("not implemented yet; fix dropdown first"));
+  /*TTT.action(function () {
     buttonFn().dispatchEvent(new Event("click", {bubbles: true}));
     sendToPeterFn().dispatchEvent(new Event("click", {bubbles: true}));
   });
@@ -83,53 +66,50 @@ QUnit.test("ajax: dropdown button", function (assert) {
   TTT.waitForResponse();
   TTT.asserts(1, function () {
     assert.equal(buttonLabelFn().textContent, "SendTo: All");
-  });
-  TTT.startTest();
+  });*/
+  test.start();
 });
 
-QUnit.test("ajax: currency change event", function (assert) {
-  let currencyInputFn = querySelectorFn("#page\\:mainForm\\:value\\:\\:field");
-  let currencyFn = querySelectorFn("#page\\:mainForm\\:currency");
-  let currencyOptionFn = querySelectorAllFn("#page\\:mainForm\\:currency option");
-  let outputFieldFn = querySelectorFn("#page\\:mainForm\\:valueInEuro .tobago-out");
+it("ajax: currency change event", function (done) {
+  let inputFn = querySelectorFn("#page\\:mainForm\\:value\\:\\:field");
+  let selectFn = querySelectorFn("#page\\:mainForm\\:currency\\:\\:field");
+  let optionsFn = querySelectorAllFn("#page\\:mainForm\\:currency option");
+  let outputFn = querySelectorFn("#page\\:mainForm\\:valueInEuro tobago-out");
 
-  let TTT = new TobagoTestTool(assert);
-  TTT.action(function () {
-    currencyInputFn().value = "1000";
-    currencyOptionFn().item(1).selected = false;
-    currencyOptionFn().item(2).selected = false;
-    currencyOptionFn().item(3).selected = false;
-    currencyOptionFn().item(0).selected = true; // Yen
-    currencyFn().dispatchEvent(new Event("change", {bubbles: true}));
-  });
-  TTT.waitForResponse();
-  TTT.asserts(1, function () {
-    assert.equal(outputFieldFn().textContent, "8,85");
-  });
-  TTT.action(function () {
-    currencyInputFn().value = "2000";
-    currencyOptionFn().item(0).selected = false;
-    currencyOptionFn().item(2).selected = false;
-    currencyOptionFn().item(3).selected = false;
-    currencyOptionFn().item(1).selected = true; // Trinidad-Tobago Dollar
-    currencyFn().dispatchEvent(new Event("change", {bubbles: true}));
-  });
-  TTT.waitForResponse();
-  TTT.asserts(1, function () {
-    assert.equal(outputFieldFn().textContent, "267,50");
-  });
-  TTT.action(function () {
-    currencyInputFn().value = "3000";
-    currencyOptionFn().item(0).selected = false;
-    currencyOptionFn().item(1).selected = false;
-    currencyOptionFn().item(3).selected = false;
-    currencyOptionFn().item(2).selected = true; // US Dollar
-    currencyFn().dispatchEvent(new Event("change", {bubbles: true}));
-  });
-  TTT.waitForResponse();
-  TTT.asserts(1, function () {
-    assert.equal(outputFieldFn().textContent, "2.688,29");
-  });
-  TTT.startTest();
+  const test = new JasmineTestTool(done);
+  test.setup(() => parseInt(inputFn().value.replaceAll(".", "")) === 1000
+      && outputFn().textContent === "1.000,00",
+      () => {
+        inputFn().value = "1000";
+        optionsFn().item(0).selected = false; // Yen
+        optionsFn().item(1).selected = false; // Trinidad-Tobago Dollar
+        optionsFn().item(2).selected = false; // US Dollar
+        optionsFn().item(3).selected = true; // Euro
+      },
+      "change", selectFn);
+
+  test.do(() => inputFn().value = "1000");
+  test.do(() => optionsFn().item(0).selected = true); // Yen
+  test.do(() => optionsFn().item(1).selected = false); // Trinidad-Tobago Dollar
+  test.do(() => optionsFn().item(2).selected = false); // US Dollar
+  test.do(() => optionsFn().item(3).selected = false); // Euro
+  test.event("change", selectFn, () => outputFn().textContent === "8,85");
+  test.do(() => expect(outputFn().textContent).toBe("8,85"));
+
+  test.do(() => inputFn().value = "2000");
+  test.do(() => optionsFn().item(0).selected = false); // Yen
+  test.do(() => optionsFn().item(1).selected = true); // Trinidad-Tobago Dollar
+  test.do(() => optionsFn().item(2).selected = false); // US Dollar
+  test.do(() => optionsFn().item(3).selected = false); // Euro
+  test.event("change", selectFn, () => outputFn().textContent === "267,50");
+  test.do(() => expect(outputFn().textContent).toBe("267,50"));
+
+  test.do(() => inputFn().value = "3000");
+  test.do(() => optionsFn().item(0).selected = false); // Yen
+  test.do(() => optionsFn().item(1).selected = false); // Trinidad-Tobago Dollar
+  test.do(() => optionsFn().item(2).selected = true); // US Dollar
+  test.do(() => optionsFn().item(3).selected = false); // Euro
+  test.event("change", selectFn, () => outputFn().textContent === "2.688,29");
+  test.do(() => expect(outputFn().textContent).toBe("2.688,29"));
+  test.start();
 });
-*/