Select like opera

Select texts insider links, for firefox only

当前为 2016-12-18 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Select like opera
  3. // @namespace lkytal
  4. // @author lkytal
  5. // @homepage https://lkytal.github.io/
  6. // @icon http://lkytal.qiniudn.com/ic.ico
  7. // @version 1.1.2
  8. // @description Select texts insider links, for firefox only
  9. // @include *
  10. // @exclude http://www.baidu.com/*
  11. // @exclude https://www.baidu.com/*
  12. // @grant unsafeWindow
  13. // @grant GM_getValue
  14. // @grant GM_setValue
  15. // @homepageURL https://git.oschina.net/coldfire/GM
  16. // ==/UserScript==
  17.  
  18. selectLikeOpera = function() {
  19. var findHTMLAchor = function(a) {
  20. if (a.nodeType === 3) a = a.parentNode;
  21. do {
  22. if (a.constructor === HTMLAnchorElement) return a;
  23. } while ((a = a.parentNode) && a !== document.body);
  24. return null;
  25. };
  26. var preventEvent = function(e) {
  27. e.preventDefault();
  28. e.stopPropagation();
  29. return false;
  30. };
  31. var rangeOperator = (function() {
  32. var w = typeof InstallTrigger === 'undefined';
  33. return {
  34. createRange: function(x, y) {
  35. if (w) {
  36. return document.caretRangeFromPoint(x, y)
  37. }
  38. else
  39. {
  40. var a = document.createRange();
  41. var p = document.caretPositionFromPoint(x, y);
  42. a.setStart(p.offsetNode, p.offset);
  43. return a;
  44. }
  45. return null;
  46. },
  47. rangeAttr: ((w ? '-webkit-' : '-moz-') + 'user-select')
  48. }
  49. })();
  50. var j = (function() {
  51. var o = [{
  52. p: rangeOperator.rangeAttr,
  53. v: 'text'
  54. }, {
  55. p: 'outline-width',
  56. v: 0
  57. }];
  58. var n;
  59. var s;
  60. return function(a) {
  61. if (a) {
  62. n = a, s = [];
  63. for (var i = o.length - 1; i >= 0; i -= 1) {
  64. s.push([n.style.getPropertyValue(o[i].p), n.style.getPropertyPriority(o[i].p)]);
  65. n.style.setProperty(o[i].p, o[i].v, 'important');
  66. }
  67. }
  68. else if (n)
  69. {
  70. for (var i = o.length; i-- > 0;) {
  71. n.style.removeProperty(o[i].p);
  72. if (s[i][0] !== null) n.style.setProperty(o[i].p, s[i][0], s[i][1]);
  73. }
  74. n = s = null
  75. }
  76. }
  77. })();
  78. var toggleEvent = function(events, bAdd) {
  79. if (bAdd === undefined) bAdd = true;
  80. if (events.constructor !== Array) events = [events];
  81.  
  82. for (var i = 0, len = events.length; i < len; i += 1)
  83. {
  84. if (bAdd)
  85. {
  86. document.addEventListener(events[i], eventList[events[i]], true);
  87. }
  88. else
  89. {
  90. document.removeEventListener(events[i], eventList[events[i]], true);
  91. }
  92. }
  93. };
  94. var removeEvent = function(a) {
  95. toggleEvent(a, false);
  96. };
  97. var m, q, u, v, z, A = function() {
  98. q = v = true;
  99. u = z = false;
  100. };
  101. var B, selected = document.getSelection();
  102. selectEvent = function(e) {
  103. if (e.which < 2) {
  104. A();
  105. var x = e.clientX,
  106. y = e.clientY;
  107. if (selected.rangeCount > 0) {
  108. var a = selected.getRangeAt(0);
  109. if (!a.collapsed) {
  110. var r = rangeOperator.createRange(x, y);
  111. if (r && a.isPointInRange(r.startContainer, r.startOffset)) return;
  112. }
  113. }
  114. j();
  115. var t = e.target,
  116. n = findHTMLAchor(t);
  117. if (!n) n = t.nodeType !== 3 ? t : t.parentNode;
  118. if (n.constructor === HTMLCanvasElement || n.textContent === '') return;
  119. var r = n.getBoundingClientRect();
  120. B = {
  121. n: n,
  122. x: Math.round(r.left),
  123. y: Math.round(r.top),
  124. c: 0
  125. };
  126. m = {
  127. x: x,
  128. y: y
  129. };
  130. toggleEvent(['mousemove', 'mouseup', 'dragend', 'dragstart']);
  131. j(n);
  132. }
  133. };
  134. var D = 3,
  135. K = 0.8,
  136. eventList = {
  137. 'mousemove': function(e) {
  138. if (B) {
  139. if (B.c++ < 12) {
  140. var r = B.n.getBoundingClientRect();
  141. if (Math.round(r.left) !== B.x || Math.round(r.top) !== B.y) {
  142. removeEvent(['mousemove', 'mouseup', 'dragend', 'dragstart', 'click']);
  143. j();
  144. selected.removeAllRanges();
  145. return;
  146. }
  147. } else {
  148. B = null;
  149. }
  150. }
  151. var x = e.clientX,
  152. y = e.clientY;
  153. if (v) {
  154. selected.removeAllRanges();
  155. var a = x > m.x ? -2 : 2;
  156. var b = rangeOperator.createRange(x + a, y);
  157. if (b) {
  158. selected.addRange(b);
  159. v = false;
  160. }
  161. }
  162. if (q) {
  163. var c = Math.abs(m.x - x),
  164. d = Math.abs(m.y - y);
  165. u = d === 0 || c / d > K;
  166. if (c > D || d > D) {
  167. q = false;
  168. z = true;
  169. toggleEvent('click');
  170. }
  171. }
  172. if (u) {
  173. var b = rangeOperator.createRange(x, y);
  174. if (b) selected.extend(b.startContainer, b.startOffset);
  175. }
  176. },
  177. 'dragstart': function(e) {
  178. removeEvent('dragstart');
  179. if (u) return preventEvent(e);
  180. },
  181. 'mouseup': function(e) {
  182. removeEvent(['mousemove', 'mouseup', 'dragstart', 'dragend']);
  183. if (!u && z) z = false;
  184. setTimeout(function() {
  185. removeEvent('click');
  186. }, 111);
  187. },
  188. 'dragend': function(e) {
  189. removeEvent(['dragend', 'mousemove', 'mouseup']);
  190. },
  191. 'click': function(e) {
  192. removeEvent('click');
  193. if (z) return preventEvent(e);
  194. }
  195. };
  196.  
  197. document.addEventListener('mousedown', selectEvent, true);
  198. };
  199.  
  200. setTimeout(selectLikeOpera, 300);