Search code examples
javascripttwitter-bootstrapwysihtml5

Accessing the wysihtml5 editor object to use it inside "events"?


I found this in the documentation of bootstrap-wysihtml5:

The underlying wysihtml5 object
You can access the wysihtml5 editor object like this:

var wysihtml5Editor = $('#some-textarea').wysihtml5().data("wysihtml5").editor;
wysihtml5Editor.composer.commands.exec("bold"); 

So I tried this:

 <script type="text/javascript">
  var myCustomTemplates = {
    link : function(locale) {
      return "<li>" +
        "<div class='bootstrap-wysihtml5-insert-link-modal modal hide fade'>" +
          "<div class='modal-header'>" +
            "<a class='close' data-dismiss='modal'>&times;</a>" +
            "<h3>" + locale.link.insert + "</h3>" +
          "</div>" +
          "<div class='modal-body'>" +
            "<input value='http://' class='bootstrap-wysihtml5-insert-link-url input-xlarge'>" +
          "</div>" +
          "<div class='modal-footer'>" +
            "<a href='#' class='btn' data-dismiss='modal'>" + locale.link.cancel + "</a>" +
            "<a href='#' class='btn btn-primary' data-dismiss='modal'>" + locale.link.insert + "</a>" +
          "</div>" +
        "</div>" +
        "<a class='btn' data-wysihtml5-command='createLink' title='" + locale.link.insert + "'><i class='icon-link'></i></a>" +
      "</li>";
    },
    "font-styles": function(locale, options) {
      return "<li>" +
        "<a class='logo'>Logo</a>" +
      "</li>" +
      "<li>" +
        "<a class='btn btn-paragraph' data-wysihtml5-command='formatBlock' data-wysihtml5-command-value='p'>" + locale.font_styles.p + "</a>" +
      "</li>" +
      "<li>" +
        "<a class='btn btn-paragraph' data-wysihtml5-command='formatBlock' data-wysihtml5-command-value='p'>" + locale.font_styles.p + "</a>" +
      "</li>";
    }
  }


  $('#wysihtml5-textarea').wysihtml5('deepExtend', {
    "font-styles": true, //Font styling, e.g. h1, h2, etc. Default true
    "emphasis": true, //Italics, bold, etc. Default true
    "lists": true, //(Un)ordered lists, e.g. Bullets, Numbers. Default true
    "html": true, //Button which allows you to edit the generated HTML. Default false
    "image": false, //Button to insert an image. Default true,
    "link": false,
    "format-code": false, // enable syntax highlighting
    customTemplates: myCustomTemplates,
    "events": {
      "focus": function() { 
        //var wysihtml5Editor = $('#wysihtml5-textarea').wysihtml5().data("wysihtml5").editor;
        //wysihtml5Editor.composer.commands.exec("insertHTML", "<a href=...>");
      }
    },
    parserRules: {
      tags: {
        p: {}
      }
    },
    "stylesheets": ["<%= root_url %>wysiwyg-color.css", "<%= root_url %>github.css"], // CSS stylesheets to load
  });
 </script>

But it seems like it is breaking the code:

GET http://localhost:3000/posts/lib/css/wysiwyg-color.css 404 (Not Found)

And wysihtml5Editor.composer.commands.exec is not working either.

(The file loads just fine if I don't include the content inside "focus": function() {)

What the right way of doing this?


Solution

  • EDIT

    Here's a minimally working code, to use as a starting point:

    // I use this to keep this code out of the global scope. 
    // This takes this form: (function($){...})(jQuery);
    // and allows me to use $ without worry about it interfering
    // with other libraries and frameworks that share it's use.
    (function priv($) {
        // This is another scope thing; I can set the reference
        // later on, but it will be in the parent scope, so I
        // can cache these and then access them from within a
        // window.onload handler, for instance, that I create 
        // further down.
        var $editor,
            opts;
    
        // A more elegant, clean way of doing what was in the docs.
        opts = {
            // Note, it's not necessary to use quotes on labels in
            // object notation, UNLESS there's something not allowed.
            // This and format-code have comments ONLY because they
            // have that infernal dash in there. No others in this 
            // list do, however.
            'font-styles': false,
            'format-code': false,
            emphasis: true,
            lists: true,
            html: false,
            image: false,
            link: false,
            events: { 
                // Passing a reference to a function I've declared
                // later. I could not have this before the actual
                // functions, though, if I use var onload = function...
                // since "hoisting" does not occur. So, be careful
                // emulating this too liberally if you don't under
                // why it works.
                load: onload,
                focus: onfocus,
                blur: onblur
            }
        };
    
        // I'm using the `window.onload` method to setup my editor
        // AFTER the page has loaded and the DOM is ready. 
        $(window).on('load', function load() {
            // See, I set this up here, and can access it in the
            // onload, onfocus, and onblur handlers without 
            // requerying. It's called caching a reference.
            $editor = $('#wysihtml5-textarea');
    
            $editor.wysihtml5(opts);
        });
    
        function onload() {
            console.log('load');
        }
    
        function onfocus() {
            console.log('focus');
        }
    
        function onblur() {
            console.log('blur');
        }
    
    })(jQuery);​
    

    http://jsfiddle.net/userdude/nWebx/5/


    I put the wysihtml5 editor demo in a properly running fiddle and then modified it to run your referenced code:

    $(window).on('load', function load(){
        /*$('.textarea').wysihtml5();
        $(prettyPrint);*/
    
        $('#wysihtml5-textarea').wysihtml5('deepExtend', {
            "font-styles": true, //Font styling, e.g. h1, h2, etc. Default true
            "emphasis": true, //Italics, bold, etc. Default true
            "lists": true, //(Un)ordered lists, e.g. Bullets, Numbers. Default true
            "html": true, //Button which allows you to edit the generated HTML. Default false
            "image": false, //Button to insert an image. Default true,
            "link": false,
            "format-code": false, // enable syntax highlighting
            customTemplates: myCustomTemplates,
            "events": {
                "focus": function() { 
                    var wysihtml5Editor = $('#wysihtml5-textarea').wysihtml5().data("wysihtml5").editor;
                    wysihtml5Editor.composer.commands.exec("insertHTML", "<a href=...>");
                }
            },
            parserRules: {
                tags: {
                    p: {}
                }
            },
            "stylesheets": ["<%= root_url %>wysiwyg-color.css", "<%= root_url %>github.css"], // CSS stylesheets to load
        });
    })
    

    http://jsfiddle.net/userdude/nWebx/2/

    With this as-is, I receive this error in Chrome Console:

    Uncaught ReferenceError: myCustomTemplates is not defined

    So I comment that line out, and it runs. Try it:

    http://jsfiddle.net/userdude/nWebx/1/

    Now, I am running the editor code within a window.onload event using jQuery's $.on() event handler method:

    $(window).on('load', function load(){
        $('#wysihtml5-textarea').wysihtml5('deepExtend', {
            ...
        });
    }) // <<< I'd try to always using `;` at the end of statements.
    

    And I also get no errors with the focus handler, although I need to check that it's event running to beginning with. So, what is in myCustomTemplates?