diff --git a/docs/slyedit_readme.txt b/docs/slyedit_readme.txt index 6b8de55021798fc1d02417fce91f495f523112f5..6bb810477a1886ce52cc71249053863dfe7e9891 100644 --- a/docs/slyedit_readme.txt +++ b/docs/slyedit_readme.txt @@ -1,13 +1,13 @@ SlyEdit message editor - Version 1.83 - Release date: 2022-12-14 + Version 1.84 + Release date: 2023-02-10 by Eric Oulashin Sysop of Digital Distortion BBS BBS internet address: digitaldistortionbbs.com - Alternate: digdist.synchro.net + Alternate: digdist.synchro.net Email: eric.oulashin@gmail.com @@ -918,6 +918,10 @@ message to lower-case and comparing them with the words in the dictionary. =================== Version Date Description ------- ---- ----------- +1.84 2023-02-10 Sysops: When importing a file from the BBS machine, + SlyEdit now prompts to send it immediately or not (if + not, edit it before sending). Sending immediately can be + useful for posting ANSI files unmodified. 1.83 2022-12-13 Quote lines that are wider than the user's terminal width are now wrapped to the user's terminal width to ensure all the quote lines are entirely available to be quoted. diff --git a/exec/SlyEdit.js b/exec/SlyEdit.js index 4212fe739464bdc164ff6e50942cfa497e555719..62fba8b228993137412e82975ff65c6d67b5845c 100644 --- a/exec/SlyEdit.js +++ b/exec/SlyEdit.js @@ -25,6 +25,11 @@ * Quote lines that are wider than the user's terminal width are * now wrapped to the user's terminal width to ensure all the * quote lines are entirely available to be quoted. + * 2023-02-10 Eric Oulashin Version 1.84 + * Sysops: When importing a file from the BBS machine, SlyEdit now + * prompts to send it immediately or not (if not, edit it before + * sending). Sending immediately can be useful for posting + * ANSI files unmodified. */ "use strict"; @@ -94,12 +99,12 @@ const SPELL_CHECK_PAUSE_MS = 1000; // This script requires Synchronet version 3.14 or higher. // Exit if the Synchronet version is below the minimum. -if (system.version_num < 31400) +if (system.version_num < 31500) // 3.15 for user.is_sysop { console.print("\x01n"); console.crlf(); console.print("\x01n\x01h\x01y\x01i* Warning:\x01n\x01h\x01w " + EDITOR_PROGRAM_NAME); - console.print(" " + "requires version \x01g3.14\x01w or"); + console.print(" " + "requires version \x01g3.15\x01w or"); console.crlf(); console.print("higher of Synchronet. This BBS is using version \x01g"); console.print(system.version + "\x01w. Please notify the sysop."); @@ -122,8 +127,8 @@ if (console.screen_columns < 80) } // Version information -var EDITOR_VERSION = "1.83"; -var EDITOR_VER_DATE = "2022-12-14"; +var EDITOR_VERSION = "1.84"; +var EDITOR_VER_DATE = "2023-02-10"; // Program variables @@ -1144,7 +1149,7 @@ function doEditLoop() break; case CMDLIST_HELP_KEY: case CMDLIST_HELP_KEY_2: - displayCommandList(true, true, true, gCanCrossPost, gConfigSettings.userIsSysop, + displayCommandList(true, true, true, gCanCrossPost, gConfigSettings.enableTextReplacements, gConfigSettings.allowUserSettings, gConfigSettings.allowSpellCheck, gConfigSettings.allowColorSelection); clearEditAreaBuffer(); @@ -1497,7 +1502,7 @@ function doEditLoop() else if (enterRetObj.showHelp) { displayProgramInfo(true, false); - displayCommandList(false, false, true, gCanCrossPost, gConfigSettings.userIsSysop, + displayCommandList(false, false, true, gCanCrossPost, gConfigSettings.enableTextReplacements, gConfigSettings.allowUserSettings, gConfigSettings.allowSpellCheck, gConfigSettings.allowColorSelection); clearEditAreaBuffer(); @@ -1560,20 +1565,22 @@ function doEditLoop() break; case IMPORT_FILE_KEY: // Only let sysops import files. - if (gConfigSettings.userIsSysop) + if (user.is_sysop) { - var importRetObj = importFile(gConfigSettings.userIsSysop, curpos); + var importRetObj = importFile(curpos); curpos.x = importRetObj.x; curpos.y = importRetObj.y; currentWordLength = importRetObj.currentWordLength; - console.print(chooseEditColor()); // Make sure the edit color is correct + continueOn = !importRetObj.sendImmediately; + if (continueOn) + console.print(chooseEditColor()); // Make sure the edit color is correct } break; case EXPORT_TO_FILE_KEY: // Only let sysops export/save the message to a file. - if (gConfigSettings.userIsSysop) + if (user.is_sysop) { - exportToFile(gConfigSettings.userIsSysop); + exportToFile(); console.print(chooseEditColor()); // Make sure the edit color is correct console.gotoxy(curpos); } @@ -3488,7 +3495,7 @@ function callDCTESCMenu(pCurpos) var editLineDiff = pCurpos.y - gEditTop; var chosenAction = doDCTESCMenu(gEditLeft, gEditRight, gEditTop, displayMessageRectangle, gEditLinesIndex, - editLineDiff, gConfigSettings.userIsSysop, gCanCrossPost); + editLineDiff, gCanCrossPost); return chosenAction; } // Shows the ESC menu (different, depending on the UI style) and takes action @@ -3505,6 +3512,7 @@ function callDCTESCMenu(pCurpos) // x: The horizontal component of the cursor position // y: The vertical component of the cursor position // currentWordLength: The length of the current word +// sendImmediately: Boolean - Whether or not to send immediately (i.e., if importing a file) function doESCMenu(pCurpos, pCurrentWordLength) { var returnObj = { @@ -3536,18 +3544,19 @@ function doESCMenu(pCurpos, pCurrentWordLength) toggleInsertMode(pCurpos); break; case ESC_MENU_SYSOP_IMPORT_FILE: - if (gConfigSettings.userIsSysop) + if (user.is_sysop) { - var retval = importFile(gConfigSettings.userIsSysop, pCurpos); + var retval = importFile(pCurpos); returnObj.x = retval.x; returnObj.y = retval.y; returnObj.currentWordLength = retval.currentWordLength; + returnObj.continueOn = !retval.sendImmediately; } break; case ESC_MENU_SYSOP_EXPORT_FILE: - if (gConfigSettings.userIsSysop) + if (user.is_sysop) { - exportToFile(gConfigSettings.userIsSysop); + exportToFile(); console.gotoxy(returnObj.x, returnObj.y); } break; @@ -3557,7 +3566,7 @@ function doESCMenu(pCurpos, pCurrentWordLength) returnObj.y = retval.y; break; case ESC_MENU_HELP_COMMAND_LIST: - displayCommandList(true, true, true, gCanCrossPost, gConfigSettings.userIsSysop, + displayCommandList(true, true, true, gCanCrossPost, gConfigSettings.enableTextReplacements, gConfigSettings.allowUserSettings, gConfigSettings.allowSpellCheck, gConfigSettings.allowColorSelection); clearEditAreaBuffer(); @@ -3787,23 +3796,24 @@ function insertLineIntoMsg(pInsertLineIndex, pString, pHardNewline, pIsQuoteLine // // Parameters: // pIsSysop: Whether or not the user is the sysop -// pCurpos: The current cursor position (with x and y properties) // // Return value: An object containing the following information: // x: The horizontal component of the cursor's location // y: The vertical component of the cursor's location // currentWordLength: The length of the current word -function importFile(pIsSysop, pCurpos) +// sendImmediately: Boolean - Whether or not to send the message immediately +function importFile(pCurpos) { // Create the return object var retObj = { x: pCurpos.x, y: pCurpos.y, - currentWordLength: getWordLength(gEditLinesIndex, gTextLineIndex) - } + currentWordLength: getWordLength(gEditLinesIndex, gTextLineIndex), + sendImmediately: false + }; // Don't let non-sysops do this. - if (!pIsSysop) + if (!user.is_sysop) return retObj; var loadedAFile = false; @@ -3829,40 +3839,63 @@ function importFile(pIsSysop, pCurpos) var inFile = new File(filename); if (inFile.exists && inFile.open("r")) { - const maxLineLength = gEditWidth - 1; // Don't insert lines longer than this - var fileLine; - while (!inFile.eof) + // Prompt if the user wants to send the file as-is or import into the edit area + //promptYesNo(pQuestion, pDefaultYes, pBoxTitle, pIceRefreshForBothAnswers, pAlwaysEraseBox) + retObj.sendImmediately = promptYesNo("Send immediately", true, "Send", true, true); + var fileLine = ""; + if (retObj.sendImmediately) + { + while (!inFile.eof) + { + // Read the next line from the file + fileLine = inFile.readln(2048); + // fileLine should be a string, but I've seen some cases + // where for some reason it isn't. If it's not a string, + // then continue onto the next line. + if (typeof(fileLine) != "string") + continue; + // Add the line to gEditLines + // TODO: It seems this isn't populating gEditLines and + // it's sending an empty message. + gEditLines.push(new TextLine(fileLine, true, false)); + } + } + else { - fileLine = inFile.readln(1024); - // fileLine should always be a string, but there seem to be - // situations where it isn't. So if it's a string, we can - // insert text into gEditLines as normal. If it's not a - // string, insert a blank line. - if (typeof(fileLine) == "string") + const maxLineLength = gEditWidth - 1; // Don't insert lines longer than this + while (!inFile.eof) { - // Tab characters can cause problems, so replace tabs with 3 spaces. - fileLine = fileLine.replace(/\t/, " "); - // Insert the line into the message, splitting up the line, - // if the line is longer than the edit area. - do + fileLine = inFile.readln(1024); + // fileLine should always be a string, but there seem to be + // situations where it isn't. So if it's a string, we can + // insert text into gEditLines as normal. If it's not a + // string, insert a blank line. + if (typeof(fileLine) == "string") { - insertLineIntoMsg(gEditLinesIndex, fileLine.substr(0, maxLineLength), - true, false); - fileLine = fileLine.substr(maxLineLength); - ++gEditLinesIndex; - } while (fileLine.length > maxLineLength); - // Edge case, if the line still has characters in it - if (fileLine.length > 0) + // Tab characters can cause problems, so replace tabs with 3 spaces. + fileLine = fileLine.replace(/\t/, " "); + // Insert the line into the message, splitting up the line, + // if the line is longer than the edit area. + do + { + insertLineIntoMsg(gEditLinesIndex, fileLine.substr(0, maxLineLength), + true, false); + fileLine = fileLine.substr(maxLineLength); + ++gEditLinesIndex; + } while (fileLine.length > maxLineLength); + // Edge case, if the line still has characters in it + if (fileLine.length > 0) + { + insertLineIntoMsg(gEditLinesIndex, fileLine, true, false); + ++gEditLinesIndex; + } + } + else { - insertLineIntoMsg(gEditLinesIndex, fileLine, true, false); + insertLineIntoMsg(gEditLinesIndex, "", true, false); ++gEditLinesIndex; } } - else - { - insertLineIntoMsg(gEditLinesIndex, "", true, false); - ++gEditLinesIndex; - } } inFile.close(); @@ -3887,8 +3920,8 @@ function importFile(pIsSysop, pCurpos) // Refresh the help line on the bottom of the screen fpDisplayBottomHelpLine(console.screen_rows, gUseQuotes); - // If we loaded a file, then refresh the message text. - if (loadedAFile) + // If not sending immediately and we loaded a file, then refresh the message text. + if (!retObj.sendImmediately && loadedAFile) { // Insert a blank line into gEditLines so that the user ends up on a new // blank line. @@ -3936,13 +3969,10 @@ function importFile(pIsSysop, pCurpos) // This function lets sysops export (save) the current message to // a file. -// -// Parameters: -// pIsSysop: Whether or not the user is the sysop -function exportToFile(pIsSysop) +function exportToFile() { // Don't let non-sysops do this. - if (!pIsSysop) + if (!user.is_sysop) return; // Go to the last row on the screen and prompt the user for a filename diff --git a/exec/SlyEdit_DCTStuff.js b/exec/SlyEdit_DCTStuff.js index c244e557c83f9a155164c5acdc85c9fef7b5636d..57eb98fc8b22e2e8166416f438fe5ea0344e4c46 100644 --- a/exec/SlyEdit_DCTStuff.js +++ b/exec/SlyEdit_DCTStuff.js @@ -686,12 +686,11 @@ function displayTimeRemaining_DCTStyle() // function. // pEditLineDiff: The difference between the current edit line and the top of // the edit area. -// pIsSysop: Whether or not the user is a sysop. // pCanCrossPost: Whether or not cross-posting is allowed. // // Return value: The action code, based on the user's selection function doDCTESCMenu(pEditLeft, pEditRight, pEditTop, pDisplayMessageRectangle, - pEditLinesIndex, pEditLineDiff, pIsSysop, pCanCrossPost) + pEditLinesIndex, pEditLineDiff, pCanCrossPost) { // This function displays the top menu options, with a given one highlighted. // @@ -699,10 +698,9 @@ function doDCTESCMenu(pEditLeft, pEditRight, pEditTop, pDisplayMessageRectangle, // pItemPositions: An object containing the menu item positions. // pHighlightedItemNum: The index (0-based) of the menu item to be highlighted. // pMenus: An array containing the menus - // pIsSysop: Whether or not the user is the sysop. // // Return value: The user's last keypress during the menu's input loop. - function displayTopMenuItems(pItemPositions, pHighlightedItemNum, pMenus, pIsSysop) + function displayTopMenuItems(pItemPositions, pHighlightedItemNum, pMenus) { // File console.gotoxy(pItemPositions.fileX, pItemPositions.mainMenuY); @@ -725,7 +723,7 @@ function doDCTESCMenu(pEditLeft, pEditRight, pEditTop, pDisplayMessageRectangle, else console.print("\x01n " + gConfigSettings.DCTColors.UnselectedMenuLabelText + "Edit\x01n "); // SysOp - if (pIsSysop) + if (user.is_sysop) { console.gotoxy(pItemPositions.sysopX, pItemPositions.mainMenuY); if (pHighlightedItemNum == 2) @@ -780,7 +778,7 @@ function doDCTESCMenu(pEditLeft, pEditRight, pEditTop, pDisplayMessageRectangle, doDCTESCMenu.mainMenuItemPositions.editX = doDCTESCMenu.mainMenuItemPositions.fileX + 11; doDCTESCMenu.mainMenuItemPositions.sysopX = doDCTESCMenu.mainMenuItemPositions.editX + 11; // Horizontal position of of the "Help" text - if (pIsSysop) + if (user.is_sysop) doDCTESCMenu.mainMenuItemPositions.helpX = doDCTESCMenu.mainMenuItemPositions.sysopX + 12; else doDCTESCMenu.mainMenuItemPositions.helpX = doDCTESCMenu.mainMenuItemPositions.sysopX; @@ -869,20 +867,20 @@ function doDCTESCMenu(pEditLeft, pEditRight, pEditTop, pDisplayMessageRectangle, var menuNum = fileMenuNum; // 0: File, ..., 3: Help var subMenuItemNum = 0; var menuRetObj = displayTopMenuItems(doDCTESCMenu.mainMenuItemPositions, menuNum, - doDCTESCMenu.allMenus, pIsSysop); + doDCTESCMenu.allMenus); // Input loop var userInput = ""; var matchedMenuRetval = false; // Whether one of the menu return values was matched var continueOn = true; while (continueOn) { - matchedMenuRetval = valMatchesMenuCode(menuRetObj.returnVal, pIsSysop); + matchedMenuRetval = valMatchesMenuCode(menuRetObj.returnVal); // If a menu return value was matched, then set userInput to it. if (matchedMenuRetval) userInput = menuRetObj.returnVal; // If the user's input from the last menu was ESC, left, right, or one of the // characters from the menus, then set userInput to the last menu keypress. - else if (inputMatchesMenuSelection(menuRetObj.userInput, pIsSysop)) + else if (inputMatchesMenuSelection(menuRetObj.userInput)) userInput = menuRetObj.userInput; // If nothing from the menu was matched, then get a key from the user. else @@ -903,10 +901,10 @@ function doDCTESCMenu(pEditLeft, pEditRight, pEditTop, pDisplayMessageRectangle, else --menuNum; // Don't allow the sysop menu for non-sysops. - if ((menuNum == sysopMenuNum) && !pIsSysop) + if ((menuNum == sysopMenuNum) && !user.is_sysop) --menuNum; subMenuItemNum = 0; - menuRetObj = displayTopMenuItems(doDCTESCMenu.mainMenuItemPositions, menuNum, doDCTESCMenu.allMenus, pIsSysop); + menuRetObj = displayTopMenuItems(doDCTESCMenu.mainMenuItemPositions, menuNum, doDCTESCMenu.allMenus); break; case KEY_RIGHT: if (menuNum == 3) @@ -914,10 +912,10 @@ function doDCTESCMenu(pEditLeft, pEditRight, pEditTop, pDisplayMessageRectangle, else ++menuNum; // Don't allow the sysop menu for non-sysops. - if ((menuNum == sysopMenuNum) && !pIsSysop) + if ((menuNum == sysopMenuNum) && !user.is_sysop) ++menuNum; subMenuItemNum = 0; - menuRetObj = displayTopMenuItems(doDCTESCMenu.mainMenuItemPositions, menuNum, doDCTESCMenu.allMenus, pIsSysop); + menuRetObj = displayTopMenuItems(doDCTESCMenu.mainMenuItemPositions, menuNum, doDCTESCMenu.allMenus); break; case KEY_UP: case KEY_DOWN: @@ -982,13 +980,13 @@ function doDCTESCMenu(pEditLeft, pEditRight, pEditTop, pDisplayMessageRectangle, // Import file (sysop only) else if (userInput == DCTMENU_SYSOP_IMPORT_FILE) { - if (pIsSysop) + if (user.is_sysop) chosenAction = ESC_MENU_SYSOP_IMPORT_FILE; } // Import file for sysop, or Insert/Overwrite toggle for non-sysop else if (userInput == "I") { - if (pIsSysop) + if (user.is_sysop) chosenAction = ESC_MENU_SYSOP_IMPORT_FILE; else chosenAction = ESC_MENU_INS_OVR_TOGGLE; @@ -1008,7 +1006,7 @@ function doDCTESCMenu(pEditLeft, pEditRight, pEditTop, pDisplayMessageRectangle, // Export the message else if ((userInput == "X") || (userInput == DCTMENU_SYSOP_EXPORT_FILE)) { - if (pIsSysop) + if (user.is_sysop) chosenAction = ESC_MENU_SYSOP_EXPORT_FILE; } // Edit the message @@ -1041,10 +1039,9 @@ function doDCTESCMenu(pEditLeft, pEditRight, pEditTop, pDisplayMessageRectangle, // // Parameters: // pVal: The value to test -// pIsSysop: Whether or not the user is a sysop // // Return: Boolean - Whether or not the value matches a DCT Edit menu return value. -function valMatchesMenuCode(pVal, pIsSysop) +function valMatchesMenuCode(pVal) { var valMatches = false; valMatches = ((pVal == DCTMENU_FILE_SAVE) || (pVal == DCTMENU_FILE_ABORT) || @@ -1054,7 +1051,7 @@ function valMatchesMenuCode(pVal, pIsSysop) (pVal == DCTMENU_EDIT_SETTINGS) || (pVal == DCTMENU_EDIT_SPELL_CHECKER)); if (gConfigSettings.enableTextReplacements) valMatches = (valMatches || (pVal == DCTMENU_LIST_TXT_REPLACEMENTS)); - if (pIsSysop) + if (user.is_sysop) valMatches = (valMatches || (pVal == DCTMENU_SYSOP_IMPORT_FILE) || (pVal == DCTMENU_SYSOP_EXPORT_FILE)); return valMatches; } @@ -1064,13 +1061,12 @@ function valMatchesMenuCode(pVal, pIsSysop) // // Parameters: // pInput: The user input to test -// pIsSysop: Whether or not the user is a sysop -function inputMatchesMenuSelection(pInput, pIsSysop) +function inputMatchesMenuSelection(pInput) { return((pInput == KEY_ESC) || (pInput == KEY_LEFT) || (pInput == KEY_RIGHT) || (pInput == KEY_ENTER) || (pInput == "S") || (pInput == "A") || (pInput == "E") || - (pInput == "I") || (pIsSysop && (pInput == "X")) || + (pInput == "I") || (user.is_sysop && (pInput == "X")) || (pInput == "F") || (pInput == "C") || (pInput == "G") || (pInput == "P") || (pInput == "T")); } diff --git a/exec/SlyEdit_Misc.js b/exec/SlyEdit_Misc.js index ab5445ccaa78fe44f65c7dba2e792fdcc4fe8f49..f9ff2b0d64c3e11d79fea66e7c59e87456080080 100644 --- a/exec/SlyEdit_Misc.js +++ b/exec/SlyEdit_Misc.js @@ -1798,13 +1798,12 @@ function displayHelpHeader() // pClear: Whether or not to clear the screen first // pPause: Whether or not to pause at the end // pCanCrossPost: Whether or not cross-posting is enabled -// pIsSysop: Whether or not the user is the sysop. // pTxtReplacments: Whether or not the text replacements feature is enabled // pUserSettings: Whether or not the user settings feature is enabled // pSpellCheck: Whether or not spell check is allowed // pCanChangeColor: Whether or not changing text color is allowed -function displayCommandList(pDisplayHeader, pClear, pPause, pCanCrossPost, pIsSysop, - pTxtReplacments, pUserSettings, pSpellCheck, pCanChangeColor) +function displayCommandList(pDisplayHeader, pClear, pPause, pCanCrossPost, pTxtReplacments, + pUserSettings, pSpellCheck, pCanChangeColor) { if (pClear) console.clear("\x01n"); @@ -1814,8 +1813,6 @@ function displayCommandList(pDisplayHeader, pClear, pPause, pCanCrossPost, pIsSy console.crlf(); } - var isSysop = (pIsSysop != null ? pIsSysop : user.compare_ars("SYSOP")); - // This function displays a key and its description with formatting & colors. // // Parameters: @@ -1879,7 +1876,7 @@ function displayCommandList(pDisplayHeader, pClear, pPause, pCanCrossPost, pIsSy remainingHotkeysAndDescriptions.push(makeHotkeyAndDescObj("Ctrl-K", "Change text color")); if (pSpellCheck) remainingHotkeysAndDescriptions.push(makeHotkeyAndDescObj("Ctrl-R", "Spell checker")); - if (isSysop) + if (user.is_sysop) { remainingHotkeysAndDescriptions.push(makeHotkeyAndDescObj("Ctrl-O", "Import a file")); remainingHotkeysAndDescriptions.push(makeHotkeyAndDescObj("Ctrl-X", "Export to file")); @@ -2081,7 +2078,6 @@ function promptYesNo(pQuestion, pDefaultYes, pBoxTitle, pIceRefreshForBothAnswer function ReadSlyEditConfigFile() { var cfgObj = { - userIsSysop: user.compare_ars("SYSOP"), // Whether or not the user is a sysop // Default settings thirdPartyLoadOnStart: [], runJSOnStart: [],