Misplaced Pages

User:Cryptic/cologneblue.js: Difference between revisions

Article snapshot taken from Wikipedia with creative commons attribution-sharealike license. Give it a read and then ask your questions in the chat. We can research this topic together.
< User:Cryptic Browse history interactively← Previous editContent deleted Content added
Revision as of 17:51, 22 February 2020 view sourceCryptic (talk | contribs)Administrators41,692 edits Run styling changes both immediately (in an attempt to prevent FOUC) and when dom is complete (to be sure it affects all entities)← Previous edit Latest revision as of 17:55, 17 December 2024 view source Cryptic (talk | contribs)Administrators41,692 editsm
(41 intermediate revisions by the same user not shown)
Line 76: Line 76:


// Add links for Logs, Current version, Enable rollback. // Add links for Logs, Current version, Enable rollback.
// Restore Talk: and non-Talk: links to the footer for pages not in namespaces besides Article: and Talk:.
// Fix the non-Talk: link in namespace Talk:, which normally goes to itself (!)
// Copy the more-informative label for Undelete on the (hidden) left navbar to the Undelete link on the bottom. // Copy the more-informative label for Undelete on the (hidden) left navbar to the Undelete link on the bottom.
// If there's a template providing a default delete reason, display that in a delete link at the bottom, retaining the no-reason delete link. // If there's a template providing a default delete reason, display that in a delete link at the bottom, retaining the no-reason delete link.
Line 82: Line 84:
function morelinks() function morelinks()
{ {
// Talk/non-Talk links. I don't want to speculate on the moon logic that removed them from every namespace *except* 0 and 1.
// Since they're still present for namespaces 0 and 1, be sure to put them in the same place those appear (after "Watch"), instead of before Protect like I'll do for the others.
var watch = document.getElementById("ca-cb-watch") || document.getElementById("ca-cb-unwatch");
if (watch)
{
var ns = mw.config.get('wgNamespaceNumber');
var title = mw.config.get('wgTitle');
// not negative namespaces (Special: and Media:), and don't duplicate in namespaces 0 and 1
if (ns > 1)
{
// I'd use mw.config.get('wgFormattedNamespaces'), except it's not always there in time. At least not in greasemonkey, where I'm prototyping this so folks can only point and laugh at a *working* illiterate version of it instead of broken ones.
var ns_title = mw.config.get('wgCanonicalNamespace');
ns_title = ns_title.replace(/^Project/, 'Misplaced Pages'); // 4/5, the only ones we localize

var parent = watch.parentNode;

// Contributions and Block links
if (ns == 2 || ns == 3)
{
var basetitle = title.replace(/\/.*/, '');
addexplicitlink("/search/?title=" + encodeURIComponent('Special:Contributions/' + basetitle),
'Contribs', parent, watch.nextSibling);
pipe(parent, null, watch.nextSibling);
addexplicitlink("/search/?title=" + encodeURIComponent('Special:Block/' + basetitle),
'Block', parent, watch.nextSibling);
pipe(parent, null, watch.nextSibling);
}

var linkname;
if (ns % 2)
{
ns -= 1;
ns_title = ns_title.replace(/_talk$/, '');
linkname = ns_title;
}
else
{
ns += 1;
ns_title += '_talk';
linkname = "Talk";
}

addexplicitlink("/search/?title=" + encodeURIComponent(ns_title + ':' + title),
linkname, parent, watch.nextSibling);
pipe(parent, null, watch.nextSibling);
}
else if (ns == 1) // there's still a link in the Talk: namespace... but it's to the *same page*, and titled Talk. Doesn't anyone ever look at this stuff before deploying it?
{
var lk = document.getElementById('ca-cb-talk').firstChild;
if (lk.nodeName == 'A')
{
lk.href = "/search/?title=" + encodeURIComponent(title);
var txt = lk.firstChild;
if (txt.nodeName == '#text')
txt.nodeValue = 'Article';
}
}
}

var enable_rollback_txt = "var head=document.getElementsByTagName('head');" var enable_rollback_txt = "var head=document.getElementsByTagName('head');"
+ "var style=document.createElement('style');" + "var style=document.createElement('style');"
Line 90: Line 151:
// If there's a protect link, add link for Logs and Current version. // If there's a protect link, add link for Logs and Current version.
// Always add a link for Enable rollback. // Always add a link for Enable rollback.
var protect = document.getElementById("cb-ca-unprotect"); var protect = document.getElementById("ca-cb-unprotect");
if (!protect) if (!protect)
protect = document.getElementById("cb-ca-protect"); protect = document.getElementById("ca-cb-protect");
if (protect) if (protect)
{ {
var parent = protect.parentNode; var parent = protect.parentNode;


pipe(parent, null, protect);
addexplicitlink("/search/?title=Special:Log&page=" + encodeURIComponent(mw.config.get('wgPageName')), addexplicitlink("/search/?title=Special:Log&page=" + encodeURIComponent(mw.config.get('wgPageName')),
'Logs', parent, protect); 'Logs', parent, protect);
pipe(parent, null, protect);


pipe(parent, null, protect);
addexplicitlink("/search/?title=" + encodeURIComponent(mw.config.get('wgPageName')), addexplicitlink("/search/?title=" + encodeURIComponent(mw.config.get('wgPageName')),
'Curr', parent, protect); 'Curr', parent, protect);

pipe(parent, null, protect); pipe(parent, null, protect);

addlink_onclick(enable_rollback_txt, 'Enable rollback', parent, protect); addlink_onclick(enable_rollback_txt, 'Enable rollback', parent, protect);
pipe(parent, null, protect);
} }
else else
{ {
var parent = document.getElementById("searchform-footer").parentNode; var parent = document.getElementById("searchform-footer").parentNode;

pipe(parent);
addlink_onclick(enable_rollback_txt, 'Enable rollback', parent); addlink_onclick(enable_rollback_txt, 'Enable rollback', parent);
} }




var del = document.getElementById("cb-ca-undelete"); var del = document.getElementById("ca-cb-undelete");
if (!del) if (!del)
{ {
del = document.getElementById("cb-ca-delete"); del = document.getElementById("ca-cb-delete");
if (del) if (del)
{ {
Line 160: Line 219:
delete_reason += " to ]"; delete_reason += " to ]";
break; break;
}
}
else if (node.tagName == 'P' && node.firstChild)
{
var n = node.firstChild;
if (n.textContent && n.textContent.match(/^\s*#redirect\s*$/i))
{
n = n.nextSibling;
if (n.tagName == 'A')
{
delete_reason += " to ]";
break;
}
} }
} }
Line 185: Line 257:
&& node.firstChild.nextSibling.firstChild.nodeName == '#text' && node.firstChild.nextSibling.firstChild.nodeName == '#text'
&& node.firstChild.nextSibling.firstChild.nodeValue.match(/^redirect *$/i) && node.firstChild.nextSibling.firstChild.nodeValue.match(/^redirect *$/i)
&& node.firstChild.nextSibling.firstChild.nextSibling.tagName == 'A' && node.firstChild.nextSibling.firstChild.nextSibling.tagName == 'A')
&& node.firstChild.nextSibling.firstChild.nextSibling.className == 'new') node = node.firstChild.nextSibling.firstChild.nextSibling;
node = node.firstChild.nextSibling.firstChild.nextSibling.firstChild;
else if (node.tagName == 'DIV' else if (node.tagName == 'DIV'
&& node.className == 'redirectMsg' && node.className == 'redirectMsg'
Line 196: Line 267:
&& node.firstElementChild.nextElementSibling.firstChild.tagName == 'LI' && node.firstElementChild.nextElementSibling.firstChild.tagName == 'LI'
&& node.firstElementChild.nextElementSibling.firstChild.firstChild && node.firstElementChild.nextElementSibling.firstChild.firstChild
&& node.firstElementChild.nextElementSibling.firstChild.firstChild.tagName == 'A' && node.firstElementChild.nextElementSibling.firstChild.firstChild.tagName == 'A')
&& node.firstElementChild.nextElementSibling.firstChild.firstChild.className == 'new') node = node.firstElementChild.nextElementSibling.firstChild.firstChild;
node = node.firstElementChild.nextElementSibling.firstChild.firstChild.firstChild;
else else
continue; continue;


delete_reason = "]: Redirect to a deleted or nonexistent page: ]"; if (node.className == 'new')
delete_reason = "]: Redirect to a deleted or nonexistent page: ]";
else if (node.firstChild.nodeValue.match(/^(Talk|(Draft|User)(talk)?):/i))
delete_reason = "]: ] from mainspace to ]";
else
break;


addexplicitlink(del.firstChild.href + "&wpReason=" + encodeURIComponent(delete_reason), addexplicitlink(del.firstChild.href + "&wpReason=" + encodeURIComponent(delete_reason),
Line 224: Line 299:


// If a template, wikilink, or external link appears in a diff, make it clickable // If a template, wikilink, or external link appears in a diff, make it clickable
function link_links_in_diffs() function link_links_dim_refs_in_diffs()
{ {
var tds = document.getElementsByTagName('td'); var tds = document.getElementsByTagName('td');


for (var i = 0; i < tds.length; ++i) for (var i = 0; i < tds.length; ++i)
{
if (tds.className == 'diff-deletedline' || tds.className == 'diff-addedline' || tds.className == 'diff-context')
var classes = tds.className.split(' ');
{
var txt = tds.innerHTML.replace(new RegExp('(\\ <]+)( ])', 'gi'), '$1<a href="$2">$2</a>$3');
txt = txt.replace(new RegExp('\\{\\{((?:talk|user|wikipedia|image|mediawiki|template|help|category|portal)(?:talk)?:+)()', 'gi'), '{{<a href="https://en.wikipedia.org/$1">$1</a>$2');
txt = txt.replace(new RegExp('\\{\\{(+)()', 'g'), '{{<a href="https://en.wikipedia.org/Template:$1">$1</a>$2');
txt = txt.replace(new RegExp('(\\|<]+)(|])', 'g'), '$1<a href="https://en.wikipedia.org/$2">$2</a>$3');
tds.innerHTML = txt.replace(new RegExp('(\\|]*<SPAN class="*">:?)(|<]+)(</SPAN>|])', 'gi'), '$1<a href="https://en.wikipedia.org/$2">$2</a>$3');
}
}


for (var j = 0; j < classes.length; j++)
if (classes == 'diff-context' || classes == 'diff-addedline' || classes == 'diff-deletedline')
{
var txt = tds.innerHTML;


if (txt.indexOf("&@<my") < 0)
// If a ref appears in a diff page but isn't changed, dim it out and make it smaller so it doesn't distract from text
{
function dim_refs_in_diffs()
txt = txt.replace(new RegExp('<(/?(del|ins)( class="*")?)>', 'g'), '&@<mybra;$1&@<myket;');
{
txt = txt.replace(new RegExp('(&lt;ref*?(/&gt;|\\bref\\b( *&gt;)?))', 'gi'), '<span style="opacity:0.25; font-size:x-small !important;">$1</span>');
var tds = document.getElementsByTagName('td');
txt = txt.replace(new RegExp('&@<mybra;', 'g'), '<');
txt = txt.replace(new RegExp('&@<myket;', 'g'), '>');
}


txt = txt.replace(new RegExp('(\\ <]+)( ])', 'gi'), '$1<a href="$2">$2</a>$3');
for (var i = 0; i < tds.length; ++i)
txt = txt.replace(new RegExp('\\{\\{((?:talk|user|wikipedia|image|mediawiki|template|help|category|portal)(?:talk)?:+)()', 'gi'), '{{<a href="https://en.wikipedia.org/$1">$1</a>$2');
if (tds.className == 'diff-deletedline' || tds.className == 'diff-addedline' || tds.className == 'diff-context')
txt = txt.replace(new RegExp('\\{\\{(\\s*(?:tlsp|lts|tl?)\\s*\\|\\s*|\\s*)(+)()', 'g'), '{{$1<a href="https://en.wikipedia.org/Template:$2">$2</a>$3');
{
function enwikilk(match, p1, p2, p3){ return p1 + '<a href="https://en.wikipedia.org/' + p2.replace(/ +/g, '_') + '">' + p2 + '</a>' + p3; };
var txt = tds.innerHTML;
txt = txt.replace(new RegExp('(\\|<]+)(|])', 'g'), enwikilk);
if (txt.indexOf("&@my") != -1)
txt = txt.replace(new RegExp('(\\|]*<SPAN class="*">:?)(|<]+)(</SPAN>|])', 'gi'), enwikilk);
continue;
txt = txt.replace(new RegExp('<(/?(del|ins)( class="*")?)>', 'g'), '&@mybra;$1&@myket;'); txt = txt.replace(new RegExp('\\b(url\\s*=\\s*)(https?://|{} <>]+?)(\\s*(\\||\\}\\}))', 'gi'), '$1<a href="$2">$2</a>$3');

txt = txt.replace(new RegExp('(&lt;ref*?(/&gt;|\\bref\\b( *&gt;)?))', 'gi'), '<span style="color:#cccccc !important; font-size:x-small !important;">$1</span>');
tds.innerHTML = txt;
txt = txt.replace(new RegExp('(url *= *)(http:\\/\\/\\|\\} <]+?)( *(\\||\\}\\}|</div>$))', 'gi'), '$1<a href="$2">$2</a>$3');
txt = txt.replace(new RegExp('&@mybra;', 'g'), '<'); break;
}
txt = txt.replace(new RegExp('&@myket;', 'g'), '>');
}
tds.innerHTML = txt;
}
} }


Line 305: Line 379:
{ {
cesarb_fixDiffOverflowTable(table); cesarb_fixDiffOverflowTable(table);
dim_refs_in_diffs(); link_links_dim_refs_in_diffs();
link_links_in_diffs();
break loop; break loop;
} }
Line 334: Line 407:
* the same place. * the same place.
* 3. Whenever an item is selected from the dropdownlist, immediately insert it * 3. Whenever an item is selected from the dropdownlist, immediately insert it
* into the "Additional reasons" input for further editing, then reselect * into the "Additional reasons" input for further editing, then reselect the
* "Other reason". * first option.
* 4. Add a button to clear the reason line. * 4. Add a button to clear the reason line.
* 5. If a preset deletion reason, or adding reasons from the dropdownlist, * 5. If a preset deletion reason, or adding reasons from the dropdownlist,
Line 352: Line 425:
if (delreason) if (delreason)
{ {
var p = delreason.parentNode; var p = delreason.parentNode; // "You are about to delete ] along with all of its history. Please:"
var ul = p.previousElementSibling; var ul = p.previousElementSibling; // "*Confirm...", "*Review...", "*Check...", "*Provide..."
if (ul.nodeName == 'UL') if (ul.nodeName == 'UL')
{ {
p = ul.previousElementSibling; p = ul.previousElementSibling;
var div = p.previousElementSibling; // "WARNING: Other pages link to..." Duh. *Always* present, because of the user pages that uselessly transclude ].
if (p.nodeName == 'P') if (p.nodeName == 'P')
{ {
Line 362: Line 436:
ul.parentNode.removeChild(ul); ul.parentNode.removeChild(ul);
} }
if (div && div.nodeName == 'DIV')
div.parentNode.removeChild(div);
} }
} }
Line 368: Line 444:
//$(".oo-ui-dropdownInputWidget").removeClass("oo-ui-dropdownInputWidget"); //$(".oo-ui-dropdownInputWidget").removeClass("oo-ui-dropdownInputWidget");
//$(".oo-ui-dropdownInputWidget-php").removeClass("oo-ui-dropdownInputWidget-php"); //$(".oo-ui-dropdownInputWidget-php").removeClass("oo-ui-dropdownInputWidget-php");

/* Expand the whole list. We actually create a new one, copy the elements /* Expand the whole list. We actually create a new one, copy the elements
* from the old one into there, and hide the old one, to minimize interference * from the old one into there, and hide the old one, to minimize interference
* from hostile developers. */ * from hostile developers. */
var nsel = document.createElement('select'); var nsel = document.createElement('select');

var len = 0; var len = 0;

// Create an empty option to keep selected, since "Other reason" was removed
function add_option(grp, lbl)
{
var nop = document.createElement('option');
nop.value = lbl;
nop.appendChild(document.createTextNode(lbl));
grp.appendChild(nop);
return 1;
};
len += add_option(nsel, '');

var g1_seen = 0;
var optgroups = reasons.getElementsByTagName('optgroup'); var optgroups = reasons.getElementsByTagName('optgroup');
for (var i = 0; i < optgroups.length; ++i) for (var i = 0; i < optgroups.length; ++i)
{ {
var og = optgroups; var og = optgroups;
/* Skip the oversighter-only section (how come it's displayed to // Skip the talk section (we put it with the primary g8)
if (!og.label.match(/talk pages/i))
* everyone?) - obviously this is very fragile */
{
if (og.label != "FOR USE BY OVERSIGHTERS ONLY, when suppressing privacy and defamation:")
var nog = document.createElement('optgroup');
{
nog.label = og.label;
var nog = document.createElement('optgroup');
nsel.appendChild(nog);
nog.label = og.label;
++len;
nsel.appendChild(nog);
++len;


var options = og.getElementsByTagName('option'); var options = og.getElementsByTagName('option');
for (var j = 0; j < options.length; ++j) for (var j = 0; j < options.length; ++j)
{ {
var txt = options.value; var txt = options.value;
/* Entirely the wrong place to try to teach admins which articles
* can be A7d; the text for U5 is vague and antagonistic; and add
* same advice to G7 and U1 that db-g7 and db-u1 do */
if (txt.match(/^\\].+/))
txt = txt.replace(/ \(indiv.+/, '');
else if (txt.match(/^\\].+/))
txt = txt.replace(/Misuse of Misplaced Pages as a web host/, "Writings unrelated to Wikimedia's goals, by a user with few or no edits outside of userspace");
else if (txt.match(/^\\].+/))
txt = txt.replace(/Cross-\\] \\]/, "]");
else if (txt.match(/^\\].+/))
txt = txt + " – If you wish to retrieve it, please see ]";
else if (txt.match(/^\\].+/))
txt = txt.replace(/to retrieve it, see/, "If you wish to retrieve it, please see");
else if (txt.match(/^\\].+/))
txt = txt.replace(/ or \\] submission/, '');


// enable G1 and G2 in all namespaces, to be used in extremis
var nop = document.createElement('option');
if (txt.match(/^\\].+/))
nop.value = txt;
g1_seen = 1;
nop.appendChild(document.createTextNode(txt));
else if (txt.match(/^\\].+/) && !g1_seen)
nog.appendChild(nop);
++len; {
len += add_option(nog, "]: ], meaningless, or incomprehensible");
}
len += add_option(nog, "]: Test page");
}
g1_seen = 1; // so it isn't added again on the next g3
}

