Thread Tools Display Modes
09-09-16, 10:36 PM   #1
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
string.gsub questions

I am rewriting LibAboutPanel by Ackis to add some features, and this isn't new news to some people. However, I have hit some stumbling blocks.

In the attached picture, you will see under Version that the repository keyword is still visible, and should have been replaced.

Also, under Email, it says "Unknown" yet the ToC does have a value.

And last, for whatever reason, the display is changing "https:" to "http:" and I don't know why.

Linked first is my ToC, then the code for the library. I am using the AboutOptionsTable() API from the library.
Code:
## Interface: 70000
## Title: SmartRes2
## Notes: Co-ordinated targetless Party and Raid wipe recovery. Evolved
## Notes-ruRU: @localization(locale="ruRU", key="Notes", namespace="ToC")@
## Notes-deDE: @localization(locale="deDE", key="Notes", namespace="ToC")@
## Notes-koKR: @localization(locale="koKR", key="Notes", namespace="ToC")@
## Notes-esMX: @localization(locale="esMX", key="Notes", namespace="ToC")@
## Notes-esES: @localization(locale="esES", key="Notes", namespace="ToC")@
## Notes-ptBR: @localization(locale="ptBR", key="Notes", namespace="ToC")@
## Notes-zhCN: @localization(locale="zhCN", key="Notes", namespace="ToC")@
## Notes-zhTW: @localization(locale="zhTW", key="Notes", namespace="ToC")@
## Notes-itIT: @localization(locale="itIT", key="Notes", namespace="ToC")@
## Notes-frFR: @localization(locale="frFR", key="Notes", namespace="ToC")@
## Version: @project-version@
## X-Project-Revision: @project-revision@
## Author: Myrroddin of Knights of the Storm
## X-Author-Server: Llane US
## X-Author-Faction: Alliance
## X-Email: psvander at gmail dot com
## X-Category: Raid, Party, Healer, Priest, Shaman, Paladin, Druid, Monk
## SavedVariables: SmartRes2DB
## X-Localizations: enUS, frFR, deDE, esES, esMX, ruRU, zhCN, koKR, zhTW, ptBR, itIT
## X-Website: https://mods.curse.com/addons/wow/smartres2
## X-Credits: Jerry, Onaforeignshore, Morgalm, Torhal, and the original SmartRes team!
## X-License: (c) 2009 - 2016, Paul "Myrroddin" Vandersypen. All Rights Reserved
Here is the library code.
Code:
--[[
	Whom is doing what with this library
	$Date: $
	$Revision: $
	$Author: $
	$URL: $
	$Id: $
	$Header: $
]]--

local lib = LibStub:NewLibrary("LibAboutPanel-2.0", "$Revision: 1 $")
if not lib then
	return -- no upgrade necessary
end

-- handy fuction to create Title Case -----------
-- string.gsub(string, "(%a)([%w_']*)", TitleCase)
local function TitleCase(first, rest)
	return first:upper() .. rest:lower()
end

-- localization ---------------------------------
local function defaultTranslations(L, key)
	-- no translation for the key
	-- so it becomes its own translation
	return key
end
local L = setmetatable({},
	{__index = defaultTranslations
})

if GetLocale() == "koKR" then
--@localization(locale="koKR", format="lua_additive_table")@
elseif GetLocale() == "frFR" then
--@localization(locale="frFR", format="lua_additive_table")@
elseif GetLocale() == "deDE" then
--@localization(locale="deDE", format="lua_additive_table")@
elseif GetLocale() == "ruRU" then
--@localization(locale="ruRU", format="lua_additive_table")@
elseif GetLocale() == "zhTW" then
--@localization(locale="zhTW", format="lua_additive_table")@
elseif GetLocale() == "zhCN" then
--@localization(locale="zhCN", format="lua_additive_table")@
elseif GetLocale() == "itIT" then
--@localization(locale="itIT", format="lua_additive_table")@
elseif GetLocale() == "ptBR" then
--@localization(locale="ptBR", format="lua_additive_table")@
elseif GetLocale() == "esES" or GetLocale() == "esMX" then
--@localization(locale="esES", format="lua_additive_table")@
end

