Select text inside a link like Opera

Disable link dragging and select text.

当前为 2015-09-28 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Select text inside a link like Opera
  3. // @namespace eight04.blogspot.com
  4. // @description Disable link dragging and select text.
  5. // @include http://*
  6. // @include https://*
  7. // @version 4.0.12
  8. // @grant GM_addStyle
  9. // @run-at document-start
  10. // ==/UserScript==
  11.  
  12. "use strict";
  13.  
  14. function caretPositionFromPoint(x, y) {
  15. if (document.caretPositionFromPoint) {
  16. return document.caretPositionFromPoint(x, y);
  17. }
  18. var r = document.caretRangeFromPoint(x, y);
  19. return {
  20. offsetNode: r.startContainer,
  21. offset: r.startOffset
  22. };
  23. }
  24.  
  25. function inSelect(caretPos, selection){
  26. var i, len = selection.rangeCount, range;
  27. for (i = 0; i < len; i++) {
  28. range = selection.getRangeAt(i);
  29. if (range.isPointInRange(caretPos.offsetNode, caretPos.offset)) {
  30. return true;
  31. }
  32. }
  33. return false;
  34. }
  35.  
  36. var force = {
  37. target: null,
  38. select: getSelection(),
  39. currentPos: {
  40. x: null,
  41. y: null
  42. },
  43. startPos: {
  44. x: null,
  45. y: null
  46. },
  47. lastMouseDownPos: {
  48. x: null,
  49. y: null
  50. },
  51. handleEvent: function(e){
  52. var caretPos, a, movementX, movementY, select;
  53.  
  54. if (e.type == "click") {
  55.  
  56. if (e.ctrlKey || e.shiftKey || e.altKey || e.button) {
  57. return;
  58. }
  59.  
  60. // Fix browser clicking issue.
  61. select = window.getSelection();
  62. if (this.uninitFlag || !select.isCollapsed && e.pageX && e.pageY && (e.pageX != this.lastMouseDownPos.x || e.pageY != this.lastMouseDownPos.y)) {
  63. e.preventDefault();
  64. e.stopImmediatePropagation();
  65. }
  66.  
  67. } else if (e.type == "mousedown") {
  68.  
  69. if (e.ctrlKey || e.shiftKey || e.altKey || e.button) {
  70. return;
  71. }
  72.  
  73. // Trak clicking to solve this:
  74. // https://greasyfork.org/ru/forum/discussion/1898/doesn-t-work-on-some-sites
  75. this.lastMouseDownPos.x = e.pageX;
  76. this.lastMouseDownPos.y = e.pageY;
  77.  
  78. this.uninitFlag = false;
  79.  
  80. if (e.target.nodeName == "IMG") {
  81. this.imgFlag = true;
  82. }
  83.  
  84. select = window.getSelection();
  85. if (!select.isCollapsed) {
  86. caretPos = caretPositionFromPoint(e.pageX - window.scrollX, e.pageY - window.scrollY);
  87. if (!inSelect(caretPos, select)) {
  88. select.collapse(caretPos.offsetNode, caretPos.offset);
  89. }
  90. }
  91.  
  92. } else if (e.type == "mouseup") {
  93.  
  94. this.checkMove = false;
  95. this.imgFlag = false;
  96.  
  97. if (!this.target) {
  98. return;
  99. }
  100.  
  101. this.uninitFlag = true;
  102. this.uninit();
  103.  
  104. } else if (e.type == "mousemove") {
  105.  
  106. this.moveX = e.pageX - this.currentPos.x;
  107. this.moveY = e.pageY - this.currentPos.y;
  108. this.currentPos.x = e.pageX;
  109. this.currentPos.y = e.pageY;
  110.  
  111. if (!this.target) {
  112. return;
  113. }
  114.  
  115. select = window.getSelection();
  116. caretPos = caretPositionFromPoint(this.currentPos.x - window.scrollX, this.currentPos.y - window.scrollY);
  117. if (!this.multiSelect) {
  118. select.extend(caretPos.offsetNode, caretPos.offset);
  119. } else {
  120. this.range.setEnd(caretPos.offsetNode, caretPos.offset);
  121. }
  122.  
  123. } else if (e.type == "dragstart") {
  124.  
  125. if (e.button || e.altKey || e.shiftKey) {
  126. return;
  127. }
  128.  
  129. if (this.imgFlag) {
  130. this.imgFlag = false;
  131. return;
  132. }
  133.  
  134. a = e.target;
  135. while (a.nodeName != "A" && a.nodeName != "HTML") {
  136. a = a.parentNode;
  137. }
  138.  
  139. if (!a.href) {
  140. return;
  141. }
  142.  
  143. movementX = e.pageX - this.currentPos.x;
  144. movementY = e.pageY - this.currentPos.y;
  145.  
  146. if (!movementX && !movementY) {
  147. movementX = this.moveX;
  148. movementY = this.moveY;
  149. }
  150. if (Math.abs(movementX) < Math.abs(movementY)) {
  151. return;
  152. }
  153.  
  154. e.preventDefault();
  155. this.target = a;
  156. this.init(e);
  157. }
  158. },
  159. init: function(e){
  160. var select = window.getSelection();
  161.  
  162. this.startPos.x = e.pageX;
  163. this.startPos.y = e.pageY;
  164.  
  165. this.multiSelect = e.ctrlKey;
  166.  
  167. var caretPos = caretPositionFromPoint(this.startPos.x - window.scrollX, this.startPos.y - window.scrollY);
  168. if (!this.multiSelect) {
  169. select.collapse(caretPos.offsetNode, caretPos.offset);
  170. } else {
  171. this.range = new Range();
  172. this.range.setEnd(caretPos.offsetNode, caretPos.offset);
  173. this.range.collapse();
  174. select.addRange(this.range);
  175. }
  176.  
  177. this.target.classList.add("force-select");
  178.  
  179. },
  180. uninit: function(){
  181.  
  182. this.target.classList.remove("force-select");
  183. this.target = null;
  184. this.range = null;
  185. this.multiSelect = false;
  186.  
  187. }
  188. };
  189.  
  190. document.addEventListener("mousemove", force, false);
  191. document.addEventListener("mouseup", force, false);
  192. document.addEventListener("mousedown", force, true);
  193. document.addEventListener("click", force, true);
  194. document.addEventListener("dragstart", force, true);
  195. document.addEventListener("DOMContentLoaded", function(){
  196. GM_addStyle(".force-select{ -moz-user-select: text!important; }");
  197. }, false);