MediaWiki:Common.js

From Thorium Mod Wiki
Jump to navigation Jump to search

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
//Adapted from Terraria Wiki MediaWiki:Common.js

$(function() {
// Disable triggering of new browser tab when clicking URL links that point to internal wiki addresses (purge, edit, etc)
$('a[href^="//thoriummod.wiki.gg/"]').removeAttr('target');

// Select links to new tabs for Template:ilnt and Template:elnt
$('.linkNewTab a').attr('target','_blank');
});

// Implement border-collapse + border-radius workaround for "terraria"-class tables 
/* (temporarily?) disabled, broke display for tables with percentage widths 
$('.terraria:not(.outer)')
	.removeClass('terraria')
	.addClass('inner')
	.wrap('<table class="terraria outer"></table>');
*/

// Desktop view for mobile screen
$(window).on('load', function(){
   // desktop view for mobile screen.
   var $btn = $('#mw-panel .resize-sensor');
   var $menu = $('#mw-panel .portal');
   $btn.on('click', function(){
      $('#mw-panel').toggleClass('on');
   });
});


// Disable creation of non-talk pages by anonymous IP editors and link to registration (also disabled by abuse filter but this provides warning before attempting edit)
var wgPageName = mw.config.get( 'wgPageName' );
var wgUserName = mw.config.get( 'wgUserName' );

var isTalk = false, isAnon = false;
if (wgPageName.indexOf('talk:') > -1 || wgPageName.indexOf('Talk:') > -1) isTalk = true;
if (wgUserName === null) isAnon = true;

if (isAnon == true){
    $('a.new').each(function(){
        var href = $(this).attr('href');
        $(this).attr('href', href.replace(/&action=edit/g, '') );
    });
}