-- per AddOn options ----------------------------
local aboutTable = {}

-- LibAboutPanel stuff --------------------------
local editbox = CreateFrame("EditBox", nil, UIParent)
editbox:Hide()
editbox:SetAutoFocus(true)
editbox:SetHeight(32)
editbox:SetFontObject("GameFontHighlightSmall")
lib.editbox = editbox

local left = editbox:CreateTexture(nil, "BACKGROUND")
left:SetWidth(8) left:SetHeight(20)
left:SetPoint("LEFT", -5, 0)
left:SetTexture("Interface\\Common\\Common-Input-Border")
left:SetTexCoord(0, 0.0625, 0, 0.625)

local right = editbox:CreateTexture(nil, "BACKGROUND")
right:SetWidth(8) right:SetHeight(20)
right:SetPoint("RIGHT", 0, 0)
right:SetTexture("Interface\\Common\\Common-Input-Border")
right:SetTexCoord(0.9375, 1, 0, 0.625)

local center = editbox:CreateTexture(nil, "BACKGROUND")
center:SetHeight(20)
center:SetPoint("RIGHT", right, "LEFT", 0, 0)
center:SetPoint("LEFT", left, "RIGHT", 0, 0)
center:SetTexture("Interface\\Common\\Common-Input-Border")
center:SetTexCoord(0.0625, 0.9375, 0, 0.625)

editbox:SetScript("OnEscapePressed", editbox.ClearFocus)
editbox:SetScript("OnEnterPressed", editbox.ClearFocus)
editbox:SetScript("OnEditFocusLost", editbox.Hide)
editbox:SetScript("OnEditFocusGained", editbox.HighlightText)
editbox:SetScript("OnTextChanged", function(self)
	self:SetText(self:GetParent().val)
	self:HighlightText()
end)

local function OpenEditbox(self)
	editbox:SetText(self.val)
	editbox:SetParent(self)
	editbox:SetPoint("LEFT", self)
	editbox:SetPoint("RIGHT", self)
	editbox:Show()
end

local fields = { "Version", "Author", "X-Category", "X-License", "X-Email", "X-Website", "X-Credits", "X-Localizations" }
local haseditbox = { ["X-Website"] = true, ["X-Email"] = true }

local function HideTooltip()
	GameTooltip:Hide()
end

local function ShowTooltip(self)
	GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT")
	GameTooltip:SetText(L["Click and press Ctrl-C to copy"])
end

-- embedded functions beginning of file code
lib.embeds = lib.embeds or {}
local mixins = {
	"CreateAboutPanel",
	"AboutOptionsTable"
}

--- Embeds lib on target AddOn
-- So you can call LibStub("LibAboutPanel-2.0"):Embed(myAddOn)
-- @param target AddOn table in which to embed
-- @usage
-- local AddOnName, AddOn = ...
-- LibStub("LibAboutPanel-2.0"):Embed(AddOn)
-- -- **OR**, if using Ace3
-- -- you do not explicitly call :Embed
-- local MyAddOn = LibStub("AceAddon-3.0"):NewAddon("MyAddOn", "LibAboutPanel-2.0")
function lib:Embed(target)
	for k, v in pairs(mixins) do
		target[v] = self[v]
	end
	self.embeds[target] = true
	return target
end

--- Create a new About panel
-- @paramsig AddOn[, parent]
-- @param AddOn name of which you are attaching the panel. String
-- @param parent AddOn name in Interface Options. String or nil
-- If parent is provided, panel will be under [+]
-- otherwise the panel will be a normal AddOn category
-- @return frame To do as you wish
-- @usage local aboutFrame = MyAddOn:CreateAboutPanel("MyAddOn", "MyAddOn")
-- -- OR
-- MyAddOn:CreateAboutPanel("MyAddOn", "MyAddOn")
function lib:CreateAboutPanel(AddOn, parent)
	-- Remove spaces from AddOn because GetMetadata doesn't like those
	local gsubName = gsub(AddOn, " ", "")
	
	local about = CreateFrame("Frame", nil, UIParent)
	about.name = not parent and gsubName or L["About"]
	about.parent = parent
	about.AddOnName = gsubName
	about:Hide()
	about:SetScript("OnShow", OnShow)
	-- about.refresh = function() OnShow() end
	InterfaceOptions_AddCategory(about)
	return about
