nathanvda / on_the_spot

A rails3 unobtrusive in-place-editing plugin, using jQuery/jEditable.
MIT License
132 stars 37 forks source link

Allow custom display text #3

Closed christophermanning closed 13 years ago

christophermanning commented 14 years ago

Right now there is now way to specify custom display text for a textarea.

Changing http://github.com/nathanvda/on_the_spot/blob/master/lib/on_the_spot/on_the_spot_helpers.rb#L28 to:

 options.reverse_merge!(:ok_text => t('on_the_spot.ok'),
                         :cancel_text => t('on_the_spot.cancel'),
                         :tooltip => t('on_the_spot.tooltip'),
                         :rows => 5,
                         :columns => 40,
                         :display_text => object.send(field.to_sym).to_s
                        )

  update_url = url_for(:action => 'update_attribute_on_the_spot')

  field_value = options[:display_text]

This would allow custom display text

nathanvda commented 14 years ago

This sounds good. But when the value is updated, you get to see the default-value again. Is it enough to only change the first text? Could you please explain the use-case? Is it to change the initial (empty) text?

christophermanning commented 14 years ago

My use case was for when I needed to parse and display markdown. Now I think I will just use showdown js to render that.

It could still be useful to add this to provide the end user the flexibility to display whatever initial text they want.

johnrees commented 12 years ago

I'm trying to work with markdown, I'd rather use RedCarpet than a javascript callback, so far I have this:

budgets/show.html.haml

= on_the_spot_edit @budget, :description, type: 'textarea', display_text: markdown(@budget.description), loadurl: description_budget_path(@budget)

routes.rb

resources :budgets do
  collection do
    put :update_attribute_on_the_spot
  end
  member do
    get 'description'
...

_budgetscontroller.rb

  def description
    @budget = Budget.find(params[:id])
    render :text => @budget.description
  end

_applicationhelper.rb

  def markdown(text)
    Redcarpet::Markdown.new(Redcarpet::Render::HTML.new(hard_wrap: true),
      autolink: true, lax_html_blocks: true, autolink: true, ).render(text).html_safe if text
  end

Everything works as expected, the page loads with the markdown parsed into HTML. When edited, the user sees the raw markdown code but the problem is when it is then saved, the page then shows the raw markdown instead of the HTML. In JEditable the save action could then return the rendered markdown

"However save.php should return rendered html" - http://www.appelsiini.net/projects/jeditable

but as far as I can tell update_attribute_on_the_spot returns the raw markdown (forgive me if I'm wrong). Is there a simple way to change this behaviour so that it can return anything, in this case the edited text via the markdown helper method?

nathanvda commented 12 years ago

Hi, definitely this is possible. I will provide some example code later today.

I have done that for a small side-project of mine (though I switched to using pagedown later).

nathanvda commented 12 years ago

In my view I had the following:

 on_the_spot_edit note, :content, :type => :autogrow, :onblur => 'submit',
                    :url => {:controller => :notes, :action => :update },
                    :loadurl => note_content_url,
                    :display_text => display_note_content(note))

Let me explain this a bit: I specify a :loadurl as you had and the :displaytext, but also overwrite the :url that will be used to save the data (and will return the new data in return).

In my helper I had:

def display_note_content(note)
  note.content.blank? ? '' : BlueCloth.new(note.content).to_html.html_safe
end

In my controller my update looked like:

def update
  klass, field, id = params[:id].split('__')
  @note = current_user.notes.find(id)

  if @note.update_attributes(field => params[:value])
    render :text => BlueCloth.new(@note.send(field)).to_html.html_safe, :status => 200
  else
    render :text => @note.errors.full_messages.join("\n"), :status => 422
  end
end

Hope this helps.

johnrees commented 12 years ago

Thanks Nathan! I've managed to implement something very similar now.

I might try and work on a feature so that models have a method like ots_FIELDNAME which will return the value of FIELDNAME formatted however you like. e.g.

def ots_description
    BlueCloth.new(description).to_html.html_safe
end

Then the default update_attribute_on_the_spot method can first check if the ots_FIELDNAME property exists and return that, otherwise it'd return the raw FIELDNAME property as it does currently.

This would remove the requirement for the extra controller methods. What do you think?

johnrees commented 12 years ago

Something like this perhaps?

_lib/on_the_spot/controllerextension.rb

parsed_data = JSON.parse(select_data.gsub("'", '"'))
return_value = object.respond_to?("ots_#{field}") ? "ots_#{field}" : field
render :text => parsed_data[object.send(return_value).to_s]
nathanvda commented 12 years ago

Yeah, this sounds very reasonable. I would rather have the look-up method or attribute to be configurable. But a very good suggestion. I will try to implement something like that later today.

Indeed, it think it would be very good/easy to not have to implement the method yourself, because it is almost identical.

So I am thinking more along the lines of the following:

 on_the_spot_edit note, :content, :type => :autogrow, :onblur => 'submit',
                    :loadurl => note_content_url,
                    :display_method => :display_content

And this will make sure it will always call the method display_content for that instance. So you do not have to specify the url and the display_method is also called when doing the first rendering.

What do you think?

Thank you!

johnrees commented 12 years ago

That looks great. Actually, I just looked over best_in_place's documentation and it has a :display_as property that behaves similarly to what you have just suggested. If something like the above could be implemented that would be brilliant. Thanks!

nathanvda commented 12 years ago

I just released a new version.

In your routes you will have to specify an extra option:

resources :posts do
  collection do
    put :update_attribute_on_the_spot
    get :get_attribute_on_the_spot
  end
end

and then you can just do something like

on_the_spot_edit @post, :some_field, :type => :textarea, :display_method => :some_formatted_method

Hope this helps!

johnrees commented 12 years ago

Win!

This gem is now perfect for me.

Thanks so much.

nathanvda commented 12 years ago

:D :D :D