--imports
local WIM = WIM ;
local _G = _G ;
local table = table ;
local string = string ;
local pairs = pairs ;
local CreateFrame = CreateFrame ;
local date = date ;
local time = time ;
local select = select ;
local tonumber = tonumber ;
local DDM = WIM.libs . DropDownMenu ;
--set namespace
setfenv ( 1 , WIM ) ;
local History = CreateModule ( " History " , true ) ;
-- default history settings.
db_defaults.history = {
preview = true ,
previewCount = 25 ,
maxPer = true ,
maxCount = 500 ,
ageLimit = true ,
maxAge = 60 * 60 * 24 * 7 * 2 ,
whispers = {
friends = true ,
guild = true ,
all = true
} ,
chat = {
preview = true ,
previewCount = 25 ,
maxPer = true ,
maxCount = 500 ,
ageLimit = true ,
maxAge = 60 * 60 * 24 * 7 * 2 ,
}
} ;
db_defaults.displayColors . historyIn = {
r = 0.4705882352941176 ,
g = 0.4705882352941176 ,
b = 0.4705882352941176
} ;
db_defaults.displayColors . historyOut = {
r = 0.7058823529411764 ,
g = 0.7058823529411764 ,
b = 0.7058823529411764
} ;
local dDay = 60 * 60 * 24 ;
local dWeek = dDay * 7 ;
local dMonth = dWeek * 4 ;
local dYear = dMonth * 12 ;
local tmpTable = { } ;
local ViewTypes = { } ;
local ChannelCache = { } ;
local CensoredCache = { } ;
local function clearTmpTable ( )
for key , _ in pairs ( tmpTable ) do
tmpTable [ key ] = nil ;
end
end
local function isEmptyTable ( tbl )
for k , _ in pairs ( tbl ) do
if ( k ~= " info " ) then
return false ;
end
end
return true ;
end
local function getPlayerHistoryTable ( convoName )
if ( history [ env.realm ] and history [ env.realm ] [ env.character ] and history [ env.realm ] [ env.character ] [ convoName ] ) then
return history [ env.realm ] [ env.character ] [ convoName ] ;
else
-- this player hasn't been set up yet. Do it now.
history [ env.realm ] = history [ env.realm ] or { } ;
history [ env.realm ] [ env.character ] = history [ env.realm ] [ env.character ] or { } ;
history [ env.realm ] [ env.character ] [ convoName ] = history [ env.realm ] [ env.character ] [ convoName ] or { info = { } } ;
return history [ env.realm ] [ env.character ] [ convoName ] ;
end
end
local function createWidget ( )
local button = _G.CreateFrame ( " Button " ) ;
button.SetHistory = function ( self , isHistory )
self.parentWindow . isHistory = isHistory ;
if ( isHistory and modules.History . enabled ) then
self : SetAlpha ( 1 ) ;
-- DisplayTutorial(L["WIM History Button"], _G.format(L["Clicking the %s button on the message window will show that user's history in WIM's History Viewer."],
-- "|T"..GetSelectedSkin().message_window.widgets.history.NormalTexture..":0:0:0:0|t"));
else
self : SetAlpha ( 0 ) ;
end
end
button.UpdateProps = function ( self )
self : SetHistory ( self.parentWindow . isHistory ) ;
end
button : SetScript ( " OnEnter " , function ( self )
if ( db.showToolTips == true and self.parentWindow . isHistory ) then
_G.GameTooltip : SetOwner ( self , " ANCHOR_TOPRIGHT " ) ;
_G.GameTooltip : SetText ( L [ " Click to view message history. " ] ) ;
end
end ) ;
button : SetScript ( " OnLeave " , function ( self )
_G.GameTooltip : Hide ( ) ;
end ) ;
button : SetScript ( " OnClick " , function ( self , button )
if ( self.parentWindow . isHistory ) then
ShowHistoryViewer ( self.parentWindow . theUser ) ;
end
end ) ;
return button ;
end
-- store a cached entry if a record is cached. This will be used by History:ReplaceCensoredMessage if original message is shown.
local function cacheIfCensored ( record , ... )
local arg1 , arg2 , arg3 , arg4 , arg5 , arg6 , arg7 , arg8 , arg9 , arg10 , arg11 , arg12 , arg13 , arg14 , arg15 , arg16 , arg17 = ... ;
local lineID = arg11 ;
local isChatLineCensored = _G.C_ChatInfo and _G.C_ChatInfo . IsChatLineCensored and _G.C_ChatInfo . IsChatLineCensored ( lineID ) ;
if ( isChatLineCensored ) then
CensoredCache [ lineID ] = record ;
record.censored = true ;
-- filter out Show Message link
record.msg = record.msg : gsub ( ' |Hcensoredmessage:[^|]+|h.-|h ' , ' ' ) ;
end
return record ;
end
-- replace a history record by lineID. Returns true is msg is updated.
function History : ReplaceCensoredMessage ( lineID , msg )
if ( lineID and msg and CensoredCache [ lineID ] ) then
-- filter out report link
msg = msg : gsub ( ' |Hreportcensoredmessage:[^|]+|h.-|h ' , ' ' ) ;
if CensoredCache [ lineID ] . msg ~= msg then
CensoredCache [ lineID ] . msg = msg ;
return true
end
end
return false ;
end
local function safeName ( user )
return string.lower ( user or " " )
end
--BNet_GetValidatedCharacterName
local function recordWhisper ( inbound , ... )
local msg , from = ... ;
if not from then
return
end
local db = db.history . whispers ;
local win = windows.active . whisper [ safeName ( from ) ] or windows.active . chat [ from ] or windows.active . w2w [ safeName ( from ) ] ;
if ( win and ( lists.gm [ from ] or db.all or ( db.friends and ( lists.friends [ from ] or win.isBN ) ) or ( db.guild and lists.guild [ from ] ) ) ) then
win.widgets . history : SetHistory ( true ) ;
--If realid/btag whisper, we save them under btag to avoid caching issues
--(ie NAME is encoded and changes every session, we can't use that to save whispers, plus if user dumps cache, they all return unknown)
local pid = _G.BNet_GetBNetIDAccount ( from )
if pid then
local _ , _ , btag , _ , toonName = GetBNGetFriendInfoByID ( pid )
from = btag or toonName or from
end
local history = getPlayerHistoryTable ( from ) ;
history.info . gm = lists.gm [ from ] ;
table.insert ( history , cacheIfCensored ( {
convo = from ,
type = 1 , -- whisper
inbound = inbound or false ,
from = inbound and from or env.character ,
msg = msg ,
time = _G.time ( ) ;
} , ... ) ) ;
if ( WIM.db . history.maxPer ) then
while ( WIM.db . history.maxCount < # history ) do
table.remove ( history , 1 ) ;
end
end
end
end
function History : PostEvent_Whisper ( ... )
recordWhisper ( true , ... ) ;
end
function History : PostEvent_WhisperInform ( ... )
recordWhisper ( false , ... ) ;
end
local function deleteOldHistory ( isChat )
local historyDB = isChat and db.history . chat or db.history ;
local count = 0 ;
for realm , characters in pairs ( history ) do
for character , convos in pairs ( characters ) do
for convo , messages in pairs ( convos ) do
for i =# messages , 1 , - 1 do
if ( ( time ( ) - messages [ i ] . time ) > historyDB.maxAge and ( ( isChat and messages [ i ] . type == 2 ) or ( not isChat and messages [ i ] . type == 1 ) ) ) then
dPrint ( " Deleting History. " .. realm .. " . " .. character .. " . " .. convo .. " [ " .. i .. " ] " ) ;
table.remove ( messages , i ) ;
count = count + 1 ;
end
end
if ( isEmptyTable ( messages ) ) then convos [ convo ] = nil ; end
end
if ( isEmptyTable ( convos ) ) then characters [ character ] = nil ; end
end
if ( isEmptyTable ( characters ) ) then history [ realm ] = nil ; end
end
if ( count > 0 ) then
_G.DEFAULT_CHAT_FRAME : AddMessage ( _G.format ( L [ " WIM pruned %d |4message:messages; from your history. " ] , count ) ) ;
end
end
function History : OnEnableWIM ( )
-- clean up history if asked to.
if ( db.history . ageLimit ) then
deleteOldHistory ( ) ;
end
end
function History : OnEnable ( )
RegisterWidget ( " history " , createWidget ) ;
for widget in Widgets ( " history " ) do
local win = widget.parentWindow ;
if ( win ) then
local history = history [ env.realm ] and history [ env.realm ] [ env.character ] and history [ env.realm ] [ env.character ] [ win.theUser ] and win.type == " whisper " ;
if ( history ) then
widget : SetHistory ( true ) ;
end
end
end
end
function History : OnDisable ( )
if ( db.modules . History.enabled ) then
return ;
end
for widget in Widgets ( " history " ) do
if ( widget.parentWindow . type == " whisper " ) then
widget : SetHistory ( false ) ; -- module is disabled, hide Icons.
end
end
end
function History : OnWindowDestroyed ( win )
win.isHistory = nil ;
end
function History : OnWindowCreated ( win )
if ( db.history . preview ) then
local history = history [ env.realm ] and history [ env.realm ] [ env.character ] and history [ env.realm ] [ env.character ] [ win.theUser ] ;
if ( history ) then
local type = win.type == " whisper " and 1 ;
for i =# history , 1 , - 1 do
table.insert ( tmpTable , 1 , history [ i ] ) ;
if ( # tmpTable >= db.history . previewCount ) then
break ;
end
end
if ( # tmpTable > 0 ) then
win.isHistory = true ;
win.widgets . history : SetHistory ( true ) ;
for i = 1 , # tmpTable do
local color = db.displayColors [ tmpTable [ i ] . inbound and " historyIn " or " historyOut " ] ;
win.nextStamp = tmpTable [ i ] . time ;
win.nextStampColor = db.displayColors . historyOut ;
win : AddMessage ( applyMessageFormatting ( win.widgets . chat_display , " CHAT_MSG_WHISPER " , tmpTable [ i ] . msg , tmpTable [ i ] . from ,
nil , nil , nil , nil , nil , nil , nil , nil , - i , " 0x0300000000000000 " ) , color.r , color.g , color.b ) ;
end
win.widgets . chat_display : AddMessage ( " " ) ;
end
clearTmpTable ( ) ;
end
end
end
--Chat History
local ChatHistory = CreateModule ( " HistoryChat " ) ;
-- synonymous functions
ChatHistory.OnWindowDestroyed = History.OnWindowDestroyed ;
function ChatHistory : OnEnableWIM ( )
-- clean up history if asked to.
if ( db.history . chat.ageLimit ) then
deleteOldHistory ( true ) ;
end
end
function ChatHistory : OnEnable ( )
RegisterWidget ( " history " , createWidget ) ;
for widget in Widgets ( " history " ) do
local win = widget.parentWindow ;
if ( win ) then
local chatName = win.theUser
local history = history [ env.realm ] and history [ env.realm ] [ env.character ] and history [ env.realm ] [ env.character ] [ chatName ] and win.type == " chat " ;
if ( history ) then
widget : SetHistory ( true ) ;
end
end
end
end
function ChatHistory : OnDisable ( )
if ( modules.HistoryChat . enabled ) then
return ;
end
for widget in Widgets ( " history " ) do
if ( widget.parentWindow . type == " chat " ) then
widget : SetHistory ( false ) ; -- module is disabled, hide Icons.
end
end
end
local function recordChannelChat ( recordAs , ChannelType , ... )
local msg , from = ... ;
local db = db.history . whispers ;
local win = windows.active . chat [ recordAs ] ;
if ( win ) then
win.widgets . history : SetHistory ( true ) ;
local history = getPlayerHistoryTable ( recordAs ) ;
history.info . chat = true ;
history.info . channelNumber = channelNumber ;
table.insert ( history , cacheIfCensored ( {
event = ChannelType ,
channelName = recordAs ,
type = 2 , -- chat
from = from ,
msg = msg ,
time = _G.time ( ) ;
} , ... ) ) ;
if ( WIM.db . history.chat . maxPer ) then
while ( WIM.db . history.chat . maxCount < # history ) do
table.remove ( history , 1 ) ;
end
end
end
end
function ChatHistory : PostEvent_ChatMessage ( event , ... )
local arg1 , arg2 , arg3 , arg4 , arg5 , arg6 , arg7 , arg8 , arg9 , arg10 , arg11 = ... ;
event = event : gsub ( " CHAT_MSG_ " , " " ) ;
if ( event == " CHANNEL " ) then
local recordAs ;
local isWorld = arg7 and arg7 > 0 ;
local chatType = isWorld and " world " or " custom " ;
local channelName = string.split ( " - " , arg9 ) ;
local channelNumber = arg8 ;
recordAs = channelName ;
if ( recordAs and ( ( isWorld and db.history . chat.world ) or ( not isWorld and db.history . chat.custom ) ) ) then
local noHistory = db.chat [ isWorld and " world " or " custom " ] . channelSettings [ channelName ] and db.chat [ isWorld and " world " or " custom " ] . channelSettings [ channelName ] . noHistory ;
if ( not noHistory ) then
recordChannelChat ( recordAs , event , ... ) ;
end
end
else
local recordAs ;
local chatType ;
if ( event == " GUILD " and db.history . chat.guild ) then
recordAs = _G.GUILD ;
chatType = " guild " ;
elseif ( event == " OFFICER " and db.history . chat.officer ) then
recordAs = _G.GUILD_RANK1_DESC ;
chatType = " officer " ;
elseif ( ( event == " PARTY " or event == " PARTY_LEADER " ) and db.history . chat.party ) then
recordAs = _G.PARTY ;
chatType = " party " ;
elseif ( ( event == " RAID " or event == " RAID_LEADER " ) and db.history . chat.raid ) then
recordAs = _G.RAID ;
chatType = " raid " ;
elseif ( ( event == " INSTANCE_CHAT " or event == " INSTANCE_CHAT_LEADER " ) and db.history . chat.battleground ) then
recordAs = _G.INSTANCE_CHAT ;
chatType = " battleground " ;
elseif ( event == " SAY " and db.history . chat.say ) then
recordAs = _G.SAY ;
chatType = " say " ;
end
if ( recordAs ) then
recordChannelChat ( recordAs , event , ... ) ;
end
end
end
--------------------------------------
-- History Viewer --
--------------------------------------
local function searchResult ( msg , search )
search = string.lower ( string.trim ( search ) ) ;
msg = string.lower ( msg ) ;
local start , stop , match = string.find ( search , " ([^%s]+) " , 1 ) ;
while ( match ) do
if ( not string.find ( msg , match ) ) then
return false ;
end
start , stop , match = string.find ( search , " ([^%s]+) " , stop + 1 ) ;
end
return true ;
end
local function createHistoryViewer ( )
-- Changes for Patch 9.0.1 - Shadowlands, retail and classic
local win = CreateFrame ( " Frame " , " WIM3_HistoryFrame " , _G.UIParent , " BackdropTemplate " ) ;
win : Hide ( ) ;
win.filter = { } ;
-- set size and position
win : SetWidth ( 700 ) ;
win : SetHeight ( 505 ) ;
win : SetPoint ( " CENTER " ) ;
-- set backdrop - changes for Patch 9.0.1 - Shadowlands
win.backdropInfo = { bgFile = " Interface \\ AddOns \\ " .. addonTocName .. " \\ Sources \\ Options \\ Textures \\ Frame_Background " ,
edgeFile = " Interface \\ AddOns \\ " .. addonTocName .. " \\ Sources \\ Options \\ Textures \\ Frame " ,
tile = true , tileSize = 64 , edgeSize = 64 ,
insets = { left = 64 , right = 64 , top = 64 , bottom = 64 } } ;
win : ApplyBackdrop ( ) ;
-- set basic frame properties
win : SetClampedToScreen ( true ) ;
win : SetFrameStrata ( " DIALOG " ) ;
win : SetMovable ( true ) ;
win : SetToplevel ( true ) ;
win : EnableMouse ( true ) ;
win : RegisterForDrag ( " LeftButton " ) ;
if win.SetResizeBounds then -- WoW 10.0
win : SetResizeBounds ( 240 , 240 )
else
win : SetMinResize ( 600 , 400 ) ;
end
-- set script events
win : SetScript ( " OnDragStart " , function ( self ) self : StartMoving ( ) ; end ) ;
win : SetScript ( " OnDragStop " , function ( self ) self : StopMovingOrSizing ( ) ; end ) ;
-- create and set title bar text
win.title = win : CreateFontString ( win : GetName ( ) .. " Title " , " OVERLAY " , " ChatFontNormal " ) ;
win.title : SetPoint ( " TOPLEFT " , 50 , - 20 ) ;
local font = win.title : GetFont ( ) ;
win.title : SetFont ( font , 16 , " " ) ;
win.title : SetText ( L [ " History Viewer " ] )
-- create close button
win.close = CreateFrame ( " Button " , win : GetName ( ) .. " Close " , win ) ;
win.close : SetWidth ( 18 ) ; win.close : SetHeight ( 18 ) ;
win.close : SetPoint ( " TOPRIGHT " , - 24 , - 20 ) ;
win.close : SetNormalTexture ( " Interface \\ AddOns \\ " .. addonTocName .. " \\ Sources \\ Options \\ Textures \\ blipRed " ) ;
win.close : SetHighlightTexture ( " Interface \\ AddOns \\ " .. addonTocName .. " \\ Sources \\ Options \\ Textures \\ close " , " BLEND " ) ;
win.close : SetScript ( " OnClick " , function ( self )
self : GetParent ( ) : Hide ( ) ;
end ) ;
-- window actions
win : SetScript ( " OnShow " , function ( self )
_G.PlaySound ( 850 ) ;
self.UpdateUserList ( ) ;
end ) ;
win : SetScript ( " OnHide " , function ( self ) _G.PlaySound ( 851 ) ; end ) ;
table.insert ( _G.UISpecialFrames , win : GetName ( ) ) ;
-- create nav
win.nav = CreateFrame ( " Frame " , nil , win ) ;
win.nav . border = win.nav : CreateTexture ( nil , " BACKGROUND " ) ;
win.nav . border : SetColorTexture ( 1 , 1 , 1 , .25 ) ;
win.nav . border : SetPoint ( " TOPRIGHT " ) ;
win.nav . border : SetPoint ( " BOTTOMRIGHT " ) ;
win.nav . border : SetWidth ( 2 ) ;
win.nav : SetPoint ( " TOPLEFT " , 18 , - 47 ) ;
win.nav : SetPoint ( " BOTTOMLEFT " , 18 , 18 ) ;
win.nav : SetWidth ( 200 ) ;
win.nav . user = DDM.Create_DropDownMenu ( " WIM3_HistoryUserMenu " , win.nav )
win.nav . user : SetParent ( win.nav )
win.nav . user : SetPoint ( " TOPLEFT " , - 15 , 0 ) ;
DDM.UIDropDownMenu_SetWidth ( win.nav . user , win.nav : GetWidth ( ) - 25 ) ;
win.nav . user.list = { } ;
win.nav . user.getUserList = function ( self )
for key , _ in pairs ( self.list ) do
self.list [ key ] = nil ;
end
local thisToon = env.realm .. " / " .. env.character ;
for realm , users in pairs ( history ) do
table.insert ( self.list , realm ) ;
for user , _ in pairs ( users ) do
if ( thisToon == realm .. " / " .. user ) then
thisToon = nil ;
end
table.insert ( self.list , realm .. " / " .. user ) ;
end
end
if ( thisToon ) then
table.insert ( self.list , 1 , thisToon ) ;
end
table.sort ( self.list ) ;
return self.list ;
end
win.nav . user.init = function ( )
local self = win.nav . user ;
local list = self : getUserList ( ) ;
for i = 1 , # list do
local info = { } ;
info.text = list [ i ] ;
info.value = list [ i ] ;
info.func = function ( self )
self = self or _G.this ;
win.USER = self.value ;
win.CONVO = " " ;
win.FILTER = " " ;
win.UpdateUserList ( ) ;
DDM.UIDropDownMenu_SetSelectedValue ( win.nav . user , self.value ) ;
end ;
DDM.UIDropDownMenu_AddButton ( info , DDM.UIDropDownMenu_MENU_LEVEL ) ;
end
end
win.nav . user : SetScript ( " OnShow " , function ( self )
DDM.UIDropDownMenu_Initialize ( self , self.init ) ;
DDM.UIDropDownMenu_SetSelectedValue ( self , win.USER ) ;
end ) ;
win.nav . filters = CreateFrame ( " Frame " , nil , win.nav ) ;
win.nav . filters : SetPoint ( " BOTTOMLEFT " ) ;
win.nav . filters : SetPoint ( " BOTTOMRIGHT " , - 2 , 0 ) ;
win.nav . filters : SetHeight ( 125 ) ;
win.nav . filters.border = win.nav . filters : CreateTexture ( nil , " BACKGROUND " ) ;
win.nav . filters.border : SetColorTexture ( 1 , 1 , 1 , .25 ) ;
win.nav . filters.border : SetPoint ( " TOPLEFT " ) ;
win.nav . filters.border : SetPoint ( " TOPRIGHT " ) ;
win.nav . filters.border : SetHeight ( 20 ) ;
win.nav . filters.text = win.nav . filters : CreateFontString ( nil , " OVERLAY " , " ChatFontNormal " ) ;
win.nav . filters.text : SetPoint ( " TOPLEFT " , win.nav . filters.border ) ;
win.nav . filters.text : SetPoint ( " BOTTOMRIGHT " , win.nav . filters.border ) ;
win.nav . filters.text : SetText ( L [ " Filters " ] ) ;
win.nav . filters.text : SetTextColor ( _G.GameFontNormal : GetTextColor ( ) ) ;
win.nav . filters.scroll = CreateFrame ( " ScrollFrame " , " WIM3_HistoryFilterListScroll " , win.nav . filters , " FauxScrollFrameTemplate " ) ;
win.nav . filters.scroll : SetPoint ( " TOPLEFT " , 0 , - 22 ) ;
win.nav . filters.scroll : SetPoint ( " BOTTOMRIGHT " , - 23 , 0 ) ;
win.nav . filters.scroll . buttons = { } ;
win.nav . filters.scroll . createButton = function ( )
local button = CreateFrame ( " Button " , nil , win.nav . filters ) ;
if ( # win.nav . filters.scroll . buttons > 0 ) then
button : SetPoint ( " TOPLEFT " , win.nav . filters.scroll . buttons [ # win.nav . filters.scroll . buttons ] , " BOTTOMLEFT " ) ;
button : SetPoint ( " TOPRIGHT " , win.nav . filters.scroll . buttons [ # win.nav . filters.scroll . buttons ] , " BOTTOMRIGHT " ) ;
else
button : SetPoint ( " TOPLEFT " , win.nav . filters.scroll ) ;
button : SetPoint ( " TOPRIGHT " , win.nav . filters.scroll ) ;
end
button : SetHeight ( 20 ) ;
button : SetHighlightTexture ( " Interface \\ QuestFrame \\ UI-QuestLogTitleHighlight " , " ADD " ) ;
button : GetHighlightTexture ( ) : SetVertexColor ( .196 , .388 , .5 ) ;
button.text = button : CreateFontString ( nil , " OVERLAY " , " ChatFontNormal " ) ;
button.text : SetAllPoints ( ) ;
button.text : SetJustifyH ( " LEFT " ) ;
button.SetFilter = function ( self , filter )
self.filter = filter ;
if ( _G.type ( filter ) == " number " ) then
self.text : SetText ( " " .. date ( L [ " _DateFormat " ] , filter ) ) ;
else
self.filter = " " ;
self.text : SetText ( " " .. filter ) ;
end
end
button : SetScript ( " OnClick " , function ( self )
win.FILTER = self.filter ;
win.nav . filters.scroll . update ( ) ;
win.UpdateDisplay ( ) ;
end ) ;
table.insert ( win.nav . filters.scroll . buttons , button ) ;
return button ;
end
for i = 1 , 5 do
win.nav . filters.scroll . createButton ( ) ;
end
win.nav . filters.scroll . update = function ( )
local self = win.nav . filters.scroll ;
local offset = _G.FauxScrollFrame_GetOffset ( self ) ;
for i = 1 , # self.buttons do
local index = i + offset ;
if ( index <= # win.FILTERLIST ) then
self.buttons [ i ] : SetFilter ( win.FILTERLIST [ index ] ) ;
self.buttons [ i ] : Show ( ) ;
if ( self.buttons [ i ] . filter == win.FILTER ) then
self.buttons [ i ] : LockHighlight ( ) ;
else
self.buttons [ i ] : UnlockHighlight ( ) ;
end
else
self.buttons [ i ] : Hide ( ) ;
end
end
_G.FauxScrollFrame_Update ( self , # win.FILTERLIST , 5 , 20 ) ;
end
win.nav . filters.scroll : SetScript ( " OnShow " , function ( self )
self : update ( ) ;
end ) ;
win.nav . filters.scroll : SetScript ( " OnVerticalScroll " , function ( self , offset )
_G.FauxScrollFrame_OnVerticalScroll ( self , offset , 20 , win.nav . filters.scroll . update ) ;
end ) ;
win.nav . userList = CreateFrame ( " Frame " , nil , win.nav ) ;
win.nav . userList : SetPoint ( " BOTTOMLEFT " , win.nav . filters , " TOPLEFT " , 0 , 1 ) ;
win.nav . userList : SetPoint ( " BOTTOMRIGHT " , win.nav . filters , " TOPRIGHT " , 0 , 1 ) ;
win.nav . userList : SetPoint ( " TOP " , 0 , - 30 ) ;
win.nav . userList.border = win.nav . userList : CreateTexture ( nil , " BACKGROUND " ) ;
win.nav . userList.border : SetColorTexture ( 1 , 1 , 1 , .25 ) ;
win.nav . userList.border : SetPoint ( " TOPLEFT " , 0 , 1 ) ;
win.nav . userList.border : SetPoint ( " TOPRIGHT " , 0 , 1 ) ;
win.nav . userList.border : SetHeight ( 1 ) ;
win.nav . userList.scroll = CreateFrame ( " ScrollFrame " , " WIM3_HistoryUserListScroll " , win.nav . userList , " FauxScrollFrameTemplate " ) ;
win.nav . userList.scroll : SetPoint ( " TOPLEFT " , 0 , - 2 ) ;
win.nav . userList.scroll : SetPoint ( " BOTTOMRIGHT " , - 23 , 0 ) ;
win.nav . userList.scroll . buttons = { } ;
win.nav . userList.scroll . createButton = function ( )
local button = CreateFrame ( " Button " , nil , win.nav . userList ) ;
if ( # win.nav . userList.scroll . buttons > 0 ) then
button : SetPoint ( " TOPLEFT " , win.nav . userList.scroll . buttons [ # win.nav . userList.scroll . buttons ] , " BOTTOMLEFT " ) ;
button : SetPoint ( " TOPRIGHT " , win.nav . userList.scroll . buttons [ # win.nav . userList.scroll . buttons ] , " BOTTOMRIGHT " ) ;
else
button : SetPoint ( " TOPLEFT " , win.nav . userList.scroll ) ;
button : SetPoint ( " TOPRIGHT " , win.nav . userList.scroll ) ;
end
button : SetHeight ( 20 ) ;
button : SetHighlightTexture ( " Interface \\ QuestFrame \\ UI-QuestLogTitleHighlight " , " ADD " ) ;
button : GetHighlightTexture ( ) : SetVertexColor ( .196 , .388 , .5 ) ;
button.text = button : CreateFontString ( nil , " OVERLAY " , " ChatFontNormal " ) ;
button.text : SetPoint ( " TOPLEFT " ) ;
button.text : SetPoint ( " BOTTOMRIGHT " , - 18 , 0 ) ;
button.text : SetJustifyH ( " LEFT " ) ;
button.SetUser = function ( self , user )
local original , extra , color = user , " " ;
local gmTag
user , gmTag = string.match ( original , " ([^*]+)(*?)$ " ) ;
color = gmTag == " * " and constants.classes [ L [ " Game Master " ] ] . color or " ffffff " ;
if ( string.match ( original , " ^* " ) ) then
extra = " |TInterface \\ AddOns \\ WIM \\ Skins \\ Default \\ minimap.blp:20:20:0:0|t " ;
color = " fff569 " ;
end
if not user then
_G.print ( " Your WIM history is damaged beyond repair and must be erased before it can be used again do to having conversation with a realid friend that has no battletag. This bug has been fixed in WIM but your history cannot be repaired " )
return
end
self.user = user ;
self.text : SetText ( " |cff " .. color .. user .. " |r " .. extra .. ( gmTag == " * " and " |TInterface \\ ChatFrame \\ UI-ChatIcon-Blizz.blp:0:2:0:0|t " or " " ) ) ;
if ( user == win.SELECT ) then
self : Click ( ) ;
end
end
button : SetScript ( " OnClick " , function ( self )
win : SelectConvo ( self.user ) ;
win.nav . userList.scroll . update ( ) ;
end ) ;
button.delete = CreateFrame ( " Button " , nil , button ) ;
button.delete : SetNormalTexture ( " Interface \\ AddOns \\ " .. addonTocName .. " \\ Modules \\ Textures \\ xNormal " ) ;
button.delete : SetPushedTexture ( " Interface \\ AddOns \\ " .. addonTocName .. " \\ Modules \\ Textures \\ xPressed " ) ;
button.delete : SetWidth ( 16 ) ;
button.delete : SetHeight ( 16 ) ;
button.delete : SetAlpha ( .5 ) ;
button.delete : SetPoint ( " RIGHT " ) ;
button.delete : SetScript ( " OnClick " , function ( self )
_G.StaticPopupDialogs [ " WIM_DELETE_HISTORY " ] = {
preferredIndex = STATICPOPUP_NUMDIALOGS ,
text = _G.format ( L [ " Are you sure you want to delete all history saved for %s on %s? " ] ,
" |cff69ccf0 " .. self : GetParent ( ) . user .. " |r " ,
" |cff69ccf0 " .. win.USER .. " |r "
) ,
button1 = L [ " Yes " ] ,
button2 = L [ " No " ] ,
OnAccept = function ( )
local realm , character = string.match ( win.USER , " ^([^/]+)/?(.*)$ " ) ;
if ( realm and character and history [ realm ] and history [ realm ] [ character ] ) then
history [ realm ] [ character ] [ self : GetParent ( ) . user ] = nil ;
if ( isEmptyTable ( history [ realm ] [ character ] ) ) then
history [ realm ] [ character ] = nil ;
if ( isEmptyTable ( history [ realm ] ) ) then
history [ realm ] = nil ;
end
end
elseif ( realm and history [ realm ] ) then
for char , convos in pairs ( history [ realm ] ) do
convos [ self : GetParent ( ) . user ] = nil ;
if ( isEmptyTable ( convos ) ) then
history [ realm ] [ char ] = nil ;
end
end
if ( isEmptyTable ( history [ realm ] ) ) then
history [ realm ] = nil ;
end
end
win.nav . user : Hide ( ) ;
win.nav . user : Show ( ) ;
win.UpdateUserList ( ) ;
end ,
timeout = 0 ,
whileDead = 1 ,
hideOnEscape = 1
} ;
_G.StaticPopup_Show ( " WIM_DELETE_HISTORY " ) ;
end ) ;
table.insert ( win.nav . userList.scroll . buttons , button ) ;
return button ;
end
win.nav . userList.scroll . update = function ( )
local self = win.nav . userList.scroll ;
local maxButtons = _G.math . floor ( self : GetHeight ( ) / 20 ) ;
local offset = _G.FauxScrollFrame_GetOffset ( self ) ;
for i = 1 , # self.buttons do
if ( i <= maxButtons ) then
self.buttons [ i ] : Show ( ) ;
local index = i + offset ;
if ( index <= # win.USERLIST ) then
self.buttons [ i ] : SetUser ( win.USERLIST [ index ] ) ;
self.buttons [ i ] : Show ( ) ;
if ( self.buttons [ i ] . user == win.CONVO ) then
self.buttons [ i ] : LockHighlight ( ) ;
else
self.buttons [ i ] : UnlockHighlight ( ) ;
end
else
self.buttons [ i ] : Hide ( ) ;
end
else
self.buttons [ i ] : Hide ( ) ;
end
end
_G.FauxScrollFrame_Update ( self , # win.USERLIST , maxButtons , 20 ) ;
end
win.nav . userList.scroll : SetScript ( " OnShow " , function ( self )
local maxButtons = _G.math . floor ( self : GetHeight ( ) / 20 ) ;
if ( maxButtons > # self.buttons ) then
local toCreate = maxButtons - # self.buttons ;
for i = 1 , toCreate do
self.createButton ( ) ;
end
end
self : update ( ) ;
end ) ;
win.nav . userList.scroll : SetScript ( " OnVerticalScroll " , function ( self , offset )
_G.FauxScrollFrame_OnVerticalScroll ( self , offset , 20 , win.nav . userList.scroll . update ) ;
end ) ;
--search bar
win.search = CreateFrame ( " Frame " , nil , win ) ;
win.search . bg = win.search : CreateTexture ( nil , " BACKGROUND " ) ;
win.search . bg : SetColorTexture ( 1 , 1 , 1 , .25 ) ;
win.search . bg : SetAllPoints ( ) ;
win.search : SetPoint ( " TOPLEFT " , win.nav , " TOPRIGHT " ) ;
win.search : SetPoint ( " RIGHT " , - 18 , 0 ) ;
win.search : SetHeight ( 30 ) ;
win.search . clear = CreateFrame ( " Button " , nil , win.search ) ;
win.search . clear : SetNormalTexture ( " Interface \\ AddOns \\ " .. addonTocName .. " \\ Modules \\ Textures \\ xNormal " ) ;
win.search . clear : SetPushedTexture ( " Interface \\ AddOns \\ " .. addonTocName .. " \\ Modules \\ Textures \\ xPressed " ) ;
win.search . clear : SetWidth ( 16 ) ;
win.search . clear : SetHeight ( 16 ) ;
win.search . clear : SetPoint ( " RIGHT " , - 5 , 0 )
win.search . clear : SetScript ( " OnClick " , function ( self )
win.search . text : ClearFocus ( ) ;
win.search . text : SetText ( " " ) ;
for key , _ in pairs ( win.SEARCHLIST ) do
win.SEARCHLIST [ key ] = nil ;
end
win.search . result : Hide ( ) ;
win.UpdateFilterList ( ) ;
win.UpdateDisplay ( ) ;
end ) ;
win.search . text = CreateFrame ( " EditBox " , nil , win.search ) ;
win.search . text : SetFontObject ( _G.ChatFontNormal ) ;
win.search . text : SetWidth ( 200 ) ; win.search . text : SetHeight ( 15 ) ;
win.search . text : SetPoint ( " RIGHT " , win.search . clear , " LEFT " , - 5 , 0 ) ;
win.search . text : SetScript ( " OnEditFocusGained " , function ( self ) self : HighlightText ( ) end ) ;
win.search . text : SetScript ( " OnEditFocusLost " , function ( self ) self : HighlightText ( 0 , 0 ) end ) ;
win.search . text : SetScript ( " OnEnterPressed " , function ( self )
for key , _ in pairs ( win.SEARCHLIST ) do
win.SEARCHLIST [ key ] = nil ;
end
local realm , character = string.match ( win.USER , " ^([^/]+)/?(.*)$ " ) ;
if ( realm and character and history [ realm ] and history [ realm ] [ character ] ) then
for convo , tbl in pairs ( history [ realm ] [ character ] ) do
for i = 1 , # tbl do
if ( searchResult ( tbl [ i ] . msg , self : GetText ( ) ) ) then
table.insert ( win.SEARCHLIST , copyTable ( tbl [ i ] , { seq = i } ) ) ;
end
end
end
elseif ( realm and history [ realm ] ) then
for char , convos in pairs ( history [ realm ] ) do
for convo , tbl in pairs ( convos ) do
for i = 1 , # tbl do
if ( searchResult ( tbl [ i ] . msg , self : GetText ( ) ) ) then
table.insert ( win.SEARCHLIST , copyTable ( tbl [ i ] , { seq = i } ) ) ;
end
end
end
end
end
table.sort ( win.SEARCHLIST , function ( a , b )
if ( a.seq and b.seq ) then
return tonumber ( a.time .. " . " .. a.seq ) < tonumber ( b.time .. " . " .. b.seq )
end
return a.time < b.time ;
end ) ;
if ( # win.SEARCHLIST > 0 ) then
win.search . result : SetText ( _G.format ( L [ " Search resulted in %d |4message:messages;. " ] , # win.SEARCHLIST ) )
else
win.search . result : SetText ( " |cffff0000 " .. L [ " No results found! " ] .. " |r " ) ;
end
win.search . result : Show ( ) ;
self : ClearFocus ( ) ;
win.UpdateFilterList ( ) ;
win.UpdateDisplay ( ) ;
end ) ;
options.AddFramedBackdrop ( win.search . text ) ;
win.search . text : SetAutoFocus ( false ) ;
win.search . text : SetScript ( " OnEscapePressed " , function ( self ) self : ClearFocus ( ) end ) ;
win.search . label = win.search : CreateFontString ( nil , " OVERLAY " , " ChatFontNormal " ) ;
win.search . label : SetText ( L [ " Search " ] .. " : " ) ;
win.search . label : SetTextColor ( _G.GameFontNormal : GetTextColor ( ) ) ;
win.search . label : SetPoint ( " RIGHT " , win.search . text , " LEFT " , - 5 , 0 ) ;
win.search . result = win.search : CreateFontString ( nil , " OVERLAY " , " ChatFontSmall " ) ;
win.search . result : SetPoint ( " LEFT " ) ;
win.search . result : SetPoint ( " RIGHT " , win.search . label , " LEFT " , - 5 , 0 ) ;
win.search . result : Hide ( ) ;
--content frame
win.content = CreateFrame ( " Frame " , nil , win ) ;
win.content . border = win.content : CreateTexture ( nil , " BACKGROUND " ) ;
win.content . border : SetColorTexture ( 1 , 1 , 1 , .25 ) ;
win.content . border : SetPoint ( " BOTTOMLEFT " ) ;
win.content . border : SetPoint ( " BOTTOMRIGHT " ) ;
win.content . border : SetHeight ( 1 ) ;
win.content : SetPoint ( " TOPLEFT " , win.search , " BOTTOMLEFT " ) ;
win.content : SetPoint ( " BOTTOMRIGHT " , win , " BOTTOMRIGHT " , - 18 , 40 ) ;
win.content . tabs = { } ;
win.content . createTab = function ( self , index )
local tab = CreateFrame ( " Button " , nil , self ) ;
tab.index = index ;
tab.frame = ViewTypes [ index ] . frame ;
tab : SetHeight ( 20 ) ;
tab.text = tab : CreateFontString ( nil , " OVERLAY " , " ChatFontSmall " ) ;
tab.text : SetAllPoints ( ) ;
tab.text : SetText ( ViewTypes [ index ] . text ) ;
tab.bg = tab : CreateTexture ( nil , " BACKGROUND " ) ;
tab.bg : SetColorTexture ( 1 , 1 , 1 , .25 ) ;
tab.bg : SetAllPoints ( ) ;
tab : SetWidth ( tab.text : GetStringWidth ( ) + 16 ) ;
if ( # self.tabs > 0 ) then
tab : SetPoint ( " TOPLEFT " , self.tabs [ # self.tabs ] , " TOPRIGHT " , 2 , 0 ) ;
else
tab : SetPoint ( " TOPLEFT " , self , " BOTTOMLEFT " , 5 , 0 ) ;
end
tab : SetScript ( " OnClick " , function ( self )
for i = 1 , # win.content . tabs do
if ( win.progressBar : IsVisible ( ) ) then
win.progressBar . delete : Click ( ) ;
end
if ( self.index == i ) then
win.content . tabs [ i ] : SetAlpha ( 1 ) ;
win.TAB = self.index ;
if ( self.frame == " chatFrame " ) then
win.content . chatFrame : Show ( ) ;
win.content . textFrame : Hide ( ) ;
else
win.content . textFrame : Show ( ) ;
win.content . chatFrame : Hide ( ) ;
end
else
win.content . tabs [ i ] : SetAlpha ( .5 ) ;
end
end
win : UpdateDisplay ( ) ;
end ) ;
table.insert ( self.tabs , tab ) ;
end
for i = 1 , # ViewTypes do
win.content : createTab ( i ) ;
end
win.content . chatFrame = CreateFrame ( " ScrollingMessageFrame " , " WIM3_HistoryChatFrame " , win.content ) ;
win.content . chatFrame : SetPoint ( " TOPLEFT " , 4 , - 4 ) ;
win.content . chatFrame : SetPoint ( " BOTTOMRIGHT " , - 30 , 4 ) ;
win.content . chatFrame : SetFontObject ( " ChatFontNormal " ) ;
win.content . chatFrame : EnableMouse ( true ) ;
win.content . chatFrame : EnableMouseWheel ( true ) ;
win.content . chatFrame : SetJustifyH ( " LEFT " ) ;
win.content . chatFrame : SetFading ( false ) ;
win.content . chatFrame : SetMaxLines ( 800 ) ;
win.content . chatFrame.update = function ( self )
if ( self : AtTop ( ) ) then
self.up : Disable ( ) ;
else
self.up : Enable ( ) ;
end
if ( self : AtBottom ( ) ) then
self.down : Disable ( ) ;
else
self.down : Enable ( ) ;
end
end
win.content . chatFrame : SetScript ( " OnShow " , function ( self )
self : update ( ) ;
end ) ;
win.content . chatFrame : SetScript ( " OnMouseWheel " , function ( self , ... )
if ( select ( 1 , ... ) > 0 ) then
if ( _G.IsControlKeyDown ( ) ) then
self : ScrollToTop ( ) ;
else
if ( _G.IsShiftKeyDown ( ) ) then
self : PageUp ( ) ;
else
self : ScrollUp ( ) ;
end
end
else
if ( _G.IsControlKeyDown ( ) ) then
self : ScrollToBottom ( ) ;
else
if ( _G.IsShiftKeyDown ( ) ) then
self : PageDown ( ) ;
else
self : ScrollDown ( ) ;
end
end
end
self : update ( ) ;
end ) ;
win.content . chatFrame : SetScript ( " OnHyperlinkClick " , _G.ChatFrame_OnHyperlinkShow ) ;
win.content . chatFrame.up = CreateFrame ( " Button " , nil , win.content . chatFrame ) ;
win.content . chatFrame.up : SetWidth ( 28 ) ; win.content . chatFrame.up : SetHeight ( 28 ) ;
win.content . chatFrame.up : SetNormalTexture ( " Interface \\ ChatFrame \\ UI-ChatIcon-ScrollUp-Up " ) ;
win.content . chatFrame.up : SetPushedTexture ( " Interface \\ ChatFrame \\ UI-ChatIcon-ScrollUp-Down " ) ;
win.content . chatFrame.up : SetDisabledTexture ( " Interface \\ ChatFrame \\ UI-ChatIcon-ScrollUp-Disabled " ) ;
win.content . chatFrame.up : SetHighlightTexture ( " Interface \\ Buttons \\ UI-Common-MouseHilight " , " ADD " ) ;
win.content . chatFrame.up : SetPoint ( " TOPRIGHT " , 30 , 0 ) ;
win.content . chatFrame.up : SetScript ( " OnClick " , function ( self )
local obj = self : GetParent ( ) ;
if ( _G.IsControlKeyDown ( ) ) then
obj : ScrollToTop ( ) ;
else
if ( _G.IsShiftKeyDown ( ) ) then
obj : PageUp ( ) ;
else
obj : ScrollUp ( ) ;
end
end
obj : update ( ) ;
end ) ;
win.content . chatFrame.down = CreateFrame ( " Button " , nil , win.content . chatFrame ) ;
win.content . chatFrame.down : SetWidth ( 28 ) ; win.content . chatFrame.down : SetHeight ( 28 ) ;
win.content . chatFrame.down : SetNormalTexture ( " Interface \\ ChatFrame \\ UI-ChatIcon-ScrollDown-Up " ) ;
win.content . chatFrame.down : SetPushedTexture ( " Interface \\ ChatFrame \\ UI-ChatIcon-ScrollDown-Down " ) ;
win.content . chatFrame.down : SetDisabledTexture ( " Interface \\ ChatFrame \\ UI-ChatIcon-ScrollDown-Disabled " ) ;
win.content . chatFrame.down : SetHighlightTexture ( " Interface \\ Buttons \\ UI-Common-MouseHilight " , " ADD " ) ;
win.content . chatFrame.down : SetPoint ( " BOTTOMRIGHT " , 30 , - 4 ) ;
win.content . chatFrame.down : SetScript ( " OnClick " , function ( self )
local obj = self : GetParent ( ) ;
if ( _G.IsControlKeyDown ( ) ) then
obj : ScrollToBottom ( ) ;
else
if ( _G.IsShiftKeyDown ( ) ) then
obj : PageDown ( ) ;
else
obj : ScrollDown ( ) ;
end
end
obj : update ( ) ;
end ) ;
win.content . textFrame = CreateFrame ( " ScrollFrame " , " WIM3_HistoryTextFrame " , win.content , " UIPanelScrollFrameTemplate " ) ;
win.content . textFrame : SetPoint ( " TOPLEFT " , win.content , " TOPLEFT " , 4 , - 4 ) ;
win.content . textFrame : SetPoint ( " BOTTOMRIGHT " , - 25 , 4 ) ;
win.content . textFrame.text = CreateFrame ( " EditBox " , " WIM3_HistoryTextFrameText " , win.content . textFrame ) ;
win.content . textFrame.text : SetFontObject ( _G.ChatFontNormal ) ;
win.content . textFrame.text : SetMultiLine ( true ) ;
win.content . textFrame : SetScrollChild ( win.content . textFrame.text ) ;
win.content . textFrame.text : SetWidth ( win.content . textFrame : GetWidth ( ) ) ;
win.content . textFrame.text : SetHeight ( 200 ) ;
win.content . textFrame.text : SetAutoFocus ( false ) ;
win.content . textFrame.text : SetScript ( " OnEscapePressed " , function ( self ) self : ClearFocus ( ) end ) ;
win.content . textFrame.text : SetScript ( " OnTextChanged " , function ( self )
win.content . textFrame : UpdateScrollChildRect ( ) ;
end ) ;
win.content . textFrame.text . AddMessage = function ( self , msg , r , g , b )
local color ;
--if(r and g and b) then
-- color = RGBPercentToHex(r, g, b);
--end
msg = msg : gsub ( " |c[0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f] " , " " ) ;
msg = msg : gsub ( " |r " , " " ) ;
--self:SetText(self:GetText()..(color and "|cff"..color or "")..msg..(color and "|r" or "").."\n");
self : SetText ( self : GetText ( ) .. msg .. " \n " ) ;
end ;
--resize
win.resize = CreateFrame ( " Button " , nil , win ) ;
win.resize : SetNormalTexture ( " Interface \\ AddOns \\ " .. addonTocName .. " \\ Skins \\ Default \\ resize " ) ;
win.resize : SetHighlightTexture ( " Interface \\ AddOns \\ " .. addonTocName .. " \\ Skins \\ Default \\ resize " , " ADD " ) ;
win.resize : SetWidth ( 20 ) ; win.resize : SetHeight ( 20 ) ;
win.resize : SetPoint ( " BOTTOMRIGHT " , - 11 , 11 ) ;
win.resize : SetScript ( " OnMouseDown " , function ( self )
self : GetParent ( ) . isSizing = true ;
self : GetParent ( ) : SetResizable ( true ) ;
self : GetParent ( ) : StartSizing ( " BOTTOMRIGHT " ) ;
self : SetScript ( " OnUpdate " , function ( self )
win.nav . userList.scroll : update ( ) ;
end ) ;
end ) ;
win.resize : SetScript ( " OnMouseUp " , function ( self )
self : SetScript ( " OnUpdate " , nil ) ;
self : GetParent ( ) . isSizing = false ;
self : GetParent ( ) : StopMovingOrSizing ( ) ;
win.nav . userList.scroll : Hide ( ) ;
win.nav . userList.scroll : Show ( ) ;
end ) ;
win.USER = env.realm .. " / " .. env.character ;
win.USERLIST = { } ;
win.CONVO = " " ;
win.CONVOLIST = { } ;
win.FILTER = " " ;
win.FILTERLIST = { } ;
win.SEARCHLIST = { } ;
win.SelectConvo = function ( self , convo )
win.search . text : SetText ( " " ) ;
win.search . result : Hide ( ) ;
for k , _ in pairs ( win.SEARCHLIST ) do
win.SEARCHLIST [ k ] = nil ;
end
win.CONVO = convo ;
win.FILTER = " " ;
win.UpdateConvoList ( ) ;
win.UpdateFilterList ( ) ;
win.UpdateDisplay ( ) ;
end
win.UpdateDisplay = function ( self )
if ( win.displayUpdate ) then
win.displayUpdate : Show ( ) ;
end
end
win.UpdateFilterList = function ( self )
for i = 1 , # win.FILTERLIST do
win.FILTERLIST [ i ] = nil ;
end
local theList = # win.SEARCHLIST > 0 and win.SEARCHLIST or win.CONVOLIST ;
for i = 1 , # theList do
local t = theList [ i ] . time ;
local tbl = date ( " *t " , t ) ;
t = time { year = tbl.year , month = tbl.month , day = tbl.day , hour = 0 } ;
addToTableUnique ( win.FILTERLIST , t ) ;
win.FILTER = t ;
end
if ( # win.FILTERLIST > 0 ) then
table.insert ( win.FILTERLIST , 1 , L [ " Show All " ] ) ;
end
win.nav . filters.scroll : Hide ( ) ;
win.nav . filters.scroll : Show ( ) ;
end
win.UpdateConvoList = function ( self )
for i = 1 , # win.CONVOLIST do
win.CONVOLIST [ i ] = nil ;
end
local realm , character = string.match ( win.USER , " ^([^/]+)/?(.*)$ " ) ;
if ( realm and character and history [ realm ] and history [ realm ] [ character ] ) then
local tbl = history [ realm ] [ character ] [ win.CONVO ] ;
if tbl then
for i = 1 , # tbl do
table.insert ( win.CONVOLIST , copyTable ( tbl [ i ] , { seq = i } ) ) ;
end
else
ShowHistoryViewer ( )
end
elseif ( realm and history [ realm ] ) then
for char , tbl in pairs ( history [ realm ] ) do
if ( tbl [ win.CONVO ] ) then
for i = 1 , # tbl [ win.CONVO ] do
table.insert ( win.CONVOLIST , copyTable ( tbl [ win.CONVO ] [ i ] , { seq = i } ) ) ;
end
end
end
end
table.sort ( win.CONVOLIST , function ( a , b )
if ( a.seq and b.seq ) then
return tonumber ( a.time .. " . " .. a.seq ) < tonumber ( b.time .. " . " .. b.seq )
end
return a.time < b.time ;
end ) ;
end
win.UpdateUserList = function ( self )
for i = 1 , # win.USERLIST do
win.USERLIST [ i ] = nil ;
end
local realm , character = string.match ( win.USER , " ^([^/]+)/?(.*)$ " ) ;
if ( realm and character and history [ realm ] and history [ realm ] [ character ] ) then
local tbl = history [ realm ] [ character ] ;
for convo , t in pairs ( tbl ) do
ChannelCache [ convo ] = t.info and t.info . channelNumber or nil ;
convo = ( t.info and t.info . chat and " * " or " " ) .. convo
addToTableUnique ( win.USERLIST , convo .. ( t.info and t.info . gm and " * " or " " ) ) ;
end
elseif ( realm and ( not character or character == " " ) and history [ realm ] ) then
for char , tbl in pairs ( history [ realm ] ) do
for convo , t in pairs ( tbl ) do
ChannelCache [ convo ] = t.info and t.info . channelNumber or nil ;
convo = ( t.info and t.info . chat and " * " or " " ) .. convo
addToTableUnique ( win.USERLIST , convo .. ( t.info and t.info . gm and " * " or " " ) ) ;
end
end
end
table.sort ( win.USERLIST ) ;
win.nav . userList.scroll : Hide ( ) ;
win.nav . userList.scroll : Show ( ) ;
if ( # win.USERLIST > 0 ) then
if ( not win.SELECT ) then
win.nav . userList.scroll . buttons [ 1 ] : Click ( ) ;
else
win.SELECT = nil ;
end
else
win.SELECT = nil ;
win : SelectConvo ( " " ) ;
end
end
win.progressBar = CreateFrame ( " Frame " , nil , win.content ) ;
win.progressBar : SetFrameStrata ( " TOOLTIP " ) ;
win.progressBar : SetWidth ( 300 ) ; win.progressBar : SetHeight ( 65 ) ;
win.progressBar : SetPoint ( " CENTER " , 0 , 50 ) ;
options.AddFramedBackdrop ( win.progressBar ) ;
win.progressBar . backdrop.bg : SetColorTexture ( 0 , 0 , 0 , 1 ) ;
win.progressBar . bar = CreateFrame ( " Frame " , nil , win.progressBar ) ;
options.AddFramedBackdrop ( win.progressBar . bar ) ;
win.progressBar . bar : SetWidth ( win.progressBar : GetWidth ( ) - 50 ) ; win.progressBar . bar : SetHeight ( 15 ) ;
win.progressBar . bar : SetPoint ( " CENTER " , - 10 , - 5 ) ;
win.progressBar . bar.bg = win.progressBar . bar : CreateTexture ( nil , " OVERLAY " ) ;
win.progressBar . bar.bg : SetColorTexture ( 1 , 1 , 1 , .5 ) ;
win.progressBar . bar.bg : SetPoint ( " TOPLEFT " ) ;
win.progressBar . bar.bg : SetPoint ( " BOTTOMLEFT " ) ;
win.progressBar . text = win.progressBar : CreateFontString ( nil , " OVERLAY " , " ChatFontNormal " ) ;
win.progressBar . text : SetPoint ( " BOTTOMLEFT " , win.progressBar . bar , " TOPLEFT " , 0 , 5 ) ;
win.progressBar . text : SetText ( L [ " Loading History " ] .. " ... " ) ;
win.progressBar : SetScript ( " OnShow " , function ( self )
win.content . chatFrame : SetAlpha ( .5 ) ;
win.content . textFrame : SetAlpha ( .5 ) ;
end ) ;
win.progressBar : SetScript ( " OnHide " , function ( self )
win.content . chatFrame : SetAlpha ( 1 ) ;
win.content . textFrame : SetAlpha ( 1 ) ;
end ) ;
win.progressBar . delete = CreateFrame ( " Button " , nil , win.progressBar ) ;
win.progressBar . delete : SetNormalTexture ( " Interface \\ AddOns \\ " .. addonTocName .. " \\ Modules \\ Textures \\ xNormal " ) ;
win.progressBar . delete : SetPushedTexture ( " Interface \\ AddOns \\ " .. addonTocName .. " \\ Modules \\ Textures \\ xPressed " ) ;
win.progressBar . delete : SetWidth ( 16 ) ;
win.progressBar . delete : SetHeight ( 16 ) ;
win.progressBar . delete : SetPoint ( " LEFT " , win.progressBar . bar , " RIGHT " , 4 , 0 ) ;
win.progressBar . delete : SetScript ( " OnClick " , function ( self )
win.displayUpdate : Hide ( ) ;
end ) ;
win.content . tabs [ 1 ] : Click ( ) ;
return win ;
end
local HistoryViewer ;
local function createDisplayUpdate ( )
-- displayUpdate loads messages into the correct content frames avoiding lag from system ops.
local displayUpdate = CreateFrame ( " Frame " ) ;
displayUpdate : Hide ( ) ;
displayUpdate.firstPass = true ;
displayUpdate.tmpTable = { } ;
displayUpdate.Process = function ( self )
self.i = self.i or 1 ;
if ( not self.curList or not self.curList [ self.i ] ) then
self : Hide ( ) ;
return ;
end
HistoryViewer.progressBar . bar.bg : SetWidth ( HistoryViewer.progressBar . bar : GetWidth ( ) * self.i /# self.curList ) ;
-- clear tmpTable
for k , _ in pairs ( self.tmpTable ) do
self.tmpTable [ k ] = nil ;
end
-- load tmpTable
for k , v in pairs ( self.curList [ self.i ] ) do
self.tmpTable [ k ] = v ;
end
if ( self.filter ) then
if ( self.min <= self.tmpTable . time and self.max > self.tmpTable . time ) then
ViewTypes [ HistoryViewer.TAB ] . func ( self.frame , self.tmpTable ) ;
else
self.i = self.i + 1 ;
self : Process ( ) ;
return ;
end
else
ViewTypes [ HistoryViewer.TAB ] . func ( self.frame , self.tmpTable ) ;
end
self.i = self.i + 1 ;
end ;
displayUpdate : SetScript ( " OnUpdate " , function ( self , elapsed )
if ( self.firstPass ) then
HistoryViewer.content . chatFrame : Clear ( ) ;
HistoryViewer.content . chatFrame.lastDate = nil ;
HistoryViewer.content . chatFrame : SetIndentedWordWrap ( db.wordwrap_indent ) ;
HistoryViewer.content . textFrame.text : SetText ( " " ) ;
HistoryViewer.content . textFrame.text . lastDate = nil ;
self.firstPass = nil ;
end
self : Process ( )
end ) ;
displayUpdate : SetScript ( " OnHide " , function ( self )
self.firstPass = true ;
self.i = 1 ;
HistoryViewer.progressBar : Hide ( ) ;
HistoryViewer.content . chatFrame : update ( ) ;
local buttons = HistoryViewer.nav . userList.scroll . buttons ;
for i = 1 , # buttons do
buttons [ i ] : Enable ( ) ;
buttons [ i ] . delete : Enable ( ) ;
end
buttons = HistoryViewer.nav . filters.scroll . buttons ;
for i = 1 , # buttons do
buttons [ i ] : Enable ( ) ;
end
end ) ;
displayUpdate : SetScript ( " OnShow " , function ( self )
local buttons = HistoryViewer.nav . userList.scroll . buttons ;
for i = 1 , # buttons do
buttons [ i ] : Disable ( ) ;
buttons [ i ] . delete : Disable ( ) ;
end
buttons = HistoryViewer.nav . filters.scroll . buttons ;
for i = 1 , # buttons do
buttons [ i ] : Disable ( ) ;
end
HistoryViewer.progressBar : Show ( ) ;
self.curList = # HistoryViewer.SEARCHLIST > 0 and HistoryViewer.SEARCHLIST or HistoryViewer.CONVOLIST ;
self.frame = ViewTypes [ HistoryViewer.TAB ] . frame == " chatFrame " and HistoryViewer.content . chatFrame or HistoryViewer.content . textFrame.text ;
self.filter = _G.type ( HistoryViewer.FILTER ) == " number " or nil ;
self.min , self.max = 0 , 0 ;
if ( self.filter ) then
local t = HistoryViewer.FILTER ;
local tbl = date ( " *t " , t ) ;
t = time { year = tbl.year , month = tbl.month , day = tbl.day , hour = 0 } ;
self.min , self.max = t , t + dDay ;
end
end ) ;
return displayUpdate ;
end
local colorWhite = { r = 1 , g = 1 , b = 1 } ;
local chatFrameMsgId = - 1 ;
table.insert ( ViewTypes , {
text = L [ " Chat View " ] ,
frame = " chatFrame " ,
func = function ( frame , msg )
local color ;
if ( msg.type == 1 ) then
color = db.displayColors [ msg.inbound and " wispIn " or " wispOut " ] ;
nextColor.r , nextColor.g , nextColor.b = color.r , color.g , color.b ;
elseif ( msg.type == 2 ) then
if ( msg.event == CHANNEL ) then
color = _G.ChatTypeInfo [ " CHANNEL " .. msg.channelNumber ] ;
else
color = _G.ChatTypeInfo [ msg.event ] ;
end
color = color or colorWhite ;
nextColor.r , nextColor.g , nextColor.b = color.r , color.g , color.b ;
end
frame.nextStamp = msg.time ;
frame : AddMessage ( applyStringModifiers ( applyMessageFormatting ( frame , " CHAT_MSG_ " .. ( msg.event or " WHISPER " ) , msg.msg , msg.from ,
nil , nil , nil , nil , 0 , msg.channelName and ChannelCache [ msg.channelName ] , msg.channelName , nil , chatFrameMsgId , " 0x0300000000000000 " ) , frame ) , color.r , color.g , color.b ) ;
chatFrameMsgId = chatFrameMsgId > - 1000 and chatFrameMsgId - 1 or - 1 ;
end
} ) ;
table.insert ( ViewTypes , {
text = L [ " Text View " ] ,
frame = " textFrame " ,
func = function ( frame , msg )
frame.noEscapedStrings = true ;
if ( msg.type == 1 or msg.type == 2 ) then
local color = db.displayColors [ msg.inbound and " wispIn " or " wispOut " ] ;
nextColor.r , nextColor.g , nextColor.b = color.r , color.g , color.b ;
frame.nextStamp = msg.time ;
frame : AddMessage ( applyStringModifiers ( applyMessageFormatting ( frame , " CHAT_MSG_WHISPER " , msg.msg , msg.from ,
nil , nil , nil , nil , 0 , msg.channelName and ChannelCache [ msg.channelName ] , msg.channelName , " 0x0300000000000000 " ) , frame ) , color.r , color.g , color.b )
end
end
} ) ;
-- stewart
table.insert ( ViewTypes , {
text = L [ " BBCode " ] ,
frame = " textFrame " ,
func = function ( frame , msg )
local color ;
if ( msg.type == 1 ) then
color = db.displayColors [ msg.inbound and " wispIn " or " wispOut " ] ;
nextColor.r , nextColor.g , nextColor.b = color.r , color.g , color.b ;
elseif ( msg.type == 2 ) then
if ( msg.event == CHANNEL ) then
color = _G.ChatTypeInfo [ " CHANNEL " .. msg.channelNumber ] ;
else
color = _G.ChatTypeInfo [ msg.event ] ;
end
color = color or colorWhite ;
nextColor.r , nextColor.g , nextColor.b = color.r , color.g , color.b ;
end
frame.noEscapedStrings = nil ;
frame.noEmoticons = true ;
frame.nextStamp = msg.time ;
local chatColor = " [color=# " .. RGBPercentToHex ( color.r , color.g , color.b ) .. " ] " ;
local chatColorPattern = " %[color%=%# " .. RGBPercentToHex ( color.r , color.g , color.b ) .. " %]%s*%[%/color%] " ;
msg = applyMessageFormatting ( frame , " CHAT_MSG_WHISPER " , msg.msg , msg.from )
msg = applyStringModifiers ( msg , frame ) ;
msg = msg : gsub ( " |c[0-9A-Fa-f][0-9A-Fa-f]([0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f])|Hwim_url:([^|]*)|h.-|h|r " , " [/color][url=%2][color=#%1]%2[/color][/url] " .. chatColor ) ;
msg = msg : gsub ( " |c[0-9A-Fa-f][0-9A-Fa-f]([0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f]) " , " [color=#%1] " ) ;
msg = msg : gsub ( " |r " , " [/color] " ) ;
msg = msg : gsub ( " (%[color%=%#[0-9A-Fa-f]+%])|Hitem:(%d+)[:%d]*|h([^|]+)|h(%[%/color%]) " , " [/color][url=http://www.wowhead.com/?item=%2]%1%3%4[/url] " .. chatColor ) ;
msg = chatColor .. msg .. " [/color] " ;
msg = msg : gsub ( " (%[color%=%#[0-9A-Fa-f]+%])(%[color%=%#[0-9A-Fa-f]+%])(.-)(%[%/color%]) " , " %2%3%4%1 " ) ;
msg = msg : gsub ( chatColorPattern , " " ) ;
frame : AddMessage ( msg , color.r , color.g , color.b )
end
} ) ;
table.insert ( ViewTypes , {
text = " HTML " ,
frame = " textFrame " ,
func = function ( frame , msg )
local color ;
if ( msg.type == 1 ) then
color = db.displayColors [ msg.inbound and " wispIn " or " wispOut " ] ;
nextColor.r , nextColor.g , nextColor.b = color.r , color.g , color.b ;
elseif ( msg.type == 2 ) then
if ( msg.event == CHANNEL ) then
color = _G.ChatTypeInfo [ " CHANNEL " .. msg.channelNumber ] ;
else
color = _G.ChatTypeInfo [ msg.event ] ;
end
color = color or colorWhite ;
nextColor.r , nextColor.g , nextColor.b = color.r , color.g , color.b ;
end
frame.noEscapedStrings = nil ;
frame.noEmoticons = true ;
frame.nextStamp = msg.time ;
local chatColor = " <font color='# " .. RGBPercentToHex ( color.r , color.g , color.b ) .. " '> " ;
local chatColorPattern = " %<font color%='%# " .. RGBPercentToHex ( color.r , color.g , color.b ) .. " '%>%s*%<%/font%> " ;
msg = applyMessageFormatting ( frame , " CHAT_MSG_WHISPER " , msg.msg , msg.from )
msg = applyStringModifiers ( msg , frame ) ;
-- html escapes
msg = msg : gsub ( " & " , " & " ) ;
msg = msg : gsub ( " < " , " < " ) ;
msg = msg : gsub ( " > " , " > " ) ;
msg = msg : gsub ( " \" " , " " " ) ;
-- color & URL handling...
msg = msg : gsub ( " |c[0-9A-Fa-f][0-9A-Fa-f]([0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f])|Hwim_url:([^|]*)|h.-|h|r " , " </color><a href='%2'><font color='#%1'>%2</font></a> " .. chatColor ) ;
msg = msg : gsub ( " |c[0-9A-Fa-f][0-9A-Fa-f]([0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f]) " , " <font color='#%1'> " ) ;
msg = msg : gsub ( " |r " , " </font> " ) ;
msg = msg : gsub ( " (%<font color%='%#[0-9A-Fa-f]+'%>)|Hitem:(%d+)[:%d]*|h([^|]+)|h(%[%/color%]) " , " </font><a href='http://www.wowhead.com/?item=%2'>%1%3%4</a> " .. chatColor ) ;
msg = chatColor .. msg .. " </font> " ;
msg = msg : gsub ( " (%<font color%='%#[0-9A-Fa-f]+'%>)(%<font color%='%#[0-9A-Fa-f]+'%>)(.-)(%<%/font%>) " , " %2%3%4%1 " ) ;
msg = " <br> " .. msg : gsub ( chatColorPattern , " " ) ;
frame : AddMessage ( msg , color.r , color.g , color.b )
end
} ) ;
function ShowHistoryViewer ( user )
local exists = HistoryViewer
if ( HistoryViewer and not user and HistoryViewer : IsShown ( ) ) then
HistoryViewer : Hide ( ) ;
return ;
end
HistoryViewer = HistoryViewer or createHistoryViewer ( ) ;
HistoryViewer.displayUpdate = HistoryViewer.displayUpdate or createDisplayUpdate ( ) ;
if ( user ) then
HistoryViewer.USER = env.realm .. " / " .. env.character ;
HistoryViewer.SELECT = user ;
HistoryViewer.nav : Hide ( ) ;
HistoryViewer.nav : Show ( ) ;
HistoryViewer.UpdateUserList ( ) ;
HistoryViewer : SelectConvo ( user ) ;
-- DisplayTutorial(L["WIM History Viewer"], L["WIM History Viewer can be accessed any time by typing:"].." \n|cff69ccf0/wim history|r");
end
HistoryViewer : Show ( ) ;
if not exists and not user then --force update on first show without user
HistoryViewer : Hide ( ) ;
HistoryViewer : Show ( ) ;
end
end
RegisterSlashCommand ( " history " , function ( ) ShowHistoryViewer ( ) ; end , L [ " Display history viewer. " ] )