chore: move addon into Chatter/ + add standard .gitignore

Matches the Exiles fork-layout convention (each addon in its own folder).
This commit is contained in:
2026-05-25 10:59:27 +02:00
parent 7462acab8c
commit 5eaec81f02
50 changed files with 7 additions and 0 deletions
+135
View File
@@ -0,0 +1,135 @@
local mod = Chatter:NewModule("All Edge resizing","AceHook-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["All Edge resizing"]
function mod:Info()
return L["Allows you to use the edge for resizing, instead of just the lower right corner."]
end
local anchorPoints = { "TopLeft", "TopRight", "BottomLeft", "BottomRight", "Top", "Right", "Left", "Bottom" }
function mod:OnInitialize()
end
local function ChatFrame_StartResizing(self)
local chatFrame = self:GetParent()
if chatFrame.isLocked then return end
if chatFrame.isDocked and chatFrame ~= DEFAULT_CHAT_FRAME then return end
chatFrame.resizing = 1
chatFrame:StartSizing(self.anchorPoint)
end
local function ChatFrame_StopResizing(self)
local chatFrame = self:GetParent()
chatFrame:StopMovingOrSizing()
if chatFrame == DEFAULT_CHAT_FRAME then
FCF_DockUpdate()
end
chatFrame.resizing = nil
FCF_SavePositionAndDimensions(chatFrame);
end
function mod:SetChatWindowLocked(index, locked, ...)
local f = _G["ChatFrame" .. index]
for _, v in ipairs(anchorPoints) do
local k = "resize" .. v
if f[k] then
f[k]:EnableMouse(not locked)
end
end
return self.hooks.SetChatWindowLocked(index, locked, ...)
end
function mod:MakeResizers(frame)
local f = frame
if not f.resizeTopLeft then
f.background = _G[("ChatFrame%dBackground"):format(frame:GetID())]
for _, v in ipairs(anchorPoints) do
local k = "resize" .. v
f[k] = CreateFrame("Button", "ChatFrame" .. frame:GetID() .. "Resize" .. v, f)
f[k].anchorPoint = v:upper()
f[k]:SetWidth(16)
f[k]:SetHeight(16)
f[k]:SetScript("OnMouseDown", ChatFrame_StartResizing)
f[k]:SetScript("OnMouseUp", ChatFrame_StopResizing)
LowerFrameLevel(f[k])
end
f.resizeTopLeft:SetPoint("TOPLEFT", f.background, -2, 2)
f.resizeTopRight:SetPoint("TOPRIGHT", f.background, 2, 2)
f.resizeBottomLeft:SetPoint("BOTTOMLEFT", f.background, -2, -3)
f.resizeBottomRight:SetPoint("BOTTOMRIGHT", f.background, 2, -3)
f.resizeTop:SetPoint("LEFT", f.resizeTopLeft, "RIGHT", 0, 0)
f.resizeTop:SetPoint("RIGHT", f.resizeTopRight, "LEFT", 0, 0)
f.resizeRight:SetPoint("TOP", f.resizeTopRight, "BOTTOM", 0, 0)
f.resizeRight:SetPoint("BOTTOM", f.resizeBottomRight, "TOP", 0, 0)
f.resizeBottom:SetPoint("LEFT", f.resizeBottomLeft, "RIGHT", 0, 0)
f.resizeBottom:SetPoint("RIGHT", f.resizeBottomRight, "LEFT", 0, 0)
f.resizeLeft:SetPoint("TOP", f.resizeTopLeft, "BOTTOM", 0, 0)
f.resizeLeft:SetPoint("BOTTOM", f.resizeBottomLeft, "TOP", 0, 0)
else
f.resizeTopLeft:Show()
f.resizeTopRight:Show()
f.resizeBottomLeft:Show()
f.resizeBottomRight:Show()
f.resizeTop:Show()
f.resizeTop:Show()
f.resizeRight:Show()
f.resizeRight:Show()
f.resizeBottom:Show()
f.resizeBottom:Show()
f.resizeLeft:Show()
f.resizeLeft:Show()
end
end
function mod:HideResizers(f)
f.resizeTopLeft:Hide()
f.resizeTopRight:Hide()
f.resizeBottomLeft:Hide()
f.resizeBottomRight:Hide()
f.resizeTop:Hide()
f.resizeTop:Hide()
f.resizeRight:Hide()
f.resizeRight:Hide()
f.resizeBottom:Hide()
f.resizeBottom:Hide()
f.resizeLeft:Hide()
f.resizeLeft:Hide()
end
function mod:OnEnable()
for i = 1, NUM_CHAT_WINDOWS do
local f = _G[("ChatFrame%d"):format(i)]
self:MakeResizers(f)
local b = _G[("ChatFrame%dResizeButton"):format(i)]
b:SetScript("OnShow", b.Hide)
b:Hide()
end
for index,name in ipairs(self.TempChatFrames) do
local f = _G[name]
self:MakeResizers(f)
local b = _G[("ChatFrame%dResizeButton"):format(f:GetID())]
b:SetScript("OnShow", b.Hide)
b:Hide()
end
self:RawHook("SetChatWindowLocked",true)
end
function mod:OnDisable()
for i = 1, NUM_CHAT_WINDOWS do
local f = _G["ChatFrame"..i]
self:HideResizers(f)
local b = _G[("ChatFrame%dResizeButton"):format(f:GetID())]
b:SetScript("OnShow", b.Show)
b:Show()
end
for index,name in ipairs(self.TempChatFrames) do
local f = _G[name]
self:HideResizers(f)
local b = _G[("ChatFrame%dResizeButton"):format(f:GetID())]
b:SetScript("OnShow", b.Show)
b:Show()
end
self:UnhookAll()
end
+352
View File
@@ -0,0 +1,352 @@
local mod = Chatter:NewModule("Alt Linking", "AceHook-3.0", "AceEvent-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["Alt Linking"]
local NAMES
local GUILDNOTES
local pairs = _G.pairs
local select = _G.select
local setmetatable = _G.setmetatable
local tinsert = _G.tinsert
local tremove = _G.tremove
local type = _G.type
local unpack = _G.unpack
local strlower= _G.string.lower
local gmatch = _G.string.gmatch
local leftBracket, rightBracket
local defaults = {
realm = {},
profile = {
guildNotes=true,
altNotesFallback=true,
colorMode = "COLOR_MOD",
color = {0.6, 0.6, 0.6},
leftBracket = "[",
rightBracket = "]",
}
}
local colorModes = {
COLOR_MOD = L["Use PlayerNames coloring"],
CUSTOM = L["Use custom color"],
CHANNEL = L["Use channel color"]
}
local customColorNames = setmetatable({}, {
__index = function(t, v)
local r, g, b = unpack(mod.db.profile.color)
t[v] = ("|cff%02x%02x%02x%s|r"):format(r * 255, g * 255, b * 255, v)
return t[v]
end
})
local options
function mod:GetOptions()
options = options or {
guildNotes = {
order=100,
type = "toggle",
name = L["Use guildnotes"],
desc = L["Look in guildnotes for character names, unless a note is set manually"],
get = function()
return mod.db.profile.guildNotes
end,
set = function(info, v)
mod.db.profile.guildNotes = v
mod:EnableGuildNotes(v)
end,
},
altNotesFallback = {
order=101,
type = "toggle",
name = L["Alt note fallback"],
desc = L["If no name can be found for an 'alt' rank character, use entire note"],
disabled = function()
return not mod.db.profile.guildNotes
end,
get = function()
return mod.db.profile.altNotesFallback
end,
set = function(info, v)
mod.db.profile.altNotesFallback = v
mod:ScanGuildNotes()
end,
},
colorMode = {
order=110,
type = "select",
name = L["Name color"],
desc = L["Set the coloring mode for alt names"],
values = colorModes,
get = function()
return mod.db.profile.colorMode
end,
set = function(info, v)
mod.db.profile.colorMode = v
end
},
color = {
order=111,
type = "color",
name = L["Custom color"],
desc = L["Select the custom color to use for alt names"],
get = function()
return unpack(mod.db.profile.color)
end,
set = function(info, r, g, b)
mod.db.profile.color[1] = r
mod.db.profile.color[2] = g
mod.db.profile.color[3] = b
for k, v in pairs(customColorNames) do
customColorNames[k] = nil
end
end,
disabled = function() return mod.db.profile.colorMode ~= "CUSTOM" end
},
leftbracket = {
type = "input",
name = L["Left Bracket"],
desc = L["Character to use for the left bracket"],
get = function() return mod.db.profile.leftBracket end,
set = function(i, v)
mod.db.profile.leftBracket = v
leftBracket = v
end
},
rightbracket = {
type = "input",
name = L["Right Bracket"],
desc = L["Character to use for the right bracket"],
get = function() return mod.db.profile.rightBracket end,
set = function(i, v)
mod.db.profile.rightBracket = v
rightBracket = v
end
},
}
return options
end
local accept = function(self, char)
local editBox = _G[this:GetParent():GetName().."EditBox"]
local main = editBox:GetText()
mod:AddAlt(char, main)
this:GetParent():Hide()
end
StaticPopupDialogs['MENUITEM_SET_MAIN'] = {
text = L["Who is %s's main?"],
button1 = TEXT(ACCEPT),
button2 = TEXT(CANCEL),
hasEditBox = 1,
maxLetters = 128,
exclusive = 0,
OnShow = function()
_G[this:GetName().."EditBox"]:SetFocus()
end,
OnHide = function()
if ( _G[this:GetName().."EditBox"]:IsShown() ) then
_G[this:GetName().."EditBox"]:SetFocus();
end
_G[this:GetName().."EditBox"]:SetText("");
end,
OnAccept = accept,
EditBoxOnEnterPressed = accept,
EditBoxOnEscapePressed = function() this:GetParent():Hide() end,
timeout = 0,
whileDead = 1,
hideOnEscape = 1
}
UnitPopupButtons["SET_MAIN"] = {
text = L["Set Main"],
dist = 0,
func = mod.GetMainName
}
function mod:OnInitialize()
self.db = Chatter.db:RegisterNamespace("AltLinks", defaults)
end
function mod:Decorate(frame)
if not self:IsHooked(frame,"AddMessage") then
self:RawHook(frame, "AddMessage", true)
end
end
function mod:OnEnable()
NAMES = self.db.realm
UnitPopupButtons["SET_MAIN"].func = self.GetMainName
tinsert(UnitPopupMenus["SELF"], #UnitPopupMenus["SELF"] - 1, "SET_MAIN")
tinsert(UnitPopupMenus["PLAYER"], #UnitPopupMenus["PLAYER"] - 1, "SET_MAIN")
tinsert(UnitPopupMenus["FRIEND"], #UnitPopupMenus["FRIEND"] - 1, "SET_MAIN")
tinsert(UnitPopupMenus["PARTY"], #UnitPopupMenus["PARTY"] - 1, "SET_MAIN")
self:SecureHook("UnitPopup_ShowMenu")
leftBracket, rightBracket = self.db.profile.leftBracket, self.db.profile.rightBracket
mod:EnableGuildNotes(mod.db.profile.guildNotes)
for i = 1, NUM_CHAT_WINDOWS do
local cf = _G["ChatFrame" .. i]
if cf ~= COMBATLOG then
self:RawHook(cf, "AddMessage", true)
end
end
for index,name in ipairs(self.TempChatFrames) do
local cf = _G[name]
if cf then
self:RawHook(cf, "AddMessage", true)
end
end
self.colorMod = Chatter:GetModule("Player Class Colors")
end
local types = {"SELF", "PLAYER", "FRIEND", "PARTY"}
function mod:OnDisable()
for j = 1, #types do
local t = types[j]
for i = 1, #UnitPopupMenus[t] do
if UnitPopupMenus[t][i] == "SET_MAIN" then
tremove(UnitPopupMenus[t], i)
break
end
end
end
mod:EnableGuildNotes(false)
end
function mod.GetMainName()
local alt = UIDROPDOWNMENU_INIT_MENU.name
local popup = StaticPopup_Show("MENUITEM_SET_MAIN", alt)
if popup then
popup.data = alt
local editbox = getglobal(popup:GetName().."EditBox")
editbox:SetText(NAMES[alt] or GUILDNOTES[alt] or "")
editbox:HighlightText()
end
end
function mod:UnitPopup_ShowMenu(dropdownMenu, which, unit, name, userData, ...)
for i=1, UIDROPDOWNMENU_MAXBUTTONS do
local button = _G["DropDownList"..UIDROPDOWNMENU_MENU_LEVEL.."Button"..i];
if button.value == "SET_MAIN" then
button.func = UnitPopupButtons["SET_MAIN"].func
end
end
end
function mod:AddAlt(alt, main)
if #main == 0 then
if GUILDNOTES[alt] then
-- let the user store an empty note, meaning "dont show me this main"
else
main = nil
end
end
NAMES[alt] = main
end
local function pName(msg, name)
if name and #name > 0 then
local alt = NAMES[name] or GUILDNOTES[name]
if alt and alt ~= "" then -- empty notes can be stored to override guildnote data
local mode = mod.db.profile.colorMode
if mode == "CUSTOM" then
alt = customColorNames[alt]
elseif mode == "COLOR_MOD" and mod.colorMod and mod.colorMod:IsEnabled() then
alt = mod.colorMod:ColorName(alt)
end
return ("%s%s%s%s"):format( msg, leftBracket, alt, rightBracket )
end
end
return msg
end
function mod:AddMessage(frame, text, ...)
if text and type(text) == "string" then
--text = text:gsub("(|Hplayer:([^:]+)[:%d+]*|h.-|h)", pName)
text = text:gsub("(|Hplayer:([^:]+).-|h.-|h)", pName)
end
return self.hooks[frame].AddMessage(frame, text, ...)
end
function mod:Info()
return L["Enables you to right-click a person's name in chat and set a note on them to be displayed in chat, such as their main character's name. Can also scan guild notes for character names to display, if no note has been manually set."]
end
function mod:EnableGuildNotes(enable)
GUILDNOTES={}
if enable then
mod:RegisterEvent("GUILD_ROSTER_UPDATE")
if IsInGuild() then
GuildRoster()
end
mod:ScanGuildNotes() -- Unfortunately we can't count on GuildRoster() triggering the event if someone else triggered it recently. So we try once at first straight off the bat.
else
mod:UnregisterEvent("GUILD_ROSTER_UPDATE")
end
end
local doscan=true -- always the first time we start up
function mod:GUILD_ROSTER_UPDATE(event,arg1)
-- arg1 gets set for SOME changes to the guild, but notably not for player notes.. doh (unless you're the one editing them yourself)
-- we force a scan when the guild frame is actually visible (i.e. when we know the player is actually interested in seeing changes)
-- i'd like to be able to not have the guildframe check there, but there's plenty of stupid-ass addons that spam GuildRoster() every 10/15/20 seconds, so ... no.
if arg1 or GuildFrame:IsVisible() or doscan then
doscan=false
mod:ScanGuildNotes()
end
if arg1 then
-- but it appears that when arg1 is set, the player note change isn't available yet; that happens on the next arg1=nil update (about 0.1s later), so catch that one too. ghod this is messy.
doscan=true
end
end
function mod:ScanGuildNotes()
if not IsInGuild() then
return
end
--DBG print("Scanning guildnotes!")
--DBG local n,nFallback=0,0
local names = {} -- ["playername"]="Playername" (note lowercase = uppercase) (yes, this works for 'foreign' letters too in WoW, even though it does not in standard Lua)
GUILDNOTES = {} -- Yes, we do want to zap it, otherwise we end up storing notes for people being promoted/demoted through alt ranks and stuff
-- #1: find all names
for i=1,GetNumGuildMembers(true) do
local name = GetGuildRosterInfo(i)
names[strlower(name or "?")] = name
end
-- #2: scan all words in all guild notes, see if a name is mentioned
for i=1,GetNumGuildMembers(true) do
local name, rank, rankIndex, level, class, zone, note, officernote, online, status = GetGuildRosterInfo(i);
local success
for word in gmatch(strlower(note or ""), "[%a\128-\255]+") do
if names[word] then
GUILDNOTES[name] = names[word]
success = true
--DBG n=n+1
break
end
end
if not success and mod.db.profile.altNotesFallback and note and note~="" then
-- #3: no joy? then if this is an 'alt' rank, use the entire note
rank=strlower(rank or "")
if strfind(rank, "alt") or
strfind(rank, L["alt2"]) or
strfind(rank, L["alt3"]) then
GUILDNOTES[name] = note
--DBG print("Fallback: ",note)
--DBG nFallback=nFallback+1
end
end
end
--DBG print("Mapped",n,"names and",nFallback,"fallbacks!")
end
+16
View File
@@ -0,0 +1,16 @@
local mod = Chatter:NewModule("Chat Autolog")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["Chat Autolog"]
function mod:OnEnable()
self.isLogging = LoggingChat()
LoggingChat(true)
end
function mod:OnDisable()
LoggingChat(self.isLogging)
end
function mod:Info()
return L["Automatically turns on chat logging."]
end
+84
View File
@@ -0,0 +1,84 @@
local mod = Chatter:NewModule("Automatic Whisper Windows", "AceHook-3.0", "AceEvent-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["Automatic Whisper Windows"]
function mod:OnEnable()
self:RegisterEvent("CHAT_MSG_WHISPER","ProcessWhisper")
self:RegisterEvent("CHAT_MSG_WHISPER_INFORM","ProcessWhisper")
self:RegisterEvent("CHAT_MSG_BN_WHISPER_INFORM", "ProcessWhisper")
self:RegisterEvent("CHAT_MSG_BN_WHISPER","ProcessWhisper")
end
function mod:OnDisable()
self:UnregisterEvent("CHAT_MSG_WHISPER")
self:UnregisterEvent("CHAT_MSG_WHISPER_INFORM")
self:UnregisterEvent("CHAT_MSG_BNWHISPER")
self:UnregisterEvent("CHAT_MSG_BNWHISPER_INFORM")
end
function mod:AlwaysDecorate(frame)
if not self:IsEnabled() then
local t = frame.chatType
local a = frame.chatTarget
local accessID = ChatHistory_GetAccessID(t, a)
local chatFrame = nil
for i= 1,NUM_CHAT_WINDOWS do
local cf = _G["ChatFrame"..i]
local i = cf:GetNumMessages(accessID)
if i > 0 then
chatFrame = cf
end
end
if chatFrame then
Chatter.loading = true
for i = 1, chatFrame:GetNumMessages(accessID) do
local text, accessID, lineID, extraData = chatFrame:GetMessageInfo(i, accessID);
local cType, cTarget = ChatHistory_GetChatType(extraData);
local info = ChatTypeInfo[cType];
frame:AddMessage(text, info.r, info.g, info.b, lineID, false, accessID, extraData);
end
Chatter.loading = false
end
end
end
function mod:ProcessWhisper(event,message,sender,language,channelString,target,flags,arg7,arg8,...)
-- Do we have a temp window already for this target
local type = "WHISPER"
if event == "CHAT_MSG_BN_WHISPER" or event == "CHAT_MSG_BN_WHISPER_INFORM" then
type = "BN_WHISPER"
end
if FCFManager_GetNumDedicatedFrames(type, sender) == 0 then
local chatFrame = nil
local foundSrc = false
local accessID = ChatHistory_GetAccessID(type, sender)
for i= 1,NUM_CHAT_WINDOWS do
local cf = _G["ChatFrame"..i]
if not foundSrc then
for i = 1, cf:GetNumMessages(accessID) do
chatFrame = cf
foundSrc = true
end
end
end
if not chatFrame then
return true
end
Chatter.loading = true
local t = FCF_OpenTemporaryWindow(type, sender, chatFrame, true)
-- lets hand copy the shit over
for i = 1, chatFrame:GetNumMessages(accessID) do
local text, accessID, lineID, extraData = chatFrame:GetMessageInfo(i, accessID);
local cType, cTarget = ChatHistory_GetChatType(extraData);
local info = ChatTypeInfo[cType];
t:AddMessage(text, info.r, info.g, info.b, lineID, false, accessID, extraData);
end
Chatter.loading = false
-- was a fix for an issue in the editbox, no longer needed
--for i=1,NUM_CHAT_WINDOWS do
-- local cf = _G["ChatFrame"..i.."EditBox"]
-- cf:Show()
--end
end
end
+131
View File
@@ -0,0 +1,131 @@
-- Strip icons like |TInterface\\FriendsFrame\\UI-Toast-ToastIcons.tga:16:16:0:0:128:64:2:29:34:61
local mod = Chatter:NewModule("BNet", "AceHook-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["RealID Polish"]
local defaults = {
profile = {
toastx = 0,
toasty = 0,
showToast = false
}
}
local options
function mod:GetOptions()
options = options or {
showToastIcons = {
order=100,
type = "toggle",
name = L["Show Toast Icons"],
desc = L["Show toast icons in the chat frames"],
get = function()
return mod.db.profile.showToast
end,
set = function(info, v)
mod.db.profile.showToast = v
end,
},
toastWindowXoffset = {
order=101,
type = "range",
min = -4000,
max = 4000,
name = L["Toast X offset"],
desc = L["Move the Toast X offset to ChatFrame1"],
step = 1,
bigStep = 1,
get = function()
return mod.db.profile.toastx
end,
set = function(info, v)
mod.db.profile.toastx = v
mod:UpdateToastOffsets()
end,
},
toastWindowYoffset = {
order=102,
type = "range",
min = -4000,
max = 4000,
name = L["Toast Y offset"],
desc = L["Move the Toast Y offset, relative to ChatFrame1"],
step = 1,
bigStep = 1,
get = function()
return mod.db.profile.toasty
end,
set = function(info, v)
mod.db.profile.toasty = v
mod:UpdateToastOffsets()
end,
},
testToast = {
order=103,
name = L["Test"],
type = "execute",
func = function() BNToastFrame_AddToast(BN_TOAST_TYPE_NEW_INVITE) end,
}
}
return options
end
function mod:UpdateToastOffsets()
if self:IsEnabled() then
local cf = DEFAULT_CHAT_FRAME
local bside = cf.buttonSide
local cfTop = cf.buttonFrame:GetTop() or 0
local bnH = BNToastFrame:GetHeight() or 0
local offscreen = cfTop + bnH + BN_TOAST_TOP_OFFSET + BN_TOAST_TOP_BUFFER > GetScreenHeight();
BN_TOAST_LEFT_OFFSET = 1 + self.db.profile.toastx
if bside == "right" then
BN_TOAST_RIGHT_OFFSET = -1 + self.db.profile.toastx
end
BN_TOAST_TOP_OFFSET = 40 + self.db.profile.toasty
if offscreen then
BN_TOAST_BOTTOM_OFFSET = -12 + self.db.profile.toasty
end
BNToastFrame_UpdateAnchor(true)
end
end
function mod:OnInitialize()
self.db = Chatter.db:RegisterNamespace("RealIdPolish", defaults)
end
function mod:OnDisable()
self:UnhookAll()
BN_TOAST_TOP_OFFSET = 40
BN_TOAST_BOTTOM_OFFSET = -12
BN_TOAST_RIGHT_OFFSET = -1
BN_TOAST_LEFT_OFFSET = 1
BN_TOAST_TOP_BUFFER = 20
BN_TOAST_MAX_LINE_WIDTH = 196
end
function mod:OnEnable()
for i = 1, NUM_CHAT_WINDOWS do
local cf = _G["ChatFrame" .. i]
if cf ~= COMBATLOG then
self:RawHook(cf, "AddMessage", true)
end
end
self:Hook("BNToastFrame_Close",true)
self:UpdateToastOffsets()
end
function mod:BNToastFrame_Close()
self:UpdateToastOffsets()
end
function mod:ParseLinks(text)
if not text then return nil end
if mod.db.profile.showToast then return text end
text = gsub(text, "(|TInterface(.*)ToastIcons.tga([:%d]*)|t)", "")
return text
end
function mod:AddMessage(frame, text, ...)
return self.hooks[frame].AddMessage(frame, mod:ParseLinks(text), ...)
end
+234
View File
@@ -0,0 +1,234 @@
local mod = Chatter:NewModule("Disable Buttons", "AceHook-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["Disable Buttons"]
local fmt = _G.string.format
local function hide(self)
if not self.override then
self:Hide()
end
self.override = nil
end
local options = {
bottomButton = {
type = "toggle",
name = L["Show bottom when scrolled"],
desc = L["Show bottom button when scrolled up"],
width = "double",
get = function()
return mod.db.profile.scrollReminder
end,
set = function(info, v)
mod.db.profile.scrollReminder = v
if v then
mod:EnableBottomButton()
else
mod:DisableBottomButton()
end
end
}
}
local bottomButtons = {}
local defaults = { profile = {} }
local clickFunc = function(self) self:GetParent():ScrollToBottom() end
function mod:OnInitialize()
self.db = Chatter.db:RegisterNamespace("Buttons", defaults)
for i = 1, NUM_CHAT_WINDOWS do
local f = _G["ChatFrame" .. i]
local button = CreateFrame("Button", nil, f)
button:SetNormalTexture([[Interface\ChatFrame\UI-ChatIcon-ScrollEnd-Up]])
button:SetPushedTexture([[Interface\ChatFrame\UI-ChatIcon-ScrollEnd-Down]])
button:SetDisabledTexture([[Interface\ChatFrame\UI-ChatIcon-ScrollEnd-Disabled]])
button:SetHighlightTexture([[Interface\Buttons\UI-Common-MouseHilight]])
button:SetWidth(20)
button:SetHeight(20)
button:SetPoint("TOPRIGHT", f, "TOPRIGHT", 0, 0)
button:SetScript("OnClick", clickFunc)
button:Hide()
f.downButton = button
end
self:SecureHook("FCF_RestorePositionAndDimensions")
end
function mod:Decorate(frame)
local button = CreateFrame("Button", nil, frame)
button:SetNormalTexture([[Interface\ChatFrame\UI-ChatIcon-ScrollEnd-Up]])
button:SetPushedTexture([[Interface\ChatFrame\UI-ChatIcon-ScrollEnd-Down]])
button:SetDisabledTexture([[Interface\ChatFrame\UI-ChatIcon-ScrollEnd-Disabled]])
button:SetHighlightTexture([[Interface\Buttons\UI-Common-MouseHilight]])
button:SetWidth(20)
button:SetHeight(20)
button:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, 0)
button:SetScript("OnClick", clickFunc)
button:Hide()
frame.downButton = button
-- Adjust the menu buttons
self:ApplyFrameChanges(frame)
if(self.db.profile.scrollReminder) then self:ApplyBottomButton(frame) end
end
function mod:FCF_RestorePositionAndDimensions(chatFrame)
if Chatter.db.profile.modules[mod:GetName()] then
chatFrame:SetClampRectInsets(0, 0, 0, 0)
end
end
-- Fix the jump in
for i = 1, NUM_CHAT_WINDOWS do
local f = _G["ChatFrame" .. i]
f:SetClampRectInsets(0, 0, 0, 0)
end
function mod:ApplyFrameChanges(f)
f:SetClampRectInsets(0, 0, 0, 0)
local ff = _G[f:GetName() .. "ButtonFrame"]
ff:Hide()
ff:SetScript("OnShow", hide)
end
function mod:OnEnable()
ChatFrameMenuButton:Hide()
ChatFrameMenuButton:SetScript("OnShow", hide)
FriendsMicroButton:Hide()
FriendsMicroButton:SetScript("OnShow", hide)
for i = 1, NUM_CHAT_WINDOWS do
local f = _G["ChatFrame" .. i]
self:ApplyFrameChanges(f)
end
if(self.db.profile.scrollReminder) then self:EnableBottomButton() end
for index,frame in ipairs(self.TempChatFrames) do
local f = _G[frame]
self:ApplyFrameChanges(f)
end
end
function mod:UnDecorate(frame)
frame:SetClampRectInsets(-35, 35, 26, -50)
-- Reset the postion so if the buttons were offscreen frame goes to where it should be
if frame:IsMovable() then
FCF_RestorePositionAndDimensions(frame)
end
local ff = _G[frame:GetName() .. "ButtonFrame"]
ff:Show()
ff:SetScript("OnShow", nil)
end
function mod:OnDisable()
ChatFrameMenuButton:Show()
ChatFrameMenuButton:SetScript("OnShow", nil)
FriendsMicroButton:Show()
FriendsMicroButton:SetScript("OnShow", nil)
self:DisableBottomButton()
for i = 1, NUM_CHAT_WINDOWS do
local f = _G["ChatFrame" .. i]
self:UnDecorate(f)
end
for index,frame in ipairs(self.TempChatFrames) do
local f = _G[frame]
self:UnDecorate(f)
end
end
function mod:Info()
return L["Hides the buttons attached to the chat frame"]
end
function mod:ApplyBottomButton(frame)
if self:IsHooked(frame,"ScrollUp") then
return nil
end
self:Hook(frame, "ScrollUp", true)
self:Hook(frame, "ScrollToTop", "ScrollUp", true)
self:Hook(frame, "PageUp", "ScrollUp", true)
self:Hook(frame, "ScrollDown", true)
self:Hook(frame, "ScrollToBottom", "ScrollDownForce", true)
self:Hook(frame, "PageDown", "ScrollDown", true)
if frame:GetCurrentScroll() ~= 0 then
frame.downButton:Show()
end
if frame ~= COMBATLOG then
self:Hook(frame, "AddMessage", true)
end
end
function mod:EnableBottomButton()
if self.buttonsEnabled then return end
self.buttonsEnabled = true
for i = 1, NUM_CHAT_WINDOWS do
local f = _G["ChatFrame" .. i]
if f then
self:ApplyBottomButton(f)
end
end
for index,frame in ipairs(self.TempChatFrames) do
local f = _G[frame]
if f then
self:ApplyBottomButton(f)
end
end
end
function mod:UnApplyBottomButton(f)
self:Unhook(f, "ScrollUp")
self:Unhook(f, "ScrollToTop")
self:Unhook(f, "PageUp")
self:Unhook(f, "ScrollDown")
self:Unhook(f, "ScrollToBottom")
self:Unhook(f, "PageDown")
if f ~= COMBATLOG then
self:Unhook(f, "AddMessage")
end
f.downButton:Hide()
end
function mod:DisableBottomButton()
if not self.buttonsEnabled then return end
self.buttonsEnabled = false
for i = 1, NUM_CHAT_WINDOWS do
local f = _G["ChatFrame" .. i]
if f then
self:UnApplyBottomButton(f)
end
end
for index,frame in ipairs(self.TempChatFrames) do
local f = _G[frame]
if f then
self:UnApplyBottomButton(f)
end
end
end
function mod:ScrollUp(frame)
frame.downButton:Show()
frame.downButton:UnlockHighlight()
end
function mod:ScrollDown(frame)
if frame:GetCurrentScroll() == 0 then
frame.downButton:Hide()
frame.downButton:UnlockHighlight()
end
end
function mod:ScrollDownForce(frame)
frame.downButton:Hide()
frame.downButton:UnlockHighlight()
end
function mod:AddMessage(frame, text, ...)
if frame:GetCurrentScroll() > 0 then
frame.downButton:Show()
frame.downButton:LockHighlight()
else
frame.downButton:Hide()
frame.downButton:UnlockHighlight()
end
end
function mod:GetOptions()
return options
end
+114
View File
@@ -0,0 +1,114 @@
local mod = Chatter:NewModule("Channel Colors", "AceEvent-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["Channel Colors"]
local GetChannelList = _G.GetChannelList
local GetChannelName = _G.GetChannelName
local GetMessageTypeColor = _G.GetMessageTypeColor
local select = _G.select
local tonumber = _G.tonumber
local type = _G.type
function mod:Info()
return L["Keeps your channel colors by name rather than by number."]
end
local defaults = {
profile = { colors = {} }
}
local options = {
splitter = {
type = "header",
name = L["Other Channels"],
order = 49
}
}
function mod:OnInitialize()
self.db = Chatter.db:RegisterNamespace("ChannelColors", defaults)
end
function mod:OnEnable()
self:RegisterEvent("UPDATE_CHAT_COLOR")
self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE")
self:AddChannels(GetChannelList())
self:AddChannels(
"SAY", L["Say"],
"YELL", L["Yell"],
"GUILD", L["Guild"],
"OFFICER", L["Officer"],
"PARTY", L["Party"],
"PARTY_LEADER", PARTY_LEADER,
"RAID", L["Raid"],
"RAID_LEADER", L["Raid Leader"],
"RAID_WARNING", L["Raid Warning"],
"BATTLEGROUND", L["Battleground"],
"BATTLEGROUND_LEADER", L["Battleground Leader"],
"WHISPER", L["Whisper"],
"BN_WHISPER", L["RealID Whisper"],
"BN_CONVERSATION", L["RealID Conversation"]
)
end
function mod:AddChannels(...)
for i = 1, select("#", ...), 2 do
local id, name = select(i, ...)
self.db.profile.colors[name] = self.db.profile.colors[name] or {}
if not self.db.profile.colors[name].r then
local r, g, b = GetMessageTypeColor(type(id) == "number" and ("CHANNEL" .. id) or id)
self.db.profile.colors[name].r = r
self.db.profile.colors[name].g = g
self.db.profile.colors[name].b = b
end
if not options[name:gsub(" ", "_")] then
options[name:gsub(" ", "_")] = {
type = "color",
name = name,
desc = L["Select a color for this channel"],
order = type(id) == "number" and (50 + id) or 48,
get = function()
local c = self.db.profile.colors[name]
if c then
return c.r, c.g, c.b
else
return GetMessageTypeColor(type(id) == "number" and ("CHANNEL" .. id) or id)
end
end,
set = function(info, r, g, b)
self.db.profile.colors[name] = self.db.profile.colors[name] or {}
self.db.profile.colors[name].r = r
self.db.profile.colors[name].g = g
self.db.profile.colors[name].b = b
ChangeChatColor(type(id) == "number" and ("CHANNEL" .. id) or id, r, g, b);
end
}
end
end
end
function mod:CHAT_MSG_CHANNEL_NOTICE(evt, notice, _, _, fullname, _, _, channelType, channelNumber, channelName)
if notice == "YOU_JOINED" then
self:AddChannels(GetChannelList())
channelName = channelName:match("^(%w+)")
local c = self.db.profile.colors[channelName]
if c then
ChangeChatColor("CHANNEL" .. channelNumber, c.r, c.g, c.b);
end
end
end
function mod:UPDATE_CHAT_COLOR(evt, chan, r, g, b)
if chan then
local num = tonumber(chan:match("(%d+)$"))
local channelNum = num and select(2, GetChannelName(num))
local name = channelNum and channelNum:match("^(%w+)") or chan
self.db.profile.colors[name] = self.db.profile.colors[name] or {}
self.db.profile.colors[name].r = r
self.db.profile.colors[name].g = g
self.db.profile.colors[name].b = b
end
end
function mod:GetOptions()
return options
end
+199
View File
@@ -0,0 +1,199 @@
local mod = Chatter:NewModule("Channel Names", "AceHook-3.0", "AceEvent-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["Channel Names"]
local gsub = _G.string.gsub
local find = _G.string.find
local pairs = _G.pairs
local loadstring = _G.loadstring
local tostring = _G.tostring
local GetChannelList = _G.GetChannelList
local select = _G.select
local empty_tag = L["$$EMPTY$$"];
local defaults = {
profile = {
channels = {
[L["Guild"]] = "[G]",
[L["Officer"]] = "[O]",
[L["Party"]] = "[P]",
[PARTY_LEADER] = "[PL]",
[L["Dungeon Guide"]] = "[DG]",
[L["Raid"]] = "[R]",
[L["Raid Leader"]] = "[RL]",
[L["Raid Warning"]] = "[RW]",
[L["LookingForGroup"]] = "[LFG]",
[L["Battleground"]] = "[BG]",
[L["Battleground Leader"]] = "[BL]",
-- Not localized here intentionally
["Whisper From"] = "[W:From]",
["Whisper To"] = "[W:To]",
["BN Whisper From"] = "[BN:From]",
["BN Whisper To"] = "[BN:To]",
["away BN Whisper To"] = "<Away>[BN:To]",
["busy BN Whisper To"] = "<Busy>[BN:To]"
},
addSpace = true
}
}
local channels
local options = {
splitter = {
type = "header",
name = L["Custom Channels"]
},
addSpace = {
type = "toggle",
name = L["Add space after channels"],
desc = L["Add space after channels"],
get = function() return mod.db.profile.addSpace end,
set = function(info, v) mod.db.profile.addSpace = v end
}
}
local serverChannels = {}
local function excludeChannels(...)
for i = 1, select("#", ...) do
local name = select(i, ...)
serverChannels[name] = true
end
end
local functions = {}
local function addChannel(name)
options[name:gsub(" ", "_")] = {
type = "input",
name = name,
desc = L["Replace this channel name with..."],
order = name:lower() == name and 101 or 98,
get = function()
local v = mod.db.profile.channels[name]
return v == "" and " " or v
end,
set = function(info, v)
mod.db.profile.channels[name] = #v > 0 and v or nil
if v:match("^function%(") then
functions[name] = loadstring("return " .. v)()
else
functions[name] = nil
end
end
}
end
function mod:OnInitialize()
self.db = Chatter.db:RegisterNamespace("ChannelNames", defaults)
self.db.profile.customChannels = nil
for k, _ in pairs(self.db.profile.channels) do
addChannel(k)
end
excludeChannels(EnumerateServerChannels())
for k, v in pairs(serverChannels) do
addChannel(k)
end
self:AddCustomChannels(GetChannelList())
for k, v in pairs(self.db.profile.channels) do
if v:match("^function%(") then
functions[k] = loadstring("return " .. v)()
end
end
end
function mod:AddCustomChannels(...)
for i = 1, select("#", ...), 2 do
local id, name = select(i, ...)
if not serverChannels[name] and not options[name:gsub(" ", "_")] then
options[name:gsub(" ", "_")] = {
type = "input",
name = name,
desc = L["Replace this channel name with..."],
order = id <= 4 and 98 or 101,
get = function()
local v = self.db.profile.channels[name:lower()]
return v == "" and " " or v
end,
set = function(info, v)
self.db.profile.channels[name:lower()] = #v > 0 and v or nil
if v:match("^function%(") then
functions[name:lower()] = loadstring("return " .. v)()
end
end
}
end
end
end
function mod:Decorate(frame)
if not self:IsHooked(frame,"AddMessage") then
self:RawHook(frame, "AddMessage", true)
end
end
function mod:OnEnable()
channels = self.db.profile.channels
self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE")
for i = 1, NUM_CHAT_WINDOWS do
local cf = _G["ChatFrame" .. i]
if cf ~= COMBATLOG then
self:RawHook(cf, "AddMessage", true)
end
end
for index,name in ipairs(self.TempChatFrames) do
local cf = _G[name]
if cf then
self:RawHook(cf, "AddMessage", true)
end
end
end
function mod:CHAT_MSG_CHANNEL_NOTICE()
self:AddCustomChannels(GetChannelList())
end
local function replaceChannel(origChannel, msg, num, channel)
local f = functions[channel] or functions[channel:lower()]
local newChannelName = f and f(channel) or channels[channel] or channels[channel:lower()] or msg
if newChannelName == empty_tag then return "" end
return ("|Hchannel:%s|h%s|h%s"):format(origChannel, newChannelName, mod.db.profile.addSpace and " " or "")
end
local function replaceChannelRW(msg, channel)
local f = functions[channel] or functions[channel:lower()]
local newChannelName = f and f(channel) or channels[channel] or channels[channel:lower()] or msg
return newChannelName .. (mod.db.profile.addSpace and " " or "")
end
function mod:AddMessage(frame, text, ...)
if not text then
return self.hooks[frame].AddMessage(frame, text, ...)
end
-- removed the start of check, since blizz timestamps inject themselves in front of the line
if (CHAT_TIMESTAMP_FORMAT) then
text = gsub(text, "|Hchannel:(%S-)|h(%[([%d. ]*)([^%]]+)%])|h ", replaceChannel)
text = gsub(text, "(%[(" .. L["Raid Warning"] .. ")%]) ", replaceChannelRW)
else
text = gsub(text, "^|Hchannel:(%S-)|h(%[([%d. ]*)([^%]]+)%])|h ", replaceChannel)
text = gsub(text, "^(%[(" .. L["Raid Warning"] .. ")%]) ", replaceChannelRW)
end
text = gsub(text, L["To (|Hplayer.-|h):"], mod.db.profile.channels["Whisper To"] .. (mod.db.profile.addSpace and " %1:" or "%1:"))
text = gsub(text, L["(|Hplayer.-|h) whispers:"], mod.db.profile.channels["Whisper From"] .. (mod.db.profile.addSpace and " %1:" or "%1:"))
text = gsub(text, L["To (|HBNplayer.-|h):"], mod.db.profile.channels["BN Whisper To"] .. (mod.db.profile.addSpace and " %1:" or "%1:"))
text = gsub(text, L["To <Away>(|HBNplayer.-|h):"], mod.db.profile.channels["away BN Whisper To"] .. (mod.db.profile.addSpace and " %1:" or "%1:"))
text = gsub(text, L["To <Busy>(|HBNplayer.-|h):"], mod.db.profile.channels["busy BN Whisper To"] .. (mod.db.profile.addSpace and " %1:" or "%1:"))
text = gsub(text, L["(|HBNplayer.-|h) whispers:"], mod.db.profile.channels["BN Whisper From"] .. (mod.db.profile.addSpace and " %1:" or "%1:"))
return self.hooks[frame].AddMessage(frame, text, ...)
end
function mod:GetOptions()
return options
end
function mod:Info()
return L["Enables you to replace channel names with your own names. You can use '%s' to force an empty string."]:format( empty_tag )
end
mod.funcs = functions
+38
View File
@@ -0,0 +1,38 @@
local mod = Chatter:NewModule("Disable Fading")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["Disable Fading"]
mod.toggleLabel = L["Disable Fading"]
function mod:Decorate(cf)
cf:SetFading(nil)
end
function mod:OnEnable()
for i = 1, NUM_CHAT_WINDOWS do
local cf = _G["ChatFrame" .. i]
cf:SetFading(nil)
end
for index,name in ipairs(self.TempChatFrames) do
local cf = _G[name]
if cf then
cf:SetFading(nil)
end
end
end
function mod:OnDisable()
for i = 1, NUM_CHAT_WINDOWS do
local cf = _G["ChatFrame" .. i]
cf:SetFading(true)
end
for index,name in ipairs(self.TempChatFrames) do
local cf = _G[name]
if cf then
cf:SetFading(true)
end
end
end
function mod:Info()
return L["Makes old text disappear rather than fade out"]
end
+182
View File
@@ -0,0 +1,182 @@
local mod = Chatter:NewModule("Chat Font", "AceEvent-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["Chat Font"]
local Media = LibStub("LibSharedMedia-3.0")
local pairs = _G.pairs
local player_entered_world = false
local defaults = {
profile = {
frames = {}
}
}
local outlines = {[""] = "None", ["OUTLINE"] = "Outline", ["THICKOUTLINE"] = "Thick Outline"}
local options = {
font = {
type = "select",
name = L["Font"],
desc = L["Font"],
dialogControl = 'LSM30_Font',
values = Media:HashTable("font"),
get = function() return mod.db.profile.font end,
set = function(info, v)
mod.db.profile.font = v
mod:SetFont(nil, v)
end
},
fontsize = {
type = "range",
name = L["Font size"],
desc = L["Font size"],
min = 4,
max = 30,
step = 1,
bigStep = 1,
get = function() return mod.db.profile.fontsize end,
set = function(info, v)
mod.db.profile.fontsize = v
mod:SetFont(nil, nil, v)
end
},
outline = {
type = "select",
name = L["Font Outline"],
desc = L["Font outlining"],
values = outlines,
get = function() return mod.db.profile.outline or "" end,
set = function(info, v)
mod.db.profile.outline = v
mod:SetFont(nil, nil, nil, v)
end
}
}
function mod:OnInitialize()
for i = 1, NUM_CHAT_WINDOWS do
defaults.profile.frames["FRAME_" .. i] = {}
end
self.db = Chatter.db:RegisterNamespace("ChatFont", defaults)
for i = 1, NUM_CHAT_WINDOWS do
local cf = _G["ChatFrame" .. i]
local t = {
type = "group",
name = L["Chat Frame "] .. i,
desc = L["Chat Frame "] .. i,
args = {
fontsize = {
type = "range",
name = L["Font size"],
desc = L["Font size"],
min = 4,
max = 30,
step = 1,
bigStep = 1,
get = function() return mod.db.profile.frames["FRAME_" .. i].fontsize or mod.db.profile.fontsize end,
set = function(info, v)
mod.db.profile.frames["FRAME_" .. i].fontsize = v
mod:SetFont(cf, nil, v)
end
},
font = {
type = "select",
name = L["Font"],
desc = L["Font"],
dialogControl = 'LSM30_Font',
values = Media:HashTable("font"),
get = function() return mod.db.profile.frames["FRAME_" .. i].font or mod.db.profile.font end,
set = function(info, v)
mod.db.profile.frames["FRAME_" .. i].font = v
mod:SetFont(cf, v)
end
},
outline = {
type = "select",
name = L["Font Outline"],
desc = L["Font outlining"],
values = outlines,
get = function() return mod.db.profile.frames["FRAME_" .. i].outline or "" end,
set = function(info, v)
mod.db.profile.frames["FRAME_" .. i].outline = v
mod:SetFont(cf, nil, nil, v)
end
}
}
}
options["frame" .. i] = t
end
end
function mod:LibSharedMedia_Registered()
self:SetFont()
end
function mod:Popout(frame,src)
local fontName, fontHeight, fontFlags = src:GetFont()
frame:SetFont(fontName,fontHeight,fontFlags)
end
function mod:OnEnable()
Media.RegisterCallback(mod, "LibSharedMedia_Registered")
self:LibSharedMedia_Registered()
if not player_entered_world then
self:RegisterEvent("PLAYER_ENTERING_WORLD")
end
end
function mod:PLAYER_ENTERING_WORLD()
self:SetFont()
self:UnregisterAllEvents()
player_entered_world = true
end
function mod:OnDisable()
Media.UnregisterCallback(mod, "LibSharedMedia_Registered")
self:SetFont(nil, "Arial Narrow", 12, "")
end
function mod:SetFont(cf, font, size, outline)
if cf then
self:SetFrameFont(cf, font, size, outline)
else
for i = 1, NUM_CHAT_WINDOWS do
cf = _G["ChatFrame" .. i]
self:SetFrameFont(cf, font, size, outline)
end
for index,name in ipairs(self.TempChatFrames) do
local cf = _G[name]
if cf then
self:SetFrameFont(cf, font, size, outline)
end
end
end
end
function mod:SetFrameFont(cf, font, size, outline)
local f = "FRAME_" .. cf:GetName():match("%d+")
local prof = self.db.profile.frames[f]
local profFont = nil
if prof then
profFont = prof.font
else
prof = {}
end
if profFont == "Default" then
profFont = nil
end
local f, s, m = cf:GetFont()
font = Media:Fetch("font", font or profFont or self.db.profile.font or f)
size = size or prof.fontsize or self.db.profile.fontsize or s
outline = outline or prof.outline or self.db.profile.outline or m
cf:SetFont(font, size, outline)
end
function mod:GetOptions()
return options
end
function mod:Info()
return L["Enables you to set a custom font and font size for your chat frames"]
end
+277
View File
@@ -0,0 +1,277 @@
local mod = Chatter:NewModule("Borders/Background")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["Borders/Background"]
local Media = LibStub("LibSharedMedia-3.0")
local CreateFrame = _G.CreateFrame
local pairs = _G.pairs
local tinsert = _G.tinsert
local type = _G.type
local options = {
}
local defaults = {
profile = {
frames = {}
}
}
local frame_defaults = {
enable = true,
combatLogFix = false,
background = "Blizzard Tooltip",
border = "Blizzard Tooltip",
inset = 3,
edgeSize = 12,
backgroundColor = { r = 0, g = 0, b = 0, a = 1 },
borderColor = { r = 1, g = 1, b = 1, a = 1 },
}
local function deepcopy(tbl)
local new = {}
for key,value in pairs(tbl) do
new[key] = type(value) == "table" and deepcopy(value) or value -- if it's a table, run deepCopy on it too, so we get a copy and not the original
end
return new
end
local frames = {}
function mod:OnInitialize()
for i = 1, NUM_CHAT_WINDOWS do
defaults.profile.frames["FRAME_" .. i] = deepcopy(frame_defaults)
if _G["ChatFrame" .. i] == COMBATLOG then
defaults.profile.frames["FRAME_" .. i].enable = false
end
end
defaults.profile.frames.FRAME_2.combatLogFix = true
self.db = Chatter.db:RegisterNamespace("ChatFrameBorders", defaults)
Media.RegisterCallback(mod, "LibSharedMedia_Registered")
for i = 1, NUM_CHAT_WINDOWS do
local cf = _G["ChatFrame" .. i]
local frame = CreateFrame("Frame", nil, cf, "ChatFrameBorderTemplate")
frame:EnableMouse(false)
cf:SetFrameStrata("LOW")
frame:SetFrameStrata("BACKGROUND")
frame:SetFrameLevel(1)
frame:Hide()
frame.id = "FRAME_" .. i
tinsert(frames, frame)
local t = {
type = "group",
name = L["Chat Frame "] .. i,
desc = L["Chat Frame "] .. i,
args = {
enable = {
type = "toggle",
name = L["Enable"],
desc = L["Enable borders on this frame"],
order = 1,
get = function()
return mod.db.profile.frames[frame.id].enable
end,
set = function(info, v)
mod.db.profile.frames[frame.id].enable = v
if v then
frame:Show()
else
frame:Hide()
end
end
},
combatLogFix = {
type = "toggle",
name = L["Combat Log Fix"],
desc = L["Resize this border to fit the new combat log"],
get = function() return mod.db.profile.frames[frame.id].combatLogFix end,
set = function(info, v)
mod.db.profile.frames[frame.id].combatLogFix = v
mod:SetAnchors(frame, v)
end
},
background = {
type = "select",
name = L["Background texture"],
desc = L["Background texture"],
dialogControl = "LSM30_Background",
values = Media:HashTable("background"),
get = function() return mod.db.profile.frames[frame.id].background end,
set = function(info, v)
mod.db.profile.frames[frame.id].background = v
mod:SetBackdrop(frame)
end
},
border = {
type = "select",
name = L["Border texture"],
desc = L["Border texture"],
dialogControl = "LSM30_Border",
values = Media:HashTable("border"),
get = function() return mod.db.profile.frames[frame.id].border end,
set = function(info, v)
mod.db.profile.frames[frame.id].border = v
mod:SetBackdrop(frame)
end
},
backgroundColor = {
type = "color",
name = L["Background color"],
desc = L["Background color"],
hasAlpha = true,
get = function()
local c = mod.db.profile.frames[frame.id].backgroundColor
return c.r, c.g, c.b, c.a
end,
set = function(info, r, g, b, a)
local c = mod.db.profile.frames[frame.id].backgroundColor
c.r, c.g, c.b, c.a = r, g, b, a
mod:SetBackdrop(frame)
end
},
borderColor = {
type = "color",
name = L["Border color"],
desc = L["Border color"],
hasAlpha = true,
get = function()
local c = mod.db.profile.frames[frame.id].borderColor
return c.r, c.g, c.b, c.a
end,
set = function(info, r, g, b, a)
local c = mod.db.profile.frames[frame.id].borderColor
c.r, c.g, c.b, c.a = r, g, b, a
mod:SetBackdrop(frame)
end
},
inset = {
type = "range",
name = L["Background Inset"],
desc = L["Background Inset"],
min = 1,
max = 64,
step = 1,
bigStep = 1,
get = function() return mod.db.profile.frames[frame.id].inset end,
set = function(info, v)
mod.db.profile.frames[frame.id].inset = v
mod:SetBackdrop(frame)
end
},
tileSize = {
type = "range",
name = L["Tile Size"],
desc = L["Tile Size"],
min = 1,
max = 64,
step = 1,
bigStep = 1,
get = function() return mod.db.profile.frames[frame.id].tileSize end,
set = function(info, v)
mod.db.profile.frames[frame.id].tileSize = v
mod:SetBackdrop(frame)
end
},
edgeSize = {
type = "range",
name = L["Edge Size"],
desc = L["Edge Size"],
min = 1,
max = 64,
step = 1,
bigStep = 1,
get = function() return mod.db.profile.frames[frame.id].edgeSize end,
set = function(info, v)
mod.db.profile.frames[frame.id].edgeSize = v
mod:SetBackdrop(frame)
end
}
}
}
options[frame.id] = t
end
end
function mod:LibSharedMedia_Registered()
mod:SetBackdrops()
end
function mod:Decorate(cf)
local frame = CreateFrame("Frame", nil, cf, "ChatFrameBorderTemplate")
frame:EnableMouse(false)
cf:SetFrameStrata("LOW")
frame:SetFrameStrata("BACKGROUND")
frame:SetFrameLevel(1)
frame:Hide()
frame.id = "FRAME_1"
tinsert(frames, frame)
self:SetBackdrops()
frame:Show()
mod:SetAnchors(frame, self.db.profile.frames["FRAME_1"].combatLogFix)
end
function mod:OnEnable()
self:LibSharedMedia_Registered()
self:SetBackdrops()
for i = 1, #frames do
frames[i]:Show()
mod:SetAnchors(frames[i], self.db.profile.frames["FRAME_" .. i].combatLogFix)
end
Media.RegisterCallback(mod, "LibSharedMedia_Registered")
end
function mod:OnDisable()
for i = 1, #frames do
frames[i]:Hide()
end
end
function mod:SetBackdrops()
for i = 1, #frames do
self:SetBackdrop(frames[i])
end
end
do
function mod:SetBackdrop(frame)
local profile = self.db.profile.frames[frame.id]
frame:SetBackdrop({
bgFile = Media:Fetch("background", profile.background),
edgeFile = Media:Fetch("border", profile.border),
tile = true,
tileSize = profile.tileSize,
edgeSize = profile.edgeSize,
insets = {left = profile.inset, right = profile.inset, top = profile.inset, bottom = profile.inset}
})
local c = profile.backgroundColor
frame:SetBackdropColor(c.r, c.g, c.b, c.a)
local c = profile.borderColor
frame:SetBackdropBorderColor(c.r, c.g, c.b, c.a)
end
end
function mod:GetOptions()
return options
end
function mod:SetAnchors(frame, fix)
local p = frame:GetParent()
frame:ClearAllPoints()
if fix then
frame:SetPoint("TOPLEFT", p, "TOPLEFT", -5, 30)
frame:SetPoint("TOPRIGHT", p, "TOPRIGHT", 5, 30)
frame:SetPoint("BOTTOMLEFT", p, "BOTTOMLEFT", -5, -10)
frame:SetPoint("BOTTOMRIGHT", p, "BOTTOMRIGHT", 5, -10)
else
frame:SetPoint("TOPLEFT", p, "TOPLEFT", -5, 5)
frame:SetPoint("TOPRIGHT", p, "TOPRIGHT", 5, 5)
frame:SetPoint("BOTTOMLEFT", p, "BOTTOMLEFT", -5, -10)
frame:SetPoint("BOTTOMRIGHT", p, "BOTTOMRIGHT", 5, -10)
end
end
function mod:Info()
return L["Gives you finer control over the chat frame's background and border colors"]
end
+39
View File
@@ -0,0 +1,39 @@
<Ui>
<Script file="ChatFrameBorders.lua" />
<Frame name="ChatFrameBorderTemplate" virtual="true" enableMouse="false">
<Backdrop bgFile="Interface\\ChatFrame\\ChatFrameBackground" edgeFile="Interface\Tooltips\UI-Tooltip-Border" tile="true">
<EdgeSize>
<AbsValue val="16"/>
</EdgeSize>
<TileSize>
<AbsValue val="16"/>
</TileSize>
<BackgroundInsets>
<AbsInset left="5" right="5" top="5" bottom="5"/>
</BackgroundInsets>
</Backdrop>
<Anchors>
<Anchor point="TOPLEFT" relativePoint="TOPLEFT">
<Offset>
<AbsDimension x="-5" y="7"/>
</Offset>
</Anchor>
<Anchor point="TOPRIGHT" relativePoint="TOPRIGHT">
<Offset>
<AbsDimension x="5" y="10"/>
</Offset>
</Anchor>
<Anchor point="BOTTOMLEFT" relativePoint="BOTTOMLEFT">
<Offset>
<AbsDimension x="-5" y="-10"/>
</Offset>
</Anchor>
<Anchor point="BOTTOMRIGHT" relativePoint="BOTTOMRIGHT">
<Offset>
<AbsDimension x="5" y="-10"/>
</Offset>
</Anchor>
</Anchors>
</Frame>
</Ui>
+65
View File
@@ -0,0 +1,65 @@
local mod = Chatter:NewModule("ChatLink", "AceHook-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["Chat Link"]
local gsub = _G.string.gsub
local find = _G.string.find
local GetChannelName = _G.GetChannelName
local EnumerateServerChannels = _G.EnumerateServerChannels
local select = _G.select
local serverChannels = {}
local function excludeChannels(...)
for i = 1, select("#", ...) do
local name = select(i, ...)
serverChannels[name] = true
end
end
function mod:Decorate(frame)
if not self:IsHooked(frame,"AddMessage") then
self:RawHook(frame, "AddMessage", true)
end
end
function mod:OnEnable()
excludeChannels(EnumerateServerChannels())
for i = 1, NUM_CHAT_WINDOWS do
local cf = _G["ChatFrame" .. i]
if cf ~= COMBATLOG then
self:RawHook(cf, "AddMessage", true)
end
end
for index,name in ipairs(self.TempChatFrames) do
local cf = _G[name]
if cf then
self:RawHook(cf, "AddMessage", true)
end
end
end
function mod:OnDisable()
end
function mod:ParseLinks(text)
if not text then return nil end
text = gsub(text, "{CLINK:item:(%x+):([%d-]-:[%d-]-:[%d-]-:[%d-]-:[%d-]-:[%d-]-:[%d-]-:[%d-]-:[%d-]-):([^}]-)}", "|c%1|Hitem:%2|h[%3]|h|r")
text = gsub(text, "{CLINK:talent:(%x+):([%d-]-:[%d-]-):([^}]-)}", "|c%1|Htalent:%2|h[%3]|h|r")
text = gsub(text, "{CLINK:glyph:(%x+):([%d-]-:[%d-]-):([^}]-)}", "|c%1|Hglyph:%2|h[%3]|h|r")
text = gsub(text, "{CLINK:enchant:(%x+):([%d-]-):([^}]-)}", "|c%1|Henchant:%2|h[%3]|h|r")
text = gsub(text, "{CLINK:spell:(%x+):([%d-]-):([^}]-)}", "|c%1|Hspell:%2|h[%3]|h|r")
text = gsub(text, "{CLINK:quest:(%x+):([%d-]-):([%d-]-):([^}]-)}", "|c%1|Hquest:%2:%3|h[%4]|h|r")
text = gsub(text, "{CLINK:(%x+):([%d-]-:[%d-]-:[%d-]-:[%d-]-:[%d-]-:[%d-]-:[%d-]-:[%d-]-:[%d-]-):([^}]-)}", "|c%1|Hitem:%2|h[%3]|h|r")
text = gsub(text, "{CLINK:trade:(%x+):(%-?%d-:%-?%d-:.*:.*):([^}]-)}", "|c%1|Htrade:%2|h[%3]|h|r")
-- {CLINK:achievement:ffffff00:780:00000000001ED5C3:1:12:16:8:4294967295:4294967295:4294967295:4294967295:Explore Redridge Mountains}
text = gsub(text, "{CLINK:achievement:(%x+):(%-?%d-:%-?%x-:%-?%d-:%-?%d-:%-?%d-:%-?%d-:%-?%d-:%-?%d-:%-?%d-:%-?%d-):([^}]-)}", "|c%1|Hachievement:%2|h[%3]|h|r")
return text
end
function mod:AddMessage(frame, text, ...)
return self.hooks[frame].AddMessage(frame, mod:ParseLinks(text), ...)
end
function mod:Info()
return L["Lets you link items, enchants, spells, talents, achievements and quests in custom channels."]
end
+162
View File
@@ -0,0 +1,162 @@
local mod = Chatter:NewModule("Mousewheel Scroll", "AceHook-3.0","AceEvent-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["Mousewheel Scroll"]
local IsShiftKeyDown = _G.IsShiftKeyDown
local IsControlKeyDown = _G.IsControlKeyDown
local scrollFunc = function(self, arg1)
-- prevent itemtooltips to be kept open when using LinkHover.
HideUIPanel(GameTooltip)
if arg1 > 0 then
if IsShiftKeyDown() then
self:ScrollToTop()
elseif IsControlKeyDown() then
self:PageUp()
else
for i = 1, mod.db.profile.scrollLines do
self:ScrollUp()
end
end
elseif arg1 < 0 then
if IsShiftKeyDown() then
self:ScrollToBottom()
elseif IsControlKeyDown() then
self:PageDown()
else
for i = 1, mod.db.profile.scrollLines do
self:ScrollDown()
end
end
end
end
local defaults = { profile = { scrollLines = 1 } }
local options = {
lines = {
type = "range",
name = L["Scroll lines"],
desc = L["How many lines to scroll per mouse wheel click"],
min = 1,
max = 20,
step = 1,
bigStep = 1,
get = function() return mod.db.profile.scrollLines end,
set = function(info, v) mod.db.profile.scrollLines = v end
}
}
function mod:OnInitialize()
self.db = Chatter.db:RegisterNamespace(self:GetName(), defaults)
self:RegisterEvent("CVAR_UPDATE", "ChangedVars")
if _G.InterfaceOptionsSocialPanelChatMouseScroll_SetScrolling then
self:RawHook("InterfaceOptionsSocialPanelChatMouseScroll_SetScrolling",true)
end
end
function mod:InterfaceOptionsSocialPanelChatMouseScroll_SetScrolling()
-- We want to intercept this and handle it ourselves
end
function mod:ChangedVars(event,cvar,value)
if cvar == "CHAT_MOUSE_WHEEL_SCROLL" then
if value == "1" then
for i = 1, NUM_CHAT_WINDOWS do
local cf = _G[("%s%d"):format("ChatFrame", i)]
cf:SetScript("OnMouseWheel", FloatingChatFrame_OnMouseScroll)
cf:EnableMouseWheel(true)
end
for index,name in ipairs(self.TempChatFrames) do
local cf = _G[name]
if cf then
cf:SetScript("OnMouseWheel", FloatingChatFrame_OnMouseScroll)
cf:EnableMouseWheel(true)
end
end
end
if value == "0" and self:IsEnabled() then
for i = 1, NUM_CHAT_WINDOWS do
local cf = _G[("%s%d"):format("ChatFrame", i)]
cf:SetScript("OnMouseWheel", scrollFunc)
cf:EnableMouseWheel(true)
end
for index,name in ipairs(self.TempChatFrames) do
local cf = _G[name]
if cf then
cf:SetScript("OnMouseWheel", scrollFunc)
cf:EnableMouseWheel(true)
end
end
end
end
end
function mod:OnEnable()
if GetCVar("chatMouseScroll") == "1" then
return
end
for i = 1, NUM_CHAT_WINDOWS do
local cf = _G[("%s%d"):format("ChatFrame", i)]
cf:SetScript("OnMouseWheel", scrollFunc)
if not cf:IsMouseWheelEnabled() then
cf:EnableMouseWheel(true)
end
end
for index,name in ipairs(self.TempChatFrames) do
local cf = _G[name]
if cf then
cf:SetScript("OnMouseWheel", scrollFunc)
if not cf:IsMouseWheelEnabled() then
cf:EnableMouseWheel(true)
end
end
end
end
function mod:Decorate(frame)
if GetCVar("chatMouseScroll") == "1" then
return
end
frame:SetScript("OnMouseWheel", scrollFunc)
frame:EnableMouseWheel(true)
end
function mod:OnDisable()
for i = 1, NUM_CHAT_WINDOWS do
local cf = _G[("%s%d"):format("ChatFrame", i)]
if GetCVarBool("chatMouseScroll") then
cf:SetScript("OnMouseWheel", FloatingChatFrame_OnMouseScroll)
if not cf:IsMouseWheelEnabled() then
cf:EnableMouseWheel(true)
end
else
cf:SetScript("OnMouseWheel", nil)
if cf:IsMouseWheelEnabled() then
cf:EnableMouseWheel(true)
end
end
end
for index,name in ipairs(self.TempChatFrames) do
local cf = _G[name]
if GetCVarBool("chatMouseScroll") then
cf:SetScript("OnMouseWheel", FloatingChatFrame_OnMouseScroll)
if not cf:IsMouseWheelEnabled() then
cf:EnableMouseWheel(true)
end
else
cf:SetScript("OnMouseWheel", nil)
if cf:IsMouseWheelEnabled() then
cf:EnableMouseWheel(true)
end
end
end
end
function mod:Info()
return L["Lets you use the mousewheel to page up and down chat."]
end
function mod:GetOptions()
return options
end
+304
View File
@@ -0,0 +1,304 @@
local mod = Chatter:NewModule("ChatTabs", "AceHook-3.0", "AceEvent-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
local font = GameFontNormalSmall
mod.modName = L["Chat Tabs"]
local defaults = {
profile = {
height = 29,
tabFlash = true
}
}
local options = {
height = {
order = 101,
type = "range",
name = L["Button Height"],
desc = L["Button's height, and text offset from the frame"],
step = 1,
bigStep = 1,
get = function() return mod.db.profile.height end,
set = function(info, v)
mod.db.profile.height = v
for i = 1, NUM_CHAT_WINDOWS do
local tab = _G["ChatFrame"..i.."Tab"]
tab:SetHeight(v)
end
end,
disabled = function() return not mod:IsEnabled() end
},
hidetabs = {
order = 102,
type = "toggle",
name = L["Hide Tabs"],
desc = L["Hides chat frame tabs"],
get = function() return mod.db.profile.chattabs end,
set = function(info, v) mod.db.profile.chattabs = not mod.db.profile.chattabs; mod:ToggleTabShow() end,
disabled = function() return not mod:IsEnabled() end
},
hideflash = {
order = 103,
type = "toggle",
name = L["Enable Tab Flashing"],
desc = L["Enables the Tab to flash when you miss a message"],
get = function() return mod.db.profile.tabFlash end,
set = function(info, v) mod.db.profile.tabFlash = not mod.db.profile.tabFlash; mod:DecorateTabs() end,
disabled = function() return not mod:IsEnabled() end
}
}
function mod:OnInitialize()
self.db = Chatter.db:RegisterNamespace(self:GetName(), defaults)
end
local function SetFontSizes()
for i = 1, NUM_CHAT_WINDOWS do
local tab = _G["ChatFrame"..i.."Tab"]
mod:OnLeave(tab)
end
for index,name in ipairs(self.TempChatFrames) do
local tab = _G[name.."Tab"]
mod:OnLeave(tab)
end
end
function mod:Decorate(frame)
local name = "ChatFrame"..frame:GetID();
local tab = _G[name.."Tab"]
tab:SetHeight(mod.db.profile.height)
_G[name.."TabLeft"]:Hide()
_G[name.."TabMiddle"]:Hide()
_G[name.."TabRight"]:Hide()
tab.leftSelectedTexture:SetAlpha(0)
tab.rightSelectedTexture:SetAlpha(0)
tab.middleSelectedTexture:SetAlpha(0)
tab.leftHighlightTexture:SetTexture(nil)
tab.rightHighlightTexture:SetTexture(nil)
tab.middleHighlightTexture:SetTexture([[BUTTONS\CheckButtonGlow]])
tab.middleHighlightTexture:SetWidth(76)
tab.middleHighlightTexture:SetTexCoord(0, 0, 1, 0.5)
tab.leftSelectedTexture:SetAlpha(0)
tab.rightSelectedTexture:SetAlpha(0)
tab.middleSelectedTexture:SetAlpha(0)
tab:EnableMouseWheel(true)
self:HookScript(tab, "OnMouseWheel")
tab:Show()
if (mod.db.profile.chattabs) then
mod:HideTab(tab)
end
end
function mod:DecorateTabs()
CHAT_FRAME_FADE_OUT_TIME = 0.5
CHAT_TAB_HIDE_DELAY = 0
CHAT_FRAME_TAB_SELECTED_MOUSEOVER_ALPHA = 1
CHAT_FRAME_TAB_SELECTED_NOMOUSE_ALPHA = 0
CHAT_FRAME_TAB_ALERTING_MOUSEOVER_ALPHA = 1
if self.db.profile.tabFlash then
CHAT_FRAME_TAB_ALERTING_NOMOUSE_ALPHA = 1
else
CHAT_FRAME_TAB_ALERTING_NOMOUSE_ALPHA = 0
end
CHAT_FRAME_TAB_NORMAL_MOUSEOVER_ALPHA = 1
CHAT_FRAME_TAB_NORMAL_NOMOUSE_ALPHA = 0
end
function mod:UndecorateTabs()
CHAT_FRAME_FADE_OUT_TIME = 2
CHAT_TAB_HIDE_DELAY = 1
CHAT_FRAME_TAB_SELECTED_MOUSEOVER_ALPHA = 1
CHAT_FRAME_TAB_SELECTED_NOMOUSE_ALPHA = 0.4
CHAT_FRAME_TAB_ALERTING_MOUSEOVER_ALPHA = 1
CHAT_FRAME_TAB_ALERTING_NOMOUSE_ALPHA = 1
CHAT_FRAME_TAB_NORMAL_MOUSEOVER_ALPHA = 0.6
CHAT_FRAME_TAB_NORMAL_NOMOUSE_ALPHA = 0.2
end
function mod:OnEnable()
-- self:Hook("FCF_Close", true)
self:DecorateTabs()
for i = 1, NUM_CHAT_WINDOWS do
local chat = _G["ChatFrame"..i]
local tab = _G["ChatFrame"..i.."Tab"]
tab:SetHeight(mod.db.profile.height)
_G["ChatFrame"..i.."TabLeft"]:Hide()
_G["ChatFrame"..i.."TabMiddle"]:Hide()
_G["ChatFrame"..i.."TabRight"]:Hide()
tab.leftSelectedTexture:SetAlpha(0)
tab.rightSelectedTexture:SetAlpha(0)
tab.middleSelectedTexture:SetAlpha(0)
tab.leftHighlightTexture:SetTexture(nil)
tab.rightHighlightTexture:SetTexture(nil)
tab.middleHighlightTexture:SetTexture([[BUTTONS\CheckButtonGlow]])
tab.middleHighlightTexture:SetWidth(76)
tab.middleHighlightTexture:SetTexCoord(0, 0, 1, 0.5)
tab.leftSelectedTexture:SetAlpha(0)
tab.rightSelectedTexture:SetAlpha(0)
tab.middleSelectedTexture:SetAlpha(0)
--[[ TODO: Grum @ 18/10/2008
There seems to be a bug with certain fonts/fontObjects which prevents
tab:GetNormalFontObject() to return anything sensible
The buttons now have font objects. If you change the size on one it will change on
the other tabs as well. However assigning a new font object seems to go wrong with
the default ChatFrame$Tab font-object. This will need further investigation
For now I just disabled all the font-changing mechanics.
--]]
tab:EnableMouseWheel(true)
self:HookScript(tab, "OnMouseWheel")
if (mod.db.profile.chattabs) then
mod:HideTab(tab)
end
tab.noMouseAlpha=0
tab:SetAlpha(0)
end
for index,name in ipairs(self.TempChatFrames) do
local chat = _G[name]
local tab = _G[name.."Tab"]
tab:SetHeight(mod.db.profile.height)
_G[name.."TabLeft"]:Hide()
_G[name.."TabMiddle"]:Hide()
_G[name.."TabRight"]:Hide()
tab.leftSelectedTexture:SetAlpha(0)
tab.rightSelectedTexture:SetAlpha(0)
tab.middleSelectedTexture:SetAlpha(0)
tab.leftHighlightTexture:SetTexture(nil)
tab.rightHighlightTexture:SetTexture(nil)
tab.middleHighlightTexture:SetTexture([[BUTTONS\CheckButtonGlow]])
tab.middleHighlightTexture:SetWidth(76)
tab.middleHighlightTexture:SetTexCoord(0, 0, 1, 0.5)
tab.leftSelectedTexture:SetAlpha(0)
tab.rightSelectedTexture:SetAlpha(0)
tab.middleSelectedTexture:SetAlpha(0)
tab:EnableMouseWheel(true)
if not self:IsHooked(tab,"OnMouseWheel") then
self:HookScript(tab, "OnMouseWheel")
end
if (mod.db.profile.chattabs) then
mod:HideTab(tab)
end
tab.noMouseAlpha=0
tab:SetAlpha(0)
end
end
function mod:OnDisable()
for i = 1, NUM_CHAT_WINDOWS do
local chat = _G["ChatFrame"..i]
local tab = _G["ChatFrame"..i.."Tab"]
tab:SetHeight(32)
_G["ChatFrame"..i.."TabLeft"]:Show()
_G["ChatFrame"..i.."TabMiddle"]:Show()
_G["ChatFrame"..i.."TabRight"]:Show()
tab:EnableMouseWheel(false)
tab:Hide()
tab.noMousealpha=0.2
tab:SetAlpha(0.2)
end
for index,name in ipairs(self.TempChatFrames) do
local chat = _G[name]
local tab = _G[name.."Tab"]
tab:SetHeight(32)
_G[name.."TabLeft"]:Show()
_G[name.."TabMiddle"]:Show()
_G[name.."TabRight"]:Show()
tab:EnableMouseWheel(false)
tab:Hide()
tab.noMousealpha=0.2
tab:SetAlpha(0.2)
end
self:UndecorateTabs()
end
function mod:FCF_Close(f)
_G[f:GetName() .. "Tab"]:Hide()
end
function mod:OnClick(f, button, ...)
if button == "LeftButton" then
SetFontSizes(f)
end
end
function mod:ToggleTabShow()
for i = 1, NUM_CHAT_WINDOWS do
local tab = _G["ChatFrame"..i.."Tab"]
local chat = _G["ChatFrame"..i]
if (mod.db.profile.chattabs) then
tab:SetScript("OnShow", function(...) tab:Hide() end)
else
tab:SetScript("OnShow", function(...) tab:Show() end)
end
tab:Show()
tab:Hide()
if chat.isDocked or chat:IsVisible() then
tab:Show()
end
end
for index,name in ipairs(self.TempChatFrames) do
local tab = _G[name.."Tab"]
local chat = _G[name]
if (mod.db.profile.chattabs) then
tab:SetScript("OnShow", function(...) tab:Hide() end)
else
tab:SetScript("OnShow", function(...) tab:Show() end)
end
tab:Show()
tab:Hide()
if chat.isDocked or chat:IsVisible() then
tab:Show()
end
end
end
function mod:HideTab(tab)
tab:SetScript("OnShow", function(...) tab:Hide() end)
tab:Show()
if tab:IsVisible() then
tab:Hide()
end
end
function mod:OnMouseWheel(frame, dir)
local chat = _G["ChatFrame" .. frame:GetID()]
if not chat.isDocked then return end
local t
for i = 1, #GENERAL_CHAT_DOCK.DOCKED_CHAT_FRAMES do
if GENERAL_CHAT_DOCK.DOCKED_CHAT_FRAMES[i]:IsVisible() then
t = i
break
end
end
if t == 1 and dir > 0 then
t = #GENERAL_CHAT_DOCK.DOCKED_CHAT_FRAMES
elseif t == #GENERAL_CHAT_DOCK.DOCKED_CHAT_FRAMES and dir < 0 then
t = 1
elseif t then
t = t + (dir < 0 and 1 or -1)
end
if t then
_G[GENERAL_CHAT_DOCK.DOCKED_CHAT_FRAMES[t]:GetName() .. "Tab"]:Click()
end
--SetFontSizes()
end
function mod:OnEnter(frame)
local f, s = font:GetFont()
frame:SetFont(f, s + 2)
end
function mod:OnLeave(frame)
local f, s = font:GetFont()
if(_G["ChatFrame" .. frame:GetID()]:IsVisible()) then
frame:SetFont(f, s + 2)
else
frame:SetFont(f, s - 1)
end
end
function mod:GetOptions()
return options
end
+134
View File
@@ -0,0 +1,134 @@
local mod = Chatter:NewModule("Invite Links", "AceHook-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["Invite Links"]
local gsub = _G.string.gsub
local ipairs = _G.ipairs
local fmt = _G.string.format
local sub = _G.string.sub
local InviteUnit = _G.InviteUnit
local next = _G.next
local type = _G.type
local IsAltKeyDown = _G.IsAltKeyDown
local match = _G.string.match
local options = {
addWord = {
type = "input",
name = L["Add Word"],
desc = L["Add word to your invite trigger list"],
get = function() end,
set = function(info, v)
mod.db.profile.words[v:lower()] = v
end
},
removeWord = {
type = "select",
name = L["Remove Word"],
desc = L["Remove a word from your invite trigger list"],
get = function() end,
set = function(info, v)
mod.db.profile.words[v:lower()] = nil
end,
values = function() return mod.db.profile.words end,
confirm = function(info, v) return (L["Remove this word from your trigger list?"]) end
},
altClick = {
type = "toggle",
name = L["Alt-click name to invite"],
width = "double",
desc = L["Lets you alt-click player names to invite them to your party."],
get = function() return mod.db.profile.altClickToinvite end,
set = function(i, v) mod.db.profile.altClickToinvite = v end
}
}
local defaults = {
profile = {
words = {},
altClickToInvite = true
}
}
local words
function mod:OnInitialize()
self.db = Chatter.db:RegisterNamespace(self:GetName(), defaults)
end
function mod:Decorate(frame)
self:RawHook(frame, "AddMessage", true)
end
function mod:OnEnable()
words = self.db.profile.words
if not next(words) then
words[L["invite"]] = L["invite"]
words[L["inv"]] = L["inv"]
end
for i = 1, NUM_CHAT_WINDOWS do
local cf = _G["ChatFrame" .. i]
if cf ~= COMBATLOG then
self:RawHook(cf, "AddMessage", true)
end
end
for index,name in ipairs(self.TempChatFrames) do
local cf = _G[name]
if cf then
self:RawHook(cf, "AddMessage", true)
end
end
self:RawHook(nil, "SetItemRef", true)
end
local style = "|cffffffff|Hinvite:%s|h[%s]|h|r"
local valid_events = {
CHAT_MSG_SAY = true,
CHAT_MSG_CHANNEL = true,
CHAT_MSG_WHISPER = true,
CHAT_MSG_OFFICER = true,
CHAT_MSG_GUILD = true
}
local function addLinks(m, t, p)
if words[t:lower()] and p ~= "_" then
t = fmt(style, arg2, t)
return t .. p
end
return m
end
function mod:AddMessage(frame, text, ...)
if not text then
return self.hooks[frame].AddMessage(frame, text, ...)
end
if valid_events[event] and type(arg2) == "string" then
text = gsub(text, "((%w+)(.?))", addLinks)
end
return self.hooks[frame].AddMessage(frame, text, ...)
end
function mod:SetItemRef(link, text, button)
local linkType = sub(link, 1, 6)
-- Chatter:Print(IsAltKeyDown(), linkType, self.db.profile.altClickToInvite)
if IsAltKeyDown() and linkType == "player" and self.db.profile.altClickToInvite then
local name = match(link, "player:([^:]+)")
InviteUnit(name)
return nil
elseif linkType == "invite" then
local name = sub(link, 8)
InviteUnit(name)
return nil
end
return self.hooks.SetItemRef(link, text, button)
end
function mod:Info()
return L["Gives you more flexibility in how you invite people to your group."]
end
function mod:GetOptions()
return options
end
+228
View File
@@ -0,0 +1,228 @@
local mod = Chatter:NewModule("Chat Copy", "AceHook-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["Copy Chat"]
local lines = {}
local table_concat = _G.table.concat
local CreateFrame = _G.CreateFrame
local GetSpellInfo = _G.GetSpellInfo
local select = _G.select
local tinsert = _G.tinsert
local tostring = _G.tostring
local PaneBackdrop = {
bgFile = [[Interface\DialogFrame\UI-DialogBox-Background]],
edgeFile = [[Interface\DialogFrame\UI-DialogBox-Border]],
tile = true, tileSize = 16, edgeSize = 16,
insets = { left = 3, right = 3, top = 5, bottom = 3 }
}
local InsetBackdrop = {
bgFile = [[Interface\DialogFrame\UI-DialogBox-Background]],
edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]],
tile = true, tileSize = 16, edgeSize = 16,
insets = { left = 3, right = 3, top = 5, bottom = 3 }
}
local tex = select(3, GetSpellInfo(586))
local buttons = {}
local defaults = {
profile = {
copyIcon = false,
}
}
function mod:OnInitialize()
self.db = Chatter.db:RegisterNamespace("CopyChat", defaults)
local frame = CreateFrame("Frame", "ChatterCopyFrame", UIParent)
tinsert(UISpecialFrames, "ChatterCopyFrame")
frame:SetBackdrop(PaneBackdrop)
frame:SetBackdropColor(0,0,0,1)
frame:SetWidth(500)
frame:SetHeight(400)
frame:SetPoint("CENTER", UIParent, "CENTER")
frame:Hide()
frame:SetFrameStrata("DIALOG")
self.frame = frame
local scrollArea = CreateFrame("ScrollFrame", "ChatterCopyScroll", frame, "UIPanelScrollFrameTemplate")
scrollArea:SetPoint("TOPLEFT", frame, "TOPLEFT", 8, -30)
scrollArea:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -30, 8)
local editBox = CreateFrame("EditBox", nil, frame)
editBox:SetMultiLine(true)
editBox:SetMaxLetters(99999)
editBox:EnableMouse(true)
editBox:SetAutoFocus(false)
editBox:SetFontObject(ChatFontNormal)
editBox:SetWidth(400)
editBox:SetHeight(270)
editBox:SetScript("OnEscapePressed", function() frame:Hide() end)
self.editBox = editBox
scrollArea:SetScrollChild(editBox)
local close = CreateFrame("Button", nil, frame, "UIPanelCloseButton")
close:SetPoint("TOPRIGHT", frame, "TOPRIGHT")
end
local options
function mod:GetOptions()
options = options or {
guildNotes = {
order=100,
type = "toggle",
name = L["Show copy icon"],
desc = L["Toggle the copy icon on the chat frame."],
get = function()
return mod.db.profile.copyIcon
end,
set = function(info, v)
mod.db.profile.copyIcon = v
mod:HideCopyButton(v)
end,
},
}
return options
end
function mod:Decorate(frame)
local button = self:MakeCopyButton(frame)
local tab = _G["ChatFrame" .. frame:GetID()]
self:HookScript(tab, "OnShow")
self:HookScript(tab, "OnHide")
tab.copyButton = button
if self.db.profile.copyIcon then
tab.copyButton:Show()
end
end
function mod:OnEnable()
Chatter:AddMenuHook(self, "Menu")
for i = 1, NUM_CHAT_WINDOWS do
local cf = _G["ChatFrame" .. i]
self:MakeCopyButton(cf)
end
for index,f in ipairs(self.TempChatFrames) do
local cf = _G[f]
self:MakeCopyButton(cf)
end
for i = 1, #buttons do
local p = buttons[i]:GetParent()
local tab = _G["ChatFrame" .. p:GetID()]
self:HookScript(tab, "OnShow")
self:HookScript(tab, "OnHide")
tab.copyButton = buttons[i]
if self.db.profile.copyIcon then
tab.copyButton:Show()
else
tab.copyButton:Hide()
end
end
end
function mod:OnDisable()
Chatter:RemoveMenuHook(self)
for i = 1, #buttons do
buttons[i]:Hide()
end
end
function mod:HideCopyButton(val)
if not val then
for i = 1, #buttons do
buttons[i]:Hide()
end
else
for i = 1, #buttons do
buttons[i]:Show()
end
end
end
function mod:MakeCopyButton(frame)
for index,cb in ipairs(buttons) do
if cb:GetParent() == frame then
return nil
end
end
local button = CreateFrame("Button", nil, frame)
button:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", 0, -5)
button:SetHeight(10)
button:SetWidth(10)
button:SetNormalTexture(tex)
button:SetHighlightTexture([[Interface\Buttons\ButtonHilight-Square]])
button:SetScript("OnClick", function() mod:Copy(frame) end)
button:SetScript("OnEnter", function(self)
self:SetHeight(28)
self:SetWidth(28)
GameTooltip:SetOwner(self)
GameTooltip:ClearLines()
GameTooltip:AddLine(L["Copy text from this frame."])
GameTooltip:Show()
end)
button:SetScript("OnLeave", function(self)
button:SetHeight(10)
button:SetWidth(10)
GameTooltip:Hide()
end)
button:Hide()
tinsert(buttons, button)
return button
end
local menuButtons = {}
function mod:Menu(chatTab, button)
local frame = _G["ChatFrame" .. chatTab:GetID()]
local info = menuButtons[chatTab:GetID()]
if not info then
info = {}
info.text = L["Copy Text"]
info.func = function() mod:Copy(frame) end
info.notCheckable = 1;
menuButtons[chatTab:GetID()] = info
end
return info
end
function mod:Copy(frame)
local _, size = frame:GetFont()
FCF_SetChatWindowFontSize(frame, frame, 0.01)
local lineCt = self:GetLines(frame:GetRegions())
local text = table_concat(lines, "\n", 1, lineCt)
FCF_SetChatWindowFontSize(frame, frame, size)
self.frame:Show()
self.editBox:SetText(text)
self.editBox:HighlightText(0)
end
function mod:GetLines(...)
local ct = 1
for i = select("#", ...), 1, -1 do
local region = select(i, ...)
if region:GetObjectType() == "FontString" then
lines[ct] = tostring(region:GetText())
ct = ct + 1
end
end
return ct - 1
end
function mod:OnShow(cft)
local cfn = cft:GetName():match("ChatFrame%d")
if cfn and _G[cfn]:IsVisible() and self.db.profile.copyIcon then
cft.copyButton:Show()
end
end
function mod:OnHide(cft)
local cfn = cft:GetName():match("ChatFrame%d")
if cfn and _G[cfn]:IsVisible() then
cft.copyButton:Hide()
end
end
function mod:Info()
return L["Lets you copy text out of your chat frames."]
end
+42
View File
@@ -0,0 +1,42 @@
local frame = CreateFrame("Frame")
LibStub("AceHook-3.0"):Embed(frame)
local strmatch = strmatch
-- GUILD_MOTD_TEMPLATE = "Guild Message of the Day: %s"; -- %s is the guild MOTD
local pattern = GUILD_MOTD_TEMPLATE:
gsub("[-%%+*.()%[%]]", "%%%1"):
gsub("%%%%s", "(.+)")
local gmotdData
function frame:AddMessage(frame, text, ...)
local gmotd
if text then
gmotd = strmatch(text, pattern)
end
if gmotd then
gmotdData={text,...}
self:UnhookAll()
else
return self.hooks[frame].AddMessage(frame, text, ...)
end
end
frame:RawHook(ChatFrame1, "AddMessage", true)
local delay=2.5
frame:SetScript("OnUpdate", function(self, expired)
delay=delay-expired
if delay<0 then
self:Hide()
self:UnhookAll()
if gmotdData then
ChatFrame1:AddMessage(unpack(gmotdData))
gmotdData=nil
end
end
end)
+615
View File
@@ -0,0 +1,615 @@
local mod = Chatter:NewModule("Edit Box Polish", "AceHook-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["Edit Box Polish"]
local Media = LibStub("LibSharedMedia-3.0")
local backgrounds, borders, fonts = {}, {}, {}
local CreateFrame = _G.CreateFrame
local max = _G.max
local pairs = _G.pairs
local select = _G.select
local VALID_ATTACH_POINTS = {
TOP = L["Top"],
BOTTOM = L["Bottom"],
FREE = L["Free-floating"],
LOCK = L["Free-floating, Locked"]
}
local function updateEditBox(method, ...)
for i = 1, NUM_CHAT_WINDOWS do
local f = _G["ChatFrame" .. i .. "EditBox"]
f[method](f, ...)
end
for index,name in ipairs(mod.TempChatFrames) do
local cf = _G[name.."EditBox"]
if cf then
cf[method](cf,...)
end
end
end
local options = {
background = {
type = "select",
name = L["Background texture"],
desc = L["Background texture"],
values = Media:HashTable("background"),
dialogControl = "LSM30_Background",
get = function() return mod.db.profile.background end,
set = function(info, v)
mod.db.profile.background = v
mod:SetBackdrop()
end
},
border = {
type = "select",
name = L["Border texture"],
desc = L["Border texture"],
dialogControl = "LSM30_Border",
values = Media:HashTable("border"),
get = function() return mod.db.profile.border end,
set = function(info, v)
mod.db.profile.border = v
mod:SetBackdrop()
end
},
backgroundColor = {
type = "color",
name = L["Background color"],
desc = L["Background color"],
hasAlpha = true,
get = function()
local c = mod.db.profile.backgroundColor
return c.r, c.g, c.b, c.a
end,
set = function(info, r, g, b, a)
local c = mod.db.profile.backgroundColor
c.r, c.g, c.b, c.a = r, g, b, a
mod:SetBackdrop()
end
},
borderColor = {
type = "color",
name = L["Border color"],
desc = L["Border color"],
hasAlpha = true,
get = function()
local c = mod.db.profile.borderColor
return c.r, c.g, c.b, c.a
end,
set = function(info, r, g, b, a)
local c = mod.db.profile.borderColor
c.r, c.g, c.b, c.a = r, g, b, a
mod:SetBackdrop()
end
},
inset = {
type = "range",
name = L["Background Inset"],
desc = L["Background Inset"],
min = 1,
max = 64,
step = 1,
bigStep = 1,
get = function() return mod.db.profile.inset end,
set = function(info, v)
mod.db.profile.inset = v
mod:SetBackdrop()
end
},
tileSize = {
type = "range",
name = L["Tile Size"],
desc = L["Tile Size"],
min = 1,
max = 64,
step = 1,
bigStep = 1,
get = function() return mod.db.profile.tileSize end,
set = function(info, v)
mod.db.profile.tileSize = v
mod:SetBackdrop()
end
},
edgeSize = {
type = "range",
name = L["Edge Size"],
desc = L["Edge Size"],
min = 1,
max = 64,
step = 1,
bigStep = 1,
get = function() return mod.db.profile.edgeSize end,
set = function(info, v)
mod.db.profile.edgeSize = v
mod:SetBackdrop()
end
},
attach = {
type = "select",
name = L["Attach to..."],
desc = L["Attach edit box to..."],
get = function() return mod.db.profile.attach end,
values = VALID_ATTACH_POINTS,
set = function(info, v)
mod.db.profile.attach = v
-- we loop in set attach anyways
mod:SetAttach()
end
},
colorByChannel = {
type = "toggle",
name = L["Color border by channel"],
desc = L["Sets the frame's border color to the color of your currently active channel"],
get = function()
return mod.db.profile.colorByChannel
end,
set = function(info, v)
mod.db.profile.colorByChannel = v
if v then
mod:RawHook("ChatEdit_UpdateHeader", "SetBorderByChannel", true)
else
if mod:IsHooked("ChatEdit_UpdateHeader") then
mod:Unhook("ChatEdit_UpdateHeader")
local c = mod.db.profile.borderColor
for _, frame in ipairs(self.frames) do
frame:SetBackdropBorderColor(c.r, c.g, c.b, c.a)
end
end
end
end
},
useAltKey = {
type = "toggle",
name = L["Use Alt key for cursor movement"],
desc = L["Requires the Alt key to be held down to move the cursor in chat"],
get = function()
return mod.db.profile.useAlt
end,
set = function(info, v)
mod.db.profile.useAlt = v
updateEditBox("SetAltArrowKeyMode", v)
end
},
font = {
type = "select",
name = L["Font"],
dialogControl = "LSM30_Font",
desc = L["Select the font to use for the edit box"],
values = Media:HashTable("font"),
get = function() return mod.db.profile.font end,
set = function(i, v)
mod.db.profile.font = v
for i = 1, NUM_CHAT_WINDOWS do
local ff = _G["ChatFrame"..i.."EditBox"]
local _, s, m = ff:GetFont()
ff:SetFont(Media:Fetch("font", v), s, m)
end
end
},
height = {
type = "range",
name = L["Height"],
desc = L["Select the height of the edit box"],
min = 5,
max = 50,
step = 1,
bigStep = 1,
get = function() return mod.db.profile.height end,
set = function(i, v)
mod.db.profile.height = v
mod:UpdateHeight()
end
}
}
local defaults = {
profile = {
background = "Blizzard Tooltip",
border = "Blizzard Tooltip",
hideDialog = true,
backgroundColor = {r = 0, g = 0, b = 0, a = 1},
borderColor = {r = 1, g = 1, b = 1, a = 1},
inset = 3,
edgeSize = 12,
tileSize = 16,
height = 22,
attach = "BOTTOM",
colorByChannel = true,
useAlt = false,
font = (function()
for i = 1, NUM_CHAT_WINDOWS do
local ff = _G["ChatFrame"..i.."EditBox"]
local f = ff:GetFont()
for k,v in pairs(Media:HashTable("font")) do
if v == f then return k end
end
end
end)()
}
}
function mod:LibSharedMedia_Registered(mediaType, key)
--for k, v in pairs(Media:List("background")) do
-- backgrounds[v] = v
--end
--for k, v in pairs(Media:List("border")) do
-- borders[v] = v
--end
--for k, v in pairs(Media:List("font")) do
-- fonts[v] = v
--end
-- If we were missing this media, reset it now
if mediaType == "font" and key == self.db.profile.font then
for _, frame in ipairs(self.frames) do
local f = frame:GetParent()
if f then
local font, s, m = f:GetFont()
f:SetFont(Media:Fetch("font", self.db.profile.font), s, m)
end
end
end
if mediaType == "border" and key == self.db.profile.border then
self:SetBackdrop()
end
if mediaType == "background" and key == self.db.profile.background then
self:SetBackdrop()
end
end
function mod:OnInitialize()
self.db = Chatter.db:RegisterNamespace("EditBox", defaults)
Media.RegisterCallback(mod, "LibSharedMedia_Registered")
self.frames = {}
self:LibSharedMedia_Registered()
for i = 1, NUM_CHAT_WINDOWS do
local parent = _G["ChatFrame"..i.."EditBox"]
local frame = CreateFrame("Frame", nil, parent)
frame:SetFrameStrata("DIALOG")
frame:SetFrameLevel(parent:GetFrameLevel() - 1)
frame:SetAllPoints(parent)
frame:Hide()
parent.lDrag = CreateFrame("Frame", nil, parent)
parent.lDrag:SetWidth(15)
parent.lDrag:SetPoint("TOPLEFT", parent, "TOPLEFT")
parent.lDrag:SetPoint("BOTTOMLEFT", parent, "BOTTOMLEFT")
parent.rDrag = CreateFrame("Frame", nil, parent)
parent.rDrag:SetWidth(15)
parent.rDrag:SetPoint("TOPRIGHT", parent, "TOPRIGHT")
parent.rDrag:SetPoint("BOTTOMRIGHT", parent, "BOTTOMRIGHT")
parent.lDrag.left = true
parent.frame = frame
tinsert(self.frames, frame)
end
end
function mod:Decorate(chatframe)
local parent = _G[chatframe:GetName().."EditBox"]
local frame = CreateFrame("Frame", nil, parent)
frame:SetFrameStrata("DIALOG")
frame:SetFrameLevel(parent:GetFrameLevel() - 1)
frame:SetAllPoints(parent)
parent.lDrag = CreateFrame("Frame", nil, parent)
parent.lDrag:SetWidth(15)
parent.lDrag:SetPoint("TOPLEFT", parent, "TOPLEFT")
parent.lDrag:SetPoint("BOTTOMLEFT", parent, "BOTTOMLEFT")
parent.rDrag = CreateFrame("Frame", nil, parent)
parent.rDrag:SetWidth(15)
parent.rDrag:SetPoint("TOPRIGHT", parent, "TOPRIGHT")
parent.rDrag:SetPoint("BOTTOMRIGHT", parent, "BOTTOMRIGHT")
parent.lDrag.left = true
parent.frame = frame
tinsert(self.frames, frame)
local name = chatframe:GetName()
local f = _G[name.."EditBox"]
_G[name.."EditBoxLeft"]:Hide()
_G[name.."EditBoxRight"]:Hide()
_G[name.."EditBoxMid"]:Hide()
_G[name.."EditBoxFocusLeft"]:SetTexture(nil)
_G[name.."EditBoxFocusRight"]:SetTexture(nil)
_G[name.."EditBoxFocusMid"]:SetTexture(nil)
f:Hide()
frame:Show()
local font, s, m = f:GetFont()
f:SetFont(Media:Fetch("font", self.db.profile.font), s, m)
self:SetAttach(nil, self.db.profile.editX, self.db.profile.editY, self.db.profile.editW)
self:SetBackdrop()
self:UpdateHeight()
end
function mod:OnEnable()
self:LibSharedMedia_Registered()
updateEditBox("SetAltArrowKeyMode", mod.db.profile.useAlt)
for i = 1, NUM_CHAT_WINDOWS do
local f = _G["ChatFrame"..i.."EditBox"]
_G["ChatFrame"..i.."EditBoxLeft"]:Hide()
_G["ChatFrame"..i.."EditBoxRight"]:Hide()
_G["ChatFrame"..i.."EditBoxMid"]:Hide()
_G["ChatFrame"..i.."EditBoxFocusLeft"]:SetTexture(nil)
_G["ChatFrame"..i.."EditBoxFocusRight"]:SetTexture(nil)
_G["ChatFrame"..i.."EditBoxFocusMid"]:SetTexture(nil)
f:Hide()
self.frames[i]:Show()
local font, s, m = f:GetFont()
f:SetFont(Media:Fetch("font", self.db.profile.font), s, m)
self:SetAttach(nil, self.db.profile.editX, self.db.profile.editY, self.db.profile.editW)
end
for index,name in ipairs(self.TempChatFrames) do
local f = _G[name.."EditBox"]
_G[name.."EditBoxLeft"]:Hide()
_G[name.."EditBoxRight"]:Hide()
_G[name.."EditBoxMid"]:Hide()
_G[name.."EditBoxFocusLeft"]:SetTexture(nil)
_G[name.."EditBoxFocusRight"]:SetTexture(nil)
_G[name.."EditBoxFocusMid"]:SetTexture(nil)
f:Hide()
self.frames[NUM_CHAT_WINDOWS+index]:Show()
local font, s, m = f:GetFont()
f:SetFont(Media:Fetch("font", self.db.profile.font), s, m)
self:SetAttach(nil, self.db.profile.editX, self.db.profile.editY, self.db.profile.editW)
end
-- make sure they all show
for index,frame in ipairs(self.frames) do
frame:Show()
end
self:SecureHook("ChatEdit_DeactivateChat")
self:SecureHook("ChatEdit_SetLastActiveWindow")
self:SetBackdrop()
self:UpdateHeight()
if self.db.profile.colorByChannel then
self:RawHook("ChatEdit_UpdateHeader", "SetBorderByChannel", true)
end
self:SecureHook("FCF_Tab_OnClick")
end
function mod:FCF_Tab_OnClick(frame,button)
if self.db.profile.attach == "TOP" and GetCVar("chatStyle") ~= "classic" then
local chatFrame = _G["ChatFrame"..frame:GetID()];
ChatEdit_DeactivateChat(chatFrame.editBox)
end
end
function mod:OnDisable()
for i = 1, NUM_CHAT_WINDOWS do
local f = _G["ChatFrame"..i.."EditBox"]
_G["ChatFrame"..i.."EditBoxLeft"]:Show()
_G["ChatFrame"..i.."EditBoxRight"]:Show()
_G["ChatFrame"..i.."EditBoxMid"]:Show()
f:SetAltArrowKeyMode(true)
f:EnableMouse(true)
f.frame:Hide()
self:SetAttach("BOTTOM")
f:SetFont(Media:Fetch("font", defaults.profile.font), 14)
end
for index,name in ipairs(self.TempChatFrames) do
local f = _G[name.."EditBox"]
_G[name.."EditBoxLeft"]:Show()
_G[name.."EditBoxRight"]:Show()
_G[name.."EditBoxMid"]:Show()
f:SetAltArrowKeyMode(true)
f:EnableMouse(true)
f.frame:Hide()
self:SetAttach("BOTTOM")
f:SetFont(Media:Fetch("font", defaults.profile.font), 14)
end
end
-- changed the Hide to SetAlpha(0), the new ChatSystem OnHide handlers go though some looping
-- when in IM style and Classic style, cause heavy delays on the chat edit box.
function mod:ChatEdit_SetLastActiveWindow(frame)
if self.db.profile.hideDialog and frame:IsShown() then
frame:SetAlpha(0)
else
frame:SetAlpha(1)
end
frame:EnableMouse(true)
end
function mod:ChatEdit_DeactivateChat(frame)
if self.db.profile.hideDialog and frame:IsShown() then
frame:SetAlpha(0)
frame:EnableMouse(false)
end
end
function mod:GetOptions()
return options
end
function mod:SetBackdrop()
for _, frame in ipairs(self.frames) do
frame:SetBackdrop({
bgFile = Media:Fetch("background", self.db.profile.background),
edgeFile = Media:Fetch("border", self.db.profile.border),
tile = true,
tileSize = self.db.profile.tileSize,
edgeSize = self.db.profile.edgeSize,
insets = {left = self.db.profile.inset, right = self.db.profile.inset, top = self.db.profile.inset, bottom = self.db.profile.inset}
})
local c = self.db.profile.backgroundColor
frame:SetBackdropColor(c.r, c.g, c.b, c.a)
local c = self.db.profile.borderColor
frame:SetBackdropBorderColor(c.r, c.g, c.b, c.a)
end
end
function mod:SetBorderByChannel(...)
self.hooks.ChatEdit_UpdateHeader(...)
for index, frame in ipairs(self.frames) do
local f = _G["ChatFrame"..index.."EditBox"]
local attr = f:GetAttribute("chatType")
if attr == "CHANNEL" then
local chan = f:GetAttribute("channelTarget")
if chan == 0 then
local c = self.db.profile.borderColor
frame:SetBackdropBorderColor(c.r, c.g, c.b, c.a)
else
local r, g, b = GetMessageTypeColor("CHANNEL" .. chan)
frame:SetBackdropBorderColor(r, g, b, 1)
end
else
local r, g, b = GetMessageTypeColor(attr)
frame:SetBackdropBorderColor(r, g, b, 1)
end
end
end
do
local function startMoving(self)
self:StartMoving()
end
local function stopMoving(self)
self:StopMovingOrSizing()
mod.db.profile.editX = self:GetLeft()
mod.db.profile.editY = self:GetTop()
mod.db.profile.editW = self:GetRight() - self:GetLeft()
end
local cfHeight
local function constrainHeight(self)
self:GetParent():SetHeight(cfHeight)
end
local function startDragging(self)
cfHeight = self:GetParent():GetHeight()
self:GetParent():StartSizing(not self.left and "TOPRIGHT" or "TOPLEFT")
self:SetScript("OnUpdate", constrainHeight)
end
local function stopDragging(self)
local parent = self:GetParent()
parent:StopMovingOrSizing()
self:SetScript("OnUpdate", nil)
mod.db.profile.editX = parent:GetLeft()
mod.db.profile.editY = parent:GetTop()
mod.db.profile.editW = parent:GetWidth()
end
function mod:SetAttach(val, x, y, w)
for i = 1, NUM_CHAT_WINDOWS do
local frame = _G["ChatFrame" .. i .. "EditBox"]
local val = val or self.db.profile.attach
if not x and val == "FREE" then
if self.db.profile.editX and self.db.profile.editY then
x, y, w = self.db.profile.editX, self.db.profile.editY, self.db.profile.editW
else
x, y, w = frame:GetLeft(), frame:GetTop(), max(frame:GetWidth(), (frame:GetRight() or 0) - (frame:GetLeft() or 0))
end
end
if not w or w < 10 then w = 100 end
frame:ClearAllPoints()
-- Turn off clamping
if val ~= "FREE" then
frame:SetMovable(false)
frame.lDrag:EnableMouse(false)
frame.rDrag:EnableMouse(false)
frame:SetScript("OnMouseDown", nil)
frame:SetScript("OnMouseUp", nil)
frame.lDrag:EnableMouse(false)
frame.rDrag:EnableMouse(false)
frame.lDrag:SetScript("OnMouseDown", nil)
frame.rDrag:SetScript("OnMouseDown", nil)
frame.lDrag:SetScript("OnMouseUp", nil)
frame.rDrag:SetScript("OnMouseUp", nil)
end
if val == "TOP" then
-- When on top we need to prevent left clicking from activating the edit box.
frame:SetPoint("BOTTOMLEFT", frame.chatFrame, "TOPLEFT", 0, 3)
frame:SetPoint("BOTTOMRIGHT", frame.chatFrame, "TOPRIGHT", 0, 3)
elseif val == "BOTTOM" then
frame:SetPoint("TOPLEFT", frame.chatFrame, "BOTTOMLEFT", 0, -8)
frame:SetPoint("TOPRIGHT", frame.chatFrame, "BOTTOMRIGHT", 0, -8)
elseif val == "FREE" then
if i == 1 then
frame:SetFrameLevel(frame:GetFrameLevel()+1)
end
frame:EnableMouse(true)
frame:SetMovable(true)
frame:SetResizable(true)
frame:SetScript("OnMouseDown", startMoving)
frame:SetScript("OnMouseUp", stopMoving)
frame:SetWidth(w)
frame:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", x, y)
frame:SetMinResize(40, 1)
frame.lDrag:EnableMouse(true)
frame.rDrag:EnableMouse(true)
frame.lDrag:SetScript("OnMouseDown", startDragging)
frame.rDrag:SetScript("OnMouseDown", startDragging)
frame.lDrag:SetScript("OnMouseUp", stopDragging)
frame.rDrag:SetScript("OnMouseUp", stopDragging)
elseif val == "LOCK" then
frame:SetWidth(self.db.profile.editW or w)
frame:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", self.db.profile.editX or x, self.db.profile.editY or y)
end
end
for index,name in ipairs(self.TempChatFrames) do
local frame = _G[name .. "EditBox"]
local val = val or self.db.profile.attach
if not x and val == "FREE" then
x, y, w = frame:GetLeft(), frame:GetTop(), max(frame:GetWidth(), (frame:GetRight() or 0) - (frame:GetLeft() or 0))
end
if not w or w < 10 then w = 100 end
frame:ClearAllPoints()
if val ~= "FREE" then
frame:SetMovable(false)
frame.lDrag:EnableMouse(false)
frame.rDrag:EnableMouse(false)
frame:SetScript("OnMouseDown", nil)
frame:SetScript("OnMouseUp", nil)
frame.lDrag:EnableMouse(false)
frame.rDrag:EnableMouse(false)
frame.lDrag:SetScript("OnMouseDown", nil)
frame.rDrag:SetScript("OnMouseDown", nil)
frame.lDrag:SetScript("OnMouseUp", nil)
frame.rDrag:SetScript("OnMouseUp", nil)
end
if val == "TOP" then
frame:SetPoint("BOTTOMLEFT", _G[name], "TOPLEFT", 0, 3)
frame:SetPoint("BOTTOMRIGHT", _G[name], "TOPRIGHT", 0, 3)
elseif val == "BOTTOM" then
frame:SetPoint("TOPLEFT", _G[name], "BOTTOMLEFT", 0, -8)
frame:SetPoint("TOPRIGHT", _G[name], "BOTTOMRIGHT", 0, -8)
elseif val == "FREE" then
frame:EnableMouse(true)
frame:SetMovable(true)
frame:SetResizable(true)
frame:SetScript("OnMouseDown", startMoving)
frame:SetScript("OnMouseUp", stopMoving)
frame:SetWidth(w)
frame:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", x, y)
frame:SetMinResize(40, 1)
frame.lDrag:EnableMouse(true)
frame.rDrag:EnableMouse(true)
frame.lDrag:SetScript("OnMouseDown", startDragging)
frame.rDrag:SetScript("OnMouseDown", startDragging)
frame.lDrag:SetScript("OnMouseUp", stopDragging)
frame.rDrag:SetScript("OnMouseUp", stopDragging)
elseif val == "LOCK" then
frame:SetWidth(self.db.profile.editW or w)
frame:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", self.db.profile.editX or x, self.db.profile.editY or y)
end
end
end
end
function mod:Info()
return L["Lets you customize the position and look of the edit box"]
end
function mod:UpdateHeight()
for i = 1, NUM_CHAT_WINDOWS do
local ff = _G["ChatFrame"..i.."EditBox"]
ff:SetHeight(mod.db.profile.height)
end
for index,name in ipairs(self.TempChatFrames) do
local ff = _G[name.."EditBox"]
ff:SetHeight(mod.db.profile.height)
end
end
+41
View File
@@ -0,0 +1,41 @@
local mod = Chatter:NewModule("Editbox History", "AceHook-3.0" )
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["Edit Box History"]
local history, enabled
local defaults = { realm = { history = { } } }
local editbox = DEFAULT_CHAT_FRAME.editBox
function mod:OnInitialize()
self.db = Chatter.db:RegisterNamespace("Editbox History", defaults)
history = self.db.realm.history
-- Hook adding lines
self:SecureHook( editbox, "AddHistoryLine" )
end
function mod:OnEnable()
-- Keeping state if we're enabled or not
enable = false
for _, line in ipairs( history ) do
editbox:AddHistoryLine( line )
end
enabled = true
end
function mod:AddHistoryLine( object, line )
-- While in 'OnEnable' this code just returns
if not self:IsEnabled() or not enabled then return end
local history = history
tinsert( history, line )
-- clear out the excess values
for i=1, #history - object:GetHistoryLines() do
tremove( history, 1 )
end
end
function mod:Info()
return L["Remembers the history of the editbox across sessions."]
end
+61
View File
@@ -0,0 +1,61 @@
local mod = Chatter:NewModule("Group Say (/gr)", "AceHook-3.0", "AceConsole-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["Group Say (/gr)"]
local GetNumPartyMembers = _G.GetNumPartyMembers
local IsInInstance = _G.IsInInstance
local GetNumPartyMembers = _G.GetNumPartyMembers
local GetNumRaidMembers = _G.GetNumRaidMembers
local SendChatMessage = _G.SendChatMessage
function mod:Decorate(frame)
self:HookScript(_G[frame:GetName().."EditBox"], "OnTextChanged")
end
function mod:OnEnable()
for i = 1, 10 do
self:HookScript(_G["ChatFrame" .. i .. "EditBox"], "OnTextChanged")
end
for index,name in ipairs(self.TempChatFrames) do
local cf = _G[name.."EditBox"]
if cf then
self:HookScript(cf, "OnTextChanged")
end
end
if not self.slashCommandRegistered then
self:RegisterChatCommand("gr", "SendChatMessage")
self.slashCommandRegistered = true
end
end
function mod:OnTextChanged(obj)
local text = obj:GetText()
if text:sub(1, 4) == "/gr " then
obj:SetText(self:GetGroupDistribution(true) .. text:sub(5));
ChatEdit_ParseText(obj, 0)
end
self.hooks[obj].OnTextChanged(obj)
end
function mod:SendChatMessage(input)
SendChatMessage(input, self:GetGroupDistribution())
end
function mod:GetGroupDistribution(slash)
local inInstance, kind = IsInInstance()
if inInstance and (kind == "pvp") then
return slash and "/bg " or "BATTLEGROUND"
end
if GetNumRaidMembers() > 0 then
return slash and "/ra " or "RAID"
end
if GetNumPartyMembers() > 0 then
return slash and "/p " or "PARTY"
end
return slash and "/s " or "SAY"
end
function mod:Info()
return L["Provides a /gr slash command to let you speak in your group (raid, party, or battleground) automatically."]
end
+253
View File
@@ -0,0 +1,253 @@
local mod = Chatter:NewModule("Highlights", "AceHook-3.0", "AceEvent-3.0", "LibSink-2.0")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["Highlights"]
local Media = LibStub("LibSharedMedia-3.0")
local PlaySoundFile = _G.PlaySoundFile
local UnitName = _G.UnitName
local pairs = _G.pairs
local select = _G.select
local type = _G.type
local gsub = _G.string.gsub
local ChatFrame_GetMessageEventFilters = _G.ChatFrame_GetMessageEventFilters
local defSound = {["None"] = [[Interface\Quiet.mp3]]}
Media:Register("sound", "Loot Chime", [[Sound\interface\igLootCreature.wav]])
Media:Register("sound", "Whisper Ping", [[Sound\interface\iTellMessage.wav]])
Media:Register("sound", "Magic Click", [[Sound\interface\MagicClick.wav]])
local player = UnitName("player")
local defaults = {
profile = {
words = {
[player:lower()] = player
},
sound = true,
soundFile = "None",
useSink = true,
rerouteMessage = true,
customChannels = {},
sinkOptions = {}
}
}
local options = {
defaultOptions = {
type = "group",
name = L["Options"],
order = 1,
args = {
sound = {
type = "toggle",
name = L["Use sound"],
desc = L["Play a soundfile when one of your keywords is said."],
get = function()
return mod.db.profile.sound
end,
set = function(info, v)
mod.db.profile.sound = v
end
},
sink = {
type = "toggle",
name = L["Show SCT message"],
desc = L["Show highlights in your SCT mod"],
order = 21,
get = function()
return mod.db.profile.useSink
end,
set = function(info, v)
mod.db.profile.useSink = v
end
},
rerouteMessage = {
type = "toggle",
name = L["Reroute whole message to SCT"],
desc = L["Reroute whole message to SCT instead of just displaying 'who said keyword in channel'"],
order = 22,
get = function()
return mod.db.profile.rerouteMessage
end,
set = function(info, v)
mod.db.profile.rerouteMessage = v
end,
disabled = function() return not mod.db.profile.useSink end
},
soundFile = {
type = "select",
name = L["Sound File"],
desc = L["Sound file to play"],
get = function()
return mod.db.profile.soundFile
end,
set = function(info, v)
mod.db.profile.soundFile = v
PlaySoundFile(Media:Fetch("sound", v))
end,
dialogControl = "LSM30_Sound",
values = function () if Media:HashTable("sound") then return Media:HashTable("sound") else return defSound end end,
disabled = function() return not mod.db.profile.sound end
},
addWord = {
type = "input",
name = L["Add Word"],
desc = L["Add word to your highlight list"],
get = function() end,
set = function(info, v)
-- no whitespace only stuff
if v:match("^%s*$") then return end
mod.db.profile.words[v:lower()] = v
end
},
removeWord = {
type = "select",
name = L["Remove Word"],
desc = L["Remove a word from your highlight list"],
get = function() end,
set = function(info, v)
mod.db.profile.words[v:lower()] = nil
end,
values = function() return mod.db.profile.words end,
confirm = function(info, v) return (L["Remove this word from your highlights?"]) end
}
}
},
config = {
type = "group",
name = L["Custom Channel Sounds"],
args = {}
}
}
function mod:OnInitialize()
self.db = Chatter.db:RegisterNamespace("Highlight", defaults)
self:AddCustomChannels(GetChannelList())
self:SetSinkStorage(self.db.profile.sinkOptions)
options.output = self:GetSinkAce3OptionsDataTable()
end
local words
function mod:OnEnable()
words = self.db.profile.words
self:RegisterEvent("CHAT_MSG_SAY", "ParseChat")
self:RegisterEvent("CHAT_MSG_GUILD", "ParseChat")
self:RegisterEvent("CHAT_MSG_BATTLEGROUND", "ParseChat")
self:RegisterEvent("CHAT_MSG_BATTLEGROUND_LEADER", "ParseChat")
self:RegisterEvent("CHAT_MSG_OFFICER", "ParseChat")
self:RegisterEvent("CHAT_MSG_PARTY", "ParseChat")
self:RegisterEvent("CHAT_MSG_RAID_LEADER", "ParseChat")
self:RegisterEvent("CHAT_MSG_RAID", "ParseChat")
self:RegisterEvent("CHAT_MSG_RAID_WARNING", "ParseChat")
self:RegisterEvent("CHAT_MSG_SAY", "ParseChat")
self:RegisterEvent("CHAT_MSG_WHISPER", "ParseChat")
self:RegisterEvent("CHAT_MSG_BN_WHISPER", "ParseChat")
self:RegisterEvent("CHAT_MSG_BN_CONVERSATION", "ParseChat")
self:RegisterEvent("CHAT_MSG_CHANNEL", "ParseChat")
self:RegisterEvent("CHAT_MSG_YELL", "ParseChat")
self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE")
self:AddCustomChannels(GetChannelList())
self:AddCustomChannels(
"YELL", L["Yell"],
"GUILD", L["Guild"],
"OFFICER", L["Officer"],
"RAID", L["Raid"],
"PARTY", L["Party"],
"RAID_WARNING", L["Raid Warning"],
"SAY", L["Say"],
"BATTLEGROUND", L["Battleground"],
"BATTLEGROUND_LEADER", L["Battleground"],
"WHISPER", L["Whisper"],
"BN_WHISPER", L["RealID Whisper"],
"BN_CONVERSATION", L["RealID Conversation"]
)
end
function mod:CHAT_MSG_CHANNEL_NOTICE(evt, notice)
self:AddCustomChannels(GetChannelList())
end
function mod:AddCustomChannels(...)
-- excludeChannels(EnumerateServerChannels())
for i = 1, select("#", ...), 2 do
local id, name = select(i, ...)
if not options[name:gsub(" ", "_")] then
options.config.args[name:gsub(" ", "_")] = {
type = "select",
name = name,
values = Media:HashTable("sound") or {},
desc = L["Play a sound when a message is received in this channel"],
order = type(id) == "number" and 103 or 102,
get = function() return self.db.profile.customChannels[id] or "None" end,
set = function(info, v)
self.db.profile.customChannels[id] = v
PlaySoundFile(Media:Fetch("sound", v))
end
}
end
end
end
function mod:ParseChat(evt, msg, sender, ...)
if sender == player then return end
local filters = ChatFrame_GetMessageEventFilters(evt)
if filters then
for i, filterFunc in ipairs(filters) do
local filtered, new_message = filterFunc(DEFAULT_CHAT_FRAME, evt, msg, sender, ...)
if filtered then
return
end
msg = new_message or msg
end
end
local msg = msg:lower()
for k, v in pairs(words) do
if msg:find(k) then
self:Highlight(msg, sender, k, select(7, ...), evt)
return
end
end
if evt == "CHAT_MSG_CHANNEL" then
local num = select(6, ...)
local snd = self.db.profile.customChannels[num]
if snd then
PlaySoundFile(Media:Fetch("sound", snd))
return
end
else
local e = evt:gsub("^CHAT_MSG_", "")
local snd = self.db.profile.customChannels[e]
if snd then
PlaySoundFile(Media:Fetch("sound", snd))
return
end
end
end
function mod:Highlight(msg, who, what, where, event)
if not where or #where == 0 then
where = _G[event] or event:gsub("CHAT_MSG_", "")
end
if self.db.profile.sound then
PlaySoundFile(Media:Fetch("sound", self.db.profile.soundFile))
end
if self.db.profile.useSink then
if mod.db.profile.rerouteMessage then
msg = gsub( msg, "|h[^|]+|h(.-)|h", "%1" )
self:Pour((L["[%s] %s: %s"]):format(where, who, msg), 1, 1, 0, nil, 24, "OUTLINE", false)
else
self:Pour((L["%s said '%s' in %s"]):format(who, what, where), 1, 1, 0, nil, 24, "OUTLINE", false)
end
end
end
function mod:Info()
return L["Alerts you when someone says a keyword or speaks in a specified channel."]
end
function mod:GetOptions()
return options
end
-- vim: ts=4 noexpandtab
+56
View File
@@ -0,0 +1,56 @@
local mod = Chatter:NewModule("Justify Text")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["Text Justification"]
mod.toggleLabel = L["Enable text justification"]
local defaults = {
profile = {}
}
local VALID_JUSTIFICATIONS = {
LEFT = L["Left"],
RIGHT = L["Right"],
CENTER = L["Center"]
}
local options = {}
function mod:OnInitialize()
self.db = Chatter.db:RegisterNamespace("JustifyText", defaults)
for i = 1, NUM_CHAT_WINDOWS do
local s = "FRAME_" .. i
local f = _G["ChatFrame" .. i]
options[s] = {
type = "select",
name = L["Chat Frame "] .. i,
desc = L["Chat Frame "] .. i,
values = VALID_JUSTIFICATIONS,
get = function() return self.db.profile[s] or "LEFT" end,
set = function(info, v)
self.db.profile[s] = v
f:SetJustifyH(v)
end
}
end
end
function mod:OnEnable()
for i = 1, NUM_CHAT_WINDOWS do
local cf = _G["ChatFrame" .. i]
cf:SetJustifyH(self.db.profile["FRAME_" .. i] or "LEFT")
end
end
function mod:OnDisable()
for i = 1, NUM_CHAT_WINDOWS do
local cf = _G["ChatFrame" .. i]
cf:SetJustifyH("LEFT")
end
end
function mod:GetOptions()
return options
end
function mod:Info()
return L["Lets you set the justification of text in your chat frames."]
end
+53
View File
@@ -0,0 +1,53 @@
local mod = Chatter:NewModule("Link Hover", "AceHook-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["Link Hover"]
local strmatch = _G.string.match
local linkTypes = {
item = true,
enchant = true,
spell = true,
quest = true,
-- player = true
}
function mod:Decorate(frame)
self:HookScript(frame, "OnHyperlinkEnter", enter)
self:HookScript(frame, "OnHyperlinkLeave", leave)
end
function mod:OnEnable()
for i = 1, NUM_CHAT_WINDOWS do
local frame = _G["ChatFrame"..i]
self:HookScript(frame, "OnHyperlinkEnter", enter)
self:HookScript(frame, "OnHyperlinkLeave", leave)
end
for index,name in ipairs(self.TempChatFrames) do
local cf = _G[name]
if cf then
self:HookScript(cf, "OnHyperlinkEnter", enter)
self:HookScript(cf, "OnHyperlinkLeave", leave)
end
end
end
function mod:OnHyperlinkEnter(f, link)
local t = strmatch(link, "^(.-):")
if linkTypes[t] then
ShowUIPanel(GameTooltip)
GameTooltip:SetOwner(UIParent, "ANCHOR_CURSOR")
GameTooltip:SetHyperlink(link)
GameTooltip:Show()
end
end
function mod:OnHyperlinkLeave(f, link)
local t = strmatch(link, "^(.-):")
if linkTypes[t] then
HideUIPanel(GameTooltip)
end
end
function mod:Info()
return L["Makes link tooltips show when you hover them in chat."]
end
+714
View File
@@ -0,0 +1,714 @@
local mod = Chatter:NewModule("Player Class Colors", "AceHook-3.0", "AceEvent-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
local AceTab = LibStub("AceTab-3.0")
mod.modName = L["Player Names"]
local local_names = {}
local leftBracket, rightBracket, separator
local colorSelfInText, emphasizeSelfInText
local gsub = _G.string.gsub
local strmatch = _G.string.match
local find = _G.string.find
local pairs = _G.pairs
local wipe = _G.wipe
local string_format = _G.string.format
local GetQuestDifficultyColor = _G.GetQuestDifficultyColor
local GetChannelName = _G.GetChannelName
local GetFriendInfo = _G.GetFriendInfo
local GetGuildRosterInfo = _G.GetGuildRosterInfo
local GetGuildRosterSelection = _G.GetGuildRosterSelection
local GetGuildRosterShowOffline = _G.GetGuildRosterShowOffline
local GetNumFriends = _G.GetNumFriends
local GetNumGuildMembers = _G.GetNumGuildMembers
local GetNumPartyMembers = _G.GetNumPartyMembers
local GetNumRaidMembers = _G.GetNumRaidMembers
local GetNumWhoResults = _G.GetNumWhoResults
local GetWhoInfo = _G.GetWhoInfo
local GuildRoster = _G.GuildRoster
local SetGuildRosterSelection = _G.SetGuildRosterSelection
local SetGuildRosterShowOffline = _G.SetGuildRosterShowOffline
local UnitClass = _G.UnitClass
local UnitExists = _G.UnitExists
local UnitIsFriend = _G.UnitIsFriend
local UnitIsPlayer = _G.UnitIsPlayer
local UnitLevel = _G.UnitLevel
local UnitName = _G.UnitName
local floor = _G.math.floor
local select = _G.select
local setmetatable = _G.setmetatable
local sqrt = _G.sqrt
local tinsert = _G.tinsert
local type = _G.type
local player = UnitName("player")
local channels = {
GUILD = {},
PARTY = {},
RAID = {}
}
local colorMethods = {
CLASS = L["Class"],
NAME = L["Name"],
NONE = L["None"],
}
local defaults = {
realm = {
names = {},
levels = {},
},
profile = {
saveData = false,
nameColoring = "CLASS",
leftBracket = "[",
rightBracket = "]",
separator = ":",
useTabComplete = true,
colorSelfInText = true,
emphasizeSelfInText = true,
},
global = {}
}
defaults.global.classes = {}
for _, class in ipairs(CLASS_SORT_ORDER) do
defaults.global.classes[class] = LOCALIZED_CLASS_NAMES_MALE[class]
end
local default_nick_color = { ["r"] = 0.627, ["g"] = 0.627, ["b"] = 0.627 }
local localizedToSystemClass = table.invert(defaults.global.classes)
local tabComplete
do
function tabComplete(t, text, pos)
local word = text:sub(pos)
if #word == 0 then return end
local cf = ChatEdit_GetActiveWindow()
local channel = cf:GetAttribute("chatType")
if channel == "CHANNEL" then
local cn = select(2, GetChannelName(cf:GetAttribute("channelTarget")))
channel = cn and cn:lower() or ""
elseif channel == "OFFICER" then
channel = "GUILD"
elseif channel == "RAID_WARNING" or channel == "RAID_LEADER" or channel == "BATTLEGROUND" or channel == "BATTLEGROUND_LEADER" then
channel = "RAID"
end
if channels[channel] then
for k, v in pairs(channels[channel]) do
if k:lower():match("^" .. word:lower()) then
tinsert(t, k)
end
end
end
return t
end
end
local getNameColor
do
local sq2 = sqrt(2)
local pi = _G.math.pi
local cos = _G.math.cos
local fmod = _G.math.fmod
local strbyte = _G.strbyte
local t = {}
-- http://www.tecgraf.puc-rio.br/~mgattass/color/HSVtoRGB.htm
local function HSVtoRGB(h, s, v)
if ( s == 0 ) then
--achromatic=fail
t.r = v
t.g = v
t.b = v
if not t.r then t.r = 0 end
if not t.g then t.g = 0 end
if not t.b then t.b = 0 end
return t.r,t.g,t.b
end
h = h/60
local i = floor(h)
local i1 = v * (1 - s)
local i2 = v * (1 - s * (h - i))
local i3 = v * (1 - s * (1 - (h - i)))
if i == 0 then
-- return v, i3, i1
t.r = v
t.g = i3
t.b = i1
elseif i == 1 then
-- return i2, v, i1
t.r = i2
t.g = v
t.b = i1
elseif i == 2 then
-- return i1, v, i3
t.r = i1
t.g = v
t.b = i3
elseif i == 3 then
-- return i3, i2, v
t.r = i3
t.g = i2
t.b = v
elseif i == 4 then
-- return i3, i1, v
t.r = i3
t.g = i1
t.b = v
elseif i == 5 then
-- return v, i1, i2
t.r = v
t.g = i1
t.b = i2
else
DEFAULT_CHAT_FRAME:AddMessage("Chatter HSVtoRGB failed")
end
if not t.r then t.r = 0 end
if not t.g then t.g = 0 end
if not t.b then t.b = 0 end
return t.r,t.g,t.b
end
function getNameColor(name)
local seed = 5381 --old seed: 5124
local h, s, v = 1, 1, 1
local r, g, b
for i = 1, #name do
seed = 33 * seed + strbyte(name, i) --used to use 29 here
end
-- h = fmod(seed, 255) / 255
h = fmod(seed, 360) --changed the HSVtoRGB to acompany this change
if (h > 220) and (h < 270) then
h = h + 60
end
t.r, t.g, t.b = HSVtoRGB(h, s, v)
return t
end
end
local cache = {};
local function wipeCache()
wipe(cache)
end
local function updateSaveData(v)
if v then
for k, v in pairs(local_names) do
mod.db.realm.names[k] = v
end
end
end
function mod:OnInitialize()
self.db = Chatter.db:RegisterNamespace("PlayerNames", defaults)
for k, v in pairs(self.db.realm.names) do
if type(v) == "string" then
self.db.realm.names[k] = {class = v}
end
end
if self.db.global and self.db.global.names then
self.db.global.names = nil -- get rid of old data
end
end
function mod:Decorate(frame)
if not self:IsHooked(frame,"AddMessage") then
self:RawHook(frame, "AddMessage", true)
end
end
function mod:OnEnable()
self:RegisterEvent("RAID_ROSTER_UPDATE")
self:RegisterEvent("PARTY_MEMBERS_CHANGED")
self:RegisterEvent("WHO_LIST_UPDATE")
self:RegisterEvent("PLAYER_TARGET_CHANGED")
self:RegisterEvent("CHAT_MSG_SYSTEM", "WHO_LIST_UPDATE")
self:RegisterEvent("FRIENDLIST_UPDATE")
self:RegisterEvent("GUILD_ROSTER_UPDATE")
self:RegisterEvent("CHAT_MSG_CHANNEL_JOIN")
self:RegisterEvent("CHAT_MSG_CHANNEL_LEAVE")
self:RegisterEvent("CHAT_MSG_CHANNEL", "CHAT_MSG_CHANNEL_JOIN")
leftBracket, rightBracket, separator = self.db.profile.leftBracket, self.db.profile.rightBracket, self.db.profile.separator
colorSelfInText, emphasizeSelfInText = self.db.profile.colorSelfInText, self.db.profile.emphasizeSelfInText
if IsInGuild() then
GuildRoster()
end
self:RAID_ROSTER_UPDATE()
self:PARTY_MEMBERS_CHANGED()
for i = 1, NUM_CHAT_WINDOWS do
local cf = _G["ChatFrame" .. i]
if cf ~= COMBATLOG then
self:RawHook(cf, "AddMessage", true)
end
end
for index,frame in ipairs(self.TempChatFrames) do
local cf = _G[frame]
self:RawHook(cf, "AddMessage", true)
end
if self.db.profile.useTabComplete then
AceTab:RegisterTabCompletion("Chatter", nil, tabComplete)
end
if CUSTOM_CLASS_COLORS and CUSTOM_CLASS_COLORS.RegisterCallback then
CUSTOM_CLASS_COLORS:RegisterCallback(wipeCache)
end
end
function mod:OnDisable()
if AceTab:IsTabCompletionRegistered("Chatter") then
AceTab:UnregisterTabCompletion("Chatter")
end
if CUSTOM_CLASS_COLORS and CUSTOM_CLASS_COLORS.UnregisterCallback then
CUSTOM_CLASS_COLORS:UnregisterCallback(wipeCache)
end
end
function mod:ClearCustomClassColorCache()
end
function mod:AddPlayer(name, class, level, save)
if name and class and class ~= UNKNOWN then
if save or self.db.realm.names[name] then -- if we already have an entry saved from elsewhere, we update it regardless of the requested "save" type - nothing else makes sense
self.db.realm.names[name] = self.db.realm.names[name] or {}
self.db.realm.names[name].class = class
if level and level ~= 0 then
self.db.realm.names[name].level = level
end
else
local_names[name] = local_names[name] or {}
local_names[name].class = class
if level and level ~= 0 then
local_names[name].level = level
end
end
cache[name] = nil
end
end
function mod:FRIENDLIST_UPDATE(evt)
for i = 1, GetNumFriends() do
local name, level, class = GetFriendInfo(i)
if class then
self:AddPlayer(name, localizedToSystemClass[class], level, self.db.profile.saveFriends)
end
end
end
--[[
function mod:GUILD_ROSTER_UPDATE(evt)
local n = GetNumGuildMembers()
if not n or n == 0 then
return
end
local offline = GetGuildRosterShowOffline()
local selection = GetGuildRosterSelection()
self:UnregisterEvent("GUILD_ROSTER_UPDATE")
SetGuildRosterShowOffline(true)
SetGuildRosterSelection(0)
GetGuildRosterInfo(0)
n = GetNumGuildMembers()
for k, v in pairs(channels.GUILD) do
channels.GUILD[k] = nil
end
for i = 1, n do
local name, _, _, level, _, _, _, _, online, _, class = GetGuildRosterInfo(i)
if online then
channels.GUILD[name] = name
end
self:AddPlayer(name, class, level, self.db.profile.saveGuild)
end
SetGuildRosterShowOffline(offline)
SetGuildRosterSelection(selection)
self:RegisterEvent("GUILD_ROSTER_UPDATE")
end
]]
function mod:GUILD_ROSTER_UPDATE(evt)
if not IsInGuild() then return end
wipe( channels.GUILD )
for i = 1, GetNumGuildMembers() do
local name, _, _, level, _, _, _, _, online, _, class = GetGuildRosterInfo(i)
if name then
if online then
channels.GUILD[name] = name
end
self:AddPlayer(name, class, level, self.db.profile.saveGuild)
end
end
end
function mod:RAID_ROSTER_UPDATE(evt)
wipe(channels.RAID)
for i = 1, GetNumRaidMembers() do
local n, _, _, l, _, c = GetRaidRosterInfo(i)
if n and c and l then
channels.RAID[n] = true
self:AddPlayer(n, c, l, self.db.profile.saveParty)
end
end
end
function mod:PARTY_MEMBERS_CHANGED(evt)
wipe(channels.PARTY)
for i = 1, GetNumPartyMembers() do
local n = UnitName("party" .. i)
local _, c = UnitClass("party" .. i)
local l = UnitLevel("party" .. i)
channels.PARTY[n] = true
self:AddPlayer(n, c, l, self.db.profile.saveParty)
end
end
function mod:PLAYER_TARGET_CHANGED(evt)
if not UnitExists("target") or not UnitIsPlayer("target") or not UnitIsFriend("player", "target") then return end
local _, c = UnitClass("target")
local l = UnitLevel("target")
self:AddPlayer(UnitName("target"), c, l, self.db.profile.saveTarget)
end
function mod:UPDATE_MOUSEOVER_UNIT(evt)
if not UnitExists("mouseover") or not UnitIsPlayer("mouseover") or not UnitIsFriend("player", "mouseover") then return end
local _, c = UnitClass("mouseover")
local l = UnitLevel("mouseover")
self:AddPlayer(UnitName("mouseover"), c, l, self.db.profile.saveTarget)
end
function mod:WHO_LIST_UPDATE(evt)
if GetNumWhoResults() <= 3 or self.db.profile.saveAllWho then
for i = 1, GetNumWhoResults() do
local name, _, level, _, _, _, class = GetWhoInfo(i)
if class then
self:AddPlayer(name, class, level, self.db.profile.saveWho)
end
end
end
end
function mod:CHAT_MSG_CHANNEL_JOIN(evt, _, name, _, _, _, _, _, _, chan)
channels[chan:lower()] = channels[chan:lower()] or {}
channels[chan:lower()][name] = true
end
function mod:CHAT_MSG_CHANNEL_LEAVE(evt, _, name, _, _, _, _, _, _, chan)
if not channels[chan:lower()] then return end
channels[chan:lower()][name] = nil
end
local function changeName(msgHeader, name, extra, msgCnt,displayName, msgBody)
if name ~= player then
if emphasizeSelfInText then
msgBody = msgBody:gsub("("..player..")" , "|cffffff00>|r%1|cffffff00<|r"):gsub("("..player:lower()..")" , "|cffffff00>|r%1|cffffff00<|r")
end
if colorSelfInText then
msgBody = msgBody:gsub("("..player..")" , "|cffff0000%1|r"):gsub("("..player:lower()..")" , "|cffff0000%1|r")
end
end
if not strmatch( displayName, "|cff" ) then
displayName = mod:ColorName( name )
end
cache[name] = displayName
local level
local tab = mod.db.realm.names[name] or local_names[name]
if tab then
level = mod.db.profile.includeLevel and tab.level or nil
end
if level and (level ~= 80 or not mod.db.profile.excludeMaxLevel) then
if mod.db.profile.levelByDiff then
local c = GetQuestDifficultyColor(level)
level = ("|cff%02x%02x%02x%s|r"):format(c.r * 255, c.g * 255, c.b * 255, level)
displayName = ("%s%s%s"):format( displayName, separator, level )
else
-- If we already have a color -- steal it and use it to color the level
if strmatch( displayName, "|cff......" ) then
-- This will seriously fuck up the string if there is already more than 1 color ... FIXME
level = gsub(displayName, "((|cff......).-|r)", function (string, color)
return ("%s%s|r"):format( color, level )
end )
end
displayName = ("%s%s%s"):format( displayName, separator, level )
end
end
return ("|Hplayer:%s%s%s|h%s%s%s|h%s"):format(name, extra, msgCnt, leftBracket, displayName, rightBracket, msgBody)
end
function mod:ColorName( name )
local class
local tab = mod.db.realm.names[name] or local_names[name]
if tab then class = tab.class end
-- already known?
if cache[name] then
name = cache[name]
else
local coloring = mod.db.profile.nameColoring
-- not yet colored by blizzy
if coloring ~= "NONE" then
local c = default_nick_color
if coloring == "CLASS" then
c = CUSTOM_CLASS_COLORS and CUSTOM_CLASS_COLORS[class] or RAID_CLASS_COLORS[class] or default_nick_color
elseif coloring == "NAME" then
c = getNameColor(name)
end
name = ("|cff%02x%02x%02x%s|r"):format(c.r * 255, c.g * 255, c.b * 255, name )
end
end
return name
end
function mod:AddMessage(frame, text, ...)
if text and type(text) == "string" then
text = text:gsub("(|Hplayer:([^|:]+)([:%d+]*)([^|]*)|h%[([^%]]+)%]|h)(.-)$", changeName)
end
return self.hooks[frame].AddMessage(frame, text, ...)
end
function mod:Info()
return L["Provides options to color player names, add player levels, and add tab completion of player names."]
end
local options
function mod:GetOptions()
if not options then -- save RAM / load time
options = {
save = {
type = "group",
name = L["Save Data"],
desc = L["Save data between sessions. Will increase memory usage"],
args = {
guild = {
type = "toggle",
name = L["Guild"],
desc = L["Save class data from guild between sessions."],
get = function()
return mod.db.profile.saveGuild
end,
set = function(info, v)
mod.db.profile.saveGuild = v
updateSaveData(v)
end
},
group = {
type = "toggle",
name = L["Group"],
desc = L["Save class data from groups between sessions."],
get = function()
return mod.db.profile.saveGroup
end,
set = function(info, v)
mod.db.profile.saveGroup = v
updateSaveData(v)
end
},
friend = {
type = "toggle",
name = L["Friends"],
desc = L["Save class data from friends between sessions."],
get = function()
return mod.db.profile.saveFriends
end,
set = function(info, v)
mod.db.profile.saveFriends = v
updateSaveData(v)
end
},
target = {
type = "toggle",
name = L["Target/Mouseover"],
desc = L["Save class data from target/mouseover between sessions."],
get = function()
return mod.db.profile.saveTarget
end,
set = function(info, v)
mod.db.profile.saveTarget = v
updateSaveData(v)
end
},
who = {
type = "toggle",
name = L["Who"],
desc = L["Save class data from /who queries between sessions."],
order = 104,
get = function()
return mod.db.profile.saveWho
end,
set = function(info, v)
mod.db.profile.saveWho = v
updateSaveData(v)
end
},
saveAllWho = {
type = "toggle",
name = L["Save all /who data"],
desc = L["Will save all data for large /who queries"],
disabled = function() return not mod.db.profile.saveWho end,
order = 105,
get = function()
return mod.db.profile.saveAllWho
end,
set = function(info, v)
mod.db.profile.saveAllWho = v
end
},
resetDB = {
type = "execute",
name = L["Reset Data"],
desc = L["Destroys all your saved class/level data"],
func = function() wipe( mod.db.realm.names ) end,
order = 101,
confirm = function() return L["Are you sure you want to delete all your saved class/level data?"] end
}
}
},
leftbracket = {
type = "input",
name = L["Left Bracket"],
desc = L["Character to use for the left bracket"],
get = function() return mod.db.profile.leftBracket end,
set = function(i, v)
mod.db.profile.leftBracket = v
leftBracket = v
end
},
rightbracket = {
type = "input",
name = L["Right Bracket"],
desc = L["Character to use for the right bracket"],
get = function() return mod.db.profile.rightBracket end,
set = function(i, v)
mod.db.profile.rightBracket = v
rightBracket = v
end
},
separator = {
type = "input",
name = L["Separator"],
desc = L["Character to use between the name and level"],
get = function() return mod.db.profile.separator end,
set = function(i, v)
mod.db.profile.separator = v
separator = v
end
},
useTabComplete = {
type = "toggle",
name = L["Use Tab Complete"],
desc = L["Use tab key to automatically complete character names."],
get = function() return mod.db.profile.useTabComplete end,
set = function(info, v)
mod.db.profile.useTabComplete = v
if v and not AceTab:IsTabCompletionRegistered("Chatter") then
AceTab:RegisterTabCompletion("Chatter", nil, tabComplete)
elseif not v and AceTab:IsTabCompletionRegistered("Chatter") then
AceTab:UnregisterTabCompletion("Chatter")
end
end
},
colorSelfInText = {
type = "toggle",
name = L["Color self in messages"],
desc = L["Color own charname in messages."],
get = function() return mod.db.profile.colorSelfInText end,
set = function(i, v)
mod.db.profile.colorSelfInText = v
colorSelfInText = v
end
},
emphasizeSelfInText = {
type = "toggle",
name = L["Emphasize self in messages"],
desc = L["Add surrounding brackets to own charname in messages."],
width = "double",
get = function() return mod.db.profile.emphasizeSelfInText end,
set = function(i, v)
mod.db.profile.emphasizeSelfInText = v
emphasizeSelfInText = v
end
},
levelHeader = {
type = "header",
name = L["Level Options"],
order = 104
},
includeLevel = {
type = "toggle",
name = L["Include level"],
desc = L["Include the player's level"],
order = 105,
get = function() return mod.db.profile.includeLevel end,
set = function(info, val)
mod.db.profile.includeLevel = val
wipeCache()
end
},
excludeMaxLevel = {
type = "toggle",
name = L["Exclude max levels"],
desc = L["Exclude level display for max level characters"],
order = 105,
get = function() return mod.db.profile.excludeMaxLevel end,
set = function(info, val)
mod.db.profile.excludeMaxLevel = val
wipeCache()
end,
hidden = function() return not mod.db.profile.includeLevel end
},
colorLevelByDifficulty = {
type = "toggle",
name = L["Color level by difficulty"],
desc = L["Color level by difficulty"],
order = 105,
get = function()
return mod.db.profile.levelByDiff
end,
set = function(info, v)
mod.db.profile.levelByDiff = v
wipeCache()
end,
hidden = function() return not mod.db.profile.includeLevel end
},
colorBy = {
type = "select",
name = L["Color Player Names By..."],
desc = L["Select a method for coloring player names"],
values = colorMethods,
get = function() return mod.db.profile.nameColoring end,
set = function(info, val)
mod.db.profile.nameColoring = val
wipeCache()
end
}
}
end
return options
end
+90
View File
@@ -0,0 +1,90 @@
local mod = Chatter:NewModule("Scrollback")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["Scrollback"]
mod.toggleLabel = L["Enable Scrollback length modification"]
local defaults = {
profile = {}
}
local options = {}
local cache = setmetatable({}, {__mode='k'})
local function acquire()
local t = next(cache) or {}
cache[t] = nil
return t
end
local function reclaim(t)
for k in pairs(t) do
t[k] = nil
end
cache[t] = true
end
local function setlines(frame, lines)
if frame:GetMaxLines() ~= lines then
local history = acquire()
for regions = frame:GetNumRegions(),1,-1 do
local region = select(regions, frame:GetRegions())
if region:GetObjectType() == "FontString" then
table.insert(history, {region:GetText(), region:GetTextColor() })
end
end
frame:SetMaxLines(lines or 250)
Chatter.loading = true
for k,v in pairs(history) do
frame:AddMessage(unpack(v))
end
Chatter.loading = false
reclaim(history)
end
end
function mod:OnInitialize()
self.db = Chatter.db:RegisterNamespace("Scrollback", defaults)
for i = 1, NUM_CHAT_WINDOWS do
local s = "FRAME_" .. i
local frame = _G["ChatFrame" .. i]
options[s] = {
type = "range",
name = L["Chat Frame "] .. i,
desc = L["Chat Frame "] .. i,
min = 250,
max = 2500,
step = 10,
get = function() return self.db.profile[s] or 250 end,
set = function(info, value)
self.db.profile[s] = value
setlines(frame, value)
end
}
end
end
function mod:OnEnable()
for i = 1, NUM_CHAT_WINDOWS do
setlines(_G["ChatFrame"..i], self.db.profile["FRAME_"..i])
end
end
function mod:OnDisable()
for i = 1, NUM_CHAT_WINDOWS do
setlines(_G["ChatFrame"..i], 250)
end
end
function mod:GetOptions()
return options
end
function mod:Info()
return L["Lets you set the scrollback length of your chat frames."]
end
+74
View File
@@ -0,0 +1,74 @@
local mod = Chatter:NewModule("Server Positioning", "AceHook-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["Server Positioning"]
local defaults = {
profile = {
windowdata = {
['*'] = {
-- Blizzard defaults
width = 430,
height = 120,
}
}
}
}
function mod:OnInitialize()
self.db = Chatter.db:RegisterNamespace("Server Positioning", defaults)
self.db.RegisterCallback(self, "OnProfileChanged", "UpdateWindowData")
self.db.RegisterCallback(self, "OnProfileCopied", "UpdateWindowData")
self.db.RegisterCallback(self, "OnProfileReset", "UpdateWindowData")
end
function mod:Info()
return L["Disable server side storage of chat frame position and size."]
end
function mod:OnEnable()
self:RawHook('SetChatWindowSavedPosition', true)
self:RawHook('GetChatWindowSavedPosition', true)
self:RawHook('SetChatWindowSavedDimensions', true)
self:RawHook('GetChatWindowSavedDimensions', true)
self:UpdateWindowData()
end
function mod:OnDisable()
self:UnhookAll()
self:UpdateWindowData()
end
function mod:SetChatWindowSavedPosition(id, point, xOffset, yOffset)
local data = self.db.profile.windowdata[id]
data.point, data.xOffset, data.yOffset = point, xOffset, yOffset
end
function mod:GetChatWindowSavedPosition(id)
local data = self.db.profile.windowdata[id]
if not data.point then
data.point, data.xOffset, data.yOffset = self.hooks.GetChatWindowSavedPosition(id)
end
return data.point, data.xOffset, data.yOffset
end
function mod:SetChatWindowSavedDimensions(id, width, height)
local data = self.db.profile.windowdata[id]
data.width, data.height = width, height
end
function mod:GetChatWindowSavedDimensions(id)
local data = self.db.profile.windowdata[id]
if not data.width then
data.width, data.height = self.hooks.GetChatWindowSavedDimensions(id)
end
return data.width, data.height
end
function mod:UpdateWindowData()
for i = 1,NUM_CHAT_WINDOWS do
local frame = _G["ChatFrame"..i]
if frame and type(frame.GetID) == "function" then
FloatingChatFrame_Update(frame:GetID())
end
end
end
+98
View File
@@ -0,0 +1,98 @@
local mod = Chatter:NewModule("Message Splitting", "AceHook-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["Message Split"]
function mod:Info()
return L["Allows you to type messages longer than normal, and splits message that are too long."]
end
local function ChatEdit_SendText(editBox, addHistory, doParse)
if doParse then
ChatEdit_ParseText(editBox, 1);
end
local type = editBox:GetAttribute("chatType");
local text = editBox:GetText();
if ( strfind(text, "%s*[^%s]+") ) then
if ( type == "WHISPER") then
local target = editBox:GetAttribute("tellTarget");
ChatEdit_SetLastToldTarget(target);
SendChatMessage(text, type, editBox.language, target);
elseif ( type == "CHANNEL") then
SendChatMessage(text, type, editBox.language, editBox:GetAttribute("channelTarget"));
else
SendChatMessage(text, type, editBox.language);
end
if ( addHistory ) then
ChatEdit_AddHistory(editBox);
end
end
end
local MAX = 256
local getChunk
do
local buf = {}
function getChunk(text, start)
local stack = 0
local first = nil
buf = wipe(buf)
if start > #text then return nil end
for i = start, start + MAX - 1 do
local byte = text:sub(i, i)
local bit = text:sub(i, i+1)
if bit == "|c" or bit == "|H" then
first = first or i
stack = stack + 1
elseif (bit == "|r" or bit == "|h") and stack > 0 and first then
stack = stack - 1
if stack == 0 then
tinsert(buf, text:sub(first, i))
first = nil
end
elseif (byte == " " or byte == "") and stack == 0 and first then
tinsert(buf, text:sub(first or 1, i))
first = nil
else
first = first or i
end
end
if #buf == 0 then return nil end
local str = table.concat(buf, "")
return start + #str, str
end
end
function mod:OnEnterPressed(editBox)
local text = editBox:GetText()
if #text <= 255 then
ChatEdit_OnEnterPressed(editBox)
return
end
local first = true
for start, chunk in getChunk, text, 1 do
editBox:SetText(chunk)
ChatEdit_SendText(editBox, true, first);
first = false
end
local type = editBox:GetAttribute("chatType");
if ( ChatTypeInfo[type].sticky == 1 ) then
editBox:SetAttribute("stickyType", type);
end
ChatEdit_OnEscapePressed(editBox);
end
function mod:OnEnable()
ChatFrameEditBox:SetMaxLetters(2048)
ChatFrameEditBox:SetMaxBytes(2048)
self:RawHookScript(ChatFrameEditBox, "OnEnterPressed")
end
function mod:OnDisable()
ChatFrameEditBox:SetMaxLetters(256)
ChatFrameEditBox:SetMaxBytes(256)
end
+59
View File
@@ -0,0 +1,59 @@
local mod = Chatter:NewModule("Sticky Channels")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["Sticky Channels"]
local pairs = _G.pairs
local channels = {
SAY = L["Say"],
EMOTE = L["Emote"],
YELL = L["Yell"],
OFFICER = L["Officer"],
RAID_WARNING = L["Raid Warning"],
WHISPER = L["Whisper"],
BN_WHISPER = L["RealID Whisper"],
CHANNEL = L["Custom channels"]
}
local options = {}
local defaults = {profile = {}}
function mod:OnInitialize()
self.db = Chatter.db:RegisterNamespace("StickyChannels", defaults)
for k, v in pairs(channels) do
defaults.profile[k] = true
options[k] = {
type = "toggle",
name = v,
desc = (L["Make %s sticky"]):format(v),
get = function() return mod.db.profile[k] end,
set = function(info, v)
mod.db.profile[k] = v
ChatTypeInfo[k].sticky = v and 1 or 0
end
}
end
end
function mod:OnEnable()
for k, v in pairs(channels) do
ChatTypeInfo[k].sticky = self.db.profile[k] and 1 or 0
end
end
function mod:OnDisable()
ChatTypeInfo.EMOTE.sticky = 0
ChatTypeInfo.YELL.sticky = 0
ChatTypeInfo.OFFICER.sticky = 0
ChatTypeInfo.RAID_WARNING.sticky = 0
ChatTypeInfo.WHISPER.sticky = 0
ChatTypeInfo.CHANNEL.sticky = 0
ChatTypeInfo.BN_WHISPER.sticky = 0
end
function mod:GetOptions()
return options
end
function mod:Info()
return L["Makes channels you select sticky."]
end
+55
View File
@@ -0,0 +1,55 @@
local mod = Chatter:NewModule("Tell Target (/tt)", "AceHook-3.0", "AceEvent-3.0", "AceConsole-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["Tell Target (/tt)"]
local UnitIsPlayer = _G.UnitIsPlayer
local UnitCanAssist = _G.UnitCanAssist
local UnitIsCharmed = _G.UnitIsCharmed
local SendChatMessage = _G.SendChatMessage
local UnitIsSameServer = _G.UnitIsSameServer
local UnitName = _G.UnitName
local gsub = _G.string.gsub
function mod:OnEnable()
-- self:SecureHook("ChatEdit_ParseText")
for i = 1, 10 do
self:HookScript(_G["ChatFrame" .. i .. "EditBox"], "OnTextChanged")
end
if not self.slashCommandRegistered then
self:RegisterChatCommand("tt", "SendChatMessage")
self.slashCommandRegistered = true
end
end
function mod:OnTextChanged(obj)
local text = obj:GetText()
if text:sub(1, 4) == "/tt " then
self:TellTarget(obj.chatFrame, text:sub(5))
end
self.hooks[obj].OnTextChanged(obj)
end
function mod:TellTarget(frame, msg)
local unitname, realm
if UnitIsPlayer("target") and (UnitIsFriend("player", "target") or UnitIsCharmed("target")) then
unitname, realm = UnitName("target")
if unitname then unitname = gsub(unitname, " ", "") end
if unitname and not UnitIsSameServer("player", "target") then
unitname = unitname .. "-" .. gsub(realm, " ", "")
end
end
ChatFrame_SendTell((unitname or "InvalidTarget"), frame)
_G[frame:GetName() .. "EditBox"]:SetText(msg)
end
function mod:Info()
return L["Enables the /tt command to send a tell to your target."]
end
function mod:SendChatMessage(input)
if UnitIsPlayer("target") and (UnitCanAssist("player", "target") or UnitIsCharmed("target"))then
SendChatMessage(input, "WHISPER", nil, UnitName("target"))
end
end
+153
View File
@@ -0,0 +1,153 @@
local mod = Chatter:NewModule("Timestamps", "AceHook-3.0","AceEvent-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["Timestamps"]
local date = _G.date
local SELECTED_FORMAT
local COLOR
local FORMATS = {
["%I:%M:%S %p"] = L["HH:MM:SS AM (12-hour)"],
["%I:%M:S"] = L["HH:MM (12-hour)"],
["%X"] = L["HH:MM:SS (24-hour)"],
["%I:%M"] = L["HH:MM (12-hour)"],
["%H:%M"] = L["HH:MM (24-hour)"],
["%M:%S"] = L["MM:SS"],
}
local CHATFRAMES = {
["Frame1"] = L["Chat Frame "].."1",
["Frame3"] = L["Chat Frame "].."3",
["Frame4"] = L["Chat Frame "].."4",
["Frame5"] = L["Chat Frame "].."5",
["Frame6"] = L["Chat Frame "].."6",
["Frame7"] = L["Chat Frame "].."7",
["Frame8"] = L["Chat Frame "].."8",
["Frame9"] = L["Chat Frame "].."9",
["Frame10"] = L["Chat Frame "].."10",
["Frame11"] = L["Chat Frame "].."11",
["Frame12"] = L["Chat Frame "].."12",
["Frame13"] = L["Chat Frame "].."13",
["Frame14"] = L["Chat Frame "].."14",
["Frame15"] = L["Chat Frame "].."15",
["Frame16"] = L["Chat Frame "].."16",
["Frame17"] = L["Chat Frame "].."17",
["Frame18"] = L["Chat Frame "].."18",
}
local defaults = {
profile = { format = "%X", color = { r = 0.45, g = 0.45, b = 0.45 }, frames = {["Frame1"] = true, ["Frame3"] = true, ["Frame4"] = true, ["Frame5"] = true, ["Frame6"] = true, ["Frame7"] = true} }
}
local options = {
format = {
type = "select",
name = L["Timestamp format"],
desc = L["Timestamp format"],
values = FORMATS,
get = function() return mod.db.profile.format end,
set = function(info, v)
mod.db.profile.format = v
SELECTED_FORMAT = ("[" .. v .. "]")
end
},
customFormat = {
type = "input",
name = L["Custom format (advanced)"],
desc = L["Enter a custom time format. See http://www.lua.org/pil/22.1.html for a list of valid formatting symbols."],
get = function() return mod.db.profile.customFormat end,
set = function(info, v)
if #v == 0 then v = nil end
mod.db.profile.customFormat = v
SELECTED_FORMAT = v
end,
order = 101
},
color = {
type = "color",
name = L["Timestamp color"],
desc = L["Timestamp color"],
get = function()
local c = mod.db.profile.color
return c.r, c.g, c.b
end,
set = function(info, r, g, b, a)
local c = mod.db.profile.color
c.r, c.g, c.b = r, g, b
COLOR = ("%02x%02x%02x"):format(r * 255, g * 255, b * 255)
end,
disabled = function() return mod.db.profile.colorByChannel end
},
useChannelColor = {
type = "toggle",
name = L["Use channel color"],
desc = L["Color timestamps the same as the channel they appear in."],
get = function()
return mod.db.profile.colorByChannel
end,
set = function(info, v)
mod.db.profile.colorByChannel = v
end
},
frames = {
type = "multiselect",
name = L["Per chat frame settings"],
desc = L["Choose which chat frames display timestamps"],
values = CHATFRAMES,
get = function(info, k) return mod.db.profile.frames[k] end,
set = function(info, k, v) mod.db.profile.frames[k] = v end,
},
}
function mod:OnInitialize()
self.db = Chatter.db:RegisterNamespace("Timestamps", defaults)
end
function mod:Decorate(frame)
if not self:IsHooked(frame,"AddMessage") then
self:RawHook(frame, "AddMessage", true)
end
end
function mod:OnEnable()
SELECTED_FORMAT = mod.db.profile.customFormat or ("[" .. self.db.profile.format .. "]")
local c = self.db.profile.color
COLOR = ("%02x%02x%02x"):format(c.r * 255, c.g * 255, c.b * 255)
for i = 1, NUM_CHAT_WINDOWS do
local cf = _G["ChatFrame" .. i]
if cf ~= COMBATLOG then
self:RawHook(cf, "AddMessage", true)
end
end
for index,name in ipairs(self.TempChatFrames) do
local cf = _G[name]
if cf then
self:RawHook(cf, "AddMessage", true)
end
end
end
function mod:AddMessage(frame, text, ...)
local id = frame:GetID()
if id and self.db.profile.frames["Frame"..id] and not(CHAT_TIMESTAMP_FORMAT) then
if not Chatter.loading then
if not text then
return self.hooks[frame].AddMessage(frame, text, ...)
end
if self.db.profile.colorByChannel then
text = date(SELECTED_FORMAT) .. text
else
text = "|cff"..COLOR..date(SELECTED_FORMAT).."|r".. text
end
end
return self.hooks[frame].AddMessage(frame, text, ...)
end
return self.hooks[frame].AddMessage(frame, text, ...)
end
function mod:Info()
return L["Adds timestamps to chat."]
end
function mod:GetOptions()
return options
end
+42
View File
@@ -0,0 +1,42 @@
local mod = Chatter:NewModule("Tiny Chat")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["Tiny Chat"]
function mod:Info()
return L["Allows you to make the chat frames much smaller than usual."]
end
function mod:Decorate(frame)
frame:SetMinResize(50, 20)
frame:SetMaxResize(5000, 5000)
end
function mod:OnEnable()
for i = 1, NUM_CHAT_WINDOWS do
local cf = _G["ChatFrame" .. i]
cf:SetMinResize(50, 20)
cf:SetMaxResize(5000, 5000)
end
for index,name in ipairs(self.TempChatFrames) do
local cf = _G[name]
if cf then
cf:SetMinResize(50, 20)
cf:SetMaxResize(5000, 5000)
end
end
end
function mod:OnDisable()
for i = 1, NUM_CHAT_WINDOWS do
local cf = _G["ChatFrame" .. i]
cf:SetMinResize(296, 75)
cf:SetMaxResize(608, 400)
end
for index,name in ipairs(self.TempChatFrames) do
local cf = _G[name]
if cf then
cf:SetMinResize(296, 75)
cf:SetMaxResize(608, 400)
end
end
end
+535
View File
@@ -0,0 +1,535 @@
local mod = Chatter:NewModule("URL Copy", "AceHook-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["URL Copy"]
local gsub = _G.string.gsub
local ipairs = _G.ipairs
local pairs = _G.pairs
local fmt = _G.string.format
local sub = _G.string.sub
local tlds
local style = "|cffffffff|Hurl:%s|h[%s]|h|r"
local function Link(link, ...)
if link == nil then
return ""
end
return mod:RegisterMatch(fmt(style, link, link))
end
local function Link_TLD(link, tld, ...)
if link == nil or tld == nil then
return ""
end
if tlds[tld:upper()] then
return mod:RegisterMatch(fmt(style, link, link))
else
return mod:RegisterMatch(link)
end
end
local patterns = {
-- X://Y url
{ pattern = "^(%a[%w%.+-]+://%S+)", matchfunc=Link},
{ pattern = "%f[%S](%a[%w%.+-]+://%S+)", matchfunc=Link},
-- www.X.Y url
{ pattern = "^(www%.[-%w_%%]+%.%S+)", matchfunc=Link},
{ pattern = "%f[%S](www%.[-%w_%%]+%.%S+)", matchfunc=Link},
-- "W X"@Y.Z email (this is seriously a valid email)
--{ pattern = '^(%"[^%"]+%"@[-%w_%%%.]+%.(%a%a+))', matchfunc=Link_TLD},
--{ pattern = '%f[%S](%"[^%"]+%"@[-%w_%%%.]+%.(%a%a+))', matchfunc=Link_TLD},
-- X@Y.Z email
{ pattern = "(%S+@[-%w_%%%.]+%.(%a%a+))", matchfunc=Link_TLD},
-- XXX.YYY.ZZZ.WWW:VVVV/UUUUU IPv4 address with port and path
{ pattern = "^([0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d:[0-6]?%d?%d?%d?%d/%S+)", matchfunc=Link},
{ pattern = "%f[%S]([0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d:[0-6]?%d?%d?%d?%d/%S+)", matchfunc=Link},
-- XXX.YYY.ZZZ.WWW:VVVV IPv4 address with port (IP of ts server for example)
{ pattern = "^([0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d:[0-6]?%d?%d?%d?%d)%f[%D]", matchfunc=Link},
{ pattern = "%f[%S]([0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d:[0-6]?%d?%d?%d?%d)%f[%D]", matchfunc=Link},
-- XXX.YYY.ZZZ.WWW/VVVVV IPv4 address with path
{ pattern = "^([0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%/%S+)", matchfunc=Link},
{ pattern = "%f[%S]([0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%/%S+)", matchfunc=Link},
-- XXX.YYY.ZZZ.WWW IPv4 address
{ pattern = "^([0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%)%f[%D]", matchfunc=Link},
{ pattern = "%f[%S]([0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%)%f[%D]", matchfunc=Link},
-- X.Y.Z:WWWW/VVVVV url with port and path
{ pattern = "^([-%w_%%%.]+[-%w_%%]%.(%a%a+):[0-6]?%d?%d?%d?%d/%S+)", matchfunc=Link_TLD},
{ pattern = "%f[%S]([-%w_%%%.]+[-%w_%%]%.(%a%a+):[0-6]?%d?%d?%d?%d/%S+)", matchfunc=Link_TLD},
-- X.Y.Z:WWWW url with port (ts server for example)
{ pattern = "^([-%w_%%%.]+[-%w_%%]%.(%a%a+):[0-6]?%d?%d?%d?%d)%f[%D]", matchfunc=Link_TLD},
{ pattern = "%f[%S]([-%w_%%%.]+[-%w_%%]%.(%a%a+):[0-6]?%d?%d?%d?%d)%f[%D]", matchfunc=Link_TLD},
-- X.Y.Z/WWWWW url with path
{ pattern = "^([-%w_%%%.]+[-%w_%%]%.(%a%a+)/%S+)", matchfunc=Link_TLD},
{ pattern = "%f[%S]([-%w_%%%.]+[-%w_%%]%.(%a%a+)/%S+)", matchfunc=Link_TLD},
-- X.Y.Z url
{ pattern = "^([-%w_%%%.]+[-%w_%%]%.(%a%a+))", matchfunc=Link_TLD},
{ pattern = "%f[%S]([-%w_%%%.]+[-%w_%%]%.(%a%a+))", matchfunc=Link_TLD},
}
local options = {
mangleMumble = {
type = "toggle",
name = L["Parse Mumble links"],
desc = L["Automatically inject your character's name into Mumble links, so you connect with your username prefilled."],
get = function() return mod.db.profile.mangleMumble end,
set = function(info, v) mod.db.profile.mangleMumble = v end
},
mangleTeamspeak = {
type = "toggle",
name = L["Parse Teamspeak 3 links"],
desc = L["Automatically inject your character's name into Teamspeak 3 links, so you connect with your username prefilled."],
get = function() return mod.db.profile.mangleTeamspeak end,
set = function(info, v) mod.db.profile.mangleTeamspeak = v end
}
}
do
local defaults = {
profile = {
mangleMumble = true,
mangleTeamspeak = true
}
}
local events = {
"CHAT_MSG_BATTLEGROUND", "CHAT_MSG_BATTLEGROUND_LEADER",
"CHAT_MSG_CHANNEL", "CHAT_MSG_EMOTE",
"CHAT_MSG_GUILD", "CHAT_MSG_OFFICER",
"CHAT_MSG_PARTY", "CHAT_MSG_RAID",
"CHAT_MSG_RAID_LEADER", "CHAT_MSG_RAID_WARNING", "CHAT_MSG_PARTY_LEADER",
"CHAT_MSG_SAY", "CHAT_MSG_WHISPER","CHAT_MSG_BN_WHISPER",
"CHAT_MSG_WHISPER_INFORM", "CHAT_MSG_YELL", "CHAT_MSG_BN_WHISPER_INFORM","CHAT_MSG_BN_CONVERSATION"
}
function mod:OnInitialize()
self.db = Chatter.db:RegisterNamespace("UrlCopy", defaults)
end
function mod:OnEnable()
for _,event in ipairs(events) do
ChatFrame_AddMessageEventFilter(event, self.filterFunc)
end
self:RawHook("SetItemRef", true)
end
function mod:OnDisable()
for _,event in ipairs(events) do
ChatFrame_RemoveMessageEventFilter(event, self.filterFunc)
end
end
end
do
local tokennum, matchTable = 1, {}
mod.filterFunc = function(frame, event, msg, ...)
if not msg then return false, msg, ... end
for i, v in ipairs(patterns) do
msg = gsub(msg, v.pattern, v.matchfunc)
end
for k,v in pairs(matchTable) do
msg = gsub(msg, k, v)
matchTable[k] = nil
end
return false, msg, ...
end
function mod:RegisterMatch(text)
local token = "\255\254\253"..tokennum.."\253\254\255"
matchTable[token] = gsub(text, "%%", "%%%%")
tokennum = tokennum + 1
return token
end
end
--[[ Popup Box ]]--
local currentLink
StaticPopupDialogs["ChatterUrlCopyDialog"] = {
text = "URL - Ctrl-C to copy",
button2 = CLOSE,
hasEditBox = 1,
hasWideEditBox = 1,
OnShow = function()
local editBox = _G[this:GetName().."WideEditBox"]
if editBox then
editBox:SetText(currentLink)
editBox:SetFocus()
editBox:HighlightText(0)
end
local button = _G[this:GetName().."Button2"]
if button then
button:ClearAllPoints()
button:SetWidth(200)
button:SetPoint("CENTER", editBox, "CENTER", 0, -30)
end
end,
EditBoxOnEscapePressed = function() this:GetParent():Hide() end,
timeout = 0,
whileDead = 1,
hideOnEscape = 1,
maxLetters=1024, -- this otherwise gets cached from other dialogs which caps it at 10..20..30...
}
local mangleLinkForVoiceChat
do
--[[
mumble://192.168.1.102:50008?version=1.2.0
mumble://foo:bar@192.168.1.102:50008?version=1.2.0
mumble://:bar@192.168.1.102:50008?version=1.2.0
]]--
-- Messes with Mumble links to inject our own username. Nifty magical!
local function injectCharacterNameForMumble(scheme, connstr)
local pre, post = strsplit("@", connstr, 2)
local new
if post then
local user, password = strsplit(":", pre, 2)
if password then
new = UnitName("player") .. ":" .. password
else
new = UnitName("player")
end
new = new .. "@" .. post
else
new = UnitName("player") .. "@" .. pre
end
return scheme .. new
end
local buff = {}
local function addTS3Nickname(...)
wipe(buff)
for i = 1, select("#", ...) do
local chunk = select(i, ...)
local key, val = strsplit("=", chunk, 2)
if val then
if strlower(key) ~= "nickname" then
tinsert(buff, chunk)
end
end
end
if not gotName then
local nick = "nickname=" .. UnitName("player")
tinsert(buff, nick)
end
return table.concat(buff, "&")
end
--[[
ts3server://ts3.hoster.com
ts3server://ts3.hoster.com?
ts3server://ts3.hoster.com?port=9987&
ts3server://ts3.hoster.com?port=9987&nickname=UserNickname&password=serverPassword
]]--
local function injectCharacterNameForTeamspeak(scheme, connstr)
local url, query = strsplit("?", connstr, 2)
if query then
query = addTS3Nickname(strsplit("&", query))
else
query = "nickname=" .. UnitName("player")
end
return scheme .. url .. "?" .. query
end
function mangleLinkForVoiceChat(text)
if mod.db.profile.mangleMumble then
text = text:gsub("^(mumble://)([^/?]+)", injectCharacterNameForMumble)
end
if mod.db.profile.mangleTeamspeak then
text = text:gsub("^(ts3server://)(.+)", injectCharacterNameForTeamspeak)
end
return text
end
end
function mod:SetItemRef(link, text, button)
if sub(link, 1, 3) == "url" then
currentLink = sub(link, 5)
currentLink = mangleLinkForVoiceChat(currentLink)
StaticPopup_Show("ChatterUrlCopyDialog")
return
end
return self.hooks.SetItemRef(link, text, button)
end
function mod:Info()
return L["Lets you copy URLs out of chat."]
end
function mod:GetOptions()
return options
end
tlds = {
ONION = true,
-- Copied from http://data.iana.org/TLD/tlds-alpha-by-domain.txt
-- Version 2008041301, Last Updated Mon Apr 21 08:07:00 2008 UTC
AC = true,
AD = true,
AE = true,
AERO = true,
AF = true,
AG = true,
AI = true,
AL = true,
AM = true,
AN = true,
AO = true,
AQ = true,
AR = true,
ARPA = true,
AS = true,
ASIA = true,
AT = true,
AU = true,
AW = true,
AX = true,
AZ = true,
BA = true,
BB = true,
BD = true,
BE = true,
BF = true,
BG = true,
BH = true,
BI = true,
BIZ = true,
BJ = true,
BM = true,
BN = true,
BO = true,
BR = true,
BS = true,
BT = true,
BV = true,
BW = true,
BY = true,
BZ = true,
CA = true,
CAT = true,
CC = true,
CD = true,
CF = true,
CG = true,
CH = true,
CI = true,
CK = true,
CL = true,
CM = true,
CN = true,
CO = true,
COM = true,
COOP = true,
CR = true,
CU = true,
CV = true,
CX = true,
CY = true,
CZ = true,
DE = true,
DJ = true,
DK = true,
DM = true,
DO = true,
DZ = true,
EC = true,
EDU = true,
EE = true,
EG = true,
ER = true,
ES = true,
ET = true,
EU = true,
FI = true,
FJ = true,
FK = true,
FM = true,
FO = true,
FR = true,
GA = true,
GB = true,
GD = true,
GE = true,
GF = true,
GG = true,
GH = true,
GI = true,
GL = true,
GM = true,
GN = true,
GOV = true,
GP = true,
GQ = true,
GR = true,
GS = true,
GT = true,
GU = true,
GW = true,
GY = true,
HK = true,
HM = true,
HN = true,
HR = true,
HT = true,
HU = true,
ID = true,
IE = true,
IL = true,
IM = true,
IN = true,
INFO = true,
INT = true,
IO = true,
IQ = true,
IR = true,
IS = true,
IT = true,
JE = true,
JM = true,
JO = true,
JOBS = true,
JP = true,
KE = true,
KG = true,
KH = true,
KI = true,
KM = true,
KN = true,
KP = true,
KR = true,
KW = true,
KY = true,
KZ = true,
LA = true,
LB = true,
LC = true,
LI = true,
LK = true,
LR = true,
LS = true,
LT = true,
LU = true,
LV = true,
LY = true,
MA = true,
MC = true,
MD = true,
ME = true,
MG = true,
MH = true,
MIL = true,
MK = true,
ML = true,
MM = true,
MN = true,
MO = true,
MOBI = true,
MP = true,
MQ = true,
MR = true,
MS = true,
MT = true,
MU = true,
MUSEUM = true,
MV = true,
MW = true,
MX = true,
MY = true,
MZ = true,
NA = true,
NAME = true,
NC = true,
NE = true,
NET = true,
NF = true,
NG = true,
NI = true,
NL = true,
NO = true,
NP = true,
NR = true,
NU = true,
NZ = true,
OM = true,
ORG = true,
PA = true,
PE = true,
PF = true,
PG = true,
PH = true,
PK = true,
PL = true,
PM = true,
PN = true,
PR = true,
PRO = true,
PS = true,
PT = true,
PW = true,
PY = true,
QA = true,
RE = true,
RO = true,
RS = true,
RU = true,
RW = true,
SA = true,
SB = true,
SC = true,
SD = true,
SE = true,
SG = true,
SH = true,
SI = true,
SJ = true,
SK = true,
SL = true,
SM = true,
SN = true,
SO = true,
SR = true,
ST = true,
SU = true,
SV = true,
SY = true,
SZ = true,
TC = true,
TD = true,
TEL = true,
TF = true,
TG = true,
TH = true,
TJ = true,
TK = true,
TL = true,
TM = true,
TN = true,
TO = true,
TP = true,
TR = true,
TRAVEL = true,
TT = true,
TV = true,
TW = true,
TZ = true,
UA = true,
UG = true,
UK = true,
UM = true,
US = true,
UY = true,
UZ = true,
VA = true,
VC = true,
VE = true,
VG = true,
VI = true,
VN = true,
VU = true,
WF = true,
WS = true,
YE = true,
YT = true,
YU = true,
ZA = true,
ZM = true,
ZW = true,
}