Guest User

FFItemTooltip.js, rev. 63161

a guest
May 22nd, 2020
57
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. $(function() {
  2.     // This element is placed at the bottom of the page. It serves as a tooltip for showing article info on hover.
  3.     var tooltip = $("<div id=\"item-tooltip\"></div>");
  4.    
  5.     // Cache for already-checked items, to save resources.
  6.     var cache = {};
  7.     var failed = {};
  8.     var cachePages = {};
  9.     // To properly load the tooltip when the user changes focus quickly.
  10.     var hovered_article = null;
  11.     // For positioning the tooltip.
  12.     var lastX = 0, lastY = 0;
  13.    
  14.     function updatePosition() {
  15.         tooltip.css({
  16.            "left": Math.min(wind.width() - tooltip.width() - 35, lastX + 10),
  17.            "top":  Math.min(wind.height() - tooltip.height() - 35, lastY + 50)
  18.         });
  19.     }
  20.    
  21.     // Generates a section of key-value pairs to the tooltip.
  22.     function generateSection(sec, items) {
  23.         for (var i = 0; i < items.length; i++) {
  24.             var item = $("<div class=\"it-infoitem\"><span class=\"it-infoitem-key\"></span><span class=\"it-infoitem-val\"></span></div>");
  25.             var current = $(items[i]);
  26.             item.find(".it-infoitem-key").text(current.find(".pi-data-label").text());
  27.             item.find(".it-infoitem-val").html(current.find(".pi-data-value").html()); // To allow for listing.
  28.             sec.append(item);
  29.         }
  30.     }
  31.    
  32.     function splitByMany(str, sep) {
  33.         var result = [];
  34.         var buffer = "";
  35.         for (var i = 0; i < str.length; i++) {
  36.             if (sep.indexOf(str.substr(i, 1)) > -1) {
  37.                 if (buffer.length > 0)
  38.                     result.push(buffer);
  39.                 buffer = "";
  40.             }
  41.             buffer += str.substr(i, 1);
  42.         }
  43.         if (buffer.length > 0)
  44.             result.push(buffer);
  45.         return result;
  46.     }
  47.    
  48.     // Generates a section of key-value pairs to the tooltip from our own syntax.
  49.     function generateDataSection(str) {
  50.         var sec = $("<div class=\"it-infobox\"></div>");
  51.         var item;
  52.        
  53.         var lines = splitByMany(str, ["!", "~"]);
  54.         for (var i = 0; i < lines.length; i++) {
  55.             if (lines[i].indexOf("!") === 0) {
  56.                 if (item !== undefined)
  57.                     sec.append(item);
  58.                 item = $("<div class=\"it-infoitem\"><span class=\"it-infoitem-key\"></span><span class=\"it-infoitem-val\"></span></div>");
  59.                 item.find(".it-infoitem-key").text(lines[i].substr(1).trim());
  60.             } else if (item !== undefined)
  61.                 item.find(".it-infoitem-val").append($("<p></p>").text(lines[i].substr(1).trim()));
  62.         }
  63.         if (item !== undefined)
  64.             sec.append(item);
  65.        
  66.         return sec;
  67.     }
  68.    
  69.     function attrIsSet(val, defValue) {
  70.         return val !== null && val !== undefined && val.length > 0 && val != defValue;
  71.     }
  72.    
  73.     // Updates the DOM for our tooltip element using the found data.
  74.     function setTooltip(data) {
  75.         tooltip.html("<div class=\"it-header\"><img/><div class=\"it-title\">-</div></div>");
  76.         if (data.hasClass("tooltip-data")) {
  77.             tooltip.find(".it-title").text(data.attr("data-title"));
  78.             tooltip.find(".it-header img").attr("src",
  79.                 (data.find("img").attr("data-src") !== undefined && data.find("img").attr("data-src").length > 0) ? data.find("img").attr("data-src") : data.find("img").attr("src"));
  80.             if (attrIsSet(tooltip.attr("data-desc"), "{{{Description}}}"))
  81.                 tooltip.append($("<div class=\"it-infobox it-desc\"></div>").text(tooltip.attr("data-desc")));
  82.             for (var i = 1; i <= 5; i++) {
  83.                 if (attrIsSet(data.attr("data-sectiontitle" + i), "{{{Section title " + i + "}}}")) {
  84.                     tooltip.append($("<div class=\"it-infobox-title\"></div>").text(data.attr("data-sectiontitle" + i)));
  85.                     tooltip.append(generateDataSection(data.attr("data-sectionlist" + i)));
  86.                 }
  87.             }
  88.         } else {
  89.             tooltip.find(".it-title").text(data.find(".pi-title").text());
  90.             tooltip.find(".it-header img").attr("src", data.find(".pi-image img").attr("src"));
  91.             if (data.find(".pi-image .pi-caption").length > 0)
  92.                 tooltip.append($("<div class=\"it-infobox it-desc\"></div>").text(data.find(".pi-image .pi-caption").text()));
  93.             var dsec = data.find("section, >.pi-data");
  94.             for (var i = 0; i < dsec.length; i++) {
  95.                 var csec = $(dsec[i]);
  96.                 var sec = $("<div class=\"it-infobox\"></div>");
  97.                 if (csec.is("section")) {
  98.                     var ibTitle = csec.find(".pi-header"); // Collapsible sections can have titles.
  99.                     if (ibTitle.length > 0)
  100.                         tooltip.append($("<div class=\"it-infobox-title\"></div>").text(ibTitle.text()));
  101.                     generateSection(sec, csec.find(".pi-data"));
  102.                 } else
  103.                     generateSection(sec, csec);
  104.                 tooltip.append(sec);
  105.             }
  106.         }
  107.         tooltip.show();
  108.         tooltip.find(".it-infobox").each(function() {
  109.             if (this.offsetHeight < this.scrollHeight)
  110.                 sec.addClass("overflow"); // Applies some overflow-look through pseudoclasses.
  111.         });
  112.         updatePosition();
  113.     }
  114.    
  115.     // Measurement to avoid mess-up for our jQuery selector statement, as it's influenced by user input.
  116.     function escapeHtml(unsafe) {
  117.         return decodeURIComponent(unsafe
  118.             .replace(/"/g, "&quot;")
  119.             .replace(/%~/g, "-")
  120.             .replace(/_/g, " ")
  121.             .replace(/\\/g, ""));
  122.     }
  123.    
  124.     // Checks if we have cached data on the article, and loads/sets accordingly.
  125.     function updateTooltip(article) {
  126.         tooltip.hide();
  127.         hovered_article = article;
  128.         if (article in cache) {
  129.             if (cache[article] !== false) {
  130.                 setTooltip(cache[article]); // The article data was cached, load it.
  131.             }
  132.         } else { // The article wasn't found in cache, pull it.
  133.             tooltip.html("<div class=\"it-title\">Loading...</div>");
  134.             tooltip.show();
  135.             updatePosition();
  136.            
  137.             var handleDom = function(domString) {
  138.                 var dom = $(domString);
  139.                 var queryParts = article.split("#");
  140.                
  141.                 // We're showing information from the first infobox in the tooltip.
  142.                 var infobox = $(dom.find(".portable-infobox"));
  143.                 if (dom.find(".tooltip-data").length > 0)
  144.                     infobox = dom.find(".tooltip-data");
  145.                
  146.                 if (queryParts.length > 1) { // URL has anchor, look for the right infobox.
  147.                     var currentTabber = $(dom.find("#WikiaArticle>div"));
  148.                     var anchorParts = queryParts[1].split("-");
  149.                     for (var i = 0; i < anchorParts.length; i++) {
  150.                         var newTabber = $(currentTabber.find(">.tabber>.tabbertab[title='" + escapeHtml(anchorParts[i]) + "']"));
  151.                         if (newTabber.length > 0)
  152.                             currentTabber = newTabber;
  153.                         if (currentTabber.find(">.tooltip-data").length > 0) {
  154.                             infobox = currentTabber.find(">.tooltip-data");
  155.                             break;
  156.                         }
  157.                     }
  158.                     // If our nested tabbers contains any infobox, we'll use that over the first one one the page.
  159.                     if ($(currentTabber.find(".portable-infobox")).length > 0) {
  160.                         infobox = $(currentTabber.find(".portable-infobox"));
  161.                     }
  162.                     if (currentTabber.find(">.tooltip-data").length > 0) {
  163.                         infobox = currentTabber.find(">.tooltip-data");
  164.                     }
  165.                 }
  166.                
  167.                 if (infobox.length > 0) {
  168.                     infobox = $(infobox[0]);
  169.                    
  170.                     // Handle infobox tabs.
  171.                     if (queryParts.length > 1 && infobox.find(".pi-tab-link").length > 1) {
  172.                         var tabId = "pi-tab-0";
  173.                         var escapedAnchor = escapeHtml(queryParts[1]);
  174.                         infobox.find(".pi-tab-link").each(function() {
  175.                             if ($(this).text().trim() == escapedAnchor) {
  176.                                 tabId = $(this).attr("data-pi-tab");
  177.                             }
  178.                         });
  179.                         infobox.find(".pi-image-collection-tab-content").each(function() {
  180.                             if ($(this).attr("id") != tabId)
  181.                                 $(this).remove();
  182.                         });
  183.                         infobox.find(".pi-title").text(
  184.                             infobox.find(".pi-title").text() + " » " + escapedAnchor
  185.                         );
  186.                     }
  187.                    
  188.                     cache[article] = infobox;
  189.                     if (hovered_article == article)
  190.                         setTooltip(infobox);
  191.                 } else {
  192.                     // No infobox, so we'll mark this article as not having a tooltip.
  193.                     cache[article] = false;
  194.                 }
  195.             };
  196.            
  197.             // Cache page content for sets.
  198.             var articleName = article.split("#")[0];
  199.             if (articleName in cachePages)
  200.                 handleDom(cachePages[articleName]);
  201.             else
  202.                 $.get("https://fantastic-frontier-roblox.fandom.com/wiki/" + article, function(domString) {
  203.                     cachePages[articleName] = domString;
  204.                     handleDom(domString);
  205.                 }).fail(function() {
  206.                     // Article did not exist, so we'll mark this article as not having a tooltip.
  207.                     cache[article] = false;
  208.                 });
  209.         }
  210.     }
  211.    
  212.     // Assigns hover-logic for an element to display tooltips.
  213.     function setupElement(elem) {
  214.         var article = elem.is("div") ? elem.attr("data-article") : elem.attr("href").substr(6); // Trim away /wiki/.
  215.         elem.hover(function() {
  216.             updateTooltip(article);
  217.         }, function() {
  218.             tooltip.hide();
  219.             hovered_article = null;
  220.         });
  221.     }
  222.    
  223.     // Hook up tooltips to wiki links.
  224.     $("#WikiaArticle a[href^='/wiki/'], #WikiaArticle .tooltip-linker").each(function() {
  225.         setupElement($(this));
  226.     });
  227.    
  228.     // Initialize.
  229.     tooltip.hide();
  230.     $(document.body).append(tooltip);
  231.     var wind = $(window);
  232.    
  233.     // Follow the cursor.
  234.     $(document).on('mousemove', function(e){
  235.         lastX = e.clientX;
  236.         lastY = e.clientY;
  237.         updatePosition();
  238.     });
  239. });
Add Comment
Please, Sign In to add comment