Mabinogi World Wiki is brought to you by Coty C., 808idiotz, our other patrons, and contributors like you!!
Want to make the wiki better? Contribute towards getting larger projects done on our Patreon!

Difference between revisions of "MediaWiki:Common.js"

From Mabinogi World Wiki
Jump to: navigation, search
m (testing out on demand loading of CalcSystem)
m
 
(68 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 +
// importX
 +
function importPage(name, type) {
 +
return mw.loader.load( '/index.php?title=' + name + '&action=raw&ctype=' + type, type );
 +
}
 +
 +
function importScript(name) { return importPage(name, 'text/javascript'); }
 +
function importStylesheet(name) { return importPage(name, 'text/css'); }
 +
 +
// Toggler buttons
 +
jQuery(function($) {
 +
$(".toggler").each(function() {
 +
var $this = $(this);
 +
$this.click(togglerClick.bind($this));
 +
if (!$this.hasClass("toggler-on") && !$this.hasClass("toggler-off")){
 +
$this.addClass("toggler-off");
 +
}
 +
if ($this.hasClass("start-on")) $this.click();
 +
});
 +
});
 +
 +
function togglerClick() {
 +
var $this = this, found = false;
 +
var classes = $this.attr("class");
 +
 +
classes.replace(/toggle-([\w\d\-]+)/g, function (_, target) {
 +
found = true;
 +
 +
var $target = $("." + target);
 +
var action = classes.match(/action-(\w+)(-(\w+))?/), arg;
 +
 +
if (action) {
 +
arg = action[3] || "";
 +
action = action[1];
 +
} else {
 +
action = "collapse";
 +
}
 +
 +
switch(action) {
 +
case "opacity":
 +
var isOn = $target.css("opacity") != "1";
 +
$target.css("opacity", isOn ? "1" : (parseInt(arg) / 100).toString());
 +
break;
 +
case "hide":
 +
var isOn = $target.css("visibility") != "visible";
 +
$target.css("visibility", isOn ? "visible" : "hidden");
 +
break;
 +
case "collapse":
 +
$target.toggle();
 +
break;
 +
default:
 +
console.warn("Toggler error: Action", action, "is not known.");
 +
return;
 +
}
 +
});
 +
 +
if (found) {
 +
$this.toggleClass("toggler-on");
 +
$this.toggleClass("toggler-off");
 +
} else {
 +
console.warn("Toggler error: Toggler must have a target defined with toggle-CLASS", this);
 +
}
 +
}
 +
 +
// Parking content box handling
 
jQuery(function($) {
 
jQuery(function($) {
 
$(".parking").each(function() {
 
$(".parking").each(function() {
Line 16: Line 80:
 
});
 
});
 
});
 
});
 +
});
 +
 +
// Add mini link near page titles.
 +
jQuery(function($) {
 +
var $img = $("<img>").attr({
 +
"alt": "mini",
 +
"title": "link here!",
 +
"src": "/skins/common/images/mw/mini.png"
 +
}).css({
 +
"margin-bottom": "3px",
 +
})
 +
 +
if(mw.config.exists("wgArticleId") && mw.config.get("wgArticleId") != "0") {
 +
$("<a>").css({
 +
"margin-left": "10px",
 +
"font-size": "12px"
 +
}).attr("href", "//mabi.world/w" + mw.config.get("wgArticleId").toString(36))
 +
.append($img.css({
 +
"vertical-align": "text-bottom",
 +
}))
 +
.appendTo(".firstHeading");
 +
}
 +
 +
var $mwftt = $(".mw-wikiforum-thread-top");
 +
if($mwftt.length > 0) {
 +
var threadNum = $mwftt.text().replace("[#", "").replace("]", "");
 +
$('<a>')
 +
.attr("href", "//mabi.world/D" + parseInt(threadNum).toString(36))
 +
.text("[#" + threadNum + "]")
 +
.append($img)
 +
.appendTo($mwftt.empty());
 +
}
 
});
 
});
  
Line 42: Line 138:
 
});
 
});
 
}
 
}
 +
}(jQuery));
 +
 +
// Collapse multiple references (click to expand)
 +
jQuery(function($) {
 +
    $(".mw-cite-backlink:has(sup)").each(function() {
 +
        var $this = $(this);
 +
        var $sups = $this.find("sup").hide();
 +
        var $arrow = $this.contents().first().detach();
 +
        $this.prepend(document.createTextNode(" "));
 +
       
 +
        $("<span>")
 +
        .css({
 +
            "cursor": "pointer",
 +
            "color": "blue",
 +
            "text-decoration": "underline",
 +
        })
 +
        .click(function () { $sups.toggle() })
 +
        .text($arrow.text().trim())
 +
        .prependTo($this);
 +
    });
 
}(jQuery));
 
}(jQuery));
  
Line 249: Line 365:
 
jQuery( createNavigationBarToggleButton );
 
jQuery( createNavigationBarToggleButton );
  
 +
/* Mouse-over boxes (Work-in-progress) */
 +
jQuery(function($) {
 +
var $affectedSpans = $(".mouseover-wrapper");
 +
 +
$affectedSpans.each(function () {
 +
var $this = $(this);
 +
 +
var $custom = $this.children(".mouseover-custom");
 +
 +
$this.data({
 +
"lock": false,
 +
 +
"style": $custom.children(".mouseover-custom-fade-style").text(),
 +
"anchor": parseInt($custom.children(".mouseover-custom-anchor").text() || 9),
 +
"modx": parseInt($custom.children(".mouseover-custom-modx").text() || 0),
 +
"mody": parseInt($custom.children(".mouseover-custom-mody").text() || 0),
 +
"fade-length": parseFloat($custom.children(".mouseover-custom-fade-length").text() || 200.0),
 +
});
 +
 +
$this.children(".mouseover-content").hide();
 +
 +
$this.click(mouseoverbox_open);
  
// Stuff to make special users have a different color. First written by Kotarou3
+
$this.mousemove(mouseoverbox_move);
// but extensively cleaned up by Saiyr.
+
$this.mouseout(mouseoverbox_out);
 +
});
  
// We don't look for things to color unless we're on a file, talk, special, or
+
$("body").click(mouseoverboxes_close)
// history page.
+
});
function shouldColorSpecialUsers() {
+
 
    return (wgNamespaceNumber == 6 ||     // File namespace
+
function get_largest_dims(elem, filter) {
            wgNamespaceNumber % 2 == 1 || // Talk namespaces are odd numbered
+
var $elem = $(elem), $ret = $elem, width = 0, height = 0;
            wgNamespaceNumber == -1 ||    // Special namespace
+
$elem.add($elem.find(filter || "*"))
            wgAction == 'history' ||      // History action
+
.filter(function () {
            location.search.indexOf('oldid') != -1); // Diff pages
+
var $this = $(this)
 +
var w = $this.width(), h = $this.height();
 +
if (w*h > width*height) {
 +
width = w;
 +
height = h;
 +
$ret = $this;
 +
}
 +
});
 +
return $ret;
 
}
 
}
  
