refactor TS for tc:tab / tc:tabGroup
issue: TOBAGO-1633: TS refactoring
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TabGroupRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TabGroupRenderer.java
index 664b3b8..9049d0e 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TabGroupRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TabGroupRenderer.java
@@ -41,6 +41,7 @@
import org.apache.myfaces.tobago.renderkit.RendererBase;
import org.apache.myfaces.tobago.renderkit.css.BootstrapClass;
import org.apache.myfaces.tobago.renderkit.css.TobagoClass;
+import org.apache.myfaces.tobago.renderkit.html.CustomAttributes;
import org.apache.myfaces.tobago.renderkit.html.DataAttributes;
import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
@@ -72,7 +73,7 @@
private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
- private static final String ACTIVE_INDEX_POSTFIX = ComponentUtils.SUB_SEPARATOR + "activeIndex";
+ private static final String INDEX_POSTFIX = ComponentUtils.SUB_SEPARATOR + "index";
@Override
public void processEvent(final ComponentSystemEvent event) {
@@ -124,15 +125,15 @@
final String clientId = component.getClientId(facesContext);
final Map parameters = facesContext.getExternalContext().getRequestParameterMap();
- final String newValue = (String) parameters.get(clientId + ACTIVE_INDEX_POSTFIX);
+ final String newValue = (String) parameters.get(clientId + INDEX_POSTFIX);
try {
- final int activeIndex = Integer.parseInt(newValue);
- if (activeIndex != oldIndex) {
- final TabChangeEvent event = new TabChangeEvent(component, oldIndex, activeIndex);
+ final int newIndex = Integer.parseInt(newValue);
+ if (newIndex != oldIndex) {
+ final TabChangeEvent event = new TabChangeEvent(component, oldIndex, newIndex);
component.queueEvent(event);
}
} catch (final NumberFormatException e) {
- LOG.error("Can't parse activeIndex: '" + newValue + "'");
+ LOG.error("Can't parse newIndex: '" + newValue + "'");
}
}
@@ -141,10 +142,10 @@
final AbstractUITabGroup tabGroup = (AbstractUITabGroup) uiComponent;
- final int activeIndex = ensureRenderedActiveIndex(facesContext, tabGroup);
+ final int selectedIndex = ensureRenderedSelectedIndex(facesContext, tabGroup);
final String clientId = tabGroup.getClientId(facesContext);
- final String hiddenId = clientId + TabGroupRenderer.ACTIVE_INDEX_POSTFIX;
+ final String hiddenId = clientId + TabGroupRenderer.INDEX_POSTFIX;
final SwitchType switchType = tabGroup.getSwitchType();
final Markup markup = tabGroup.getMarkup();
final TobagoResponseWriter writer = getResponseWriter(facesContext);
@@ -157,33 +158,33 @@
tabGroup.getCustomClass(),
markup != null && markup.contains(Markup.SPREAD) ? TobagoClass.SPREAD : null);
HtmlRendererUtils.writeDataAttributes(facesContext, writer, tabGroup);
- writer.writeAttribute(DataAttributes.SWITCH_TYPE, switchType.name(), false);
+ writer.writeAttribute(CustomAttributes.SWITCH_TYPE, switchType.name(), false);
writer.startElement(HtmlElements.INPUT);
writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.HIDDEN);
- writer.writeAttribute(HtmlAttributes.VALUE, activeIndex);
+ writer.writeAttribute(HtmlAttributes.VALUE, selectedIndex);
writer.writeNameAttribute(hiddenId);
writer.writeIdAttribute(hiddenId);
writer.endElement(HtmlElements.INPUT);
if (tabGroup.isShowNavigationBar()) {
- encodeHeader(facesContext, writer, tabGroup, activeIndex, switchType);
+ encodeHeader(facesContext, writer, tabGroup, selectedIndex, switchType);
}
- encodeContent(facesContext, writer, tabGroup, activeIndex, switchType);
+ encodeContent(facesContext, writer, tabGroup, selectedIndex, switchType);
writer.endElement(HtmlElements.TOBAGO_TAB_GROUP);
}
- private int ensureRenderedActiveIndex(final FacesContext context, final AbstractUITabGroup tabGroup) {
- final int activeIndex = tabGroup.getSelectedIndex();
+ private int ensureRenderedSelectedIndex(final FacesContext context, final AbstractUITabGroup tabGroup) {
+ final int selectedIndex = tabGroup.getSelectedIndex();
// ensure to select a rendered tab
int index = -1;
int closestRenderedTabIndex = -1;
for (final UIComponent tab : tabGroup.getChildren()) {
if (tab instanceof AbstractUIPanelBase) {
index++;
- if (index == activeIndex) {
+ if (index == selectedIndex) {
if (tab.isRendered()) {
return index;
} else if (closestRenderedTabIndex > -1) {
@@ -192,7 +193,7 @@
}
if (tab.isRendered()) {
closestRenderedTabIndex = index;
- if (index > activeIndex) {
+ if (index > selectedIndex) {
break;
}
}
@@ -213,7 +214,7 @@
private void encodeHeader(
final FacesContext facesContext, final TobagoResponseWriter writer, final AbstractUITabGroup tabGroup,
- final int activeIndex, final SwitchType switchType)
+ final int selectedIndex, final SwitchType switchType)
throws IOException {
final String tabGroupClientId = tabGroup.getClientId(facesContext);
@@ -241,7 +242,7 @@
final String tabId = tab.getClientId(facesContext);
Markup markup = tab.getMarkup() != null ? tab.getMarkup() : Markup.NULL;
- if (activeIndex == index) {
+ if (selectedIndex == index) {
markup = markup.add(Markup.SELECTED);
}
final FacesMessage.Severity maxSeverity
@@ -260,7 +261,7 @@
tab.getCustomClass());
writer.writeAttribute(HtmlAttributes.FOR, tabGroupClientId, true);
writer.writeAttribute(HtmlAttributes.ROLE, HtmlRoleValues.PRESENTATION.toString(), false);
- writer.writeAttribute(DataAttributes.TAB_GROUP_INDEX, index);
+ writer.writeAttribute(CustomAttributes.INDEX, index);
final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, tab);
if (title != null) {
writer.writeAttribute(HtmlAttributes.TITLE, title, true);
@@ -272,7 +273,7 @@
}
if (tab.isDisabled()) {
writer.writeClassAttribute(BootstrapClass.NAV_LINK, BootstrapClass.DISABLED);
- } else if (activeIndex == index) {
+ } else if (selectedIndex == index) {
writer.writeClassAttribute(BootstrapClass.NAV_LINK, BootstrapClass.ACTIVE);
} else {
writer.writeClassAttribute(BootstrapClass.NAV_LINK);
@@ -286,7 +287,9 @@
if (!disabled) {
final CommandMap map = RenderUtils.getBehaviorCommands(facesContext, tab);
CommandMap.merge(map, tabGroupMap);
- writer.writeAttribute(DataAttributes.COMMANDS, JsonUtils.encode(map), false);
+ if (false) { // TBD
+ writer.writeAttribute(DataAttributes.COMMANDS, JsonUtils.encode(map), false);
+ }
}
if (!disabled && label.getAccessKey() != null) {
@@ -335,14 +338,14 @@
protected void encodeContent(
final FacesContext facesContext, final TobagoResponseWriter writer, final AbstractUITabGroup tabGroup,
- final int activeIndex, final SwitchType switchType) throws IOException {
+ final int selectedIndex, final SwitchType switchType) throws IOException {
writer.startElement(HtmlElements.DIV);
writer.writeClassAttribute(BootstrapClass.CARD_BODY, BootstrapClass.TAB_CONTENT);
int index = 0;
for (final UIComponent child : tabGroup.getChildren()) {
if (child instanceof AbstractUITab) {
final AbstractUITab tab = (AbstractUITab) child;
- if (tab.isRendered() && (switchType == SwitchType.client || index == activeIndex) && !tab.isDisabled()) {
+ if (tab.isRendered() && (switchType == SwitchType.client || index == selectedIndex) && !tab.isDisabled()) {
final Markup markup = tab.getMarkup();
writer.startElement(HtmlElements.DIV);
@@ -350,11 +353,11 @@
TobagoClass.TAB__CONTENT,
TobagoClass.TAB__CONTENT.createMarkup(markup),
BootstrapClass.TAB_PANE,
- index == activeIndex ? BootstrapClass.ACTIVE : null);
+ index == selectedIndex ? BootstrapClass.ACTIVE : null);
writer.writeAttribute(HtmlAttributes.ROLE, HtmlRoleValues.TABPANEL.toString(), false);
writer.writeIdAttribute(getTabPanelId(facesContext, tab));
- writer.writeAttribute(DataAttributes.TAB_GROUP_INDEX, index);
+ writer.writeAttribute(CustomAttributes.INDEX, index);
tab.encodeAll(facesContext);
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/CustomAttributes.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/CustomAttributes.java
index 2955d36..2e49e66 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/CustomAttributes.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/CustomAttributes.java
@@ -21,14 +21,23 @@
public enum CustomAttributes implements MarkupLanguageAttributes {
- MIN_CHARS("min-chars"),
- DELAY("delay"),
- MAX_ITEMS("max-items"),
- UPDATE("update"),
- TOTAL_COUNT("total-count"),
- LOCAL_MENU("local-menu"),
DATA("data"),
- ORIENTATION("orientation");
+ DELAY("delay"),
+ /**
+ * The index of the tab inside the tab group.
+ */
+ INDEX("index"),
+ LOCAL_MENU("local-menu"),
+ MAX_ITEMS("max-items"),
+ MIN_CHARS("min-chars"),
+ ORIENTATION("orientation"),
+ /**
+ * The mode of the tab switch: client, reloadTab, reloadPage.
+ */
+ SWITCH_TYPE("switch-type"),
+ TOTAL_COUNT("total-count"),
+ UPDATE("update");
+
private final String value;
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/DataAttributes.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/DataAttributes.java
index 5a28407..175737f 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/DataAttributes.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/DataAttributes.java
@@ -169,16 +169,6 @@
SCROLL_POSITION("data-tobago-scroll-position"),
- /**
- * The mode of the tab switch: client, reloadTab, reloadPage.
- */
- SWITCH_TYPE("data-tobago-switch-type"),
-
- /**
- * The index of the tab inside the tab group.
- */
- TAB_GROUP_INDEX("data-tobago-tab-group-index"),
-
TARGET("data-target"),
TITLE("data-title"),
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/HtmlAttributes.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/HtmlAttributes.java
index 82f27ac..4dca011 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/HtmlAttributes.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/HtmlAttributes.java
@@ -19,6 +19,9 @@
package org.apache.myfaces.tobago.renderkit.html;
+/**
+ * HTML standard attributes. For non-standard attributes {@link CustomAttributes}
+ */
public enum HtmlAttributes implements MarkupLanguageAttributes {
ACCEPT_CHARSET("accept-charset"),
@@ -119,25 +122,7 @@
VALIGN("valign"),
VALUE("value"),
WIDTH("width"),
- XMLNS("xmlns"),
-
- // Non standard attributes ///////////////////////////////////////////////////////////
-
- /**
- * The index of the tab inside the tab group.
- *
- * @deprecated since 4.3.0, please use {@link DataAttributes#TAB_GROUP_INDEX}
- */
- @Deprecated
- TABGROUPINDEX("tabgroupindex"),
- /**
- * The mode of the tab switch: client, reloadTab, reloadPage.
- *
- * @deprecated since 4.3.0, please use {@link DataAttributes#SWITCH_TYPE}
- */
- @Deprecated
- SWITCHTYPE("switchtype");
-
+ XMLNS("xmlns");
private final String value;
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/070-tab/01-ajax/Tab_Ajax.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/070-tab/01-ajax/Tab_Ajax.xhtml
index 15a7fe0..15c5da0 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/070-tab/01-ajax/Tab_Ajax.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/070-tab/01-ajax/Tab_Ajax.xhtml
@@ -42,7 +42,7 @@
<tc:tab id="t11" label="One">
First tab.
</tc:tab>
- <tc:tab id="t12" label="Two" disabled="true">
+ <tc:tab id="t12" label="Two (disabled)" disabled="true">
Second tab.
</tc:tab>
<tc:tab id="t13" label="Three">
diff --git a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-command.ts b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-command.ts
index eb1110a..d998774 100644
--- a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-command.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-command.ts
@@ -244,51 +244,47 @@
}
}
- static init = function (element: HTMLElement, force: boolean = false) {
+ static init = function (element: HTMLElement) {
for (const commandElement of DomUtils.selfOrQuerySelectorAll(element, "[data-tobago-commands]")) {
- // TODO hack to set command eventListeners after tobago-tab EventListeners
- if (force || commandElement.parentElement.tagName !== "TOBAGO-TAB") {
+ const commandMap = new CommandMap(commandElement.dataset["tobagoCommands"]);
- const commandMap = new CommandMap(commandElement.dataset["tobagoCommands"]);
+ for (const entry of commandMap.commands.entries()) {
+ const key: string = entry[0];
+ const value: Command = entry[1];
- for (const entry of commandMap.commands.entries()) {
- const key: string = entry[0];
- const value: Command = entry[1];
-
- switch (key) {
- case "change":
- commandElement.addEventListener("change", CommandMap.change);
- break;
- case "complete":
- if (parseFloat(commandElement.getAttribute("value")) >= parseFloat(commandElement.getAttribute("max"))) {
- if (commandMap.complete.execute || commandMap.complete.render) {
- jsf.ajax.request(
- this.id,
- null,
- {
- "javax.faces.behavior.event": "complete",
- execute: commandMap.complete.execute,
- render: commandMap.complete.render
- });
- } else {
- Command.submitAction(this, commandMap.complete.action, commandMap.complete);
- }
+ switch (key) {
+ case "change":
+ commandElement.addEventListener("change", CommandMap.change);
+ break;
+ case "complete":
+ if (parseFloat(commandElement.getAttribute("value")) >= parseFloat(commandElement.getAttribute("max"))) {
+ if (commandMap.complete.execute || commandMap.complete.render) {
+ jsf.ajax.request(
+ this.id,
+ null,
+ {
+ "javax.faces.behavior.event": "complete",
+ execute: commandMap.complete.execute,
+ render: commandMap.complete.render
+ });
+ } else {
+ Command.submitAction(this, commandMap.complete.action, commandMap.complete);
}
- break;
- case "load":
- setTimeout(function () {
- Command.submitAction(this, commandMap.load.action, commandMap.load);
- },
- commandMap.load.delay || 100);
- break;
- case "resize":
- window.addEventListener("resize", CommandMap.resize);
- break;
- default:
- commandElement.addEventListener(key, CommandMap.otherEvent);
- }
+ }
+ break;
+ case "load":
+ setTimeout(function () {
+ Command.submitAction(this, commandMap.load.action, commandMap.load);
+ },
+ commandMap.load.delay || 100);
+ break;
+ case "resize":
+ window.addEventListener("resize", CommandMap.resize);
+ break;
+ default:
+ commandElement.addEventListener(key, CommandMap.otherEvent);
}
}
}
diff --git a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-tab.ts b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-tab.ts
index e9f2ed4..fcb822c 100644
--- a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-tab.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-tab.ts
@@ -18,74 +18,103 @@
import {Command} from "./tobago-command";
class TabGroup extends HTMLElement {
- private markupCssClass: string = "tobago-tab-markup-selected";
+
+ private hiddenInput: HTMLInputElement;
constructor() {
super();
+ this.hiddenInput = this.querySelector(":scope > input[type=hidden]");
}
connectedCallback() {
- const tabGroup: TabGroup = this;
- const hiddenInput: HTMLInputElement = this.querySelector(":scope > input[type=hidden]");
+ }
- for (const tab of tabGroup.tabs) {
- const navLink: HTMLLinkElement = tab.querySelector(":scope > .nav-link");
- if (!navLink.classList.contains("disabled")) {
- navLink.addEventListener('click', function () {
- hiddenInput.value = tab.groupIndex;
-
- if (tabGroup.dataset.tobagoSwitchType === "client") {
- tabGroup.activeTab.classList.remove(tabGroup.markupCssClass);
- tabGroup.activeNavLink.classList.remove("active");
- tabGroup.activeTabContent.classList.remove("active");
-
- tab.classList.add(tabGroup.markupCssClass);
- navLink.classList.add("active");
- tabGroup.getTabContent(tab.groupIndex).classList.add("active");
- }
- });
- }
- }
-
- Command.init(tabGroup, true);
+ get switchType(): string {
+ return this.getAttribute("switch-type");
}
get tabs(): NodeListOf<Tab> {
- return this.querySelectorAll("tobago-tab[for='" + this.id + "']");
+ return this.querySelectorAll(":scope > .card-header > .card-header-tabs > tobago-tab") as NodeListOf<Tab>;
}
- get activeTab(): Tab {
- return this.querySelector("tobago-tab[for='" + this.id + "']." + this.markupCssClass);
+ getSelectedTab(): Tab {
+ return this.querySelector(":scope > .card-header > .card-header-tabs > tobago-tab[index='" + this.selected + "']") as Tab;
}
- get activeNavLink(): HTMLLinkElement {
- return this.querySelector("tobago-tab[for='" + this.id + "'] > .nav-link.active");
+ get selected(): number {
+ return parseInt(this.hiddenInput.value);
}
- get activeTabContent(): HTMLDivElement {
- return this.querySelector(":scope > .card-body.tab-content > .tobago-tab-content.active");
- }
-
- getTabContent(tabGroupIndex: string): HTMLDivElement {
- return this.querySelector(":scope > .card-body > .tobago-tab-content[data-tobago-tab-group-index='"
- + tabGroupIndex + "']");
+ set selected(index: number) {
+ this.hiddenInput.value = String(index);
}
}
-class Tab extends HTMLElement {
+export class Tab extends HTMLElement {
+
constructor() {
super();
}
connectedCallback() {
+ let navLink = this.navLink;
+ if (!navLink.classList.contains("disabled")) {
+ navLink.addEventListener("click", this.select.bind(this));
+ }
}
- get groupIndex(): string {
- return this.dataset.tobagoTabGroupIndex;
+ get index(): number {
+ return parseInt(this.getAttribute("index"));
+ }
+
+ get navLink(): HTMLLinkElement {
+ return this.querySelector(".nav-link");
+ }
+
+ get tabGroup(): TabGroup {
+ return this.closest("tobago-tab-group") as TabGroup;
+ }
+
+ select(event: MouseEvent) {
+ const tabGroup = this.tabGroup;
+ const old = tabGroup.getSelectedTab();
+ tabGroup.selected = this.index;
+
+ switch (tabGroup.switchType) {
+ case "client":
+ old.navLink.classList.remove("active");
+ this.navLink.classList.add("active");
+ old.content.classList.remove("active");
+ this.content.classList.add("active");
+ break;
+ case "reloadTab":
+ jsf.ajax.request(
+ this.navLink,
+ event, {
+ //"javax.faces.behavior.event": "click",
+ execute: tabGroup.id,
+ render: tabGroup.id
+ });
+ break;
+ case "reloadPage":
+ Command.submitAction(this.navLink, this.id);
+ break;
+ case "none": // todo
+ console.error("Not implemented yet: %s", tabGroup.switchType);
+ break;
+ default:
+ console.error("Unknown switchType='%s'", tabGroup.switchType);
+ break;
+ }
+ }
+
+ get content(): HTMLElement {
+ return this.closest("tobago-tab-group")
+ .querySelector(":scope > .card-body.tab-content > .tab-pane[index='" + this.index + "']");
}
}
document.addEventListener("DOMContentLoaded", function (event) {
- window.customElements.define('tobago-tab-group', TabGroup);
window.customElements.define('tobago-tab', Tab);
+ window.customElements.define('tobago-tab-group', TabGroup);
});