Giter VIP home page Giter VIP logo

prototype-ujs's Introduction

Unobtrusive scripting support for prototype.js

This unobtrusive scripting support file is developed for the Ruby on Rails framework, but is not strictly tied to any specific backend. You can drop this into any application to:

  • force confirmation dialogs for various actions;
  • make non-GET requests from hyperlinks;
  • make forms or hyperlinks submit data asynchronously with Ajax;
  • have submit buttons become automatically disabled on form submit to prevent double-clicking.

These features are achieved by adding certain "data" attributes to your HTML markup. Full documentation of recognized attributes is below.

Requirements

  • prototype.js 1.7 RC3 or later;
  • for Ruby on Rails only: <%= csrf_meta_tag %> in the HEAD of your main layout;
  • HTML5 doctype (optional).

If you don't use HTML5, adding "data" attributes to your HTML4 or XHTML pages might make them fail W3C markup validation. However, this shouldn't create any issues for web browsers or other user agents.

In Ruby on Rails 3, the csrf_meta_tag helper generates two meta tags containing values necessary for cross-site request forgery protection built into Rails. If you're using Rails 2, here is how to implement that helper:

# app/helpers/application_helper.rb
def csrf_meta_tag
  if protect_against_forgery?
    out = %(<meta name="csrf-param" content="%s"/>\n)
    out << %(<meta name="csrf-token" content="%s"/>)
    out % [ Rack::Utils.escape_html(request_forgery_protection_token),
            Rack::Utils.escape_html(form_authenticity_token) ]
  end
end

Documentation

"data-confirm": Confirmation dialogs for links and forms

<form data-confirm="Are you sure you want to submit?">...</form>

The presence of this attribute indicates that activating a link or submitting a form should be intercepted so the user can be presented a JavaScript confirm() dialog containing the text that is the value of the attribute. If the user chooses to cancel, the action doesn't take place.

"data-disable-with": Automatic disabling of submit buttons in forms

<input type="submit" value="Save" data-disable-with="Saving...">

This attribute indicates that a submit button should get disabled while the form is submitting. This is to prevent accidental double-clicks from the user, which could result in duplicate HTTP requests that the backend may not detect as such. The value of the attribute is text that will become the new value of the button in its disabled state.

"data-method": Links that result in POST, PUT, or DELETE requests

<a href="..." data-method="delete" rel="nofollow">Delete this entry</a>

Activating hyperlinks (usually by clicking or tapping on them) always results in an HTTP GET request. However, if your application is RESTful, some links are in fact actions that change data on the server and must be performed with non-GET requests. This attribute allows marking up such links with an explicit method such as "post", "put" or "delete".

The way it works is that, when the link is activated, it constructs a hidden form in the document with the "action" attribute corresponding to "href" value of the link and the method corresponding to "data-method" value, and submits that form.

Note for non-Rails backends: because submitting forms with HTTP methods other than GET and POST isn't widely supported across browsers, all other HTTP methods are actually sent over POST with the intended method indicated in the "_method" parameter. Rails framework automatically detects and compensates for this.

"data-remote": Make links and forms submit asynchronously with Ajax

<form data-remote="true">...</form>

This attribute indicates that the link or form is to be submitted asynchronously; that is, without the page refreshing.

If the backend is configured to return snippets of JavaScript for these requests, those snippets will get executed on the page once requests are completed. This is regular prototype.js behavior, and can be used for modifying the document after an action has taken place.

Alternatively, you can handle the following custom events to hook into the lifecycle of the Ajax request.

Custom events fired during "data-remote" requests

  • ajax:before (no memo, stoppable) — fires before the Ajax request is initiated. If you stop this event with event.stop() method, the Ajax request will never take place.
  • ajax:create — right after the Ajax request object has been initialized, but before it is sent. Useful for adding custom request headers.
  • ajax:success — after completion, if the HTTP response was success;
  • ajax:failure — after completion, if the server returned an error;
  • ajax:complete — after the request has been completed, no matter what outcome.

The Ajax.Response instance of the current request is accessible on each of these events except ajax:before through the memo property. The Ajax.Request instance is then accessible through the request property on the response object. To illustrate, an example event handler would look like:

function(event) {
  var response = event.memo
  response.request       //=> Ajax.Request instance
  response.responseText  //=> text body of the response
  response.responseJSON  //=> data object in case of JSON responses
}

Examples

When processing a request failed on the server, it might return the error message as HTML:

