Difference between revisions of "MediaWiki:Gadget-MarkupFormatting.js"
(Add button to the edit toolbar, instead of having only the keyboard shortcut.) |
Dinoguy1000 (talk | contribs) (make sure there's no whitespace before list markup) |
||
(26 intermediate revisions by 2 users not shown) | |||
Line 3: | Line 3: | ||
* Original author is Deltaneos. | * Original author is Deltaneos. | ||
* Adapted to gadget by Becasita. | * Adapted to gadget by Becasita. | ||
− | * @author Deltaneos, Becasita | + | * Further improvements by Dinoguy1000. |
− | * @contact [[User:Becasita]] | + | * @author Deltaneos, Becasita, Dinoguy1000 |
+ | * @contact [[User:Becasita]] <https://yugipedia.com/wiki/User:Becasita> | ||
+ | * @contact [[User:Dinoguy1000]] <https://yugipedia.com/wiki/User:Dinoguy1000> | ||
*/ | */ | ||
( function _gadgetMarkupFormatting( window, $, mw, console ) { | ( function _gadgetMarkupFormatting( window, $, mw, console ) { | ||
"use strict"; | "use strict"; | ||
− | var LAST_LOG = ' | + | var LAST_LOG = '13:11, 17 February 2024 (UTC)'; |
/** | /** | ||
Line 17: | Line 19: | ||
// Get the selected text or all text | // Get the selected text or all text | ||
var selected_text = (window.getSelection().toString()) ? window.getSelection().toString() : text; | var selected_text = (window.getSelection().toString()) ? window.getSelection().toString() : text; | ||
− | var cleaned_text | + | var cleaned_text, pos, max_pos = -1, j; |
− | |||
− | |||
− | |||
− | |||
− | |||
− | // | + | // Normalize whitespace and put each line in an array |
− | + | var lines = selected_text | |
− | var lines | + | // paranoia |
+ | .replace(/\r\n/g, '\n') | ||
+ | // collapse multiple newlines | ||
+ | // "[^\S\n]" selects all whitespace but newlines <https://stackoverflow.com/a/3469155> | ||
+ | .replace(/(?:\n[^\S\n]*){3,}/g, '\n\n') | ||
+ | // replace all non-newline whitespace characters (except the ideographic space) with U+0020 spaces | ||
+ | .replace(/[^\S\n \u3000]/g, ' ') | ||
+ | // collapse multiple spaces | ||
+ | .replace(/ +/g, ' ') | ||
+ | // remove spaces from the ends of lines | ||
+ | .replace(/ +$/gm, '') | ||
+ | // normalize whitespace within template parameter lines | ||
+ | .replace(/^ ?\| ?([^=\n]+?) ?= ?([^\}])/gm, '| $1 = $2') | ||
+ | // split by line | ||
+ | .split('\n'); | ||
// Loop through each line to find the furthest out "=". | // Loop through each line to find the furthest out "=". | ||
for (var i = 0; i < lines.length; i++) | for (var i = 0; i < lines.length; i++) | ||
{ | { | ||
− | pos = | + | pos = lines[i].startsWith('|') ? lines[i].indexOf(' = ') : -1; |
− | if (pos > max_pos) max_pos = pos; | + | if (pos > max_pos) { max_pos = pos; } |
} | } | ||
Line 38: | Line 49: | ||
for (i = 0; i < lines.length; i++) | for (i = 0; i < lines.length; i++) | ||
{ | { | ||
− | // | + | // Only touch lines that start with a pipe and have an equals sign (but not {{=}}) |
− | + | if (lines[i].startsWith('|') && lines[i].indexOf(' = ') > 0) | |
− | |||
− | |||
− | |||
− | |||
{ | { | ||
− | + | // Get the number of spaces to add | |
+ | pos = lines[i].indexOf(' = '); | ||
+ | lines[i] = lines[i].substring(0, pos) + ' '.repeat(max_pos - pos) + lines[i].substring(pos); | ||
} | } | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
− | + | cleaned_text = lines.join('\n'); | |
− | |||
− | |||
− | |||
− | |||
− | for ( | + | // Check for gallery tags |
+ | if (cleaned_text.indexOf('<gallery') > -1) | ||
{ | { | ||
− | // | + | // Get the text inside each set of gallery tags |
− | + | var galleries = cleaned_text.match(/<gallery[^>]*>(\n[^<][^\n]*)+\n<\/gallery>/g); | |
− | + | var gallery_lines; | |
− | + | for (i = 0; i < galleries.length; i++) | |
− | // | + | { |
− | + | // Reset max_pos from previous iterations | |
+ | max_pos = -1; | ||
− | + | // Reduce the spacing around the "|" in each line to a single space. | |
− | + | // Put each line in an array. | |
− | + | gallery_lines = galleries[i].replace(/^([^\|]+?) ?\| ?/gm, '$1 \| ').split('\n'); | |
− | |||
− | |||
− | |||
− | + | // Loop through each line to find the furthest out "|" | |
− | + | for (j = 0; j < gallery_lines.length; j++) | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
{ | { | ||
− | + | pos = gallery_lines[j].indexOf('|'); | |
+ | if (pos > max_pos) { max_pos = pos; } | ||
} | } | ||
− | + | ||
+ | // Check if this gallery needs aligned (some galleries may not have anything but filenames) | ||
+ | if (max_pos > -1) | ||
{ | { | ||
− | space = | + | // Loop through each line again |
+ | for (j = 0; j < gallery_lines.length; j++) | ||
+ | { | ||
+ | if (gallery_lines[j].indexOf('|') > 0) { | ||
+ | // Get the amount of space to add | ||
+ | pos = gallery_lines[j].indexOf('|'); | ||
+ | gallery_lines[j] = gallery_lines[j].substring(0, pos) + ' '.repeat(max_pos - pos) + gallery_lines[j].substring(pos); | ||
+ | } | ||
+ | } | ||
} | } | ||
− | + | cleaned_text = cleaned_text.replace(galleries[i], gallery_lines.join('\n')); | |
− | |||
− | |||
} | } | ||
+ | } | ||
− | + | // Final changes | |
− | + | cleaned_text = cleaned_text | |
+ | // add space between list markup and list item content | ||
+ | .replace(/^ ?([*#:;]+) ?/gm, '$1 ') | ||
+ | // fix [[wikipedia:MOS:LISTGAP]] issues | ||
+ | .replace(/^([*#:;][^\n]+)\n+(?=[*#:;])/gm, '$1\n') | ||
+ | // add space around header content | ||
+ | .replace(/^(=+) ?(.+?) ?\1$/gm, '$1 $2 $1') | ||
+ | // ensure each header is preceded by an empty line | ||
+ | .replace(/\n+((=+) .* \2)/gm, '\n\n$1') | ||
+ | // ensure each header is followed by content on the next line | ||
+ | .replace(/^((=+) .* \2)\n+/gm, '$1\n'); | ||
// Replace the old text with the new text | // Replace the old text with the new text | ||
Line 108: | Line 119: | ||
function doAlign( $textBox ) { | function doAlign( $textBox ) { | ||
− | $textBox. | + | $textBox.val( function( index, text ) { |
return align( text ); | return align( text ); | ||
} ); | } ); | ||
Line 139: | Line 150: | ||
} ); | } ); | ||
− | $( '#wikiEditor-ui-toolbar' ) | + | if ( mw.user.options.get( 'usebetatoolbar' ) == 1 ) { |
− | + | // Enhanced edit toolbar: | |
− | .append( $button ) | + | $( '#wikiEditor-ui-toolbar' ) |
− | + | .find( '.tabs' ) | |
+ | .append( $button ) | ||
+ | ; | ||
+ | } else { | ||
+ | // Classic toolbar: | ||
+ | $( '#toolbar' ).append( | ||
+ | $( '<div>' ) | ||
+ | .addClass( 'mw-toolbar-editbutton' ) | ||
+ | .addClass( 'mw-toolbar-editbutton--custom' ) | ||
+ | .append( $button ) | ||
+ | ); | ||
+ | } | ||
/** | /** | ||
Line 166: | Line 188: | ||
} | } | ||
− | mw.hook( 'wikipage.editform' ).add( init ); | + | mw.hook( 'wikipage.editform' ).add( function() { |
+ | if( mw.config.get('wgNamespaceNumber') !== 10) { | ||
+ | mw.loader.using( 'mediawiki.toolbar' ).then( init ); | ||
+ | } | ||
+ | } ); | ||
console.log( '[Gadget] MarkupFormatting last updated at', LAST_LOG ); | console.log( '[Gadget] MarkupFormatting last updated at', LAST_LOG ); | ||
} )( window, window.jQuery, window.mediaWiki, window.console ); | } )( window, window.jQuery, window.mediaWiki, window.console ); |
Latest revision as of 13:11, 17 February 2024
/**
* Prettifies template transclusions and gallery tags.
* Original author is Deltaneos.
* Adapted to gadget by Becasita.
* Further improvements by Dinoguy1000.
* @author Deltaneos, Becasita, Dinoguy1000
* @contact [[User:Becasita]] <https://yugipedia.com/wiki/User:Becasita>
* @contact [[User:Dinoguy1000]] <https://yugipedia.com/wiki/User:Dinoguy1000>
*/
( function _gadgetMarkupFormatting( window, $, mw, console ) {
"use strict";
var LAST_LOG = '13:11, 17 February 2024 (UTC)';
/**
* By Deltaneos
*/
function align( text ) {
// Get the selected text or all text
var selected_text = (window.getSelection().toString()) ? window.getSelection().toString() : text;
var cleaned_text, pos, max_pos = -1, j;
// Normalize whitespace and put each line in an array
var lines = selected_text
// paranoia
.replace(/\r\n/g, '\n')
// collapse multiple newlines
// "[^\S\n]" selects all whitespace but newlines <https://stackoverflow.com/a/3469155>
.replace(/(?:\n[^\S\n]*){3,}/g, '\n\n')
// replace all non-newline whitespace characters (except the ideographic space) with U+0020 spaces
.replace(/[^\S\n \u3000]/g, ' ')
// collapse multiple spaces
.replace(/ +/g, ' ')
// remove spaces from the ends of lines
.replace(/ +$/gm, '')
// normalize whitespace within template parameter lines
.replace(/^ ?\| ?([^=\n]+?) ?= ?([^\}])/gm, '| $1 = $2')
// split by line
.split('\n');
// Loop through each line to find the furthest out "=".
for (var i = 0; i < lines.length; i++)
{
pos = lines[i].startsWith('|') ? lines[i].indexOf(' = ') : -1;
if (pos > max_pos) { max_pos = pos; }
}
// Loop through each line again
for (i = 0; i < lines.length; i++)
{
// Only touch lines that start with a pipe and have an equals sign (but not {{=}})
if (lines[i].startsWith('|') && lines[i].indexOf(' = ') > 0)
{
// Get the number of spaces to add
pos = lines[i].indexOf(' = ');
lines[i] = lines[i].substring(0, pos) + ' '.repeat(max_pos - pos) + lines[i].substring(pos);
}
}
cleaned_text = lines.join('\n');
// Check for gallery tags
if (cleaned_text.indexOf('<gallery') > -1)
{
// Get the text inside each set of gallery tags
var galleries = cleaned_text.match(/<gallery[^>]*>(\n[^<][^\n]*)+\n<\/gallery>/g);
var gallery_lines;
for (i = 0; i < galleries.length; i++)
{
// Reset max_pos from previous iterations
max_pos = -1;
// Reduce the spacing around the "|" in each line to a single space.
// Put each line in an array.
gallery_lines = galleries[i].replace(/^([^\|]+?) ?\| ?/gm, '$1 \| ').split('\n');
// Loop through each line to find the furthest out "|"
for (j = 0; j < gallery_lines.length; j++)
{
pos = gallery_lines[j].indexOf('|');
if (pos > max_pos) { max_pos = pos; }
}
// Check if this gallery needs aligned (some galleries may not have anything but filenames)
if (max_pos > -1)
{
// Loop through each line again
for (j = 0; j < gallery_lines.length; j++)
{
if (gallery_lines[j].indexOf('|') > 0) {
// Get the amount of space to add
pos = gallery_lines[j].indexOf('|');
gallery_lines[j] = gallery_lines[j].substring(0, pos) + ' '.repeat(max_pos - pos) + gallery_lines[j].substring(pos);
}
}
}
cleaned_text = cleaned_text.replace(galleries[i], gallery_lines.join('\n'));
}
}
// Final changes
cleaned_text = cleaned_text
// add space between list markup and list item content
.replace(/^ ?([*#:;]+) ?/gm, '$1 ')
// fix [[wikipedia:MOS:LISTGAP]] issues
.replace(/^([*#:;][^\n]+)\n+(?=[*#:;])/gm, '$1\n')
// add space around header content
.replace(/^(=+) ?(.+?) ?\1$/gm, '$1 $2 $1')
// ensure each header is preceded by an empty line
.replace(/\n+((=+) .* \2)/gm, '\n\n$1')
// ensure each header is followed by content on the next line
.replace(/^((=+) .* \2)\n+/gm, '$1\n');
// Replace the old text with the new text
return text.replace(selected_text, cleaned_text);
}
function doAlign( $textBox ) {
$textBox.val( function( index, text ) {
return align( text );
} );
}
function init() {
var $editBox = $( '#wpTextbox1' );
if ( !$editBox.length ) {
window.MARKUP_FORMATTING_ONKEYDOWN_SET = function() {
// Nothing, just to prevent errors.
};
return;
}
var $button = $( '<span>', {
id: 'ca-alignText',
'class': 'tab',
html: $( '<a>', {
href: '#',
title: 'Align text.',
text: 'Align text',
} ),
click: function( e ) {
e.preventDefault();
doAlign( $editBox );
},
} );
if ( mw.user.options.get( 'usebetatoolbar' ) == 1 ) {
// Enhanced edit toolbar:
$( '#wikiEditor-ui-toolbar' )
.find( '.tabs' )
.append( $button )
;
} else {
// Classic toolbar:
$( '#toolbar' ).append(
$( '<div>' )
.addClass( 'mw-toolbar-editbutton' )
.addClass( 'mw-toolbar-editbutton--custom' )
.append( $button )
);
}
/**
* To add a keyboard shortcut, add the following to Special:MyPage/common.js
* ```
* mw.loader.using( 'ext.gadget.MarkupFormatting' ).then( function() {
* window.MARKUP_FORMATTING_ONKEYDOWN_SET( function( e ) {
* return // predicate.
* } );
* } );
* ```
* @param {function} keysPredicate Callback that receives
* an onKeydown event and returns a boolean indicating
* when the keydown listeners should be triggered.
*/
window.MARKUP_FORMATTING_ONKEYDOWN_SET = function( keysPredicate ) {
$editBox.keydown( function( e ) {
if ( keysPredicate( e ) ) {
doAlign( $editBox );
}
} );
};
}
mw.hook( 'wikipage.editform' ).add( function() {
if( mw.config.get('wgNamespaceNumber') !== 10) {
mw.loader.using( 'mediawiki.toolbar' ).then( init );
}
} );
console.log( '[Gadget] MarkupFormatting last updated at', LAST_LOG );
} )( window, window.jQuery, window.mediaWiki, window.console );