User:Dtrebbien/Sandbox/newPagesTool.js

Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
function addlimenu(tabs, name, id, href, position) {
    var na, mn;
    var li;
 
    if (!id)  id = name;
    if (!href) href = '#';
 
    na = document.createElement("a");
    na.appendChild(document.createTextNode(name));
    na.href = href;
    mn = document.createElement("ul");
    li = document.createElement("li");
    li.appendChild(na);
    li.appendChild(mn);
    if (id) li.id = id;
    li.className = 'tabmenu';
 
    if (position) {
        tabs.insertBefore(li, position);
    } else {
        tabs.appendChild(li);
    }

    return mn;  // useful because it gives us the <ul> to add <li>s to
}

var wgPreferences = wgPreferences || new Object;
var wgMessages = wgMessages || new Object;

/**
 * Date Format 1.2.2
 * (c) 2007-2008 Steven Levithan <stevenlevithan.com>
 * MIT license
 * Includes enhancements by Scott Trenda <scott.trenda.net> and Kris Kowal <cixar.com/~kris.kowal/>
 * Includes modifications by D. Trebbien to remove localized day names (`ddd` and `dddd`) and to use `wgMessages.monthNames` instead of `dateFormat.i18n.monthNames`. Also `mmm` was removed and `mmmm` altered so that the 'january' message would be at `wgMessages.monthNames[0]`.
 *
 * Accepts a date, a mask, or a date and a mask.
 * Returns a formatted version of the given date.
 * The date defaults to the current date/time.
 * The mask defaults to dateFormat.masks.default.
 *
 * @see http://blog.stevenlevithan.com/archives/date-time-format
 */
var dateFormat = function() {
   var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,
      timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
      timezoneClip = /[^-+\dA-Z]/g,
      pad = function(val, len) {
         val = String(val);
         len = len || 2;
         while(val.length < len) val = "0" + val;
         return val;
      };

	// regexes and supporting functions are cached through closure
	return function(date, mask, utc) {
      var dF = dateFormat;

      // you can't provide utc if you skip other args (use the "UTC:" mask prefix)
      if(arguments.length == 1 && (typeof date == "string" || date instanceof String) && !/\d/.test(date))
      {
         mask = date;
         date = undefined;
      }

      // passing date through Date applies Date.parse, if necessary
      date = date ? new Date(date) : new Date();
      if(isNaN(date)) throw new SyntaxError("invalid date");

      mask = String(dF.masks[mask] || mask || dF.masks["default"]);

      // allow setting the utc argument via the mask
      if(mask.slice(0, 4) == "UTC:")
      {
         mask = mask.slice(4);
         utc = true;
      }

      var _ = utc ? "getUTC" : "get",
         d = date[_ + "Date"](),
         D = date[_ + "Day"](),
         m = date[_ + "Month"](),
         y = date[_ + "FullYear"](),
         H = date[_ + "Hours"](),
         M = date[_ + "Minutes"](),
         s = date[_ + "Seconds"](),
         L = date[_ + "Milliseconds"](),
         o = utc ? 0 : date.getTimezoneOffset(),
         flags = {
            d:    d,
            dd:   pad(d),
            //ddd:  dF.i18n.dayNames[D],
            //dddd: dF.i18n.dayNames[D + 7],
            m:    m + 1,
            mm:   pad(m + 1),
            //mmm:  dF.i18n.monthNames[m],
            mmmm: wgMessages.monthNames[m],
            yy:   String(y).slice(2),
            yyyy: y,
            h:    H % 12 || 12,
            hh:   pad(H % 12 || 12),
            H:    H,
            HH:   pad(H),
            M:    M,
            MM:   pad(M),
            s:    s,
            ss:   pad(s),
            l:    pad(L, 3),
            L:    pad(L > 99 ? Math.round(L / 10) : L),
            t:    H < 12 ? "a"  : "p",
            tt:   H < 12 ? "am" : "pm",
            T:    H < 12 ? "A"  : "P",
            TT:   H < 12 ? "AM" : "PM",
            Z:    utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
            o:    (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),
            S:    ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]
         };

      return mask.replace(token, function($0) {
         return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
      });
	};
}();

