diff --git a/BagSync_Search.lua b/BagSync_Search.lua
index c761cf4..a5564b4 100644
--- a/BagSync_Search.lua
+++ b/BagSync_Search.lua
@@ -128,17 +128,10 @@ function bgSearch:LoadSlider()
row:SetScript("OnClick", function(self)
if self.link then
if IsShiftKeyDown() then
- local passChk = false
- for i = 1, NUM_CHAT_WINDOWS do
- local editBox = _G[("ChatFrame%dEditBox"):format(i)]
- if editBox:IsVisible() then
- editBox:Insert(self.link)
- passChk = true
- break
- end
- end
- if not passChk then
- _G[("ChatFrame1EditBox"):Insert(self.link)
+ local editBox = ChatEdit_ChooseBoxForSend()
+ if editBox then
+ editBox:Insert(self.link)
+ ChatFrame_OpenChat(editBox:GetText())
end
elseif IsControlKeyDown() then
DressUpItemLink(self.link)
diff --git a/libs/LibItemSearch-1.0.lua b/libs/LibItemSearch-1.0.lua
new file mode 100644
index 0000000..e7f52a6
--- /dev/null
+++ b/libs/LibItemSearch-1.0.lua
@@ -0,0 +1,417 @@
+--[[
+ ItemSearch
+ An item text search engine of some sort
+
+ Grammar:
+ <search> := <intersect search>
+ <intersect search> := <union search> & <union search> ; <union search>
+ <union search> := <negatable search> | <negatable search> ; <negatable search>
+ <negatable search> := !<primitive search> ; <primitive search>
+ <primitive search> := <tooltip search> ; <quality search> ; <type search> ; <text search>
+ <tooltip search> := bop ; boa ; bou ; boe ; quest
+ <quality search> := q<op><text> ; q<op><digit>
+ <ilvl search> := ilvl<op><number>
+ <type search> := t:<text>
+ <text search> := <text>
+ <op> := : | = | == | != | ~= | < | > | <= | >=
+
+ I kindof half want to make a full parser for this
+--]]
+
+local MAJOR, MINOR = "LibItemSearch-1.0", 2
+local ItemSearch = LibStub:NewLibrary(MAJOR, MINOR)
+if not ItemSearch then return end
+
+--[[ general search ]]--
+
+function ItemSearch:Find(itemLink, search)
+ if not search then
+ return true
+ end
+
+ if not itemLink then
+ return false
+ end
+
+ local search = search:lower()
+ if search:match('\124') then
+ return self:FindUnionSearch(itemLink, strsplit('\124', search))
+ end
+ return self:FindUnionSearch(itemLink, search)
+end
+
+
+--[[ union search: <search>&<search> ]]--
+
+function ItemSearch:FindUnionSearch(itemLink, ...)
+ for i = 1, select('#', ...) do
+ local search = select(i, ...)
+ if search and search ~= '' then
+ if search:match('\038') then
+ if self:FindIntersectSearch(itemLink, strsplit('\038', search)) then
+ return true
+ end
+ else
+ if self:FindIntersectSearch(itemLink, search) then
+ return true
+ end
+ end
+ end
+ end
+ return false
+end
+
+
+--[[ intersect search: <search>|<search> ]]--
+
+function ItemSearch:FindIntersectSearch(itemLink, ...)
+ for i = 1, select('#', ...) do
+ local search = select(i, ...)
+ if search and search ~= '' then
+ if not self:FindNegatableSearch(itemLink, search) then
+ return false
+ end
+ end
+ end
+ return true
+end
+
+
+--[[ negated search: !<search> ]]--
+
+function ItemSearch:FindNegatableSearch(itemLink, search)
+ local negatedSearch = search:match('^\033(.+)$')
+ if negatedSearch then
+ return not self:FindTypedSearch(itemLink, negatedSearch)
+ end
+ return self:FindTypedSearch(itemLink, search)
+end
+
+
+--[[
+ typed search:
+ user defined search types
+
+ A typed search object should look like the following:
+ {
+ string id
+ unique identifier for the search type,
+
+ string searchCapture = function isSearch(self, search)
+ returns a capture if the given search matches this typed search
+ returns nil if the search is not a match for this type
+
+ bool isMatch = function findItem(self, itemLink, searchCapture)
+ returns true if <itemLink> is in the search defined by <searchCapture>
+ }
+--]]
+
+local typedSearches = {}
+function ItemSearch:RegisterTypedSearch(typedSearchObj)
+ typedSearches[typedSearchObj.id] = typedSearchObj
+end
+
+function ItemSearch:GetTypedSearches()
+ return pairs(typedSearches)
+end
+
+function ItemSearch:GetTypedSearch(id)
+ return typedSearches[id]
+end
+
+function ItemSearch:FindTypedSearch(itemLink, search)
+ if not search then
+ return false
+ end
+
+ for id, searchInfo in self:GetTypedSearches() do
+ local capture1, capture2, capture3 = searchInfo:isSearch(search)
+ if capture1 then
+ return searchInfo:findItem(itemLink, capture1, capture2, capture3)
+ end
+ end
+
+ return self:GetTypedSearch('itemTypeGeneric'):findItem(itemLink, search) or self:GetTypedSearch('itemName'):findItem(itemLink, search)
+end
+
+
+--[[
+ Basic typed searches
+--]]
+
+function ItemSearch:Compare(op, lhs, rhs)
+ --ugly, but it works
+ if op == ':' or op == '=' or op == '==' then
+ return lhs == rhs
+ end
+ if op == '!=' or op == '~=' then
+ return lhs ~= rhs
+ end
+ if op == '<=' then
+ return lhs <= rhs
+ end
+ if op == '<' then
+ return lhs < rhs
+ end
+ if op == '>' then
+ return lhs > rhs
+ end
+ if op == '>=' then
+ return lhs >= rhs
+ end
+ return false
+end
+
+
+--[[ basic text search n:(.+) ]]--
+
+local function search_IsInText(search, ...)
+ for i = 1, select('#', ...) do
+ local text = select(i, ...)
+ text = text and tostring(text):lower()
+ if text and (text == search or text:match(search)) then
+ return true
+ end
+ end
+ return false
+end
+
+ItemSearch:RegisterTypedSearch{
+ id = 'itemName',
+
+ isSearch = function(self, search)
+ return search and search:match('^n:(.+)$')
+ end,
+
+ findItem = function(self, itemLink, search)
+ local itemName = (GetItemInfo(itemLink))
+ return search_IsInText(search, itemName)
+ end
+}
+
+
+--[[ item type,subtype,equip loc search t:(.+) ]]--
+
+ItemSearch:RegisterTypedSearch{
+ id = 'itemTypeGeneric',
+
+ isSearch = function(self, search)
+ return search and search:match('^t:(.+)$')
+ end,
+
+ findItem = function(self, itemLink, search)
+ local name, link, quality, iLevel, reqLevel, type, subType, maxStack, equipSlot = GetItemInfo(itemLink)
+ if not name then
+ return false
+ end
+ return search_IsInText(search, type, subType, _G[equipSlot])
+ end
+}
+
+
+--[[ item quality search: q(sign)(%d+) | q:(qualityName) ]]--
+
+ItemSearch:RegisterTypedSearch{
+ id = 'itemQuality',
+
+ isSearch = function(self, search)
+ if search then
+ return search:match('^q([%~%:%<%>%=%!]+)(%w+)$')
+ end
+ end,
+
+ descToQuality = function(self, desc)
+ local q = 0
+
+ local quality = _G['ITEM_QUALITY' .. q .. '_DESC']
+ while quality and quality:lower() ~= desc do
+ q = q + 1
+ quality = _G['ITEM_QUALITY' .. q .. '_DESC']
+ end
+
+ if quality then
+ return q
+ end
+ end,
+
+ findItem = function(self, itemLink, op, search)
+ local name, link, quality = GetItemInfo(itemLink)
+ if not name then
+ return false
+ end
+
+ local num = tonumber(search) or self:descToQuality(search)
+ return num and ItemSearch:Compare(op, quality, num) or false
+ end,
+}
+
+--[[ item level search: lvl(sign)(%d+) ]]--
+
+ItemSearch:RegisterTypedSearch{
+ id = 'itemLevel',
+
+ isSearch = function(self, search)
+ if search then
+ return search:match('^ilvl([:<>=!]+)(%d+)$')
+ end
+ end,
+
+ findItem = function(self, itemLink, op, search)
+ local name, link, quality, iLvl = GetItemInfo(itemLink)
+ if not iLvl then
+ return false
+ end
+
+ local num = tonumber(search)
+ return num and ItemSearch:Compare(op, iLvl, num) or false
+ end,
+}
+
+
+--[[ tooltip keyword search ]]--
+
+local tooltipCache = setmetatable({}, {__index = function(t, k) local v = {} t[k] = v return v end})
+local tooltipScanner = _G['LibItemSearchTooltipScanner'] or CreateFrame('GameTooltip', 'LibItemSearchTooltipScanner', UIParent, 'GameTooltipTemplate')
+
+local function link_FindSearchInTooltip(itemLink, search)
+ --look in the cache for the result
+ local itemID = itemLink:match('item:(%d+)')
+ local cachedResult = tooltipCache[search][itemID]
+ if cachedResult ~= nil then
+ return cachedResult
+ end
+
+ --no match?, pull in the resut from tooltip parsing
+ tooltipScanner:SetOwner(UIParent, 'ANCHOR_NONE')
+ tooltipScanner:SetHyperlink(itemLink)
+
+ local result = false
+ if tooltipScanner:NumLines() > 1 and _G[tooltipScanner:GetName() .. 'TextLeft2']:GetText() == search then
+ result = true
+ elseif tooltipScanner:NumLines() > 2 and _G[tooltipScanner:GetName() .. 'TextLeft3']:GetText() == search then
+ result = true
+ end
+ tooltipScanner:Hide()
+
+ tooltipCache[search][itemID] = result
+ return result
+end
+
+ItemSearch:RegisterTypedSearch{
+ id = 'tooltip',
+
+ isSearch = function(self, search)
+ return self.keywords[search]
+ end,
+
+ findItem = function(self, itemLink, search)
+ return search and link_FindSearchInTooltip(itemLink, search)
+ end,
+
+ keywords = {
+ ['boe'] = ITEM_BIND_ON_EQUIP,
+ ['bop'] = ITEM_BIND_ON_PICKUP,
+ ['bou'] = ITEM_BIND_ON_USE,
+ ['quest'] = ITEM_BIND_QUEST,
+ ['boa'] = ITEM_BIND_TO_ACCOUNT
+ }
+}
+
+
+--[[ equipment set search ]]--
+
+local function IsWardrobeLoaded()
+ local name, title, notes, enabled, loadable, reason, security = GetAddOnInfo('Wardrobe')
+ return enabled
+end
+
+local function findEquipmentSetByName(search)
+ local startsWithSearch = '^' .. search
+ local partialMatch = nil
+
+ for i = 1, GetNumEquipmentSets() do
+ local setName = (GetEquipmentSetInfo(i))
+ local lSetName = setName:lower()
+
+ if lSetName == search then
+ return setName
+ end
+
+ if lSetName:match(startsWithSearch) then
+ partialMatch = setName
+ end
+ end
+
+ -- Wardrobe Support
+ if Wardrobe then
+ for i, outfit in ipairs( Wardrobe.CurrentConfig.Outfit) do
+ local setName = outfit.OutfitName
+ local lSetName = setName:lower()
+
+ if lSetName == search then
+ return setName
+ end
+
+ if lSetName:match(startsWithSearch) then
+ partialMatch = setName
+ end
+ end
+ end
+
+ return partialMatch
+end
+
+local function isItemInEquipmentSet(itemLink, setName)
+ if not setName then
+ return false
+ end
+
+ local itemIDs = GetEquipmentSetItemIDs(setName)
+ if not itemIDs then
+ return false
+ end
+
+ local itemID = tonumber(itemLink:match('item:(%d+)'))
+ for inventoryID, setItemID in pairs(itemIDs) do
+ if itemID == setItemID then
+ return true
+ end
+ end
+
+ return false
+end
+
+local function isItemInWardrobeSet(itemLink, setName)
+ if not Wardrobe then return false end
+
+ local itemName = (GetItemInfo(itemLink))
+ for i, outfit in ipairs(Wardrobe.CurrentConfig.Outfit) do
+ if outfit.OutfitName == setName then
+ for j, item in pairs(outfit.Item) do
+ if item and (item.IsSlotUsed == 1) and (item.Name == itemName) then
+ return true
+ end
+ end
+ end
+ end
+
+ return false
+end
+
+ItemSearch:RegisterTypedSearch{
+ id = 'equipmentSet',
+
+ isSearch = function(self, search)
+ return search and search:match('^s:(.+)$')
+ end,
+
+ findItem = function(self, itemLink, search)
+ local setName = findEquipmentSetByName(search)
+ if not setName then
+ return false
+ end
+
+ return isItemInEquipmentSet(itemLink, setName)
+ or isItemInWardrobeSet(itemLink, setName)
+ end,
+}
\ No newline at end of file
diff --git a/libs/LibStub.lua b/libs/LibStub.lua
new file mode 100644
index 0000000..0a41ac0
--- /dev/null
+++ b/libs/LibStub.lua
@@ -0,0 +1,30 @@
+-- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info
+-- LibStub is hereby placed in the Public Domain Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
+local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
+local LibStub = _G[LIBSTUB_MAJOR]
+
+if not LibStub or LibStub.minor < LIBSTUB_MINOR then
+ LibStub = LibStub or {libs = {}, minors = {} }
+ _G[LIBSTUB_MAJOR] = LibStub
+ LibStub.minor = LIBSTUB_MINOR
+
+ function LibStub:NewLibrary(major, minor)
+ assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
+ minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
+
+ local oldminor = self.minors[major]
+ if oldminor and oldminor >= minor then return nil end
+ self.minors[major], self.libs[major] = minor, self.libs[major] or {}
+ return self.libs[major], oldminor
+ end
+
+ function LibStub:GetLibrary(major, silent)
+ if not self.libs[major] and not silent then
+ error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
+ end
+ return self.libs[major], self.minors[major]
+ end
+
+ function LibStub:IterateLibraries() return pairs(self.libs) end
+ setmetatable(LibStub, { __call = LibStub.GetLibrary })
+end
diff --git a/libs/tekKonfigDropdown.lua b/libs/tekKonfigDropdown.lua
new file mode 100644
index 0000000..42a9b16
--- /dev/null
+++ b/libs/tekKonfigDropdown.lua
@@ -0,0 +1,85 @@
+local lib, oldminor = LibStub:NewLibrary("tekKonfig-Dropdown", 3)
+if not lib then return end
+oldminor = oldminor or 0
+
+
+local GameTooltip = GameTooltip
+local function HideTooltip() GameTooltip:Hide() end
+local function ShowTooltip(self)
+ if self.frame.tiptext then
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT")
+ GameTooltip:SetText(self.frame.tiptext, nil, nil, nil, nil, true)
+ end
+end
+local function ShowTooltip2(self) ShowTooltip(self.container) end
+
+
+local function OnClick(self)
+ ToggleDropDownMenu(nil, nil, self:GetParent())
+ PlaySound("igMainMenuOptionCheckBoxOn")
+end
+
+local function OnHide() CloseDropDownMenus() end
+
+
+-- Create a dropdown.
+-- All args optional, parent recommended
+function lib.new(parent, label, ...)
+ local container = CreateFrame("Button", nil, parent)
+ container:SetWidth(149+13) container:SetHeight(32+24)
+ container:SetScript("OnEnter", ShowTooltip)
+ container:SetScript("OnLeave", HideTooltip)
+ if select("#", ...) > 0 then container:SetPoint(...) end
+
+ local name = "tekKonfigDropdown"..GetTime() -- Sadly, some of these frames must be named
+ local f = CreateFrame("Frame", name, parent)
+ f:SetWidth(149) f:SetHeight(32)
+ f:SetPoint("TOPLEFT", container, -13, -24)
+ f:EnableMouse(true)
+ f:SetScript("OnHide", OnHide)
+ container.frame = f
+
+ local ltex = f:CreateTexture(name.."Left", "ARTWORK")
+ ltex:SetWidth(25) ltex:SetHeight(64)
+ ltex:SetPoint("TOPLEFT", 0, 17)
+ ltex:SetTexture("Interface\\Glues\\CharacterCreate\\CharacterCreate-LabelFrame")
+ ltex:SetTexCoord(0, 0.1953125, 0, 1)
+
+ local rtex = f:CreateTexture(nil, "ARTWORK")
+ rtex:SetWidth(25) rtex:SetHeight(64)
+ rtex:SetPoint("RIGHT")
+ rtex:SetTexture("Interface\\Glues\\CharacterCreate\\CharacterCreate-LabelFrame")
+ rtex:SetTexCoord(0.8046875, 1, 0, 1)
+
+ local mtex = f:CreateTexture(nil, "ARTWORK")
+ mtex:SetWidth(115) mtex:SetHeight(64)
+ mtex:SetPoint("LEFT", ltex, "RIGHT")
+ mtex:SetPoint("RIGHT", rtex, "LEFT")
+ mtex:SetTexture("Interface\\Glues\\CharacterCreate\\CharacterCreate-LabelFrame")
+ mtex:SetTexCoord(0.1953125, 0.8046875, 0, 1)
+
+ local text = f:CreateFontString(name.."Text", "ARTWORK", "GameFontHighlightSmall")
+ text:SetWidth(0) text:SetHeight(10)
+ text:SetPoint("RIGHT", rtex, -43, 2)
+ text:SetJustifyH("RIGHT")
+
+ local button = CreateFrame("Button", nil, f)
+ button:SetWidth(24) button:SetHeight(24)
+ button:SetPoint("TOPRIGHT", rtex, -16, -18)
+ button:SetScript("OnClick", OnClick)
+ button:SetScript("OnEnter", ShowTooltip2)
+ button.container = container
+
+ button:SetNormalTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Up")
+ button:SetPushedTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Down")
+ button:SetHighlightTexture("Interface\\Buttons\\UI-Common-MouseHilight")
+ button:SetDisabledTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Disabled")
+ button:GetHighlightTexture():SetBlendMode("ADD")
+
+ local labeltext = f:CreateFontString(nil, "BACKGROUND", "GameFontNormal")--GameFontHighlight
+ labeltext:SetPoint("BOTTOMLEFT", container, "TOPLEFT", 16-13, 3-24)
+ labeltext:SetText(label)
+
+ return f, text, container, labeltext
+end
+
diff --git a/libs/tekKonfigScroll.lua b/libs/tekKonfigScroll.lua
new file mode 100644
index 0000000..ff69b13
--- /dev/null
+++ b/libs/tekKonfigScroll.lua
@@ -0,0 +1,80 @@
+
+local lib, oldminor = LibStub:NewLibrary("tekKonfig-Scroll", 2)
+if not lib then return end
+
+lib.bg = {
+ edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
+ tile = true,
+ tileSize = 16,
+ edgeSize = 12,
+ insets = { left = 0, right = 0, top = 5, bottom = 5 }
+}
+
+-- Creates a scrollbar
+-- Parent is required, offset and step are optional
+function lib.new(parent, offset, step)
+ local f = CreateFrame("Slider", nil, parent)
+ f:SetWidth(16)
+
+ f:SetPoint("TOPRIGHT", 0 - (offset or 0), -16 - (offset or 0))
+ f:SetPoint("BOTTOMRIGHT", 0 - (offset or 0), 16 + (offset or 0))
+
+ local up = CreateFrame("Button", nil, f)
+ up:SetPoint("BOTTOM", f, "TOP")
+ up:SetWidth(16) up:SetHeight(16)
+ up:SetNormalTexture("Interface\\Buttons\\UI-ScrollBar-ScrollUpButton-Up")
+ up:SetPushedTexture("Interface\\Buttons\\UI-ScrollBar-ScrollUpButton-Down")
+ up:SetDisabledTexture("Interface\\Buttons\\UI-ScrollBar-ScrollUpButton-Disabled")
+ up:SetHighlightTexture("Interface\\Buttons\\UI-ScrollBar-ScrollUpButton-Highlight")
+
+ up:GetNormalTexture():SetTexCoord(1/4, 3/4, 1/4, 3/4)
+ up:GetPushedTexture():SetTexCoord(1/4, 3/4, 1/4, 3/4)
+ up:GetDisabledTexture():SetTexCoord(1/4, 3/4, 1/4, 3/4)
+ up:GetHighlightTexture():SetTexCoord(1/4, 3/4, 1/4, 3/4)
+ up:GetHighlightTexture():SetBlendMode("ADD")
+
+ up:SetScript("OnClick", function(self)
+ local parent = self:GetParent()
+ parent:SetValue(parent:GetValue() - (step or parent:GetHeight()/2))
+ PlaySound("UChatScrollButton")
+ end)
+
+ local down = CreateFrame("Button", nil, f)
+ down:SetPoint("TOP", f, "BOTTOM")
+ down:SetWidth(16) down:SetHeight(16)
+ down:SetNormalTexture("Interface\\Buttons\\UI-ScrollBar-ScrollDownButton-Up")
+ down:SetPushedTexture("Interface\\Buttons\\UI-ScrollBar-ScrollDownButton-Down")
+ down:SetDisabledTexture("Interface\\Buttons\\UI-ScrollBar-ScrollDownButton-Disabled")
+ down:SetHighlightTexture("Interface\\Buttons\\UI-ScrollBar-ScrollDownButton-Highlight")
+
+ down:GetNormalTexture():SetTexCoord(1/4, 3/4, 1/4, 3/4)
+ down:GetPushedTexture():SetTexCoord(1/4, 3/4, 1/4, 3/4)
+ down:GetDisabledTexture():SetTexCoord(1/4, 3/4, 1/4, 3/4)
+ down:GetHighlightTexture():SetTexCoord(1/4, 3/4, 1/4, 3/4)
+ down:GetHighlightTexture():SetBlendMode("ADD")
+
+ down:SetScript("OnClick", function(self)
+ local parent = self:GetParent()
+ parent:SetValue(parent:GetValue() + (step or parent:GetHeight()/2))
+ PlaySound("UChatScrollButton")
+ end)
+
+ f:SetThumbTexture("Interface\\Buttons\\UI-ScrollBar-Knob")
+ local thumb = f:GetThumbTexture()
+ thumb:SetWidth(16) thumb:SetHeight(24)
+ thumb:SetTexCoord(1/4, 3/4, 1/8, 7/8)
+
+ f:SetScript("OnValueChanged", function(self, value)
+ local min, max = self:GetMinMaxValues()
+ if value == min then up:Disable() else up:Enable() end
+ if value == max then down:Disable() else down:Enable() end
+ end)
+
+ local border = CreateFrame("Frame", nil, f)
+ border:SetPoint("TOPLEFT", up, -5, 5)
+ border:SetPoint("BOTTOMRIGHT", down, 5, -3)
+ border:SetBackdrop(lib.bg)
+ border:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b, 0.5)
+
+ return f, up, down, border
+end