MediaWiki:Gadget-DelReqHandler.js
Not: Sayfayı kaydettikten sonra değişiklikleri görebilmek için tarayıcınızın önbelleğinizi temizlemeniz gerekir. Google Chrome, Firefox, Microsoft Edge ve Safari: ⇧ Shift tuşuna basılı tutun ve Yeniden Yükle araç çubuğu düğmesine tıklayın. Ayrıntılar ve diğer tarayıcılara yönelik yönergeler için Vikipedi:Önbelleğinizi atlayın sayfasını inceleyin.
/**** Guard against double inclusions */
if (typeof (DelReqHandler) == 'undefined') {
/**** Some things may not be defined in some cases */
var DelReqUtils =
{
/* includepage (from MediaWiki:Common.js) may not be defined if this is called through
the gadgets mechanism. Define our own. (And do it the nice way.) */
includePage : function (script)
{
var url = wgScriptPath
+ '/index.php?title='
+ encodeURIComponent (script.replace (/ /g, '_'))
+ '&action=raw&ctype=text/javascript';
var scriptElem = document.createElement( 'script' );
scriptElem.setAttribute ('src', url);
scriptElem.setAttribute ('type', 'text/javascript');
document.getElementsByTagName ('head')[0].appendChild (scriptElem);
},
/* userIsInGroup (from MediaWiki:Utilities.js) sometimes isn't defined even after the
call to includePage below because page loading is asynchronous. Define our own. */
userIsInGroup : function (group)
{
if (mw.config.get('wgUserGroups')) {
if (!group || group.length == 0) group = '*';
for (var i=0; i < mw.config.get('wgUserGroups').length; i++) {
if (mw.config.get('wgUserGroups')[i] == group) return true;
}
}
return false;
},
// The following function is defined in several places, and unfortunately, it is defined
// wrongly in some places. (For instance, in [[:en:User:Lupin/popups.js]]: it should use
// decodeURIComponent, not decodeURI!!!) Make sure we've got the right version here:
getParamValue : function (paramName)
{
var cmdRe = RegExp ('[&?]' + paramName + '=([^&]*)');
var h = document.location.href;
var m = cmdRe.exec (document.location.href);
if (m) {
try {
return decodeURIComponent (m[1]);
} catch (someError) {}
}
return null;
}
} // End of DelReqUtils
/**** Enable the whole shebang only for sysops. */
if (DelReqUtils.userIsInGroup ('sysop')) {
/**** Import needed files. Do a crude check to see whether we already have these files.
Actually, we should probably change function includePage in MediaWiki:Common.js
to keep track of already included files! */
if (typeof userIsInGroup != 'function') {
DelReqUtils.includePage ('MediaWiki:Utilities.js');
}
/**** Another file import */
if (typeof ajaxSubmit != 'function') {
DelReqUtils.includePage ('MediaWiki:AjaxSubmit.js');
}
var DelReqHandler =
{
/*------------------------------------------------------------------------------------------
Deletion request closing: add "[d][del]" and "[k][keep]" links to the left of the section edit
links of a deletion request. [d] and [k] open the deletion request for editing in a new window
(or tab), add "delh" and "delf" with "Deleted." or "Kept." plus the signature (four tildes)
and then save and close the tab. [del] and [keep] do the same, but don't save and close the
window, so that the user may enter an additional comment.
------------------------------------------------------------------------------------------*/
lupo_close_del : 'close_del',
lupo_close_keep : 'close_keep',
lupo_quick_closure : '&lupo_quick_closure=1',
close_del_summary : 'Deleted.',
close_keep_summary : 'Kept.',
closeRequestLinks : function ()
{
function addRequestLinks (name, href, before, parent)
{
parent.insertBefore (document.createTextNode ('['), before);
parent.insertBefore
(makeRawLink ( name.substring (0, 1)
, href + DelReqHandler.lupo_quick_closure
, '_blank'), before);
parent.insertBefore (document.createTextNode (']'), before);
parent.insertBefore (document.createTextNode ('['), before);
parent.insertBefore (makeRawLink (name, href, '_blank'), before);
parent.insertBefore (document.createTextNode (']'), before);
}
var param = DelReqUtils.getParamValue ('fakeaction');
if (param == null &&
(document.URL.indexOf ('Commons:Deletion_requests') >= 0 ||
mw.config.get('wgPageName') == 'Commons:Deletion_requests')) // To catch the 'COM:DEL' shortcut...
{
// We're on COM:DEL or one of its daily subpages
var edit_lks = getElementsByClassName (document, 'span', 'editsection');
for (i = 0; i < edit_lks.length; i++) {
// Find the A within:
var anchors = edit_lks[i].getElementsByTagName ('a');
if (anchors != null && anchors.length > 0) {
var anchor = anchors[0];
var href = anchor.getAttribute ('href');
if (href.indexOf ('Commons:Deletion_requests/20') < 0 &&
href.indexOf ('Commons:Deletion_requests/') > 0)
{
var offset = href.indexOf ('§ion=1');
var len = 10;
if (offset < 0) {
offset = href.indexOf ('§ion=T-1'); // Fix for MW 1.13alpha
len = 12;
}
if (offset > 0 && offset + len == href.length) {
// It's really an edit lk to a deletion request subpage, and not a section
// edit for a daily subpage or something else
href = href.substring (0, offset);
var orig_bracket = edit_lks[i].firstChild;
// [d][del]
addRequestLinks
('del', href + '&fakeaction=' + DelReqHandler.lupo_close_del,
orig_bracket, edit_lks[i]);
// [k][keep]
addRequestLinks
('keep', href + '&fakeaction=' + DelReqHandler.lupo_close_keep,
orig_bracket, edit_lks[i]);
}
}
}
}
} else if (param != null) {
// We're on a deletion request subpage
var summary = null;
if (param == DelReqHandler.lupo_close_del) {
summary = DelReqHandler.close_del_summary;
} else if (param == DelReqHandler.lupo_close_keep) {
summary = DelReqHandler.close_keep_summary;
}
if (summary != null) {
var text = document.editform.wpTextbox1;
text.value =
'\{\{delh\}\}\n'
+ text.value
+ '----\n'
+ '\'\'\'' + summary + '\'\'\' \~\~\~\~\n'
+ '\{\{delf\}\}';
setEditSummary (summary);
if (DelReqUtils.getParamValue ('lupo_quick_closure') == '1') {
submitAndClose (document.editform);
} else {
// Don't close the window to allow adding a comment.
if (text.scrollHeight > text.clientHeight) {
text.scrollTop = text.scrollHeight - text.clientHeight;
}
text.focus ();
}
}
}
},
/*------------------------------------------------------------------------------------------
Links on every non-deleted image mentioned on a deletion request page. The "[del]" link
triggers deletion (auto-completed!) of the image, with a deletion summary linking to the
deletion request. If the image has a talk page, it is deleted as well. The "[keep]" link
automatically removes the "delete" template from the image page and adds the "kept" template
to the image talk page, both linking back to the deletion request.
------------------------------------------------------------------------------------------*/
lupo_del_reason : 'delreason',
lupo_keep_reason : 'keepreason',
last_reason : "",
/* promptForReason
*
* Execute the del or keep link (by opening a new window), but prompt for a reason first.
*
* Parameters:
* href String The del/keep href, already prepared.
* default_reason optional String If set, use this reason if the user doesn't enter one.
* If no default_reason is given and the user doesn't enter
* anything, nothing is executed.
* use_last optional boolean If true, use the last entered reason as the default.
* Defaults to false.
*/
promptForReason : function (href, default_reason, use_last)
{
var reason = null;
var label = 'Reason:';
var default_string = default_reason;
if (use_last) default_string = DelReqHandler.last_reason;
if (default_string == null) default_string = "";
reason = prompt (label, default_string);
DelReqHandler.last_reason = reason;
if (reason && reason.length > 0) {
window.open (href + encodeURIComponent (reason), '_blank');
}
return false;
},
/* addDelKeepLinks
*
* Add [del] and [keep] links after all the links given.
*
* Parameters:
* lks Array Static array of DOM elements, which must be links.
* do_keep optional boolean If true, also add [keep] links. Otherwise, only add [del]
* links. Defaults to false.
* on_del_req optional boolean If true, try to automatically set a deletion reason by
* figuring out the deletion request (but if a reason is given,
* use that). Otherwise, use 'reason'. Defaults to false.
* use_last optional boolean If true and the prompting links are used, make the prompt
* default to the last used reason.
* reason optional String Reason to use. If not set or set to the empty string,
* generate links that prompt for a reason, unless
* 'on_del_req' is true. Defaults to null (not set).
*/
addDelKeepLinks : function (lks, do_keep, on_del_req, use_last, reason)
{
var with_keep = do_keep || false;
var is_del_req = on_del_req || false;
for (i = 0; i < lks.length; i++) {
var href = lks[i].getAttribute ('href');
var classes = lks[i].getAttribute ('class') || "";
var lk_title = lks[i].getAttribute ('title') || "";
if ( classes.search (/\bnew\b/) < 0
&& href != null && href.length > 0 && href[0] == '/')
{
// Internal link to existing thingy. Check whether to add the links
var lk_through_img = classes.search (/\bimage\b/) >= 0;
var isImgLk =
lk_through_img
|| (lk_title.indexOf ('Image:') == 0) && (lk_title.indexOf ('/') < 0);
var gallerybox = null;
if (lk_through_img) {
var parent = lks[i].parentNode;
while ( gallerybox == null && parent != null
&& parent.nodeName.toLowerCase () == 'div')
{
if (parent.getAttribute ('class') == 'gallerybox') gallerybox = parent;
parent = parent.parentNode;
}
if (gallerybox != null) {
if (mw.config.get('wgNamespaceNumber') == 14) {
// Galleries on category pages (NamespaceNumber == 14) have a link to the image in
// in the "gallerytext"; so don't add a link for this one; we'll add one for the
// textual link instead.
isImgLk = false;
} else {
gallerybox = gallerybox.firstChild;
while ( gallerybox != null
&& ( typeof (gallerybox.getAttribute) != 'function'
|| gallerybox.getAttribute ('class') != 'gallerytext'))
{
// The test for typeof (gallerybox.getAttribute) is needed because newlines
// between XHTML elements may be present in the DOM tree as text nodes! And
// Firefox 2 at least doesn't have 'getAttribute' for text nodes...
gallerybox = gallerybox.nextSibling;
}
if (gallerybox == null || gallerybox.nodeName.toLowerCase () != 'div') {
// Gallerytext not found. Don't insert links
isImgLk = false;
}
}
} else {
// Apparently not in a gallery
isImgLk = false;
}
} // end if lk_through_img
if (isImgLk) {
// Insert small [del][keep] small after the link
var curr_lk = lks[i];
var del_href = href + '?action=delete&' + DelReqHandler.lupo_del_reason + '=';
var keep_href = href + '?action=edit&' + DelReqHandler.lupo_keep_reason + '=';
var del_reason = reason;
if (is_del_req && !del_reason) {
var curr_elem = i-1;
// Figure out the actual deletion request by finding the previous editsection link,
// or alternatively, the previous link that already has a delreason (must be within
// the same deletion request, otherwise the editsection link is found first).
while (del_reason == null && curr_elem >= 0) {
var curr_href = lks[curr_elem].getAttribute ('href');
if (curr_href != null) {
if (curr_href.indexOf (DelReqHandler.lupo_close_del) > 0) {
del_reason = curr_href.substring (curr_href.indexOf ('title=') + 6);
var idx = del_reason.indexOf ("&")
if (idx >= 0) del_reason = del_reason.substring (0, idx);
del_reason = encodeURIComponent ('[[')
+ del_reason
+ encodeURIComponent (']]');
} else {
var offset = curr_href.indexOf (DelReqHandler.lupo_del_reason + '=');
if (offset > 0) {
del_reason =
curr_href.substring (offset + DelReqHandler.lupo_del_reason.length + 1);
}
}
}
curr_elem = curr_elem - 1;
}
}
// Add the links
var toInsert = document.createElement ('small');
var new_link;
if (del_reason)
new_link = makeRawLink ('del', del_href + del_reason, '_blank');
else
new_link = makeActiveLink (
'del'
, 'DelReqHandler.promptForReason ("'
+ del_href
+ '", null' // No default reason here!
+ (use_last ? ', true);' : ');')
+ ' void 0;');
toInsert.appendChild (document.createTextNode (' ['));
toInsert.appendChild (new_link);
toInsert.appendChild (document.createTextNode (']'));
if (with_keep) {
toInsert.appendChild (document.createTextNode (' ['));
if (del_reason)
toInsert.appendChild (makeRawLink ('keep', keep_href + del_reason, '_blank'));
else
toInsert.appendChild (
makeActiveLink (
'keep'
, 'DelReqHandler.promptForReason ("'
+ keep_href
+ '", "Kept."' // Use a default reason here.
+ (use_last ? ', true);' : ');')
+ ' void 0;'));
toInsert.appendChild (document.createTextNode (']'));
}
if (gallerybox != null) {
// Insert the links at the beginning of the gallerytext
gallerybox.insertBefore (toInsert, gallerybox.firstChild);
} else {
// Append the links after the current link
curr_lk.parentNode.insertBefore (toInsert, curr_lk.nextSibling);
}
if (is_del_req) {
// Replace the link just handled by the new one to have a sentinel that does have a
// deletion request attribute.
lks[i] = new_link;
}
} // end if isImgLk
} // end if
} // end for all links
},
delRequestLinks : function ()
{
if (document.URL.indexOf ('Commons:Deletion_requests') < 0 &&
mw.config.get('wgPageName') != 'Commons:Deletion_requests') // To catch the 'COM:DEL' shortcut...
{
return;
}
// Ok, it's really a deletion request page (either individual, or daily, monthly, overall)
var lks = getElementsByTagNameStatic ('a', document.getElementById ('bodyContent'));
// Do *not* use getElementsByTagName directly: it returns a live NodeList of 'a'-tags, and
// since we are going to add more anchors, we might end up traversing our newly added
// links, too! Using a static (i.e., non-live) list is much faster anyway.
DelReqHandler.addDelKeepLinks (lks, true, true);
},
autodelete : function ()
{
if (document.forms == null || document.forms[0] == null) {
// Something went wrong. Maybe the page or the image has already been deleted.
window.close ();
} else {
var param = DelReqUtils.getParamValue (DelReqHandler.lupo_del_reason);
var reason = document.getElementById ('wpReason');
var is_page = (param != null && param.length > 2 && param.substring (0, 2) == '\[\[');
if (is_page)
reason.value = 'per ' + param;
else
reason.value = param;
// Also delete the talk page, if there is one.
try {
var back_link = document.getElementById ('contentSub').getElementsByTagName ('a')[0];
if (back_link != null) {
var href = back_link.getAttribute ('href');
var offset = href.indexOf ('Image:');
if (offset > 0) {
var talk_link = document.getElementById ('ca-talk').getElementsByTagName ('a')[0];
var talk_href = talk_link.getAttribute ('href');
if (talk_href.indexOf ('&action=edit') < 0) {
// Talk page exists
href = talk_href
+ '?action=delete&' + DelReqHandler.lupo_del_reason + '=';
if (is_page)
href = href + encodeURIComponent ('Talk page of image deleted per ' + param);
else
href = href + encodeURIComponent ('Talk page of deleted image: ' + param);
window.open (href, '_blank');
}
}
}
} catch (e) {
}
submitAndClose (document.forms[0]);
}
},
months : new Array ("January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"),
autokeep : function ()
{
var edit_form = document.getElementById ('editform');
if (edit_form == null) {window.close (); return;}
var edit_text = document.getElementById ('wpTextbox1');
if (edit_text == null) {window.close (); return;}
var text = edit_text.value;
var success = false;
if ('Image' == mw.config.get('wgCanonicalNamespace')) {
// IF we're on the image page:
// Search for the "delete" tag (beware of nested transclusions, such as the reason
// containing a "tl" template)
var start = text.indexOf ('\{\{delete');
if (start < 0) start = text.indexOf ('\{\{Delete');
if (start < 0) start = text.indexOf ('\{\{vfd');
if (start < 0) start = text.indexOf ('\{\{Vfd');
if (start < 0) start = text.indexOf ('\{\{ifd');
if (start < 0) start = text.indexOf ('\{\{Ifd');
if (start >= 0) {
var level = 0;
var curr = start + 2;
var end = 0;
while (curr < text.length && end == 0) {
var opening = text.indexOf ('\{\{', curr);
var closing = text.indexOf ('\}\}', curr);
if (opening >= 0 && opening < closing) {
level = level + 1;
curr = opening + 2;
} else {
if (closing < 0) {
// No closing braces found
curr = text.length;
} else {
if (level > 0) level = level - 1; else end = closing + 2;
curr = closing + 2;
}
}
}
if (end > start) {
// Also strip whitespace after the "delete" template
if (start > 0) {
edit_text.value = text.substring (0, start)
+ text.substring (end).replace(/^\s*/, '');
} else {
edit_text.value = text.substring (end).replace(/^\s*/, '');
}
setEditSummary ( 'Kept per '
+ DelReqUtils.getParamValue (DelReqHandler.lupo_keep_reason));
success = true;
} else {
setEditSummary ('ERROR: End of deletion tag not found');
}
} else {
setEditSummary ('ERROR: No deletion tag found.');
}
// Open the talk page for editing
var talk_link = document.getElementById ('ca-talk').getElementsByTagName ('a')[0];
var talk_href = talk_link.getAttribute ('href');
if (talk_href.indexOf ('&action=edit') < 0) talk_href = talk_href + '?action=edit';
talk_href = talk_href
+ '&' + DelReqHandler.lupo_keep_reason + '='
+ encodeURIComponent
(DelReqUtils.getParamValue (DelReqHandler.lupo_keep_reason));
if (success) {
// Don't close the window but re-load the talk page into it!
ajaxSubmit
(document.forms[0], null, function() { window.location.href = talk_href; });
} else {
// Don't submit and close the image description page, but *do* continue with the talk
// page.
window.setTimeout(function() { window.open (talk_href, '_blank'); }, 100);
}
} else if ('Image_talk' == mw.config.get('wgCanonicalNamespace')) {
// We're on the talk page: just append "kept"
setEditSummary ('\{\{kept\}\}');
try {
var param = DelReqUtils.getParamValue (DelReqHandler.lupo_keep_reason);
// Contains the deletion request's page name
// Strip the [[ and ]]
param = param.substring (2, param.length - 2);
// Find the date by getting the earliest history of the deletion request
// ("&dir=prev&action=history"). If there's only one "li" within the form, the date is
// the text of the first "a" within that "li", otherwise it's the text of the second "a"
// within the last "li"
var X = sajax_init_object();
if (X != null) {
var uri = mw.config.get('wgServer') + wgScriptPath + '/api.php'
+ '?action=query&format=xml' // XML query
+ '&prop=revisions&rvlimit=1' // Exactly one revision
+ '&titles=' + encodeURIComponent (param) // Of the deletion request
+ '&rvprop=timestamp' // Only the timestamp
+ '&rvdir=newer' // Start at the oldest revision
// Make the call
X.open ('GET', uri, true);
X.setRequestHeader ('Pragma', 'cache=no');
X.setRequestHeader ('Cache-Control', 'no-transform');
// Manually set the mime type. This is crucial, otherwise responseXML may be empty.
// TODO: does IE have this? If not, what to do on IE?
if (typeof (X.overrideMimeType) == 'function')
X.overrideMimeType ('text/xml');
X.onreadystatechange =
function()
{
if (X.readyState != 4) return;
if (X.status != 200) { success = false; return; }
// Yep, we've got the response
if (X.responseXML != null) {
try {
var revision = X.responseXML.getElementsByTagName ('rev');
var timestamp = null;
if (revision == null || revision.length == 0)
revision = null;
else
revision = revision[0];
if (revision != null) {
timestamp = revision.getAttribute ('timestamp');
if (timestamp != null && timestamp.length >= 10) {
// Extract year, month, and day from the timestamp. We don't care about the
// exact time.
var year = timestamp.substr (0, 4);
var month = parseInt (timestamp.substr (5, 2), 10); // Specify the radix
var day = parseInt (timestamp.substr (8, 2), 10); // Specify the radix
// Note: we must specify the radix here, otherwise, "08" and "09" will be
// treated as invalid octal numbers!
edit_text.value = edit_text.value
+ '\n\{\{kept|'
+ DelReqHandler.months[month-1]
+ ' ' + day + ', ' + year
+ '|' + param + '\}\}';
success = true;
}
}
} catch (ex) {
// Swallow
}
}
if (!success) {
// Huh? Somehow, we couldn't get the date.
edit_text.value = edit_text.value + '\n\{\{kept||' + param + '\}\}';
}
submitAndClose (document.forms[0]);
}; // end of onreadystate handler
X.send (null); // No POST data
} else {
// We don't have XMLHttp...
edit_text.value = edit_text.value + '\n\{\{kept||' + param + '\}\}';
// We cannot close the window either, we can just submit the form.
document.forms[0].submit ();
}
} catch (e) {
// TODO: Improve error handling. Just propagate the exception?
alert ('Exception: ' + e);
}
}
},
setupAutoDel : function ()
{
// Wait until the included scripts have loaded.
if (typeof (ajaxSubmit) != 'function' || typeof (setEditSummary) != 'function')
window.setTimeout (DelReqHandler.setupAutoDel, 100);
else {
// Everything's loaded now
if (document.URL.indexOf (DelReqHandler.lupo_del_reason) > 0) {
DelReqHandler.autodelete ();
} else if (document.URL.indexOf (DelReqHandler.lupo_keep_reason) > 0) {
DelReqHandler.autokeep ();
} else {
DelReqHandler.closeRequestLinks();
DelReqHandler.delRequestLinks();
}
}
}
} // End of DelReqHandler
$(DelReqHandler.setupAutoDel);
} // End of sysop check
} // End of idempotency check