// some common format strings
dateFormat.masks =
{
   "default":      "ddd mmm dd yyyy HH:MM:ss",
   shortDate:      "m/d/yy",
   mediumDate:     "mmm d, yyyy",
   longDate:       "mmmm d, yyyy",
   fullDate:       "dddd, mmmm d, yyyy",
   shortTime:      "h:MM TT",
   mediumTime:     "h:MM:ss TT",
   longTime:       "h:MM:ss TT Z",
   isoDate:        "yyyy-mm-dd",
   isoTime:        "HH:MM:ss",
   isoDateTime:    "yyyy-mm-dd'T'HH:MM:ss",
   isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"
};

// for convenience...
Date.prototype.format = function(mask, utc) {
   return dateFormat(this, mask, utc);
};

/**
 * Takes a given timestamp, as generated by the API, and formats it per the user's Date & Time preferences.
 *
 * Note that the API timestamp "2008-08-22T21:37:39Z" means "Mon, 22 Sep 2008 21:37:39 GMT".
 */
var formatTimestamp = function(timestamp) {
   timestamp = timestamp.split(/-0?|:0?|T|Z/);
   var date = new Date(Date.UTC(parseInt(timestamp[0]), parseInt(timestamp[1]), parseInt(timestamp[2]),
      parseInt(timestamp[3]), parseInt(timestamp[4]), parseInt(timestamp[5])));
   
   var timeCorrection = wgPreferences.timecorrection.split(/:0?/);
   date.setUTCHours(date.getUTCHours() + parseInt(timeCorrection[0]));
   date.setUTCMinutes(date.getUTCMinutes() + parseInt(timeCorrection[1]));
   
   var format = "HH:MM, d mmmm yyyy";
   switch(wgPreferences.date)
   {
      case "ISO 8601":
         format = "isoDateTime";
         break;
         
      case "ymd":
         format = "HH:MM, yyyy mmmm d";
         break;
      
      case "mdy":
         format = "HH:MM, mmmm d, yyyy";
         break;
      
      default:
      case "default":
      case "dmy":
         break;
   }
   
   return date.format("UTC:" + format);
};

if(!Object.prototype.join)
{
   /**
    * Joins together the keys of an object, separating them by `separator`.
    *
    * The effect should be no different than creating an array `arr` of all of the object's keys,
    * and calling `join(separator)` on that.
    */
   Object.prototype.join = function(separator) {
      var result = "";
      for(var k in this)
      {
         if(result != "")
            result += separator;
         result += k;
      }
      return result;
   };
}

if(!window.hasAttribute)
{
   if(window.HTMLElement && HTMLElement.prototype.hasAttribute && window.Element && Element.prototype.hasAttribute) // Firefox
   {
      window.hasAttribute = function(e, attr)
      {
         return e.hasAttribute(attr);
      }
   }
   else // IE, Chrome
   {
      window.hasAttribute = function(e, attr)
      {
         return e.getAttribute(attr) != null;
      }
   }
}

var wRclimit = wRclimit || 50;
if(500 < wRclimit)
   wRclimit = 500;
var wRcshow = wRcshow || "!bot|!redirect";
var wUpdateDelay = wUpdateDelay || 10000;
if(wUpdateDelay < 3000)
   wUpdateDelay = 3000;
if(!window.wUpdatesEnabledByDefault)
   window.wUpdatesEnabledByDefault = true;

