Jump to content

Wikipedia:User scripts/Techniques

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Extremecircuitz (talk | contribs) at 20:07, 21 October 2007 (Getting the various toolbars (personal, tabs, sidebar): corrected the sidebar id since p-navigation does NOT include the interaction box below it.). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

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.

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.

Preview pages

document.getElementById("wikiPreview")

Edit pages

document.getElementById('ca-edit').className == 'selected'
document.title.indexOf("Editing ") == 0

or

wgAction=='edit'
/[?&]action=edit/.test(window.location.href)
  • Based on: Force edit summary
  • This may fail when Wikipedia is under heavy load and you hit Save page but get a preview instead. Then the url contains action=submit.
 document.editform
  • Should work regardless of skin and language

History pages

window.location.href.indexOf("&action=history") != -1

or

wgAction=='history'

Special pages

window.location.href.indexOf("Special:") != -1
!/wiki\/Special:|w\/index.php?title=Special:/.test(window.location.href)
wgCanonicalNamespace == "Special"

Pages with history

document.getElementById('ca-history')

Editable pages

document.getElementById('ca-edit')

Getting various parts of a page

Getting the page title

See Wikipedia:WikiProject User scripts/Scripts/Get Page Name and Wikipedia:WikiProject User scripts/Scripts/Get tidy title.

 var pagetitleRe=/[^:]*:\/\/en\.wikipedia\.org\/(wiki\/|w\/index\.php\?title=)([^&?]*)/;
 pagetitleRe.exec(decodeURI(location.href))[2].split('_').join(' ');
  • This tries to get the article title from the URL
 document.getElementsByTagName('h1')[0].firstChild.nodeValue
  • This grabs the title at the top of the page (for example, "Editing Wikipedia:WikiProject User scripts/Techniques (section)").

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: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)[reply]

Inserting content

document.getElementById("content").insertBefore(document.createTextNode("abcdef"), document.getElementsByTagName("h1")[0])

Pressing buttons

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

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

Add accesskey and title

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

Disabling accesskeys and titles

ta['pt-logout'] = null;

Update accesskeys and titles

akeytt();

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)) 

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);

Include an external js-file on wikipedia

function import_external(page) {
document.write('<script type="text/javascript" src="' 
             + 'http://en.wikipedia.org/w/index.php?title=' 
             + page
             + '&action=raw&ctype=text/javascript"></script>');

} 
import_external('User:Ilmari Karonen/godmode-light.js');

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();

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);

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.

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.

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.)
  • You may find it desirable to hide the IFRAME.
  • This solution just feels cludgy.

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";

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) in several ways:

Direct assignment
eval("myvar=" + r)
Using braces
eval("(" + r + ")")
Using null
eval("null," + r)
Using undefined
eval("undefined," + r)

What is faster/more efficient? Someone needs to run a few benchmarks.

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.