User:Thundercraft5/global.js/Wikimarks.js

// originally from https://dev.fandom.com/wiki/MediaWiki:Wikimarks/code.js /** * Wikimarks v2 * Replaces the original version following it being broken by verbatim being disabled * * @author Pecoes  * @author Cqm	 * * Changes from the original: * - No longer uses verbatim, thus should be more stable. * - No longer allows javascript: URLs (and thus custom functions) * - Supports wikitext as well as (most of) the old syntax * * New Wiki Nav Todos: * - Test for touchscreens? * * Used files: * - */

/*global importArticle */

/*jshint bitwise:true, camelcase:true, curly:true, eqeqeq:true, es3:false, forin:true, immed:true, indent:4, latedef:true, newcap:true, noarg:true, noempty:true, nonew:true, plusplus:true, quotmark:single, undef:true, unused:true, strict:true, trailing:true, browser:true, devel:false, jquery:true, onevar:true

'use strict';
 * (function($, mw, dev) {

var conf = mw.config.get([			'stylepath',			'wgPageName',			'wgScriptPath',			'wgServer',			'wgUserName'		]), api = new mw.Api; var logger = (function {		Object.entries(this).forEach(([k, v]) => { let func = v.bind(null, `[${k.toUpperCase}] [Wikimarks]:`); this[k] = (...data) => func(...data); });		return this;	}.call({ debug: mw.log, log: console.log, warn: console.warn, error: console.error, }));

/**	 * Insert Wikimarks into the DOM and attach the relevant events */	function addHtml($menu) { var $wikimarks = $('.wikimarks');

$wikimarks.find('> .wds-dropdown > .wds-tabs__tab-label > a').append(			' '		);

$wikimarks.children('.wds-dropdown').append($menu);

$wikimarks .css('background-image', 'none') .find('.wds-tabs__tab-label > a').css('visibility', 'visible');

// everything is now done // so fire an event so people can interact/extend it further mw.hook('wikimarks.loaded').fire($wikimarks); }

/**	 * Prepare the parsed HTML and attach to the DOM */	function prepareHtml(html) { var $parsed = $(html);

// remove the parser output wrapping element if ($parsed.hasClass('mw-parser-output')) { $parsed = $parsed.children; }

var $menu = $(' ') .addClass('wds-is-not-scrollable wds-dropdown__content') .append($parsed);

// add classes to elements $menu .children('ul') .addClass('wds-list wds-is-linked wds-has-bolded-items') .children('li') .children('a') .siblings('ul') .wrap(' ') .addClass('wds-list wds-is-linked') .children('li') .children('a') .siblings('ul') .wrap(' ') .addClass('wds-list wds-is-linked') .children('li') .children('a');

// add chevrons $menu.find('.wds-dropdown-level-2__content').siblings('a').each(function {			var $this = $(this),				chevron = ' ';

$this.append(chevron); $this.addClass('wds-dropdown-level-2__toggle'); $this.parent('li').addClass('wds-dropdown-level-2'); });

$menu.find('.wds-dropdown-level-3__content').siblings('a').each(function {			var $this = $(this),				chevron = ' ';

$this.append(chevron); $this.addClass('wds-dropdown-level-3__toggle'); $this.parent('li').addClass('wds-dropdown-level-3'); });

// add sticked to parent class for level 3 submenus $.unique($menu.find('.wds-dropdown-level-2').parent).each(function {			$(this).children.each(function(i) { var $this = $(this), $list;

if ($this.hasClass('wds-dropdown-level-2')) { $list = $this.find('> .wds-dropdown-level-2__content > .wds-list');

if (($list.children.length - 1) < i) { $this.addClass('wds-is-sticked-to-parent'); }				}			});		});

// add sticked to parent class for level 4 submenus $.unique($menu.find('.wds-dropdown-level-3').parent).each(function {			$(this).children.each(function(i) { var $this = $(this);

if ($this.hasClass('wds-dropdown-level-3')) { if (($this.find('.wds-list').children.length - 1) < i) { $this.addClass('wds-is-sticked-to-parent'); }				}			});		});

