Mercurial > hg > Aquinas
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>
