Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

ajaxified inquiry form #98

Closed
wants to merge 1 commit into from

2 participants

@keram

hello guys,
improved inquiry form with ajax with properties:

  • in default configuration it behaves like before only is submitted through ajax
  • when javascript is not available it fallback to current old implementation
  • you can load form through ajax on other pages than contact. You just need put this snippet of code where you want:
<%= render :partial => 'refinery/inquiries/inquiries/javascripts' %>
  • customizable and configurable you can set form id, form holder,some callbacks etc. For example you want initialize inquiry form only after your custom event (maybe click on button) then you may put this snippet of code:
<%= render :partial => 'refinery/inquiries/inquiries/javascripts', :locals => {:initialize_onload => false} %>
<a id="frm-a" href="/contact">contact form</a>
<% content_for :javascripts do %>
<script>
$(function() {

    $('#frm-a').on('click', function () {
        new refinery.Inquiry({
            holder : { id : 'custom-holder-id', append_to: '#body_content_title' },
            onload : {
                fnc : window.alert,
                args : 'Inquiry Form loaded and binded'
            }});
    });
    return false;
});
</script>
<% end %>

and more..

In next step I would like write documentation and implement some polyfill for #77

@keram keram ajaxified inquiry form
sanitize passed form holder id prevent xss
refactoring & with bugfix on customized form holder
removing forgotted debug setting from inquiry model
f4a35c6
@parndt parndt commented on the diff
...ontrollers/refinery/inquiries/inquiries_controller.rb
((29 lines not shown))
+ end
+
+ def render_json_response(type, hash)
+ unless [ :ok, :redirect, :error ].include?(type)
+ raise "Invalid json response type: #{type}"
+ end
+
+ json = {
+ :status => type,
+ :html => nil,
+ :message => nil,
+ :errors => nil,
+ :to => nil }.merge(hash)
+
+ render_options = {:json => json}
+ render(render_options)
@parndt Owner
parndt added a note

could just be

render :json => json
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@keram keram closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 19, 2012
  1. @keram

    ajaxified inquiry form

    keram authored
    sanitize passed form holder id prevent xss
    refactoring & with bugfix on customized form holder
    removing forgotted debug setting from inquiry model
