Wikipedia:WikiProject User scripts/Techniques

From Wikipedia, the free encyclopedia

Shortcut:
WP:WPUS/T

This page will collect various techniques for achieving common tasks needed in writing user scripts. Discussion about limitations, relative portability, and speed of the various alternatives is strongly encouraged. There is a lot of duplication and non-optimal efforts out there, and this will hopefully encourage us to write tighter, more correct code, both easier and faster.

An advanced API for interacting with Wikipedia content is being developed, large parts of which are already operational. The various possibilities are described at mw:API. The idea is to send an AJAX request (see below) to the API containing a query. The result of this query can be returned in several formats, of which JSON is perhaps the most useful, see below.

Contents

[edit] Identifying the type of page

This refers to techniques for identifying the current namespace of the current page, whether or not it is an edit page, a preview page, a Special page, etc.

[edit] Preview pages

document.getElementById("wikiPreview")

[edit] Edit pages

document.getElementById("editform")

This will be null when not editing a page.

[edit] History pages

wgAction === 'history'

[edit] Special pages

wgNamespaceNumber === -1

[edit] Pages with history

document.getElementById('ca-history')

[edit] Editable pages

document.getElementById('ca-edit')

Be advised that this also returns the edit tab if you're currently editing the page.

[edit] Getting various parts of a page

[edit] Getting the page title and namespace

  • wgCanonicalNamespace contains the name of the namespace, e.g. "".
  • wgCanonicalSpecialPageName is normally false but for special pages it contains the non-localized name.
  • wgNamespaceNumber is 0 for the main namespace, -1 for special pages, and other values for other namespaces.
  • wgPageName is the article name as it is shown on the url, e.g. "Kumano_Kodō". It includes the namespace identifier.
  • wgTitle is the title of the article, without namespace identifier or escaping, e.g. "Kumano Kodō".

[edit] Getting the various toolbars (personal, tabs, sidebar)

var tabs = document.getElementById(BAR NAME).getElementsByTagName('ul')[0];
  • Where BAR NAME is one of the following strings:
    'p-cactions' 
    the tabs at the top of the page (with the article, discussion, edit, history, move, and watch links)
    'p-personal' 
    the personal toolbar (i.e. the one at the top, with a link to user page, user talk, prefs, watchlist, contribs, log out)
    'p-navigation' 
    the navigation toolbar (i.e. Main page, Featured Content, etc.)
    'p-interaction' 
    the interaction toolbar, below the navigation toolbar
    'p-tb' 
    the toolbox (What links here, Related changes etc.)
  • This gets the toolbar in a form that can be the first arg to Wikipedia:WikiProject User scripts/Scripts/Add LI link

TODO: Someone please test the search and toolbox ones, and see if they work the same. Thanks!

The search box is 'p-search' but there's no <ul> element in it. [ælfəks] 10:38, 24 June 2006 (UTC)
The search box can be retrieved by simply replacing the 'ul' in getElementsByTagName('ul') with 'div', as all the toolboxes' ids are in div tags. Extremecircuitz (Talk | Userboxes page) 20:17, 21 October 2007 (UTC)

[edit] Inserting content

document.getElementById("content").insertBefore(document.createTextNode("abcdef"), document.getElementsByTagName("h1")[0])
  • On a page with a h1 heading, this works in Firefox 1.0.4 on OSX, but fails on some other browsers. Anyone know how or why? JesseW 20:58, 29 August 2005 (UTC)
  • No, but does it help if you delay execution until the page has loaded? Lupin|talk|popups 12:14, 4 October 2005 (UTC)

[edit] Pressing buttons

document.editform.wpDiff.click()
  • Presses the diff button.

[edit] Accesskeys and link titles

Things to add, modify and remove accesskeys and link titles for list items with an id tag.

[edit] Add accesskey and title

ta['ca-purge'] = ['g', 'Purge the internal cache for this page'];

[edit] Disabling accesskeys and titles

ta['pt-logout'] = null;

[edit] Update accesskeys and titles

akeytt();

[edit] Altering existing interface links

To change the url, name, or any other aspect of existing tab buttons, personal bar links, or other links, use the following: (where id is the id of the link to be changed, e.g. "pt-preferences", "ca-edit", "n-portal" or "t-whatlinkshere"; url is the new URL, and name is the new displayed name for the link, e.g. "my preferences", "edit this page", "Community Portal", or "What links here")

document.getElementById(id).childNodes[0].href=url
q=document.getElementById(id).firstChild; q.removeChild(q.firstChild); q.appendChild(document.createTextNode(name)) 

[edit] Onload Structure

wikibits.js contains a function called addOnloadHook() that attaches functions to the onLoad event:

addOnloadHook( myFunction );

Functions can also be written inline as

addOnloadHook( function() {
    // Code here
} );

Do not assign window.onload to a function directly, as this overwrites any other onLoad functions that may have been previously set.

Note: This technique can cause an error message in some situations. If you need the whole page to be loaded when your hook executes, try:

hookEvent("load", myHookFunction);

[edit] Include an external js-file on wikipedia

wikibits.js contains the Javascript function importScriptURI() and importStylessheetURI(), which allow you to import any external Javascript or CSS file that you want.

importScriptURI("http://meta.wikimedia.org/w/index.php?title=MediaWiki:Wikiminiatlas.js&action=raw&ctype=text/javascript&smaxage=21600&maxage=86400")

[edit] AJAX

If you want to read the content from a webpage from JavaScript, and have AJAX fun, use the predefined function sajax_init_object:

javascript:void(a=sajax_init_object(),a.open("GET","http://enter.the.name.of.a.website.here",true),a.onreadystatechange=function(){if(a.readyState!=4)return;alert("["+a.status+":"+a.statusText+"]\n"+a.responseText);},a.send())

You can copy the above code to the address bar of your browser to test it.

The same in a more friendly layout, like you would use in a script file:

a=sajax_init_object();
a.open("GET", "http://enter.the.name.of.a.website.here", true);
a.onreadystatechange = function()
{
    if(a.readyState != 4) return;
    alert("[" + a.status + ":" + a.statusText + "]\n" + a.responseText);
};
a.send();

[edit] Retrieving the wikitext of a page

It's easy! Test it:

javascript:void(a=sajax_init_object(),a.open("GET",wgServer+wgScriptPath+"/index.php?title=Knights_of_the_Lambda_Calculus&action=raw",true),a.onreadystatechange=function(){if(a.readyState!=4)return;alert("["+a.status+":"+a.statusText+"]\n"+a.responseText);},a.send(null))

And again, in a more friendly layout:

a=sajax_init_object();
a.open("GET", wgServer + wgScriptPath + "/index.php?title=Knights_of_the_Lambda_Calculus&action=raw", true);
a.onreadystatechange = function()
{
    if(a.readyState != 4) return;
    alert("[" + a.status + ":" + a.statusText + "]\n" + a.responseText);
};
a.send(null);

[edit] Editing the wikitext of a page

Currently work is underway to make this solution unnecessary in most situations. See mw:API.

One might be tempted to use the same AJAX method as above, first GET'ing the edit page, then POST'ing the new data. Unfortunately this won't work. IE refuses to load the HTML of the edit page as XML, because its parser says the HTML is not valid XML or something. I tried POST'ing without first asking for an edit form, but that doesn't work either. A few solutions would be:

  • Write an HTML parser in JavaScript. Good luck.
  • Try to locate wpTextbox1 using regexen. Fragile.
  • Look for the body-tag and insert the contents of that tag in a DIV using innerHTML.
    It's easier to use the next, similar solution.
  • Don't use AJAX, but an IFRAME instead.

The last solution mimics the user navigating to the edit page, modifying, and saving. You can try it out, if you wish:

javascript:void(f=document.createElement("IFRAME"),f.src=wgServer+wgScriptPath+"/index.php?title=Wikipedia:Sandbox&action=edit",document.body.appendChild(f))

Note that the IFRAME appears at the bottom left of the document. Wait until it has finished loading. IFRAME's trigger an event when that happens, so this can be done programmatically as well.

javascript:void(e=f.contentWindow.document.editform,e.wpTextbox1.value+="\n\nTest message.",e.wpSummary.value="faux AJAX test",e.wpSave.click())

You have now posted "Test message." to the sandbox.

[edit] Pros

  • Since it mimics the user doing normal modifications, it could probably be made to work in every browser.
  • You have access to all normal editing tools, including diff functionality, and any specialized scripts that you have configured to only load on edit pages.
  • It's comparatively easy to use.
  • No risk of breaking UTF-8 characters, something which can happen when using uncareful AJAX scripts.
  • It will work in browsers that disable AJAX by default (like some IE setups).

[edit] Cons

  • The server has to prepare an HTML form for you, and the browser has to parse it. Since the edit is made automatically, this may mean wasted server and client time.
  • User scripts will load, dragging down performance. (Although this might also be a good thing, see above.)
    • using the "useskin" parameter to load using a different skin may avoid this, though user scripts (if any) for the other skin will then load.
  • You may find it desirable to hide the IFRAME.
  • This solution just feels cludgy.

[edit] Automatic edits

On edit pages you can find the textbox with the wikitext like this:

var t = document.editform.wpTextbox1;

Then you can read and write the wikitext:

if(/^\s*$/.test(t.value)) ... ;
t.value = t.value + "\n==New section==\n";

To make an edit based on the current selecion, you can use:

insertTags(tagOpen, tagClose, sampleText)

The last parameter will be used if the selection turns out to be empty.

[edit] JSON

Parsing JSON text, as delivered by e.g. the MediaWiki API. The API always returns resultText's of the form "{ ... }"; they can be evaluated (parsed) like this:

eval("0," + r)

[edit] Update a script

Scripts on a user's computer are updated to the most recent version version by bypassing (clearing) the browser cache - the user has to push Shift-Reload (Mozilla) or Shift-F5 (MS-IE). A JavaScript can do the same by calling:

window.location.reload(true);

This forced reload ("forceGet") immediately reloads the current page including all images, scripts, and stylesheets. This should not be done from edit or preview pages as the edits might get lost.

For users that have a lot of scripts installed, reloading them all may take up a lot of time. See Gerbrant.mng.decache and its talk page for example code on how you can let JavaScript remove arbitrary files from your browser cache using an external application.