// add G8 talk pages right before g10 (in particular, so it isn't removed for user talk subpages)
else if (txt.match(/^\\].+/))
len += add_option(nog, "]: Talk page of a nonexistent or deleted page");

// essentially all G13s are drafts now, not afc-templated user subpages
else if (txt.match(/^\\].+/))
txt = txt.replace(/ or \\] submission/, '');

// Entirely the wrong place to try to teach admins which articles can be A7d
else if (txt.match(/^\\].+/))
txt = txt.replace(/ \(indiv.+/, '');

// the text for U5 is vague and antagonistic
else if (txt.match(/^\\].+/))
txt = txt.replace(/Misuse of Misplaced Pages as a web host/, "Writings unrelated to Wikimedia's goals, by a user with few or no edits outside of userspace");

// more specific link for R2
else if (txt.match(/^\\].+/))
txt = txt.replace(/Cross-\\] \\]/, "]");

len += add_option(nog, txt);
}
}
} }


Line 423: Line 522:


// Move the additional reason input, watch checkbox, and delete button above it, so they're always in the same place // Move the additional reason input, watch checkbox, and delete button above it, so they're always in the same place
var reasonrow; var reason;
var deletebutton; var deletebutton;
var imgtable = document.getElementById('mw-img-deleteconfirm-table'); var imgtable = document.getElementById('mw-img-deleteconfirm-table');
if (imgtable) if (imgtable)
{ {
reasonrow = imgtable.getElementsByTagName('tr'); reason = imgtable.getElementsByTagName('tr'); // probably not, but I'll worry about it the next time I delete an image
reason.id = 'actual_reason';
deletebutton = imgtable.getElementsByTagName('tr').getElementsByClassName('mw-submit').firstElementChild; deletebutton = imgtable.getElementsByTagName('tr').getElementsByClassName('mw-submit').firstElementChild;
} }
else else
{ {
reasonrow = document.getElementById('wpReason'); reason = document.getElementById('wpReason').firstChild;
reason.id = 'actual_reason';
deletebutton = document.getElementById('wpConfirmB'); deletebutton = document.getElementById('wpConfirmB');
} }
Line 440: Line 541:
spacer.style = "margin-left:1em"; spacer.style = "margin-left:1em";


