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.
//<pre>This .js is meant for all sorts of general category maintenance.

//Note: the variable names will be coalesced soon into something orderly
var subCatXML; //the xml page on which the categories are listed
var subCats; //the array containing the category names
var subCatsInDoc; //boolean array
var meow; //the category in which the inquiry is to be made
var meowCat; //the category currently being looked into
var meowDir = 'down'; //the direction in which the searching is going
var meowNav = true; // whether navigating or not
var meowQuery; //query string using query.php

if (wgNamespaceNumber == 14) {
  addOnloadHook( function() {
   var liCat = document.getElementById('t-whatlinkshere').cloneNode(true);
   aCat = liCat.firstChild;
   liCat.setAttribute('id', 't-catclear')
   aCat.setAttribute('href', 'javascript:catPageSet()')
   aCat.setAttribute('title', 'Get this category ready for clearing to lower levels')
   aCat.setAttribute('accesskey', '');
   aCat.firstChild.nodeValue = 'Put pages in subcategory';
   getElementsByClassName(document.getElementById('p-tb'), 'div', "pBody")[0].getElementsByTagName('ul')[0].appendChild(liCat);
  });
}

if ((query_get('action') == 'edit' || query_get('action') == 'submit') && query_get('kitten')) {
  addOnloadHook( function() {
   var liCat = document.getElementById('t-whatlinkshere').cloneNode(true);
   aCat = liCat.firstChild;
   liCat.setAttribute('id', 't-catsub');  
   aCat.setAttribute('href', 'javascript:catInitialize();')
   aCat.setAttribute('title', 'Get this category ready for clearing to lower levels [\\]')
   aCat.setAttribute('accesskey', '\\');
   aCat.firstChild.nodeValue = 'Put page in subcategory';
   getElementsByClassName(document.getElementById('p-tb'), 'div', "pBody")[0].getElementsByTagName('ul')[0].appendChild(liCat);
  });
}

function catPageSet() {
  if (document.getElementById('mw-pages')) {
    var startCat = prompt('From which category do you wish to start navigation? "' + wgPageName.replace(/_/g, ' ') + '" will be the default value.') || '';
    var catPages = document.getElementById('mw-pages').getElementsByTagName('a');
    var catSuffix = '&action=edit&kitten=' + encodeURIComponent(mw.config.get('wgPageName')) + (startCat ? '&start=' + encodeURIComponent(startCat.replace(/\\s/g, '_')) : '');

    for (i = 1; i < catPages.length; i++) {
      kittenPage = catPages[i];
      if (kittenPage.getAttribute('title')) {
        kittenPage.href = mw.config.get('wgServer') + mw.config.get('wgScriptPath') + '/index.php?title='+encodeURIComponent( kittenPage.getAttribute('title'))+catSuffix;
        kittenPage.style.color = '#633';
        kittenPage.onmouseup = function() { this.style.color = '#393' }
      }
    }
  }
  else {
    alert('No pages in category.');
  }
}

function catInitialize() {
  meow = query_get('kitten').replace(/_/g, ' ');
  meowCat = query_get('start').replace(/_/g, ' ') || meow;
  getSubCats()
}

function getSubCats() {
  meowQuery = wgServer + wgScriptPath
  switch (meowDir) {
    case 'down': meowQuery += '/query.php?what=category&cptitle=' + encodeURI(meowCat) + '&cpnamespace=14&format=xml&cplimit=100';
                 break;
    case 'up': meowQuery += '/query.php?what=categories&titles=' + encodeURI(meowCat) + '&clextended&format=xml';
               break;
  }
  subCats = [];
  subCatsInDoc = [];
  try {
    subCatsXML = sajax_init_object();
    if (subCatsXML.overrideMimeType) subCatsXML.overrideMimeType('text/xml');
    subCatsXML.onreadystatechange = getSubCatContent;
    subCatsXML.open('GET', meowQuery, true );
   subCatsXML.send(null);
 } catch(ohNoesHayUnError) {}
}

//parses results of ajax query and sorts subcategory names, A-Z
function getSubCatContent() {
  if (subCatsXML.readyState != 4) {
    return;
  } 

  if(subCatsXML.status != 200) {
    alert ('There was an error.');
    return;
  }

  var XMLdoc = subCatsXML.responseXML.documentElement;

  if(!XMLdoc) {
    return;
  }

  if(!XMLdoc.getElementsByTagName('pages')) {
    alert('Category not found.')
    return;
  }
  //make an array of all of the categories
  var subCatXMLarray = XMLdoc.getElementsByTagName(meowDir == 'down' ? 'title' : 'cl');
  var SCXAlength = subCatXMLarray.length;
  for (i = 0; i < SCXAlength; i++) {
    subCats[subCats.length] = subCatXMLarray[i].firstChild.nodeValue; //.substring('9');
    //the following involves the document rather than the XML, so meh, but it works
    subCatsInDoc[subCatsInDoc.length] = new RegExp(subCats[i], 'i').test(document.getElementById('wpTextbox1').value)
  }

  subCats.sort();
  navigation();
}

function navigation() {
  var catString;
  if (meowDir == 'down') {
    if (subCats[0] != '' && subCats[0]) {
      catString = 'This is a list of categories below ' + meowCat + '. Please type the identification number of a category in order to view more information about it, or select it for replacement.\n\n-1. Select a category above ' + meowCat + ' to which you want to navigate.\n0. Replace ' + meow + ' with ' + meowCat + ' in this document.\n';
    }
    else {
      catString = meowCat + ' has no subcategories. You can:\n\n-1. View the categories above ' + meowCat + '\n0. Replace ' + meow + ' with ' + meowCat;
    }
  }
  else {
    if (subCats[0] != '' && subCats[0]) {
      catString = meowCat + ' is a subcategory of the following categories. Select the identification number of a category.\n\n0. Replace ' + meow + ' with ' + meowCat + '\n';
    }
    else {
      catString = meowCat + ' is an uncategorized category. Whatever.';
    }
  }
  for (i = 0; i < subCats.length; i++) {
    catString += (i+1) + '. ' + subCats[i] + (subCatsInDoc[i] ? ' (already in document)' : '') + '\n';
  }
  var replaceCat = prompt(catString);

  if (replaceCat == -1) {
    meowDir = 'up';
    getSubCats();
  }
  else if (replaceCat == 0) {
    textReplaceCat(meow.substring('9'), meowCat.substring('9'));
  }
  else if (replaceCat != NaN) {
    if (subCats[0] == '' || !subCats[0]) {
      navigation();
      return;
    }
    meowCat = subCats[replaceCat - 1];
    meowDir = 'down'
    if (meowCat) {
      getSubCats();
    } else {
      return;
    }
  }
  else {
    return;
  }
}

function textReplaceCat(oldCat, newCat) {
  var catValue = document.getElementById( 'wpTextbox1' ).value.replace(new RegExp('[[Category:[\\s]*'+oldCat+'(]]|\\|)', 'gi'), '\n[[Category:'+newCat+'$1');
  document.getElementById('wpTextbox1').value = catValue;
  document.getElementById('wpSummary').value = 'Replacing [[Category:' + oldCat + ']] with [[Category:' + newCat + ']]';
  document.getElementById('wpDiff').click();
}

//regex written by Lupin; capturing parentheses capture parameter name of query
function query_get(paramName) {
  var cmdRe=RegExp('[&?]'+paramName+'=([^&]*)');
  var h=document.location;
  var m;
  if (m=cmdRe.exec(h)) {
    try { 
      return decodeURIComponent(m[1]);
    } catch (someError) {}
  }
  return null;
}

//</pre>