document.on('ajax:failure', '#account_settings', function(event, container) {
  // insert the failure message inside the "#account_settings" element
  container.insert(event.memo.responseText)
})

Set custom HTTP headers just for a specific type of forms:

document.on('ajax:create', 'form.new_conversation', function(event) {
  var request = event.memo.request
  request.options.requestHeaders = {'Accept': 'text/html'}
})

If the form has file uploads, they can't be serialized and sent with Ajax. This detects file uploads in forms marked with "data-remote", prevents the Ajax request and, instead, submits the form normally (synchronously). The same form without file uploads would still be sent asynchronously, with Ajax:

document.on('ajax:before', 'form', function(e, form) {
  // detects if there are files for upload
  var hasFiles = form.select('input[type=file]').any(function(i){ return i.getValue() })
  if (hasFiles) {
    e.stop()       // prevent Ajax request, it won't work for files
    form.submit()  // submit the form as usual
  }
})

prototype-ujs's People

Contributors

akaspick avatar brianmario avatar jamis avatar josh avatar kangax avatar mislav avatar nostef avatar nzkoz avatar qhoxie avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

prototype-ujs's Issues

ajax:complete not called when link is in updated area

I have:

<body>
<head>
<%= javascript_include_tag :defaults %>
<%= javascript_include_tag "myscript" %>
</head>
</html>
<div id="my_div">
<%= link_to new_model_path, :remote => true %>
</div>
</html>
</body>
models_controller
def new
@model = Model.new
end

new.js.erb
$("my_div").update("<%= escape_javascript(render :partial => 'new) %>");

myscript.js
document.on('ajax:complete', 'a', function(response) {
alert('a:complete');
});


my on:complete function is never called.

Rails 3 disable with remote form button immediately re-enabled

Taken from:https://rails.lighthouseapp.com/projects/8994/tickets/5714-rails3-disable_with-remote-form-button-immediately-gets-re-enabled

When submitting a remote form with a "disable_with" option, the reasonable expectation is that the button will be re-enabled after the ajax response. Instead, the button is immediately re-enabled after the request is made but before the response is received. The problem is that the re-enabling code in rails.js (lines 167-174) is fired on ajax:after:

document.on("ajax:after", "form", function(event, element) {
var inputs = element.select("input[type=submit][disabled=true][data-disable-with]");
inputs.each(function(input) {
input.value = input.readAttribute('data-original-value');
input.removeAttribute('data-original-value');
input.disabled = false;
});
});
If changed to be ajax:complete (line 167):

document.on("ajax:complete", "form", function(event, element) {
//original code here
}
The code works as expected: the button is disabled until the ajax response is received.

Needs updating for Rails 3.0.4

The new Rails 3.0.4 CSRF protection means rails.js needs to be updated. Appears that the same code added to rails.js in railties-3.0.4 works here as well:

Ajax.Responders.register({
  onCreate: function(request) {
    var csrf_meta_tag = $$('meta[name=csrf-token]')[0];

    if (csrf_meta_tag) {
      var header = 'X-CSRF-Token',
          token = csrf_meta_tag.readAttribute('content');

      if (!request.options.requestHeaders) {
        request.options.requestHeaders = {};
      }
      request.options.requestHeaders[header] = token;
    }
  }
});

rails3 link_to :method => :delete doesn't work correctly in IE8

<%= link_to 'Destroy', user, :confirm => 'Are you sure?', :method => :delete %>
When the confirm dialog shows, the request has already been posted and the destroy action is called, so the ok or cancel button have no effect, the record is always deleted,and i found out the request method is "post" not "delete".

this works fine in firefox

<%= csrf_meta_tag %> already in my layout file

:confirm option on buttons (button_to, button_tag) not working for me

the :confirm option on buttons isn't working for me, but works for link_to. i can find no evidence of this breaking for others via google so i suspect i might having something else wrong.

<%= button_to "text", "/", :confirm => "are you sure?" %>

yields

<input data-confirm="are you sure?" name="commit" type="submit" />

but line 159 of rails.js

   document.on('click', 'a[data-confirm], a[data-remote], a[data-method]', function(event, link) {

isn't observing any input buttons. adding input[data-confirm] works for me, but is this suppose to be working without that addition?

Typo in tag name of textarea

Line 63 of rails.js:
document.on('focusin', 'input, select, texarea', function(focusEvent, input) {
should be:
document.on('focusin', 'input, select, textarea', function(focusEvent, input) {

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.