local GREY = "|cff999999"; local RED = "|cffff0000"; local WHITE = "|cffFFFFFF"; local GREEN = "|cff1eff00"; local PURPLE = "|cff9F3FFF"; local BLUE = "|cff0070dd"; local ORANGE = "|cffFF8400"; local AL = LibStub("AceLocale-3.0"):GetLocale("AtlasLoot"); local modules = {"AtlasLoot_BurningCrusade", "AtlasLoot_Vanity", "AtlasLoot_Crafting", "AtlasLoot_OriginalWoW", "AtlasLoot_WorldEvents", "AtlasLoot_WrathoftheLichKing"}; local currentPage = 1; local SearchResult = nil; -- Supported Operators local OP_AND = "&" local BINARYOPERATORS = {OP_AND}; -- multi-character patterns must come before single-character patterns local RELATIONAL_OPERATORS = {">=", "<=", "<>", "<", ">", "="}; -- Supported Stat Filters local STAT_FILTERS = { -- Base Stats ["stamina"] = "ITEM_MOD_STAMINA_SHORT", ["stam"] = "ITEM_MOD_STAMINA_SHORT", ["sta"] = "ITEM_MOD_STAMINA_SHORT", ["strength"] = "ITEM_MOD_STRENGTH_SHORT", ["str"] = "ITEM_MOD_STRENGTH_SHORT", ["agility"] = "ITEM_MOD_AGILITY_SHORT", ["agi"] = "ITEM_MOD_AGILITY_SHORT", ["intellect"] = "ITEM_MOD_INTELLECT_SHORT", ["int"] = "ITEM_MOD_INTELLECT_SHORT", ["spirit"] = "ITEM_MOD_SPIRIT_SHORT", ["spir"] = "ITEM_MOD_SPIRIT_SHORT", ["spi"] = "ITEM_MOD_SPIRIT_SHORT", ["health"] = "ITEM_MOD_HEALTH_SHORT", ["mana"] = "ITEM_MOD_MANA_SHORT", ["mp5"] = "ITEM_MOD_POWER_REGEN0_SHORT", ["mpr"] = "ITEM_MOD_POWER_REGEN0_SHORT", ["hp5"] = "ITEM_MOD_HEALTH_REGEN_SHORT", ["hpr"] = "ITEM_MOD_HEALTH_REGEN_SHORT", -- Sockets ["socketblue"] = "EMPTY_SOCKET_BLUE", ["socketred"] = "EMPTY_SOCKET_RED", ["socketyellow"] = "EMPTY_SOCKET_YELLOW", ["socketnocolor"] = "EMPTY_SOCKET_NO_COLOR", ["socketwhite"] = "EMPTY_SOCKET_NO_COLOR", ["socketmeta"] = "EMPTY_SOCKET_META", ["meta"] = "EMPTY_SOCKET_META", -- Secondary Stats ["attackpowerferal"] = "ITEM_MOD_FERAL_ATTACK_POWER_SHORT", ["attackpowferal"] = "ITEM_MOD_FERAL_ATTACK_POWER_SHORT", ["apferal"] = "ITEM_MOD_FERAL_ATTACK_POWER_SHORT", ["attackpower"] = "ITEM_MOD_ATTACK_POWER_SHORT", ["attackpow"] = "ITEM_MOD_ATTACK_POWER_SHORT", ["ap"] = "ITEM_MOD_ATTACK_POWER_SHORT", ["spellpower"] = "ITEM_MOD_SPELL_POWER_SHORT", ["spellpow"] = "ITEM_MOD_SPELL_POWER_SHORT", ["sp"] = "ITEM_MOD_SPELL_POWER_SHORT", ["spellpenetration"] = "ITEM_MOD_SPELL_PENETRATION_SHORT", ["spellpen"] = "ITEM_MOD_SPELL_PENETRATION_SHORT", ["spp"] = "ITEM_MOD_SPELL_PENETRATION_SHORT", ["crit"] = "ITEM_MOD_CRIT_RATING_SHORT", ["haste"] = "ITEM_MOD_HASTE_RATING_SHORT", ["hit"] = "ITEM_MOD_HIT_RATING_SHORT", ["armorpenetration"] = "ITEM_MOD_ARMOR_PENETRATION_RATING_SHORT", ["armourpenetration"] = "ITEM_MOD_ARMOR_PENETRATION_RATING_SHORT", ["armorpen"] = "ITEM_MOD_ARMOR_PENETRATION_RATING_SHORT", ["armourpen"] = "ITEM_MOD_ARMOR_PENETRATION_RATING_SHORT", ["arp"] = "ITEM_MOD_ARMOR_PENETRATION_RATING_SHORT", ["expertise"] = "ITEM_MOD_EXPERTISE_RATING_SHORT", ["exp"] = "ITEM_MOD_EXPERTISE_RATING_SHORT", ["dps"] = "ITEM_MOD_DAMAGE_PER_SECOND_SHORT", ["resilience"] = "ITEM_MOD_RESILIENCE_RATING", ["resil"] = "ITEM_MOD_RESILIENCE_RATING", ["res"] = "ITEM_MOD_RESILIENCE_RATING", ["defense"] = "ITEM_MOD_DEFENSE_SKILL_RATING_SHORT", ["def"] = "ITEM_MOD_DEFENSE_SKILL_RATING_SHORT", ["dodge"] = "ITEM_MOD_DODGE_RATING_SHORT", ["dod"] = "ITEM_MOD_DODGE_RATING_SHORT", ["block"] = "ITEM_MOD_BLOCK_RATING_SHORT", ["blockvalue"] = "ITEM_MOD_BLOCK_VALUE_SHORT", ["blockval"] = "ITEM_MOD_BLOCK_VALUE_SHORT", ["bv"] = "ITEM_MOD_BLOCK_VALUE_SHORT", ["parry"] = "ITEM_MOD_PARRY_RATING_SHORT", -- Resistances ["armor"] = "RESISTANCE0_NAME", ["armour"] = "RESISTANCE0_NAME", ["arm"] = "RESISTANCE0_NAME", ["resistancephysical"] = "RESISTANCE0_NAME", ["resistancephys"] = "RESISTANCE0_NAME", ["resphys"] = "RESISTANCE0_NAME", ["resistanceholy"] = "RESISTANCE1_NAME", ["resholy"] = "RESISTANCE1_NAME", ["resistancefire"] = "RESISTANCE2_NAME", ["resfire"] = "RESISTANCE2_NAME", ["resistancenature"] = "RESISTANCE3_NAME", ["resnature"] = "RESISTANCE3_NAME", ["resnat"] = "RESISTANCE3_NAME", ["resistanceforst"] = "RESISTANCE4_NAME", ["resfrost"] = "RESISTANCE4_NAME", ["resistanceshadow"] = "RESISTANCE5_NAME", ["resshadow"] = "RESISTANCE5_NAME", ["resshad"] = "RESISTANCE5_NAME", ["resistancearcane"] = "RESISTANCE6_NAME", ["resarcane"] = "RESISTANCE6_NAME", ["resarc"] = "RESISTANCE6_NAME" }; local SOCKET_FILTERS = { ["socket"] = true, ["sockets"] = true, ["gem"] = true, ["gems"] = true }; local SOCKET_TYPES = {"EMPTY_SOCKET_BLUE", "EMPTY_SOCKET_RED", "EMPTY_SOCKET_YELLOW", "EMPTY_SOCKET_META", "EMPTY_SOCKET_NO_COLOR"}; local INFO_FILTERS = { ["ilvl"] = true, ["minlvl"] = true -- ["type"] = true, -- ["subtype"] = true, }; local QUALITY_FILTERS = { ["poor"] = 0, ["common"] = 1, ["uncommon"] = 2, ["rare"] = 3, ["epic"] = 4, ["legendary"] = 5, ["artifact"] = 6, ["heirloom"] = 7 }; local SLOT_FILTERS = { ["none"] = "INVTYPE_NON_EQUIP", ["head"] = "INVTYPE_HEAD", ["neck"] = "INVTYPE_NECK", ["shoulder"] = "INVTYPE_SHOULDER", ["body"] = "INVTYPE_BODY", ["chest"] = "INVTYPE_CHEST", ["waist"] = "INVTYPE_WAIST", ["legs"] = "INVTYPE_LEGS", ["feet"] = "INVTYPE_FEET", ["wrist"] = "INVTYPE_WRIST", ["hand"] = "INVTYPE_HAND", ["finger"] = "INVTYPE_FINGER", ["trinket"] = "INVTYPE_TRINKET", ["weapon"] = "INVTYPE_WEAPON", ["shield"] = "INVTYPE_SHIELD", ["ranged"] = "INVTYPE_RANGED", ["cloak"] = "INVTYPE_CLOAK", ["2hweapon"] = "INVTYPE_2HWEAPON", ["2h"] = "INVTYPE_2HWEAPON", ["bag"] = "INVTYPE_BAG", ["tabard"] = "INVTYPE_TABARD", ["robe"] = "INVTYPE_ROBE", ["weaponmainhand"] = "INVTYPE_WEAPONMAINHAND", ["mainhand"] = "INVTYPE_WEAPONMAINHAND", ["weaponoffhand"] = "INVTYPE_WEAPONOFFHAND", ["offhand"] = "INVTYPE_WEAPONOFFHAND", ["holdable"] = "INVTYPE_HOLDABLE", ["ammo"] = "INVTYPE_AMMO", ["thrown"] = "INVTYPE_THROWN", ["rangedright"] = "INVTYPE_RANGEDRIGHT", ["quiver"] = "INVTYPE_QUIVER", ["relic"] = "INVTYPE_RELIC" }; local TYPE_FILTERS = { ["cloth"] = "Cloth", ["leather"] = "Leather", ["mail"] = "Mail", ["plate"] = "Plate", ["shield"] = "Shields", ["libram"] = "Librams", ["idol"] = "Idols", ["totem"] = "Totems", ["sigil"] = "Sigils", ["axe1h"] = "One-Handed Axes", ["axe2h"] = "Two-Handed Axes", ["bows"] = "Bows", ["bow"] = "Bows", ["guns"] = "Guns", ["gun"] = "Guns", ["mace1h"] = "One-Handed Maces", ["mace2h"] = "Two-Handed Maces", ["polearm"] = "Polearms", ["sword1h"] = "One-Handed Swords", ["sword2h"] = "Two-Handed Swords", ["staff"] = "Staves", ["fist"] = "Fist Weapons", ["generic"] = "", ["dagger"] = "Daggers", ["thrown"] = "Thrown", ["crossbows"] = "Crossbows", ["crossbow"] = "Crossbows", ["wand"] = "Wands", ["fishingpole"] = "Fishing Poles" } local NON_EQUIPABLE_SLOTS = { ["INVTYPE_NON_EQUIP"] = true, ["INVTYPE_BODY"] = true, ["INVTYPE_BAG"] = true, ["INVTYPE_AMMO"] = true, ["INVTYPE_QUIVER"] = true }; SLASH_ATLASLOOTHELP1 = "/atlasloothelp"; SlashCmdList["ATLASLOOTHELP"] = function(msg, editBox) local function show(caption, t) local keys = {} for key in pairs(t) do table.insert(keys, key) end table.sort(keys, function(a, b) return a < b end) print(caption .. ": " .. table.concat(keys, ", ")) end show("stat", STAT_FILTERS) show("socket", SOCKET_FILTERS) show("slot", SLOT_FILTERS) show("quality", QUALITY_FILTERS) show("info", INFO_FILTERS) print("\nExamples:") print("gladiator") print("str>40") print("gladiator&str>40") print("str>40&ilvl>=120&ilvl<140&int>0&socket>2"); print("sp>20&quality>=rare&quality20&minlvl<=50") end SLASH_ATLASLOOTSEARCH1 = "/atlaslootsearch"; SLASH_ATLASLOOTSEARCH2 = "/als"; SlashCmdList["ATLASLOOTSEARCH"] = function(search, editBox) AtlasLootDefaultFrame:Show() if search and search ~= '' then AtlasLootDefaultFrameSearchBox:SetText(search) AtlasLootDefaultFrameSearchButton:Click() end end -- split one string on another (delimiter can be more than one character) local function SplitString(str, delimiter) local result = {} local start = 1 local len = #str while start <= len do local delimPos = str:find(delimiter, start, true) if delimPos then result[#result + 1] = str:sub(start, delimPos - 1) -- grab up to the delimeter start = delimPos + #delimiter -- advance past the delimiter else result[#result + 1] = str:sub(start) -- grab the rest of the string break end end return result end local function CompareNumbersByOperator(operator, left, right) return left and right and ((operator == "<>" and left ~= right) or (operator == "<=" and left <= right) or (operator == ">=" and left >= right) or (operator == "=" and left == right) or (operator == "<" and left < right) or (operator == ">" and left > right)) end local function ThrowQueryError(...) error("Error: " .. string.format(...)) end local function IsItemStatMatch(term, stats) local filterKey = STAT_FILTERS[term.left] if not filterKey then return end local statValue = tonumber(stats[filterKey]) if not statValue then return end local searchedValue = tonumber(term.right) if not searchedValue then ThrowQueryError("'%s' requires a numeric argument", term.left) end return CompareNumbersByOperator(term.relational, statValue, searchedValue) end local function IsItemLevelFilterMatch(term, itemLvl) if term.left ~= "ilvl" then return end local searchedValue = tonumber(term.right); if not searchedValue then ThrowQueryError("ilvl search requires a numeric argument") end return itemLvl ~= nil and itemLvl > 0 and CompareNumbersByOperator(term.relational, itemLvl, searchedValue) end local function IsItemQualityMatch(term, itemQuality) if term.left ~= "quality" then return end local searchedValue = QUALITY_FILTERS[term.right] if not searchedValue then ThrowQueryError("unrecognized quality value \"%s\"", term.right) end return CompareNumbersByOperator(term.relational, itemQuality, searchedValue) end local function IsItemSocketMatch(term, stats) if not SOCKET_FILTERS[term.left] then return end local searchedValue = tonumber(term.right) if not searchedValue then ThrowQueryError("'%s' requires a numeric argument", term.left) end local socketCount = 0; for _, socketType in pairs(SOCKET_TYPES) do local statValue = tonumber(stats[socketType]); if statValue then socketCount = socketCount + statValue; end end return CompareNumbersByOperator(term.relational, socketCount, searchedValue) end local function IsMinLevelFilterMatch(term, minLvl) if term.left ~= "minlvl" then return end local searchedValue = tonumber(term.right); if not searchedValue then ThrowQueryError("minlvl search requires a numeric argument") end return minLvl ~= nil and minLvl > 0 and CompareNumbersByOperator(term.relational, minLvl, searchedValue) end local function IsItemSlotMatch(term, itemEquipLoc) if term.left ~= "slot" then return end if term.relational ~= "=" then ThrowQueryError("slot searches should be in the form \"slot=[slotname]\"") end local slot = SLOT_FILTERS[term.right] if not slot then ThrowQueryError("unrecognized slot name: \"%s\"", term.right) end return slot == itemEquipLoc end local function IsItemTypeMatch(term, itemEquipType) if term.left ~= "type" then return end if term.relational ~= "=" then ThrowQueryError("type searches should be in the form \"type=[typename]\"") end local type = TYPE_FILTERS[term.right] if not type then ThrowQueryError("unrecognized type name: \"%s\"", term.right) end return type == itemEquipType; end local function nameMatches(name, searchText) if AtlasLoot.db.profile.PartialMatching then return string.find(string.lower(name), string.lower(searchText)); else return string.lower(name) == string.lower(searchText); end end local RelationalFunctions = { ["ilvl"] = {IsItemLevelFilterMatch, 3}, ["minlvl"] = {IsMinLevelFilterMatch, 4}, ["type"] = {IsItemTypeMatch, 6}, ["slot"] = {IsItemSlotMatch, 5}, ["quality"] = {IsItemQualityMatch, 2}, ["gem"] = {IsItemSocketMatch, 7}, ["gems"] = {IsItemSocketMatch, 7}, ["socket"] = {IsItemSocketMatch, 7}, ["sockets"] = {IsItemSocketMatch, 7}, -- Base Stats ["stamina"] = {IsItemStatMatch, 7}, ["stam"] = {IsItemStatMatch, 7}, ["sta"] = {IsItemStatMatch, 7}, ["strength"] = {IsItemStatMatch, 7}, ["str"] = {IsItemStatMatch, 7}, ["agility"] = {IsItemStatMatch, 7}, ["agi"] = {IsItemStatMatch, 7}, ["intellect"] = {IsItemStatMatch, 7}, ["int"] = {IsItemStatMatch, 7}, ["spirit"] = {IsItemStatMatch, 7}, ["spir"] = {IsItemStatMatch, 7}, ["spi"] = {IsItemStatMatch, 7}, ["health"] = {IsItemStatMatch, 7}, ["mana"] = {IsItemStatMatch, 7}, ["mp5"] = {IsItemStatMatch, 7}, ["mpr"] = {IsItemStatMatch, 7}, ["hp5"] = {IsItemStatMatch, 7}, ["hpr"] = {IsItemStatMatch, 7}, -- Sockets ["socketblue"] = {IsItemStatMatch, 7}, ["socketred"] = {IsItemStatMatch, 7}, ["socketyellow"] = {IsItemStatMatch, 7}, ["socketnocolor"] = {IsItemStatMatch, 7}, ["socketwhite"] = {IsItemStatMatch, 7}, ["socketmeta"] = {IsItemStatMatch, 7}, ["meta"] = {IsItemStatMatch, 7}, -- Secondary Stats ["attackpowerferal"] = {IsItemStatMatch, 7}, ["attackpowferal"] = {IsItemStatMatch, 7}, ["apferal"] = {IsItemStatMatch, 7}, ["attackpower"] = {IsItemStatMatch, 7}, ["attackpow"] = {IsItemStatMatch, 7}, ["ap"] = {IsItemStatMatch, 7}, ["spellpower"] = {IsItemStatMatch, 7}, ["spellpow"] = {IsItemStatMatch, 7}, ["sp"] = {IsItemStatMatch, 7}, ["spellpenetration"] = {IsItemStatMatch, 7}, ["spellpen"] = {IsItemStatMatch, 7}, ["spp"] = {IsItemStatMatch, 7}, ["crit"] = {IsItemStatMatch, 7}, ["haste"] = {IsItemStatMatch, 7}, ["hit"] = {IsItemStatMatch, 7}, ["armorpenetration"] = {IsItemStatMatch, 7}, ["armourpenetration"] = {IsItemStatMatch, 7}, ["armorpen"] = {IsItemStatMatch, 7}, ["armourpen"] = {IsItemStatMatch, 7}, ["arp"] = {IsItemStatMatch, 7}, ["expertise"] = {IsItemStatMatch, 7}, ["exp"] = {IsItemStatMatch, 7}, ["dps"] = {IsItemStatMatch, 7}, ["resilience"] = {IsItemStatMatch, 7}, ["resil"] = {IsItemStatMatch, 7}, ["res"] = {IsItemStatMatch, 7}, ["defense"] = {IsItemStatMatch, 7}, ["def"] = {IsItemStatMatch, 7}, ["dodge"] = {IsItemStatMatch, 7}, ["dod"] = {IsItemStatMatch, 7}, ["block"] = {IsItemStatMatch, 7}, ["blockvalue"] = {IsItemStatMatch, 7}, ["blockval"] = {IsItemStatMatch, 7}, ["bv"] = {IsItemStatMatch, 7}, ["parry"] = {IsItemStatMatch, 7}, -- Resistances ["armor"] = {IsItemStatMatch, 7}, ["armour"] = {IsItemStatMatch, 7}, ["arm"] = {IsItemStatMatch, 7}, ["resistancephysical"] = {IsItemStatMatch, 7}, ["resistancephys"] = {IsItemStatMatch, 7}, ["resphys"] = {IsItemStatMatch, 7}, ["resistanceholy"] = {IsItemStatMatch, 7}, ["resholy"] = {IsItemStatMatch, 7}, ["resistancefire"] = {IsItemStatMatch, 7}, ["resfire"] = {IsItemStatMatch, 7}, ["resistancenature"] = {IsItemStatMatch, 7}, ["resnature"] = {IsItemStatMatch, 7}, ["resnat"] = {IsItemStatMatch, 7}, ["resistanceforst"] = {IsItemStatMatch, 7}, ["resfrost"] = {IsItemStatMatch, 7}, ["resistanceshadow"] = {IsItemStatMatch, 7}, ["resshadow"] = {IsItemStatMatch, 7}, ["resshad"] = {IsItemStatMatch, 7}, ["resistancearcane"] = {IsItemStatMatch, 7}, ["resarcane"] = {IsItemStatMatch, 7}, ["resarc"] = {IsItemStatMatch, 7}, } local function ItemMatchesTerm(term, itemDetails) if term.relational then local func, arg = unpack(RelationalFunctions[term.left]); if func then return func(term, itemDetails[arg]); end return false; else return nameMatches(itemDetails[1], term.name); end end local function ItemMatchesAllTerms(searchTerms, itemDetails) local function IsItemEquipableMatch(itemEquipLoc) return not AtlasLoot.db.profile.EquipableFilter or ((itemEquipLoc and itemEquipLoc ~= '' and not NON_EQUIPABLE_SLOTS[itemEquipLoc])) end for _, term in ipairs(searchTerms) do if not ItemMatchesTerm(term, itemDetails) then return false end end return true and IsItemEquipableMatch(itemDetails[5]) end local function ParseTerm(termText) for _, relational in ipairs(RELATIONAL_OPERATORS) do local operands = SplitString(termText, relational) if #operands == 2 then return { left = operands[1], right = operands[2], relational = relational } end end return { name = termText } end -- Parse search text into '&'-delimited search terms, -- then parse each term on its relational operator, if present. local function ParseQuery(searchText) local terms = {} for _, term in pairs(SplitString(searchText, OP_AND)) do table.insert(terms, ParseTerm(term)); end return terms end local function GetSpellName(itemId, atlasName) local spellName = GetSpellInfo(string.sub(itemId, 2)); if spellName then return spellName elseif (string.sub(atlasName, 1, 2) == "=d") then return gsub(atlasName, "=ds=", ""); else return gsub(atlasName, "=q%d=", ""); end end local function DoSearch(searchText) AtlasLootCharDB["SearchResult"] = {Name = "Search Result" , Type = "Search", Back = true}; AtlasLootCharDB.LastSearchedText = searchText; local count = 0; local tablenum = 1; local searchTerms = ParseQuery(searchText); local equipableFilterOn = AtlasLoot.db.profile.EquipableFilter; local function GetItemDetails(itemId, atlasName) -- Name, Link, Quality(num), iLvl(num), minLvl(num), itemType(localized string), itemSubType(localized string), stackCount(num), itemEquipLoc(enum), texture(link to a local file), displayId(num) local itemName, _, itemQuality, itemLvl, minLvl, _, itemSubType, _, itemEquipLoc = GetItemInfo(itemId); if not itemName then itemName = gsub(atlasName, "=q%d=", "") end return itemName, itemQuality, itemLvl, minLvl, itemEquipLoc, itemSubType, GetItemStats("item:" .. itemId) end local function AddItemToSearchResult(itemId, itemType, itemName, dataID, itemIdBackup, difCap, dataPage) local lootPage = AtlasLoot_Data[dataID].Name or "Argh!"; if AtlasLootCharDB["SearchResult"][tablenum] == nil then AtlasLootCharDB["SearchResult"][tablenum] = {Name = "Page "..tablenum}; end table.insert(AtlasLootCharDB["SearchResult"][tablenum], {(count % 30) + 1, itemId, itemType, itemName, lootPage, "", "", dataID .. "|" .. "AtlasLoot_Data" .. "|" .. tostring(dataPage), itemIdBackup, [AtlasLoot_Difficulty.MAX_DIF] = difCap}); count = count + 1; if (count) % 30 == 0 then tablenum = tablenum + 1; end end for dataID, data in pairs(AtlasLoot_Data) do for dataPage, t in ipairs(data) do for _, v in ipairs(t) do if type(v) == "table" then local _, itemId, itemType, atlasName = unpack(v) if type(itemId) == "number" and itemId > 0 then local itemIdBackup = itemId; if #searchTerms == 1 and searchTerms[1].name then if nameMatches(atlasName, searchTerms[1].name) then AddItemToSearchResult(itemId, itemType, atlasName, dataID, itemIdBackup, AtlasLoot_Difficulty:getMaxDifficulty(data.Type), dataPage); end else local difficultyCap = min(AtlasLoot_Difficulty:getMaxDifficulty(data.Type), ItemindexID); itemId = AtlasLoot:FindId(itemId, difficultyCap, data.Type) or 2; local item = Item:CreateFromID(itemId); item:ContinueOnLoad(function() local itemDetails = {GetItemDetails(item.itemID, atlasName)}; if ItemMatchesAllTerms(searchTerms, itemDetails) then AddItemToSearchResult(itemId, itemType, atlasName, dataID, itemIdBackup, AtlasLoot_Difficulty:getMaxDifficulty(data.Type), dataPage); end end) end elseif not equipableFilterOn and itemId and itemId ~= "" and string.sub(itemId, 1, 1) == "s" then local spellName = GetSpellName(itemId, atlasName) if nameMatches(spellName, searchText) then spellName = string.sub(atlasName, 1, 4) .. spellName; AddItemToSearchResult(itemId, itemType, spellName, dataID, itemIdBackup, AtlasLoot_Difficulty:getMaxDifficulty(data.Type), dataPage); end end end end end end end function AtlasLoot:ShowSearchResult() AtlasLoot:ShowItemsFrame("SearchResult", "AtlasLootCharDB", 1); end function AtlasLoot:Search(Text) if not Text then return end Text = strtrim(Text); if Text == "" then return end -- Decide if we need load all modules or just specified ones local allDisabled = not self.db.profile.SearchOn.All; if allDisabled then for _, module in ipairs(modules) do if self.db.profile.SearchOn[module] == true then allDisabled = false; break end end end if allDisabled then DEFAULT_CHAT_FRAME:AddMessage(RED .. AL["AtlasLoot"] .. ": " .. WHITE .. AL["You don't have any module selected to search on."]); return; end if self.db.profile.SearchOn.All then AtlasLoot:LoadAllModules(); else for k, v in pairs(self.db.profile.SearchOn) do if k ~= "All" and v == true and not IsAddOnLoaded(k) and LoadAddOn(k) and self.db.profile.LoDNotify then DEFAULT_CHAT_FRAME:AddMessage(GREEN .. AL["AtlasLoot"] .. ": " .. ORANGE .. k .. WHITE .. " " .. AL["sucessfully loaded."]); end end end local success, message = pcall(DoSearch, Text) if not success then message = message:match("[^:]+: (.*)") or message -- strip stack location DEFAULT_CHAT_FRAME:AddMessage(RED .. AL["AtlasLoot"] .. ": " .. WHITE .. message); elseif #AtlasLootCharDB["SearchResult"] == 0 then local itemFilterErrorMessage = ""; if operator then itemFilterErrorMessage = [[ Please check if you have a typo in the filter. For help, type "/atlasloothelp". You might also have to query the server for item informations to load them into your client's Cache.]]; end DEFAULT_CHAT_FRAME:AddMessage(RED .. AL["AtlasLoot"] .. ": " .. WHITE .. AL["No match found for"] .. " \"" .. Text .. "\"." .. itemFilterErrorMessage); else AtlasLoot:ShowItemsFrame("SearchResult", "AtlasLootCharDB", 1); end end function AtlasLoot:ShowSearchOptions(button) local dewdrop = AceLibrary("Dewdrop-2.0"); if dewdrop:IsOpen(button) then dewdrop:Close(1); else local setOptions = function() dewdrop:AddLine("text", AL["Search on"], "isTitle", true, "notCheckable", true); dewdrop:AddLine("text", AL["All modules"], "checked", self.db.profile.SearchOn.All, "tooltipTitle", AL["All modules"], "tooltipText", AL["If checked, AtlasLoot will load and search across all the modules."], "func", function() self.db.profile.SearchOn.All = not self.db.profile.SearchOn.All; end); for _, module in ipairs(modules) do if IsAddOnLoadOnDemand(module) then local title = GetAddOnMetadata(module, "title"); local notes = GetAddOnMetadata(module, "notes"); dewdrop:AddLine("text", title, "checked", self.db.profile.SearchOn.All or self.db.profile.SearchOn[module], "disabled", self.db.profile.SearchOn.All, "tooltipTitle", title, "tooltipText", notes, "func", function() if self.db.profile.SearchOn[module] == nil then self.db.profile.SearchOn[module] = true; else self.db.profile.SearchOn[module] = nil; end end); end end dewdrop:AddLine("text", AL["Search options"], "isTitle", true, "notCheckable", true); dewdrop:AddLine("text", AL["Partial matching"], "checked", self.db.profile.PartialMatching, "tooltipTitle", AL["Partial matching"], "tooltipText", AL["If checked, AtlasLoot search item names for a partial match."], "func", function() self.db.profile.PartialMatching = not self.db.profile.PartialMatching end); dewdrop:AddLine("text", "Only search equipable", -- TODO: put in AL "checked", self.db.profile.EquipableFilter, "tooltipTitle", "Equipable filter", -- TODO: put in AL "tooltipText", "If checked, AtlasLoot only includes items that are euipable.", -- TODO: put in AL "func", function() self.db.profile.EquipableFilter = not self.db.profile.EquipableFilter end); end; dewdrop:Open(button, 'point', function(parent) return "BOTTOMLEFT", "BOTTOMRIGHT"; end, "children", setOptions); end end function AtlasLoot:GetOriginalDataFromSearchResult(itemID) for i, v in ipairs(AtlasLootCharDB["SearchResult"]) do if v[2] == itemID then AtlasLoot_ShowWishListDropDown(v[2], v[3], v[4], v[5], v[8], this, nil); end end end