User:Lunarity/global.js

"use strict";

// polyfill for 'matches' selector function // http://www.w3.org/TR/2012/WD-selectors-api2-20120628/#interface-definitions (function { var e = document.createElement('div'); // document.body isn't available yet if (!e.matches) { var polyfill = e.mozMatchesSelector   || e.webkitMatchesSelector   || e.msMatchesSelector //IE9   || e.oMatchesSelector   || (e.querySelectorAll && function(aSel) { //IE8 has querySelector[All] but not 'matches' var p = this.parentNode, result = 0; if (!p) { // Detached node with no parent p = e;       p.appendChild(this); result = 8; }     var nodes = p.querySelectorAll(aSel); for (var i = nodes.length ; i-- ; ) { if (nodes[i] === this) { result |= 1; break; }     }      if (result & 8) p.removeChild(this); return !!(result & 1); }); if (polyfill) window.Element.prototype.matches = polyfill; } });

// Mozilla MDN code. if ( !Array.prototype.forEach ) { Array.prototype.forEach = function(fn, scope) { scope = scope || this; for(var i = 0, l = this.length; i < l; ++i) { fn.call(scope, this[i], i, this); } } }

/** * JavaScript to Toggle the Wikia Rail on and off. * Adds a button to the toolbar that allows expand/shrink. * * Exploits oasis-one-column for formatting. one-column occurs normally * on special pages like Edit, RecentChanges, Diff, etc so we don't do * anything on those pages. (Edit still has the Rail but it provides a * built-in collapser for it) */

