rustdesk/src/ui/grid.tis

235 lines
8.0 KiB
Plaintext

class Grid: Behavior {
const TABLE_HEADER_CLICK = 0x81;
const TABLE_ROW_CLICK = 0x82;
const TABLE_ROW_DBL_CLICK = 0x83;
function onHeaderClick(headerCell)
{
this.postEvent(TABLE_HEADER_CLICK, headerCell.index, headerCell);
return true;
}
function onRowClick(row , reason)
{
this.postEvent(TABLE_ROW_CLICK, row.index, row);
return true;
}
function onRowDoubleClick(row)
{
this.postEvent(TABLE_ROW_DBL_CLICK, row.index, row);
return true;
}
function getCurrentRow()
{
return this.$(tbody>tr:current);
}
function getCurrentColumn()
{
return this.$(thead>:current); // return current cell in header row
}
function setCurrentRow(row, reason = #by_code, doubleClick = false)
{
if (!row) return;
// get previously selected row:
var prev = this.getCurrentRow();
if (prev)
{
if (prev === row && !doubleClick) return; // already here, nothing to do.
prev.state.current = false; // drop state flag
}
row.state.current = true;
row.scrollToView();
if (doubleClick)
this.onRowDoubleClick(row,reason);
else
this.onRowClick(row,reason);
}
function setCurrentColumn(col)
{
// get previously selected column:
var prev = this.getCurrentColumn();
if (prev)
{
if (prev === col) return; // already here, nothing to do.
prev.state.current = false; // drop state flag
}
col.state.current = true; // set state flag
col.scrollToView();
this.onHeaderClick(col);
}
function sortRows(sortClicked)
{
var col = this.sortBy;
if (!col) return;
var byColumn = col.index;
var nowDesc = (col.attributes["sort"] || "desc") == "desc";
if (sortClicked) (this.$(thead [sort]) || col).attributes["sort"] = undefined; // drop any other sort order.
var getValue = function(x) {
var value = x.attributes["value"];
if (value == undefined) return x.text.toLowerCase();
return value.toFloat();
}
var sort = function(r1, r2, asc) {
if (r1[1].text == "..") {
return -1;
}
if (r2[1].text == "..") {
return 1;
}
if (!asc)
return getValue(r1[byColumn]) < getValue(r2[byColumn]) ? -1 : 1;
else
return getValue(r1[byColumn]) > getValue(r2[byColumn]) ? -1 : 1;
}
if (nowDesc)
{
if (sortClicked) col.attributes["sort"] = "asc";
this.body.sort(:r1, r2: sort(r1, r2, sortClicked ? true : false));
} else {
if (sortClicked) col.attributes["sort"] = "desc";
this.body.sort(:r1, r2: sort(r1, r2, sortClicked ? false : true));
}
}
function attached()
{
assert this.tag == "table" : "wrong element type for grid, table expected";
this.body = this.$(:root>tbody);
assert this.body : "Grid require <tbody> element";
}
function onMouse(evt)
{
if ((evt.type != Event.MOUSE_DOWN) && (evt.type != Event.MOUSE_DCLICK))
return false;
if (!evt.mainButton)
return false;
// auxiliary function, returns row this target element belongs to
function targetRow(target) { return target.$p(tbody>tr); }
// auxiliary function, returns row this target element belongs to
function targetHeaderCell(target) { return target.$p(thead>tr>th); }
if (var row = targetRow(evt.target)) // click on the row
this.setCurrentRow(row, #by_mouse, evt.type == Event.MOUSE_DCLICK);
else if (var headerCell = targetHeaderCell(evt.target))
{
this.setCurrentColumn(headerCell); // click on the header cell
if (evt.type != Event.MOUSE_DCLICK && headerCell.$is(.sortable)) {
this.sortBy = headerCell;
this.sortRows(true);
}
}
//return true; // as it is always ours then stop event bubbling
}
function onFocus(evt)
{
return (evt.type == Event.GOT_FOCUS || evt.type == Event.LOST_FOCUS);
}
function onKey(evt)
{
if (evt.type != Event.KEY_DOWN)
return false;
switch(evt.keyCode)
{
case Event.VK_DOWN:
{
var crow = this.getCurrentRow();
var idx = crow? crow.index + 1 : 0;
if (idx < this.body.length) this.setCurrentRow(this.body[idx],#by_key);
}
return true;
case Event.VK_UP:
{
var crow = this.getCurrentRow();
var idx = crow? crow.index - 1 : this.length - 1;
if (idx >= 0) this.setCurrentRow(this.body[idx],#by_key);
}
return true;
case Event.VK_PRIOR:
{
var y = this.body.scroll(#top) - this.body.scroll(#height);
var r;
for(var i = this.body.length - 1; i >= 0; --i)
{
var pr = r; r = this.body[i];
if (r.box(#top, #inner, #content) < y)
{
// this row is further than scroll pos - height of scroll area
this.setCurrentRow(pr? pr: r,#by_key); // to last fully visible
return true;
}
}
this.setCurrentRow(r,#by_key); // just in case
}
return true;
case Event.VK_NEXT:
{
var y = this.body.scroll(#top) + 2 * this.body.scroll(#height);
var lastScrollable = this.body.length - 1;
var r;
for(var i = 0; i <= lastScrollable; ++i)
{
var pr = r; r = this.body[i];
if (r.box(#bottom, #inner, #content) > y)
{
// this row is further than scroll pos - height of scroll area
this.setCurrentRow(pr? pr: r,#by_key); // to last fully visible
return true;
}
}
this.setCurrentRow(r,#by_key); // just in case
}
return true;
case Event.VK_HOME:
{
if (this.body.length)
this.setCurrentRow(this.body.first,#by_key);
}
return true;
case Event.VK_END:
{
if (this.body.length)
this.setCurrentRow(this.body.last,#by_key);
}
return true;
}
var char = handler.get_char(keymap[evt.keyCode] || "", evt.keyCode);
if (char) {
var crow = this.getCurrentRow();
var idx = crow? crow.index + 1 : 0;
while (idx < this.body.length) {
var el = this.body[idx];
var text = el[1].text;
if (text && text[0].toLowerCase() == char) {
this.setCurrentRow(el, #by_key);
return true;
}
idx += 1;
}
}
if (evt.keyCode == Event.VK_ENTER ||
(view.mediaVar("platform") == "OSX" && evt.keyCode == 0x4C)) {
this.onRowDoubleClick(this.getCurrentRow());
}
return false;
}
}