local addonName , addon = ...
if not addon.healthCheck then return end
local L = addon.L
-- The sack
local window = nil
-- What state is the sack in?
local state = " BugSackTabAll "
local searchResults = { }
local searchThrough = nil
-- Frame state variables
local currentErrorIndex = nil -- Index of the error in the currentSackContents currently shown
local currentSackContents = nil -- List of all the errors currently navigated in the sack
local currentSackSession = nil -- Current session ID available in the sack
local currentErrorObject = nil
local tabs = nil
local countLabel , sessionLabel , textArea = nil , nil , nil
local nextButton , prevButton , sendButton = nil , nil , nil
local searchLabel , searchBox = nil , nil
local sessionFormat = " %s - |cffff4411%s|r - |cff44ff44%d|r " -- <date> - <sent by> - <session id>
local countFormat = " %d/%d " -- 1/10
local sourceFormat = L [ " Sent by %s (%s) " ]
local localFormat = L [ " Local (%s) " ]
-- Updates the total bug count and so forth.
local lastState = nil
local function updateSackDisplay ( forceRefresh )
if state ~= lastState then forceRefresh = true end
lastState = state
if forceRefresh then
currentErrorObject = nil
currentErrorIndex = nil
else
currentErrorObject = currentSackContents and currentSackContents [ currentErrorIndex ]
end
if state == " BugSackTabAll " then
currentSackContents = addon : GetErrors ( )
currentSackSession = BugGrabber : GetSessionId ( )
elseif state == " BugSackTabSession " then
local s = BugGrabber : GetSessionId ( )
currentSackContents = addon : GetErrors ( s )
currentSackSession = s
elseif state == " BugSackTabLast " then
local s = BugGrabber : GetSessionId ( ) - 1
currentSackContents = addon : GetErrors ( s )
currentSackSession = s
elseif state == " BugSackSearch " then
currentSackSession = - 1
currentSackContents = searchResults
end
local size = # currentSackContents
local eo = nil
if forceRefresh then
-- We need to reset the currently shown error to the highest index
eo = currentSackContents [ size ]
currentErrorIndex = size
else
-- we need to adapt the currentErrorIndex index to the new error list
for i , v in next , currentSackContents do
if v == currentErrorObject then
currentErrorIndex = i
eo = v
break
end
end
end
if not eo then eo = currentSackContents [ currentErrorIndex ] end
if not eo then eo = currentSackContents [ size ] end
if currentSackSession == - 1 and eo then currentSackSession = eo.session end
if size > 0 then
local source = nil
if eo.source then source = sourceFormat : format ( eo.source , " error " )
else source = localFormat : format ( " error " ) end
if eo.session == BugGrabber : GetSessionId ( ) then
sessionLabel : SetText ( sessionFormat : format ( L [ " Today " ] , source , eo.session ) )
else
sessionLabel : SetText ( sessionFormat : format ( eo.time , source , eo.session ) )
end
countLabel : SetText ( countFormat : format ( currentErrorIndex , size ) )
textArea : SetText ( addon : FormatError ( eo ) )
if currentErrorIndex >= size then
nextButton : Disable ( )
else
nextButton : Enable ( )
end
if currentErrorIndex <= 1 then
prevButton : Disable ( )
else
prevButton : Enable ( )
end
if sendButton then sendButton : Enable ( ) end
else
countLabel : SetText ( )
if currentSackSession == BugGrabber : GetSessionId ( ) then
sessionLabel : SetText ( ( " %s (%d) " ) : format ( L [ " Today " ] , BugGrabber : GetSessionId ( ) ) )
else
sessionLabel : SetText ( ( " %d " ) : format ( currentSackSession ) )
end
textArea : SetText ( L [ " You have no bugs, yay! " ] )
nextButton : Disable ( )
prevButton : Disable ( )
if sendButton then sendButton : Disable ( ) end
end
for i , t in next , tabs do
if state == t : GetName ( ) then
PanelTemplates_SelectTab ( t )
else
PanelTemplates_DeselectTab ( t )
end
end
end
hooksecurefunc ( addon , " UpdateDisplay " , function ( )
if not window or not window : IsShown ( ) then return end
-- can't just hook it right in because it would pass |self| as forceRefresh
updateSackDisplay ( true )
end )
-- Only invoked when actually clicking a tab
local function setActiveMethod ( tab )
searchLabel : Hide ( )
searchBox : Hide ( )
sessionLabel : Show ( )
wipe ( searchResults )
--[[if searchThrough then
wipe ( searchThrough )
searchThrough = nil
end ] ]
state = type ( tab ) == " table " and tab : GetName ( ) or tab
updateSackDisplay ( true )
end
local function clearSearch ( )
setActiveMethod ( " BugSackTabAll " )
end
local function filterSack ( editbox )
for i , t in next , tabs do
PanelTemplates_DeselectTab ( t )
end
wipe ( searchResults )
local text = editbox : GetText ( )
-- If there's no text in the box, we reset to all bugs so the search can start over
if not searchThrough or not text or text : trim ( ) : len ( ) == 0 then
state = " BugSackTabAll "
else
for i , err in next , searchThrough do
if err.message and err.message : find ( text ) then
searchResults [ # searchResults + 1 ] = err
elseif err.stack and err.stack : find ( text ) then
searchResults [ # searchResults + 1 ] = err
elseif err.locals and err.locals : find ( text ) then
searchResults [ # searchResults + 1 ] = err
end
end
state = " BugSackSearch "
end
updateSackDisplay ( true )
end
local function createBugSack ( )
window = CreateFrame ( " Frame " , " BugSackFrame " , UIParent )
window : Hide ( )
window : SetFrameStrata ( " DIALOG " )
window : SetWidth ( 500 )
window : SetHeight ( 310 )
window : SetPoint ( " CENTER " )
window : SetMovable ( true )
window : EnableMouse ( true )
window : RegisterForDrag ( " LeftButton " )
window : SetClampedToScreen ( true )
window : SetScript ( " OnDragStart " , window.StartMoving )
window : SetScript ( " OnDragStop " , window.StopMovingOrSizing )
window : SetScript ( " OnShow " , function ( )
PlaySound ( 844 ) -- SOUNDKIT.IG_QUEST_LOG_OPEN
end )
window : SetScript ( " OnHide " , function ( )
currentErrorObject = nil
currentSackSession = nil
currentSackContents = nil
PlaySound ( 845 ) -- SOUNDKIT.IG_QUEST_LOG_CLOSE
end )
local titlebg = window : CreateTexture ( nil , " BORDER " )
titlebg : SetTexture ( 251966 ) --"Interface\\PaperDollInfoFrame\\UI-GearManager-Title-Background"
titlebg : SetPoint ( " TOPLEFT " , 9 , - 6 )
titlebg : SetPoint ( " BOTTOMRIGHT " , window , " TOPRIGHT " , - 28 , - 24 )
local dialogbg = window : CreateTexture ( nil , " BACKGROUND " )
dialogbg : SetTexture ( 136548 ) --"Interface\\PaperDollInfoFrame\\UI-Character-CharacterTab-L1"
dialogbg : SetPoint ( " TOPLEFT " , 8 , - 12 )
dialogbg : SetPoint ( " BOTTOMRIGHT " , - 6 , 8 )
dialogbg : SetTexCoord ( 0.255 , 1 , 0.29 , 1 )
local topleft = window : CreateTexture ( nil , " BORDER " )
topleft : SetTexture ( 251963 ) --"Interface\\PaperDollInfoFrame\\UI-GearManager-Border"
topleft : SetWidth ( 64 )
topleft : SetHeight ( 64 )
topleft : SetPoint ( " TOPLEFT " )
topleft : SetTexCoord ( 0.501953125 , 0.625 , 0 , 1 )
local topright = window : CreateTexture ( nil , " BORDER " )
topright : SetTexture ( 251963 ) --"Interface\\PaperDollInfoFrame\\UI-GearManager-Border"
topright : SetWidth ( 64 )
topright : SetHeight ( 64 )
topright : SetPoint ( " TOPRIGHT " )
topright : SetTexCoord ( 0.625 , 0.75 , 0 , 1 )
local top = window : CreateTexture ( nil , " BORDER " )
top : SetTexture ( 251963 ) --"Interface\\PaperDollInfoFrame\\UI-GearManager-Border"
top : SetHeight ( 64 )
top : SetPoint ( " TOPLEFT " , topleft , " TOPRIGHT " )
top : SetPoint ( " TOPRIGHT " , topright , " TOPLEFT " )
top : SetTexCoord ( 0.25 , 0.369140625 , 0 , 1 )
local bottomleft = window : CreateTexture ( nil , " BORDER " )
bottomleft : SetTexture ( 251963 ) --"Interface\\PaperDollInfoFrame\\UI-GearManager-Border"
bottomleft : SetWidth ( 64 )
bottomleft : SetHeight ( 64 )
bottomleft : SetPoint ( " BOTTOMLEFT " )
bottomleft : SetTexCoord ( 0.751953125 , 0.875 , 0 , 1 )
local bottomright = window : CreateTexture ( nil , " BORDER " )
bottomright : SetTexture ( 251963 ) --"Interface\\PaperDollInfoFrame\\UI-GearManager-Border"
bottomright : SetWidth ( 64 )
bottomright : SetHeight ( 64 )
bottomright : SetPoint ( " BOTTOMRIGHT " )
bottomright : SetTexCoord ( 0.875 , 1 , 0 , 1 )
local bottom = window : CreateTexture ( nil , " BORDER " )
bottom : SetTexture ( 251963 ) --"Interface\\PaperDollInfoFrame\\UI-GearManager-Border"
bottom : SetHeight ( 64 )
bottom : SetPoint ( " BOTTOMLEFT " , bottomleft , " BOTTOMRIGHT " )
bottom : SetPoint ( " BOTTOMRIGHT " , bottomright , " BOTTOMLEFT " )
bottom : SetTexCoord ( 0.376953125 , 0.498046875 , 0 , 1 )
local left = window : CreateTexture ( nil , " BORDER " )
left : SetTexture ( 251963 ) --"Interface\\PaperDollInfoFrame\\UI-GearManager-Border"
left : SetWidth ( 64 )
left : SetPoint ( " TOPLEFT " , topleft , " BOTTOMLEFT " )
left : SetPoint ( " BOTTOMLEFT " , bottomleft , " TOPLEFT " )
left : SetTexCoord ( 0.001953125 , 0.125 , 0 , 1 )
local right = window : CreateTexture ( nil , " BORDER " )
right : SetTexture ( 251963 ) --"Interface\\PaperDollInfoFrame\\UI-GearManager-Border"
right : SetWidth ( 64 )
right : SetPoint ( " TOPRIGHT " , topright , " BOTTOMRIGHT " )
right : SetPoint ( " BOTTOMRIGHT " , bottomright , " TOPRIGHT " )
right : SetTexCoord ( 0.1171875 , 0.2421875 , 0 , 1 )
local close = CreateFrame ( " Button " , nil , window , " UIPanelCloseButton " )
close : SetPoint ( " TOPRIGHT " , 2 , 1 )
close : SetScript ( " OnClick " , addon.CloseSack )
countLabel = window : CreateFontString ( nil , " ARTWORK " , " GameFontNormal " )
countLabel : SetPoint ( " TOPRIGHT " , titlebg , - 6 , - 3 )
countLabel : SetJustifyH ( " RIGHT " )
countLabel : SetTextColor ( 1 , 1 , 1 , 1 )
sessionLabel = CreateFrame ( " Button " , nil , window )
sessionLabel : SetNormalFontObject ( " GameFontNormalLeft " )
sessionLabel : SetHighlightFontObject ( " GameFontHighlightLeft " )
sessionLabel : SetPoint ( " TOPLEFT " , titlebg , 6 , - 1 )
sessionLabel : SetPoint ( " BOTTOMRIGHT " , titlebg , " BOTTOMRIGHT " , - 26 , 1 )
sessionLabel : RegisterForClicks ( " LeftButtonUp " , " LeftButtonDown " , " RightButtonUp " , " RightButtonDown " )
sessionLabel : SetScript ( " OnHide " , function ( )
window : StopMovingOrSizing ( )
end )
sessionLabel : SetScript ( " OnMouseUp " , function ( )
window : StopMovingOrSizing ( )
end )
sessionLabel : SetScript ( " OnMouseDown " , function ( )
window : StartMoving ( )
end )
sessionLabel : SetScript ( " OnDoubleClick " , function ( )
sessionLabel : Hide ( )
searchLabel : Show ( )
searchBox : Show ( )
searchThrough = currentSackContents
end )
sessionLabel : SetScript ( " OnClick " , function ( self , button )
if button ~= " RightButton " then
return
end
window : Hide ( )
InterfaceOptionsFrame_OpenToCategory ( addonName )
end )
local quickTips = " |cff44ff44Double-click|r to filter bug reports. After you are done with the search results, return to the full sack by selecting a tab at the bottom. |cff44ff44Left-click|r and drag to move the window. |cff44ff44Right-click|r to close the sack and open the interface options for BugSack. "
sessionLabel : SetScript ( " OnEnter " , function ( self )
GameTooltip : SetOwner ( self , " ANCHOR_TOPLEFT " , - 8 , 8 )
GameTooltip : AddLine ( " Quick tips " )
GameTooltip : AddLine ( quickTips , 1 , 1 , 1 , 1 )
GameTooltip : Show ( )
end )
sessionLabel : SetScript ( " OnLeave " , function ( self )
if GameTooltip : IsOwned ( self ) then
GameTooltip : Hide ( )
end
end )
searchLabel = window : CreateFontString ( nil , " ARTWORK " , " GameFontNormal " )
searchLabel : SetText ( " Filter: " )
searchLabel : SetJustifyH ( " LEFT " )
searchLabel : SetPoint ( " TOPLEFT " , titlebg , 6 , - 3 )
searchLabel : SetTextColor ( 1 , 1 , 1 , 1 )
searchLabel : Hide ( )
searchBox = CreateFrame ( " EditBox " , nil , window )
searchBox : SetTextInsets ( 4 , 4 , 0 , 0 )
searchBox : SetMaxLetters ( 50 )
searchBox : SetFontObject ( " ChatFontNormal " )
searchBox : SetScript ( " OnShow " , function ( self )
self : SetFocus ( )
end )
searchBox : SetScript ( " OnHide " , function ( self )
self : ClearFocus ( )
self : SetText ( " " )
end )
searchBox : SetScript ( " OnEscapePressed " , clearSearch )
searchBox : SetScript ( " OnTextChanged " , filterSack )
searchBox : SetAutoFocus ( false )
searchBox : SetPoint ( " TOPLEFT " , searchLabel , " TOPRIGHT " , 6 , 1 )
searchBox : SetPoint ( " BOTTOMRIGHT " , titlebg , " BOTTOMRIGHT " , - 26 , 1 )
searchBox : Hide ( )
local searchBackdrop = searchBox : CreateTexture ( nil , " BACKGROUND " )
searchBackdrop : SetAllPoints ( )
searchBackdrop : SetColorTexture ( 0 , 0 , 0 , 0.5 )
nextButton = CreateFrame ( " Button " , " BugSackNextButton " , window , " UIPanelButtonTemplate " )
nextButton : SetPoint ( " BOTTOMRIGHT " , window , - 11 , 16 )
nextButton : SetFrameStrata ( " FULLSCREEN " )
nextButton : SetWidth ( 130 )
nextButton : SetText ( L [ " Next > " ] )
nextButton : SetScript ( " OnClick " , function ( )
if IsShiftKeyDown ( ) then
currentErrorIndex = # currentSackContents
else
currentErrorIndex = currentErrorIndex + 1
end
updateSackDisplay ( )
end )
prevButton = CreateFrame ( " Button " , " BugSackPrevButton " , window , " UIPanelButtonTemplate " )
prevButton : SetPoint ( " BOTTOMLEFT " , window , 14 , 16 )
prevButton : SetFrameStrata ( " FULLSCREEN " )
prevButton : SetWidth ( 130 )
prevButton : SetText ( L [ " < Previous " ] )
prevButton : SetScript ( " OnClick " , function ( )
if IsShiftKeyDown ( ) then
currentErrorIndex = 1
else
currentErrorIndex = currentErrorIndex - 1
end
updateSackDisplay ( )
end )
if addon.Serialize then
sendButton = CreateFrame ( " Button " , " BugSackSendButton " , window , " UIPanelButtonTemplate " )
sendButton : SetPoint ( " LEFT " , prevButton , " RIGHT " )
sendButton : SetPoint ( " RIGHT " , nextButton , " LEFT " )
sendButton : SetFrameStrata ( " FULLSCREEN " )
sendButton : SetText ( L [ " Send bugs " ] )
sendButton : SetScript ( " OnClick " , function ( )
local eo = currentSackContents [ currentErrorIndex ]
local popup = StaticPopup_Show ( " BugSackSendBugs " , eo.session )
popup.data = eo.session
window : Hide ( )
end )
end
local scroll = CreateFrame ( " ScrollFrame " , " BugSackScroll " , window , " UIPanelScrollFrameTemplate " )
scroll : SetPoint ( " TOPLEFT " , window , " TOPLEFT " , 16 , - 36 )
scroll : SetPoint ( " BOTTOMRIGHT " , nextButton , " TOPRIGHT " , - 24 , 8 )
textArea = CreateFrame ( " EditBox " , " BugSackScrollText " , scroll )
textArea : SetTextColor ( .5 , .5 , .5 , 1 )
textArea : SetAutoFocus ( false )
textArea : SetMultiLine ( true )
textArea : SetFontObject ( _G [ addon.db . fontSize ] or GameFontHighlightSmall )
textArea : SetMaxLetters ( 99999 )
textArea : EnableMouse ( true )
textArea : SetScript ( " OnEscapePressed " , textArea.ClearFocus )
textArea : SetWidth ( 450 )
scroll : SetScrollChild ( textArea )
local all = CreateFrame ( " Button " , " BugSackTabAll " , window , " CharacterFrameTabButtonTemplate " )
all : SetFrameStrata ( " FULLSCREEN " )
all : SetPoint ( " TOPLEFT " , window , " BOTTOMLEFT " , 0 , 8 )
all : SetText ( L [ " All bugs " ] )
all : SetScript ( " OnLoad " , nil )
all : SetScript ( " OnShow " , nil )
all : SetScript ( " OnClick " , setActiveMethod )
all.bugs = " all "
local session = CreateFrame ( " Button " , " BugSackTabSession " , window , " CharacterFrameTabButtonTemplate " )
session : SetFrameStrata ( " FULLSCREEN " )
session : SetPoint ( " LEFT " , all , " RIGHT " )
session : SetText ( L [ " Current session " ] )
session : SetScript ( " OnLoad " , nil )
session : SetScript ( " OnShow " , nil )
session : SetScript ( " OnClick " , setActiveMethod )
session.bugs = " currentSession "
local last = CreateFrame ( " Button " , " BugSackTabLast " , window , " CharacterFrameTabButtonTemplate " )
last : SetFrameStrata ( " FULLSCREEN " )
last : SetPoint ( " LEFT " , session , " RIGHT " )
last : SetText ( L [ " Previous session " ] )
last : SetScript ( " OnLoad " , nil )
last : SetScript ( " OnShow " , nil )
last : SetScript ( " OnClick " , setActiveMethod )
last.bugs = " previousSession "
tabs = { all , session , last }
local size = 500 / 3
for i , t in next , tabs do
PanelTemplates_TabResize ( t , nil , size , size )
if i == 1 then
PanelTemplates_SelectTab ( t )
else
PanelTemplates_DeselectTab ( t )
end
end
end
-- Called when the sack is supposed to be opened or refreshed,
-- and can only be called by :OpenSack or something that is available
-- from the sack window, so we know that currentSackContents is set.
local function show ( )
if createBugSack then
createBugSack ( )
createBugSack = nil
end
updateSackDisplay ( true )
window : Show ( )
end
function addon : CloseSack ( )
window : Hide ( )
end
function addon : OpenSack ( )
if window and window : IsShown ( ) then
-- Window is already open, we just need to update various texts.
return
end
-- XXX we should show the most recent error (from this session) that has not previously been shown in the sack
-- XXX so, 5 errors are caught, the user clicks the icon, we start it at the first of those 5 errors.
--[[if not currentSackContents then
currentSackContents = BugGrabber : GetDB ( currentSackSession )
end ] ]
show ( )
end