BGG Shortcuts

Keyboard shortcuts for the Geek

当前为 2016-02-21 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name BGG Shortcuts
  3. // @namespace BGG Shortcuts
  4. // @version 0.9.1
  5. // @description Keyboard shortcuts for the Geek
  6. // @include http://*.boardgamegeek.*/*
  7. // @include http://boardgamegeek.*/*
  8. // @include https://*.boardgamegeek.*/*
  9. // @include https://boardgamegeek.*/*
  10. // @copyright 2013+, JB McMichael
  11. // ==/UserScript==
  12.  
  13. /*
  14. * CHANGLOG::
  15. * ============================================
  16. * 0.9.1 - Fixed a stupid bug
  17. * 0.9.0 - Updated so that the shortcuts work on the new game page style
  18. * 0.8.1 - Updated to work on https
  19. * 0.8.0 - Forum links pop up in a modal so that you don't lose your place on a page
  20. * 0.7.0 - Changed the links to just be J for next item, H for home, and / for search, but disabled shortcuts in form elements
  21. * 0.6.1 - Give the page some time to load its scripts before changing links
  22. * 0.6.0 - Added a shortcut to go to the searchbox Ctrl + /
  23. * 0.5.0 - Added homepage links opening in new tab
  24. * 0.4.0 - If search returns one result just go to that result
  25. * 0.3.0 - Added homepage shortcut; Ctrl + Shift + H
  26. * 0.2.0 - Cleaned up the subscription jump link
  27. * 0.1.0 - First version, shortcut for subscriptions; Ctrl + M
  28. *
  29. */
  30.  
  31. (function () {
  32. "use strict";
  33. console.log('Loaded BGG Shortcuts');
  34. document.body.addEventListener('keydown', function(e) {
  35. var active = document.activeElement.tagName.toLowerCase(),
  36. badElements = ['input', 'textarea', 'select'];
  37.  
  38. // ignore shortcuts if we are in some form of input
  39. if (badElements.indexOf(active) === -1) {
  40. // Next subscription item J
  41. if (e.keyCode === 74) {
  42. if (!!document.querySelector('[href="/subscriptions/next"]')) {
  43. document.querySelectorAll('[href="/subscriptions/next"]').click();
  44. } else if (!!document.querySelectorAll("img:not(dn).nextsubcol")[0]) {
  45. [].slice.call(document.querySelectorAll("img:not(dn).nextsubcol")[0].parentNode.parentNode.click());
  46. }
  47. }
  48. // Home page H
  49. if (e.keyCode === 72 && window.location.href !== window.location.origin) {
  50. window.location.href = window.location.origin;
  51. }
  52. // Search box jump /
  53. if (e.keyCode === 191) {
  54. var searchbox = !!document.getElementById('sitesearch') ? document.getElementById('sitesearch') : document.querySelector('[ng-model="searchctrl.search.q"]');
  55. document.body.scrollTop = 0;
  56. searchbox.focus();
  57. window.setTimeout(function() { searchbox.value = ''; }, 10);
  58. }
  59. }
  60. }, false);
  61. //check for one result on the search page
  62. if (window.location.pathname === '/geeksearch.php' && window.location.search.search(/action=search/)) {
  63. var results = document.querySelectorAll('#collectionitems tbody tr');
  64. console.log('We are searching');
  65. if (results.length === 2) {
  66. console.log('Found just one result, redirect');
  67. var link = results[1].querySelectorAll('#results_objectname1 a'),
  68. href = link[0].getAttribute('href');
  69. window.location.href = window.location.origin + href;
  70. }
  71. }
  72. // set all homepage module links to open in new tab
  73. if (window.location.pathname === '/') {
  74. window.setTimeout(function(){
  75. console.log('Changing homepage links');
  76. var links = document.querySelectorAll('.innermoduletable tbody td a.ng-binding'),
  77. linkArray = [].slice.call(links);
  78. linkArray.forEach(function(item, index){
  79. item.setAttribute('target', '_blank');
  80. });
  81. },500);
  82. }
  83.  
  84. // popup forum links in a dialog
  85. if (window.location.pathname.split('/')[1] === 'boardgame') {
  86. // grab all forum link clicks
  87. document.addEventListener('click', forumClick, false);
  88. }
  89. function forumClick(e) {
  90. if (e.target.tagName === 'A' && e.target.href.split('/')[3] === 'thread') {
  91. e.preventDefault();
  92. // use the BGG API to get the thread
  93. var req = new XMLHttpRequest(),
  94. apiUrl = window.location.protocol + '//' + window.location.host + '/xmlapi2/thread?id=',
  95. diag = document.createElement('dialog'),
  96. content = document.createElement('div'),
  97. close = document.createElement('button'),
  98. thread = e.target.href.split('/')[4];
  99. diag.style.width = '80%';
  100. diag.style.height = '80%';
  101. diag.style.border = '2px solid rgba(0, 0, 0, 0.3)';
  102. diag.style.borderRadius = '6px';
  103. diag.style.boxShadow = '0 3px 7px rgba(0, 0, 0, 0.3)';
  104. content.style.overflowY = 'auto';
  105. content.style.height = '95%';
  106. content.style.margin = '5px 0px';
  107. close.innerText = 'Close';
  108. req.onreadystatechange = showContents;
  109. req.open('GET', apiUrl + thread, true);
  110. req.send();
  111. function showContents(e) {
  112. if (req.readyState === 4 && req.status === 200) {
  113. var subject = req.responseXML.documentElement.children[0].firstChild.nodeValue,
  114. articles = req.responseXML.documentElement.children[1].children;
  115. for (var i = 0; i < articles.length; i++) {
  116. var article = articles[i];
  117. var user = article.getAttribute('username');
  118. var title = article.children[0].firstChild.nodeValue;
  119. var body = article.children[1].firstChild.nodeValue;
  120. var postdate = article.getAttribute('postdate');
  121. var articleDiv = document.createElement('div');
  122. var dl = document.createElement('dl');
  123. var ddLeft = document.createElement('dd');
  124. var ddRight = document.createElement('dd');
  125. var userDiv = document.createElement('div');
  126. var bottomDl =document.createElement('dl');
  127. var ddLeft2 = document.createElement('dd');
  128. var ddCommands = document.createElement('dd');
  129. var ul = document.createElement('ul');
  130. var li = document.createElement('li');
  131. var ulInfo = document.createElement('ul');
  132. var liInfo = document.createElement('li');
  133. var postLink = document.createElement('a');
  134. var clearDiv = document.createElement('div');
  135. var rollsDiv = document.createElement('div');
  136. var userInfo = getUser(user);
  137. articleDiv.addClass('article');
  138. rollsDiv.addClass('rollsblock');
  139. ddLeft.addClass('left');
  140. ddRight.addClass('right');
  141. userDiv.addClass('username');
  142. userDiv.innerHTML = user;
  143. ddLeft.appendChild(userDiv);
  144. ddRight.innerHTML = body;
  145. dl.appendChild(ddLeft);
  146. dl.appendChild(ddRight);
  147. articleDiv.appendChild(dl);
  148. ddLeft2.addClass('left');
  149. ddCommands.addClass('commands');
  150. ul.appendChild(li);
  151. ddCommands.appendChild(ul);
  152. clearDiv.addClass('clear');
  153. ulInfo.addClass('information');
  154. postLink.innerHTML = postdate;
  155. liInfo.appendChild(postLink);
  156. ulInfo.appendChild(liInfo);
  157. ddCommands.appendChild(ulInfo);
  158. bottomDl.appendChild(ddLeft2);
  159. bottomDl.appendChild(ddCommands);
  160. articleDiv.appendChild(bottomDl);
  161. articleDiv.appendChild(clearDiv);
  162. articleDiv.appendChild(rollsDiv);
  163. content.appendChild(articleDiv);
  164. }
  165. diag.insertBefore(close, diag.childNodes[0]);
  166. diag.insertBefore(content, diag.childNodes[0]);
  167. close.addEventListener('click', function(e) { diag.close(); });
  168. document.body.insertBefore(diag,document.body.childNodes[0]);
  169. diag.showModal();
  170. }
  171. }
  172. }
  173. }
  174. function getUser(name) {
  175. var req = new XMLHttpRequest(),
  176. apiUrl = window.location.protocol + '//' + window.location.host + '/xmlapi2/user?name=' + name;
  177. req.onreadystatechange = function(e) {
  178. if (req.readyState === 4 && req.status === 200) {
  179. console.log(req.responseXML);
  180. }
  181. };
  182. req.open('GET', apiUrl, true);
  183. req.send();
  184. }
  185. }());