You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lo...@apache.org on 2020/04/02 15:27:10 UTC
[myfaces-tobago] 01/02: TOBAGO-2021: Sheet should be able to lazy
load rows by scroll events
This is an automated email from the ASF dual-hosted git repository.
lofwyr pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git
commit 0848847e2931ed7c78f2622c9460275fd4299d4b
Author: Udo Schnurpfeil <ud...@irian.eu>
AuthorDate: Thu Apr 2 08:36:37 2020 +0200
TOBAGO-2021: Sheet should be able to lazy load rows by scroll events
---
.../myfaces/tobago/component/Attributes.java | 1 +
.../apache/myfaces/tobago/event/SheetAction.java | 7 +-
.../tobago/internal/component/AbstractUISheet.java | 22 +-
.../internal/renderkit/renderer/SheetRenderer.java | 19 +-
.../renderkit/renderer/TreeNodeRenderer.java | 2 +-
.../taglib/component/SheetTagDeclaration.java | 6 +
.../tobago/renderkit/html/CustomAttributes.java | 20 ++
.../tobago/renderkit/html/DataAttributes.java | 5 -
.../tobago/example/demo/SheetController.java | 9 +-
.../080-sheet/90-lazy/Sheet_Lazy.xhtml} | 7 +-
.../src/main/npm/ts/tobago-sheet.ts | 280 +++++++++++++++++++--
11 files changed, 342 insertions(+), 36 deletions(-)
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/component/Attributes.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/component/Attributes.java
index 1317934..be4813f 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/component/Attributes.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/component/Attributes.java
@@ -146,6 +146,7 @@ public enum Attributes {
labelWidth,
large,
layoutOrder,
+ lazy,
left,
level,
lang,
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/event/SheetAction.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/event/SheetAction.java
index 07a1236..c9d04ec 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/event/SheetAction.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/event/SheetAction.java
@@ -54,7 +54,12 @@ public enum SheetAction {
/**
* Sorting
*/
- sort();
+ sort,
+
+ /**
+ * A lazy load is requested
+ */
+ lazy;
private String bundleKey;
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUISheet.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUISheet.java
index fdb0841..dc134eb 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUISheet.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUISheet.java
@@ -93,6 +93,21 @@ public abstract class AbstractUISheet extends AbstractUIData
@Override
public void encodeAll(FacesContext facesContext) throws IOException {
+ if (isLazy()) {
+ if (getRows() == 0) {
+ LOG.warn("Sheet id={} has lazy=true set, but not set the rows attribute!", getClientId(facesContext));
+ }
+ if (getShowRowRange() != ShowPosition.none) {
+ LOG.warn("Sheet id={} has lazy=true set, but also set showRowRange!=none!", getClientId(facesContext));
+ }
+ if (getShowPageRange() != ShowPosition.none) {
+ LOG.warn("Sheet id={} has lazy=true set, but also set showPageRange!=none!", getClientId(facesContext));
+ }
+ if (getShowDirectLinks() != ShowPosition.none) {
+ LOG.warn("Sheet id={} has lazy=true set, but also set showDirectLinks!=none!", getClientId(facesContext));
+ }
+ }
+
final AbstractUIReload reload = ComponentUtils.getReloadFacet(this);
if (reload != null && AjaxUtils.isAjaxRequest(facesContext) && reload.isRendered() && !reload.isUpdate()) {
@@ -202,7 +217,7 @@ public abstract class AbstractUISheet extends AbstractUIData
return getRowCount();
}
final int last = getFirst() + getRows();
- return last < getRowCount() ? last : getRowCount();
+ return Math.min(last, getRowCount());
}
/**
@@ -510,7 +525,7 @@ public abstract class AbstractUISheet extends AbstractUIData
break;
case prev:
first = getFirst() - getRows();
- first = first < 0 ? 0 : first;
+ first = Math.max(first, 0);
break;
case next:
if (hasRowCount()) {
@@ -528,6 +543,7 @@ public abstract class AbstractUISheet extends AbstractUIData
first = getFirstRowIndexOfLastPage();
break;
case toRow:
+ case lazy:
first = pageEvent.getValue() - 1;
if (hasRowCount() && first > getFirstRowIndexOfLastPage()) {
first = getFirstRowIndexOfLastPage();
@@ -593,4 +609,6 @@ public abstract class AbstractUISheet extends AbstractUIData
public abstract ShowPosition getShowPageRange();
public abstract ShowPosition getShowDirectLinks();
+
+ public abstract boolean isLazy();
}
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SheetRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SheetRenderer.java
index f2e6c2b..72992ab 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SheetRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SheetRenderer.java
@@ -58,11 +58,13 @@ import org.apache.myfaces.tobago.renderkit.css.BootstrapClass;
import org.apache.myfaces.tobago.renderkit.css.CssItem;
import org.apache.myfaces.tobago.renderkit.css.Icons;
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.HtmlButtonTypes;
import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
import org.apache.myfaces.tobago.renderkit.html.HtmlInputTypes;
+import org.apache.myfaces.tobago.util.AjaxUtils;
import org.apache.myfaces.tobago.util.ComponentUtils;
import org.apache.myfaces.tobago.util.ResourceUtils;
import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
@@ -71,6 +73,7 @@ import org.slf4j.LoggerFactory;
import javax.el.ValueExpression;
import javax.faces.application.Application;
+import javax.faces.component.NamingContainer;
import javax.faces.component.UIColumn;
import javax.faces.component.UIComponent;
import javax.faces.component.UIData;
@@ -96,6 +99,7 @@ public class SheetRenderer extends RendererBase {
private static final String SUFFIX_COLUMN_RENDERED = ComponentUtils.SUB_SEPARATOR + "rendered";
private static final String SUFFIX_SCROLL_POSITION = ComponentUtils.SUB_SEPARATOR + "scrollPosition";
private static final String SUFFIX_SELECTED = ComponentUtils.SUB_SEPARATOR + "selected";
+ private static final String SUFFIX_LAZY = NamingContainer.SEPARATOR_CHAR + "pageActionlazy";
private static final String SUFFIX_PAGE_ACTION = "pageAction";
@Override
@@ -193,6 +197,7 @@ public class SheetRenderer extends RendererBase {
break;
case toPage:
case toRow:
+ case lazy:
event = new PageActionEvent(component, action);
final int target;
final String value;
@@ -273,6 +278,10 @@ public class SheetRenderer extends RendererBase {
}
writer.writeAttribute(DataAttributes.SELECTION_MODE, sheet.getSelectable().name(), false);
writer.writeAttribute(DataAttributes.FIRST, Integer.toString(sheet.getFirst()), false);
+ writer.writeAttribute(CustomAttributes.ROWS, sheet.getRows());
+ writer.writeAttribute(CustomAttributes.ROW_COUNT, Integer.toString(sheet.getRowCount()), false);
+ writer.writeAttribute(CustomAttributes.LAZY, sheet.isLazy());
+ writer.writeAttribute(CustomAttributes.LAZY_UPDATE, sheet.isLazy() && AjaxUtils.isAjaxRequest(facesContext));
final boolean autoLayout = sheet.isAutoLayout();
if (!autoLayout) {
@@ -337,6 +346,10 @@ public class SheetRenderer extends RendererBase {
sheetId + SUFFIX_SELECTED);
}
+ if (sheet.isLazy()) {
+ encodeHiddenInput(writer,null, sheetId + SUFFIX_LAZY);
+ }
+
StringBuilder expandedValue = null;
if (sheet.isTreeModel()) {
expandedValue = new StringBuilder(",");
@@ -630,11 +643,7 @@ public class SheetRenderer extends RendererBase {
}
writer.startElement(HtmlElements.TR);
- if (rowRendered instanceof Boolean) {
- // if rowRendered attribute is set we need the rowIndex on the client
- writer.writeAttribute(DataAttributes.ROW_INDEX, rowIndex);
- }
-
+ writer.writeAttribute(CustomAttributes.ROW_INDEX, rowIndex);
final boolean selected = selectedRows.contains(rowIndex);
final String[] rowMarkups = (String[]) sheet.getAttributes().get("rowMarkup");
Markup rowMarkup = Markup.NULL;
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeNodeRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeNodeRenderer.java
index 2569227..54ee3a6 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeNodeRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeNodeRenderer.java
@@ -150,7 +150,7 @@ public class TreeNodeRenderer extends RendererBase {
writer.writeAttribute(HtmlAttributes.VALUE, clientId, true);
writer.writeIdAttribute(clientId);
writer.writeAttribute(HtmlAttributes.SELECTED, selectedState.isAncestorOfSelected(path));
- writer.writeAttribute(DataAttributes.ROW_INDEX, data.getRowIndex());
+ writer.writeAttribute(CustomAttributes.ROW_INDEX, data.getRowIndex());
} else {
writer.startElement(HtmlElements.TOBAGO_TREE_NODE);
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SheetTagDeclaration.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SheetTagDeclaration.java
index d845e5b..7918612 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SheetTagDeclaration.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SheetTagDeclaration.java
@@ -260,6 +260,12 @@ public interface SheetTagDeclaration
methodSignature = "javax.faces.event.ActionEvent")
void setSortActionListener(String sortActionListener);
+ /**
+ * Lazy loading by scroll event.
+ */
+ @TagAttribute
+ @UIComponentTagAttribute(type = "boolean", defaultValue = "false")
+ void setLazy(String lazy);
/**
* Flag indicating if paging arrows are shown near direct links
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 7b8030b..1f1201c 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
@@ -37,6 +37,14 @@ public enum CustomAttributes implements MarkupLanguageAttributes {
*/
INDEX("index"),
ITEMS("items"),
+ /**
+ * Lazy loading in sheet.
+ */
+ LAZY("lazy"),
+ /**
+ * Is this request/response an update of lazy loaded data in sheet.
+ */
+ LAZY_UPDATE("lazy-update"),
LOCALE("locale"),
LOCAL_MENU("local-menu"),
MAX_ITEMS("max-items"),
@@ -51,6 +59,18 @@ public enum CustomAttributes implements MarkupLanguageAttributes {
*/
RENDER("render"),
/**
+ * Number of rows to show/load for lazy loading in sheet.
+ */
+ ROWS("rows"),
+ /**
+ * Number of all rows in sheet.
+ */
+ ROW_COUNT("row-count"),
+ /**
+ * Index of a specific row in the sheet.
+ */
+ ROW_INDEX("row-index"),
+ /**
* The mode of the tab switch: client, reloadTab, reloadPage.
*/
SWITCH_TYPE("switch-type"),
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 385f88a..41736ab 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
@@ -121,11 +121,6 @@ public enum DataAttributes implements MarkupLanguageAttributes {
*/
RELOAD("data-tobago-reload"),
- /*
- * Holds the index of the row in a sheet, if the sheet has a rowRendered attribute.
- */
- ROW_INDEX("data-tobago-row-index"),
-
SELECTION_MODE("data-tobago-selection-mode"),
/**
diff --git a/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/SheetController.java b/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/SheetController.java
index 46b529f..53fff0f 100644
--- a/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/SheetController.java
+++ b/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/SheetController.java
@@ -83,12 +83,17 @@ public class SheetController implements Serializable {
private void init() {
solarList = astroData.findAll().collect(Collectors.toList());
+ int j = 1;
hugeSolarList = new ArrayList<>();
- for (int i = 1; i <= 1000; i++) {
+ for (; ; ) {
for (final SolarObject solarObject : solarList) {
final SolarObject solarObjectClone = new SolarObject(solarObject);
- solarObjectClone.setName(solarObject.getName() + " (" + i + ". entry)");
hugeSolarList.add(solarObjectClone);
+ solarObjectClone.setName("#" + j++ + " " + solarObject.getName());
+
+ if (j > 10000) {
+ return;
+ }
}
}
}
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/40-test/3000-sheet/20-1000-entries/1000_Entries.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/080-sheet/90-lazy/Sheet_Lazy.xhtml
similarity index 88%
rename from tobago-example/tobago-example-demo/src/main/webapp/content/40-test/3000-sheet/20-1000-entries/1000_Entries.xhtml
rename to tobago-example/tobago-example-demo/src/main/webapp/content/20-component/080-sheet/90-lazy/Sheet_Lazy.xhtml
index e64270b..5e46039 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/40-test/3000-sheet/20-1000-entries/1000_Entries.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/080-sheet/90-lazy/Sheet_Lazy.xhtml
@@ -21,10 +21,11 @@
xmlns="http://www.w3.org/1999/xhtml"
xmlns:tc="http://myfaces.apache.org/tobago/component"
xmlns:ui="http://java.sun.com/jsf/facelets">
-
+ <ui:param name="title" value="Lazy Loading Large Data"/>
<tc:sheet value="#{sheetController.hugeSolarList}" id="sheet" var="luminary"
- rows="1000" markup="small" >
- <tc:style maxHeight="600px"/>
+ rows="20" markup="small" lazy="true"
+ showRowRange="none" showDirectLinks="none" showPageRange="none">
+ <tc:style maxHeight="500px"/>
<tc:column label="Name">
<tc:out value="#{luminary.name}" labelLayout="skip"/>
</tc:column>
diff --git a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-sheet.ts b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-sheet.ts
index 375fda5..5b6604c 100644
--- a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-sheet.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-sheet.ts
@@ -25,6 +25,8 @@ class Sheet extends HTMLElement {
mousemoveData: any;
mousedownOnRowData: any;
+ lastCheckMillis: number;
+
private static getScrollBarSize(): number {
const body = document.getElementsByTagName("body").item(0);
@@ -48,12 +50,23 @@ class Sheet extends HTMLElement {
return ["INPUT", "TEXTAREA", "SELECT", "A", "BUTTON"].indexOf(element.tagName) > -1;
}
+ private static getRowTemplate(columns: number, rowIndex: number) : string {
+ return `<tr row-index="${rowIndex}" class="tobago-sheet-row" dummy="dummy">
+<td class="tobago-sheet-cell" colspan="${columns}"> </td>
+</tr>`;
+ }
+
constructor() {
super();
}
connectedCallback(): void {
+ if (this.lazyUpdate) {
+ // nothing to do here, will be done in method lazyResponse()
+ return;
+ }
+
// synchronize column widths ----------------------------------------------------------------------------------- //
// basic idea: there are two possible sources for the sizes:
@@ -153,7 +166,7 @@ class Sheet extends HTMLElement {
const selectionMode = this.dataset.tobagoSelectionMode;
if (selectionMode === "single" || selectionMode === "singleOrNone" || selectionMode === "multi") {
- for (const row of this.getRows()) {
+ for (const row of this.getRowElements()) {
row.addEventListener("mousedown", this.mousedownOnRow.bind(this));
row.addEventListener("click", this.clickOnRow.bind(this));
@@ -167,6 +180,43 @@ class Sheet extends HTMLElement {
});
}
+ // lazy load by scrolling ----------------------------------------------------------------- //
+
+ const lazy = this.lazy;
+
+ if (lazy) {
+ // prepare the sheet with some auto-created (empty) rows
+ const rowCount = this.rowCount;
+ const sheetBody = this.tableBodyDiv;
+ const tableBody = this.tableBody;
+ const columns = tableBody.rows[0].cells.length;
+ let current: HTMLTableRowElement = tableBody.rows[0]; // current row in this algorithm, begin with first
+ // the algorithm goes straight through all rows, not selectors, because of performance
+ for (let i = 0; i < rowCount; i++) {
+ if (current) {
+ const rowIndex = Number(current.getAttribute("row-index"));
+ if (i < rowIndex) {
+ const template = Sheet.getRowTemplate(columns, i);
+ current.insertAdjacentHTML("beforebegin", template);
+ } else if (i === rowIndex) {
+ current = current.nextElementSibling as HTMLTableRowElement;
+ // } else { TBD: I think this is not possible
+ // const template = Sheet.getRowTemplate(columns, i);
+ // current.insertAdjacentHTML("afterend", template);
+ // current = current.nextElementSibling as HTMLTableRowElement;
+ }
+ } else {
+ const template = Sheet.getRowTemplate(columns, i);
+ tableBody.insertAdjacentHTML("beforeend", template);
+ }
+ }
+
+ sheetBody.addEventListener("scroll", this.lazyCheck.bind(this));
+
+ // initial
+ this.lazyCheck();
+ }
+
// ---------------------------------------------------------------------------------------- //
for (const checkbox of <NodeListOf<HTMLInputElement>>this.querySelectorAll(
@@ -191,7 +241,212 @@ class Sheet extends HTMLElement {
}
});
}
+ }
+
+ // attribute getter + setter ---------------------------------------------------------- //
+ get lazyActive():boolean {
+ return this.hasAttribute("lazy-active");
+ }
+
+ set lazyActive(update:boolean) {
+ if (update) {
+ this.setAttribute("lazy-active", "");
+ } else {
+ this.removeAttribute("lazy-active");
+ }
+ }
+
+ get lazy():boolean {
+ return this.hasAttribute("lazy");
+ }
+
+ set lazy(update:boolean) {
+ if (update) {
+ this.setAttribute("lazy", "");
+ } else {
+ this.removeAttribute("lazy");
+ }
+ }
+
+ get lazyUpdate():boolean {
+ return this.hasAttribute("lazy-update");
+ }
+
+ get rows():number {
+ return parseInt(this.getAttribute("rows"));
+ }
+
+ get rowCount():number {
+ return parseInt(this.getAttribute("row-count"));
+ }
+
+ get tableBodyDiv(): HTMLDivElement {
+ return this.querySelector(".tobago-sheet-body");
+ }
+
+ get tableBody(): HTMLTableSectionElement {
+ return this.querySelector(".tobago-sheet-bodyTable>tbody");
+ }
+
+ // -------------------------------------------------------------------------------------- //
+
+ /*
+ when an event occurs (initial load OR scroll event OR AJAX response)
+
+ then -> Tobago.Sheet.lazyCheck()
+ 1. check, if the lazy reload is currently active
+ a) yes -> do nothing and exit
+ b) no -> step 2.
+ 2. check, if there are data need to load (depends on scroll position and already loaded data)
+ a) yes -> set lazy reload to active and make an AJAX request with Tobago.Sheet.reloadLazy()
+ b) no -> do nothing and exit
+
+ AJAX response -> 1. update the rows in the sheet from the response
+ 2. go to the first part of this description
+ */
+
+ /**
+ * Checks if a lazy update is required, because there are unloaded rows in the visible area.
+ */
+ lazyCheck(event?): void {
+
+ if (this.lazyActive) {
+ // nothing to do, because there is an active AJAX running
+ return;
+ }
+
+ if (this.lastCheckMillis && Date.now() - this.lastCheckMillis < 100) {
+ // do nothing, because the last call was just a moment ago
+ return;
+ }
+
+ this.lastCheckMillis = Date.now();
+ const next = this.nextLazyLoad();
+ // console.info("next %o", next); // @DEV_ONLY
+ if (next) {
+ this.lazyActive = true;
+ const rootNode = this.getRootNode() as ShadowRoot | Document;
+ const input = rootNode.getElementById(this.id + ":pageActionlazy") as HTMLInputElement;
+ input.value = String(next);
+ this.reloadWithAction(input);
+ }
+ }
+
+ nextLazyLoad(): number {
+ // find first tr in current visible area
+ const rows = this.rows;
+ const rowElements = this.tableBody.rows;
+ let min = 0;
+ let max = rowElements.length;
+ // binary search
+ let i;
+ while (min < max) {
+ i = Math.floor((max - min) / 2) + min;
+ // console.log("min i max -> %d %d %d", min, i, max); // @DEV_ONLY
+ if (this.isRowAboveVisibleArea(rowElements[i])) {
+ min = i + 1;
+ } else {
+ max = i;
+ }
+ }
+ for (i = min; i < min + rows && i < rowElements.length; i++) {
+ if (this.isRowDummy(rowElements[i])) {
+ return i + 1;
+ }
+ }
+
+ return null;
+ }
+
+ isRowAboveVisibleArea(tr: HTMLTableRowElement): boolean {
+ const sheetBody = this.tableBodyDiv;
+ const viewStart = sheetBody.scrollTop;
+ const trEnd = tr.offsetTop + tr.clientHeight;
+ return trEnd < viewStart;
+ }
+
+ isRowDummy(tr): boolean {
+ return tr.hasAttribute("dummy");
+ }
+
+ lazyResponse(event): void {
+ let updates;
+ if (event.status === "complete") {
+ updates = event.responseXML.querySelectorAll("update");
+ for (let i = 0; i < updates.length; i++) {
+ const update = updates[i];
+ const id = update.getAttribute("id");
+ if (id.indexOf(":") > -1) { // is a JSF element id, but not a technical id from the framework
+ console.debug("[tobago-sheet][complete] Update after jsf.ajax complete: #" + id); // @DEV_ONLY
+
+ const sheet = document.getElementById(id);
+ sheet.id = id + "::lazy-temporary";
+
+ const page = Page.page();
+ page.insertAdjacentHTML("beforeend", `<div id="${id}"></div>`);
+ const sheetLoader = document.getElementById(id);
+ }
+ }
+ } else if (event.status === "success") {
+ updates = event.responseXML.querySelectorAll("update");
+ for (let i = 0; i < updates.length; i++) {
+ const update = updates[i];
+ const id = update.getAttribute("id");
+ if (id.indexOf(":") > -1) { // is a JSF element id, but not a technical id from the framework
+ console.debug("[tobago-sheet][success] Update after jsf.ajax complete: #" + id); // @DEV_ONLY
+
+ // sync the new rows into the sheet
+ const sheetLoader = document.getElementById(id);
+ const sheet = document.getElementById(id + "::lazy-temporary");
+ sheet.id = id;
+ const tbody = sheet.querySelector(".tobago-sheet-bodyTable>tbody");
+
+ const newRows = sheetLoader.querySelectorAll(".tobago-sheet-bodyTable>tbody>tr");
+ for (i = 0; i < newRows.length; i++) {
+ const newRow = newRows[i];
+ const rowIndex = Number(newRow.getAttribute("row-index"));
+ const row = tbody.querySelector("tr[row-index='" + rowIndex + "']");
+ // replace the old row with the new row
+ row.insertAdjacentElement("afterend", newRow);
+ tbody.removeChild(row);
+ }
+
+ sheetLoader.parentElement.removeChild(sheetLoader);
+ this.lazyActive = false;
+ }
+ }
+ }
+ }
+
+ lazyError(data): void {
+ console.error("Sheet lazy loading error:"
+ + "\nError Description: " + data.description
+ + "\nError Name: " + data.errorName
+ + "\nError errorMessage: " + data.errorMessage
+ + "\nResponse Code: " + data.responseCode
+ + "\nResponse Text: " + data.responseText
+ + "\nStatus: " + data.status
+ + "\nType: " + data.type);
+ }
+
+ // tbd: how to do this in Tobago 5?
+ reloadWithAction(source: HTMLElement): void {
+ console.debug("reload sheet with action '" + source.id + "'"); // @DEV_ONLY
+ const executeIds = this.id;
+ const renderIds = this.id;
+ const lazy = this.lazy;
+
+ jsf.ajax.request(
+ source.id,
+ null,
+ {
+ "javax.faces.behavior.event": "reload",
+ execute: executeIds,
+ render: renderIds,
+ onevent: lazy ? this.lazyResponse.bind(this) : undefined,
+ onerror: lazy ? this.lazyError.bind(this) : undefined
+ });
}
loadColumnWidths(): number[] {
@@ -358,7 +613,7 @@ class Sheet extends HTMLElement {
window.getSelection().removeAllRanges();
}
- const rows = this.getRows();
+ const rows = this.getRowElements();
const selector = this.getSelectorCheckbox(row);
const selectionMode = this.dataset.tobagoSelectionMode;
@@ -464,7 +719,7 @@ class Sheet extends HTMLElement {
return row.querySelector("tr>td>input.tobago-sheet-columnSelector");
}
- getRows(): NodeListOf<HTMLTableRowElement> {
+ getRowElements(): NodeListOf<HTMLTableRowElement> {
return this.getBodyTable().querySelectorAll("tbody>tr");
}
@@ -473,11 +728,7 @@ class Sheet extends HTMLElement {
}
isRowSelected(row: HTMLTableRowElement): boolean {
- let rowIndex = +row.dataset.tobagoRowIndex;
- if (!rowIndex) {
- rowIndex = row.sectionRowIndex + this.getFirst();
- }
- return this.isSelected(rowIndex);
+ return this.isSelected(parseInt(row.dataset.tobagoRowIndex));
}
isSelected(rowIndex: number): boolean {
@@ -503,17 +754,17 @@ class Sheet extends HTMLElement {
}
selectAll(): void {
- const rows = this.getRows();
+ const rows = this.getRowElements();
this.selectRange(rows, 0, rows.length - 1, true, false);
}
deselectAll(): void {
- const rows = this.getRows();
+ const rows = this.getRowElements();
this.selectRange(rows, 0, rows.length - 1, false, true);
}
toggleAll(): void {
- const rows = this.getRows();
+ const rows = this.getRowElements();
this.selectRange(rows, 0, rows.length - 1, true, true);
}
@@ -538,12 +789,7 @@ class Sheet extends HTMLElement {
}
getDataIndex(row: HTMLTableRowElement): number {
- const rowIndex = parseInt(row.dataset.tobagoRowIndex);
- if (rowIndex) {
- return rowIndex;
- } else {
- return row.sectionRowIndex + this.getFirst();
- }
+ return parseInt(row.dataset.tobagoRowIndex);
}
/**