changeset 115:b3d53c87d7ea

towards dictionary lookup support
author ht
date Sat, 23 Mar 2019 17:34:03 +0000
parents 1940408e02bf
children 45b039236dc0
files findWord.js hoverDemo.html
diffstat 2 files changed, 304 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/findWord.js	Sat Mar 23 17:34:03 2019 +0000
@@ -0,0 +1,242 @@
+// Thanks to https://stackoverflow.com/a/30586239 for word-finder
+$(function() {
+  // Get the HTML in #hoverText - just a wrapper for convenience
+  var $hoverText = $("#hoverText");
+
+  // Get the full word the cursor is over regardless of span breaks
+  function getFullWord(event) {
+     var i, begin, end, range, textNode, offset;
+    
+    // Internet Explorer
+    if (document.body.createTextRange) {
+       try {
+         range = document.body.createTextRange();
+         range.moveToPoint(event.clientX, event.clientY);
+         range.select();
+         range = getTextRangeBoundaryPosition(range, true);
+      
+         textNode = range.node;
+         offset = range.offset;
+       } catch(e) {
+         return ""; // Sigh, IE
+       }
+    }
+    
+    // Firefox, Safari
+    // REF: https://developer.mozilla.org/en-US/docs/Web/API/Document/caretPositionFromPoint
+    else if (document.caretPositionFromPoint) {
+      range = document.caretPositionFromPoint(event.clientX, event.clientY);
+      textNode = range.offsetNode;
+      offset = range.offset;
+
+      // Chrome
+      // REF: https://developer.mozilla.org/en-US/docs/Web/API/document/caretRangeFromPoint
+    } else if (document.caretRangeFromPoint) {
+      range = document.caretRangeFromPoint(event.clientX, event.clientY);
+      textNode = range.startContainer;
+      offset = range.startOffset;
+    }
+
+    // Only act on text nodes
+    if (!textNode || textNode.nodeType !== Node.TEXT_NODE) {
+      return "";
+    }
+
+    var data = textNode.textContent;
+
+    // Sometimes the offset can be at the 'length' of the data.
+    // It might be a bug with this 'experimental' feature
+    // Compensate for this below
+    if (offset >= data.length) {
+      offset = data.length - 1;
+    }
+
+    // Ignore the cursor on spaces - these aren't words
+    if (isW(data[offset])) {
+      return "";
+    }
+
+    // Scan behind the current character until whitespace is found, or beginning
+    i = begin = end = offset;
+    while (i > 0 && !isW(data[i - 1])) {
+      i--;
+    }
+    begin = i;
+
+    // Scan ahead of the current character until whitespace is found, or end
+    i = offset;
+    while (i < data.length - 1 && !isW(data[i + 1])) {
+      i++;
+    }
+    end = i;
+
+    // This is our temporary word
+    var word = data.substring(begin, end + 1);
+
+    // Demo only
+    showBridge(null, null, null);
+
+    // If at a node boundary, cross over and see what 
+    // the next word is and check if this should be added to our temp word
+    if (end === data.length - 1 || begin === 0) {
+
+      var nextNode = getNextNode(textNode);
+      var prevNode = getPrevNode(textNode);
+
+      // Get the next node text
+      if (end == data.length - 1 && nextNode) {
+        var nextText = nextNode.textContent;
+
+        // Demo only
+        showBridge(word, nextText, null);
+
+        // Add the letters from the next text block until a whitespace, or end
+        i = 0;
+        while (i < nextText.length && !isW(nextText[i])) {
+          word += nextText[i++];
+        }
+
+      } else if (begin === 0 && prevNode) {
+        // Get the previous node text
+        var prevText = prevNode.textContent;
+
+        // Demo only
+        // HST: showBridge(word, null, prevText);
+
+        // Add the letters from the next text block until a whitespace, or end
+        i = prevText.length - 1;
+        while (i >= 0 && !isW(prevText[i])) {
+          word = prevText[i--] + word;
+        }
+      }
+    }
+    return word;
+  }
+
+  // Return the word the cursor is over
+  $hoverText.mousemove(function(e) {
+    var word = getFullWord(e);
+    if (word !== "") {
+       var res=$("#result");
+       var pageX = event.pageX;
+       var pageY = event.pageY;
+       //var parentOffset = jQuery('ul li.large', this).parent().offset();
+       //var relX = pageX - parentOffset.left;
+       //var relY = pageY - parentOffset.top; 
+
+       res.css("left",pageX + "px").css("top",pageY + "px");
+       res.text(word);
+    }
+  });
+});
+
+// Helper functions
+
+// Whitespace checker
+function isW(s) {
+  return /[ \f\n\r\t\v\u00A0\u2028\u2029]/.test(s);
+}
+
+// Barrier nodes are BR, DIV, P, PRE, TD, TR, ... 
+function isBarrierNode(node) {
+  return node ? /^(BR|DIV|P|PRE|TD|TR|TABLE)$/i.test(node.nodeName) : true;
+}
+
+// Try to find the next adjacent node
+function getNextNode(node) {
+  var n = null;
+  // Does this node have a sibling?
+  if (node.nextSibling) {
+    n = node.nextSibling;
+
+    // Doe this node's container have a sibling?
+  } else if (node.parentNode && node.parentNode.nextSibling) {
+    n = node.parentNode.nextSibling;
+  }
+  return isBarrierNode(n) ? null : n;
+}
+
+// Try to find the prev adjacent node
+function getPrevNode(node) {
+  var n = null;
+
+  // Does this node have a sibling?
+  if (node.previousSibling) {
+    n = node.previousSibling;
+
+    // Doe this node's container have a sibling?
+  } else if (node.parentNode && node.parentNode.previousSibling) {
+    n = node.parentNode.previousSibling;
+  }
+  return isBarrierNode(n) ? null : n;
+}
+
+// REF: http://stackoverflow.com/questions/3127369/how-to-get-selected-textnode-in-contenteditable-div-in-ie
+function getChildIndex(node) {
+  var i = 0;
+  while( (node = node.previousSibling) ) {
+    i++;
+  }
+  return i;
+}
+
+// All this code just to make this work with IE, OTL
+// REF: http://stackoverflow.com/questions/3127369/how-to-get-selected-textnode-in-contenteditable-div-in-ie
+function getTextRangeBoundaryPosition(textRange, isStart) {
+  var workingRange = textRange.duplicate();
+  workingRange.collapse(isStart);
+  var containerElement = workingRange.parentElement();
+  var workingNode = document.createElement("span");
+  var comparison, workingComparisonType = isStart ?
+    "StartToStart" : "StartToEnd";
+
+  var boundaryPosition, boundaryNode;
+
+  // Move the working range through the container's children, starting at
+  // the end and working backwards, until the working range reaches or goes
+  // past the boundary we're interested in
+  do {
+    containerElement.insertBefore(workingNode, workingNode.previousSibling);
+    workingRange.moveToElementText(workingNode);
+  } while ( (comparison = workingRange.compareEndPoints(
+    workingComparisonType, textRange)) > 0 && workingNode.previousSibling);
+
+  // We've now reached or gone past the boundary of the text range we're
+  // interested in so have identified the node we want
+  boundaryNode = workingNode.nextSibling;
+  if (comparison == -1 && boundaryNode) {
+    // This must be a data node (text, comment, cdata) since we've overshot.
+    // The working range is collapsed at the start of the node containing
+    // the text range's boundary, so we move the end of the working range
+    // to the boundary point and measure the length of its text to get
+    // the boundary's offset within the node
+    workingRange.setEndPoint(isStart ? "EndToStart" : "EndToEnd", textRange);
+
+    boundaryPosition = {
+      node: boundaryNode,
+      offset: workingRange.text.length
+    };
+  } else {
+    // We've hit the boundary exactly, so this must be an element
+    boundaryPosition = {
+      node: containerElement,
+      offset: getChildIndex(workingNode)
+    };
+  }
+
+  // Clean up
+  workingNode.parentNode.removeChild(workingNode);
+
+  return boundaryPosition;
+}
+
+// DEMO-ONLY code - this shows how the word is recombined across boundaries
+function showBridge(word, nextText, prevText) {
+  if (nextText) {
+    $("#bridge").html("<span class=\"word\">" + word + "</span>  |  " + nextText.substring(0, 20) + "...").show();
+  } else if (prevText) {
+    $("#bridge").html("..." + prevText.substring(prevText.length - 20, prevText.length) + "  |  <span class=\"word\">" + word + "</span>").show();
+  } else {
+    $("#bridge").hide();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hoverDemo.html	Sat Mar 23 17:34:03 2019 +0000
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <title>Hover demo</title>
+  </head>
+  <style>
+.kinovar { color:red; font-size:20px;}
+.slavic { color: blue;}
+#result {top:10px;left:10px;}
+.floater { position: fixed; background-color:white; border:2px solid
+    black; padding:4px;}
+.word { color:blue;}
+  </style>
+<script
+src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
+<script src="findWord.js"></script>
+ <div id="bridge" class="floater"></div>
+ <div id="result" class="floater"></div>
+    <h1>Hover demo</h1>
+ <div id="hoverText">
+<p><span class="kinovar"><span id="selection_index3337"
+class="selection_index"></span>По f7-мъ часЁ твори1тъ сщ7eнникъ начaло
+съ кади1ломъ и3 со свэщeю, цrкимъ двeремъ tвeрзєннымъ, и3 поeтъ:
+Х</span>rт0съ воскRсе: <span class="kinovar">со стіхи2. И# по стісёхъ
+pал0мъ: Б</span>лгcви2 душE моS гDа: <span class="kinovar">И#
+є3ктеніA. Тaже каfjсма nбhчнаz.</span></p>
+<div class="slavic"> <input value="Works around other tags!"></input>
+	<p><span
+id="selection_index3737" class="selection_index"></span>(л. рo7з
+њб.)</p>
+	<p><span class="kinovar"><span id="selection_index3738"
+class="selection_index"></span>Во вт0рникъ вeчера</span> </p>
+	<p><span
+class="kinovar"><span id="selection_index3739"
+class="selection_index"></span>tдaніе прaздника
+пaсхи.</span></p>
+	<p><span class="kinovar"><span
+id="selection_index3740" class="selection_index"></span>По f7-мъ часЁ
+твори1тъ сщ7eнникъ начaло съ кади1ломъ и3 со свэщeю, цrкимъ двeремъ
+tвeрзєннымъ, и3 поeтъ: Х</span>rт0съ воскRсе: <span class="kinovar">со
+стіхи2. И# по стісёхъ pал0мъ: Б</span>лгcви2 душE моS гDа: <span
+class="kinovar">И# є3ктеніA. Тaже каfjсма nбhчнаz.<input value="Works
+around inline tags too"></input></span></p>
+	<p><span class="kinovar"><span
+id="selection_index3741" class="selection_index"></span>На ГDи
+воззвaхъ: поeмъ стіхи6ры самоглaсны, слэпaгw, на ѕ7. Глaсъ
+в7:</span></p>
+    </div>
+</div>
+  <body>
+
+
+
+    <hr/>
+    <address><a href="mailto:ht@inf.ed.ac.uk">Henry S. Thompson</a></address>
+<!-- Created: Sat Mar 23 17:06:33 GMTST 2019 -->
+<!-- hhmts start -->
+Last modified: Sat Mar 23 17:14:05 GMTST 2019
+<!-- hhmts end -->
+  </body>
+
+</html>