REMOTIPART WIP
This commit is contained in:
parent
7a5841a1e1
commit
37bf5c5aee
11 changed files with 693 additions and 183 deletions
1
Gemfile
1
Gemfile
|
|
@ -17,6 +17,7 @@ gem 'rack-cors', '~> 0.2.4', :require => 'rack/cors'
|
|||
gem 'devise', '1.5.3'
|
||||
gem 'jwt'
|
||||
gem 'oauth2-provider', '0.0.19'
|
||||
gem 'remotipart', '~> 1.0'
|
||||
|
||||
gem 'omniauth', '1.0.1'
|
||||
gem 'omniauth-facebook'
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ GEM
|
|||
fixture_builder (0.3.1)
|
||||
activerecord (>= 2)
|
||||
activesupport (>= 2)
|
||||
fog (1.2.0)
|
||||
fog (1.3.0)
|
||||
builder
|
||||
excon (~> 0.12.0)
|
||||
formatador (~> 0.2.0)
|
||||
|
|
@ -341,6 +341,7 @@ GEM
|
|||
redis (2.2.2)
|
||||
redis-namespace (1.0.3)
|
||||
redis (< 3.0.0)
|
||||
remotipart (1.0.2)
|
||||
resque (1.20.0)
|
||||
multi_json (~> 1.0)
|
||||
redis-namespace (~> 1.0.2)
|
||||
|
|
@ -513,6 +514,7 @@ DEPENDENCIES
|
|||
rails-i18n
|
||||
rails_autolink
|
||||
redcarpet (= 2.0.1)
|
||||
remotipart (~> 1.0)
|
||||
resque (= 1.20.0)
|
||||
resque-timeout (= 1.0.0)
|
||||
rest-client (= 1.6.7)
|
||||
|
|
|
|||
|
|
@ -41,21 +41,23 @@ class PhotosController < ApplicationController
|
|||
end
|
||||
|
||||
def create
|
||||
begin
|
||||
raise unless params[:photo][:aspect_ids]
|
||||
rescuing_photo_errors do |p|
|
||||
if remotipart_submitted?
|
||||
@photo = current_user.build_post(:photo, params[:photo])
|
||||
else
|
||||
raise "not remotipart" unless params[:photo][:aspect_ids]
|
||||
|
||||
if params[:photo][:aspect_ids] == "all"
|
||||
params[:photo][:aspect_ids] = current_user.aspects.collect{|x| x.id}
|
||||
elsif params[:photo][:aspect_ids].is_a?(Hash)
|
||||
params[:photo][:aspect_ids] = params[:photo][:aspect_ids].values
|
||||
end
|
||||
if params[:photo][:aspect_ids] == "all"
|
||||
params[:photo][:aspect_ids] = current_user.aspects.collect { |x| x.id }
|
||||
elsif params[:photo][:aspect_ids].is_a?(Hash)
|
||||
params[:photo][:aspect_ids] = params[:photo][:aspect_ids].values
|
||||
end
|
||||
|
||||
params[:photo][:user_file] = file_handler(params)
|
||||
params[:photo][:user_file] = file_handler(params)
|
||||
|
||||
@photo = current_user.build_post(:photo, params[:photo])
|
||||
|
||||
if @photo.save
|
||||
@photo = current_user.build_post(:photo, params[:photo])
|
||||
|
||||
if @photo.save
|
||||
aspects = current_user.aspects_from_ids(params[:photo][:aspect_ids])
|
||||
|
||||
unless @photo.pending
|
||||
|
|
@ -65,11 +67,14 @@ class PhotosController < ApplicationController
|
|||
|
||||
if params[:photo][:set_profile_photo]
|
||||
profile_params = {:image_url => @photo.url(:thumb_large),
|
||||
:image_url_medium => @photo.url(:thumb_medium),
|
||||
:image_url_small => @photo.url(:thumb_small)}
|
||||
:image_url_medium => @photo.url(:thumb_medium),
|
||||
:image_url_small => @photo.url(:thumb_small)}
|
||||
current_user.update_profile(profile_params)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if @photo.save
|
||||
respond_to do |format|
|
||||
format.json{ render(:layout => false , :json => {"success" => true, "data" => @photo}.to_json )}
|
||||
format.html{ render(:layout => false , :json => {"success" => true, "data" => @photo}.to_json )}
|
||||
|
|
@ -77,19 +82,6 @@ class PhotosController < ApplicationController
|
|||
else
|
||||
respond_with @photo, :location => photos_path, :error => message
|
||||
end
|
||||
|
||||
rescue TypeError
|
||||
message = I18n.t 'photos.create.type_error'
|
||||
respond_with @photo, :location => photos_path, :error => message
|
||||
|
||||
rescue CarrierWave::IntegrityError
|
||||
message = I18n.t 'photos.create.integrity_error'
|
||||
respond_with @photo, :location => photos_path, :error => message
|
||||
|
||||
rescue RuntimeError => e
|
||||
message = I18n.t 'photos.create.runtime_error'
|
||||
respond_with @photo, :location => photos_path, :error => message
|
||||
raise e
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -200,4 +192,23 @@ class PhotosController < ApplicationController
|
|||
file
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def rescuing_photo_errors
|
||||
begin
|
||||
yield
|
||||
rescue TypeError
|
||||
message = I18n.t 'photos.create.type_error'
|
||||
respond_with @photo, :location => photos_path, :error => message
|
||||
|
||||
rescue CarrierWave::IntegrityError
|
||||
message = I18n.t 'photos.create.integrity_error'
|
||||
respond_with @photo, :location => photos_path, :error => message
|
||||
|
||||
rescue RuntimeError => e
|
||||
message = I18n.t 'photos.create.runtime_error'
|
||||
respond_with @photo, :location => photos_path, :error => message
|
||||
raise e
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ class PostsController < ApplicationController
|
|||
:xml
|
||||
|
||||
def new
|
||||
render :text => "", :layout => true
|
||||
|
||||
end
|
||||
|
||||
def show
|
||||
|
|
@ -40,7 +40,7 @@ class PostsController < ApplicationController
|
|||
format.xml{ render :xml => @post.to_diaspora_xml }
|
||||
format.mobile{render 'posts/show.mobile.haml'}
|
||||
format.json{ render :json => PostPresenter.new(@post, current_user).to_json }
|
||||
format.any{render 'posts/show.html.haml'}
|
||||
format.any{render 'posts/show.html.haml'}
|
||||
end
|
||||
|
||||
else
|
||||
|
|
|
|||
|
|
@ -53,7 +53,8 @@ class StatusMessagesController < ApplicationController
|
|||
receiving_services = Service.titles(services)
|
||||
|
||||
current_user.dispatch_post(@status_message, :url => short_post_url(@status_message.guid), :service_types => receiving_services)
|
||||
|
||||
|
||||
#this is done implicitly, somewhere else, apparently, says max. :'(
|
||||
# @status_message.photos.each do |photo|
|
||||
# current_user.dispatch_post(photo)
|
||||
# end
|
||||
|
|
|
|||
|
|
@ -83,4 +83,4 @@
|
|||
});
|
||||
}
|
||||
|
||||
createUploader();
|
||||
createUploader();
|
||||
15
app/views/posts/new.html.haml
Normal file
15
app/views/posts/new.html.haml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
= form_for Photo.new, :html => { :multipart => true }, :remote => true do |f|
|
||||
= f.label :user_file
|
||||
= f.file_field :user_file
|
||||
= f.submit
|
||||
|
||||
:javascript
|
||||
$(function(){
|
||||
console.log($('#new_photo'))
|
||||
$('#new_photo').bind('ajax:success', function(event, data) {
|
||||
alert("happy day")
|
||||
console.log(data)
|
||||
console.log(new Backbone.Model(data)); // Your newly created Backbone.js model
|
||||
|
||||
});
|
||||
});
|
||||
|
|
@ -25,6 +25,8 @@ javascripts:
|
|||
- public/javascripts/vendor/timeago.js
|
||||
- public/javascripts/vendor/facebox.js
|
||||
- public/javascripts/vendor/underscore.js
|
||||
- public/javascripts/vendor/jquery.iframe-transport.js
|
||||
- public/javascripts/vendor/jquery.remotipart.js
|
||||
- public/javascripts/vendor/jquery.events.input.js
|
||||
- public/javascripts/vendor/jquery.elastic.js
|
||||
- public/javascripts/vendor/jquery.mentionsInput.js
|
||||
|
|
|
|||
|
|
@ -1,198 +1,374 @@
|
|||
/* Clear form plugin - called using $("elem").clearForm(); */
|
||||
$.fn.clearForm = function() {
|
||||
return this.each(function() {
|
||||
if ($(this).is('form')) {
|
||||
return $(':input', this).clearForm();
|
||||
}
|
||||
if ($(this).hasClass('clear_on_submit') || $(this).is(':text') || $(this).is(':password') || $(this).is('textarea')) {
|
||||
$(this).val('');
|
||||
} else if ($(this).is(':checkbox') || $(this).is(':radio')) {
|
||||
$(this).attr('checked', false);
|
||||
} else if ($(this).is('select')) {
|
||||
this.selectedIndex = -1;
|
||||
} else if ($(this).attr('name') == 'photos[]') {
|
||||
$(this).val('');
|
||||
}
|
||||
$(this).blur();
|
||||
});
|
||||
};
|
||||
(function($, undefined) {
|
||||
|
||||
/**
|
||||
* Unobtrusive scripting adapter for jQuery
|
||||
*
|
||||
* Requires jQuery 1.4.3 or later.
|
||||
* Requires jQuery 1.6.0 or later.
|
||||
* https://github.com/rails/jquery-ujs
|
||||
|
||||
* Uploading file using rails.js
|
||||
* =============================
|
||||
*
|
||||
* By default, browsers do not allow files to be uploaded via AJAX. As a result, if there are any non-blank file fields
|
||||
* in the remote form, this adapter aborts the AJAX submission and allows the form to submit through standard means.
|
||||
*
|
||||
* The `ajax:aborted:file` event allows you to bind your own handler to process the form submission however you wish.
|
||||
*
|
||||
* Ex:
|
||||
* $('form').live('ajax:aborted:file', function(event, elements){
|
||||
* // Implement own remote file-transfer handler here for non-blank file inputs passed in `elements`.
|
||||
* // Returning false in this handler tells rails.js to disallow standard form submission
|
||||
* return false;
|
||||
* });
|
||||
*
|
||||
* The `ajax:aborted:file` event is fired when a file-type input is detected with a non-blank value.
|
||||
*
|
||||
* Third-party tools can use this hook to detect when an AJAX file upload is attempted, and then use
|
||||
* techniques like the iframe method to upload the file instead.
|
||||
*
|
||||
* Required fields in rails.js
|
||||
* ===========================
|
||||
*
|
||||
* If any blank required inputs (required="required") are detected in the remote form, the whole form submission
|
||||
* is canceled. Note that this is unlike file inputs, which still allow standard (non-AJAX) form submission.
|
||||
*
|
||||
* The `ajax:aborted:required` event allows you to bind your own handler to inform the user of blank required inputs.
|
||||
*
|
||||
* !! Note that Opera does not fire the form's submit event if there are blank required inputs, so this event may never
|
||||
* get fired in Opera. This event is what causes other browsers to exhibit the same submit-aborting behavior.
|
||||
*
|
||||
* Ex:
|
||||
* $('form').live('ajax:aborted:required', function(event, elements){
|
||||
* // Returning false in this handler tells rails.js to submit the form anyway.
|
||||
* // The blank required inputs are passed to this function in `elements`.
|
||||
* return ! confirm("Would you like to submit the form with missing info?");
|
||||
* });
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
// Make sure that every Ajax request sends the CSRF token
|
||||
function CSRFProtection(fn) {
|
||||
var token = $('meta[name="csrf-token"]').attr('content');
|
||||
if (token) fn(function(xhr) { xhr.setRequestHeader('X-CSRF-Token', token) });
|
||||
}
|
||||
if ($().jquery == '1.5') { // gruesome hack
|
||||
var factory = $.ajaxSettings.xhr;
|
||||
$.ajaxSettings.xhr = function() {
|
||||
var xhr = factory();
|
||||
CSRFProtection(function(setHeader) {
|
||||
var open = xhr.open;
|
||||
xhr.open = function() { open.apply(this, arguments); setHeader(this) };
|
||||
});
|
||||
return xhr;
|
||||
};
|
||||
}
|
||||
else $(document).ajaxSend(function(e, xhr) {
|
||||
CSRFProtection(function(setHeader) { setHeader(xhr) });
|
||||
});
|
||||
// Shorthand to make it a little easier to call public rails functions from within rails.js
|
||||
var rails;
|
||||
|
||||
// Triggers an event on an element and returns the event result
|
||||
function fire(obj, name, data) {
|
||||
var event = new $.Event(name);
|
||||
obj.trigger(event, data);
|
||||
return event.result !== false;
|
||||
}
|
||||
$.rails = rails = {
|
||||
// Link elements bound by jquery-ujs
|
||||
linkClickSelector: 'a[data-confirm], a[data-method], a[data-remote], a[data-disable-with]',
|
||||
|
||||
// Submits "remote" forms and links with ajax
|
||||
function handleRemote(element) {
|
||||
var method, url, data,
|
||||
dataType = element.attr('data-type') || ($.ajaxSettings && $.ajaxSettings.dataType);
|
||||
// Select elements bound by jquery-ujs
|
||||
inputChangeSelector: 'select[data-remote], input[data-remote], textarea[data-remote]',
|
||||
|
||||
if (element.is('form')) {
|
||||
method = element.attr('method');
|
||||
url = element.attr('action');
|
||||
data = element.serializeArray();
|
||||
// memoized value from clicked submit button
|
||||
var button = element.data('ujs:submit-button');
|
||||
if (button) {
|
||||
data.push(button);
|
||||
element.data('ujs:submit-button', null);
|
||||
}
|
||||
} else {
|
||||
method = element.attr('data-method');
|
||||
url = element.attr('href');
|
||||
data = null;
|
||||
}
|
||||
// Form elements bound by jquery-ujs
|
||||
formSubmitSelector: 'form',
|
||||
|
||||
$.ajax({
|
||||
url: url, type: method || 'GET', data: data, dataType: dataType,
|
||||
// stopping the "ajax:beforeSend" event will cancel the ajax request
|
||||
beforeSend: function(xhr, settings) {
|
||||
if (settings.dataType === undefined) {
|
||||
xhr.setRequestHeader('accept', '*/*;q=0.5, ' + settings.accepts.script);
|
||||
// Form input elements bound by jquery-ujs
|
||||
formInputClickSelector: 'form input[type=submit], form input[type=image], form button[type=submit], form button:not(button[type])',
|
||||
|
||||
// Form input elements disabled during form submission
|
||||
disableSelector: 'input[data-disable-with], button[data-disable-with], textarea[data-disable-with]',
|
||||
|
||||
// Form input elements re-enabled after form submission
|
||||
enableSelector: 'input[data-disable-with]:disabled, button[data-disable-with]:disabled, textarea[data-disable-with]:disabled',
|
||||
|
||||
// Form required input elements
|
||||
requiredInputSelector: 'input[name][required]:not([disabled]),textarea[name][required]:not([disabled])',
|
||||
|
||||
// Form file input elements
|
||||
fileInputSelector: 'input:file',
|
||||
|
||||
// Link onClick disable selector with possible reenable after remote submission
|
||||
linkDisableSelector: 'a[data-disable-with]',
|
||||
|
||||
// Make sure that every Ajax request sends the CSRF token
|
||||
CSRFProtection: function(xhr) {
|
||||
var token = $('meta[name="csrf-token"]').attr('content');
|
||||
if (token) xhr.setRequestHeader('X-CSRF-Token', token);
|
||||
},
|
||||
|
||||
// Triggers an event on an element and returns false if the event result is false
|
||||
fire: function(obj, name, data) {
|
||||
var event = $.Event(name);
|
||||
obj.trigger(event, data);
|
||||
return event.result !== false;
|
||||
},
|
||||
|
||||
// Default confirm dialog, may be overridden with custom confirm dialog in $.rails.confirm
|
||||
confirm: function(message) {
|
||||
return confirm(message);
|
||||
},
|
||||
|
||||
// Default ajax function, may be overridden with custom function in $.rails.ajax
|
||||
ajax: function(options) {
|
||||
return $.ajax(options);
|
||||
},
|
||||
|
||||
// Submits "remote" forms and links with ajax
|
||||
handleRemote: function(element) {
|
||||
var method, url, data,
|
||||
crossDomain = element.data('cross-domain') || null,
|
||||
dataType = element.data('type') || ($.ajaxSettings && $.ajaxSettings.dataType),
|
||||
options;
|
||||
|
||||
if (rails.fire(element, 'ajax:before')) {
|
||||
|
||||
if (element.is('form')) {
|
||||
method = element.attr('method');
|
||||
url = element.attr('action');
|
||||
data = element.serializeArray();
|
||||
// memoized value from clicked submit button
|
||||
var button = element.data('ujs:submit-button');
|
||||
if (button) {
|
||||
data.push(button);
|
||||
element.data('ujs:submit-button', null);
|
||||
}
|
||||
} else if (element.is(rails.inputChangeSelector)) {
|
||||
method = element.data('method');
|
||||
url = element.data('url');
|
||||
data = element.serialize();
|
||||
if (element.data('params')) data = data + "&" + element.data('params');
|
||||
} else {
|
||||
method = element.data('method');
|
||||
url = element.attr('href');
|
||||
data = element.data('params') || null;
|
||||
}
|
||||
return fire(element, 'ajax:beforeSend', [xhr, settings]);
|
||||
},
|
||||
success: function(data, status, xhr) {
|
||||
element.trigger('ajax:success', [data, status, xhr]);
|
||||
},
|
||||
complete: function(xhr, status) {
|
||||
element.trigger('ajax:complete', [xhr, status]);
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
element.trigger('ajax:error', [xhr, status, error]);
|
||||
|
||||
options = {
|
||||
type: method || 'GET', data: data, dataType: dataType, crossDomain: crossDomain,
|
||||
// stopping the "ajax:beforeSend" event will cancel the ajax request
|
||||
beforeSend: function(xhr, settings) {
|
||||
if (settings.dataType === undefined) {
|
||||
xhr.setRequestHeader('accept', '*/*;q=0.5, ' + settings.accepts.script);
|
||||
}
|
||||
return rails.fire(element, 'ajax:beforeSend', [xhr, settings]);
|
||||
},
|
||||
success: function(data, status, xhr) {
|
||||
alert("hella boner jamz")
|
||||
element.trigger('ajax:success', [data, status, xhr]);
|
||||
},
|
||||
complete: function(xhr, status) {
|
||||
element.trigger('ajax:complete', [xhr, status]);
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
element.trigger('ajax:error', [xhr, status, error]);
|
||||
}
|
||||
};
|
||||
// Only pass url to `ajax` options if not blank
|
||||
if (url) { options.url = url; }
|
||||
|
||||
return rails.ajax(options);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// Handles "data-method" on links such as:
|
||||
// <a href="/users/5" data-method="delete" rel="nofollow" data-confirm="Are you sure?">Delete</a>
|
||||
function handleMethod(link) {
|
||||
var href = link.attr('href'),
|
||||
method = link.attr('data-method'),
|
||||
csrf_token = $('meta[name=csrf-token]').attr('content'),
|
||||
csrf_param = $('meta[name=csrf-param]').attr('content'),
|
||||
form = $('<form method="post" action="' + href + '"></form>'),
|
||||
metadata_input = '<input name="_method" value="' + method + '" type="hidden" />',
|
||||
form_params = link.data('form-params');
|
||||
// Handles "data-method" on links such as:
|
||||
// <a href="/users/5" data-method="delete" rel="nofollow" data-confirm="Are you sure?">Delete</a>
|
||||
handleMethod: function(link) {
|
||||
var href = link.attr('href'),
|
||||
method = link.data('method'),
|
||||
target = link.attr('target'),
|
||||
csrf_token = $('meta[name=csrf-token]').attr('content'),
|
||||
csrf_param = $('meta[name=csrf-param]').attr('content'),
|
||||
form = $('<form method="post" action="' + href + '"></form>'),
|
||||
metadata_input = '<input name="_method" value="' + method + '" type="hidden" />';
|
||||
|
||||
if (csrf_param !== undefined && csrf_token !== undefined) {
|
||||
metadata_input += '<input name="' + csrf_param + '" value="' + csrf_token + '" type="hidden" />';
|
||||
}
|
||||
|
||||
// support non-nested JSON encoded params for links
|
||||
if (form_params != undefined) {
|
||||
var params = $.parseJSON(form_params);
|
||||
for (key in params) {
|
||||
form.append($("<input>").attr({"type": "hidden", "name": key, "value": params[key]}));
|
||||
if (csrf_param !== undefined && csrf_token !== undefined) {
|
||||
metadata_input += '<input name="' + csrf_param + '" value="' + csrf_token + '" type="hidden" />';
|
||||
}
|
||||
}
|
||||
|
||||
form.hide().append(metadata_input).appendTo('body');
|
||||
form.submit();
|
||||
}
|
||||
if (target) { form.attr('target', target); }
|
||||
|
||||
function disableFormElements(form) {
|
||||
form.find('input[data-disable-with]').each(function() {
|
||||
var input = $(this);
|
||||
input.data('ujs:enable-with', input.val())
|
||||
.val(input.attr('data-disable-with'))
|
||||
.attr('disabled', 'disabled');
|
||||
});
|
||||
}
|
||||
form.hide().append(metadata_input).appendTo('body');
|
||||
form.submit();
|
||||
},
|
||||
|
||||
function enableFormElements(form) {
|
||||
form.find('input[data-disable-with]').each(function() {
|
||||
var input = $(this);
|
||||
input.val(input.data('ujs:enable-with')).removeAttr('disabled');
|
||||
});
|
||||
}
|
||||
/* Disables form elements:
|
||||
- Caches element value in 'ujs:enable-with' data store
|
||||
- Replaces element text with value of 'data-disable-with' attribute
|
||||
- Sets disabled property to true
|
||||
*/
|
||||
disableFormElements: function(form) {
|
||||
form.find(rails.disableSelector).each(function() {
|
||||
var element = $(this), method = element.is('button') ? 'html' : 'val';
|
||||
element.data('ujs:enable-with', element[method]());
|
||||
element[method](element.data('disable-with'));
|
||||
element.prop('disabled', true);
|
||||
});
|
||||
},
|
||||
|
||||
function allowAction(element) {
|
||||
var message = element.attr('data-confirm');
|
||||
return !message || (fire(element, 'confirm') && confirm(message));
|
||||
}
|
||||
/* Re-enables disabled form elements:
|
||||
- Replaces element text with cached value from 'ujs:enable-with' data store (created in `disableFormElements`)
|
||||
- Sets disabled property to false
|
||||
*/
|
||||
enableFormElements: function(form) {
|
||||
form.find(rails.enableSelector).each(function() {
|
||||
var element = $(this), method = element.is('button') ? 'html' : 'val';
|
||||
if (element.data('ujs:enable-with')) element[method](element.data('ujs:enable-with'));
|
||||
element.prop('disabled', false);
|
||||
});
|
||||
},
|
||||
|
||||
function requiredValuesMissing(form) {
|
||||
var missing = false;
|
||||
form.find('input[name][required]').each(function() {
|
||||
if (!$(this).val()) missing = true;
|
||||
});
|
||||
return missing;
|
||||
}
|
||||
/* For 'data-confirm' attribute:
|
||||
- Fires `confirm` event
|
||||
- Shows the confirmation dialog
|
||||
- Fires the `confirm:complete` event
|
||||
|
||||
$('a[data-confirm], a[data-method], a[data-remote]').live('click.rails', function(e) {
|
||||
var link = $(this);
|
||||
if (!allowAction(link)) return false;
|
||||
Returns `true` if no function stops the chain and user chose yes; `false` otherwise.
|
||||
Attaching a handler to the element's `confirm` event that returns a `falsy` value cancels the confirmation dialog.
|
||||
Attaching a handler to the element's `confirm:complete` event that returns a `falsy` value makes this function
|
||||
return false. The `confirm:complete` event is fired whether or not the user answered true or false to the dialog.
|
||||
*/
|
||||
allowAction: function(element) {
|
||||
var message = element.data('confirm'),
|
||||
answer = false, callback;
|
||||
if (!message) { return true; }
|
||||
|
||||
if (link.attr('data-remote') != undefined) {
|
||||
handleRemote(link);
|
||||
if (rails.fire(element, 'confirm')) {
|
||||
answer = rails.confirm(message);
|
||||
callback = rails.fire(element, 'confirm:complete', [answer]);
|
||||
}
|
||||
return answer && callback;
|
||||
},
|
||||
|
||||
// Helper function which checks for blank inputs in a form that match the specified CSS selector
|
||||
blankInputs: function(form, specifiedSelector, nonBlank) {
|
||||
var inputs = $(), input,
|
||||
selector = specifiedSelector || 'input,textarea';
|
||||
form.find(selector).each(function() {
|
||||
input = $(this);
|
||||
// Collect non-blank inputs if nonBlank option is true, otherwise, collect blank inputs
|
||||
if (nonBlank ? input.val() : !input.val()) {
|
||||
inputs = inputs.add(input);
|
||||
}
|
||||
});
|
||||
return inputs.length ? inputs : false;
|
||||
},
|
||||
|
||||
// Helper function which checks for non-blank inputs in a form that match the specified CSS selector
|
||||
nonBlankInputs: function(form, specifiedSelector) {
|
||||
return rails.blankInputs(form, specifiedSelector, true); // true specifies nonBlank
|
||||
},
|
||||
|
||||
// Helper function, needed to provide consistent behavior in IE
|
||||
stopEverything: function(e) {
|
||||
$(e.target).trigger('ujs:everythingStopped');
|
||||
e.stopImmediatePropagation();
|
||||
return false;
|
||||
} else if (link.attr('data-method')) {
|
||||
handleMethod(link);
|
||||
},
|
||||
|
||||
// find all the submit events directly bound to the form and
|
||||
// manually invoke them. If anyone returns false then stop the loop
|
||||
callFormSubmitBindings: function(form, event) {
|
||||
var events = form.data('events'), continuePropagation = true;
|
||||
if (events !== undefined && events['submit'] !== undefined) {
|
||||
$.each(events['submit'], function(i, obj){
|
||||
if (typeof obj.handler === 'function') return continuePropagation = obj.handler(event);
|
||||
});
|
||||
}
|
||||
return continuePropagation;
|
||||
},
|
||||
|
||||
// replace element's html with the 'data-disable-with' after storing original html
|
||||
// and prevent clicking on it
|
||||
disableElement: function(element) {
|
||||
element.data('ujs:enable-with', element.html()); // store enabled state
|
||||
element.html(element.data('disable-with')); // set to disabled state
|
||||
element.bind('click.railsDisable', function(e) { // prevent further clicking
|
||||
return rails.stopEverything(e)
|
||||
});
|
||||
},
|
||||
|
||||
// restore element to its original state which was disabled by 'disableElement' above
|
||||
enableElement: function(element) {
|
||||
if (element.data('ujs:enable-with') !== undefined) {
|
||||
element.html(element.data('ujs:enable-with')); // set to old enabled state
|
||||
// this should be element.removeData('ujs:enable-with')
|
||||
// but, there is currently a bug in jquery which makes hyphenated data attributes not get removed
|
||||
element.data('ujs:enable-with', false); // clean up cache
|
||||
}
|
||||
element.unbind('click.railsDisable'); // enable element
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
$.ajaxPrefilter(function(options, originalOptions, xhr){ if ( !options.crossDomain ) { rails.CSRFProtection(xhr); }});
|
||||
|
||||
$(document).delegate(rails.linkDisableSelector, 'ajax:complete', function() {
|
||||
rails.enableElement($(this));
|
||||
});
|
||||
|
||||
$(document).delegate(rails.linkClickSelector, 'click.rails', function(e) {
|
||||
var link = $(this), method = link.data('method'), data = link.data('params');
|
||||
if (!rails.allowAction(link)) return rails.stopEverything(e);
|
||||
|
||||
if (link.is(rails.linkDisableSelector)) rails.disableElement(link);
|
||||
|
||||
if (link.data('remote') !== undefined) {
|
||||
if ( (e.metaKey || e.ctrlKey) && (!method || method === 'GET') && !data ) { return true; }
|
||||
|
||||
if (rails.handleRemote(link) === false) { rails.enableElement(link); }
|
||||
return false;
|
||||
|
||||
} else if (link.data('method')) {
|
||||
rails.handleMethod(link);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
$('form').live('submit.rails', function(e) {
|
||||
var form = $(this), remote = form.attr('data-remote') != undefined;
|
||||
if (!allowAction(form)) return false;
|
||||
$(document).delegate(rails.inputChangeSelector, 'change.rails', function(e) {
|
||||
var link = $(this);
|
||||
if (!rails.allowAction(link)) return rails.stopEverything(e);
|
||||
|
||||
// skip other logic when required values are missing
|
||||
if (requiredValuesMissing(form)) return !remote;
|
||||
rails.handleRemote(link);
|
||||
return false;
|
||||
});
|
||||
|
||||
$(document).delegate(rails.formSubmitSelector, 'submit.rails', function(e) {
|
||||
var form = $(this),
|
||||
remote = form.data('remote') !== undefined,
|
||||
blankRequiredInputs = rails.blankInputs(form, rails.requiredInputSelector),
|
||||
nonBlankFileInputs = rails.nonBlankInputs(form, rails.fileInputSelector);
|
||||
|
||||
if (!rails.allowAction(form)) return rails.stopEverything(e);
|
||||
|
||||
// skip other logic when required values are missing or file upload is present
|
||||
if (blankRequiredInputs && form.attr("novalidate") == undefined && rails.fire(form, 'ajax:aborted:required', [blankRequiredInputs])) {
|
||||
return rails.stopEverything(e);
|
||||
}
|
||||
|
||||
if (remote) {
|
||||
handleRemote(form);
|
||||
if (nonBlankFileInputs) {
|
||||
return rails.fire(form, 'ajax:aborted:file', [nonBlankFileInputs]);
|
||||
}
|
||||
|
||||
// If browser does not support submit bubbling, then this live-binding will be called before direct
|
||||
// bindings. Therefore, we should directly call any direct bindings before remotely submitting form.
|
||||
if (!$.support.submitBubbles && $().jquery < '1.7' && rails.callFormSubmitBindings(form, e) === false) return rails.stopEverything(e);
|
||||
|
||||
rails.handleRemote(form);
|
||||
return false;
|
||||
|
||||
} else {
|
||||
// slight timeout so that the submit button gets properly serialized
|
||||
setTimeout(function(){ disableFormElements(form) }, 13);
|
||||
setTimeout(function(){ rails.disableFormElements(form); }, 13);
|
||||
}
|
||||
});
|
||||
|
||||
$('form input[type=submit], form button[type=submit], form button:not([type])').live('click.rails', function() {
|
||||
$(document).delegate(rails.formInputClickSelector, 'click.rails', function(event) {
|
||||
var button = $(this);
|
||||
if (!allowAction(button)) return false;
|
||||
|
||||
if (!rails.allowAction(button)) return rails.stopEverything(event);
|
||||
|
||||
// register the pressed submit button
|
||||
var name = button.attr('name'), data = name ? {name:name, value:button.val()} : null;
|
||||
var name = button.attr('name'),
|
||||
data = name ? {name:name, value:button.val()} : null;
|
||||
|
||||
button.closest('form').data('ujs:submit-button', data);
|
||||
});
|
||||
|
||||
$('form').live('ajax:beforeSend.rails', function(event) {
|
||||
if (this == event.target) disableFormElements($(this));
|
||||
$(document).delegate(rails.formSubmitSelector, 'ajax:beforeSend.rails', function(event) {
|
||||
if (this == event.target) rails.disableFormElements($(this));
|
||||
});
|
||||
|
||||
$('form').live('ajax:complete.rails', function(event) {
|
||||
if (this == event.target) enableFormElements($(this));
|
||||
$(document).delegate(rails.formSubmitSelector, 'ajax:complete.rails', function(event) {
|
||||
if (this == event.target) rails.enableFormElements($(this));
|
||||
});
|
||||
|
||||
})( jQuery );
|
||||
|
||||
|
|
|
|||
233
public/javascripts/vendor/jquery.iframe-transport.js
vendored
Normal file
233
public/javascripts/vendor/jquery.iframe-transport.js
vendored
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
// This [jQuery](http://jquery.com/) plugin implements an `<iframe>`
|
||||
// [transport](http://api.jquery.com/extending-ajax/#Transports) so that
|
||||
// `$.ajax()` calls support the uploading of files using standard HTML file
|
||||
// input fields. This is done by switching the exchange from `XMLHttpRequest` to
|
||||
// a hidden `iframe` element containing a form that is submitted.
|
||||
|
||||
// The [source for the plugin](http://github.com/cmlenz/jquery-iframe-transport)
|
||||
// is available on [Github](http://github.com/) and dual licensed under the MIT
|
||||
// or GPL Version 2 licenses.
|
||||
|
||||
// ## Usage
|
||||
|
||||
// To use this plugin, you simply add a `iframe` option with the value `true`
|
||||
// to the Ajax settings an `$.ajax()` call, and specify the file fields to
|
||||
// include in the submssion using the `files` option, which can be a selector,
|
||||
// jQuery object, or a list of DOM elements containing one or more
|
||||
// `<input type="file">` elements:
|
||||
|
||||
// $("#myform").submit(function() {
|
||||
// $.ajax(this.action, {
|
||||
// files: $(":file", this),
|
||||
// iframe: true
|
||||
// }).complete(function(data) {
|
||||
// console.log(data);
|
||||
// });
|
||||
// });
|
||||
|
||||
// The plugin will construct a hidden `<iframe>` element containing a copy of
|
||||
// the form the file field belongs to, will disable any form fields not
|
||||
// explicitly included, submit that form, and process the response.
|
||||
|
||||
// If you want to include other form fields in the form submission, include them
|
||||
// in the `data` option, and set the `processData` option to `false`:
|
||||
|
||||
// $("#myform").submit(function() {
|
||||
// $.ajax(this.action, {
|
||||
// data: $(":text", this).serializeArray(),
|
||||
// files: $(":file", this),
|
||||
// iframe: true,
|
||||
// processData: false
|
||||
// }).complete(function(data) {
|
||||
// console.log(data);
|
||||
// });
|
||||
// });
|
||||
|
||||
// ### The Server Side
|
||||
|
||||
// If the response is not HTML or XML, you (unfortunately) need to apply some
|
||||
// trickery on the server side. To send back a JSON payload, send back an HTML
|
||||
// `<textarea>` element with a `data-type` attribute that contains the MIME
|
||||
// type, and put the actual payload in the textarea:
|
||||
|
||||
// <textarea data-type="application/json">
|
||||
// {"ok": true, "message": "Thanks so much"}
|
||||
// </textarea>
|
||||
|
||||
// The iframe transport plugin will detect this and attempt to apply the same
|
||||
// conversions that jQuery applies to regular responses. That means for the
|
||||
// example above you should get a Javascript object as the `data` parameter of
|
||||
// the `complete` callback, with the properties `ok: true` and
|
||||
// `message: "Thanks so much"`.
|
||||
|
||||
// ### Compatibility
|
||||
|
||||
// This plugin has primarily been tested on Safari 5, Firefox 4, and Internet
|
||||
// Explorer all the way back to version 6. While I haven't found any issues with
|
||||
// it so far, I'm fairly sure it still doesn't work around all the quirks in all
|
||||
// different browsers. But the code is still pretty simple overall, so you
|
||||
// should be able to fix it and contribute a patch :)
|
||||
|
||||
// ## Annotated Source
|
||||
|
||||
(function($, undefined) {
|
||||
|
||||
// Register a prefilter that checks whether the `iframe` option is set, and
|
||||
// switches to the iframe transport if it is `true`.
|
||||
$.ajaxPrefilter(function(options, origOptions, jqXHR) {
|
||||
if (options.iframe) {
|
||||
return "iframe";
|
||||
}
|
||||
});
|
||||
|
||||
// Register an iframe transport, independent of requested data type. It will
|
||||
// only activate when the "files" option has been set to a non-empty list of
|
||||
// enabled file inputs.
|
||||
$.ajaxTransport("iframe", function(options, origOptions, jqXHR) {
|
||||
var form = null,
|
||||
iframe = null,
|
||||
origAction = null,
|
||||
origTarget = null,
|
||||
origEnctype = null,
|
||||
addedFields = [],
|
||||
disabledFields = [],
|
||||
files = $(options.files).filter(":file:enabled");
|
||||
|
||||
// This function gets called after a successful submission or an abortion
|
||||
// and should revert all changes made to the page to enable the
|
||||
// submission via this transport.
|
||||
function cleanUp() {
|
||||
$(addedFields).each(function() {
|
||||
this.remove();
|
||||
});
|
||||
$(disabledFields).each(function() {
|
||||
this.disabled = false;
|
||||
});
|
||||
form.attr("action", origAction || "")
|
||||
.attr("target", origTarget || "")
|
||||
.attr("enctype", origEnctype || "");
|
||||
iframe.attr("src", "javascript:false;").remove();
|
||||
}
|
||||
|
||||
// Remove "iframe" from the data types list so that further processing is
|
||||
// based on the content type returned by the server, without attempting an
|
||||
// (unsupported) conversion from "iframe" to the actual type.
|
||||
options.dataTypes.shift();
|
||||
|
||||
if (files.length) {
|
||||
// Determine the form the file fields belong to, and make sure they all
|
||||
// actually belong to the same form.
|
||||
files.each(function() {
|
||||
if (form !== null && this.form !== form) {
|
||||
jQuery.error("All file fields must belong to the same form");
|
||||
}
|
||||
form = this.form;
|
||||
});
|
||||
form = $(form);
|
||||
|
||||
// Store the original form attributes that we'll be replacing temporarily.
|
||||
origAction = form.attr("action");
|
||||
origTarget = form.attr("target");
|
||||
origEnctype = form.attr("enctype");
|
||||
|
||||
// We need to disable all other inputs in the form so that they don't get
|
||||
// included in the submitted data unexpectedly.
|
||||
form.find(":input:not(:submit)").each(function() {
|
||||
if (!this.disabled && (this.type != "file" || files.index(this) < 0)) {
|
||||
this.disabled = true;
|
||||
disabledFields.push(this);
|
||||
}
|
||||
});
|
||||
|
||||
// If there is any additional data specified via the `data` option,
|
||||
// we add it as hidden fields to the form. This (currently) requires
|
||||
// the `processData` option to be set to false so that the data doesn't
|
||||
// get serialized to a string.
|
||||
if (typeof(options.data) === "string" && options.data.length > 0) {
|
||||
jQuery.error("data must not be serialized");
|
||||
}
|
||||
$.each(options.data || {}, function(name, value) {
|
||||
if ($.isPlainObject(value)) {
|
||||
name = value.name;
|
||||
value = value.value;
|
||||
}
|
||||
addedFields.push($("<input type='hidden'>").attr("name", name)
|
||||
.attr("value", value).appendTo(form));
|
||||
});
|
||||
|
||||
// Add a hidden `X-Requested-With` field with the value `IFrame` to the
|
||||
// field, to help server-side code to determine that the upload happened
|
||||
// through this transport.
|
||||
addedFields.push($("<input type='hidden' name='X-Requested-With'>")
|
||||
.attr("value", "IFrame").appendTo(form));
|
||||
|
||||
// Borrowed straight from the JQuery source
|
||||
// Provides a way of specifying the accepted data type similar to HTTP_ACCEPTS
|
||||
accepts = options.dataTypes[ 0 ] && options.accepts[ options.dataTypes[0] ] ?
|
||||
options.accepts[ options.dataTypes[0] ] + ( options.dataTypes[ 0 ] !== "*" ? ", */*; q=0.01" : "" ) :
|
||||
options.accepts[ "*" ]
|
||||
|
||||
addedFields.push($("<input type='hidden' name='X-Http-Accept'>")
|
||||
.attr("value", accepts).appendTo(form));
|
||||
|
||||
return {
|
||||
|
||||
// The `send` function is called by jQuery when the request should be
|
||||
// sent.
|
||||
send: function(headers, completeCallback) {
|
||||
iframe = $("<iframe src='javascript:false;' name='iframe-" + $.now()
|
||||
+ "' style='display:none'></iframe>");
|
||||
|
||||
// The first load event gets fired after the iframe has been injected
|
||||
// into the DOM, and is used to prepare the actual submission.
|
||||
iframe.bind("load", function() {
|
||||
|
||||
// The second load event gets fired when the response to the form
|
||||
// submission is received. The implementation detects whether the
|
||||
// actual payload is embedded in a `<textarea>` element, and
|
||||
// prepares the required conversions to be made in that case.
|
||||
iframe.unbind("load").bind("load", function() {
|
||||
|
||||
var doc = this.contentWindow ? this.contentWindow.document :
|
||||
(this.contentDocument ? this.contentDocument : this.document),
|
||||
root = doc.documentElement ? doc.documentElement : doc.body,
|
||||
textarea = root.getElementsByTagName("textarea")[0],
|
||||
type = textarea ? textarea.getAttribute("data-type") : null;
|
||||
|
||||
var status = textarea ? parseInt(textarea.getAttribute("response-code")) : 200,
|
||||
statusText = "OK",
|
||||
responses = { text: type ? textarea.value : root ? root.innerHTML : null },
|
||||
headers = "Content-Type: " + (type || "text/html")
|
||||
|
||||
completeCallback(status, statusText, responses, headers);
|
||||
|
||||
setTimeout(cleanUp, 50);
|
||||
});
|
||||
|
||||
// Now that the load handler has been set up, reconfigure and
|
||||
// submit the form.
|
||||
form.attr("action", options.url)
|
||||
.attr("target", iframe.attr("name"))
|
||||
.attr("enctype", "multipart/form-data")
|
||||
.get(0).submit();
|
||||
});
|
||||
|
||||
// After everything has been set up correctly, the iframe gets
|
||||
// injected into the DOM so that the submission can be initiated.
|
||||
iframe.insertAfter(form);
|
||||
},
|
||||
|
||||
// The `abort` function is called by jQuery when the request should be
|
||||
// aborted.
|
||||
abort: function() {
|
||||
if (iframe !== null) {
|
||||
iframe.unbind("load").attr("src", "javascript:false;");
|
||||
cleanUp();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
69
public/javascripts/vendor/jquery.remotipart.js
vendored
Normal file
69
public/javascripts/vendor/jquery.remotipart.js
vendored
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
//= require jquery.iframe-transport.js
|
||||
//= require_self
|
||||
|
||||
(function($) {
|
||||
|
||||
var remotipart;
|
||||
|
||||
$.remotipart = remotipart = {
|
||||
|
||||
setup: function(form) {
|
||||
form
|
||||
// Allow setup part of $.rails.handleRemote to setup remote settings before canceling default remote handler
|
||||
// This is required in order to change the remote settings using the form details
|
||||
.one('ajax:beforeSend.remotipart', function(e, xhr, settings){
|
||||
// Delete the beforeSend bindings, since we're about to re-submit via ajaxSubmit with the beforeSubmit
|
||||
// hook that was just setup and triggered via the default `$.rails.handleRemote`
|
||||
// delete settings.beforeSend;
|
||||
delete settings.beforeSend;
|
||||
|
||||
settings.iframe = true;
|
||||
settings.files = $($.rails.fileInputSelector, form);
|
||||
settings.data = form.serializeArray();
|
||||
settings.processData = false;
|
||||
|
||||
// Modify some settings to integrate JS request with rails helpers and middleware
|
||||
if (settings.dataType === undefined) { settings.dataType = 'script *'; }
|
||||
settings.data.push({name: 'remotipart_submitted', value: true});
|
||||
|
||||
// Allow remotipartSubmit to be cancelled if needed
|
||||
if ($.rails.fire(form, 'ajax:remotipartSubmit', [xhr, settings])) {
|
||||
// Second verse, same as the first
|
||||
$.rails.ajax(settings);
|
||||
}
|
||||
|
||||
//Run cleanup
|
||||
remotipart.teardown(form);
|
||||
|
||||
// Cancel the jQuery UJS request
|
||||
return false;
|
||||
})
|
||||
|
||||
// Keep track that we just set this particular form with Remotipart bindings
|
||||
// Note: The `true` value will get over-written with the `settings.dataType` from the `ajax:beforeSend` handler
|
||||
.data('remotipartSubmitted', true);
|
||||
},
|
||||
|
||||
teardown: function(form) {
|
||||
form
|
||||
.unbind('ajax:beforeSend.remotipart')
|
||||
.removeData('remotipartSubmitted')
|
||||
}
|
||||
};
|
||||
|
||||
$('form').live('ajax:aborted:file', function(){
|
||||
var form = $(this);
|
||||
|
||||
remotipart.setup(form);
|
||||
|
||||
// If browser does not support submit bubbling, then this live-binding will be called before direct
|
||||
// bindings. Therefore, we should directly call any direct bindings before remotely submitting form.
|
||||
if (!$.support.submitBubbles && $().jquery < '1.7' && $.rails.callFormSubmitBindings(form) === false) return $.rails.stopEverything(e);
|
||||
|
||||
// Manually call jquery-ujs remote call so that it can setup form and settings as usual,
|
||||
// and trigger the `ajax:beforeSend` callback to which remotipart binds functionality.
|
||||
$.rails.handleRemote(form);
|
||||
return false;
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
Loading…
Reference in a new issue