Tutorial: jMod Tutorial

jMod Tutorial

Under construction
Setup
Usage

Setup

Setup Meta Block

When loading jMod via "@require", your meta block should look something like this:

// ==UserScript==
// @name             script_name
// @namespace        http://downloadurl.com/user/user_name
// @description      script description
// @author           user_name
// @downloadURL      http://downloadurl.com/script/script_name.user.js
// @updateURL        http://downloadurl.com/script/script_name.meta.js
// @homepage         http://downloadurl.com/script/script_name
// @include          http://includeurl.com/*
// @require          http://myuserjs.org/API/0.0.16/jMod.js
// @version          0.0.1
// @grant            unsafeWindow
// @grant            GM_info
// @grant            GM_log
// @grant            GM_addStyle
// @grant            GM_getMetadata
// @grant            GM_xmlhttpRequest
// @grant            GM_registerMenuCommand
// @grant            GM_getValue
// @grant            GM_setValue
// @grant            GM_listValues
// @grant            GM_deleteValue
// @unwrap
// @noframes
// @run-at           document-start
// @jMod             {"API": {"log": {"debug": true}}}
// ==/UserScript==

The only line required is:

// @require          http://myuserjs.org/API/0.0.16/jMod.js
However, it is highly encouraged that you consider following:

Grants

Name Description
GM_info
GM_getMetadata(for scriptish)
Allows jMod to access your script info, which automates its initialization.
unsafeWindow Allows jMod to access the unsafeWindow. Without this, jMod can run into some scope and permission issues.
GM_xmlhttpRequest Allows jMod.SendMessage to access remote information from any domain. Very helpful when checking for updates.
GM_addStyle Allows jMod.API.addStyle to add CSS far faster than any other method.
GM_getValue
GM_setValue
GM_listValues
GM_deleteValue
Allows jMod to use GM storage options instead of localStorage. This is important if your userscript runs on multiple domains since localStorage settings are specific to a single domain.

Script Information

Name Description
downloadURL
jModdownloadURL
Allows jMod to find out your true myUserJS script name and username. If you are using a site like greasyfork.org that rewrites your downloadURL, add jModdownloadURLto your meta block to ensure jMod can properly parse your download URL.
updateURL
jModupdateURL
Similar to downloadURL except the URL is also parsed for the update type via its extension (meta.js, metajs.js or data.js).
jModscriptname(or jMod_script_name)
jModusername(or jMod_username)
You can also set your myUserJS script name and username by using these keys in your meta block. You can manually set these values later when your script executes, but using your meta block is the preferred method.

Other

Name Description
run-at jMod is designed to run at any time, even at start. This can be an issue for some scripts considering it will then execute before the DOM exists. However, jMod has several features to assist script authors with this problem.
see Standard Events below.
jMod This can be set to a valid JSON string, to be parsed as soon as jMod initializes. The value is processed before any changes are made to the document. Thus, if notifications or tooltips were disabled, their initializers would not execute and no document changes would be made.

Setup Script Tag

When loading jMod by adding a script tag to the document, you can use the following methods to initialize your configuration:

<script>
jMOD_CONFIGURATION = {
	API: {
		Storage: {
			engine: 'localStorage'
		}
	},
};
</script>
<script src="http://myuserjs.org/API/0.0.16/jMod.js" data-username="myUserName" data-script_name="myScriptName" Update.DOMTiming="true" data-jmod-config='{"API": {"log": {"debug": true}}}'></script>

Once again, not all of this is necessary; only the following is required to load jMod:

<script src="http://myuserjs.org/API/0.0.16/jMod.js"></script>

Attributes

You can set individual configuration values via attributes using the following format: Update.DOMTiming="true", Update-DOMTiming="true", data-Update-DOMTiming="true"


Additionally, you can pass a JSON formatted string to the attribute data-jmod-config. If valid, it will be merged with the jMod.Config object.

Configuration Variable

Alternatively, you can initialize your configuration with a global variable named jMOD_CONFIGURATION. If valid, it will be merged with the jMod.Config object.

Usage

Usage Standard Events

jMod is, by design, meant to be used by userscripts without the need for additional resources (like jQuery). So jMod handles several events for you, like waiting for the DOM to be available


// Start DOM interactions
function onDOMReadyCB(){
	console.log('onDOMReadyCB');
}
jMod.onDOMReady = onDOMReadyCB;

// jMod fully initialized
function onReadyCB(){
	console.log('onReadyCB');
}
jMod.onReady = onReadyCB;

// Page is ready
function onPageReadyCB(){
	console.log('onPageReadyCB');
}
jMod.onPageReady = onPageReadyCB;

