Select text inside a link like Opera

Disable link dragging and select text.

当前为 2014-11-18 提交的版本,查看 最新版本

  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.11
  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. if (this.uninitFlag || e.pageX && e.pageY && (e.pageX != this.lastMouseDownPos.x || e.pageY != this.lastMouseDownPos.y)) {
  62. e.preventDefault();
  63. e.stopImmediatePropagation();
  64. }
  65.  
  66. } else if (e.type == "mousedown") {
  67.  
  68. if (e.ctrlKey || e.shiftKey || e.altKey || e.button) {
  69. return;
  70. }
  71.  
  72. // Trak clicking to solve this:
  73. // https://greasyfork.org/ru/forum/discussion/1898/doesn-t-work-on-some-sites
  74. this.lastMouseDownPos.x = e.pageX;
  75. this.lastMouseDownPos.y = e.pageY;
  76.  
  77. this.uninitFlag = false;
  78.  
  79. if (e.target.nodeName == "IMG") {
  80. this.imgFlag = true;
  81. }
  82.  
  83. select = window.getSelection();
  84. if (!select.isCollapsed) {
  85. caretPos = caretPositionFromPoint(e.pageX - window.scrollX, e.pageY - window.scrollY);
  86. if (!inSelect(caretPos, select)) {
  87. select.collapse(caretPos.offsetNode, caretPos.offset);
  88. }
  89. }
  90.  
  91. } else if (e.type == "mouseup") {
  92.  
  93. this.checkMove = false;
  94. this.imgFlag = false;
  95.  
  96. if (!this.target) {
  97. return;
  98. }
  99.  
  100. this.uninitFlag = true;
  101. this.uninit();
  102.  
  103. } else if (e.type == "mousemove") {
  104.  
  105. this.moveX = e.pageX - this.currentPos.x;
  106. this.moveY = e.pageY - this.currentPos.y;
  107. this.currentPos.x = e.pageX;
  108. this.currentPos.y = e.pageY;
  109.  
  110. if (!this.target) {
  111. return;
  112. }
  113.  
  114. select = window.getSelection();
  115. caretPos = caretPositionFromPoint(this.currentPos.x - window.scrollX, this.currentPos.y - window.scrollY);
  116. if (!this.multiSelect) {
  117. select.extend(caretPos.offsetNode, caretPos.offset);
  118. } else {
  119. this.range.setEnd(caretPos.offsetNode, caretPos.offset);
  120. }
  121.  
  122. } else if (e.type == "dragstart") {
  123.  
  124. if (e.button || e.altKey || e.shiftKey) {
  125. return;
  126. }
  127.  
  128. if (this.imgFlag) {
  129. this.imgFlag = false;
  130. return;
  131. }
  132.  
  133. a = e.target;
  134. while (a.nodeName != "A" && a.nodeName != "HTML") {
  135. a = a.parentNode;
  136. }
  137.  
  138. if (!a.href) {
  139. return;
  140. }
  141.  
  142. movementX = e.pageX - this.currentPos.x;
  143. movementY = e.pageY - this.currentPos.y;
  144.  
  145. if (!movementX && !movementY) {
  146. movementX = this.moveX;
  147. movementY = this.moveY;
  148. }
  149. if (Math.abs(movementX) < Math.abs(movementY)) {
  150. return;
  151. }
  152.  
  153. e.preventDefault();
  154. this.target = a;
  155. this.init(e);
  156. }
  157. },
  158. init: function(e){
  159. var select = window.getSelection();
  160.  
  161. this.startPos.x = e.pageX;
  162. this.startPos.y = e.pageY;
  163.  
  164. this.multiSelect = e.ctrlKey;
  165.  
  166. var caretPos = caretPositionFromPoint(this.startPos.x - window.scrollX, this.startPos.y - window.scrollY);
  167. if (!this.multiSelect) {
  168. select.collapse(caretPos.offsetNode, caretPos.offset);
  169. } else {
  170. this.range = new Range();
  171. this.range.setEnd(caretPos.offsetNode, caretPos.offset);
  172. this.range.collapse();
  173. select.addRange(this.range);
  174. }
  175.  
  176. this.target.classList.add("force-select");
  177.  
  178. },
  179. uninit: function(){
  180.  
  181. this.target.classList.remove("force-select");
  182. this.target = null;
  183. this.range = null;
  184. this.multiSelect = false;
  185.  
  186. }
  187. };
  188.  
  189. document.addEventListener("mousemove", force, false);
  190. document.addEventListener("mouseup", force, false);
  191. document.addEventListener("mousedown", force, true);
  192. document.addEventListener("click", force, true);
  193. document.addEventListener("dragstart", force, true);
  194. document.addEventListener("DOMContentLoaded", function(){
  195. GM_addStyle(".force-select{ -moz-user-select: text!important; }");
  196. }, false);