Skip to content
Snippets Groups Projects
Commit a7640043 authored by Eric Oulashin's avatar Eric Oulashin
Browse files

New: ddmr_cfg.js is a menu-based configurator for Digital Distortion Message...

New: ddmr_cfg.js is a menu-based configurator for Digital Distortion Message Reader. Also, refactored slyedcfg.js a bit to make it a little simpler.
parent 8df3f13c
No related branches found
No related tags found
1 merge request!455Update branch with changes from master
...@@ -25,9 +25,33 @@ var gHelpWrapWidth = uifc.screen_width - 10; ...@@ -25,9 +25,33 @@ var gHelpWrapWidth = uifc.screen_width - 10;
// Read the SlyEdit configuration file // Read the SlyEdit configuration file
var gCfgInfo = readSlyEditCfgFile(); var gCfgInfo = readSlyEditCfgFile();
// Show the main menu and go from there // Show the main menu and go from there.
doMainMenu(); // This is in a loop so that if the user aborts from confirming to save
// settings, they'll return to the main menu.
var anyOptionChanged = false;
var continueOn = true;
while (continueOn)
{
anyOptionChanged = doMainMenu(anyOptionChanged) || anyOptionChanged;
// If any configuration option changed, prompt the user & save if the user wants to
if (anyOptionChanged)
{
var userChoice = promptYesNo("Save configuration?", true, WIN_ORG|WIN_MID|WIN_ACT|WIN_ESC);
if (typeof(userChoice) === "boolean")
{
if (userChoice)
{
if (saveSlyEditCfgFile())
uifc.msg("Changes were successfully saved (to mods dir)");
else
uifc.msg("Failed to save settings!");
}
continueOn = false;
}
}
else
continueOn = false;
}
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
...@@ -36,8 +60,7 @@ doMainMenu(); ...@@ -36,8 +60,7 @@ doMainMenu();
function doMainMenu() function doMainMenu()
{ {
// Create a CTX to specify the current selected item index // Create a CTX to specify the current selected item index
if (doMainMenu.ctx == undefined) var ctx = uifc.list.CTX();
doMainMenu.ctx = uifc.list.CTX();
var helpText = "Behavior: Behavior settings\r\nIce Colors: Ice-related color settings\r\nDCT Colors: DCT-related color settings"; var helpText = "Behavior: Behavior settings\r\nIce Colors: Ice-related color settings\r\nDCT Colors: DCT-related color settings";
// Selection // Selection
var winMode = WIN_ORG|WIN_MID|WIN_ACT|WIN_ESC; var winMode = WIN_ORG|WIN_MID|WIN_ACT|WIN_ESC;
...@@ -47,8 +70,8 @@ function doMainMenu() ...@@ -47,8 +70,8 @@ function doMainMenu()
while (continueOn && !js.terminated) while (continueOn && !js.terminated)
{ {
uifc.help_text = word_wrap(helpText, gHelpWrapWidth); uifc.help_text = word_wrap(helpText, gHelpWrapWidth);
var selection = uifc.list(winMode, menuTitle, ["Behavior", "Ice Colors", "DCT Colors"], doMainMenu.ctx); var selection = uifc.list(winMode, menuTitle, ["Behavior", "Ice Colors", "DCT Colors"], ctx);
doMainMenu.ctx.cur = selection; // Remember the current selected item ctx.cur = selection; // Remember the current selected item
switch (selection) switch (selection)
{ {
case -1: // ESC case -1: // ESC
...@@ -65,19 +88,7 @@ function doMainMenu() ...@@ -65,19 +88,7 @@ function doMainMenu()
break; break;
} }
} }
return anyOptionChanged;
// If any configuration option changed, prompt the user & save if the user wants to
if (anyOptionChanged)
{
var userChoice = promptYesNo("Save configuration?", true, WIN_ORG|WIN_MID|WIN_ACT|WIN_ESC);
if (typeof(userChoice) === "boolean" && userChoice)
{
if (saveSlyEditCfgFile())
uifc.msg("Changes were successfully saved (to mods dir)");
else
uifc.msg("Failed to save settings!");
}
}
} }
// Allows the user to change behavior settings. // Allows the user to change behavior settings.
...@@ -112,8 +123,9 @@ function doBehaviorMenu() ...@@ -112,8 +123,9 @@ function doBehaviorMenu()
"taglinePrefix", "taglinePrefix",
"dictionaryFilenames" "dictionaryFilenames"
]; ];
// Menu item text for the toggle options: // Menu item text for the options:
var toggleOptItems = [ var optionStrs = [
// Toggle options:
"Display end info screen", "Display end info screen",
"Enable user input timeout", "Enable user input timeout",
"Re-wrap quote lines", "Re-wrap quote lines",
...@@ -127,20 +139,34 @@ function doBehaviorMenu() ...@@ -127,20 +139,34 @@ function doBehaviorMenu()
"Enable taglines", "Enable taglines",
"Shuffle taglines", "Shuffle taglines",
"Double-quotes around tag lines", "Double-quotes around tag lines",
"Allow/enable spell check" "Allow/enable spell check",
// Other options:
"User input timeout (MS)",
"Enable text replacements",
"Tagline filename",
"Tagline prefix",
"Dictionary filenames"
]; ];
// Build the array of items to be displayed on the menu // Build the array of items to be displayed on the menu
var menuItems = []; var menuItems = [];
// Toggle (on/off) settings // Toggle (on/off) settings
for (var i = 0; i < 14; ++i) var optionIdx = 0
menuItems.push(formatCfgMenuText(itemTextMaxLen, toggleOptItems[i], gCfgInfo.cfgSections.BEHAVIOR[cfgOptProps[i]])); for (; optionIdx < 14; ++optionIdx)
menuItems.push(formatCfgMenuText(itemTextMaxLen, optionStrs[optionIdx], gCfgInfo.cfgSections.BEHAVIOR[cfgOptProps[optionIdx]]));
// Text input settings, etc. // Text input settings, etc.
menuItems.push(formatCfgMenuText(itemTextMaxLen, "User input timeout (MS)", gCfgInfo.cfgSections.BEHAVIOR.inputTimeoutMS)); menuItems.push(formatCfgMenuText(itemTextMaxLen, optionStrs[optionIdx++], gCfgInfo.cfgSections.BEHAVIOR.inputTimeoutMS));
// Text replacements can be a boolean true/false or "regex" // Text replacements can be a boolean true/false or "regex"
menuItems.push(formatCfgMenuText(itemTextMaxLen, "Enable text replacements", getTxtReplacementsVal())); menuItems.push(formatCfgMenuText(itemTextMaxLen, optionStrs[optionIdx++], getTxtReplacementsVal()));
menuItems.push(formatCfgMenuText(itemTextMaxLen, "Tagline filename", gCfgInfo.cfgSections.BEHAVIOR.tagLineFilename)); menuItems.push(formatCfgMenuText(itemTextMaxLen, optionStrs[optionIdx++], gCfgInfo.cfgSections.BEHAVIOR.tagLineFilename));
menuItems.push(formatCfgMenuText(itemTextMaxLen, "Tagline prefix", gCfgInfo.cfgSections.BEHAVIOR.taglinePrefix)); menuItems.push(formatCfgMenuText(itemTextMaxLen, optionStrs[optionIdx++], gCfgInfo.cfgSections.BEHAVIOR.taglinePrefix));
menuItems.push("Dictionary filenames"); // dictionaryFilenames //menuItems.push(formatCfgMenuText(itemTextMaxLen, optionStrs[optionIdx++], gCfgInfo.cfgSections.BEHAVIOR.dictionaryFilenames.substr(0,30)));
menuItems.push(formatCfgMenuText(itemTextMaxLen, optionStrs[optionIdx++], gCfgInfo.cfgSections.BEHAVIOR.dictionaryFilenames));
// A dictionary of help text for each option, indexed by the option name from the configuration file
if (doBehaviorMenu.optHelp == undefined)
doBehaviorMenu.optHelp = getOptionHelpText();
if (doBehaviorMenu.mainScreenHelp == undefined)
doBehaviorMenu.mainScreenHelp = getBehaviorScreenHelp(doBehaviorMenu.optHelp, cfgOptProps);
// Create a CTX to specify the current selected item index // Create a CTX to specify the current selected item index
if (doBehaviorMenu.ctx == undefined) if (doBehaviorMenu.ctx == undefined)
...@@ -152,59 +178,20 @@ function doBehaviorMenu() ...@@ -152,59 +178,20 @@ function doBehaviorMenu()
var continueOn = true; var continueOn = true;
while (continueOn && !js.terminated) while (continueOn && !js.terminated)
{ {
uifc.help_text = getBehaviorScreenHelp(); uifc.help_text = doBehaviorMenu.mainScreenHelp;
var optionMenuSelection = uifc.list(winMode, menuTitle, menuItems, doBehaviorMenu.ctx); var optionMenuSelection = uifc.list(winMode, menuTitle, menuItems, doBehaviorMenu.ctx);
doBehaviorMenu.ctx.cur = optionMenuSelection; // Remember the current selected item doBehaviorMenu.ctx.cur = optionMenuSelection; // Remember the current selected item
switch (optionMenuSelection) if (optionMenuSelection == -1) // ESC
continueOn = false;
else
{ {
case -1: // ESC var optName = cfgOptProps[optionMenuSelection];
continueOn = false; var itemType = typeof(gCfgInfo.cfgSections.BEHAVIOR[optName]);
break; uifc.help_text = doBehaviorMenu.optHelp[optName];
// 0-13 are boolean values if (optName == "enableTextReplacements")
case 0: {
case 1: // Enable text replacements - This is above boolean because this
case 2: // could be mistaken for a boolean if it's true or false
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
gCfgInfo.cfgSections.BEHAVIOR[cfgOptProps[optionMenuSelection]] = !gCfgInfo.cfgSections.BEHAVIOR[cfgOptProps[optionMenuSelection]];
anyOptionChanged = true;
menuItems[optionMenuSelection] = formatCfgMenuText(itemTextMaxLen, toggleOptItems[optionMenuSelection], gCfgInfo.cfgSections.BEHAVIOR[cfgOptProps[optionMenuSelection]]);
// With a separate window to prompt for toggling the item:
/*
if (inputCfgObjBoolean(cfgOptProps[optionMenuSelection], toggleOptItems[optionMenuSelection]))
{
anyOptionChanged = true;
menuItems[optionMenuSelection] = formatCfgMenuText(itemTextMaxLen, toggleOptItems[optionMenuSelection], gCfgInfo.cfgSections.BEHAVIOR[cfgOptProps[optionMenuSelection]]);
}
*/
break;
case 14: // User input timeout (MS)
uifc.help_text = "The user inactivity timeout, in milliseconds";
var userInput = uifc.input(WIN_MID, "User input timeout (MS)", gCfgInfo.cfgSections.BEHAVIOR.inputTimeoutMS.toString(), 0, K_NUMBER|K_EDIT);
if (typeof(userInput) === "string" && userInput.length > 0)
{
var value = parseInt(userInput);
if (!isNaN(value) && value > 0 && gCfgInfo.cfgSections.BEHAVIOR.inputTimeoutMS != value)
{
gCfgInfo.cfgSections.BEHAVIOR.inputTimeoutMS = value;
anyOptionChanged = true;
menuItems[optionMenuSelection] = formatCfgMenuText(itemTextMaxLen, "User input timeout (MS)", value);
}
}
break;
case 15: // Enable text replacements (yes/no/regex)
var helpText = "Whether or not to enable text replacements (AKA macros). Can be ";
helpText += "true, false, or 'regex' to use regular expressions.";
uifc.help_text = word_wrap(helpText, gHelpWrapWidth);
// Store the current value wo we can see if it changes // Store the current value wo we can see if it changes
var valBackup = gCfgInfo.cfgSections.BEHAVIOR.enableTextReplacements; var valBackup = gCfgInfo.cfgSections.BEHAVIOR.enableTextReplacements;
// Prompt the user // Prompt the user
...@@ -213,7 +200,7 @@ function doBehaviorMenu() ...@@ -213,7 +200,7 @@ function doBehaviorMenu()
ctx.cur = gCfgInfo.cfgSections.BEHAVIOR.enableTextReplacements ? 0 : 1; ctx.cur = gCfgInfo.cfgSections.BEHAVIOR.enableTextReplacements ? 0 : 1;
else if (gCfgInfo.cfgSections.BEHAVIOR.enableTextReplacements.toLowerCase() === "regex") else if (gCfgInfo.cfgSections.BEHAVIOR.enableTextReplacements.toLowerCase() === "regex")
ctx.cur = 2; ctx.cur = 2;
var txtReplacementsSelection = uifc.list(winMode, "Enable text replacements", ["Yes", "No", "Regex"], ctx); var txtReplacementsSelection = uifc.list(winMode, optionStrs[optionMenuSelection], ["Yes", "No", "Regex"], ctx);
switch (txtReplacementsSelection) switch (txtReplacementsSelection)
{ {
case 0: case 0:
...@@ -231,35 +218,59 @@ function doBehaviorMenu() ...@@ -231,35 +218,59 @@ function doBehaviorMenu()
anyOptionChanged = true; anyOptionChanged = true;
menuItems[optionMenuSelection] = formatCfgMenuText(itemTextMaxLen, "Enable text replacements", getTxtReplacementsVal()); menuItems[optionMenuSelection] = formatCfgMenuText(itemTextMaxLen, "Enable text replacements", getTxtReplacementsVal());
} }
break; }
case 16: // Tagline filename else if (itemType === "boolean")
var helpText = "The name of the file where tag lines are stored. This file is loaded from the sbbs ctrl directory."; {
uifc.help_text = word_wrap(helpText, gHelpWrapWidth); gCfgInfo.cfgSections.BEHAVIOR[optName] = !gCfgInfo.cfgSections.BEHAVIOR[optName];
var userInput = uifc.input(WIN_MID, "Tagline filename", gCfgInfo.cfgSections.BEHAVIOR.tagLineFilename, 60, K_EDIT); anyOptionChanged = true;
menuItems[optionMenuSelection] = formatCfgMenuText(itemTextMaxLen, optionStrs[optionMenuSelection], gCfgInfo.cfgSections.BEHAVIOR[optName]);
}
else if (itemType === "number")
{
var promptStr = optionStrs[optionMenuSelection];
var initialVal = gCfgInfo.cfgSections.BEHAVIOR[optName].toString();
var minVal = 1;
var userInput = uifc.input(WIN_MID, promptStr, initialVal, 0, K_NUMBER|K_EDIT);
if (typeof(userInput) === "string" && userInput.length > 0)
{
var value = parseInt(userInput);
if (!isNaN(value) && value >= minVal && gCfgInfo.cfgSections.BEHAVIOR[optName] != value)
{
gCfgInfo.cfgSections.BEHAVIOR[optName] = value;
anyOptionChanged = true;
menuItems[optionMenuSelection] = formatCfgMenuText(itemTextMaxLen, optionStrs[optionMenuSelection], gCfgInfo.cfgSections.BEHAVIOR[optName]);
}
}
}
else if (optName == "tagLineFilename")
{
// Tagline filename
var userInput = uifc.input(WIN_MID, optionStrs[optionMenuSelection], gCfgInfo.cfgSections.BEHAVIOR.tagLineFilename, 60, K_EDIT);
if (typeof(userInput) === "string" && userInput != gCfgInfo.cfgSections.BEHAVIOR.tagLineFilename) if (typeof(userInput) === "string" && userInput != gCfgInfo.cfgSections.BEHAVIOR.tagLineFilename)
{ {
gCfgInfo.cfgSections.BEHAVIOR.tagLineFilename = userInput; gCfgInfo.cfgSections.BEHAVIOR.tagLineFilename = userInput;
anyOptionChanged = true; anyOptionChanged = true;
menuItems[optionMenuSelection] = formatCfgMenuText(itemTextMaxLen, "Tagline filename", userInput); menuItems[optionMenuSelection] = formatCfgMenuText(itemTextMaxLen, "Tagline filename", userInput);
} }
break; }
case 17: // Tagline prefix else if (optName == "taglinePrefix")
var helpText = "Text to add to the front of a tagline when adding it to the message. This "; {
helpText += "can be blank (nothing after the =) if no prefix is desired."; // Tagline prefix
uifc.help_text = word_wrap(helpText, gHelpWrapWidth); var userInput = uifc.input(WIN_MID, optionStrs[optionMenuSelection], gCfgInfo.cfgSections.BEHAVIOR.taglinePrefix, 0, K_EDIT);
var userInput = uifc.input(WIN_MID, "Tagline prefix", gCfgInfo.cfgSections.BEHAVIOR.taglinePrefix, 0, K_EDIT);
if (typeof(userInput) === "string" && userInput != gCfgInfo.cfgSections.BEHAVIOR.taglinePrefix) if (typeof(userInput) === "string" && userInput != gCfgInfo.cfgSections.BEHAVIOR.taglinePrefix)
{ {
gCfgInfo.cfgSections.BEHAVIOR.tagLineFilename = userInput; gCfgInfo.cfgSections.BEHAVIOR.tagLineFilename = userInput;
anyOptionChanged = true; anyOptionChanged = true;
menuItems[optionMenuSelection] = formatCfgMenuText(itemTextMaxLen, "Tagline prefix", userInput); menuItems[optionMenuSelection] = formatCfgMenuText(itemTextMaxLen, "Tagline prefix", userInput);
} }
break; }
case 18: // Dictionary filenames else if (optName == "dictionaryFilenames")
{
// Dictionary filenames
var userInput = promptDictionaries(); var userInput = promptDictionaries();
anyOptionChanged = (userInput != gCfgInfo.cfgSections.BEHAVIOR.dictionaryFilenames); anyOptionChanged = (userInput != gCfgInfo.cfgSections.BEHAVIOR.dictionaryFilenames);
gCfgInfo.cfgSections.BEHAVIOR.dictionaryFilenames = userInput; gCfgInfo.cfgSections.BEHAVIOR.dictionaryFilenames = userInput;
break; }
} }
} }
...@@ -529,64 +540,85 @@ function promptYesNo(pQuestion, pInitialVal, pWinMode) ...@@ -529,64 +540,85 @@ function promptYesNo(pQuestion, pInitialVal, pWinMode)
/////////////////////////////////////////////////// ///////////////////////////////////////////////////
// Help text functions // Help text functions
// Returns help text for the behavior configuration screen // Returns a dictionary of help text, indexed by the option name from the configuration file
function getBehaviorScreenHelp() function getOptionHelpText()
{ {
if (getBehaviorScreenHelp.help == undefined) var optionHelpText = {};
{ optionHelpText["displayEndInfoScreen"] = "Display end info screen: Whether or not to display editor info when exiting";
getBehaviorScreenHelp.help = "This screen allows you to configure behavior options for SlyEdit.\r\n\r\n";
getBehaviorScreenHelp.help += "Display end info screen: Whether or not to display editor info when exiting\r\n\r\n"; optionHelpText["userInputTimeout"] = "User input timeout: Whether or not to enable user inactivity timeout";
getBehaviorScreenHelp.help += "User input timeout: Whether or not to enable user inactivity timeout\r\n\r\n"; optionHelpText["reWrapQuoteLines"] = "Re-wrap quote lines: If true, quote lines will be re-wrapped so that they are complete ";
optionHelpText["reWrapQuoteLines"] += "but still look good when quoted. If this option is disabled, then quote lines will ";
optionHelpText["reWrapQuoteLines"] += "simply be trimmed to fit into the message.";
getBehaviorScreenHelp.help += "Re-wrap quote lines: If true, quote lines will be re-wrapped so that they are complete "; optionHelpText["useQuoteLineInitials"] = "Use author initials in quoted lines: Whether or not to prefix the quote ";
getBehaviorScreenHelp.help += "but still look good when quoted. If this option is disabled, then quote lines will "; optionHelpText["useQuoteLineInitials"] += "lines with the last author's initials. Users can change this for themselves too.";
getBehaviorScreenHelp.help += "simply be trimmed to fit into the message.\r\n\r\n";
getBehaviorScreenHelp.help += "Use author initials in quoted lines: Whether or not to prefix the quote ";
getBehaviorScreenHelp.help += "lines with the last author's initials. Users can change this for themselves too.\r\n\r\n";
getBehaviorScreenHelp.help += "Indent quoted lines with author initials: When prefixing quote lines with the last author's initials, "; optionHelpText["indentQuoteLinesWithInitials"] = "Indent quoted lines with author initials: When prefixing quote lines with the last author's initials, ";
getBehaviorScreenHelp.help += "whether or not to indent the quote lines with a space. Users can change this for themselves too.\r\n\r\n"; optionHelpText["indentQuoteLinesWithInitials"] += "whether or not to indent the quote lines with a space. Users can change this for themselves too.";
getBehaviorScreenHelp.help += "Allow editing quote lines: Whether or not to allow editing quote lines\r\n\r\n"; optionHelpText["allowEditQuoteLines"] = "Allow editing quote lines: Whether or not to allow editing quote lines";
getBehaviorScreenHelp.help += "Allow user settings: Whether or not to allow users to change their user settings.\r\n\r\n"; optionHelpText["allowUserSettings"] = "Allow user settings: Whether or not to allow users to change their user settings.";
getBehaviorScreenHelp.help += "Allow color selection: Whether or not to let the user change the text color\r\n\r\n"; optionHelpText["allowColorSelection"] = "Allow color selection: Whether or not to let the user change the text color";
getBehaviorScreenHelp.help += "Save colors as ANSI: Whether or not to save message color/attribute codes as ANSI "; optionHelpText["saveColorsAsANSI"] = "Save colors as ANSI: Whether or not to save message color/attribute codes as ANSI ";
getBehaviorScreenHelp.help += "(if not, they will be saved as Synchronet attribute codes)\r\n\r\n"; optionHelpText["saveColorsAsANSI"] += "(if not, they will be saved as Synchronet attribute codes)";
getBehaviorScreenHelp.help += "Allow cross-posting: Whether or not to allow cross-posting to multiple sub-boards\r\n\r\n"; optionHelpText["allowCrossPosting"] = "Allow cross-posting: Whether or not to allow cross-posting to multiple sub-boards";
getBehaviorScreenHelp.help += "Enable taglines: Whether or not to enable the option to add a tagline.\r\n\r\n"; optionHelpText["enableTaglines"] = "Enable taglines: Whether or not to enable the option to add a tagline.";
getBehaviorScreenHelp.help += "Shuffle taglines: Whether or not to shuffle (randomize) the list of taglines when they are "; optionHelpText["shuffleTaglines"] = "Shuffle taglines: Whether or not to shuffle (randomize) the list of taglines when they are ";
getBehaviorScreenHelp.help += "displayed for the user to choose from\r\n\r\n"; optionHelpText["shuffleTaglines"] += "displayed for the user to choose from";
getBehaviorScreenHelp.help += "Double-quotes around tag lines: Whether or not to add double-quotes around taglines\r\n\r\n"; optionHelpText["quoteTaglines"] = "Double-quotes around tag lines: Whether or not to add double-quotes around taglines";
getBehaviorScreenHelp.help += "Allow/enable spell check: Whether or not to allow spell check\r\n\r\n"; optionHelpText["allowSpellCheck"] = "Allow/enable spell check: Whether or not to allow spell check";
getBehaviorScreenHelp.help += "User input timeout (MS): The user inactivity timeout, in milliseconds\r\n\r\n"; optionHelpText["inputTimeoutMS"] = "User input timeout (MS): The user inactivity timeout, in milliseconds";
getBehaviorScreenHelp.help += "Enable text replacements: Whether or not to enable text replacements (AKA macros). Can be "; optionHelpText["enableTextReplacements"] = "Enable text replacements: Whether or not to enable text replacements (AKA macros). Can be ";
getBehaviorScreenHelp.help += "true, false, or 'regex' to use regular expressions.\r\n\r\n"; optionHelpText["enableTextReplacements"] += "true, false, or 'regex' to use regular expressions.";
getBehaviorScreenHelp.help += "Tagline filename: The name of the file where tag lines are stored. This file is loaded "; optionHelpText["tagLineFilename"] = "Tagline filename: The name of the file where tag lines are stored. This file is loaded ";
getBehaviorScreenHelp.help += "from the sbbs ctrl directory.\r\n\r\n"; optionHelpText["tagLineFilename"] += "from the sbbs ctrl directory.";
getBehaviorScreenHelp.help += "Tagline prefix: Text to add to the front of a tagline when adding it to the message. This "; optionHelpText["taglinePrefix"] = "Tagline prefix: Text to add to the front of a tagline when adding it to the message. This ";
getBehaviorScreenHelp.help += "can be blank (nothing after the =) if no prefix is desired.\r\n\r\n"; optionHelpText["taglinePrefix"] += "can be blank (nothing after the =) if no prefix is desired.";
getBehaviorScreenHelp.help += "Dictionary filenames: These are dictionaries to use for spell check. "; optionHelpText["dictionaryFilenames"] = "Dictionary filenames: These are dictionaries to use for spell check. ";
getBehaviorScreenHelp.help += "The dictionary filenames are in the format dictionary_<language>.txt, where "; optionHelpText["dictionaryFilenames"] += "The dictionary filenames are in the format dictionary_<language>.txt, where ";
getBehaviorScreenHelp.help += "<language> is the language name. The dictionary files are located in either "; optionHelpText["dictionaryFilenames"] += "<language> is the language name. The dictionary files are located in either ";
getBehaviorScreenHelp.help += "sbbs/mods, sbbs/ctrl, or the same directory as SlyEdit. Users can change "; optionHelpText["dictionaryFilenames"] += "sbbs/mods, sbbs/ctrl, or the same directory as SlyEdit. Users can change ";
getBehaviorScreenHelp.help += "this for themselves too."; optionHelpText["dictionaryFilenames"] += "this for themselves too.";
// Word-wrap the help text items
for (var prop in optionHelpText)
optionHelpText[prop] = word_wrap(optionHelpText[prop], gHelpWrapWidth);
return optionHelpText;
}
// Returns help text for the behavior configuration screen
//
// Parameters:
// pOptionHelpText: An object of help text for each option, indexed by the option name from the configuration file
// pCfgOptProps: An array specifying the properties to include in the help text and their order
//
// Return value: Help text for the behavior options screen
function getBehaviorScreenHelp(pOptionHelpText, pCfgOptProps)
{
if (getBehaviorScreenHelp.help == undefined)
{
getBehaviorScreenHelp.help = "This screen allows you to configure behavior options for SlyEdit.\r\n\r\n";
for (var i = 0; i < pCfgOptProps.length; ++i)
{
var optName = pCfgOptProps[i];
getBehaviorScreenHelp.help += pOptionHelpText[optName] + "\r\n\r\n";
}
getBehaviorScreenHelp.help = word_wrap(getBehaviorScreenHelp.help, gHelpWrapWidth); getBehaviorScreenHelp.help = word_wrap(getBehaviorScreenHelp.help, gHelpWrapWidth);
} }
return getBehaviorScreenHelp.help; return getBehaviorScreenHelp.help;
...@@ -720,10 +752,8 @@ function readSlyEditCfgFile() ...@@ -720,10 +752,8 @@ function readSlyEditCfgFile()
// Return value: Boolean - Whether or not the save fully succeeded // Return value: Boolean - Whether or not the save fully succeeded
function saveSlyEditCfgFile() function saveSlyEditCfgFile()
{ {
var saveSucceeded = false;
// If SlyEdit.cfg doesn't exist in the sbbs/mods directory, then copy it // If SlyEdit.cfg doesn't exist in the sbbs/mods directory, then copy it
// from sbbs/ctrl // from sbbs/ctrl to sbbs/mods
// gCfgInfo.cfgFilename contains the full path & filename of the configuration // gCfgInfo.cfgFilename contains the full path & filename of the configuration
// file // file
var originalCfgFilename = ""; var originalCfgFilename = "";
...@@ -734,185 +764,26 @@ function saveSlyEditCfgFile() ...@@ -734,185 +764,26 @@ function saveSlyEditCfgFile()
var modsSlyEditCfgFilename = system.mods_dir + gSlyEdCfgFileName; var modsSlyEditCfgFilename = system.mods_dir + gSlyEdCfgFileName;
var modsSlyEditCfgFileExists = file_exists(modsSlyEditCfgFilename); var modsSlyEditCfgFileExists = file_exists(modsSlyEditCfgFilename);
if (!modsSlyEditCfgFileExists && file_exists(originalCfgFilename)) if (!modsSlyEditCfgFileExists && file_exists(originalCfgFilename))
modsSlyEditCfgFileExists = file_copy(originalCfgFilename, modsSlyEditCfgFilename);
var cfgFile = new File(modsSlyEditCfgFilename);
if (modsSlyEditCfgFileExists)
{ {
if (cfgFile.open("r+")) // Reading and writing (file must exist) if (!file_copy(originalCfgFilename, modsSlyEditCfgFilename))
{ return false;
for (var settingName in gCfgInfo.cfgSections.BEHAVIOR)
cfgFile.iniSetValue("BEHAVIOR", settingName, gCfgInfo.cfgSections.BEHAVIOR[settingName]);
for (var settingName in gCfgInfo.cfgSections.ICE_COLORS)
cfgFile.iniSetValue("ICE_COLORS", settingName, gCfgInfo.cfgSections.ICE_COLORS[settingName]);
for (var settingName in gCfgInfo.cfgSections.DCT_COLORS)
cfgFile.iniSetValue("DCT_COLORS", settingName, gCfgInfo.cfgSections.DCT_COLORS[settingName]);
cfgFile.close();
saveSucceeded = true;
}
} }
else
// Open the configuration file and save the current settings to it
var saveSucceeded = false;
var cfgFile = new File(modsSlyEditCfgFilename);
if (cfgFile.open("r+")) // Reading and writing (file must exist)
{ {
// Creae a new SlyEdit.cfg in sbbs/mods for (var settingName in gCfgInfo.cfgSections.BEHAVIOR)
if (cfgFile.open("w")) cfgFile.iniSetValue("BEHAVIOR", settingName, gCfgInfo.cfgSections.BEHAVIOR[settingName]);
{ for (var settingName in gCfgInfo.cfgSections.ICE_COLORS)
saveSucceeded = true; cfgFile.iniSetValue("ICE_COLORS", settingName, gCfgInfo.cfgSections.ICE_COLORS[settingName]);
// Behavior section for (var settingName in gCfgInfo.cfgSections.DCT_COLORS)
if (!cfgFile.writeln("[BEHAVIOR]")) cfgFile.iniSetValue("DCT_COLORS", settingName, gCfgInfo.cfgSections.DCT_COLORS[settingName]);
saveSucceeded = false;
for (var settingName in gCfgInfo.cfgSections.BEHAVIOR)
{
// Write any comments for this setting
var comments = getIniFileCommentsForOpt(settingName, "BEHAVIOR");
for (var i = 0; i < comments.length; ++i)
{
if (!cfgFile.writeln(comments[i]))
saveSucceeded = false;
}
// Write the setting
var settingLine = settingName + "=" + gCfgInfo.cfgSections.BEHAVIOR[settingName];
if (!cfgFile.writeln(settingLine))
saveSucceeded = false;
}
// ICE_COLORS section
if (!cfgFile.writeln("[ICE_COLORS]"))
saveSucceeded = false;
for (var settingName in gCfgInfo.cfgSections.ICE_COLORS)
{
// Write any comments for this setting
var comments = getIniFileCommentsForOpt(settingName, "ICE_COLORS");
for (var i = 0; i < comments.length; ++i)
{
if (!cfgFile.writeln(comments[i]))
saveSucceeded = false;
}
// Write the setting
var settingLine = settingName + "=" + gCfgInfo.cfgSections.ICE_COLORS[settingName];
if (!cfgFile.writeln(settingLine))
saveSucceeded = false;
}
// DCT_COLORS section
if (!cfgFile.writeln("[DCT_COLORS]"))
saveSucceeded = false;
for (var settingName in gCfgInfo.cfgSections.DCT_COLORS)
{
// Write any comments for this setting
var comments = getIniFileCommentsForOpt(settingName, "DCT_COLORS");
for (var i = 0; i < comments.length; ++i)
{
if (!cfgFile.writeln(comments[i]))
saveSucceeded = false;
}
// Write the setting
var settingLine = settingName + "=" + gCfgInfo.cfgSections.DCT_COLORS[settingName];
if (!cfgFile.writeln(settingLine))
saveSucceeded = false;
}
cfgFile.close(); cfgFile.close();
} saveSucceeded = true;
} }
return saveSucceeded; return saveSucceeded;
} }
// Returns an array of INI file comments for a particular option (and section name)
function getIniFileCommentsForOpt(pOptName, pSectionName)
{
var commentLines = [];
if (pSectionName == "BEHAVIOR")
{
if (pOptName == "reWrapQuoteLines")
{
commentLines.push("; If the reWrapQuoteLines option is set to true, quote lines will be re-wrapped");
commentLines.push("; so that they are complete but still look good when quoted. If this option is");
commentLines.push("; disabled, then quote lines will simply be trimmed to fit into the message.");
}
else if (pOptName == "allowColorSelection")
commentLines.push("; Whether or not to let the user change the text color");
else if (pOptName == "saveColorsAsANSI")
{
commentLines.push("; Whether or not to save message color/attribute codes as ANSI (if not, they");
commentLines.push("; will be saved as Synchronet attribute codes)");
}
else if (pOptName == "allowCrossPosting")
commentLines.push("; Whether or not to allow cross-posting");
else if (pOptName == "enableTextReplacements")
{
commentLines.push("; Whether or not to enable text replacements (AKA macros).");
commentLines.push("; enableTextReplacements can have one of the following values:");
commentLines.push("; false : Text replacement is disabled");
commentLines.push("; true : Text replacement is enabled and performed as literal search and replace");
commentLines.push("; regex : Text replacement is enabled using regular expressions");
}
else if (pOptName == "tagLineFilename")
commentLines.push("; The name of the file where tag lines are stored");
else if (pOptName == "taglinePrefix")
{
commentLines.push("; Text to add to the front of a tagline when adding it to the message.");
commentLines.push("; This can be blank (nothing after the =) if no prefix is desired.");
}
else if (pOptName == "quoteTaglines")
commentLines.push("; Whether or not to add double-quotes around taglines");
else if (pOptName == "shuffleTaglines")
{
commentLines.push("; Whether or not to shuffle (randomize) the list of taglines when they are");
commentLines.push("; displayed for the user to choose from");
}
else if (pOptName == "allowUserSettings")
commentLines.push("; Whether or not to allow users to change their user settings.");
//; The following settings serve as defaults for the user settings, which
//; each user can change for themselves:
else if (pOptName == "useQuoteLineInitials")
{
commentLines.push("; Whether or not to prefix the quote lines with the last author's initials");
commentLines.push("; This also has a user option that takes precedence over this setting.");
}
else if (pOptName == "indentQuoteLinesWithInitials")
{
commentLines.push("; When prefixing quote lines with the last author's initials, whether or not");
commentLines.push("; to indent the quote lines with a space.");
commentLines.push("; This also has a user option that takes precedence over this setting.");
}
else if (pOptName == "enableTaglines")
{
commentLines.push("; Whether or not to enable the option to add a tagline");
commentLines.push("; This also has a user option that takes precedence over this setting.");
}
else if (pOptName == "allowEditQuoteLine")
{
commentLines.push("; Whether or not to allow editing quote lines");
commentLines.push("; This also has a user option that takes precedence over this setting.");
}
else if (pOptName == "allowSpellCheck")
{
commentLines.push("; Whether or not to allow spell check");
commentLines.push("; This also has a user option that takes precedence over this setting.");
}
else if (pOptName == "dictionaryFilenames")
{
commentLines.push("; Dictionary filenames (used for spell check): This is a comma-separated list of");
commentLines.push("; dictionary filenames. The dictionary filenames are in the format");
commentLines.push("; dictionary_<language>.txt, where <language> is the language name. In this");
commentLines.push("; list, the filenames can be in that format, or just <language>.txt, or just");
commentLines.push("; <language>. Leave blank to use all dictionary files that exist on the");
commentLines.push("; system. The dictionary files are located in either sbbs/mods, sbbs/ctrl, or");
commentLines.push("; the same directory as SlyEdit.");
commentLines.push("; This also has a user option that takes precedence over this setting.");
}
}
else if (pSectionName == "ICE_COLORS")
{
if (pOptName == "ThemeFilename")
commentLines.push("; The filename of the theme file (no leading path necessary)");
else if (pOptName == "menuOptClassicColors")
commentLines.push("; Whether or not to use all classic IceEdit colors (true/false)");
}
else if (pSectionName == "DCT_COLORS")
{
if (pOptName == "ThemeFilename")
commentLines.push("; The filename of the theme file (no leading path necessary)");
}
return commentLines;
}
\ No newline at end of file
// Configurator for Digital Distortion Message Reader: This is a menu-driven configuration
// program/script for Digital Distortion Message reader. If you're running DDMsgReader from
// xtrn/DDMsgReader (the standard location), then any changes are saved to DDMsgReader.cfg in
// sbbs/mods, so that custom changes don't get overridden due to an update.
// If you have DDMsgReader in a directory other than xtrn/DDMsgReader, then the changes to
// DDMsgReader.cfg will be saved in that directory (assuming you're running ddmr_cfg.js from
// that same directory).
// Currently for DDMsgReader 1.85.
//
// If you're running DDMsgReader from xtrn/DDMsgReader (the standard location) and you want
// to save the configuration file there (rather than sbbs/mods), you can use one of the
// following command-line options: noMods, -noMods, no_mods, or -no_mods
"use strict";
require("sbbsdefs.js", "P_NONE");
require("uifcdefs.js", "UIFC_INMSG");
if (!uifc.init("DigDist. Message Reader 1.85 Configurator"))
{
print("Failed to initialize uifc");
exit(1);
}
js.on_exit("uifc.bail()");
// DDMsgReader base configuration filename, and help text wrap width
var gDDMRCfgFileName = "DDMsgReader.cfg";
var gHelpWrapWidth = uifc.screen_width - 10;
// When saving the configuration file, always save it in the same directory
// as DDMsgReader (or this script); don't copy to mods
var gAlwaysSaveCfgInOriginalDir = false;
// Parse command-line arguments
parseCmdLineArgs();
// Read the DDMsgReader configuration file
var gCfgInfo = readDDMsgReaderCfgFile();
// Show the main menu and go from there.
// This is in a loop so that if the user aborts from confirming to save
// settings, they'll return to the main menu.
var anyOptionChanged = false;
var continueOn = true;
while (continueOn)
{
anyOptionChanged = doMainMenu() || anyOptionChanged;
// If any option changed, then let the user save the configuration if they want to
if (anyOptionChanged)
{
var userChoice = promptYesNo("Save configuration?", true, WIN_ORG|WIN_MID|WIN_ACT|WIN_ESC);
if (typeof(userChoice) === "boolean")
{
if (userChoice)
{
var saveRetObj = saveDDMsgReaderCfgFile();
if (saveRetObj.saveSucceeded)
{
var msg = "Changes were successfully saved";
if (saveRetObj.savedToModsDir)
msg += " (saved to the mods dir)";
uifc.msg(msg);
}
else
uifc.msg("Failed to save settings!");
}
continueOn = false;
}
}
else
continueOn = false;
}
///////////////////////////////////////////////////////////
// Functions
function doMainMenu()
{
// For menu item text formatting
var itemTextMaxLen = 50;
// Configuration option object properties
// cfgOptProps must correspond exactly with optionStrs & menuItems
var cfgOptProps = [
"listInterfaceStyle", // String (Lightbar/Traditional)
"reverseListOrder", // Boolean
"readerInterfaceStyle", // String (Scrollable/Traditional)
//"readerInterfaceStyleForANSIMessages", // String (Scrollable/Traditional)
"displayBoardInfoInHeader", // Boolean
"promptToContinueListingMessages", // Boolean
"promptConfirmReadMessage", // Boolean
"msgListDisplayTime", // String (written/imported)
"msgAreaList_lastImportedMsg_time", // String (written/imported)
"startMode", // String (Reader/List)
"tabSpaces", // Number
"pauseAfterNewMsgScan", // Boolean
"readingPostOnSubBoardInsteadOfGoToNext", // Boolean
"areaChooserHdrFilenameBase", // String
"areaChooserHdrMaxLines", // Number
"displayAvatars", // Boolean
"rightJustifyAvatars", // Boolean
"msgListSort", // String (Written/Received)
"convertYStyleMCIAttrsToSync", // Boolean
"prependFowardMsgSubject", // Boolean
"enableIndexedModeMsgListCache", // Boolean
"quickUserValSetIndex", // Number (can be -1)
"saveAllHdrsWhenSavingMsgToBBSPC", // Boolean
"useIndexedModeForNewscan", // Boolean
"themeFilename" // String
];
// Strings for the options to display on the menu
var optionStrs = [
"List Interface Style",
"Reverse List Order",
"Reader Interface Style",
//"readerInterfaceStyleForANSIMessages",
"Display Board Info In Header",
"Prompt to Continue Listing Messages",
"Prompt to Confirm Reading Message",
"Message List Display Time",
"Message Area List: Last Imported Message Time",
"Start Mode",
"Number of Spaces for Tabs",
"Pause After New Message Scan",
"Reading Post On Sub-Board Instead Of Go To Next",
"Area Chooser Header Filename Base",
"Area Chooser Header Max # of Lines",
"Display Avatars",
"Right-Justify Avatars",
"Message List Sort",
"Convert Y-Style MCI Attributes To Sync",
"Prepend Forwarded Message Subject with \"Fwd\"",
"Enable Indexed Mode Message List Cache",
"Quick User Val Set Index",
"Save All Headers When Saving Message To BBS PC",
"Use Indexed Mode For Newscan",
"Theme Filename"
];
// Build an array of formatted string to be displayed on the menu
// (the value formatting will depend on the variable type)
var menuItems = [];
for (var i = 0; i < cfgOptProps.length; ++i)
{
var propName = cfgOptProps[i];
menuItems.push(formatCfgMenuText(itemTextMaxLen, optionStrs[i], gCfgInfo.cfgOptions[propName]));
}
// Help text
// A dictionary of help text for each option, indexed by the option name from the configuration file
if (doMainMenu.optHelp == undefined)
doMainMenu.optHelp = getOptionHelpText();
if (doMainMenu.mainScreenHelp == undefined)
doMainMenu.mainScreenHelp = getMainHelp(doMainMenu.optHelp, cfgOptProps);
// Create a CTX to specify the current selected item index
if (doMainMenu.ctx == undefined)
doMainMenu.ctx = uifc.list.CTX();
// Selection
var winMode = WIN_ORG|WIN_MID|WIN_ACT|WIN_ESC;
var menuTitle = "DD Message Reader Behavior Configuration";
var anyOptionChanged = false;
var continueOn = true;
while (continueOn && !js.terminated)
{
uifc.help_text = doMainMenu.mainScreenHelp;
var optionMenuSelection = uifc.list(winMode, menuTitle, menuItems, doMainMenu.ctx);
doMainMenu.ctx.cur = optionMenuSelection; // Remember the current selected item
if (optionMenuSelection == -1) // ESC
continueOn = false;
else
{
var optName = cfgOptProps[optionMenuSelection];
var itemType = typeof(gCfgInfo.cfgOptions[optName]);
uifc.help_text = doMainMenu.optHelp[optName];
if (optName == "quickUserValSetIndex")
{
// User quick-validation set index
var selectedValSetIdx = promptQuickValSet();
if (selectedValSetIdx > -1)
{
gCfgInfo.cfgOptions.quickUserValSetIndex = selectedValSetIdx;
anyOptionChanged = true;
menuItems[optionMenuSelection] = formatCfgMenuText(itemTextMaxLen, optionStrs[optionMenuSelection], gCfgInfo.cfgOptions[optName]);
}
}
else if (itemType === "boolean")
{
gCfgInfo.cfgOptions[optName] = !gCfgInfo.cfgOptions[optName];
anyOptionChanged = true;
menuItems[optionMenuSelection] = formatCfgMenuText(itemTextMaxLen, optionStrs[optionMenuSelection], gCfgInfo.cfgOptions[optName]);
}
else if (itemType === "number")
{
var promptStr = optionStrs[optionMenuSelection];
var initialVal = gCfgInfo.cfgOptions[optName].toString();
var minVal = 1;
var userInput = uifc.input(WIN_MID, promptStr, initialVal, 0, K_NUMBER|K_EDIT);
if (typeof(userInput) === "string" && userInput.length > 0)
{
var value = parseInt(userInput);
if (!isNaN(value) && value >= minVal && gCfgInfo.cfgOptions[optName] != value)
{
gCfgInfo.cfgOptions[optName] = value;
anyOptionChanged = true;
menuItems[optionMenuSelection] = formatCfgMenuText(itemTextMaxLen, optionStrs[optionMenuSelection], gCfgInfo.cfgOptions[optName]);
}
}
}
else
{
if (optName == "areaChooserHdrFilenameBase")
{
// Area chooser header filename base
var promptStr = optionStrs[optionMenuSelection];
var userInput = uifc.input(WIN_MID, promptStr, gCfgInfo.cfgOptions[optName], 60, K_EDIT);
if (typeof(userInput) === "string" && userInput.length > 0)
{
gCfgInfo.cfgOptions[optName] = userInput;
anyOptionChanged = true;
menuItems[optionMenuSelection] = formatCfgMenuText(itemTextMaxLen, optionStrs[optionMenuSelection], gCfgInfo.cfgOptions[optName]);
}
}
else if (optName == "themeFilename")
{
// Theme filename
var userInput = promptThemeFilename();
if (typeof(userInput) === "string" && userInput != gCfgInfo.cfgOptions[optName])
{
gCfgInfo.cfgOptions[optName] = userInput;
anyOptionChanged = true;
menuItems[optionMenuSelection] = formatCfgMenuText(itemTextMaxLen, optionStrs[optionMenuSelection], gCfgInfo.cfgOptions[optName]);
}
}
else
{
// Multiple-choice
var options = [];
if (optName == "listInterfaceStyle")
options = ["Lightbar", "Traditional"];
else if (optName == "readerInterfaceStyle")
options = ["Scrollable", "Traditional"];
else if (optName == "msgListDisplayTime" || optName == "msgAreaList_lastImportedMsg_time")
options = ["Written", "Imported"];
else if (optName == "startMode")
options = ["Reader", "List"];
else if (optName == "msgListSort")
options = ["Written", "Received"];
var promptStr = optionStrs[optionMenuSelection];
var userChoice = promptMultipleChoice(promptStr, options, gCfgInfo.cfgOptions[optName]);
if (userChoice != null && userChoice != undefined && userChoice != gCfgInfo.cfgOptions[optName])
{
gCfgInfo.cfgOptions[optName] = userChoice;
anyOptionChanged = true;
menuItems[optionMenuSelection] = formatCfgMenuText(itemTextMaxLen, optionStrs[optionMenuSelection], gCfgInfo.cfgOptions[optName]);
}
}
}
}
}
return anyOptionChanged;
}
// Formats text for a behavior option
//
// Parameters:
// pItemTextMaxLen: The maximum length for menu item text
// pItemText: The text of the item to be displayed on the menu
// pVal: The value of the option
//
// Return value: The formatted text for the menu item, with a Yes/No value indicating whether it's enabled
function formatCfgMenuText(pItemTextMaxLen, pItemText, pVal)
{
if (formatCfgMenuText.formatStr == undefined)
formatCfgMenuText.formatStr = "%-" + pItemTextMaxLen + "s %s";
// Determine what should be displayed for the value
var valType = typeof(pVal);
var value = "";
if (valType === "boolean")
value = pVal ? "Yes" : "No";
else
value = pVal.toString();
return format(formatCfgMenuText.formatStr, pItemText.substr(0, pItemTextMaxLen), value);
}
// Prompts the user for which dictionaries to use (for spell check)
function promptThemeFilename()
{
// Find theme filenames. There should be a DefaultTheme.cfg; also, look
// for theme .cfg filenames starting with DDMR_Theme_
var defaultThemeFilename = js.exec_dir + "DefaultTheme.cfg";
var themeFilenames = [];
if (file_exists(defaultThemeFilename))
themeFilenames.push(defaultThemeFilename);
themeFilenames = themeFilenames.concat(directory(js.exec_dir + "DDMR_Theme_*.cfg"));
// Abbreviated theme file names: Get just the filename without the full path,
// and remove the trailing .cfg
var abbreviatedThemeFilenames = [];
for (var i = 0; i < themeFilenames.length; ++i)
{
var themeFilename = file_getname(themeFilenames[i]).replace(/\.cfg$/, "");
abbreviatedThemeFilenames.push(themeFilename);
}
// Add an option at the end to let the user type it themselves
abbreviatedThemeFilenames.push("Type your own filename");
// Create a context, and look for the current theme filename & set the
// current index
var ctx = uifc.list.CTX();
if (gCfgInfo.cfgOptions.themeFilename.length > 0)
{
var themeFilenameUpper = gCfgInfo.cfgOptions.themeFilename.toUpperCase();
for (var i = 0; i < themeFilenames.length; ++i)
{
if (themeFilenames[i].toUpperCase() == themeFilenameUpper)
{
ctx.cur = i;
break;
}
}
}
// User input
var chosenThemeFilename = null;
var selection = uifc.list(WIN_MID, "Theme Filename", abbreviatedThemeFilenames, ctx);
if (selection == -1)
{
// User quit/aborted; do nothing
}
// Last item: Let the user input the filename themselves
else if (selection == abbreviatedThemeFilenames.length-1)
{
var userInput = uifc.input(WIN_MID, "Theme filename", "", 0, K_EDIT);
if (typeof(userInput) === "string")
chosenThemeFilename = userInput;
}
else
chosenThemeFilename = file_getname(themeFilenames[selection]);
return chosenThemeFilename;
}
// Prompts the user to select one of multiple values for an option
//
// Parameters:
// pPrompt: The prompt text
// pChoices: An array of the choices
// pCurrentVal: The current value (to set the index in the menu)
//
// Return value: The user's chosen value, or null if the user aborted
function promptMultipleChoice(pPrompt, pChoices, pCurrentVal)
{
//uifc.help_text = pHelpText;
// Create a context object with the current value index
var currentValUpper = pCurrentVal.toUpperCase();
var ctx = uifc.list.CTX();
for (var i = 0; i < pChoices.length; ++i)
{
if (pChoices[i].toUpperCase() == currentValUpper)
{
ctx.cur = i;
break;
}
}
// Prompt the user and return their chosen value
var chosenValue = null;
//var winMode = WIN_ORG|WIN_MID|WIN_ACT|WIN_ESC;
var winMode = WIN_MID;
var userSelection = uifc.list(winMode, pPrompt, pChoices, ctx);
if (userSelection >= 0 && userSelection < pChoices.length)
chosenValue = pChoices[userSelection];
return chosenValue;
}
// Prompts the user Yes/No for a boolean response
//
// Parameters:
// pQuestion: The question/prompt for the user
// pInitialVal: Boolean - Whether the initial selection in the menu should
// be Yes (true) or No (false)
// pWinMode: Optional window mode bits. If not specified, WIN_MID will be used.
//
// Return value: Boolean true (yes), false (no), or null if the user aborted
function promptYesNo(pQuestion, pInitialVal, pWinMode)
{
var chosenVal = null;
var winMode = typeof(pWinMode) === "number" ? pWinMode : WIN_MID;
// Create a CTX to specify the current selected item index
var ctx = uifc.list.CTX();
ctx.cur = typeof(pInitialVal) === "boolean" && pInitialVal ? 0 : 1;
switch (uifc.list(winMode, pQuestion, ["Yes", "No"], ctx))
{
case -1: // User quit/aborted - Leave chosenVal as null
break;
case 0: // User chose Yes
chosenVal = true;
break;
case 1: // User chose No
chosenVal = false;
break;
default:
break;
}
return chosenVal;
}
// Prompts the user for a quick-validation set. Returns the index of the
// validation set, or -1 if none chosen.
function promptQuickValSet()
{
var chosenQuickValSetIdx = -1;
var promptStr = "Quick-Validation Values";
// Create a context object with the current value index
var ctx = uifc.list.CTX();
if (gCfgInfo.cfgOptions.quickUserValSetIndex >= 0 && gCfgInfo.cfgOptions.quickUserValSetIndex < quickValSets.length)
ctx.cur = gCfgInfo.cfgOptions.quickUserValSetIndex;
// Choices: If main.ini exists (i.e., Synchronet 3.20+), then get the
// quick validation sets from that. Otherwise, just make a list of indexes 0-9.
var menuStrs = [];
if (file_exists(system.ctrl_dir + "main.ini"))
{
var quickValSets = getQuickValidationVals();
var formatStr = "%-d: SL: %-3d F1: %s";
for (var i = 0; i < quickValSets.length; ++i)
menuStrs.push(format(formatStr, i, quickValSets[i].level, getUserValFlagsStr(quickValSets[i].flags1)));
}
else
{
for (var i = 0; i < 10; ++i)
menuStrs.push(i.toString());
}
// Prompt the user and return their chosen value
var chosenValue = null;
//var winMode = WIN_ORG|WIN_MID|WIN_ACT|WIN_ESC;
var winMode = WIN_MID;
var userSelection = uifc.list(winMode, promptStr, menuStrs, ctx);
if (userSelection >= 0 && userSelection < quickValSets.length)
chosenQuickValSetIdx = userSelection;
return chosenQuickValSetIdx;
}
///////////////////////////////////////////////////
// Help text functions
// Returns a dictionary of help text, indexed by the option name from the configuration file
function getOptionHelpText()
{
var optionHelpText = {};
optionHelpText["listInterfaceStyle"] = "List Interface Style: Either Lightbar or Traditional";
optionHelpText["reverseListOrder"] = "Reverse List Order: Whether or not message lists are to be shown in reverse order. This is a default for ";
optionHelpText["reverseListOrder"] += "a user setting.";
optionHelpText["readerInterfaceStyle"] = "Reader Interface Style: This can be either Scrollable (allowing scrolling up & down) or Traditional. ";
optionHelpText["readerInterfaceStyle"] += "The scrollable interface only works if the user's terminal supports ANSI. The reader will fall back ";
optionHelpText["readerInterfaceStyle"] += "to a traditional interface if the usser's terminal doesn't support ANSI.";
//optionHelpText["readerInterfaceStyleForANSIMessages"] = "";
optionHelpText["displayBoardInfoInHeader"] = "Display Board Info In Header: Whether or not to display the message group and sub-board lines in the ";
optionHelpText["displayBoardInfoInHeader"] += "header at the top of the screen (an additional 2 lines).";
optionHelpText["promptToContinueListingMessages"] = "Prompt to Continue Listing Messages: Whether or not to ask the user if they want to continue listing ";
optionHelpText["promptToContinueListingMessages"] += "messages after they read a message";
optionHelpText["promptConfirmReadMessage"] = "Prompt to Confirm Reading Message: Whether or not to prompt the user to confirm to read a message ";
optionHelpText["promptConfirmReadMessage"] += "when a message is selected from the message list";
optionHelpText["msgListDisplayTime"] = "Message List Display Time: Whether to display the message import time or the written time in the ";
optionHelpText["msgListDisplayTime"] += "message lists. Valid values are imported and written";
optionHelpText["msgAreaList_lastImportedMsg_time"] = "Message Area List Last Imported Message Time: For the last message time in the message lists, ";
optionHelpText["msgAreaList_lastImportedMsg_time"] += "whether to use message import time or written time. Valid values are imported and written";
optionHelpText["startMode"] = "Start Mode: Specifies the default startup mode (Reader/Read or Lister/List)";
optionHelpText["tabSpaces"] = "Number of Spaces for Tabs: This specifies how many spaces to use for tabs (if a message has tabs)";
optionHelpText["pauseAfterNewMsgScan"] = "Pause After Nes Message Scan: Whether or not to pause at the end of a newscan";
optionHelpText["readingPostOnSubBoardInsteadOfGoToNext"] = "Reading Post On Sub-Board Instead Of Go To Next: When reading messages (but not for a newscan, etc.): ";
optionHelpText["readingPostOnSubBoardInsteadOfGoToNext"] += "Whether or not to ask the user whether to post on the sub-board in reader mode after reading the last ";
optionHelpText["readingPostOnSubBoardInsteadOfGoToNext"] += "message instead of prompting to go to the next sub-board. This is like the stock Synchronet behavior.";
optionHelpText["areaChooserHdrFilenameBase"] = "Area Chooser Header Filename Base: If you'd like to have an ANSI displayed above the lists of the area ";
optionHelpText["areaChooserHdrFilenameBase"] += "chooser, you can specify the 'base' of the filename (without the .ans/.asc) here. The file must be in the ";
optionHelpText["areaChooserHdrFilenameBase"] += "same directory as DDMsgReader.js.";
optionHelpText["areaChooserHdrMaxLines"] = "Area Chooser Header Max # of Lines: The maximum number of lines to use from the area chooser header file";
optionHelpText["displayAvatars"] = "Display Avatars: Whether or not to display user avatars (the small user-specified ANSIs) when reading messages";
optionHelpText["rightJustifyAvatars"] = "Right-Justify Avatars: Whether or not to display user avatars on the right. If false, they will be displayed ";
optionHelpText["rightJustifyAvatars"] += "on the left.";
optionHelpText["msgListSort"] = "Message List Sort: How to sort the message lists - Either Received (by date/time received, which is faster), ";
optionHelpText["msgListSort"] += "or Written (by date/time written, which takes time due to sorting)";
optionHelpText["convertYStyleMCIAttrsToSync"] = "Convert Y-Style MCI Attributes to Sync: Whether or not to convert Y-Style MCI attribute/color codes to ";
optionHelpText["convertYStyleMCIAttrsToSync"] += "Synchronet attribute codes (if disabled, these codes will appear as-is rather than as the colors or ";
optionHelpText["convertYStyleMCIAttrsToSync"] += "attributes they represent)";
optionHelpText["prependFowardMsgSubject"] = "Prepend Forwarded Message Subject with \"Fwd\" Whether or not to prepend the subject for forwarded messages ";
optionHelpText["prependFowardMsgSubject"] += "with \"Fwd: \"";
optionHelpText["enableIndexedModeMsgListCache"] = "Enable Indexed Mode Message List Cache: For indexed reader mode, whether or not to enable caching the message ";
optionHelpText["enableIndexedModeMsgListCache"] += "header lists for performance";
optionHelpText["quickUserValSetIndex"] = "Quick User Val Set Index: An index of a quick-validation set from SCFG > System > Security Options > ";
optionHelpText["quickUserValSetIndex"] += "Quick-Validation Values to be used by the sysop to quick-validate a local user who has posted a message while ";
optionHelpText["quickUserValSetIndex"] += "reading the message. This index is 0-based, as they appear in SCFG. Normally there are 10 quick-validation ";
optionHelpText["quickUserValSetIndex"] += "values, so valid values for this index are 0 through 9. If you would rather DDMsgReader display a menu of ";
optionHelpText["quickUserValSetIndex"] += "quick-validation sets, you can set this to an invalid index (such as -1).";
optionHelpText["saveAllHdrsWhenSavingMsgToBBSPC"] = "Save All Headers When Saving Message to BBS PC: As the sysop, you can save messages to the BBS PC. This ";
optionHelpText["saveAllHdrsWhenSavingMsgToBBSPC"] += "option specifies whether or not to save all the message headers along with the message. If disabled, ";
optionHelpText["saveAllHdrsWhenSavingMsgToBBSPC"] += "only a few relevant headers will be saved (such as From, To, Subject, and message time).";
optionHelpText["useIndexedModeForNewscan"] = "Used Indexed Mode for Newscan: Whether or not to use indexed mode for message newscans (not for new-to-you ";
optionHelpText["useIndexedModeForNewscan"] += "scans). This is a default for a user setting. When indexed mode is enabled for newscans, the reader displays ";
optionHelpText["useIndexedModeForNewscan"] += "a menu showing each sub-board and the number of new messages and total messages in each. When disabled, ";
optionHelpText["useIndexedModeForNewscan"] += "the reader will do a traditional newscan where it will scan through the sub-boards and go into reader ";
optionHelpText["useIndexedModeForNewscan"] += "mode when there are new messages in a sub-board.";
optionHelpText["themeFilename"] = "Theme filename: The name of a file for a color theme to use";
// Word-wrap the help text items
for (var prop in optionHelpText)
optionHelpText[prop] = word_wrap(optionHelpText[prop], gHelpWrapWidth);
return optionHelpText;
}
// Returns help text for the main configuration screen (behavior settings)
//
// Parameters:
// pOptionHelpText: An object of help text for each option, indexed by the option name from the configuration file
// pCfgOptProps: An array specifying the properties to include in the help text and their order
//
// Return value: Help text for the main configuration screen (behavior settings)
function getMainHelp(pOptionHelpText, pCfgOptProps)
{
var helpText = "This screen allows you to configure behavior options for Digital Distortion Message Reader.\r\n\r\n";
for (var i = 0; i < pCfgOptProps.length; ++i)
{
var optName = pCfgOptProps[i];
helpText += pOptionHelpText[optName] + "\r\n\r\n";
}
return word_wrap(helpText, gHelpWrapWidth);
}
///////////////////////////////////////////////////
// Non-UI utility functions
// Returns an array of the quick-validation sets configured in
// SCFG > System > Security > Quick-Validation Values. This reads
// from main.ini, which exists with Synchronet 3.20 and newer.
// In SCFG:
//
// Level 60 |
// Flag Set #1 |
// Flag Set #2 |
// Flag Set #3 |
// Flag Set #4 |
// Exemptions |
// Restrictions |
// Extend Expiration 0 days |
// Additional Credits 0 |
//
// Each object in the returned array will have the following properties:
// level (numeric)
// expire
// flags1
// flags2
// flags3
// flags4
// credits
// exemptions
// restrictions
function getQuickValidationVals()
{
var validationValSets = [];
// In SCFG > System > Security > Quick-Validation Values, there are 10 sets of
// validation values. These are in main.ini as [valset:0] through [valset:9]
// This reads from main.ini, which exists with Synchronet 3.20 and newer.
//system.version_num >= 32000
var mainIniFile = new File(system.ctrl_dir + "main.ini");
if (mainIniFile.open("r"))
{
for (var i = 0; i < 10; ++i)
{
// Flags:
// AZ is 0x2000001
// A is 1
// Z is 0x2000000
var valSection = mainIniFile.iniGetObject(format("valset:%d", i));
if (valSection != null)
validationValSets.push(valSection);
}
mainIniFile.close();
}
return validationValSets;
}
// Generates a string based on user quick-validation flags
//
// Parameters:
// pFlags: A bitfield of user quick-validation flags
//
// Return value: A string representing the quick-validation flags (as would appear in SCFG)
function getUserValFlagsStr(pFlags)
{
var flagLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var flagsStr = "";
for (var i = 0; i < flagLetters.length; ++i)
flagsStr += (Boolean((1 << i) & pFlags) ? flagLetters[i] : " ");
return truncsp(flagsStr);
}
// Parses command-line arguments & sets any applicable values
function parseCmdLineArgs()
{
for (var i = 0; i < argv.length; ++i)
{
var argUpper = argv[i].toUpperCase();
if (argUpper == "NOMODS" || argUpper == "NO_MODS" || argUpper == "-NOMODS" || argUpper == "-NO_MODS")
gAlwaysSaveCfgInOriginalDir = true;
}
}
// Reads the DDMsgReader configuration file
//
// Return value: An object with the following properties:
// cfgFilename: The full path & filename of the DDMsgReader configuration file that was read
// cfgOptions: A dictionary of the configuration options and their values
function readDDMsgReaderCfgFile()
{
var retObj = {
cfgFilename: "",
cfgOptions: {}
};
// Determine the location of the configuration file. First look for it
// in the sbbs/mods directory, then sbbs/ctrl, then in the same directory
// as this script.
var cfgFilename = file_cfgname(system.mods_dir, gDDMRCfgFileName);
if (!file_exists(cfgFilename))
cfgFilename = file_cfgname(system.ctrl_dir, gDDMRCfgFileName);
if (!file_exists(cfgFilename))
cfgFilename = file_cfgname(js.exec_dir, gDDMRCfgFileName);
retObj.cfgFilename = cfgFilename;
// Open and read the configuration file
var cfgFile = new File(retObj.cfgFilename);
if (cfgFile.open("r"))
{
retObj.cfgOptions = cfgFile.iniGetObject();
cfgFile.close();
}
// In case some settings weren't loaded, add defaults
if (!retObj.cfgOptions.hasOwnProperty("listInterfaceStyle"))
retObj.cfgOptions.listInterfaceStyle = "Lightbar";
if (!retObj.cfgOptions.hasOwnProperty("reverseListOrder"))
retObj.cfgOptions.reverseListOrder = false;
if (!retObj.cfgOptions.hasOwnProperty("readerInterfaceStyle"))
retObj.cfgOptions.readerInterfaceStyle = "Scrollable";
if (!retObj.cfgOptions.hasOwnProperty("readerInterfaceStyleForANSIMessages"))
retObj.cfgOptions.readerInterfaceStyleForANSIMessages = "Scrollable";
if (!retObj.cfgOptions.hasOwnProperty("displayBoardInfoInHeader"))
retObj.cfgOptions.displayBoardInfoInHeader = false;
if (!retObj.cfgOptions.hasOwnProperty("promptToContinueListingMessages"))
retObj.cfgOptions.promptToContinueListingMessages = false;
if (!retObj.cfgOptions.hasOwnProperty("promptConfirmReadMessage"))
retObj.cfgOptions.promptConfirmReadMessage = false;
if (!retObj.cfgOptions.hasOwnProperty("msgListDisplayTime"))
retObj.cfgOptions.msgListDisplayTime = "written";
if (!retObj.cfgOptions.hasOwnProperty("msgAreaList_lastImportedMsg_time"))
retObj.cfgOptions.msgAreaList_lastImportedMsg_time = "written";
if (!retObj.cfgOptions.hasOwnProperty("startMode"))
retObj.cfgOptions.startMode = "Reader";
if (!retObj.cfgOptions.hasOwnProperty("tabSpaces"))
retObj.cfgOptions.tabSpaces = 3;
if (!retObj.cfgOptions.hasOwnProperty("pauseAfterNewMsgScan"))
retObj.cfgOptions.pauseAfterNewMsgScan = true;
if (!retObj.cfgOptions.hasOwnProperty("readingPostOnSubBoardInsteadOfGoToNext"))
retObj.cfgOptions.readingPostOnSubBoardInsteadOfGoToNext = false;
if (!retObj.cfgOptions.hasOwnProperty("areaChooserHdrFilenameBase"))
retObj.cfgOptions.areaChooserHdrFilenameBase = "";
if (!retObj.cfgOptions.hasOwnProperty("areaChooserHdrMaxLines"))
retObj.cfgOptions.areaChooserHdrMaxLines = 12;
if (!retObj.cfgOptions.hasOwnProperty("displayAvatars"))
retObj.cfgOptions.displayAvatars = true;
if (!retObj.cfgOptions.hasOwnProperty("rightJustifyAvatars"))
retObj.cfgOptions.rightJustifyAvatars = true;
if (!retObj.cfgOptions.hasOwnProperty("msgListSort"))
retObj.cfgOptions.msgListSort = "Received";
if (!retObj.cfgOptions.hasOwnProperty("convertYStyleMCIAttrsToSync"))
retObj.cfgOptions.convertYStyleMCIAttrsToSync = true;
if (!retObj.cfgOptions.hasOwnProperty("prependFowardMsgSubject"))
retObj.cfgOptions.prependFowardMsgSubject = true;
if (!retObj.cfgOptions.hasOwnProperty("enableIndexedModeMsgListCache"))
retObj.cfgOptions.enableIndexedModeMsgListCache = true;
if (!retObj.cfgOptions.hasOwnProperty("quickUserValSetIndex"))
retObj.cfgOptions.quickUserValSetIndex = -1;
if (!retObj.cfgOptions.hasOwnProperty("saveAllHdrsWhenSavingMsgToBBSPC"))
retObj.cfgOptions.saveAllHdrsWhenSavingMsgToBBSPC = false;
if (!retObj.cfgOptions.hasOwnProperty("useIndexedModeForNewscan"))
retObj.cfgOptions.useIndexedModeForNewscan = false;
if (!retObj.cfgOptions.hasOwnProperty("themeFilename"))
retObj.cfgOptions.themeFilename = "DefaultTheme.cfg";
return retObj;
}
// Saves the DDMsgReader configuration file using the settings in gCfgInfo
//
// Return value: An object with the following properties:
// saveSucceeded: Boolean - Whether or not the save fully succeeded
// savedToModsDir: Boolean - Whether or not the .cfg file was saved to the mods directory
function saveDDMsgReaderCfgFile()
{
var retObj = {
saveSucceeded: false,
savedToModsDir: false
};
// If the configuration file was loaded from the standard location in
// the Git repository (xtrn/DDMsgReader), and the option to always save
// in the original directory is not set, then the configuration file
// should be copied to sbbs/mods to avoid custom settings being overwritten
// with an update.
var defaultDirRE = new RegExp("xtrn[\\\\/]DDMsgReader[\\\\/]" + gDDMRCfgFileName + "$");
var cfgFilename = gCfgInfo.cfgFilename;
if (defaultDirRE.test(cfgFilename) && !gAlwaysSaveCfgInOriginalDir)
{
cfgFilename = system.mods_dir + gDDMRCfgFileName;
if (!file_copy(gCfgInfo.cfgFilename, cfgFilename))
return false;
retObj.savedToModsDir = true;
}
var cfgFile = new File(cfgFilename);
if (cfgFile.open("r+")) // Reading and writing (file must exist)
{
for (var settingName in gCfgInfo.cfgOptions)
cfgFile.iniSetValue(null, settingName, gCfgInfo.cfgOptions[settingName]);
cfgFile.close();
retObj.saveSucceeded = true;
}
return retObj;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment