├── .github ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .pkgmeta ├── .travis.yml ├── .travis ├── deploy.enc └── wiki.py ├── LICENSE.txt ├── README.md ├── categories ├── Artifact.lua ├── Collections.lua ├── Consumables.lua ├── Equipment.lua ├── EquipmentSets.lua ├── Events.lua ├── Invalid.lua ├── Inventory.lua ├── Junk.lua ├── New.lua ├── Professions.lua ├── Quests.lua ├── ReagentBank.lua ├── Teleport.lua └── TradeGoods.lua ├── core ├── Blizzard.lua ├── Constants.lua ├── Database.lua ├── Init.lua ├── Localization.lua └── Private.lua ├── embed.xml ├── locale ├── deDE.lua ├── esES.lua ├── esMX.lua ├── frFR.lua ├── itIT.lua ├── koKR.lua ├── ptBR.lua ├── ruRU.lua ├── zhCN.lua └── zhTW.lua ├── mixins ├── Bag.lua ├── Callback.lua ├── Category.lua ├── Container.lua ├── Event.lua ├── Item.lua ├── Parent.lua ├── Slot.lua └── Widget.lua └── widgets ├── AutoDeposit.lua ├── AutoVendor.lua ├── BagSlot.lua ├── Bags.lua ├── Currencies.lua ├── Deposit.lua ├── FreeSlots.lua ├── MarkKnown.lua ├── Money.lua ├── Restack.lua └── Search.lua /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | If you're opening a feature request, please search through the existing issues first. 2 | If you're submitting an issue, please fill in the following: 3 | 4 | - What version are you using? 5 | - Can the issue be reproduced, and if so, how? 6 | - If there was an error message, please include it. 7 | - If there is a graphical issue, please include a screenshot (you can drag-n-drop here). 8 | 9 | Make sure you check back often until the issue is resolved for any follow-up questions. 10 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Fixes #. 2 | 3 | Changes proposed in this pull request: 4 | - 5 | -------------------------------------------------------------------------------- /.pkgmeta: -------------------------------------------------------------------------------- 1 | package-as: LibContainer 2 | 3 | manual-changelog: 4 | filename: CHANGELOG.md 5 | markup-type: markdown 6 | 7 | ignore: 8 | - utils 9 | - README.md 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | python: 4 | - "3.6" 5 | 6 | branches: 7 | only: 8 | - master 9 | 10 | before_script: 11 | - openssl aes-256-cbc -K $encrypted_5980be8a6828_key -iv $encrypted_5980be8a6828_iv -in .travis/deploy.enc -out "$HOME/.ssh/deploy" -d 12 | - chmod 600 "$HOME/.ssh/deploy" 13 | - echo -e "Host github.com\n\tIdentityFile $HOME/.ssh/deploy\n" >> $HOME/.ssh/config 14 | - git config --global user.email "$GIT_EMAIL" 15 | - git config --global user.name "$GIT_NAME" 16 | 17 | script: 18 | - git clone "git@github.com:$TRAVIS_REPO_SLUG.wiki" .wiki 19 | - python3 .travis/wiki.py 20 | - cd .wiki 21 | - git add . 22 | - git commit -m "$TRAVIS_COMMIT" 23 | - git push origin master 24 | 25 | env: 26 | global: 27 | - secure: jEDTbxNs+HU1A1hf4O5AIvt4KFAMxwRUPAG9TJx2H06VEaRTeMvwCfGNRpfOcMX8FCp4qeU2mc9IDNnDKEpxjXOzhZGP6Bpm6jumNr/ruUngNtFVWHNVU5SgomuqiQISxH6Yr6ZAS7HcXCbWdkFT3NV8IqMwhyiqLRVnMeyjmPQTOfK2v/nIoeMUH46uGfXr6OspPe60glx/+c22namZW39lF+0ir/Yvb/WPqtX3Ihjo/I17+UhypRoIjyxdw+GZPfYOepuJPQKv5y5QtIspaEn4goPRIm0E3kzT1JTwdQKaGV6Ru3iu8QJogIT3gW6oixv5hEZrZamAdBeGZ/AxhGVG4ot2AnErw2JmEiECgj9dbU1O1xd7yd+dJv1zu8m9gIQ6UQN/JuhHyoABu50SSp1cW4U9jE1hEUW7lUVe38tkEJoP6hffGHtC5thmfhLPCf8NZctLdWFhDyvHLn5rPaokzHqHqw2750lCpM9PGliksFGCr2WCPfHK/Ben+AMkbOnoTT3nzcwse58eA7UlWq2T58BzDf7S3uCBnFIWKW4LujoSXtFynAOm9APyb3ZyCcdv8eAVxCBo2oXjqxScHCf/qpWUsNxU6Uxm6Vq4u9aIIxY6Ea6iU5k7TtVZHG4QRI9FxaVFIC9xjxOgiY1DOc4zF51GGCCQWLmwhEi+gY0= 28 | - secure: Ty+w0gJi2V4uzq6phEZgldxsq/gxKdSoYl6Z2xKiiGjYQHRM4yu0k7oKcH45qm5PHK8Vz3pgSGr3RXqfBs0euzgjeP6NgXU3fflxxz61kmuBIwb77omR/6OXzozKBNXo6KSnvkcfbWn9ehHtiYDyvBJ07OaVuPtU6zw70dJSom8P9+xhewIa9e5xqGVBIL9ReSsryLs3j+WwFJOmFKbvwn83ObJ3a5W05lXncdBQion9Tm6uOMeoLOzVWbuxQVIm4fNKdNho386OG5TcRo6IIpe1jnoz87v4lVz1Fm8tikgO7xQXFwJm94/+qvkzdvfGQNxNL9J6WYjwVzez+pnbNU4w4NefxlxvL6PVLI98WE4IQUx0edDSACKee5fC5GIxiv35kyCOUSj4k9/hekAd9bzMrwpi3tzrPBG/mD2c5TwGDGaii5mZi4n6pdkLAJeUNJlnkO+73fFTmr/2wBzkqxEqKAMNypqoW80SLqN5P8+GfGql7RD71x7QxCRaDItsycqSsJwiTLRCCDp224Jt4KTM10/lbPDwQx9N1GvACHdKQWlYHxEgQ5KRrCVBUmMweWC9YIOAJHL/s8DK9eWBZkgupxBCqMHk2bsP5QPnJbR8YNuAyxa+lUfKg9aQWG+AgoikcSRyHbO312tyD2n7C60lau1Zit4JqX1FSXmUB7c= 29 | 30 | notifications: 31 | email: false 32 | -------------------------------------------------------------------------------- /.travis/deploy.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/p3lim-wow/LibContainer/b4fed010368dd215c43eb14dd052a5abd32acc2f/.travis/deploy.enc -------------------------------------------------------------------------------- /.travis/wiki.py: -------------------------------------------------------------------------------- 1 | import os, re, glob 2 | 3 | # compile regex patterns beforehand 4 | START = re.compile(r'^\t*--\[\[ ?((\w+):(.+))$') 5 | STOP = re.compile(r'^\t*--\]\]$') 6 | 7 | # create a dictionary to store our pages 8 | pages = {} 9 | 10 | print('Parsing documentation in \'{}\''.format(os.getcwd())) 11 | for file in glob.glob('**/*.lua', recursive=True): 12 | # iterates recursively for every Lua file, then open file for reading 13 | with open(file) as f: 14 | isReading = False 15 | textBlock = '' 16 | isHeader = False 17 | pageName = None 18 | numBlocks = 0 19 | 20 | # traverse file line-by-line for content 21 | for line in f: 22 | if not isReading: 23 | # we're not currently reading a text block, search for the start of one 24 | header = START.match(line) 25 | if header: 26 | # found a text block 27 | # the expected format is: 28 | # "--[[ PageName:foo..." 29 | if header.group(3).lower() == 'header': 30 | # our "foo" was "header", which signifies this should be text on top of 31 | # the page, but there's already a dedicated heading for the page 32 | isHeader = True 33 | else: 34 | # everything else gets h3 35 | textBlock = '### {}\n\n'.format(header.group(1)) 36 | 37 | # store the page name and toggle reading mode 38 | pageName = header.group(2) 39 | isReading = True 40 | else: 41 | # we're reading, check if the line signifies the end of a block 42 | if STOP.match(line): 43 | # line signified the end of a block, we'll need to store it 44 | # the expected format is: 45 | # "--]]" 46 | if not pageName in pages: 47 | # page does not have a list to store blocks in - create it 48 | pages[pageName] = [] 49 | 50 | if isHeader: 51 | # the block was a header, we need to put it at the top of the list of blocks 52 | pages[pageName].insert(0, textBlock) 53 | else: 54 | # normal block, just append it 55 | pages[pageName].append(textBlock) 56 | 57 | # reset back to normal 58 | isReading = False 59 | isHeader = False 60 | textBlock = '' 61 | pageName = None 62 | numBlocks += 1 63 | continue 64 | else: 65 | # we're currently in the middle of a block, just store the line 66 | # we also need to strip leading tabs, forcing indented text blocks to use 67 | # spaces within as whitespace if needed 68 | textBlock += line.lstrip('\t') 69 | 70 | if numBlocks > 0: 71 | # at the end of a file, if we found some blocks, log it 72 | print('- Found {} blocks in \'{}\''.format(numBlocks, file)) 73 | 74 | 75 | # done parsing docs, let's write it out 76 | print('\nWriting to files') 77 | 78 | for name, blocks in pages.items(): 79 | # iterates over 'pages' dict 80 | # figure out the path we want to save to, and log it 81 | path = '.wiki/{}.md'.format(name) 82 | print('- {}'.format(path)) 83 | 84 | with open(path, 'w') as f: 85 | # open the output file for writing, join the blocks for the page, then write 86 | f.write('\n***\n\n'.join(blocks)) 87 | 88 | print('\nDone!') 89 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 Adrian L Lange 2 | 3 | All rights reserved. 4 | 5 | Permission is granted for anyone to use, read, or otherwise interpret 6 | this software for any purpose, without any restrictions. 7 | 8 | Permission is granted for anyone to modify this software or sample from 9 | it, and to distribute such modified versions or derivative works as long 10 | as neither the names of this software nor its author(s) are used in the 11 | name or title of the work or in any other way that may cause it to be 12 | confused with this software. 13 | 14 | Permission is granted for anyone to aggregate this software with other 15 | works not derived from this software for the purpose of creating a user 16 | interface compilation for "World of Warcraft" and to distribute such 17 | compilations as long as the software is not modified in any way, 18 | including by modifying or removing any files. 19 | 20 | This software may not be distributed standalone or in any other way, in 21 | whole or in part, modified or unmodified, without specific prior written 22 | permission from the author(s) of this software. 23 | 24 | The names of this software and/or its author(s) may not be used to 25 | promote or endorse works derived from this software without specific 26 | prior written permission from the author(s) of this software. 27 | 28 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 29 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 30 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 31 | IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 32 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 33 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 34 | OTHER DEALINGS IN THE SOFTWARE. 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LibContainer 2 | 3 | This is an AddOn framework for the popular MMORPG "World of Warcraft". 4 | It is not designed to be run as an AddOn by itself, it _must be embedded_. 5 | 6 | ## Description 7 | 8 | LibContainer is a category-based container framework for creating bag and bank AddOns. 9 | It takes away all the logic needed to update and create bags and slots, leaving the developer 10 | with the task of creating a layout with the design of their desires. 11 | 12 | The framework is very extensible and is easily manipulated, has widgets for additional 13 | capabilities you'd expect to find in a container AddOn. 14 | 15 | For more information on how to get started, see the [wiki](//github.com/p3lim-wow/LibContainer/wiki). 16 | 17 | ## Feedback 18 | 19 | If you would like to report a bug or contribute to the project, please follow [this link](//github.com/p3lim-wow/LibContainer/issues?q=) to get started. 20 | 21 | ## Legal 22 | 23 | Please see the [LICENSE](//github.com/p3lim-wow/LibContainer/blob/master/LICENSE.txt) file. 24 | -------------------------------------------------------------------------------- /categories/Artifact.lua: -------------------------------------------------------------------------------- 1 | local L = LibContainer.locale 2 | 3 | local name = 'ArtifactPower' 4 | local localizedName = L['Artifact Power'] 5 | local index = 100 6 | 7 | local filter = function(Slot) 8 | local custom = LibContainer.db.KnownItems[Slot:GetItemID()] 9 | if(custom and type(custom) == 'number') then 10 | return custom == index 11 | else 12 | return IsArtifactPowerItem(Slot:GetItemID()) 13 | end 14 | end 15 | 16 | LibContainer:AddCategory(index, name, localizedName, filter) 17 | -------------------------------------------------------------------------------- /categories/Collections.lua: -------------------------------------------------------------------------------- 1 | local L = LibContainer.locale 2 | 3 | local name = 'Collections' 4 | local localizedName = L['Collections'] 5 | local index = 80 6 | 7 | local scanTip = CreateFrame('GameTooltip', 'LibContainerScanTip' .. math.floor(GetTime()), nil, 'GameTooltipTemplate') 8 | scanTip:SetOwner(WorldFrame, 'ANCHOR_NONE') 9 | local scanTipName = scanTip:GetName() 10 | 11 | local filter = function(Slot) 12 | local custom = LibContainer.db.KnownItems[Slot:GetItemID()] 13 | if(custom and type(custom) == 'number') then 14 | return custom == index 15 | else 16 | local itemClass = Slot:GetItemClass() 17 | if(itemClass == LE_ITEM_CLASS_BATTLEPET) then 18 | -- caged battlepets 19 | return true 20 | elseif(itemClass == LE_ITEM_CLASS_MISCELLANEOUS) then 21 | local itemSubClass = Slot:GetItemSubClass() 22 | if(itemSubClass == 2 or itemSubClass == 5) then 23 | -- uncaged battlepets and mounts 24 | return true 25 | elseif(itemSubClass == 4) then 26 | -- toys 27 | -- return not not (C_ToyBox.GetToyInfo(Slot:GetItemID())) -- returns data for non-toys, confirmed will be fixed soon™ 28 | scanTip:SetBagItem(Slot:GetBagAndSlot()) 29 | scanTip:Show() 30 | 31 | for index = 1, scanTip:NumLines() do 32 | local line = _G[scanTipName .. 'TextLeft' .. index] 33 | if(line and line:GetText() == TOY) then -- "Toy" 34 | return true 35 | end 36 | end 37 | end 38 | end 39 | end 40 | end 41 | 42 | LibContainer:AddCategory(index, name, localizedName, filter) 43 | -------------------------------------------------------------------------------- /categories/Consumables.lua: -------------------------------------------------------------------------------- 1 | local L = LibContainer.locale 2 | 3 | local name = 'Consumables' 4 | local localizedName = L['Consumables'] 5 | local index = 41 6 | 7 | local filter = function(Slot) 8 | local custom = LibContainer.db.KnownItems[Slot:GetItemID()] 9 | if(custom and type(custom) == 'number') then 10 | return custom == index 11 | else 12 | local itemClass = Slot:GetItemClass() 13 | local itemSubClass = Slot:GetItemSubClass() 14 | if(itemClass == LE_ITEM_CLASS_CONSUMABLE and itemSubClass >= 1) then 15 | -- consumables other than engineering explosives and devices, they're considered profession related 16 | if(itemSubClass ~= 8) then 17 | -- but not consumables in the "other" subclass 18 | return true 19 | end 20 | elseif(itemClass == LE_ITEM_CLASS_ITEM_ENHANCEMENT) then 21 | -- enchants, armor kits etc 22 | return true 23 | end 24 | end 25 | end 26 | 27 | LibContainer:AddCategory(index, name, localizedName, filter) 28 | -------------------------------------------------------------------------------- /categories/Equipment.lua: -------------------------------------------------------------------------------- 1 | local L = LibContainer.locale 2 | 3 | local name = 'Equipment' 4 | local localizedName = L['Equipment'] 5 | local index = 30 6 | 7 | local filter = function(Slot) 8 | local custom = LibContainer.db.KnownItems[Slot:GetItemID()] 9 | if(custom and type(custom) == 'number') then 10 | return custom == index 11 | else 12 | if(Slot:GetItemQuality() >= LE_ITEM_QUALITY_UNCOMMON) then 13 | local itemClass = Slot:GetItemClass() 14 | if(itemClass == LE_ITEM_CLASS_WEAPON or itemClass == LE_ITEM_CLASS_ARMOR) then 15 | return true 16 | elseif(itemClass == LE_ITEM_CLASS_GEM and Slot:GetItemSubClass() == 11) then 17 | return true 18 | end 19 | end 20 | end 21 | end 22 | 23 | LibContainer:AddCategory(index, name, localizedName, filter) 24 | -------------------------------------------------------------------------------- /categories/EquipmentSets.lua: -------------------------------------------------------------------------------- 1 | local L = LibContainer.locale 2 | 3 | local name = 'EquipmentSets' 4 | local localizedName = L['Equipment Sets'] 5 | local index = 31 6 | 7 | local filter = function(Slot) 8 | local custom = LibContainer.db.KnownItems[Slot:GetItemID()] 9 | if(custom and type(custom) == 'number') then 10 | return custom == index 11 | else 12 | return not not GetContainerItemEquipmentSetInfo(Slot:GetBagAndSlot()) 13 | end 14 | end 15 | 16 | LibContainer:AddCategory(index, name, localizedName, filter) 17 | -------------------------------------------------------------------------------- /categories/Events.lua: -------------------------------------------------------------------------------- 1 | local L = LibContainer.locale 2 | 3 | local name = 'Events' 4 | local localizedName = L['World Events'] 5 | local index = 70 6 | 7 | local filter = function(Slot) 8 | local custom = LibContainer.db.KnownItems[Slot:GetItemID()] 9 | if(custom and type(custom) == 'number') then 10 | return custom == index 11 | else 12 | local itemClass = Slot:GetItemClass() 13 | if(itemClass == LE_ITEM_CLASS_QUESTITEM) then 14 | -- quest items that is not part of, or starts, a quest can be considered holiday related 15 | return not Slot:GetItemQuestID() and not Slot:IsItemQuestItem() 16 | elseif(itemClass == LE_ITEM_CLASS_MISCELLANEOUS and Slot:GetItemSubClass() == 3) then 17 | -- holiday crap 18 | return true 19 | end 20 | end 21 | end 22 | 23 | LibContainer:AddCategory(index, name, localizedName, filter) 24 | -------------------------------------------------------------------------------- /categories/Invalid.lua: -------------------------------------------------------------------------------- 1 | local L = LibContainer.locale 2 | 3 | local name = 'Invalid' 4 | local localizedName = L['Erroneous'] 5 | local index = 2 6 | 7 | local filter = function(Slot) 8 | -- any item that is not retrieving information 9 | return not GetContainerItemLink(Slot:GetBagAndSlot()) 10 | end 11 | 12 | LibContainer:AddCategory(index, name, localizedName, filter) 13 | -------------------------------------------------------------------------------- /categories/Inventory.lua: -------------------------------------------------------------------------------- 1 | local L = LibContainer.locale 2 | 3 | local name = 'Inventory' 4 | local localizedName = L['Inventory'] 5 | local index = 1 -- as low as possible 6 | 7 | local filter = function(Slot) 8 | -- default path 9 | return true 10 | end 11 | 12 | LibContainer:AddCategory(index, name, localizedName, filter) 13 | -------------------------------------------------------------------------------- /categories/Junk.lua: -------------------------------------------------------------------------------- 1 | local L = LibContainer.locale 2 | 3 | local name = 'Junk' 4 | local localizedName = L['Junk'] 5 | local index = 998 -- as high as possible 6 | 7 | local filter = function(Slot) 8 | local custom = LibContainer.db.KnownItems[Slot:GetItemID()] 9 | if(custom and type(custom) == 'number') then 10 | return custom == index 11 | else 12 | if(IsArtifactPowerItem(Slot:GetItemID())) then 13 | -- Crucible's Promise makes AP items useless 14 | return (select(13, GetAchievementInfo(12071))) 15 | else 16 | return Slot:GetItemQuality() == LE_ITEM_QUALITY_POOR 17 | end 18 | end 19 | end 20 | 21 | local sort = function(slotA, slotB) 22 | return (slotA:GetItemValue() * slotA:GetItemCount()) > (slotB:GetItemValue() * slotB:GetItemCount()) 23 | end 24 | 25 | LibContainer:AddCategory(index, name, localizedName, filter, sort) 26 | -------------------------------------------------------------------------------- /categories/New.lua: -------------------------------------------------------------------------------- 1 | local L = LibContainer.locale 2 | 3 | local name = 'New' 4 | local localizedName = L['New Items'] 5 | local index = 997 -- as high as possible 6 | 7 | local filter = function(Slot) 8 | local custom = LibContainer.db.KnownItems[Slot:GetItemID()] 9 | if(custom and type(custom) == 'number') then 10 | return custom == index 11 | else 12 | -- don't mark junk as new 13 | return Slot:GetItemQuality() > LE_ITEM_QUALITY_POOR 14 | end 15 | end 16 | 17 | LibContainer:AddCategory(index, name, localizedName, filter) 18 | -------------------------------------------------------------------------------- /categories/Professions.lua: -------------------------------------------------------------------------------- 1 | local L = LibContainer.locale 2 | 3 | local name = 'Professions' 4 | local localizedName = L['Professions'] 5 | local index = 50 6 | 7 | local filter = function(Slot) 8 | local custom = LibContainer.db.KnownItems[Slot:GetItemID()] 9 | if(custom and type(custom) == 'number') then 10 | return custom == index 11 | else 12 | local itemClass = Slot:GetItemClass() 13 | local itemSubClass = Slot:GetItemSubClass() 14 | if(itemClass == LE_ITEM_CLASS_CONSUMABLE and itemSubClass == 0) then 15 | -- engineering explosives and devices 16 | return true 17 | elseif(itemClass == LE_ITEM_CLASS_RECIPE) then 18 | return true 19 | elseif(itemClass == LE_ITEM_CLASS_CONTAINER and itemSubClass ~= 1) then 20 | -- profession bags 21 | return true 22 | end 23 | end 24 | end 25 | 26 | LibContainer:AddCategory(index, name, localizedName, filter) 27 | -------------------------------------------------------------------------------- /categories/Quests.lua: -------------------------------------------------------------------------------- 1 | local L = LibContainer.locale 2 | 3 | local name = 'Quests' 4 | local localizedName = L['Quest Items'] 5 | local index = 20 6 | 7 | local filter = function(Slot) 8 | local custom = LibContainer.db.KnownItems[Slot:GetItemID()] 9 | if(custom and type(custom) == 'number') then 10 | return custom == index 11 | else 12 | -- any item that is part of, or starts, a quest 13 | return Slot:GetItemQuestID() or Slot:IsItemQuestItem() 14 | end 15 | end 16 | 17 | LibContainer:AddCategory(index, name, localizedName, filter) 18 | -------------------------------------------------------------------------------- /categories/ReagentBank.lua: -------------------------------------------------------------------------------- 1 | local L = LibContainer.locale 2 | 3 | local name = 'ReagentBank' 4 | local localizedName = L['Reagent Bank'] 5 | local index = 999 -- as high as possible 6 | 7 | local filter = function(Slot) 8 | -- default path for reagent bank items, not allowing custom items here 9 | local bagID = Slot:GetBagAndSlot() 10 | return IsReagentBankUnlocked() and bagID == REAGENTBANK_CONTAINER 11 | end 12 | 13 | LibContainer:AddCategory(index, name, localizedName, filter) 14 | -------------------------------------------------------------------------------- /categories/Teleport.lua: -------------------------------------------------------------------------------- 1 | local L = LibContainer.locale 2 | 3 | local name = 'Teleport' 4 | local localizedName = L['Teleporters'] 5 | local index = 60 6 | 7 | local teleporters 8 | local filter = function(Slot) 9 | local itemID = Slot:GetItemID() 10 | local custom = LibContainer.db.KnownItems[itemID] 11 | if(custom and type(custom) == 'number') then 12 | return custom == index 13 | else 14 | return teleporters[itemID] 15 | end 16 | end 17 | 18 | LibContainer:AddCategory(index, name, localizedName, filter) 19 | 20 | -- custom list of any items that provide teleportation, because they deserve their own category 21 | teleporters = { 22 | -- Quest/achievement rewards 23 | [21711] = true, -- Lunar Festival Invitation 24 | [35230] = true, -- Darnarian's Scroll of Teleportation 25 | [52251] = true, -- Jaina's Locket 26 | [68808] = true, -- Hero's Hearthstone 27 | [68809] = true, -- Veteran's Hearthstone 28 | [110560] = true, -- Garrison Hearthstone 29 | [128353] = true, -- Admiral's Compass 30 | [140192] = true, -- Dalaran Hearthstone 31 | [141605] = true, -- Flight Master's Whistle 32 | 33 | -- Equipment 34 | [17690] = true, -- Frostwolf Insignia Rank 1 35 | [17691] = true, -- Stormpike Insignia Rank 1 36 | [17900] = true, -- Stormpike Insignia Rank 2 37 | [17901] = true, -- Stormpike Insignia Rank 3 38 | [17902] = true, -- Stormpike Insignia Rank 4 39 | [17903] = true, -- Stormpike Insignia Rank 5 40 | [17904] = true, -- Stormpike Insignia Rank 6 41 | [17905] = true, -- Frostwolf Insignia Rank 2 42 | [17906] = true, -- Frostwolf Insignia Rank 3 43 | [17907] = true, -- Frostwolf Insignia Rank 4 44 | [17908] = true, -- Frostwolf Insignia Rank 5 45 | [17909] = true, -- Frostwolf Insignia Rank 6 46 | [22589] = true, -- Atiesh, Greatstaff of the Guardian (Mage) 47 | [22630] = true, -- Atiesh, Greatstaff of the Guardian (Warlock) 48 | [22631] = true, -- Atiesh, Greatstaff of the Guardian (Priest) 49 | [22632] = true, -- Atiesh, Greatstaff of the Guardian (Druid) 50 | [28585] = true, -- Ruby Slippers 51 | [32757] = true, -- Blessed Medallion of Karabor 52 | [40585] = true, -- Signet of the Kirin Tor 53 | [40586] = true, -- Band of the Kirin Tor 54 | [44934] = true, -- Loop of the Kirin Tor 55 | [44935] = true, -- Ring of the Kirin Tor 56 | [45688] = true, -- Inscribed Band of the Kirin Tor 57 | [45689] = true, -- Inscribed Loop of the Kirin Tor 58 | [45690] = true, -- Inscribed Ring of the Kirin Tor 59 | [45691] = true, -- Inscribed Signet of the Kirin Tor 60 | [46874] = true, -- Argent Crusader's Tabard 61 | [48954] = true, -- Etched Band of the Kirin Tor 62 | [48955] = true, -- Etched Loop of the Kirin Tor 63 | [48956] = true, -- Etched Ring of the Kirin Tor 64 | [48957] = true, -- Etched Signet of the Kirin Tor 65 | [50287] = true, -- Boots of the Bay 66 | [51557] = true, -- Runed Signet of the Kirin Tor 67 | [51558] = true, -- Runed Loop of the Kirin Tor 68 | [51559] = true, -- Runed Ring of the Kirin Tor 69 | [51560] = true, -- Runed Band of the Kirin Tor 70 | [63206] = true, -- Wrap of Unity 71 | [63207] = true, -- Wrap of Unity 72 | [63352] = true, -- Shroud of Cooperation 73 | [63353] = true, -- Shroud of Cooperation 74 | [63378] = true, -- Hellscream's Reach Tabard 75 | [63379] = true, -- Baradin's Wardens Tabard 76 | [65274] = true, -- Cloak of Coordination 77 | [65360] = true, -- Cloak of Coordination 78 | [95050] = true, -- The Brassiest Knuckle (Horde) 79 | [95051] = true, -- The Brassiest Knuckle (Alliance) 80 | [103678] = true, -- Time-Lost Artifact 81 | [139599] = true, -- Empowered Ring of the Kirin Tor 82 | [142469] = true, -- Violet Seal of the Grand Magus 83 | 84 | -- Misc 85 | [6948] = true, -- Hearthstone 86 | [37118] = true, -- Scroll of Recall 87 | [37863] = true, -- Direbrew's Remote 88 | [44314] = true, -- Scroll of Recall II 89 | [44315] = true, -- Scroll of Recall III 90 | [58487] = true, -- Potion of Deepholm 91 | [64457] = true, -- The Last Relic of Argus 92 | [87548] = true, -- Lorewalker's Lodestone 93 | [118663] = true, -- Relic of Karabor 94 | [128502] = true, -- Hunter's Seeking Crystal 95 | [128503] = true, -- Master Hunter's Seeking Crystal 96 | [129276] = true, -- Beginner's Guide to Dimensional Rifting 97 | [139590] = true, -- Scroll of Teleport: Ravenholdt 98 | [141013] = true, -- Scroll of Town Portal: Shala'nir 99 | [141014] = true, -- Scroll of Town Portal: Sashj'tar 100 | [141015] = true, -- Scroll of Town Portal: Kal'delar 101 | [141016] = true, -- Scroll of Town Portal: Faronaar 102 | [141017] = true, -- Scroll of Town Portal: Lian'tril 103 | } 104 | -------------------------------------------------------------------------------- /categories/TradeGoods.lua: -------------------------------------------------------------------------------- 1 | local L = LibContainer.locale 2 | 3 | local name = 'TradeGoods' 4 | local localizedName = L['Trade Goods'] 5 | local index = 40 6 | 7 | local filter = function(Slot) 8 | local custom = LibContainer.db.KnownItems[Slot:GetItemID()] 9 | if(custom and type(custom) == 'number') then 10 | return custom == index 11 | else 12 | return Slot:GetItemClass() == LE_ITEM_CLASS_TRADEGOODS 13 | end 14 | end 15 | 16 | LibContainer:AddCategory(index, name, localizedName, filter) 17 | -------------------------------------------------------------------------------- /core/Blizzard.lua: -------------------------------------------------------------------------------- 1 | local parentMixin = LibContainer.mixins.parent 2 | 3 | --[[ LibContainer:DisableBlizzard(parentType) 4 | Disables the stock UI for the given parent type (see [Parent:GetType()](Parent#parentgettype)). 5 | 6 | * parentType - parent container type (string) 7 | --]] 8 | function LibContainer:DisableBlizzard(parentType) 9 | if(parentType == 'bags') then 10 | MainMenuBarBackpackButton:UnregisterEvent('INVENTORY_SEARCH_UPDATE') 11 | 12 | for containerIndex = BACKPACK_CONTAINER + 1, NUM_BAG_SLOTS + 1 do 13 | -- for some reason the indices are skewed 14 | _G['ContainerFrame' .. containerIndex]:UnregisterAllEvents() 15 | end 16 | 17 | -- TODO: disable bag slot buttons 18 | elseif(parentType == 'bank') then 19 | BankFrame:UnregisterAllEvents() 20 | ReagentBankFrame:UnregisterAllEvents() 21 | 22 | for containerIndex = NUM_BAG_SLOTS + 2, NUM_BAG_SLOTS + NUM_BANKBAGSLOTS + 2 do 23 | -- for some reason the indices are skewed 24 | _G['ContainerFrame' .. containerIndex]:UnregisterAllEvents() 25 | end 26 | else 27 | error('parentType is invalid.') 28 | end 29 | end 30 | 31 | --[[ Parent:OverrideToggles() 32 | Overrides the methods for toggling the visible state of the stock bags to instead toggle 33 | the visibility of the Parent container. 34 | 35 | This is optional, but highly recommended for typical usage. 36 | The layout could instead override the methods themselves and add custom bindings. 37 | --]] 38 | function parentMixin:OverrideToggles() 39 | assert(self:GetType() == 'bags', 'OverrideToggles can only be called on bags') 40 | 41 | OpenAllBags = function() 42 | self:Toggle(true) 43 | end 44 | 45 | CloseAllBags = function() 46 | self:Toggle(false) 47 | end 48 | 49 | ToggleBackpack = function() 50 | self:Toggle() 51 | end 52 | 53 | ToggleAllBags = ToggleBackpack 54 | ToggleBag = nop 55 | end 56 | -------------------------------------------------------------------------------- /core/Constants.lua: -------------------------------------------------------------------------------- 1 | local bagSlots = {} 2 | bagSlots.bags = {} 3 | bagSlots.bank = {} 4 | 5 | bagSlots.bank[BANK_CONTAINER] = true 6 | bagSlots.bank[REAGENTBANK_CONTAINER] = true 7 | 8 | for index = BACKPACK_CONTAINER, NUM_BAG_SLOTS do 9 | bagSlots.bags[index] = true 10 | end 11 | 12 | for index = 1, NUM_BANKBAGSLOTS do 13 | bagSlots.bank[NUM_BAG_SLOTS + index] = true 14 | end 15 | 16 | local bagSizes = setmetatable({ 17 | [BACKPACK_CONTAINER] = BACKPACK_BASE_SIZE + 4, 18 | [BANK_CONTAINER] = NUM_BANKGENERIC_SLOTS, 19 | [REAGENTBANK_CONTAINER] = 98 20 | }, { 21 | __index = function() 22 | return MAX_CONTAINER_ITEMS 23 | end 24 | }) 25 | 26 | LibContainer.constants.bagSlots = bagSlots 27 | LibContainer.constants.bagSizes = bagSizes 28 | -------------------------------------------------------------------------------- /core/Database.lua: -------------------------------------------------------------------------------- 1 | local parentAddOnName = ... 2 | local defaults = { 3 | KnownItems = {}, -- key = itemID, value = categoryKey 4 | } 5 | 6 | local database_name = 'LibContainerDB' 7 | --[[ LibContainer:SetDatabase(globalName) 8 | Set the global name for the database. 9 | 10 | * globalName - global savedvariable name (string) 11 | --]] 12 | function LibContainer:SetDatabase(db) 13 | assert(type(db) == 'string', 'db argument is invalid.') 14 | assert(not _G[db], 'db argument is invalid.') 15 | 16 | -- TODO: consider using TOC metadata instead? 17 | database_name = db 18 | end 19 | 20 | --[[ LibContainer:ResetDatabase() 21 | Resets the database back to the defaults. 22 | --]] 23 | function LibContainer:ResetDatabase() 24 | LibContainer.db = defaults 25 | end 26 | 27 | --[[ LibContainer:SetVariable(key, value) 28 | Sets the variable value by key. 29 | 30 | * key - savedvariable key (string) 31 | * value - savedvariable value (string|number|boolean) 32 | --]] 33 | function LibContainer:SetVariable(key, value) 34 | assert(type(key) == 'string', 'key argument is invalid.') 35 | assert(value ~= nil, 'value argument is invalid.') 36 | 37 | LibContainer.db[key] = value 38 | end 39 | 40 | --[[ LibContainer:GetVariable(key) 41 | Returns the variable value by key. 42 | --]] 43 | function LibContainer:GetVariable(key) 44 | return LibContainer.db[key] 45 | end 46 | 47 | local function Initialize() 48 | local db = _G[database_name] 49 | if(not db) then 50 | db = defaults 51 | end 52 | 53 | LibContainer.db = db 54 | _G[database_name] = db 55 | end 56 | 57 | local Handler = CreateFrame('Frame') 58 | Handler:RegisterEvent('ADDON_LOADED') 59 | Handler:SetScript('OnEvent', function(self, event, name) 60 | if(name == parentAddOnName) then 61 | self:UnregisterEvent(event) 62 | Initialize() 63 | end 64 | end) 65 | -------------------------------------------------------------------------------- /core/Init.lua: -------------------------------------------------------------------------------- 1 | assert(not LibContainer, 'Only one instance of LibContainer can exist.') 2 | 3 | LibContainer = {} 4 | LibContainer.mixins = {} 5 | LibContainer.constants = {} 6 | LibContainer.locale = {} 7 | -------------------------------------------------------------------------------- /core/Localization.lua: -------------------------------------------------------------------------------- 1 | local localizations = {} 2 | local locale = GetLocale() 3 | setmetatable(LibContainer.locale, { 4 | __call = function(_, newLocale) 5 | localizations[newLocale] = {} 6 | return localizations[newLocale] 7 | end, 8 | __index = function(_, key) 9 | local localeTable = localizations[locale] 10 | return localeTable and localeTable[key] or tostring(key) 11 | end 12 | }) 13 | -------------------------------------------------------------------------------- /core/Private.lua: -------------------------------------------------------------------------------- 1 | -- we don't want people to mess around with these 2 | LibContainer.mixins = nil 3 | LibContainer.constants = nil 4 | LibContainer.locale = nil 5 | -------------------------------------------------------------------------------- /embed.xml: -------------------------------------------------------------------------------- 1 | 2 |