/*
hook
*/
addOnloadHook(accessKeys);
addOnloadHook(pagesLayout);
/*
useful functions
*/
function $(element)
{
return document.getElementById(element);
}
function addClass(element, newClass)
{
if (!element instanceof Object) return false;
if (element.className)
{
var classes = element.className.split(' ');
classes.push(newClass);
return element.className = classes.join(' ');
}
else return element.className = newClass;
}
function hasClass(element, classToCheck)
{
if (!element instanceof Object || !element.className) return false;
var classes = element.className.split(' ');
for (var i = 0; i < classes.length; i++)
{
if (classes[i] == classToCheck)
return true;
}
return false;
}
function removeClass(element, oldClass)
{
if (!element instanceof Object || !element.className) return false;
var classes = element.className.split(' ');
var newClasses = [];
for (var i = 0; i < classes.length; i++)
{
if (classes[i] != oldClass)
newClasses.push(classes[i]);
}
return element.className = newClasses;
}
String.prototype.trim = function()
{
return this.replace(/^[\s|\n]+|[\s|\n]+$/g, '');
}
String.prototype.ltrim = function()
{
return this.replace(/^[\s|\n]+/, '');
}
String.prototype.rtrim = function()
{
return this.replace(/[\s|\n]+$/, '');
}
/*
do access keys
*/
function accessKeys()
{
var caEdit = $('ca-edit');
var tPrint = $('t-print');
var content = $('content');
/*
DISABLE ACCESS KEYS
*/
// Disable logo
$('p-logo').childNodes[1].accessKey = null;
// disable access keys, so quickedit can use them
if (wgAction == 'view' || wgAction == 'purge')
{
if (caEdit) caEdit.firstChild.accessKey = null; // edit this page
if (tPrint) tPrint.firstChild.accessKey = null; // printable version
}
/*
ENABLE ACCESS KEYS
*/
// viewing a non-existent page
if (caEdit && caEdit.firstChild && !caEdit.firstChild.accessKey && caEdit.firstChild.firstChild.nodeValue == 'Create this page')
caEdit.firstChild.accessKey = 'e';
// Diff navigation links
// check if we're viewing an oldid page
var revisionNav = $('mw-revision-nav');
var mwPrevlink = document.getElementsByClassName('mw-prevlink');
var mwNextlink = document.getElementsByClassName('mw-nextlink');
var prevlink, nextlink;
if (revisionNav)
{
if (revisionNav.childNodes[1].firstChild.nodeValue == 'diff')
{
// have both prev and next
prevlink = revisionNav.childNodes[1];
nextlink = revisionNav.childNodes[11];
}
else // only have next
nextlink = revisionNav.childNodes[7];
}
else if (mwPrevlink.length > 0 || mwNextlink.length > 0)
{
prevlink = mwNextlink[0];
nextlink = mwPrevlink[0];
}
else
{
prevlink = $('differences-prevlink');
nextlink = $('differences-nextlink');
}
// assign previous link
if (prevlink && !$('wpPreview'))
{
if (tPrint) tPrint.firstChild.accessKey = null;
prevlink.accessKey = 'p';
}
// assign next link
if (nextlink)
{
$('pt-mytalk').firstChild.accessKey = null;
nextlink.accessKey = 'n';
}
// Content accesskey
var book = $('ca-nstab-book');
var portal = $('ca-nstab-portal');
var special = $('ca-nstab-special');
var contentTab;
if (book) contentTab = book;
else if (portal) contentTab = portal;
else if (special) contentTab = special;
else contentTab = '';
if (contentTab) contentTab.firstChild.accessKey = 'c';
// QuickEdit link
var contentSub = $('contentSub');
if (contentSub.innerHTML != '' && !special)
{
var qeAccessKey = 'b';
var qeLeadLink = $('sectionlink-0');
if (qeLeadLink) qeLeadLink.accessKey = qeAccessKey;
console.log('1: ' + qeLeadLink);
}
else if ($('t-find-edit'))
{
$('t-find-edit').firstChild.setAttribute('accesskey', 'b');
console.log('2');
}
// creating new page, from search results page
var newLinks = content.getElementsByClassName('new');
if (wgPageName == 'Special:Search' && newLinks[0])
newLinks[0].accessKey = 'e';
// Sidebar links
var drafts = $('t-drafts');
var goals = $('t-goals');
var pageSize = $('t-page-size');
if (drafts) drafts.firstChild.setAttribute('accesskey', 'd'); // Drafts
if (goals) goals.firstChild.setAttribute('accesskey', 'g'); // Goals
// if (pageSize) pageSize.firstChild.setAttribute('accesskey', 'a'); // Page Size
// access key for edit box on uneditable page
var permissionErrors = content.getElementsByClassName('permissions-errors');
if (permissionErrors.length > 0) $('wpTextbox1').accessKey = ',';
}
/*
do page layout
*/
function pagesLayout()
{
/*
variables
*/
var content = $('content');
var jumpToNav = $('jump-to-nav');
var pPersonal = $('p-personal');
var afterJumpToNav = jumpToNav.nextSibling.nextSibling.nextSibling.nextSibling;
var bodyContent = $('bodyContent');
var cactions = $('p-cactions');
var caEdit = $('ca-edit');
var caMain = $('ca-nstab-main');
var contentSub = $('contentSub');
var firstDiffElement = content.getElementsByClassName('diff')[0];
var globalWrapper = $('globalWrapper');
var h2 = content.getElementsByTagName('h2');
var paragraphs = content.getElementsByTagName('p');
var pBody = pPersonal.getElementsByClassName('pBody')[0];
var pendingChanges = $('mw-fr-revisiontag');
var relLinks = content.getElementsByClassName('rellink');
var section0 = $('section-0');
var siteSub = $('siteSub');
var toc = $('toc');
var tPrint = $('t-print');
var userMessages = content.getElementsByClassName('usermessage');
var wikiPreview = $('wikiPreview');
var wikitables = content.getElementsByClassName('wikitable');
/*
Layout
*/
// Fatter pages except when it would exceed page width
if (window.innerWidth > 1425) globalWrapper.style.width = cactions.style.width = pBody.style.width = '1400px';
else globalWrapper.style.width = cactions.style.width = pBody.style.width = (window.innerWidth - 25) + 'px';
// Thinner page width for articles (1000 pixels wide)
var thinnerPage = false;
var fatterPage = false;
// TODO fatterPages
// fatterPageTerms
if (typeof(fatterPageTerms) == 'object' && fatterPageTerms.length > 0)
{
for (var i = 0; i < fatterPageTerms.length; i++)
{
if (wgPageName.replace(/_/g, ' ').indexOf(fatterPageTerms[i]) != -1)
{
fatterPage = true;
break;
}
}
}
// thinnerPages
if (typeof(thinnerPages) == 'object' && thinnerPages.length > 0)
{
for (var i = 0; i < thinnerPages.length; i++)
{
if (wgPageName.indexOf(thinnerPages[i].replace(/ /g, '_')) == 0)
{
thinnerPage = true;
break;
}
}
}
// TODO thinnerPageTerms
// Thinner pages for articles
if (window.innerWidth > 1025 && fatterPage == false && (wgCanonicalNamespace == '' || thinnerPage) && (wgAction == 'view' || wgAction == 'submit' || wgAction == 'edit' || wgAction == 'purge') && (location.href.indexOf('title=') && location.href.indexOf('diff=')) == -1 && !(wgCanonicalNamespace == '' && wgTitle == wgMainPageTitle))
globalWrapper.style.width = cactions.style.width = pBody.style.width = '1000px';
// Forced page to use article styles
if ($('thinner-page'))
{
globalWrapper.style.width = cactions.style.width = pBody.style.width = '1000px';
appendCSS('#bodyContent > p, #wikiPreview > p, .text-indent { text-indent: 2em !important; }');
}
// Shorter search text (searchGoButton, mw-searchButton)
$('searchGoButton').value = 'G';
$('mw-searchButton').value = 'S';
// remove the extra space after editsections
var editSections = document.getElementsByClassName('editsection');
var nextSibling;
for (var i = 0; i < editSections.length; i++)
{
nextSibling = editSections[i].nextSibling;
if (nextSibling && nextSibling.nodeType == 3 && nextSibling.nodeValue == ' ')
nextSibling.parentNode.removeChild(nextSibling);
}
// adjust references
var references = document.getElementsByClassName('references-small');
for (var i = 0; i < references.length; i++)
{
var ref = references[i];
var colCount = parseInt(ref.style.MozColumnCount || 1);
var colWidth = ref.style.MozColumnWidth || '30em';
if (colCount == 2 || (colWidth.substr(colWidth.length - 2, 2) == 'em' && parseInt(colWidth) >= 30)) ref.style.MozColumnCount = ref.style.MozColumnWidth = 'auto';
if (ref.scrollHeight > 250)
{
addClass(ref, 'grey-border');
ref.style.clear = 'both';
}
// Indicate how many references there are in the box.
var numberOfReferences = Math.floor(ref.childNodes[1].childNodes[1].childNodes.length / 2);
var referencesHeading = ref.previousSibling.previousSibling;
if (referencesHeading.nodeName == 'H2')
{
var referencesHeadline = referencesHeading.getElementsByClassName('mw-headline')[0];
var newReferencesNode = document.createElement('span');
newReferencesNode.style.fontSize = '75%';
newReferencesNode.style.color = 'grey';
newReferencesNode.appendChild(document.createTextNode(' (' + numberOfReferences + ' total)'));
referencesHeadline.appendChild(newReferencesNode);
}
}
// changes for non-discussion and discussion pages; covers discussion pages not in a "talk:" namespace, such as many noticeboards
isDiscussionPage = ($('ca-addsection'));
// don't add fancy text changes on pages with short paragraphs (discussions), AND better separate discussions
if (isDiscussionPage)
{
importStylesheet('User:Gary King/short paragraphs.css');
importStylesheet('User:Gary King/discussions.css');
}
// insert clear: right; after h3, h4, h5
function addClears(elements)
{
for (var i = 0; i < elements.length; i++)
{
h = elements[i];
if (!h.nextSibling) continue;
div = document.createElement('div');
addClass(div, 'clear-right');
h.parentNode.insertBefore(div, h.nextSibling);
}
}
h3 = content.getElementsByTagName('h3');
h4 = content.getElementsByTagName('h4');
h5 = content.getElementsByTagName('h5');
/*addClears(h3);
addClears(h4);
addClears(h5);*/
// adjust top icons distance from right
var topIcons = document.getElementsByClassName('topicon');
var numberOfTopIcons = topIcons.length;
function getRightDist(element)
{
return getLengthInPixels(element.style.right)[0];
}
// loop through top icons and get the one with the largest style.right value
var leftMostTopIconRightValue = 0;
for (var i = 0; i < numberOfTopIcons; i++)
{
var rightDist = getRightDist(topIcons[i])
if (rightDist > leftMostTopIconRightValue)
leftMostTopIconRightValue = rightDist;
}
var trumpIconLength = getTrumpIconLength(), distanceRight;
if (trumpIconLength) distanceRight = trumpIconLength;
else if (leftMostTopIconRightValue) distanceRight = leftMostTopIconRightValue + 25;
else distanceRight = 0;
function getTrumpIconLength()
{
var trumpIcons = { 'status-top': 175, 'TemplateUserinfo': 225 };
var trumpIconLength = 0;
for (var icon in trumpIcons)
{
if ($(icon))
{
var trumpIconLength = trumpIcons[icon];
break;
}
}
return trumpIconLength;
}
/*var distanceRight = 0;
// ordered from left to right
var firstIcon = $('protected-icon') || $('status-top');
var secondIcon = $('spoken-icon');
var thirdIcon = $('commons-icon') || $('featured-star') || $('good-star') || $('rollback-icon') || $('script-icon');
var trumpIcons = { 'status-top': 150, 'TemplateUserinfo': 225 };
var trumpIconLength = getTrumpIconLength();
if (trumpIconLength) distanceRight = trumpIconLength;
else if (firstIcon) distanceRight = getRightDist(firstIcon) + 25;
else if (secondIcon) distanceRight = getRightDist(secondIcon) + 25;
else if (thirdIcon) distanceRight = getRightDist(thirdIcon) + 30;*/
// move QuickEdit section-0 link to top-right corner of page
sectionLink0 = $('sectionlink-0');
// QE is adding an edit link to the lead section, so move it to the corner
if (sectionLink0)
{
link = sectionLink0.parentNode;
link.id = 'editsection-0';
addClass(link, 'lead-qe-link');
link.style.marginRight = distanceRight + 'px';
// add new edit link into QE edit link
newLink = document.createElement('a');
newLink.href = wgScript + '?title=' + encodeURIComponent(mw.config.get('wgPageName')) + '&action=edit§ion=0';
newLink.title = 'Edit section';
newLink.appendChild(document.createTextNode('edit'));
link.insertBefore(newLink, sectionLink0);
link.insertBefore(document.createTextNode('/'), sectionLink0);
// move it
content.insertBefore(link, section0);
}
// better padding for boxes aligned to the left and right
toccolours = content.getElementsByClassName('toccolours');
for (var i = 0; i < toccolours.length; i++)
{
tocColour = toccolours[i];
textSideMargin = '1.5em';
if (tocColour.style.cssFloat == 'right')
{
tocColour.style.marginRight = 0;
tocColour.style.marginLeft = textSideMargin;
}
else if (tocColour.style.cssFloat == 'left')
{
tocColour.style.marginLeft = 0;
tocColour.style.marginRight = textSideMargin;
}
}
// don't indent lines in certain cases
// italicized lines that are not indented and therefore look like hatnotes
for (var i = 0; i < paragraphs.length; i++)
{
p = paragraphs[i];
if (p.parentNode != bodyContent && p.parentNode != wikiPreview) continue;
if (p.childNodes.length == 1 && p.firstChild.nodeName == 'I' && p.previousSibling.previousSibling.previousSibling.previousSibling != jumpToNav) p.style.textIndent = 0;
}
// merge multiple hatnotes together
// TODO Make these work together? i.e. if a dablink is followed by a reflink, merge them anyway.
function mergeLinks(className)
{
links = content.getElementsByClassName(className);
for (var i = links.length - 1; i >= 0; i--)
{
l = links[i];
// give "title" attribute to node
l.title = className;
if (!l.nextSibling || !l.nextSibling.nextSibling || !hasClass(l.nextSibling.nextSibling, className)) continue;
nextEl = l.nextSibling.nextSibling;
addClass(nextEl, 'merged-hatnote');
text = document.createTextNode(className == 'dablink' ? ' ' : '. ');
l.appendChild(text);
l.appendChild(nextEl);
}
}
mergeLinks('dablink');
mergeLinks('rellink');
// contentSub (redirects, contribution page user info, etc.)
/*if (contentSub.firstChild)
{
if (pendingChanges)
{
newPCDiv = document.createElement('div');
addClass(newPCDiv, 'contentSub');
newPCDiv.style.display = 'block';
newPCDiv.appendChild(pendingChanges);
contentSub.parentNode.insertBefore(newPCDiv, jumpToNav);
}
addClass(contentSub, 'merged-content-sub');
if (contentSub.firstChild.nodeType == 3) contentSub.firstChild.nodeValue = contentSub.firstChild.nodeValue.replace(/^\s+/g, '');
newDiv = document.createElement('div');
newDiv.style.display = 'block';
addClass(newDiv, 'contentSub');
contentSub.parentNode.insertBefore(newDiv, contentSub.nextSibling);
}
else
addClass(contentSub, 'contentSub');*/
// move a left-aligned thumb image to before any header that immediately precedes it
leftAlignedThumb = 'tleft';
thumbs = content.getElementsByClassName(leftAlignedThumb);
for (var i = 0; i < thumbs.length; i++)
{
t = thumbs[i];
movedText = 'This left-aligned image thumb was moved from the section below to the section above, in accordance with the Manual of Style (WP:MOS).';
// immediately precedes it
if (!t.previousSibling && !t.previousSibling.previousSibling) continue;
prev = t.previousSibling.previousSibling;
if (prev.nodeName == 'H3' || prev.nodeName == 'H4' || prev.nodeName == 'H5')
{
t.parentNode.insertBefore(t, prev);
t.title = movedText;
}
// preceded by a rellink, then precedes it
if (!prev.previousSibling && !prev.previousSibling.previousSibling && !hasClass(prev.previousSibling.previousSibling, 'rellink')) continue;
prev = prev.previousSibling.previousSibling;
if (prev && (prev.nodeName == 'H3' || prev.nodeName == 'H4' || prev.nodeName == 'H5'))
{
t.parentNode.insertBefore(t, prev);
t.title = movedText;
}
}
// indent rellinks if an image is to the left of it
for (var i = 0; i < relLinks.length; i++)
{
l = relLinks[i];
if (!l.previousSibling || !l.previousSibling.previousSibling) continue;
two = l.previousSibling.previousSibling;
if (!two.previousSibling) continue;
three = two.previousSibling;
if (!three.previousSibling) continue;
four = three.previousSibling;
if ((two && hasClass(two, leftAlignedThumb)) || (three && hasClass(three, leftAlignedThumb)) || (four && hasClass(four, leftAlignedThumb))) addClass(l, 'text-indent');
}
// get length in pixels
function getLengthInPixels(length, emInPixels)
{
// 1em ~ 13px
if (typeof(emInPixels) == 'undefined') emInPixels = 13;
var value = parseInt(length);
var type = length.substring(length.length - 2, length.length);
if (type == 'em')
{
value = value * emInPixels;
type = 'px';
}
return [value, type];
}
// proper padding for left- and right-aligned tables
function checkAndFixTableMargins(table)
{
var alignment, result;
// calculate "alignment"
if (wikitables[i].align) alignment = wikitables[i].align;
else if (wikitables[i].style.cssFloat) alignment = wikitables[i].style.cssFloat;
if (alignment != 'left' && alignment != 'right') return false;
var margin = alignment == 'left' ? table.style.marginRight : table.style.marginLeft;
var pixelLengths = getLengthInPixels(margin)
var value = pixelLengths[0];
var type = pixelLengths[1];
if (type == 'px' && value < 13) result = '13px';
else if ((type == 'em' && value < 1) || !type) result = '1em';
else result = '1em'; // may need to add checks for more "type"s
if (alignment == 'left') table.style.marginRight = result;
else table.style.marginLeft = result;
return result;
}
for (var i = 0; i < wikitables.length; i++)
checkAndFixTableMargins(wikitables[i])
// add more space above .usermessage on Main Page
if (wgCanonicalNamespace == '' && wgTitle == wgMainPageTitle && userMessages.length > 0)
userMessages[0].style.margin = '2em 0 0 0';
// have no max width for non-standard TOCs
toctitle = $('toctitle');
if (!toctitle) appendCSS('.toc { max-width: none; }');
// add accesskeys for QE section links
for (var i = 1; i <= 9; i++)
{
link = $('sectionlink-' + i);
if (!link) break;
link.accessKey = i;
}
// number h2 headers
if (!(wgCanonicalNamespace == '' && wgTitle == wgMainPageTitle) && (wgAction == 'view' || wgAction == 'purge'))
{
if (firstDiffElement) start = 2;
else if (toc) start = 1;
else start = 0;
begin = 0;
for (var i = start; i < h2.length; i++)
{
number = document.createElement('span');
addClass(number, 'heading-number');
number.appendChild(document.createTextNode(begin + 1 + '. '));
h2[i].insertBefore(number, h2[i].firstChild);
begin++;
}
}
// remove diff whitespace, around .diff-deletedline and .diff-addedline
deletedLines = content.getElementsByClassName('diff-deletedline');
addedLines = content.getElementsByClassName('diff-addedline');
function trimDiffs(elements)
{
for (var i = 0; i < elements.length; i++)
{
if (!elements[i].firstChild) continue;
elements[i].firstChild.innerHTML = elements[i].firstChild.innerHTML.trim();
}
}
// FIXME Removes * and perhaps other characters at beginning of the line.
/*trimDiffs(deletedLines);
trimDiffs(addedLines);*/
// TODO Use white-space: pre-wrap; on deletedLines[i].firstChild and strip whtiespace added
// by the software so that added/removed whitespaces are more clear?
// remove extra line breaks - only in articles, for now at least
if (wgCanonicalNamespace == '')
{
// at the beginning of the page
next = afterJumpToNav;
if (hasClass(next, 'dablink') || next.nodeName == 'DL')
{
next2 = next.nextSibling.nextSibling;
next3 = next2.nextSibling.nextSibling;
if (next2.nodeName == 'P' && next2.firstChild.nodeName == 'BR')
next2.removeChild(next2.firstChild);
else if (next3.nodeName == 'P' && next3.firstChild.nodeName == 'BR')
next3.removeChild(next3.firstChild);
}
// before the TOC
if (toc && toc.previousSibling.previousSibling)
{
beforeTOC = toc.previousSibling.previousSibling;
if (beforeTOC.nodeName == 'P' && beforeTOC.childNodes.length == 1 && beforeTOC.firstChild.nodeName == 'BR')
beforeTOC.parentNode.removeChild(beforeTOC);
}
}
}