ContentEditable div - all HTML after the first 

2019-02-27 09:50发布

问题:

I've been working on a condenteditable div, whereby I highlight text when it goes over a defined maximum length.

Codepen here: http://codepen.io/doublesidedstickytape/pen/NqBMXR

It works out OK - unless a user press Return - then it breaks!

I'm thinking that I could could get all the HTML content after the first [x] amount of characters, then loop through each of the elements (which act as new lines) - to wrap a highlight class around them in my hidden div.

I'm not sure how to achieve this though.

HTML

<div class="wrapper">
  <div contenteditable="true" data-maxlength="10" class="editable"></div>
  <div contenteditable="true" class="readonly"></div>
</div>

JS

$(document).on("keyup", "div.editable", function(event) {

  // GOOD TO STORE THIS IN A VAR
  // PREVENTS THE BROWSER HAVING TO 
  // FIGURE OUT WHAT $(this) IS
  // EACH TIME YOU CALL IT
  var element = $(this);

  // KEYUP  
  if (event.type == "keyup") {

    var maximumLength = element.attr("data-maxlength");
    var currentLength = element.text().length;
    var content = element.text();

    // CURRENT LENGTH IS GREATER THAN
    // THE SPECIFIED MAXIMUM LENGTH
    if (currentLength > maximumLength) {
      var over = element.html().substr(maximumLength);
      over = "<span class='highlight'>" + over + "</span>";
      content = element.html().substr(0, maximumLength) + over;
    }
    $("div.readonly").html(content);

  }

});

CSS

body {
  margin: 0 auto;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 1em;
  line-height: 1.4em;
  color: #444;
}

div.wrapper {
  position: relative;
  margin-top: 15px;
}

div.editable,
div.readonly {
  width: 300px;
  white-space: wrap;
  position: absolute;
  top: 0;
  left: 0;
}

div.editable {
  border-bottom: 1px solid #00aeed;
  outline: none;
}

div.readonly {
  z-index: -99;
  color: transparent;
  background: transparent;
}

span.highlight {
  background: #fcc !important;
}

$(document).on("keyup", "div.editable", function(event) {

  // GOOD TO STORE THIS IN A VAR
  // PREVENTS THE BROWSER HAVING TO 
  // FIGURE OUT WHAT $(this) IS
  // EACH TIME YOU CALL IT
  var element = $(this);

  // KEYUP  
  if (event.type == "keyup") {

    var maximumLength = element.attr("data-maxlength");
    var currentLength = element.text().length;
    var content = element.text();

    // CURRENT LENGTH IS GREATER THAN
    // THE SPECIFIED MAXIMUM LENGTH
    if (currentLength > maximumLength) {
      var over = element.html().substr(maximumLength);
      over = "<span class='highlight'>" + over + "</span>";
      content = element.html().substr(0, maximumLength) + over;
    }
    $("div.readonly").html(content);

  }

});
body {
  margin: 0 auto;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 1em;
  line-height: 1.4em;
  color: #444;
}
div.wrapper {
  position: relative;
  margin-top: 15px;
}
div.editable,
div.readonly {
  width: 300px;
  white-space: wrap;
  position: absolute;
  top: 0;
  left: 0;
}
div.editable {
  border-bottom: 1px solid #00aeed;
  outline: none;
}
div.readonly {
  z-index: -99;
  color: transparent;
  background: transparent;
}
span.highlight {
  background: #fcc !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<div class="wrapper">
  <div contenteditable="true" data-maxlength="10" class="editable"></div>
  <div contenteditable="true" class="readonly"></div>
</div>

回答1:

I have worked out a solution, see: http://jsfiddle.net/alan0xd7/6o1sr5fg/

  • If there are text that needs highlighting, first we just copy over the content HTML to div.readonly for further processing. If no highlighting is required, we just empty the div.

  • The collectTextNodes() function iterates through all the DOM nodes in the content HTML, and collects all text nodes. The collected nodes would only contain text, and no child nodes.

  • For all the text nodes we collected, we run them through the highlight() function to highlight the text.

  • highlight() works by first skipping maximumLength number of characters, then wrap everything in <span class='highlight'>.