-
Notifications
You must be signed in to change notification settings - Fork 49
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.
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_log
// ==/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. I often like to brag that it can 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.init function:
GM_config.init(
{
'id': 'GM_config', // The id used for this instance of GM_config
'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). This call, as the name implies, initializes GM_config.
Once you have passed GM_config the information about all of your fields you can call the "open" method:
GM_config.open();
That function displays the GUI to the user, where in this case they can easily enter their name. They can also save their changed value so that when they open the GUI in the future it will display their name again. How you invoke the open method to show the GUI is completely your responsibility.
To gain access to their name programmatically you can use:
var username = GM_config.get('Name');
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. You set this title at the same time you pass your fields to init:
GM_config.init(
{
'id': 'GM_config', // 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
}
}
});
Optionally, you could also set title property to a DOM element (for instance if you want to provide a link):
// Create the title link
var title = document.createElement('a');
title.textContent = 'Script Settings';
title.href = 'https://github.com/sizzlemctwizzle/GM_config';
GM_config.init(
{
'id': 'GM_config', // The id used for this instance of GM_config
'title': title, // Panel Title
...
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.
GM_config.init(
{
'id': 'GM_config', // 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
}
},
'css': '#GM_config_section_0 { display: none !important; }' // CSS that will hide the section
});
To make functional customization possible, GM_config provides many event callbacks. Additionally, you can set the value of fields directly:
GM_config.set('Name', 'Sizzle McTwizzle');
However, although this sets the value of the field in memory, it won't save the value. You will need to call GM_config.save(). However, that function saves all field values, so if you're manually modifying several fields make sure to only call save() once.
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():
var frame = document.createElement('div');
document.body.appendChild(frame);
GM_config.init(
{
'id': 'GM_config', // The id used for this instance of GM_config
'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
}
},
'frame': frame // Element used for the panel
});
GM_config.open();
Although GM_config has now been made object oriented so that multiple instances can exist in the same scope, for simplicity and backwards compatibility a default instance is created for you. However, if you want to use multiple instances of GM_config, simply create an instance of GM_configStruct.
var gmc = new GM_configStruct(
{
'id': 'MyConfig', // You need to use a different id for each instance
'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
}
});
gmc.open();
As you can see, you can do initialization using the constructor.
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. The best example I've seen so far is probably uso - Count Issues, so go ahead and give that a look if you want to see all the crazy stuff you can do with GM_config. My unit test may also be of some help.