You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

872 lines
32 KiB

-- File: WhisperEngine.lua
-- Author: John Langone (Pazza - Bronzebeard)
-- Description: This module handles whisper behaviors as well as their respective window actions.
--[[
Extends Modules by adding:
Module:PostEvent_Whisper(args[...])
Module:PostEvent_WhisperInform(args[...])
]]
-- imports
local WIM = WIM;
local _G = _G;
local CreateFrame = CreateFrame;
local hooksecurefunc = hooksecurefunc;
local table = table;
local pairs = pairs;
local strupper = strupper;
local gsub = gsub;
local strlen = strlen;
local strsub = strsub;
local string = string;
local IsShiftKeyDown = IsShiftKeyDown;
local select = select;
local unpack = unpack;
local math = math;
local time = time;
local playerRealm = GetRealmName();
local GetPlayerInfoByGUID = GetPlayerInfoByGUID;
local FlashClientIcon = FlashClientIcon;
-- set name space
setfenv(1, WIM);
-- create WIM Module
local WhisperEngine = CreateModule("WhisperEngine", true);
-- declare default settings for whispers.
-- if new global env wasn't set to WIM's namespace, then your module would call as follows:
-- WhisperEngine.db_defaults... or WIM.db_defaults...
db_defaults.pop_rules.whisper = {
--pop-up rule sets based off of your location
resting = {
onSend = true,
onReceive = true,
supress = true,
autofocus = true,
keepfocus = true,
},
combat = {
onSend = false,
onReceive = false,
supress = false,
autofocus = false,
keepfocus = false,
},
pvp = {
onSend = true,
onReceive = true,
supress = true,
autofocus = false,
keepfocus = false,
},
arena = {
onSend = false,
onReceive = false,
supress = false,
autofocus = false,
keepfocus = false,
},
party = {
onSend = true,
onReceive = true,
supress = true,
autofocus = false,
keepfocus = false,
},
raid = {
onSend = true,
onReceive = true,
supress = true,
autofocus = false,
keepfocus = false,
},
other = {
onSend = true,
onReceive = true,
supress = true,
autofocus = false,
keepfocus = false,
},
alwaysOther = false,
intercept = true,
obeyAutoFocusRules = false,
}
db_defaults.displayColors.wispIn = {
r=0.5607843137254902,
g=0.03137254901960784,
b=0.7607843137254902
}
db_defaults.displayColors.wispOut = {
r=1,
g=0.07843137254901961,
b=0.9882352941176471
}
db_defaults.displayColors.BNwispIn = {
r=0,
g=0.4862745098039216,
b=0.6549019607843137,
}
db_defaults.displayColors.BNwispOut = {
r=0.1725490196078431,
g=0.6352941176470588,
b=1,
}
local Windows = windows.active.whisper;
local WhisperQueue_Bowl = {}; -- used to recycle tables for queue
local WhisperQueue = {}; -- active event queue
local WhisperQueue_Index = {}; -- a quick reference to an active index
local CF_MessageEventHandler_orig; -- used for a hook of the chat frame. Messaage filter handlers aren't sufficient.
local addToTableUnique = addToTableUnique;
local removeFromTable = removeFromTable;
local recentSent = {};
local maxRecent = 10;
local alertPushed = false;
local function updateMinimapAlerts()
local count = 0;
for _, win in pairs(Windows) do
if(not win:IsVisible()) then
count = count + (win.unreadCount or 0);
end
end
if(count == 0 and alertPushed) then
alertPushed = false;
MinimapPopAlert(L["Whispers"]);
elseif(count > 0) then
alertPushed = true;
local color = db.displayColors.wispIn;
MinimapPushAlert(L["Whispers"], RGBPercentToHex(color.r, color.g, color.b), count);
-- DisplayTutorial(L["Whisper Received!"], L["You received a whisper which was hidden due to your current activity. You can change how whispers behave in WIM's options by typing"].." |cff69ccf0/wim|r");
end
end
local CHAT_EVENTS = {
"CHAT_MSG_WHISPER",
"CHAT_MSG_WHISPER_INFORM",
"CHAT_MSG_AFK",
"CHAT_MSG_DND",
"CHAT_MSG_SYSTEM",
"CHAT_MSG_BN_WHISPER",
"CHAT_MSG_BN_WHISPER_INFORM",
"CHAT_MSG_BN_INLINE_TOAST_ALERT"
};
function WhisperEngine:OnEnableWIM()
for i = 1, #CHAT_EVENTS do
WhisperEngine:RegisterEvent(CHAT_EVENTS[i]);
end
end
function WhisperEngine:OnEnable ()
for i = 1, #CHAT_EVENTS do
_G.ChatFrame_AddMessageEventFilter(CHAT_EVENTS[i], WhisperEngine.ChatMessageEventFilter);
end
end
function WhisperEngine:OnDisable()
for i = 1, #CHAT_EVENTS do
_G.ChatFrame_RemoveMessageEventFilter(CHAT_EVENTS[i], WhisperEngine.ChatMessageEventFilter);
end
end
local function safeName(user)
return string.lower(user or "")
end
local function getWhisperWindowByUser(user, isBN, bnID, fromEvent)
if isBN then
if bnID and not string.find(user, "^|K") then
local _
_, user = GetBNGetFriendInfoByID(bnID) -- fix window handler when using the chat hyperlink
end
else
user = string.gsub(user," ","") -- Drii: WoW build15050 whisper bug for x-realm server with space
user = fromEvent and user or FormatUserName(user);
end
if(not user or user == "") then
-- if invalid user, then return nil;
return nil;
end
local obj = Windows[safeName(user)];
if(obj and obj.type == "whisper") then
-- if the whisper window exists, return the object
-- update name if from event
obj.user = user
obj.theUser = user
return obj;
else
-- otherwise, create a new one.
Windows[safeName(user)] = CreateWhisperWindow(user);
Windows[safeName(user)].isBN = isBN;
Windows[safeName(user)].bn = Windows[safeName(user)].bn or {};
if(db.whoLookups or lists.gm[safeName(user)] or Windows[safeName(user)].isBN) then
Windows[safeName(user)]:SendWho(); -- send who request
end
Windows[safeName(user)].online = true;
return Windows[safeName(user)], true;
end
end
local function windowDestroyed(self)
if(IsShiftKeyDown() or self.forceShift) then
local user = self:GetParent().theUser;
Windows[safeName(user)].online = nil;
Windows[safeName(user)].msgSent = nil;
for k in pairs(Windows[safeName(user)].bn) do
Windows[safeName(user)].bn[k] = nil;
end
Windows[safeName(user)].isBN = nil;
Windows[safeName(user)] = nil;
end
end
function WhisperEngine:OnWindowDestroyed(win)
if(win.type == "whisper") then
local user = win.theUser;
Windows[safeName(user)] = nil;
end
end
function WhisperEngine:OnWindowShow(win)
updateMinimapAlerts();
end
local splitMessage, splitMessageLinks = {}, {};
function SendSplitMessage(PRIORITY, HEADER, theMsg, CHANNEL, EXTRA, to)
-- determine isBNET
local isBN, messageLimit = false, 255;
if(Windows[safeName(to)] and Windows[safeName(to)].isBN) then
isBN = true;
messageLimit = 800;
end
-- seperate escape sequences when chained without spaces
theMsg = string.gsub(theMsg, "|r|c", "|r |c");
theMsg = string.gsub(theMsg, "|t|T", "|t |T");
theMsg = string.gsub(theMsg, "|h|H", "|h |H");
-- parse out links as to not split them incorrectly.
theMsg, results = string.gsub(theMsg, "(|H[^|]+|h.-|h|r)", function(theLink)
table.insert(splitMessageLinks, theLink);
return "\001\002"..paddString(#splitMessageLinks, "0", string.len(theLink)-4).."\003\004";
end);
-- split up each word.
SplitToTable(theMsg, "%s", splitMessage);
--reconstruct message into chunks of no more than 255 characters.
local chunk = "";
for i=1, #splitMessage + 1 do
if(splitMessage[i] and string.len(chunk) + string.len(splitMessage[i]) < messageLimit) then
chunk = chunk..splitMessage[i].." ";
else
-- reinsert links of necessary
chunk = string.gsub(chunk, "\001\002%d+\003\004", function(link)
local index = _G.tonumber(string.match(link, "(%d+)"));
return splitMessageLinks[index] or link;
end);
if(isBN) then
_G.BNSendWhisper(Windows[safeName(to)].bn.id, chunk);
else
_G.SendChatMessage(chunk, CHANNEL, EXTRA, to)
-- _G.ChatThrottleLib:SendChatMessage(PRIORITY, HEADER, chunk, CHANNEL, EXTRA, to);
end
chunk = (splitMessage[i] or "").." ";
end
end
-- clean up
for k, _ in pairs(splitMessage) do
splitMessage[k] = nil;
end
for k, _ in pairs(splitMessageLinks) do
splitMessageLinks[k] = nil;
end
end
RegisterWidgetTrigger("msg_box", "whisper", "OnEnterPressed", function(self)
local obj = self:GetParent();
local msg = PreSendFilterText(self:GetText());
local messageLength = obj.isBN and 800 or 255;
local msgCount = math.ceil(string.len(msg)/messageLength);
if(msgCount == 1) then
Windows[safeName(obj.theUser)].msgSent = true;
if(obj.isBN) then
_G.BNSendWhisper(obj.bn.id, msg);
else
_G.SendChatMessage(msg, "WHISPER", nil, obj.theUser);
-- _G.ChatThrottleLib:SendChatMessage("ALERT", "WIM", msg, "WHISPER", nil, obj.theUser);
end
elseif(msgCount > 1) then
Windows[safeName(obj.theUser)].msgSent = true;
SendSplitMessage("ALERT", "WIM", msg, "WHISPER", nil, obj.theUser);
end
self:SetText("");
end);
--------------------------------------
-- Event Handlers --
--------------------------------------
local CMS_PATTERNS = {
PLAYER_NOT_FOUND = _G.ERR_CHAT_PLAYER_NOT_FOUND_S:gsub("%%s", "(.+)"),
CHAT_IGNORED = _G.CHAT_IGNORED:gsub("%%s", "(.+)"),
FRIEND_ONLINE = _G.ERR_FRIEND_ONLINE_SS:gsub("%[", "%%["):gsub("%]", "%%]"):gsub("%%s", "(.+)"),
FRIEND_OFFLINE = _G.ERR_FRIEND_OFFLINE_S:gsub("%%s", "(.+)")
};
function WhisperEngine.ChatMessageEventFilter (frame, event, ...)
-- Process all events except for CHAT_MSG_SYSTEM
if (event ~= "CHAT_MSG_SYSTEM") then
local ignore, block = (IgnoreOrBlockEvent or function () end)(event, ...)
if (not frame._isWIM and not ignore and not block) then
-- execute appropriate supression rules
local curState = curState;
curState = db.pop_rules.whisper.alwaysOther and "other" or curState;
if(WIM.db.pop_rules.whisper[curState].supress) then
return true
end
elseif (frame._isWIM and ignore or block) then
return true
end
-- Processes CHAT_MSG_SYSTEM events
elseif (event == "CHAT_MSG_SYSTEM") then
local msg = ...;
local curState = db.pop_rules.whisper.alwaysOther and "other" or curState;
for check, pattern in pairs(CMS_PATTERNS) do
local user = FormatUserName(string.match(msg, pattern));
if (user) then
local win = Windows[safeName(user)];
if (win) then
-- error message
if 'PLAYER_NOT_FOUND' == check or 'CHAT_IGNORED' == check then
if (not frame._isWIM) then
if(win:IsShown() and db.pop_rules.whisper[curState].supress or not win.msgSent) then
return true;
end
else
if win.online then
win:AddMessage(msg, db.displayColors.errorMsg.r, db.displayColors.errorMsg.g, db.displayColors.errorMsg.b);
win.online = false;
end
end
-- system message
elseif 'FRIEND_ONLINE' == check or 'FRIEND_OFFLINE' == check then
if (not frame._isWIM) then
if(win:IsShown() and db.pop_rules.whisper[curState].supress) then
return true;
end
else
if 'FRIEND_ONLINE' == check then
msg = user.." ".._G.BN_TOAST_ONLINE
win.online = true;
else
msg = user.." ".._G.BN_TOAST_OFFLINE
win.online = false;
end
win:AddMessage(msg, db.displayColors.sysMsg.r, db.displayColors.sysMsg.g, db.displayColors.sysMsg.b);
end
end
end
-- no need to check remaining patterns
break;
end
end
end
return false, ...
end
function WhisperEngine:CHAT_MSG_WHISPER(...)
local arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17 = ...;
arg2 = _G.Ambiguate(arg2, "none")
local win, isNew = getWhisperWindowByUser(arg2, nil, nil, true);
local chatFilters = _G.ChatFrame_GetMessageEventFilters('CHAT_MSG_WHISPER');
local filter = false;
if ( chatFilters ) then
local newarg1, newarg2, newarg3, newarg4, newarg5, newarg6, newarg7, newarg8, newarg9, newarg10, newarg11, newarg12, newarg13, newarg14;
for _, filterFunc in pairs(chatFilters) do
filter, newarg1, newarg2, newarg3, newarg4, newarg5, newarg6, newarg7, newarg8, newarg9, newarg10, newarg11, newarg12, newarg13, newarg14 = filterFunc(win.widgets.chat_display, 'CHAT_MSG_WHISPER', arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14);
if ( filter ) then
if (isNew) then
win:close();
end
return true;
elseif ( newarg1 ) then
local _;
arg1, _, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14 = newarg1, newarg2, newarg3, newarg4, newarg5, newarg6, newarg7, newarg8, newarg9, newarg10, newarg11, newarg12, newarg13, newarg14;
end
end
end
local color = WIM.db.displayColors.wispIn; -- color contains .r, .g & .b
win.unreadCount = win.unreadCount and (win.unreadCount + 1) or 1;
win:AddEventMessage(color.r, color.g, color.b, "CHAT_MSG_WHISPER", arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14);
win:Pop("in");
_G.ChatEdit_SetLastTellTarget(arg2, "WHISPER");
win.online = true;
updateMinimapAlerts();
-- get missing data available from C_PlayerInfo
if (arg12 and (not win.race or win.class)) then
local class, _, race = GetPlayerInfoByGUID(arg12);
win.WhoCallback({
Name = win.theUser,
Online = true,
Guild = win.guild,
Class = class or win.class,
Level = win.level,
Race = race or win.race,
Zone = win.location
});
end
-- emulate blizzards flash client icon behavior.
if FlashClientIcon then
FlashClientIcon();
end
CallModuleFunction("PostEvent_Whisper", arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14);
end
function WhisperEngine:CHAT_MSG_WHISPER_INFORM(...)
local arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17 = ...;
arg2 = _G.Ambiguate(arg2, "none")
local win, isNew = getWhisperWindowByUser(arg2, nil, nil, true);
local chatFilters = _G.ChatFrame_GetMessageEventFilters('CHAT_MSG_WHISPER_INFORM');
local filter = false;
if ( chatFilters ) then
local newarg1, newarg2, newarg3, newarg4, newarg5, newarg6, newarg7, newarg8, newarg9, newarg10, newarg11, newarg12, newarg13, newarg14;
for _, filterFunc in pairs(chatFilters) do
filter, newarg1, newarg2, newarg3, newarg4, newarg5, newarg6, newarg7, newarg8, newarg9, newarg10, newarg11, newarg12, newarg13, newarg14 = filterFunc(win.widgets.chat_display, 'CHAT_MSG_WHISPER_INFORM', arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14);
if ( filter ) then
if (isNew) then
win:close();
end
return true;
elseif ( newarg1 ) then
local _;
arg1, _, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14 = newarg1, newarg2, newarg3, newarg4, newarg5, newarg6, newarg7, newarg8, newarg9, newarg10, newarg11, newarg12, newarg13, newarg14;
end
end
end
local color = db.displayColors.wispOut; -- color contains .r, .g & .b
win:AddEventMessage(color.r, color.g, color.b, "CHAT_MSG_WHISPER_INFORM", arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14);
win.unreadCount = 0; -- having replied to conversation implies the messages have been read.
win:Pop("out");
_G.ChatEdit_SetLastToldTarget(arg2, "WHISPER");
win.online = true;
win.msgSent = false;
updateMinimapAlerts();
CallModuleFunction("PostEvent_WhisperInform", arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14);
addToTableUnique(recentSent, arg1);
if(#recentSent > maxRecent) then
table.remove(recentSent, 1);
end
end
function WhisperEngine:CHAT_MSG_BN_WHISPER_INFORM(...)
local arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17 = ...;
local win, isNew = getWhisperWindowByUser(arg2, true, arg13, true);
if not win then return end --due to a client bug, we can not receive the other player's name, so do nothing
local chatFilters = _G.ChatFrame_GetMessageEventFilters('CHAT_MSG_BN_WHISPER_INFORM');
local filter = false;
if ( chatFilters ) then
local newarg1, newarg2, newarg3, newarg4, newarg5, newarg6, newarg7, newarg8, newarg9, newarg10, newarg11, newarg12, newarg13, newarg14;
for _, filterFunc in pairs(chatFilters) do
filter, newarg1, newarg2, newarg3, newarg4, newarg5, newarg6, newarg7, newarg8, newarg9, newarg10, newarg11, newarg12, newarg13, newarg14 = filterFunc(win.widgets.chat_display, 'CHAT_MSG_BN_WHISPER_INFORM', arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14);
if ( filter ) then
if (isNew) then
win:close();
end
return true;
elseif ( newarg1 ) then
local _;
arg1, _, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14 = newarg1, newarg2, newarg3, newarg4, newarg5, newarg6, newarg7, newarg8, newarg9, newarg10, newarg11, newarg12, newarg13, newarg14;
end
end
end
local color = db.displayColors.BNwispOut; -- color contains .r, .g & .b
if not win then return end --due to a client bug, we can not receive the other player's name, so do nothing
win:AddEventMessage(color.r, color.g, color.b, "CHAT_MSG_BN_WHISPER_INFORM", arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14);
win.unreadCount = 0; -- having replied to conversation implies the messages have been read.
win:Pop("out");
_G.ChatEdit_SetLastToldTarget(arg2, "BN_WHISPER");
win.online = true;
win.msgSent = false;
updateMinimapAlerts();
-- emulate blizzards flash client icon behavior.
if FlashClientIcon then
FlashClientIcon();
end
CallModuleFunction("PostEvent_WhisperInform", arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14);
addToTableUnique(recentSent, arg1);
if(#recentSent > maxRecent) then
table.remove(recentSent, 1);
end
end
function WhisperEngine:CHAT_MSG_BN_WHISPER(...)
local arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17 = ...;
local win, isNew = getWhisperWindowByUser(arg2, true, arg13, true);
if not win then return end --due to a client bug, we can not receive the other player's name, so do nothing
local chatFilters = _G.ChatFrame_GetMessageEventFilters('CHAT_MSG_BN_WHISPER');
local filter = false;
if ( chatFilters ) then
local newarg1, newarg2, newarg3, newarg4, newarg5, newarg6, newarg7, newarg8, newarg9, newarg10, newarg11, newarg12, newarg13, newarg14;
for _, filterFunc in pairs(chatFilters) do
filter, newarg1, newarg2, newarg3, newarg4, newarg5, newarg6, newarg7, newarg8, newarg9, newarg10, newarg11, newarg12, newarg13, newarg14 = filterFunc(win.widgets.chat_display, 'CHAT_MSG_BN_WHISPER', arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14);
if ( filter ) then
if (isNew) then
win:close();
end
return true;
elseif ( newarg1 ) then
local _;
arg1, _, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14 = newarg1, newarg2, newarg3, newarg4, newarg5, newarg6, newarg7, newarg8, newarg9, newarg10, newarg11, newarg12, newarg13, newarg14;
end
end
end
local color = WIM.db.displayColors.BNwispIn; -- color contains .r, .g & .b
win.unreadCount = win.unreadCount and (win.unreadCount + 1) or 1;
win:AddEventMessage(color.r, color.g, color.b, "CHAT_MSG_BN_WHISPER", arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14);
win:Pop("in");
_G.ChatEdit_SetLastTellTarget(arg2, "BN_WHISPER");
win.online = true;
updateMinimapAlerts();
CallModuleFunction("PostEvent_Whisper", arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14);
end
function WhisperEngine:CHAT_MSG_AFK(...)
local color = db.displayColors.wispIn; -- color contains .r, .g & .b
local win = Windows[safeName(select(2, ...))];
if(win) then
win:AddEventMessage(color.r, color.g, color.b, "CHAT_MSG_AFK", ...);
win:Pop("out");
_G.ChatEdit_SetLastTellTarget(select(2, ...), "AFK");
win.online = true;
end
end
function WhisperEngine:CHAT_MSG_DND(...)
local color = db.displayColors.wispIn; -- color contains .r, .g & .b
local win = Windows[safeName(select(2, ...))];
if(win) then
win:AddEventMessage(color.r, color.g, color.b, "CHAT_MSG_AFK", ...);
win:Pop("out");
_G.ChatEdit_SetLastTellTarget(select(2, ...), "AFK");
win.online = true;
end
end
local CMS_SLUG = {};
function WhisperEngine:CHAT_MSG_SYSTEM(...)
-- the proccessing of the actual message is taking place within the ChatMessageFilter
local chatFilters = _G.ChatFrame_GetMessageEventFilters('CHAT_MSG_SYSTEM');
if ( chatFilters ) then
for _, filterFunc in pairs(chatFilters) do
CMS_SLUG._isWIM = true;
filterFunc(CMS_SLUG, 'CHAT_MSG_SYSTEM', ...);
end
end
end
function WhisperEngine:CHAT_MSG_BN_INLINE_TOAST_ALERT(process, playerName, languageName, channelName, playerName2, specialFlags, zoneChannelID, channelIndex, channelBaseName, unused, lineID, guid, bnSenderID, isMobile, isSubtitle, hideSenderInLetterbox, supressRaidIcons)
local online = process == "FRIEND_ONLINE"
local offline = process == "FRIEND_OFFLINE"
local curState = db.pop_rules.whisper.alwaysOther and "other" or curState;
local _, accName = GetBNGetFriendInfoByID(bnSenderID)
local win = Windows[safeName(accName)]
if win then
local msg = accName.." "..(online and _G.BN_TOAST_ONLINE or offline and _G.BN_TOAST_OFFLINE or "")
win:AddMessage(msg, db.displayColors.sysMsg.r, db.displayColors.sysMsg.g, db.displayColors.sysMsg.b);
win.online = online;
return;
end
end
--------------------------------------
-- Whisper Related Hooks --
--------------------------------------
local function replyTellTarget(TellNotTold)
if (db.enabled) then
local curState = curState;
curState = db.pop_rules.whisper.alwaysOther and "other" or curState;
local lastTell;
if (TellNotTold) then
lastTell = _G.ChatEdit_GetLastTellTarget();
else
lastTell = _G.ChatEdit_GetLastToldTarget();
end
-- Grab the string after the slash command
if not lastTell then return end--because if you fat finger R or try to re ply before someone sent a tell, it generates a lua error without this
local bNetID;
if (lastTell:find("^|K")) then
lastTell = _G.BNTokenFindName(lastTell) or lastTell;
bNetID = _G.BNet_GetBNetIDAccount(lastTell);
end
if (lastTell ~= "" and db.pop_rules.whisper.intercept) then
lastTell = _G.Ambiguate(lastTell, "none")
local win = getWhisperWindowByUser(lastTell, bNetID and true, bNetID);
if (win:IsVisible() or db.pop_rules.whisper[curState].onSend) then
win.widgets.msg_box.setText = 1;
win:Pop(true); -- force popup
win.widgets.msg_box:SetFocus();
local eb = getVisibleChatFrameEditBox();
_G.ChatEdit_OnEscapePressed(getVisibleChatFrameEditBox() or _G.ChatFrame1EditBox);
end
end
end
end
-- "/w |Kf287|k0000000000000|k "
local tellTargetExtractionAutoComplete = _G.AUTOCOMPLETE_LIST.ALL;
function CF_ExtractTellTarget(editBox, msg, chatType)
-- Grab the string after the slash command
local target = string.match(msg, "%s*(.*)");
local bNetID;
--_G.DEFAULT_CHAT_FRAME:AddMessage("Raw: "..msg:gsub("|", ":")); -- debugging
if (target:find("^|K")) then
local old_target, old_msg = target, msg
target, msg = _G.BNTokenFindName(target)
target = target or old_target
msg = msg or old_msg
bNetID = _G.BNet_GetBNetIDAccount(target);
else
--If we haven't even finished one word, we aren't done.
if (not target or not string.find(target, "%s") or (string.sub(target, 1, 1) == "|")) then
return false;
end
--[[if (_G.GetAutoCompleteResults(target, tellTargetExtractionAutoComplete.include,
tellTargetExtractionAutoComplete.exclude, 1, nil, true)) then
--Even if there's a space, we still want to let the person keep typing -- they may be trying to type whatever
-- -- is in AutoComplete.
return false;
end--]]
--Keep pulling off everything after the last space until we either have something on the AutoComplete list or
-- -- only a single word is left.
while (string.find(target, "%s")) do
--Pull off everything after the last space.
target = string.match(target, "(%S+)%s+[^%s]*");
target = _G.Ambiguate(target, "none")
if (_G.GetAutoCompleteResults(target, 1, 0, tellTargetExtractionAutoComplete.include,
tellTargetExtractionAutoComplete.exclude, 1, nil, true)) then
break;
end
end
msg = string.sub(msg, string.len(target) + 2);
end
if (db and db.enabled) then
local curState = curState;
curState = db.pop_rules.whisper.alwaysOther and "other" or curState;
if (db.pop_rules.whisper.intercept and db.pop_rules.whisper[curState].onSend) then
target = _G.Ambiguate(target, "none")--For good measure, ambiguate again cause it seems some mods interfere with this process
local win = getWhisperWindowByUser(target, bNetID and true, bNetID);
if not win then return end --due to a client bug, we can not receive the other player's name, so do nothing
win.widgets.msg_box.setText = 1;
win:Pop(true); -- force popup
win.widgets.msg_box:SetFocus();
_G.ChatEdit_OnEscapePressed(editBox);
end
end
end
function CF_SentBNetTell(target)
if (db and db.enabled) then
local curState = curState;
curState = db.pop_rules.whisper.alwaysOther and "other" or curState;
if (db.pop_rules.whisper.intercept and db.pop_rules.whisper[curState].onSend) then
local bNetID = _G.BNet_GetBNetIDAccount(target);
target = _G.Ambiguate(target, "none")--For good measure, ambiguate again cause it seems some mods interfere with this process
local win = getWhisperWindowByUser(target, true, bNetID);
if not win then return end --due to a client bug, we can not receive the other player's name, so do nothing
win.widgets.msg_box.setText = 1;
win:Pop(true); -- force popup
win.widgets.msg_box:SetFocus();
local editBox = _G.ChatEdit_ChooseBoxForSend()
_G.ChatEdit_OnEscapePressed(editBox);
end
end
end
function CF_OpenChat(text, chatFrame, desiredCursorPosition)
local editBox = _G.ChatEdit_ChooseBoxForSend(chatFrame)
local chatType = editBox:GetAttribute("chatType")
local target = editBox:GetAttribute("tellTarget")
local sticky = editBox:GetAttribute("stickyType")
if chatType == "WHISPER" then
if not string.find(target, "^|K") then
return
end
elseif chatType ~= "BN_WHISPER" or not target then
return
end
if not editBox:IsVisible() then return end
if (db and db.enabled) then
local curState = curState;
curState = db.pop_rules.whisper.alwaysOther and "other" or curState;
if (db.pop_rules.whisper.intercept and db.pop_rules.whisper[curState].onSend) then
local bNetID = _G.BNet_GetBNetIDAccount(target);
target = _G.Ambiguate(target, "none")--For good measure, ambiguate again cause it seems some mods interfere with this process
local win = getWhisperWindowByUser(target, bNetID and true, bNetID);
if not win then return end --due to a client bug, we can not receive the other player's name, so do nothing
win.widgets.msg_box.setText = 1;
win:Pop(true); -- force popup
if not (sticky == "WHISPER" or sticky == "BN_WHISPER") then
win.widgets.msg_box:SetFocus();
_G.ChatEdit_OnEscapePressed(editBox);
end
end
end
end
-- the following hook is needed in order to intercept /r
hooksecurefunc("ChatEdit_ExtractTellTarget", CF_ExtractTellTarget);
hooksecurefunc("ChatFrame_OpenChat", CF_OpenChat);
hooksecurefunc("ChatFrame_SendBNetTell", CF_SentBNetTell);
--Hook ChatFrame_ReplyTell & ChatFrame_ReplyTell2
hooksecurefunc("ChatFrame_ReplyTell", function() replyTellTarget(true) end);
hooksecurefunc("ChatFrame_ReplyTell2", function() replyTellTarget(false) end);
local hookedSendChatMessage = _G.SendChatMessage;
function _G.SendChatMessage(...)
if(select(2, ...) == "WHISPER") then
local win = Windows[safeName(FormatUserName(select(4, ...))) or "NIL"];
if(win) then
win.msgSent = true;
end
end
hookedSendChatMessage(...);
end
-- global reference
GetWhisperWindowByUser = getWhisperWindowByUser;
-- define context menu
local info = {};
info.text = "MENU_MSGBOX";
local msgBoxMenu = AddContextMenu(info.text, info);
info = {};
info.text = WIM.L["Recently Sent Messages"];
info.notCheckable = true;
msgBoxMenu:AddSubItem(AddContextMenu("RECENT_LIST", info), 1);
local recentMenu = GetContextMenu("RECENT_LIST");
if(recentMenu.menuTable) then
for k, _ in pairs(recentMenu.menuTable) do
recentMenu.menuTable[k] = nil;
end
end
for i=1, maxRecent do
info = GetContextMenu("RECENT_LIST"..i) or {};
info.txt = " ";
info.hidden = true;
info.notCheckable = true;
recentMenu:AddSubItem(AddContextMenu("RECENT_LIST"..i, info));
end
local function recentMenuClick(self)
libs.DropDownMenu.CloseDropDownMenus();
if(MSG_CONTEXT_MENU_EDITBOX) then
if(_G.IsShiftKeyDown()) then
MSG_CONTEXT_MENU_EDITBOX:Insert(self.value);
else
MSG_CONTEXT_MENU_EDITBOX:SetText(self.value);
end
end
end
RegisterWidgetTrigger("msg_box", "whisper,chat,w2w", "OnMouseDown", function(self)
if(#recentSent == 0) then
local item = GetContextMenu("RECENT_LIST1");
item.text = "|cff808080 - "..L["None"].." - |r";
item.notClickable = true;
item.hidden = nil;
return;
end
for i=maxRecent, 1, -1 do
local item = GetContextMenu("RECENT_LIST"..(10-i+1));
item.notClickable = nil;
if(recentSent[i]) then
item.text = recentSent[i];
item.value = recentSent[i];
item.func = recentMenuClick;
item.hidden = nil;
else
item.hidden = true;
end
end
end);
-- This is a core module and must always be loaded...
WhisperEngine.canDisable = false;
WhisperEngine:Enable();