end

--- Creates a table of an AddOn's ToC fields
-- see http://www.wowace.com/addons/ace3/pages/api/ace-config-3-0/
-- @param AddOn name string whose ToC you want parsed
-- @return aboutTable suitable for use with AceConfig-3.0
-- @usage -- assuming options is your top-level table
-- local options = {} -- put your regular stuff here
-- options.args.aboutTable = MyAddOn:AboutOptionsTable("MyAddOn")
-- options.args.aboutTable.order = 100 -- use any number in the hierarchy
-- LibStub("AceConfig-3.0"):RegisterOptionsTable("MyAddOn", options)
function lib:AboutOptionsTable(AddOn)
	assert(LibStub("AceConfig-3.0"), "LibAboutPanel-2.0 API 'AboutOptionsTable' requires AceConfig-3.0", 2)
	aboutTable[AddOn] = aboutTable[AddOn] or {
		order = 10,
		name = L["About"],
		type = "group",
		args = {
			title = {
				order = 10,
				name = "|cffe6cc80" .. AddOn .. "|r",
				type = "description",
				fontSize = "large"
			},
			blank = {
				order = 20,
				name = "",
				type = "description"
			},
			notes = {
				order = 30,
				name = function()
					local notefield = "Notes"
					if GetLocale() ~= "enUS" then
						notefield = notefield .. "-" .. GetLocale()
					end
					local notes = GetAddOnMetadata(AddOn, notefield)
					return "|cffe6cc80" .. L["Notes"] .. ": |r" .. notes
				end,
				type = "description",
				fontSize = "medium"
			},
			blank2 = {
				order = 40,
				name = "",
				type = "description"
			},
			author = {
				order = 50,
				name = function()
					local author = GetAddOnMetadata(AddOn, "Author")
					author = string.gsub(author, "(%a)([%w_']*)", TitleCase)
					local authorservername = GetAddOnMetadata(AddOn, "X-Author-Server")
					authorservername = string.gsub(authorservername, "(%a)([%w_']*)", TitleCase)
					local authorfaction = GetAddOnMetadata(AddOn, "X-Author-Faction")
					authorfaction = string.gsub(authorfaction, "(%a)([%w_']*)", TitleCase)
					authorfaction = string.gsub(authorfaction, "Alliance", FACTION_ALLIANCE)
					authorfaction = string.gsub(authorfaction, "Horde", FACTION_HORDE)

					if authorservername and authorfaction then
						author = string.format(L["%s on the %s realm (%s)"], author, authorservername, authorfaction)
					elseif authorservername and not authorfaction then
						author = string.format(L["%s on the %s realm"], author, authorservername)
					elseif not authorservername and authorfaction then
						author = (author .. "( " .. authorfaction .. ")")
					else
						author = author -- redundancy check
					end
					return "|cffe6cc80" .. L["Author"] .. ": |r".. author
				end,
				type = "description"
			},
			version = {
				order = 60,
				name = function()
					local addonversion = GetAddOnMetadata(AddOn, "Version")
					-- replace repository keywords
					addonversion = string.gsub(addonversion, "@project-version@", L["Repository"]) -- Curse
					addonversion = string.gsub(addonversion, "wowi:revision", L["Repository"]) -- WoWInterface
					return "|cffe6cc80" .. L["Version"] .. ": |r" .. addonversion
				end,
				type = "description"
			},
			license = {
				order = 70,
				name = function()
					local copyright = GetAddOnMetadata(AddOn, "X-License") or UNKNOWN
					-- replace with © if applicable
					copyright = string.gsub(copyright, "Copyright", "©")
					copyright = string.gsub(copyright, "copyright", "©")
					copyright = string.gsub(copyright, "(C)", "©")
					copyright = string.gsub(copyright, "(c)", "©")
					copyright = string.gsub(copyright, "All Rights Reserved", L["All Rights Reserved"])
					return "|cffe6cc80" .. L["License"] .. ": |r" .. copyright
				end,
				type = "description"
			},
			localizations = {
				order = 80,
				name = function()
					local localizations = GetAddOnMetadata(AddOn, "X-Localizations") or UNKNOWN
					-- replace with global strings
					localizations = string.gsub(localizations, "enUS", LFG_LIST_LANGUAGE_ENUS)
					localizations = string.gsub(localizations, "frFR", LFG_LIST_LANGUAGE_FRFR)
					localizations = string.gsub(localizations, "deDE", LFG_LIST_LANGUAGE_DEDE)
					localizations = string.gsub(localizations, "esES", LFG_LIST_LANGUAGE_ESES)
					localizations = string.gsub(localizations, "esMX", LFG_LIST_LANGUAGE_ESMX)
					localizations = string.gsub(localizations, "koKR", LFG_LIST_LANGUAGE_KOKR)
					localizations = string.gsub(localizations, "itIT", LFG_LIST_LANGUAGE_ITIT)
					localizations = string.gsub(localizations, "ptBR", LFG_LIST_LANGUAGE_PTBR)
					localizations = string.gsub(localizations, "ruRU", LFG_LIST_LANGUAGE_RURU)
					localizations = string.gsub(localizations, "zhCN", LFG_LIST_LANGUAGE_ZHCN)
					localizations = string.gsub(localizations, "zhTW", LFG_LIST_LANGUAGE_ZHTW)
					return "|cffe6cc80" .. L["Localizations"] .. ": |r" .. localizations
				end,
				type = "description"
			},
			credits = {
				order = 90,
				name = function()
					return "|cffe6cc80" .. L["Credits"] .. ": |r" .. GetAddOnMetadata(AddOn, "X-Credits") or UNKNOWN
				end,
				type = "description"
			},
			website = {
				order = 100,
				name = "|cffe6cc80" .. L["Website"] .. ": |r",
				desc = L["Click and press Ctrl-C to copy"],
				type = "input",
				get = function()
					local website = GetAddOnMetadata(AddOn, "X-Website") or UNKNOWN
					return (haseditbox["X-Website"] and "|cff77ccff" or "") .. website
				end,
				width = "full"
			},
			email = {
				order = 110,
				name = "|cffe6cc80" .. L["Email"] .. ": |r",
				desc = L["Click and press Ctrl-C to copy"],
				get = function()
					local eMail = GetAddOnMetadata(AddOn, "X-Email") or UNKNOWN
					eMail = string.gsub(eMail, " at ", "@")
					eMail = string.gsub(eMail, " dot ", ".")
					return (haseditbox["X-Email"] and "|cff77ccff" or "") .. eMail
				end,
				type = "input",
				width = "full"
			}
		}
	}
	return aboutTable[AddOn]