// Page is loaded
function loadCB(){
	console.log('loadCB');
}
jMod.load = loadCB;
Any function can be added to the event stack using the following syntax:
jMod.EVENT_NAME = function(e){};
or
jMod.Events.addListener('EVENT_NAME', function(e){}, fireRecorded);
fireRecorded - Some events (like onDOMReady) record the most recent firing. If fireRecorded is true then, if there is a recorded event when adding to the stack, the callback is fired immediately with the recorded arguments. This is useful if you need the DOM but don't know if it is loaded yet.

Events Table

Order Name Arguments Description
1 onDOMReady none Fires as soon as the DOM is available.
2 onReady none Fires as soon as all the jMod resources are added and initialized. This includes anything added using jMod.CSS = 'custom css'; which stores values until the DOM is available.
3 onPageReady none Fires when document.readyState is complete.
4* onPerformanceReady none Fires when ALL the window's performance values are available. This is when you should make your update requests, and report stats to the server.
4* load event Fires when the window's load event fires.
* DOMContentLoaded event Fires when the window's DOMContentLoaded event fires.
* onreadystatechange event Fires when the window's onreadystatechange event fires.
* afterscriptexecute event Fires when the window's afterscriptexecute event fires.
* beforescriptexecute event Fires when the window's beforescriptexecute event fires.
* Fire order can be unpredictable

jMod events logged using firebug

Usage Settings

jMod has a powerful settings dialog generator built in, no need to write one yourself anymore!

Preference Types

Name Preference Features Description
input tooltip, icon
textarea tooltip, icon
select tooltip
range tooltip
checkbox label tooltip, checkbox tooltips
radio label tooltip, radio tooltips
toggle label tooltip, toggle tooltips

Settings Example

The following example utilizes most of the features jMod Settings has to offer:

