I have written a userscript for a particular webpage, and this script has some variables that I would like to be modifiable by the user, without them having to edit the script by hand such that the variables survive script updates.
Currently I am injecting a new <form>
into the existing settings page of the website with the appropriate inputs and a <button>
to trigger an injected function of which should run GM_saveValue
with a value extracted from the form.
The problem is that this script/function isn't able to access GM_saveValue
as that only exists in the scope of the TM script itself, hence I cannot actually save the settings. The rest of the code is fine, except this problem.
I have also tried defining the function inside of the userscript instead of injecting it in a <script>
tag, but this has much the same problem that the page itself is unaware of this function due to it being in TM's scope.
Is there a way to either make GM_setValue
accessible to the script that is injected into the page, or to make the button on the page able to access the function in the Userscript?
Option 1, inject a script tag:
let custom_settings_section = document.createElement('section');
let settings_script_tag = document.createElement('script');
settings_script_tag.text = `
function qol_saveCustomVariables() {
GM_setValue("custom_currency", document.querySelector('qol_custom_currency').value); // GM_setValue is unavailable in this scope.
document.querySelector('qol_save_success').style.display = "block";
}
`;
main_content.appendChild(settings_script_tag);
custom_settings_section.innerHTML = `
</script>
<h3>Ch4rl1e's QoL Settings</h3>
<form onsubmit="return false">
<p>Custom Currency Symbol: <input id="qol_custom_currency" type="string" name="qol_custom_currency" value=${custom_currency}></p>
<button onclick=qol_saveCustomVariables()>Save</button>
<p id="qol_save_success" class="alert alert-success" style="display: none;">Saved!</p>
</form>
`;
Option 2 define function in userscript:
let main_content = document.querySelector("#rightcolumn");
let custom_settings_section = document.createElement('section');
function qol_saveCustomVariables() { // the button injected into the page cannot "see" this function
GM_setValue("custom_currency", document.querySelector('qol_custom_currency').value);
document.querySelector('qol_save_success').style.display = "block";
}
custom_settings_section.innerHTML = `
<h3>Ch4rl1e's QoL Settings</h3>
<form onsubmit="return false">
<p>Custom Currency Symbol: <input id="qol_custom_currency" type="string" name="qol_custom_currency" value=${custom_currency}></p>
<button onclick=qol_saveCustomVariables()>Save</button>
<p id="qol_save_success" class="alert alert-success" style="display: none;">Saved!</p>
</form>
`
main_content.appendChild(custom_settings_section);
Solved
By creating the submit button "properly" (e.g. with document.createElement
) and then registering an eventListener for "click", and putting the relevant functionality inside of that, it works!
let main_content = document.querySelector("#rightcolumn");
let custom_settings_section = document.createElement('section');
custom_settings_section.innerHTML = `
<h3 id="qol">Ch4rl1e's QoL Settings</h3>
<form onsubmit="return false">
<p id="qol_save_success" class="alert alert-success" style="display: none;">Saved!</p>
<p>Custom Currency Symbol: <input id="qol_custom_currency" type="string" name="qol_custom_currency" value=${custom_currency}></p>
</form>
`;
var custom_settings_save_button = document.createElement('button');
custom_settings_save_button.class = "btn btn-primary";
custom_settings_save_button.innerHTML = "Save";
custom_settings_save_button.addEventListener("click", () => {
GM_setValue("custom_currency", document.querySelector('#qol_custom_currency').value);
document.querySelector('#qol_save_success').style.display = "block";
});
custom_settings_section.appendChild(custom_settings_save_button);
main_content.appendChild(custom_settings_section);
}
(I did also move the div
that reports a success message but it should be possible to insert the button between the form and said div, it's more work)