Événement de déclenchement sur une nouvelle ligne dans le contenu modifiable div

J'essaie d'écouter un événement qui indique qu'une nouvelle ligne a été créée dans un div modifiable de contenu. Le but est de montrer éventuellement à un utilisateur des options chaque fois qu'une nouvelle ligne vide est créée et que le curseur se trouve sur cette ligne, ou si l'utilisateur clique sur la position du curseur sur une ligne actuellement vide.

Dans mon livre, il semble y avoir quatre événements qui conduiraient l'utilisateur à être sur une nouvelle ligne dans un div contenediable:

  • appuyez sur Entrée
  • coller du contenu qui a une nouvelle ligne vide à la fin
  • cliquer pour déplacer le curseur (ligne clignotante) vers une ligne vide
  • utilisez les touches fléchées pour passer à une nouvelle ligne

Bien sûr, dans une div contenediable, une nouvelle ligne signifie des choses différentes pour différents navigateurs, dans chrome, il semble créer des balises <div><br/></div>, mais après avoir parcouru suffisamment, il semble que d'autres navigateurs puissent créer des balises <div><p></p></div> ou peut-être <span>.

J'ai maintenant essayé de comprendre cela plusieurs fois et suffit de le faire. Est-ce vraiment la meilleure façon d'écouter les nouveaux éléments ajoutés sous cette div, et/ou de vérifier si la position du curseur est actuellement dans les balises "nouvelle ligne" vides. vérifier chaque fois que le curseur se déplace semble très inefficace-y a-t-il une meilleure façon de le faire?

Pour résumer pour tldr; les gens

  • existe-t-il un meilleur moyen de vérifier les nouvelles lignes dans les divs modifiables de contenu?
  • comment déclencher un événement basé sur d'une façon efficace?

Juste Pour info c'est dans un contexte angulaire et j'ai aussi jQuery (la réponse peut choisir d'utiliser ou de ne pas utiliser ces bibliothèques).

----- modifier - - - - -

Jusqu'à présent, les réponses se sont concentrées sur la création de nouveaux "événements" de ligne et le suivi de ces événements, peut-être que l'interrogation de la position du curseur est un moyen plus fiable de déterminer si le curseur est sur une ligne vide ou non.

24
demandé sur David Anderton 2015-08-05 14:00:28

4 réponses

Les autres réponses à ce jour ont discuté de la surveillance des événements qui créent une nouvelle ligne dans un div modifiable de contenu. Toutefois, les efforts déployés jusqu'à présent, il semble que ce n'est pas un moyen fiable de vérifier si l'utilisateur a apporté le curseur sur une nouvelle ligne.

Malgré les préoccupations que d'avoir un événement setInterval est maladroit et ajoutant à la surcharge, peut-être que c'est juste ma perception. J'ai testé le ci-dessous dans Firefox et Chrome sur 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>

Voir Violon Ici

côté-note: le comportement des nouvelles lignes dans le contenu modifiable semble varié, mais j'ai noté dans firefox qu'il imitera les éléments existants dans le domaine. c'est-à-dire si vous utilisez <div></div>, firefox utilisera <div></div>, Si vous utilisez <p></p> firefox fera de même

11
répondu David Anderton 2015-08-14 10:55:10

C'est ce que j'ai fait:

$("#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...");
}

Ici est le JSFiddle démo

9
répondu Ahs N 2015-08-05 16:06:04

J'ai testé ce code sur Chrome et Edge. Edge a supprimé la ligne vide lorsque je copie et colle du bloc-notes.

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');
                }
            }
        }
    });
1
répondu Tzach Ovadia 2015-08-07 16:50:10

Voici un début pour vous. Je ne voudrais même pas essayer de deviner différentes implémentations de navigateur. Au lieu de cela, corrigez-le en poussant le focus vers une zone de texte cachée, puis en le testant en fonction d'une nouvelle ligne (par exemple textarea.value.match(/\n$/)).

Cela devrait gérer tous les cas d'utilisation, et le reste ne fait que simuler le caret et la sélection via la plage. Il y a des plugins qui existent juste à cette fin.

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 Exemple

1
répondu Josh Burgess 2015-08-10 20:06:41