JS, HTML. Гугл прикрась. Как динамически вставить предварительно подготовленный HTML-код в contenteditable div на HTML-странице

Я пишу мессенджер и моя цель добавить возможность вставлять код и выделять его, как это делается на Stack Overflow. Я использую библиотеку prettify от Google. Вот часть html:

<div id="test" style="margin-left: auto; margin-right: auto; overflow-y: scroll;" contenteditable="true"
                 placeholder="Type your message" name="message" ng-model="message">
            </div>

и js-функция:

$scope.pasteHtmlAtCaret = function () {
            document.getElementById('test').focus();
            var sel, range;
            if (window.getSelection) {
                // IE9 and non-IE
                sel = window.getSelection();
                if (sel.getRangeAt && sel.rangeCount) {
                    range = sel.getRangeAt(0);

                    // Range.createContextualFragment() would be useful here but is
                    // only relatively recently standardized and is not supported in
                    // some browsers (IE9, for one)
                    var el = document.createElement("div");
                    //var el = document.getElementById('test');

                    /*var text = sel.toString().replace(/</g, "&lt;");
                    text = text.replace(/>/g, "&gt;");
                    text = text.replace(/&/g, "&amp;");*/

                    el.innerHTML = "<pre class=prettyprint linenums><code>" + sel.toString() + '</code></pre></br>';

                    range.deleteContents();

                    var frag = document.createDocumentFragment(), node, lastNode;
                    while ((node = el.firstChild)) {
                        lastNode = frag.appendChild(node);
                    }
                    var firstNode = frag.firstChild;
                    range.insertNode(frag);
                    prettyPrint();
                    // Preserve the selection
                    if (lastNode) {
                        range = range.cloneRange();
                        range.setStartAfter(lastNode);
                        range.setStartBefore(firstNode);

                        sel.removeAllRanges();
                        sel.addRange(range);
                    }
                }
            } else if ((sel = document.selection) && sel.type != "Control") {
                var originalRange = sel.createRange();
                originalRange.collapse(true);
                sel.createRange().pasteHTML(html);

                range = sel.createRange();
                range.setEndPoint("StartToStart", originalRange);
                range.select();
            }
        }

Как видите, я уже пробовал ставить &lt; (в комментариях) и другие символы вместо символов ‹, > и &. Однако они отображаются так, как они есть в коде js, а не как символы. Подскажите, пожалуйста, как мне вставить преттифицированный html-код внутрь моего блока div (или, возможно, другого контейнера).

Возможно, вы могли бы также сказать мне, как сделать так, чтобы prettify отображал номера строк, потому что они сейчас не отображаются (они как-то воспринимаются как другой класс)


person Andrey    schedule 17.09.2016    source источник


Ответы (1)


Afaict, вы создаете <pre class=prettyprint>, но библиотека prettify на самом деле никогда не вызывается для него.

Я думаю, вы можете просто использовать PR.prettyPrintOne и передайте исходный код HTML. Вы правы в том, что вам следует избегать &, < и >, поскольку для этого требуется HTML, а не простой исходный код.

PR.prettyPrintOne доступен при загрузке <script src=".../prettify.js"></script>, но не при загрузке <script src=".../run_prettify.js"></script>.


/*var text = sel.toString().replace(/</g, "&lt;");
text = text.replace(/>/g, "&gt;");
text = text.replace(/&/g, "&amp;");*/

Здесь есть ошибка. Вы должны сначала выполнить .replace(/&/g, "&amp;"), потому что

"<".replace(/</g, "&lt;").replace(/&/g, "&amp;") === "&amp;lt;"

в то время как

"<".replace(/&/g, "&amp;").replace(/</g, "&lt;") === "&lt;"

Порядок замены имеет значение, когда некоторые строки подстановки также соответствуют шаблонам :)

function htmlEscape(s) {
  return (String(s).replace(/&/g, "&amp;")
      .replace(/</g, "&lt;")
      .replace(/>/g, "&gt;"));
}
person Mike Samuel    schedule 19.09.2016
comment
На самом деле я вызываю функцию prettyPrint() в своем коде, и она создает код из выбранной части сообщения. Вопрос был в том, как сделать так, чтобы html-код тоже подсвечивался. Но я нашел способ: я заменил тег ‹code› на тег ‹xmp›. Однако ваш совет с заменой был полезен, так что отметьте ответ как правильный - person Andrey; 22.09.2016