Home

Mike Medley edited this page Nov 25, 2017 · 54 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.

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
// ==/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 GM_config can 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.init function:

GM_config.init(
{
  'id': 'MyConfig', // 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.

Opening the configuration panel

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, which in this case lets them 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.

Accessing a field's value

To gain access to their name programmatically you can use:

var username = GM_config.get('Name');

Setting the title

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

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': 'MyConfig', // The id used for this instance of GM_config
  'title': title, // Panel Title
  ...

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.

GM_config.init(
{
  '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
    }
  },
  'css': '#MyConfig_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.

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

var frame = document.createElement('div');
document.body.appendChild(frame);
GM_config.init(
{
  'id': 'MyConfig', // 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();

Creating multiple instances

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. You must use a different id value for each instance.

var gmc = new GM_configStruct(
{
  'id': 'YourConfig', // 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.

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