var watch = document.getElementById('wpWatch').parentNode.parentNode; var watch = document.getElementById('wpWatch').parentNode;
var watchlabel = watch.nextElementSibling; var watchlabel = watch.nextElementSibling;


var clearbutton = makebutton('clear', var clearbutton = makebutton('clear',
'var reason = document.getElementById("wpReason");' 'var reason = document.getElementById("actual_reason");'
+ 'reason.value="";' + 'reason.value="";'
+ 'reason.style="background-color:white";' + 'reason.style="background-color:white";'
Line 455: Line 556:
div.appendChild(watchlabel); div.appendChild(watchlabel);
div.appendChild(clearbutton); div.appendChild(clearbutton);
div.appendChild(reasonrow); div.appendChild(reason);
div.appendChild(nsel); div.appendChild(nsel);


for (var n = root.firstChild; n; n = n.nextChild) for (var n = root.firstChild; n; n = n.nextSibling)
n.style.display='none'; n.style.display='none';


Line 468: Line 569:
nsel.onchange = function() nsel.onchange = function()
{ {
var reason = document.getElementById('wpReason'); var reason = document.getElementById('actual_reason');
var sel = this.selectedIndex; var sel = this.selectedIndex;
if (sel != 0) // 0 is "Other reason" if (sel != 0) // 0 is "Other reason"
Line 487: Line 588:
/* And set initial value of wpWatch for c1/g7/g8/g13/u1. If initially g8, and /* And set initial value of wpWatch for c1/g7/g8/g13/u1. If initially g8, and
* deleting a talk page, then don't change watched status. */ * deleting a talk page, then don't change watched status. */
var reasonv = document.getElementById('wpReason').value; var reasonv = document.getElementById('actual_reason').value;
if (reasonv.match(/^\alk page.*of a (deleted|non.?exist)/)) if (reasonv.match(/^\alk page.*of a (deleted|non.?exist)/))
document.getElementById('wpWatch').checked = !!document.getElementById("cb-ca-unwatch"); document.getElementById('wpWatch').firstChild.checked = !!document.getElementById("ca-cb-unwatch");
else else
document.getElementById('wpWatch').checked = should_watch(reasonv); document.getElementById('wpWatch').firstChild.checked = should_watch(reasonv);


/* Whenever anything forces the length of the additional-reasons input above /* Whenever anything forces the length of the additional-reasons input above
* its max, change its background color */ * its max, change its background color */
var reason = document.getElementById('wpReason');
reason.oninput = function(){ check_reason_length(this); }; reason.oninput = function(){ check_reason_length(this); };


Line 528: Line 628:
} }


// Add "ahah" links to watchlist - "all histories above here" // Add "ahah" links to watchlist - "all histories above here".
// Also makes the "diff" links on watchlist match those on the history page, so marking the one visited changes the color of the other.
function addahah() function addahah()
{ {
Line 536: Line 637:
{ {
if (as.innerHTML == 'diff') if (as.innerHTML == 'diff')
as.href = as.href.replace(/&curid=+/, ''); as.href = as.href.replace(/&curid=+&diff=(+)&oldid=+/, '&diff=prev&oldid=$1');
else if (as.innerHTML == 'hist') else if (as.innerHTML == 'hist')
{ {
Line 580: Line 681:
for (var li = wlh.firstChild; li; li = li.nextSibling) for (var li = wlh.firstChild; li; li = li.nextSibling)
if (li.firstChild if (li.firstChild
&& li.firstChild.href && li.firstChild.firstChild
&& li.firstChild.href.indexOf('&redirect=no') != -1 && li.firstChild.firstChild.href
&& li.firstChild.nextSibling.nodeValue.indexOf('(redirect page)') != -1) && li.firstChild.firstChild.href.indexOf('&redirect=no') != -1
&& (li.firstChild.nextSibling.nodeValue.indexOf('(redirect page)') != -1
|| li.firstChild.nextSibling.nodeValue.indexOf('(redirect to section ') != -1))
{ {
if (!tgt) if (!tgt)
tgt = "&action=delete&wpReason=" tgt = "&action=delete&wpReason="
+ encodeURIComponent("]: Redirect to a deleted or nonexistent page: ]").replace('%20', '+', 'g') + encodeURIComponent("]: Redirect to a deleted or nonexistent page: ]").replace('_', '+', 'g').replace('%20', '+', 'g')
+ "&action=delete"; + "&action=delete";


var newnode = addexplicitlink(li.firstChild.href + tgt, 'delete G8'); var newnode = addexplicitlink(li.firstChild.firstChild.href + tgt, 'delete G8');
// Place on the same line, whether there are incoming links to this redirect or not // Place on the same line, whether there are incoming links to this redirect or not
var x; var x;
Line 639: Line 742:
if (footer) if (footer)
for (var n = footer.firstChild; n; n = n.nextSibling) for (var n = footer.firstChild; n; n = n.nextSibling)
{
if (n.tagName == 'A' && n.href.indexOf('Misplaced Pages:About') > 0)
{ if (n.tagName == 'BR')
var span = document.createElement('span'); n.style.display = 'none';
else if (n.tagName == 'UL')
span.appendChild(document.createTextNode(new Date().toUTCString()));
span.setAttribute('onClick', 'this.firstChild.textContent = new Date().toUTCString();'); for (var nn = n.firstChild; nn; nn = nn.nextSibling)
if (nn.firstChild && nn.firstChild.tagName == 'A' && nn.firstChild.href.indexOf('Misplaced Pages:About') > 0)
footer.insertBefore(span, n);
footer.removeChild(n);
break;
}
}


// Add a "reduced" button when editing File: pages to edit away ]
function add_reduced_button()
{
if (document.editform.wpTextbox1.value.match(/\{\{(on-free reduced|rphaned non-free revisions) *(\|*)*\}\}/))
{
var button = makebutton('reduced',
'var old = document.editform.wpTextbox1.value;'
+ 'var s = old;'
+ 's = s.replace(/^*\\{\\{(on-free reduced|rphaned non-free revisions) *(\\|*)*\\}\\}*/g, "");'
+ 's = s.replace(/^\\{\\{(on-free reduced|rphaned non-free revisions) *(\\|*)*\\}\\}?/gm, "");'
+ 's = s.replace(/^\\{\\{(on-free reduced|rphaned non-free revisions) *(\\|*)*\\}\\}/g, "");'
+ 'if (s != old)'
+ ' {'
+ ' document.editform.wpTextbox1.value = s;'
+ ' document.editform.wpSummary.value = "Previous version removed";'
+ ' document.getElementById("wpWatchthis").checked = 0;'
+ ' document.editform.wpSummary.focus();'
+ ' }');
var first = document.getElementById('firstHeading');
first.appendChild(button, first.nextSibling);
var button2 = makebutton('reducemore',
'var old = document.editform.wpTextbox1.value;'
+ 'var s = old;'
+ 's = s.replace(/^*\\{\\{(on-free reduced|rphaned non-free revisions) *(\\|*)*\\}\\}*/g, "");'
+ 's = s.replace(/^\\{\\{(on-free reduced|rphaned non-free revisions) *(\\|*)*\\}\\}?/gm, "");'
+ 's = s.replace(/^\\{\\{(on-free reduced|rphaned non-free revisions) *(\\|*)*\\}\\}/g, "");'
+ 's = "{{non-free reduce}}\\n" + s;'
+ 'if (s != old)'
+ ' {'
+ ' document.editform.wpTextbox1.value = s;'
+ ' document.editform.wpSummary.value = "Previous version removed; but current version needs size reduction per ]";'
+ ' document.getElementById("wpWatchthis").checked = 1;'
+ ' document.editform.wpSummary.focus();'
+ ' }');
first.appendChild(button2, first.nextSibling.nextSibling);
}
}


// Add a link to delete all but the current revision of a file
function add_del_prev_revisions()
{
var filehistory = document.getElementById("filehistory");
if (!filehistory)
return;

var target = '';
var ids = '';

var spans = document.getElementsByTagName("span");
for (var i = 0; i < spans.length; ++i)
{
var span = spans;
var classes = span.className.split(' ');
for (var j = 0; j < classes.length; ++j)
if (classes == 'mw-revdelundel-link')
{
var a = span.firstChild.nextSibling;
if (a && a.title == 'Special:RevisionDelete')
{ {
var matches = a.href.match("&ids=(+)$"); var span = document.createElement('span');
if (matches) span.appendChild(document.createTextNode(new Date().toUTCString()));
span.setAttribute('onClick', 'this.firstChild.textContent = new Date().toUTCString();');
{
if (target == '') var olda = nn.firstChild;
{ nn.insertBefore(span, olda);
target = a.href; nn.removeChild(olda);
ids = matches; return;
}
else
{
target += ',';
target += matches;
ids += ',';
ids += matches;
}
}
} }
break; }
}
}

if (target != '')
{
pipe(filehistory, ' - ');
addexplicitlink(target + '&wpReason=' + encodeURIComponent(']: Orphaned revision of nonfree media'),
'Delete revisions ' + ids,
filehistory);
}
}


// Autoselect "delete file content" at ] if we preselected the deleting-orphan-revisions reason
function revision_delete_stuff()
{
var reason = document.getElementById('wpReason');
if (reason && reason.value == ']: Orphaned revision of nonfree media')
{
var radios = document.getElementsByName('wpHidePrimary');
if (radios.length == 1) // one revision
radios.checked = 1;
else if (radios.length == 3) // two or more revisions
radios.checked = 1;
reason.focus(); // so I can just hit enter to confirm
}

// Edit link
var n = document.getElementById('firstHeading');
n = n.nextElementSibling.nextElementSibling;
var hist = n.firstElementChild.nextElementSibling;
if (hist && hist.nodeName == 'A' && hist.href.match(/&action=history$/))
{
pipe(n);
addexplicitlink(hist.href.replace(/action=history$/,"action=edit"), 'Edit', n);
}
} }


Line 813: Line 806:
{ {
var watched = false; var watched = false;
var bot = document.getElementById("cb-ca-watch"); var bot = document.getElementById("ca-cb-watch");
if (!bot) if (!bot)
{ {
bot = document.getElementById("cb-ca-unwatch"); bot = document.getElementById("ca-cb-unwatch");
if (!bot) if (!bot)
return; return;
Line 854: Line 847:
var div = document.getElementById('mw-category-media'); var div = document.getElementById('mw-category-media');
if (div) if (div)
for (var ul = div.firstChild; ul; ul = ul.nextSibling) for (var ul = div.firstChild; ul; ul = ul.nextSibling)
if (ul.tagName == 'UL' && ul.className.indexOf('mw-gallery-traditional') >= 0) if (ul.tagName == 'UL' && ul.className.indexOf('mw-gallery-traditional') >= 0)
{ {
var count = 0; var count = 0;
var first = 0; var first = 0;
for (var node = ul.firstChild; ; node = node.nextSibling) for (var node = ul.firstChild; ; node = node.nextSibling)
{
{
if (node && node.tagName == 'LI') if (node && node.tagName == 'LI')
if (++count == 1) if (++count == 1)
first = node; first = node;


if (count == 11 || (!node && count != 0)) if (count == 11 || (!node && count != 0))
{ {
var newnode = document.createElement("br"); var newnode = document.createElement("br");
ul.insertBefore(newnode, first); ul.insertBefore(newnode, first);
newnode = document.createElement("a"); newnode = document.createElement("a");
newnode.setAttribute("onClick", "var i,n=this;for(i=0;i<"+count+";++i){n=n.nextSibling;if(!n)break;if(n.tagName!='LI'){n=n.nextSibling;if(!n)break;}window.open(n.firstChild.firstChild.nextSibling.firstChild.firstChild.href,'_blank');}"); newnode.setAttribute("onClick", "var i,n=this;for(i=0;i<"+count+";++i){n=n.nextSibling;if(!n)break;if(n.tagName!='LI'){n=n.nextSibling;if(!n)break;}window.open(n.firstChild.firstChild.nextSibling.firstChild.firstChild.href,'_blank');}");
newnode.setAttribute("href", "#"); newnode.setAttribute("href", "#");
newnode.appendChild(document.createTextNode('>>')); newnode.appendChild(document.createTextNode('>>'));
ul.insertBefore(newnode, first); ul.insertBefore(newnode, first);
count = 0; count = 0;
first = 0; first = 0;
} }


if (!node) if (!node)
break; break;
}
}
} }
} }


Line 893: Line 886:
var div = document.getElementById('mw-pages'); var div = document.getElementById('mw-pages');
if (!div) if (!div)
{
{
start = 0; start = 0;
div = document.getElementById('mw-category-media'); div = document.getElementById('mw-category-media');
if (!div) if (!div)
div = document.getElementById('mw-subcategories'); div = document.getElementById('mw-subcategories');
}
}
if (div) if (div)
{
{
var lks = document.getElementsByTagName('a'); var lks = document.getElementsByTagName('a');
var count = 0; var count = 0;
var hrefs = ; var hrefs = ;
var max_to_open = 10; var max_to_open = 10;
if (mw.config.get('wgPageName').indexOf('Category:Candidates_for_speedy_deletion_as_empty_categories') == 0) if (mw.config.get('wgPageName').indexOf('Category:Candidates_for_speedy_deletion_as_empty_categories') == 0)
max_to_open = 5; max_to_open = 5;


for (var i = 0; i < lks.length; ++i) for (var i = 0; i < lks.length; ++i)
{ {
for (var p = lks; p; p = p.parentNode) for (var p = lks; p; p = p.parentNode)
if (p == div if (p == div
&& lks.firstChild.nodeValue != 'next page' && lks.firstChild.nodeValue != 'next page'
&& lks.firstChild.nodeValue != 'previous page') && lks.firstChild.nodeValue != 'previous page')
{
{
++count; ++count;
if (count != start) if (count != start)
hrefs = lks.href; hrefs = lks.href;
break; break;
}
}
if (count == max_to_open + start) if (count == max_to_open + start)
break; break;
} }


if (count > start) if (count > start)
{ {
count -= start; count -= start;
var s = ""; var s = "";
for (var j = 0; j < count; ++j) for (var j = 0; j < count; ++j)
s += 'window.open("' + hrefs + '", "_blank");'; s += 'window.open("' + hrefs + '", "_blank");';
var newnode = document.createElement("a"); var newnode = document.createElement("a");
newnode.setAttribute("onClick", s); newnode.setAttribute("onClick", s);
newnode.setAttribute("href", "#"); newnode.setAttribute("href", "#");
newnode.appendChild(document.createTextNode('open'+count)); newnode.appendChild(document.createTextNode('open'+count));
div.insertBefore(newnode, div.firstChild.nextSibling.nextSibling); div.insertBefore(newnode, div.firstChild.nextSibling.nextSibling);
} }
}
}
} }
} }
Line 961: Line 954:
else if (action == 'delete') else if (action == 'delete')
expand_delete_dropdown_etc(); expand_delete_dropdown_etc();

// Work ]
else if (mw.config.get('wgNamespaceNumber') == 6) // File:
{
if (action == 'edit')
add_reduced_button();
else
add_del_prev_revisions();
}
else if (pagename == 'Special:RevisionDelete')
revision_delete_stuff();


var sum = document.getElementById("wpSummary"); var sum = document.getElementById("wpSummary");
Line 1,016: Line 998:
} }
manipulate_styling(); manipulate_styling();
function manipulate_styling2()
$(manipulate_styling);
{
manipulate_styling();
setTimeout(manipulate_styling, 250);
}
$(manipulate_styling2);
//</nowiki> //</nowiki>

Latest revision as of 17:55, 17 December 2024

//<nowiki>
function add_global_style(css)
{
  var head, style;
  head = document.getElementsByTagName('head');
  if (!head)
    return;
  style = document.createElement('style');
  style.type = 'text/css';
  style.innerHTML = css;
  head.appendChild(style);
}

function add_link_general(url, action, name, id, node, prev)
{
  var na = document.createElement('a');
  na.setAttribute('href', url);

  var txt = document.createTextNode(name);
  na.appendChild(txt);

  if (id)
    na.id = id;

  if (action)
    {
      if (typeof action == "string")
        na.setAttribute("onClick", action);
      else if (typeof action == "function")
        na.onclick = action;
    }

  if (node)
    if (prev)
      node.insertBefore(na, prev);
    else
      node.appendChild(na);
  else
    return na;
}


function addexplicitlink(url, name, node, prev)
{
  return add_link_general(url, null, name, null, node, prev);
}


function addlink_onclick(action, name, node, prev)
{
  return add_link_general('#', action, name, null, node, prev);
}


function pipe(node, txt, prev)
{
  if (node)
    if (prev)
      node.insertBefore(document.createTextNode(txt ? txt : ' | '), prev);
    else
      node.appendChild(document.createTextNode(txt ? txt : ' | '));
  else
    return document.createTextNode(' | ');
}


function makebutton(lbl, action)
{
  var button = document.createElement('input');
  button.type = 'button';
  button.value = lbl;
  button.setAttribute('onClick', action);
  return button;
}


// Add links for Logs, Current version, Enable rollback.
// Restore Talk: and non-Talk: links to the footer for pages not in namespaces besides Article: and Talk:.
// Fix the non-Talk: link in namespace Talk:, which normally goes to itself (!)
// Copy the more-informative label for Undelete on the (hidden) left navbar to the Undelete link on the bottom.
// If there's a template providing a default delete reason, display that in a delete link at the bottom, retaining the no-reason delete link.
// If it's a redirect-to-existent-page reason, provide the name of the target page.
// If this page is a redirect to a non-existent page, do the same.
function morelinks()
{
  // Talk/non-Talk links.  I don't want to speculate on the moon logic that removed them from every namespace *except* 0 and 1.
  // Since they're still present for namespaces 0 and 1, be sure to put them in the same place those appear (after "Watch"), instead of before Protect like I'll do for the others.
  var watch = document.getElementById("ca-cb-watch") || document.getElementById("ca-cb-unwatch");
  if (watch)
    {
      var ns = mw.config.get('wgNamespaceNumber');
      var title = mw.config.get('wgTitle');
      // not negative namespaces (Special: and Media:), and don't duplicate in namespaces 0 and 1
      if (ns > 1)
        {
          // I'd use mw.config.get('wgFormattedNamespaces'), except it's not always there in time.  At least not in greasemonkey, where I'm prototyping this so folks can only point and laugh at a *working* illiterate version of it instead of broken ones.
          var ns_title = mw.config.get('wgCanonicalNamespace');
          ns_title = ns_title.replace(/^Project/, 'Misplaced Pages');  // 4/5, the only ones we localize

          var parent = watch.parentNode;

          // Contributions and Block links
          if (ns == 2 || ns == 3)
            {
              var basetitle = title.replace(/\/.*/, '');
              addexplicitlink("/search/?title=" + encodeURIComponent('Special:Contributions/' + basetitle),
                              'Contribs', parent, watch.nextSibling);
              pipe(parent, null, watch.nextSibling);
              addexplicitlink("/search/?title=" + encodeURIComponent('Special:Block/' + basetitle),
                              'Block', parent, watch.nextSibling);
              pipe(parent, null, watch.nextSibling);
            }

          var linkname;
          if (ns % 2)
            {
              ns -= 1;
              ns_title = ns_title.replace(/_talk$/, '');
              linkname = ns_title;
            }
          else
            {
              ns += 1;
              ns_title += '_talk';
              linkname = "Talk";
            }

          addexplicitlink("/search/?title=" + encodeURIComponent(ns_title + ':' + title),
                          linkname, parent, watch.nextSibling);
          pipe(parent, null, watch.nextSibling);
        }
      else if (ns == 1) // there's still a link in the Talk: namespace... but it's to the *same page*, and titled Talk.  Doesn't anyone ever look at this stuff before deploying it?
        {
          var lk = document.getElementById('ca-cb-talk').firstChild;
          if (lk.nodeName == 'A')
            {
              lk.href = "/search/?title=" + encodeURIComponent(title);
              var txt = lk.firstChild;
              if (txt.nodeName == '#text')
                txt.nodeValue = 'Article';
            }
        }
    }

  var enable_rollback_txt = "var head=document.getElementsByTagName('head');"
                            + "var style=document.createElement('style');"
                            + "style.type='text/css';"
                            + "style.innerHTML='.mw-rollback-link { display:inline !important; }';"
                            + "head.appendChild(style);";

  // If there's a protect link, add link for Logs and Current version.
  // Always add a link for Enable rollback.
  var protect = document.getElementById("ca-cb-unprotect");
  if (!protect)
    protect = document.getElementById("ca-cb-protect");
  if (protect)
    {
      var parent = protect.parentNode;

      pipe(parent, null, protect);
      addexplicitlink("/search/?title=Special:Log&page=" + encodeURIComponent(mw.config.get('wgPageName')),
                      'Logs', parent, protect);

      pipe(parent, null, protect);
      addexplicitlink("/search/?title=" + encodeURIComponent(mw.config.get('wgPageName')),
                      'Curr', parent, protect);

      pipe(parent, null, protect);
      addlink_onclick(enable_rollback_txt, 'Enable rollback', parent, protect);
    }
  else
    {
      var parent = document.getElementById("searchform-footer").parentNode;
      addlink_onclick(enable_rollback_txt, 'Enable rollback', parent);
    }


  var del = document.getElementById("ca-cb-undelete");
  if (!del)
    {
      del = document.getElementById("ca-cb-delete");
      if (del)
        {
          var delete_reason = document.getElementById("delete-reason");
          if (delete_reason)
            {
              delete_reason = delete_reason.firstChild.nodeValue;
              if (delete_reason)
                {
                  if (delete_reason.match(/Redirect.*to\+a\+deleted\+or\+non-existent\+page/))
                    {
                      delete_reason = encodeURIComponent("]: Redirect to a deleted or nonexistent page");

                      for (var node = document.getElementById('mw-content-text').firstChild.firstChild; node; node = node.nextSibling)
                        if (node.tagName == 'OL' && node.firstChild)
                          {
                            var n = node.firstChild;
                            if (n.tagName != 'LI' && n.nextSibling)
                              n = n.nextSibling;
                            if (n.tagName == 'LI')
                              {
                                delete_reason += ": ]";
                                break;
                              }
                          }
                    }
                  else if (delete_reason.match(/Cross.*namespace.+redirect.+from.+mainspace/))
                    {
                      delete_reason = encodeURIComponent("]: ] from mainspace");

                      for (var node = document.getElementById('mw-content-text').firstChild.firstChild; node; node = node.nextSibling)
                        if (node.tagName == 'OL' && node.firstChild)
                          {
                            var n = node.firstChild;
                            if (n.tagName != 'LI' && n.nextSibling)
                              n = n.nextSibling;
                            if (n.tagName == 'LI')
                              {
                                delete_reason += " to ]";
                                break;
                              }
                          }
                        else if (node.tagName == 'P' && node.firstChild)
                          {
                            var n = node.firstChild;
                            if (n.textContent && n.textContent.match(/^\s*#redirect\s*$/i))
                              {
                                n = n.nextSibling;
                                if (n.tagName == 'A')
                                  {
                                    delete_reason += " to ]";
                                    break;
                                  }
                              }
                          }
                    }
                  else if (delete_reason.match(/^CSD.F5:/))
                    delete_reason = encodeURIComponent(']: Unused non-free media file for more than 7 days');
                  else
                    delete_reason = delete_reason.replace("+", "%20", "g");

                  addexplicitlink(del.firstChild.href + "&wpReason=" + delete_reason,
                                  decodeURIComponent(delete_reason),
                                  del.parentNode, del.nextSibling);
                  pipe(del.parentNode, ': ', del.nextSibling);
                }
            }
          else
            {
              for (var node = document.getElementById('mw-content-text').firstChild.firstChild; node; node = node.nextSibling)
                {
                  if (node.tagName == 'OL'
                      && node.firstChild
                      && node.firstChild.nextSibling
                      && node.firstChild.nextSibling.tagName == 'LI'
                      && node.firstChild.nextSibling.firstChild
                      && node.firstChild.nextSibling.firstChild.nodeName == '#text'
                      && node.firstChild.nextSibling.firstChild.nodeValue.match(/^redirect *$/i)
                      && node.firstChild.nextSibling.firstChild.nextSibling.tagName == 'A')
                    node = node.firstChild.nextSibling.firstChild.nextSibling;
                  else if (node.tagName == 'DIV'
                           && node.className == 'redirectMsg'
                           && node.firstElementChild
                           && node.firstElementChild.nextElementSibling
                           && node.firstElementChild.nextElementSibling.tagName == 'UL'
                           && node.firstElementChild.nextElementSibling.firstChild
                           && node.firstElementChild.nextElementSibling.firstChild.tagName == 'LI'
                           && node.firstElementChild.nextElementSibling.firstChild.firstChild
                           && node.firstElementChild.nextElementSibling.firstChild.firstChild.tagName == 'A')
                    node = node.firstElementChild.nextElementSibling.firstChild.firstChild;
                  else
                    continue;

                  if (node.className == 'new')
                    delete_reason = "]: Redirect to a deleted or nonexistent page: ]";
                  else if (node.firstChild.nodeValue.match(/^(Talk|(Draft|User)(talk)?):/i))
                    delete_reason = "]: ] from mainspace to ]";
                  else
                    break;

                  addexplicitlink(del.firstChild.href + "&wpReason=" + encodeURIComponent(delete_reason),
                                  delete_reason,
                                  del.parentNode, del.nextSibling);
                  pipe(del.parentNode, ': ', del.nextSibling);

                  break;
                }
            }
        }
    }
  else  // Show number of deleted revisions in undelete link at bottom
    {
      var sidenode = document.getElementById("ca-undelete");
      if (sidenode)
        del.firstChild.firstChild.nodeValue = sidenode.firstChild.firstChild.nodeValue;
    }
}


// If a template, wikilink, or external link appears in a diff, make it clickable
function link_links_dim_refs_in_diffs()
{
  var tds = document.getElementsByTagName('td');

  for (var i = 0; i < tds.length; ++i)
    {
      var classes = tds.className.split(' ');

      for (var j = 0; j < classes.length; j++)
        if (classes == 'diff-context' || classes == 'diff-addedline' || classes == 'diff-deletedline')
          {
            var txt = tds.innerHTML;

            if (txt.indexOf("&@<my") < 0)
              {
                txt = txt.replace(new RegExp('<(/?(del|ins)( class="*")?)>', 'g'), '&@<mybra;$1&@<myket;');
                txt = txt.replace(new RegExp('(&lt;ref*?(/&gt;|\\bref\\b( *&gt;)?))', 'gi'), '<span style="opacity:0.25; font-size:x-small !important;">$1</span>');
                txt = txt.replace(new RegExp('&@<mybra;', 'g'), '<');
                txt = txt.replace(new RegExp('&@<myket;', 'g'), '>');
              }

            txt = txt.replace(new RegExp('(\\ <]+)( ])', 'gi'), '$1<a href="$2">$2</a>$3');
            txt = txt.replace(new RegExp('\\{\\{((?:talk|user|wikipedia|image|mediawiki|template|help|category|portal)(?:talk)?:+)()', 'gi'), '{{<a href="https://en.wikipedia.org/$1">$1</a>$2');
            txt = txt.replace(new RegExp('\\{\\{(\\s*(?:tlsp|lts|tl?)\\s*\\|\\s*|\\s*)(+)()', 'g'), '{{$1<a href="https://en.wikipedia.org/Template:$2">$2</a>$3');
            function enwikilk(match, p1, p2, p3){ return p1 + '<a href="https://en.wikipedia.org/' + p2.replace(/ +/g, '_') + '">' + p2 + '</a>' + p3; };
            txt = txt.replace(new RegExp('(\\|<]+)(|])', 'g'), enwikilk);
            txt = txt.replace(new RegExp('(\\|]*<SPAN class="*">:?)(|<]+)(</SPAN>|])', 'gi'), enwikilk);
            txt = txt.replace(new RegExp('\\b(url\\s*=\\s*)(https?://|{} <>]+?)(\\s*(\\||\\}\\}))', 'gi'), '$1<a href="$2">$2</a>$3');

            tds.innerHTML = txt;
            break;
          }
    }
}


function cesarb_fixDiffOverflowTableCell(cell)
{
  var div = document.createElement('div');
  div.style.overflow = 'auto';
  cell.insertBefore(div, cell.firstChild);

  while (div.nextSibling)
    div.appendChild(div.nextSibling);
}


function cesarb_fixDiffOverflowTable(table)
{
  var cells = table.getElementsByTagName('td');

  for (var i = 0; i < cells.length; i++)
    {
      var cell = cells;
      var classes = cell.className.split(' ');

      for (var j = 0; j < classes.length; j++)
        if (classes == 'diff-context' || classes == 'diff-addedline' || classes == 'diff-deletedline' || classes == 'diff-otitle' || classes == 'diff-ntitle')
          {
            cesarb_fixDiffOverflowTableCell(cell);
            break;
          }
    }
}


function cesarb_fixDiffOverflowLoadListener(evt)
{
  var tables = document.getElementsByTagName('table');

loop:
  for (var i = 0; i < tables.length; i++)
    {
      var table = tables;
      var classes = table.className.split(' ');

      for (var j = 0; j < classes.length; j++)
        if (classes == 'diff')
          {
            cesarb_fixDiffOverflowTable(table);
            link_links_dim_refs_in_diffs();
            break loop;
          }
    }
}

function check_reason_length(node)
{
  if (node.value.length > node.maxLength
      && (node.maxLength > 0 || node.value.length > 255))
    node.style = "background-color:pink";
  else
    node.style = "background-color:white";
}

function should_watch(txt)
{
  return (!txt.match(/^\[\[WP:CSD#(C1|G7|G8|G13|U1)\|/)
          || txt.match(/^\edirect to a/));
}

/* In no particular order:
 * 1. Expands the delete dropdownlist to show all its contents instead of just
 *    the currently-selected line.
 * 2. Move the "Additional reasons" input, the watchlist checkbox, and the
 *    delete button above the newly-expanded dropdownlist, so they're always in
 *    the same place.
 * 3. Whenever an item is selected from the dropdownlist, immediately insert it
 *    into the "Additional reasons" input for further editing, then reselect the
 *    first option.
 * 4. Add a button to clear the reason line.
 * 5. If a preset deletion reason, or adding reasons from the dropdownlist,
 *    force the deletion reason above its maximum length, color the input pink
 *    so I know it'll be truncated. */
function expand_delete_dropdown_etc()
{
  var reasons = document.getElementById('wpDeleteReasonList');
  if (!reasons)
    return;

  /* Remove the warnings.  Seeing them 50000 times was enough.  The right way
   * to do it is to put them in a named div, but some busybody is sure to raise
   * a fuss if I edit ].  Life's too short. */
  var delreason = document.getElementById('Deletereason');
  if (delreason)
    {
      var p = delreason.parentNode;      // "You are about to delete ] along with all of its history. Please:"
      var ul = p.previousElementSibling; // "*Confirm...", "*Review...", "*Check...", "*Provide..."
      if (ul.nodeName == 'UL')
        {
          p = ul.previousElementSibling;
          var div = p.previousElementSibling;   // "WARNING: Other pages link to..."  Duh.  *Always* present, because of the user pages that uselessly transclude ].
          if (p.nodeName == 'P')
            {
              p.parentNode.removeChild(p);
              ul.parentNode.removeChild(ul);
            }
          if (div && div.nodeName == 'DIV')
            div.parentNode.removeChild(div);
        }
    }

  // OOjs considered harmful
  //$(".oo-ui-dropdownInputWidget").removeClass("oo-ui-dropdownInputWidget");
  //$(".oo-ui-dropdownInputWidget-php").removeClass("oo-ui-dropdownInputWidget-php");

  /* Expand the whole list.  We actually create a new one, copy the elements
   * from the old one into there, and hide the old one, to minimize interference
   * from hostile developers. */
  var nsel = document.createElement('select');
  var len = 0;

  // Create an empty option to keep selected, since "Other reason" was removed
  function add_option(grp, lbl)
  {
    var nop = document.createElement('option');
    nop.value = lbl;
    nop.appendChild(document.createTextNode(lbl));
    grp.appendChild(nop);
    return 1;
  };
  len += add_option(nsel, '');

  var g1_seen = 0;
  var optgroups = reasons.getElementsByTagName('optgroup');
  for (var i = 0; i < optgroups.length; ++i)
    {
      var og = optgroups;
      // Skip the talk section (we put it with the primary g8)
      if (!og.label.match(/talk pages/i))
        {
          var nog = document.createElement('optgroup');
          nog.label = og.label;
          nsel.appendChild(nog);
          ++len;

          var options = og.getElementsByTagName('option');
          for (var j = 0; j < options.length; ++j)
            {
              var txt = options.value;

              // enable G1 and G2 in all namespaces, to be used in extremis
              if (txt.match(/^\\].+/))
                g1_seen = 1;
              else if (txt.match(/^\\].+/) && !g1_seen)
                {
                  len += add_option(nog, "]: ], meaningless, or incomprehensible");
                  len += add_option(nog, "]: Test page");
                  g1_seen = 1; // so it isn't added again on the next g3
                }

              // add G8 talk pages right before g10 (in particular, so it isn't removed for user talk subpages)
              else if (txt.match(/^\\].+/))
                len += add_option(nog, "]: Talk page of a nonexistent or deleted page");

              // essentially all G13s are drafts now, not afc-templated user subpages
              else if (txt.match(/^\\].+/))
                txt = txt.replace(/ or \\] submission/, '');

              // Entirely the wrong place to try to teach admins which articles can be A7d
              else if (txt.match(/^\\].+/))
                txt = txt.replace(/ \(indiv.+/, '');

              // the text for U5 is vague and antagonistic
              else if (txt.match(/^\\].+/))
                txt = txt.replace(/Misuse of Misplaced Pages as a web host/, "Writings unrelated to Wikimedia's goals, by a user with few or no edits outside of userspace");

              // more specific link for R2
              else if (txt.match(/^\\].+/))
                txt = txt.replace(/Cross-\\] \\]/, "]");

              len += add_option(nog, txt);
            }
        }
    }

  nsel.id = 'nsel';
  nsel.size = len;

  var root = document.getElementById('mw-delete-table');
  var div = document.createElement('div');

  // Move the additional reason input, watch checkbox, and delete button above it, so they're always in the same place
  var reason;
  var deletebutton;
  var imgtable = document.getElementById('mw-img-deleteconfirm-table');
  if (imgtable)
    {
      reason = imgtable.getElementsByTagName('tr');  // probably not, but I'll worry about it the next time I delete an image
      reason.id = 'actual_reason';
      deletebutton = imgtable.getElementsByTagName('tr').getElementsByClassName('mw-submit').firstElementChild;
    }
  else
    {
      reason = document.getElementById('wpReason').firstChild;
      reason.id = 'actual_reason';
      deletebutton = document.getElementById('wpConfirmB');
    }

  var spacer = document.createElement('span');
  spacer.style = "margin-left:1em";

  var watch = document.getElementById('wpWatch').parentNode;
  var watchlabel = watch.nextElementSibling;

  var clearbutton = makebutton('clear',
                               'var reason = document.getElementById("actual_reason");'
                               + 'reason.value="";'
                               + 'reason.style="background-color:white";'
                               + 'reason.focus()');
  clearbutton.style = "margin-left:1em";

  div.appendChild(deletebutton);
  div.appendChild(spacer);
  div.appendChild(watch);
  div.appendChild(watchlabel);
  div.appendChild(clearbutton);
  div.appendChild(reason);
  div.appendChild(nsel);

  for (var n = root.firstChild; n; n = n.nextSibling)
    n.style.display='none';

  root.appendChild(div);

  /* Whenever clicking something in the reason dropdown, insert it into the
   * additional-reasons input, reselect "other reason", and unflag watched for
   * c1/g7/g8/g13/u1 */
  nsel.onchange = function()
    {
      var reason = document.getElementById('actual_reason');
      var sel = this.selectedIndex;
      if (sel != 0)     // 0 is "Other reason"
        {
          var txt = this.firstChild.textContent;

          if (reason.value.length > 0)
            reason.value += '; ';
          reason.value += txt;
          check_reason_length(reason);

          document.getElementById('wpWatch').checked = should_watch(this.value);

          this.selectedIndex = 0;
          reason.focus();
        }
    };
  /* And set initial value of wpWatch for c1/g7/g8/g13/u1.  If initially g8, and
   * deleting a talk page, then don't change watched status. */
  var reasonv = document.getElementById('actual_reason').value;
  if (reasonv.match(/^\alk page.*of a (deleted|non.?exist)/))
    document.getElementById('wpWatch').firstChild.checked = !!document.getElementById("ca-cb-unwatch");
  else
    document.getElementById('wpWatch').firstChild.checked = should_watch(reasonv);

  /* Whenever anything forces the length of the additional-reasons input above
   * its max, change its background color */
  reason.oninput = function(){ check_reason_length(this); };

  // And initially, e.g. from presets
  check_reason_length(reason);

  reason.focus();

  /* More oo-ui detritus - it keeps multiplying, and this one even unhides
   * itself *AND* reinserts itself if removed!!  Unbefuckinglievable.  So hide
   * it globally. */
  add_global_style('.oo-ui-dropdownWidget { display:none !important; }');
}