function loadSpecialUsersFromCookie() {
+
function mouseoverbox_open(ev) {
    if (!document.cookie) {
+
var $this = $(this);
        return null;
+
 
    }
+
var x, y;
    var match = document.cookie.match(/(?:^|; )SpecialUsers=([^;]*)(?:$|;)/);
+
var modx = $this.data("modx"), mody = $this.data("mody");
    if (match != null) {
+
 
        try {
+
var $largest = get_largest_dims($this, ".mouseover-trigger, .mouseover-trigger *");
            return JSON.parse(unescape(match[1]));
+
var pos = $largest.offset();
        } catch (e) {
+
var triggerWidth = $largest.width();
            // ignore so we refetch
+
var triggerHeight = $largest.height();
        }
 
    }
 
    return null;
 
}
 
  
// Fetch all users in a group, handling pagination
+
var left = pos.left, top = pos.top;
function fetchGroupUsers($, group) {
+
var center = left + triggerWidth / 2, middle = top + triggerHeight / 2;
    var from = "";
+
var right = left + triggerWidth, bottom = top + triggerHeight;
    var fetchMore = true;
 
    var usersList = [];
 
    while (fetchMore) {
 
        $.ajax({
 
            url: "/api.php?action=query&format=json&list=allusers&augroup="
 
                + group + "&aufrom=" + from,
 
            async: false,
 
            success: function(users) {
 
                // users = JSON.parse(users); should be done automatically
 
                $.each(users.query.allusers, function(_, user) {
 
                    usersList.push(user.name);
 
                });
 
                if (users['query-continue']) {
 
                    from = encodeURIComponent(users['query-continue'].allusers.aufrom);
 
                } else {
 
                    fetchMore = false;
 
                }
 
            }});
 
    }
 
    return usersList;
 
}
 
  
var colorSpecialUsers = (function($) {
+
mouseoverboxes_close();
    return function() {
 
        // Maps groups to colors. The lower the group on the list, the higher
 
        // the precedence of the color.
 
        var specialColors = [
 
            [ 'sysop', '#1A8E18' ],
 
            [ 'bureaucrat', '#1A8E18' ],
 
            [ 'minion', '#008080' ]
 
        ];
 
        if (!shouldColorSpecialUsers()) {
 
            return;
 
        }
 
  
        var specialUsers = loadSpecialUsersFromCookie();
+
var $content = mouseoverbox_show($this);
        var needSpecialUsers = specialUsers == null;
 
  
        if (needSpecialUsers) {
+
$this.data("lock", true);
            specialUsers = {};
 
            $.each(specialColors, function(_, groupInfo) {
 
                var group = groupInfo[0];
 
                var color = groupInfo[1];
 
                var users = fetchGroupUsers($, group);
 
                $.each(users, function(_, user) {
 
                    specialUsers[user] = color;
 
                });
 
            });
 
            // Set a cookie expiring in 7 days to cache information
 
            var expirationDate = new Date();
 
            expirationDate.setDate(expirationDate.getDate() + 7);
 
            var cookieText = JSON.stringify(specialUsers);
 
            document.cookie = "SpecialUsers=" + escape(cookieText) +
 
                ";expires=" + expirationDate.toUTCString();
 
        }
 
        var userMatcher = /^User:(.*?)(?: \(page does not exist\))?$/;
 
        var noiseFilter = function() {
 
            // Get rid of diff links, etc
 
            return this.href.match(/User:[^&?#]+$/);
 
        };
 
        $('a[title^="User:"]').filter(noiseFilter).each(function(_, a) {
 
            var match = a.title.match(userMatcher);
 
            if (specialUsers[match[1]]) {
 
                a.style.color = specialUsers[match[1]];
 
            }
 
        });
 
    }
 
}(jQuery));
 
  
jQuery(colorSpecialUsers);
+
var $clargest = get_largest_dims($content);
 +
var width = $clargest.width();
 +
var height = $clargest.height();
  
/* Mouse-over boxes (Work-in-progress) */
+
switch ($this.data("anchor")) {
function initmouseoverbox()
+
case 1:
{
+
// Bottom-right of content to top-right of trigger.
var affectedSpans = new Array();
+
x = right - width + modx;
var affectedSpansi = 0;
+
y = top - height + (mody || -10);
var spans = document.getElementsByTagName("span");
+
break;
for (i = 0; i < spans.length; i++)
+
case 2:
{
+
// Bottom-center of content to top-center of trigger.
if (spans[i].getAttribute("class") == null)
+
x = center - width / 2 + modx;
continue;
+
y = top - height + (mody || -10);
var classes = spans[i].getAttribute("class").split(" ");
+
break;
for (c = 0; c < classes.length; c++)
+
case 3:
if (classes[c] == "mouseover-wrapper")
+
// Bottom-left of content to top-left of trigger.
{
+
x = left + modx;
affectedSpans[affectedSpansi] = i;
+
y = top - height + (mody || -10);
affectedSpansi++;
+
break;
break;
+
case 4:
}
+
// Middle-right of content to middle-left of trigger.
 +
x = left - width + (modx || -10);
 +
y = middle - height / 2 + mody;
 +
break;
 +
case 5:
 +
// Middle-center of content to middle-center of trigger.
 +
x = center - width / 2 + modx;
 +
y = middle - height / 2 + mody;
 +
break;
 +
case 6:
 +
// Middle-left of content to middle-right of trigger.
 +
x = right + (modx || 10);
 +
y = middle - height / 2 + mody;
 +
break;
 +
case 7:
 +
// Top-right of content to bottom-right of trigger.
 +
x = right - width + modx;
 +
y = bottom + (mody || 10);
 +
break;
 +
case 8:
 +
// Top-center of content to bottom-center of trigger.
 +
x = center - width / 2 + modx;
 +
y = bottom + (mody || 10);
 +
break;
 +
case 9:
 +
default:
 +
// Top-left of content to bottom-left of trigger.
 +
x = left + modx;
 +
y = bottom + (mody || 20);
 +
break;
 
}
 
}
  
var content = null;
+
$content.offset({
var mouseover = null;
+
"top": y,
var innerDivs = null;
+
"left": x,
for (i = 0; i < affectedSpansi; i++)
+
});
{
 
innerDivs = spans[affectedSpans[i]].getElementsByTagName("div");
 
for (c = 0; c < innerDivs.length; c++)
 
if (innerDivs[c].getAttribute("id") == "mouseover-content")
 
content = innerDivs[c];
 
else if (innerDivs[c].getAttribute("id") == "mouseover-trigger")
 
trigger = innerDivs[c];
 
content.style.display = "none";
 
  
/* Replace <p>s inside the trigger with <br />s */
+
ev.stopPropagation();
var ps = trigger.getElementsByTagName("p");
+
}
var anchor = trigger.getElementsByTagName("a");
 
var parent = null;
 
var innerHTML = null;
 
var e1 = null;
 
var e2 = null;
 
for (d = 0; d < anchor.length; d++)
 
{
 
anchor[d].setAttribute("title", "");
 
}
 
for (c = 0; c < ps.length; c++)
 
{
 
var parent = ps[c].parentNode;
 
var innerHTML = ps[c].innerHTML;
 
  
e1 = document.createElement("br");
+
function mouseoverboxes_close() {
parent.replaceChild(e1, ps[c]);
+
$(".mouseover-content:visible").each(function () {
e2 = document.createElement("br");
+
var $this = $(this).parent();
e2.setAttribute("class", "mouseover-p");
 
parent.insertBefore(e2, e1.nextSibling);
 
e1 = document.createTextNode(innerHTML);
 
parent.insertBefore(e1, e2.nextSibling);
 
e2 = document.createElement("br");
 
parent.insertBefore(e2, e1.nextSibling);
 
e1 = document.createElement("br");
 
e1.setAttribute("class", "mouseover-p");
 
parent.insertBefore(e1, e2.nextSibling);
 
}
 
  
trigger.setAttribute("onmouseover", "mouseoverbox(" + i + ", this, event);");
+
mouseoverbox_hide($this);
trigger.setAttribute("onmousemove", "mouseoverbox(" + i + ", this, event, true);");
+
$this.data("lock", false);
trigger.setAttribute("onmouseout", "mouseoverbox(" + i + ", this);");
+
})
}
 
 
}
 
}
jQuery(initmouseoverbox);
 
  
var mouseoverboxes = new Array();
+
function mouseoverbox_show($this) {
function mouseoverFade(id, fadelength, lastTick) // Had to make it global becuase of setTimeout
+
var $content = $this.find(".mouseover-content");
{
+
 
if (lastTick !== undefined)
+
$content
{
+
.stop()
var curTick = new Date().getTime();
+
.attr("style", $this.data("style"))
var elapsedTicks = curTick - lastTick;
+
.css({
 +
"position": "absolute",
 +
"opacity": "0"
 +
})
 +
.show();
  
if (mouseoverboxes[id].fadeState == 1 && mouseoverboxes[id].style.display != "block")
+
$content.animate({
mouseoverboxes[id].style.display = "block";
+
"opacity": "1",
 +
}, {
 +
"duration": $this.data("fade-length"),
 +
});
  
if (mouseoverboxes[id].fadeTimeLeft <= elapsedTicks)
+
return $content;
{
+
}
mouseoverboxes[id].style.opacity = mouseoverboxes[id].fadeState == 1 ? 1 : 0;
 
if (mouseoverboxes[id].fadeState == -1)
 
mouseoverboxes[id].style.display = "none";
 
mouseoverboxes[id].fadeState = mouseoverboxes[id].fadeState == 1 ? 2 : -2;
 
return;
 
}
 
  
mouseoverboxes[id].fadeTimeLeft -= elapsedTicks;
+
function mouseoverbox_move(ev) {
var newOpVal = mouseoverboxes[id].fadeTimeLeft/fadelength;
+
var $this = $(this);
if (mouseoverboxes[id].fadeState == 1)
+
var $content = $this.find(".mouseover-content");
newOpVal = 1 - newOpVal;
 
  
mouseoverboxes[id].style.opacity = newOpVal;
+
if ($this.data("lock")) return;
  
setTimeout("mouseoverFade(" + id + ", " + fadelength + ", " + curTick + ")", 20);
+
// If we're over the content and it moved out, close.
 +
if (mouseoverbox_movedout($this, ev)) {
 +
mouseoverbox_hide($this);
 
return;
 
return;
 +
} else if (!$content.is(":visible")) {
 +
mouseoverbox_show($this)
 
}
 
}
if (mouseoverboxes[id].fadeState == undefined)
 
if (mouseoverboxes[id].style.opacity == undefined || mouseoverboxes[id].style.opacity == "" || mouseoverboxes[id].style.opacity == 1)
 
mouseoverboxes[id].fadeState = 2;
 
else
 
mouseoverboxes[id].fadeState = -2;
 
  
if (mouseoverboxes[id].fadeState == 1 || mouseoverboxes[id].fadeState == -1)
+
var x, y;
{
+
var modx = $this.data("modx"), mody = $this.data("mody");
mouseoverboxes[id].fadeState = mouseoverboxes[id].fadeState == 1 ? -1 : 1;
+
 
mouseoverboxes[id].fadeTimeLeft = fadelength - mouseoverboxes[id].fadeTimeLeft;
+
var $largest = get_largest_dims($content);
 +
var width = $largest.width();
 +
var height = $largest.height();
 +
 
 +
switch ($this.data("anchor")) {
 +
case 1:
 +
y = (mody || -10) - height;
 +
x = (modx || -10) - width;
 +
break;
 +
case 2:
 +
y = (mody || -10) - height;
 +
x = modx - width / 2;
 +
break;
 +
case 3:
 +
y = (mody || -10) - height;
 +
x = (modx || 10);
 +
break;
 +
case 4:
 +
y = mody - height / 2;
 +
x = (modx || -10) - width;
 +
break;
 +
case 5:
 +
y = mody - height / 2;
 +
x = modx - width / 2;
 +
break;
 +
case 6:
 +
y = mody - height / 2;
 +
x = (modx || 10);
 +
break;
 +
case 7:
 +
y = (mody || 10);
 +
x = (modx || -10) - width;
 +
break;
 +
case 8:
 +
y = (mody || 10);
 +
x = modx - width / 2;
 +
break;
 +
case 9:
 +
default:
 +
y = (mody || 20);
 +
x = (modx || -1);
 +
break;
 
}
 
}
else
+
 
{
+
$content.offset({
mouseoverboxes[id].fadeState = mouseoverboxes[id].fadeState == 2 ? -1 : 1;
+
"top": ev.pageY + y,
mouseoverboxes[id].fadeTimeLeft = fadelength;
+
"left": ev.pageX + x,
setTimeout("mouseoverFade(" + id + ", " + fadelength + ", " + new Date().getTime() + ")", 20);
+
});
}
 
 
}
 
}
function mouseoverbox(id, obj, event, update)
 
{
 
function updatexy(id, event)
 
{
 
var x, y;
 
switch (mouseoverboxes[id].settings["anchor"])
 
{
 
case 1:
 
y = (-mouseoverboxes[id].offsetHeight) + (mouseoverboxes[id].settings["mody"] == 0 ? -10 : mouseoverboxes[id].settings["mody"]);
 
x = (-mouseoverboxes[id].offsetWidth) + (mouseoverboxes[id].settings["modx"] == 0 ? -10 : mouseoverboxes[id].settings["modx"]);
 
break;
 
case 2:
 
y = (-mouseoverboxes[id].offsetHeight) + (mouseoverboxes[id].settings["mody"] == 0 ? -10 : mouseoverboxes[id].settings["mody"]);
 
x = (-(mouseoverboxes[id].offsetWidth/2)) + mouseoverboxes[id].settings["modx"];
 
break;
 
case 3:
 
y = (-mouseoverboxes[id].offsetHeight) + (mouseoverboxes[id].settings["mody"] == 0 ? -10 : mouseoverboxes[id].settings["mody"]);
 
x = mouseoverboxes[id].settings["modx"] == 0 ? 10 : mouseoverboxes[id].settings["modx"];
 
break;
 
case 4:
 
y = (-(mouseoverboxes[id].offsetHeight/2)) + mouseoverboxes[id].settings["mody"];
 
x = (-mouseoverboxes[id].offsetWidth) + (mouseoverboxes[id].settings["modx"] == 0 ? -10 : mouseoverboxes[id].settings["modx"]);
 
break;
 
case 5:
 
y = (-(mouseoverboxes[id].offsetHeight/2)) + mouseoverboxes[id].settings["mody"];
 
x = (-(mouseoverboxes[id].offsetWidth/2)) + mouseoverboxes[id].settings["modx"];
 
break;
 
case 6:
 
y = (-(mouseoverboxes[id].offsetHeight/2)) + mouseoverboxes[id].settings["mody"];
 
x = mouseoverboxes[id].settings["modx"] == 0 ? 10 : mouseoverboxes[id].settings["modx"];
 
break;
 
case 7:
 
y = mouseoverboxes[id].settings["mody"] == 0 ? 10 : mouseoverboxes[id].settings["mody"];
 
x = (-mouseoverboxes[id].offsetWidth) + (mouseoverboxes[id].settings["modx"] == 0 ? -10 : mouseoverboxes[id].settings["modx"]);
 
break;
 
case 8:
 
y = mouseoverboxes[id].settings["mody"] == 0 ? 10 : mouseoverboxes[id].settings["mody"];
 
x = (-(mouseoverboxes[id].offsetWidth/2)) + mouseoverboxes[id].settings["modx"];
 
break;
 
case 9:
 
default:
 
y = mouseoverboxes[id].settings["mody"] == 0 ? 20 : mouseoverboxes[id].settings["mody"];
 
x = mouseoverboxes[id].settings["modx"] == 0 ? -1 : mouseoverboxes[id].settings["modx"];
 
break;
 
}
 
  
mouseoverboxes[id].style.top = (event.clientY + y) + "px";
+
function mouseoverbox_movedout($this, ev) {
mouseoverboxes[id].style.left = (event.clientX + x) + "px";
+
var $trigger = $this.find(".mouseover-trigger");
}
+
 
 +
var $largest = get_largest_dims($trigger);
 +
var pos = $largest.offset();
 +
var width = $largest.width();
 +
var height = $largest.height();
  
if (mouseoverboxes[id] === undefined)
+
var x = ev.pageX, y = ev.pageY;
{
 
mouseoverboxes[id] = document.createElement("div");
 
  
var settings = new Array();
+
return x < pos.left || x > pos.left + width
/* Defaults */
+
|| y < pos.top || y > pos.top + height;
settings["style"] = "";
+
}
settings["anchor"] = 9;
 
settings["modx"] = 0;
 
settings["mody"] = 0;
 
settings["fade-length"] = 200.0;
 
  
var divs = obj.parentNode.getElementsByTagName("div");
+
function mouseoverbox_out(ev) {
for (i = 0; i < divs.length; i++)
+
var $this = $(this);
if (divs[i].getAttribute("id") == "mouseover-custom")
 
{
 
var spans = divs[i].getElementsByTagName("span");
 
for (c = 0; c < spans.length; c++)
 
switch (spans[c].getAttribute("id"))
 
{
 
case "mouseover-custom-style":
 
if (spans[c].innerHTML != "")
 
settings["style"] = spans[c].innerHTML;
 
break;
 
case "mouseover-custom-anchor":
 
if (spans[c].innerHTML != "")
 
settings["anchor"] = parseInt(spans[c].innerHTML);
 
break;
 
case "mouseover-custom-modx":
 
if (spans[c].innerHTML != "")
 
settings["modx"] = parseInt(spans[c].innerHTML);
 
break;
 
case "mouseover-custom-mody":
 
if (spans[c].innerHTML != "")
 
settings["mody"] = parseInt(spans[c].innerHTML);
 
break;
 
case "mouseover-custom-fade-length":
 
if (spans[c].innerHTML != "")
 
settings["fade-length"] = parseInt(spans[c].innerHTML);
 
break;
 
}
 
break;
 
}
 
else if (divs[i].getAttribute("id") == "mouseover-content")
 
mouseoverboxes[id].innerHTML = divs[i].innerHTML;
 
  
mouseoverboxes[id].setAttribute("class", "mouseover-box");
+
if ($this.data("lock")) return;
mouseoverboxes[id].style.cssText = settings["style"];
 
mouseoverboxes[id].style.display = "none";
 
mouseoverboxes[id].style.position = "fixed";
 
mouseoverboxes[id].style.opacity = 0;
 
mouseoverboxes[id].settings = settings;
 
document.getElementById("bodyContent").appendChild(mouseoverboxes[id]);
 
}
 
  
if (event !== undefined)
+
if (event.relatedTarget && event.relatedTarget.parentNode == this) {
{
+
// Make sure we're still in the bounding box.
updatexy(id, event);
+
if (!mouseoverbox_movedout($this, ev)) {
if (mouseoverboxes[id].style.display != "block")
 
mouseoverboxes[id].style.display = "block";
 
if (update == true)
 
 
return;
 
return;
 +
}
 
}
 
}
 +
 +
mouseoverbox_hide($this);
 +
}
 +
 +
function mouseoverbox_hide($this) {
 +
var $content = $this.find(".mouseover-content");
  
mouseoverFade(id, mouseoverboxes[id].settings["fade-length"]);
+
$content.animate({
 +
"opacity": "0",
 +
}, {
 +
"duration": $this.data("fade-length"),
 +
"complete": function () { $content.hide() },
 +
});
 
}
 
}
  
Line 630: Line 672:
 
         $.each(convertibleDivClasses, function(_, cssClass) {
 
         $.each(convertibleDivClasses, function(_, cssClass) {
 
             var $links = $('.' + cssClass + ' a.new[href*="Special:Upload"]');
 
             var $links = $('.' + cssClass + ' a.new[href*="Special:Upload"]');
             $links.html('<img src="http://wiki.mabinogiworld.com/images/f/f0/No_File.png" />');
+
             $links.html('<img src="//wiki.mabinogiworld.com/images/f/f0/No_File.png" />');
 
         });
 
         });
 
     }
 
     }
Line 636: Line 678:
 
jQuery(convertRedImageLinksToNotFoundImage);
 
jQuery(convertRedImageLinksToNotFoundImage);
  
//
 
// Timers JS
 
//
 
/*
 
JavaScript module for calculating Mabinogi schedules.
 
  
Copyright 2011 Saiyr (me@saiyr.org)
+
jQuery.fn.reverse = Array.prototype.reverse;
 +
// Scroll to hidden sections on the wiki
 +
function doScrollPage() {
 +
if (location.hash && location.hash.length > 1) {
 +
var $x = $(location.hash + ', a[name="' + location.hash.substr(1) + '"]');
 +
if (!$x.is(":visible")) {
 +
var parents = $x.parents(".NavContent");
 +
if (parents.length) {
 +
// Spoiler tag.
 +
parents.reverse().each(function () {
 +
var $this = $(this);
 +
if (!$this.is(":visible")) {
 +
toggleNavigationBar(parseInt($this.parent().children(".NavHead").children(".NavToggle").attr("id").substr(9)));
 +
}
 +
});
 +
} else if ((parents = $x.parents(".tabdiv")).length) {
 +
// Tabs.
 +
$x.parents('div[id*="tab"]').each(function () {
 +
var $this = $(this);
 +
$this.parent(".tabdiv").children("ul").children("li:nth-child(" + $(this).attr("id").replace(/^.*tab/,'') + ")").click()
 +
});
 +
}
 +
}
 +
$("html,body").scrollTop($x.offset().top)
 +
}
 +
}
 +
jQuery(doScrollPage);
  
License: http://www.opensource.org/licenses/mit-license.php
+
var onloadHash = location.hash;
 
+
jQuery.getScript('//mabi.world/jquery.ba-hashchange.js', function () {
Original work by Kakurady (Moongates, Price) and Huijun (Rua).
+
jQuery(window).hashchange(doScrollPage);
*/
+
if (onloadHash != location.hash) doScrollPage();
(function(a,n){function e(a,b,e){return function(f,k){var g,h;g=c.o(f).G;var d=f-f%l;h=Math.floor((f-b)/l)%a.length;e&&(g<6?d-=6*i:d+=18*i);h<0&&(h+=a.length);g=d;for(var d=[],j=0;j<k;j++)d.push({time:new Date(g+l*j),item:a[(j+h)%a.length]});return d}}var i=9E4,l=i*24,k=Date.parse("Mar 23, 2008 22:21:00 GMT"),m=[a.a.d,a.a.c,a.a.e,a.a.i,a.a.h,a.a.d,a.a.g,a.a.j,a.a.f,a.a.h,a.a.d,a.a.e,a.a.i,a.a.c,a.a.h,a.a.d,a.a.f,a.a.g,a.a.j,a.a.d,a.a.i,a.a.e,a.a.g,a.a.f],p=Date.parse("Mar 24, 2008 00:00:00 GMT"),
+
});
c={A:function(o){return(o||new Date).getTime()+a.D},m:e(m,k,!0),w:e([a.b.e,a.b.l,a.b.r,a.b.k,a.b.p,a.b.n,a.b.t,a.b.c,a.b.u,a.b.n,a.b.k,a.b.q,a.b.s,a.b.l],p,!1),z:e(function(a){var b=a.B,a=a.F;return[b,b,b,a,b,b,b,b,a,b,b,a,b,a,a,b,a,a,a,b,b,b,b,b,b,b,a,b,a,b,b,a,b,b,b,a,b,b,b,a,b,b,a]}(a.C),k,!0),o:function(a){return{hour:Math.floor(a/i)%24,minute:Math.floor(a/1500)%60}},v:function(c){for(var c=this.m(c,m.length),b=0;b<c.length;b++)if(c[b].item===a.a.c)return b}};n.mabiTimers=c;c.getServerTimeMillis=
 
c.A;c.getMoonGates=c.m;c.getPriceLocations=c.w;c.getRuaStatuses=c.z;c.serverTimeToErinnTime=c.o;c.getNextCeoMoonGate=c.v})({a:{e:"Tir Chonaill",g:"Dunbarton",f:"Bangor",h:"Emain Macha",i:"Taillteann",d:"Tara",c:"Ceo Island",j:"Port Ceann"},b:{e:"Outside Tir Chonaill Inn",l:"Dugald Aisle Logging Camp Hut",r:"Dunbarton East Potato Field",k:"Dragon Ruins - House at 5 o'clock ",p:"Bangor Bar",n:"Sen Mag 5th house from West",t:"Emain Macha - Alley Behind Weapon Shop",c:"Ceo Island",u:"Emain Macha - Island in South Pathway",
 
q:"Outside Barri Dungeon",s:"Dunbarton School Stairway"},C:{B:"Resting",F:"Working"},D:-252E5},window);
 
 
 
importScript('MediaWiki:Calculator.js');
 
  
 
// don't load the calc system unless it will actually do something
 
// don't load the calc system unless it will actually do something
Line 659: Line 717:
 
     importScript('MediaWiki:CalcSystem.js');
 
     importScript('MediaWiki:CalcSystem.js');
 
}
 
}
 +
 +
var weatherWidget = $(".weather-widget-rain-summary, .weather-widget-hour, .weather-widget").length > 0;
 +
var timerWidget = $(".make-timer, .time-erinn-current, .time-server-current").length > 0;
 +
 +
if (weatherWidget || timerWidget) {
 +
    jQuery.getScript('//mabi.world/moment.js', function () {
 +
        jQuery.getScript('//mabi.world/moment-timezone-with-data.js', function () {
 +
            jQuery.getScript('//mabi.world/widgets.js', function () {
 +
                if (weatherWidget) {
 +
                    jQuery.getScript('https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.3/jquery-ui.min.js', function () {
 +
                        jQuery.getScript('//mabi.world/forecast.js');
 +
                        importStylesheet('MediaWiki:Forecast.css');
 +
                    });
 +
                }
 +
                if (timerWidget) {
 +
                    jQuery.getScript('//mabi.world/timers.js');
 +
                    importStylesheet('MediaWiki:Timers.css');
 +
                }
 +
            })
 +
        })
 +
    });
 +
}
 +
 +
jQuery(function () {
 +
    importScript('MediaWiki:Toolbar.js');
 +
});
 +
 +
jQuery(function ($) {
 +
    switch ($("#LoadFormScript").text()) {
 +
    case "Enchant": importScript("MediaWiki:EnchantForm.js"); break;
 +
    case "Title": importScript("MediaWiki:TitleForm.js"); break;
 +
    }
 +
});

Latest revision as of 19:18, 13 March 2019

// importX
function importPage(name, type) {
	return mw.loader.load( '/index.php?title=' + name + '&action=raw&ctype=' + type, type );
}

function importScript(name) { return importPage(name, 'text/javascript'); }
function importStylesheet(name) { return importPage(name, 'text/css'); }

// Toggler buttons
jQuery(function($) {
	$(".toggler").each(function() {
		var $this = $(this);
		$this.click(togglerClick.bind($this));
		if (!$this.hasClass("toggler-on") && !$this.hasClass("toggler-off")){
			$this.addClass("toggler-off");
		}
		if ($this.hasClass("start-on")) $this.click();
	});
});

function togglerClick() {
	var $this = this, found = false;
	var classes = $this.attr("class");

	classes.replace(/toggle-([\w\d\-]+)/g, function (_, target) {
		found = true;

		var $target = $("." + target);
		var action = classes.match(/action-(\w+)(-(\w+))?/), arg;

		if (action) {
			arg = action[3] || "";
			action = action[1];
		} else {
			action = "collapse";
		}

		switch(action) {
			case "opacity":
				var isOn = $target.css("opacity") != "1";
				$target.css("opacity", isOn ? "1" : (parseInt(arg) / 100).toString());
				break;
			case "hide":
				var isOn = $target.css("visibility") != "visible";
				$target.css("visibility", isOn ? "visible" : "hidden");
				break;
			case "collapse":
				$target.toggle();
				break;
			default:
				console.warn("Toggler error: Action", action, "is not known.");
				return;
		}
	});

	if (found) {
		$this.toggleClass("toggler-on");
		$this.toggleClass("toggler-off");
	} else {
		console.warn("Toggler error: Toggler must have a target defined with toggle-CLASS", this);
	}
}

// Parking content box handling
jQuery(function($) {
	$(".parking").each(function() {
		var $this = $(this);
		$this.data("position", $this.css("position"));
		$this.data("top", $this.offset().top);
	});
	$(window).bind("scroll resize", function(){
		var scrollTop = $(window).scrollTop();
		$(".parking").each(function() {
			var $this = $(this);
			if (scrollTop >= $this.data("top") && scrollTop !== 0) {
				$this.css("position", "fixed");
			} else {
				$this.css("position", $this.data("position"));
			}
		});
	});
});

// Add mini link near page titles.
jQuery(function($) {
	var $img = $("<img>").attr({
		"alt": "mini",
		"title": "link here!",
		"src": "/skins/common/images/mw/mini.png"
	}).css({
		"margin-bottom": "3px",
	})

	if(mw.config.exists("wgArticleId") && mw.config.get("wgArticleId") != "0") {
		$("<a>").css({
			"margin-left": "10px",
			"font-size": "12px"
		}).attr("href", "//mabi.world/w" + mw.config.get("wgArticleId").toString(36))
		.append($img.css({
			"vertical-align": "text-bottom",
		}))
		.appendTo(".firstHeading");
	}

	var $mwftt = $(".mw-wikiforum-thread-top");
	if($mwftt.length > 0) {
		var threadNum = $mwftt.text().replace("[#", "").replace("]", "");
		$('<a>')
		.attr("href", "//mabi.world/D" + parseInt(threadNum).toString(36))
		.text("[#" + threadNum + "]")
		.append($img)
		.appendTo($mwftt.empty());
	}
});

jQuery(function($) {
	return function() {
		$('.tabdiv > div').hide();
		$('.tabdiv').each(function() {
			$(this).find('> ul li').addClass('inactive');
			$(this).find('> ul li:first').removeClass('inactive');
			$(this).find('> ul li:first').addClass('active');
			$(this).find('> div:first').show();
		});
	 	$('.tabdiv > ul li').each(function() {
			var a = $(this).find('a:first');
			var target = a.attr('href');
			$(a).attr('href', ''); // Opera hates real hrefs
			$(this).click(function() {
				$(this).parent().find('> li').removeClass('active');
				$(this).parent().find('> li').addClass('inactive');
				$(this).parent().parent().find('> div').hide();
				$(this).addClass('active');
				$(this).removeClass('inactive');
				$(target).show();
				return false;
			});
		});
	}
}(jQuery));

// Collapse multiple references (click to expand)
jQuery(function($) {
    $(".mw-cite-backlink:has(sup)").each(function() {
        var $this = $(this);
        var $sups = $this.find("sup").hide();
        var $arrow = $this.contents().first().detach();
        $this.prepend(document.createTextNode(" "));
        
        $("<span>")
        .css({
            "cursor": "pointer",
            "color": "blue",
            "text-decoration": "underline",
        })
        .click(function () { $sups.toggle() })
        .text($arrow.text().trim())
        .prependTo($this);
    });
}(jQuery));

/** Collapsible tables *********************************************************
 *
 *  Description: Allows tables to be collapsed, showing only the header. See
 *               [[Wikipedia:NavFrame]].
 *  Maintainers: [[User:R. Koot]]
 */
 
var autoCollapse = 2;
var collapseCaption = "hide";
var expandCaption = "show";
 
function collapseTable( tableIndex )
{
    var Button = document.getElementById( "collapseButton" + tableIndex );
    var Table = document.getElementById( "collapsibleTable" + tableIndex );
 
    if ( !Table || !Button ) {
        return false;
    }
 
    var Rows = Table.rows;
 
    if ( Button.firstChild.data == collapseCaption ) {
        for ( var i = 1; i < Rows.length; i++ ) {
            Rows[i].style.display = "none";
        }
        Button.firstChild.data = expandCaption;
    } else {
        for ( var i = 1; i < Rows.length; i++ ) {
            Rows[i].style.display = Rows[0].style.display;
        }
        Button.firstChild.data = collapseCaption;
    }
}

/* Test if an element has a certain class **************************************
 *
 * Description: Uses regular expressions and caching for better performance.
 * Maintainers: [[User:Mike Dillon]], [[User:R. Koot]], [[User:SG]]
 */
 
var hasClass = ( function() {
        var reCache = {};
        return function( element, className ) {
                return ( reCache[className] ? reCache[className] : ( reCache[className] = new RegExp( "(?:\\s|^)" + className + "(?:\\s|$)" ) ) ).test( element.className );
        };
})();
 
function createCollapseButtons()
{
    var tableIndex = 0;
    var NavigationBoxes = new Object();
    var Tables = document.getElementsByTagName( "table" );
 
    for ( var i = 0; i < Tables.length; i++ ) {
        if ( hasClass( Tables[i], "collapsible" ) ) {
 
            /* only add button and increment count if there is a header row to work with */
            var HeaderRow = Tables[i].getElementsByTagName( "tr" )[0];
            if (!HeaderRow) continue;
            var Header = HeaderRow.getElementsByTagName( "th" )[0];
            if (!Header) continue;
 
            NavigationBoxes[ tableIndex ] = Tables[i];
            Tables[i].setAttribute( "id", "collapsibleTable" + tableIndex );
 
            var Button     = document.createElement( "span" );
            var ButtonLink = document.createElement( "a" );
            var ButtonText = document.createTextNode( collapseCaption );
 
            Button.style.styleFloat = "right";
            Button.style.cssFloat = "right";
            Button.style.fontWeight = "normal";
            Button.style.textAlign = "right";
            Button.style.width = "auto";
            Button.className = "collapseButton";  /* Khenta Edit */ //Styles are declared in Common.css 
            ButtonLink.style.color = Header.style.color;
            ButtonLink.setAttribute( "id", "collapseButton" + tableIndex );
            ButtonLink.setAttribute( "href", "javascript:collapseTable(" + tableIndex + ");" );
            ButtonLink.appendChild( ButtonText );
 
            Button.appendChild( document.createTextNode( "[" ) );
            Button.appendChild( ButtonLink );
            Button.appendChild( document.createTextNode( "]" ) );
 
            Header.insertBefore( Button, Header.childNodes[0] );
            tableIndex++;
        }
    }
 
    for ( var i = 0;  i < tableIndex; i++ ) {
        if ( hasClass( NavigationBoxes[i], "collapsed" ) || ( tableIndex >= autoCollapse && hasClass( NavigationBoxes[i], "autocollapse" ) ) ) {
            collapseTable( i );
        } 
        else if ( hasClass( NavigationBoxes[i], "innercollapse" ) ) {
            var element = NavigationBoxes[i];
            while (element = element.parentNode) {
                if ( hasClass( element, "outercollapse" ) ) {
                    collapseTable ( i );
                    break;
                }
            }
        }
    }
}
 
jQuery( createCollapseButtons );
 
 
/** Dynamic Navigation Bars (experimental) *************************************
 *
 *  Description: See [[Wikipedia:NavFrame]].
 *  Maintainers: UNMAINTAINED
 */
 
// set up the words in your language
var NavigationBarHide = '[' + collapseCaption + ']';
var NavigationBarShow = '[' + expandCaption + ']';
 
