forked from mbk-lab/rui_orig
Added TableView cell/row selection mode
This commit is contained in:
parent
15a11dc558
commit
1a4040bd00
|
@ -1,3 +1,7 @@
|
||||||
|
# v0.5.0
|
||||||
|
|
||||||
|
* Added HasFocus function to the View interface
|
||||||
|
|
||||||
# v0.4.0
|
# v0.4.0
|
||||||
|
|
||||||
* Added SetTitle and SetTitleColor function to the Session interface
|
* Added SetTitle and SetTitleColor function to the Session interface
|
||||||
|
|
481
app_scripts.js
481
app_scripts.js
|
@ -615,11 +615,12 @@ function selectDropDownListItem(elementId, number) {
|
||||||
|
|
||||||
function listItemClickEvent(element, event) {
|
function listItemClickEvent(element, event) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
||||||
var selected = false;
|
var selected = false;
|
||||||
if (element.classList) {
|
if (element.classList) {
|
||||||
selected = (element.classList.contains("ruiListItemFocused") || element.classList.contains("ruiListItemSelected"));
|
const focusStyle = getListFocusedItemStyle(element);
|
||||||
} else {
|
const blurStyle = getListSelectedItemStyle(element);
|
||||||
selected = element.className.indexOf("ruiListItemFocused") >= 0 || element.className.indexOf("ruiListItemSelected") >= 0;
|
selected = (element.classList.contains(focusStyle) || element.classList.contains(blurStyle));
|
||||||
}
|
}
|
||||||
|
|
||||||
var list = element.parentNode.parentNode
|
var list = element.parentNode.parentNode
|
||||||
|
@ -640,18 +641,27 @@ function getListItemNumber(itemId) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getStyleAttribute(element, attr, defValue) {
|
||||||
|
var result = element.getAttribute(attr);
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return defValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getListFocusedItemStyle(element) {
|
||||||
|
return getStyleAttribute(element, "data-focusitemstyle", "ruiListItemFocused");
|
||||||
|
}
|
||||||
|
|
||||||
|
function getListSelectedItemStyle(element) {
|
||||||
|
return getStyleAttribute(element, "data-bluritemstyle", "ruiListItemSelected");
|
||||||
|
}
|
||||||
|
|
||||||
function selectListItem(element, item, needSendMessage) {
|
function selectListItem(element, item, needSendMessage) {
|
||||||
var currentId = element.getAttribute("data-current");
|
var currentId = element.getAttribute("data-current");
|
||||||
var message;
|
var message;
|
||||||
var focusStyle = element.getAttribute("data-focusitemstyle");
|
const focusStyle = getListFocusedItemStyle(element);
|
||||||
var blurStyle = element.getAttribute("data-bluritemstyle");
|
const blurStyle = getListSelectedItemStyle(element);
|
||||||
|
|
||||||
if (!focusStyle) {
|
|
||||||
focusStyle = "ruiListItemFocused"
|
|
||||||
}
|
|
||||||
if (!blurStyle) {
|
|
||||||
blurStyle = "ruiListItemSelected"
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentId) {
|
if (currentId) {
|
||||||
var current = document.getElementById(currentId);
|
var current = document.getElementById(currentId);
|
||||||
|
@ -801,24 +811,29 @@ function findBottomListItem(list, x, y) {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
function listViewKeyDownEvent(element, event) {
|
function getKey(event) {
|
||||||
var key;
|
|
||||||
if (event.key) {
|
if (event.key) {
|
||||||
key = event.key;
|
return event.key;
|
||||||
} else if (event.keyCode) {
|
}
|
||||||
|
|
||||||
|
if (event.keyCode) {
|
||||||
switch (event.keyCode) {
|
switch (event.keyCode) {
|
||||||
case 13: key = "Enter"; break;
|
case 13: return "Enter";
|
||||||
case 32: key = " "; break;
|
case 32: return " ";
|
||||||
case 33: key = "PageUp"; break;
|
case 33: return "PageUp";
|
||||||
case 34: key = "PageDown"; break;
|
case 34: return "PageDown";
|
||||||
case 35: key = "End"; break;
|
case 35: return "End";
|
||||||
case 36: key = "Home"; break;
|
case 36: return "Home";
|
||||||
case 37: key = "ArrowLeft"; break;
|
case 37: return "ArrowLeft";
|
||||||
case 38: key = "ArrowUp"; break;
|
case 38: return "ArrowUp";
|
||||||
case 39: key = "ArrowRight"; break;
|
case 39: return "ArrowRight";
|
||||||
case 40: key = "ArrowDown"; break;
|
case 40: return "ArrowDown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function listViewKeyDownEvent(element, event) {
|
||||||
|
const key = getKey(event);
|
||||||
if (key) {
|
if (key) {
|
||||||
var currentId = element.getAttribute("data-current");
|
var currentId = element.getAttribute("data-current");
|
||||||
var current
|
var current
|
||||||
|
@ -885,20 +900,9 @@ function listViewFocusEvent(element, event) {
|
||||||
if (currentId) {
|
if (currentId) {
|
||||||
var current = document.getElementById(currentId);
|
var current = document.getElementById(currentId);
|
||||||
if (current) {
|
if (current) {
|
||||||
var focusStyle = element.getAttribute("data-focusitemstyle");
|
|
||||||
var blurStyle = element.getAttribute("data-bluritemstyle");
|
|
||||||
if (!focusStyle) {
|
|
||||||
focusStyle = "ruiListItemFocused"
|
|
||||||
}
|
|
||||||
if (!blurStyle) {
|
|
||||||
blurStyle = "ruiListItemSelected"
|
|
||||||
}
|
|
||||||
|
|
||||||
if (current.classList) {
|
if (current.classList) {
|
||||||
current.classList.remove(blurStyle);
|
current.classList.remove(getListSelectedItemStyle(element));
|
||||||
current.classList.add(focusStyle);
|
current.classList.add(getListFocusedItemStyle(element));
|
||||||
} else { // IE < 10
|
|
||||||
current.className = "ruiListItem " + focusStyle;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -909,20 +913,9 @@ function listViewBlurEvent(element, event) {
|
||||||
if (currentId) {
|
if (currentId) {
|
||||||
var current = document.getElementById(currentId);
|
var current = document.getElementById(currentId);
|
||||||
if (current) {
|
if (current) {
|
||||||
var focusStyle = element.getAttribute("data-focusitemstyle");
|
|
||||||
var blurStyle = element.getAttribute("data-bluritemstyle");
|
|
||||||
if (!focusStyle) {
|
|
||||||
focusStyle = "ruiListItemFocused"
|
|
||||||
}
|
|
||||||
if (!blurStyle) {
|
|
||||||
blurStyle = "ruiListItemSelected"
|
|
||||||
}
|
|
||||||
|
|
||||||
if (current.classList) {
|
if (current.classList) {
|
||||||
current.classList.remove(focusStyle);
|
current.classList.remove(getListFocusedItemStyle(element));
|
||||||
current.classList.add(blurStyle);
|
current.classList.add(getListSelectedItemStyle(element));
|
||||||
} else { // IE < 10
|
|
||||||
current.className = "ruiListItem " + blurStyle;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1373,3 +1366,387 @@ function setTitleColor(color) {
|
||||||
function detailsEvent(element) {
|
function detailsEvent(element) {
|
||||||
sendMessage("details-open{session=" + sessionID + ",id=" + element.id + ",open=" + (element.open ? "1}" : "0}"));
|
sendMessage("details-open{session=" + sessionID + ",id=" + element.id + ",open=" + (element.open ? "1}" : "0}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getTableFocusedItemStyle(element) {
|
||||||
|
return getStyleAttribute(element, "data-focusitemstyle", "ruiCurrentTableCellFocused");
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTableSelectedItemStyle(element) {
|
||||||
|
return getStyleAttribute(element, "data-bluritemstyle", "ruiCurrentTableCell");
|
||||||
|
}
|
||||||
|
|
||||||
|
function tableViewFocusEvent(element, event) {
|
||||||
|
var currentId = element.getAttribute("data-current");
|
||||||
|
if (currentId) {
|
||||||
|
var current = document.getElementById(currentId);
|
||||||
|
if (current) {
|
||||||
|
if (current.classList) {
|
||||||
|
current.classList.remove(getTableSelectedItemStyle(element));
|
||||||
|
current.classList.add(getTableFocusedItemStyle(element));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function tableViewBlurEvent(element, event) {
|
||||||
|
var currentId = element.getAttribute("data-current");
|
||||||
|
if (currentId) {
|
||||||
|
var current = document.getElementById(currentId);
|
||||||
|
if (current && current.classList) {
|
||||||
|
current.classList.remove(getTableFocusedItemStyle(element));
|
||||||
|
current.classList.add(getTableSelectedItemStyle(element));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setTableCellCursor(element, row, column) {
|
||||||
|
const cellID = element.id + "-" + row + "-" + column;
|
||||||
|
var cell = document.getElementById(cellID);
|
||||||
|
if (!cell) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const focusStyle = getTableFocusedItemStyle(element);
|
||||||
|
const oldCellID = element.getAttribute("data-current");
|
||||||
|
if (oldCellID) {
|
||||||
|
const oldCell = document.getElementById(oldCellID);
|
||||||
|
if (oldCell && oldCell.classList) {
|
||||||
|
oldCell.classList.remove(focusStyle);
|
||||||
|
oldCell.classList.remove(getTableSelectedItemStyle(element));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cell.classList.add(focusStyle);
|
||||||
|
element.setAttribute("data-current", cellID);
|
||||||
|
|
||||||
|
sendMessage("currentCell{session=" + sessionID + ",id=" + element.id +
|
||||||
|
",row=" + row + ",column=" + column + "}");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function moveTableCellCursor(element, row, column, dr, dc) {
|
||||||
|
const rows = element.getAttribute("data-rows");
|
||||||
|
if (!rows) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const columns = element.getAttribute("data-columns");
|
||||||
|
if (!columns) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rowCount = parseInt(rows);
|
||||||
|
const columnCount = parseInt(columns);
|
||||||
|
|
||||||
|
row += dr;
|
||||||
|
column += dc;
|
||||||
|
while (row >= 0 && row < rowCount && column >= 0 && column < columnCount) {
|
||||||
|
if (setTableCellCursor(element, row, column)) {
|
||||||
|
return;
|
||||||
|
} else if (dr == 0) {
|
||||||
|
var r2 = row - 1;
|
||||||
|
while (r2 >= 0) {
|
||||||
|
if (setTableCellCursor(element, r2, column)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
r2--;
|
||||||
|
}
|
||||||
|
} else if (dc == 0) {
|
||||||
|
var c2 = column - 1;
|
||||||
|
while (c2 >= 0) {
|
||||||
|
if (setTableCellCursor(element, row, c2)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
c2--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
row += dr;
|
||||||
|
column += dc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function tableViewCellKeyDownEvent(element, event) {
|
||||||
|
const key = getKey(event);
|
||||||
|
if (key) {
|
||||||
|
const currentId = element.getAttribute("data-current");
|
||||||
|
if (currentId) {
|
||||||
|
const elements = currentId.split("-");
|
||||||
|
if (elements.length >= 3) {
|
||||||
|
const row = parseInt(elements[1], 10)
|
||||||
|
const column = parseInt(elements[2], 10)
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case " ":
|
||||||
|
case "Enter":
|
||||||
|
sendMessage("cellClick{session=" + sessionID + ",id=" + element.id +
|
||||||
|
",row=" + row + ",column=" + column + "}");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "ArrowLeft":
|
||||||
|
moveTableCellCursor(element, row, column, 0, -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "ArrowRight":
|
||||||
|
moveTableCellCursor(element, row, column, 0, 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "ArrowDown":
|
||||||
|
moveTableCellCursor(element, row, column, 1, 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "ArrowUp":
|
||||||
|
moveTableCellCursor(element, row, column, -1, 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Home":
|
||||||
|
// TODO
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "End":
|
||||||
|
/*var newRow = rowCount-1;
|
||||||
|
while (newRow > row) {
|
||||||
|
if (setTableRowCursor(element, newRow)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
newRow--;
|
||||||
|
}*/
|
||||||
|
// TODO
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "PageUp":
|
||||||
|
// TODO
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "PageDown":
|
||||||
|
// TODO
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case "ArrowLeft":
|
||||||
|
case "ArrowRight":
|
||||||
|
case "ArrowDown":
|
||||||
|
case "ArrowUp":
|
||||||
|
case "Home":
|
||||||
|
case "End":
|
||||||
|
case "PageUp":
|
||||||
|
case "PageDown":
|
||||||
|
const rows = element.getAttribute("data-rows");
|
||||||
|
const columns = element.getAttribute("data-columns");
|
||||||
|
if (rows && columns) {
|
||||||
|
const rowCount = parseInt(rows);
|
||||||
|
const columnCount = parseInt(rows);
|
||||||
|
row = 0;
|
||||||
|
while (row < rowCount) {
|
||||||
|
column = 0;
|
||||||
|
while (columns < columnCount) {
|
||||||
|
if (setTableCellCursor(element, row, column)) {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
column++;
|
||||||
|
}
|
||||||
|
row++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setTableRowCursor(element, row) {
|
||||||
|
const tableRowID = element.id + "-" + row;
|
||||||
|
var tableRow = document.getElementById(tableRowID);
|
||||||
|
if (!tableRow) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const focusStyle = getTableFocusedItemStyle(element);
|
||||||
|
const oldRowID = element.getAttribute("data-current");
|
||||||
|
if (oldRowID) {
|
||||||
|
const oldRow = document.getElementById(oldRowID);
|
||||||
|
if (oldRow && oldRow.classList) {
|
||||||
|
oldRow.classList.remove(focusStyle);
|
||||||
|
oldRow.classList.remove(getTableSelectedItemStyle(element));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tableRow.classList.add(focusStyle);
|
||||||
|
element.setAttribute("data-current", tableRowID);
|
||||||
|
|
||||||
|
sendMessage("currentRow{session=" + sessionID + ",id=" + element.id + ",row=" + row + "}");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function moveTableRowCursor(element, row, dr) {
|
||||||
|
const rows = element.getAttribute("data-rows");
|
||||||
|
if (!rows) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rowCount = parseInt(rows);
|
||||||
|
row += dr;
|
||||||
|
while (row >= 0 && row < rowCount) {
|
||||||
|
if (setTableRowCursor(element, row)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
row += dr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function tableViewRowKeyDownEvent(element, event) {
|
||||||
|
const key = getKey(event);
|
||||||
|
if (key) {
|
||||||
|
const currentId = element.getAttribute("data-current");
|
||||||
|
if (currentId) {
|
||||||
|
const elements = currentId.split("-");
|
||||||
|
if (elements.length >= 2) {
|
||||||
|
const row = parseInt(elements[1], 10);
|
||||||
|
switch (key) {
|
||||||
|
case " ":
|
||||||
|
case "Enter":
|
||||||
|
sendMessage("rowClick{session=" + sessionID + ",id=" + element.id + ",row=" + row + "}");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "ArrowDown":
|
||||||
|
moveTableRowCursor(element, row, 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "ArrowUp":
|
||||||
|
moveTableRowCursor(element, row, -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Home":
|
||||||
|
var newRow = 0;
|
||||||
|
while (newRow < row) {
|
||||||
|
if (setTableRowCursor(element, newRow)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
newRow++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "End":
|
||||||
|
var newRow = rowCount-1;
|
||||||
|
while (newRow > row) {
|
||||||
|
if (setTableRowCursor(element, newRow)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
newRow--;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "PageUp":
|
||||||
|
// TODO
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "PageDown":
|
||||||
|
// TODO
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case "ArrowLeft":
|
||||||
|
case "ArrowRight":
|
||||||
|
case "ArrowDown":
|
||||||
|
case "ArrowUp":
|
||||||
|
case "Home":
|
||||||
|
case "End":
|
||||||
|
case "PageUp":
|
||||||
|
case "PageDown":
|
||||||
|
const rows = element.getAttribute("data-rows");
|
||||||
|
if (rows) {
|
||||||
|
const rowCount = parseInt(rows);
|
||||||
|
row = 0;
|
||||||
|
while (row < rowCount) {
|
||||||
|
if (setTableRowCursor(element, row)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
row++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
function tableCellClickEvent(element, event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const elements = element.id.split("-");
|
||||||
|
if (elements.length < 3) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const tableID = elements[0];
|
||||||
|
const row = parseInt(elements[1], 10);
|
||||||
|
const column = parseInt(elements[2], 10);
|
||||||
|
const table = document.getElementById(tableID);
|
||||||
|
if (table) {
|
||||||
|
const selection = table.getAttribute("data-selection");
|
||||||
|
if (selection == "cell") {
|
||||||
|
const currentID = table.getAttribute("data-current");
|
||||||
|
if (!currentID || currentID != element.ID) {
|
||||||
|
setTableCellCursor(table, row, column)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sendMessage("cellClick{session=" + sessionID + ",id=" + tableID +
|
||||||
|
",row=" + row + ",column=" + column + "}");
|
||||||
|
}
|
||||||
|
|
||||||
|
function tableRowClickEvent(element, event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const elements = element.id.split("-");
|
||||||
|
if (elements.length < 2) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const tableID = elements[0];
|
||||||
|
const row = parseInt(elements[1], 10);
|
||||||
|
const table = document.getElementById(tableID);
|
||||||
|
if (table) {
|
||||||
|
const selection = table.getAttribute("data-selection");
|
||||||
|
if (selection == "cell") {
|
||||||
|
const currentID = table.getAttribute("data-current");
|
||||||
|
if (!currentID || currentID != element.ID) {
|
||||||
|
setTableRowCursor(table, row)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sendMessage("rowClick{session=" + sessionID + ",id=" + tableID + ",row=" + row + "}");
|
||||||
|
}
|
|
@ -148,11 +148,15 @@ func (customView *CustomViewData) Scroll() Frame {
|
||||||
return customView.superView.Scroll()
|
return customView.superView.Scroll()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (customView *CustomViewData) HasFocus() bool {
|
||||||
|
return customView.superView.HasFocus()
|
||||||
|
}
|
||||||
|
|
||||||
func (customView *CustomViewData) onResize(self View, x, y, width, height float64) {
|
func (customView *CustomViewData) onResize(self View, x, y, width, height float64) {
|
||||||
customView.superView.onResize(customView.superView, x, y, width, height)
|
customView.superView.onResize(customView.superView, x, y, width, height)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (customView *CustomViewData) onItemResize(self View, index int, x, y, width, height float64) {
|
func (customView *CustomViewData) onItemResize(self View, index string, x, y, width, height float64) {
|
||||||
customView.superView.onItemResize(customView.superView, index, x, y, width, height)
|
customView.superView.onItemResize(customView.superView, index, x, y, width, height)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,10 @@ func (picker *datePickerData) Init(session Session) {
|
||||||
picker.dateChangedListeners = []func(DatePicker, time.Time){}
|
picker.dateChangedListeners = []func(DatePicker, time.Time){}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (picker *datePickerData) Focusable() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (picker *datePickerData) normalizeTag(tag string) string {
|
func (picker *datePickerData) normalizeTag(tag string) string {
|
||||||
tag = strings.ToLower(tag)
|
tag = strings.ToLower(tag)
|
||||||
switch tag {
|
switch tag {
|
||||||
|
|
|
@ -213,24 +213,32 @@ theme {
|
||||||
text-color = @ruiPopupTextColor,
|
text-color = @ruiPopupTextColor,
|
||||||
radius = 4px,
|
radius = 4px,
|
||||||
shadow = _{spread-radius=4px, blur=16px, color=#80808080},
|
shadow = _{spread-radius=4px, blur=16px, color=#80808080},
|
||||||
}
|
},
|
||||||
ruiPopupTitle {
|
ruiPopupTitle {
|
||||||
background-color = @ruiPopupTitleColor,
|
background-color = @ruiPopupTitleColor,
|
||||||
text-color = @ruiPopupTitleTextColor,
|
text-color = @ruiPopupTitleTextColor,
|
||||||
min-height = 24px,
|
min-height = 24px,
|
||||||
}
|
},
|
||||||
ruiMessageText {
|
ruiMessageText {
|
||||||
padding-left = 64px,
|
padding-left = 64px,
|
||||||
padding-right = 64px,
|
padding-right = 64px,
|
||||||
padding-top = 32px,
|
padding-top = 32px,
|
||||||
padding-bottom = 32px,
|
padding-bottom = 32px,
|
||||||
}
|
},
|
||||||
ruiPopupMenuItem {
|
ruiPopupMenuItem {
|
||||||
padding-top = 4px,
|
padding-top = 4px,
|
||||||
padding-bottom = 4px,
|
padding-bottom = 4px,
|
||||||
padding-left = 8px,
|
padding-left = 8px,
|
||||||
padding-right = 8px,
|
padding-right = 8px,
|
||||||
}
|
},
|
||||||
|
ruiCurrentTableCell {
|
||||||
|
background-color=@ruiSelectedColor,
|
||||||
|
text-color=@ruiSelectedTextColor,
|
||||||
|
},
|
||||||
|
ruiCurrentTableCellFocused {
|
||||||
|
background-color=@ruiHighlightColor,
|
||||||
|
text-color=@ruiHighlightTextColor,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,8 @@ GridLayout {
|
||||||
DropDownList { row = 5, column = 1, id = tableFootStyle, current = 0, items = ["none", "tableFoot1", "rui.Params"]},
|
DropDownList { row = 5, column = 1, id = tableFootStyle, current = 0, items = ["none", "tableFoot1", "rui.Params"]},
|
||||||
Checkbox { row = 6, column = 0:1, id = tableRowStyle, content = "Row style" },
|
Checkbox { row = 6, column = 0:1, id = tableRowStyle, content = "Row style" },
|
||||||
Checkbox { row = 7, column = 0:1, id = tableColumnStyle, content = "Column style" },
|
Checkbox { row = 7, column = 0:1, id = tableColumnStyle, content = "Column style" },
|
||||||
|
TextView { row = 8, text = "Selection mode" },
|
||||||
|
DropDownList { row = 8, column = 1, id = tableSelectionMode, current = 0, items = ["none", "cell", "row"]},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -93,6 +95,10 @@ func createTableViewDemo(session rui.Session) rui.View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rui.Set(view, "tableSelectionMode", rui.DropDownEvent, func(list rui.DropDownList, number int) {
|
||||||
|
rui.Set(view, "demoTableView1", rui.SelectionMode, number)
|
||||||
|
})
|
||||||
|
|
||||||
rui.Set(view, "tableCellGap", rui.DropDownEvent, func(list rui.DropDownList, number int) {
|
rui.Set(view, "tableCellGap", rui.DropDownEvent, func(list rui.DropDownList, number int) {
|
||||||
if number == 0 {
|
if number == 0 {
|
||||||
rui.Set(view, "demoTableView1", rui.Gap, rui.Px(0))
|
rui.Set(view, "demoTableView1", rui.Gap, rui.Px(0))
|
||||||
|
|
|
@ -39,6 +39,10 @@ func (list *dropDownListData) Init(session Session) {
|
||||||
list.dropDownListener = []func(DropDownList, int){}
|
list.dropDownListener = []func(DropDownList, int){}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (list *dropDownListData) Focusable() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (list *dropDownListData) Remove(tag string) {
|
func (list *dropDownListData) Remove(tag string) {
|
||||||
list.remove(strings.ToLower(tag))
|
list.remove(strings.ToLower(tag))
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,10 @@ func (edit *editViewData) Init(session Session) {
|
||||||
edit.tag = "EditView"
|
edit.tag = "EditView"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (edit *editViewData) Focusable() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (edit *editViewData) normalizeTag(tag string) string {
|
func (edit *editViewData) normalizeTag(tag string) string {
|
||||||
tag = strings.ToLower(tag)
|
tag = strings.ToLower(tag)
|
||||||
switch tag {
|
switch tag {
|
||||||
|
|
|
@ -89,6 +89,10 @@ func (picker *filePickerData) Init(session Session) {
|
||||||
picker.fileSelectedListeners = []func(FilePicker, []FileInfo){}
|
picker.fileSelectedListeners = []func(FilePicker, []FileInfo){}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (picker *filePickerData) Focusable() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (picker *filePickerData) Files() []FileInfo {
|
func (picker *filePickerData) Files() []FileInfo {
|
||||||
return picker.files
|
return picker.files
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,13 +140,11 @@ func getFocusListeners(view View, subviewID string, tag string) []func(View) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func focusEventsHtml(view View, buffer *strings.Builder) {
|
func focusEventsHtml(view View, buffer *strings.Builder) {
|
||||||
for tag, js := range focusEvents {
|
if view.Focusable() {
|
||||||
if value := view.getRaw(tag); value != nil {
|
for _, js := range focusEvents {
|
||||||
if listeners, ok := value.([]func(View)); ok && len(listeners) > 0 {
|
|
||||||
buffer.WriteString(js.jsEvent + `="` + js.jsFunc + `(this, event)" `)
|
buffer.WriteString(js.jsEvent + `="` + js.jsFunc + `(this, event)" `)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFocusListeners returns a FocusListener list. If there are no listeners then the empty list is returned
|
// GetFocusListeners returns a FocusListener list. If there are no listeners then the empty list is returned
|
||||||
|
|
15
listView.go
15
listView.go
|
@ -1083,15 +1083,13 @@ func (listView *listViewData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||||
func (listView *listViewData) handleCommand(self View, command string, data DataObject) bool {
|
func (listView *listViewData) handleCommand(self View, command string, data DataObject) bool {
|
||||||
switch command {
|
switch command {
|
||||||
case "itemSelected":
|
case "itemSelected":
|
||||||
if text, ok := data.PropertyValue(`number`); ok {
|
if number, ok := dataIntProperty(data, `number`); ok {
|
||||||
if number, err := strconv.Atoi(text); err == nil {
|
|
||||||
listView.properties[Current] = number
|
listView.properties[Current] = number
|
||||||
for _, listener := range listView.selectedListeners {
|
for _, listener := range listView.selectedListeners {
|
||||||
listener(listView, number)
|
listener(listView, number)
|
||||||
}
|
}
|
||||||
listView.propertyChangedEvent(Current)
|
listView.propertyChangedEvent(Current)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
case "itemUnselected":
|
case "itemUnselected":
|
||||||
if _, ok := listView.properties[Current]; ok {
|
if _, ok := listView.properties[Current]; ok {
|
||||||
|
@ -1162,9 +1160,14 @@ func (listView *listViewData) onItemClick() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (listView *listViewData) onItemResize(self View, index int, x, y, width, height float64) {
|
func (listView *listViewData) onItemResize(self View, index string, x, y, width, height float64) {
|
||||||
if index >= 0 && index < len(listView.itemFrame) {
|
n, err := strconv.Atoi(index)
|
||||||
listView.itemFrame[index] = Frame{Left: x, Top: y, Width: width, Height: height}
|
if err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
} else if n >= 0 && n < len(listView.itemFrame) {
|
||||||
|
listView.itemFrame[n] = Frame{Left: x, Top: y, Width: width, Height: height}
|
||||||
|
} else {
|
||||||
|
ErrorLogF(`Invalid ListView item index: %d`, n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -168,6 +168,10 @@ func (player *mediaPlayerData) Init(session Session) {
|
||||||
player.tag = "MediaPlayer"
|
player.tag = "MediaPlayer"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (player *mediaPlayerData) Focusable() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (player *mediaPlayerData) Remove(tag string) {
|
func (player *mediaPlayerData) Remove(tag string) {
|
||||||
player.remove(strings.ToLower(tag))
|
player.remove(strings.ToLower(tag))
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,10 @@ func (picker *numberPickerData) Init(session Session) {
|
||||||
picker.numberChangedListeners = []func(NumberPicker, float64){}
|
picker.numberChangedListeners = []func(NumberPicker, float64){}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (picker *numberPickerData) Focusable() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (picker *numberPickerData) normalizeTag(tag string) string {
|
func (picker *numberPickerData) normalizeTag(tag string) string {
|
||||||
tag = strings.ToLower(tag)
|
tag = strings.ToLower(tag)
|
||||||
switch tag {
|
switch tag {
|
||||||
|
|
|
@ -18,7 +18,7 @@ func (view *viewData) onResize(self View, x, y, width, height float64) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *viewData) onItemResize(self View, index int, x, y, width, height float64) {
|
func (view *viewData) onItemResize(self View, index string, x, y, width, height float64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *viewData) setFrameListener(tag string, value interface{}) bool {
|
func (view *viewData) setFrameListener(tag string, value interface{}) bool {
|
||||||
|
|
|
@ -378,15 +378,11 @@ func (session *sessionData) handleResize(data DataObject) {
|
||||||
}
|
}
|
||||||
if viewID, ok := obj.PropertyValue("id"); ok {
|
if viewID, ok := obj.PropertyValue("id"); ok {
|
||||||
if n := strings.IndexRune(viewID, '-'); n > 0 {
|
if n := strings.IndexRune(viewID, '-'); n > 0 {
|
||||||
if index, err := strconv.Atoi(viewID[n+1:]); err == nil {
|
|
||||||
if view := session.viewByHTMLID(viewID[:n]); view != nil {
|
if view := session.viewByHTMLID(viewID[:n]); view != nil {
|
||||||
view.onItemResize(view, index, getFloat("x"), getFloat("y"), getFloat("width"), getFloat("height"))
|
view.onItemResize(view, viewID[n+1:], getFloat("x"), getFloat("y"), getFloat("width"), getFloat("height"))
|
||||||
} else {
|
} else {
|
||||||
ErrorLogF(`View with id == %s not found`, viewID[:n])
|
ErrorLogF(`View with id == %s not found`, viewID[:n])
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
ErrorLogF(`Invalid view id == %s not found`, viewID)
|
|
||||||
}
|
|
||||||
} else if view := session.viewByHTMLID(viewID); view != nil {
|
} else if view := session.viewByHTMLID(viewID); view != nil {
|
||||||
view.onResize(view, getFloat("x"), getFloat("y"), getFloat("width"), getFloat("height"))
|
view.onResize(view, getFloat("x"), getFloat("y"), getFloat("width"), getFloat("height"))
|
||||||
view.setScroll(getFloat("scroll-x"), getFloat("scroll-y"), getFloat("scroll-width"), getFloat("scroll-height"))
|
view.setScroll(getFloat("scroll-x"), getFloat("scroll-y"), getFloat("scroll-width"), getFloat("scroll-height"))
|
||||||
|
|
340
tableView.go
340
tableView.go
|
@ -214,11 +214,14 @@ type TableView interface {
|
||||||
View
|
View
|
||||||
ParanetView
|
ParanetView
|
||||||
ReloadTableData()
|
ReloadTableData()
|
||||||
|
CellFrame(row, column int) Frame
|
||||||
|
getCurrent() CellIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
type tableViewData struct {
|
type tableViewData struct {
|
||||||
viewData
|
viewData
|
||||||
cellViews []View
|
cellViews []View
|
||||||
|
cellFrame []Frame
|
||||||
cellSelectedListener, cellClickedListener []func(TableView, int, int)
|
cellSelectedListener, cellClickedListener []func(TableView, int, int)
|
||||||
rowSelectedListener, rowClickedListener []func(TableView, int)
|
rowSelectedListener, rowClickedListener []func(TableView, int)
|
||||||
current CellIndex
|
current CellIndex
|
||||||
|
@ -245,6 +248,7 @@ func (table *tableViewData) Init(session Session) {
|
||||||
table.viewData.Init(session)
|
table.viewData.Init(session)
|
||||||
table.tag = "TableView"
|
table.tag = "TableView"
|
||||||
table.cellViews = []View{}
|
table.cellViews = []View{}
|
||||||
|
table.cellFrame = []Frame{}
|
||||||
table.cellSelectedListener = []func(TableView, int, int){}
|
table.cellSelectedListener = []func(TableView, int, int){}
|
||||||
table.cellClickedListener = []func(TableView, int, int){}
|
table.cellClickedListener = []func(TableView, int, int){}
|
||||||
table.rowSelectedListener = []func(TableView, int){}
|
table.rowSelectedListener = []func(TableView, int){}
|
||||||
|
@ -270,6 +274,10 @@ func (table *tableViewData) normalizeTag(tag string) string {
|
||||||
return tag
|
return tag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (table *tableViewData) Focusable() bool {
|
||||||
|
return GetSelectionMode(table, "") != NoneSelection
|
||||||
|
}
|
||||||
|
|
||||||
func (table *tableViewData) Get(tag string) interface{} {
|
func (table *tableViewData) Get(tag string) interface{} {
|
||||||
return table.get(table.normalizeTag(tag))
|
return table.get(table.normalizeTag(tag))
|
||||||
}
|
}
|
||||||
|
@ -312,6 +320,10 @@ func (table *tableViewData) remove(tag string) {
|
||||||
table.current.Column = -1
|
table.current.Column = -1
|
||||||
table.propertyChanged(tag)
|
table.propertyChanged(tag)
|
||||||
|
|
||||||
|
case SelectionMode:
|
||||||
|
table.viewData.remove(tag)
|
||||||
|
table.propertyChanged(tag)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
table.viewData.remove(tag)
|
table.viewData.remove(tag)
|
||||||
}
|
}
|
||||||
|
@ -486,14 +498,51 @@ func (table *tableViewData) set(tag string, value interface{}) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
case Current:
|
case Current:
|
||||||
switch GetSelectionMode(table, "") {
|
switch value := value.(type) {
|
||||||
case NoneSelection:
|
case int:
|
||||||
|
table.current.Row = value
|
||||||
|
table.current.Column = -1
|
||||||
|
|
||||||
case CellSelection:
|
case CellIndex:
|
||||||
// TODO
|
table.current = value
|
||||||
|
|
||||||
case RowSelection:
|
case DataObject:
|
||||||
// TODO
|
if row, ok := dataIntProperty(value, "row"); ok {
|
||||||
|
table.current.Row = row
|
||||||
|
}
|
||||||
|
if column, ok := dataIntProperty(value, "column"); ok {
|
||||||
|
table.current.Column = column
|
||||||
|
}
|
||||||
|
|
||||||
|
case string:
|
||||||
|
if strings.Contains(value, ",") {
|
||||||
|
if values := strings.Split(value, ","); len(values) == 2 {
|
||||||
|
var n = []int{0, 0}
|
||||||
|
for i := 0; i < 2; i++ {
|
||||||
|
var err error
|
||||||
|
if n[i], err = strconv.Atoi(values[i]); err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
table.current.Row = n[0]
|
||||||
|
table.current.Column = n[1]
|
||||||
|
} else {
|
||||||
|
notCompatibleType(tag, value)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
n, err := strconv.Atoi(value)
|
||||||
|
if err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
table.current.Row = n
|
||||||
|
table.current.Column = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
notCompatibleType(tag, value)
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -524,11 +573,75 @@ func (table *tableViewData) propertyChanged(tag string) {
|
||||||
updateCSSProperty(htmlID, "border-spacing", gap.cssString("0"), session)
|
updateCSSProperty(htmlID, "border-spacing", gap.cssString("0"), session)
|
||||||
updateCSSProperty(htmlID, "border-collapse", "separate", session)
|
updateCSSProperty(htmlID, "border-collapse", "separate", session)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SelectionMode:
|
||||||
|
htmlID := table.htmlID()
|
||||||
|
session := table.Session()
|
||||||
|
|
||||||
|
switch GetSelectionMode(table, "") {
|
||||||
|
case CellSelection:
|
||||||
|
updateProperty(htmlID, "tabindex", "0", session)
|
||||||
|
updateProperty(htmlID, "onfocus", "tableViewFocusEvent(this, event)", session)
|
||||||
|
updateProperty(htmlID, "onblur", "tableViewBlurEvent(this, event)", session)
|
||||||
|
updateProperty(htmlID, "data-selection", "cell", session)
|
||||||
|
updateProperty(htmlID, "data-focusitemstyle", table.currentStyle(), session)
|
||||||
|
updateProperty(htmlID, "data-bluritemstyle", table.currentInactiveStyle(), session)
|
||||||
|
|
||||||
|
if table.current.Row >= 0 && table.current.Column >= 0 {
|
||||||
|
updateProperty(htmlID, "data-current", table.cellID(table.current.Row, table.current.Column), session)
|
||||||
|
} else {
|
||||||
|
removeProperty(htmlID, "data-current", session)
|
||||||
|
}
|
||||||
|
updateProperty(htmlID, "onkeydown", "tableViewCellKeyDownEvent(this, event)", session)
|
||||||
|
|
||||||
|
case RowSelection:
|
||||||
|
updateProperty(htmlID, "tabindex", "0", session)
|
||||||
|
updateProperty(htmlID, "onfocus", "tableViewFocusEvent(this, event)", session)
|
||||||
|
updateProperty(htmlID, "onblur", "tableViewBlurEvent(this, event)", session)
|
||||||
|
updateProperty(htmlID, "data-selection", "cell", session)
|
||||||
|
updateProperty(htmlID, "data-focusitemstyle", table.currentStyle(), session)
|
||||||
|
updateProperty(htmlID, "data-bluritemstyle", table.currentInactiveStyle(), session)
|
||||||
|
|
||||||
|
if table.current.Row >= 0 {
|
||||||
|
updateProperty(htmlID, "data-current", table.rowID(table.current.Row), session)
|
||||||
|
} else {
|
||||||
|
removeProperty(htmlID, "data-current", session)
|
||||||
|
}
|
||||||
|
updateProperty(htmlID, "onkeydown", "tableViewRowKeyDownEvent(this, event)", session)
|
||||||
|
|
||||||
|
default: // NoneSelection
|
||||||
|
for _, prop := range []string{"tabindex", "data-current", "onfocus", "onblur", "onkeydown", "data-selection"} {
|
||||||
|
removeProperty(htmlID, prop, session)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateInnerHTML(htmlID, session)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
table.propertyChangedEvent(tag)
|
table.propertyChangedEvent(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (table *tableViewData) currentStyle() string {
|
||||||
|
if value := table.getRaw(CurrentStyle); value != nil {
|
||||||
|
if style, ok := value.(string); ok {
|
||||||
|
if style, ok = table.session.resolveConstants(style); ok {
|
||||||
|
return style
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "ruiCurrentTableCellFocused"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (table *tableViewData) currentInactiveStyle() string {
|
||||||
|
if value := table.getRaw(CurrentInactiveStyle); value != nil {
|
||||||
|
if style, ok := value.(string); ok {
|
||||||
|
if style, ok = table.session.resolveConstants(style); ok {
|
||||||
|
return style
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "ruiCurrentTableCell"
|
||||||
|
}
|
||||||
|
|
||||||
func (table *tableViewData) valueToCellListeners(value interface{}) []func(TableView, int, int) {
|
func (table *tableViewData) valueToCellListeners(value interface{}) []func(TableView, int, int) {
|
||||||
if value == nil {
|
if value == nil {
|
||||||
return []func(TableView, int, int){}
|
return []func(TableView, int, int){}
|
||||||
|
@ -643,16 +756,69 @@ func (table *tableViewData) htmlTag() string {
|
||||||
return "table"
|
return "table"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (table *tableViewData) htmlSubviews(self View, buffer *strings.Builder) {
|
func (table *tableViewData) rowID(index int) string {
|
||||||
table.cellViews = []View{}
|
return fmt.Sprintf("%s-%d", table.htmlID(), index)
|
||||||
|
}
|
||||||
|
|
||||||
content := table.getRaw(Content)
|
func (table *tableViewData) cellID(row, column int) string {
|
||||||
if content == nil {
|
return fmt.Sprintf("%s-%d-%d", table.htmlID(), row, column)
|
||||||
return
|
}
|
||||||
|
|
||||||
|
func (table *tableViewData) htmlProperties(self View, buffer *strings.Builder) {
|
||||||
|
|
||||||
|
if content := table.content(); content != nil {
|
||||||
|
buffer.WriteString(` data-rows="`)
|
||||||
|
buffer.WriteString(strconv.Itoa(content.RowCount()))
|
||||||
|
buffer.WriteString(`" data-columns="`)
|
||||||
|
buffer.WriteString(strconv.Itoa(content.ColumnCount()))
|
||||||
|
buffer.WriteRune('"')
|
||||||
}
|
}
|
||||||
|
|
||||||
adapter, ok := content.(TableAdapter)
|
if selectionMode := GetSelectionMode(table, ""); selectionMode != NoneSelection {
|
||||||
if !ok {
|
buffer.WriteString(` onfocus="tableViewFocusEvent(this, event)" onblur="tableViewBlurEvent(this, event)" data-focusitemstyle="`)
|
||||||
|
buffer.WriteString(table.currentStyle())
|
||||||
|
buffer.WriteString(`" data-bluritemstyle="`)
|
||||||
|
buffer.WriteString(table.currentInactiveStyle())
|
||||||
|
buffer.WriteRune('"')
|
||||||
|
|
||||||
|
switch selectionMode {
|
||||||
|
case RowSelection:
|
||||||
|
buffer.WriteString(` data-selection="row" onkeydown="tableViewRowKeyDownEvent(this, event)"`)
|
||||||
|
if table.current.Row >= 0 {
|
||||||
|
buffer.WriteString(` data-current="`)
|
||||||
|
buffer.WriteString(table.rowID(table.current.Row))
|
||||||
|
buffer.WriteRune('"')
|
||||||
|
}
|
||||||
|
|
||||||
|
case CellSelection:
|
||||||
|
buffer.WriteString(` data-selection="cell" onkeydown="tableViewCellKeyDownEvent(this, event)"`)
|
||||||
|
if table.current.Row >= 0 && table.current.Column >= 0 {
|
||||||
|
buffer.WriteString(` data-current="`)
|
||||||
|
buffer.WriteString(table.cellID(table.current.Row, table.current.Column))
|
||||||
|
buffer.WriteRune('"')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
table.viewData.htmlProperties(self, buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (table *tableViewData) content() TableAdapter {
|
||||||
|
if content := table.getRaw(Content); content != nil {
|
||||||
|
if adapter, ok := content.(TableAdapter); ok {
|
||||||
|
return adapter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (table *tableViewData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||||
|
table.cellViews = []View{}
|
||||||
|
table.cellFrame = []Frame{}
|
||||||
|
|
||||||
|
adapter := table.content()
|
||||||
|
if adapter == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -662,10 +828,12 @@ func (table *tableViewData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table.cellFrame = make([]Frame, rowCount*columnCount)
|
||||||
|
|
||||||
rowStyle := table.getRowStyle()
|
rowStyle := table.getRowStyle()
|
||||||
|
|
||||||
var cellStyle1 TableCellStyle = nil
|
var cellStyle1 TableCellStyle = nil
|
||||||
if style, ok := content.(TableCellStyle); ok {
|
if style, ok := adapter.(TableCellStyle); ok {
|
||||||
cellStyle1 = style
|
cellStyle1 = style
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -691,6 +859,7 @@ func (table *tableViewData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||||
view.Init(session)
|
view.Init(session)
|
||||||
|
|
||||||
ignorCells := []struct{ row, column int }{}
|
ignorCells := []struct{ row, column int }{}
|
||||||
|
selectionMode := GetSelectionMode(table, "")
|
||||||
|
|
||||||
tableCSS := func(startRow, endRow int, cellTag string, cellBorder BorderProperty, cellPadding BoundsProperty) {
|
tableCSS := func(startRow, endRow int, cellTag string, cellBorder BorderProperty, cellPadding BoundsProperty) {
|
||||||
for row := startRow; row < endRow; row++ {
|
for row := startRow; row < endRow; row++ {
|
||||||
|
@ -706,13 +875,30 @@ func (table *tableViewData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cssBuilder.buffer.Len() > 0 {
|
buffer.WriteString(`<tr id="`)
|
||||||
buffer.WriteString(`<tr style="`)
|
buffer.WriteString(table.rowID(row))
|
||||||
buffer.WriteString(cssBuilder.buffer.String())
|
buffer.WriteRune('"')
|
||||||
buffer.WriteString(`">`)
|
|
||||||
|
if selectionMode == RowSelection {
|
||||||
|
if row == table.current.Row {
|
||||||
|
buffer.WriteString(` class="`)
|
||||||
|
if table.HasFocus() {
|
||||||
|
buffer.WriteString(table.currentStyle())
|
||||||
} else {
|
} else {
|
||||||
buffer.WriteString("<tr>")
|
buffer.WriteString(table.currentInactiveStyle())
|
||||||
}
|
}
|
||||||
|
buffer.WriteRune('"')
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.WriteString(` onclick="tableRowClickEvent(this, event)"`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if cssBuilder.buffer.Len() > 0 {
|
||||||
|
buffer.WriteString(` style="`)
|
||||||
|
buffer.WriteString(cssBuilder.buffer.String())
|
||||||
|
buffer.WriteString(`"`)
|
||||||
|
}
|
||||||
|
buffer.WriteString(">")
|
||||||
|
|
||||||
for column := 0; column < columnCount; column++ {
|
for column := 0; column < columnCount; column++ {
|
||||||
ignore := false
|
ignore := false
|
||||||
|
@ -748,7 +934,7 @@ func (table *tableViewData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||||
return value
|
return value
|
||||||
|
|
||||||
case string:
|
case string:
|
||||||
if value, ok = session.resolveConstants(value); ok {
|
if value, ok := session.resolveConstants(value); ok {
|
||||||
if n, err := strconv.Atoi(value); err == nil {
|
if n, err := strconv.Atoi(value); err == nil {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
@ -780,6 +966,23 @@ func (table *tableViewData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||||
|
|
||||||
buffer.WriteRune('<')
|
buffer.WriteRune('<')
|
||||||
buffer.WriteString(cellTag)
|
buffer.WriteString(cellTag)
|
||||||
|
buffer.WriteString(` id="`)
|
||||||
|
buffer.WriteString(table.cellID(row, column))
|
||||||
|
buffer.WriteString(`" class="ruiView`)
|
||||||
|
|
||||||
|
if selectionMode == CellSelection && row == table.current.Row && column == table.current.Column {
|
||||||
|
buffer.WriteRune(' ')
|
||||||
|
if table.HasFocus() {
|
||||||
|
buffer.WriteString(table.currentStyle())
|
||||||
|
} else {
|
||||||
|
buffer.WriteString(table.currentInactiveStyle())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer.WriteRune('"')
|
||||||
|
|
||||||
|
if selectionMode == CellSelection {
|
||||||
|
buffer.WriteString(` onclick="tableCellClickEvent(this, event)"`)
|
||||||
|
}
|
||||||
|
|
||||||
if columnSpan > 1 {
|
if columnSpan > 1 {
|
||||||
buffer.WriteString(` colspan="`)
|
buffer.WriteString(` colspan="`)
|
||||||
|
@ -1087,6 +1290,10 @@ func (table *tableViewData) getCellBorder() BorderProperty {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (table *tableViewData) getCurrent() CellIndex {
|
||||||
|
return table.current
|
||||||
|
}
|
||||||
|
|
||||||
func (table *tableViewData) cssStyle(self View, builder cssBuilder) {
|
func (table *tableViewData) cssStyle(self View, builder cssBuilder) {
|
||||||
table.viewData.cssViewStyle(builder, table.Session())
|
table.viewData.cssViewStyle(builder, table.Session())
|
||||||
|
|
||||||
|
@ -1101,30 +1308,93 @@ func (table *tableViewData) cssStyle(self View, builder cssBuilder) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (table *tableViewData) ReloadTableData() {
|
func (table *tableViewData) ReloadTableData() {
|
||||||
|
if content := table.content(); content != nil {
|
||||||
|
updateProperty(table.htmlID(), "data-rows", strconv.Itoa(content.RowCount()), table.Session())
|
||||||
|
updateProperty(table.htmlID(), "data-columns", strconv.Itoa(content.ColumnCount()), table.Session())
|
||||||
|
}
|
||||||
updateInnerHTML(table.htmlID(), table.Session())
|
updateInnerHTML(table.htmlID(), table.Session())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cell *tableCellView) Set(tag string, value interface{}) bool {
|
func (table *tableViewData) onItemResize(self View, index string, x, y, width, height float64) {
|
||||||
return cell.set(strings.ToLower(tag), value)
|
if n := strings.IndexRune(index, '-'); n > 0 {
|
||||||
|
if row, err := strconv.Atoi(index[:n]); err == nil {
|
||||||
|
if column, err := strconv.Atoi(index[n+1:]); err == nil {
|
||||||
|
if content := table.content(); content != nil {
|
||||||
|
i := row*content.ColumnCount() + column
|
||||||
|
if i < len(table.cellFrame) {
|
||||||
|
table.cellFrame[i].Left = x
|
||||||
|
table.cellFrame[i].Top = y
|
||||||
|
table.cellFrame[i].Width = width
|
||||||
|
table.cellFrame[i].Height = height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ErrorLogF(`Invalid cell index: %s`, index)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cell *tableCellView) set(tag string, value interface{}) bool {
|
func (table *tableViewData) CellFrame(row, column int) Frame {
|
||||||
switch tag {
|
if content := table.content(); content != nil {
|
||||||
case VerticalAlign:
|
i := row*content.ColumnCount() + column
|
||||||
tag = TableVerticalAlign
|
if i < len(table.cellFrame) {
|
||||||
|
return table.cellFrame[i]
|
||||||
}
|
}
|
||||||
return cell.viewData.set(tag, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cell *tableCellView) cssStyle(self View, builder cssBuilder) {
|
|
||||||
session := cell.Session()
|
|
||||||
cell.viewData.cssViewStyle(builder, session)
|
|
||||||
|
|
||||||
if value, ok := enumProperty(cell, TableVerticalAlign, session, 0); ok {
|
|
||||||
builder.add("vertical-align", enumProperties[TableVerticalAlign].values[value])
|
|
||||||
}
|
}
|
||||||
|
return Frame{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (table *tableViewData) Views() []View {
|
func (table *tableViewData) Views() []View {
|
||||||
return table.cellViews
|
return table.cellViews
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (table *tableViewData) handleCommand(self View, command string, data DataObject) bool {
|
||||||
|
switch command {
|
||||||
|
case "currentRow":
|
||||||
|
if row, ok := dataIntProperty(data, "row"); ok && row != table.current.Row {
|
||||||
|
table.current.Row = row
|
||||||
|
for _, listener := range table.rowSelectedListener {
|
||||||
|
listener(table, row)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case "currentCell":
|
||||||
|
if row, ok := dataIntProperty(data, "row"); ok {
|
||||||
|
if column, ok := dataIntProperty(data, "column"); ok {
|
||||||
|
if row != table.current.Row || column != table.current.Column {
|
||||||
|
table.current.Row = row
|
||||||
|
table.current.Column = column
|
||||||
|
for _, listener := range table.cellSelectedListener {
|
||||||
|
listener(table, row, column)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case "rowClick":
|
||||||
|
if row, ok := dataIntProperty(data, "row"); ok {
|
||||||
|
for _, listener := range table.rowClickedListener {
|
||||||
|
listener(table, row)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case "cellClick":
|
||||||
|
if row, ok := dataIntProperty(data, "row"); ok {
|
||||||
|
if column, ok := dataIntProperty(data, "column"); ok {
|
||||||
|
for _, listener := range table.cellClickedListener {
|
||||||
|
listener(table, row, column)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return table.viewData.handleCommand(self, command, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,28 @@
|
||||||
package rui
|
package rui
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
func (cell *tableCellView) Set(tag string, value interface{}) bool {
|
||||||
|
return cell.set(strings.ToLower(tag), value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cell *tableCellView) set(tag string, value interface{}) bool {
|
||||||
|
switch tag {
|
||||||
|
case VerticalAlign:
|
||||||
|
tag = TableVerticalAlign
|
||||||
|
}
|
||||||
|
return cell.viewData.set(tag, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cell *tableCellView) cssStyle(self View, builder cssBuilder) {
|
||||||
|
session := cell.Session()
|
||||||
|
cell.viewData.cssViewStyle(builder, session)
|
||||||
|
|
||||||
|
if value, ok := enumProperty(cell, TableVerticalAlign, session, 0); ok {
|
||||||
|
builder.add("vertical-align", enumProperties[TableVerticalAlign].values[value])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetSelectionMode returns the mode of the TableView elements selection.
|
// GetSelectionMode returns the mode of the TableView elements selection.
|
||||||
// Valid values are NoneSelection (0), CellSelection (1), and RowSelection (2).
|
// Valid values are NoneSelection (0), CellSelection (1), and RowSelection (2).
|
||||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||||
|
@ -15,6 +38,42 @@ func GetSelectionMode(view View, subviewID string) int {
|
||||||
return NoneSelection
|
return NoneSelection
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetSelectionMode returns the index of the TableView selected row.
|
||||||
|
// If there is no selected row, then a value less than 0 are returned.
|
||||||
|
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||||
|
func GetCurrentTableRow(view View, subviewID string) int {
|
||||||
|
if subviewID != "" {
|
||||||
|
view = ViewByID(view, subviewID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if view != nil {
|
||||||
|
if selectionMode := GetSelectionMode(view, ""); selectionMode != NoneSelection {
|
||||||
|
if tableView, ok := view.(TableView); ok {
|
||||||
|
return tableView.getCurrent().Row
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCurrentTableCell returns the row and column index of the TableView selected cell.
|
||||||
|
// If there is no selected cell, then a value of the row and column index less than 0 is returned.
|
||||||
|
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||||
|
func GetCurrentTableCell(view View, subviewID string) CellIndex {
|
||||||
|
if subviewID != "" {
|
||||||
|
view = ViewByID(view, subviewID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if view != nil {
|
||||||
|
if selectionMode := GetSelectionMode(view, ""); selectionMode != NoneSelection {
|
||||||
|
if tableView, ok := view.(TableView); ok {
|
||||||
|
return tableView.getCurrent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CellIndex{Row: -1, Column: -1}
|
||||||
|
}
|
||||||
|
|
||||||
// GetTableCellClickedListeners returns listeners of event which occurs when the user clicks on a table cell.
|
// GetTableCellClickedListeners returns listeners of event which occurs when the user clicks on a table cell.
|
||||||
// If there are no listeners then the empty list is returned.
|
// If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||||
|
|
|
@ -44,6 +44,10 @@ func (picker *timePickerData) Init(session Session) {
|
||||||
picker.timeChangedListeners = []func(TimePicker, time.Time){}
|
picker.timeChangedListeners = []func(TimePicker, time.Time){}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (picker *timePickerData) Focusable() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (picker *timePickerData) normalizeTag(tag string) string {
|
func (picker *timePickerData) normalizeTag(tag string) string {
|
||||||
tag = strings.ToLower(tag)
|
tag = strings.ToLower(tag)
|
||||||
switch tag {
|
switch tag {
|
||||||
|
|
18
view.go
18
view.go
|
@ -58,6 +58,8 @@ type View interface {
|
||||||
SetAnimated(tag string, value interface{}, animation Animation) bool
|
SetAnimated(tag string, value interface{}, animation Animation) bool
|
||||||
// SetChangeListener set the function to track the change of the View property
|
// SetChangeListener set the function to track the change of the View property
|
||||||
SetChangeListener(tag string, listener func(View, string))
|
SetChangeListener(tag string, listener func(View, string))
|
||||||
|
// HasFocus returns 'true' if the view has focus
|
||||||
|
HasFocus() bool
|
||||||
|
|
||||||
handleCommand(self View, command string, data DataObject) bool
|
handleCommand(self View, command string, data DataObject) bool
|
||||||
htmlClass(disabled bool) string
|
htmlClass(disabled bool) string
|
||||||
|
@ -73,7 +75,7 @@ type View interface {
|
||||||
getTransitions() Params
|
getTransitions() Params
|
||||||
|
|
||||||
onResize(self View, x, y, width, height float64)
|
onResize(self View, x, y, width, height float64)
|
||||||
onItemResize(self View, index int, x, y, width, height float64)
|
onItemResize(self View, index string, x, y, width, height float64)
|
||||||
setNoResizeEvent()
|
setNoResizeEvent()
|
||||||
isNoResizeEvent() bool
|
isNoResizeEvent() bool
|
||||||
setScroll(x, y, width, height float64)
|
setScroll(x, y, width, height float64)
|
||||||
|
@ -95,6 +97,7 @@ type viewData struct {
|
||||||
scroll Frame
|
scroll Frame
|
||||||
noResizeEvent bool
|
noResizeEvent bool
|
||||||
created bool
|
created bool
|
||||||
|
hasFocus bool
|
||||||
//animation map[string]AnimationEndListener
|
//animation map[string]AnimationEndListener
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -737,7 +740,14 @@ func (view *viewData) handleCommand(self View, command string, data DataObject)
|
||||||
case TouchStart, TouchEnd, TouchMove, TouchCancel:
|
case TouchStart, TouchEnd, TouchMove, TouchCancel:
|
||||||
handleTouchEvents(self, command, data)
|
handleTouchEvents(self, command, data)
|
||||||
|
|
||||||
case FocusEvent, LostFocusEvent:
|
case FocusEvent:
|
||||||
|
view.hasFocus = true
|
||||||
|
for _, listener := range getFocusListeners(view, "", command) {
|
||||||
|
listener(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
case LostFocusEvent:
|
||||||
|
view.hasFocus = false
|
||||||
for _, listener := range getFocusListeners(view, "", command) {
|
for _, listener := range getFocusListeners(view, "", command) {
|
||||||
listener(self)
|
listener(self)
|
||||||
}
|
}
|
||||||
|
@ -838,3 +848,7 @@ func (view *viewData) SetChangeListener(tag string, listener func(View, string))
|
||||||
view.changeListener[tag] = listener
|
view.changeListener[tag] = listener
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (view *viewData) HasFocus() bool {
|
||||||
|
return view.hasFocus
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue