Faking 'onpaste' in Firefox

When trying to find a solution for cleaning Rich Text pasting into a textarea, we needed to find a way to detect pastes and trigger an event based on said action. Internet Explorer and Safari both have an onpaste event that allows you to hook javascript into a paste event, but Firefox does not allow this.

After a little Googling, I didn’t really come across much of a solution so I decided to roll my own.

  function checkForPaste(event) {
    var e = event.element();
    if ((e.previousValue && e.value.length > e.previousValue.length + 1) ||
        (!e.previousValue && e.value.length > 1)) { 
      if (e.onpaste) {
        e.onpaste(e)
      } else if (e.readAttribute("onpaste")) {
        eval(e.readAttribute("onpaste"));
      }
    }
      e.previousValue = e.value;
  }

  function firefoxOnPaste() {
    $$('textarea').each(function(e) { 
      if (e.onpaste || e.readAttribute("onpaste")) {
        Event.observe(e,'input',checkForPaste);
      }
    });
  }

  if (Prototype.Browser.Gecko) {
    document.observe('dom:loaded', firefoxOnPaste);
  }

This snippet of code will automatically detect if an onpaste has been either added to a textarea’s attribute list (e.g. <textarea onpaste='alert("Pasted!")/>) or set programmatically. It will then automatically simulate paste detection using the oninput event and trigger the onpaste code when it believes a paste has been made.

The snippet will detect correctly for all pasting I’ve tried, including selecting a chunk and pasting a replacement. The only major caveat I’ve seen thus far is that the first input change after the page load will register as a paste if the textarea’s value has already been set. In any case, I thought it was a relatively straightforward way to solve the problem.

Share:

Comment on this post (0 comments)


Use 'link_to_remote' unobtrusively

I have become a big believer in unobtrusive scripting utilizing lowpro, but I still like being able to use the Rails Prototype helpers because they are there and simple (not to mention hooked into plugins such as Redbox). But by default, the href on a link_to_remote is set to ’#’, which hardly gives the desired behavior when Javascript is disabled. However, with a quick rewrite of the link_to_remote helper, we can achieve unobtrusiveness (if not complete code separation) for any link_to_remote call:

def link_to_remote(name, options = {}, html_options = {})
    html_options.merge!({:href => url_for(options[:url])}) unless options[:url].blank?
    super(name, options, html_options)
end

Link_to_remote is actually just a wrapper on link_to_function, which accepts html options. However, if you set href in the html_options hash, it will override the default ’#’ and use the url specified. Now whether javascript is enabled or not, the same URL will be called. Respond_to to the rescue! Just drop some custom code into the action to which you are linking, and you can easily render out an HTML page or perform javascript behavior, depending on the format desired:

class SomeController < ApplicationController
  def some_action
    respond_to do |format|
      format.html { redirect_to :back } # reload the page we were just on
      format.js { render :update do |page| 
        # update the content dynamically
      end }
    end
  end
end

It’s a simple technique, but this has allowed me to use redboxes for modal controls and seamlessly degrade to a properly laid out form if javascript is disabled, all without changing a single line of code in the redbox plugin.

Share:

Comment on this post (1 comment)