end

local function OnShow(frame)
	-- Get the localized version of notes if it exists or fall back to the English one.
	local notefield = "Notes"
	if GetLocale() ~= "enUS" then
		notefield = notefield .. "-" .. GetLocale()
	end
	local notes = GetAddOnMetadata(frame.AddOnName, notefield)

	-- main title about.name or L["About"] ------
	local title = frame.about_title
	if not title then
		title = frame:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge")
		frame.about_title = title
	end
	title:SetPoint("TOPLEFT", 16, -16)
	title:SetText(frame.parent and (frame.parent .. " - " .. L["About"]) or frame.name)

	-- ToC Notes field --------------------------
	if not frame.about_subtitle then
		frame.about_subtitle = frame:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
	end
	local subtitle = frame.about_subtitle
	subtitle:SetHeight(32)
	subtitle:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -8)
	subtitle:SetPoint("RIGHT", frame, -32, 0)
	subtitle:SetNonSpaceWrap(true)
	subtitle:SetJustifyH("LEFT")
	subtitle:SetJustifyV("TOP")
	subtitle:SetText(notes)
	
	local anchor
	for i = 1, #fields do
		local field = fields[i]
		local value = GetAddOnMetadata(frame.AddOnName, field)
		if value then
			local title = frame[field .. "_title"]
			if not title then
				title = frame:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall")
				frame[field .. "_title"] = title
			end
			title:SetWidth(80)

			if not anchor then
				title:SetPoint("TOPLEFT", subtitle, "BOTTOMLEFT", -2, -12)
			else
				title:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", 0, -10)
			end
			title:SetJustifyH("RIGHT")
			title:SetJustifyV("TOP")
			-- fix for display
			-- first strip "X-" from field
			-- then TitleCase field
			local fixed_field = field:gsub("X%-", "")
			fixed_field = string.gsub(fixed_field, "(%a)([%w_']*)", TitleCase)
			title:SetText(L[fixed_field])

			local detail = frame[field .. "_detail"]
			if not detail then
				detail = frame:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
				frame[field .. "_detail"] = detail
			end
			detail:SetPoint("TOPLEFT", title, "TOPRIGHT", 4, 0)
			detail:SetPoint("RIGHT", frame, -16, 0)
			detail:SetJustifyH("LEFT")
			detail:SetJustifyV("TOP")

			if field == "Author" then
				local authorservername = GetAddOnMetadata(frame.AddOnName, "X-Author-Server")
				-- Title Case server
				authorservername = string.gsub(authorservername, "(%a)([%w_']*)", TitleCase)
				local authorfaction = GetAddOnMetadata(frame.AddOnName, "X-Author-Faction")
				authorfaction = string.gsub(authorfaction, "(%a)([%w_']*)", TitleCase)
				-- localize authorfaction -------
				aauthorfaction = string.gsub(authorfaction, "Alliance", FACTION_ALLIANCE)
				authorfaction = string.gsub(authorfaction, "Horde", FACTION_HORDE)

				if authorservername and authorfaction then
					detail:SetFormattedText(L["%s on the %s realm (%s)"], value, authorservername, authorfaction)
				elseif authorservername and not authorfaction then
					detail:SetFormattedText(L["%s on the %s realm"], value, authorservername)
				elseif not authorservername and authorfaction then
					detail:SetText(value .. "( " .. authorfaction .. ")")
				else
					detail:SetText(value)
				end
			elseif field == "Version" then
				local addonversion = GetAddOnMetadata(frame.AddOnName, field)
				-- Remove @project-revision@ and replace it with Repository
				addonversion = string.gsub(addonversion, "@project-version@", L["Repository"]) -- Curse
				addonversion = string.gsub(addonversion, "wowi:revision", L["Repository"]) -- WoWInterface
				detail:SetText(addonversion)
			elseif field == "X-License" then
				local copyright = GetAddOnMetadata(frame.AddOnName, "X-Copyright")
				if copyright then
					-- replace with © if applicable
					copyright = string.gsub(copyright, "Copyright", "\0169")
					copyright = string.gsub(copyright, "copyright", "\0169")
					copyright = string.gsub(copyright, "(C)", "\0169")
					copyright = string.gsub(copyright, "(c)", "\0169")
					detail:SetText(copyright .. "\n" .. value)
				else
					detail:SetText(value)
				end
			elseif field == "X-Localizations" then
				local localizations = GetAddOnMetadata(frame.AddOnName, "X-Localizations"):lower()
				-- replace with global strings
				localizations = string.gsub(localizations, "enus", LFG_LIST_LANGUAGE_ENUS)
				localizations = string.gsub(localizations, "frfr", LFG_LIST_LANGUAGE_FRFR)
				localizations = string.gsub(localizations, "dede", LFG_LIST_LANGUAGE_DEDE)
				localizations = string.gsub(localizations, "eses", LFG_LIST_LANGUAGE_ESES)
				localizations = string.gsub(localizations, "esmx", LFG_LIST_LANGUAGE_ESMX)
				localizations = string.gsub(localizations, "kokr", LFG_LIST_LANGUAGE_KOKR)
				localizations = string.gsub(localizations, "itit", LFG_LIST_LANGUAGE_ITIT)
				localizations = string.gsub(localizations, "ptbr", LFG_LIST_LANGUAGE_PTBR)
				localizations = string.gsub(localizations, "ruru", LFG_LIST_LANGUAGE_RURU)
				localizations = string.gsub(localizations, "zhcn", LFG_LIST_LANGUAGE_ZHCN)
				localizations = string.gsub(localizations, "zhtw", LFG_LIST_LANGUAGE_ZHTW)
				detail:SetText(localizations)
			elseif field == "X-Website" then
				detail:SetText((haseditbox[field] and "|cff77ccff" or "") .. gsub(value, "^https?://", ""))
			else
				local email = GetAddOnMetadata(frame.AddOnName, field):lower()
				email = string.gsub(email, " at ", "@")
				email = string.gsub(email, " dot ", ".")
				detail:SetText((haseditbox[field] and "|cff77ccff" or "") .. value)
			end

			local lineheight = math.min(detail:GetStringHeight(), 32)
			title:SetHeight(lineheight)
			detail:SetHeight(lineheight)

			if haseditbox[field] then
				local button = CreateFrame("Button", nil, frame)
				button:SetAllPoints(detail)
				button.value = value
				button:SetScript("OnClick", OpenEditbox)
				button:SetScript("OnEnter", ShowTooltip)
				button:SetScript("OnLeave", HideTooltip)
			end

			anchor = title
		end
	end
