Newer
Older
if (this.CanDelete() || this.CanDeleteLastMsg())
{
if (this.NumSelectedMessages() > 0)
{
console.gotoxy(1, console.screen_rows);
console.attributes = "N";
console.clearline();
// The PromptAndDeleteOrUndeleteSelectedMessages() method will prompt the user for confirmation
// to delete the message and then delete it if confirmed.

Eric Oulashin
committed
var delSuccessful = this.PromptAndDeleteOrUndeleteSelectedMessages({ x: 1, y: console.screen_rows}, true);
// If successfully deleted, have the menu draw only the check character column in the
// next iteration
if (delSuccessful)
{
this.selectedMessages = {};
drawMenu = true;
}
// In case all messages were deleted, if the user can't view deleted messages,
// show an appropriate message and don't continue listing messages.
//if (this.NumMessages(true) == 0)
if (!this.NonDeletedMessagesExist() && !canViewDeletedMsgs())
continueOn = false;
else
{
// There are still messages to list, so refresh the header & help lines
this.WriteMsgListScreenTopHeader();
DisplayHelpLine(this.msgListLightbarModeHelpLine);
}
}
else
{
// There are no selected messages

Eric Oulashin
committed
writeWithPause(1, console.screen_rows, "\x01n\x01h\x01yThere are no selected messages.", ERROR_PAUSE_WAIT_MS, "\x01n", true);
// Refresh the help line
DisplayHelpLine(this.msgListLightbarModeHelpLine);
}
}
}
// U: Undelete message(s)
else if (lastUserInputUpper == this.msgListKeys.undeleteMessage)
{
if (this.CanDelete() || this.CanDeleteLastMsg())
{
console.gotoxy(1, console.screen_rows);
console.attributes = "N";
console.clearline();
if (this.NumSelectedMessages() > 0)
{
// Multi-message undelete
this.PromptAndDeleteOrUndeleteSelectedMessages({ x: 1, y: console.screen_rows}, false);
}
else
{
// Single-message undelete
this.PromptAndDeleteOrUndeleteMessage(this.lightbarListSelectedMsgIdx, { x: 1, y: console.screen_rows}, false);
}
// Refresh the header & help line.
this.WriteMsgListScreenTopHeader();
DisplayHelpLine(this.msgListLightbarModeHelpLine);
}
}

Eric Oulashin
committed
else if (lastUserInputUpper == this.msgListKeys.userSettings)
{

Eric Oulashin
committed
var userSettingsRetObj = this.DoUserSettings_Scrollable(function(pReader) { DisplayHelpLine(pReader.msgListLightbarModeHelpLine); });

Eric Oulashin
committed
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
lastUserInputUpper = "";
drawMenu = userSettingsRetObj.needWholeScreenRefresh;
// In case the user changed their twitlist, re-filter the messages for this sub-board
if (userSettingsRetObj.userTwitListChanged)
{
console.gotoxy(1, console.screen_rows);
console.crlf();
console.print("\x01nTwitlist changed; re-filtering..");
var tmpMsgbase = new MsgBase(this.subBoardCode);
if (tmpMsgbase.open())
{
var tmpAllMsgHdrs = tmpMsgbase.get_all_msg_headers(true);
tmpMsgbase.close();
this.FilterMsgHdrsIntoHdrsForCurrentSubBoard(tmpAllMsgHdrs, true);
}
else
console.print("\x01y\x01hFailed to open the messagbase!\x01\r\n\x01p");
this.SetUpLightbarMsgListVars();
msgListMenu = this.CreateLightbarMsgListMenu();
drawMenu = true;
}
if (userSettingsRetObj.needWholeScreenRefresh)
{
this.WriteMsgListScreenTopHeader();
DisplayHelpLine(this.msgListLightbarModeHelpLine);
}
else
msgListMenu.DrawPartialAbs(userSettingsRetObj.optionBoxTopLeftX, userSettingsRetObj.optionBoxTopLeftY, userSettingsRetObj.optionBoxWidth, userSettingsRetObj.optionBoxHeight);
}
// TODO
else if (lastUserInputUpper == "S")
{
// Refresh the help line
DisplayHelpLine(this.msgListLightbarModeHelpLine);
}

nightfox
committed
}
this.lightbarListSelectedMsgIdx = msgListMenu.selectedItemIdx;
this.lightbarListTopMsgIdx = msgListMenu.topItemIdx;