// Open up to 20 history pages from watchlist, starting here and going up
function openahah(kk)
{
  var as = document.getElementsByTagName('a');
  var j = 0, k = 0;
  ++kk;
  for (var n = 0; n < as.length; ++n)
    if (as.innerHTML == 'hist' && kk - k++ <= 20)
      {
        if (k <= kk)
          {
            as.setAttribute('class', as.getAttribute('class') + ' modified');
            window.open(as.href, '_blank');
          }
        else
          break;
      }
}

// Add "ahah" links to watchlist - "all histories above here".
// Also makes the "diff" links on watchlist match those on the history page, so marking the one visited changes the color of the other.
function addahah()
{
  var as = document.getElementsByTagName('a');
  var k = 0;
  for (var n = 0; n < as.length; ++n)
    {
      if (as.innerHTML == 'diff')
        as.href = as.href.replace(/&curid=+&diff=(+)&oldid=+/, '&diff=prev&oldid=$1');
      else if (as.innerHTML == 'hist')
        {
          addexplicitlink('javascript:openahah(' + (k++) + ')', 'ahah', as.parentNode, as.nextSibling);
          pipe(as.parentNode, ') (', as.nextSibling);
        }
    }
}


// Shows only the most recent change to each article listed in Special:RecentChangesLinked/articlename, like on Special:Watchlist, instead of all changes
function fix_relatedchanges()
{
  var uls = document.getElementsByTagName('ul');
  var entries = new Object;
  for (var i = 0; i < uls.length; ++i)
    if (uls.className && uls.className.indexOf('special') >= 0)
      {
        var ul = uls;
        var li = ul.getElementsByTagName('li');
        for (var j = 0; j < li.length; ++j)
          {
            var a = li.getElementsByTagName('a');
            if (a.firstChild.data == 'diff')
              if (entries.href] == 'y')
                li.style.display = 'none';
              else
                {
                  a.href = a.href.replace(/&curid=+/, '');
                  entries.href] = 'y';
                }
          }
      }
}