// if this is updated, be sure to update the code @pared-processComment
function processComment(comment)
{
   comment = comment.replace(/</g, "&lt;"); // to help prevent XSS attacks
   comment = comment.replace(/\[\[\s*(?![Ii]mage\s*:)([^|]*?)(?:\|(.*?))?\s*\]\]/g,
      "<a href='" + wgServer + "/wiki/$1' title='$1'>$+</a>");
   comment = comment.replace(/'''([^']*?)'''/g, "<b>$1</b>");
   comment = comment.replace(/''([^']*?)''/g, "<i>$1</i>");
   comment = comment.replace(/\{\{\s*([^|]*?)(\s*(\||&lt;!|\}))/g,
      "{"+"{<a href='" + wgServer + "/wiki/Template:$1' title='Template:$1' class='external text'>$1</a>$2");
   return comment;
}

function finishDisablingUpdates()
{
   var endiUpdates = document.getElementById("a-endiupdates");
   endiUpdates.onclick = function() {
      enableUpdates();
   };
   endiUpdates.innerHTML = "Enable updates";
}

function enableUpdates(initialRun)
{
   if(!updateNewPages.updatesEnabled || initialRun)
   {
      updateNewPages.updatesEnabled = true;
      var endiUpdates = document.getElementById("a-endiupdates");
      endiUpdates.onclick = function() {
         endiUpdates.innerHTML = "Disabling...";
         updateNewPages.updatesEnabled = false;
      };
      endiUpdates.innerHTML = "Disable updates";
      setTimeout("updateNewPages()", 1);
   }
}

function updateNewPages()
{
   if(updateNewPages.updatesEnabled)
   {
      var bodyContent = document.getElementById("bodyContent");
      var ul = bodyContent.getElementsByTagName("ul")[0];
      
      var list = updateNewPages.list;
      var request = updateNewPages.request;

      request.open("GET", wgServer + wgScriptPath + "/api.php?format=xml&action=query&list=recentchanges" +
         "&rctype=new&rcnamespace=0&rcprop=user|comment|timestamp|title|ids|sizes|redirect|patrolled&rcshow=" + wRcshow + "&rclimit=" + wRclimit, // TO DO: handle the `offset` parameter of the URL
         false);
      request.send(null);
      if(request.responseXML)
      {
         var titles = new Array;
         var users = new Object; // this is a map between `User:...` and `User talk:...`s and arrays of <a> elements that link to the page
         
         var rcs = request.responseXML.getElementsByTagName("rc");
         for(var i = 0; i < rcs.length; i++)
         {
            var rc = rcs[i];
            var title = rc.getAttribute("title");
            titles.push(title);
            
            var li = null;
            for(var j = 0; j < list.length; j++)
            {
               if(list[j].title == title) // TO CHECK: whether the `title` parameter of new pages, as generated by the Special:NewPages page, is escaped in the same way as the `title` parameter of <rc>s
               {
                  li = list[j];
                  li.patrolled = hasAttribute(rc, "patrolled");
               }
            }
            
            if(!li)
            {
               if(wRclimit <= list.length)
                  ul.removeChild(list.shift());
                  
               li = document.createElement("li");
               li.title = title;
               li.appendChild(document.createTextNode(formatTimestamp(rc.getAttribute("timestamp")) + " "));
               var a = document.createElement("a"); // link to the article
               a.title = title;
               if(hasAttribute(rc, "patrolled"))
               {
                  a.href = wgServer + "/wiki/" + encodeURIComponent(title) + "?easydb=1";
                  li.patrolled = true;
               }
               else
                  a.href = wgServer + "/w/index.php?title=" + encodeURIComponent(title) + "&rcid=" + rc.getAttribute("rcid") + "&easydb=1";
               a.innerHTML = title;
               li.appendChild(a);
               li.appendChild(document.createTextNode(" ("));
               a = document.createElement("a"); // hist
               a.title = title;
               a.href = wgServer + "/w/index.php?title=" + encodeURIComponent(title) + "&action=history";
               a.innerHTML = "hist";
               li.appendChild(a);
               li.appendChild(document.createTextNode(") [" + rc.getAttribute("newlen") + " bytes] ")); // TO DO: format the number
               a = document.createElement("a"); // link to the user page
               var user = rc.getAttribute("user");
               if(hasAttribute(rc, "anon"))
               {
                  a.title = user;
                  a.href = wgServer + "/wiki/Special:Contributions/" + user;
               }
               else
               {
                  a.title = "User:" + user;
                  if(!users[a.title])
                     users[a.title] = new Array;
                  users[a.title].push(a);
                  a.href = wgServer + "/wiki/User:" + user;
               }
               a.innerHTML = user;
               li.appendChild(a);
               li.appendChild(document.createTextNode(" ("));
               a = document.createElement("a"); // link to user talk
               a.title = "User talk:" + user;
               if(!users[a.title])
                  users[a.title] = new Array;
               users[a.title].push(a);
               a.href = wgServer + "/wiki/User talk:" + user;
               a.innerHTML = "Talk";
               li.appendChild(a);
               if(!hasAttribute(rc, "anon"))
               {
                  li.appendChild(document.createTextNode(" | "));
                  a = document.createElement("a"); // link to user contributions list
                  a.title = "Special:Contributions/" + user;
                  a.href = wgServer + "/wiki/Special:Contributions/" + user;
                  a.innerHTML = "contribs";
                  li.appendChild(a);
               }
               li.appendChild(document.createTextNode(") "));
               var span = document.createElement("span");
               span.className = "comment";
               span.innerHTML = processComment(rc.getAttribute("comment"));
               li.appendChild(span);
               
               list.push(li);
               ul.insertBefore(li, ul.firstChild);
            }
         }
         
         // check if titles have been deleted, or if they are in `Category:Candidates for speedy deletion` or `Category:Possible copyright violations`, and set the class name
         request.abort();
         request.open("GET", wgServer + wgScriptPath + "/api.php?format=xml&action=query&prop=info|categories" +
            "&cllimit=500&titles=" + encodeURIComponent(titles.join("|")),
            false);
         request.send(null);
         if(request.responseXML)
         {
            var pages = request.responseXML.getElementsByTagName("page");
            outer: for(var i = 0; i < pages.length; i++)
            {
               var page = pages[i];
               var title = page.getAttribute("title");
               
               for(var j = 0; j < list.length; j++) // find the corresponding <li>
               {
                  if(list[j].title == title) // TO CHECK: whether the `title` parameter of new pages, as generated by the Special:NewPages page or as the attribute of an <rc>, is escaped in the same way as the `title` parameter of <page>s
                  {
                     var li = list[j];
                     if(hasAttribute(page, "missing"))
                     {
                        if(li.style.display != "none")
                        {
                           li.style.display = "none"; // hide it for now. It will eventually be deleted.
                           window.status = title + " was deleted.";
                           //window.alert(title + " was deleted.");
                        }
                     }
                     else
                     {
                        var categories = page.getElementsByTagName("cl");
                        for(var k = 0; k < categories.length; k++)
                        {
                           var title = categories[k].getAttribute("title");
                           if(title == "Category:Candidates for speedy deletion")
                           {
                              li.className = "plainlinks sdcandidate";
                              continue outer;
                           }
                           else if(title == "Category:Possible copyright violations")
                           {
                              li.className = "plainlinks possiblecopyvio";
                              continue outer;
                           }
                        }
                        
                        if(li.patrolled)
                        {
                           li.className = "plainlinks";
                           li.getElementsByTagName("a")[0].href = wgServer + "/wiki/" + encodeURIComponent(li.title) + "?easydb=1";
                        }
                        else
                        {
                           li.className = "plainlinks not-patrolled";
                           li.getElementsByTagName("a")[0].href = wgServer + "/w/index.php?title=" + encodeURIComponent(li.title) + "&rcid=" + rc.getAttribute("rcid") + "&easydb=1";
                        }
                     }
                     
                     continue outer;
                  }
               }
            }
         }
         
         // go through `users`, performing existence checks
         request.abort();
         request.open("GET", wgServer + wgScriptPath + "/api.php?format=xml&action=query&prop=info" +
            "&titles=" + encodeURIComponent(users.join("|")),
            false);
         request.send(null);
         if(request.responseXML)
         {
            var pages = request.responseXML.getElementsByTagName("page");
            for(var i = 0; i < pages.length; i++)
            {
               var page = pages[i];
               if(hasAttribute(page, "missing"))
               {
                  var arr = users[page.getAttribute("title")];
                  for(var j = 0; j < arr.length; j++)
                  {
                     arr[j].className = "new";
                  }
               }
            }
         }
      } // end `if(request.responseXML)`
      
      request.abort();
      setTimeout("updateNewPages()", wUpdateDelay);
   }
   else
      finishDisablingUpdates();
}

updateNewPages.list = new Array; // from oldest to newest
updateNewPages.request = sajax_init_object();
updateNewPages.updatesEnabled = wUpdatesEnabledByDefault;

$(function() {
   var i = window.location.href.indexOf("?");
   var queryString = (0 < i) ? window.location.href.substring(i+1) : "";

   if(wgCanonicalNamespace == "Special" && wgCanonicalSpecialPageName == "Newpages")
   {
      if(!wgPreferences.timecorrect || !wgPreferences.date || !wgPreferences.language)
      {
         wgPreferences.language = wgUserLanguage;
      
         var request = sajax_init_object();
         request.open("GET", wgServer + wgScriptPath + "/api.php?format=xml&action=query" +
            "&meta=userinfo&uiprop=options",
            false);
         request.send(null);
         if(request.responseXML)
         {
            var options = request.responseXML.getElementsByTagName("options")[0];
            wgPreferences.timecorrection = options.getAttribute("timecorrection");
            wgPreferences.date = options.getAttribute("date");
         
            if(window.wAlertSource && wgPreferences.toSource)
               window.alert("var wgPreferences = " + wgPreferences.toSource() + ";");
         }
         else
         {
            wgPreferences.timecorrection = "0:00";
         }
      }
      
      if(!wgMessages.monthNames)
      {
         wgMessages.monthNames = new Array;

         var request = sajax_init_object();
         request.open("GET", wgServer + wgScriptPath + "/api.php?format=xml&action=query" +
            "&meta=allmessages&ammessages=january|february|march|april|may|june" +
            "|july|august|september|october|november|december&amlang=" + wgPreferences.language,
            false);
         request.send(null);
         if(request.responseXML)
         {
            var messages = request.responseXML.getElementsByTagName("message");
            for(var i = 0; i < messages.length; i++)
            {
               var message = messages[i];
               var name = message.getAttribute("name");
               wgMessages[name] = message.innerText || message.textContent;
               wgMessages.monthNames.push(message.innerText || message.textContent);
            }
            
            if(window.wgMessages && wgMessages.toSource)
               window.alert("var wgMessages = " + wgMessages.toSource() + ";");
         }
         else
         {
            window.wgMessages = ({monthNames:["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], january:"January", february:"February", march:"March", april:"April", may:"May", june:"June", july:"July", august:"August", september:"September", october:"October", november:"November", december:"December"});
         }
      }
   
      var bodyContent = document.getElementById("bodyContent");
      var ul = bodyContent.getElementsByTagName("ul")[0];
      var lis = ul.getElementsByTagName("li");
      // TO DO: trim to `wRclimit`
      for(var i = 0; i < lis.length; i++)
      {
         var li = lis[i];
         var title = li.getElementsByTagName("a")[0].title.replace("_", " ");
         li.title = title;
         
         var span = li.getElementsByTagName("span")[0];
         var comment = span.innerHTML;
         // pared-processComment
         comment = comment.replace(/'''([^']*?)'''/g, "<b>$1</b>");
         comment = comment.replace(/''([^']*?)''/g, "<i>$1</i>");
         comment = comment.replace(/\{\{\s*([^|]*?)(\s*(\||&lt;!|\}))/g,
            "{"+"{<a href='" + wgServer + "/wiki/Template:$1' title='Template:$1' class='external text'>$1</a>$2");
         span.innerHTML = comment;
         
         updateNewPages.list.unshift(li); // the <li>s go from newest to oldest, so we insert at 0 each time
      }
      
      var endiUpdates = document.createElement("a");
      endiUpdates.id = "a-endiupdates";
      endiUpdates.href = "#";
      endiUpdates.style.paddingLeft = "12px";
      ul.parentNode.insertBefore(endiUpdates, ul);
      if(updateNewPages.updatesEnabled)
         enableUpdates(true);
      else
         finishDisablingUpdates();
   }
   else if(0 <= queryString.search(/(?:^|&)easydb=/i))
   {
      // TO DO: http://matt.blissett.me.uk/web/authoring/css_menus/with_javascript/
      //importScript('Wikipedia:WikiProject User scripts/Scripts/Add LI menu');
      importStylesheet("Wikipedia:WikiProject User scripts/Scripts/Add LI menu/css");
      
      var tabs = document.getElementById("p-cactions").getElementsByTagName("ul")[0];
      addlimenu(tabs, "db", "ca-db", "#", document.getElementById("ca-edit"));
      mw.util.addPortletLink("ca-db", "javascript:db('attack')", "attack", "ca-db-attack", "Serves no purpose but to disparage or threaten its subject or some other entity");
      mw.util.addPortletLink("ca-db", "javascript:db('band')", "band", "ca-db-band", "About a band, singer, musician, or musical ensemble that does not indicate the importance or significance of the subject");
      mw.util.addPortletLink("ca-db", "javascript:db('bio')", "bio", "ca-db-bio", "About a real person that does not indicate the importance or significance of the subject");
      mw.util.addPortletLink("ca-db", "javascript:db('blank')", "blank", "ca-db-blank", "Empty article, or one that consists only of external links, category tags and \"see also\" sections, a rephrasing of the title, attempts to correspond with the person or group named by its title, chat-like comments, template tags and/or images");
      mw.util.addPortletLink("ca-db", "javascript:db('nocontext')", "nocontext", "ca-db-nocontext", "Very short and lacking sufficient context to identify the subject");
      mw.util.addPortletLink("ca-db", "javascript:db('nonsense')", "nonsense", "ca-db-nonsense", "Unsalvageably incoherent with no meaningful content or history; patent nonsense");
      mw.util.addPortletLink("ca-db", "javascript:db('spam')", "spam", "ca-db-spam", "Does nothing but promote some entity and would require a fundamental rewrite in order to become encyclopedic");
      mw.util.addPortletLink("ca-db", "javascript:db('test')", "test", "ca-db-test", "Test page");
      mw.util.addPortletLink("ca-db", "javascript:db('vandalism')", "vandalism", "ca-db-vandalism", "Pure vandalism");
   }
   else if(wgAction == "edit" && /&db=([^&]*)/.test(queryString))
   {
      var code = RegExp.$1;
      var wpTextbox1 = document.getElementById("wpTextbox1");
      if(/\{\{\s*db-(\w*)\s*\}\}/.test(wpTextbox1.innerHTML))
      {
         window.alert("The article already has a speedy deletion template, `{"+"{db-" + RegExp.$1 + "}"+"}`, so `{"+"{db-" + code + "}"+"}` will not be added.");
      }
      else
      {
         wpTextbox1.style.display = "none";
         wpTextbox1.innerHTML = "{"+"{db-" + code + "}"+"}\n" + wpTextbox1.innerHTML;
         document.getElementById("wpSummary").value = "db-" + code;
         document.getElementById("wpMinoredit").setAttribute("checked", "1");
         document.getElementById("wpSave").click();
      }
   }
});

if(!window.wShowDBConfirmationDialog)
   window.wShowDBConfirmationDialog = true;

function db(code)
{
   if(!wShowDBConfirmationDialog)
   {
      window.location = wgServer + "/w/index.php?action=edit&title=" + encodeURIComponent(wgTitle) + "&db=" + code;
   }
   else if(!db.inUse)
   {
      db.inUse = true;
   
      var request = sajax_init_object();
      request.open("GET", wgServer + wgScriptPath + "/api.php?format=xml&action=parse&text={"+"{db-" + code + "}"+"}", false);
      request.send(null);
      if(request.responseXML)
      {
         var div = document.createElement("div");
         div.id = "db-confirmation-dialog";
         var text = request.responseXML.getElementsByTagName("text")[0];
         div.innerHTML = text.innerText || text.textContent;
         div.style.position = "absolute";
         div.style.zIndex = "10";
         div.style.top = "170px";
         div.style.right = "0";
         document.getElementById("bodyContent").appendChild(div);
         var tbody = div.getElementsByTagName("tbody")[0];
         
         var tr = document.createElement("tr");
         var td = document.createElement("td");
         td.style.border = "medium none";
         td.style.padding = "0px";
         td.style.width = "1px";
         tr.appendChild(td);
         
         td = document.createElement("td");
         td.align = "right";

         var button = document.createElement("button");
         button.innerHTML = "<b>Confirm</b>";
         button.onclick = function() {
            window.location = wgServer + "/w/index.php?action=edit&title=" + encodeURIComponent(wgTitle) + "&db=" + code;
         };
         button.style.marginRight = "3px";
         td.appendChild(button);
         button = document.createElement("button");
         button.innerHTML = "Cancel";
         button.onclick = function() {
            var div = document.getElementById("db-confirmation-dialog");
            div.parentNode.removeChild(div);
            db.inUse = false;
         };
         td.appendChild(button);
         
         tr.appendChild(td);
         tbody.appendChild(tr);
      }
      else
      {
         window.alert("Failed to parse `{"+"{db-" + code + "}"+"}`");
      }
   }
}