Jared Rader
Jared Rader

Reputation: 880

What's wrong with the jQuery in markdown preview gem?

Working on a Rails tutorial as part of an online course. They suggest using this gem for implementing a live markdown editor. I couldn't get the gem to work so I started inspecting it. The repository is two years old, so I'm not surprised the gem isn't working right off. I followed the installation instructions and the appropriate files are loading, I just don't understand why it's not working.

It would be really convenient if it did work because installation is really simple. The way it's set up, all you have to do after installing the gem, running the rake task and adding uses_markdown_preview to the appropriate controller is add a class "markdown_preview" to the textarea you want to preview.

What should happen is, once you've added the "markdown_preview" class to your text area, a jQuery file executes the function markdownPreview on that class, which creates a kind of control bar with three buttons. An editing button, which is on at default so you can edit the textarea. A preview button, which once you click it should take the input text and render a preview of the text, applying the markdown on the text. And a help button, which once you click, will reveal instructions for how to use markdown.

The first thing I noticed was that the jQuery was using out of date selectors, i.e. .live(). When I changed those to .on(), the jQuery file loaded the buttons I described above, but still none of the events work. I'll post the file below:

(function( $ ){

  $.fn.markdownPreview = function( type ) {  

    return this.each(function() {

      var $this = $(this);

      $this.wrap( '<div class="markdown_wrap editing"></div>' );

      $this.before( '<div class="markdown_wrap_menu"><div class="markdown_wrap_menu_help">Help</div><div class="markdown_wrap_menu_edit">Write</div><div class="markdown_wrap_menu_preview">Preview</div></div>' );

var help_text = [
   '<div class="content cheatsheet">',
   '<h2>Markdown Cheat Sheet</h2>',
   '<div class="cheatsheet-content">',
   '<div class="mod">',
   '<div class="col">',
   '<h3>Format Text</h3>',
   '<p>Headers</p>',
   '<pre># This is an &lt;h1&gt; tag',
   '## This is an &lt;h2&gt; tag',
   '###### This is an &lt;h6&gt; tag</pre>',
   '    <p>Text styles</p>',
   '    <pre>*This text will be italic*',
   '_This will also be italic_',
   '**This text will be bold**',
   '__This will also be bold__',
   '',
   '*You **can** combine them*',
   '</pre>',
   '</div>',
   '<div class="col">',
   '<h3>Lists</h3>',
   '<p>Unordered</p>',
   '<pre>* Item 1',
   '* Item 2',
   '  * Item 2a',
   '  * Item 2b</pre>',
   '     <p>Ordered</p>',
   '     <pre>1. Item 1',
   '2. Item 2',
   '3. Item 3',
   '   * Item 3a',
   '   * Item 3b</pre>',
   '</div>',
   '<div class="col">',
   '<h3>Miscellaneous</h3>',
   '<p>Images</p>',
   '<pre>![GitHub Logo](/images/logo.png)',
   'Format: ![Alt Text](url)',
   '</pre>',
   '<p>Links</p>',
   '<pre>http://github.com - automatic!',
   '[GitHub](http://github.com)</pre>',
   '<p>Blockquotes</p>',
   '<pre>As Kanye West said:',
   '&gt; We\'re living the future so',
   '&gt; the present is our past.',
   '</pre>',
   '</div>',
   '</div>',
   '<div class="rule"></div>',
   '</div>',
   '</div>' ].join( "\n" );


$this.before( '<div class="markdown_wrap_help">' + help_text + '</div>' );

  $this.wrap( '<div class="markdown_wrap_content"></div>' );
  $this.after( '<div class="markdown_wrap_preview"></div>' );

  $this.wrap( '<div class="markdown_wrap_editor"></div>' );

  /*
  if ( !type || type == 'width' ) {
    $this.width( $this.width() );
    }

  if ( !type || type == 'height' ) {
        $this.height( $this.height() );
    }*/

  });

  };

  $( '.markdown_wrap_menu_help' ).live( 'click', function(){
  //console.log( 'Clicked Help' );
    $( this ).closest( '.markdown_wrap' ).toggleClass( 'helping' );

    $( this ).closest( '.markdown_wrap' ).find( '.markdown_wrap_help' ).slideToggle( 'fast' );
  });

  $( '.markdown_wrap_menu_edit' ).live( 'click', function(){
    //console.log( 'Clicked Edit' );
    $( this ).closest( '.markdown_wrap' ).removeClass( 'previewing' ).addClass( 'editing' );

    $( this ).closest( '.markdown_wrap' ).find( '.markdown_wrap_preview' ).hide();
    $( this ).closest( '.markdown_wrap' ).find( '.markdown_wrap_editor' ).show();
  });

  $( '.markdown_wrap_menu_preview' ).live( 'click', function(){
    //console.log( 'Clicked Preview' );
    $( this ).closest( '.markdown_wrap' ).removeClass( 'editing' ).addClass( 'previewing' );

    var editor  = $( this ).closest( '.markdown_wrap' ).find( '.markdown_wrap_editor' );
    var preview = $( this ).closest( '.markdown_wrap' ).find( '.markdown_wrap_preview' );

    preview.html( 'Loading...' );

    editor.hide();
    preview.show();

    var editor_content = editor.find( 'textarea' ).val();

    $.ajax({
      type: 'POST',
      url: '/markdown_preview/convert',
      data: { 'format' : 'json', 'markdown_text' : editor_content },
      success: function( data, textStatus, jqXHR ){
        preview.html( data['html'] );
      },
      error: function(jqXHR, textStatus, errorThrown){
        //console.log( "ERROR" );
        //console.log( jqXHR );
        //console.log( textStatus );
        //console.log( errorThrown );
      },
      dataType: 'text json' 
    });

  });
})( jQuery );


$( document ).ready( function(){
  $( '.markdown_preview' ).markdownPreview();
});

Besides the .live() selectors, what else is wrong with this file? And why does it seem like the code works until it gets to these events, i.e.:

$( '.markdown_wrap_menu_help' ).live( 'click', function(){
  //console.log( 'Clicked Help' );
    $( this ).closest( '.markdown_wrap' ).toggleClass( 'helping' );

    $( this ).closest( '.markdown_wrap' ).find( '.markdown_wrap_help' ).slideToggle( 'fast' );
  });

I can add code above that first event, like an alert() function, and I've confirmed that will execute, but when I click on any of the buttons, nothing happens.

Upvotes: 0

Views: 142

Answers (1)

Jared Rader
Jared Rader

Reputation: 880

Figured it out. This:

$( '.markdown_wrap_menu_help' ).live( 'click', function(){
//console.log( 'Clicked Help' );
  $( this ).closest( '.markdown_wrap' ).toggleClass( 'helping' );

  $( this ).closest( '.markdown_wrap' ).find( '.markdown_wrap_help' ).slideToggle( 'fast' );
});

Should be:

$( document ).on('click', '.markdown_wrap_menu_help', function(){
  $( this ).closest( '.markdown_wrap' ).toggleClass( 'helping' );

  $( this ).closest( '.markdown_wrap' ).find( '.markdown_wrap_help' ).slideToggle( 'fast' );
});

I've been focusing mostly on Rails and my jQuery's lacking. If anyone could actually explain why the old code worked in the previous jQuery library and why this change works for the current version, that'd be helpful.

Upvotes: 1

Related Questions