// shows and hides content and picture (if available) of navigation bars
// Parameters:
//     indexNavigationBar: the index of navigation bar to be toggled
function toggleNavigationBar(indexNavigationBar)
{
    var NavToggle = document.getElementById("NavToggle" + indexNavigationBar);
    var NavFrame = document.getElementById("NavFrame" + indexNavigationBar);
 
    if (!NavFrame || !NavToggle) {
        return false;
    }
 
    // if shown now
    if (NavToggle.firstChild.data == NavigationBarHide) {
        for (var NavChild = NavFrame.firstChild; NavChild != null; NavChild = NavChild.nextSibling) {
            if (hasClass(NavChild, 'NavContent') || hasClass(NavChild, 'NavPic')) {
                NavChild.style.display = 'none';
            }
        }
    NavToggle.firstChild.data = NavigationBarShow;
 
    // if hidden now
    } else if (NavToggle.firstChild.data == NavigationBarShow) {
        for (var NavChild = NavFrame.firstChild; NavChild != null; NavChild = NavChild.nextSibling) {
            if (hasClass(NavChild, 'NavContent') || hasClass(NavChild, 'NavPic')) {
                NavChild.style.display = 'block';
            }
        }
        NavToggle.firstChild.data = NavigationBarHide;
    }
}
 
// adds show/hide-button to navigation bars
function createNavigationBarToggleButton()
{
    var indexNavigationBar = 0;
    // iterate over all < div >-elements 
    var divs = document.getElementsByTagName("div");
    for (var i = 0; NavFrame = divs[i]; i++) {
        // if found a navigation bar
        if (hasClass(NavFrame, "NavFrame")) {
 
            indexNavigationBar++;
            var NavToggle = document.createElement("a");
            NavToggle.className = 'NavToggle';
            NavToggle.setAttribute('id', 'NavToggle' + indexNavigationBar);
            NavToggle.setAttribute('href', 'javascript:toggleNavigationBar(' + indexNavigationBar + ');');
 
            var isCollapsed = hasClass( NavFrame, "collapsed" );
            /*
             * Check if any children are already hidden.  This loop is here for backwards compatibility:
             * the old way of making NavFrames start out collapsed was to manually add style="display:none"
             * to all the NavPic/NavContent elements.  Since this was bad for accessibility (no way to make
             * the content visible without JavaScript support), the new recommended way is to add the class
             * "collapsed" to the NavFrame itself, just like with collapsible tables.
             */
            for (var NavChild = NavFrame.firstChild; NavChild != null && !isCollapsed; NavChild = NavChild.nextSibling) {
                if ( hasClass( NavChild, 'NavPic' ) || hasClass( NavChild, 'NavContent' ) ) {
                    if ( NavChild.style.display == 'none' ) {
                        isCollapsed = true;
                    }
                }
            }
            if (isCollapsed) {
                for (var NavChild = NavFrame.firstChild; NavChild != null; NavChild = NavChild.nextSibling) {
                    if ( hasClass( NavChild, 'NavPic' ) || hasClass( NavChild, 'NavContent' ) ) {
                        NavChild.style.display = 'none';
                    }
                }
            }
            var NavToggleText = document.createTextNode(isCollapsed ? NavigationBarShow : NavigationBarHide);
            NavToggle.appendChild(NavToggleText);
 
            // Find the NavHead and attach the toggle link (Must be this complicated because Moz's firstChild handling is borked)
            for(var j=0; j < NavFrame.childNodes.length; j++) {
                if (hasClass(NavFrame.childNodes[j], "NavHead")) {
                    NavFrame.childNodes[j].appendChild(NavToggle);
                }
            }
            NavFrame.setAttribute('id', 'NavFrame' + indexNavigationBar);
        }
    }
}
 
jQuery( createNavigationBarToggleButton );

/* Mouse-over boxes (Work-in-progress) */
jQuery(function($) {
	var $affectedSpans = $(".mouseover-wrapper");

	$affectedSpans.each(function () {
		var $this = $(this);

		var $custom = $this.children(".mouseover-custom");

		$this.data({
			"lock": false,

			"style": $custom.children(".mouseover-custom-fade-style").text(),
			"anchor": parseInt($custom.children(".mouseover-custom-anchor").text() || 9),
			"modx": parseInt($custom.children(".mouseover-custom-modx").text() || 0),
			"mody": parseInt($custom.children(".mouseover-custom-mody").text() || 0),
			"fade-length": parseFloat($custom.children(".mouseover-custom-fade-length").text() || 200.0),
		});

		$this.children(".mouseover-content").hide();

		$this.click(mouseoverbox_open);

		$this.mousemove(mouseoverbox_move);
		$this.mouseout(mouseoverbox_out);
	});

	$("body").click(mouseoverboxes_close)
});

function get_largest_dims(elem, filter) {
	var $elem = $(elem), $ret = $elem, width = 0, height = 0;
	$elem.add($elem.find(filter || "*"))
		.filter(function () {
			var $this = $(this)
			var w = $this.width(), h = $this.height();
			if (w*h > width*height) {
				width = w;
				height = h;
				$ret = $this;
			}
		});
	return $ret;
}

function mouseoverbox_open(ev) {
	var $this = $(this);

	var x, y;
	var modx = $this.data("modx"), mody = $this.data("mody");

	var $largest = get_largest_dims($this, ".mouseover-trigger, .mouseover-trigger *");
	var pos = $largest.offset();
	var triggerWidth = $largest.width();
	var triggerHeight = $largest.height();

	var left = pos.left, top = pos.top;
	var center = left + triggerWidth / 2, middle = top + triggerHeight / 2;
	var right = left + triggerWidth, bottom = top + triggerHeight;

	mouseoverboxes_close();

	var $content = mouseoverbox_show($this);

	$this.data("lock", true);

	var $clargest = get_largest_dims($content);
	var width = $clargest.width();
	var height = $clargest.height();

	switch ($this.data("anchor")) {
		case 1:
			// Bottom-right of content to top-right of trigger.
			x = right - width + modx;
			y = top - height + (mody || -10);
			break;
		case 2:
			// Bottom-center of content to top-center of trigger.
			x = center - width / 2 + modx;
			y = top - height + (mody || -10);
			break;
		case 3:
			// Bottom-left of content to top-left of trigger.
			x = left + modx;
			y = top - height + (mody || -10);
			break;
		case 4:
			// Middle-right of content to middle-left of trigger.
			x = left - width + (modx || -10);
			y = middle - height / 2 + mody;
			break;
		case 5:
			// Middle-center of content to middle-center of trigger.
			x = center - width / 2 + modx;
			y = middle - height / 2 + mody;
			break;
		case 6:
			// Middle-left of content to middle-right of trigger.
			x = right + (modx || 10);
			y = middle - height / 2 + mody;
			break;
		case 7:
			// Top-right of content to bottom-right of trigger.
			x = right - width + modx;
			y = bottom + (mody || 10);
			break;
		case 8:
			// Top-center of content to bottom-center of trigger.
			x = center - width / 2 + modx;
			y = bottom + (mody || 10);
			break;
		case 9:
		default:
			// Top-left of content to bottom-left of trigger.
			x = left + modx;
			y = bottom + (mody || 20);
			break;
	}

	$content.offset({
		"top": y,
		"left": x,
	});

	ev.stopPropagation();
}

function mouseoverboxes_close() {
	$(".mouseover-content:visible").each(function () {
		var $this = $(this).parent();

		mouseoverbox_hide($this);
		$this.data("lock", false);
	})
}

