From 3c1505d0444ffac75bb4da7c99c993780303c83b Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke <marijnh@gmail.com>
Date: Thu, 22 Jan 2015 16:11:27 +0100
Subject: [PATCH] [selection-pointer addon] Add

---
 addon/selection/selection-pointer.js | 95 ++++++++++++++++++++++++++++
 doc/manual.html                      |  8 +++
 mode/htmlmixed/index.html            |  6 +-
 3 files changed, 108 insertions(+), 1 deletion(-)
 create mode 100644 addon/selection/selection-pointer.js

diff --git a/addon/selection/selection-pointer.js b/addon/selection/selection-pointer.js
new file mode 100644
index 000000000..ba5999496
--- /dev/null
+++ b/addon/selection/selection-pointer.js
@@ -0,0 +1,95 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+  "use strict";
+
+  CodeMirror.defineOption("selectionPointer", false, function(cm, val) {
+    var data = cm.state.selectionPointer;
+    if (data) {
+      CodeMirror.off(cm.getWrapperElement(), "mousemove", data.mousemove);
+      CodeMirror.off(cm.getWrapperElement(), "mouseleave", data.mouseleave);
+      cm.off("cursorActivity", reset);
+      cm.off("scroll", reset);
+      cm.state.selectionPointer = null;
+      cm.display.lineDiv.style.cursor = "";
+    }
+    if (val) {
+      data = cm.state.selectionPointer = {
+        value: typeof val == "string" ? val : "default",
+        mousemove: function(event) { mousemove(cm, event); },
+        mouseleave: function(event) { mouseleave(cm, event); },
+        rects: null,
+        mouseX: null, mouseY: null,
+        willUpdate: false
+      };
+      CodeMirror.on(cm.getWrapperElement(), "mousemove", data.mousemove);
+      CodeMirror.on(cm.getWrapperElement(), "mousemove", data.mousemove);
+      cm.on("cursorActivity", reset);
+      cm.on("scroll", reset);
+    }
+  });
+
+  function mousemove(cm, event) {
+    var data = cm.state.selectionPointer;
+    if (event.buttons == null ? event.which : event.buttons) {
+      data.mouseX = data.mouseY = null;
+    } else {
+      data.mouseX = event.clientX;
+      data.mouseY = event.clientY;
+    }
+    scheduleUpdate(cm);
+  }
+
+  function mouseout(cm, event) {
+    if (!cm.getWrapperElement().contains(event.relatedTarget)) {
+      var data = cm.state.selectionPointer;
+      data.mouseX = data.mouseY = null;
+      scheduleUpdate(cm);
+    }
+  }
+
+  function reset(cm) {
+    cm.state.selectionPointer.rects = null;
+    scheduleUpdate(cm);
+  }
+
+  function scheduleUpdate(cm) {
+    if (!cm.state.selectionPointer.willUpdate) {
+      cm.state.selectionPointer.willUpdate = true;
+      setTimeout(function() {
+        update(cm);
+        cm.state.selectionPointer.willUpdate = false;
+      }, 50);
+    }
+  }
+
+  function update(cm) {
+    var data = cm.state.selectionPointer;
+    if (!data) return;
+    if (data.rects == null && data.mouseX != null) {
+      data.rects = [];
+      if (cm.somethingSelected()) {
+        for (var sel = cm.display.selectionDiv.firstChild; sel; sel = sel.nextSibling)
+          data.rects.push(sel.getBoundingClientRect());
+      }
+    }
+    var inside = false;
+    if (data.mouseX != null) for (var i = 0; i < data.rects.length; i++) {
+      var rect = data.rects[i];
+      if (rect.left <= data.mouseX && rect.right >= data.mouseX &&
+          rect.top <= data.mouseY && rect.bottom >= data.mouseY)
+        inside = true;
+    }
+    var cursor = inside ? data.value : "";
+    if (cm.display.lineDiv.style.cursor != cursor)
+      cm.display.lineDiv.style.cursor = cursor;
+  }
+});
diff --git a/doc/manual.html b/doc/manual.html
index 4fee2bed9..365104051 100644
--- a/doc/manual.html
+++ b/doc/manual.html
@@ -2635,6 +2635,14 @@ editor.setOption("extraKeys", {
       and adds a background with the class <code>CodeMirror-activeline-background</code>.
       is enabled. See the <a href="../demo/activeline.html">demo</a>.</dd>
 
+      <dt id="addon_selection-pointer"><a href="../addon/selection/selection-pointer.js"><code>selection/selection-pointer.js</code></a></dt>
+      <dd>Defines a <code>selectionPointer</code> option which you can
+      use to control the mouse cursor appearance when hovering over
+      the selection. It can be set to a string,
+      like <code>"pointer"</code>, or to true, in which case
+      the <code>"default"</code> (arrow) cursor will be used. You can
+      see a demo <a href="../mode/htmlmixed/index.html">here</a>.</dd>
+
       <dt id="addon_loadmode"><a href="../addon/mode/loadmode.js"><code>mode/loadmode.js</code></a></dt>
       <dd>Defines a <code>CodeMirror.requireMode(modename,
       callback)</code> function that will try to load a given mode and
diff --git a/mode/htmlmixed/index.html b/mode/htmlmixed/index.html
index 61630293f..f94df9e21 100644
--- a/mode/htmlmixed/index.html
+++ b/mode/htmlmixed/index.html
@@ -6,6 +6,7 @@
 
 <link rel="stylesheet" href="../../lib/codemirror.css">
 <script src="../../lib/codemirror.js"></script>
+<script src="../../addon/selection/selection-pointer.js"></script>
 <script src="../xml/xml.js"></script>
 <script src="../javascript/javascript.js"></script>
 <script src="../css/css.js"></script>
@@ -62,7 +63,10 @@
                       {matches: /(text|application)\/(x-)?vb(a|script)/i,
                        mode: "vbscript"}]
       };
-      var editor = CodeMirror.fromTextArea(document.getElementById("code"), {mode: mixedMode});
+      var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+        mode: mixedMode,
+        selectionPointer: true
+      });
     </script>
 
     <p>The HTML mixed mode depends on the XML, JavaScript, and CSS modes.</p>
-- 
GitLab