Search code examples
javascriptjqueryknockout.jstinymcedurandal

How to use TinyMCE in Durandal (Knockout, RequireJS)


i try since hours to get the TinyMCE running in my SPA. i found already some answers but there not working for me.

e.g. this JSFiddle http://jsfiddle.net/scottmessinger/yJ5GV/2/;

They are all more about how to bind the data but not how about to just start the TinyMCE^^ if i put the scripts in index.html AND call it in the index.html by "textarea" was the only way to see an result.

Main.js (load tinymce scripts)

requirejs.config({
 paths: {
    'text': '../lib/require/text',
    'durandal':'../lib/durandal/js',
    'plugins' : '../lib/durandal/js/plugins',
    'transitions' : '../lib/durandal/js/transitions',
    'knockout': '../lib/knockout/knockout-3.1.0',
    'jquery': '../lib/jquery/jquery-1.9.1',
    'bootstrap': '../lib/bootstrap/js/bootstrap',
    'lodash': '../lib/lodash/lodash',
    'jqueryUI': '../lib/jquery/jquery-ui.min',
    'tinymce': '../lib/tinymce/tinymce.min',
    'tinymceJquery': '../lib/tinymce/jquery.tinymce.min'
},
shim: {
    'jquery': {
        exports: '$'
    },
    'bootstrap': {
        deps: ['jquery'],
        exports: 'jQuery'
   }
}
});

Verwaltung.js

define([
'services/accountrepository',
'plugins/router',
'services/blogrepository',
'durandal/app',
], function (accountrepository, router, blogrepository, app) {

ko.bindingHandlers.tinymce = {
    init: function (element, valueAccessor, allBindingsAccessor, 
                    context, arg1, arg2) {
        var options = allBindingsAccessor().tinymceOptions || {};
        var modelValue = valueAccessor();
        var value = ko.utils.unwrapObservable(valueAccessor());

        var el = $(element);
        var id = el.attr('id');

        //options.theme = "advanced";
        options.theme = "modern";

        options.menubar = false;
        options.plugins = [
            "advlist autolink autosave link image lists charmap print preview hr anchor pagebreak spellchecker",
            "searchreplace wordcount visualblocks visualchars code fullscreen insertdatetime media nonbreaking",
            "table contextmenu directionality template textcolor paste fullpage textcolor"
        ];
        //tinymce buttons
        //http://www.tinymce.com/tryit/classic.php
        options.toolbar_items_size = 'small';
        options.toolbar1 =
        "bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | forecolor backcolor | hr removeformat | subscript superscript  ";

        ////handle edits made in the editor. Updates after an undo point is reached.
        options.setup = function (editor) {
            editor.on('change', function (e) {
                if (ko.isWriteableObservable(modelValue)) {
                    var content = editor.getContent({ format: 'raw' });
                    modelValue(content);
                }
            });

        };

        el.html(value);

        $(element).tinymce(options);

        //handle disposal (if KO removes by the template binding)
        ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
            var tinymceInstance = tinyMCE.get(id);
            if (tinymceInstance != undefined) {
                // if instance already exist, then get rid of it... we don't want it
                tinymceInstance.remove();
            }
        });              
    },
    update: function (element, valueAccessor, allBindingsAccessor, 
                      context) {

        var el = $(element);
        var value = ko.utils.unwrapObservable(valueAccessor());
        var id = el.attr('id');

        //handle programmatic updates to the observable
        // also makes sure it doesn't update it if it's the same. 
        // otherwise, it will reload the instance, causing the cursor to jump.
        if (id !== undefined) {
            //$(el).tinymce();

            var tinymceInstance = tinyMCE.get(id);
            if (!tinymceInstance)
                return;
            var content = tinymceInstance.getContent({ format: 'raw' });
            if (content !== value) {
                //tinymceInstance.setContent(value);
                valueAccessor(content);
                //$(el).html(value);
            }
        }
    }

};

var viewmodel = function () {
     var self = this;

    self.fieldValue = ko.observable("two");

 };
return viewmodel;
});

Verwaltung.html

<textarea data-bind="tinymce: FieldValue"></textarea>      

Solution

  • In theory this should work as Knockout is composing this view only once the DOM has been loaded and the element is ready, however Durandal can be a little pick about this. Durandal does have some events you can use to load this plugin. Personally I would take all this code out of the Knockout extension and place this within a Durandal ViewModel or Widget. using a model you can hooking into the compositionComplete event I would make a call to initialize the TinyMCE plugin, however if you want to compose this into multiple views then this is difficult as the parent would have to call this as compose does not get may life cycle events. If you wish to compose into multiple views then you can use a Durandal Widget.

    http://durandaljs.com/documentation/Hooking-Lifecycle-Callbacks.html http://durandaljs.com/documentation/Creating-A-Widget

    I think you might need to get to grips with creating Views/viewmodel, widgets and composing before you try to load plugins. Just to get your knowledge on these core areas of the Framework. Durandal is a fantastic tool so keep at it!