nightfox
committed
return retObj;
}
// For the DigDistMsgLister class: Creates & returns a DDLightbarMenu for
// performing the lightbar message list.
function DigDistMsgReader_CreateLightbarMsgListMenu()
{
// Start & end indexes for the various items in each message list row
var msgListIdxes = {
msgNumStart: 0,
msgNumEnd: this.MSGNUM_LEN,
selectMarkStart: this.MSGNUM_LEN,
selectMarkEnd: this.MSGNUM_LEN+1,
};
msgListIdxes.fromNameStart = this.MSGNUM_LEN + 1;
msgListIdxes.fromNameEnd = msgListIdxes.fromNameStart + +this.FROM_LEN + 1;
msgListIdxes.toNameStart = msgListIdxes.fromNameEnd;
msgListIdxes.toNameEnd = msgListIdxes.toNameStart + +this.TO_LEN + 1;
msgListIdxes.subjStart = msgListIdxes.toNameEnd;
msgListIdxes.subjEnd = msgListIdxes.subjStart + +this.SUBJ_LEN + 1;

Eric Oulashin
committed
if (this.showScoresInMsgList)
{
msgListIdxes.scoreStart = msgListIdxes.subjEnd;
msgListIdxes.scoreEnd = msgListIdxes.scoreStart + +this.SCORE_LEN + 1;
msgListIdxes.dateStart = msgListIdxes.scoreEnd;
}
else
msgListIdxes.dateStart = msgListIdxes.subjEnd;
msgListIdxes.dateEnd = msgListIdxes.dateStart + +this.DATE_LEN + 1;
msgListIdxes.timeStart = msgListIdxes.dateEnd;
msgListIdxes.timeEnd = console.screen_columns - 1; // msgListIdxes.timeStart + +this.TIME_LEN + 1;
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
var msgListMenuHeight = console.screen_rows - this.lightbarMsgListStartScreenRow;
var msgListMenu = new DDLightbarMenu(1, this.lightbarMsgListStartScreenRow, console.screen_columns, msgListMenuHeight);
msgListMenu.scrollbarEnabled = true;
msgListMenu.borderEnabled = false;
msgListMenu.SetColors({
itemColor: [{start: msgListIdxes.msgNumStart, end: msgListIdxes.msgNumEnd, attrs: this.colors.msgListMsgNumColor},
{start: msgListIdxes.selectMarkStart, end: msgListIdxes.selectMarkEnd, attrs: this.colors.selectedMsgMarkColor},
{start: msgListIdxes.fromNameStart, end: msgListIdxes.fromNameEnd, attrs: this.colors.msgListFromColor},
{start: msgListIdxes.toNameStart, end: msgListIdxes.toNameEnd, attrs: this.colors.msgListToColor},
{start: msgListIdxes.subjStart, end: msgListIdxes.subjEnd, attrs: this.colors.msgListSubjectColor},
{start: msgListIdxes.dateStart, end: msgListIdxes.dateEnd, attrs: this.colors.msgListDateColor},
{start: msgListIdxes.timeStart, end: msgListIdxes.timeEnd, attrs: this.colors.msgListTimeColor}],
altItemColor: [{start: msgListIdxes.msgNumStart, end: msgListIdxes.msgNumEnd, attrs: this.colors.msgListToUserMsgNumColor},
{start: msgListIdxes.selectMarkStart, end: msgListIdxes.selectMarkEnd, attrs: this.colors.selectedMsgMarkColor},
{start: msgListIdxes.fromNameStart, end: msgListIdxes.fromNameEnd, attrs: this.colors.msgListToUserFromColor},
{start: msgListIdxes.toNameStart, end: msgListIdxes.toNameEnd, attrs: this.colors.msgListToUserToColor},
{start: msgListIdxes.subjStart, end: msgListIdxes.subjEnd, attrs: this.colors.msgListToUserSubjectColor},
{start: msgListIdxes.dateStart, end: msgListIdxes.dateEnd, attrs: this.colors.msgListToUserDateColor},
{start: msgListIdxes.timeStart, end: msgListIdxes.timeEnd, attrs: this.colors.msgListToUserTimeColor}],
selectedItemColor: [{start: msgListIdxes.msgNumStart, end: msgListIdxes.msgNumEnd, attrs: this.colors.msgListMsgNumHighlightColor},
{start: msgListIdxes.selectMarkStart, end: msgListIdxes.selectMarkEnd, attrs: this.colors.selectedMsgMarkColor + this.colors.msgListHighlightBkgColor},
{start: msgListIdxes.fromNameStart, end: msgListIdxes.fromNameEnd, attrs: this.colors.msgListFromHighlightColor},
{start: msgListIdxes.toNameStart, end: msgListIdxes.toNameEnd, attrs: this.colors.msgListToHighlightColor},
{start: msgListIdxes.subjStart, end: msgListIdxes.subjEnd, attrs: this.colors.msgListSubjHighlightColor},
{start: msgListIdxes.dateStart, end: msgListIdxes.dateEnd, attrs: this.colors.msgListDateHighlightColor},
{start: msgListIdxes.timeStart, end: msgListIdxes.timeEnd, attrs: this.colors.msgListTimeHighlightColor}],
altSelectedItemColor: [{start: msgListIdxes.msgNumStart, end: msgListIdxes.msgNumEnd, attrs: this.colors.msgListMsgNumHighlightColor},
{start: msgListIdxes.selectMarkStart, end: msgListIdxes.selectMarkEnd, attrs: this.colors.selectedMsgMarkColor + this.colors.msgListHighlightBkgColor},
{start: msgListIdxes.fromNameStart, end: msgListIdxes.fromNameEnd, attrs: this.colors.msgListFromHighlightColor},
{start: msgListIdxes.toNameStart, end: msgListIdxes.toNameEnd, attrs: this.colors.msgListToHighlightColor},
{start: msgListIdxes.subjStart, end: msgListIdxes.subjEnd, attrs: this.colors.msgListSubjHighlightColor},
{start: msgListIdxes.dateStart, end: msgListIdxes.dateEnd, attrs: this.colors.msgListDateHighlightColor},
{start: msgListIdxes.timeStart, end: msgListIdxes.timeEnd, attrs: this.colors.msgListTimeHighlightColor}]
});

Eric Oulashin
committed
// If we are to show message vote scores in the list (i.e., if the
// user's terminal is wide enough), then splice in color specifiers
// for the score column.
if (this.showScoresInMsgList)
{
msgListMenu.colors.itemColor.splice(5, 0, {start: msgListIdxes.scoreStart, end: msgListIdxes.scoreEnd, attrs: this.colors.msgListScoreColor});
msgListMenu.colors.altItemColor.splice(5, 0, {start: msgListIdxes.scoreStart, end: msgListIdxes.scoreEnd, attrs: this.colors.msgListToUserScoreColor});
msgListMenu.colors.selectedItemColor.splice(5, 0, {start: msgListIdxes.scoreStart, end: msgListIdxes.scoreEnd, attrs: this.colors.msgListScoreHighlightColor + this.colors.msgListHighlightBkgColor});
msgListMenu.colors.altSelectedItemColor.splice(5, 0, {start: msgListIdxes.scoreStart, end: msgListIdxes.scoreEnd, attrs: this.colors.msgListScoreHighlightColor + this.colors.msgListHighlightBkgColor});
}
msgListMenu.multiSelect = false;
msgListMenu.ampersandHotkeysInItems = false;
msgListMenu.wrapNavigation = false;
// Add additional keypresses for quitting the menu's input loop so we can
// respond to these keys

Eric Oulashin
committed
// Ctrl-A: Select all messages
var additionalQuitKeys = "EeqQgGcCsS ?0123456789" + CTRL_A + this.msgListKeys.batchDelete + this.msgListKeys.userSettings;
if (this.CanDelete() || this.CanDeleteLastMsg())

Eric Oulashin
committed
{

Eric Oulashin
committed
additionalQuitKeys += this.msgListKeys.deleteMessage + this.msgListKeys.undeleteMessage.toLowerCase() + this.msgListKeys.undeleteMessage.toUpperCase();

Eric Oulashin
committed
additionalQuitKeys += '\x7f'; // Ensure DEL is in there
additionalQuitKeys += '\x08'; // Ensure BACKSPACE is in there (can be an alternate for delete)
}
if (this.CanEdit())

Eric Oulashin
committed
additionalQuitKeys += this.msgListKeys.editMsg;
msgListMenu.AddAdditionalQuitKeys(additionalQuitKeys);

Eric Oulashin
committed
// Add additional keypresses for PageUp, PageDown, HOME (first page), and END (last page)
msgListMenu.AddAdditionalPageUpKeys("Pp"); // Previous page
msgListMenu.AddAdditionalPageDownKeys("Nn"); // Next page
msgListMenu.AddAdditionalFirstPageKeys("Ff"); // First page
msgListMenu.AddAdditionalLastPageKeys("Ll"); // Last page
// Change the menu's NumItems() and GetItem() function to reference
// the message list in this object rather than add the menu items
// to the menu
msgListMenu.msgReader = this; // Add this object to the menu object
msgListMenu.NumItems = function() {
return this.msgReader.NumMessages();
};

Eric Oulashin
committed
msgListMenu.readingPersonalEmail = this.subBoardCode.toLowerCase() == "mail";
msgListMenu.GetItem = function(pItemIndex) {
var menuItemObj = this.MakeItemWithRetval(-1);

Eric Oulashin
committed
var itemIdx = (this.msgReader.userSettings.listMessagesInReverse ? this.msgReader.NumMessages() - pItemIndex - 1 : pItemIndex);

Eric Oulashin
committed
// In order to get vote score information (displayed if the user's terminal is wide
// enough), the 2nd parameter to GetMsgHdrByIdx() should be true.
var msgHdr = this.msgReader.GetMsgHdrByIdx(itemIdx, this.msgReader.showScoresInMsgList);
if (msgHdr != null)
{
// When setting the item text, call PrintMessageInfo with true as
// the last parameter to return the string instead
menuItemObj.text = strip_ctrl(this.msgReader.PrintMessageInfo(msgHdr, false, itemIdx+1, true));
menuItemObj.retval = msgHdr.number;
if (this.msgReader.subBoardCode != "mail")
menuItemObj.useAltColors = userHandleAliasNameMatch(msgHdr.to);

Eric Oulashin
committed
// For any indicator character next to the message, prioritize deleted, then selected,
// then unread, then attachments
// First, to ensure the correct status character color is used, copy the menu item colors
// in any of these cases; then change the attributes for the 2nd color (selected).
if (this.msgReader.MessageIsSelected(this.msgReader.subBoardCode, pItemIndex) || (msgHdr.attr & MSG_DELETE) == MSG_DELETE || (msgHdr.attr & MSG_READ) == 0 || msgHdrHasAttachmentFlag(msgHdr))
{
menuItemObj.itemColor = [];
for (var i = 0; i < this.colors.itemColor.length; ++i)
menuItemObj.itemColor.push(this.colors.itemColor[i]);
menuItemObj.itemSelectedColor = [];
for (var i = 0; i < this.colors.selectedItemColor.length; ++i)
menuItemObj.itemSelectedColor.push(this.colors.selectedItemColor[i]);
}
// Change the color
// Deleted
if ((msgHdr.attr & MSG_DELETE) == MSG_DELETE)
{

Eric Oulashin
committed
if (menuItemObj.itemColor.length >= 2)
menuItemObj.itemColor[1].attrs = "\x01r\x01h\x01i";
if (menuItemObj.itemSelectedColor.length >= 2)
menuItemObj.itemSelectedColor[1].attrs = "\x01r\x01h\x01i" + this.msgReader.colors.msgListHighlightBkgColor;
}
// Selected, unread, or has attachments
else if (this.msgReader.MessageIsSelected(this.msgReader.subBoardCode, pItemIndex) || (msgHdr.attr & MSG_READ) == 0 || msgHdrHasAttachmentFlag(msgHdr))
{
if (menuItemObj.itemColor.length >= 2)
menuItemObj.itemColor[1].attrs = "\x01n" + this.msgReader.colors.selectedMsgMarkColor;
if (menuItemObj.itemSelectedColor.length >= 2)
menuItemObj.itemSelectedColor[1].attrs = "\x01n" + this.msgReader.colors.selectedMsgMarkColor + this.msgReader.colors.msgListHighlightBkgColor;
}
}
return menuItemObj;
};
// Adjust the menu indexes to ensure they're correct for the current sub-board
this.AdjustLightbarMsgListMenuIdxes(msgListMenu);
return msgListMenu;
}
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
// For the DigDistMsgLister class: Creates a DDLightbarMenu object for the user to choose
// a message group.
//
// Return value: A DDLightbarMenu object set up to let the user choose a message group
function DigDistMsgReader_CreateLightbarMsgGrpMenu()
{
// Start & end indexes for the various items in each mssage group list row
// Selected mark, group#, description, # sub-boards
var msgGrpListIdxes = {
markCharStart: 0,
markCharEnd: 1,
grpNumStart: 1,
grpNumEnd: 2 + (+this.areaNumLen)
};
msgGrpListIdxes.descStart = msgGrpListIdxes.grpNumEnd;
msgGrpListIdxes.descEnd = msgGrpListIdxes.descStart + +this.msgGrpDescLen;
msgGrpListIdxes.numItemsStart = msgGrpListIdxes.descEnd;
msgGrpListIdxes.numItemsEnd = msgGrpListIdxes.numItemsStart + +this.numItemsLen;
// Set numItemsEnd to -1 to let the whole rest of the lines be colored
msgGrpListIdxes.numItemsEnd = -1;
var listStartRow = this.areaChangeHdrLines.length + 2;
var msgGrpMenuHeight = console.screen_rows - listStartRow;
var msgGrpMenu = new DDLightbarMenu(1, listStartRow, console.screen_columns, msgGrpMenuHeight);
msgGrpMenu.scrollbarEnabled = true;
msgGrpMenu.borderEnabled = false;
msgGrpMenu.SetColors({
itemColor: [{start: msgGrpListIdxes.markCharStart, end: msgGrpListIdxes.markCharEnd, attrs: this.colors.areaChooserMsgAreaMarkColor},
{start: msgGrpListIdxes.grpNumStart, end: msgGrpListIdxes.grpNumEnd, attrs: this.colors.areaChooserMsgAreaNumColor},
{start: msgGrpListIdxes.descStart, end: msgGrpListIdxes.descEnd, attrs: this.colors.areaChooserMsgAreaDescColor},
{start: msgGrpListIdxes.numItemsStart, end: msgGrpListIdxes.numItemsEnd, attrs: this.colors.areaChooserMsgAreaNumItemsColor}],
selectedItemColor: [{start: msgGrpListIdxes.markCharStart, end: msgGrpListIdxes.markCharEnd, attrs: this.colors.areaChooserMsgAreaMarkColor + this.colors.areaChooserMsgAreaBkgHighlightColor},
{start: msgGrpListIdxes.grpNumStart, end: msgGrpListIdxes.grpNumEnd, attrs: this.colors.areaChooserMsgAreaNumHighlightColor},
{start: msgGrpListIdxes.descStart, end: msgGrpListIdxes.descEnd, attrs: this.colors.areaChooserMsgAreaDescHighlightColor},
{start: msgGrpListIdxes.numItemsStart, end: msgGrpListIdxes.numItemsEnd, attrs: this.colors.areaChooserMsgAreaNumItemsHighlightColor}]
});
msgGrpMenu.multiSelect = false;
msgGrpMenu.ampersandHotkeysInItems = false;
msgGrpMenu.wrapNavigation = false;
// Add additional keypresses for quitting the menu's input loop so we can
// respond to these keys
msgGrpMenu.AddAdditionalQuitKeys("nNqQ ?0123456789/" + CTRL_F);
// Change the menu's NumItems() and GetItem() function to reference
// the message list in this object rather than add the menu items
// to the menu
msgGrpMenu.msgReader = this; // Add this object to the menu object
msgGrpMenu.NumItems = function() {
return msg_area.grp_list.length;
};
msgGrpMenu.GetItem = function(pGrpIndex) {
var menuItemObj = this.MakeItemWithRetval(-1);
if ((pGrpIndex >= 0) && (pGrpIndex < msg_area.grp_list.length))
{
menuItemObj.text = format(((typeof(bbs.curgrp) == "number") && (pGrpIndex == msg_area.sub[this.msgReader.subBoardCode].grp_index)) ? "*" : " ");
menuItemObj.text += format(this.msgReader.msgGrpListPrintfStr, +(pGrpIndex+1),
msg_area.grp_list[pGrpIndex].description.substr(0, this.msgReader.msgGrpDescLen),
msg_area.grp_list[pGrpIndex].sub_list.length);
menuItemObj.text = strip_ctrl(menuItemObj.text);
menuItemObj.retval = pGrpIndex;
}
return menuItemObj;
};
// Set the currently selected item to the current group

Eric Oulashin
committed
msgGrpMenu.SetSelectedItemIdx(msg_area.sub[this.subBoardCode].grp_index);
/*
msgGrpMenu.selectedItemIdx = msg_area.sub[this.subBoardCode].grp_index;
if (msgGrpMenu.selectedItemIdx >= msgGrpMenu.topItemIdx+msgGrpMenu.GetNumItemsPerPage())
msgGrpMenu.topItemIdx = msgGrpMenu.selectedItemIdx - msgGrpMenu.GetNumItemsPerPage() + 1;

Eric Oulashin
committed
*/
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
return msgGrpMenu;
}
// For the DigDistMsgLister class: Creates a DDLightbarMenu object for the user to choose
// a sub-board within a message group.
//
// Parameters:
// pGrpIdx: The index of the group to list sub-boards for
//
// Return value: A DDLightbarMenu object set up to let the user choose a sub-board within the
// given message group
function DigDistMsgReader_CreateLightbarSubBoardMenu(pGrpIdx)
{
// Start & end indexes for the various items in each sub-board list row
// Selected mark, group#, description, # sub-boards
var subBrdListIdxes = {
markCharStart: 0,
markCharEnd: 1,
subNumStart: 1,
subNumEnd: 2 + (+this.areaNumLen)
};
subBrdListIdxes.descStart = subBrdListIdxes.subNumEnd;
subBrdListIdxes.descEnd = subBrdListIdxes.descStart + +(this.subBoardListPrintfInfo[pGrpIdx].nameLen) + 1;
subBrdListIdxes.numItemsStart = subBrdListIdxes.descEnd;
subBrdListIdxes.numItemsEnd = subBrdListIdxes.numItemsStart + +(this.subBoardListPrintfInfo[pGrpIdx].numMsgsLen) + 1;
subBrdListIdxes.dateStart = subBrdListIdxes.numItemsEnd;
subBrdListIdxes.dateEnd = subBrdListIdxes.dateStart + +this.dateLen + 1;
subBrdListIdxes.timeStart = subBrdListIdxes.dateEnd;
// Set timeEnd to -1 to let the whole rest of the lines be colored
subBrdListIdxes.timeEnd = -1;
var listStartRow = this.areaChangeHdrLines.length + 3;
var subBrdMenuHeight = console.screen_rows - listStartRow;
var subBoardMenu = new DDLightbarMenu(1, listStartRow, console.screen_columns, subBrdMenuHeight);
subBoardMenu.scrollbarEnabled = true;
subBoardMenu.borderEnabled = false;
subBoardMenu.SetColors({
itemColor: [{start: subBrdListIdxes.markCharStart, end: subBrdListIdxes.markCharEnd, attrs: this.colors.areaChooserMsgAreaMarkColor},
{start: subBrdListIdxes.subNumStart, end: subBrdListIdxes.subNumEnd, attrs: this.colors.areaChooserMsgAreaNumColor},
{start: subBrdListIdxes.descStart, end: subBrdListIdxes.descEnd, attrs: this.colors.areaChooserMsgAreaDescColor},
{start: subBrdListIdxes.numItemsStart, end: subBrdListIdxes.numItemsEnd, attrs: this.colors.areaChooserMsgAreaNumItemsColor},
{start: subBrdListIdxes.dateStart, end: subBrdListIdxes.dateEnd, attrs: this.colors.areaChooserMsgAreaLatestDateColor},
{start: subBrdListIdxes.timeStart, end: subBrdListIdxes.timeEnd, attrs: this.colors.areaChooserMsgAreaLatestTimeColor}],
selectedItemColor: [{start: subBrdListIdxes.markCharStart, end: subBrdListIdxes.markCharEnd, attrs: this.colors.areaChooserMsgAreaMarkColor + this.colors.areaChooserMsgAreaBkgHighlightColor},
{start: subBrdListIdxes.subNumStart, end: subBrdListIdxes.subNumEnd, attrs: this.colors.areaChooserMsgAreaNumHighlightColor},
{start: subBrdListIdxes.descStart, end: subBrdListIdxes.descEnd, attrs: this.colors.areaChooserMsgAreaDescHighlightColor},
{start: subBrdListIdxes.numItemsStart, end: subBrdListIdxes.numItemsEnd, attrs: this.colors.areaChooserMsgAreaNumItemsHighlightColor},
{start: subBrdListIdxes.dateStart, end: subBrdListIdxes.dateEnd, attrs: this.colors.areaChooserMsgAreaDateHighlightColor},
{start: subBrdListIdxes.timeStart, end: subBrdListIdxes.timeEnd, attrs: this.colors.areaChooserMsgAreaTimeHighlightColor}]
});
subBoardMenu.multiSelect = false;
subBoardMenu.ampersandHotkeysInItems = false;
subBoardMenu.wrapNavigation = false;
// Add additional keypresses for quitting the menu's input loop so we can
// respond to these keys
subBoardMenu.AddAdditionalQuitKeys("nNqQ ?0123456789/" + CTRL_F);

Eric Oulashin
committed
// Add the sub-board items to the menu
for (var subIdx = 0; subIdx < msg_area.grp_list[pGrpIdx].sub_list.length; ++subIdx)
{
var itemText = this.GetMsgSubBoardLine(pGrpIdx, subIdx, false);
subBoardMenu.Add(strip_ctrl(itemText), subIdx);
}
// Alternately, we could change the menu's NumItems() and GetItem():
/*
// Change the menu's NumItems() and GetItem() function to reference
// the message list in this object rather than add the menu items
// to the menu
subBoardMenu.msgReader = this; // Add this object to the menu object
subBoardMenu.grpIdx = pGrpIdx;
subBoardMenu.NumItems = function() {
return msg_area.grp_list[pGrpIdx].sub_list.length;
};
subBoardMenu.GetItem = function(pSubIdx) {
var menuItemObj = this.MakeItemWithRetval(-1);
if ((pSubIdx >= 0) && (pSubIdx < msg_area.grp_list[this.grpIdx].sub_list.length))
{
//var highlight = (msg_area.grp_list[this.grpIdx].sub_list[pSubIdx].code.toUpperCase() == this.msgReader.subBoardCode.toUpperCase());
menuItemObj.text = this.msgReader.GetMsgSubBoardLine(this.grpIdx, pSubIdx, false);
menuItemObj.text = strip_ctrl(menuItemObj.text);
menuItemObj.retval = pSubIdx;
}
return menuItemObj;
};

Eric Oulashin
committed
*/
// Set the currently selected item to the current group
if (msg_area.sub[this.subBoardCode].grp_index == pGrpIdx)
{

Eric Oulashin
committed
subBoardMenu.SetSelectedItemIdx(msg_area.sub[this.subBoardCode].index);
/*
subBoardMenu.selectedItemIdx = msg_area.sub[this.subBoardCode].index;
if (subBoardMenu.selectedItemIdx >= subBoardMenu.topItemIdx+subBoardMenu.GetNumItemsPerPage())
subBoardMenu.topItemIdx = subBoardMenu.selectedItemIdx - subBoardMenu.GetNumItemsPerPage() + 1;

Eric Oulashin
committed
*/
}
else
{

Eric Oulashin
committed
subBoardMenu.SetSelectedItemIdx(0);
/*
subBoardMenu.selectedItemIdx = 0;
subBoardMenu.topItemIdx = 0;

Eric Oulashin
committed
*/
}
return subBoardMenu;
}
// For the DigDistMsgLister class: Adjusts lightbar menu indexes for a message list menu
function DigDistMsgReader_AdjustLightbarMsgListMenuIdxes(pMsgListMenu)
{

Eric Oulashin
committed
pMsgListMenu.SetSelectedItemIdx(this.lightbarListSelectedMsgIdx);
/*
pMsgListMenu.selectedItemIdx = this.lightbarListSelectedMsgIdx;
pMsgListMenu.topItemIdx = this.lightbarListTopMsgIdx;

Eric Oulashin
committed
*/
// In the DDLightbarMenu class, the top index on the last page should
// allow for displaying a full page of items. So if
// this.lightbarListTopMsgIdx is beyond the top index for the last
// page in the menu object, then adjust this.lightbarListTopMsgIdx.
var menuTopItemIdxOnLastPage = pMsgListMenu.GetTopItemIdxOfLastPage();
if (pMsgListMenu.topItemIdx > menuTopItemIdxOnLastPage)
{
pMsgListMenu.topItemIdx = menuTopItemIdxOnLastPage;
this.lightbarListTopMsgIdx = menuTopItemIdxOnLastPage;
}
// TODO: Ensure this.lightbarListTopMsgIdx is always correct for the last page
}
// For the DigDistMsgListerClass: Prints a line of information about
// a message.
//
// Parameters:
// pMsgHeader: The message header object, returned by MsgBase.get_msg_header().
// pHighlight: Optional boolean - Whether or not to highlight the line (true) or
// use the standard colors (false).
// pMsgNum: Optional - A number to use for the message instead of the number/offset
// in the message header
// pReturnStrInstead: Optional boolean - Whether or not to return a formatted string
// instead of printing to the console. Defaults to false.
function DigDistMsgReader_PrintMessageInfo(pMsgHeader, pHighlight, pMsgNum, pReturnStrInstead)
{
// pMsgHeader must be a valid object.
if (typeof(pMsgHeader) == "undefined")
return;
if (pMsgHeader == null)
return;
var highlight = false;
if (typeof(pHighlight) == "boolean")
highlight = pHighlight;
// Get the message's import date & time as strings. If
// this.msgList_displayMessageDateImported is true, use the message import date.
// Otherwise, use the message written date.
var sDate;
var sTime;
if (this.msgList_displayMessageDateImported)
{
sDate = strftime("%Y-%m-%d", pMsgHeader.when_imported_time);
sTime = strftime("%H:%M:%S", pMsgHeader.when_imported_time);
}
else
{
//sDate = strftime("%Y-%m-%d", pMsgHeader.when_written_time);
//sTime = strftime("%H:%M:%S", pMsgHeader.when_written_time);
var msgWrittenLocalTime = msgWrittenTimeToLocalBBSTime(pMsgHeader);
if (msgWrittenLocalTime != -1)
{
sDate = strftime("%Y-%m-%d", msgWrittenLocalTime);
sTime = strftime("%H:%M:%S", msgWrittenLocalTime);
}
else
{
sDate = strftime("%Y-%m-%d", pMsgHeader.when_written_time);
sTime = strftime("%H:%M:%S", pMsgHeader.when_written_time);
}
}
//var msgNum = (typeof(pMsgNum) == "number" ? pMsgNum : pMsgHeader.offset+1);
var msgNum = (typeof(pMsgNum) == "number" ? pMsgNum : this.GetMsgIdx(pMsgHeader.number)+1);

nightfox
committed
if (msgNum == 0) // In case GetMsgIdx() returns -1 for failure
msgNum = 1;
// Determine if the message has been deleted.
var msgDeleted = ((pMsgHeader.attr & MSG_DELETE) == MSG_DELETE);
// msgIndicatorChar will contain (possibly) a character to display after
// the message number to indicate whether it has been deleted, selected,
// etc. If not, then it will just be a space.
var msgIndicatorChar = " ";
// Get the message score value
var msgVoteInfo = getMsgUpDownvotesAndScore(pMsgHeader);
// Ensure the score number can fit within 4 digits
if (msgVoteInfo.voteScore > 9999)
msgVoteInfo.voteScore = 9999;
else if (msgVoteInfo.voteScore < -999)
msgVoteInfo.voteScore = -999;
// Generate the string with the message header information.
var msgHdrStr = "";
// Note: The message header has the following fields:
// 'number': The message number
// 'offset': The message offset
// 'to': Who the message is directed to (string)
// 'from' Who wrote the message (string)
// 'subject': The message subject (string)
// 'date': The date - Full text (string)
// To access one of these, use brackets; i.e., msgHeader['to']
if (highlight)
{

Eric Oulashin
committed
// For any indicator character next to the message, prioritize selected, then deleted,
// then unread, then attachments
if (this.MessageIsSelected(this.subBoardCode, msgNum-1))
msgIndicatorChar = "\x01n" + this.colors.selectedMsgMarkColor + this.colors.msgListHighlightBkgColor + CHECK_CHAR + "\x01n";
else if (msgDeleted)
msgIndicatorChar = "\x01n\x01r\x01h\x01i" + this.colors.msgListHighlightBkgColor + "*\x01n";

Eric Oulashin
committed
else if (this.readingPersonalEmail && (pMsgHeader.attr & MSG_READ) == 0)
msgIndicatorChar = "\x01n" + this.colors.selectedMsgMarkColor + this.colors.msgListHighlightBkgColor + "U\x01n";
else if (msgHdrHasAttachmentFlag(pMsgHeader))
msgIndicatorChar = "\x01n" + this.colors.selectedMsgMarkColor + this.colors.msgListHighlightBkgColor + "A\x01n";
var fromName = pMsgHeader.from;
// If the message was posted anonymously and the logged-in user is
// not the sysop, then show "Anonymous" for the 'from' name.
Eric Oulashin
committed
if (!user.is_sysop && ((pMsgHeader.attr & MSG_ANONYMOUS) == MSG_ANONYMOUS))
fromName = "Anonymous";
if (this.showScoresInMsgList)
{
msgHdrStr += format(this.sMsgInfoFormatHighlightStr, msgNum, msgIndicatorChar,
fromName.substr(0, this.FROM_LEN),
pMsgHeader.to.substr(0, this.TO_LEN),
pMsgHeader.subject.substr(0, this.SUBJ_LEN),
msgVoteInfo.voteScore, sDate, sTime);
}
else
{

Eric Oulashin
committed
msgHdrStr += format(this.sMsgInfoFormatHighlightStr, msgNum, msgIndicatorChar,
fromName.substr(0, this.FROM_LEN),
pMsgHeader.to.substr(0, this.TO_LEN),
pMsgHeader.subject.substr(0, this.SUBJ_LEN),

Eric Oulashin
committed
sDate, sTime);
}
}
else
{

Eric Oulashin
committed
// For any indicator character next to the message, prioritize selected, then deleted,
// then unread, then attachments
if (this.MessageIsSelected(this.subBoardCode, msgNum-1))
msgIndicatorChar = "\x01n" + this.colors.selectedMsgMarkColor + CHECK_CHAR + "\x01n";
else if (msgDeleted)
msgIndicatorChar = "\x01n\x01r\x01h\x01i*\x01n";

Eric Oulashin
committed
else if (this.readingPersonalEmail && (pMsgHeader.attr & MSG_READ) == 0)
msgIndicatorChar = "\x01n" + this.colors.selectedMsgMarkColor + "U\x01n";
else if (msgHdrHasAttachmentFlag(pMsgHeader))

Eric Oulashin
committed
msgIndicatorChar = "\x01n" + this.colors.selectedMsgMarkColor + "A\x01n";
// Determine whether to use the normal, "to-user", or "from-user" format string.
// The differences are the colors. Then, output the message information line.
var toNameUpper = pMsgHeader.to.toUpperCase();
var msgToUser = ((toNameUpper == user.alias.toUpperCase()) || (toNameUpper == user.name.toUpperCase()) || (toNameUpper == user.handle.toUpperCase()));
var fromNameUpper = pMsgHeader.from.toUpperCase();
var msgIsFromUser = ((fromNameUpper == user.alias.toUpperCase()) || (fromNameUpper == user.name.toUpperCase()) || (fromNameUpper == user.handle.toUpperCase()));
var formatStr = ""; // Format string for printing the message information
if (this.readingPersonalEmail)
formatStr = this.sMsgInfoFormatStr;
else
formatStr = (msgToUser ? this.sMsgInfoToUserFormatStr : (msgIsFromUser ? this.sMsgInfoFromUserFormatStr : this.sMsgInfoFormatStr));
var fromName = pMsgHeader.from;
// If the message was posted anonymously and the logged-in user is
// not the sysop, then show "Anonymous" for the 'from' name.
Eric Oulashin
committed
if (!user.is_sysop && ((pMsgHeader.attr & MSG_ANONYMOUS) == MSG_ANONYMOUS))
fromName = "Anonymous";
if (this.showScoresInMsgList)
{
msgHdrStr += format(formatStr, msgNum, msgIndicatorChar, fromName.substr(0, this.FROM_LEN),
pMsgHeader.to.substr(0, this.TO_LEN), pMsgHeader.subject.substr(0, this.SUBJ_LEN),
msgVoteInfo.voteScore, sDate, sTime);
}
else
{
msgHdrStr += format(formatStr, msgNum, msgIndicatorChar, fromName.substr(0, this.FROM_LEN),
pMsgHeader.to.substr(0, this.TO_LEN), pMsgHeader.subject.substr(0, this.SUBJ_LEN),
sDate, sTime);
}
}
var returnStrInstead = (typeof(pReturnStrInstead) == "boolean" ? pReturnStrInstead : false);
if (!returnStrInstead)
{
console.print(msgHdrStr);
console.cleartoeol("\x01n"); // To clear away any extra text that may have been entered by the user
}
return msgHdrStr;
}
// For the traditional interface of DigDistMsgListerClass: Prompts the user to
// continue or read a message (by number).
//
// Parameters:
// pStart: Whether or not we're on the first page (true or false)
// pEnd: Whether or not we're at the last page (true or false)