end

-- EoF embedding
for AddOn in pairs(lib.embeds) do
	lib:Embed(AddOn)
end
Attached Thumbnails
Click image for larger version

Name:	SR2.jpg
Views:	141
Size:	82.7 KB
ID:	8814  

Last edited by myrroddin : 09-09-16 at 10:38 PM. Reason: Missed something
  Reply With Quote
09-10-16, 05:55 AM   #2
Lombra
A Molten Giant
 
Lombra's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 554
Escape the dash.

Don't know about the URL.

Why do you have that OnShow? Doesn't the Ace config thingy do all of that?

Edit: Unrelated, but I think "Unknown" looks bad. Just don't show it at all, imo.
__________________
Grab your sword and fight the Horde!
  Reply With Quote
09-11-16, 12:31 AM   #3
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Originally Posted by Lombra View Post
Why do you have that OnShow? Doesn't the Ace config thingy do all of that?
LibAboutPanel isn't an AceConfig plugin. It creates and manages its own frames. It does have optional support for generating an AceConfig table, but in general it's a standalone library.

Originally Posted by Lombra View Post
Edit: Unrelated, but I think "Unknown" looks bad. Just don't show it at all, imo.
Agreed. If there's no data for a particular field, just don't show that field at all.

Some other aesthetic commentary based on your screenshot and the code:

