feat(GridView): allows navigation by arrow keys
All checks were successful
AntOS front-end / Build-AntOS-Frontend (push) Successful in 35s

This commit is contained in:
DanyLE 2024-07-28 19:05:34 +02:00
parent 4bbc6c770a
commit 59fb302e18
9 changed files with 202 additions and 12 deletions

View File

@ -8,7 +8,7 @@ TSC=./node_modules/typescript/bin/tsc
UGLIFYJS=./node_modules/terser/bin/terser UGLIFYJS=./node_modules/terser/bin/terser
UGLIFYCSS=./node_modules/uglifycss/uglifycss UGLIFYCSS=./node_modules/uglifycss/uglifycss
VERSION?=2.0.2-b VERSION?=2.0.3-b
BUILDID?=master BUILDID?=master
GSED=sed GSED=sed

53
d.ts/antos.d.ts vendored
View File

@ -4780,14 +4780,14 @@ declare namespace OS {
* @returns {void} * @returns {void}
* @memberof ListViewTag * @memberof ListViewTag
*/ */
nav_next(): void; nav_prev(): void;
/** /**
* Navigate the list down * Navigate the list down
* *
* @returns {void} * @returns {void}
* @memberof ListViewTag * @memberof ListViewTag
*/ */
nav_prev(): void; nav_next(): void;
/** /**
* Commit the navigated item * Commit the navigated item
* *
@ -6300,6 +6300,13 @@ declare namespace OS {
* @memberof GridViewTag * @memberof GridViewTag
*/ */
private _dnd; private _dnd;
/**
* Grid navigation index
*
* @private
* @type {number}
*/
private _nav_index;
/** /**
* placeholder of list drag and drop event handle * placeholder of list drag and drop event handle
* *
@ -6480,6 +6487,12 @@ declare namespace OS {
* @memberof GridViewTag * @memberof GridViewTag
*/ */
delete(row: GridRowTag): void; delete(row: GridRowTag): void;
/**
* Scroll the grid view to item
*
* @memberof GridViewTag
*/
scroll_to_item(item: GridRowTag): void;
/** /**
* Scroll the grid view to bottom * Scroll the grid view to bottom
* *
@ -6559,6 +6572,42 @@ declare namespace OS {
* @memberof GridViewTag * @memberof GridViewTag
*/ */
private calibrate_header; private calibrate_header;
/**
* Reset the navigation indicator
*
* @private
*/
private nav_reset;
/**
* Navigate the list up
*
* @public
* @returns {void}
* @memberof ListViewTag
*/
nav_prev(): void;
/**
* Navigate the list down
*
* @returns {void}
* @memberof ListViewTag
*/
nav_next(): void;
/**
* Commit the navigated item
*
* @returns {void}
* @memberof ListViewTag
*/
nav_commit(): void;
/**
* Handle special key event such as key up and down
*
* @private
* @param {JQuery.KeyboardEventBase} event
* @returns {void}
*/
private handle_special_key;
/** /**
* Mount the grid view tag * Mount the grid view tag
* *

View File

@ -685,7 +685,7 @@ namespace OS {
InfoDialog.scheme = `\ InfoDialog.scheme = `\
<afx-app-window width='300' height='350' apptitle = "Info" > <afx-app-window width='300' height='350' apptitle = "Info" >
<afx-vbox padding = "10"> <afx-vbox padding = "10">
<afx-grid-view data-id = "grid" ></afx-grid-view> <afx-grid-view data-id = "grid" focusable="true"></afx-grid-view>
<div data-height="35" style="text-align: right;"> <div data-height="35" style="text-align: right;">
<afx-button data-id = "btnCancel" text = "__(Cancel)"></afx-button> <afx-button data-id = "btnCancel" text = "__(Cancel)"></afx-button>
</div> </div>

View File

@ -497,6 +497,14 @@ namespace OS {
*/ */
private _dnd: { from: GridRowTag[]; to: GridRowTag }; private _dnd: { from: GridRowTag[]; to: GridRowTag };
/**
* Grid navigation index
*
* @private
* @type {number}
*/
private _nav_index: number;
/** /**
* placeholder of list drag and drop event handle * placeholder of list drag and drop event handle
* *
@ -514,6 +522,7 @@ namespace OS {
*/ */
constructor() { constructor() {
super(); super();
this._nav_index = -1;
} }
/** /**
@ -883,6 +892,35 @@ namespace OS {
} }
$(row).remove(); $(row).remove();
} }
/**
* Scroll the grid view to item
*
* @memberof GridViewTag
*/
scroll_to_item(item: GridRowTag)
{
const cell = $(item).children()[0];
const offset = $(this.refs.container).offset();
const cell_offset = $(cell).offset();
const top = $(this.refs.container).scrollTop();
const cell_height = $(cell).outerHeight();
const container_height = $(this.refs.container).outerHeight();
if (cell_offset.top + cell_height > container_height + offset.top)
{
$(this.refs.container).scrollTop(
top +
(cell_offset.top + cell_height - offset.top - container_height)
);
} else if (cell_offset.top < offset.top) {
$(this.refs.container).scrollTop(
top -
(offset.top - cell_offset.top)
);
}
}
/** /**
* Scroll the grid view to bottom * Scroll the grid view to bottom
* *
@ -1042,6 +1080,7 @@ namespace OS {
} }
evt.data.item = row; evt.data.item = row;
this._selectedRow = row; this._selectedRow = row;
this._nav_index = $(row).index();
this._onrowselect(evt); this._onrowselect(evt);
return this.observable.trigger("rowselect", evt); return this.observable.trigger("rowselect", evt);
} }
@ -1152,6 +1191,101 @@ namespace OS {
} }
} }
/**
* Reset the navigation indicator
*
* @private
*/
private nav_reset() {
const el = $(this.refs.grid).children().eq(this._nav_index);
if(el)
{
$(el).removeClass("gridview-nav-focus");
}
}
/**
* Navigate the list up
*
* @public
* @returns {void}
* @memberof ListViewTag
*/
public nav_prev() {
console.log("nav_prev");
if(this._nav_index <= 0) {
return;
}
this.nav_reset();
this._nav_index--;
const el = $(this.refs.grid).children().eq(this._nav_index);
if(el) {
$(el).addClass("gridview-nav-focus");
this.scroll_to_item(el[0] as GridRowTag);
}
}
/**
* Navigate the list down
*
* @returns {void}
* @memberof ListViewTag
*/
public nav_next() {
console.log("nav_next");
if(this._nav_index >= this.rows.length - 1) {
return;
}
this.nav_reset();
this._nav_index++;
const el = $(this.refs.grid).children().eq(this._nav_index);
if(el) {
$(el).addClass("gridview-nav-focus");
this.scroll_to_item(el[0] as GridRowTag);
}
}
/**
* Commit the navigated item
*
* @returns {void}
* @memberof ListViewTag
*/
public nav_commit() {
if(this._nav_index > this.rows.length - 1 || this._nav_index < 0) {
return;
}
const el = $(this.refs.grid).children().eq(this._nav_index);
if(el) {
(el[0] as GridRowTag).selected = true;
}
}
/**
* Handle special key event such as key up and down
*
* @private
* @param {JQuery.KeyboardEventBase} event
* @returns {void}
*/
private handle_special_key(event: JQuery.KeyboardEventBase) {
switch (event.which) {
case 37:
case 38:
this.nav_prev();
return event.preventDefault();
case 39:
case 40:
this.nav_next();
return event.preventDefault();
case 13:
event.preventDefault();
return this.nav_commit();
default:
break;
}
}
/** /**
* Mount the grid view tag * Mount the grid view tag
* *
@ -1160,6 +1294,9 @@ namespace OS {
* @memberof GridViewTag * @memberof GridViewTag
*/ */
protected mount(): void { protected mount(): void {
$(this).on("keyup", (e) => {
this.handle_special_key(e);
});
$(this).css("overflow", "hidden"); $(this).css("overflow", "hidden");
$(this.refs.grid).css("display", "grid"); $(this.refs.grid).css("display", "grid");
$(this.refs.header).css("display", "grid"); $(this.refs.header).css("display", "grid");

View File

@ -1122,7 +1122,7 @@ namespace OS {
* @returns {void} * @returns {void}
* @memberof ListViewTag * @memberof ListViewTag
*/ */
public nav_next() { public nav_prev() {
if(this._nav_index <= 0) { if(this._nav_index <= 0) {
return; return;
} }
@ -1141,7 +1141,7 @@ namespace OS {
* @returns {void} * @returns {void}
* @memberof ListViewTag * @memberof ListViewTag
*/ */
public nav_prev() { public nav_next() {
if(this._nav_index >= this.data.length - 1) { if(this._nav_index >= this.data.length - 1) {
return; return;
} }
@ -1179,11 +1179,11 @@ namespace OS {
switch (event.which) { switch (event.which) {
case 37: case 37:
case 38: case 38:
this.nav_next(); this.nav_prev();
return event.preventDefault(); return event.preventDefault();
case 39: case 39:
case 40: case 40:
this.nav_prev(); this.nav_next();
return event.preventDefault(); return event.preventDefault();
case 13: case 13:
event.preventDefault(); event.preventDefault();

View File

@ -156,12 +156,12 @@ namespace OS {
return this.toggle(false); return this.toggle(false);
case 37: case 37:
applist.nav_next(); applist.nav_prev();
return e.preventDefault(); return e.preventDefault();
case 38: case 38:
return e.preventDefault(); return e.preventDefault();
case 39: case 39:
applist.nav_prev(); applist.nav_next();
return e.preventDefault(); return e.preventDefault();
case 40: case 40:
return e.preventDefault(); return e.preventDefault();

View File

@ -6,7 +6,7 @@
"author": "Xuan Sang LE", "author": "Xuan Sang LE",
"email": "xsang.le@gmail.com" "email": "xsang.le@gmail.com"
}, },
"version":"0.2.1-b", "version":"0.2.2-b",
"category":"System", "category":"System",
"iconclass":"fa fa-wrench", "iconclass":"fa fa-wrench",
"mimes":["none"] "mimes":["none"]

View File

@ -75,7 +75,7 @@
<afx-hbox data-id="app-about" tabname = "__(Versions)" iconclass = "bi bi-info-square" padding="10"> <afx-hbox data-id="app-about" tabname = "__(Versions)" iconclass = "bi bi-info-square" padding="10">
<afx-vbox> <afx-vbox>
<afx-label text = "__(System versions)" iconclass = "bi bi-gear-wide-connected" class = "header" data-height="30"></afx-label> <afx-label text = "__(System versions)" iconclass = "bi bi-gear-wide-connected" class = "header" data-height="30"></afx-label>
<afx-grid-view data-id="grid-version"></afx-grid-view> <afx-grid-view data-id="grid-version" focusable="true"></afx-grid-view>
</afx-vbox> </afx-vbox>
</afx-hbox> </afx-hbox>

View File

@ -17,6 +17,10 @@ afx-grid-view afx-grid-row.afx-grid-row-selected afx-grid-cell
background-color: var(--item-bg-active); background-color: var(--item-bg-active);
color:var(--text-tertiary); color:var(--text-tertiary);
} }
afx-grid-view afx-grid-row.gridview-nav-focus afx-grid-cell
{
background-color: var(--item-bg-hover);
}
afx-grid-view afx-grid-row.afx-grid-row-selected afx-grid-cell.afx-grid-cell-selected afx-grid-view afx-grid-row.afx-grid-row-selected afx-grid-cell.afx-grid-cell-selected
{ {
font-weight: normal; font-weight: normal;