Usuario:Ignacio Rodríguez/TemplateScriptTest.js
(Redirigido desde «Usuario:Ninovolador/TemplateScriptTest.js»)
Nota: Después de publicar, quizás necesite actualizar la caché de su navegador para ver los cambios.
- Firefox/Safari: Mantenga presionada la tecla Shift mientras pulsa el botón Actualizar, o presiona Ctrl+F5 o Ctrl+R (⌘+R en Mac)
- Google Chrome: presione Ctrl+Shift+R (⌘+Shift+R en Mac)
- Internet Explorer/Edge: mantenga presionada Ctrl mientras pulsa Actualizar, o presione Ctrl+F5
- Opera: Presiona Ctrl+F5.
/*
This page defines a TemplateScript library. It's not meant to be referenced
directly. See [[Wikisource:TemplateScript]] for usage.
*/
/* global $, pathoschild */
/**
* TemplateScript adds configurable templates and scripts to the sidebar, and adds an example regex editor.
* @see https://meta.wikimedia.org/wiki/TemplateScript
* @update-token [[File:Pathoschild/templatescript.js]]
*/
// <nowiki>
$.ajax('//tools-static.wmflabs.org/meta/scripts/pathoschild.templatescript.js', { dataType:'script', cache:true }).then(function() {
/*********
** Define library
*********/
pathoschild.TemplateScript.library.define({
key: 'wikisource.proofreading',
name: 'Herramientas de transcripción',
url: '//es.wikisource.org/wiki/Wikisource:TemplateScript',
description: 'Una serie de herramientas para facilitar la <a href="/wiki/Ayuda:Páginas de transcripción">transcripción en el espacio de nombres <tt>Página:</tt></a> Incluye herramientas para mejorar el OCR, agregar encabezados, y otras herramientas de formato.',
categories: [
{
name: 'Herramientas de transcripción',
scripts: [
{ key: 'add-header', name: 'Agregar encabezado', scriptUrl:'Special:MyPage/titulos.js', script: function(editor) { addPageHeader(editor); }, forNamespaces: 'page', accessKey:'3' },
{ key: 'add-footer', name: 'Agregar pie de página', scriptUrl:'Special:MyPage/titulos.js', script: function(editor) { addPageFooter(editor); }, forNamespaces: 'page', accessKey:'4' },
{ key: 'ocr', name: 'OCR (reconocimiento automático de texto)', script: function(editor) { do_hocr(); }, forNamespaces: 'page', accessKey:'1' },
{ key: 'cleanup-ocr', name: 'Limpiar OCR', script: function(editor) { pageCleanup(editor); }, forNamespaces: 'page', accessKey:'2' },
{ key: 'make-refs', name: 'Hacer referencias', script: function(editor) { makeReference(editor); }, forNamespaces: 'page', accessKey:'h' },
{ key: 'smallcaps', name: 'A versalitas', script: function(editor) { smallcaps(editor); }, forNamespaces: 'page' },
{ key: 'uppercase', name: 'A mayúsculas', script: function(editor) { upper(editor); }, forNamespaces: 'page' },
{ key: 'lowercase', name: 'A minúsculas', script: function(editor) { lower(editor); }, forNamespaces: 'page' }
]
}
]
});
/*********
** Page context
*********/
var state = {
initialised: false, // whether the page context has been initialised
page: {
number: null, // the djvu page number extracted from the URL
proofed: null
},
specialFormats: [] // work-specific header template formats
};
/*********
** Private methods
*********/
/**
* Initialise the data needed by the page tools.
*/
var _initialise = function() {
// only initialise once
if(state.initialised)
return;
state.initialised = true;
// get page metadata
//var pn = /\.(?:djvu|pdf)\/([0-9]+)&action=edit/g.exec(location.href);
var pn = obtenerPn();
var pq = document.getElementById('pagequality');
state.page = {
number: pn !== null ? parseInt(pn[1], 10) : null,
proofed: pq && pq.getAttribute('class') && pq.getAttribute('class').match(/quality0|quality[2-4]/)
};
// get user-defined work formats
// expected format:
// {
// title: /History of England /,
// evenHeader: '{{rh|...}}',
// oddHeader: '{{rh|...}}',
// footer: '',
// footerWithReferences: '{{smallrefs}}'
// }
if(window.specialFormats)
//state.specialFormats = state.specialFormats.concat(window.specialFormats);
state.specialFormats = window.specialFormats.concat(state.specialFormats);
};
/**
* Convert the text to title case based on English rules.
* @param {string} text The text to convert.
*/
var obtenerPn = function(){
var pnfc= /\.(?:djvu|pdf)\/([0-9]+)/g.exec($("#firstHeading").html());
window.pn = pnfc !== null ? parseInt(pnfc[1], 10) : null;
return window.pn;
};
var _titlecase = function(text) {
// split text into individual words and examine them one by one
var words = text.toLowerCase().split(" ");
$.each(function(i, word) {
switch(word) {
case "a":
case "á":
case "e":
case "é":
case "i":
case "y":
case "o":
case "ó":
case "u":
case "el":
case "la":
case "los":
case "las":
case "un":
case "una":
case "unos":
case "de":
case "del":
break; // don't capitalise articles, "to" as part of an infinitive, prepositions or short conjunctions
default: // capitalise everything else
words[i] = word.substring(0, 1).toUpperCase() + word.substring(1, words[i].length);
break;
}
});
// capitalise first word regardless
words[0] = words[0].substring(0, 1).toUpperCase() + words[0].substring(1, words[0].length);
// capitalise last word regardless
var last = words.length-1;
words[last] = words[last].substring(0, 1).toUpperCase() + words[last].substring(1, words[last].length);
// reconstruct title
return words.join(' ');
};
/*********
** Script methods
*********/
/**
* Add a {{running header}} template to the page.
* @param {object} editor The script helpers for the page.
*/
var addPageHeader = function(editor) {
_initialise();
obtenerPn();
if(window.pn === null)
return;
var isEven = (window.pn % 2 === 0);
var generic = true;
var headertext = '';
for (var f in state.specialFormats) {
var format = state.specialFormats[f];
if (mw.config.get('wgTitle').match(format.title)) {
headertext = isEven ? format.evenHeader : format.oddHeader;
generic = false;
break;
}
}
// no special header matched, use a generic running header
if (generic) {
if (isEven)
headertext = '{{RH|left='+state.page.number+'|center=}}'; // assume verso, with page number at left
else
headertext = '{{RH|center=|right='+state.page.number+'}}';
}
$('#wpHeaderTextbox').val(function(i, val) {
return $.trim(val + '\n' + headertext);
});
};
/**
* Clean up OCR errors in the text, and push <noinclude> content at the top
* & bottom of the page into the header & footer boxes respectively.
* @param {object} editor The script helpers for the page.
*/
var pageCleanup = function(editor) {
_initialise();
// push <noinclude> content at the top & bottom into the header & footer
if (editor.get().match(/^<noinclude\>/)) {
var text = editor.get();
var e = text.indexOf("</noinclude>");
$('#wpHeaderTextbox').val(function(i, val) {
return $.trim(val + "\n" + text.substr(11, e-11).replace(/^\s+|\s+$/g, ''));
});
editor.set(text.substr(e+12));
}
if (editor.get().match(/<\/noinclude\>$/)) {
var text = editor.get();
var s = text.lastIndexOf("<noinclude>");
$('#wpFooterTextbox').val(function(i, val) {
return $.trim(text.substr(s+11, text.length-s-11-12).replace(/^\s+|\s+$/g, '') + "\n" + val);
});
editor.set(text.substr(0, s));
}
// clean up text
editor
// remove trailing spaces at the end of each line
.replace(/ +\n/g, '\n')
// remove trailing whitespace preceding a hard line break
.replace(/ +<br *\/?>/g, '<br />')
// remove trailing whitespace and numerals at the end of page text
// (numerals are nearly always page numbers in the footer)
.replace(/[\s\d]+$/g, '')
// remove trailing spaces at the end of refs
.replace(/ +<\/ref>/g, '</ref>')
// remove trailing spaces at the end of template calls
.replace(/ +}}/g, '}}')
// convert double-hyphen to mdash (avoiding breaking HTML comment syntax)
.replace(/([^\!])--([^>])/g, '$1—$2')
// remove spacing around mdash, but only if it has spaces on both sides
// (we don't want to remove the trailing space from "...as follows:— ",
// bearing in mind that the space will already be gone if at end of line).
.replace(/ +— +/g, '—')
// join words that are hyphenated across a line break
// (but leave "|-" table syntax alone)
.replace(/([^\|])-\n/g, '$1');
// clean up pages if they don't have <poem>
if (!editor.contains('<poem>')) {
editor
// lines that start with " should probably be new lines,
// if the previous line ends in punctuation,
// other than a comma or semicolon
// and let's get rid of trailing space while we're at it
.replace(/([^\n\w,;])\n\" */g, '$1\n\n"')
// lines that end with " should probably precede a new line,
// unless preceded by a comma,
// or unless the new line starts with a lower-case letter;
// and let's get rid of preceding space while we're at it
.replace(/([^,])\ *\"\n([^a-z\n])/g, '$1"\n\n$2')
// remove single line breaks; preserve multiple.
// but not if there's a tag, template or table syntax either side of the line break
.replace(/([^>}\|\n])\n([^:#\*<{\|\n])/g, '$1 $2')
// collapse sequences of spaces into a single space
.replace(/ +/g, ' ');
}
// more page cleanup
editor
// dump spurious hard breaks at the end of paragraphs
.replace(/<br *\/?>\n\n/g, '\n\n')
// remove unwanted spaces around punctuation marks
.replace(/ ([;:\?!,\.])/g, '$1')
// unicodify
.replace(/—/g, '—')
.replace(/–/g, '–')
.replace(/"/g, '"')
// straighten quotes and apostrophes.
.replace(/[“”]/g, '"')
.replace(/[‘’`]/g, '\'')
//OCR fixes
// números
.replace(/1([^0-9\.\s,;:])/g, 'l$1')
.replace(/0([^0-9\.\s,;:])/g, 'o$1')
.replace(/[58~]([^0-9\.\s,;:])/g, 's$1')
.replace(/([a-zA-Z])6/g, '$1ó')
.replace(/([a-zA-Z])0/g, '$1o')
.replace(/6([^0-9\.\s,;:])/g, 'é$1')
.replace(/_/g, '—')
.replace(/ \(l/g,' d')
.replace(/I\)/g,'P')
.replace(/([a-záéíóú])U/g, '$1u')
//partículas y consonantongos que no existen, o casi no existen en español
.replace(/c([ ,.\n])/,'e$1') // c final --> e
.replace(/ hl([aeiouáéíóú])/g, 'bl$1')
.replace(/hr/g, 'br')
.replace(/cb/g, 'ch')
.replace(/Cb/g, 'Ch')
.replace(/([Aa])1/g, '$1l')
.replace(/tn/g, 'tu')
.replace(/([ae])iite/g,'$1nte')
.replace(/([ae])ute(s?[ ,.\n])/g, '$1nte$2')
.replace(/([scgp])nn/g,'$1un')
.replace(/clel/g, 'del')
.replace(/cou/g, 'con')
.replace(/nii/g, 'mi')
.replace(/ iia/g, ' na')
.replace(/cne/g, 'cue')
.replace(/cleb/g, 'deb')
.replace(/snf/g, 'suf')
.replace(/aiito([ ,.\n])/g, 'anto$1')
.replace(/ln([dn])/g, 'lu$1')
.replace(/rn([pb])/g, 'm$1')
.replace(/ iuc/g, ' inc')
.replace(/ rn/g, ' m')
.replace(/ nne/g, ' nue')
.replace(/clia/g, 'cha')
.replace(/ lia/g, ' ha')
.replace(/([^u])irn/g, '$1im')
.replace(/([ae])iid/g, '$1nd')
.replace(/cli([jrd])/g, 'di$1')
.replace(/clist/g, 'dist')
.replace(/cnto([ ,.\n])/,'ento$1')
.replace(/nndo([ ,.\n])/,'ando$1')
.replace(/ii([ ,.\n])/,'n$1')
.replace(/cl([ ,.\n])/,'d$1')
.replace(/fc/g, 'fe')
.replace(/gnl/g,'gul')
.replace(/nlt/g,'nst')
.replace(/pne/g,'pue')
.replace(/oue/g,'one')
.replace(/xol/g,'xcl')
.replace(/ gn/g,' gu')
.replace(/dn([oa])/g,'du$1')
.replace(/ oo/g,' co')
.replace(/([n])eoe/g,'$1ece')
.replace(/ncs/g,'nes')
//fi --> ñ
.replace(/ afio/g,' año')
.replace(/ifia/g,'iña')
.replace(/afier/g,'añer')
.replace(/tafia/g,'taña')
.replace(/([Ss])efial/g,'$1eñal')
.replace(/([Ss])efior/g,'$1eñor')
.replace(/efio([ .,\n])/g,'eño$1')
.replace(/mafio([ .,\n])/g,'maño$1')
.replace(/trafio/g,'traño')
// OCR a español (gracias Aleator)
.replace(/([Qq])(?:ll|n|li)/g, '$1u')
.replace(/([Qq])(?:o|a|tl|u)([eié])/g, '$1u$2')
.replace(/([Qq])(?:o|a|tl|u)á/g, '$1ué')
.replace(/([Qq])[aou][ceors]/g, '$1ue')
.replace(/([Qq])lll/g, '$1ue')
.replace(/d([A-ZÁÉÍÓÚ])/g,'¿$1')
.replace(/ d([qcdhp])/g,' ¿$1')
.replace(/([a-zó])[Pp]"/g,'$1?"')
.replace(/([a-zó])[Pp]([ .,\n])/g,'$1?$2')
.replace(/ DO /g,' no ')
.replace(/ UTI /g,' un ')
.replace(/ u n /g,' un ')
.replace(/ n /g,' a ')
.replace(/ d /g,' el ')
.replace(/]([a-záéíóú])/g,'l$1')
.replace(/fi/g,'fi')
.replace(/fl/g,'fl')
.replace(/((?!para).{4})noi([ao])/g,'$1nci$2')
.replace(/au([ ,.\n])/g, 'an$1')
.replace(/aha([ ,.\n])/g, 'aba$1')
.replace(/ahan([ ,.\n])/g, 'aban$1')
.replace(/(a[iïíìl!1I]g[anou][nu])/g, 'algun')
.replace(/(ag[un]a)/g, 'agua')
.replace(/ afio /g, ' año ')
.replace(/ ao/g, ' au')
.replace(/ oen/g, ' cen')
.replace(/c[iïíìl!1I][56d][un]([ ,.\n])/g, 'ción$1')
.replace(/oio[un]/g, 'cion ')
.replace(/oió[un]/g, 'ción ')
.replace(/(c[iïíìl!1I][56d][ns][ce][8s] )/g, 'ciones ')
.replace(/( corno )/g, ' como ')
.replace(/( co[un][iïíìl!1I]o )/g, ' como ')
.replace(/( eomo )/g, ' como ')
.replace(/( [oce][op]n )/g, ' con ')
.replace(/(cb)/g, 'ch')
.replace(/c[ïíl!1I]o([ ,.\n])/g, 'cio$1')
.replace(/( c[li]e )/g, ' de ')
.replace(/( d[ocs] )/g, ' de ')
.replace(/( ¿c )/g, ' de ')
.replace(/( c[li][ce]l )/g, ' del ')
.replace(/( d[ce][iïíìl!1I] )/g, ' del ')
.replace(/(d[ce][s8])/g, 'des')
.replace(/(d[iïíìl!1I])/g, 'di')
.replace(/([BE][iïíìl!1I] )/g, 'El ')
.replace(/(EUa )/g, 'Ella ')
.replace(/ eua /g, ' ella')
.replace(/( [ce][iïíìl!1I] )/g, ' el ')
.replace(/( [ce][iïíìl!1I][iïíìl!1I]a)/g, ' ella')
.replace(/( [ce][iïíìl!1I][iïíìl!1I]o)/g, ' ello')
.replace(/(eU)/g, 'ell')
.replace(/(cm)/g, 'em')
.replace(/[BE][nqu] /g, 'En ')
.replace(/ cn/g, ' en')
.replace(/[ce][un]do([ ,.\n])/g, 'endo$1')
.replace(/ [ce][un] /g, ' en ')
.replace(/[ce]n[lt] /g, 'ent ')
.replace(/[ce][un][lt]o[un][ce][ce]s/g, 'entonces')
.replace(/E[un][lt]o[un][ce][ce]s/g, 'Entonces')
.replace(/ [ce]n[it]r[ce]/g, ' entre')
.replace(/ [ce][as] /g, ' es ')
.replace(/[ce][8s][ce]ri/g, 'escri')
.replace(/ [ce][s8][lt]([aáà])([ t])/g, ' est$1$2')
.replace(/ [ce][8s][tl]([aoe])/g, ' est$1')
.replace(/ [ce]t[ce]([.,;:])/g, ' etc$1')
.replace(/ é[8s][tl]([aoe])/g, ' ést$1')
.replace(/exlr/g, 'extr')
.replace(/(g[iïíìl!1I][6é]s)/g, 'glés')
.replace(/g[nu][óé]/g, 'gué')
.replace(/gn[ce]/g, 'gne')
.replace(/gu[ce]/g, 'gue')
.replace(/ha[nu] /g, 'han ')
.replace(/ ba /g, ' ha ')
.replace(/ h[ns]b/g, ' hab')
.replace(/[bh][oe]mbr[ce]/g, 'hombre')
.replace(/(horn)/g, 'hom')
.replace(/ [iïíìl!1]a /g, ' la ')
.replace(/ [iïíìl!1]a[a8s] /g, ' las ')
.replace(/ [iïíìl!1]o /g, ' lo ')
.replace(/ [iïíìl!1]o[a8s] /g, ' los ')
.replace(/(lloa([ ,.\n]))/g, 'llos$1')
.replace(/(llaa([ ,.\n]))/g, 'llas$1')
.replace(/(loient[ec]([ ,.\n]))/g, 'lmente$1')
.replace(/m[ce][un]t[ce]([ ,.\n])/g, 'mente$1')
.replace(/m[ce]ot[ce]([ ,.\n])/g, 'mente$1')
.replace(/ mne/g, ' mue')
.replace(/(Q[anou][ce])/g, 'Que')
.replace(/([çq][anou][ceoa])/g, 'que')
.replace(/([çq]ii[ceo])/g, 'que')
.replace(/q[a-záéíóú]e/g, 'que')
.replace(/q[a-záéíóú]é/g, 'qué')
.replace(/([çq][anou][óé])/g, 'qué')
.replace(/ [sB][ec] /g, ' se ')
.replace(/ sn /g, ' su ')
.replace(/ tau /g, ' tan ')
.replace(/ [un][un] /g, ' un ')
.replace(/ [un](?:[un]|ii)a /g, ' una ')
.replace(/ o[un]a /g, ' una ')
.replace(/ \'?"?[lv] /g, ' y ')
.replace(/(•)/g, '.')
.replace(/[lt!]'/g, 'r')
.replace(/i([A-ZÁÉÍÓÚ])/g,'¡$1')
//paréntesis en palabras
.replace(/\(\)/g,'o')
.replace(/\(\'\)/g,'ó')
.replace(/l\)([a-záéíóú])/g,'b$1')
.replace(/\(\(/g,'«')
.replace(/\)\)/g,'»')
//espacio después de punto o coma
.replace(/(\.)([A-ZÁÉÍÓÚ])/g,'$1 $2')
.replace(/([,;:!\?])([a-záéíóú])/g,'$1 $2')
.replace(/([a-záéíóú][a-záéíóú][a-záéíóú])\. ([a-záéíóú][a-záéíóú])/g,'$1, $2')
.replace(/([a-záéíóú])\'([a-záéíóú])/g,'$1 $2')
.replace(/\.-/g, '.—')
.replace(/\^ /g, ', ')
.replace(/ P /g, '? ')
.replace(/([¿¡]) /g, '$1');
};
/**
* As you work your way through the page, when you encounter a reference, just mark it with <ref></ref> tags and continue.
* Once you've got to the end of the page and proofed the references, simply highlight each reference in turn,
* and use this function to move it to its proper position.
* @param {object} editor The script helpers for the page.
*/
var makeReference = function(editor) {
_initialise();
var editbox = $('#wpTextbox1').get(0);
editbox.focus();
var refStart = editbox.selectionStart;
var refEnd = editbox.selectionEnd;
var firstref = editbox.value.indexOf('<ref></ref>');
if (firstref != -1) {
editbox.value = editbox.value.slice(0,firstref+5)
+ editbox.value.slice(refStart, refEnd)
+ editbox.value.slice(firstref+5, refStart)
+ editbox.value.slice(refEnd);
}
addPageFooter(editor);
};
/**
* Insert formatted references into the footer box if needed.
* @param {object} editor The script helpers for the page.
*/
var addPageFooter = function(editor) {
_initialise();
var editbox = $('#wpTextbox1').get(0);
var footerbox;
var generic;
var format;
var f;
if (editbox.value.indexOf("<ref") == -1 && editbox.value.indexOf("{{#tag:ref") == -1) {
// page contains no refs
generic = true;
for (f in state.specialFormats) {
format = state.specialFormats[f];
if (mw.config.get('wgTitle').match(format.title)) {
footerbox = format.footer;
generic = false;
break;
}
}
// no special footer matched, use just strip out the references tag
if (generic)
footerbox = '';
}
else {
generic = true;
for (f in state.specialFormats) {
format = state.specialFormats[f];
if (mw.config.get('wgTitle').match(format.title)) {
footerbox = format.footerWithReferences;
generic = false;
break;
}
}
// no special footer matched, so use a generic ref tag
if (generic)
footerbox = '{{listaref}}';
}
$('#wpFooterTextbox').val(footerbox);
};
/**
* Mark the selected text with {{sc}}. If the text is uppercase, it will be converted to titlecase.
* @param {object} editor The script helpers for the page.
*/
var smallcaps = function(editor) {
_initialise();
editor.replaceSelection(function(text) {
// Applying small-caps to all-caps text is pointless...
// ... unless the all-caps is OCR of text that is actually small-caps.
// Check if text is all-caps, and if it is, convert it to title case before applying small-caps.
if (text == text.toUpperCase())
text = _titlecase(text);
return '{{may|' + text + '}}';
});
};
/**
* Convert the text to uppercase.
* @param {object} editor The script helpers for the page.
*/
var upper = function(editor) {
_initialise();
editor.replaceSelection(function(text) {
return text.toUpperCase();
});
};
var lower = function(editor) {
_initialise();
editor.replaceSelection(function(text) {
return text.toLowerCase();
});
};
/*global $, mw*/
/*
* Query an ocr for a given Page:, first try to get the hocr text layer as it's available
* for most book, fast and of a better quality. If it fails, try the older and slower
* ocr method. hocr fail around 1/5000 books. ocr should never fails as it use the image
* visible on the Page:.
*/
var lang = mw.config.get( 'wgContentLanguage' );
function disable_input(set)
{
if (set) {
$(document).keyup(function(e) {
if (e.which == 27) { disable_input(false); }
});
}
set ? $('#wsOcr1').off('click') : $('#wsOcr1').on('click', do_hocr);
$('#wpTextbox1').prop('disabled', set);
}
function ocr_callback(data) {
if (data.error) {
alert(data.text);
} else {
// Checking if tb is disabled is required with chrome as ESC doesn't kill
// the query.
var tb = document.getElementById("wpTextbox1");
if (tb.disabled)
tb.value = data.text;
}
disable_input(false);
}
function hocr_callback(data) {
if (data.error) {
// Fallback to the slow way.
disable_input(false);
do_ocr();
return;
} else {
// Checking if tb is disabled is required with chrome as ESC doesn't kill
// the query.
var tb = document.getElementById("wpTextbox1");
if (tb.disabled) {
localStorage.ws_hOCR = data.text;
var text = $(data.text).text();
// Ugly as hell.
text = text.replace(/[ ]*\n[ ]*/g, '\n')
.replace(/\n\n\n\n/g, '@_@_@_@_@_@')
.replace(/\n\n/g, '\n')
.replace(/@_@_@_@_@_@/g, '\n\n')
.replace(/\n\n\n/g, '\n\n');
tb.value = $.trim(text);
}
}
disable_input(false);
}
function do_hocr() {
disable_input(true);
var request_url = '//tools.wmflabs.org/phetools/hocr_cgi.py?cmd=hocr&book='
+ encodeURIComponent(mw.config.get('wgTitle')) + '&lang=' + lang + '&user=' + mw.config.get('wgUserName');
$.getJSON(request_url).done(hocr_callback).fail(do_ocr);
}
function do_ocr() {
if ($( '.prp-page-image img' ).length) {
disable_input(true);
// server side can't use protocol relative url, request it as https:
var url_image = 'https:' + $( '.prp-page-image img' ).attr('src');
var request_url = "//tools.wmflabs.org/phetools/ocr.php?cmd=ocr&url="+url_image+"&lang="+lang+"&user="+mw.config.get('wgUserName');
$.getJSON( request_url ).done( ocr_callback );
}
}
});
// </nowiki>