// remove href from text converted to links $menu.find('a[href="' + conf.wgScriptPath + '/wiki/"]') .removeAttr('href') .css('cursor', 'pointer');

$menu.find('a') // titles don't add anything to the links .removeAttr('title') // remove external link class for ease of reading the source html .removeClass('extiw');

// kill chat opening in a new window $menu.find('.WikiaChatLink').removeClass('WikiaChatLink');

logger.log('Ready');

addHtml($menu); }

/**	 * Pass the preprocess wikimarks to action=parse to be converted into wikitext */	function parseWikimarks(data) { api.post({				action: 'parse',				contentmodel: 'wikitext',				prop: 'text',				text: data,				disablelimitreport: 1,			}) .done(function(data) {				var text = data.parse.text['*'];

// remove any residual comments text = text.replace(//g, '').trim;

prepareHtml(text); }).catch(logger.warn);	}

/**	 * Preprocesses a wikimarks page to make it compatible with the wikitext parser */	function preprocessData(data) { data = data.trim.split(/\n+/);

var invalidLink = false, parsed = [], // handles: // - /wiki/ (wiki pages) // - index.php, api.php, and wikia.php (API) // - /f and /d (discussions) relativeUrlRe = /\/(wiki\/|(?:index|api|wikia)\.php|f|d)/;

data.forEach(function(elem) {			// ignore comments			if (elem.indexOf('//') === 0 || elem.indexOf('#') === 0) {				return;			}

// handle external links elem = elem.replace(/^(\*+)\s*\[([^\s]+)\s+(.+?)\]\s*$/, function(_, p1, p2, p3) {				// handle query strings				if (p2.indexOf('?') === 0) {					return p1 + '[ ' + p3 + ']';				}

// allow appending to existing query strings as well if (p2.indexOf('&') === 0) { return p1 + '[' + location.href + p2 + ' ' + p3 + ']'; }

// handle relative URLs if (p2.search(relativeUrlRe) === 0) { p2 = conf.wgServer + conf.wgScriptPath + p2; }

// else just return it unchanged return p1 + ' [' + p2 + ' ' + p3 + ']'; });

// don't touch raw html // assumes that all html will begin with a tag, e.g. <span... if (!/^\*+\s*</.test(elem)) { // parse old style links to wikitext for backwards compatibility elem = elem.replace(/^(\*+)\s*([^\[]+?)\s*=\s*(.+?)\s*$/, function(_, p1, p2, p3) {					// handle absolute URLs					// 'http://' or 'https://' or '//'					if (p3.search(/(?:https?:)?\/\//) === 0) {						return p1 + ' [' + p3 + ' ' + p2 + ']';					}

// handle query strings if (p3.indexOf('?') === 0) { return p1 + '[ ' + p2 + ']'; }

// allow appending to existing query strings as well if (p2.indexOf('&') === 0) { return p1 + '[' + location.href + p2 + ' ' + p3 + ']'; }

// attempt to fix instances of Foo?bar=baz // domain added below if (p3.indexOf('?') > -1) { p3 = '/wiki/' + p3; }

// handle relative URLs if (p3.search(relativeUrlRe) === 0) { p3 = conf.wgServer + conf.wgScriptPath + p3; return p1 + ' [' + p3 + ' ' + p2 + ']'; }

// ## BREAKING CHANGE ## // don't allow 'javascript:' urls // ridiculously difficult to parse these in js without using `eval` if (p3.search(/(?:javascript:)?(?:url|win)\(/) === 0) {						p3 = '#invalidLink';						invalidLink = true;					}

// else we expect a normal wikilink return p1 + ' ' + p2 + ''; });			}

// remove css comment // caused by loading wikimarks config through RL and pretending it's CSS if (elem.search(/^\/\*.+?\*\/$/) === 0) { elem = ''; }

// substitute in global variables // syntax: {$VAR} where VAR is a global variable // @todo limit to stuff available in mw.config? elem = elem.replace(/\{\$(.+?)\}/g, function(_, p1) {				// fix for properties of globals				var parts = p1.split('.'),					test = window,					prop,					i;

for (i = 0; i < parts.length; i += 1) { prop = parts[i];

// @todo how secure is this? if (test.hasOwnProperty(prop)) { test = test[prop]; } else { break; }				}

if (['string', 'number'].indexOf(typeof test) > -1 || Array.isArray(test)) { return test.toString; }			});

// make simple text strings into a null link so it doesn't break the styling elem = elem.replace(/^(\*+)\s*([A-Za-z0-9\s]+)\s*$/, '$1 #|$2');

parsed.push(elem); });

