User:Inductiveload/Running header.js

/* * Does a lookup two previous Page:* from the current, extract the rh from * its content, insert it in the header after trying to increase the rh page * number. See the FIXME comment(s) for caveats. * * Originally at User:Phe/Running header.js * * To use this script, add the following to your .js: *	 importScript('User:Inductiveload/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 = [-2, -4, 2, 4, -1, 1]; //offsets to try, in order 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) *\|(.*?)\|(.*?)(?:\|(.*?))?\}\}/,     "");    return rh;  }

RunningHeaderAutoComplete.prototype.add_rh = function(rh) {

//remove existing RH   this.header.value = this.header.value.replace(      /\n?/, '');

// 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(/\{\{ *([Rr]h|[Rr]unning header|[[Rr]unningHeader) */, "{{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 = new RegExp("{" +       "{ *([Rr]h|[Rr]unning header|[[Rr]unningHeader) *\\|[^\n<]*}}");      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);

var offset = this.offsets[this.offset]; // console.log("Trying offset: ", offset);

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.set_running_header = function {

if (!this.header) { return; }

this.try_offset; };

function install_css(css) { $('head').append('' + css + ' '); }

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) .click(function(e) {       e.preventDefault;        callback;      }); }

function handle_alt_click(elem, callback) { $(elem).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));