GetmeUK / ContentTools

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

New Tool "Edit as HTML" #420

Closed aplblpsil closed 6 years ago

aplblpsil commented 7 years ago

Hi, I have a problem on my new tool wich works with CodeMirror : Content Tools does not reconizes what i'm typing on my applied tool and don't want to save it.

For exemple if I click on my tool with the base p tag, all the content editable is converted and editable directly in HTML with CodeMirror. When I disable this tool, the content changeds are displayed but the placeholder too (after my changes, maybe because of the 'ce-element--empty' class) and if I add content, the save method don't take anything. Any idea to help me ? Thanks in advance.

Screenshots : Tool applied => editgithub2017-06-19

Tool disabled after edit => githubpbplaceholder2017-06-19

Validation => capture du 2017-06-19 10 40 23

My code js :

//NEW TOOL : EDIT AS HTML 
            ContentTools.Tools.EditAsHtml = (function(_super) {
                __extends(EditAsHtml, _super);

                function EditAsHtml() {
                  return EditAsHtml.__super__.constructor.apply(this, arguments);
                }

                ContentTools.ToolShelf.stow(EditAsHtml, 'edit-html');

                EditAsHtml.label = 'Edit as HTML';

                EditAsHtml.icon = 'preformatted';

                EditAsHtml.className = 'edit-html';

                EditAsHtml.canApply = function(element, selection) {
                  return true;
                };

                EditAsHtml.isApplied = function(element, selection) {
                  var _ref, bool;
                  if (!this.canApply(element)) {
                    return false;
                  }
                  if ((_ref = element.type()) === 'ListItemText' || _ref === 'TableCellText') {
                    element = element.parent();
                  }
                  if(that.ctCodeMirror != undefined && that.ctCodeMirror.getValue() != "") {
                    bool = true;
                  }else {
                    bool = false;
                  }
                  return bool;
                };

                EditAsHtml.apply = function(element, selection, callback) {
                  var className, toolDetail, _i, _len, _ref, $container, containerDOM, content, $element, html;
                  toolDetail = {
                    'tool': this,
                    'element': element,
                    'selection': selection
                  };

                  $container = $('.content.target-animation-content-txt'); 

                  if (!this.dispatchEditorEvent('tool-apply', toolDetail)) {
                    return;
                  }
                  if ((_ref = element.type()) === 'ListItemText' || _ref === 'TableCellText') {
                    element = element.parent();
                  }
                  if(this.isApplied(element, selection)){
                    content = that.ctCodeMirror.getValue();
                    $container.empty().append(content);

                    that.ctCodeMirror = null;
                    callback(false);
                  }else{ 
                    containerDOM = $container.get().shift();
                    html = $container.html();
                    $container.empty();

                    that.ctCodeMirror = CodeMirror(containerDOM, {
                      value: html,
                      mode:  "htmlmixed"
                    });

                    CodeMirror.commands["selectAll"](that.ctCodeMirror);
                    that.ctCodeMirror.autoFormatRange(that.ctCodeMirror.getCursor(true), that.ctCodeMirror.getCursor(false));
                  }                  
                  callback(true);
                  return this.dispatchEditorEvent('tool-applied', toolDetail);
                };

                return EditAsHtml;

            })(ContentTools.Tool);

//SAVE CONTENT OVERRIDE (extract)
$inputCtContent = $('#input-ct-content');
if(regions['content-ct'] != undefined){
                    $inputCtContent.attr('value', regions['content-ct']);
                }else{
                   // console.log($('.content.target-animation-content-txt').html());
                    $inputCtContent.attr('value', $('.content.target-animation-content-txt').html());
                }

My code HTML :

<div class="content  target-animation-content-txt" data-editable="" data-name="content-ct">
            ${structure php: !empty(content) && !empty(content.contentText) ? content.contentText : null}
        </div>
anthonyjb commented 7 years ago

Hi @aplblpsil,

If you update the contents of an element you need to let the editable element (not the DOM element) in question know so it can sync it's internal copy of the contents (a HTMLString instance) with the updated HTML in the DOM. You can do this by calling _syncContent, for example:

// Modify the elements HTML content with via another library
CodeMirror.commands["selectAll"](that.ctCodeMirror);
that.ctCodeMirror.autoFormatRange(that.ctCodeMirror.getCursor(true), that.ctCodeMirror.getCursor(false));

// Sync the changes with the ContentEdit.Element
element._syncContent();
aplblpsil commented 7 years ago

Hi @anthonyjb and thanks for your answer, Unfortunetly the solution given doesn't work for me, I have the same behaviour... Method apply here :

EditAsHtml.apply = function(element, selection, callback) {
                  var className, toolDetail, _i, _len, _ref, $container, containerDOM, content, html;
                  toolDetail = {
                    'tool': this,
                    'element': element,
                    'selection': selection
                  };

                  $container = $('.content.target-animation-content-txt'); 

                  if (!this.dispatchEditorEvent('tool-apply', toolDetail)) {
                    return;
                  }
                  if ((_ref = element.type()) === 'ListItemText' || _ref === 'TableCellText') {
                    element = element.parent();
                  }
                  if(this.isApplied(element, selection)){
                    // Sync the changes with the ContentEdit.Element
                    content = that.ctCodeMirror.getValue();
                    $container.empty().append(content);
                    that.ctCodeMirror = null;
                    element._syncContent();
                  }else{
                    // $element = $(element._domElement); 
                    containerDOM = $container.get().shift();
                    html = $container.html();
                    $container.empty();

                    that.ctCodeMirror = CodeMirror(containerDOM, {
                      value: html,
                      mode:  "htmlmixed"
                    });

                    CodeMirror.commands["selectAll"](that.ctCodeMirror);
                    that.ctCodeMirror.autoFormatRange(that.ctCodeMirror.getCursor(true), that.ctCodeMirror.getCursor(false));
                    that.ctCodeMirror.on('change', function(){
                        // Sync the changes with the ContentEdit.Element
                        element._syncContent();
                    });

                  }                  
                  callback(true);
                  return this.dispatchEditorEvent('tool-applied', toolDetail);
                };

Thank you again for your help.

itsmelion commented 6 years ago

This should be a Major Feature. sometimes you just need edit the HTML.

I Implemented ContentTools on my project, in to replace an old WYSIWYG and when i get from DB some pages that contain other HTML tags like divs etc, instead of p, tables, it cant be saved nor edited. Thats really sad. 😞

anthonyjb commented 6 years ago

Hi @itsmelion - you could easily add in the ability to edit raw HTML to any system using ContentTools, the problem really is that ContentEdit (the library that enables the editing of HTML content) only supports a small subset of clean HTML and isn't designed to handle every scenario. So if you change the raw HTML to a format not supported by ContentEdit (like inserting a div) it will only pass that content as a static non-editable element.

To some extent ContentFlow (https://www.youtube.com/watch?v=HQaNrI3yJwo&t=18s) provides additional flexibility in this regard because you can define chunks of editable HTML (which can be divs) and arrange them into stacks of content. For example almost all of this site (https://www.brintons.co.uk) is edited using ContentTools and ContentFlow, it supports lots of complex layouts and the client never needs to use raw HTML.