// For each redirect link on Special:WhatLinksHere, add a "delete G8" link next to it to delete it with deletion summary prefilled
function add_g8redir_links()
{
  var tgt = null;
  var wlh = document.getElementById('mw-whatlinkshere-list');
  if (wlh)
    for (var li = wlh.firstChild; li; li = li.nextSibling)
      if (li.firstChild
          && li.firstChild.firstChild
          && li.firstChild.firstChild.href
          && li.firstChild.firstChild.href.indexOf('&redirect=no') != -1
          && (li.firstChild.nextSibling.nodeValue.indexOf('(redirect page)') != -1
              || li.firstChild.nextSibling.nodeValue.indexOf('(redirect to section ') != -1))
        {
          if (!tgt)
            tgt = "&action=delete&wpReason="
                  + encodeURIComponent("]: Redirect to a deleted or nonexistent page: ]").replace('_', '+', 'g').replace('%20', '+', 'g')
                  + "&action=delete";

          var newnode = addexplicitlink(li.firstChild.firstChild.href + tgt, 'delete G8');
          // Place on the same line, whether there are incoming links to this redirect or not
          var x;
          for (x = li.firstElementChild; x; x = x.nextElementSibling)
            if (x.tagName && x.tagName == 'UL')
              {
                li.insertBefore(newnode, x);
                break;
              }
          if (!x)
            li.appendChild(newnode);
        }
}


