Weitere Optionen
KKeine Bearbeitungszusammenfassung |
KKeine Bearbeitungszusammenfassung |
||
| Zeile 1: | Zeile 1: | ||
// < | //<source lang="javascript"> | ||
/ | /* | ||
HotCat V2.2b | |||
/ | */ | ||
if (typeof (HotCat) == 'undefined') { // Guard against double inclusions | |||
// Configuration stuff. | |||
var HotCat = { | |||
messages : | |||
{ cat_removed : 'Entferne [[Kategorie:$1]]' | |||
,template_removed : 'Entferne {{[[Kategorie:$1|$1]]}}' | |||
,cat_added : 'Ergänze [[Kategorie:$1]]' | |||
,cat_keychange: 'neuer Sortierschlüssel für [[Kategorie:$1]]: ' | |||
,cat_notFound : 'Kategorie "$1" konnte nicht gefunden werden' | |||
,cat_exists : 'Kategorie "$1" bereits enthalten; nicht ergänzt' | |||
,cat_resolved : ' (Weiterleitung [[Kategorie:$1]] aufgelöst)' //wird nicht benötigt | |||
,uncat_removed: 'entferne {{uncategorized}}' //wird nicht benötigt | |||
,prefix : '[[Hilfe:HotCat|HotCat]]: ' | |||
// 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 Kategorien' | |||
// $1 is replaced by a number | |||
,commit : 'Speichern' | |||
// Button text. Localize to wgContentLanguage here; localize to wgUserLanguage in a subpage, | |||
// see localization hook below. | |||
,ok : 'OK' | |||
// Button text. Localize to wgContentLanguage here; localize to wgUserLanguage in a subpage, | |||
// see localization hook below. | |||
,cancel : 'Abbrechen' | |||
// Button text. Localize to wgContentLanguage here; localize to wgUserLanguage in a subpage, | |||
// see localization hook below. | |||
,multi_error : 'Quelltext konnte nicht abrufen werden. Deine Änderungen wurden deshalb nicht gespeichert.' | |||
// Localize to wgContentLanguage here; localize to wgUserLanguage in a subpage, | |||
// see localization hook below. | |||
} | |||
,category_canonical : 'Kategorie' | |||
// 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 : 'Kategorien' | |||
// Plural of category_canonical | |||
,disambig_category : null | |||
// 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. | |||
,redir_category : 'Wikipedia:Kategorienweiterleitung' | |||
// Any category in this category is deemed a (soft) redirect to some other category defined by the first link | |||
// to another category. If your wiki doesn't have soft category redirects, set this to null. | |||
,links : {change: '(±)', remove: '(−)', add: '(+)', restore: '(×)', undo: '(×)', down: '(↓)', up: '(↑)'} | |||
// The little modification links displayed after category names. | |||
,tooltips : { | |||
change: 'Ändern' | |||
,remove: 'Entfernen' | |||
,add: 'Neue Kategorie hinzufügen' | |||
,restore: 'Wiederherstellen' | |||
,undo: 'Zurücksetzen' | |||
,down: 'durch Unterkategorie ersetzen' | |||
,up: 'durch Überkategorie ersetzen' | |||
} | |||
// 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 : 'Mehrere Kategorien ändern' | |||
// Tooltip for the "enter multi-mode" link | |||
,disable : | |||
function () { // Return true to disable HotCat | |||
return ( wgNamespaceNumber < 0 // Special pages; Special:Upload is handled differently | |||
|| wgNamespaceNumber == 10 // Templates | |||
|| wgNamespaceNumber == 8 // MediaWiki | |||
|| wgNamespaceNumber == 2 | |||
&& wgTitle && wgTitle.length >= 3 && wgTitle.lastIndexOf ('.js') + 3 == wgTitle.length | |||
// User scripts | |||
|| typeof (wgNamespaceIds) != 'unknown' | |||
&& ( wgNamespaceNumber == wgNamespaceIds['creator'] | |||
|| wgNamespaceNumber == wgNamespaceIds['timedtext'] | |||
) | |||
); | |||
} | |||
,uncat_regexp : null | |||
// A regexp matching a templates used to mark uncategorized pages, if your wiki does have that. | |||
// If not, set it to null. | |||
,existsYes : 'http://upload.wikimedia.org/wikipedia/commons/thumb/b/be/P_yes.svg/20px-P_yes.svg.png' | |||
,existsNo : 'http://upload.wikimedia.org/wikipedia/commons/thumb/4/42/P_no.svg/20px-P_no.svg.png' | |||
// 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 : 'Search index' | |||
,pagelist : 'Page list' | |||
,combined : 'Combined search' | |||
,subcat : 'Subcategories' | |||
,parentcat : 'Parent categories' | |||
} | |||
// Names for the search engines | |||
// 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. | |||
,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 | |||
}; | |||
importScript ('MediaWiki:Gadget-HotCat.js/' + wgUserLanguage); | |||
// Localization hook to localize HotCat.messages.commit and HotCat.messages.multi_error. For German, the | |||
// file would be "MediaWiki:Gadget-HotCat.js/de", and its contents could be for instance | |||
// | |||
// HotCat.messages.commit = 'Speichern'; | |||
// HotCat.messages.ok = 'OK'; | |||
// HotCat.messages.cancel = 'Abbrechen'; | |||
// HotCat.messages.multi_error = 'Seitentext konnte nicht vom Server geladen werden. Die Änderungen können ' | |||
// +'leider nicht gespeichert werden.'; | |||
var | // No further changes should be necessary here. | ||
(function () { | |||
// First auto-localize the regexps for the category and the template namespaces. | |||
if (typeof (wgFormattedNamespaces) != 'undefined') { | |||
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, '[ _]').replace(/([\\\^\$\.\?\*\+\(\)])/g, '\\$1'); | |||
} | |||
fallback = fallback.toLowerCase(); | |||
var canonical = wgFormattedNamespaces["" + namespaceNumber].toLowerCase(); | |||
var regexp = create_regexp_str (canonical); | |||
if (fallback && canonical != fallback) regexp += '|' + create_regexp_str (fallback) | |||
for (var cat_name in wgNamespaceIds) { | |||
if ( typeof (cat_name) == 'string' | |||
&& cat_name.toLowerCase () != canonical | |||
&& cat_name.toLowerCase () != fallback | |||
&& wgNamespaceIds[cat_name] == namespaceNumber) | |||
{ | |||
regexp += '|' + create_regexp_str (cat_name); | |||
} | |||
} | |||
return regexp; | |||
} | |||
if (wgFormattedNamespaces['14']) { | |||
HotCat.category_canonical = wgFormattedNamespaces['14']; | |||
HotCat.category_regexp = autoLocalize (14, 'category'); | |||
} | |||
if (wgFormattedNamespaces['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 = 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 = wgScript + '?'; | |||
if (href.indexOf (script) == 0 || href.indexOf (wgServer + script) == 0) { | |||
// href="/w/index.php?title=..." | |||
return param ('title', href); | |||
} else { | |||
// href="/wiki/..." | |||
var prefix = wgArticlePath.replace ('$1', ""); | |||
if (href.indexOf (prefix) != 0) prefix = wgServer + prefix; // Fully expanded URL? | |||
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); | |||
} | |||
// Text modification | |||
var findCatsRE = | |||
new RegExp ('\\[\\[\\s*(?:' + HotCat.category_regexp + ')\\s*:\[^\\]\]+\\]\\]', 'g'); | |||
function replaceByBlanks (match) { | |||
return match.replace(/(\s|\S)/g, ' '); // /./ doesn't match linebreaks. /(\s|\S)/ does. | |||
} | } | ||
var | function find_category (wikitext, category, once) { | ||
var cat_regex = null; | |||
if(HotCat.template_categories[category]){ | |||
cat_regex = new RegExp ('\\{\\{\\s*(' + HotCat.template_regexp + '(?=\\s*:))?\\s*' | |||
+ '(?:' + HotCat.template_categories[category] + ')' | |||
+ '\\s*(\\|.*?)?\\}\\}', 'g' | |||
); | |||
} else { | |||
var cat_name = category.replace(/([\\\^\$\.\?\*\+\(\)])/g, '\\$1'); | |||
var initial = cat_name.substr (0, 1); | |||
cat_regex = new RegExp ('\\[\\[\\s*(' + HotCat.category_regexp + ')\\s*:\\s*' | |||
+ (initial == '\\' | |||
? initial | |||
: '[' + initial.toUpperCase() + initial.toLowerCase() + ']') | |||
+ cat_name.substring (1).replace (/[ _]/g, '[ _]') | |||
+ '\\s*(\\|.*?)?\\]\\]', '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 | |||
} | |||
function change_category (wikitext, toRemove, toAdd, key) { | |||
function | 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; | ||
// We should try to find interwiki links here, but that's for later. | |||
return index; | |||
} | |||
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); | |||
if (toRemove && toRemove.length > 0) { | |||
var matches = find_category (wikitext, toRemove); | |||
if (!matches || matches.length == 0) { | |||
return {text: wikitext, 'summary': summary, error: HotCat.messages.cat_notFound.replace ('$1', 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; | |||
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', toRemove)); | |||
} | |||
} | |||
} | |||
} | |||
if (toAdd && toAdd.length > 0) { | |||
var matches = find_category (wikitext, toAdd); | |||
if (matches && matches.length > 0) { | |||
return {text: wikitext, 'summary': summary, error : HotCat.messages.cat_exists.replace ('$1', toAdd)}; | |||
} else { | |||
if (cat_point < 0) | |||
cat_point = find_insertionpoint (wikitext); | |||
var newcatstring = '[[' + nameSpace + ':' + toAdd + (key || "") + ']]'; | |||
if (cat_point >= 0) { | |||
wikitext = wikitext.substring (0, cat_point) + '\n' + newcatstring + wikitext.substring (cat_point); | |||
} else { | |||
if (wikitext.length > 0 && wikitext.substr (wikitext.length - 1, 1) != '\n') | |||
wikitext += '\n'; | |||
wikitext += newcatstring; | |||
} | |||
if (keyChange) { | |||
var k = key || ""; | |||
if (k.length > 0) k = k.substr (1); | |||
summary.push (HotCat.messages.cat_keychange.replace ('$1', toAdd) + '"' + k + '"'); | |||
} else { | |||
summary.push (HotCat.messages.cat_added.replace ('$1', toAdd)); | |||
} | |||
if (HotCat.uncat_regexp) { | |||
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}; | |||
} | |||
if (wgAction == 'edit') { | |||
// Legacy code based on URI parameters, can add/remove/change only one single category. Still | |||
// used for single-category changes. | |||
var toRemove = param ('hotcat_removecat'); | |||
var toAdd = param ('hotcat_newcat'); | |||
if (toAdd) { | |||
toAdd = capitalize (toAdd.replace (/_/g, ' ').replace (/^\s+|\s+$/g, "")); | |||
if (toAdd.length == 0) toAdd = null; | |||
} | |||
if (toRemove) { | |||
toRemove = capitalize (toRemove.replace (/_/g, ' ').replace (/^\s+|\s+$/g, "")); | |||
if (toRemove.length == 0) toRemove = null; | |||
} | |||
if (toAdd || toRemove) { | |||
addOnloadHook (function () { | |||
if (!document.editform || !document.editform.wpTextbox1) return; | |||
var comment = param ('hotcat_comment') || ""; | |||
var cat_key = param ('hotcat_sortkey'); | |||
var result = change_category (document.editform.wpTextbox1.value, toRemove, toAdd, cat_key); | |||
var do_commit = !HotCat.noCommit && !result.error && param ('hotcat_nocommit') != '1'; | |||
document.editform.wpTextbox1.value = result.text; | |||
if (result.summary && result.summary.length > 0) | |||
document.editform.wpSummary.value = HotCat.messages.prefix + result.summary.join ('; ') + comment + HotCat.messages.using; | |||
document.editform.wpMinoredit.checked = true ; | |||
if (result.error) alert (result.error); | |||
if (do_commit) { | |||
// Hide the entire edit section so as not to tempt the user into editing... | |||
var content = document.getElementById ('bodyContent') // monobook & vector skin | |||
|| document.getElementById ('mw_contentholder') // modern skin | |||
|| document.getElementById ('article'); // classic skins | |||
if (content) content.style.display = 'none'; | |||
document.editform.submit(); | |||
} | |||
}); | |||
} | |||
return; | |||
} | |||
// 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; | |||
} | |||
var catLine = null; | |||
var onUpload = false; | |||
var editors = []; | |||
var commitButton = null; | |||
var commitForm = null; | |||
var multiSpan = null; | |||
var pageText = null; | |||
var | var pageTime = null; | ||
var pageWatched = false; | |||
var watchCreate = false; | |||
var | var watchEdit = false; | ||
var | var minorEdits = false; | ||
var | |||
var | var is_rtl = false; | ||
function | function setMultiInput () { | ||
var | if (commitButton || onUpload) return; | ||
for ( var i = 0 ; i < | 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); | |||
} | |||
// Get the preferences, so that we can set wpWatchthis correctly later on. Also get information | |||
// about whether the current user watches the page. Must use Ajax here. | |||
if (wgUserName) { | |||
var request = sajax_init_object (); | |||
request.open | |||
('GET', wgServer + wgScriptPath + '/api.php?format=json&action=query&meta=userinfo&uiprop=options&prop=info&inprop=watched&titles=' + encodeURIComponent (wgPageName), true); | |||
request.onreadystatechange = | |||
function () { | |||
if (request.readyState != 4) return; | |||
if (request.status == 200 && request.responseText && request.responseText.charAt(0) == '{') { | |||
var json = eval ('(' + request.responseText + ')'); | |||
if (json && json.query) { | |||
if (json.query.userinfo && json.query.userinfo.options) { | |||
watchCreate = json.query.userinfo.options.watchcreations == '1'; | |||
watchEdit = json.query.userinfo.options.watchdefault == '1'; | |||
minorEdits = json.query.userinfo.options.minordefault == 1; | |||
} | |||
if (json.query.pages) { | |||
for (var p in json.query.pages) { | |||
pageWatched = typeof (json.query.pages[p].watched) == 'string'; | |||
break; | |||
} | |||
} | |||
} | |||
} | |||
}; | |||
request.setRequestHeader ('Pragma', 'cache=yes'); | |||
request.setRequestHeader ('Cache-Control', 'no-transform'); | |||
request.send (null); | |||
} | |||
} | |||
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 | 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; | |||
} | } | ||
function | function performChanges () { | ||
if ( | // Don't use the edit API or LAPI, it's always bothersome to report back errors like edit | ||
// conflicts. Instead, make one remote call (blocking, because we can't continue anyway if | |||
// it doesn't succeed), getting the page text. Perform the changes on the text, then construct | |||
if ( | // a form to submit all this as a diff. | ||
// Note: we have to do this even if we already got the page text. Other scripts may have already | |||
// edited the text, and we don't necessarily get an edit conflict with ourself. Use case: open | |||
// a file page, add an image note through ImageAnnotator, then change the categories. If HotCat | |||
// still operates on the page text loaded initially, it'll delete the just added note again, and | |||
// somehow the MediaWiki software does not produce an edit conflict. | |||
if (wgArticleId != 0) { | |||
var request = sajax_init_object (); | |||
var uri = wgServer + wgScriptPath | |||
+ '/api.php?format=json&action=query&titles=' + encodeURIComponent (wgPageName) | |||
+ '&prop=info%7Crevisions&inprop=watched&rvprop=content%7Ctimestamp'; | |||
request.open ('GET', uri, false); // Yes, synchronous | |||
request.send (null); | |||
if (request.status == 200 && request.responseText && request.responseText.charAt(0) == '{') { | |||
setPage (eval ('(' + request.responseText + ')')); | |||
} | |||
} else { | |||
pageText = null; | |||
} | |||
if (pageText === null) { | |||
alert (HotCat.messages.multi_error); | |||
return; | |||
} | |||
// Create a form and submit it | |||
if (!commitForm) { | |||
var formContainer = make ('div'); | |||
formContainer.style.display = 'none'; | |||
document.body.appendChild (formContainer); | |||
formContainer.innerHTML = | |||
'<form method="post" enctype="multipart/form-data" action="' | |||
+ wgScript + '?title=' + encodeURIComponent (wgPageName) | |||
+ '&action=edit">' | |||
+ '<input type="hidden" name="wpTextbox1" />' | |||
+ '<input type="hidden" name="wpSummary" value="" />' | |||
+ '<input type="checkbox" name="wpMinoredit" value="1" />' | |||
+ '<input type="checkbox" name="wpWatchthis" value="1" />' | |||
+ '<input type="hidden" name="wpEdittime" />' | |||
+ '<input type="hidden" name="wpStarttime" />' | |||
+ '<input type="hidden" name="wpDiff" value="wpDiff" />' | |||
+ '</form>'; | |||
commitForm = formContainer.firstChild; | |||
} | |||
var result = { text : pageText }; | |||
var changed = [], added = [], deleted = [], changes = 0; | |||
for (var i=0; i < editors.length; i++) { | |||
if (editors[i].state == CategoryEditor.CHANGED) { | |||
result = change_category ( | |||
result.text | |||
, editors[i].originalCategory | |||
, editors[i].currentCategory | |||
, editors[i].currentKey | |||
); | |||
if (!result.error) { | |||
changes++; | |||
if (!editors[i].originalCategory || editors[i].originalCategory.length == 0) { | |||
added.push (editors[i].currentCategory); | |||
} else { | |||
changed.push ({from : editors[i].originalCategory, to : editors[i].currentCategory}); | |||
} | |||
} | |||
} else if ( editors[i].state == CategoryEditor.DELETED | |||
&& editors[i].originalCategory | |||
&& editors[i].originalCategory.length > 0) | |||
{ | |||
result = change_category (result.text, editors[i].originalCategory, null, null); | |||
if (!result.error) { | |||
changes++; | |||
deleted.push (editors[i].originalCategory); | |||
} | |||
} | |||
} | |||
// Fill in the form and submit it | |||
commitForm.wpMinoredit.checked = minorEdits; | |||
commitForm.wpWatchthis.checked = wgArticleId == 0 && watchCreate || watchEdit || pageWatched; | |||
if (wgArticleId > 0) { | |||
if (changes == 1) { | |||
if (result.summary && result.summary.length > 0) | |||
commitForm.wpSummary.value = HotCat.messages.prefix + result.summary.join ('; ') + HotCat.messages.using; | |||
commitForm.wpMinoredit.checked = true; | |||
} else if (changes > 1) { | |||
var summary = []; | |||
var shortSummary = []; | |||
// Deleted | |||
for (var i=0; i < deleted.length; i++) { | |||
summary.push ('−[[' + HotCat.category_canonical + ':' + deleted[i] + ']]'); | |||
} | } | ||
if (deleted.length == 1) | |||
} | shortSummary.push ('−[[' + HotCat.category_canonical + ':' + deleted[0] + ']]'); | ||
else if (deleted.length > 1) | |||
shortSummary.push ('− ' + HotCat.messages.multi_change.replace ('$1', "" + deleted.length)); | |||
// Added | |||
for (var i=0; i < added.length; i++) { | |||
summary.push ('+[[' + HotCat.category_canonical + ':' + added[i] + ']]'); | |||
} | |||
if (added.length == 1) | |||
shortSummary.push ('+[[' + HotCat.category_canonical + ':' + added[0] + ']]'); | |||
else if (added.length > 1) | |||
shortSummary.push ('+ ' + HotCat.messages.multi_change.replace ('$1', "" + added.length)); | |||
// Changed | |||
for (var i=0; i < changed.length; i++) { | |||
if (changed[i].from != changed[i].to) { | |||
summary.push ('±[[' + HotCat.category_canonical + ':' + changed[i].from + ']]→[[' | |||
+ HotCat.category_canonical + ':' + changed[i].to + ']]'); | |||
} else { | |||
summary.push ('±[[' + HotCat.category_canonical + ':' + changed[i].from + ']]'); | |||
} | |||
} | |||
if (changed.length == 1) { | |||
if (changed[0].from != changed[0].to) { | |||
shortSummary.push ('±[[' + HotCat.category_canonical + ':' + changed[0].from + ']]→[[' | |||
+ HotCat.category_canonical + ':' + changed[0].to + ']]'); | |||
} else { | |||
shortSummary.push ('±[[' + HotCat.category_canonical + ':' + changed[0].from + ']]'); | |||
} | |||
} else if (changed.length > 1) { | |||
shortSummary.push ('± ' + HotCat.messages.multi_change.replace ('$1', "" + changed.length)); | |||
} | |||
if (summary.length > 0) { | |||
summary = summary.join ('; '); | |||
if (summary.length > 200 - HotCat.messages.prefix.length - HotCat.messages.using.length) { | |||
summary = shortSummary.join ('; '); | |||
} | |||
commitForm.wpSummary.value = HotCat.messages.prefix + summary + HotCat.messages.using; | |||
} | |||
} | |||
} | |||
commitForm.wpTextbox1.value = result.text; | |||
commitForm.wpStarttime.value = currentTimestamp (); | |||
commitForm.wpEdittime.value = pageTime || commitForm.wpStarttime.value; | |||
commitForm.submit(); | |||
} | |||
function | function resolveMulti (toResolve, callback) { | ||
for (var i = 0; i < toResolve.length; i++) { | |||
toResolve[i].dab = null; | |||
toResolve[i].dabInput = toResolve[i].lastInput; | |||
} | |||
if (noSuggestions) { | |||
callback (toResolve); | |||
return; | |||
} | |||
var request = sajax_init_object (); | |||
if (!request) { | |||
noSuggestions = true; | |||
callback (toResolve); | |||
return; | |||
} | |||
var | var url = wgServer + wgScriptPath + '/api.php'; | ||
if ( | // Use %7C instead of |, otherwise Konqueror insists on re-encoding the arguments, resulting in doubly encoded | ||
if ( | // category names. (That is a bug in Konqueror. Other browsers don't have this problem.) | ||
var args = 'action=query&prop=info%7Clinks%7Ccategories&plnamespace=14&pllimit=50' | |||
+ '&cllimit=' + (toResolve.length * 10) // Category limit is global, link limit is per page | |||
+ '&format=json&titles='; | |||
for (var i = 0; i < toResolve.length; i++) { | |||
args += encodeURIComponent ('Category:' + toResolve[i].dabInput); | |||
if (i+1 < toResolve.length) args += '%7C'; | |||
} | |||
if (url.length + args.length + 1 > 2000) { // Lowest common denominator: IE has a URI length limit of 2083 | |||
request.open ('POST', url, true); | |||
request.setRequestHeader ('Content-Type', 'application/x-www-form-urlencoded'); | |||
} else { | |||
url += '?' + args; args = null; | |||
request.open ('GET', url, true); | |||
} | |||
request.onreadystatechange = | |||
function () { | |||
if (request.readyState != 4) return; | |||
if (request.status != 200) { | |||
callback (toResolve); | |||
return; | |||
} | |||
resolveRedirects (toResolve, eval ('(' + request.responseText + ')')); | |||
callback (toResolve); | |||
}; | |||
request.setRequestHeader ('Pragma', 'cache=yes'); | |||
request.setRequestHeader ('Cache-Control', 'no-transform'); | |||
request.send (args); | |||
} | |||
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? | |||
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 (var i = 0; i < lks.length; i++) { | |||
if ( lks[i]['ns'] == 14 // Category namespace | |||
&& 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']; | |||
titles.push (match.substring (match.indexOf (':') + 1)); | |||
if (is_redir) break; | |||
} | } | ||
} | } | ||
for (var j = 0; j < toResolve.length; j++) { | |||
if (toResolve[j].dabInput != page.title.substring (page.title.indexOf (':') + 1)) continue; | |||
if (titles.length > 1) { | |||
toResolve[j].dab = titles; | |||
if ( | |||
} else { | } else { | ||
toResolve[j].inputExists = true; // Might actually be wrong... | |||
toResolve[j].icon.src = HotCat.existsYes; | |||
toResolve[j].text.value = | |||
titles[0] + (toResolve[j].currentKey != null ? '|' + toResolve[j].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) { | |||
performChanges (); | |||
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) { | |||
CategoryEditor.makeActive (firstDab); | |||
} else if (!dontChange) { | |||
performChanges (); | |||
} | |||
} | |||
); | |||
} | } | ||
// | var noSuggestions = false; | ||
return | var suggestionEngines = { | ||
} | opensearch : | ||
{ uri : '/api.php?format=json&action=opensearch&namespace=14&limit=30&search=$1' // $1 = search term | |||
,handler : // Function to convert result of uri into an array of category names | |||
function (responseText, queryKey) { | |||
if (responseText.charAt (0) != '[') return null; | |||
var queryResult = eval ('(' + responseText + ')'); | |||
if (queryResult != null && queryResult.length == 2 && queryResult[0].toLowerCase() == queryKey.toLowerCase()) { | |||
var titles = queryResult[1]; | |||
for (var i = 0; i < titles.length; i++) { | |||
titles[i] = titles[i].substring (titles[i].indexOf (':') + 1); // rm namespace | |||
} | |||
return titles; | |||
} | |||
return null; | |||
} | |||
} | |||
,internalsearch : | |||
{ uri : '/api.php?format=json&action=query&list=allpages&apnamespace=14&aplimit=30&apfrom=$1' | |||
,handler : | |||
function (responseText, queryKey) { | |||
if (responseText.charAt (0) != '{') return null; | |||
var queryResult = eval ('(' + responseText + ')'); | |||
if (queryResult && queryResult.query && queryResult.query.allpages) { | |||
var titles = queryResult.query.allpages; | |||
var key = queryKey.toLowerCase(); | |||
for (var i = 0; i < titles.length; i++) { | |||
titles[i] = titles[i].title.substring (titles[i].title.indexOf (':') + 1); // rm namespace | |||
if (titles[i].toLowerCase().indexOf (key) != 0) { | |||
titles.splice (i, 1); // Doesn't start with the query key | |||
i--; | |||
} | |||
} | |||
return titles; | |||
} | |||
return null; | |||
} | |||
} | |||
,subcategories : | |||
{ uri : '/api.php?format=json&action=query&list=categorymembers&cmnamespace=14&cmlimit=max&cmtitle=Category:$1' | |||
,handler : | |||
function (responseText, queryKey) { | |||
if (responseText.charAt (0) != '{') return null; | |||
var queryResult = eval ('(' + responseText + ')'); | |||
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 (responseText, queryKey) { | |||
if (responseText.charAt (0) != '{') return null; | |||
var queryResult = eval ('(' + responseText + ')'); | |||
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} | |||
,pagelist : {name: 'Page list', engines: ['internalsearch'], cache: {}, show: true, temp: false} | |||
,combined : {name: 'Combined search', engines: ['opensearch', 'internalsearch'], cache: {}, show: true, temp: false} | |||
,subcat : {name: 'Subcategories', engines: ['subcategories'], cache: {}, show: true, temp: true} | |||
,parentcat : {name: 'Parent categories', engines: ['parentcategories'], cache: {}, show: true, temp: 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; | |||
CategoryEditor.makeActive = function (toActivate) { | |||
for (var i = 0; i < editors.length; i++) { | |||
if (editors[i] != toActivate) editors[i].inactivate (); | |||
} | |||
toActivate.is_active = true; | |||
if (toActivate.dab) { | |||
toActivate.showSuggestions (toActivate.dab, false, null, null); // do autocompletion, no key, no engine selector | |||
toActivate.dab = null; | |||
} | |||
}; | |||
CategoryEditor.prototype = { | |||
initialize : function (line, span, after, key) { | |||
// 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; | |||
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'; | |||
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 ('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.line = line; | |||
this.engine = HotCat.suggestions; | |||
this.span = span; | |||
this.currentCategory = this.originalCategory; | |||
this.currentExists = this.originalExists; | |||
this.currentKey = this.originalKey; | |||
this.state = CategoryEditor.UNCHANGED; | |||
this.lastSavedState = CategoryEditor.UNCHANGED; | |||
this.lastSavedCategory = this.originalCategory; | |||
this.lastSavedKey = this.originalKey; | |||
this.lastSavedExists = this.originalExists; | |||
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'; | |||
this.linkSpan.appendChild (this.normalLinks); | |||
this.undelLink = make ('span'); | |||
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); | |||
}, | |||
makeForm : function () { | |||
var form = make ('form'); | |||
form.method = 'POST'; form.onsubmit = bind (this.accept, this); | |||
this.form = form; | |||
var text = make ('input'); text.type = 'text'; text.size = HotCat.editbox_width; | |||
if (!noSuggestions) { | |||
text.onkeyup = | |||
bind ( | |||
function (evt) { | |||
evt = evt || window.event || window.Event; // W3C, IE, Netscape | |||
var key = evt.keyCode || 0; | |||
if (key == 38 || key == 40) { // Up and down arrows | |||
// In case a browser doesn't generate keypress events for arrow keys... | |||
if (this.keyCount == 0) return this.processKey (evt); | |||
} else { | |||
if (key == 27) this.resetKeySelection (); // ESC | |||
// Also do this for ESC as a workaround for Firefox bug 524360 | |||
// https://bugzilla.mozilla.org/show_bug.cgi?id=524360 | |||
var dont_autocomplete = (key == 8 || key == 46 || key == 27); // BS, DEL, ESC | |||
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); | |||
} | |||
} | |||
,this | |||
); | |||
text.onkeydown = | |||
bind ( | |||
function (evt) { | |||
evt = evt || window.event || window.Event; // W3C, IE, Netscape | |||
this.lastKey = evt.keyCode || 0; | |||
this.keyCount = 0; | |||
// Handle return explicitly, to override the default form submission to be able to check for ctrl | |||
if (evt.keyCode == 13) this.accept (evt); | |||
} | |||
,this | |||
); | |||
// And handle continued pressing of arrow keys | |||
text.onkeypress = bind (function (evt) {this.keyCount++; return this.processKey (evt);}, this); | |||
} | |||
text.onfocus = bind (function () { CategoryEditor.makeActive (this); }, this); | |||
this.text = text; | |||
this.icon = make ('img'); | |||
var list = null; | |||
if (!noSuggestions) { | |||
list = make ('select'); | |||
list.onclick = bind (function () { if (this.setValueFromList ()) this.textchange (); }, this); | |||
list.ondblclick = bind (function (e) { if (this.setValueFromList ()) this.accept (e); }, this); | |||
list.onchange = bind (function (e) { this.setValueFromList (); this.text.focus(); }, this); | |||
list.onkeyup = | |||
bind ( | |||
function (evt) { | |||
evt = evt || window.event || window.Event; // W3C, IE, Netscape | |||
if (evt.keyCode == 27) { | |||
this.resetKeySelection (); | |||
this.text.focus(); | |||
var self = this; | |||
window.setTimeout (function () {self.textchange (true);}, HotCat.suggest_delay); | |||
} else if (evt.keyCode == 13) { | |||
this.accept (evt); | |||
} | |||
} | |||
,this | |||
); | |||
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 = bind ( | |||
function () { | |||
this.engine = this.engineSelector.options[this.engineSelector.selectedIndex].value; | |||
this.textchange (true, true); // Don't autocomplete, force re-display of list | |||
} | |||
,this | |||
); | |||
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; | |||
if (list) form.appendChild (list); | |||
if (this.engineSelector) form.appendChild (this.engineSelector); | |||
form.appendChild (text); | |||
if (!noSuggestions) form.appendChild (this.icon); | |||
form.appendChild (OK); | |||
form.appendChild (cancel); | |||
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.currentCategroy = this.lastSavedCategory; | |||
this.currentExists = this.lastSavedExists; | |||
this.currentKey = this.lastSavedKey; | |||
this.icon.src = 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; | |||
// Display the form | |||
if (this.catLink) this.catLink.style.display = 'none'; | |||
this.linkSpan.style.display = 'none'; | |||
this.form.style.display = 'inline'; | |||
CategoryEditor.makeActive (this); | |||
// 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; | |||
}, | |||
open : function (evt) { | |||
var result = this.display (evt); | |||
var v = this.lastSavedCategory; | |||
if (v.length == 0) return result; | |||
if (this.engine && suggestionConfigs[this.engine].temp) this.engine = HotCat.suggestions; | |||
this.textchange (false, true); // do autocompletion, force display of suggestions | |||
return result; | |||
}, | |||
down : function (evt) { | |||
var result = this.display (evt); | |||
var v = this.lastSavedCategory; | |||
if (v.length == 0) return result; | |||
this.text.readOnly = true; // This request may be very slow! | |||
this.engine = 'subcat'; | |||
this.textchange (false, true); | |||
return result; | |||
}, | |||
up : function (evt) { | |||
var result = this.display (evt); | |||
var v = this.lastSavedCategory; | |||
if (v.length == 0) return result; | |||
this.engine = 'parentcat'; | |||
this.textchange (false, true); | |||
return result; | |||
}, | |||
cancel : function () { | |||
if (this.isAddCategory && !onUpload) { | |||
this.removeEditor(); // We added a new adder when opening | |||
return; | |||
} | |||
// Close, re-display link | |||
if (this.list) this.list.style.display = 'none'; | |||
if (this.engineSelector) this.engineSelector.style.display = 'none'; | |||
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; | |||
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 (); | |||
}, | |||
removeEditor : function () { | |||
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.lastSavedCategory = this.originalCategory; | |||
this.lastSavedKey = this.originalKey; | |||
this.lastSavedExists = this.originalExists; | |||
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 = wgArticlePath.replace ('$1', 'Category:' + this.currentCategory); | |||
this.catLink.title = ""; | |||
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 = capitalize (value[0].replace(/_/g, ' ').replace(/^\s+|\s+$/g, "")); | |||
this.lastInput = v; | |||
if (v.length == 0) { | |||
this.cancel (); | |||
return false; | |||
} | |||
if ( !dontCheck | |||
&& ( v == this.lastSavedCategory && key == this.lastSavedKey | |||
|| wgNamespaceNumber == 14 && v == wgTitle | |||
) | |||
) | |||
{ | |||
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) { | |||
CategoryEditor.makeActive (resolved[0]); | |||
} else { | |||
if (resolved[0].acceptCheck(true)) { | |||
resolved[0].commit ( | |||
(resolved[0].currentCategory != original) | |||
? HotCat.messages.cat_resolved.replace ('$1', 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 = wgArticlePath.replace ('$1', 'Category:' + this.currentCategory); | |||
this.catLink.title = ""; | |||
this.catLink.className = this.currentExists ? "" : 'new'; | |||
this.lastSavedCategory = this.currentCategory; | |||
this.lastSavedKey = this.currentKey; | |||
this.lastSavedExists = this.currentExists; | |||
// Close form and redisplay category | |||
if (this.list) this.list.style.display = 'none'; | |||
if (this.engineSelector) this.engineSelector.style.display = 'none'; | |||
this.form.style.display = 'none'; | |||
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 (); | |||
}, | |||
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 | |||
) | |||
) | |||
|| wgNamespaceNumber == 14 && this.currentCategory == wgTitle | |||
) | |||
{ | |||
this.cancel (); | |||
return; | |||
} | |||
if (commitButton || onUpload) { | |||
this.close (); | |||
} else { | |||
if (this.list) this.list.style.display = 'none'; | |||
if (this.engineSelector) this.engineSelector.style.display = 'none'; | |||
// Execute change from this.originalCategory to this.currentCategory|this.currentKey, | |||
var editlk = wgServer + wgScript + '?title=' + encodeURIComponent (wgPageName) | |||
+ '&action=edit'; | |||
var url = editlk + '&hotcat_newcat=' + encodeURIComponent (this.currentCategory); | |||
if (this.currentKey != null) url += '&hotcat_sortkey=' + encodeURIComponent (this.currentKey); | |||
if (this.originalCategory.length > 0) | |||
url += '&hotcat_removecat=' + encodeURIComponent (this.originalCategory); | |||
if (comment) url = url + '&hotcat_comment=' + encodeURIComponent (comment); | |||
if (this.noCommit || HotCat.no_autocommit) url = url + '&hotcat_nocommit=1'; | |||
document.location = url; | |||
} | |||
}, | |||
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.style.textDecoration = 'line-through'; | |||
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 { | |||
// Execute single category deletion. | |||
var editlk = wgServer + wgScript + '?title=' + encodeURIComponent (wgPageName) | |||
+ '&action=edit'; | |||
if (noCommit || HotCat.no_autocommit) editlk += '&hotcat_nocommit=1'; | |||
document.location = | |||
editlk + '&hotcat_removecat=' + encodeURIComponent (this.originalCategory); | |||
} | |||
} | |||
}, | |||
restore : function (evt) { | |||
// Can occur only if we do have a commit button and are not on the upload form | |||
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 | |||
setValueFromList : function (idx) { | |||
if (typeof (idx) == 'undefined') idx = this.list.selectedIndex; | |||
if (idx >= 0 && idx < this.list.options.length) { | |||
var v = this.text.value.split ('|'); | |||
this.text.value = this.list.options[idx].text + (v.length > 1 ? '|' + v[1] : ""); | |||
this.inputExists = true; // Might be wrong if from a dab list... | |||
if (this.icon) this.icon.src = HotCat.existsYes; | |||
return true; | |||
} | |||
return false; | |||
}, | |||
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); | |||
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; | |||
}, | |||
function | makeCall : function (url, callbackObj, engine, queryKey) { | ||
var cb = callbackObj; | |||
} | var e = engine; | ||
var v = queryKey; | |||
var r = sajax_init_object (); | |||
cb.requests.push (r); | |||
r.open('GET', url, true); | |||
r.onreadystatechange = | |||
bind ( | |||
function () { | |||
if (r.readyState == 4) { | |||
if (r.status != 200) cb.dontCache = true; | |||
if (r.status == 200 && r.responseText != null) { | |||
var titles = e.handler (r.responseText, v); | |||
if (titles && titles.length > 0) { | |||
if (cb.allTitles == null) { | |||
cb.allTitles = titles; | |||
} else { | |||
cb.allTitles = cb.allTitles.concat (titles); | |||
} | |||
} | |||
} | |||
cb.callsMade++; | |||
} | |||
if (cb.callsMade == cb.nofCalls) { | |||
if (!cb.dontCache && !suggestionConfigs[cb.engineName].cache[v]) { | |||
suggestionConfigs[cb.engineName].cache[v] = cb.allTitles; | |||
} | |||
this.text.readOnly = false; | |||
if (!cb.cancelled) this.showSuggestions (cb.allTitles, cb.noCompletion, v, cb.engineName); | |||
if (cb === this.callbackObj) this.callbackObj = null; | |||
delete cb; | |||
} | |||
} | |||
,this | |||
); | |||
r.setRequestHeader ('Pragma', 'cache=yes'); | |||
r.setRequestHeader ('Cache-Control', 'no-transform'); | |||
r.send (null); | |||
}, | |||
callbackObj : null, | |||
function | textchange : function (dont_autocomplete, force) { | ||
// Hide all other lists | |||
CategoryEditor.makeActive (this); | |||
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; | ||
} | |||
// 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) v = v.substring (0, pipe); | |||
if (this.lastInput == v && !force) return; // No change | |||
if (this.lastInput != v) checkMultiInput (); | |||
this.lastInput = v; | |||
this.lastRealInput = v; | |||
if (v.length == 0) { this.showSuggestions([]); return; } | |||
if (!sajax_init_object ()) { | |||
noSuggestions = true; | |||
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 (this.callbackObj) this.callbackObj.cancelled = true; | |||
var engineName = suggestionConfigs[this.engine] ? this.engine : 'combined'; | |||
if (suggestionConfigs[engineName].cache[v]) { | |||
this.showSuggestions (suggestionConfigs[engineName].cache[v], dont_autocomplete, v, engineName); | |||
return; | |||
} | |||
} | |||
function | var engines = suggestionConfigs[engineName].engines; | ||
this.callbackObj = | |||
{allTitles: null, requests: [], callsMade: 0, nofCalls: engines.length, noCompletion: dont_autocomplete, engineName: engineName}; | |||
for (var j = 0; j < engines.length; j++) { | |||
engine = suggestionEngines[engines[j]]; | |||
var url = wgServer + wgScriptPath + engine.uri.replace (/\$1/g, encodeURIComponent (v)); | |||
this.makeCall (url, this.callbackObj, engine, v); | |||
} | |||
}, | |||
showSuggestions : function (titles, dontAutocomplete, queryKey, engineName) { | |||
this.text.readOnly = false; | |||
this.dab = null; | |||
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; | |||
} | |||
var haveEngine = !!engineName; | |||
if (haveEngine) { | |||
haveEngine = this.engineSelector != 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; | |||
if (titles) { | |||
titles.sort ( | |||
function (a, b) { | |||
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 (v) == 0 ? 1 : 0); | |||
var prefixMatchB = (b.indexOf (v) == 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 (var i = 0; i < titles.length; i++) { | |||
if ( i+1 < titles.length && titles[i] == titles[i+1] | |||
|| wgNamespaceNumber == 14 && titles[i] == 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 = HotCat.existsNo; | |||
this.inputExists = false; | |||
} | |||
return; | |||
} | |||
// Get current input text | |||
var v = this.text.value.split('|'); | |||
var key = v.length > 1 ? '|' + v[1] : ""; | |||
v = capitalize (v[0]); | |||
var firstTitle = titles[0]; | |||
var completed = this.autoComplete (firstTitle, v, key, dontAutocomplete); | |||
if (engineName && suggestionConfigs[engineName] && !suggestionConfigs[engineName].temp) { | |||
this.icon.src = completed ? HotCat.existsYes : HotCat.existsNo; | |||
this.inputExists = completed; | |||
} | |||
if (completed) { | |||
this.lastInput = firstTitle; | |||
if (titles.length == 1) { | |||
this.list.style.display = 'none'; | |||
if (this.engineSelector) this.engineSelector.style.display = 'none'; | |||
return; | |||
} | |||
} | |||
if (!this.is_active) { | |||
this.list.style.display = 'none'; | |||
if (this.engineSelector) this.engineSelector.style.display = 'none'; | |||
return; | |||
} | |||
var nofItems = (titles.length > 5 ? 5 : titles.length); | |||
if (nofItems <= 1) nofItems = 2; | |||
this.list.size = nofItems; | |||
this.list.style.align = 'left'; | |||
this.list.style.zIndex = 5; | |||
this.list.style.position = 'absolute'; | |||
// Compute initial list position. First the height. | |||
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.left = '-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 < 5) maxListHeight = (listh / nofItems) * 5; | |||
function scroll_offset (what) { | |||
var s = 'scroll' + what; | |||
return (document.documentElement ? document.documentElement[s] : 0) | |||
|| document.body[s] || 0; | |||
} | |||
function viewport (what) { | |||
if (typeof (is_safari) != 'undefined' && is_safari && !document.evaluate) | |||
return window['inner' + what]; | |||
var s = 'client' + what; | |||
if (typeof (is_opera) != 'undefined' && is_opera) return document.body[s]; | |||
return (document.documentElement ? document.documentElement[s] : 0) | |||
|| document.body[s] || 0; | |||
} | |||
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}; | |||
} | |||
// IE6 seems to report in this.text.offsetTop and this.text.offsetLeft global offsets?? | |||
// Possibly this has something to do with the special status of input elements in IE as | |||
// "windowed controls". Calculate the relative offsets manually. | |||
var textPos = position (this.text); | |||
var catLinePos = position (this.line); | |||
var textTop = textPos.y - catLinePos.y; | |||
var textLeft = textPos.x - catLinePos.x; | |||
if (window.ie6_bugs) { | |||
// IE6 somehow has a problem with inline-displayed forms (to which our list belongs), and will add the | |||
// offset of the beginning of the text to the offsets we'd normally calculate, which in particular with | |||
// right-aligned category lines as they occur in some older skins completely misplaces the lists, sometimes | |||
// even off-screen. This appears to affect only the horizontal positioning of the list and of the | |||
// engineSelector. Try to account for this bizarre behavior. Notes: dunno if that also occurs on IE7. | |||
var textStartPos = position (this.line.firstChild); | |||
textStartPos.x -= catLinePos.x; | |||
textLeft -= textStartPos.x; | |||
} | |||
var nl = textLeft; | |||
var nt = 0; | |||
var offset = 0; | |||
if (haveEngine) { | |||
this.engineSelector.style.zIndex = 5; | |||
this.engineSelector.style.position = 'absolute'; | |||
this.engineSelector.style.width = this.text.offsetWidth + '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.left = '-1000px'; | |||
this.engineSelector.style.top = textTop + 'px'; | |||
this.engineSelector.style.display = ""; | |||
offset = this.engineSelector.offsetHeight; | |||
this.engineSelector.style.display = 'none'; | |||
} else { | |||
offset = this.engineSelector.offsetHeight; | |||
} | |||
this.engineSelector.style.left = nl + 'px'; | |||
} | |||
if (textPos.y < maxListHeight + offset) { | |||
// The list might extend beyond the upper border of the page. Let's avoid that by placing it | |||
// below the input text field. | |||
nt = textTop + this.text.offsetHeight + offset + 1; | |||
if (haveEngine) this.engineSelector.style.top = textTop + this.text.offsetHeight + 'px'; | |||
} else { | |||
nt = textTop - listh - offset; | |||
if (haveEngine) this.engineSelector.style.top = textTop - offset + 'px'; | |||
} | |||
this.list.style.top = nt + 'px'; | |||
this.list.style.width = ""; // No fixed width (yet) | |||
this.list.style.left = nl + 'px'; | |||
// (Re-)fill the list | |||
while (this.list.firstChild) this.list.removeChild (this.list.firstChild); | |||
for (var i = 0 ; i < titles.length ; i++) { | |||
var opt = make ('option') ; | |||
opt.appendChild (make (titles[i], true)); | |||
this.list.appendChild (opt); | |||
} | |||
if (haveEngine) { | |||
this.selectEngine (engineName); | |||
this.engineSelector.style.display = ""; | |||
} | |||
this.list.style.display = 'block'; | |||
// Set the width of the list | |||
var scroll = scroll_offset ('Left'); | |||
var view_w = viewport ('Width'); | |||
var l_pos = position (this.list); | |||
if (this.list.offsetWidth < this.text.offsetWidth) { | |||
this.list.style.width = this.text.offsetWidth + 'px'; | |||
return; | |||
} | |||
// Make sure that the list fits horizontally into the browser window | |||
var w = this.list.offsetWidth; | |||
if (l_pos.x + w > scroll + view_w) { | |||
if (w > view_w) w = view_w; | |||
this.list.style.width = w + 'px'; | |||
this.list.style.left = nl - (l_pos.x + w - scroll - view_w) + 'px'; | |||
} | |||
}, | |||
var | autoComplete : function (newVal, actVal, key, dontModify) { | ||
if (newVal == actVal) return true; | |||
if (dontModify || newVal.indexOf (actVal) != 0) 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. | |||
if (!( this.text.setSelectionRange | |||
|| this.text.createTextRange | |||
|| typeof (this.text.selectionStart) != 'undefined' | |||
&& typeof (this.text.selectionEnd) != 'undefined' | |||
) | |||
) | |||
return false; | |||
// Here we know that we can indeed select properly. If we can't doing this would be a major | |||
// annoyance. | |||
this.text.focus(); | |||
var start = actVal.length; | |||
this.text.value = newVal + key; | |||
if (this.text.setSelectionRange) // e.g. khtml | |||
this.text.setSelectionRange (start, newVal.length); | |||
else if (this.text.createTextRange) { // IE | |||
var new_selection = this.text.createTextRange(); | |||
new_selection.move ('character', start); | |||
new_selection.moveEnd ('character', newVal.length - start); | |||
new_selection.select(); | |||
} else { | |||
this.text.selectionStart = start; | |||
this.text.selectionEnd = newVal.length; | |||
} | |||
return true; | |||
}, | |||
processKey : function (evt) { | |||
if (this.lastKey == 38 || this.lastKey == 40) { // Up and down arrows | |||
if (this.list.style.display != 'none') { | |||
// List is visible, so there are suggestions | |||
this.highlightSuggestion (this.lastKey == 38 ? -1 : 1); | |||
// 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 (); | |||
} | |||
} | |||
return true; | |||
}, | |||
highlightSuggestion : function (dir) { | |||
if (noSuggestions || !this.list || this.list.style.display == 'none') return; | |||
var curr = this.list.selectedIndex; | |||
var tgt = curr < 0 ? 0 : curr + dir; | |||
tgt = tgt < 0 ? 0 : tgt; | |||
if (tgt != curr && tgt < this.list.options.length) { | |||
if (curr >= 0 && curr < this.list.options.length) 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.lastInput, key, false); | |||
if (!completed) { | |||
this.text.value = this.list.options[tgt].text + key; | |||
} | |||
this.lastInput = this.list.options[tgt].text; | |||
} | |||
}, | |||
resetKeySelection : function () { | |||
if (noSuggestions || !this.list || this.list.style.display == 'none') return; | |||
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] : ""; | ||
this.text.value = this.lastRealInput + key; | |||
this.lastInput = this.lastRealInput; | |||
} | |||
} | |||
function | }; // end CategoryEditor.prototype | ||
var | |||
var | 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. | |||
HotCat.no_autocommit = | |||
(typeof (hotcat_no_autocommit) != 'undefined' | |||
? !!hotcat_no_autocommit | |||
: (typeof (JSconfig) != 'undefined' && typeof (JSconfig.keys['HotCatNoAutoCommit']) != 'undefined' | |||
? JSconfig.keys['HotCatNoAutoCommit'] | |||
: HotCat.no_autocommit | |||
) | |||
); | |||
HotCat.suggest_delay = window.hotcat_suggestion_delay | |||
|| typeof (JSconfig) != 'undefined' && JSconfig.keys['HotCatSuggestionDelay'] | |||
|| HotCat.suggest_delay; | |||
HotCat.editbox_width = window.hotcat_editbox_width | |||
|| typeof (JSconfig) != 'undefined' && JSconfig.keys['HotCatEditBoxWidth'] | |||
|| HotCat.editbox_width; | |||
HotCat.suggestions = window.hotcat_suggestions | |||
|| typeof (JSconfig) != 'undefined' && JSconfig.keys['HotCatSuggestions'] | |||
|| HotCat.suggestions; | |||
if (typeof (HotCat.suggestions) != 'string' || !suggestionConfigs[HotCat.suggestions]) | |||
HotCat.suggestions = 'combined'; | |||
HotCat.fixed_search = | |||
(typeof (hotcat_suggestions_fixed) != 'undefined' | |||
? !!hotcat_suggestions_fixed | |||
: (typeof (JSconfig) != 'undefined' && typeof (JSconfig.keys['HotCatFixedSuggestions']) != 'undefined' | |||
? JSconfig.keys['HotCatFixedSuggestions'] | |||
: HotCat.fixed_search | |||
) | |||
); | |||
HotCat.bg_changed = window.hotcat_changed_background | |||
|| typeof (JSconfig) != 'undefined' && JSconfig.keys['HotCatChangedBackground'] | |||
|| HotCat.bg_changed; | |||
HotCat.use_up_down = | |||
(typeof (hotcat_use_category_links) != 'undefined' | |||
? !!hotcat_use_category_links | |||
: (typeof (JSconfig) != 'undefined' && typeof (JSconfig.keys['HotCatUseCategoryLinks']) != 'undefined' | |||
? JSconfig.keys['HotCatUseCategoryLinks'] | |||
: HotCat.use_up_down | |||
) | |||
); | |||
// 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 (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) == 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 above the "watch this" box, and change the onsubmit handler. | |||
var ip = document.getElementById ('wpWatchthis'); | |||
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) | |||
ip = ip.parentNode.parentNode; // The containing <tr> | |||
var newRow = make ('tr'); | |||
var labelCell = make ('td'); | |||
var lineCell = make ('td'); | |||
newRow.appendChild (labelCell); | |||
newRow.appendChild (lineCell); | |||
// Create the category line | |||
catLine = make ('div'); | |||
catLine.className = 'catlinks'; | |||
catLine.id = 'catlinks'; | |||
catLine.style.textAlign = 'left'; | |||
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 optionsTable = document.getElementById ('mw-htmlform-options'); | |||
if (optionsTable) optionsTable.width = '100%'; | |||
ip.parentNode.insertBefore (newRow, ip); | |||
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'); | |||
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; | |||
} | |||
} | |||
return true; | |||
}; | |||
}) (form.onsubmit); | |||
} | |||
} | |||
var cleanedText = null; | |||
// | function isOnPage (span) { | ||
var catTitle = title (span.firstChild.getAttribute ('href', 2)); | |||
if (!catTitle) return null; | |||
return ; | catTitle = catTitle.substr (catTitle.indexOf (':') + 1).replace (/_/g, ' '); | ||
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 | var initialized = false; | ||
function setup () { | |||
if (initialized) return; | |||
initialized = true; | |||
// 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 | |||
|| getElementsByClassName (document , 'p' , 'catlinks')[0]; // MW < 1.13 | |||
var hiddenCats = document.getElementById ('mw-hidden-catlinks'); | |||
if (!catLine) { | |||
var footer = null; | |||
if (!hiddenCats) { | |||
footer = getElementsByClassName (document , 'div' , 'printfooter')[0]; | |||
if (!footer) return; // Don't know where to insert the category line | |||
} | |||
catLine = make ('div'); | |||
catLine.id = 'mw-normal-catlinks'; | |||
catLine.style.textAlign = 'left'; | |||
// Add a label | |||
var label = make ('a'); | |||
label.href = 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 | |||
catLine.style.position = 'relative'; | |||
if (is_rtl) catLine.dir = 'rtl'; | |||
// Create editors for all existing categories | |||
function createEditors (line) { | |||
var 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 (var i = 0; i < cats.length; i++) copyCats[i] = cats[i]; | |||
var editor = null; | |||
for (var 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]); | |||
} | |||
} | |||
return copyCats.length > 0 ? copyCats[copyCats.length-1] : null; | |||
} | |||
var lastSpan = createEditors (catLine); | |||
// Create one to add a new category | |||
var editor = new CategoryEditor(catLine, null, null, lastSpan != null); | |||
if (!onUpload) { | |||
if (pageText !== null && hiddenCats) { | |||
hiddenCats.style.position = 'relative'; | |||
if (is_rtl) hiddenCats.dir = 'rtl'; | |||
createEditors (hiddenCats); | |||
} | |||
// 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; | |||
} | } | ||
function setPage (json) { | |||
} | if (!json || !json.query || !json.query.pages) return; | ||
for (var p in json.query.pages) { | |||
var page = json.query.pages[p]; | |||
if (!page.revisions || page.revisions.length == 0) break; | |||
pageText = page.revisions[0]['*']; | |||
pageTime = page.revisions[0].timestamp.replace (/\D/g, ""); | |||
pageWatched = typeof (page.watched) == 'string'; | |||
break; | |||
} | |||
} | |||
function | function getPage () { | ||
// We know we have an article here. | |||
if (wgArticleId == 0) { | |||
// Doesn't exist yet. | |||
pageText = ""; | |||
pageTime = null; | |||
setup (); | |||
} else { | |||
var url = wgServer + wgScriptPath + '/api.php?format=json&callback=HotCat.start&action=query&titles=' | |||
+ encodeURIComponent (wgPageName) + '&prop=info%7Crevisions&rvprop=content%7Ctimestamp'; | |||
var s = make ('script'); | |||
s.src = url; | |||
s.type = 'text/javascript'; | |||
HotCat.start = function (json) { setPage (json); setup (); }; | |||
document.getElementsByTagName ('head')[0].appendChild (s); | |||
window.setTimeout (setup, 4000); // 4 seconds. Just in case getting the wikitext takes longer. | |||
} | } | ||
} | } | ||
function | function run () { | ||
if (HotCat.started) return; | |||
HotCat.started = true; | |||
initialize (); | |||
if (is_rtl && window.ie6_bugs) return; // Disabled! IE6 with RTL is just too broken... | |||
if (wgNamespaceNumber == -1 && wgCanonicalSpecialPageName == 'Upload' && wgUserName) { | |||
setup_upload (); | |||
setup (); | |||
// Check for state restoration | |||
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 (!wgIsArticle || wgAction != 'view' || !can_edit() || HotCat.disable()) return; | |||
getPage (); | |||
} | |||
} | } | ||
function | // Legacy stuff | ||
function closeForm () { | |||
var | // 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; | |||
} | } | ||
var | |||
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; | |||
for (var 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 = wgArticlePath.split ('$1').join ('Category:' + encodeURI (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 (var i = 0; i < newSpans.length; i++) { | |||
editor = new CategoryEditor (catLine, newSpans[i].element, newSpans[i].title, newSpans[i].key); | |||
} | |||
} | |||
return null; | |||
} | } | ||
// Now export these legacy functions | |||
window.hotcat_get_state = function () { return getState(); }; | |||
window.hotcat_set_state = function (state) { return setState (state); }; | |||
window.hotcat_close_form = function () { closeForm (); }; | |||
addOnloadHook (run); | |||
})(); | |||
} // end if (guard) | |||
//</source> | |||
// </ | |||