1. You should use values as-is, rather than forcing your "ideal" capitalization onto what the addon author wrote. While replacing "phanx" with "Phanx" might be merely annoying if I preferred all-lowercase, replacing "FSH" with "Fsh" would actually be incorrect if those were my initials or another acronym/initialism, and replacing names like "Billy-Bob McDonald" with "Billy-bob Mcdonald" would also be incorrect.

2. Nobody cares what server/faction the addon's author plays on. Plus, in this day and age, it's unlikely the author's "pen name" is the same as their primary character's name, or maybe even any of their characters' names, so this information doesn't even give someone another way to contact the author. It's just clutter. If you really want to show it anyway for the very small % of addons that bother including it, the current "<name> on the <realm> realm" format feels awkward and overly wordy. "<name> of <realm>" would be better.

3. In copyright fields, you should not replace the word "Copyright" with a "©" symbol. While it's not hugely important here, legally speaking, the "©" symbol is purely aesthetic and has no actual meaning. You also should not replace the phrase "All Rights Reserved" with an arbitrary translation for non-English users. Translating legal terms and documents is a complicated process even for lawyers who specialize in that kind of thing. Most of the time, if you look at any legal documents that are translated into another language, the translation is even prefraced with a notice stating that the translation is not authoriative or legally meaningful, and is provided only for convenience -- only the document in its original language is official. You are not a lawyer, and neither are your volunteer translators, so just leave the legal text as it's written.

