ویکی اقتباس
urwikiquote
https://ur.wikiquote.org/wiki/%D8%B5%D9%81%D8%AD%DB%81_%D8%A7%D9%88%D9%84
MediaWiki 1.48.0-wmf.1
first-letter
میڈیا
خاص
تبادلۂ خیال
صارف
تبادلۂ خیال صارف
ویکی اقتباس
تبادلۂ خیال ویکی اقتباس
فائل
تبادلۂ خیال فائل
میڈیاویکی
تبادلۂ خیال میڈیاویکی
سانچہ
تبادلۂ خیال سانچہ
معاونت
تبادلۂ خیال معاونت
زمرہ
تبادلۂ خیال زمرہ
TimedText
TimedText talk
ماڈیول
تبادلۂ خیال ماڈیول
Event
Event talk
میڈیاویکی:RefToolbar.js
8
3280
15274
14148
2026-11-02T18:07:46Z
Maintenance script
1230
Use thumb.wikimedia.org for thumbnails ([[phab:T427465]], Operator: Ladsgroup)
15274
javascript
text/javascript
// Todo: make autodate an option in the CiteTemplate object, not a preference
// Global object
if (typeof CiteTB == 'undefined') {
var CiteTB = {
"Templates" : {}, // All templates
"Options" : {}, // Global options
"UserOptions" : {}, // User options
"DefaultOptions" : {}, // Script defaults
"ErrorChecks" : {} // Error check functions
};
}
// only load on edit, unless its a user JS/CSS page
if ((mw.config.get('wgAction') == 'edit' || mw.config.get('wgAction') == 'submit') && !((mw.config.get('wgNamespaceNumber') == 2 || mw.config.get('wgNamespaceNumber') == 4) &&
(mw.config.get('wgPageName').indexOf('.js') != -1 || mw.config.get('wgPageName').indexOf('.css') != -1 ))) {
appendCSS(".cite-form-td {"+
"height: 0 !important;"+
"padding: 0.1em !important;"+
"}");
// Default options, these mainly exist so the script won't break if a new option is added
CiteTB.DefaultOptions = {
"date format" : "<year>-<zmonth>-<zdate>",
"autodate fields" : [],
"months" : ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
"modal" : true,
"autoparse" : false,
"expandtemplates": false
};
// Get an option - user settings override global which override defaults
CiteTB.getOption = function(opt) {
if (CiteTB.UserOptions[opt] != undefined) {
return CiteTB.UserOptions[opt];
} else if (CiteTB.Options[opt] != undefined) {
return CiteTB.Options[opt];
}
return CiteTB.DefaultOptions[opt];
}
CiteTB.init = function() {
/* Main stuff, build the actual toolbar structure
* 1. get the template list, make the dropdown list and set up the template dialog boxes
* 2. actually build the toolbar:
* * A section for cites
* ** dropdown for the templates (previously defined)
* ** button for named refs with a dialog box
* ** button for errorcheck
* 3. add the whole thing to the main toolbar
*/
if (typeof $('div[rel=cites]')[0] != 'undefined') { // Mystery IE bug workaround
return;
}
$('head').trigger('reftoolbarbase');
var $target = $('#wpTextbox1');
var temlist = {};
var d = new Date();
var start = d.getTime();
for (var t in CiteTB.Templates) {
var tem = CiteTB.Templates[t];
sform = CiteTB.escStr(tem.shortform);
var actionobj = {
type: 'dialog',
module: 'cite-dialog-'+sform
};
var dialogobj = {};
dialogobj['cite-dialog-'+sform] = {
resizeme: false,
titleMsg: 'cite-dialog-'+sform,
id: 'citetoolbar-'+sform,
init: function() {},
html: tem.getInitial(),
dialog: {
width:675,
open: function() {
$(this).html(CiteTB.getOpenTemplate().getForm());
$('.cite-prev-parse').on( 'click', CiteTB.prevParseClick);
},
beforeclose: function() {
CiteTB.resetForm();
},
buttons: {
'cite-form-submit': function() {
$.wikiEditor.modules.toolbar.fn.doAction( $(this).data( 'context' ), {
type: 'encapsulate',
options: {
peri: ' '
}
}, $(this) );
var ref = CiteTB.getRef(false, true);
$(this).dialog( 'close' );
$.wikiEditor.modules.toolbar.fn.doAction( $(this).data( 'context' ), {
type: 'encapsulate',
options: {
pre: ref
}
}, $(this) );
},
'cite-form-showhide': CiteTB.showHideExtra,
'cite-refpreview': function() {
var ref = CiteTB.getRef(false, false);
var template = CiteTB.getOpenTemplate();
var div = $("#citetoolbar-"+CiteTB.escStr(template.shortform));
div.find('.cite-preview-label').show();
div.find('.cite-ref-preview').text(ref).show();
if (CiteTB.getOption('autoparse')) {
CiteTB.prevParseClick();
} else {
div.find('.cite-prev-parse').show();
div.find('.cite-prev-parsed-label').hide();
div.find('.cite-preview-parsed').html('');
}
},
'wikieditor-toolbar-tool-link-cancel': function() {
$(this).dialog( 'close' );
},
'cite-form-reset': function() {
CiteTB.resetForm();
}
}
}
};
$target.wikiEditor('addDialog', dialogobj);
if (!CiteTB.getOption('modal')) {
//$('#citetoolbar-'+sform).dialog('option', 'modal', false);
}
temlist[sform] = {label: tem.templatename, action: actionobj };
}
var refsection = {
'sections': {
'cites': {
type: 'toolbar',
labelMsg: 'cite-section-label',
groups: {
'template': {
tools: {
'template': {
type: 'select',
labelMsg: 'cite-template-list',
list: temlist
}
}
},
'namedrefs': {
labelMsg: 'cite-named-refs-label',
tools: {
'nrefs': {
type: 'button',
action: {
type: 'dialog',
module: 'cite-toolbar-namedrefs'
},
icon: '//thumb.wikimedia.org/wikipedia/commons/thumb/b/be/Nuvola_clipboard_lined.svg/60px-Nuvola_clipboard_lined.svg.png',
section: 'cites',
group: 'namedrefs',
labelMsg: 'cite-named-refs-button'
}
}
},
'errorcheck': {
labelMsg: 'cite-errorcheck-label',
tools: {
'echeck': {
type: 'button',
action: {
type: 'dialog',
module: 'cite-toolbar-errorcheck'
},
icon: '//thumb.wikimedia.org/wikipedia/commons/thumb/a/a3/Nuvola_apps_korganizer-NO.png/60px-Nuvola_apps_korganizer-NO.png',
section: 'cites',
group: 'errorcheck',
labelMsg: 'cite-errorcheck-button'
}
}
}
}
}
}
};
var defaultdialogs = {
'cite-toolbar-errorcheck': {
titleMsg: 'cite-errorcheck-label',
id: 'citetoolbar-errorcheck',
resizeme: false,
init: function() {},
html: '<div id="cite-namedref-loading">'+
'<img src="//upload.wikimedia.org/wikipedia/commons/4/42/Loading.gif" />'+
' '+mw.usability.getMsg('cite-loading')+'</div>',
dialog: {
width:550,
open: function() {
CiteTB.loadRefs();
},
buttons: {
'cite-errorcheck-submit': function() {
var errorchecks = $("input[name='cite-err-test']:checked");
var errors = [];
for (var i=0; i<errorchecks.length; i++) {
errors = errors.concat(CiteTB.ErrorChecks[$(errorchecks[i]).val()].run());
}
CiteTB.displayErrors(errors);
$(this).dialog( 'close' );
},
'wikieditor-toolbar-tool-link-cancel': function() {
$(this).dialog( 'close' );
}
}
}
},
'cite-toolbar-namedrefs': {
titleMsg: 'cite-named-refs-title',
resizeme: false,
id: 'citetoolbar-namedrefs',
html: '<div id="cite-namedref-loading">'+
'<img src="//upload.wikimedia.org/wikipedia/commons/4/42/Loading.gif" />'+
' '+mw.usability.getMsg('cite-loading')+'</div>',
init: function() {},
dialog: {
width: 550,
open: function() {
CiteTB.loadRefs();
},
buttons: {
'cite-form-submit': function() {
var refname = $("#cite-namedref-select").val();
if (refname == '') {
return;
}
$.wikiEditor.modules.toolbar.fn.doAction( $(this).data( 'context' ), {
type: 'encapsulate',
options: {
peri: ' '
}
}, $(this) );
$(this).dialog( 'close' );
$.wikiEditor.modules.toolbar.fn.doAction( $(this).data( 'context' ), {
type: 'encapsulate',
options: {
pre: CiteTB.getNamedRef(refname, true)
}
}, $(this) );
},
'wikieditor-toolbar-tool-link-cancel': function() {
$(this).dialog( 'close' );
}
}
}
}
};
$target.wikiEditor('addDialog', defaultdialogs);
$('#citetoolbar-namedrefs').off('dialogopen');
if (!CiteTB.getOption('modal')) {
//$('#citetoolbar-namedrefs').dialog('option', 'modal', false);
//$('#citetoolbar-errorcheck').dialog('option', 'modal', false);
appendCSS(".ui-widget-overlay {"+
"display:none !important;"+
"}");
}
$target.wikiEditor('addToToolbar', refsection);
}
// Load local data - messages, cite templates, etc.
$(document).ready( function() {
switch( wgUserLanguage ) {
case 'en': // English
var RefToolbarMessages = importScript('MediaWiki:RefToolbarMessages-en.js');
break;
case 'de': // German
var RefToolbarMessages = importScript('MediaWiki:RefToolbarMessages-de.js');
break;
default: // Urdu
var RefToolbarMessages = importScript('MediaWiki:RefToolbarMessages-ur.js');
}
});
// Setup the main object
CiteTB.mainRefList = [];
CiteTB.refsLoaded = false;
// REF FUNCTIONS
// Actually assemble a ref from user input
CiteTB.getRef = function(inneronly, forinsert) {
var template = CiteTB.getOpenTemplate();
var templatename = template.templatename;
var res = '';
var refobj = {'shorttag':false};
if (!inneronly) {
var group = $('#cite-'+CiteTB.escStr(template.shortform)+'-group').val();
var refname = $('#cite-'+CiteTB.escStr(template.shortform)+'-name').val();
res += '<ref';
if (refname) {
refname = $.trim(refname);
res+=' name='+CiteTB.getQuotedString(refname);
refobj.refname = refname;
}
if (group) {
group = $.trim(group);
res+=' group='+CiteTB.getQuotedString(group);
refobj.refgroup = group;
}
res+='>';
}
var content ='{{'+templatename;
for( var i=0; i<template.basic.length; i++ ) {
var fieldname = template.basic[i].field;
var field = $('#cite-'+CiteTB.escStr(template.shortform)+'-'+fieldname).val();
if (field) {
content+='|'+fieldname.replace(/_/g, " ")+'=';
content+= $.trim(field.replace("|", "{{!}}"));
}
}
if ($('#cite-form-status').val() != 'closed') {
for( var i=0; i<template.extra.length; i++ ) {
var fieldname = template.extra[i].field;
var field = $('#cite-'+CiteTB.escStr(template.shortform)+'-'+fieldname).val();
if (field) {
content+='|'+fieldname.replace(/_/g, " ")+'=';
content+= $.trim(field.replace("|", "{{!}}"));
}
}
}
content+= '}}';
res+=content;
refobj.content = content;
if (!inneronly) {
res+= '</ref>';
}
if (forinsert) {
CiteTB.mainRefList.push(refobj);
}
return res;
}
// Make a reference to a named ref
CiteTB.getNamedRef = function(refname, forinsert) {
var inner = 'name=';
if (forinsert) {
CiteTB.mainRefList.push( {'shorttag':true, 'refname':refname} );
}
return '<ref name='+CiteTB.getQuotedString(refname)+' />';
}
// Function to load the ref list
CiteTB.loadRefs = function() {
if (CiteTB.refsLoaded) {
return;
}
CiteTB.getPageText(CiteTB.loadRefsInternal);
}
// Function that actually loads the list from the page text
CiteTB.loadRefsInternal = function(text) {
// What this does: extract first name/group extract second name/group shorttag inner content
var refsregex = /< *ref(?: +(name|group) *= *(?:"([^"]*?)"|'([^']*?)'|([^ '"\/\>]*?)) *)? *(?: +(name|group) *= *(?:"([^"]*?)"|'([^']*?)'|([^ '"\/\>]*?)) *)? *(?:\/ *>|>((?:.|\n)*?)< *\/ *ref *>)/gim
// This should work regardless of the quoting used for names/groups and for linebreaks in the inner content
while (true) {
var ref = refsregex.exec(text);
if (ref == null) {
break;
}
var refobj = {};
if (ref[9]) { // Content + short tag check
//alert('"'+ref[9]+'"');
refobj['content'] = ref[9];
refobj['shorttag'] = false;
} else {
refobj['shorttag'] = true;
}
if (ref[1] != '') { // First name/group
if (ref[2]) {
refobj['ref'+ref[1]] = ref[2];
} else if (ref[3]) {
refobj['ref'+ref[1]] = ref[3];
} else {
refobj['ref'+ref[1]] = ref[4];
}
}
if (ref[5] != '') { // Second name/group
if (ref[6]) {
refobj['ref'+ref[5]] = ref[6];
} else if (ref[7]) {
refobj['ref'+ref[5]] = ref[7];
} else {
refobj['ref'+ref[5]] = ref[8];
}
}
CiteTB.mainRefList.push(refobj);
}
CiteTB.refsLoaded = true;
CiteTB.setupErrorCheck();
CiteTB.setupNamedRefs()
}
// AJAX FUNCTIONS
// Parse some wikitext and hand it off to a callback function
CiteTB.parse = function(text, callback) {
$.post( mw.config.get('wgServer')+wgScriptPath+'/api.php',
{action:'parse', title:mw.config.get('wgPageName'), text:text, prop:'text', format:'json'},
function(data) {
var html = data['parse']['text']['*'];
callback(html);
},
'json'
);
}
// Use the API to expand templates on some text
CiteTB.expandtemplates = function(text, callback) {
$.post( mw.config.get('wgServer')+wgScriptPath+'/api.php',
{action:'expandtemplates', title:mw.config.get('wgPageName'), text:text, format:'json'},
function(data) {
var restext = data['expandtemplates']['*'];
callback(restext);
},
'json'
);
}
// Function to get the page text
CiteTB.getPageText = function(callback) {
var section = $("input[name='wpSection']").val();
if ( section != '' ) {
var postdata = {action:'query', prop:'revisions', rvprop:'content', pageids:wgArticleId, format:'json'};
if (CiteTB.getOption('expandtemplates')) {
postdata['rvexpandtemplates'] = '1';
}
$.get( mw.config.get('wgServer')+wgScriptPath+'/api.php',
postdata,
function(data) {
var pagetext = data['query']['pages'][wgArticleId.toString()]['revisions'][0]['*'];
callback(pagetext);
},
'json'
);
} else {
if (CiteTB.getOption('expandtemplates')) {
CiteTB.expandtemplates($('#wpTextbox1').wikiEditor('getContents').text(), callback);
} else {
callback($('#wpTextbox1').wikiEditor('getContents').text());
}
}
}
// Autofill a template from an ID (ISBN, DOI, PMID)
CiteTB.initAutofill = function() {
var elemid = $(this).attr('id');
var res = /^cite\-auto\-(.*?)\-(.*)\-(.*)$/.exec(elemid);
var tem = res[1];
var field = res[2];
var autotype = res[3];
var id = $('#cite-'+tem+'-'+field).val();
if (!id) {
return false;
}
var url = '//toolserver.org/~alexz/ref/lookup.php?';
url+=autotype+'='+encodeURIComponent(id);
url+='&template='+encodeURIComponent(tem);
var s = document.createElement('script');
s.setAttribute('src', url);
s.setAttribute('type', 'text/javascript');
document.getElementsByTagName('head')[0].appendChild(s);
return false;
}
// Callback for autofill
//TODO: Autofill the URL, at least for DOI
CiteTB.autoFill = function(data, template, type) {
var cl = 'cite-'+template+'-';
$('.'+cl+'title').val(data.title);
if ($('.'+cl+'last1')) {
for(var i=0; i<data.authors.length; i++) {
if ($('.'+cl+'last'+(i+1)).length) {
$('.'+cl+'last'+(i+1)).val(data.authors[i][0]);
$('.'+cl+'first'+(i+1)).val(data.authors[i][1]);
} else {
var coauthors = [];
for(var j=i; j<data.authors.length; j++) {
coauthors.push(data.authors[j].join(', '));
}
$('.'+cl+'coauthors').val(coauthors.join(', '));
break;
}
}
} else if($('.'+cl+'author1')) {
for(var i=0; i<data.authors.length; i++) {
if ($('.'+cl+'author'+(i+1)).length) {
$('.'+cl+'author'+(i+1)).val(data.authors[i].join(', '));
} else {
var coauthors = [];
for(var j=i; j<data.authors.length; j++) {
coauthors.push(data.authors[j].join(', '));
}
$('.'+cl+'coauthors').val(coauthors.join(', '));
break;
}
}
} else {
var authors = [];
for(var i=0; j<data.authors.length; j++) {
authors.push(data.authors[j].join(', '));
}
$('.'+cl+'authors').val(authors.join(', '));
}
if (type == 'pmid' || type == 'doi') {
if (type == 'doi') {
var DT = new Date(data.date);
$('.'+cl+'date').val(CiteTB.formatDate(DT));
} else {
$('.'+cl+'date').val(data.date);
}
$('.'+cl+'journal').val(data.journal);
$('.'+cl+'volume').val(data.volume);
$('.'+cl+'issue').val(data.issue);
$('.'+cl+'pages').val(data.pages);
} else if (type == 'isbn') {
$('.'+cl+'publisher').val(data.publisher);
$('.'+cl+'location').val(data.location);
$('.'+cl+'year').val(data.year);
$('.'+cl+'edition').val(data.edition);
}
}
// FORM DIALOG FUNCTIONS
// fill the accessdate param with the current date
CiteTB.fillAccessdate = function() {
var elemid = $(this).attr('id');
var res = /^cite\-date\-(.*?)\-(.*)$/.exec(elemid);
var id = res[1];
var field = res[2];
var DT = new Date();
datestr = CiteTB.formatDate(DT);
datestr= datestr.replace(/1/g, "1").replace(/2/g, "2").replace(/3/g, "3").replace(/4/g, "4").replace(/5/g, "5");
datestr= datestr.replace(/6/g, "6").replace(/7/g, "7").replace(/8/g, "8").replace(/9/g, "9").replace(/0/g, "0");
$('#cite-'+id+'-'+field).val(datestr);
return false;
}
CiteTB.formatDate = function(DT) {
var datestr = CiteTB.getOption('date format');
var zmonth = '';
var month = DT.getUTCMonth()+1;
if (month < 10) {
zmonth = "0"+month.toString();
} else {
zmonth = month.toString();
}
month = month.toString();
var zdate = '';
var date = DT.getUTCDate();
if (date < 10) {
zdate = "0"+date.toString();
} else {
zdate = date.toString();
}
date = date.toString()
datestr = datestr.replace('<date>', date);
datestr = datestr.replace('<month>', month);
datestr = datestr.replace('<zdate>', zdate);
datestr = datestr.replace('<zmonth>', zmonth);
datestr = datestr.replace('<monthname>', CiteTB.getOption('months')[DT.getUTCMonth()]);
datestr = datestr.replace('<year>', DT.getUTCFullYear().toString());
return datestr;
}
// Function called after the ref list is loaded, to actually set the contents of the named ref dialog
// Until the list is loaded, its just a "Loading" placeholder
CiteTB.setupNamedRefs = function() {
var names = []
for( var i=0; i<CiteTB.mainRefList.length; i++) {
if (!CiteTB.mainRefList[i].shorttag && CiteTB.mainRefList[i].refname) {
names.push(CiteTB.mainRefList[i]);
}
}
var stuff = $('<div />')
$('#citetoolbar-namedrefs').html( stuff );
if (names.length == 0) {
stuff.html(mw.usability.getMsg('cite-no-namedrefs'));
} else {
stuff.html(mw.usability.getMsg('cite-namedrefs-intro'));
var select = $('<select id="cite-namedref-select">');
select.append($('<option value="" />').text(mw.usability.getMsg('cite-named-refs-dropdown')));
for(var i=0; i<names.length; i++) {
select.append($('<option />').text(names[i].refname));
}
stuff.after(select);
select.before('<br />');
var prevlabel = $('<div id="cite-nref-preview-label" style="display:none;" />').html(mw.usability.getMsg('cite-raw-preview'));
select.after(prevlabel);
prevlabel.before("<br /><br />");
prevlabel.after('<div id="cite-namedref-preview" style="padding:0.5em; font-size:110%" />');
var parselabel = $('<span id="cite-parsed-label" style="display:none;" />').html(mw.usability.getMsg('cite-parsed-label'));
$('#cite-namedref-preview').after(parselabel);
parselabel.after('<div id="cite-namedref-parsed" style="padding-bottom:0.5em; font-size:110%" />');
var link = $('<a href="#" id="cite-nref-parse" style="margin:0 1em 0 1em; display:none; color:darkblue" />');
link.html(mw.usability.getMsg('cite-form-parse'));
$('#cite-namedref-parsed').after(link);
$("#cite-namedref-select").on( 'change', CiteTB.namedRefSelectClick);
$('#cite-nref-parse').on( 'click', CiteTB.nrefParseClick);
}
}
// Function to get the errorcheck form HTML
CiteTB.setupErrorCheck = function() {
var form = $('<div id="cite-errorcheck-heading" />').html(mw.usability.getMsg('cite-errorcheck-heading'));
var ul = $("<ul id='cite-errcheck-list' />");
for (var t in CiteTB.ErrorChecks) {
test = CiteTB.ErrorChecks[t];
ul.append(test.getRow());
}
form.append(ul);
$('#citetoolbar-errorcheck').html(form);
}
// Callback function for parsed preview
CiteTB.fillNrefPreview = function(parsed) {
$('#cite-parsed-label').show();
$('#cite-namedref-parsed').html(parsed);
}
// Click handler for the named-ref parsed preview
CiteTB.nrefParseClick = function() {
var choice = $("#cite-namedref-select").val();
if (choice == '') {
$('#cite-parsed-label').hide();
$('#cite-namedref-parsed').text('');
return false;
}
$('#cite-nref-parse').hide();
for( var i=0; i<CiteTB.mainRefList.length; i++) {
if (!CiteTB.mainRefList[i].shorttag && CiteTB.mainRefList[i].refname == choice) {
CiteTB.parse(CiteTB.mainRefList[i].content, CiteTB.fillNrefPreview);
return false;
}
}
}
// Click handler for the named-ref dropdown
CiteTB.lastnamedrefchoice = '';
CiteTB.namedRefSelectClick = function() {
var choice = $("#cite-namedref-select").val();
if (CiteTB.lastnamedrefchoice == choice) {
return;
}
CiteTB.lastnamedrefchoice = choice;
$('#cite-parsed-label').hide();
$('#cite-namedref-parsed').text('');
if (choice == '') {
$('#cite-nref-preview-label').hide();
$('#cite-namedref-preview').text('');
$('#cite-nref-parse').hide();
return;
}
for( var i=0; i<CiteTB.mainRefList.length; i++) {
if (!CiteTB.mainRefList[i].shorttag && CiteTB.mainRefList[i].refname == choice) {
$('#cite-nref-preview-label').show();
$('#cite-namedref-preview').text(CiteTB.mainRefList[i].content);
if (CiteTB.getOption('autoparse')) {
CiteTB.nrefParseClick();
} else {
$('#cite-nref-parse').show();
}
}
}
}
// callback function for parsed preview
CiteTB.fillTemplatePreview = function(text) {
var template = CiteTB.getOpenTemplate();
var div = $("#citetoolbar-"+CiteTB.escStr(template.shortform));
div.find('.cite-prev-parsed-label').show();
div.find('.cite-preview-parsed').html(text);
}
// Click handler for template parsed preview
CiteTB.prevParseClick = function() {
var ref = CiteTB.getRef(true, false);
var template = CiteTB.getOpenTemplate();
var div = $("#citetoolbar-"+CiteTB.escStr(template.shortform));
div.find('.cite-prev-parse').hide();
CiteTB.parse(ref, CiteTB.fillTemplatePreview);
}
// Show/hide the extra fields in the dialog box
CiteTB.showHideExtra = function() {
var template = CiteTB.getOpenTemplate();
var div = $("#citetoolbar-"+CiteTB.escStr(template.shortform));
var setting = div.find(".cite-form-status").val();
if ( setting == 'closed' ) {
div.find(".cite-form-status").val('open');
div.find('.cite-extra-fields').show(1, function() {
// jQuery adds "display:block", which screws things up
div.find('.cite-extra-fields').attr('style', 'width:100%; background-color:transparent;');
});
} else {
div.find(".cite-form-status").val('closed')
div.find('.cite-extra-fields').hide();
}
}
// Resets form fields and previews
CiteTB.resetForm = function() {
var template = CiteTB.getOpenTemplate();
var div = $("#citetoolbar-"+CiteTB.escStr(template.shortform));
div.find('.cite-preview-label').hide();
div.find('.cite-ref-preview').text('').hide();
div.find('.cite-prev-parsed-label').hide();
div.find('.cite-preview-parsed').html('');
div.find('.cite-prev-parse').hide();
var id = CiteTB.escStr(template.shortform);
$('#citetoolbar-'+id+' input[type=text]').val('');
}
// STRING UTILITY FUNCTIONS
// Returns a string quoted as necessary for name/group attributes
CiteTB.getQuotedString = function(s) {
var sp = /\s/.test(s); // spaces
var sq = /\'/.test(s); // single quotes
var dq = /\"/.test(s); // double quotes
if (!sp && !sq && !dq) { // No quotes necessary
return s;
} else if (!dq) { // Can use double quotes
return '"'+s+'"';
} else if (!sq) { // Can use single quotes
return "'"+s+"'";
} else { // Has double and single quotes
s = s.replace(/\"/g, '\"');
return '"'+s+'"';
}
}
// Fix up strings for output - capitalize first char, replace underscores with spaces
CiteTB.fixStr = function(s) {
s = s.slice(0,1).toUpperCase() + s.slice(1);
s = s.replace('_',' ');
return s;
}
// Escape spaces and quotes for use in HTML classes/ids
CiteTB.escStr = function(s) {
return s.replace(' ', '-').replace("'", "\'").replace('"', '\"');
}
// MISC FUNCTIONS
// Determine which template form is open, and get the template object for it
CiteTB.getOpenTemplate = function() {
var dialogs = $(".ui-dialog-content.ui-widget-content:visible");
var templatename = $(dialogs[0]).find(".cite-template").val();
var template = null;
return CiteTB.Templates[templatename];
}
// Display the report for the error checks
CiteTB.displayErrors = function(errors) {
$('#cite-err-report').remove();
var table = $('<table id="cite-err-report" style="width:100%; border:1px solid #A9A9A9; background-color:#FFEFD5; padding:0.25em; margin-top:0.5em" />');
$('#editpage-copywarn').before(table);
var tr1 = $('<tr style="width:100%" />');
var th1 = $('<th style="width:60%; font-size:110%" />').html(mw.usability.getMsg('cite-err-report-heading'));
var th2 = $('<th style="text-align:left; width:40%" />');
im = $('<img />').attr('src', '//thumb.wikimedia.org/wikipedia/commons/thumb/5/55/Gtk-stop.svg/20px-Gtk-stop.svg.png');
im.attr('alt', mw.usability.getMsg('cite-err-report-close')).attr('title', mw.usability.getMsg('cite-err-report-close'));
var ad = $('<a id="cite-err-check-close" />').attr('href', '#');
ad.append(im);
th2.append(ad);
tr1.append(th1).append(th2);
table.append(tr1);
$('#cite-err-check-close').on('click', function() { $('#cite-err-report').remove(); });
if (errors.length == 0) {
var tr = $('<tr style="width:100%;" />');
var td = $('<td style="text-align:center; margin:1.5px;" />').html(mw.usability.getMsg('cite-err-report-empty'));
tr.append(td);
table.append(tr);
return;
}
for(var e in errors) {
var err = errors[e];
var tr = $('<tr style="width:100%;" />');
var td1 = $('<td style="border: 1px solid black; margin:1.5px; width:60%" />').html(err.err);
var td2 = $('<td style="border: 1px solid black; margin:1.5px; width:40%" />').html(mw.usability.getMsg(err.msg));
tr.append(td1).append(td2);
table.append(tr);
}
}
} // End of code loaded only on edit
5f3oi8l2l4fo6k6rtw95kkyycna1opi
میڈیاویکی:Gadget-RefToolbarNoDialogs.js
8
3281
15273
14159
2026-11-02T18:07:45Z
Maintenance script
1230
Use thumb.wikimedia.org for thumbnails ([[phab:T427465]], Operator: Ladsgroup)
15273
javascript
text/javascript
var numforms = 0;
var wikEdAutoUpdateUrl;
function refbuttons() {
if (mwCustomEditButtons && (document.getElementById('toolbar') || document.getElementById('wikiEditor-ui-toolbar'))/* && wikEdAutoUpdateUrl == null*/) {
if (document.getElementById('toolbar')) {
button = document.createElement('a');
button.href = "javascript:easyCiteMain()";
button.title = "حوالہ درج کریں";
buttonimage = document.createElement('img');
buttonimage.src = "//upload.wikimedia.org/wikipedia/commons/0/00/Button_easy_cite_%281%29.png";
buttonimage.alt = "Insert footnote";
button.appendChild(buttonimage);
document.getElementById('toolbar').appendChild(button);
} else {
button = document.createElement('a');
button.href = "#";
button.title = "حوالہ درج کریں";
button.id = 'reftoolbar-button';
buttonimage = document.createElement('img');
buttonimage.src = "//thumb.wikimedia.org/wikipedia/commons/thumb/9/9a/Curly_Brackets.svg/40px-Curly_Brackets.svg.png";
buttonimage.alt = "حوالہ درج کریں";
button.classname = "tool tool-button";
buttonimage.style.width = "22px";
buttonimage.style.height = "17px";
buttonimage.style.paddingTop = "5px";
buttonimage.style.paddingLeft = "3px";
button.appendChild(buttonimage)
document.getElementById('wikiEditor-ui-toolbar').childNodes[0].childNodes[1].appendChild(button);
//document.getElementById('reftoolbar-button').onclick = easyCiteMain;
$('#reftoolbar-button').live('click', function() { easyCiteMain(); });
}
if (navigator.userAgent.indexOf('MSIE') == -1) {
citemain = document.createElement('div');
citemain.style.display = 'none';
citemain.setAttribute('Id', 'citeselect');
citemain.appendChild( addOption("citeWeb()", "حوالۂ جال") );
citemain.appendChild( addOption("citeBook()", "حوالۂ کتاب") );
citemain.appendChild( addOption("citeJournal()", "حوالۂ رسالہ") );
citemain.appendChild( addOption("citeNews()", "حوالۂ خبر") );
citemain.appendChild( addOption("citeNamedRef()", "نامزد حوالہ") );
citemain.appendChild( addOption("dispErrors()", "خامی کی پڑتال") );
citemain.appendChild( addOption("hideInitial()", "منسوخ") );
document.getElementById('wpTextbox1').parentNode.insertBefore(citemain, document.getElementById('wpTextbox1'));
}
else {
selection = '<div id="citeselect" style="display:none"><input type="button" value="حوالۂ جال" onclick="citeWeb()" />'+
'<input type="button" value="حوالۂ کتاب" onclick="citeBook()" />'+
'<input type="button" value="حوالۂ رسالہ" onclick="citeJournal()" />'+
'<input type="button" value="حوالۂ خبر" onclick="citeNews()" />'+
'<input type="button" value="نامزد حوالہ" onclick="citeNamedRef()" />'+
'<input type="button" value="خامی کی پڑتال" onclick="dispErrors()" />'+
'<input type="button" value="منسوخ" onclick="hideInitial()" /></div>';
document.getElementById('editform').innerHTML = selection + document.getElementById('editform').innerHTML;
}
}
}
function addOption(script, text) {
option = document.createElement('input');
option.setAttribute('type', 'button');
option.setAttribute('onclick', script);
option.setAttribute("value", text);
return option;
}
function hideInitial() {
document.getElementById('citeselect').style.display = 'none';
oldFormHide();
}
function oldFormHide() {
if (numforms != 0) {
document.getElementById('citediv'+numforms).style.display = 'none';
}
if (document.getElementById('errorform') != null) {
document.getElementById('citeselect').removeChild(document.getElementById('errorform'));
}
}
function easyCiteMain() {
document.getElementById('citeselect').style.display = '';
}
var months = ['جنوری', 'فروری', 'مارچ', 'اپریل', 'مئی', 'جون',
'جولائی', 'اگست', 'ستمبر', 'اکتوبر', 'نومبر', 'دسمبر'];
var citeGlobalDateFormat = "<date> <monthname> <year>";
function getTime() {
var datestr = '';
if (typeof citeUserDateFormat != 'undefined') {
datestr = citeUserDateFormat;
} else {
datestr = citeGlobalDateFormat;
}
var DT = new Date();
var zmonth = '';
var month = DT.getUTCMonth()+1;
if (month < 10) {
zmonth = "0"+month.toString();
} else {
zmonth = month.toString();
}
month = month.toString();
var zdate = '';
var date = DT.getUTCDate()
if (date < 10) {
zdate = "0"+date.toString();
} else {
zdate = date.toString();
}
date = date.toString()
datestr = datestr.replace('<date>', date);
datestr = datestr.replace('<month>', month);
datestr = datestr.replace('<zdate>', zdate);
datestr = datestr.replace('<zmonth>', zmonth);
datestr = datestr.replace('<monthname>', months[DT.getUTCMonth()]);
datestr = datestr.replace('<year>', DT.getUTCFullYear().toString());
return (datestr);
}
function citeWeb() {
citeNewsWeb("حوالہ جال/آلہ");
}
function citeNews() {
citeNewsWeb("حوالہ خبر/آلہ");
}
function citeNewsWeb(templatename) {
oldFormHide();
template = templatename;
var legend;
if (template == "حوالہ جال") {
legend = "ماخذ حوالہ جال";
} else {
legend = "ماخذ حوالہ خبر";
}
newtime = getTime();
numforms++;
form = '<div id="citediv'+numforms+'">'+
'<fieldset><legend>'+legend+'</legend>'+
'<table cellspacing="5">'+
'<input type="hidden" value="'+template+'" id="template">'+
'<tr><td width="120"><label for="url"> ربط: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="url"></td>'+
'<td width="120"><label for="title"> عنوان: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="title"></td></tr>'+
'<tr><td width="120"><label for="last"> آخری نام: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="last"></td>'+
'<td width="120"><label for="first"> پہلا نام: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="first"></td></tr>'+
'<tr><td width="120"><label for="coauthors"> دیگر مصنفین: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="coauthors"></td>'+
'<td width="120"><label for="date"> تاریخ اشاعت: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="date"></td></tr>'+
'<tr><td width="120"><label for="work"> تصنیف: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="work"></td>'+
'<td width="120"><label for="publisher"> ناشر: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="publisher"></td></tr>'+
'<tr><td width="120"><label for="pages"> صفحات: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="pages"></td>'+
'<td width="120"><label for="language"> زبان: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="language"></td></tr>'+
'<tr><td width="120"><label for="accessdate"> تاریخ حصولیابی: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="accessdate" value="'+ newtime +'"></td>'+
'<td width="120"><label for="location"> مقام: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="location"></td></tr>'+
'<tr><td width="120"><label for="refname"> نام حوالہ: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="refname"></td></tr>'+
'</table>'+
'<input type="button" value="حوالہ درج کریں" onClick="addcites()">'+
'</fieldset></div>';
document.getElementById('citeselect').innerHTML += form;
}
function citeBook() {
oldFormHide();
template = "حوالہ کتاب/آلہ";
numforms++;
form = '<div id="citediv'+numforms+'">'+
'<fieldset><legend>ماخذ حوالہ کتاب</legend>'+
'<table cellspacing="5">'+
'<input type="hidden" value="'+template+'" id="template">'+
'<tr><td width="120"><label for="last"> آخری نام: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="last"></td>'+
'<td width="120"><label for="first"> پہلا نام: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="first"></td></tr>'+
'<tr><td width="120"><label for="coauthors"> دیگر مصنفین: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="coauthors"></td>'+
'<td width="120"><label for="others"> دیگر: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="others"></td></tr>'+
'<tr><td width="120"><label for="title"> عنوان: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="title"></td>'+
'<td width="120"><label for="editor"> مرتب: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="editor"></td></tr>'+
'<tr><td width="120"><label for="publisher"> ناشر: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="publisher"></td>'+
'<td width="120"><label for="location"> مقام: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="location"></td></tr>'+
'<tr><td width="120"><label for="date"> تاریخ اشاعت: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="date"></td>'+
'<td width="120"><label for="edition"> اشاعت: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="edition"></td></tr>'+
'<tr><td width="120"><label for="series"> سلسلہ: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="series"></td>'+
'<td width="120"><label for="volume"> جلد: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="volume"></td></tr>'+
'<tr><td width="120"><label for="pages"> صفحات: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="pages"></td>'+
'<td width="120"><label for="chapter"> باب: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="chapter"></td></tr>'+
'<tr><td width="120"><label for="isbn"> ISBN: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="isbn"></td>'+
'<td width="120"><label for="oclc"> OCLC: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="oclc"></td></tr>'+
'<tr><td width="120"><label for="url"> ربط: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="url"></td>'+
'<td width="120"><label for="accessdate"> تاریخ حصولیابی: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="accessdate"></td></tr>'+
'<tr><td width="120"><label for="language"> زبان: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="language"></td>'+
'<td width="120"><label for="refname"> نام حوالہ: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="refname"></td></tr>'+
'</table>'+
'<input type="button" value="حوالہ درج کریں" onClick="addcites()">'+
'</fieldset></div>';
document.getElementById('citeselect').innerHTML += form;
}
function citeJournal() {
oldFormHide();
template = "حوالہ رسالہ";
numforms++;
form = '<div id="citediv'+numforms+'">'+
'<fieldset><legend>ماخذ حوالہ رسالہ</legend>'+
'<table cellspacing="5">'+
'<input type="hidden" value="'+template+'" id="template">'+
'<tr><td width="120"><label for="last"> آخری نام: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="last"></td>'+
'<td width="120"><label for="first"> پہلا نام: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="first"></td></tr>'+
'<tr><td width="120"><label for="coauthors"> دیگر مصنفین: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="coauthors"></td>'+
'<td width="120"><label for="date"> تاریخ اشاعت: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="date"></td></tr>'+
'<tr><td width="120"><label for="title"> عنوان: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="title"></td>'+
'<td width="120"><label for="journal"> رسالہ: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="journal"></td></tr>'+
'<tr><td width="120"><label for="publisher"> ناشر: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="publisher"></td>'+
'<td width="120"><label for="location"> مقام: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="location"></td></tr>'+
'<tr><td width="120"><label for="volume"> جلد: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="volume"></td>'+
'<td width="120"><label for="issue"> شمارہ: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="issue"></td></tr>'+
'<tr><td width="120"><label for="pages"> صفحات: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="pages"></td>'+
'<td width="120"><label for="issn"> ISSN: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="issn"></td></tr>'+
'<tr><td width="120"><label for="oclc"> OCLC: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="oclc"></td>'+
'<td width="120"><label for="language"> زبان: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="language"></td></tr>'+
'<tr><td width="120"><label for="url"> ربط: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="url"></td>'+
'<td width="120"><label for="accessdate"> تاریخ حصولیابی: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="accessdate"></td></tr>'+
'<tr><td width="120"><label for="refname"> نام حوالہ: </label></td>'+
'<td width="400"><input type="text" tabindex=1 style="width:100%" id="refname"></td></tr>'+
'</table>'+
'<input type="button" value="حوالہ درج کریں" onClick="addcites()">'+
'</fieldset></div>';
document.getElementById('citeselect').innerHTML += form;
}
function addcites(template) {
cites = document.getElementById('citediv'+numforms).getElementsByTagName('input');
var citebegin = '<ref';
var citename = '';
var citeinner = '';
for (var i=0; i<cites.length-1; i++) {
if (cites[i].value != '' && cites[i].id != "refname" && cites[i].id != "template") {
citeinner += "|" + cites[i].id + "=" + cites[i].value;
}
else if (cites[i].value != '' && cites[i].id == "refname" && cites[i].id != "template") {
citebegin += ' name="' + cites[i].value + '"';
}
else if (cites[i].value != '' && cites[i].id != "refname" && cites[i].id == "template") {
citename = '>{{' + cites[i].value;
}
}
cite = citebegin + citename + citeinner + "}}</ref>";
insertTags(cite, '', '');
document.getElementById('citediv'+numforms).style.display = 'none';
}
function getNamedRefs(calls) {
if (typeof(wikEdUseWikEd) != 'undefined') {
if (wikEdUseWikEd == true) {
WikEdUpdateTextarea();
}
}
text = document.getElementById('wpTextbox1').value;
var regex;
if (calls) {
regex = /< *?ref +?name *?= *?(('([^']*?)')|("([^"]*?)")|([^'"\s]*?[^\/]\b)) *?\/ *?>/gi //'
} else {
regex = /< *?ref +?name *?= *?(('([^']*?)')|("([^"]*?)")|([^'"\s]*?[^\/]\b)) *?>/gi //'
}
var namedrefs = new Array();
var i=0;
var nr=true;
do {
ref = regex.exec(text);
if(ref != null){
if (ref[5]) {
namedrefs[i] = ref[5];
} else if (ref[3]) {
namedrefs[i] = ref[3];
} else {
namedrefs[i] = ref[6];
}
i++;
} else {
nr=false;
}
} while (nr==true);
return namedrefs;
}
function citeNamedRef() {
namedrefs = getNamedRefs(false);
if (namedrefs == '') {
oldFormHide();
numforms++;
out = '<div id="citediv'+numforms+'"><fieldset>'+
'<legend>متن میں حوالہ جات</legend>کوئی نامزد حوالہ موجود نہیں (<tt><ref name="نام"></tt>) متن میں</fieldset></div>';
document.getElementById('citeselect').innerHTML += out;
}
else {
oldFormHide();
numforms++;
form = '<div id="citediv'+numforms+'">'+
'<fieldset><legend>مضمون میں حوالہ جات</legend>'+
'<table cellspacing="5">'+
'<tr><td><label for="namedrefs"> نامزد حوالہ جات متن میں</label></td>'+
'<td><select name="namedrefs" id="namedrefs">';
for (var i=0;i<namedrefs.length;i++) {
form+= '<option value="'+namedrefs[i]+'">'+namedrefs[i]+'</option>';
}
form+= '</select>'+
'</td></tr></table>'+
'<input type="button" value="حوالہ درج کریں" onClick="addnamedcite()">'+
'</fieldset></div>';
document.getElementById('citeselect').innerHTML += form;
}
}
function addnamedcite() {
name = document.getElementById('citediv'+numforms).getElementsByTagName('select')[0].value;
ref = '<ref name="'+name+'" />';
insertTags(ref, '', '');
document.getElementById('citediv'+numforms).style.display = 'none';
}
function getAllRefs() {
if (typeof(wikEdUseWikEd) != 'undefined') {
if (wikEdUseWikEd == true) {
WikEdUpdateTextarea();
}
}
text = document.getElementById('wpTextbox1').value;
regex = /< *?ref( +?name *?= *?(('([^']*?)')|("([^"]*?)")|([^'"\s]*?[^\/]\b)))? *?>((.|\n)*?)< *?\/? *?ref *?>/gim //"
var allrefs = new Array();
var i=0;
var nr=true;
do {
ref = regex.exec(text);
if(ref != null){
if (ref[0].search(/[^\s]{150}/) != -1) {
ref[0] = ref[0].replace(/\|([^\s])/g, "| $1");
}
ref[0] = ref[0].replace(/</g, "<");
ref[0] = ref[0].replace(/>/g, ">");
allrefs[i] = ref[0];
i++;
} else {
nr=false;
}
} while (nr==true);
return allrefs;
}
function NRcallError(namedrefs, refname) {
for (var i=0; i<namedrefs.length; i++) {
if (namedrefs[i] == refname) {
return true;
}
}
return false;
}
function errorCheck() {
var allrefs = getAllRefs();
var allrefscontent = new Array();
var samecontentexclude = new Array();
var sx=0;
var templateexclude = new Array();
var tx=0;
var skipcheck = false;
var namedrefcalls = getNamedRefs(true);
for (var i=0; i<allrefs.length; i++) {
allrefscontent[i] = allrefs[i].replace(/< *?ref( +?name *?= *?(('([^']*?)')|("([^"]*?)")|([^'"\s]*?[^\/]\b)))? *?>((.|\n)*?)< *?\/? *?ref *?>/gim, "$8"); //"
}
var namedrefs = getNamedRefs(false);
var errorlist = new Array();
var q=0;
unclosed = document.getElementById('unclosed').checked;
samecontent = document.getElementById('samecontent').checked;
templates = document.getElementById('templates').checked;
repeated = document.getElementById('repeated').checked;
undef = document.getElementById('undef').checked;
for (var i=0; i<allrefs.length; i++) {
if (allrefs[i].search(/< *?\/ *?ref *?>/) == -1 && unclosed) {
errorlist[q] = '<tr><td width="75%"><tt>'+allrefs[i]+'</tt></td>';
errorlist[q] += '<td width="25%">Unclosed <tt><ref></tt> tag</td></tr>';
q++;
}
if (samecontent) {
for (var d=0; d<samecontentexclude.length; d++) {
if (allrefscontent[i] == samecontentexclude[d]) {
skipcheck = true;
}
}
var p=0;
while (p<allrefs.length && !skipcheck) {
if (allrefscontent[i] == allrefscontent[p] && i != p) {
errorlist[q] = '<tr><td width="75%"><tt>'+allrefscontent[i]+'</tt></td>';
errorlist[q] += '<td width="25%">Multiple refs contain this content, a <a href="//en.wikipedia.org/wiki/Wikipedia:Footnotes#Naming_a_ref_tag_so_it_can_be_used_more_than_once">named reference</a> should be used instead</td></tr>';
q++;
samecontentexclude[sx] = allrefscontent[i]
sx++;
break;
}
p++;
}
skipcheck=false;
}
if (templates) {
if (allrefscontent[i].search(/\{\{cite/i) == -1 && allrefscontent[i].search(/\{\{citation/i) == -1 && allrefscontent[i].search(/\{\{Comic (book|strip) reference/i) == -1 && allrefscontent[i].search(/\{\{Editorial cartoon reference/i) == -1 && allrefscontent[i].search(/\{\{harv/i) == -1) {
for (var x=0; x<templateexclude.length; x++) {
if (allrefscontent[i] == templateexclude[x]) {
skipcheck = true;
}
}
if (!skipcheck) {
errorlist[q] = '<tr><td width="75%"><tt>'+allrefs[i]+'</tt></td>';
errorlist[q] += '<td width="25%">Does not use a <a href="//en.wikipedia.org/wiki/Wikipedia:Citation_templates">citation template</a></td></tr>';
q++;
templateexclude[tx] = allrefscontent[i];
tx++;
}
skipcheck = false;
}
}
}
if (repeated) {
var repeatnameexclude = new Array();
var rx=0;
for (var k=0; k<namedrefs.length; k++) {
for (var d=0; d<repeatnameexclude.length; d++) {
if (namedrefs[k] == repeatnameexclude[d]) {
skipcheck = true;
}
}
var z=0;
while (z<namedrefs.length && !skipcheck) {
if (namedrefs[k] == namedrefs[z] && k != z) {
errorlist[q] = '<tr><td width="75%"><tt>'+namedrefs[k]+'</tt></td>';
errorlist[q] += '<td width="25%">متعدد حوالہ جات <a href="//en.wikipedia.org/wiki/Wikipedia:Footnotes#Naming_a_ref_tag_so_it_can_be_used_more_than_once">ایک نام</a></td></tr> سے دیے جارہے ہیں';
q++;
repeatnameexclude[rx] = namedrefs[z];
rx++;
break;
}
z++;
}
skipcheck = false;
}
}
if (undef) {
var undefexclude = new Array();
var ux=0;
for (var p=0; p<namedrefcalls.length; p++) {
for (var d=0; d<undefexclude.length; d++) {
if (allrefscontent[i] == undefexclude[d]) {
skipcheck = true;
}
}
if (!skipcheck) {
if (!NRcallError(namedrefs, namedrefcalls[p])) {
errorlist[q] = '<tr><td width="75%"><tt>'+namedrefcalls[p]+'</tt></td>';
errorlist[q] += '<td width="25%">ایک <a href="//en.wikipedia.org/wiki/Wikipedia:Footnotes#Naming_a_ref_tag_so_it_can_be_used_more_than_once">نامزد حوالہ</a> استعمال کیا جارہا ہے لیکن وضاحت نہیں کی گئی</td></tr>';
q++;
undefexclude[ux] = namedrefs[p];
ux++;
}
}
skipcheck = false;
}
}
if (q > 0) {
return errorlist;
} else {
return 0;
}
}
function dispErrors() {
oldFormHide();
form = '<div id="errorform"><fieldset>'+
'<legend>خامی کی پڑتال</legend>'+
'<b>پڑتال برائے:</b><br/>'+
'<input type="checkbox" id="unclosed" /> مفتوح <tt><ref></tt> ٹیگز<br/>'+
'<input type="checkbox" id="samecontent" /> یکساں مواد پر مشتمل حوالہ جات<br/>'+
'<input type="checkbox" id="templates" /> حوالہ جات جو <a href="//en.wikipedia.org/wiki/Wikipedia:Citation_templates">حوالہ جاتی سانچہ</a><br/> استعمال نہیں کرتے'+
'<input type="checkbox" id="repeated" /> ایک جیسے نام والے متعدد حوالہ جات<br/>'+
'<input type="checkbox" id="undef" /> غیر واضح نامزد حوالہ جات کا استعمال<br/>'+
'<input type="button" id="errorchecksubmit" value="پڑتال برائے منتخب خامی" onclick="doErrorCheck()"/>'+
'</fieldset></div>';
document.getElementById('citeselect').innerHTML += form;
}
function doErrorCheck() {
var errors = errorCheck();
document.getElementById('citeselect').removeChild(document.getElementById('errorform'));
if (errors == 0) {
if (numforms != 0) {
document.getElementById('citediv'+numforms).style.display = 'none';
}
numforms++;
out = '<div id="citediv'+numforms+'"><fieldset>'+
'<legend>خامی کی پڑتال</legend>کوئی خامی نہیں۔</fieldset></div>';
document.getElementById('citeselect').innerHTML += out;
}
else {
if (numforms != 0) {
document.getElementById('citediv'+numforms).style.display = 'none';
}
numforms++;
form = '<div id="citediv'+numforms+'">'+
'<fieldset><legend>خامی کی پڑتال</legend>'+
'<table border="1px">';
for (var i=0; i<errors.length; i++) {
form+=errors[i];
}
form+= '</table>'+
'</fieldset></div>';
document.getElementById('citeselect').innerHTML += form;
}
}
$( refbuttons );
d0u0o84xmszneie5726acz74x0t9e0v
میڈیاویکی:Gadget-HotCat.js
8
3288
15272
8258
2026-11-02T18:07:44Z
Maintenance script
1230
Use thumb.wikimedia.org for thumbnails ([[phab:T427465]], Operator: Ladsgroup)
15272
javascript
text/javascript
//<source lang="javascript">
/*
HotCat V2.31
Ajax-based simple Category manager. Allows adding/removing/changing categories on a page view.
Supports multiple category changes, as well as redirect and disambiguation resolution. Also
plugs into the upload form. Search engines to use for the suggestion list are configurable, and
can be selected interactively.
Documentation: https://commons.wikimedia.org/wiki/Help:Gadget-HotCat
List of main authors: https://commons.wikimedia.org/wiki/Help:Gadget-HotCat/Version_history
License: Quadruple licensed GFDL, GPL, LGPL and Creative Commons Attribution 3.0 (CC-BY-3.0)
Choose whichever license of these you like best :-)
*/
/*
This code is MW version safe. It should run on any MediaWiki installation >= MW 1.15. Note
that HotCat is supposed to run with or without jQuery, and also on older installations that
do not yet have window.mw. If you use any of these newer features, make sure you qualify them
by checking whether they exist at all, and by providing some meaningful fallback implementation
if not. To start itself, HotCat uses jQuery(document).ready(). If it doesn't exist, HotCat won't
start.
*/
/* jshint ignore:start */ // This old code uses too many coding conventions incompatible with jshint.
(function () {
// Support: MW 1.16
var conf = window.mw ? mw.config.get() : window;
if (
// Guard against double inclusions (in old IE/Opera element ids become window properties)
(window.HotCat && !window.HotCat.nodeName)
// Not on edit pages
|| conf.wgAction == 'edit'
) {
return;
}
// Configuration stuff.
window.HotCat = {
// Localize these messages to the main language of your wiki.
messages :
{ cat_removed : 'نے [[زمرہ:$1]] ہٹایا'
,template_removed : 'نے {{[[زمرہ:$1]]}} ہٹایا'
,cat_added : 'نے [[زمرہ:$1]] کا اضافہ کیا'
,cat_keychange: 'نئی کلید برائے [[زمرہ:$1]]: "$2"' // $2 نئی کلید ہے
,cat_notFound : 'زمرہ "$1" موجود نہیں ہے'
,cat_exists : 'زمرہ "$1" پہلے سے موجود ہے؛ اس کا اضافہ نہیں کیا جاسکتا.'
,cat_resolved : ' (redirect [[Category:$1]] resolved)'
,uncat_removed: 'removed {{uncategorized}}'
,separator : '؛ '
,prefix : ""
// Some text to prefix to the edit summary.
,using : ' [[ویکیپیڈیا:فوری زمرہ بندی|فوری زمرہ بندی]] کے ذریعہ'
// Some text to append to the edit summary. Named 'using' for historical reasons. If you prefer
// to have a marker at the front, use prefix and set this to the empty string.
,multi_change : '$1 categories'
// $1 is replaced by a number. If your language has several plural forms (c.f. [[:en:Dual (grammatical form)]]),
// you can set this to an array of strings suitable for passing to mw.language.configPlural().
// If that function doesn't exist, HotCat will simply fall back to using the last
// entry in the array.
,commit : 'محفوظ'
// Button text. Localize to wgContentLanguage here; localize to wgUserLanguage in a subpage,
// see localization hook below.
,ok : 'ٹھیک'
// Button text. Localize to wgContentLanguage here; localize to wgUserLanguage in a subpage,
// see localization hook below.
,cancel : 'منسوخ'
// Button text. Localize to wgContentLanguage here; localize to wgUserLanguage in a subpage,
// see localization hook below.
,multi_error : 'Could not retrieve the page text from the server. Therefore, your category changes '
+'cannot be saved. We apologize for the inconvenience.'
// Localize to wgContentLanguage here; localize to wgUserLanguage in a subpage,
// see localization hook below.
,short_catchange : null
// Defaults to '[[' + category_canonical + ':$1]]'. Can be overridden if in the short edit summaries
// not the standard category name should be used but, say, a shorter namespace alias. $1 is replaced
// by a category name.
}
,category_regexp : '[Cc][Aa][Tt][Ee][Gg][Oo][Rr][Yy]'
// Regular sub-expression matching all possible names for the category namespace. Is automatically localized
// correctly if you're running MediaWiki 1.16 or later. Otherwise, set it appropriately, e.g. at the German
// Wikipedia, use '[Cc][Aa][Tt][Ee][Gg][Oo][Rr][Yy]|[Kk][Aa][Tt][Ee][Gg][Oo][Rr][Ii][Ee]', or at the
// Chinese Wikipedia, use '[Cc][Aa][Tt][Ee][Gg][Oo][Rr][Yy]|分类|分類'. Note that namespaces are case-
// insensitive!
,category_canonical : 'زمرہ'
// The standard category name on your wiki. Is automatically localized correctly if you're running
// MediaWiki 1.16 or later; otherwise, set it to the preferred category name (e.g., "Kategorie").
,categories : 'زمرہ جات'
// Plural of category_canonical.
,disambig_category : 'ضد ابہام'
// Any category in this category is deemed a disambiguation category; i.e., a category that should not contain
// any items, but that contains links to other categories where stuff should be categorized. If you don't have
// that concept on your wiki, set it to null. Use blanks, not underscores.
,redir_category : 'رجوع مکرر زمرہ جات'
// Any category in this category is deemed a (soft) redirect to some other category defined by a link
// to another non-blacklisted category. If your wiki doesn't have soft category redirects, set this to null.
// If a soft-redirected category contains more than one link to another non-blacklisted category, it's considered
// a disambiguation category instead.
,links : {change: '(±)', remove: '(\u2212)', add: '(+)', restore: '(×)', undo: '(×)', down: '(\u2193)', up: '(\u2191)'}
// The little modification links displayed after category names. U+2212 is a minus sign; U+2193 and U+2191 are
// downward and upward pointing arrows. Do not use ↓ and ↑ in the code!
,tooltips : {
change: 'درستی کریں'
,remove: 'ہٹائیں'
,add: 'نئے زمرہ کا اضافہ کریں'
,restore: 'استرجع کریں'
,undo: 'استرجع کریں'
,down: 'تبدیلی کے لیے کھولیں اور ذیلی زمرہ جات دکھائیں'
,up: 'تبدیلی کے لیے کھولیں اور اساسی زمرہ جات دکھائیں'
}
// The tooltips for the above links
,addmulti : '<span>+<sup>+</sup></span>'
// The HTML content of the "enter multi-mode" link at the front.
,multi_tooltip : 'متعدد زمرہ جات کی درستگی کریں'
// Tooltip for the "enter multi-mode" link
,disable :
function () { // Return true to disable HotCat.
var ns = conf.wgNamespaceNumber;
var nsIds = conf.wgNamespaceIds;
return ( ns < 0 // Special pages; Special:Upload is handled differently
|| ns === 10 // Templates
|| ns === 828 // Module (Lua)
|| ns === 8 // MediaWiki
|| ns === 6 && conf.wgArticleId === 0 // Non-existing file pages
|| ns === 2 && /\.(js|css)$/.test(conf.wgTitle) // User scripts
|| nsIds
&& ( ns === nsIds['creator']
|| ns === nsIds['timedtext']
|| ns === nsIds['institution']
)
);
}
,uncat_regexp : /\{\{\s*([Uu]ncat(egori[sz]ed( image)?)?|[Nn]ocat|[Nn]eedscategory)[^}]*\}\}\s*(<\!--.*?--\>)?/g
// A regexp matching a templates used to mark uncategorized pages, if your wiki does have that.
// If not, set it to null.
,existsYes : '//thumb.wikimedia.org/wikipedia/commons/thumb/b/be/P_yes.svg/20px-P_yes.svg.png'
,existsNo : '//thumb.wikimedia.org/wikipedia/commons/thumb/4/42/P_no.svg/20px-P_no.svg.png'
// The images used for the little indication icon. Should not need changing.
,template_regexp : '[Tt][Ee][Mm][Pp][Ll][Aa][Tt][Ee]'
// Regexp to recognize templates. Like "category" above; autolocalized for MW 1.16+, otherwise set manually here.
// On the German Wikipedia, you might use '[Tt][Ee][Mm][Pp][Ll][Aa][Tt][Ee]|[Vv][Oo][Rr][Ll][Aa][Gg][Ee]'.
,template_categories : {}
// a list of categories which can be removed by removing a template
// key: the category without namespace
// value: A regexp matching the template name, again without namespace
// If you don't have this at your wiki, or don't want this, set it to an empty object {}.
,engine_names : {
searchindex : 'اشاریہ تلاش'
,pagelist : 'فہرست صفحات'
,combined : 'مربوط تلاش'
,subcat : 'ذیلی زمرہ جات'
,parentcat : 'اساسی زمرہ جات'
}
// Names for the search engines
,capitalizePageNames : true
// Set to false if your wiki has case-sensitive page names. MediaWiki has two modes: either the first letter
// of a page is automatically capitalized ("first-letter"; Category:aa == Category:Aa), or it isn't
// ("case-sensitive"; Category:aa != Category:Aa). It doesn't currently have a fully case-insensitive mode
// (which would mean Category:aa == Category:Aa == Category:AA == Category:aA)
// HotCat tries to set this correctly automatically using an API query. It's still a good idea to manually
// configure it correctly; either directly here if you copied HotCat, or in the local configuration file
// MediaWiki:Gadget-HotCat.js/local_defaults if you hotlink to the Commons-version, to ensure it is set even
// if that API query should fail for some strange reason.
,upload_disabled : false
// If upload_disabled is true, HotCat will not be used on the Upload form.
,blacklist : null
// Single regular expression matching blacklisted categories that cannot be changed or
// added using HotCat. For instance /\bstubs?$/ (any category ending with the word "stub"
// or "stubs"), or /(\bstubs?$)|\bmaintenance\b/ (stub categories and any category with the
// word "maintenance" in its title.
// Stuff changeable by users:
,bg_changed : '#F8CCB0'
// Background for changed categories in multi-edit mode. Default is a very light salmon pink.
,no_autocommit : false
// If true, HotCat will never automatically submit changes. HotCat will only open an edit page with
// the changes; users must always save explicitly.
,del_needs_diff : false
// If true, the "category deletion" link "(-)" will never save automatically but always show an
// edit page where the user has to save the edit manually. Is false by default because that's the
// traditional behavior. This setting overrides no_autocommit for "(-)" links.
,suggest_delay : 100
// Time, in milliseconds, that HotCat waits after a keystroke before making a request to the
// server to get suggestions.
,editbox_width : 40
// Default width, in characters, of the text input field.
,suggestions : 'combined'
// One of the engine_names above, to be used as the default suggestion engine.
,fixed_search : false
// If true, always use the default engine, and never display a selector.
,use_up_down : true
// If false, do not display the "up" and "down" links
,list_size : 5
// Default list size
,single_minor : true
// If true, single category changes are marked as minor edits. If false, they're not.
,dont_add_to_watchlist : false
// If true, never add a page to the user's watchlist. If false, pages get added to the watchlist if
// the user has the "Add pages I edit to my watchlist" or the "Add pages I create to my watchlist"
// options in his or her preferences set.
,shortcuts : null
,addShortcuts :
function (map) {
if (!map) return;
window.HotCat.shortcuts = window.HotCat.shortcuts || {};
for (var k in map) {
if (!map.hasOwnProperty (k) || typeof k != 'string') continue;
var v = map[k];
if (typeof v != 'string') continue;
k = k.replace (/^\s+|\s+$/g, "");
v = v.replace (/^\s+|\s+$/g, "");
if (k.length === 0 || v.length === 0) continue;
window.HotCat.shortcuts[k] = v;
}
}
};
// More backwards compatibility. We have a few places where we test for the browser: once for
// Safari < 3.0, twice for WebKit (Chrome or Safari, any versions), twice for IE <= 6, and
// once for IE < 8.
var ua = navigator.userAgent.toLowerCase();
var is_ie6 = /msie ([0-9]{1,}[\.0-9]{0,})/.exec(ua) !== null && parseFloat(RegExp.$1) <= 6.0;
var is_ie_lt8 = /msie ([0-9]{1,}[\.0-9]{0,})/.exec(ua) !== null && parseFloat(RegExp.$1) < 8.0;
var is_webkit = /applewebkit\/\d+/.test(ua) && ua.indexOf ('spoofer') < 0;
// And even more compatbility. HotCat was developed without jQuery, and anyway current jQuery
// (1.7.1) doesn't seem to support in jquery.getJSON() or jQuery.ajax() the automatic
// switching from GET to POST requests if the query arguments would make the uri too long.
// (IE has a hard limit of 2083 bytes, and the servers may have limits around 4 or 8kB.)
// Anyway, HotCat is supposed to run on wikis without jQuery, so we'd have to supply some
// ajax routines ourselves in any case. We can't rely on the old sajax_init_object(), newer
// MW versions (>= 1.19) might not have it.
var getJSON = (function () {
function getRequest () {
var request = null;
try {
request = new window.XMLHttpRequest();
} catch (anything) {
if (window.ActiveXObject) {
try {
request = new window.ActiveXObject('Microsoft.XMLHTTP');
} catch (any) {
}
} // end if IE
} // end try-catch
return request;
}
return function (settings) {
var req = getRequest();
if (!req && settings && settings.error) settings.error (req);
if (!req || !settings || !settings.uri) return req;
var uri = armorUri (settings.uri);
var args = settings.data || null;
var method;
if (args && uri.length + args.length + 1 > 2000) {
// We lose caching, but at least we can make the request
method = 'POST';
req.setRequestHeader ('Content-Type', 'application/x-www-form-urlencoded');
} else {
method = 'GET';
if (args) uri += '?' + args;
args = null;
}
req.open (method, uri, true);
req.onreadystatechange = function () {
if (req.readyState != 4) return;
if (req.status != 200 || !req.responseText || !(/^\s*[\{\[]/.test(req.responseText))) {
if (settings.error) settings.error (req);
} else {
if (settings.success) settings.success (eval ('(' + req.responseText + ')'));
}
};
req.setRequestHeader ('Pragma', 'cache=yes');
req.setRequestHeader ('Cache-Control', 'no-transform');
req.send (args);
return req;
};
})();
function armorUri (uri) {
// Avoid protocol-relative URIs, IE7 has a bug with them in Ajax calls
if (uri.length >= 2 && uri.substring(0, 2) == '//') return document.location.protocol + uri;
return uri;
}
function LoadTrigger (needed) {
this.queue = [];
this.toLoad = needed;
}
LoadTrigger.prototype = {
register : function (callback) {
if (this.toLoad <= 0) {
callback (); // Execute directly
} else {
this.queue[this.queue.length] = callback;
}
},
loaded : function () {
if (this.toLoad > 0) {
this.toLoad--;
if (this.toLoad === 0) {
// Run queued callbacks once
for (var i = 0; i < this.queue.length; i++) this.queue[i]();
this.queue = [];
}
}
}
};
var setupCompleted = new LoadTrigger(1);
// Used to run user-registered code once HotCat is fully set up and ready.
HotCat.runWhenReady = function (callback) {setupCompleted.register(callback);};
var loadTrigger = new LoadTrigger(2);
// Used to delay running the HotCat setup until /local_defaults and localizations have been loaded.
function load (uri) {
var head = document.getElementsByTagName ('head')[0];
var s = document.createElement ('script');
s.setAttribute ('src', armorUri(uri));
s.setAttribute ('type', 'text/javascript');
var done = false;
function afterLoad () {
if (done) return;
done = true;
s.onload = s.onreadystatechange = s.onerror = null; // Properly clean up to avoid memory leaks in IE
if (head && s.parentNode) head.removeChild (s);
loadTrigger.loaded();
}
s.onload = s.onreadystatechange = function () { // onreadystatechange for IE, onload for all others
if (done) return;
if (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') {
afterLoad ();
}
};
s.onerror = afterLoad; // Clean up, but otherwise ignore errors
head.insertBefore (s, head.firstChild); // appendChild may trigger bugs in IE6 here
}
function loadJS (page) {
load (conf.wgServer + conf.wgScript + '?title=' + encodeURIComponent (page) + '&action=raw&ctype=text/javascript');
}
function loadURI (href) {
var url = href;
if (url.substring (0, 2) == '//') {
url = window.location.protocol + url;
} else if (url.substring (0, 1) == '/') {
url = conf.wgServer + url;
}
load (url);
}
// Load local configurations, overriding the pre-set default values in the HotCat object above. This is always loaded
// from the wiki where this script is executing, even if this script itself is hotlinked from the Commons. This can
// be used to change the default settings, or to provide localized interface texts for edit summaries and so on.
loadJS ('MediaWiki:Gadget-HotCat.js/local_defaults');
// Load localized UI texts. These are the texts that HotCat displays on the page itself. Texts shown in edit summaries
// should be localized in /local_defaults above.
if (conf.wgUserLanguage != 'en') {
// Lupo: somebody thought it would be a good idea to add this. So the default is true, and you have to set it to false
// explicitly if you're not on the Commons and don't want that.
if (typeof window.hotcat_translations_from_commons == 'undefined') {
window.hotcat_translations_from_commons = true;
}
// Localization hook to localize HotCat messages, tooltips, and engine names for wgUserLanguage.
if (window.hotcat_translations_from_commons && conf.wgServer.indexOf('//commons') < 0) {
loadURI ('//commons.wikimedia.org/w/index.php?title='
+ 'MediaWiki:Gadget-HotCat.js/' + conf.wgUserLanguage
+ '&action=raw&ctype=text/javascript'
);
} else {
// Load translations locally
loadJS ('MediaWiki:Gadget-HotCat.js/' + conf.wgUserLanguage);
}
} else {
loadTrigger.loaded();
}
// No further changes should be necessary here.
// The following regular expression strings are used when searching for categories in wikitext.
var wikiTextBlank = '[\\t _\\xA0\\u1680\\u180E\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]+';
var wikiTextBlankRE = new RegExp (wikiTextBlank, 'g');
// Regexp for handling blanks inside a category title or namespace name.
// See http://svn.wikimedia.org/viewvc/mediawiki/trunk/phase3/includes/Title.php?revision=104051&view=markup#l2722
// See also http://www.fileformat.info/info/unicode/category/Zs/list.htm
// MediaWiki collapses several contiguous blanks inside a page title to one single blank. It also replace a
// number of special whitespace characters by simple blanks. And finally, blanks are treated as underscores.
// Therefore, when looking for page titles in wikitext, we must handle all these cases.
// Note: we _do_ include the horizontal tab in the above list, even though the MediaWiki software for some reason
// appears to not handle it. The zero-width space \u200B is _not_ handled as a space inside titles by MW.
var wikiTextBlankOrBidi = '[\\t _\\xA0\\u1680\\u180E\\u2000-\\u200B\\u200E\\u200F\\u2028-\\u202F\\u205F\\u3000]*';
// Whitespace regexp for handling whitespace between link components. Including the horizontal tab, but not \n\r\f\v:
// a link must be on one single line.
// MediaWiki also removes Unicode bidi override characters in page titles (and namespace names) completely.
// This is *not* handled, as it would require us to allow any of [\u200E\u200F\u202A-\u202E] between any two
// characters inside a category link. It _could_ be done though... We _do_ handle strange spaces, including the
// zero-width space \u200B, and bidi overrides between the components of a category link (adjacent to the colon,
// or adjacent to and inside of "[[" and "]]").
// First auto-localize the regexps for the category and the template namespaces.
var formattedNamespaces = conf.wgFormattedNamespaces;
var namespaceIds = conf.wgNamespaceIds;
if (formattedNamespaces) {
function autoLocalize (namespaceNumber, fallback) {
function create_regexp_str (name)
{
if (!name || name.length === 0) return "";
var regex_name = "";
for (var i = 0; i < name.length; i++){
var initial = name.substr (i, 1);
var ll = initial.toLowerCase ();
var ul = initial.toUpperCase ();
if (ll == ul){
regex_name += initial;
} else {
regex_name += '[' + ll + ul + ']';
}
}
return regex_name
.replace(/([\\\^\$\.\?\*\+\(\)])/g, '\\$1')
.replace (wikiTextBlankRE, wikiTextBlank);
}
fallback = fallback.toLowerCase();
var canonical = formattedNamespaces["" + namespaceNumber].toLowerCase();
var regexp = create_regexp_str (canonical);
if (fallback && canonical != fallback) regexp += '|' + create_regexp_str(fallback);
if (namespaceIds) {
for (var cat_name in namespaceIds) {
if ( typeof cat_name == 'string'
&& cat_name.toLowerCase() != canonical
&& cat_name.toLowerCase() != fallback
&& namespaceIds[cat_name] == namespaceNumber)
{
regexp += '|' + create_regexp_str(cat_name);
}
}
}
return regexp;
}
if (formattedNamespaces['14']) {
HotCat.category_canonical = formattedNamespaces['14'];
HotCat.category_regexp = autoLocalize (14, 'category');
}
if (formattedNamespaces['10']) {
HotCat.template_regexp = autoLocalize (10, 'template');
}
}
// Utility functions. Yes, this duplicates some functionality that also exists in other places, but
// to keep this whole stuff in a single file not depending on any other on-wiki Javascripts, we re-do
// these few operations here.
function bind (func, target) {
var f = func, tgt = target;
return function () { return f.apply (tgt, arguments); };
}
function make (arg, literal) {
if (!arg) return null;
return literal ? document.createTextNode (arg) : document.createElement (arg);
}
function param (name, uri) {
if (typeof uri == 'undefined' || uri === null) uri = document.location.href;
var re = new RegExp ('[&?]' + name + '=([^&#]*)');
var m = re.exec (uri);
if (m && m.length > 1) return decodeURIComponent(m[1]);
return null;
}
function title (href) {
if (!href) return null;
var script = conf.wgScript + '?';
if (href.indexOf (script) === 0 || href.indexOf (conf.wgServer + script) === 0 || conf.wgServer.substring(0, 2) == '//' && href.indexOf (document.location.protocol + conf.wgServer + script) === 0) {
// href="/w/index.php?title=..."
return param ('title', href);
} else {
// href="/wiki/..."
var prefix = conf.wgArticlePath.replace ('$1', "");
if (href.indexOf (prefix) !== 0) prefix = conf.wgServer + prefix; // Fully expanded URL?
if (href.indexOf (prefix) !== 0 && prefix.substring(0, 2) == '//') prefix = document.location.protocol + prefix; // Protocol-relative wgServer?
if (href.indexOf (prefix) === 0)
return decodeURIComponent (href.substring (prefix.length));
}
return null;
}
function hasClass (elem, name) {
return (' ' + elem.className + ' ').indexOf (' ' + name + ' ') >= 0;
}
function capitalize (str) {
if (!str || str.length === 0) return str;
return str.substr(0, 1).toUpperCase() + str.substr (1);
}
function wikiPagePath (pageName) {
// Note: do not simply use encodeURI, it doesn't encode '&', which might break if wgArticlePath actually has the $1 in
// a query parameter.
return conf.wgArticlePath.replace('$1', encodeURIComponent (pageName).replace(/%3A/g, ':').replace(/%2F/g, '/'));
}
function escapeRE(str) {
return str.replace(/([\\\^\$\.\?\*\+\(\)\[\]])/g, '\\$1');
}
function substituteFactory (options) {
options = options || {};
var lead = options.indicator || '$';
var indicator = escapeRE (lead);
var lbrace = escapeRE (options.lbrace || '{');
var rbrace = escapeRE (options.rbrace || '}');
var re;
re = new RegExp(
'(?:' + indicator + '(' + indicator + '))|' // $$
+'(?:' + indicator + '(\\d+))|' // $0, $1
+'(?:' + indicator + '(?:' + lbrace + '([^' + lbrace + rbrace + ']+)' + rbrace + '))|' // ${key}
+'(?:' + indicator + '(?!(?:[' + indicator + lbrace + ']|\\d))(\\S+?)\\b)' // $key (only if first char after $ is not $, digit, or { )
,'g');
// Replace $1, $2, or ${key1}, ${key2}, or $key1, $key2 by values from map. $$ is replaced by a single $.
return function (str, map) {
if (!map) return str;
return str.replace(re
,function (match, prefix, idx, key, alpha) {
if (prefix == lead) return lead;
var k = alpha || key || idx;
var replacement = typeof map[k] === 'function' ? map[k](match, k) : map[k];
return typeof replacement === 'string' ? replacement : (replacement || match);
}
);
};
}
var substitute = substituteFactory();
var replaceShortcuts = (function () {
var replaceHash = substituteFactory({indicator:'#',lbrace:'[',rbrace:']'});
return function (str, map) {
var s = replaceHash (str, map);
return HotCat.capitalizePageNames ? capitalize(s) : s;
};
})();
// Text modification
var findCatsRE =
new RegExp ('\\[\\[' + wikiTextBlankOrBidi + '(?:' + HotCat.category_regexp + ')' + wikiTextBlankOrBidi + ':[^\\]]+\\]\\]', 'g');
function replaceByBlanks (match) {
return match.replace(/(\s|\S)/g, ' '); // /./ doesn't match linebreaks. /(\s|\S)/ does.
}
function find_category (wikitext, category, once) {
var cat_regex = null;
if(HotCat.template_categories[category]){
cat_regex = new RegExp ('\\{\\{' + wikiTextBlankOrBidi + '(' + HotCat.template_regexp + '(?=' + wikiTextBlankOrBidi + ':))?' + wikiTextBlankOrBidi
+ '(?:' + HotCat.template_categories[category] + ')'
+ wikiTextBlankOrBidi + '(\\|.*?)?\\}\\}', 'g'
);
} else {
var cat_name = escapeRE (category);
var initial = cat_name.substr (0, 1);
cat_regex = new RegExp ('\\[\\[' + wikiTextBlankOrBidi + '(' + HotCat.category_regexp + ')' + wikiTextBlankOrBidi + ':' + wikiTextBlankOrBidi
+ (initial == '\\' || !HotCat.capitalizePageNames
? initial
: '[' + initial.toUpperCase() + initial.toLowerCase() + ']')
+ cat_name.substring (1).replace (wikiTextBlankRE, wikiTextBlank)
+ wikiTextBlankOrBidi + '(\\|.*?)?\\]\\]', 'g'
);
}
if (once) return cat_regex.exec (wikitext);
var copiedtext = wikitext
.replace(/<\!--(\s|\S)*?--\>/g, replaceByBlanks)
.replace(/<nowiki\>(\s|\S)*?<\/nowiki>/g, replaceByBlanks);
var result = [];
var curr_match = null;
while ((curr_match = cat_regex.exec (copiedtext)) !== null) {
result.push ({match : curr_match});
}
result.re = cat_regex;
return result; // An array containing all matches, with positions, in result[i].match
}
var interlanguageRE = null;
function change_category (wikitext, toRemove, toAdd, key, is_hidden) {
function find_insertionpoint (wikitext) {
var copiedtext = wikitext
.replace(/<\!--(\s|\S)*?--\>/g, replaceByBlanks)
.replace(/<nowiki\>(\s|\S)*?<\/nowiki>/g, replaceByBlanks);
// Search in copiedtext to avoid that we insert inside an HTML comment or a nowiki "element".
var index = -1;
findCatsRE.lastIndex = 0;
while (findCatsRE.exec(copiedtext) !== null) index = findCatsRE.lastIndex;
if (index < 0) {
// Find the index of the first interlanguage link...
var match = null;
if (!interlanguageRE) {
// Approximation without API: interlanguage links start with 2 to 3 lower case letters, optionally followed by
// a sequence of groups consisting of a dash followed by one or more lower case letters. Exceptions are "simple"
// and "tokipona".
match = /((^|\n\r?)(\[\[\s*(([a-z]{2,3}(-[a-z]+)*)|simple|tokipona)\s*:[^\]]+\]\]\s*))+$/.exec (copiedtext);
} else {
match = interlanguageRE.exec(copiedtext);
}
if (match) index = match.index;
return {idx : index, onCat : false};
}
return {idx : index, onCat : index >= 0};
}
var summary = [];
var nameSpace = HotCat.category_canonical;
var cat_point = -1; // Position of removed category;
if (key) key = '|' + key;
var keyChange = (toRemove && toAdd && toRemove == toAdd && toAdd.length > 0);
var matches;
if (toRemove && toRemove.length > 0) {
matches = find_category (wikitext, toRemove);
if (!matches || matches.length === 0) {
return {text: wikitext, 'summary': summary, error: HotCat.messages.cat_notFound.replace (/\$1/g, toRemove)};
} else {
var before = wikitext.substring (0, matches[0].match.index);
var after = wikitext.substring (matches[0].match.index + matches[0].match[0].length);
if (matches.length > 1) {
// Remove all occurrences in after
matches.re.lastIndex = 0;
after = after.replace (matches.re, "");
}
if (toAdd) {
nameSpace = matches[0].match[1] || nameSpace;
if (key === null) key = matches[0].match[2]; // Remember the category key, if any.
}
// Remove whitespace (properly): strip whitespace, but only up to the next line feed.
// If we then have two linefeeds in a row, remove one. Otherwise, if we have two non-
// whitespace characters, insert a blank.
var i = before.length - 1;
while (i >= 0 && before.charAt (i) != '\n' && before.substr (i, 1).search (/\s/) >= 0) i--;
var j = 0;
while (j < after.length && after.charAt (j) != '\n' && after.substr (j, 1).search (/\s/) >= 0)
j++;
if (i >= 0 && before.charAt (i) == '\n' && (after.length === 0 || j < after.length && after.charAt (j) == '\n'))
i--;
if (i >= 0) before = before.substring (0, i+1); else before = "";
if (j < after.length) after = after.substring (j); else after = "";
if (before.length > 0 && before.substring (before.length - 1).search (/\S/) >= 0
&& after.length > 0 && after.substr (0, 1).search (/\S/) >= 0)
before += ' ';
cat_point = before.length;
if (cat_point === 0 && after.length > 0 && after.substr(0,1) == '\n') {
after = after.substr(1);
}
wikitext = before + after;
if (!keyChange) {
if(HotCat.template_categories[toRemove]) {
summary.push (HotCat.messages.template_removed.replace (/\$1/g, toRemove));
} else {
summary.push (HotCat.messages.cat_removed.replace (/\$1/g, toRemove));
}
}
}
}
if (toAdd && toAdd.length > 0) {
matches = find_category (wikitext, toAdd);
if (matches && matches.length > 0) {
return {text: wikitext, 'summary': summary, error : HotCat.messages.cat_exists.replace (/\$1/g, toAdd)};
} else {
var onCat = false;
if (cat_point < 0) {
var point = find_insertionpoint (wikitext);
cat_point = point.idx;
onCat = point.onCat;
} else {
onCat = true;
}
var newcatstring = '[[' + nameSpace + ':' + toAdd + (key || "") + ']]';
if (cat_point >= 0) {
var suffix = wikitext.substring (cat_point);
wikitext = wikitext.substring (0, cat_point) + (cat_point > 0 ? '\n' : "") + newcatstring + (!onCat ? '\n' : "");
if (suffix.length > 0 && suffix.substr(0, 1) != '\n') {
wikitext += '\n' + suffix;
} else {
wikitext += suffix;
}
} else {
if (wikitext.length > 0 && wikitext.substr (wikitext.length - 1, 1) != '\n')
wikitext += '\n';
wikitext += (wikitext.length > 0 ? '\n' : "") + newcatstring;
}
if (keyChange) {
var k = key || "";
if (k.length > 0) k = k.substr (1);
summary.push (substitute (HotCat.messages.cat_keychange, [null, toAdd, k]));
} else {
summary.push (HotCat.messages.cat_added.replace (/\$1/g, toAdd));
}
if (HotCat.uncat_regexp && !is_hidden) {
var txt = wikitext.replace (HotCat.uncat_regexp, ""); // Remove "uncat" templates
if (txt.length != wikitext.length) {
wikitext = txt;
summary.push (HotCat.messages.uncat_removed);
}
}
}
}
return {text: wikitext, 'summary': summary, error: null};
}
// The real HotCat UI
function evtKeys (e) {
e = e || window.event || window.Event; // W3C, IE, Netscape
var code = 0;
if (typeof e.ctrlKey != 'undefined') { // All modern browsers
// Ctrl-click seems to be overloaded in FF/Mac (it opens a pop-up menu), so treat cmd-click
// as a ctrl-click, too.
if (e.ctrlKey || e.metaKey) code |= 1;
if (e.shiftKey) code |= 2;
} else if (typeof e.modifiers != 'undefined') { // Netscape...
if (e.modifiers & (Event.CONTROL_MASK | Event.META_MASK)) code |= 1;
if (e.modifiers & Event.SHIFT_MASK) code |= 2;
}
return code;
}
function evtKill (e) {
e = e || window.event || window.Event; // W3C, IE, Netscape
if (typeof e.preventDefault != 'undefined') {
e.preventDefault ();
e.stopPropagation ();
} else
e.cancelBubble = true;
return false;
}
function addEvent (node, evt, f, capture) {
if (window.jQuery && (!capture || !node.addEventListener)) window.jQuery (node).bind (evt, f);
else if (node.addEventListener) node.addEventListener (evt, f, capture); // FF etc; IE >= 9
else if (node.attachEvent) node.attachEvent ('on' + evt, f); // Older IE; Opera
else node['on' + evt] = f; // Very old!
}
var catLine = null;
var onUpload = false;
var editors = [];
var commitButton = null;
var commitForm = null;
var multiSpan = null;
var pageText = null;
var pageTime = null;
var pageWatched = false;
var watchCreate = false;
var watchEdit = false;
var minorEdits = false;
var editToken = null;
var is_rtl = false;
var serverTime = null;
var lastRevId = null;
var pageTextRevId = null;
var conflictingUser = null;
var newDOM = false; // true if MediaWiki serves the new UL-LI DOM for categories
function setMultiInput () {
if (commitButton || onUpload) return;
commitButton = make ('input');
commitButton.type = 'button';
commitButton.value = HotCat.messages.commit;
commitButton.onclick = multiSubmit;
if (multiSpan) {
multiSpan.parentNode.replaceChild (commitButton, multiSpan);
} else {
catLine.appendChild (commitButton);
}
}
function checkMultiInput () {
if (!commitButton) return;
var has_changes = false;
for (var i = 0; i < editors.length; i++) {
if (editors[i].state != CategoryEditor.UNCHANGED) {
has_changes = true;
break;
}
}
commitButton.disabled = !has_changes;
}
function currentTimestamp () {
var now = new Date();
var ts = "" + now.getUTCFullYear();
function two (s) { return s.substr (s.length - 2); }
ts = ts
+ two ('0' + (now.getUTCMonth() + 1))
+ two ('0' + now.getUTCDate())
+ two ('00' + now.getUTCHours())
+ two ('00' + now.getUTCMinutes())
+ two ('00' + now.getUTCSeconds());
return ts;
}
var saveInProgress = false;
function initiateEdit (doEdit, failure) {
if (saveInProgress) return;
saveInProgress = true;
var oldButtonState;
if (commitButton) {
oldButtonState = commitButton.disabled;
commitButton.disabled = true;
}
function fail() {
saveInProgress = false;
if (commitButton) commitButton.disabled = oldButtonState;
failure.apply(this, arguments);
}
// Must use Ajax here to get the user options and the edit token.
getJSON ({
uri : conf.wgServer + conf.wgScriptPath + '/api.php'
,data : 'format=json&action=query&titles=' + encodeURIComponent (conf.wgPageName)
+ '&prop=info%7Crevisions%7Clanglinks&inprop=watched&intoken=edit&rvprop=content%7Ctimestamp%7Cids%7Cuser&lllimit=500'
+ '&rvlimit=2&rvdir=newer&rvstartid=' + conf.wgCurRevisionId
+ '&meta=siteinfo%7Cuserinfo&uiprop=options'
,success : function (json) { setPage(json); doEdit(fail); }
,error : function (req) { fail(req.status + ' ' + req.statusText); }
});
}
function multiChangeMsg (count) {
var msg = HotCat.messages.multi_change;
if (typeof msg != 'string' && msg.length) {
if (window.mw && mw.language && mw.language.convertPlural) {
msg = mw.language.convertPlural (count, msg);
} else {
msg = msg[msg.length-1];
}
}
return substitute (msg, [null, "" + count]);
}
function performChanges (failure, singleEditor) {
if (pageText === null) {
failure (HotCat.messages.multi_error);
return;
}
// Backwards compatibility after message change (added $2 to cat_keychange)
if (HotCat.messages.cat_keychange.indexOf ('$2') < 0) HotCat.messages.cat_keychange += '"$2"';
// More backwards-compatibility with earlier HotCat versions:
if (!HotCat.messages.short_catchange) HotCat.messages.short_catchange = '[[' + HotCat.category_canonical + ':$1]]';
// Create a form and submit it. We don't use the edit API (api.php?action=edit) because
// (a) sensibly reporting back errors like edit conflicts is always a hassle, and
// (b) we want to show a diff for multi-edits anyway, and
// (c) we want to trigger onsubmit events, allowing user code to intercept the edit.
// Using the form, we can do (b) and (c), and we get (a) for free. And, of course, using the form
// automatically reloads the page with the updated categories on a successful submit, which
// we would have to do explicitly if we used the edit API.
var action;
// Normally, we don't have to care about edit conflicts. If some other user edited the page in the meantime, the
// server will take care of it and merge the edit automatically or present an edit conflict screen. However, the
// server suppresses edit conflicts with oneself. Hence, if we have a conflict, and the conflicting user is the
// current user, then we set the "oldid" value and switch to diff, which gives the "you are editing an old version;
// if you save, any more recent changes will be lost" screen.
var editingOldVersion = lastRevId !== null && lastRevId != conf.wgCurRevisionId || pageTextRevId !== null && pageTextRevId != conf.wgCurRevisionId;
var selfEditConflict = editingOldVersion && conflictingUser && conflictingUser == conf.wgUserName;
if (singleEditor && !singleEditor.noCommit && !HotCat.no_autocommit && editToken && !selfEditConflict) {
// If we do have an edit conflict, but not with ourself, that's no reason not to attempt to save: the server side may actually be able to
// merge the changes. We just need to make sure that we do present a diff view if it's a self edit conflict.
commitForm.wpEditToken.value = editToken;
action = commitForm.wpDiff;
if (action) action.name = action.value = 'wpSave';
} else {
action = commitForm.wpSave;
if (action) action.name = action.value = 'wpDiff';
}
var result = { text : pageText };
var changed = [], added = [], deleted = [], changes = 0;
var toEdit = !!singleEditor ? [singleEditor] : editors;
var error = null;
var i;
for (i=0; i < toEdit.length; i++) {
if (toEdit[i].state == CategoryEditor.CHANGED) {
result = change_category (
result.text
, toEdit[i].originalCategory
, toEdit[i].currentCategory
, toEdit[i].currentKey
, toEdit[i].currentHidden
);
if (!result.error) {
changes++;
if (!toEdit[i].originalCategory || toEdit[i].originalCategory.length === 0) {
added.push (toEdit[i].currentCategory);
} else {
changed.push ({from : toEdit[i].originalCategory, to : toEdit[i].currentCategory});
}
} else if (error === null) {
error = result.error;
}
} else if ( toEdit[i].state == CategoryEditor.DELETED
&& toEdit[i].originalCategory
&& toEdit[i].originalCategory.length > 0)
{
result = change_category (result.text, toEdit[i].originalCategory, null, null, false);
if (!result.error) {
changes++;
deleted.push (toEdit[i].originalCategory);
} else if (error === null) {
error = result.error;
}
}
}
if (error !== null) { // Do not commit if there were errors
action = commitForm.wpSave;
if (action) action.name = action.value = 'wpDiff';
}
// Fill in the form and submit it
commitForm.wpAutoSummary.value = 'd41d8cd98f00b204e9800998ecf8427e'; // MD5 hash of the empty string
commitForm.wpMinoredit.checked = minorEdits;
commitForm.wpWatchthis.checked = conf.wgArticleId === 0 && watchCreate || watchEdit || pageWatched;
if (conf.wgArticleId > 0 || !!singleEditor) {
if (changes == 1) {
if (result.summary && result.summary.length > 0)
commitForm.wpSummary.value = HotCat.messages.prefix + result.summary.join (HotCat.messages.separator) + HotCat.messages.using;
commitForm.wpMinoredit.checked = HotCat.single_minor || minorEdits;
} else if (changes > 1) {
var summary = [];
var shortSummary = [];
// Deleted
for (i = 0; i < deleted.length; i++) {
summary.push ('-' + substitute (HotCat.messages.short_catchange, [null, deleted[i]]));
}
if (deleted.length == 1)
shortSummary.push ('-' + substitute (HotCat.messages.short_catchange, [null, deleted[0]]));
else if (deleted.length > 1)
shortSummary.push ('- ' + multiChangeMsg (deleted.length));
// Added
for (i = 0; i < added.length; i++) {
summary.push ('+' + substitute (HotCat.messages.short_catchange, [null, added[i]]));
}
if (added.length == 1)
shortSummary.push ('+' + substitute (HotCat.messages.short_catchange, [null, added[0]]));
else if (added.length > 1)
shortSummary.push ('+ ' + multiChangeMsg (added.length));
// Changed
var arrow = is_rtl ? '\u2190' : '\u2192'; // left and right arrows. Don't use ← and → in the code.
for (i = 0; i < changed.length; i++) {
if (changed[i].from != changed[i].to) {
summary.push ('±' + substitute (HotCat.messages.short_catchange, [null, changed[i].from]) + arrow
+ substitute (HotCat.messages.short_catchange, [null, changed[i].to]));
} else {
summary.push ('±' + substitute (HotCat.messages.short_catchange, [null, changed[i].from]));
}
}
if (changed.length == 1) {
if (changed[0].from != changed[0].to) {
shortSummary.push ('±' + substitute (HotCat.messages.short_catchange, [null, changed[0].from]) + arrow
+ substitute (HotCat.messages.short_catchange, [null, changed[0].to]));
} else {
shortSummary.push ('±' + substitute (HotCat.messages.short_catchange, [null, changed[0].from]));
}
} else if (changed.length > 1) {
shortSummary.push ('± ' + multiChangeMsg (changed.length));
}
if (summary.length > 0) {
summary = summary.join (HotCat.messages.separator);
if (summary.length > 200 - HotCat.messages.prefix.length - HotCat.messages.using.length) {
summary = shortSummary.join (HotCat.messages.separator);
}
commitForm.wpSummary.value = HotCat.messages.prefix + summary + HotCat.messages.using;
}
}
}
commitForm.wpTextbox1.value = result.text;
commitForm.wpStarttime.value = serverTime || currentTimestamp ();
commitForm.wpEdittime.value = pageTime || commitForm.wpStarttime.value;
if (selfEditConflict) commitForm.oldid.value = "" + (pageTextRevId || conf.wgCurRevisionId);
// Submit the form in a way that triggers onsubmit events: commitForm.submit() doesn't.
commitForm.hcCommit.click();
}
function resolveMulti (toResolve, callback) {
var i;
for (i = 0; i < toResolve.length; i++) {
toResolve[i].dab = null;
toResolve[i].dabInput = toResolve[i].lastInput;
}
if (noSuggestions) {
callback (toResolve);
return;
}
// Use %7C instead of |, otherwise Konqueror insists on re-encoding the arguments, resulting in doubly encoded
// category names. (That is a bug in Konqueror. Other browsers don't have this problem.)
var args = 'action=query&prop=info%7Clinks%7Ccategories%7Ccategoryinfo&plnamespace=14'
+ '&pllimit=' + (toResolve.length * 10)
+ '&cllimit=' + (toResolve.length * 10)
+ '&format=json&titles=';
for (i = 0; i < toResolve.length; i++) {
var v = toResolve[i].dabInput;
v = replaceShortcuts (v, HotCat.shortcuts);
toResolve[i].dabInputCleaned = v;
args += encodeURIComponent ('Category:' + v);
if (i+1 < toResolve.length) args += '%7C';
}
getJSON({
uri : conf.wgServer + conf.wgScriptPath + '/api.php'
,data : args
,success: function (json) { resolveRedirects (toResolve, json); callback (toResolve); }
,error: function (req) { if (!req) noSuggestions = true; callback (toResolve); }
});
}
function resolveOne (page, toResolve) {
var cats = page.categories;
var lks = page.links;
var is_dab = false;
var is_redir = typeof page.redirect == 'string'; // Hard redirect?
var is_hidden = page.categoryinfo && typeof page.categoryinfo.hidden == 'string';
var is_missing = typeof page.missing == 'string';
var i;
for (i = 0; i < toResolve.length; i++) {
if (toResolve.length > 1 && toResolve[i].dabInputCleaned != page.title.substring (page.title.indexOf (':') + 1)) continue;
// Note: the server returns in page an NFC normalized Unicode title. If our input was not NFC normalized, we may not find
// any entry here. If we have only one editor to resolve (the most common case, I presume), we may simply skip the check.
toResolve[i].currentHidden = is_hidden;
toResolve[i].inputExists = !is_missing;
toResolve[i].icon.src = armorUri(is_missing ? HotCat.existsNo : HotCat.existsYes);
}
if (is_missing) return;
if (!is_redir && cats && (HotCat.disambig_category || HotCat.redir_category)) {
for (var c = 0; c < cats.length; c++) {
var cat = cats[c]['title'];
// Strip namespace prefix
if (cat) {
cat = cat.substring (cat.indexOf (':') + 1).replace(/_/g, ' ');
if (cat == HotCat.disambig_category) {
is_dab = true; break;
} else if (cat == HotCat.redir_category) {
is_redir = true; break;
}
}
}
}
if (!is_redir && !is_dab) return;
if (!lks || lks.length === 0) return;
var titles = [];
for (i = 0; i < lks.length; i++) {
if ( lks[i]['ns'] == 14 // Category namespace -- always true since we ask only for the category links
&& lks[i]['title'] && lks[i]['title'].length > 0) // Name not empty
{
// Internal link to existing thingy. Extract the page name and remove the namespace.
var match = lks[i]['title'];
match = match.substring (match.indexOf (':') + 1);
// Exclude blacklisted categories.
if (!HotCat.blacklist || !HotCat.blacklist.test (match)) {
titles.push (match);
}
}
}
if (titles.length === 0) {
return;
}
for (i = 0; i < toResolve.length; i++) {
if (toResolve.length > 1 && toResolve[i].dabInputCleaned != page.title.substring (page.title.indexOf (':') + 1)) continue;
toResolve[i].inputExists = true; // Might actually be wrong if it's a redirect pointing to a non-existing category
toResolve[i].icon.src = armorUri(HotCat.existsYes);
if (titles.length > 1) {
toResolve[i].dab = titles;
} else {
toResolve[i].text.value =
titles[0] + (toResolve[i].currentKey !== null ? '|' + toResolve[i].currentKey : "");
}
}
}
function resolveRedirects (toResolve, params) {
if (!params || !params.query || !params.query.pages) return;
for (var p in params.query.pages) resolveOne (params.query.pages[p], toResolve);
}
function multiSubmit () {
var toResolve = [];
for (var i = 0; i < editors.length; i++) {
if (editors[i].state == CategoryEditor.CHANGE_PENDING || editors[i].state == CategoryEditor.OPEN)
toResolve.push (editors[i]);
}
if (toResolve.length === 0) {
initiateEdit (function (failure) {performChanges (failure);}, function (msg) {alert (msg);});
return;
}
resolveMulti (
toResolve
, function (resolved) {
var firstDab = null;
var dontChange = false;
for (var i = 0; i < resolved.length; i++) {
if (resolved[i].lastInput != resolved[i].dabInput) {
// We didn't disable all the open editors, but we did asynchronous calls. It is
// theoretically possible that the user changed something...
dontChange = true;
} else {
if (resolved[i].dab) {
if (!firstDab) firstDab = resolved[i];
} else {
if (resolved[i].acceptCheck(true)) resolved[i].commit();
}
}
}
if (firstDab) {
showDab (firstDab);
} else if (!dontChange) {
initiateEdit (function (failure) {performChanges (failure);}, function (msg) {alert (msg);});
}
}
);
}
var cat_prefix = null;
var noSuggestions = false;
var suggestionEngines = {
opensearch :
{ uri : '/api.php?format=json&action=opensearch&namespace=14&limit=30&search=Category:$1' // $1 = search term
,handler : // Function to convert result of uri into an array of category names
function (queryResult, queryKey) {
if (queryResult && queryResult.length >= 2) {
var key = queryResult[0].substring(queryResult[0].indexOf(':') + 1);
var titles = queryResult[1];
var exists = false;
if (!cat_prefix) cat_prefix = new RegExp ('^(' + HotCat.category_regexp + ':)');
for (var i = 0; i < titles.length; i++) {
cat_prefix.lastIndex = 0;
var m = cat_prefix.exec (titles[i]);
if (m && m.length > 1) {
titles[i] = titles[i].substring (titles[i].indexOf (':') + 1); // rm namespace
if (key == titles[i]) exists = true;
} else {
titles.splice (i, 1); // Nope, it's not a category after all.
i--;
}
}
titles.exists = exists;
if (queryKey != key) titles.normalized = key; // Remember the NFC normalized key we got back from the server
return titles;
}
return null;
}
}
,internalsearch :
{ uri : '/api.php?format=json&action=query&list=allpages&apnamespace=14&aplimit=30&apfrom=$1&apprefix=$1'
,handler :
function (queryResult, queryKey) {
if (queryResult && queryResult.query && queryResult.query.allpages) {
var titles = queryResult.query.allpages;
for (var i = 0; i < titles.length; i++) {
titles[i] = titles[i].title.substring (titles[i].title.indexOf (':') + 1); // rm namespace
}
return titles;
}
return null;
}
}
,exists :
{ uri : '/api.php?format=json&action=query&prop=info&titles=Category:$1'
,handler :
function (queryResult, queryKey) {
if (queryResult && queryResult.query && queryResult.query.pages && !queryResult.query.pages[-1]) {
// Should have exactly 1
for (var p in queryResult.query.pages) {
var title = queryResult.query.pages[p].title;
title = title.substring (title.indexOf (':') + 1);
var titles = [title];
titles.exists = true;
if (queryKey != title) titles.normalized = title; // NFC
return titles;
}
}
return null;
}
}
,subcategories :
// I don't understand why they didn't map cmnamespace=14 automatically to cmtype=subcat,
// which gives better results and is faster.
{ uri : '/api.php?format=json&action=query&list=categorymembers'
+(function (version) {
var m = version.match(/^(\d+)\.(\d+)/);
var major = 0, minor = 0;
if (m && m.length > 1) {
major = parseInt (m[1], 10);
minor = (m.length > 2 ? parseInt (m[2], 10) : 0);
}
if (major > 1 || major === 1 && minor > 17) return '&cmtype=subcat'; // Since MW1.18
return '&cmnamespace=14';
}
)(conf.wgVersion)
+'&cmlimit=max&cmtitle=Category:$1'
,handler :
function (queryResult, queryKey) {
if (queryResult && queryResult.query && queryResult.query.categorymembers) {
var titles = queryResult.query.categorymembers;
for (var i = 0; i < titles.length; i++) {
titles[i] = titles[i].title.substring (titles[i].title.indexOf (':') + 1); // rm namespace
}
return titles;
}
return null;
}
}
,parentcategories :
{ uri : '/api.php?format=json&action=query&prop=categories&titles=Category:$1&cllimit=max'
,handler :
function (queryResult, queryKey) {
if (queryResult && queryResult.query && queryResult.query.pages) {
for (var p in queryResult.query.pages) {
if (queryResult.query.pages[p].categories) {
var titles = queryResult.query.pages[p].categories;
for (var i = 0; i < titles.length; i++) {
titles[i] = titles[i].title.substring (titles[i].title.indexOf (':') + 1); // rm namespace
}
return titles;
}
}
}
return null;
}
}
};
var suggestionConfigs = {
searchindex : {name: 'Search index', engines: ['opensearch'], cache: {}, show: true, temp: false, noCompletion : false}
,pagelist : {name: 'Page list', engines: ['internalsearch', 'exists'], cache: {}, show: true, temp: false, noCompletion : false}
,combined : {name: 'Combined search', engines: ['opensearch', 'internalsearch'], cache: {}, show: true, temp: false, noCompletion : false}
,subcat : {name: 'Subcategories', engines: ['subcategories'], cache: {}, show: true, temp: true, noCompletion : true}
,parentcat : {name: 'Parent categories', engines: ['parentcategories'], cache: {}, show: true, temp: true, noCompletion : true}
};
function CategoryEditor () { this.initialize.apply (this, arguments); }
CategoryEditor.UNCHANGED = 0;
CategoryEditor.OPEN = 1; // Open, but no input yet
CategoryEditor.CHANGE_PENDING = 2; // Open, some input made
CategoryEditor.CHANGED = 3;
CategoryEditor.DELETED = 4;
// IE6 sometimes forgets to redraw the list when editors are opened or closed.
// Adding/removing a dummy element helps, at least when opening editors.
var dummyElement = make ('\xa0', true);
function forceRedraw () {
if (!is_ie6) return;
if (dummyElement.parentNode) {
document.body.removeChild (dummyElement);
} else {
document.body.appendChild (dummyElement);
}
}
// Event keyCodes that we handle in the text input field/suggestion list.
var BS = 8, TAB = 9, RET = 13, ESC = 27, SPACE = 32, PGUP = 33, PGDOWN = 34, UP = 38, DOWN = 40, DEL = 46, IME = 229;
function makeActive (which) {
if (which.is_active) return;
for (var i = 0; i < editors.length; i++) {
if (editors[i] !== which) editors[i].inactivate ();
}
which.is_active = true;
if (which.dab) {
showDab (which);
} else {
// Check for programmatic value changes.
var expectedInput = which.lastRealInput || which.lastInput || "";
var actualValue = which.text.value || "";
if (expectedInput.length === 0 && actualValue.length > 0 || expectedInput.length > 0 && actualValue.indexOf (expectedInput) !== 0) {
// Somehow the field's value appears to have changed, and which.lastSelection therefore is no longer valid. Try to set the
// cursor at the end of the category, and do not display the old suggestion list.
which.showsList = false;
var v = actualValue.split('|');
which.lastRealInput = which.lastInput = v[0];
if (v.length > 1) which.currentKey = v[1];
if (which.lastSelection) which.lastSelection = {start: v[0].length, end: v[0].length};
}
if (which.showsList) which.displayList();
if (which.lastSelection) {
if (is_webkit) {
// WebKit (Safari, Chrome) has problems selecting inside focus()
// See http://code.google.com/p/chromium/issues/detail?id=32865#c6
window.setTimeout (
function () { which.setSelection (which.lastSelection.start, which.lastSelection.end); }
,1
);
} else {
which.setSelection (which.lastSelection.start, which.lastSelection.end);
}
}
}
}
function showDab (which) {
if (!which.is_active) {
makeActive(which);
} else {
which.showSuggestions (which.dab, false, null, null); // do autocompletion, no key, no engine selector
which.dab = null;
}
}
CategoryEditor.prototype = {
initialize : function (line, span, after, key, is_hidden) {
// If a span is given, 'after' is the category title, otherwise it may be an element after which to
// insert the new span. 'key' is likewise overloaded; if a span is given, it is the category key (if
// known), otherwise it is a boolean indicating whether a bar shall be prepended.
if (!span) {
this.isAddCategory = true;
// Create add span and append to catLinks
this.originalCategory = "";
this.originalKey = null;
this.originalExists = false;
if (!newDOM) {
span = make ('span');
span.className = 'noprint';
if (key) {
span.appendChild (make (' | ', true));
if (after) {
after.parentNode.insertBefore (span, after.nextSibling);
after = after.nextSibling;
} else {
line.appendChild (span);
}
} else if (line.firstChild) {
span.appendChild (make (' ', true));
line.appendChild (span);
}
}
this.linkSpan = make ('span');
this.linkSpan.className = 'noprint nopopups hotcatlink';
var lk = make ('a'); lk.href = '#catlinks'; lk.onclick = bind (this.open, this);
lk.appendChild (make (HotCat.links.add, true)); lk.title = HotCat.tooltips.add;
this.linkSpan.appendChild (lk);
span = make (newDOM ? 'li' : 'span');
span.className = 'noprint';
if (is_rtl) span.dir = 'rtl';
span.appendChild (this.linkSpan);
if (after)
after.parentNode.insertBefore (span, after.nextSibling);
else
line.appendChild (span);
this.normalLinks = null;
this.undelLink = null;
this.catLink = null;
} else {
if (is_rtl) span.dir = 'rtl';
this.isAddCategory = false;
this.catLink = span.firstChild;
this.originalCategory = after;
this.originalKey = (key && key.length > 1) ? key.substr(1) : null; // > 1 because it includes the leading bar
this.originalExists = !hasClass (this.catLink, 'new');
// Create change and del links
this.makeLinkSpan ();
if (!this.originalExists && this.upDownLinks) this.upDownLinks.style.display = 'none';
span.appendChild (this.linkSpan);
}
this.originalHidden = is_hidden;
this.line = line;
this.engine = HotCat.suggestions;
this.span = span;
this.currentCategory = this.originalCategory;
this.currentExists = this.originalExists;
this.currentHidden = this.originalHidden;
this.currentKey = this.originalKey;
this.state = CategoryEditor.UNCHANGED;
this.lastSavedState = CategoryEditor.UNCHANGED;
this.lastSavedCategory = this.originalCategory;
this.lastSavedKey = this.originalKey;
this.lastSavedExists = this.originalExists;
this.lastSavedHidden = this.originalHidden;
if (this.catLink && this.currentKey) {
this.catLink.title = this.currentKey;
}
editors[editors.length] = this;
},
makeLinkSpan : function () {
this.normalLinks = make ('span');
var lk = null;
if (this.originalCategory && this.originalCategory.length > 0) {
lk = make ('a'); lk.href = '#catlinks'; lk.onclick = bind (this.remove, this);
lk.appendChild (make (HotCat.links.remove, true)); lk.title = HotCat.tooltips.remove;
this.normalLinks.appendChild (make (' ', true));
this.normalLinks.appendChild (lk);
}
if (!HotCat.template_categories[this.originalCategory]) {
lk = make ('a'); lk.href = '#catlinks'; lk.onclick = bind (this.open, this);
lk.appendChild (make (HotCat.links.change, true)); lk.title = HotCat.tooltips.change;
this.normalLinks.appendChild (make (' ', true));
this.normalLinks.appendChild (lk);
if (!noSuggestions && HotCat.use_up_down) {
this.upDownLinks = make ('span');
lk = make ('a'); lk.href = '#catlinks'; lk.onclick = bind (this.down, this);
lk.appendChild (make (HotCat.links.down, true)); lk.title = HotCat.tooltips.down;
this.upDownLinks.appendChild (make (' ', true));
this.upDownLinks.appendChild (lk);
lk = make ('a'); lk.href = '#catlinks'; lk.onclick = bind (this.up, this);
lk.appendChild (make (HotCat.links.up, true)); lk.title = HotCat.tooltips.up;
this.upDownLinks.appendChild (make (' ', true));
this.upDownLinks.appendChild (lk);
this.normalLinks.appendChild (this.upDownLinks);
}
}
this.linkSpan = make ('span');
this.linkSpan.className = 'noprint nopopups hotcatlink';
this.linkSpan.appendChild (this.normalLinks);
this.undelLink = make ('span');
this.undelLink.className = 'nopopups hotcatlink';
this.undelLink.style.display = 'none';
lk = make ('a'); lk.href = '#catlinks'; lk.onclick = bind (this.restore, this);
lk.appendChild (make (HotCat.links.restore, true)); lk.title = HotCat.tooltips.restore;
this.undelLink.appendChild (make (' ', true));
this.undelLink.appendChild (lk);
this.linkSpan.appendChild (this.undelLink);
},
invokeSuggestions : function (dont_autocomplete) {
if (this.engine && suggestionConfigs[this.engine] && suggestionConfigs[this.engine].temp && !dont_autocomplete) {
this.engine = HotCat.suggestions; // Reset to a search upon input
}
this.state = CategoryEditor.CHANGE_PENDING;
var self = this;
window.setTimeout (function () {self.textchange (dont_autocomplete);}, HotCat.suggest_delay);
},
makeForm : function () {
var form = make ('form');
form.method = 'POST'; form.onsubmit = bind (this.accept, this);
this.form = form;
var self = this;
var text = make ('input'); text.type = 'text'; text.size = HotCat.editbox_width;
if (!noSuggestions) {
// Be careful here to handle IME input. This is browser/OS/IME dependent, but basically there are two mechanisms:
// - Modern (DOM Level 3) browsers use compositionstart/compositionend events to signal composition; if the
// composition is not canceled, there'll be a textInput event following. During a composition key events are
// either all suppressed (FF/Gecko), or otherwise have keyDown === IME for all keys (Webkit).
// - Webkit sends a textInput followed by keyDown === IME and a keyUp with the key that ended composition.
// - Gecko doesn't send textInput but just a keyUp with the key that ended composition, without sending keyDown
// first. Gecko doesn't send any keydown while IME is active.
// - Older browsers signal composition by keyDown === IME for the first and subsequent keys for a composition. The
// first keyDown !== IME is certainly after the end of the composition. Typically, composition end can also be
// detected by a keyDown IME with a keyUp of space, tab, escape, or return. (Example: IE8)
text.onkeyup =
function (evt) {
evt = evt || window.event || window.Event; // W3C, IE, Netscape
var key = evt.keyCode || 0;
if (self.ime && self.lastKey === IME && !self.usesComposition && (key === TAB || key === RET || key == ESC || key === SPACE)) self.ime = false;
if (self.ime) return true;
if (key === UP || key === DOWN || key === PGUP || key === PGDOWN) {
// In case a browser doesn't generate keypress events for arrow keys...
if (self.keyCount === 0) return self.processKey (evt);
} else {
if (key === ESC && self.lastKey !== IME) {
if (!self.resetKeySelection ()) {
// No undo of key selection: treat ESC as "cancel".
self.cancel ();
return;
}
}
// Also do this for ESC as a workaround for Firefox bug 524360
// https://bugzilla.mozilla.org/show_bug.cgi?id=524360
self.invokeSuggestions (key === BS || key === DEL || key === ESC);
}
return true;
};
text.onkeydown =
function (evt) {
evt = evt || window.event || window.Event; // W3C, IE, Netscape
var key = evt.keyCode || 0;
self.lastKey = key;
self.keyCount = 0;
// DOM Level < 3 IME input
if (!self.ime && key === IME && !self.usesComposition) {
// self.usesComposition catches browsers that may emit spurious keydown IME after a composition has ended
self.ime = true;
} else if (self.ime && key !== IME && !(key >= 16 && key <= 20 || key >= 91 && key <= 93 || key === 144)) {
// Ignore control keys: ctrl, shift, alt, alt gr, caps lock, windows/apple cmd keys, num lock. Only the windows keys
// terminate IME (apple cmd doesn't), but they also cause a blur, so it's OK to ignore them here.
// Note: Safari 4 (530.17) propagates ESC out of an IME composition (observed at least on Win XP).
self.ime = false;
}
if (self.ime) return true;
// Handle return explicitly, to override the default form submission to be able to check for ctrl
if (key === RET) return self.accept (evt);
// Inhibit default behavior of ESC (revert to last real input in FF: we do that ourselves)
return (key === ESC) ? evtKill(evt) : true;
};
// And handle continued pressing of arrow keys
text.onkeypress = function (evt) {self.keyCount++; return self.processKey (evt);};
addEvent (text, 'focus', function () { makeActive(self); });
// On IE, blur events are asynchronous, and may thus arrive after the element has lost the focus. Since IE
// can get the selection only while the element is active (has the focus), we may not always get the selection.
// Therefore, use an IE-specific synchronous event on IE...
// Don't test for text.selectionStart being defined; FF3.6.4 raises an exception when trying to access that
// property while the element is not being displayed.
addEvent (text
, (typeof text.onbeforedeactivate != 'undefined' && text.createTextRange) ? 'beforedeactivate' : 'blur'
, bind (this.saveView, this)
);
// DOM Level 3 IME handling
try {
// Setting lastKey = IME provides a fake keyDown for Gecko's single keyUp after a cmposition. If we didn't do this,
// cancelling a composition via ESC would also cancel and close the whole category input editor.
addEvent(text, 'compositionstart', function (evt) { self.lastKey = IME; self.usesComposition = true; self.ime = true; });
addEvent(text, 'compositionend', function (evt) { self.lastKey = IME; self.usesComposition = true; self.ime = false; });
addEvent(text, 'textInput', function (evt) { self.ime = false; self.invokeSuggestions(false); });
} catch (any) {
// Just in case some browsers might produce exceptions with these DOM Level 3 events
}
addEvent(text, 'blur', function (evt) { self.usesComposition = false; self.ime = false; });
}
this.text = text;
this.icon = make ('img');
var list = null;
if (!noSuggestions) {
list = make ('select');
list.onclick = function (e) { if (self.highlightSuggestion(0)) self.textchange (false, true); };
list.ondblclick = function (e) { if (self.highlightSuggestion(0)) self.accept (e); };
list.onchange = function (e) { self.highlightSuggestion(0); self.text.focus(); };
list.onkeyup =
function (evt) {
evt = evt || window.event || window.Event; // W3C, IE, Netscape
if (evt.keyCode === ESC) {
self.resetKeySelection ();
self.text.focus();
window.setTimeout (function () {self.textchange (true);}, HotCat.suggest_delay);
} else if (evt.keyCode === RET) {
self.accept (evt);
}
};
if (!HotCat.fixed_search) {
var engineSelector = make ('select');
for (var key in suggestionConfigs) {
if (suggestionConfigs[key].show) {
var opt = make ('option');
opt.value = key;
if (key == this.engine) opt.selected = true;
opt.appendChild (make (suggestionConfigs[key].name, true));
engineSelector.appendChild (opt);
}
}
engineSelector.onchange =
function () {
self.engine = self.engineSelector.options[self.engineSelector.selectedIndex].value;
self.text.focus();
self.textchange (true, true); // Don't autocomplete, force re-display of list
};
this.engineSelector = engineSelector;
}
}
this.list = list;
function button_label (id, defaultText) {
var label = null;
if ( onUpload
&& typeof UFUI != 'undefined'
&& typeof UIElements != 'undefined'
&& typeof UFUI.getLabel == 'function')
{
try {
label = UFUI.getLabel (id, true);
// Extract the plain text. IE doesn't know that Node.TEXT_NODE === 3
while (label && label.nodeType != 3) label = label.firstChild;
} catch (ex) {
label = null;
}
}
if (!label || !label.data) return defaultText;
return label.data;
}
// Do not use type 'submit'; we cannot detect modifier keys if we do
var OK = make ('input'); OK.type = 'button';
OK.value = button_label ('wpOkUploadLbl', HotCat.messages.ok);
OK.onclick = bind (this.accept, this);
this.ok = OK;
var cancel = make ('input'); cancel.type = 'button';
cancel.value = button_label ('wpCancelUploadLbl', HotCat.messages.cancel);
cancel.onclick = bind (this.cancel, this);
this.cancelButton = cancel;
var span = make ('span');
span.className = 'hotcatinput';
span.style.position = 'relative';
// FF3.6: add the input field first, then the two absolutely positioned elements. Otherwise, FF3.6 may leave the
// suggestions and the selector at the right edge of the screen if display of the input field causes a re-layout
// moving the form to the front of the next line.
span.appendChild (text);
// IE8/IE9: put some text into this span (a0 is nbsp) and make sure it always stays on the
// same line as the input field, otherwise, IE8/9 miscalculates the height of the span and
// then the engine selector may overlap the input field.
span.appendChild (make ('\xa0', true));
span.style.whiteSpace = 'nowrap';
if (list) span.appendChild (list);
if (this.engineSelector) span.appendChild (this.engineSelector);
if (!noSuggestions) span.appendChild (this.icon);
span.appendChild (OK);
span.appendChild (cancel);
form.appendChild(span);
form.style.display = 'none';
this.span.appendChild (form);
},
display : function (evt) {
if (this.isAddCategory && !onUpload) {
var newAdder = new CategoryEditor (this.line, null, this.span, true); // Create a new one
}
if (!commitButton && !onUpload) {
for (var i = 0; i < editors.length; i++) {
if (editors[i].state != CategoryEditor.UNCHANGED) {
setMultiInput();
break;
}
}
}
if (!this.form) {
this.makeForm ();
}
if (this.list) this.list.style.display = 'none';
if (this.engineSelector) this.engineSelector.style.display = 'none';
this.currentCategory = this.lastSavedCategory;
this.currentExists = this.lastSavedExists;
this.currentHidden = this.lastSavedHidden;
this.currentKey = this.lastSavedKey;
this.icon.src = armorUri(this.currentExists ? HotCat.existsYes : HotCat.existsNo);
this.text.value = this.currentCategory + (this.currentKey !== null ? '|' + this.currentKey : "");
this.originalState = this.state;
this.lastInput = this.currentCategory;
this.inputExists = this.currentExists;
this.state = this.state == CategoryEditor.UNCHANGED ? CategoryEditor.OPEN : CategoryEditor.CHANGE_PENDING;
this.lastSelection = {start: this.currentCategory.length, end: this.currentCategory.length};
this.showsList = false;
// Display the form
if (this.catLink) this.catLink.style.display = 'none';
this.linkSpan.style.display = 'none';
this.form.style.display = 'inline';
this.ok.disabled = false;
// Kill the event before focussing, otherwise IE will kill the onfocus event!
var result = evtKill (evt);
this.text.focus();
this.text.readOnly = false;
checkMultiInput ();
return result;
},
show : function (evt, engine, readOnly) {
var result = this.display (evt);
var v = this.lastSavedCategory;
if (v.length === 0) return result;
this.text.readOnly = !!readOnly;
this.engine = engine;
this.textchange (false, true); // do autocompletion, force display of suggestions
forceRedraw ();
return result;
},
open : function (evt) {
return this.show (evt, (this.engine && suggestionConfigs[this.engine].temp) ? HotCat.suggestions : this.engine);
},
down : function (evt) {
return this.show (evt, 'subcat', true);
},
up : function (evt) {
return this.show (evt, 'parentcat');
},
cancel : function () {
if (this.isAddCategory && !onUpload) {
this.removeEditor(); // We added a new adder when opening
return;
}
// Close, re-display link
this.inactivate();
this.form.style.display = 'none';
if (this.catLink) this.catLink.style.display = "";
this.linkSpan.style.display = "";
this.state = this.originalState;
this.currentCategory = this.lastSavedCategory;
this.currentKey = this.lastSavedKey;
this.currentExists = this.lastSavedExists;
this.currentHidden = this.lastSavedHidden;
if (this.catLink) {
if (this.currentKey && this.currentKey.length > 0) {
this.catLink.title = this.currentKey;
} else {
this.catLink.title = "";
}
}
if (this.state == CategoryEditor.UNCHANGED) {
if (this.catLink) this.catLink.style.backgroundColor = 'transparent';
} else {
if (!onUpload) {
try {
this.catLink.style.backgroundColor = HotCat.bg_changed;
} catch (ex) {}
}
}
checkMultiInput ();
forceRedraw ();
},
removeEditor : function () {
if (!newDOM) {
var next = this.span.nextSibling;
if (next) next.parentNode.removeChild (next);
}
this.span.parentNode.removeChild (this.span);
for (var i = 0; i < editors.length; i++) {
if (editors[i] == this) {
editors.splice (i, 1);
break;
}
}
checkMultiInput ();
var self = this;
window.setTimeout (function () {delete self;}, 10);
},
rollback : function (evt) {
this.undoLink.parentNode.removeChild (this.undoLink);
this.undoLink = null;
this.currentCategory = this.originalCategory;
this.currentKey = this.originalKey;
this.currentExists = this.originalExists;
this.currentHidden = this.originalHidden;
this.lastSavedCategory = this.originalCategory;
this.lastSavedKey = this.originalKey;
this.lastSavedExists = this.originalExists;
this.lastSavedHidden = this.originalHidden;
this.state = CategoryEditor.UNCHANGED;
if (!this.currentCategory || this.currentCategory.length === 0) {
// It was a newly added category. Remove the whole editor.
this.removeEditor();
} else {
// Redisplay the link...
this.catLink.removeChild (this.catLink.firstChild);
this.catLink.appendChild (make (this.currentCategory, true));
this.catLink.href = wikiPagePath (HotCat.category_canonical + ':' + this.currentCategory);
this.catLink.title = this.currentKey || "";
this.catLink.className = this.currentExists ? "" : 'new';
this.catLink.style.backgroundColor = 'transparent';
if (this.upDownLinks) this.upDownLinks.style.display = this.currentExists ? "" : 'none';
checkMultiInput ();
}
return evtKill (evt);
},
inactivate : function () {
if (this.list) this.list.style.display = 'none';
if (this.engineSelector) this.engineSelector.style.display = 'none';
this.is_active = false;
},
acceptCheck : function (dontCheck) {
this.sanitizeInput ();
var value = this.text.value.split('|');
var key = null;
if (value.length > 1) key = value[1];
var v = value[0].replace(/_/g, ' ').replace(/^\s+|\s+$/g, "");
if (HotCat.capitalizePageNames) v = capitalize (v);
this.lastInput = v;
v = replaceShortcuts(v, HotCat.shortcuts);
if (v.length === 0) {
this.cancel ();
return false;
}
if (!dontCheck
&& ( conf.wgNamespaceNumber === 14 && v == conf.wgTitle
|| HotCat.blacklist && HotCat.blacklist.test(v))
)
{
this.cancel ();
return false;
}
this.currentCategory = v;
this.currentKey = key;
this.currentExists = this.inputExists;
return true;
},
accept : function (evt) {
this.noCommit = (evtKeys (evt) & 1) !== 0;
var result = evtKill (evt);
if (this.acceptCheck ()) {
var toResolve = [this];
var original = this.currentCategory;
resolveMulti (
toResolve
,function (resolved) {
if (resolved[0].dab) {
showDab (resolved[0]);
} else {
if (resolved[0].acceptCheck(true)) {
resolved[0].commit (
(resolved[0].currentCategory != original)
? HotCat.messages.cat_resolved.replace (/\$1/g, original)
: null
);
}
}
}
);
}
return result;
},
close : function () {
if (!this.catLink) {
// Create a catLink
this.catLink = make ('a');
this.catLink.appendChild (make ('foo', true));
this.catLink.style.display = 'none';
this.span.insertBefore (this.catLink, this.span.firstChild.nextSibling);
}
this.catLink.removeChild (this.catLink.firstChild);
this.catLink.appendChild (make (this.currentCategory, true));
this.catLink.href = wikiPagePath (HotCat.category_canonical + ':' + this.currentCategory);
this.catLink.className = this.currentExists ? "" : 'new';
this.lastSavedCategory = this.currentCategory;
this.lastSavedKey = this.currentKey;
this.lastSavedExists = this.currentExists;
this.lastSavedHidden = this.currentHidden;
// Close form and redisplay category
this.inactivate();
this.form.style.display = 'none';
this.catLink.title = this.currentKey || "";
this.catLink.style.display = "";
if (this.isAddCategory) {
if (onUpload) {
var newAdder = new CategoryEditor (this.line, null, this.span, true); // Create a new one
}
this.isAddCategory = false;
this.linkSpan.parentNode.removeChild (this.linkSpan);
this.makeLinkSpan ();
this.span.appendChild (this.linkSpan);
}
if (!this.undoLink) {
// Append an undo link.
var span = make ('span');
var lk = make ('a'); lk.href = '#catlinks'; lk.onclick = bind (this.rollback, this);
lk.appendChild (make (HotCat.links.undo, true)); lk.title = HotCat.tooltips.undo;
span.appendChild (make (' ', true));
span.appendChild (lk);
this.normalLinks.appendChild (span);
this.undoLink = span;
if (!onUpload) {
try {
this.catLink.style.backgroundColor = HotCat.bg_changed;
} catch (ex) {}
}
}
if (this.upDownLinks) this.upDownLinks.style.display = this.lastSavedExists ? "" : 'none';
this.linkSpan.style.display = "";
this.state = CategoryEditor.CHANGED;
checkMultiInput ();
forceRedraw ();
},
commit : function (comment) {
// Check again to catch problem cases after redirect resolution
if ( ( this.currentCategory == this.originalCategory
&& (this.currentKey == this.originalKey
|| this.currentKey === null && this.originalKey.length === 0
)
)
|| conf.wgNamespaceNumber == 14 && this.currentCategory == conf.wgTitle
|| HotCat.blacklist && HotCat.blacklist.test (this.currentCategory)
)
{
this.cancel ();
return;
}
if (commitButton || onUpload) {
this.close ();
} else {
this.close ();
var self = this;
initiateEdit (function (failure) {performChanges (failure, self);}, function (msg) {alert (msg);});
}
},
remove : function (evt) {
this.doRemove (evtKeys (evt) & 1);
return evtKill (evt);
},
doRemove : function (noCommit) {
if (this.isAddCategory) { // Empty input on adding a new category
this.cancel ();
return;
}
if (!commitButton && !onUpload) {
for (var i = 0; i < editors.length; i++) {
if (editors[i].state != CategoryEditor.UNCHANGED) {
setMultiInput();
break;
}
}
}
if (commitButton) {
this.catLink.title = "";
this.catLink.style.cssText += '; text-decoration : line-through !important;';
try {
this.catLink.style.backgroundColor = HotCat.bg_changed;
} catch (ex) {}
this.originalState = this.state;
this.state = CategoryEditor.DELETED;
this.normalLinks.style.display = 'none';
this.undelLink.style.display = "";
checkMultiInput ();
} else {
if (onUpload) {
// Remove this editor completely
this.removeEditor ();
} else {
this.originalState = this.state;
this.state = CategoryEditor.DELETED;
this.noCommit = noCommit || HotCat.del_needs_diff;
var self = this;
initiateEdit (function (failure) {performChanges (failure, self);}, function (msg) {self.state = self.originalState; alert (msg);});
}
}
},
restore : function (evt) {
// Can occur only if we do have a commit button and are not on the upload form
this.catLink.title = this.currentKey || "";
this.catLink.style.textDecoration = "";
this.state = this.originalState;
if (this.state == CategoryEditor.UNCHANGED) {
this.catLink.style.backgroundColor = 'transparent';
} else {
try {
this.catLink.style.backgroundColor = HotCat.bg_changed;
} catch (ex) {}
}
this.normalLinks.style.display = "";
this.undelLink.style.display = 'none';
checkMultiInput ();
return evtKill (evt);
},
// Internal operations
selectEngine : function (engineName) {
if (!this.engineSelector) return;
for (var i = 0; i < this.engineSelector.options.length; i++) {
this.engineSelector.options[i].selected = this.engineSelector.options[i].value == engineName;
}
},
sanitizeInput : function () {
var v = this.text.value || "";
v = v.replace(/^(\s|_)+/, ""); // Trim leading blanks and underscores
var re = new RegExp ('^(' + HotCat.category_regexp + '):');
if (re.test (v)) {
v = v.substring (v.indexOf (':') + 1).replace(/^(\s|_)+/, "");
}
if (HotCat.capitalizePageNames) v = capitalize (v);
// Only update the input field if there is a difference. IE8 appears to reset the selection
// and place the cursor at the front upon reset, which makes our autocompletetion become a
// nuisance. FF and IE6 don't seem to have this problem.
if (this.text.value !== null && this.text.value != v)
this.text.value = v;
},
makeCall : function (url, callbackObj, engine, queryKey, cleanKey) {
var cb = callbackObj;
var e = engine;
var v = queryKey;
var z = cleanKey;
var thisObj = this;
function done () {
cb.callsMade++;
if (cb.callsMade === cb.nofCalls) {
if (cb.exists) cb.allTitles.exists = true;
if (cb.normalized) cb.allTitles.normalized = cb.normalized;
if (!cb.dontCache && !suggestionConfigs[cb.engineName].cache[z]) {
suggestionConfigs[cb.engineName].cache[z] = cb.allTitles;
}
thisObj.text.readOnly = false;
if (!cb.cancelled) thisObj.showSuggestions (cb.allTitles, cb.noCompletion, v, cb.engineName);
if (cb === thisObj.callbackObj) thisObj.callbackObj = null;
delete cb;
}
}
getJSON ({
uri : url
,success : function (json) {
var titles = e.handler (json, z);
if (titles && titles.length > 0) {
if (cb.allTitles === null) {
cb.allTitles = titles;
} else {
cb.allTitles = cb.allTitles.concat (titles);
}
if (titles.exists) cb.exists = true;
if (titles.normalized) cb.normalized = titles.normalized;
}
done();
}
,error : function (req) {if (!req) noSuggestions = true; cb.dontCache = true; done(); }
});
},
callbackObj : null,
textchange : function (dont_autocomplete, force) {
// Hide all other lists
makeActive (this);
// Get input value, omit sort key, if any
this.sanitizeInput ();
var v = this.text.value;
// Disregard anything after a pipe.
var pipe = v.indexOf ('|');
if (pipe >= 0) {
this.currentKey = v.substring (pipe+1);
v = v.substring (0, pipe);
} else {
this.currentKey = null;
}
if (this.lastInput == v && !force) return; // No change
if (this.lastInput != v) checkMultiInput ();
this.lastInput = v;
this.lastRealInput = v;
// Mark blacklisted inputs.
this.ok.disabled = v.length > 0 && HotCat.blacklist && HotCat.blacklist.test (v);
if (noSuggestions) {
// No Ajax: just make sure the list is hidden
if (this.list) this.list.style.display = 'none';
if (this.engineSelector) this.engineSelector.style.display = 'none';
if (this.icon) this.icon.style.display = 'none';
return;
}
if (v.length === 0) { this.showSuggestions([]); return; }
var cleanKey = v.replace(/[\u200E\u200F\u202A-\u202E]/g, "").replace(wikiTextBlankRE, ' ');
cleanKey = replaceShortcuts(cleanKey, HotCat.shortcuts);
cleanKey = cleanKey.replace(/^\s+|\s+$/g, '');
if (cleanKey.length === 0) { this.showSuggestions([]); return; }
if (this.callbackObj) this.callbackObj.cancelled = true;
var engineName = suggestionConfigs[this.engine] ? this.engine : 'combined';
dont_autocomplete = dont_autocomplete || suggestionConfigs[engineName].noCompletion;
if (suggestionConfigs[engineName].cache[cleanKey]) {
this.showSuggestions (suggestionConfigs[engineName].cache[cleanKey], dont_autocomplete, v, engineName);
return;
}
var engines = suggestionConfigs[engineName].engines;
this.callbackObj =
{allTitles: null, callsMade: 0, nofCalls: engines.length, noCompletion: dont_autocomplete, engineName: engineName};
this.makeCalls (engines, this.callbackObj, v, cleanKey);
},
makeCalls : function (engines, cb, v, cleanKey) {
for (var j = 0; j < engines.length; j++) {
var engine = suggestionEngines[engines[j]];
var url = conf.wgServer + conf.wgScriptPath + engine.uri.replace (/\$1/g, encodeURIComponent (cleanKey));
this.makeCall (url, cb, engine, v, cleanKey);
}
},
showSuggestions : function (titles, dontAutocomplete, queryKey, engineName) {
this.text.readOnly = false;
this.dab = null;
this.showsList = false;
if (!this.list) return;
if (noSuggestions) {
if (this.list) this.list.style.display = 'none';
if (this.engineSelector) this.engineSelector.style.display = 'none';
if (this.icon) this.icon.style.display = 'none';
this.inputExists = true; // Default...
return;
}
this.engineName = engineName;
if (engineName) {
if (!this.engineSelector) this.engineName = null;
} else {
if (this.engineSelector) this.engineSelector.style.display = 'none';
}
if (queryKey) {
if (this.lastInput.indexOf (queryKey) !== 0) return;
if (this.lastQuery && this.lastInput.indexOf (this.lastQuery) === 0 && this.lastQuery.length > queryKey.length)
return;
}
this.lastQuery = queryKey;
// Get current input text
var v = this.text.value.split('|');
var key = v.length > 1 ? '|' + v[1] : "";
v = (HotCat.capitalizePageNames ? capitalize (v[0]) : v[0]);
var vNormalized = v;
var knownToExist = titles && titles.exists;
var i;
if (titles) {
if (titles.normalized && v.indexOf(queryKey) === 0) {
// We got back a different normalization than what is in the input field
vNormalized = titles.normalized + v.substring(queryKey.length);
}
var vLow = vNormalized.toLowerCase ();
// Strip blacklisted categories
if (HotCat.blacklist) {
for (i = 0; i < titles.length; i++) {
if (HotCat.blacklist.test (titles[i])) {
titles.splice(i, 1);
i--;
}
}
}
titles.sort (
function (a, b) {
if (a == b) return 0;
if (a.indexOf (b) === 0) return 1; // a begins with b: a > b
if (b.indexOf (a) === 0) return -1; // b begins with a: a < b
// Opensearch may return stuff not beginning with the search prefix!
var prefixMatchA = (a.indexOf (vNormalized) === 0 ? 1 : 0);
var prefixMatchB = (b.indexOf (vNormalized) === 0 ? 1 : 0);
if (prefixMatchA != prefixMatchB) return prefixMatchB - prefixMatchA;
// Case-insensitive prefix match!
var aLow = a.toLowerCase(), bLow = b.toLowerCase();
prefixMatchA = (aLow.indexOf (vLow) === 0 ? 1 : 0);
prefixMatchB = (bLow.indexOf (vLow) === 0 ? 1 : 0);
if (prefixMatchA != prefixMatchB) return prefixMatchB - prefixMatchA;
if (a < b) return -1;
if (b < a) return 1;
return 0;
}
);
// Remove duplicates and self-references
for (i = 0; i < titles.length; i++) {
if ( i+1 < titles.length && titles[i] == titles[i+1]
|| conf.wgNamespaceNumber == 14 && titles[i] == conf.wgTitle
)
{
titles.splice (i, 1);
i--;
}
}
}
if (!titles || titles.length === 0) {
if (this.list) this.list.style.display = 'none';
if (this.engineSelector) this.engineSelector.style.display = 'none';
if (engineName && suggestionConfigs[engineName] && !suggestionConfigs[engineName].temp) {
if (this.icon) this.icon.src = armorUri(HotCat.existsNo);
this.inputExists = false;
}
return;
}
var firstTitle = titles[0];
var completed = this.autoComplete (firstTitle, v, vNormalized, key, dontAutocomplete);
var existing = completed || knownToExist || firstTitle == replaceShortcuts(v, HotCat.shortcuts);
if (engineName && suggestionConfigs[engineName] && !suggestionConfigs[engineName].temp) {
this.icon.src = armorUri(existing ? HotCat.existsYes : HotCat.existsNo);
this.inputExists = existing;
}
if (completed) {
this.lastInput = firstTitle;
if (titles.length === 1) {
this.list.style.display = 'none';
if (this.engineSelector) this.engineSelector.style.display = 'none';
return;
}
}
// (Re-)fill the list
while (this.list.firstChild) this.list.removeChild (this.list.firstChild);
for (i = 0 ; i < titles.length ; i++) {
var opt = make ('option') ;
opt.appendChild (make (titles[i], true));
opt.selected = completed && (i === 0);
this.list.appendChild (opt);
}
this.displayList();
},
displayList : function () {
this.showsList = true;
if (!this.is_active) {
this.list.style.display = 'none';
if (this.engineSelector) this.engineSelector.style.display = 'none';
return;
}
var nofItems = (this.list.options.length > HotCat.list_size ? HotCat.list_size : this.list.options.length);
if (nofItems <= 1) nofItems = 2;
this.list.size = nofItems;
this.list.style.align = is_rtl ? 'right' : 'left';
this.list.style.zIndex = 5;
this.list.style.position = 'absolute';
// Compute initial list position. First the height.
var anchor = is_rtl ? 'right' : 'left';
var listh = 0;
if (this.list.style.display == 'none') {
// Off-screen display to get the height
this.list.style.top = this.text.offsetTop + 'px';
this.list.style[anchor] = '-10000px';
this.list.style.display = "";
listh = this.list.offsetHeight;
this.list.style.display = 'none';
} else {
listh = this.list.offsetHeight;
}
// Approximate calculation of maximum list size
var maxListHeight = listh;
if (nofItems < HotCat.list_size) maxListHeight = (listh / nofItems) * HotCat.list_size;
function viewport (what) {
if (is_webkit && !document.evaluate)
return window['inner' + what]; // Safari < 3.0
var s = 'client' + what;
if (window.opera) return document.body[s];
return (document.documentElement ? document.documentElement[s] : 0)
|| document.body[s] || 0;
}
function scroll_offset (what) {
var s = 'scroll' + what;
var result = (document.documentElement ? document.documentElement[s] : 0)
|| document.body[s] || 0;
if (is_rtl && what == 'Left') {
// RTL inconsistencies.
// FF: 0 at the far right, then increasingly negative values.
// IE >= 8: 0 at the far right, then increasingly positive values.
// Webkit: scrollWidth - clientWidth at the far right, then down to zero.
// IE 7: like webkit; IE6: disabled in RTL anyway since too many problems.
// Opera: don't know...
if (result < 0) result = - result;
if (!is_webkit && !is_ie_lt8) {
result = scroll_offset('Width') - viewport('Width') - result;
}
// Now all have webkit behavior, i.e. zero if at the leftmost edge.
}
return result;
}
function position (node) {
// Stripped-down simplified position function. It's good enough for our purposes.
if (node.getBoundingClientRect) {
var box = node.getBoundingClientRect ();
return { x : Math.round (box.left + scroll_offset ('Left'))
,y : Math.round (box.top + scroll_offset ('Top'))
};
}
var t = 0, l = 0;
do {
t = t + (node.offsetTop || 0);
l = l + (node.offsetLeft || 0);
node = node.offsetParent;
} while (node);
return {x : l, y : t};
}
var textPos = position (this.text);
var nl = 0;
var nt = 0;
var offset = 0;
// Opera 9.5 somehow has offsetWidth = 0 here?? Use the next best value...
var textBoxWidth = this.text.offsetWidth || this.text.clientWidth;
if (this.engineName) {
this.engineSelector.style.zIndex = 5;
this.engineSelector.style.position = 'absolute';
this.engineSelector.style.width = textBoxWidth + 'px';
// Figure out the height of this selector: display it off-screen, then hide it again.
if (this.engineSelector.style.display == 'none') {
this.engineSelector.style[anchor] = '-10000px';
this.engineSelector.style.top = '0px';
this.engineSelector.style.display = "";
offset = this.engineSelector.offsetHeight;
this.engineSelector.style.display = 'none';
} else {
offset = this.engineSelector.offsetHeight;
}
this.engineSelector.style[anchor] = nl + 'px';
}
if (textPos.y < maxListHeight + offset + 1) {
// The list might extend beyond the upper border of the page. Let's avoid that by placing it
// below the input text field.
nt = this.text.offsetHeight + offset + 1;
if (this.engineName) this.engineSelector.style.top = this.text.offsetHeight + 'px';
} else {
nt = - listh - offset - 1;
if (this.engineName) this.engineSelector.style.top = - (offset + 1) + 'px';
}
this.list.style.top = nt + 'px';
this.list.style.width = ""; // No fixed width (yet)
this.list.style[anchor] = nl + 'px';
if (this.engineName) {
this.selectEngine (this.engineName);
this.engineSelector.style.display = "";
}
this.list.style.display = 'block';
// Set the width of the list
if (this.list.offsetWidth < textBoxWidth ) {
this.list.style.width = textBoxWidth + 'px';
return;
}
// If the list is wider than the textbox: make sure it fits horizontally into the browser window
var scroll = scroll_offset ('Left');
var view_w = viewport ('Width');
var w = this.list.offsetWidth;
var l_pos = position (this.list);
var left = l_pos.x;
var right = left + w;
if (left < scroll || right > scroll + view_w) {
if (w > view_w) {
w = view_w;
this.list.style.width = w + 'px';
if (is_rtl) {
left = right - w;
} else {
right = left + w;
}
}
var relative_offset = 0;
if (left < scroll) {
relative_offset = scroll - left;
} else if (right > scroll + view_w) {
relative_offset = - (right - scroll - view_w);
}
if (is_rtl) relative_offset = - relative_offset;
if (relative_offset !== 0) {
this.list.style[anchor] = (nl + relative_offset) + 'px';
}
}
},
autoComplete : function (newVal, actVal, normalizedActVal, key, dontModify) {
if (newVal == actVal) return true;
if (dontModify || this.ime || !this.canSelect()) return false;
// If we can't select properly or an IME composition is ongoing, autocompletion would be a major annoyance to the user.
if (newVal.indexOf (actVal) !== 0) {
// Maybe it'll work with the normalized value (NFC)?
if (normalizedActVal && newVal.indexOf(normalizedActVal) === 0) {
if (this.lastRealInput == actVal) this.lastRealInput = normalizedActVal;
actVal = normalizedActVal;
} else {
return false;
}
}
// Actual input is a prefix of the new text. Fill in new text, selecting the newly added suffix
// such that it can be easily removed by typing backspace if the suggestion is unwanted.
this.text.focus();
this.text.value = newVal + key;
this.setSelection (actVal.length, newVal.length);
return true;
},
canSelect : function () {
return this.text.setSelectionRange
|| this.text.createTextRange
|| typeof this.text.selectionStart != 'undefined'
&& typeof this.text.selectionEnd != 'undefined';
},
setSelection : function (from, to) {
// this.text must be focused (at least on IE)
if (!this.text.value) return;
if (this.text.setSelectionRange) { // e.g. khtml
this.text.setSelectionRange (from, to);
} else if (typeof this.text.selectionStart != 'undefined') {
if (from > this.text.selectionStart) {
this.text.selectionEnd = to;
this.text.selectionStart = from;
} else {
this.text.selectionStart = from;
this.text.selectionEnd = to;
}
} else if (this.text.createTextRange) { // IE
var new_selection = this.text.createTextRange();
new_selection.move ('character', from);
new_selection.moveEnd ('character', to - from);
new_selection.select();
}
},
getSelection : function () {
var from = 0, to = 0;
// this.text must be focused (at least on IE)
if (!this.text.value) {
// No text.
} else if (typeof this.text.selectionStart != 'undefined') {
from = this.text.selectionStart;
to = this.text.selectionEnd;
} else if (document.selection && document.selection.createRange) { // IE
var rng = document.selection.createRange().duplicate();
if (rng.parentElement() === this.text) {
try {
var textRng = this.text.createTextRange();
textRng.move('character', 0);
textRng.setEndPoint('EndToEnd', rng);
// We're in a single-line input box: no need to care about IE's strange
// handling of line ends
to = textRng.text.length;
textRng.setEndPoint('EndToStart', rng);
from = textRng.text.length;
} catch (notFocused) {
from = this.text.value.length; to = from; // At end of text
}
}
}
return {start: from, end: to};
},
saveView : function (evt) {
this.lastSelection = this.getSelection ();
},
processKey : function (evt) {
var dir = 0;
switch (this.lastKey) {
case UP: dir = -1;
case DOWN: if (dir === 0) dir = 1;
case PGUP: if (dir === 0) dir = -HotCat.list_size;
case PGDOWN: if (dir === 0) dir = HotCat.list_size;
if (this.list.style.display != 'none') {
// List is visible, so there are suggestions
this.highlightSuggestion (dir);
// Kill the event, otherwise some browsers (e.g., Firefox) may additionally treat an up-arrow
// as "place the text cursor at the front", which we don't want here.
return evtKill (evt);
} else if ( this.keyCount <= 1
&& (!this.callbackObj || this.callbackObj.callsMade == this.callbackObj.nofCalls)
)
{
// If no suggestions displayed, get them, unless we're already getting them.
this.textchange ();
}
break;
case ESC: // Inhibit default behavior (revert to last real input in FF: we do that ourselves)
return evtKill (evt);
}
return true;
},
highlightSuggestion : function (dir) {
if (noSuggestions || !this.list || this.list.style.display == 'none') return false;
var curr = this.list.selectedIndex;
var tgt = -1;
if (dir === 0) {
if (curr < 0 || curr >= this.list.options.length) return false;
tgt = curr;
} else {
tgt = curr < 0 ? 0 : curr + dir;
tgt = tgt < 0 ? 0 : tgt;
if (tgt >= this.list.options.length) tgt = this.list.options.length - 1;
}
if (tgt != curr || dir === 0) {
if (curr >= 0 && curr < this.list.options.length && dir !== 0) this.list.options[curr].selected = false;
this.list.options[tgt].selected = true;
// Get current input text
var v = this.text.value.split('|');
var key = v.length > 1 ? '|' + v[1] : "";
var completed = this.autoComplete (this.list.options[tgt].text, this.lastRealInput, null, key, false);
if (!completed || this.list.options[tgt].text == this.lastRealInput) {
this.text.value = this.list.options[tgt].text + key;
if (this.canSelect()) this.setSelection (this.list.options[tgt].text.length, this.list.options[tgt].text.length);
}
this.lastInput = this.list.options[tgt].text;
this.inputExists = true; // Might be wrong if from a dab list...
if (this.icon) this.icon.src = armorUri(HotCat.existsYes);
this.state = CategoryEditor.CHANGE_PENDING;
}
return true;
},
resetKeySelection : function () {
if (noSuggestions || !this.list || this.list.style.display == 'none') return false;
var curr = this.list.selectedIndex;
if (curr >= 0 && curr < this.list.options.length) {
this.list.options[curr].selected = false;
// Get current input text
var v = this.text.value.split('|');
var key = v.length > 1 ? '|' + v[1] : "";
// ESC is handled strangely by some browsers (e.g., FF); somehow it resets the input value before
// our event handlers ever get a chance to run.
var result = v[0] != this.lastInput;
if (v[0] != this.lastRealInput) {
this.text.value = this.lastRealInput + key;
result = true;
}
this.lastInput = this.lastRealInput;
return result;
}
return false;
}
}; // end CategoryEditor.prototype
function initialize () {
// User configurations. Do this here, called from the onload handler, so that users can
// override it easily in their own user script files by just declaring variables. JSconfig
// is some feature used at Wikimedia Commons.
var config = (typeof JSconfig != 'undefined' && JSconfig.keys) ? JSconfig.keys : {};
HotCat.dont_add_to_watchlist =
(typeof window.hotcat_dont_add_to_watchlist != 'undefined'
? !!window.hotcat_dont_add_to_watchlist
: (typeof config.HotCatDontAddToWatchlist != 'undefined'
? config.HotCatDontAddToWatchlist
: HotCat.dont_add_to_watchlist
)
);
HotCat.no_autocommit =
(typeof window.hotcat_no_autocommit != 'undefined'
? !!window.hotcat_no_autocommit
: (typeof config.HotCatNoAutoCommit != 'undefined'
? config.HotCatNoAutoCommit
: HotCat.no_autocommit
)
);
HotCat.del_needs_diff =
(typeof window.hotcat_del_needs_diff != 'undefined'
? !!window.hotcat_del_needs_diff
: (typeof config.HotCatDelNeedsDiff != 'undefined'
? config.HotCatDelNeedsDiff
: HotCat.del_needs_diff
)
);
HotCat.suggest_delay = window.hotcat_suggestion_delay
|| config['HotCatSuggestionDelay']
|| HotCat.suggest_delay;
HotCat.editbox_width = window.hotcat_editbox_width
|| config['HotCatEditBoxWidth']
|| HotCat.editbox_width;
HotCat.suggestions = window.hotcat_suggestions
|| config['HotCatSuggestions']
|| HotCat.suggestions;
if (typeof HotCat.suggestions != 'string' || !suggestionConfigs[HotCat.suggestions])
HotCat.suggestions = 'combined';
HotCat.fixed_search =
(typeof window.hotcat_suggestions_fixed != 'undefined'
? !!window.hotcat_suggestions_fixed
: (typeof config.HotCatFixedSuggestions != 'undefined'
? config.HotCatFixedSuggestions
: HotCat.fixed_search
)
);
HotCat.single_minor =
(typeof window.hotcat_single_changes_are_minor != 'undefined'
? !!window.hotcat_single_changes_are_minor
: (typeof config.HotCatMinorSingleChanges != 'undefined'
? config.HotCatMinorSingleChanges
: HotCat.single_minor
)
);
HotCat.bg_changed = window.hotcat_changed_background
|| config.HotCatChangedBackground
|| HotCat.bg_changed;
HotCat.use_up_down =
(typeof window.hotcat_use_category_links != 'undefined'
? !!window.hotcat_use_category_links
: (typeof config.HotCatUseCategoryLinks != 'undefined'
? config.HotCatUseCategoryLinks
: HotCat.use_up_down
)
);
HotCat.list_size = window.hotcat_list_size
|| config.HotCatListSize
|| HotCat.list_size;
// Numeric input, make sure we have a numeric value
HotCat.list_size = parseInt (HotCat.list_size, 10);
if (isNaN (HotCat.list_size) || HotCat.list_size < 5) HotCat.list_size = 5;
if (HotCat.list_size > 15) HotCat.list_size = 15;
// Localize search engine names
if (HotCat.engine_names) {
for (var key in HotCat.engine_names) {
if (suggestionConfigs[key] && HotCat.engine_names[key]) {
suggestionConfigs[key].name = HotCat.engine_names[key];
}
}
}
// Catch both native RTL and "faked" RTL through [[MediaWiki:Rtl.js]]
is_rtl = hasClass (document.body, 'rtl');
if (!is_rtl) {
if (document.defaultView && document.defaultView.getComputedStyle) { // Gecko etc.
is_rtl = document.defaultView.getComputedStyle (document.body, null).getPropertyValue ('direction');
} else if (document.body.currentStyle) { // IE, has subtle differences to getComputedStyle
is_rtl = document.body.currentStyle['direction'];
} else { // Not exactly right, but best effort
is_rtl = document.body.style['direction'];
}
is_rtl = (is_rtl == 'rtl');
}
}
function can_edit () {
var container = null;
switch (mw.config.get('skin')) {
case 'cologneblue':
container = document.getElementById ('quickbar');
// Fall through
case 'standard':
case 'nostalgia':
if (!container) container = document.getElementById ('topbar');
var lks = container.getElementsByTagName ('a');
for (var i = 0; i < lks.length; i++) {
if ( param ('title', lks[i].href) == conf.wgPageName
&& param ('action', lks[i].href) == 'edit')
return true;
}
return false;
default:
// all modern skins:
return document.getElementById ('ca-edit') !== null;
}
return false;
}
function setup_upload () {
onUpload = true;
// Add an empty category bar at the end of the table containing the description, and change the onsubmit handler.
var ip = document.getElementById ('mw-htmlform-description') || document.getElementById ('wpDestFile');
if (!ip) {
ip = document.getElementById ('wpDestFile');
while (ip && ip.nodeName.toLowerCase() != 'table') ip = ip.parentNode;
}
if (!ip) return;
var reupload = document.getElementById ('wpForReUpload');
var destFile = document.getElementById ('wpDestFile');
if ( (reupload && !!reupload.value)
|| (destFile && (destFile.disabled || destFile.readOnly)))
return; // re-upload form...
// Insert a table row with two fields (label and empty category bar)
var labelCell = make ('td');
var lineCell = make ('td');
// Create the category line
catLine = make ('div');
catLine.className = 'catlinks';
catLine.id = 'catlinks';
catLine.style.textAlign = is_rtl ? 'right' : 'left';
// We'll be inside a table row. Make sure that we don't have margins or strange borders.
catLine.style.margin = '0';
catLine.style.border = 'none';
lineCell.appendChild (catLine);
// Create the label
var label = null;
if ( typeof UFUI != 'undefined'
&& typeof UIElements != 'undefined'
&& typeof UFUI.getLabel == 'function'
)
{
try {
label = UFUI.getLabel('wpCategoriesUploadLbl');
} catch (ex) {
label = null;
}
}
if (!label) {
labelCell.id = 'hotcatLabel';
labelCell.appendChild (make (HotCat.categories, true));
} else {
labelCell.id = 'hotcatLabelTranslated';
labelCell.appendChild (label);
}
labelCell.className = 'mw-label';
labelCell.style.textAlign = 'right';
labelCell.style.verticalAlign = 'middle';
// Change the onsubmit handler
var form = document.getElementById('upload') || document.getElementById('mw-upload-form');
if (form) {
var newRow = ip.insertRow (-1);
newRow.appendChild (labelCell);
newRow.appendChild (lineCell);
form.onsubmit = (function (oldSubmit) {
return function () {
var do_submit = true;
if (oldSubmit) {
if (typeof oldSubmit == 'string')
do_submit = eval (oldSubmit);
else if (typeof oldSubmit == 'function')
do_submit = oldSubmit.apply (form, arguments);
}
if (!do_submit) return false;
closeForm ();
// Copy the categories
var eb = document.getElementById ('wpUploadDescription')
|| document.getElementById ('wpDesc');
var addedOne = false;
for (var i = 0; i < editors.length; i++) {
var t = editors[i].currentCategory;
if (!t) continue ;
var key = editors[i].currentKey;
var new_cat = '[[' + HotCat.category_canonical + ':' + t + (key ? '|' + key : "") + ']]';
// Only add if not already present
var cleanedText = eb.value
.replace(/<\!--(\s|\S)*?--\>/g, "")
.replace(/<nowiki\>(\s|\S)*?<\/nowiki>/g, "");
if (!find_category (cleanedText, t, true)) {
eb.value += '\n' + new_cat;
addedOne = true;
}
}
if (addedOne) {
// Remove "subst:unc" added by Flinfo if it didn't find categories
eb.value = eb.value.replace(/\{\{subst:unc\}\}/g, "");
}
return true;
};
}) (form.onsubmit);
}
}
var cleanedText = null;
function isOnPage (span) {
var catTitle = title (span.firstChild.getAttribute ('href', 2));
if (!catTitle) return null;
catTitle = catTitle.substr (catTitle.indexOf (':') + 1).replace (/_/g, ' ');
if (HotCat.blacklist && HotCat.blacklist.test (catTitle)) return null;
var result = { title : catTitle, match : ["", "", ""] };
if (pageText === null) return result;
if (cleanedText === null) {
cleanedText = pageText
.replace(/<\!--(\s|\S)*?--\>/g, "")
.replace(/<nowiki\>(\s|\S)*?<\/nowiki>/g, "");
}
result.match = find_category (cleanedText, catTitle, true);
return result;
}
var initialized = false;
var setupTimeout = null;
function findByClass (scope, tag, className) {
// Compatibility routine. Uses jQuery if available, otherwise works with older getElementsByClassName
var result;
if (window.jQuery) {
result = window.jQuery(scope).find(tag + '.' + className);
} else {
result = getElementsByClassName(scope, tag, className);
}
return (result && result.length) ? result[0] : null;
}
function setup (additionalWork) {
if (initialized) return;
initialized = true;
if (setupTimeout) {
window.clearTimeout (setupTimeout);
setupTimeout = null;
}
// Find the category bar, or create an empty one if there isn't one. Then add -/+- links after
// each category, and add the + link.
catLine = catLine // Special:Upload
|| document.getElementById ('mw-normal-catlinks') // MW >= 1.13alpha
|| findByClass (document , 'p' , 'catlinks'); // MW < 1.13
var hiddenCats = document.getElementById ('mw-hidden-catlinks');
if (!catLine) {
var footer = null;
if (!hiddenCats) {
footer = findByClass (document , 'div' , 'printfooter');
if (!footer) return; // Don't know where to insert the category line
}
catLine = make ('div');
catLine.id = 'mw-normal-catlinks';
catLine.style.textAlign = is_rtl ? 'right' : 'left';
// Add a label
var label = make ('a');
label.href = conf.wgArticlePath.replace ('$1', 'Special:Categories');
label.title = HotCat.categories;
label.appendChild (make (HotCat.categories, true));
catLine.appendChild (label);
catLine.appendChild (make (':', true));
// Insert the new category line
var container = (hiddenCats ? hiddenCats.parentNode : document.getElementById ('catlinks'));
if (!container) {
container = make ('div');
container.id = 'catlinks';
footer.parentNode.insertBefore (container, footer.nextSibling);
}
container.className = 'catlinks noprint';
container.style.display = "";
if (!hiddenCats) {
container.appendChild (catLine);
} else {
container.insertBefore (catLine, hiddenCats);
}
} // end if catLine exists
if (is_rtl) catLine.dir = 'rtl';
// Create editors for all existing categories
function createEditors (line, is_hidden) {
var i;
var cats = line.getElementsByTagName ('li');
if (cats.length > 0) {
newDOM = true; line = cats[0].parentNode;
} else {
cats = line.getElementsByTagName ('span');
}
// Copy cats, otherwise it'll also magically contain our added spans as it is a live collection!
var copyCats = new Array (cats.length);
for (i = 0; i < cats.length; i++) copyCats[i] = cats[i];
var editor = null;
for (i = 0; i < copyCats.length; i++) {
var test = isOnPage (copyCats[i]);
if (test !== null && test.match !== null) {
editor = new CategoryEditor (line, copyCats[i], test.title, test.match[2], is_hidden);
}
}
return copyCats.length > 0 ? copyCats[copyCats.length-1] : null;
}
var lastSpan = createEditors (catLine, false);
// Create one to add a new category
var editor = new CategoryEditor(newDOM ? catLine.getElementsByTagName('ul')[0] : catLine, null, null, lastSpan !== null, false);
if (!onUpload) {
if (pageText !== null && hiddenCats) {
if (is_rtl) hiddenCats.dir = 'rtl';
createEditors (hiddenCats, true);
}
// And finally add the "multi-mode" span. (Do this at the end, otherwise it ends up in the list above.)
var enableMulti = make ('span');
enableMulti.className = 'noprint';
if (is_rtl) enableMulti.dir = 'rtl';
catLine.insertBefore (enableMulti, catLine.firstChild.nextSibling);
enableMulti.appendChild (make ('\xa0', true)); // nbsp
multiSpan = make ('span');
enableMulti.appendChild (multiSpan);
multiSpan.innerHTML = '(<a>' + HotCat.addmulti + '</a>)';
var lk = multiSpan.getElementsByTagName ('a')[0];
lk.onclick = function (evt) {setMultiInput (); checkMultiInput (); return evtKill (evt);};
lk.title = HotCat.multi_tooltip;
lk.style.cursor = 'pointer';
}
cleanedText = null;
if (typeof additionalWork == 'function') additionalWork();
setupCompleted.loaded(); // Trigger signal; execute registered functions
if (window.jQuery) jQuery('body').trigger('hotcatSetupCompleted');
}
function setPage (json) {
var startTime = null;
if (json && json.query) {
if (json.query.pages) {
var page = json.query.pages[conf.wgArticleId === 0 ? "-1" : "" + conf.wgArticleId];
if (page) {
if (page.revisions && page.revisions.length > 0) {
// Revisions are sorted by revision ID, hence [0] is the one we asked for, and possibly there's a [1] if we're
// not on the latest revision (edit conflicts and such).
pageText = page.revisions[0]['*'];
if (page.revisions[0].timestamp) pageTime = page.revisions[0].timestamp.replace (/\D/g, "");
if (page.revisions[0].revid) pageTextRevId = page.revisions[0].revid;
if (page.revisions.length > 1) conflictingUser = page.revisions[1].user;
}
if (page.lastrevid) lastRevId = page.lastrevid;
if (page.starttimestamp) startTime = page.starttimestamp.replace (/\D/g, "");
pageWatched = typeof page.watched == 'string';
editToken = page.edittoken;
if (page.langlinks && (!json['query-continue'] || !json['query-continue'].langlinks)) {
// We have interlanguage links, and we got them all.
var re = "";
for (var i = 0; i < page.langlinks.length; i++) {
re += (i > 0 ? '|' : "") + page.langlinks[i].lang.replace(/([\\\^\$\.\?\*\+\(\)])/g, '\\$1');
}
if (re.length > 0) {
interlanguageRE = new RegExp ('((^|\\n\\r?)(\\[\\[\\s*(' + re + ')\\s*:[^\\]]+\\]\\]\\s*))+$');
}
}
}
}
// Siteinfo
if (json.query.general) {
HotCat.capitalizePageNames = (json.query.general['case'] == 'first-letter');
if (json.query.general.time && !startTime) startTime = json.query.general.time.replace (/\D/g, "");
}
serverTime = startTime;
// Userinfo
if (json.query.userinfo && json.query.userinfo.options) {
watchCreate = !HotCat.dont_add_to_watchlist && json.query.userinfo.options.watchcreations == '1';
watchEdit = !HotCat.dont_add_to_watchlist && json.query.userinfo.options.watchdefault == '1';
minorEdits = json.query.userinfo.options.minordefault == 1;
// If the user has the "All edits are minor" preference enabled, we should honor that
// for single category changes, no matter what the site configuration is.
if (minorEdits) HotCat.single_minor = true;
}
}
}
function createCommitForm () {
if (commitForm) return;
var formContainer = make ('div');
formContainer.style.display = 'none';
document.body.appendChild (formContainer);
formContainer.innerHTML =
'<form id="hotcatCommitForm" method="post" enctype="multipart/form-data" action="'
+ conf.wgScript + '?title=' + encodeURIComponent (conf.wgPageName)
+ '&action=edit">'
+ '<input type="hidden" name="wpTextbox1" />'
+ '<input type="hidden" name="model" value="wikitext" />'
+ '<input type="hidden" name="format" value="text/x-wiki" />'
+ '<input type="hidden" name="wpSummary" value="" />'
+ '<input type="checkbox" name="wpMinoredit" value="1" />'
+ '<input type="checkbox" name="wpWatchthis" value="1" />'
+ '<input type="hidden" name="wpAutoSummary" value="" />'
+ '<input type="hidden" name="wpEdittime" />'
+ '<input type="hidden" name="wpStarttime" />'
+ '<input type="hidden" name="wpDiff" value="wpDiff" />'
+ '<input type="hidden" name="oldid" value="0" />'
+ '<input type="submit" name="hcCommit" value="hcCommit" />'
+ '<input type="hidden" name="wpEditToken" />'
+ '<input type="hidden" name="wpUltimateParam" value="1" />'
+ '</form>';
commitForm = document.getElementById ('hotcatCommitForm');
}
function getPage () {
// We know we have an article here.
if (conf.wgArticleId === 0) {
// Doesn't exist yet.
pageText = "";
pageTime = null;
setup (createCommitForm);
} else {
var url = conf.wgServer + conf.wgScriptPath + '/api.php?format=json&callback=HotCat.start&action=query&titles='
+ encodeURIComponent (conf.wgPageName)
+ '&prop=info%7Crevisions&rvprop=content%7Ctimestamp%7Cids&meta=siteinfo&rvlimit=1&rvstartid='
+ conf.wgCurRevisionId;
var s = make ('script');
s.src = armorUri(url);
s.type = 'text/javascript';
HotCat.start = function (json) { setPage (json); setup (createCommitForm); };
document.getElementsByTagName ('head')[0].appendChild (s);
setupTimeout = window.setTimeout (function () {setup (createCommitForm);}, 4000); // 4 sec, just in case getting the wikitext takes longer.
}
}
function run () {
if (HotCat.started) return;
HotCat.started = true;
loadTrigger.register(really_run);
}
function really_run () {
initialize ();
if (is_rtl && is_ie6) return; // Disabled! IE6 with RTL is just too broken...
if (!HotCat.upload_disabled && conf.wgNamespaceNumber === -1 && conf.wgCanonicalSpecialPageName == 'Upload' && conf.wgUserName) {
setup_upload ();
setup (function () {
// Check for state restoration once the setup is done otherwise, but before signalling setup completion
if ( typeof UploadForm != 'undefined'
&& typeof UploadForm.previous_hotcat_state != 'undefined'
&& UploadForm.previous_hotcat_state !== null)
{
UploadForm.previous_hotcat_state = setState (UploadForm.previous_hotcat_state);
}
});
} else {
if (!conf.wgIsArticle || conf.wgAction != 'view' || param('diff') !== null || param('oldid') !== null || !can_edit() || HotCat.disable()) return;
getPage ();
}
}
// Legacy stuff
function closeForm () {
// Close all open editors without redirect resolution and other asynchronous stuff.
for (var i = 0; i < editors.length; i++) {
if (editors[i].state == CategoryEditor.OPEN) {
editors[i].cancel();
} else if (editors[i].state == CategoryEditor.CHANGE_PENDING) {
editors[i].sanitizeInput ();
var value = editors[i].text.value.split('|');
var key = null;
if (value.length > 1) key = value[1];
var v = value[0].replace(/_/g, ' ').replace(/^\s+|\s+$/g, "");
if (v.length === 0) {
editors[i].cancel ();
} else {
editors[i].currentCategory = v;
editors[i].currentKey = key;
editors[i].currentExists = this.inputExists;
editors[i].close ();
}
}
}
}
function getState () {
var result = null;
for (var i = 0; i < editors.length; i++) {
var text = editors[i].currentCategory;
var key = editors[i].currentKey;
if (text && text.length > 0) {
if (key !== null) text += '|' + key;
if (result === null)
result = text;
else
result = result + '\n' + text;
}
}
return result;
}
function setState (state) {
var cats = state.split ('\n');
if (cats.length === 0) return null;
if (initialized && editors.length == 1 && editors[0].isAddCategory) {
// Insert new spans and create new editors for them.
var newSpans = [];
var before = editors.length == 1 ? editors[0].span : null;
var i;
for (i = 0; i < cats.length; i++) {
if (cats[i].length === 0) continue;
var cat = cats[i].split ('|');
var key = cat.length > 1 ? cat[1] : null;
cat = cat[0];
var lk = make ('a'); lk.href = wikiPagePath (HotCat.category_canonical + ':' + cat);
lk.appendChild (make (cat, true));
lk.title = cat;
var span = make ('span');
span.appendChild (lk);
if (i === 0) catLine.insertBefore (make (' ', true), before);
catLine.insertBefore (span, before);
if (before && i+1 < cats.length) parent.insertBefore (make (' | ', true), before);
newSpans.push ({element: span, title: cat, 'key': key});
}
// And change the last one...
if (before) {
before.parentNode.insertBefore (make (' | ', true), before);
}
var editor = null;
for (i = 0; i < newSpans.length; i++) {
editor = new CategoryEditor (catLine, newSpans[i].element, newSpans[i].title, newSpans[i].key);
}
}
return null;
}
// Export legacy functions
window.hotcat_get_state = function () { return getState(); };
window.hotcat_set_state = function (state) { return setState (state); };
window.hotcat_close_form = function () { closeForm (); };
if (window.mw) {
// Make sure we don't get conflicts with AjaxCategories (core development that should one day
// replace HotCat).
mw.config.set('disableAJAXCategories', true);
}
// Run as soon as possible. This varies depending on MediaWiki version;
// window's 'load' event is always safe, but usually we can do better than that.
// Check for version to avoid MediaWiki bug 32537.
var mwVersion = conf.wgVersion.split('.');
if (mwVersion[0] >= 1 && parseFloat(mwVersion[1]) > 20) {
// We can safely trigger just after user configuration is loaded. Also start HotCat if the user module fails to load.
// Avoid using Promise methods of mw.loader.using as those aren't supported in older
// MediaWiki versions.
var startHotCat = function(){
jQuery(document).ready(run);
};
mw.loader.using('user', startHotCat, startHotCat);
} else {
// mw.loader.using('user', ...) could have unintended side-effects on MW <= 1.20. Fall back to dom-ready.
jQuery(document).ready(run);
}
})();
//</source>
fby38wfctawjd55c1wivz25wjlrr2oy
میڈیاویکی:RefToolbarBase.js
8
3777
15275
7766
2026-11-02T18:07:47Z
Maintenance script
1230
Use thumb.wikimedia.org for thumbnails ([[phab:T427465]], Operator: Ladsgroup)
15275
javascript
text/javascript
// Global object
if (typeof CiteTB == 'undefined') {
var CiteTB = {
"Templates" : {}, // All templates
"Options" : {}, // Global options
"UserOptions" : {}, // User options
"DefaultOptions" : {}, // Script defaults
"ErrorChecks" : {} // Error check functions
};
}
if (typeof mw.usability == 'undefined') {
mw.usability = {};
mw.usability.getMsg = function(m) { return mw.messages.get(m); }
mw.usability.addMessages = function(msgs) { mw.messages.set(msgs); };
}
// Object for cite templates
function citeTemplate(templatename, shortform, basicfields, expandedfields) {
// Properties
this.templatename = templatename; // The template name - "cite web", "cite book", etc.
this.shortform = shortform; // A short form, used for the dropdown box
this.basic = basicfields; // Basic fields - author, title, publisher...
// Less common - quote, archiveurl - should be everything the template supports minus the basic ones
this.extra = expandedfields;
// Add it to the list
CiteTB.Templates[this.templatename] = this;
// Methods
this.makeFormInner = function(fields) {
var i=0;
var trs = new Array();
for (i=0; i<fields.length; i++) {
var fieldobj = fields[i];
var field = fieldobj.field;
var ad = false;
if ($.inArray(field, CiteTB.getOption('autodate fields')) != -1 ) {
im = $('<img />').attr('src', '//thumb.wikimedia.org/wikipedia/commons/thumb/7/7b/Nuvola_apps_date.svg/20px-Nuvola_apps_date.svg.png');
im.attr('alt', mw.usability.getMsg('cite-insert-date')).attr('title', mw.usability.getMsg('cite-insert-date'));
var ad = $('<a />').attr('href', '#');
ad.append(im);
ad.attr('id', 'cite-date-'+CiteTB.escStr(this.shortform)+'-'+field);
$('#cite-date-'+CiteTB.escStr(this.shortform)+'-'+field).live('click', CiteTB.fillAccessdate);
}
if (fieldobj.autofillid) {
var autotype = fieldobj.autofillid;
im = $('<img />').attr('src', '//thumb.wikimedia.org/wikipedia/commons/thumb/1/17/System-search.svg/20px-System-search.svg.png');
im.attr('alt', mw.usability.getMsg('cite-autofill-alt')).attr('title', mw.usability.getMsg('cite-autofill-alt'));
var ad = $('<a />').attr('href', '#');
ad.append(im);
ad.attr('id', 'cite-auto-'+CiteTB.escStr(this.shortform)+'-'+field+'-'+autotype);
$('#cite-auto-'+CiteTB.escStr(this.shortform)+'-'+field+'-'+autotype).live('click', CiteTB.initAutofill);
}
var display = mw.usability.getMsg('cite-'+field+'-label');
var tooltip = fieldobj.tooltip ? $('<abbr />').attr('title', mw.usability.getMsg(fieldobj.tooltip)).text('*') : false;
var input = '';
if (ad) {
input = $('<input tabindex="1" style="width:85%" type="text" />');
} else {
input = $('<input tabindex="1" style="width:100%" type="text" />');
}
input.attr('id', 'cite-'+CiteTB.escStr(this.shortform)+'-'+field);
if (fieldobj.autofillprop) {
input.addClass('cite-'+CiteTB.escStr(this.shortform)+'-'+fieldobj.autofillprop);
}
var label = $('<label />');
label.attr('for', 'cite-'+CiteTB.escStr(this.shortform)+'-'+field).text(display);
if (tooltip) {
label.append(tooltip);
}
var style = 'text-align:left; width:20%;';
if (i%2 == 1) {
style += ' padding-left:1em;';
} else {
var tr = $('<tr />');
}
var td1 = $('<td class="cite-form-td" />').attr('style', style);
td1.append(label);
tr.append(td1);
var td2 = $('<td class="cite-form-td" style="width:30%" />');
td2.append(input);
if (ad) {
td2.append(ad);
}
tr.append(td2);
if (i%2 == 0) {
trs.push(tr);
}
}
return trs;
}
// gives a little bit of HTML so the open form can be identified
this.getInitial = function() {
var hidden = $('<input type="hidden" class="cite-template" />');
hidden.val(this.templatename);
return hidden;
}
// makes the form used in the dialog boxes
this.getForm = function() {
var main = $("<div class='cite-form-container' />");
var form1 = $('<table style="width:100%; background-color:transparent;" class="cite-basic-fields" />');
var i=0;
var trs = this.makeFormInner(this.basic);
for (var i=0; i<trs.length; i++) {
form1.append(trs[i]);
}
var form2 = $('<table style="width:100%; background-color:transparent; display:none" class="cite-extra-fields">');
trs = this.makeFormInner(this.extra);
for (var i=0; i<trs.length; i++) {
form2.append(trs[i]);
}
main.append(form1).append(form2);
var form3 = $('<table style="width:100%; background-color:transparent;padding-top:1em" class="cite-other-fields">');
var tr = $('<tr />');
var td1 = $('<td class="cite-form-td" style="text-align:left; width:20%" />');
var label1 = $('<label />');
label1.attr('for', "cite-"+CiteTB.escStr(this.shortform)+'-name').text(mw.usability.getMsg('cite-name-label'));
td1.append(label1);
var td2 = $('<td class="cite-form-td" style="width:30%" />');
var input1 = $('<input tabindex="1" style="width:100%" type="text" />');
input1.attr('id', 'cite-'+CiteTB.escStr(this.shortform)+'-name');
td2.append(input1);
var td3 = $('<td class="cite-form-td" style="text-align:left; padding-left:1em; width:20%">');
var label2 = $('<label />');
label2.attr('for', 'cite-'+CiteTB.escStr(this.shortform)+'-group').text(mw.usability.getMsg('cite-group-label'));
td3.append(label2);
var td4 = $('<td class="cite-form-td" style="width:30%" />');
var input2 = $('<input tabindex="1" style="width:100%" type="text" />');
input2.attr('id', 'cite-'+CiteTB.escStr(this.shortform)+'-group');
td4.append(input2);
tr.append(td1).append(td2).append(td3).append(td4);
form3.append(tr);
main.append(form3);
var extras = $('<div />');
extras.append('<input type="hidden" class="cite-form-status" value="closed" />');
var hidden = $('<input type="hidden" class="cite-template" />');
hidden.val(this.templatename);
extras.append(hidden);
var span1 = $('<span class="cite-preview-label" style="display:none;" />');
span1.text(mw.usability.getMsg('cite-raw-preview'));
extras.append(span1).append('<div class="cite-ref-preview" style="padding:0.5em; font-size:110%" />');
var span2 = $('<span class="cite-prev-parsed-label" style="display:none;" />');
span2.text(mw.usability.getMsg('cite-parsed-label'));
extras.append(span2).append('<div class="cite-preview-parsed" style="padding-bottom:0.5em; font-size:110%" />');
var link = $('<a href="#" class="cite-prev-parse" style="margin:0 1em 0 1em; display:none; color:darkblue" />');
link.text(mw.usability.getMsg('cite-form-parse'));
extras.append(link);
main.append(extras);
return main;
}
}
/* Class for error checks
FIXME: DOCS OUT OF DATE
type - type of error check - current options:
* 'refcheck' - apply a function on each ref individually
* function should accept a ref object, return a string
* 'reflist' - apply a function on the entire ref list
* function should accept an array of ref objects, return an array of strings
* 'search' - apply a function ro the page text
* function should accept the page text as a string, return an array of strings
The strings returned by the function should be valid HTML
func - The function described above
testname - Name of the error check, must not contain spaces
desc - A short description of the test
*/
function citeErrorCheck(obj) {
this.obj = obj
CiteTB.ErrorChecks[this.obj.testname] = this;
this.run = function() {
var errors = [];
switch(this.obj['type']) {
case "refcheck":
CiteTB.loadRefs();
for(var i=0; i<CiteTB.mainRefList.length; i++) {
var e = this.obj.func(CiteTB.mainRefList[i]);
if (e) {
errors.push(e);
}
}
break;
case "reflist":
CiteTB.loadRefs();
errors = this.obj.func(CiteTB.mainRefList);
break;
case "search":
var func = this.obj.func
CiteTB.getPageText(function(text) {
errors = func(text);
});
break;
}
return errors;
}
this.getRow = function() {
var row = $("<li />");
var check = $("<input type='checkbox' name='cite-err-test' />");
check.attr('value', this.obj.testname);
var label = $("<label />").html(mw.usability.getMsg(this.obj.desc));
label.attr('for', this.obj.testname);
row.append(check).append(' – ').append(label);
return row;
}
}
$('head').trigger('reftoolbarbase');
jpjcm3we2jm9i8figzcazytkfsfev7m
میڈیاویکی:Gadget-Cat-a-lot.css
8
3870
15271
14149
2026-11-02T18:07:42Z
Maintenance script
1230
Use thumb.wikimedia.org for thumbnails ([[phab:T427465]], Operator: Ladsgroup)
15271
css
text/css
#cat_a_lot
{
bottom: 0;
display: block;
position: fixed;
left: 0;
z-index: 100;
padding: 5px;
box-shadow: 0px 2px 4px rgba(0,0,0,0.5);
-moz-box-shadow: 0px 2px 4px rgba(0,0,0,0.5);
-webkit-box-shadow: 0px 2px 4px rgba(0,0,0,0.5);
background-color: #FBFCC7;
background: -moz-linear-gradient(top, rgba(251, 252, 209, 0.9), #FBFCC7);
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(251, 252, 209, 0.9)), to(#FBFCC7));
}
#cat_a_lot_data, #cat_a_lot_mark_counter
{
display: none;
}
#cat_a_lot_data ul
{
list-style-image: none;
list-style-type: none;
margin: 0px 0px 0px 5px;
}
#cat_a_lot_category_list
{
max-height: 450px;
overflow: auto;
}
#cat_a_lot_selections, #cat_a_lot_mark_counter
{
background: url(/w/skins/Vector/images/portal-break.png) no-repeat;
padding: 5px;
}
a {
cursor:pointer;
}
.cat_a_lot_action
{
float:left;
}
.cat_a_lot_move
{
float:left;
margin-right: 5px;
}
.cat_a_lot_feedback
{
border: 1px #A9DE16 solid !important;
background: #EAF2CB url(/w/resources/src/mediawiki.legacy/images/ajax-loader.gif) no-repeat 8px 14px !important;
padding-right: 2.85em !important;
padding-top: 10px !important;
font-size: 1.1em !important;
}
.cat_a_lot_done {
background-image: url(//thumb.wikimedia.org/wikipedia/commons/thumb/0/0e/Dialog-apply.svg/60px-Dialog-apply.svg.png)!important;
background-position: 8px 50% !important;
padding-top: 0px !important;
}
#cat_a_lot_searchcatname {
font-size: 112%;
margin: -5px 0px 5px -5px;
width: 102%;
}
.skin-vector #cat_a_lot {
font-size: .75em;
}
.cat_a_lot_markAsDone {
background-color: #BABABA;
}
.cat_a_lot_selected
{
background-color: #DF6;
}
#cat_a_lot_no_found {
font-weight:bold;
}
tjk0nwfgeks5kj85e3gxe0kiziljdqd