From a63104b0554ec3cb32bcd67308c2a9b677e9fb8e Mon Sep 17 00:00:00 2001 From: nightfox <> Date: Tue, 6 Feb 2018 20:19:07 +0000 Subject: [PATCH] Reverting SlyEdit back to version 1.54, since there seem to still be problems with the new versions that allow text color selection. --- ctrl/SlyDCTColors_Default.cfg | 126 +- ctrl/SlyDCTColors_Midnight.cfg | 130 +- ctrl/SlyEdit.cfg | 16 - ctrl/SlyIceColors_BlueIce.cfg | 80 +- ctrl/SlyIceColors_EmeraldCity.cfg | 80 +- ctrl/SlyIceColors_FieryInferno.cfg | 80 +- ctrl/SlyIceColors_Fire-N-Ice.cfg | 80 +- ctrl/SlyIceColors_GenericBlue.cfg | 80 +- ctrl/SlyIceColors_PurpleHaze.cfg | 82 +- ctrl/SlyIceColors_ShadesOfGrey.cfg | 80 +- docs/SlyEdit_ReadMe.txt | 61 +- exec/SlyEdit.js | 4920 ++++++++++++---------------- exec/SlyEdit_DCTStuff.js | 125 +- exec/SlyEdit_IceStuff.js | 100 +- exec/SlyEdit_Misc.js | 2182 ++++-------- 15 files changed, 3368 insertions(+), 4854 deletions(-) diff --git a/ctrl/SlyDCTColors_Default.cfg b/ctrl/SlyDCTColors_Default.cfg index da77d1a139..aee9ba67fe 100644 --- a/ctrl/SlyDCTColors_Default.cfg +++ b/ctrl/SlyDCTColors_Default.cfg @@ -1,86 +1,88 @@ ; This is a color theme file for SlyEdit's DCT Style. ; This color scheme mimics DCT Edit's default color scheme. +; Text edit color +TextEditColor=nw ; The color to use for quoted lines in the message -QuoteLineColor=\1n\1c +QuoteLineColor=nc ; Border colors -TopBorderColor1=\1n\1r -TopBorderColor2=\1n\1r\1h -EditAreaBorderColor1=\1n\1g -EditAreaBorderColor2=\1n\1g\1h -EditModeBrackets=\1n\1k\1h -EditMode=\1n\1w +TopBorderColor1=nr +TopBorderColor2=nrh +EditAreaBorderColor1=ng +EditAreaBorderColor2=ngh +EditModeBrackets=nkh +EditMode=nw ; Colors for the top informational area -TopLabelColor=\1n\1b\1h -TopLabelColonColor=\1n\1b -TopFromColor=\1n\1c\1h -TopFromFillColor=\1n\1c -TopToColor=\1n\1c\1h -TopToFillColor=\1n\1c -TopSubjColor=\1n\1w\1h -TopSubjFillColor=\1n\1w -TopAreaColor=\1n\1g\1h -TopAreaFillColor=\1n\1g -TopTimeColor=\1n\1y\1h -TopTimeFillColor=\1n\1r -TopTimeLeftColor=\1n\1y\1h -TopTimeLeftFillColor=\1n\1r -TopInfoBracketColor=\1n\1m +TopLabelColor=nbh +TopLabelColonColor=nb +TopFromColor=nch +TopFromFillColor=nc +TopToColor=nch +TopToFillColor=nc +TopSubjColor=nwh +TopSubjFillColor=nw +TopAreaColor=ngh +TopAreaFillColor=ng +TopTimeColor=nyh +TopTimeFillColor=nr +TopTimeLeftColor=nyh +TopTimeLeftFillColor=nr +TopInfoBracketColor=nm ; Colors for the quote window -QuoteWinText=\1n7\1b -QuoteLineHighlightColor=\1n\1w -QuoteWinBorderTextColor=\1n7\1r -QuoteWinBorderColor=\1n\1k7 +QuoteWinText=n7b +QuoteLineHighlightColor=nw +QuoteWinBorderTextColor=n7r +QuoteWinBorderColor=nk7 ; Colors for the bottom row help text -BottomHelpBrackets=\1n\1k\1h -BottomHelpKeys=\1n\1r\1h -BottomHelpFill=\1n\1r -BottomHelpKeyDesc=\1n\1c +BottomHelpBrackets=nkh +BottomHelpKeys=nrh +BottomHelpFill=nr +BottomHelpKeyDesc=nc ; Colors for text boxes -TextBoxBorder=\1n\1k7 -TextBoxBorderText=\1n\1r7 -TextBoxInnerText=\1n\1b7 -YesNoBoxBrackets=\1n\1k7 -YesNoBoxYesNoText=\1n\1w\1h7 +TextBoxBorder=nk7 +TextBoxBorderText=nr7 +TextBoxInnerText=nb7 +YesNoBoxBrackets=nk7 +YesNoBoxYesNoText=nwh7 ; Colors for the menus -SelectedMenuLabelBorders=\1n\1w -SelectedMenuLabelText=\1n\1k7 -UnselectedMenuLabelText=\1n\1w\1h -MenuBorders=\1n\1k7 -MenuSelectedItems=\1n\1w -MenuUnselectedItems=\1n\1k7 -MenuHotkeys=\1n\1w\1h7 +SelectedMenuLabelBorders=nw +SelectedMenuLabelText=nk7 +UnselectedMenuLabelText=nwh +MenuBorders=nk7 +MenuSelectedItems=nw +MenuUnselectedItems=nk7 +MenuHotkeys=nwh7 ; Color settings for list boxes -listBoxBorder=\1n\1g -listBoxBorderText=\1n\1b\1h +listBoxBorder=ng +listBoxBorderText=nbh ; Colors for the cross-post selection box -crossPostMsgAreaNum=\1n\1h\1w -crossPostMsgAreaNumHighlight=\1n4\1h\1w -crossPostMsgAreaDesc=\1n\1c -crossPostMsgAreaDescHighlight=\1n4\1c -crossPostChk=\1n\1h\1y -crossPostChkHighlight=\1n4\1h\1y -crossPostMsgGrpMark=\1n\1h\1g -crossPostMsgGrpMarkHighlight=\1n4\1h\1g +crossPostMsgAreaNum=nhw +crossPostMsgAreaNumHighlight=n4hw +crossPostMsgAreaDesc=nc +crossPostMsgAreaDescHighlight=n4c +crossPostChk=nhy +crossPostChkHighlight=n4hy +crossPostMsgGrpMark=nhg +crossPostMsgGrpMarkHighlight=n4hg ; For the text items in list boxes -listBoxItemText=\1n\1c -listBoxItemHighlight=\1n4\1w\1h +listBoxItemText=nc +listBoxItemHighlight=n4wh ; Colors for message saving and sub-board post info when exiting SlyEdit -msgWillBePostedHdr=\1n\1c -msgPostedGrpHdr=\1n\1h\1b -msgPostedSubBoardName=\1n\1g -msgPostedOriginalAreaText=\1n\1c -msgHasBeenSavedText=\1n\1h\1c -msgAbortedText=\1n\1h\1m -emptyMsgNotSentText=\1n\1h\1m -genMsgErrorText=\1n\1h\1m \ No newline at end of file +msgWillBePostedHdr=nc +msgPostedGrpHdr=nhb +msgPostedSubBoardName=ng +msgPostedOriginalAreaText=nc +msgHasBeenSavedText=nhc +msgAbortedText=nhm +emptyMsgNotSentText=nhm +genMsgErrorText=nhm \ No newline at end of file diff --git a/ctrl/SlyDCTColors_Midnight.cfg b/ctrl/SlyDCTColors_Midnight.cfg index 439febb7eb..0937216ab8 100644 --- a/ctrl/SlyDCTColors_Midnight.cfg +++ b/ctrl/SlyDCTColors_Midnight.cfg @@ -1,88 +1,90 @@ ; This is a color theme file for SlyEdit's DCT Style. ; This is a color scheme I call "Midnight". +; Text edit color +TextEditColor=nw ; The color to use for quoted lines in the message -QuoteLineColor=\1n\1c +QuoteLineColor=nc ; Border colors -TopBorderColor1=\1n\1b -TopBorderColor2=\1n\1k\1h -EditAreaBorderColor1=\1n\1b\1h -EditAreaBorderColor2=\1n\1k\1h -EditModeBrackets=\1n\1k\1h -EditMode=\1n\1w +TopBorderColor1=nb +TopBorderColor2=nkh +EditAreaBorderColor1=nbh +EditAreaBorderColor2=nkh +EditModeBrackets=nkh +EditMode=nw ; Colors for the top informational area -TopLabelColor=\1n\1b\1h -TopLabelColonColor=\1n\1b -TopFromColor=\1n\1c -TopFromFillColor=\1n\1k\1h -TopToColor=\1n\1b -TopToFillColor=\1n\1k\1h -TopSubjColor=\1n\1k\1h -TopSubjFillColor=\1n\1k\1h -TopAreaColor=\1n\1b -TopAreaFillColor=\1n\1k\1h -TopTimeColor=\1n\1k\1h -TopTimeFillColor=\1n\1k\1h -TopTimeLeftColor=\1n\1k\1h -TopTimeLeftFillColor=\1n\1k\1h -TopInfoBracketColor=\1n\1w +TopLabelColor=nbh +TopLabelColonColor=nb +TopFromColor=nc +TopFromFillColor=nkh +TopToColor=nb +TopToFillColor=nkh +TopSubjColor=nkh +TopSubjFillColor=nkh +TopAreaColor=nb +TopAreaFillColor=nkh +TopTimeColor=nkh +TopTimeFillColor=nkh +TopTimeLeftColor=nkh +TopTimeLeftFillColor=nkh +TopInfoBracketColor=nw ; Colors for the quote window -QuoteWinText=\1n7\1b -QuoteLineHighlightColor=\1n\1w -QuoteWinBorderTextColor=\1n7\1r -QuoteWinBorderColor=\1n\1k7 +QuoteWinText=n7b +QuoteLineHighlightColor=nw +QuoteWinBorderTextColor=n7r +QuoteWinBorderColor=nk7 ; Colors for the bottom row help text -BottomHelpBrackets=\1n\1k\1h -BottomHelpKeys=\1n\1b -BottomHelpFill=\1n\1k\1h -BottomHelpKeyDesc=\1n\1c +BottomHelpBrackets=nkh +BottomHelpKeys=nb +BottomHelpFill=nkh +BottomHelpKeyDesc=nc ; Colors for text boxes -TextBoxBorder=\1n\1k\1h -TextBoxBorderText=\1n\1b\1h -TextBoxInnerText=\1n\1w -YesNoBoxBrackets=\1n\1k\1h -YesNoBoxYesNoText=\1n\1w +TextBoxBorder=nkh +TextBoxBorderText=nbh +TextBoxInnerText=nw +YesNoBoxBrackets=nkh +YesNoBoxYesNoText=nw ; Colors for the menus -SelectedMenuLabelBorders=\1n\1b -SelectedMenuLabelText=\1n\1k4 -UnselectedMenuLabelText=\1n\1b -MenuBorders=\1n\1k\1h -MenuSelectedItems=\1n\1w -MenuUnselectedItems=\1n\1b -MenuHotkeys=\1n\1b\1h +SelectedMenuLabelBorders=nb +SelectedMenuLabelText=nk4 +UnselectedMenuLabelText=nb +MenuBorders=nkh +MenuSelectedItems=nw +MenuUnselectedItems=nb +MenuHotkeys=nbh ; Color settings for list boxes -listBoxBorder=\1n\1h\1k -listBoxBorderText=\1n\1b\1h +listBoxBorder=nhk +listBoxBorderText=nbh ; Colors for the cross-post selection box -crossPostBorder=\1n\1h\1k -crossPostBorderText=\1n\1b\1h -crossPostMsgAreaNum=\1n\1h\1w -crossPostMsgAreaNumHighlight=\1n4\1h\1w -crossPostMsgAreaDesc=\1n\1c -crossPostMsgAreaDescHighlight=\1n4\1c -crossPostChk=\1n\1h\1y -crossPostChkHighlight=\1n4\1h\1y -crossPostMsgGrpMark=\1n\1h\1g -crossPostMsgGrpMarkHighlight=\1n4\1h\1g +crossPostBorder=nhk +crossPostBorderText=nbh +crossPostMsgAreaNum=nhw +crossPostMsgAreaNumHighlight=n4hw +crossPostMsgAreaDesc=nc +crossPostMsgAreaDescHighlight=n4c +crossPostChk=nhy +crossPostChkHighlight=n4hy +crossPostMsgGrpMark=nhg +crossPostMsgGrpMarkHighlight=n4hg ; For the text items in list boxes -listBoxItemText=\1n\1b\1h -listBoxItemHighlight=\1n4\1w\1h +listBoxItemText=nbh +listBoxItemHighlight=n4wh ; Colors for message saving and sub-board post info when exiting SlyEdit -msgWillBePostedHdr=\1n\1c -msgPostedGrpHdr=\1n\1h\1b -msgPostedSubBoardName=\1n\1g -msgPostedOriginalAreaText=\1n\1c -msgHasBeenSavedText=\1n\1h\1c -msgAbortedText=\1n\1h\1m -emptyMsgNotSentText=\1n\1h\1m -genMsgErrorText=\1n\1h\1m \ No newline at end of file +msgWillBePostedHdr=nc +msgPostedGrpHdr=nhb +msgPostedSubBoardName=ng +msgPostedOriginalAreaText=nc +msgHasBeenSavedText=nhc +msgAbortedText=nhm +emptyMsgNotSentText=nhm +genMsgErrorText=nhm \ No newline at end of file diff --git a/ctrl/SlyEdit.cfg b/ctrl/SlyEdit.cfg index 420ae20c12..b1e1c0f1e2 100644 --- a/ctrl/SlyEdit.cfg +++ b/ctrl/SlyEdit.cfg @@ -43,22 +43,6 @@ enableTaglines=false ; Whether or not to allow editing quote lines allowEditQuoteLines=true -; Whether or not to allow the user to select a text color -allowColorSelection=true -; Comma-separated list of group names (short name or description) for groups to -; disallow color selection -noColorSelectionGrpNames= -; Comma-separated list of sub-board codes for sub-boards to disallow color -; selection -noColorSelectionSubBoardCodes= -; Comma-separated list of group names (short name or description) for message -; groups where message color codes should be converted to ANSI codes -cvtColorToANSIGrpNames= -; Comma-separated list of sub-board codes for message groups where message color -; codes should be converted to ANSI codes -cvtColorToANSISubBoardCodes= - - ; To use a different color theme file, change the ThemeFilename ; setting. If you want, you can comment out the current setting ; (by placing a ; in front of the line) and un-commenting one diff --git a/ctrl/SlyIceColors_BlueIce.cfg b/ctrl/SlyIceColors_BlueIce.cfg index 95404c667f..7b23f3e612 100644 --- a/ctrl/SlyIceColors_BlueIce.cfg +++ b/ctrl/SlyIceColors_BlueIce.cfg @@ -1,60 +1,62 @@ ; This is a color theme file for SlyEdit's Ice Style. ; This color scheme mimics IceEdit/QuikEdit's "Blue Ice" theme. +; Text edit color +TextEditColor=nw ; The color to use for quoted lines in the message -QuoteLineColor=\1n\1c +QuoteLineColor=nc ; Border colors -BorderColor1=\1n\1b -BorderColor2=\1n\1b\1h -KeyInfoLabelColor=\1c\1h +BorderColor1=nb +BorderColor2=nbh +KeyInfoLabelColor=ch ; Colors for the top informational area TopInfoBkgColor=4 -TopLabelColor=\1c\1h -TopLabelColonColor=\1b\1h -TopToColor=\1w\1h -TopFromColor=\1w\1h -TopSubjectColor=\1w\1h -TopTimeColor=\1g\1h -TopTimeLeftColor=\1g\1h -EditMode=\1c\1h +TopLabelColor=ch +TopLabelColonColor=bh +TopToColor=wh +TopFromColor=wh +TopSubjectColor=wh +TopTimeColor=gh +TopTimeLeftColor=gh +EditMode=ch ; Colors for the quote window -QuoteWinText=\1n\1h\1w -QuoteLineHighlightColor=4\1h\1c -QuoteWinBorderTextColor=\1n\1c\1h +QuoteWinText=nhw +QuoteLineHighlightColor=4hc +QuoteWinBorderTextColor=nch ; Colors for the multi-choice options -SelectedOptionBorderColor=\1n\1b\1h4 -SelectedOptionTextColor=\1n\1c\1h4 -UnselectedOptionBorderColor=\1n\1b -UnselectedOptionTextColor=\1n\1w +SelectedOptionBorderColor=nbh4 +SelectedOptionTextColor=nch4 +UnselectedOptionBorderColor=nb +UnselectedOptionTextColor=nw ; Color settings for list boxes -listBoxBorder=\1n\1b -listBoxBorderText=\1n\1b\1h +listBoxBorder=nb +listBoxBorderText=nbh ; Colors for the cross-post selection box -crossPostMsgAreaNum=\1n\1h\1w -crossPostMsgAreaNumHighlight=\1n4\1h\1w -crossPostMsgAreaDesc=\1n\1c -crossPostMsgAreaDescHighlight=\1n4\1c -crossPostChk=\1n\1h\1y -crossPostChkHighlight=\1n4\1h\1y -crossPostMsgGrpMark=\1n\1h\1g -crossPostMsgGrpMarkHighlight=\1n4\1h\1g +crossPostMsgAreaNum=nhw +crossPostMsgAreaNumHighlight=n4hw +crossPostMsgAreaDesc=nc +crossPostMsgAreaDescHighlight=n4c +crossPostChk=nhy +crossPostChkHighlight=n4hy +crossPostMsgGrpMark=nhg +crossPostMsgGrpMarkHighlight=n4hg ; For the text items in list boxes -listBoxItemText=\1n\1c -listBoxItemHighlight=\1n4\1w\1h +listBoxItemText=nc +listBoxItemHighlight=n4wh ; Colors for message saving and sub-board post info when exiting SlyEdit -msgWillBePostedHdr=\1n\1c -msgPostedGrpHdr=\1n\1h\1b -msgPostedSubBoardName=\1n\1g -msgPostedOriginalAreaText=\1n\1c -msgHasBeenSavedText=\1n\1h\1c -msgAbortedText=\1n\1h\1m -emptyMsgNotSentText=\1n\1h\1m -genMsgErrorText=\1n\1h\1m \ No newline at end of file +msgWillBePostedHdr=nc +msgPostedGrpHdr=nhb +msgPostedSubBoardName=ng +msgPostedOriginalAreaText=nc +msgHasBeenSavedText=nhc +msgAbortedText=nhm +emptyMsgNotSentText=nhm +genMsgErrorText=nhm \ No newline at end of file diff --git a/ctrl/SlyIceColors_EmeraldCity.cfg b/ctrl/SlyIceColors_EmeraldCity.cfg index 670f161cd9..4924ea808e 100644 --- a/ctrl/SlyIceColors_EmeraldCity.cfg +++ b/ctrl/SlyIceColors_EmeraldCity.cfg @@ -1,60 +1,62 @@ ; This is a color theme file for SlyEdit's Ice Style. ; This color scheme mimics IceEdit/QuikEdit's "Emerald City" theme. +; Text edit color +TextEditColor=nw ; The color to use for quoted lines in the message -QuoteLineColor=\1n\1g +QuoteLineColor=ng ; Border colors -BorderColor1=\1n\1g -BorderColor2=\1n\1g\1h -KeyInfoLabelColor=\1c\1h +BorderColor1=ng +BorderColor2=ngh +KeyInfoLabelColor=ch ; Colors for the top informational area TopInfoBkgColor=2 -TopLabelColor=\1c\1h -TopLabelColonColor=\1g\1h -TopToColor=\1w\1h -TopFromColor=\1w\1h -TopSubjectColor=\1w\1h -TopTimeColor=\1g\1h -TopTimeLeftColor=\1g\1h -EditMode=\1c\1h +TopLabelColor=ch +TopLabelColonColor=gh +TopToColor=wh +TopFromColor=wh +TopSubjectColor=wh +TopTimeColor=gh +TopTimeLeftColor=gh +EditMode=ch ; Colors for the quote window -QuoteWinText=\1n\1h\1w -QuoteLineHighlightColor=6\1h\1c -QuoteWinBorderTextColor=\1n\1c\1h +QuoteWinText=nhw +QuoteLineHighlightColor=6hc +QuoteWinBorderTextColor=nch ; Colors for the multi-choice options -SelectedOptionBorderColor=\1n\1c\1h6 -SelectedOptionTextColor=\1n\1c\1h6 -UnselectedOptionBorderColor=\1n\1g -UnselectedOptionTextColor=\1n\1w +SelectedOptionBorderColor=nch6 +SelectedOptionTextColor=nch6 +UnselectedOptionBorderColor=ng +UnselectedOptionTextColor=nw ; Color settings for list boxes -listBoxBorder=\1n\1g -listBoxBorderText=\1n\1g\1h +listBoxBorder=ng +listBoxBorderText=ngh ; Colors for the cross-post selection box -crossPostMsgAreaNum=\1n\1h\1w -crossPostMsgAreaNumHighlight=\1n4\1h\1w -crossPostMsgAreaDesc=\1n\1c -crossPostMsgAreaDescHighlight=\1n4\1c -crossPostChk=\1n\1h\1y -crossPostChkHighlight=\1n4\1h\1y -crossPostMsgGrpMark=\1n\1h\1g -crossPostMsgGrpMarkHighlight=\1n4\1h\1g +crossPostMsgAreaNum=nhw +crossPostMsgAreaNumHighlight=n4hw +crossPostMsgAreaDesc=nc +crossPostMsgAreaDescHighlight=n4c +crossPostChk=nhy +crossPostChkHighlight=n4hy +crossPostMsgGrpMark=nhg +crossPostMsgGrpMarkHighlight=n4hg ; For the text items in list boxes -listBoxItemText=\1n\1g -listBoxItemHighlight=\1n4\1w\1h +listBoxItemText=ng +listBoxItemHighlight=n4wh ; Colors for message saving and sub-board post info when exiting SlyEdit -msgWillBePostedHdr=\1n\1c -msgPostedGrpHdr=\1n\1h\1b -msgPostedSubBoardName=\1n\1g -msgPostedOriginalAreaText=\1n\1c -msgHasBeenSavedText=\1n\1h\1c -msgAbortedText=\1n\1h\1m -emptyMsgNotSentText=\1n\1h\1m -genMsgErrorText=\1n\1h\1m \ No newline at end of file +msgWillBePostedHdr=nc +msgPostedGrpHdr=nhb +msgPostedSubBoardName=ng +msgPostedOriginalAreaText=nc +msgHasBeenSavedText=nhc +msgAbortedText=nhm +emptyMsgNotSentText=nhm +genMsgErrorText=nhm \ No newline at end of file diff --git a/ctrl/SlyIceColors_FieryInferno.cfg b/ctrl/SlyIceColors_FieryInferno.cfg index c0fd369ede..d62cdc8d3c 100644 --- a/ctrl/SlyIceColors_FieryInferno.cfg +++ b/ctrl/SlyIceColors_FieryInferno.cfg @@ -1,60 +1,62 @@ ; This is a color theme file for SlyEdit's Ice Style. ; This color scheme mimics IceEdit/QuikEdit's "Fiery Inferno" theme. +; Text edit color +TextEditColor=nw ; The color to use for quoted lines in the message -QuoteLineColor=\1n\1c +QuoteLineColor=nc ; Border colors -BorderColor1=\1n\1r -BorderColor2=\1n\1r\1h -KeyInfoLabelColor=\1y\1h +BorderColor1=nr +BorderColor2=nrh +KeyInfoLabelColor=yh ; Colors for the top informational area TopInfoBkgColor=1 -TopLabelColor=\1y\1h -TopLabelColonColor=\1r\1h -TopToColor=\1w\1h -TopFromColor=\1w\1h -TopSubjectColor=\1w\1h -TopTimeColor=\1w\1h -TopTimeLeftColor=\1w\1h -EditMode=\1y\1h +TopLabelColor=yh +TopLabelColonColor=rh +TopToColor=wh +TopFromColor=wh +TopSubjectColor=wh +TopTimeColor=wh +TopTimeLeftColor=wh +EditMode=yh ; Colors for the quote window -QuoteWinText=\1n\1h\1w -QuoteLineHighlightColor=1\1h\1y -QuoteWinBorderTextColor=\1n\1y\1h +QuoteWinText=nhw +QuoteLineHighlightColor=1hy +QuoteWinBorderTextColor=nyh ; Colors for the multi-choice options -SelectedOptionBorderColor=\1n\1r\1h1 -SelectedOptionTextColor=\1n\1y\1h1 -UnselectedOptionBorderColor=\1n\1r -UnselectedOptionTextColor=\1n\1w +SelectedOptionBorderColor=nrh1 +SelectedOptionTextColor=nyh1 +UnselectedOptionBorderColor=nr +UnselectedOptionTextColor=nw ; Color settings for list boxes -listBoxBorder=\1n\1r -listBoxBorderText=\1n\1r\1h +listBoxBorder=nr +listBoxBorderText=nrh ; Colors for the cross-post selection box -crossPostMsgAreaNum=\1n\1h\1w -crossPostMsgAreaNumHighlight=\1n4\1h\1w -crossPostMsgAreaDesc=\1n\1c -crossPostMsgAreaDescHighlight=\1n4\1c -crossPostChk=\1n\1h\1y -crossPostChkHighlight=\1n4\1h\1y -crossPostMsgGrpMark=\1n\1h\1g -crossPostMsgGrpMarkHighlight=\1n4\1h\1g +crossPostMsgAreaNum=nhw +crossPostMsgAreaNumHighlight=n4hw +crossPostMsgAreaDesc=nc +crossPostMsgAreaDescHighlight=n4c +crossPostChk=nhy +crossPostChkHighlight=n4hy +crossPostMsgGrpMark=nhg +crossPostMsgGrpMarkHighlight=n4hg ; For the text items in list boxes -listBoxItemText=\1n\1r\1h -listBoxItemHighlight=\1n7\1r +listBoxItemText=nrh +listBoxItemHighlight=n7r ; Colors for message saving and sub-board post info when exiting SlyEdit -msgWillBePostedHdr=\1n\1c -msgPostedGrpHdr=\1n\1h\1b -msgPostedSubBoardName=\1n\1g -msgPostedOriginalAreaText=\1n\1c -msgHasBeenSavedText=\1n\1h\1c -msgAbortedText=\1n\1h\1m -emptyMsgNotSentText=\1n\1h\1m -genMsgErrorText=\1n\1h\1m \ No newline at end of file +msgWillBePostedHdr=nc +msgPostedGrpHdr=nhb +msgPostedSubBoardName=ng +msgPostedOriginalAreaText=nc +msgHasBeenSavedText=nhc +msgAbortedText=nhm +emptyMsgNotSentText=nhm +genMsgErrorText=nhm \ No newline at end of file diff --git a/ctrl/SlyIceColors_Fire-N-Ice.cfg b/ctrl/SlyIceColors_Fire-N-Ice.cfg index 3c01071e21..fc92b940d3 100644 --- a/ctrl/SlyIceColors_Fire-N-Ice.cfg +++ b/ctrl/SlyIceColors_Fire-N-Ice.cfg @@ -1,60 +1,62 @@ ; This is a color theme file for SlyEdit's Ice Style. ; This color scheme mimics IceEdit/QuikEdit's "Fire & Ice" theme. +; Text edit color +TextEditColor=nw ; The color to use for quoted lines in the message -QuoteLineColor=\1n\1c +QuoteLineColor=nc ; Border colors -BorderColor1=\1n\1r -BorderColor2=\1n\1r\1h -KeyInfoLabelColor=\1y\1h +BorderColor1=nr +BorderColor2=nrh +KeyInfoLabelColor=yh ; Colors for the top informational area TopInfoBkgColor=4 -TopLabelColor=\1y\1h -TopLabelColonColor=\1k\1h -TopToColor=\1w\1h -TopFromColor=\1w\1h -TopSubjectColor=\1w\1h -TopTimeColor=\1w\1h -TopTimeLeftColor=\1w\1h -EditMode=\1y\1h +TopLabelColor=yh +TopLabelColonColor=kh +TopToColor=wh +TopFromColor=wh +TopSubjectColor=wh +TopTimeColor=wh +TopTimeLeftColor=wh +EditMode=yh ; Colors for the quote window -QuoteWinText=\1n\1h\1w -QuoteLineHighlightColor=4\1h\1y -QuoteWinBorderTextColor=\1n\1y\1h +QuoteWinText=nhw +QuoteLineHighlightColor=4hy +QuoteWinBorderTextColor=nyh ; Colors for the multi-choice options -SelectedOptionBorderColor=\1n\1b\1h4 -SelectedOptionTextColor=\1n\1y\1h4 -UnselectedOptionBorderColor=\1n\1b -UnselectedOptionTextColor=\1n\1w +SelectedOptionBorderColor=nbh4 +SelectedOptionTextColor=nyh4 +UnselectedOptionBorderColor=nb +UnselectedOptionTextColor=nw ; Color settings for list boxes -listBoxBorder=\1n\1r -listBoxBorderText=\1n\1b\1h +listBoxBorder=nr +listBoxBorderText=nbh ; Colors for the cross-post selection box -crossPostMsgAreaNum=\1n\1h\1w -crossPostMsgAreaNumHighlight=\1n4\1h\1w -crossPostMsgAreaDesc=\1n\1c -crossPostMsgAreaDescHighlight=\1n4\1c -crossPostChk=\1n\1h\1y -crossPostChkHighlight=\1n4\1h\1y -crossPostMsgGrpMark=\1n\1h\1g -crossPostMsgGrpMarkHighlight=\1n4\1h\1g +crossPostMsgAreaNum=nhw +crossPostMsgAreaNumHighlight=n4hw +crossPostMsgAreaDesc=nc +crossPostMsgAreaDescHighlight=n4c +crossPostChk=nhy +crossPostChkHighlight=n4hy +crossPostMsgGrpMark=nhg +crossPostMsgGrpMarkHighlight=n4hg ; For the text items in list boxes -listBoxItemText=\1n\1b\1h -listBoxItemHighlight=\1n4\1w\1h +listBoxItemText=nbh +listBoxItemHighlight=n4wh ; Colors for message saving and sub-board post info when exiting SlyEdit -msgWillBePostedHdr=\1n\1c -msgPostedGrpHdr=\1n\1h\1b -msgPostedSubBoardName=\1n\1g -msgPostedOriginalAreaText=\1n\1c -msgHasBeenSavedText=\1n\1h\1c -msgAbortedText=\1n\1h\1m -emptyMsgNotSentText=\1n\1h\1m -genMsgErrorText=\1n\1h\1m \ No newline at end of file +msgWillBePostedHdr=nc +msgPostedGrpHdr=nhb +msgPostedSubBoardName=ng +msgPostedOriginalAreaText=nc +msgHasBeenSavedText=nhc +msgAbortedText=nhm +emptyMsgNotSentText=nhm +genMsgErrorText=nhm \ No newline at end of file diff --git a/ctrl/SlyIceColors_GenericBlue.cfg b/ctrl/SlyIceColors_GenericBlue.cfg index b7849c162c..2643030bc2 100644 --- a/ctrl/SlyIceColors_GenericBlue.cfg +++ b/ctrl/SlyIceColors_GenericBlue.cfg @@ -1,60 +1,62 @@ ; This is a color theme file for SlyEdit's Ice Style. ; This color scheme mimics IceEdit/QuikEdit's "Generic Blue" theme. +; Text edit color +TextEditColor=nw ; The color to use for quoted lines in the message -QuoteLineColor=\1n\1c +QuoteLineColor=nc ; Border colors -BorderColor1=\1n\1b -BorderColor2=\1n\1b -KeyInfoLabelColor=\1c\1h +BorderColor1=nb +BorderColor2=nb +KeyInfoLabelColor=ch ; Colors for the top informational area TopInfoBkgColor=4 -TopLabelColor=\1c\1h -TopLabelColonColor=\1b\1h -TopToColor=\1w\1h -TopFromColor=\1w\1h -TopSubjectColor=\1w\1h -TopTimeColor=\1b\1h -TopTimeLeftColor=\1b\1h -EditMode=\1c\1h +TopLabelColor=ch +TopLabelColonColor=bh +TopToColor=wh +TopFromColor=wh +TopSubjectColor=wh +TopTimeColor=bh +TopTimeLeftColor=bh +EditMode=ch ; Colors for the quote window -QuoteWinText=\1n\1h\1w -QuoteLineHighlightColor=4\1h\1c -QuoteWinBorderTextColor=\1n\1c\1h +QuoteWinText=nhw +QuoteLineHighlightColor=4hc +QuoteWinBorderTextColor=nch ; Colors for the multi-choice options -SelectedOptionBorderColor=\1n\1b\1h4 -SelectedOptionTextColor=\1n\1c\1h4 -UnselectedOptionBorderColor=\1n\1w -UnselectedOptionTextColor=\1n\1w +SelectedOptionBorderColor=nbh4 +SelectedOptionTextColor=nch4 +UnselectedOptionBorderColor=nw +UnselectedOptionTextColor=nw ; Color settings for list boxes -listBoxBorder=\1n\1b -listBoxBorderText=\1n\1b\1h +listBoxBorder=nb +listBoxBorderText=nbh ; Colors for the cross-post selection box -crossPostMsgAreaNum=\1n\1h\1w -crossPostMsgAreaNumHighlight=\1n4\1h\1w -crossPostMsgAreaDesc=\1n\1c -crossPostMsgAreaDescHighlight=\1n4\1c -crossPostChk=\1n\1h\1y -crossPostChkHighlight=\1n4\1h\1y -crossPostMsgGrpMark=\1n\1h\1g -crossPostMsgGrpMarkHighlight=\1n4\1h\1g +crossPostMsgAreaNum=nhw +crossPostMsgAreaNumHighlight=n4hw +crossPostMsgAreaDesc=nc +crossPostMsgAreaDescHighlight=n4c +crossPostChk=nhy +crossPostChkHighlight=n4hy +crossPostMsgGrpMark=nhg +crossPostMsgGrpMarkHighlight=n4hg ; For the text items in list boxes -listBoxItemText=\1n\1b\1h -listBoxItemHighlight=\1n4\1w\1h +listBoxItemText=nbh +listBoxItemHighlight=n4wh ; Colors for message saving and sub-board post info when exiting SlyEdit -msgWillBePostedHdr=\1n\1c -msgPostedGrpHdr=\1n\1h\1b -msgPostedSubBoardName=\1n\1g -msgPostedOriginalAreaText=\1n\1c -msgHasBeenSavedText=\1n\1h\1c -msgAbortedText=\1n\1h\1m -emptyMsgNotSentText=\1n\1h\1m -genMsgErrorText=\1n\1h\1m \ No newline at end of file +msgWillBePostedHdr=nc +msgPostedGrpHdr=nhb +msgPostedSubBoardName=ng +msgPostedOriginalAreaText=nc +msgHasBeenSavedText=nhc +msgAbortedText=nhm +emptyMsgNotSentText=nhm +genMsgErrorText=nhm \ No newline at end of file diff --git a/ctrl/SlyIceColors_PurpleHaze.cfg b/ctrl/SlyIceColors_PurpleHaze.cfg index 285796923a..f75fba4181 100644 --- a/ctrl/SlyIceColors_PurpleHaze.cfg +++ b/ctrl/SlyIceColors_PurpleHaze.cfg @@ -1,59 +1,61 @@ ; This is a color theme file for SlyEdit's Ice Style. +; Text edit color +TextEditColor=nw ; The color to use for quoted lines in the message -QuoteLineColor=\1n\1c +QuoteLineColor=nc ; Border colors -BorderColor1=\1n\1m -BorderColor2=\1n\1m\1h -KeyInfoLabelColor=\1n\1m +BorderColor1=nm +BorderColor2=nmh +KeyInfoLabelColor=nm ; Colors for the top informational area -TopInfoBkgColor=\1n -TopLabelColor=\1n\1m -TopLabelColonColor=\1b\1h -TopToColor=\1m\1h -TopFromColor=\1m\1h -TopSubjectColor=\1m\1h -TopTimeColor=\1n\1m\1h -TopTimeLeftColor=\1n\1m\1h -EditMode=\1n\1c +TopInfoBkgColor=n +TopLabelColor=nm +TopLabelColonColor=bh +TopToColor=mh +TopFromColor=mh +TopSubjectColor=mh +TopTimeColor=nmh +TopTimeLeftColor=nmh +EditMode=nc ; Colors for the quote window -QuoteWinText=\1n\1h\1w -QuoteLineHighlightColor=4\1h\1m -QuoteWinBorderTextColor=\1n\1c\1h +QuoteWinText=nhw +QuoteLineHighlightColor=4hm +QuoteWinBorderTextColor=nch ; Colors for the multi-choice options -SelectedOptionBorderColor=\1n\1b\1h4 -SelectedOptionTextColor=\1n\1c\1h4 -UnselectedOptionBorderColor=\1n\1b -UnselectedOptionTextColor=\1n\1w +SelectedOptionBorderColor=nbh4 +SelectedOptionTextColor=nch4 +UnselectedOptionBorderColor=nb +UnselectedOptionTextColor=nw ; Color settings for list boxes -listBoxBorder=\1n\1m -listBoxBorderText=\1n\1b\1h +listBoxBorder=nm +listBoxBorderText=nbh ; Colors for the cross-post selection box -crossPostMsgAreaNum=\1n\1h\1w -crossPostMsgAreaNumHighlight=\1n4\1h\1w -crossPostMsgAreaDesc=\1n\1c -crossPostMsgAreaDescHighlight=\1n4\1m\1h -crossPostChk=\1n\1h\1y -crossPostChkHighlight=\1n4\1h\1y -crossPostMsgGrpMark=\1n\1h\1g -crossPostMsgGrpMarkHighlight=\1n4\1h\1g +crossPostMsgAreaNum=nhw +crossPostMsgAreaNumHighlight=n4hw +crossPostMsgAreaDesc=nc +crossPostMsgAreaDescHighlight=n4mh +crossPostChk=nhy +crossPostChkHighlight=n4hy +crossPostMsgGrpMark=nhg +crossPostMsgGrpMarkHighlight=n4hg ; For the text items in list boxes -listBoxItemText=\1n\1c -listBoxItemHighlight=\1n4\1m\1h +listBoxItemText=nc +listBoxItemHighlight=n4mh ; Colors for message saving and sub-board post info when exiting SlyEdit -msgWillBePostedHdr=\1n\1c -msgPostedGrpHdr=\1n\1h\1b -msgPostedSubBoardName=\1n\1g -msgPostedOriginalAreaText=\1n\1c -msgHasBeenSavedText=\1n\1h\1c -msgAbortedText=\1n\1h\1m -emptyMsgNotSentText=\1n\1h\1m -genMsgErrorText=\1n\1h\1m \ No newline at end of file +msgWillBePostedHdr=nc +msgPostedGrpHdr=nhb +msgPostedSubBoardName=ng +msgPostedOriginalAreaText=nc +msgHasBeenSavedText=nhc +msgAbortedText=nhm +emptyMsgNotSentText=nhm +genMsgErrorText=nhm \ No newline at end of file diff --git a/ctrl/SlyIceColors_ShadesOfGrey.cfg b/ctrl/SlyIceColors_ShadesOfGrey.cfg index c1024ddd10..6b805a9eb2 100644 --- a/ctrl/SlyIceColors_ShadesOfGrey.cfg +++ b/ctrl/SlyIceColors_ShadesOfGrey.cfg @@ -1,60 +1,62 @@ ; This is a color theme file for SlyEdit's Ice Style. ; This color scheme mimics IceEdit/QuikEdit's "Shades of Gray" theme. +; Text edit color +TextEditColor=nw ; The color to use for quoted lines in the message -QuoteLineColor=\1n\1k\1h +QuoteLineColor=nkh ; Border colors -BorderColor1=\1n\1k\1h -BorderColor2=\1n\1b -KeyInfoLabelColor=\1n\1w +BorderColor1=nkh +BorderColor2=nb +KeyInfoLabelColor=nw ; Colors for the top informational area TopInfoBkgColor=4 -TopLabelColor=\1n\1w4 -TopLabelColonColor=\1b\1h -TopToColor=\1w\1h -TopFromColor=\1w\1h -TopSubjectColor=\1w\1h -TopTimeColor=\1w\1h -TopTimeLeftColor=\1w\1h -EditMode=\1n\1w4 +TopLabelColor=nw4 +TopLabelColonColor=bh +TopToColor=wh +TopFromColor=wh +TopSubjectColor=wh +TopTimeColor=wh +TopTimeLeftColor=wh +EditMode=nw4 ; Colors for the quote window -QuoteWinText=\1n\1h\1w -QuoteLineHighlightColor=7\1h\1w -QuoteWinBorderTextColor=\1n\1w +QuoteWinText=nhw +QuoteLineHighlightColor=7hw +QuoteWinBorderTextColor=nw ; Colors for the multi-choice options -SelectedOptionBorderColor=\1n\1w\1h7 -SelectedOptionTextColor=\1n\1w\1h7 -UnselectedOptionBorderColor=\1n\1k\1h -UnselectedOptionTextColor=\1n\1w\1h +SelectedOptionBorderColor=nwh7 +SelectedOptionTextColor=nwh7 +UnselectedOptionBorderColor=nkh +UnselectedOptionTextColor=nwh ; Color settings for list boxes -listBoxBorder=\1n\1h\1k -listBoxBorderText=\1n\1w +listBoxBorder=nhk +listBoxBorderText=nw ; Colors for the cross-post selection box -crossPostMsgAreaNum=\1n\1h\1w -crossPostMsgAreaNumHighlight=\1n4\1h\1w -crossPostMsgAreaDesc=\1n\1c -crossPostMsgAreaDescHighlight=\1n4\1c -crossPostChk=\1n\1h\1y -crossPostChkHighlight=\1n4\1h\1y -crossPostMsgGrpMark=\1n\1h\1g -crossPostMsgGrpMarkHighlight=\1n4\1h\1g +crossPostMsgAreaNum=nhw +crossPostMsgAreaNumHighlight=n4hw +crossPostMsgAreaDesc=nc +crossPostMsgAreaDescHighlight=n4c +crossPostChk=nhy +crossPostChkHighlight=n4hy +crossPostMsgGrpMark=nhg +crossPostMsgGrpMarkHighlight=n4hg ; For the text items in list boxes -listBoxItemText=\1n\1w -listBoxItemHighlight=\1n4\1w\1h +listBoxItemText=nw +listBoxItemHighlight=n4wh ; Colors for message saving and sub-board post info when exiting SlyEdit -msgWillBePostedHdr=\1n\1c -msgPostedGrpHdr=\1n\1h\1b -msgPostedSubBoardName=\1n\1g -msgPostedOriginalAreaText=\1n\1c -msgHasBeenSavedText=\1n\1h\1c -msgAbortedText=\1n\1h\1m -emptyMsgNotSentText=\1n\1h\1m -genMsgErrorText=\1n\1h\1m \ No newline at end of file +msgWillBePostedHdr=nc +msgPostedGrpHdr=nhb +msgPostedSubBoardName=ng +msgPostedOriginalAreaText=nc +msgHasBeenSavedText=nhc +msgAbortedText=nhm +emptyMsgNotSentText=nhm +genMsgErrorText=nhm \ No newline at end of file diff --git a/docs/SlyEdit_ReadMe.txt b/docs/SlyEdit_ReadMe.txt index 4638b56547..459e3a7364 100644 --- a/docs/SlyEdit_ReadMe.txt +++ b/docs/SlyEdit_ReadMe.txt @@ -1,6 +1,6 @@ SlyEdit message editor - Version 1.59 - Release date: 2018-02-01 + Version 1.54 + Release date: 2017-12-26 by @@ -198,7 +198,7 @@ BBS machine): Help keys Slash commands (on blank line) --------- ------------------------------ Ctrl-G : General help � /A : Abort -Ctrl-L : Command key list (this list) � /S : Save +Ctrl-P : Command key help � /S : Save Ctrl-R : Program information � /Q : Quote message Ctrl-T : List text replacements � /T : List text replacements � /U : Your settings @@ -207,11 +207,11 @@ Command/edit keys ----------------- Ctrl-A : Abort message � PageUp : Page up Ctrl-Z : Save message � PageDown: Page down -Ctrl-Q : Quote message � Ctrl-S : Search for text +Ctrl-Q : Quote message � Ctrl-N : Find text Insert/Ctrl-I: Toggle insert/overwrite mode � Ctrl-D : Delete line ESC : Command menu -Ctrl-U : Your settings � Ctrl-K : Choose text color Ctrl-O : Import a file � Ctrl-X : Export to file +Ctrl-U : Your settings 5. Digital Distortion Message Lister note @@ -341,31 +341,6 @@ enableTagLines Whether or not to enable the option for users setting, which users can configure in their own settings. -allowColorSelection Whether or not to allow users to select text - colors for their message. Valid values are - true and false. - -noColorSelectionGrpNames A comma-separated list of message group names - where users are not allowed to select colors - for their message. These can be the group's - short names or their descriptions. - -noColorSelectionSubBoardCodes A comma-separated list of message sub-board - internal codes where users are not allowed - to select colors for their message. - -cvtColorToANSIGrpNames A comma-separated list of group names for - message groups where text color codes should - be converted to ANSI codes. These can be the - group's short names or their descriptions. - This can also be "All" to have SlyEdit - convert to ANSI for all message groups. - - -cvtColorToANSISubBoardCodes A comma-separated list of sub-board internal - codes where text color codes should be - converted to ANSI codes. - Ice colors ---------- Setting Description @@ -685,12 +660,12 @@ listBoxItemHighlight The color to use for the currently selected 10. Text replacements (AKA Macros) ================================== -Text replacements (AKA Macros), which lets you (the sysop) define words to be -replaced with other text as the user types a message. This feature can be -used, for instance, to replace commonly misspelled words with their correct -versions or to replace swear words with less offensive words. This feature is -toggled by the enableTextReplacements option in SlyEdit.cfg can can have one of -three values: +SlyEdit version 1.29 added text replacements (AKA Macros), which lets you (the +sysop) define words to be replaced with other text as the user types a message. +This feature can be used, for instance, to replace commonly misspelled words +with their correct versions or to replace swear words with less offensive +words. This feature is toggled by the enableTextReplacements option in +SlyEdit.cfg can can have one of three values: false : Text replacement is disabled true : Text replacement is enabled and performed as literal search and replace regex : Text replacement is enabled using regular expressions as implemented by @@ -699,14 +674,12 @@ regex : Text replacement is enabled using regular expressions as implemented by JavaScript-C or "SpiderMonkey"). The text searches are performed on single words only, as the user types the -message, and are replaced by whatever text you configure for the word. -Synchronet color/attribute codes are allowed in the replacement text, but the -color/attribute codes will be stripped if colors are not allowed according to -the SlyEdit configuration. The configuration for text replacing is read from a -configuration file called SlyEdit_TextReplacements.cfg, which is plain text and -can be placed in either sbbs/ctrl or in the same directory as SlyEdit's .js -files (SlyEdit.js, SlyEdit_Misc.js, etc.). Each line in -SlyEdit_TextReplacements.cfg needs to have the following format: +message, and are replaced by whatever text you configure for the word. The +configuration for text replacing is read from a configuration file called +SlyEdit_TextReplacements.cfg, which is plain text and can be placed in either +sbbs/ctrl or in the same directory as SlyEdit's .js files (SlyEdit.js, +SlyEdit_Misc.js, etc.). Each line in SlyEdit_TextReplacements.cfg needs to +have the following format: originalWord=replacementText where originalWord is the word to be replaced, and replacementText is the text to replace the word with. diff --git a/exec/SlyEdit.js b/exec/SlyEdit.js index 460d160287..f3ef2392c9 100644 --- a/exec/SlyEdit.js +++ b/exec/SlyEdit.js @@ -34,56 +34,6 @@ * or more non-space characters before the >. Also * fixed an issue where wrapped quote lines were * sometimes missing the quote line prefix. - * 2017-12-27 Eric Oulashin Version 1.55 Beta - * Started working on text color selection again - * 2018-01-04 Eric Oulashin Version 1.55 - * Releasing this version, with text color support. - * It seems to be working fairly well overall. - * 2018-01-05 Eric Oulashin Version 1.56 - * Fixed a bug reported by Al: When saving a message - * with /s on a blank line, SlyEdit was quitting with - * an error due to a non-existent edit line. - * 2018-01-08 Eric Oulashin Version 1.57 - * Updated the settings noColorSelectionInGrpNames, - * noColorSelectionInSubBoardCodes, cvtColorToANSIGrpNames, - * and cvtColorToANSISubBoardCodes to be comma-separated - * only (instead of either comma or space-separated), - * to keep things simple and in case there are any spaces - * in any message group descriptions. - * Removed the TextEditColor setting from the color theme - * files, since that probably no longer makes sense now - * that the user can change the text color. - * When inserting quote lines into a message, ensured the - * quote lines have the "normal" attribute. The user's - * chosen colors are applied to their own text lines. - * When importing a file (for sysops only), any color or - * attribute codes are stripped if colors are not allowed - * in the current message area according to the SlyEdit - * configuration file. - * Fixed a bug in refreshing the help text line on the - * bottom of the screen after choosing text colors. - * Also, updated to remove ANSI from quote lines so that - * quote lines look better. - * 2018-01-27 Eric Oulashin Version 1.58 Beta - * Bug fix: - * - Incorrect color used when refreshing quote lines - * (such as when the User Settings dialog is closed) - * - After changing the text color for text above a - * quote line, the incorrect color was used for - * refreshing quote lines below it - * Also, when saving a message, SlyEdit now removes any - * stray ASCII-1 characters that aren't part of a - * Synchronet color code. - * 2018-01-28 Eric Oulashin Version 1.58 - * Releasing this version - * 2018-02-01 Eric Oulashin Version 1.59 - * Updated to strip control characters from the - * information read from the drop file. Also made a bug - * fix: When backspacing, it now properly removes any - * Synchronet attribute codes immediately after the - * character being deleted. - * 2018-02-02 Eric Oulashin Version 1.60 - * Bug fixes for edit line indexes with a wide terminal */ /* Command-line arguments: @@ -129,10 +79,10 @@ var gConfigSettings = ReadSlyEditConfigFile(); var gUserSettings = ReadUserSettingsFile(gConfigSettings); // Load any specified 3rd-party startup scripts for (var i = 0; i < gConfigSettings.thirdPartyLoadOnStart.length; ++i) - load(gConfigSettings.thirdPartyLoadOnStart[i]); + load(gConfigSettings.thirdPartyLoadOnStart[i]); // Execute any provided startup JavaScript commands for (var i = 0; i < gConfigSettings.runJSOnStart.length; ++i) - eval(gConfigSettings.runJSOnStart[i]); + eval(gConfigSettings.runJSOnStart[i]); const EDITOR_PROGRAM_NAME = "SlyEdit"; const ERRORMSG_PAUSE_MS = 1500; @@ -161,8 +111,8 @@ if (!console.term_supports(USER_ANSI)) } // Constants -const EDITOR_VERSION = "1.60"; -const EDITOR_VER_DATE = "2018-02-02"; +const EDITOR_VERSION = "1.54"; +const EDITOR_VER_DATE = "2017-12-26"; // Program variables @@ -185,8 +135,9 @@ if (console.screen_columns < 80) // Colors var gQuoteWinTextColor = "\1n\1" + "7\1k"; // Normal text color for the quote window (DCT default) var gQuoteLineHighlightColor = "\1n\1w"; // Highlighted text color for the quote window (DCT default) -var gTextAttrs = "\1n"; // The text color for edit mode +var gTextAttrs = "\1n\1w"; // The text color for edit mode var gQuoteLineColor = "\1n\1c"; // The text color for quote lines +var gUseTextAttribs = false; // Will be set to true if text colors start to be used // gQuotePrefix contains the text to prepend to quote lines. // gQuotePrefix will later be updated to include the "To" user's @@ -208,9 +159,9 @@ var gCrossPostMsgSubs = new Object(); // Return value: Boolean - Whether or not the property is the name of one of the // functions in the gCrossPostMsgSubs object gCrossPostMsgSubs.propIsFuncName = function(pPropName) { - return((pPropName == "propIsFuncName") || (pPropName == "add") || (pPropName == "remove") || - (pPropName == "subCodeExists") || (pPropName == "numMsgGrps") || - (pPropName == "numSubBoards")); + return((pPropName == "propIsFuncName") || (pPropName == "add") || (pPropName == "remove") || + (pPropName == "subCodeExists") || (pPropName == "numMsgGrps") || + (pPropName == "numSubBoards")); }; // This function returns whether or not the a message sub-coard code exists in // gCrossPostMsgSubs. @@ -218,14 +169,14 @@ gCrossPostMsgSubs.propIsFuncName = function(pPropName) { // Parameters: // pSubCode: The sub-code to look for gCrossPostMsgSubs.subCodeExists = function(pSubCode) { - if (typeof(pSubCode) != "string") - return false; - - var grpIndex = msg_area.sub[pSubCode].grp_index; - var foundIt = false; - if (this.hasOwnProperty(grpIndex)) - foundIt = this[grpIndex].hasOwnProperty(pSubCode); - return foundIt; + if (typeof(pSubCode) != "string") + return false; + + var grpIndex = msg_area.sub[pSubCode].grp_index; + var foundIt = false; + if (this.hasOwnProperty(grpIndex)) + foundIt = this[grpIndex].hasOwnProperty(pSubCode); + return foundIt; }; // This function adds a sub-board code to gCrossPostMsgSubs. // @@ -247,41 +198,41 @@ gCrossPostMsgSubs.add = function(pSubCode) { // Parameters: // pSubCode: The sub-code to remove gCrossPostMsgSubs.remove = function(pSubCode) { - if (typeof(pSubCode) != "string") - return; + if (typeof(pSubCode) != "string") + return; - var grpIndex = msg_area.sub[pSubCode].grp_index; - if (this.hasOwnProperty(grpIndex)) - { - delete this[grpIndex][pSubCode]; - if (numObjProperties(this[grpIndex]) == 0) - delete this[grpIndex]; - } + var grpIndex = msg_area.sub[pSubCode].grp_index; + if (this.hasOwnProperty(grpIndex)) + { + delete this[grpIndex][pSubCode]; + if (numObjProperties(this[grpIndex]) == 0) + delete this[grpIndex]; + } }; // This function returns the number of message groups in // gCrossPostMsgSubs. gCrossPostMsgSubs.numMsgGrps = function() { - var msgGrpCount = 0; - for (var prop in this) - { - if (!this.propIsFuncName(prop)) - ++msgGrpCount; - } - return msgGrpCount; + var msgGrpCount = 0; + for (var prop in this) + { + if (!this.propIsFuncName(prop)) + ++msgGrpCount; + } + return msgGrpCount; }; // This function returns the number of sub-boards the user has chosen to post // the message into. gCrossPostMsgSubs.numSubBoards = function () { - var numMsgSubs = 0; - for (var grpIndex in this) - { - if (!this.propIsFuncName(grpIndex)) - { - for (var subCode in gCrossPostMsgSubs[grpIndex]) - ++numMsgSubs; - } - } - return numMsgSubs; + var numMsgSubs = 0; + for (var grpIndex in this) + { + if (!this.propIsFuncName(grpIndex)) + { + for (var subCode in gCrossPostMsgSubs[grpIndex]) + ++numMsgSubs; + } + } + return numMsgSubs; } @@ -303,6 +254,7 @@ if (EDITOR_STYLE == "DCT") gEditTop = 6; gQuoteWinTextColor = gConfigSettings.DCTColors.QuoteWinText; gQuoteLineHighlightColor = gConfigSettings.DCTColors.QuoteLineHighlightColor; + gTextAttrs = gConfigSettings.DCTColors.TextEditColor; gQuoteLineColor = gConfigSettings.DCTColors.QuoteLineColor; // Function pointers for the DCTEdit-style screen update functions @@ -322,6 +274,7 @@ else if (EDITOR_STYLE == "ICE") gEditTop = 5; gQuoteWinTextColor = gConfigSettings.iceColors.QuoteWinText; gQuoteLineHighlightColor = gConfigSettings.iceColors.QuoteLineHighlightColor; + gTextAttrs = gConfigSettings.iceColors.TextEditColor; gQuoteLineColor = gConfigSettings.iceColors.QuoteLineColor; // Function pointers for the IceEdit-style screen update functions @@ -354,7 +307,7 @@ var gQuoteLinesTopIndex = 0; // Index of the first displayed quote line var gQuoteLinesIndex = 0; // Index of the current quote line // The gEditLines array will contain TextLine objects storing the line // information. -var gEditLines = []; +var gEditLines = new Array(); var gEditLinesIndex = 0; // Index into gEditLines for the line being edited var gTextLineIndex = 0; // Index into the current text line being edited // Format strings used for printf() to display text in the edit area @@ -373,6 +326,12 @@ function clearEditAreaBuffer() gEditAreaBuffer[lineNum] = ""; } clearEditAreaBuffer(); +// gTxtreplacements will be an associative array that stores words (in upper +// case) to be replaced with other words. +var gNumTxtReplacements = 0; +var gTxtReplacements = new Object(); +if (gConfigSettings.enableTextReplacements) + gNumTxtReplacements = populateTxtReplacements(gTxtReplacements, gConfigSettings.textReplacementsUseRegex); // Set some stuff up for message editing var gUseQuotes = true; @@ -418,12 +377,12 @@ console.clear(); // Read the message from name, to name, and subject from the drop file // (msginf in the node directory). -var gMsgAreaNameInfo = null; // Will store the value returned by getCurMsgInfo(). +var gMsgAreaInfo = null; // Will store the value returned by getCurMsgInfo(). var setMsgAreaInfoObj = false; var gMsgSubj = ""; var gFromName = user.alias; var gToName = gInputFilename; -var gMsgAreaName = ""; +var gMsgArea = ""; var gTaglineFile = ""; var dropFileTime = -Infinity; var dropFileName = file_getcase(system.node_dir + "msginf"); @@ -438,15 +397,15 @@ if (dropFileName != undefined) info = dropFile.readAll(); dropFile.close(); - gFromName = strip_ctrl(info[0]); - gToName = strip_ctrl(info[1]); - gMsgSubj = strip_ctrl(info[2]); - gMsgAreaName = strip_ctrl(info[4]); + gFromName = info[0]; + gToName = info[1]; + gMsgSubj = info[2]; + gMsgArea = info[4]; // Now that we know the name of the message area // that the message is being posted in, call - // getCurMsgInfo() to set gMsgAreaNameInfo. - gMsgAreaNameInfo = getCurMsgInfo(gMsgAreaName); + // getCurMsgInfo() to set gMsgAreaInfo. + gMsgAreaInfo = getCurMsgInfo(gMsgArea); setMsgAreaInfoObj = true; // If the msginf file has 7 lines, then the 7th line is the full @@ -460,26 +419,19 @@ if (dropFileName != undefined) } file_remove(dropFileName); } -// If gMsgAreaNameInfo hasn't been set yet, then set it. +// If gMsgAreaInfo hasn't been set yet, then set it. if (!setMsgAreaInfoObj) { - gMsgAreaNameInfo = getCurMsgInfo(gMsgAreaName); + gMsgAreaInfo = getCurMsgInfo(gMsgArea); setMsgAreaInfoObj = true; } -// gTxtreplacements will be an associative array that stores words (in upper -// case) to be replaced with other words. -var gNumTxtReplacements = 0; -var gTxtReplacements = new Object(); -if (gConfigSettings.enableTextReplacements) - gNumTxtReplacements = populateTxtReplacements(gTxtReplacements, gConfigSettings.textReplacementsUseRegex); - // Set a variable to store whether or not cross-posting can be done. -var gCanCrossPost = (gConfigSettings.allowCrossPosting && postingInMsgSubBoard(gMsgAreaName)); +var gCanCrossPost = (gConfigSettings.allowCrossPosting && postingInMsgSubBoard(gMsgArea)); // If the user is posting in a message sub-board, then add its information // to gCrossPostMsgSubs. -if (postingInMsgSubBoard(gMsgAreaName)) - gCrossPostMsgSubs.add(gMsgAreaNameInfo.subBoardCode); +if (postingInMsgSubBoard(gMsgArea)) + gCrossPostMsgSubs.add(gMsgAreaInfo.subBoardCode); // Open the quote file / message file readQuoteOrMessageFile(); @@ -494,83 +446,17 @@ var gOldSubj = gMsgSubj; // Now it's edit time. var exitCode = doEditLoop(); -var crossPostEditLines = []; // For a copy of the edit lines, for cross-posting, in case of different color settings -// Do some post-edit processing of the message lines (in gEditLines) +// Remove any extra blank lines that may be at the end of +// the message (in gEditLines). if ((exitCode == 0) && (gEditLines.length > 0)) { - // Remove any extra blank lines that may be at the end of - // the message lines var lineIndex = gEditLines.length - 1; - while ((lineIndex > 0) && (lineIndex < gEditLines.length) && (gEditLines[lineIndex].displayLength() == 0)) + while ((lineIndex > 0) && (lineIndex < gEditLines.length) && + (gEditLines[lineIndex].length() == 0)) { gEditLines.splice(lineIndex, 1); --lineIndex; } - - ///// - // Color processing - - // If there are other message areas selected for cross-posting, - // save a copy of the message lines so we can do color processing - // as needed for the other message areas to be cross-posted into - if (gCrossPostMsgSubs.numMsgGrps() > 0) - { - for (var i = 0; i < gEditLines.length; ++i) - { - var editLineCopy = new TextLine(); - editLineCopy.text = gEditLines[i].text; - editLineCopy.hardNewlineEnd = gEditLines[i].hardNewlineEnd; - editLineCopy.isQuoteLine = gEditLines[i].isQuoteLine; - editLineCopy.text = gEditLines[i].text; - crossPostEditLines.push(editLineCopy); - } - } - - // If the message text contains only "\1n" or "\1n\1w" attribute codes, - // then strip them all out. Also, if other Synchronet color codes are - // found, then check to see if color codes should be converted to ANSI, - // and if so, do it. - var sawOtherSyncAttrs = false; - var syncAttrRegexWithoutNormalOrWhite = /[krgybmc01234567hipq,;\.dtl<>\[\]asz]/i; - for (var i = 0; (i < gEditLines.length) && !sawOtherSyncAttrs; ++i) - sawOtherSyncAttrs = syncAttrRegexWithoutNormalOrWhite.test(gEditLines[i].text); - if (sawOtherSyncAttrs) - { - if (shouldConvertMsgColorsToANSIInMsgArea(gMsgAreaName, bbs.cursub_code)) - { - for (var i = 0; i < gEditLines.length; ++i) - gEditLines[i].text = SyncAttrsToANSI(gEditLines[i].text); - } - } - else - { - // Check to see if there are only normal or normal & white attribute codes - var sawNormalAttrOnly = false; - var sawNormalAndWhiteOnly = false; - for (var i = 0; (i < gEditLines.length) && !sawNormalAttrOnly && !sawNormalAndWhiteOnly; ++i) - { - sawNormalAttrOnly = /n/gi.test(gEditLines[i].text); - sawNormalAndWhiteOnly = /nw/gi.test(gEditLines[i].text); - } - if (sawNormalAttrOnly || sawNormalAndWhiteOnly) - { - // Remove the normal & normal-white attribute codes. - for (var i = 0; i < gEditLines.length; ++i) - { - gEditLines[i].text = gEditLines[i].text.replace(/[nw]/ig, ""); - if (crossPostEditLines.length > i) - crossPostEditLines[i].text = gEditLines[i].text.replace(/[nw]/ig, ""); - } - } - } - // Remove any stray ASCII-1 characters that aren't part of a Synchronet attribute - // code, if there are any. - for (var i = 0; i < gEditLines.length; ++i) - { - gEditLines[i].text = removeStrayANSIOneChars(gEditLines[i].text); - if (crossPostEditLines.length > i) - crossPostEditLines[i].text = removeStrayANSIOneChars(crossPostEditLines[i].text); - } } // Clear the screen and display the end-of-program information (if the setting @@ -578,8 +464,8 @@ if ((exitCode == 0) && (gEditLines.length > 0)) console.clear("\1n"); if (gConfigSettings.displayEndInfoScreen) { - displayProgramExitInfo(false); - console.crlf(); + displayProgramExitInfo(false); + console.crlf(); } // If the user wrote & saved a message, then output the message @@ -589,23 +475,56 @@ if ((exitCode == 0) && (gEditLines.length > 0)) { // Store whether the user is still posting the message in the original sub-board // and whether that's the only sub-board they're posting in. - var postingInOriginalSubBoard = gCrossPostMsgSubs.subCodeExists(gMsgAreaNameInfo.subBoardCode); + var postingInOriginalSubBoard = gCrossPostMsgSubs.subCodeExists(gMsgAreaInfo.subBoardCode); var postingOnlyInOriginalSubBoard = (postingInOriginalSubBoard && (gCrossPostMsgSubs.numSubBoards() == 1)); - // If some message areas have been selected for cross-posting, do the - // cross-posting. + // If some message areas have been selected for cross-posting, then otuput + // which areas will be cross-posted into, and do the cross-posting. var crossPosted = false; if (gCrossPostMsgSubs.numMsgGrps() > 0) { - // Read the user's signature, in case they have one - var msgSigInfo = readUserSigFile(); - - // Create a single string containing the user's entire message. - var msgObj = { - msgContents: "" - }; + // If the will cross-post into other sub-boards, then create a string containing + // the user's entire message. + var msgContents = ""; if (!postingOnlyInOriginalSubBoard) - msgObj.msgContents = concatMsgEditLines(crossPostEditLines, msgSigInfo, false); + { + // Append each line to msgContents. Then, + // - If using Synchronet 3.15 or higher: + // Depending on whether the line has a hard newline + // or a soft newline, append a "\r\n" or a " \n", as + // per Synchronet's standard as of 3.15. + // - Otherwise (Synchronet 3.14 and below): + // Just append a "\r\n" to the line + if (system.version_num >= 31500) + { + var useHardNewline = false; + for (var i = 0; i < gEditLines.length; ++i) + { + // Use a hard newline if the current edit line has one or if this is + // the last line of the message. + useHardNewline = (gEditLines[i].hardNewlineEnd || (i == gEditLines.length-1)); + msgContents += gEditLines[i].text + (useHardNewline ? "\r\n" : " \n"); + } + } + else // Synchronet 3.14 and below + { + for (var i = 0; i < gEditLines.length; ++i) + msgContents += gEditLines[i].text + "\r\n"; + } + + // Read the user's signature, in case they have one + var msgSigInfo = readUserSigFile(); + // If the user has not chosen to auto-sign messages, then also append their + // signature to the message now. + if (!gUserSettings.autoSignMessages) + { + // Append a blank line to separate the message & signature. + // Note: msgContents already has a newline at the end, so we don't have + // to append one here; just append the signature. + if (msgSigInfo.sigContents.length > 0) + msgContents += msgSigInfo.sigContents + "\r\n"; + } + } console.print("\1n"); console.crlf(); @@ -616,10 +535,10 @@ if ((exitCode == 0) && (gEditLines.length > 0)) // cross-post logging). if (postingInOriginalSubBoard && !postingOnlyInOriginalSubBoard) { - log(LOG_INFO, EDITOR_PROGRAM_NAME + ": " + user.alias + " is posting a message in " + msg_area.sub[gMsgAreaNameInfo.subBoardCode].grp_name + - " " + msg_area.sub[gMsgAreaNameInfo.subBoardCode].description + " (" + gMsgSubj + ")"); - bbs.log_str(EDITOR_PROGRAM_NAME + ": " + user.alias + " is posting a message in " + msg_area.sub[gMsgAreaNameInfo.subBoardCode].grp_name + - " " + msg_area.sub[gMsgAreaNameInfo.subBoardCode].description + " (" + gMsgSubj + ")"); + log(LOG_INFO, "SlyEdit: " + user.alias + " is posting a message in " + msg_area.sub[gMsgAreaInfo.subBoardCode].grp_name + + " " + msg_area.sub[gMsgAreaInfo.subBoardCode].description + " (" + gMsgSubj + ")"); + bbs.log_str("SlyEdit: " + user.alias + " is posting a message in " + msg_area.sub[gMsgAreaInfo.subBoardCode].grp_name + + " " + msg_area.sub[gMsgAreaInfo.subBoardCode].description + " (" + gMsgSubj + ")"); } var postMsgErrStr = ""; // For storing errors related to saving the message for (var grpIndex in gCrossPostMsgSubs) @@ -628,12 +547,11 @@ if ((exitCode == 0) && (gEditLines.length > 0)) if (gCrossPostMsgSubs.propIsFuncName(grpIndex)) continue; - // Output the sub-board that will be posted to console.print("\1n" + gConfigSettings.genColors.msgPostedGrpHdr + msg_area.grp_list[grpIndex].description + ":"); console.crlf(); for (var subCode in gCrossPostMsgSubs[grpIndex]) { - if (subCode == gMsgAreaNameInfo.subBoardCode) + if (subCode == gMsgAreaInfo.subBoardCode) { printf("\1n " + gConfigSettings.genColors.msgPostedSubBoardName + "%-48s", msg_area.sub[subCode].description.substr(0, 48)); console.print("\1n " + gConfigSettings.genColors.msgPostedOriginalAreaText + "(original message area)"); @@ -642,56 +560,23 @@ if ((exitCode == 0) && (gEditLines.length > 0)) // to post in that sub, then post the message there. else { + // Write a log in the BBS log about which message area the user is + // cross-posting into. + log(LOG_INFO, "SlyEdit: " + user.alias + " is cross-posting a message in " + msg_area.sub[subCode].grp_name + + " " + msg_area.sub[subCode].description + " (" + gMsgSubj + ")"); + bbs.log_str("SlyEdit: " + user.alias + " is cross-posting a message in " + msg_area.sub[subCode].grp_name + + " " + msg_area.sub[subCode].description + " (" + gMsgSubj + ")"); + // Write the cross-posting message area on the user's screen. printf("\1n " + gConfigSettings.genColors.msgPostedSubBoardName + "%-73s", msg_area.sub[subCode].description.substr(0, 73)); if (user.compare_ars(msg_area.sub[subCode].post_ars)) { - // msgPostingObj will point to msgObj or a new one, depending on color settings - var msgPostingObj; - // If message text color is allowed & is allowed in this - // area, then check if ANSI conversion should be done. - if (gConfigSettings.allowColorSelection && colorSelectionAllowedInMsgArea(msg_area.sub[subCode].name, subCode)) - { - if (shouldConvertMsgColorsToANSIInMsgArea(msg_area.sub[subCode].name, subCode)) - { - msgPostingObj = { - msgContents: SyncAttrsToANSI(msgObj.msgContents) - }; - msgSigInfo.sigContents = SyncAttrsToANSI(msgSigInfo.sigContents); - } - else // Post the message as-is - msgPostingObj = msgObj; - } - else // Color is not allowed - Strip any Synchronet attribute codes from the message - { - msgPostingObj = { - msgContents: concatMsgEditLines(crossPostEditLines, msgSigInfo, true) - }; - // In case the user's signature has any return/newline - // characters in it, split it up and strip ctrl characters - // from each line, then put it back together. - var sigLines = msgSigInfo.sigContents.split("\r\n"); - if ((sigLines.length > 0) && (sigLines[sigLines.length-1].length == 0)) - sigLines.splice(-1, 1); - msgSigInfo.sigContents = ""; - for (var sigIdx = 0; sigIdx < sigLines.length; ++sigIdx) - msgSigInfo.sigContents += strip_ctrl(sigLines[sigIdx]) + "\r\n"; - } - - - // Write a log in the BBS log about which message area the user is - // cross-posting into. - log(LOG_INFO, EDITOR_PROGRAM_NAME + ": " + user.alias + " is cross-posting a message in " + msg_area.sub[subCode].grp_name + - " " + msg_area.sub[subCode].description + " (" + gMsgSubj + ")"); - bbs.log_str(EDITOR_PROGRAM_NAME + ": " + user.alias + " is cross-posting a message in " + msg_area.sub[subCode].grp_name + - " " + msg_area.sub[subCode].description + " (" + gMsgSubj + ")"); - // If the user's auto-sign setting is enabled, then auto-sign // the message and append their signature afterward. Otherwise, // don't auto-sign, and their signature has already been appended. if (gUserSettings.autoSignMessages) { - var msgContents2 = msgPostingObj.msgContents + "\r\n"; + var msgContents2 = msgContents + "\r\n"; msgContents2 += getSignName(subCode, gUserSettings.autoSignRealNameOnlyFirst, gUserSettings.autoSignEmailsRealName); msgContents2 += "\r\n\r\n"; if (msgSigInfo.sigContents.length > 0) @@ -699,7 +584,7 @@ if ((exitCode == 0) && (gEditLines.length > 0)) postMsgErrStr = postMsgToSubBoard(subCode, gToName, gMsgSubj, msgContents2, user.number); } else - postMsgErrStr = postMsgToSubBoard(subCode, gToName, gMsgSubj, msgPostingObj.msgContents, user.number); + postMsgErrStr = postMsgToSubBoard(subCode, gToName, gMsgSubj, msgContents, user.number); if (postMsgErrStr.length == 0) { savedTheMessage = true; @@ -736,9 +621,9 @@ if ((exitCode == 0) && (gEditLines.length > 0)) // want to save it will be determined by whether the user's current sub-board // code is in the list of cross-post areas. var saveMsgFile = true; - if (postingInMsgSubBoard(gMsgAreaName)) + if (postingInMsgSubBoard(gMsgArea)) { - if (!gCrossPostMsgSubs.subCodeExists(gMsgAreaNameInfo.subBoardCode)) + if (!gCrossPostMsgSubs.subCodeExists(gMsgAreaInfo.subBoardCode)) { saveMsgFile = false; // If the message was cross-posted to other message areas and not in the @@ -775,7 +660,7 @@ if ((exitCode == 0) && (gEditLines.length > 0)) if (gUserSettings.autoSignMessages) { msgFile.writeln(""); - var subCode = (postingInMsgSubBoard(gMsgAreaName) ? gMsgAreaNameInfo.subBoardCode : "mail"); + var subCode = (postingInMsgSubBoard(gMsgArea) ? gMsgAreaInfo.subBoardCode : "mail"); msgFile.writeln(getSignName(subCode, gUserSettings.autoSignRealNameOnlyFirst, gUserSettings.autoSignEmailsRealName)); } msgFile.close(); @@ -813,36 +698,36 @@ bbs.sys_status = gOldStatus; // Set the end-of-program status message. var endStatusMessage = ""; if (exitCode == 1) - endStatusMessage = gConfigSettings.genColors.msgAbortedText + "Message aborted."; + endStatusMessage = gConfigSettings.genColors.msgAbortedText + "Message aborted."; else if (exitCode == 0) { - if (gEditLines.length > 0) - { - if (savedTheMessage) - endStatusMessage = gConfigSettings.genColors.msgHasBeenSavedText + "The message has been saved."; - else - endStatusMessage = gConfigSettings.genColors.msgAbortedText + "Message aborted."; - } - else - endStatusMessage = gConfigSettings.genColors.emptyMsgNotSentText + "Empty message not sent."; + if (gEditLines.length > 0) + { + if (savedTheMessage) + endStatusMessage = gConfigSettings.genColors.msgHasBeenSavedText + "The message has been saved."; + else + endStatusMessage = gConfigSettings.genColors.msgAbortedText + "Message aborted."; + } + else + endStatusMessage = gConfigSettings.genColors.emptyMsgNotSentText + "Empty message not sent."; } // We shouldn't hit this else case, but it's here just to be safe. else - endStatusMessage = gConfigSettings.genColors.genMsgErrorText + "Possible message error."; + endStatusMessage = gConfigSettings.genColors.genMsgErrorText + "Possible message error."; console.print(endStatusMessage); console.crlf(); // If the user's setting to pause after every screenful is disabled, then // pause here so that they can see the exit information. if (user.settings & USER_PAUSE == 0) - mswait(1000); + mswait(1000); // Load any specified 3rd-party exit scripts and execute any provided exit // JavaScript commands. for (var i = 0; i < gConfigSettings.thirdPartyLoadOnExit.length; ++i) - load(gConfigSettings.thirdPartyLoadOnExit[i]); + load(gConfigSettings.thirdPartyLoadOnExit[i]); for (var i = 0; i < gConfigSettings.runJSOnExit.length; ++i) - eval(gConfigSettings.runJSOnExit[i]); + eval(gConfigSettings.runJSOnExit[i]); exit(exitCode); @@ -869,9 +754,7 @@ function readQuoteOrMessageFile() // Only use textLine if it's actually a string. if (typeof(textLine) == "string") { - // Remove any ANSI and/or Synchronet color codes from quote lines so - // the quote lines look better - textLine = strip_ctrl(cvtANSIToSyncAndRemoveUnwantedANSI(textLine)); + textLine = strip_ctrl(textLine); // If the line has only whitespace and/or > characters, // then make the line blank before putting it into // gQuoteLines. @@ -1006,8 +889,12 @@ function doEditLoop() returnCode = 1; // Aborted continueOn = false; } - else // Make sure the edit/quote color attribute is set + else + { + // Make sure the edit color attribute is set. + //console.print("\1n" + gTextAttrs); console.print(chooseEditColor()); + } break; case SAVE_KEY: returnCode = 0; // Save @@ -1015,7 +902,8 @@ function doEditLoop() break; case CMDLIST_HELP_KEY: case CMDLIST_HELP_KEY_2: - displayCommandList(true, true, true, gCanCrossPost, gConfigSettings); + displayCommandList(true, true, true, gCanCrossPost, gConfigSettings.userIsSysop, + gConfigSettings.enableTextReplacements, gConfigSettings.allowUserSettings); clearEditAreaBuffer(); fpRedrawScreen(gEditLeft, gEditRight, gEditTop, gEditBottom, gTextAttrs, gInsertMode, gUseQuotes, gEditLinesIndex-(curpos.y-gEditTop), @@ -1042,7 +930,6 @@ function doEditLoop() var retObject = doQuoteSelection(curpos, currentWordLength); curpos.x = retObject.x; curpos.y = retObject.y; - gTextLineIndex = gEditLines[gEditLinesIndex].displayIdxToActualIdx(curpos.x-gEditLeft); currentWordLength = retObject.currentWordLength; // If user input timed out, then abort. if (retObject.timedOut) @@ -1056,81 +943,19 @@ function doEditLoop() } break; case CHANGE_COLOR_KEY: - // If the text index is 0 and the current line contains only - // Synchronet attribute codes, then change the text index to - // the end of the text line - if ((gTextLineIndex == 0) && gOnlySyncAttrsInStrRegex.test(gEditLines[gEditLinesIndex].text)) - gTextLineIndex = gEditLines[gEditLinesIndex].text.length; - // Let the user change the text color if SlyEdit is configured - // to do so, color selection is allowed in the current message - // area, and the current line is not a quote line. Also, for - // now, only allow color selection if the text line index is - // at the end of the text line. - var colorsAllowedObj = colorSelectionAllowedInSettingsAndLine(gMsgAreaName, bbs.cursub_code); - if (colorsAllowedObj.colorsAllowed) + // Let the user change the text color. + /*if (gConfigSettings.allowColorSelection) { - var retObj = doColorSelection(curpos, currentWordLength); + var retObj = doColorSelection(gTextAttrs, curpos, currentWordLength); if (!retObj.timedOut) { - // Only do this if the user actually chose a text attribute and - // it's different from the current text attribute - if ((retObj.txtAttrs.length > 0) && (retObj.txtAttrs != gTextAttrs)) - { - var oldTextAttrs = gTextAttrs; - gTextAttrs = retObj.txtAttrs; - // If the text line currently contains just a normal or normal-white - // attribute code, then remove it before appending the new attribute code. - if ((gTextLineIndex == 0) && (gEditLines[gEditLinesIndex].displayLength() == 0)) - { - var txtLineLower = gEditLines[gEditLinesIndex].text.toLowerCase(); - if (txtLineLower == "\1n\1w") - gEditLines[gEditLinesIndex].text = gEditLines[gEditLinesIndex].text.substr(4); - else if (txtLineLower == "\1n") - gEditLines[gEditLinesIndex].text = gEditLines[gEditLinesIndex].text.substr(2); - // If the line starts with the old attribute, then remove it. - if (gEditLines[gEditLinesIndex].text.indexOf(oldTextAttrs) == 0) - gEditLines[gEditLinesIndex].text = gEditLines[gEditLinesIndex].text.substr(oldTextAttrs.length); - } - // Add the attribute code(s) to the text line - if (gTextLineIndex < gEditLines[gEditLinesIndex].text.length) - gEditLines[gEditLinesIndex].text = gEditLines[gEditLinesIndex].text.substr(0, gTextLineIndex) + gTextAttrs + gEditLines[gEditLinesIndex].text.substr(gTextLineIndex); - else - gEditLines[gEditLinesIndex].text += gTextAttrs; - gTextLineIndex += gTextAttrs.length; - curpos.x = retObj.x; - curpos.y = retObj.y; - // If the text line is now too long, fix off-by-one issue with - // gTextLineIndex for when the line is wrapped - if (gEditLines[gEditLinesIndex].text.length > gEditWidth-1) - ++gTextLineIndex; - currentWordLength = retObj.currentWordLength; - // Output the correct text color - if ((gTextAttrs != "\1N") && (gTextAttrs != "\1n")) - console.print("\1n" + oldTextAttrs + gTextAttrs); - else - console.print(gTextAttrs); - // Refresh the rest of the text on the screen so that the colors are correct - console.print(gEditLines[gEditLinesIndex].text.substr(gTextLineIndex)); - var screenY = curpos.y + 1; - for (var lineIdx = gEditLinesIndex+1; (lineIdx < gEditLines.length) && (screenY <= gEditBottom); ++lineIdx) - { - console.gotoxy(1, screenY++); - if (gEditLines[lineIdx].isQuoteLine) - console.print("\1n" + gQuoteLineColor + strip_ctrl(gEditLines[lineIdx].text)); - else - console.print(gEditLines[lineIdx].text); - } - - // Put the cursor back where it should be, and output - // the correct text color - console.gotoxy(curpos); - if ((gTextAttrs != "\1N") && (gTextAttrs != "\1n")) - console.print("\1n" + oldTextAttrs + gTextAttrs); - else - console.print(gTextAttrs); - } - else - console.print(gTextAttrs); + // Note: DoColorSelection() will prefix the color with the normal + // attribute. + gTextAttrs = retObj.txtAttrs; + console.print(gTextAttrs); + curpos.x = retObj.x; + curpos.y = retObj.y; + currentWordLength = retObj.currentWordLength; } else { @@ -1141,16 +966,7 @@ function doEditLoop() console.print("\1n\1h\1r" + EDITOR_PROGRAM_NAME + ": Input timeout reached."); continue; } - } - else - { - writeWithPause(1, console.screen_rows, "\1y\1h" + colorsAllowedObj.errorMsg + "\1n", ERRORMSG_PAUSE_MS); - // Refresh the help line on the bottom of the screen - fpDisplayBottomHelpLine(console.screen_rows, gUseQuotes); - // Make sure the edit color is correct, and put the cursor where it should be - console.print(chooseEditColor()); - console.gotoxy(curpos); - } + }*/ break; case KEY_UP: // Move the cursor up one line. @@ -1158,12 +974,15 @@ function doEditLoop() { --gEditLinesIndex; - // gTextLineIndex should contain the index in the text - // line where the cursor would add text. Figure it out - // based on the cursor's horizontal position. - var textLineDisplayableLen = gEditLines[gEditLinesIndex].displayLength(); - if (curpos.x > gEditLeft + textLineDisplayableLen) - curpos.x = gEditLeft + textLineDisplayableLen; + // gTextLineIndex should containg the index in the text + // line where the cursor would add text. If the previous + // line is shorter than the one we just left, then + // gTextLineIndex and curpos.x need to be adjusted. + if (gTextLineIndex > gEditLines[gEditLinesIndex].length()) + { + gTextLineIndex = gEditLines[gEditLinesIndex].length(); + curpos.x = gEditLeft + gEditLines[gEditLinesIndex].length(); + } // Figure out the vertical coordinate of where the // cursor should be. // If the cursor is at the top of the edit area, @@ -1174,7 +993,6 @@ function doEditLoop() --curpos.y; console.gotoxy(curpos); - gTextLineIndex = gEditLines[gEditLinesIndex].displayIdxToActualIdx(curpos.x-gEditLeft); currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); console.print(chooseEditColor()); // Make sure the edit color is correct } @@ -1184,24 +1002,28 @@ function doEditLoop() if (gEditLinesIndex < gEditLines.length-1) { ++gEditLinesIndex; - - // gTextLineIndex should contain the index in the text - // line where the cursor would add text. Figure it out - // based on the cursor's horizontal position. - var textLineDisplayableLen = gEditLines[gEditLinesIndex].displayLength(); - if (curpos.x > gEditLeft + textLineDisplayableLen) - curpos.x = gEditLeft + textLineDisplayableLen; + // gTextLineIndex should containg the index in the text + // line where the cursor would add text. If the next + // line is shorter than the one we just left, then + // gTextLineIndex and curpos.x need to be adjusted. + if (gTextLineIndex > gEditLines[gEditLinesIndex].length()) + { + gTextLineIndex = gEditLines[gEditLinesIndex].length(); + curpos.x = gEditLeft + gEditLines[gEditLinesIndex].length(); + } // Figure out the vertical coordinate of where the // cursor should be. // If the cursor is at the bottom of the edit area, // then scroll down through the message by 1 line. if (curpos.y == gEditBottom) - displayEditLines(gEditTop, gEditLinesIndex-(gEditBottom-gEditTop), gEditBottom, true, /*true*/false); + { + displayEditLines(gEditTop, gEditLinesIndex-(gEditBottom-gEditTop), + gEditBottom, true, /*true*/false); + } else ++curpos.y; console.gotoxy(curpos); - gTextLineIndex = gEditLines[gEditLinesIndex].displayIdxToActualIdx(curpos.x-gEditLeft); currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); console.print(chooseEditColor()); // Make sure the edit color is correct } @@ -1214,31 +1036,7 @@ function doEditLoop() --curpos.x; console.gotoxy(curpos); if (gTextLineIndex > 0) - { - // Account for Synchronet color/attribute codes that might - // be before the current index, if this isn't a quote line - if (!gEditLines[gEditLinesIndex].isQuoteLine) - { - var previousSyncColorCodeIdx = regexLastIndexOf(gEditLines[gEditLinesIndex].text, gSyncAttrRegex, 0, gTextLineIndex); - while (previousSyncColorCodeIdx == gTextLineIndex-2) - { - gTextLineIndex -= 2; - previousSyncColorCodeIdx = regexLastIndexOf(gEditLines[gEditLinesIndex].text, gSyncAttrRegex, 0, gTextLineIndex); - } - } - if (!gEditLines[gEditLinesIndex].isQuoteLine) - { - // See if there are any Synchronet color/attribute codes - // before the current character in the text line, and if - // so, set the text color appropriately (and if there are - // no colors, then set the color to normal). - var attrsStr = gEditLines[gEditLinesIndex].getLastAttrCodes(gTextLineIndex); - if (attrsStr.length == 0) - gTextAttrs = "\1n"; - else - gTextAttrs = attrsStr; - } - } + --gTextLineIndex; } else { @@ -1249,19 +1047,21 @@ function doEditLoop() if (gEditLinesIndex > 0) { --gEditLinesIndex; - curpos.x = gEditLeft + gEditLines[gEditLinesIndex].displayLength(); + curpos.x = gEditLeft + gEditLines[gEditLinesIndex].length(); // Move the cursor up or scroll up by one line if (curpos.y > 1) --curpos.y; else displayEditLines(gEditTop, gEditLinesIndex, gEditBottom, true, /*true*/false); + gTextLineIndex = gEditLines[gEditLinesIndex].length(); console.gotoxy(curpos); } } - gTextLineIndex = gEditLines[gEditLinesIndex].displayIdxToActualIdx(curpos.x-gEditLeft); + console.print(chooseEditColor()); + + // Update the current word length. currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); - // Output the text color, depending on if this line is a quote line or - // an edit line + // Make sure the edit color is correct console.print(chooseEditColor()); break; case KEY_RIGHT: @@ -1272,37 +1072,11 @@ function doEditLoop() { // The current line index must be within bounds // before we can move the cursor to the right. - if (gTextLineIndex < gEditLines[gEditLinesIndex].text.length) + if (gTextLineIndex < gEditLines[gEditLinesIndex].length()) { ++curpos.x; - // Account for Synchronet color codes to the right of gTextLineIndex, - // if this isn't a quote line - if (!gEditLines[gEditLinesIndex].isQuoteLine) - { - /* - var nextSyncColorCodeIdx = strSearchNext(gEditLines[gEditLinesIndex].text, gSyncAttrRegex, gTextLineIndex); - while (nextSyncColorCodeIdx == gTextLineIndex+1) - { - gTextLineIndex += 2; - nextSyncColorCodeIdx = strSearchNext(gEditLines[gEditLinesIndex].text, gSyncAttrRegex, gTextLineIndex); - } - */ - } - if (!gEditLines[gEditLinesIndex].isQuoteLine) - { - // See if there are any Synchronet color/attribute codes - // before the current character in the text line, and if - // so, set the text color appropriately (and if there are - // no colors, then set the color to normal). - var attrsStr = gEditLines[gEditLinesIndex].getLastAttrCodes(gTextLineIndex); - if (attrsStr.length == 0) - gTextAttrs = "\1n"; - else - gTextAttrs = attrsStr; - } - // Output the text color, depending on if this line is a quote line or - // an edit line - console.print(chooseEditColor()); + console.gotoxy(curpos); + ++gTextLineIndex; } else { @@ -1320,6 +1094,8 @@ function doEditLoop() else displayEditLines(gEditTop, gEditLinesIndex-(gEditBottom-gEditTop), gEditBottom, true, /*true*/false); + gTextLineIndex = 0; + console.gotoxy(curpos); } } } @@ -1338,34 +1114,31 @@ function doEditLoop() ++curpos.y; else displayEditLines(gEditTop, gEditLinesIndex-(gEditBottom-gEditTop), gEditBottom, true, false); + gTextLineIndex = 0; + console.gotoxy(curpos); } } - console.gotoxy(curpos); console.print(chooseEditColor()); - gTextLineIndex = gEditLines[gEditLinesIndex].displayIdxToActualIdx(curpos.x-gEditLeft); + + // Update the current word length. currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); // Make sure the edit color is correct console.print(chooseEditColor()); break; case KEY_HOME: // Go to the beginning of the line + gTextLineIndex = 0; curpos.x = gEditLeft; console.gotoxy(curpos); - gTextLineIndex = gEditLines[gEditLinesIndex].displayIdxToActualIdx(curpos.x-gEditLeft); + // Update the current word length. currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); - // Update the text color for the cursor on the screen - gTextAttrs = "\1n"; - console.print(chooseEditColor()); break; case KEY_END: // Go to the end of the line if (gEditLinesIndex < gEditLines.length) { - // Setting the text line index with the actual text string - // length and the cursor X position with the length() function - // because the string might have color/attribute codes, so the - // text string would be longer than it appears on the screen. - curpos.x = gEditLeft + gEditLines[gEditLinesIndex].displayLength(); + gTextLineIndex = gEditLines[gEditLinesIndex].length(); + curpos.x = gEditLeft + gTextLineIndex; // If the cursor position would be to the right of the edit // area, then place it at gEditRight. if (curpos.x > gEditRight) @@ -1377,24 +1150,8 @@ function doEditLoop() // Place the cursor where it should be. console.gotoxy(curpos); - gTextLineIndex = gEditLines[gEditLinesIndex].displayIdxToActualIdx(curpos.x-gEditLeft); + // Update the current word length. currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); - - if (!gEditLines[gEditLinesIndex].isQuoteLine) - { - // See if there are any Synchronet color/attribute codes - // before the current character in the text line, and if - // so, set the text color appropriately (and if there are - // no colors, then set the color to normal). - var attrsStr = gEditLines[gEditLinesIndex].getLastAttrCodes(gTextLineIndex); - if (attrsStr.length == 0) - gTextAttrs = "\1n"; - else - gTextAttrs = attrsStr; - } - // Output the text color, depending on if this line is a quote line or - // an edit line - console.print(chooseEditColor()); } break; case BACKSPACE: @@ -1404,7 +1161,6 @@ function doEditLoop() var retObject = doBackspace(curpos, currentWordLength); curpos.x = retObject.x; curpos.y = retObject.y; - //gTextLineIndex = gEditLines[gEditLinesIndex].displayIdxToActualIdx(curpos.x-gEditLeft); currentWordLength = retObject.currentWordLength; // Make sure the edit color is correct console.print(chooseEditColor()); @@ -1417,28 +1173,26 @@ function doEditLoop() var retObject = doDeleteKey(curpos, currentWordLength); curpos.x = retObject.x; curpos.y = retObject.y; - gTextLineIndex = gEditLines[gEditLinesIndex].displayIdxToActualIdx(curpos.x-gEditLeft); currentWordLength = retObject.currentWordLength; // Make sure the edit color is correct console.print(chooseEditColor()); } break; case KEY_ENTER: - var cursorAtBeginningOrEnd = ((curpos.x == 1) || (curpos.x >= gEditLines[gEditLinesIndex].displayLength())); + var cursorAtBeginningOrEnd = ((curpos.x == 1) || (curpos.x >= gEditLines[gEditLinesIndex].length())); var letUserEditLine = (cursorAtBeginningOrEnd ? true : textLineIsEditable(gEditLinesIndex)); if (letUserEditLine) { var retObject = doEnterKey(curpos, currentWordLength); + curpos.x = retObject.x; + curpos.y = retObject.y; + currentWordLength = retObject.currentWordLength; returnCode = retObject.returnCode; continueOn = retObject.continueOn; // Check for whether we should do quote selection or // show the help screen (if the user entered /Q or /?) if (continueOn) { - curpos.x = retObject.x; - curpos.y = retObject.y; - gTextLineIndex = gEditLines[gEditLinesIndex].displayIdxToActualIdx(curpos.x-gEditLeft); - currentWordLength = retObject.currentWordLength; if (retObject.doQuoteSelection) { if (gUseQuotes) @@ -1446,7 +1200,6 @@ function doEditLoop() retObject = doQuoteSelection(curpos, currentWordLength); curpos.x = retObject.x; curpos.y = retObject.y; - gTextLineIndex = gEditLines[gEditLinesIndex].displayIdxToActualIdx(curpos.x-gEditLeft); currentWordLength = retObject.currentWordLength; // If user input timed out, then abort. if (retObject.timedOut) @@ -1462,11 +1215,12 @@ function doEditLoop() else if (retObject.showHelp) { displayProgramInfo(true, false); - displayCommandList(false, false, true, gCanCrossPost, gConfigSettings); + displayCommandList(false, false, true, gCanCrossPost, gConfigSettings.userIsSysop, + gConfigSettings.enableTextReplacements, gConfigSettings.allowUserSettings); clearEditAreaBuffer(); fpRedrawScreen(gEditLeft, gEditRight, gEditTop, gEditBottom, gTextAttrs, gInsertMode, gUseQuotes, gEditLinesIndex-(curpos.y-gEditTop), - displayEditLines); + displayEditLines); console.gotoxy(curpos); } else if (retObject.doCrossPostSelection) @@ -1474,15 +1228,16 @@ function doEditLoop() if (gCanCrossPost) doCrossPosting(); } - // Make sure the edit color is correct - console.print(chooseEditColor()); } + // Make sure the edit color is correct + console.print(chooseEditColor()); } break; // Insert/overwrite mode toggle case KEY_INSERT: case TOGGLE_INSERT_KEY: toggleInsertMode(null); + //console.print("\1n" + gTextAttrs); console.print(chooseEditColor()); console.gotoxy(curpos); break; @@ -1493,12 +1248,12 @@ function doEditLoop() continueOn = retObj.continueOn; curpos.x = retObj.x; curpos.y = retObj.y; - gTextLineIndex = gEditLines[gEditLinesIndex].displayIdxToActualIdx(curpos.x-gEditLeft); currentWordLength = retObj.currentWordLength; // If we can continue on, put the cursor back // where it should be. if (continueOn) { + //console.print("\1n" + gTextAttrs); console.print(chooseEditColor()); console.gotoxy(curpos); } @@ -1507,7 +1262,6 @@ function doEditLoop() var retObj = findText(curpos); curpos.x = retObj.x; curpos.y = retObj.y; - gTextLineIndex = gEditLines[gEditLinesIndex].displayIdxToActualIdx(curpos.x-gEditLeft); console.print(chooseEditColor()); // Make sure the edit color is correct break; case IMPORT_FILE_KEY: @@ -1517,7 +1271,6 @@ function doEditLoop() var retObj = importFile(gConfigSettings.userIsSysop, curpos); curpos.x = retObj.x; curpos.y = retObj.y; - gTextLineIndex = gEditLines[gEditLinesIndex].displayIdxToActualIdx(curpos.x-gEditLeft); currentWordLength = retObj.currentWordLength; console.print(chooseEditColor()); // Make sure the edit color is correct } @@ -1534,7 +1287,6 @@ function doEditLoop() var retObj = doDeleteLine(curpos); curpos.x = retObj.x; curpos.y = retObj.y; - gTextLineIndex = gEditLines[gEditLinesIndex].displayIdxToActualIdx(curpos.x-gEditLeft); currentWordLength = retObj.currentWordLength; console.print(chooseEditColor()); // Make sure the edit color is correct break; @@ -1557,10 +1309,15 @@ function doEditLoop() displayEditLines(gEditTop, topEditIndex, gEditBottom, true, /*true*/false); // Set the cursor to the last place on the last line. gEditLinesIndex = topEditIndex + gEditHeight - 1; - var textLineDisplayableLen = gEditLines[gEditLinesIndex].displayLength(); - if (curpos.x > gEditLeft + textLineDisplayableLen) - curpos.x = gEditLeft + textLineDisplayableLen; + gTextLineIndex = gEditLines[gEditLinesIndex].length(); + if ((gTextLineIndex > 0) && (gEditLines[gEditLinesIndex].length == gEditWidth)) + --gTextLineIndex; + curpos.x = gEditLeft + gTextLineIndex; curpos.y = gEditBottom; + console.gotoxy(curpos); + + // Update the current word length. + currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); } else { @@ -1572,11 +1329,12 @@ function doEditLoop() gTextLineIndex = 0; curpos.x = gEditLeft; curpos.y = gEditTop; + console.gotoxy(curpos); + + // Update the current word length. + currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); } } - console.gotoxy(curpos); - currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); - gTextLineIndex = gEditLines[gEditLinesIndex].displayIdxToActualIdx(curpos.x-gEditLeft); console.print(chooseEditColor()); // Make sure the edit color is correct break; case KEY_PAGE_DOWN: // Move 1 page down in the message @@ -1603,8 +1361,13 @@ function doEditLoop() displayEditLines(gEditTop, topEditIndex, gEditBottom, true, /*true*/false); // Set the cursor to the first place on the first line. gEditLinesIndex = topEditIndex; + gTextLineIndex = 0; curpos.x = gEditLeft; curpos.y = gEditTop; + console.gotoxy(curpos); + + // Update the current word length. + currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); } else { @@ -1622,15 +1385,17 @@ function doEditLoop() gEditLinesIndex = bottomEditIndex; else gEditLinesIndex = lastEditLineIndex; - var textLineDisplayableLen = gEditLines[gEditLinesIndex].displayLength(); - if (curpos.x > gEditLeft + textLineDisplayableLen) - curpos.x = gEditLeft + textLineDisplayableLen; + gTextLineIndex = gEditLines[gEditLinesIndex].length(); + if ((gTextLineIndex > 0) && (gEditLines[gEditLinesIndex].length == gEditWidth)) + --gTextLineIndex; + curpos.x = gEditLeft + gTextLineIndex; curpos.y += (gEditLinesIndex-oldEditLinesIndex); + console.gotoxy(curpos); + + // Update the current word length. + currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); } } - console.gotoxy(curpos); - gTextLineIndex = gEditLines[gEditLinesIndex].displayIdxToActualIdx(curpos.x-gEditLeft); - currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); console.print(chooseEditColor()); // Make sure the edit color is correct break; case CROSSPOST_KEY: @@ -1645,15 +1410,10 @@ function doEditLoop() doUserSettings(curpos, true); break; default: - // If the text line is editable, let the typed character - // be added to the line + // For the tab character, insert 3 spaces. Otherwise, + // if it's a printable character, add the character. if (textLineIsEditable(gEditLinesIndex)) { - // For the tab character, insert 3 spaces. Otherwise, - // if it's a printable character, add the character. - // Note: doPrintableChar() updates gEditLinesIndex - // and gTextLineIndex. - // TODO: This isn't handling tab anymore if (/\t/.test(userInput)) { var retObject; @@ -1736,22 +1496,12 @@ function doEditLoop() } } - // If gEditLines has only 1 line in it and it's blank or only has Synchronet - // attribute codes, then remove it so that we can test to see if the message - // is empty. + // If gEditLines has only 1 line in it and it's blank, then + // remove it so that we can test to see if the message is empty. if (gEditLines.length == 1) { - if (gEditLines[0].displayLength() == 0) + if (gEditLines[0].length() == 0) gEditLines.splice(0, 1); - else - { - var syncAttrRegex = /\1[krgybmcw01234567hinpq,;\.dtl<>\[\]asz]$/i; - var allSyncAttrCodes = true; - for (var i = 0; (i < gEditLines[0].text.length) && allSyncAttrCodes; i += 2) - allSyncAttrCodes = syncAttrRegex.test(gEditLines[0].text.substr(i, 2)); - if (allSyncAttrCodes) - gEditLines.splice(0, 1); - } } return returnCode; @@ -1767,254 +1517,203 @@ function doEditLoop() // position and currentLength, the current word length. function doBackspace(pCurpos, pCurrentWordLength) { - // Create the return object. - var retObj = new Object(); - retObj.x = pCurpos.x; - retObj.y = pCurpos.y; - retObj.currentWordLength = pCurrentWordLength; + // Create the return object. + var retObj = new Object(); + retObj.x = pCurpos.x; + retObj.y = pCurpos.y; + retObj.currentWordLength = pCurrentWordLength; + + var didBackspace = false; + // For later, store a backup of the current edit line index and + // cursor position. + var originalCurrentLineIndex = gEditLinesIndex; + var originalX = pCurpos.x; + var originalY = pCurpos.y; + var originallyOnLastLine = (gEditLinesIndex == gEditLines.length-1); + + // If the cursor is beyond the leftmost position in + // the edit area, then we can simply remove the last + // character in the current line and move the cursor + // over to the left. + if (retObj.x > gEditLeft) + { + if (gTextLineIndex > 0) + { + console.print(BACKSPACE); + console.print(" "); + --retObj.x; + console.gotoxy(retObj.x, retObj.y); + + // Remove the previous character from the text line + var textLineLength = gEditLines[gEditLinesIndex].length(); + if (textLineLength > 0) + { + var textLine = gEditLines[gEditLinesIndex].text.substr(0, gTextLineIndex-1) + + gEditLines[gEditLinesIndex].text.substr(gTextLineIndex); + gEditLines[gEditLinesIndex].text = textLine; + didBackspace = true; + --gTextLineIndex; + } + } + } + else + { + // The cursor is at the leftmost position in the edit area. + // If we are beyond the first text line, then move as much of + // the current text line as possible up to the previous line, + // if there's room (if not, don't do anything). + if (gEditLinesIndex > 0) + { + var prevLineIndex = gEditLinesIndex - 1; + if (gEditLines[gEditLinesIndex].length() > 0) + { + // Store the previous line's original length + var originalPrevLineLen = gEditLines[prevLineIndex].length(); - var didBackspace = false; - // For later, store a backup of the current edit line index and - // cursor position. - var originalCurrentLineIndex = gEditLinesIndex; - var originalX = pCurpos.x; - var originalY = pCurpos.y; - var originallyOnLastLine = (gEditLinesIndex == gEditLines.length-1); - - // If the cursor is beyond the leftmost position in - // the edit area, then we can simply remove the last - // character in the current line and move the cursor - // over to the left. - if (retObj.x > gEditLeft) - { - //displayDebugText(1, 1, "Here 1!! \1;", console.getxy(), false, false, true); // Temporary - if (gTextLineIndex > 0) - { - //displayDebugText(1, 1, "Here 2!! \1;", console.getxy(), false, false, true); // Temporary - console.print(BACKSPACE); - console.print("\1n " + gTextAttrs); - --retObj.x; - console.gotoxy(retObj.x, retObj.y); + // See how much space is at the end of the previous line + var previousLineEndSpace = gEditWidth - gEditLines[prevLineIndex].length(); + if (previousLineEndSpace > 0) + { + var index = previousLineEndSpace - 1; + // If that index is valid for the current line, then find the first + // space in the current line so that the text would fit at the end + // of the previous line. Otherwise, set index to the length of the + // current line so that we'll move the whole current line up to the + // previous line. + if (index < gEditLines[gEditLinesIndex].length()) + { + for (; index >= 0; --index) + { + if (gEditLines[gEditLinesIndex].text.charAt(index) == " ") + break; + } + } + else + index = gEditLines[gEditLinesIndex].length(); + // If we found a space, then move the part of the current line before + // the space to the end of the previous line. + if (index > 0) + { + var linePart = gEditLines[gEditLinesIndex].text.substr(0, index); + gEditLines[gEditLinesIndex].text = gEditLines[gEditLinesIndex].text.substr(index); + gEditLines[prevLineIndex].text += linePart; + gEditLines[prevLineIndex].hardNewlineEnd = gEditLines[gEditLinesIndex].hardNewlineEnd; + + // If the current line is now blank, then remove it from gEditLines. + if (gEditLines[gEditLinesIndex].length() == 0) + gEditLines.splice(gEditLinesIndex, 1); + + // Update the global edit variables so that the cursor is placed + // on the previous line. + --gEditLinesIndex; + // Search for linePart in the line - If found, the cursor should + // be placed where it starts. If it' snot found, place the cursor + // at the end of the line. + var linePartIndex = gEditLines[gEditLinesIndex].text.indexOf(linePart); + if (linePartIndex > -1) + gTextLineIndex = linePartIndex; + else + gTextLineIndex = gEditLines[gEditLinesIndex].length(); - // Remove the previous character from the text line - var textLineVisibleLength = gEditLines[gEditLinesIndex].displayLength(); - if (textLineVisibleLength > 0) - { - // Account for any Synchronet color/attribute codes that might be in - // the text line immediately before the current index. If there are - // any, then remove those as well as the character before them. If - // there aren't any Synchronet attribute codes immediately before the - // current index, then just the previous character will be removed. - var attrInfo = gEditLines[gEditLinesIndex].getAttrsAndIndexesBeforeIdx(gTextLineIndex); - var substrLen = gTextLineIndex - 1; - var textLineIndexDecrementAmount = 1; - if (attrInfo.syncAttrEndIdx == gTextLineIndex-1) - { - substrLen = attrInfo.syncAttrStartIdx - 1; // We want to remove the attribute codes and the character before it - textLineIndexDecrementAmount = attrInfo.attrStr.length + 1; - if (substrLen < 0) // In case the attribute codes were at the beginning of the line - { - substrLen = 0; - --textLineIndexDecrementAmount; - } - } - // Now actually get the substrings to remove the character(s) - var substr1 = gEditLines[gEditLinesIndex].text.substr(0, substrLen); - //var substrObj2 = gEditLines[gEditLinesIndex].substrWithSyncColorCodes(substrObj1.endIdx+2); // TODO: Regular substring? - var substr2 = gEditLines[gEditLinesIndex].text.substr(gTextLineIndex); - // If the 'after' part of the string is just the attributes - if (gOnlySyncAttrsInStrRegex.test(substr2)) - substr2 = ""; - //if (substrObj2.strSub == attrInfo.attrStr) - // substrObj2.clear(); - gEditLines[gEditLinesIndex].text = substr1 + substr2; - gTextLineIndex -= textLineIndexDecrementAmount; - // Set the 'after' part to a blank string, and set the text attribute - var newTextAttrs = gEditLines[gEditLinesIndex].getLastAttrCodes(gTextLineIndex); - if (newTextAttrs.length > 0) - gTextAttrs = newTextAttrs; - else - gTextAttrs = "\1n"; - console.print(chooseEditColor()); // Set the cursor color to edit line or quote line color - didBackspace = true; - } - } - } - else - { - // The cursor is at the leftmost position in the edit area. - // If we are beyond the first text line, then move as much of - // the current text line as possible up to the previous line, - // if there's room (if not, don't do anything). - if (gEditLinesIndex > 0) - { - //displayDebugText(1, 1, "Here 3!! \1;", console.getxy(), false, false, true); // Temporary - var prevLineIndex = gEditLinesIndex - 1; - if (gEditLines[gEditLinesIndex].displayLength() > 0) - { - //displayDebugText(1, 1, "Here 4!! \1;", console.getxy(), false, false, true); // Temporary - // Store the previous line's original visible length - var originalPrevLineLen = gEditLines[prevLineIndex].displayLength(); + retObj.x = gEditLeft + gTextLineIndex; + if (retObj.y > gEditTop) + --retObj.y; - // See how much space is at the end of the previous line - var prevLineNumCharsAvailable = gEditWidth - gEditLines[prevLineIndex].displayLength(); - if (prevLineNumCharsAvailable > 0) - { - //displayDebugText(1, 1, "Here 5!! \1;", console.getxy(), false, false, true); // Temporary - var index = prevLineNumCharsAvailable - 1; - // If that index is valid for the current line, then find the first - // space in the current line so that the text would fit at the end - // of the previous line. Otherwise, set index to the length of the - // current line so that we'll move the whole current line up to the - // previous line. - if (index < gEditLines[gEditLinesIndex].text.length) - { - for (; index >= 0; --index) - { - if (gEditLines[gEditLinesIndex].text.charAt(index) == " ") - break; - } - } - else - index = gEditLines[gEditLinesIndex].text.length; - // If we found a space, then move the part of the current line before - // the space to the end of the previous line. - if (index > 0) - { - //displayDebugText(1, 1, "Here 6!! \1;", console.getxy(), false, false, true); // Temporary - var linePart = gEditLines[gEditLinesIndex].text.substr(0, index); - gEditLines[gEditLinesIndex].text = gEditLines[gEditLinesIndex].text.substr(index+1); - // Save the text line index for the previous line where - // the new part will start - We'll set gTextLineIndex to - // this later. - var newTextLineIndex = gEditLines[prevLineIndex].text.length; - // Append the part of the current line to the previous line - gEditLines[prevLineIndex].text += linePart; - gEditLines[prevLineIndex].hardNewlineEnd = gEditLines[gEditLinesIndex].hardNewlineEnd; - - // If the current line is now blank, then remove it from gEditLines. - if (gEditLines[gEditLinesIndex].displayLength() == 0) - gEditLines.splice(gEditLinesIndex, 1); - - // Update the global edit variables so that the cursor is placed - // on the previous line. - --gEditLinesIndex; - // Update the text line index to the correct position in the text line - gTextLineIndex = newTextLineIndex; + didBackspace = true; + } + } + } + else + { + // The current line's length is 0. + // If there's enough room on the previous line, remove the + // current line and place the cursor at the end of the + // previous line. + if (gEditLines[prevLineIndex].length() <= gEditWidth-1) + { + // Copy the current line's "hard newline end" setting to the + // previous line (so that if there's a blank line below the + // current line, the blank line will be preserved), then remove + // the current edit line. + gEditLines[gEditLinesIndex-1].hardNewlineEnd = gEditLines[gEditLinesIndex].hardNewlineEnd; + gEditLines.splice(gEditLinesIndex, 1); + + --gEditLinesIndex; + gTextLineIndex = gEditLines[prevLineIndex].length(); + retObj.x = gEditLeft + gEditLines[prevLineIndex].length(); + if (retObj.y > gEditTop) + --retObj.y; + + didBackspace = true; + } + } + } + } - // The horizontal cursor position should be placed right - // after the original first line's text, where the 2nd line's - // text starts. - retObj.x = gEditLeft + strip_ctrl(gEditLines[gEditLinesIndex].text.substr(0, newTextLineIndex)).length; - if (retObj.y > gEditTop) - --retObj.y; + // If the backspace was performed, then re-adjust the text lines + // and refresh the screen. + if (didBackspace) + { + // Store the previous line of text now so we can compare it later + var prevTextline = ""; + if (gEditLinesIndex > 0) + prevTextline = gEditLines[gEditLinesIndex-1].text; + + // Re-adjust the text lines + reAdjustTextLines(gEditLines, gEditLinesIndex, gEditLines.length, gEditWidth); + + // If the previous line's length increased, that probably means that the + // user backspaced to the beginning of the current line and the word was + // moved to the end of the previous line. If so, then move the cursor to + // the end of the previous line. + //var scrolled = false; + if ((gEditLinesIndex > 0) && + (gEditLines[gEditLinesIndex-1].length() > prevTextline.length)) + { + // Update the text index variables and cusor position variables. + --gEditLinesIndex; + gTextLineIndex = gEditLines[gEditLinesIndex].length(); + retObj.x = gEditLeft + gTextLineIndex; + if (retObj.y > gEditTop) + --retObj.y; + } - didBackspace = true; - } - } - } - else - { - //displayDebugText(1, 1, "Here 7!! \1;", console.getxy(), false, false, true); // Temporary - // The current line's displayable length is 0. - // Save the current line's text, to preserve color/attribute - // codes that might be there - var currentLineAttrCodes = gEditLines[gEditLinesIndex].text; - // If there's enough room on the previous line, remove the - // current line and place the cursor at the end of the - // previous line. - if (gEditLines[prevLineIndex].displayLength() <= gEditWidth-1) - { - //displayDebugText(1, 1, "Here 8!! \1;", console.getxy(), false, false, true); // Temporary - // Copy the current line's "hard newline end" setting to the - // previous line (so that if there's a blank line below the - // current line, the blank line will be preserved), then remove - // the current edit line. - gEditLines[gEditLinesIndex-1].hardNewlineEnd = gEditLines[gEditLinesIndex].hardNewlineEnd; - gEditLines.splice(gEditLinesIndex, 1); + // If the cursor was at the leftmost position in the edit area, + // update the edit lines from the currently-set screen line #. + if (originalX == gEditLeft) + { + // Since the original X position was at the left edge of the edit area, + // display the edit lines starting with the previous line if possible. + if ((gEditLinesIndex > 0) && (retObj.y > gEditTop)) + displayEditLines(retObj.y-1, gEditLinesIndex-1, gEditBottom, true, true); + else + displayEditLines(retObj.y, gEditLinesIndex, gEditBottom, true, true); + } + // If the original horizontal cursor position was in the middle of + // the line, and the line is the last line on the screen, then + // only refresh that one line on the screen. + else if ((originalX > gEditLeft) && (originalX < gEditLeft + gEditWidth - 1) && originallyOnLastLine) + displayEditLines(originalY, originalCurrentLineIndex, originalY, false); + // If scrolling was to be done, then refresh the entire + // current message text on the screen from the top of the + // edit area. Otherwise, only refresh starting from the + // original horizontal position and message line. + else + { + // Display the edit lines starting with the previous line if possible. + if ((gEditLinesIndex > 0) && (retObj.y > gEditTop)) + displayEditLines(retObj.y-1, gEditLinesIndex-1, gEditBottom, true, true); + else + displayEditLines(retObj.y, gEditLinesIndex, gEditBottom, true, true); + } - --gEditLinesIndex; - // Append the former previous line's attribute codes to the - // end of the current line - gEditLines[prevLineIndex].text += currentLineAttrCodes; - gTextLineIndex = gEditLines[prevLineIndex].text.length; - retObj.x = gEditLeft + gEditLines[prevLineIndex].displayLength(); - if (retObj.y > gEditTop) - --retObj.y; - // Set & output the attribute codes - gTextAttrs = currentLineAttrCodes; - console.print(chooseEditColor()); + // Make sure the current word length is correct. + retObj.currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); + } - didBackspace = true; - } - } - } - } - - // If the backspace was performed, then re-adjust the text lines - // and refresh the screen. - if (didBackspace) - { - //displayDebugText(1, 1, "Here 9!! \1;", console.getxy(), false, false, true); // Temporary - // Store the previous line of text now so we can compare it later - var prevTextline = ""; - if (gEditLinesIndex > 0) - prevTextline = gEditLines[gEditLinesIndex-1].text; - - // Re-adjust the text lines - reAdjustTextLines(gEditLines, gEditLinesIndex, gEditLines.length, gEditWidth); - - // If the previous line's length increased, that probably means that the - // user backspaced to the beginning of the current line and the word was - // moved to the end of the previous line. If so, then move the cursor to - // the end of the previous line. - //var scrolled = false; - if ((gEditLinesIndex > 0) && (gEditLines[gEditLinesIndex-1].displayLength() > prevTextline.length)) - { - // Update the text index variables and cusor position variables. - --gEditLinesIndex; - gTextLineIndex = gEditLines[gEditLinesIndex].text.length; - retObj.x = gEditLeft + gTextLineIndex; - if (retObj.y > gEditTop) - --retObj.y; - } - - // If the cursor was at the leftmost position in the edit area, - // update the edit lines from the currently-set screen line #. - if (originalX == gEditLeft) - { - // Since the original X position was at the left edge of the edit area, - // display the edit lines starting with the previous line if possible. - if ((gEditLinesIndex > 0) && (retObj.y > gEditTop)) - displayEditLines(retObj.y-1, gEditLinesIndex-1, gEditBottom, true, true); - else - displayEditLines(retObj.y, gEditLinesIndex, gEditBottom, true, true); - } - // If the original horizontal cursor position was in the middle of - // the line, and the line is the last line on the screen, then - // only refresh that one line on the screen. - else if ((originalX > gEditLeft) && (originalX < gEditLeft + gEditWidth - 1) && originallyOnLastLine) - displayEditLines(originalY, originalCurrentLineIndex, originalY, false); - // If scrolling was to be done, then refresh the entire - // current message text on the screen from the top of the - // edit area. Otherwise, only refresh starting from the - // original horizontal position and message line. - else - { - // Display the edit lines starting with the previous line if possible. - if ((gEditLinesIndex > 0) && (retObj.y > gEditTop)) - displayEditLines(retObj.y-1, gEditLinesIndex-1, gEditBottom, true, true); - else - displayEditLines(retObj.y, gEditLinesIndex, gEditBottom, true, true); - } - - // Make sure the current word length is correct. - retObj.currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); - } - - // Make sure the cursor is placed where it should be. - console.gotoxy(retObj.x, retObj.y); - return retObj; + // Make sure the cursor is placed where it should be. + console.gotoxy(retObj.x, retObj.y); + return retObj; } // Helper function for doEditLoop(): Handles the delete key behavior. @@ -2028,11 +1727,11 @@ function doBackspace(pCurpos, pCurrentWordLength) // position and currentLength, the current word length. function doDeleteKey(pCurpos, pCurrentWordLength) { - var returnObject = { - x: pCurpos.x, - y: pCurpos.y, - currentWordLength: pCurrentWordLength - }; + // Create the return object + var returnObject = new Object(); + returnObject.x = pCurpos.x; + returnObject.y = pCurpos.y; + returnObject.currentWordLength = pCurrentWordLength; // If gEditLinesIndex is invalid, then return without doing anything. if ((gEditLinesIndex < 0) || (gEditLinesIndex >= gEditLines.length)) @@ -2043,21 +1742,14 @@ function doDeleteKey(pCurpos, pCurrentWordLength) // If the text line index is within bounds, then we can // delete the next character and refresh the screen. - //displayDebugText(1, 1, "Txt idx: " + gTextLineIndex + ", len: " + gEditLines[gEditLinesIndex].text.length + " ", pCurpos, false, false, false); // Temporary - if (gTextLineIndex < gEditLines[gEditLinesIndex].text.length) + if (gTextLineIndex < gEditLines[gEditLinesIndex].length()) { - var substrObj1 = gEditLines[gEditLinesIndex].substrWithSyncColorCodes(0, pCurpos.x-1); - // For the rest-of-line substring, account for Synchronet attribute codes - // at/ahead of the start index. - var substr2StartIdx = substrObj1.endIdx + 1; - while (gSyncAttrRegex.test(gEditLines[gEditLinesIndex].text.substr(substr2StartIdx, 2))) - substr2StartIdx += 2; - ++substr2StartIdx; - var substr2 = gEditLines[gEditLinesIndex].text.substr(substr2StartIdx); - gEditLines[gEditLinesIndex].text = substrObj1.strSub + substr2; + var lineText = gEditLines[gEditLinesIndex].text.substr(0, gTextLineIndex) + + gEditLines[gEditLinesIndex].text.substr(gTextLineIndex+1); + gEditLines[gEditLinesIndex].text = lineText; // If the current character is a space, then reset the current word length. // to 0. Otherwise, set it to the current word length. - if (gTextLineIndex < gEditLines[gEditLinesIndex].text.length) + if (gTextLineIndex < gEditLines[gEditLinesIndex].length()) { if (gEditLines[gEditLinesIndex].text.charAt(gTextLineIndex) == " ") returnObject.currentWordLength = 0; @@ -2098,7 +1790,7 @@ function doDeleteKey(pCurpos, pCurrentWordLength) gEditLines[gEditLinesIndex].hardNewlineEnd = false; // If the current line is blank and is not the last line, then remove it. - if (gEditLines[gEditLinesIndex].displayLength() == 0) + if (gEditLines[gEditLinesIndex].length() == 0) { if (gEditLinesIndex < gEditLines.length-1) { @@ -2112,7 +1804,7 @@ function doDeleteKey(pCurpos, pCurrentWordLength) else if (gEditLinesIndex < gEditLines.length-1) { var nextLineIndex = gEditLinesIndex + 1; - if (gEditLines[nextLineIndex].displayLength() == 0) + if (gEditLines[nextLineIndex].length() == 0) gEditLines[nextLineIndex].hardNewlineEnd = false; } @@ -2158,218 +1850,168 @@ function doDeleteKey(pCurpos, pCurrentWordLength) // currentLength: The length of the current word function doPrintableChar(pUserInput, pCurpos, pCurrentWordLength) { - var retObj = { - x: pCurpos.x, - y: pCurpos.y, - currentWordLength: pCurrentWordLength - }; + // Create the return object. + var retObj = new Object(); + retObj.x = pCurpos.x; + retObj.y = pCurpos.y; + retObj.currentWordLength = pCurrentWordLength; - var lineIdxWasAtBeginningOrMiddle = false; + // Note: gTextLineIndex is where the new character will appear in the line. + // If gTextLineIndex is somehow past the end of the current line, then + // fill it with spaces up to gTextLineIndex. + if (gTextLineIndex > gEditLines[gEditLinesIndex].length()) + { + var numSpaces = gTextLineIndex - gEditLines[gEditLinesIndex].length(); + if (numSpaces > 0) + gEditLines[gEditLinesIndex].text += format("%" + numSpaces + "s", ""); + gEditLines[gEditLinesIndex].text += pUserInput; + } + // If gTextLineIndex is at the end of the line, then just append the char. + else if (gTextLineIndex == gEditLines[gEditLinesIndex].length()) + gEditLines[gEditLinesIndex].text += pUserInput; + else + { + // gTextLineIndex is at the beginning or in the middle of the line. + if (inInsertMode()) + { + gEditLines[gEditLinesIndex].text = spliceIntoStr(gEditLines[gEditLinesIndex].text, + gTextLineIndex, pUserInput); + } + else + { + gEditLines[gEditLinesIndex].text = gEditLines[gEditLinesIndex].text.substr(0, gTextLineIndex) + + pUserInput + gEditLines[gEditLinesIndex].text.substr(gTextLineIndex+1); + } + } - // Note: gTextLineIndex is where the new character will appear in the line. - // If gTextLineIndex is somehow past the end of the current line, then - // fill it with spaces up to gTextLineIndex. - if (gTextLineIndex > gEditLines[gEditLinesIndex].text.length) - { - var numSpaces = gTextLineIndex - gEditLines[gEditLinesIndex].text.length; - if (numSpaces > 0) - gEditLines[gEditLinesIndex].text += format("%" + numSpaces + "s", ""); - gEditLines[gEditLinesIndex].text += pUserInput; - } - // If gTextLineIndex is at the end of the line, then just append the char. - else if (gTextLineIndex == gEditLines[gEditLinesIndex].text.length) - gEditLines[gEditLinesIndex].text += pUserInput; - else - { - // gTextLineIndex is at the beginning or in the middle of the line. - lineIdxWasAtBeginningOrMiddle = true; - if (inInsertMode()) - gEditLines[gEditLinesIndex].text = spliceIntoStr(gEditLines[gEditLinesIndex].text, gTextLineIndex, pUserInput); - else - { - // If there are Synchronet attribute codes at the current index, replace each 2 chars & - // next char; otherwise, replace 1 char. - var nextCharDiff = 1; - var tmpIdx = gTextLineIndex - while (tmpIdx < gEditLines[gEditLinesIndex].text.length) - { - if (gSyncAttrRegex.test(gEditLines[gEditLinesIndex].text.substr(tmpIdx, 2))) - { - nextCharDiff += 2; - tmpIdx += 2; - } - else - break; - } - gEditLines[gEditLinesIndex].text = gEditLines[gEditLinesIndex].text.substr(0, gTextLineIndex) + pUserInput + gEditLines[gEditLinesIndex].text.substr(gTextLineIndex+nextCharDiff); - } - } + // Handle text replacement (AKA macros). Added 2013-08-31. + var madeTxtReplacement = false; // For screen refresh purposes + if (gConfigSettings.enableTextReplacements && (pUserInput == " ")) + { + var txtReplaceObj = gEditLines[gEditLinesIndex].doMacroTxtReplacement(gTxtReplacements, gTextLineIndex, + gConfigSettings.textReplacementsUseRegex); + madeTxtReplacement = txtReplaceObj.madeTxtReplacement; + if (madeTxtReplacement) + { + retObj.x += txtReplaceObj.wordLenDiff; + gTextLineIndex += txtReplaceObj.wordLenDiff; + } + } - // Handle text replacement (AKA macros). Added 2013-08-31. - var madeTxtReplacement = false; // For screen refresh purposes - if (gConfigSettings.enableTextReplacements && (pUserInput == " ")) - { - var colorsAllowedObj = colorSelectionAllowedInSettingsAndLine(gMsgAreaName, bbs.cursub_code); - var txtReplaceObj = gEditLines[gEditLinesIndex].doMacroTxtReplacement(gTxtReplacements, gTextLineIndex, - gConfigSettings.textReplacementsUseRegex, - colorsAllowedObj.colorsAllowed, gTextAttrs); - madeTxtReplacement = txtReplaceObj.madeTxtReplacement; - if (madeTxtReplacement) - { - retObj.x += txtReplaceObj.displayableWordLenDiff; - gTextLineIndex += txtReplaceObj.wordLenDiff; - } - } + // Store a copy of the current line so that we can compare it later to see + // if it was modified by reAdjustTextLines(). + var originalAfterCharApplied = gEditLines[gEditLinesIndex].text; - // Store a copy of the current line so that we can compare it later to see - // if it was modified by reAdjustTextLines(). - var originalAfterCharApplied = gEditLines[gEditLinesIndex].text; - var originalTextLineLength = gEditLines[gEditLinesIndex].text.length; - var originalTextLineDisplayLength = gEditLines[gEditLinesIndex].displayLength(); - var originalTextLineScreenLength = gEditLines[gEditLinesIndex].displayLength(); - - // If the line is now too long to fit in the edit area, then we will have - // to re-adjust the text lines. - var reAdjusted = false; - if (gEditLines[gEditLinesIndex].displayLength() >= gEditWidth-1) - reAdjusted = reAdjustTextLines(gEditLines, gEditLinesIndex, gEditLines.length, gEditWidth); - var wasOnLastLine = (gEditLinesIndex == gEditLines.length-1); // For possible adjustments later - - // placeCursorAtEnd specifies whether or not to place the cursor at its - // spot using console.gotoxy() at the end. This is an optimization. - var placeCursorAtEnd = true; - - // If the current text line is now different (modified by reAdjustTextLines()) - // or text replacements were made, then we'll need to refresh multiple lines - // on the screen. - if ((reAdjusted && (gEditLines[gEditLinesIndex].text != originalAfterCharApplied)) || madeTxtReplacement) - { - // If gTextLineIndex is >= gEditLines[gEditLinesIndex].text.length, then - // we know the current word was wrapped to the next line. Figure out what - // retObj.x, retObj.currentWordLength, gEditLinesIndex, and gTextLineIndex - // should be, and increment retObj.y. Also figure out what lines on the - // screen to update, and deal with scrolling if necessary. - if (gTextLineIndex >= gEditLines[gEditLinesIndex].text.length) - { - var numChars = 0; - // Special case: If the current line's length is exactly the longest - // edit with, then the # of chars should be 0 or 1, depending on whether the - // entered character was a space or not. Otherwise, calculate numChars - // normally. - if (gEditLines[gEditLinesIndex].displayLength() == gEditWidth-1) - numChars = (pUserInput == " " ? 0 : 1); - else - { - numChars = originalTextLineScreenLength - gEditLines[gEditLinesIndex].displayLength(); - if (gEditLinesIndex < gEditLines.length-1) - numChars = gEditLines[gEditLinesIndex+1].displayLength(); - } - retObj.x = gEditLeft + numChars; - var originalEditLinesIndex = gEditLinesIndex++; - gTextLineIndex = numChars; - // Set gTextLineIndex to the proper value - // If The current text line has only Synchronet attribute codes, - // then set the text line index after the attribute codes. - if (gOnlySyncAttrsInStrRegex.test(gEditLines[gEditLinesIndex].text)) - gTextLineIndex = gEditLines[gEditLinesIndex].text.length; - - // Figure out which lines we need to update on the screen and whether - // to do scrolling and what retObj.y should be. - if (retObj.y < gEditBottom) - { - // We're above the last line on the screen, so we can go one - // line down. - var originalY = retObj.y++; - // Update the lines on the screen. - var bottommostRow = calcBottomUpdateRow(originalY, originalEditLinesIndex); - displayEditLines(originalY, originalEditLinesIndex, bottommostRow, true, true); - } - else - { - // We're on the last line in the edit area, so we need to scroll - // the text lines up on the screen. - var editLinesTopIndex = gEditLinesIndex - (pCurpos.y - gEditTop); - displayEditLines(gEditTop, editLinesTopIndex, gEditBottom, true, true); - } - } - else - { - // gTextLineIndex is < the line's length. Update the lines on the - // screen from the current line down. Increment retObj.x, - // retObj.currentWordLength, and gTextLineIndex. - var bottommostRow = calcBottomUpdateRow(retObj.y, gEditLinesIndex); - displayEditLines(retObj.y, gEditLinesIndex, bottommostRow, true, true); - if (pUserInput == " ") - retObj.currentWordLength = 0; - else - ++retObj.currentWordLength; - ++retObj.x; - ++gTextLineIndex; - } - } - else - { - // The text line wasn't changed by reAdjustTextLines. + // If the line is now too long to fit in the edit area, then we will have + // to re-adjust the text lines. + var reAdjusted = false; + if (gEditLines[gEditLinesIndex].length() >= gEditWidth) + reAdjusted = reAdjustTextLines(gEditLines, gEditLinesIndex, gEditLines.length, gEditWidth); - // If gTextLineIndex is not the last index of the line, then refresh the - // entire line on the screen. Otherwise, just output the character that - // the user typed. - if (gTextLineIndex < gEditLines[gEditLinesIndex].text.length-1) - displayEditLines(retObj.y, gEditLinesIndex, retObj.y, false, true); - else - { - console.print(pUserInput); - placeCursorAtEnd = false; // Since we just output the character - } + // placeCursorAtEnd specifies whether or not to place the cursor at its + // spot using console.gotoxy() at the end. This is an optimization. + var placeCursorAtEnd = true; - // Keep housekeeping variables up to date. - ++retObj.x; - ++gTextLineIndex; - /* retObj.currentWordLength is now calculated at the end, but we could do this: - if (pUserInput == " ") - retObj.currentWordLength = 0; - else - ++retObj.currentWordLength; - */ - } + // If the current text line is now different (modified by reAdjustTextLines()) + // or text replacements were made, then we'll need to refresh multiple lines + // on the screen. + if ((reAdjusted && (gEditLines[gEditLinesIndex].text != originalAfterCharApplied)) || madeTxtReplacement) + { + // If gTextLineIndex is >= gEditLines[gEditLinesIndex].length(), then + // we know the current word was wrapped to the next line. Figure out what + // retObj.x, retObj.currentWordLength, gEditLinesIndex, and gTextLineIndex + // should be, and increment retObj.y. Also figure out what lines on the + // screen to update, and deal with scrolling if necessary. + if (gTextLineIndex >= gEditLines[gEditLinesIndex].length()) + { + // I changed this on 2010-02-14 to (hopefully) place the cursor where + // it should be + // Old line (prior to 2010-02-14): + //var numChars = gTextLineIndex - gEditLines[gEditLinesIndex].length(); + // New (2010-02-14): + var numChars = 0; + // Special case: If the current line's length is exactly the longest + // edit with, then the # of chars should be 0 or 1, depending on whether the + // entered character was a space or not. Otherwise, calculate numChars + // normally. + if (gEditLines[gEditLinesIndex].length() == gEditWidth-1) + numChars = ((pUserInput == " ") ? 0 : 1); + else + numChars = gTextLineIndex - gEditLines[gEditLinesIndex].length(); + retObj.x = gEditLeft + numChars; + var originalEditLinesIndex = gEditLinesIndex++; + gTextLineIndex = numChars; + // The following line is now done at the end: + //retObj.currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); + + // Figure out which lines we need to update on the screen and whether + // to do scrolling and what retObj.y should be. + if (retObj.y < gEditBottom) + { + // We're above the last line on the screen, so we can go one + // line down. + var originalY = retObj.y++; + // Update the lines on the screen. + var bottommostRow = calcBottomUpdateRow(originalY, originalEditLinesIndex); + displayEditLines(originalY, originalEditLinesIndex, bottommostRow, true, true); + } + else + { + // We're on the last line in the edit area, so we need to scroll + // the text lines up on the screen. + var editLinesTopIndex = gEditLinesIndex - (pCurpos.y - gEditTop); + displayEditLines(gEditTop, editLinesTopIndex, gEditBottom, true, true); + } + } + else + { + // gTextLineIndex is < the line's length. Update the lines on the + // screen from the current line down. Increment retObj.x, + // retObj.currentWordLength, and gTextLineIndex. + var bottommostRow = calcBottomUpdateRow(retObj.y, gEditLinesIndex); + displayEditLines(retObj.y, gEditLinesIndex, bottommostRow, true, true); + if (pUserInput == " ") + retObj.currentWordLength = 0; + else + ++retObj.currentWordLength; + ++retObj.x; + ++gTextLineIndex; + } + } + else + { + // The text line wasn't changed by reAdjustTextLines. + + // If gTextLineIndex is not the last index of the line, then refresh the + // entire line on the screen. Otherwise, just output the character that + // the user typed. + if (gTextLineIndex < gEditLines[gEditLinesIndex].length()-1) + displayEditLines(retObj.y, gEditLinesIndex, retObj.y, false, true); + else + { + console.print(pUserInput); + placeCursorAtEnd = false; // Since we just output the character + } - // Make sure the current word length is correct. - retObj.currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); + // Keep housekeeping variables up to date. + ++retObj.x; + ++gTextLineIndex; + /* retObj.currentWordLength is now calculated at the end, but we could do this: + if (pUserInput == " ") + retObj.currentWordLength = 0; + else + ++retObj.currentWordLength; + */ + } - // If the cursor's horizontal position has gone beyond the edit width, then - // update the x & y position of the cursor, as well as the edit lines - // indexes. - if (retObj.x - gEditLeft + 1 > gEditWidth) - { - retObj.x -= gEditWidth; - ++retObj.y; - ++gEditLinesIndex; // There should be a next line in gEditLines - gTextLineIndex = gEditLines[gEditLinesIndex].displayIdxToActualIdx(retObj.x-gEditLeft); - } - else - { - // Edge case: If we re-adjusted text and the cursor was not on the last - // line, ensure the cursor and text line index are correct, in case the - // user was inserting text into a line when more lines existed below. - if (reAdjusted && !wasOnLastLine && (gEditLinesIndex > 0)) - { - if (!lineIdxWasAtBeginningOrMiddle && (originalTextLineLength > gEditLines[gEditLinesIndex-1].text.length)) - { - var wordLen = originalTextLineLength - gEditLines[gEditLinesIndex-1].text.length; - var displayableWordLen = originalTextLineDisplayLength - gEditLines[gEditLinesIndex-1].displayLength(); - retObj.x = gEditLeft + displayableWordLen - 1; - // For gTextLineIndex, subtract 1 to account for space character at the end - // left over from line wrapping - gTextLineIndex = wordLen - 1; - } - } - } + // Make sure the current word length is correct. + retObj.currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); - // Make sure the cursor is placed where it should be. - if (placeCursorAtEnd) - console.gotoxy(retObj.x, retObj.y); + // Make sure the cursor is placed where it should be. + if (placeCursorAtEnd) + console.gotoxy(retObj.x, retObj.y); - return retObj; + return retObj; } // Helper function for doEditLoop(): Performs the action for when the user @@ -2393,16 +2035,15 @@ function doPrintableChar(pUserInput, pCurpos, pCurrentWordLength) function doEnterKey(pCurpos, pCurrentWordLength) { // Create the return object - var retObj = { - x: pCurpos.x, - y: pCurpos.y, - currentWordLength: pCurrentWordLength, - returnCode: 0, - continueOn: true, - doQuoteSelection: false, - doCrossPostSelection: false, - showHelp: false - }; + var retObj = new Object(); + retObj.x = pCurpos.x; + retObj.y = pCurpos.y; + retObj.currentWordLength = pCurrentWordLength; + retObj.returnCode = 0; + retObj.continueOn = true; + retObj.doQuoteSelection = false; + retObj.doCrossPostSelection = false; + retObj.showHelp = false; // Store the current screen row position and gEditLines index. var initialScreenLine = pCurpos.y; @@ -2411,13 +2052,19 @@ function doEnterKey(pCurpos, pCurrentWordLength) // Check for slash commands (/S, /A, /?). If the user has // typed one of them by itself at the beginning of the line, // then save, abort, or show help, respectively. - if (gEditLines[gEditLinesIndex].displayLength() == 2) + if (gEditLines[gEditLinesIndex].length() == 2) { - var lineUpper = strip_ctrl(gEditLines[gEditLinesIndex].text).toUpperCase(); + var lineUpper = gEditLines[gEditLinesIndex].text.toUpperCase(); // /S: Save if (lineUpper == "/S") { - gEditLines[gEditLinesIndex].text = ""; + // If the current text line is the last one, remove it; otherwise, + // blank it out. + if (gEditLinesIndex == gEditLines.length-1) + gEditLines.splice(gEditLinesIndex, 1); + else + gEditLines[gEditLinesIndex].text = ""; + retObj.continueOn = false; return(retObj); } @@ -2437,10 +2084,9 @@ function doEnterKey(pCurpos, pCurrentWordLength) //console.print("\1n" + gTextAttrs); console.print(chooseEditColor()); - // Blank out the data in the text line, set the data in retObj - // and return it (and ensure it has any color/attribute codes - // the user may have set). - gEditLines[gEditLinesIndex].text = gTextAttrs; + // Blank out the data in the text line, set the data in + // retObj, and return it. + gEditLines[gEditLinesIndex].text = ""; retObj.currentWordLength = 0; gTextLineIndex = 0; retObj.x = gEditLeft; @@ -2462,11 +2108,9 @@ function doEnterKey(pCurpos, pCurrentWordLength) retObj.showHelp = (lineUpper == "/?"); retObj.currentWordLength = 0; gTextLineIndex = 0; - // Ensure the line is blank and has any color/attribute codes the - // user may have set. - gEditLines[gEditLinesIndex].text = gTextAttrs; + gEditLines[gEditLinesIndex].text = ""; // Blank out the /? on the screen - //console.print("\1n" + gTextAttrs); + //console.print("n" + gTextAttrs); console.print(chooseEditColor()); retObj.x = gEditLeft; console.gotoxy(retObj.x, retObj.y); @@ -2479,10 +2123,9 @@ function doEnterKey(pCurpos, pCurrentWordLength) { retObj.doCrossPostSelection = true; - // Blank out the data in the text line, set the data in retObj, and - // and return it (and ensure the line has any color/attribute codes - // the user may have set). - gEditLines[gEditLinesIndex].text = gTextAttrs; + // Blank out the data in the text line, set the data in + // retObj, and return it. + gEditLines[gEditLinesIndex].text = ""; retObj.currentWordLength = 0; gTextLineIndex = 0; retObj.x = gEditLeft; @@ -2501,16 +2144,15 @@ function doEnterKey(pCurpos, pCurrentWordLength) { if (gConfigSettings.enableTextReplacements) listTextReplacements(); - // Blank out the data in the text line, set the data in retObj, and - // return it (and ensure it has any color/attribute codes the user - // may have set). - gEditLines[gEditLinesIndex].text = gTextAttrs; + // Blank out the data in the text line, set the data in + // retObj, and return it. + gEditLines[gEditLinesIndex].text = ""; retObj.currentWordLength = 0; gTextLineIndex = 0; retObj.x = gEditLeft; retObj.y = pCurpos.y; // Blank out the /T on the screen - //console.print("\1n" + gTextAttrs); + //console.print("n" + gTextAttrs); console.print(chooseEditColor()); retObj.x = gEditLeft; console.gotoxy(retObj.x, retObj.y); @@ -2525,10 +2167,9 @@ function doEnterKey(pCurpos, pCurrentWordLength) currentCursorPos.x = retObj.x; currentCursorPos.y = retObj.y; doUserSettings(currentCursorPos, false); - // Blank out the data in the text line, set the data in retObj, and - // return it (and ensure it has any color/attribute codes the user - // may have set). - gEditLines[gEditLinesIndex].text = gTextAttrs; + // Blank out the data in the text line, set the data in + // retObj, and return it. + gEditLines[gEditLinesIndex].text = ""; retObj.currentWordLength = 0; gTextLineIndex = 0; retObj.x = gEditLeft; @@ -2553,12 +2194,12 @@ function doEnterKey(pCurpos, pCurrentWordLength) var cursorHorizDiff = 0; if (gConfigSettings.enableTextReplacements) { - var colorsAllowedObj = colorSelectionAllowedInSettingsAndLine(gMsgAreaName, bbs.cursub_code); - var txtReplaceObj = gEditLines[gEditLinesIndex].doMacroTxtReplacement(gTxtReplacements, gTextLineIndex-1, gConfigSettings.textReplacementsUseRegex, colorsAllowedObj.colorsAllowed, gTextAttrs); + var txtReplaceObj = gEditLines[gEditLinesIndex].doMacroTxtReplacement(gTxtReplacements, gTextLineIndex-1, + gConfigSettings.textReplacementsUseRegex); if (txtReplaceObj.madeTxtReplacement) { gTextLineIndex += txtReplaceObj.wordLenDiff; - retObj.x += txtReplaceObj.displayableWordLenDiff; + retObj.x += txtReplaceObj.wordLenDiff; retObj.currentWordLength += txtReplaceObj.wordLenDiff; // If the replaced text on the line is too long to print on the screen,then @@ -2567,6 +2208,7 @@ function doEnterKey(pCurpos, pCurrentWordLength) // is beyond the rightmost colum of the edit area, then wrap the line. if (gEditLeft + txtReplaceObj.newTextEndIdx - 1 >= gEditRight - 1) { + //reAdjustedTxtLines = reAdjustTextLines(gEditLines, gEditLinesIndex, gEditLines.length, gEditWidth); // If the replaced text contains at least one space, then look for // the last space that can appear within the edit area on the screen. if (gEditLines[gEditLinesIndex].text.indexOf(" ", txtReplaceObj.wordStartIdx) > -1) @@ -2629,21 +2271,8 @@ function doEnterKey(pCurpos, pCurrentWordLength) retObj.x += cursorHorizDiff; gTextLineIndex += cursorHorizDiff; - // Place the cursor where it should be console.gotoxy(retObj.x, retObj.y); - // If the current text line starts with the same attribute code twice, - // then remove one of the attribute codes. - if (gEditLines[gEditLinesIndex].text.search(gSyncAttrRegex) == 0) - { - var attrCode = gEditLines[gEditLinesIndex].text.substr(0, 2).toLowerCase(); - if (gEditLines[gEditLinesIndex].text.substr(2, 2).toLowerCase() == attrCode) - { - gEditLines[gEditLinesIndex].text = gEditLines[gEditLinesIndex].text.substr(2); - gTextLineIndex -= 2; - } - } - return retObj; } @@ -2667,163 +2296,122 @@ function doEnterKey(pCurpos, pCurrentWordLength) // the line was added below the line function enterKey_InsertOrAppendNewLine(pCurpos, pCurrentWordLength, pAppendLine) { - var returnObject = { - displayedEditlines: false, - addedATextLine: false, - addedTextLineBelow: false - }; - - // If we're at the end of the line, then we can simply - // add a new blank line & set the cursor there. - // Otherwise, we need to split the current line, and - // the text to the right of the cursor will go on the new line. - if (gTextLineIndex == gEditLines[gEditLinesIndex].text.length) - { - if (pAppendLine) - { - // Add a new blank line to the end of the message, and set - // the cursor there. - gEditLines.push(new TextLine()); - ++gEditLinesIndex; - // Ensure the new text line has any color/attribute codes the user has set - gEditLines[gEditLinesIndex].text = gTextAttrs; - returnObject.addedATextLine = true; - returnObject.addedTextLineBelow = true; - } - else - { - // Increment gEditLinesIndex and add a new line there. - ++gEditLinesIndex; - gEditLines.splice(gEditLinesIndex, 0, new TextLine()); - // Ensure the new text line has any color/attribute codes the user has set - gEditLines[gEditLinesIndex].text = gTextAttrs; - returnObject.addedATextLine = true; - } - - gTextLineIndex = 0; - pCurrentWordLength = 0; - pCurpos.x = gEditLeft; - // Update the vertical cursor position. - // If the cursor is at the bottom row, then we need - // to scroll the message down by 1 line. Otherwise, - // we can simply increment pCurpos.y. - if (pCurpos.y == gEditBottom) - { - displayEditLines(gEditTop, gEditLinesIndex-(gEditBottom-gEditTop), gEditBottom, true, true); - returnObject.displayedEditlines = true; - } - else - ++pCurpos.y; - } - else - { - // We're in the middle of the line. - // Get the text to the end of the current line. - // Note: The cursor's x position should be 1 more than display index in the string - var actualStartIdx = gEditLines[gEditLinesIndex].displayIdxToActualIdx(pCurpos.x-gEditLeft); - // If there are Synchronet attribute codes before actualStartIdx, then get them too - if (actualStartIdx >= 2) - { - var attrStartIdx = -1; - var textIdx = actualStartIdx - 2; - while (textIdx >= 0) - { - if (gSyncAttrRegex.test(gEditLines[gEditLinesIndex].text.substr(textIdx, 2))) - { - attrStartIdx = textIdx; - textIdx -= 2; - } - else - break; - } - if (attrStartIdx > -1) - actualStartIdx = attrStartIdx; - } - // Get the substring from the end of the current text line - var lineEnd = gEditLines[gEditLinesIndex].text.substr(actualStartIdx); - - // Remove that text from the current line. - gEditLines[gEditLinesIndex].text = gEditLines[gEditLinesIndex].text.substr(0, actualStartIdx); - - if (pAppendLine) - { - // Create a new line containing lineEn and append it to - // gEditLines. Then place the cursor at the start of that line. - var newTextLine = new TextLine(); - // Ensure the new text line has the text color/attribute codes the user - // has set - newTextLine.text = gTextAttrs + lineEnd; - newTextLine.hardNewlineEnd = gEditLines[gEditLinesIndex].hardNewlineEnd; - newTextLine.isQuoteLine = gEditLines[gEditLinesIndex].isQuoteLine; - gEditLines.push(newTextLine); - ++gEditLinesIndex; - returnObject.addedATextLine = true; - returnObject.addedTextLineBelow = true; - } - else - { - // Create a new line containing lineEnd and splice it into - // gEditLines on the next line. Then place the cursor at the - // start of that line. - var oldIndex = gEditLinesIndex++; - var newTextLine = new TextLine(); - // Ensure the new line has any color/attribute codes the user has set - newTextLine.text = gTextAttrs + lineEnd; - newTextLine.hardNewlineEnd = gEditLines[oldIndex].hardNewlineEnd; - newTextLine.isQuoteLine = gEditLines[oldIndex].isQuoteLine; - // If the user pressed enter at the beginning of a line, then a new - // blank line will be inserted above, so we want to make sure its - // isQuoteLine property is set to false. - if (gTextLineIndex == 0) - gEditLines[oldIndex].isQuoteLine = false; - // Splice the new text line into gEditLines at gEditLinesIndex. - gEditLines.splice(gEditLinesIndex, 0, newTextLine); - returnObject.addedATextLine = true; - } + var returnObject = new Object(); + returnObject.displayedEditlines = false; + returnObject.addedATextLine = false; + returnObject.addedTextLineBelow = false; + + // If we're at the end of the line, then we can simply + // add a new blank line & set the cursor there. + // Otherwise, we need to split the current line, and + // the text to the right of the cursor will go on the new line. + if (gTextLineIndex == gEditLines[gEditLinesIndex].length()) + { + if (pAppendLine) + { + // Add a new blank line to the end of the message, and set + // the cursor there. + gEditLines.push(new TextLine()); + ++gEditLinesIndex; + returnObject.addedATextLine = true; + returnObject.addedTextLineBelow = true; + } + else + { + // Increment gEditLinesIndex and add a new line there. + ++gEditLinesIndex; + gEditLines.splice(gEditLinesIndex, 0, new TextLine()); + returnObject.addedATextLine = true; + } - gTextLineIndex = 0; - pCurpos.x = gEditLeft; - // Update the vertical cursor position. - // If the cursor is at the bottom row, then we need - // to scroll the message down by 1 line. Otherwise, - // we can simply increment pCurpos.y. - if (pCurpos.y == gEditBottom) - { - displayEditLines(gEditTop, gEditLinesIndex-(gEditBottom-gEditTop), gEditBottom, true, true); - returnObject.displayedEditlines = true; - } - else - ++pCurpos.y; - // Figure out the current word length. - // Look for a space in lineEnd. If a space is found, - // the word length is the length of the word up until the - // space. If a space is not found, then the word length - // is the entire length of lineEnd. - var spacePos = lineEnd.indexOf(" "); - if (spacePos > -1) - pCurrentWordLength = spacePos; - else - pCurrentWordLength = strip_ctrl(lineEnd).length; - } + gTextLineIndex = 0; + pCurrentWordLength = 0; + pCurpos.x = gEditLeft; + // Update the vertical cursor position. + // If the cursor is at the bottom row, then we need + // to scroll the message down by 1 line. Otherwise, + // we can simply increment pCurpos.y. + if (pCurpos.y == gEditBottom) + { + displayEditLines(gEditTop, gEditLinesIndex-(gEditBottom-gEditTop), + gEditBottom, true, true); + returnObject.displayedEditlines = true; + } + else + ++pCurpos.y; + } + else + { + // We're in the middle of the line. + // Get the text to the end of the current line. + var lineEndText = gEditLines[gEditLinesIndex].text.substr(gTextLineIndex); + // Remove that text from the current line. + gEditLines[gEditLinesIndex].text = gEditLines[gEditLinesIndex].text.substr(0, gTextLineIndex); - // If the current line starts with the normal attribute and ends with normal-white and - // has no Synchronet attributes in between, then remove the redundant normal-white - // attributes from the end - var lineStartWithNormalAttr = (gEditLines[gEditLinesIndex].text.search(/n/i) == 0); - var lineEndsWithNormalWhite = /nw$/i.test(gEditLines[gEditLinesIndex].text); - if (lineStartWithNormalAttr && lineEndsWithNormalWhite) - { - var anySyncAttrsInBetween = gOnlySyncAttrsInStrRegex.test(gEditLines[gEditLinesIndex].text.substr(2, gEditLines[gEditLinesIndex].text.length-5)); - if (!anySyncAttrsInBetween) - gEditLines[gEditLinesIndex].text = gEditLines[gEditLinesIndex].text.substr(0, gEditLines[gEditLinesIndex].text.length-4); - } + if (pAppendLine) + { + // Create a new line containing lineEndText and append it to + // gEditLines. Then place the cursor at the start of that line. + var newTextLine = new TextLine(); + newTextLine.text = lineEndText; + newTextLine.hardNewlineEnd = gEditLines[gEditLinesIndex].hardNewlineEnd; + newTextLine.isQuoteLine = gEditLines[gEditLinesIndex].isQuoteLine; + gEditLines.push(newTextLine); + ++gEditLinesIndex; + returnObject.addedATextLine = true; + returnObject.addedTextLineBelow = true; + } + else + { + // Create a new line containing lineEndText and splice it into + // gEditLines on the next line. Then place the cursor at the + // start of that line. + var oldIndex = gEditLinesIndex++; + var newTextLine = new TextLine(); + newTextLine.text = lineEndText; + newTextLine.hardNewlineEnd = gEditLines[oldIndex].hardNewlineEnd; + newTextLine.isQuoteLine = gEditLines[oldIndex].isQuoteLine; + // If the user pressed enter at the beginning of a line, then a new + // blank line will be inserted above, so we want to make sure its + // isQuoteLine property is set to false. + if (gTextLineIndex == 0) + gEditLines[oldIndex].isQuoteLine = false; + // Splice the new text line into gEditLines at gEditLinesIndex. + gEditLines.splice(gEditLinesIndex, 0, newTextLine); + returnObject.addedATextLine = true; + } - // Set some stuff in the return object, and return it. - returnObject.x = pCurpos.x; - returnObject.y = pCurpos.y; - returnObject.currentWordLength = pCurrentWordLength; + gTextLineIndex = 0; + pCurpos.x = gEditLeft; + // Update the vertical cursor position. + // If the cursor is at the bottom row, then we need + // to scroll the message down by 1 line. Otherwise, + // we can simply increment pCurpos.y. + if (pCurpos.y == gEditBottom) + { + displayEditLines(gEditTop, gEditLinesIndex-(gEditBottom-gEditTop), + gEditBottom, true, true); + returnObject.displayedEditlines = true; + } + else + ++pCurpos.y; + // Figure out the current word length. + // Look for a space in lineEndText. If a space is found, + // the word length is the length of the word up until the + // space. If a space is not found, then the word length + // is the entire length of lineEndText. + var spacePos = lineEndText.indexOf(" "); + if (spacePos > -1) + pCurrentWordLength = spacePos; + else + pCurrentWordLength = lineEndText.length; + } - return returnObject; + // Set some stuff in the return object, and return it. + returnObject.x = pCurpos.x; + returnObject.y = pCurpos.y; + returnObject.currentWordLength = pCurrentWordLength; + return returnObject; } // Helper function for doEditLoop(): Returns whether a text line is editable @@ -2861,12 +2449,11 @@ function textLineIsEditable(pLineIdx) function doQuoteSelection(pCurpos, pCurrentWordLength) { // Create the return object - var retObj = { - x: pCurpos.x, - y: pCurpos.y, - timedOut: false, - currentWordLength: pCurrentWordLength - }; + var retObj = new Object(); + retObj.x = pCurpos.x; + retObj.y = pCurpos.y; + retObj.timedOut = false; + retObj.currentWordLength = pCurrentWordLength; // Note: Quote lines are in the gQuoteLines array, where each element is // a string. @@ -2921,6 +2508,7 @@ function doQuoteSelection(pCurpos, pCurrentWordLength) // then re-populate gQuoteLines with the original quote lines. if (trimSpacesFromQuoteLinesSettingChanged) { + //readQuoteOrMessageFile(); gQuoteLines = []; for (var i = 0; i < doQuoteSelection.backupQuoteLines.length; ++i) gQuoteLines.push(doQuoteSelection.backupQuoteLines[i]); @@ -2944,6 +2532,8 @@ function doQuoteSelection(pCurpos, pCurrentWordLength) setQuotePrefix(); if (gConfigSettings.reWrapQuoteLines) { + // TODO: This seemed to never be finishing for certain messages - Entering + // an infinite loop? I believe this was fixed as of version 1.49. wrapQuoteLines(gUserSettings.useQuoteLineInitials, gUserSettings.indentQuoteLinesWithInitials, gUserSettings.trimSpacesFromQuoteLines); } @@ -2957,10 +2547,9 @@ function doQuoteSelection(pCurpos, pCurrentWordLength) } // Set up some variables - var curpos = { - x: pCurpos.x, - y: pCurpos.y - }; + var curpos = new Object(); + curpos.x = pCurpos.x; + curpos.y = pCurpos.y; // Make the quote window's height about 42% of the edit area. const quoteWinHeight = Math.floor(gEditHeight * 0.42) + 1; // The first and last lines on the screen where quote lines are written @@ -2989,7 +2578,6 @@ function doQuoteSelection(pCurpos, pCurrentWordLength) // User input loop var quoteLine = getQuoteTextLine(gQuoteLinesIndex, quoteWinWidth); retObj.timedOut = false; - var choseFirstQuoteLine = true; var userInput = null; var continueOn = true; while (continueOn) @@ -3034,7 +2622,6 @@ function doQuoteSelection(pCurpos, pCurrentWordLength) quoteLine = getQuoteTextLine(gQuoteLinesIndex, quoteWinWidth); console.gotoxy(gEditLeft, screenLine); printf(gFormatStrWithAttr, gQuoteWinTextColor, quoteLine); - // Go up one line and display that quote line in the // highlighted color. @@ -3052,8 +2639,8 @@ function doQuoteSelection(pCurpos, pCurrentWordLength) case KEY_DOWN: // Go down 1 line in the quote window. var downRetObj = moveDownOneQuoteLine(gQuoteLinesIndex, screenLine, - quoteWinHeight, quoteWinWidth, - quoteBottomScreenRow); + quoteWinHeight, quoteWinWidth, + quoteBottomScreenRow); gQuoteLinesIndex = downRetObj.quoteLinesIndex; screenLine = downRetObj.screenLine; quoteLine = downRetObj.quoteLine; @@ -3151,13 +2738,7 @@ function doQuoteSelection(pCurpos, pCurrentWordLength) var numTimesToMoveDown = 1; // Insert the quote line into gEditLines after the current gEditLines index. - // Ensure the quote line has a normal attribute. The user's text color/attributes - // will be set back into the edit lines later. - var insertedBelow = false; - if (choseFirstQuoteLine) - insertedBelow = insertLineIntoMsg(gEditLinesIndex, "\1n" + quoteLine, true, true); - else - insertedBelow = insertLineIntoMsg(gEditLinesIndex, quoteLine, true, true); + var insertedBelow = insertLineIntoMsg(gEditLinesIndex, quoteLine, true, true); if (insertedBelow) { // The cursor will need to be moved down 1 more line. @@ -3169,7 +2750,7 @@ function doQuoteSelection(pCurpos, pCurrentWordLength) retObj.currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); } else - retObj.currentWordLength = 0; + retObj.currentWordLength = 0; // Refresh the part of the message that needs to be refreshed on the // screen (above the quote window). @@ -3228,6 +2809,7 @@ function doQuoteSelection(pCurpos, pCurrentWordLength) gInsertMode, gConfigSettings.allowColorSelection); // Make sure the color is correct for editing. + //console.print("n" + gTextAttrs); console.print(chooseEditColor()); // Put the cursor where it should be. console.gotoxy(curpos); @@ -3496,96 +3078,83 @@ function toggleInsertMode(pCurpos) // to always write the edit text regardless of gEditAreaBuffer. // By default, gEditAreaBuffer is always checked. function displayEditLines(pStartScreenRow, pArrayIndex, pEndScreenRow, pClearRemainingScreenRows, - pIgnoreEditAreaBuffer) + pIgnoreEditAreaBuffer) { - // Make sure the array has lines in it, the given array index is valid, and - // that the given line # is valid. If not, then just return. - if ((gEditLines.length == 0) || (pArrayIndex < 0) || (pStartScreenRow < 1) || (pStartScreenRow > gEditBottom)) - return; + // Make sure the array has lines in it, the given array index is valid, and + // that the given line # is valid. If not, then just return. + if ((gEditLines.length == 0) || (pArrayIndex < 0) || (pStartScreenRow < 1) || (pStartScreenRow > gEditBottom)) + return; - // Choose which ending screen row to use for displaying text, - // pEndScreenRow or gEditBottom. - var endScreenRow = (pEndScreenRow != null ? pEndScreenRow : gEditBottom); + // Choose which ending screen row to use for displaying text, + // pEndScreenRow or gEditBottom. + var endScreenRow = (pEndScreenRow != null ? pEndScreenRow : gEditBottom); - // Display the message lines - var screenLine = pStartScreenRow; - var arrayIndex = pArrayIndex; - while ((screenLine <= endScreenRow) && (arrayIndex < gEditLines.length)) - { - // Print the text from the current line in gEditLines. Note: Lines starting - // with " >" are assumed to be quote lines - Display those lines with cyan - // color and the normal lines with the appropriate color - // Note: gEditAreaBuffer is also used in clearMsgAreaToBottom(). - if ((gEditAreaBuffer[screenLine] != gEditLines[arrayIndex].text) || pIgnoreEditAreaBuffer) - { - // Choose the quote line color or the normal color for the line, then - // display the line on the screen. - var color = ""; - if (isQuoteLine(gEditLines, arrayIndex)) - color = gQuoteLineColor; - else - { - color = "\1n"; - // If we're past the first line, look for the last color codes - // in the previous line and use those, since those should be - // applicable to print the current line. - if (arrayIndex > 0) - color = gEditLines[arrayIndex-1].getLastAttrCodes(); - } - // If a color/attribute code wasn't found, then use the normal - // attribute to ensure the wrong color isn't used in the wrong place - if (color.length == 0) - color = "\1n"; - console.gotoxy(gEditLeft, screenLine); - printLineAndFillEditWidthRemainder(gEditLines[arrayIndex].text, color, isQuoteLine(gEditLines, arrayIndex)); - gEditAreaBuffer[screenLine] = gEditLines[arrayIndex].text; - } + // Display the message lines + console.print("n" + gTextAttrs); + var screenLine = pStartScreenRow; + var arrayIndex = pArrayIndex; + while ((screenLine <= endScreenRow) && (arrayIndex < gEditLines.length)) + { + // Print the text from the current line in gEditLines. Note: Lines starting + // with " >" are assumed to be quote lines - Display those lines with cyan + // color and the normal lines with gTextAttrs. + var color = gTextAttrs; + // Note: gEditAreaBuffer is also used in clearMsgAreaToBottom(). + if ((gEditAreaBuffer[screenLine] != gEditLines[arrayIndex].text) || pIgnoreEditAreaBuffer) + { + // Choose the quote line color or the normal color for the line, then + // display the line on the screen. + color = (isQuoteLine(gEditLines, arrayIndex) ? gQuoteLineColor : gTextAttrs); + console.gotoxy(gEditLeft, screenLine); + printf(gFormatStrWithAttr, color, gEditLines[arrayIndex].text); + gEditAreaBuffer[screenLine] = gEditLines[arrayIndex].text; + } - ++screenLine; - ++arrayIndex; - } - if (arrayIndex > 0) - --arrayIndex; - // incrementLineBeforeClearRemaining stores whether or not we - // should increment screenLine before clearing the remaining - // lines in the edit area. - var incrementLineBeforeClearRemaining = true; - // If the array index is valid, and if the current line is shorter - // than the edit area width, then place the cursor after the last - // character in the line. - if ((arrayIndex >= 0) && (arrayIndex < gEditLines.length) && (gEditLines[arrayIndex] != undefined) && - (gEditLines[arrayIndex].text != undefined)) - { - var lineLength = gEditLines[arrayIndex].displayLength(); - if (lineLength < gEditWidth) - { - --screenLine; - console.gotoxy(gEditLeft + gEditLines[arrayIndex].displayLength(), screenLine); - } - else if ((lineLength == gEditWidth) || (lineLength == 0)) - incrementLineBeforeClearRemaining = false; - } - else - incrementLineBeforeClearRemaining = false; + ++screenLine; + ++arrayIndex; + } + if (arrayIndex > 0) + --arrayIndex; + // incrementLineBeforeClearRemaining stores whether or not we + // should increment screenLine before clearing the remaining + // lines in the edit area. + var incrementLineBeforeClearRemaining = true; + // If the array index is valid, and if the current line is shorter + // than the edit area width, then place the cursor after the last + // character in the line. + if ((arrayIndex >= 0) && (arrayIndex < gEditLines.length) && + (gEditLines[arrayIndex] != undefined) && (gEditLines[arrayIndex].text != undefined)) + { + var lineLength = gEditLines[arrayIndex].length(); + if (lineLength < gEditWidth) + { + --screenLine; + console.gotoxy(gEditLeft + gEditLines[arrayIndex].length(), screenLine); + } + else if ((lineLength == gEditWidth) || (lineLength == 0)) + incrementLineBeforeClearRemaining = false; + } + else + incrementLineBeforeClearRemaining = false; - // Edge case: If the current screen line is below the last line, then - // clear the lines up until that point. - var clearRemainingScreenLines = (pClearRemainingScreenRows != null ? pClearRemainingScreenRows : true); - if (clearRemainingScreenLines && (screenLine <= endScreenRow)) - { - //console.print("\1n" + gTextAttrs); - console.print("\1n"); - var screenLineBackup = screenLine; // So we can move the cursor back - clearMsgAreaToBottom(incrementLineBeforeClearRemaining ? screenLine+1 : screenLine, pIgnoreEditAreaBuffer); - // Move the cursor back to the end of the current text line. - if (typeof(gEditLines[arrayIndex]) != "undefined") - console.gotoxy(gEditLeft + gEditLines[arrayIndex].displayLength(), screenLineBackup); - else - console.gotoxy(gEditLeft, screenLineBackup); - } + // Edge case: If the current screen line is below the last line, then + // clear the lines up until that point. + var clearRemainingScreenLines = (pClearRemainingScreenRows != null ? pClearRemainingScreenRows : true); + if (clearRemainingScreenLines && (screenLine <= endScreenRow)) + { + console.print("n" + gTextAttrs); + var screenLineBackup = screenLine; // So we can move the cursor back + clearMsgAreaToBottom(incrementLineBeforeClearRemaining ? screenLine+1 : screenLine, + pIgnoreEditAreaBuffer); + // Move the cursor back to the end of the current text line. + if (typeof(gEditLines[arrayIndex]) != "undefined") + console.gotoxy(gEditLeft + gEditLines[arrayIndex].length(), screenLineBackup); + else + console.gotoxy(gEditLeft, screenLineBackup); + } - // Make sure the correct color is set for the current line. - console.print(chooseEditColor()); + // Make sure the correct color is set for the current line. + console.print(chooseEditColor()); } // Clears the lines in the message area from a given line to the bottom. @@ -3617,7 +3186,7 @@ function messageIsEmpty() for (var i = 0; i < gEditLines.length; ++i) { - if (gEditLines[i].displayLength() > 0) + if (gEditLines[i].length() > 0) { msgEmpty = false; break; @@ -3641,53 +3210,54 @@ function messageIsEmpty() // up to the specified width will be cleared. Defaults to false. function displayMessageRectangle(pX, pY, pWidth, pHeight, pEditLinesIndex, pClearExtraWidth) { - // If any of the parameters are out of bounds, then just return without - // doing anything. - if ((pX < gEditLeft) || (pY < gEditTop) || (pWidth < 0) || (pHeight < 0) || (pEditLinesIndex < 0)) - return; + // If any of the parameters are out of bounds, then just return without + // doing anything. + if ((pX < gEditLeft) || (pY < gEditTop) || (pWidth < 0) || (pHeight < 0) || (pEditLinesIndex < 0)) + return; - // If pWidth is too long with the given pX, then fix it. - if (pWidth > (gEditRight - pX + 1)) - pWidth = gEditRight - pX + 1; - // If pHeight is too much with the given pY, then fix it. - if (pHeight > (gEditBottom - pY + 1)) - pHeight = gEditBottom - pY + 1; - - // Calculate the index into the edit line using pX and gEditLeft. This - // assumes that pX is within the edit area (and it should be). - const editLineIndex = pX - gEditLeft; - - // Go to the given position on the screen and output the message text. - var messageStr = ""; // Will contain a portion of the message text - var screenY = pY; - var editLinesIndex = pEditLinesIndex; - var formatStr = "%-" + pWidth + "s"; - var actualLenWritten = 0; // Actual length of text written for each line - for (var rectangleLine = 0; rectangleLine < pHeight; ++rectangleLine) - { - // Go to the position on the screen - screenY = pY + rectangleLine; - console.gotoxy(pX, screenY); - // Display the message text. If the current edit line is valid, - // then print it; otherwise, just print spaces to blank out the line. - if (typeof(gEditLines[editLinesIndex]) != "undefined") - { - actualLenWritten = printEditLine(editLinesIndex, editLineIndex, pWidth); - // If pClearExtraWidth is true, then if the box width is longer than - // the text that was written, then output spaces to clear the rest - // of the line to erase the rest of the box line. - if (pClearExtraWidth) - { - var clearWidth = pWidth - actualLenWritten; - if (pWidth > actualLenWritten) - printf("%" + clearWidth + "s", ""); - } - } - else - printf(formatStr, ""); + // If pWidth is too long with the given pX, then fix it. + if (pWidth > (gEditRight - pX + 1)) + pWidth = gEditRight - pX + 1; + // If pHeight is too much with the given pY, then fix it. + if (pHeight > (gEditBottom - pY + 1)) + pHeight = gEditBottom - pY + 1; + + // Calculate the index into the edit line using pX and gEditLeft. This + // assumes that pX is within the edit area (and it should be). + const editLineIndex = pX - gEditLeft; + + // Go to the given position on the screen and output the message text. + var messageStr = ""; // Will contain a portion of the message text + var screenY = pY; + var editLinesIndex = pEditLinesIndex; + var formatStr = "%-" + pWidth + "s"; + var actualLenWritten = 0; // Actual length of text written for each line + for (var rectangleLine = 0; rectangleLine < pHeight; ++rectangleLine) + { + // Output the correct color for the line + console.print("n" + (isQuoteLine(gEditLines, editLinesIndex) ? gQuoteLineColor : gTextAttrs)); + // Go to the position on the screen + screenY = pY + rectangleLine; + console.gotoxy(pX, screenY); + // Display the message text. If the current edit line is valid, + // then print it; otherwise, just print spaces to blank out the line. + if (typeof(gEditLines[editLinesIndex]) != "undefined") + { + actualLenWritten = printEditLine(editLinesIndex, false, editLineIndex, pWidth); + // If pClearExtraWidth is true, then if the box width is longer than + // the text that was written, then output spaces to clear the rest + // of the line to erase the rest of the box line. + if (pClearExtraWidth) + { + if (pWidth > actualLenWritten) + printf("%" + +(pWidth-actualLenWritten) + "s", ""); + } + } + else + printf(formatStr, ""); - ++editLinesIndex; - } + ++editLinesIndex; + } } // Displays the DCTEdit-style ESC menu and handles user input from that menu. @@ -3708,134 +3278,139 @@ function displayMessageRectangle(pX, pY, pWidth, pHeight, pEditLinesIndex, pClea // currentWordLength: The length of the current word function handleDCTESCMenu(pCurpos, pCurrentWordLength) { - var returnObj = new Object(); - returnObj.returnCode = 0; - returnObj.continueOn = true; - returnObj.x = pCurpos.x; - returnObj.y = pCurpos.y; - returnObj.currentWordLength = pCurrentWordLength; - - // Call doDCTMenu() to display the DCT Edit menu and get the - // user's choice. - var editLineDiff = pCurpos.y - gEditTop; - var menuChoice = doDCTMenu(gEditLeft, gEditRight, gEditTop, - displayMessageRectangle, gEditLinesIndex, - editLineDiff, gConfigSettings.userIsSysop, gCanCrossPost); - // Take action according to the user's choice. - // Save - if ((menuChoice == "S") || (menuChoice == CTRL_Z) || (menuChoice == DCTMENU_FILE_SAVE)) - { - returnObj.returnCode = 0; - returnObj.continueOn = false; - } - // Abort - else if ((menuChoice == "A") || (menuChoice == CTRL_A) || (menuChoice == DCTMENU_FILE_ABORT)) - { - // Before aborting, ask they user if they really want to abort. - if (promptYesNo("Abort message", false, "Abort", false)) - { - returnObj.returnCode = 1; // Aborted - returnObj.continueOn = false; - } - else - { - // Make sure the edit color attribute is set back. - console.print(chooseEditColor()); - } - } - // Toggle insert/overwrite mode - else if ((menuChoice == CTRL_V) || (menuChoice == DCTMENU_EDIT_INSERT_TOGGLE)) - toggleInsertMode(pCurpos); - // Import file (sysop only) - else if (menuChoice == DCTMENU_SYSOP_IMPORT_FILE) - { - var retval = importFile(gConfigSettings.userIsSysop, pCurpos); - returnObj.x = retval.x; - returnObj.y = retval.y; - returnObj.currentWordLength = retval.currentWordLength; - } - // Import file for sysop, or Insert/Overwrite toggle for non-sysop - else if (menuChoice == "I") - { - if (gConfigSettings.userIsSysop) - { - var retval = importFile(gConfigSettings.userIsSysop, pCurpos); - returnObj.x = retval.x; - returnObj.y = retval.y; - returnObj.currentWordLength = retval.currentWordLength; - } - else - toggleInsertMode(pCurpos); - } - // Find text - else if ((menuChoice == CTRL_F) || (menuChoice == "F") || - (menuChoice == DCTMENU_EDIT_FIND_TEXT)) - { - var retval = findText(pCurpos); - returnObj.x = retval.x; - returnObj.y = retval.y; - } - // Command List - else if ((menuChoice == "O") || (menuChoice == DCTMENU_HELP_COMMAND_LIST)) - { - displayCommandList(true, true, true, gCanCrossPost, gConfigSettings); - clearEditAreaBuffer(); - fpRedrawScreen(gEditLeft, gEditRight, gEditTop, gEditBottom, gTextAttrs, - gInsertMode, gUseQuotes, gEditLinesIndex-(pCurpos.y-gEditTop), - displayEditLines); - } - // General help - else if ((menuChoice == "G") || (menuChoice == DCTMENU_HELP_GENERAL)) - { - displayGeneralHelp(true, true, true); - clearEditAreaBuffer(); - fpRedrawScreen(gEditLeft, gEditRight, gEditTop, gEditBottom, gTextAttrs, - gInsertMode, gUseQuotes, gEditLinesIndex-(pCurpos.y-gEditTop), - displayEditLines); - } - // Program info - else if ((menuChoice == "P") || (menuChoice == DCTMENU_HELP_PROGRAM_INFO)) - { - displayProgramInfo(true, true); - clearEditAreaBuffer(); - fpRedrawScreen(gEditLeft, gEditRight, gEditTop, gEditBottom, gTextAttrs, - gInsertMode, gUseQuotes, gEditLinesIndex-(pCurpos.y-gEditTop), - displayEditLines); - } - // Export the message - else if ((menuChoice == "X") || (menuChoice == DCTMENU_SYSOP_EXPORT_FILE)) - { - if (gConfigSettings.userIsSysop) - { - exportToFile(gConfigSettings.userIsSysop); - console.gotoxy(returnObj.x, returnObj.y); - } - } - // Edit the message - else if ((menuChoice == "E") || (menuChoice == KEY_ESC)) - { - // We don't need to do do anything in here. - } - // Cross-post - else if ((menuChoice == CTRL_C) || (menuChoice == "C") || (menuChoice == DCTMENU_CROSS_POST)) - { - if (gCanCrossPost) - doCrossPosting(pCurpos); - } - // List text replacements - else if ((menuChoice == CTRL_T) || (menuChoice == "T") || (menuChoice == DCTMENU_LIST_TXT_REPLACEMENTS)) - { - if (gConfigSettings.enableTextReplacements) - listTextReplacements(); - } - // User settings - else if ((menuChoice == CTRL_U) || (menuChoice == "N") || (menuChoice == DCTMENU_EDIT_SETTINGS)) - doUserSettings(pCurpos, true); + var returnObj = new Object(); + returnObj.returnCode = 0; + returnObj.continueOn = true; + returnObj.x = pCurpos.x; + returnObj.y = pCurpos.y; + returnObj.currentWordLength = pCurrentWordLength; + + // Call doDCTMenu() to display the DCT Edit menu and get the + // user's choice. + var editLineDiff = pCurpos.y - gEditTop; + var menuChoice = doDCTMenu(gEditLeft, gEditRight, gEditTop, + displayMessageRectangle, gEditLinesIndex, + editLineDiff, gConfigSettings.userIsSysop, gCanCrossPost); + // Take action according to the user's choice. + // Save + if ((menuChoice == "S") || (menuChoice == CTRL_Z) || + (menuChoice == DCTMENU_FILE_SAVE)) + { + returnObj.returnCode = 0; + returnObj.continueOn = false; + } + // Abort + else if ((menuChoice == "A") || (menuChoice == CTRL_A) || + (menuChoice == DCTMENU_FILE_ABORT)) + { + // Before aborting, ask they user if they really want to abort. + if (promptYesNo("Abort message", false, "Abort", false)) + { + returnObj.returnCode = 1; // Aborted + returnObj.continueOn = false; + } + else + { + // Make sure the edit color attribute is set back. + //console.print("n" + gTextAttrs); + console.print(chooseEditColor()); + } + } + // Toggle insert/overwrite mode + else if ((menuChoice == CTRL_V) || (menuChoice == DCTMENU_EDIT_INSERT_TOGGLE)) + toggleInsertMode(pCurpos); + // Import file (sysop only) + else if (menuChoice == DCTMENU_SYSOP_IMPORT_FILE) + { + var retval = importFile(gConfigSettings.userIsSysop, pCurpos); + returnObj.x = retval.x; + returnObj.y = retval.y; + returnObj.currentWordLength = retval.currentWordLength; + } + // Import file for sysop, or Insert/Overwrite toggle for non-sysop + else if (menuChoice == "I") + { + if (gConfigSettings.userIsSysop) + { + var retval = importFile(gConfigSettings.userIsSysop, pCurpos); + returnObj.x = retval.x; + returnObj.y = retval.y; + returnObj.currentWordLength = retval.currentWordLength; + } + else + toggleInsertMode(pCurpos); + } + // Find text + else if ((menuChoice == CTRL_F) || (menuChoice == "F") || + (menuChoice == DCTMENU_EDIT_FIND_TEXT)) + { + var retval = findText(pCurpos); + returnObj.x = retval.x; + returnObj.y = retval.y; + } + // Command List + else if ((menuChoice == "O") || (menuChoice == DCTMENU_HELP_COMMAND_LIST)) + { + displayCommandList(true, true, true, gCanCrossPost, gConfigSettings.userIsSysop, + gConfigSettings.enableTextReplacements, gConfigSettings.allowUserSettings); + clearEditAreaBuffer(); + fpRedrawScreen(gEditLeft, gEditRight, gEditTop, gEditBottom, gTextAttrs, + gInsertMode, gUseQuotes, gEditLinesIndex-(pCurpos.y-gEditTop), + displayEditLines); + } + // General help + else if ((menuChoice == "G") || (menuChoice == DCTMENU_HELP_GENERAL)) + { + displayGeneralHelp(true, true, true); + clearEditAreaBuffer(); + fpRedrawScreen(gEditLeft, gEditRight, gEditTop, gEditBottom, gTextAttrs, + gInsertMode, gUseQuotes, gEditLinesIndex-(pCurpos.y-gEditTop), + displayEditLines); + } + // Program info + else if ((menuChoice == "P") || (menuChoice == DCTMENU_HELP_PROGRAM_INFO)) + { + displayProgramInfo(true, true); + clearEditAreaBuffer(); + fpRedrawScreen(gEditLeft, gEditRight, gEditTop, gEditBottom, gTextAttrs, + gInsertMode, gUseQuotes, gEditLinesIndex-(pCurpos.y-gEditTop), + displayEditLines); + } + // Export the message + else if ((menuChoice == "X") || (menuChoice == DCTMENU_SYSOP_EXPORT_FILE)) + { + if (gConfigSettings.userIsSysop) + { + exportToFile(gConfigSettings.userIsSysop); + console.gotoxy(returnObj.x, returnObj.y); + } + } + // Edit the message + else if ((menuChoice == "E") || (menuChoice == KEY_ESC)) + { + // We don't need to do do anything in here. + } + // Cross-post + else if ((menuChoice == CTRL_C) || (menuChoice == "C") || (menuChoice == DCTMENU_CROSS_POST)) + { + if (gCanCrossPost) + doCrossPosting(pCurpos); + } + // List text replacements + else if ((menuChoice == CTRL_T) || (menuChoice == "T") || (menuChoice == DCTMENU_LIST_TXT_REPLACEMENTS)) + { + if (gConfigSettings.enableTextReplacements) + listTextReplacements(); + } + // User settings + else if ((menuChoice == CTRL_U) || (menuChoice == "N") || (menuChoice == DCTMENU_EDIT_SETTINGS)) + doUserSettings(pCurpos, true); - // Make sure the edit color attribute is set back. - console.print(chooseEditColor()); + // Make sure the edit color attribute is set back. + //console.print("n" + gTextAttrs); + console.print(chooseEditColor()); - return returnObj; + return returnObj; } // Displays the IceEdit-style ESC menu and handles user input from that menu. @@ -3888,7 +3463,8 @@ function handleIceESCMenu(pCurpos, pCurrentWordLength) break; case ICE_ESC_MENU_HELP: displayProgramInfo(true, false); - displayCommandList(false, false, true, gCanCrossPost, gConfigSettings); + displayCommandList(false, false, true, gCanCrossPost, gConfigSettings.userIsSysop, + gConfigSettings.enableTextReplacements, gConfigSettings.allowUserSettings); clearEditAreaBuffer(); fpRedrawScreen(gEditLeft, gEditRight, gEditTop, gEditBottom, gTextAttrs, gInsertMode, gUseQuotes, gEditLinesIndex-(pCurpos.y-gEditTop), @@ -3922,64 +3498,65 @@ function handleIceESCMenu(pCurpos, pCurrentWordLength) // Return value: The length of the word at the given indexes function getWordLength(pEditLinesIndex, pTextLineIndex) { - // pEditLinesIndex and pTextLineIndex should be >= 0 before we can do - // anything in this function. - if ((pEditLinesIndex < 0) || (pTextLineIndex < 0)) - return 0; - // Also, make sure gEditLines[pEditLinesIndex] is valid. - if ((gEditLines[pEditLinesIndex] == null) || (typeof(gEditLines[pEditLinesIndex]) == "undefined")) - return 0; - - // This function counts and returns the number of non-whitespace characters - // before the current character. - function countBeforeCurrentChar() - { - var charCount = 0; + // pEditLinesIndex and pTextLineIndex should be >= 0 before we can do + // anything in this function. + if ((pEditLinesIndex < 0) || (pTextLineIndex < 0)) + return 0; + // Also, make sure gEditLines[pEditLinesIndex] is valid. + if ((gEditLines[pEditLinesIndex] == null) || (typeof(gEditLines[pEditLinesIndex]) == "undefined")) + return 0; + + // This function counts and returns the number of non-whitespace characters + // before the current character. + function countBeforeCurrentChar() + { + var charCount = 0; - for (var i = pTextLineIndex-1; i >= 0; --i) - { - if (!/\s/.test(gEditLines[pEditLinesIndex].text.charAt(i))) - ++charCount; - else - break; - } + for (var i = pTextLineIndex-1; i >= 0; --i) + { + if (!/\s/.test(gEditLines[pEditLinesIndex].text.charAt(i))) + ++charCount; + else + break; + } - return charCount; - } + return charCount; + } - var wordLen = 0; + var wordLen = 0; - // If there are only characters to the left, or if the current - // character is a space, then count before the current character. - if ((pTextLineIndex == gEditLines[pEditLinesIndex].displayLength()) || (gEditLines[pEditLinesIndex].text.charAt(gTextLineIndex) == " ")) - wordLen = countBeforeCurrentChar(); - // If there are charactrs to the left and at the current line index, - // then count to the left only if the current character is not whitespace. - else if (pTextLineIndex == gEditLines[pEditLinesIndex].displayLength()-1) - { - if (!/\s/.test(gEditLines[pEditLinesIndex].text.charAt(pTextLineIndex))) - wordLen = countBeforeCurrentChar() + 1; - } - // If there are characters to the left and right, then count to the left - // and right only if the current character is not whitespace. - else if (pTextLineIndex < gEditLines[pEditLinesIndex].displayLength()-1) - { - if (!/\s/.test(gEditLines[pEditLinesIndex].text.charAt(pTextLineIndex))) - { - // Count non-whitespace characters to the left, and include the current one. - wordLen = countBeforeCurrentChar() + 1; - // Count characters to the right. - for (var i = pTextLineIndex+1; i < gEditLines[pEditLinesIndex].displayLength(); ++i) - { - if (!/\s/.test(gEditLines[pEditLinesIndex].text.charAt(i))) - ++wordLen; - else - break; - } - } - } + // If there are only characters to the left, or if the current + // character is a space, then count before the current character. + if ((pTextLineIndex == gEditLines[pEditLinesIndex].length()) || + (gEditLines[pEditLinesIndex].text.charAt(gTextLineIndex) == " ")) + wordLen = countBeforeCurrentChar(); + // If there are charactrs to the left and at the current line index, + // then count to the left only if the current character is not whitespace. + else if (pTextLineIndex == gEditLines[pEditLinesIndex].length()-1) + { + if (!/\s/.test(gEditLines[pEditLinesIndex].text.charAt(pTextLineIndex))) + wordLen = countBeforeCurrentChar() + 1; + } + // If there are characters to the left and right, then count to the left + // and right only if the current character is not whitespace. + else if (pTextLineIndex < gEditLines[pEditLinesIndex].length()-1) + { + if (!/\s/.test(gEditLines[pEditLinesIndex].text.charAt(pTextLineIndex))) + { + // Count non-whitespace characters to the left, and include the current one. + wordLen = countBeforeCurrentChar() + 1; + // Count characters to the right. + for (var i = pTextLineIndex+1; i < gEditLines[pEditLinesIndex].length(); ++i) + { + if (!/\s/.test(gEditLines[pEditLinesIndex].text.charAt(i))) + ++wordLen; + else + break; + } + } + } - return wordLen; + return wordLen; } // Inserts a string into gEditLines after a given index. @@ -3994,38 +3571,38 @@ function getWordLength(pEditLinesIndex, pTextLineIndex) // (as opposed to above). function insertLineIntoMsg(pInsertLineIndex, pString, pHardNewline, pIsQuoteLine) { - var insertedBelow = false; - - // Create the new text line - var line = new TextLine(); - line.text = pString; - line.hardNewlineEnd = false; - if ((pHardNewline != null) && (typeof(pHardNewline) != "undefined")) - line.hardNewlineEnd = pHardNewline; - if ((pIsQuoteLine != null) && (typeof(pIsQuoteLine) != "undefined")) - line.isQuoteLine = pIsQuoteLine; - - // If the current message line is empty, insert the quote line above - // the current line. Otherwise, insert the quote line below the - // current line. - if (typeof(gEditLines[pInsertLineIndex]) == "undefined") - gEditLines.splice(pInsertLineIndex, 0, line); - // Note: One time, I noticed an error with the following test: - // gEditLines[pInsertLineIndex] has no properties - // Thus, I added the above test to see if the edit line is valid. - else if (gEditLines[pInsertLineIndex].displayLength() == 0) - gEditLines.splice(pInsertLineIndex, 0, line); - else - { - // Insert the quote line below the given line index - gEditLines.splice(pInsertLineIndex + 1, 0, line); - // The current message line should have its hardNewlineEnd set - // true so that the quote line won't get wrapped up. - gEditLines[pInsertLineIndex].hardNewlineEnd = true; - insertedBelow = true; - } + var insertedBelow = false; + + // Create the new text line + var line = new TextLine(); + line.text = pString; + line.hardNewlineEnd = false; + if ((pHardNewline != null) && (typeof(pHardNewline) != "undefined")) + line.hardNewlineEnd = pHardNewline; + if ((pIsQuoteLine != null) && (typeof(pIsQuoteLine) != "undefined")) + line.isQuoteLine = pIsQuoteLine; + + // If the current message line is empty, insert the quote line above + // the current line. Otherwise, insert the quote line below the + // current line. + if (typeof(gEditLines[pInsertLineIndex]) == "undefined") + gEditLines.splice(pInsertLineIndex, 0, line); + // Note: One time, I noticed an error with the following test: + // gEditLines[pInsertLineIndex] has no properties + // Thus, I added the above test to see if the edit line is valid. + else if (gEditLines[pInsertLineIndex].length() == 0) + gEditLines.splice(pInsertLineIndex, 0, line); + else + { + // Insert the quote line below the given line index + gEditLines.splice(pInsertLineIndex + 1, 0, line); + // The current message line should have its hardNewlineEnd set + // true so that the quote line won't get wrapped up. + gEditLines[pInsertLineIndex].hardNewlineEnd = true; + insertedBelow = true; + } - return insertedBelow; + return insertedBelow; } // Prompts the user for a filename on the BBS computer and loads its contents @@ -4041,153 +3618,142 @@ function insertLineIntoMsg(pInsertLineIndex, pString, pHardNewline, pIsQuoteLine // currentWordLength: The length of the current word function importFile(pIsSysop, pCurpos) { - // Create the return object - var retObj = { - x: pCurpos.x, - y: pCurpos.y, - currentWordLength: getWordLength(gEditLinesIndex, gTextLineIndex) - }; + // Create the return object + var retObj = new Object(); + retObj.x = pCurpos.x; + retObj.y = pCurpos.y; + retObj.currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); - // Don't let non-sysops do this. - if (!pIsSysop) - return retObj; + // Don't let non-sysops do this. + if (!pIsSysop) + return retObj; - var loadedAFile = false; - // This loop continues to prompt the user until they enter a valid - // filename or a blank string. - var continueOn = true; - while (continueOn) - { - // Go to the last row on the screen and prompt the user for a filename - var promptText = "\1n\1cFile:\1h"; - var promptTextLen = strip_ctrl(promptText).length; - console.gotoxy(1, console.screen_rows); - console.cleartoeol("\1n"); - console.print(promptText); - var filename = console.getstr(console.screen_columns-promptTextLen-1, K_NOCRLF); - continueOn = (filename != ""); - if (continueOn) - { - filename = file_getcase(filename); - if (filename != undefined) - { - // Open the file and insert its contents into the message. - 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) - { - 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") - { - // 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. And handle - // Synchronet color codes. - do - { - //gConfigSettings.allowColorSelection && colorSelectionAllowedInMsgArea(pMsgAreaName, pSubCode) - // Convert any ANSI colors in the file line to Synchronet - // colors - fileLine = cvtANSIToSyncAndRemoveUnwantedANSI(fileLine); - var substrObj = substrWithSyncColorCodes(fileLine, 0, maxLineLength); - // If color codes are allowed and allowed in the current message area, - // then insert the line as-is. Otherwise, strip control characters - // from the line when inserting it. - if (gConfigSettings.allowColorSelection && colorSelectionAllowedInMsgArea(gMsgAreaName, bbs.cursub_code)) - insertLineIntoMsg(gEditLinesIndex, substrObj.strSub, true, false); - else - insertLineIntoMsg(gEditLinesIndex, strip_ctrl(substrObj.strSub), true, false); - fileLine = fileLine.substr(substrObj.endIdx+1); - ++gEditLinesIndex; - } while (strip_ctrl(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, "", true, false); - ++gEditLinesIndex; - } - } - inFile.close(); + var loadedAFile = false; + // This loop continues to prompt the user until they enter a valid + // filename or a blank string. + var continueOn = true; + while (continueOn) + { + // Go to the last row on the screen and prompt the user for a filename + var promptText = "ncFile:h"; + var promptTextLen = strip_ctrl(promptText).length; + console.gotoxy(1, console.screen_rows); + console.cleartoeol("n"); + console.print(promptText); + var filename = console.getstr(console.screen_columns-promptTextLen-1, K_NOCRLF); + continueOn = (filename != ""); + if (continueOn) + { + filename = file_getcase(filename); + if (filename != undefined) + { + // Open the file and insert its contents into the message. + 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) + { + 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") + { + // 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, "", true, false); + ++gEditLinesIndex; + } + } + inFile.close(); - // If the last text line is blank, then remove it. - if (gEditLines[gEditLinesIndex].displayLength() == 0) - { - gEditLines.splice(gEditLinesIndex, 1); - --gEditLinesIndex; - } + // If the last text line is blank, then remove it. + if (gEditLines[gEditLinesIndex].length() == 0) + { + gEditLines.splice(gEditLinesIndex, 1); + --gEditLinesIndex; + } - loadedAFile = true; - continueOn = false; - } - else // Unable to open the file - writeWithPause(1, console.screen_rows, "\1y\1hUnable to open the file!", ERRORMSG_PAUSE_MS); - } - else // Could not find the correct case for the file (it doesn't exist?) - writeWithPause(1, console.screen_rows, "\1y\1hUnable to locate the file!", ERRORMSG_PAUSE_MS); - } - } + loadedAFile = true; + continueOn = false; + } + else // Unable to open the file + writeWithPause(1, console.screen_rows, "yhUnable to open the file!", ERRORMSG_PAUSE_MS); + } + else // Could not find the correct case for the file (it doesn't exist?) + writeWithPause(1, console.screen_rows, "yhUnable to locate the file!", ERRORMSG_PAUSE_MS); + } + } - // Refresh the help line on the bottom of the screen - fpDisplayBottomHelpLine(console.screen_rows, gUseQuotes); + // 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) - { - // Insert a blank line into gEditLines so that the user ends up on a new - // blank line. - // Figure out the index to start at in gEditLines - var startIndex = 0; - if (gEditLines.length > gEditHeight) - startIndex = gEditLines.length - gEditHeight; - // Refresh the message on the screen - displayEditLines(gEditTop, startIndex, gEditBottom, true, true); - - // Set up the edit lines & text line index for the last line, and - // place the cursor at the beginning of the last edit line. - // If the last line is short enough, place the cursor at the end - // of it. Otherwise, append a new line and place the cursor there. - if (gEditLines[gEditLinesIndex].displayLength() < gEditWidth-1) - { - gEditLinesIndex = gEditLines.length - 1; - gTextLineIndex = gEditLines[gEditLinesIndex].text.length; - retObj.x = gEditLeft + gEditLines[gEditLinesIndex].displayLength(); - retObj.y = gEditBottom; - if (gEditLines.length < gEditHeight) - retObj.y = gEditTop + gEditLines.length - 1; - retObj.currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); - } - else - { - // Append a new line and place the cursor there - gEditLines.push(new TextLine()); - gEditLinesIndex = gEditLines.length - 1; - gTextLineIndex = 0; - retObj.x = gEditLeft; - retObj.y = gEditBottom; - if (gEditLines.length < gEditHeight) - retObj.y = gEditTop + gEditLines.length - 1; - retObj.currentWordLength = 0; - } - } + // If we loaded a file, then refresh the message text. + if (loadedAFile) + { + // Insert a blank line into gEditLines so that the user ends up on a new + // blank line. + //displayEditLines(pScreenLine, pArrayIndex, pEndScreenRow, pClearRemainingScreenRows) + // Figure out the index to start at in gEditLines + var startIndex = 0; + if (gEditLines.length > gEditHeight) + startIndex = gEditLines.length - gEditHeight; + // Refresh the message on the screen + displayEditLines(gEditTop, startIndex, gEditBottom, true, true); + + // Set up the edit lines & text line index for the last line, and + // place the cursor at the beginning of the last edit line. + // If the last line is short enough, place the cursor at the end + // of it. Otherwise, append a new line and place the cursor there. + if (gEditLines[gEditLinesIndex].length() < gEditWidth-1) + { + gEditLinesIndex = gEditLines.length - 1; + gTextLineIndex = gEditLines[gEditLinesIndex].length(); + retObj.x = gEditLeft + gTextLineIndex; + retObj.y = gEditBottom; + if (gEditLines.length < gEditHeight) + retObj.y = gEditTop + gEditLines.length - 1; + retObj.currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); + } + else + { + // Append a new line and place the cursor there + gEditLines.push(new TextLine()); + gEditLinesIndex = gEditLines.length - 1; + gTextLineIndex = 0; + retObj.x = gEditLeft; + retObj.y = gEditBottom; + if (gEditLines.length < gEditHeight) + retObj.y = gEditTop + gEditLines.length - 1; + retObj.currentWordLength = 0; + } + } - // Make sure the cursor is where it's supposed to be. - console.gotoxy(retObj.x, retObj.y); + // Make sure the cursor is where it's supposed to be. + console.gotoxy(retObj.x, retObj.y); - return retObj; + return retObj; } // This function lets sysops export (save) the current message to @@ -4197,42 +3763,42 @@ function importFile(pIsSysop, pCurpos) // pIsSysop: Whether or not the user is the sysop function exportToFile(pIsSysop) { - // Don't let non-sysops do this. - if (!pIsSysop) - return; + // Don't let non-sysops do this. + if (!pIsSysop) + return; - // Go to the last row on the screen and prompt the user for a filename - var promptText = "\1n\1cFile:\1h"; - var promptTextLen = strip_ctrl(promptText).length; - console.gotoxy(1, console.screen_rows); - console.cleartoeol("\1n"); - console.print(promptText); - var filename = console.getstr(console.screen_columns-promptTextLen-1, K_NOCRLF); - if (filename != "") - { - var outFile = new File(filename); - if (outFile.open("w")) - { - const lastLineIndex = gEditLines.length - 1; - for (var i = 0; i < gEditLines.length; ++i) - { - // Use writeln to write all lines with CRLF except the last line. - if (i < lastLineIndex) - outFile.writeln(gEditLines[i].text); - else - outFile.write(gEditLines[i].text); - } - outFile.close(); - writeWithPause(1, console.screen_rows, "\1m\1hMessage exported.", ERRORMSG_PAUSE_MS); - } - else // Could not open the file for writing - writeWithPause(1, console.screen_rows, "\1y\1hUnable to open the file for writing!", ERRORMSG_PAUSE_MS); - } - else // No filename specified - writeWithPause(1, console.screen_rows, "\1m\1hMessage not exported.", ERRORMSG_PAUSE_MS); + // Go to the last row on the screen and prompt the user for a filename + var promptText = "ncFile:h"; + var promptTextLen = strip_ctrl(promptText).length; + console.gotoxy(1, console.screen_rows); + console.cleartoeol("n"); + console.print(promptText); + var filename = console.getstr(console.screen_columns-promptTextLen-1, K_NOCRLF); + if (filename != "") + { + var outFile = new File(filename); + if (outFile.open("w")) + { + const lastLineIndex = gEditLines.length - 1; + for (var i = 0; i < gEditLines.length; ++i) + { + // Use writeln to write all lines with CRLF except the last line. + if (i < lastLineIndex) + outFile.writeln(gEditLines[i].text); + else + outFile.write(gEditLines[i].text); + } + outFile.close(); + writeWithPause(1, console.screen_rows, "mhMessage exported.", ERRORMSG_PAUSE_MS); + } + else // Could not open the file for writing + writeWithPause(1, console.screen_rows, "yhUnable to open the file for writing!", ERRORMSG_PAUSE_MS); + } + else // No filename specified + writeWithPause(1, console.screen_rows, "mhMessage not exported.", ERRORMSG_PAUSE_MS); - // Refresh the help line on the bottom of the screen - fpDisplayBottomHelpLine(console.screen_rows, gUseQuotes); + // Refresh the help line on the bottom of the screen + fpDisplayBottomHelpLine(console.screen_rows, gUseQuotes); } // Performs a text search. @@ -4245,135 +3811,135 @@ function exportToFile(pIsSysop) // y: The vertical component of the cursor position function findText(pCurpos) { - // Create the return object. - var returnObj = new Object(); - returnObj.x = pCurpos.x; - returnObj.y = pCurpos.y; - - // This function makes use of the following "static" variables: - // lastSearchText: The text searched for last - // searchStartIndex: The starting index for gEditLines that should - // be used for the search - if (typeof(findText.lastSearchText) == "undefined") - findText.lastSearchText = ""; - if (typeof(findText.searchStartIndex) == "undefined") - findText.searchStartIndex = 0; - - // Go to the last row on the screen and prompt the user for text to find - var promptText = "ncText:h"; - var promptTextLen = strip_ctrl(promptText).length; - console.gotoxy(1, console.screen_rows); - console.cleartoeol("n"); - console.print(promptText); - var searchText = console.getstr(console.screen_columns-promptTextLen-1, K_NOCRLF); - - // If the user's search is text is different from last time, then set the - // starting gEditLines index to 0. Also, update the last search text. - if (searchText != findText.lastSearchText) - findText.searchStartIndex = 0; - findText.lastSearchText = searchText; - - // Search for the text. - var caseSensitive = false; // Case-sensitive search? - var textIndex = 0; // The index of the text in the edit lines - if (searchText.length > 0) - { - // editLinesTopIndex is the index of the line currently displayed - // at the top of the edit area, and also the line to be displayed - // at the top of the edit area. - var editLinesTopIndex = gEditLinesIndex - (pCurpos.y - gEditTop); - - // Look for the text in gEditLines - var textFound = false; - for (var i = findText.searchStartIndex; i < gEditLines.length; ++i) - { - if (caseSensitive) - textIndex = gEditLines[i].text.indexOf(searchText); - else - textIndex = gEditLines[i].text.toUpperCase().indexOf(searchText.toUpperCase()); - // If the text was found in this line, then highlight it and - // exit the search loop. - if (textIndex > -1) - { - gTextLineIndex = textIndex; - textFound = true; - - // If the line is above or below the edit area, then we'll need - // to refresh the edit lines on the screen. We also need to set - // the cursor position to the proper place. - returnObj.x = gEditLeft + gTextLineIndex; - var refresh = false; - if (i < editLinesTopIndex) - { - // The line is above the edit area. - refresh = true; - returnObj.y = gEditTop; - editLinesTopIndex = i; - } - else if (i >= editLinesTopIndex + gEditHeight) - { - // The line is below the edit area. - refresh = true; - returnObj.y = gEditBottom; - editLinesTopIndex = i - gEditHeight + 1; - } - else - { - // The line is inside the edit area. - returnObj.y = pCurpos.y + (i - gEditLinesIndex); - } + // Create the return object. + var returnObj = new Object(); + returnObj.x = pCurpos.x; + returnObj.y = pCurpos.y; + + // This function makes use of the following "static" variables: + // lastSearchText: The text searched for last + // searchStartIndex: The starting index for gEditLines that should + // be used for the search + if (typeof(findText.lastSearchText) == "undefined") + findText.lastSearchText = ""; + if (typeof(findText.searchStartIndex) == "undefined") + findText.searchStartIndex = 0; + + // Go to the last row on the screen and prompt the user for text to find + var promptText = "ncText:h"; + var promptTextLen = strip_ctrl(promptText).length; + console.gotoxy(1, console.screen_rows); + console.cleartoeol("n"); + console.print(promptText); + var searchText = console.getstr(console.screen_columns-promptTextLen-1, K_NOCRLF); + + // If the user's search is text is different from last time, then set the + // starting gEditLines index to 0. Also, update the last search text. + if (searchText != findText.lastSearchText) + findText.searchStartIndex = 0; + findText.lastSearchText = searchText; + + // Search for the text. + var caseSensitive = false; // Case-sensitive search? + var textIndex = 0; // The index of the text in the edit lines + if (searchText.length > 0) + { + // editLinesTopIndex is the index of the line currently displayed + // at the top of the edit area, and also the line to be displayed + // at the top of the edit area. + var editLinesTopIndex = gEditLinesIndex - (pCurpos.y - gEditTop); + + // Look for the text in gEditLines + var textFound = false; + for (var i = findText.searchStartIndex; i < gEditLines.length; ++i) + { + if (caseSensitive) + textIndex = gEditLines[i].text.indexOf(searchText); + else + textIndex = gEditLines[i].text.toUpperCase().indexOf(searchText.toUpperCase()); + // If the text was found in this line, then highlight it and + // exit the search loop. + if (textIndex > -1) + { + gTextLineIndex = textIndex; + textFound = true; + + // If the line is above or below the edit area, then we'll need + // to refresh the edit lines on the screen. We also need to set + // the cursor position to the proper place. + returnObj.x = gEditLeft + gTextLineIndex; + var refresh = false; + if (i < editLinesTopIndex) + { + // The line is above the edit area. + refresh = true; + returnObj.y = gEditTop; + editLinesTopIndex = i; + } + else if (i >= editLinesTopIndex + gEditHeight) + { + // The line is below the edit area. + refresh = true; + returnObj.y = gEditBottom; + editLinesTopIndex = i - gEditHeight + 1; + } + else + { + // The line is inside the edit area. + returnObj.y = pCurpos.y + (i - gEditLinesIndex); + } - gEditLinesIndex = i; + gEditLinesIndex = i; - if (refresh) - displayEditLines(gEditTop, editLinesTopIndex, gEditBottom, true, true); + if (refresh) + displayEditLines(gEditTop, editLinesTopIndex, gEditBottom, true, true); - // Highlight the found text on the line by briefly displaying it in a - // different color. - var highlightText = gEditLines[i].text.substr(textIndex, searchText.length); - console.gotoxy(returnObj.x, returnObj.y); - console.print("\1n\1k\1" + "4" + highlightText); - mswait(1500); - console.gotoxy(returnObj.x, returnObj.y); - //console.print(gTextAttrs + highlightText); - console.print(chooseEditColor() + highlightText); + // Highlight the found text on the line by briefly displaying it in a + // different color. + var highlightText = gEditLines[i].text.substr(textIndex, searchText.length); + console.gotoxy(returnObj.x, returnObj.y); + console.print("nk4" + highlightText); + mswait(1500); + console.gotoxy(returnObj.x, returnObj.y); + //console.print(gTextAttrs + highlightText); + console.print(chooseEditColor() + highlightText); - // The next time the user searches with the same text, we'll want - // to start searching at the next line. Wrap around if necessary. - findText.searchStartIndex = i + 1; - if (findText.searchStartIndex >= gEditLines.length) - findText.searchStartIndex = 0; + // The next time the user searches with the same text, we'll want + // to start searching at the next line. Wrap around if necessary. + findText.searchStartIndex = i + 1; + if (findText.searchStartIndex >= gEditLines.length) + findText.searchStartIndex = 0; - break; - } - } + break; + } + } - // If the text wasn't found, tell the user. Also, make sure searchStartIndex - // is reset to 0. - if (!textFound) - { - console.gotoxy(1, console.screen_rows); - console.cleartoeol("\1n"); - console.print("\1y\1hThe text wasn't found!"); - mswait(ERRORMSG_PAUSE_MS); + // If the text wasn't found, tell the user. Also, make sure searchStartIndex + // is reset to 0. + if (!textFound) + { + console.gotoxy(1, console.screen_rows); + console.cleartoeol("n"); + console.print("yhThe text wasn't found!"); + mswait(ERRORMSG_PAUSE_MS); - findText.searchStartIndex = 0; - } - } + findText.searchStartIndex = 0; + } + } - // Refresh the help line on the bottom of the screen - fpDisplayBottomHelpLine(console.screen_rows, gUseQuotes); + // Refresh the help line on the bottom of the screen + fpDisplayBottomHelpLine(console.screen_rows, gUseQuotes); - // Make sure the cursor is positioned where it should be. - console.gotoxy(returnObj.x, returnObj.y); + // Make sure the cursor is positioned where it should be. + console.gotoxy(returnObj.x, returnObj.y); - return returnObj; + return returnObj; } // Returns whether we're in insert mode (if not, we're in overwrite mode). function inInsertMode() { - return (gInsertMode == "INS"); + return (gInsertMode == "INS"); } // Returns either the normal edit color (gTextAttrs) or the quote line @@ -4381,7 +3947,7 @@ function inInsertMode() // is a normal line or a quote line. function chooseEditColor() { - return ("\1n" + (isQuoteLine(gEditLines, gEditLinesIndex) ? gQuoteLineColor : gTextAttrs)); + return ("n" + (isQuoteLine(gEditLines, gEditLinesIndex) ? gQuoteLineColor : gTextAttrs)); } // This function calculates the row on the screen to stop updating the @@ -4395,14 +3961,14 @@ function chooseEditColor() // message text. function calcBottomUpdateRow(pY, pTopIndex) { - var bottomScreenRow = gEditBottom; - // Note: This is designed to return the screen row # - // below the last message line. To return the exact - // bottommost screen row, subtract 1 from gEditLines.length-pTopIndex. - var bottommost = (pY + (gEditLines.length-pTopIndex)); - if (bottomScreenRow > bottommost) - bottomScreenRow = bottommost; - return bottomScreenRow; + var bottomScreenRow = gEditBottom; + // Note: This is designed to return the screen row # + // below the last message line. To return the exact + // bottommost screen row, subtract 1 from gEditLines.length-pTopIndex. + var bottommost = (pY + (gEditLines.length-pTopIndex)); + if (bottomScreenRow > bottommost) + bottomScreenRow = bottommost; + return bottomScreenRow; } // This function updates the time on the screen and puts @@ -4428,7 +3994,7 @@ function updateTime(pCurpos, pMoveCursorBack) // Display the current time on the screen fpDisplayTime(currentTime); // Make sure the edit color attribute is set. - console.print("\1n" + gTextAttrs); + console.print("n" + gTextAttrs); // Move the cursor back to where it was if (pMoveCursorBack) console.gotoxy(curpos); @@ -4440,6 +4006,7 @@ function updateTime(pCurpos, pMoveCursorBack) // This function lets the user change the text color and is called by doEditLoop(). // // Parameters: +// pTxtAttrs: The current text color & attributes // pCurpos: An object containing x and y values representing the // cursor position. // pCurrentWordLength: The length of the current word that has been typed @@ -4449,72 +4016,66 @@ function updateTime(pCurpos, pMoveCursorBack) // x and y: The horizontal and vertical cursor position // timedOut: Whether or not the user input timed out (boolean) // currentWordLength: The length of the current word -function doColorSelection(pCurpos, pCurrentWordLength) +function doColorSelection(pTxtAttrs, pCurpos, pCurrentWordLength) { - // Create the return object - var retObj = new Object(); - retObj.txtAttrs = ""; - retObj.x = pCurpos.x; - retObj.y = pCurpos.y; - retObj.timedOut = false; - retObj.currentWordLength = pCurrentWordLength; - - const originalScreenY = pCurpos.y; // For screen refreshing - - // Display the 3 rows of color/attribute options and the prompt for the - // user - var colorSelTopLine = console.screen_rows - 2; - var curpos ={ - x: 1, - y: colorSelTopLine - }; - console.gotoxy(curpos); - console.print("ncForeground: whK:nkBlack whR:nrRed whG:ngGreen whY:nyYellow whB:nbBlue whM:nmMagenta whC:ncCyan whW:nwWhite"); - console.cleartoeol("n"); - console.crlf(); - console.print("ncBackground: wh0:n0Blackn wh1:n1Redn wh2:n2kGreenn wh3:3Yellown wh4:n4Bluen wh5:n5Magentan wh6:n6kCyann wh7:n7kWhite"); - console.cleartoeol("n"); - console.crlf(); - console.clearline("n"); - console.print("cSpecial: whH:nhHigh Intensity wI:niBlinking nwhN:nNormal hg� ncChoose colors/attributeshg: c"); - // Get the attribute codes from the user. Ideally, we'd use console.getkeys(), - // but that outputs a CR at the end, which is undesirable. So instead, we call - // getUserInputWithSetOfInputStrs (defined in SlyEdit_Misc.js). - //var key = console.getkeys("KRGYBMCW01234567HIN").toString(); // Outputs a CR.. bad - var validKeys = ["KRGYBMCW", // Foreground color codes - "01234567", // Background color codes - "HIN"]; // Special color codes - var attrCodeKeys = getUserInputWithSetOfInputStrs(K_UPPER|K_NOCRLF|K_NOSPIN, validKeys, gConfigSettings); - // If the user entered some attributes, then set them in retObj.txtAttrs. - if (attrCodeKeys.length > 0) - { - retObj.txtAttrs = ""; - for (var i = 0; i < attrCodeKeys.length; ++i) - retObj.txtAttrs += "\1" + attrCodeKeys.charAt(i); - } + // Create the return object + var retObj = new Object(); + retObj.txtAttrs = pTxtAttrs; + retObj.x = pCurpos.x; + retObj.y = pCurpos.y; + retObj.timedOut = false; + retObj.currentWordLength = pCurrentWordLength; + + const originalScreenY = pCurpos.y; // For screen refreshing + + // Display the 3 rows of color/attribute options and the prompt for the + // user + var colorSelTopLine = console.screen_rows - 2; + var curpos = new Object(); + curpos.x = 1; + curpos.y = colorSelTopLine; + console.gotoxy(curpos); + console.print("ncForeground: whK:nkBlack whR:nrRed whG:ngGreen whY:nyYellow whB:nbBlue whM:nmMagenta whC:ncCyan whW:nwWhite"); + console.cleartoeol("n"); + console.crlf(); + console.print("ncBackground: wh0:n0Blackn wh1:n1Redn wh2:n2kGreenn wh3:3Yellown wh4:n4Bluen wh5:n5Magentan wh6:n6kCyann wh7:n7kWhite"); + console.cleartoeol("n"); + console.crlf(); + console.clearline("n"); + console.print("cSpecial: whH:nhHigh Intensity wI:niBlinking nwhN:nNormal hg� ncChoose colors/attributeshg: c"); + // Get the attribute codes from the user. Ideally, we'd use console.getkeys(), + // but that outputs a CR at the end, which is undesirable. So instead, we call + // getUserInputWithSetOfInputStrs (defined in SlyEdit_Misc.js). + //var key = console.getkeys("KRGYBMCW01234567HIN").toString(); // Outputs a CR.. bad + var validKeys = ["KRGYBMCW", // Foreground color codes + "01234567", // Background color codes + "HIN"]; // Special color codes + var attrCodeKeys = getUserInputWithSetOfInputStrs(K_UPPER|K_NOCRLF|K_NOSPIN, validKeys, gConfigSettings); + // If the user entered some attributes, then set them in retObj.txtAttrs. + if (attrCodeKeys.length > 0) + { + retObj.txtAttrs = (attrCodeKeys.charAt(0) == "N" ? "" : "n"); + for (var i = 0; i < attrCodeKeys.length; ++i) + retObj.txtAttrs += "" + attrCodeKeys.charAt(i); + } - // Display the parts of the screen text that we covered up with the - // color selection: Message edit lines, bottom border, and bottom help line. - var screenYDiff = colorSelTopLine - originalScreenY; - displayEditLines(colorSelTopLine, gEditLinesIndex + screenYDiff, gEditBottom, true, true); - fpDisplayTextAreaBottomBorder(gEditBottom+1, gUseQuotes, gEditLeft, gEditRight, - gInsertMode, gConfigSettings.allowColorSelection); - // Before displaying the bottom help line, if in DCT mode, clear the bottom - // line from the 65th character onwards to erase the attributes prompt text - if (EDITOR_STYLE == "DCT") - { - console.gotoxy(65, console.screen_rows); - console.cleartoeol("\1n"); - } - fpDisplayBottomHelpLine(console.screen_rows, gUseQuotes, true); + // Display the parts of the screen text that we covered up with the + // color selection: Message edit lines, bottom border, and bottom help line. + var screenYDiff = colorSelTopLine - originalScreenY; + displayEditLines(colorSelTopLine, gEditLinesIndex + screenYDiff, gEditBottom, true, true); + fpDisplayTextAreaBottomBorder(gEditBottom+1, gUseQuotes, gEditLeft, gEditRight, + gInsertMode, gConfigSettings.allowColorSelection); + fpDisplayBottomHelpLine(console.screen_rows, gUseQuotes); - // Move the cursor to where it should be before returning - console.gotoxy(pCurpos); + // Move the cursor to where it should be before returning + curpos.x = pCurpos.x; + curpos.y = pCurpos.y; + console.gotoxy(curpos); - // Set the settings in the return object, and return it. - retObj.x = pCurpos.x; - retObj.y = pCurpos.y; - return retObj; + // Set the settings in the return object, and return it. + retObj.x = curpos.x; + retObj.y = curpos.y; + return retObj; } // For the cross-posting UI: Draws the initial top border of @@ -4637,436 +4198,432 @@ function displayCrossPostHelp(selBoxUpperLeft, selBoxLowerRight) // quits out of cross-post selection. function doCrossPosting(pOriginalCurpos) { - // If cross-posting is not allowed, then just return. - if (!gCanCrossPost) - return; + // If cross-posting is not allowed, then just return. + if (!gCanCrossPost) + return; - // This function returns the index of the bottommost message group that - // can be displayed on the screen. - // - // Parameters: - // pTopGrpIndex: The index of the topmost message group displayed on screen - // pNumItemsPerPage: The number of items per page - function getBottommostGrpIndex(pTopGrpIndex, pNumItemsPerPage) - { - var bottomGrpIndex = pTopGrpIndex + pNumItemsPerPage - 1; - // If bottomGrpIndex is beyond the last index, then adjust it. - if (bottomGrpIndex >= msg_area.grp_list.length) - bottomGrpIndex = msg_area.grp_list.length - 1; - return bottomGrpIndex; - } + // This function returns the index of the bottommost message group that + // can be displayed on the screen. + // + // Parameters: + // pTopGrpIndex: The index of the topmost message group displayed on screen + // pNumItemsPerPage: The number of items per page + function getBottommostGrpIndex(pTopGrpIndex, pNumItemsPerPage) + { + var bottomGrpIndex = pTopGrpIndex + pNumItemsPerPage - 1; + // If bottomGrpIndex is beyond the last index, then adjust it. + if (bottomGrpIndex >= msg_area.grp_list.length) + bottomGrpIndex = msg_area.grp_list.length - 1; + return bottomGrpIndex; + } - // Re-writes the "Choose group" text in the top border of the selection - // box. For use when returning from the sub-board list. - // - // Parameters: - // pSelBoxUpperLeft: An object containing x and y values for the upper-left - // corner of the selection box - // pSelBoxInnerWidth: The inner width (inside the left & right borders) of the - // selection box - // pGrpIndex: The index of message group tht was chosen - function reWriteInitialTopBorderText(pSelBoxUpperLeft, pSelBoxInnerWidth, pGrpIndex) - { - // Position the cursor after the "Cross-posting: " text in the border and - // write the "Choose group" text - console.gotoxy(pSelBoxUpperLeft.x+17, pSelBoxUpperLeft.y); - console.print("\1n" + gConfigSettings.genColors.listBoxBorderText + "Choose group"); - // Re-write the border characters to overwrite the message group name - grpDesc = msg_area.grp_list[pGrpIndex].description.substr(0, pSelBoxInnerWidth-25); - // Write the updated border character(s) - console.print("\1n" + gConfigSettings.genColors.listBoxBorder + LEFT_T_SINGLE); - if (grpDesc.length > 3) - { - var numChars = grpDesc.length - 3; - for (var i = 0; i < numChars; ++i) - console.print(HORIZONTAL_SINGLE); - } - } + // Re-writes the "Choose group" text in the top border of the selection + // box. For use when returning from the sub-board list. + // + // Parameters: + // pSelBoxUpperLeft: An object containing x and y values for the upper-left + // corner of the selection box + // pSelBoxInnerWidth: The inner width (inside the left & right borders) of the + // selection box + // pGrpIndex: The index of message group tht was chosen + function reWriteInitialTopBorderText(pSelBoxUpperLeft, pSelBoxInnerWidth, pGrpIndex) + { + // Position the cursor after the "Cross-posting: " text in the border and + // write the "Choose group" text + console.gotoxy(pSelBoxUpperLeft.x+17, pSelBoxUpperLeft.y); + console.print("n" + gConfigSettings.genColors.listBoxBorderText + "Choose group"); + // Re-write the border characters to overwrite the message group name + grpDesc = msg_area.grp_list[pGrpIndex].description.substr(0, pSelBoxInnerWidth-25); + // Write the updated border character(s) + console.print("n" + gConfigSettings.genColors.listBoxBorder + LEFT_T_SINGLE); + if (grpDesc.length > 3) + { + var numChars = grpDesc.length - 3; + for (var i = 0; i < numChars; ++i) + console.print(HORIZONTAL_SINGLE); + } + } - // Store the position of the cursor when we started so that we - // can return the cursor back to this position at the end - var origStartingCurpos = null; - if ((pOriginalCurpos != null) && (typeof(pOriginalCurpos) != "undefined")) - origStartingCurpos = pOriginalCurpos; - else - origStartingCurpos = console.getxy(); - - // Construct objects to represent the screen locations of the upper-left - // and lower-right corners of the selection box. Initially, let the box - // borders be 1 character into the edit area on all sides. - var selBoxUpperLeft = { - x: gEditLeft + 3, - y: gEditTop + 1 - }; - var selBoxLowerRight = { - x: gEditRight - 3, - y: gEditBottom - 1 - }; - // Total and inner text width & height of the selection box - var selBoxWidth = selBoxLowerRight.x - selBoxUpperLeft.x + 1; - var selBoxHeight = selBoxLowerRight.y - selBoxUpperLeft.y + 1; - // Don't let the box's height be more than 17 characters. - if (selBoxHeight > 17) - { - selBoxLowerRight.y = selBoxUpperLeft.y + 16; // For a height of 17 characters - selBoxHeight = selBoxLowerRight.y - selBoxUpperLeft.y + 1; - } - // Inner size of the box (for text) - var selBoxInnerWidth = selBoxWidth - 2; - var selBoxInnerHeight = selBoxHeight - 2; - - // Calculate the index of the message line at the top of the edit area, which - // which is where the message area list box will start. We need to store - // this so that we can erase the selection box when the user is done - // selecting a message area. We'll erase the box by re-writing the message - // text. - var editLineIndexAtSelBoxTopRow = gEditLinesIndex - (origStartingCurpos.y-selBoxUpperLeft.y); - - // Variables for keeping track of the message group/area list - var topMsgGrpIndex = 0; // The index of the message group at the top of the list - // Figure out the index of the last message group to appear on the screen. - var bottomMsgGrpIndex = getBottommostGrpIndex(topMsgGrpIndex, selBoxInnerHeight); - var numPages = Math.ceil(msg_area.grp_list.length / selBoxInnerHeight); - var numItemsPerPage = selBoxInnerHeight; - var topIndexForLastPage = (selBoxInnerHeight * numPages) - selBoxInnerHeight; - // msgGrpFieldLen will store the length to use for the message group numbers - // in the list. It should be able to accommodate the highest message group - // number on the system. - var msgGrpFieldLen = msg_area.grp_list.length.toString().length; - - var selectedGrpIndex = 0; // The currently-selected group index - - // Draw the selection box borders - // Top border - drawInitialCrossPostSelBoxTopBorder(selBoxUpperLeft, selBoxWidth, - gConfigSettings.genColors.listBoxBorder, - gConfigSettings.genColors.listBoxBorderText); - // Side borders - console.print(UPPER_RIGHT_SINGLE); - for (var row = selBoxUpperLeft.y+1; row < selBoxLowerRight.y; ++row) - { - console.gotoxy(selBoxUpperLeft.x, row); - console.print(VERTICAL_SINGLE); - console.gotoxy(selBoxLowerRight.x, row); - console.print(VERTICAL_SINGLE); - } - // Bottom border - drawInitialCrossPostSelBoxBottomBorder({ x: selBoxUpperLeft.x, y: selBoxLowerRight.y }, - selBoxWidth, gConfigSettings.genColors.listBoxBorder, - false); - - // Write the message groups - var pageNum = 1; - ListScreenfulOfMsgGrps(topMsgGrpIndex, selectedGrpIndex, selBoxUpperLeft.y+1, - selBoxUpperLeft.x+1, selBoxLowerRight.y-1, selBoxLowerRight.x-1, - msgGrpFieldLen, true); - // Move the cursor to the inner upper-left corner of the selection box - var curpos = { // Current cursor position - x: selBoxUpperLeft.x+1, - y: selBoxUpperLeft.y+1 - }; - console.gotoxy(curpos); + // Store the position of the cursor when we started so that we + // can return the cursor back to this position at the end + var origStartingCurpos = null; + if ((pOriginalCurpos != null) && (typeof(pOriginalCurpos) != "undefined")) + origStartingCurpos = pOriginalCurpos; + else + origStartingCurpos = console.getxy(); + + // Construct objects to represent the screen locations of the upper-left + // and lower-right corners of the selection box. Initially, let the box + // borders be 1 character into the edit area on all sides. + var selBoxUpperLeft = new Object(); + selBoxUpperLeft.x = gEditLeft + 3; + selBoxUpperLeft.y = gEditTop + 1; + var selBoxLowerRight = new Object(); + selBoxLowerRight.x = gEditRight - 3; + selBoxLowerRight.y = gEditBottom - 1; + // Total and inner text width & height of the selection box + var selBoxWidth = selBoxLowerRight.x - selBoxUpperLeft.x + 1; + var selBoxHeight = selBoxLowerRight.y - selBoxUpperLeft.y + 1; + // Don't let the box's height be more than 17 characters. + if (selBoxHeight > 17) + { + selBoxLowerRight.y = selBoxUpperLeft.y + 16; // For a height of 17 characters + selBoxHeight = selBoxLowerRight.y - selBoxUpperLeft.y + 1; + } + // Inner size of the box (for text) + var selBoxInnerWidth = selBoxWidth - 2; + var selBoxInnerHeight = selBoxHeight - 2; - // User input loop - var userInput = null; - var continueChoosingMsgAreaName = true; - while (continueChoosingMsgAreaName) - { - pageNum = calcPageNum(topMsgGrpIndex, selBoxInnerHeight); + // Calculate the index of the message line at the top of the edit area, which + // which is where the message area list box will start. We need to store + // this so that we can erase the selection box when the user is done + // selecting a message area. We'll erase the box by re-writing the message + // text. + var editLineIndexAtSelBoxTopRow = gEditLinesIndex - (origStartingCurpos.y-selBoxUpperLeft.y); - // Get a key from the user (upper-case) and take action based upon it. - userInput = getKeyWithESCChars(K_UPPER|K_NOCRLF|K_NOSPIN, gConfigSettings); - switch (userInput) - { - case KEY_UP: // Move up one message group in the list - if (selectedGrpIndex > 0) - { - // If the previous group index is on the previous page, then - // display the previous page. - var previousGrpIndex = selectedGrpIndex - 1; - if (previousGrpIndex < topMsgGrpIndex) - { - // Adjust topMsgGrpIndex and bottomMsgGrpIndex, and - // refresh the list on the screen. - topMsgGrpIndex -= numItemsPerPage; - bottomMsgGrpIndex = getBottommostGrpIndex(topMsgGrpIndex, numItemsPerPage); - ListScreenfulOfMsgGrps(topMsgGrpIndex, previousGrpIndex, selBoxUpperLeft.y+1, - selBoxUpperLeft.x+1, selBoxLowerRight.y-1, selBoxLowerRight.x-1, - msgGrpFieldLen, true); - // We'll want to move the cursor to the leftmost character - // of the selected line. - curpos.x = selBoxUpperLeft.x+1; - curpos.y = selBoxUpperLeft.y+selBoxInnerHeight; - } - else - { - // Display the current line un-highlighted - console.gotoxy(selBoxUpperLeft.x+1, curpos.y); - writeMsgGroupLine(selectedGrpIndex, selBoxInnerWidth, msgGrpFieldLen, false); - // Display the previous line highlighted - curpos.x = selBoxUpperLeft.x+1; - --curpos.y; - console.gotoxy(curpos); - writeMsgGroupLine(previousGrpIndex, selBoxInnerWidth, msgGrpFieldLen, true); - } - selectedGrpIndex = previousGrpIndex; - console.gotoxy(curpos); // Move the cursor into place where it should be - } - break; - case KEY_DOWN: // Move down one message group in the list - if (selectedGrpIndex < msg_area.grp_list.length - 1) - { - // If the next group index is on the next page, then display - // the next page. - var nextGrpIndex = selectedGrpIndex + 1; - if (nextGrpIndex > bottomMsgGrpIndex) - { - // Adjust topMsgGrpIndex and bottomMsgGrpIndex, and - // refresh the list on the screen. - topMsgGrpIndex += numItemsPerPage; - bottomMsgGrpIndex = getBottommostGrpIndex(topMsgGrpIndex, numItemsPerPage); - ListScreenfulOfMsgGrps(topMsgGrpIndex, nextGrpIndex, selBoxUpperLeft.y+1, - selBoxUpperLeft.x+1, selBoxLowerRight.y-1, selBoxLowerRight.x-1, - msgGrpFieldLen, true); - // We'll want to move the cursor to the leftmost character - // of the selected line. - curpos.x = selBoxUpperLeft.x+1; - curpos.y = selBoxUpperLeft.y+1; - } - else - { - // Display the current line un-highlighted - console.gotoxy(selBoxUpperLeft.x+1, curpos.y); - writeMsgGroupLine(selectedGrpIndex, selBoxInnerWidth, msgGrpFieldLen, false); - // Display the next line highlighted - curpos.x = selBoxUpperLeft.x+1; - ++curpos.y; - console.gotoxy(curpos); - writeMsgGroupLine(nextGrpIndex, selBoxInnerWidth, msgGrpFieldLen, true); - } - selectedGrpIndex = nextGrpIndex; - console.gotoxy(curpos); // Move the cursor into place where it should be - } - break; - case KEY_HOME: // Go to the top message group on the screen - if (selectedGrpIndex > topMsgGrpIndex) - { - // Display the current line un-highlighted, adjust - // selectedGrpIndex, then display the new line - // highlighted. - console.gotoxy(selBoxUpperLeft.x+1, curpos.y); - writeMsgGroupLine(selectedGrpIndex, selBoxInnerWidth, msgGrpFieldLen, false); - selectedGrpIndex = topMsgGrpIndex; - curpos = { x: selBoxUpperLeft.x+1, y: selBoxUpperLeft.y+1 }; - console.gotoxy(curpos); - writeMsgGroupLine(selectedGrpIndex, selBoxInnerWidth, msgGrpFieldLen, true); - console.gotoxy(curpos); - } - break; - case KEY_END: // Go to the bottom message group on the screen - if (selectedGrpIndex < bottomMsgGrpIndex) - { - // Display the current line un-highlighted, adjust - // selectedGrpIndex, then display the new line - // highlighted. - console.gotoxy(selBoxUpperLeft.x+1, curpos.y); - writeMsgGroupLine(selectedGrpIndex, selBoxInnerWidth, msgGrpFieldLen, false); - selectedGrpIndex = bottomMsgGrpIndex; - curpos.x = selBoxUpperLeft.x + 1; - curpos.y = selBoxUpperLeft.y + (bottomMsgGrpIndex-topMsgGrpIndex+1); - console.gotoxy(curpos); - writeMsgGroupLine(selectedGrpIndex, selBoxInnerWidth, msgGrpFieldLen, true); - console.gotoxy(curpos); - } - break; - case KEY_PAGE_DOWN: // Go to the next page - var nextPageTopIndex = topMsgGrpIndex + numItemsPerPage; - if (nextPageTopIndex < msg_area.grp_list.length) - { - // Adjust topMsgGrpIndex and bottomMsgGrpIndex, and - // refresh the list on the screen. - topMsgGrpIndex = nextPageTopIndex; - pageNum = calcPageNum(topMsgGrpIndex, numItemsPerPage); - bottomMsgGrpIndex = getBottommostGrpIndex(topMsgGrpIndex, numItemsPerPage); - selectedGrpIndex = topMsgGrpIndex; - ListScreenfulOfMsgGrps(topMsgGrpIndex, selectedGrpIndex, selBoxUpperLeft.y+1, - selBoxUpperLeft.x+1, selBoxLowerRight.y-1, selBoxLowerRight.x-1, - msgGrpFieldLen, true); - // Put the cursor at the beginning of the topmost row of message groups - curpos = { x: selBoxUpperLeft.x+1, y: selBoxUpperLeft.y+1 }; - console.gotoxy(curpos); - } - break; - case KEY_PAGE_UP: // Go to the previous page - var prevPageTopIndex = topMsgGrpIndex - numItemsPerPage; - if (prevPageTopIndex >= 0) - { - // Adjust topMsgGrpIndex and bottomMsgGrpIndex, and - // refresh the list on the screen. - topMsgGrpIndex = prevPageTopIndex; - pageNum = calcPageNum(topMsgGrpIndex, numItemsPerPage); - bottomMsgGrpIndex = getBottommostGrpIndex(topMsgGrpIndex, numItemsPerPage); - selectedGrpIndex = topMsgGrpIndex; - ListScreenfulOfMsgGrps(topMsgGrpIndex, selectedGrpIndex, selBoxUpperLeft.y+1, - selBoxUpperLeft.x+1, selBoxLowerRight.y-1, selBoxLowerRight.x-1, - msgGrpFieldLen, true); - // Put the cursor at the beginning of the topmost row of message groups - curpos = { x: selBoxUpperLeft.x+1, y: selBoxUpperLeft.y+1 }; - console.gotoxy(curpos); - } - break; - case 'F': // Go to the first page - if (topMsgGrpIndex > 0) - { - topMsgGrpIndex = 0; - pageNum = calcPageNum(topMsgGrpIndex, numItemsPerPage); - bottomMsgGrpIndex = getBottommostGrpIndex(topMsgGrpIndex, numItemsPerPage); - selectedGrpIndex = 0; - ListScreenfulOfMsgGrps(topMsgGrpIndex, selectedGrpIndex, selBoxUpperLeft.y+1, - selBoxUpperLeft.x+1, selBoxLowerRight.y-1, selBoxLowerRight.x-1, - msgGrpFieldLen, true); - // Put the cursor at the beginning of the topmost row of message groups - curpos = { x: selBoxUpperLeft.x+1, y: selBoxUpperLeft.y+1 }; - console.gotoxy(curpos); - } - break; - case 'L': // Go to the last page - if (topMsgGrpIndex < topIndexForLastPage) - { - topMsgGrpIndex = topIndexForLastPage; - pageNum = calcPageNum(topMsgGrpIndex, numItemsPerPage); - bottomMsgGrpIndex = getBottommostGrpIndex(topMsgGrpIndex, numItemsPerPage); - selectedGrpIndex = topIndexForLastPage; - ListScreenfulOfMsgGrps(topMsgGrpIndex, selectedGrpIndex, selBoxUpperLeft.y+1, - selBoxUpperLeft.x+1, selBoxLowerRight.y-1, selBoxLowerRight.x-1, - msgGrpFieldLen, true); - // Put the cursor at the beginning of the topmost row of message groups - curpos = { x: selBoxUpperLeft.x+1, y: selBoxUpperLeft.y+1 }; - console.gotoxy(curpos); - } - break; - case CTRL_C: // Quit (Ctrl-C is the cross-post hotkey) - case KEY_ESC: // Quit - case "Q": // Quit - continueChoosingMsgAreaName = false; - break; - case KEY_ENTER: // Select the currently-highlighted message group - // Store the current cursor position for later, then show the - // sub-boards in the chosen message group and let the user - // toggle ones for cross-posting. - var selectCurrentGrp_originalCurpos = curpos; - var selectMsgAreaRetObj = crossPosting_selectSubBoardInGrp(selectedGrpIndex, - selBoxUpperLeft, selBoxLowerRight, selBoxWidth, - selBoxHeight, selBoxInnerWidth, selBoxInnerHeight); - // If the user toggled some sub-boards... - if (selectMsgAreaRetObj.subBoardsToggled) - { - // TODO: Does anything need to be done here? - } + // Variables for keeping track of the message group/area list + var topMsgGrpIndex = 0; // The index of the message group at the top of the list + // Figure out the index of the last message group to appear on the screen. + var bottomMsgGrpIndex = getBottommostGrpIndex(topMsgGrpIndex, selBoxInnerHeight); + var numPages = Math.ceil(msg_area.grp_list.length / selBoxInnerHeight); + var numItemsPerPage = selBoxInnerHeight; + var topIndexForLastPage = (selBoxInnerHeight * numPages) - selBoxInnerHeight; + // msgGrpFieldLen will store the length to use for the message group numbers + // in the list. It should be able to accommodate the highest message group + // number on the system. + var msgGrpFieldLen = msg_area.grp_list.length.toString().length; + + var selectedGrpIndex = 0; // The currently-selected group index + + // Draw the selection box borders + // Top border + drawInitialCrossPostSelBoxTopBorder(selBoxUpperLeft, selBoxWidth, + gConfigSettings.genColors.listBoxBorder, + gConfigSettings.genColors.listBoxBorderText); + // Side borders + console.print(UPPER_RIGHT_SINGLE); + for (var row = selBoxUpperLeft.y+1; row < selBoxLowerRight.y; ++row) + { + console.gotoxy(selBoxUpperLeft.x, row); + console.print(VERTICAL_SINGLE); + console.gotoxy(selBoxLowerRight.x, row); + console.print(VERTICAL_SINGLE); + } + // Bottom border + drawInitialCrossPostSelBoxBottomBorder({ x: selBoxUpperLeft.x, y: selBoxLowerRight.y }, + selBoxWidth, gConfigSettings.genColors.listBoxBorder, + false); + + // Write the message groups + var pageNum = 1; + ListScreenfulOfMsgGrps(topMsgGrpIndex, selectedGrpIndex, selBoxUpperLeft.y+1, + selBoxUpperLeft.x+1, selBoxLowerRight.y-1, selBoxLowerRight.x-1, + msgGrpFieldLen, true); + // Move the cursor to the inner upper-left corner of the selection box + var curpos = new Object(); // Current cursor position + curpos.x = selBoxUpperLeft.x+1; + curpos.y = selBoxUpperLeft.y+1; + console.gotoxy(curpos); + + // User input loop + var userInput = null; + var continueChoosingMsgArea = true; + while (continueChoosingMsgArea) + { + pageNum = calcPageNum(topMsgGrpIndex, selBoxInnerHeight); + + // Get a key from the user (upper-case) and take action based upon it. + userInput = getKeyWithESCChars(K_UPPER|K_NOCRLF|K_NOSPIN, gConfigSettings); + switch (userInput) + { + case KEY_UP: // Move up one message group in the list + if (selectedGrpIndex > 0) + { + // If the previous group index is on the previous page, then + // display the previous page. + var previousGrpIndex = selectedGrpIndex - 1; + if (previousGrpIndex < topMsgGrpIndex) + { + // Adjust topMsgGrpIndex and bottomMsgGrpIndex, and + // refresh the list on the screen. + topMsgGrpIndex -= numItemsPerPage; + bottomMsgGrpIndex = getBottommostGrpIndex(topMsgGrpIndex, numItemsPerPage); + ListScreenfulOfMsgGrps(topMsgGrpIndex, previousGrpIndex, selBoxUpperLeft.y+1, + selBoxUpperLeft.x+1, selBoxLowerRight.y-1, selBoxLowerRight.x-1, + msgGrpFieldLen, true); + // We'll want to move the cursor to the leftmost character + // of the selected line. + curpos.x = selBoxUpperLeft.x+1; + curpos.y = selBoxUpperLeft.y+selBoxInnerHeight; + } + else + { + // Display the current line un-highlighted + console.gotoxy(selBoxUpperLeft.x+1, curpos.y); + writeMsgGroupLine(selectedGrpIndex, selBoxInnerWidth, msgGrpFieldLen, false); + // Display the previous line highlighted + curpos.x = selBoxUpperLeft.x+1; + --curpos.y; + console.gotoxy(curpos); + writeMsgGroupLine(previousGrpIndex, selBoxInnerWidth, msgGrpFieldLen, true); + } + selectedGrpIndex = previousGrpIndex; + console.gotoxy(curpos); // Move the cursor into place where it should be + } + break; + case KEY_DOWN: // Move down one message group in the list + if (selectedGrpIndex < msg_area.grp_list.length - 1) + { + // If the next group index is on the next page, then display + // the next page. + var nextGrpIndex = selectedGrpIndex + 1; + if (nextGrpIndex > bottomMsgGrpIndex) + { + // Adjust topMsgGrpIndex and bottomMsgGrpIndex, and + // refresh the list on the screen. + topMsgGrpIndex += numItemsPerPage; + bottomMsgGrpIndex = getBottommostGrpIndex(topMsgGrpIndex, numItemsPerPage); + ListScreenfulOfMsgGrps(topMsgGrpIndex, nextGrpIndex, selBoxUpperLeft.y+1, + selBoxUpperLeft.x+1, selBoxLowerRight.y-1, selBoxLowerRight.x-1, + msgGrpFieldLen, true); + // We'll want to move the cursor to the leftmost character + // of the selected line. + curpos.x = selBoxUpperLeft.x+1; + curpos.y = selBoxUpperLeft.y+1; + } + else + { + // Display the current line un-highlighted + console.gotoxy(selBoxUpperLeft.x+1, curpos.y); + writeMsgGroupLine(selectedGrpIndex, selBoxInnerWidth, msgGrpFieldLen, false); + // Display the next line highlighted + curpos.x = selBoxUpperLeft.x+1; + ++curpos.y; + console.gotoxy(curpos); + writeMsgGroupLine(nextGrpIndex, selBoxInnerWidth, msgGrpFieldLen, true); + } + selectedGrpIndex = nextGrpIndex; + console.gotoxy(curpos); // Move the cursor into place where it should be + } + break; + case KEY_HOME: // Go to the top message group on the screen + if (selectedGrpIndex > topMsgGrpIndex) + { + // Display the current line un-highlighted, adjust + // selectedGrpIndex, then display the new line + // highlighted. + console.gotoxy(selBoxUpperLeft.x+1, curpos.y); + writeMsgGroupLine(selectedGrpIndex, selBoxInnerWidth, msgGrpFieldLen, false); + selectedGrpIndex = topMsgGrpIndex; + curpos = { x: selBoxUpperLeft.x+1, y: selBoxUpperLeft.y+1 }; + console.gotoxy(curpos); + writeMsgGroupLine(selectedGrpIndex, selBoxInnerWidth, msgGrpFieldLen, true); + console.gotoxy(curpos); + } + break; + case KEY_END: // Go to the bottom message group on the screen + if (selectedGrpIndex < bottomMsgGrpIndex) + { + // Display the current line un-highlighted, adjust + // selectedGrpIndex, then display the new line + // highlighted. + console.gotoxy(selBoxUpperLeft.x+1, curpos.y); + writeMsgGroupLine(selectedGrpIndex, selBoxInnerWidth, msgGrpFieldLen, false); + selectedGrpIndex = bottomMsgGrpIndex; + curpos.x = selBoxUpperLeft.x + 1; + curpos.y = selBoxUpperLeft.y + (bottomMsgGrpIndex-topMsgGrpIndex+1); + console.gotoxy(curpos); + writeMsgGroupLine(selectedGrpIndex, selBoxInnerWidth, msgGrpFieldLen, true); + console.gotoxy(curpos); + } + break; + case KEY_PAGE_DOWN: // Go to the next page + var nextPageTopIndex = topMsgGrpIndex + numItemsPerPage; + if (nextPageTopIndex < msg_area.grp_list.length) + { + // Adjust topMsgGrpIndex and bottomMsgGrpIndex, and + // refresh the list on the screen. + topMsgGrpIndex = nextPageTopIndex; + pageNum = calcPageNum(topMsgGrpIndex, numItemsPerPage); + bottomMsgGrpIndex = getBottommostGrpIndex(topMsgGrpIndex, numItemsPerPage); + selectedGrpIndex = topMsgGrpIndex; + ListScreenfulOfMsgGrps(topMsgGrpIndex, selectedGrpIndex, selBoxUpperLeft.y+1, + selBoxUpperLeft.x+1, selBoxLowerRight.y-1, selBoxLowerRight.x-1, + msgGrpFieldLen, true); + // Put the cursor at the beginning of the topmost row of message groups + curpos = { x: selBoxUpperLeft.x+1, y: selBoxUpperLeft.y+1 }; + console.gotoxy(curpos); + } + break; + case KEY_PAGE_UP: // Go to the previous page + var prevPageTopIndex = topMsgGrpIndex - numItemsPerPage; + if (prevPageTopIndex >= 0) + { + // Adjust topMsgGrpIndex and bottomMsgGrpIndex, and + // refresh the list on the screen. + topMsgGrpIndex = prevPageTopIndex; + pageNum = calcPageNum(topMsgGrpIndex, numItemsPerPage); + bottomMsgGrpIndex = getBottommostGrpIndex(topMsgGrpIndex, numItemsPerPage); + selectedGrpIndex = topMsgGrpIndex; + ListScreenfulOfMsgGrps(topMsgGrpIndex, selectedGrpIndex, selBoxUpperLeft.y+1, + selBoxUpperLeft.x+1, selBoxLowerRight.y-1, selBoxLowerRight.x-1, + msgGrpFieldLen, true); + // Put the cursor at the beginning of the topmost row of message groups + curpos = { x: selBoxUpperLeft.x+1, y: selBoxUpperLeft.y+1 }; + console.gotoxy(curpos); + } + break; + case 'F': // Go to the first page + if (topMsgGrpIndex > 0) + { + topMsgGrpIndex = 0; + pageNum = calcPageNum(topMsgGrpIndex, numItemsPerPage); + bottomMsgGrpIndex = getBottommostGrpIndex(topMsgGrpIndex, numItemsPerPage); + selectedGrpIndex = 0; + ListScreenfulOfMsgGrps(topMsgGrpIndex, selectedGrpIndex, selBoxUpperLeft.y+1, + selBoxUpperLeft.x+1, selBoxLowerRight.y-1, selBoxLowerRight.x-1, + msgGrpFieldLen, true); + // Put the cursor at the beginning of the topmost row of message groups + curpos = { x: selBoxUpperLeft.x+1, y: selBoxUpperLeft.y+1 }; + console.gotoxy(curpos); + } + break; + case 'L': // Go to the last page + if (topMsgGrpIndex < topIndexForLastPage) + { + topMsgGrpIndex = topIndexForLastPage; + pageNum = calcPageNum(topMsgGrpIndex, numItemsPerPage); + bottomMsgGrpIndex = getBottommostGrpIndex(topMsgGrpIndex, numItemsPerPage); + selectedGrpIndex = topIndexForLastPage; + ListScreenfulOfMsgGrps(topMsgGrpIndex, selectedGrpIndex, selBoxUpperLeft.y+1, + selBoxUpperLeft.x+1, selBoxLowerRight.y-1, selBoxLowerRight.x-1, + msgGrpFieldLen, true); + // Put the cursor at the beginning of the topmost row of message groups + curpos = { x: selBoxUpperLeft.x+1, y: selBoxUpperLeft.y+1 }; + console.gotoxy(curpos); + } + break; + case CTRL_C: // Quit (Ctrl-C is the cross-post hotkey) + case KEY_ESC: // Quit + case "Q": // Quit + continueChoosingMsgArea = false; + break; + case KEY_ENTER: // Select the currently-highlighted message group + // Store the current cursor position for later, then show the + // sub-boards in the chosen message group and let the user + // toggle ones for cross-posting. + var selectCurrentGrp_originalCurpos = curpos; + var selectMsgAreaRetObj = crossPosting_selectSubBoardInGrp(selectedGrpIndex, + selBoxUpperLeft, selBoxLowerRight, selBoxWidth, + selBoxHeight, selBoxInnerWidth, selBoxInnerHeight); + // If the user toggled some sub-boards... + if (selectMsgAreaRetObj.subBoardsToggled) + { + // TODO: Does anything need to be done here? + } - // Update the Enter action text in the bottom border to say "Select" - // (instead of "Toggle"). - console.gotoxy(selBoxUpperLeft.x+41, selBoxLowerRight.y); - console.print("\1n\1h\1bSelect"); - // Refresh the top border of the selection box, refresh the list of - // message groups in the box, and move the cursor back to its original - // position. - reWriteInitialTopBorderText(selBoxUpperLeft, selBoxInnerWidth, selectedGrpIndex); - ListScreenfulOfMsgGrps(topMsgGrpIndex, selectedGrpIndex, selBoxUpperLeft.y+1, - selBoxUpperLeft.x+1, selBoxLowerRight.y-1, - selBoxLowerRight.x-1, msgGrpFieldLen, true); - console.gotoxy(selectCurrentGrp_originalCurpos); - break; - case '?': // Display cross-post help - displayCrossPostHelp(selBoxUpperLeft, selBoxLowerRight); - console.gotoxy(selBoxUpperLeft.x+1, selBoxLowerRight.y-1); - console.pause(); - ListScreenfulOfMsgGrps(topMsgGrpIndex, selectedGrpIndex, selBoxUpperLeft.y+1, - selBoxUpperLeft.x+1, selBoxLowerRight.y-1, - selBoxLowerRight.x-1, msgGrpFieldLen, true); - console.gotoxy(curpos); - break; - default: - // If the user entered a numeric digit, then treat it as - // the start of the message group number. - if (userInput.match(/[0-9]/)) - { - var originalCurpos = curpos; - // Put the user's input back in the input buffer to - // be used for getting the rest of the message number. - console.ungetstr(userInput); - // We want to write the prompt text only if the first digit entered - // by the user is an ambiguous message group number (i.e., if - // the first digit is 2 and there's a message group # 2 and 20). - var writePromptText = (msg_area.grp_list.length >= +userInput * 10); - if (writePromptText) - { - console.gotoxy(selBoxUpperLeft.x+1, selBoxLowerRight.y); - printf("\1n\1cChoose group #:%" + +(selBoxInnerWidth-15) + "s", ""); - console.gotoxy(selBoxUpperLeft.x+17, selBoxLowerRight.y); - console.print("\1h"); - } - else - console.gotoxy(selBoxUpperLeft.x+1, selBoxLowerRight.y); - userInput = console.getnum(msg_area.grp_list.length); + // Update the Enter action text in the bottom border to say "Select" + // (instead of "Toggle"). + console.gotoxy(selBoxUpperLeft.x+41, selBoxLowerRight.y); + console.print("nhbSelect"); + // Refresh the top border of the selection box, refresh the list of + // message groups in the box, and move the cursor back to its original + // position. + reWriteInitialTopBorderText(selBoxUpperLeft, selBoxInnerWidth, selectedGrpIndex); + ListScreenfulOfMsgGrps(topMsgGrpIndex, selectedGrpIndex, selBoxUpperLeft.y+1, + selBoxUpperLeft.x+1, selBoxLowerRight.y-1, + selBoxLowerRight.x-1, msgGrpFieldLen, true); + console.gotoxy(selectCurrentGrp_originalCurpos); + break; + case '?': // Display cross-post help + displayCrossPostHelp(selBoxUpperLeft, selBoxLowerRight); + console.gotoxy(selBoxUpperLeft.x+1, selBoxLowerRight.y-1); + console.pause(); + ListScreenfulOfMsgGrps(topMsgGrpIndex, selectedGrpIndex, selBoxUpperLeft.y+1, + selBoxUpperLeft.x+1, selBoxLowerRight.y-1, + selBoxLowerRight.x-1, msgGrpFieldLen, true); + console.gotoxy(curpos); + break; + default: + // If the user entered a numeric digit, then treat it as + // the start of the message group number. + if (userInput.match(/[0-9]/)) + { + var originalCurpos = curpos; + // Put the user's input back in the input buffer to + // be used for getting the rest of the message number. + console.ungetstr(userInput); + // We want to write the prompt text only if the first digit entered + // by the user is an ambiguous message group number (i.e., if + // the first digit is 2 and there's a message group # 2 and 20). + var writePromptText = (msg_area.grp_list.length >= +userInput * 10); + if (writePromptText) + { + console.gotoxy(selBoxUpperLeft.x+1, selBoxLowerRight.y); + printf("ncChoose group #:%" + +(selBoxInnerWidth-15) + "s", ""); + console.gotoxy(selBoxUpperLeft.x+17, selBoxLowerRight.y); + console.print("h"); + } + else + console.gotoxy(selBoxUpperLeft.x+1, selBoxLowerRight.y); + userInput = console.getnum(msg_area.grp_list.length); - // Re-draw the bottom border of the selection box - if (writePromptText) - { - drawInitialCrossPostSelBoxBottomBorder({ x: selBoxUpperLeft.x, y: selBoxLowerRight.y }, - selBoxWidth, gConfigSettings.genColors.listBoxBorder, - false); - } - else - { - console.gotoxy(selBoxUpperLeft.x+1, selBoxLowerRight.y); - console.print(gConfigSettings.genColors.listBoxBorder + RIGHT_T_SINGLE); - } + // Re-draw the bottom border of the selection box + if (writePromptText) + { + drawInitialCrossPostSelBoxBottomBorder({ x: selBoxUpperLeft.x, y: selBoxLowerRight.y }, + selBoxWidth, gConfigSettings.genColors.listBoxBorder, + false); + } + else + { + console.gotoxy(selBoxUpperLeft.x+1, selBoxLowerRight.y); + console.print(gConfigSettings.genColors.listBoxBorder + RIGHT_T_SINGLE); + } - // If the user made a selection, then let them choose a - // sub-board from the group. - if (userInput > 0) - { - // Show the sub-boards in the chosen message group and - // let the user toggle ones for cross-posting. - // userInput-1 is the group index - var chosenGrpIndex = userInput - 1; - var selectMsgAreaRetObj = crossPosting_selectSubBoardInGrp(chosenGrpIndex, - selBoxUpperLeft, selBoxLowerRight, selBoxWidth, - selBoxHeight, selBoxInnerWidth, selBoxInnerHeight); - // If the user chose a sub-board, then set bbs.curgrp and - // bbs.cursub, and don't continue the input loop anymore. - if (selectMsgAreaRetObj.subBoardsToggled) - { - // TODO: Does anything need to be done here? - } - // Update the Enter action text in the bottom border to say "Select" - // (instead of "Toggle"). - console.gotoxy(selBoxUpperLeft.x+41, selBoxLowerRight.y); - console.print("\1n\1h\1bSelect"); - // Refresh the top border of the selection box - reWriteInitialTopBorderText(selBoxUpperLeft, selBoxInnerWidth, chosenGrpIndex); - } + // If the user made a selection, then let them choose a + // sub-board from the group. + if (userInput > 0) + { + // Show the sub-boards in the chosen message group and + // let the user toggle ones for cross-posting. + // userInput-1 is the group index + var chosenGrpIndex = userInput - 1; + var selectMsgAreaRetObj = crossPosting_selectSubBoardInGrp(chosenGrpIndex, + selBoxUpperLeft, selBoxLowerRight, selBoxWidth, + selBoxHeight, selBoxInnerWidth, selBoxInnerHeight); + // If the user chose a sub-board, then set bbs.curgrp and + // bbs.cursub, and don't continue the input loop anymore. + if (selectMsgAreaRetObj.subBoardsToggled) + { + // TODO: Does anything need to be done here? + } + // Update the Enter action text in the bottom border to say "Select" + // (instead of "Toggle"). + console.gotoxy(selBoxUpperLeft.x+41, selBoxLowerRight.y); + console.print("nhbSelect"); + // Refresh the top border of the selection box + reWriteInitialTopBorderText(selBoxUpperLeft, selBoxInnerWidth, chosenGrpIndex); + } - // Refresh the list of message groups in the box and move the - // cursor back to its original position. - ListScreenfulOfMsgGrps(topMsgGrpIndex, selectedGrpIndex, selBoxUpperLeft.y+1, - selBoxUpperLeft.x+1, selBoxLowerRight.y-1, - selBoxLowerRight.x-1, msgGrpFieldLen, true); - console.gotoxy(originalCurpos); - } - break; - } - } + // Refresh the list of message groups in the box and move the + // cursor back to its original position. + ListScreenfulOfMsgGrps(topMsgGrpIndex, selectedGrpIndex, selBoxUpperLeft.y+1, + selBoxUpperLeft.x+1, selBoxLowerRight.y-1, + selBoxLowerRight.x-1, msgGrpFieldLen, true); + console.gotoxy(originalCurpos); + } + break; + } + } - // We're done selecting message areas for cross-posting. - // Erase the message area selection rectangle by re-drawing the message text. - // Then, move the cursor back to where it was when we started the message - // area selection. - displayMessageRectangle(selBoxUpperLeft.x, selBoxUpperLeft.y, selBoxWidth, - selBoxHeight, editLineIndexAtSelBoxTopRow, true); - console.gotoxy(origStartingCurpos); - console.print(chooseEditColor()); + // We're done selecting message areas for cross-posting. + // Erase the message area selection rectangle by re-drawing the message text. + // Then, move the cursor back to where it was when we started the message + // area selection. + displayMessageRectangle(selBoxUpperLeft.x, selBoxUpperLeft.y, selBoxWidth, + selBoxHeight, editLineIndexAtSelBoxTopRow, true); + console.gotoxy(origStartingCurpos); } // Displays a screenful of message groups, for the cross-posting // interface. @@ -5186,7 +4743,7 @@ function writeMsgGroupLine(pGrpIndex, pTextWidth, pMsgGrpFieldLen, pHighlight) } // Write the message group information line - var markChar = (pGrpIndex == gMsgAreaNameInfo.grpIndex ? "*" : " "); + var markChar = (pGrpIndex == gMsgAreaInfo.grpIndex ? "*" : " "); printf(printfStr, markChar, +(pGrpIndex+1), msg_area.grp_list[pGrpIndex].description.substr(0, grpDescLen)); } // For cross-posting: Lets the user choose a sub-board within a message group @@ -5785,7 +5342,7 @@ function writeMsgSubLine(pGrpIndex, pSubIndex, pTextWidth, pSubNumFieldLen, pHig // Put together the printf format string var msgSubDescLen = pTextWidth - pSubNumFieldLen - 2; - var printfStr = "\1n"; + var printfStr = "n"; if (pHighlight) { printfStr += gConfigSettings.genColors.crossPostChkHighlight + "%1s" @@ -5808,284 +5365,287 @@ function writeMsgSubLine(pGrpIndex, pSubIndex, pTextWidth, pSubNumFieldLen, pHig // Writes a line in the edit lines array // // Parameters: -// pEditLineIdx: Integer - The index of the line to write. Required. +// pIndex: Integer - The index of the line to write. Required. +// pUseColors: Boolean - Whether or not to use the line's colors. +// Optional. If omitted, the colors will be used. // pStart: Integer - The index in the line of where to start. // Optional. If omitted, 0 will be used. // pLength: Integer - The length to write. Optional. If // omitted, the entire line will be written. <= 0 can be // passed to write the entire string. // -// Return value: The actual length of text written as appearing on the screen -function printEditLine(pEditLineIdx, pStart, pLength) +// Return value: The actual length of text written +function printEditLine(pIndex, pUseColors, pStart, pLength) { - if (typeof(pEditLineIdx) != "number") - return 0; - var start = (typeof(pStart) == "number" ? pStart : 0); - var length = (typeof(pLength) == "number" ? pLength : -1); - // Validation of variable values - if (pEditLineIdx < 0) - pEditLineIdx = 0; - else if (pEditLineIdx >= gEditLines.length) - { - // Before returning, write spaces for the length specified so - // that the screen is updated correctly - printf("\1n%" + length + "s", ""); - return length; - } - if (start < 0) - start = 0; - else if (start >= gEditLines[pEditLineIdx].text.length) - { - // Before returning, write spaces for the length specified so - // that the screen is updated correctly - printf("\1n%" + length + "s", ""); - return length; - } - //if (length > (gEditLines[pEditLineIdx].text.length - start)) - // length = gEditLines[pEditLineIdx].text.length - start; - - if (gEditLines[pEditLineIdx].isQuoteLine) - console.print("\1n" + gQuoteLineColor); - - var lengthWritten = 0; - // Cases where the start index is at the beginning of the line - if (start == 0) - { - // Simplest case: start is 0 and length is negative - - // Just print the entire line. - if (length <= 0) - { - console.print(gEditLines[pEditLineIdx].text); - lengthWritten = strip_ctrl(gEditLines[pEditLineIdx].text).length; - } - else - { - var textToWrite = gEditLines[pEditLineIdx].substrWithSyncColorCodes(start, length).strSub; - if (gEditLines[pEditLineIdx].isQuoteLine) - console.print(strip_ctrl(textToWrite)); - else - console.print(textToWrite); - lengthWritten = strip_ctrl(textToWrite).length; - } - } - else - { - // Start is > 0 - var textToWrite = ""; - if (length <= 0) - textToWrite = gEditLines[pEditLineIdx].substrWithSyncColorCodes(start).strSub; - else - textToWrite = gEditLines[pEditLineIdx].substrWithSyncColorCodes(start, length).strSub; - if (gEditLines[pEditLineIdx].isQuoteLine) - console.print(strip_ctrl(textToWrite)); - else - { - var firstAttrCodes = gEditLines[pEditLineIdx].getLastAttrCodes(start); - console.print(firstAttrCodes + textToWrite); - } - lengthWritten = strip_ctrl(textToWrite).length; - } + if (typeof(pIndex) != "number") + return 0; + var useColors = true; + var start = 0; + var length = -1; + if (typeof(pUseColors) == "boolean") + useColors = pUseColors; + if (typeof(pStart) == "number") + start = pStart; + if (typeof(pLength) == "number") + length = pLength; + // Validation of variable values + if (pIndex < 0) + pIndex = 0; + else if (pIndex >= gEditLines.length) + { + // Before returning, write spaces for the length specified so + // that the screen is updated correctly + for (var i = 0; i < length; ++i) + console.print(" "); + return length; + } + if (start < 0) + start = 0; + else if (start >= gEditLines[pIndex].text.length) + { + // Before returning, write spaces for the length specified so + // that the screen is updated correctly + for (var i = 0; i < length; ++i) + console.print(" "); + return length; + } + //if (length > (gEditLines[pIndex].text.length - start)) + // length = gEditLines[pIndex].text.length - start; - return lengthWritten; + var lengthWritten = 0; + if (useColors) + { + } + else + { + // Don't use the line colors + // Cases where the start index is at the beginning of the line + if (start == 0) + { + // Simplest case: start is 0 and length is negative - + // Just print the entire line. + lengthWritten = gEditLines[pIndex].text.length; + if (length <= 0) + console.print(gEditLines[pIndex].text); + else + { + var textToWrite = gEditLines[pIndex].text.substr(start, length); + console.print(textToWrite); + lengthWritten = textToWrite.length; + } + } + else + { + // Start is > 0 + var textToWrite = ""; + if (length <= 0) + textToWrite = gEditLines[pIndex].text.substr(start); + else + textToWrite = gEditLines[pIndex].text.substr(start, length); + console.print(textToWrite); + lengthWritten = textToWrite.length; + } + } + return lengthWritten; } // Lists the text replacements configured in SlyEdit using a scrollable list box. function listTextReplacements() { - if (gNumTxtReplacements == 0) - { - var originalCurpos = console.getxy(); - writeMsgOntBtmHelpLineWithPause("\1n\1h\1yThere are no text replacements.", ERRORMSG_PAUSE_MS); - console.print(chooseEditColor()); // Make sure the edit color is correct - console.gotoxy(originalCurpos); - return; - } + if (gNumTxtReplacements == 0) + { + var originalCurpos = console.getxy(); + writeMsgOntBtmHelpLineWithPause("nhyThere are no text replacements.", ERRORMSG_PAUSE_MS); + console.print(chooseEditColor()); // Make sure the edit color is correct + console.gotoxy(originalCurpos); + return; + } - // Calculate the text width for each column, which will then be used to - // calculate the width of the box. For the width of the box, we need to - // subtract at least 3 from the edit area with to accomodate the box's side - // borders and the space between the text columns. - var txtWidth = Math.floor((gEditWidth - 10)/2); - - // In order to be able to navigate forward and backwards through the text - // replacements, we need to copy them into an array, since gTxtReplacements - // is an object and not navigable both ways. This will also allow us to easily - // know how many text replacements there are (using the .length property of - // the array). - // For speed, create this only once. - if (typeof(listTextReplacements.txtReplacementArr) == "undefined") - { - var txtReplacementObj = null; - listTextReplacements.txtReplacementArr = new Array(); - for (var prop in gTxtReplacements) - { - txtReplacementObj = new Object(); - txtReplacementObj.originalText = prop; - txtReplacementObj.replacement = gTxtReplacements[prop]; - listTextReplacements.txtReplacementArr.push(txtReplacementObj); - } - } + // Calculate the text width for each column, which will then be used to + // calculate the width of the box. For the width of the box, we need to + // subtract at least 3 from the edit area with to accomodate the box's side + // borders and the space between the text columns. + var txtWidth = Math.floor((gEditWidth - 10)/2); + + // In order to be able to navigate forward and backwards through the text + // replacements, we need to copy them into an array, since gTxtReplacements + // is an object and not navigable both ways. This will also allow us to easily + // know how many text replacements there are (using the .length property of + // the array). + // For speed, create this only once. + if (typeof(listTextReplacements.txtReplacementArr) == "undefined") + { + var txtReplacementObj = null; + listTextReplacements.txtReplacementArr = new Array(); + for (var prop in gTxtReplacements) + { + txtReplacementObj = new Object(); + txtReplacementObj.originalText = prop; + txtReplacementObj.replacement = gTxtReplacements[prop]; + listTextReplacements.txtReplacementArr.push(txtReplacementObj); + } + } - // We'll want to have an object with the box dimensions. - var boxInfo = new Object(); + // We'll want to have an object with the box dimensions. + var boxInfo = new Object(); - // Construct the top & bottom border strings if they don't exist already. - if (typeof(listTextReplacements.topBorder) == "undefined") - { - listTextReplacements.topBorder = "\1n" + gConfigSettings.genColors.listBoxBorder - + UPPER_LEFT_SINGLE + "\1n" + gConfigSettings.genColors.listBoxBorderText + "Text" - + "\1n" + gConfigSettings.genColors.listBoxBorder; - for (var i = 0; i < (txtWidth-3); ++i) - listTextReplacements.topBorder += HORIZONTAL_SINGLE; - listTextReplacements.topBorder += "\1n" + gConfigSettings.genColors.listBoxBorderText - + "Replacement" + "\1n" + gConfigSettings.genColors.listBoxBorder; - for (var i = 0; i < (txtWidth-11); ++i) - listTextReplacements.topBorder += HORIZONTAL_SINGLE; - listTextReplacements.topBorder += UPPER_RIGHT_SINGLE; - } - boxInfo.width = strip_ctrl(listTextReplacements.topBorder).length; - if (typeof(listTextReplacements.bottomBorder) == "undefined") - { - var numReplacementsStr = "Total: " + listTextReplacements.txtReplacementArr.length; - listTextReplacements.bottomBorder = "\1n" + gConfigSettings.genColors.listBoxBorder - + LOWER_LEFT_SINGLE + "\1n" + gConfigSettings.genColors.listBoxBorderText - + UP_ARROW + ", " + DOWN_ARROW + ", ESC/Ctrl-T/C=Close" + "\1n" - + gConfigSettings.genColors.listBoxBorder; - var maxNumChars = boxInfo.width - numReplacementsStr.length - 28; - for (var i = 0; i < maxNumChars; ++i) - listTextReplacements.bottomBorder += HORIZONTAL_SINGLE; - listTextReplacements.bottomBorder += RIGHT_T_SINGLE + "\1n" - + gConfigSettings.genColors.listBoxBorderText + numReplacementsStr + "\1n" - + gConfigSettings.genColors.listBoxBorder + LEFT_T_SINGLE; - listTextReplacements.bottomBorder += LOWER_RIGHT_SINGLE; - } - // printf format strings for the list - if (typeof(listTextReplacements.listFormatStr) == "undefined") - { - listTextReplacements.listFormatStr = "\1n" + gConfigSettings.genColors.listBoxItemText - + "%-" + txtWidth + "s %-" + txtWidth + "s"; - } - if (typeof(listTextReplacements.listFormatStrNormalAttr) == "undefined") - listTextReplacements.listFormatStrNormalAttr = "\1n%-" + txtWidth + "s %-" + txtWidth + "s"; - - // Limit the box height to up to 12 lines. - boxInfo.height = gNumTxtReplacements + 2; - if (boxInfo.height > 12) - boxInfo.height = 12; - boxInfo.topLeftX = gEditLeft + Math.floor((gEditWidth/2) - (boxInfo.width/2)); - boxInfo.topLeftY = gEditTop + Math.floor((gEditHeight/2) - (boxInfo.height/2)); - - // Draw the top & bottom box borders for the list of text replacements - var originalCurpos = console.getxy(); - console.gotoxy(boxInfo.topLeftX, boxInfo.topLeftY); - console.print(listTextReplacements.topBorder); - console.gotoxy(boxInfo.topLeftX, boxInfo.topLeftY+boxInfo.height-1); - console.print(listTextReplacements.bottomBorder); - // Draw the side borders - console.print("\1n" + gConfigSettings.genColors.listBoxBorder); - for (var i = 0; i < boxInfo.height-2; ++i) - { - console.gotoxy(boxInfo.topLeftX, boxInfo.topLeftY+i+1); - console.print(VERTICAL_SINGLE); - console.gotoxy(boxInfo.topLeftX+boxInfo.width-1, boxInfo.topLeftY+i+1); - console.print(VERTICAL_SINGLE); - } + // Construct the top & bottom border strings if they don't exist already. + if (typeof(listTextReplacements.topBorder) == "undefined") + { + listTextReplacements.topBorder = "n" + gConfigSettings.genColors.listBoxBorder + + UPPER_LEFT_SINGLE + "n" + gConfigSettings.genColors.listBoxBorderText + "Text" + + "n" + gConfigSettings.genColors.listBoxBorder; + for (var i = 0; i < (txtWidth-3); ++i) + listTextReplacements.topBorder += HORIZONTAL_SINGLE; + listTextReplacements.topBorder += "n" + gConfigSettings.genColors.listBoxBorderText + + "Replacement" + "n" + gConfigSettings.genColors.listBoxBorder; + for (var i = 0; i < (txtWidth-11); ++i) + listTextReplacements.topBorder += HORIZONTAL_SINGLE; + listTextReplacements.topBorder += UPPER_RIGHT_SINGLE; + } + boxInfo.width = strip_ctrl(listTextReplacements.topBorder).length; + if (typeof(listTextReplacements.bottomBorder) == "undefined") + { + var numReplacementsStr = "Total: " + listTextReplacements.txtReplacementArr.length; + listTextReplacements.bottomBorder = "n" + gConfigSettings.genColors.listBoxBorder + + LOWER_LEFT_SINGLE + "n" + gConfigSettings.genColors.listBoxBorderText + + UP_ARROW + ", " + DOWN_ARROW + ", ESC/Ctrl-T/C=Close" + "n" + + gConfigSettings.genColors.listBoxBorder; + var maxNumChars = boxInfo.width - numReplacementsStr.length - 28; + for (var i = 0; i < maxNumChars; ++i) + listTextReplacements.bottomBorder += HORIZONTAL_SINGLE; + listTextReplacements.bottomBorder += RIGHT_T_SINGLE + "n" + + gConfigSettings.genColors.listBoxBorderText + numReplacementsStr + "n" + + gConfigSettings.genColors.listBoxBorder + LEFT_T_SINGLE; + listTextReplacements.bottomBorder += LOWER_RIGHT_SINGLE; + } + // printf format strings for the list + if (typeof(listTextReplacements.listFormatStr) == "undefined") + { + listTextReplacements.listFormatStr = "n" + gConfigSettings.genColors.listBoxItemText + + "%-" + txtWidth + "s %-" + txtWidth + "s"; + } + if (typeof(listTextReplacements.listFormatStrNormalAttr) == "undefined") + listTextReplacements.listFormatStrNormalAttr = "n%-" + txtWidth + "s %-" + txtWidth + "s"; + + // Limit the box height to up to 12 lines. + boxInfo.height = gNumTxtReplacements + 2; + if (boxInfo.height > 12) + boxInfo.height = 12; + boxInfo.topLeftX = gEditLeft + Math.floor((gEditWidth/2) - (boxInfo.width/2)); + boxInfo.topLeftY = gEditTop + Math.floor((gEditHeight/2) - (boxInfo.height/2)); + + // Draw the top & bottom box borders for the list of text replacements + var originalCurpos = console.getxy(); + console.gotoxy(boxInfo.topLeftX, boxInfo.topLeftY); + console.print(listTextReplacements.topBorder); + console.gotoxy(boxInfo.topLeftX, boxInfo.topLeftY+boxInfo.height-1); + console.print(listTextReplacements.bottomBorder); + // Draw the side borders + console.print("n" + gConfigSettings.genColors.listBoxBorder); + for (var i = 0; i < boxInfo.height-2; ++i) + { + console.gotoxy(boxInfo.topLeftX, boxInfo.topLeftY+i+1); + console.print(VERTICAL_SINGLE); + console.gotoxy(boxInfo.topLeftX+boxInfo.width-1, boxInfo.topLeftY+i+1); + console.print(VERTICAL_SINGLE); + } - // Set up some variables for the user input loop - const numItemsPerPage = boxInfo.height - 2; - const numPages = Math.ceil(listTextReplacements.txtReplacementArr.length / numItemsPerPage); - // For the horizontal location of the page number text for the box border: - // Based on the fact that there can be up to 9999 text replacements and 10 - // per page, there will be up to 1000 pages of replacements. To write the - // text, we'll want to be 20 characters to the left of the end of the border - // of the box. - const pageNumTxtStartX = boxInfo.topLeftX + boxInfo.width - 20; - var pageNum = 0; - var startArrIndex = 0; - var endArrIndex = 0; // One past the last array item - var screenY = 0; - // User input loop (also drawing the list of items) - var continueOn = true; - var refreshList = true; // For screen redraw optimizations - while (continueOn) - { - if (refreshList) - { - // Write the list of items for the current page - startArrIndex = pageNum * numItemsPerPage; - endArrIndex = startArrIndex + numItemsPerPage; - if (endArrIndex > listTextReplacements.txtReplacementArr.length) - endArrIndex = listTextReplacements.txtReplacementArr.length; - screenY = boxInfo.topLeftY + 1; - for (var i = startArrIndex; i < endArrIndex; ++i) - { - console.gotoxy(boxInfo.topLeftX+1, screenY); - printf(listTextReplacements.listFormatStr, - listTextReplacements.txtReplacementArr[i].originalText.substr(0, txtWidth), - listTextReplacements.txtReplacementArr[i].replacement.substr(0, txtWidth)); - ++screenY; - } - // If the current screen row is below the bottom row inside the box, - // continue and write blank lines to the bottom of the inside of the box - // to blank out any text that might still be there. - while (screenY < boxInfo.topLeftY+boxInfo.height-1) - { - console.gotoxy(boxInfo.topLeftX+1, screenY); - printf(listTextReplacements.listFormatStrNormalAttr, "", ""); - ++screenY; - } + // Set up some variables for the user input loop + const numItemsPerPage = boxInfo.height - 2; + const numPages = Math.ceil(listTextReplacements.txtReplacementArr.length / numItemsPerPage); + // For the horizontal location of the page number text for the box border: + // Based on the fact that there can be up to 9999 text replacements and 10 + // per page, there will be up to 1000 pages of replacements. To write the + // text, we'll want to be 20 characters to the left of the end of the border + // of the box. + const pageNumTxtStartX = boxInfo.topLeftX + boxInfo.width - 20; + var pageNum = 0; + var startArrIndex = 0; + var endArrIndex = 0; // One past the last array item + var screenY = 0; + // User input loop (also drawing the list of items) + var continueOn = true; + var refreshList = true; // For screen redraw optimizations + while (continueOn) + { + if (refreshList) + { + // Write the list of items for the current page + startArrIndex = pageNum * numItemsPerPage; + endArrIndex = startArrIndex + numItemsPerPage; + if (endArrIndex > listTextReplacements.txtReplacementArr.length) + endArrIndex = listTextReplacements.txtReplacementArr.length; + screenY = boxInfo.topLeftY + 1; + for (var i = startArrIndex; i < endArrIndex; ++i) + { + console.gotoxy(boxInfo.topLeftX+1, screenY); + printf(listTextReplacements.listFormatStr, + listTextReplacements.txtReplacementArr[i].originalText.substr(0, txtWidth), + listTextReplacements.txtReplacementArr[i].replacement.substr(0, txtWidth)); + ++screenY; + } + // If the current screen row is below the bottom row inside the box, + // continue and write blank lines to the bottom of the inside of the box + // to blank out any text that might still be there. + while (screenY < boxInfo.topLeftY+boxInfo.height-1) + { + console.gotoxy(boxInfo.topLeftX+1, screenY); + printf(listTextReplacements.listFormatStrNormalAttr, "", ""); + ++screenY; + } - // Update the page number in the top border of the box. - console.gotoxy(pageNumTxtStartX, boxInfo.topLeftY); - console.print("\1n" + gConfigSettings.genColors.listBoxBorder + RIGHT_T_SINGLE); - printf("\1n" + gConfigSettings.genColors.listBoxBorderText + "Page %4d of %4d", pageNum+1, numPages); - console.print("\1n" + gConfigSettings.genColors.listBoxBorder + LEFT_T_SINGLE); + // Update the page number in the top border of the box. + console.gotoxy(pageNumTxtStartX, boxInfo.topLeftY); + console.print("n" + gConfigSettings.genColors.listBoxBorder + RIGHT_T_SINGLE); + printf("n" + gConfigSettings.genColors.listBoxBorderText + "Page %4d of %4d", pageNum+1, numPages); + console.print("n" + gConfigSettings.genColors.listBoxBorder + LEFT_T_SINGLE); - // Just for sane appearance: Move the cursor to the first character of - // the first row and make it the color for the text replacements. - console.gotoxy(boxInfo.topLeftX+1, boxInfo.topLeftY+1); - console.print(gConfigSettings.genColors.listBoxItemText); - } + // Just for sane appearance: Move the cursor to the first character of + // the first row and make it the color for the text replacements. + console.gotoxy(boxInfo.topLeftX+1, boxInfo.topLeftY+1); + console.print(gConfigSettings.genColors.listBoxItemText); + } - // Get a key from the user (upper-case) and take action based upon it. - userInput = getUserKey(K_UPPER|K_NOCRLF|K_NOSPIN, gConfigSettings); - switch (userInput) - { - case KEY_UP: - // Go up one page - refreshList = (pageNum > 0); - if (refreshList) - --pageNum; - break; - case KEY_DOWN: - // Go down one page - refreshList = (pageNum < numPages-1); - if (refreshList) - ++pageNum; - break; - // Quit for ESC, Ctrl-T, Ctrl-A, and 'C' (close). - case KEY_ESC: - case CTRL_T: - case CTRL_A: - case 'C': - refreshList = false; - continueOn = false; - break; - default: - // Unrecognized command. Don't refresh the list of the screen. - refreshList = false; - break; - } - } + // Get a key from the user (upper-case) and take action based upon it. + userInput = getUserKey(K_UPPER|K_NOCRLF|K_NOSPIN, gConfigSettings); + switch (userInput) + { + case KEY_UP: + // Go up one page + refreshList = (pageNum > 0); + if (refreshList) + --pageNum; + break; + case KEY_DOWN: + // Go down one page + refreshList = (pageNum < numPages-1); + if (refreshList) + ++pageNum; + break; + // Quit for ESC, Ctrl-T, Ctrl-A, and 'C' (close). + case KEY_ESC: + case CTRL_T: + case CTRL_A: + case 'C': + refreshList = false; + continueOn = false; + break; + default: + // Unrecognized command. Don't refresh the list of the screen. + refreshList = false; + break; + } + } - // We're done listing the text replacements. - // Erase the list box rectangle by re-drawing the message text. Then, move - // the cursor back to where it was originally. - var editLineIndexAtSelBoxTopRow = gEditLinesIndex - (originalCurpos.y-boxInfo.topLeftY); - displayMessageRectangle(boxInfo.topLeftX, boxInfo.topLeftY, boxInfo.width, - boxInfo.height, editLineIndexAtSelBoxTopRow, true); - console.gotoxy(originalCurpos); - console.print(chooseEditColor()); + // We're done listing the text replacements. + // Erase the list box rectangle by re-drawing the message text. Then, move + // the cursor back to where it was originally. + var editLineIndexAtSelBoxTopRow = gEditLinesIndex - (originalCurpos.y-boxInfo.topLeftY); + displayMessageRectangle(boxInfo.topLeftX, boxInfo.topLeftY, boxInfo.width, + boxInfo.height, editLineIndexAtSelBoxTopRow, true); + console.gotoxy(originalCurpos); + console.print(chooseEditColor()); } // Lets the user manage their preferences/settings. @@ -6248,7 +5808,6 @@ function doUserSettings(pCurpos, pReturnCursorToOriginalPos) if (returnCursorWhenDone) console.gotoxy(originalCurpos); - console.print(chooseEditColor()); } // Allows the user to select a tagline. Returns an object with the following @@ -6323,7 +5882,7 @@ function setQuotePrefix() // to ensure we get the correct name in case anything in the message base // changes after this function is first called. if (!setQuotePrefix.curMsgFromName) - setQuotePrefix.curMsgFromName = getFromNameForCurMsg(gMsgAreaNameInfo); + setQuotePrefix.curMsgFromName = getFromNameForCurMsg(gMsgAreaInfo); gQuotePrefix = " > "; // The default quote prefix // If we're configured to use poster's initials in the @@ -6337,7 +5896,7 @@ function setQuotePrefix() // a message sub-board), use the gToName value read from the drop file. // Remove any leading, multiple, or trailing spaces. var quotedName = ""; - if (postingInMsgSubBoard(gMsgAreaName)) + if (postingInMsgSubBoard(gMsgArea)) { quotedName = trimSpaces(setQuotePrefix.curMsgFromName, true, true, true); if (quotedName.length == 0) @@ -6460,229 +6019,4 @@ function getSignName(pSubCode, pRealNameOnlyFirst, pRealNameForEmail) else signName = trimSpaces(user.alias, true, false, true); return signName; -} - -// Prints a text line and fills the remainder of the line -// with spaces using the normal attribute. -// -// Parameters: -// pTextLine: The text line to print -// pColor: The color/attribute code to use -// pIsQuoteLine: Boolean - Whether or not it's a quote line. If true, -// then any attribtes will be stripped and the passed-in -// color (assumed to be the quote line color as applicable) -// will be used. -function printLineAndFillEditWidthRemainder(pTextLine, pColor, pIsQuoteLine) -{ - var lineWithoutCtrlChars = strip_ctrl(pTextLine); - if (pIsQuoteLine) - console.print(pColor + lineWithoutCtrlChars); - else - console.print(pColor + pTextLine); - var printableStrLen = lineWithoutCtrlChars.length; - if (printableStrLen < gEditWidth) - printf("\1n%" + +(gEditWidth - printableStrLen) + "s", ""); -} - -// Returns whether or not text color selection is allowed in a message area. -// -// Parameters: -// pMsgAreaName: The message area (sub-board) name. This is read from the drop -// file and is also in Synchronet's message area data structures. -// This needs to be passed in case the message is being posted as -// email rather than on a sub-board. -// pSubCode: The internal sub-board code of the sub-board being posted on (or -// "mail" for personal email) -// -// Return value: Whether or not color selection is allowed in the current message area -function colorSelectionAllowedInMsgArea(pMsgAreaName, pSubCode) -{ - var colorsAllowed = true; - if (postingInMsgSubBoard(pMsgAreaName)) - { - // First check the current group short name & description in the list of message group names - var curGrpShortNameUpper = msg_area.sub[pSubCode].grp_name.toUpperCase(); - var grpIdx = msg_area.sub[pSubCode].grp_index; - var curGrpDescUpper = msg_area.grp_list[grpIdx].description.toUpperCase(); - for (var i = 0; i < gConfigSettings.noColorSelectionGrpNames.length; ++i) - { - if ((gConfigSettings.noColorSelectionGrpNames[i] == curGrpShortNameUpper) || (gConfigSettings.noColorSelectionGrpNames[i] == curGrpDescUpper)) - { - colorsAllowed = false; - break; - } - } - // If the group name wasn't found, then check the current sub-board code - // in the list of sub-board codes - if (colorsAllowed) - { - var subBoardCodeLower = pSubCode.toLowerCase(); // Should be lower case anyway, but just in case.. - for (var i = 0; i < gConfigSettings.noColorSelectionSubBoardCodes.length; ++i) - { - if (gConfigSettings.noColorSelectionSubBoardCodes[i] == subBoardCodeLower) - { - colorsAllowed = false; - break; - } - } - } - } - return colorsAllowed; -} - -// Returns whether or not color code selection is allowed according to the settings, -// and in the current message area and in the text line. -// -// Parameters: -// pMsgAreaName: The message area (sub-board) name. This is read from the drop -// file and is also in Synchronet's message area data structures. -// This needs to be passed in case the message is being posted as -// email rather than on a sub-board. -// pSubCode: The internal sub-board code of the sub-board being posted on (or -// "mail" for personal email) -// -// Return value: An object with the following properties: -// colorsAllowed: Boolean - Whether or not colors are allowed -// errorMsg: A string containing an error message if colors aren't allowed -function colorSelectionAllowedInSettingsAndLine(pMsgAreaName, pSubCode) -{ - var retObj = { - colorsAllowed: (gConfigSettings.allowColorSelection && colorSelectionAllowedInMsgArea(pMsgAreaName, pSubCode) - && !gEditLines[gEditLinesIndex].isQuoteLine), - errorMsg: "" - }; - if (!retObj.colorsAllowed) - { - if (gEditLines[gEditLinesIndex].isQuoteLine) - retObj.errorMsg = "Can't change quote line colors"; - else - retObj.errorMsg = "Changing colors is not allowed in this message area"; - } - - return retObj; -} - -// Returns whether or not message text colors should be converted to ANSI -// in a message sub-board -// -// Parameters: -// pMsgAreaName: The message area name. This needs to be passed in case -// the message is being posted as internal email and the -// group name isn't available in Sychronet's data structures -// pSubCode: The internal code of the sub-board -// -// Return value: Boolean - Whether or not to convert text colors to ANSI in -// the sub-board -function shouldConvertMsgColorsToANSIInMsgArea(pMsgAreaName, pSubCode) -{ - var convertToANSI = false; - if (postingInMsgSubBoard(pMsgAreaName)) - { - // First check the current group name in the list of message group names - var curGrpShortNameUpper = msg_area.sub[pSubCode].grp_name.toUpperCase(); - var grpIdx = msg_area.sub[pSubCode].grp_index; - var curGrpDescUpper = msg_area.grp_list[grpIdx].description.toUpperCase(); - for (var i = 0; i < gConfigSettings.cvtColorToANSIGrpNames.length; ++i) - { - if ((gConfigSettings.cvtColorToANSIGrpNames[i] == curGrpShortNameUpper) || (gConfigSettings.cvtColorToANSIGrpNames[i] == curGrpDescUpper)) - { - convertToANSI = true; - break; - } - } - // If the group name wasn't found, then check the current sub-board code - // in the list of sub-board codes - if (!convertToANSI) - { - var subBoardCodeLower = pSubCode.toLowerCase(); // Should be lower case anyway, but just in case.. - for (var i = 0; i < gConfigSettings.cvtColorToANSISubBoardCodes.length; ++i) - { - if (gConfigSettings.cvtColorToANSISubBoardCodes[i] == subBoardCodeLower) - { - convertToANSI = true; - break; - } - } - } - } - else - { - // See if the sub-board name (probably "ELECTRONIC MAIL") is in the list - var msgAreaNameUpper = pMsgAreaName.toUpperCase(); - for (var i = 0; (i < gConfigSettings.cvtColorToANSIGrpNames.length) && !convertToANSI; ++i) - convertToANSI = (gConfigSettings.cvtColorToANSIGrpNames[i] == msgAreaNameUpper); - } - return convertToANSI; -} - -// Concatenates all message edit lines together. -// -// Parameters: -// pEditLines: An array of TextLine objects (such as gEditLines, for instance) -// pSigInfo: An object containing the user's signature -// pStripCtrl: Boolean - Whether or not to strip control characters from the text -// -// Return value: A string containing all message text concatenated from pEditLines -function concatMsgEditLines(pEditLines, pSigInfo, pStripCtrl) -{ - var stripCtrlChars = (typeof(pStripCtrl) == "boolean" ? pStripCtrl : false); - var msgText = ""; - // Append each line to msgText. Then, - // - If using Synchronet 3.15 or higher: - // Depending on whether the line has a hard newline - // or a soft newline, append a "\r\n" or a " \n", as - // per Synchronet's standard as of 3.15. - // - Otherwise (Synchronet 3.14 and below): - // Just append a "\r\n" to the line - if (system.version_num >= 31500) - { - var useHardNewline = false; - if (stripCtrlChars) - { - for (var i = 0; i < pEditLines.length; ++i) - { - // Use a hard newline if the current edit line has one or if this is - // the last line of the message. - useHardNewline = (pEditLines[i].hardNewlineEnd || (i == pEditLines.length-1)); - msgText += strip_ctrl(pEditLines[i].text) + (useHardNewline ? "\r\n" : " \n"); - } - } - else // Don't strip control characters - { - for (var i = 0; i < pEditLines.length; ++i) - { - // Use a hard newline if the current edit line has one or if this is - // the last line of the message. - useHardNewline = (pEditLines[i].hardNewlineEnd || (i == pEditLines.length-1)); - msgText += pEditLines[i].text + (useHardNewline ? "\r\n" : " \n"); - } - } - } - else // Synchronet 3.14 and below - { - if (stripCtrlChars) - { - for (var i = 0; i < pEditLines.length; ++i) - msgText += strip_ctrl(pEditLines[i].text) + "\r\n"; - } - else // Don't strip control characters - { - for (var i = 0; i < pEditLines.length; ++i) - msgText += pEditLines[i].text + "\r\n"; - } - } - - // Read the user's signature, in case they have one - var msgSigInfo = (typeof(pSigInfo) == "object" ? pSigInfo : readUserSigFile()); - // If the user has not chosen to auto-sign messages, then also append their - // signature to the message now. - if (!gUserSettings.autoSignMessages) - { - // Append a blank line to separate the message & signature. - // Note: msgText already has a newline at the end, so - // we don't have to append one here; just append the signature. - if (msgSigInfo.sigContents.length > 0) - msgText += msgSigInfo.sigContents + "\r\n"; - } - return msgText; } \ No newline at end of file diff --git a/exec/SlyEdit_DCTStuff.js b/exec/SlyEdit_DCTStuff.js index fc3478ece6..5b43efa2a1 100644 --- a/exec/SlyEdit_DCTStuff.js +++ b/exec/SlyEdit_DCTStuff.js @@ -12,7 +12,7 @@ * 2009-08-22 Eric Oulashin Version 1.00 * Initial public release * 2009-12-03 Eric Oulashin Added support for color schemes. - * Added readDCTColorConfig(). + * Added readColorConfig(). * 2009-12-31 Eric Oulashin Updated promptYesNo_DCTStyle() * so that the return variable, * userResponse, defaults to the @@ -37,13 +37,13 @@ * of the theme filename, since the path is * now set in ReadSlyEditConfigFile() in * SlyEdit_Misc.js. - * 2013-01-19 Eric Oulashin Updated readDCTColorConfig() to move the + * 2013-01-19 Eric Oulashin Updated readColorConfig() to move the * general color settings to gConfigSettings.genColors.* * 2013-01-24 Eric Oulashin Updated doDCTMenu() to include an option * for cross-posting on the File menu. - * 2013-08-23 Eric Oulashin Updated readDCTColorConfig() with the new general color + * 2013-08-23 Eric Oulashin Updated readColorConfig() with the new general color * configuration settings. - * 2013-08-28 Eric Oulashin Simplified readDCTColorConfig() by having it call + * 2013-08-28 Eric Oulashin Simplified readColorConfig() by having it call * moveGenColorsToGenSettings() (defined in * SlyEdit_Misc.js) to move the general colors * into the genColors array in the configuration @@ -86,7 +86,7 @@ var DCTMENU_CROSS_POST = 12; var DCTMENU_LIST_TXT_REPLACEMENTS = 13; // Read the color configuration file -readDCTColorConfig(gConfigSettings.DCTColors.ThemeFilename); +readColorConfig(gConfigSettings.DCTColors.ThemeFilename); /////////////////////////////////////////////////////////////////////////////////// // Functions @@ -95,16 +95,16 @@ readDCTColorConfig(gConfigSettings.DCTColors.ThemeFilename); // // Parameters: // pFilename: The name of the color configuration file -function readDCTColorConfig(pFilename) +function readColorConfig(pFilename) { - var colors = readValueSettingConfigFile(pFilename, 512, true); - if (colors != null) - { - gConfigSettings.DCTColors = colors; - // Move the general color settings into gConfigSettings.genColors.* - if (EDITOR_STYLE == "DCT") - moveGenColorsToGenSettings(gConfigSettings.DCTColors, gConfigSettings); - } + var colors = readValueSettingConfigFile(pFilename, 512); + if (colors != null) + { + gConfigSettings.DCTColors = colors; + // Move the general color settings into gConfigSettings.genColors.* + if (EDITOR_STYLE == "DCT") + moveGenColorsToGenSettings(gConfigSettings.DCTColors, gConfigSettings); + } } // Re-draws the screen, in the style of DCTEdit. @@ -163,7 +163,7 @@ function redrawScreen_DCTStyle(pEditLeft, pEditRight, pEditTop, pEditBottom, pEd // Message area fieldWidth = (console.screen_columns * (27/80)).toFixed(0); - screenText = gMsgAreaName.substr(0, fieldWidth); + screenText = gMsgArea.substr(0, fieldWidth); var startX = console.screen_columns - fieldWidth - 9; console.gotoxy(startX, lineNum); console.print(gConfigSettings.DCTColors.TopLabelColor + "Area" + @@ -374,64 +374,53 @@ function DisplayTextAreaBottomBorder_DCTStyle(pLineNum, pUseQuotes, pEditLeft, p // Parameters: // pLineNum: The line number on the screen at which to draw the help line // pUsingQuotes: Boolean - Whether or not message quoting is enabled. -// pFillRestOfLine: Optional boolean - Whether or not to fill the rest of the line. -// Defaults to false. -function DisplayBottomHelpLine_DCTStyle(pLineNum, pUsingQuotes, pFillRestOfLine) +function DisplayBottomHelpLine_DCTStyle(pLineNum, pUsingQuotes) { - // For efficiency, define the help line variable only once. - if (typeof(DisplayBottomHelpLine_DCTStyle.helpText) == "undefined") - { - DisplayBottomHelpLine_DCTStyle.helpText = gConfigSettings.DCTColors.BottomHelpBrackets + - "[" + gConfigSettings.DCTColors.BottomHelpKeys + "CTRL" + - gConfigSettings.DCTColors.BottomHelpFill + DOT_CHAR + - gConfigSettings.DCTColors.BottomHelpKeys + "Z" + - gConfigSettings.DCTColors.BottomHelpBrackets + "]\1n " + - gConfigSettings.DCTColors.BottomHelpKeyDesc + "Save\1n " + - gConfigSettings.DCTColors.BottomHelpBrackets + "[" + - gConfigSettings.DCTColors.BottomHelpKeys + "CTRL" + - gConfigSettings.DCTColors.BottomHelpFill + DOT_CHAR + - gConfigSettings.DCTColors.BottomHelpKeys + "A" + - gConfigSettings.DCTColors.BottomHelpBrackets + "]\1n " + - gConfigSettings.DCTColors.BottomHelpKeyDesc + "Abort"; - // If we can allow message quoting, then add a text to show Ctrl-Q for - // quoting. - if (pUsingQuotes) - DisplayBottomHelpLine_DCTStyle.helpText += "\1n " + - gConfigSettings.DCTColors.BottomHelpBrackets + "[" + - gConfigSettings.DCTColors.BottomHelpKeys + "CTRL" + - gConfigSettings.DCTColors.BottomHelpFill + DOT_CHAR + - gConfigSettings.DCTColors.BottomHelpKeys + "Q" + - gConfigSettings.DCTColors.BottomHelpBrackets + "]\1n " + - gConfigSettings.DCTColors.BottomHelpKeyDesc + "Quote"; - DisplayBottomHelpLine_DCTStyle.helpText += "\1n " + - gConfigSettings.DCTColors.BottomHelpBrackets + "[" + - gConfigSettings.DCTColors.BottomHelpKeys + "ESC" + - gConfigSettings.DCTColors.BottomHelpBrackets + "]\1n " + - gConfigSettings.DCTColors.BottomHelpKeyDesc + "Menu"; - // Center the text by padding it in the front with spaces. This is done instead - // of using console.center() because console.center() will output a newline, - // which would not be good on the last line of the screen. - var numSpaces = (console.screen_columns/2).toFixed(0) - - (strip_ctrl(DisplayBottomHelpLine_DCTStyle.helpText).length/2).toFixed(0); - for (var i = 0; i < numSpaces; ++i) - DisplayBottomHelpLine_DCTStyle.helpText = " " + DisplayBottomHelpLine_DCTStyle.helpText; - } + // For efficiency, define the help line variable only once. + if (typeof(DisplayBottomHelpLine_DCTStyle.helpText) == "undefined") + { + DisplayBottomHelpLine_DCTStyle.helpText = gConfigSettings.DCTColors.BottomHelpBrackets + + "[" + gConfigSettings.DCTColors.BottomHelpKeys + "CTRL" + + gConfigSettings.DCTColors.BottomHelpFill + DOT_CHAR + + gConfigSettings.DCTColors.BottomHelpKeys + "Z" + + gConfigSettings.DCTColors.BottomHelpBrackets + "]n " + + gConfigSettings.DCTColors.BottomHelpKeyDesc + "Saven " + + gConfigSettings.DCTColors.BottomHelpBrackets + "[" + + gConfigSettings.DCTColors.BottomHelpKeys + "CTRL" + + gConfigSettings.DCTColors.BottomHelpFill + DOT_CHAR + + gConfigSettings.DCTColors.BottomHelpKeys + "A" + + gConfigSettings.DCTColors.BottomHelpBrackets + "]n " + + gConfigSettings.DCTColors.BottomHelpKeyDesc + "Abort"; + // If we can allow message quoting, then add a text to show Ctrl-Q for + // quoting. + if (pUsingQuotes) + DisplayBottomHelpLine_DCTStyle.helpText += "n " + + gConfigSettings.DCTColors.BottomHelpBrackets + "[" + + gConfigSettings.DCTColors.BottomHelpKeys + "CTRL" + + gConfigSettings.DCTColors.BottomHelpFill + DOT_CHAR + + gConfigSettings.DCTColors.BottomHelpKeys + "Q" + + gConfigSettings.DCTColors.BottomHelpBrackets + "]n " + + gConfigSettings.DCTColors.BottomHelpKeyDesc + "Quote"; + DisplayBottomHelpLine_DCTStyle.helpText += "n " + + gConfigSettings.DCTColors.BottomHelpBrackets + "[" + + gConfigSettings.DCTColors.BottomHelpKeys + "ESC" + + gConfigSettings.DCTColors.BottomHelpBrackets + "]n " + + gConfigSettings.DCTColors.BottomHelpKeyDesc + "Menu"; + // Center the text by padding it in the front with spaces. This is done instead + // of using console.center() because console.center() will output a newline, + // which would not be good on the last line of the screen. + var numSpaces = (console.screen_columns/2).toFixed(0) + - (strip_ctrl(DisplayBottomHelpLine_DCTStyle.helpText).length/2).toFixed(0); + for (var i = 0; i < numSpaces; ++i) + DisplayBottomHelpLine_DCTStyle.helpText = " " + DisplayBottomHelpLine_DCTStyle.helpText; + } - // Display the help line on the screen - var lineNum = console.screen_rows; + // Display the help line on the screen + var lineNum = console.screen_rows; if ((typeof(pLineNum) != "undefined") && (pLineNum != null)) lineNum = pLineNum; - console.gotoxy(1, lineNum); + console.gotoxy(1, lineNum); console.print(DisplayBottomHelpLine_DCTStyle.helpText); - // Fill the rest of the line (less 1 character) if we're told to do so - var fillRestOfLine = (typeof(pFillRestOfLine) == "boolean" ? pFillRestOfLine : false); - if (fillRestOfLine) - { - // The remainder length has 1 subtracted from it so that we don't output a newline/CR - var remainderLen = console.screen_columns - strip_ctrl(DisplayBottomHelpLine_DCTStyle.helpText).length - 1; - if (remainderLen > 0) - printf("\1n%" + remainderLen + "s", ""); - } } // Updates the insert mode displayd on the screen, for DCT Edit style. diff --git a/exec/SlyEdit_IceStuff.js b/exec/SlyEdit_IceStuff.js index 5607adc222..e3fb7e0846 100644 --- a/exec/SlyEdit_IceStuff.js +++ b/exec/SlyEdit_IceStuff.js @@ -13,7 +13,7 @@ * Initial public release * 2009-12-03 Eric Oulashin Added support for color schemes. * Added displayIceYesNoText() and - * readIceColorConfig(). + * readColorConfig(). * 2010-01-02 Eric Oulashin Removed abortConfirm_DCTStyle(), * since it's no longer used anymore. * 2011-02-02 Eric Oulashin Moved the time displaying code into @@ -23,13 +23,13 @@ * of the theme filename, since the path is * now set in ReadSlyEditConfigFile() in * SlyEdit_Misc.js. - * 2013-01-19 Eric Oulashin Updated readIceColorConfig() to move the + * 2013-01-19 Eric Oulashin Updated readColorConfig() to move the * general color settings to gConfigSettings.genColors.* * 2013-01-25 Eric Oulashin Updated doIceESCMenu() to include an option * for cross-posting, when allowed. - * 2013-08-23 Eric Oulashin Updated readIceColorConfig() with the new general color + * 2013-08-23 Eric Oulashin Updated readColorConfig() with the new general color * configuration settings. - * 2013-08-28 Eric Oulashin Simplified readIceColorConfig() by having it call + * 2013-08-28 Eric Oulashin Simplified readColorConfig() by having it call * moveGenColorsToGenSettings() (defined in * SlyEdit_Misc.js) to move the general colors * into the genColors array in the configuration @@ -48,7 +48,7 @@ * to use the new gConfigSettings.iceColors.menuOptClassicColors * configuration setting for new vs. classic Ice-style * menu option colors. - * 2013-10-17 Eric Oulashin Bug fix: Updated readIceColorConfig() to make a backup of + * 2013-10-17 Eric Oulashin Bug fix: Updated readColorConfig() to make a backup of * the menuOptClassicColors setting and set it back in the * iceColors object after reading & setting the colors. * Bug fix in DisplayTextAreaBottomBorder_IceStyle() in @@ -70,7 +70,7 @@ var ICE_ESC_MENU_HELP = 4; var ICE_ESC_MENU_CROSS_POST = 5; // Read the color configuration file -readIceColorConfig(gConfigSettings.iceColors.ThemeFilename); +readColorConfig(gConfigSettings.iceColors.ThemeFilename); /////////////////////////////////////////////////////////////////////////////////// @@ -80,20 +80,20 @@ readIceColorConfig(gConfigSettings.iceColors.ThemeFilename); // // Parameters: // pFilename: The name of the color configuration file -function readIceColorConfig(pFilename) +function readColorConfig(pFilename) { - var colors = readValueSettingConfigFile(pFilename, 512, true); - if (colors != null) - { - // Make a backup of the menuOptClassicColors setting so we can set it - // back in the Ice color settings object after setting the colors. - var useClassicColorsBackup = gConfigSettings.iceColors.menuOptClassicColors; - gConfigSettings.iceColors = colors; - // Move the general color settings into gConfigSettings.genColors.* - if (EDITOR_STYLE == "ICE") - moveGenColorsToGenSettings(gConfigSettings.iceColors, gConfigSettings); - gConfigSettings.iceColors.menuOptClassicColors = useClassicColorsBackup; - } + var colors = readValueSettingConfigFile(pFilename, 512); + if (colors != null) + { + // Make a backup of the menuOptClassicColors setting so we can set it + // back in the Ice color settings object after setting the colors. + var useClassicColorsBackup = gConfigSettings.iceColors.menuOptClassicColors; + gConfigSettings.iceColors = colors; + // Move the general color settings into gConfigSettings.genColors.* + if (EDITOR_STYLE == "ICE") + moveGenColorsToGenSettings(gConfigSettings.iceColors, gConfigSettings); + gConfigSettings.iceColors.menuOptClassicColors = useClassicColorsBackup; + } } // Re-draws the screen, in the style of IceEdit. @@ -109,7 +109,7 @@ function readIceColorConfig(pFilename) // pEditLinesIndex: The index of the message line at the top of the edit area // pDisplayEditLines: The function that displays the edit lines function redrawScreen_IceStyle(pEditLeft, pEditRight, pEditTop, pEditBottom, pEditColor, - pInsertMode, pUseQuotes, pEditLinesIndex, pDisplayEditLines) + pInsertMode, pUseQuotes, pEditLinesIndex, pDisplayEditLines) { // Top header // Generate & display the top border line (Note: Generate this @@ -235,7 +235,8 @@ function redrawScreen_IceStyle(pEditLeft, pEditRight, pEditTop, pEditBottom, pEd // The message area name should be centered on the line. So, based on its // length (up to 35 characters), figure out its starting position before // printing it. - var msgAreaName = gMsgAreaName.substr(0, 35); // The 35 used to be 20 + //var msgAreaName = gMsgArea.substr(0, 20); // Used to be 20 characters + var msgAreaName = gMsgArea.substr(0, 35); // 2 is subtracted from the starting position to leave room for the // block character and the space. var startPos = (console.screen_columns/2).toFixed(0) - (msgAreaName.length/2).toFixed(0) - 2; @@ -390,48 +391,37 @@ function DisplayTextAreaBottomBorder_IceStyle(pLineNum, pUseQuotes, pEditLeft, p // // Parameters: // pLineNum: The line number on the screen where the text should be placed -// pUsingQuotes: Boolean - Whether or not message quoting is enabled. This is -// only here to match the DCT-style function. -// pFillRestOfLine: Optional boolean - Whether or not to fill the rest of the line. -// Defaults to false. -function DisplayBottomHelpLine_IceStyle(pLineNum, pUsingQuotes, pFillRestOfLine) +// The following are not used and are only here to match the DCT-style function: +// pUsingQuotes: Boolean - Whether or not message quoting is enabled. +function DisplayBottomHelpLine_IceStyle(pLineNum, pUsingQuotes) { - // Construct the help text only once - if (typeof(DisplayBottomHelpLine_IceStyle.helpText) == "undefined") - { - // This line contains the copyright mesage & ESC key help - var screenText = iceText(EDITOR_PROGRAM_NAME + " v", "\1w") + "\1c\1h" - + EDITOR_VERSION.toString() + " " - + iceText("Copyright", "\1w") + " \1c\1h2018 " - + iceText("Eric Oulashin", "\1w") + " \1n\1b" + DOT_CHAR + " " - + iceText("Press ESCape For Help", "\1w"); - // Calculate the starting position to center the help text, and front-pad - // DisplayBottomHelpLine_IceStyle.helpText with that many spaces. - var xPos = (console.screen_columns / 2).toFixed(0) - - (strip_ctrl(screenText).length / 2).toFixed(0); - DisplayBottomHelpLine_IceStyle.helpText = ""; - for (var i = 0; i < xPos; ++i) - DisplayBottomHelpLine_IceStyle.helpText += " "; - DisplayBottomHelpLine_IceStyle.helpText += screenText; - } + // Construct the help text only once + if (typeof(DisplayBottomHelpLine_IceStyle.helpText) == "undefined") + { + // This line contains the copyright mesage & ESC key help + var screenText = iceText(EDITOR_PROGRAM_NAME + " v", "w") + "ch" + + EDITOR_VERSION.toString() + " " + + iceText("Copyright", "w") + " ch2017 " + + iceText("Eric Oulashin", "w") + " nb" + DOT_CHAR + " " + + iceText("Press ESCape For Help", "w"); + // Calculate the starting position to center the help text, and front-pad + // DisplayBottomHelpLine_IceStyle.helpText with that many spaces. + var xPos = (console.screen_columns / 2).toFixed(0) + - (strip_ctrl(screenText).length / 2).toFixed(0); + DisplayBottomHelpLine_IceStyle.helpText = ""; + for (var i = 0; i < xPos; ++i) + DisplayBottomHelpLine_IceStyle.helpText += " "; + DisplayBottomHelpLine_IceStyle.helpText += screenText; + } - // If pLineNum is not specified, then default to the last line + // If pLineNum is not specified, then default to the last line // on the screen. var lineNum = console.screen_rows; if ((typeof(pLineNum) != "undefined") && (pLineNum != null)) lineNum = pLineNum; - // Display the help text on the screen + // Display the help text on the screen console.gotoxy(1, lineNum); console.print(DisplayBottomHelpLine_IceStyle.helpText); - // Fill the rest of the line (less 1 character) if we're told to do so - var fillRestOfLine = (typeof(pFillRestOfLine) == "boolean" ? pFillRestOfLine : false); - if (fillRestOfLine) - { - // The remainder length has 1 subtracted from it so that we don't output a newline/CR - var remainderLen = console.screen_columns - strip_ctrl(DisplayBottomHelpLine_IceStyle.helpText).length - 1; - if (remainderLen > 0) - printf("\1n%" + remainderLen + "s", ""); - } } // Updates the insert mode displayd on the screen, for Ice Edit style. diff --git a/exec/SlyEdit_Misc.js b/exec/SlyEdit_Misc.js index c63dae379a..a17b573b4d 100644 --- a/exec/SlyEdit_Misc.js +++ b/exec/SlyEdit_Misc.js @@ -34,11 +34,10 @@ * handle situations when it wraps text into the * next line when that next line is blank - Ensuring * it adds a blank line below that. - * 2018-01-27 Eric Oulashin Added removeStrayANSIOneChars() */ -load("text.js"); - + load("text.js"); + // Note: These variables are declared with "var" instead of "const" to avoid // multiple declaration errors when this file is loaded more than once. @@ -157,11 +156,6 @@ var gDDML_DROP_FILE_NAME = system.node_dir + "DDML_SyncSMBInfo.txt"; var gUserSettingsFilename = backslash(system.data_dir + "user") + format("%04d", user.number) + ".SlyEdit_Settings"; -// A regular expression for matching a Synchronet color/attribute code (case-insensitive) -var gSyncAttrRegex = /[krgybmcw01234567hinpq,;\.dtl<>\[\]asz]/i; -// A regular expression to match all only Synchronet attribute codes in a string -var gOnlySyncAttrsInStrRegex = /^([krgybmcw01234567hinpq,;\.dtl<>\[\]asz])+$/i; - /////////////////////////////////////////////////////////////////////////////////// // Object/class stuff @@ -191,21 +185,19 @@ function TextLine(pText, pHardNewlineEnd, pIsQuoteLine) if ((pIsQuoteLine != null) && (typeof(pIsQuoteLine) == "boolean")) this.isQuoteLine = pIsQuoteLine; + // NEW & EXPERIMENTAL: + // For color support + this.attrs = new Array(); // An array of attributes for the line // Functions - this.displayLength = TextLine_DisplayLength; + this.length = TextLine_Length; this.print = TextLine_Print; - this.doMacroTxtReplacement = TextLine_DoMacroTxtReplacement; - this.getWord = TextLine_GetWord; - this.substrWithSyncColorCodes = TextLine_SubstrWithSyncColorCodes; - this.getLastAttrCodes = TextLine_GetLastAttrCodes; - this.getAttrsAndIndexesBeforeIdx = TextLine_GetAttrsAndIndexesBeforeIdx; - this.displayIdxToActualIdx = TextLine_DisplayIdxToActualIdx; + this.doMacroTxtReplacement = TextLine_doMacroTxtReplacement; + this.getWord = TextLine_getWord; } // For the TextLine class: Returns the length of the text. -function TextLine_DisplayLength() +function TextLine_Length() { - //return this.text.length; - return strip_ctrl(this.text).length; + return this.text.length; } // For the TextLine class: Prints the text line, using its text attributes. // @@ -226,19 +218,11 @@ function TextLine_Print(pClearToEOL) // pCharIndex: The current character index in the text line // pUseRegex: Whether or not to treat the text replacement search string as a // regular expression. -// pAllowAttrCodes: Boolean - Whether or not to allow attribute codes in -// the replacement strings -// pTextAttrs: The text attribute(s) for the message text. If there are -// any color/attribute codes in a replacement text, this will -// be appended to the end so the rest of the message will be -// the color it should be. // // Return value: An object containing the following properties: // textLineIndex: The updated text line index (integer) // wordLenDiff: The change in length of the word that // was replaced (integer) -// displayableWordLenDiff: The change in display length of the -// word that was replaced (integer) // wordStartIdx: The index of the first character in the word. // Only valid if a word was found. Otherwise, this // will be 0. @@ -250,19 +234,15 @@ function TextLine_Print(pClearToEOL) // replaced or 0 if no word was found. // madeTxtReplacement: Whether or not a text replacement was made // (boolean) -function TextLine_DoMacroTxtReplacement(pTxtReplacements, pCharIndex, pUseRegex, pAllowAttrCodes, pTextAttrs) +function TextLine_doMacroTxtReplacement(pTxtReplacements, pCharIndex, pUseRegex) { - var retObj = { - textLineIndex: pCharIndex, - wordLenDiff: 0, - displayableWordLenDiff: 0, - wordStartIdx: 0, - newTextEndIdx: 0, - newTextLen: 0, - madeTxtReplacement: false - }; - - var allowAttrCodes = (typeof(pAllowAttrCodes) == "boolean" ? pAllowAttrCodes : false); + var retObj = new Object(); + retObj.textLineIndex = pCharIndex; + retObj.wordLenDiff = 0; + retObj.wordStartIdx = 0; + retObj.newTextEndIdx = 0; + retObj.newTextLen = 0; + retObj.madeTxtReplacement = false; var wordObj = this.getWord(retObj.textLineIndex); if (wordObj.foundWord) @@ -284,17 +264,7 @@ function TextLine_DoMacroTxtReplacement(pTxtReplacements, pCharIndex, pUseRegex, if (pTxtReplacements.hasOwnProperty(prop)) { var regex = new RegExp(prop); - if (allowAttrCodes) - { - txtReplacement = wordObj.word.replace(regex, pTxtReplacements[prop]); - // If the replacement has any Synchronet attribute codes, append the - // given text attributes to it so the rest of the message is back to - // normal colors. // TODO: Dealing with high vs. normal? - if (gSyncAttrRegex.test(txtReplacement)) - txtReplacement += "\1n" + pTextAttrs; - } - else - txtReplacement = wordObj.word.replace(regex, strip_ctrl(pTxtReplacements[prop])); + txtReplacement = wordObj.word.replace(regex, pTxtReplacements[prop]); retObj.madeTxtReplacement = (txtReplacement != wordObj.word); // If a text replacement was made, then check and see if the first // letter in the original text was uppercase, and if so, make the @@ -327,31 +297,20 @@ function TextLine_DoMacroTxtReplacement(pTxtReplacements, pCharIndex, pUseRegex, wordObj.word = wordObj.word.toUpperCase(); if (pTxtReplacements.hasOwnProperty(wordObj.word)) { - if (allowAttrCodes) - { - txtReplacement = pTxtReplacements[wordObj.word]; - // If the replacement has any Synchronet attribute codes, append the - // given text attributes to it so the rest of the message is back to - // normal colors. // TODO: Dealing with high vs. normal? - if (gSyncAttrRegex.test(txtReplacement)) - txtReplacement += "\1n" + pTextAttrs; - } - else - txtReplacement = strip_ctrl(pTxtReplacements[wordObj.word]); + txtReplacement = pTxtReplacements[wordObj.word]; retObj.madeTxtReplacement = true; } } if (retObj.madeTxtReplacement) { if (firstCharUpper) - txtReplacement = txtReplacement.charAt(0).toUpperCase() + txtReplacement.substr(1); + txtReplacement = txtReplacement.charAt(0).toUpperCase() + txtReplacement.substr(1); this.text = this.text.substr(0, wordObj.startIdx) + txtReplacement + this.text.substr(wordObj.endIndex+1); // Based on the difference in word length, update the data that // matters (retObj.textLineIndex, which keeps track of the index of the current line). // Note: The horizontal cursor position variable should be replaced after calling this // function. retObj.wordLenDiff = txtReplacement.length - wordObj.word.length; - retObj.displayableWordLenDiff = strip_ctrl(txtReplacement).length - strip_ctrl(wordObj.word).length; retObj.textLineIndex += retObj.wordLenDiff; retObj.newTextEndIdx = wordObj.endIndex + retObj.wordLenDiff; retObj.newTextLen = txtReplacement.length; @@ -378,7 +337,7 @@ function TextLine_DoMacroTxtReplacement(pTxtReplacements, pCharIndex, pUseRegex, // startIdx: The index of the first character of the word (integer) // endIndex: The index of the last character of the word (integer) // This includes any control/color codes, etc. -function TextLine_GetWord(pCharIndex) +function TextLine_getWord(pCharIndex) { var retObj = { foundWord: false, @@ -415,85 +374,7 @@ function TextLine_GetWord(pCharIndex) retObj.plainWord = strip_ctrl(retObj.word); return retObj; } -// For the TextLine class: Gets a substring, handling Synchronet color codes. -// This calls substrWithSyncColorCodes() with the object's text line and -// returns the same value as that function. -// -// Parameters: -// pStartIdx: The index of where to start in the string, as it appears -// on the screen -// pLen: The length of the substring to get. Optional - If not specified, -// the rest of the string will be used. -// -// Return value: An object with the following properties: -// strSub: The substring from the string, including any Synchronet -// color codes that may exist preceding the word at pStartIdx -// startIdx: The actual index in the string where the substring starts -// (-1 if an error occurred) -// endIdx: The actual index in the string where the substring ends. -// This is the index of the last character in the substring. -// Will be -1 if an error occurred. -// len: The actual length of the substring -// printableLen: The length of the string as it would appear on the screen -// (i.e., its length without Synchronet attribute codes) -// syncAttrStartIdx: The starting index of Synchronet attributes -// (-1 if not found or an error occurred) -// syncAttrEndIdx: The ending index of Synchronet attributes, including -// the last character (-1 if not found or an error occurred) -function TextLine_SubstrWithSyncColorCodes(pStartIdx, pLen) -{ - return substrWithSyncColorCodes(this.text, pStartIdx, pLen); -} -// For the TextLine class: Returns the last attribute codes appearing in the line -// before a given index, as a string. If there are none, it will just be a -// blank string. The index is optional - If not provided, this method will use -// the end index of the string. -// -// Parameters: -// pIdx: Optional - The end index of the string to use. If not provided, this will -// use the last index of the string. -// -// Return value: Any attribute codes appearing before the given index (or last index) -// of the string, as a string. -function TextLine_GetLastAttrCodes(pIdx) -{ - var endIdx = (typeof(pIdx) == "number" ? pIdx : this.text.length-1); - if (endIdx < 0) - return ""; - if (endIdx >= this.text.length) - endIdx = this.text.length - 1; - return getAttrsBeforeStrIdx(this.text, endIdx); -} -// For the TextLine class: Returns an object with information about any Synchronet -// color/attribute codes found in the text line before a given index. -// -// Parameters: -// pIdx: The index in the text line to search before -// -// Return value: An object containing the following properties: -// attrStr: A string containing any Synchronet attribute codes -// found before the given index in the given string. If -// none are found, this string will be empty. -// syncAttrStartIdx: The index of where the attribute codes start, or -// -1 if none were found -// syncAttrEndIdx: The index of the last character of the attribute -// codes, or -1 if none were found -function TextLine_GetAttrsAndIndexesBeforeIdx(pIdx) -{ - return getAttrsAndIndexesBeforeStrIdx(this.text, pIdx); -} -// For the TextLine class: Converts a printable display index to the actual index -// of the text line, ignoring Synchronet attribute codes in the string. -// -// Parameters: -// pDisplayIdx: The string index as displayed on the screen -// -// Return value: The index in the actual string. 0 on error -function TextLine_DisplayIdxToActualIdx(pDisplayIdx) -{ - return strDisplayIdxToActualIdx(this.text, pDisplayIdx); -} // AbortConfirmFuncParams constructor: This object contains parameters used by // the abort confirmation function (actually, there are separate ones for @@ -534,200 +415,202 @@ function ChoiceScrollbox_MinWidth() function ChoiceScrollbox(pLeftX, pTopY, pWidth, pHeight, pTopBorderText, pSlyEdCfgObj, pAddTCharsAroundTopText, pReplaceTopTextSpacesWithBorderChars) { - // The default is to add left & right T characters around the top border - // text. But also use pAddTCharsAroundTopText if it's a boolean. - var addTopTCharsAroundText = true; - if (typeof(pAddTCharsAroundTopText) == "boolean") - addTopTCharsAroundText = pAddTCharsAroundTopText; - // If pReplaceTopTextSpacesWithBorderChars is true, then replace the spaces - // in pTopBorderText with border characters. - if (pReplaceTopTextSpacesWithBorderChars) - { - var startIdx = 0; - var firstSpcIdx = pTopBorderText.indexOf(" ", 0); - // Look for the first non-space after firstSpaceIdx - var nonSpcIdx = -1; - for (var i = firstSpcIdx; (i < pTopBorderText.length) && (nonSpcIdx == -1); ++i) - { - if (pTopBorderText.charAt(i) != " ") - nonSpcIdx = i; - } - var firstStrPart = ""; - var lastStrPart = ""; - var numSpaces = 0; - while ((firstSpcIdx > -1) && (nonSpcIdx > -1)) - { - firstStrPart = pTopBorderText.substr(startIdx, (firstSpcIdx-startIdx)); - lastStrPart = pTopBorderText.substr(nonSpcIdx); - numSpaces = nonSpcIdx - firstSpcIdx; - if (numSpaces > 0) - { - pTopBorderText = firstStrPart + "\1n" + pSlyEdCfgObj.genColors.listBoxBorder; - for (var i = 0; i < numSpaces; ++i) - pTopBorderText += HORIZONTAL_SINGLE; - pTopBorderText += "\1n" + pSlyEdCfgObj.genColors.listBoxBorderText + lastStrPart; - } + // The default is to add left & right T characters around the top border + // text. But also use pAddTCharsAroundTopText if it's a boolean. + var addTopTCharsAroundText = true; + if (typeof(pAddTCharsAroundTopText) == "boolean") + addTopTCharsAroundText = pAddTCharsAroundTopText; + // If pReplaceTopTextSpacesWithBorderChars is true, then replace the spaces + // in pTopBorderText with border characters. + if (pReplaceTopTextSpacesWithBorderChars) + { + var startIdx = 0; + var firstSpcIdx = pTopBorderText.indexOf(" ", 0); + // Look for the first non-space after firstSpaceIdx + var nonSpcIdx = -1; + for (var i = firstSpcIdx; (i < pTopBorderText.length) && (nonSpcIdx == -1); ++i) + { + if (pTopBorderText.charAt(i) != " ") + nonSpcIdx = i; + } + var firstStrPart = ""; + var lastStrPart = ""; + numSpaces = 0; + while ((firstSpcIdx > -1) && (nonSpcIdx > -1)) + { + firstStrPart = pTopBorderText.substr(startIdx, (firstSpcIdx-startIdx)); + lastStrPart = pTopBorderText.substr(nonSpcIdx); + numSpaces = nonSpcIdx - firstSpcIdx; + if (numSpaces > 0) + { + pTopBorderText = firstStrPart + "n" + pSlyEdCfgObj.genColors.listBoxBorder; + for (var i = 0; i < numSpaces; ++i) + pTopBorderText += HORIZONTAL_SINGLE; + pTopBorderText += "n" + pSlyEdCfgObj.genColors.listBoxBorderText + lastStrPart; + } - // Look for the next space and non-space character after that. - firstSpcIdx = pTopBorderText.indexOf(" ", nonSpcIdx); - // Look for the first non-space after firstSpaceIdx - nonSpcIdx = -1; - for (var i = firstSpcIdx; (i < pTopBorderText.length) && (nonSpcIdx == -1); ++i) - { - if (pTopBorderText.charAt(i) != " ") - nonSpcIdx = i; - } - } - } + // Look for the next space and non-space character after that. + firstSpcIdx = pTopBorderText.indexOf(" ", nonSpcIdx); + // Look for the first non-space after firstSpaceIdx + nonSpcIdx = -1; + for (var i = firstSpcIdx; (i < pTopBorderText.length) && (nonSpcIdx == -1); ++i) + { + if (pTopBorderText.charAt(i) != " ") + nonSpcIdx = i; + } + } + } - this.SlyEdCfgObj = pSlyEdCfgObj; + this.SlyEdCfgObj = pSlyEdCfgObj; - var minWidth = ChoiceScrollbox_MinWidth(); + var minWidth = ChoiceScrollbox_MinWidth(); - this.dimensions = new Object(); - this.dimensions.topLeftX = pLeftX; - this.dimensions.topLeftY = pTopY; - // Make sure the width is the minimum width - if ((pWidth < 0) || (pWidth < minWidth)) - this.dimensions.width = minWidth; - else - this.dimensions.width = pWidth; - this.dimensions.height = pHeight; - this.dimensions.bottomRightX = this.dimensions.topLeftX + this.dimensions.width - 1; - this.dimensions.bottomRightY = this.dimensions.topLeftY + this.dimensions.height - 1; - - // The text item array and member variables relating to it and the items - // displayed on the screen during the input loop - this.txtItemList = new Array(); - this.chosenTextItemIndex = -1; - this.topItemIndex = 0; - this.bottomItemIndex = 0; - - // Top border string - var innerBorderWidth = this.dimensions.width - 2; - // Calculate the maximum top border text length to account for the left/right - // T chars and "Page #### of ####" text - var maxTopBorderTextLen = innerBorderWidth - (pAddTCharsAroundTopText ? 21 : 19); - if (strip_ctrl(pTopBorderText).length > maxTopBorderTextLen) - pTopBorderText = pTopBorderText.substr(0, maxTopBorderTextLen); - this.topBorder = "\1n" + pSlyEdCfgObj.genColors.listBoxBorder + UPPER_LEFT_SINGLE; - if (addTopTCharsAroundText) - this.topBorder += RIGHT_T_SINGLE; - this.topBorder += "\1n" + pSlyEdCfgObj.genColors.listBoxBorderText - + pTopBorderText + "\1n" + pSlyEdCfgObj.genColors.listBoxBorder; - if (addTopTCharsAroundText) - this.topBorder += LEFT_T_SINGLE; - const topBorderTextLen = strip_ctrl(pTopBorderText).length; - var numHorizBorderChars = innerBorderWidth - topBorderTextLen - 20; - if (addTopTCharsAroundText) - numHorizBorderChars -= 2; - for (var i = 0; i <= numHorizBorderChars; ++i) - this.topBorder += HORIZONTAL_SINGLE; - this.topBorder += RIGHT_T_SINGLE + "\1n" + pSlyEdCfgObj.genColors.listBoxBorderText - + "Page 1 of 1" + "\1n" + pSlyEdCfgObj.genColors.listBoxBorder + LEFT_T_SINGLE - + UPPER_RIGHT_SINGLE; - - // Bottom border string - this.btmBorderNavText = "nhcb, cb, cNy)bext, cPy)brev, " - + "cFy)birst, cLy)bast, cHOMEb, cENDb, cEntery=bSelect, " - + "cESCnc/hcQy=bEnd"; - this.bottomBorder = "n" + pSlyEdCfgObj.genColors.listBoxBorder + LOWER_LEFT_SINGLE - + RIGHT_T_SINGLE + this.btmBorderNavText + "n" + pSlyEdCfgObj.genColors.listBoxBorder - + LEFT_T_SINGLE; - var numCharsRemaining = this.dimensions.width - strip_ctrl(this.btmBorderNavText).length - 6; - for (var i = 0; i < numCharsRemaining; ++i) - this.bottomBorder += HORIZONTAL_SINGLE; - this.bottomBorder += LOWER_RIGHT_SINGLE; - - // Item format strings - this.listIemFormatStr = "n" + pSlyEdCfgObj.genColors.listBoxItemText + "%-" + +(this.dimensions.width-2) + "s"; - this.listIemHighlightFormatStr = "n" + pSlyEdCfgObj.genColors.listBoxItemHighlight + "%-" + +(this.dimensions.width-2) + "s"; - - // Key functionality override function pointers - this.enterKeyOverrideFn = null; - - // inputLoopeExitKeys is an object containing additional keypresses that will - // exit the input loop. - this.inputLoopExitKeys = new Object(); - - // "Class" functions - this.addTextItem = ChoiceScrollbox_AddTextItem; // Returns the index of the item - this.getTextItem = ChoiceScrollbox_GetTextIem; - this.replaceTextItem = ChoiceScrollbox_ReplaceTextItem; - this.delTextItem = ChoiceScrollbox_DelTextItem; - this.chgCharInTextItem = ChoiceScrollbox_ChgCharInTextItem; - this.getChosenTextItemIndex = ChoiceScrollbox_GetChosenTextItemIndex; - this.setItemArray = ChoiceScrollbox_SetItemArray; // Sets the item array; returns whether or not it was set. - this.clearItems = ChoiceScrollbox_ClearItems; // Empties the array of items - this.setEnterKeyOverrideFn = ChoiceScrollbox_SetEnterKeyOverrideFn; - this.clearEnterKeyOverrideFn = ChoiceScrollbox_ClearEnterKeyOverrideFn; - this.addInputLoopExitKey = ChoiceScrollbox_AddInputLoopExitKey; - this.setBottomBorderText = ChoiceScrollbox_SetBottomBorderText; - this.drawBorder = ChoiceScrollbox_DrawBorder; - this.refreshItemCharOnScreen = ChoiceScrollbox_RefreshItemCharOnScreen; - // Does the input loop. Returns an object with the following properties: - // itemWasSelected: Boolean - Whether or not an item was selected - // selectedIndex: The index of the selected item - // selectedItem: The text of the selected item - // lastKeypress: The last key pressed by the user - this.doInputLoop = ChoiceScrollbox_DoInputLoop; + this.dimensions = new Object(); + this.dimensions.topLeftX = pLeftX; + this.dimensions.topLeftY = pTopY; + // Make sure the width is the minimum width + if ((pWidth < 0) || (pWidth < minWidth)) + this.dimensions.width = minWidth; + else + this.dimensions.width = pWidth; + this.dimensions.height = pHeight; + this.dimensions.bottomRightX = this.dimensions.topLeftX + this.dimensions.width - 1; + this.dimensions.bottomRightY = this.dimensions.topLeftY + this.dimensions.height - 1; + + // The text item array and member variables relating to it and the items + // displayed on the screen during the input loop + this.txtItemList = new Array(); + this.chosenTextItemIndex = -1; + this.topItemIndex = 0; + this.bottomItemIndex = 0; + + // Top border string + var innerBorderWidth = this.dimensions.width - 2; + // Calculate the maximum top border text length to account for the left/right + // T chars and "Page #### of ####" text + var maxTopBorderTextLen = innerBorderWidth - (pAddTCharsAroundTopText ? 21 : 19); + if (strip_ctrl(pTopBorderText).length > maxTopBorderTextLen) + pTopBorderText = pTopBorderText.substr(0, maxTopBorderTextLen); + this.topBorder = "n" + pSlyEdCfgObj.genColors.listBoxBorder + UPPER_LEFT_SINGLE; + if (addTopTCharsAroundText) + this.topBorder += RIGHT_T_SINGLE; + this.topBorder += "n" + pSlyEdCfgObj.genColors.listBoxBorderText + + pTopBorderText + "n" + pSlyEdCfgObj.genColors.listBoxBorder; + if (addTopTCharsAroundText) + this.topBorder += LEFT_T_SINGLE; + const topBorderTextLen = strip_ctrl(pTopBorderText).length; + var numHorizBorderChars = innerBorderWidth - topBorderTextLen - 20; + if (addTopTCharsAroundText) + numHorizBorderChars -= 2; + for (var i = 0; i <= numHorizBorderChars; ++i) + this.topBorder += HORIZONTAL_SINGLE; + this.topBorder += RIGHT_T_SINGLE + "n" + pSlyEdCfgObj.genColors.listBoxBorderText + + "Page 1 of 1" + "n" + pSlyEdCfgObj.genColors.listBoxBorder + LEFT_T_SINGLE + + UPPER_RIGHT_SINGLE; + + // Bottom border string + this.btmBorderNavText = "nhcb, cb, cNy)bext, cPy)brev, " + + "cFy)birst, cLy)bast, cHOMEb, cENDb, cEntery=bSelect, " + + "cESCnc/hcQy=bEnd"; + this.bottomBorder = "n" + pSlyEdCfgObj.genColors.listBoxBorder + LOWER_LEFT_SINGLE + + RIGHT_T_SINGLE + this.btmBorderNavText + "n" + pSlyEdCfgObj.genColors.listBoxBorder + + LEFT_T_SINGLE; + var numCharsRemaining = this.dimensions.width - strip_ctrl(this.btmBorderNavText).length - 6; + for (var i = 0; i < numCharsRemaining; ++i) + this.bottomBorder += HORIZONTAL_SINGLE; + this.bottomBorder += LOWER_RIGHT_SINGLE; + + // Item format strings + this.listIemFormatStr = "n" + pSlyEdCfgObj.genColors.listBoxItemText + "%-" + + +(this.dimensions.width-2) + "s"; + this.listIemHighlightFormatStr = "n" + pSlyEdCfgObj.genColors.listBoxItemHighlight + "%-" + + +(this.dimensions.width-2) + "s"; + + // Key functionality override function pointers + this.enterKeyOverrideFn = null; + + // inputLoopeExitKeys is an object containing additional keypresses that will + // exit the input loop. + this.inputLoopExitKeys = new Object(); + + // "Class" functions + this.addTextItem = ChoiceScrollbox_AddTextItem; // Returns the index of the item + this.getTextItem = ChoiceScrollbox_GetTextIem; + this.replaceTextItem = ChoiceScrollbox_ReplaceTextItem; + this.delTextItem = ChoiceScrollbox_DelTextItem; + this.chgCharInTextItem = ChoiceScrollbox_ChgCharInTextItem; + this.getChosenTextItemIndex = ChoiceScrollbox_GetChosenTextItemIndex; + this.setItemArray = ChoiceScrollbox_SetItemArray; // Sets the item array; returns whether or not it was set. + this.clearItems = ChoiceScrollbox_ClearItems; // Empties the array of items + this.setEnterKeyOverrideFn = ChoiceScrollbox_SetEnterKeyOverrideFn; + this.clearEnterKeyOverrideFn = ChoiceScrollbox_ClearEnterKeyOverrideFn; + this.addInputLoopExitKey = ChoiceScrollbox_AddInputLoopExitKey; + this.setBottomBorderText = ChoiceScrollbox_SetBottomBorderText; + this.drawBorder = ChoiceScrollbox_DrawBorder; + this.refreshItemCharOnScreen = ChoiceScrollbox_RefreshItemCharOnScreen; + // Does the input loop. Returns an object with the following properties: + // itemWasSelected: Boolean - Whether or not an item was selected + // selectedIndex: The index of the selected item + // selectedItem: The text of the selected item + // lastKeypress: The last key pressed by the user + this.doInputLoop = ChoiceScrollbox_DoInputLoop; } function ChoiceScrollbox_AddTextItem(pTextLine, pStripCtrl) { - var stripCtrl = true; - if (typeof(pStripCtrl) == "boolean") - stripCtrl = pStripCtrl; + var stripCtrl = true; + if (typeof(pStripCtrl) == "boolean") + stripCtrl = pStripCtrl; - if (stripCtrl) - this.txtItemList.push(strip_ctrl(pTextLine)); - else - this.txtItemList.push(pTextLine); - // Return the index of the added item - return this.txtItemList.length-1; + if (stripCtrl) + this.txtItemList.push(strip_ctrl(pTextLine)); + else + this.txtItemList.push(pTextLine); + // Return the index of the added item + return this.txtItemList.length-1; } function ChoiceScrollbox_GetTextIem(pItemIndex) { - if (typeof(pItemIndex) != "number") - return ""; - if ((pItemIndex < 0) || (pItemIndex >= this.txtItemList.length)) - return ""; + if (typeof(pItemIndex) != "number") + return ""; + if ((pItemIndex < 0) || (pItemIndex >= this.txtItemList.length)) + return ""; - return this.txtItemList[pItemIndex]; + return this.txtItemList[pItemIndex]; } function ChoiceScrollbox_ReplaceTextItem(pItemIndexOrStr, pNewItem) { - if (typeof(pNewItem) != "string") - return false; + if (typeof(pNewItem) != "string") + return false; - // Find the item index - var itemIndex = -1; - if (typeof(pItemIndexOrStr) == "number") - { - if ((pItemIndexOrStr < 0) || (pItemIndexOrStr >= this.txtItemList.length)) - return false; - else - itemIndex = pItemIndexOrStr; - } - else if (typeof(pItemIndexOrStr) == "string") - { - itemIndex = -1; - for (var i = 0; (i < this.txtItemList.length) && (itemIndex == -1); ++i) - { - if (this.txtItemList[i] == pItemIndexOrStr) - itemIndex = i; - } - } - else - return false; + // Find the item index + var itemIndex = -1; + if (typeof(pItemIndexOrStr) == "number") + { + if ((pItemIndexOrStr < 0) || (pItemIndexOrStr >= this.txtItemList.length)) + return false; + else + itemIndex = pItemIndexOrStr; + } + else if (typeof(pItemIndexOrStr) == "string") + { + itemIndex = -1; + for (var i = 0; (i < this.txtItemList.length) && (itemIndex == -1); ++i) + { + if (this.txtItemList[i] == pItemIndexOrStr) + itemIndex = i; + } + } + else + return false; - // Replace the item - var replacedIt = false; - if ((itemIndex > -1) && (itemIndex < this.txtItemList.length)) - { - this.txtItemList[itemIndex] = pNewItem; - replacedIt = true; - } - return replacedIt; + // Replace the item + var replacedIt = false; + if ((itemIndex > -1) && (itemIndex < this.txtItemList.length)) + { + this.txtItemList[itemIndex] = pNewItem; + replacedIt = true; + } + return replacedIt; } function ChoiceScrollbox_DelTextItem(pItemIndexOrStr) { @@ -845,75 +728,75 @@ function ChoiceScrollbox_AddInputLoopExitKey(pKeypress) } function ChoiceScrollbox_SetBottomBorderText(pText, pAddTChars, pAutoStripIfTooLong) { - if (typeof(pText) != "string") - return; + if (typeof(pText) != "string") + return; - const innerWidth = (pAddTChars ? this.dimensions.width-4 : this.dimensions.width-2); + const innerWidth = (pAddTChars ? this.dimensions.width-4 : this.dimensions.width-2); - if (pAutoStripIfTooLong) - { - if (strip_ctrl(pText).length > innerWidth) - pText = pText.substr(0, innerWidth); - } + if (pAutoStripIfTooLong) + { + if (strip_ctrl(pText).length > innerWidth) + pText = pText.substr(0, innerWidth); + } - // Re-build the bottom border string based on the new text - this.bottomBorder = "n" + this.SlyEdCfgObj.genColors.listBoxBorder + LOWER_LEFT_SINGLE; - if (pAddTChars) - this.bottomBorder += RIGHT_T_SINGLE; - if (pText.indexOf("n") != 0) - this.bottomBorder += "n"; - this.bottomBorder += pText + "n" + this.SlyEdCfgObj.genColors.listBoxBorder; - if (pAddTChars) - this.bottomBorder += LEFT_T_SINGLE; - var numCharsRemaining = this.dimensions.width - strip_ctrl(this.bottomBorder).length - 3; - for (var i = 0; i < numCharsRemaining; ++i) - this.bottomBorder += HORIZONTAL_SINGLE; - this.bottomBorder += LOWER_RIGHT_SINGLE; + // Re-build the bottom border string based on the new text + this.bottomBorder = "n" + this.SlyEdCfgObj.genColors.listBoxBorder + LOWER_LEFT_SINGLE; + if (pAddTChars) + this.bottomBorder += RIGHT_T_SINGLE; + if (pText.indexOf("n") != 0) + this.bottomBorder += "n"; + this.bottomBorder += pText + "n" + this.SlyEdCfgObj.genColors.listBoxBorder; + if (pAddTChars) + this.bottomBorder += LEFT_T_SINGLE; + var numCharsRemaining = this.dimensions.width - strip_ctrl(this.bottomBorder).length - 3; + for (var i = 0; i < numCharsRemaining; ++i) + this.bottomBorder += HORIZONTAL_SINGLE; + this.bottomBorder += LOWER_RIGHT_SINGLE; } function ChoiceScrollbox_DrawBorder() { - console.gotoxy(this.dimensions.topLeftX, this.dimensions.topLeftY); - console.print(this.topBorder); - // Draw the side border characters - var screenRow = this.dimensions.topLeftY + 1; - for (var screenRow = this.dimensions.topLeftY+1; screenRow <= this.dimensions.bottomRightY-1; ++screenRow) - { - console.gotoxy(this.dimensions.topLeftX, screenRow); - console.print(VERTICAL_SINGLE); - console.gotoxy(this.dimensions.bottomRightX, screenRow); - console.print(VERTICAL_SINGLE); - } - // Draw the bottom border - console.gotoxy(this.dimensions.topLeftX, this.dimensions.bottomRightY); - console.print(this.bottomBorder); + console.gotoxy(this.dimensions.topLeftX, this.dimensions.topLeftY); + console.print(this.topBorder); + // Draw the side border characters + var screenRow = this.dimensions.topLeftY + 1; + for (var screenRow = this.dimensions.topLeftY+1; screenRow <= this.dimensions.bottomRightY-1; ++screenRow) + { + console.gotoxy(this.dimensions.topLeftX, screenRow); + console.print(VERTICAL_SINGLE); + console.gotoxy(this.dimensions.bottomRightX, screenRow); + console.print(VERTICAL_SINGLE); + } + // Draw the bottom border + console.gotoxy(this.dimensions.topLeftX, this.dimensions.bottomRightY); + console.print(this.bottomBorder); } function ChoiceScrollbox_RefreshItemCharOnScreen(pItemIndex, pCharIndex) { - if ((typeof(pItemIndex) != "number") || (typeof(pCharIndex) != "number")) - return; - if ((pItemIndex < 0) || (pItemIndex >= this.txtItemList.length) || - (pItemIndex < this.topItemIndex) || (pItemIndex > this.bottomItemIndex)) - { - return; - } - if ((pCharIndex < 0) || (pCharIndex >= this.txtItemList[pItemIndex].length)) - return; - - // Save the current cursor position so that we can restore it later - const originalCurpos = console.getxy(); - // Go to the character's position on the screen and set the highlight or - // normal color, depending on whether the item is the currently selected item, - // then print the character on the screen. - const charScreenX = this.dimensions.topLeftX + 1 + pCharIndex; - const itemScreenY = this.dimensions.topLeftY + 1 + (pItemIndex - this.topItemIndex); - console.gotoxy(charScreenX, itemScreenY); - if (pItemIndex == this.chosenTextItemIndex) - console.print(this.SlyEdCfgObj.genColors.listBoxItemHighlight); - else - console.print(this.SlyEdCfgObj.genColors.listBoxItemText); - console.print(this.txtItemList[pItemIndex].charAt(pCharIndex)); - // Move the cursor back to where it was originally - console.gotoxy(originalCurpos); + if ((typeof(pItemIndex) != "number") || (typeof(pCharIndex) != "number")) + return; + if ((pItemIndex < 0) || (pItemIndex >= this.txtItemList.length) || + (pItemIndex < this.topItemIndex) || (pItemIndex > this.bottomItemIndex)) + { + return; + } + if ((pCharIndex < 0) || (pCharIndex >= this.txtItemList[pItemIndex].length)) + return; + + // Save the current cursor position so that we can restore it later + const originalCurpos = console.getxy(); + // Go to the character's position on the screen and set the highlight or + // normal color, depending on whether the item is the currently selected item, + // then print the character on the screen. + const charScreenX = this.dimensions.topLeftX + 1 + pCharIndex; + const itemScreenY = this.dimensions.topLeftY + 1 + (pItemIndex - this.topItemIndex); + console.gotoxy(charScreenX, itemScreenY); + if (pItemIndex == this.chosenTextItemIndex) + console.print(this.SlyEdCfgObj.genColors.listBoxItemHighlight); + else + console.print(this.SlyEdCfgObj.genColors.listBoxItemText); + console.print(this.txtItemList[pItemIndex].charAt(pCharIndex)); + // Move the cursor back to where it was originally + console.gotoxy(originalCurpos); } function ChoiceScrollbox_DoInputLoop(pDrawBorder) { @@ -1224,12 +1107,17 @@ function ChoiceScrollbox_DoInputLoop(pDrawBorder) function randomDimBrightString(pString, pColor) { // Return if an invalid string is passed in. + if (pString == null) + return ""; if (typeof(pString) != "string") return ""; - // Set the color. Default to green. - var color = (typeof(pColor) == "string" ? pColor : "\1g"); - return(randomTwoColorString(pString, "\1n" + color, "\1n\1h" + color)); + // Set the color. Default to green. + var color = "g"; + if ((pColor != null) && (typeof(pColor) != "undefined")) + color = pColor; + + return(randomTwoColorString(pString, "n" + color, "nh" + color)); } // This function takes a string and returns a copy of the string @@ -1239,18 +1127,21 @@ function randomDimBrightString(pString, pColor) // pString: The string to convert // pColor11: The first color to use (Synchronet color code) // pColor12: The second color to use (Synchronet color code) -// -// Return value: The string passed in, with the 2 colors used randomly for -// each character function randomTwoColorString(pString, pColor1, pColor2) { // Return if an invalid string is passed in. + if (pString == null) + return ""; if (typeof(pString) != "string") return ""; // Set the colors. Default to green. - var color1 = (typeof(pColor1) == "string" ? pColor1 : "\1n\1g"); - var color2 = (typeof(pColor2) == "string" ? pColor2 : "\1n\1g\1h"); + var color1 = "ng"; + if ((pColor1 != null) && (typeof(pColor1) != "undefined")) + color1 = pColor1; + var color2 = "ngh"; + if ((pColor2 != null) && (typeof(pColor2) != "undefined")) + color2 = pColor2; // Create a copy of the string without any control characters, // and then add our coloring to it. @@ -1263,7 +1154,7 @@ function randomTwoColorString(pString, pColor1, pColor2) // Determine if this character should be useColor1 useColor1 = (Math.floor(Math.random()*2) == 1); if (useColor1 != oldUseColor1) - returnString += (useColor1 ? color1 : color2); + returnString += (useColor1 ? color1 : color2); // Append the character from pString. returnString += pString.charAt(i); @@ -1277,22 +1168,26 @@ function randomTwoColorString(pString, pColor1, pColor2) // Returns the current time as a string, to be displayed on the screen. function getCurrentTimeStr() { - return strftime("%I:%M%p", time()).replace("AM", "a").replace("PM", "p"); + var timeStr = strftime("%I:%M%p", time()); + timeStr = timeStr.replace("AM", "a"); + timeStr = timeStr.replace("PM", "p"); + + return timeStr; } // Returns whether or not a character is printable. function isPrintableChar(pText) { - // Make sure pText is valid and is a string. - if (typeof(pText) != "string") - return false; - if (pText.length == 0) - return false; + // Make sure pText is valid and is a string. + if (typeof(pText) != "string") + return false; + if (pText.length == 0) + return false; - // Make sure the character is a printable ASCII character in the range of 32 to 254, - // except for 127 (delete). - var charCode = pText.charCodeAt(0); - return ((charCode > 31) && (charCode < 255) && (charCode != 127)); + // Make sure the character is a printable ASCII character in the range of 32 to 254, + // except for 127 (delete). + var charCode = pText.charCodeAt(0); + return ((charCode > 31) && (charCode < 255) && (charCode != 127)); } // Removes multiple, leading, and/or trailing spaces @@ -1381,8 +1276,11 @@ 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 -// pConfigSettings: The SlyEdit configuration settings object -function displayCommandList(pDisplayHeader, pClear, pPause, pCanCrossPost, pConfigSettings) +// 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 +function displayCommandList(pDisplayHeader, pClear, pPause, pCanCrossPost, pIsSysop, + pTxtReplacments, pUserSettings) { if (pClear) console.clear("\1n"); @@ -1392,7 +1290,7 @@ function displayCommandList(pDisplayHeader, pClear, pPause, pCanCrossPost, pConf console.crlf(); } - var isSysop = (pConfigSettings.userIsSysop != null ? pConfigSettings.userIsSysop : user.compare_ars("SYSOP")); + var isSysop = (pIsSysop != null ? pIsSysop : user.compare_ars("SYSOP")); // This function displays a key and its description with formatting & colors. // @@ -1428,9 +1326,9 @@ function displayCommandList(pDisplayHeader, pClear, pPause, pCanCrossPost, pConf displayCmdKeyFormattedDouble("Ctrl-G", "General help", "/A", "Abort", true); displayCmdKeyFormattedDouble("Ctrl-L", "Command key list (this list)", "/S", "Save", true); displayCmdKeyFormattedDouble("Ctrl-R", "Program information", "/Q", "Quote message", true); - if (pConfigSettings.enableTextReplacements) + if (pTxtReplacments) displayCmdKeyFormattedDouble("Ctrl-T", "List text replacements", "/T", "List text replacements", true); - if (pConfigSettings.allowUserSettings) + if (pUserSettings) displayCmdKeyFormattedDouble("", "", "/U", "Your settings", true); if (pCanCrossPost) displayCmdKeyFormattedDouble("", "", "/C", "Cross-post selection", true); @@ -1447,18 +1345,12 @@ function displayCommandList(pDisplayHeader, pClear, pPause, pCanCrossPost, pConf displayCmdKeyFormattedDouble("ESC", "Command menu", "Ctrl-C", "Cross-post selection", true); else displayCmdKeyFormatted("ESC", "Command menu", true); - var nextKeys = []; - if (pConfigSettings.allowUserSettings) - nextKeys.push({keyStr: "Ctrl-U", desc: "Your settings"}); - if (gConfigSettings.allowColorSelection) - nextKeys.push({keyStr: "Ctrl-K", desc: "Choose text color"}); - if (nextKeys.length == 1) - displayCmdKeyFormatted(nextKeys[0].keyStr, nextKeys[0].desc, true); - else if (nextKeys.length == 2) - displayCmdKeyFormattedDouble(nextKeys[0].keyStr, nextKeys[0].desc, nextKeys[1].keyStr, nextKeys[1].desc, true); if (isSysop) displayCmdKeyFormattedDouble("Ctrl-O", "Import a file", "Ctrl-X", "Export to file", true); + if (pUserSettings) + displayCmdKeyFormatted("Ctrl-U", "Your settings", true); + if (pPause) { // TODO: I doubt this needs consolePauseWithESCChars() anymore.. @@ -1627,6 +1519,7 @@ function promptYesNo(pQuestion, pDefaultYes, pBoxTitle, pIceRefreshForBothAnswer function ReadSlyEditConfigFile() { var cfgObj = new Object(); // Configuration object + cfgObj.userIsSysop = user.compare_ars("SYSOP"); // Whether or not the user is a sysop // Default settings cfgObj.thirdPartyLoadOnStart = new Array(); @@ -1638,10 +1531,6 @@ function ReadSlyEditConfigFile() cfgObj.inputTimeoutMS = 300000; cfgObj.reWrapQuoteLines = true; cfgObj.allowColorSelection = true; - cfgObj.noColorSelectionGrpNames = []; - cfgObj.noColorSelectionSubBoardCodes = []; - cfgObj.cvtColorToANSIGrpNames = []; - cfgObj.cvtColorToANSISubBoardCodes = []; cfgObj.useQuoteLineInitials = true; cfgObj.indentQuoteLinesWithInitials = true; cfgObj.allowCrossPosting = true; @@ -1685,6 +1574,8 @@ function ReadSlyEditConfigFile() cfgObj.iceColors.menuOptClassicColors = true; // Ice color theme file cfgObj.iceColors.ThemeFilename = genFullPathCfgFilename("SlyIceColors_BlueIce.cfg", gStartupPath); + // Text edit color + cfgObj.iceColors.TextEditColor = "\1n\1w"; // Quote line color cfgObj.iceColors.QuoteLineColor = "\1n\1c"; // Ice colors for the quote window @@ -1714,6 +1605,8 @@ function ReadSlyEditConfigFile() cfgObj.DCTColors = new Object(); // DCT color theme file cfgObj.DCTColors.ThemeFilename = genFullPathCfgFilename("SlyDCTColors_Default.cfg", gStartupPath); + // Text edit color + cfgObj.DCTColors.TextEditColor = "\1n\1w"; // Quote line color cfgObj.DCTColors.QuoteLineColor = "\1n\1c"; // DCT colors for the border stuff @@ -1847,49 +1740,6 @@ function ReadSlyEditConfigFile() cfgObj.reWrapQuoteLines = (valueUpper == "TRUE"); else if (settingUpper == "ALLOWCOLORSELECTION") cfgObj.allowColorSelection = (valueUpper == "TRUE"); - else if (settingUpper == "NOCOLORSELECTIONGRPNAMES") - { - // Message group names for message groups where text - // color selection isn't allowed. Split on commas. - // I was originally going to have this be a list of - // numbers for the group numbers/indexes and check - // against msg_area.grp_list, but that group list could - // be different for different users, depending on access - // requirements. - cfgObj.noColorSelectionGrpNames = valueUpper.split(","); - } - else if (settingUpper == "NOCOLORSELECTIONSUBBOARDCODES") - { - // Sub-board codes for sub-boards where text color selection - // isn't allowed. Split on commas, and convert all to - // lowercase, since sub-board codes need to be lowercase. - var values = value.toLowerCase().split(","); - for (var i = 0; i < values.length; ++i) - { - if (msg_area.sub.hasOwnProperty(values[i])) - cfgObj.noColorSelectionSubBoardCodes.push(values[i]); - } - } - else if (settingUpper == "CVTCOLORTOANSIGRPNAMES") - { - if ((value == "*") || (valueUpper == "ALL")) - { - for (var i = 0; i < msg_area.grp_list.length; ++i) - cfgObj.cvtColorToANSIGrpNames.push(msg_area.grp_list[i].name.toUpperCase()); - cfgObj.cvtColorToANSIGrpNames.push("ELECTRONIC MAIL"); - } - else - cfgObj.cvtColorToANSIGrpNames = valueUpper.split(","); - } - else if (settingUpper == "CVTCOLORTOANSISUBBOARDCODES") - { - var values = value.toLowerCase().split(","); - for (var i = 0; i < values.length; ++i) - { - if (msg_area.sub.hasOwnProperty(values[i])) - cfgObj.cvtColorToANSISubBoardCodes.push(values[i]); - } - } else if (settingUpper == "USEQUOTELINEINITIALS") cfgObj.useQuoteLineInitials = (valueUpper == "TRUE"); else if (settingUpper == "INDENTQUOTELINESWITHINITIALS") @@ -1965,75 +1815,73 @@ function ReadSlyEditConfigFile() // pFilename: The name of the configuration file. // pLineReadLen: The maximum number of characters to read from each // line. This is optional; if not specified, then up -// to 2048 characters will be read from each line. -// pCvtSyncColorAttrChar: Optional boolean - Whether or not to convert -// \1 in color values to ASCII char 1 in color values +// to 512 characters will be read from each line. // // Return value: An Object containing the value=setting pairs. If the // file can't be opened or no settings can be read, then // this function will return null. -function readValueSettingConfigFile(pFilename, pLineReadLen, pCvtSyncColorAttrChar) +function readValueSettingConfigFile(pFilename, pLineReadLen) { - var retObj = null; + var retObj = null; - var cfgFile = new File(pFilename); - if (cfgFile.open("r")) - { - var cvtSyncColorAttrChar = (typeof(pCvtSyncColorAttrChar) == "boolean" ? pCvtSyncColorAttrChar : false); - var numCharsPerLine = (typeof(pLineReadLen) == "number" ? pLineReadLen : 2048); - - var fileLine = null; // A line read from the file - var equalsPos = 0; // Position of a = in the line - var commentPos = 0; // Position of the start of a comment - var setting = null; // A setting name (string) - var settingUpper = null; // Upper-case setting name - var value = null; // A value for a setting (string) - var valueUpper = null; // Upper-cased value - while (!cfgFile.eof) - { - // Read the next line from the config file. - fileLine = cfgFile.readln(numCharsPerLine); - - // fileLine should be a string, but I've seen some cases - // where it isn't, so check its type. - if (typeof(fileLine) != "string") - continue; - - // If the line starts with with a semicolon (the comment - // character) or is blank, then skip it. - if ((fileLine.substr(0, 1) == ";") || (fileLine.length == 0)) - continue; + var cfgFile = new File(pFilename); + if (cfgFile.open("r")) + { + // Set the number of characters to read per line. + var numCharsPerLine = 512; + if (pLineReadLen != null) + numCharsPerLine = pLineReadLen; + + var fileLine = null; // A line read from the file + var equalsPos = 0; // Position of a = in the line + var commentPos = 0; // Position of the start of a comment + var setting = null; // A setting name (string) + var settingUpper = null; // Upper-case setting name + var value = null; // A value for a setting (string) + var valueUpper = null; // Upper-cased value + while (!cfgFile.eof) + { + // Read the next line from the config file. + fileLine = cfgFile.readln(numCharsPerLine); - // If the line has a semicolon anywhere in it, then remove - // everything from the semicolon onward. - commentPos = fileLine.indexOf(";"); - if (commentPos > -1) - fileLine = fileLine.substr(0, commentPos); + // fileLine should be a string, but I've seen some cases + // where it isn't, so check its type. + if (typeof(fileLine) != "string") + continue; - // Look for an equals sign, and if found, separate the line - // into the setting name (before the =) and the value (after the - // equals sign). - equalsPos = fileLine.indexOf("="); - if (equalsPos > 0) - { - // If retObj hasn't been created yet, then create it. - if (retObj == null) - retObj = new Object(); + // If the line starts with with a semicolon (the comment + // character) or is blank, then skip it. + if ((fileLine.substr(0, 1) == ";") || (fileLine.length == 0)) + continue; - // Read the setting & value, and trim leading & trailing spaces. Then - // set the value in retObj. - setting = trimSpaces(fileLine.substr(0, equalsPos), true, false, true); - value = trimSpaces(fileLine.substr(equalsPos+1), true, false, true); - if (cvtSyncColorAttrChar) // Replace \1 with the SOH character, for Sync color codes - value = value.replace(/\\1/g, "\1"); - retObj[setting] = value; - } - } + // If the line has a semicolon anywhere in it, then remove + // everything from the semicolon onward. + commentPos = fileLine.indexOf(";"); + if (commentPos > -1) + fileLine = fileLine.substr(0, commentPos); + + // Look for an equals sign, and if found, separate the line + // into the setting name (before the =) and the value (after the + // equals sign). + equalsPos = fileLine.indexOf("="); + if (equalsPos > 0) + { + // If retObj hasn't been created yet, then create it. + if (retObj == null) + retObj = new Object(); + + // Read the setting & value, and trim leading & trailing spaces. Then + // set the value in retObj. + setting = trimSpaces(fileLine.substr(0, equalsPos), true, false, true); + value = trimSpaces(fileLine.substr(equalsPos+1), true, false, true); + retObj[setting] = value; + } + } - cfgFile.close(); - } + cfgFile.close(); + } - return retObj; + return retObj; } // Splits a string up by a maximum length, preserving whole words. @@ -2111,25 +1959,24 @@ function splitStrStable(pStr, pMaxLen) // Return value: The spliced string function spliceIntoStr(pStr, pIndex, pStr2) { - // Error checking - var typeofPStr = typeof(pStr); - var typeofPStr2 = typeof(pStr2); - if ((typeofPStr != "string") && (typeofPStr2 != "string")) - return ""; - else if ((typeofPStr == "string") && (typeofPStr2 != "string")) - return pStr; - else if ((typeofPStr != "string") && (typeofPStr2 == "string")) - return pStr2; - // If pIndex is beyond the last index of pStr, then just return the - // two strings concatenated. - if (pIndex >= pStr.length) - return (pStr + pStr2); - // If pIndex is below 0, then just return pStr2 + pStr. - else if (pIndex < 0) - return (pStr2 + pStr); - - //return (pStr.substr(0, pIndex) + pStr2 + pStr.substr(pIndex)); - return (pStr.substr(0, pIndex) + pStr2 + pStr.substr(pIndex)); + // Error checking + var typeofPStr = typeof(pStr); + var typeofPStr2 = typeof(pStr2); + if ((typeofPStr != "string") && (typeofPStr2 != "string")) + return ""; + else if ((typeofPStr == "string") && (typeofPStr2 != "string")) + return pStr; + else if ((typeofPStr != "string") && (typeofPStr2 == "string")) + return pStr2; + // If pIndex is beyond the last index of pStr, then just return the + // two strings concatenated. + if (pIndex >= pStr.length) + return (pStr + pStr2); + // If pIndex is below 0, then just return pStr2 + pStr. + else if (pIndex < 0) + return (pStr2 + pStr); + + return (pStr.substr(0, pIndex) + pStr2 + pStr.substr(pIndex)); } // Fixes the text lines in the gEditLines array so that they all @@ -2144,177 +1991,170 @@ function spliceIntoStr(pStr, pIndex, pStr2) // Return value: Boolean - Whether or not any text was changed. function reAdjustTextLines(pTextLineArray, pStartIndex, pEndIndex, pEditWidth) { - // Returns without doing anything if any of the parameters are not - // what they should be. (Note: Not checking pTextLineArray for now..) - if ((typeof(pStartIndex) != "number") || (typeof(pEndIndex) != "number") || (typeof(pEditWidth) != "number")) - return false; - // Range checking - if ((pStartIndex < 0) || (pStartIndex >= pTextLineArray.length)) - return false; - if ((pEndIndex <= pStartIndex) || (pEndIndex < 0)) - return false; - if (pEndIndex > pTextLineArray.length) - pEndIndex = pTextLineArray.length; - if (pEditWidth <= 5) - return false; - - var textChanged = false; // We'll return this at the end of the function + // Returns without doing anything if any of the parameters are not + // what they should be. (Note: Not checking pTextLineArray for now..) + if (typeof(pStartIndex) != "number") + return false; + if (typeof(pEndIndex) != "number") + return false; + if (typeof(pEditWidth) != "number") + return false; + // Range checking + if ((pStartIndex < 0) || (pStartIndex >= pTextLineArray.length)) + return false; + if ((pEndIndex <= pStartIndex) || (pEndIndex < 0)) + return false; + if (pEndIndex > pTextLineArray.length) + pEndIndex = pTextLineArray.length; + if (pEditWidth <= 5) + return false; - var nextLineIndex = 0; - var numCharsToRemove = 0; - var splitIndex = 0; - var spaceFound = false; // Whether or not a space was found in a text line - var splitIndexOriginal = 0; - var tempText = null; - var appendedNewLine = false; // If we appended another line - for (var i = pStartIndex; i < pEndIndex; ++i) - { - // As an extra precaution, check to make sure this array element is defined. - if (pTextLineArray[i] == undefined) - continue; + var textChanged = false; // We'll return this upon function exit. - nextLineIndex = i + 1; - // If the line's text is longer or equal to the edit width, then if - // possible, move the last word to the beginning of the next line. - if (pTextLineArray[i].displayLength() >= pEditWidth) - { - numCharsToRemove = pTextLineArray[i].displayLength() - pEditWidth + 1; - splitIndex = pTextLineArray[i].displayIdxToActualIdx(pTextLineArray[i].displayLength() - numCharsToRemove); - splitIndexOriginal = splitIndex; - // If the character in the text line at splitIndex is not a space, - // then look for a space before splitIndex. - spaceFound = (pTextLineArray[i].text.charAt(splitIndex) == " "); - if (!spaceFound) - { - splitIndex = pTextLineArray[i].text.lastIndexOf(" ", splitIndex-1); - spaceFound = (splitIndex > -1); - if (!spaceFound) - splitIndex = splitIndexOriginal; - // If the character at splitIndex is the 2nd character in a Synchronet - // attribute code, then adjust splitIndex accordingly. - if ((splitIndex > 0) && gSyncAttrRegex.test(pTextLineArray[i].text.substr(splitIndex-1, 2))) - --splitIndex; - } + var nextLineIndex = 0; + var charsToRemove = 0; + var splitIndex = 0; + var spaceFound = false; // Whether or not a space was found in a text line + var splitIndexOriginal = 0; + var tempText = null; + var appendedNewLine = false; // If we appended another line + for (var i = pStartIndex; i < pEndIndex; ++i) + { + // As an extra precaution, check to make sure this array element is defined. + if (pTextLineArray[i] == undefined) + continue; + + nextLineIndex = i + 1; + // If the line's text is longer or equal to the edit width, then if + // possible, move the last word to the beginning of the next line. + if (pTextLineArray[i].text.length >= pEditWidth) + { + charsToRemove = pTextLineArray[i].text.length - pEditWidth + 1; + splitIndex = pTextLineArray[i].text.length - charsToRemove; + splitIndexOriginal = splitIndex; + // If the character in the text line at splitIndex is not a space, + // then look for a space before splitIndex. + spaceFound = (pTextLineArray[i].text.charAt(splitIndex) == " "); + if (!spaceFound) + { + splitIndex = pTextLineArray[i].text.lastIndexOf(" ", splitIndex-1); + spaceFound = (splitIndex > -1); + if (!spaceFound) + splitIndex = splitIndexOriginal; + } + tempText = pTextLineArray[i].text.substr(spaceFound ? splitIndex+1 : splitIndex); + pTextLineArray[i].text = pTextLineArray[i].text.substr(0, splitIndex); + textChanged = true; + // If we're on the last line, or if the current line has a hard + // newline or is a quote line, then append a new line below. + appendedNewLine = false; + if ((nextLineIndex == pTextLineArray.length) || pTextLineArray[i].hardNewlineEnd || + isQuoteLine(pTextLineArray, i)) + { + pTextLineArray.splice(nextLineIndex, 0, new TextLine()); + pTextLineArray[nextLineIndex].hardNewlineEnd = pTextLineArray[i].hardNewlineEnd; + pTextLineArray[i].hardNewlineEnd = false; + pTextLineArray[nextLineIndex].isQuoteLine = pTextLineArray[i].isQuoteLine; + appendedNewLine = true; + } - var tempText = pTextLineArray[i].text.substr(splitIndex); - // If the substring contains a space at the beginning or the end, then - // remove the space. - if (tempText.search(/^ /) == 0) - tempText = tempText.substr(1); - else if (tempText.search(/ $/) == tempText.length-1) - tempText = tempText.substr(0, tempText.length-1); - pTextLineArray[i].text = pTextLineArray[i].text.substr(0, splitIndex); - - textChanged = true; - // If we're on the last line, or if the current line has a hard - // newline or is a quote line, then append a new line below. - appendedNewLine = false; - if ((nextLineIndex == pTextLineArray.length) || pTextLineArray[i].hardNewlineEnd || isQuoteLine(pTextLineArray, i)) - { - pTextLineArray.splice(nextLineIndex, 0, new TextLine()); - pTextLineArray[nextLineIndex].hardNewlineEnd = pTextLineArray[i].hardNewlineEnd; - pTextLineArray[i].hardNewlineEnd = false; - pTextLineArray[nextLineIndex].isQuoteLine = pTextLineArray[i].isQuoteLine; - appendedNewLine = true; - } + // Move the text around and adjust the line properties. + if (appendedNewLine) + pTextLineArray[nextLineIndex].text = tempText; + else + { + // If we're in insert mode, then insert the text at the beginning of + // the next line. Otherwise, overwrite the text in the next line. + if (inInsertMode()) + pTextLineArray[nextLineIndex].text = tempText + " " + pTextLineArray[nextLineIndex].text; + else + { + // We're in overwrite mode, so overwite the first part of the next + // line with tempText. + if (pTextLineArray[nextLineIndex].text.length < tempText.length) + pTextLineArray[nextLineIndex].text = tempText; + else + { + pTextLineArray[nextLineIndex].text = tempText + + pTextLineArray[nextLineIndex].text.substr(tempText.length); + } + } + } + } + else + { + // pTextLineArray[i].text.length is < pEditWidth, so try to bring up text + // from the next line. - // Move the text around and adjust the line properties. - if (appendedNewLine) - pTextLineArray[nextLineIndex].text = tempText; - else - { - // If we're in insert mode, then insert the text at the beginning of - // the next line. Otherwise, overwrite the text in the next line. - if (inInsertMode()) - pTextLineArray[nextLineIndex].text = tempText + " " + pTextLineArray[nextLineIndex].text; - else - { - // We're in overwrite mode, so overwrite the first part of the next - // line with tempText. - if (pTextLineArray[nextLineIndex].text.length < tempText.length) - pTextLineArray[nextLineIndex].text = tempText; - else - pTextLineArray[nextLineIndex].text = tempText + pTextLineArray[nextLineIndex].text.substr(tempText.length); - } - } - } - else - { - // pTextLineArray[i].text.length is < pEditWidth, so try to bring up text - // from the next line. + // Only do it if the line doesn't have a hard newline and it's not a + // quote line and there is a next line. + if (!pTextLineArray[i].hardNewlineEnd && !isQuoteLine(pTextLineArray, i) && + (i < pTextLineArray.length-1)) + { + if (pTextLineArray[nextLineIndex].text.length > 0) + { + splitIndex = pEditWidth - pTextLineArray[i].text.length - 2; + // If splitIndex is negative, that means the entire next line + // can fit on the current line. + if ((splitIndex < 0) || (splitIndex > pTextLineArray[nextLineIndex].text.length)) + splitIndex = pTextLineArray[nextLineIndex].text.length; + else + { + // If the character in the next line at splitIndex is not a + // space, then look for a space before it. + if (pTextLineArray[nextLineIndex].text.charAt(splitIndex) != " ") + splitIndex = pTextLineArray[nextLineIndex].text.lastIndexOf(" ", splitIndex); + // If no space was found, then skip to the next line (we don't + // want to break up words from the next line). + if (splitIndex == -1) + continue; + } - // Only do it if the line doesn't have a hard newline and it's not a - // quote line and there is a next line. - if (!pTextLineArray[i].hardNewlineEnd && !isQuoteLine(pTextLineArray, i) && (i < pTextLineArray.length-1)) - { - if (pTextLineArray[nextLineIndex].text.length > 0) - { - splitIndex = pEditWidth - pTextLineArray[i].text.length - 2; - // If splitIndex is negative, that means the entire next line - // can fit on the current line. - if ((splitIndex < 0) || (splitIndex > pTextLineArray[nextLineIndex].text.length)) - splitIndex = pTextLineArray[nextLineIndex].text.length; - else - { - // If the character in the next line at splitIndex is not a - // space, then look for a space before it. - if (pTextLineArray[nextLineIndex].text.charAt(splitIndex) != " ") - splitIndex = pTextLineArray[nextLineIndex].text.lastIndexOf(" ", splitIndex); - // If no space was found, then skip to the next line (we don't - // want to break up words from the next line). - if (splitIndex == -1) - continue; - } - // If the character at splitIndex is the 2nd character in a Synchronet - // attribute code, then adjust splitIndex accordingly. - if ((splitIndex > 0) && gSyncAttrRegex.test(pTextLineArray[nextLineIndex].text.substr(splitIndex-1, 2))) - --splitIndex; - - // Get the text to bring up to the current line. - // If the current line does not end with a space and the next line - // does not start with a space, then add a space between this line - // and the next line's text. This is done to avoid joining words - // accidentally. - var tempText = ""; - if ((pTextLineArray[i].text.charAt(pTextLineArray[i].text.length-1) != " ") && - (pTextLineArray[nextLineIndex].text.substr(0, 1) != " ")) - { - tempText = " "; - } - tempText += pTextLineArray[nextLineIndex].text.substr(0, splitIndex); - // Move the text from the next line to the current line, if the current - // line has room for it. - if (pTextLineArray[i].text.length + tempText.length < pEditWidth) - { - pTextLineArray[i].text += tempText; - pTextLineArray[nextLineIndex].text = pTextLineArray[nextLineIndex].text.substr(splitIndex+1); - textChanged = true; + // Get the text to bring up to the current line. + // If the current line does not end with a space and the next line + // does not start with a space, then add a space between this line + // and the next line's text. This is done to avoid joining words + // accidentally. + tempText = ""; + if ((pTextLineArray[i].text.charAt(pTextLineArray[i].text.length-1) != " ") && + (pTextLineArray[nextLineIndex].text.substr(0, 1) != " ")) + { + tempText = " "; + } + tempText += pTextLineArray[nextLineIndex].text.substr(0, splitIndex); + // Move the text from the next line to the current line, if the current + // line has room for it. + if (pTextLineArray[i].text.length + tempText.length < pEditWidth) + { + pTextLineArray[i].text += tempText; + pTextLineArray[nextLineIndex].text = pTextLineArray[nextLineIndex].text.substr(splitIndex+1); + textChanged = true; - // If the next line is now blank, then remove it. - if (pTextLineArray[nextLineIndex].text.length == 0) - { - // The current line should take on the next line's - // hardnewlineEnd property before removing the next line. - pTextLineArray[i].hardNewlineEnd = pTextLineArray[nextLineIndex].hardNewlineEnd; - pTextLineArray.splice(nextLineIndex, 1); - } - } - } - else - { - // The next line's text string is blank. If its hardNewlineEnd - // property is false, then remove the line. - if (!pTextLineArray[nextLineIndex].hardNewlineEnd) - { - pTextLineArray.splice(nextLineIndex, 1); - textChanged = true; - } - } - } - } - } + // If the next line is now blank, then remove it. + if (pTextLineArray[nextLineIndex].text.length == 0) + { + // The current line should take on the next line's + // hardnewlineEnd property before removing the next line. + pTextLineArray[i].hardNewlineEnd = pTextLineArray[nextLineIndex].hardNewlineEnd; + pTextLineArray.splice(nextLineIndex, 1); + } + } + } + else + { + // The next line's text string is blank. If its hardNewlineEnd + // property is false, then remove the line. + if (!pTextLineArray[nextLineIndex].hardNewlineEnd) + { + pTextLineArray.splice(nextLineIndex, 1); + textChanged = true; + } + } + } + } + } - return textChanged; + return textChanged; } // Returns indexes of the first unquoted text line and the next @@ -2393,7 +2233,13 @@ function isQuoteLine(pLineArray, pLineIndex) var lineIsQuoteLine = false; if (typeof(pLineArray[pLineIndex]) != "undefined") + { + /* + lineIsQuoteLine = ((pLineArray[pLineIndex].isQuoteLine) || + (/^ *>/.test(pLineArray[pLineIndex].text))); + */ lineIsQuoteLine = (pLineArray[pLineIndex].isQuoteLine); + } return lineIsQuoteLine; } @@ -2409,73 +2255,73 @@ function isQuoteLine(pLineArray, pLineIndex) // control character) function toggleAttr(pAttrType, pAttrs, pNewAttr) { - // Removes an attribute from an attribute string, if it - // exists. Returns the new attribute string. - function removeAttrIfExists(pAttrs, pNewAttr) - { - var index = pAttrs.search(pNewAttr); - if (index > -1) - pAttrs = pAttrs.replace(pNewAttr, ""); - return pAttrs; - } - - // Convert pAttrs and pNewAttr to all uppercase for ease of searching - pAttrs = pAttrs.toUpperCase(); - pNewAttr = pNewAttr.toUpperCase(); - - // If pAttrs starts with the normal attribute, then - // remove it (we'll put it back on later). - var normalAtStart = false; - if (pAttrs.search(/^N/) == 0) - { - normalAtStart = true; - pAttrs = pAttrs.substr(2); - } + // Removes an attribute from an attribute string, if it + // exists. Returns the new attribute string. + function removeAttrIfExists(pAttrs, pNewAttr) + { + var index = pAttrs.search(pNewAttr); + if (index > -1) + pAttrs = pAttrs.replace(pNewAttr, ""); + return pAttrs; + } - // Prepend the attribute control character to the new attribute - var newAttr = "" + pNewAttr; + // Convert pAttrs and pNewAttr to all uppercase for ease of searching + pAttrs = pAttrs.toUpperCase(); + pNewAttr = pNewAttr.toUpperCase(); - // Set a regex for searching & replacing - var regex = ""; - switch (pAttrType) - { - case FORE_ATTR: // Foreground attribute - regex = /K|R|G|Y|B|M|C|W/g; - break; - case BKG_ATTR: // Background attribute - regex = /0|1|2|3|4|5|6|7/g; - break; - case SPECIAL_ATTR: // Special attribute - //regex = /H|I|N/g; - index = pAttrs.search(newAttr); - if (index > -1) - pAttrs = pAttrs.replace(newAttr, ""); - else - pAttrs += newAttr; - break; - default: - break; - } + // If pAttrs starts with the normal attribute, then + // remove it (we'll put it back on later). + var normalAtStart = false; + if (pAttrs.search(/^N/) == 0) + { + normalAtStart = true; + pAttrs = pAttrs.substr(2); + } - // If regex is not blank, then search & replace on it in - // pAttrs. - if (regex != "") - { - pAttrs = removeAttrIfExists(pAttrs, newAttr); - // If the regex is found, then replace it. Otherwise, - // add pNewAttr to the attribute string. - if (pAttrs.search(regex) > -1) - pAttrs = pAttrs.replace(regex, "" + pNewAttr); - else - pAttrs += "" + pNewAttr; - } + // Prepend the attribute control character to the new attribute + var newAttr = "" + pNewAttr; + + // Set a regex for searching & replacing + var regex = ""; + switch (pAttrType) + { + case FORE_ATTR: // Foreground attribute + regex = /K|R|G|Y|B|M|C|W/g; + break; + case BKG_ATTR: // Background attribute + regex = /0|1|2|3|4|5|6|7/g; + break; + case SPECIAL_ATTR: // Special attribute + //regex = /H|I|N/g; + index = pAttrs.search(newAttr); + if (index > -1) + pAttrs = pAttrs.replace(newAttr, ""); + else + pAttrs += newAttr; + break; + default: + break; + } + + // If regex is not blank, then search & replace on it in + // pAttrs. + if (regex != "") + { + pAttrs = removeAttrIfExists(pAttrs, newAttr); + // If the regex is found, then replace it. Otherwise, + // add pNewAttr to the attribute string. + if (pAttrs.search(regex) > -1) + pAttrs = pAttrs.replace(regex, "" + pNewAttr); + else + pAttrs += "" + pNewAttr; + } - // If pAttrs started with the normal attribute, then - // put it back on. - if (normalAtStart) - pAttrs = "N" + pAttrs; + // If pAttrs started with the normal attribute, then + // put it back on. + if (normalAtStart) + pAttrs = "N" + pAttrs; - return pAttrs; + return pAttrs; } // This function wraps an array of strings based on a line width. @@ -3679,38 +3525,37 @@ function postMsgToSubBoard(pSubBoardCode, pTo, pSubj, pMessage, pFromUserNum) // sigContents: String - The user's message signature function readUserSigFile() { - var retObj = { - sigFileExists: false, - sigContents: "" - }; - - // The user signature files are located in sbbs/data/user, and the filename - // is the user number (zero-padded up to 4 digits) + .sig - var userSigFilename = backslash(system.data_dir + "user") + format("%04d.sig", user.number); - retObj.sigFileExists = file_exists(userSigFilename); - if (retObj.sigFileExists) - { - var msgSigFile = new File(userSigFilename); - if (msgSigFile.open("r")) - { - var fileLine = ""; // A line read from the file - while (!msgSigFile.eof) - { - fileLine = msgSigFile.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; - - retObj.sigContents += fileLine + "\r\n"; - } + var retObj = new Object(); + retObj.sigFileExists = false; + retObj.sigContents = ""; + + // The user signature files are located in sbbs/data/user, and the filename + // is the user number (zero-padded up to 4 digits) + .sig + var userSigFilename = backslash(system.data_dir + "user") + format("%04d.sig", user.number); + retObj.sigFileExists = file_exists(userSigFilename); + if (retObj.sigFileExists) + { + var msgSigFile = new File(userSigFilename); + if (msgSigFile.open("r")) + { + var fileLine = ""; // A line read from the file + while (!msgSigFile.eof) + { + fileLine = msgSigFile.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; + + retObj.sigContents += fileLine + "\r\n"; + } - msgSigFile.close(); - } - } + msgSigFile.close(); + } + } - return retObj; + return retObj; } // Returns the sub-board code and group index for the first sub-board @@ -3760,80 +3605,73 @@ function getFirstPostableSubInfo() // Return value: The number of text replacements added to the array. function populateTxtReplacements(pArray, pRegex) { - var numTxtReplacements = 0; - - // Note: Limited to words without spaces. - // Open the word replacements configuration file - var wordReplacementsFilename = genFullPathCfgFilename("SlyEdit_TextReplacements.cfg", gStartupPath); - var arrayPopulated = false; - var wordFile = new File(wordReplacementsFilename); - if (wordFile.open("r")) - { - var fileLine = null; // A line read from the file - var equalsPos = 0; // Position of a = in the line - var wordToSearch = null; // A word to be replaced - var wordToSearchUpper = null; - var substWord = null; // The word to substitute - // This tests numTxtReplacements < 9999 so that the 9999th one is the last - // one read. - while (!wordFile.eof && (numTxtReplacements < 9999)) - { - // Read the next line from the file. - fileLine = wordFile.readln(2048); + var numTxtReplacements = 0; + + // Note: Limited to words without spaces. + // Open the word replacements configuration file + var wordReplacementsFilename = genFullPathCfgFilename("SlyEdit_TextReplacements.cfg", gStartupPath); + var arrayPopulated = false; + var wordFile = new File(wordReplacementsFilename); + if (wordFile.open("r")) + { + var fileLine = null; // A line read from the file + var equalsPos = 0; // Position of a = in the line + var wordToSearch = null; // A word to be replaced + var wordToSearchUpper = null; + var substWord = null; // The word to substitue + // This tests numTxtReplacements < 9999 so that the 9999th one is the last + // one read. + while (!wordFile.eof && (numTxtReplacements < 9999)) + { + // Read the next line from the config file. + fileLine = wordFile.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; - // If the line starts with with a semicolon (the comment - // character) or is blank, then skip it. - if ((fileLine.substr(0, 1) == ";") || (fileLine.length == 0)) - continue; + // 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; + // If the line starts with with a semicolon (the comment + // character) or is blank, then skip it. + if ((fileLine.substr(0, 1) == ";") || (fileLine.length == 0)) + continue; - // Look for an equals sign, and if found, separate the line - // into the setting name (before the =) and the value (after the - // equals sign). - equalsPos = fileLine.indexOf("="); - if (equalsPos <= 0) - continue; // = not found or is at the beginning, so go on to the next line - - // Replace \1 with the SOH character so it can be used for - // Synchronet color/attribute codes - fileLine = fileLine.replace(/\\1/g, "\1"); - - // Extract the word to search and substitution word from the line. If - // not using regular expressions, then convert the word to search to - // all uppercase for case-insensitive searching. - wordToSearch = trimSpaces(fileLine.substr(0, equalsPos), true, false, true); - wordToSearchUpper = wordToSearch.toUpperCase(); - substWord = trimSpaces(fileLine.substr(equalsPos+1), true, false, true); - // Make sure substWord only contains printable characters. If not, then - // skip this one. - var substIsPrintable = true; - for (var i = 0; (i < substWord.length) && substIsPrintable; ++i) - { - var currentChar = substWord.charAt(i); - substIsPrintable = (isPrintableChar(currentChar) || (currentChar == "\1")); - } - if (!substIsPrintable) - continue; + // Look for an equals sign, and if found, separate the line + // into the setting name (before the =) and the value (after the + // equals sign). + equalsPos = fileLine.indexOf("="); + if (equalsPos <= 0) + continue; // = not found or is at the beginning, so go on to the next line + + // Extract the word to search and substitution word from the line. If + // not using regular expressions, then convert the word to search to + // all uppercase for case-insensitive searching. + wordToSearch = trimSpaces(fileLine.substr(0, equalsPos), true, false, true); + wordToSearchUpper = wordToSearch.toUpperCase(); + substWord = strip_ctrl(trimSpaces(fileLine.substr(equalsPos+1), true, false, true)); + // Make sure substWord only contains printable characters. If not, then + // skip this one. + var substIsPrintable = true; + for (var i = 0; (i < substWord.length) && substIsPrintable; ++i) + substIsPrintable = isPrintableChar(substWord.charAt(i)); + if (!substIsPrintable) + continue; - // And add the search word and replacement text to pArray. - if (wordToSearchUpper != substWord.toUpperCase()) - { - if (pRegex) - pArray[wordToSearch] = substWord; - else - pArray[wordToSearchUpper] = substWord; - ++numTxtReplacements; - } - } + // And add the search word and replacement text to pArray. + if (wordToSearchUpper != substWord.toUpperCase()) + { + if (pRegex) + pArray[wordToSearch] = substWord; + else + pArray[wordToSearchUpper] = substWord; + ++numTxtReplacements; + } + } - wordFile.close(); - } + wordFile.close(); + } - return numTxtReplacements; + return numTxtReplacements; } function moveGenColorsToGenSettings(pColorsArray, pCfgObj) @@ -4515,637 +4353,25 @@ function getKeyWithESCChars(pGetKeyMode, pCfgObj) return userInput; } -// Returns the index of the first Synchronet attribute code before a given index -// in a string. -// -// Parameters: -// pStr: The string to search in -// pIdx: The index to search back from -// pSeriesOfAttrs: Optional boolean - Whether or not to look for a series of -// attributes. Defaults to false (look for just one attribute). -// pOnlyInWord: Optional boolean - Whether or not to look only in the current word -// (with words separated by whitespace). Defaults to false. -// -// Return value: The index of the first Synchronet attribute code before the given -// index in the string, or -1 if there is none or if the parameters -// are invalid -function strIdxOfSyncAttrBefore(pStr, pIdx, pSeriesOfAttrs, pOnlyInWord) -{ - if (typeof(pStr) != "string") - return -1; - if (typeof(pIdx) != "number") - return -1; - if ((pIdx < 0) || (pIdx >= pStr.length)) - return -1; - - var seriesOfAttrs = (typeof(pSeriesOfAttrs) == "boolean" ? pSeriesOfAttrs : false); - var onlyInWord = (typeof(pOnlyInWord) == "boolean" ? pOnlyInWord : false); - - var attrCodeIdx = pStr.lastIndexOf("\1", pIdx-1); - if (attrCodeIdx > -1) - { - // If we are to only check the current word, then continue only if - // there isn't a space between the attribute code and the given index. - if (onlyInWord) - { - if (pStr.lastIndexOf(" ", pIdx-1) >= attrCodeIdx) - attrCodeIdx = -1; - } - } - if (attrCodeIdx > -1) - { - var syncAttrRegexWholeWord = /^\1[krgybmcw01234567hinpq,;\.dtl<>\[\]asz]$/i; - if (syncAttrRegexWholeWord.test(pStr.substr(attrCodeIdx, 2))) - { - if (seriesOfAttrs) - { - for (var i = attrCodeIdx - 2; i >= 0; i -= 2) - { - if (syncAttrRegexWholeWord.test(pStr.substr(i, 2))) - attrCodeIdx = i; - else - break; - } - } - } - else - attrCodeIdx = -1; - } - return attrCodeIdx; -} - -// Gets a substring for a string, including preceding Synchronet color codes -// for the word at the given start index. -// -// Parameters: -// pStr: The string to get the substring from -// pStartIdx: The index in the string where the substring should start -// pLen: The length of the substring to get. Optional - If not specified, -// the rest of the string will be used. -// -// Return value: An object with the following properties: -// strSub: The substring from the string, including any Synchronet -// color codes that may exist preceding the word at pStartIdx -// startIdx: The actual index in the string where the substring starts -// (-1 if an error occurred) -// endIdx: The actual index in the string where the substring ends. -// This is the index of the last character in the substring. -// Will be -1 if an error occurred. -// len: The actual length of the substring -// printableLen: The length of the string as it would appear on the screen -// (i.e., its length without Synchronet attribute codes) -// syncAttrStartIdx: The starting index of Synchronet attributes -// (-1 if not found or an error occurred) -// syncAttrEndIdx: The ending index of Synchronet attributes, including -// the last character (-1 if not found or an error occurred) -function substrWithSyncColorCodes(pStr, pStartIdx, pLen) -{ - var retObj = { - strSub: "", - startIdx: -1, - endIdx: -1, - len: 0, - printableLen: 0, - syncAttrStartIdx: -1, - syncAttrEndIdx: -1, - clear: function() { - this.strSub = ""; - this.startIdx = -1; - this.endIdx = -1; - this.len = 0; - this.printableLen = 0; - this.syncAttrStartIdx = -1; - this.syncAttrEndIdx = -1; - } - }; - - if (typeof(pStr) != "string") - return retObj; - if (typeof(pStartIdx) != "number") - return retObj; - if ((pStartIdx < 0) || (pStartIdx >= pStr.length)) - return retObj; - - var substrLen = (typeof(pLen) == "number" ? pLen : pStr.length-pStartIdx); - if (substrLen > pStr.length) - substrLen = pStr.length - pStartIdx + 1; - - // If there are Synchronet attribute codes at the given index, then find out - // where the attribute codes end and extend the length to include those with - // the printable text. - retObj.startIdx = pStartIdx; - retObj.len = substrLen; - if (pStr.substr(pStartIdx).search(gSyncAttrRegex) == 0) - { - retObj.syncAttrStartIdx = pStartIdx; - retObj.syncAttrEndIdx = regexLastIndexOf(pStr, gSyncAttrRegex, pStartIdx, pStartIdx+substrLen); - if (retObj.syncAttrEndIdx > -1) - { - ++retObj.syncAttrEndIdx; // This index should be the last character in the Sync attributes - retObj.len += (retObj.syncAttrEndIdx - pStartIdx + 1); - } - } - else - { - var attrInfo = getAttrsAndIndexesBeforeStrIdx(pStr, pStartIdx); - retObj.syncAttrStartIdx = attrInfo.syncAttrStartIdx; - retObj.syncAttrEndIdx = attrInfo.syncAttrEndIdx; - if ((retObj.syncAttrStartIdx > -1) && (retObj.syncAttrEndIdx > -1)) - { - // Map the given start index to the actual index in the string - retObj.startIdx = strDisplayIdxToActualIdx(pStr, pStartIdx); - // Older code which has a bug - Doesn't map a 'on-screen' string - // index to an actual string index correctly if an attribute code - // happens to appear in the string right before pStartIdx: - /* - if (retObj.syncAttrEndIdx == pStartIdx-1) - { - var lenDiff = retObj.syncAttrEndIdx - retObj.syncAttrStartIdx + 1; - retObj.startIdx -= lenDiff; - retObj.len += lenDiff; - } - else - retObj.startIdx = strDisplayIdxToActualIdx(pStr, pStartIdx); - */ - } - else - { - // Found no attribute codes before the start index. - // See if there are any Synchronet attribute codes between the - // start index & within the length. If so, then adjust the length - // accordingly: Add Synchronet attribute code lengths to the substring - // length to account for them in the string. - var endIdx = pStartIdx + substrLen; - var i = pStartIdx; - while (i < endIdx) - { - if (gSyncAttrRegex.test(pStr.substr(i, 2))) - { - i += 2; - retObj.len += 2; - } - else - ++i; - } - } - } - retObj.endIdx = retObj.startIdx + retObj.len - 1; - retObj.strSub = pStr.substr(retObj.startIdx, retObj.len); - retObj.printableLen = strip_ctrl(retObj.strSub).length; - return retObj; -} - -// Returns the index of the last-occurring instance of a given regular expression -// in a string. -// -// Parameters: -// pStr: The string to look in -// pRegex: The regular expression to look for -// pStartIdx: Optional - The index of the starting character in the string -// pEndIdx: Optional - The index of the last character in the string to check -// -// Return value: The index of the last-occuring instance of the given regular -// expression, or -1 if not found. -function regexLastIndexOf(pStr, pRegex, pStartIdx, pEndIdx) -{ - if (typeof(pStr) != "string") - return -1; - var startIdx = (typeof(pEndIdx) == "number" ? pStartIdx : 0); - if ((startIdx < 0) || (startIdx >= pStr.length)) - return -1; - var endIdx = (typeof(pEndIdx) == "number" ? pEndIdx : pStr.length-1); - if ((endIdx < 0) || (endIdx >= pStr.length)) - return -1; - - var lastIdx = -1; - for (var i = endIdx; (i >= startIdx) && (lastIdx == -1); --i) - { - if (pStr.substr(i).search(pRegex) == 0) - lastIdx = i; - } - return lastIdx; -} - -// Finds the index of the next occurrance of a regular expression in -// a string. -// -// Parameters: -// pStr: The string to search -// pRegex: The regular expression to search for -// pStartIdx: Optional - The index of where to start in the string. -// If not specified, this value will be 0. -// -// Return value: The index of the next occurance of the regular expression, or -// -1 if not found -function strSearchNext(pStr, pRegex, pStartIdx) -{ - if (typeof(pStr) != "string") - return -1; - var startIdx = (typeof(pStartIdx) == "number" ? pStartIdx : 0); - if ((startIdx < 0) || (startIdx >= pStr.length)) - return -1; - - var subStr = (startIdx == 0 ? pStr : pStr.substr(startIdx)); - var searchIdx = subStr.search(pRegex); - if (searchIdx > -1) - searchIdx += startIdx; - return searchIdx; -} - -// Returns a string with any Synchronet color/attribute codes found in a string -// before a given index. -// -// Parameters: -// pStr: The string to search in -// pIdx: The index in the string to search before -// -// Return value: A string containing any Synchronet attribute codes found before -// the given index in the given string -function getAttrsBeforeStrIdx(pStr, pIdx) -{ - if (typeof(pStr) != "string") - return ""; - if (typeof(pIdx) != "number") - return ""; - if (pIdx < 0) - return ""; - - var idx = (pIdx < pStr.length ? pIdx : pStr.length-1); - var attrStartIdx = strIdxOfSyncAttrBefore(pStr, idx, true, false); - var attrEndIdx = strIdxOfSyncAttrBefore(pStr, idx, false, false); // Start of 2-character code - var attrsStr = ""; - if ((attrStartIdx > -1) && (attrEndIdx > -1)) - attrsStr = pStr.substring(attrStartIdx, attrEndIdx+2); - return attrsStr; -} - -// Returns an object with information about any group of Synchronet color/attribute codes -// found in a string before a given index. -// -// Parameters: -// pStr: The string to search in -// pIdx: The index in the string to search before -// -// Return value: An object containing the following properties: -// attrStr: A string containing any Synchronet attribute codes -// found before the given index in the given string. If -// none are found, this string will be empty. -// syncAttrStartIdx: The index of where the attribute codes start, or -// -1 if none were found -// syncAttrEndIdx: The index of the last character of the attribute -// codes, or -1 if none were found -function getAttrsAndIndexesBeforeStrIdx(pStr, pIdx) -{ - var retObj = { - attrStr: "", - syncAttrStartIdx: -1, - syncAttrEndIdx: -1 - }; - - if ((typeof(pStr) != "string") || (typeof(pIdx) != "number")) - return retObj; - if (pIdx < 0) - return retObj; - - var idx = (pIdx < pStr.length ? pIdx : pStr.length-1); - - // Look for indexes of any Synchronet attribute codes before the given - // index. If there are some, then set the start index after the attribute - // codes end. - retObj.syncAttrStartIdx = strIdxOfSyncAttrBefore(pStr, idx, /*false*/true, false); - if ((retObj.syncAttrStartIdx > -1) && (retObj.syncAttrStartIdx < idx)) - { - retObj.syncAttrEndIdx = regexLastIndexOf(pStr, gSyncAttrRegex, retObj.syncAttrStartIdx, idx); - if (retObj.syncAttrEndIdx == -1) - retObj.syncAttrEndIdx = regexLastIndexOf(pStr, gSyncAttrRegex, retObj.syncAttrStartIdx, retObj.syncAttrStartIdx+substrLen); - if (retObj.syncAttrEndIdx > -1) - { - ++retObj.syncAttrEndIdx; // This index should be the last character in the Sync attributes - retObj.attrStr = pStr.substring(retObj.syncAttrStartIdx, retObj.syncAttrEndIdx+1); - } - } - - if (retObj.attrStr.length == 0) - { - retObj.syncAttrStartIdx = -1; - retObj.syncAttrEndIdx = -1; - } - - return retObj; -} - -// Converts a printable display index to an actual index of a string, -// ignoring Synchronet attribute codes in the string. -// -// Parameters: -// pStr: The string to check -// pDisplayIdx: The string index as displayed on the screen -// -// Return value: The index in the actual string. 0 on error -function strDisplayIdxToActualIdx(pStr, pDisplayIdx) -{ - if (typeof(pStr) != "string") - return 0; - if (typeof(pDisplayIdx) != "number") - return 0; - - var actualIdx = 0; - var strWithoutCtrlChars = strip_ctrl(pStr); - // If the given index is one past the last actual index in the string - // without control characters, then put actualIndex one past the last - // index of the string. - if (pDisplayIdx == strWithoutCtrlChars.length) - actualIdx = pStr.length; - else - { - var syncAttrIdx = pStr.search(gSyncAttrRegex); - if (syncAttrIdx > -1) - { - // Count the printable characters, ignoring Synchronet attribute codes - // I suspect there may be a more efficient way to do this.. - var numDisplayChars = pDisplayIdx + 1; - var numDisplayableCharsSeen = 0; - var i = 0; - while ((i < pStr.length) && (numDisplayableCharsSeen < numDisplayChars)) - { - if (gSyncAttrRegex.test(pStr.substr(i, 2))) - i += 2; - else - { - actualIdx = i; - ++numDisplayableCharsSeen; - ++i; - } - } - // Edge case: If pDisplayIdx was one past the last index of the string - // displayed on the screen, then increment actualIdx by 1 to fix off-by-one - if ((actualIdx == pStr.length-1) && (pDisplayIdx == strWithoutCtrlChars.length)) - ++actualIdx; - else if (pDisplayIdx == strWithoutCtrlChars.length - 1) - ++actualIdx; - } - else - actualIdx = pDisplayIdx; - } - - return actualIdx; -} - -/////////////////////////////////////////////////////////////////////////////////////// -// Color/attribute code conversion functions - -// Converts Synchronet attribute codes to ANSI -// -// Parameters: -// pText: A string containing the text to convert -// -// Return value: The text with the color codes converted -function SyncAttrsToANSI(pText) -{ - // Attributes - var txt = pText.replace(/n/gi, "[0m"); // All attributes off - txt = txt.replace(/h/gi, "[1m"); // Bold on (use high intensity) - txt = txt.replace(/i/gi, "[5m"); // Blink on - // Foreground colors - txt = txt.replace(/k/gi, "[30m"); // Black foreground - txt = txt.replace(/r/gi, "[31m"); // Red foreground - txt = txt.replace(/g/gi, "[32m"); // Green foreground - txt = txt.replace(/y/gi, "[33m"); // Yellow foreground - txt = txt.replace(/b/gi, "[34m"); // Blue foreground - txt = txt.replace(/m/gi, "[35m"); // Magenta foreground - txt = txt.replace(/c/gi, "[36m"); // Cyan foreground - txt = txt.replace(/w/gi, "[37m"); // White foreground - // Background colors - txt = txt.replace(/0/g, "[40m"); // Black background - txt = txt.replace(/1/g, "[41m"); // Red background - txt = txt.replace(/2/g, "[42m"); // Green background - txt = txt.replace(/3/g, "[43m"); // Yellow background - txt = txt.replace(/4/g, "[44m"); // Blue background - txt = txt.replace(/5/g, "[45m"); // Magenta background - txt = txt.replace(/6/g, "[46m"); // Cyan background - txt = txt.replace(/7/g, "[47m"); // White background - return txt; -} - -// Given some text, this converts ANSI color codes to Synchronet codes and -// removes unwanted ANSI codes (such as cursor movement codes, etc.). -// -// Parameters: -// pText: A string to process -// -// Return value: A version of the string with Synchronet color codes converted to -// Synchronet attribute codes and unwanted ANSI codes removed -function cvtANSIToSyncAndRemoveUnwantedANSI(pText) -{ - // Attributes - var txt = pText.replace(/\[0[mM]/g, "\1n"); // All attributes off - txt = txt.replace(/\[1m/gi, "\1h"); // Bold on (use high intensity) - txt = txt.replace(/\[5m/gi, "\1i"); // Blink on - // Foreground colors - txt = txt.replace(/\[30m/gi, "\1k"); // Black foreground - txt = txt.replace(/\[31m/gi, "\1r"); // Red foreground - txt = txt.replace(/\[32m/gi, "\1g"); // Green foreground - txt = txt.replace(/\[33m/gi, "\1y"); // Yellow foreground - txt = txt.replace(/\[34m/gi, "\1b"); // Blue foreground - txt = txt.replace(/\[35m/gi, "\1m"); // Magenta foreground - txt = txt.replace(/\[36m/gi, "\1c"); // Cyan foreground - txt = txt.replace(/\[37m/gi, "\1w"); // White foreground - // Background colors - txt = txt.replace(/\[40m/gi, "\1" + "0"); // Black background - txt = txt.replace(/\[41m/gi, "\1" + "1"); // Red background - txt = txt.replace(/\[42m/gi, "\1" + "2"); // Green background - txt = txt.replace(/\[43m/gi, "\1" + "3"); // Yellow background - txt = txt.replace(/\[44m/gi, "\1" + "4"); // Blue background - txt = txt.replace(/\[45m/gi, "\1" + "5"); // Magenta background - txt = txt.replace(/\[46m/gi, "\1" + "6"); // Cyan background - txt = txt.replace(/\[47m/gi, "\1" + "7"); // White background - // Convert ;-delimited modes (such as [Value;...;Valuem) - txt = ANSIMultiConvertToSyncCodes(txt); - // Remove ANSI codes that are not wanted (such as moving the cursor, etc.) - txt = txt.replace(/\[[0-9]+a/gi, ""); // Cursor up - txt = txt.replace(/\[[0-9]+b/gi, ""); // Cursor down - txt = txt.replace(/\[[0-9]+c/gi, ""); // Cursor forward - txt = txt.replace(/\[[0-9]+d/gi, ""); // Cursor backward - txt = txt.replace(/\[[0-9]+;[0-9]+h/gi, ""); // Cursor position - txt = txt.replace(/\[[0-9]+;[0-9]+f/gi, ""); // Cursor position - txt = txt.replace(/\[s/gi, ""); // Restore cursor position - txt = txt.replace(/\[2j/gi, ""); // Erase display - txt = txt.replace(/\[k/gi, ""); // Erase line - txt = txt.replace(/\[=[0-9]+h/gi, ""); // Set various screen modes - txt = txt.replace(/\[=[0-9]+l/gi, ""); // Reset various screen modes - return txt; -} - -// Converts ANSI ;-delimited modes (such as [Value;...;Valuem) to Synchronet -// attribute codes -// -// Parameters: -// pText: The text with ANSI ;-delimited modes to convert -// -// Return value: The text with ANSI ;-delimited modes converted to Synchronet attributes -function ANSIMultiConvertToSyncCodes(pText) -{ - var multiMatches = pText.match(/\[[0-9]+(;[0-9]+)+m/g); - if (multiMatches == null) - return pText; - var updatedText = pText; - for (var i = 0; i < multiMatches.length; ++i) - { - // Copy the string, with the [ removed from the beginning and the - // trailing 'm' removed - var text = multiMatches[i].substr(2); - text = text.substr(0, text.length-1); - var codes = text.split(";"); - var syncCodes = ""; - for (var idx = 0; idx < codes.length; ++idx) - { - if (codes[idx] == "0") // All attributes off - syncCodes += "\1n"; - else if (codes[idx] == "1") // Bold on (high intensity) - syncCodes += "\1h"; - else if (codes[idx] == "5") // Blink on - syncCodes += "\1i"; - else if (codes[idx] == "30") // Black foreground - syncCodes += "\1k"; - else if (codes[idx] == "31") // Red foreground - syncCodes += "\1r"; - else if (codes[idx] == "32") // Green foreground - syncCodes += "\1g"; - else if (codes[idx] == "33") // Yellow foreground - syncCodes += "\1y"; - else if (codes[idx] == "34") // Blue foreground - syncCodes += "\1b"; - else if (codes[idx] == "35") // Magenta foreground - syncCodes += "\1m"; - else if (codes[idx] == "36") // Cyan foreground - syncCodes += "\1c"; - else if (codes[idx] == "37") // White foreground - syncCodes += "\1w"; - else if (codes[idx] == "40") // Black background - syncCodes += "\1" + "0"; - else if (codes[idx] == "41") // Red background - syncCodes += "\1" + "1"; - else if (codes[idx] == "42") // Green background - syncCodes += "\1" + "2"; - else if (codes[idx] == "43") // Yellow background - syncCodes += "\1" + "3"; - else if (codes[idx] == "44") // Blue background - syncCodes += "\1" + "4"; - else if (codes[idx] == "45") // Magenta background - syncCodes += "\1" + "5"; - else if (codes[idx] == "46") // Cyan background - syncCodes += "\1" + "6"; - else if (codes[idx] == "47") // White background - syncCodes += "\1" + "7"; - } - updatedText = updatedText.replace(multiMatches[i], syncCodes); - } - return updatedText; -} - -// Color/attribute code conversion functions end -/////////////////////////////////////////////////////////////////////////////////////// - -// Finds any Synchronet attributes in an array of TextLine objects before a given -// text line index and edit line index in the array of lines. -// -// Parameters: -// pEditLines: An array of TextLine objects -// pEditLineIdx: The starting edit line index in the array -// pTextLineIdx: The ending text line index in the starting line -// -// Return value: A string containing any Synchronet attribute codes found in the -// array of text lines before the given indexes -function findAttrCodesInLinesBeforeIdx(pEditLines, pEditLineIdx, pTextLineIdx) -{ - if ((pEditLineIdx < 0) || (pEditLineIdx >= pEditLines.length)) - return ""; - if (pTextLineIdx < 0) - return ""; - // Let the text line index be one past the last character but no more than that - var textLineIdx = (pTextLineIdx > pEditLines[pEditLineIdx].text.length ? pEditLines[pEditLineIdx].text.length : pTextLineIdx); - - var attrCodes = ""; - var attrCodeObj = getAttrsAndIndexesBeforeStrIdx(pEditLines[pEditLineIdx].text, textLineIdx-1); - var startIdx = attrCodeObj.syncAttrStartIdx; - while (startIdx > -1) - { - attrCodes = attrCodeObj.attrStr + attrCodes; - attrCodeObj = getAttrsAndIndexesBeforeStrIdx(pEditLines[pEditLineIdx].text, startIdx); - startIdx = attrCodeObj.syncAttrStartIdx; - } - for (var i = pEditLineIdx - 1; i >= 0; --i) - { - attrCodeObj = getAttrsAndIndexesBeforeStrIdx(pEditLines[i].text, pEditLines[i].text.length-1); - startIdx = attrCodeObj.syncAttrStartIdx; - while (startIdx > -1) - { - attrCodes = attrCodeObj.attrStr + attrCodes; - attrCodeObj = getAttrsAndIndexesBeforeStrIdx(pEditLines[i].text, startIdx); - startIdx = attrCodeObj.syncAttrStartIdx; - } - } - // TODO: Remove redundancies in attrCodes? - return attrCodes; -} - -// Removes stray ASCII-1 characters from a string that aren't part of a Synchronet -// color code. -// -// Parameters: -// pStr: The string to remove stray ASCII-1 codes from -// -// Return value: The string with the stray characters removed -function removeStrayANSIOneChars(pStr) -{ - var str = pStr; - var idx = -1; - var startIdx = 0; - while ((idx = str.indexOf("\1", startIdx)) > -1) - { - if (!gSyncAttrRegex.test(str.substr(idx, 2))) - { - str = str.substr(0, idx) + str.substr(idx+1); - startIdx = idx; - } - else - startIdx = idx + 2; - } - return str; -} - -/////////////////////////////////////////////////////////////////////////////////////// -// Debugging - // This function displays debug text at a given location on the screen, then // moves the cursor back to a given location. // // Parameters: -// pDebugX: The X location of where to write the debug text -// pDebugY: The Y location of where to write the debug text +// pDebugX: The X lcoation of where to write the debug text +// pDebugY: The Y lcoation of where to write the debug text // pText: The text to write at the debug location // pOriginalPos: An object with x and y properties containing the original cursor position // pClearDebugLineFirst: Whether or not to clear the debug line before writing the text // pPauseAfter: Whether or not to pause after displaying the text -// pClearLineAfter: Optional - Whether or not to clear the line after displaying the text -function displayDebugText(pDebugX, pDebugY, pText, pOriginalPos, pClearDebugLineFirst, pPauseAfter, pClearLineAfter) +function displayDebugText(pDebugX, pDebugY, pText, pOriginalPos, pClearDebugLineFirst, pPauseAfter) { console.gotoxy(pDebugX, pDebugY); if (pClearDebugLineFirst) - { - //console.clearline("\1n"); - console.cleartoeol("\1n"); - } + console.clearline(); // Output the text console.print(pText); if (pPauseAfter) - console.pause(); - var clearLineAfter = (typeof(pClearLineAfter) == "boolean" ? pClearLineAfter : false); - if (clearLineAfter) - { - console.gotoxy(pDebugX, pDebugY); - console.cleartoeol("\1n"); - } + console.pause(); if ((typeof(pOriginalPos) != "undefined") && (pOriginalPos != null)) console.gotoxy(pOriginalPos); -} +} \ No newline at end of file -- GitLab