Подтвердить что ты не робот

JQuery/Javascript - выделение синтаксиса как пользовательские типы в contentEditable регионе

Я создаю область 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/

Заранее благодарим за помощь.

4b9b3361

Ответ 1

Мне понравилась эта проблема, и я очень много работал, чтобы ее решить. По-моему, я, наконец, добился успеха (с небольшой помощью).

= UPDATED =

Часть кода:

[...]

// 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("");
    }
}

Скриншот:

sCREENSHOT 2

JSFiddle здесь: http://jsfiddle.net/hayatbiralem/9Z3Rg/11/

Необходимые внешние ресурсы:

Помощник Вопрос (спасибо): заменить innerHTML в contenteditable div

Инструмент тестирования Regex (спасибо): http://www.pagecolumn.com/tool/regtest.htm

Ответ 2

Имейте в виду, что разметка HTML, введенная пользователем, может быть довольно удивительной, например: <span>@use</span><span>rname</span>, которая по-прежнему выглядит как @username для пользователя.

Чтобы избежать сумасшедшего поведения каретки (и некоторых других неприятных побочных эффектов) внутри элемента contentEditable, вы должны использовать W3C DOM API и ходить дерево DOM каждый раз, когда происходит изменение HTML (вы можете нюхать изменение путем опроса body.innerHTML по таймеру).

Недавно я ответил на аналогичный вопрос для CKEditor и описал алгоритм построения карты DOM для преобразования текста в node, для нахождения текстовое совпадение. CKEditor DOM API очень похож на W3C, вы можете адаптировать тот же алгоритм.

Как только совпадение найдено, вы должны использовать DOM Range API для управления содержимым узлов DOM. Например, чтобы обернуть прогон обычного текста со стильным <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, на который нужно ответить здесь.

Ответ 3

Это похоже на решение вашей проблемы.

DEMO здесь: 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. Так что это еще нужно исправить. Я буду обновлять решение, если смогу его найти. Между тем, просто поиграйте с тем, что я предоставил сейчас, и посмотрим, поможет ли это.

Ответ 4

Как заметил Эзос в своем ответе, я бы не рекомендовал делать что-либо интенсивное (например, чтобы 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/

Я думаю, что приведенный выше код должен начать вас в правильном направлении. Как вы сказали, курсор все равно будет прыгать, поэтому вам придется его сохранять и reset в своем старом положении при каждом редактировании содержимого div. Кроме того, вы хотите настроить таймаут в зависимости от того, как долго вы ожидаете определить, существует ли имя пользователя. Вам нужно заменить // Magic на вашу проверку имени пользователя и соответствующим образом скорректировать возвращаемое значение.

Как и в сторону, вы хотите иметь в виду проблемы доступности с оберткой определенных вещей в span (см. эту проблему GitHub для Lettering.js для примера).

Изменить: Также обратите внимание, что это не надежное решение (например, он не реагирует на копирование пасты). YMMV.

Ответ 5

Метод, который вы используете, очень интенсивно работает в браузере и может вызвать некоторые проблемы, если кто-то очень быстро набирает и запускает несколько запросов до того, как "String" может быть проверен с помощью ajax. Вам может быть лучше, если вы используете библиотеку, такую ​​как http://aehlke.github.io/tag-it/ - Вы можете отобразить функцию для изменения цвета шрифта и т.д. Таким же образом он рекомендует тег.

Если я получу время, я сделаю демонстрацию скрипта.