data = parsed.join('\n').trim;

return data; }

/**	 * Load the users wikimarks */	function loadWikimarks(username) { $.ajax({			url: 'https://dev.fandom.com/api.php',			data: {				action: 'query',				format: 'json',				prop: 'revisions',				rvprop: 'content',				// don't encode anything in the username here, $.ajax does it anyway				// otherwise stuff gets encoded twice and no results are returned				titles: 'User:' + (username || conf.wgUserName).replace(/ /g, '_') + '/Wikimarks',				indexpageids: 1,				origin: '*',				// Cache results for 5 minutes in CDN and browser				maxage: 300,				smaxage: 300,			},		}).always(function(data) {			var res = '',				revisionData = data.query && data.query.pages[data.query.pageids[0]].revisions;

if (revisionData) { res = revisionData[0]['*']; }

res = preprocessData(res); parseWikimarks(res); });	}	/**	 * Shows loading status until the wikimarks have loaded	 */	function showLoading {		var $nav = $('.wds-community-header__local-navigation .wds-tabs'),			$li = $('');

$li.addClass('wds-tabs__tab wikimarks') .css({				backgroundImage: 'url("https://vignette.wikia.nocookie.net/dev/images/8/82/Facebook_throbber.gif")',				backgroundPosition: 'center center',				backgroundRepeat: 'no-repeat',			}) .append(				$(' ')					.addClass('wds-dropdown')					.append( $(' ')							.addClass('wds-tabs__tab-label wds-dropdown__toggle') .append(								$('')									.attr( 'href', 'https://dev.fandom.com/wiki/User:' + conf.wgUserName + '/Wikimarks' )									.css('visibility', 'hidden')									.append( $(' ')											.text('WIKIMARKS') )							)					)			);

// add our new tab to the start of the nav $nav.prepend($li); }

/**	 * Load stylesheets */	function loadStyles { importArticle({			'type': 'style',			'article': 'u:dev:MediaWiki:Wikimarks.css'		});

$.ajax({			url: mw.config.get('wgLoadScript'),			data: {				mode: 'articles',				articles: 'u:dev:MediaWiki:Colors/code.js',				only: 'scripts'			},			dataType: 'script',			cache: true		}).done(function {			var c = dev.colors,				w = c.wikia,				p = c.parse(w.page),				bgColor;

if (p.isBright) { if (p.lightness > 0.9) { bgColor = '#fff'; } else { bgColor = p.mix('#000', 90).hex; }			} else { bgColor = p.mix('#fff', 90).hex; }

mw.util.addCSS(				'.wds-community-header .wds-dropdown__content .wds-list.wds-is-linked .wds-dropdown-level-3 .wds-dropdown-level-3__content { background-color: ' + bgColor + '; border-color: ' + w.border + '; color: ' + w.text + '; }'			); });	}

/**	 * Checks for the correct environment before allowing the script to continue */	function init { // prevent anyone trying to load this for anons if (!conf.wgUserName) { return; }

if (!$('.wds-community-header__local-navigation').length) { logger.warn('wikinav not found, aborting...'); return; }		loadStyles; showLoading; loadWikimarks; }

logger.log('Loading...'); mw.loader.using(['mediawiki.api', 'mediawiki.util'], function {		$(init);	});

dev.loadWikimarks = loadWikimarks; }(this.jQuery, this.mediaWiki, this.dev = this.dev || {}));