function mouseoverbox_show($this) {
	var $content = $this.find(".mouseover-content");

	$content
		.stop()
		.attr("style", $this.data("style"))
		.css({
			"position": "absolute",
			"opacity": "0"
		})
		.show();

	$content.animate({
		"opacity": "1",
	}, {
		"duration": $this.data("fade-length"),
	});

	return $content;
}

function mouseoverbox_move(ev) {
	var $this = $(this);
	var $content = $this.find(".mouseover-content");

	if ($this.data("lock")) return;

	// If we're over the content and it moved out, close.
	if (mouseoverbox_movedout($this, ev)) {
		mouseoverbox_hide($this);
		return;
	} else if (!$content.is(":visible")) {
		mouseoverbox_show($this)
	}

	var x, y;
	var modx = $this.data("modx"), mody = $this.data("mody");

	var $largest = get_largest_dims($content);
	var width = $largest.width();
	var height = $largest.height();

	switch ($this.data("anchor")) {
		case 1:
			y = (mody || -10) - height;
			x = (modx || -10) - width;
			break;
		case 2:
			y = (mody || -10) - height;
			x = modx - width / 2;
			break;
		case 3:
			y = (mody || -10) - height;
			x = (modx || 10);
			break;
		case 4:
			y = mody - height / 2;
			x = (modx || -10) - width;
			break;
		case 5:
			y = mody - height / 2;
			x = modx - width / 2;
			break;
		case 6:
			y = mody - height / 2;
			x = (modx || 10);
			break;
		case 7:
			y = (mody || 10);
			x = (modx || -10) - width;
			break;
		case 8:
			y = (mody || 10);
			x = modx - width / 2;
			break;
		case 9:
		default:
			y = (mody || 20);
			x = (modx || -1);
			break;
	}

	$content.offset({
		"top": ev.pageY + y,
		"left": ev.pageX + x,
	});
}

function mouseoverbox_movedout($this, ev) {
	var $trigger = $this.find(".mouseover-trigger");

	var $largest = get_largest_dims($trigger);
	var pos = $largest.offset();
	var width = $largest.width();
	var height = $largest.height();

	var x = ev.pageX, y = ev.pageY;

	return x < pos.left || x > pos.left + width
		|| y < pos.top || y > pos.top + height;
}

function mouseoverbox_out(ev) {
	var $this = $(this);

	if ($this.data("lock")) return;

	if (event.relatedTarget && event.relatedTarget.parentNode == this) {
		// Make sure we're still in the bounding box.
		if (!mouseoverbox_movedout($this, ev)) {
			return;
		}
	}
	
	mouseoverbox_hide($this);
}

function mouseoverbox_hide($this) {
	var $content = $this.find(".mouseover-content");

	$content.animate({
		"opacity": "0",
	}, {
		"duration": $this.data("fade-length"),
		"complete": function () { $content.hide() },
	});
}

/* Remove paragraphs in any object that has a class named "no-para" */
function removeParas()
{
	var affectedEs = document.getElementsByClassName("no-para"); // E for Element

	var Ps = null;
	var parent = null;
	var dummyNode = null;
	for (i = 0; i < affectedEs.length; i++)
	{
		Ps = affectedEs[i].getElementsByTagName("p");
		do
		{
			parent = Ps[0].parentNode;
			dummyNode = document.createElement("span");
			dummyNode.innerHTML = Ps[0].innerHTML;
			parent.replaceChild(dummyNode, Ps[0]);
		} while (Ps.length != 0);
	}
}
jQuery(removeParas);

/* Fixes the extra whitespace at the end (if there is one) */
function divPreFix()
{
	var Es = document.getElementsByClassName("pre"); // E for Element
	for (i = 0; i < Es.length; i++)
		if (Es[i].tagName == "DIV") // Make sure it is a div tag
			if (Es[i].lastChild.textContent == "\n") // Check for the whitespace
				Es[i].removeChild(Es[i].lastChild);
}
jQuery(divPreFix);

// Searches a set of CSS classes for links which have css class "new" and
// changes them into the upload image.
var convertRedImageLinksToNotFoundImage = function($) {
    return function() {
        // Div classes in which we search for image links
        var convertibleDivClasses = [
            'imagetable', 'image'
        ];
        $.each(convertibleDivClasses, function(_, cssClass) {
            var $links = $('.' + cssClass + ' a.new[href*="Special:Upload"]');
            $links.html('<img src="//wiki.mabinogiworld.com/images/f/f0/No_File.png" />');
        });
    }
}(jQuery);
jQuery(convertRedImageLinksToNotFoundImage);


jQuery.fn.reverse = Array.prototype.reverse;
// Scroll to hidden sections on the wiki
function doScrollPage() {
	if (location.hash && location.hash.length > 1) {
		var $x = $(location.hash + ', a[name="' + location.hash.substr(1) + '"]');
		if (!$x.is(":visible")) {
			var parents = $x.parents(".NavContent");
			if (parents.length) {
				// Spoiler tag.
				parents.reverse().each(function () {
					var $this = $(this);
					if (!$this.is(":visible")) {
						toggleNavigationBar(parseInt($this.parent().children(".NavHead").children(".NavToggle").attr("id").substr(9)));
					}
				});
			} else if ((parents = $x.parents(".tabdiv")).length) {
				// Tabs.
				$x.parents('div[id*="tab"]').each(function () {
					var $this = $(this);
					$this.parent(".tabdiv").children("ul").children("li:nth-child(" + $(this).attr("id").replace(/^.*tab/,'') + ")").click() 
				});
			}
		}
		$("html,body").scrollTop($x.offset().top)
	}
}
jQuery(doScrollPage);

var onloadHash = location.hash;
jQuery.getScript('//mabi.world/jquery.ba-hashchange.js', function () {
	jQuery(window).hashchange(doScrollPage);
	if (onloadHash != location.hash) doScrollPage();
});

// don't load the calc system unless it will actually do something
if ($(".calc-scope").length > 0) {
    importScript('MediaWiki:CalcSystem.js');
}

var weatherWidget = $(".weather-widget-rain-summary, .weather-widget-hour, .weather-widget").length > 0;
var timerWidget = $(".make-timer, .time-erinn-current, .time-server-current").length > 0;

if (weatherWidget || timerWidget) {
    jQuery.getScript('//mabi.world/moment.js', function () {
        jQuery.getScript('//mabi.world/moment-timezone-with-data.js', function () {
            jQuery.getScript('//mabi.world/widgets.js', function () {
                if (weatherWidget) {
                    jQuery.getScript('https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.3/jquery-ui.min.js', function () {
                        jQuery.getScript('//mabi.world/forecast.js');
                        importStylesheet('MediaWiki:Forecast.css');
                    });
                }
                if (timerWidget) {
                    jQuery.getScript('//mabi.world/timers.js');
                    importStylesheet('MediaWiki:Timers.css');
                }
            })
        })
    });
}

jQuery(function () {
    importScript('MediaWiki:Toolbar.js');
});

jQuery(function ($) {
    switch ($("#LoadFormScript").text()) {
    case "Enchant": importScript("MediaWiki:EnchantForm.js"); break;
    case "Title": importScript("MediaWiki:TitleForm.js"); break;
    }
});