This page is out of date. Refresh to see the latest.
View
128 app/assets/javascripts/refinery/inquiries/inquiry.js
@@ -0,0 +1,128 @@
+(function (window, $) {
+ window.refinery = window.refinery || {};
+
+ function Inquiry (config) {
+ var cfg = config || {};
+
+ this.config.id = cfg.id || this.config.id;
+ if (cfg.holder) {
+ cfg.holder.id = cfg.holder.id || this.config.holder.id;
+ cfg.holder['class'] = cfg.holder['class'] || this.config.holder['class'];
+ cfg.holder.append_to = cfg.holder.append_to || this.config.holder.append_to;
+ this.config.holder = cfg.holder;
+ }
+
+ this.config.onbind = cfg.onbind || cfg.onload || this.config.onbind;
+ this.config.onsubmit = cfg.onsubmit || this.config.onsubmit;
+
+ this.init();
+ }
+
+ Inquiry.prototype = {
+ initialized : false,
+
+ config : {
+ id : 'new_inquiry',
+ holder : {
+ id : 'inquiry-form-holder',
+ 'class' : 'inquiries',
+ append_to : '#body .inner'
+ },
+ // for debug
+ // onbind : {
+ // fnc : window.alert,
+ // obj : this,
+ // args : 'Inquiry Form loaded and binded'
+ // },
+ // onsubmit : {
+ // fnc : window.alert,
+ // obj : this,
+ // args : 'Inquiry Form submitet'
+ // }
+ onbind : { fnc: null, obj: null, args: [] },
+ onsubmit : { fnc: null, obj: null, args: [] }
+ },
+
+ process_html: function(html) {
+ var that = this;
+
+ for (var i in html) {
+ that.updatePartial(i, html[i]);
+ }
+ },
+
+ // TODO
+ process_errors: function(errors) {
+
+ },
+
+ updatePartial: function(id, html) {
+ $('#' + id).html(html);
+ },
+
+ load : function () {
+ var that = this;
+ if ($('#' + that.config.holder.id).length === 0) {
+ $('<div>', that.config.holder).appendTo(that.config.holder.append_to);
+ }
+
+ $.getJSON('/contact', {form_holder_id : that.config.holder.id }, function (response) {
+ that.success(response, that.bind);
+ });
+ },
+ success : function (response, callback) {
+ var that = this;
+
+ if (response.html) {
+ that.process_html(response.html);
+ }
+
+ if (response.status === 'error' && response.errors) {
+ that.process_errors(response.errors);
+ } else if (response.status === 'redirect' && response.to) {
+ window.location.href = response.to;
+ }
+
+ if (typeof callback === 'function') {
+ return that.callback(callback, that);
+ }
+ },
+ callback : function (fnc, obj, args) {
+ args = (typeof args === 'string') ? [args] : args;
+ return fnc.apply(obj, args);
+ },
+ bind : function () {
+ var that = this;
+
+ $('#' + that.config.holder.id).on('ajax:success', function (event, response) {
+ that.success(response);
+ }).on('ajax:error', function (xhr, status, error) {
+ // TODO process ajax error
+ // alert('something went wrong');
+ });
+
+ if (that.config.onsubmit && typeof that.config.onsubmit.fnc === 'function') {
+ $('#' + that.config.id).on('submit', function () {
+ that.callback(that.config.onsubmit.fnc, that.config.onsubmit.obj, that.config.onsubmit.args || []);
+ });
+ }
+
+ if (that.config.onbind && typeof that.config.onbind.fnc === 'function') {
+ that.callback(that.config.onbind.fnc, that.config.onbind.obj, that.config.onbind.args || []);
+ }
+ },
+ init : function () {
+ var that = this;
+
+ if ($('#' + that.config.id).length > 0) {
+ that.bind();
+ } else {
+ that.load();
+ }
+
+ return that;
+ }
+ };
+
+ window.refinery.Inquiry = Inquiry;
+}(window, jQuery));
View
57 app/controllers/refinery/inquiries/inquiries_controller.rb
@@ -10,6 +10,8 @@ def thank_you
def new
@inquiry = ::Refinery::Inquiries::Inquiry.new
+
+ new_respond
end
def create
@@ -30,9 +32,17 @@ def create
end if ::Refinery::Inquiries::Setting.send_confirmation?
end
- redirect_to refinery.thank_you_inquiries_inquiries_path
+ respond_to do |format|
+ format.html do
+ redirect_to refinery.thank_you_inquiries_inquiries_path
+ end
+
+ format.json do
+ render_json_response :redirect, :to => refinery.thank_you_inquiries_inquiries_path
+ end
+ end
else
- render :action => 'new'
+ new_respond :error
end
end
@@ -42,6 +52,49 @@ def find_page
@page = ::Refinery::Page.find_by_link_url("/contact")
end
+ def new_respond status=:ok
+ @form_holder_config = {
+ :id => 'inquiry-form-holder',
+ :class => 'inquiries',
+ :append_to => '#body .inner'
+ }
+
+ respond_to do |format|
+ if params[:form_holder_id].present? and params[:form_holder_id] =~ /\A[a-zA-Z]+[\w\-]{,128}\Z/
+ @form_holder_config[:id] = params[:form_holder_id]
+ end
+
+ # fix "Missing partial refinery/inquiries/inquiries/form with {:formats=>[:json] .."
+ form_html = render_to_string(:partial => 'form', :formats => :html) if request.xhr?
+
+ format.html do
+ render action: 'new'
+ end
+
+ format.json do
+ render_json_response status, {
+ :errors => @inquiry.errors,
+ :html => { @form_holder_config[:id] => form_html }}
+ end
+ end
+ end
+
+ def render_json_response(type, hash)
+ unless [ :ok, :redirect, :error ].include?(type)
+ raise "Invalid json response type: #{type}"
+ end
+
+ json = {
+ :status => type,
+ :html => nil,
+ :message => nil,
+ :errors => nil,
+ :to => nil }.merge(hash)
+
+ render_options = {:json => json}
+ render(render_options)
@parndt Owner
parndt added a note

could just be