Originally Posted by myrroddin View Post
In the attached picture, you will see under Version that the repository keyword is still visible, and should have been replaced.
Is that picture using the AceConfig table or not? You're using totally different code paths for both of those, which is in general not a good idea. Rather than having two separate parts of the code that both fetch and format the TOC version field, you should factor that out into a single function that can be called from multiple places. Otherwise, whenever you change something, you have to change it in multiple places, and in reality you'll end up with different code in each place, because you'll change something in one place and forget to change it in the other(s). No good can come of this.

To minimize duplication, have a single function that fetches and formats field values:

Lua Code:
  1. local function GetDisplayText(addon, field, inlineLabel)
  2.     if not addon or not field then return end
  3.  
  4.     local value = string.trim(GetAddOnMetadata(addon, field) or "")
  5.     if value:len() == 0 then return end
  6.  
  7.     local label = field:gsub("^X%-", "")
  8.  
  9.     if label == "Author" then
  10.         local server = GetAddOnMetadata(addon, "X-Author-Server")
  11.         local faction = GetAddOnMetadata(addon, "X-Author-Faction")
  12.         if faction then
  13.             faction = faction:gsub("Alliance", FACTION_ALLIANCE)
  14.             faction = faction:gsub("Horde", FACTION_HORDE)
  15.         end
  16.  
  17.         if server and faction then
  18.             value = string.format(L["%s of %s (%s)"], value, server, faction)
  19.         elseif server then
  20.             value = string.format(L["%s of %s"], value, server)
  21.         elseif faction then
  22.             value = string.format(L["%s (%s)"], value, faction)
  23.         end
  24.        
  25.     elseif label == "Email" then
  26.         value = value:gsub(" at ", "@")
  27.         value = value:gsub(" dot ", ".")
  28.    
  29.     elseif label == "License" then
  30.         local copyright = GetAddOnMetadata(addon, "X-Copyright")
  31.         if copyright then
  32.             -- Remove trailing period if it exists,
  33.             -- then add one to separate copyright/license.
  34.             value = copyright:gsub("%.$", "") .. ". " .. value
  35.         end
  36.  
  37.     elseif label == "Version" then
  38.         -- Curse repository keyword
  39.         value = value:gsub("@project-version@", L["Repository"])
  40.         -- WoWInterface repository keyword
  41.         value = value:gsub("wowi:revision", L["Repository"])
  42.     end
  43.  
  44.     if inlineLabel then
  45.         return "|cffe6cc80" .. (L[label] or label) .. ":|r " .. value
  46.     elseif haseditbox[name] then
  47.         return "|cff77ccff" .. value .. "|r", label
  48.     else
  49.         return value, label
  50.     end
  51. end

Then, everywhere else in the code where you need a field value, just call:

Lua Code:
  1. local value, label = GetDisplayText("AddonName", "X-Author", true)

