Smart Scroll

Provides buttons to scroll web pages up and down

安裝腳本?
作者推薦腳本

您可能也會喜歡 SmartChute

安裝腳本
  1. // ==UserScript==
  2. // @version 19.11.11
  3. // @name Smart Scroll
  4. // @description Provides buttons to scroll web pages up and down
  5. // @license MIT
  6. // @author S-Marty
  7. // @compatible firefox
  8. // @compatible chrome
  9. // @namespace https://github.com/s-marty/SmartScroll
  10. // @homepageURL https://github.com/s-marty/SmartScroll
  11. // @supportURL https://github.com/s-marty/SmartScroll/wiki
  12. // @icon https://raw.githubusercontent.com/s-marty/SmartScroll/master/images/smartScroll.png
  13. // @contributionURL https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=QHFFSLZ7ENUQN&source=url
  14. // @include /^https?://.*$/
  15. // @exclude /[^\s]+\.(jpe?g|png|gif|bmp|svg)(\?[^\s]+)?$/
  16. // @run-at document-end
  17. // @grant GM.getValue
  18. // @grant GM.setValue
  19. // @grant GM_getValue
  20. // @grant GM_setValue
  21. // @noframes
  22. // ==/UserScript==
  23.  
  24. /* greasyfork.org jshint syntax checking hacks */
  25. /* jshint asi: true */
  26. /* jshint boss: true */
  27. /* jshint esversion: 6 */
  28. /* jshint loopfunc: true */
  29.  
  30. /** ****************** Features ******************
  31. *** Able to leap tall pages in a single click
  32. *** Up and down, slow or faster than a speeding bullet
  33. *** More robust than a locomotive
  34. *** Slow scroll by middle mouse button or mouse hover
  35. *** 26 Slow scrolling speeds
  36. *** Doesn't interfere with the page's native onScroll event
  37. *** Conquers bottomless or never-ending pages in most cases
  38. *** Disableable per site
  39. *** No extra @require files (jquery et.al.)
  40. *** Double-click on either button for settings ***
  41. *** Compatable with Firefox 43 to 63+ ***
  42. *** Compatable with Chrome 62 to 71 ***
  43. *** Compatable with Violentmonkey ? to 2.10 ***
  44. *** Compatable with Greasemonkey 3.9 to 4.7 ***
  45. *** Compatable with Tampermonkey 4.7 to 4.8 ***/
  46.  
  47. (function () {
  48. "use strict";
  49.  
  50. var buttons = {
  51.  
  52. monkey: function () {
  53. let style;
  54.  
  55. if (this.user.settings.ignore.indexOf(host) !=-1) return;
  56.  
  57. if (this.body && this.is_userscript) {
  58. style = document.createElement("style");
  59. style.setAttribute('id', 'smartscrollstyle');
  60. style.type = "text/css";
  61. style.innerHTML = this.buttonCss();
  62. this.head.appendChild(style);
  63.  
  64. this.up_ctn = document.createElement("span");
  65. this.dn_ctn = document.createElement("span");
  66. this.up_ctn.setAttribute("id","up_btn");
  67. this.dn_ctn.setAttribute("id","dn_btn");
  68. this.up_ctn.className = "updn_btn";
  69. this.dn_ctn.className = "updn_btn";
  70. this.body.appendChild(this.up_ctn);
  71. this.body.appendChild(this.dn_ctn);
  72.  
  73. if (this.user.settings.crawl_trigger == 'middleclick') {
  74. this.up_ctn.addEventListener('mousedown', function(e) { if(e.which==2) {buttons.creepUp(1)} }, false);
  75. this.up_ctn.addEventListener('mouseup', function(e) { if(e.which==2) {buttons.creep = !1} }, false);
  76. this.dn_ctn.addEventListener('mousedown', function(e) { if(e.which==2) {buttons.creepDn(1)} }, false);
  77. this.dn_ctn.addEventListener('mouseup', function(e) { if(e.which==2) {buttons.creep = !1} }, false);
  78. }
  79. else {
  80. this.up_ctn.addEventListener('mouseover', function(e) { buttons.creepUp(1) }, false);
  81. this.up_ctn.addEventListener('mouseout', function(e) { buttons.creep = !1 }, false);
  82. this.dn_ctn.addEventListener('mouseover', function(e) { buttons.creepDn(1) }, false);
  83. this.dn_ctn.addEventListener('mouseout', function(e) { buttons.creep = !1 }, false);
  84. }
  85.  
  86. this.up_ctn.addEventListener('dblclick', function(e) { if(e.which===1) {buttons.smartScroll_Settings(e)} }, false);
  87. this.dn_ctn.addEventListener('dblclick', function(e) { if(e.which===1) {buttons.smartScroll_Settings(e)} }, false);
  88. this.up_ctn.addEventListener('click', function(e) { if(e.which===1) {buttons.scrollToTop()} }, false);
  89. this.dn_ctn.addEventListener('click', function(e) { if(e.which===1) {buttons.scrollToBottom()} }, false);
  90.  
  91. if (root !== null && this.user.settings.bottomless_pages) {
  92. this.resize = document.createElement("iframe");
  93. this.resize.setAttribute("name","resize_frame");
  94. this.resize.setAttribute("tabindex","-1");
  95. this.resize.className = "resize_frame";
  96. root.appendChild(this.resize);
  97. this.resize.contentWindow.addEventListener('resize', function(e) { buttons.getDocumentHeight(e) }, false);
  98. }
  99.  
  100. window.addEventListener('scroll', buttons.onScroll, {passive : true});
  101. window.addEventListener('resize', buttons.onResize, false);
  102. this.body.addEventListener('mouseleave', buttons.saveAccrued, false);
  103. window.addEventListener('beforeunload', function(e) { buttons.settings_close('unload')}, false);
  104. document.addEventListener('readystatechange', function(e) { if(document.readyState === "complete") { buttons.getDocumentHeight(e)} }, false);
  105.  
  106. if (this.user.settings.dimButtons) {
  107. setTimeout(buttons.fadeOut, 3000);
  108. }
  109. }
  110. else return
  111.  
  112. },
  113. areOverVid: function(e) {
  114.  
  115. var vid = (typeof e === 'object' && e.target.tagName == 'VIDEO') ? e.target : false;
  116. if (! vid) return false;
  117. else {
  118. var isOverV = false;
  119. var isOverH = false;
  120. var vidRect = vid.getBoundingClientRect();
  121. var butRect = buttons.up_ctn.getBoundingClientRect();
  122.  
  123. if (vidRect.right - vidRect.left > window.innerWidth / 2) {
  124. isOverH = true;
  125. }
  126. else {
  127. isOverH = vidRect.left < window.innerWidth - 33 && vidRect.right > window.innerWidth - 33;
  128. }
  129. isOverV = vidRect.top < butRect.top && vidRect.bottom > butRect.top;
  130.  
  131. return isOverH && isOverV;
  132. }
  133.  
  134. },
  135. fadeOut: function(e) {
  136.  
  137. var up_btn = buttons.up_ctn;
  138. var dn_btn = buttons.dn_ctn;
  139.  
  140. if (buttons.fading) return;
  141. else if (buttons.areOverVid(e)) {
  142. if (buttons.opacity_timer) clearInterval(buttons.opacity_timer);
  143. up_btn.style.visibility = 'visible';
  144. dn_btn.style.visibility = 'visible';
  145. up_btn.style.opacity = 0.65;
  146. dn_btn.style.opacity = 0.65;
  147. buttons.fading = setTimeout( function(e) {buttons.fading = null}, 3000);
  148. setTimeout( function(e) {
  149. buttons.opacity_timer = setInterval(function() {
  150. if (up_btn.style.opacity <= 0) {
  151. clearInterval(buttons.opacity_timer);
  152. buttons.opacity_timer = null;
  153. up_btn.style.visibility = 'hidden';
  154. dn_btn.style.visibility = 'hidden';
  155. }
  156. else {
  157. up_btn.style.opacity -= 0.025;
  158. dn_btn.style.opacity -= 0.025;
  159. }
  160. }, 100);
  161. }, 3000);
  162. }
  163. else {
  164. if (buttons.opacity_timer) {
  165. clearInterval(buttons.opacity_timer);
  166. buttons.opacity_timer = null;
  167. }
  168. up_btn.style.visibility = 'visible';
  169. dn_btn.style.visibility = 'visible';
  170. up_btn.style.opacity = 0.65;
  171. dn_btn.style.opacity = 0.65;
  172. }
  173.  
  174. },
  175. reLoadStart: function(e) {
  176.  
  177. setTimeout(function() {
  178. buttons.getDocumentHeight();
  179. buttons.getVideo();
  180. setTimeout(buttons.fadeOut, 3000);
  181. }, 500);
  182.  
  183. },
  184. hideOnFullScreen: function() {
  185.  
  186. document.addEventListener("fullscreenchange", () => { buttons.onFullScreen()});
  187. document.addEventListener("mozfullscreenchange", () => { buttons.onFullScreen()});
  188. document.addEventListener("webkitfullscreenchange", () => { buttons.onFullScreen()});
  189.  
  190. },
  191. onFullScreen: function(e) {
  192.  
  193. if (document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement) {
  194. buttons.body.className = buttons.body.className + " isfullscreen";
  195. }
  196. else {
  197. buttons.body.className = buttons.body.className.replace(/\sisfullscreen/g, "");
  198. window.setTimeout(buttons.resetButtons,100);
  199. }
  200.  
  201. },
  202. hasScrollbar: function() {
  203.  
  204. let x,
  205. rootElem,
  206. overflowShown,
  207. overflowStyle,
  208. overflowYStyle,
  209. contentOverflows,
  210. alwaysShowScroll;
  211.  
  212. if (typeof window.innerHeight === 'number') {
  213. x = window.innerHeight - document.documentElement.clientHeight;
  214. return [window.innerHeight > document.documentElement.clientHeight, x+1];
  215. }
  216.  
  217. rootElem = document.documentElement || document.body;
  218.  
  219. if (typeof rootElem.currentStyle !== 'undefined') {
  220. overflowStyle = rootElem.currentStyle.overflow;
  221. }
  222.  
  223. overflowStyle = overflowStyle || window.getComputedStyle(rootElem, '').overflow
  224.  
  225. if (typeof rootElem.currentStyle !== 'undefined') {
  226. overflowYStyle = rootElem.currentStyle.overflowY;
  227. }
  228. overflowYStyle = overflowYStyle || window.getComputedStyle(rootElem, '').overflowY;
  229. contentOverflows = rootElem.scrollHeight > rootElem.clientHeight;
  230. overflowShown = /^(visible|auto)$/.test(overflowStyle) || /^(visible|auto)$/.test(overflowYStyle);
  231. alwaysShowScroll = overflowStyle === 'scroll' || overflowYStyle === 'scroll';
  232.  
  233. if ((contentOverflows && overflowShown) || (alwaysShowScroll)) {
  234. return true}
  235. else {
  236. return false}
  237.  
  238. },
  239. getScrollTop: function() {
  240.  
  241. if (typeof pageYOffset != 'undefined') {
  242. buttons._x = pageXOffset;
  243. return pageYOffset;
  244. }
  245.  
  246. },
  247. getDocumentHeight: function(e) {
  248.  
  249. let docHeight = Math.max(
  250. document.documentElement.clientHeight,
  251. document.body.scrollHeight, document.documentElement.scrollHeight,
  252. document.body.offsetHeight, document.documentElement.offsetHeight
  253. ) - ( buttons.hasScrollbar() ? buttons.scrollbar : 0 );
  254.  
  255. if (docHeight > window.innerHeight) {
  256. if(docHeight - window.innerHeight - buttons.scrollable < 6) return;
  257. buttons.getVideo();
  258. buttons.scrollable = docHeight - window.innerHeight;
  259. buttons.onScroll();
  260. }
  261.  
  262. },
  263. scrollToTop: function(e) {
  264.  
  265. var y, start = buttons.scrolled;
  266.  
  267. if (start > 0) {
  268. buttons.animate({
  269. duration: 1000,
  270. timing: function(timeFraction) {
  271. return Math.pow(timeFraction, 5);
  272. },
  273. draw: function(progress) {
  274. y = start - (progress * start);
  275. if (y < 0) y = 0;
  276. if (progress < 1) {
  277. window.scrollTo(buttons._x, y);
  278. }
  279. else {
  280. window.scrollTo(buttons._x, 0);
  281. buttons.count_accru += start;
  282. buttons.getVideo();
  283. }
  284. }
  285. });
  286. }
  287.  
  288. },
  289. scrollToBottom: function(e) {
  290.  
  291. var y, start = buttons.scrolled;
  292. var maxscroll = buttons.scrollable;
  293.  
  294. if (maxscroll > start) {
  295. buttons.animate({
  296. duration: 1000,
  297. timing: function(timeFraction) {
  298. return Math.pow(timeFraction, 5);
  299. },
  300. draw: function(progress) {
  301. y = (progress * maxscroll) + ((1 - progress) * start);
  302. if (y > maxscroll) y = maxscroll;
  303. if (progress < 1) {
  304. window.scrollTo(buttons._x, y);
  305. }
  306. else {
  307. window.scrollTo(buttons._x, maxscroll + 2);
  308. buttons.count_accru += maxscroll - start;
  309. buttons.getVideo();
  310. }
  311. }
  312. });
  313. }
  314.  
  315. },
  316. creepUp: function(e) {
  317.  
  318. if (e === 1) {
  319. buttons.creep = 1;
  320. buttons.killCreeper();
  321. buttons.creeper = setInterval(buttons.creepUp, buttons.crawl_speed_ms);
  322. }
  323. buttons.scrolled = buttons.getScrollTop();
  324. if (buttons.creep && buttons.scrolled > 0) {
  325. window.scrollTo(buttons._x, buttons.scrolled - buttons.step);
  326. buttons.count_accru += buttons.step;
  327. }
  328. else buttons.killCreeper()
  329.  
  330. },
  331. creepDn: function(e) {
  332.  
  333. if (e === 1) {
  334. buttons.creep = 1;
  335. buttons.killCreeper();
  336. buttons.creeper = setInterval(buttons.creepDn, buttons.crawl_speed_ms);
  337. }
  338. buttons.scrolled = buttons.getScrollTop();
  339. if (buttons.creep && buttons.scrollable > buttons.scrolled) {
  340. window.scrollTo(buttons._x, buttons.scrolled + buttons.step);
  341. buttons.count_accru += buttons.step;
  342. }
  343. else buttons.killCreeper()
  344.  
  345. },
  346. onResize: function(e) {
  347.  
  348. buttons.getDocumentHeight(e);
  349. window.setTimeout(buttons.resetButtons,500);
  350.  
  351. },
  352. onScroll: function(e) {
  353.  
  354. buttons.scrolled = buttons.getScrollTop();
  355. if (! buttons.scrollable) { buttons.getDocumentHeight(e) }
  356. if (buttons.scrolled > 0) {
  357. buttons.toggle_up_btn("show");
  358. }
  359. else {
  360. buttons.toggle_up_btn("hide");
  361. }
  362. if (buttons.scrollable > buttons.scrolled) {
  363. buttons.toggle_dn_btn("show");
  364. }
  365. else {
  366. buttons.toggle_dn_btn("hide");
  367. }
  368. },
  369. toggle_up_btn: function(action) {
  370.  
  371. if (action == "show" && buttons.up_btn_show != "show") {
  372. buttons.up_btn_show = "show";
  373. buttons.animate({
  374. duration: 400,
  375. timing: function(timeFraction) {
  376. return Math.pow(timeFraction, 2);
  377. },
  378. draw: function(progress) {
  379. buttons.up_ctn.style.right = -33 + (progress * 33) + 'px';
  380. }
  381. });
  382. }
  383. else if (action == "hide" && buttons.up_btn_show != "hide") {
  384. buttons.up_btn_show = "hide";
  385. buttons.animate({
  386. duration: 500,
  387. timing: function back(x, timeFraction) {
  388. return Math.pow(timeFraction, 2) * ((x + 1) * timeFraction - x)
  389. }.bind(null, 2.8),
  390. draw: function(progress) {
  391. buttons.up_ctn.style.right = 0 - (progress * 33) + 'px';
  392. }
  393. });
  394. }
  395.  
  396. },
  397. toggle_dn_btn: function(action) {
  398.  
  399. if (action == "show" && buttons.dn_btn_show != "show") {
  400. buttons.dn_btn_show = "show";
  401. buttons.animate({
  402. duration: 400,
  403. timing: function(timeFraction) {
  404. return Math.pow(timeFraction, 2);
  405. },
  406. draw: function(progress) {
  407. buttons.dn_ctn.style.right = -33 + (progress * 33) + 'px';
  408. }
  409. });
  410. }
  411. else if (action == "hide" && buttons.dn_btn_show != "hide") {
  412. buttons.dn_btn_show = "hide";
  413. buttons.animate({
  414. duration: 500,
  415. timing: function back(x, timeFraction) {
  416. return Math.pow(timeFraction, 2) * ((x + 1) * timeFraction - x)
  417. }.bind(null, 2.8),
  418. draw: function(progress) {
  419. buttons.dn_ctn.style.right = 0 - (progress * 33) + 'px';
  420. }
  421. });
  422. }
  423.  
  424. },
  425. killCreeper: function() {
  426.  
  427. if (this.creeper !== null) {
  428. clearInterval(this.creeper);
  429. this.creeper = null;
  430. }
  431.  
  432. },
  433. getVideo: function() {
  434.  
  435. if (buttons.user.settings.dimButtons) {
  436. var vid = document.querySelectorAll('video');
  437.  
  438. if (vid.length) {
  439. for (let i = 0; i < vid.length; i++) {
  440. if (vid[i].scrollWidth > 100 && vid[i].scrollHeight > 50) {
  441. vid[i].addEventListener('mousemove', buttons.fadeOut, false);
  442. }
  443. }
  444. document.addEventListener("keydown", function(e) {
  445. if ((e.which == 38 || e.which == 40) && ["INPUT", "TEXTAREA"].indexOf(document.activeElement.tagName) < 0) {
  446. buttons.fadeOut()
  447. }
  448. }, false);
  449. }
  450. }
  451.  
  452. },
  453. animate: function ({timing, draw, duration}) {
  454.  
  455. let start = performance.now();
  456.  
  457. requestAnimationFrame(function animate(time) {
  458. let timeFraction = (time - start) / duration;
  459. if (timeFraction > 1) timeFraction = 1;
  460. let progress = timing(timeFraction);
  461. draw(progress);
  462. if (timeFraction < 1 && buttons.allowScroll) {
  463. requestAnimationFrame(animate);
  464. }
  465. });
  466.  
  467. },
  468. smartScroll_Settings: function(e) {
  469.  
  470. let modal = document.querySelector(".smartScroll_Settings"), form;
  471.  
  472. if (! buttons.settings_id && modal === null) {
  473. buttons.allowScroll = false;
  474. buttons.killCreeper();
  475.  
  476. var s, i, n;
  477. var sel = '';
  478. var plus_sel = '';
  479. var minus_sel = '';
  480. var crawl_sel = '';
  481. let hostname = window.location.hostname;
  482. let m = hostname.match(/^([\w\-]*\.)?([\w\-]+\.((\w{3,4}$)|(\w{2}\.\w{2}$)))/i);
  483.  
  484. if (m !== null && m.length > 2) {
  485. if (typeof m[1] == 'undefined') {m[1] = '';}
  486. hostname = m[1] + m[2];
  487. }
  488.  
  489. let hex = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'],
  490. div = document.createElement("div"),
  491. div2 = div,
  492. html = '',
  493. id = 'a',
  494. doctype = document.createElement("br").outerHTML.indexOf('/') > 0 ? 'XHTML' : 'HTML';
  495.  
  496. for (n = 0; n < 16; n++) {
  497. id += hex[Math.floor(Math.random()*16)];
  498. }
  499.  
  500. var selected = doctype == 'HTML' ? 'selected' : 'selected="selected"';
  501. let rangetype = document.createElement("input");
  502.  
  503. rangetype.setAttribute("type", "range");
  504. rangetype = rangetype.type != "text";
  505. if (! rangetype) {
  506. let opts = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,16,17,19,21,23,26,30,36,44,57,80,100];
  507.  
  508. crawl_sel = '<select name="crawl_speed">';
  509. opts.forEach( function(opt) {
  510. sel = opt == buttons.user.settings.crawl_speed ? selected : '';
  511. crawl_sel += '<option value="'+opt+'" '+sel+'>'+opt+'</option>';
  512. });
  513. crawl_sel += '</select>';
  514. }
  515.  
  516. plus_sel = '<select name="top_plus" style="width: 52px;height: 20px;font-size: 12px;">';
  517. minus_sel = '<select name="bot_minus" style="width: 52px;height: 20px;font-size: 12px;margin-left:36px;">';
  518.  
  519. [0,5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,99].forEach( function(opt) {
  520. sel = opt == buttons.user.settings.top_plus ? selected : '';
  521. plus_sel += '<option value="'+opt+'" '+sel+'>'+opt+'</option>';
  522. sel = opt == buttons.user.settings.bot_minus ? selected : '';
  523. minus_sel += '<option value="'+opt+'" '+sel+'>'+opt+'</option>';
  524. });
  525.  
  526. plus_sel += '</select>';
  527. minus_sel += '</select>';
  528.  
  529. let checked = doctype == 'HTML' ? 'checked' : 'checked="checked"';
  530. let inputclose = doctype == 'HTML' ? '' : '</input>';
  531. let APOS = '\u0027';
  532. let NBSP = '\u00A0';
  533. let MIDDOT = '\u00B7';
  534. let CDATA1 = doctype == 'HTML' ? '' : '/*<![CD'+'ATA[*/';
  535. let CDATA2 = doctype == 'HTML' ? '' : '/*]'+']>*/';
  536. let ignoredHTML = '', ignored = this.user.settings.ignore.split(",");
  537. let padding = [60, 40, 65];
  538. let scrolledToDateTitle = 'That'+APOS+'s ';
  539.  
  540. switch (true) {
  541. case this.user.count > 32602522:
  542. padding = [0,160,5];
  543. s = ((Math.round(this.user.count * 8.825569e-6)) / 10000);
  544. scrolledToDateTitle += (s == 1 ? 'The ' : s +' ')+'Light Second'+(s == 1 ? '' : 's')+'.';
  545. break;
  546. case this.user.count > 2676326:
  547. padding = [20,120,25];
  548. s = ((Math.round(this.user.count * 6.134495e-6)) / 100)
  549. scrolledToDateTitle += (s == 1 ? 'The ' : s +' Times the ')+'Width of the U.S.';
  550. break;
  551. case this.user.count > 669082:
  552. padding = [30,100,35];
  553. s = ((Math.round(this.user.count * 7.747293e-5)) / 100)
  554. scrolledToDateTitle += (s == 1 ? '' : s +' times ')+'the Altitude of the ISS.';
  555. break;
  556. case this.user.count > 3041:
  557. padding = [40,80,45];
  558. s = ((Math.round(this.user.count * 1.644e-2)) / 100);
  559. scrolledToDateTitle += s +' Mile'+(s == 1 ? '' : 's')+'.';
  560. break;
  561. default:
  562. s = ((Math.round(this.user.count * 8.68)) / 10);
  563. scrolledToDateTitle += s +' F'+(s == 1 ? 'oo' : 'ee')+'t';
  564. }
  565.  
  566. let scrolledToDate = this.user.count.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") +',000 Pixels Smart Scrolled.';
  567. let addable = false;
  568.  
  569. for (n = 0; n < ignored.length; n++) {
  570. if (ignored[n].length < 5) continue;
  571. addable = addable || hostname == ignored[n];
  572. ignoredHTML += '<span class="ignores"><button style="padding:0px 3px 1px;margin-right:6px;background-color:#ff3333;color:#fff;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px" onclick="document.forms[\'sssettings\'].remove.value+=\''+ignored[n]+',\';this.disabled=\'disabled\'" title="Mark '+ignored[n]+' for deletion from this list">x</button><span>'+ignored[n]+'</span></span><br />';
  573. }
  574. addable = addable ? '' : ('<span class="addable"><button style="padding:0px 3px 1px;margin-right:6px;background-color:#33ff33;color:#000;font-weight:bold;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px" onclick="document.forms[\'sssettings\'].add.value+=\''+hostname+'\';this.disabled=\'disabled\'" title="Mark '+hostname+' for addition to this list">+</button><span>'+hostname+'</span></span><br />');
  575.  
  576. html = '<div id="'+id+'" style="width:500px;height:400px;margin:auto auto;border-radius:12px 54px 12px 100px;-webkit-border-radius:12px 54px 12px 100px;-moz-border-radius:12px 54px 12px 100px;border:3px solid #CCC;">'+
  577. ' <div style="width:500px;height:50px;background-color:#000;border-radius:12px 50px 0px 0px;-webkit-border-radius:12px 50px 0px 0px;-moz-border-radius:12px 50px 0px 0px;">'+
  578. ' <div style="width: 380px;height:40px;padding:12px 0 0 65px;color:#eee;font-size: 1.5em;font-weight: bold;background:transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAQAAABLCVATAAAAAmJLR0QA/vCI/CkAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfiDBwSIh99fynEAAAD9klEQVRIx6XWzW9UVRjH8c+dzjBtAfsCUlIsKbSU8hZpijGRRAzhTY0Y4sqgiYQENVEXJiTEVUPQjSgr3Rhd+i+wKAYJSMJb5U2YAkljpSVAUlqgZZjOzHXR28tMKSSkZzKbc879nuc+z+/53RNsCc1oBEKPZCWft'+
  579. 'WFcTighQBj909NsD5GaDhQIjcups0aHf50yqtZ6dS7rMywlJRCWPZFgKmgC0q5TuwWuOewUeGiv9e7I6JGRknoqsimgx2ptstJ8Tc44oCeaPyrQZa0aba44YkT6eaCsNts1W6jeCV3Ol6wdlfOjVUbVa3JY7xRURUvXE0yHbZZoVeOyPc4pL2i/GzZoUmNcg5wBFXFWH0tM5iarzUYtWlX50y6XJk9SqQIBjtnlikrtmm3Q7nHJMYkJZl6t7ZZYoso/9jofRRN41Q6rozIXnfSpXmmtmm1VI18OCuVs0qxVtR479ShGy20O+F2Xpriqf/ncoCrLNNpsvBw0rt0qDWbhtgsxptX3Nil6x3eaY9RZD1Gp0QrtcUwJyOlUb7YQuSgftPjNuxKKknY6aEFclAJCNWp1yEW7'+
  580. 'E4yr064xKudanwgltTpovUARRaH3/GSxpCp7LBQKVVukVb2ccEJHOWvUmQ0KXrHfGwKLvSlUiM4rSNqh2oDANrXRS85RZ6mz0pOCXKlRZVSXQKPdRHEEcT8VBLZFgFBREOVpuTNPlL0o7p0g2jidXYiLID4gZVFpsueUbHmxEXqpFJSagbElS0H5GYDKdPRgsuVeeCQ8KAX1y5YYZxD9nrbUJythNPfIf6WvmHHLXJVRNcbcFag0vwyWELotK/CyymjlkVuuPVF2Wp9hDyPTGPGzDut86IKKEh0FLvrAOq/7xVg0/8CIPmnBBChpWK9BWQTO2Oe+ISd8rT+2rgrn7HbKPXftNyAQGHPLDUNR3aLy97hnVIBCFEPBSR+7IIkKJ3wZe1RWEYFhw/6OpROBMq64JYs6DTH'+
  581. 'quH3OSzrtG6fjbC1VjVGDMjKxjpIToacc0aSoXadffeZmtHxEymtOOl6COaTRmGsGdZdIOTL/CqPuaVBUb7l5etyPGrffOdflo/Qu84MtxmUM6DYgFZt//DlK642spM1HkvYZiDKSjXW0wgHvG5Ux4JirZk3/OUoaMGyeRyp0anDRvTJJtvnWZnfccFO3SzFmSkQwy1WDNrtvnrcNORTrluW+8pZeIzK63S+LZkpEE1FlXXJbQd5qc92IctXqCxtdd9kfjimU+cVERMF096O8nHotVuhx1EO1tmlxTZ8hqacuMIGCYcHW8Hn3o6CsZdPPuE7lPZAsPNXjk+ekn+M+QdkzedWSIzO7+QklVJvlf7qjThcu+vTfAAAAAElFTkSuQmCC) no-repeat 10px center;">'+
  582. ' Smart Scroll Settings</div>'+
  583. ' </div>'+
  584. ' <form id="'+id+'_settings_form" name="sssettings" class="sssettings" action="javascript:void(0)" onsubmit="return false" style="padding:10px;height:330px;border-radius:0px 0px 10px 96px;-webkit-border-radius:0px 0px 10px 96px;-moz-border-radius:0px 0px 10px 96px;">'+
  585. ' <div style="width:100%;height:240px;padding-bottom:0px;">'+
  586. ' <div style="width:50%;height:100%;padding:0px;float:left;border-radius:0px 0px 0px 96px;-webkit-border-radius:0px 0px 0px 96px;-moz-border-radius:0px 0px 0px 96px;">'+
  587. ' <span style="margin-left:30px;">Slow scrolling speed:</span><br />'+ (rangetype ?
  588. ' <input name ="crawl_speed" type="range" min="1" max="100" step="1" value="'+this.user.settings.crawl_speed+'" onchange="document.getElementById(\'crawl_speed_now\').innerHTML=this.value" style="width: 180px;">'+inputclose+' <span id="crawl_speed_now">'+this.user.settings.crawl_speed+'</span><br />'+
  589. ' <span style="font-size:11px;">'+NBSP+'Slow '+MIDDOT+NBSP+MIDDOT+NBSP+MIDDOT+NBSP+MIDDOT+' Fast '+MIDDOT+NBSP+MIDDOT+NBSP+MIDDOT+NBSP+MIDDOT+' Faster</span><br /><br />' :
  590. ' '+crawl_sel+'<br />'+
  591. ' <span style="font-size:11px;">1 = Slow thru 100 = Fast</span><br /><br />')+
  592. ' <input type="checkbox" name="bottomless_pages" id="bottomless1" '+(this.user.settings.bottomless_pages ? checked : "")+' >'+inputclose+' <label for="bottomless1" title="Recalculates when pages add content to bottom">Bottomless pages</label><br />'+
  593. ' <input type="checkbox" name="refresh" id="refresh1" '+(this.user.settings.refresh ? checked : "")+' >'+inputclose+' <label for="refresh1" title="Refresh current page upon critical settings changes made here">Auto page refresh</label><br />'+
  594. ' <input type="checkbox" name="dimButtons" id="dimButtons1" '+(this.user.settings.dimButtons ? checked : "")+' >'+inputclose+' <label for="dimButtons1" title="Buttons will disappear when over videos after 3 seconds">Fade out over video</label><br />'+
  595. ' <div style="margin: 6px 0 2px 30px;">Slow scroll trigger</div>'+
  596. ' <span><input type="radio" name="crawl_trigger" id="trigger1" value="middleclick"'+(this.user.settings.crawl_trigger == "middleclick" ? checked : "")+' >'+inputclose+' <label for="trigger1" title="Middle mouse button held down">Middleclick</label> '+
  597. ' <input type="radio" name="crawl_trigger" id="trigger2" value="hover" '+(this.user.settings.crawl_trigger == "hover" ? checked : "")+' style="margin-left:10px;">'+inputclose+' <label for="trigger2" title="Mouse pointer held over">Hover</label></span><br />'+
  598. ' <div style="margin: 6px 0 2px 30px;">Button Position</div>'+
  599. ' <span><input type="radio" name="position" id="position1" value="top" onmouseout="this.blur()" '+(this.user.settings.position == "top" ? checked : "")+'>'+inputclose+' <label for="position1" title="Always at top right">Top</label>'+
  600. ' <input type="radio" name="position" id="position2" value="middle" onmouseout="this.blur()" '+(this.user.settings.position == "middle" ? checked : "")+' style="margin-left:6px;">'+inputclose+' <label for="position2" title="Always at middle right">Middle</label>'+
  601. ' <input type="radio" name="position" id="position3" value="bottom" onmouseout="this.blur()" '+(this.user.settings.position == "bottom" ? checked : "")+' style="margin-left:6px;">'+inputclose+' <label for="position3" title="Always at bottom right">Bottom</label></span><br />'+
  602. ' <span>'+plus_sel+'<span title="Pixels down from top">:Plus</span>'+minus_sel+'<span title="Pixels up from bottom">:Less</span></span><br />'+
  603. ' </div>'+
  604. ' <div style="width:50%;height:100%;float:left;">'+
  605. ' <div style="width:100%;height:20px;text-align:center;" title="(Scroll buttons will not be used)">Ignored Sites</div>'+
  606. ' <div id="ssignored" style="width:224px;height:180px;overflow-y: auto;overflow-x: hidden;border: 1px solid #000;padding: 6px;line-height:1.3;border-radius:5px;-webkit-border-radius:5px;-moz-border-radius:5px;">'+
  607. ' '+addable+ignoredHTML+'</div>'+
  608. ' <div style="width:100%;height:12px;text-align:center;font-style: italic;color:blue;font-size: 12px;padding-top: 4px;cursor:help" title="'+scrolledToDateTitle+'">'+scrolledToDate+'</div>'+
  609. ' </div>'+
  610. ' </div>'+
  611. ' <div style="width:100%;height:90px;border-radius:0px 0px 10px 96px;-webkit-border-radius:0px 0px 10px 96px;-moz-border-radius:0px 0px 10px 96px;">'+
  612. ' <div style="width:fit-content;width: -moz-fit-content;height:80px;margin:10px auto 0px;background-color:transparent">'+
  613. ' <button id="'+id+'_settings_close" style="background-color:#ff3333;padding:30px '+padding[0]+'px;border-radius:0px 0px 0px 74px;-webkit-border-radius:0px 0px 0px 74px;-moz-border-radius:0px 0px 0px 74px;">Cancel</button> '+
  614. ' <button id="'+id+'_settings_donate" style="background-color:#ffff33;padding:30px '+padding[1]+'px;">Donate</button>'+
  615. ' <button id="'+id+'_settings_save" style="background-color:#33ff33;padding:30px '+padding[2]+'px;">Save</button>'+
  616. ' </div>'+
  617. ' </div>'+
  618. ' <input name ="remove" type="hidden" value="">'+inputclose+'<input name ="add" type="hidden" value="">'+inputclose+'<input name ="'+id+'" type="hidden" value="">'+inputclose+
  619. ' <input name ="submit" type="submit" value="" style="width:0px;height:0px;opacity:0;">'+inputclose+
  620. ' </form>'+
  621. '</div>'+
  622. '<style type="text/css">'+CDATA1+
  623. ' #pdus div, #pdus span, #pdus label, #pdus form, #pdus input, #pdus button {margin:0px;padding:0px;border:0px;color:#333;box-sizing:content-box;background-color:#EEE; font: 14px \'Titillium Web\', \'Helvetica Neue\', Helvetica, Arial, sans-serif; box-shadow: none;min-height:0px;line-height: 1;text-align:left; text-decoration:none;outline:none; }'+
  624. ' #pdus div, #pdus form {display:block;} #pdus span, #pdus label {display:inline;} #pdus input, #pdus button {display:inline-block;}'+CDATA2+
  625. '</style>';
  626. div.setAttribute('id', 'pdus');
  627. div.className = "smartScroll_Settings";
  628. div.style = 'width:100%;height:100%;margin:0;padding:0;position:fixed;top:0px;left:0px;background-color: rgba(0, 0, 0, 0.7);z-index:84000;';
  629. div.innerHTML = html;
  630. /* Some (unmentionable large) sites remove settings modal as soon as it is appended */
  631. buttons.body.removeChild=function() {return div2}
  632. buttons.body.replaceChild=function() {return div2}
  633. if (e && e == 'removed') {
  634. buttons.body.innerHTML += div.outerHTML
  635. }
  636. else {
  637. buttons.body.appendChild(div);
  638. setTimeout(function() {
  639. if (document.querySelector(".smartScroll_Settings") === null) {
  640. buttons.settings_id = "";
  641. buttons.smartScroll_Settings('removed');
  642. }
  643. }, 300);
  644. }
  645. buttons.settings_id = id;
  646. form = document.querySelector('form#'+id+'_settings_form');
  647. form.querySelector('#'+id+'_settings_close').addEventListener('click', function(e) { buttons.settings_close() }, false);
  648. form.querySelector('#'+id+'_settings_donate').addEventListener('click', function(e) { buttons.settings_donate() }, false);
  649. form.querySelector('#'+id+'_settings_save').addEventListener('click', function(e) { buttons.onSettingsSave() }, false);
  650. form.querySelector('#'+id+'_settings_save').addEventListener('change', function(e) { buttons.onSettingsSave() }, false);
  651. form.querySelector('#position1').addEventListener('change', function(e) { buttons.updateButtonCss() }, false);
  652. form.querySelector('#position2').addEventListener('change', function(e) { buttons.updateButtonCss() }, false);
  653. form.querySelector('#position3').addEventListener('change', function(e) { buttons.updateButtonCss() }, false);
  654.  
  655. let options1 = form.top_plus.options;
  656. let options2 = form.bot_minus.options;
  657.  
  658. for (i = 0;i < options1.length; i++) {
  659. options1[i].addEventListener('mouseup', function(e) { buttons.updateButtonCss(e) }, false);
  660. options2[i].addEventListener('mouseup', function(e) { buttons.updateButtonCss(e) }, false);
  661. };
  662.  
  663. }
  664. else {
  665. buttons.settings_close()
  666. }
  667.  
  668. },
  669. onSettingsSave: function() {
  670.  
  671. var form = document.querySelector('form#'+buttons.settings_id+'_settings_form');
  672. var inputs = form.querySelectorAll('input, select'),
  673. settings = { ignore: this.user.settings.ignore },
  674. input,
  675. val,
  676. i, n,
  677. ignoreUpdated = false,
  678. refreshNeeded = false;
  679.  
  680. if (form.querySelector('input[name="'+buttons.settings_id+'"]') !== null) {
  681. for (i = 0; i < inputs.length; i++) {
  682. val = null;
  683. input = inputs[i];
  684.  
  685. switch (input.type) {
  686. case 'checkbox':
  687. val = input.checked;
  688. if (this.user.settings[input.name] != val && input.name != 'refresh') {
  689. refreshNeeded = true;
  690. }
  691. break;
  692. case 'select':
  693. case 'select-one':
  694. val = parseInt(input[input.selectedIndex].value);
  695. break;
  696. case 'radio':
  697. if (input.checked) {
  698. val = input.value;
  699. if (this.user.settings[input.name] != val) {
  700. refreshNeeded = true;
  701. }
  702. }
  703. else {continue;}
  704. break;
  705. case 'range':
  706. val = parseInt(input.value);
  707. break;
  708. case 'hidden':
  709. if (input.name == buttons.settings_id) {
  710. continue;
  711. }
  712. else if (input.name == "remove" && input.value != "") {
  713. let thisUrl = false;
  714. let urls = input.value.split(",");
  715.  
  716. for (n = 0; n < urls.length; n++) {
  717. if (urls[n].length < 5) continue;
  718. if (urls[n].indexOf(window.location.hostname) !=-1) {
  719. thisUrl = true;
  720. }
  721. var url = new RegExp(urls[n] +",", "gi");
  722. settings.ignore = settings.ignore.replace(url, "");
  723. }
  724. refreshNeeded = refreshNeeded || thisUrl;
  725. continue;
  726. }
  727. else if (input.name == "add" && input.value != "") {
  728. settings.ignore += input.value.trim() +',';
  729. refreshNeeded = ignoreUpdated = true;
  730. continue;
  731. }
  732. else { continue; }
  733. break;
  734. default: continue;
  735. }
  736. if (val !== null) {
  737. settings[input.name] = val;
  738. }
  739. }
  740. if (ignoreUpdated) {
  741. let ignore = settings.ignore.split(',');
  742.  
  743. ignore.pop();
  744. if (ignore.length > 1) {
  745. ignore.sort();
  746. settings.ignore = ignore.join() +',';
  747. }
  748. }
  749. buttons.saveSettings({name: 'user_settings', value: settings});
  750. if (refreshNeeded && settings.refresh) {
  751. window.location = window.location;
  752. }
  753. else {
  754. this.resetButtons();
  755. }
  756. }
  757. buttons.settings_close();
  758.  
  759. },
  760. settings_close: function(e) {
  761.  
  762. let modal = document.querySelector(".smartScroll_Settings");
  763.  
  764. if (modal !== null) {
  765. modal.remove();
  766. }
  767. buttons.settings_id = "";
  768. if (typeof e != "undefined" && e == 'unload') {
  769. buttons.toggle_up_btn("hide");
  770. buttons.toggle_dn_btn("hide");
  771. }
  772. else { buttons.resetButtons(); }
  773.  
  774. },
  775. saveAccrued: function(e) {
  776.  
  777. if (buttons.count_accru > 1000) {
  778. buttons.initSettings({name: "count"});
  779. }
  780.  
  781. },
  782. saveSettings: function(settings) {
  783.  
  784. if (typeof settings == 'undefined' || typeof settings.name == 'undefined' || settings.name == '') {
  785. console.error('saveSettings() input error');
  786. return;
  787. }
  788.  
  789. switch(settings.name) {
  790. case 'user_settings':
  791. this.GM.setValue('settings', JSON.stringify(settings.value));
  792. break;
  793. case 'count':
  794. if (this.count_accru > 999) {
  795. let totalCount = Math.round(this.count_accru / 1000) + settings.value;
  796.  
  797. this.GM.setValue('count', totalCount);
  798. this.user.count = totalCount;
  799. this.count_accru = 0;
  800. }
  801. else {
  802. this.user.count = settings.value;
  803. }
  804. break;
  805. }
  806.  
  807. },
  808. settings_donate: function() {
  809.  
  810. let donate_url = "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=QHFFSLZ7ENUQN&source=url";
  811. window.open(donate_url, '_blank');
  812.  
  813. },
  814. updateButtonCss: function(e) {
  815.  
  816. let style = document.querySelector('#smartscrollstyle');
  817. let form = document.querySelector('form#'+buttons.settings_id+'_settings_form');
  818. let position2 = form.position2.checked;
  819. let position3 = form.position3.checked;
  820. let position = 'top';
  821.  
  822. if (position2) position = 'middle';
  823. else if (position3) position = 'bottom';
  824.  
  825. let settings = {
  826. position: position,
  827. top_plus: parseInt(form.top_plus[form.top_plus.selectedIndex].value),
  828. bot_minus: parseInt(form.bot_minus[form.bot_minus.selectedIndex].value),
  829. bottomless_pages: buttons.user.settings.bottomless_pages
  830. };
  831. style.innerHTML = buttons.buttonCss(settings);
  832.  
  833. },
  834. buttonCss: function(settings) {
  835.  
  836. let btn_css = '',
  837. dn_btn_css = '',
  838. updn_btn_css = '';
  839.  
  840. settings = typeof settings === 'object' ? settings : this.user.settings;
  841. if (settings.position == 'top') {
  842. updn_btn_css = 'top:'+(settings.top_plus)+'px;';
  843. dn_btn_css = 'margin-top:33px;';
  844. } else if (settings.position == 'bottom') {
  845. updn_btn_css = 'bottom:'+(settings.bot_minus+33)+'px;';
  846. dn_btn_css = 'margin-bottom:-33px;';
  847. } else if (settings.position == 'middle') {
  848. updn_btn_css = 'bottom:50%;';
  849. dn_btn_css = 'margin-bottom:-33px;';
  850. }
  851.  
  852. btn_css += '#up_btn { position:fixed; right:-33px; z-index:54000; height:36px; width:33px; display:inline; cursor:pointer; background:url('+up_btn_src+') no-repeat scroll 50% 50% rgba(0, 0, 0, 0.7); }';
  853. btn_css += '#dn_btn { position:fixed; right:-33px; z-index:54000; height:36px; width:33px; display:inline; cursor:pointer; '+dn_btn_css+'background:url('+dn_btn_src+') no-repeat scroll 50% 50% rgba(0, 0, 0, 0.7); }';
  854. btn_css += '.updn_btn { '+updn_btn_css+'opacity:0.65; } .isfullscreen > .updn_btn { display:none;}';
  855. btn_css += '.sssettings button:hover {opacity:0.85;} .updn_btn:hover { opacity:1; } .sssettings button[disabled], .sssettings button[disabled]:hover { opacity:0.35;} ';
  856. btn_css += '.sssettings span button:hover:enabled {line-height: 1.4 !important; width: 10px !important;} .sssettings .ignores button[disabled] + span { opacity:0.5;} .sssettings .addable button + span { opacity:0.5;} .sssettings .addable button[disabled] + span { opacity:1;}';
  857.  
  858. if (settings.bottomless_pages) {
  859. btn_css += 'iframe.resize_frame {position: absolute; display: block ;top: 0; bottom: 0; left: 0; height: 100%; opacity: 0; z-index: 0; width: 0; border: 0; background-color: transparent;}';
  860. if ('contentType' in document) { // Firefox
  861. if (document.contentType.indexOf("image") ==-1) {
  862. btn_css += 'body {position:relative !important;} body.isfullscreen {position:initial !important;}';
  863. }
  864. }
  865. else {
  866. btn_css += 'body {position:relative !important;} body.isfullscreen {position:initial !important;}';
  867. }
  868. }
  869.  
  870. return btn_css;
  871.  
  872. },
  873. scrolledUpdate: function(e) {
  874.  
  875. if (buttons.count_accru > 1000 || e === true) {
  876. buttons.initSettings({name: "count"});
  877. }
  878. window.setTimeout(buttons.scrolledUpdate, 120000);
  879.  
  880. },
  881. resetButtons: function (e) {
  882.  
  883. buttons.allowScroll = true;
  884. buttons.up_btn_show = "";
  885. buttons.dn_btn_show = "";
  886. buttons.getDocumentHeight(e);
  887. buttons.crawl_speed_ms = Math.round(200 / buttons.user.settings.crawl_speed);
  888.  
  889. },
  890. syncGM_getValue: function (e) {
  891.  
  892. if (e.detail.setting == 'settings') {
  893. buttons.initSettings(e.detail);
  894. }
  895. else if (e.detail.setting == 'count') {
  896. if (e.detail.value && e.detail.value != "{}") {
  897. buttons.saveSettings({name: "count", value: JSON.parse(e.detail.value)});
  898. }
  899. }
  900.  
  901. },
  902. initSettings: function (detail) {
  903.  
  904. if (typeof detail.name != 'undefined') {
  905. this.GM.getValue(detail.name, "{}").then(function (value) {
  906.  
  907. var details = {
  908. detail: {
  909. setting: detail.name,
  910. value: value || "{}"
  911. }
  912. };
  913.  
  914. try{
  915. buttons.syncGM_getValue(details);
  916. }
  917. catch (e) {
  918. console.warn( 'Smart Scroll: UPDATE Your Browser ',e.name );
  919. }
  920. });
  921.  
  922. }
  923. else {
  924.  
  925. var settings,
  926. setting = detail.setting,
  927. value = detail.value;
  928.  
  929. if (! value || value == "{}") {
  930. settings = false;
  931. console.warn( 'Smart Scroll: NO storage database');
  932. }
  933. else {
  934. settings = JSON.parse(value);
  935. //console.log( 'Smart Scroll: Initializing settings from storage database');
  936. }
  937.  
  938. if (! settings) {
  939. settings = this.user;
  940. console.log( 'Smart Scroll: Installing storage database...' );
  941. for (let k in settings) {
  942. let jstr = JSON.stringify(settings[k]);
  943.  
  944. this.GM.setValue(k, jstr);
  945. console.log( 'Smart Scroll: Inserting '+k+': '+ jstr);
  946. }
  947. settings = this.user.settings;
  948. console.log( 'Smart Scroll: dONE' );
  949. }
  950. this.user.settings = settings;
  951. this.scrolledUpdate(true);
  952. this.monkey();
  953. this.monkey = null;
  954. }
  955.  
  956. },
  957. init: function () {
  958.  
  959. if (typeof GM_info === "object" || typeof GM === "object") {
  960. this.is_userscript = true;
  961. if (typeof GM === "undefined") {
  962. console.log( 'Smart Scroll: Legacy GM_setValue enabled' );
  963. this.GM = {
  964. info: GM_info,
  965. setValue: GM_setValue,
  966. getValue: function () {
  967. return new Promise( (resolve, reject) => {
  968. try {
  969. resolve(GM_getValue.apply(this, arguments));
  970. }
  971. catch (e) { reject(e) }
  972. });
  973. }
  974. };
  975. }
  976. else { this.GM = GM; }
  977.  
  978. var outerscroll = document.createElement("div");
  979. var innerscroll = document.createElement("div");
  980.  
  981. outerscroll.style = "position:absolute;top:0px;background-color:transparent;";
  982. innerscroll.style = "height:"+ (window.innerHeight - 100) +"px;width:100px;overflow:scroll;background-color:transparent;";
  983. this.body.appendChild(outerscroll);
  984. outerscroll.appendChild(innerscroll);
  985. let h1 = innerscroll.scrollHeight;
  986. innerscroll.style.overflow = 'hidden';
  987. let h2 = innerscroll.scrollHeight;
  988. this.scrollbar = h2 - h1;
  989. innerscroll.remove();
  990. outerscroll.remove();
  991.  
  992. this.initSettings({name: "settings"});
  993. }
  994.  
  995. },
  996. head: document.head || document.getElementsByTagName('head')[0],
  997. body: document.body || document.documentElement,
  998. user: {
  999. settings: {
  1000. bottomless_pages: true,
  1001. crawl_trigger: 'hover',
  1002. position: 'bottom',
  1003. dimButtons: true,
  1004. crawl_speed: 21,
  1005. refresh: true,
  1006. bot_minus: 30,
  1007. top_plus: 0,
  1008. ignore: ''
  1009. },
  1010. count: 0
  1011. },
  1012. crawl_speed_ms: 10,
  1013. opacity_timer: null,
  1014. allowScroll: true,
  1015. settings_id: "",
  1016. up_btn_show: "",
  1017. dn_btn_show: "",
  1018. count_accru: 0,
  1019. scrollable: 0,
  1020. scrollbar: 0,
  1021. scrolled: 0,
  1022. creeper: null,
  1023. up_ctn: null,
  1024. dn_ctn: null,
  1025. creep: !1,
  1026. step: 5,
  1027. GM: null,
  1028. _x: 0
  1029. };
  1030.  
  1031. var _once = 0;
  1032. var up_btn_src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAkCAQAAACtIJtXAAAAAmJLR0QA/vCI/CkAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfiDBkQOCqvuzNgAAABWElEQVRIx6XWO7aDIBCA4V+OWYOaVbiDFGlccopkD/Sp0qiswcJb+ODhgNwjXXh8DpFhLKa558uVVvxmuF8iyi8PcWBkCHoaapmILTdA5fQZDJXIlPHl/vSlX2LKENDCcoCaemdab7Q8Am1kzxuj0d4clQ9sTAtoxiORB0jITgyZg'+
  1033. 'EUGnxgxVJnAglSYNQ5lY2iEqR03bnTCSLPHoVIxdHwA+AiIjUPFY9iAGLLFsW7kGIMLyEi9JoCS/64QiEUSJVzgyfMEUWfAi9cJIhA+AARI1kZ8IEQihHHS5n0AXOTtpKWxyd5gGPbX+mASn/YKfm+nSYUnPrfZE63CE5/b7IlWx8z7XwzOG2mCuygNaCerVPxCSwP2elKpWzEHCG7wmhaNjpQcW2MSRWBB5JITK1FCNXNLjl8QyS2ILuO2KlWWe/HjoM6+z4vffO0DBco7V1sB09xfIv4A9ICG7qoP1KkAAAAASUVORK5CYII=';
  1034. var dn_btn_src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAkCAQAAACtIJtXAAAAAmJLR0QA/vCI/CkAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfiDBkRAC0ngnAPAAABV0lEQVRIx6XWO5KDMAyA4R8PnAHIKbjBFtkiR06TIjdwnyoN4DOkYAsClm2Z8Q4q/fhGgGxRfZaRF2eiei9wOUXUL37UiZkpGunpdCK33QGtGHM4WpWp89vD5eu4xtQxYJXtAB3dzgzBbJ0CQ+aZN8ZigzWmHNiYAbDMKVEGaMhOT'+
  1035. 'IWAR6aQmHG0hcCKtLhvHsbn0P+rJvs9D5Pm8KSh4ZZsutHQ8EzyMGkOvwA8IuTGQ8zKPL4Por0HiWxA/D6iutjimiASuCbrFeIeISFwLyFi5BjIECFyDGSJFMkBO+HEsdEQDZhxnuhFxWuInsFWTbWstE5BcuEr2sQVXxq+ok168kpCniojK94WIuv11McfNb3QjgF/PZmjW7EEiG7wjgGLzbQc32MOmsCK6C0n16KUbiZbTtgQKW2IkpHRHrXlUf056Irv8+q9nPtBgfrC2ajgs4yniD+XioU/GQ3iSgAAAABJRU5ErkJggg==';
  1036. var root = buttons.body;
  1037. var host = window.location.hostname;
  1038. /* Not in Frames */
  1039. if (window.self == window.top) {
  1040. switch(true) {
  1041. /* Special case sites */
  1042. case host.indexOf('youtube') !=-1 :
  1043. buttons.hideOnFullScreen();
  1044. window.addEventListener("yt-navigate-finish", function(e) { buttons.reLoadStart(e) }, false);
  1045. /* body remains 0 height propter full-screen styling */
  1046. if (root = document.querySelector("ytd-app #content")) {
  1047. buttons.init();
  1048. }
  1049. else {
  1050. buttons.body.addEventListener('yt-page-data-updated', function(e) {
  1051. if (root = document.querySelector("ytd-app #content")) {
  1052. if (_once++ < 1) buttons.init();
  1053. }
  1054. }, false);
  1055. }
  1056. break;
  1057. default: buttons.init();
  1058. }
  1059. }
  1060. }());