۵٬۱۲۵
ویرایش
بدون خلاصۀ ویرایش |
بدون خلاصۀ ویرایش |
||
خط ۱: | خط ۱: | ||
/* | |||
This imports the latest version of HotCat from Commons. | |||
HotCat is a gadget to make changes to categories much easier. | |||
can be | Full documentation can be found at [[commons:Help:Gadget-HotCat]]d | ||
*/ | |||
//mw.loader.load( '//commons.wikimedia.org/w/index.php?title=MediaWiki:Gadget-HotCat.js&action=raw&ctype=text/javascript' ); | |||
//به دلیل بروز مشکل در باز شدن هاتکت کد را به اینجا انتقال دادم | |||
//<source lang="javascript"> | |||
/* | |||
HotCat V2.32 | |||
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; | ||
( function ( | function htmlEscape(str) { | ||
// | return String(str) | ||
.replace(/&/g, '&') | |||
.replace(/"/g, '"') | |||
.replace(/'/g, ''') | |||
.replace(/</g, '<') | |||
.replace(/>/g, '>'); | |||
} | |||
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; | return; | ||
} | |||
// Configuration stuff. | |||
window.HotCat = { | |||
// Localize these messages to the main language of your wiki. | |||
messages : | |||
{cat_removed : 'removed [[Category:$1]]' | |||
,template_removed : 'removed {{[[Category:$1]]}}' | |||
,cat_added : 'added [[Category:$1]]' | |||
,cat_keychange: 'new key for [[Category:$1]]: "$2"' // $2 is the new key | |||
,cat_notFound : 'Category "$1" not found' | |||
,cat_exists : 'Category "$1" already exists; not added.' | |||
,cat_resolved : ' (redirect [[Category:$1]] resolved)' | |||
,uncat_removed: 'removed {{uncategorized}}' | |||
,separator : '; ' | |||
,prefix : "" | |||
// Some text to prefix to the edit summary. | |||
,using : ' using [[Help:Gadget-HotCat|HotCat]]' | |||
// 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 : 'Save' | |||
// 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 : '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 : 'Category' | |||
// 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 : 'Categories' | |||
// Plural of category_canonical. | |||
,disambig_category : 'Disambiguation' | |||
// 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 : 'Category redirects' | |||
// 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: 'Modify' | |||
,remove: 'Remove' | |||
,add: 'Add a new category' | |||
,restore: 'Undo changes' | |||
,undo: 'Undo changes' | |||
,down: 'Open for modifying and display subcategories' | |||
,up: 'Open for modifying and display parent categories' | |||
} | |||
// 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 : 'Modify several categories' | |||
// Tooltip for the "enter multi-mode" link | |||
// Return true to disable HotCat. | ,disable : | ||
function () { // Return true to disable HotCat. | |||
var ns = conf.wgNamespaceNumber; | var ns = conf.wgNamespaceNumber; | ||
var nsIds = conf.wgNamespaceIds; | var nsIds = conf.wgNamespaceIds; | ||
return ( | 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 : '//upload.wikimedia.org/wikipedia/commons/thumb/b/be/P_yes.svg/20px-P_yes.svg.png' | |||
,existsNo : '//upload.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 : 'Search index' | |||
,pagelist : 'Page list' | |||
,combined : 'Combined search' | |||
,subcat : 'Subcategories' | |||
,parentcat : 'Parent categories' | |||
} | |||
// 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 : | |||
if ( !map ) return; | function (map) { | ||
if (!map) return; | |||
window.HotCat.shortcuts = window.HotCat.shortcuts || {}; | window.HotCat.shortcuts = window.HotCat.shortcuts || {}; | ||
for ( var k in map ) { | for (var k in map) { | ||
if ( !map.hasOwnProperty( k ) || typeof k ! | if (!map.hasOwnProperty (k) || typeof k != 'string') continue; | ||
var v = map[k]; | |||
var v = map[ k ]; | if (typeof v != 'string') continue; | ||
if ( typeof v ! | k = k.replace (/^\s+|\s+$/g, ""); | ||
v = v.replace (/^\s+|\s+$/g, ""); | |||
k = k.replace( /^\s+|\s+$/g, | if (k.length === 0 || v.length === 0) continue; | ||
v = v.replace( /^\s+|\s+$/g, | window.HotCat.shortcuts[k] = v; | ||
if ( | |||
window.HotCat.shortcuts[ k ] = v; | |||
} | } | ||
} | } | ||
}; | |||
// More backwards compatibility. We have a few places where we test for the browser: once for | // More backwards compatibility. We have a few places where we test for the browser: once for | ||
// Safari < 3.0, | // 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 ua = navigator.userAgent.toLowerCase(); | ||
var is_webkit = /applewebkit\/\d+/.test( ua ) && ua.indexOf( 'spoofer' ) < 0; | var is_ie6 = /msie ([0-9]{1,}[\.0-9]{0,})/.exec(ua) !== null && parseFloat(RegExp.$1) <= 6.0; | ||
var | 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 ( | 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 { | |||
if ( | 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. | // Used to delay running the HotCat setup until /local_defaults and localizations have been loaded. | ||
function load( uri | function load (uri) { | ||
var s = document.createElement( 'script' ); | var head = document.getElementsByTagName ('head')[0]; | ||
s.src | var s = document.createElement ('script'); | ||
var | 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. | s.onload = s.onreadystatechange = function () { // onreadystatechange for IE, onload for all others | ||
if ( | if (done) return; | ||
if (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') { | |||
afterLoad (); | |||
if ( | |||
} | } | ||
}; | }; | ||
s.onerror = afterLoad; // Clean up, but otherwise ignore errors | |||
head.insertBefore (s, head.firstChild); // appendChild may trigger bugs in IE6 here | |||
} | } | ||
function loadJS( page | function loadJS (page) { | ||
load( conf.wgServer + conf.wgScript + '?title=' + encodeURIComponent( page ) + '&action=raw&ctype=text/javascript' | load (conf.wgServer + conf.wgScript + '?title=' + encodeURIComponent (page) + '&action=raw&ctype=text/javascript'); | ||
} | } | ||
function loadURI( href | function loadURI (href) { | ||
var url = href; | var url = href; | ||
if ( url.substring( 0, 2 ) | if (url.substring (0, 2) == '//') { | ||
url = window.location.protocol + url; | |||
load( 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 | // 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 Commons. This can | // 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. | // 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' | 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 | // 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. | // should be localized in /local_defaults above. | ||
if ( conf.wgUserLanguage ! | 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 | // 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 Commons and don't want that. | // explicitly if you're not on the Commons and don't want that. | ||
if ( window.hotcat_translations_from_commons == | 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. | // Localization hook to localize HotCat messages, tooltips, and engine names for wgUserLanguage. | ||
if ( window.hotcat_translations_from_commons && conf.wgServer.indexOf( '//commons' ) < 0 ) { | if (window.hotcat_translations_from_commons && conf.wgServer.indexOf('//commons') < 0) { | ||
loadURI( '//commons.wikimedia.org/w/index.php?title=' + | loadURI ('//commons.wikimedia.org/w/index.php?title=' | ||
+ 'MediaWiki:Gadget-HotCat.js/' + conf.wgUserLanguage | |||
+ '&action=raw&ctype=text/javascript' | |||
); | |||
} else { | } else { | ||
// Load translations locally | // Load translations locally | ||
loadJS( 'MediaWiki:Gadget-HotCat.js/' + conf.wgUserLanguage | loadJS ('MediaWiki:Gadget-HotCat.js/' + conf.wgUserLanguage); | ||
} | } | ||
} else { | } else { | ||
خط ۲۹۸: | خط ۴۰۵: | ||
// The following regular expression strings are used when searching for categories in wikitext. | // 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 wikiTextBlank = '[\\t _\\xA0\\u1680\\u180E\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]+'; | ||
var wikiTextBlankRE = new RegExp( wikiTextBlank, 'g' ); | var wikiTextBlankRE = new RegExp (wikiTextBlank, 'g'); | ||
// Regexp for handling blanks inside a category title or namespace name. | // 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 http://svn.wikimedia.org/viewvc/mediawiki/trunk/phase3/includes/Title.php?revision=104051&view=markup#l2722 | ||
خط ۳۲۰: | خط ۴۲۷: | ||
var formattedNamespaces = conf.wgFormattedNamespaces; | var formattedNamespaces = conf.wgFormattedNamespaces; | ||
var namespaceIds = conf.wgNamespaceIds; | var namespaceIds = conf.wgNamespaceIds; | ||
function autoLocalize( namespaceNumber, fallback ) { | 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); | |||
} | |||
var | fallback = fallback.toLowerCase(); | ||
var canonical = formattedNamespaces["" + namespaceNumber].toLowerCase(); | |||
var | 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 | return regexp; | ||
} | } | ||
if (formattedNamespaces['14']) { | |||
HotCat.category_canonical = formattedNamespaces['14']; | |||
HotCat.category_regexp = autoLocalize (14, 'category'); | |||
} | |||
if (formattedNamespaces['10']) { | |||
if ( | HotCat.template_regexp = autoLocalize (10, 'template'); | ||
} | } | ||
} | } | ||
// Utility functions. Yes, this duplicates some functionality that also exists in other places, but | // 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 | // to keep this whole stuff in a single file not depending on any other on-wiki Javascripts, we re-do | ||
// these few operations here. | // these few operations here. | ||
function make( arg, literal ) { | function bind (func, target) { | ||
if ( !arg ) return null; | var f = func, tgt = target; | ||
return function () { return f.apply (tgt, arguments); }; | |||
return literal ? document.createTextNode( arg ) : document.createElement( arg ); | } | ||
function make (arg, literal) { | |||
if (!arg) return null; | |||
return literal ? document.createTextNode (arg) : document.createElement (arg); | |||
} | } | ||
function param( name, uri ) { | function param (name, uri) { | ||
uri = | if (typeof uri == 'undefined' || uri === null) uri = document.location.href; | ||
var re = new RegExp( '[&?]' + name + '=([^&#]*)' ); | var re = new RegExp ('[&?]' + name + '=([^&#]*)'); | ||
var m = re.exec( uri ); | var m = re.exec (uri); | ||
if ( m && m.length > 1 ) return decodeURIComponent( m[ 1 ] ); | if (m && m.length > 1) return decodeURIComponent(m[1]); | ||
return null; | return null; | ||
} | } | ||
function title( href ) { | function title (href) { | ||
if ( !href ) return null; | if (!href) return null; | ||
var script = conf.wgScript + '?'; | var script = conf.wgScript + '?'; | ||
if ( href.indexOf( script ) === 0 || href.indexOf( conf.wgServer + script ) === 0 || conf.wgServer.substring( 0, 2 ) | 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=..." | // href="/w/index.php?title=..." | ||
return param( 'title', href ); | return param ('title', href); | ||
} else { | } else { | ||
// href="/wiki/..." | // href="/wiki/..." | ||
var prefix = conf.wgArticlePath.replace( '$1', | var prefix = conf.wgArticlePath.replace ('$1', ""); | ||
if ( href.indexOf( prefix ) ) prefix = conf.wgServer + prefix; // Fully expanded URL? | 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 ) && prefix.substring( 0, 2 ) | if (href.indexOf (prefix) === 0) | ||
return decodeURIComponent (href.substring (prefix.length)); | |||
if ( href.indexOf( prefix ) === 0 ) return decodeURIComponent( href.substring( prefix.length ) ); | |||
} | } | ||
return null; | return null; | ||
} | } | ||
function hasClass( elem, name ) { | function hasClass (elem, name) { | ||
return ( ' ' + elem.className + ' ' ).indexOf( ' ' + name + ' ' ) >= 0; | return (' ' + elem.className + ' ').indexOf (' ' + name + ' ') >= 0; | ||
} | } | ||
function capitalize( str ) { | function capitalize (str) { | ||
if ( !str || | if (!str || str.length === 0) return str; | ||
return str.substr(0, 1).toUpperCase() + str.substr (1); | |||
return str.substr( 0, 1 ).toUpperCase() + str.substr( 1 ); | |||
} | } | ||
function wikiPagePath( pageName ) { | function wikiPagePath (pageName) { | ||
// Note: do not simply use encodeURI, it doesn't encode '&', which might break if wgArticlePath actually has the $1 in | // Note: do not simply use encodeURI, it doesn't encode '&', which might break if wgArticlePath actually has the $1 in | ||
// a query parameter. | // a query parameter. | ||
return conf.wgArticlePath.replace( '$1', encodeURIComponent( pageName ).replace( /%3A/g, ':' ).replace( /%2F/g, '/' ) ); | return conf.wgArticlePath.replace('$1', encodeURIComponent (pageName).replace(/%3A/g, ':').replace(/%2F/g, '/')); | ||
} | } | ||
function escapeRE( str ) { | function escapeRE(str) { | ||
return str.replace( /([\\^$.?*+()[\]])/g, '\\$1' ); | return str.replace(/([\\\^\$\.\?\*\+\(\)\[\]])/g, '\\$1'); | ||
} | } | ||
function substituteFactory( options ) { | function substituteFactory (options) { | ||
options = options || {}; | options = options || {}; | ||
var lead = options.indicator || '$'; | var lead = options.indicator || '$'; | ||
var indicator = escapeRE( lead ); | var indicator = escapeRE (lead); | ||
var lbrace = escapeRE( options.lbrace || '{' ); | var lbrace = escapeRE (options.lbrace || '{'); | ||
var rbrace = escapeRE( options.rbrace || '}' ); | var rbrace = escapeRE (options.rbrace || '}'); | ||
var re; | var re; | ||
re = new RegExp( | re = new RegExp( | ||
'(?:' + indicator + '(' + indicator + '))|' // $$ | |||
+'(?:' + indicator + '(\\d+))|' // $0, $1 | |||
+'(?:' + indicator + '(?:' + lbrace + '([^' + lbrace + rbrace + ']+)' + rbrace + '))|' // ${key} | |||
'(?:' + indicator + '(\\d+))|' | +'(?:' + indicator + '(?!(?:[' + indicator + lbrace + ']|\\d))(\\S+?)\\b)' // $key (only if first char after $ is not $, digit, or { ) | ||
,'g'); | |||
'(?:' + indicator + '(?:' + lbrace + '([^' + lbrace + rbrace + ']+)' + rbrace + '))|' | |||
'(?:' + indicator + '(?!(?:[' + indicator + lbrace + ']|\\d))(\\S+?)\\b)', | |||
'g' | |||
// Replace $1, $2, or ${key1}, ${key2}, or $key1, $key2 by values from map. $$ is replaced by a single $. | // Replace $1, $2, or ${key1}, ${key2}, or $key1, $key2 by values from map. $$ is replaced by a single $. | ||
return function ( str, map ) { | return function (str, map) { | ||
if ( !map ) return str; | if (!map) return str; | ||
return str.replace(re | |||
return str.replace( re, function ( match, prefix, idx, key, alpha ) { | ,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 substitute = substituteFactory(); | ||
var replaceShortcuts = ( function () { | var replaceShortcuts = (function () { | ||
var replaceHash = substituteFactory( { | var replaceHash = substituteFactory({indicator:'#',lbrace:'[',rbrace:']'}); | ||
return function (str, map) { | |||
var s = replaceHash (str, map); | |||
return HotCat.capitalizePageNames ? capitalize(s) : s; | |||
return function ( str, map ) { | |||
var s = replaceHash( str, map ); | |||
return | |||
}; | }; | ||
}( | })(); | ||
// Text modification | // Text modification | ||
var findCatsRE = | var findCatsRE = | ||
new RegExp ('\\[\\[' + wikiTextBlankOrBidi + '(?:' + HotCat.category_regexp + ')' + wikiTextBlankOrBidi + ':[^\\]]+\\]\\]', 'g'); | |||
function replaceByBlanks( match ) { | function replaceByBlanks (match) { | ||
return match.replace( /(\s|\S)/g, ' ' ); // /./ doesn't match linebreaks. /(\s|\S)/ does. | return match.replace(/(\s|\S)/g, ' '); // /./ doesn't match linebreaks. /(\s|\S)/ does. | ||
} | } | ||
function find_category( wikitext, category, once ) { | function find_category (wikitext, category, once) { | ||
var cat_regex = null; | var cat_regex = null; | ||
if ( | if(HotCat.template_categories[category]){ | ||
cat_regex = new RegExp( | cat_regex = new RegExp ('\\{\\{' + wikiTextBlankOrBidi + '(' + HotCat.template_regexp + '(?=' + wikiTextBlankOrBidi + ':))?' + wikiTextBlankOrBidi | ||
+ '(?:' + HotCat.template_categories[category] + ')' | |||
+ wikiTextBlankOrBidi + '(\\|.*?)?\\}\\}', 'g' | |||
); | ); | ||
} else { | } else { | ||
var cat_name = escapeRE( category ); | var cat_name = escapeRE (category); | ||
var initial = cat_name.substr( 0, 1 ); | var initial = cat_name.substr (0, 1); | ||
cat_regex = new RegExp( | 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 ); | if (once) return cat_regex.exec (wikitext); | ||
var copiedtext = wikitext | var copiedtext = wikitext | ||
.replace(/<\!--(\s|\S)*?--\>/g, replaceByBlanks) | |||
.replace(/<nowiki\>(\s|\S)*?<\/nowiki>/g, replaceByBlanks); | |||
var result = []; | var result = []; | ||
var curr_match = null; | var curr_match = null; | ||
while ( ( curr_match = cat_regex.exec( copiedtext ) ) !== null ) { | while ((curr_match = cat_regex.exec (copiedtext)) !== null) { | ||
result.push( { | result.push ({match : curr_match}); | ||
} | } | ||
result.re = cat_regex; | result.re = cat_regex; | ||
return result; // An array containing all matches, with positions, in result[ i ].match | return result; // An array containing all matches, with positions, in result[i].match | ||
} | } | ||
var interlanguageRE = null; | var interlanguageRE = null; | ||
function change_category( wikitext, toRemove, toAdd, key, is_hidden ) { | function change_category (wikitext, toRemove, toAdd, key, is_hidden) { | ||
function find_insertionpoint( wikitext ) { | function find_insertionpoint (wikitext) { | ||
var copiedtext = 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". | // Search in copiedtext to avoid that we insert inside an HTML comment or a nowiki "element". | ||
var index = -1; | var index = -1; | ||
findCatsRE.lastIndex = 0; | findCatsRE.lastIndex = 0; | ||
while ( findCatsRE.exec( copiedtext ) !== null ) index = findCatsRE.lastIndex; | while (findCatsRE.exec(copiedtext) !== null) index = findCatsRE.lastIndex; | ||
if (index < 0) { | |||
if ( index < 0 ) { | |||
// Find the index of the first interlanguage link... | // Find the index of the first interlanguage link... | ||
var match = null; | var match = null; | ||
if ( !interlanguageRE ) { | 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 ); | match = /((^|\n\r?)(\[\[\s*(([a-z]{2,3}(-[a-z]+)*)|simple|tokipona)\s*:[^\]]+\]\]\s*))+$/.exec (copiedtext); | ||
} else { | } else { | ||
match = interlanguageRE.exec( copiedtext ); | match = interlanguageRE.exec(copiedtext); | ||
} | } | ||
if ( match ) index = match.index; | if (match) index = match.index; | ||
return {idx : index, onCat : false}; | |||
return { | |||
} | } | ||
return { | return {idx : index, onCat : index >= 0}; | ||
} | } | ||
var summary = [] | 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 ) { | if (toRemove && toRemove.length > 0) { | ||
matches = find_category( wikitext, toRemove ); | matches = find_category (wikitext, toRemove); | ||
if ( !matches || | if (!matches || matches.length === 0) { | ||
return { | return {text: wikitext, 'summary': summary, error: HotCat.messages.cat_notFound.replace (/\$1/g, toRemove)}; | ||
} else { | } else { | ||
var before = wikitext.substring( 0, matches[ 0 ].match.index ) | 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 ) { | if (matches.length > 1) { | ||
// Remove all occurrences in after | |||
matches.re.lastIndex = 0; | matches.re.lastIndex = 0; | ||
after = after.replace( matches.re, | after = after.replace (matches.re, ""); | ||
} | } | ||
if ( toAdd ) { | if (toAdd) { | ||
nameSpace = matches[0].match[1] || nameSpace; | |||
if ( key === null ) key = matches[ 0 ].match[ 2 ]; | 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. | // Remove whitespace (properly): strip whitespace, but only up to the next line feed. | ||
خط ۵۷۲: | خط ۶۵۸: | ||
// whitespace characters, insert a blank. | // whitespace characters, insert a blank. | ||
var i = before.length - 1; | var i = before.length - 1; | ||
while ( i >= 0 && before.charAt( i ) ! | while (i >= 0 && before.charAt (i) != '\n' && before.substr (i, 1).search (/\s/) >= 0) i--; | ||
var j = 0; | var j = 0; | ||
while ( j < after.length && after.charAt( j ) ! | while (j < after.length && after.charAt (j) != '\n' && after.substr (j, 1).search (/\s/) >= 0) | ||
j++; | |||
if ( i >= 0 && before.charAt( i ) | 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 (i >= 0) before = before.substring (0, i+1); else before = ""; | ||
if (j < after.length) after = after.substring (j); else after = ""; | |||
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) | |||
if ( | |||
before += ' '; | before += ' '; | ||
cat_point = before.length; | |||
if (cat_point === 0 && after.length > 0 && after.substr(0,1) == '\n') { | |||
after = after.substr(1); | |||
} | } | ||
wikitext = before + after; | wikitext = before + after; | ||
if ( !keyChange ) { | if (!keyChange) { | ||
if ( | 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) { | |||
if ( toAdd && toAdd.length ) { | matches = find_category (wikitext, toAdd); | ||
matches = find_category( wikitext, toAdd ); | if (matches && matches.length > 0) { | ||
if ( matches && matches.length ) { | return {text: wikitext, 'summary': summary, error : HotCat.messages.cat_exists.replace (/\$1/g, toAdd)}; | ||
return { | |||
} else { | } else { | ||
var onCat = false; | var onCat = false; | ||
if ( cat_point < 0 ) { | if (cat_point < 0) { | ||
var point = find_insertionpoint( wikitext ); | var point = find_insertionpoint (wikitext); | ||
cat_point = point.idx; | cat_point = point.idx; | ||
onCat = point.onCat; | onCat = point.onCat; | ||
خط ۶۱۹: | خط ۶۹۶: | ||
onCat = true; | onCat = true; | ||
} | } | ||
var newcatstring = '[[' + nameSpace + ':' + toAdd + ( key || | var newcatstring = '[[' + nameSpace + ':' + toAdd + (key || "") + ']]'; | ||
if ( cat_point >= 0 ) { | if (cat_point >= 0) { | ||
var suffix = wikitext.substring( cat_point ); | var suffix = wikitext.substring (cat_point); | ||
wikitext = wikitext.substring( 0, cat_point ) + ( cat_point > 0 ? '\n' : | wikitext = wikitext.substring (0, cat_point) + (cat_point > 0 ? '\n' : "") + newcatstring + (!onCat ? '\n' : ""); | ||
if ( suffix.length && suffix.substr( 0, 1 ) ! | if (suffix.length > 0 && suffix.substr(0, 1) != '\n') { | ||
wikitext += '\n' + suffix; | |||
} else { | |||
wikitext += suffix; | |||
} | |||
} else { | } else { | ||
if ( wikitext.length && wikitext.substr( wikitext.length - 1, 1 ) ! | if (wikitext.length > 0 && wikitext.substr (wikitext.length - 1, 1) != '\n') | ||
wikitext += '\n'; | |||
wikitext += ( wikitext.length ? '\n' : | wikitext += (wikitext.length > 0 ? '\n' : "") + newcatstring; | ||
} | } | ||
if ( keyChange ) { | if (keyChange) { | ||
var k = key || | var k = key || ""; | ||
if ( k.length ) k = k.substr( 1 ); | if (k.length > 0) k = k.substr (1); | ||
summary.push (substitute (HotCat.messages.cat_keychange, [null, toAdd, k])); | |||
summary.push( substitute( | |||
} else { | } else { | ||
summary.push( | summary.push (HotCat.messages.cat_added.replace (/\$1/g, toAdd)); | ||
} | } | ||
if ( | if (HotCat.uncat_regexp && !is_hidden) { | ||
var txt = wikitext.replace( | var txt = wikitext.replace (HotCat.uncat_regexp, ""); // Remove "uncat" templates | ||
if ( txt.length ! | if (txt.length != wikitext.length) { | ||
wikitext = txt; | wikitext = txt; | ||
summary.push( | summary.push (HotCat.messages.uncat_removed); | ||
} | } | ||
} | } | ||
} | } | ||
} | } | ||
return { | return {text: wikitext, 'summary': summary, error: null}; | ||
} | } | ||
// The real HotCat UI | // The real HotCat UI | ||
function evtKeys( e ) { | function evtKeys (e) { | ||
/ | e = e || window.event || window.Event; // W3C, IE, Netscape | ||
var code = 0; | var code = 0; | ||
if ( e.ctrlKey ) { // All modern browsers | 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.ctrlKey || e.metaKey) code |= 1; | ||
if (e.shiftKey) code |= 2; | |||
if ( e. | } 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; | return code; | ||
} | } | ||
function evtKill( e ) { | function evtKill (e) { | ||
if ( e.preventDefault ) { | e = e || window.event || window.Event; // W3C, IE, Netscape | ||
e.preventDefault(); | if (typeof e.preventDefault != 'undefined') { | ||
e.stopPropagation(); | e.preventDefault (); | ||
} else | e.stopPropagation (); | ||
} else | |||
e.cancelBubble = true; | e.cancelBubble = true; | ||
return false; | return false; | ||
} | |||
function addEvent (node, evt, f, capture) { | |||
if (window.jQuery && (!capture || !node.addEventListener)) window.jQuery (node).on(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 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 | 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 | function checkMultiInput () { | ||
if (!commitButton) return; | |||
if ( | var has_changes = false; | ||
for (var i = 0; i < editors.length; i++) { | |||
if (editors[i].state != CategoryEditor.UNCHANGED) { | |||
has_changes = true; | |||
break; | |||
if ( | |||
} | } | ||
} | } | ||
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; | var saveInProgress = false; | ||
function initiateEdit( doEdit, failure ) { | function initiateEdit (doEdit, failure) { | ||
if ( saveInProgress ) return; | if (saveInProgress) return; | ||
saveInProgress = true; | saveInProgress = true; | ||
var oldButtonState; | var oldButtonState; | ||
if ( commitButton ) { | if (commitButton) { | ||
oldButtonState = commitButton.disabled; | oldButtonState = commitButton.disabled; | ||
commitButton.disabled = true; | commitButton.disabled = true; | ||
خط ۷۶۳: | خط ۸۳۵: | ||
function fail() { | function fail() { | ||
saveInProgress = false; | saveInProgress = false; | ||
if ( commitButton ) commitButton.disabled = oldButtonState; | if (commitButton) commitButton.disabled = oldButtonState; | ||
failure.apply( this, arguments ); | failure.apply(this, arguments); | ||
} | } | ||
// Must use Ajax here to get the user options and the edit token. | // 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&rawcontinue=&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 | function multiChangeMsg (count) { | ||
var | 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 ) { | function performChanges (failure, singleEditor) { | ||
if ( pageText === null ) { | if (pageText === null) { | ||
failure( | failure (HotCat.messages.multi_error); | ||
return; | return; | ||
} | } | ||
// Backwards compatibility after message change (added $2 to cat_keychange) | // Backwards compatibility after message change (added $2 to cat_keychange) | ||
if ( | if (HotCat.messages.cat_keychange.indexOf ('$2') < 0) HotCat.messages.cat_keychange += '"$2"'; | ||
// More backwards-compatibility with earlier HotCat versions: | // More backwards-compatibility with earlier HotCat versions: | ||
if ( ! | 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 | // 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 | // (a) sensibly reporting back errors like edit conflicts is always a hassle, and | ||
خط ۸۲۹: | خط ۸۸۶: | ||
// current user, then we set the "oldid" value and switch to diff, which gives the "you are editing an old version; | // 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. | // if you save, any more recent changes will be lost" screen. | ||
var | var editingOldVersion = lastRevId !== null && lastRevId != conf.wgCurRevisionId || pageTextRevId !== null && pageTextRevId != conf.wgCurRevisionId; | ||
var selfEditConflict = editingOldVersion && conflictingUser && conflictingUser == conf.wgUserName; | |||
if ( singleEditor && !singleEditor.noCommit && ! | 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 | // 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. | // 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; | commitForm.wpEditToken.value = editToken; | ||
action = commitForm.wpDiff; | action = commitForm.wpDiff; | ||
if ( action ) action.name = action.value = 'wpSave'; | if (action) action.name = action.value = 'wpSave'; | ||
} else { | } else { | ||
action = commitForm.wpSave; | action = commitForm.wpSave; | ||
if ( action ) action.name = action.value = 'wpDiff'; | if (action) action.name = action.value = 'wpDiff'; | ||
} | } | ||
var result = { | 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 | |||
for ( i = 0; i < toEdit.length; i++ ) { | , toEdit[i].currentKey | ||
, toEdit[i].currentHidden | |||
); | |||
result = change_category( | if (!result.error) { | ||
if ( !result.error ) { | |||
changes++; | changes++; | ||
if ( ! | if (!toEdit[i].originalCategory || toEdit[i].originalCategory.length === 0) { | ||
added.push( | added.push (toEdit[i].currentCategory); | ||
} else { | } else { | ||
changed.push( { | changed.push ({from : toEdit[i].originalCategory, to : toEdit[i].currentCategory}); | ||
} | } | ||
} else if ( error === null ) { | } else if (error === null) { | ||
error = result.error; | error = result.error; | ||
} | } | ||
} else if ( | } else if ( toEdit[i].state == CategoryEditor.DELETED | ||
&& toEdit[i].originalCategory | |||
result = change_category( | && toEdit[i].originalCategory.length > 0) | ||
{ | |||
result = change_category (result.text, toEdit[i].originalCategory, null, null, false); | |||
if (!result.error) { | |||
if ( !result.error ) { | |||
changes++; | changes++; | ||
deleted.push( | deleted.push (toEdit[i].originalCategory); | ||
} else if ( error === null ) { | } else if (error === null) { | ||
error = result.error; | error = result.error; | ||
} | } | ||
} | } | ||
} | } | ||
if ( error !== null ) { // Do not commit if there were errors | if (error !== null) { // Do not commit if there were errors | ||
action = commitForm.wpSave; | action = commitForm.wpSave; | ||
if ( action ) action.name = action.value = 'wpDiff'; | if (action) action.name = action.value = 'wpDiff'; | ||
} | } | ||
// Fill in the form and submit it | // Fill in the form and submit it | ||
commitForm.wpAutoSummary.value = 'd41d8cd98f00b204e9800998ecf8427e'; // MD5 hash of the empty string | |||
commitForm.wpMinoredit.checked = minorEdits; | commitForm.wpMinoredit.checked = minorEdits; | ||
commitForm.wpWatchthis.checked = | commitForm.wpWatchthis.checked = conf.wgArticleId === 0 && watchCreate || watchEdit || pageWatched; | ||
if ( conf.wgArticleId || !!singleEditor ) { | 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) { | |||
if ( changes | |||
if ( result.summary && result.summary.length ) commitForm.wpSummary.value = | |||
commitForm.wpMinoredit.checked = | |||
} else if ( changes ) { | |||
var summary = []; | var summary = []; | ||
var shortSummary = []; | var shortSummary = []; | ||
// Deleted | // Deleted | ||
for ( i = 0; i < deleted.length; i++ ) summary.push( '-' + substitute( | for (i = 0; i < deleted.length; i++) { | ||
summary.push ('-' + substitute (HotCat.messages.short_catchange, [null, deleted[i]])); | |||
if ( deleted.length | } | ||
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 | // Added | ||
for ( i = 0; i < added.length; i++ ) summary.push( '+' + substitute( | for (i = 0; i < added.length; i++) { | ||
summary.push ('+' + substitute (HotCat.messages.short_catchange, [null, added[i]])); | |||
if ( added.length | } | ||
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 | // Changed | ||
var arrow = is_rtl ? '\u2190' : '\u2192'; // left and right arrows. Don't use ← and → in the code. | var arrow = is_rtl ? '\u2190' : '\u2192'; // left and right arrows. Don't use ← and → in the code. | ||
for ( i = 0; i < changed.length; i++ ) { | for (i = 0; i < changed.length; i++) { | ||
if ( changed[ i ].from ! | if (changed[i].from != changed[i].to) { | ||
summary.push( | summary.push ('±' + substitute (HotCat.messages.short_catchange, [null, changed[i].from]) + arrow | ||
+ substitute (HotCat.messages.short_catchange, [null, changed[i].to])); | |||
} else { | } else { | ||
summary.push( '±' + substitute( | summary.push ('±' + substitute (HotCat.messages.short_catchange, [null, changed[i].from])); | ||
} | } | ||
} | } | ||
if ( changed.length | if (changed.length == 1) { | ||
if ( changed[ 0 ].from ! | if (changed[0].from != changed[0].to) { | ||
shortSummary.push( | shortSummary.push ('±' + substitute (HotCat.messages.short_catchange, [null, changed[0].from]) + arrow | ||
+ substitute (HotCat.messages.short_catchange, [null, changed[0].to])); | |||
} else { | } else { | ||
shortSummary.push( '±' + substitute( | shortSummary.push ('±' + substitute (HotCat.messages.short_catchange, [null, changed[0].from])); | ||
} | } | ||
} else if ( changed.length ) { | } else if (changed.length > 1) { | ||
shortSummary.push( '± ' + multiChangeMsg( changed.length ) ); | shortSummary.push ('± ' + multiChangeMsg (changed.length)); | ||
} | } | ||
if ( summary.length ) { | if (summary.length > 0) { | ||
summary = summary.join( | summary = summary.join (HotCat.messages.separator); | ||
if ( summary.length > 200 - | if (summary.length > 200 - HotCat.messages.prefix.length - HotCat.messages.using.length) { | ||
summary = shortSummary.join (HotCat.messages.separator); | |||
commitForm.wpSummary.value = | } | ||
commitForm.wpSummary.value = HotCat.messages.prefix + summary + HotCat.messages.using; | |||
} | } | ||
} | } | ||
} | } | ||
commitForm.wpTextbox1.value = result.text; | commitForm.wpTextbox1.value = result.text; | ||
commitForm.wpStarttime.value = serverTime || currentTimestamp(); | commitForm.wpStarttime.value = serverTime || currentTimestamp (); | ||
commitForm.wpEdittime.value = pageTime || commitForm.wpStarttime.value; | commitForm.wpEdittime.value = pageTime || commitForm.wpStarttime.value; | ||
if ( selfEditConflict ) commitForm.oldid.value = | if (selfEditConflict) commitForm.oldid.value = "" + (pageTextRevId || conf.wgCurRevisionId); | ||
// Submit the form in a way that triggers onsubmit events: commitForm.submit() doesn't. | // Submit the form in a way that triggers onsubmit events: commitForm.submit() doesn't. | ||
commitForm.hcCommit.click(); | commitForm.hcCommit.click(); | ||
} | } | ||
function resolveOne( page, toResolve ) { | function resolveMulti (toResolve, callback) { | ||
var cats = page.categories | var i; | ||
for (i = 0; i < toResolve.length; i++) { | |||
toResolve[i].dab = null; | |||
toResolve[i].dabInput = toResolve[i].lastInput; | |||
} | |||
if (noSuggestions) { | |||
callback (toResolve); | |||
for ( i = 0; i < toResolve.length; i++ ) { | return; | ||
if ( | } | ||
// 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 | // 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. | // 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].currentHidden = is_hidden; | ||
toResolve[ i ].inputExists = !is_missing; | toResolve[i].inputExists = !is_missing; | ||
toResolve[ i ].icon.src = ( is_missing ? | toResolve[i].icon.src = armorUri(is_missing ? HotCat.existsNo : HotCat.existsYes); | ||
} | } | ||
if ( is_missing ) return; | if (is_missing) return; | ||
if ( !is_redir && cats && ( | if (!is_redir && cats && (HotCat.disambig_category || HotCat.redir_category)) { | ||
for ( var c = 0; c < cats.length; c++ ) { | for (var c = 0; c < cats.length; c++) { | ||
var cat = cats[ c ] | var cat = cats[c]['title']; | ||
// Strip namespace prefix | // Strip namespace prefix | ||
if ( cat ) { | if (cat) { | ||
cat = cat.substring( cat.indexOf( ':' ) + 1 ).replace( /_/g, ' ' ); | cat = cat.substring (cat.indexOf (':') + 1).replace(/_/g, ' '); | ||
if ( cat == | if (cat == HotCat.disambig_category) { | ||
is_dab = true; | is_dab = true; break; | ||
} else if (cat == HotCat.redir_category) { | |||
} else if ( cat == | is_redir = true; break; | ||
is_redir = true; | |||
} | } | ||
} | } | ||
} | } | ||
} | } | ||
if ( !is_redir && !is_dab ) return; | if (!is_redir && !is_dab) return; | ||
if ( !lks || | if (!lks || lks.length === 0) return; | ||
var titles = []; | var titles = []; | ||
for ( i = 0; i < lks.length; i++ ) { | for (i = 0; i < lks.length; i++) { | ||
if ( | 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. | // Internal link to existing thingy. Extract the page name and remove the namespace. | ||
var match = lks[ i ] | var match = lks[i]['title']; | ||
match = match.substring( match.indexOf( ':' ) + 1 ); | match = match.substring (match.indexOf (':') + 1); | ||
// Exclude blacklisted categories. | // Exclude blacklisted categories. | ||
if ( ! | if (!HotCat.blacklist || !HotCat.blacklist.test (match)) { | ||
titles.push (match); | |||
} | |||
} | } | ||
} | } | ||
if (titles.length === 0) { | |||
if ( | |||
return; | 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; | |||
for ( i = 0; i < toResolve.length; i++ ) { | } else { | ||
toResolve[i].text.value = | |||
titles[0] + (toResolve[i].currentKey !== null ? '|' + toResolve[i].currentKey : ""); | |||
if ( | |||
} | } | ||
} | } | ||
} | } | ||
function | function resolveRedirects (toResolve, params) { | ||
if ( ! | if (!params || !params.query || !params.query.pages) return; | ||
for (var p in params.query.pages) resolveOne (params.query.pages[p], toResolve); | |||
} | } | ||
function multiSubmit() { | function multiSubmit () { | ||
var toResolve = []; | var toResolve = []; | ||
for ( var i = 0; i < editors.length; i++ ) | for (var i = 0; i < editors.length; i++) { | ||
if ( editors[ i ].state | if (editors[i].state == CategoryEditor.CHANGE_PENDING || editors[i].state == CategoryEditor.OPEN) | ||
toResolve.push (editors[i]); | |||
if ( | } | ||
initiateEdit( function ( failure ) { | if (toResolve.length === 0) { | ||
initiateEdit (function (failure) {performChanges (failure);}, function (msg) {alert (msg);}); | |||
return; | return; | ||
} | } | ||
resolveMulti( toResolve, function ( resolved ) { | 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 = { | var suggestionEngines = { | ||
opensearch: | opensearch : | ||
uri: '/api.php?format=json&action=opensearch&namespace=14&limit=30&search=Category:$1' | { 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; | |||
return | |||
} | } | ||
} | } | ||
,internalsearch : | |||
{ uri : '/api.php?format=json&action=query&list=allpages&apnamespace=14&aplimit=30&apfrom=$1&apprefix=$1' | |||
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 | } | ||
return titles; | |||
} | |||
return null; | |||
} | } | ||
} | } | ||
,exists : | |||
{ uri : '/api.php?format=json&action=query&prop=info&titles=Category:$1' | |||
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, | |||
uri: '/api.php?format=json&action=query&list=categorymembers&cmtype=subcat&cmlimit=max&cmtitle=Category:$1', | // 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) { | |||
return | 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' | |||
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 = { | 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} | |||
}; | }; | ||
CategoryEditor.UNCHANGED = 0; | function CategoryEditor () { this.initialize.apply (this, arguments); } | ||
CategoryEditor.OPEN = 1; // Open, but no input yet | CategoryEditor.UNCHANGED = 0; | ||
CategoryEditor.OPEN = 1; // Open, but no input yet | |||
CategoryEditor.CHANGE_PENDING = 2; // Open, some input made | CategoryEditor.CHANGE_PENDING = 2; // Open, some input made | ||
CategoryEditor.CHANGED = 3; | CategoryEditor.CHANGED = 3; | ||
CategoryEditor.DELETED = 4; | CategoryEditor.DELETED = 4; | ||
// IE6 sometimes forgets to redraw the list when editors are opened or closed. | // IE6 sometimes forgets to redraw the list when editors are opened or closed. | ||
// Adding/removing a dummy element helps, at least when opening editors. | // Adding/removing a dummy element helps, at least when opening editors. | ||
var dummyElement = make( '\xa0', true ); | var dummyElement = make ('\xa0', true); | ||
function forceRedraw() { | function forceRedraw () { | ||
if ( dummyElement.parentNode ) document.body.removeChild( dummyElement ); else document.body.appendChild( dummyElement ); | 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. | // Event keyCodes that we handle in the text input field/suggestion list. | ||
var BS = 8, | 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 = { | CategoryEditor.prototype = { | ||
initialize: function ( line, span, after, key, is_hidden ) { | 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 | // 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 | // 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. | // known), otherwise it is a boolean indicating whether a bar shall be prepended. | ||
if ( !span ) { | if (!span) { | ||
this.isAddCategory = true; | this.isAddCategory = true; | ||
// Create add span and append to catLinks | // Create add span and append to catLinks | ||
this.originalCategory = | this.originalCategory = ""; | ||
this.originalKey = null; | this.originalKey = null; | ||
this.originalExists = false; | this.originalExists = false; | ||
if ( !newDOM ) { | if (!newDOM) { | ||
span = make( 'span' ); | span = make ('span'); | ||
span.className = 'noprint'; | span.className = 'noprint'; | ||
if ( key ) { | if (key) { | ||
span.appendChild( make( ' | ', true ) ); | span.appendChild (make (' | ', true)); | ||
if ( after ) { | if (after) { | ||
after.parentNode.insertBefore( span, after.nextSibling ); | after.parentNode.insertBefore (span, after.nextSibling); | ||
after = after.nextSibling; | after = after.nextSibling; | ||
} else { | } else { | ||
line.appendChild( span ); | line.appendChild (span); | ||
} | } | ||
} else if ( line.firstChild ) { | } else if (line.firstChild) { | ||
span.appendChild( make( ' ', true ) ); | span.appendChild (make (' ', true)); | ||
line.appendChild( span ); | line.appendChild (span); | ||
} | } | ||
} | } | ||
this.linkSpan = make( 'span' ); | this.linkSpan = make ('span'); | ||
this.linkSpan.className = 'noprint nopopups hotcatlink'; | this.linkSpan.className = 'noprint nopopups hotcatlink'; | ||
var lk = make( 'a' ); | 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); | |||
lk.appendChild( make( | span = make (newDOM ? 'li' : 'span'); | ||
this.linkSpan.appendChild( lk ); | |||
span = make( newDOM ? 'li' : 'span' ); | |||
span.className = 'noprint'; | span.className = 'noprint'; | ||
if ( is_rtl ) span.dir = 'rtl'; | if (is_rtl) span.dir = 'rtl'; | ||
span.appendChild (this.linkSpan); | |||
span.appendChild( this.linkSpan ); | if (after) | ||
if ( after ) after.parentNode.insertBefore( span, after.nextSibling ); else line.appendChild( span ); | after.parentNode.insertBefore (span, after.nextSibling); | ||
else | |||
line.appendChild (span); | |||
this.normalLinks = null; | this.normalLinks = null; | ||
this.undelLink = null; | this.undelLink = null; | ||
this.catLink = null; | this.catLink = null; | ||
} else { | } else { | ||
if ( is_rtl ) span.dir = 'rtl'; | if (is_rtl) span.dir = 'rtl'; | ||
this.isAddCategory = false; | this.isAddCategory = false; | ||
this.catLink = span.firstChild; | this.catLink = span.firstChild; | ||
this.originalCategory = after; | this.originalCategory = after; | ||
this.originalKey = ( key && key.length > 1 ) ? key.substr( 1 ) : null; // > 1 because it includes the leading bar | this.originalKey = (key && key.length > 1) ? key.substr(1) : null; // > 1 because it includes the leading bar | ||
this.originalExists = !hasClass( this.catLink, 'new' ); | this.originalExists = !hasClass (this.catLink, 'new'); | ||
// Create change and del links | // Create change and del links | ||
this.makeLinkSpan(); | this.makeLinkSpan (); | ||
if ( !this.originalExists && this.upDownLinks ) this.upDownLinks.style.display = 'none'; | if (!this.originalExists && this.upDownLinks) this.upDownLinks.style.display = 'none'; | ||
span.appendChild (this.linkSpan); | |||
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; | |||
editors[ editors.length ] = this; | |||
}, | }, | ||
makeLinkSpan: function () { | makeLinkSpan : function () { | ||
this.normalLinks = make( 'span' ); | this.normalLinks = make ('span'); | ||
var lk = null; | var lk = null; | ||
if ( this.originalCategory && this.originalCategory.length ) { | if (this.originalCategory && this.originalCategory.length > 0) { | ||
lk = make( 'a' ); | 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)); | |||
lk.appendChild( make( | this.normalLinks.appendChild (lk); | ||
this.normalLinks.appendChild( make( ' ', true ) ); | |||
this.normalLinks.appendChild( lk ); | |||
} | } | ||
if ( ! | if (!HotCat.template_categories[this.originalCategory]) { | ||
lk = make( 'a' ); | 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)); | |||
lk.appendChild( make( | this.normalLinks.appendChild (lk); | ||
if (!noSuggestions && HotCat.use_up_down) { | |||
this.normalLinks.appendChild( make( ' ', true ) ); | this.upDownLinks = make ('span'); | ||
this.normalLinks.appendChild( lk ); | lk = make ('a'); lk.href = '#catlinks'; lk.onclick = bind (this.down, this); | ||
if ( !noSuggestions && | lk.appendChild (make (HotCat.links.down, true)); lk.title = HotCat.tooltips.down; | ||
this.upDownLinks = make( 'span' ); | this.upDownLinks.appendChild (make (' ', true)); | ||
lk = make( 'a' ); | 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; | |||
lk.appendChild( make( | this.upDownLinks.appendChild (make (' ', true)); | ||
this.upDownLinks.appendChild (lk); | |||
this.upDownLinks.appendChild( make( ' ', true ) ); | this.normalLinks.appendChild (this.upDownLinks); | ||
this.upDownLinks.appendChild( lk ); | |||
lk = make( 'a' ); | |||
lk.appendChild( make( | |||
this.upDownLinks.appendChild( make( ' ', true ) ); | |||
this.upDownLinks.appendChild( lk ); | |||
this.normalLinks.appendChild( this.upDownLinks ); | |||
} | } | ||
} | } | ||
this.linkSpan = make( 'span' ); | this.linkSpan = make ('span'); | ||
this.linkSpan.className = 'noprint nopopups hotcatlink'; | this.linkSpan.className = 'noprint nopopups hotcatlink'; | ||
this.linkSpan.appendChild( this.normalLinks ); | this.linkSpan.appendChild (this.normalLinks); | ||
this.undelLink = make( 'span' ); | this.undelLink = make ('span'); | ||
this.undelLink.className = 'nopopups hotcatlink'; | this.undelLink.className = 'nopopups hotcatlink'; | ||
this.undelLink.style.display = 'none'; | this.undelLink.style.display = 'none'; | ||
lk = make( 'a' ); | 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)); | |||
lk.appendChild( make( | this.undelLink.appendChild (lk); | ||
this.linkSpan.appendChild (this.undelLink); | |||
this.undelLink.appendChild( make( ' ', true ) ); | |||
this.undelLink.appendChild( lk ); | |||
this.linkSpan.appendChild( this.undelLink ); | |||
}, | }, | ||
invokeSuggestions: function ( dont_autocomplete ) { | invokeSuggestions : function (dont_autocomplete) { | ||
if ( this.engine && suggestionConfigs[ this.engine ] && suggestionConfigs[ this.engine ].temp && !dont_autocomplete ) this.engine = | 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; | this.state = CategoryEditor.CHANGE_PENDING; | ||
var self = this; | var self = this; | ||
window.setTimeout( function () { | window.setTimeout (function () {self.textchange (dont_autocomplete);}, HotCat.suggest_delay); | ||
}, | }, | ||
makeForm: function () { | makeForm : function () { | ||
var form = make( 'form' ); | var form = make ('form'); | ||
form.method = 'POST'; | form.method = 'POST'; form.onsubmit = bind (this.accept, this); | ||
this.form = form; | this.form = form; | ||
var self = this; | var self = this; | ||
var text = make( 'input' ); | var text = make ('input'); text.type = 'text'; text.size = HotCat.editbox_width; | ||
if (!noSuggestions) { | |||
if ( !noSuggestions ) { | |||
// Be careful here to handle IME input. This is browser/OS/IME dependent, but basically there are two mechanisms: | // 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 | // - Modern (DOM Level 3) browsers use compositionstart/compositionend events to signal composition; if the | ||
خط ۱٬۵۰۷: | خط ۱٬۴۶۸: | ||
// - Older browsers signal composition by keyDown === IME for the first and subsequent keys for a composition. The | // - 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 | // 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. | // detected by a keyDown IME with a keyUp of space, tab, escape, or return. (Example: IE8) | ||
text.onkeyup = function ( evt ) { | 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 | // And handle continued pressing of arrow keys | ||
text.onkeypress = function ( evt ) { | 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 | // 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. | // 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... | // Therefore, use an IE-specific synchronous event on IE... | ||
// Don't test for text.selectionStart being defined; | // 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. | |||
( text.onbeforedeactivate != | addEvent (text | ||
this.saveView | , (typeof text.onbeforedeactivate != 'undefined' && text.createTextRange) ? 'beforedeactivate' : 'blur' | ||
, bind (this.saveView, this) | |||
); | |||
// DOM Level 3 IME handling | // DOM Level 3 IME handling | ||
try { | try { | ||
// Setting lastKey = IME provides a fake keyDown for Gecko's single keyUp after a cmposition. If we didn't do this, | // 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. | // 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) { | |||
} catch ( any ) { | |||
// Just in case some browsers might produce exceptions with these DOM Level 3 events | // 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.text = text; | ||
this.icon = make( 'img' ); | this.icon = make ('img'); | ||
var list = null; | var list = null; | ||
if ( !noSuggestions ) { | if (!noSuggestions) { | ||
list = make( 'select' ); | list = make ('select'); | ||
list.onclick = function () { | 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.ondblclick = function ( e ) { | list.onkeyup = | ||
function (evt) { | |||
evt = evt || window.event || window.Event; // W3C, IE, Netscape | |||
list.onchange = function () { | if (evt.keyCode === ESC) { | ||
self.resetKeySelection (); | |||
self.text.focus(); | |||
window.setTimeout (function () {self.textchange (true);}, HotCat.suggest_delay); | |||
list.onkeyup = function ( evt ) { | } 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'); | |||
if ( ! | |||
var engineSelector = make( 'select' ); | |||
for ( var key in suggestionConfigs ) { | |||
if ( suggestionConfigs[ key ].show ) { | |||
var opt = make( 'option' ); | |||
opt.value = key; | opt.value = key; | ||
if ( key | if (key == this.engine) opt.selected = true; | ||
opt.appendChild (make (suggestionConfigs[key].name, true)); | |||
opt.appendChild( make( suggestionConfigs[ key ].name, true ) ); | engineSelector.appendChild (opt); | ||
engineSelector.appendChild( opt ); | |||
} | } | ||
} | } | ||
engineSelector.onchange = function () { | 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.engineSelector = engineSelector; | ||
} | } | ||
خط ۱٬۶۴۴: | خط ۱٬۵۸۱: | ||
this.list = list; | this.list = list; | ||
function button_label( id, defaultText ) { | function button_label (id, defaultText) { | ||
var label = null; | var label = null; | ||
if ( | if ( onUpload | ||
&& typeof UFUI != 'undefined' | |||
&& typeof UIElements != 'undefined' | |||
&& typeof UFUI.getLabel == 'function') | |||
{ | |||
try { | try { | ||
label = UFUI.getLabel( id, true ); | label = UFUI.getLabel (id, true); | ||
// Extract the plain text. IE doesn't know that Node.TEXT_NODE === 3 | // Extract the plain text. IE doesn't know that Node.TEXT_NODE === 3 | ||
while ( label && label.nodeType ! | while (label && label.nodeType != 3) label = label.firstChild; | ||
} catch ( ex ) { | } catch (ex) { | ||
label = null; | label = null; | ||
} | } | ||
} | } | ||
if ( !label || !label.data ) return defaultText; | if (!label || !label.data) return defaultText; | ||
return label.data; | return label.data; | ||
} | } | ||
// Do not use type 'submit'; we cannot detect modifier keys if we do | // Do not use type 'submit'; we cannot detect modifier keys if we do | ||
var OK = make( 'input' ); | var OK = make ('input'); OK.type = 'button'; | ||
OK.value = button_label ('wpOkUploadLbl', HotCat.messages.ok); | |||
OK.value = button_label( 'wpOkUploadLbl', | OK.onclick = bind (this.accept, this); | ||
OK.onclick = this.accept | |||
this.ok = OK; | this.ok = OK; | ||
var cancel = make( 'input' ); | var cancel = make ('input'); cancel.type = 'button'; | ||
cancel.value = button_label ('wpCancelUploadLbl', HotCat.messages.cancel); | |||
cancel.value = button_label( 'wpCancelUploadLbl', | cancel.onclick = bind (this.cancel, this); | ||
cancel.onclick = this.cancel | |||
this.cancelButton = cancel; | this.cancelButton = cancel; | ||
var span = make( 'span' ); | var span = make ('span'); | ||
span.className = 'hotcatinput'; | span.className = 'hotcatinput'; | ||
span.style.position = 'relative'; | span.style.position = 'relative'; | ||
span.appendChild( text ); | // 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 | |||
// line as the input field, otherwise, IE8/9 miscalculates the height of the span and | |||
// then the engine selector may overlap the input field. | // then the engine selector may overlap the input field. | ||
span.appendChild( make( '\xa0', true ) ); | span.appendChild (make ('\xa0', true)); | ||
span.style.whiteSpace = 'nowrap'; | span.style.whiteSpace = 'nowrap'; | ||
if ( list ) span.appendChild( list ); | if (list) span.appendChild (list); | ||
if (this.engineSelector) span.appendChild (this.engineSelector); | |||
if ( this.engineSelector ) span.appendChild( this.engineSelector ); | if (!noSuggestions) span.appendChild (this.icon); | ||
span.appendChild (OK); | |||
if ( !noSuggestions ) span.appendChild( this.icon ); | span.appendChild (cancel); | ||
form.appendChild(span); | |||
span.appendChild( OK ); | |||
span.appendChild( cancel ); | |||
form.appendChild( span ); | |||
form.style.display = 'none'; | form.style.display = 'none'; | ||
this.span.appendChild( form ); | this.span.appendChild (form); | ||
}, | }, | ||
display: function ( evt ) { | display : function (evt) { | ||
if ( this.isAddCategory && !onUpload ) { | if (this.isAddCategory && !onUpload) { | ||
var newAdder = new CategoryEditor (this.line, null, this.span, true); // Create a new one | |||
} | } | ||
if ( !commitButton && !onUpload ) { | if (!commitButton && !onUpload) { | ||
for ( var i = 0; i < editors.length; i++ ) { | for (var i = 0; i < editors.length; i++) { | ||
if ( editors[ i ].state ! | if (editors[i].state != CategoryEditor.UNCHANGED) { | ||
setMultiInput(); | setMultiInput(); | ||
break; | break; | ||
خط ۱٬۷۱۶: | خط ۱٬۶۴۷: | ||
} | } | ||
} | } | ||
if ( !this.form ) this.makeForm(); | if (!this.form) { | ||
this.makeForm (); | |||
if ( this.list ) this.list.style.display = 'none'; | } | ||
if (this.list) this.list.style.display = 'none'; | |||
if ( this.engineSelector ) this.engineSelector.style.display = 'none'; | if (this.engineSelector) this.engineSelector.style.display = 'none'; | ||
this.currentCategory = this.lastSavedCategory; | this.currentCategory = this.lastSavedCategory; | ||
this.currentExists = this.lastSavedExists; | this.currentExists = this.lastSavedExists; | ||
this.currentHidden = this.lastSavedHidden; | this.currentHidden = this.lastSavedHidden; | ||
this.currentKey = this.lastSavedKey; | this.currentKey = this.lastSavedKey; | ||
this.icon.src = ( this.currentExists ? | this.icon.src = armorUri(this.currentExists ? HotCat.existsYes : HotCat.existsNo); | ||
this.text.value = this.currentCategory + ( this.currentKey !== null ? '|' + this.currentKey : | this.text.value = this.currentCategory + (this.currentKey !== null ? '|' + this.currentKey : ""); | ||
this.originalState = this.state; | this.originalState = this.state; | ||
this.lastInput = this.currentCategory; | this.lastInput = this.currentCategory; | ||
this.inputExists = this.currentExists; | this.inputExists = this.currentExists; | ||
this.state = this.state | this.state = this.state == CategoryEditor.UNCHANGED ? CategoryEditor.OPEN : CategoryEditor.CHANGE_PENDING; | ||
this.lastSelection = { | this.lastSelection = {start: this.currentCategory.length, end: this.currentCategory.length}; | ||
this.showsList = false; | this.showsList = false; | ||
// Display the form | // Display the form | ||
if ( this.catLink ) this.catLink.style.display = 'none'; | if (this.catLink) this.catLink.style.display = 'none'; | ||
this.linkSpan.style.display = 'none'; | this.linkSpan.style.display = 'none'; | ||
this.form.style.display = 'inline'; | this.form.style.display = 'inline'; | ||
this.ok.disabled = false; | this.ok.disabled = false; | ||
// Kill the event before focussing, otherwise IE will kill the onfocus event! | // Kill the event before focussing, otherwise IE will kill the onfocus event! | ||
var result = evtKill( evt ); | var result = evtKill (evt); | ||
this.text.focus(); | this.text.focus(); | ||
this.text.readOnly = false; | this.text.readOnly = false; | ||
checkMultiInput(); | checkMultiInput (); | ||
return result; | return result; | ||
}, | }, | ||
show: function ( evt, engine, readOnly ) { | show : function (evt, engine, readOnly) { | ||
var result = this.display( evt ); | var result = this.display (evt); | ||
var v = this.lastSavedCategory; | var v = this.lastSavedCategory; | ||
if ( | if (v.length === 0) return result; | ||
this.text.readOnly = !!readOnly; | this.text.readOnly = !!readOnly; | ||
this.engine = engine; | this.engine = engine; | ||
this.textchange( false, true ); // do autocompletion, force display of suggestions | this.textchange (false, true); // do autocompletion, force display of suggestions | ||
forceRedraw(); | forceRedraw (); | ||
return result; | return result; | ||
}, | }, | ||
open: function ( evt ) { | open : function (evt) { | ||
return this.show( evt, ( this.engine && suggestionConfigs[ this.engine ].temp ) ? | return this.show (evt, (this.engine && suggestionConfigs[this.engine].temp) ? HotCat.suggestions : this.engine); | ||
}, | }, | ||
down: function ( evt ) { | down : function (evt) { | ||
return this.show( evt, 'subcat', true ); | return this.show (evt, 'subcat', true); | ||
}, | }, | ||
up: function ( evt ) { | up : function (evt) { | ||
return this.show( evt, 'parentcat' ); | return this.show (evt, 'parentcat'); | ||
}, | }, | ||
cancel: function () { | cancel : function () { | ||
if ( this.isAddCategory && !onUpload ) { | if (this.isAddCategory && !onUpload) { | ||
this.removeEditor(); // We added a new adder when opening | this.removeEditor(); // We added a new adder when opening | ||
return; | return; | ||
خط ۱٬۷۸۳: | خط ۱٬۷۰۸: | ||
this.inactivate(); | this.inactivate(); | ||
this.form.style.display = 'none'; | this.form.style.display = 'none'; | ||
if ( this.catLink ) this.catLink.style.display = | if (this.catLink) this.catLink.style.display = ""; | ||
this.linkSpan.style.display = ""; | |||
this.linkSpan.style.display = | |||
this.state = this.originalState; | this.state = this.originalState; | ||
this.currentCategory = this.lastSavedCategory; | this.currentCategory = this.lastSavedCategory; | ||
this.currentKey = this.lastSavedKey; | this.currentKey = this.lastSavedKey; | ||
this.currentExists = this.lastSavedExists; | this.currentExists = this.lastSavedExists; | ||
this.currentHidden = this.lastSavedHidden; | this.currentHidden = this.lastSavedHidden; | ||
if ( this.catLink ) | if (this.catLink) { | ||
if ( this.currentKey && this.currentKey.length ) { this.catLink.title = this.currentKey; } else { this.catLink.title = | if (this.currentKey && this.currentKey.length > 0) { | ||
this.catLink.title = this.currentKey; | |||
if ( this.state | } else { | ||
if ( this.catLink ) this.catLink.style.backgroundColor = 'transparent'; | this.catLink.title = ""; | ||
} | |||
} | |||
if (this.state == CategoryEditor.UNCHANGED) { | |||
if (this.catLink) this.catLink.style.backgroundColor = 'transparent'; | |||
} else { | } else { | ||
if ( !onUpload ) { | if (!onUpload) { | ||
try { | try { | ||
this.catLink.style.backgroundColor = | this.catLink.style.backgroundColor = HotCat.bg_changed; | ||
} catch ( ex ) {} | } catch (ex) {} | ||
} | } | ||
} | } | ||
checkMultiInput(); | checkMultiInput (); | ||
forceRedraw(); | forceRedraw (); | ||
}, | }, | ||
removeEditor: function () { | removeEditor : function () { | ||
if ( !newDOM ) { | if (!newDOM) { | ||
var next = this.span.nextSibling; | var next = this.span.nextSibling; | ||
if ( next ) next.parentNode.removeChild( next ); | if (next) next.parentNode.removeChild (next); | ||
} | } | ||
this.span.parentNode.removeChild( this.span ); | this.span.parentNode.removeChild (this.span); | ||
for ( var i = 0; i < editors.length; i++ ) { | for (var i = 0; i < editors.length; i++) { | ||
if ( editors[ i ] | if (editors[i] == this) { | ||
editors.splice( i, 1 ); | editors.splice (i, 1); | ||
break; | break; | ||
} | } | ||
} | } | ||
checkMultiInput(); | checkMultiInput (); | ||
var self = this; | |||
window.setTimeout (function () {delete self;}, 10); | |||
}, | }, | ||
rollback: function ( evt ) { | rollback : function (evt) { | ||
this.undoLink.parentNode.removeChild( this.undoLink ); | this.undoLink.parentNode.removeChild (this.undoLink); | ||
this.undoLink = null; | this.undoLink = null; | ||
this.currentCategory = this.originalCategory; | this.currentCategory = this.originalCategory; | ||
خط ۱٬۸۳۴: | خط ۱٬۷۶۴: | ||
this.lastSavedHidden = this.originalHidden; | this.lastSavedHidden = this.originalHidden; | ||
this.state = CategoryEditor.UNCHANGED; | this.state = CategoryEditor.UNCHANGED; | ||
if ( !this.currentCategory || | if (!this.currentCategory || this.currentCategory.length === 0) { | ||
// It was a newly added category. Remove the whole editor. | // It was a newly added category. Remove the whole editor. | ||
this.removeEditor(); | this.removeEditor(); | ||
} else { | } else { | ||
// Redisplay the link... | // Redisplay the link... | ||
this.catLink.removeChild( this.catLink.firstChild ); | this.catLink.removeChild (this.catLink.firstChild); | ||
this.catLink.appendChild( make( this.currentCategory, true ) ); | this.catLink.appendChild (make (this.currentCategory, true)); | ||
this.catLink.href = wikiPagePath( | this.catLink.href = wikiPagePath (HotCat.category_canonical + ':' + this.currentCategory); | ||
this.catLink.title = this.currentKey || | this.catLink.title = this.currentKey || ""; | ||
this.catLink.className = this.currentExists ? | this.catLink.className = this.currentExists ? "" : 'new'; | ||
this.catLink.style.backgroundColor = 'transparent'; | this.catLink.style.backgroundColor = 'transparent'; | ||
if ( this.upDownLinks ) this.upDownLinks.style.display = this.currentExists ? | if (this.upDownLinks) this.upDownLinks.style.display = this.currentExists ? "" : 'none'; | ||
checkMultiInput (); | |||
checkMultiInput(); | |||
} | } | ||
return evtKill( evt ); | return evtKill (evt); | ||
}, | }, | ||
inactivate: function () { | inactivate : function () { | ||
if ( this.list ) this.list.style.display = 'none'; | if (this.list) this.list.style.display = 'none'; | ||
if (this.engineSelector) this.engineSelector.style.display = 'none'; | |||
if ( this.engineSelector ) this.engineSelector.style.display = 'none'; | |||
this.is_active = false; | this.is_active = false; | ||
}, | }, | ||
acceptCheck: function ( dontCheck ) { | acceptCheck : function (dontCheck) { | ||
this.sanitizeInput(); | this.sanitizeInput (); | ||
var value = this.text.value.split( '|' ); | var value = this.text.value.split('|'); | ||
var key = null; | var key = null; | ||
if ( value.length > 1 ) key = value[ 1 ]; | if (value.length > 1) key = value[1]; | ||
var v = value[0].replace(/_/g, ' ').replace(/^\s+|\s+$/g, ""); | |||
var v = value[ 0 ].replace( /_/g, ' ' ).replace( /^\s+|\s+$/g, | if (HotCat.capitalizePageNames) v = capitalize (v); | ||
if ( | |||
this.lastInput = v; | this.lastInput = v; | ||
v = replaceShortcuts( v, | v = replaceShortcuts(v, HotCat.shortcuts); | ||
if ( | if (v.length === 0) { | ||
this.cancel(); | this.cancel (); | ||
return false; | return false; | ||
} | } | ||
if ( !dontCheck && ( | if (!dontCheck | ||
&& ( conf.wgNamespaceNumber === 14 && v == conf.wgTitle | |||
this.cancel(); | || HotCat.blacklist && HotCat.blacklist.test(v)) | ||
) | |||
{ | |||
this.cancel (); | |||
return false; | return false; | ||
} | } | ||
خط ۱٬۸۸۶: | خط ۱٬۸۱۴: | ||
}, | }, | ||
accept: function ( evt ) { | accept : function (evt) { | ||
this.noCommit = (evtKeys (evt) & 1) !== 0; | |||
this.noCommit = ( evtKeys( evt ) & 1 ) !== 0; | var result = evtKill (evt); | ||
var result = evtKill( evt ); | if (this.acceptCheck ()) { | ||
if ( this.acceptCheck() ) { | var toResolve = [this]; | ||
var toResolve = [ this ]; | var original = this.currentCategory; | ||
var original = this.currentCategory; | resolveMulti ( | ||
resolveMulti( toResolve, function ( resolved ) { | 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; | return result; | ||
}, | }, | ||
close: function () { | close : function () { | ||
if ( !this.catLink ) { | if (!this.catLink) { | ||
// Create a catLink | // Create a catLink | ||
this.catLink = make( 'a' ); | this.catLink = make ('a'); | ||
this.catLink.appendChild( make( 'foo', true ) ); | this.catLink.appendChild (make ('foo', true)); | ||
this.catLink.style.display = 'none'; | this.catLink.style.display = 'none'; | ||
this.span.insertBefore( this.catLink, this.span.firstChild.nextSibling ); | this.span.insertBefore (this.catLink, this.span.firstChild.nextSibling); | ||
} | } | ||
this.catLink.removeChild( this.catLink.firstChild ); | this.catLink.removeChild (this.catLink.firstChild); | ||
this.catLink.appendChild( make( this.currentCategory, true ) ); | this.catLink.appendChild (make (this.currentCategory, true)); | ||
this.catLink.href = wikiPagePath( | this.catLink.href = wikiPagePath (HotCat.category_canonical + ':' + this.currentCategory); | ||
this.catLink.className = this.currentExists ? | this.catLink.className = this.currentExists ? "" : 'new'; | ||
this.lastSavedCategory = this.currentCategory; | this.lastSavedCategory = this.currentCategory; | ||
this.lastSavedKey = this.currentKey; | this.lastSavedKey = this.currentKey; | ||
this.lastSavedExists = this.currentExists; | this.lastSavedExists = this.currentExists; | ||
this.lastSavedHidden = this.currentHidden; | this.lastSavedHidden = this.currentHidden; | ||
// Close form and redisplay category | // Close form and redisplay category | ||
this.inactivate(); | this.inactivate(); | ||
this.form.style.display = 'none'; | this.form.style.display = 'none'; | ||
this.catLink.title = this.currentKey || | this.catLink.title = this.currentKey || ""; | ||
this.catLink.style.display = | this.catLink.style.display = ""; | ||
if ( this.isAddCategory ) { | if (this.isAddCategory) { | ||
if ( onUpload ) { | if (onUpload) { | ||
var newAdder = new CategoryEditor (this.line, null, this.span, true); // Create a new one | |||
} | } | ||
this.isAddCategory = false; | this.isAddCategory = false; | ||
this.linkSpan.parentNode.removeChild( this.linkSpan ); | this.linkSpan.parentNode.removeChild (this.linkSpan); | ||
this.makeLinkSpan(); | this.makeLinkSpan (); | ||
this.span.appendChild( this.linkSpan ); | this.span.appendChild (this.linkSpan); | ||
} | } | ||
if ( !this.undoLink ) { | if (!this.undoLink) { | ||
// Append an undo link. | // Append an undo link. | ||
var span = make( 'span' ); | var span = make ('span'); | ||
var lk = make( 'a' ); | 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)); | |||
lk.appendChild( make( | span.appendChild (lk); | ||
this.normalLinks.appendChild (span); | |||
span.appendChild( make( ' ', true ) ); | |||
span.appendChild( lk ); | |||
this.normalLinks.appendChild( span ); | |||
this.undoLink = span; | this.undoLink = span; | ||
if ( !onUpload ) { | if (!onUpload) { | ||
try { | try { | ||
this.catLink.style.backgroundColor = | this.catLink.style.backgroundColor = HotCat.bg_changed; | ||
} catch ( ex ) {} | } catch (ex) {} | ||
} | } | ||
} | } | ||
if ( this.upDownLinks ) this.upDownLinks.style.display = this.lastSavedExists ? | if (this.upDownLinks) this.upDownLinks.style.display = this.lastSavedExists ? "" : 'none'; | ||
this.linkSpan.style.display = ""; | |||
this.linkSpan.style.display = | |||
this.state = CategoryEditor.CHANGED; | this.state = CategoryEditor.CHANGED; | ||
checkMultiInput(); | checkMultiInput (); | ||
forceRedraw(); | forceRedraw (); | ||
}, | }, | ||
commit: function () { | commit : function (comment) { | ||
// Check again to catch problem cases after redirect resolution | // Check again to catch problem cases after redirect resolution | ||
if ( | 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 (); | |||
this.cancel(); | |||
return; | return; | ||
} | } | ||
if ( commitButton || onUpload ) { | if (commitButton || onUpload) { | ||
this.close(); | this.close (); | ||
} else { | } else { | ||
this.close(); | this.close (); | ||
var self = this; | var self = this; | ||
initiateEdit( function ( failure ) { | initiateEdit (function (failure) {performChanges (failure, self);}, function (msg) {alert (msg);}); | ||
} | } | ||
}, | }, | ||
remove: function ( evt ) { | remove : function (evt) { | ||
this.doRemove (evtKeys (evt) & 1); | |||
this.doRemove( evtKeys( evt ) & 1 ); | return evtKill (evt); | ||
return evtKill( evt ); | |||
}, | }, | ||
doRemove: function ( noCommit ) { | doRemove : function (noCommit) { | ||
if ( this.isAddCategory ) { // Empty input on adding a new category | if (this.isAddCategory) { // Empty input on adding a new category | ||
this.cancel(); | this.cancel (); | ||
return; | return; | ||
} | } | ||
if ( !commitButton && !onUpload ) { | if (!commitButton && !onUpload) { | ||
for ( var i = 0; i < editors.length; i++ ) { | for (var i = 0; i < editors.length; i++) { | ||
if ( editors[ i ].state ! | if (editors[i].state != CategoryEditor.UNCHANGED) { | ||
setMultiInput(); | setMultiInput(); | ||
break; | break; | ||
خط ۲٬۰۱۴: | خط ۱٬۹۳۳: | ||
} | } | ||
} | } | ||
if ( commitButton ) { | if (commitButton) { | ||
this.catLink.title = | this.catLink.title = ""; | ||
this.catLink.style.cssText += '; text-decoration : line-through !important;'; | this.catLink.style.cssText += '; text-decoration : line-through !important;'; | ||
try { | try { | ||
this.catLink.style.backgroundColor = | this.catLink.style.backgroundColor = HotCat.bg_changed; | ||
} catch ( ex ) {} | } catch (ex) {} | ||
this.originalState = this.state; | this.originalState = this.state; | ||
this.state = CategoryEditor.DELETED; | this.state = CategoryEditor.DELETED; | ||
this.normalLinks.style.display = 'none'; | this.normalLinks.style.display = 'none'; | ||
this.undelLink.style.display = | this.undelLink.style.display = ""; | ||
checkMultiInput(); | checkMultiInput (); | ||
} else { | } else { | ||
if ( onUpload ) { | if (onUpload) { | ||
// Remove this editor completely | // Remove this editor completely | ||
this.removeEditor(); | this.removeEditor (); | ||
} else { | } else { | ||
this.originalState = this.state; | this.originalState = this.state; | ||
this.state = CategoryEditor.DELETED; | this.state = CategoryEditor.DELETED; | ||
this.noCommit = noCommit || | this.noCommit = noCommit || HotCat.del_needs_diff; | ||
var self = this; | var self = this; | ||
initiateEdit( | initiateEdit (function (failure) {performChanges (failure, self);}, function (msg) {self.state = self.originalState; alert (msg);}); | ||
} | } | ||
} | } | ||
}, | }, | ||
restore: function ( evt ) { | restore : function (evt) { | ||
// Can occur only if we do have a commit button and are not on the upload form | // Can occur only if we do have a commit button and are not on the upload form | ||
this.catLink.title = this.currentKey || | this.catLink.title = this.currentKey || ""; | ||
this.catLink.style.textDecoration = | this.catLink.style.textDecoration = ""; | ||
this.state = this.originalState; | this.state = this.originalState; | ||
if ( this.state | if (this.state == CategoryEditor.UNCHANGED) { | ||
this.catLink.style.backgroundColor = 'transparent'; | this.catLink.style.backgroundColor = 'transparent'; | ||
} else { | } else { | ||
try { | try { | ||
this.catLink.style.backgroundColor = | this.catLink.style.backgroundColor = HotCat.bg_changed; | ||
} catch ( ex ) {} | } catch (ex) {} | ||
} | } | ||
this.normalLinks.style.display = | this.normalLinks.style.display = ""; | ||
this.undelLink.style.display = 'none'; | this.undelLink.style.display = 'none'; | ||
checkMultiInput(); | checkMultiInput (); | ||
return evtKill( evt ); | return evtKill (evt); | ||
}, | }, | ||
// Internal operations | // Internal operations | ||
selectEngine: function ( engineName ) { | selectEngine : function (engineName) { | ||
if ( !this.engineSelector ) return; | if (!this.engineSelector) return; | ||
for ( var i = 0; i < this.engineSelector.options.length; i++ ) this.engineSelector.options[ i ].selected = this.engineSelector.options[ i ].value | for (var i = 0; i < this.engineSelector.options.length; i++) { | ||
this.engineSelector.options[i].selected = this.engineSelector.options[i].value == engineName; | |||
} | |||
}, | }, | ||
sanitizeInput: function () { | sanitizeInput : function () { | ||
var v = this.text.value || | var v = this.text.value || ""; | ||
v = v.replace( /^(\s|_)+/, | v = v.replace(/^(\s|_)+/, ""); // Trim leading blanks and underscores | ||
var re = new RegExp( '^(' + | var re = new RegExp ('^(' + HotCat.category_regexp + '):'); | ||
if ( re.test( v ) ) v = v.substring( v.indexOf( ':' ) + 1 ).replace( /^(\s|_)+/, | if (re.test (v)) { | ||
v = v.substring (v.indexOf (':') + 1).replace(/^(\s|_)+/, ""); | |||
if ( | } | ||
if (HotCat.capitalizePageNames) v = capitalize (v); | |||
// Only update the input field if there is a difference. | // Only update the input field if there is a difference. IE8 appears to reset the selection | ||
// reset | // and place the cursor at the front upon reset, which makes our autocompletetion become a | ||
if ( this.text.value !== null && this.text.value ! | // 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 ) { | makeCall : function (url, callbackObj, engine, queryKey, cleanKey) { | ||
var cb = callbackObj | var cb = callbackObj; | ||
var e = engine; | |||
var v = queryKey; | |||
var z = cleanKey; | |||
var thisObj = this; | |||
function done() { | function done () { | ||
cb.callsMade++; | cb.callsMade++; | ||
if ( cb.callsMade === cb.nofCalls ) { | if (cb.callsMade === cb.nofCalls) { | ||
if ( cb.exists ) cb.allTitles.exists = true; | if (cb.exists) cb.allTitles.exists = true; | ||
if (cb.normalized) cb.allTitles.normalized = cb.normalized; | |||
if ( cb.normalized ) cb.allTitles.normalized = cb.normalized; | if (!cb.dontCache && !suggestionConfigs[cb.engineName].cache[z]) { | ||
suggestionConfigs[cb.engineName].cache[z] = cb.allTitles; | |||
if ( !cb.dontCache && !suggestionConfigs[ cb.engineName ].cache[ z ] ) suggestionConfigs[ cb.engineName ].cache[ z ] = cb.allTitles; | } | ||
thisObj.text.readOnly = false; | thisObj.text.readOnly = false; | ||
if ( !cb.cancelled ) thisObj.showSuggestions( cb.allTitles, cb.noCompletion, v, cb.engineName ); | if (!cb.cancelled) thisObj.showSuggestions (cb.allTitles, cb.noCompletion, v, cb.engineName); | ||
if (cb === thisObj.callbackObj) thisObj.callbackObj = null; | |||
if ( cb === thisObj.callbackObj ) thisObj.callbackObj = null; | delete cb; | ||
cb | |||
} | } | ||
} | } | ||
getJSON ({ | |||
var titles = e.handler( json, z ); | uri : url | ||
if ( titles && titles.length ) { | ,success : function (json) { | ||
if ( cb.allTitles === null ) cb.allTitles = titles; else cb.allTitles = cb.allTitles.concat( titles ); | var titles = e.handler (json, z); | ||
if ( titles.exists ) cb.exists = true; | if (titles && titles.length > 0) { | ||
if ( titles.normalized ) cb.normalized = titles.normalized; | 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(); | done(); | ||
} | |||
,error : function (req) {if (!req) noSuggestions = true; cb.dontCache = true; done(); } | |||
}); | |||
} ); | |||
}, | }, | ||
callbackObj: null, | callbackObj : null, | ||
textchange: function ( dont_autocomplete, force ) { | textchange : function (dont_autocomplete, force) { | ||
// Hide all other lists | // Hide all other lists | ||
makeActive( this ); | makeActive (this); | ||
// Get input value, omit sort key, if any | // Get input value, omit sort key, if any | ||
this.sanitizeInput(); | this.sanitizeInput (); | ||
var v = this.text.value; | var v = this.text.value; | ||
// Disregard anything after a pipe. | // Disregard anything after a pipe. | ||
var pipe = v.indexOf( '|' ); | var pipe = v.indexOf ('|'); | ||
if ( pipe >= 0 ) { | if (pipe >= 0) { | ||
this.currentKey = v.substring( pipe + 1 ); | this.currentKey = v.substring (pipe+1); | ||
v = v.substring( 0, pipe ); | v = v.substring (0, pipe); | ||
} else { | } else { | ||
this.currentKey = null; | this.currentKey = null; | ||
} | } | ||
if ( this.lastInput | if (this.lastInput == v && !force) return; // No change | ||
if ( this.lastInput ! | if (this.lastInput != v) checkMultiInput (); | ||
this.lastInput = v; | this.lastInput = v; | ||
this.lastRealInput = v; | this.lastRealInput = v; | ||
// Mark blacklisted inputs. | // Mark blacklisted inputs. | ||
this.ok.disabled = v.length && | this.ok.disabled = v.length > 0 && HotCat.blacklist && HotCat.blacklist.test (v); | ||
if ( | if (noSuggestions) { | ||
this. | // 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; | return; | ||
} | } | ||
if ( this. | 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; } | |||
var engineName = suggestionConfigs[ this.engine ] ? this.engine : 'combined'; | if (this.callbackObj) this.callbackObj.cancelled = true; | ||
var engineName = suggestionConfigs[this.engine] ? this.engine : 'combined'; | |||
dont_autocomplete = dont_autocomplete || suggestionConfigs[ engineName ].noCompletion; | dont_autocomplete = dont_autocomplete || suggestionConfigs[engineName].noCompletion; | ||
if ( suggestionConfigs[ engineName ].cache[ cleanKey ] ) { | if (suggestionConfigs[engineName].cache[cleanKey]) { | ||
this.showSuggestions( suggestionConfigs[ engineName ].cache[ cleanKey ], dont_autocomplete, v, engineName ); | this.showSuggestions (suggestionConfigs[engineName].cache[cleanKey], dont_autocomplete, v, engineName); | ||
return; | return; | ||
} | } | ||
var engines = suggestionConfigs[ engineName ].engines; | var engines = suggestionConfigs[engineName].engines; | ||
this.callbackObj = | this.callbackObj = | ||
allTitles: null, | {allTitles: null, callsMade: 0, nofCalls: engines.length, noCompletion: dont_autocomplete, engineName: engineName}; | ||
this.makeCalls (engines, this.callbackObj, v, cleanKey); | |||
this.makeCalls( engines, this.callbackObj, v, cleanKey ); | |||
}, | }, | ||
makeCalls: function ( engines, cb, v, cleanKey ) { | makeCalls : function (engines, cb, v, cleanKey) { | ||
for ( var j = 0; j < engines.length; j++ ) { | for (var j = 0; j < engines.length; j++) { | ||
var engine = suggestionEngines[ engines[ j ] ]; | var engine = suggestionEngines[engines[j]]; | ||
var url = conf.wgServer + conf.wgScriptPath + engine.uri.replace( /\$1/g, encodeURIComponent( cleanKey ) ); | var url = conf.wgServer + conf.wgScriptPath + engine.uri.replace (/\$1/g, encodeURIComponent (cleanKey)); | ||
this.makeCall( url, cb, engine, v, cleanKey ); | this.makeCall (url, cb, engine, v, cleanKey); | ||
} | } | ||
}, | }, | ||
showSuggestions: function ( titles, dontAutocomplete, queryKey, engineName ) { | showSuggestions : function (titles, dontAutocomplete, queryKey, engineName) { | ||
this.text.readOnly = false; | this.text.readOnly = false; | ||
this.dab = null; | this.dab = null; | ||
this.showsList = false; | this.showsList = false; | ||
if ( !this.list ) return; | if (!this.list) return; | ||
if ( noSuggestions ) { | if (noSuggestions) { | ||
if ( this.list ) this.list.style.display = 'none'; | if (this.list) this.list.style.display = 'none'; | ||
if (this.engineSelector) this.engineSelector.style.display = 'none'; | |||
if ( this.engineSelector ) this.engineSelector.style.display = 'none'; | if (this.icon) this.icon.style.display = 'none'; | ||
if ( this.icon ) this.icon.style.display = 'none'; | |||
this.inputExists = true; // Default... | this.inputExists = true; // Default... | ||
return; | return; | ||
} | } | ||
this.engineName = engineName; | this.engineName = engineName; | ||
if ( engineName ) { | if (engineName) { | ||
if ( !this.engineSelector ) this.engineName = null; | if (!this.engineSelector) this.engineName = null; | ||
} else { | } else { | ||
if ( this.engineSelector ) this.engineSelector.style.display = 'none'; | if (this.engineSelector) this.engineSelector.style.display = 'none'; | ||
} | } | ||
if ( queryKey ) { | if (queryKey) { | ||
if ( this.lastInput.indexOf( queryKey ) ) return; | if (this.lastInput.indexOf (queryKey) !== 0) return; | ||
if ( this.lastQuery && this.lastInput.indexOf( this.lastQuery ) === 0 && this.lastQuery.length > queryKey.length ) return; | if (this.lastQuery && this.lastInput.indexOf (this.lastQuery) === 0 && this.lastQuery.length > queryKey.length) | ||
return; | |||
} | } | ||
this.lastQuery = queryKey; | this.lastQuery = queryKey; | ||
// Get current input text | // Get current input text | ||
var v = this.text.value.split( '|' ); | var v = this.text.value.split('|'); | ||
var key = v.length > 1 ? '|' + v[ 1 ] : | var key = v.length > 1 ? '|' + v[1] : ""; | ||
v = ( | v = (HotCat.capitalizePageNames ? capitalize (v[0]) : v[0]); | ||
var vNormalized = v; | var vNormalized = v; | ||
var knownToExist = titles && titles.exists; | var knownToExist = titles && titles.exists; | ||
var i; | var i; | ||
if ( titles ) { | if (titles) { | ||
if ( titles.normalized && v.indexOf( queryKey ) === 0 ) { | 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 ); | vNormalized = titles.normalized + v.substring(queryKey.length); | ||
} | } | ||
var vLow = vNormalized.toLowerCase(); | var vLow = vNormalized.toLowerCase (); | ||
// Strip blacklisted categories | // Strip blacklisted categories | ||
if ( | if (HotCat.blacklist) { | ||
for ( i = 0; i < titles.length; i++ ) { | for (i = 0; i < titles.length; i++) { | ||
if ( | if (HotCat.blacklist.test (titles[i])) { | ||
titles.splice( i, 1 ); | titles.splice(i, 1); | ||
i--; | i--; | ||
} | } | ||
} | } | ||
} | } | ||
titles.sort( | titles.sort ( | ||
function ( a, b ) { | function (a, b) { | ||
if ( a | if (a == b) return 0; | ||
if (a.indexOf (b) === 0) return 1; // a begins with b: a > b | |||
if ( a.indexOf( b ) === 0 ) return 1; | if (b.indexOf (a) === 0) return -1; // b begins with a: a < b | ||
if ( b.indexOf( a ) === 0 ) return -1; | |||
// Opensearch may return stuff not beginning with the search prefix! | // Opensearch may return stuff not beginning with the search prefix! | ||
var prefixMatchA = ( a.indexOf( vNormalized ) === 0 ? 1 : 0 ); | var prefixMatchA = (a.indexOf (vNormalized) === 0 ? 1 : 0); | ||
var prefixMatchB = ( b.indexOf( vNormalized ) === 0 ? 1 : 0 ); | var prefixMatchB = (b.indexOf (vNormalized) === 0 ? 1 : 0); | ||
if ( prefixMatchA ! | if (prefixMatchA != prefixMatchB) return prefixMatchB - prefixMatchA; | ||
// Case-insensitive prefix match! | // Case-insensitive prefix match! | ||
var aLow = a.toLowerCase(), | var aLow = a.toLowerCase(), bLow = b.toLowerCase(); | ||
prefixMatchA = (aLow.indexOf (vLow) === 0 ? 1 : 0); | |||
prefixMatchA = ( aLow.indexOf( vLow ) === 0 ? 1 : 0 ); | prefixMatchB = (bLow.indexOf (vLow) === 0 ? 1 : 0); | ||
prefixMatchB = ( bLow.indexOf( vLow ) === 0 ? 1 : 0 ); | if (prefixMatchA != prefixMatchB) return prefixMatchB - prefixMatchA; | ||
if ( prefixMatchA ! | if (a < b) return -1; | ||
if (b < a) return 1; | |||
if ( a < b ) return -1; | |||
if ( b < a ) return 1; | |||
return 0; | return 0; | ||
} ); | } | ||
); | |||
// Remove duplicates and self-references | // Remove duplicates and self-references | ||
for ( i = 0; i < titles.length; i++ ) { | for (i = 0; i < titles.length; i++) { | ||
if ( | if ( i+1 < titles.length && titles[i] == titles[i+1] | ||
|| conf.wgNamespaceNumber == 14 && titles[i] == conf.wgTitle | |||
) | |||
{ | |||
titles.splice( i, 1 ); | titles.splice (i, 1); | ||
i--; | i--; | ||
} | } | ||
} | } | ||
} | } | ||
if ( !titles || | if (!titles || titles.length === 0) { | ||
if ( this.list ) this.list.style.display = 'none'; | if (this.list) this.list.style.display = 'none'; | ||
if (this.engineSelector) this.engineSelector.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); | |||
if ( engineName && suggestionConfigs[ engineName ] && !suggestionConfigs[ engineName ].temp ) { | |||
if ( this.icon ) this.icon.src = | |||
this.inputExists = false; | this.inputExists = false; | ||
} | } | ||
خط ۲٬۲۹۷: | خط ۲٬۱۸۹: | ||
} | } | ||
var firstTitle = titles[ 0 ]; | var firstTitle = titles[0]; | ||
var completed = this.autoComplete( firstTitle, v, vNormalized, key, dontAutocomplete ); | var completed = this.autoComplete (firstTitle, v, vNormalized, key, dontAutocomplete); | ||
var existing = completed || knownToExist || firstTitle | var existing = completed || knownToExist || firstTitle == replaceShortcuts(v, HotCat.shortcuts); | ||
if ( engineName && suggestionConfigs[ engineName ] && !suggestionConfigs[ engineName ].temp ) { | if (engineName && suggestionConfigs[engineName] && !suggestionConfigs[engineName].temp) { | ||
this.icon.src = ( existing ? | this.icon.src = armorUri(existing ? HotCat.existsYes : HotCat.existsNo); | ||
this.inputExists = existing; | this.inputExists = existing; | ||
} | } | ||
if ( completed ) { | if (completed) { | ||
this.lastInput = firstTitle; | this.lastInput = firstTitle; | ||
if ( titles.length === 1 ) { | if (titles.length === 1) { | ||
this.list.style.display = 'none'; | this.list.style.display = 'none'; | ||
if ( this.engineSelector ) this.engineSelector.style.display = 'none'; | if (this.engineSelector) this.engineSelector.style.display = 'none'; | ||
return; | return; | ||
} | } | ||
} | } | ||
// (Re-)fill the list | // (Re-)fill the list | ||
while ( this.list.firstChild ) this.list.removeChild( this.list.firstChild ); | while (this.list.firstChild) this.list.removeChild (this.list.firstChild); | ||
for (i = 0 ; i < titles.length ; i++) { | |||
for ( i = 0; i < titles.length; i++ ) { | var opt = make ('option') ; | ||
var opt = make( 'option' ); | opt.appendChild (make (titles[i], true)); | ||
opt.appendChild( make( titles[ i ], true ) ); | opt.selected = completed && (i === 0); | ||
opt.selected = completed && ( i === 0 ); | this.list.appendChild (opt); | ||
this.list.appendChild( opt ); | |||
} | } | ||
this.displayList(); | this.displayList(); | ||
}, | }, | ||
displayList: function () { | displayList : function () { | ||
this.showsList = true; | this.showsList = true; | ||
if ( !this.is_active ) { | if (!this.is_active) { | ||
this.list.style.display = 'none'; | this.list.style.display = 'none'; | ||
if ( this.engineSelector ) this.engineSelector.style.display = 'none'; | if (this.engineSelector) this.engineSelector.style.display = 'none'; | ||
return; | return; | ||
} | } | ||
var nofItems = ( this.list.options.length > | var nofItems = (this.list.options.length > HotCat.list_size ? HotCat.list_size : this.list.options.length); | ||
if ( nofItems <= 1 ) nofItems = 2; | if (nofItems <= 1) nofItems = 2; | ||
this.list.size = nofItems; | this.list.size = nofItems; | ||
this.list.style.align = is_rtl ? 'right' : 'left'; | this.list.style.align = is_rtl ? 'right' : 'left'; | ||
this.list.style.zIndex = 5; | this.list.style.zIndex = 5; | ||
this.list.style.position = 'absolute'; | this.list.style.position = 'absolute'; | ||
// Compute initial list position. First the height. | // Compute initial list position. First the height. | ||
var anchor = is_rtl ? 'right' : 'left'; | var anchor = is_rtl ? 'right' : 'left'; | ||
var listh = 0; | var listh = 0; | ||
if ( this.list.style.display | if (this.list.style.display == 'none') { | ||
// Off-screen display to get the height | // Off-screen display to get the height | ||
this.list.style.top = this.text.offsetTop + 'px'; | this.list.style.top = this.text.offsetTop + 'px'; | ||
this.list.style[ anchor ] = '-10000px'; | this.list.style[anchor] = '-10000px'; | ||
this.list.style.display = | this.list.style.display = ""; | ||
listh = this.list.offsetHeight; | listh = this.list.offsetHeight; | ||
this.list.style.display = 'none'; | this.list.style.display = 'none'; | ||
خط ۲٬۳۵۵: | خط ۲٬۲۴۳: | ||
// Approximate calculation of maximum list size | // Approximate calculation of maximum list size | ||
var maxListHeight = listh; | var maxListHeight = listh; | ||
if ( nofItems < | if (nofItems < HotCat.list_size) maxListHeight = (listh / nofItems) * HotCat.list_size; | ||
function viewport( what ) { | function viewport (what) { | ||
if ( is_webkit && !document.evaluate ) | if (is_webkit && !document.evaluate) | ||
return window['inner' + what]; // Safari < 3.0 | |||
return window[ 'inner' + what ]; | |||
var s = 'client' + what; | var s = 'client' + what; | ||
if ( window.opera ) return document.body[ s ]; | if (window.opera) return document.body[s]; | ||
return (document.documentElement ? document.documentElement[s] : 0) | |||
return ( document.documentElement ? document.documentElement[ s ] : 0 ) || document.body[ s ] || 0; | || document.body[s] || 0; | ||
} | } | ||
function scroll_offset( what ) { | function scroll_offset (what) { | ||
var s = 'scroll' + what; | var s = 'scroll' + what; | ||
var result = ( document.documentElement ? document.documentElement[ s ] : 0 ) || document.body[ s ] || 0; | var result = (document.documentElement ? document.documentElement[s] : 0) | ||
if ( is_rtl && what | || document.body[s] || 0; | ||
if (is_rtl && what == 'Left') { | |||
// RTL inconsistencies. | // RTL inconsistencies. | ||
// FF: 0 at the far right, then increasingly negative values. | // FF: 0 at the far right, then increasingly negative values. | ||
// IE >= 8: 0 at the far right, then increasingly positive values. | // IE >= 8: 0 at the far right, then increasingly positive values. | ||
// Webkit: scrollWidth - clientWidth at the far right, then down to zero. | // 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... | // Opera: don't know... | ||
if ( result < 0 ) result = -result; | if (result < 0) result = - result; | ||
if (!is_webkit && !is_ie_lt8) { | |||
if ( !is_webkit ) result = scroll_offset( 'Width' ) - viewport( 'Width' ) - result; | result = scroll_offset('Width') - viewport('Width') - result; | ||
} | |||
// Now all have webkit behavior, i.e. zero if at the leftmost edge. | // Now all have webkit behavior, i.e. zero if at the leftmost edge. | ||
} | } | ||
return result; | return result; | ||
} | } | ||
function position( node ) { | function position (node) { | ||
// Stripped-down simplified position function. It's good enough for our purposes. | // Stripped-down simplified position function. It's good enough for our purposes. | ||
if ( node.getBoundingClientRect ) { | if (node.getBoundingClientRect) { | ||
var box = node.getBoundingClientRect(); | var box = node.getBoundingClientRect (); | ||
return { | return { x : Math.round (box.left + scroll_offset ('Left')) | ||
,y : Math.round (box.top + scroll_offset ('Top')) | |||
}; | |||
} | } | ||
var t = 0, | var t = 0, l = 0; | ||
do { | do { | ||
t + | t = t + (node.offsetTop || 0); | ||
l + | l = l + (node.offsetLeft || 0); | ||
node = node.offsetParent; | node = node.offsetParent; | ||
} while ( node ); | } while (node); | ||
return { | return {x : l, y : t}; | ||
} | } | ||
var textPos = position( this.text ) | 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 ) { | if (this.engineName) { | ||
this.engineSelector.style.zIndex = 5; | this.engineSelector.style.zIndex = 5; | ||
this.engineSelector.style.position = 'absolute'; | this.engineSelector.style.position = 'absolute'; | ||
this.engineSelector.style.width = textBoxWidth + 'px'; | this.engineSelector.style.width = textBoxWidth + 'px'; | ||
// Figure out the height of this selector: display it off-screen, then hide it again. | // Figure out the height of this selector: display it off-screen, then hide it again. | ||
if ( this.engineSelector.style.display | if (this.engineSelector.style.display == 'none') { | ||
this.engineSelector.style[ anchor ] = '-10000px'; | this.engineSelector.style[anchor] = '-10000px'; | ||
this.engineSelector.style.top = ' | this.engineSelector.style.top = '0px'; | ||
this.engineSelector.style.display = | this.engineSelector.style.display = ""; | ||
offset = this.engineSelector.offsetHeight; | offset = this.engineSelector.offsetHeight; | ||
this.engineSelector.style.display = 'none'; | this.engineSelector.style.display = 'none'; | ||
خط ۲٬۴۲۶: | خط ۲٬۳۰۹: | ||
offset = this.engineSelector.offsetHeight; | offset = this.engineSelector.offsetHeight; | ||
} | } | ||
this.engineSelector.style[ anchor ] = nl + 'px'; | this.engineSelector.style[anchor] = nl + 'px'; | ||
} | } | ||
if ( textPos.y < maxListHeight + offset + 1 ) { | 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; | nt = this.text.offsetHeight + offset + 1; | ||
if ( this.engineName ) this.engineSelector.style.top = this.text.offsetHeight + 'px'; | if (this.engineName) this.engineSelector.style.top = this.text.offsetHeight + 'px'; | ||
} else { | } else { | ||
nt = -listh - offset - 1; | nt = - listh - offset - 1; | ||
if ( this.engineName ) this.engineSelector.style.top = -( offset + 1 ) + 'px'; | if (this.engineName) this.engineSelector.style.top = - (offset + 1) + 'px'; | ||
} | } | ||
this.list.style.top = nt + 'px'; | this.list.style.top = nt + 'px'; | ||
this.list.style.width = | this.list.style.width = ""; // No fixed width (yet) | ||
this.list.style[ anchor ] = nl + 'px'; | this.list.style[anchor] = nl + 'px'; | ||
if ( this.engineName ) { | if (this.engineName) { | ||
this.selectEngine( this.engineName ); | this.selectEngine (this.engineName); | ||
this.engineSelector.style.display = | this.engineSelector.style.display = ""; | ||
} | } | ||
this.list.style.display = 'block'; | this.list.style.display = 'block'; | ||
// Set the width of the list | // Set the width of the list | ||
if ( this.list.offsetWidth < textBoxWidth ) { | if (this.list.offsetWidth < textBoxWidth ) { | ||
this.list.style.width = textBoxWidth + 'px'; | this.list.style.width = textBoxWidth + 'px'; | ||
return; | return; | ||
} | } | ||
// If the list is wider than the textbox: make sure it fits horizontally into the browser window | // If the list is wider than the textbox: make sure it fits horizontally into the browser window | ||
var scroll = scroll_offset( 'Left' ); | var scroll = scroll_offset ('Left'); | ||
var view_w = viewport( 'Width' ); | var view_w = viewport ('Width'); | ||
var w = this.list.offsetWidth; | var w = this.list.offsetWidth; | ||
var l_pos = position( this.list ); | var l_pos = position (this.list); | ||
var left = l_pos.x; | var left = l_pos.x; | ||
var right = left + w; | var right = left + w; | ||
if ( left < scroll || right > scroll + view_w ) { | if (left < scroll || right > scroll + view_w) { | ||
if ( w > view_w ) { | if (w > view_w) { | ||
w = view_w; | w = view_w; | ||
this.list.style.width = w + 'px'; | this.list.style.width = w + 'px'; | ||
if ( is_rtl ) left = right - w; else right = left + w; | if (is_rtl) { | ||
left = right - w; | |||
} else { | |||
right = left + w; | |||
} | |||
} | } | ||
var relative_offset = 0; | var relative_offset = 0; | ||
if ( left < scroll ) relative_offset = scroll - left; else if ( right > scroll + view_w ) relative_offset = -( right - scroll - view_w ); | if (left < scroll) { | ||
relative_offset = scroll - left; | |||
if ( is_rtl ) relative_offset = -relative_offset; | } else if (right > scroll + view_w) { | ||
relative_offset = - (right - scroll - view_w); | |||
if ( relative_offset ) this.list.style[ anchor ] = ( nl + relative_offset ) + 'px'; | } | ||
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 ) { | autoComplete : function (newVal, actVal, normalizedActVal, key, dontModify) { | ||
if ( newVal | if (newVal == actVal) return true; | ||
if (dontModify || this.ime || !this.canSelect()) return false; | |||
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 we can't select properly or an IME composition is ongoing, autocompletion would be a major annoyance to the user. | ||
if ( newVal.indexOf( actVal ) ) { | if (newVal.indexOf (actVal) !== 0) { | ||
// Maybe it'll work with the normalized value (NFC)? | // Maybe it'll work with the normalized value (NFC)? | ||
if ( normalizedActVal && newVal.indexOf( normalizedActVal ) === 0 ) { | if (normalizedActVal && newVal.indexOf(normalizedActVal) === 0) { | ||
if ( this.lastRealInput | if (this.lastRealInput == actVal) this.lastRealInput = normalizedActVal; | ||
actVal = normalizedActVal; | actVal = normalizedActVal; | ||
} else { | } else { | ||
خط ۲٬۴۹۲: | خط ۲٬۳۸۰: | ||
this.text.focus(); | this.text.focus(); | ||
this.text.value = newVal + key; | this.text.value = newVal + key; | ||
this.setSelection( actVal.length, newVal.length ); | this.setSelection (actVal.length, newVal.length); | ||
return true; | return true; | ||
}, | }, | ||
canSelect: function () { | canSelect : function () { | ||
return this.text.setSelectionRange || | return this.text.setSelectionRange | ||
|| this.text.createTextRange | |||
|| typeof this.text.selectionStart != 'undefined' | |||
&& typeof this.text.selectionEnd != 'undefined'; | |||
}, | }, | ||
setSelection: function ( from, to ) { | setSelection : function (from, to) { | ||
// this.text must be focused (at least on IE) | // this.text must be focused (at least on IE) | ||
if ( !this.text.value ) return; | if (!this.text.value) return; | ||
if ( this.text.setSelectionRange ) { // e.g. khtml | if (this.text.setSelectionRange) { // e.g. khtml | ||
this.text.setSelectionRange( from, to ); | this.text.setSelectionRange (from, to); | ||
} else if ( this.text.selectionStart != | } else if (typeof this.text.selectionStart != 'undefined') { | ||
if ( from > this.text.selectionStart ) { | if (from > this.text.selectionStart) { | ||
this.text.selectionEnd = to; | this.text.selectionEnd = to; | ||
this.text.selectionStart = from; | this.text.selectionStart = from; | ||
} else { | } else { | ||
this.text.selectionStart = from; | this.text.selectionStart = from; | ||
this.text.selectionEnd = to; | this.text.selectionEnd = to; | ||
} | } | ||
} else if ( this.text.createTextRange ) { // IE | } else if (this.text.createTextRange) { // IE | ||
var new_selection = this.text.createTextRange(); | var new_selection = this.text.createTextRange(); | ||
new_selection.move( 'character', from ); | new_selection.move ('character', from); | ||
new_selection.moveEnd( 'character', to - from ); | new_selection.moveEnd ('character', to - from); | ||
new_selection.select(); | new_selection.select(); | ||
} | } | ||
}, | }, | ||
getSelection: function () { | getSelection : function () { | ||
var from = 0, | var from = 0, to = 0; | ||
// this.text must be focused (at least on IE) | // this.text must be focused (at least on IE) | ||
if ( !this.text.value ) { | if (!this.text.value) { | ||
// No text. | // No text. | ||
} else if ( this.text.selectionStart != | } else if (typeof this.text.selectionStart != 'undefined') { | ||
from = this.text.selectionStart; | from = this.text.selectionStart; | ||
to = this.text.selectionEnd; | to = this.text.selectionEnd; | ||
} else if ( document.selection && document.selection.createRange ) { // IE | } else if (document.selection && document.selection.createRange) { // IE | ||
var rng = document.selection.createRange().duplicate(); | var rng = document.selection.createRange().duplicate(); | ||
if ( rng.parentElement() === this.text ) { | if (rng.parentElement() === this.text) { | ||
try { | try { | ||
var textRng = this.text.createTextRange(); | var textRng = this.text.createTextRange(); | ||
textRng.move( 'character', 0 ); | textRng.move('character', 0); | ||
textRng.setEndPoint( 'EndToEnd', rng ); | textRng.setEndPoint('EndToEnd', rng); | ||
// We're in a single-line input box: no need to care about IE's strange | // We're in a single-line input box: no need to care about IE's strange | ||
// handling of line ends | // handling of line ends | ||
to = textRng.text.length; | to = textRng.text.length; | ||
textRng.setEndPoint( 'EndToStart', rng ); | textRng.setEndPoint('EndToStart', rng); | ||
from = textRng.text.length; | from = textRng.text.length; | ||
} catch ( notFocused ) { | } catch (notFocused) { | ||
from = this.text.value.length; | from = this.text.value.length; to = from; // At end of text | ||
} | } | ||
} | } | ||
} | } | ||
return { | return {start: from, end: to}; | ||
}, | }, | ||
saveView: function () { | saveView : function (evt) { | ||
this.lastSelection = this.getSelection(); | this.lastSelection = this.getSelection (); | ||
}, | }, | ||
processKey: function ( evt ) { | processKey : function (evt) { | ||
var dir = 0; | var dir = 0; | ||
switch ( this.lastKey ) { | switch (this.lastKey) { | ||
case UP: | case UP: dir = -1; | ||
case DOWN: if (dir === 0) dir = 1; | |||
case PGUP: if (dir === 0) dir = -HotCat.list_size; | |||
case DOWN: | case PGDOWN: if (dir === 0) dir = HotCat.list_size; | ||
if (this.list.style.display != 'none') { | |||
// List is visible, so there are suggestions | |||
case PGUP: | 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. | |||
case PGDOWN: | return evtKill (evt); | ||
dir = | } 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; | break; | ||
case ESC: // Inhibit default behavior (revert to last real input in FF: we do that ourselves) | case ESC: // Inhibit default behavior (revert to last real input in FF: we do that ourselves) | ||
return evtKill( evt ); | return evtKill (evt); | ||
} | } | ||
return true; | return true; | ||
}, | }, | ||
highlightSuggestion: function ( dir ) { | highlightSuggestion : function (dir) { | ||
if ( noSuggestions || !this.list || this.list.style.display | if (noSuggestions || !this.list || this.list.style.display == 'none') return false; | ||
var curr = this.list.selectedIndex; | var curr = this.list.selectedIndex; | ||
var tgt = -1; | var tgt = -1; | ||
if ( dir === 0 ) { | if (dir === 0) { | ||
if ( curr < 0 || curr >= this.list.options.length ) return false; | if (curr < 0 || curr >= this.list.options.length) return false; | ||
tgt = curr; | tgt = curr; | ||
} else { | } else { | ||
tgt = curr < 0 ? 0 : curr + dir; | tgt = curr < 0 ? 0 : curr + dir; | ||
tgt = tgt < 0 ? 0 : tgt; | tgt = tgt < 0 ? 0 : tgt; | ||
if ( tgt >= this.list.options.length ) tgt = this.list.options.length - 1; | if (tgt >= this.list.options.length) tgt = this.list.options.length - 1; | ||
} | } | ||
if ( tgt ! | if (tgt != curr || dir === 0) { | ||
if ( curr >= 0 && curr < this.list.options.length && dir !== 0 ) this.list.options[ curr ].selected = false; | if (curr >= 0 && curr < this.list.options.length && dir !== 0) this.list.options[curr].selected = false; | ||
this.list.options[tgt].selected = true; | |||
this.list.options[ tgt ].selected = true; | |||
// Get current input text | // Get current input text | ||
var v = this.text.value.split( '|' ); | var v = this.text.value.split('|'); | ||
var key = v.length > 1 ? '|' + v[ 1 ] : | var key = v.length > 1 ? '|' + v[1] : ""; | ||
var completed = this.autoComplete( this.list.options[ tgt ].text, this.lastRealInput, null, key, false ); | var completed = this.autoComplete (this.list.options[tgt].text, this.lastRealInput, null, key, false); | ||
if ( !completed || this.list.options[ tgt ].text | if (!completed || this.list.options[tgt].text == this.lastRealInput) { | ||
this.text.value = this.list.options[ tgt ].text + key; | 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 ); | 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.lastInput = this.list.options[tgt].text; | ||
this.inputExists = true; // Might be wrong if from a dab list... | this.inputExists = true; // Might be wrong if from a dab list... | ||
if ( this.icon ) this.icon.src = | if (this.icon) this.icon.src = armorUri(HotCat.existsYes); | ||
this.state = CategoryEditor.CHANGE_PENDING; | this.state = CategoryEditor.CHANGE_PENDING; | ||
} | } | ||
خط ۲٬۶۳۲: | خط ۲٬۵۰۲: | ||
}, | }, | ||
resetKeySelection: function () { | resetKeySelection : function () { | ||
if ( noSuggestions || !this.list || this.list.style.display | if (noSuggestions || !this.list || this.list.style.display == 'none') return false; | ||
var curr = this.list.selectedIndex; | var curr = this.list.selectedIndex; | ||
if ( curr >= 0 && curr < this.list.options.length ) { | if (curr >= 0 && curr < this.list.options.length) { | ||
this.list.options[ curr ].selected = false; | this.list.options[curr].selected = false; | ||
// Get current input text | // Get current input text | ||
var v = this.text.value.split( '|' ); | var v = this.text.value.split('|'); | ||
var key = v.length > 1 ? '|' + v[ 1 ] : | var key = v.length > 1 ? '|' + v[1] : ""; | ||
// ESC is handled strangely by some browsers (e.g., FF); somehow it resets the input value before | // 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. | // our event handlers ever get a chance to run. | ||
var result = v[ 0 ] ! | var result = v[0] != this.lastInput; | ||
if ( v[ 0 ] ! | if (v[0] != this.lastRealInput) { | ||
this.text.value = this.lastRealInput + key; | this.text.value = this.lastRealInput + key; | ||
result = true; | result = true; | ||
خط ۲٬۶۵۳: | خط ۲٬۵۲۲: | ||
return false; | return false; | ||
} | } | ||
}; // end CategoryEditor.prototype | }; // end CategoryEditor.prototype | ||
function initialize() { | function initialize () { | ||
// User configurations. Do this here, called from the onload handler, so that users can | // 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 | // override it easily in their own user script files by just declaring variables. JSconfig | ||
// is some feature used at Wikimedia Commons. | // is some feature used at Wikimedia Commons. | ||
var config = ( | 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 | |||
) | |||
); | |||
if ( typeof | 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]; | |||
if ( | |||
} | } | ||
} | } | ||
} | } | ||
// Catch both native RTL and "faked" RTL through [[MediaWiki:Rtl.js]] | // Catch both native RTL and "faked" RTL through [[MediaWiki:Rtl.js]] | ||
is_rtl = hasClass( document.body, 'rtl' ); | is_rtl = hasClass (document.body, 'rtl'); | ||
if ( !is_rtl ) { | if (!is_rtl) { | ||
if ( document.defaultView && document.defaultView.getComputedStyle ) { // Gecko etc. | if (document.defaultView && document.defaultView.getComputedStyle) { // Gecko etc. | ||
is_rtl = document.defaultView.getComputedStyle( document.body, null ).getPropertyValue( 'direction' ); | is_rtl = document.defaultView.getComputedStyle (document.body, null).getPropertyValue ('direction'); | ||
} else if ( document.body.currentStyle ) { // IE, has subtle differences to getComputedStyle | } else if (document.body.currentStyle) { // IE, has subtle differences to getComputedStyle | ||
is_rtl = document.body.currentStyle | is_rtl = document.body.currentStyle['direction']; | ||
} else { // Not exactly right, but best effort | } else { // Not exactly right, but best effort | ||
is_rtl = document.body.style | is_rtl = document.body.style['direction']; | ||
} | } | ||
is_rtl = ( is_rtl | is_rtl = (is_rtl == 'rtl'); | ||
} | } | ||
} | } | ||
function can_edit() { | function can_edit () { | ||
var container = null; | var container = null; | ||
switch ( mw.config.get( 'skin' ) ) { | switch (mw.config.get('skin')) { | ||
case 'cologneblue': | case 'cologneblue': | ||
container = document.getElementById( 'quickbar' ); | container = document.getElementById ('quickbar'); | ||
// Fall through | |||
case 'standard': | case 'standard': | ||
case 'nostalgia': | case 'nostalgia': | ||
if ( !container ) container = document.getElementById( 'topbar' ); | if (!container) container = document.getElementById ('topbar'); | ||
var lks = container.getElementsByTagName( 'a' ); | var lks = container.getElementsByTagName ('a'); | ||
for ( var i = 0; i < lks.length; i++ ) { | for (var i = 0; i < lks.length; i++) { | ||
if ( | if ( param ('title', lks[i].href) == conf.wgPageName | ||
&& param ('action', lks[i].href) == 'edit') | |||
return true; | return true; | ||
} | } | ||
return false; | return false; | ||
default: | default: | ||
// all modern skins: | // all modern skins: | ||
return document.getElementById( 'ca-edit' ) !== null; | return document.getElementById ('ca-edit') !== null; | ||
} | } | ||
return false; | |||
} | } | ||
function setup_upload() { | function setup_upload () { | ||
onUpload = true; | onUpload = true; | ||
// Add an empty category bar at the end of the table containing the description, and change the onsubmit handler. | // 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' ); | var ip = document.getElementById ('mw-htmlform-description') || document.getElementById ('wpDestFile'); | ||
if ( !ip ) { | if (!ip) { | ||
ip = document.getElementById( 'wpDestFile' ); | ip = document.getElementById ('wpDestFile'); | ||
while ( ip && ip.nodeName.toLowerCase() ! | while (ip && ip.nodeName.toLowerCase() != 'table') ip = ip.parentNode; | ||
} | } | ||
if ( !ip ) return; | if (!ip) return; | ||
var reupload = document.getElementById( 'wpForReUpload' ); | var reupload = document.getElementById ('wpForReUpload'); | ||
var destFile = document.getElementById( 'wpDestFile' ); | var destFile = document.getElementById ('wpDestFile'); | ||
if ( | if ( (reupload && !!reupload.value) | ||
|| (destFile && (destFile.disabled || destFile.readOnly))) | |||
return; // re-upload form... | return; // re-upload form... | ||
// Insert a table row with two fields (label and empty category bar) | // Insert a table row with two fields (label and empty category bar) | ||
var labelCell = make( 'td' ); | var labelCell = make ('td'); | ||
var lineCell = make( 'td' ); | var lineCell = make ('td'); | ||
// Create the category line | // Create the category line | ||
catLine = make( 'div' ); | catLine = make ('div'); | ||
catLine.className = 'catlinks'; | catLine.className = 'catlinks'; | ||
catLine.id = 'catlinks'; | catLine.id = 'catlinks'; | ||
خط ۲٬۸۷۱: | خط ۲٬۶۶۹: | ||
catLine.style.margin = '0'; | catLine.style.margin = '0'; | ||
catLine.style.border = 'none'; | catLine.style.border = 'none'; | ||
lineCell.appendChild( catLine ); | lineCell.appendChild (catLine); | ||
// Create the label | // Create the label | ||
var label = null; | var label = null; | ||
if ( | if ( typeof UFUI != 'undefined' | ||
&& typeof UIElements != 'undefined' | |||
&& typeof UFUI.getLabel == 'function' | |||
) | |||
{ | |||
try { | try { | ||
label = UFUI.getLabel( 'wpCategoriesUploadLbl' ); | label = UFUI.getLabel('wpCategoriesUploadLbl'); | ||
} catch ( ex ) { | } catch (ex) { | ||
label = null; | label = null; | ||
} | } | ||
} | } | ||
if ( !label ) { | if (!label) { | ||
labelCell.id = 'hotcatLabel'; | labelCell.id = 'hotcatLabel'; | ||
labelCell.appendChild( make( | labelCell.appendChild (make (HotCat.categories, true)); | ||
} else { | } else { | ||
labelCell.id = 'hotcatLabelTranslated'; | labelCell.id = 'hotcatLabelTranslated'; | ||
labelCell.appendChild( label ); | labelCell.appendChild (label); | ||
} | } | ||
labelCell.className = 'mw-label'; | labelCell.className = 'mw-label'; | ||
labelCell.style.textAlign = 'right'; | labelCell.style.textAlign = 'right'; | ||
labelCell.style.verticalAlign = 'middle'; | labelCell.style.verticalAlign = 'middle'; | ||
// Change the onsubmit handler | // Change the onsubmit handler | ||
var form = document.getElementById( 'upload' ) || document.getElementById( 'mw-upload-form' ); | var form = document.getElementById('upload') || document.getElementById('mw-upload-form'); | ||
if ( form ) { | if (form) { | ||
var newRow = ip.insertRow( -1 ); | var newRow = ip.insertRow (-1); | ||
newRow.appendChild( labelCell ); | newRow.appendChild (labelCell); | ||
newRow.appendChild( lineCell ); | newRow.appendChild (lineCell); | ||
form.onsubmit = ( function ( oldSubmit ) { | form.onsubmit = (function (oldSubmit) { | ||
return function () { | return function () { | ||
var do_submit = true; | var do_submit = true; | ||
if ( oldSubmit ) { | if (oldSubmit) { | ||
if ( typeof oldSubmit | if (typeof oldSubmit == 'string') | ||
do_submit = eval (oldSubmit); | |||
do_submit = eval( oldSubmit ); | else if (typeof oldSubmit == 'function') | ||
do_submit = oldSubmit.apply (form, arguments); | |||
do_submit = oldSubmit.apply( form, arguments ); | |||
} | } | ||
if ( !do_submit ) return false; | if (!do_submit) return false; | ||
closeForm(); | closeForm (); | ||
// Copy the categories | // Copy the categories | ||
var eb = document.getElementById( 'wpUploadDescription' ) || document.getElementById( 'wpDesc' ); | var eb = document.getElementById ('wpUploadDescription') | ||
|| document.getElementById ('wpDesc'); | |||
var addedOne = false; | var addedOne = false; | ||
for ( var i = 0; i < editors.length; i++ ) { | for (var i = 0; i < editors.length; i++) { | ||
var t = editors[ i ].currentCategory; | var t = editors[i].currentCategory; | ||
if ( !t ) continue; | if (!t) continue ; | ||
var key = editors[ i ].currentKey; | var key = editors[i].currentKey; | ||
var new_cat = '[[' + | var new_cat = '[[' + HotCat.category_canonical + ':' + t + (key ? '|' + key : "") + ']]'; | ||
// Only add if not already present | // Only add if not already present | ||
var cleanedText = eb.value | var cleanedText = eb.value | ||
.replace(/<\!--(\s|\S)*?--\>/g, "") | |||
.replace(/<nowiki\>(\s|\S)*?<\/nowiki>/g, ""); | |||
if ( !find_category( cleanedText, t, true ) ) { | if (!find_category (cleanedText, t, true)) { | ||
eb.value += '\n' + new_cat; | eb.value += '\n' + new_cat; | ||
addedOne = true; | addedOne = true; | ||
} | } | ||
} | } | ||
if ( addedOne ) { | if (addedOne) { | ||
// Remove "subst:unc" added by Flinfo if it didn't find categories | |||
eb.value = eb.value.replace( /\{\{subst:unc\}\}/g, | eb.value = eb.value.replace(/\{\{subst:unc\}\}/g, ""); | ||
} | } | ||
return true; | return true; | ||
}; | }; | ||
}( form.onsubmit | }) (form.onsubmit); | ||
} | } | ||
} | } | ||
خط ۲٬۹۳۹: | خط ۲٬۷۴۰: | ||
var cleanedText = null; | var cleanedText = null; | ||
function isOnPage( span ) { | function isOnPage (span) { | ||
var catTitle = title (span.firstChild.getAttribute ('href', 2)); | |||
if (!catTitle) return null; | |||
var catTitle = title( span.firstChild.getAttribute( 'href' ) ); | catTitle = catTitle.substr (catTitle.indexOf (':') + 1).replace (/_/g, ' '); | ||
if ( !catTitle ) return null; | if (HotCat.blacklist && HotCat.blacklist.test (catTitle)) return null; | ||
var result = { title : catTitle, match : ["", "", ""] }; | |||
catTitle = catTitle.substr( catTitle.indexOf( ':' ) + 1 ).replace( /_/g, ' ' ); | if (pageText === null) return result; | ||
if ( | if (cleanedText === null) { | ||
var result = { | |||
if ( pageText === null ) return result; | |||
if ( cleanedText === null ) { | |||
cleanedText = pageText | cleanedText = pageText | ||
.replace( /<!--(\s|\S)*?-->/g, | .replace(/<\!--(\s|\S)*?--\>/g, "") | ||
.replace( /<nowiki>(\s|\S)*?<\/nowiki>/g, | .replace(/<nowiki\>(\s|\S)*?<\/nowiki>/g, ""); | ||
} | } | ||
result.match = find_category( cleanedText, catTitle, true ); | result.match = find_category (cleanedText, catTitle, true); | ||
return result; | return result; | ||
} | } | ||
خط ۲٬۹۶۶: | خط ۲٬۷۵۹: | ||
var setupTimeout = null; | var setupTimeout = null; | ||
function findByClass( scope, tag, className ) { | function findByClass (scope, tag, className) { | ||
var result = | // Compatibility routine. Uses jQuery if available, otherwise works with older getElementsByClassName | ||
return ( result && result.length ) ? result[ 0 ] : null; | 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 ) { | function setup (additionalWork) { | ||
if ( initialized ) return; | if (initialized) return; | ||
initialized = true; | initialized = true; | ||
if ( setupTimeout ) { | if (setupTimeout) { | ||
window.clearTimeout( setupTimeout ); | window.clearTimeout (setupTimeout); | ||
setupTimeout = null; | setupTimeout = null; | ||
} | } | ||
// Find the category bar, or create an empty one if there isn't one. Then add -/+- links after | // Find the category bar, or create an empty one if there isn't one. Then add -/+- links after | ||
// each category, and add the + link. | // each category, and add the + link. | ||
catLine = | 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'); | |||
var hiddenCats = document.getElementById( 'mw-hidden-catlinks' ); | if (!catLine) { | ||
if ( !catLine ) { | |||
var footer = null; | var footer = null; | ||
if ( !hiddenCats ) { | if (!hiddenCats) { | ||
footer = findByClass( document, 'div', 'printfooter' ); | footer = findByClass (document , 'div' , 'printfooter'); | ||
if ( !footer ) return; // Don't know where to insert the category line | if (!footer) return; // Don't know where to insert the category line | ||
} | } | ||
catLine = make( 'div' ); | catLine = make ('div'); | ||
catLine.id = 'mw-normal-catlinks'; | catLine.id = 'mw-normal-catlinks'; | ||
catLine.style.textAlign = is_rtl ? 'right' : 'left'; | catLine.style.textAlign = is_rtl ? 'right' : 'left'; | ||
// Add a label | // Add a label | ||
var label = make( 'a' ); | var label = make ('a'); | ||
label.href = conf.wgArticlePath.replace( '$1', 'Special:Categories' ); | label.href = conf.wgArticlePath.replace ('$1', 'Special:Categories'); | ||
label.title = | label.title = HotCat.categories; | ||
label.appendChild( make( | label.appendChild (make (HotCat.categories, true)); | ||
catLine.appendChild( label ); | catLine.appendChild (label); | ||
catLine.appendChild( make( ':', true ) ); | catLine.appendChild (make (':', true)); | ||
// Insert the new category line | // Insert the new category line | ||
var container = ( hiddenCats ? hiddenCats.parentNode : document.getElementById( 'catlinks' ) ); | var container = (hiddenCats ? hiddenCats.parentNode : document.getElementById ('catlinks')); | ||
if ( !container ) { | if (!container) { | ||
container = make( 'div' ); | container = make ('div'); | ||
container.id = 'catlinks'; | container.id = 'catlinks'; | ||
footer.parentNode.insertBefore( container, footer.nextSibling ); | footer.parentNode.insertBefore (container, footer.nextSibling); | ||
} | } | ||
container.className = 'catlinks noprint'; | container.className = 'catlinks noprint'; | ||
container.style.display = | container.style.display = ""; | ||
if ( !hiddenCats ) container.appendChild( catLine ); else container.insertBefore( catLine, hiddenCats ); | if (!hiddenCats) { | ||
container.appendChild (catLine); | |||
} else { | |||
container.insertBefore (catLine, hiddenCats); | |||
} | |||
} // end if catLine exists | } // end if catLine exists | ||
if ( is_rtl ) catLine.dir = 'rtl'; | if (is_rtl) catLine.dir = 'rtl'; | ||
// Create editors for all existing categories | // Create editors for all existing categories | ||
function createEditors( line, is_hidden ) { | function createEditors (line, is_hidden) { | ||
var i; | var i; | ||
var cats = line.getElementsByTagName( 'li' ); | var cats = line.getElementsByTagName ('li'); | ||
if ( cats.length ) { | if (cats.length > 0) { | ||
newDOM = true; | newDOM = true; line = cats[0].parentNode; | ||
} else { | } else { | ||
cats = line.getElementsByTagName( 'span' ); | cats = line.getElementsByTagName ('span'); | ||
} | } | ||
// Copy cats, otherwise it'll also magically contain our added spans as it is a live collection! | // Copy cats, otherwise it'll also magically contain our added spans as it is a live collection! | ||
var copyCats = new Array( cats.length ); | var copyCats = new Array (cats.length); | ||
for ( i = 0; i < cats.length; i++ ) copyCats[ i ] = cats[ i ]; | for (i = 0; i < cats.length; i++) copyCats[i] = cats[i]; | ||
for ( i = 0; i < copyCats.length; i++ ) { | var editor = null; | ||
var test = isOnPage( copyCats[ i ] ); | for (i = 0; i < copyCats.length; i++) { | ||
if ( test !== null && test.match !== null ) { | var test = isOnPage (copyCats[i]); | ||
if (test !== null && test.match !== null) { | |||
new CategoryEditor( line, copyCats[ i ], test.title, test.match[ 2 ], is_hidden ); | editor = new CategoryEditor (line, copyCats[i], test.title, test.match[2], is_hidden); | ||
} | } | ||
} | } | ||
return copyCats.length ? copyCats[ copyCats.length - 1 ] : null; | return copyCats.length > 0 ? copyCats[copyCats.length-1] : null; | ||
} | } | ||
var lastSpan = createEditors( catLine, false ); | var lastSpan = createEditors (catLine, false); | ||
// Create one to add a new category | // 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 ( !onUpload ) { | if (pageText !== null && hiddenCats) { | ||
if ( pageText !== null && hiddenCats ) { | if (is_rtl) hiddenCats.dir = 'rtl'; | ||
if ( is_rtl ) hiddenCats.dir = 'rtl'; | createEditors (hiddenCats, true); | ||
createEditors( hiddenCats, true ); | |||
} | } | ||
// And finally add the "multi-mode" span. (Do this at the end, otherwise it ends up in the list above.) | // And finally add the "multi-mode" span. (Do this at the end, otherwise it ends up in the list above.) | ||
var enableMulti = make( 'span' ); | var enableMulti = make ('span'); | ||
enableMulti.className = 'noprint'; | enableMulti.className = 'noprint'; | ||
if ( is_rtl ) enableMulti.dir = 'rtl'; | if (is_rtl) enableMulti.dir = 'rtl'; | ||
catLine.insertBefore( enableMulti, catLine.firstChild.nextSibling ); | catLine.insertBefore (enableMulti, catLine.firstChild.nextSibling); | ||
enableMulti.appendChild( make( '\xa0', true ) ); // nbsp | enableMulti.appendChild (make ('\xa0', true)); // nbsp | ||
multiSpan = make( 'span' ); | multiSpan = make ('span'); | ||
enableMulti.appendChild( multiSpan ); | enableMulti.appendChild (multiSpan); | ||
multiSpan.innerHTML = '(<a>' + | multiSpan.innerHTML = '(<a>' + HotCat.addmulti + '</a>)'; | ||
var lk = multiSpan.getElementsByTagName( 'a' )[ 0 ]; | var lk = multiSpan.getElementsByTagName ('a')[0]; | ||
lk.onclick = function ( evt ) { | lk.onclick = function (evt) {setMultiInput (); checkMultiInput (); return evtKill (evt);}; | ||
lk.title = HotCat.multi_tooltip; | |||
lk.title = | |||
lk.style.cursor = 'pointer'; | lk.style.cursor = 'pointer'; | ||
} | } | ||
cleanedText = null; | cleanedText = null; | ||
if ( additionalWork | 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() { | function createCommitForm () { | ||
if ( commitForm ) return; | if (commitForm) return; | ||
var formContainer = make( 'div' ); | var formContainer = make ('div'); | ||
formContainer.style.display = 'none'; | formContainer.style.display = 'none'; | ||
document.body.appendChild( formContainer ); | document.body.appendChild (formContainer); | ||
formContainer.innerHTML = | formContainer.innerHTML = | ||
'<form id="hotcatCommitForm" method="post" enctype="multipart/form-data" action="' | '<form id="hotcatCommitForm" method="post" enctype="multipart/form-data" action="' | ||
conf.wgScript + '?title=' + encodeURIComponent( conf.wgPageName ) + '&action= | + conf.wgScript + '?title=' + htmlEscape(encodeURIComponent (conf.wgPageName)) | ||
'<input type="hidden" name="wpTextbox1">' | + '&action=edit">' | ||
'<input type="hidden" name="model" value="wikitext">' | + '<input type="hidden" name="wpTextbox1" />' | ||
'<input type="hidden" name="format" value="text/x-wiki">' | + '<input type="hidden" name="model" value="wikitext" />' | ||
'<input type="hidden" name="wpSummary" value="">' | + '<input type="hidden" name="format" value="text/x-wiki" />' | ||
'<input type="checkbox" name="wpMinoredit" value="1">' | + '<input type="hidden" name="wpSummary" value="" />' | ||
'<input type="checkbox" name="wpWatchthis" value="1">' | + '<input type="checkbox" name="wpMinoredit" value="1" />' | ||
'<input type="hidden" name="wpAutoSummary" value=" | + '<input type="checkbox" name="wpWatchthis" value="1" />' | ||
'<input type="hidden" name="wpEdittime">' | + '<input type="hidden" name="wpAutoSummary" value="" />' | ||
'<input type="hidden" name="wpStarttime">' | + '<input type="hidden" name="wpEdittime" />' | ||
'<input type="hidden" name="wpDiff" value="wpDiff">' | + '<input type="hidden" name="wpStarttime" />' | ||
'<input type="hidden" name="oldid" value="0">' | + '<input type="hidden" name="wpDiff" value="wpDiff" />' | ||
'<input type="submit" name="hcCommit" value="hcCommit">' | + '<input type="hidden" name="oldid" value="0" />' | ||
'<input type="hidden" name="wpEditToken">' | + '<input type="submit" name="hcCommit" value="hcCommit" />' | ||
'<input type="hidden" name="wpUltimateParam" value="1">' | + '<input type="hidden" name="wpEditToken" />' | ||
+ '<input type="hidden" name="wpUltimateParam" value="1" />' | |||
+ '<input type="hidden" value="ℳ𝒲♥𝓊𝓃𝒾𝒸ℴ𝒹ℯ" name="wpUnicodeCheck" />' | |||
'</form>'; | + '</form>'; | ||
commitForm = document.getElementById( 'hotcatCommitForm' ); | commitForm = document.getElementById ('hotcatCommitForm'); | ||
} | } | ||
function getPage() { | function getPage () { | ||
// We know we have an article here. | // We know we have an article here. | ||
if ( | if (conf.wgArticleId === 0) { | ||
// Doesn't exist yet. Disable on non-existing User pages -- might be a global user page. | // Doesn't exist yet. | ||
if (conf.wgNamespaceNumber === 2) { | |||
pageText = | // Disable on non-existing User pages -- might be a global user page. | ||
return; | |||
} | |||
pageText = ""; | |||
pageTime = null; | pageTime = null; | ||
setup( createCommitForm ); | setup (createCommitForm); | ||
} else { | } else { | ||
var url = conf.wgServer + conf.wgScriptPath + '/api.php?format=json&callback=HotCat.start&action=query&rawcontinue=&titles=' + | var url = conf.wgServer + conf.wgScriptPath + '/api.php?format=json&callback=HotCat.start&action=query&rawcontinue=&titles=' | ||
+ encodeURIComponent (conf.wgPageName) | |||
+ '&prop=info%7Crevisions&rvprop=content%7Ctimestamp%7Cids&meta=siteinfo&rvlimit=1&rvstartid=' | |||
+ conf.wgCurRevisionId; | |||
var s = make( 'script' ); | var s = make ('script'); | ||
s.src = url; | 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. | |||
document.getElementsByTagName( 'head' )[ 0 ].appendChild( s ); | |||
setupTimeout = window.setTimeout( function () { | |||
} | } | ||
} | } | ||
function | 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 ( | 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() { | function getState () { | ||
var result = null; | var result = null; | ||
for ( var i = 0; i < editors.length; i++ ) { | for (var i = 0; i < editors.length; i++) { | ||
var text = editors[ i ].currentCategory; | var text = editors[i].currentCategory; | ||
var key = editors[ i ].currentKey; | var key = editors[i].currentKey; | ||
if ( text && text.length ) { | if (text && text.length > 0) { | ||
if ( key !== null ) text += '|' + key; | if (key !== null) text += '|' + key; | ||
if ( result === null ) result = text; else result + | if (result === null) | ||
result = text; | |||
else | |||
result = result + '\n' + text; | |||
} | } | ||
} | } | ||
خط ۳٬۱۸۰: | خط ۳٬۰۳۷: | ||
} | } | ||
function | function setState (state) { | ||
var cats = state.split ('\n'); | |||
if (cats.length === 0) return null; | |||
if ( | 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; | |||
if ( | var i; | ||
for (i = 0; i < cats.length; i++) { | |||
if (cats[i].length === 0) continue; | |||
if ( | 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 | // Export legacy functions | ||
window.hotcat_get_state = function () { | window.hotcat_get_state = function () { return getState(); }; | ||
window.hotcat_set_state = function (state) { return setState (state); }; | |||
window.hotcat_close_form = function () { closeForm (); }; | |||
window.hotcat_set_state = function ( state ) { | |||
window.hotcat_close_form = function () { | |||
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; | // 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. | // 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('.'); | ||
mw. | 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. | ||
catLine = null; | // 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); | ||
if (parseFloat(mwVersion[1]) > 21) { | |||
// Reload HotCat after page is saved (bug T103285) | |||
mw.hook('postEdit').add( function () { | |||
catLine = null; | |||
editors = []; | |||
initialized = false; | |||
HotCat.started = false; | |||
run (); | |||
} ); | |||
} | |||
} else { | |||
// mw.loader.using('user', ...) could have unintended side-effects on MW <= 1.20. Fall back to dom-ready. | |||
jQuery(document).ready(run); | |||
} | } | ||
})(); | |||
//</source> | |||
// Präfix „Datei:“ für Dateibeschreibungsseiten und Spezial:Hochladen als Vorgabe | |||
$(function () { | |||
var namespaceNumber = mw.config.get('wgNamespaceNumber'); | |||
}( | if (namespaceNumber === -1 && mw.config.get('wgCanonicalSpecialPageName') == 'Upload') { | ||
// We're on Special:Upload: pretend we were in the file namespace. | |||
namespaceNumber = 6; | |||
} | |||
// Exclude all other namespaces including talk pages and special pages | |||
if (namespaceNumber !== 6) return; | |||
$('body').on('focus', '.hotcatinput input:text', function () { | |||
var wasSet = $(this).data('hotcatprefixset'); | |||
if (wasSet) return; // Already done, don't re-do it (user might have deleted pre-filled text) | |||
if (!this.value) { | |||
// If input field is empty, then pre-fill it | |||
var namespaceNames = mw.config.get('wgFormattedNamespaces'); | |||
if (namespaceNames && typeof (namespaceNames[namespaceNumber]) == 'string') { | |||
var suffix = ':'; | |||
this.value = namespaceNames[namespaceNumber] + suffix; | |||
} | |||
} | |||
$(this).data('hotcatprefixset', true); | |||
}); | |||
}); |
ویرایش