diff --git a/xtrn/DDAreaChoosers/DDFileAreaChooser.cfg b/xtrn/DDAreaChoosers/DDFileAreaChooser.cfg index 206bf56598396128d2339969efeded52975b9836..00a7aaeaecaf130710d50f44f3c1e0bd3ea8dec8 100644 --- a/xtrn/DDAreaChoosers/DDFileAreaChooser.cfg +++ b/xtrn/DDAreaChoosers/DDFileAreaChooser.cfg @@ -1,5 +1,7 @@ [BEHAVIOR] useLightbarInterface=true +areaChooserHdrFilenameBase=fileAreaChgHeader +areaChooserHdrMaxLines=5 [COLORS] ; Area number diff --git a/xtrn/DDAreaChoosers/DDFileAreaChooser.js b/xtrn/DDAreaChoosers/DDFileAreaChooser.js index 9ab6ebf00aa07cf36f0564647036ea51b97d2f0e..63ee3f94496754d9e51147501661b9eb58edf8a5 100644 --- a/xtrn/DDAreaChoosers/DDFileAreaChooser.js +++ b/xtrn/DDAreaChoosers/DDFileAreaChooser.js @@ -80,8 +80,8 @@ if (system.version_num < 31400) } // Version & date variables -var DD_FILE_AREA_CHOOSER_VERSION = "1.09"; -var DD_FILE_AREA_CHOOSER_VER_DATE = "2016-01-17"; +var DD_FILE_AREA_CHOOSER_VERSION = "1.10 Beta 1"; +var DD_FILE_AREA_CHOOSER_VER_DATE = "2016-02-14"; // Keyboard input key codes var CTRL_M = "\x0d"; @@ -97,6 +97,14 @@ var KEY_PAGE_DOWN = "\1PgDn"; var UP_ARROW = ascii(24); var DOWN_ARROW = ascii(25); +// Determine the script's startup directory. +// This code is a trick that was created by Deuce, suggested by Rob Swindell +// as a way to detect which directory the script was executed in. I've +// shortened the code a little. +var gStartupPath = '.'; +try { throw dig.dist(dist); } catch(e) { gStartupPath = e.fileName; } +gStartupPath = backslash(gStartupPath.replace(/[\/\\][^\/\\]*$/,'')); + // 1st command-line argument: Whether or not to choose a file library first (if // false, then only choose a directory within the user's current library). This // can be true or false. @@ -161,6 +169,10 @@ function DDFileAreaChooser() this.areaNumLen = 4; this.descFieldLen = 67; // Description field length + // Filename base of a header to display above the area list + this.areaChooserHdrFilenameBase = "fileAreaChgHeader"; + this.areaChooserHdrMaxLines = 5; + // Set the function pointers for the object this.ReadConfigFile = DDFileAreaChooser_ReadConfigFile; this.SelectFileArea = DDFileAreaChooser_selectFileArea; @@ -183,9 +195,10 @@ function DDFileAreaChooser() this.ShowHelpScreen = DDFileAreaChooser_showHelpScreen; // Misc. functions this.NumFilesInDir = DDFileAreaChooser_NumFilesInDir; - // Function to build the directory printf information for a file lib this.BuildFileDirPrintfInfoForLib = DDFileAreaChooser_buildFileDirPrintfInfoForLib; + // Function to display the header above the area list + this.DisplayAreaChgHdr = DDFileAreaChooser_DisplayAreaChgHdr; // Read the settings from the config file. this.ReadConfigFile(); @@ -268,6 +281,10 @@ function DDFileAreaChooser() // created on the fly the first time the user lists directories for // a file library. this.fileDirListPrintfInfo = new Array(); + + // areaChangeHdrLines is an array of text lines to use as a header to display + // above the message area changer lists. + this.areaChangeHdrLines = loadTextFileIntoArray(this.areaChooserHdrFilenameBase, this.areaChooserHdrMaxLines); } // For the DDFileAreaChooser class: Lets the user choose a file area. @@ -316,6 +333,9 @@ function DDFileAreaChooser_selectFileArea_Traditional(pChooseLib) bbs.command_str = ""; console.clear("\1n"); + this.DisplayAreaChgHdr(1); + if (this.areaChangeHdrLines.length > 0) + console.crlf(); this.ListFileLibs(); console.print("\1n\1b\1h� \1n\1cWhich, \1hQ\1n\1cuit, or [\1h" + +(bbs.curlib+1) + "\1n\1c]:\1h "); // Accept Q (quit) or a file library number @@ -352,47 +372,50 @@ function DDFileAreaChooser_selectFileArea_Traditional(pChooseLib) // Return value: Boolean - Whether or not the user chose a file area. function DDFileAreaChooser_selectDirWithinFileLib_Traditional(pLibNumber, pSelectedDir) { - var userChoseAnArea = false; + var userChoseAnArea = false; - // If the file library number is valid, then - // set it and let the user choose a file directory - // within the library. - if (pLibNumber > 0) - { - // Ensure that the file directory printf information is created for - // this file library. - this.BuildFileDirPrintfInfoForLib(pLibNumber-1); + // If the file library number is valid, then + // set it and let the user choose a file directory + // within the library. + if (pLibNumber > 0) + { + // Ensure that the file directory printf information is created for + // this file library. + this.BuildFileDirPrintfInfoForLib(pLibNumber-1); - // Set the default directory #: The current directory, or if the - // user chose a different file library, then this should be set - // to the first directory. - var defaultDir = bbs.curdir + 1; - if (pLibNumber-1 != bbs.curlib) - defaultDir = 1; + // Set the default directory #: The current directory, or if the + // user chose a different file library, then this should be set + // to the first directory. + var defaultDir = bbs.curdir + 1; + if (pLibNumber-1 != bbs.curlib) + defaultDir = 1; - console.clear("\1n"); - this.ListDirsInFileLib(pLibNumber - 1, defaultDir - 1); - console.print("\1n\1b\1h� \1n\1cWhich, \1hQ\1n\1cuit, or [\1h" + defaultDir + - "\1n\1c]: \1h"); - // Accept Q (quit) or a file directory number - var selectedDir = console.getkeys("Q", file_area.lib_list[pLibNumber - 1].dir_list.length); - - // If the user just pressed enter (selectedDir would be blank), - // default the selected directory. - if (selectedDir.toString() == "") - selectedDir = defaultDir; - - // If the user chose a directory, then set bbs.curlib & - // bbs.curdir and quit the file library loop. - if ((pLibNumber.toString() != "Q") && (selectedDir > 0)) - { - bbs.curlib = pLibNumber - 1; - bbs.curdir = selectedDir - 1; - userChoseAnArea = true; - } - } + console.clear("\1n"); + this.DisplayAreaChgHdr(1); + if (this.areaChangeHdrLines.length > 0) + console.crlf(); + this.ListDirsInFileLib(pLibNumber - 1, defaultDir - 1); + console.print("\1n\1b\1h� \1n\1cWhich, \1hQ\1n\1cuit, or [\1h" + defaultDir + + "\1n\1c]: \1h"); + // Accept Q (quit) or a file directory number + var selectedDir = console.getkeys("Q", file_area.lib_list[pLibNumber - 1].dir_list.length); + + // If the user just pressed enter (selectedDir would be blank), + // default the selected directory. + if (selectedDir.toString() == "") + selectedDir = defaultDir; + + // If the user chose a directory, then set bbs.curlib & + // bbs.curdir and quit the file library loop. + if ((pLibNumber.toString() != "Q") && (selectedDir > 0)) + { + bbs.curlib = pLibNumber - 1; + bbs.curdir = selectedDir - 1; + userChoseAnArea = true; + } + } - return userChoseAnArea; + return userChoseAnArea; } // For the DDFileAreaChooser class: Traditional user interface for listing @@ -566,7 +589,7 @@ function DDFileAreaChooser_selectFileArea_Lightbar(pChooseLib) if ((bbs.curlib != null) && (typeof(bbs.curlib) == "number")) selectedLibIndex = bbs.curlib; - var listStartRow = 2; // The row on the screen where the list will start + var listStartRow = 2+this.areaChangeHdrLines.length; // The row on the screen where the list will start var listEndRow = console.screen_rows - 1; // Row on screen where list will end var topFileLibIndex = 0; // The index of the message group at the top of the list @@ -612,14 +635,15 @@ function DDFileAreaChooser_selectFileArea_Lightbar(pChooseLib) } } - // Clear the screen, write the help line and group list header, and output + // Clear the screen, write the header, help line, and group list header, and output // a screenful of message groups. console.clear("\1n"); + this.DisplayAreaChgHdr(1); this.WriteKeyHelpLine(); var curpos = new Object(); curpos.x = 1; - curpos.y = 1; + curpos.y = 1+this.areaChangeHdrLines.length; console.gotoxy(curpos); this.WriteLibListHdrLine(numPages, pageNum); this.ListScreenfulOfFileLibs(topFileLibIndex, listStartRow, listEndRow, false, false); @@ -729,7 +753,7 @@ function DDFileAreaChooser_selectFileArea_Lightbar(pChooseLib) { // An area was not chosen, so we'll have to re-draw // the header and list of message groups. - console.gotoxy(1, 1); + console.gotoxy(1, 1+this.areaChangeHdrLines.length); this.WriteLibListHdrLine(numPages, pageNum); this.ListScreenfulOfFileLibs(topFileLibIndex, listStartRow, listEndRow, false, true); } @@ -784,6 +808,7 @@ function DDFileAreaChooser_selectFileArea_Lightbar(pChooseLib) selectedLibIndex = topIndexForLastPage; } break; + case KEY_ESC: // Quit case 'Q': // Quit continueChoosingFileArea = false; break; @@ -791,8 +816,9 @@ function DDFileAreaChooser_selectFileArea_Lightbar(pChooseLib) this.ShowHelpScreen(true, true); console.pause(); // Refresh the screen + this.DisplayAreaChgHdr(1); this.WriteKeyHelpLine(); - console.gotoxy(1, 1); + console.gotoxy(1, 1+this.areaChangeHdrLines.length); this.WriteLibListHdrLine(numPages, pageNum); this.ListScreenfulOfFileLibs(topFileLibIndex, listStartRow, listEndRow, false, true); break; @@ -876,347 +902,348 @@ function DDFileAreaChooser_selectFileArea_Lightbar(pChooseLib) // Will be -1 if none chosen. function DDFileAreaChooser_selectDirWithinFileLib_Lightbar(pLibIndex, pHighlightIndex) { - // Create the return object. - var retObj = new Object(); - retObj.fileDirChosen = false; - retObj.fileLibIndex = -1; - - var libIndex = 0; - if (typeof(pLibIndex) == "number") - libIndex = pLibIndex; - else if ((bbs.curlib != null) && (typeof(bbs.curlib) == "number")) - libIndex = bbs.curlib; - // Double-check libIndex - if (libIndex < 0) - libIndex = 0; - else if (libIndex >= file_area.lib_list.length) - libIndex = file_area.lib_list.length - 1; - - var highlightIndex = 0; - if ((pHighlightIndex != null) && (typeof(pHighlightIndex) == "number")) - highlightIndex = pHighlightIndex; - else if ((bbs.curdir != null) && (typeof(bbs.curdir) == "number") && - (bbs.curlib == pLibIndex)) - { - highlightIndex = bbs.curdir; - } - // Double-check highlightIndex - if (highlightIndex < 0) - highlightIndex = 0; - else if (highlightIndex >= file_area.lib_list[libIndex].dir_list.length) - highlightIndex = file_area.lib_list[libIndex].dir_list.length - 1; - - // If there are no sub-boards in the given message group, then show - // an error and return. - if (file_area.lib_list[libIndex].dir_list.length == 0) - { - console.clear("\1n"); - console.print("\1y\1hThere are no directories in the chosen library.\r\n\1p"); - return retObj; - } - - // Ensure that the file directory printf information is created for - // this file library. - this.BuildFileDirPrintfInfoForLib(libIndex); - - // Returns the index of the bottommost directory that can be displayed on - // the screen. - // - // Parameters: - // pTopDirIndex: The index of the topmost directory displayed on screen - // pNumItemsPerPage: The number of items per page - function getBottommostDirIndex(pTopDirIndex, pNumItemsPerPage) - { - var bottomDirIndex = pTopDirIndex + pNumItemsPerPage - 1; - // If bottomDirIndex is beyond the last index, then adjust it. - if (bottomDirIndex >= file_area.lib_list[libIndex].dir_list.length) - bottomDirIndex = file_area.lib_list[libIndex].dir_list.length - 1; - return bottomDirIndex; - } + // Create the return object. + var retObj = new Object(); + retObj.fileDirChosen = false; + retObj.fileLibIndex = -1; + var libIndex = 0; + if (typeof(pLibIndex) == "number") + libIndex = pLibIndex; + else if ((bbs.curlib != null) && (typeof(bbs.curlib) == "number")) + libIndex = bbs.curlib; + // Double-check libIndex + if (libIndex < 0) + libIndex = 0; + else if (libIndex >= file_area.lib_list.length) + libIndex = file_area.lib_list.length - 1; + + var highlightIndex = 0; + if ((pHighlightIndex != null) && (typeof(pHighlightIndex) == "number")) + highlightIndex = pHighlightIndex; + else if ((bbs.curdir != null) && (typeof(bbs.curdir) == "number") && + (bbs.curlib == pLibIndex)) + { + highlightIndex = bbs.curdir; + } + // Double-check highlightIndex + if (highlightIndex < 0) + highlightIndex = 0; + else if (highlightIndex >= file_area.lib_list[libIndex].dir_list.length) + highlightIndex = file_area.lib_list[libIndex].dir_list.length - 1; + + // If there are no sub-boards in the given message group, then show + // an error and return. + if (file_area.lib_list[libIndex].dir_list.length == 0) + { + console.clear("\1n"); + console.print("\1y\1hThere are no directories in the chosen library.\r\n\1p"); + return retObj; + } - // Figure out the index of the user's currently-selected sub-board. - var selectedDirIndex = 0; - if ((bbs.curdir != null) && (typeof(bbs.curdir) == "number")) - { - if ((bbs.curlib != null) && (typeof(bbs.curlib) == "number") && - (bbs.curlib == pLibIndex)) - { - selectedDirIndex = bbs.curdir; - } - } + // Ensure that the file directory printf information is created for + // this file library. + this.BuildFileDirPrintfInfoForLib(libIndex); - var listStartRow = 3; // The row on the screen where the list will start - var listEndRow = console.screen_rows - 1; // Row on screen where list will end - var topDirIndex = 0; // The index of the message group at the top of the list - // Figure out the index of the last message group to appear on the screen. - var numItemsPerPage = listEndRow - listStartRow + 1; - var bottomDirIndex = getBottommostDirIndex(topDirIndex, numItemsPerPage); - // Figure out how many pages are needed to list all the sub-boards. - var numPages = Math.ceil(file_area.lib_list[libIndex].dir_list.length / numItemsPerPage); - var pageNum = calcPageNum(topDirIndex, numItemsPerPage); - // Figure out the top index for the last page. - var topIndexForLastPage = (numItemsPerPage * numPages) - numItemsPerPage; - - // If the highlighted row is beyond the current screen, then - // go to the appropriate page. - if (selectedDirIndex > bottomDirIndex) - { - var nextPageTopIndex = 0; - while (selectedDirIndex > bottomDirIndex) - { - nextPageTopIndex = topDirIndex + numItemsPerPage; - if (nextPageTopIndex < file_area.lib_list[libIndex].dir_list.length) - { - // Adjust topDirIndex and bottomDirIndex, and - // refresh the list on the screen. - topDirIndex = nextPageTopIndex; - pageNum = calcPageNum(topDirIndex, numItemsPerPage); - bottomDirIndex = getBottommostDirIndex(topDirIndex, numItemsPerPage); - } - else - break; - } + // Returns the index of the bottommost directory that can be displayed on + // the screen. + // + // Parameters: + // pTopDirIndex: The index of the topmost directory displayed on screen + // pNumItemsPerPage: The number of items per page + function getBottommostDirIndex(pTopDirIndex, pNumItemsPerPage) + { + var bottomDirIndex = pTopDirIndex + pNumItemsPerPage - 1; + // If bottomDirIndex is beyond the last index, then adjust it. + if (bottomDirIndex >= file_area.lib_list[libIndex].dir_list.length) + bottomDirIndex = file_area.lib_list[libIndex].dir_list.length - 1; + return bottomDirIndex; + } - // If we didn't find the correct page for some reason, then set the - // variables to display page 1 and select the first message group. - var foundCorrectPage = - ((topDirIndex < file_area.lib_list[libIndex].dir_list.length) && - (selectedDirIndex >= topDirIndex) && (selectedDirIndex <= bottomDirIndex)); - if (!foundCorrectPage) - { - topDirIndex = 0; - pageNum = calcPageNum(topDirIndex, numItemsPerPage); - bottomDirIndex = getBottommostDirIndex(topDirIndex, numItemsPerPage); - selectedDirIndex = 0; - } - } - // Clear the screen, write the help line and group list header, and output - // a screenful of message groups. - console.clear("\1n"); - this.WriteDirListHdr1Line(libIndex, numPages, pageNum); - this.WriteKeyHelpLine(); - - var curpos = new Object(); - curpos.x = 1; - curpos.y = 2; - console.gotoxy(curpos); - printf(this.fileDirHdrPrintfStr, "Dir #", "Description", "# Files"); - this.ListScreenfulOfDirs(libIndex, topDirIndex, listStartRow, listEndRow, - false, false); - // Start of the input loop. - var highlightScrenRow = 0; // The row on the screen for the highlighted group - var userInput = ""; // Will store a keypress from the user - var continueChoosingFileDir = true; - while (continueChoosingFileDir) - { - // Highlight the currently-selected message group - highlightScrenRow = listStartRow + (selectedDirIndex - topDirIndex); - curpos.y = highlightScrenRow; - if ((highlightScrenRow > 0) && (highlightScrenRow < console.screen_rows)) - { - console.gotoxy(1, highlightScrenRow); - this.WriteFileLibDirLine(libIndex, selectedDirIndex, true); - } + // Figure out the index of the user's currently-selected sub-board. + var selectedDirIndex = 0; + if ((bbs.curdir != null) && (typeof(bbs.curdir) == "number")) + { + if ((bbs.curlib != null) && (typeof(bbs.curlib) == "number") && (bbs.curlib == pLibIndex)) + selectedDirIndex = bbs.curdir; + } - // Get a key from the user (upper-case) and take action based upon it. - userInput = getKeyWithESCChars(K_UPPER | K_NOCRLF); - switch (userInput) - { - case KEY_UP: // Move up one message group in the list - if (selectedDirIndex > 0) - { - // If the previous group index is on the previous page, then - // display the previous page. - var previousSubIndex = selectedDirIndex - 1; - if (previousSubIndex < topDirIndex) - { - // Adjust topDirIndex and bottomDirIndex, and - // refresh the list on the screen. - topDirIndex -= numItemsPerPage; - pageNum = calcPageNum(topDirIndex, numItemsPerPage); - bottomDirIndex = getBottommostDirIndex(topDirIndex, numItemsPerPage); - this.updatePageNumInHeader(pageNum, numPages, false, false); - this.ListScreenfulOfDirs(libIndex, topDirIndex, listStartRow, - listEndRow, false, true); - } - else - { - // Display the current line un-highlighted. - console.gotoxy(1, curpos.y); - this.WriteFileLibDirLine(libIndex, selectedDirIndex, false); - } - selectedDirIndex = previousSubIndex; - } - break; - case KEY_DOWN: // Move down one message group in the list - if (selectedDirIndex < file_area.lib_list[libIndex].dir_list.length - 1) - { - // If the next group index is on the next page, then display - // the next page. - var nextGrpIndex = selectedDirIndex + 1; - if (nextGrpIndex > bottomDirIndex) - { - // Adjust topDirIndex and bottomDirIndex, and - // refresh the list on the screen. - topDirIndex += numItemsPerPage; - pageNum = calcPageNum(topDirIndex, numItemsPerPage); - bottomDirIndex = getBottommostDirIndex(topDirIndex, numItemsPerPage); - this.updatePageNumInHeader(pageNum, numPages, false, false); - this.ListScreenfulOfDirs(libIndex, topDirIndex, listStartRow, - listEndRow, false, true); - } - else - { - // Display the current line un-highlighted. - console.gotoxy(1, curpos.y); - this.WriteFileLibDirLine(libIndex, selectedDirIndex, false); - } - selectedDirIndex = nextGrpIndex; - } - break; - case KEY_HOME: // Go to the top message group on the screen - if (selectedDirIndex > topDirIndex) - { - // Display the current line un-highlighted, then adjust - // selectedDirIndex. - console.gotoxy(1, curpos.y); - this.WriteFileLibDirLine(libIndex, selectedDirIndex, false); - selectedDirIndex = topDirIndex; - // Note: curpos.y is set at the start of the while loop. - } - break; - case KEY_END: // Go to the bottom message group on the screen - if (selectedDirIndex < bottomDirIndex) - { - // Display the current line un-highlighted, then adjust - // selectedDirIndex. - console.gotoxy(1, curpos.y); - this.WriteFileLibDirLine(libIndex, selectedDirIndex, false); - selectedDirIndex = bottomDirIndex; - // Note: curpos.y is set at the start of the while loop. - } - break; - case KEY_ENTER: // Select the currently-highlighted sub-board; and we're done. - continueChoosingFileDir = false; - retObj.fileDirChosen = true; - retObj.fileLibIndex = selectedDirIndex; - break; - case KEY_PAGE_DOWN: // Go to the next page - var nextPageTopIndex = topDirIndex + numItemsPerPage; - if (nextPageTopIndex < file_area.lib_list[libIndex].dir_list.length) - { - // Adjust topDirIndex and bottomDirIndex, and - // refresh the list on the screen. - topDirIndex = nextPageTopIndex; - pageNum = calcPageNum(topDirIndex, numItemsPerPage); - bottomDirIndex = getBottommostDirIndex(topDirIndex, numItemsPerPage); - this.updatePageNumInHeader(pageNum, numPages, false, false); - this.ListScreenfulOfDirs(libIndex, topDirIndex, listStartRow, - listEndRow, false, true); - selectedDirIndex = topDirIndex; - } - break; - case KEY_PAGE_UP: // Go to the previous page - var prevPageTopIndex = topDirIndex - numItemsPerPage; - if (prevPageTopIndex >= 0) - { - // Adjust topDirIndex and bottomDirIndex, and - // refresh the list on the screen. - topDirIndex = prevPageTopIndex; - pageNum = calcPageNum(topDirIndex, numItemsPerPage); - bottomDirIndex = getBottommostDirIndex(topDirIndex, numItemsPerPage); - this.updatePageNumInHeader(pageNum, numPages, false, false); - this.ListScreenfulOfDirs(libIndex, topDirIndex, listStartRow, - listEndRow, false, true); - selectedDirIndex = topDirIndex; - } - break; - case 'F': // Go to the first page - if (topDirIndex > 0) - { - topDirIndex = 0; - pageNum = calcPageNum(topDirIndex, numItemsPerPage); - bottomDirIndex = getBottommostDirIndex(topDirIndex, numItemsPerPage); - this.updatePageNumInHeader(pageNum, numPages, false, false); - this.ListScreenfulOfDirs(libIndex, topDirIndex, listStartRow, - listEndRow, false, true); - selectedDirIndex = 0; - } - break; - case 'L': // Go to the last page - if (topDirIndex < topIndexForLastPage) - { - topDirIndex = topIndexForLastPage; - pageNum = calcPageNum(topDirIndex, numItemsPerPage); - bottomDirIndex = getBottommostDirIndex(topDirIndex, numItemsPerPage); - this.updatePageNumInHeader(pageNum, numPages, false, false); - this.ListScreenfulOfDirs(libIndex, topDirIndex, listStartRow, - listEndRow, false, true); - selectedDirIndex = topIndexForLastPage; - } - break; - case 'Q': // Quit - continueChoosingFileDir = false; - break; - case '?': // Show help - this.ShowHelpScreen(true, true); - console.pause(); - // Refresh the screen - console.gotoxy(1, 1); - this.WriteDirListHdr1Line(libIndex, numPages, pageNum); - console.cleartoeol("\1n"); - this.WriteKeyHelpLine(); - console.gotoxy(1, 2); - printf(this.fileDirHdrPrintfStr, "Dir #", "Description", "# Files"); - this.ListScreenfulOfDirs(libIndex, topDirIndex, listStartRow, - listEndRow, false, true); - break; - default: - // If the user entered a numeric digit, then treat it as - // the start of the message group number. - if (userInput.match(/[0-9]/)) - { - var originalCurpos = curpos; - - // Put the user's input back in the input buffer to - // be used for getting the rest of the message number. - console.ungetstr(userInput); - // Move the cursor to the bottom of the screen and - // prompt the user for the message number. - console.gotoxy(1, console.screen_rows); - console.clearline("\1n"); - console.print("\1cDir #: \1h"); - userInput = console.getnum(file_area.lib_list[libIndex].dir_list.length); - // If the user made a selection, then set it in the - // return object and don't continue the input loop. - if (userInput > 0) - { - continueChoosingFileDir = false; - retObj.fileDirChosen = true; - retObj.fileLibIndex = userInput - 1; - } - else - { - // The user didn't enter a selection. Now we need to - // re-draw the screen due to everything being moved - // up one line. - console.gotoxy(1, 1); - this.WriteDirListHdr1Line(libIndex, numPages, pageNum); - console.cleartoeol("\1n"); - this.WriteKeyHelpLine(); - console.gotoxy(1, 2); - printf(this.fileDirHdrPrintfStr, "Dir #", "Description", "# Files"); - this.ListScreenfulOfDirs(libIndex, topDirIndex, listStartRow, - listEndRow, false, true); - } - } - break; - } - } + var listStartRow = 3+this.areaChangeHdrLines.length; // The row on the screen where the list will start + var listEndRow = console.screen_rows - 1; // Row on screen where list will end + var topDirIndex = 0; // The index of the message group at the top of the list + // Figure out the index of the last message group to appear on the screen. + var numItemsPerPage = listEndRow - listStartRow + 1; + var bottomDirIndex = getBottommostDirIndex(topDirIndex, numItemsPerPage); + // Figure out how many pages are needed to list all the sub-boards. + var numPages = Math.ceil(file_area.lib_list[libIndex].dir_list.length / numItemsPerPage); + var pageNum = calcPageNum(topDirIndex, numItemsPerPage); + // Figure out the top index for the last page. + var topIndexForLastPage = (numItemsPerPage * numPages) - numItemsPerPage; + + // If the highlighted row is beyond the current screen, then + // go to the appropriate page. + if (selectedDirIndex > bottomDirIndex) + { + var nextPageTopIndex = 0; + while (selectedDirIndex > bottomDirIndex) + { + nextPageTopIndex = topDirIndex + numItemsPerPage; + if (nextPageTopIndex < file_area.lib_list[libIndex].dir_list.length) + { + // Adjust topDirIndex and bottomDirIndex, and + // refresh the list on the screen. + topDirIndex = nextPageTopIndex; + pageNum = calcPageNum(topDirIndex, numItemsPerPage); + bottomDirIndex = getBottommostDirIndex(topDirIndex, numItemsPerPage); + } + else + break; + } - return retObj; + // If we didn't find the correct page for some reason, then set the + // variables to display page 1 and select the first message group. + var foundCorrectPage = ((topDirIndex < file_area.lib_list[libIndex].dir_list.length) && + (selectedDirIndex >= topDirIndex) && (selectedDirIndex <= bottomDirIndex)); + if (!foundCorrectPage) + { + topDirIndex = 0; + pageNum = calcPageNum(topDirIndex, numItemsPerPage); + bottomDirIndex = getBottommostDirIndex(topDirIndex, numItemsPerPage); + selectedDirIndex = 0; + } + } + + // Clear the screen, write the header, help line, and group list header, and output + // a screenful of message groups. + console.clear("\1n"); + this.DisplayAreaChgHdr(1); + if (this.areaChangeHdrLines.length > 0) + console.crlf(); + this.WriteDirListHdr1Line(libIndex, numPages, pageNum); + this.WriteKeyHelpLine(); + + var curpos = new Object(); + curpos.x = 1; + curpos.y = 2+this.areaChangeHdrLines.length; + console.gotoxy(curpos); + printf(this.fileDirHdrPrintfStr, "Dir #", "Description", "# Files"); + this.ListScreenfulOfDirs(libIndex, topDirIndex, listStartRow, listEndRow, + false, false); + // Start of the input loop. + var highlightScrenRow = 0; // The row on the screen for the highlighted group + var userInput = ""; // Will store a keypress from the user + var continueChoosingFileDir = true; + while (continueChoosingFileDir) + { + // Highlight the currently-selected message group + highlightScrenRow = listStartRow + (selectedDirIndex - topDirIndex); + curpos.y = highlightScrenRow; + if ((highlightScrenRow > 0) && (highlightScrenRow < console.screen_rows)) + { + console.gotoxy(1, highlightScrenRow); + this.WriteFileLibDirLine(libIndex, selectedDirIndex, true); + } + + // Get a key from the user (upper-case) and take action based upon it. + userInput = getKeyWithESCChars(K_UPPER | K_NOCRLF); + switch (userInput) + { + case KEY_UP: // Move up one message group in the list + if (selectedDirIndex > 0) + { + // If the previous group index is on the previous page, then + // display the previous page. + var previousSubIndex = selectedDirIndex - 1; + if (previousSubIndex < topDirIndex) + { + // Adjust topDirIndex and bottomDirIndex, and + // refresh the list on the screen. + topDirIndex -= numItemsPerPage; + pageNum = calcPageNum(topDirIndex, numItemsPerPage); + bottomDirIndex = getBottommostDirIndex(topDirIndex, numItemsPerPage); + this.updatePageNumInHeader(pageNum, numPages, false, false); + this.ListScreenfulOfDirs(libIndex, topDirIndex, listStartRow, + listEndRow, false, true); + } + else + { + // Display the current line un-highlighted. + console.gotoxy(1, curpos.y); + this.WriteFileLibDirLine(libIndex, selectedDirIndex, false); + } + selectedDirIndex = previousSubIndex; + } + break; + case KEY_DOWN: // Move down one message group in the list + if (selectedDirIndex < file_area.lib_list[libIndex].dir_list.length - 1) + { + // If the next group index is on the next page, then display + // the next page. + var nextGrpIndex = selectedDirIndex + 1; + if (nextGrpIndex > bottomDirIndex) + { + // Adjust topDirIndex and bottomDirIndex, and + // refresh the list on the screen. + topDirIndex += numItemsPerPage; + pageNum = calcPageNum(topDirIndex, numItemsPerPage); + bottomDirIndex = getBottommostDirIndex(topDirIndex, numItemsPerPage); + this.updatePageNumInHeader(pageNum, numPages, false, false); + this.ListScreenfulOfDirs(libIndex, topDirIndex, listStartRow, + listEndRow, false, true); + } + else + { + // Display the current line un-highlighted. + console.gotoxy(1, curpos.y); + this.WriteFileLibDirLine(libIndex, selectedDirIndex, false); + } + selectedDirIndex = nextGrpIndex; + } + break; + case KEY_HOME: // Go to the top message group on the screen + if (selectedDirIndex > topDirIndex) + { + // Display the current line un-highlighted, then adjust + // selectedDirIndex. + console.gotoxy(1, curpos.y); + this.WriteFileLibDirLine(libIndex, selectedDirIndex, false); + selectedDirIndex = topDirIndex; + // Note: curpos.y is set at the start of the while loop. + } + break; + case KEY_END: // Go to the bottom message group on the screen + if (selectedDirIndex < bottomDirIndex) + { + // Display the current line un-highlighted, then adjust + // selectedDirIndex. + console.gotoxy(1, curpos.y); + this.WriteFileLibDirLine(libIndex, selectedDirIndex, false); + selectedDirIndex = bottomDirIndex; + // Note: curpos.y is set at the start of the while loop. + } + break; + case KEY_ENTER: // Select the currently-highlighted sub-board; and we're done. + continueChoosingFileDir = false; + retObj.fileDirChosen = true; + retObj.fileLibIndex = selectedDirIndex; + break; + case KEY_PAGE_DOWN: // Go to the next page + var nextPageTopIndex = topDirIndex + numItemsPerPage; + if (nextPageTopIndex < file_area.lib_list[libIndex].dir_list.length) + { + // Adjust topDirIndex and bottomDirIndex, and + // refresh the list on the screen. + topDirIndex = nextPageTopIndex; + pageNum = calcPageNum(topDirIndex, numItemsPerPage); + bottomDirIndex = getBottommostDirIndex(topDirIndex, numItemsPerPage); + this.updatePageNumInHeader(pageNum, numPages, false, false); + this.ListScreenfulOfDirs(libIndex, topDirIndex, listStartRow, + listEndRow, false, true); + selectedDirIndex = topDirIndex; + } + break; + case KEY_PAGE_UP: // Go to the previous page + var prevPageTopIndex = topDirIndex - numItemsPerPage; + if (prevPageTopIndex >= 0) + { + // Adjust topDirIndex and bottomDirIndex, and + // refresh the list on the screen. + topDirIndex = prevPageTopIndex; + pageNum = calcPageNum(topDirIndex, numItemsPerPage); + bottomDirIndex = getBottommostDirIndex(topDirIndex, numItemsPerPage); + this.updatePageNumInHeader(pageNum, numPages, false, false); + this.ListScreenfulOfDirs(libIndex, topDirIndex, listStartRow, + listEndRow, false, true); + selectedDirIndex = topDirIndex; + } + break; + case 'F': // Go to the first page + if (topDirIndex > 0) + { + topDirIndex = 0; + pageNum = calcPageNum(topDirIndex, numItemsPerPage); + bottomDirIndex = getBottommostDirIndex(topDirIndex, numItemsPerPage); + this.updatePageNumInHeader(pageNum, numPages, false, false); + this.ListScreenfulOfDirs(libIndex, topDirIndex, listStartRow, + listEndRow, false, true); + selectedDirIndex = 0; + } + break; + case 'L': // Go to the last page + if (topDirIndex < topIndexForLastPage) + { + topDirIndex = topIndexForLastPage; + pageNum = calcPageNum(topDirIndex, numItemsPerPage); + bottomDirIndex = getBottommostDirIndex(topDirIndex, numItemsPerPage); + this.updatePageNumInHeader(pageNum, numPages, false, false); + this.ListScreenfulOfDirs(libIndex, topDirIndex, listStartRow, + listEndRow, false, true); + selectedDirIndex = topIndexForLastPage; + } + break; + case KEY_ESC: // Quit + case 'Q': // Quit + continueChoosingFileDir = false; + break; + case '?': // Show help + this.ShowHelpScreen(true, true); + console.pause(); + // Refresh the screen + this.DisplayAreaChgHdr(1); + console.gotoxy(1, 1+this.areaChangeHdrLines.length); + this.WriteDirListHdr1Line(libIndex, numPages, pageNum); + console.cleartoeol("\1n"); + this.WriteKeyHelpLine(); + console.gotoxy(1, 2+this.areaChangeHdrLines.length); + printf(this.fileDirHdrPrintfStr, "Dir #", "Description", "# Files"); + this.ListScreenfulOfDirs(libIndex, topDirIndex, listStartRow, + listEndRow, false, true); + break; + default: + // If the user entered a numeric digit, then treat it as + // the start of the message group number. + if (userInput.match(/[0-9]/)) + { + var originalCurpos = curpos; + + // Put the user's input back in the input buffer to + // be used for getting the rest of the message number. + console.ungetstr(userInput); + // Move the cursor to the bottom of the screen and + // prompt the user for the message number. + console.gotoxy(1, console.screen_rows); + console.clearline("\1n"); + console.print("\1cDir #: \1h"); + userInput = console.getnum(file_area.lib_list[libIndex].dir_list.length); + // If the user made a selection, then set it in the + // return object and don't continue the input loop. + if (userInput > 0) + { + continueChoosingFileDir = false; + retObj.fileDirChosen = true; + retObj.fileLibIndex = userInput - 1; + } + else + { + // The user didn't enter a selection. Now we need to + // re-draw the screen due to everything being moved + // up one line. + console.gotoxy(1, 1); + this.WriteDirListHdr1Line(libIndex, numPages, pageNum); + console.cleartoeol("\1n"); + this.WriteKeyHelpLine(); + console.gotoxy(1, 2); + printf(this.fileDirHdrPrintfStr, "Dir #", "Description", "# Files"); + this.ListScreenfulOfDirs(libIndex, topDirIndex, listStartRow, + listEndRow, false, true); + } + } + break; + } + } + + return retObj; } // Displays a screenful of file libraries (for the lightbar interface). @@ -1363,12 +1390,12 @@ function DDFileAreaChooser_updatePageNumInHeader(pPageNum, pNumPages, pFileLib, if (pFileLib) { - console.gotoxy(30, 1); + console.gotoxy(30, 1+this.areaChangeHdrLines.length); console.print("\1n" + this.colors.header + pPageNum + " of " + pNumPages + ") "); } else { - console.gotoxy(67, 1); + console.gotoxy(67, 1+this.areaChangeHdrLines.length); console.print("\1n" + this.colors.fileAreaHdr + pPageNum + " of " + pNumPages + ") "); } @@ -1464,82 +1491,82 @@ function DDFileAreaChooser_writeKeyHelpLine() // For the DDFileAreaChooser class: Reads the configuration file. function DDFileAreaChooser_ReadConfigFile() { - // Determine the script's startup directory. - // This code is a trick that was created by Deuce, suggested by Rob Swindell - // as a way to detect which directory the script was executed in. I've - // shortened the code a little. - var startup_path = '.'; - try { throw dig.dist(dist); } catch(e) { startup_path = e.fileName; } - startup_path = backslash(startup_path.replace(/[\/\\][^\/\\]*$/,'')); - - // Open the configuration file - var cfgFile = new File(startup_path + "DDFileAreaChooser.cfg"); - if (cfgFile.open("r")) - { - var settingsMode = "behavior"; - var fileLine = null; // A line read from the file - var equalsPos = 0; // Position of a = in the line - var commentPos = 0; // Position of the start of a comment - var setting = null; // A setting name (string) - var settingUpper = null; // Upper-case setting name - var value = null; // A value for a setting (string) - while (!cfgFile.eof) - { - // Read the next line from the config file. - fileLine = cfgFile.readln(2048); + // Open the configuration file + var cfgFile = new File(gStartupPath + "DDFileAreaChooser.cfg"); + if (cfgFile.open("r")) + { + var settingsMode = "behavior"; + var fileLine = null; // A line read from the file + var equalsPos = 0; // Position of a = in the line + var commentPos = 0; // Position of the start of a comment + var setting = null; // A setting name (string) + var settingUpper = null; // Upper-case setting name + var value = null; // A value for a setting (string) + while (!cfgFile.eof) + { + // Read the next line from the config file. + fileLine = cfgFile.readln(2048); - // fileLine should be a string, but I've seen some cases - // where it isn't, so check its type. - if (typeof(fileLine) != "string") - continue; + // fileLine should be a string, but I've seen some cases + // where it isn't, so check its type. + if (typeof(fileLine) != "string") + continue; - // If the line starts with with a semicolon (the comment - // character) or is blank, then skip it. - if ((fileLine.substr(0, 1) == ";") || (fileLine.length == 0)) - continue; + // If the line starts with with a semicolon (the comment + // character) or is blank, then skip it. + if ((fileLine.substr(0, 1) == ";") || (fileLine.length == 0)) + continue; - // If in the "behavior" section, then set the behavior-related variables. - if (fileLine.toUpperCase() == "[BEHAVIOR]") - { - settingsMode = "behavior"; - continue; - } - else if (fileLine.toUpperCase() == "[COLORS]") - { - settingsMode = "colors"; - continue; - } + // If in the "behavior" section, then set the behavior-related variables. + if (fileLine.toUpperCase() == "[BEHAVIOR]") + { + settingsMode = "behavior"; + continue; + } + else if (fileLine.toUpperCase() == "[COLORS]") + { + settingsMode = "colors"; + continue; + } - // If the line has a semicolon anywhere in it, then remove - // everything from the semicolon onward. - commentPos = fileLine.indexOf(";"); - if (commentPos > -1) - fileLine = fileLine.substr(0, commentPos); - - // Look for an equals sign, and if found, separate the line - // into the setting name (before the =) and the value (after the - // equals sign). - equalsPos = fileLine.indexOf("="); - if (equalsPos > 0) - { - // Read the setting & value, and trim leading & trailing spaces. - setting = trimSpaces(fileLine.substr(0, equalsPos), true, false, true); - settingUpper = setting.toUpperCase(); - value = trimSpaces(fileLine.substr(equalsPos+1), true, false, true); - - if (settingsMode == "behavior") - { - // Set the appropriate value in the settings object. - if (settingUpper == "USELIGHTBARINTERFACE") - this.useLightbarInterface = (value.toUpperCase() == "TRUE"); - } - else if (settingsMode == "colors") - this.colors[setting] = value; - } - } - - cfgFile.close(); - } + // If the line has a semicolon anywhere in it, then remove + // everything from the semicolon onward. + commentPos = fileLine.indexOf(";"); + if (commentPos > -1) + fileLine = fileLine.substr(0, commentPos); + + // Look for an equals sign, and if found, separate the line + // into the setting name (before the =) and the value (after the + // equals sign). + equalsPos = fileLine.indexOf("="); + if (equalsPos > 0) + { + // Read the setting & value, and trim leading & trailing spaces. + setting = trimSpaces(fileLine.substr(0, equalsPos), true, false, true); + settingUpper = setting.toUpperCase(); + value = trimSpaces(fileLine.substr(equalsPos+1), true, false, true); + + if (settingsMode == "behavior") + { + // Set the appropriate value in the settings object. + if (settingUpper == "USELIGHTBARINTERFACE") + this.useLightbarInterface = (value.toUpperCase() == "TRUE"); + else if (settingUpper == "AREACHOOSERHDRFILENAMEBASE") + this.areaChooserHdrFilenameBase = value; + else if (settingUpper == "AREACHOOSERHDRMAXLINES") + { + var maxNumLines = +value; + if (maxNumLines > 0) + this.areaChooserHdrMaxLines = maxNumLines; + } + } + else if (settingsMode == "colors") + this.colors[setting] = value; + } + } + + cfgFile.close(); + } } // Misc. functions @@ -1684,6 +1711,64 @@ function DDFileAreaChooser_buildFileDirPrintfInfoForLib(pLibIndex) } } +// For the DDFileAreaChooser class: Displays the area chooser header +// +// Parameters: +// pStartScreenRow: The row on the screen at which to start displaying the +// header information. Will be used if the user's terminal +// supports ANSI. +// pClearRowsFirst: Optional boolean - Whether or not to clear the rows first. +// Defaults to true. Only valid if the user's terminal supports +// ANSI. +function DDFileAreaChooser_DisplayAreaChgHdr(pStartScreenRow, pClearRowsFirst) +{ + if (this.areaChangeHdrLines == null) + return; + if (this.areaChangeHdrLines.length == 0) + return; + + // If the user's terminal supports ANSI and pStartScreenRow is a number, then + // we can move the cursor and display the header where specified. + if (console.term_supports(USER_ANSI) && (typeof(pStartScreenRow) == "number")) + { + // If specified to clear the rows first, then do so. + var screenX = 1; + var screenY = pStartScreenRow; + var clearRowsFirst = (typeof(pClearRowsFirst) == "boolean" ? pClearRowsFirst : true); + if (clearRowsFirst) + { + console.print("\1n"); + for (var hdrFileIdx = 0; hdrFileIdx < this.areaChangeHdrLines.length; ++hdrFileIdx) + { + console.gotoxy(screenX, screenY++); + console.cleartoeol(); + } + } + // Display the header starting on the first column and the given screen row. + screenX = 1; + screenY = pStartScreenRow; + for (var hdrFileIdx = 0; hdrFileIdx < this.areaChangeHdrLines.length; ++hdrFileIdx) + { + console.gotoxy(screenX, screenY++); + console.print(this.areaChangeHdrLines[hdrFileIdx]); + //console.putmsg(this.areaChangeHdrLines[hdrFileIdx]); + //console.cleartoeol("\1n"); // Shouldn't do this, as it resets color attributes + } + } + else + { + // The user's terminal doesn't support ANSI or pStartScreenRow is not a + // number - So just output the header lines. + for (var hdrFileIdx = 0; hdrFileIdx < this.areaChangeHdrLines.length; ++hdrFileIdx) + { + console.print(this.areaChangeHdrLines[hdrFileIdx]); + //console.putmsg(this.areaChangeHdrLines[hdrFileIdx]); + //console.cleartoeol("\1n"); // Shouldn't do this, as it resets color attributes + console.crlf(); + } + } +} + // Removes multiple, leading, and/or trailing spaces // The search & replace regular expressions used in this // function came from the following URL: @@ -1823,4 +1908,128 @@ function getKeyWithESCChars(pGetKeyMode) } return userInput; +} + +// Loads a text file (an .ans or .asc) into an array. This will first look for +// an .ans version, and if exists, convert to Synchronet colors before loading +// it. If an .ans doesn't exist, this will look for an .asc version. +// +// Parameters: +// pFilenameBase: The filename without the extension +// pMaxNumLines: Optional - The maximum number of lines to load from the text file +// +// Return value: An array containing the lines from the text file +function loadTextFileIntoArray(pFilenameBase, pMaxNumLines) +{ + if (typeof(pFilenameBase) != "string") + return new Array(); + + var maxNumLines = (typeof(pMaxNumLines) == "number" ? pMaxNumLines : -1); + + var txtFileLines = new Array(); + // See if there is a header file that is made for the user's terminal + // width (areaChgHeader-<width>.ans/asc). If not, then just go with + // msgHeader.ans/asc. + var txtFileExists = true; + var txtFilenameFullPath = gStartupPath + pFilenameBase; + var txtFileFilename = ""; + if (file_exists(txtFilenameFullPath + "-" + console.screen_columns + ".ans")) + txtFileFilename = txtFilenameFullPath + "-" + console.screen_columns + ".ans"; + else if (file_exists(txtFilenameFullPath + "-" + console.screen_columns + ".asc")) + txtFileFilename = txtFilenameFullPath + "-" + console.screen_columns + ".asc"; + else if (file_exists(txtFilenameFullPath + ".ans")) + txtFileFilename = txtFilenameFullPath + ".ans"; + else if (file_exists(txtFilenameFullPath + ".asc")) + txtFileFilename = txtFilenameFullPath + ".asc"; + else + txtFileExists = false; + if (txtFileExists) + { + var syncConvertedHdrFilename = txtFileFilename; + // If the user's console doesn't support ANSI and the header file is ANSI, + // then convert it to Synchronet attribute codes and read that file instead. + if (!console.term_supports(USER_ANSI) && (getStrAfterPeriod(txtFileFilename).toUpperCase() == "ANS")) + { + syncConvertedHdrFilename = txtFilenameFullPath + "_converted.asc"; + if (!file_exists(syncConvertedHdrFilename)) + { + if (getStrAfterPeriod(txtFileFilename).toUpperCase() == "ANS") + { + var filenameBase = txtFileFilename.substr(0, dotIdx); + var cmdLine = system.exec_dir + "ans2asc \"" + txtFileFilename + "\" \"" + + syncConvertedHdrFilename + "\""; + // Note: Both system.exec(cmdLine) and + // bbs.exec(cmdLine, EX_NATIVE, gStartupPath) could be used to + // execute the command, but system.exec() seems noticeably faster. + system.exec(cmdLine); + } + else + syncConvertedHdrFilename = txtFileFilename; + } + } + /* + // If the header file is ANSI, then convert it to Synchronet attribute + // codes and read that file instead. This is done so that this script can + // accurately get the file line lengths using console.strlen(). + var syncConvertedHdrFilename = txtFilenameFullPath + "_converted.asc"; + if (!file_exists(syncConvertedHdrFilename)) + { + if (getStrAfterPeriod(txtFileFilename).toUpperCase() == "ANS") + { + var filenameBase = txtFileFilename.substr(0, dotIdx); + var cmdLine = system.exec_dir + "ans2asc \"" + txtFileFilename + "\" \"" + + syncConvertedHdrFilename + "\""; + // Note: Both system.exec(cmdLine) and + // bbs.exec(cmdLine, EX_NATIVE, gStartupPath) could be used to + // execute the command, but system.exec() seems noticeably faster. + system.exec(cmdLine); + } + else + syncConvertedHdrFilename = txtFileFilename; + } + */ + // Read the header file into txtFileLines + var hdrFile = new File(syncConvertedHdrFilename); + if (hdrFile.open("r")) + { + var fileLine = null; + while (!hdrFile.eof) + { + // Read the next line from the header file. + fileLine = hdrFile.readln(2048); + // fileLine should be a string, but I've seen some cases + // where it isn't, so check its type. + if (typeof(fileLine) != "string") + continue; + + // Make sure the line isn't longer than the user's terminal + //if (fileLine.length > console.screen_columns) + // fileLine = fileLine.substr(0, console.screen_columns); + txtFileLines.push(fileLine); + + // If the header array now has the maximum number of lines, then + // stop reading the header file. + if (txtFileLines.length == maxNumLines) + break; + } + hdrFile.close(); + } + } + return txtFileLines; +} + +// Returns the portion (if any) of a string after the period. +// +// Parameters: +// pStr: The string to extract from +// +// Return value: The portion of the string after the dot, if there is one. If +// not, then an empty string will be returned. +function getStrAfterPeriod(pStr) +{ + var strAfterPeriod = ""; + var dotIdx = pStr.lastIndexOf("."); + if (dotIdx > -1) + strAfterPeriod = pStr.substr(dotIdx+1); + return strAfterPeriod; } \ No newline at end of file diff --git a/xtrn/DDAreaChoosers/DDMsgAreaChooser.cfg b/xtrn/DDAreaChoosers/DDMsgAreaChooser.cfg index 7e5cd45fe00f5dfb2be5d5d6f78af43fd0b96a6d..1c510a59a5ce5838dd9c673c9fba212088972eba 100644 --- a/xtrn/DDAreaChoosers/DDMsgAreaChooser.cfg +++ b/xtrn/DDAreaChoosers/DDMsgAreaChooser.cfg @@ -4,6 +4,8 @@ useLightbarInterface=true ; will be the messaeg import date. If false, the date will represent ; the timestamp in the message. showImportDates=true +areaChooserHdrFilenameBase=msgAreaChgHeader +areaChooserHdrMaxLines=5 [COLORS] ; Area number diff --git a/xtrn/DDAreaChoosers/DDMsgAreaChooser.js b/xtrn/DDAreaChoosers/DDMsgAreaChooser.js index 0e194726dca5fcce1ca9ac2217156e1aac16e727..c40dd6a59a46574c3d8c2c7fb2b32c585ace7635 100644 --- a/xtrn/DDAreaChoosers/DDMsgAreaChooser.js +++ b/xtrn/DDAreaChoosers/DDMsgAreaChooser.js @@ -50,6 +50,8 @@ * line argument now specifies whether or not to * allow choosing the message group, and it defaults * to true. + * 2016-02-12 Eric Oulashin 1.10Beta Started working on adding the ability to display + * a header ANSI/ASCII file above the list. */ /* Command-line arguments: @@ -78,8 +80,8 @@ if (system.version_num < 31400) } // Version & date variables -var DD_MSG_AREA_CHOOSER_VERSION = "1.09"; -var DD_MSG_AREA_CHOOSER_VER_DATE = "2016-01-17"; +var DD_MSG_AREA_CHOOSER_VERSION = "1.10 Beta 2"; +var DD_MSG_AREA_CHOOSER_VER_DATE = "2016-02-14"; // Keyboard input key codes var CTRL_M = "\x0d"; @@ -94,6 +96,14 @@ var KEY_PAGE_DOWN = "\1PgDn"; var UP_ARROW = ascii(24); var DOWN_ARROW = ascii(25); +// Determine the script's startup directory. +// This code is a trick that was created by Deuce, suggested by Rob Swindell +// as a way to detect which directory the script was executed in. I've +// shortened the code a little. +var gStartupPath = '.'; +try { throw dig.dist(dist); } catch(e) { gStartupPath = e.fileName; } +gStartupPath = backslash(gStartupPath.replace(/[\/\\][^\/\\]*$/,'')); + // 1st command-line argument: Whether or not to choose a message group first (if // false, then only choose a sub-board within the user's current group). This // can be true or false. @@ -175,6 +185,10 @@ function DDMsgAreaChooser() this.msgGrpDescLen = console.screen_columns - this.areaNumLen - this.numItemsLen - 5; + // Filename base of a header to display above the area list + this.areaChooserHdrFilenameBase = "msgAreaChgHeader"; + this.areaChooserHdrMaxLines = 5; + // Set the function pointers for the object this.ReadConfigFile = DDMsgAreaChooser_ReadConfigFile; this.WriteKeyHelpLine = DDMsgAreaChooser_writeKeyHelpLine; @@ -198,6 +212,7 @@ function DDMsgAreaChooser() // Function to build the sub-board printf information for a message // group this.BuildSubBoardPrintfInfoForGrp = DDMsgAreaChooser_buildSubBoardPrintfInfoForGrp; + this.DisplayAreaChgHdr = DDMsgAreaChooser_DisplayAreaChgHdr; // Read the settings from the config file. this.ReadConfigFile(); @@ -287,6 +302,10 @@ function DDMsgAreaChooser() // on the fly the first time the user lists sub-boards for a message // group. this.subBoardListPrintfInfo = new Array(); + + // areaChangeHdrLines is an array of text lines to use as a header to display + // above the message area changer lists. + this.areaChangeHdrLines = loadTextFileIntoArray(this.areaChooserHdrFilenameBase, this.areaChooserHdrMaxLines); } // For the DDMsgAreaChooser class: Writes the line of key help at the bottom @@ -399,7 +418,7 @@ function DDMsgAreaChooser_selectMsgArea_Lightbar(pChooseGroup) if ((bbs.curgrp != null) && (typeof(bbs.curgrp) == "number")) selectedGrpIndex = bbs.curgrp; - var listStartRow = 2; // The row on the screen where the list will start + var listStartRow = 2 + this.areaChangeHdrLines.length; // The row on the screen where the list will start var listEndRow = console.screen_rows - 1; // Row on screen where list will end var topMsgGrpIndex = 0; // The index of the message group at the top of the list @@ -442,14 +461,15 @@ function DDMsgAreaChooser_selectMsgArea_Lightbar(pChooseGroup) } } - // Clear the screen, write the help line and group list header, and output + // Clear the screen, write the header, help line, and group list header, and output // a screenful of message groups. console.clear("\1n"); + this.DisplayAreaChgHdr(1); this.WriteKeyHelpLine(); var curpos = new Object(); curpos.x = 1; - curpos.y = 1; + curpos.y = 1 + this.areaChangeHdrLines.length; console.gotoxy(curpos); var pageNum = calcPageNum(topMsgGrpIndex, numItemsPerPage); this.WriteGrpListHdrLine(numPages, pageNum); @@ -557,7 +577,8 @@ function DDMsgAreaChooser_selectMsgArea_Lightbar(pChooseGroup) { // A sub-board was not chosen, so we'll have to re-draw // the header and list of message groups. - console.gotoxy(1, 1); + this.DisplayAreaChgHdr(1); + console.gotoxy(1, 1+this.areaChangeHdrLines.length); this.WriteGrpListHdrLine(numPages, pageNum); this.ListScreenfulOfMsgGrps(topMsgGrpIndex, listStartRow, listEndRow, false, true); } @@ -620,7 +641,8 @@ function DDMsgAreaChooser_selectMsgArea_Lightbar(pChooseGroup) console.pause(); // Refresh the screen this.WriteKeyHelpLine(); - console.gotoxy(1, 1); + this.DisplayAreaChgHdr(1); + console.gotoxy(1, 1+this.areaChangeHdrLines.length); this.WriteGrpListHdrLine(numPages, pageNum); this.ListScreenfulOfMsgGrps(topMsgGrpIndex, listStartRow, listEndRow, false, true); break; @@ -775,7 +797,7 @@ function DDMsgAreaChooser_selectSubBoard_Lightbar(pGrpIndex, pMarkIndex) } } - var listStartRow = 3; // The row on the screen where the list will start + var listStartRow = 3+this.areaChangeHdrLines.length; // The row on the screen where the list will start var listEndRow = console.screen_rows - 1; // Row on screen where list will end var topSubIndex = 0; // The index of the message group at the top of the list // Figure out the index of the last message group to appear on the screen. @@ -818,16 +840,19 @@ function DDMsgAreaChooser_selectSubBoard_Lightbar(pGrpIndex, pMarkIndex) } } - // Clear the screen, write the help line and group list header, and output + // Clear the screen, write the header, help line, and group list header, and output // a screenful of message groups. console.clear("\1n"); + this.DisplayAreaChgHdr(1); // Don't need to since it should already be drawn + if (this.areaChangeHdrLines.length > 0) + console.crlf(); var pageNum = calcPageNum(topSubIndex, numItemsPerPage); this.WriteSubBrdListHdr1Line(grpIndex, numPages, pageNum); this.WriteKeyHelpLine(); var curpos = new Object(); curpos.x = 1; - curpos.y = 2; + curpos.y = 2+this.areaChangeHdrLines.length; console.gotoxy(curpos); printf(this.subBoardListHdrPrintfStr, "Sub #", "Name", "# Posts", "Latest date & time"); this.ListScreenfulOfSubBrds(grpIndex, topSubIndex, listStartRow, listEndRow, @@ -991,11 +1016,12 @@ function DDMsgAreaChooser_selectSubBoard_Lightbar(pGrpIndex, pMarkIndex) this.ShowHelpScreen(true, true); console.pause(); // Refresh the screen - console.gotoxy(1, 1); + this.DisplayAreaChgHdr(1); + console.gotoxy(1, 1+this.areaChangeHdrLines.length); this.WriteSubBrdListHdr1Line(grpIndex, numPages, pageNum); console.cleartoeol("\1n"); this.WriteKeyHelpLine(); - console.gotoxy(1, 2); + console.gotoxy(1, 2+this.areaChangeHdrLines.length); printf(this.subBoardListHdrPrintfStr, "Sub #", "Name", "# Posts", "Latest date & time"); this.ListScreenfulOfSubBrds(grpIndex, topSubIndex, listStartRow, @@ -1080,6 +1106,9 @@ function DDMsgAreaChooser_selectMsgArea_Traditional(pChooseGroup) bbs.command_str = ""; console.clear("\1n"); + this.DisplayAreaChgHdr(1); + if (this.areaChangeHdrLines.length > 0) + console.crlf(); this.ListMsgGrps(); console.crlf(); console.print("\1n\1b\1h� \1n\1cWhich, \1hQ\1n\1cuit, or [\1h" + +(bbs.curgrp+1) + "\1n\1c]: \1h"); @@ -1149,6 +1178,9 @@ function DDMsgAreaChooser_selectSubBoard_Traditional(pGrpIdx, pDefaultSubBoardId retObj.subBoardChosen = false; retObj.subBoardIndex = -1; + this.DisplayAreaChgHdr(1); + if (this.areaChangeHdrLines.length > 0) + console.crlf(); this.ListSubBoardsInMsgGroup(pGrpIdx, pDefaultSubBoardIdx); console.crlf(); console.print("\1n\1b\1h� \1n\1cWhich, \1hQ\1n\1cuit, or [\1h" + +(pDefaultSubBoardIdx+1) + "\1n\1c]: \1h"); @@ -1491,12 +1523,12 @@ function DDMsgAreaChooser_updatePageNumInHeader(pPageNum, pNumPages, pGroup, pRe if (pGroup) { - console.gotoxy(29, 1); + console.gotoxy(29, 1+this.areaChangeHdrLines.length); console.print("\1n" + this.colors.header + pPageNum + " of " + pNumPages + ") "); } else { - console.gotoxy(51, 1); + console.gotoxy(51, 1+this.areaChangeHdrLines.length); console.print("\1n" + this.colors.subBoardHeader + pPageNum + " of " + pNumPages + ") "); } @@ -1647,84 +1679,92 @@ function DDMsgAreaChooser_writeMsgSubBrdLine(pGrpIndex, pSubIndex, pHighlight) // For the DDMsgAreaChooser class: Reads the configuration file. function DDMsgAreaChooser_ReadConfigFile() { - // Determine the script's startup directory. - // This code is a trick that was created by Deuce, suggested by Rob Swindell - // as a way to detect which directory the script was executed in. I've - // shortened the code a little. - var startup_path = '.'; - try { throw dig.dist(dist); } catch(e) { startup_path = e.fileName; } - startup_path = backslash(startup_path.replace(/[\/\\][^\/\\]*$/,'')); - - // Open the configuration file - var cfgFile = new File(startup_path + "DDMsgAreaChooser.cfg"); - if (cfgFile.open("r")) - { - var settingsMode = "behavior"; - var fileLine = null; // A line read from the file - var equalsPos = 0; // Position of a = in the line - var commentPos = 0; // Position of the start of a comment - var setting = null; // A setting name (string) - var settingUpper = null; // Upper-case setting name - var value = null; // A value for a setting (string) - while (!cfgFile.eof) - { - // Read the next line from the config file. - fileLine = cfgFile.readln(2048); + // Determine the script's startup directory. + // This code is a trick that was created by Deuce, suggested by Rob Swindell + // as a way to detect which directory the script was executed in. I've + // shortened the code a little. + var startup_path = '.'; + try { throw dig.dist(dist); } catch(e) { startup_path = e.fileName; } + startup_path = backslash(startup_path.replace(/[\/\\][^\/\\]*$/,'')); + + // Open the configuration file + var cfgFile = new File(startup_path + "DDMsgAreaChooser.cfg"); + if (cfgFile.open("r")) + { + var settingsMode = "behavior"; + var fileLine = null; // A line read from the file + var equalsPos = 0; // Position of a = in the line + var commentPos = 0; // Position of the start of a comment + var setting = null; // A setting name (string) + var settingUpper = null; // Upper-case setting name + var value = null; // A value for a setting (string) + while (!cfgFile.eof) + { + // Read the next line from the config file. + fileLine = cfgFile.readln(2048); - // fileLine should be a string, but I've seen some cases - // where it isn't, so check its type. - if (typeof(fileLine) != "string") - continue; + // fileLine should be a string, but I've seen some cases + // where it isn't, so check its type. + if (typeof(fileLine) != "string") + continue; - // If the line starts with with a semicolon (the comment - // character) or is blank, then skip it. - if ((fileLine.substr(0, 1) == ";") || (fileLine.length == 0)) - continue; + // If the line starts with with a semicolon (the comment + // character) or is blank, then skip it. + if ((fileLine.substr(0, 1) == ";") || (fileLine.length == 0)) + continue; - // If in the "behavior" section, then set the behavior-related variables. - if (fileLine.toUpperCase() == "[BEHAVIOR]") - { - settingsMode = "behavior"; - continue; - } - else if (fileLine.toUpperCase() == "[COLORS]") - { - settingsMode = "colors"; - continue; - } + // If in the "behavior" section, then set the behavior-related variables. + if (fileLine.toUpperCase() == "[BEHAVIOR]") + { + settingsMode = "behavior"; + continue; + } + else if (fileLine.toUpperCase() == "[COLORS]") + { + settingsMode = "colors"; + continue; + } - // If the line has a semicolon anywhere in it, then remove - // everything from the semicolon onward. - commentPos = fileLine.indexOf(";"); - if (commentPos > -1) - fileLine = fileLine.substr(0, commentPos); - - // Look for an equals sign, and if found, separate the line - // into the setting name (before the =) and the value (after the - // equals sign). - equalsPos = fileLine.indexOf("="); - if (equalsPos > 0) - { - // Read the setting & value, and trim leading & trailing spaces. - setting = trimSpaces(fileLine.substr(0, equalsPos), true, false, true); - settingUpper = setting.toUpperCase(); - value = trimSpaces(fileLine.substr(equalsPos+1), true, false, true); + // If the line has a semicolon anywhere in it, then remove + // everything from the semicolon onward. + commentPos = fileLine.indexOf(";"); + if (commentPos > -1) + fileLine = fileLine.substr(0, commentPos); + + // Look for an equals sign, and if found, separate the line + // into the setting name (before the =) and the value (after the + // equals sign). + equalsPos = fileLine.indexOf("="); + if (equalsPos > 0) + { + // Read the setting & value, and trim leading & trailing spaces. + setting = trimSpaces(fileLine.substr(0, equalsPos), true, false, true); + settingUpper = setting.toUpperCase(); + value = trimSpaces(fileLine.substr(equalsPos+1), true, false, true); - if (settingsMode == "behavior") - { - // Set the appropriate value in the settings object. - if (settingUpper == "USELIGHTBARINTERFACE") - this.useLightbarInterface = (value.toUpperCase() == "TRUE"); - else if (settingUpper == "SHOWIMPORTDATES") - this.showImportDates = (value.toUpperCase() == "TRUE"); - } - else if (settingsMode == "colors") - this.colors[setting] = value; - } - } - - cfgFile.close(); - } + if (settingsMode == "behavior") + { + // Set the appropriate value in the settings object. + if (settingUpper == "USELIGHTBARINTERFACE") + this.useLightbarInterface = (value.toUpperCase() == "TRUE"); + else if (settingUpper == "SHOWIMPORTDATES") + this.showImportDates = (value.toUpperCase() == "TRUE"); + else if (settingUpper == "AREACHOOSERHDRFILENAMEBASE") + this.areaChooserHdrFilenameBase = value; + else if (settingUpper == "AREACHOOSERHDRMAXLINES") + { + var maxNumLines = +value; + if (maxNumLines > 0) + this.areaChooserHdrMaxLines = maxNumLines; + } + } + else if (settingsMode == "colors") + this.colors[setting] = value; + } + } + + cfgFile.close(); + } } // For the DDMsgAreaChooser class: Shows the help screen @@ -1785,10 +1825,10 @@ function DDMsgAreaChooser_showHelpScreen(pLightbar, pClearScreen) console.crlf(); } -// Builds sub-board printf format information for a message group. -// The widths of the description & # messages columns are calculated -// based on the greatest number of messages in a sub-board for the -// message group. +// For the DDMsgAreaChooser class: Builds sub-board printf format information +// for a message group. The widths of the description & # messages columns +// are calculated based on the greatest number of messages in a sub-board for +// the message group. // // Parameters: // pGrpIndex: The index of the message group @@ -1837,6 +1877,64 @@ function DDMsgAreaChooser_buildSubBoardPrintfInfoForGrp(pGrpIndex) } } +// For the DDMsgAreaChooser class: Displays the area chooser header +// +// Parameters: +// pStartScreenRow: The row on the screen at which to start displaying the +// header information. Will be used if the user's terminal +// supports ANSI. +// pClearRowsFirst: Optional boolean - Whether or not to clear the rows first. +// Defaults to true. Only valid if the user's terminal supports +// ANSI. +function DDMsgAreaChooser_DisplayAreaChgHdr(pStartScreenRow, pClearRowsFirst) +{ + if (this.areaChangeHdrLines == null) + return; + if (this.areaChangeHdrLines.length == 0) + return; + + // If the user's terminal supports ANSI and pStartScreenRow is a number, then + // we can move the cursor and display the header where specified. + if (console.term_supports(USER_ANSI) && (typeof(pStartScreenRow) == "number")) + { + // If specified to clear the rows first, then do so. + var screenX = 1; + var screenY = pStartScreenRow; + var clearRowsFirst = (typeof(pClearRowsFirst) == "boolean" ? pClearRowsFirst : true); + if (clearRowsFirst) + { + console.print("\1n"); + for (var hdrFileIdx = 0; hdrFileIdx < this.areaChangeHdrLines.length; ++hdrFileIdx) + { + console.gotoxy(screenX, screenY++); + console.cleartoeol(); + } + } + // Display the header starting on the first column and the given screen row. + screenX = 1; + screenY = pStartScreenRow; + for (var hdrFileIdx = 0; hdrFileIdx < this.areaChangeHdrLines.length; ++hdrFileIdx) + { + console.gotoxy(screenX, screenY++); + console.print(this.areaChangeHdrLines[hdrFileIdx]); + //console.putmsg(this.areaChangeHdrLines[hdrFileIdx]); + //console.cleartoeol("\1n"); // Shouldn't do this, as it resets color attributes + } + } + else + { + // The user's terminal doesn't support ANSI or pStartScreenRow is not a + // number - So just output the header lines. + for (var hdrFileIdx = 0; hdrFileIdx < this.areaChangeHdrLines.length; ++hdrFileIdx) + { + console.print(this.areaChangeHdrLines[hdrFileIdx]); + //console.putmsg(this.areaChangeHdrLines[hdrFileIdx]); + //console.cleartoeol("\1n"); // Shouldn't do this, as it resets color attributes + console.crlf(); + } + } +} + // Removes multiple, leading, and/or trailing spaces. // The search & replace regular expressions used in this // function came from the following URL: @@ -1932,45 +2030,173 @@ function getGreatestNumMsgs(pGrpIndex) // Return value: The user's keypress function getKeyWithESCChars(pGetKeyMode) { - var getKeyMode = K_NONE; - if (typeof(pGetKeyMode) == "number") - getKeyMode = pGetKeyMode; - - var userInput = console.getkey(getKeyMode); - if (userInput == KEY_ESC) { - switch (console.inkey(K_NOECHO|K_NOSPIN, 2)) { - case '[': - switch (console.inkey(K_NOECHO|K_NOSPIN, 2)) { - case 'V': - userInput = KEY_PAGE_UP; - break; - case 'U': - userInput = KEY_PAGE_DOWN; - break; - } - break; - case 'O': - switch (console.inkey(K_NOECHO|K_NOSPIN, 2)) { - case 'P': - userInput = "\1F1"; - break; - case 'Q': - userInput = "\1F2"; - break; - case 'R': - userInput = "\1F3"; - break; - case 'S': - userInput = "\1F4"; - break; - case 't': - userInput = "\1F5"; - break; - } - default: - break; - } - } + var getKeyMode = K_NONE; + if (typeof(pGetKeyMode) == "number") + getKeyMode = pGetKeyMode; + + var userInput = console.getkey(getKeyMode); + if (userInput == KEY_ESC) + { + switch (console.inkey(K_NOECHO|K_NOSPIN, 2)) + { + case '[': + switch (console.inkey(K_NOECHO|K_NOSPIN, 2)) + { + case 'V': + userInput = KEY_PAGE_UP; + break; + case 'U': + userInput = KEY_PAGE_DOWN; + break; + } + break; + case 'O': + switch (console.inkey(K_NOECHO|K_NOSPIN, 2)) + { + case 'P': + userInput = "\1F1"; + break; + case 'Q': + userInput = "\1F2"; + break; + case 'R': + userInput = "\1F3"; + break; + case 'S': + userInput = "\1F4"; + break; + case 't': + userInput = "\1F5"; + break; + } + default: + break; + } + } + + return userInput; +} + +// Loads a text file (an .ans or .asc) into an array. This will first look for +// an .ans version, and if exists, convert to Synchronet colors before loading +// it. If an .ans doesn't exist, this will look for an .asc version. +// +// Parameters: +// pFilenameBase: The filename without the extension +// pMaxNumLines: Optional - The maximum number of lines to load from the text file +// +// Return value: An array containing the lines from the text file +function loadTextFileIntoArray(pFilenameBase, pMaxNumLines) +{ + if (typeof(pFilenameBase) != "string") + return new Array(); + + var maxNumLines = (typeof(pMaxNumLines) == "number" ? pMaxNumLines : -1); + + var txtFileLines = new Array(); + // See if there is a header file that is made for the user's terminal + // width (areaChgHeader-<width>.ans/asc). If not, then just go with + // msgHeader.ans/asc. + var txtFileExists = true; + var txtFilenameFullPath = gStartupPath + pFilenameBase; + var txtFileFilename = ""; + if (file_exists(txtFilenameFullPath + "-" + console.screen_columns + ".ans")) + txtFileFilename = txtFilenameFullPath + "-" + console.screen_columns + ".ans"; + else if (file_exists(txtFilenameFullPath + "-" + console.screen_columns + ".asc")) + txtFileFilename = txtFilenameFullPath + "-" + console.screen_columns + ".asc"; + else if (file_exists(txtFilenameFullPath + ".ans")) + txtFileFilename = txtFilenameFullPath + ".ans"; + else if (file_exists(txtFilenameFullPath + ".asc")) + txtFileFilename = txtFilenameFullPath + ".asc"; + else + txtFileExists = false; + if (txtFileExists) + { + var syncConvertedHdrFilename = txtFileFilename; + // If the user's console doesn't support ANSI and the header file is ANSI, + // then convert it to Synchronet attribute codes and read that file instead. + if (!console.term_supports(USER_ANSI) && (getStrAfterPeriod(txtFileFilename).toUpperCase() == "ANS")) + { + syncConvertedHdrFilename = txtFilenameFullPath + "_converted.asc"; + if (!file_exists(syncConvertedHdrFilename)) + { + if (getStrAfterPeriod(txtFileFilename).toUpperCase() == "ANS") + { + var filenameBase = txtFileFilename.substr(0, dotIdx); + var cmdLine = system.exec_dir + "ans2asc \"" + txtFileFilename + "\" \"" + + syncConvertedHdrFilename + "\""; + // Note: Both system.exec(cmdLine) and + // bbs.exec(cmdLine, EX_NATIVE, gStartupPath) could be used to + // execute the command, but system.exec() seems noticeably faster. + system.exec(cmdLine); + } + else + syncConvertedHdrFilename = txtFileFilename; + } + } + /* + // If the header file is ANSI, then convert it to Synchronet attribute + // codes and read that file instead. This is done so that this script can + // accurately get the file line lengths using console.strlen(). + var syncConvertedHdrFilename = txtFilenameFullPath + "_converted.asc"; + if (!file_exists(syncConvertedHdrFilename)) + { + if (getStrAfterPeriod(txtFileFilename).toUpperCase() == "ANS") + { + var filenameBase = txtFileFilename.substr(0, dotIdx); + var cmdLine = system.exec_dir + "ans2asc \"" + txtFileFilename + "\" \"" + + syncConvertedHdrFilename + "\""; + // Note: Both system.exec(cmdLine) and + // bbs.exec(cmdLine, EX_NATIVE, gStartupPath) could be used to + // execute the command, but system.exec() seems noticeably faster. + system.exec(cmdLine); + } + else + syncConvertedHdrFilename = txtFileFilename; + } + */ + // Read the header file into txtFileLines + var hdrFile = new File(syncConvertedHdrFilename); + if (hdrFile.open("r")) + { + var fileLine = null; + while (!hdrFile.eof) + { + // Read the next line from the header file. + fileLine = hdrFile.readln(2048); + // fileLine should be a string, but I've seen some cases + // where it isn't, so check its type. + if (typeof(fileLine) != "string") + continue; + + // Make sure the line isn't longer than the user's terminal + //if (fileLine.length > console.screen_columns) + // fileLine = fileLine.substr(0, console.screen_columns); + txtFileLines.push(fileLine); + + // If the header array now has the maximum number of lines, then + // stop reading the header file. + if (txtFileLines.length == maxNumLines) + break; + } + hdrFile.close(); + } + } + return txtFileLines; +} - return userInput; +// Returns the portion (if any) of a string after the period. +// +// Parameters: +// pStr: The string to extract from +// +// Return value: The portion of the string after the dot, if there is one. If +// not, then an empty string will be returned. +function getStrAfterPeriod(pStr) +{ + var strAfterPeriod = ""; + var dotIdx = pStr.lastIndexOf("."); + if (dotIdx > -1) + strAfterPeriod = pStr.substr(dotIdx+1); + return strAfterPeriod; } \ No newline at end of file diff --git a/xtrn/DDAreaChoosers/Read Me.txt b/xtrn/DDAreaChoosers/Read Me.txt index 74c647e9fe2162b751948733d1111d56b8bf0b8e..42de386d79cd7cc0778925ea1b9d2a2d062723c7 100644 --- a/xtrn/DDAreaChoosers/Read Me.txt +++ b/xtrn/DDAreaChoosers/Read Me.txt @@ -1,6 +1,6 @@ Digital Distortion Area Choosers - Version 1.09 - Release date: 2016-01-17 + Version 1.10 + Release date: 2016-??-?? by @@ -21,7 +21,6 @@ Contents 4. Configuration file 5. DDMsgAreaChooser class: Properties & methods 6. DDFileAreaChooser class: Properties & methods -7. Revision History 1. Disclaimer @@ -214,6 +213,23 @@ showImportDates true/false: Whether or not to show the in the latest date & time column in the sub-board lists. +areaChooserHdrFilenameBase The filename to use (without the + extension) for a header to display above + the message area chooser list. For + example, if areaChgHeader is specified, + then the chooser will look for + areaChgHeader.ans if it exists, and if + not, the chooser will look for + areaChgHeader.asc. Additionally, you + can have multiple header files for + different terminal widths; fpr example, + areaChgHeader-80.ans for an 80-column + terminal, areaChgHeader-140.ans for a + 140-column terminal, etc. + +areaChooserHdrMaxLines The maximum number of lines to use from + the message area chooser header file + Colors section: Message area chooser ------------------------------------ Color setting Description @@ -281,6 +297,23 @@ Setting Description useLightbarInterface true/false: Whether or not to use a lightbar user interface. +areaChooserHdrFilenameBase The filename to use (without the + extension) for a header to display above + the file area chooser list. For example, + if areaChgHeader is specified, then the + chooser will look for areaChgHeader.ans + if it exists, and if not, the chooser + will look for areaChgHeader.asc. + Additionally, you can have multiple + header files for different terminal + widths; fpr example, areaChgHeader-80.ans + for an 80-column terminal, + areaChgHeader-140.ans for a 140-column + terminal, etc. + +areaChooserHdrMaxLines The maximum number of lines to use from + the message area chooser header file + Colors section: File area chooser ------------------------------------ Color setting Description @@ -414,53 +447,3 @@ ListDirsInFileLib(pLibIndex, Lists the directories in the user's specify the index of the file library and the index of the directory to mark with the "chosen" character. -7. Revision History -=================== -Version Date Description -------- ---- ----------- -1.09 2016-01-17 Added a command-line parameter to let the user choose a - message sub-board only within their current message - group, or file directory only within their current file - library. -1.08 2015-04-19 Added customizable color settings for the key help text - line displayed at the bottom of the screen in lightbar - mode. Also, updated to allow the PageUp and PageDown - keys to be used instead of the P and N keys to go to the - previous & next pages in lightbar mode. -1.07 2014-12-22 Message area chooser: - Bug fix: Made this.colors.subBoardHeader apply to the - whole line rather than just the page number. - Bug fix: The initial display of the page number is now - correct (previously, it would start out saying page 1, - even if on another page). - Documentation & example configuration files: - Added the color options subBoardHeader (for the message - area chooser) and fileAreaHdr (for the file area chooser) - to the documentation and example configuration files. -1.06 2014-09-14 Bug fix: Updated the lightbar highlight format string to - include a normal attribute at the end to avoid the - highlight color to be used when clearing the screen, - etc. Bug reported by Psi-Jack. -1.05 2013-05-10 Bug fix in the file area chooser: When listing - directories in a file group, it would sometimes - crash due to an incorrect array index used, and - the array was not set up. Those have been fixed. -1.04 2013-05-04 Updated to properly format message sub-boards and - file directories with more than 9999 entries. The - formatting is now dynamically adjusted depending - on the greatest number of entries in a sub-board - for a message group or file directory in a file - library (the descriptions will shrink as the - text length of the greatest number of entries - increases). -1.03 2012-11-30 Bug fix: After leaving the help screen from the - sub-board/directory list, the top line is now - correctly written with the page information as "Page - # of #". -1.02 2012-10-06 For the lightbar interface, the current page number is - now displayed at the top of the screen (along with the - total number of pages) and is updated when going to a - new page. -1.01 2011-04-22 Fixed the wording when choosing a message sub-board and - file library. -1.00 2010-03-13 First public release \ No newline at end of file diff --git a/xtrn/DDAreaChoosers/Revision history.txt b/xtrn/DDAreaChoosers/Revision history.txt new file mode 100644 index 0000000000000000000000000000000000000000..0b78364a2941d1572562044aad87a646fcc0ea9e --- /dev/null +++ b/xtrn/DDAreaChoosers/Revision history.txt @@ -0,0 +1,59 @@ +This file lists all of the changes made for each release of the Digital +Distortion Area Choosers. + +Revision History (change log) +============================= +Version Date Description +------- ---- ----------- +1.10 2016-??-?? Added the ability to display a custom header file above + the area lists in the area choosers. Added the + configuration options areaChooserHdrFilenameBase and + areaChooserHdrMaxLines to specify the filename (without + the extension) and maximum number of lines from the header + file to use. +1.09 2016-01-17 Added a command-line parameter to let the user choose a + message sub-board only within their current message + group, or file directory only within their current file + library. +1.08 2015-04-19 Added customizable color settings for the key help text + line displayed at the bottom of the screen in lightbar + mode. Also, updated to allow the PageUp and PageDown + keys to be used instead of the P and N keys to go to the + previous & next pages in lightbar mode. +1.07 2014-12-22 Message area chooser: + Bug fix: Made this.colors.subBoardHeader apply to the + whole line rather than just the page number. + Bug fix: The initial display of the page number is now + correct (previously, it would start out saying page 1, + even if on another page). + Documentation & example configuration files: + Added the color options subBoardHeader (for the message + area chooser) and fileAreaHdr (for the file area chooser) + to the documentation and example configuration files. +1.06 2014-09-14 Bug fix: Updated the lightbar highlight format string to + include a normal attribute at the end to avoid the + highlight color to be used when clearing the screen, + etc. Bug reported by Psi-Jack. +1.05 2013-05-10 Bug fix in the file area chooser: When listing + directories in a file group, it would sometimes + crash due to an incorrect array index used, and + the array was not set up. Those have been fixed. +1.04 2013-05-04 Updated to properly format message sub-boards and + file directories with more than 9999 entries. The + formatting is now dynamically adjusted depending + on the greatest number of entries in a sub-board + for a message group or file directory in a file + library (the descriptions will shrink as the + text length of the greatest number of entries + increases). +1.03 2012-11-30 Bug fix: After leaving the help screen from the + sub-board/directory list, the top line is now + correctly written with the page information as "Page + # of #". +1.02 2012-10-06 For the lightbar interface, the current page number is + now displayed at the top of the screen (along with the + total number of pages) and is updated when going to a + new page. +1.01 2011-04-22 Fixed the wording when choosing a message sub-board and + file library. +1.00 2010-03-13 First public release \ No newline at end of file