Fandom

Wikia Developers Wiki

Preferences

847pages on
this wiki
Add New Page
Talk5 Share

==Intro==

The number of addons here at dev is growing. And they are getting more flexible too. The more an addon's user base grows the more configuration options it accumulates. All of these options require hand-editing of the JavaScript file that embeds the addon. That's no problem as long your addon's audience consists only of people with at least basic JavaScript knowledge. When it comes to user-scripts that's probably fine for the time being. But what about site-scripts? Wouldn't it be nice to add per-user options to those as well? But the majority of users will lack access to the JavaScript source. And most of them wouldn't know how to edit it even if they had access. So what now? Simply drop the idea of per-user options? Or force the admins to edit the JavaScript source for each and every of their users?


The preferences module gives an easy answer to that. Every user gets his own Special:Scripts page where he can adjust settings in a convenient web interface. No Javascript hacking required.


Addons can have three different types of settings:

  • local settings will apply only to the wiki where Special:Scripts was called
  • global settings will apply to all wikis
  • shared settings are a special variant of global settings. Other user's addons will get read-access to them. You can use shared settings to advertise things about yourself to the community - the list of languages other community members may contact you in e.g.

==Demo==

If you want to see the Preferences module at work, you will have to install at least one addon that uses it. For demo purposes I created: w:c:preferences:MediaWiki:Demo.js. You can add it to your addon list by adding this to your global.js:

importArticles({ type: 'script', articles: 'u:preferences:MediaWiki:Demo.js' });

You will see two things:

  1. Three pseudo-addons named "Demo 1", "Demo 2" and "Demo 3". Each of them has a local and a global field. You will find the value you enter into the global field at each wiki you go. Visit Special:Scripts at a few wikis and you'll see. The local values will obviously only be visible if you return to the wiki where you set them. You can also see your data in the raw by visiting w:c:preferences:Special:MyPage/preferences.js
  2. For the shared data you will see a bit more than a demo. This is something that should become useful soon. You can set your language preferences here. To see your own and a few other early tester's language preferences go to w:c:pecoes:SharedDemo.js. To see your own data in the raw go to w:c:preferences:Special:MyPage/shared.js.



==API== The Preferences module consists of several files and exposes several classes. We need to start with the Loader:


===Loader===

This is the loader for Preferences.js. You will need to use it where ever you want to use the Preferences module:

;(function(a,b,d){function c(){var f=d.config.get("wgUserName"),g="u:preferences:",h=g+"MediaWiki:",e=[g+"User:"+f+"/preferences.js",h+"Preferences.js"];if(d.config.get("wgCanonicalNamespace")==="Special"&&d.config.get("wgTitle")==="Scripts"){e.unshift(h+"Special.js")}b.getScript("/load.php?debug=false&mode=articles&only=scripts&articles="+e.join("|"));a.defer=b.Deferred();b(function(){b('<iframe id="pref-server" src="//preferences.wikia.com/wiki/MediaWiki:Server1?action=render" style="display:none;"></iframe>').appendTo(document.body).on("load",function(){a.defer.resolve()})});a.promises=[];var i=function(j){this.addon=j;this.queue=[]};b.each(["main","form","update","post","fail"],function(j,k){i.prototype[k]=function(m,l){this.queue.push({type:k,arg1:m,arg2:l});return this}});a.addon=function(j){var k=new i(j);a.promises.push(k);return k}}if(window.postMessage&&window.JSON&&!a.addon){c()}}((window.dev=window.dev||{}).preferences=window.dev.preferences||{},jQuery,mediaWiki));

(The loader is minified. The unobfuscated version is here.)

For performance reasons it is strongly recommended not to import the loader but to copy/paste it into your addon instead. The loader itself is only 900 Bytes large. It will add a tiny bit of bloat to your script. But only a tiny bit. The performance and speed increase will be worth it.

===Two kinds of data===

The local and global preferences of the users and their shared preferences are stored in different files. That has security reasons. If a user decides to edit their preferences file by hand, he will probably trash it, but he will only ruin it for himself and for nobody else. That makes it safe to store the data as a self-executing JavaScript file (JSONP). The major advantage of this format is that the browsers' security model allows for the inclusion of scripts from any domain and thus any wiki. In other words: The local and global preferences load fast.

But what of the shared preferences? Well, they are meant to be loaded not only by their respective owners but by all interested Wikians. So if a user should make the bad decision to edit them by hand, he might be able to wreak all kinds of havoc in other users' names. If the shared preferences were loaded as a script that is. In that case they would be able to access Wikia with the same privileges as the current user.

So instead we're storing the shared data in pure (JSON) format. Pure JSON has a few disadvantages. The most important one being that that browsers do not permit loading JSON from different domains. That's the reason why the Preferences module loads an iframe. The iframe is always local to http://preferences.wikia.com/ and can access the JSON data. The iframe's script safely evaluates the data and messages it to the script in the main window. That's a little complicated. A little slower. But safe.

It's only safe from a security standpoint though. Users who fry their shared data by hand-editing it, will make all other users' shared data unreadable as well. That's because the shared files are requested simultaneusly (to reduce the number of server requests) and one read error is too much. They can still ruin it for everybody. But they will not be able to cause any harm beyond that. And you will get a warning message that should help you pinpoint the damaged file quickly.


===Two kinds of scripts===

The Preferences module has two different modes:

  1. Special:Scripts and
  2. all other pages

Both of these modes have different needs and since the Preferences module is... um... modular, scripts will find it to have different capabilities in the two contexts. So much so that I strongly recommend to split your interaction with Preferences in two scripts:

  1. the form script that generates and evaluates the form on Special:Scripts and
  2. the main script that simply reads the preferences and does with them whatever it is your addon does.

Keeping these two parts in separate scripts will help you keep the code base of your addon clean and short. You will not have to include stuff that's only needed on Special:Scripts on each and every single page. You will also keep all that messy HTML and CSS and whatnot neatly tucked away into a file of its own. But most importantly you will profit from the performance boost that comes from bulk loading those form scripts. The Preferences module will collect the names of all form scripts on startup and should be able to load the lot of them with a single importArticles statement.


===Examples===

Let's look at a simple example of a main script now and go over the code afterwards. Let's say your addon would allow the user to set a color preference for every wiki he goes to. This is what it might look like:

====Example 1====

// the loader:
;(function(a,b,d){function c(){var f=d.config.get("wgUserName"),g="u:preferences:",i=g+"MediaWiki:",e=[g+"User:"+f+"/preferences.js",i+"Preferences.js"];if(d.config.get("wgCanonicalNamespace")==="Special"&&d.config.get("wgTitle")==="Scripts"){e.unshift(i+"Special.js")}window.importArticles({type:"script",articles:e});a.server=b.Deferred();b(function(){b('<iframe id="pref-server" src="//preferences.wikia.com/wiki/MediaWiki:Server1?action=render" style="display:none;"></iframe>').appendTo(document.body).on("load",function(){a.server.resolve()})});a.prefs=[];var h=function(j){this.addon=j;this.queue=[]};b.each(["main","form","post","fail"],function(j,k){h.prototype[k]=function(m,l){this.queue.push({type:k,arg1:m,arg2:l});return this}});a.addon=function(j){var k=new h(j);a.prefs.push(k);return k}}if(window.postMessage&&window.JSON&&!a.addon){c()}}((window.dev=window.dev||{}).preferences=window.dev.preferences||{},jQuery,mediaWiki));
 
// the main script:
 
dev.preferences.addon('MyAddon')
.form('u:dev:myForm.js')
.main(function (data) {
    alert('your color preference is ' + data.local().get('color', 'white'));
});

The object that addon() returns is called a Promise and closely modelled after jQuery's Promises. Promise objects have several methods - all of which take a callback as their parameter. Each of these methods represents a process - the loading of external files eg. Once the process has finished the Preferences module "promises" to execute the callback.

The methods of Promises are commented en detail below so let's go over the basics only:

  • The addon() method expects the name of your addon as a parameter and retuns a Promise object.
  • The form() method receives the name of your form script as its parameter. The Preferences module "promises" to load and run this script if and when the current page should be Special:Scripts.
  • The main() method receives a callback as parameter and "promises" to call it once
    • the Preferences module has loaded,
    • the user's local and global preferences have loaded and
    • all requested shared preferences have loaded (more on those in the next example)
    The callback will not be executed if the current page is Special:Scripts. In fact: main() and form() are mutually exclusive. You can chain both methods in any order you like but only one of them will load and execute anything. The other will have no effect.


====local, global and shared====

Let's take a look inside the callback to main() now:

The callback receives a Main object as its parameter. The most important methods of Main objects:

  • local() returns the preferences that are local to the current wiki,
  • global() returns the preferences that are global to all of Wikia and
  • shared() returns the shared preferences of a particular user (more in the next example)

Each of these methods returns itself an object. Those objects are mediaWiki.Map objects. They look and behave exactly like mediaWiki.user or mediaWiki.config. If you're already familiar with those, you won't find many surprises here. Feel free to read about these types of objects on the MediaWiki site, but you will also find plenty of examples in the reference below.

This particular statement:

data.local().get('color', 'white')

means: Fetch the "color" preference for the current user and the current wiki and the specified addon and return "white" in case the preference was never set.

Now let's look at a variation of the first example and use the shared object instead. The shared object is a little quirky. Unlike the local and global preferences it is not loaded by default. That means you have to explicitly request it. You can request more than one shared object at once however and they will be loaded simultaneously. So let's do that. Let's compare the current users' chosen color to the chosen color of the user whose page he's visiting:


====Example 2====

// the loader again:
;(function(a,b,d){function c(){var f=d.config.get("wgUserName"),g="u:preferences:",i=g+"MediaWiki:",e=[g+"User:"+f+"/preferences.js",i+"Preferences.js"];if(d.config.get("wgCanonicalNamespace")==="Special"&&d.config.get("wgTitle")==="Scripts"){e.unshift(i+"Special.js")}window.importArticles({type:"script",articles:e});a.server=b.Deferred();b(function(){b('<iframe id="pref-server" src="//preferences.wikia.com/wiki/MediaWiki:Server1?action=render" style="display:none;"></iframe>').appendTo(document.body).on("load",function(){a.server.resolve()})});a.prefs=[];var h=function(j){this.addon=j;this.queue=[]};b.each(["main","form","post","fail"],function(j,k){h.prototype[k]=function(m,l){this.queue.push({type:k,arg1:m,arg2:l});return this}});a.addon=function(j){var k=new h(j);a.prefs.push(k);return k}}if(window.postMessage&&window.JSON&&!a.addon){c()}}((window.dev=window.dev||{}).preferences=window.dev.preferences||{},jQuery,mediaWiki));
 
// the main script:
 
dev.preferences.addon('MyAddon')
.main(['YourName', 'TheOtherGuysName'], function (data) {
    alert('your color preference is '   + data.shared('YourName').get('color'));
    alert('your host\'s preference is ' + data.shared('TheOtherGuysName').get('color'));
})
.fail(function (msg) {
    alert('something seems to have gone wrong: ', msg);
});

Here we call the main method with its optional first parameter: an array of usernames whose shared objects should be loaded. Once they're loaded and parsed the callback will be executed.

And we're also using another method of Promise objects here: fail(). Since requesting shared objects requires a slightly complicated network request there's a certain risk of failure. With fail() you can catch those errors and show a message to your users. Errors will be logged to the browser's console regardless, so using fail() is completely optional.


===Form scripts===

Form scripts are different right from the start. Instead of loading the Preferences module, they are loaded by the Preferences module:

====Example 3====

// no loader required!
 
// the form script:
var input;
dev.preferences.addon('MyAddon')
.form(function (data) {
    input = data.localTab(
        '<input value="' + data.local().get('color', 'white') + '" />' 
    ).find('input');
})
.post(function (data) {
    data.global().set('color', input.val());
});

The form() promise can also be used with a callback. The callback will be executed once:

  • the Preferences module has loaded,
  • the user's local, global and shared preferences have loaded and
  • the page has been primed and tabs can be added now.

The data parameter to form() promises is a Form object. Form objects share the local(), global() and shared() methods with Main objects and additionally offer localTab() with which you can create a local tab for your addon on Special:Scripts. There's also globalTab() of course.

There is no sharedTab() method however. Since shared objects are shared between addons, there cannot be one addon that's responsible for adding them to Special:Scripts. The code that generates the shared form is part of w:c:preferences:MediaWiki:Special.js - the third component of the Preferences module. If you would like to create a new shared property contact me and I'll add it for you.

Note that the Preferences module does not help you with the creation of your form in any way. Adding the required inputs, textareas, fieldsets, etc. is completely up to you. The Preferences module only creates the tabs and injects your HTML into them.

The return values of both localTab() and globalTab() are jQuery objects that point to their respective containers. The find() and the val() methods you see in the example above are jQuery methods.

The post() callback will be executed after the users clicks on the "Save" button and before the data is saved to the server. The post() promise is meant to give you the opportunity to evaluate your form and write the changes back into the local and global objects. The data parameter is - as with form() - a Form object .

==Reference==

===Module===

The interface of the Preferences module is a little unorthodox. Despite all of its functionality it only has a single method: addon(). Instead of interacting with the module itself, you will interact with the object addon() returns. This slightly convoluted technique is needed because the loader does little more than load the other files the module requires. All additional functionality it seems to offer is simulated. The loader pretends to contain the addon() method and it pretends to add methods to the object addon() returns. These methods don't contain any active code however. Their names and parameters are added to a queue and executed later when their actual code has loaded. That works because all of these methods take callbacks as their main parameters.


dev.preferences.addon

dev.preferences.addon(name)
this is the one method you will have to call at least once to use dev.preferences. It returns the Promise that will allow all further interaction. This method is included in the loader and thus available immediately. The parameter needs to be a string or an error will be thrown.
returns Promise
dev.preferences.addon('Example')
.main  (function () { /* ... */ })
.form  (function () { /* ... */ })
.post  (function () { /* ... */ })
.update(function () { /* ... */ })
.fail  (function () { /* ... */ });
available immediately from loader

dev.preferences.log

dev.preferences.log()
logs lots of data about the module to the console (where available):
  • the list of form scripts (if any)
  • all local and global preferences of the current user
  • all loaded shared objects (if any)
  • the state of the promises
  • all local and global Special:Script tabs (if any)
returns nothing
Despite being part of the module this method is not available immediately like addon()
available after either Promise.form() or Promise.main() have fired

===Promise objects===

Promise.main

Promise.main(callback)
executes callback after
  1. the Preferences module has loaded fully
  2. the current user's local and global preferences have loaded
  3. the iframe and the server script within it have fully loaded

The callback receives a Main object as its parameter:

dev.preferences.addon('Example')
.main(function (data) {
    // data is an instance of Main now
    data.log();
});
Promise.main(true, callback)

Promise.main(user, callback)
Promise.main(users, callback)

This useage loads the shared object of one or more users in addition to the rest of the module. executes callback after
  1. the Preferences module has loaded fully
  2. the current user's local and global preferences have loaded
  3. the iframe and the server script within it have fully loaded and
  4. the users' shared objects have loaded.

The username(s) must be a single string, an array of strings or a boolean - otherwise an Error will thrown. If the parameter is "true" the current user's shared object will be fetched.

The callback receives a Main object as its parameter.

returns Promise
As the name suggests main() is meant to be used in main scripts. Using it in a form script will have no effect. The callback will not be executed. In other words: The callback to main() is mutually exclusive with the callbacks of form() and post().
dev.preferences.addon('Example')
.main(function (data) {
    // this callback will fire on all pages but Special:Scripts
})
.form(function (data) {
    // this callback will fire on Special:Scripts only
});

You can catch problems that occurr while downloading any of the associated files with the fail() method.

dev.preferences.addon('Example')
.main([user1, user2, user3], function (data) { /*...*/ })
.fail(function (message) {
    alert(
        'something went wrong while downloading the data: ',
        message
    );
});
available immediately after the loader has executed

Promise.form

Promise.form(script)
loads and runs the specified form script if the current page is Special:Scripts. You could certainly load the script yourself, but it's recommended to let form() do the loading because it can aggregate scripts and load all of them in bulk. This useage of form() is meant for main scripts. It will work in form scripts as well. That "feature" may be removed though.
Promise.form(callback)
executes callback after:
  1. the Preferences module has loaded fully
  2. the current user's local and global preferences have loaded
  3. the iframe and the server script within it have fully loaded
  4. the current user's shared object has loaded

Note that the current user's shared object is loaded by default. You needn't request it. In fact: You cannot request it - nor any other shared object for that matter. This is a crucial difference to main(). main() may request any number of shared objects, but none - not even the current user's shared object - are loaded by default.

This useage of form() is meant for form scripts but it will also work in main scripts. It's probably useful for debugging and testing to keep main code and form code in the same file until they're done and separate them only in the end.

returns Promise
As the name suggests form() is meant to be used in main scripts. Using it in a main script will have no effect. The callback will not be executed. In other words: The callback to form() and the callback to post() are mutually exclusive with the callback of main().
dev.preferences.addon('Example')
.main(function (data) {
    // this callback will fire on all pages but Special:Scripts
})
.form(function (data) {
    // this callback will fire on Special:Scripts only
});

You can catch problems that occurr while downloading any of the associated files with the fail() method.

dev.preferences.addon('Example')
.main([user1, user2, user3], function (data) { /*...*/ })
.fail(function (message) {
    alert(
        'something went wrong while downloading the data: ',
         message
    );
});
available immediately after the loader has executed

Promise.post

Promise.post(callback)
executes callback after the user has clicked on the "Save" button on Special:Scripts, but before any data is posted to the server. This method is designed to work like the onpost event in HTML forms.

The parameter to the callback is a form object.

returns Promise
The Preference module does not evaluate your form. You will have to do that yourself. Entirely. None of the changes and inputs the user makes will be posted to the server until you explicitly change the dataset with Form.local or Form.global
var input = {};
dev.preferences.addon('Example')
.form(function (data) {
    input.local = data.localTab(
        '<input value="' + data.local().get('test') + '" />' 
    ).find('input');
})
.form(function (data) {
    input.global = data.globalTab(
        '<input value="' + data.global().get('test') + '" />' 
    ).find('input');
})
.post(function (data) {
    data.local() .set('test', input.local .val());
    data.global().set('test', input.global.val());
});

To avoid bloat only properties that clearly have a value will be saved. These are considered to be non-values:

  • undefined
  • null
  • 0
  • ""

If you must use any of these values, encapsulate them in an object of their own. The purge of empty properties goes only one level deep into the mediaWiki.Map.

available immediately after the loader has executed

Promise.update

Promise.update(callback)
executes the callback after the data has been saved by another addon or the user in the current window or another. This method is only available in main scripts and will not fire in form scripts. That means main() is effected while form() and post() are not. After this method has fired you should consider all data you have fetched with local(), global() and shared() invalid and fetch it again.
returns Promise
NOT IMPLEMENTED YET
available immediately after the loader has executed
Promise.fail(callback)
...
returns Promise
...
available immediately after the loader has executed

===Main objects===

The callbacks of the Promise object's methods receive themselves objects as parameters. It is these objects that allow you to read and manipulate the data. There are two types: Main and Form objects. They share the same prototype, so they also share most of their methods. The methods that differ between the two types are listed first.

Main objects are available to main scripts i.e. on pages other than Special:Scripts only.

Form objects are availalbe to form scripts i.e. on Special:Scrits only.


Main.save

Main.save()
saves the current user's local and global preferences to the server. It will also save the current user's shared object if loaded. This method is not available on Special:Scripts.
returns jQuery Promise
dev.preferences.addon('Example')
.main(function (data) {
    data.local().set('hello', 'world');
    data.save()
    .done(function () {
        alert('data was saved');
    })
    .fail(function (message) {
        alert('error', message);
    })
    .always(function () {
        alert('this alert will be shown either way');
    });
});
available after main() has fired

Main.local

Main.local()
fetches the user's preferences for the current wiki
Main.local(wiki)
fetches the user's preferences for the specified wiki. The name should be the same as in interwiki links - not the wgDBname which is occasionally different. Community Central e.g. has the interwiki name "community" but the wgDBname "wikicities". The interwiki name is identical with the subdomain name: http://community.wikia.com
returns mediaWiki.Map
Main.local returns a wrapper for the original data. Any change you will make to the map will be saved.
var map = data.local();
 
// fetch the property "example" from the map and
// returns null if property is not set:
example = map.get('example');
 
// fetch the property "example" from the map and 
// return "hello world" if the property is not set:
example = map.get('example', 'hello world');
 
// set the property "example":
map.set('example', 'hello world');
 
// set multiple properties without overwriting the map:
// map is: { two: 2 }
map.set({ one: 1, three: 3 });
// map is: { one: 1, two: 2, three: 3 }
 