if (isAnon == true && isTalk == false) {
    var anonWarnText = 'Page creation by anonymous editors is currently disabled. <br/> To create this page, please <a href="http://thoriummod.gamepedia.com/Special:CreateAccount">register an account</a> first.';
    $('body').append('<div class="anonWarnOverlay" style="display:none; background-color: #000; opacity: 0.4; position: fixed; top: 0px; left: 0px; width: 100%; height: 100%; z-index: 500;"></div>');					
    $('body').prepend('<div class="anonWarnBox" style="display:none; text-align:center; font-weight: bold; box-shadow: 7px 7px 5px #000; font-size: 0.9em; line-height: 1.5em; z-index: 501; opacity: 1; position: fixed; width: 50%; left: 25%; top: 30%; background: #F7F7F7; border: #222 ridge 1px; padding: 20px;">' + anonWarnText + '</div>');

    $('#ca-edit a:contains(Create), #ca-ve-edit a:contains(Create), a.external.text:contains(edit this page)').attr('href', '#').click(function(){
        $('.anonWarnBox').show();
        $('.anonWarnOverlay').show();
    });
    
    $('.anonWarnOverlay').click(function(){
        $('.anonWarnBox').hide();
        $(this).hide();
    });
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * common Utilities
 */
var util = (function(){
	var exports = {
		/* common l10n factory */
		l10nFactory: function($lang, $data) {
			return function ($key) {
				return $data[$key] && ($data[$key][$lang] || $data[$key]['en']) || '';
			};
		}
	};

	function throttle(t, e, o, n) {
		var r, i = !1,
			u = 0;

		function c() {
			r && clearTimeout(r)
		}

		function a() {
			for (var a = arguments.length, d = new Array(a), l = 0; l < a; l++) d[l] = arguments[l];
			var f = this,
				v = Date.now() - u;

			function p() {
				u = Date.now(), o.apply(f, d)
			}

			function h() {
				r = void 0
			}
			i || (n && !r && p(), c(), void 0 === n && v > t ? p() : !0 !== e && (r = setTimeout(n ? h : p, void 0 === n ? t - v : t)))
		}
		return "boolean" != typeof e && (n = o, o = e, e = void 0), a.cancel = function() {
			c(), i = !0
		}, a
	}

	function debounce(t, e, o) {
		return void 0 === o ? throttle(t, e, !1) : throttle(t, o, !1 !== e)
	}
	exports.debounce = debounce;
	exports.throttle = throttle;
	return exports;
})();

///////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * Handle wide tables
 *
 * Display a horizontal floating scroll bar when the table width exceeds the page width.
 */
$.when($.ready, mw.loader.using(['mediawiki.util'])).then( function() {
	var TABLE_WIDE_CLASS = "table-wide";
	var TABLE_WIDE_INNER_CLASS = "table-wide-inner";

	var handleWideTables = function(tables) {
		var handler = mw.util.debounce(100, function() {
			if(!tables){
				return;
			}
			tables.forEach(function(table) {
				var $table = $(table);
				if(!$table.data('container')){
					$table.data('container', table.parentNode);
				}
				var container = $table.data('container');
				if(!container){
					return;
				}
				var $innerBox = $table.parent();
				var $outerBox = $innerBox.parent();
				var overwide = table.getBoundingClientRect().width > container.getBoundingClientRect().width;
				if($outerBox.hasClass(TABLE_WIDE_CLASS)){
					if(overwide){
						$innerBox.floatingScroll("update");
					}else{
						$outerBox.before($table).remove();
					}
				}else{
					if(overwide) {
						$('<div/>').addClass(TABLE_WIDE_INNER_CLASS).appendTo(
							$('<div/>').addClass(TABLE_WIDE_CLASS).insertBefore($table)
						).append($table).floatingScroll("init").floatingScroll("update");
					}
				}
			});
		});
		handler();
		window.addEventListener("resize", handler);
	};

	var isEditorActive  = function() {
		var e = new URLSearchParams(window.location.search);
		return "edit" === e.get("action") || "submit" === e.get("action") || ("edit" === e.get("veaction")
			|| "submit" === e.get("veaction") || "editsource" === e.get("veaction"));
	}

	mw.hook("wikipage.content").add(function() {
		if (!isEditorActive()) {
			var el = document.querySelector("#bodyContent");
			if (el) {
				handleWideTables(el.querySelectorAll("table"));
			}
		}
	});
});

// AJAX tables
$(function() {
	$("table.ajax").each(function (i) {
		var table = $(this).attr("id", "ajaxTable" + i);
		table.find(".nojs-message").remove();
		var headerLinks = $('<span style="float: right;">').appendTo(table.find('th').first());
		var cell = table.find("td").first();
		var needLink = true;
		cell.parent().show();
		if (cell.hasClass("showLinkHere")) {
			var old = cell.html();
			var rep = old.replace(/\[link\](.*?)\[\/link\]/, '<a href="javascript:;" class="ajax-load-link">$1</a>');
			if (rep !== old) {
				cell.html(rep);
				needLink = false;
			}
		}
		if (needLink) {
			headerLinks.html('[<a href="javascript:;" class="ajax-load-link">show data</a>]');
		}
		table.find(".ajax-load-link").parent().addBack().filter('a').click(function(event) {
			event.preventDefault();
			var sourceTitle = table.data('ajax-source-page'), baseLink = mw.config.get('wgScript') + '?';
			cell.text('Please wait, the content is being loaded...');
			$.get(baseLink + $.param({ action: 'render', title: sourceTitle }), function (data) {
				if (!data) {
					return;
				}
				cell.html(data);
				cell.find('.ajaxHide').remove();
				cell.find('.terraria:not(.ajaxForceTerraria)').removeClass('terraria');
				if (cell.find("table.sortable").length) {
					mw.loader.using('jquery.tablesorter', function() {
						cell.find("table.sortable").tablesorter();
					});
				}
				headerLinks.text('[');
				headerLinks.append($('<a>edit</a>').attr('href', baseLink + $.param({ action: 'edit', title: sourceTitle })));
				headerLinks.append(document.createTextNode(']\u00A0['));
				var shown = true;
				$("<a href='javascript:;'>hide</a>").click(function() {
					shown = !shown;
					cell.toggle(shown);
					$(this).text(shown ? "hide" : "show");
				}).appendTo(headerLinks);
				headerLinks.append(document.createTextNode(']'));
			}).fail(function() {
				cell.text('Unable to load table; the source article for it might not exist.');
			});
		});
	});
});

//$(addAjaxDisplayLink);
/*$.when( $.ready ).then(function() {
  // Document is ready.
   // desktop view for mobile screen.
   $('#mw-panel').append('<div id="menu-toggle-button"></div>');
   var $btn = $('#menu-toggle-button');
   var $menu = $('#mw-panel .portal');
   $btn.on('click', function(){
      $('#mw-panel').toggleClass('on');
   });
});

$(window).on('load', function(){

   //main page header.
   var $btn = $('#mf-wikiheader #mf-wikiheader-toggle-link');
   if($btn.length){
      var $box = $('#mf-wikiheader');
      $btn.css('display', 'inline');
      if($box.innerHeight() > 180){
         $box.addClass('collapsed');
      }
      $btn.on('click', function(){
         $box.toggleClass('collapsed');
      });
   }

   //sidebar height fix.
   var $sidebar = $('#mw-panel');
   var $bottom = $sidebar.offset().top + $sidebar.outerHeight(true);
   var $wrapper = $('#global-wrapper');
   var $left_height = $bottom-($wrapper.outerHeight(true)-$wrapper.outerHeight());
   if ($left_height > $wrapper.height()){
   	   $wrapper.css('min-height', $left_height+'px');
   }
});*/

///////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * Make sidebar sections collapsible
 */
$(function(){
	$panel = $('#mw-panel');
	$("#mw-panel .portal").each(function(index, el){
		var $el = $(el);
		var $id = $el.attr("id");
		if(!$id){
			return;
		}
		// for < 1366px
		$el.removeClass('expanded');
		// for >= 1366px
		if(localStorage.getItem('sidebar_c_'+$id) === "y"){
			$el.addClass('collapsed').find('.body').slideUp(0);
		}
	});
	$("#mw-panel .portal").on("click", "h3", function(event){
		var $el = $(this).parent();
		var $id = $el.attr("id");
		if(!$id){
			return;
		}
		event.stopPropagation();
		if($panel.width() < 200){
			$el.toggleClass('collapsed');
			if($el.hasClass('collapsed')){ // more consistent between class and slide status.
				localStorage.setItem('sidebar_c_'+$id, "y");
				$el.find('.body').slideUp('fast');
			}
			else{
				localStorage.setItem('sidebar_c_'+$id, "n");
				$el.find('.body').slideDown('fast');
			}
		}
		else{
			$("#mw-panel .portal").not($el).removeClass('expanded');
			$el.toggleClass('expanded');
		}
	});
});

///////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * content width toggle
 */
$(function(){
	$body = $('body');
	$('<div id="nav-content-size-toggle"><span></span></div>')
	.prependTo($('#mw-head'))
	.on('click', function(){
		$body.toggleClass('content-size-expanded');
	});
});

///////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * floating-scroll v3.2.0
 * https://amphiluke.github.io/floating-scroll/
 * (c) 2022 Amphiluke
 */
! function(t, i) {
    "object" == typeof exports && "undefined" != typeof module ? i(require("jquery")) : "function" == typeof define && define.amd ? define(["jquery"], i) : i((t = "undefined" != typeof globalThis ? globalThis : t || self).jQuery)
}(this, (function(t) {
    "use strict";
    var i = "horizontal",
        n = "vertical",
        e = {
            init: function(t, n) {
                var e = this;
                e.orientationProps = function(t) {
                    var n = t === i;
                    return {
                        ORIENTATION: t,
                        SIZE: n ? "width" : "height",
                        X_SIZE: n ? "height" : "width",
                        OFFSET_SIZE: n ? "offsetWidth" : "offsetHeight",
                        OFFSET_X_SIZE: n ? "offsetHeight" : "offsetWidth",
                        CLIENT_SIZE: n ? "clientWidth" : "clientHeight",
                        CLIENT_X_SIZE: n ? "clientHeight" : "clientWidth",
                        INNER_X_SIZE: n ? "innerHeight" : "innerWidth",
                        SCROLL_SIZE: n ? "scrollWidth" : "scrollHeight",
                        SCROLL_POS: n ? "scrollLeft" : "scrollTop",
                        START: n ? "left" : "top",
                        X_START: n ? "top" : "left",
                        X_END: n ? "bottom" : "right"
                    }
                }(n);
                var o = t.closest(".fl-scrolls-body");
                o.length && (e.scrollBody = o), e.container = t[0], e.visible = !0, e.initWidget(), e.updateAPI(), e.addEventHandlers(), e.skipSyncContainer = e.skipSyncWidget = !1
            },
            initWidget: function() {
                var i = this,
                    n = i.orientationProps,
                    e = n.ORIENTATION,
                    o = n.SIZE,
                    r = n.SCROLL_SIZE,
                    c = i.widget = t('<div class="fl-scrolls" data-orientation="' + e + '"></div>');
                t("<div></div>").appendTo(c)[o](i.container[r]), c.appendTo(i.container)
            },
            addEventHandlers: function() {
                var i = this;
                (i.eventHandlers = [{
                    $el: t(window),
                    handlers: {
                        "destroyDetached.fscroll": function(t) {
                            "fscroll" === t.namespace && i.destroyDetachedAPI()
                        }
                    }
                }, {
                    $el: i.scrollBody || t(window),
                    handlers: {
                        scroll: function() {
                            i.updateAPI()
                        },
                        resize: function() {
                            i.updateAPI()
                        }
                    }
                }, {
                    $el: i.widget,
                    handlers: {
                        scroll: function() {
                            i.visible && !i.skipSyncContainer && i.syncContainer(), i.skipSyncContainer = !1
                        }
                    }
                }, {
                    $el: t(i.container),
                    handlers: {
                        scroll: function() {
                            i.skipSyncWidget || i.syncWidget(), i.skipSyncWidget = !1
                        },
                        focusin: function() {
                            setTimeout((function() {
                                i.widget && i.syncWidget()
                            }), 0)
                        },
                        "update.fscroll": function(t) {
                            "fscroll" === t.namespace && i.updateAPI()
                        },
                        "destroy.fscroll": function(t) {
                            "fscroll" === t.namespace && i.destroyAPI()
                        }
                    }
                }]).forEach((function(t) {
                    var i = t.$el,
                        n = t.handlers;
                    return i.bind(n)
                }))
            },
            checkVisibility: function() {
                var t = this,
                    i = t.widget,
                    n = t.container,
                    e = t.scrollBody,
                    o = t.orientationProps,
                    r = o.SCROLL_SIZE,
                    c = o.OFFSET_SIZE,
                    l = o.X_START,
                    s = o.X_END,
                    d = o.INNER_X_SIZE,
                    a = o.CLIENT_X_SIZE,
                    f = i[0][r] <= i[0][c];
                if (!f) {
                    var h = n.getBoundingClientRect(),
                        u = e ? e[0].getBoundingClientRect()[s] : window[d] || document.documentElement[a];
                    f = h[s] <= u || h[l] > u
                }
                t.visible === f && (t.visible = !f, i.toggleClass("fl-scrolls-hidden"))
            },
            syncContainer: function() {
                var t = this,
                    i = t.orientationProps.SCROLL_POS,
                    n = t.widget[0][i];
                t.container[i] !== n && (t.skipSyncWidget = !0, t.container[i] = n)
            },
            syncWidget: function() {
                var t = this,
                    i = t.orientationProps.SCROLL_POS,
                    n = t.container[i];
                t.widget[0][i] !== n && (t.skipSyncContainer = !0, t.widget[0][i] = n)
            },
            updateAPI: function() {
                var i = this,
                    n = i.orientationProps,
                    e = n.SIZE,
                    o = n.X_SIZE,
                    r = n.OFFSET_X_SIZE,
                    c = n.CLIENT_SIZE,
                    l = n.CLIENT_X_SIZE,
                    s = n.SCROLL_SIZE,
                    d = n.START,
                    a = i.widget,
                    f = i.container,
                    h = i.scrollBody,
                    u = f[c],
                    S = f[s];
                a[e](u), h || a.css(d, f.getBoundingClientRect()[d] + "px"), t("div", a)[e](S), S > u && a[o](a[0][r] - a[0][l] + 1), i.syncWidget(), i.checkVisibility()
            },
            destroyAPI: function() {
                var t = this;
                t.eventHandlers.forEach((function(t) {
                    var i = t.$el,
                        n = t.handlers;
                    return i.unbind(n)
                })), t.widget.remove(), t.eventHandlers = t.widget = t.container = t.scrollBody = null
            },
            destroyDetachedAPI: function() {
                t.contains(document.body, this.container) || this.destroyAPI()
            }
        };
    t.fn.floatingScroll = function(o, r) {
        if (void 0 === o && (o = "init"), void 0 === r && (r = {}), "init" === o) {
            var c = r.orientation,
                l = void 0 === c ? i : c;
            if (l !== i && l !== n) throw new Error("Scrollbar orientation should be either “horizontal” or “vertical”");
            this.each((function(i, n) {
                return Object.create(e).init(t(n), l)
            }))
        } else Object.prototype.hasOwnProperty.call(e, o + "API") && this.trigger(o + ".fscroll");
        return this
    }, t((function() {
        t("body [data-fl-scrolls]").each((function(i, n) {
            var e = t(n);
            e.floatingScroll("init", e.data("flScrolls") || {})
        }))
    }))
}));

/**
 * custom control for [[Template:Sound]]
 * Original ported from https://minecraft.gamepedia.com/MediaWiki:Gadget-sound.js.
 */
$(function(){
	$('.mw-parser-output .sound').prop('title', 'Click to play').on('click', function(e){
		// Ignore links
		if (e.target.tagName === 'A') {
			return;
		}
		var audio = $(this).find('audio')[0];
		if (audio) {
			audio.paused ? audio.play() : audio.pause();
		}
	}).find('audio').on('play', function(){
		// Stop any already playing sounds
		var playing = $('.sound-playing audio')[0];
		playing && playing.pause();
		$(this).closest('.sound').addClass('sound-playing').prop('title', 'Click to stop');
	}).on('pause', function(){
		// Reset back to the start
		this.currentTime = 0;
		$(this).closest('.sound').removeClass('sound-playing').prop('title', 'Click to play');
	});
});


///////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * for other templates
 */
$(function(){
	/* mode tabs switch for [[Template:npcinfobox]] and [[Template:npcinfobtable]] and so on */
	$('.modesbox .modetabs .tab').on('click', function(){
		var $this = $(this);
		if($this.hasClass('current')){
			return;
		}
		$this.parent().children().removeClass('current');
		$this.addClass('current');
		$this.closest('.modesbox').removeClass('c-expert c-master c-normal').addClass($this.hasClass('normal')?'c-normal':($this.hasClass('expert')?'c-expert':'c-master'));
	});
});

// Recipe finder functionality - by Philo04
if(mw.config.get("wgPageName") == "Thorium_Mod_Wiki:Recipe_Finder"){
	var RecipeFinderSearchBox = $("<input>")
		.addClass("mw-inputbox-input mw-ui-input mw-ui-input-inline")
		.css("vertical-align", "top")
		.attr("id", "RecipeFinderSearchInput")
		.attr("autocomplete", "off");
	var RecipeFinderSearchButton = $("<button>")
		.addClass("mw-ui-button mw-ui-progressive")
		.attr("id", "RecipeFinderSearchButton")
		.attr("title", "Search")
		.append("Search");
	$("#RecipeFinderInput").append(RecipeFinderSearchBox, RecipeFinderSearchButton);

	function FindRecipes(){
		var inputArray = $("#RecipeFinderSearchInput").val().trim().toLowerCase().split(" ");
		var excludedWords = ["of"];
		for (var i = 0; i < inputArray.length; i++){
			if (!excludedWords.includes(inputArray[i])) {
				inputArray[i] = inputArray[i][0].toUpperCase() + inputArray[i].substr(1);
			}
		}
		
		var RecipeFinderSearchQuery = inputArray.join(" ");
		new mw.Api().get({
			action: "parse",
			text: "{{#if:{{recipes/exist|ingredient=" + RecipeFinderSearchQuery + "}}|{{recipes|ingredient=" + RecipeFinderSearchQuery + "|title={{item|" + RecipeFinderSearchQuery.replace(/^#/, "") + "|note=({{recipes/count|ingredient=" + RecipeFinderSearchQuery + "}} recipes)}}}}|<span style=\"color:red;font-weight:bold;\">Recipes: No result</span>}}",
			disablelimitreport: true,
			format: "json"
		}).then(function(data){
			$("#RecipeFinderOutput").empty();
			$("#RecipeFinderOutput").append(data.parse.text['*']);
			mw.loader.using(["jquery.tablesorter"], function(){// have to load separately to make the table sortable
				$("#RecipeFinderOutput table.sortable").tablesorter();
			});
		});
	}

	$("#RecipeFinderSearchButton").on("click", FindRecipes);
	
	$("#RecipeFinderSearchInput").on("keyup", function(event){
		if(event.key == "Enter"){
			FindRecipes();
		}
	});
}