diff --git a/ctrl/SlyDCTColors_Default.cfg b/ctrl/SlyDCTColors_Default.cfg index f88e6a665d259e3675e33105249cc638a96803b3..023e86d121a4653f3667b6c42607a44e80e56dae 100644 --- a/ctrl/SlyDCTColors_Default.cfg +++ b/ctrl/SlyDCTColors_Default.cfg @@ -1,82 +1,87 @@ -; 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=nc - -; Border colors -TopBorderColor1=nr -TopBorderColor2=nrh -EditAreaBorderColor1=ng -EditAreaBorderColor2=ngh -EditModeBrackets=nkh -EditMode=nw - -; Colors for the top informational area -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=n7b -QuoteLineHighlightColor=nw -QuoteWinBorderTextColor=n7r -QuoteWinBorderColor=nk7 - -; Colors for the bottom row help text -BottomHelpBrackets=nkh -BottomHelpKeys=nrh -BottomHelpFill=nr -BottomHelpKeyDesc=nc - -; Colors for text boxes -TextBoxBorder=nk7 -TextBoxBorderText=nr7 -TextBoxInnerText=nb7 -YesNoBoxBrackets=nk7 -YesNoBoxYesNoText=nwh7 - -; Colors for the menus -SelectedMenuLabelBorders=nw -SelectedMenuLabelText=nk7 -UnselectedMenuLabelText=nwh -MenuBorders=nk7 -MenuSelectedItems=nw -MenuUnselectedItems=nk7 -MenuHotkeys=nwh7 - -; Colors for the cross-post selection box -crossPostBorder=ng -crossPostBorderText=nbh -crossPostMsgAreaNum=nhw -crossPostMsgAreaNumHighlight=n4hw -crossPostMsgAreaDesc=nc -crossPostMsgAreaDescHighlight=n4c -crossPostChk=nhy -crossPostChkHighlight=n4hy -crossPostMsgGrpMark=nhg -crossPostMsgGrpMarkHighlight=n4hg - -; Colors for message saving and sub-board post info when exiting SlyEdit -msgWillBePostedHdr=nc -msgPostedGrpHdr=nhb -msgPostedSubBoardName=ng -msgPostedOriginalAreaText=nc -msgHasBeenSavedText=nhc -msgAbortedText=nhm -emptyMsgNotSentText=nhm +; 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=nc + +; Border colors +TopBorderColor1=nr +TopBorderColor2=nrh +EditAreaBorderColor1=ng +EditAreaBorderColor2=ngh +EditModeBrackets=nkh +EditMode=nw + +; Colors for the top informational area +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=n7b +QuoteLineHighlightColor=nw +QuoteWinBorderTextColor=n7r +QuoteWinBorderColor=nk7 + +; Colors for the bottom row help text +BottomHelpBrackets=nkh +BottomHelpKeys=nrh +BottomHelpFill=nr +BottomHelpKeyDesc=nc + +; Colors for text boxes +TextBoxBorder=nk7 +TextBoxBorderText=nr7 +TextBoxInnerText=nb7 +YesNoBoxBrackets=nk7 +YesNoBoxYesNoText=nwh7 + +; Colors for the menus +SelectedMenuLabelBorders=nw +SelectedMenuLabelText=nk7 +UnselectedMenuLabelText=nwh +MenuBorders=nk7 +MenuSelectedItems=nw +MenuUnselectedItems=nk7 +MenuHotkeys=nwh7 + +; Color settings for list boxes +listBoxBorder=ng +listBoxBorderText=nbh + +; Colors for the cross-post selection box +crossPostMsgAreaNum=nhw +crossPostMsgAreaNumHighlight=n4hw +crossPostMsgAreaDesc=nc +crossPostMsgAreaDescHighlight=n4c +crossPostChk=nhy +crossPostChkHighlight=n4hy +crossPostMsgGrpMark=nhg +crossPostMsgGrpMarkHighlight=n4hg + +; Colors for the text replacement list +txtReplacementList=nc + +; Colors for message saving and sub-board post info when exiting SlyEdit +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 07a28f1cb77d2f4082ae69be9553fcaca1fddf7a..8de32e937b5bff82162532a788163d07969318bf 100644 --- a/ctrl/SlyDCTColors_Midnight.cfg +++ b/ctrl/SlyDCTColors_Midnight.cfg @@ -1,82 +1,89 @@ -; 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=nc - -; Border colors -TopBorderColor1=nb -TopBorderColor2=nkh -EditAreaBorderColor1=nbh -EditAreaBorderColor2=nkh -EditModeBrackets=nkh -EditMode=nw - -; Colors for the top informational area -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=n7b -QuoteLineHighlightColor=nw -QuoteWinBorderTextColor=n7r -QuoteWinBorderColor=nk7 - -; Colors for the bottom row help text -BottomHelpBrackets=nkh -BottomHelpKeys=nb -BottomHelpFill=nkh -BottomHelpKeyDesc=nc - -; Colors for text boxes -TextBoxBorder=nkh -TextBoxBorderText=nbh -TextBoxInnerText=nw -YesNoBoxBrackets=nkh -YesNoBoxYesNoText=nw - -; Colors for the menus -SelectedMenuLabelBorders=nb -SelectedMenuLabelText=nk4 -UnselectedMenuLabelText=nb -MenuBorders=nkh -MenuSelectedItems=nw -MenuUnselectedItems=nb -MenuHotkeys=nbh - -; Colors for the cross-post selection box -crossPostBorder=nhk -crossPostBorderText=nbh -crossPostMsgAreaNum=nhw -crossPostMsgAreaNumHighlight=n4hw -crossPostMsgAreaDesc=nc -crossPostMsgAreaDescHighlight=n4c -crossPostChk=nhy -crossPostChkHighlight=n4hy -crossPostMsgGrpMark=nhg -crossPostMsgGrpMarkHighlight=n4hg - -; Colors for message saving and sub-board post info when exiting SlyEdit -msgWillBePostedHdr=nc -msgPostedGrpHdr=nhb -msgPostedSubBoardName=ng -msgPostedOriginalAreaText=nc -msgHasBeenSavedText=nhc -msgAbortedText=nhm -emptyMsgNotSentText=nhm +; 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=nc + +; Border colors +TopBorderColor1=nb +TopBorderColor2=nkh +EditAreaBorderColor1=nbh +EditAreaBorderColor2=nkh +EditModeBrackets=nkh +EditMode=nw + +; Colors for the top informational area +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=n7b +QuoteLineHighlightColor=nw +QuoteWinBorderTextColor=n7r +QuoteWinBorderColor=nk7 + +; Colors for the bottom row help text +BottomHelpBrackets=nkh +BottomHelpKeys=nb +BottomHelpFill=nkh +BottomHelpKeyDesc=nc + +; Colors for text boxes +TextBoxBorder=nkh +TextBoxBorderText=nbh +TextBoxInnerText=nw +YesNoBoxBrackets=nkh +YesNoBoxYesNoText=nw + +; Colors for the menus +SelectedMenuLabelBorders=nb +SelectedMenuLabelText=nk4 +UnselectedMenuLabelText=nb +MenuBorders=nkh +MenuSelectedItems=nw +MenuUnselectedItems=nb +MenuHotkeys=nbh + +; Color settings for list boxes +listBoxBorder=nhk +listBoxBorderText=nbh + +; Colors for the cross-post selection box +crossPostBorder=nhk +crossPostBorderText=nbh +crossPostMsgAreaNum=nhw +crossPostMsgAreaNumHighlight=n4hw +crossPostMsgAreaDesc=nc +crossPostMsgAreaDescHighlight=n4c +crossPostChk=nhy +crossPostChkHighlight=n4hy +crossPostMsgGrpMark=nhg +crossPostMsgGrpMarkHighlight=n4hg + +; Colors for the text replacement list +txtReplacementList=nbh + +; Colors for message saving and sub-board post info when exiting SlyEdit +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 8981a84dd213a8e5fbfdc18a6c2db757c1ebda01..c49274ece52bda8abf922ae0420bd99f9a7f7e9d 100644 --- a/ctrl/SlyEdit.cfg +++ b/ctrl/SlyEdit.cfg @@ -13,6 +13,12 @@ useQuoteLineInitials=true indentQuoteLinesWithInitials=true ; Whether or not to allow cross-posting allowCrossPosting=true +; Whether or not to enable text replacements (AKA macros). +; enableTextReplacements can have one of the following 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 +enableTextReplacements=true ; 3rd-party startup scripts ;add3rdPartyStartupScript= ; JavaScript commands to run upon start of SlyEdit diff --git a/ctrl/SlyEdit_TextReplacements.cfg b/ctrl/SlyEdit_TextReplacements.cfg new file mode 100644 index 0000000000000000000000000000000000000000..71a3e313a6a04b1996310e4417c1700098b763cb --- /dev/null +++ b/ctrl/SlyEdit_TextReplacements.cfg @@ -0,0 +1,10 @@ +; This file configures text replacements (AKA Macros) for SlyEdit. Each line +; needs to be in this format: +; originalWord=replacementText +; where originalWord is the word to be replaced, and replacementText is the +; text to replace the word with. +; The option enableTextReplacements in SlyEdit.cfg can have one of the +; following values: +; false (disabled) +; true (enabled, literal string matching) +; regex (enabled, using regular expressions) diff --git a/ctrl/SlyIceColors_BlueIce.cfg b/ctrl/SlyIceColors_BlueIce.cfg index 3d87ebb200a139963b78da6e460a75e129f16fbd..e19588b3d1eec1bdc322266e98450e5800d65492 100644 --- a/ctrl/SlyIceColors_BlueIce.cfg +++ b/ctrl/SlyIceColors_BlueIce.cfg @@ -1,56 +1,61 @@ -; 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=nc - -; Border colors -BorderColor1=nb -BorderColor2=nbh -KeyInfoLabelColor=ch - -; Colors for the top informational area -TopInfoBkgColor=4 -TopLabelColor=ch -TopLabelColonColor=bh -TopToColor=wh -TopFromColor=wh -TopSubjectColor=wh -TopTimeColor=gh -TopTimeLeftColor=gh -EditMode=ch - -; Colors for the quote window -QuoteWinText=nhw -QuoteLineHighlightColor=4hc -QuoteWinBorderTextColor=nch - -; Colors for the multi-choice options -SelectedOptionBorderColor=nbh4 -SelectedOptionTextColor=nch4 -UnselectedOptionBorderColor=nb -UnselectedOptionTextColor=nw - -; Colors for the cross-post selection box -crossPostBorder=nb -crossPostBorderText=nbh -crossPostMsgAreaNum=nhw -crossPostMsgAreaNumHighlight=n4hw -crossPostMsgAreaDesc=nc -crossPostMsgAreaDescHighlight=n4c -crossPostChk=nhy -crossPostChkHighlight=n4hy -crossPostMsgGrpMark=nhg -crossPostMsgGrpMarkHighlight=n4hg - -; Colors for message saving and sub-board post info when exiting SlyEdit -msgWillBePostedHdr=nc -msgPostedGrpHdr=nhb -msgPostedSubBoardName=ng -msgPostedOriginalAreaText=nc -msgHasBeenSavedText=nhc -msgAbortedText=nhm -emptyMsgNotSentText=nhm +; 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=nc + +; Border colors +BorderColor1=nb +BorderColor2=nbh +KeyInfoLabelColor=ch + +; Colors for the top informational area +TopInfoBkgColor=4 +TopLabelColor=ch +TopLabelColonColor=bh +TopToColor=wh +TopFromColor=wh +TopSubjectColor=wh +TopTimeColor=gh +TopTimeLeftColor=gh +EditMode=ch + +; Colors for the quote window +QuoteWinText=nhw +QuoteLineHighlightColor=4hc +QuoteWinBorderTextColor=nch + +; Colors for the multi-choice options +SelectedOptionBorderColor=nbh4 +SelectedOptionTextColor=nch4 +UnselectedOptionBorderColor=nb +UnselectedOptionTextColor=nw + +; Color settings for list boxes +listBoxBorder=nb +listBoxBorderText=nbh + +; Colors for the cross-post selection box +crossPostMsgAreaNum=nhw +crossPostMsgAreaNumHighlight=n4hw +crossPostMsgAreaDesc=nc +crossPostMsgAreaDescHighlight=n4c +crossPostChk=nhy +crossPostChkHighlight=n4hy +crossPostMsgGrpMark=nhg +crossPostMsgGrpMarkHighlight=n4hg + +; Colors for the text replacement list +txtReplacementList=nc + +; Colors for message saving and sub-board post info when exiting SlyEdit +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 e687c077aca6de07e6cc6f68e50ce96a34d6c7ff..b2ec661d7a5ca4e7c14204150633ac94bb148934 100644 --- a/ctrl/SlyIceColors_EmeraldCity.cfg +++ b/ctrl/SlyIceColors_EmeraldCity.cfg @@ -1,56 +1,61 @@ -; 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=ng - -; Border colors -BorderColor1=ng -BorderColor2=ngh -KeyInfoLabelColor=ch - -; Colors for the top informational area -TopInfoBkgColor=2 -TopLabelColor=ch -TopLabelColonColor=gh -TopToColor=wh -TopFromColor=wh -TopSubjectColor=wh -TopTimeColor=gh -TopTimeLeftColor=gh -EditMode=ch - -; Colors for the quote window -QuoteWinText=nhw -QuoteLineHighlightColor=6hc -QuoteWinBorderTextColor=nch - -; Colors for the multi-choice options -SelectedOptionBorderColor=nch6 -SelectedOptionTextColor=nch6 -UnselectedOptionBorderColor=ng -UnselectedOptionTextColor=nw - -; Colors for the cross-post selection box -crossPostBorder=ng -crossPostBorderText=ngh -crossPostMsgAreaNum=nhw -crossPostMsgAreaNumHighlight=n4hw -crossPostMsgAreaDesc=nc -crossPostMsgAreaDescHighlight=n4c -crossPostChk=nhy -crossPostChkHighlight=n4hy -crossPostMsgGrpMark=nhg -crossPostMsgGrpMarkHighlight=n4hg - -; Colors for message saving and sub-board post info when exiting SlyEdit -msgWillBePostedHdr=nc -msgPostedGrpHdr=nhb -msgPostedSubBoardName=ng -msgPostedOriginalAreaText=nc -msgHasBeenSavedText=nhc -msgAbortedText=nhm -emptyMsgNotSentText=nhm +; 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=ng + +; Border colors +BorderColor1=ng +BorderColor2=ngh +KeyInfoLabelColor=ch + +; Colors for the top informational area +TopInfoBkgColor=2 +TopLabelColor=ch +TopLabelColonColor=gh +TopToColor=wh +TopFromColor=wh +TopSubjectColor=wh +TopTimeColor=gh +TopTimeLeftColor=gh +EditMode=ch + +; Colors for the quote window +QuoteWinText=nhw +QuoteLineHighlightColor=6hc +QuoteWinBorderTextColor=nch + +; Colors for the multi-choice options +SelectedOptionBorderColor=nch6 +SelectedOptionTextColor=nch6 +UnselectedOptionBorderColor=ng +UnselectedOptionTextColor=nw + +; Color settings for list boxes +listBoxBorder=ng +listBoxBorderText=ngh + +; Colors for the cross-post selection box +crossPostMsgAreaNum=nhw +crossPostMsgAreaNumHighlight=n4hw +crossPostMsgAreaDesc=nc +crossPostMsgAreaDescHighlight=n4c +crossPostChk=nhy +crossPostChkHighlight=n4hy +crossPostMsgGrpMark=nhg +crossPostMsgGrpMarkHighlight=n4hg + +; Colors for the text replacement list +txtReplacementList=ng + +; Colors for message saving and sub-board post info when exiting SlyEdit +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 4bf851feeda1184670f82e16f6a0f70f1c40a6b1..a22b541424efaa502ea7d943dc7147be5beb885f 100644 --- a/ctrl/SlyIceColors_FieryInferno.cfg +++ b/ctrl/SlyIceColors_FieryInferno.cfg @@ -1,56 +1,61 @@ -; 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=nc - -; Border colors -BorderColor1=nr -BorderColor2=nrh -KeyInfoLabelColor=yh - -; Colors for the top informational area -TopInfoBkgColor=1 -TopLabelColor=yh -TopLabelColonColor=rh -TopToColor=wh -TopFromColor=wh -TopSubjectColor=wh -TopTimeColor=wh -TopTimeLeftColor=wh -EditMode=yh - -; Colors for the quote window -QuoteWinText=nhw -QuoteLineHighlightColor=1hy -QuoteWinBorderTextColor=nyh - -; Colors for the multi-choice options -SelectedOptionBorderColor=nrh1 -SelectedOptionTextColor=nyh1 -UnselectedOptionBorderColor=nr -UnselectedOptionTextColor=nw - -; Colors for the cross-post selection box -crossPostBorder=nr -crossPostBorderText=nrh -crossPostMsgAreaNum=nhw -crossPostMsgAreaNumHighlight=n4hw -crossPostMsgAreaDesc=nc -crossPostMsgAreaDescHighlight=n4c -crossPostChk=nhy -crossPostChkHighlight=n4hy -crossPostMsgGrpMark=nhg -crossPostMsgGrpMarkHighlight=n4hg - -; Colors for message saving and sub-board post info when exiting SlyEdit -msgWillBePostedHdr=nc -msgPostedGrpHdr=nhb -msgPostedSubBoardName=ng -msgPostedOriginalAreaText=nc -msgHasBeenSavedText=nhc -msgAbortedText=nhm -emptyMsgNotSentText=nhm +; 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=nc + +; Border colors +BorderColor1=nr +BorderColor2=nrh +KeyInfoLabelColor=yh + +; Colors for the top informational area +TopInfoBkgColor=1 +TopLabelColor=yh +TopLabelColonColor=rh +TopToColor=wh +TopFromColor=wh +TopSubjectColor=wh +TopTimeColor=wh +TopTimeLeftColor=wh +EditMode=yh + +; Colors for the quote window +QuoteWinText=nhw +QuoteLineHighlightColor=1hy +QuoteWinBorderTextColor=nyh + +; Colors for the multi-choice options +SelectedOptionBorderColor=nrh1 +SelectedOptionTextColor=nyh1 +UnselectedOptionBorderColor=nr +UnselectedOptionTextColor=nw + +; Color settings for list boxes +listBoxBorder=nr +listBoxBorderText=nrh + +; Colors for the cross-post selection box +crossPostMsgAreaNum=nhw +crossPostMsgAreaNumHighlight=n4hw +crossPostMsgAreaDesc=nc +crossPostMsgAreaDescHighlight=n4c +crossPostChk=nhy +crossPostChkHighlight=n4hy +crossPostMsgGrpMark=nhg +crossPostMsgGrpMarkHighlight=n4hg + +; Colors for the text replacement list +txtReplacementList=nrh + +; Colors for message saving and sub-board post info when exiting SlyEdit +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 7d4f22aefe859c68c8f9d71f01ad8313cb0aa088..1e7b7bff290eff15b246d47f96c3fe592e995bac 100644 --- a/ctrl/SlyIceColors_Fire-N-Ice.cfg +++ b/ctrl/SlyIceColors_Fire-N-Ice.cfg @@ -1,56 +1,61 @@ -; 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=nc - -; Border colors -BorderColor1=nr -BorderColor2=nrh -KeyInfoLabelColor=yh - -; Colors for the top informational area -TopInfoBkgColor=4 -TopLabelColor=yh -TopLabelColonColor=kh -TopToColor=wh -TopFromColor=wh -TopSubjectColor=wh -TopTimeColor=wh -TopTimeLeftColor=wh -EditMode=yh - -; Colors for the quote window -QuoteWinText=nhw -QuoteLineHighlightColor=4hy -QuoteWinBorderTextColor=nyh - -; Colors for the multi-choice options -SelectedOptionBorderColor=nbh4 -SelectedOptionTextColor=nyh4 -UnselectedOptionBorderColor=nb -UnselectedOptionTextColor=nw - -; Colors for the cross-post selection box -crossPostBorder=nr -crossPostBorderText=nbh -crossPostMsgAreaNum=nhw -crossPostMsgAreaNumHighlight=n4hw -crossPostMsgAreaDesc=nc -crossPostMsgAreaDescHighlight=n4c -crossPostChk=nhy -crossPostChkHighlight=n4hy -crossPostMsgGrpMark=nhg -crossPostMsgGrpMarkHighlight=n4hg - -; Colors for message saving and sub-board post info when exiting SlyEdit -msgWillBePostedHdr=nc -msgPostedGrpHdr=nhb -msgPostedSubBoardName=ng -msgPostedOriginalAreaText=nc -msgHasBeenSavedText=nhc -msgAbortedText=nhm -emptyMsgNotSentText=nhm +; 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=nc + +; Border colors +BorderColor1=nr +BorderColor2=nrh +KeyInfoLabelColor=yh + +; Colors for the top informational area +TopInfoBkgColor=4 +TopLabelColor=yh +TopLabelColonColor=kh +TopToColor=wh +TopFromColor=wh +TopSubjectColor=wh +TopTimeColor=wh +TopTimeLeftColor=wh +EditMode=yh + +; Colors for the quote window +QuoteWinText=nhw +QuoteLineHighlightColor=4hy +QuoteWinBorderTextColor=nyh + +; Colors for the multi-choice options +SelectedOptionBorderColor=nbh4 +SelectedOptionTextColor=nyh4 +UnselectedOptionBorderColor=nb +UnselectedOptionTextColor=nw + +; Color settings for list boxes +listBoxBorder=nr +listBoxBorderText=nbh + +; Colors for the cross-post selection box +crossPostMsgAreaNum=nhw +crossPostMsgAreaNumHighlight=n4hw +crossPostMsgAreaDesc=nc +crossPostMsgAreaDescHighlight=n4c +crossPostChk=nhy +crossPostChkHighlight=n4hy +crossPostMsgGrpMark=nhg +crossPostMsgGrpMarkHighlight=n4hg + +; Colors for the text replacement list +txtReplacementList=nbh + +; Colors for message saving and sub-board post info when exiting SlyEdit +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 6d3162ef630d40eba1ae7d9bce65dd6d5c26d913..9c120c67aa1a2cafda3c99f76406c9b0f0ae6bd0 100644 --- a/ctrl/SlyIceColors_GenericBlue.cfg +++ b/ctrl/SlyIceColors_GenericBlue.cfg @@ -1,56 +1,61 @@ -; 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=nc - -; Border colors -BorderColor1=nb -BorderColor2=nb -KeyInfoLabelColor=ch - -; Colors for the top informational area -TopInfoBkgColor=4 -TopLabelColor=ch -TopLabelColonColor=bh -TopToColor=wh -TopFromColor=wh -TopSubjectColor=wh -TopTimeColor=bh -TopTimeLeftColor=bh -EditMode=ch - -; Colors for the quote window -QuoteWinText=nhw -QuoteLineHighlightColor=4hc -QuoteWinBorderTextColor=nch - -; Colors for the multi-choice options -SelectedOptionBorderColor=nbh4 -SelectedOptionTextColor=nch4 -UnselectedOptionBorderColor=nw -UnselectedOptionTextColor=nw - -; Colors for the cross-post selection box -crossPostBorder=nb -crossPostBorderText=nbh -crossPostMsgAreaNum=nhw -crossPostMsgAreaNumHighlight=n4hw -crossPostMsgAreaDesc=nc -crossPostMsgAreaDescHighlight=n4c -crossPostChk=nhy -crossPostChkHighlight=n4hy -crossPostMsgGrpMark=nhg -crossPostMsgGrpMarkHighlight=n4hg - -; Colors for message saving and sub-board post info when exiting SlyEdit -msgWillBePostedHdr=nc -msgPostedGrpHdr=nhb -msgPostedSubBoardName=ng -msgPostedOriginalAreaText=nc -msgHasBeenSavedText=nhc -msgAbortedText=nhm -emptyMsgNotSentText=nhm +; 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=nc + +; Border colors +BorderColor1=nb +BorderColor2=nb +KeyInfoLabelColor=ch + +; Colors for the top informational area +TopInfoBkgColor=4 +TopLabelColor=ch +TopLabelColonColor=bh +TopToColor=wh +TopFromColor=wh +TopSubjectColor=wh +TopTimeColor=bh +TopTimeLeftColor=bh +EditMode=ch + +; Colors for the quote window +QuoteWinText=nhw +QuoteLineHighlightColor=4hc +QuoteWinBorderTextColor=nch + +; Colors for the multi-choice options +SelectedOptionBorderColor=nbh4 +SelectedOptionTextColor=nch4 +UnselectedOptionBorderColor=nw +UnselectedOptionTextColor=nw + +; Color settings for list boxes +listBoxBorder=nb +listBoxBorderText=nbh + +; Colors for the cross-post selection box +crossPostMsgAreaNum=nhw +crossPostMsgAreaNumHighlight=n4hw +crossPostMsgAreaDesc=nc +crossPostMsgAreaDescHighlight=n4c +crossPostChk=nhy +crossPostChkHighlight=n4hy +crossPostMsgGrpMark=nhg +crossPostMsgGrpMarkHighlight=n4hg + +; Colors for the text replacement list +txtReplacementList=nbh + +; Colors for message saving and sub-board post info when exiting SlyEdit +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 1b960059a5edaad1dea430dc3450bd59888bea19..1b4f42a4e15126b4879887b37e705e520705696c 100644 --- a/ctrl/SlyIceColors_ShadesOfGrey.cfg +++ b/ctrl/SlyIceColors_ShadesOfGrey.cfg @@ -1,56 +1,61 @@ -; 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=nkh - -; Border colors -BorderColor1=nkh -BorderColor2=nb -KeyInfoLabelColor=nw - -; Colors for the top informational area -TopInfoBkgColor=4 -TopLabelColor=nw4 -TopLabelColonColor=bh -TopToColor=wh -TopFromColor=wh -TopSubjectColor=wh -TopTimeColor=wh -TopTimeLeftColor=wh -EditMode=nw4 - -; Colors for the quote window -QuoteWinText=nhw -QuoteLineHighlightColor=7hw -QuoteWinBorderTextColor=nw - -; Colors for the multi-choice options -SelectedOptionBorderColor=nwh7 -SelectedOptionTextColor=nwh7 -UnselectedOptionBorderColor=nkh -UnselectedOptionTextColor=nwh - -; Colors for the cross-post selection box -crossPostBorder=nhk -crossPostBorderText=nw -crossPostMsgAreaNum=nhw -crossPostMsgAreaNumHighlight=n4hw -crossPostMsgAreaDesc=nc -crossPostMsgAreaDescHighlight=n4c -crossPostChk=nhy -crossPostChkHighlight=n4hy -crossPostMsgGrpMark=nhg -crossPostMsgGrpMarkHighlight=n4hg - -; Colors for message saving and sub-board post info when exiting SlyEdit -msgWillBePostedHdr=nc -msgPostedGrpHdr=nhb -msgPostedSubBoardName=ng -msgPostedOriginalAreaText=nc -msgHasBeenSavedText=nhc -msgAbortedText=nhm -emptyMsgNotSentText=nhm +; 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=nkh + +; Border colors +BorderColor1=nkh +BorderColor2=nb +KeyInfoLabelColor=nw + +; Colors for the top informational area +TopInfoBkgColor=4 +TopLabelColor=nw4 +TopLabelColonColor=bh +TopToColor=wh +TopFromColor=wh +TopSubjectColor=wh +TopTimeColor=wh +TopTimeLeftColor=wh +EditMode=nw4 + +; Colors for the quote window +QuoteWinText=nhw +QuoteLineHighlightColor=7hw +QuoteWinBorderTextColor=nw + +; Colors for the multi-choice options +SelectedOptionBorderColor=nwh7 +SelectedOptionTextColor=nwh7 +UnselectedOptionBorderColor=nkh +UnselectedOptionTextColor=nwh + +; Color settings for list boxes +listBoxBorder=nhk +listBoxBorderText=nw + +; Colors for the cross-post selection box +crossPostMsgAreaNum=nhw +crossPostMsgAreaNumHighlight=n4hw +crossPostMsgAreaDesc=nc +crossPostMsgAreaDescHighlight=n4c +crossPostChk=nhy +crossPostChkHighlight=n4hy +crossPostMsgGrpMark=nhg +crossPostMsgGrpMarkHighlight=n4hg + +; Colors for the text replacement list +txtReplacementList=nw + +; Colors for message saving and sub-board post info when exiting SlyEdit +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_DD_Message_Lister_notes.txt b/docs/SlyEdit_DD_Message_Lister_notes.txt index 387b64a6f7ac11e4d534789669c64a962857821b..031ecf00a1018189330363a0ba215a78697a08b8 100644 --- a/docs/SlyEdit_DD_Message_Lister_notes.txt +++ b/docs/SlyEdit_DD_Message_Lister_notes.txt @@ -14,6 +14,7 @@ Message Lister with the recent versions of SlyEdit: SlyEdit Digital Distortion message Lister ------- --------------------------------- +1.29 1.36+ 1.28 1.36+ 1.27 1.36+ 1.26 1.35 diff --git a/docs/SlyEdit_ReadMe.txt b/docs/SlyEdit_ReadMe.txt index da96ae96e3ac24e85865ee5360866cf3c8cbbc5d..5564d1a099fe6824f81874d8d50a9dea2c018ac6 100644 --- a/docs/SlyEdit_ReadMe.txt +++ b/docs/SlyEdit_ReadMe.txt @@ -1,6 +1,6 @@ SlyEdit message editor - Version 1.28 - Release date: 2013-08-24 + Version 1.29 + Release date: 2013-09-02 by @@ -18,15 +18,16 @@ Upgrading.txt. Contents ======== -1. Disclaimer -2. Introduction -3. Installation & Setup -4. Features -5. Digital Distortion Message Lister note -6. Configuration file -7. Ice-style Color Theme Settings -8. DCT-style Color Theme Settings -9. Common colors (appearing in both Ice and DCT color theme files) + 1. Disclaimer + 2. Introduction + 3. Installation & Setup + 4. Features + 5. Digital Distortion Message Lister note + 6. Configuration file + 7. Ice-style Color Theme Settings + 8. DCT-style Color Theme Settings + 9. Common colors (appearing in both Ice and DCT color theme files) +10. Text replacements (AKA Macros) 1. Disclaimer @@ -195,8 +196,10 @@ Help keys Slash commands (on blank line) Ctrl-G : General help � /A : Abort Ctrl-P : Command key help � /S : Save Ctrl-R : Program information � /Q : Quote message +Ctrl-T : List text replacements � /T : List text replacements � /C : Cross-post selection + Command/edit keys ----------------- Ctrl-A : Abort message � Ctrl-W : Page up @@ -300,6 +303,15 @@ allowCrossPosting Whether or not to allow cross-posting messages into different/multiple message sub-boards. Valid values are true and false. +enableTextReplacements Toggles the use of text replacements (AKA + macros) as the user types a message. Valid + values are true, false, and regex. If regex + is used, text replacements will be enabled + and used as regular expressions as + implemented by JavaScript. For more + information, see section 10 (Text + replacements (AKA Macros)). + Ice colors ---------- Setting Description @@ -523,11 +535,19 @@ MenuHotkeys The color to use for the hotkey characters in 9. Common colors (appearing in both Ice and DCT color theme files) ================================================================== -crossPostBorder The color to use for the border of the cross- - post area selection box - -crossPostBorderText The color to use for the top border text of - the cross-post area selection box +listBoxBorder The color to use for the border of list + boxes, such as the cross-post area selection + box and the text replacements list box. Note + that this setting replaces crossPostBorder, + which was used in previous versions of + SlyEdit. + +listBoxBorderText The color to use for text in the borders of + list boxes, such as the cross-post area + selection box and the text replacements list + box. Note that this setting replaces + crossPostBorderText, which was used in + previous versions of SlyEdit. crossPostMsgAreaNum The color to use for the message group/sub- board numbers in the cross-post area @@ -590,4 +610,97 @@ emptyMsgNotSentText The color to use for the Message Not Sent text when exiting SlyEdit genMsgErrorText The color to use for general message error - text when exiting SlyEdit \ No newline at end of file + text when exiting SlyEdit + +10. Text replacements (AKA Macros) +================================== +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 + JavaScript (more accurately, Synchronet's JavaScript interpreter, which + at the time of this writing is Mozilla's JavaScript engine (AKA + 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. 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. + +The options for the enableTextReplacements configuration optoin are explained +in more detail below: + +- false: Text replacing is disabled + +- true: Literal text search and replace - The words will be matched literally +and replaced with the text on the right side of the = in +SlyEdit_TextReplacements.cfg. In this mode, word matching is not +case-sensitive. The words can have both uppercase and lowercase letters and +will still be matched to the words configured in SlyEdit_TextReplacements.cfg. +In this mode, if the first letter of the original word is uppercase, then the +first letter of the replaced text will also be uppercase. +While this works, one drawback to literal text searching is that it won't +replace a word if there are punctuation characters or other characters around +the word or if the word is misspelled. + +- regex: With this option, SlyEdit will treat the word searches (on the left +side of the = in SlyEdit_TextReplacements.cfg) as regular expressions, as +implemented by JavaScript. When using regular expressions, SlyEdit will start +trying all the regular expressions provided and apply only the first one that +changes the text and will stop there. +Regular expressions offer a more flexible way to serach and replace text. For +example, in case a word is surrounded by punctuation or other characters, a +regular expression can be given that will still match the word. For example, +you might want a regular expression that changes "teh" to "the" (since "teh" +is a common misspelling of "the"). To ensure that the word is replaced even if +the word has other characters around it, you could use a regular exprssion and +replacement such as this: +(.*)teh(.*)=$1the$2 +That way, even if the word is enclosed in quotes (such as "teh"), the word will +still be converted to "the". And to preserve the first letter's case (if it's +uppercase or lowercase), this regular expression and replacement string would +handle that: +(.*)([tT])eh(.*)=$1$2he$3 +SlyEdit applies the regular expressions on a per-word basis; that is, the +expression .* in a regular expression will match any characters only in the +last word the user typed, not the entire line. + +For more information on regular expressions, the +following are some web pages that explain them: + +General information about regular expressions: +http://www.regular-expressions.info/tutorial.html + +Information on text grouping and backreferencing with parenthesis (the page +calls them "round brackets") - A very powerful feature of regular expressions: +http://www.regular-expressions.info/brackets.html + +General information about regular expressions geared toward JavaScript: +http://www.javascriptkit.com/javatutors/re.shtml + +Information about using backreferences with regular expressions in JavaScript: +http://stackoverflow.com/questions/2447915/javascript-string-regex-backreferences + +JavaScript-specific information on regular exprssions: +http://www.w3schools.com/js/js_obj_regexp.asp +http://www.w3schools.com/jsref/jsref_obj_regexp.asp + +One nice thing about JavaScript's implementation (among others) of regular +expressions is that it supports the use of parentheses for character grouping +and backreferencing to place a portion of the matched text in the replacement +text. In JavaScript, each numbered capture buffer is preceded by a dollar sign +($). For example, the regular expression (darn) will match the word "darn" and +store it in buffer 1, and in JavaScript (and with SlyEdit's search and +replace), you would use $1 to refer to the word "darn". For example, for +(darn), the replacement $1it would replace the word "darn" with "darnit". \ No newline at end of file diff --git a/docs/SlyEdit_Upgrading.txt b/docs/SlyEdit_Upgrading.txt index 21475d060cc8695bdba50d1c09f0fa82657382dd..d508ae4d43862d3eb8376292c0c989cad638c72a 100644 --- a/docs/SlyEdit_Upgrading.txt +++ b/docs/SlyEdit_Upgrading.txt @@ -41,6 +41,46 @@ configuration should look like this (ICE mode is used here): 2. Notes and new configuration file settings ============================================ +Upgrading to version 1.29 +------------------------- +A new "text replacements" (AKA macros) feature has been added. This feature +lets you (the sysop) define words to be replaced with other text. 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 as the user +types a message. For more details, see the section regarding text replacements +in the "Read Me.txt" file. + + +The color settings crossPostBorder and crossPostBorderText have been +renamed to listBoxBorder and listBoxBorderText. crossPostBorder and +crossPostBorderText will still work, but if listBoxBorder and +listBoxBorderText are used in your theme configuration files, those will be +used instead. + +Also, the following color setting has been added (for both the DCT-style and +Ice-style theme files): +txtReplacementList The color to use for the text replacements in the + text replacement list. + +Upgrading to version 1.28 +------------------------- +New general color settings (for both the DCT-style and Ice-style theme files): +msgWillBePostedHdr The color to use for the text �Your message will be posted into the following area(s)� text when exiting SlyEdit + +msgPostedGrpHdr The color to use for the group name header when listing the message's posted message areas when exiting SlyEdit + +msgPostedSubBoardName The color to use for the message sub-boards when listing the message's posted message areas when exiting SlyEdit + +msgPostedOriginalAreaText The color to use for the text �(original message area)� when listing the message's posted message areas when exiting SlyEdit + +msgHasBeenSavedText The color to use for the text �The message has been saved.� when exiting SlyEdit + +msgAbortedText The color to use for the Message Aborted text when exiting SlyEdit + +emptyMsgNotSentText The color to use for the Message Not Sent text when exiting SlyEdit + +genMsgErrorText The color to use for general message error text when exiting SlyEdit + Upgrading to version 1.20 ------------------------- Version 1.20 added a cross-posting feature, and there is a new configuration diff --git a/exec/SlyEdit.js b/exec/SlyEdit.js index d22665d6a31eaf92f3378c0bb3d7e9b11c6c7471..5870c9ea2288de0e9b6323b878a3542451504962 100644 --- a/exec/SlyEdit.js +++ b/exec/SlyEdit.js @@ -13,43 +13,31 @@ * 2009-08-22 Eric Oulashin Version 1.00 * Initial public release * ....Removed some comments... - * 2013-05-16 Eric Oulashin Version 1.26 beta - * Fix for getting author initials for quote lines: - * Updated to use bbs.msg_number only for Synchronet - * 3.16 builds starting on May 12, 2013 and to use - * bbs.smb_curmsg before that build date. May 12, - * 2013 was right after Digital Man put in his change - * to make bbs.msg_number work in JavaScript scripts, - * and it's accurate in all situations. - * 2013-05-17 Eric Oulashin Version 1.26 - * Made another change to make sure the call - * to bbs.get_msg_header() in getFromNameForCurMsg() - * in SlyEdit_Misc.js had the correct first parameter - * to specify whether the message number is an - * offset. Released as version 1.26 after some - * testing. - * 2013-05-24 Eric Oulashin Version 1.27 - * Updated to check whether bbs.msg_number is > 0 - * rather than checking the Synchronet version - * >= 3.16 & build date at least May 12, 2013 - * to determine whether to use bbs.msg_number or - * bbs.smb_curmsg. Sysops who use Digital - * Message Lister must now update the message - * lister to version 1.36 or newer to properly - * work with this version of SlyEdit. Also, - * in SlyEdit_Misc.js, updated to add one more - * data member to the return object: - * msgNumIsOffset, which stores whether or not the - * message number is an offset. - * 2013-08-23 Eric Oulashin Version 1.28 Beta (start) - * Added 8 new color settings for the text displayed - * when SlyEdit exits regarding which message - * areas the message was posted in, and the saved - * and abort messages. * 2013-08-24 Eric Oulashin Version 1.28 * Bug fix: SlyEdit sometimes didn't quote the last * line of a message when using author's initials. * This has been fixed. + * Added 8 new color settings for the text displayed + * when SlyEdit exits regarding which message + * areas the message was posted in, and the saved + * and abort messages. + * 2013-08-28 Eric Oulashin Version 1.29 Beta (started) + * Started working on a macros feature as in + * QuikEdit. I'll call it text replacements. + * 2013-08-31 Eric Oulashin Worked on doPrintableChar() for text replacements + * and started working on doEnterKey() for text + * replacements. + * 2013-09-01 Eric Oulashin Worked on doEnterKey() for text replacements. + * Started working on a new function, listTextReplacements(). + * 2013-09-02 Eric Oulashin Version 1.29 + * Worked on doEnterKey() for text replacements to + * improve the line splitting if the new text has + * spaces in it. Updated the text replacment list + * box in the UI to show the page number and total + * number of pages. Updated so that the command to + * list the text replacements will only work if + * text replacements is enabled. + * After some more testing, I decided to release 1.29 today. */ /* Command-line arguments: @@ -73,13 +61,13 @@ var EDITOR_STYLE = "DCT"; // The second command-line argument (argv[1]) can change this. if (typeof(argv[1]) != "undefined") { - var styleUpper = argv[1].toUpperCase(); - // Make sure styleUpper is valid before setting EDITOR_STYLE. - if (styleUpper == "DCT") - EDITOR_STYLE = "DCT"; - else if (styleUpper == "ICE") - EDITOR_STYLE = "ICE"; - else if (styleUpper == "RANDOM") + var styleUpper = argv[1].toUpperCase(); + // Make sure styleUpper is valid before setting EDITOR_STYLE. + if (styleUpper == "DCT") + EDITOR_STYLE = "DCT"; + else if (styleUpper == "ICE") + EDITOR_STYLE = "ICE"; + else if (styleUpper == "RANDOM") EDITOR_STYLE = (Math.floor(Math.random()*2) == 0) ? "DCT" : "ICE"; } @@ -103,27 +91,27 @@ const EDITOR_PROGRAM_NAME = "SlyEdit"; if (system.version_num < 31400) { console.print("n"); - console.crlf(); - console.print("nhyi* Warning:nhw " + EDITOR_PROGRAM_NAME); - console.print(" " + "requires version g3.14w or"); - console.crlf(); - console.print("higher of Synchronet. This BBS is using version g"); - console.print(system.version + "w. Please notify the sysop."); - console.crlf(); - console.pause(); - exit(1); // 1: Aborted + console.crlf(); + console.print("nhyi* Warning:nhw " + EDITOR_PROGRAM_NAME); + console.print(" " + "requires version g3.14w or"); + console.crlf(); + console.print("higher of Synchronet. This BBS is using version g"); + console.print(system.version + "w. Please notify the sysop."); + console.crlf(); + console.pause(); + exit(1); // 1: Aborted } // If the user's terminal doesn't support ANSI, then exit. if (!console.term_supports(USER_ANSI)) { - console.print("n\r\nhyERROR: w" + EDITOR_PROGRAM_NAME + - " requires an ANSI terminal.n\r\np"); - exit(1); // 1: Aborted + console.print("n\r\nhyERROR: w" + EDITOR_PROGRAM_NAME + + " requires an ANSI terminal.n\r\np"); + exit(1); // 1: Aborted } // Constants -const EDITOR_VERSION = "1.28"; -const EDITOR_VER_DATE = "2013-08-24"; +const EDITOR_VERSION = "1.29"; +const EDITOR_VER_DATE = "2013-09-02"; // Program variables @@ -140,8 +128,8 @@ var gEditRight = gEditLeft + 79; // Based on gEditLeft being 1-based // If the screen has less than 80 columns, then use the whole screen. if (console.screen_columns < 80) { - gEditLeft = 1; - gEditRight = console.screen_columns; + gEditLeft = 1; + gEditRight = console.screen_columns; } // Colors @@ -238,41 +226,41 @@ var fpHandleESCMenu = null; var fpDisplayTime = null; if (EDITOR_STYLE == "DCT") { - load(gStartupPath + "SlyEdit_DCTStuff.js"); - 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 - fpDrawQuoteWindowTopBorder = DrawQuoteWindowTopBorder_DCTStyle; - fpDisplayTextAreaBottomBorder = DisplayTextAreaBottomBorder_DCTStyle; - fpDrawQuoteWindowBottomBorder = DrawQuoteWindowBottomBorder_DCTStyle; - fpRedrawScreen = redrawScreen_DCTStyle; - fpUpdateInsertModeOnScreen = updateInsertModeOnScreen_DCTStyle; - fpDisplayBottomHelpLine = DisplayBottomHelpLine_DCTStyle; - fpHandleESCMenu = handleDCTESCMenu; - fpDisplayTime = displayTime_DCTStyle; + load(gStartupPath + "SlyEdit_DCTStuff.js"); + 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 + fpDrawQuoteWindowTopBorder = DrawQuoteWindowTopBorder_DCTStyle; + fpDisplayTextAreaBottomBorder = DisplayTextAreaBottomBorder_DCTStyle; + fpDrawQuoteWindowBottomBorder = DrawQuoteWindowBottomBorder_DCTStyle; + fpRedrawScreen = redrawScreen_DCTStyle; + fpUpdateInsertModeOnScreen = updateInsertModeOnScreen_DCTStyle; + fpDisplayBottomHelpLine = DisplayBottomHelpLine_DCTStyle; + fpHandleESCMenu = handleDCTESCMenu; + fpDisplayTime = displayTime_DCTStyle; } else if (EDITOR_STYLE == "ICE") { - load(gStartupPath + "SlyEdit_IceStuff.js"); - 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 - fpDrawQuoteWindowTopBorder = DrawQuoteWindowTopBorder_IceStyle; - fpDisplayTextAreaBottomBorder = DisplayTextAreaBottomBorder_IceStyle; - fpDrawQuoteWindowBottomBorder = DrawQuoteWindowBottomBorder_IceStyle; - fpRedrawScreen = redrawScreen_IceStyle; - fpUpdateInsertModeOnScreen = updateInsertModeOnScreen_IceStyle; - fpDisplayBottomHelpLine = DisplayBottomHelpLine_IceStyle; - fpHandleESCMenu = handleIceESCMenu; - fpDisplayTime = displayTime_IceStyle; + load(gStartupPath + "SlyEdit_IceStuff.js"); + 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 + fpDrawQuoteWindowTopBorder = DrawQuoteWindowTopBorder_IceStyle; + fpDisplayTextAreaBottomBorder = DisplayTextAreaBottomBorder_IceStyle; + fpDrawQuoteWindowBottomBorder = DrawQuoteWindowBottomBorder_IceStyle; + fpRedrawScreen = redrawScreen_IceStyle; + fpUpdateInsertModeOnScreen = updateInsertModeOnScreen_IceStyle; + fpDisplayBottomHelpLine = DisplayBottomHelpLine_IceStyle; + fpHandleESCMenu = handleIceESCMenu; + fpDisplayTime = displayTime_IceStyle; } // Temporary (for testing): Make the edit area small @@ -311,35 +299,41 @@ 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; var gInputFilename = file_getcase(system.node_dir + "QUOTES.TXT"); if (gInputFilename == undefined) { - gUseQuotes = false; - if ((argc > 0) && (gInputFilename == undefined)) - gInputFilename = argv[0]; + gUseQuotes = false; + if ((argc > 0) && (gInputFilename == undefined)) + gInputFilename = argv[0]; } else { - var all_files = directory(system.node_dir + "*"); - var newest_filedate = -Infinity; - var newest_filename; - for (var file in all_files) - { - if (all_files[file].search(/quotes.txt$/i) != -1) - { - var this_date = file_date(all_files[file]); - if (this_date > newest_filedate) - { - newest_filename = all_files[file]; - newest_filedate = this_date; - } - } - } - if (newest_filename != undefined) - gInputFilename = newest_filename; + var all_files = directory(system.node_dir + "*"); + var newest_filedate = -Infinity; + var newest_filename; + for (var file in all_files) + { + if (all_files[file].search(/quotes.txt$/i) != -1) + { + var this_date = file_date(all_files[file]); + if (this_date > newest_filedate) + { + newest_filename = all_files[file]; + newest_filedate = this_date; + } + } + } + if (newest_filename != undefined) + gInputFilename = newest_filename; } var gOldStatus = bbs.sys_status; @@ -363,25 +357,25 @@ var dropFileTime = -Infinity; var dropFileName = file_getcase(system.node_dir + "msginf"); if (dropFileName != undefined) { - if (file_date(dropFileName) >= dropFileTime) - { - var dropFile = new File(dropFileName); - if (dropFile.exists && dropFile.open("r")) - { - dropFileTime = dropFile.date; - info = dropFile.readAll(); - dropFile.close(); - - gFromName = info[0]; - gToName = info[1]; - gMsgSubj = info[2]; - gMsgArea = info[4]; + if (file_date(dropFileName) >= dropFileTime) + { + var dropFile = new File(dropFileName); + if (dropFile.exists && dropFile.open("r")) + { + dropFileTime = dropFile.date; + info = dropFile.readAll(); + dropFile.close(); + + 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 gMsgAreaInfo. - gMsgAreaInfo = getCurMsgInfo(gMsgArea); - setMsgAreaInfoObj = true; + gMsgAreaInfo = getCurMsgInfo(gMsgArea); + setMsgAreaInfoObj = true; // If we're configured to use poster's initials in the // quote lines, then do it. @@ -407,22 +401,22 @@ if (dropFileName != undefined) gQuotePrefix = ""; if (gConfigSettings.indentQuoteLinesWithInitials) gQuotePrefix = " "; - // Use the initials or first 2 characters from the - // quoted name for gQuotePrefix. - var spaceIndex = quotedName.indexOf(" "); - if (spaceIndex > -1) // If a space exists, use the initials - { + // Use the initials or first 2 characters from the + // quoted name for gQuotePrefix. + var spaceIndex = quotedName.indexOf(" "); + if (spaceIndex > -1) // If a space exists, use the initials + { gQuotePrefix += quotedName.charAt(0).toUpperCase(); - if (quotedName.length > spaceIndex+1) - gQuotePrefix += quotedName.charAt(spaceIndex+1).toUpperCase(); - gQuotePrefix += "> "; - } - else // A space doesn't exist; use the first 2 letters - gQuotePrefix += quotedName.substr(0, 2) + "> "; + if (quotedName.length > spaceIndex+1) + gQuotePrefix += quotedName.charAt(spaceIndex+1).toUpperCase(); + gQuotePrefix += "> "; + } + else // A space doesn't exist; use the first 2 letters + gQuotePrefix += quotedName.substr(0, 2) + "> "; + } } - } - } - file_remove(dropFileName); + } + file_remove(dropFileName); } // If gMsgAreaInfo hasn't been set yet, then set it. if (!setMsgAreaInfoObj) @@ -441,10 +435,10 @@ if (postingInMsgSubBoard(gMsgArea)) var inputFile = new File(gInputFilename); if (inputFile.open("r", false)) { - // Read into the gQuoteLines or gEditLines array, depending on the value - // of gUseQuotes. Use a buffer size that should be long enough. - if (gUseQuotes) - { + // Read into the gQuoteLines or gEditLines array, depending on the value + // of gUseQuotes. Use a buffer size that should be long enough. + if (gUseQuotes) + { var textLine = null; // Line of text read from the quotes file while (!inputFile.eof) { @@ -478,45 +472,45 @@ if (inputFile.open("r", false)) gQuoteLines[i] = quote_msg(gQuoteLines[i], maxQuoteLineWidth, gQuotePrefix); } } - } - else - { - var textLine = null; - while (!inputFile.eof) - { - textLine = new TextLine(); - textLine.text = inputFile.readln(2048); - if (typeof(textLine.text) == "string") - textLine.text = strip_ctrl(textLine.text); - else - textLine.text = ""; - textLine.hardNewlineEnd = true; - // If there would still be room on the line for at least - // 1 more character, then add a space to the end of the - // line. - if (textLine.text.length < console.screen_columns-1) - textLine.text += " "; - gEditLines.push(textLine); - } - - // If the last edit line is undefined (which is possible after reading the end - // of the quotes file), then remove it from gEditLines. - if (gEditLines.length > 0) - { - if (gEditLines.length > 0) - { - var lastQuoteLineIndex = gEditLines.length - 1; - if (gEditLines[lastQuoteLineIndex].text == undefined) - gEditLines.splice(lastQuoteLineIndex, 1); - } - } - } - inputFile.close(); + } + else + { + var textLine = null; + while (!inputFile.eof) + { + textLine = new TextLine(); + textLine.text = inputFile.readln(2048); + if (typeof(textLine.text) == "string") + textLine.text = strip_ctrl(textLine.text); + else + textLine.text = ""; + textLine.hardNewlineEnd = true; + // If there would still be room on the line for at least + // 1 more character, then add a space to the end of the + // line. + if (textLine.text.length < console.screen_columns-1) + textLine.text += " "; + gEditLines.push(textLine); + } + + // If the last edit line is undefined (which is possible after reading the end + // of the quotes file), then remove it from gEditLines. + if (gEditLines.length > 0) + { + if (gEditLines.length > 0) + { + var lastQuoteLineIndex = gEditLines.length - 1; + if (gEditLines[lastQuoteLineIndex].text == undefined) + gEditLines.splice(lastQuoteLineIndex, 1); + } + } + } + inputFile.close(); } // If the subject is blank, set it to something. if (gMsgSubj == "") - gMsgSubj = gToName.replace(/^.*[\\\/]/,''); + gMsgSubj = gToName.replace(/^.*[\\\/]/,''); // Store a copy of the current subject (possibly allowing the user to // change the subject in the future) var gOldSubj = gMsgSubj; @@ -767,81 +761,82 @@ exit(exitCode); // Edit mode & input loop function doEditLoop() { - // Return codes: - // 0: Success - // 1: Aborted - var returnCode = 0; + // Return codes: + // 0: Success + // 1: Aborted + var returnCode = 0; // Set the shortcut keys. Note: Avoid CTRL_H because that - // backspace. - const ABORT_KEY = CTRL_A; - const CROSSPOST_KEY = CTRL_C; - const DELETE_LINE_KEY = CTRL_D; - const GENERAL_HELP_KEY = CTRL_G; - const TOGGLE_INSERT_KEY = CTRL_I; - const CHANGE_COLOR_KEY = CTRL_K; - const FIND_TEXT_KEY = CTRL_N; - const IMPORT_FILE_KEY = CTRL_O; - const CMDLIST_HELP_KEY = CTRL_P; - const QUOTE_KEY = CTRL_Q; - const PROGRAM_INFO_HELP_KEY = CTRL_R; - const PAGE_DOWN_KEY = CTRL_S; - const PAGE_UP_KEY = CTRL_W; - const EXPORT_FILE_KEY = CTRL_X; - const SAVE_KEY = CTRL_Z; + // is backspace. + const ABORT_KEY = CTRL_A; + const CROSSPOST_KEY = CTRL_C; + const DELETE_LINE_KEY = CTRL_D; + const GENERAL_HELP_KEY = CTRL_G; + const TOGGLE_INSERT_KEY = CTRL_I; + const CHANGE_COLOR_KEY = CTRL_K; + const FIND_TEXT_KEY = CTRL_N; + const IMPORT_FILE_KEY = CTRL_O; + const CMDLIST_HELP_KEY = CTRL_P; + const QUOTE_KEY = CTRL_Q; + const PROGRAM_INFO_HELP_KEY = CTRL_R; + const PAGE_DOWN_KEY = CTRL_S; + const LIST_TXT_REPLACEMENTS_KEY = CTRL_T; + const PAGE_UP_KEY = CTRL_W; + const EXPORT_FILE_KEY = CTRL_X; + const SAVE_KEY = CTRL_Z; // Draw the screen. // Note: This is purposefully drawing the top of the message. We // want to place the cursor at the first character on the top line, - // too. This is for the case where we're editin an existing message - + // too. This is for the case where we're editing an existing message - // we want to start editigng it at the top. - fpRedrawScreen(gEditLeft, gEditRight, gEditTop, gEditBottom, gTextAttrs, - gInsertMode, gUseQuotes, 0, displayEditLines); - - var curpos = new Object(); - curpos.x = gEditLeft; - curpos.y = gEditTop; - console.gotoxy(curpos); - - // Input loop - var userInput = ""; - var currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); - var numKeysPressed = 0; // Used only to determine when to call updateTime() - var continueOn = true; - while (continueOn) - { - // Get a key, and time out after 5 minutes. - // Get a keypress from the user. If the setting for using the - // input timeout is enabled and the user is not a sysop, then use - // the input timeout specified in the config file. Otherwise, - // don't use a timeout. - if (gConfigSettings.userInputTimeout && !gIsSysop) - userInput = console.inkey(K_NOCRLF|K_NOSPIN, gConfigSettings.inputTimeoutMS); - else - userInput = console.getkey(K_NOCRLF|K_NOSPIN); - // If userInput is blank, then the input timeout was probably - // reached, so abort. - if (userInput == "") - { - returnCode = 1; // Aborted - continueOn = false; - console.crlf(); - console.print("nhr" + EDITOR_PROGRAM_NAME + ": Input timeout reached."); - continue; - } - - // If we reach this code, the timeout wasn't reached. - ++numKeysPressed; - - // If gEditLines currently has 1 less line than we need, - // then add a new line to gEditLines. - if (gEditLines.length == gEditLinesIndex) - gEditLines.push(new TextLine()); - - // Take the appropriate action for the key pressed. - switch (userInput) - { - case ABORT_KEY: + fpRedrawScreen(gEditLeft, gEditRight, gEditTop, gEditBottom, gTextAttrs, + gInsertMode, gUseQuotes, 0, displayEditLines); + + var curpos = new Object(); + curpos.x = gEditLeft; + curpos.y = gEditTop; + console.gotoxy(curpos); + + // Input loop + var userInput = ""; + var currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); + var numKeysPressed = 0; // Used only to determine when to call updateTime() + var continueOn = true; + while (continueOn) + { + // Get a key, and time out after 5 minutes. + // Get a keypress from the user. If the setting for using the + // input timeout is enabled and the user is not a sysop, then use + // the input timeout specified in the config file. Otherwise, + // don't use a timeout. + if (gConfigSettings.userInputTimeout && !gIsSysop) + userInput = console.inkey(K_NOCRLF|K_NOSPIN, gConfigSettings.inputTimeoutMS); + else + userInput = console.getkey(K_NOCRLF|K_NOSPIN); + // If userInput is blank, then the input timeout was probably + // reached, so abort. + if (userInput == "") + { + returnCode = 1; // Aborted + continueOn = false; + console.crlf(); + console.print("nhr" + EDITOR_PROGRAM_NAME + ": Input timeout reached."); + continue; + } + + // If we get here, that means the timeout wasn't reached. + ++numKeysPressed; + + // If gEditLines currently has 1 less line than we need, + // then add a new line to gEditLines. + if (gEditLines.length == gEditLinesIndex) + gEditLines.push(new TextLine()); + + // Take the appropriate action for the key pressed. + switch (userInput) + { + case ABORT_KEY: // Before aborting, ask they user if they really want to abort. if (promptYesNo("Abort message", false, "Abort")) { @@ -854,33 +849,33 @@ function doEditLoop() //console.print("n" + gTextAttrs); console.print(chooseEditColor()); } - break; - case SAVE_KEY: - returnCode = 0; // Save - continueOn = false; - break; - case CMDLIST_HELP_KEY: - displayCommandList(true, true, true, gCanCrossPost, gIsSysop); - clearEditAreaBuffer(); + break; + case SAVE_KEY: + returnCode = 0; // Save + continueOn = false; + break; + case CMDLIST_HELP_KEY: + displayCommandList(true, true, true, gCanCrossPost, gIsSysop, gConfigSettings.enableTextReplacements); + clearEditAreaBuffer(); + fpRedrawScreen(gEditLeft, gEditRight, gEditTop, gEditBottom, gTextAttrs, + gInsertMode, gUseQuotes, gEditLinesIndex-(curpos.y-gEditTop), + displayEditLines); + break; + case GENERAL_HELP_KEY: + displayGeneralHelp(true, true, true); + clearEditAreaBuffer(); fpRedrawScreen(gEditLeft, gEditRight, gEditTop, gEditBottom, gTextAttrs, - gInsertMode, gUseQuotes, gEditLinesIndex-(curpos.y-gEditTop), - displayEditLines); - break; - case GENERAL_HELP_KEY: - displayGeneralHelp(true, true, true); - clearEditAreaBuffer(); - fpRedrawScreen(gEditLeft, gEditRight, gEditTop, gEditBottom, gTextAttrs, - gInsertMode, gUseQuotes, gEditLinesIndex-(curpos.y-gEditTop), - displayEditLines); - break; - case PROGRAM_INFO_HELP_KEY: - displayProgramInfo(true, true, true); - clearEditAreaBuffer(); - fpRedrawScreen(gEditLeft, gEditRight, gEditTop, gEditBottom, gTextAttrs, - gInsertMode, gUseQuotes, gEditLinesIndex-(curpos.y-gEditTop), - displayEditLines); + gInsertMode, gUseQuotes, gEditLinesIndex-(curpos.y-gEditTop), + displayEditLines); break; - case QUOTE_KEY: + case PROGRAM_INFO_HELP_KEY: + displayProgramInfo(true, true); + clearEditAreaBuffer(); + fpRedrawScreen(gEditLeft, gEditRight, gEditTop, gEditBottom, gTextAttrs, + gInsertMode, gUseQuotes, gEditLinesIndex-(curpos.y-gEditTop), + displayEditLines); + break; + case QUOTE_KEY: // Let the user choose & insert quote lines into the message. if (gUseQuotes) { @@ -900,7 +895,7 @@ function doEditLoop() } break; case CHANGE_COLOR_KEY: - /* + /* // Let the user change the text color. if (gConfigSettings.allowColorSelection) { @@ -920,260 +915,260 @@ function doEditLoop() } */ break; - case KEY_UP: - // Move the cursor up one line. - if (gEditLinesIndex > 0) - { - --gEditLinesIndex; - - // 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, - // then scroll up through the message by 1 line. - if (curpos.y == gEditTop) - displayEditLines(gEditTop, gEditLinesIndex, gEditBottom, true, /*true*/false); - else - --curpos.y; - - console.gotoxy(curpos); - currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); - console.print(chooseEditColor()); // Make sure the edit color is correct - } - break; - case KEY_DOWN: - // Move the cursor down one line. - if (gEditLinesIndex < gEditLines.length-1) - { - ++gEditLinesIndex; - // 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); - } - else - ++curpos.y; - - console.gotoxy(curpos); - currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); - console.print(chooseEditColor()); // Make sure the edit color is correct - } - break; - case KEY_LEFT: - // If the horizontal cursor position is right of the - // leftmost edit position, then let it move left. - if (curpos.x > gEditLeft) - { - --curpos.x; - console.gotoxy(curpos); - if (gTextLineIndex > 0) - --gTextLineIndex; - } - else - { - // The cursor is at the leftmost position in the - // edit area. If there are text lines above the - // current line, then move the cursor to the end - // of the previous line. - if (gEditLinesIndex > 0) - { - --gEditLinesIndex; - 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); - } - } - console.print(chooseEditColor()); - - // Update the current word length. - currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); - // Make sure the edit color is correct - console.print(chooseEditColor()); - break; - case KEY_RIGHT: - // If the horizontal cursor position is left of the - // rightmost edit position, then the cursor can move - // to the right. - if (curpos.x < gEditRight) - { - // The current line index must be within bounds - // before we can move the cursor to the right. - if (gTextLineIndex < gEditLines[gEditLinesIndex].length()) - { - ++curpos.x; - console.gotoxy(curpos); - ++gTextLineIndex; - } - else - { - // The cursor is at the rightmost position on the - // line. If there are text lines below the current - // line, then move the cursor to the start of the - // next line. - if (gEditLinesIndex < gEditLines.length-1) - { - ++gEditLinesIndex; - curpos.x = gEditLeft; - // Move the cursor down or scroll down by one line - if (curpos.y < gEditBottom) - ++curpos.y; - else - displayEditLines(gEditTop, gEditLinesIndex-(gEditBottom-gEditTop), - gEditBottom, true, /*true*/false); - gTextLineIndex = 0; - console.gotoxy(curpos); - } - } - } - else - { - // The cursor is at the rightmost position in the - // edit area. If there are text lines below the - // current line, then move the cursor to the start - // of the next line. - if (gEditLinesIndex < gEditLines.length-1) - { - ++gEditLinesIndex; - curpos.x = gEditLeft; - // Move the cursor down or scroll down by one line - if (curpos.y < gEditBottom) - ++curpos.y; - else - displayEditLines(gEditTop, gEditLinesIndex-(gEditBottom-gEditTop), - gEditBottom, true, false); - gTextLineIndex = 0; - console.gotoxy(curpos); - } - } - console.print(chooseEditColor()); - - // 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); - // Update the current word length. + case KEY_UP: + // Move the cursor up one line. + if (gEditLinesIndex > 0) + { + --gEditLinesIndex; + + // 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, + // then scroll up through the message by 1 line. + if (curpos.y == gEditTop) + displayEditLines(gEditTop, gEditLinesIndex, gEditBottom, true, /*true*/false); + else + --curpos.y; + + console.gotoxy(curpos); + currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); + console.print(chooseEditColor()); // Make sure the edit color is correct + } + break; + case KEY_DOWN: + // Move the cursor down one line. + if (gEditLinesIndex < gEditLines.length-1) + { + ++gEditLinesIndex; + // 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); + } + else + ++curpos.y; + + console.gotoxy(curpos); + currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); + console.print(chooseEditColor()); // Make sure the edit color is correct + } + break; + case KEY_LEFT: + // If the horizontal cursor position is right of the + // leftmost edit position, then let it move left. + if (curpos.x > gEditLeft) + { + --curpos.x; + console.gotoxy(curpos); + if (gTextLineIndex > 0) + --gTextLineIndex; + } + else + { + // The cursor is at the leftmost position in the + // edit area. If there are text lines above the + // current line, then move the cursor to the end + // of the previous line. + if (gEditLinesIndex > 0) + { + --gEditLinesIndex; + 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); + } + } + console.print(chooseEditColor()); + + // Update the current word length. + currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); + // Make sure the edit color is correct + console.print(chooseEditColor()); + break; + case KEY_RIGHT: + // If the horizontal cursor position is left of the + // rightmost edit position, then the cursor can move + // to the right. + if (curpos.x < gEditRight) + { + // The current line index must be within bounds + // before we can move the cursor to the right. + if (gTextLineIndex < gEditLines[gEditLinesIndex].length()) + { + ++curpos.x; + console.gotoxy(curpos); + ++gTextLineIndex; + } + else + { + // The cursor is at the rightmost position on the + // line. If there are text lines below the current + // line, then move the cursor to the start of the + // next line. + if (gEditLinesIndex < gEditLines.length-1) + { + ++gEditLinesIndex; + curpos.x = gEditLeft; + // Move the cursor down or scroll down by one line + if (curpos.y < gEditBottom) + ++curpos.y; + else + displayEditLines(gEditTop, gEditLinesIndex-(gEditBottom-gEditTop), + gEditBottom, true, /*true*/false); + gTextLineIndex = 0; + console.gotoxy(curpos); + } + } + } + else + { + // The cursor is at the rightmost position in the + // edit area. If there are text lines below the + // current line, then move the cursor to the start + // of the next line. + if (gEditLinesIndex < gEditLines.length-1) + { + ++gEditLinesIndex; + curpos.x = gEditLeft; + // Move the cursor down or scroll down by one line + if (curpos.y < gEditBottom) + ++curpos.y; + else + displayEditLines(gEditTop, gEditLinesIndex-(gEditBottom-gEditTop), + gEditBottom, true, false); + gTextLineIndex = 0; + console.gotoxy(curpos); + } + } + console.print(chooseEditColor()); + + // Update the current word length. currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); - break; - case KEY_END: - // Go to the end of the line - if (gEditLinesIndex < gEditLines.length) - { - 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) - { + // 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); + // Update the current word length. + currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); + break; + case KEY_END: + // Go to the end of the line + if (gEditLinesIndex < gEditLines.length) + { + 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) + { var difference = curpos.x - gEditRight; curpos.x -= difference; gTextLineIndex -= difference; - } - // Place the cursor where it should be. - console.gotoxy(curpos); + } + // Place the cursor where it should be. + console.gotoxy(curpos); - // Update the current word length. + // Update the current word length. currentWordLength = getWordLength(gEditLinesIndex, gTextLineIndex); - } - break; - case BACKSPACE: - // Delete the previous character - var retObject = doBackspace(curpos, currentWordLength); - curpos.x = retObject.x; - curpos.y = retObject.y; - currentWordLength = retObject.currentWordLength; - // Make sure the edit color is correct - console.print(chooseEditColor()); - break; - case KEY_DEL: - // Delete the next character - var retObject = doDeleteKey(curpos, currentWordLength); - curpos.x = retObject.x; - curpos.y = retObject.y; - currentWordLength = retObject.currentWordLength; - // Make sure the edit color is correct - console.print(chooseEditColor()); - break; - case KEY_ENTER: - 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) - { - if (retObject.doQuoteSelection) - { - if (gUseQuotes) - { - retObject = doQuoteSelection(curpos, currentWordLength); - curpos.x = retObject.x; - curpos.y = retObject.y; - currentWordLength = retObject.currentWordLength; - // If user input timed out, then abort. - if (retObject.timedOut) - { - returnCode = 1; // Aborted - continueOn = false; - console.crlf(); - console.print("nhr" + EDITOR_PROGRAM_NAME + ": Input timeout reached."); - continue; - } - } - } - else if (retObject.showHelp) - { - displayProgramInfo(true, true, false); - displayCommandList(false, false, true, gCanCrossPost, gIsSysop); - clearEditAreaBuffer(); - fpRedrawScreen(gEditLeft, gEditRight, gEditTop, gEditBottom, gTextAttrs, - gInsertMode, gUseQuotes, gEditLinesIndex-(curpos.y-gEditTop), - displayEditLines); - console.gotoxy(curpos); - } - else if (retObject.doCrossPostSelection) - { - if (gCanCrossPost) - doCrossPosting(); - } - } - // Make sure the edit color is correct - console.print(chooseEditColor()); - break; + } + break; + case BACKSPACE: + // Delete the previous character + var retObject = doBackspace(curpos, currentWordLength); + curpos.x = retObject.x; + curpos.y = retObject.y; + currentWordLength = retObject.currentWordLength; + // Make sure the edit color is correct + console.print(chooseEditColor()); + break; + case KEY_DEL: + // Delete the next character + var retObject = doDeleteKey(curpos, currentWordLength); + curpos.x = retObject.x; + curpos.y = retObject.y; + currentWordLength = retObject.currentWordLength; + // Make sure the edit color is correct + console.print(chooseEditColor()); + break; + case KEY_ENTER: + 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) + { + if (retObject.doQuoteSelection) + { + if (gUseQuotes) + { + retObject = doQuoteSelection(curpos, currentWordLength); + curpos.x = retObject.x; + curpos.y = retObject.y; + currentWordLength = retObject.currentWordLength; + // If user input timed out, then abort. + if (retObject.timedOut) + { + returnCode = 1; // Aborted + continueOn = false; + console.crlf(); + console.print("nhr" + EDITOR_PROGRAM_NAME + ": Input timeout reached."); + continue; + } + } + } + else if (retObject.showHelp) + { + displayProgramInfo(true, false); + displayCommandList(false, false, true, gCanCrossPost, gIsSysop, gConfigSettings.enableTextReplacements); + clearEditAreaBuffer(); + fpRedrawScreen(gEditLeft, gEditRight, gEditTop, gEditBottom, gTextAttrs, + gInsertMode, gUseQuotes, gEditLinesIndex-(curpos.y-gEditTop), + displayEditLines); + console.gotoxy(curpos); + } + else if (retObject.doCrossPostSelection) + { + if (gCanCrossPost) + doCrossPosting(); + } + } + // Make sure the edit color is correct + console.print(chooseEditColor()); + break; // Insert/overwrite mode toggle case KEY_INSERT: case TOGGLE_INSERT_KEY: @@ -1182,7 +1177,7 @@ function doEditLoop() console.print(chooseEditColor()); console.gotoxy(curpos); break; - case KEY_ESC: + case KEY_ESC: // Do the ESC menu var retObj = fpHandleESCMenu(curpos, currentWordLength); returnCode = retObj.returnCode; @@ -1198,7 +1193,7 @@ function doEditLoop() console.print(chooseEditColor()); console.gotoxy(curpos); } - break; + break; case FIND_TEXT_KEY: var retObj = findText(curpos); curpos.x = retObj.x; @@ -1343,9 +1338,13 @@ function doEditLoop() if (gCanCrossPost) doCrossPosting(); break; + case LIST_TXT_REPLACEMENTS_KEY: + if (gConfigSettings.enableTextReplacements) + listTextReplacements(); + break; default: // For the tab character, insert 3 spaces. Otherwise, - // if it's a printabel character, add the character. + // if it's a printable character, add the character. if (/\t/.test(userInput)) { var retObject; @@ -1368,13 +1367,13 @@ function doEditLoop() } } break; - } + } - // For every 5 keys pressed, dheck the current time and update - // it on the screen if necessary. - if (numKeysPressed % 5 == 0) - updateTime(); - } + // For every 5 keys pressed, dheck the current time and update + // it on the screen if necessary. + if (numKeysPressed % 5 == 0) + updateTime(); + } // 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. @@ -1384,7 +1383,7 @@ function doEditLoop() gEditLines.splice(0, 1); } - return returnCode; + return returnCode; } // Helper function for doEditLoop(): Handles the backspace behavior. // @@ -1398,52 +1397,52 @@ function doEditLoop() function doBackspace(pCurpos, 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 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) { @@ -1522,20 +1521,20 @@ function doBackspace(pCurpos, pCurrentWordLength) didBackspace = true; } } - } - } + } + } - // If the backspace was performed, then re-adjust the text lines - // and refresh the screen. - if (didBackspace) - { + // 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); + 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 @@ -1569,10 +1568,10 @@ function doBackspace(pCurpos, pCurrentWordLength) // 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. + // 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. @@ -1584,11 +1583,11 @@ function doBackspace(pCurpos, pCurrentWordLength) // 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; + return retObj; } // Helper function for doEditLoop(): Handles the delete key behavior. @@ -1604,9 +1603,9 @@ function doDeleteKey(pCurpos, pCurrentWordLength) { // Create the return object var returnObject = new Object(); - returnObject.x = pCurpos.x; - returnObject.y = pCurpos.y; - returnObject.currentWordLength = pCurrentWordLength; + returnObject.x = pCurpos.x; + returnObject.y = pCurpos.y; + returnObject.currentWordLength = pCurrentWordLength; // Store the original line text (for testing to see if we should update the screen). var originalLineText = gEditLines[gEditLinesIndex].text; @@ -1737,8 +1736,8 @@ function doPrintableChar(pUserInput, pCurpos, pCurrentWordLength) // Create the return object. var retObj = new Object(); retObj.x = pCurpos.x; - retObj.y = pCurpos.y; - retObj.currentWordLength = pCurrentWordLength; + retObj.y = pCurpos.y; + retObj.currentWordLength = pCurrentWordLength; // Note: gTextLineIndex is where the new character will appear in the line. // If gTextLineIndex is somehow past the end of the current line, then @@ -1768,6 +1767,21 @@ function doPrintableChar(pUserInput, pCurpos, pCurrentWordLength) } } + // Handle text replacement (AKA macros). Added 2013-08-31. + var madeTxtReplacement = false; // For screen refresh purposes + if (gConfigSettings.enableTextReplacements && (pUserInput == " ")) + { + var txtReplaceObj = doMacroTxtReplacementInEditLine(gTxtReplacements, gEditLinesIndex, + gTextLineIndex, + gConfigSettings.textReplacementsUseRegex); + madeTxtReplacement = txtReplaceObj.madeTxtReplacement; + if (madeTxtReplacement) + { + retObj.x += txtReplaceObj.wordLenDiff; + 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; @@ -1782,9 +1796,10 @@ function doPrintableChar(pUserInput, pCurpos, pCurrentWordLength) // 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()), - // then we'll need to refresh multiple lines on the screen. - if (reAdjusted && (gEditLines[gEditLinesIndex].text != originalAfterCharApplied)) + // 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) { // TODO: In case the user entered a whole line of text without any spaces, // the new character would appear on the next line, so we need to figure @@ -1909,14 +1924,18 @@ function doEnterKey(pCurpos, pCurrentWordLength) { // Create the return object 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; + 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; + var initialEditLinesIndex = gEditLinesIndex; // Check for slash commands (/S, /A, /?). If the user has // typed one of them by itself at the beginning of the line, @@ -2009,21 +2028,96 @@ function doEnterKey(pCurpos, pCurrentWordLength) console.gotoxy(retObj.x, retObj.y); return(retObj); } + else if (lineUpper == "/T") + { + if (gConfigSettings.enableTextReplacements) + listTextReplacements(); + // 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 /C on the screen + //console.print("n" + gTextAttrs); + console.print(chooseEditColor()); + retObj.x = gEditLeft; + console.gotoxy(retObj.x, retObj.y); + console.print(" "); + // Put the cursor where it should be and return. + console.gotoxy(retObj.x, retObj.y); + return(retObj); + } } - // Store the current screen row position and gEditLines index. - var initialScreenLine = pCurpos.y; - var initialEditLinesIndex = gEditLinesIndex; + // Handle text replacement (AKA macros). Added 2013-08-31. + var reAdjustedTxtLines = false; // For screen refresh purposes + // cursorHorizDiff will be set if the replaced word is too long to fit on + // the end of the line - In that case, the cursor and line index will have + // to be adjusted since the new word will be moved to the next line. + var cursorHorizDiff = 0; + if (gConfigSettings.enableTextReplacements) + { + var txtReplaceObj = doMacroTxtReplacementInEditLine(gTxtReplacements, gEditLinesIndex, + gTextLineIndex-1, + gConfigSettings.textReplacementsUseRegex); + if (txtReplaceObj.madeTxtReplacement) + { + gTextLineIndex += txtReplaceObj.wordLenDiff; + retObj.x += txtReplaceObj.wordLenDiff; + retObj.currentWordLength += txtReplaceObj.wordLenDiff; + + // If the replaced text on the line is too long to print on the screen,then + // then we'll need to wrap the line. + // If the logical screen column of the last character of the last word + // 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) + { + var spaceIdx = gEditLines[gEditLinesIndex].text.lastIndexOf(" ", txtReplaceObj.textLineIndex); + while ((spaceIdx > -1) && (spaceIdx > gEditWidth-2)) // To split lines at the 79th column + spaceIdx = gEditLines[gEditLinesIndex].text.lastIndexOf(" ", spaceIdx-1); + // If a space was found after the start of the new text, then + // set gTextLineIndex to the first character of the word we want + // to split the line at, and the horizontal cursor offset based on + // the difference. + if (spaceIdx > txtReplaceObj.wordStartIdx) + { + gTextLineIndex = spaceIdx + 1; + cursorHorizDiff = txtReplaceObj.newTextEndIdx - spaceIdx; + } + else + { + gTextLineIndex = txtReplaceObj.wordStartIdx; + cursorHorizDiff = txtReplaceObj.newTextLen; + } + } + else + { + // The new text doesn't contain a space, so set gTextLineIndex + // to the start of the new word so that + // enterKey_InsertOrAppendNewLine() will split the line there. + gTextLineIndex = txtReplaceObj.wordStartIdx; + cursorHorizDiff = txtReplaceObj.newTextLen; + } + } + } + } - // If we're currently on the last line, then we'll need to append - // a new line. Otherwise, we'll need to splice a new line into - // gEditLines where appropriate. + // If we're currently on the last line, then we'll need to append + // a new line. Otherwise, we'll need to splice a new line into + // gEditLines where appropriate. - var appendLineToEnd = (gEditLinesIndex == gEditLines.length-1); - var retObject = enterKey_InsertOrAppendNewLine(pCurpos, pCurrentWordLength, appendLineToEnd); - retObj.x = retObject.x; - retObj.y = retObject.y; - retObj.currentWordLength = retObject.currentWordLength; + var appendLineToEnd = (gEditLinesIndex == gEditLines.length-1); + var retObject = enterKey_InsertOrAppendNewLine(pCurpos, pCurrentWordLength, appendLineToEnd); + retObj.x = retObject.x; + retObj.y = retObject.y; + retObj.currentWordLength = retObject.currentWordLength; // If a line was added to gEditLines, then set the hardNewlineEnd property // to true for both lines. @@ -2033,18 +2127,23 @@ function doEnterKey(pCurpos, pCurrentWordLength) gEditLines[gEditLinesIndex].hardNewlineEnd = true; } - // Refresh the message text on the screen if that wasn't done by - // enterKey_InsertOrAppendNewLine(). - if (!retObject.displayedEditlines) + // Refresh the message text on the screen if that wasn't done by + // enterKey_InsertOrAppendNewLine(). + if (!retObject.displayedEditlines) displayEditLines(initialScreenLine, initialEditLinesIndex, gEditBottom, true, true); - console.gotoxy(retObj.x, retObj.y); + // Note: cursorHorizDiff is set if a word was replaced and the line was + // wrapped because the new word wastoo long to fit on the end of the line. + retObj.x += cursorHorizDiff; + gTextLineIndex += cursorHorizDiff; - return retObj; + console.gotoxy(retObj.x, retObj.y); + + return retObj; } // Helper function for doEnterKey(): Appends/inserts a line to gEditLines -// and returns the position of where the cursor shoul dbe. +// and returns the position of where the cursor should be. // // Parameters: // pCurpos: An object containing x and y values representing the @@ -2068,117 +2167,117 @@ function enterKey_InsertOrAppendNewLine(pCurpos, pCurrentWordLength, pAppendLine 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; + // 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()); + } + else + { + // Increment gEditLinesIndex and add a new line there. + ++gEditLinesIndex; + gEditLines.splice(gEditLinesIndex, 0, new TextLine()); 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); + } + + 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 (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; + 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 (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) + } + 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); + gEditLines.splice(gEditLinesIndex, 0, newTextLine); 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 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; - } - - // Set some stuff in the return object, and return it. - returnObject.x = pCurpos.x; - returnObject.y = pCurpos.y; - returnObject.currentWordLength = pCurrentWordLength; - return returnObject; + + 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; + } + + // Set some stuff in the return object, and return it. + returnObject.x = pCurpos.x; + returnObject.y = pCurpos.y; + returnObject.currentWordLength = pCurrentWordLength; + return returnObject; } // This function handles quote selection and is called by doEditLoop(). @@ -2238,19 +2337,19 @@ function doQuoteSelection(pCurpos, pCurrentWordLength) var continueOn = true; while (continueOn) { - // Get a key, and time out after 1 minute. - userInput = console.inkey(0, 100000); - if (userInput == "") - { - // The input timeout was reached. Abort. - retObj.timedOut = true; - continueOn = false; - break; - } - - // If we got here, that means the user input didn't time out. - switch (userInput) - { + // Get a key, and time out after 1 minute. + userInput = console.inkey(0, 100000); + if (userInput == "") + { + // The input timeout was reached. Abort. + retObj.timedOut = true; + continueOn = false; + break; + } + + // If we got here, that means the user input didn't time out. + switch (userInput) + { case KEY_UP: // Go up 1 quote line if (gQuoteLinesIndex > 0) @@ -2362,7 +2461,7 @@ function doQuoteSelection(pCurpos, pCurrentWordLength) // Quit out of the input loop (get out of quote mode). continueOn = false; break; - } + } } // We've exited quote mode. Refresh the message text on the screen. Note: @@ -2384,9 +2483,9 @@ function doQuoteSelection(pCurpos, pCurrentWordLength) console.gotoxy(curpos); // Set the settings in the return object, and return it. - retObj.x = curpos.x; - retObj.y = curpos.y; - return retObj; + retObj.x = curpos.x; + retObj.y = curpos.y; + return retObj; } // Helper for doQuoteSelection(): This function moves the quote selection @@ -2656,18 +2755,18 @@ function displayEditLines(pStartScreenRow, pArrayIndex, pEndScreenRow, pClearRem // pEndScreenRow or gEditBottom. var endScreenRow = (pEndScreenRow != null ? pEndScreenRow : gEditBottom); - // 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) + // 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. @@ -2677,21 +2776,21 @@ function displayEditLines(pStartScreenRow, pArrayIndex, pEndScreenRow, pClearRem 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)) - { + ++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) { @@ -2700,28 +2799,28 @@ function displayEditLines(pStartScreenRow, pArrayIndex, pEndScreenRow, pClearRem } else if ((lineLength == gEditWidth) || (lineLength == 0)) incrementLineBeforeClearRemaining = false; - } - else + } + 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("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") + // 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. @@ -2735,7 +2834,7 @@ function clearMsgAreaToBottom(pStartLine, pIgnoreEditAreaBuffer) { for (var screenLine = pStartLine; screenLine <= gEditBottom; ++screenLine) { - // Note: gEditAreaBuffer is also used in displayEditLines(). + // Note: gEditAreaBuffer is also used in displayEditLines(). if ((gEditAreaBuffer[screenLine].length > 0) || pIgnoreEditAreaBuffer) { console.gotoxy(gEditLeft, screenLine); @@ -2749,18 +2848,18 @@ function clearMsgAreaToBottom(pStartLine, pIgnoreEditAreaBuffer) // it, and this tests to see if they are all empty). function messageIsEmpty() { - var msgEmpty = true; - - for (var i = 0; i < gEditLines.length; ++i) - { - if (gEditLines[i].length() > 0) - { - msgEmpty = false; - break; - } - } - - return msgEmpty; + var msgEmpty = true; + + for (var i = 0; i < gEditLines.length; ++i) + { + if (gEditLines[i].length() > 0) + { + msgEmpty = false; + break; + } + } + + return msgEmpty; } // Displays a part of the message text in a rectangle on the screen. This @@ -2918,11 +3017,11 @@ function handleDCTESCMenu(pCurpos, pCurrentWordLength) // Command List else if ((menuChoice == "O") || (menuChoice == DCTMENU_HELP_COMMAND_LIST)) { - displayCommandList(true, true, true, gCanCrossPost, gIsSysop); + displayCommandList(true, true, true, gCanCrossPost, gIsSysop, gConfigSettings.enableTextReplacements); clearEditAreaBuffer(); fpRedrawScreen(gEditLeft, gEditRight, gEditTop, gEditBottom, gTextAttrs, - gInsertMode, gUseQuotes, gEditLinesIndex-(pCurpos.y-gEditTop), - displayEditLines); + gInsertMode, gUseQuotes, gEditLinesIndex-(pCurpos.y-gEditTop), + displayEditLines); } // General help else if ((menuChoice == "G") || (menuChoice == DCTMENU_HELP_GENERAL)) @@ -2930,17 +3029,17 @@ function handleDCTESCMenu(pCurpos, pCurrentWordLength) displayGeneralHelp(true, true, true); clearEditAreaBuffer(); fpRedrawScreen(gEditLeft, gEditRight, gEditTop, gEditBottom, gTextAttrs, - gInsertMode, gUseQuotes, gEditLinesIndex-(pCurpos.y-gEditTop), - displayEditLines); + gInsertMode, gUseQuotes, gEditLinesIndex-(pCurpos.y-gEditTop), + displayEditLines); } // Program info else if ((menuChoice == "P") || (menuChoice == DCTMENU_HELP_PROGRAM_INFO)) { - displayProgramInfo(true, true, true); + displayProgramInfo(true, true); clearEditAreaBuffer(); fpRedrawScreen(gEditLeft, gEditRight, gEditTop, gEditBottom, gTextAttrs, - gInsertMode, gUseQuotes, gEditLinesIndex-(pCurpos.y-gEditTop), - displayEditLines); + gInsertMode, gUseQuotes, gEditLinesIndex-(pCurpos.y-gEditTop), + displayEditLines); } // Export the message else if ((menuChoice == "X") || (menuChoice == DCTMENU_SYSOP_EXPORT_FILE)) @@ -3017,8 +3116,8 @@ function handleIceESCMenu(pCurpos, pCurrentWordLength) // Nothing needs to be done for this option. break; case ICE_ESC_MENU_HELP: - displayProgramInfo(true, true, false); - displayCommandList(false, false, true, gCanCrossPost, gIsSysop); + displayProgramInfo(true, false); + displayCommandList(false, false, true, gCanCrossPost, gIsSysop, gConfigSettings.enableTextReplacements); clearEditAreaBuffer(); fpRedrawScreen(gEditLeft, gEditRight, gEditTop, gEditBottom, gTextAttrs, gInsertMode, gUseQuotes, gEditLinesIndex-(pCurpos.y-gEditTop), @@ -3529,26 +3628,26 @@ function calcBottomUpdateRow(pY, pTopIndex) // the cursor back to where it was. function updateTime() { - if (typeof(updateTime.timeStr) == "undefined") - updateTime.timeStr = getCurrentTimeStr(); - - // If the current time has changed since the last time this - // function was called, then update the time on the screen. - var currentTime = getCurrentTimeStr(); - if (currentTime != updateTime.timeStr) - { - // Get the current cursor position so we can move - // the cursor back there when we're done. - var curpos = console.getxy(); - // Display the current time on the screen - fpDisplayTime(currentTime); - // Make sure the edit color attribute is set. - console.print("n" + gTextAttrs); - // Move the cursor back to where it was - console.gotoxy(curpos); - // Update this function's time variable - updateTime.timeStr = currentTime; - } + if (typeof(updateTime.timeStr) == "undefined") + updateTime.timeStr = getCurrentTimeStr(); + + // If the current time has changed since the last time this + // function was called, then update the time on the screen. + var currentTime = getCurrentTimeStr(); + if (currentTime != updateTime.timeStr) + { + // Get the current cursor position so we can move + // the cursor back there when we're done. + var curpos = console.getxy(); + // Display the current time on the screen + fpDisplayTime(currentTime); + // Make sure the edit color attribute is set. + console.print("n" + gTextAttrs); + // Move the cursor back to where it was + console.gotoxy(curpos); + // Update this function's time variable + updateTime.timeStr = currentTime; + } } // This function lets the user change the text color and is called by doEditLoop(). @@ -3566,10 +3665,10 @@ function doColorSelection(pCurpos, pCurrentWordLength) { // Create the return object var retObj = new Object(); - retObj.x = pCurpos.x; - retObj.y = pCurpos.y; - retObj.timedOut = false; - retObj.currentWordLength = pCurrentWordLength; + retObj.x = pCurpos.x; + retObj.y = pCurpos.y; + retObj.timedOut = false; + retObj.currentWordLength = pCurrentWordLength; // Note: The current text color is stored in gTextAttrs @@ -3683,19 +3782,19 @@ function doColorSelection(pCurpos, pCurrentWordLength) var continueOn = true; while (continueOn) { - // Get a key, and time out after 1 minute. - userInput = console.inkey(0, 100000); - if (userInput == "") - { - // The input timeout was reached. Abort. - retObj.timedOut = true; - continueOn = false; - break; - } - - // If we got here, that means the user input didn't time out. - switch (userInput) - { + // Get a key, and time out after 1 minute. + userInput = console.inkey(0, 100000); + if (userInput == "") + { + // The input timeout was reached. Abort. + retObj.timedOut = true; + continueOn = false; + break; + } + + // If we got here, that means the user input didn't time out. + switch (userInput) + { case KEY_UP: // Go up 1 quote line if (gQuoteLinesIndex > 0) @@ -3807,7 +3906,7 @@ function doColorSelection(pCurpos, pCurrentWordLength) // Quit out of the input loop (get out of quote mode). continueOn = false; break; - } + } } // We've exited quote mode. Refresh the message text on the screen. Note: @@ -3829,9 +3928,9 @@ function doColorSelection(pCurpos, pCurrentWordLength) console.gotoxy(curpos); */ // Set the settings in the return object, and return it. - retObj.x = curpos.x; - retObj.y = curpos.y; - return retObj; + retObj.x = curpos.x; + retObj.y = curpos.y; + return retObj; } // For the cross-posting UI: Draws the initial top border of @@ -3987,13 +4086,13 @@ function doCrossPosting(pOriginalCurpos) // 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.crossPostBorderTxt + "Choose group"); + console.print("n" + gConfigSettings.genColors.listBoxBorderText + "Choose group"); //Choose group //Areas in <xxxxx> // 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.crossPostBorder + LEFT_T_SINGLE); + console.print("n" + gConfigSettings.genColors.listBoxBorder + LEFT_T_SINGLE); if (grpDesc.length > 3) { var numChars = grpDesc.length - 3; @@ -4056,8 +4155,8 @@ function doCrossPosting(pOriginalCurpos) // Draw the selection box borders // Top border drawInitialCrossPostSelBoxTopBorder(selBoxUpperLeft, selBoxWidth, - gConfigSettings.genColors.crossPostBorder, - gConfigSettings.genColors.crossPostBorderTxt); + gConfigSettings.genColors.listBoxBorder, + gConfigSettings.genColors.listBoxBorderText); // Side borders console.print(UPPER_RIGHT_SINGLE); for (var row = selBoxUpperLeft.y+1; row < selBoxLowerRight.y; ++row) @@ -4069,7 +4168,7 @@ function doCrossPosting(pOriginalCurpos) } // Bottom border drawInitialCrossPostSelBoxBottomBorder({ x: selBoxUpperLeft.x, y: selBoxLowerRight.y }, - selBoxWidth, gConfigSettings.genColors.crossPostBorder, + selBoxWidth, gConfigSettings.genColors.listBoxBorder, false); // Write the message groups @@ -4330,13 +4429,13 @@ function doCrossPosting(pOriginalCurpos) if (writePromptText) { drawInitialCrossPostSelBoxBottomBorder({ x: selBoxUpperLeft.x, y: selBoxLowerRight.y }, - selBoxWidth, gConfigSettings.genColors.crossPostBorder, + selBoxWidth, gConfigSettings.genColors.listBoxBorder, false); } else { console.gotoxy(selBoxUpperLeft.x+1, selBoxLowerRight.y); - console.print(gConfigSettings.genColors.crossPostBorder + RIGHT_T_SINGLE); + console.print(gConfigSettings.genColors.listBoxBorder + RIGHT_T_SINGLE); } // If the user made a selection, then let them choose a @@ -4601,7 +4700,7 @@ function crossPosting_selectSubBoardInGrp(pGrpIndex, pSelBoxUpperLeft, pSelBoxLo mswait(pPauseMS); // Refresh the bottom border of the selection box drawInitialCrossPostSelBoxBottomBorder({ x: pX, y: pY }, pSelBoxWidth, - gConfigSettings.genColors.crossPostBorder, true); + gConfigSettings.genColors.listBoxBorder, true); console.gotoxy(pCurpos); } @@ -4611,10 +4710,10 @@ function crossPosting_selectSubBoardInGrp(pGrpIndex, pSelBoxUpperLeft, pSelBoxLo //�Cross-posting: Areas in console.gotoxy(pSelBoxUpperLeft.x+17, pSelBoxUpperLeft.y); var grpDesc = msg_area.grp_list[pGrpIndex].description.substr(0, pSelBoxInnerWidth-25); - console.print("n" + gConfigSettings.genColors.crossPostBorderTxt + "Areas in " + + console.print("n" + gConfigSettings.genColors.listBoxBorderText + "Areas in " + grpDesc); // Write the updated border character(s) - console.print("n" + gConfigSettings.genColors.crossPostBorder); + console.print("n" + gConfigSettings.genColors.listBoxBorder); // If the length of the group description is shorter than the remaining text // the selection box border, then draw horizontal lines to fill in the gap. if (grpDesc.length < 3) @@ -4923,13 +5022,13 @@ function crossPosting_selectSubBoardInGrp(pGrpIndex, pSelBoxUpperLeft, pSelBoxLo if (writePromptText) { drawInitialCrossPostSelBoxBottomBorder({ x: pSelBoxUpperLeft.x, y: pSelBoxLowerRight.y }, - pSelBoxWidth, gConfigSettings.genColors.crossPostBorder, + pSelBoxWidth, gConfigSettings.genColors.listBoxBorder, true); } else { console.gotoxy(pSelBoxUpperLeft.x+1, pSelBoxLowerRight.y); - console.print(gConfigSettings.genColors.crossPostBorder + RIGHT_T_SINGLE); + console.print(gConfigSettings.genColors.listBoxBorder + RIGHT_T_SINGLE); } // If the user made a selection, then toggle it on/off. @@ -5205,4 +5304,210 @@ function printEditLine(pIndex, pUseColors, pStart, pLength) } } return lengthWritten; +} + +// Lists the text replacements configured in SlyEdit using a scrollable list box. +function listTextReplacements() +{ + if (gNumTxtReplacements == 0) + { + writeMsgOntBtmHelpLineWithPause("nhyThere are no text replacements.", 1500); + 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); + } + } + + // 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 = "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.txtReplacementList + + "%-" + 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); + + // 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, screenY); + console.print("n" + gConfigSettings.genColors.listBoxBorder + VERTICAL_SINGLE); + printf(listTextReplacements.listFormatStr, + listTextReplacements.txtReplacementArr[i].originalText.substr(0, txtWidth), + listTextReplacements.txtReplacementArr[i].replacement.substr(0, txtWidth)); + console.print("n" + gConfigSettings.genColors.listBoxBorder + VERTICAL_SINGLE); + ++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. + //if (screenY < boxInfo.topLeftY+boxInfo.height) + while (screenY < boxInfo.topLeftY+boxInfo.height-1) + { + console.gotoxy(boxInfo.topLeftX, screenY); + console.print("n" + gConfigSettings.genColors.listBoxBorder + VERTICAL_SINGLE); + printf(listTextReplacements.listFormatStrNormalAttr, "", ""); + console.print("n" + gConfigSettings.genColors.listBoxBorder + VERTICAL_SINGLE); + ++screenY; + } + + // 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.txtReplacementList); + } + + // Get a key from the user (upper-case) and take action based upon it. + userInput = console.getkey(K_UPPER | K_NOCRLF); + 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()); +} + +// Writes some text over the bottom help line, with a pause before erasing the +// text and refreshing the bottom help line. +// +// Parameters: +// pMsg: The text to write +// pPauseMS: The pause (in milliseconds) to wait while displaying the message +function writeMsgOntBtmHelpLineWithPause(pMsg, pPauseMS) +{ + // Write the message with the pause, then refresh the help line on the + // bottom of the screen. + writeWithPause(1, console.screen_rows, pMsg, pPauseMS); + fpDisplayBottomHelpLine(console.screen_rows, gUseQuotes); } \ No newline at end of file diff --git a/exec/SlyEdit_DCTStuff.js b/exec/SlyEdit_DCTStuff.js index 2183d77703771d1ba59cc95f24287726b0375c59..aed6ffb05af5689cd85029e9ca9cc60e602ea072 100644 --- a/exec/SlyEdit_DCTStuff.js +++ b/exec/SlyEdit_DCTStuff.js @@ -41,6 +41,11 @@ * for cross-posting on the File menu. * 2013-08-23 Eric Oulashin Updated readColorConfig() with the new general color * configuration settings. + * 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 + * object. */ load("sbbsdefs.js"); @@ -79,63 +84,7 @@ function readColorConfig(pFilename) gConfigSettings.DCTColors = colors; // Move the general color settings into gConfigSettings.genColors.* if (EDITOR_STYLE == "DCT") - { - if (gConfigSettings.DCTColors.hasOwnProperty("crossPostBorder")) - gConfigSettings.genColors.crossPostBorder = gConfigSettings.DCTColors.crossPostBorder; - if (gConfigSettings.DCTColors.hasOwnProperty("crossPostBorderText")) - gConfigSettings.genColors.crossPostBorderTxt = gConfigSettings.DCTColors.crossPostBorderText; - if (gConfigSettings.DCTColors.hasOwnProperty("crossPostMsgAreaNum")) - gConfigSettings.genColors.crossPostMsgAreaNum = gConfigSettings.DCTColors.crossPostMsgAreaNum; - if (gConfigSettings.DCTColors.hasOwnProperty("crossPostMsgAreaNumHighlight")) - gConfigSettings.genColors.crossPostMsgAreaNumHighlight = gConfigSettings.DCTColors.crossPostMsgAreaNumHighlight; - if (gConfigSettings.DCTColors.hasOwnProperty("crossPostMsgAreaDesc")) - gConfigSettings.genColors.crossPostMsgAreaDesc = gConfigSettings.DCTColors.crossPostMsgAreaDesc; - if (gConfigSettings.DCTColors.hasOwnProperty("crossPostMsgAreaDescHighlight")) - gConfigSettings.genColors.crossPostMsgAreaDescHighlight = gConfigSettings.DCTColors.crossPostMsgAreaDescHighlight; - if (gConfigSettings.DCTColors.hasOwnProperty("crossPostChk")) - gConfigSettings.genColors.crossPostChk = gConfigSettings.DCTColors.crossPostChk; - if (gConfigSettings.DCTColors.hasOwnProperty("crossPostChkHighlight")) - gConfigSettings.genColors.crossPostChkHighlight = gConfigSettings.DCTColors.crossPostChkHighlight; - if (gConfigSettings.DCTColors.hasOwnProperty("crossPostMsgGrpMark")) - gConfigSettings.genColors.crossPostMsgGrpMark = gConfigSettings.DCTColors.crossPostMsgGrpMark; - if (gConfigSettings.DCTColors.hasOwnProperty("crossPostMsgGrpMarkHighlight")) - gConfigSettings.genColors.crossPostMsgGrpMarkHighlight = gConfigSettings.DCTColors.crossPostMsgGrpMarkHighlight; - if (gConfigSettings.DCTColors.hasOwnProperty("msgWillBePostedHdr")) - gConfigSettings.genColors.msgWillBePostedHdr = gConfigSettings.DCTColors.msgWillBePostedHdr; - if (gConfigSettings.DCTColors.hasOwnProperty("msgPostedGrpHdr")) - gConfigSettings.genColors.msgPostedGrpHdr = gConfigSettings.DCTColors.msgPostedGrpHdr; - if (gConfigSettings.DCTColors.hasOwnProperty("msgPostedSubBoardName")) - gConfigSettings.genColors.msgPostedSubBoardName = gConfigSettings.DCTColors.msgPostedSubBoardName; - if (gConfigSettings.DCTColors.hasOwnProperty("msgPostedOriginalAreaText")) - gConfigSettings.genColors.msgPostedOriginalAreaText = gConfigSettings.DCTColors.msgPostedOriginalAreaText; - if (gConfigSettings.DCTColors.hasOwnProperty("msgHasBeenSavedText")) - gConfigSettings.genColors.msgHasBeenSavedText = gConfigSettings.DCTColors.msgHasBeenSavedText; - if (gConfigSettings.DCTColors.hasOwnProperty("msgAbortedText")) - gConfigSettings.genColors.msgAbortedText = gConfigSettings.DCTColors.msgAbortedText; - if (gConfigSettings.DCTColors.hasOwnProperty("emptyMsgNotSentText")) - gConfigSettings.genColors.emptyMsgNotSentText = gConfigSettings.DCTColors.emptyMsgNotSentText; - if (gConfigSettings.DCTColors.hasOwnProperty("genMsgErrorText")) - gConfigSettings.genColors.genMsgErrorText = gConfigSettings.DCTColors.genMsgErrorText; - - delete gConfigSettings.DCTColors.crossPostBorder; - delete gConfigSettings.DCTColors.crossPostBorderText; - delete gConfigSettings.DCTColors.crossPostMsgAreaNum; - delete gConfigSettings.DCTColors.crossPostMsgAreaNumHighlight; - delete gConfigSettings.DCTColors.crossPostMsgAreaDesc; - delete gConfigSettings.DCTColors.crossPostMsgAreaDescHighlight; - delete gConfigSettings.DCTColors.crossPostChk; - delete gConfigSettings.DCTColors.crossPostChkHighlight; - delete gConfigSettings.DCTColors.crossPostMsgGrpMark; - delete gConfigSettings.DCTColors.crossPostMsgGrpMarkHighlight; - delete gConfigSettings.DCTColors.msgWillBePostedHdr; - delete gConfigSettings.DCTColors.msgPostedGrpHdr; - delete gConfigSettings.DCTColors.msgPostedSubBoardName; - delete gConfigSettings.DCTColors.msgPostedOriginalAreaText; - delete gConfigSettings.DCTColors.msgHasBeenSavedText; - delete gConfigSettings.DCTColors.msgAbortedText; - delete gConfigSettings.DCTColors.emptyMsgNotSentText; - delete gConfigSettings.DCTColors.genMsgErrorText; - } + moveGenColorsToGenSettings(gConfigSettings.DCTColors, gConfigSettings); } } diff --git a/exec/SlyEdit_IceStuff.js b/exec/SlyEdit_IceStuff.js index 0eeff41452790a55bb840e28e553c358ebbb102e..0210190e18d58737196b91a284558005532a0cf9 100644 --- a/exec/SlyEdit_IceStuff.js +++ b/exec/SlyEdit_IceStuff.js @@ -27,6 +27,11 @@ * for cross-posting, when allowed. * 2013-08-23 Eric Oulashin Updated readColorConfig() with the new general color * configuration settings. + * 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 + * object. */ load("sbbsdefs.js"); @@ -58,63 +63,7 @@ function readColorConfig(pFilename) gConfigSettings.iceColors = colors; // Move the general color settings into gConfigSettings.genColors.* if (EDITOR_STYLE == "ICE") - { - if (gConfigSettings.iceColors.hasOwnProperty("crossPostBorder")) - gConfigSettings.genColors.crossPostBorder = gConfigSettings.iceColors.crossPostBorder; - if (gConfigSettings.iceColors.hasOwnProperty("crossPostBorderText")) - gConfigSettings.genColors.crossPostBorderTxt = gConfigSettings.iceColors.crossPostBorderText; - if (gConfigSettings.iceColors.hasOwnProperty("crossPostMsgAreaNum")) - gConfigSettings.genColors.crossPostMsgAreaNum = gConfigSettings.iceColors.crossPostMsgAreaNum; - if (gConfigSettings.iceColors.hasOwnProperty("crossPostMsgAreaNumHighlight")) - gConfigSettings.genColors.crossPostMsgAreaNumHighlight = gConfigSettings.iceColors.crossPostMsgAreaNumHighlight; - if (gConfigSettings.iceColors.hasOwnProperty("crossPostMsgAreaDesc")) - gConfigSettings.genColors.crossPostMsgAreaDesc = gConfigSettings.iceColors.crossPostMsgAreaDesc; - if (gConfigSettings.iceColors.hasOwnProperty("crossPostMsgAreaDescHighlight")) - gConfigSettings.genColors.crossPostMsgAreaDescHighlight = gConfigSettings.iceColors.crossPostMsgAreaDescHighlight; - if (gConfigSettings.iceColors.hasOwnProperty("crossPostChk")) - gConfigSettings.genColors.crossPostChk = gConfigSettings.iceColors.crossPostChk; - if (gConfigSettings.iceColors.hasOwnProperty("crossPostChkHighlight")) - gConfigSettings.genColors.crossPostChkHighlight = gConfigSettings.iceColors.crossPostChkHighlight; - if (gConfigSettings.iceColors.hasOwnProperty("crossPostMsgGrpMark")) - gConfigSettings.genColors.crossPostMsgGrpMark = gConfigSettings.iceColors.crossPostMsgGrpMark; - if (gConfigSettings.iceColors.hasOwnProperty("crossPostMsgGrpMarkHighlight")) - gConfigSettings.genColors.crossPostMsgGrpMarkHighlight = gConfigSettings.iceColors.crossPostMsgGrpMarkHighlight; - if (gConfigSettings.iceColors.hasOwnProperty("msgWillBePostedHdr")) - gConfigSettings.genColors.msgWillBePostedHdr = gConfigSettings.iceColors.msgWillBePostedHdr; - if (gConfigSettings.iceColors.hasOwnProperty("msgPostedGrpHdr")) - gConfigSettings.genColors.msgPostedGrpHdr = gConfigSettings.iceColors.msgPostedGrpHdr; - if (gConfigSettings.iceColors.hasOwnProperty("msgPostedSubBoardName")) - gConfigSettings.genColors.msgPostedSubBoardName = gConfigSettings.iceColors.msgPostedSubBoardName; - if (gConfigSettings.iceColors.hasOwnProperty("msgPostedOriginalAreaText")) - gConfigSettings.genColors.msgPostedOriginalAreaText = gConfigSettings.iceColors.msgPostedOriginalAreaText; - if (gConfigSettings.iceColors.hasOwnProperty("msgHasBeenSavedText")) - gConfigSettings.genColors.msgHasBeenSavedText = gConfigSettings.iceColors.msgHasBeenSavedText; - if (gConfigSettings.iceColors.hasOwnProperty("msgAbortedText")) - gConfigSettings.genColors.msgAbortedText = gConfigSettings.iceColors.msgAbortedText; - if (gConfigSettings.iceColors.hasOwnProperty("emptyMsgNotSentText")) - gConfigSettings.genColors.emptyMsgNotSentText = gConfigSettings.iceColors.emptyMsgNotSentText; - if (gConfigSettings.iceColors.hasOwnProperty("genMsgErrorText")) - gConfigSettings.genColors.genMsgErrorText = gConfigSettings.iceColors.genMsgErrorText; - - delete gConfigSettings.iceColors.crossPostBorder; - delete gConfigSettings.iceColors.crossPostBorderText; - delete gConfigSettings.iceColors.crossPostMsgAreaNum; - delete gConfigSettings.iceColors.crossPostMsgAreaNumHighlight; - delete gConfigSettings.iceColors.crossPostMsgAreaDesc; - delete gConfigSettings.iceColors.crossPostMsgAreaDescHighlight; - delete gConfigSettings.iceColors.crossPostChk; - delete gConfigSettings.iceColors.crossPostChkHighlight; - delete gConfigSettings.iceColors.crossPostMsgGrpMark; - delete gConfigSettings.iceColors.crossPostMsgGrpMarkHighlight; - delete gConfigSettings.iceColors.msgWillBePostedHdr; - delete gConfigSettings.iceColors.msgPostedGrpHdr; - delete gConfigSettings.iceColors.msgPostedSubBoardName; - delete gConfigSettings.iceColors.msgPostedOriginalAreaText; - delete gConfigSettings.iceColors.msgHasBeenSavedText; - delete gConfigSettings.iceColors.msgAbortedText; - delete gConfigSettings.iceColors.emptyMsgNotSentText; - delete gConfigSettings.iceColors.genMsgErrorText; - } + moveGenColorsToGenSettings(gConfigSettings.iceColors, gConfigSettings); } } diff --git a/exec/SlyEdit_Misc.js b/exec/SlyEdit_Misc.js index 81b3780104edd94c03d55b962a6f7e405ba845ba..90e8b59355c557298da04989992b59cd63e70560 100644 --- a/exec/SlyEdit_Misc.js +++ b/exec/SlyEdit_Misc.js @@ -12,107 +12,28 @@ * 2009-08-22 Eric Oulashin Version 1.00 * Initial public release * ....Removed some comments... - * 2012-12-21 Eric Oulashin Updated to check for the .cfg files in the - * sbbs/ctrl directory first, and if they aren't - * there, assume they're in the same directory as - * the .js file. - * 2012-12-23 Eric Oulashin Worked on updating wrapQuoteLines() and - * firstNonQuoteTxtIndex() to support putting the - * "To" user's initials before the > in quote lines. - * 2012-12-25 Eric Oulashin Updated wrapQuoteLines() to insert a > in quote - * lines right after the leading quote characters - * (if any), without a space afteward, to indicate - * an additional level of quoting. - * 2012-12-27 Eric Oulashin Bug fix in wrapQuoteLines(): When prefixing - * quote lines with author initials, if wrapping - * resulted in additional quote lines, it wasn't - * adding a > character to the additional line(s). - * 2012-12-28 Eric Oulashin Updated firstNonQuoteTxtIndex() to more - * intelligently find the first non-quote index - * when using author initials in quote lines. - * I.e., dealing with multiply-quoted lines that - * start like this: - * > AD> - * > AD>> - * etc.. - * 2012-12-30 Eric Oulashin Added the getCurMsgInfo() and - * getFromNameForCurMsg() functions. - * getCurMsgInfo() reads DDML_SyncSMBInfo.txt, - * which is written to the node directory by - * the Digital Distortion Message Lister and - * contains information about the current - * message being read so that SlyEdit can - * read it for getting the sender name from - * the message header. That was necessary - * because the information about that in the - * bbs object (provided by Synchronet) can't - * be modified. - * 2013-01-02 Eric Oulashin Fixed a bug in getFromNameForCurMsg() where - * reading low-numbered messages in a sub-board - * would result in getting the incorrect - * original author name. Updated - * getFromNameForCurMsg() to just use the - * sub-board code and message offset to get - * the header for the current message being - * read. - * 2013-01-13 Eric Oulashin Added calcPageNum(). - * 2013-01-18 Eric Oulashin Updated ReadSlyEditConfigFile() to include - * border color & border text color settings - * for choosing message areas for cross-posting. - * 2013-01-19 Eric Oulashin Added postingInMsgSubBoard(). Updated - * ReadSlyEditConfigFile() to read a new setting, - * allowCrossPosting, from the config file. Added - * CHECK_CHAR. - * 2013-01-20 Eric Oulashin Added numObjProperties(). Also added - * postMsgToSubBoard(), for cross-posting support. - * 2013-01-22 Eric Oulashin Updated displayProgramExitInfo(): Removed the - * SlyEdit block text so that the overall message - * it displays is shorter. - * 2013-01-24 Eric Oulashin Updated ReadSlyEditConfigFile() to check the - * following directories, in order, for the - * configuration files: - * 1. Mods directory - * 2. Ctrl directory - * 3. Current directory (where SlyEdit is located) - * 2013-02-03 Eric Oulashin Added readUserSigFile(). - * 2013-02-13 Eric Oulashin Updated getCurMsgInfo() to get the first - * postable message sub-board if the user has no - * current sub-board (i.e., a new user is applying - * for access). Also, updated ReadSlyEditConfigFile() - * to default indentQuoteLinesWithInitials to true. - * 2013-05-14 Eric Oulashin Updated getCurMsgInfo() and getFromNameForCurMsg() - * to use the absolute message number (bbs.msg_number) - * rather than messages indexes so that it gets - * the correct message header in all cases, including - * when replying to messages during "Scan for messages - * to you". - * 2013-05-16 Eric Oulashin Added a function that returns whether the - * Synchronet compile date is at least May 12, 2013. - * That was when Digital Man's change to make - * bbs.msg_number work when a script is running - * first went into the Synchronet daily builds. - * 2013-05-18 Eric Oulashin Speed optimization (hopefully) for the - * aforementioned function: Made the return - * value a function property so that it only has - * to be figured out once, and eliminates the - * need for a global variable to store it for - * speed optimization purposes. - * 2013-05-23 Eric Oulashin Simplified the decision of whether to use - * bbs.msg_number or bbs.smb_curmsg by checking - * whether bbs.msg_number is > 0 (if it is, then - * it's valid, so use it). This is simpler than - * checking the Synchronet version & build date. - * 2013-05-24 Eric Oulashin Updated getCurMsgInfo() to add one more - * data member to the return object: - * msgNumIsOffset, which stores whether or not the - * message number is an offset. If not, then it's - * the aboslute message number (i.e., bbs.msg_number). - * That simplified getFromNameForCurMsg(), which can - * pass that to msgBase.get_msg_header(). * 2013-08-24 Eric Oulashin Bug fix in wrapQuoteLines(): Off-by-one bug toward * the end where there might be more quote lines * than lineInfo objects, so it wouldn't quote the * last line when using author initials. + * 2013-08-28 Eric Oulashin Updated ReadSlyEditConfigFile() to read and + * set the enableTextReplacements setting. It + * defaults to false. Also added populateTxtReplacements(). + * Added moveGenColorsToGenSettings(), which + * can be called by JavaScripts for different + * UI styles to move the general color settings + * from their own color array into the genColors + * array in the configuration object. + * 2013-08-31 Eric Oulashin Added the function getWordFromEditLine(). + * 2013-09-02 Eric Oulashin Worked on the new function doMacroTxtReplacementInEditLine(), + * which performs text replacement (AKA macros) on + * one of the message edit lines. Added + * genFullPathCfgFilename() so that the logic for finding + * the configuration files is all in one place. Added + * getFirstLetterFromStr() and firstLetterIsUppercase(), + * which are helpers for doMacroTxtReplacementInEditLine() + * for checking & fixing first-letter capitalization + * after doing a regex replace. * */ @@ -360,8 +281,6 @@ function getCurrentTimeStr() function isPrintableChar(pText) { // Make sure pText is valid and is a string. - if ((pText == null) || (pText == undefined)) - return false; if (typeof(pText) != "string") return false; if (pText.length == 0) @@ -460,7 +379,8 @@ function displayHelpHeader() // pPause: Whether or not to pause at the end // pCanCrossPost: Whether or not cross-posting is enabled // pIsSysop: Whether or not the user is the sysop. -function displayCommandList(pDisplayHeader, pClear, pPause, pCanCrossPost, pIsSysop) +// pTxtReplacments: Whether or not the text replacements feature is enabled +function displayCommandList(pDisplayHeader, pClear, pPause, pCanCrossPost, pIsSysop, pTxtReplacments) { if (pClear) console.clear("n"); @@ -506,6 +426,8 @@ function displayCommandList(pDisplayHeader, pClear, pPause, pCanCrossPost, pIsSy displayCmdKeyFormattedDouble("Ctrl-G", "General help", "/A", "Abort", true); displayCmdKeyFormattedDouble("Ctrl-P", "Command key help", "/S", "Save", true); displayCmdKeyFormattedDouble("Ctrl-R", "Program information", "/Q", "Quote message", true); + if (pTxtReplacments) + displayCmdKeyFormattedDouble("Ctrl-T", "List text replacements", "/T", "List text replacements", true); if (pCanCrossPost) displayCmdKeyFormattedDouble("", "", "/C", "Cross-post selection", true); printf(" ch%-7sg nc%s", "", "", "/?", "Show help"); @@ -553,61 +475,23 @@ function displayGeneralHelp(pDisplayHeader, pClear, pPause) console.pause(); } -// Displays the text to display above program info screens. -function displayProgInfoHeader() -{ - // Construct the header text lines only once. - if (typeof(displayProgInfoHeader.headerLines) == "undefined") - { - displayProgInfoHeader.headerLines = new Array(); - - var progNameLen = strip_ctrl(EDITOR_PROGRAM_NAME).length; - - // Top border - var headerTextStr = "nhc" + UPPER_LEFT_SINGLE; - for (var i = 0; i < progNameLen + 2; ++i) - headerTextStr += HORIZONTAL_SINGLE; - headerTextStr += UPPER_RIGHT_SINGLE; - displayProgInfoHeader.headerLines.push(headerTextStr); - - // Middle line: Header text string - headerTextStr = VERTICAL_SINGLE + "4y " + EDITOR_PROGRAM_NAME + " nhc" - + VERTICAL_SINGLE; - displayProgInfoHeader.headerLines.push(headerTextStr); - - // Lower border - headerTextStr = LOWER_LEFT_SINGLE; - for (var i = 0; i < progNameLen + 2; ++i) - headerTextStr += HORIZONTAL_SINGLE; - headerTextStr += LOWER_RIGHT_SINGLE; - displayProgInfoHeader.headerLines.push(headerTextStr); - } - - // Print the header strings - for (var index in displayProgInfoHeader.headerLines) - console.center(displayProgInfoHeader.headerLines[index]); -} - // Displays program information. // // Parameters: -// pDisplayHeader: Whether or not to display the help header. // pClear: Whether or not to clear the screen first // pPause: Whether or not to pause at the end -function displayProgramInfo(pDisplayHeader, pClear, pPause) +function displayProgramInfo(pClear, pPause) { if (pClear) console.clear("n"); - if (pDisplayHeader) - displayProgInfoHeader(); // Print the program information - console.center("ncVersion g" + EDITOR_VERSION + " wh(b" + - EDITOR_VER_DATE + "w)"); + console.center("nhc" + EDITOR_PROGRAM_NAME + "n cVersion g" + + EDITOR_VERSION + " wh(b" + EDITOR_VER_DATE + "w)"); console.center("ncby Eric Oulashin"); console.crlf(); - console.print("ncSlyEdit is a full-screen message editor written for Synchronet that mimics\r\n"); - console.print("the look & feel of IceEdit or DCT Edit."); + console.print("ncSlyEdit is a full-screen message editor for Synchronet that mimics the look &\r\n"); + console.print("feel of IceEdit or DCT Edit."); console.crlf(); if (pPause) console.pause(); @@ -736,12 +620,17 @@ function ReadSlyEditConfigFile() // initials. cfgObj.indentQuoteLinesWithInitials = true; cfgObj.allowCrossPosting = true; + cfgObj.enableTextReplacements = false; + cfgObj.textReplacementsUseRegex = false; // General SlyEdit color settings cfgObj.genColors = new Object(); // Cross-posting UI element colors - cfgObj.genColors.crossPostBorder = "ng"; - cfgObj.genColors.crossPostBorderTxt = "nbh"; + // Deprecated colors: + //cfgObj.genColors.crossPostBorder = "ng"; + //cfgObj.genColors.crossPostBorderTxt = "nbh"; + cfgObj.genColors.listBoxBorder = "ng"; + cfgObj.genColors.listBoxBorderText = "nbh"; cfgObj.genColors.crossPostMsgAreaNum = "nhw"; cfgObj.genColors.crossPostMsgAreaNumHighlight = "n4hw"; cfgObj.genColors.crossPostMsgAreaDesc = "nc"; @@ -763,11 +652,7 @@ function ReadSlyEditConfigFile() // Default Ice-style colors cfgObj.iceColors = new Object(); // Ice color theme file - cfgObj.iceColors.ThemeFilename = system.mods_dir + "SlyIceColors_BlueIce.cfg"; - if (!file_exists(cfgObj.iceColors.ThemeFilename)) - cfgObj.iceColors.ThemeFilename = system.ctrl_dir + "SlyIceColors_BlueIce.cfg"; - if (!file_exists(cfgObj.iceColors.ThemeFilename)) - cfgObj.iceColors.ThemeFilename = gStartupPath + "SlyIceColors_BlueIce.cfg"; + cfgObj.iceColors.ThemeFilename = genFullPathCfgFilename("SlyIceColors_BlueIce.cfg", gStartupPath); // Text edit color cfgObj.iceColors.TextEditColor = "nw"; // Quote line color @@ -798,11 +683,7 @@ function ReadSlyEditConfigFile() // Default DCT-style colors cfgObj.DCTColors = new Object(); // DCT color theme file - cfgObj.DCTColors.ThemeFilename = system.mods_dir + "SlyDCTColors_Default.cfg"; - if (!file_exists(cfgObj.DCTColors.ThemeFilename)) - cfgObj.DCTColors.ThemeFilename = system.ctrl_dir + "SlyDCTColors_Default.cfg"; - if (!file_exists(cfgObj.DCTColors.ThemeFilename)) - cfgObj.DCTColors.ThemeFilename = gStartupPath + "SlyDCTColors_Default.cfg"; + cfgObj.DCTColors.ThemeFilename = genFullPathCfgFilename("SlyDCTColors_Default.cfg", gStartupPath); // Text edit color cfgObj.DCTColors.TextEditColor = "nw"; // Quote line color @@ -861,11 +742,7 @@ function ReadSlyEditConfigFile() cfgObj.DCTColors.MenuHotkeys = "nwh7"; // Open the SlyEdit configuration file - var slyEdCfgFileName = system.mods_dir + "SlyEdit.cfg"; - if (!file_exists(slyEdCfgFileName)) - slyEdCfgFileName = system.ctrl_dir + "SlyEdit.cfg"; - if (!file_exists(slyEdCfgFileName)) - slyEdCfgFileName = gStartupPath + "SlyEdit.cfg"; + var slyEdCfgFileName = genFullPathCfgFilename("SlyEdit.cfg", gStartupPath); var cfgFile = new File(slyEdCfgFileName); if (cfgFile.open("r")) { @@ -954,28 +831,29 @@ function ReadSlyEditConfigFile() cfgObj.runJSOnExit.push(value); else if (settingUpper == "ALLOWCROSSPOSTING") cfgObj.allowCrossPosting = (valueUpper == "TRUE"); + else if (settingUpper == "ENABLETEXTREPLACEMENTS") + { + // The enableTxtReplacements setting in the config file can + // be regex, true, or false: + // - regex: Text replacement enabled using regular expressions + // - true: Text replacement enabled using exact match + // - false: Text replacement disabled + cfgObj.textReplacementsUseRegex = (valueUpper == "REGEX"); + if (cfgObj.textReplacementsUseRegex) + cfgObj.enableTextReplacements = true; + else + cfgObj.enableTextReplacements = (valueUpper == "TRUE"); + } } else if (settingsMode == "ICEColors") { if (settingUpper == "THEMEFILENAME") - { - cfgObj.iceColors.ThemeFilename = system.mods_dir + value; - if (!file_exists(cfgObj.iceColors.ThemeFilename)) - cfgObj.iceColors.ThemeFilename = system.ctrl_dir + value; - if (!file_exists(cfgObj.iceColors.ThemeFilename)) - cfgObj.iceColors.ThemeFilename = gStartupPath + value; - } + cfgObj.iceColors.ThemeFilename = genFullPathCfgFilename(value, gStartupPath); } else if (settingsMode == "DCTColors") { if (settingUpper == "THEMEFILENAME") - { - cfgObj.DCTColors.ThemeFilename = system.mods_dir + value; - if (!file_exists(cfgObj.DCTColors.ThemeFilename)) - cfgObj.DCTColors.ThemeFilename = system.ctrl_dir + value; - if (!file_exists(cfgObj.DCTColors.ThemeFilename)) - cfgObj.DCTColors.ThemeFilename = gStartupPath + value; - } + cfgObj.DCTColors.ThemeFilename = genFullPathCfgFilename(value, gStartupPath); } } } @@ -2388,6 +2266,410 @@ function getFirstPostableSubInfo() return retObj; } +// Reads SlyEdit_TextReplacements.cfg (from sbbs/mods, sbbs/ctrl, or the +// script's directory) and populates an associative array with the WORD=text +// pairs. When not using regular expressions, the key will be in all uppercase +// and the value in lowercase. This function will read up to 9999 replacements. +// +// Parameters: +// pArray: The array to populate. Must be created as "new Array()". +// pRegex: Whether or not the text replace feature is configured to use regular +// expressions. If so, then the search words in the array will not +// be converted to uppercase and the replacement text will not be +// converted to lowercase. +// +// 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 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; + + // 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) and the substitution + // word to all lowercase (to make sure it looks good). + wordToSearch = trimSpaces(fileLine.substr(0, equalsPos), true, false, true); + 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) + substIsPrintable = isPrintableChar(substWord.charAt(i)); + if (!substIsPrintable) + continue; + + // And add the search word and replacement text to pArray. + if (pRegex) + { + if (wordToSearch.toUpperCase() != substWord.toUpperCase()) + { + pArray[wordToSearch] = substWord; + ++numTxtReplacements; + } + } + else + { + wordToSearch = wordToSearch.toUpperCase(); + substWord = substWord.toLowerCase(); + if (wordToSearch != substWord.toUpperCase()) + { + pArray[wordToSearch] = substWord; + ++numTxtReplacements; + } + } + } + + wordFile.close(); + } + + return numTxtReplacements; +} + +function moveGenColorsToGenSettings(pColorsArray, pCfgObj) +{ + // Set up an array of color setting names + var colorSettingStrings = new Array(); + colorSettingStrings.push("crossPostBorder"); // Deprecated + colorSettingStrings.push("crossPostBorderText"); // Deprecated + colorSettingStrings.push("listBoxBorder"); + colorSettingStrings.push("listBoxBorderText"); + colorSettingStrings.push("crossPostMsgAreaNum"); + colorSettingStrings.push("crossPostMsgAreaNumHighlight"); + colorSettingStrings.push("crossPostMsgAreaDesc"); + colorSettingStrings.push("crossPostMsgAreaDescHighlight"); + colorSettingStrings.push("crossPostChk"); + colorSettingStrings.push("crossPostChkHighlight"); + colorSettingStrings.push("crossPostMsgGrpMark"); + colorSettingStrings.push("crossPostMsgGrpMarkHighlight"); + colorSettingStrings.push("msgWillBePostedHdr"); + colorSettingStrings.push("msgPostedGrpHdr"); + colorSettingStrings.push("msgPostedSubBoardName"); + colorSettingStrings.push("msgPostedOriginalAreaText"); + colorSettingStrings.push("msgHasBeenSavedText"); + colorSettingStrings.push("msgAbortedText"); + colorSettingStrings.push("emptyMsgNotSentText"); + colorSettingStrings.push("genMsgErrorText"); + colorSettingStrings.push("txtReplacementList"); + + var colorName = ""; + for (var i = 0; i < colorSettingStrings.length; ++i) + { + colorName = colorSettingStrings[i]; + if (pColorsArray.hasOwnProperty(colorName)) + { + pCfgObj.genColors[colorName] = pColorsArray[colorName]; + delete pColorsArray[colorName]; + } + } + // If listBoxBorder and listBoxBorderText exist in the general colors settings, + // then remove crossPostBorder and crossPostBorderText if they exist. + if (pCfgObj.genColors.hasOwnProperty["listBoxBorder"] && pCfgObj.genColors.hasOwnProperty["crossPostBorder"]) + { + // Favor crossPostBorder to preserve backwards compatibility. + pCfgObj.genColors["listBoxBorder"] = pCfgObj.genColors["crossPostBorder"]; + delete pCfgObj.genColors["crossPostBorder"]; + } + if (pCfgObj.genColors.hasOwnProperty["listBoxBorderText"] && pCfgObj.genColors.hasOwnProperty["crossPostBorderText"]) + { + // Favor crossPostBorderText to preserve backwards compatibility. + pCfgObj.genColors["listBoxBorderText"] = pCfgObj.genColors["crossPostBorderText"]; + delete pCfgObj.genColors["crossPostBorderText"]; + } +} + +// Returns whether or not a character is a letter. +// +// Parameters: +// pChar: The character to test +// +// Return value: Boolean - Whether or not the character is a letter +function charIsLetter(pChar) +{ + return /^[ABCDEFGHIJKLMNOPQRSTUVWXYZ�������������������������������������������������������������]$/.test(pChar.toUpperCase()); +} + +// Returns the word in a text line at a given index. If the index +// is at a space, then this function will return the word before +// (to the left of) the space. +// +// Parameters: +// pEditLinesIndex: The index of the line to look at (0-based) +// pCharIndex: The character index in the text line (0-based) +// +// Return value: An object containing the following properties: +// foundWord: Whether or not a word was found (boolean) +// word: The word in the edit line at the given indexes (text) +// editLineIndex: The index of the edit line (integer) +// startIdx: The index of the first character of the word (integer) +// endIndex: The index of the last character of the word (integer) +function getWordFromEditLine(pEditLinesIndex, pCharIndex) +{ + var retObj = new Object(); + retObj.foundWord = false; + retObj.word = ""; + retObj.editLineIndex = pEditLinesIndex; + retObj.startIdx = 0; + retObj.endIndex = 0; + + // Parameter checking + if ((pEditLinesIndex < 0) || (pEditLinesIndex >= gEditLines.length)) + { + retObj.editLineIndex = 0; + return retObj; + } + if ((pCharIndex < 0) || (pCharIndex >= gEditLines[pEditLinesIndex].text.length)) + { + //displayDebugText(1, 1, "pCharIndex: " + pCharIndex, null, true, false); // Temporary + //displayDebugText(1, 2, "Line len: " + gEditLines[pEditLinesIndex].text.length, console.getxy(), true, false); // Temporary + return retObj; + } + + // If pCharIndex specifies the index of a space, then look for a non-space + // character before it. + var charIndex = pCharIndex; + while (gEditLines[pEditLinesIndex].text.charAt(charIndex) == " ") + --charIndex; + // Look for the start & end of the word based on the indexes of a space + // before and at/after the given character index. + var wordStartIdx = charIndex; + var wordEndIdx = charIndex; + while ((gEditLines[pEditLinesIndex].text.charAt(wordStartIdx) != " ") && (wordStartIdx >= 0)) + --wordStartIdx; + ++wordStartIdx; + while ((gEditLines[pEditLinesIndex].text.charAt(wordEndIdx) != " ") && (wordEndIdx < gEditLines[pEditLinesIndex].text.length)) + ++wordEndIdx; + --wordEndIdx; + + retObj.foundWord = true; + retObj.startIdx = wordStartIdx; + retObj.endIndex = wordEndIdx; + retObj.word = gEditLines[pEditLinesIndex].text.substring(wordStartIdx, wordEndIdx+1); + return retObj; +} + +// Performs text replacement (AKA macro replacement) in an edit line. +// +// Parameters: +// pTxtReplacements: An associative array of text to be replaced (i.e., +// gTxtReplacements) +// pEditLinesIndex: The index of the line in gEditLines +// pCharIndex: The current character index in the text line +// pUseRegex: Whether or not to treat the text replacement search string as a +// regular expression. +// +// 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) +// wordStartIdx: The index of the first character in the word. +// Only valid if a word was found. Otherwise, this +// will be 0. +// newTextEndIdx: The index of the last character in the new +// text. Only valid if a word was replaced. +// Otherwise, this will be 0. +// newTextLen: The length of the new text in the string. Will be +// the length of the existing word if the word wasn't +// replaced or 0 if no word was found. +// madeTxtReplacement: Whether or not a text replacement was made +// (boolean) +function doMacroTxtReplacementInEditLine(pTxtReplacements, pEditLinesIndex, pCharIndex, pUseRegex) +{ + var retObj = new Object(); + retObj.textLineIndex = pCharIndex; + retObj.wordLenDiff = 0; + retObj.wordStartIdx = 0; + retObj.newTextEndIdx = 0; + retObj.newTextLen = 0; + retObj.madeTxtReplacement = false; + + var wordObj = getWordFromEditLine(pEditLinesIndex, retObj.textLineIndex); + if (wordObj.foundWord) + { + retObj.wordStartIdx = wordObj.startIdx; + retObj.newTextLen = wordObj.word.length; + + // See if the word starts with a capital letter; if so, we'll capitalize + // the replacement word. + //var firstCharUpper = (wordObj.word.charAt(0) == wordObj.word.charAt(0).toUpperCase()); + var firstCharUpper = false; + var txtReplacement = ""; + if (pUseRegex) + { + // Since a regular expression might have more characters in addition + // to the actual word, we need to go through all the replacement strings + // in pTxtReplacements and use the first one that changes the text. + for (var prop in pTxtReplacements) + { + if (pTxtReplacements.hasOwnProperty(prop)) + { + var regex = new RegExp(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 + // first letter in the new text (txtReplacement) uppercase. + if (retObj.madeTxtReplacement) + { + if (firstLetterIsUppercase(wordObj.word)) + { + var letterInfo = getFirstLetterFromStr(txtReplacement); + if (letterInfo.idx > -1) + { + txtReplacement = txtReplacement.substr(0, letterInfo.idx) + + letterInfo.letter.toUpperCase() + + txtReplacement.substr(letterInfo.idx+1); + } + } + // Now that we've made a text replacement, stop going through + // pTxtReplacements looking for a matching regex. + break; + } + } + } + } + else + { + // Not using a regular expression. + firstCharUpper = (wordObj.word.charAt(0) == wordObj.word.charAt(0).toUpperCase()); + // Convert the word to all uppercase to do the case-insensitive lookup + // in pTxtReplacements. + wordObj.word = wordObj.word.toUpperCase(); + if (pTxtReplacements.hasOwnProperty(wordObj.word)) + { + txtReplacement = pTxtReplacements[wordObj.word].toLowerCase(); + retObj.madeTxtReplacement = true; + } + } + if (retObj.madeTxtReplacement) + { + if (firstCharUpper) + txtReplacement = txtReplacement.charAt(0).toUpperCase() + txtReplacement.substr(1); + gEditLines[pEditLinesIndex].text = gEditLines[pEditLinesIndex].text.substr(0, wordObj.startIdx) + + txtReplacement + + gEditLines[pEditLinesIndex].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.textLineIndex += retObj.wordLenDiff; + retObj.newTextEndIdx = wordObj.endIndex + retObj.wordLenDiff; + retObj.newTextLen = txtReplacement.length; + } + } + + return retObj; +} + +// For configuration files, this function returns a fully-pathed filename. +// This function first checks to see if the file exists in the sbbs/mods +// directory, then the sbbs/ctrl directory, and if the file is not found there, +// this function defaults to the given default path. +// +// Parameters: +// pFilename: The name of the file to look for +// pDefaultPath: The default directory (must have a trailing separator character) +function genFullPathCfgFilename(pFilename, pDefaultPath) +{ + var fullyPathedFilename = system.mods_dir + pFilename; + if (!file_exists(fullyPathedFilename)) + fullyPathedFilename = system.ctrl_dir + pFilename; + if (!file_exists(fullyPathedFilename)) + { + if (typeof(pDefaultPath) == "string") + { + // Make sure the default path has a trailing path separator + var defaultPath = backslash(pDefaultPath); + fullyPathedFilename = defaultPath + pFilename; + } + else + fullyPathedFilename = pFilename; + } + return fullyPathedFilename; +} + +// Returns the first letter found in a string and its index. If a letter is +// not found, the string returned will be blank, and the index will be -1. +// +// Parameters: +// pString: The string to search +// +// Return value: An object with the following properties: +// letter: The first letter found in the string, or a blank string if none was found +// idx: The index of the first letter found, or -1 if none was found +function getFirstLetterFromStr(pString) +{ + var retObj = new Object; + retObj.letter = ""; + retObj.idx = -1; + + var theChar = ""; + for (var i = 0; (i < pString.length) && (retObj.idx == -1); ++i) + { + theChar = pString.charAt(i); + if (charIsLetter(theChar)) + { + retObj.idx = i; + retObj.letter = theChar; + } + } + + return retObj; +} + +// Returns whether or not the first letter in a string is uppercase. If the +// string doesn't contain any letters, then this function will return false. +// +// Parameters: +// pString: The string to search +// +// Return value: Boolean - Whether or not the first letter in the string is uppercase +function firstLetterIsUppercase(pString) +{ + var firstIsUpper = false; + var letterObj = getFirstLetterFromStr(pString); + if (letterObj.idx > -1) + { + var theLetter = pString.charAt(letterObj.idx); + firstIsUpper = (theLetter == theLetter.toUpperCase()); + } + return firstIsUpper; +} + // This function displays debug text at a given location on the screen, then // moves the cursor back to a given location. //