bgmcard

not a card game

// ==UserScript==
// @name        bgmcard
// @namespace   bgm/uli
// @description not a card game
// @include     http://bgm.tv/*/topic/*
// @include     http://bangumi.tv/*/topic/*
// @include     http://chii.in/*/topic/*
// @version     0.1.4
// @grant       none
// ==/UserScript==


// card css
var card_css = document.createElement("style");
card_css.textContent = [
		".card_container {position: absolute; transition: left 0.5s, right 0.5s, opacity 0.5s; width: 30em; margin: 1em 0 0 1em; padding: 0 1em; border-radius: 8px; z-index: 50; box-shadow: 2px 2px 5px #999; background-color: rgba(255,255,255,0.9); font-size: 13px; color: #444; border-left: 1em solid #F09199;}",
		".card_container_inner {overflow: hidden; margin: 0 -1em; padding: 1em; border-radius: 8px; border-right: 1em solid rgba(255,255,255,0.9);}",
		".card_content {white-space: pre-wrap; transition: all 0.5s ease; margin-left: 0; width: 30em; max-height: 20em; -moz-columns: auto 30em; -webkit-columns: auto 30em;}",
		".card_cover {float: right; border-color: #C7C7C9 #A9A9AB #858486; border-width: 0 1px 1px 0; border-style: solid; max-width: 10em; max-height: 20em; margin: 0 0 0.5em 0.5em;}",
		".card_link {color: #0084B4 !important;}",
		".card_page {padding-right: 1em; border-top: 1px solid #AAA; display: block; transition: width 0.5s; color: transparent; line-height: 0;}",
		".card_charging {color: #369CF8; font-size: 15px; font-style: italic; font-family: Georgia; padding: 1em 0;}",
		""
		].join("\n");

document.body.appendChild(card_css);


var topmost_card = function(ele) {
	var all_container = document.querySelectorAll(".card_container");
	//for (let x of document.querySelectorAll(".card_container")) {
	for (var i = 0; i < all_container.length; i++) {
		all_container[i].style.zIndex = "49";
		all_container[i].style.opacity = "0.8";
	}
	ele.style.zIndex = "50";
	ele.style.opacity = "1";
};

var set_coordinate = function(ele, rect) {
	ele.style.left = window.scrollX + rect.right + "px";
	ele.style.top = window.scrollY + rect.top + "px";
};


// set card --have no card--> refine card -> charge card -> shooting
//          --already had--> release card -> shooting

var refine_card = function(doc, uri) {

	var get_element = function(selectors) {
		var ele = doc.querySelector(selectors);
		if (ele) return ele;
		else {
			var blank_ele = document.createElement("div");
			blank_ele.href = ""; //some have no cover image, will return null
			return blank_ele;
		}
	};

	var title = get_element(".nameSingle").textContent;
	var cover_src = get_element(".cover.thickbox").href;
	var info = get_element("#infobox").textContent;
	var sum_txt = get_element("#subject_summary, .detail").textContent;

	var text_trim_join = function(str) {
		var trim = function(x) {return x.trim()};
		return str.split('\n').filter(trim).map(trim).join('\n');
	};

	var card_txt = ['', text_trim_join(info), sum_txt].join('\n\n');

	var title_link = document.createElement("a");
	title_link.className = "card_link";
	title_link.textContent = text_trim_join(title);
	title_link.href = uri;

	var cover = document.createElement("img");
	cover.className = "card_cover";
	cover.src = cover_src;

	var card = document.createElement("p");
	card.className = "card_content";
	//card.textContent = card_txt;

	var card_page = document.createElement("span");
	card_page.className = "card_page";

	var container_inner = document.createElement("div");
	container_inner.className = "card_container_inner";

	//card.insertBefore(title_link, card.firstChild);
	//card.insertBefore(cover, card.firstChild);
	card.appendChild(cover);
	card.appendChild(title_link);
	card.appendChild(document.createTextNode(card_txt));

	container_inner.appendChild(card);
	container_inner.appendChild(card_page);

	return [container_inner, card, card_page];
};

var charge_card = function(uri, type, id_number) {
	var card_number = type.slice(0, 3) + "#" + id_number;

	var card_charging = document.createElement("div");
	card_charging.className = "card_charging";
	card_charging.innerHTML = "Card <u>" + card_number + "</u> Charging...";

	var container = document.createElement("div");
	container.className = "card_container";
	container.id = uri;

	container.appendChild(card_charging);

	return [container, card_charging];
};

