GetmeUK / ContentTools

A JS library for building WYSIWYG editors for HTML content.
http://getcontenttools.com
MIT License
3.96k stars 398 forks source link

losing styles and fonts when adding a new paragraph #379

Closed senthil49 closed 7 years ago

senthil49 commented 7 years ago

Hi, whats your recommendation to retain styles/fonts from previous paragraph if we do manage to insert a new para? or is there a better way to add new paragraphs that am missing?

anthonyjb commented 7 years ago

Hi @senthil49 - hopefully this code will give you a starting point:

    // Listen for mount events
    ContentEdit.Root.get().bind('mount', function(element) {

      // Check the element attached is a text element
      if (element.type() !== 'Text') {
        return;
      }

      // Check the element is a paragraph
      if (element.tagName() !== 'p') {
        return;
      }

      // Check the element is a new (empty) paragraph
      if (element.content.length() > 0) {
        return;
      }

      // Get the previous node that supports content
      var previousElement = element.previousContent()

      // Check it's also a paragraph
      if (!previousElement || previousElement.tagName() !== 'p') {
        return;
      }

      // Apply the class and style attributes for the previous paragraph to the
      // new one.
      if (previousElement.attr('class')) {
        var classes = previousElement.attr('class').split(' ');
        for (var i = 0; i < classes.length; i++) {
          element.addCSSClass(classes[i]);
        }
      }
      element.attr('style', previousElement.attr('style'));

    });

The approach I've taken here is to listen for the mount event, determine if a new paragraph has been mounted, find the previous paragraph (if there is one) and then copy any styles for it over to the new paragraph.

senthil49 commented 7 years ago

great! thats helpful.

mansooraziz commented 7 years ago

Hi @anthonyjb, I have implemented the above solution, I had to take off this check if (element.content.length() > 0) as it wouldn't work when the paragraph is split into two. It works fine but the problem is that this 'mount' event is also being called on page load, which is unnecessarily copying styles to next p tags. I only want this to be called when 'Enter' key is pressed. At the moment I have created a flag like ContentEdit.Root.EnterPressed which is being set in Text.prototype._keyReturn function, and the mounting code is wrapped within the if check. like:

// Listen for mount events
ContentEdit.Root.get().bind('mount', function(element) {
if (ContentEdit.Root.EnterPressed == true){
  ....
  //do copying styles
  ....
  //unset the enter flag
  ContentEdit.Root.EnterPressed = false;
  }
}

Can you please confirm if there is any better way of doing this?

anthonyjb commented 7 years ago

Hi @mansooraziz,

So taking of the content.length() test will mean that when the editor starts you get styles copied between every paragraph in a cascading style (which I think is what you are describing).

Possibly a better approach is to consider overwriting the _keyReturn method for ContentEdit.Text to handle copying paragraph styles. However the approach you've stated is the only simple way around the issue I can think of currently.

I will have a look at this moving forward though because it would be a useful feature/behaviour to havein the ContentEdit library.

mansooraziz commented 7 years ago

Hi @anthonyjb Thanks for your reply, I have update the _keyReturn method, can you please have a look if it's looks fine?

Text.prototype._keyReturn = function (ev) { ..... .... .. var styleValues = this.getStyleValues(['font', 'color']); //copy selected styles from current P tag element = new this.constructor('p', { style: styleValues }, tail); .. .... ..... }

Element.prototype.getStyleValues = function (stylesToCopy) { try {
var currentParagraphStyles = this.attr('style').split(';'); var stylesToApply = []; currentParagraphStyles.forEach(function (style) { style = style.trim(); stylesToCopy.forEach(function (styleToCopy) { if (style.indexOf(styleToCopy) >= 0 && stylesToApply.indexOf(style) < 0) { stylesToApply.push(style); } }); }); //we dont neeed margins to be added for new P tag unless it was requested in parameter if (stylesToApply.indexOf('margin') < 0){
stylesToApply.push('margin: 0;'); }

    return stylesToApply.join(';');

} catch (err) {
    return "";
}            

}

mansooraziz commented 7 years ago

There is another modification we had to do i.e. at the moment if user press enter more than once it doesn't allow creation of multiple lines ( i mean empty P tags), We added an option (ContentEdit.PRUNE_BLANK_LINES ) and modified whitespace check in _keyReturn as below

// Only add an empty paragraph if PRUNE_BLANK_LINES is not set if (ContentEdit.PRUNE_BLANK_LINES && this.content.isWhitespace()) { return; }

But to make it work we had to take out .trim() from many places, because it trims all the empty P tags that we want to keep. It would be great if trimming empty P tags is configurable option.

senthil49 commented 7 years ago

Hi @anthonyjb, Thanks for your help so far. Can you please take a look at mansoor's question?

anthonyjb commented 7 years ago

Hi @senthil49 @mansooraziz please see this discussion on the topic of empty paragraphs here: https://github.com/GetmeUK/ContentTools/issues/298