var SettingsTest = function(){
	console.log('jMod.Settings Test');
	var SettingOptions = {
		title: 'Example Title',
		settings: [
			{
				name: 'Setting 1',
				description: 'Setting 1 description',
				tooltip: {
					innerHTML: 'Text input Top-Right Tooltip',
					placement: 'top-right'
				},
				icon: {
					name: 'fa-microphone',
					tooltip: {
						innerHTML: 'icon tooltip',
						placement: 'right'
					}
				},
				tab: 'Tab Name 1',
				section: 'Other',
				type: 'input',
				'default': 'foo bar'
			},
			{
				name: 'element example',
				tab: 'Tab Name 1',
				section: 'Other',
				type: 'element',
				innerHTML: [
					'Element Example: ',
					{
						type: 'img',
						attributes: {
							src: "https://assets-cdn.github.com/images/modules/logos_page/GitHub-Logo.png",
							height: "10px"
						}
					}
				]
			},
			{
				name: 'Toggle',
				description: 'Toggle Test',
				options: {
					'val1': {
						label: 'Toggle 1',
						on: 'ON',
						off: 'OFF',
						tooltip: {
							innerHTML: 'Toggle Tooltip 1',
							placement: 'right'
						}
					},
					'val2': {
						label: 'Toggle 2',
						on: 'ON',
						off: 'OFF',
						tooltip: {
							innerHTML: 'Toggle Tooltip 2',
							placement: 'right'
						}
					},
					'val3': {
						label: 'Toggle 3',
						on: 'WIDE ON',
						off: 'WIDE OFF',
						className: 'wide',
						tooltip: {
							innerHTML: 'Toggle Tooltip 3',
							placement: 'right'
						}
					},
					'val4': {
						label: 'Toggle 4',
						on: 'EX WIDE ON',
						off: 'EX WIDE OFF',
						className: 'ex-wide',
						tooltip: {
							innerHTML: 'Toggle Tooltip 4',
							placement: 'right'
						}
					}
				},
				tab: 'Tab Name 1',
				section: 'Other',
				type: 'toggle',
				'default': 'val3,val4'
			},
			{
				name: 'Setting 2',
				tooltip: {
					innerHTML: 'Select Left Tooltip',
					placement: 'left'
				},
				tab: 'Tab Name 1',
				section: 'Other',
				type: 'select',
				options: {
					'val1': 'Option 1',
					'val2': 'Option 2',
					'val3': 'Option 3',
					'val4': 'Option 4',
				},
				'default': 'val3'
			},
			{
				name: 'Setting 3',
				tooltip: {
					innerHTML: 'Textarea Top Left Tooltip',
					placement: 'left-top'
				},
				icon: {
					name: 'fa-question-circle',
					tooltip: {
						innerHTML: 'Icon Tooltip for Textarea',
						placement: 'right'
					}
				},
				style: {
					minHeight: '100px'
				},
				tab: 'Tab Name 1',
				section: 'Other',
				type: 'textarea',
				'default': 'taco'
			},
			{
				name: 'Checkboxes',
				tab: 'Tab Name 1',
				tooltip: {
					innerHTML: 'Top Label Tooltip',
					placement: 'top-left',
					margin: {
						//left: '5px'
					}
				},
				section: 'Other2',
				options: {
					'val1': {
						label: 'Checkbox 1',
						tooltip: {
							innerHTML: 'Checkbox Tooltip 1',
							placement: 'top'
						}
					},
					'val2': {
						label: 'Checkbox 2',
						tooltip: {
							innerHTML: 'Checkbox Tooltip 2',
							placement: 'top'
						}
					},
					'val3': {
						label: 'Checkbox 3',
						className: 'wide',
						tooltip: {
							innerHTML: 'Checkbox Tooltip 3',
							placement: 'top'
						}
					},
					'val4': {
						label: 'Checkbox 4',
						className: 'ex-wide',
						tooltip: {
							innerHTML: 'Checkbox Tooltip 4',
							placement: 'top'
						}
					}
				},
				type: 'checkbox',
				'default': 'val1,val3'
			},
			{
				name: 'Depend Checkbox',
				description: 'Depend on Value of Checkboxes',
				tab: 'Tab Name 1',
				section: 'Other2',
				type: 'input',
				'default': 'Depend Checkbox',
				depend: {
					'Checkboxes': ['val1', 'val4']
				}
			},
			{
				name: 'Radio',
				tab: 'Tab Name 1',
				tooltip: {
					innerHTML: 'Bottom Label Tooltip',
					placement: 'bottom-left'
				},
				section: 'Other2',
				options: {
					'val1': {
						label: 'Radio 1',
						tooltip: {
							innerHTML: 'Radio Tooltip 1',
							placement: 'bottom'
						}
					},
					'val2': {
						label: 'Radio 2',
						tooltip: {
							innerHTML: 'Radio Tooltip 2',
							placement: 'bottom'
						}
					},
					'val3': {
						label: 'Radio 3',
						className: 'wide',
						tooltip: {
							innerHTML: 'Radio Tooltip 3',
							placement: 'bottom'
						}
					},
					'val4': {
						label: 'Radio 4',
						className: 'ex-wide',
						tooltip: {
							innerHTML: 'Radio Tooltip 4',
							placement: 'bottom'
						}
					}
				},
				type: 'radio',
				'default': 'val1'
			},
			{
				name: 'Depend 1',
				description: 'Depend on Value of Radio',
				tab: 'Tab Name 1',
				section: 'Other2',
				type: 'input',
				'default': 'Depend 1',
				depend: {
					'Radio': ['val2', 'val4']
				}
			},
			{
				name: 'Depend 2',
				description: 'Depend on Value of Radio',
				tab: 'Tab Name 1',
				section: 'Other2',
				type: 'input',
				'default': 'Depend 2',
				depend: {
					'Radio': function(prefEl, data, radioValue){
						if(radioValue == 'val1')
							return true;
						return false;
					}
				}
			},
			{
				name: 'Range',
				min: 20,
				max: 567,
				tooltip: {
					innerHTML: 'Slider tooltip',
					placement: 'top',
				},
				tab: 'Tab Name 1',
				section: 'Other',
				type: 'range',
				'default': '50'
			},
			{
				name: 'Setting 6',
				tab: 'Tab Name 2',
				section: 'Other',
				type: 'input'
			},
			{
				name: 'Setting 7',
				tab: 'Tab Name 2',
				section: 'Other',
				type: 'input'
			},
		],
		tabs: [
			// (optional) Additional Custom tab
			{
				name: 'About',
				innerHTML: [
					{
						type: 'h1',
						innerHTML: 'About'
					},
					{
						type: 'p',
						innerHTML: 'about example'
					}
				]
			},
			// (optional) Adding information about a tab referenced by a setting
			{
				name: 'Tab Name 1',
				displayName: 'Tab 1 displayName',
				content: {
					footer: {
						type: 'div',
						innerHTML: 'Tab 1 Footer foo bar'
					}
				}
			}
		],
		// (optional) Change the order of the tabs. Tabs left out will be added after in the order they are referenced by your settings
		tabOrder: ['About', 'Tab Name 1'],
		// (optional) Set the active tab
		activeTab: 'Tab Name 1',
		// (optional) callback that fires before the settings dialog closes
		onBeforeHide: function(e){
			console.log('Settings on before hide');
		}
	};
	
	jMod.Settings(SettingOptions);
	
	
	setTimeout(function(){
		// Show the settings dialog
		console.log('Show jMod Settings');
		jMod.Settings.show();
		console.log('Setting 1 Value: ', jMod.Settings.get('Setting 1'));
		console.log('Setting 1 Default: ', jMod.Settings.getDefault('Setting 1'));
	},100);
		
	//setTimeout(function(){
		//var settingsNav = document.querySelector('.jMod-settings .nav-tabs');
		// Switch to Tab #1 in the settings dialog
		//jMod.Tabs.show(settingsNav, 1);
	//},2000);
};

jMod.onReady = SettingsTest;