User:Lampak/DelReqHandler.js

Note: After saving, you have to bypass your browser's cache to see the changes. Internet Explorer: press Ctrl-F5, Mozilla: hold down Shift while clicking Reload (or press Ctrl-Shift-R), Opera/Konqueror: press F5, Safari: hold down Shift + Alt while clicking Reload, Chrome: hold down Shift while clicking Reload.
//<source lang="javascript">

/*
  Support for quick deletions and closing of deletion requests at the Commons.
 
  Author: [[User:Lupo]], October 2007 - January 2008
  License: Quadruple licensed GFDL, GPL, LGPL and Creative Commons Attribution 3.0 (CC-BY-3.0)
 
  Choose whichever license of these you like best :-)

  Tested only in Firefox.
*/

/**** Guard against double inclusions */

if (typeof (DelReqHandler) == 'undefined') {

/**** Some things may not be defined in some cases */

var DelReqUtils =
{
  // 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, href)
  {
    var cmdRe = RegExp ('[&?]' + paramName + '=([^&]*)');
    var h = href || document.location.href;
    var m = cmdRe.exec (h);
    if (m) {
      try {
        return decodeURIComponent (m[1]);
      } catch (someError) {}
    }
    return null;
  }

} // End of DelReqUtils

/**** Enable the whole shebang only for sysops. */
if (true || wgUserGroups.join (' ').indexOf ('sysop') >= 0) {

importScript ('MediaWiki:Utilities.js');
importScript ('MediaWiki:AjaxSubmit.js');
importScript ('MediaWiki:MD5.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 &&
        wgPageName.indexOf ('Commons:Deletion_requests') >= 0)
    {
      // We're on COM:DEL or one of its daily subpages
      // Don't do anything if we're not viewing the current version of the page
      if (wgAction != 'view' || document.URL.search (/[?&]oldid=/) >= 0)
        return;
      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 ('&section=1');
            var len = 10;
            if (offset < 0) {
              offset = href.indexOf ('&section=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, filename)
  {
    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) {
      if (filename)
        DelReqHandler.execute (filename, reason);
      else
        window.open (href + encodeURIComponent (reason), '_blank');
    }
  },

  /* 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)
  {
    // Don't do anything if we're not viewing the current version of the page
    if (wgAction != 'view' || document.URL.search (/[?&]oldid=/) >= 0)
      return;
    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', 2);
      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.charAt(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 ('File:') == 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 (wgNamespaceNumber == 14 || wgNamespaceNumber == -1) {
              // Galleries on category pages (NamespaceNumber == 14) or on special pages 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 + '=';
          // Extract the file name from the href
          var del_filename = titleFromHref (href);
          if (del_filename) {
            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 = makeActiveLink (
                            'del'
                          , 'DelReqHandler.execute ("'
                            + stringifyJS (del_filename)
                            + '", "'
                            + stringifyJS (del_reason)
                            + '");'
                         );
            } else {
              new_link = makeActiveLink (
                            'del'
                          , 'DelReqHandler.promptForReason ("'
                            + stringifyJS (del_href)
                            + '", null'   // No default reason here!
                            + (use_last ? ', true, "' : ', false, "')
                            + stringifyJS (del_filename)                            
                            + '");'
                         );
            }
            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 ("'
                     + stringifyJS (keep_href)
                     + '", "Kept."'  // Use a default reason here.
                     + (use_last ? ', true);' : ');')
                  )
                );
              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 del_filename
        } // end if isImgLk
      } // end if
    } // end for all links
  },

  delRequestLinks : function ()
  {
    if (wgPageName.indexOf ('Commons:Deletion_requests') < 0) return;
 
    // Ok, it's really a deletion request page (either individual, or daily, monthly, overall)
    var content =    document.getElementById ('bodyContent')       // monobook
                  || document.getElementById ('mw_contentholder')  // "modern" skin
                  || document.getElementById ('article');          // classic skins
    if (!content) return;
    var lks = getElementsByTagNameStatic ('a', content);
    // 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 (false && wgUserGroups.join (' ').indexOf ('sysop') < 0) {
      // That actually should never occur.
      window.close ();
      return;
    } else if (document.forms == null || document.forms[0] == null) {
      // Something went wrong. Maybe the page or the image has already been deleted.
      window.close ();
      return;
    } else if (wgNamespaceNumber != 6 && wgNamespaceNumber != 7) {
      // Hey, this is intended *only* for file deletions! Don't do anything in other namespaces,
      window.close ();
      return;
    } else {
      var may_commit = false;
      if (!wgRestrictionEdit.join || wgRestrictionEdit.join (' ').indexOf ('sysop') < 0) {
        // Only commit if page is not protected:
        may_commit = true;
      }
      if (may_commit) {
        // Check the token
        var token = DelReqUtils.getParamValue ('deltoken');
        var fn    = wgPageName.replace (/ /g, '_');
        var now = new Date ();
        now = Math.floor (now.getTime () / (30 * 1000)); // 30 seconds
        may_commit =
          (   (token == hex_md5 (fn + document.cookie + wgUserName + now))
           || (token == hex_md5 (fn + document.cookie + wgUserName + (now-1)))
          );
      }
      var param = DelReqUtils.getParamValue (DelReqHandler.lupo_del_reason);
      var reason = document.getElementById ('wpReason');
      if (reason == null) return;
      var is_page = (param != null && param.length > 2 && param.substring (0, 2) == '\[\[');
  
      if (is_page)
        reason.value = 'Per ' + param;
      else
        reason.value = param;
  
      if (wgNamespaceNumber != 1 && wgCanonicalNamespace.indexOf ('_talk') < 0) {
        // Also delete the talk page, if there is one.
        try {
          var talk_href = DelReqHandler.find_talk_page_link ();
          if (talk_href.indexOf ('action=edit') < 0) {
            // Talk page exists. Extract talk page name from link
            var talk_filename = titleFromHref (talk_href);
            if (talk_filename) {
              DelReqHandler.execute (
                  talk_filename
                , (is_page
                    ? 'Talk page of file deleted per ' + param
                    : 'Talk page of deleted file: ' + param
                  )
                , (document.location.href.indexOf ('&withJS=MediaWiki:Gadget-DelReqHandler.js') >= 0
                    ? '&withJS=MediaWiki:Gadget-DelReqHandler.js'
                    : ""
                  )
              );
            }
          }
        } catch (e) {
        }
      }
      if (may_commit)
        submitAndClose (document.forms[0]);
      else {
        var div = document.createElement ('div');
        div.style.border = '1px #FF0000 solid';
        div.style.backgroundColor = 'lightpink';
        div.style.padding = '0.5em';
        div.style.marginTop = '0.5em';
        div.style.marginBottom = '0.5em';
        document.forms[0].parentNode.insertBefore (div, document.forms[0].nextSibling);
        div.innerHTML =
            '<b>Warning:</b> you got here through a script. This script cannot commit '
          + 'this form because either the page to be deleted is <em>protected</em> or the '
          + 'deletion <em>token has expired</em>. Check carefully if you really want to '
          + 'delete this file and then either '
          + '<ul><li><b>close</b> this window to <b>keep</b> the file, or</li>'
          + '<li>manually click the submit button above to <b>delete</b> the file.</li>';
      }
    }
  },
  
  find_talk_page_link : function ()
  {
    var container = null;
    var a         = null;
    switch (skin) {
      case 'cologneblue':
      case 'standard':
      case 'nostalgia':
        var container = document.getElementById ('footer');
        var lks = container.getElementsByTagName ('a');
        var ns = wgCanonicalNamespace;
        var filename = null;
        if (ns.length == 0) {
          filename = 'Talk:' + wgPageName;
        } else {
          ns = ns + "_talk:";
          var i = wgPageName.indexOf (':');
          filename = ns + wgPageName.substr (i+1);
        }
        for (var i = 0; i < lks.length; i++) {
          var p = titleFromLink (lks[i]);
          if (p && p == filename) {
            a = lks[i].getAttribute ('href', 2);
            break;
          }
        }
        break;
      default:
        // all modern skins:
        a = document.getElementById ('ca-talk');
        if (a) a = a.getElementsByTagName ('a');
        if (a && a.length > 0) a = a[0]; else a = null;
        if (a) a = a.getAttribute ('href', 2);
    }
    return a;
  },

  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 (wgNamespaceNumber == 6) {
  
      // 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_href = wgPageName.replace (/ /g, '_');
      // Strip off namespace.
      talk_href = talk_href.substr (talk_href.indexOf (':') + 1);
      talk_href = wgServer
                  + wgArticlePath.replace ('$1', 'File_talk:' + encodeURI (talk_href))
                  + '?action=edit';
      talk_href = talk_href
                + '&' + DelReqHandler.lupo_keep_reason + '='
                + encodeURIComponent
                   (DelReqUtils.getParamValue (DelReqHandler.lupo_keep_reason));
      if (document.location.href.indexOf ('&withJS=MediaWiki:Gadget-DelReqHandler.js') >= 0)
         // Pass it on
         talk_href = talk_href + '&withJS=MediaWiki:Gadget-DelReqHandler.js';
      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 (wgNamespaceNumber == 7) {
      // We're on the talk page: just append "kept"
      setEditSummary ('\{\{kept\}\}');
      try {
        var del_req_page = DelReqUtils.getParamValue (DelReqHandler.lupo_keep_reason);
        // Strip the [[ and ]]
        del_req_page = del_req_page.substring (2, del_req_page.length - 2);
        // Find the date by getting the timestamp of the earliest revision of the deletion request.
        var request = sajax_init_object();
        if (request != null) {
          var uri = mw.config.get('wgServer') + mw.config.get('wgScriptPath') + '/api.php?action=query'
                  + '&prop=revisions&rvlimit=1'                    // Exactly one revision
                  + '&titles=' + encodeURIComponent (del_req_page) // Of the deletion request
                  + '&rvprop=timestamp'                            // Only the timestamp
                  + '&rvdir=newer'                                 // Start at the oldest revision
                  + '&format=json&callback=DelReqHandler.addKeepToTalk';
          // Make the call
          request.open ('GET', uri, true);
          request.setRequestHeader ('Pragma', 'cache=no');
          request.setRequestHeader ('Cache-Control', 'no-transform');
          request.onreadystatechange =
            function()
            {
              if (request.readyState != 4) return; // Request not completed yet
              if (request.status != 200)   return; // Request failed
              eval (request.responseText);
            };
          request.send (null); // No POST data
        } else {
          // We don't have XMLHttp...
          edit_text.value = edit_text.value + '\n\{\{kept||' + del_req_page + '\}\}';
          // 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);
      }
    }
  },

  addKeepToTalk : function (results) // JSON callback
  {
    if (!results || !results.query || !results.query.pages) return;
    var success   = false;
    var edit_text = document.getElementById ('wpTextbox1'); // We *know* this exists
    try {
      var del_req_page = DelReqUtils.getParamValue (DelReqHandler.lupo_keep_reason);
      del_req_page = del_req_page.substring (2, del_req_page.length - 2);
      for (var page in results.query.pages) {
        // There should be only one, but the for-loop is the easiest to get the unknown page id used
        // as the sub-object selector...
        var p = results.query.pages[page];
        if (p.revisions && p.revisions.length > 0) {
          var ts = p.revisions[0].timestamp;
          if (ts && ts.length > 10) {
            // Extract year, month, and day from the timestamp. We don't care about the
            // exact time.
            var year  = ts.substr (0, 4);
            var month = ts.substr (5, 2);
            var day   = ts.substr (8, 2);
            edit_text.value = edit_text.value
                            + '\n\{\{kept|'
                            + "" + year + '-' + month + '-' + day
                            + '|' + del_req_page + '\}\}';
            success = true;
          }
        }
        break;
      }
    } catch (ex) {
      // Swallow
    }
    if (!success) {
      // Huh? Somehow, we couldn't get the date.
      edit_text.value = edit_text.value + '\n\{\{kept||' + del_req_page + '\}\}';
    }
    submitAndClose (document.forms[0]);
  },

  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();
      }
    }
  },

  execute : function (filename, reason, extra)
  {
    if (filename) {
      var href = mw.config.get('wgServer') + mw.config.get('wgArticlePath').replace ('$1', encodeURI (filename))
               + '?action=delete'
               + '&' + DelReqHandler.lupo_del_reason + '=' + encodeURIComponent (reason)
               + '&deltoken=' + DelReqHandler.get_token (filename)
               + (extra || "");
      window.open (href, '_blank');
    }
  },

  get_token : function (filename)
  {
    if (!filename) return "";
    var now = new Date ();
    now = Math.floor (now.getTime () / (30 * 1000)); // 30 seconds
    return hex_md5 (filename + document.cookie + wgUserName + now);
  }

} // End of DelReqHandler

$ (DelReqHandler.setupAutoDel);

} // End of sysop check

} // End of idempotency check

//</source>