load Profile modules and settings (Import/Export) (NOT FINISHED)

@Bunny67 I need help finishing this.
This commit is contained in:
Crum
2018-01-04 20:11:53 -06:00
parent 610d202bdb
commit 3bc22fd800
8 changed files with 1255 additions and 849 deletions
+2 -2
View File
@@ -304,8 +304,8 @@ function E:PLAYER_ENTERING_WORLD()
if(not self.MediaUpdated) then if(not self.MediaUpdated) then
self:UpdateMedia() self:UpdateMedia()
self.MediaUpdated = true self.MediaUpdated = true
else -- else
self:ScheduleTimer("CheckRole", 0.01) -- self:ScheduleTimer("CheckRole", 0.01)
end end
local _, instanceType = IsInInstance() local _, instanceType = IsInInstance()
+546
View File
@@ -0,0 +1,546 @@
local E, L, V, P, G = unpack(ElvUI)
local D = E:NewModule("Distributor", "AceEvent-3.0","AceTimer-3.0","AceComm-3.0","AceSerializer-3.0")
local LibCompress = LibStub:GetLibrary("LibCompress");
local LibBase64 = LibStub("LibBase64-1.0");
local tonumber, type, pcall, loadstring = tonumber, type, pcall, loadstring;
local len, format, split, find = string.len, string.format, string.split, string.find;
local CreateFrame = CreateFrame;
local GetNumRaidMembers, UnitInRaid = GetNumRaidMembers, UnitInRaid;
local GetNumPartyMembers, UnitInParty = GetNumPartyMembers, UnitInParty;
local ACCEPT, CANCEL, YES, NO = ACCEPT, CANCEL, YES, NO;
----------------------------------
-- CONSTANTS
----------------------------------
local REQUEST_PREFIX = "ELVUI_REQUEST"
local REPLY_PREFIX = "ELVUI_REPLY"
local TRANSFER_PREFIX = "ELVUI_TRANSFER"
local TRANSFER_COMPLETE_PREFIX = "ELVUI_COMPLETE"
-- The active downloads
local Downloads = {}
local Uploads = {}
function D:Initialize()
self:RegisterComm(REQUEST_PREFIX)
self:RegisterEvent("CHAT_MSG_ADDON")
self.statusBar = CreateFrame("StatusBar", "ElvUI_Download", UIParent)
E:RegisterStatusBar(self.statusBar);
E:CreateBackdrop(self.statusBar, "Default")
self.statusBar:SetStatusBarTexture(E.media.normTex)
self.statusBar:SetStatusBarColor(0.95, 0.15, 0.15)
self.statusBar:SetWidth(250)
self.statusBar:SetWidth(18)
self.statusBar.text = self.statusBar:CreateFontString(nil, "OVERLAY")
E:FontTemplate(self.statusBar.text)
self.statusBar.text:SetPoint("CENTER", 0, 0)
self.statusBar:Hide()
end
-- Used to start uploads
function D:Distribute(target, otherServer, isGlobal)
local profileKey, data;
if not isGlobal then
if ElvDB.profileKeys then
profileKey = ElvDB.profileKeys[E.myname.." - "..E.myrealm]
end
data = ElvDB.profiles[profileKey]
else
profileKey = "global"
data = ElvDB.global
end
if not data or not profileKey then return end
local serialData = self:Serialize(data)
local length = len(serialData)
local message = format("%s:%d:%s", profileKey, length, target)
Uploads[profileKey] = {
serialData = serialData,
target = target,
}
if otherServer then
local numParty, numRaid = GetNumPartyMembers(), GetNumRaidMembers();
if(numRaid > 0 and UnitInRaid("target")) then
self:SendCommMessage(REQUEST_PREFIX, message, "RAID");
elseif(numParty > 0 and UnitInParty("target")) then
self:SendCommMessage(REQUEST_PREFIX, message, "PARTY");
else
E:Print(L["Must be in group with the player if he isn't on the same server as you."])
return
end
else
self:SendCommMessage(REQUEST_PREFIX, message, "WHISPER", target)
end
self:RegisterComm(REPLY_PREFIX)
E:StaticPopup_Show("DISTRIBUTOR_WAITING")
end
function D:CHAT_MSG_ADDON(_, _, message, _, sender)
if not Downloads[sender] then return end
local cur = len(message)
local max = Downloads[sender].length
Downloads[sender].current = Downloads[sender].current + cur
if Downloads[sender].current > max then
Downloads[sender].current = max
end
self.statusBar:SetValue(Downloads[sender].current)
end
function D:OnCommReceived(prefix, msg, dist, sender)
if prefix == REQUEST_PREFIX then
local profile, length, sendTo = split(":", msg)
if dist ~= "WHISPER" and sendTo ~= E.myname then
return
end
if self.statusBar:IsShown() then
self:SendCommMessage(REPLY_PREFIX, profile..":NO", dist, sender)
return
end
local textString = format(L["%s is attempting to share the profile %s with you. Would you like to accept the request?"], sender, profile)
if profile == "global" then
textString = format(L["%s is attempting to share his filters with you. Would you like to accept the request?"], sender)
end
E.PopupDialogs["DISTRIBUTOR_RESPONSE"] = {
text = textString,
OnAccept = function()
self.statusBar:SetMinMaxValues(0, length)
self.statusBar:SetValue(0)
self.statusBar.text:SetFormattedText(L["Data From: %s"], sender)
E:StaticPopupSpecial_Show(self.statusBar)
self:SendCommMessage(REPLY_PREFIX, profile..":YES", dist, sender)
end,
OnCancel = function()
self:SendCommMessage(REPLY_PREFIX, profile..":NO", dist, sender)
end,
button1 = ACCEPT,
button2 = CANCEL,
timeout = 32,
whileDead = 1,
hideOnEscape = 1,
}
E:StaticPopup_Show("DISTRIBUTOR_RESPONSE")
Downloads[sender] = {
current = 0,
length = tonumber(length),
profile = profile,
}
self:RegisterComm(TRANSFER_PREFIX)
elseif prefix == REPLY_PREFIX then
self:UnregisterComm(REPLY_PREFIX)
E:StaticPopup_Hide("DISTRIBUTOR_WAITING")
local profileKey, response = split(":", msg)
if response == "YES" then
self:RegisterComm(TRANSFER_COMPLETE_PREFIX)
self:SendCommMessage(TRANSFER_PREFIX, Uploads[profileKey].serialData, dist, Uploads[profileKey].target)
Uploads[profileKey] = nil
else
E:StaticPopup_Show("DISTRIBUTOR_REQUEST_DENIED")
Uploads[profileKey] = nil
end
elseif prefix == TRANSFER_PREFIX then
self:UnregisterComm(TRANSFER_PREFIX)
E:StaticPopupSpecial_Hide(self.statusBar)
local profileKey = Downloads[sender].profile
local success, data = self:Deserialize(msg)
if success then
local textString = format(L["Profile download complete from %s, would you like to load the profile %s now?"], sender, profileKey)
if profileKey == "global" then
textString = format(L["Filter download complete from %s, would you like to apply changes now?"], sender)
else
if not ElvDB.profiles[profileKey] then
ElvDB.profiles[profileKey] = data
else
textString = format(L["Profile download complete from %s, but the profile %s already exists. Change the name or else it will overwrite the existing profile."], sender, profileKey)
E.PopupDialogs["DISTRIBUTOR_CONFIRM"] = {
text = textString,
button1 = ACCEPT,
hasEditBox = 1,
editBoxWidth = 350,
maxLetters = 127,
OnAccept = function(self)
ElvDB.profiles[self.editBox:GetText()] = data
LibStub("AceAddon-3.0"):GetAddon("ElvUI").data:SetProfile(self.editBox:GetText())
E:UpdateAll(true)
Downloads[sender] = nil
end,
OnShow = function(self) self.editBox:SetText(profileKey) self.editBox:SetFocus() end,
timeout = 0,
exclusive = 1,
whileDead = 1,
hideOnEscape = 1,
preferredIndex = 3
}
E:StaticPopup_Show("DISTRIBUTOR_CONFIRM")
self:SendCommMessage(TRANSFER_COMPLETE_PREFIX, "COMPLETE", dist, sender)
return
end
end
E.PopupDialogs["DISTRIBUTOR_CONFIRM"] = {
text = textString,
OnAccept = function()
if profileKey == "global" then
E:CopyTable(ElvDB.global, data)
E:UpdateAll(true)
else
LibStub("AceAddon-3.0"):GetAddon("ElvUI").data:SetProfile(profileKey)
end
Downloads[sender] = nil
end,
OnCancel = function()
Downloads[sender] = nil
end,
button1 = YES,
button2 = NO,
whileDead = 1,
hideOnEscape = 1,
}
E:StaticPopup_Show("DISTRIBUTOR_CONFIRM")
self:SendCommMessage(TRANSFER_COMPLETE_PREFIX, "COMPLETE", dist, sender)
else
E:StaticPopup_Show("DISTRIBUTOR_FAILED")
self:SendCommMessage(TRANSFER_COMPLETE_PREFIX, "FAILED", dist, sender)
end
elseif prefix == TRANSFER_COMPLETE_PREFIX then
self:UnregisterComm(TRANSFER_COMPLETE_PREFIX)
if msg == "COMPLETE" then
E:StaticPopup_Show("DISTRIBUTOR_SUCCESS")
else
E:StaticPopup_Show("DISTRIBUTOR_FAILED")
end
end
end
local function GetProfileData(profileType)
if(not profileType or type(profileType) ~= "string") then
E:Print("Bad argument #1 to 'GetProfileData' (string expected)");
return;
end
local profileKey;
local profileData = {};
if(profileType == "profile") then
if(ElvDB.profileKeys) then
profileKey = ElvDB.profileKeys[E.myname.." - "..E.myrealm];
end
profileData = E:CopyTable(profileData , ElvDB.profiles[profileKey])
profileData = E:RemoveTableDuplicates(profileData, P);
elseif(profileType == "private") then
local privateProfileKey = E.myname.." - "..E.myrealm;
profileKey = "private";
profileData = E:CopyTable(profileData, ElvPrivateDB.profiles[privateProfileKey]);
profileData = E:RemoveTableDuplicates(profileData, V);
elseif(profileType == "global") then
profileKey = "global";
profileData = E:CopyTable(profileData, ElvDB.global);
profileData = E:RemoveTableDuplicates(profileData, G);
elseif(profileType == "filtersNP") then
profileKey = "filtersNP";
profileData["nameplates"] = {};
profileData["nameplates"]["filter"] = {};
profileData["nameplates"]["filter"] = E:CopyTable(profileData["nameplates"]["filter"], ElvDB.global.nameplates.filter);
profileData = E:RemoveTableDuplicates(profileData, G);
elseif(profileType == "filtersUF") then
profileKey = "filtersUF";
profileData["unitframe"] = {};
profileData["unitframe"]["aurafilters"] = {};
profileData["unitframe"]["aurafilters"] = E:CopyTable(profileData["unitframe"]["aurafilters"], ElvDB.global.unitframe.aurafilters);
profileData["unitframe"]["buffwatch"] = {};
profileData["unitframe"]["buffwatch"] = E:CopyTable(profileData["unitframe"]["buffwatch"], ElvDB.global.unitframe.buffwatch);
profileData = E:RemoveTableDuplicates(profileData, G);
elseif(profileType == "filtersAll") then
profileKey = "filtersAll";
profileData["nameplates"] = {};
profileData["nameplates"]["filter"] = {};
profileData["nameplates"]["filter"] = E:CopyTable(profileData["nameplates"]["filter"], ElvDB.global.nameplates.filter);
profileData["unitframe"] = {};
profileData["unitframe"]["aurafilters"] = {};
profileData["unitframe"]["aurafilters"] = E:CopyTable(profileData["unitframe"]["aurafilters"], ElvDB.global.unitframe.aurafilters);
profileData["unitframe"]["buffwatch"] = {};
profileData["unitframe"]["buffwatch"] = E:CopyTable(profileData["unitframe"]["buffwatch"], ElvDB.global.unitframe.buffwatch);
profileData = E:RemoveTableDuplicates(profileData, G);
end
return profileKey, profileData;
end
local function GetProfileExport(profileType, exportFormat)
local profileExport, exportString;
local profileKey, profileData = GetProfileData(profileType);
if(not profileKey or not profileData or (profileData and type(profileData) ~= "table")) then
E:Print("Error getting data from 'GetProfileData'");
return;
end
if(exportFormat == "text") then
local serialData = D:Serialize(profileData);
exportString = D:CreateProfileExport(serialData, profileType, profileKey);
local compressedData = LibCompress:Compress(exportString);
local encodedData = LibBase64:Encode(compressedData);
profileExport = encodedData;
elseif(exportFormat == "luaTable") then
exportString = E:TableToLuaString(profileData);
profileExport = D:CreateProfileExport(exportString, profileType, profileKey);
elseif(exportFormat == "luaPlugin") then
profileExport = E:ProfileTableToPluginFormat(profileData, profileType);
end
return profileKey, profileExport;
end
function D:CreateProfileExport(dataString, profileType, profileKey)
local returnString;
if(profileType == "profile") then
returnString = format("%s::%s::%s", dataString, profileType, profileKey);
else
returnString = format("%s::%s", dataString, profileType);
end
return returnString;
end
function D:GetImportStringType(dataString)
local stringType = "";
if(LibBase64:IsBase64(dataString)) then
stringType = "Base64";
elseif(find(dataString, "{")) then
stringType = "Table";
end
return stringType;
end
function D:Decode(dataString)
local profileInfo, profileType, profileKey, profileData, message;
local stringType = self:GetImportStringType(dataString);
if(stringType == "Base64") then
local decodedData = LibBase64:Decode(dataString);
local decompressedData, message = LibCompress:Decompress(decodedData);
if(not decompressedData) then
E:Print("Error decompressing data:", message);
return;
end
local serializedData, success;
serializedData, profileInfo = E:StringSplitMultiDelim(decompressedData, "^^::");
if not profileInfo then
E:Print("Error importing profile. String is invalid or corrupted!")
return
end
serializedData = format("%s%s", serializedData, "^^");
profileType, profileKey = E:StringSplitMultiDelim(profileInfo, "::");
success, profileData = D:Deserialize(serializedData);
if(not success) then
E:Print("Error deserializing:", profileData);
return;
end
elseif(stringType == "Table") then
local profileDataAsString;
profileDataAsString, profileInfo = E:StringSplitMultiDelim(dataString, "}::");
if not profileInfo then
E:Print("Error extracting profile info. Invalid import string!")
return
end
if(not profileDataAsString) then
E:Print("Error extracting profile data. Invalid import string!");
return;
end
profileDataAsString = format("%s%s", profileDataAsString, "}");
profileType, profileKey = E:StringSplitMultiDelim(profileInfo, "::");
local profileToTable = loadstring(format("%s %s", "return", profileDataAsString));
if(profileToTable) then
message, profileData = pcall(profileToTable);
end
if(not profileData or type(profileData) ~= "table") then
E:Print("Error converting lua string to table:", message);
return;
end
end
return profileType, profileKey, profileData;
end
local function SetImportedProfile(profileType, profileKey, profileData, force)
D.profileType = nil;
D.profileKey = nil;
D.profileData = nil;
if(profileType == "profile") then
if(not ElvDB.profiles[profileKey] or force) then
if(force and E.data.keys.profile == profileKey) then
local tempKey = profileKey.."_Temp";
E.data.keys.profile = tempKey;
end
ElvDB.profiles[profileKey] = profileData;
E.data:SetProfile(profileKey);
else
D.profileType = profileType;
D.profileKey = profileKey;
D.profileData = profileData;
E:StaticPopup_Show("IMPORT_PROFILE_EXISTS");
return;
end
elseif(profileType == "private") then
local profileKey = ElvPrivateDB.profileKeys[E.myname.." - "..E.myrealm];
ElvPrivateDB.profiles[profileKey] = profileData;
E:StaticPopup_Show("IMPORT_RL");
elseif(profileType == "global") then
E:CopyTable(ElvDB.global, profileData);
E:StaticPopup_Show("IMPORT_RL");
elseif(profileType == "filtersNP") then
E:CopyTable(ElvDB.global.nameplates, profileData.nameplates);
elseif(profileType == "filtersUF") then
E:CopyTable(ElvDB.global.unitframe, profileData.unitframe);
elseif(profileType == "filtersAll") then
E:CopyTable(ElvDB.global.nameplates, profileData.nameplates);
E:CopyTable(ElvDB.global.unitframe, profileData.unitframe);
end
E:UpdateAll(true);
end
function D:ExportProfile(profileType, exportFormat)
if(not profileType or not exportFormat) then
E:Print("Bad argument to 'ExportProfile' (string expected)");
return;
end
local profileKey, profileExport = GetProfileExport(profileType, exportFormat);
return profileKey, profileExport;
end
function D:ImportProfile(dataString)
local profileType, profileKey, profileData = self:Decode(dataString);
if(not profileData or type(profileData) ~= "table") then
E:Print("Error: something went wrong when converting string to table!");
return;
end
if(profileType and ((profileType == "profile" and profileKey) or profileType ~= "profile")) then
SetImportedProfile(profileType, profileKey, profileData);
end
return true;
end
E.PopupDialogs["DISTRIBUTOR_SUCCESS"] = {
text = L["Your profile was successfully recieved by the player."],
whileDead = 1,
hideOnEscape = 1,
button1 = OKAY,
}
E.PopupDialogs["DISTRIBUTOR_WAITING"] = {
text = L["Profile request sent. Waiting for response from player."],
whileDead = 1,
hideOnEscape = 1,
timeout = 35,
}
E.PopupDialogs["DISTRIBUTOR_REQUEST_DENIED"] = {
text = L["Request was denied by user."],
whileDead = 1,
hideOnEscape = 1,
button1 = OKAY,
}
E.PopupDialogs["DISTRIBUTOR_FAILED"] = {
text = L["Lord! It's a miracle! The download up and vanished like a fart in the wind! Try Again!"],
whileDead = 1,
hideOnEscape = 1,
button1 = OKAY,
}
E.PopupDialogs["DISTRIBUTOR_RESPONSE"] = {}
E.PopupDialogs["DISTRIBUTOR_CONFIRM"] = {}
E.PopupDialogs["IMPORT_PROFILE_EXISTS"] = {
text = L["The profile you tried to import already exists. Choose a new name or accept to overwrite the existing profile."],
button1 = ACCEPT,
button2 = CANCEL,
hasEditBox = 1,
editBoxWidth = 350,
maxLetters = 127,
OnAccept = function(self)
local profileType = D.profileType;
local profileKey = self.editBox:GetText();
local profileData = D.profileData;
SetImportedProfile(profileType, profileKey, profileData, true);
end,
EditBoxOnTextChanged = function(self)
if(self:GetText() == "") then
self:GetParent().button1:Disable();
else
self:GetParent().button1:Enable();
end
end,
OnShow = function(self) self.editBox:SetText(D.profileKey); self.editBox:SetFocus(); end,
timeout = 0,
whileDead = 1,
hideOnEscape = true,
preferredIndex = 3
};
E.PopupDialogs["IMPORT_RL"] = {
text = L["You have imported settings which may require a UI reload to take effect. Reload now?"],
button1 = ACCEPT,
button2 = CANCEL,
OnAccept = ReloadUI,
timeout = 0,
whileDead = 1,
hideOnEscape = false,
preferredIndex = 3
};
local function InitializeCallback()
D:Initialize()
end
E:RegisterModule(D:GetName(), InitializeCallback)
@@ -6,34 +6,50 @@ Description: A library to encode and decode Base64 strings
License: MIT License: MIT
]] ]]
local LibBase64 = LibStub:NewLibrary("LibBase64-1.0-ElvUI", 1) local modf = math.modf
local sub = string.sub
local format = string.format
local getn = table.getn
local gsub = string.gsub
local strlen = string.len
local byte = string.byte
local LibBase64 = LibStub:NewLibrary("LibBase64-1.0", 1)
if not LibBase64 then if not LibBase64 then
return return
end end
local _chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' local chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
local charTable = {}
local byteToNum = {} local byteToNum = {}
local numToChar = {} local numToChar = {}
for i = 1, #_chars do
numToChar[i - 1] = _chars:sub(i, i) for i = 1, strlen(chars) do
byteToNum[_chars:byte(i)] = i - 1 charTable[i] = sub(chars, i, i)
end end
_chars = nil
local A_byte = ("A"):byte() for i = 1, getn(charTable) do
local Z_byte = ("Z"):byte() numToChar[i - 1] = sub(chars, i, i)
local a_byte = ("a"):byte() byteToNum[byte(chars, i)] = i - 1
local z_byte = ("z"):byte() end
local zero_byte = ("0"):byte()
local nine_byte = ("9"):byte() charTable = nil
local plus_byte = ("+"):byte()
local slash_byte = ("/"):byte() local A_byte = byte("A")
local equals_byte = ("="):byte() local Z_byte = byte("Z")
local a_byte = byte("a")
local z_byte = byte("z")
local zero_byte = byte("0")
local nine_byte = byte("9")
local plus_byte = byte("+")
local slash_byte = byte("/")
local equals_byte = byte("=")
local whitespace = { local whitespace = {
[(" "):byte()] = true, [byte(" ")] = true,
[("\t"):byte()] = true, [byte("\t")] = true,
[("\n"):byte()] = true, [byte("\n")] = true,
[("\r"):byte()] = true, [byte("\r")] = true,
} }
local t = {} local t = {}
@@ -46,29 +62,29 @@ local t = {}
-- @return a Base64-encoded string -- @return a Base64-encoded string
function LibBase64:Encode(text, maxLineLength, lineEnding) function LibBase64:Encode(text, maxLineLength, lineEnding)
if type(text) ~= "string" then if type(text) ~= "string" then
error(("Bad argument #1 to `Encode'. Expected %q, got %q"):format("string", type(text)), 2) error(format("Bad argument #1 to `Encode'. Expected %q, got %q", "string", type(text)), 2)
end end
if maxLineLength == nil then if maxLineLength == nil then
-- do nothing -- do nothing
elseif type(maxLineLength) ~= "number" then elseif type(maxLineLength) ~= "number" then
error(("Bad argument #2 to `Encode'. Expected %q or %q, got %q"):format("number", "nil", type(maxLineLength)), 2) error(format("Bad argument #2 to `Encode'. Expected %q or %q, got %q", "number", "nil", type(maxLineLength)), 2)
elseif (maxLineLength % 4) ~= 0 then elseif modf(maxLineLength, 4) ~= 0 then
error(("Bad argument #2 to `Encode'. Expected a multiple of 4, got %s"):format(maxLineLength), 2) error(format("Bad argument #2 to `Encode'. Expected a multiple of 4, got %s", maxLineLength), 2)
elseif maxLineLength <= 0 then elseif maxLineLength <= 0 then
error(("Bad argument #2 to `Encode'. Expected a number > 0, got %s"):format(maxLineLength), 2) error(format("Bad argument #2 to `Encode'. Expected a number > 0, got %s", maxLineLength), 2)
end end
if lineEnding == nil then if lineEnding == nil then
lineEnding = "\r\n" lineEnding = "\r\n"
elseif type(lineEnding) ~= "string" then elseif type(lineEnding) ~= "string" then
error(("Bad argument #3 to `Encode'. Expected %q, got %q"):format("string", type(lineEnding)), 2) error(format("Bad argument #3 to `Encode'. Expected %q, got %q", "string", type(lineEnding)), 2)
end end
local currentLength = 0 local currentLength = 0
for i = 1, #text, 3 do for i = 1, getn(text), 3 do
local a, b, c = text:byte(i, i+2) local a, b, c = byte(text, i, i+2)
local nilNum = 0 local nilNum = 0
if not b then if not b then
nilNum = 2 nilNum = 2
@@ -80,33 +96,33 @@ function LibBase64:Encode(text, maxLineLength, lineEnding)
end end
local num = a * 2^16 + b * 2^8 + c local num = a * 2^16 + b * 2^8 + c
local d = num % 2^6 local d = modf(num, 2^6)
num = (num - d) / 2^6 num = (num - d) / 2^6
local c = num % 2^6 local c = modf(num, 2^6)
num = (num - c) / 2^6 num = (num - c) / 2^6
local b = num % 2^6 local b = modf(num, 2^6)
num = (num - b) / 2^6 num = (num - b) / 2^6
local a = num % 2^6 local a = modf(num, 2^6)
t[#t+1] = numToChar[a] t[getn(t+1)] = numToChar[a]
t[#t+1] = numToChar[b] t[getn(t+1)] = numToChar[b]
t[#t+1] = (nilNum >= 2) and "=" or numToChar[c] t[getn(t+1)] = (nilNum >= 2) and "=" or numToChar[c]
t[#t+1] = (nilNum >= 1) and "=" or numToChar[d] t[getn(t+1)] = (nilNum >= 1) and "=" or numToChar[d]
currentLength = currentLength + 4 currentLength = currentLength + 4
if maxLineLength and (currentLength % maxLineLength) == 0 then if maxLineLength and modf(currentLength, maxLineLength) == 0 then
t[#t+1] = lineEnding t[getn(t+1)] = lineEnding
end end
end end
local s = table.concat(t) local s = table.concat(t)
for i = 1, #t do for i = 1, getn(t) do
t[i] = nil t[i] = nil
end end
return s return s
@@ -122,27 +138,27 @@ local t2 = {}
-- @return a bytestring -- @return a bytestring
function LibBase64:Decode(text) function LibBase64:Decode(text)
if type(text) ~= "string" then if type(text) ~= "string" then
error(("Bad argument #1 to `Decode'. Expected %q, got %q"):format("string", type(text)), 2) error(format("Bad argument #1 to `Decode'. Expected %q, got %q", "string", type(text)), 2)
end end
for i = 1, #text do for i = 1, getn(text) do
local byte = text:byte(i) local byte = byte(text, i)
if whitespace[byte] or byte == equals_byte then if whitespace[byte] or byte == equals_byte then
-- do nothing -- do nothing
else else
local num = byteToNum[byte] local num = byteToNum[byte]
if not num then if not num then
for i = 1, #t2 do for i = 1, getn(t2) do
t2[k] = nil t2[k] = nil
end end
error(("Bad argument #1 to `Decode'. Received an invalid char: %q"):format(text:sub(i, i)), 2) error(format("Bad argument #1 to `Decode'. Received an invalid char: %q", sub(text, i, i)), 2)
end end
t2[#t2+1] = num t2[getn(t2+1)] = num
end end
end end
for i = 1, #t2, 4 do for i = 1, getn(t2), 4 do
local a, b, c, d = t2[i], t2[i+1], t2[i+2], t2[i+3] local a, b, c, d = t2[i], t2[i+1], t2[i+2], t2[i+3]
local nilNum = 0 local nilNum = 0
@@ -157,30 +173,30 @@ function LibBase64:Decode(text)
local num = a * 2^18 + b * 2^12 + c * 2^6 + d local num = a * 2^18 + b * 2^12 + c * 2^6 + d
local c = num % 2^8 local c = modf(num, 2^8)
num = (num - c) / 2^8 num = (num - c) / 2^8
local b = num % 2^8 local b = modf(num, 2^8)
num = (num - b) / 2^8 num = (num - b) / 2^8
local a = num % 2^8 local a = modf(num, 2^8)
t[#t+1] = string.char(a) t[getn(t+1)] = string.char(a)
if nilNum < 2 then if nilNum < 2 then
t[#t+1] = string.char(b) t[getn(t+1)] = string.char(b)
end end
if nilNum < 1 then if nilNum < 1 then
t[#t+1] = string.char(c) t[getn(t+1)] = string.char(c)
end end
end end
for i = 1, #t2 do for i = 1, getn(t2) do
t2[i] = nil t2[i] = nil
end end
local s = table.concat(t) local s = table.concat(t)
for i = 1, #t do for i = 1, getn(t) do
t[i] = nil t[i] = nil
end end
@@ -189,15 +205,15 @@ end
function LibBase64:IsBase64(text) function LibBase64:IsBase64(text)
if type(text) ~= "string" then if type(text) ~= "string" then
error(("Bad argument #1 to `IsBase64'. Expected %q, got %q"):format("string", type(text)), 2) error(format("Bad argument #1 to `IsBase64'. Expected %q, got %q", "string", type(text)), 2)
end end
if #text % 4 ~= 0 then if modf(strlen(text), 4 ~= 0) then
return false return false
end end
for i = 1, #text do for i = 1, getn(text) do
local byte = text:byte(i) local byte = byte(text, i)
if whitespace[byte] or byte == equals_byte then if whitespace[byte] or byte == equals_byte then
-- do nothing -- do nothing
else else
File diff suppressed because it is too large Load Diff
@@ -16,11 +16,9 @@
<Include file="LibDataBroker\LibDataBroker-1.1.xml"/> <Include file="LibDataBroker\LibDataBroker-1.1.xml"/>
<Include file="LibElvUIPlugin-1.0\LibElvUIPlugin-1.0.xml"/> <Include file="LibElvUIPlugin-1.0\LibElvUIPlugin-1.0.xml"/>
<Include file="oUF\oUF.xml"/> <Include file="oUF\oUF.xml"/>
<!--
<Include file="UTF8\UTF8.xml"/> <Include file="UTF8\UTF8.xml"/>
<Include file="LibCompress\LibCompress.xml"/> <Include file="LibCompress\LibCompress.xml"/>
<Include file="LibBase64-1.0\LibBase64-1.0.xml"/> <Include file="LibBase64-1.0\LibBase64-1.0.xml"/>
-->
<Include file="LibAnim\LibAnim.xml"/> <Include file="LibAnim\LibAnim.xml"/>
<Include file="LibUIDropDownMenu\LibUIDropDownMenu.xml"/> <Include file="LibUIDropDownMenu\LibUIDropDownMenu.xml"/>
</Ui> </Ui>
+299 -1
View File
@@ -1,5 +1,5 @@
local E, L, V, P, G = unpack(ElvUI); local E, L, V, P, G = unpack(ElvUI);
--local D = E:GetModule("Distributor"); local D = E:GetModule("Distributor");
local AceGUI = LibStub("AceGUI-3.0"); local AceGUI = LibStub("AceGUI-3.0");
local pairs = pairs; local pairs = pairs;
@@ -161,5 +161,303 @@ for _, testerName in pairs(TESTERS) do
TESTER_STRING = TESTER_STRING .. LINE_BREAK .. testerName; TESTER_STRING = TESTER_STRING .. LINE_BREAK .. testerName;
end end
E.Options.args.credits = {
type = "group",
name = L["Credits"],
order = -1,
args = {
text = {
order = 1,
type = "description",
name = L["ELVUI_CREDITS"] .. "\n\n" .. L["Coding:"] .. DEVELOPER_STRING .. "\n\n" .. L["Testing:"] .. TESTER_STRING .. "\n\n" .. L["Donations:"] .. DONATOR_STRING
}
}
}
local profileTypeItems = {
["profile"] = L["Profile"],
["private"] = L["Private (Character Settings)"],
["global"] = L["Global (Account Settings)"],
["filtersNP"] = L["Filters (NamePlates)"],
["filtersUF"] = L["Filters (UnitFrames)"],
["filtersAll"] = L["Filters (All)"]
}
local profileTypeListOrder = {
"profile",
"private",
"global",
"filtersNP",
"filtersUF",
"filtersAll"
}
local exportTypeItems = {
["text"] = L["Text"],
["luaTable"] = L["Table"],
["luaPlugin"] = L["Plugin"]
}
local exportTypeListOrder = {
"text",
"luaTable",
"luaPlugin"
}
local exportString = ""
local function ExportImport_Open(mode)
local frame = AceGUI:Create("Frame")
frame:SetTitle("")
frame:EnableResize(false)
frame:SetWidth(800)
frame:SetHeight(600)
frame.frame:SetFrameStrata("FULLSCREEN_DIALOG")
frame:SetLayout("flow")
local box = AceGUI:Create("MultiLineEditBox")
box:SetNumLines(30)
box:DisableButton(true)
box:SetWidth(800)
box:SetLabel("")
frame:AddChild(box)
box.editBox.OnTextChangedOrig = box.editBox:GetScript("OnTextChanged")
box.editBox.OnCursorChangedOrig = box.editBox:GetScript("OnCursorChanged")
box.editBox:SetScript("OnCursorChanged", nil)
local label1 = AceGUI:Create("Label")
local font = GameFontHighlightSmall:GetFont()
label1:SetFont(font, 14)
label1:SetText(" ")
label1:SetWidth(800)
frame:AddChild(label1)
local label2 = AceGUI:Create("Label")
local font = GameFontHighlightSmall:GetFont()
label2:SetFont(font, 14)
label2:SetText(" \n ")
label2:SetWidth(800)
frame:AddChild(label2)
if(mode == "export") then
frame:SetTitle(L["Export Profile"])
local profileTypeDropdown = AceGUI:Create("Dropdown")
profileTypeDropdown:SetMultiselect(false)
profileTypeDropdown:SetLabel(L["Choose What To Export"])
profileTypeDropdown:SetList(profileTypeItems, profileTypeListOrder)
profileTypeDropdown:SetValue("profile")
frame:AddChild(profileTypeDropdown)
local exportFormatDropdown = AceGUI:Create("Dropdown")
exportFormatDropdown:SetMultiselect(false)
exportFormatDropdown:SetLabel(L["Choose Export Format"])
exportFormatDropdown:SetList(exportTypeItems, exportTypeListOrder)
exportFormatDropdown:SetValue("text")
exportFormatDropdown:SetWidth(150)
frame:AddChild(exportFormatDropdown)
local exportButton = AceGUI:Create("Button")
exportButton:SetText(L["Export Now"])
exportButton:SetAutoWidth(true)
local function OnClick(self)
label1:SetText(" ")
label2:SetText(" ")
local profileType, exportFormat = profileTypeDropdown:GetValue(), exportFormatDropdown:GetValue()
local profileKey, profileExport = D:ExportProfile(profileType, exportFormat)
if(not profileKey or not profileExport) then
label1:SetText(L["Error exporting profile!"])
else
label1:SetText(format("%s: %s%s|r", L["Exported"], E.media.hexvaluecolor, profileTypeItems[profileType]))
if(profileType == "profile") then
label2:SetText(format("%s: %s%s|r", L["Profile Name"], E.media.hexvaluecolor, profileKey))
end
end
box:SetText(profileExport)
box.editBox:HighlightText()
box:SetFocus()
exportString = profileExport
end
exportButton:SetCallback("OnClick", OnClick)
frame:AddChild(exportButton)
box.editBox:SetScript("OnChar", function() box:SetText(exportString) box.editBox:HighlightText() end)
box.editBox:SetScript("OnTextChanged", function(self)
box:SetText(exportString)
box.editBox:HighlightText()
end)
elseif(mode == "import") then
frame:SetTitle(L["Import Profile"])
local importButton = AceGUI:Create("Button")
importButton:SetDisabled(true)
importButton:SetText(L["Import Now"])
importButton:SetAutoWidth(true)
importButton:SetCallback("OnClick", function()
label1:SetText(" ")
label2:SetText(" ")
local text
local success = D:ImportProfile(box:GetText())
if(success) then
text = L["Profile imported successfully!"]
else
text = L["Error decoding data. Import string may be corrupted!"]
end
label1:SetText(text)
end)
frame:AddChild(importButton)
local decodeButton = AceGUI:Create("Button")
decodeButton:SetDisabled(true)
decodeButton:SetText(L["Decode Text"])
decodeButton:SetAutoWidth(true)
decodeButton:SetCallback("OnClick", function()
label1:SetText(" ")
label2:SetText(" ")
local decodedText
local profileType, profileKey, profileData = D:Decode(box:GetText())
if(profileData) then
decodedText = E:TableToLuaString(profileData)
end
local importText = D:CreateProfileExport(decodedText, profileType, profileKey)
box:SetText(importText)
end)
frame:AddChild(decodeButton)
local oldText = ""
local function OnTextChanged()
local text = box:GetText()
if(text == "") then
label1:SetText(" ")
label2:SetText(" ")
importButton:SetDisabled(true)
decodeButton:SetDisabled(true)
elseif(oldText ~= text) then
local stringType = D:GetImportStringType(text)
if(stringType == "Base64") then
decodeButton:SetDisabled(false)
else
decodeButton:SetDisabled(true)
end
local profileType, profileKey = D:Decode(text)
if not profileType or (profileType and profileType == "profile" and not profileKey) then
label1:SetText(L["Error decoding data. Import string may be corrupted!"])
label2:SetText(" ")
importButton:SetDisabled(true)
decodeButton:SetDisabled(true)
else
label1:SetText(format("%s: %s%s|r", L["Importing"], E.media.hexvaluecolor, profileTypeItems[profileType] or ""))
if(profileType == "profile") then
label2:SetText(format("%s: %s%s|r", L["Profile Name"], E.media.hexvaluecolor, profileKey))
end
importButton:SetDisabled(false)
end
box.scrollFrame:UpdateScrollChildRect()
box.scrollFrame:SetVerticalScroll(box.scrollFrame:GetVerticalScrollRange())
box.scrollFrame:SetFrameLevel(box.scrollFrame:GetParent():GetFrameLevel() - 2)
oldText = text
end
end
box.editBox:SetFocus()
box.editBox:SetScript("OnChar", nil)
box.editBox:SetScript("OnTextChanged", OnTextChanged)
end
frame:SetCallback("OnClose", function(widget)
box.editBox:SetScript("OnChar", nil)
box.editBox:SetScript("OnTextChanged", box.editBox.OnTextChangedOrig)
box.editBox:SetScript("OnCursorChanged", box.editBox.OnCursorChangedOrig)
box.editBox.OnTextChangedOrig = nil
box.editBox.OnCursorChangedOrig = nil
exportString = ""
AceGUI:Release(widget)
ACD:Open("ElvUI")
end)
label1:SetText(" ")
label2:SetText(" ")
ACD:Close("ElvUI")
GameTooltip:Hide()
end
E.Options.args.profiles = LibStub("AceDBOptions-3.0"):GetOptionsTable(E.data)
AC.RegisterOptionsTable(P, "ElvProfiles", E.Options.args.profiles)
E.Options.args.profiles.order = -10
if(not E.Options.args.profiles.plugins) then
E.Options.args.profiles.plugins = {}
end
E.Options.args.profiles.plugins["ElvUI"] = {
spacer = {
order = 89,
type = "description",
name = "\n\n"
},
desc = {
order = 90,
type = "description",
name = L["This feature will allow you to transfer settings to other characters."]
},
distributeProfile = {
order = 91,
name = L["Share Current Profile"],
desc = L["Sends your current profile to your target."],
type = "execute",
func = function()
if(not UnitExists("target") or not UnitIsPlayer("target") or not UnitIsFriend("player", "target") or UnitIsUnit("player", "target")) then
E:Print(L["You must be targeting a player."])
return
end
local name, server = UnitName("target")
if(name and (not server or server == "")) then
D:Distribute(name)
elseif(server) then
D:Distribute(name, true)
end
end
},
distributeGlobal = {
order = 92,
type = "execute",
name = L["Share Filters"],
desc = L["Sends your filter settings to your target."],
func = function()
if(not UnitExists("target") or not UnitIsPlayer("target") or not UnitIsFriend("player", "target") or UnitIsUnit("player", "target")) then
E:Print(L["You must be targeting a player."])
return
end
local name, server = UnitName("target")
if(name and (not server or server == "")) then
D:Distribute(name, false, true)
elseif(server) then
D:Distribute(name, true, true)
end
end,
},
spacer2 = {
order = 93,
type = "description",
name = ""
},
exportProfile = {
order = 94,
type = "execute",
name = L["Export Profile"],
func = function() ExportImport_Open("export") end
},
importProfile = {
order = 95,
type = "execute",
name = L["Import Profile"],
func = function() ExportImport_Open("import") end
}
}
@@ -3,6 +3,6 @@
<Include file="AceConfigRegistry-3.0\AceConfigRegistry-3.0.xml"/> <Include file="AceConfigRegistry-3.0\AceConfigRegistry-3.0.xml"/>
<Include file="AceConfigCmd-3.0\AceConfigCmd-3.0.xml"/> <Include file="AceConfigCmd-3.0\AceConfigCmd-3.0.xml"/>
<Include file="AceConfigDialog-3.0\AceConfigDialog-3.0.xml"/> <Include file="AceConfigDialog-3.0\AceConfigDialog-3.0.xml"/>
<!--<Include file="AceConfigDropdown-3.0\AceConfigDropdown-3.0.xml"/>--> <Include file="AceConfigDropdown-3.0\AceConfigDropdown-3.0.xml"/>
<Script file="AceConfig-3.0.lua"/> <Script file="AceConfig-3.0.lua"/>
</Ui> </Ui>
+4 -4
View File
@@ -665,7 +665,7 @@ local function GetOptionsTable_Castbar(hasTicks, updateFunc, groupName, numUnits
func = function() func = function()
local frameName = E:StringTitle(groupName) local frameName = E:StringTitle(groupName)
frameName = "ElvUF_"..frameName frameName = "ElvUF_"..frameName
frameName = frameName:gsub("t(arget)", "T%1") frameName = gsub(frameName, "t(arget)", "T%1")
if numUnits then if numUnits then
for i=1, numUnits do for i=1, numUnits do
@@ -835,7 +835,7 @@ local function GetOptionsTable_Castbar(hasTicks, updateFunc, groupName, numUnits
tickColor = { tickColor = {
order = 2, order = 2,
type = "color", type = "color",
name = "COLOR", name = COLOR,
hasAlpha = true, hasAlpha = true,
get = function(info) get = function(info)
local c = E.db.unitframe.units[groupName].castbar.tickColor local c = E.db.unitframe.units[groupName].castbar.tickColor
@@ -1659,7 +1659,7 @@ local function GetOptionsTable_RaidDebuff(updateFunc, groupName)
color = { color = {
order = 4, order = 4,
type = "color", type = "color",
name = "COLOR", name = COLOR,
hasAlpha = true, hasAlpha = true,
get = function(info) get = function(info)
local c = E.db.unitframe.units.raid.rdebuffs.duration.color local c = E.db.unitframe.units.raid.rdebuffs.duration.color
@@ -1713,7 +1713,7 @@ local function GetOptionsTable_RaidDebuff(updateFunc, groupName)
color = { color = {
order = 4, order = 4,
type = "color", type = "color",
name = "COLOR", name = COLOR,
hasAlpha = true, hasAlpha = true,
get = function(info) get = function(info)
local c = E.db.unitframe.units[groupName].rdebuffs.stack.color local c = E.db.unitframe.units[groupName].rdebuffs.stack.color