MTJ
MTJ

Reputation: 1097

Altering CKEditor HTML content after instanceReady and paste

I need to add contenteditable="false" on all CKEditor content elements having CSS class="readonly" and contenteditable="true" to elements having CSS class="writable". Preferably on paste and instance ready.

I know of config.on.instanceReady and config.on.paste but what should I write into the function just eludes me ;)

Btw. I'm not using inline editor.

editor.document is listed as read only property in the documentation so I cannot use that.

Final solution thanks to Oleq for showing me to the right path. applyToAll is required if writables are within readonly.

 // Add custom rule to dataFilter (when data comes *into* editor).
 on{pluginsLoaded: function (evt){
 this.dataProcessor.dataFilter.addRules( {
     elements: {
         $: function ( element ) {
             if (element.hasClass('readonly'))
             {
                 element.attributes.contenteditable = 'false';
             }

             if (element.hasClass('writable'))
             {
                 element.attributes.contenteditable = 'true';
             }
         }
     }
  },{applyToAll: true});


  this.dataProcessor.htmlFilter.addRules( {
      elements: {
          $: function ( element ) {
              if(element.hasClass('readonly') || element.hasClass('writable'))
              {
                  delete element.attributes.contenteditable;
              }
          }
      }
  },{applyToAll: true});

  });

Upvotes: 1

Views: 1762

Answers (2)

oleq
oleq

Reputation: 15895

You should use CKEditor's dataProcessor.dataFilter. This is the standard mechanism used by the editor to filter input (JSFiddle). It handles data set with editor.setData, data pasted by the user and, of course, initial HTML from textarea or any element to which CKEditor is attached.

CKEDITOR.replace( 'my-editor', {
    // See http://stackoverflow.com/a/15659962/1485219
    extraAllowedContent: 'span(readonly)',

    // Just to make the interface clear.
    toolbarGroups: [
        {"name":"document","groups":["mode"]},
        {"name":"basicstyles","groups":["basicstyles"]}
    ],
    on: {
        // When all plugins were loaded but editor data is not yet processed.
        pluginsLoaded: function( evt ) {
            // Add custom rule to dataFilter (when data comes *into* editor).
            this.dataProcessor.dataFilter.addRules( {
                elements: {
                    // Check all elements. Rules can be specific, i.e. for img or h2.
                    $: function( element ) {
                        if ( element.hasClass( 'readonly' ) ) {
                            element.attributes.contenteditable = "false";
                        }
                    }
                }
            } );
        }
    }
} );

EDIT: I created you a widget (JSFiddle) because I feel this is what you really wanted to do:

// This plugin brings a widget into editor.
CKEDITOR.plugins.add( 'myFirstWidget', {
    // Widget plugin must be loaded (must be present in the build of CKEditor).
    requires: 'widget',

    init: function( editor ) {
        editor.widgets.add( 'myFirstWidget', {        
            button: 'My First Widget Button',

            // http://stackoverflow.com/a/15659962/1485219
            allowedContent: 'span(readonly)',                            
            requiredContent: 'span(readonly)',

            // Make all <span class="readonly"> a non-editable widget. 
            upcast: function( element ) {
                return element.name == 'span' && element.hasClass( 'readonly' );
            }
        } );        
    }
} );

CKEDITOR.replace( 'my-editor', {
    // Use the plugin.
    extraPlugins: 'myFirstWidget',

    // Just to make the interface clear.
    toolbar: [ [ 'Source', '-', 'MyFirstWidget' ] ]
} );

Learn more about widgets and awesomeness they bring.

Upvotes: 1

97ldave
97ldave

Reputation: 5249

You could do this in JavaScript:

var readOnlyEls = document.querySelectorAll('.readonly');
for (var i=0; i < readOnlyEls.length; i++) {
    readOnlyEls[i].setAttribute("contenteditable", false);
}

var writableEls = document.querySelectorAll('.writable');
for (var i=0; i < writableEls .length; i++) {
    writableEls[i].setAttribute("contenteditable", true);
}

Or if you are using jQuery:

$(".readonly").attr("contenteditable", false);
$(".writable").attr("contenteditable", true);

Upvotes: 0

Related Questions