Wikipedia:User scripts/Guide: Difference between revisions

Content deleted Content added
ce
 
(14 intermediate revisions by 9 users not shown)
Line 28:
To make a [[Hello world]] program, insert the following code into your ''User:YourUserName/common.js'' file:
 
<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.
Line 39:
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%">
// Qwikify
$( document ).ready( function () {
Line 52:
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 () {
Line 69:
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:
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
document.editform.wpTextbox1.value = "{" + "{wikify}}\n\n" + document.editform.wpTextbox1.value;
</syntaxhighlight>
Line 77:
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:
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
function doQwikify() {
document.editform.wpTextbox1.value = "{" + "{wikify}}\n\n" + document.editform.wpTextbox1.value;
Line 86:
And that's it! Combine it all together and it 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 () {
Line 132:
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]]:
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
mw.loader.load( 'https://localhost/wikipediatest.js' );
</syntaxhighlight>
 
In some environmentenvironments, you need to write this likeas:<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>
Line 180:
** [[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]], (mayfor comeKDE-based with Linux)desktops
** [[GNOME Text Editor]], for [[GNOME]]
 
=== JavaScript Debuggers ===
Line 201 ⟶ 203:
One option is <code>[//api.jquery.com/ready/ .ready()]</code> from [[jQuery]].
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
// Define our main function
function myScript() {
Line 215 ⟶ 217:
 
Since the function is called only once, many users prefer to shorten this code with an [[anonymous function]]:
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
$( document ).ready( function () {
// ... code ...
Line 239 ⟶ 241:
Code that works with page content and avoids the aforementioned pitfalls may look like this:
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
mw.hook( 'wikipage.content' ).add( function ( $content ) {
const $target = $content.find( '.targetClass' );
Line 256 ⟶ 258:
</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>.
 
=== Finding elements ===
Every [[HTML]] element is a node in a [[Document Object Model|DOM]] model allowing scripts to access the element, for example, on the following HTML page.
 
<syntaxhighlight lang="html" copy style="min-width:fit-content; max-width: 40%">
<form name="frmname" id="frmid">
<textarea name="txtname" id="txtid"></textarea>
Line 269 ⟶ 271:
 
We can find element <code>textarea</code>:
* Using its <code>id</code>: <syntaxhighlight lang="js" copy style="min-width:fit-content; max-width: 40%" inline>$( '#txtid' )</syntaxhighlight>
* In the array of all elements with the same <code>tag</code>: <syntaxhighlight lang="js" copy style="min-width:fit-content; max-width: 40%" inline>$( 'textarea' )</syntaxhighlight>
* Using an element next to it: <syntaxhighlight lang="js" copy style="min-width:fit-content; max-width: 40%" inline>$( '#neighbor' ).prev()</syntaxhighlight>
* As a child of its parent: <syntaxhighlight lang="js" copy style="min-width:fit-content; max-width: 40%" inline>$( '#frmid' ).children( 'form' )</syntaxhighlight>
* As a form element, using <code>name</code>: <syntaxhighlight lang="js" copy style="min-width:fit-content; max-width: 40%" inline>$( '#frmid [name="txtname"]' )</syntaxhighlight>
 
'' [http://jsfiddle.net/compwhizii/j2QRf/ This example on jsFiddle] ''
 
The [//api.jquery.com jQuery API reference] is an excellent source for documentation.
Line 283 ⟶ 285:
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%">
if ( mw.config.get( 'wgAction' ) === 'history' ) { // Continue only on history pages.
</syntaxhighlight>
* [[: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%">
if ( mw.config.get( 'wgCanonicalNamespace' ) === 'User_talk') { // Continue only on User_talk pages.
</syntaxhighlight><syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
if ( mw.config.get( 'wgPageName' ) === 'Article_name' ) { // Continue only for the article "Article name".
</syntaxhighlight>
 
* Presence of elements (only in second and third parts of the script)<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
function func_start() {
if ( $( '#editForm' ).length == 0 ) return; //No edit form ? exit
Line 324 ⟶ 326:
 
==== Portlet structure ====
<syntaxhighlight lang="html" copy style="min-width:fit-content; max-width: 40%">
<div id="p-myname" class="portlet">
<h5>Header</h5>
Line 349 ⟶ 351:
* <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%">
// Several examples of portlet links
 
Line 368 ⟶ 370:
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.
 
<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>');
Line 382 ⟶ 384:
To hide an element, you can use JQuery's [//api.jquery.com/hide/ <code>.hide()</code>] function.
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
// Example: remove special characters toolbar from edit page
$( '#editpage-specialchars' ).hide();
Line 401 ⟶ 403:
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.
 
<syntaxhighlight lang="js" copy style="min-width:fit-content; max-width: 40%">mw.util.addPortlet('p-twinkle', 'TW', '#p-cactions');
mw.util.addPortletLink('p-twinkle', '#', 'Tag');
mw.util.addPortletLink('p-twinkle', '#', 'CSD');</syntaxhighlight>
Line 410 ⟶ 412:
The most important element on the edit page is a <kbd><textarea></kbd> with the article text inside. You can reference it with
 
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
var $textbox = $( '#wpTextbox1' );
</syntaxhighlight>
 
You can manipulate it using the [https://doc.wikimedia.org/mediawiki-core/master/js/jQueryPlugins.html#module-jquery.textSelection.html jquery.textSelection] ResourceLoader module.
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
var $textbox = $( '#wpTextbox1' );
$textbox.textSelection( 'setContents', 'This is bold!' );
Line 425 ⟶ 427:
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();
Line 440 ⟶ 442:
==== 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 ===
Line 462 ⟶ 484:
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.
Line 474 ⟶ 496:
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>
Line 480 ⟶ 502:
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 */}
Line 502 ⟶ 524:
===== 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 ) {
/* .. */
Line 531 ⟶ 553:
 
===== Using jQuery $.getJSON =====
<syntaxhighlight lang="javascript" copy style="min-width:fit-content; max-width: 40%">
$.getJSON(
mw.util.wikiScript('api'),
Line 558 ⟶ 580:
 
===== 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' )
Line 576 ⟶ 598:
===== 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", {} )
Line 607 ⟶ 629:
 
===== 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
Line 651 ⟶ 673:
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>
 
Line 660 ⟶ 682:
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){
Line 668 ⟶ 690:
== 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 only, 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., But there can be <code>/*except comments */</code> above them.
 
An alternative way is to put this line in your Javascript file[[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>
Line 687 ⟶ 709:
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>