From 028f4dac7afb13a5eada4998506bb2d2371a6e75 Mon Sep 17 00:00:00 2001 From: echicken <> Date: Mon, 15 Feb 2016 10:45:31 +0000 Subject: [PATCH] Sufficiently revised to be called version 3. Now you can include your door game score files at the top of the list, or whatever thrilling .ans or .txt files you wish to showcase. Improved scrolling. Added horizontal scrolling for score files that may be slightly wider than the 'window'. There's also some web junk that I added earlier for, uh ... Drakahn99, who requested it. If you're already using a previous version, the config file has been changed and you'll need to change with it. --- xtrn/bullshit/bullshit.ini | 27 +- xtrn/bullshit/bullshit.js | 574 +++++++++++++++++++++++++------------ xtrn/bullshit/readme.txt | 175 ++++++++--- 3 files changed, 539 insertions(+), 237 deletions(-) diff --git a/xtrn/bullshit/bullshit.ini b/xtrn/bullshit/bullshit.ini index e020d38ef2..050ed41709 100644 --- a/xtrn/bullshit/bullshit.ini +++ b/xtrn/bullshit/bullshit.ini @@ -1,13 +1,14 @@ -; Internal code of the message area containing your bulletins -messageBase = BULLSHIT - -; See sbbsdefs.js for valid colors to specify here -titleColor = WHITE -headingColor = DARKGRAY -textColor = LIGHTGRAY -footerColor = WHITE -lightbarForeground = LIGHTCYAN -lightbarBackground = BG_CYAN -listForeground = LIGHTGRAY -; borderColor may be a comma-separated list if you want a gradient -borderColor = LIGHTBLUE,CYAN,LIGHTCYAN,LIGHTGRAY,WHITE +messageBase = BULLSHIT +maxMessages = 0 + +[colors] +title = WHITE +text = LIGHTGRAY +heading = DARKGRAY +lightbarForeground = LIGHTCYAN +lightbarBackground = BG_CYAN +listForeground = LIGHTGRAY +footer = WHITE +border = LIGHTBLUE,CYAN,LIGHTCYAN,LIGHTGRAY,WHITE + +[files] diff --git a/xtrn/bullshit/bullshit.js b/xtrn/bullshit/bullshit.js index 1222977100..14ae4b72af 100644 --- a/xtrn/bullshit/bullshit.js +++ b/xtrn/bullshit/bullshit.js @@ -1,186 +1,388 @@ -load("sbbsdefs.js"); -load("frame.js"); -load("tree.js"); -load("scrollbar.js"); -load("funclib.js"); - -js.branch_limit = 0; - -var frame, - titleFrame, - listFrame, - footerFrame, - tree, - ini, - msgBase, - treeScroll; - -/* drawFrameBorder(frame, color, gradient) - Draws a border of color 'color' around Frame object 'frame' - If 'gradient' is true, 'color' must be an array of colors to draw in order - See sbbsdefs.js for valid colors */ -var drawFrameBorder = function(frame, color) { - var theColor = color; - if(color instanceof Array) - var sectionLength = Math.round(frame.width / color.length); - for(var y = 1; y <= frame.height; y++) { - for(var x = 1; x <= frame.width; x++) { - if(x > 1 && x < frame.width && y > 1 && y < frame.height) - continue; - var msg = false; - frame.gotoxy(x, y); - if(y == 1 && x == 1) - msg = ascii(218); - else if(y == 1 && x == frame.width) - msg = ascii(191); - else if(y == frame.height && x == 1) - msg = ascii(192); - else if(y == frame.height && x == frame.width) - msg = ascii(217); - else if(x == 1 || x == frame.width) - msg = ascii(179); - else - msg = ascii(196); - if(color instanceof Array) { - if(x == 1) - theColor = color[0]; - else if(x % sectionLength == 0 && x < frame.width) - theColor = color[x / sectionLength]; - else if(x == frame.width) - theColor = color[color.length - 1]; - } - frame.putmsg(msg, theColor); - } - } -} - -var showMsg = function(msg) { - try { - var readerFrame = new Frame(2, 5, console.screen_columns - 2, console.screen_rows - 8, BG_BLACK|WHITE, frame); - readerFrame.open(); - msgBase.open(); - var h = msgBase.get_msg_header(msg); - var b = msgBase.get_msg_body(msg); - msgBase.close(); - readerFrame.putmsg( - format( - "%-52s%s\r\n\r\n", - h.subject.substr(0, console.screen_columns - 30), - system.timestr(h.when_written_time) - ), - getColor(ini.titleColor) - ); - readerFrame.putmsg(word_wrap(b, console.screen_columns - 2), getColor(ini.textColor)); - readerFrame.scrollTo(0, 0); - var scroller = new ScrollBar(readerFrame, { autohide : true }); - scroller.open(); - scroller.cycle(); - } catch(err) { - log(LOG_ERR, err); - return false; - } - while(!js.terminated) { - if(frame.cycle()) { - scroller.cycle(); - console.gotoxy(console.screen_columns, console.screen_rows); - } - var userInput = console.inkey(K_NONE, 5); - if(userInput.toUpperCase() == "Q" || ascii(userInput) == 27) - break; - else if(userInput == KEY_UP && readerFrame.data_height > readerFrame.height) - readerFrame.scroll(0, -1); - else if(userInput == KEY_DOWN && readerFrame.data_height > readerFrame.height) - readerFrame.scroll(0, 1); - } - readerFrame.close(); - readerFrame.delete(); - return true; -} - -var init = function() { - try { - var f = new File(js.exec_dir + "bullshit.ini"); - f.open("r"); - ini = f.iniGetObject(); - f.close(); - ini.borderColor = ini.borderColor.toUpperCase().split(","); - if(ini.borderColor.length > 1) { - for(var b = 0; b < ini.borderColor.length; b++) - ini.borderColor[b] = getColor(ini.borderColor[b]); - } else { - ini.borderColor = getColor(ini.borderColor[0]); - } - ini.lightbarForeground = getColor(ini.lightbarForeground); - ini.lightbarBackground = getColor(ini.lightbarBackground); - - frame = new Frame(1, 1, console.screen_columns, console.screen_rows, BG_BLACK|WHITE); - titleFrame = new Frame(1, 1, console.screen_columns, 3, BG_BLACK|WHITE, frame); - listFrame = new Frame(1, 4, console.screen_columns, console.screen_rows - 6, BG_BLACK|WHITE, frame); - listTreeFrame = new Frame(2, 6, console.screen_columns - 2, console.screen_rows - 9, BG_BLACK|WHITE, listFrame); - footerFrame = new Frame(1, console.screen_rows - 2, console.screen_columns, 3, BG_BLACK|WHITE, frame); - drawFrameBorder(titleFrame, ini.borderColor); - drawFrameBorder(listFrame, ini.borderColor); - drawFrameBorder(footerFrame, ini.borderColor); - tree = new Tree(listTreeFrame); - tree.colors.lfg = ini.lightbarForeground; - tree.colors.lbg = ini.lightbarBackground; - - var titleLen = console.screen_columns - 29; - msgBase = new MsgBase(ini.messageBase); - msgBase.open(); - for(var m = msgBase.last_msg; m >= msgBase.first_msg; m = m - 1) { - try { - var h = msgBase.get_msg_header(m); - if(h === null) - throw "Header is null"; - tree.addItem( - format( - "%-" + titleLen + "s%s", - h.subject.substr(0, console.screen_columns - 29), - system.timestr(h.when_written_time) - ), - showMsg, - m - ); - } catch(err) { - continue; - } - } - msgBase.close(); - - titleFrame.gotoxy(3, 2); - titleFrame.putmsg("Bulletins", getColor(ini.titleColor)); - titleFrame.gotoxy(console.screen_columns - 25, 2); - titleFrame.putmsg("bullshit v2 by echicken", DARKGRAY); - listFrame.gotoxy(3, 2); - listFrame.putmsg(format("%-" + titleLen + "s%s", "Title", "Date"), getColor(ini.headingColor)); - footerFrame.gotoxy(3, 2); - footerFrame.putmsg("[ESC] or Q to quit, Up/Down arrows to scroll", getColor(ini.footerColor)); - treeScroll = new ScrollBar(tree); - frame.open(); - tree.open(); - } catch(err) { - log(LOG_ERR, err); - return false; - } - return true; -} - -var main = function() { - while(!js.terminated) { - var userInput = console.inkey(K_NONE, 5); - if(userInput.toUpperCase() == "Q" || ascii(userInput) == 27) - break; - tree.getcmd(userInput); - if(frame.cycle()) { - treeScroll.cycle(); - console.gotoxy(console.screen_columns, console.screen_rows); - } - } -} - -if(init()) { - main(); - frame.close(); -} -exit(); +load('sbbsdefs.js'); +load('frame.js'); +load('tree.js'); +load('scrollbar.js'); +load('funclib.js'); + +js.branch_limit = 0; +js.time_limit = 0; + +var settings, frame, tree, treeScroll, viewer; + +Frame.prototype.drawBorder = function(color, title) { + this.pushxy(); + var theColor = color; + if (Array.isArray(color)) { + var sectionLength = Math.round(this.width / color.length); + } + for (var y = 1; y <= this.height; y++) { + for (var x = 1; x <= this.width; x++) { + if (x > 1 && x < this.width && y > 1 && y < this.height) continue; + var msg; + this.gotoxy(x, y); + if (y === 1 && x === 1) { + msg = ascii(218); + } else if (y === 1 && x === this.width) { + msg = ascii(191); + } else if (y === this.height && x === 1) { + msg = ascii(192); + } else if (y === this.height && x === this.width) { + msg = ascii(217); + } else if (x === 1 || x === this.width) { + msg = ascii(179); + } else { + msg = ascii(196); + } + if (Array.isArray(color)) { + if (x === 1) { + theColor = color[0]; + } else if (x % sectionLength === 0 && x < this.width) { + theColor = color[x / sectionLength]; + } else if (x === this.width) { + theColor = color[color.length - 1]; + } + } + this.putmsg(msg, theColor); + } + } + if (typeof title === 'object') { + this.gotoxy(title.x, title.y); + this.attr = title.attr; + this.putmsg(ascii(180) + title.text + ascii(195)); + } + this.popxy(); +} + +var Viewer = function (item) { + + var frames = { + top : null, + title : null, + content : null + }; + + frames.top = new Frame( + frame.x, + frame.y + 3, + frame.width, + frame.height - 6, + WHITE, + frame + ); + frames.top.drawBorder(settings.colors.border); + + frames.title = new Frame( + frames.top.x + 1, + frames.top.y + 1, + frames.top.width - 2, + 1, + settings.colors.title, + frames.top + ); + + frames.content = new Frame( + frames.top.x + 1, + frames.title.y + frames.title.height + 1, + frames.top.width - 2, + frames.top.height - frames.title.height - 3, + settings.colors.text, + frames.top + ); + + if (typeof item === 'number') { + + var msgBase = new MsgBase(settings.messageBase); + msgBase.open(); + var header = msgBase.get_msg_header(item); + var body = msgBase.get_msg_body(item); + msgBase.close(); + + frames.title.putmsg( + format( + '%-' + (frame.width - 29) + 's%s', + header.subject.substr(0, frame.width - 30), + system.timestr(header.when_written_time) + ), + settings.colors.title + ); + frames.content.putmsg(word_wrap(body, frames.content.width)); + + } else { + + frames.title.putmsg( + format( + '%-' + (frame.width - 29) + 's%s', + item.substr(0, frame.width - 30), + system.timestr(file_date(settings.files[item])) + ), + settings.colors.title + ); + + frames.content.x = frames.top.x; + frames.content.width = frames.top.width; + + try { + frames.content.load(settings.files[item]); + } catch (err) { + log(LOG_ERR, err); + } + + frames.content.width = frames.top.width - 2; + frames.content.x = frames.top.x + 1; + + } + + frames.content.scrollTo(0, 0); + frames.content.h_scroll = true; + + var scrollbar = new ScrollBar(frames.content); + frames.top.open(); + + this.getcmd = function (cmd) { + + var ret = true; + switch (cmd.toUpperCase()) { + case '\x1B': + case 'Q': + ret = false; + frames.top.close(); + break; + case KEY_UP: + if (frames.content.data_height > frames.content.height && + frames.content.offset.y >= 1 + ) { + frames.content.scroll(0, -1); + } + break; + case KEY_DOWN: + if (frames.content.data_height > frames.content.height && + frames.content.data_height - frames.content.offset.y > + frames.content.height + ) { + frames.content.scroll(0, 1); + } + break; + case KEY_LEFT: + if (frames.content.data_width > frames.content.width && + frames.content.offset.x >= 1 + ) { + frames.content.scroll(-1, 0); + } + break; + case KEY_RIGHT: + if (frames.content.data_width > frames.content.width && + frames.content.data_width - frames.content.offset.x > + frames.content.width + ) { + frames.content.scroll(1, 0); + } + break; + default: + break; + } + + return ret; + + } + + this.cycle = function () { + scrollbar.cycle(); + } + +} + +function loadSettings() { + + var f = new File(js.exec_dir + 'bullshit.ini'); + if (!f.open('r')) throw 'Failed to open bullshit.ini.'; + var settings = f.iniGetObject(); + settings.colors = f.iniGetObject('colors'); + settings.files = f.iniGetObject('files'); + f.close(); + + Object.keys(settings.colors).forEach( + function (k) { + settings.colors[k] = settings.colors[k].toUpperCase().split(','); + if (settings.colors[k].length > 1) { + settings.colors[k].forEach( + function (e, i, a) { a[i] = getColor(e); } + ); + } else { + settings.colors[k] = getColor(settings.colors[k][0]); + } + } + ); + + return settings; + +} + +function loadList() { + + Object.keys(settings.files).forEach( + function (key) { + if (!file_exists(settings.files[key])) return; + tree.addItem( + format ( + '%-' + (frame.width - 29) + 's%s', + key, system.timestr(file_date(settings.files[key])) + ), + key + ); + } + ); + + var msgBase = new MsgBase(settings.messageBase); + msgBase.open(); + var shown = 0; + for (var m = msgBase.last_msg; m >= msgBase.first_msg; m = m - 1) { + try { + var h = msgBase.get_msg_header(m); + } catch (err) { + continue; + } + if (h === null) continue; + tree.addItem( + format( + '%-' + (frame.width - 29) + 's%s', + h.subject.substr(0, frame.width - 30), + system.timestr(h.when_written_time) + ), + m + ); + shown++; + if (settings.maxMessages > 0 && shown >= settings.maxMessages) break; + } + msgBase.close(); + + tree.open(); + +} + +function initDisplay() { + + frame = new Frame( + 1, + 1, + console.screen_columns, + console.screen_rows, + WHITE + ); + + var titleFrame = new Frame( + frame.x, + frame.y, + frame.width, + 3, + WHITE, + frame + ); + + var footerFrame = new Frame( + frame.x, + frame.y + frame.height - 3, + frame.width, + 3, + WHITE, + frame + ); + + var treeFrame = new Frame( + frame.x, + titleFrame.y + titleFrame.height, + frame.width, + frame.height - titleFrame.height - footerFrame.height, + WHITE, + frame + ); + + var treeSubFrame = new Frame( + treeFrame.x + 1, + treeFrame.y + 2, + treeFrame.width - 2, + treeFrame.height - 3, + WHITE, + treeFrame + ); + + titleFrame.drawBorder(settings.colors.border); + treeFrame.drawBorder(settings.colors.border); + footerFrame.drawBorder(settings.colors.border); + + titleFrame.gotoxy(3, 2); + titleFrame.putmsg('Bulletins', settings.colors.title); + titleFrame.gotoxy(frame.width - 25, 2); + titleFrame.putmsg('bullshit v3 by echicken', settings.colors.heading); + + treeFrame.gotoxy(3, 2); + treeFrame.putmsg('Title', settings.colors.heading); + treeFrame.gotoxy(treeFrame.x + treeFrame.width - 27, 2); + treeFrame.putmsg('Date', settings.colors.heading); + + footerFrame.gotoxy(3, 2); + footerFrame.putmsg( + 'Q to quit, Up/Down arrows to scroll', settings.colors.footer + ); + + tree = new Tree(treeSubFrame); + tree.colors.lfg = settings.colors.lightbarForeground; + tree.colors.lbg = settings.colors.lightbarBackground; + tree.colors.fg = settings.colors.listForeground; + + treeScroll = new ScrollBar(tree); + + frame.open(); + +} + +function init() { + settings = loadSettings(); + initDisplay(); + loadList(); +} + +function main() { + + while (!js.terminated) { + + var userInput = console.inkey(K_NONE, 5); + + if (typeof viewer !== 'undefined') { + + var ret = viewer.getcmd(userInput); + viewer.cycle(); + if (!ret) viewer = undefined; + + } else { + + if (userInput.toUpperCase() === 'Q' || userInput == '\x1B') { + break; + } else { + var ret = tree.getcmd(userInput); + treeScroll.cycle(); + if (typeof ret === 'number' || typeof ret === 'string') { + viewer = new Viewer(ret); + } + } + + } + + if (frame.cycle()) { + console.gotoxy(console.screen_columns, console.screen_rows); + } + + } + +} + +function cleanUp() { + frame.close(); +} + +try { + init(); + main(); + cleanUp(); +} catch (err) { + log(LOG_ERR, err); +} \ No newline at end of file diff --git a/xtrn/bullshit/readme.txt b/xtrn/bullshit/readme.txt index 1ccc060653..82755507f8 100644 --- a/xtrn/bullshit/readme.txt +++ b/xtrn/bullshit/readme.txt @@ -1,53 +1,152 @@ -Bullshit 2.0 --=-=-=-=-=-= +Bullshit 3.0 by echicken -at- bbs.electronicchicken.com -Bullshit is a bulletin listing/reading module for Synchronet BBS 3.16+. It -uses a sysops-only message base on your BBS as a storage back-end. Adding -new bulletins to your system becomes as easy as posting a message. +Contents + 1) About + 2) Setup + 3) Customization + 4) Bullshit for the web + 5) Support -Installation: --=-=-=-=-=-=- -Launch SCFG (BBS->Configure in the Synchronet Control Panel on Windows.) +1) About -In 'Message Areas', select your local message group, and create a new sub with -the following details: + Bullshit is a lightbar bulletin lister/reader for Synchronet BBS 3.16+. + A message sub-board is used as a storage back-end, so that you can add a + new bulletin to the list just by posting a message. You can also include + .ANS or .TXT files - such as door game score files - as pinned items at the + top of the list. -Long Name Bulletins -Short Name Bulletins -QWK Name BULLSHIT -Internal Code BULLSHIT -Access Requirements LEVEL 90 -Reading Requirements LEVEL 90 -Posting Requirements LEVEL 90 -In the "Toggle Options" for the sub, ensure that "Default on for new scan", -"Forced on for new scan", and "Default on for your scan" are set to 'No'. +2) Setup -(You can set the Access, Reading, and Posting requirements to any ARS value -that you want. Ideally, only the Sysop should be able to see or post to this -sub, and Bullshit will be the interface by which users view messages here.) + 2.1) Create a message area -Return to the main menu of SCFG, go to 'External Programs', then to -'Online Programs (Doors)'. Select whatever externals section you want to -place Bullshit in ('Main' might be a good choice) and then add a new item -with the following details: + Launch SCFG (BBS->Configure in the Synchronet Control Panel on Windows.) -Name Bullshit -Internal Code BULLSHIT -Start-up Directory /sbbs/xtrn/bullshit -Command Line ?bullshit.js -Multiple Concurrent Users Yes + In 'Message Areas', select your local message group, and create a new + sub with the following details: -If you want Bullshit to run during your logon process, set the following: + Long Name Bulletins + Short Name Bulletins + QWK Name BULLSHIT + Internal Code BULLSHIT + Access Requirements LEVEL 90 + Reading Requirements LEVEL 90 + Posting Requirements LEVEL 90 -Execute on Event logon + Toggle Options... -Next you can edit 'bullshit.ini' to your liking. It contains some options for -colors and such. + Default on for new scan No + Forced on for new scan No + Default on for your scan No -Now go ahead and start posting messages in the Bulletins sub-board that you -created. The subject line of each message will appear as the bulletin title, -and the message body will be the text of the bulletin. \ No newline at end of file + Note: You can name this message area whatever you want, and you can use + an existing message area if you wish. Ideally only the sysop will be + able to read or post to this area, and it won't be included in the new + message scan. + + + 2.2) Create an External Program entry + + Still in SCFG, return to the main menu, select 'External Programs', + then 'Online Programs (Doors)', choose the section you wish to add + Bullshit to, then create a new entry with the following details: + + Name Bullshit + Internal Code BULLSHIT + Start-up Directory /sbbs/xtrn/bullshit + Command Line ?bullshit.js + Multiple Concurrent Users Yes + + If you want Bullshit to run during your logon process, set the + following: + + Execute on Event logon + + All other options can be left at their default settings. + + +3) Customization + + Some customization settings are available in 'bullshit.ini': + + In the root section: + + - The 'messageBase' setting specifies the internal code of the + message sub-board that Bullshit should load. + - The 'maxMessages' setting specifies how many of the most recent + messages in this area should be listed. (Use 0 for no limit.) + + + In the 'colors' section: + + - 'title' and 'text' are the colors used when viewing an item + - 'heading' controls color or the 'Title' and 'Date' column headings + - 'lightbarForeground' and 'lightbarBackground' control the color of + a highlighted item in the list + - 'listForeground' controls the color of a non-highlighted item + - 'footer' controls the color of the 'Q to quit ...' text + - 'border' can be a single color, or a comma-separated list + + The 'files' section is empty by default. Here you can add any number of + entries for files that you wish to include in the list. The key will be + used as the item's title in the list, while the value must be the path to + the file, for example: + + LORD Scores = /sbbs/xtrn/lord/score.ans + + At the moment, only files with .ANS and .TXT extensions can be loaded. If + that's a huge pain for you, let me know and I'll maybe do something about + it at some point. + + +4) Bullshit for the web + + The included '999-bullshit.xjs' file is compatible with my "new" web UI for + Synchronet (https://github.com/echicken/synchronet-web-v4). You can add it + to your site by copying it to the 'pages' subdirectory, renaming it as + needed. You could also just copy the contents of this file into another of + your pages if you wish for bulletins to show up there (000-home.xjs, for + example.) + + This will probably work with ecweb v3 as well, but I haven't bothered to + test it. + + For cosmetic and snobbish design reasons, your pinned 'files' list will not + be displayed in the web UI. You're better off creating a 'Scores' page of + some kind for this purpose. + + +5) Support + + You can contact me for support via any of the following means, in the + following order of preference: + + DOVE-Net: + + Post a message to 'echicken' in the 'Synchronet Sysops' sub-board. + Unless I'm dead or on vacation, I'll probably get back to you within a + day or so. + + + electronic chicken bbs: + + Post a message in the 'Support' sub-board of the 'Local' message group + on my BBS, bbs.electronicchicken.com + + + IRC : #synchronet on irc.synchro.net: + + I'm not always in front of a computer, so you won't always receive an + immediate response if you contact me on IRC. That said, if you stay + online and idle, I'll probably see your message and respond eventually. + + + Email: + + You can email me at echicken -at- bbs.electronicchicken.com, however I + prefer to discuss problems & provide support in a public forum in case + any information that comes up can be of benefit to somebody else in the + future. -- GitLab