User:Arcorann/runningheader.js
Jump to navigation
Jump to search
Note: After saving, changes may not occur immediately. Click here to learn how to bypass your browser's cache.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (Cmd-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (Cmd-Shift-R on a Mac)
- Internet Explorer: Hold Ctrl while clicking Refresh, or press Ctrl-F5
- Opera: Clear the cache in Tools → Preferences
For details and instructions about other browsers, see Wikipedia:Bypass your cache.
Code that you insert on this page could contain malicious content capable of compromising your account. If you are unsure whether code you are adding to this page is safe, you can ask at the central discussion page, Scriptorium. The code will be executed when previewing this page under some skins, including Monobook. You can in the interim if you wish to refresh the content sooner under another skin. |
![]() | Documentation for this script can be added at User:Arcorann/runningheader. |
/*
* Running header auto-extraction, edited to adapt to recto-verso header usage
* Does a lookup one page previous for rvh, then two pages previous for rh,
* then tries other pages (-4, +2, +4, +1)
*
* Currently WIP
*
* Derived from MediaWiki:Gadget-RunningHeader.js (User:Inductiveload/Running_header.js)
* Originally at User:Phe/Running header.js
*
*/
( function ( $, mw ) {
'use strict';
// Roman numeral functions
// From http://blog.stevenlevithan.com/archives/javascript-roman-numeral-converter
function int_to_roman( num ) {
if ( Number( num ) === 0 ) {
return false;
}
var digits = String( Number( num ) ).split( '' ),
key = [ '', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM',
'', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC',
'', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'
],
roman = '',
i = 3;
while ( i-- ) {
roman = ( key[ +digits.pop() + ( i * 10 ) ] || '' ) + roman;
}
return Array( +digits.join( '' ) + 1 ).join( 'M' ) + roman;
}
function roman_to_int( in_str ) {
var str = in_str.toUpperCase(),
validator =
/^M*(?:D?C{0,3}|C[MD])(?:L?X{0,3}|X[CL])(?:V?I{0,3}|I[XV])$/,
token = /[MDLV]|C[MD]?|X[CL]?|I[XV]?/g,
key = {
M: 1000,
CM: 900,
D: 500,
CD: 400,
C: 100,
XC: 90,
L: 50,
XL: 40,
X: 10,
IX: 9,
V: 5,
IV: 4,
I: 1
},
num = 0,
m;
if ( !( str && validator.test( str ) ) ) { return false; }
while ( ( m = token.exec( str ) ) ) { num += key[ m[ 0 ] ]; }
return num;
}
var RunningHeaderAutoComplete = function () {
this.offsets_rvh = [ -1, -2, -4, 1, 2, 4 ];
this.offsets_rh = [ -2, -4, 2, 4, -1, 1 ];// offsets to try, in order
this.offsets_fallback = [ -2, -4, 2, 4, -1, 1 ];
this.offset = 0;
// swap the header around if the offset is odd
this.recto_verso_swap_sides = true;
this.flash_textbox = true;
this.header = document.getElementsByName( 'wpHeaderTextbox' )[ 0 ];
};
RunningHeaderAutoComplete.prototype.increment_arabic = function ( rh, inc ) {
try {
// now attempt to increment the number
var r = new RegExp(
'^(.*[\\|][\\[\\( ]*)(\\d+)([\\]\\)\\. ]*[\\|}].*)$' );
var regex_res = r.exec( rh );
var page = Number( r.exec( rh )[ 2 ] ) + inc;
rh = regex_res[ 1 ] + String( page ) + regex_res[ 3 ];
this.add_rh( rh );
return true;
} catch ( err ) {
return false;
}
};
RunningHeaderAutoComplete.prototype.increment_roman = function ( rh, inc ) {
try {
// now attempt to increment a roman numeral
var r = new RegExp(
'^(.*[\\|] *)([ivxlcm]+|[IVXLCM]+)(\\.? *[\\|}].*)$' );
var regex_res = r.exec( rh );
var numeral = regex_res[ 2 ];
var lower_case = false;
if ( numeral.charCodeAt( 0 ) > 96 && numeral.charCodeAt( 0 ) < 123 ) {
lower_case = true;
}
var number = roman_to_int( numeral ) + inc;
numeral = int_to_roman( number );
if ( lower_case ) {
numeral = numeral.toLowerCase();
}
// insert the numeral back into the RH
rh = regex_res[ 1 ] + numeral + regex_res[ 3 ];
this.add_rh( rh );
return true;
} catch ( err ) {
return false;
}
};
RunningHeaderAutoComplete.prototype.swap_rh = function ( rh ) {
rh = rh.replace( /\{\{ *([Rr]h|[Rr]unning header|[[Rr]unningHeader) *\|(.*?)\|(.*?)(?:\|(.*?))?\}\}/,
'{{running header|$4|$3|$2}}' );
return rh;
};
RunningHeaderAutoComplete.prototype.add_rh = function ( rh ) {
// remove existing RH
this.header.value = this.header.value.replace(
/\{\{ *(rh|rh\/\d|running header|rvh|recto-verso header) *\|.*\}\}\n?/i, '' );
// swap sides if the offset is odd
if ( this.recto_verso_swap_sides && ( this.offsets[ this.offset ] % 2 ) !== 0 ) {
rh = this.swap_rh( rh );
} else {
// normalise the template name
rh = rh.replace( /\{\{ *(rh|running ?header) *\|/i, '{{running header|' );
}
var r = new RegExp( /^\s*$/ );
if ( r.test( this.header.value ) ) {
this.header.value = rh;
} else {
this.header.value = rh + '\n' + this.header.value;
}
// flash the textbox
if ( this.flash_textbox ) {
this.header.animate( { backgroundColor: 'lightgreen' }, 500 );
}
};
RunningHeaderAutoComplete.prototype.fill_rh = function ( data ) {
var success = false;
if ( this.header && !data.query.pages[ 0 ].missing ) {
var content = data.query.pages[ 0 ].revisions[ 0 ].slots.main.content;
var r = /\{\{ *(rh|running ?header|rvh|recto-verso header) *\|[^\n<]*\}\}/i;
var match = r.exec( content );
if ( match ) {
// FIXME: needs to be tweaked, actually works only if the first
// rh parameters consisting of only digits or roman numerals is the one to increment
var rh = match[ 0 ];
var pg_offset = this.offsets[ this.offset ];
// try to increment the number
success = this.increment_arabic( rh, -pg_offset );
if ( !success ) { // we failed to get a number, see if there is a roman numeral
success = this.increment_roman( rh, -pg_offset );
}
if ( !success ) {
// we didn't find a number to increment
// set equal to the previous page's header, the user needs to edit by hand
this.add_rh( rh );
}
if ( $( 'prp_header' ).css( 'display' ) == 'none' ) {
// pr_toggle_visibility();
}
}
}
return success;
};
RunningHeaderAutoComplete.prototype.next_offset = function () {
if ( this.offset < this.offsets.length - 1 ) {
this.offset++;
return true;
}
return false;
};
RunningHeaderAutoComplete.prototype.try_offset = function () {
var rhac = this;
var r = new RegExp( '(\\d+)$' );
var page = Number( r.exec( mw.config.get( 'wgPageName' ) )[ 1 ] ) + this.offsets[
this.offset ];
var pagename = mw.config.get( 'wgPageName' ).replace( /\d+$/g, page );
mw.loader.using( [ 'mediawiki.api' ], function () {
var api = new mw.Api();
api.get( {
action: 'query',
prop: 'revisions',
rvprop: 'content',
rvslots: 'main',
titles: pagename,
format: 'json',
formatversion: 2
} )
.done( function ( jsondata ) {
var success = rhac.fill_rh( jsondata );
if ( !success && rhac.next_offset() ) {
rhac.try_offset();
}
} )
.fail( function () {
if ( rhac.next_offset() ) {
rhac.try_offset();
}
} );
} );
};
RunningHeaderAutoComplete.prototype.check_header = function () {
if ( !this.header ) {
return;
}
var rc_rvh = /\{\{(rvh|recto-verso header)/i;
var rc_rh = /\{\{(rh|running ?header)/i;
var rc_temp = /(odd|even|chapter\S)/i;
// check prefilled running header
if (rc_rvh.exec(this.header)) {
this.offsets = this.offsets_rvh;
} else if (rc_rh.exec(this.header)) {
this.offsets = this.offsets_rh;
} else {
this.offsets = this.offsets_fallback;
}
};
RunningHeaderAutoComplete.prototype.set_running_header = function () {
if ( !this.header ) {
return;
}
this.check_header();
this.try_offset();
};
function add_portlet( callback ) {
var portlet = mw.util.addPortletLink(
'p-tb',
'#',
'Running header',
't-running-header',
'Add a running header based on the running headers on surrounding pages'
);
$( portlet )
.on( 'click', function ( e ) {
e.preventDefault();
callback();
} );
}
function handle_alt_click( elem, callback ) {
$( elem ).on( 'click', function ( event ) {
if ( event.altKey ) {
callback();
}
} );
}
if ( [ 'Page' ].indexOf( mw.config.get( 'wgCanonicalNamespace' ) ) !== -1 ) {
var RunningHeaderAutoCompleteInstance = new RunningHeaderAutoComplete();
var go_fn = function () {
RunningHeaderAutoCompleteInstance.set_running_header();
};
add_portlet( go_fn );
handle_alt_click( RunningHeaderAutoCompleteInstance.header, go_fn );
}
}( jQuery, mediaWiki ) );