Skip to content
This repository has been archived by the owner on Jun 15, 2019. It is now read-only.

Toolbox module notes

creesch edited this page Dec 18, 2014 · 4 revisions

Execution Flow

var TB in tbmodule.js is the core extension object. It contains all methods (or at least references to them) and data needed to run the extension. It gets initialized right after var TBUtils, and includes a reference to TBUtils (TB.utils).

Module Creation

An extension is created by creating a new instance of the TB.Module object. You must pass in a full proper name, in Title Caps, e.g. var modButton = new TB.Module('Mod Button'); (and you must use the new keyword). By default, this full name is used to derive a short name (Module.shortname) with whitespace stripped, which is used in numerous places to identify the module, including as the module key in calls for settings and storage. This short name can be manually set to something different, simply set `Module.shortname = 'NewShortName'. Please don't do this; just make the names match, including capitalization.

You then create all of that extension's functions, data attributes, etc. as properties of the new TB.Module object instance. The execution entry point into the module is called init(); this is what gets called if the module is enabled. For basic porting, it should be possible to simply stick a module's existing code into the new module structure's init(), and then helper functions and such can be ported over as time permits.

Once you're done (at the end of the module's file), you call TB.register_module(<moduleName>) to add that module object to the extension, e.g. TB.register_module(modButton);. Module init order is stored in TB.moduleList, which is updated in order of registration. It is theoretically possible to modify the order of this list, but no method has been implemented to do so in a safe manner at the module level.

TB.init()

The very last file that gets run in the extension needs to be tbobjectinit.js. This should come last in the lists of files in manifest.json and main.js. All it contains is TB.init();, which calls the extension initializer. At this point, all that does is go through all the registered modules (in order of TB.moduleList) and call each module's init() function, subject to a few conditions.

TB.init() checks each module's configuration flags (set in Module.config) before running it. This includes whether the module is a beta or developer mode-only module. It also has a flag for whether the module needs access to TB.utils.mySubs, in which case it wraps the module's init() in a call to TB.utils.getModSubs().

I recommend against putting any extension logic into the Toolbox object, or into TB.init(). /u/agentlame is planning to split our core functionality out of notifier.js, into core.js, which should behave like a normal module.

Settings

A module's settings allows us to specify a single default value, which is then picked up by the Module.setting() convenience method. You can also specify that a given setting should only be shown in beta mode (and/or developer mode, whatever that means), that a setting should be hidden altogether, what the text that goes next to the setting input should say, and what type of data it contains (which impacts how it's parsed and what <input> type is generated. At a minimum, every module has at least a setting called "enabled", example:

        "enabled", { // this one serves as an example as well as the absolute minimum setting that every module has
            "type": "boolean", 
            "default": false,
            "betamode": false, // optional
            "hidden": false, // optional
            "title": "Enable " + this.name + "."
        }

You don't need to specify this setting, and you probably shouldn't change any of its values :P except to set the module enabled by default.

By default, a TB.Module instance is configured with the beta flag, which means it won't show up at all unless beta mode is enabled. You can change this simply by setting Module.config["betamode"] = false; as it's just a safety feature to prevent unfinished modules from somehow ending up in the regular user's vicinity. Module.config["debugmode"] is currently tied to Toolbox's debug mode, which may or may not make sense and is subject to change.

To let a module know about a setting, simply call Module.register_setting(); the first argument is the name, the second argument is an object as above.

Best practice is to use the Module.setting() convenience method, which should allow you to write this.setting('name', value) inside a module and not have to worry about the module's key or the setting's default value. Check out tbmodule.js:173 for the definition; it's really important that you get the module's name correct so that Module.shortname matches the module's key in LocalStorage. If it doesn't, you can override Module.shortname in your module with the correct value, e.g. modButton.shortname = 'ModButton';.

Settings Injection

TB.injectSettings() handles the automatic generation of settings dialogs, including their save handlers, for the Toolbox Settings dialog. It gets called in modbar.js when the Toolbox Settings dialog is generated, loops through a module's registered settings, and generates the settings <input> elements along with a click event handler which, using some jQuery magic provided by jQuery.bindFirst(), parses and saves the injected settings from new modules before the page is reloaded by modbar.js upon settings save.

Here, again, the order of settings is not guaranteed (why JS doesn't have an ordered dict type object is beyond me...), so I'm planning to rewrite that.

Module Structure, Conventions

A module's main code, to be called on page load, should be placed in Module.init(). Other helper methods specific to that module can be created as properties of the module alongside Module.init(). There are a few reserved names here: Module.name, Module.shortname, Module.settings, Module.settingsList (which contains the order for a module's settings), Module.config, and Module.setting.

Module.settings is an array of settings keyed on the setting name. The setting name should match the key used in localstorage. See above for a description of each setting.

Module.setting() is a convenience method which uses the module's shortname and setting default values to make it easier to write settings calls; it just wraps TB.utils.getSetting() and setSetting() (which alias to TBUtils) so you don't have to write the module name and the setting's default value every time.

Module.name and Module.shortname are pretty self-explanatory.

Module.init() gets called on page load if the module should be run (if it's enabled and beta settings are correct). Stick your main code in here.

UI Generators

UI generators and utility methods are stored in TB.ui (aka TBui, from tbui,js). Currently there are three generator methods:

TB.ui.popup() generates popup dialogs (with optional tabs) like the Mod Button, User Tagger, etc. See those modules for usage examples.

TB.ui.overlay() generates window overlays (with optional tabs) like used in config.js for subreddid toolbox settings.

TB.ui.selectMultiple() generates a generic multiple selection UI with two dropdown menus, like the one in Mod Button.

A more comprehensive explantion of all generators and utility methods can be found on the TBui function class page.