diff --git a/xtrn/ddfilelister/ddfilelister.js b/xtrn/ddfilelister/ddfilelister.js index fb7298bc62f8d3161640264e2012b6d54d7c66b7..c11bec4ed72c3084ab132e6f3291fcea016f30d0 100644 --- a/xtrn/ddfilelister/ddfilelister.js +++ b/xtrn/ddfilelister/ddfilelister.js @@ -156,6 +156,13 @@ * Now optionally displays the number of files in the directory in the * header at the top of the list, configurable with the * displayNumFilesInHeader option in the config file + * 2025-02-22 Eric Oulashin Version 2.28 + * If extended descriptions are enabled and a filename is too long to + * fully fit in the menu, prepend the full filename (wrapped) to the + * description. + * New bottom line menu option to toggle extended descriptions on/off + * Fix: useFilenameIfNoDescription option now used in traditional + * (non-lightbar) mode. */ "use strict"; @@ -197,8 +204,8 @@ var gAvatar = load({}, "avatar_lib.js"); // Version information -var LISTER_VERSION = "2.27"; -var LISTER_DATE = "2025-02-20"; +var LISTER_VERSION = "2.28"; +var LISTER_DATE = "2025-02-22"; /////////////////////////////////////////////////////////////////////////////// @@ -285,8 +292,9 @@ var FILE_DOWNLOAD_SINGLE = 4; var FILE_EDIT = 5; var HELP = 6; var QUIT = 7; -var FILE_MOVE = 8; // Sysop action -var FILE_DELETE = 9; // Sysop action +var TOGGLE_EXTD_DESCS = 8; // Toggle extended descriptions +var FILE_MOVE = 9; // Sysop action +var FILE_DELETE = 10; // Sysop action var NEXT_PAGE = 10; var PREV_PAGE = 11; @@ -444,16 +452,16 @@ if (gFileList.length == 0) } // Construct and display the menu/command bar at the bottom of the screen -var fileMenuBar = new DDFileMenuBar({ x: 1, y: console.screen_rows }); +var gFileMenuBar = new DDFileMenuBar({ x: 1, y: console.screen_rows }); // Clear the screen and display the header lines console.clear("\x01n"); if ((gListBehavior & FL_NO_HDR) != FL_NO_HDR) displayFileLibAndDirHeader(false, null, !gUseLightbarInterface || !console.term_supports(USER_ANSI)); // Create the file list menu (must be done after displayFileLibAndDirHeader() when using ANSI and lightbar) -var gFileListMenu = createFileListMenu(fileMenuBar.getAllActionKeysStr(true, true) + KEY_LEFT + KEY_RIGHT + KEY_DEL /*+ CTRL_C*/); +var gFileListMenu = createFileListMenu(gFileMenuBar.getAllActionKeysStr(true, true) + KEY_LEFT + KEY_RIGHT + KEY_DEL /*+ CTRL_C*/); if (gUseLightbarInterface && console.term_supports(USER_ANSI)) { - fileMenuBar.writePromptLine(); + gFileMenuBar.writePromptLine(); // In a loop, show the file list menu, allowing the user to scroll the file list, // and respond to user input until the user decides to quit. gFileListMenu.Draw({}); @@ -475,14 +483,25 @@ if (gUseLightbarInterface && console.term_supports(USER_ANSI)) if (lastUserInputUpper == null || lastUserInputUpper == "Q" || console.aborted) continueDoingFileList = false; else if (lastUserInputUpper == KEY_LEFT) - fileMenuBar.decrementMenuItemAndRefresh(); + gFileMenuBar.decrementMenuItemAndRefresh(); else if (lastUserInputUpper == KEY_RIGHT) - fileMenuBar.incrementMenuItemAndRefresh(); + gFileMenuBar.incrementMenuItemAndRefresh(); else if (lastUserInputUpper == KEY_ENTER) { - currentActionVal = fileMenuBar.getCurrentSelectedAction(); - fileMenuBar.setCurrentActionCode(currentActionVal); - actionRetObj = doAction(currentActionVal, gFileList, gFileListMenu); + currentActionVal = gFileMenuBar.getCurrentSelectedAction(); + gFileMenuBar.setCurrentActionCode(currentActionVal); + if (currentActionVal == TOGGLE_EXTD_DESCS) + { + // Toggle extended descriptions + toggleExtdDescriptionsForUser_Lightbar(); + drawFileListMenu = true; // Ensure the menu re-draws itself (properly) + actionRetObj = null; + } + else + { + // Handle actions (other than extended description toggle) + actionRetObj = doAction(currentActionVal, gFileList, gFileListMenu); + } } // Allow the delete key as a special key for sysops to delete the selected file(s). Also allow backspace // due to some terminals returning backspace for delete. @@ -490,16 +509,27 @@ if (gUseLightbarInterface && console.term_supports(USER_ANSI)) { if (user.is_sysop) { - fileMenuBar.setCurrentActionCode(FILE_DELETE, true); + gFileMenuBar.setCurrentActionCode(FILE_DELETE, true); actionRetObj = doAction(FILE_DELETE, gFileList, gFileListMenu); currentActionVal = FILE_DELETE; } } else { - currentActionVal = fileMenuBar.getActionFromChar(lastUserInputUpper, false); - fileMenuBar.setCurrentActionCode(currentActionVal, true); - actionRetObj = doAction(currentActionVal, gFileList, gFileListMenu); + currentActionVal = gFileMenuBar.getActionFromChar(lastUserInputUpper, false); + gFileMenuBar.setCurrentActionCode(currentActionVal, true); + if (currentActionVal == TOGGLE_EXTD_DESCS) + { + // Toggle extended descriptions + toggleExtdDescriptionsForUser_Lightbar(); + drawFileListMenu = true; // Ensure the menu re-draws itself (properly) + actionRetObj = null; + } + else + { + // Handle actions (other than extended description toggle) + actionRetObj = doAction(currentActionVal, gFileList, gFileListMenu); + } } // If an action was done (actionRetObj is not null), then look at actionRetObj and // do what's needed. Note that quit (for the Q key) is already handled. @@ -523,8 +553,8 @@ if (gUseLightbarInterface && console.term_supports(USER_ANSI)) displayFileLibAndDirHeader(false, null, gFileListMenu.numberedMode); } } - if (actionRetObj.reDrawCmdBar) // Could call fileMenuBar.constructPromptText(); if needed - fileMenuBar.writePromptLine(); + if (actionRetObj.reDrawCmdBar) // Could call gFileMenuBar.constructPromptText(); if needed + gFileMenuBar.writePromptLine(); var redrewPartOfFileListMenu = false; // If we are to re-draw the main screen content, then // enable the flag to draw the file list menu on the next @@ -643,7 +673,7 @@ else var topItemIndexForLastPage = allFileInfoLines.length - numLinesPerPage; // Allowed keys for user input - var validOptionKeys = "IVBDEMNPFLQ?" + KEY_PAGEDN + KEY_PAGEUP + KEY_HOME + KEY_END; + var validOptionKeys = "IVBDEMNPFLXQ?" + KEY_PAGEDN + KEY_PAGEUP + KEY_HOME + KEY_END; if (user.is_sysop) validOptionKeys += KEY_DEL + KEY_BACKSPACE; // If the user's terminal supports ANSI, then also allow left, right, and enter (option navigation & selection) @@ -680,16 +710,16 @@ else } if (refreshWholePromptLine || drawMenu) - fileMenuBar.pos = console.getxy(); + gFileMenuBar.pos = console.getxy(); if (refreshWholePromptLine) - fileMenuBar.writePromptLine(); + gFileMenuBar.writePromptLine(); var userInput = console.getkeys(validOptionKeys, -1, K_UPPER|K_NOECHO|K_NOSPIN|K_NOCRLF).toString(); // If the user pressed the enter key, change userInput to the key // corresponding to what we'd expect for that option if (userInput == KEY_ENTER) { - //currentActionVal = fileMenuBar.getCurrentSelectedAction(); - switch (fileMenuBar.getCurrentSelectedAction()) + //currentActionVal = gFileMenuBar.getCurrentSelectedAction(); + switch (gFileMenuBar.getCurrentSelectedAction()) { case NEXT_PAGE: userInput = KEY_PAGEDN; @@ -711,14 +741,14 @@ else // Check action based on the user's last input if (userInput == KEY_LEFT) { - fileMenuBar.decrementMenuItemAndRefresh(); + gFileMenuBar.decrementMenuItemAndRefresh(); drawDirHeaderLines = false; drawMenu = false; refreshWholePromptLine = false; } else if (userInput == KEY_RIGHT) { - fileMenuBar.incrementMenuItemAndRefresh(); + gFileMenuBar.incrementMenuItemAndRefresh(); drawDirHeaderLines = false; drawMenu = false; refreshWholePromptLine = false; @@ -728,8 +758,8 @@ else drawDirHeaderLines = true; drawMenu = true; refreshWholePromptLine = true; - currentActionVal = fileMenuBar.getCurrentSelectedAction(); - fileMenuBar.setCurrentActionCode(currentActionVal); + currentActionVal = gFileMenuBar.getCurrentSelectedAction(); + gFileMenuBar.setCurrentActionCode(currentActionVal); actionRetObj = doAction(currentActionVal, gFileList, gFileListMenu); } // Allow the delete key as a special key for sysops to delete the selected file(s). Also allow backspace @@ -741,7 +771,7 @@ else drawDirHeaderLines = true; drawMenu = true; refreshWholePromptLine = true; - fileMenuBar.setCurrentActionCode(FILE_DELETE, true); + gFileMenuBar.setCurrentActionCode(FILE_DELETE, true); actionRetObj = doAction(FILE_DELETE, gFileList, gFileListMenu); currentActionVal = FILE_DELETE; } @@ -807,8 +837,8 @@ else refreshWholePromptLine = false; } currentActionVal = NEXT_PAGE; - //fileMenuBar.setCurrentActionCode(NEXT_PAGE, !refreshWholePromptLine); - fileMenuBar.setCurrentActionCode(NEXT_PAGE, true); + //gFileMenuBar.setCurrentActionCode(NEXT_PAGE, !refreshWholePromptLine); + gFileMenuBar.setCurrentActionCode(NEXT_PAGE, true); } else if (userInput == "P" || userInput == KEY_PAGEUP) { @@ -829,8 +859,8 @@ else refreshWholePromptLine = false; } currentActionVal = PREV_PAGE; - //fileMenuBar.setCurrentActionCode(PREV_PAGE, !refreshWholePromptLine); - fileMenuBar.setCurrentActionCode(PREV_PAGE, true); + //gFileMenuBar.setCurrentActionCode(PREV_PAGE, !refreshWholePromptLine); + gFileMenuBar.setCurrentActionCode(PREV_PAGE, true); } else if (userInput == "F" || userInput == KEY_HOME) { @@ -849,8 +879,8 @@ else refreshWholePromptLine = false; } currentActionVal = FIRST_PAGE; - //fileMenuBar.setCurrentActionCode(FIRST_PAGE, !refreshWholePromptLine); - fileMenuBar.setCurrentActionCode(FIRST_PAGE, true); + //gFileMenuBar.setCurrentActionCode(FIRST_PAGE, !refreshWholePromptLine); + gFileMenuBar.setCurrentActionCode(FIRST_PAGE, true); } else if (userInput == "L" || userInput == KEY_END) { @@ -869,16 +899,31 @@ else refreshWholePromptLine = false; } currentActionVal = LAST_PAGE; - //fileMenuBar.setCurrentActionCode(LAST_PAGE, !refreshWholePromptLine); - fileMenuBar.setCurrentActionCode(LAST_PAGE, true); + //gFileMenuBar.setCurrentActionCode(LAST_PAGE, !refreshWholePromptLine); + gFileMenuBar.setCurrentActionCode(LAST_PAGE, true); + } + else if (userInput == "X") + { + // Toggle extended descriptions + var userCanToggle = (Boolean(user.settings & USER_EXTDESC) ? true : userCanEnableExtendedDescriptions()); + if (userCanToggle) + { + user.settings ^= USER_EXTDESC; + allFileInfoLines = []; + for (var i = 0; i < gFileList.length; ++i) + allFileInfoLines = allFileInfoLines.concat(getFileInfoLineArrayForTraditionalUI(gFileList, i, formatInfo)); + topItemIndexForLastPage = allFileInfoLines.length - numLinesPerPage; + drawMenu = true; + drawDirHeaderLines = true; + } } else { drawDirHeaderLines = true; drawMenu = true; refreshWholePromptLine = true; - currentActionVal = fileMenuBar.getActionFromChar(userInput, false); - fileMenuBar.setCurrentActionCode(currentActionVal, true); + currentActionVal = gFileMenuBar.getActionFromChar(userInput, false); + gFileMenuBar.setCurrentActionCode(currentActionVal, true); actionRetObj = doAction(currentActionVal, gFileList, gFileListMenu); } } @@ -992,6 +1037,29 @@ function doAction(pActionCode, pFileList, pFileListMenu) return retObj; } +// Toggles the user's extended descriptions. This is a special action case for the +// lightbar interface which re-creates the lightbar menu, which will behave differently +// depending on whether the user's extended descriptions are enabled or not. +function toggleExtdDescriptionsForUser_Lightbar() +{ + // Toggle extended descriptions + var userCanToggle = (Boolean(user.settings & USER_EXTDESC) ? true : userCanEnableExtendedDescriptions()); + if (userCanToggle) + { + var currentSelectedItemIdx = gFileListMenu.selectedItemIdx; + user.settings ^= USER_EXTDESC; + var listPopRetObj = populateFileList(gScriptMode); + if (listPopRetObj.exitNow) // Shouldn't happen here, but just in case + exit(0); + gFileListMenu = createFileListMenu(gFileMenuBar.getAllActionKeysStr(true, true) + KEY_LEFT + KEY_RIGHT + KEY_DEL /*+ CTRL_C*/); + gFileListMenu.SetSelectedItemIdx(currentSelectedItemIdx); + // If the user has enabled extended descriptions, then write the + // current selected file's extended description on the screen + if (Boolean(user.settings & USER_EXTDESC)) + displayFileExtDescOnMainScreen(gFileListMenu.selectedItemIdx); + } +} + // Returns a string representing an action code, for relevant actions (not necessarily all actions) // // Parameters: @@ -1949,6 +2017,8 @@ function displayHelpScreen() printf(printfStr, "M", "Move the file(s) to another directory"); printf(printfStr, "DEL", "Delete the file(s)"); } + if (userCanEnableExtendedDescriptions()) + printf(printfStr, "X", "Toggle extended descriptions (currently " + (Boolean(user.settings & USER_EXTDESC) ? "on" : "off") + ")"); printf(printfStr, "?", "Show this help screen"); // Ctrl-C for aborting (wanted to use isDoingFileSearch() but it seems even for searching/scanning, // the mode is LIST_DIR rather than a search/scan @@ -2627,7 +2697,6 @@ function DDFileMenuBar(pPos) // The user is not a sysop; there is room for the Edit comand this.cmdArray.push(new DDFileMenuBarItem("Edit", 0, FILE_EDIT)); } - //DDFileMenuBarItem(pItemText, pPos, pRetCode, pHotkeyOverride) if (!gUseLightbarInterface || !console.term_supports(USER_ANSI)) { this.cmdArray.push(new DDFileMenuBarItem("Next", 0, NEXT_PAGE, KEY_PAGEDN)); @@ -2635,6 +2704,16 @@ function DDFileMenuBar(pPos) this.cmdArray.push(new DDFileMenuBarItem("First", 0, FIRST_PAGE)); this.cmdArray.push(new DDFileMenuBarItem("Last", 0, LAST_PAGE)); } + // If the user can enable extended descriptions (terminal size is big enough and the + // user's terminal supports ANSI), add a command ("Xtd") to toggle extended descriptions. + // And if the user's terminal is less than 87 characters wide and using the traditional + // (non-lightbar) user interface and the user is a sysop, don't make it visible because + // there wouldn't be enough room to display it. + if (userCanEnableExtendedDescriptions()) + { + var displayXtdCmdText = !(console.screen_columns < 87 && !gUseLightbarInterface && user.is_sysop); + this.cmdArray.push(new DDFileMenuBarItem("Xtd", 0, TOGGLE_EXTD_DESCS, null, displayXtdCmdText)); + } this.cmdArray.push(new DDFileMenuBarItem("?", 0, HELP)); this.cmdArray.push(new DDFileMenuBarItem("Quit", 0, QUIT)); @@ -2648,12 +2727,19 @@ function DDFileMenuBar(pPos) // Return value: The number of additional solid blocks used to fill the whole screen row function DDFileMenuBar_constructPromptText() { + var numDisplayableItems = 0; var totalItemTextLen = 0; for (var i = 0; i < this.cmdArray.length; ++i) - totalItemTextLen += this.cmdArray[i].itemText.length; + { + if (this.cmdArray[i].displayItem) + { + ++numDisplayableItems; + totalItemTextLen += this.cmdArray[i].itemText.length; + } + } // The number of inner characters (without the outer solid blocks) is the total text // length of all the items + 2 characters for each item except the last one - var numInnerChars = totalItemTextLen + (2 * (this.cmdArray.length-1)); + var numInnerChars = totalItemTextLen + (2 * (numDisplayableItems-1)); // The number of solid blocks: Subtracting 11 because there will be 5 block characters on each side, // and subtract 1 extra so it doesn't fill the last character on the screen var numSolidBlocks = console.screen_columns - numInnerChars - 11; @@ -2665,8 +2751,13 @@ function DDFileMenuBar_constructPromptText() this.promptText += THIN_RECTANGLE_LEFT; // Add the menu item text & block characters var menuItemXPos = 6 + numSolidBlocksPerSide; // The X position of the start of item text for each item + var maxPromptLineLen = console.screen_columns - 1; // Maximum length of the prompt line for (var i = 0; i < this.cmdArray.length; ++i) { + // If the current item's displayItem property is false, then skip it. + if (!this.cmdArray[i].displayItem) + continue; + this.cmdArray[i].pos = menuItemXPos; var numTrailingBlockChars = 0; var selected = (i == this.currentCommandIdx); @@ -2676,8 +2767,17 @@ function DDFileMenuBar_constructPromptText() withTrailingBlock = true; numTrailingBlockChars = 2; } - menuItemXPos += this.cmdArray[i].itemText.length + numTrailingBlockChars; - this.promptText += this.getDDFileMenuBarItemText(this.cmdArray[i].itemText, selected, withTrailingBlock); + //menuItemXPos += this.cmdArray[i].itemText.length + numTrailingBlockChars; + //this.promptText += this.getDDFileMenuBarItemText(this.cmdArray[i].itemText, selected, withTrailingBlock); + + // If the line with this item text would be short enough to fit on the screen, + // then add this item's text + var numCharsNeeded = this.cmdArray[i].itemText.length + numTrailingBlockChars; + if (console.strlen(this.promptText) + numCharsNeeded + numSolidBlocksPerSide <= maxPromptLineLen) + { + menuItemXPos += this.cmdArray[i].itemText.length + numTrailingBlockChars; + this.promptText += this.getDDFileMenuBarItemText(this.cmdArray[i].itemText, selected, withTrailingBlock); + } } // Add the right-side blocks this.promptText += "\x01w" + THIN_RECTANGLE_RIGHT; @@ -2708,7 +2808,9 @@ function DDFileMenuBar_refreshWithNewAction(pCmdIdx) { if (typeof(pCmdIdx) !== "number") return; - if (pCmdIdx == this.currentCommandIdx) + if (pCmdIdx == this.currentCommandIdx || pCmdIdx < 0 || pCmdIdx >= this.cmdArray.length) + return; + if (!this.cmdArray[pCmdIdx].displayItem) return; // Refresh the prompt area for the previous index with regular colors @@ -2767,8 +2869,14 @@ function DDFileMenuBar_getDDFileMenuBarItemText(pText, pSelected, pWithTrailingB function DDFileMenuBar_incrementMenuItemAndRefresh() { var newCmdIdx = this.currentCommandIdx + 1; + while (newCmdIdx < this.cmdArray.length && !this.cmdArray[newCmdIdx].displayItem) + ++newCmdIdx; if (newCmdIdx >= this.cmdArray.length) + { newCmdIdx = 0; + while (newCmdIdx < this.currentCommandIdx && !this.cmdArray[newCmdIdx].displayItem) + ++newCmdIdx; + } // Will set this.currentCommandIdx this.refreshWithNewAction(newCmdIdx); } @@ -2777,8 +2885,14 @@ function DDFileMenuBar_incrementMenuItemAndRefresh() function DDFileMenuBar_decrementMenuItemAndRefresh() { var newCmdIdx = this.currentCommandIdx - 1; + while (newCmdIdx > 0 && !this.cmdArray[newCmdIdx].displayItem) + --newCmdIdx; if (newCmdIdx < 0) + { newCmdIdx = this.cmdArray.length - 1; + while (newCmdIdx > this.currentCommandIdx && !this.cmdArray[newCmdIdx].displayItem) + --newCmdIdx; + } // Will set this.currentCommandIdx this.refreshWithNewAction(newCmdIdx); } @@ -2850,7 +2964,7 @@ function DDFileMenuBar_setCurrentActionCode(pActionCode, pRefreshOnScreen) { if (this.cmdArray[i].retCode == pActionCode) { - if (refreshOnScreen) + if (refreshOnScreen && this.cmdArray[i].displayItem) this.refreshWithNewAction(i); else { @@ -2890,8 +3004,9 @@ function DDFileMenuBar_getAllActionKeysStr(pLowercase, pUppercase) // pItemText: The text of the item // pPos: Horizontal (or vertical) starting location in the bar // pRetCode: The item's return code -// pHotkeyOverride: Optional: A key to use for the action instead of the first character in pItemText -function DDFileMenuBarItem(pItemText, pPos, pRetCode, pHotkeyOverride) +// pHotkeyOverride: Optional - A key to use for the action instead of the first character in pItemText +// pDisplayItem: Optional - Whether or not this item should be displayed on the menu bar. Defaults to true. +function DDFileMenuBarItem(pItemText, pPos, pRetCode, pHotkeyOverride, pDisplayItem) { this.itemText = pItemText; this.pos = pPos; @@ -2899,6 +3014,7 @@ function DDFileMenuBarItem(pItemText, pPos, pRetCode, pHotkeyOverride) this.hotkeyOverride = null; if (pHotkeyOverride != null && typeof(pHotkeyOverride) !== "undefined") this.hotkeyOverride = pHotkeyOverride; + this.displayItem = (typeof(pDisplayItem) === "boolean" ? pDisplayItem : true); } @@ -3326,7 +3442,6 @@ function displayListHdrLine(pMoveToLocationFirst, pNumberedMode) // Return value: The DDLightbarMenu object for the file list in the file directory function createFileListMenu(pQuitKeys) { - //DDLightbarMenu(pX, pY, pWidth, pHeight) // Create the menu object. Place it below the header lines (which should have been written // before this), and also leave 1 row at the bottom for the prompt line var startRow = gNumHeaderLinesDisplayed > 0 ? gNumHeaderLinesDisplayed + 1 : 1; @@ -4577,7 +4692,7 @@ function populateFileList(pSearchMode) exitNow: false, exitCode: 0 }; - + var dirErrors = []; var allSameDir = true; @@ -5160,6 +5275,13 @@ function extendedDescEnabled() return userExtDescEnabled && console.screen_columns >= 80 && gUseLightbarInterface && console.term_supports(USER_ANSI); } +// Returns whether the user can enable extended descriptions (depends on their terminal size and whether +// their terminal can use ANSI) +function userCanEnableExtendedDescriptions() +{ + return console.screen_columns >= 80 && console.term_supports(USER_ANSI); +} + // Displays a file's extended description on the main screen, next to the // file list menu. This is to be used when the user's extended file description // option is enabled (where the menu would take up about the left half of @@ -5230,10 +5352,15 @@ function displayFileExtDescOnMainScreen(pFileIdx, pStartScreenRow, pEndScreenRow fileDesc = removeOrReplaceSyncCursorMovementChars(fileDesc); // If there is no description and the option to use the filename is enabled, then use the // filename. - if (gUseFilenameIfNoDescription && (fileDesc == "" || /^\s+$/.test(fileDesc))) + var fileDescIsEmptyOrWhitespace = (fileDesc == "" || /^\s+$/.test(fileDesc)); + if (gUseFilenameIfNoDescription && fileDescIsEmptyOrWhitespace) fileDesc = lfexpand(word_wrap(fileMetadata.name + "\r\n(No description)", maxDescLen, null, false)); + // If there is a description and the filename is too long to fit on the menu, then prepend the + // full filename (wrapped) to the the description + else if (!fileDescIsEmptyOrWhitespace && fileMetadata.name.length > gFileListMenu.filenameLen) + fileDesc = lfexpand(word_wrap(fileMetadata.name, maxDescLen, null, false)) + "\r\n" + fileDesc; + // Display the description on the screen var fileDescArray = fileDesc.split("\r\n"); - //if (user.is_sysop) console.print("\x01nfileDescArray is array: " + Array.isArray(fileDescArray) + " \x01p"); // Temporary console.attributes = "N"; // screenRowNum is to keep track of the row on the screen where the // description line would be placed, in case the start row is after that @@ -5498,9 +5625,8 @@ function getFileInfoLineArrayForTraditionalUI(pFileList, pIdx, pFormatInfo) if (pFileList[pIdx] == undefined) return []; - var userExtDescEnabled = ((user.settings & USER_EXTDESC) == USER_EXTDESC); var descLines; - if (userExtDescEnabled) + if (Boolean(user.settings & USER_EXTDESC)) // If extended descriptions descLines = getExtdFileDescArray(pFileList, pIdx); else { @@ -5510,14 +5636,38 @@ function getFileInfoLineArrayForTraditionalUI(pFileList, pIdx, pFormatInfo) if (!Array.isArray(descLines)) descLines = []; if (descLines.length == 0) - descLines.push(""); + { + // There is no description. If the option to use the filename is enabled, then use the filename. + if (gUseFilenameIfNoDescription) + { + var fileDesc = lfexpand(word_wrap(pFileList[pIdx].name + "\r\n(No description)", pFormatInfo.descLen, null, false)); + var fileDescArray = fileDesc.split("\r\n"); + for (var i = 0; i < fileDescArray.length; ++i) + descLines.push(fileDescArray[i]); + } + else + descLines.push(""); + } + else + { + // If the filename is too long to fit on the menu, then prepend the full filename (wrapped) to + // the the description. + if (pFileList[pIdx].name.length > gFileListMenu.filenameLen) + { + var filenameLines = []; + var fileDescArray = lfexpand(word_wrap(pFileList[pIdx].name, pFormatInfo.descLen, null, false)).split("\r\n"); + for (var i = 0; i < fileDescArray.length; ++i) + filenameLines.push(fileDescArray[i]); + descLines = filenameLines.concat(descLines); + } + } var filename = shortenFilename(pFileList[pIdx].name, pFormatInfo.filenameLen, true); // Note: substrWithAttrCodes() is defined in dd_lightbar_menu.js var fileInfoLines = []; var fileSizeStr = file_size_str(pFileList[pIdx].size, null, FILE_SIZE_PRECISION); fileInfoLines.push(format(pFormatInfo.formatStr, pIdx+1, filename, fileSizeStr.substr(0, pFormatInfo.fileSizeLen), substrWithAttrCodes(descLines[0], 0, pFormatInfo.descLen))); - if (userExtDescEnabled) + if (Boolean(user.settings & USER_EXTDESC)) // If extended descriptions { for (var i = 1; i < descLines.length; ++i) fileInfoLines.push(format(pFormatInfo.formatStrExtdDescLines, substrWithAttrCodes(descLines[i], 0, pFormatInfo.descLen))); diff --git a/xtrn/ddfilelister/readme.txt b/xtrn/ddfilelister/readme.txt index 8ceb186fc070540f43aa1420b64a44a9fa4f295e..56bc50dbe15406671f2ec40db952611a2c40eb18 100644 --- a/xtrn/ddfilelister/readme.txt +++ b/xtrn/ddfilelister/readme.txt @@ -1,6 +1,6 @@ Digital Distortion File Lister - Version 2.27 - Release date: 2025-02-20 + Version 2.28 + Release date: 2025-02-22 by @@ -35,10 +35,10 @@ that there are no serious issues with it (at least, none that I have seen). 2. Introduction =============== -This release is version 2.00 because I had previously released a message lister -mod for Synchronet which was just a list header and a command bar to display -under the list, and it still used Synchronet's stock file list. Now that -Synchronet provides a JavaScript interface to its filebases (as of version +This release is version 2.## because I had previously released a message lister +mod (version 1.##) for Synchronet which was just a list header and a command bar +to display under the list, and it still used Synchronet's stock file list. Now +that Synchronet provides a JavaScript interface to its filebases (as of version 3.19), more customization is possible with JavaScript. Digital Distortion File Lister is a script for Synchronet that provides an @@ -59,6 +59,21 @@ side. If the user's extended file description setting is disabled, the lightbar file menu will use the entire width of the screen, with the short file descriptions being displayed in a single row with each file. +In order to display extended descriptions, however, this file lister currently +requires ANSI support (for cursor movements & such) and a terminal width of at +least 80 characters in order to display everything, since the extended +descriptions will be displayed to the right of the menu. If the user's terminal +doesn't meet these requirements, short descriptions will be displayed. + +The user can toggle extended descriptions on/off from within this file lister +using the X key. However, if the user's terminal doesn't meet the above +requiremtnts for extended description mode, the user won't be able to toggle +extended descriptions from within this file lister. + +If a filename is too long to be fully displayed in the menu item, the full file +description will be displayed above the description (wrapped to the description +area width) if extended descriptions are enabled. + When adding files to the user's batch download queue or (for the sysop) selecting files to move or delete, multi-select mode can be used, allowing the user to select multiple files using the spacebar. If the spacebar is not diff --git a/xtrn/ddfilelister/revision_history.txt b/xtrn/ddfilelister/revision_history.txt index 36836b7a443ca153caabd9bcfc01ff89534b4004..40a507001d932fd06915a178ed49cad518678322 100644 --- a/xtrn/ddfilelister/revision_history.txt +++ b/xtrn/ddfilelister/revision_history.txt @@ -5,6 +5,13 @@ Revision History (change log) ============================= Version Date Description ------- ---- ----------- +2.28 2025-02-22 If extended descriptions are enabled and a filename is + too long to fully fit in the menu, prepend the full + filename (wrapped) to the description. + New bottom line menu option to toggle extended + descriptions on/off + Fix: useFilenameIfNoDescription option now used in + traditional (non-lightbar) mode. 2.27 2025-02-20 Now optionally displays the number of files in the directory in the header at the top of the list, configurable with the displayNumFilesInHeader option in