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 2023/04/15 10:11:27 UTC

[myfaces-tobago] 01/02: feature: split button

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

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

commit 9076e325f604e844435a700c539aca40e6d1278f
Author: Henning Noeth <hn...@apache.org>
AuthorDate: Sat Apr 15 10:52:49 2023 +0200

    feature: split button
    
    * automatically add a .dropdown-toggle-split CSS class, if no label/image/labelFacet is set. Then, only the dropdown arrow icon is visible.
    * fix border-radius if the dropdown-toggle button is at the end of the button group
    * add test for border-radius
    * add split button example in demo
    
    Issue: TOBAGO-2201
---
 .../renderkit/renderer/CommandRendererBase.java    |  5 +-
 .../tobago/renderkit/css/BootstrapClass.java       |  1 +
 .../040-command/20-buttons/Button_Group.test.js    | 20 ++++--
 .../040-command/20-buttons/Button_Group.xhtml      | 76 ++++++++++++++++------
 tobago-theme/src/main/scss/_tobago.scss            |  6 ++
 5 files changed, 81 insertions(+), 27 deletions(-)

diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/CommandRendererBase.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/CommandRendererBase.java
index bb65b45951..f77da4720d 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/CommandRendererBase.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/CommandRendererBase.java
@@ -66,6 +66,8 @@ public abstract class CommandRendererBase<T extends AbstractUICommand> extends D
     final String clientId = component.getClientId(facesContext);
     final boolean disabled = component.isDisabled();
     final LabelWithAccessKey label = new LabelWithAccessKey(component);
+    final String image = component.getImage();
+    final UIComponent labelFacet = ComponentUtils.getFacet(component, Facets.label);
     final boolean anchor = (component.getLink() != null || component.getOutcome() != null) && !disabled;
     final String target = component.getTarget();
     final boolean autoSpacing = component.getAutoSpacing(facesContext);
@@ -121,6 +123,7 @@ public abstract class CommandRendererBase<T extends AbstractUICommand> extends D
         autoSpacing && !dropdownSubmenu ? TobagoClass.AUTO__SPACING : null,
         dropdownSubmenu ? BootstrapClass.DROPDOWN_ITEM : null,
         parentOfCommands && !dropdownSubmenu ? BootstrapClass.DROPDOWN_TOGGLE : null,
+        label.getLabel() == null && image == null && labelFacet == null ? BootstrapClass.DROPDOWN_TOGGLE_SPLIT : null,
         component.getCustomClass(),
         isInside(facesContext, HtmlElements.TOBAGO_LINKS) && !dropdownSubmenu ? BootstrapClass.NAV_LINK : null);
 
@@ -138,10 +141,8 @@ public abstract class CommandRendererBase<T extends AbstractUICommand> extends D
       encodeBehavior(writer, facesContext, component);
     }
 
-    final String image = component.getImage();
     HtmlRendererUtils.encodeIconOrImage(writer, image);
 
