NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name Shikimori Userpage lists tooltip
// @namespace http://shikimori.org/
// @version 1.7
// @description Show list in tooltip when mouseover links. Used tippy.js lib - https://atomiks.github.io/tippyjs/
// @author XENKing
// @license MIT
// @match https://shikimori.org/*
// @match http://shikimori.org/*
// @require https://code.jquery.com/jquery-latest.min.js
// @require https://unpkg.com/popper.js@1/dist/umd/popper.min.js
// @require https://unpkg.com/tippy.js@4
// @grant GM_addStyle
// @grant GM_getResourceText
// ==/UserScript==
// BUG: profile-head set state hover while tooltip hover
// base64 cat-loading pic
const INITIAL_CONTENT = '<img src="https://www.dropbox.com/s/7zf7nedbr0imw7q/tooltip_load.gif?raw=1" width=150px style="overflow: hidden !important; margin:5px 0;"></img>';
let fetch_counter = 1;
let item_size = null;
let showTooltip = false;
function appendStyle() {
let head = document.getElementsByTagName('head')[0];
let style = document.createElement('link');
style.href = "https://unpkg.com/tippy.js@4/themes/light-border.css"
style.type = 'text/css';
style.rel = 'stylesheet';
head.append(style);
}
function checkPath() {
if (/^\w+:\/{2}[\w.]+\/\w+$/.test(location.href)) {
showTooltip = true;
return true;
}
return false;
}
let resizeTooltip = function (div, tip) {
const {
popper
} = tip;
const {
tooltip,
content
} = tip.popperChildren;
tip.state.isFetching = false;
if (!tip.state.isVisible) {
return;
}
if (!tip._transitionEndListener) {
tip._transitionEndListener = event => {
if (event.target === event.currentTarget) {
content.style.opacity = '1';
tip.setContent(div);
}
};
}
tooltip.addEventListener('transitionend', tip._transitionEndListener);
if (!tip._baseHeight) {
tip._baseHeight = tooltip.clientHeight;
}
if (!tip._baseHeight) {
tip._baseWidth = tooltip.clientWidth;
}
//content.style.opacity = '0';
tip.setContent(div);
const height = tooltip.clientHeight;
popper.style.height = height + 'px';
tooltip.style.height = tip._baseHeight + 'px';
// Cause reflow so we can start the height transition.
void tooltip.offsetHeight;
void tooltip.offsetWidth;
// Start the transition.
tooltip.style.height = height + 'px';
if (height > 550) {
tooltip.style.maxHeight = "27em";
tooltip.style.overflowY = "auto";
}
// Remove the Loading... content and wait until the
// transition finishes.
};
let fetchAll = function (url, div, tip) {
let is_full = true;
let header = new Headers({
'Access-Control-Allow-Origin': '*',
'Content-Type': 'multipart/form-data',
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content,
'X-Requested-With': 'XMLHttpRequest',
});
let sentData = {
method: 'GET',
mode: 'cors',
header: header,
cache: 'default',
};
fetch(url + "/page/" + fetch_counter, sentData)
.then(response => response.text())
.then(html => {
let parser = new DOMParser();
// Parse the text
let doc = parser.parseFromString(html, "text/html");
if (item_size === null) {
item_size = doc.querySelector(".always-active.selected span").innerText;
// try to add searchbox
//$(doc).find('.b-collection_search input').clone(true).appendTo(div);
}
if (item_size > 400) {
is_full = false;
item_size -= 400;
fetch_counter++;
}
// debug
//console.log("item_size" + item_size);
//console.log("fetch_counter" + fetch_counter);
doc.querySelectorAll(".user_rate").forEach((el, i) => {
let tr = document.createElement("tr");
let td_name = document.createElement("td");
td_name.className = "name";
let link = el.querySelector(".entries .name a");
let index = el.querySelector(".index");
index.style.color = "#9da2a8";
index.style.paddingRight = "5px";
index.style.width = "20px";
index.style.textAlign = "center";
link.style.whiteSpace = "pre";
td_name.appendChild(link);
tr.appendChild(index);
tr.appendChild(td_name);
div.appendChild(tr);
});
}).catch(error => {
console.log("fetch error: " + error);
tip.state.isFetching = false;
return;
}).finally(() => {
if (is_full) {
resizeTooltip(div, tip);
return;
}
fetchAll(url, div, tip);
});
};
function createTip() {
if (!checkPath() || !showTooltip) {
return;
}
appendStyle();
tippy.group(tippy('.stat_name a', {
content: INITIAL_CONTENT,
interactive: true,
theme: 'light-border',
boundary: 'window',
maxWidth: '800px',
animation: 'fade',
duration: 100,
delay: 200,
followCursor: 'initial',
flip: true,
hideOnClick: 'toggle',
placement: "bottom-start",
flipBehavior: ["top", "bottom"],
onShow(tip) {
fetch_counter = 1;
item_size = null;
if (tip.state.isFetching === true || tip.state.canFetch === false) {
return;
}
tip.state.isFetching = true;
tip.state.canFetch = false;
let url = tip.reference.href;
let div = document.createElement("table");
div.style.textAlign = "left";
// fetch first, count size, split in 400, fetch all, show tooltip
fetchAll(url, div, tip);
},
onHidden(tip) {
tip.state.canFetch = true;
tip.setContent(INITIAL_CONTENT);
const {
tooltip
} = tip.popperChildren;
tooltip.style.height = null;
tooltip.removeEventListener('transitionend', tip._transitionEndListener);
tip._transitionEndListener = null;
}
}));
}
// Using ImoutoChan loading function
function ready(fn) {
document.addEventListener('page:load', fn);
document.addEventListener('turbolinks:load', fn);
if (document.attachEvent ? document.readyState === "complete" : document.readyState !== "loading") {
fn();
}
else {
document.addEventListener('DOMContentLoaded', fn);
}
}
ready(createTip);