Commit 29d97a2b authored by Michael Long's avatar Michael Long
Browse files

xtrnmenu module v3

parent d322c5e1
Pipeline #1272 passed with stage
in 14 minutes and 56 seconds
......@@ -106,4 +106,29 @@ searchagainmsg: "\x01n\x01mPress S to Search Again."
;favorte_remove_item: "Remove Item"
;add_favorites_msg: "\x01c\x01hAdd Favorite"
;remove_favorites_msg: "\x01c\x01hRemove Favorite"
;custom.favorites_inst: "\x01n\x01w\x01h\x012[Up/Down/Home/End] to Navigate, [Enter] to Select, [Q] to Quit"
;favorites_inst: "\x01n\x01w\x01h\x012 [Up/Down/Home/End] to Navigate, [Enter] to Select, [Q] to Quit, [S] to Search "
;favorites_inst_rem: "\x01n\x01w\x01h\x012 [Up/Down/Home/End] to Navigate, [Enter] to Select, [Q] to Quit "
;favorite_add_search_prompt: "\x01c\x01hSearch (ESC to Cancel): \x01n"
; autocomplete (search) box on add favorite
; see cga_defs.js for color codes
; autocomplete input box
;favorite_add_search_fg=LIGHTGRAY
;favorite_add_search_bg=BG_BLACK
; autocomplete result box
;favorite_add_search_sfg=LIGHTGRAY
;favorite_add_search_sbg=BG_BLACK
; autocomplete highlighted row
;favorite_add_search_hsfg=WHITE
;favorite_add_search_hsbg=BG_MAGENTA
; scrolling menu on add favorite
; lightbar non-current item
;favorite_add_fg=LIGHTGRAY
;favorite_add_bg=BG_BLACK
; lightbar current item
;favorite_add_lfg=WHITE
;favorite_add_lbg=BG_MAGENTA
; tree heading
;favorite_add_cfg=WHITE
;favorite_add_cbg=BG_BLACK
\ No newline at end of file
......@@ -218,7 +218,7 @@ ExternalMenus.prototype.getOptions = function(menutype, menuid) {
}
this.options.custom = this.xtrn_custommenu_options;
return this.options;
}
......@@ -250,20 +250,20 @@ ExternalMenus.prototype.getMenu = function(menuid) {
xtrn_area.sec_list.forEach(function (sec) {
if (sec.can_access) {
menuitems.push({
"input": i,
"target": sec.code,
"type": "xtrnmenu",
"title": sec.name,
"access_string": sec.ars
input: i,
target: sec.code,
type: "xtrnmenu",
title: sec.name,
access_string: sec.ars
});
i++;
}
});
menu = {
"id": "main",
"title": "Main Menu",
"items": menuitems
id: "main",
title: "Main Menu",
items: menuitems
};
}
return menu;
......@@ -278,12 +278,17 @@ ExternalMenus.prototype.getSectionMenu = function(menuid) {
}
var menuitems = [];
var menu, title;
var title;
var menu = {
id: menuid,
title: null,
items: []
}
xtrn_area.sec_list.some(function (sec) {
if (sec.code.toLowerCase() == menuid.toLowerCase()) {
title = sec.name;
menu.title = sec.name;
if (!sec.can_access || sec.prog_list.length < 1) {
return false;
......@@ -292,22 +297,18 @@ ExternalMenus.prototype.getSectionMenu = function(menuid) {
var i = 1;
sec.prog_list.some(function (prog) {
menuitems.push({
'input' : i,
'target': prog.code,
'title': prog.name,
'type': 'xtrnprog',
'access_string': prog.ars,
'cost': prog.cost
input : i,
target: prog.code,
title: prog.name,
type: 'xtrnprog',
access_string: prog.ars,
cost: prog.cost
});
i++;
});
if (menuitems.length > 0) {
menu = {
'id': menuid,
'title': title,
'items': menuitems,
};
menu.items = menuitems;
}
return;
}
......@@ -447,6 +448,11 @@ ExternalMenus.prototype.sort_by_input = function(a, b) {
return 0;
}
// Handle json update
ExternalMenus.prototype.processUpdate = function(update) {
log(ERROR, "Unhandled JSON DB packet: " + JSON.stringify(update));
}
// Sort for special menus, by value numerically desc
ExternalMenus.prototype.sort_special = function(obj) {
var keys = [];
......@@ -458,6 +464,8 @@ ExternalMenus.prototype.sort_special = function(obj) {
// return menu object for special menu (most recent, etc.)
ExternalMenus.prototype.getSpecial = function(menutype, title, itemcount) {
var options = this.getOptions('custommenu', menutype);
var menu;
var menuitems = [];
......@@ -476,10 +484,11 @@ ExternalMenus.prototype.getSpecial = function(menutype, title, itemcount) {
}
try {
load("json-client.js")
require("json-client.js", "JSONClient");
var jsonClient = new JSONClient(this.options.json_host, this.options.json_port);
jsonClient.callback = processUpdate;
jsonClient.callback = this.processUpdate;
} catch (e) {
writeln("NP" + e);
log(LOG_ERR, "xtrnmenulib: Could not initialize JSON database so special menu is now disabled: " + e);
return false;
}
......@@ -559,13 +568,13 @@ ExternalMenus.prototype.getSpecial = function(menutype, title, itemcount) {
break;
}
menuitems.push({
'input': i,
'target': xtrn_area.prog[e].code,
'title': xtrn_area.prog[e].name,
'type': 'xtrnprog',
'access_string': xtrn_area.prog[e].ars,
'cost': xtrn_area.prog[e].cost,
'stats': stats,
input: i,
target: xtrn_area.prog[e].code,
title: xtrn_area.prog[e].name,
type: 'xtrnprog',
access_string: xtrn_area.prog[e].ars,
cost: xtrn_area.prog[e].cost,
stats: stats,
});
i++;
break;
......@@ -578,9 +587,9 @@ ExternalMenus.prototype.getSpecial = function(menutype, title, itemcount) {
}
if (menuitems.length > 0) {
menu = {
'id': menutype,
'title': title,
'items': menuitems,
id: menutype,
title: title,
items: menuitems,
};
}
......@@ -602,9 +611,9 @@ ExternalMenus.prototype.getFavorites = function(title, itemcount) {
}
try {
load("json-client.js")
require("json-client.js", "JSONClient");
var jsonClient = new JSONClient(this.options.json_host, this.options.json_port);
jsonClient.callback = processUpdate;
jsonClient.callback = this.processUpdate;
} catch (e) {
log(LOG_ERR, "xtrnmenulib: Could not initialize JSON database so favorites is now disabled: " + e);
return false;
......@@ -624,12 +633,12 @@ ExternalMenus.prototype.getFavorites = function(title, itemcount) {
var stats;
menuitems.push({
'input': i,
'target': xtrn_area.prog[e].code,
'title': xtrn_area.prog[e].name,
'type': 'xtrnprog',
'access_string': xtrn_area.prog[e].ars,
'cost': xtrn_area.prog[e].cost,
input: i,
target: xtrn_area.prog[e].code,
title: xtrn_area.prog[e].name,
type: 'xtrnprog',
access_string: xtrn_area.prog[e].ars,
cost: xtrn_area.prog[e].cost,
});
i++;
break;
......@@ -642,9 +651,9 @@ ExternalMenus.prototype.getFavorites = function(title, itemcount) {
}
menu = {
'id': 'favorites',
'title': title,
'items': menuitems,
id: 'favorites',
title: title !== undefined ? title : 'Favorites',
items: menuitems,
};
return menu;
......
......@@ -19,6 +19,8 @@ require("sbbsdefs.js", "K_NONE");
require("xtrnmenulib.js", "MENU_LOADED");
const ansiterm = load({}, 'ansiterm_lib.js');
var options, xsec = -1;
//// Main
......@@ -110,9 +112,9 @@ function dopre(progCode)
}
try {
load("json-client.js")
require("json-client.js", "JSONClient");
var jsonClient = new JSONClient(options.json_host, options.json_port);
jsonClient.callback = processUpdate;
jsonClient.callback = ExternalMenus.processUpdate;
} catch (e) {
log(LOG_ERR, "xtrnmenu pre: Could not initialize JSON database so door tracking is now disabled: " + e);
return;
......@@ -218,9 +220,9 @@ function dopost(progCode)
}
try {
load("json-client.js")
require("json-client.js", "JSONClient");
var jsonClient = new JSONClient(options.json_host, options.json_port);
jsonClient.callback = processUpdate;
jsonClient.callback = ExternalMenus.processUpdate;
} catch (e) {
log(LOG_ERR, "xtrnmenu pre: Could not initialize JSON database so door tracking is now disabled: " + e);
return;
......@@ -267,15 +269,6 @@ function dopost(progCode)
}
}
/**
* JSON DB handler
* @param update
*/
function processUpdate(update)
{
log(ERROR, "Unhandler JSON DB packet: " + JSON.stringify(update));
}
// Runs custom commands, for gamesrv
function docommand(command, commandparam1, commandparam2)
{
......@@ -600,6 +593,12 @@ function external_menu_custom(menuid)
break;
}
// empty menu
if (!menuobj.items.length && (menuid != "main")) {
write(options.no_programs_msg);
break;
}
system.node_list[bbs.node_num-1].aux = 0; /* aux is 0, only if at menu */
bbs.node_action = NODE_XTRN;
bbs.node_sync();
......@@ -842,7 +841,12 @@ function external_menu_custom(menuid)
// don't have ESC do anything on the main menu
} else if ((keyin == 'q') || (keyin == "\x1B")) {
if (gamesrv && (menuid == 'main')) {
bbs.logoff();
// doing it this way rather than calling bbs.logoff()
// so that the prompt defaults to Yes
console.crlf();
if (console.yesno("Do you wish to logoff")) {
bbs.logoff(false);
}
} else {
console.clear();
return;
......@@ -1397,11 +1401,11 @@ function search_menu(title, itemcount) {
if (menuconfig.menus[i].title.toLowerCase().indexOf(searchterm) !== -1) {
if (user.compare_ars(menuconfig.menus[i].title.access_string)) {
menuitemsfiltered.push({
'input': input++,
'id': menuconfig.menus[i].id,
'title': menuconfig.menus[i].title,
'target': menuconfig.menus[i].id,
'type': 'custommenu'
input: input++,
id: menuconfig.menus[i].id,
title: menuconfig.menus[i].title,
target: menuconfig.menus[i].id,
type: 'custommenu'
});
}
}
......@@ -1414,11 +1418,11 @@ function search_menu(title, itemcount) {
if (xtrn_area.sec_list[i].name.toLowerCase().indexOf(searchterm) !== -1) {
if (xtrn_area.sec_list[i].can_access) {
menuitemsfiltered.push({
'input': input++,
'id': xtrn_area.sec_list[i].code,
'title': xtrn_area.sec_list[i].name,
'target': xtrn_area.sec_list[i].code,
'type': 'xtrnmenu'
input: input++,
id: xtrn_area.sec_list[i].code,
title: xtrn_area.sec_list[i].name,
target: xtrn_area.sec_list[i].code,
type: 'xtrnmenu'
});
}
}
......@@ -1432,11 +1436,11 @@ function search_menu(title, itemcount) {
if (xtrn_area.sec_list[i].prog_list[k].name.toLowerCase().indexOf(searchterm) !== -1) {
if (xtrn_area.sec_list[i].prog_list[k].can_access) {
menuitemsfiltered.push({
'input': input++,
'id': xtrn_area.sec_list[i].prog_list[k].code,
'title': xtrn_area.sec_list[i].prog_list[k].name,
'target': xtrn_area.sec_list[i].prog_list[k].code,
'type': 'xtrnprog'
input: input++,
id: xtrn_area.sec_list[i].prog_list[k].code,
title: xtrn_area.sec_list[i].prog_list[k].name,
target: xtrn_area.sec_list[i].prog_list[k].code,
type: 'xtrnprog'
});
}
}
......@@ -2054,6 +2058,16 @@ function favorites_menu(title, itemcount) {
if (keyin) {
if ((keyin == '+') || (keyin == '=')) {
add_favorite();
} else if ((keyin == "\x08") || (keyin == "\x7f")) {
// delete
if (menuitemsfiltered[selected_index].type == 'xtrnprog') {
console.crlf();
if (!console.noyes("Do you wish to remove " +
menuitemsfiltered[selected_index].title)) {
remove_favorite(menuitemsfiltered[selected_index].target.toLowerCase());
}
}
} else if ((keyin == '-') || (keyin == '_')) {
remove_favorite();
} else {
......@@ -2084,6 +2098,12 @@ function favorites_menu(title, itemcount) {
// Add an entry to the favorites menu
function add_favorite()
{
require("frame.js", "Frame");
require("tree.js", "Tree");
require("scrollbar.js", "ScrollBar");
require('typeahead.js', 'Typeahead');
load(js.global, 'cga_defs.js');
var options = ExternalMenus.getOptions('custommenu', 'favorites');
if (!options.json_enabled) {
......@@ -2092,9 +2112,9 @@ function add_favorite()
}
try {
load("json-client.js")
require("json-client.js", "JSONClient");
var jsonClient = new JSONClient(options.json_host, options.json_port);
jsonClient.callback = processUpdate;
jsonClient.callback = ExternalMenus.processUpdate;
} catch (e) {
log(LOG_ERR, "xtrnmenu add_favorites: Could not initialize JSON database so favorites is now disabled: " + e);
return false;
......@@ -2107,12 +2127,10 @@ function add_favorite()
jsonData = [];
}
load("frame.js");
load("tree.js");
var frame = new Frame(1, 1, console.screen_columns, 4, WHITE);
var treeframe = new Frame(1, 5, console.screen_columns, console.screen_rows-5, WHITE);
var frame = new Frame(1, 1, console.screen_columns, console.screen_rows, WHITE);
var treeframe = new Frame(frame.x, frame.y+4, frame.width, frame.height-5, WHITE);
var tree = new Tree(treeframe);
var s = new ScrollBar(tree);
frame.open();
treeframe.open();
......@@ -2120,7 +2138,7 @@ function add_favorite()
? options.custom.add_favorites_msg : "\x01c\x01hAdd Favorite");
frame.gotoxy(1, 3);
frame.putmsg(options.custom.favorites_inst !== undefined
? options.custom.favorites_inst : '\x01n\x01w\x01h\x012[Up/Down/Home/End] to Navigate, [Enter] to Select, [Q] to Quit');
? options.custom.favorites_inst : '\x01n\x01w\x01h\x012 [Up/Down/Home/End] to Navigate, [Enter] to Select, [Q] to Quit, [S] to Search ');
var xtrnwidth = 0;
var sortedItems = [];
......@@ -2154,13 +2172,23 @@ function add_favorite()
}
treeframe.width = xtrnwidth + 2;
tree.colors.fg = LIGHTGRAY;
tree.colors.bg = BG_BLACK;
tree.colors.lfg = WHITE;
tree.colors.lbg = BG_MAGENTA;
tree.colors.kfg = YELLOW;
// lightbar non-current item
tree.colors.fg = options.custom.favorite_add_fg
? js.global[options.custom.favorite_add_fg] : LIGHTGRAY;
tree.colors.bg = options.custom.favorite_add_bg
? js.global[options.custom.favorite_add_bg] : BG_BLACK;
// lightbar current item
tree.colors.lfg = options.custom.favorite_add_lfg
? js.global[options.custom.favorite_add_lfg] : WHITE;
tree.colors.lbg = options.custom.favorite_add_lbg
? js.global[options.custom.favorite_add_lbg] : BG_MAGENTA;
// tree heading
tree.colors.cfg = options.custom.favorite_add_cfg
? js.global[options.custom.favorite_add_cfg] : WHITE;
tree.colors.cbg = options.custom.favorite_add_cbg
? js.global[options.custom.favorite_add_cbg] : BG_BLACK;
// other tree color settings not applicable to this implementation
tree.open();
console.clear(BG_BLACK|LIGHTGRAY);
......@@ -2172,37 +2200,120 @@ function add_favorite()
var key;
var xtrn;
while(bbs.online) {
key = console.getkey();
key = console.getkey(K_NOSPIN);
if (key == "\x0d") {
// hit enter, item is selected
break;
}
if ((key.toLowerCase() == 'q') || (key == "\x1B")) return;
selection = tree.getcmd({ key: key, mouse: false });
if (key == KEY_UP || key == KEY_DOWN || key == KEY_HOME || key == KEY_END) {
if ((key == KEY_UP) && (tree.line == 1)) {
// pressed up on first item, go to end
tree.end();
tree.refresh(); // fixes itself with it going to next to last item
} else if ((key == KEY_DOWN) && (tree.line == sortedItems.length)) {
// pressed down on last item, go to start
tree.home();
tree.refresh(); // fixes issue with it going to 2nd item
} else if ((key.toLowerCase() == 'q') || (key == "\x1B")) {
return;
} else if (key.toLowerCase() == 's') {
xtrn = add_favorite_search(frame, treeframe, options);
break;
} else {
selection = tree.getcmd({key: key, mouse: false});
if (key == KEY_UP || key == KEY_DOWN || key == KEY_HOME || key == KEY_END) {
if ((key == KEY_UP) && (tree.line == 1)) {
// pressed up on first item, go to end
tree.end();
tree.refresh(); // fixes itself with it going to next to last item
} else if ((key == KEY_DOWN) && (tree.line == sortedItems.length)) {
// pressed down on last item, go to start
tree.home();
tree.refresh(); // fixes issue with it going to 2nd item
}
xtrn = tree.currentItem;
}
xtrn = tree.currentItem;
}
frame.cycle();
treeframe.cycle();
s.cycle();
}
if (typeof xtrn.code !== "undefined") {
jsonData.push(xtrn.code);
jsonClient.write("xtrnmenu", "favorites_" + user.alias, jsonData, 2);
}
jsonData.push(xtrn.code);
jsonClient.write("xtrnmenu", "favorites_" + user.alias, jsonData, 2);
}
// Type ahead search for add favorite
function add_favorite_search(frame, treeframe, options) {
require("frame.js", "Frame");
require("tree.js", "Tree");
require('typeahead.js', 'Typeahead');
load(js.global, 'cga_defs.js');
var sframe = new Frame(
1,
1,
console.screen_columns,
console.screen_rows,
LIGHTGRAY,
frame
);
sframe.open();
const typeahead = new Typeahead({
x : 1,
y : 1,
bg : options.custom.favorite_add_search_fg
? js.global[options.custom.favorite_add_search_fg] : LIGHTGRAY,
fg: options.custom.favorite_add_search_bg
? js.global[options.custom.favorite_add_search_bg] : BG_BLACK,
sfg: options.custom.favorite_add_search_sfg
? js.global[options.custom.favorite_add_search_sfg] : LIGHTGRAY,
sbg: options.custom.favorite_add_search_sbg
? js.global[options.custom.favorite_add_search_sbg] : BG_BLACK,
hsfg: options.custom.favorite_add_search_hsfg
? js.global[options.custom.favorite_add_search_hsfg] : WHITE,
hsbg: options.custom.favorite_add_search_hsbg
? js.global[options.custom.favorite_add_search_hsbg] : BG_MAGENTA,
prompt: options.custom.favorite_add_search_prompt
? options.custom.favorite_add_search_prompt : "\x01c\x01hSearch (ESC to Cancel): \x01n",
len: treeframe.width,
frame: sframe,
datasources: [
function (searchterm) {
const ret = [];
for (i in xtrn_area.sec_list) {
for (var k in xtrn_area.sec_list[i].prog_list) {
if (xtrn_area.sec_list[i].prog_list[k].name.toLowerCase().indexOf(searchterm.toLowerCase()) !== -1) {
if (xtrn_area.sec_list[i].prog_list[k].can_access) {
ret.push({
'code': xtrn_area.sec_list[i].prog_list[k].code,
'text': xtrn_area.sec_list[i].prog_list[k].name,
});
}
}
}
}
return ret;
}
]
});
var user_input = undefined;
while (typeof user_input !== 'object') {
var key = console.inkey(K_NONE, 5);
if (key == "\x1B") {
typeahead.close();
sframe.close();
return false;
}
user_input = typeahead.inkey(key);
typeahead.cycle();
if (sframe.cycle()) typeahead.updateCursor();
}
typeahead.close();
sframe.close();
return user_input;
}
// Remove an entry from the favorites menu
function remove_favorite()
function remove_favorite(xtrncode)
{
var options = ExternalMenus.getOptions('custommenu', 'favorites');
......@@ -2212,9 +2323,9 @@ function remove_favorite()
}
try {
load("json-client.js")
require("json-client.js", "JSONClient");
var jsonClient = new JSONClient(options.json_host, options.json_port);
jsonClient.callback = processUpdate;
jsonClient.callback = ExternalMenus.processUpdate;
} catch (e) {
log(LOG_ERR, "xtrnmenu remove_favorites: Could not initialize JSON database so favorites is now disabled: " + e);
return false;
......@@ -2227,98 +2338,104 @@ function remove_favorite()
jsonData = [];
}
load("frame.js");
load("tree.js");
var frame = new Frame(1, 1, console.screen_columns, 4, WHITE);
var treeframe = new Frame(1, 5, console.screen_columns, console.screen_rows-5, WHITE);