Skip to content
Mike Medley edited this page May 30, 2023 · 63 revisions

IconAbout GM_config

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.

Notice:

You may be impacted by a recent change to how values are read from storage

Including GM_config in your 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.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.

Getting Started

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
...

Opening the configuration panel

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.

Accessing a field's value

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'));
    }
  }
});

Customizing GM_config

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
});

Using an element instead of an iframe

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();

Calling init() multiple times

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.

In conclusion

For real-world examples look at one of the scripts that already use GM_config. My unit test may also be of some help.