Subj : Custom Scrollabe Text File Viewer
To   : All
From : Codefenix
Date : Tue Nov 05 2024 06:38 pm

As discussed in Synchronet Discussion, I wanted a viewer for text files with a scrollable interface.

This is the one that I came up with. Some parts I lifted from other modules to try to understand how frames and scrollbars work. It works, but it's far from perfect. I plan to use it in conjunction with some other mods that I tinker with (news readers, inter-bbs one-liner history, etc) as well as general text files.

Here's a demo of me using it in my modified General Text Files section:
https://conchaos.synchro.net/img/viewfile_demo.gif

It uses a frame object to display the text, but I'm starting to think that's not the best idea. Some files take a long time to load, and files no larger than 117 KB can lead to "out of memory" errors. Getting the impression frames weren't meant for "large" objects, so maybe there's a better way.

Anyone who wants to try it is more than welcome. Just be aware it may not give optimal results for now.

// viewfile.js ============================================= start //

load("sbbsdefs.js");
load("frame.js");
load("scrollbar.js");

const OPTIONS = " " + ascii(24) + " / " + ascii(25) +
               " / pg-up / pg-dn / home / end / q: quit";

function init_display() {
   const w = console.screen_columns;
   const h = console.screen_rows;
   const f = { top: new Frame(1, 1, w, h, BG_BLACK|LIGHTGRAY) };
   f.topbar = new Frame(1, 1, w, 1, BG_LIGHTGRAY|BLACK, f.top);
   f.output = new Frame(1, 2, w, h - 2, BG_BLACK|LIGHTGRAY, f.top);
   f.bottombar = new Frame(1, h, w, 1, BG_LIGHTGRAY|BLACK, f.top);
   f.output_scroll = new ScrollBar(f.output, { autohide: true });
   f.output.word_wrap = true;
   f.bottombar.putmsg(OPTIONS);
   f.top.open();
   return f;
}

function main(file_name, file_title, scroll_to_top) {
   var title = file_title ? file_title : file_getname(file_name);
   var exit_viewer = false;
   var key_pressed;
   const frames = init_display();
   if (file_exists(file_name)) {
       log(LOG_INFO, "Loading " + title);
       frames.topbar.putmsg("Loading " + title.substr(0, 65) + "...");
       frames.top.cycle();
       //frames.output.load(file_name); /* Issues with frame load():
                                      // Seems slow; eg: 4 secs to load 49 KB.
                                      // "out of memory" error loading 219 KB.
                                      // "out of memory" error loading 117 KB.
                                      // Not all extension types supported.

       var txt = new File(file_name); // Trying this as an alternative..
       if (txt.open("r")) {           // ... but still slow. :(
           frames.output.putmsg(strip_ansi(txt.read()).replace(/\f/g, ""));
           txt.close();
       }

       if (scroll_to_top) {
           frames.output.scrollTo(0, 0);
       }
       frames.output_scroll.cycle();
       log(LOG_INFO, "Done loading: " + title);
       frames.top.cycle();
       frames.topbar.clear();
       frames.topbar.putmsg("Viewing: " + title.substr(0, 70));
       frames.top.cycle();
       frames.output_scroll.cycle();
       while (!js.terminated && !exit_viewer) {
           frames.output_scroll.cycle();
           key_pressed = console.inkey(K_NONE, 5).toUpperCase();
           if (key_pressed == KEY_UP && frames.output.offset.y > 0) {
               frames.output.scroll(0, -1);
           } else if (key_pressed == KEY_DOWN && (frames.output.offset.y +
                      frames.output.height) < frames.output.data_height) {
               frames.output.scroll(0, 1);
           } else if (key_pressed == KEY_PAGEUP &&
                      frames.output.offset.y > 0 ) {
               frames.output.scroll(0, -1 * frames.output.height);
           } else if (key_pressed == KEY_PAGEDN && (frames.output.offset.y +
                      frames.output.height) < frames.output.data_height) {
               frames.output.scroll(0, frames.output.height);
           } else if (key_pressed == KEY_HOME) {
               frames.output.scrollTo(0, 0);
           } else if (key_pressed == KEY_END) {
               frames.output.scrollTo(0, frames.output.data_height -
                                         frames.output.height - 1);
           } else if (key_pressed == "Q") {
               exit_viewer = true;
           }
           frames.output_scroll.cycle();
           frames.top.cycle();
       }
       frames.top.close();
       print("\x01q\x01l\x01n");
   } else {
       log(LOG_ERROR, "File not found: " + file_name);
   }
}

// 1: file path (string)
// 2: title (string)
// 3: start from top (boolean; default is false)
main(argv[0], argv[1], argv[2]);

// viewfile.js ============================================= end //

|15 � � � codefenix � � � ConstructiveChaos BBS � � � � �
|08 � � � (https/telnet/ssh)://conchaos.synchro.net � � �
|07

...A fool must now and then be right by chance.
---
� Synchronet � -=[ ConstructiveChaos BBS | conchaos.synchro.net ]=-