Guest User

Untitled

a guest
May 20th, 2016
101
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 48.57 KB | None | 0 0
  1. /*global content,Components,addMessageListener,sendAsyncMessage*/
  2. var yass = {
  3.  
  4. m_pref: {},
  5. m_prefservice: Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch),
  6. m_consoleservice: Components.classes["@mozilla.org/consoleservice;1"].getService(Components.interfaces.nsIConsoleService),
  7. m_sobj: null,
  8. m_jumpto: 0,
  9. m_wheelactive: false,
  10. m_lastfunctime: 0,
  11. m_lastaccel: 1.0,
  12. m_lasteventtime: (new Date()).getTime(),
  13. m_lasteventtime_vtp: 0,
  14. m_speed: 0.0001,
  15. m_lastcheckdesignmodearg: null,
  16. m_keyenable: true,
  17. m_keyscrolltarget: null,
  18. m_clickedtarget: null,
  19. m_mousescrolltarget: null,
  20. m_mousemoved: [-100000, -100000],
  21. m_edgesize: 54,
  22. m_sumpixelscroll: 0,
  23. m_jumptoremain: 0,
  24. m_lastdocument: null,
  25. m_ticksstack: [],
  26. m_timer: Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer),
  27. m_mousebuttonstate: false,
  28.  
  29. oneshot: function(func, delay) {
  30. this.m_timer.initWithCallback(func, delay, 0);
  31. },
  32.  
  33. range: function(t, min, max) {
  34. return (t < min) ? min : ((t > max) ? max : t);
  35. },
  36.  
  37. dump: function(s) {
  38. if (this.m_pref.dolog) this.m_consoleservice.logStringMessage(s);
  39. },
  40.  
  41. bouncyEdgeSize: function() {
  42. return Math.min(this.m_sobj.body.clientHeight * 0.2, this.m_edgesize);
  43. },
  44.  
  45. m_virtualtrackpad: {
  46. m_timer: Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer),
  47. m_running: false,
  48. m_step: 0,
  49. m_reset: false,
  50. m_lastinstep: 0,
  51. m_lastinstep_cur: 0,
  52.  
  53. oneshot: function(func, delay) {
  54. this.m_timer.initWithCallback(func, delay, 0);
  55. },
  56.  
  57. startvirtualtrackpad: function(step, time) {
  58. this.m_reset = true;
  59. //yass.dump("" + step + "/" + time + " ");
  60. if (time > 30) return; // too big gap of time
  61. var laststep = this.m_lastinstep;
  62. var absstep = Math.abs(step);
  63. if (laststep + 50 < absstep) return; // ignore big positive gap
  64. // calcurate average from remaining 3 items
  65. if (absstep < 30) {
  66. this.m_step = 0; // step too small to determine as flick
  67. }
  68. else if (laststep < absstep) {
  69. //yass.dump(" flick ");
  70. this.m_step = step;
  71. if (this.m_running == false) this.virtualtrackpad();
  72. }
  73.  
  74. // save current step
  75. this.m_lastinstep = absstep;
  76. },
  77.  
  78. virtualtrackpad: function() {
  79. this.m_running = true;
  80. if (!this.m_reset) {
  81. this.m_step *= 0.94;
  82. yass.handleEvent({
  83. type: "MozMousePixelScroll",
  84. detail: this.m_step,
  85. preventDefault: function() {},
  86. stopPropagation: function() {},
  87. generated: true
  88. });
  89. }
  90. //yass.dump("trackpad " + this.m_vtp_step + "\n");
  91. if (Math.abs(this.m_step) < 1 || (yass.m_sobj && yass.m_sobj.offset != 0)) {
  92. this.m_running = false;
  93. return;
  94. }
  95. this.m_reset = false;
  96. this.oneshot(function() {
  97. yass.m_virtualtrackpad.virtualtrackpad();
  98. }, 10);
  99. }
  100. },
  101.  
  102. urgeRefreshTarget: function() {
  103. this.m_mousescrolltarget = null;
  104. this.m_keyscrolltarget = null;
  105. this.m_clickedtarget = null;
  106. },
  107.  
  108. // check document consistency and commit full reset if false
  109. checkDocumentOfEvent: function(ev) {
  110. if (ev.originalTarget.ownerDocument != this.m_lastdocument) {
  111. // full reset
  112. this.refreshTarget(null, null);
  113. this.m_lastcheckdesignmodearg = null;
  114. this.urgeRefreshTarget();
  115. this.checkDesignMode(ev);
  116. this.checkBlackList(ev.originalTarget.baseURI);
  117. this.m_lastdocument = ev.originalTarget.ownerDocument;
  118. }
  119. },
  120.  
  121. checkTickWheel: function(d) {
  122. if (this.m_ticksstack == null) return;
  123. if (this.m_sobj == null) return; // on no scrollable area and on xul(about:blank), ev.detail is not normal value
  124. this.m_ticksstack.push(Math.abs(d));
  125. if (this.m_ticksstack.length < 10) return;
  126. // pick lowest delta value
  127. var tickwheel = 99999;
  128. for (var i in this.m_ticksstack) {
  129. if (this.m_ticksstack[i] < tickwheel) tickwheel = this.m_ticksstack[i];
  130. }
  131. if (tickwheel < 28) tickwheel = 28;
  132. sendAsyncMessage("YASmoothScrolling@kataho:set_tickwheel", { tickwheel: tickwheel });
  133. this.dump("yass:tickwheel set to " + tickwheel);
  134. this.m_pref.tickwheel = tickwheel;
  135. this.m_ticksstack = null;
  136. },
  137.  
  138. handleEvent: function(ev) {
  139. if (!this.m_pref.enabled) return;
  140. if (ev.altKey || ev.ctrlKey || (ev.keyCode != 32 && ev.shiftKey)) return;
  141.  
  142. var fromkeyboard = false;
  143.  
  144. var mozscrollstep = 0;
  145.  
  146. var ev_detail = ev.detail;
  147.  
  148. var ctm = (new Date()).getTime();
  149.  
  150. switch (ev.type) {
  151. case "wheel":
  152. ev_detail = ev.deltaY * [1.0, 28.0, 500.0][ev.deltaMode];
  153. //this.dump("DX:" + ev.deltaX + " DY:" + ev.deltaY + " " + ev.deltaMode);
  154. var wheeldeltax = ev.deltaX * [1.0, 28.0, 500.0][ev.deltaMode];
  155. if (Math.abs(ev_detail) < Math.abs(wheeldeltax)) return;
  156. case "MozMousePixelScroll": // eslint-disable-line no-fallthrough
  157. if (this.m_mousebuttonstate) return;
  158. mozscrollstep = mozscrollstep || (ev_detail * (this.m_pref.wheelstep / this.m_pref.tickwheel));
  159. //case "DOMMouseScroll":
  160. // this makes iframe mouse cursor scrolled in immediatly a scroll target (chrome like behavior)
  161. // but this is firefox and it causes unexpected speed reset when passing over unscrollable iframe (ex. banners of ads)
  162. //this.checkDocumentOfEvent(ev);
  163. if (ev.axis && ev.axis == ev.HORIZONTAL_AXIS) return; // handle only vertical events
  164. this.m_keyscrolltarget = null;
  165. var mousex = ev.screenX - this.m_mousemoved[0];
  166. var mousey = ev.screenY - this.m_mousemoved[1];
  167. if ((mousex * mousex) + (mousey * mousey) >= 16 || this.m_mousescrolltarget == null) {
  168. this.m_mousescrolltarget = ev.originalTarget;
  169. this.m_mousemoved = [ev.screenX, ev.screenY];
  170. this.refreshTarget(ev.originalTarget, ev_detail);
  171. }
  172. this.checkTickWheel(ev_detail);
  173. //this.dump("MEV:" + ev_detail + " ");
  174. //if (wheeldeltax != 0 && this.m_sobj) {
  175. // this.m_sobj.body.scrollLeft += wheeldeltax;
  176. //}
  177. break;
  178.  
  179. case "keydown":
  180. var spacekey = false;
  181. switch (ev.keyCode) {
  182. case 38:
  183. ev_detail = -1;
  184. break;
  185. case 40:
  186. ev_detail = 1;
  187. break;
  188. case 33:
  189. ev_detail = -2;
  190. break;
  191. case 34:
  192. ev_detail = 2;
  193. break;
  194. case 35:
  195. ev_detail = 3;
  196. break;
  197. case 36:
  198. ev_detail = -3;
  199. break;
  200. case 32:
  201. ev_detail = (ev.shiftKey) ? -2 : 2;
  202. spacekey = (ev.shiftKey) ? false : true;
  203. break;
  204. default:
  205. // mainly for google reader shortcut issue
  206. this.refreshTarget(null, null);
  207. this.m_mousescrolltarget = null;
  208. return;
  209. }
  210. var detailsq_ = ev_detail * ev_detail;
  211. if (this.m_pref.usekbd == false && detailsq_ == 1) return;
  212. if (this.m_pref.usepagejump == false && detailsq_ == 4) return;
  213. if (this.m_pref.usewholejump == false && detailsq_ == 9) return;
  214.  
  215. this.checkDocumentOfEvent(ev);
  216. this.checkDesignMode(ev);
  217. if (this.m_keyenable == false) return;
  218. if (this.m_keyscrolltarget == null || this.m_sobj == null || this.m_clickedtarget != null) {
  219. var t = this.m_clickedtarget ? this.m_clickedtarget : ev.originalTarget;
  220. this.refreshTarget(t, ev_detail);
  221. this.m_keyscrolltarget = ev.originalTarget;
  222. }
  223.  
  224. var tagname = ev.target.tagName.toLowerCase();
  225. yass.dump("key target tagname=" + tagname);
  226. if (tagname == "input") {
  227. if (spacekey) return;
  228. var typeattr = (ev.target.getAttribute("type")) ? ev.target.getAttribute("type").toLowerCase() : "text";
  229. if (/^(text|search|password|url|tel|email|datetime|date|month|week|time|datetime-local|number|color|range|radio)$/.test(typeattr)) return;
  230. }
  231. if (/^(select|textarea|embed|object|audio|video)$/.test(tagname)) return;
  232.  
  233. fromkeyboard = true;
  234. this.m_mousescrolltarget = null;
  235. this.m_clickedtarget = null;
  236. break;
  237.  
  238. case "mousedown":
  239. if (ev.button == 2) this.m_mousebuttonstate = true;
  240. this.m_clickedtarget = ev.target;
  241. if (this.m_sobj && this.m_sobj.offset / this.m_lastd < 0) return;
  242. this.m_jumpto = this.m_vpos;
  243. return;
  244.  
  245. case "mouseup":
  246. this.m_mousebuttonstate = false;
  247. return;
  248.  
  249. case "DOMContentLoaded":
  250. case "unload":
  251. case "resize":
  252. this.urgeRefreshTarget();
  253. return;
  254.  
  255. default:
  256. return;
  257. }
  258.  
  259. if (this.m_pref.blacklist_hit == true) return;
  260.  
  261. if (!this.m_sobj) return;
  262.  
  263. ev.preventDefault();
  264.  
  265. if (ev_detail == 0) return; // maybe this fixes microsoft smooth wheel problem
  266.  
  267. // ignore events in edge bounce animation
  268. // for MacOS native flick
  269. if (mozscrollstep != 0 && this.m_edgesize != 0) {
  270. if (ctm - this.m_lasteventtime <= 200) {
  271. if (((this.m_sobj.offset < 0 || this.m_vpos < 5) && mozscrollstep < 0) ||
  272. ((this.m_sobj.offset > 0 || this.m_vpos > this.m_sobj.maxscroll - 5) && mozscrollstep > 0)) {
  273. this.m_lasteventtime = ctm;
  274. return;
  275. }
  276. }
  277. }
  278.  
  279. var detailsq = ev_detail * ev_detail;
  280. var pagescroll = (detailsq == 4);
  281. var wholepagescroll = (detailsq == 9);
  282.  
  283. var evtime = this.range((ctm - this.m_lasteventtime), 1, 1500);
  284. this.m_sumpixelscroll += Math.abs(mozscrollstep);
  285. var speed = 0.24 * (this.m_sumpixelscroll / this.m_pref.wheelstep / evtime); // distance(ticks) / time
  286. this.m_speed *= 1.0 - this.range(((evtime - 100) / 800), 0, 0.9999); // speed loss
  287. this.m_speed = Math.max(this.m_speed, speed);
  288. //yass.dump("e deta:" + ev_detail + " time:" + evtime + " sum:" + this.m_sumpixelscroll +
  289. // " speed:" + Math.round(this.m_speed * 100000));
  290.  
  291. var edgemargin = (0.64 / (fromkeyboard ? this.m_pref.kbddumping : this.m_pref.wheeldumping)) + ((this.m_edgesize == 0) ? 2 : 0);
  292. var edgelimit = this.bouncyEdgeSize() + edgemargin + 25;
  293.  
  294. // branch for pixel scroller
  295. // set "step" and "this.m_lasteventtime"
  296. var step = 0;
  297. if (mozscrollstep != 0) {
  298. step = Math.abs(mozscrollstep);
  299. var p = 300;
  300. if (this.m_pref.useflickemulation) {
  301. if (!("generated" in ev)) {
  302. this.m_virtualtrackpad.startvirtualtrackpad(mozscrollstep, ctm - this.m_lasteventtime_vtp);
  303. this.m_lasteventtime_vtp = ctm;
  304. }
  305. }
  306. if (this.m_sumpixelscroll >= p) {
  307. this.m_sumpixelscroll = Math.round(this.m_sumpixelscroll / 11);
  308. this.m_lasteventtime = ctm - Math.round(evtime / 11);
  309. }
  310. }
  311. else {
  312. // branch of step
  313. step =
  314. (fromkeyboard) ?
  315. ((pagescroll) ?
  316. Math.max(0, this.m_sobj.body.clientHeight - this.m_pref.pagemargin) :
  317. ((wholepagescroll) ?
  318. (this.m_sobj.maxscroll + 100) :
  319. this.m_pref.kbdstep)) :
  320. this.m_pref.wheelstep;
  321.  
  322. this.m_lasteventtime = ctm;
  323. }
  324.  
  325. var delta = step * ((ev_detail < 0) ? -1 : 1);
  326.  
  327. if (!this.m_wheelactive) {
  328. // actually we shold know scroll height change asap and refrect to m_sobj.maxscroll
  329. // changing scroll target's (most case it is body) "overflow" to hidden,fixed implesitly makes scrollHeight to 0
  330. // few pages (facebook) make scrolling target's "overflow" to fixed for preventing scrolling when showing modal dialog
  331. this.m_sobj.refreshmaxscroll();
  332. this.m_beginsmoothtime = ctm;
  333. this.m_resetsmooth = 0;
  334. this.m_lastd = 0;
  335. // something special power prevents scrollTop to be just 1pixel up so
  336. this.m_sobj.body.scrollTop = (this.m_sobj.body.scrollTop - ((ev_detail < 0) ? 1.0000001 : -1));
  337. this.m_jumpto = this.m_sobj.body.scrollTop - 0 + delta + ((ev_detail * this.m_jumptoremain > 0) ? this.m_jumptoremain : 0);
  338. this.m_jumpto = this.range(this.m_jumpto, -edgelimit, this.m_sobj.maxscroll + edgelimit);
  339. this.m_jumptoremain = 0;
  340. this.m_wheelactive = true;
  341. this.m_lastscrolltop = this.m_sobj.body.scrollTop;
  342. this.m_lastfunctime = (new Date()).getTime() - 17;
  343. this.m_vpos = this.m_sobj.body.scrollTop;
  344. this.funcwheel(fromkeyboard, delta, edgemargin);
  345. }
  346. else {
  347. this.m_resetsmooth = 1;
  348.  
  349. var accel = 1.0;
  350.  
  351. if (fromkeyboard) {
  352. if (!pagescroll) accel = this.m_pref.kbdaccel / 100;
  353. }
  354. else {
  355. if (this.m_sobj.offset == 0 && this.m_lastd * ev_detail < 0) {
  356. this.m_jumpto += (this.m_vpos - this.m_jumpto) * 0.92;
  357. return;
  358. }
  359. accel = this.range(this.m_pref.wheelaccel * this.m_speed, 1.0, 30.0);
  360. }
  361. this.m_jumpto += delta * accel;
  362. this.m_jumpto = this.range(this.m_jumpto, -edgelimit, this.m_sobj.maxscroll + edgelimit);
  363. }
  364. },
  365.  
  366. // class scroller that have no edge element
  367. ScrollerNoEdge: (function() {
  368. var F = function(orig, b, type, w, h, log) {
  369. this.target = orig;
  370. this.body = b;
  371. this.scrolltype = type;
  372. this.width = w;
  373. this.height = h;
  374. this.log = log;
  375. this.offset = 0;
  376. };
  377. F.prototype = {
  378. activate: function() {
  379. this.etop = yass.edgetop;
  380. this.ebot = yass.edgebot;
  381. this.innerframe = (this.body.ownerDocument.defaultView.frameElement) ? true : false;
  382. this.maxscroll = this.body.scrollHeight - this.body.clientHeight;
  383. },
  384. adjust: function(newp, oldp) {
  385. // adjust maxscroll
  386. var scrollsize = this.body.scrollHeight - this.body.clientHeight;
  387. if (scrollsize != this.maxscroll) this.maxscroll = scrollsize;
  388. if (this.maxscroll == 0) return false;
  389. // on the edge - must be stopped explicitly
  390. if (this.body.scrollTop == 0 || this.body.scrollTop == this.maxscroll) return false;
  391. return true;
  392. },
  393. scrollovercheck: function(hint) {
  394. yass.dump("yass - must not be called.");
  395. return false;
  396. },
  397. stop: function() {},
  398. release: function() {},
  399. render: function(offsetscroll, pos) {
  400. this.body.scrollTop = pos;
  401. },
  402. restoreedges: function() {},
  403. refreshmaxscroll: function() {
  404. this.maxscroll = this.body.scrollHeight - this.body.clientHeight;
  405. }
  406. };
  407. return F;
  408. })(),
  409.  
  410. // class scroller
  411. Scroller: (function() {
  412. var F = function(orig, b, type, w, h, log) {
  413. this.target = orig;
  414. this.body = b;
  415. this.scrolltype = type;
  416. this.width = w;
  417. this.height = h;
  418. this.log = log;
  419. this.offset = 0;
  420. };
  421. F.prototype = {
  422. activate: function() {
  423. this.etop = yass.edgetop;
  424. this.ebot = yass.edgebot;
  425. this.body._yass_ownedby = this;
  426. this.offset = 0;
  427. var h0 = this.ebot.setowner(this.body);
  428. var h1 = this.etop.setowner(this.body);
  429. this.innerframe = (this.body.ownerDocument.defaultView.frameElement) ? true : false;
  430. this.maxscroll = this.body.scrollHeight - this.body.clientHeight - h0 - h1;
  431. },
  432. refreshmaxscroll: function() {
  433. this.maxscroll = this.body.scrollHeight - this.body.clientHeight;
  434. },
  435. adjust: function(newp, oldp) {
  436. // adjust maxscroll
  437. var scrollsize = this.body.scrollHeight - this.body.clientHeight - this.ebot.e.clientHeight - this.etop.e.clientHeight;
  438. if (scrollsize != this.maxscroll) {
  439. // there are evil pages that have 100% height child or absolutely positioned child. scrollHeight not be changed by making botedge height changed
  440. // bot edge's height change changes maxscroll - emergency stop
  441. if (this._lastscrollheight == this.body.scrollHeight && newp > this.maxscroll) return false;
  442. this.maxscroll = scrollsize;
  443. }
  444. this._lastscrollheight = this.body.scrollHeight;
  445. if (this.maxscroll <= 0) return false; // fixed previous "==" which causes bouncing back/foreward forever bug
  446.  
  447. // when entering top edge
  448. if (oldp >= 0 && newp < 0) {
  449. this.etop.adjust(this.ebot);
  450. }
  451. // when entering bottom edge
  452. else if (oldp <= this.maxscroll && newp > this.maxscroll) {
  453. this.ebot.adjust();
  454. }
  455.  
  456. return true;
  457. },
  458. scrollovercheck: function(hint) {
  459. if (this.offset == 0) {
  460. return (
  461. (hint > 0 && this.body.scrollTop < this.maxscroll) ||
  462. (hint < 0 && this.body.scrollTop > 0));
  463. }
  464. else {
  465. return !((this.offset > 0 && hint > 0) || (this.offset < 0 && hint < 0));
  466. }
  467. },
  468. stop: function() {
  469. this.etop.e.style.height = "0px";
  470. this.ebot.e.style.height = "0px";
  471. this.etop.render_abs(0);
  472. if (this.offset < 0) this.body.scrollTop = 0;
  473. this.offset = 0;
  474. },
  475. release: function() {
  476. // if document is already closed, accessing dead object exception thrown (Firefox15beta)
  477. try {
  478. var x = this.etop.e.style; // eslint-disable-line no-unused-vars
  479. this.stop();
  480. }
  481. catch (e) {}
  482. try {
  483. if (this.body && this.body._yass_ownedby == this) this.body._yass_ownedby = null;
  484. }
  485. catch (e) {}
  486. this.etop.e = null;
  487. this.ebot.e = null;
  488. this.body = null;
  489. },
  490. // realize virtual offset
  491. render: function(offsetscroll, pos) {
  492. this.offset = offsetscroll;
  493. if (offsetscroll < 0) {
  494. offsetscroll = -offsetscroll; // invert
  495. var h = this.etop.e.clientHeight;
  496. if (h < offsetscroll) h += 64;
  497. this.etop.render_abs(h);
  498. this.etop.e.style.height = h + "px";
  499. this.body.scrollTop = h - offsetscroll;
  500. }
  501. else if (offsetscroll > 0) {
  502. if (this.ebot.e.clientHeight < offsetscroll) this.ebot.e.style.height = (offsetscroll + 50) + "px";
  503. this.body.scrollTop = this.maxscroll + offsetscroll;
  504. }
  505. else {
  506. this.etop.e.style.height =
  507. this.ebot.e.style.height = "0px";
  508. this.etop.render_abs(0);
  509. this.body.scrollTop = pos;
  510. }
  511. }
  512. };
  513. return F;
  514. })(),
  515.  
  516. // edgetop object extends div element
  517. edgetop: {
  518. e: null,
  519. dummy: null,
  520. epadding: null,
  521.  
  522. eorig: function(doc) {
  523. var e = null;
  524. if ((e = doc.getElementById("yass_top_edge"))) return e;
  525. e = doc.createElement("div");
  526. e.style.backgroundImage = "url(chrome://yass/content/edgebgtop.png)";
  527. e.style.backgroundAttachment =
  528. e.style.backgroundAttachment = "scroll";
  529. e.style.backgroundPosition = "bottom";
  530. e.style.height =
  531. e.style.borderWidth =
  532. e.style.margin =
  533. e.style.padding = "0px";
  534. e.style.display = "block";
  535. //e.style.postion = "absolute";
  536. //e.style.left = e.style.top = "0px";
  537. e.setAttribute("id", "yass_top_edge");
  538. return e;
  539. },
  540.  
  541. dummyorig: function(doc) {
  542. var e = null;
  543. if ((e = doc.getElementById("yass_top_edge_dummy"))) return e;
  544. e = doc.createElement("div");
  545. e.style.height = e.style.width = "1px";
  546. e.style.borderWidth =
  547. e.style.margin =
  548. e.style.padding = "0px";
  549. e.style.display = "block";
  550. //e.style.postion = "absolute";
  551. //e.style.left = e.style.top = "0px";
  552. e.setAttribute("id", "yass_top_edge_dummy");
  553. return e;
  554. },
  555.  
  556. epaddingorig: function(doc) {
  557. var e = null;
  558. if ((e = doc.getElementById("yass_top_edge_padding"))) return e;
  559. e = doc.createElement("div");
  560. e.style.height =
  561. e.style.borderWidth =
  562. e.style.margin =
  563. e.style.padding = "0px";
  564. e.style.display = "block";
  565. e.setAttribute("id", "yass_top_edge_padding");
  566. return e;
  567. },
  568.  
  569. _owner: null,
  570.  
  571. setowner: function(owner) {
  572. this.e = this.eorig(owner.ownerDocument);
  573. this.dummy = this.dummyorig(owner.ownerDocument);
  574. this.epadding = this.epaddingorig(owner.ownerDocument);
  575. // edges must be inserted inside of body not html even if html is scrollable
  576. // body may return frameset but owner must be scrollable something inside of frame, so it must not be, as far as here.
  577. owner = (owner == owner.ownerDocument.documentElement) ? owner.ownerDocument.body : owner;
  578. if (this._owner == owner || this.e == owner) return this.e.clientHeight;
  579. if (this._owner) {
  580. try {
  581. this._owner.removeChild(this.e);
  582. this._owner.removeChild(this.dummy);
  583. this._owner.removeChild(this.epadding);
  584. if (this._ancientnode) this._ancientnode.style.marginTop = this._ancientnode_marginback; // restore offset - must be tested
  585. }
  586. catch (ex) {}
  587. }
  588. this.abselms = [];
  589. this.e.style.height = "0px";
  590. this.e.style.marginBottom = "0px";
  591. try {
  592. this.epadding.style.padding = "0px";
  593. }
  594. catch (ex) {}
  595. this._owner = owner;
  596. this._ancientnode = null;
  597. this._paddingback = owner.style.paddingTop;
  598. // detect body margin size
  599. var bodymargintop = 0;
  600. var bodypaddingtop = 0;
  601. var bodymarginleft = 0;
  602. this._widthtarget = owner;
  603. var s; // local computed style
  604. var i; // index of elements
  605. var e; // an element
  606. if (owner == owner.ownerDocument.body) {
  607. s = owner.ownerDocument.defaultView.getComputedStyle(owner, null);
  608. bodymargintop = s.getPropertyCSSValue("margin-top").getFloatValue(5); // as pixels
  609. bodypaddingtop = s.getPropertyCSSValue("padding-top").getFloatValue(5); // as pixels
  610. bodymarginleft = Math.max(0, ((owner.parentNode.clientWidth - owner.offsetWidth) / 2)); // this way can get correct margin in case margin:0 auto
  611. this._widthtarget = owner.ownerDocument.documentElement;
  612. this._ancientnode = owner.ownerDocument.querySelector(
  613. "body>p:-moz-first-node,body>dl:-moz-first-node,body>multicol:-moz-first-node,body>blockquote:-moz-first-node," +
  614. "body>h1:-moz-first-node,body>h2:-moz-first-node,body>h3:-moz-first-node,body>h4:-moz-first-node,body>h5:-moz-first-node," +
  615. "body>h6:-moz-first-node,body>listing:-moz-first-node,body>plaintext:-moz-first-node,body>xmp:-moz-first-node," +
  616. "body>pre:-moz-first-node,body>ul:-moz-first-node,body>menu:-moz-first-node,body>dir:-moz-first-node,body>ol:-moz-first-node"
  617. ); // compatible only with 3.5 and later versions
  618. // put dummy div for negate first node offset hack
  619. if (this._ancientnode) {
  620. // check style for display:noe
  621. var astyle = owner.ownerDocument.defaultView.getComputedStyle(this._ancientnode, null);
  622. if (astyle.getPropertyCSSValue("display").cssText == "none") this._ancientnode = null;
  623. if (astyle.getPropertyCSSValue("margin-top").getFloatValue(5) != 0) this._ancientnode = null;
  624. }
  625. if (this._ancientnode) {
  626. this._ancientnode_marginback = this._ancientnode.style.marginTop;
  627. this._ancientnode.style.marginTop = bodymargintop + "px";
  628. }
  629. else {
  630. // apply bodymargin to dummy element
  631. this.e.style.marginBottom = bodymargintop + "px";
  632. }
  633. }
  634. // collect absolute elements
  635. var elms = owner.children;
  636. // algorithm 1: search for immediate children consider case of inline style
  637. for (i = 0; i < elms.length; i++) {
  638. e = elms[i];
  639. if (e === undefined) continue;
  640. if (e.nodeName === undefined) continue;
  641. if (e.nodeName.toLowerCase() != "div") continue;
  642. if (e.id == "yass_bottom_edge") continue;
  643. s = e.ownerDocument.defaultView.getComputedStyle(e, null);
  644. if (s.getPropertyCSSValue("position").cssText == "absolute") {
  645. try {
  646. this.abselms.push([e, s.getPropertyCSSValue("top").getFloatValue(5)]);
  647. }
  648. catch (ex) {}
  649. }
  650. }
  651. // algorithm 2: (new!) search for "absolute" in DOM stylesheet and query with those selectors of rules found
  652. var regexpAbsolute = /position\s*:\s*absolute/;
  653. var selectorsAbsolute = [];
  654. for (var sindex = 0; sindex < content.document.styleSheets.length; sindex++) {
  655. var sheet = content.document.styleSheets[sindex];
  656. if (!sheet.cssRules) continue;
  657. var rstack = [{r: sheet.cssRules, i: 0}];
  658. while (rstack.length > 0) {
  659. var rules = rstack[0];
  660. if (rules.i >= rules.r.length) {
  661. rstack.shift(); // upward node
  662. }
  663. else {
  664. var rule = rules.r[rules.i];
  665. rules.i++;
  666. if (rule.cssRules) {
  667. rstack.unshift({r: rule.cssRules, i: 0}); // downward node
  668. }
  669. else {
  670. if (regexpAbsolute.test(rule.cssText) && rule.selectorText && rule.selectorText.length > 0) {
  671. selectorsAbsolute.push(rule.selectorText);
  672. }
  673. }
  674. }
  675. }
  676. }
  677. var abselmsCandidate = (selectorsAbsolute.length > 0) ? owner.querySelectorAll(selectorsAbsolute.join(",")) : [];
  678. // make them sure by gettingComputedStyle
  679. for (i = 0; i < abselmsCandidate.length; i++) {
  680. e = abselmsCandidate[i];
  681. s = e.ownerDocument.defaultView.getComputedStyle(e, null);
  682. if (s.getPropertyCSSValue("position").cssText == "absolute") {
  683. // avoid duplicate push
  684. if (!(this.abselms.find(function(element) { return (element[0] == e); }))) {
  685. try {
  686. this.abselms.push([e, s.getPropertyCSSValue("top").getFloatValue(5)]);
  687. }
  688. catch (ex) {}
  689. }
  690. }
  691. }
  692. // delete children of elm in list == positon:absolute
  693. // delete children of other position style element
  694. this.abselms = this.abselms.filter(function(earg) {
  695. for (var e = earg[0].parentElement; e != owner && e != null; e = e.parentElement) {
  696. var cssValue = e.ownerDocument.defaultView.getComputedStyle(e, null).getPropertyCSSValue("position");
  697. if (cssValue && cssValue.cssText && cssValue.cssText != "static") {
  698. return false;
  699. }
  700. }
  701. return true;
  702. });
  703. yass.dump("absolute elments:" + this.abselms.length);
  704.  
  705. if (bodypaddingtop > 0) {
  706. if (owner.childNodes.length == 0) owner.appendChild(this.epadding);
  707. else owner.insertBefore(this.epadding, owner.childNodes[0]);
  708. this.epadding.style.paddingBottom = bodypaddingtop + "px";
  709. }
  710. this.dummy.style.marginTop = -(bodymargintop + bodypaddingtop + 1) + "px"; // negate docuemnt margin
  711. this.e.style.marginLeft = -bodymarginleft + "px";
  712. this.e.style.width = "1px";
  713. if (owner.childNodes.length == 0) owner.appendChild(this.e); // edge is below the dummy element
  714. else owner.insertBefore(this.e, owner.childNodes[0]);
  715. if (owner.childNodes.length == 0) owner.appendChild(this.dummy); // dummy is above
  716. else owner.insertBefore(this.dummy, owner.childNodes[0]);
  717. return 0;
  718. },
  719.  
  720. adjust: function(ebot) {
  721. // adjust width
  722. //this.e.style.width = this._widthtarget.clientWidth + "px";
  723. // copy width from edge on the bottom
  724. try {
  725. this.e.style.width = ebot.e.ownerDocument.defaultView.getComputedStyle(ebot.e, null).getPropertyCSSValue("width").getFloatValue(5) + "px";
  726. }
  727. catch (e) {
  728. this.e.style.width = "1px";
  729. }
  730. // for firebug sidewindow : item inserted on top of children so late
  731. if (this._owner.childNodes[0] != this.dummy) {
  732. if (this.epadding.style.paddingBottom != "0px") this._owner.insertBefore(this.epadding, this._owner.childNodes[0]);
  733. this._owner.insertBefore(this.e, this._owner.childNodes[0]);
  734. this._owner.insertBefore(this.dummy, this._owner.childNodes[0]);
  735. yass.dump("top edge children order changed\n");
  736. }
  737. },
  738.  
  739. render_abs: function(offset) {
  740. for (var i in this.abselms) {
  741. this.abselms[i][0].style.top = (this.abselms[i][1] + offset) + "px";
  742. // forcibly restore original value for elements changed after picked as absolute elements
  743. this.abselms[i][0].style.position = (offset == 0) ? null : "absolute";
  744. }
  745. }
  746. },
  747.  
  748. // edgebot object extends div element
  749. edgebot: {
  750. e: null,
  751.  
  752. ecommon: function(doc) {
  753. var e = null;
  754. if ((e = doc.getElementById("yass_bottom_edge"))) return e;
  755. e = doc.createElement("div");
  756. e.style.backgroundImage = "url(chrome://yass/content/edgebgbot.png)";
  757. e.style.backgroundPosition = "0px 0px";
  758. e.style.height =
  759. e.style.borderWidth =
  760. e.style.padding =
  761. e.style.margin = "0px";
  762. e.style.width = "100%";
  763. e.style.display = "block";
  764. e.setAttribute("id", "yass_bottom_edge");
  765. return e;
  766. },
  767.  
  768. eabsolute: function(doc) {
  769. var e = this.ecommon(doc);
  770. e.style.position = "absolute";
  771. e.style.top =
  772. e.style.left = "0px";
  773. return e;
  774. },
  775.  
  776. estatic: function(doc) {
  777. var e = this.ecommon(doc);
  778. e.style.position = "static";
  779. e.style.top =
  780. e.style.left = null;
  781. return e;
  782. },
  783.  
  784. _owner: null,
  785.  
  786. setowner: function(owner) {
  787. // edges must be inserted inside of body not html even if html is scrollable
  788. var body = owner.ownerDocument.body;
  789. owner = (owner == owner.ownerDocument.documentElement) ? body : owner;
  790. // search more proper owner element for bottom edge in DOM (prefer child element having equal clientHeight of parent)
  791. if (owner !== body) {
  792. while (owner.children.length > 0) {
  793. var properOwner = [];
  794. for (var c = 0; c < owner.children.length; c++) {
  795. var cowner = owner.children[c];
  796. var cownerstyle = cowner.ownerDocument.defaultView.getComputedStyle(cowner, "");
  797. if (cowner.clientHeight == owner.clientHeight && cownerstyle.getPropertyValue("position") != "absolute" && !/left|right/.test(cownerstyle.getPropertyValue("float"))) {
  798. properOwner.push(cowner);
  799. }
  800. }
  801. if (properOwner.length != 1) { break; }
  802. owner = properOwner[0];
  803. }
  804. }
  805. if ((this._owner == owner || this.e == owner) && this.e) return this.e.clientHeight;
  806. if (this._owner) {
  807. try {
  808. this._owner.removeChild(this.e);
  809. }
  810. catch (e) {}
  811. }
  812. if (this.e) this.e.style.height = "0px";
  813. this._owner = owner;
  814. if (owner == body) {
  815. this.e = this.eabsolute(owner.ownerDocument);
  816. // height hint is from html's if body is owner
  817. // body or html the one more difference between clientH and scrollH
  818. var doc = owner.ownerDocument.documentElement;
  819. var body_h = owner.scrollHeight;
  820. var doc_h = doc.scrollHeight;
  821. this._heighttarget = (body_h > doc_h) ? body : doc;
  822. }
  823. else {
  824. this.e = this.estatic(owner.ownerDocument);
  825. this._heighttarget = owner;
  826. }
  827.  
  828. owner.appendChild(this.e);
  829.  
  830. return 0;
  831. },
  832.  
  833. adjust: function() {
  834. // adjust position top
  835. if (this._owner == null) return;
  836. if (this.e.style.position == "absolute") this.e.style.top = this._heighttarget.scrollHeight + "px";
  837. // adjust children order
  838. if (this._owner.childNodes[this._owner.childNodes.length - 1] != this.e) {
  839. this._owner.appendChild(this.e);
  840. yass.dump("bottom edge children order changed\n");
  841. }
  842. }
  843. },
  844.  
  845. funcwheel: function(kbd, idelta, edgemargin) {
  846. if (this.m_wheelactive == false || this.m_sobj == null) {
  847. this.m_wheelactive = false;
  848. if (this.m_sobj) {
  849. this.m_sobj.stop();
  850. }
  851. return;
  852. }
  853.  
  854. var bdumpfunc = (this.m_pref.prefversion <= 2) ?
  855. (function(t, _d) {
  856. return yass.range(t / _d + 0.2, 0.05, 1.0);
  857. }) :
  858. (function(t, _d) {
  859. return yass.range(t / _d, 0.05, 1.0);
  860. });
  861.  
  862. var dump = kbd ? this.m_pref.kbddumping : this.m_pref.wheeldumping;
  863. var bdump = kbd ? this.m_pref.kbdbdumping : this.m_pref.wheelbdumping;
  864.  
  865. var tm = (new Date()).getTime();
  866. var frametime = (tm - this.m_lastfunctime);
  867. frametime = Math.min(frametime, 51);
  868. this.m_lastfunctime = tm;
  869.  
  870. if (frametime <= 0) {
  871. this.oneshot(function() {
  872. yass.funcwheel(kbd, idelta, edgemargin);
  873. }, 3);
  874. return;
  875. }
  876.  
  877. var fordest = (this.m_jumpto - this.m_vpos);
  878.  
  879. if ((this.m_sobj.offset / fordest) < 0) {
  880. dump = 0.45;
  881. bdump = 0.295;
  882. }
  883.  
  884. bdump *= 2000;
  885.  
  886. var d = 0;
  887. var looptimetotal = 0;
  888. var lastd = 0;
  889.  
  890. do {
  891. var localfordest = fordest - d;
  892. var looptime = Math.min(17, frametime - looptimetotal);
  893. looptimetotal += looptime;
  894.  
  895. var f = dump * (looptime / 17);
  896.  
  897. // dumping of begining
  898. if (bdump > 0.0) {
  899. // check reset beginning smooth
  900. if (this.m_resetsmooth > 0) {
  901. if (this.m_pref.prefversion >= 3) {
  902. var lastsmoothtime = this.m_beginsmoothtime;
  903. var smoothtime = tm;
  904. var count = 0;
  905. do { // eslint-disable-line no-constant-condition
  906. if (smoothtime < lastsmoothtime) {
  907. break;
  908. }
  909. var timefromev = tm - smoothtime + 17 + looptimetotal;
  910. var b = bdumpfunc(timefromev, bdump);
  911. var x = this.m_lastd / (localfordest * f * b);
  912. if (x < 0) {
  913. this.m_beginsmoothtime = tm;
  914. break;
  915. }
  916. if (x < 1) {
  917. this.m_beginsmoothtime = smoothtime;
  918. break;
  919. }
  920. smoothtime -= 34;
  921. count++;
  922. } while (true);
  923. }
  924. else {
  925. this.m_beginsmoothtime = tm;
  926. }
  927. this.m_resetsmooth = 0;
  928. }
  929.  
  930. f *= bdumpfunc(tm - this.m_beginsmoothtime + 17 + looptimetotal, bdump);
  931. }
  932.  
  933. d += localfordest * f;
  934. if (lastd == 0) lastd = d;
  935.  
  936. } while (frametime - looptimetotal > 4);
  937.  
  938. this.m_lastd = lastd;
  939.  
  940. var lastmvpos = this.m_vpos;
  941. this.m_vpos += d;
  942.  
  943. var lenfordest = fordest * fordest;
  944.  
  945. // adjust maxscroll (autopagerize or somthing dynamically add elements on m_sobj.body)
  946. if (this.m_sobj.adjust(this.m_vpos, lastmvpos) == false) {
  947. this.m_wheelactive = false;
  948. this.m_sobj.stop();
  949. return;
  950. }
  951.  
  952. // get virtual scrolltop offset
  953. var ofs = this.bouncyEdgeSize(); // offset size
  954. var offsetscroll = 0;
  955. if (this.m_vpos < 0) {
  956. offsetscroll = this.m_vpos;
  957. if (this.m_jumpto != edgemargin && (d * d < ofs / (ofs - Math.min(-offsetscroll, ofs)) - 1)) {
  958. this.m_jumpto = edgemargin;
  959. this.m_resetsmooth = 1;
  960. }
  961. if (this.m_sobj.innerframe) {
  962. this.urgeRefreshTarget(); // forcibly reset scroll target and prompt to check scroll over
  963. }
  964. }
  965. else if (this.m_vpos > this.m_sobj.maxscroll) {
  966. offsetscroll = this.m_vpos - this.m_sobj.maxscroll;
  967. if (this.m_jumpto != this.m_sobj.maxscroll - edgemargin && (d * d < ofs / (ofs - Math.min(offsetscroll, ofs)) - 1)) {
  968. this.m_jumpto = this.m_sobj.maxscroll - edgemargin;
  969. this.m_resetsmooth = 1;
  970. }
  971. if (this.m_sobj.innerframe) {
  972. this.urgeRefreshTarget(); // forcibly reset scroll target and prompt to check scroll over
  973. }
  974. }
  975. else if (lenfordest <= 1.0 || (lenfordest < 100.0 && d * d < 0.2) || this.m_sobj.body.scrollTop != this.m_lastscrolltop) {
  976. this.m_wheelactive = false;
  977. this.m_sobj.stop();
  978. this.m_jumptoremain = fordest;
  979. return;
  980. }
  981.  
  982. this.m_sobj.render(offsetscroll, this.m_vpos);
  983.  
  984. this.m_lastscrolltop = this.m_sobj.body.scrollTop;
  985.  
  986. this.oneshot(function() {
  987. yass.funcwheel(kbd, idelta, edgemargin);
  988. }, 10);
  989. },
  990.  
  991. toggleKeyHook: function(b) {
  992. this.m_keyenable = b;
  993. },
  994.  
  995. refreshTarget: function(target, detail) {
  996. // externally ordered for releasing of m_sobj
  997. if (target == null) {
  998. this.m_wheelactive = false;
  999. if (this.m_sobj) this.m_sobj.release();
  1000. this.m_sobj = null;
  1001. return;
  1002. }
  1003.  
  1004. this.checkBlackList(target.baseURI);
  1005.  
  1006. var newobj = this.findNodeToScroll(target, detail, "");
  1007. // null : stop immediately
  1008. // object not activated : change to it
  1009. // 1 : do not change the target
  1010.  
  1011. if (newobj === 1) return;
  1012.  
  1013. if (newobj == null) {
  1014. this.m_wheelactive = false;
  1015. if (this.m_sobj) this.m_sobj.release();
  1016. this.m_sobj = null;
  1017. this.dump("N: target null\n");
  1018. }
  1019. else if (this.m_sobj && newobj.body != this.m_sobj.body) {
  1020. this.m_wheelactive = false;
  1021. this.m_sobj.release();
  1022. this.m_sobj = newobj;
  1023. this.m_sobj.activate();
  1024. this.dump("A:");
  1025. }
  1026. else if (this.m_sobj == null) {
  1027. this.m_sobj = newobj;
  1028. this.m_sobj.activate();
  1029. this.dump("B:");
  1030. }
  1031.  
  1032. if (newobj) {
  1033. this.dump(newobj.log + "\n");
  1034. }
  1035. },
  1036.  
  1037. checkDesignMode: function(ev) {
  1038. if (ev.originalTarget == this.m_lastcheckdesignmodearg) return;
  1039. this.m_lastcheckdesignmodearg = ev.originalTarget;
  1040.  
  1041. var b = true;
  1042. var mode = (ev.originalTarget.ownerDocument && ev.originalTarget.ownerDocument.designMode) ? ev.originalTarget.ownerDocument.designMode : "off";
  1043. if (mode && mode.toLowerCase() == "on") b = false;
  1044. if (ev.originalTarget.getAttribute) {
  1045. var ceditable = ev.originalTarget.getAttribute("contenteditable");
  1046. if (ceditable == "") ceditable = "true";
  1047. if (!ev.originalTarget.hasAttribute("contenteditable")) ceditable = "false";
  1048. if (ceditable.toLowerCase() == "true") b = false;
  1049. }
  1050. this.toggleKeyHook(b);
  1051. },
  1052.  
  1053. checkBlackList: function(uri) {
  1054. if (this.m_pref.blacklist_lasturi == uri) return;
  1055. this.m_pref.blacklist_lasturi = uri;
  1056. this.m_pref.blacklist_hit = false;
  1057. this.dump("BL_:" + uri + "\n");
  1058. var bl = this.m_pref.blacklist.split(/\n/);
  1059. for (var i in bl) {
  1060. var pattern = bl[i];
  1061. if (typeof(pattern) != "string") continue;
  1062. if (pattern.length == 0) continue;
  1063. if (RegExp(pattern).test(uri)) {
  1064. // hit
  1065. this.m_pref.blacklist_hit = true;
  1066. this.dump("BL_:blacklist pattern [" + pattern + "] matched to [" + uri + "]\n");
  1067. return;
  1068. }
  1069. }
  1070. },
  1071.  
  1072. // based on the code in All-in-One Gestures
  1073. findNodeToScroll: function(orig, hint, log) {
  1074. function getstyle(e, pname) {
  1075. var p = e.ownerDocument.defaultView.getComputedStyle(e, "").getPropertyValue(pname);
  1076. var val = parseFloat(p);
  1077. if (!isNaN(val)) return Math.ceil(val);
  1078. if (p == "thin") return 1;
  1079. if (p == "medium") return 3;
  1080. if (p == "thick") return 5;
  1081. return 0;
  1082. }
  1083.  
  1084. // 0 neither scrollable 1 vertical only 2 horizontal only 3 both
  1085. function getscrolltype(wscroll, wclient, hscroll, hclient) {
  1086. if (hclient < 50) return 0;
  1087. if (hscroll - hclient < 10) hclient = hscroll; // too small to scroll
  1088. var flag = 0;
  1089. if (wscroll > wclient) flag += 1;
  1090. if (hscroll > hclient) flag += 2;
  1091. return flag;
  1092. }
  1093.  
  1094. function newobject(p) {
  1095. var editable = false;
  1096. if (p.parentNode && p.parentNode.nodeName.toLowerCase() == "textarea") editable = true;
  1097. var mode = (p.ownerDocument && p.ownerDocument.designMode) ? p.ownerDocument.designMode : "off";
  1098. if (mode && mode.toLowerCase() == "on") editable = true;
  1099. if (p.isContentEditable) editable = true;
  1100. if (editable) return yass.ScrollerNoEdge;
  1101.  
  1102. if (yass.m_edgesize == 0 || orig.baseURI.indexOf("//firebug") > 0) return yass.ScrollerNoEdge;
  1103.  
  1104. // give bouncing edge up for display:flex scroll tatget
  1105. var edgeOwner = (p == orig.ownerDocument.documentElement) ? orig.ownerDocument.body : p;
  1106. var styleDisplay = edgeOwner.ownerDocument.defaultView.getComputedStyle(edgeOwner, "").getPropertyValue("display");
  1107. if (/^(flex|inline-flex|-moz-box)$/.test(styleDisplay)) return yass.ScrollerNoEdge;
  1108.  
  1109. return yass.Scroller;
  1110. }
  1111.  
  1112. // true: scrollable / false: bottom most or top most
  1113. // this is called onto html or body only
  1114. var scrollovercheck =
  1115. (!hint) ?
  1116. (function() {
  1117. return true;
  1118. }) : (
  1119. (hint < 0) ?
  1120. (function(fe, n, a, b) {
  1121. if (fe == null) return true;
  1122. return (("_yass_ownedby" in n) && n._yass_ownedby) ? n._yass_ownedby.scrollovercheck(hint) : (a > 0);
  1123. }) :
  1124. (function(fe, n, a, b) {
  1125. if (fe == null) return true;
  1126. // there are some region unmovable really but looks 1px scrollable ----------------------------------v
  1127. return (("_yass_ownedby" in n) && n._yass_ownedby) ? n._yass_ownedby.scrollovercheck(hint) : (a < b) && (b > 1);
  1128. })
  1129. );
  1130.  
  1131. // select element have scrollable parameters even if they are popup window type
  1132. // directly rendered selectable pane return option for origin of event
  1133. if (orig.nodeName.toLowerCase() == "select") orig = orig.parentNode;
  1134.  
  1135. if (!orig.ownerDocument) {
  1136. this.dump("ownerDocument unreachable\n");
  1137. return null;
  1138. }
  1139. var doc = orig.ownerDocument.documentElement;
  1140. if (doc && doc.nodeName.toLowerCase() != "html") {
  1141. this.dump("doc is " + doc.nodeName + " not html\n");
  1142. return null;
  1143. }
  1144.  
  1145. var bodies = doc.getElementsByTagName("body");
  1146. if (!bodies || bodies.length == 0) {
  1147. this.dump("no body\n");
  1148. return null;
  1149. }
  1150. var body = bodies[0];
  1151.  
  1152. var node = (orig == doc) ? body : orig;
  1153.  
  1154. var frameelement = orig.ownerDocument.defaultView.frameElement;
  1155.  
  1156. // if this is in a unscrollable frame element
  1157. if (frameelement && frameelement.scrolling && frameelement.scrolling.toLowerCase() == "no") {
  1158. return this.findNodeToScroll(frameelement.ownerDocument.documentElement, hint, log + "!");
  1159. }
  1160.  
  1161. var bodyOverflowValue = null;
  1162.  
  1163. do {
  1164. var nodename = node.nodeName.toLowerCase();
  1165.  
  1166. /*log*/
  1167. log += nodename;
  1168.  
  1169. /***/
  1170. try {
  1171.  
  1172. // when mouse is on scrollbar in select tag popup, parent is <select>
  1173. if (/^(select|option|optgroup)$/.test(nodename)) {
  1174. this.dump("option found :" + log);
  1175. return null;
  1176. }
  1177.  
  1178. var overflowprop = node.ownerDocument.defaultView.getComputedStyle(node, "").getPropertyValue("overflow-y");
  1179. if (node == body) bodyOverflowValue = overflowprop;
  1180.  
  1181. if (node.clientWidth && node.clientHeight &&
  1182. (overflowprop != "hidden") &&
  1183. (node == doc || node == body || overflowprop != "visible")
  1184. ) {
  1185. var realwidth, realheight;
  1186. if ("scrollLeftMax" in node) realwidth = node.scrollWidth - node.scrollLeftMax;
  1187. else realwidth = node.clientWidth + getstyle(node, "border-left-width") + getstyle(node, "border-right-width");
  1188. if ("scrollTopMax" in node) realheight = node.scrollHeight - node.scrollTopMax;
  1189. else realheight = node.clientHeight + getstyle(node, "border-top-width") + getstyle(node, "border-bottom-width");
  1190.  
  1191. var scrolltype = getscrolltype(node.scrollWidth, realwidth, node.scrollHeight, realheight);
  1192. /*log*/
  1193. log += "(" + node.scrollTop + " " + (node.scrollHeight - realheight) + ")";
  1194.  
  1195. if ((scrolltype >= 2) &&
  1196. // scroll focus overflow applied only on inner frame (HTML|BODY)
  1197. ((node != doc && node != body) || scrollovercheck(frameelement, node, node.scrollTop, node.scrollHeight - realheight))
  1198. ) {
  1199. return new(newobject(node))(orig, node, scrolltype, realwidth, realheight, log);
  1200. }
  1201. }
  1202.  
  1203. if (node == doc) break;
  1204.  
  1205. /***/
  1206. }
  1207. catch (e) {}
  1208.  
  1209. /*log*/
  1210. log += ">";
  1211.  
  1212. node = node.parentNode;
  1213.  
  1214. } while (node);
  1215.  
  1216. if (frameelement) {
  1217. var upper = this.findNodeToScroll(frameelement.ownerDocument.documentElement, hint, log + "!");
  1218. if (upper != null) return upper;
  1219. return 1;
  1220. }
  1221.  
  1222. // no scrollable area found in content ( mainly for image only page to handle )
  1223.  
  1224. // gmail problem - gmail have main fullscreen iframe as main scrollable area
  1225. // while top html have little pixels larger scrollheight than clientheight
  1226. if (body.scrollHeight - body.clientHeight > 10) {
  1227. if (bodyOverflowValue && bodyOverflowValue == "hidden") {
  1228. log += " *DEFAULT hidden body*";
  1229. return null;
  1230. }
  1231. log += " *DEFAULT body*";
  1232. return new(newobject(body))(orig, body, 3, body.clientWidth, body.clientHeight, log);
  1233. }
  1234. if (doc.scrollHeight - doc.clientHeight > 10) {
  1235. log += " *DEFAULT html*";
  1236. return new(newobject(doc))(orig, doc, 3, doc.clientWidth, doc.clientHeight, log);
  1237. }
  1238.  
  1239. this.dump(log + " *continue*\n");
  1240. return 1;
  1241. },
  1242.  
  1243. refreshPreferences: function() {
  1244. this.refreshTarget(null, null);
  1245. this.urgeRefreshTarget();
  1246.  
  1247. var ps = this.m_prefservice;
  1248.  
  1249. var presetid = ps.getCharPref("extensions.yass.selectedpreset");
  1250. var presets = ps.getCharPref("extensions.yass.preset." + presetid).split(",");
  1251.  
  1252. this.m_pref.wheelstep = presets[0];
  1253. this.m_pref.wheeldumping = (900 - presets[1]) / 1000;
  1254. this.m_pref.wheelbdumping = presets[2] / 890;
  1255. this.m_pref.wheelaccel = presets[3];
  1256. this.m_pref.kbdstep = presets[4];
  1257. this.m_pref.kbddumping = (900 - presets[5]) / 1000;
  1258. this.m_pref.kbdbdumping = presets[6] / 890;
  1259. this.m_pref.kbdaccel = presets[7];
  1260. this.m_pref.usekbd = ps.getBoolPref("extensions.yass.usekbd");
  1261. this.m_pref.enabled = (ps.getCharPref("extensions.yass.enabled") == "true") ? true : false;
  1262. this.m_pref.usepagejump = ps.getBoolPref("extensions.yass.usepagejump");
  1263. this.m_pref.pagemargin = ps.getIntPref("extensions.yass.pagemargin");
  1264. this.m_pref.prefversion = ps.getCharPref("extensions.yass.prefversion") - 0;
  1265. this.m_pref.usewholejump = ps.getBoolPref("extensions.yass.usewholejump");
  1266. this.m_pref.useflickemulation = ps.getBoolPref("extensions.yass.useflickemulation");
  1267. this.m_pref.tickwheel = ps.getIntPref("extensions.yass.tickwheel");
  1268. this.m_pref.dolog = false;
  1269. try {
  1270. this.m_pref.dolog = ps.getBoolPref("extensions.yass.dolog");
  1271. }
  1272. catch (e) {}
  1273.  
  1274. this.m_edgesize = ps.getIntPref("extensions.yass.edgetype");
  1275.  
  1276. // event listener
  1277. if ("onwheel" in content.document.createElement("div"))
  1278. addEventListener("wheel", yass, false);
  1279. else
  1280. addEventListener("MozMousePixelScroll", yass, false);
  1281.  
  1282. // blacklist
  1283. {
  1284. var str_trim = function(s) {
  1285. return s.replace(/^\s+|\s+$/g, "");
  1286. };
  1287. var rawlist = ps.getCharPref("extensions.yass.blacklist").split(/\n/);
  1288. var blist = [];
  1289. for (var i in rawlist) {
  1290. var p = rawlist[i];
  1291. if (typeof(p) != "string") continue;
  1292. if (str_trim(p).length == 0) continue;
  1293. blist.push(str_trim(p).replace(/\./g, "\\.").replace(/\+/g, "\\+").replace(/\?/g, "\\?").replace(/\*/g, ".*") + "$");
  1294. }
  1295. this.m_pref.blacklist = blist.join("\n");
  1296. this.m_pref.blacklist_lasturi = "xxxxxx";
  1297. this.checkBlackList(content.document.baseURI);
  1298. }
  1299.  
  1300. // contextmenu
  1301. this.m_pref.showcontextmenu = ps.getBoolPref("extensions.yass.showcontextmenu");
  1302. }
  1303. };
  1304.  
  1305. // runs per tabs open (not content load)
  1306. (function() {
  1307.  
  1308. addEventListener("resize", yass, false);
  1309. addEventListener("keydown", yass, true);
  1310. addEventListener("mousedown", yass, false);
  1311. addEventListener("mouseup", yass, false);
  1312. // we often have only content changed on link navigation
  1313. // so we should reset scroll target by listening to this
  1314. addEventListener("DOMContentLoaded", yass, true); // every content load
  1315. addEventListener("DOMWindowCreated", function() { yass.refreshPreferences(); }, false); // very early from DOMContentLoaded
  1316. addEventListener("unload", yass, true); // tab close
  1317.  
  1318. // message listener
  1319. addMessageListener("YASmoothScrolling@kataho:refreshPreferences", function(msg) {
  1320. yass.refreshPreferences();
  1321. });
  1322. addMessageListener("YASmoothScrolling@kataho:reset_design_mode_check_target", function(msg) {
  1323. yass.m_lastcheckdesignmodearg = null;
  1324. });
  1325. })();
Advertisement
Add Comment
Please, Sign In to add comment