InoReader Scroll Marker

Display the marker of page scroll in InoReader. / InoReaderでページスクロールしたときにマーカーを表示します。

目前為 2014-10-13 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name InoReader Scroll Marker
  3. // @description Display the marker of page scroll in InoReader. / InoReaderでページスクロールしたときにマーカーを表示します。
  4. // @description:en Display the marker of page scroll in InoReader.
  5. // @description:ja InoReaderでページスクロールしたときにマーカーを表示します。
  6. // @id InoReaderScrollMarker
  7. // @namespace http://userscripts.org/scripts/show/173921
  8. // @homepage https://greasyfork.org/scripts/894-inoreader-scroll-marker
  9. // @include http://inoreader.com/*
  10. // @include https://inoreader.com/*
  11. // @include http://www.inoreader.com/*
  12. // @include https://www.inoreader.com/*
  13. // @include http://beta.inoreader.com/*
  14. // @include https://beta.inoreader.com/*
  15. // @include http://us.inoreader.com/*
  16. // @include https://us.inoreader.com/*
  17. // @exclude *inoreader.com/stream*
  18. // @exclude *inoreader.com/m/*
  19. // @exclude *inoreader.com/old/stream*
  20. // @exclude *inoreader.com/old/m/*
  21. // @version 1.12
  22. // @grant GM_addStyle
  23. // ==/UserScript==
  24.  
  25. (function() {
  26. 'use strict';
  27.  
  28. if (!/Ino\s?Reader/i.test(document.title)) return;
  29. try {
  30. if (typeof localStorage !== 'object') return window.alert('IRSM Error: DOM Storage');
  31. } catch (er) {
  32. return window.alert('IRSM Error: DOM Storage');
  33. }
  34. var $id = function(id) {
  35. return document.getElementById(id);
  36. }, iInit;
  37.  
  38. var init = function() {
  39. var ismRp = document.createElement('div'),
  40. ismTwc = document.createElement('div'),
  41. nScrPos = 0,
  42. nCheck = 0,
  43. nTime = 750,
  44. shift = false,
  45. exUpKey, exUpCode, exUpShift, exDownKey, exDownCode, exDownShift,
  46. exOpenKey, exOpenCode, exOpenShift, exSpaceKey, exSpaceCode, exSpaceShift,
  47. exSSpaceKey, exSSpaceCode, exSSpaceShift, articleID, iMarker, iIrkc, st;
  48. ismRp.id = 'irsm_scroll_marker_rp';
  49. ismTwc.id = 'irsm_scroll_marker_twc';
  50. ismRp.className = 'irsm_scroll_marker';
  51. ismTwc.className = 'irsm_scroll_marker';
  52. $id('reader_pane').insertBefore(ismRp, $id('reader_pane').firstChild);
  53. new MutationObserver(function() {
  54. var rp = $id('reader_pane');
  55. if (!$id('irsm_scroll_marker_rp') && rp && rp.childNodes.length) {
  56. rp.insertBefore(ismRp, rp.firstChild);
  57. }
  58. }).observe($id('reader_pane'), {
  59. childList: true
  60. });
  61. new MutationObserver(function() {
  62. var twcafc = document.querySelector('#three_way_contents > .article_full_contents:last-child');
  63. if (!$id('irsm_scroll_marker_twc') && twcafc && twcafc.childNodes.length) {
  64. twcafc.insertBefore(ismTwc, twcafc.firstChild);
  65. }
  66. }).observe($id('three_way_contents'), {
  67. childList: true
  68. });
  69. var CSS = '#irsm_settings { display: none; color: black; position: absolute; top: 68px; left: 68px; z-index: 90200; background: rgba(255, 255, 255, 0.98); border: 1px solid #999999; border-radius: 4px; box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2); -moz-user-select: none; -webkit-user-select: none; }' +
  70. '#irsm_s_titlebar { background-color: #666666; border-radius: 4px 4px 0 0; padding: 2px 0 0 4px; height: 2em; min-width: 20em; }' +
  71. '#irsm_s_title a { font-size: 110%; font-weight: bold; color: white; text-decoration: none; }' +
  72. '#irsm_s_title a:hover { color: #FFFF99; }' +
  73. '#irsm_s_btn { position: absolute; top: 2px; right: 4px; }' +
  74. '#irsm_s_ok { margin-right: 0.5em; padding: 0 2em; }' +
  75. '#irsm_s_cancel { padding: 0 1ex; }' +
  76. '#irsm_s_ok, #irsm_s_cancel { font-size: 80%; }' +
  77. '#irsm_s_body { padding: 0.5em 1em; min-width: 30em; }' +
  78. '#irsm_s_body fieldset { margin: 4px 2px; background: rgba(255, 255, 255, 0); }' +
  79. '#irsm_s_body input { margin-left: 0.5em; text-align: center; width: 6ex; }' +
  80. '#irsm_s_body input[type="checkbox"] { vertical-align: middle; width: auto; }' +
  81. '#irsm_s_time { vertical-align: inherit; }' +
  82. '.irsm_scroll_marker { position: absolute; left: 0; width: 100%; height: 4px; margin-top: -2px; background: rgba(255,0,0,0.25); display: none; z-index: 9000; }' +
  83. '.irsm_s_hide { display: none; }' +
  84. '#three_way_contents .article_full_contents { padding: 4px 0; }' +
  85. '#three_way_contents .article_footer { display: none; box-shadow: 0 2px 4px 0 #333; width: auto; padding-left: 20px; padding-right: 20px; }' +
  86. '#subscriptions_buttons:hover + #splitter #three_way_contents .article_footer, #three_way_contents .article_footer:hover { display: block; }';
  87. GM_addStyle(CSS);
  88.  
  89. var locale_ja = [
  90. '設定',
  91. 'キャンセル',
  92. 'マーカーを表示する時間 (ミリ秒):',
  93. 'マーカーを表示するショートカットキー'
  94. ];
  95. var locale_en = [
  96. 'Settings',
  97. 'Cancel',
  98. 'Time to display the marker (msec):',
  99. 'Keyboard shortcut to display the marker'
  100. ];
  101. var loc = (window.navigator.language === 'ja') ? locale_ja : locale_en;
  102.  
  103. var currentEntry = function() {
  104. if ($id('article_dialog')) {
  105. return document.querySelector('#article_dialog > .article_full_contents');
  106. }
  107. if ($id('three_way_contents') && $id('three_way_contents').style.display !== 'none' && $id('reader_pane').getElementsByClassName('article_current article_current_3way')[0]) {
  108. return document.querySelector('#three_way_contents > .article_full_contents:last-child');
  109. }
  110. if ($id('subscriptions_articles')) {
  111. return document.querySelector('#subscriptions_articles > .article_current');
  112. }
  113. return document.querySelector('#reader_pane .article_current');
  114. };
  115.  
  116. var checkArticle = function(e, key) {
  117. var btn = $id('view_style_img'),
  118. rp = $id('reader_pane');
  119. if (((rp && rp.classList.contains('reader_pane_view_style_1')) || (btn && btn.hasAttribute('src') && btn.getAttribute('src') !== 'images/application-image.png')) && (e.keyCode === 32 || e.keyCode === exSpaceCode || e.keyCode === exSSpaceCode)) {
  120. var ce = currentEntry();
  121. if (key === 'down') {
  122. if (ce && ce.id) return ce.id;
  123. else if (articleID) return articleID;
  124. else return '';
  125. } else if (key === 'up') {
  126. if (ce && ce.id && ce.id !== articleID) {
  127. return true;
  128. } else return false;
  129. } else return false;
  130. } else return false;
  131. };
  132.  
  133. var exKey = function() {
  134. if ($id('irkc_key-PageUp')) {
  135. exUpKey = $id('irkc_key-PageUp').value;
  136. if (exUpKey) {
  137. exUpCode = (/^[%&]$/.test(exUpKey)) ? 32 : exUpKey.toUpperCase().charCodeAt(0);
  138. exUpShift = (isNaN(exUpKey) && exUpKey === exUpKey.toUpperCase() && exUpKey !== '&') ? true : false;
  139. }
  140. }
  141. if ($id('irkc_key-PageDown')) {
  142. exDownKey = $id('irkc_key-PageDown').value;
  143. if (exDownKey) {
  144. exDownCode = (/^[%&]$/.test(exDownKey)) ? 32 : exDownKey.toUpperCase().charCodeAt(0);
  145. exDownShift = (isNaN(exDownKey) && exDownKey === exDownKey.toUpperCase() && exDownKey !== '&') ? true : false;
  146. }
  147. }
  148. if ($id('irkc_key-space')) {
  149. exSpaceKey = $id('irkc_key-space').value;
  150. if (exSpaceKey) {
  151. exSpaceCode = (/^[%&]$/.test(exSpaceKey)) ? 32 : exSpaceKey.toUpperCase().charCodeAt(0);
  152. exSpaceShift = (isNaN(exSpaceKey) && exSpaceKey === exSpaceKey.toUpperCase() && exSpaceKey !== '&') ? true : false;
  153. }
  154. }
  155. if ($id('irkc_key-SPACE')) {
  156. exSSpaceKey = $id('irkc_key-SPACE').value;
  157. if (exSSpaceKey) {
  158. exSSpaceCode = (/^[%&]$/.test(exSSpaceKey)) ? 32 : exSSpaceKey.toUpperCase().charCodeAt(0);
  159. exSSpaceShift = (isNaN(exSSpaceKey) && exSSpaceKey === exSSpaceKey.toUpperCase() && exSSpaceKey !== '&') ? true : false;
  160. }
  161. }
  162. if ($id('irkc_key-o')) {
  163. exOpenKey = $id('irkc_key-o').value;
  164. if (exOpenKey) {
  165. exOpenCode = (/^[%&]$/.test(exOpenKey)) ? 32 : exOpenKey.toUpperCase().charCodeAt(0);
  166. exOpenShift = (isNaN(exOpenKey) && exOpenKey === exOpenKey.toUpperCase() && exOpenKey !== '&') ? true : false;
  167. }
  168. }
  169. };
  170.  
  171. var checkIrkc = function() {
  172. if ($id('irkc_ok')) {
  173. window.clearInterval(iIrkc);
  174. $id('irkc_ok').addEventListener('click', function() {
  175. exKey();
  176. }, false);
  177. exKey();
  178. } else if (nCheck < 99) nCheck++;
  179. else window.clearInterval(iIrkc);
  180. };
  181.  
  182. var viewSettings = function() {
  183. if ($id('irsm_settings').style.display === 'block') {
  184. $id('irsm_settings').style.display = 'none';
  185. return;
  186. }
  187. $id('irsm_s_time').value = st.time;
  188. $id('irsm_s_key_page').checked = (st.key_page) ? true : false;
  189. $id('irsm_s_key_space').checked = (st.key_space) ? true : false;
  190. $id('irsm_settings').style.display = 'block';
  191. };
  192.  
  193. var loadSettings = function() {
  194. st = {};
  195. try {
  196. st = JSON.parse(localStorage.getItem('InoReaderScrollMarker_settings')) || {};
  197. } catch (er) {
  198. window.alert('IRSM Error: Load Settings');
  199. }
  200. var notB = function(a) {
  201. return (typeof a !== 'boolean') ? true : false;
  202. };
  203. var notN = function(a) {
  204. return (typeof a !== 'number') ? true : false;
  205. };
  206. if (notN(st.time)) st.time = nTime;
  207. if (notB(st.key_page)) st.key_page = true;
  208. if (notB(st.key_space)) st.key_space = true;
  209. };
  210.  
  211. var saveSettings = function() {
  212. try {
  213. localStorage.setItem('InoReaderScrollMarker_settings', JSON.stringify(st));
  214. } catch (er) {
  215. window.alert('IRSM Error: Save Settings');
  216. }
  217. };
  218.  
  219. var div = document.createElement('div');
  220. div.id = 'irsm_settings';
  221. document.body.appendChild(div);
  222. $id('irsm_settings').innerHTML = '<div id="irsm_s_titlebar"><div id="irsm_s_title"><a href="https://greasyfork.org/scripts/894-inoreader-scroll-marker" target="_blank">InoReader Scroll Marker ' + loc[0] + '</a></div><div id="irsm_s_btn"><input type="button" id="irsm_s_ok" value="OK"><input type="button" id="irsm_s_cancel" value="' + loc[1] + '"></div></div><div id="irsm_s_body"><label>' + loc[2] + '<input id="irsm_s_time" type="text" maxlength="4"></label><fieldset><legend>' + loc[3] + ' : </legend><label><input id="irsm_s_key_page" type="checkbox">PageUp / PageDown</label><br><label><input id="irsm_s_key_space" type="checkbox">Space / Shift+Space</label></fieldset></div>';
  223.  
  224. var menu = $id('sb_rp_settings_menu'),
  225. pqm = $id('preferences_quick_main'),
  226. item = document.createElement('div');
  227. item.id = 'irsm_settings-menu';
  228. item.innerHTML = 'Scroll Marker ' + loc[0];
  229. if (menu) {
  230. item.className = 'inno_toolbar_button_menu_item';
  231. var menuList = menu.children;
  232. if (!menuList[menuList.length - 1].id) {
  233. var line = document.createElement('div');
  234. line.className = 'inno_toolbar_button_menu_line';
  235. menu.insertBefore(line, menu.lastChild.nextSibling);
  236. }
  237. menu.insertBefore(item, menu.lastChild.nextSibling);
  238. } else if ($id('quick_options') && pqm) {
  239. item.className = 'quick_options_link';
  240. pqm.insertBefore(item, pqm.lastChild.nextSibling);
  241. }
  242.  
  243. document.addEventListener('keydown', function(e) {
  244. var eRp = $id('reader_pane'),
  245. eTwc = $id('three_way_contents');
  246. if (eRp && !/^input|^textarea/i.test(e.target.tagName) && st.time !== 0) {
  247. if (
  248. (st.key_page && e.keyCode === 33) ||
  249. (st.key_page && e.keyCode === 34) ||
  250. (st.key_page && exUpKey && e.keyCode === exUpCode) ||
  251. (st.key_page && exDownKey && e.keyCode === exDownCode) ||
  252. (st.key_space && e.keyCode === 32 && exSpaceKey !== '&') ||
  253. (st.key_space && e.keyCode === 32 && e.shiftKey && exSSpaceKey !== '%') ||
  254. (st.key_space && exSpaceKey && e.keyCode === exSpaceCode) ||
  255. (st.key_space && exSSpaceKey && e.keyCode === exSSpaceCode)
  256. ) {
  257. if (
  258. (exUpCode !== exDownCode && (
  259. (e.keyCode === exUpCode && e.shiftKey !== exUpShift) ||
  260. (e.keyCode === exDownCode && e.shiftKey !== exDownShift)
  261. )) ||
  262. (exSpaceCode !== exSSpaceCode && (
  263. (e.keyCode === exSpaceCode && e.shiftKey !== exSpaceShift) ||
  264. (e.keyCode === exSSpaceCode && e.shiftKey !== exSSpaceShift)
  265. ))
  266. ) return;
  267. articleID = checkArticle(e, 'down');
  268. ismRp.style.display = 'none';
  269. ismTwc.style.display = 'none';
  270. nScrPos = (eTwc.offsetParent) ? eTwc.scrollTop : eRp.scrollTop;
  271. if (e.shiftKey) shift = true;
  272. } else if (e.keyCode === 13 || (!exOpenKey && e.keyCode === 79) || (exOpenKey && e.keyCode === exOpenCode && e.shiftKey === exOpenShift)) {
  273. var ac = currentEntry();
  274. if (ac) {
  275. window.clearTimeout(iMarker);
  276. ismRp.style.display = 'none';
  277. ismTwc.style.display = 'none';
  278. }
  279. } else if (ismRp.style.display !== 'none') {
  280. window.clearTimeout(iMarker);
  281. ismRp.style.display = 'none';
  282. } else if (ismTwc.style.display !== 'none') {
  283. window.clearTimeout(iMarker);
  284. ismTwc.style.display = 'none';
  285. }
  286. }
  287. }, true);
  288.  
  289. document.addEventListener('keyup', function(e) {
  290. var eRp = $id('reader_pane'),
  291. eTwc = $id('three_way_contents'),
  292. soh = 0,
  293. sst = 0;
  294. if (eRp && !/^input|^textarea/i.test(e.target.tagName) && st.time !== 0) {
  295. var bTwc = (eTwc.offsetParent) ? true : false;
  296. soh = (bTwc) ? eTwc.offsetHeight : eRp.offsetHeight;
  297. sst = (bTwc) ? eTwc.scrollTop : eRp.scrollTop;
  298. if (
  299. (st.key_page && e.keyCode === 33) ||
  300. (st.key_page && exUpKey && e.keyCode === exUpCode && (e.shiftKey === exUpShift || shift)) ||
  301. (st.key_space && e.keyCode === 32 && e.shiftKey && exSSpaceKey !== '%') ||
  302. (st.key_space && exSSpaceKey && e.keyCode === exSSpaceCode && (e.shiftKey === exSSpaceShift || shift))
  303. ) {
  304. if (nScrPos !== sst) {
  305. if (checkArticle(e, 'up')) {
  306. articleID = '';
  307. return;
  308. }
  309. if (bTwc) {
  310. ismTwc.style.display = 'block';
  311. ismTwc.style.top = (nScrPos - (ismTwc.scrollHeight / 2)) + 'px';
  312. } else {
  313. ismRp.style.display = 'block';
  314. ismRp.style.top = (nScrPos - (ismRp.scrollHeight / 2)) + 'px';
  315. }
  316. window.clearTimeout(iMarker);
  317. if (st.time > 0) {
  318. iMarker = window.setTimeout(function() {
  319. window.clearTimeout(iMarker);
  320. ismRp.style.display = 'none';
  321. ismTwc.style.display = 'none';
  322. }, st.time);
  323. }
  324. }
  325. shift = false;
  326. } else if (
  327. (st.key_page && e.keyCode === 34) ||
  328. (st.key_page && exDownKey && e.keyCode === exDownCode && (e.shiftKey === exDownShift || shift)) ||
  329. (st.key_space && e.keyCode === 32 && !e.shiftKey && exSpaceKey !== '&') ||
  330. (st.key_space && exSpaceKey && e.keyCode === exSpaceCode && (e.shiftKey === exSpaceShift || shift))
  331. ) {
  332. if (nScrPos !== sst) {
  333. if (checkArticle(e, 'up')) {
  334. articleID = '';
  335. return;
  336. }
  337. if (bTwc) {
  338. ismTwc.style.display = 'block';
  339. ismTwc.style.top = (nScrPos + soh - (ismTwc.scrollHeight / 2)) + 'px';
  340. } else {
  341. ismRp.style.display = 'block';
  342. ismRp.style.top = (nScrPos + soh - (ismRp.scrollHeight / 2)) + 'px';
  343. }
  344. window.clearTimeout(iMarker);
  345. if (st.time > 0) {
  346. iMarker = window.setTimeout(function() {
  347. window.clearTimeout(iMarker);
  348. ismRp.style.display = 'none';
  349. ismTwc.style.display = 'none';
  350. }, st.time);
  351. }
  352. }
  353. shift = false;
  354. }
  355. }
  356. }, true);
  357.  
  358. document.addEventListener('click', function(e) {
  359. if (e.button >= 2) return;
  360. if (e.target.id === 'irsm_settings-menu') {
  361. viewSettings();
  362. } else if (e.target.id === 'irsm_s_ok') {
  363. var time = $id('irsm_s_time').value,
  364. problem = false;
  365. if (time === '' || /^\s+$/.test(time)) st.time = nTime;
  366. else if (time && !isNaN(time)) st.time = Number(time);
  367. else problem = true;
  368. if (!problem) {
  369. st.key_page = $id('irsm_s_key_page').checked;
  370. st.key_space = $id('irsm_s_key_space').checked;
  371. $id('irsm_s_ok').blur();
  372. $id('irsm_settings').style.display = 'none';
  373. saveSettings();
  374. }
  375. } else if (e.target.id === 'irsm_s_cancel') {
  376. $id('irsm_s_cancel').blur();
  377. $id('irsm_settings').style.display = 'none';
  378. } else if (ismRp.style.display !== 'none') {
  379. window.clearTimeout(iMarker);
  380. ismRp.style.display = 'none';
  381. } else if (ismTwc.style.display !== 'none') {
  382. window.clearTimeout(iMarker);
  383. ismTwc.style.display = 'none';
  384. }
  385. }, false);
  386.  
  387. loadSettings();
  388. iIrkc = window.setInterval(function() {
  389. checkIrkc();
  390. }, 250);
  391.  
  392. $id('irsm_s_titlebar').addEventListener('dblclick', function(e) {
  393. if (e.target.nodeName === 'DIV') {
  394. $id('irsm_s_body').classList.toggle('irsm_s_hide');
  395. $id('irsm_s_btn').classList.toggle('irsm_s_hide');
  396. }
  397. }, false);
  398. };
  399.  
  400. iInit = window.setInterval(function() {
  401. if ($id('tree') && $id('tree').innerHTML) {
  402. window.clearInterval(iInit);
  403. window.setTimeout(function() {
  404. init();
  405. }, 1000);
  406. }
  407. }, 500);
  408.  
  409. })();