-    final UIComponent labelFacet = ComponentUtils.getFacet(component, Facets.label);
     if (labelFacet != null) {
       insideBegin(facesContext, Facets.label);
       for (final UIComponent child : RenderUtils.getFacetChildren(labelFacet)) {
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/css/BootstrapClass.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/css/BootstrapClass.java
index e0285c0ee4..5c3d2c53e3 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/css/BootstrapClass.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/css/BootstrapClass.java
@@ -311,6 +311,7 @@ public enum BootstrapClass implements CssItem {
   DROPDOWN_MENU("dropdown-menu"),
   DROPDOWN_MENU_END("dropdown-menu-end"),
   DROPDOWN_TOGGLE("dropdown-toggle"),
+  DROPDOWN_TOGGLE_SPLIT("dropdown-toggle-split"),
   ERROR_FEEDBACK("error-feedback"),
   ERROR_TOOLTIP("error-tooltip"),
   FADE("fade"),
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/040-command/20-buttons/Button_Group.test.js b/tobago-example/tobago-example-demo/src/main/webapp/content/040-command/20-buttons/Button_Group.test.js
index f3cdc1caf7..e32775cab3 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/040-command/20-buttons/Button_Group.test.js
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/040-command/20-buttons/Button_Group.test.js
@@ -15,13 +15,25 @@
  * limitations under the License.
  */
 
-import {querySelectorFn} from "/script/tobago-test.js";
+import {elementByIdFn} from "/script/tobago-test.js";
 import {JasmineTestTool} from "/tobago/test/tobago-test-tool.js";
 
 it("Dropdown button has 'btn-group'", function (done) {
-  let buttonFn = querySelectorFn("#page\\:mainForm\\:buttonWithLinks");
+  const dropdownFn = elementByIdFn("page:mainForm:splitPrimary");
 
-  let test = new JasmineTestTool(done);
-  test.do(() => expect(buttonFn().classList.contains("btn-group")).toBe(true, "id=buttonWithLinks must have 'btn-group'"));
+  const test = new JasmineTestTool(done);
+  test.do(() => expect(dropdownFn().classList.contains("btn-group")).toBe(true, "id=buttonWithLinks must have 'btn-group'"));
+  test.start();
+});
+
+it("Split button has rounded corners", function (done) {
+  const buttonFn = elementByIdFn("page:mainForm:splitPrimary::command");
+  const buttonStyle = getComputedStyle(buttonFn());
+
+  const test = new JasmineTestTool(done);
+  test.do(() => expect(buttonStyle.borderTopLeftRadius).toBe("0px"));
+  test.do(() => expect(buttonStyle.borderBottomLeftRadius).toBe("0px"));
+  test.do(() => expect(buttonStyle.borderTopRightRadius).toBe("6px"));
+  test.do(() => expect(buttonStyle.borderBottomRightRadius).toBe("6px"));
   test.start();
 });
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/040-command/20-buttons/Button_Group.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/040-command/20-buttons/Button_Group.xhtml
index d6bf262943..e989b0b18e 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/040-command/20-buttons/Button_Group.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/040-command/20-buttons/Button_Group.xhtml
@@ -59,31 +59,65 @@
     </tc:buttons>
   </tc:section>
 
-  <tc:section label="Dropdown Button">
-    <p>A dropdown button can also be placed in a <code class="language-markup">&lt;tc:buttons/></code> tag.</p>
+  <tc:section label="Split buttons">
+    <p>A dropdown button can also be placed in a <code class="language-markup">&lt;tc:buttons/></code> tag to create a
+      split button.</p>
     <demo-highlight language="markup">&lt;tc:buttons>
-  &lt;tc:button label="Dropdown" omit="true">
-    &lt;tc:link label="Action 1"/>
-    ...
-    &lt;tc:separator/>
-    &lt;tc:link label="Other Action"/>
+  &lt;tc:button label="Primary" markup="primary"/>
+  &lt;tc:button omit="true" markup="primary">
+    &lt;tc:link label="Entry 1"/>
+    &lt;tc:link label="Entry 2"/>
+    &lt;tc:link label="Entry 3"/>
   &lt;/tc:button>
-  &lt;tc:button label="Center"/>
-  &lt;tc:button label="Right"/>
-&lt;/tc:buttons></demo-highlight>
+&lt;/tc:buttons>
+    </demo-highlight>
+    <tc:buttons id="splitButtonsPrimary">
+      <tc:button label="Primary" markup="primary"/>
+      <tc:button id="splitPrimary" omit="true" markup="primary">
+        <tc:link label="Entry 1"/>
+        <tc:link label="Entry 2"/>
+        <tc:link label="Entry 3"/>
+      </tc:button>
+    </tc:buttons>
     <tc:buttons>
-      <tc:button id="buttonWithLinks" label="Dropdown" omit="true">
-        <tc:link label="Action 1"/>
-        <tc:link label="Action 2"/>
-        <tc:link label="Action 3">
-          <tc:link label="Action 3.1"/>
-          <tc:link label="Action 3.2"/>
-        </tc:link>
-        <tc:separator/>
-        <tc:link label="Other Action"/>
+      <tc:button label="Secondary" markup="secondary"/>
+      <tc:button omit="true" markup="secondary">
+        <tc:link label="Entry 1"/>
+        <tc:link label="Entry 2"/>
+        <tc:link label="Entry 3"/>
+      </tc:button>
+    </tc:buttons>
+    <tc:buttons>
+      <tc:button label="Success" markup="success"/>
+      <tc:button omit="true" markup="success">
+        <tc:link label="Entry 1"/>
+        <tc:link label="Entry 2"/>
+        <tc:link label="Entry 3"/>
+      </tc:button>
+    </tc:buttons>
+    <tc:buttons>
+      <tc:button label="Info" markup="info"/>
+      <tc:button omit="true" markup="info">
+        <tc:link label="Entry 1"/>
+        <tc:link label="Entry 2"/>
+        <tc:link label="Entry 3"/>
+      </tc:button>
+    </tc:buttons>
+    <tc:buttons>
+      <tc:button label="Warning" markup="warning"/>
+      <tc:button omit="true" markup="warning">
+        <tc:link label="Entry 1"/>
+        <tc:link label="Entry 2"/>
+        <tc:link label="Entry 3"/>
+      </tc:button>
+    </tc:buttons>
+    <tc:buttons>
+      <tc:button label="Danger" markup="danger"/>
+      <tc:button omit="true" markup="danger">
+        <tc:link label="Entry 1"/>
+        <tc:link label="Entry 2"/>
+        <tc:link label="Entry 3"/>
       </tc:button>
-      <tc:button label="Center"/>
-      <tc:button label="Right"/>
     </tc:buttons>
   </tc:section>
 
diff --git a/tobago-theme/src/main/scss/_tobago.scss b/tobago-theme/src/main/scss/_tobago.scss
index c8102322b0..4467496f5e 100644
--- a/tobago-theme/src/main/scss/_tobago.scss
+++ b/tobago-theme/src/main/scss/_tobago.scss
@@ -455,6 +455,12 @@ tobago-buttons {
   > .tobago-button {
     display: inline-block;
   }
+
+  > tobago-dropdown:last-child > .tobago-button.dropdown-toggle-split:first-child {
+    //split buttons in Tobago have a tobago-dropdown tag included, which leads to an issue with border-radius
+    border-top-right-radius: var(--bs-btn-border-radius);
+    border-bottom-right-radius: var(--bs-btn-border-radius);
+  }
 }
 
 /* collapsible -------------------------------------------------------------- */