gael gael - 6 months ago 21
Javascript Question

How to preserve multiple <br> when no content before or after with ContentTools

I noticed ContentTools (a wysiwyg editor) remove multiple

<br>
tags at the beginning or the ending of a
<p>
, when no content precedes or follows the
<br>
.

<p>
<br><br><br><br>
some text
<br><br><br><br>
</p>


Becomes when i save the document

<p>
some text
</p>


I'd like to preserve all the
<br>
tags to allow user to align vertically their content. How to do this ?

Answer

ContentTools default behaviour is to trim white space from standard text elements (e.g paragraphs, headings, etc). There's no setting to modify this behaviour (at least not at the moment), but if you need this behaviour you can patch the library to achieve this.

How you apply the patch is up to you, for long term support it would be better to fork the ContentEdit and ContentTools libraries, make the updates to the CoffeeScript and build a custom version of the ContentTools library, that way at least you can easily merge in future updates (it's a youngish library right now so we make updates frequently).

Alternatively if you want a quick solution right now you can modify the content-tools.js in the build folder (though you might then want to manually minify it).

I'll describe the JS changes that are required here (but they're equally easy to make to the CoffeeScript (as they're pretty much identical):

Find the function Text constructor code:

function Text(tagName, attributes, content) {
  Text.__super__.constructor.call(this, tagName, attributes);
  if (content instanceof HTMLString.String) {
    this.content = content;
  } else {
    this.content = new HTMLString.String(content).trim();
  }
}

and modify the line

this.content = new HTMLString.String(content).trim();

to

this.content = new HTMLString.String(content, true);

This tells the string to preserve white space and we've removed the call to trim which would remove all white space characters from the string (including <br> elements).

Then we need to modify the HTML method, find the html function for the Text element:

Text.prototype.html = function(indent) {
  var content;
  if (indent == null) {
    indent = '';
  }
  if (!this._lastCached || this._lastCached < this._modified) {
    content = this.content.copy().trim();
    content.optimize();
    this._lastCached = Date.now();
    this._cached = content.html();
  }
  return ("" + indent + "<" + this._tagName + (this._attributesToString()) + ">\n") + ("" + indent + ContentEdit.INDENT + this._cached + "\n") + ("" + indent + "</" + this._tagName + ">");
};

and modify the line

content = this.content.copy().trim();

to

content = this.content.copy();

Again here we're removing the call to trim. The string will now retain white space characters.

Finally we need to modify the method that converts DOM elements to ContentEdit.Text instances, find the fromDomElement method:

Text.fromDOMElement = function(domElement) {
  return new this(domElement.tagName, this.getDOMElementAttributes(domElement), domElement.innerHTML.replace(/^\s+|\s+$/g, ''));
};

and replace it with:

Text.fromDOMElement = function(domElement) {
  return new this(domElement.tagName, this.getDOMElementAttributes(domElement), domElement.innerHTML);
};

And that should be it, I'm sorry there's not an easier solution available right now, there's been some discussion around this previously here should you want to contribute to the debate.