Lua Code:
SellAllInBag = CreateFrame('Frame')
SellAllInBag.itemsToSell = {}
SellAllInBag.pendingBags = {}
function SellAllInBag:SetCurrentBag(bagID)
wipe(self.itemsToSell)
self.currentBagID = bagID
self.itemsSold = 0
local toggleEvent = (bagID ~= nil) and self.RegisterEvent or self.UnregisterEvent
toggleEvent(self, 'BAG_UPDATE')
toggleEvent(self, 'BAG_UPDATE_DELAYED')
end
function SellAllInBag:AttemptSellItems(index)
for i=index or 1, #self.itemsToSell do
UseContainerItem(self.currentBagID, self.itemsToSell[i])
end
end
function SellAllInBag:ProcessNextInQueue()
local bagInQueue = tremove(self.pendingBags, 1)
if bagInQueue then
self(bagInQueue)
end
end
function SellAllInBag:OnEvent(event)
if ( event == 'BAG_UPDATE' ) then
self.itemsSold = self.itemsSold + 1
elseif ( event == 'BAG_UPDATE_DELAYED' ) then
if ( self.itemsSold == #self.itemsToSell ) then
self:SetCurrentBag(nil)
self:ProcessNextInQueue()
else
self:AttemptSellItems(self.itemsSold)
end
elseif ( event == 'MERCHANT_SHOW' ) then
self.merchantAvailable = true
elseif ( event == 'MERCHANT_CLOSED' ) then
self.merchantAvailable = false
self:SetCurrentBag(nil)
wipe(self.pendingBags)
end
end
SellAllInBag:RegisterEvent('MERCHANT_SHOW')
SellAllInBag:RegisterEvent('MERCHANT_CLOSED')
SellAllInBag:SetScript('OnEvent', SellAllInBag.OnEvent)
setmetatable(SellAllInBag, {
__index = getmetatable(SellAllInBag).__index;
__call = function(self, bagID)
--------------------------------------------------
if self.merchantAvailable then
if not self.currentBagID then
self:SetCurrentBag(bagID)
local itemsToSell = self.itemsToSell
for slot=1, GetContainerNumSlots(bagID) do
local link = select(7, GetContainerItemInfo(bagID, slot))
local sellPrice = (link and select(11, GetItemInfo(link))) or 0
if sellPrice > 0 then
itemsToSell[#itemsToSell + 1] = slot
end
end
if #itemsToSell > 0 then
self:AttemptSellItems()
else
self:SetCurrentBag(nil)
end
else
tinsert(self.pendingBags, bagID)
end
end
--------------------------------------------------
end;
})
Here's a robust solution for you. Using C_Timer.After is bad for multiple reasons, one of which is asynchronous execution.
Unlike the others, this takes into account if you're actually interacting with an NPC and it is safe to use even if you have massive lag.
It's a bit over-engineered, but I think this is your best bet. You can also run this for multiple bags and it'll queue them up and finish them off in order.
The way it works is it attempts to sell as many items as possible at once, counting each item that goes through, but when the server throttles your request, it'll queue a new attempt to sell as many items as possible from the items you have remaining in your bag. It will look like chunks of items are disappearing out of your bags.
Usage: