Gadget kitchen/January 2012 training

Gadget tutorial: notes for Brion Vibber's tutorial at the SF Hackathon, 21 Jan 2012 '''Please feel free to improve formatting or add links, but please do not significantly change the structure of this document or add or remove sections. It's meant for the students to see so they can follow along with Brion.'''

One of our core values: You can customize the software to do what you want. MediaWiki is FLOSS but runs on a server, so you can't change it directly. But really MediaWiki is two programs: And you can easily modify the latter. A user script is similar to a Greasemonkey extension for Firefox. It is an extension that lets you write clientside JavaScript which will be loaded after the website finishes loading, thus allowing your script to alter the page. It's personal: it only runs for users that install or enable it. But you don't need browser additions to add JavaScript customizations, because we have provided a place in MediaWiki itself for you to plug things in. Check out this intro page on User Scripts and Gadgets: http://www.mediawiki.org/wiki/Gadget_kitchen
 * serverside in PHP
 * clientside in HTML/JS

Definitions
There are 3 ways to insert additional JavaScript into the system.
 * 1) A user script just belongs to you as a user
 * We let you do anything you want.
 * Anything you can do in JS
 * No security concerns. Only runs as you.
 * No one else automatically gets that script, except by copying your userscript page.
 * "you can XSS yourself"


 * 1) A gadget belongs to anyone who enables it in their user preferences.
 * Gadgets must be enabled by an admin
 * Wikipedia has a vetting process for which gadgets are available.


 * 1) The siteJS is located at MediaWiki:Common.js
 * Affects everyone. Runs automatically for logged-in users.
 * Only the administrators of that wiki can change its Common.js
 * A lot of the time, extra tools are added to the sidebar through siteJS

A gadget is shared among multiple users. For example, if you log in to mediawiki.org and go to your user preferences, and click the Gadgets tab, look at those options with checkboxes. Sometimes people will write a user script to prototype it for a gadget or the Site JS. Explain here that all these things are just executing JavaScript on the client side. They're all ways of doing the same thing.
 * Question: Can I write a gadget and make that run, on my wiki, for anon logged-in users?
 * Yes, but it is not as simple as it should be. You  have to include the code for that gadget in the global site JS.  But  Gadgets is being rewritten.  Ask Roan outside this room about the future  of gadgets, which will make certain things easier.

How to Write A User Script

 * Go to
 * https://www.mediawiki.org/wiki/Gadget_kitchen


 * Pull up mediawiki:tutorial-quickrc.js (a tutorial for user scripts that has been sitting around for a while)
 * http://www.mediawiki.org/wiki/MediaWiki:Tutorial-QuickRC.js
 * TODO: ADD SCREENSHOTS HERE


 * Log in to mediawiki.org; create a user account if you haven't already.
 * Go to your preferences and click the Gadgets tab.
 * Let's turn on Code Editor, which Brion wrote.
 * Now, go to Appearance tab in preferences
 * Shared CSS/JS for all skins, click the link for Custom JavaScript.
 * Now you are editing User:You/common.js which is just a wiki page like any other. We turned on code editor gadget, so we have line numbers, syntax highlighting.
 * LET'S PROVIDE A SAMPLE THING TO TYPE IN.

or try to change title or background color.
 * Just hit save and then that thing will happen.

Messing with jQuery

 * We also have jQuery!
 * $('#content').css('border', 'solid 10px red');


 * In Gadget Kitchen, do these steps:
 * https://www.mediawiki.org/wiki/Gadget_kitchen#I_want_to_try.21
 * Notice that we still have the border on the page. Refresh and the border is gone.
 * Sample code adds a link to the toolbox section on sidebar. Click it and it pops up dialog box with list of recently changed pages. This shows and does several things: adds to UI, makes interactive, uses MediaWiki REST API.
 * Take a look at  and similar functions.  These functions are what MW itself uses and you can use them too.  Anything in mw.* namespace should be reliable for future versions.  Now, tells our JS module system, have you loaded  jquery.ui.dialog plugin to make dialogs?  If not, please load it.
 * To find out what modules are available, um, there may not be a good list yet. Look at https://svn.wikimedia.org/viewvc/mediawiki/trunk/phase3/resources/Resources.php?view=markup.
 * More documents are at https://www.mediawiki.org/wiki/Gadget_kitchen#Where_can_I_find_more_docs.3F and https://www.mediawiki.org/wiki/ResourceLoader and https://www.mediawiki.org/wiki/API:Main_page
 * TODO: DKinzler: would be awesome if mw.* would be self-descriptive. mw.help .... or documentation!

How our JavaScript/jQuery calls work
"Hope you like closures! You're gonna use them a lot!" There's a list of modules to load, and a function to run when it's loaded. You don't have to worry about module load order. We have straightforward code in here - jQuery, jqueryui dialog plugin, tell it string & size, contents, it makes a dialog. jQuery.getJSON loads things from our web api. There are standard jQuery functions for doing http fetch of JSON data. We use a little mw.util function called wikiscript that gives us location of API endpoint. (There are easier ways to do this in 1.19 coming up that encapsulate API access stuff. MW 1.19 will be out in March probably.) Sample code: there are some parameters, function returns your data, goes through that, build some stuff.

Using our Web API
Now, look at web API help. This gives you all the modules, parameters, sample links.
 * Start with https://www.mediawiki.org/wiki/API:Main_page
 * Then: https://en.wikipedia.org/w/api.php
 * Also check out the query sandbox: https://en.wikipedia.org/wiki/Special:ApiSandbox Tells you what an API call would look like. (Coded by Max Semenik)  Good for:
 * "I wanna do some query that pulls this data, not sure how to do it."

Sample

 * Idea: query, fetch all pages.
 * Hit Make Request button. This is the JSON we get back.

Back to the tutorial JS
At the end here is our ready function. jQuery's .ready waits to do stuff until the page is fully initialized. THEN go through and add links. utility function:  which is kind of cryptic, but documented (hopefully) over on https://www.mediawiki.org/wiki/ResourceLoader/Default_modules (which unfortunately does not tell you which portals exist).
 * TODO: improve Default modules docs.

Standard jQuery code at the end of the new common.js ... add an event that calls our code.

Ideas for exercises

 * More elaborate: try to localise this!
 * (idea: localise? because what about cross-loading JS?  too advanced for this)
 * Change the query re the sidebar popup.

Make it a tab!
How do I make a tab? Look at your user JS in User:(you):Common.js. Look in the default modules. AddPortletLink. call - changed destination parameter -- Change from the toolbar  to a tab   and hit Save. "Quick changelog" now shows up in dropdown near the searchbox. Now let's try replacing that with  and hit Save -- and now it is a tab near the Edit etc.
 * On line 75 of common.js.
 * Reminder: use Firebug! or dev tools in chrome or safari.

Exercise idea
Can we add another web API call? Page history of the page you're on. So let's go back to our code in common.js and change the query we make -- line 47, 'prop': 'revisions'; and rvprop is comment
 * Back to API sandbox.
 * format=json is what you always want.
 * action=query
 * prop=revisions
 * rvprop = comment
 * titles=Main Page     ## example
 * 'titles': mw.config.get('wgPageName'); ### should be documented somewhere in here.
 * separate plurals by vertical bar
 * If you have a JS console like firebug, run the little snippets!
 * instead of query=recentchanges, we now have query=changes (change line 54 as well)
 * array is indexed by pageid,so you need to find the pageid to get the other ones.
 * TODO: Brion to pretest this particular change.

Next exercise:

Show how to turn this into a gadget
Look at a Special:Gadgets page such as https://en.wikipedia.org/wiki/Special:Gadgets. This is a list of gadgets. Look at definitions. Anyone can see this page. You have to be an admin to edit it. On our wikis, you have to be an admin to edit this. To turn your US into a gadget: Q: What's the protocol for turning my US into an en.wp gadget? Answer: Look at https://en.wikipedia.org/wiki/Wikipedia:Gadget ''A note to future presenters: ensure that students do more typing, less copy-pasting! Take the basic bits in part by part.'''
 * There is a defn file that is a little list. You can define mult sections. Each line is a single item.
 * example: CodeEditor. Name, compat with RL, needs to load this module, and then actual page file.
 * Go to Gadget-Codeeditor.js -- you see where it loads it from Toolserver.org where its actual code lives.
 * you find admins, say you want to set something up as a gadget. They can copy your gadget into a gadget definition.
 * "Proposal" is active, "Evaluation" is not.
 * Tell Sumana so she can help you move forward in the process.