// test if a property "example" is set:
if (map.exists('example')) { /*...*/ }
 
// the objects gets cached, so calling local()
// multiple times will yield the same object:
console.log(data.local() === data.local());
available after main() has fired

Main.global

Main.global()
fetches the user's preferences for all wikis
returns mediaWiki.Map
Main.global returns a wrapper for the original data. Any change you will make to the map will be saved.
var map = data.global();
 
// fetch the property "example" from the map and
// returns null if property is not set:
example = map.get('example');
 
// fetch the property "example" from the map and 
// return "hello world" if the property is not set:
example = map.get('example', 'hello world');
 
// set the property "example":
map.set('example', 'hello world');
 
// set multiple properties without overwriting the map:
// map is: { two: 2 }
map.set({ one: 1, three: 3 });
// map is: { one: 1, two: 2, three: 3 }
 
// test if a property "example" is set:
if (map.exists('example')) { /*...*/ }
 
// the objects gets cached, so calling global()
// multiple times will yield the same object:
console.log(data.global() === data.global());
available after main() has fired

Main.shared

Main.shared()
fetches the shared object for the current user
Main.shared(user)
fetches the shared object for the specified user; will throw an Error if user is not a string
returns mediaWiki.Map
Main.shared - unlike Main.local and Main.global - returns a clone of the original data. Only the user can modify the original shared data. You cannot. Not on Special:Scripts and not on any other page.
var map = data.shared('someUser');
 
// fetch the property "example" from the map and
// returns null if property is not set:
example = data.shared('someUser').get('example');
 
// fetch the property "example" from the map and 
// return "hello world" if the property is not set:
example = map.get('example', 'hello world');
 
// test if a property "example" is set:
if (map.exists('example')) { /*...*/ }
 
// the objects gets cached, so calling shared()
// multiple times will yield the same object:
console.log(data.shared('someUser') === data.shared('someUser'));
available after main() has fired

Main.log

Main.log()
logs the Main object to the console (where available)
returns nothing
data.log();
available after main() has fired

===Form objects===

The callbacks of the Promise object's methods receive themselves objects as parameters. It is these objects that allow you to read and manipulate the data. There are two types: Main and Form objects. They share the same prototype, so they also share most of their methods. The methods that differ between the two types are listed first.

Main objects are available to main scripts i.e. on pages other than Special:Scripts only.

Form objects are availalbe to form scripts i.e. on Special:Scrits only.


Form.localTab

Form.localTab(html)
creates a new local tab on Special:Scripts for the current addon and injects the html into it. The data will be appended to the tab should it already exist. The parameter can be a string, a DOM element or a jQuery object.
Form.localTab()
returns container
returns the container into which the HTML was injected as a jQuery object
dev.preferences.addon('Example')
.form(function (data) {
    data.localTab(
        '<input type="text" value="' + data.local().get('test') + '" />'
    );
});
available after form() has fired; only availalbe on Special:Scripts

Form.globalTab

Form.globalTab(html)
creates a new global tab on Special:Scripts for the current addon and injects the html into it. The data will be appended to the tab should it already exist. The parameter can be a string, a DOM element or a jQuery object.
Form.globalTab()
returns container
returns the container into which the HTML was injected as a jQuery object
dev.preferences.addon('Example')
.form(function (data) {
    data.globalTab(
        '<input type="text" value="' + 
            data.global().get('test') +
        '" />'
    );
});
available after form() has fired; only availalbe on Special:Scripts

Form.css

Form.css(styles)
adds css rules to the page. When using this method you can make use of the pseudo-colors listed below. The parameter must be a string, otherwise an Error will be thrown
returns Form object
see below
available after form() has fired; only availalbe on Special:Scripts
$body color of the page background
$page color of the article background
$menu color of button elements and menu
$contrast color of text in buttons or menu (either white or black)
$link color of links in article
$text color of text in article
$border color of frames, separators and other line elements
$wikia color of WikiaHeader at the top of the page
$gradient secondary color of button elements

Form.local

Form.local()
fetches the user's preferences for the current wiki
Form.local(wiki)
fetches the user's preferences for the specified wiki. The name should be the same as in interwiki links - not the wgDBname which is occasionally different. Community Central e.g. has the interwiki name "community" but the wgDBname "wikicities". The interwiki name is identical with the subdomain name: http://community.wikia.com
returns mediaWiki.Map
Form.local returns a wrapper for the original data. Any change you will make to the map will be saved.
var map = data.local();
 
// fetch the property "example" from the map and
// returns null if property is not set:
example = map.get('example');
 
// fetch the property "example" from the map and 
// return "hello world" if the property is not set:
example = map.get('example', 'hello world');
 
// set the property "example":
map.set('example', 'hello world');
 
// set multiple properties without overwriting the map:
// map is: { two: 2 }
map.set({ one: 1, three: 3 });
// map is: { one: 1, two: 2, three: 3 }
 
// test if a property "example" is set:
if (map.exists('example')) { /*...*/ }
 
// the objects gets cached, so calling local()
// multiple times will yield the same object:
console.log(data.local() === data.local());
available after form() has fired

Form.global

Form.global()
fetches the user's preferences for all wikis
returns mediaWiki.Map
Form.global returns a wrapper for the original data. Any change you will make to the map will be saved.
var map = data.global();
 
// fetch the property "example" from the map and
// returns null if property is not set:
example = map.get('example');
 
// fetch the property "example" from the map and 
// return "hello world" if the property is not set:
example = map.get('example', 'hello world');
 
// set the property "example":
map.set('example', 'hello world');
 
// set multiple properties without overwriting the map:
// map is: { two: 2 }
map.set({ one: 1, three: 3 });
// map is: { one: 1, two: 2, three: 3 }
 
// test if a property "example" is set:
if (map.exists('example')) { /*...*/ }
 
// the objects gets cached, so calling global()
// multiple times will yield the same object:
console.log(data.global() === data.global());
available after form() has fired

Form.shared

Form.shared()
fetches the shared object for the current user
Form.shared(user)
fetches the shared object for the specified user; will throw an Error if user is not a string
returns mediaWiki.Map
Form.shared - unlike Form.local and Form.global - returns a clone of the original data. Only the user can modify the original shared data. You cannot. Not on Special:Scripts and not on any other page.
var map = data.shared('someUser');
 
// fetch the property "example" from the map and
// returns null if property is not set:
example = data.shared('someUser').get('example');
 
// fetch the property "example" from the map and 
// return "hello world" if the property is not set:
example = map.get('example', 'hello world');
 
// test if a property "example" is set:
if (map.exists('example')) { /*...*/ }
 
// the objects gets cached, so calling shared()
// multiple times will yield the same object:
console.log(data.shared('someUser') === data.shared('someUser'));
available after form() has fired

Form.log

Form.log()
logs the Form object to the console (where available)
returns nothing
data.log();
available after form() has fired

==Files==


===Minification===

All of these files are minified with the YUI compressor. It's true that the MediaWiki ResourceLoader also minifies, but it doesn't obfuscate - maybe because obfuscation-on-the-fly would cause too much server processing... But obfuscation reduces the file size even further and can eek out that extra bit of speed. Obfuscation also makes the files completely unreadable and so you'll find two links for each file below. The minified version is the one you should use in your scripts and the full version is the one you can read if you like.

===Loader component===

The loader is both - a self-contained torso module and a loader for all other parts of the Preferences module Loader.js | Loader.min.js

===Main component===

This is the main module. This is where the data is processed and this is what programmers interact with. Preferences.js | Preferences.min.js

===Special component===

This is the part of the module that's only loaded on Special:Scripts. It is also the part end-users interact with. Special.js | Special.min.js

===Server component===

This is the server component that's loaded into an iframe and is thus always local to //preferences.wikia.com. The server component fetches the shared objects, saves local/global/shared objects and gives access to the localStorage at the Preferences Wiki. The server component communicates with the main component through inter-window messaging.
Server.js | Server.min.js

===Global and local preferences===

The user's global and local preferences are stored at the Preferences Wiki (w:c:preferences:) in JSONP format and follow the naming scheme: User:Name/preferences. Your own preferences are here (if it exists already)

===Shared preferences===

The user's shared preferences are stored at the Preferences Wiki as well but in a different file and in JSON format. The naming scheme is: User:Name/shared.js. Your own shared object is here (if it exists already)


Start a Discussion Discussions about Preferences

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.