Wikipedia:User scripts/Guide: Difference between revisions

Content deleted Content added
Finding elements: capitialization
Prerequisites: remove w3schools, it's bad and has always been bad
 
(293 intermediate revisions by 96 users not shown)
Line 1:
{{Wikipedia programs}}
{{TOCright}}
{{UC}}
 
{{Shortcut|WP:US/G}}
This is a small guide on writing user scripts for [[Wikimedia Foundation|Wikimedia]] sites. Of course, some basic [[JavaScript]] knowledge is required. (See also [[JavaScript syntax]].)
 
{{About|writing user scripts for use on Wikipedia|text=For instructions on how to install user scripts, see [[Wikipedia:User scripts#How do you install user scripts?|How do you install user scripts?]]}}
== Built-in scripts ==
 
== Prerequisites ==
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]].
{{Wikibooks|JavaScript}}
To write user scripts, you will have to learn at least some of the programming language that they are written in: [[JavaScript]].
 
Try these links:
Of most interest are:
* [https://developer.mozilla.org/docs/Web/JavaScript Mozilla Developer Network's JavaScript site]
* More than 30 project-, page- and user-specific variables at the top of the rendered HTML page.
* [[JavaScript syntax]]
* [[mw:ResourceLoader/Default modules|Default Javascript Modules]]
* [[jQuery]]
* [[MediaWiki:Common.js]] (as [{{SERVER}}{{SCRIPTPATH}}/index.php?title=-&action=raw&smaxage=0&gen=js generated]), supported by local [[Wikipedia:Administrators|administrators]].
* The user's own [[Special:MyPage/skin.js|/vector.js]] (exact name depends on the [[Wikipedia:Skin|skin]] in the user's preferences).
 
Also, it would definitely help if you tried using [[Wikipedia:User scripts|one of our scripts]] and got it working. The rest of this tutorial assumes you know where the various things are (all explained at ''{{Section link|Wikipedia:User scripts#How do you install user scripts?}}'').
== Userscript structure ==
 
== Forking an existing script ==
The personal <tt>/vector.js</tt> and the [[Wikipedia:Gadget|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, [http://api.jquery.com/ready/ <code>.ready()</code>] from [[jQuery]].
Starting out, it may be easier to modify an existing script to do what you want, rather than create a new script from scratch. This is called "forking". To do this, copy the script to a subpage, ending in ".js",<ref group="n." name="contentmodel">The actual requirement is that the page have contentmodel "javascript". Making a page whose title ends in ".js" will automatically give it that content model and indicates to readers that the page contains JavaScript.</ref> of your user page. Then, [[WP:US#How do you install user scripts?|install the new page]] like a normal user script.
 
== Writing a script from scratch ==
<source lang="javascript">
//Define our main function
function myScript(){
//... code ...
};
 
Although you can write a script directly in your [[Special:EditPage/Special:MyPage/common.js|common.js]] page or ''skin''.js (such as vector.js) page, it is usually better to create a new subpage for it in the form ''YourUserName/title''.js, where ''title'' is the name of your script. That keeps your main js pages from getting cluttered and is helpful when you have multiple scripts installed. You will also want to [[WP:US#How do you install user scripts?|install the new user script]].
// Schedule it to run after the HTML page is rendered
$( document ).ready( myScript );
 
=== Hello world ===
// This shorthand is also valid
 
jQuery( myScript );
To make a [[Hello world]] program, insert the following code into your ''User:YourUserName/common.js'' file:
</source>
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">importScript('User:YourUserName/hello-world.js');</syntaxhighlight>
 
Next, create the page ''User:YourUserName/hello-world.js'', and insert this code:
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">$('#bodyContent').prepend('<p>Hello world!</p>');</syntaxhighlight>
 
This will write "Hello world!" on every page, below the title, until you remove the code. User scripts are written in [[JavaScript]], and both of the above code snippets are in JavaScript. The second snippet uses [[JQuery]], a JavaScript library that specializes in manipulating [[HTML]]. <code>$</code> is a JQuery [[Function (computer programming)|function]] that lets us target the [[HTML]] element we want. <code>#bodyContent</code> is a string in [[CSS selector]] syntax, and means target the HTML element with property <code>id="bodyContent"</code> . <code>prepend</code> is a JQuery function that inserts HTML code as a child of the <code>#bodyContent</code> element. <code><nowiki><p>Hello world!</p></nowiki></code> is the HTML code to be inserted.
 
=== Your first script ===
We will be writing a user script by modifying your common.js. For the purpose of this tutorial, we will write a simple version of the [[Wikipedia:WikiProject User scripts/Scripts/Quick wikify|Quick wikify]] module, which adds the <code><nowiki>{{Wikify}}</nowiki></code> maintenance template to the top of an article when you click a link called "Wikify" in the "More" menu. To begin, change <code>MODULE_NAME</code> in the module template to "Qwikify". Your template should look like this:
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
Since the function is called only once, many users prefer to shorten this code with an "anonymous function call":
// Qwikify
<source lang="javascript">
$( document ).ready( function () {
MODULE_CODE;
//... code ...
} );
</syntaxhighlight>
 
In <code>MODULE_CODE</code>, we want to add the "Wikify" tab, so we will use the [[#Adding elements|<code>addPortletLink()</code> function]] (requiring the <code>mediawiki.util</code> module). Replace <code>MODULE_CODE</code> with a call to this function. Then we will bind an event handler so that when this link is clicked, we will call another function named <code>doQwikify()</code> that will actually execute the code. The <code>name</code> is what is shown on the tab, so set that to <code>'Wikify'</code>. Most tabs have an ID of <code>ca-''name''</code>, so set the ID to <code>'ca-wikify'</code>. The title (also known as [[mouseover]] or [[rollover]] text) should be something like <code>'Mark for wikification'</code>.
// Or
 
jQuery( function() {
Lastly, we use jQuery's [//api.jquery.com/click/ .click()] to listen for clicks on this link, and when that happens, execute a function. After we call <code>doQwikify()</code>, it says <code>event.preventDefault()</code>. Since we clicked on a link, we need to tell the browser to prevent its default behavior (going to the URL, <code>'#'</code>). We want the page to stay right where it is at, so to prevent the browser from following the link, we prevent that and do our own custom action.
//... code ...
 
Altogether, your new function should look like this:
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
// Make sure the utilities module is loaded (will only load if not already)
mw.loader.using( 'mediawiki.util', function () {
// Wait for the page to be parsed
$( document ).ready( function () {
// See the "Portlets (menus and tabs)" subsection below
var link = mw.util.addPortletLink( 'p-cactions', '#', 'Wikify', 'ca-wikify', 'Mark for wikification');
$( link ).click( function ( event ) {
event.preventDefault();
doQwikify();
} );
} );
} );
</syntaxhighlight>
</source>
 
Now, we must write our actual <code>doQwikify()</code> function. It will edit the edit box, so we need to get the name of that and its form. Viewing the source of the page shows that the form is named <code>editform</code> and the textbox is named <code>wpTextbox1</code>, meaning that the actual text is <code>document.editform.wpTextbox1.value</code>. To add {{tl|wikify}} (and two new lines), we simply do:
'' '''Note:''' <code>$</code> and <code>jQuery</code> are both the same object, the use between the two is simply your preference ''
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
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.
document.editform.wpTextbox1.value = "{" + "{wikify}}\n\n" + document.editform.wpTextbox1.value;
</syntaxhighlight>
 
(We separate the two "{" brackets in the front of the wikify template so it doesn't get expanded when we write this code on the wiki.)
== Editing and loading the user script ==
 
Finally, we want to submit the form for the user. Luckily, JavaScript has a built-in function just for this named <code>submit()</code>. To submit our editing form, use <code>document.editform.submit()</code>. Your code should now look something like this:
=== Previewing in /vector.js ===
You can edit your script directly on your [[Special:MyPage/skin.js|/vector.js]] page, then click [Show preview] and the new code is executed right away on the preview page.
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
=== Saving in /vector.js ===
function doQwikify() {
document.editform.wpTextbox1.value = "{" + "{wikify}}\n\n" + document.editform.wpTextbox1.value;
document.editform.submit();
}
</syntaxhighlight>
 
And that's it! Combine it all together and it should look like this:
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.
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
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 [[Wikipedia:Bypass your cache|bypassing your browser cache]].
// Make sure the utilities module is loaded (will only load if not already)
mw.loader.using( 'mediawiki.util', function () {
// Wait for the page to be parsed
$( document ).ready( function () {
// See the "Portlets (menus and tabs)" subsection below
var link = mw.util.addPortletLink( 'p-cactions', '#', 'Wikify', 'ca-wikify', 'Mark for wikification');
$( link ).click( function ( event ) {
event.preventDefault();
doQwikify();
} );
} );
} );
 
function doQwikify() {
=== Local HTML file ===
document.editform.wpTextbox1.value = "{" + "{wikify}}\n\n" + document.editform.wpTextbox1.value;
* Save Wikipedia page to your local hard drive, including all corresponding .css and .js files. Specific details depend on your browser. <!--how-to might be nice-->
document.editform.submit();
* Open saved page in your editor, insert your script code either between <code>&lt;script>&lt;/script></code> tags or as a separate local file with <code>&lt;script src="file://C://you_local_path/name.js">&lt;/script></code>.
}
* Open saved page in your browser and preview the result.
</syntaxhighlight>
 
Save this to your ''User:YourUserName/common.js'' page. Then go visit a page such as the [[Wikipedia:Sandbox|Sandbox]], go into the "More" menu, click "Wikify", and watch the user script add the maintenance tag for you.
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
 
== Built-in scripts ==
=== Load from a localhost web server ===
All Wikipedia pages include some built-in [[MediaWiki]] JavaScript code, with variables and functions that can be used in user scripts. Some of them were already mentioned (<code>$()</code>, <code>importScript()</code>, <code>mw.util</code>). This code is generally loaded as [[mw:ResourceLoader/Core modules|ResourceLoader modules]] (some of it preloaded, some loaded on demand) and ends up in properties of these globally available objects:
* <code>mw</code> (<code>mediaWiki</code>) for MediaWiki core,
* <code>$</code> (<code>jQuery</code>) for [[mw:jQuery|jQuery]],
* <code>OO</code> for [[mw:OOjs|OOjs]].
 
Some commonly accessed properties of <code>mw</code> include <code>mw.config</code>, <code>mw.user.options</code>, <code>mw.util</code>, <code>mw.Title</code>, <code>mw.loader</code>, and <code>mw.hook</code>. <code>OO.ui</code> is the namespace of [[mw:OOUI|OOUI]]. See [[mw:ResourceLoader/Core modules]] for more details.
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 [[Special:Mypage/skin.js|/vector.js]]:
 
== Development and testing ==
<source lang="javascript">
The following [[development environment]]s can be used to develop and test your script.
mw.loader.load( 'http://localhost/wikipediatest.js' );
</source>
 
=== Basic ===
Then run any [[web server]] on your computer and create the <tt>wikipediatest.js</tt> file in the appropriate folder. The code inside this file will be executed as if it was inside your <tt>/vector.js</tt>.
*Using the preview button: You can edit your script directly on your [[Special:MyPage/common.js|/common.js]] page, then click [Show preview] and the new code is executed right away on the preview page.
*Saving it: 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 is not convenient and creates unnecessary entries in the page history.
*Execute it in your browser's JavaScript console: All modern browsers come with a JavaScript console and other development tools. You can type or paste and execute your code there; script errors and warnings will also be shown there. How to open the console depends on your browser:
**In Google Chrome and Edge – press {{press key|Ctrl|Shift|J}}
**In Firefox – press {{press key|F12}}
**In Safari – press {{press key|Ctrl|Alt|C}}
:You may need to click the Console tab if a different pane is currently open.
 
=== Loading it from a localhost web server ===
You can edit your <tt>wikipediatest.js</tt> 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 [[Wikipedia:Bypass your cache|bypass your browser cache]].)
 
The best and most recommended way to load a JavaScript file during development is from your local web server (see below for an easy way to install a web server). Put this string in your [[Special:Mypage/common.js|/common.js]]:
For example you could use [http://www.ritlabs.com/en/products/tinyweb/ TinyWeb] which is less than 100kbyte on disk and doesn't require installation. Save and unzip <tt>tinyweb.zip</tt> for example into <tt>c:\Program Files\Tinyweb</tt>, then create a shortcut to <tt>tiny.exe</tt>, in shortcut properties add an argument — path to your folder with <tt>wikipediatest.js</tt> and any file <tt>index.html</tt> (required). Start TinyWeb with this shortcut; unload it with Task Manager.
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
Note that this method doesn't work in latest [[Opera (web browser)|Opera]] browser due to added security restriction, see [http://www.opera.com/docs/changelogs/windows/950/ Opera 9.50 for Windows changelog]: "Local servers can use remote resources, but not vice versa".
mw.loader.load( 'https://localhost/wikipediatest.js' );
</syntaxhighlight>
 
In some environments, you need to write this as:<ref>https://developer.mozilla.org/en-US/docs/Web/Security/Mixed_content</ref>
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
mw.loader.load( 'http://127.0.0.1/wikipediatest.js' );
</syntaxhighlight>
 
Then run any [[web server]] on your computer and create the <kbd>wikipediatest.js</kbd> file in the appropriate folder. The code inside this file will be executed as if it was inside your personal script.
 
You can edit your <kbd>wikipediatest.js</kbd> file with any text editor, perhaps with syntax highlighting and other convenient features, save the file and simply reload any Wikipedia page to see the results. (You do not need to wait, and if your web server is nice or you set it right, you do not even need to [[Wikipedia:Bypass your cache|bypass your browser cache]].)
 
Most modern code editors and IDEs allow you to set up a localhost server –&nbsp;eg. use [https://atom.io/packages/atom-live-server atom-live-server] in [[Atom (text editor)|Atom]], and [https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer Live Server] in [[VS Code]]. [[WebStorm]] and [[PhpStorm]] have the feature built in, without requiring an extension. You can also use a third party program such as [[Node.js]]'s <code>npx http-server</code> command ([https://www.youtube.com/watch?v=hnTiNvv5Eec video tutorial]), or [[XAMPP]].
 
If you have [[Python (language)|Python]] installed, you can run <code>python -m http.server</code> from command-line from the folder your script is in.
 
On Windows, you could also use for example [https://www.ritlabs.com/en/products/tinyweb/download.php TinyWeb], less than 100&nbsp;kbyte on disk and not requiring installation. Save and unzip <kbd>tinyweb.zip</kbd> for example into <kbd>c:\Program Files\Tinyweb</kbd>, create a shortcut to <kbd>tiny.exe</kbd>, and add an argument in shortcut properties — path to your folder with <kbd>wikipediatest.js</kbd> and any file <kbd>index.html</kbd> (required). Start TinyWeb with this shortcut; unload it with Task Manager.
 
Note that this method doesn't work in [[Opera (web browser)|Opera]] 9.50 (and later) due to added security restrictions, see [http://www.opera.com/docs/changelogs/windows/950/ Opera 9.50 for Windows changelog]: "Local servers can use remote resources, but not vice versa". In [[Google Chrome|Chrome]], it may be necessary to [http://stackoverflow.com/a/25075349/6357045 enable SSL], otherwise the script will refuse to load.
 
=== Browser-specific ===
Some browsers allow you to automatically execute your javascriptJavaScript code on specific web pages. This way you don'tdo evennot have to be logged in to Wikipedia. One example is [[Tampermonkey]]. However, making user scripts work with one of these extensions might require some modifications to the script code.
 
=== Running pieces of code ===
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]].
You can run pieces of code on already loaded pages via the JavaScript console. See the [https://developer.chrome.com/docs/devtools/console/javascript/ guide for doing this in Chrome]. It works similarly in most other browsers. In addition, [[Chromium]]-based browsers have a [https://developer.chrome.com/docs/devtools/javascript/snippets snippets] feature where short pieces of JavaScript code can be saved and debugged.
 
== Publishing ==
However, making userscript work with one of these extensions might require some modifications to the script code.
 
Once you have finished the user script code, you can save it as a page so that others can import it. By convention, scripts are in your userspace and have titles ending in ".js",<ref group="n." name="contentmodel" /> for example "User:YourUsernameHere/MyCoolScript.js". Others can then [[WP:US#How do you install user scripts?|install the new script]].
Some notes for [[Opera (web browser)|Opera]]:
* placing your script in a corresponding folder as <code><name>.js</code> 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
 
=== PiecesText ofeditors codeand debugging ===
You can run pieces of code on already loaded pages, for example directly in the browser address field: <code>javascript: var s = document.title; alert(s); void 0</code>
 
=== Text editors ===
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.
You can use anything from a simple [[text editor]], to a more feature-packed [[code editor]] or [[Integrated development environment|IDE]]. Here are some recommended editors, by operating system.
* [http://www.squarefree.com/shell/ JavaScript Shell for FireFox and Opera]
* [http://blog.monstuff.com/archives/000287.html JavaScript Shell for IE]
 
* Windows
However a full-blown Javascript debugger is much more convenient.
** [[VS Code]] (cross-platform)
** [[Notepad++]]
* Mac OS X
** [[Xcode]]
** [[JEdit]] (cross-platform)
** [[Komodo Edit]] (cross-platform)
** [[Aptana Studio]] (cross-platform)
** [[TextMate]] (not free)
** [[Coda (web development software)|Coda]] (not free)
** [[PhpStorm]] (not free, cross-platform, a free license for MediaWiki Developers is also available<ref>https://lists.wikimedia.org/pipermail/mediawiki-l/2010-June/034396.html</ref>)
* Linux
** [[Neovim]]/[[Emacs]]
** [[gedit]] (may come with Linux)
** [[Kate (text editor)|Kate]], for KDE-based desktops
** [[GNOME Text Editor]], for [[GNOME]]
 
=== PublishingJavaScript your user scriptDebuggers ===
 
These are typically built into browsers, in their DevTools window. Debuggers allow you to step debug (go through your JavaScript code line-by-line, hover over variables to see their values, etc.)
Once you have finished the user script code you either need to paste it into your <tt>/vector.js</tt> if it is only for personal use. Or if it is for use by others then you should upload it to for instance [[Special:Mypage/yourscript.js|User:Yourname/yourscript.js]]. Then other users can import it by putting this line in their <tt>/vector.js</tt>.
 
* [[Firefox]] - use Tools → JavaScript Console showing all JavaScript and CSS errors.
<source lang="javascript">
* [[Google Chrome|Chrome]] and [[Microsoft Edge|Edge]] - use Tools → Developer Tools.
importScript( 'User:Yourname/yourscript.js' );
* [[Safari (web browser)|Safari]] - Safari → Preferences → Advanced and enable the "Show Develop menu in menu bar" option. Then use Develop → Show Web Inspector to open up the development tools.
</source>
* [[Opera browser|Opera]] - use Tools → Advanced → Error Console showing all JavaScript and CSS errors.
 
== CSSBasic filestechniques ==
 
=== Running code on page load ===
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 <tt>/vector.css</tt>, but that is slow and messy.
 
The personal <code>user</code> module (built from /common.js, /common.css and optionally the skin-specific files for the current skin; see [[#Writing a script from scratch|above]]) and [[Wikipedia:Gadget|gadgets]] are loaded on all pages. Most scripts will want to manipulate elements on the page; to do so the page needs to be ready (it may not be the case at the time the modules are loaded). We can defer execution of code by using a special function.
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 [[Special:Mypage/skin.css|/vector.css]]:
<source lang="css">
@import "http://localhost/wikipediatest.css";
</source>
'''Note!''' Such <code>@import</code> statements must come before any other declarations in your <tt>/vector.css</tt>. But there can be <code>/* comments */</code> above them.
 
==== <code>$(document).ready(...)</code> ====
An alternative way is to put this line anywhere in your <tt>/vector.js</tt> instead:
One option is <code>[//api.jquery.com/ready/ .ready()]</code> from [[jQuery]].
 
<sourcesyntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
// Define our main function
mw.loader.load( 'http://localhost/wikipediatest.css', 'text/css' );
function myScript() {
</source>
// ... code ...
};
 
// Schedule it to run after the HTML page is parsed
=== Publishing a CSS file ===
$( document ).ready( myScript );
 
// This shorthand is also valid
Once you have finished the CSS code you either need to paste it into your <tt>/vector.css</tt> if it is only for personal use. Or if it is for use by others then you should upload it to for instance [[Special:Mypage/yourscript.css|User:Yourname/yourscript.css]]. Then other users can import it by putting this line in their <tt>/vector.js</tt>. Note, that is in their ".js", not their ".css".
jQuery( myScript );
</syntaxhighlight>
 
Since the function is called only once, many users prefer to shorten this code with an [[anonymous function]]:
<source lang="javascript">
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
importStylesheet( 'User:Yourname/yourscript.css' );
$( document ).ready( function () {
</source>
// ... code ...
} );
 
// Or
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.
jQuery( function () {
// ... code ...
} );
</syntaxhighlight>
 
'' '''Note:''' <code>$</code> and <code>jQuery</code> are the same object; choosing between them is purely a matter of opinion.''
For completeness, in case someone wonders. Users can import your <tt>User:Yourname/yourscript.css</tt> from their <tt>/vector.css</tt> 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:
<source lang="css">
@import "/w/index.php?title=User:Yourname/yourscript.css&action=raw&ctype=text/css";
</source>
 
Many scripts use this function simply to add some script interface, such as a link in a portlet. Then the main part of the code is executed after the user clicks on that link.
== Software ==
 
==== <code>mw.hook('wikipage.content').add(...)</code> ====
Any text editor will do. If you plan to use non-ascii characters in string, your text editor should support [[UTF-8]].
However, if your code works with the content part of the page (the <code>#mw-content-text</code> element), you should use the <code>[https://doc.wikimedia.org/mediawiki-core/master/js/Hooks.html#~event:'wikipage.content' 'wikipage.content']</code> [[Hooking|hook]] instead. This way your code will successfully reprocess the page when it is updated asynchronously and the hook is fired again. There are plenty of tools that do so, ranging from edit preview to watchlist autoupdate.
 
Be sure to only work with the descendants of the <code>$content</code> element that your handler function takes and not the whole page. Otherwise, you may end up running the same code for the same elements many times. Note that the <code>'wikipage.content'</code> hook may be fired ''really'' many times.
[[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]]
 
Be cautious about what comes in the <code>$content</code> argument of the handler function. You should not assume it is the <code>#mw-content-text</code> element. It can be a small portion of the page, e.g. when it is previewed.
For debugging in [[Firefox]] you can use Tools → Javascript Console which shows all Javascript and CSS errors. [http://getfirebug.com/ FireBug] is strongly recommended for convenient debugging.
 
Code that works with page content and avoids the aforementioned pitfalls may look like this:
For debugging in [[Opera browser|Opera]] you can use Tools → Advanced → Error Console which shows all Javascript and CSS errors. [http://dragonfly.opera.com/ Dragonfly] is strongly recommended for convenient debugging.
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
For debugging in IE see [http://blogs.msdn.com/ie/archive/2004/10/26/247912.aspx IEBlog: Scripting Debugging in Internet Explorer]
mw.hook( 'wikipage.content' ).add( function ( $content ) {
const $target = $content.find( '.targetClass' );
if ( $target.length ) {
// Do things with $target
}
 
// Only perform some operations when it is #mw-content-text in the argument
if ( $content.is( '#mw-content-text' ) ) {
const $note = $( '<div>' )
.addClass( 'myScript-note' )
.text( 'MyScript has successfully processed the content!' );
$content.prepend( $note );
}
} );
</syntaxhighlight>
 
If your code works with page content and adds event handlers to DOM elements, then, instead of hooking to <code>'wikipage.content'</code> and looking for elements to attach event listeners to when it is fired, you may attach one event listener to an element outside of the content area or the whole <code>document</code> but filter events by a selector (see [https://api.jquery.com/on/#on-events-selector-data-handler jQuery's documentation]). That is, instead of writing <syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%" inline>$content.find( '.targetClass' ).on( 'click', ... )</syntaxhighlight> you can write <syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%" inline>$( document ).on( 'click', '.targetClass', ... )</syntaxhighlight>.
== DHTML methods ==
 
=== Finding elements ===
Every [[HTML]] element is a node ofin a [[Document Object Model|DOM]] model which allowsallowing scripts to access the element., Forfor example, on thisthe following HTML page.
 
<syntaxhighlight lang="html" copy style="min-width:fit-content; max-width: 40%">
<source lang="html4strict">
<form name="frmname" id="frmid">
<textarea name="txtname" id="txtid"></textarea>
<input id="neighbor" />
</form>
</syntaxhighlight>
</source>
 
We can «find» element <ttcode>textarea</ttcode>:
* Using its <ttcode>id</ttcode>: <codesyntaxhighlight lang="js" copy style="min-width:fit-content; max-width: 40%" inline>$( '#txtid' )</codesyntaxhighlight>
* In the array of all elements with the same <ttcode>tag</ttcode>: <codesyntaxhighlight lang="js" copy style="min-width:fit-content; max-width: 40%" inline>$( 'textarea' )</codesyntaxhighlight>
* Using an element next to it: <codesyntaxhighlight lang="js" copy style="min-width:fit-content; max-width: 40%" inline>$( '#neighbor' ).prev()</codesyntaxhighlight>
* As a child of its parent: <codesyntaxhighlight lang="js" copy style="min-width:fit-content; max-width: 40%" inline>$( '#frmid' ).children( 'form' )</codesyntaxhighlight>
* As a form element, using <ttcode>name</ttcode>: <codesyntaxhighlight lang="js" copy style="min-width:fit-content; max-width: 40%" inline>$( '#frmid [name="txtname"]' )</codesyntaxhighlight>
 
'' [http://jsfiddle.net/compwhizii/j2QRf/ This example on jsFiddle] ''
 
The [http://docs.jquery.com/Main_Page jQuery documentation] and [http://api.jquery.com jQuery API reference] areis an excellent sourcessource for documentation.
<!--To see all the elements on the page and their relations simply look at the page source code.-->
 
=== Checking the current page ===
Many scripts are supposed to work only on some pages. You can check:
 
* The page type<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
* page address
if ( mw.config.get( 'wgAction' ) === 'history' ) { // Continue only on history pages.
<source lang="javascript">
</syntaxhighlight>
if (document.___URL.indexOf('action=history') != -1) {
* [[:mw:Manual:Interface/JavaScript#mw.config|<kbd>wg</kbd> (Wikimedia global) variables]]; many of them have the same meaning as [[Help:Magic words|Magic words]]<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
//continue only on history pages
if ( mw.config.get( 'wgCanonicalNamespace' ) === 'User_talk') { // Continue only on User_talk pages.
</source>
</syntaxhighlight><syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
* <tt>wg</tt> variables; many of them have the same meaning as [[Help:Magic words|Magic words]]
if ( mw.config.get( 'wgPageName' ) === 'Article_name' ) { // Continue only for the article "Article name".
<source lang="javascript">
</syntaxhighlight>
if (wgCanonicalNamespace == 'User_talk') {
//continue only on User_talk pages
</source>
* presense of elements (only in 2nd and 3rd parts of the script)
<source lang="javascript">
function func_start () {
if (!document.editform) return; //no edit form → exit
… …
</source>
 
* Presence of elements (only in second and third parts of the script)<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
=== portlets ===
function func_start() {
Usual places to add your own links — <tt>portlet</tt> blocks with these id's:
if ( $( '#editForm' ).length == 0 ) return; //No edit form ? exit
// …
</syntaxhighlight>
 
=== Portlets (menus and tabs) ===
<div style="border:1px solid gray">
{|
|rowspan=2|<sup>''p-logo''</sup>
|<sup>''p-personal''</sup> <u>name</u> <u>My talk</u> <u>My preferences</u> …</div>
|-
|<div style="border:1px solid gray;float:right">
<sup>''p-search''</sup>
<div style="height:10px;width:40px;border:1px solid gray;margin-left:10px;margin-bottom:3px">&nbsp;</div>
</div><sup>''p-cactions''</sup> <u>Article</u> <u>Discussion</u> <u>Read</u> <u>Edit</u> <u>History</u> …</div>
|-
|
<br/><div style="border:1px solid gray">
<sup>''p-navigation''</sup><br/>
&nbsp;Main page …</div>
<br/><div style="border:1px solid gray">
<sup>''p-interaction''</sup><br/>&nbsp; …
</div>
<br/><div style="border:1px solid gray">
<sup>''p-tb''</sup><br/> …<br/>Upload file<br/> …
</div>
<br/><div style="border:1px solid gray">
<sup>''p-lang''</sup><br/>(interwikis)
</div>
 
{{main|Help:Customizing toolbars}}{{shortcut|WP:PORTLET}}
|
<div style='margin-left:50px'>
Portlet structure:
 
Portlets are MediaWiki's name for groups of links located in the topbar and sidebar. Here is a diagram of portlet ID's.
<source lang="html4strict">
 
[[File:MediaWiki portlet names.svg|500px|thumb|[[MediaWiki]] portlets as seen in [[Wikipedia:Skin|Vector legacy skin]].]]
 
==== List of portlets (portlet types)<span class="anchor" id="List of portlets"></span> ====
 
* Top
** <span style="color:green;">p-personal</span> - The links at the top right of the page. "personal" stands for "personal tools".
** <span style="color:red;">p-namespaces</span> - The tabs on the left that never collapse. Not recommended, not much space. The article and talk tabs are located here.
**<span style="color:red;">p-views</span> - The tabs in the middle that never collapse. Not recommended, not much space. The favorite page star tab is located here.
**<span style="color:green;">p-cactions</span> - The items in the "More" tab's dropdown menu. "cactions" stands for "content actions".
** <span style="color:red;">p-search</span> - Adding things here will mess up the appearance of the search box. Not recommended.
* Left
** <span style="color:red;">p-logo</span> - Adding things here will mess up the appearance of the logo. Not recommended.
** <span style="color:green;">p-navigation</span>
** <span style="color:green;">p-interaction</span> - Has the title "Contribute".
** <span style="color:green;">p-tb</span> - Has the title "Tools". TB stands for toolbox.
** <span style="color:red;">p-coll-print_export</span> - Has the title "Print/export". Not a good place to add things, since this should just be for printing and exporting.
**<span style="color:red;">p-wikibase-otherprojects</span> - Has the title "In other projects". Not a good place to add things, since this should just be for links to other projects such as Wikisource, Wikibooks, etc.
** <span style="color:red;">p-lang</span> - Has the title "Languages". Not a good place to add things, since this should just be for languages.
 
==== Portlet structure ====
<syntaxhighlight lang="html" copy style="min-width:fit-content; max-width: 40%">
<div id="p-myname" class="portlet">
<h5>Header</h5>
<div class="body">
<ul>
<li id="..."> <a ...> //linksLinks
<li id="..."> <a ...>
… …...
</syntaxhighlight>
</source>
</div>
|}
</div>
 
==== Adding elements ====
There is a special function in [{{SERVER}}/skins-1.5/common/wikibits.js wikibits.js] that simplifies the process of adding your own links into portlets:<br/>
There is a special function in <code>mediawiki.util</code>, <code>[https://www.mediawiki.org/wiki/ResourceLoader/Core_modules#addPortletLink mw.util.addPortletLink()]</code> that simplifies the process of adding your own links to portlets. The advantage of using this function is that your code should work across all skins, and not break when these skins change their HTML. Its parameters, in order:
<tt>'''addPortletLink''' (portlet, href, text, id, tooltip, accesskey, nextnode)</tt>
 
* <code>portletId</code> – ID of the target [[#Portlets (menus and tabs)|portlet]]
<source lang="javascript">
* <code>href</code> – link URL
//Several examples of portlet links
** Set to <code>'#'</code> if you do not need to open a page and want to use a JavaScript listener instead.
addPortletLink ('p-tb', wgArticlePath.replace('$1', 'Special:MyPage/vector.js'), 'My vector.js', 'pt-myvector', 'Visit your vector.js file');
* <code>text</code> – human-readable link text
addPortletLink ('p-personal', wgScript + '?title=User:' + encodeURIComponent(wgUserName) + '/Notes&action=edit', 'My notes', 'pt-mynotes', 'Edit your personal notes');
* <code>id</code> (optional) – unique ID of the item
addPortletLink ('p-tb', wgArticlePath.replace('$1', 'Special:Prefixindex/'+wgPageName), 'Prefixindex', 'tb-prefixindex');
** Use a prefix such as {{abbr|ca-|Content Actions (p-cactions)}}, {{abbr|pt-|Personal Tools (p-personal)}}, {{abbr|n-|Navigation (p-navigation)}}, or {{abbr|t-|Tools/Toolbox (p-tb)}} – for consistency with other links in the group of chosen <code>portletId</code>.
addPortletLink ('p-personal', '/wiki/Special:Log/' + encodeURIComponent(wgUserName), 'My logs', 'pt-mylogs');
* <code>tooltip</code> (optional) – helpful text appearing on mouse hover
</source>
* <code>accesskey</code> (optional) – [https://www.w3schools.com/tags/att_global_accesskey.asp keyboard shortcut key]
** Set to <code>null</code> if you do not need it.
** Use <code>$( '[accesskey=x]' )</code> in the console to see if 'x' is already used.
* <code>nextNode</code> (optional) – element that this will be added in front of
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
Last 4 arguments are optional; all arguments are explained in the code.
// Several examples of portlet links
* <tt>id</tt> of your new link (in case you need to access it later with <tt>getElementById</tt>)
* <tt>tooltip</tt>
* <tt>accesskey</tt>
* <tt>nextnode</tt> — if you want to insert new link before another element, in our example this could be <code>document.getElementById('t-specialpages')</code>, i.e. «Special pages» link
 
// Adds a link to your js file to the toolbox. tb = toolbox
=== Adding elements ===
mw.util.addPortletLink ( 'p-tb', mw.util.getUrl( 'Special:MyPage/common.js' ), 'My JS', 'pt-myvector', 'Visit your js file');
In all other cases there are two ways to insert new elements:
 
// Add a link to the edit page for your Notes in your personal links
1) adding them to <tt>'''innerHTML'''</tt> of the parent element
// Note: We assume that short/pretty URLs are in use with ?action, ideally you would check for that.
mw.util.addPortletLink ( 'p-personal', mw.util.getUrl( 'Special:MyPage/Notes' ) + '?action=edit', 'My notes', 'pt-mynotes', 'Edit your personal notes' );
 
// Adds a link to prefix index for the current page to the toolbox
<source lang="javascript">
mw.util.addPortletLink ( 'p-tb', mw.util.getUrl( 'Special:Prefixindex/' + mw.config.get( 'wgPageName' ) ), 'Prefixindex', 'tb-prefixindex');
//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>';
</source>
 
// Adds a link to logs for your account
mw.util.addPortletLink ( 'p-personal', mw.util.getUrl( 'Special:Log/' + mw.config.get( 'wgUserName' ) ), 'My logs', 'pt-mylogs');
</syntaxhighlight>
 
Or you can use JQuery. Simply attach it in another place with <code>.append()</code>, <code>.prepend()</code>, <code>.before()</code>, or <code>.after()</code>. [https://www.w3schools.com/jquery/jquery_dom_add.asp][https://javascript.info/article/modifying-document/before-prepend-append-after.svg]. Warning: This is fragile. You may get it working on a couple skins, but a couple other skins may look broken.
2) using DOM methods: <tt>'''createElement()'''</tt>, then attach as child using <tt>'''appendChild()'''</tt> or <tt>'''insertBefore()'''</tt>. For examples of usage see the code of <tt>addPortletLink()</tt>
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
// Add a clickable button on the edit article page, above the edit summary.
$('.editOptions').prepend('<button type="button" id="my-custom-button">Do Things</button>');
 
// Add a listener to your button, that does something when it is clicked.
$('#my-custom-button').click(function(e) {
// do things
});
</syntaxhighlight>
 
=== Removing elements ===
 
To movehide an element, simplyyou attachcan ituse inJQuery's another place with[//api.jquery.com/hide/ <ttcode>appendChild.hide()</ttcode>] or <tt>insertBefore()</tt>function.
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
To hide an element you can set its <code>style.display</code> to <code>none</code>:
// Example: remove special characters toolbar from edit page
$( '#editpage-specialchars' ).hide();
 
// Or modify the CSS directly
<source lang="javascript">
$( '#editpage-specialchars' ).css( 'display', 'none' );
//Example: remove copyright warning from edit page
</syntaxhighlight>
var el = document.getElementById('editpage-copywarn');
if (el) el.style.display = 'none';
</source>
 
Or you can do it by placing code in [[Special:Mypage/common.css|common.css]]:
This is easier with [[Special:Mypage/skin.css|your vector.css]] though: <code style="white-space:nowrap">#editpage-copywarn { display:none; }</code>
 
<syntaxhighlight lang="css">
== Edit page ==
#editpage-specialchars {
display:none;
}
</syntaxhighlight>
 
=== TextAdding manipulationmenus ===
You can add menus using <code>mw.util.addPortlet()</code> (see [[wmdoc:mediawiki-core/master/js/module-mediawiki.util.html#.addPortlet|documentation]]). The menu will not show up until you put a portletLink in it. If you add a menu adjacent to #p-cactions, it will be a dropdown menu in the Vector and Vector 2022 skins, with the correct dropdown HTML added for you.
The most important element on the edit page is a <tt><textarea></tt> with the article text inside. You can reference it with<br/>
<code>var txt = document.editform.wpTextbox1</code> // or <br/>
<code>var txt = document.getElementById('wpTextbox1')</code>
 
<syntaxhighlight lang="js" copy style="min-width:fit-content; max-width: 40%">mw.util.addPortlet('p-twinkle', 'TW', '#p-cactions');
You can add new text to the beginning: <code>txt = "new phrase" + txt</code> or to the end: <code>txt += "new phrase"</code>
mw.util.addPortletLink('p-twinkle', '#', 'Tag');
mw.util.addPortletLink('p-twinkle', '#', 'CSD');</syntaxhighlight>
 
=== Editing ===
There is a function in wikibits.js that can add text to cursor position: <br/>
'''insertTags''' (tagOpen, tagClose, sampleText)
 
==== Textarea with article wikicode ====
=== Toolbar ===
The most important element on the edit page is a <kbd><textarea></kbd> with the article text inside. You can reference it with
Buttons above textarea are located inside <code><nowiki><div id='toolbar'></nowiki></code>.
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
Buttons are defined with <tt>mwEditButtons[]<tt> and <tt>mwCustomEditButtons[]</tt> arrays. Then the 2nd part of your script is called by <tt>addOnloadHook</tt>. Only after that the buttons are created by <tt>mwSetupToolbar()</tt> in [http://en.wikipedia.org//skins-1.5/common/edit.js edit.js].
var $textbox = $( '#wpTextbox1' );
</syntaxhighlight>
 
You can manipulate it using the [https://doc.wikimedia.org/mediawiki-core/master/js/module-jquery.textSelection.html jquery.textSelection] ResourceLoader module.
So the easiest way to modify buttons is to work with these arrays:
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
var $textbox = $( '#wpTextbox1' );
$textbox.textSelection( 'setContents', 'This is bold!' );
$textbox.textSelection( 'setSelection', { start: 8, end: 12 } );
$textbox.textSelection( 'encapsulateSelection', { pre: '<b>', post: '</b>' } );
// Result: Textbox contains 'This is <b>bold</b>!', with cursor before the '!'
</syntaxhighlight>
 
Or you can grab <code><textbox></code>'s text, create a [[string (computer science)|string]], modify it, then write it back. Note; other editing tools might not recognise your changes or cause conflicts if you use this methodology instead of the textSelection api.
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
// Get value.
let value = $('#wpTextbox1').val();
 
// Your code goes here. Do things to value. RegEx, .replace(), concatenate, etc.
 
// Then write it back.
$('#wpTextbox1').val(value);
</syntaxhighlight>
 
==== Editing toolbar ====
WikiEditor is now the default toolbar when editing the source code of articles, but some users are still using the original toolbar. You can turn on and off WikiEditor by checking and unchecking the "Enable the editing toolbar" check box in [[Special:Preferences#mw-prefsection-editing|your preferences]].<ref group="n.">See [[mw:Extension:WikiEditor/Toolbar customization]] for information on how to customize WikiEditor.</ref><ref group="n.">See [[User:V111P/js/addToolbarButtons]] for a script that allows you to easily add buttons to whichever of the two toolbars the user is using.</ref>
 
==== Edittools ====
There is another edit panel under textarea. Usually it is generated from [[MediaWiki:Edittools]] by [[mw:Extension:CharInsert|Extension:CharInsert]] and consists of a lot of JavaScript links. In the English Wikipedia, this approach was replaced by [[MediaWiki:Gadget-charinsert.js]] and [[MediaWiki:Gadget-charinsert-core.js]].
 
==== Automatic and semi-automatic editing ====
You can automate the editing of a page using the following code template:
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width:40%;">
mw.loader.using("mediawiki.user", () => {
$.post( mw.config.get('wgScriptPath') + '/api.php', {
action: 'edit',
title: "[Page title]",
text: "[Text]",
summary: "[Edit summary]",
token: mw.user.tokens.get('csrfToken'), // This is the user token required to authorize the edit.
format: 'json'
}).then(function(r){
if (r.error) {
mw.notify(r.error.info, {type: 'error', title: 'Error while trying to edit'}); // Sends an error message if unable to edit the page.
}
});
});
</syntaxhighlight>
 
=== Doing something after another user script ===
Sometimes you may want to add or remove something from the DOM, but another user script edits the same area of the DOM. It can be random which user script finishes first, creating a [[race condition]].
 
One way to coordinate this is use the [https://doc.wikimedia.org/mediawiki-core/master/js/Hooks.html mw.hook] interface. Perhaps the other script sends a <code>[[#mw.hook('wikipage.content').add(...)|wikipage.content]]</code> event when it is done, or can be modified to do so (or you can ask the maintainer).
 
Another way to avoid this is to use a [https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver MutationObserver].
 
=== User settings ===
If you want your users to be able to manually set configuration variables, one way to do this is to have them place <code>window.scriptNameSettingName = 'value here';</code> in their common.js file. Then within your user script, you can read this value with <code>if ( window.scriptNameSettingName == 'value here' )</code>.
 
Notice that "scriptName" is one of the pieces of the variable name. This is important to help make sure the variable is unique.
 
Do not use <code>let scriptNameSettingName = 'value here';</code> in the common.js file. If the user forgets the setting, you may get undeclared variable errors.
 
If you want your user script to write and save configuration settings as it is running, you may want to have it write to its own .js file in the user's userspace. See [[User:Novem Linguae/twinkleoptions.js|twinkleoptions.js]] or [[User:Novem Linguae/redwarnConfig.js|redwarnConfig.js]] for examples.
 
== Preventing bugs ==
 
=== <nowiki>&lt;nowiki&gt; tags</nowiki> ===
You may want to place the following code at the top and bottom of your user script, in a comment. This will help prevent bugs, such as <code><nowiki>~~~~</nowiki></code> turning into your hard-coded signature when you save the page.
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">//<nowiki>
 
Your code here.
 
//</nowiki></syntaxhighlight>
 
If you need to print &lt;nowiki&gt; or &lt;/nowiki&gt; tags within your user script, use a trick such as <code>const tag = '</' + 'nowiki>';</code> to keep from messing up the nowiki tag on line 1 and on the last line.
 
=== Function scope ===
 
Do not declare named functions in the global namespace. For example, this is bad:
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">function submitEdit() {/* do stuff */}
 
$(function(){/* main code here */});</syntaxhighlight>
 
What if another of your user scripts also declares a <code><nowiki>submitEdit()</nowiki></code> function? This can lead to [[race conditions]] and hard-to-trace bugs. Instead, use classes named after your script, or place all your functions inside of an [[immediately invoked function expression]] (IIFE) such as <code><nowiki>$(function {});</nowiki></code>. JavaScript allows [[Nested function|nested functions]].
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">$(function(){
function submitEdit() {/* do stuff */}
/* main code here */
});</syntaxhighlight>
 
== Ajax ==
[[Ajax (programming)|AJAX]] (''asynchronous JavaScript and XML'') is a popular name for a web programming technique that queries the server or fetches content without reloading the entire page. This is great for API requests. We do not have access to the SQL database in front end code, so the [[mw:Action_API|MediaWiki action API]] (or one of the [[mw:REST_API|other APIs]]) is the main way we retrieve data.
 
=== Basic examples ===
==== mediawiki.api ====
MediaWiki provides some modules with helper functions facilitating the use of its API. The main modules available are
* [https://doc.wikimedia.org/mediawiki-core/master/js/mw.Api.html mediawiki.api]
If your script makes use any method or code provided by these modules, remember to indicate the dependencies with [[mw:ResourceLoader/Default_modules#mediaWiki.loader|mw.loader.using]] or, in case of gadgets, on its definition at [[MediaWiki:Gadgets-definition]].
 
This API has several advantages especially when dealing with POST requests. It provides automatic token refresh and retry, handles various error situations and does parameter request building for several common use cases like rolling back a revision.
 
Be sure to follow the [[meta:User-Agent policy|user agent policy]] by setting a user agent header (see code there). See also [[mw:API:Etiquette]].
 
==== Get the wikitext of a page ====
===== Using module <code>mediawiki.api</code>=====
Note: make sure to add <code>mediawiki.api</code> to your dependencies!
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
function doSomethingWithText( wikitext ) {
/* .. */
alert( 'The wikitext of the page is:\n\n' + wikitext );
}
function doSomethingInCaseOfError () {
/* .. */
console.log( 'err' );
}
(new mw.Api()).get( {
prop: 'revisions',
rvprop: 'content',
rvlimit: 1,
indexpageids: true,
titles: 'Wikipedia:Sandbox'
} )
.then( function ( data ) {
var q = data.query,
id = q && q.pageids && q.pageids[0],
pg = id && q.pages && q.pages[ id ],
rv = pg && pg.revisions;
if ( rv && rv[0] && rv[0]['*'] ) {
doSomethingWithText( rv[0]['*'] );
}
} )
.catch( doSomethingInCaseOfError );
</syntaxhighlight>
 
===== Using jQuery $.getJSON =====
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
$.getJSON(
mw.util.wikiScript('api'),
{
format: 'json',
action: 'query',
prop: 'revisions',
rvprop: 'content',
rvlimit: 1,
titles: 'Wikipedia:Sandbox'
}
)
.then(function ( data ) {
var page, wikitext;
try {
for ( page in data.query.pages ) {
wikitext = data.query.pages[page].revisions[0]['*'];
doSomethingWithText( wikitext );
}
} catch ( e ) {
doSomethingInCaseOfError();
}
})
.catch( doSomethingInCaseOfError );
</syntaxhighlight>
 
===== Using jQuery $.ajax =====
Fetching a page content can be done using jQuery <code>$.ajax</code>, which does an HTTP [[GET (HTTP)|GET]] request.<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
$.ajax({
url: mw.util.getUrl( 'Wikipedia:Sandbox' )
})
.then(function( data ) {
alert( 'The remote page contains:\n' + data );
})
.catch(function() {
alert( 'The ajax request failed.' );
});
</syntaxhighlight>
 
==== Edit a page and other common actions ====
Scripts can perform common actions (like editing, protection, blocking, deletion, etc.) through the [{{SERVER}}/w/api.php API]. These actions require an edit token, valid for any action during the same session. (However, you should get a new token for different tasks in case this changes in the future.)
 
The code below shows how to edit a page, but it can easily be adapted to other actions by reading the [{{SERVER}}/w/api.php API documentation].
===== Using module <code>mediawiki.api</code>=====
Note: make sure to add <code>mediawiki.api</code> to your dependencies!
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
// Edit page via the mw.Api module.
// postWithEditToken( {} ) may be used instead of postWithToken("csrf", {} )
// for actions such as editing that require a CSRF token.
// The line "text: info.text," will cause the call
// to replace entire page content with supplied data.
// alternatively, one can append or prepend the data to the page, by using
// "appendtext: info.text," or "prependtext: info.text," instead.
// when using "appendtext", it is possible to append the text to a specific section,
// by setting the optional field "section".
function editPage( info ) {
var api = new mw.Api();
api.postWithToken("csrf", {
action: 'edit',
title: info.title,
text: info.text, // will replace entire page content
summary: info.summary
} ).done(function( data ) {
alert( 'Page edited!' );
} ).fail( function(code, data) {
console.log( api.getErrorMessage( data ).text());
} );
}
editPage({
title: 'User:' + mw.config.get( 'wgUserName' ) + '/Sandbox',
text: 'Cool! It works! :-) ~~' + '~~',
summary: 'Trying to edit my sandbox [[Project:User scripts/Guide|using API]]...'
});
</syntaxhighlight>
 
===== Using plain jQuery =====
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
// Edit page (must be done through POST)
// the line "text: info.text," will cause the call
// to replace entire page content with supplied data.
// alternatively, one can append or prepend the data to the page, by using
// "appendtext: info.text," or "prependtext: info.text," instead.
// when using "appendtext", it is possible to append the text to a specific section,
// by setting the optional field "section".
function editPage( info ) {
$.ajax({
url: mw.util.wikiScript( 'api' ),
type: 'POST',
dataType: 'json',
data: {
format: 'json',
action: 'edit',
title: info.title,
text: info.text, // will replace entire page content
summary: info.summary,
token: mw.user.tokens.get( 'csrfToken' )
}
})
.then (function( data ) {
if ( data && data.edit && data.edit.result && data.edit.result == 'Success' ) {
alert( 'Page edited!' );
} else {
alert( 'The edit query returned an error. =(' );
}
})
.catch ( function() {
alert( 'The ajax request failed.' );
});
}
editPage({
title: 'User:' + mw.config.get( 'wgUserName' ) + '/Sandbox',
text: 'Cool! It works! :-) ~~' + '~~',
summary: 'Trying to edit my sandbox [[Project:User scripts/Guide/Ajax|using AJAX]]...'
});
</syntaxhighlight>
 
====Load JavaScript from Wiki page====
 
Security warning: Do not load Wikipedia pages that do not end in .js into your script using this method, because anybody can edit those pages.
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">let title = "User:YourName/YourScript.js";
mw.loader.load( "https://en.wikipedia.org/w/index.php?title="+title+"&action=raw&ctype=text/javascript" );</syntaxhighlight>
 
====Load JSON from Wiki page====
 
JSON is useful when you want to import complex data into your script. For example, maybe you have a bot that publishes certain data to a Wiki page regularly, and you want your script to read that data.
 
Careful with <code>ctype</code>. Set it to <code>raw</code> for normal Wiki pages, and <code>application/json</code> for pages where a template editor or admin has set the [https://www.mediawiki.org/wiki/Help:ChangeContentModel Content Model] to JSON.
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">let jsonData;
let title = "User:YourName/YourData.json";
$.getJSON(mw.config.get('wgScriptPath')+'/index.php?action=raw&ctype=application/json&title='+title, function(data){
jsonData = data;
});</syntaxhighlight>
 
== Working with CSS ==
 
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 via [[Special:EditPage/Special:MyPage/common.css|editing your ''User:YourUserName/common.css'' page]].
 
=== Loading a localhost file ===
For local development, you can load a CSS file from your local web server (see the previous section for an easy-to-install web server). Put this line at the top of your [[Special:Mypage/common.css|/common.css]]:
<syntaxhighlight lang="css" style="min-width:fit-content; max-width: 40%">
@import "http://localhost/wikipediatest.css";
</syntaxhighlight>
'''Note!''' Such <code>@import</code> statements must come before any other declarations in your CSS, except comments.
 
An alternative way is to put this line in your [[Special:Mypage/common.js|/common.js]] instead:
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
mw.loader.load( 'http://localhost/wikipediatest.css', 'text/css' );
</syntaxhighlight>
 
=== Publishing a CSS file ===
 
Once you have finished the CSS code, you either need to paste it into your <kbd>/vector.css</kbd> if it is only for personal use. Or if it is for use by others then you should upload it to for instance [[Special:Mypage/yourscript.css|User:Yourname/yourscript.css]]. Then other users can import it by putting the following line in their <kbd>/common.js</kbd> file. Note, that is in their ".js", not their ".css".
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
importStylesheet( 'User:Yourname/yourscript.css' );
</syntaxhighlight>
 
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 <kbd>User:Yourname/yourscript.css</kbd> from their <kbd>/common.css</kbd> 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:
<syntaxhighlight lang="css">
@import "/w/index.php?title=User:Yourname/yourscript.css&action=raw&ctype=text/css";
</syntaxhighlight>
 
==See also==
<source lang="javascript">
* [[mw:Gadget kitchen]]
//Example: modify signature button.
* [[Wikipedia:User scripts/Techniques]]
if (mwEditButtons.length >= 10 && mwEditButtons[9].tagOpen == '--~~~~')
* [[mw:ResourceLoader/Migration guide (users)]]
mwEditButtons[9].tagOpen = ' — ~~~~';
* {{Section link|mw:ResourceLoader/Core modules#jquery}}
</source>
 
==Notes==
Also see [[:en:User:MarkS/Extra_edit_buttons]].
{{reflist|group=n.}}
 
=== EdittoolsReferences ===
{{reflist}}
There is another edit panel under textarea. Usually it's generated from [[MediaWiki:Edittools]] by [[mw:Extension:CharInsert|Extension:CharInsert]] and consists of a lot of javascript links to the <tt>insertTags()</tt>. In English Wikipedia this approach was replaced by [[MediaWiki:Edittools.js]].
 
{{Wikipedia:User scripts/Navbox}}
<source lang="javascript">
{{Wikipedia technical help|collapsed}}
//Example: adding your own quick insert to Edittools
var specialchars = document.getElementById ('editpage-specialchars');
specialchars.innerHTML +=
"<a onclick=\"insertTags('<div>','</div>','');return false\"
href='#'>&lt;div&gt;</a>";
</source>
 
[[Category:Wikipedia scripts| User scripts/Guide]]
There is no crucial difference between toolbar and edittools, you can insert your own custom links into both.
[[Category:Wikipedia how-to]]