views:

64

answers:

2

I've had problems with many of the WYSIWYG gems/plugins for Rails, so I'm building one myself using the RedCloth gem. I want users to see a live preview of their HTML-formatted text as they're filling out a form, but don't know how to do that using jQuery and RedCloth. Here's what I tried in application.js:

$('#comment').keyup(function(){
  var formatted = RedCloth.new($(this).val()).to_html;
  $('#preview').html(formatted);
});

Not surprised this didn't work, since RedCloth.new probably can't be executed in the .js file, but don't know how else to dynamically format the text.

A: 

I think you are going to need to do this one in javascript, unless you want to have an ajax call on a keyup event or something along those lines.

This link has some good resources: http://stackoverflow.com/questions/895135/javascript-libraries-for-markdown-textile-and-others-anchor-references

Geoff Lanotte
What you are trying to do is run server code (RedCloth) client-side, that won't work. You can either use [jQuery to post](http://api.jquery.com/jQuery.post/) the data to a controller action, call RedCloth there, then return the HTML as a partial inside a `respond_to` block for example, or look at something like [Showdown](http://attacklab.net/showdown/) if you want to parse Markdown source completely on the client side. If you used Showdown and created HTML from markdown, then you could post either markdown or HTML to the server.
Andy Atkinson
A: 

I just had to deal with this issue myself. You have 2 options, as alluded to by Geoff & Andy:

  1. Use JavaScript to parse the textile and jquery to stick it into your page
  2. Use an an Ajax call to get the parsed textile from the server and use jquery to stick it into the page

I'm using http://github.com/aaronchi/jrails to replace scriptactulous with jquery, which makes things a little easier.

Here's what I did:

I decided to implement option 2 because getting the formatting exactly as it will appear through RedCloth is paramount for my application.

I added the following into the <head> of my page:

<script>
var timeStamp1 = -1;
var timeStampSent1 = -1;
function delay() {
    setTimeout('preview()',1000);
}
function preview() {
    var n = new Date().getTime();
    // Ask for update if textarea was changed since this function last ran
    if (timeStamp1 != -1 && timeStamp1 != timeStampSent1) {
        $.post('/whatevers/ajax_update_preview', $('#textile').serialize(), null, "script");
        timeStampSent1 = timeStamp1;
    }
    delay(); // Run this again in 1000ms
}

// Important for letting you send ajax requests with jquery & rails
jQuery.ajaxSetup({  
    'beforeSend': function (xhr) {xhr.setRequestHeader("Accept", "text/javascript")}  
});


$(document).ready(function(){
    // Event binding to watch for changes to the textarea
    $('#textile').keydown(function() {
      timeStamp1 = event.timeStamp
    });
});
</script>

In the <body> you'll obviously need:

<textarea id="textile" name="some_text"></textarea>
<div id="preview"></div>

You need the following in your controller:

class WhateversController < ApplicationController
  def ajax_update_preview
    txt = params[:some_text]
    render :update do |page|
      page.replace_html 'preview', :partial => 'preview', :object => txt
    end
  end

And the partial (_preview.html.haml; it's in HAML because that's what I use but you could do it in ERB too, and you'll need to gem.config the RedCloth gem in environment.rb):

- if live_textile_preview
  = RedCloth.new(live_textile_preview).to_html

Finally, remember to put this in your routes.rb:

map.resources :whatevers, :collection => {:ajax_update_preview => :post}

I'm pretty inexperienced with javascript (I just sort of hack things together), so I'm sure the JS here could be improved.

Be aware that this is a major hit on server resources if you have lots of simultaneous users. If this is the case you'd be much better off processing the textile on the client side with javascript.

Max Masnick