Merge pull request #14421 from dback2/entityListReorderColumns

Entity list - reorder columns
This commit is contained in:
John Conklin II 2018-12-07 10:59:02 -08:00 committed by GitHub
commit d7e3935d57
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 117 additions and 40 deletions

View file

@ -1390,6 +1390,10 @@ input[type=button]#export {
cursor: col-resize; cursor: col-resize;
} }
#entity-table .dragging {
background-color: #b3ecff;
}
#entity-table td { #entity-table td {
box-sizing: border-box; box-sizing: border-box;
} }

View file

@ -21,6 +21,8 @@ const MAX_LENGTH_RADIUS = 9;
const MINIMUM_COLUMN_WIDTH = 24; const MINIMUM_COLUMN_WIDTH = 24;
const SCROLLBAR_WIDTH = 20; const SCROLLBAR_WIDTH = 20;
const RESIZER_WIDTH = 10; const RESIZER_WIDTH = 10;
const DELTA_X_MOVE_COLUMNS_THRESHOLD = 2;
const DELTA_X_COLUMN_SWAP_POSITION = 5;
const COLUMNS = { const COLUMNS = {
type: { type: {
@ -108,8 +110,8 @@ const COLUMNS = {
}; };
const COMPARE_ASCENDING = function(a, b) { const COMPARE_ASCENDING = function(a, b) {
let va = a[currentSortColumn]; let va = a[currentSortColumnID];
let vb = b[currentSortColumn]; let vb = b[currentSortColumnID];
if (va < vb) { if (va < vb) {
return -1; return -1;
@ -172,7 +174,7 @@ let entityList = null; // The ListView
*/ */
let entityListContextMenu = null; let entityListContextMenu = null;
let currentSortColumn = 'type'; let currentSortColumnID = 'type';
let currentSortOrder = ASCENDING_SORT; let currentSortOrder = ASCENDING_SORT;
let elSortOrders = {}; let elSortOrders = {};
let typeFilters = []; let typeFilters = [];
@ -180,10 +182,13 @@ let isFilterInView = false;
let columns = []; let columns = [];
let columnsByID = {}; let columnsByID = {};
let currentResizeEl = null; let lastResizeEvent = null;
let startResizeEvent = null;
let resizeColumnIndex = 0; let resizeColumnIndex = 0;
let startThClick = null; let elTargetTh = null;
let elTargetSpan = null;
let targetColumnIndex = 0;
let lastColumnSwapPosition = -1;
let initialThEvent = null;
let renameTimeout = null; let renameTimeout = null;
let renameLastBlur = null; let renameLastBlur = null;
let renameLastEntityID = null; let renameLastEntityID = null;
@ -230,10 +235,6 @@ const PROFILE = !ENABLE_PROFILING ? PROFILE_NOOP : function(name, fn, args) {
console.log("PROFILE-Web " + profileIndent + "(" + name + ") End " + delta + "ms"); console.log("PROFILE-Web " + profileIndent + "(" + name + ") End " + delta + "ms");
}; };
debugPrint = function (message) {
console.log(message);
};
function loaded() { function loaded() {
openEventBridge(function() { openEventBridge(function() {
elEntityTable = document.getElementById("entity-table"); elEntityTable = document.getElementById("entity-table");
@ -324,10 +325,11 @@ function loaded() {
for (let columnID in COLUMNS) { for (let columnID in COLUMNS) {
let columnData = COLUMNS[columnID]; let columnData = COLUMNS[columnID];
let thID = "entity-" + columnID;
let elTh = document.createElement("th"); let elTh = document.createElement("th");
let thID = "entity-" + columnID;
elTh.setAttribute("id", thID); elTh.setAttribute("id", thID);
elTh.setAttribute("data-resizable-column-id", thID); elTh.setAttribute("columnIndex", columnIndex);
elTh.setAttribute("columnID", columnID);
if (columnData.glyph) { if (columnData.glyph) {
let elGlyph = document.createElement("span"); let elGlyph = document.createElement("span");
elGlyph.className = "glyph"; elGlyph.className = "glyph";
@ -336,20 +338,20 @@ function loaded() {
} else { } else {
elTh.innerText = columnData.columnHeader; elTh.innerText = columnData.columnHeader;
} }
elTh.onmousedown = function() { elTh.onmousedown = function(event) {
startThClick = this; if (event.target.nodeName === 'TH') {
}; elTargetTh = event.target;
elTh.onmouseup = function() { targetColumnIndex = parseInt(elTargetTh.getAttribute("columnIndex"));
if (startThClick === this) { lastColumnSwapPosition = event.clientX;
setSortColumn(columnID); } else if (event.target.nodeName === 'SPAN') {
elTargetSpan = event.target;
} }
startThClick = null; initialThEvent = event;
}; };
let elResizer = document.createElement("span"); let elResizer = document.createElement("span");
elResizer.className = "resizer"; elResizer.className = "resizer";
elResizer.innerHTML = "&nbsp;"; elResizer.innerHTML = "&nbsp;";
elResizer.setAttribute("columnIndex", columnIndex);
elResizer.onmousedown = onStartResize; elResizer.onmousedown = onStartResize;
elTh.appendChild(elResizer); elTh.appendChild(elResizer);
@ -762,13 +764,13 @@ function loaded() {
refreshNoEntitiesMessage(); refreshNoEntitiesMessage();
} }
function setSortColumn(column) { function setSortColumn(columnID) {
PROFILE("set-sort-column", function() { PROFILE("set-sort-column", function() {
if (currentSortColumn === column) { if (currentSortColumnID === columnID) {
currentSortOrder *= -1; currentSortOrder *= -1;
} else { } else {
elSortOrders[currentSortColumn].innerHTML = ""; elSortOrders[currentSortColumnID].innerHTML = "";
currentSortColumn = column; currentSortColumnID = columnID;
currentSortOrder = ASCENDING_SORT; currentSortOrder = ASCENDING_SORT;
} }
refreshSortOrder(); refreshSortOrder();
@ -777,7 +779,7 @@ function loaded() {
} }
function refreshSortOrder() { function refreshSortOrder() {
elSortOrders[currentSortColumn].innerHTML = currentSortOrder === ASCENDING_SORT ? ASCENDING_STRING : DESCENDING_STRING; elSortOrders[currentSortColumnID].innerHTML = currentSortOrder === ASCENDING_SORT ? ASCENDING_STRING : DESCENDING_STRING;
} }
function refreshEntities() { function refreshEntities() {
@ -1093,8 +1095,8 @@ function loaded() {
} }
function onStartResize(event) { function onStartResize(event) {
startResizeEvent = event; lastResizeEvent = event;
resizeColumnIndex = parseInt(this.getAttribute("columnIndex")); resizeColumnIndex = parseInt(this.parentNode.getAttribute("columnIndex"));
event.stopPropagation(); event.stopPropagation();
} }
@ -1137,8 +1139,37 @@ function loaded() {
entityList.refresh(); entityList.refresh();
} }
document.onmousemove = function(ev) { function swapColumns(columnAIndex, columnBIndex) {
if (startResizeEvent) { let columnA = columns[columnAIndex];
let columnB = columns[columnBIndex];
let columnATh = columns[columnAIndex].elTh;
let columnBTh = columns[columnBIndex].elTh;
let columnThParent = columnATh.parentNode;
columnThParent.removeChild(columnBTh);
columnThParent.insertBefore(columnBTh, columnATh);
columnATh.setAttribute("columnIndex", columnBIndex);
columnBTh.setAttribute("columnIndex", columnAIndex);
columnA.elResizer.setAttribute("columnIndex", columnBIndex);
columnB.elResizer.setAttribute("columnIndex", columnAIndex);
for (let i = 0; i < visibleEntities.length; ++i) {
let elRow = visibleEntities[i].elRow;
if (elRow) {
let columnACell = elRow.childNodes[columnAIndex];
let columnBCell = elRow.childNodes[columnBIndex];
elRow.removeChild(columnBCell);
elRow.insertBefore(columnBCell, columnACell);
}
}
columns[columnAIndex] = columnB;
columns[columnBIndex] = columnA;
updateColumnWidths();
}
document.onmousemove = function(event) {
if (lastResizeEvent) {
startTh = null; startTh = null;
let column = columns[resizeColumnIndex]; let column = columns[resizeColumnIndex];
@ -1150,7 +1181,7 @@ function loaded() {
} }
let fullWidth = elEntityTableBody.offsetWidth; let fullWidth = elEntityTableBody.offsetWidth;
let dx = ev.clientX - startResizeEvent.clientX; let dx = event.clientX - lastResizeEvent.clientX;
let dPct = dx / fullWidth; let dPct = dx / fullWidth;
let newColWidth = column.width + dPct; let newColWidth = column.width + dPct;
@ -1160,14 +1191,60 @@ function loaded() {
column.width += dPct; column.width += dPct;
nextColumn.width -= dPct; nextColumn.width -= dPct;
updateColumnWidths(); updateColumnWidths();
startResizeEvent = ev; lastResizeEvent = event;
}
} else if (elTargetTh) {
let dxFromInitial = event.clientX - initialThEvent.clientX;
if (Math.abs(dxFromInitial) >= DELTA_X_MOVE_COLUMNS_THRESHOLD) {
elTargetTh.className = "dragging";
}
if (targetColumnIndex < columns.length - 1) {
let nextColumnIndex = targetColumnIndex + 1;
let nextColumnTh = columns[nextColumnIndex].elTh;
let nextColumnStartX = nextColumnTh.getBoundingClientRect().left;
if (event.clientX >= nextColumnStartX && event.clientX - lastColumnSwapPosition >= DELTA_X_COLUMN_SWAP_POSITION) {
swapColumns(targetColumnIndex, nextColumnIndex);
targetColumnIndex = nextColumnIndex;
lastColumnSwapPosition = event.clientX;
}
}
if (targetColumnIndex >= 1) {
let prevColumnIndex = targetColumnIndex - 1;
let prevColumnTh = columns[prevColumnIndex].elTh;
let prevColumnEndX = prevColumnTh.getBoundingClientRect().right;
if (event.clientX <= prevColumnEndX && lastColumnSwapPosition - event.clientX >= DELTA_X_COLUMN_SWAP_POSITION) {
swapColumns(prevColumnIndex, targetColumnIndex);
targetColumnIndex = prevColumnIndex;
lastColumnSwapPosition = event.clientX;
}
}
} else if (elTargetSpan) {
let dxFromInitial = event.clientX - initialThEvent.clientX;
if (Math.abs(dxFromInitial) >= DELTA_X_MOVE_COLUMNS_THRESHOLD) {
elTargetTh = elTargetSpan.parentNode;
elTargetTh.className = "dragging";
targetColumnIndex = parseInt(elTargetTh.getAttribute("columnIndex"));
lastColumnSwapPosition = event.clientX;
elTargetSpan = null;
} }
} }
}; };
document.onmouseup = function(ev) { document.onmouseup = function(event) {
startResizeEvent = null; if (elTargetTh) {
ev.stopPropagation(); if (elTargetTh.className !== "dragging" && elTargetTh === event.target) {
let columnID = elTargetTh.getAttribute("columnID");
setSortColumn(columnID);
}
elTargetTh.className = "";
} else if (elTargetSpan) {
let columnID = elTargetSpan.parentNode.getAttribute("columnID");
setSortColumn(columnID);
}
lastResizeEvent = null;
elTargetTh = null;
elTargetSpan = null;
initialThEvent = null;
}; };
function setSpaceMode(spaceMode) { function setSpaceMode(spaceMode) {

View file

@ -9,10 +9,6 @@
const SCROLL_ROWS = 2; // number of rows used as scrolling buffer, each time we pass this number of rows we scroll const SCROLL_ROWS = 2; // number of rows used as scrolling buffer, each time we pass this number of rows we scroll
const FIRST_ROW_INDEX = 2; // the first elRow element's index in the child nodes of the table body const FIRST_ROW_INDEX = 2; // the first elRow element's index in the child nodes of the table body
debugPrint = function (message) {
console.log(message);
};
function ListView(elTableBody, elTableScroll, elTableHeaderRow, createRowFunction, updateRowFunction, clearRowFunction, function ListView(elTableBody, elTableScroll, elTableHeaderRow, createRowFunction, updateRowFunction, clearRowFunction,
preRefreshFunction, postRefreshFunction, preResizeFunction, WINDOW_NONVARIABLE_HEIGHT) { preRefreshFunction, postRefreshFunction, preResizeFunction, WINDOW_NONVARIABLE_HEIGHT) {
this.elTableBody = elTableBody; this.elTableBody = elTableBody;
@ -246,7 +242,7 @@ ListView.prototype = {
resize: function() { resize: function() {
if (!this.elTableBody || !this.elTableScroll) { if (!this.elTableBody || !this.elTableScroll) {
debugPrint("ListView.resize - no valid table body or table scroll element"); console.log("ListView.resize - no valid table body or table scroll element");
return; return;
} }
this.preResizeFunction(); this.preResizeFunction();
@ -288,7 +284,7 @@ ListView.prototype = {
initialize: function() { initialize: function() {
if (!this.elTableBody || !this.elTableScroll) { if (!this.elTableBody || !this.elTableScroll) {
debugPrint("ListView.initialize - no valid table body or table scroll element"); console.log("ListView.initialize - no valid table body or table scroll element");
return; return;
} }