bgmcard

not a card game

  1. // ==UserScript==
  2. // @name bgmcard
  3. // @namespace bgm/uli
  4. // @description not a card game
  5. // @include http://bgm.tv/*/topic/*
  6. // @include http://bangumi.tv/*/topic/*
  7. // @include http://chii.in/*/topic/*
  8. // @version 0.1.4
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12.  
  13. // card css
  14. var card_css = document.createElement("style");
  15. card_css.textContent = [
  16. ".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;}",
  17. ".card_container_inner {overflow: hidden; margin: 0 -1em; padding: 1em; border-radius: 8px; border-right: 1em solid rgba(255,255,255,0.9);}",
  18. ".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;}",
  19. ".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;}",
  20. ".card_link {color: #0084B4 !important;}",
  21. ".card_page {padding-right: 1em; border-top: 1px solid #AAA; display: block; transition: width 0.5s; color: transparent; line-height: 0;}",
  22. ".card_charging {color: #369CF8; font-size: 15px; font-style: italic; font-family: Georgia; padding: 1em 0;}",
  23. ""
  24. ].join("\n");
  25.  
  26. document.body.appendChild(card_css);
  27.  
  28.  
  29. var topmost_card = function(ele) {
  30. var all_container = document.querySelectorAll(".card_container");
  31. //for (let x of document.querySelectorAll(".card_container")) {
  32. for (var i = 0; i < all_container.length; i++) {
  33. all_container[i].style.zIndex = "49";
  34. all_container[i].style.opacity = "0.8";
  35. }
  36. ele.style.zIndex = "50";
  37. ele.style.opacity = "1";
  38. };
  39.  
  40. var set_coordinate = function(ele, rect) {
  41. ele.style.left = window.scrollX + rect.right + "px";
  42. ele.style.top = window.scrollY + rect.top + "px";
  43. };
  44.  
  45.  
  46. // set card --have no card--> refine card -> charge card -> shooting
  47. // --already had--> release card -> shooting
  48.  
  49. var refine_card = function(doc, uri) {
  50.  
  51. var get_element = function(selectors) {
  52. var ele = doc.querySelector(selectors);
  53. if (ele) return ele;
  54. else {
  55. var blank_ele = document.createElement("div");
  56. blank_ele.href = ""; //some have no cover image, will return null
  57. return blank_ele;
  58. }
  59. };
  60.  
  61. var title = get_element(".nameSingle").textContent;
  62. var cover_src = get_element(".cover.thickbox").href;
  63. var info = get_element("#infobox").textContent;
  64. var sum_txt = get_element("#subject_summary, .detail").textContent;
  65.  
  66. var text_trim_join = function(str) {
  67. var trim = function(x) {return x.trim()};
  68. return str.split('\n').filter(trim).map(trim).join('\n');
  69. };
  70.  
  71. var card_txt = ['', text_trim_join(info), sum_txt].join('\n\n');
  72.  
  73. var title_link = document.createElement("a");
  74. title_link.className = "card_link";
  75. title_link.textContent = text_trim_join(title);
  76. title_link.href = uri;
  77.  
  78. var cover = document.createElement("img");
  79. cover.className = "card_cover";
  80. cover.src = cover_src;
  81.  
  82. var card = document.createElement("p");
  83. card.className = "card_content";
  84. //card.textContent = card_txt;
  85.  
  86. var card_page = document.createElement("span");
  87. card_page.className = "card_page";
  88.  
  89. var container_inner = document.createElement("div");
  90. container_inner.className = "card_container_inner";
  91.  
  92. //card.insertBefore(title_link, card.firstChild);
  93. //card.insertBefore(cover, card.firstChild);
  94. card.appendChild(cover);
  95. card.appendChild(title_link);
  96. card.appendChild(document.createTextNode(card_txt));
  97.  
  98. container_inner.appendChild(card);
  99. container_inner.appendChild(card_page);
  100.  
  101. return [container_inner, card, card_page];
  102. };
  103.  
  104. var charge_card = function(uri, type, id_number) {
  105. var card_number = type.slice(0, 3) + "#" + id_number;
  106.  
  107. var card_charging = document.createElement("div");
  108. card_charging.className = "card_charging";
  109. card_charging.innerHTML = "Card <u>" + card_number + "</u> Charging...";
  110.  
  111. var container = document.createElement("div");
  112. container.className = "card_container";
  113. container.id = uri;
  114.  
  115. container.appendChild(card_charging);
  116.  
  117. return [container, card_charging];
  118. };
  119.  
  120. var release_card = function(evt, uri, page_total) {
  121. evt.preventDefault();
  122.  
  123. var container = document.getElementById(uri);
  124. var tg_c = container.querySelector(".card_content");
  125. var tg_p = container.querySelector(".card_page");
  126.  
  127. tg_c.style.marginLeft = "0";
  128. tg_p.textContent = "1/" + page_total;
  129. tg_p.style.width = 1/page_total*100 + "%";
  130.  
  131. container.style.display = "block";
  132. var rect = evt.target.getBoundingClientRect();
  133. set_coordinate(container, rect);
  134. topmost_card(container);
  135. };
  136.  
  137.  
  138. var set_card = function(e, uri) {
  139. var ar = uri.split('/');
  140. var type = ar[ar.length-2];
  141. var id_number = ar[ar.length-1];
  142.  
  143. var set_card_exec = function(evt) {
  144. evt.preventDefault();
  145.  
  146. //var [container, card_charging] = charge_card(uri, type, id_number);
  147. var temp = charge_card(uri, type, id_number);
  148. var container = temp[0], card_charging = temp[1];
  149.  
  150. var rect = evt.target.getBoundingClientRect();
  151. set_coordinate(container, rect);
  152.  
  153. document.body.firstElementChild.appendChild(container);
  154. // use body.appendChild will cover up some parts
  155. topmost_card(container);
  156.  
  157. var xhr = new XMLHttpRequest();
  158. xhr.onload = function() {
  159. var doc = this.responseXML;
  160.  
  161. //var [container_inner, card, card_page] = refine_card(doc, uri, type);
  162. var temp2 = refine_card(doc, uri, type);
  163. var container_inner = temp2[0], card = temp2[1], card_page = temp2[2];
  164. container.replaceChild(container_inner, container.firstChild);
  165.  
  166. if (container_inner.scrollHeight > container_inner.clientHeight) {
  167. card.style.height = "20em";
  168. }
  169.  
  170. //XXX if cover image is not loaded as soon as the card is appended
  171. //card.scrollWidth will be smaller than when the image is showed
  172. //need some placeholder or other fix
  173. var page_total = Math.floor(card.scrollWidth / card.clientWidth);
  174. card_page.counter = 0;
  175. card_page.textContent = "1/" + page_total;
  176. card_page.style.width = 1/page_total*100 + "%";
  177.  
  178. container.addEventListener("click", function(ev) {
  179. var tg = ev.target;
  180. if (tg.className == "card_link") return;
  181.  
  182. if (tg.className != "card_container") {
  183. if (ev.currentTarget.style.zIndex == "49") {
  184. topmost_card(ev.currentTarget);
  185. return;
  186. }
  187.  
  188. var tg_c = ev.currentTarget.querySelector(".card_content");
  189. page_total = Math.floor(tg_c.scrollWidth / tg_c.clientWidth);
  190.  
  191. if (page_total == 1) return;
  192.  
  193. if (tg_c.style.marginLeft == '') tg_c.style.marginLeft = "0";
  194.  
  195. //XXX select text is also "click"
  196. var current_margin = parseInt(tg_c.style.marginLeft);
  197. var counter = card_page.counter;
  198. // below is for page turning calc
  199. if (Math.floor(counter/(page_total-1)) % 2 == 0) {
  200. tg_c.style.marginLeft = current_margin - 31 + "em";
  201. } else {
  202. tg_c.style.marginLeft = current_margin + 31 + "em";
  203. }
  204. card_page.counter = card_page.counter + 1;
  205. if (Math.floor(card_page.counter/(page_total-1)) % 2 == 0)
  206. var pg_2 = card_page.counter%(page_total-1) + 1;
  207. else
  208. var pg_2 = page_total - card_page.counter%(page_total-1);
  209. card_page.style.width = pg_2/page_total*100 + "%";
  210. card_page.textContent = pg_2 + "/" + page_total;
  211. } else {
  212. // hide card
  213. ev.currentTarget.style.display = "none";
  214. }
  215. });
  216.  
  217. // when click link second time, release card directly
  218. e.removeEventListener("click", set_card_exec);
  219. var release_card_c = function(evt) {
  220. return release_card(evt, uri, page_total);
  221. };
  222. e.addEventListener("click", release_card_c);
  223. };
  224.  
  225. xhr.timeout = 5000;
  226. xhr.ontimeout = function() {
  227. card_charging.textContent = "Shooting failed. Card charging too slow. Try again.";
  228. e.addEventListener("click", set_card_exec);
  229. };
  230.  
  231. xhr.open("GET", uri);
  232. xhr.responseType = "document";
  233. xhr.send();
  234. };
  235.  
  236.  
  237. e.addEventListener("click", set_card_exec);
  238. }
  239.  
  240.  
  241. var links = document.getElementsByTagName("a");
  242. //for (let t of links) {
  243. for (var i = 0; i < links.length; i++) {
  244. if (/\/(subject|character|person)\/\d+$/.test(links[i].href)) {
  245. if (links[i].href != document.location.href) set_card(links[i], links[i].href);
  246. }
  247. }