var release_card = function(evt, uri, page_total) {
	evt.preventDefault();

	var container = document.getElementById(uri);
	var tg_c = container.querySelector(".card_content");
	var tg_p = container.querySelector(".card_page");

	tg_c.style.marginLeft = "0";
	tg_p.textContent = "1/" + page_total;
	tg_p.style.width = 1/page_total*100 + "%";

	container.style.display = "block";
	var rect = evt.target.getBoundingClientRect();
	set_coordinate(container, rect);
	topmost_card(container);
};


var set_card = function(e, uri) {
	var ar = uri.split('/');
	var type = ar[ar.length-2];
	var id_number = ar[ar.length-1];

	var set_card_exec = function(evt) {
		evt.preventDefault();

		//var [container, card_charging] = charge_card(uri, type, id_number);
		var temp = charge_card(uri, type, id_number);
		var container = temp[0], card_charging = temp[1];

		var rect = evt.target.getBoundingClientRect();
		set_coordinate(container, rect);

		document.body.firstElementChild.appendChild(container);
		// use body.appendChild will cover up some parts
		topmost_card(container);

		var xhr = new XMLHttpRequest();
		xhr.onload = function() {
			var doc = this.responseXML;

			//var [container_inner, card, card_page] = refine_card(doc, uri, type);
			var temp2 = refine_card(doc, uri, type);
			var container_inner = temp2[0], card = temp2[1], card_page = temp2[2];
			container.replaceChild(container_inner, container.firstChild);

			if (container_inner.scrollHeight > container_inner.clientHeight) {
				card.style.height = "20em";
			}

			//XXX if cover image is not loaded as soon as the card is appended
			//card.scrollWidth will be smaller than when the image is showed
			//need some placeholder or other fix
			var page_total = Math.floor(card.scrollWidth / card.clientWidth);
			card_page.counter = 0;
			card_page.textContent = "1/" + page_total;
			card_page.style.width = 1/page_total*100 + "%";

			container.addEventListener("click", function(ev) {
				var tg = ev.target;
				if (tg.className == "card_link") return;

				if (tg.className != "card_container") {
					if (ev.currentTarget.style.zIndex == "49") {
						topmost_card(ev.currentTarget);
						return;
					}

					var tg_c = ev.currentTarget.querySelector(".card_content");
					page_total = Math.floor(tg_c.scrollWidth / tg_c.clientWidth);

					if (page_total == 1) return;

					if (tg_c.style.marginLeft == '') tg_c.style.marginLeft = "0";

					//XXX select text is also "click"
					var current_margin = parseInt(tg_c.style.marginLeft);
					var counter = card_page.counter;	
					// below is for page turning calc
					if (Math.floor(counter/(page_total-1)) % 2 == 0) {
						tg_c.style.marginLeft = current_margin - 31 + "em";
					} else {
						tg_c.style.marginLeft = current_margin + 31 + "em";
					}
					card_page.counter = card_page.counter + 1;
					if (Math.floor(card_page.counter/(page_total-1)) % 2 == 0)
						var pg_2 = card_page.counter%(page_total-1) + 1;
					else
						var pg_2 = page_total - card_page.counter%(page_total-1);
					card_page.style.width = pg_2/page_total*100 + "%";
					card_page.textContent = pg_2 + "/" + page_total;
				} else {
					// hide card
					ev.currentTarget.style.display = "none";
				}
			});

			// when click link second time, release card directly
			e.removeEventListener("click", set_card_exec);
			var release_card_c = function(evt) {
				return release_card(evt, uri, page_total);
			};
			e.addEventListener("click", release_card_c);
		};

		xhr.timeout = 5000;
		xhr.ontimeout = function() {
			card_charging.textContent = "Shooting failed. Card charging too slow. Try again.";
			e.addEventListener("click", set_card_exec);
		};

		xhr.open("GET", uri);
		xhr.responseType = "document";
		xhr.send();
	};


	e.addEventListener("click", set_card_exec);
}


var links = document.getElementsByTagName("a");
//for (let t of links) {
for (var i = 0; i < links.length; i++) {
	if (/\/(subject|character|person)\/\d+$/.test(links[i].href)) {
		if (links[i].href != document.location.href) set_card(links[i], links[i].href);
	}
}