nightfox
committed
// pAllowChgSubBoard: Optional - A boolean to specify whether or not to allow
// changing to another sub-board. Defaults to true.
//
// Return value: An object with the following properties:
// continueOn: Boolean, whether or not the user wants to continue
// listing the messages
// userInput: The user's input
// selectedMsgOffset: The offset of the message selected to read,
// if one was selected. If a message was not
// selected, this will be -1.
function DigDistMsgReader_PromptContinueOrReadMsg(pStart, pEnd, pAllowChgSubBoard)
{

nightfox
committed
// Create the return object and set some initial default values
var retObj = {
continueOn: true,
userInput: "",
selectedMsgOffset: -1
};

nightfox
committed
var allowChgSubBoard = (typeof(pAllowChgSubBoard) == "boolean" ? pAllowChgSubBoard : true);
var continueOn = true;
// Prompt the user whether or not to continue or to read a message
// (by message number). Make use of the different prompt texts,
// depending whether we're at the beginning, in the middle, or at
// the end of the message list.
var userInput = "";
var allowedKeys = "?GS"; // ? = help, G = Go to message #, S = Select message(s), Ctrl-D: Batch delete

Eric Oulashin
committed
allowedKeys += this.msgListKeys.userSettings;

nightfox
committed
if (allowChgSubBoard)
allowedKeys += "C"; // Change to another message area
if (this.CanDelete() || this.CanDeleteLastMsg())

Eric Oulashin
committed
{

nightfox
committed
allowedKeys += "D"; // Delete

Eric Oulashin
committed
allowedKeys += this.enhReaderKeys.deleteMessage;
allowedKeys += '\x7f';
allowedKeys += '\x08';
}

nightfox
committed
if (this.CanEdit())
allowedKeys += "E"; // Edit
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
if (pStart && pEnd)
{
// This is the only page.
console.print(this.msgListOnlyOnePageContinuePrompt);
// Get input from the user. Allow only Q (quit).
allowedKeys += "Q";
}
else if (pStart)
{
// We're on the first page.
console.print(this.sStartContinuePrompt);
// Get input from the user. Allow only L (last), N (next), or Q (quit).
allowedKeys += "LNQ";
}
else if (pEnd)
{
// We're on the last page.
console.print(this.sEndContinuePrompt);
// Get input from the user. Allow only F (first), P (previous), or Q (quit).
allowedKeys += "FPQ";
}
else
{
// We're neither on the first nor last page. Allow F (first), L (last),
// N (next), P (previous), or Q (quit).
console.print(this.sContinuePrompt);
allowedKeys += "FLNPQ";
}
// Get the user's input. Allow CTRL-D (batch delete) without echoing it.
// If the user didn't press CTRL-L, allow the keys in allowedKeys or a number from 1
// to the highest message number.
userInput = console.getkey(K_NOECHO);

Eric Oulashin
committed
if (userInput != this.enhReaderKeys.batchDelete) // CTRL_D
{
console.ungetstr(userInput);
userInput = console.getkeys(allowedKeys, this.HighestMessageNum()).toString();
}
if (userInput == "Q")
continueOn = false;
// If the user has typed all numbers, then read that message.
if ((userInput != "") && /^[0-9]+$/.test(userInput))
{
// If the user entered a valid message number, then let the user read the message.
// The message number might be invalid if there are search results that
// have non-continuous message numbers.
if (this.IsValidMessageNum(userInput))
{
// See if the current message header has our "isBogus" property and it's true.
// Only let the user read the message if it's not a bogus message header.
// The message header could have the "isBogus" property, for instance, if
// it's a vote message (introduced in Synchronet 3.17).
var tmpMsgHdr = this.GetMsgHdrByIdx(+(userInput-1), false);

Eric Oulashin
committed
if (tmpMsgHdr != null)
{
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
// Confirm with the user whether to read the message
var readMsg = true;
if (this.promptToReadMessage)
{
var sReadMsgConfirmText = this.colors["readMsgConfirmColor"]
+ "Read message "
+ this.colors["readMsgConfirmNumberColor"]
+ userInput + this.colors["readMsgConfirmColor"]
+ ": Are you sure";
readMsg = console.yesno(sReadMsgConfirmText);
}
if (readMsg)
{
// Update the message list screen variables
this.CalcMsgListScreenIdxVarsFromMsgNum(+userInput);
// Return from here so that the calling function can switch
// into reader mode.
retObj.continueOn = continueOn;
retObj.userInput = userInput;
retObj.selectedMsgOffset = userInput-1;
return retObj;
}
else
this.deniedReadingMessage = true;
// Prompt the user whether or not to continue listing
// messages.
if (this.promptToContinueListingMessages)
{
continueOn = console.yesno(this.colors["afterReadMsg_ListMorePromptColor"] +
"Continue listing messages");
}
}
else
{
console.print("\x01n\x01h\x01yThat's not a readable message.\x01n");
console.crlf();
console.pause();
}
}
else
{
// The user entered an invalid message number.
console.print("\x01n\x01h\x01w" + userInput + " \x01y is not a valid message number.\x01n");
console.crlf();
console.pause();
continueOn = true;
}
}
// Make sure color highlighting is turned off
console.attributes = "N";
// Fill the return object with the required values, and return it.
retObj.continueOn = continueOn;
retObj.userInput = userInput;
return retObj;
}
// For the DigDistMsgReader Class: Given a message number of a message in the
// current message area, lets the user read a message and allows the user to
// respond, etc. This is an enhanced version that allows scrolling up & down
// the message with the up & down arrow keys, and the left & right arrow keys
// will return from the function to allow calling code to navigate back & forth
// through the message sub-board.
//
// Parameters:
// pOffset: The offset of the message to be read
// pAllowChgArea: Optional boolean - Whether or not to allow changing the
// message area
//
// Return value: And object with the following properties:
// offsetValid: Boolean - Whether or not the passed-in offset was valid
// msgDeleted: Boolean - Whether or not the message is marked as deleted
// (not deleted by the user in the reader)
// userReplied: Boolean - Whether or not the user replied to the message.
// lastKeypress: The last keypress from the user - For navigation purposes
// newMsgOffset: The offset of another message to read, if the user
// input another message number. If the user did not
// input another message number, this will be -1.
// nextAction: The next action for the caller to take. This will be
// one of the values specified by the ACTION_* constants.
// This defaults to ACTION_NONE on error.
// refreshEnhancedRdrHelpLine: Boolean - Whether or not to refresh the
// enhanced reader help line on the screen
// (for instance, if switched to the traditional
// non-scrolling interface to read the message)
function DigDistMsgReader_ReadMessageEnhanced(pOffset, pAllowChgArea)
{
var retObj = {
offsetValid: true,
msgNotReadable: false,
userReplied: false,
lastKeypress: "",
newMsgOffset: -1,
nextAction: ACTION_NONE,
refreshEnhancedRdrHelpLine: false
};
// Get the message header. Don't expand fields since we may need to save
// the header later with the MSG_READ attribute.
//var msgHeader = this.GetMsgHdrByIdx(pOffset, false);
// Get the message header. Get expanded fields so that we can show any
// voting stats/responses that may be included with the message.
var msgHeader = this.GetMsgHdrByIdx(pOffset, true);
if (msgHeader == null)
{

Eric Oulashin
committed
//console.print("\x01n" + replaceAtCodesInStr(format(this.text.invalidMsgNumText, +(pOffset+1))) + "\x01n");
//console.crlf();
console.putmsg("\x01n" + format(this.text.invalidMsgNumText, +(pOffset+1)) + "\x01n");
console.inkey(K_NONE, ERROR_PAUSE_WAIT_MS);
retObj.offsetValid = false;
return retObj;
}

nightfox
committed
// If this message is not readable for the user (it's marked as deleted and
// the system is set to not show deleted messages, etc.), then don't let the
// user read it, and just silently return.
// TODO: If the message is not readable, this will end up causing an infinite loop.

nightfox
committed
retObj.msgNotReadable = !isReadableMsgHdr(msgHeader, this.subBoardCode);
if (retObj.msgNotReadable)
return retObj;

Eric Oulashin
committed
// Mark the message as read if it was written to the current user

Eric Oulashin
committed
var personalEmailToCurrentSysopUser = this.readingPersonalEmail && user.is_sysop && msgHeader.to.toUpperCase().indexOf("SYSOP") == 0;
if (((msgHeader.attr & MSG_READ) == 0) && (userHandleAliasNameMatch(msgHeader.to) || personalEmailToCurrentSysopUser))

Eric Oulashin
committed
{
// Using applyAttrsInMsgHdrInMessagbase(), which loads the header without
// expanded fields and saves the attributes with that header.
var saveRetObj = applyAttrsInMsgHdrInMessagbase(this.subBoardCode, msgHeader.number, MSG_READ);
if (this.SearchTypePopulatesSearchResults() && saveRetObj.saveSucceeded)
this.RefreshHdrInSavedArrays(pOffset, MSG_READ, true);
}
// Updating message pointers etc.
updateScanPtrAndOrLastRead(this.subBoardCode, msgHeader, this.doingMsgScan);
// Update the message list index variables so that the message list is in
// the right spot for the message currently being read
this.CalcMsgListScreenIdxVarsFromMsgNum(pOffset+1);
// Check the pAllowChgArea parameter. If it's a boolean, then use it. If
// not, then check to see if we're reading personal mail - If not, then allow
// the user to change to a different message area.
var allowChgMsgArea = true;
if (typeof(pAllowChgArea) == "boolean")
allowChgMsgArea = pAllowChgArea;
else
allowChgMsgArea = (this.subBoardCode != "mail");

nightfox
committed
// Get the message text and see if it has any ANSI codes. Remove any pause
// codes it might have. If it has ANSI codes, then don't use the scrolling
// interface so that the ANSI gets displayed properly.
var getMsgBodyRetObj = this.GetMsgBody(msgHeader);
var messageText = getMsgBodyRetObj.msgBody;
if (msgHdrHasAttachmentFlag(msgHeader))
{
messageText = "\x01n\x01g\x01h- This message contains one or more attachments. Press CTRL-A to download.\x01n\r\n"
+ "\x01n\x01g\x01h--------------------------------------------------------------------------\x01n\r\n"
+ messageText;
}
var useScrollingInterface = this.scrollingReaderInterface && console.term_supports(USER_ANSI);
// If we switch to the non-scrolling interface here, then the calling method should
// refresh the enhanced reader help line on the screen.
retObj.refreshEnhancedRdrHelpLine = (this.scrollingReaderInterface && !useScrollingInterface);
// If the current message is new to the user, update the number of posts read this session.
if (pOffset > this.GetScanPtrMsgIdx())
++bbs.posts_read;
// Use the scrollable reader interface if the setting is enabled & the user's
// terminal supports ANSI. Otherwise, use a more traditional user interface.
if (useScrollingInterface)
retObj = this.ReadMessageEnhanced_Scrollable(msgHeader, allowChgMsgArea, messageText, pOffset, getMsgBodyRetObj.pmode);
else
retObj = this.ReadMessageEnhanced_Traditional(msgHeader, allowChgMsgArea, messageText, pOffset, getMsgBodyRetObj.pmode);
return retObj;
}
// Helper method for ReadMessageEnhanced() - Does the scrollable reader interface
function DigDistMsgReader_ReadMessageEnhanced_Scrollable(msgHeader, allowChgMsgArea, messageText, pOffset, pmode)
{
var retObj = {
offsetValid: true,
msgNotReadable: false,
userReplied: false,
lastKeypress: "",
newMsgOffset: -1,
nextAction: ACTION_NONE,
refreshEnhancedRdrHelpLine: false
};
Eric Oulashin
committed
// This is a scrollbar update function for use when viewing the message.
function msgScrollbarUpdateFn(pFractionToLastPage)
{
// Update the scrollbar position for the message, depending on the
// value of pFractionToLastMessage.
fractionToLastPage = pFractionToLastPage;
solidBlockStartRow = msgReaderObj.msgAreaTop + Math.floor(numNonSolidScrollBlocks * pFractionToLastPage);
if (solidBlockStartRow != solidBlockLastStartRow)

Eric Oulashin
committed
msgReaderObj.UpdateEnhancedReaderScrollbar(solidBlockStartRow, solidBlockLastStartRow, numSolidScrollBlocks);
Eric Oulashin
committed
solidBlockLastStartRow = solidBlockStartRow;
console.gotoxy(1, console.screen_rows);
}
// This is a scrollbar update function for use when viewing the header info/kludge lines.
function msgInfoScrollbarUpdateFn(pFractionToLastPage)
{
var infoSolidBlockStartRow = msgReaderObj.msgAreaTop + Math.floor(numNonSolidInfoScrollBlocks * pFractionToLastPage);
if (infoSolidBlockStartRow != lastInfoSolidBlockStartRow)

Eric Oulashin
committed
msgReaderObj.UpdateEnhancedReaderScrollbar(infoSolidBlockStartRow, lastInfoSolidBlockStartRow, numInfoSolidScrollBlocks);
Eric Oulashin
committed
lastInfoSolidBlockStartRow = infoSolidBlockStartRow;
console.gotoxy(1, console.screen_rows);
}
var msgAreaWidth = this.userSettings.useEnhReaderScrollbar ? this.msgAreaWidth : this.msgAreaWidth + 1;

Eric Oulashin
committed
Eric Oulashin
committed
// We could word-wrap the message to ensure words aren't split across lines, but
// doing so could make some messages look bad (i.e., messages with drawing characters),
// and word_wrap also might not handle ANSI or other color/attribute codes..
//if (!textHasDrawingChars(messageText))

Eric Oulashin
committed
// messageText = word_wrap(messageText, msgAreaWidth);
Eric Oulashin
committed
// If the message has ANSI content, then use a Graphic object to help make
// the message look good. Also, remove any ANSI clear screen codes from the
// message text.
var msgHasANSICodes = messageText.indexOf("\x1b[") >= 0;
if (msgHasANSICodes)
{
messageText = messageText.replace(/\u001b\[[012]J/gi, "");
//var graphic = new Graphic(msgAreaWidth, this.msgAreaHeight-1);
// To help ensure ANSI messages look good, it seems the Graphic object should have
// its with later set to 1 less than the width used to create it.
var graphicWidth = (msgAreaWidth < console.screen_columns ? msgAreaWidth+1 : console.screen_columns);
var graphic = new Graphic(graphicWidth, this.msgAreaHeight-1);
graphic.auto_extend = true;
graphic.ANSI = ansiterm.expand_ctrl_a(messageText);

Eric Oulashin
committed
//graphic.normalize();
graphic.width = graphicWidth - 1;

Eric Oulashin
committed
//messageText = graphic.MSG.split('\n');
messageText = graphic.MSG;
}
// Show the message header
this.DisplayEnhancedMsgHdr(msgHeader, pOffset+1, 1);
// Get the message text, interpret any @-codes in it, replace tabs with spaces
// to prevent weirdness when displaying the message lines, and word-wrap the
// text so that it looks good on the screen,
var msgInfo = this.GetMsgInfoForEnhancedReader(msgHeader, true, true, true, messageText);
var topMsgLineIdxForLastPage = msgInfo.topMsgLineIdxForLastPage;
var numSolidScrollBlocks = msgInfo.numSolidScrollBlocks;
var numNonSolidScrollBlocks = msgInfo.numNonSolidScrollBlocks;
var solidBlockStartRow = msgInfo.solidBlockStartRow;
var solidBlockLastStartRow = solidBlockStartRow;
var topMsgLineIdx = 0;
var fractionToLastPage = 0;
if (topMsgLineIdxForLastPage != 0)
fractionToLastPage = topMsgLineIdx / topMsgLineIdxForLastPage;

Eric Oulashin
committed
// If use of the scrollbar is enabled, draw an initial scrollbar on the rightmost
// column of the message area showing the fraction of the message shown and what
// part of the message is currently being shown. The scrollbar will be updated
// minimally in the input loop to minimize screen redraws.
if (this.userSettings.useEnhReaderScrollbar)