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

Событие триггера на новой строке в содержимом editable div

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

В моей книге, кажется, есть четыре события, которые приведут к тому, что пользователь будет на новой строке в контентном div:

  • нажмите enter
  • вставка содержимого с пустой строкой в ​​конце
  • щелчок, заставляющий каретку (мигающую линию) перемещать позицию в пустую строку
  • с помощью клавиш со стрелками для перехода к новой строке

Конечно, в контентной div новая строка означает разные вещи для разных браузеров, в хроме кажется, что создает теги <div><br/></div>, но, просматривая вокруг SO достаточно, кажется, что другие браузеры могут создать <div><p></p></div> или, возможно, <span> теги.

Теперь я попытался это выяснить пару раз и просто должен сделать это. Действительно ли это лучший способ прослушать новые элементы, добавляемые под этим div, и/или проверить, находится ли позиция каретки в пустых тегах "новой строки". проверяя каждый раз, когда шаги каретки кажутся крайне неэффективными - есть ли лучший способ сделать это?

Подводя итог для TL;DR; люди

  • Есть ли лучший способ проверить новые строки в содержимом редактируемых div?
  • как я могу инициировать событие, основанное на этом эффективно?

Просто fyi это в контексте Angular, и у меня также есть jQuery (ответ может выбрать использование или не использование этих библиотек).

----- edit -----

До сих пор ответы были сосредоточены на создании новых событий "событий" и мониторинге этих событий, возможно, опрос позиции каретки - более надежный способ определить, находится ли каретка в пустой строке или нет.

4b9b3361

Ответ 1

В других ответах до сих пор обсуждалось отслеживание событий, которые создают новую строку в редакторе content editable. Однако из тех усилий, которые были предприняты до сих пор, кажется, что это не надежный способ контроля, если пользователь привел каретку на новую строку.

Несмотря на то, что наличие события setInterval неудобно и добавляет накладные расходы, возможно, это только мое восприятие. Я тестировал ниже в Firefox и Chrome на OSX.

function getNewLines() {
  console.log(document.getSelection());
  if (document.getSelection().anchorNode) {
    var node = document.getSelection().anchorNode;
    var nodeContents = "";
    if (node.innerHTML) {
      nodeContents = node.innerHTML.toLowerCase();
    } else {
      nodeContents = node.innerHTML;
    }
    if (nodeContents !== undefined) {
      if (nodeContents === "" || nodeContents == "<br>" || nodeContents ==
        "<br/>" || nodeContents.substr(nodeContents.length - 5) == "<br/>" ||
        nodeContents.substr(nodeContents.length - 4) == "<br>") {
        console.log("you are on a new line :]");
      } else {
        console.log('nope not a new line');
      }
    } else {
      console.log('nice try, but no not a new line');
    }
  }
}
setInterval(getNewLines, 100);
<div contenteditable="true">
  <p>Lets get started!</p>
</div>

Ответ 2

Это то, что я сделал:

$("#main").keyup(function (e) {
    if (e.which == 13) {
        doSomething();
    }
});
$("#main").on("click", "div:has(br)", function () {
    doSomething();
});
$("#main").on("paste", function () {
    setTimeout(function () {
        debugger;
        if ($('#main').children().last().children().last().has('br').length >0) {
            doSomething();
        }
    }, 100);
});

function doSomething(){
   alert("new line...");
}

Вот демон JSFiddle

Ответ 3

Я тестировал этот код на Chrome и Edge. Edge удалил пустую строку при копировании и вставке из блокнота.

http://codepen.io/tzach/pen/XbGWjZ?editors=101

angular
    .module('app', [])
    .directive('contenteditable', function ($timeout) {
        return {
            link: function($scope, element, attrs) {

                element.css('white-space', 'pre');

                element.on('keypress', function (e) {
                    if (e.keyCode === 13) {
                        $timeout(function () {
                            onNewLine();
                        }, 100);
                    }
                });

                element.on('paste', function (e) {
                    $timeout(function () {
                        var text = element.text();
                        var textRows = text.split('\n');

                        var html = element.html();
                        var htmlRows = html.split('<br>');

                        if (textRows[textRows.length - 1].trim() == '' ||
                            htmlRows[htmlRows.length - 1].trim() == '') {
                                onNewLine();
                        }
                    },0);
                });

                element.on('click', function(e) {
                    var html = e.target.innerHTML;
                    var text = e.target.innerText;
                    if (text === '\n' || html.toLowerCase() === '<br>') {
                        onNewLine();
                    }
                });

                function onNewLine() {
                    alert('new empty line');
                }
            }
        }
    });

Ответ 4

Здесь вы начинаете. Я даже не стал бы пытаться угадать различные версии браузера. Вместо этого закрепите его, нажав фокус на скрытое текстовое поле, а затем проверив на основе новой строки (например, textarea.value.match(/\n$/)).

Это должно обрабатывать все варианты использования, а остальное просто подталкивать каретку и выбирать по диапазону. Существуют плагины, которые существуют только для этой цели.

JavaScript

var contentEditable = document.querySelector('.content pre'),
    textarea = document.querySelector('.content textarea');

contentEditable.addEventListener('click', function() {
    textarea.focus();
    contentEditable.classList.add('pseudo-focus');
});
textarea.addEventListener('keyup', function(e) {
    contentEditable.innerText = textarea.value;

    if (textarea.value.match(/\n$/)) {
        alert('newline');
    }
});

HTML

<div class="content">
    <pre id="editable" contenteditable></pre>
    <textarea></textarea>
</div>

Пример JSFiddle