// Move the notifications indicator from the sidebar (which I've hidden in css) to the bottom
function move_notif(notif)
{
  var a = notif.firstChild;
  notif = a.firstChild;
  if (a.className.indexOf('mw-echo-notifications-badge-all-read') < 0 && a.className.indexOf('mw-echo-unseen-notifications') >= 0)
    {
      var search = document.getElementById("searchform-footer");
      if (search)
        {
          var newnode = document.createElement("a");
          newnode.setAttribute("class", "mw-echo-unread-notifications");
          newnode.setAttribute("href", "/Special:Notifications");
          newnode.appendChild(document.createTextNode("*"));
          search.parentNode.insertBefore(newnode, search);
        }
   }
}
function move_notifications_to_bottom()
{
  var notif1 = document.getElementById("pt-notifications-alert");
  if (notif1)
    move_notif(notif1);
  var notif2 = document.getElementById("pt-notifications-notice");
  if (notif2)
    move_notif(notif2);
}


// Replace the useless link to ] in the footer with the current time in UTC.  Click to update rather than automatic, since it's occasionally useful to know when I loaded the page.
function current_time_in_footer()
{
  var footer = document.getElementById("footer-navigation");
  if (footer)
    for (var n = footer.firstChild; n; n = n.nextSibling)
      {
        if (n.tagName == 'BR')
          n.style.display = 'none';
        else if (n.tagName == 'UL')
          for (var nn = n.firstChild; nn; nn = nn.nextSibling)
            if (nn.firstChild && nn.firstChild.tagName == 'A' && nn.firstChild.href.indexOf('Misplaced Pages:About') > 0)
              {
                var span = document.createElement('span');
                span.appendChild(document.createTextNode(new Date().toUTCString()));
                span.setAttribute('onClick', 'this.firstChild.textContent = new Date().toUTCString();');
                var olda = nn.firstChild;
                nn.insertBefore(span, olda);
                nn.removeChild(olda);
                return;
              }
      }
}


