Rangy: word under caret (again)

若如初见. 提交于 2019-12-06 12:27:22

As Rangy uses a global window.rangy variable, I think I'll have to use version 1.2.2 anyway.

Having read Rangy's code, I had the intuition that probably it would be feasible to load two versions of Rangy in the same page. I did a google search and found I was right. Tim Down (creator of Rangy) explained it in an issue report. He gave this example:

<script type="text/javascript" src="/rangy-1.0.1/rangy-core.js"></script>
<script type="text/javascript" src="/rangy-1.0.1/rangy-cssclassapplier.js"></script>

<script type="text/javascript">
    var rangy1 = rangy;
</script>

<script type="text/javascript" src="/rangy-1.1.2/rangy-core.js"></script>
<script type="text/javascript" src="/rangy-1.1.2/rangy-cssclassapplier.js"></script>

So you could load the version of Rangy that your code wants. Rename it and use this name in your code, and then load what wysihtml5 wants and leave this version as rangy.

Otherwise, having to implement expand yourself in a way that faithfully replicates what Rangy 1.3 does is not a simple matter.

Here's an extremely primitive implementation of code that would expand selections to word boundaries. This code is going to be tripped by elements starting or ending within words.

var word_sep = " ";

function expand() {
    var sel = rangy.getSelection();
    var range = sel.getRangeAt(0);

    var start_node = range.startContainer;
    if (start_node.nodeType === Node.TEXT_NODE) {
        var sep_at = start_node.nodeValue.lastIndexOf(word_sep, range.startOffset);
        range.setStart(start_node, (sep_at !== -1) ? sep_at + 1 : 0);
    }

    var end_node = range.endContainer;
    if (end_node.nodeType === Node.TEXT_NODE) {
        var sep_at = end_node.nodeValue.indexOf(word_sep, range.endOffset);
        range.setEnd(end_node, (sep_at !== -1) ? sep_at : range.endContainer.nodeValue.length);
    }
    sel.setSingleRange(range);
}

Here's a fiddle for it. This should work in rangy 1.2.2. (It would even work without rangy.)

For those interested, based in @Louis suggestions, I made this JsFiddle that shows a wysihtml5 integration to know the currently typed word.

It doesn't need the use of the expand function that is in rangy 1.3 which is still an alpha release.

http://jsfiddle.net/zPxSL/2/

$(function () {

    $('#txt').wysihtml5();

    var editor = $('#txt').data("wysihtml5").editor;

    $(".wysihtml5-sandbox").contents().find("body").click(function(e) {
        getCurrentlyTypedWord();
    });
    $(".wysihtml5-sandbox").contents().find("body").keydown(function(e) {
        getCurrentlyTypedWord();
    });

    function getCurrentlyTypedWord() {
        var iframe = this.$("iframe.wysihtml5-sandbox").get(0);
        var sel = rangy.getIframeSelection(iframe);
        var wordSeparator = " ";
        if (sel.rangeCount > 0) {
            var selectedRange = sel.getRangeAt(0);
            var isCollapsed = selectedRange.collapsed;
            var isTextNode = (selectedRange.startContainer.nodeType === Node.TEXT_NODE);
            var isSimpleCaret = (selectedRange.startOffset === selectedRange.endOffset);
            var isSimpleCaretOnTextNode = (isCollapsed && isTextNode && isSimpleCaret);
            // only trigger this behavior when the selection is collapsed on a text node container,
            // and there is an empty selection (this means just a caret)
            // this is definitely the case when an user is typing
            if (isSimpleCaretOnTextNode) {
                var textNode = selectedRange.startContainer;
                var text = textNode.nodeValue;
                var caretIndex = selectedRange.startOffset;
                // Get word begin boundary
                var startSeparatorIndex = text.lastIndexOf(wordSeparator, caretIndex);
                var startWordIndex = (startSeparatorIndex !== -1) ? startSeparatorIndex + 1 : 0;
                // Get word end boundary
                var endSeparatorIndex = text.indexOf(wordSeparator, caretIndex);
                var endWordIndex = (endSeparatorIndex !== -1) ? endSeparatorIndex : text.length
                // Create word range
                var wordRange = selectedRange.cloneRange();
                wordRange.setStart(textNode, startWordIndex);
                wordRange.setEnd(textNode, endWordIndex);
                console.debug("Word range:", wordRange.toString());
                return wordRange;
            }
        }
    }


});
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!