User:Zackmann08/scripts/indent.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump.
This code will be executed when previewing this page.
This code will be executed when previewing this page.
This user script seems to have a documentation page at User:Zackmann08/scripts/indent.
;
// code copied from [[User:Frietjes/indent.js]]";
importScript('User:Zackmann08/scripts/wait.js');
const MAX_PARAM_LENGTH = 25
var long_labels = [ ];
// -------------------------------------------------------------------------------- //
function wpIndent(s)
{
var alignflag = 0;
// Mangle file/image link
while(s.search(/(\[\[[\t _]*(?:image|file)[\t _]*:[^\[\]=]*)=/gi) >=0 ) {
s = s.replace(/(\[\[[\t _]*(?:image|file)[\t _]*:[^\[\]=]*)=/gi, '$1<!-- FIX EQ MARKER -->');
}
// Mangle html tags
while(s.search(/(<[\t \r\n]*[a-z]+[^<>]*)=/gi) >=0 ) {
s = s.replace(/(<[\t \r\n]*[a-z]+[^<>]*)=/gi, '$1<!-- FIX EQ MARKER -->');
}
// Election box
s = s.replace(/(\{\{[_ ]*[Ee]lection[_ ]*box[^{}\|\r\n]*[a-z])[\t ]*\|[\t ]*([\r\n][\t ]*\|)/g, '$1$2');
// Mark some spacing
s = s.replace(/(= ) (\|)/g, '$1<!-- SPACE MARKER -->$2');
// Some fixes for the case where infoboxes have the pipes at the end of the line
var old = '';
while(s != old) {
old = s;
s = s.replace(/(\{\{[_\t\r\n ]*(?:[Ii]nfobox|[Ss]peciesbox|[Ff]ootball[_ ]*box)(?:\{\{(?:\{\{(?:\{\{[^{}]*\}\}|[^{}])*\}\}|[^{}])*\}\}|[^{}])*)(\|)[\t ]*([\r\n])/gim, '$1$3$2');
}
s = s.replace(/(\{\{[_\t\r\n ]*(?:[Ii]nfobox|[Ss]peciesbox|[Ff]ootball[_ ]*box)(?:\{\{(?:\{\{(?:\{\{[^{}]*\}\}|[^{}])*\}\}|[^{}])*\}\}|[^{}])*)[\t\r\n ]*\|[\t ]*([\r\n][\t ]*\}\})/gi, '$1$2');
s = s.replace(/(\{\{[_\t\r\n ]*(?:[Ii]nfobox|[Ss]peciesbox|[Ff]ootball[_ ]*box)(?:\{\{(?:\{\{(?:\{\{[^{}]*\}\}|[^{}])*\}\}|[^{}])*\}\}|[^{}])*[\r\n])[\t\r\n ]*\|[\t ]*(\}\})/gi, '$1$2');
// Space before end of line
while(s.search(/([^=])[\t ]+[\r\n]/g) >= 0) {
s = s.replace(/([^=])[\t ]+([\r\n])/g, '$1$2');
}
// Unroll infobox
if(s.search(/\{\{[_\t\r\n ]*(?:[Ii]nfobox|[Ss]peciesbox|[Ff]ootball[_ ]*box)/g) >=0 ) {
s = s.replace(/([^\t \r\n])([\t ]*\|[\t ]*[^=\|\[\]\{\]\t ][^=\|\[\]\{\]]*=)/g, '$1\n$2');
s = s.replace(/(=)([\t ]*\|[\t ]*[^=\|\[\]\{\]\t ][^=\|\[\]\{\]]*=)/g, '$1\n$2');
s = s.replace(/([^\t \r\n])[\t \r\n]*(\}\})/g, '$1\n$2'); // put trailing braces on a newline
}
// Add some markers
s = s.replace(/(\|[ ]*(?:[a-z_ ]+)[\t ]*=[^\r\n]*(?:[\r\n][\t ]*♦§[0-9][0-9]*§♦[\t ]*|)*)[\r\n]([\t ]*\|[\t ]*(?:pattern|left|right|body|shorts|socks))/g, '$1<!-- UNGAP MARKER -->\n\n$2');
s = s.replace(/(\|[ ]*(?:league|cup[0-9]+)(?:[ ]*result|)[\t ]*=[^\r\n]*(?:[\r\n][\t ]*♦§[0-9]+§♦[\t ]*|))[\r\n]([\t ]*\|[ ]*(?:[a-z]+ attendance|[a-z]+ topscorer|league scorer))/g, '$1<!-- UNGAP MARKER -->\n\n$2');
s = s.replace(/[\r\n]([\t ]*\|[ ]*prevseason[ ]*=)/g, '<!-- UNGAP MARKER -->\n\n$1');
s = s.replace(/[\t ]*[\r\n][\t ]*([\r\n][\t ]*\|[\t ]*[A-Za-z0-9_\-\t ]*=)/g, '\n<!--\n GAP MARKER\n -->$1');
s = s.replace(/[\r\n][\t ]*[\r\n]/g, '\n<!-- GAP MARKER -->\n');
// Labels that should not be indented
for(var i=0; i < long_labels.length; i++) {
var re = new RegExp('(\\|[\\t ]*)(' + long_labels[i] + ')[\\t ]*=[\\t ]*', 'g');
s = s.replace(re, '$1_FIX_ = <!-- _THIS_LONG_LABEL_ $2 -->');
}
var longRegex = new RegExp('(\\|[\\t ]*)([\\w\/]{' + MAX_PARAM_LENGTH + ',})[\\t ]*=[\\t ]*', 'g');
s = s.replace(longRegex, '$1_FIX_ = <!-- _THIS_LONG_LABEL_ $2 -->');
// uniform pre-pipe indentation
var c0 = s.split(/[\r\n]\|/g).length;
var c1 = s.split(/[\r\n][\t ]\|/g).length;
var c2 = s.split(/[\r\n][\t ][\t ][\t ]*\|/g).length;
if (c0 >= c1 && c0 >= c2) {
s = s.replace(/([\r\n])[\s]*(\|)/g, '$1$2');
} else if (c1 >= c0 && c1 >= c2 ) {
s = s.replace(/([\r\n])[\s]*(\|)/g, '$1 $2');
} else {
s = s.replace(/([\r\n])[\s]*(\|)/g, '$1 $2');
}
// uniform post-pipe indentation
c0 = s.split(/[\r\n][\t ]*\|[^=\|\[\]\{\]\t ]/g).length;
c1 = s.split(/[\r\n][\t ]*\|[\t ][\t ]*[^=\|\[\]\{\]\t ]/g).length;
if (c1 >= c0) {
s = s.replace(/([\r\n][\t ]*\|)[\t ]*([^=\|\[\]\{\]\t ])/g, '$1 $2');
} else {
s = s.replace(/([\r\n][\t ]*\|)[\t ]*([^=\|\[\]\{\]\t ])/g, '$1$2');
}
// flip space and =
s = s.replace(/(\|[^=\|\[\]\{\]\t ][\t ]*)(=)([\t ][\t ][\t ]*)/g, '$1$3$2');
var two_or_more_space_before_equal_count = s.split(/[^=\|\[\]\{\}][\s][\s][\s]*=/g).length - 1;
if (two_or_more_space_before_equal_count > 1) {
// Unalign
s = s.replace(/[\s]*\|[\s]*[\r\n]([\s]*[^=\|\[\]\{\]]*?=)[\t ]*/g, '\n|$1 ');
s = s.replace(/(\|[\s ]*[^=\|\[\]\{\]]*?)[\s]*=[\t ]*/g, '$1 = ');
s = s.replace(/[\r\n]([\s]*[^\s\|])/g, '<!-- ♦§NEWLINE§♦ -->$1');
s = s.replace(/<!--[\s]*<!-- ♦§NEWLINE§♦ -->[\s]*GAP MARKER[\s]*<!-- ♦§NEWLINE§♦ -->[\s]*-->/g, '<!--\n GAP MARKER\n -->');
// Realign
for(var i=40; i>1; i--) {
var r1 = new RegExp('([\\r\\n][\\s]*\\|[^=\\|\\[\\]\\{\\}]{'+(i)+'}=[^\\r\\n]*[\\r\\n][\\s]*\\|[^=\\|\\[\\]\\{\\}]{0,'+(i-1)+'})(=)','g');
while( s.search(r1) > -1) {
s = s.replace(r1, '$1 $2');
}
var r2 = new RegExp('([\\r\\n][\\s]*\\|[^=\\|\\[\\]\\{\\}]{0,'+(i-1)+'})(=[^\\r\\n]*[\\r\\n][\\s]*\\|[^=\\|\\[\\]\\{\\}]{'+(i)+'}=)','g');
while( s.search(r2) > -1) {
s = s.replace(r2, '$1 $2');
}
}
} else if (two_or_more_space_before_equal_count > 0) {
s = s.replace(/([^=\|\[\]\{\}][\s])[\s][\s]*(=)/g, '$1$2');
}
s = s.replace(/<!-- ♦§NEWLINE§♦ -->/g, '\n');
s = s.replace(/<!-- FIX EQ MARKER -->/g, '=');
s = s.replace(/<!-- SPACE MARKER -->/g, ' ');
s = s.replace(/<!--[\s]*GAP MARKER[\s]*-->/g, '');
s = s.replace(/<!--[\s]*UNGAP MARKER[\s]*-->[\t ]*[\r\n][\t ]*[\r\n]*([\s]*)/g, '\n$1');
s = s.replace(/_FIX_[\t ]*=[\t ]*<!--[\t ]* _THIS_LONG_LABEL_ [\t ]*([^<>]*?)[\t ]*-->[\t ]*/g, '$1 = ');
s = s.replace(/([^\|\{\t ])[\t ]*(\|)[\t ]*([\r\n])([^\*:;\{\|])/g, '$1$3$2$4');
s = s.replace(/(\{\{cite[^{}\r\n]*)[\t ][\t ]+([^{}\r\n]*\}\})/g, '$1 $2');
return s;
}
// -------------------------------------------------------------------------------- //
function wpUnsmall(s)
{
var strlist = s.split(/(\{\{[\t \r\n]*(?:[Ii]nfobox|[Ff]ootball[_ ]*box)(?:[^{}]|\{\{(?:(?:[^{}]|\{\{(?:[^{}]|\{\{(?:[^{}]|\{\{[^{}]*\}\})*\}\})*\}\})*|\{\{[^{}]*\}\})*\}\})*\}\})/);
for (i = 0; i < strlist.length; i++) {
s = strlist[i];
if(s.search(/\{\{[_\t\r\n ]*(?:[Ii]nfobox|[Ff]ootball[_ ]*box)/g) >=0 ) {
var stmp = '';
while( stmp != s ) {
stmp = s;
s = s.replace(/(\|[ ]*name[ ]*=[^\[\]\|\{\}]*sm)(all)/gi, '$1<!--MARKER DO NOT FIX MARKER-->$2');
}
s = s.replace(/<[\t ]*\/?[\t ]*small[^<>]*>/gi, '');
s = s.replace(/\{\{small(?:er|)[\t ]*\|[\t ]*1[\t ]*=[\t ]*((?:[^{}]|\{\{(?:(?:[^{}]|\{\{(?:[^{}]|\{\{(?:[^{}]|\{\{[^{}]*\}\})*\}\})*\}\})*|\{\{[^{}]*\}\})*\}\})*?)[\t ]*\}\}/gi, '$1');
s = s.replace(/\{\{small(?:er|)[\t ]*\|((?:[^{}]|\{\{(?:(?:[^{}]|\{\{(?:[^{}]|\{\{[^{}]*\}\})*\}\})*|\{\{[^{}]*\}\})*\}\})*)\}\}/gi, '$1');
s = s.replace(/<!--[ ]*MARKER DO NOT FIX MARKER[ ]*-->/g, '');
strlist[i] = s;
}
}
return strlist.join('');
}
// -------------------------------------------------------------------------------- //
function startIndent(mytxt)
{
// Regular expression which matchs a template arg
var argexp = new RegExp("(\\|[\\s]*[^=\\|\\[\\]\\{\\}]*=[\\s]*)", "gm");
// Internal for and while loop variables
var i=0; var j=0; var loopcount=0;
// Array used to hold the list of unnested templates
var tlist = [];
// Mark dollar signs which are problematic for regexp
mytxt = mytxt.replace(/\$/g, '♦§DOLLAR§♦');
// Remove comments
loopcount = 0;
while( (mytxt.search(/<!--.*?-->/g) >= 0) && (loopcount < 20) ) {
// Split into chunks, isolating the comments
var strlist = mytxt.split(/(<!--.*?-->)/);
// Loop through the chunks, removing the comments templates
for (i = 0; i < strlist.length; i++) {
if( strlist[i].search(/^<!--.*?-->$/) >= 0 ) {
tlist.push(strlist[i]);
strlist[i] = '♦§' + (tlist.length - 1) + '§♦';
}
}
// Join the chunks back together for the next iteration
mytxt = strlist.join('');
loopcount++;
}
var istart = tlist.length;
// Now start unnesting the templates
loopcount = 0;
while( (mytxt.search(/(?:\{\{|\}\})/g) >= 0) && (loopcount < 20) ) {
// Split into chunks, isolating the unnested templates
var strlist = mytxt.split(/(\{\{[^\{\}]*\}\})/);
// Loop through the chunks, removing the unnested templates
for (i = 0; i < strlist.length; i++) {
if( strlist[i].search(/^\{\{[^\{\}]*\}\}$/) >= 0 ) {
tlist.push(strlist[i]);
strlist[i] = '♦§' + (tlist.length - 1) + '§♦';
}
}
// Join the chunks back together for the next iteration
mytxt = strlist.join('');
loopcount++;
}
// Now start indenting the list of unnested templates
for(i=istart; i < tlist.length; ++i) {
tlist[i] = wpIndent(tlist[i]);
}
// Reassemble the article
while(mytxt.search(/♦§[0-9][0-9]*§♦/g) >= 0) {
var n = mytxt.match(/♦§[0-9][0-9]*§♦/)[0].replace(/♦§([0-9]*)§♦/, '$1');
mytxt = mytxt.replace(new RegExp('♦§' + n + '§♦', 'g'), tlist[Number(n)]);
}
mytxt = mytxt.replace(/[\t ]*[\r\n]*[\t ]*[\r\n][\t ]*(\{\{)[\t ]*((?:[Ii]nfobox|[Ss]peciesbox))/g, '\n$1$2');
mytxt = mytxt.replace(/(\{\{[^{}=\|\r\n]*)([\r\n])(\|)[\t ]*(\{\{)/g, '$1$3$2$4');
// Unmark dollar signs which are problematic for regexp
mytxt = mytxt.replace(/♦§DOLLAR§♦/g, '\$');
return mytxt;
}
function indentInfobox(mytxt){
mw.notify('Indenting Infobox!', {type: 'info'})
const regex = /\|\s*((?:header|label|data|class|rowclass|below)\d*[a-d]?)\s*=/g
var full_matches = [...mytxt.matchAll(regex)];
var values = full_matches.map(match => match[1]);
var longest = values.reduce((a, b) => (a.length >= b.length ? a : b));
for (const val of values) {
mytxt = mytxt.replace(new RegExp(`(\\s*)\\|\\s*${RegExp.escape(val)}\\s*=\\s*`), "$1| " + val.padEnd(longest.length+1) + '= ')
}
return mytxt;
}
jQuery(document).ready(function($) {
var myContent = $('#wpTextbox1').textSelection('getContents');
// var myContent = document.getElementsByName('wpTextbox1')[0];
// -------------------------------------------------------------------------------- //
var mysummary = "Cleaning up syntax using [[:en:User:Zackmann08/scripts/indent|indent.js]]";
// var mysummary = "";
if(typeof indenteditsummary == 'string') {mysummary = indenteditsummary;}
var linktext = "Indent";
// -------------------------------------------------------------------------------- //
// Overid default action of marking minor edit when clicking accesskey + I
$("#wpMinoredit").removeAttr("accesskey");
$(document).ready(function() {
if(mw.config.get('wgNamespaceNumber') != -1 && myContent && (mw.config.get('wgPageName') != 'User:Zackmann08/scripts/JWB.js/loader')) {
$(document).keydown(function(event) {
// Check if Control key is pressed (event.ctrlKey)
// Check if Alt key is pressed (event.altKey)
// Check if the 'I' key is pressed (event.which or event.keyCode for 'I' is 73)
if (event.ctrlKey && event.altKey && event.code === 'KeyI') {
// Prevent the default browser action for this key combination (e.g., opening developer tools)
console.log('i shortcut triggered')
event.preventDefault();
wpIndentTemplates(0);
}
});
mw.loader.using(['mediawiki.util']).done( function() {
var portletlink = mw.util.addPortletLink('p-tb', '#', linktext, 't-indent', 'Indent text');
$(portletlink).click(function(e) {
e.preventDefault();
wpIndentTemplates(0);
});
});
(async () => {
await waitForElement("wpMinoredit");
document.getElementById("wpMinoredit").removeAttribute("accesskey");
})();
// Add button to bottom toolbar after the "Show changes" button
mw.loader.using( [ 'oojs-ui-core' ] ).then( function () {
if ( document.getElementById( 'wpDiff' ) ) {
var diff = document.getElementById( 'wpDiffWidget' );
try {
var indentButton = new OO.ui.ButtonWidget();
indentButton.setElementId( 'wpIndent' ).setIcon( 'indent' ).setLabel( 'Indent' );
indentButton.on( 'click', function () {
wpIndentTemplates(0);
});
indentButton.$element.insertBefore( $(diff.nextSibling) );
} catch (err) {
mw.notify('Failed to insert ButtonWidget: ' + err.message, {type: 'warn'});
return;
}
}
});
}
});
// -------------------------------------------------------------------------------- //
function wpIndentTemplates(debugflag)
{
console.log('wpIndentTemplates RAN')
// Copy the contents of the text window so we can modify it without problems
const original = $('#wpTextbox1').textSelection('getContents');
var mytxt = original
if ((mw.config.get('wgCanonicalNamespace') == 'Template' && !mw.config.get('wgPageName').match(/(\/doc|\/testcase)/)) || mw.config.get('wgPageName') == 'User:Zackmann08/indent') {
mytxt = indentInfobox(mytxt);
} else {
mytxt = startIndent(mytxt);
}
// Remove small tags (if opt-in)
if(typeof removesmalltags == 'string' && removesmalltags == 'yes') {
var oldtxt = mytxt;
mytxt = wpUnsmall(mytxt);
if (oldtxt != mytxt) {
mysummary = mysmallsummary;
}
}
if (mytxt != original) {
mw.notify('Indent complete!', {type: 'success'});
// myContent.value = mytxt;
$('#wpTextbox1').textSelection('setContents', mytxt);
var editsummary = document.getElementsByName('wpSummary')[0];
if(typeof editsummary == 'object') {
if (editsummary.value.indexOf(mysummary) == -1) {
if (editsummary.value.match(/[^\*\/\s][^\/\s]?\s*$/)) {
editsummary.value += '; ' + mysummary;
} else {
editsummary.value += mysummary;
}
}
}
} else {
mw.notify('Nothing to indent...', {type: 'error'});
}
}
mw.hook( 'wikiEditor.toolbarReady' ).add( function ( $textarea ) {
$textarea.wikiEditor( 'addToToolbar', {
section: 'main', // Options: 'main', 'advanced'
group: 'insert', // Options: 'format', 'insert', etc.
tools: {
'indent-button': {
type: 'button',
label: 'Indent text', // Button text
icon: '//upload.wikimedia.org/wikipedia/commons/a/a3/OOjs_UI_icon_indent-ltr.svg', // Icon URL
action: {
type: 'callback',
execute: function ( context ) {
wpIndentTemplates(0);
}
}
}
}
} );
} );
// -------------------------------------------------------------------------------- //
});