2013-04-29 6 views
6

Così sto provando ad integrare Inline Editing da CKEditor con Knockout.js. Sono in grado di caricare correttamente CKEditor e knockout.js.Integrazione CKEditor inline con knockoutjs

io proprio non riesco a ottenere l'aggiornamento ko.observable la proprietà:

<script type="text/javascript"> 

    var viewModel = function() { 
     var self = this; 
     self.editorText = ko.observable('ABC'); 
     self.testNewValue = function() { 
      console.log(this.editorText()); 
     }; 
    } 

    ko.applyBindings(new viewModel()); 
</script> 

Ecco il codice html:

<div id="editable" contenteditable="true" data-bind="html: editorText"> 
</div> 
<div> 
    <input type="button" data-bind="click: testNewValue" value="test" /> 
</div> 

Il risultato console.log mostra sempre "ABC" a prescindere se lo hai aggiornato o meno. Nota: ho anche provato data-bind="text: editorText"

+1

Il bind html è [non bidirezionale] (https://github.com/SteveSanderson/knockout/issues/430). Devi creare il tuo [binding personalizzato per contenteditable] (http://stackoverflow.com/questions/7904522/knockout-content-editable-custom-binding). – nemesv

+0

Ecco fatto. Grazie! – jmogera

+0

C'è anche Froala, che non metterà il tuo css in linea. Plugin knockout: https: // github.com/froala/knockout-froala –

risposta

11

Devi scrivere il tuo gestore di binding personalizzato affinché la tua proprietà osservabile sia collegata con un'istanza di CKEditor.

Innanzitutto, è possibile iniziare dall'associazione personalizzata trovata here. Uno dei post contiene un'associazione personalizzata, anche se non sono sicuro che funzioni. Devi controllare. Ho copiato qui, i crediti non vanno a me ovviamente:

ko.bindingHandlers.ckEditor = { 

    init: function (element, valueAccessor, allBindingsAccessor, viewModel) { 
     var txtBoxID = $(element).attr("id"); 
     var options = allBindingsAccessor().richTextOptions || {}; 
     options.toolbar_Full = [ 
      ['Source', '-', 'Format', 'Font', 'FontSize', 'TextColor', 'BGColor', '-', 'Bold', 'Italic', 'Underline', 'SpellChecker'], 
      ['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote', 'CreateDiv', '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock', '-', 'BidiLtr', 'BidiRtl'], 
      ['Link', 'Unlink', 'Image', 'Table'] 
     ]; 

     // handle disposal (if KO removes by the template binding) 
     ko.utils.domNodeDisposal.addDisposeCallback(element, function() { 
      if (CKEDITOR.instances[txtBoxID]){ 
       CKEDITOR.remove(CKEDITOR.instances[txtBoxID]); 
      } 
     }); 

     $(element).ckeditor(options); 

     // wire up the blur event to ensure our observable is properly updated 
     CKEDITOR.instances[txtBoxID].focusManager.blur = function() { 
      var observable = valueAccessor(); 
      observable($(element).val()); 
     }; 
    }, 
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) { 
     var val = ko.utils.unwrapObservable(valueAccessor()); 
     $(element).val(val); 
    } 
} 

Un utilizzo tipico allora sarebbe nel codice HTML:

<textarea id="txt_viewModelVariableName" 
      data-bind="ckEditor: viewModelVariableName"></textarea> 

In secondo luogo, si potrebbe verificare la custom binding handler for TinyMCE inizialmente scritto da Ryan Niemeyer e aggiornato da altre persone di talento. Forse TinyMCE potrebbe funzionare per te al posto di CKEditor?

+0

si applica alla modifica in linea? – jmogera

+0

err, sinceramente non lo so. Prima dovevo andare sul sito web di CKEditor4 per sapere cosa significa "editing inline" :-) Ma il modo migliore per vederlo sarebbe scrivere il codice :-) – Jalayn

+3

Steve Sanderson è il creatore di knockoutJs, Ryan Niemeyer è semplicemente fantastico tipo. –

2

Per rispondere alla domanda specifica, è necessario tenere traccia di dove proviene una modifica in modo che l'aggiornamento non venga attivato due volte. Quando l'osservabile viene aggiornato non dall'editor, non si desidera l'improvviso cambiamento nell'editor per aggiornare nuovamente l'osservabile. Stessa idea quando l'editor aggiorna l'osservabile, non si desidera che l'osservabile notifichi nuovamente l'editor. Ero abituato ai booleani per tenerne traccia. Il codice redattore agnostico è inferiore:

var isObservableChange = false; 
var isEditorChange = false; 

editor.change = function() { 
    if(!isObservableChange){ 
     isEditorChange = true; 
     observable(editor.data); 
     isEditorChange = false; 
    } 
}; 

observable.subscribe(function (newValue) { 
    if(!isEditorChange){ 
     isObservableChange = true; 
     editor.data = observable(); 
     isObservableChange = false; 
    } 
}); 

ho avuto un progetto in cui stavo cercando mio meglio per ottenere la modifica in linea con CKEditor. Alla fine ho rinunciato e ho provato TinyMCE con lo stesso tipo di codice e la soluzione ha funzionato. L'esempio seguente usa knockout 2.3.0, tinymce 4.0.8 e jquery 1.10.2. Il jquery può essere sostituito con l'accesso a un documento normale, ma io uso jquery come stampella per il codice veloce. Il codice vincolante è il seguente:

ko.bindingHandlers.wysiwyg = { 
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) { 
     var value = valueAccessor(); 
     var valueUnwrapped = ko.unwrap(value); 
     var allBindings = allBindingsAccessor(); 
     var $element = $(element); 
     $element.attr('id', 'wysiwyg_' + Date.now()); 
     if (ko.isObservable(value)) { 
      var isSubscriberChange = false; 
      var isEditorChange = true; 
      $element.html(value()); 
      var isEditorChange = false; 

      tinymce.init({ 
       selector: '#' + $element.attr('id'), 
       inline: true, 
       plugins: [ 
        "advlist autolink lists link image charmap print preview anchor", 
        "searchreplace visualblocks code fullscreen", 
        "insertdatetime media table contextmenu paste" 
       ], 
       toolbar: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image", 
       setup: function (editor) { 
        editor.on('change', function() { 
         if (!isSubscriberChange) { 
          isEditorChange = true; 
          value($element.html()); 
          isEditorChange = false; 
         } 
        }); 
       } 
      }); 
      value.subscribe(function (newValue) { 
       if (!isEditorChange) { 
        isSubscriberChange = true; 
        $element.html(newValue); 
        isSubscriberChange = false; 
       } 
      }); 
     } 
    } 
} 

Per utilizzarlo è sufficiente associarlo a un div. in questo modo

<div data-bind="wysiwyg: test"></div> 

Un esempio di lavoro può essere trovato qui http://jsfiddle.net/dhQk/2xjKc/ Spero che questo aiuta.

EDIT:

Sembra che la versione CKEditor funziona dopo tutto. Ho appena dovuto usare un cdn diverso. Il collegamento è http://jsfiddle.net/dhQk/CSwr6/