14

我正在我的网站上开发一个 contentEditable 区域,用户可以在其中互相键入消息。

<div contentEditable="true" class="smartText">User types here...</div>

问题是,我们将在里面有智能文本,这意味着如果用户@usersame在这个 div 中输入,如果用户名存在,则@username应该以蓝色突出显示,如果用户名不存在,则应该以绿色突出显示。当然,所有这些都应该在用户键入时发生......

我不知道从哪里开始,现在我有这个:

$("body").on("keyup",".smartText",function(){
      var $this = $(this),
          value = $this.html(),
          regex = /[^>]#\S+[^ ]/gim;
      value = value.replace(regex,"<span style='color:red'>$&</span>");
      $this.html(value);
});

但是文本一直在跳跃(以及插入符号的位置)并且感觉方向不正确。我想它有点类似于 JSFiddle,它找到了颜色代码。我基本上想要和 Twitter 一样的东西。

这是一个可以玩的 JSFiddle:http: //jsfiddle.net/denislexic/bhu9N/4/

在此先感谢您的帮助。

4

5 回答 5

14

我喜欢这个问题,我非常努力地解决了这个问题。我相信我终于成功了(在一点帮助下)。

= 更新 =

一段代码:

[...]

// formatText
formatText: function (el) {
    var savedSel = helper.saveSelection(el);
    el.innerHTML = el.innerHTML.replace(/<span[\s\S]*?>([\s\S]*?)<\/span>/g,"$1");
    el.innerHTML = el.innerHTML.replace(/(@[^\s<\.]+)/g, helper.highlight);

    // Restore the original selection
    helper.restoreSelection(el, savedSel);
}

[...]

// point
keyup: function(e){                    

    // format if key is valid
    if(helper.keyIsAvailable(e)){
        helper.formatText($this[0]);
    }

    // delete blank html elements
    if(helper.keyIsDelete && $this.text()=="") {
        $this.html("");
    }
}

截屏:

截图 2

JSFiddle在这里:http: //jsfiddle.net/hayatbiralem/9Z3Rg/11/

所需的外部资源:

帮助问题(谢谢): 替换 contenteditable div 中的 innerHTML

正则表达式测试工具(感谢): http: //www.pagecolumn.com/tool/regtest.htm

于 2014-01-29T16:54:29.303 回答
4

请记住,用户键入的 HTML 标记可能非常令人惊讶,例如:<span>@use</span><span>rname</span>,在用户看来仍然如此@username

为了避免元素内部出现疯狂的插入符号行为(以及其他一些讨厌的副作用)contentEditable,您应该使用W3C DOM API并在每次 HTML 发生更改时遍历 DOM 树(您可以通过轮询body.innerHTML计时器来嗅探更改)。

我最近为 CKEditor 回答了一个类似的问题,并描述了如何构建 DOM 的文本到节点映射以查找文本匹配的算法。CKEditor DOM API与W3C 非常相似,您可以采用相同的算法。

一旦找到匹配项,您应该使用DOM Range API来操作 DOM 节点的内容。例如,用 styled 包装一段纯文本<SPAN>

var range = document.createRange();
range.setStart(startNode, startOffset);
range.setEnd(endNode, endOffset);
var span = document.createElement("span");
span.style.backgroundColor = "blue"
range.surroundContents(span);

总的来说,这个任务非常重要,当然不是你可以放在一页 JavaScript 代码中的东西,这里要回答。

于 2014-01-29T10:38:09.807 回答
2

这似乎可以解决您的问题。

演示在这里:http: //jsfiddle.net/bhu9N/5/

$(document).ready(function() {
    $("body").on("keyup", ".editable", function(e) {
        var $this = $(this);
        if(e.keyCode==32) {//space
            var words = $this.text().split(' ');
            var lastword = $.trim(words[words.length-1]);
            var reg = /^@\S+/;
            if(reg.test(lastword)) {
                //make an AJAX call for checking this word for existence
                //suppose data is returned and data==1 means green
                var data = 1;
                if(data==1) {
                    var orgtext = $this.html();
                    orgtext = orgtext.replace(lastword, '<span class="green">'+lastword+'</span>');
                    $this.html(orgtext);
                }
            }   
        }
    });

});​

突出显示文本后,光标将转到 div 的开头。所以这仍然需要修复。如果我能找到它,我将更新解决方案。同时,只需使用我现在提供的内容,看看它是否有帮助。

于 2012-10-28T08:13:29.850 回答
1

正如 Ezos 在他的回答中指出的那样,我不建议每次用户释放密钥时都尝试做任何密集的事情(例如发出 Ajax 请求以检查用户名是否存在)。你可能过得不好。话虽如此,我建议在用户停止输入后等待一段时间,以浏览他们输入的内容并突出显示单词,例如:

var textarea = $(".smartText");
var highlightWords = function highlightWords() {
    var original = textarea.text();
    var replaced = original.replace(/@[a-zA-Z0-9]+/g, function (username) {
        // Magic
        return "<span class='exists'>" + username + "</span>";
    });
    textarea.html(replaced);
};
var timer;

textarea.keyup(function (e) {
    clearTimeout(timer);
    if ($(this).text()) {
        timer = setTimeout(highlightWords, 1000);
    }
});

链接到小提琴:http: //jsfiddle.net/neJLW/

我认为上面的代码应该让你朝着正确的方向开始。就像你说的那样,光标仍然会跳来跳去,所以每次编辑div. 此外,您需要根据您希望确定用户名是否存在需要多长时间来调整超时。您需要// Magic用您的用户名检查替换并相应地调整返回值。

顺便说一句,您需要记住将某些内容包装在spans 中的可访问性问题(有关示例,请参阅此 GitHub 问题 for Lettering.js)。

编辑:另请注意,这不是一个强大的解决方案(例如,它不会对复制粘贴做出反应)。YMMV。

于 2014-01-29T01:48:24.507 回答
0

您使用的方法似乎是浏览器密集型的,如果有人键入非常快并且在可以通过 ajax 验证“字符串”之前运行多个请求,则可能会导致一些问题。如果您使用诸如http://aehlke.github.io/tag-it/之类的库,您可能会更好- 您可以描述一个更改字体颜色等的函数,就像它推荐一个标签一样。

如果我有时间,我会做小提琴演示。

于 2014-01-29T00:36:55.730 回答