document.my = new Object;

function modifyWatchlist(title, action)
{
  if (title == null)
    title = mw.config.get('wgPageName');

  var reqData = {
    'action': 'watch',
    'format': 'json',
    'title': title,
    'token': mw.user.tokens.get('watchToken'),
    'uselang': mw.config.get('wgUserLanguage')
  };

  if (action === 'unwatch')
    reqData.unwatch = '';

  jQuery.ajax(
    {
      url: mw.util.wikiScript('api'),
      dataType: 'json',
      type: 'POST',
      data: reqData,
      success: function(data, textStatus, xhr)
        {
          if (action == 'unwatch')
            {
              document.my.watchlk.style.display="inline";
              document.my.unwatchlk.style.display="none";
            }
          else
            {
              document.my.watchlk.style.display="none";
              document.my.unwatchlk.style.display="inline";
            }
        }
    });
}
document.my.modifyWatchlist = modifyWatchlist;
function fix_watch_links()
{
  try
    {
      var watched = false;
      var bot = document.getElementById("ca-cb-watch");
      if (!bot)
        {
          bot = document.getElementById("ca-cb-unwatch");
          if (!bot)
            return;
          watched = true;
        }

      bot.firstChild.style.display = "none";

      var a = document.createElement("a");
      a.setAttribute("href", "javascript:document.my.modifyWatchlist(mw.util.getParamValue('title'), 'watch');");
      a.appendChild(document.createTextNode('Watch'));
      bot.appendChild(a);
      document.my.watchlk = a;
      if (watched)
        a.style.display = "none";

      a = document.createElement("a");
      a.setAttribute("href", "javascript:document.my.modifyWatchlist(mw.util.getParamValue('title'), 'unwatch');");
      a.appendChild(document.createTextNode('Unwatch'));
      bot.appendChild(a);
      document.my.unwatchlk = a;
      if (!watched)
        a.style.display = "none";
    }
  catch (e)
    {
    }
}