Note that this also consolidates formatting the label text (if the third parameter evaluates to true, then the label is prepended to the text inline; otherwise it's provided as a second return value) so you're not repeating that 20 times throughout the rest of the code either.

Originally Posted by myrroddin View Post
Also, under Email, it says "Unknown" yet the ToC does have a value.
What do you get if you run /dump GetAddOnMetadata("NameOfTheAddon", "X-Email") manually?

Originally Posted by myrroddin View Post
And last, for whatever reason, the display is changing "https:" to "http:" and I don't know why.
What do you get if you run /dump GetAddOnMetadata("NameOfTheAddon", "X-Website") manually?

(Also, in your non-AceConfig code path, you're stripping off the http or https protocol, but I don't see a reason to do this. Again, just show the values the addon author provided.)

Some other issues with your current code:

Code:
local function HideTooltip()
	GameTooltip:Hide()
end
Very minor, but you don't need this. There's already a global "GameTooltip_Hide" function that does this, so just use that.

Code:
	local notefield = "Notes"
	if GetLocale() ~= "enUS" then
		notefield = notefield .. "-" .. GetLocale()
	end
	local notes = GetAddOnMetadata(AddOn, notefield)
This will fail for many addons in non-English locales, because providing localized Notes fields in a TOC file is the exception rather than the rule -- more addons don't do it, than do. You should fall back to "Notes" if "Notes-frFR", for example, isn't found:

Code:
	local lang, notes = GetLocale()
	if lang ~= "enUS" then
		notes = GetAddOnMetadata(AddOn, "Notes-" .. lang)
	end
	if not notes then
		notes = GetAddOnMetadata(AddOn, "Notes")
	end
... or with the unified fetch-and-format function I posted above:

Code:
	local lang, notes, notesLabel = GetLocale()
	if lang ~= "enUS" then
		notes, notesLabel = GetDisplayText(AddOn, "Notes-" .. lang)
	end
	if not notes then
		notes, notesLabel = GetDisplayText(AddOn, "Notes")
	end
(You may want to re-read through the original LibAboutPanel code, as it handles this situation correctly.)

Your current AceConfig table generator code will throw an error if used on an addon that doesn't specify an author, an author server, and an author faction. You need to check that GetAddOnMetadata actually returned something before performing string operations on that returned value.

Also, the parts highlighted in red here are not necessary:

Code:
	if authorservername and authorfaction then
		author = string.format(L["%s on the %s realm (%s)"], author, authorservername, authorfaction)
	elseif authorservername and not authorfaction then
		author = string.format(L["%s on the %s realm"], author, authorservername)
	elseif not authorservername and authorfaction then
		author = (author .. "( " .. authorfaction .. ")")
	else
		author = author -- redundancy check
	end
If both "authorservername" and "authorfaction" (by the way, you should use camelCasing or under_scores to make your variable names more readable, eg. "authorServerName" or "author_server_name") have values, then the first condition matches, and no further conditions in the chain are checked.

If you get to the second condition, and "authorservername" has a value, you already know that "authorfaction" does not have a value -- if it did, the first condition would have matched instead -- so you don't need to check it again.

The "else" part does literally nothing, other than wasting CPU time reassigning a variable to the value it already has. Just delete that.

(Also, the unified fetch-and-format function I posted above doesn't have any of these issues.)

Code:
	local fixed_field = field:gsub("X%-", "")
	fixed_field = string.gsub(fixed_field, "(%a)([%w_']*)", TitleCase)
	title:SetText(L[fixed_field])
You really are overly fond of your TitleCase function.

In this case, the field names are things you specified yourself, in your own code so you already control their capitalization -- and as far as I can see, they're all already "initial capital + remainder lowercase", so running them through more functions to format them that way is just a waste of time.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.

Last edited by Phanx : 09-11-16 at 12:36 AM.
  Reply With Quote
09-11-16, 01:21 AM   #4
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
All excellent feedback, as always. Thank you Phanx and Lombra.

As to the lack of effiecency with my existing code, yes, Phanx's solution is by far more optimized and elegant. I did intend on doing something like that after I got the initial thing working, but now I'll just put it straight in.

I didn't like the "unknown" thing either, but couldn't figure out a way to bypass a ToC field if it didn't exist. I do now.

The TitleCase will be removed, and the camelCase/under_scores will be fixed. Some of that was copy/paste from the original LibAboutPanel. Yeah, no excuses!

The copyright and all rights reserved will be reverted, and I admit I am no lawyer as Phanx pointed out, and was unaware of the legalities.

Not going one by one though the tips and suggestions, but I will use them.
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » string.gsub questions


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off