Mark owned ScummVM/ResidualVM Games

A simple aid for collecting ScummVM and ResidualVM-supported games

  1. // ==UserScript==
  2. // @name Mark owned ScummVM/ResidualVM Games
  3. // @namespace ssokolow.com
  4. // @description A simple aid for collecting ScummVM and ResidualVM-supported games
  5. // @license MIT
  6. // @version 6
  7. //
  8. // @require https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js
  9. //
  10. // @match *://scummvm.org/compatibility
  11. // @match *://scummvm.org/compatibility/*
  12. // @match *://residualvm.org/compatibility
  13. // @match *://residualvm.org/compatibility/*
  14. // @match *://www.scummvm.org/compatibility
  15. // @match *://www.scummvm.org/compatibility/*
  16. // @match *://www.residualvm.org/compatibility
  17. // @match *://www.residualvm.org/compatibility/*
  18. //
  19. // @grant GM_setValue
  20. // @grant GM.setValue
  21. // @grant GM_getValue
  22. // @grant GM.getValue
  23. // @grant GM_deleteValue
  24. // @grant GM.deleteValue
  25. // @grant GM_listValues
  26. // @grant GM.listValues
  27. // ==/UserScript==
  28.  
  29. const OWNED_OPACITY = 0.3;
  30. var hide_owned;
  31. var owned_games;
  32.  
  33. /// Code shared between initial setup and the click handler
  34. var mark_owned = function(node, state) {
  35. let row = node.closest('tr');
  36. if (state) {
  37. row.style.opacity = OWNED_OPACITY;
  38. row.classList.add('owned');
  39. } else {
  40. row.style.opacity = 1.0;
  41. row.classList.remove('owned');
  42. }
  43. };
  44.  
  45. // TODO: Finish factoring out jQuery
  46. /// click() handler for the per-game toggle button
  47. var toggleOwnership = function(e) {
  48. e.preventDefault();
  49. let game_id = this.dataset.gameId;
  50.  
  51. // Toggle based on what's displayed so that it will always act as the
  52. // user expects, regardless of changes since last reload
  53. if (this.textContent == '+') {
  54. this.textContent = '-';
  55. mark_owned(this, true);
  56. GM.setValue(game_id, true);
  57. } else {
  58. this.textContent = '+';
  59. mark_owned(this, false);
  60. GM.deleteValue(game_id);
  61. }
  62. };
  63.  
  64. /// click() handler for the whole-table hide/show button
  65. var toggleVisible = function(e) {
  66. document.querySelectorAll('tr.owned').forEach(function(node) {
  67. node.style.display = hide_owned ? '' : 'none';
  68. });
  69. this.textContent = hide_owned ? '-' : '+';
  70. GM.setValue('__HIDE_OWNED', hide_owned = !hide_owned);
  71. };
  72.  
  73. /// Shared code to generate a toggle button
  74. var makeButton = function(initial_state, label) {
  75. let button = document.createElement("div");
  76. button.setAttribute('class', 'toggle_btn');
  77. button.setAttribute('title', label);
  78. button.textContent = initial_state ? '+' : '-'
  79. button.style.cssText = "" +
  80. "background: #c0c0c0; " +
  81. "border-radius: 3px; " +
  82. "color: black; " +
  83. "display: inline-block; " +
  84. "margin-right: 5px; " +
  85. "padding: 0 2px; " +
  86. "text-align: center; " +
  87. "width: 1em; " +
  88. "cursor: pointer";
  89. return button;
  90. };
  91.  
  92. (async function() {
  93. let state = await Promise.all([
  94. GM.getValue('__HIDE_OWNED', false),
  95. GM.listValues()
  96. ]);
  97. hide_owned = state[0];
  98. owned_games = state[1];
  99.  
  100. // Per-entry code
  101. document.querySelectorAll('table.chart a').forEach(function(node) {
  102. console.log(node);
  103. // Extract the game ID for use in record-keeping
  104. let site_id = location.hostname.split('.');
  105. site_id = site_id[site_id.length - 2]; // "scummvm" or "residualvm"
  106. let url = node.getAttribute('href').split('/');
  107. let game_id = url[url.length-1] ? url[url.length-1] : url[url.length-2];
  108. game_id = site_id + "_" + game_id;
  109.  
  110. // Craft a button to toggle ownership status
  111. let togglebutton = makeButton(owned_games.indexOf(game_id) == -1,
  112. "Toggle Owned")
  113. togglebutton.addEventListener("click", toggleOwnership);
  114. togglebutton.dataset.gameId = game_id;
  115. node.closest('td').prepend(togglebutton);
  116.  
  117. // TODO: Profile alternatives like an x|y|z regexp or a popping iteration
  118. if (owned_games.indexOf(game_id) !== -1){ mark_owned(node, true); }
  119. });
  120.  
  121. // Global toggle-button code
  122. let g_button = makeButton(hide_owned, "Show/Hide Owned Games")
  123. g_button.id = 'gm_visible_toggle';
  124. g_button.style.position = 'relative';
  125. g_button.style.marginRight = '-100%';
  126. g_button.style.top = '14px';
  127. g_button.style.left = '0';
  128. g_button.addEventListener("click", toggleVisible);
  129. let container = document.querySelector("#content .content");
  130. if (!container) {
  131. container = document.querySelector("section.intro ~ section.content");
  132. }
  133. container.prepend(g_button);
  134.  
  135.  
  136. if (hide_owned) {
  137. document.querySelectorAll('tr.owned').forEach(function(node) {
  138. node.style.display = 'none';
  139. });
  140. }
  141.  
  142. // Hover-style the buttons and add a better print stylesheet to
  143. // make "thrifting TODO" printouts easier
  144. let style_elem = document.createElement("style");
  145. style_elem.textContent = "td > .toggle_btn { visibility: hidden; }\n\n" +
  146. "td:hover > .toggle_btn { visibility: visible; }\n\n" +
  147. "@media print { " +
  148. "section.box section.content, #content, .rbwrapper > .box > .content { " +
  149. "position: absolute !important; " +
  150. "top: 0 !important; " +
  151. "left: 0 !important; " +
  152. "right: 0 !important; " +
  153. "z-index: 9999 !important; " +
  154. "margin: 0 !important; " +
  155. "padding: 0 !important; " +
  156. "background: white !important; " +
  157. "} " +
  158. "table.chart, #container { width: 100% !important; } " +
  159. "#header, #menu, #footer, .intro, .cookie-consent, .toggle_btn { " +
  160. "display: none !important; " +
  161. "} " +
  162. "html, body, #container { background: white !important; } " +
  163. "}";
  164. document.head.appendChild(style_elem);
  165. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址