-
Notifications
You must be signed in to change notification settings - Fork 48
Home
GM_config is a user script library that allows the user to edit certain saved values through a graphical settings menu. This framework was specifically designed to abstract the creation of this menu so the script author could focus more time on integrating these saved values into their script. GM_config dynamically builds its graphical interface using the DOM API, which means it doesn't contain a single string of HTML.
You may be impacted by a recent change to how values are read from storage
To include GM_config in a script use an @require
// ==UserScript==
// @name Script Name
// @namespace Script Namespace
// @require https://openuserjs.org/src/libs/sizzle/GM_config.js
// @grant GM_getValue
// @grant GM_setValue
// @grant GM.getValue
// @grant GM.setValue
// ==/UserScript==
That is all you need to use the library. However, if you're okay with using localStorage (because you are only running your script on a single domain that you also trust) to store the saved values, you can remove the @grant
lines. GM_config can actually run on an ordinary web page in a modern browser.
The basic concept of GM_config revolves around the concept of "fields". These are a collection of JSON objects that you pass to GM_config to represent values, and the information about these values, that you want GM_config to store and allow the users of your script to edit through the graphical interface. For instance, say I want the user to be able to enter their name so I can give them a personalized greeting each time they run my script. The JSON of that field would look like this:
'Name': // This is the id of the field
{
'label': 'Name', // Appears next to field
'type': 'text', // Makes this setting a text field
'title': 'Give us your name!', // Add a tooltip (hover over text)
'default': 'Sizzle McTwizzle' // Default value if user doesn't change it
}
All I have to do is pass this JSON to the GM_config constructor:
let gmc = new GM_config(
{
'id': 'MyConfig', // The id used for this instance of GM_config
'title': 'Script Settings', // Panel Title
'fields': // Fields object
{
'Name': // This is the id of the field
{
'label': 'Name', // Appears next to field
'type': 'text', // Makes this setting a text field
'default': 'Sizzle McTwizzle' // Default value if user doesn't change it
}
}
});
As you can see, all fields get passed as a collection in the fields object. You can set the label next to the field so your users know they should enter their name here. There is a "type" parameter that lets you specify to GM_config what type of data should go in this field. The field above is a simple text input, but GM_config offers many different data types (for a list of all of the supported types see the Fields page).
At the top of of the GUI window GM_config creates, there is a place where you can put some relevant title that lets the user know what this window does. Optionally, you could also set title property to a DOM element (for instance if you want to provide a link):
// Create the title link
let title = document.createElement('a');
title.textContent = 'Script Settings';
title.href = 'https://github.com/sizzlemctwizzle/GM_config';
let gmc = new GM_config(
{
'id': 'MyConfig', // The id used for this instance of GM_config
'title': title, // Panel Title
...
If you want to use multiple instances of GM_config, simply use a different id
value for each instance.
let myConfig = new GM_config(
{
'id': 'YourConfig', // You need to use a different id for each instance
...
Once you have passed GM_config the information about all of your fields you can call the "open" method:
let gmc = new GM_config(...);
gmc.open();
That function displays the GUI to the user. They can also save their changed value so that when they open the GUI in the future it will display saved values. How you invoke the open method to show the GUI is completely your responsibility.
To gain access a field's value programmatically must use an event:
let gmc = new GM_config(
{
'id': 'MyConfig', // The id used for this instance of GM_config
...
'fields': // Fields object
{
'Name': // This is the id of the field
{
...
}
},
'events':
{
'init': function () { // runs after initialization completes
// override saved value
this.set('Name', 'Mike Medley');
// open frame
this.open();
},
'save': function () { // runs after values are saved
// log the saved value of the Name field
this.log(this.get('Name'));
}
}
});
Finally, the GUI that GM_config creates is very bare bones. This is intentional since I wanted to leave it up to my users to style things to their liking. Inspect the source of the GUI and you will notice that almost every element has a class and/or unique id. To apply a custom style when the GUI is open, just pass your CSS as a string to the init method just like you did with the title above.
let gmc = new GM_config(
{
'id': 'MyConfig', // The id used for this instance of GM_config
...
'css': '#MyConfig_section_0 { display: none !important; }' // CSS that will hide the section
});
It is possible to use a block HTML element for displaying the configuration panel rather than using the standard iframe. Simply pass the element to init():
let frame = document.createElement('div');
document.body.appendChild(frame);
let gmc = new GM_config(
{
'id': 'MyConfig', // The id used for this instance of GM_config
...
'frame': frame // Element used for the panel
});
gmc.open();
It is actually possible to call init() multiple times and actually change GM_config's settings (like title, fields, css, callback functions). Anything passed to init() will replace the current values, but anything you don't pass will remain the same (except "id", always pass the same "id"). This means that you can define new fields or replace existing fields. If you want to remove a field, set it to null
. This all happens in memory, so it's best if you don't do it while the settings panel is open or you might experience unintended consequences (the easiest way to get around this is to just close and reopen the panel). You can also remove or reload fields on the config panel manually, but you'll still have to write your own code to remove/modify existing section headings (sorry, I'm too lazy to do that).
Changing the "id" can be problematic since it defines where values are stored (this also applies to changing the "id" you use in a new version of your script). Stored values will be lost if you change the "id" (obviously there are ways you can migrate these values if you know what you're doing).
So why is this useful? Well currently the best example I have of utilizing this feature is here.
For real-world examples look at one of the scripts that already use GM_config. My unit test may also be of some help.