cshell.js 14.27 KiB
/*
JAVASCRIPT CHAT MENU SHELL - For Synchronet v3.15+ - Matt Johnson(2010)
$ID: $
*****************************************************************************
* IMPORTANT INFORMATION:
* Without customizing some binary "wallpaper" this shell is very boring
* If you wish to use this, I recommend creating a folder in your
* system.text_dir called "cshell" ("/sbbs/text/cshell/") and another within
* called "xtrn" ("/sbbs/text/cshell/xtrn/").
*
* WALLPAPER:
* file: <menu_name>.<width>x<height>.bin
* RIGHT WINDOW ICON:
* file: icon.16x10.bin
*
* NOTE: for a standard 80 x 24 terminal, menu wallpaper has a maximum
* size of 34 x 22, and the main wallpaper has a maximum size of 60 x 22,
* though these numbers largely depend on the size of the side menu and
* right window. The max width can be determined by this formula:
* WALLPAPER WIDTH =
* SCREEN COLUMNS - RIGHT WINDOW WIDTH - (SIDE MENU WIDTH + 1) - 2
*
* DEFAULT SIDE MENU WIDTH: 25
* DEFAULT RIGHT WINDOW WIDTH: 18
******************************************************************************
This shell relies on having commservice.js, commclient.js, and all other related
"/sbbs/exec/" & "/sbbs/exec/load/" files up to date. The shell will automatically
be linked to inter-BBS chat if you are running commservice.js as a node
Much of the lightbar menu code has been taken from lbshell.js, by Deuce.
*/
bbs.command_str=''; // clear STR (Contains the EXEC for default.js)
load("nodedefs.js");
load("lightbar.js");
load("str_cmds.js");
load("chateng.js");
load("graphic.js");
load("funclib.js");
load("clock.js");
load("cshell_menu.js");
load("cshell_obj.js");
const root=js.exec_dir;
var settings_file=new File(
system.data_dir + "user/" + printPadded(user.number,4,"0","right") + ".shell.ini"
);
var screen_rows=console.screen_rows;
var screen_columns=console.screen_columns;
var full_redraw=false;
var orig_passthru=console.ctrlkey_passthru;
var cmdlist=new CommandList();
var settings=new Settings();
var favorites=new Favorites();
var bottom=new BottomLine();
var right=new RightWindow();
var center=new MainWindow();
var left=new LeftWindow();
/* SHELL FUNCTIONS */
function init()
{
loadSettings();
bottom.init();
right.init();
center.init();
left.init();
if(favorites.items.length > 0) {
loadMenu("favorites");
showLeftWindow();
}
redraw();
if(left.menu && left.menu.node_action) bbs.node_action=left.menu.node_action;
else bbs.node_action=NODE_MAIN;
}
function shell()
{
while(!js.terminated) {
cycle();
var cmd="";
if(left.menu) {
cmd=left.menu.getval();
/* LEFT MENU COMMAND PROCESSING */
switch(cmd)
{
case ctrl('R'): /* CTRL-R (Quick Redraw in SyncEdit) */
case ctrl('O'): /* CTRL-O - Pause */
case ctrl('U'): /* CTRL-U User List */
case ctrl('T'): /* CTRL-T Time Info */
case ctrl('K'): /* CTRL-K Control Key Menu */
case ctrl('P'): /* Ctrl-P Messages */
case ctrl('C'): /* Ctrl-P ABORT */
handleCtrlKey(cmd);
continue;
case KEY_UP:
lightBarUp(left.menu);
break;
case KEY_DOWN:
lightBarDown(left.menu);
break;
case KEY_HOME:
lightBarHome(left.menu);
break;
case KEY_END:
lightBarEnd(left.menu);
break;
case KEY_LEFT:
previousMenu();
break;
case KEY_RIGHT:
case "Q":
case "\x1b":
hideLeftWindow();
center.restore();
bottom.restore();
continue;
case "+":
if(left.currentmenu == "favorites" ||
left.currentmenu == "addfavorite" ||
left.currentmenu == "removefavorite") {
break;
}
favorites.mi=left.currentmenu;
favorites.mt=left.menu.title;
favorites.ii=left.menu.current;
favorites.it=left.menu.items[favorites.ii].text.substr(3);
loadMenu("addfavorite");
break;
default:
if(left.menu.items[cmd]) {
var item_id=left.menu.items[cmd].id;
left.process(item_id);
}
break;
}
}
if(!cmd) cmd=console.inkey(K_NOCRLF|K_NOSPIN|K_NOECHO|K_UPPER,5);
if(!cmd) continue;
/* MAIN MENU PROCESS */
switch(cmd)
{
case ctrl('R'): /* CTRL-R (Quick Redraw in SyncEdit) */
case ctrl('O'): /* CTRL-O - Pause */
case ctrl('U'): /* CTRL-U User List */
case ctrl('T'): /* CTRL-T Time Info */
case ctrl('K'): /* CTRL-K Control Key Menu */
case ctrl('P'): /* Ctrl-P Messages */
case ctrl('C'): /* Ctrl-P ABORT */
handleCtrlKey(cmd);
continue;
case " ":
redraw();
break;
case "-":
if(!favorites.items.length > 0) {
break;
}
loadMenu("delfavorite");
break;
case "\x1b":
case "Q":
center.quitChat();
return false;
default:
var sc=bottom.menu.items[cmd];
if(sc && sc.enabled) {
cmdlist[sc.command].apply(cmdlist[sc.command],sc.parameters);
}
break;
}
if(!left.menu) continue;
if(!left.menu_shown) showLeftWindow();
if(!left.title_shown) left.drawTitle();
if(menuinfo[left.currentmenu]) {
menuinfo[left.currentmenu]();
}
}
}
function cycle()
{
/* Update node action */
if(bbs.node_action != system.node_list[bbs.node_num-1].action)
system.node_list[bbs.node_num-1].action = bbs.node_action;
/* Check for messages */
if(system.node_list[bbs.node_num-1].misc & NODE_MSGW) {
if(!center.in_chat) right.addNotice();
center.notice(system.get_telegram(user.number));
}
if(system.node_list[bbs.node_num-1].misc & NODE_NMSG) {
if(!center.in_chat) right.addNotice();
center.notice(system.get_node_message(bbs.node_num));
}
/* Fix up node status */
if(system.node_list[bbs.node_num-1].status==NODE_WFC) {
system.node_list[bbs.node_num-1].status=NODE_INUSE;
}
/* Check if user data has changed */
if((system.node_list[bbs.node_num-1].misc & NODE_UDAT) && user.compare_ars("REST NOT G")) {
user.cached=false;
system.node_list[bbs.node_num-1].misc &= ~NODE_UDAT;
}
/* Interrupted? */
if(system.node_list[bbs.node_num-1].misc & NODE_INTR) {
bbs.hangup();
}
/* Sysop Chat? */
if(system.node_list[bbs.node_num-1].misc & NODE_LCHAT) {
// TODO: No way of calling bbs.priave_chat(true)
// bbs.private_chat();
bbs.nodesync();
full_redraw=true;
}
right.cycle();
center.cycle();
left.cycle();
if(full_redraw) {
redraw();
}
}
/* GLOBAL FUNCTIONS */
function handleCtrlKey(key)
{
switch(key) {
case ctrl('C'): /* Ctrl-P ABORT */
console.aborted=false;
break;
}
}
function getHotkey(item)
{
var index=item.indexOf("|")+1;
return item[index].toUpperCase();
}
function redraw()
{
console.clear(ANSI_NORMAL);
drawTopline();
drawOutline();
center.redraw();
right.redraw();
left.redraw();
bottom.redraw();
if(menuinfo[left.currentmenu]) {
menuinfo[left.currentmenu]();
}
bbs.sys_status|=SS_PAUSEOFF;
console.ctrlkey_passthru="+KOPTUC";
full_redraw=false;
}
function loadWallPaper(file)
{
if(!file_exists(file)) return false;
var width=0;
var height=0;
var size=file_getname(file).split(".")[1].split("x");
if(size[0]) width=Number(size[0]);
if(size[1]) height=Number(size[1]);
var wp=new Graphic(width,height);
wp.load(file);
return wp;
}
function drawTitle(x,y,str)
{
console.attributes=BG_LIGHTGRAY + BLACK;
var top=printPadded("",str.length,"\xDF");
var middle=str;
var bottom=printPadded("",str.length,"\xDC");
console.gotoxy(x,y);
console.pushxy();
console.putmsg(top,P_SAVEATR);
console.popxy();
console.down();
console.pushxy();
console.putmsg(middle,P_SAVEATR);
console.popxy();
console.down();
console.putmsg(bottom,P_SAVEATR);
}
function drawSeparator(x,y)
{
console.gotoxy(x,y);
console.pushxy();
console.attributes=BG_BLACK + (settings.shell_bg>>4);
for(var i=0;i<settings.main_height;i++) {
console.putmsg("\xB3",P_SAVEATR);
console.popxy();
console.down();
console.pushxy();
}
}
function drawTopline()
{
var sysname=" \1k" + system.name + " : \1b" + system.location;
var sysop="\1kSysOp : \1b" + system.operator + " ";
var title=splitPadded(sysname,sysop,console.screen_columns," ");
console.home();
console.attributes=settings.shell_bg;
console.putmsg(title,P_SAVEATR);
}
function drawOutline()
{
console.attributes=BG_BLACK + (settings.shell_bg>>4);
var outline=splitPadded("\xDD","\xDE",console.screen_columns," ");
for(var l=2;l<console.screen_rows;l++) {
console.gotoxy(1,l);
console.putmsg(outline,P_SAVEATR);
}
}
function displayInfo(text)
{
console.putmsg(text);
console.popxy();
console.down();
console.pushxy();
}
function setPosition(x,y)
{
console.gotoxy(x,y);
console.pushxy();
}
function logoff()
{
center.quitChat();
if(bbs.batch_dnload_total) {
if(console.yesno(bbs.text(Menu_downloadBatchQ))) {
bbs.batch_download();
bbs.logoff();
}
} else bbs.hangup();
}
function chatInput()
{
showChat();
while(center.in_chat) {
cycle();
var key=console.inkey(K_NOCRLF|K_NOSPIN|K_NOECHO,5);
if(!key) continue;
switch(key) {
case '\r':
if(!center.chat.input_line.buffer.length) {
center.in_chat=false;
}
break;
case '\x09': /* CTRL-I TAB */
center.toggleChannel();
continue;
case '\x1b':
center.in_chat=false;
break;
default:
break;
}
center.chat.processKey(key);
}
hideChat();
}
/* MAIN MENU */
function hideChat()
{
if(left.menu && left.menu.node_action) bbs.node_action=left.menu.node_action;
else bbs.node_action=NODE_MAIN;
center.chat.chatroom.active=false;
center.redraw();
bottom.restore();
}
function showChat()
{
center.in_chat=true;
right.chat_msgs=0;
right.notices=0;
right.update=true;
bbs.node_action=NODE_CHAT;
center.chat.chatroom.active=true;
center.redraw();
console.gotoxy(1,center.chat.input_line.y);
console.cleartoeol(settings.shell_bg);
console.right();
console.attributes=BG_LIGHTGRAY;
console.putmsg("\1k\xDDCHAT:",P_SAVEATR);
console.attributes=settings.shell_bg;
console.putmsg("\1k\xDD",P_SAVEATR);
center.chat.input_line.clear();
}
/* MAIN WINDOW */
function stretchCenter(height)
{
var rows=this.rows;
rows+=height;
center.chat.resize(undefined,rows,undefined,undefined);
}
function expandCenter(width,side)
{
var cols=center.chat.chatroom.columns;
var x=center.chat.chatroom.x;
if(side=="left"){
x-=width;
cols+=width;
}
if(side=="right"){
cols+=width;
}
center.chat.resize(cols,undefined,x,undefined);
}
/* LEFT MENU */
function hideLeftWindow()
{
expandCenter(settings.menu_width+1,"left");
delete left.menu;
left.currentmenu="";
left.menu_shown=false;
left.title_shown=false;
left.previous=[];
}
function showLeftWindow()
{
expandCenter(-(settings.menu_width+1),"left");
drawSeparator(settings.menu_width+2,2,settings.main_height);
left.menu_shown=true;
}
function lightBarUp(m)
{
do {
if(m.current==0)
m.current=m.items.length;
m.current--;
} while(m.items[m.current].disabled || m.items[m.current].retval==undefined);
}
function lightBarHome(m)
{
m.current=0;
while(m.items[m.current].disabled || m.items[m.current].retval==undefined) {
m.current++;
if(m.current==m.items.length)
m.current=0;
}
}
function lighBarEnd(m)
{
left.menu.current=left.menu.items.length-1;
while(left.menu.items[left.menu.current].disabled || left.menu.items[left.menu.current].retval==undefined) {
if(m.current==0)
m.current=m.items.length;
m.current--;
}
}
function lightBarDown(m)
{
do {
m.current++;
if(m.current==m.items.length)
m.current=0;
} while(m.items[m.current].disabled || m.items[m.current].retval==undefined);
}
function previousMenu()
{
left.previousMenu();
}
function addcmd(text,id,disabled)
{
this.add(text,undefined,settings.menu_width,undefined,undefined,disabled);
this.items[this.items.length-1].id=id;
}
function fill_menu(lb)
{
if(left.previous.length) offset=5;
else offset=4;
while(lb.items.length<settings.main_height-offset)
{
lb.add("","",settings.menu_width,undefined,undefined,true);
}
if(left.previous.length) lb.add(format_opt("Previous Menu",settings.menu_width,-1),KEY_LEFT,settings.menu_width);
lb.add(format_opt("Main Menu",settings.menu_width,0),KEY_RIGHT,settings.menu_width);
}
function set_hotkeys(lb)
{
/* USE FIRST AVAILABLE HOTKEY AS TRIGGER */
/* RETURN VALUE = ITEM INDEX FOR MENU COMMAND REFERENCE */
var hotkeys="1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var index=0;
for(var i=0;i<lb.items.length;i++) {
if(lb.items[i].disabled) continue;
while(bottom.menu.items[hotkeys[index]]) index++;
lb.items[i].text="|" + hotkeys[index++] + " " + lb.items[i].text;
lb.items[i].retval=i;
}
}
function loadMenu()
{
return left.loadMenu.apply(left,arguments);
}
/* MENU FUNCTIONS */
function format_opt(str, width, expand)
{
var spaces80=" ";
if(expand == -1) {
opt='|< ';
var cleaned=str;
cleaned=cleaned.replace(/\|/g,'');
opt+=str+spaces80.substr(0,width-cleaned.length-2);
return opt;
} else if(expand == 0) {
opt=str;
var cleaned=opt;
cleaned=cleaned.replace(/\|/g,'');
opt+=spaces80.substr(0,width-cleaned.length-2);
opt+=' |>';
return opt;
} else if(expand == 1) {
opt=str;
var cleaned=opt;
cleaned=cleaned.replace(/\|/g,'');
opt+=spaces80.substr(0,width-cleaned.length-2);
opt+=' |+';
return opt;
}
return(str);
}
function todo_getfiles(lib, dir)
{
var path=format("%s%s.ixb", file_area.lib_list[lib].dir_list[dir].data_dir, file_area.lib_list[lib].dir_list[dir].code);
return(file_size(path)/22); /* F_IXBSIZE */
}
function clear_screen()
{
/*
* Called whenever a command needs to exit the menu for user interaction.
*
* If you'd like a header before non-menu stuff, this is the place to put
* it.
*/
bbs.sys_status&=~SS_PAUSEOFF;
console.clear(ANSI_NORMAL);
full_redraw=true;
/* We are going to a line-mode thing... re-enable CTRL keys. */
}
/* USER SETTINGS */
function saveSettings()
{
settings_file.open('w+',false);
if(!settings_file.is_open) {
log("error opening user settings",LOG_WARNING);
return;
}
settings_file.iniSetObject("settings",settings);
for(var f=0;f<favorites.items.length;f++) {
var fav=favorites.items[f];
var value=
fav.menuID + "," +
fav.menuTitle + "," +
fav.itemID + "," +
fav.itemTitle + "," +
fav.xtrnsec;
settings_file.iniSetValue("favorites",f,value);
}
settings_file.close();
}
function loadSettings()
{
if(file_exists(settings_file.name)) {
settings_file.open('r',true);
if(!settings_file.is_open) {
log("error opening user settings",LOG_WARNING);
return;
}
var set=settings_file.iniGetObject("settings");
var fav=settings_file.iniGetObject("favorites");
settings=new Settings(set);
favorites=new Favorites(fav);
settings_file.close();
}
}
init();
shell();