Difference between revisions of "MediaWiki:Common.js"
From Game Logs
m (fix loading indicator for Grimoire) |
(Better Grimoire support) |
||
(7 intermediate revisions by the same user not shown) | |||
Line 5: | Line 5: | ||
$(function() { | $(function() { | ||
+ | |||
// Activate only on 5ed pages. | // Activate only on 5ed pages. | ||
− | if ((wgCategories || []).indexOf("DnD 5") === -1) | + | // if ((wgCategories || []).indexOf("DnD 5") === -1) |
− | + | // return; | |
− | + | ||
+ | var instanceId = 0, | ||
+ | timeout = null; | ||
+ | |||
+ | // Convert readable spell name into a Grimoire link. | ||
+ | var grimTextToURL = function(text) { | ||
+ | var spell = text.trim().toLowerCase() | ||
+ | .replace(/[^\w\d\ \-]/g, '') | ||
+ | .replace(/\ +/g, '-'); | ||
+ | return spell ? ("//thebombzen.com/grimoire/spells/" + spell) : false | ||
+ | }; | ||
+ | |||
+ | // RTL alignment support depending on popup position. | ||
+ | var alignPopup = function(popup) { | ||
+ | var container = popup.parent(), | ||
+ | width = $(window).width(), | ||
+ | threshold = container.offset().left + popup.outerWidth(); | ||
+ | popup.toggleClass("rtl", threshold > width); | ||
+ | }; | ||
− | + | // Activation event | |
− | + | $(".dnd5-grimoire").off("mouseenter").on("mouseenter", function(e) { | |
+ | var currentId = this.getAttribute("data-instance-id"); | ||
− | + | if (!currentId) | |
− | + | return; | |
− | // | + | // Hide active popup at once if it's from another source. |
− | if ( | + | if (instanceId && instanceId != currentId) { |
− | + | var current = document.querySelector("[data-instance-id='" + instanceId + "']"); | |
− | + | $(current).find(".dnd5-grimoire-wrapper").hide(); | |
− | |||
} | } | ||
− | + | instanceId = currentId; | |
− | var | + | window.clearTimeout(timeout); |
− | . | + | timeout = null; |
− | . | + | |
+ | var link = $(e.currentTarget), | ||
+ | embed = link.find(".dnd5-grimoire-embed"), | ||
+ | wrapper = embed.closest(".dnd5-grimoire-wrapper"), | ||
+ | spellURL = grimTextToURL(link.text()); | ||
+ | |||
− | if (! | + | if (!spellURL.length) |
return; | return; | ||
− | + | // Instantiate on first occurence. | |
− | + | if (!wrapper.length) { | |
+ | wrapper = $("<div></div>") | ||
+ | .addClass("dnd5-grimoire-wrapper") | ||
+ | .appendTo(link); | ||
+ | |||
+ | embed = $("<div></div>").addClass("dnd5-grimoire-embed dnd5-grimoire-loader").appendTo(wrapper); | ||
+ | |||
+ | // Show the block first, better with loader. | ||
− | + | // no Promises, damn. | |
+ | $.ajax({ | ||
+ | "url": spellURL, | ||
+ | "type": "get", | ||
+ | "cache": true | ||
+ | }) | ||
+ | .then(function(data) { | ||
+ | var doc = $(data); | ||
+ | var article = doc.find("article"); | ||
+ | if (!article.length) | ||
+ | return console.log("Failed to find the DOM chunk with spell description"); | ||
+ | embed.removeClass("dnd5-grimoire-loader").append(article); | ||
+ | alignPopup(wrapper); | ||
+ | }) | ||
+ | .fail(function() { | ||
+ | embed.removeClass("loading").html("<p>Failed to look up this spell :(</p>"); | ||
+ | }); | ||
+ | } | ||
+ | |||
+ | if (!wrapper.is(":visible")) { | ||
+ | wrapper.show(); | ||
+ | alignPopup(wrapper); | ||
+ | } | ||
+ | }); | ||
− | + | // Deactivation event | |
− | + | $(".dnd5-grimoire").off("mouseleave").on("mouseleave", function(e) { | |
− | + | var link = $(e.currentTarget), | |
− | + | wrapper = link.find(".dnd5-grimoire-wrapper"), | |
− | + | leaveId = this.getAttribute("data-instance-id"); | |
− | + | if (leaveId == instanceId && !timeout) { | |
− | + | timeout = window.setTimeout(function() { | |
− | + | wrapper.hide(); | |
− | + | timeout = instanceId = 0; | |
− | + | }, 150); | |
− | + | } | |
− | |||
− | |||
− | |||
− | |||
− | } | ||
}); | }); | ||
− | + | ||
− | $(".dnd5-grimoire"). | + | // Swap captions for ext-anchors to the Grim URL. |
− | + | $(".dnd5-grimoire").each(function(idx) { | |
− | if ( | + | this.setAttribute("data-instance-id", ++idx); |
+ | var link = $(this); | ||
+ | // Insert an external link to the Grimoire page on first hover. | ||
+ | if (link.find("a").length) | ||
return; | return; | ||
− | + | link.html( | |
+ | $("<a></a>").text(link.text()) | ||
+ | .prop("href", "https:" + grimTextToURL(link.text())) | ||
+ | .prop("target", "_blank") | ||
+ | ); | ||
}); | }); | ||
}); | }); | ||
/* TEMPLATE:GRIMOIRE ENDS */ | /* TEMPLATE:GRIMOIRE ENDS */ | ||
+ | |||
+ | |||
+ | /* COLUMN-HOVER TABLE ACTUATOR STARTS */ | ||
+ | |||
+ | $(function() { | ||
+ | |||
+ | // Given a jQ pointer to a table cell, get a list of all cells at that pos. | ||
+ | // Note: ignores rows that have merged cells. | ||
+ | var getColumnCells = function(cell) { | ||
+ | var items = [], | ||
+ | targetPos = cell.index(); | ||
+ | if (parseInt(cell.prop("colspan") || 1, 10) != 1) | ||
+ | return items; | ||
+ | |||
+ | cell.closest("table").find("tr").each(function() { | ||
+ | // Make this work only on rows with no merged cells. | ||
+ | if (parseInt($(this).find("[colspan]").prop("colspan") || 1, 10) != 1) | ||
+ | return; | ||
+ | var row = $(this).find("td:eq(" + targetPos + "), th:eq(" + targetPos + ")"); // either | ||
+ | row.each(function() { | ||
+ | items.push($(this)); | ||
+ | }); | ||
+ | }); | ||
+ | |||
+ | return items; | ||
+ | }; | ||
+ | |||
+ | $("table.columns").on("mouseenter mouseleave", "td, th", function(e) { | ||
+ | var cell = $(e.target).closest("td, th"), | ||
+ | vertSiblings = getColumnCells(cell), | ||
+ | method = e.type == "mouseenter" ? "addClass" : "removeClass"; | ||
+ | |||
+ | vertSiblings.forEach(function(el) { $(el)[method]("hovered"); }); | ||
+ | }); | ||
+ | }); | ||
+ | |||
+ | /* COLUMN-HOVER TABLE ACTUATOR ENDS */ |
Latest revision as of 04:34, 6 January 2019
/* Any JavaScript here will be loaded for all users on every page load. */ /* TEMPLATE:GRIMOIRE STARTS */ $(function() { // Activate only on 5ed pages. // if ((wgCategories || []).indexOf("DnD 5") === -1) // return; var instanceId = 0, timeout = null; // Convert readable spell name into a Grimoire link. var grimTextToURL = function(text) { var spell = text.trim().toLowerCase() .replace(/[^\w\d\ \-]/g, '') .replace(/\ +/g, '-'); return spell ? ("//thebombzen.com/grimoire/spells/" + spell) : false }; // RTL alignment support depending on popup position. var alignPopup = function(popup) { var container = popup.parent(), width = $(window).width(), threshold = container.offset().left + popup.outerWidth(); popup.toggleClass("rtl", threshold > width); }; // Activation event $(".dnd5-grimoire").off("mouseenter").on("mouseenter", function(e) { var currentId = this.getAttribute("data-instance-id"); if (!currentId) return; // Hide active popup at once if it's from another source. if (instanceId && instanceId != currentId) { var current = document.querySelector("[data-instance-id='" + instanceId + "']"); $(current).find(".dnd5-grimoire-wrapper").hide(); } instanceId = currentId; window.clearTimeout(timeout); timeout = null; var link = $(e.currentTarget), embed = link.find(".dnd5-grimoire-embed"), wrapper = embed.closest(".dnd5-grimoire-wrapper"), spellURL = grimTextToURL(link.text()); if (!spellURL.length) return; // Instantiate on first occurence. if (!wrapper.length) { wrapper = $("<div></div>") .addClass("dnd5-grimoire-wrapper") .appendTo(link); embed = $("<div></div>").addClass("dnd5-grimoire-embed dnd5-grimoire-loader").appendTo(wrapper); // Show the block first, better with loader. // no Promises, damn. $.ajax({ "url": spellURL, "type": "get", "cache": true }) .then(function(data) { var doc = $(data); var article = doc.find("article"); if (!article.length) return console.log("Failed to find the DOM chunk with spell description"); embed.removeClass("dnd5-grimoire-loader").append(article); alignPopup(wrapper); }) .fail(function() { embed.removeClass("loading").html("<p>Failed to look up this spell :(</p>"); }); } if (!wrapper.is(":visible")) { wrapper.show(); alignPopup(wrapper); } }); // Deactivation event $(".dnd5-grimoire").off("mouseleave").on("mouseleave", function(e) { var link = $(e.currentTarget), wrapper = link.find(".dnd5-grimoire-wrapper"), leaveId = this.getAttribute("data-instance-id"); if (leaveId == instanceId && !timeout) { timeout = window.setTimeout(function() { wrapper.hide(); timeout = instanceId = 0; }, 150); } }); // Swap captions for ext-anchors to the Grim URL. $(".dnd5-grimoire").each(function(idx) { this.setAttribute("data-instance-id", ++idx); var link = $(this); // Insert an external link to the Grimoire page on first hover. if (link.find("a").length) return; link.html( $("<a></a>").text(link.text()) .prop("href", "https:" + grimTextToURL(link.text())) .prop("target", "_blank") ); }); }); /* TEMPLATE:GRIMOIRE ENDS */ /* COLUMN-HOVER TABLE ACTUATOR STARTS */ $(function() { // Given a jQ pointer to a table cell, get a list of all cells at that pos. // Note: ignores rows that have merged cells. var getColumnCells = function(cell) { var items = [], targetPos = cell.index(); if (parseInt(cell.prop("colspan") || 1, 10) != 1) return items; cell.closest("table").find("tr").each(function() { // Make this work only on rows with no merged cells. if (parseInt($(this).find("[colspan]").prop("colspan") || 1, 10) != 1) return; var row = $(this).find("td:eq(" + targetPos + "), th:eq(" + targetPos + ")"); // either row.each(function() { items.push($(this)); }); }); return items; }; $("table.columns").on("mouseenter mouseleave", "td, th", function(e) { var cell = $(e.target).closest("td, th"), vertSiblings = getColumnCells(cell), method = e.type == "mouseenter" ? "addClass" : "removeClass"; vertSiblings.forEach(function(el) { $(el)[method]("hovered"); }); }); }); /* COLUMN-HOVER TABLE ACTUATOR ENDS */