![]() | This project page or section is in a state of significant expansion or restructuring. You are welcome to assist in its construction by editing it as well. If this project page has not been edited in several days, please remove this template. If you are the editor who added this template and you are actively editing, please be sure to replace this template with {{in use}} during the active editing session. Click on the link for template parameters to use.
This page was last edited by Johnduhart (talk | contribs) 13 years ago. (Update timer) |
This is a small guide on writing user scripts for Wikimedia sites. Of course, some basic JavaScript knowledge is required. (See also JavaScript syntax.)
Built-in scripts
All Wikipedia pages include some built-in MediaWiki JavaScript code, with variables and functions that can be utilized in user scripts. The specific code depends on the viewed page and current users, for more details see Wikipedia:Catalogue of CSS classes#Stylesheets and JavaScript.
Of most interest are:
- More than 30 project-, page- and user-specific variables at the top of the rendered HTML page.
- Default Javascript Modules
- MediaWiki:Common.js (as generated), supported by local administrators.
- The user's own /vector.js (exact name depends on the skin in the user's preferences).
Userscript structure
The personal /vector.js and the gadgets are included early in the generated HTML page. This means that in most cases we need to defer the script actions until the page is loaded. The most common way is to use a special function, .ready()
from jQuery.
//Define our main function
function myScript(){
//... code ...
};
// Schedule it to run after the HTML page is rendered
$( document ).ready( myScript );
// This shorthand is also valid
jQuery( myScript );
Since the function is called only once, many users prefer to shorten this code with an "anonymous function call":
$( document ).ready( function() {
//... code ...
} );
// Or
jQuery( function() {
//... code ...
} );
Note: $
and jQuery
are both the same object, the use between the two is simply your preference
Many scripts use this function simply to add some script interface, such as a link in a leftside portlet. Then the main part of the code is executed after the user clicks on that link.
Editing and loading the user script
Previewing in /vector.js
You can edit your script directly on your /vector.js page, then click [Show preview] and the new code is executed right away on the preview page.
Saving in /vector.js
If required elements are missing on the preview page (for example, your script does something on history pages), you will have to save the script in order to test it.
However it's not convenient and creates unnecessary load on the WikiMedia servers. Also, it seems like these days Wikimedia servers are configured not to give out the saved .js version right away, so you have to wait some minutes after saving and then bypassing your browser cache.
Local HTML file
- Save Wikipedia page to your local hard drive, including all corresponding .css and .js files. Specific details depend on your browser.
- Open saved page in your editor, insert your script code either between
<script></script>
tags or as a separate local file with<script src="file://C://you_local_path/name.js"></script>
. - Open saved page in your browser and preview the result.
This is a very traffic-wise way to quickly develop a user script. However, it has the following disadvantages:
- browser will not let you test Ajax queries from a local file
- you have to save different pages depending on what exactly page (history, etc.) is needed for testing
- you have to periodically re-save all .js files to synchronize with MediaWiki changes
- if you want to "casually" test the script while you're browsing Wikipedia, you still have to use other testing methods
Load from a localhost web server
The best and most recommended way is to load a JavaScript file from your local web server. (See below for an easy way to install a web server.) Put this string in your /vector.js:
mw.loader.load( 'http://localhost/wikipediatest.js' );
Then run any web server on your computer and create the wikipediatest.js file in the appropriate folder. The code inside this file will be executed as if it was inside your /vector.js.
You can edit your wikipediatest.js file with any text editor, perhaps with syntax highlighting and other convenient features, then save the file and simply reload any Wikipedia page to see the results. (You don't need to wait, and if your web server is nice or you set it right you don't even need to bypass your browser cache.)
For example you could use TinyWeb which is less than 100kbyte on disk and doesn't require installation. Save and unzip tinyweb.zip for example into c:\Program Files\Tinyweb, then create a shortcut to tiny.exe, in shortcut properties add an argument — path to your folder with wikipediatest.js and any file index.html (required). Start TinyWeb with this shortcut; unload it with Task Manager.
Note that this method doesn't work in latest Opera browser due to added security restriction, see Opera 9.50 for Windows changelog: "Local servers can use remote resources, but not vice versa".
Browser-specific
Some browsers allow you to automatically execute your javascript code on specific web pages. This way you don't even have to be logged in.
The most famous solution is Greasemonkey for Firefox browsers. Some alternatives for other browsers are listed at Greasemonkey#Greasemonkey compatibility and equivalents for other browsers.
However, making userscript work with one of these extensions might require some modifications to the script code.
Some notes for Opera:
- placing your script in a corresponding folder as
<name>.js
file should work for many userscripts - older versions of Opera (probably below 9.50) did not support UTF-8 local scripts, meaning you could only use latin characters
Pieces of code
You can run pieces of code on already loaded pages, for example directly in the browser address field: javascript: var s = document.title; alert(s); void 0
Or you can use bookmarklet «JavaScript Shell». It opens new browser window where you can paste or type your code and run it in the context of the current page.
However a full-blown Javascript debugger is much more convenient.
Publishing your user script
Once you have finished the user script code you either need to paste it into your /vector.js if it is only for personal use. Or if it is for use by others then you should upload it to for instance User:Yourname/yourscript.js. Then other users can import it by putting this line in their /vector.js.
importScript( 'User:Yourname/yourscript.js' );
CSS files
Some user scripts also use some CSS code, or even are built with CSS only. Then you need to code and test CSS code. That can be done in your /vector.css, but that is slow and messy.
Instead you can load a CSS file from your local web server. (See previous section for an easy to install web server.) Put this line at the very top of your /vector.css:
@import "http://localhost/wikipediatest.css";
Note! Such @import
statements must come before any other declarations in your /vector.css. But there can be /* comments */
above them.
An alternative way is to put this line anywhere in your /vector.js instead:
mw.loader.load( 'http://localhost/wikipediatest.css', 'text/css' );
Publishing a CSS file
Once you have finished the CSS code you either need to paste it into your /vector.css if it is only for personal use. Or if it is for use by others then you should upload it to for instance User:Yourname/yourscript.css. Then other users can import it by putting this line in their /vector.js. Note, that is in their ".js", not their ".css".
importStylesheet( 'User:Yourname/yourscript.css' );
If the CSS should be used together with a user script written in JavaScript then you can make it easy for the users. Simply put the line above in the JavaScript code for your user script, then the users only need to "install" your JavaScript.
For completeness, in case someone wonders. Users can import your User:Yourname/yourscript.css from their /vector.css too. This of course has the advantage that it works even if the user has JavaScript disabled. Although it takes this slightly complex line of code:
@import "/w/index.php?title=User:Yourname/yourscript.css&action=raw&ctype=text/css";
Software
Any text editor will do. If you plan to use non-ascii characters in string, your text editor should support UTF-8.
Notepad++ is recommended, since it can:
- highlight Javascript code
- quickly insert standard Javascript keywords and methods with Ctrl-Enter
- show the list of all functions and quickly jump to any function
- Code folding
For debugging in Firefox you can use Tools → Javascript Console which shows all Javascript and CSS errors. FireBug is strongly recommended for convenient debugging.
For debugging in Opera you can use Tools → Advanced → Error Console which shows all Javascript and CSS errors. Dragonfly is strongly recommended for convenient debugging.
For debugging in IE see IEBlog: Scripting Debugging in Internet Explorer
DHTML methods
Finding elements
Every HTML element is a node of DOM model which allows scripts to access the element. For example on this page
<form name="frmname" id="frmid">
<textarea name="txtname" id="txtid"></textarea>
<input id="neighbor" />
</form>
We can «find» element textarea:
- Using its id:
$( '#txtid' )
- In the array of all elements with the same tag:
$( 'textarea' )
- Using element next to it:
$( '#neighbor').prev()
- As a child of its parent:
$( '#frmid' ).children( 'form' )
- As a form element, using name:
$( '#frmid [name="txtname"]')
The jQuery documentation and jQuery API reference are excellent sources for documentation.
Checking the page
Many scripts are supposed to work only on some pages. You can check:
- page address
if (document.URL.indexOf('action=history') != -1) {
//continue only on history pages
- wg variables; many of them have the same meaning as Magic words
if (wgCanonicalNamespace == 'User_talk') {
//continue only on User_talk pages
- presense of elements (only in 2nd and 3rd parts of the script)
function func_start () {
if (!document.editform) return; //no edit form → exit
… …
portlets
Usual places to add your own links — portlet blocks with these id's:
p-logo | p-personal name My talk My preferences … |
p-search | |
p-navigation p-interaction p-tb p-lang |
Portlet structure: <div id="p-myname" class="portlet">
<h5>Header</h5>
<div class="body">
<ul>
<li id="…"> <a …> //links
<li id="…"> <a …>
… …
|
There is a special function in wikibits.js that simplifies the process of adding your own links into portlets:
addPortletLink (portlet, href, text, id, tooltip, accesskey, nextnode)
//Several examples of portlet links
addPortletLink ('p-tb', wgArticlePath.replace('$1', 'Special:MyPage/vector.js'), 'My vector.js', 'pt-myvector', 'Visit your vector.js file');
addPortletLink ('p-personal', wgScript + '?title=User:' + encodeURIComponent(wgUserName) + '/Notes&action=edit', 'My notes', 'pt-mynotes', 'Edit your personal notes');
addPortletLink ('p-tb', wgArticlePath.replace('$1', 'Special:Prefixindex/'+wgPageName), 'Prefixindex', 'tb-prefixindex');
addPortletLink ('p-personal', '/wiki/Special:Log/' + encodeURIComponent(wgUserName), 'My logs', 'pt-mylogs');
Last 4 arguments are optional; all arguments are explained in the code.
- id of your new link (in case you need to access it later with getElementById)
- tooltip
- accesskey
- nextnode — if you want to insert new link before another element, in our example this could be
document.getElementById('t-specialpages')
, i.e. «Special pages» link
Adding elements
In all other cases there are two ways to insert new elements:
1) adding them to innerHTML of the parent element
//Example: using innerHTML to create a new portlet
document.getElementById('p-tb').innerHTML +=
'</div>'+
'<div id=p-"mything" class="portlet">'+
'<h5>mine</h5>'+
'<div class="body"><ul>'+
'<li><a href="/wiki/Special:MyPage/vector.js">My vector.js</a></li>'+
'</ul></div>'+
'</div>';
2) using DOM methods: createElement(), then attach as child using appendChild() or insertBefore(). For examples of usage see the code of addPortletLink()
Removing elements
To move an element simply attach it in another place with appendChild() or insertBefore().
To hide an element you can set its style.display
to none
:
//Example: remove copyright warning from edit page
var el = document.getElementById('editpage-copywarn');
if (el) el.style.display = 'none';
This is easier with your vector.css though: #editpage-copywarn { display:none; }
Edit page
Text manipulation
The most important element on the edit page is a <textarea> with the article text inside. You can reference it with
var txt = document.editform.wpTextbox1
// or
var txt = document.getElementById('wpTextbox1')
You can add new text to the beginning: txt = "new phrase" + txt
or to the end: txt += "new phrase"
There is a function in wikibits.js that can add text to cursor position:
insertTags (tagOpen, tagClose, sampleText)
Toolbar
Buttons above textarea are located inside <div id='toolbar'>
.
Buttons are defined with mwEditButtons[] and mwCustomEditButtons[] arrays. Then the 2nd part of your script is called by addOnloadHook. Only after that the buttons are created by mwSetupToolbar() in edit.js.
So the easiest way to modify buttons is to work with these arrays:
//Example: modify signature button.
if (mwEditButtons.length >= 10 && mwEditButtons[9].tagOpen == '--~~~~')
mwEditButtons[9].tagOpen = ' — ~~~~';
Also see en:User:MarkS/Extra_edit_buttons.
Edittools
There is another edit panel under textarea. Usually it's generated from MediaWiki:Edittools by Extension:CharInsert and consists of a lot of javascript links to the insertTags(). In English Wikipedia this approach was replaced by MediaWiki:Edittools.js.
//Example: adding your own quick insert to Edittools
var specialchars = document.getElementById ('editpage-specialchars');
specialchars.innerHTML +=
"<a onclick=\"insertTags('<div>','</div>','');return false\"
href='#'><div></a>";
There is no crucial difference between toolbar and edittools, you can insert your own custom links into both.