diff --git a/scripts/system/html/js/entityList.js b/scripts/system/html/js/entityList.js index 4745431283..55000cfb93 100644 --- a/scripts/system/html/js/entityList.js +++ b/scripts/system/html/js/entityList.js @@ -20,7 +20,7 @@ const IMAGE_MODEL_NAME = 'default-image-model.fbx'; const COLLAPSE_EXTRA_INFO = "E"; const EXPAND_EXTRA_INFO = "D"; const FILTER_IN_VIEW_ATTRIBUTE = "pressed"; -const WINDOW_NONVARIABLE_HEIGHT = 206; +const WINDOW_NONVARIABLE_HEIGHT = 207; const NUM_COLUMNS = 12; const EMPTY_ENTITY_ID = "0"; const DELETE = 46; // Key code for the delete key. @@ -68,7 +68,7 @@ var visibleEntities = []; // List of all entities that are currently selected var selectedEntities = []; -var entityList = null; // ListView +var entityList = null; // The ListView var currentSortColumn = 'type'; var currentSortOrder = ASCENDING_SORT; @@ -178,11 +178,11 @@ function loaded() { elInView.onclick = toggleFilterInView; elRadius.onchange = onRadiusChange; elInfoToggle.onclick = toggleInfo; - window.onresize = resize; elNoEntitiesInView.style.display = "none"; - entityList = new ListView("entity-table", "entity-table-body", "entity-table-scroll", createRow, updateRow, clearRow); + entityList = new ListView("entity-table", "entity-table-body", "entity-table-scroll", + createRow, updateRow, clearRow, resize, WINDOW_NONVARIABLE_HEIGHT); function onRowClicked(clickEvent) { let entityID = this.dataset.entityID; @@ -257,7 +257,7 @@ function loaded() { function updateEntityData(entityData) { entities = []; entitiesByID = {}; - visibleEntities = []; + visibleEntities.length = 0; // maintains itemData reference in ListView PROFILE("map-data", function() { entityData.forEach(function(entity) { @@ -282,7 +282,7 @@ function loaded() { isBaked: entity.isBaked ? BAKED_GLYPH : null, drawCalls: displayIfNonZero(entity.drawCalls), hasScript: entity.hasScript ? SCRIPT_GLYPH : null, - elRow: null, + elRow: null, // if this entity has a row element assigned to it selected: false } @@ -317,9 +317,6 @@ function loaded() { PROFILE("update-dom", function() { entityList.itemData = visibleEntities; - if (visibleEntities.length < entityList.rowOffset) { - entityList.resetRowOffset(); - } entityList.refresh(); }); @@ -330,6 +327,9 @@ function loaded() { function removeEntities(deletedIDs) { // Loop from the back so we can pop items off while iterating + + // delete any entities matching deletedIDs list from entities and entitiesByID lists + // if the entity had an associated row element then ensure row is unselected and clear it's entity for (let j = entities.length - 1; j >= 0; --j) { let id = entities[j].id; for (let i = 0, length = deletedIDs.length; i < length; ++i) { @@ -346,6 +346,7 @@ function loaded() { } } + // delete any entities matching deletedIDs list from selectedEntities list for (let j = selectedEntities.length - 1; j >= 0; --j) { let id = selectedEntities[j].id; for (let i = 0, length = deletedIDs.length; i < length; ++i) { @@ -355,14 +356,32 @@ function loaded() { } } } + + // delete any entities matching deletedIDs list from visibleEntities list + // if this was a row that was above our current row offset (a hidden top row in the top buffer), + // then decrease row offset accordingly + let firstVisibleRow = entityList.getFirstVisibleRowIndex(); + for (let j = visibleEntities.length - 1; j >= 0; --j) { + let id = visibleEntities[j].id; + for (let i = 0, length = deletedIDs.length; i < length; ++i) { + if (id === deletedIDs[i]) { + if (j < firstVisibleRow && entityList.rowOffset > 0) { + entityList.rowOffset--; + } + visibleEntities.splice(j, 1); + break; + } + } + } - entityList.removeItems(deletedIDs); + entityList.refresh(); refreshFooter(); refreshNoEntitiesMessage(); } function clearEntities() { + // clear the associated entity ID from all visible row elements let firstVisibleRow = entityList.getFirstVisibleRowIndex(); let lastVisibleRow = entityList.getLastVisibleRowIndex(); for (let i = firstVisibleRow; i <= lastVisibleRow && i < visibleEntities.length; i++) { @@ -372,9 +391,9 @@ function loaded() { entities = []; entitiesByID = {}; - visibleEntities = []; + visibleEntities.length = 0; // maintains itemData reference in ListView - entityList.resetRowOffset(); + entityList.resetToTop(); entityList.clear(); refreshFooter(); @@ -439,6 +458,7 @@ function loaded() { function updateSelectedEntities(selectedIDs) { let notFound = false; + // reset all currently selected entities and their rows first selectedEntities.forEach(function(id) { let entity = entitiesByID[id]; if (entity !== undefined) { @@ -449,8 +469,8 @@ function loaded() { } }); + // then reset selected entities list with newly selected entities and set them selected selectedEntities = []; - selectedIDs.forEach(function(id) { selectedEntities.push(id); let entity = entitiesByID[id]; @@ -489,6 +509,7 @@ function loaded() { } function updateRow(elRow, itemData) { + // update all column texts and glyphs to this entity's data let typeCell = elRow.childNodes[COLUMN_INDEX.TYPE]; typeCell.innerText = itemData.type; let nameCell = elRow.childNodes[COLUMN_INDEX.NAME]; @@ -514,12 +535,16 @@ function loaded() { let hasScriptCell = elRow.childNodes[COLUMN_INDEX.HAS_SCRIPT]; hasScriptCell.innerText = itemData.hasScript; + // if this entity was previously selected flag it's row as selected if (itemData.selected) { elRow.className = 'selected'; } else { elRow.className = ''; } - + + // if this row previously had an associated entity ID that wasn't the new entity ID then clear + // the ID from the row and the row element from the previous entity's data, then set the new + // entity ID to the row and the row element to the new entity's data let prevEntityID = elRow.dataset.entityID; let newEntityID = itemData.id; let validPrevItemID = prevEntityID !== undefined && prevEntityID !== EMPTY_ENTITY_ID; @@ -534,6 +559,7 @@ function loaded() { } function clearRow(elRow) { + // reset all texts and glyphs for each of the row's column for (let i = 0; i < NUM_COLUMNS; i++) { let cell = elRow.childNodes[i]; if (isGlyphColumn(i)) { @@ -543,22 +569,18 @@ function loaded() { } } + // clear the row from any associated entity let entityID = elRow.dataset.entityID; if (entityID && entitiesByID[entityID]) { entitiesByID[entityID].elRow = null; } + // reset the row to hidden and clear the entity from the row elRow.className = ''; elRow.dataset.entityID = EMPTY_ENTITY_ID; } function resize() { - // Store current scroll position - let prevScrollTop = elEntityTableScroll.scrollTop; - - // Take up available window space - elEntityTableScroll.style.height = window.innerHeight - 207; - let SCROLLABAR_WIDTH = 21; let tds = document.querySelectorAll("#entity-table-body tr:first-child td"); let ths = document.querySelectorAll("#entity-table thead th"); @@ -589,15 +611,8 @@ function loaded() { ths[3].width = 0.08 * tableWidth; ths[4].width = 0.08 * tableWidth; } - } - - // Reinitialize rows according to new table height and refresh row data - entityList.resetRows(window.innerHeight - WINDOW_NONVARIABLE_HEIGHT); - entityList.refresh(); - - // Restore scrolling to previous scroll position before resetting rows - elEntityTableScroll.scrollTop = prevScrollTop; - }; + } + } function toggleFilterInView() { isFilterInView = !isFilterInView; @@ -614,14 +629,15 @@ function loaded() { function onFilterChange() { refreshEntityList(); - resize(); + entityList.resize(); } function onRadiusChange() { elRadius.value = Math.max(elRadius.value, 0); + elNoEntitiesRadius.firstChild.nodeValue = elRadius.value; + elNoEntitiesMessage.style.display = "none"; EventBridge.emitWebEvent(JSON.stringify({ type: 'radius', radius: elRadius.value })); refreshEntities(); - elNoEntitiesRadius.firstChild.nodeValue = elRadius.value; } function toggleInfo(event) { @@ -633,7 +649,7 @@ function loaded() { elEntityTable.className = ""; elInfoToggleGlyph.innerHTML = EXPAND_EXTRA_INFO; } - resize(); + entityList.resize(); event.stopPropagation(); } @@ -644,7 +660,6 @@ function loaded() { let keyCode = keyDownEvent.keyCode; if (keyCode === DELETE) { EventBridge.emitWebEvent(JSON.stringify({ type: 'delete' })); - refreshEntities(); } if (keyDownEvent.keyCode === KEY_P && keyDownEvent.ctrlKey) { if (keyDownEvent.shiftKey) { @@ -686,7 +701,6 @@ function loaded() { }); } - resize(); refreshSortOrder(); refreshEntities(); }); diff --git a/scripts/system/html/js/listView.js b/scripts/system/html/js/listView.js index deb638e698..80e032bf70 100644 --- a/scripts/system/html/js/listView.js +++ b/scripts/system/html/js/listView.js @@ -13,7 +13,8 @@ debugPrint = function (message) { console.log(message); }; -function ListView(tableId, tableBodyId, tableScrollId, createRowFunction, updateRowFunction, clearRowFunction) { +function ListView(tableId, tableBodyId, tableScrollId, createRowFunction, updateRowFunction, + clearRowFunction, resizeFunction, WINDOW_NONVARIABLE_HEIGHT) { this.elTable = document.getElementById(tableId); this.elTableBody = document.getElementById(tableBodyId); this.elTableScroll = document.getElementById(tableScrollId); @@ -21,17 +22,22 @@ function ListView(tableId, tableBodyId, tableScrollId, createRowFunction, update this.elTopBuffer = null; this.elBottomBuffer = null; - this.elRows = []; - this.itemData = []; - this.createRowFunction = createRowFunction; this.updateRowFunction = updateRowFunction; this.clearRowFunction = clearRowFunction; + this.resizeFunction = resizeFunction; + + // the list of row elements created in the table up to max viewable height plus SCROLL_ROWS rows for scrolling buffer + this.elRows = []; + // the list of all row item data to show in the scrolling table, passed to updateRowFunction to set to each row + this.itemData = []; + // the current index within the itemData list that is set to the top most elRow element + this.rowOffset = 0; + // height of the elRow elements + this.rowHeight = 0; + // the previous elTableScroll.scrollTop value when the elRows were last shifted for scrolling + this.lastRowShiftScrollTop = 0; - this.rowOffset = 0; // the current index within the itemData list used for the top most elRow element - this.rowHeight = 0; // height of the elRow elements - this.lastRowChangeScrollTop = 0; // the previous elTableScroll.scrollTop value when the rows were scrolled - this.initialize(); }; @@ -52,144 +58,99 @@ ListView.prototype = { return this.getFirstVisibleRowIndex() + entityList.getNumRows() - 1; }, - resetRowOffset: function() { + resetToTop: function() { this.rowOffset = 0; - this.lastRowChangeScrollTop = 0; - }, - - removeItems: function(removeItems) { - let firstVisibleRow = this.getFirstVisibleRowIndex(); - let lastVisibleRow = this.getLastVisibleRowIndex(); - let prevRowOffset = this.rowOffset; - let prevTopHeight = parseInt(this.elTopBuffer.getAttribute("height")); - - // remove items from our itemData list that match anything in the removeItems list - // if this was a row that was above our current row offset (a hidden top row in the top buffer), - // then decrease row offset accordingly - let deletedHiddenTopRows = false; - let deletedVisibleRows = false; - for (let j = this.itemData.length - 1; j >= 0; --j) { - let id = this.itemData[j].id; - for (let i = 0, length = removeItems.length; i < length; ++i) { - if (id === removeItems[i]) { - if (j < firstVisibleRow) { - this.rowOffset--; - deletedHiddenTopRows = true; - } else if (j >= firstVisibleRow && j < lastVisibleRow) { - deletedVisibleRows = true; - } - this.itemData.splice(j, 1); - break; - } - } - } - - // if we deleted both hidden rows in the top buffer above our row offset as well as rows that are currently being - // shown, then we need to adjust the scroll position to compensate unless we are at the bottom of the list - let adjustScrollTop = deletedHiddenTopRows && deletedVisibleRows; - if (this.rowOffset + this.getNumRows() > this.itemData.length) { - this.rowOffset = this.itemData.length - this.getNumRows(); - adjustScrollTop = false; - } - - this.refresh(); - - // decrease the last scrolling point to adjust for the amount of row space that was lost from the removed items - let newTopHeight = parseInt(this.elTopBuffer.getAttribute("height")); - let topHeightChange = prevTopHeight - newTopHeight; - this.lastRowChangeScrollTop -= topHeightChange; - if (adjustScrollTop) { - this.elTableScroll.scrollTop -= topHeightChange; - } + this.lastRowShiftScrollTop = 0; + this.refreshBuffers(); + this.elTableScroll.scrollTop = 0; }, clear: function() { for (let i = 0; i < this.getNumRows(); i++) { let elRow = this.elTableBody.childNodes[i + FIRST_ROW_INDEX]; this.clearRowFunction(elRow); - elRow.style.display = "none"; + elRow.style.display = "none"; // hide cleared rows } }, - - scrollDown: function(numScrollRows) { - let prevTopHeight = parseInt(this.elTopBuffer.getAttribute("height")); - let prevBottomHeight = parseInt(this.elBottomBuffer.getAttribute("height")); - - // for each row to scroll down, move the top row element to the bottom of the - // table before the bottom buffer and reset it's row data to the new item - for (let i = 0; i < numScrollRows; i++) { - let rowMovedTopToBottom = this.elTableBody.childNodes[FIRST_ROW_INDEX]; - let rowIndex = this.getNumRows() + this.rowOffset; - this.elTableBody.removeChild(rowMovedTopToBottom); - this.elTableBody.insertBefore(rowMovedTopToBottom, this.elBottomBuffer); - this.updateRowFunction(rowMovedTopToBottom, this.itemData[rowIndex]); - this.rowOffset++; - } - - // add the row space that was scrolled away to the top buffer height and last scroll point - // remove the row space that was scrolled away from the bottom buffer height - let scrolledSpace = this.rowHeight * numScrollRows; - let newTopHeight = prevTopHeight + scrolledSpace; - let newBottomHeight = prevBottomHeight - scrolledSpace; - this.elTopBuffer.setAttribute("height", newTopHeight); - this.elBottomBuffer.setAttribute("height", newBottomHeight); - this.lastRowChangeScrollTop += scrolledSpace; - }, - - scrollUp: function(numScrollRows) { - let prevTopHeight = parseInt(this.elTopBuffer.getAttribute("height")); - let prevBottomHeight = parseInt(this.elBottomBuffer.getAttribute("height")); - // for each row to scroll up, move the bottom row element to the top of - // the table before the top row and reset it's row data to the new item - for (let i = 0; i < numScrollRows; i++) { - let topRow = this.elTableBody.childNodes[FIRST_ROW_INDEX]; - let rowMovedBottomToTop = this.elTableBody.childNodes[FIRST_ROW_INDEX + this.getNumRows() - 1]; - let rowIndex = this.rowOffset - 1; - this.elTableBody.removeChild(rowMovedBottomToTop); - this.elTableBody.insertBefore(rowMovedBottomToTop, topRow); - this.updateRowFunction(rowMovedBottomToTop, this.itemData[rowIndex]); - this.rowOffset--; - } - - // remove the row space that was scrolled away from the top buffer height and last scroll point - // add the row space that was scrolled away to the bottom buffer height - let scrolledSpace = this.rowHeight * numScrollRows; - let newTopHeight = prevTopHeight - scrolledSpace; - let newBottomHeight = prevBottomHeight + scrolledSpace; - this.elTopBuffer.setAttribute("height", newTopHeight); - this.elBottomBuffer.setAttribute("height", newBottomHeight); - this.lastRowChangeScrollTop -= scrolledSpace; - }, - onScroll: function() { var that = this.listView; - - let scrollTop = that.elTableScroll.scrollTop; - let scrollHeight = that.getScrollHeight(); - let nextRowChangeScrollTop = that.lastRowChangeScrollTop + scrollHeight; - let totalItems = that.itemData.length; - let numRows = that.getNumRows(); + that.scroll(); + }, + + scroll: function() { + let scrollTop = this.elTableScroll.scrollTop; + let scrollHeight = this.getScrollHeight(); + let nextRowChangeScrollTop = this.lastRowShiftScrollTop + scrollHeight; + let totalItems = this.itemData.length; + let numRows = this.getNumRows(); // if the top of the scroll area has past the amount of scroll row space since the last point of scrolling and there // are still more rows to scroll to then trigger a scroll down by the min of the scroll row space or number of // remaining rows below // if the top of the scroll area has gone back above the last point of scrolling then trigger a scroll up by min of // the scroll row space or number of rows above - if (scrollTop >= nextRowChangeScrollTop && numRows + that.rowOffset < totalItems) { + if (scrollTop >= nextRowChangeScrollTop && numRows + this.rowOffset < totalItems) { let numScrolls = Math.ceil((scrollTop - nextRowChangeScrollTop) / scrollHeight); let numScrollRows = numScrolls * SCROLL_ROWS; - if (numScrollRows + that.rowOffset + numRows > totalItems) { - numScrollRows = totalItems - that.rowOffset - numRows; + if (numScrollRows + this.rowOffset + numRows > totalItems) { + numScrollRows = totalItems - this.rowOffset - numRows; } - that.scrollDown(numScrollRows); - } else if (scrollTop < that.lastRowChangeScrollTop) { - let numScrolls = Math.ceil((that.lastRowChangeScrollTop - scrollTop) / scrollHeight); + this.scrollRows(numScrollRows); + } else if (scrollTop < this.lastRowShiftScrollTop) { + let numScrolls = Math.ceil((this.lastRowShiftScrollTop - scrollTop) / scrollHeight); let numScrollRows = numScrolls * SCROLL_ROWS; - if (that.rowOffset - numScrollRows < 0) { - numScrollRows = that.rowOffset; + if (this.rowOffset - numScrollRows < 0) { + numScrollRows = this.rowOffset; } - that.scrollUp(numScrollRows); + this.scrollRows(-numScrollRows); + } + }, + + scrollRows: function(numScrollRows) { + let numScrollRowsAbsolute = Math.abs(numScrollRows); + if (numScrollRowsAbsolute === 0) { + return; + } + + let scrollDown = numScrollRows > 0; + + let prevTopHeight = parseInt(this.elTopBuffer.getAttribute("height")); + let prevBottomHeight = parseInt(this.elBottomBuffer.getAttribute("height")); + + // if the number of rows to scroll at once is greater than the total visible number of row elements, + // then just advance the rowOffset accordingly and allow the refresh below to update all rows + if (numScrollRowsAbsolute > this.getNumRows()) { + this.rowOffset += numScrollRows; + } else { + // for each row to scroll down, move the top row element to the bottom of the + // table before the bottom buffer and reset it's row data to the new item + // for each row to scroll up, move the bottom row element to the top of + // the table before the top row and reset it's row data to the new item + for (let i = 0; i < numScrollRowsAbsolute; i++) { + let topRow = this.elTableBody.childNodes[FIRST_ROW_INDEX]; + let rowToMove = scrollDown ? topRow : this.elTableBody.childNodes[FIRST_ROW_INDEX + this.getNumRows() - 1]; + let rowIndex = scrollDown ? this.getNumRows() + this.rowOffset : this.rowOffset - 1; + let moveRowBefore = scrollDown ? this.elBottomBuffer : topRow; + this.elTableBody.removeChild(rowToMove); + this.elTableBody.insertBefore(rowToMove, moveRowBefore); + this.updateRowFunction(rowToMove, this.itemData[rowIndex]); + this.rowOffset += scrollDown ? 1 : -1; + } + } + + // add/remove the row space that was scrolled away to the top buffer height and last scroll point + // add/remove the row space that was scrolled away to the bottom buffer height + let scrolledSpace = this.rowHeight * numScrollRows; + let newTopHeight = prevTopHeight + scrolledSpace; + let newBottomHeight = prevBottomHeight - scrolledSpace; + this.elTopBuffer.setAttribute("height", newTopHeight); + this.elBottomBuffer.setAttribute("height", newBottomHeight); + this.lastRowShiftScrollTop += scrolledSpace; + + // if scrolling more than the total number of visible rows at once then refresh all row data + if (numScrollRowsAbsolute > this.getNumRows()) { + this.refresh(); } }, @@ -200,9 +161,14 @@ ListView.prototype = { return; } + let prevScrollTop = this.elTableScroll.scrollTop; + // start with all row data cleared and initially set to invisible this.clear(); + // if we are at the bottom of the list adjust row offset to make sure all rows stay in view + this.refreshRowOffset(); + // update all row data and set rows visible until max visible items reached for (let i = 0; i < numRows; i++) { let rowIndex = i + this.rowOffset; @@ -213,16 +179,30 @@ ListView.prototype = { let elRow = this.elTableBody.childNodes[rowElementIndex]; let itemData = this.itemData[rowIndex]; this.updateRowFunction(elRow, itemData); - elRow.style.display = ""; + elRow.style.display = ""; // make sure the row is visible } + // update the top and bottom buffer heights to adjust for above changes + this.refreshBuffers(); + + // adjust the last row shift scroll point based on how much the current scroll point changed + let scrollTopDifference = this.elTableScroll.scrollTop - prevScrollTop; + if (scrollTopDifference !== 0) { + this.lastRowShiftScrollTop += scrollTopDifference; + if (this.lastRowShiftScrollTop < 0) { + this.lastRowShiftScrollTop = 0; + } + } + }, + + refreshBuffers: function() { // top buffer height is the number of hidden rows above the top row let topHiddenRows = this.rowOffset; let topBufferHeight = this.rowHeight * topHiddenRows; this.elTopBuffer.setAttribute("height", topBufferHeight); // bottom buffer height is the number of hidden rows below the bottom row (last scroll buffer row) - let bottomHiddenRows = this.itemData.length - numRows - this.rowOffset; + let bottomHiddenRows = this.itemData.length - this.getNumRows() - this.rowOffset; let bottomBufferHeight = this.rowHeight * bottomHiddenRows; if (bottomHiddenRows < 0) { bottomBufferHeight = 0; @@ -230,40 +210,64 @@ ListView.prototype = { this.elBottomBuffer.setAttribute("height", bottomBufferHeight); }, - resetRows: function(viewableHeight) { - if (!this.elTableBody) { - debugPrint("ListView.resetRows - no valid table body element"); + refreshRowOffset: function() { + // make sure the row offset isn't causing visible rows to pass the end of the item list and is clamped to 0 + var numRows = this.getNumRows(); + if (this.rowOffset + numRows > this.itemData.length) { + this.rowOffset = this.itemData.length - numRows; + } + if (this.rowOffset < 0) { + this.rowOffset = 0; + } + }, + + onResize: function() { + var that = this.listView; + that.resize(); + }, + + resize: function() { + if (!this.elTableBody || !this.elTableScroll) { + debugPrint("ListView.resize - no valid table body or table scroll element"); return; } - - this.resetRowOffset(); - - this.elTopBuffer.setAttribute("height", 0); - this.elBottomBuffer.setAttribute("height", 0); - // clear out any existing rows + let prevScrollTop = this.elTableScroll.scrollTop; + + // take up available window space + this.elTableScroll.style.height = window.innerHeight - WINDOW_NONVARIABLE_HEIGHT; + let viewableHeight = parseInt(this.elTableScroll.style.height) + 1; + + // remove all existing row elements and clear row list for (let i = 0; i < this.getNumRows(); i++) { - let elRow = elRows[i]; + let elRow = this.elRows[i]; this.elTableBody.removeChild(elRow); } this.elRows = []; - // create new row elements inserted between the top and bottom buffers that can fit into viewable scroll area + // create new row elements inserted between the top and bottom buffers up until the max viewable scroll area let usedHeight = 0; while(usedHeight < viewableHeight) { let newRow = this.createRowFunction(); this.elTableBody.insertBefore(newRow, this.elBottomBuffer); - this.rowHeight = this.elTableBody.offsetHeight - usedHeight; - usedHeight = this.elTableBody.offsetHeight; + this.rowHeight = newRow.offsetHeight; + usedHeight += this.rowHeight; this.elRows.push(newRow); } - // add extras rows for scrolling buffer purposes + // add SCROLL_ROWS extras rows for scrolling buffer purposes for (let i = 0; i < SCROLL_ROWS; i++) { let scrollRow = this.createRowFunction(); this.elTableBody.insertBefore(scrollRow, this.elBottomBuffer); this.elRows.push(scrollRow); } + + this.resizeFunction(); + + // restore the scroll point to the same scroll point from before above changes + this.elTableScroll.scrollTop = prevScrollTop; + + this.refresh(); }, initialize: function() { @@ -285,5 +289,10 @@ ListView.prototype = { this.elTableScroll.listView = this; this.elTableScroll.onscroll = this.onScroll; + window.listView = this; + window.onresize = this.onResize; + + // initialize all row elements + this.resize(); } };