jcallahan@249: -- LUA API ------------------------------------------------------------ jcallahan@249: jcallahan@249: local _G = getfenv(0) jcallahan@249: jcallahan@249: local table = _G.table jcallahan@249: jcallahan@249: -- ADDON NAMESPACE ---------------------------------------------------- jcallahan@249: jcallahan@249: local ADDON_NAME, private = ... jcallahan@249: jcallahan@249: local LibStub = _G.LibStub jcallahan@249: local WDP = LibStub("AceAddon-3.0"):GetAddon(ADDON_NAME) jcallahan@259: local Dialog = LibStub("LibDialog-1.0") jcallahan@249: jcallahan@249: local ParseGUID = private.ParseGUID jcallahan@260: local ItemLinkToID = private.ItemLinkToID jcallahan@263: local DBEntry = private.DBEntry jcallahan@249: jcallahan@258: -- CONSTANTS ---------------------------------------------------------- jcallahan@258: jcallahan@258: local EDIT_MAXCHARS = 3000 jcallahan@259: local EDIT_DESCRIPTION_FORMAT = "Enter your comment below, being as descriptive as possible. Comments are limited to %s characters, including newlines and spaces." jcallahan@259: local LINK_COMMENT_TOOLTIP = "Click here to create a link to the comment page on WoWDB." jcallahan@261: local LINK_EDITBOX_DESC_FORMAT = "Copy the highlighted text and paste it into your browser to visit the comments for |cffffd200%s|r." jcallahan@259: jcallahan@259: local URL_BASE = "http://www.wowdb.com/" jcallahan@259: jcallahan@259: local URL_TYPE_MAP = { jcallahan@259: ITEM = "items", jcallahan@259: OBJECT = "objects", jcallahan@259: NPC = "npcs", jcallahan@261: QUEST = "quests", jcallahan@260: SPELL = "spells", jcallahan@259: VEHICLE = "npcs", jcallahan@259: } jcallahan@259: jcallahan@259: Dialog:Register("WDP_CommentLink", { jcallahan@259: text = "", jcallahan@259: editboxes = { jcallahan@259: { jcallahan@259: text = _G.UNKNOWN, jcallahan@259: on_escape_pressed = function(self) jcallahan@259: self:ClearFocus() jcallahan@259: end, jcallahan@265: on_enter_pressed = function(self) jcallahan@265: self:GetParent().buttons[1]:Click() jcallahan@265: end, jcallahan@259: }, jcallahan@259: }, jcallahan@259: buttons = { jcallahan@259: { jcallahan@259: text = _G.OKAY, jcallahan@259: } jcallahan@259: }, jcallahan@259: show_while_dead = true, jcallahan@259: hide_on_escape = true, jcallahan@259: is_exclusive = true, jcallahan@259: on_show = function(self, data) jcallahan@259: local editbox = self.editboxes[1] jcallahan@259: editbox:SetWidth(self:GetWidth() - 20) jcallahan@259: editbox:SetText(("%s%s/%d#related:comments"):format(URL_BASE, URL_TYPE_MAP[data.type_name], data.id)) jcallahan@259: editbox:HighlightText() jcallahan@259: editbox:SetFocus() jcallahan@259: jcallahan@261: self.text:SetJustifyH("LEFT") jcallahan@259: self.text:SetFormattedText(LINK_EDITBOX_DESC_FORMAT:format(data.label)) jcallahan@259: end, jcallahan@259: }) jcallahan@259: jcallahan@259: local comment_subject = {} jcallahan@258: jcallahan@249: -- HELPERS ------------------------------------------------------------ jcallahan@249: jcallahan@249: local comment_frame jcallahan@249: do jcallahan@249: local panel = _G.CreateFrame("Frame", "WDP_CommentFrame", _G.UIParent, "TranslucentFrameTemplate") jcallahan@258: panel:SetSize(480, 350) jcallahan@249: panel:SetPoint("CENTER", _G.UIParent, "CENTER") jcallahan@249: panel:SetFrameStrata("DIALOG") jcallahan@249: panel.Bg:SetTexture([[Interface\FrameGeneral\UI-Background-Rock]], true, true) jcallahan@249: panel.Bg:SetHorizTile(true) jcallahan@249: panel.Bg:SetVertTile(true) jcallahan@264: panel:EnableMouse(true) jcallahan@264: panel:SetMovable(true) jcallahan@249: panel:Hide() jcallahan@249: comment_frame = panel jcallahan@249: jcallahan@249: table.insert(_G.UISpecialFrames, panel:GetName()) jcallahan@249: jcallahan@249: local streaks = panel:CreateTexture("$parentTopTileStreaks", "BORDER", "_UI-Frame-TopTileStreaks", -6) jcallahan@249: streaks:SetPoint("TOPLEFT", 13, -13) jcallahan@249: streaks:SetPoint("BOTTOMRIGHT", panel, "TOPRIGHT", -13, -35) jcallahan@249: jcallahan@249: local header = _G.CreateFrame("Frame", "$parentHeader", panel, "TranslucentFrameTemplate") jcallahan@249: header:SetSize(128, 64) jcallahan@249: header:SetPoint("CENTER", panel, "TOP", 0, -8) jcallahan@249: header.Bg:SetTexture([[Interface\FrameGeneral\UI-Background-Marble]]) jcallahan@249: header.Bg:SetHorizTile(true) jcallahan@249: header.Bg:SetVertTile(true) jcallahan@264: header:SetMovable(true) jcallahan@264: jcallahan@264: header:SetScript("OnMouseDown", function() jcallahan@264: panel:StartMoving() jcallahan@264: end) jcallahan@264: jcallahan@264: header:SetScript("OnMouseUp", function() jcallahan@264: panel:StopMovingOrSizing() jcallahan@264: end) jcallahan@264: jcallahan@249: panel.header = header jcallahan@249: jcallahan@249: local logo = header:CreateTexture(nil, "ARTWORK") jcallahan@249: logo:SetTexture([[Interface\AddOns\WoWDBProfiler\wowdb-logo]]) jcallahan@249: logo:SetPoint("TOPLEFT", header, 10, -10) jcallahan@249: logo:SetPoint("BOTTOMRIGHT", header, -10, 10) jcallahan@249: jcallahan@258: local subject_name = panel:CreateFontString(nil, "ARTWORK", "GameFontNormal") jcallahan@258: subject_name:SetPoint("TOP", header, "BOTTOM", 0, -10) jcallahan@258: panel.subject_name = subject_name jcallahan@258: jcallahan@258: local subject_data = panel:CreateFontString(nil, "ARTWORK", "GameFontNormal") jcallahan@258: subject_data:SetPoint("TOP", subject_name, "BOTTOM", 0, -3) jcallahan@258: panel.subject_data = subject_data jcallahan@249: jcallahan@249: local close = _G.CreateFrame("Button", nil, panel, "UIPanelCloseButton") jcallahan@249: close:SetPoint("TOPRIGHT", panel, "TOPRIGHT", -7, -7) jcallahan@249: jcallahan@249: local scroll_frame = _G.CreateFrame("ScrollFrame", "$parentScrollFrame", panel) jcallahan@249: scroll_frame:SetSize(435, 150) jcallahan@249: scroll_frame:SetPoint("BOTTOM", 0, 70) jcallahan@249: jcallahan@249: scroll_frame:SetScript("OnScrollRangeChanged", function(self, x, y) jcallahan@249: _G.ScrollFrame_OnScrollRangeChanged(self, x, y) jcallahan@249: end) jcallahan@249: jcallahan@249: scroll_frame:SetScript("OnVerticalScroll", function(self, offset) jcallahan@249: local scrollbar = self.ScrollBar jcallahan@249: scrollbar:SetValue(offset) jcallahan@249: jcallahan@249: local min, max = scrollbar:GetMinMaxValues() jcallahan@249: jcallahan@249: if offset == 0 then jcallahan@249: scrollbar.ScrollUpButton:Disable() jcallahan@249: else jcallahan@249: scrollbar.ScrollUpButton:Enable() jcallahan@249: end jcallahan@249: jcallahan@249: if (scrollbar:GetValue() - max) == 0 then jcallahan@249: scrollbar.ScrollDownButton:Disable() jcallahan@249: else jcallahan@249: scrollbar.ScrollDownButton:Enable() jcallahan@249: end jcallahan@249: end) jcallahan@249: jcallahan@249: scroll_frame:SetScript("OnMouseWheel", function(self, delta) jcallahan@249: _G.ScrollFrameTemplate_OnMouseWheel(self, delta) jcallahan@249: end) jcallahan@249: jcallahan@266: -- This is needed because the EditBox starts with a height of a single line, so getting focus on click would require finding the EditBox blindly. jcallahan@266: scroll_frame:SetScript("OnMouseUp", function(self) jcallahan@266: _G.EditBox_SetFocus(self.edit_box) jcallahan@266: end) jcallahan@266: jcallahan@258: panel.scroll_frame = scroll_frame jcallahan@258: jcallahan@249: local edit_container = _G.CreateFrame("Frame", nil, scroll_frame) jcallahan@249: edit_container:SetPoint("TOPLEFT", scroll_frame, -7, 7) jcallahan@249: edit_container:SetPoint("BOTTOMRIGHT", scroll_frame, 7, -7) jcallahan@249: edit_container:SetFrameLevel(scroll_frame:GetFrameLevel() - 1) jcallahan@249: edit_container:SetBackdrop({ jcallahan@249: bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], jcallahan@249: edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]], jcallahan@249: tile = true, jcallahan@249: tileSize = 16, jcallahan@249: edgeSize = 16, jcallahan@249: insets = { jcallahan@249: left = 5, jcallahan@249: right = 5, jcallahan@249: top = 5, jcallahan@249: bottom = 5 jcallahan@249: } jcallahan@249: }) jcallahan@249: jcallahan@249: edit_container:SetBackdropBorderColor(_G.TOOLTIP_DEFAULT_COLOR.r, _G.TOOLTIP_DEFAULT_COLOR.g, _G.TOOLTIP_DEFAULT_COLOR.b) jcallahan@249: edit_container:SetBackdropColor(0, 0, 0) jcallahan@249: jcallahan@259: local link_button = _G.CreateFrame("Button", "$parentLinkButton", panel) jcallahan@259: link_button:SetSize(32, 16) jcallahan@259: link_button:SetPoint("TOPRIGHT", edit_container, "BOTTOMRIGHT", 5, 0) jcallahan@259: jcallahan@259: link_button:SetNormalTexture([[Interface\TradeSkillFrame\UI-TradeSkill-LinkButton]]) jcallahan@259: link_button:GetNormalTexture():SetTexCoord(0, 1, 0, 0.5) jcallahan@259: jcallahan@259: link_button:SetHighlightTexture([[Interface\TradeSkillFrame\UI-TradeSkill-LinkButton]]) jcallahan@259: link_button:GetHighlightTexture():SetTexCoord(0, 1, 0.5, 1) jcallahan@259: jcallahan@259: link_button:SetScript("OnClick", function(self) jcallahan@259: Dialog:Spawn("WDP_CommentLink", { type_name = comment_subject.type_name, id = comment_subject.id, label = comment_subject.label }) jcallahan@259: end) jcallahan@259: jcallahan@259: link_button:SetScript("OnEnter", function(self) jcallahan@259: _G.GameTooltip:SetOwner(self, "ANCHOR_TOPLEFT") jcallahan@259: _G.GameTooltip:SetText(LINK_COMMENT_TOOLTIP, nil, nil, nil, nil, 1) jcallahan@259: _G.GameTooltip:Show() jcallahan@259: end) jcallahan@259: jcallahan@259: link_button:SetScript("OnLeave", _G.GameTooltip_Hide) jcallahan@259: jcallahan@266: local edit_description = edit_container:CreateFontString(nil, "ARTWORK", "GameFontHighlight") jcallahan@258: edit_description:SetHeight(36) jcallahan@258: edit_description:SetPoint("BOTTOMLEFT", edit_container, "TOPLEFT", 5, 3) jcallahan@258: edit_description:SetPoint("BOTTOMRIGHT", edit_container, "TOPRIGHT", 5, 3) jcallahan@258: edit_description:SetFormattedText(EDIT_DESCRIPTION_FORMAT, _G.BreakUpLargeNumbers(EDIT_MAXCHARS)) jcallahan@258: edit_description:SetWordWrap(true) jcallahan@258: edit_description:SetJustifyH("LEFT") jcallahan@258: jcallahan@266: local edit_box = _G.CreateFrame("EditBox", "$parentEditBox", scroll_frame) jcallahan@249: edit_box:SetMultiLine(true) jcallahan@258: edit_box:SetMaxLetters(EDIT_MAXCHARS) jcallahan@249: edit_box:EnableMouse(true) jcallahan@249: edit_box:SetAutoFocus(false) jcallahan@249: edit_box:SetFontObject("ChatFontNormal") jcallahan@249: edit_box:SetSize(420, 220) jcallahan@249: edit_box:HighlightText(0) jcallahan@266: edit_box:SetFrameLevel(scroll_frame:GetFrameLevel() + 1) jcallahan@249: jcallahan@249: edit_box:SetScript("OnCursorChanged", _G.ScrollingEdit_OnCursorChanged) jcallahan@249: edit_box:SetScript("OnEscapePressed", _G.EditBox_ClearFocus) jcallahan@249: edit_box:SetScript("OnShow", function(self) jcallahan@249: _G.EditBox_SetFocus(self) jcallahan@249: jcallahan@249: if self:GetNumLetters() > 0 then jcallahan@249: panel.submitButton:Enable() jcallahan@249: else jcallahan@249: panel.submitButton:Disable() jcallahan@249: end jcallahan@249: end) jcallahan@249: jcallahan@249: edit_box:SetScript("OnTextChanged", function(self, user_input) jcallahan@249: local parent = self:GetParent() jcallahan@249: local num_letters = self:GetNumLetters() jcallahan@249: _G.ScrollingEdit_OnTextChanged(self, parent) jcallahan@258: parent.charCount:SetFormattedText(_G.BreakUpLargeNumbers(self:GetMaxLetters() - num_letters)) jcallahan@249: jcallahan@249: if num_letters > 0 then jcallahan@249: panel.submitButton:Enable(); jcallahan@258: else jcallahan@258: panel.submitButton:Disable() jcallahan@249: end jcallahan@249: end) jcallahan@249: jcallahan@249: edit_box:SetScript("OnUpdate", function(self, elapsed) jcallahan@249: _G.ScrollingEdit_OnUpdate(self, elapsed, self:GetParent()) jcallahan@249: end) jcallahan@249: jcallahan@258: scroll_frame.edit_box = edit_box jcallahan@249: scroll_frame:SetScrollChild(edit_box) jcallahan@249: jcallahan@249: local char_count = scroll_frame:CreateFontString(nil, "OVERLAY", "GameFontDisableLarge") jcallahan@249: char_count:SetPoint("BOTTOMRIGHT", -15, 0) jcallahan@249: scroll_frame.charCount = char_count jcallahan@249: jcallahan@249: local scroll_bar = _G.CreateFrame("Slider", "$parentScrollBar", scroll_frame, "UIPanelScrollBarTemplate") jcallahan@249: scroll_bar:SetPoint("TOPLEFT", scroll_frame, "TOPRIGHT", -13, -16) jcallahan@249: scroll_bar:SetPoint("BOTTOMLEFT", scroll_frame, "BOTTOMRIGHT", -13, 16) jcallahan@249: scroll_frame.ScrollBar = scroll_bar jcallahan@249: jcallahan@249: _G.ScrollFrame_OnLoad(scroll_frame) jcallahan@249: jcallahan@249: local submit = _G.CreateFrame("Button", "$parentSubmit", panel, "GameMenuButtonTemplate") jcallahan@249: submit:SetSize(160, 30) jcallahan@249: submit:SetPoint("BOTTOM", 0, 15) jcallahan@249: submit:SetText(_G.SUBMIT) jcallahan@249: submit:Enable(false) jcallahan@249: jcallahan@249: submit:SetScript("OnClick", function() jcallahan@263: local entry = DBEntry(URL_TYPE_MAP[comment_subject.type_name], comment_subject.id) jcallahan@263: jcallahan@263: if not entry then jcallahan@263: WDP:Print("An error has occurred; please report at http://wow.curseforge.com/addons/wowdb-profiler/create-ticket/") jcallahan@263: return jcallahan@263: end jcallahan@263: entry.comments = entry.comments or {} jcallahan@263: entry.comments[#entry.comments + 1] = edit_box:GetText() jcallahan@263: jcallahan@249: edit_box:SetText("") jcallahan@249: _G.HideUIPanel(panel) jcallahan@249: end) jcallahan@249: panel.submitButton = submit jcallahan@249: end jcallahan@249: jcallahan@260: local function CreateUnitComment(unit_id) jcallahan@260: if not _G.UnitExists(unit_id) then jcallahan@260: WDP:Printf("Unit '%s' does not exist.", unit_id) jcallahan@260: return jcallahan@260: end jcallahan@260: local unit_type, unit_idnum = ParseGUID(_G.UnitGUID(unit_id)) jcallahan@260: jcallahan@260: if not unit_idnum then jcallahan@260: WDP:Printf("Unable to determine unit from '%s'", unit_id) jcallahan@260: return jcallahan@260: end jcallahan@259: local type_name = private.UNIT_TYPE_NAMES[unit_type + 1] jcallahan@259: local unit_name = _G.UnitName(unit_id) jcallahan@259: comment_subject.type_name = type_name jcallahan@259: comment_subject.id = unit_idnum jcallahan@259: comment_subject.label = unit_name jcallahan@259: jcallahan@259: comment_frame.subject_name:SetText(unit_name) jcallahan@259: comment_frame.subject_data:SetFormattedText("(%s #%d)", type_name, unit_idnum) jcallahan@258: comment_frame.scroll_frame.edit_box:SetText("") jcallahan@262: _G.ShowUIPanel(comment_frame) jcallahan@249: end jcallahan@249: jcallahan@260: local DATA_TYPE_MAPPING = { jcallahan@260: merchant = "ITEM", jcallahan@260: } jcallahan@260: jcallahan@260: local CURSOR_DATA_FUNCS = { jcallahan@260: item = function(data_type, data, data_subtype) jcallahan@260: local item_name = _G.GetItemInfo(data) jcallahan@260: comment_subject.type_name = data_type jcallahan@260: comment_subject.id = data jcallahan@260: comment_subject.label = item_name jcallahan@260: jcallahan@260: comment_frame.subject_name:SetText(item_name) jcallahan@260: comment_frame.subject_data:SetFormattedText("(%s #%d)", data_type, data) jcallahan@260: end, jcallahan@260: merchant = function(data_type, data) jcallahan@260: local item_link = _G.GetMerchantItemLink(data) jcallahan@260: local item_name = _G.GetItemInfo(item_link) jcallahan@260: local item_id = ItemLinkToID(item_link) jcallahan@260: comment_subject.type_name = data_type jcallahan@260: comment_subject.id = item_id jcallahan@260: comment_subject.label = item_name jcallahan@260: jcallahan@260: comment_frame.subject_name:SetText(item_name) jcallahan@260: comment_frame.subject_data:SetFormattedText("(%s #%d)", data_type, item_id) jcallahan@260: end, jcallahan@260: spell = function(data_type, data, data_subtype, subdata) jcallahan@260: local spell_name = _G.GetSpellInfo(subdata) jcallahan@260: comment_subject.type_name = data_type jcallahan@260: comment_subject.id = subdata jcallahan@260: comment_subject.label = spell_name jcallahan@260: jcallahan@260: comment_frame.subject_name:SetText(spell_name) jcallahan@260: comment_frame.subject_data:SetFormattedText("(%s #%d)", data_type, subdata) jcallahan@260: end, jcallahan@260: } jcallahan@260: jcallahan@249: local function CreateCursorComment() jcallahan@260: local data_type, data, data_subtype, subdata = _G.GetCursorInfo() jcallahan@260: jcallahan@260: if not CURSOR_DATA_FUNCS[data_type] then jcallahan@260: WDP:Print("Unable to determine comment subject from cursor.") jcallahan@260: return jcallahan@260: end jcallahan@260: CURSOR_DATA_FUNCS[data_type](DATA_TYPE_MAPPING[data_type] or data_type:upper(), data, data_subtype, subdata) jcallahan@260: comment_frame.scroll_frame.edit_box:SetText("") jcallahan@262: _G.ShowUIPanel(comment_frame) jcallahan@249: end jcallahan@249: jcallahan@261: local function CreateQuestComment() jcallahan@261: local index = _G.GetQuestLogSelection() jcallahan@261: jcallahan@261: if not index or not _G.QuestLogFrame:IsShown() then jcallahan@261: WDP:Print("You must select a quest from the Quest frame.") jcallahan@261: return jcallahan@261: end jcallahan@261: local title, _, tag, _, is_header, _, _, _, idnum = _G.GetQuestLogTitle(index) jcallahan@261: jcallahan@261: if is_header then jcallahan@261: WDP:Print("You must select a quest from the Quest frame.") jcallahan@261: return jcallahan@261: end jcallahan@261: comment_subject.type_name = "QUEST" jcallahan@261: comment_subject.id = idnum jcallahan@261: comment_subject.label = title jcallahan@261: jcallahan@261: comment_frame.subject_name:SetText(title) jcallahan@261: comment_frame.subject_data:SetFormattedText("(%s #%d)", "QUEST", idnum) jcallahan@261: comment_frame.scroll_frame.edit_box:SetText("") jcallahan@262: _G.ShowUIPanel(comment_frame) jcallahan@261: end jcallahan@261: jcallahan@249: -- METHODS ------------------------------------------------------------ jcallahan@249: jcallahan@249: function private.ProcessCommentCommand(arg) jcallahan@249: if not arg or arg == "" then jcallahan@249: WDP:Print("You must supply a valid comment type.") jcallahan@249: return jcallahan@249: end jcallahan@249: jcallahan@249: if arg == "cursor" then jcallahan@260: CreateCursorComment() jcallahan@249: return jcallahan@261: elseif arg == "quest" then jcallahan@261: CreateQuestComment() jcallahan@261: return jcallahan@249: end jcallahan@260: CreateUnitComment(arg) jcallahan@249: end