388 lines
13 KiB
JavaScript
388 lines
13 KiB
JavaScript
/*!
|
|
@file pi.js
|
|
@brief Contains PI for base action
|
|
@author Valentin Reinbold
|
|
@copyright (c) 2021, Corsair Memory, Inc. All Rights Reserved.
|
|
*/
|
|
|
|
function PI(inContext, inLanguage) {
|
|
// Init PI
|
|
var instance = this;
|
|
|
|
var appWarningMessage = document.getElementById('app-warning-message');
|
|
var authWarningMessage = document.getElementById('auth-warning-message');
|
|
var accessButton = document.getElementById('access-button');
|
|
|
|
// Add event listener
|
|
accessButton.addEventListener("click", () => {
|
|
instance.sendToPlugin({ 'grantAccess': true });
|
|
});
|
|
|
|
// Private function to return the action identifier
|
|
function getAction() {
|
|
// Find out type of action
|
|
if (instance instanceof MutePI)
|
|
return "com.elgato.discord.mute";
|
|
if (instance instanceof DeafenPI)
|
|
return "com.elgato.discord.deafen";
|
|
if (instance instanceof VoiceChannelPI)
|
|
return "com.elgato.discord.channel.voice";
|
|
if (instance instanceof TextChannelPI)
|
|
return "com.elgato.discord.channel.text";
|
|
if (instance instanceof PushToTalkPI)
|
|
return "com.elgato.discord.pushto.talk";
|
|
if (instance instanceof PushToMutePI)
|
|
return "com.elgato.discord.pushto.mute";
|
|
if (instance instanceof VolumePI)
|
|
return "com.elgato.discord.volumecontrol";
|
|
if (instance instanceof VolumeButtonPI)
|
|
return "com.elgato.discord.volumecontrolbutton";
|
|
if (instance instanceof UserVolumeButtonPI)
|
|
return "com.elgato.discord.uservolumecontrolbutton";
|
|
if (instance instanceof UserVolumeDialPI)
|
|
return "com.elgato.discord.uservolumecontroldial";
|
|
if (instance instanceof PushToTalkTogglePI)
|
|
return "com.elgato.discord.pushtotalktoggle";
|
|
if (instance instanceof NotificationsPI)
|
|
return "com.elgato.discord.notifications";
|
|
if (instance instanceof SetAudioDevicePI)
|
|
return "com.elgato.discord.setaudiodevice";
|
|
if (instance instanceof ServerStatsPI)
|
|
return "com.elgato.discord.serverstats";
|
|
if (instance instanceof SoundboardPI)
|
|
return "com.elgato.discord.soundboard";
|
|
}
|
|
|
|
// Public function called to initialize field
|
|
this.initField = function(key) {
|
|
// Init data
|
|
updateField(key, settings[key]);
|
|
// Add event listener
|
|
document.getElementById(key).addEventListener("input", fieldChanged);
|
|
}
|
|
|
|
// Private function called to update field
|
|
function updateField(key, value) {
|
|
value = value || "";
|
|
// Update field content
|
|
document.getElementById(key).value = value;
|
|
}
|
|
|
|
// Field changed
|
|
function fieldChanged(event) {
|
|
var key = event.srcElement.id;
|
|
var value = (event ? event.target.value : undefined);
|
|
// Update data
|
|
updateField(key, value);
|
|
// Update settings
|
|
settings[key] = value;
|
|
instance.saveSettings();
|
|
}
|
|
|
|
// Public function called to load the fields
|
|
this.load = function (data) {
|
|
if (data.disabled) {
|
|
// Show app warning message
|
|
appWarningMessage.style.display = "block";
|
|
authWarningMessage.style.display = "none";
|
|
}
|
|
else if (data.unauthorized) {
|
|
// Show auth warning message
|
|
appWarningMessage.style.display = "none";
|
|
authWarningMessage.style.display = "block";
|
|
}
|
|
else {
|
|
// Hide warning messages
|
|
appWarningMessage.style.display = "none";
|
|
authWarningMessage.style.display = "none";
|
|
}
|
|
}
|
|
|
|
// Public function to send data to the plugin
|
|
this.sendToPlugin = function (inData) {
|
|
sendToPlugin(getAction(), inContext, inData);
|
|
};
|
|
|
|
// Public function to save the settings
|
|
this.saveSettings = function () {
|
|
saveSettings(inContext, settings);
|
|
};
|
|
setTimeout(()=>this.saveSettings(), 1000);
|
|
|
|
/* --- Localization --- */
|
|
|
|
this.localization = {};
|
|
|
|
var finished = false;
|
|
loadLocalization(inLanguage);
|
|
loadLocalization("en");
|
|
|
|
function loadLocalization(language) {
|
|
getLocalization(language, function(inStatus, inLocalization) {
|
|
if (inStatus) {
|
|
instance.localization[language] = inLocalization['PI'];
|
|
|
|
if (!finished) {
|
|
finished = true;
|
|
}
|
|
else {
|
|
instance.localize(function (key) {
|
|
// Actual localization
|
|
var value = instance.localization[inLanguage][key];
|
|
if (value != undefined && value != "") {
|
|
return value;
|
|
}
|
|
// Default localization
|
|
value = instance.localization["en"][key];
|
|
if (value != undefined && value != "") {
|
|
return value;
|
|
}
|
|
return key;
|
|
});
|
|
}
|
|
}
|
|
else {
|
|
console.log(inLocalization);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Localize the UI
|
|
this.localize = function (tr) {
|
|
// Check if localizations were loaded
|
|
if (instance.localization == null) {
|
|
return;
|
|
}
|
|
|
|
// Localize the warning message select
|
|
document.getElementById("app-warning").innerHTML = tr("AppWarning");
|
|
document.getElementById("auth-warning").innerHTML = tr("AuthWarning");
|
|
document.getElementById("access-label").innerHTML = tr("AccessLabel");
|
|
document.getElementById("access-button").innerHTML = tr("AccessButton");
|
|
|
|
const nodes = document.getElementsByClassName('translated');
|
|
for(const node of nodes){
|
|
const text = node.getAttribute("x-text");
|
|
//if(text){
|
|
// If the node has a dummy span child, we need to recreate it
|
|
let hasSpan = false;
|
|
const spans = node.getElementsByTagName("span");
|
|
if(spans.length > 0){
|
|
hasSpan = true;
|
|
}
|
|
|
|
const translated = tr(text);
|
|
node.innerHTML = translated ? translated : text;
|
|
|
|
if(hasSpan){
|
|
node.prepend(document.createElement("span"));
|
|
}
|
|
//}
|
|
}
|
|
};
|
|
|
|
// Load the localizations
|
|
function getLocalization(inLanguage, inCallback) {
|
|
var url = "../" + inLanguage + ".json";
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open("GET", url, true);
|
|
xhr.onload = function () {
|
|
if (xhr.readyState == XMLHttpRequest.DONE) {
|
|
try {
|
|
data = JSON.parse(xhr.responseText);
|
|
var localization = data['Localization'];
|
|
inCallback(true, localization);
|
|
}
|
|
catch(e) {
|
|
inCallback(false, 'Localizations is not a valid json.');
|
|
}
|
|
}
|
|
else {
|
|
inCallback(false, 'Could not load the localizations.');
|
|
}
|
|
};
|
|
xhr.onerror = function () {
|
|
inCallback(false, 'An error occurred while loading the localizations.');
|
|
};
|
|
xhr.ontimeout = function () {
|
|
inCallback(false, 'Localization timed out.');
|
|
};
|
|
xhr.send();
|
|
}
|
|
this.setAndValidateField = function(input, key, value){
|
|
if(!input || !input.type){
|
|
return;
|
|
}
|
|
if (value === undefined){
|
|
value = settings[key];
|
|
}
|
|
|
|
switch(input.type){
|
|
//case "range": case "select-one":
|
|
case "radio": case "checkbox":
|
|
break;
|
|
case "range":
|
|
input.value = parseInt(value);
|
|
if( input.value != settings[key]){
|
|
settings[key] = parseInt(input.value);
|
|
}
|
|
break;
|
|
default:
|
|
input.value = value;
|
|
if( input.value != settings[key]){
|
|
settings[key] = input.value;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
this.addSliderTooltip = function (slider, textFn) {
|
|
if (typeof textFn != "function"){
|
|
textFn = (value)=>{
|
|
return value;
|
|
}
|
|
}
|
|
const adjustSlider = slider;
|
|
const tooltip = document.querySelector('.sdpi-info-label');
|
|
|
|
// Add clickable labels
|
|
const parent = slider.parentNode;
|
|
if (parent){
|
|
const clickables = parent.getElementsByClassName("clickable");
|
|
for( const clickable of clickables){
|
|
const value = clickable.getAttribute("x-value");
|
|
if (value){
|
|
clickable.addEventListener('click', (event)=>{
|
|
slider.value = value;
|
|
let ev = new Event("change", { "bubbles": true, "cancelable": true });
|
|
slider.dispatchEvent(ev);
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
tooltip.textContent = textFn(parseFloat(adjustSlider.value));
|
|
|
|
const fn = () => {
|
|
const tw = tooltip.getBoundingClientRect().width;
|
|
const rangeRect = adjustSlider.getBoundingClientRect();
|
|
const w = rangeRect.width - tw / 2;
|
|
const percnt = (adjustSlider.value - adjustSlider.min) / (adjustSlider.max - adjustSlider.min);
|
|
if (tooltip.classList.contains('hidden')) {
|
|
tooltip.style.top = '-1000px';
|
|
} else {
|
|
tooltip.style.left = `${rangeRect.left + Math.round(w * percnt) - tw / 4}px`;
|
|
tooltip.textContent = textFn(parseFloat(adjustSlider.value));
|
|
tooltip.style.top = `${rangeRect.top - 30}px`;
|
|
}
|
|
}
|
|
|
|
if (adjustSlider) {
|
|
adjustSlider.addEventListener(
|
|
'mouseenter',
|
|
function() {
|
|
tooltip.classList.remove('hidden');
|
|
tooltip.classList.add('shown');
|
|
fn();
|
|
},
|
|
false
|
|
);
|
|
|
|
adjustSlider.addEventListener(
|
|
'mouseout',
|
|
function() {
|
|
tooltip.classList.remove('shown');
|
|
tooltip.classList.add('hidden');
|
|
fn();
|
|
},
|
|
false
|
|
);
|
|
|
|
adjustSlider.addEventListener('input', fn, false);
|
|
}
|
|
}
|
|
|
|
// function called to empty the field options
|
|
this.emptyField = function (key) {
|
|
var options = document.getElementsByClassName(key);
|
|
while (options.length > 0) {
|
|
options[0].parentNode.removeChild(options[0]);
|
|
}
|
|
}
|
|
|
|
this.updateName = function(settingsField, nameField, node){
|
|
if (settings[settingsField] && node.selectedIndex >= 0){
|
|
// Ensure we actually have a nick for the user
|
|
let selectedOption = node.options[node.selectedIndex];
|
|
if (selectedOption){
|
|
settings[nameField] = selectedOption.innerText;
|
|
}
|
|
}
|
|
}
|
|
|
|
/** function called to load the field options
|
|
* @param {{key: any, value: any}} defaults
|
|
*/
|
|
this.loadField = function(key, list, defaults) {
|
|
// Remove previously shown options
|
|
this.emptyField(key);
|
|
|
|
if(Array.isArray(list)){
|
|
const newList = {};
|
|
for(const item of list){
|
|
if(item && item.id){
|
|
newList[item.id] = item;
|
|
}
|
|
}
|
|
list = newList;
|
|
}
|
|
|
|
if(defaults !== undefined){
|
|
if (typeof list !== "object"){
|
|
list = {};
|
|
}
|
|
if(defaults.value){
|
|
list[defaults.key] = {name: defaults.value};
|
|
}
|
|
}
|
|
|
|
// If there is no element
|
|
if (list == undefined || Object.keys(list).length == 0) {
|
|
// Show & Select the 'Nothing' option
|
|
document.getElementById('no-' + key).style.display = "block";
|
|
document.getElementById(key).value = 'no-' + key;
|
|
return;
|
|
}
|
|
|
|
// Hide the 'Nothing' option
|
|
document.getElementById('no-' + key).style.display = "none";
|
|
|
|
// Sort the elements alphabatically
|
|
var IDsSorted = Object.keys(list).sort((a, b) => {
|
|
return list[a].name.localeCompare(list[b].name);
|
|
});
|
|
|
|
// Add the options
|
|
IDsSorted.forEach(id => {
|
|
var option = "<option value='" + id + "' class='" + key + "'>" + list[id].name + "</option>";
|
|
document.getElementById('no-' + key).insertAdjacentHTML("beforebegin", option);
|
|
});
|
|
|
|
// If no existing element configured
|
|
if (settings[key] == undefined || !(settings[key] in list)) {
|
|
// If a default wasn't provided
|
|
if (!defaults || !defaults.key){
|
|
// Choose the first option in the list
|
|
settings[key] = IDsSorted[0];
|
|
}
|
|
else {
|
|
// Choose the default option
|
|
settings[key] = defaults.key;
|
|
}
|
|
this.saveSettings();
|
|
}
|
|
|
|
// Select the currently configured element
|
|
document.getElementById(key).value = settings[key];
|
|
}
|
|
}
|