if (window.skin === "oasis") { $(function($) {   // Arrow (symbol) for Unicode codings    var _expandMsg = "Expand Content \u2192", // 2192 is arrow-right        _shrinkMsg = "Shrink Content \u2190", // 2190 is arrow-left        _$link = $(document.createElement('a')),        _$rail = $('#WikiaRail'),        _header = document.getElementById('WikiaPageHeader'),        _search = _header && document.getElementById('WikiaSearch');

function expandContent {       _$rail.hide; if (_search) _header.appendChild(_search); document.body.className += " oasis-one-column"; }   function shrinkContent {       document.body.className = document.body.className.replace(          /(?:^|\s+)oasis-one-column\b/, ''        ); if (_search) _$rail.prepend(_search); _$rail.show; }   function updateLink(aExpanded) {       _$link.text(aExpanded ? _shrinkMsg : _expandMsg); }   function createClickHandler(aExpandFunc, aShrinkFunc) {       return function(event) { if (_$link.text === _expandMsg) updateLink(aExpandFunc || true); else updateLink(aShrinkFunc && false); return false; };   }

var handle_click; if (!/\boasis-one-column\b/.test(document.body.className)) { handle_click = createClickHandler(expandContent, shrinkContent); } else { // TODO: Make this work in Visual mode. Requires manual inline-CSS. var node = $('#EditPage .editpage-widemode-trigger'); if (node.length) { var edit_toggle = function { node.click; }; handle_click = createClickHandler(edit_toggle, edit_toggle); // Install an event handler to keep the button in sync node.click(function(event) {               updateLink(/\beditpage-sourcewidemode-on\b/.test(                      document.getElementById('EditPage').className                ));            }); }   }    if (handle_click) { var toolbar = $("#WikiaFooter .toolbar > ul.tools"); if (toolbar.length) { _$link .prop('href', '#') .text(_expandMsg) .click(handle_click) .appendTo(document.createElement('li')) .parent .appendTo(toolbar) ;       }    } }); }

/** * Fix the MediaWiki diffs (including AJAX ones). * Display the diffs in monospace font with white-space preservation. * We can't just use CSS for this because MediaWiki generates bad diffs; there are * unnecessary new-lines added at the start and end of each modified line in the * diff which obviously end up being shown unless we fix it. * This script strips the unnecessary new-line characters as well as setting * the inline styles to monospace/pre-wrap (Easier to manage all in one place). * * The Edit page fixing only works in browsers with MutationObserver support. * Those are Firefox14+ or Chrome18+. */ $(function {   var _selectors = 'td.diff-addedline, td.diff-deletedline, td.diff-context';    _selectors = _selectors.replace(/(^|, )/g, '$1table.diff ');    _selectors = _selectors.replace(/(,|$)/g, ' > div$1');

// jQuery hard constrains the given selectors to the context. If the selector // references any nodes which are above the context node in the tree then the // selector will always fail. It makes more sense for the CSS selector to   // start from the node and walk up the tree, following the selector right to    // left but whatever. querySelectorAll works that way so we can just use that. //   function fixSingleNode(aNode, aIndex, aArray) // Array.forEach compatible {       aNode.normalize; // Merge adjacent text nodes to simplify this var n = aNode.firstChild; if (n.nodeType === 3) // n.TEXT_NODE === 3 n.data = n.data.replace(/^\s*?\n/, ""); n = aNode.lastChild; if (n.nodeType === 3) n.data = n.data.replace(/\n\s*$/, ""); }   var _observer, _dialog; function observeDialog(mutations) {       // mutations is an Array of MutationRecord /*interface MutationRecord { readonly attribute DOMString type; readonly attribute Node target; readonly attribute NodeList? addedNodes; //? means optional readonly attribute NodeList? removedNodes; readonly attribute Node? previousSibling; readonly attribute Node? nextSibling; readonly attribute DOMString? attributeName; readonly attribute DOMString? attributeNamespace; readonly attribute DOMString? oldValue; };*/       // The mutation list only generates mutations for direct changes. Adding // a whole sub-tree only generates one mutation for the root node that // was placed into the DOM (i.e. a node already in the DOM had a new child       // added). This is understandable but it means the mutations aren't very // useful directly, we need to do a full sub-tree search with selectors. var m, sel = _selectors; for (var i = mutations.length ; i-- ; ) { m = mutations[i].addedNodes; for (var j = m.length ; j-- ; ) { // Don't ask. I have no idea how this happens in Firefox. if (typeof(m[j].querySelectorAll) !== 'function') { console.log('EDITPAGEBOMB: ' + m[j] + ' (' + m[j].querySelectorAll + ')'); continue; }               [].forEach.call(m[j].querySelectorAll(sel), fixSingleNode); // Both jQuery and querySelectorAll will only match children, fix. if (m[j].matches(sel)) fixSingleNode(m[j]); }       }    }    function observeBody(mutations) {       // This is way simpler and faster than walking the mutation list var node = document.getElementById('EditPageDialog'); if (node !== _dialog) { _dialog = node; _observer.disconnect; // Prevent leaking previous DOM sub-tree if (node) { [].forEach.call(node.querySelectorAll(_selectors), fixSingleNode); _observer.observe(node, {                   childList: true,                    subtree: true // All children of all sub-nodes                }); }       }    }

// Build custom stylesheet. var s = document.createElement('style'); s.setAttribute("type", "text/css"); s.appendChild(document.createTextNode( _selectors + "{" + "font-family: monospace;" + "white-space: pre-wrap;" + "word-break: break-all;" // Break anywhere, ignore language rules + "word-wrap: break-word; overflow-wrap: break-word;" + "}"   ));    document.head.appendChild(s); s = null; // If we're on a diff page then run the fix. // Regex uses look-ahead (?= means "followed by"). The trick is that the line // is not *consumed* by the look-ahead matches so the 2nd (or more) // look-aheads get to walk over the same characters. if (window.wgAction === 'historysubmit' || (window.wgAction === 'view' && /^[^\?]+(?=.*?[\?&]diff)(?=.*?[\?&]oldid=)/.test(window.location.href))) {       [].forEach.call(document.querySelectorAll(_selectors), fixSingleNode); }

// If we're on an edit page then we need to watch for pop-up Diff overlays if (window.wgAction === 'edit') { // We use the DOM4 MutationObserver to detect when the pop-up is shown. var observer_factory = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; if (observer_factory) { var observer = new observer_factory(observeBody); _observer = new observer_factory(observeDialog); // We observe nodes added to the body *directly*, not any of its // children. This is more efficient since the overlay is always added // to and we won't get events caused by the WYSIWYG editor. observer.observe(document.body, {childList: true}); }   } });