function add_open10()
{
  // >> on image categories
  if (mw.config.get('wgPageName').indexOf('Category:Orphaned_non-free_use_Wikipedia_files_as_of') == 0
      || mw.config.get('wgPageName').indexOf('Category:Wikipedia_files') == 0)
    {
      var div = document.getElementById('mw-category-media');
      if (div)
        for (var ul = div.firstChild; ul; ul = ul.nextSibling)
          if (ul.tagName == 'UL' && ul.className.indexOf('mw-gallery-traditional') >= 0)
            {
              var count = 0;
              var first = 0;
              for (var node = ul.firstChild; ; node = node.nextSibling)
                {
                  if (node && node.tagName == 'LI')
                    if (++count == 1)
                      first = node;

                  if (count == 11 || (!node && count != 0))
                    {
                      var newnode = document.createElement("br");
                      ul.insertBefore(newnode, first);
                      newnode = document.createElement("a");
                      newnode.setAttribute("onClick", "var i,n=this;for(i=0;i<"+count+";++i){n=n.nextSibling;if(!n)break;if(n.tagName!='LI'){n=n.nextSibling;if(!n)break;}window.open(n.firstChild.firstChild.nextSibling.firstChild.firstChild.href,'_blank');}");
                      newnode.setAttribute("href", "#");
                      newnode.appendChild(document.createTextNode('>>'));
                      ul.insertBefore(newnode, first);
                      count = 0;
                      first = 0;
                    }

                  if (!node)
                    break;
                }
            }
    }

  // open10 on non-image categories
  if (mw.config.get('wgPageName') == 'Category:Non-free_files_with_orphaned_versions_more_than_7_days_old'
      || mw.config.get('wgPageName').indexOf('Category:Candidates_for_speedy_deletion') == 0
      || mw.config.get('wgPageName').indexOf('Category:Candidates_for_uncontroversial_speedy_deletion') == 0
      || mw.config.get('wgPageName').indexOf('Category:Wikipedia_files') == 0)
    {
      var start = 1;
      var div = document.getElementById('mw-pages');
      if (!div)
        {
          start = 0;
          div = document.getElementById('mw-category-media');
          if (!div)
            div = document.getElementById('mw-subcategories');
        }
      if (div)
        {
          var lks = document.getElementsByTagName('a');
          var count = 0;
          var hrefs = ;
          var max_to_open = 10;
          if (mw.config.get('wgPageName').indexOf('Category:Candidates_for_speedy_deletion_as_empty_categories') == 0)
            max_to_open = 5;

          for (var i = 0; i < lks.length; ++i)
            {
              for (var p = lks; p; p = p.parentNode)
                if (p == div
                    && lks.firstChild.nodeValue != 'next page'
                    && lks.firstChild.nodeValue != 'previous page')
                  {
                    ++count;
                    if (count != start)
                      hrefs = lks.href;
                    break;
                  }
              if (count == max_to_open + start)
                break;
            }

          if (count > start)
            {
              count -= start;
              var s = "";
              for (var j = 0; j < count; ++j)
                s += 'window.open("' + hrefs + '", "_blank");';
              var newnode = document.createElement("a");
              newnode.setAttribute("onClick", s);
              newnode.setAttribute("href", "#");
              newnode.appendChild(document.createTextNode('open'+count));
              div.insertBefore(newnode, div.firstChild.nextSibling.nextSibling);
            }
        }
    }
}


function do_onload()
{
  fix_watch_links();
  add_open10();
  cesarb_fixDiffOverflowLoadListener();
  morelinks();
  move_notifications_to_bottom();
  current_time_in_footer();

  var pagename = mw.config.get('wgPageName');
  var action = mw.config.get('wgAction');

  if (pagename == 'Special:Watchlist')
    addahah();
  else if (pagename.indexOf('Special:RecentChangesLinked/') == 0)
    fix_relatedchanges();
  else if (pagename.indexOf('Special:WhatLinksHere/') == 0)
    add_g8redir_links();
  else if (action == 'delete')
    expand_delete_dropdown_etc();

  var sum = document.getElementById("wpSummary");
  if (sum)
    sum.style.height = "18px";
}
$(do_onload);

// From ]
$('a.new').attr('href', function(index, value)
  {
    var fileTitle = mw.util.getParamValue('wpDestFile', value);
    var fileName = mw.config.get('wgFormattedNamespaces') + ':' + fileTitle;
    var params =
      {
        action: 'edit',
        redlink: 1
      };
    return mw.util.getUrl(fileName, params);
  });

// Run styling changes both immediately (in an attempt to prevent ]) and when dom is complete (to be sure it affects all entities)
function manipulate_styling()
{
  // Make ffd notices more noticeable so I stop overlooking them when deleting orphaned images
  $('table.imbox-delete:has(a)').each(function(){$(this).css("background-color", "red");});

  // remove ugly styles from buttons:
  $(".mw-ui-button").removeClass("mw-ui-button");
  $(".oo-ui-buttonInputWidget").removeClass("oo-ui-buttonInputWidget");
  $(".oo-ui-buttonElement-button").removeClass("oo-ui-buttonElement-button");
  // and dropdowns
  $(".oo-ui-indicator-down").removeClass("oo-ui-indicator-down");
  // and checkboxes:
  $(".oo-ui-checkboxInputWidget").removeClass("oo-ui-checkboxInputWidget");
  // and input fields:
  $(".oo-ui-inputWidget").removeClass("oo-ui-inputWidget");
  $(".oo-ui-inputWidget-input").removeClass("oo-ui-inputWidget-input");
  $(".oo-ui-textInputWidget").removeClass("oo-ui-textInputWidget");
  $(".oo-ui-textInputWidget-type-text").removeClass("oo-ui-textInputWidget-type-text");
  $(".oo-ui-textInputWidget-php").removeClass("oo-ui-textInputWidget-php");
  // remove inflated field margins:
  $(".oo-ui-fieldLayout-header").removeClass("oo-ui-fieldLayout-header");
}
manipulate_styling();
function manipulate_styling2()
{
  manipulate_styling();
  setTimeout(manipulate_styling, 250);
}
$(manipulate_styling2);
//</nowiki>