render :json => json
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ end
+
end
end
end
View
35 app/views/refinery/inquiries/inquiries/_form.html.erb
@@ -0,0 +1,35 @@
+<%
+ form_html_config = { :'data-type' => 'json' }
+ form_html_config.merge!(form_config) if local_assigns.has_key? :form_config
+ local_assigns
+%>
+<%= form_for [refinery, :inquiries, @inquiry],
+ :remote => true, :html => form_html_config do |f| %>
+ <%= render :partial => '/refinery/admin/error_messages',
+ :locals => {
+ :object => @inquiry,
+ :include_object_name => true
+ } %>
+ <div class="field">
+ <%= f.required_label :name, :class => 'placeholder-fallback' %>
+ <%= f.text_field :name, :class => 'text', :required => 'required',
+ :placeholder => t('name', :scope => 'activerecord.attributes.refinery/inquiries/inquiry') %>
+ </div>
+ <div class="field">
+ <%= f.required_label :email, :class => 'placeholder-fallback' %>
+ <%= f.email_field :email, :class => 'text email', :required => 'required', :placeholder => t('email', :scope => 'activerecord.attributes.refinery/inquiries/inquiry') %>
+ </div>
+ <div class="field">
+ <%= f.label :phone, :class => 'placeholder-fallback' %>
+ <%= f.text_field :phone, :class => 'text phone', :placeholder => t('phone', :scope => 'activerecord.attributes.refinery/inquiries/inquiry') %>
+ </div>
+ <div class="field message_field">
+ <%= f.required_label :message, :class => 'placeholder-fallback' %>
+ <%= f.text_area :message, :rows => 8, :required => 'required', :placeholder => t('message', :scope => 'activerecord.attributes.refinery/inquiries/inquiry') %>
+ </div>
+ <div class="actions">
+ <%= hidden_field_tag :form_holder_id, @form_holder_config[:id] if @form_holder_config.present? %>
+ <%= f.submit t('.send'), :disable_with => t('.sending_please_wait') %>
+ <%= link_to t('.privacy_policy'), '/pages/privacy-policy', :id => 'privacy_link' if Refinery::Inquiries.show_contact_privacy_link %>
+ </div>
+<% end %>
View
12 app/views/refinery/inquiries/inquiries/_javascripts.html.erb
@@ -0,0 +1,12 @@
+<%
+ initialize_onload = (local_assigns.has_key?(:initialize_onload) ? initialize_onload : true)
+ config ||= nil
+%>
+<% content_for :javascripts, javascript_include_tag('refinery/inquiries/inquiry.js') %>
+<% content_for :javascripts do %>
+<script>
+ $(function() {
+ new refinery.Inquiry(<%= config.to_json.html_safe if config %>);
+ });
+</script>
+<% end if initialize_onload %>
View
39 app/views/refinery/inquiries/inquiries/new.html.erb
@@ -1,34 +1,9 @@
+<% form_config = @form_config || { } %>
<% content_for :body do %>
- <%= raw @page.content_for(Refinery::Pages.default_parts.first.to_sym) if Refinery::Pages.default_parts.any? %>
-
- <div class='inquiries'>
- <%= form_for [refinery, :inquiries, @inquiry] do |f| %>
- <%= render :partial => "/refinery/admin/error_messages",
- :locals => {
- :object => @inquiry,
- :include_object_name => true
- } %>
- <div class="field">
- <%= f.required_label :name, :class => 'placeholder-fallback' %>
- <%= f.text_field :name, :class => 'text', :required => 'required', :placeholder => t('name', :scope => 'activerecord.attributes.refinery/inquiries/inquiry') %>
- </div>
- <div class="field">
- <%= f.required_label :email, :class => 'placeholder-fallback' %>
- <%= f.email_field :email, :class => 'text email', :required => 'required', :placeholder => t('email', :scope => 'activerecord.attributes.refinery/inquiries/inquiry') %>
- </div>
- <div class="field">
- <%= f.label :phone, :class => 'placeholder-fallback' %>
- <%= f.text_field :phone, :class => 'text phone', :placeholder => t('phone', :scope => 'activerecord.attributes.refinery/inquiries/inquiry') %>
- </div>
- <div class='field message_field'>
- <%= f.required_label :message, :class => 'placeholder-fallback' %>
- <%= f.text_area :message, :rows => 8, :required => 'required', :placeholder => t('message', :scope => 'activerecord.attributes.refinery/inquiries/inquiry') %>
- </div>
- <div class="actions">
- <%= f.submit t('.send') %>
- <%= link_to t('.privacy_policy'), "/pages/privacy-policy", :id => "privacy_link" if Refinery::Inquiries.show_contact_privacy_link %>
- </div>
- <% end %>
- </div>
+ <%= raw @page.content_for(:body) if Refinery::Pages.default_parts.any? %>
+ <%= content_tag(:div, @form_holder_config) do %>
+ <%= render :partial => 'form', :locals => {:form_config => form_config} %>
+ <% end %>
<% end %>
-<%= render "/refinery/content_page" %>
+<%= render :partial => 'javascripts', :locals => {:config => form_config.merge({:holder => @form_holder_config })} %>
+<%= render '/refinery/content_page' %>
Something went wrong with that request. Please try again.