resolved 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,171 @@
1
+ /*
2
+ * jQuery Iframe Transport Plugin 1.4
3
+ * https://github.com/blueimp/jQuery-File-Upload
4
+ *
5
+ * Copyright 2011, Sebastian Tschan
6
+ * https://blueimp.net
7
+ *
8
+ * Licensed under the MIT license:
9
+ * http://www.opensource.org/licenses/MIT
10
+ */
11
+
12
+ /*jslint unparam: true, nomen: true */
13
+ /*global define, window, document */
14
+
15
+ (function (factory) {
16
+ 'use strict';
17
+ if (typeof define === 'function' && define.amd) {
18
+ // Register as an anonymous AMD module:
19
+ define(['jquery'], factory);
20
+ } else {
21
+ // Browser globals:
22
+ factory(window.jQuery);
23
+ }
24
+ }(function ($) {
25
+ 'use strict';
26
+
27
+ // Helper variable to create unique names for the transport iframes:
28
+ var counter = 0;
29
+
30
+ // The iframe transport accepts three additional options:
31
+ // options.fileInput: a jQuery collection of file input fields
32
+ // options.paramName: the parameter name for the file form data,
33
+ // overrides the name property of the file input field(s),
34
+ // can be a string or an array of strings.
35
+ // options.formData: an array of objects with name and value properties,
36
+ // equivalent to the return data of .serializeArray(), e.g.:
37
+ // [{name: 'a', value: 1}, {name: 'b', value: 2}]
38
+ $.ajaxTransport('iframe', function (options) {
39
+ if (options.async && (options.type === 'POST' || options.type === 'GET')) {
40
+ var form,
41
+ iframe;
42
+ return {
43
+ send: function (_, completeCallback) {
44
+ form = $('<form style="display:none;"></form>');
45
+ // javascript:false as initial iframe src
46
+ // prevents warning popups on HTTPS in IE6.
47
+ // IE versions below IE8 cannot set the name property of
48
+ // elements that have already been added to the DOM,
49
+ // so we set the name along with the iframe HTML markup:
50
+ iframe = $(
51
+ '<iframe src="javascript:false;" name="iframe-transport-' +
52
+ (counter += 1) + '"></iframe>'
53
+ ).bind('load', function () {
54
+ var fileInputClones,
55
+ paramNames = $.isArray(options.paramName) ?
56
+ options.paramName : [options.paramName];
57
+ iframe
58
+ .unbind('load')
59
+ .bind('load', function () {
60
+ var response;
61
+ // Wrap in a try/catch block to catch exceptions thrown
62
+ // when trying to access cross-domain iframe contents:
63
+ try {
64
+ response = iframe.contents();
65
+ // Google Chrome and Firefox do not throw an
66
+ // exception when calling iframe.contents() on
67
+ // cross-domain requests, so we unify the response:
68
+ if (!response.length || !response[0].firstChild) {
69
+ throw new Error();
70
+ }
71
+ } catch (e) {
72
+ response = undefined;
73
+ }
74
+ // The complete callback returns the
75
+ // iframe content document as response object:
76
+ completeCallback(
77
+ 200,
78
+ 'success',
79
+ {'iframe': response}
80
+ );
81
+ // Fix for IE endless progress bar activity bug
82
+ // (happens on form submits to iframe targets):
83
+ $('<iframe src="javascript:false;"></iframe>')
84
+ .appendTo(form);
85
+ form.remove();
86
+ });
87
+ form
88
+ .prop('target', iframe.prop('name'))
89
+ .prop('action', options.url)
90
+ .prop('method', options.type);
91
+ if (options.formData) {
92
+ $.each(options.formData, function (index, field) {
93
+ $('<input type="hidden"/>')
94
+ .prop('name', field.name)
95
+ .val(field.value)
96
+ .appendTo(form);
97
+ });
98
+ }
99
+ if (options.fileInput && options.fileInput.length &&
100
+ options.type === 'POST') {
101
+ fileInputClones = options.fileInput.clone();
102
+ // Insert a clone for each file input field:
103
+ options.fileInput.after(function (index) {
104
+ return fileInputClones[index];
105
+ });
106
+ if (options.paramName) {
107
+ options.fileInput.each(function (index) {
108
+ $(this).prop(
109
+ 'name',
110
+ paramNames[index] || options.paramName
111
+ );
112
+ });
113
+ }
114
+ // Appending the file input fields to the hidden form
115
+ // removes them from their original location:
116
+ form
117
+ .append(options.fileInput)
118
+ .prop('enctype', 'multipart/form-data')
119
+ // enctype must be set as encoding for IE:
120
+ .prop('encoding', 'multipart/form-data');
121
+ }
122
+ form.submit();
123
+ // Insert the file input fields at their original location
124
+ // by replacing the clones with the originals:
125
+ if (fileInputClones && fileInputClones.length) {
126
+ options.fileInput.each(function (index, input) {
127
+ var clone = $(fileInputClones[index]);
128
+ $(input).prop('name', clone.prop('name'));
129
+ clone.replaceWith(input);
130
+ });
131
+ }
132
+ });
133
+ form.append(iframe).appendTo(document.body);
134
+ },
135
+ abort: function () {
136
+ if (iframe) {
137
+ // javascript:false as iframe src aborts the request
138
+ // and prevents warning popups on HTTPS in IE6.
139
+ // concat is used to avoid the "Script URL" JSLint error:
140
+ iframe
141
+ .unbind('load')
142
+ .prop('src', 'javascript'.concat(':false;'));
143
+ }
144
+ if (form) {
145
+ form.remove();
146
+ }
147
+ }
148
+ };
149
+ }
150
+ });
151
+
152
+ // The iframe transport returns the iframe content document as response.
153
+ // The following adds converters from iframe to text, json, html, and script:
154
+ $.ajaxSetup({
155
+ converters: {
156
+ 'iframe text': function (iframe) {
157
+ return $(iframe[0].body).text();
158
+ },
159
+ 'iframe json': function (iframe) {
160
+ return $.parseJSON($(iframe[0].body).text());
161
+ },
162
+ 'iframe html': function (iframe) {
163
+ return $(iframe[0].body).html();
164
+ },
165
+ 'iframe script': function (iframe) {
166
+ return $.globalEval($(iframe[0].body).text());
167
+ }
168
+ }
169
+ });
170
+
171
+ }));
@@ -0,0 +1,272 @@
1
+ /*!
2
+ * jQuery UI Widget @VERSION
3
+ *
4
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
5
+ * Dual licensed under the MIT or GPL Version 2 licenses.
6
+ * http://jquery.org/license
7
+ *
8
+ * http://docs.jquery.com/UI/Widget
9
+ */
10
+ (function( $, undefined ) {
11
+
12
+ // jQuery 1.4+
13
+ if ( $.cleanData ) {
14
+ var _cleanData = $.cleanData;
15
+ $.cleanData = function( elems ) {
16
+ for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
17
+ try {
18
+ $( elem ).triggerHandler( "remove" );
19
+ // http://bugs.jquery.com/ticket/8235
20
+ } catch( e ) {}
21
+ }
22
+ _cleanData( elems );
23
+ };
24
+ } else {
25
+ var _remove = $.fn.remove;
26
+ $.fn.remove = function( selector, keepData ) {
27
+ return this.each(function() {
28
+ if ( !keepData ) {
29
+ if ( !selector || $.filter( selector, [ this ] ).length ) {
30
+ $( "*", this ).add( [ this ] ).each(function() {
31
+ try {
32
+ $( this ).triggerHandler( "remove" );
33
+ // http://bugs.jquery.com/ticket/8235
34
+ } catch( e ) {}
35
+ });
36
+ }
37
+ }
38
+ return _remove.call( $(this), selector, keepData );
39
+ });
40
+ };
41
+ }
42
+
43
+ $.widget = function( name, base, prototype ) {
44
+ var namespace = name.split( "." )[ 0 ],
45
+ fullName;
46
+ name = name.split( "." )[ 1 ];
47
+ fullName = namespace + "-" + name;
48
+
49
+ if ( !prototype ) {
50
+ prototype = base;
51
+ base = $.Widget;
52
+ }
53
+
54
+ // create selector for plugin
55
+ $.expr[ ":" ][ fullName ] = function( elem ) {
56
+ return !!$.data( elem, name );
57
+ };
58
+
59
+ $[ namespace ] = $[ namespace ] || {};
60
+ $[ namespace ][ name ] = function( options, element ) {
61
+ // allow instantiation without initializing for simple inheritance
62
+ if ( arguments.length ) {
63
+ this._createWidget( options, element );
64
+ }
65
+ };
66
+
67
+ var basePrototype = new base();
68
+ // we need to make the options hash a property directly on the new instance
69
+ // otherwise we'll modify the options hash on the prototype that we're
70
+ // inheriting from
71
+ // $.each( basePrototype, function( key, val ) {
72
+ // if ( $.isPlainObject(val) ) {
73
+ // basePrototype[ key ] = $.extend( {}, val );
74
+ // }
75
+ // });
76
+ basePrototype.options = $.extend( true, {}, basePrototype.options );
77
+ $[ namespace ][ name ].prototype = $.extend( true, basePrototype, {
78
+ namespace: namespace,
79
+ widgetName: name,
80
+ widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name,
81
+ widgetBaseClass: fullName
82
+ }, prototype );
83
+
84
+ $.widget.bridge( name, $[ namespace ][ name ] );
85
+ };
86
+
87
+ $.widget.bridge = function( name, object ) {
88
+ $.fn[ name ] = function( options ) {
89
+ var isMethodCall = typeof options === "string",
90
+ args = Array.prototype.slice.call( arguments, 1 ),
91
+ returnValue = this;
92
+
93
+ // allow multiple hashes to be passed on init
94
+ options = !isMethodCall && args.length ?
95
+ $.extend.apply( null, [ true, options ].concat(args) ) :
96
+ options;
97
+
98
+ // prevent calls to internal methods
99
+ if ( isMethodCall && options.charAt( 0 ) === "_" ) {
100
+ return returnValue;
101
+ }
102
+
103
+ if ( isMethodCall ) {
104
+ this.each(function() {
105
+ var instance = $.data( this, name ),
106
+ methodValue = instance && $.isFunction( instance[options] ) ?
107
+ instance[ options ].apply( instance, args ) :
108
+ instance;
109
+ // TODO: add this back in 1.9 and use $.error() (see #5972)
110
+ // if ( !instance ) {
111
+ // throw "cannot call methods on " + name + " prior to initialization; " +
112
+ // "attempted to call method '" + options + "'";
113
+ // }
114
+ // if ( !$.isFunction( instance[options] ) ) {
115
+ // throw "no such method '" + options + "' for " + name + " widget instance";
116
+ // }
117
+ // var methodValue = instance[ options ].apply( instance, args );
118
+ if ( methodValue !== instance && methodValue !== undefined ) {
119
+ returnValue = methodValue;
120
+ return false;
121
+ }
122
+ });
123
+ } else {
124
+ this.each(function() {
125
+ var instance = $.data( this, name );
126
+ if ( instance ) {
127
+ instance.option( options || {} )._init();
128
+ } else {
129
+ $.data( this, name, new object( options, this ) );
130
+ }
131
+ });
132
+ }
133
+
134
+ return returnValue;
135
+ };
136
+ };
137
+
138
+ $.Widget = function( options, element ) {
139
+ // allow instantiation without initializing for simple inheritance
140
+ if ( arguments.length ) {
141
+ this._createWidget( options, element );
142
+ }
143
+ };
144
+
145
+ $.Widget.prototype = {
146
+ widgetName: "widget",
147
+ widgetEventPrefix: "",
148
+ options: {
149
+ disabled: false
150
+ },
151
+ _createWidget: function( options, element ) {
152
+ // $.widget.bridge stores the plugin instance, but we do it anyway
153
+ // so that it's stored even before the _create function runs
154
+ $.data( element, this.widgetName, this );
155
+ this.element = $( element );
156
+ this.options = $.extend( true, {},
157
+ this.options,
158
+ this._getCreateOptions(),
159
+ options );
160
+
161
+ var self = this;
162
+ this.element.bind( "remove." + this.widgetName, function() {
163
+ self.destroy();
164
+ });
165
+
166
+ this._create();
167
+ this._trigger( "create" );
168
+ this._init();
169
+ },
170
+ _getCreateOptions: function() {
171
+ return $.metadata && $.metadata.get( this.element[0] )[ this.widgetName ];
172
+ },
173
+ _create: function() {},
174
+ _init: function() {},
175
+
176
+ destroy: function() {
177
+ this.element
178
+ .unbind( "." + this.widgetName )
179
+ .removeData( this.widgetName );
180
+ this.widget()
181
+ .unbind( "." + this.widgetName )
182
+ .removeAttr( "aria-disabled" )
183
+ .removeClass(
184
+ this.widgetBaseClass + "-disabled " +
185
+ "ui-state-disabled" );
186
+ },
187
+
188
+ widget: function() {
189
+ return this.element;
190
+ },
191
+
192
+ option: function( key, value ) {
193
+ var options = key;
194
+
195
+ if ( arguments.length === 0 ) {
196
+ // don't return a reference to the internal hash
197
+ return $.extend( {}, this.options );
198
+ }
199
+
200
+ if (typeof key === "string" ) {
201
+ if ( value === undefined ) {
202
+ return this.options[ key ];
203
+ }
204
+ options = {};
205
+ options[ key ] = value;
206
+ }
207
+
208
+ this._setOptions( options );
209
+
210
+ return this;
211
+ },
212
+ _setOptions: function( options ) {
213
+ var self = this;
214
+ $.each( options, function( key, value ) {
215
+ self._setOption( key, value );
216
+ });
217
+
218
+ return this;
219
+ },
220
+ _setOption: function( key, value ) {
221
+ this.options[ key ] = value;
222
+
223
+ if ( key === "disabled" ) {
224
+ this.widget()
225
+ [ value ? "addClass" : "removeClass"](
226
+ this.widgetBaseClass + "-disabled" + " " +
227
+ "ui-state-disabled" )
228
+ .attr( "aria-disabled", value );
229
+ }
230
+
231
+ return this;
232
+ },
233
+
234
+ enable: function() {
235
+ return this._setOption( "disabled", false );
236
+ },
237
+ disable: function() {
238
+ return this._setOption( "disabled", true );
239
+ },
240
+
241
+ _trigger: function( type, event, data ) {
242
+ var prop, orig,
243
+ callback = this.options[ type ];
244
+
245
+ data = data || {};
246
+ event = $.Event( event );
247
+ event.type = ( type === this.widgetEventPrefix ?
248
+ type :
249
+ this.widgetEventPrefix + type ).toLowerCase();
250
+ // the original event may come from any element
251
+ // so we need to reset the target on the new event
252
+ event.target = this.element[ 0 ];
253
+
254
+ // copy original event properties over to the new event
255
+ orig = event.originalEvent;
256
+ if ( orig ) {
257
+ for ( prop in orig ) {
258
+ if ( !( prop in event ) ) {
259
+ event[ prop ] = orig[ prop ];
260
+ }
261
+ }
262
+ }
263
+
264
+ this.element.trigger( event, data );
265
+
266
+ return !( $.isFunction(callback) &&
267
+ callback.call( this.element[0], event, data ) === false ||
268
+ event.isDefaultPrevented() );
269
+ }
270
+ };
271
+
272
+ })( jQuery );
@@ -0,0 +1,377 @@
1
+ (function($, undefined) {
2
+
3
+ /**
4
+ * Unobtrusive scripting adapter for jQuery
5
+ *
6
+ * Requires jQuery 1.6.0 or later.
7
+ * https://github.com/rails/jquery-ujs
8
+
9
+ * Uploading file using rails.js
10
+ * =============================
11
+ *
12
+ * By default, browsers do not allow files to be uploaded via AJAX. As a result, if there are any non-blank file fields
13
+ * in the remote form, this adapter aborts the AJAX submission and allows the form to submit through standard means.
14
+ *
15
+ * The `ajax:aborted:file` event allows you to bind your own handler to process the form submission however you wish.
16
+ *
17
+ * Ex:
18
+ * $('form').live('ajax:aborted:file', function(event, elements){
19
+ * // Implement own remote file-transfer handler here for non-blank file inputs passed in `elements`.
20
+ * // Returning false in this handler tells rails.js to disallow standard form submission
21
+ * return false;
22
+ * });
23
+ *
24
+ * The `ajax:aborted:file` event is fired when a file-type input is detected with a non-blank value.
25
+ *
26
+ * Third-party tools can use this hook to detect when an AJAX file upload is attempted, and then use
27
+ * techniques like the iframe method to upload the file instead.
28
+ *
29
+ * Required fields in rails.js
30
+ * ===========================
31
+ *
32
+ * If any blank required inputs (required="required") are detected in the remote form, the whole form submission
33
+ * is canceled. Note that this is unlike file inputs, which still allow standard (non-AJAX) form submission.
34
+ *
35
+ * The `ajax:aborted:required` event allows you to bind your own handler to inform the user of blank required inputs.
36
+ *
37
+ * !! Note that Opera does not fire the form's submit event if there are blank required inputs, so this event may never
38
+ * get fired in Opera. This event is what causes other browsers to exhibit the same submit-aborting behavior.
39
+ *
40
+ * Ex:
41
+ * $('form').live('ajax:aborted:required', function(event, elements){
42
+ * // Returning false in this handler tells rails.js to submit the form anyway.
43
+ * // The blank required inputs are passed to this function in `elements`.
44
+ * return ! confirm("Would you like to submit the form with missing info?");
45
+ * });
46
+ */
47
+
48
+ // Shorthand to make it a little easier to call public rails functions from within rails.js
49
+ var rails;
50
+
51
+ $.rails = rails = {
52
+ // Link elements bound by jquery-ujs
53
+ linkClickSelector: 'a[data-confirm], a[data-method], a[data-remote], a[data-disable-with]',
54
+
55
+ // Select elements bound by jquery-ujs
56
+ inputChangeSelector: 'select[data-remote], input[data-remote], textarea[data-remote]',
57
+
58
+ // Form elements bound by jquery-ujs
59
+ formSubmitSelector: 'form',
60
+
61
+ // Form input elements bound by jquery-ujs
62
+ formInputClickSelector: 'form input[type=submit], form input[type=image], form button[type=submit], form button:not(button[type])',
63
+
64
+ // Form input elements disabled during form submission
65
+ disableSelector: 'input[data-disable-with], button[data-disable-with], textarea[data-disable-with]',
66
+
67
+ // Form input elements re-enabled after form submission
68
+ enableSelector: 'input[data-disable-with]:disabled, button[data-disable-with]:disabled, textarea[data-disable-with]:disabled',
69
+
70
+ // Form required input elements
71
+ requiredInputSelector: 'input[name][required]:not([disabled]),textarea[name][required]:not([disabled])',
72
+
73
+ // Form file input elements
74
+ fileInputSelector: 'input:file',
75
+
76
+ // Link onClick disable selector with possible reenable after remote submission
77
+ linkDisableSelector: 'a[data-disable-with]',
78
+
79
+ // Make sure that every Ajax request sends the CSRF token
80
+ CSRFProtection: function(xhr) {
81
+ var token = $('meta[name="csrf-token"]').attr('content');
82
+ if (token) xhr.setRequestHeader('X-CSRF-Token', token);
83
+ },
84
+
85
+ // Triggers an event on an element and returns false if the event result is false
86
+ fire: function(obj, name, data) {
87
+ var event = $.Event(name);
88
+ obj.trigger(event, data);
89
+ return event.result !== false;
90
+ },
91
+
92
+ // Default confirm dialog, may be overridden with custom confirm dialog in $.rails.confirm
93
+ confirm: function(message) {
94
+ return confirm(message);
95
+ },
96
+
97
+ // Default ajax function, may be overridden with custom function in $.rails.ajax
98
+ ajax: function(options) {
99
+ return $.ajax(options);
100
+ },
101
+
102
+ // Default way to get an element's href. May be overridden at $.rails.href.
103
+ href: function(element) {
104
+ return element.attr('href');
105
+ },
106
+
107
+ // Submits "remote" forms and links with ajax
108
+ handleRemote: function(element) {
109
+ var method, url, data, crossDomain, dataType, options;
110
+
111
+ if (rails.fire(element, 'ajax:before')) {
112
+ crossDomain = element.data('cross-domain') || null;
113
+ dataType = element.data('type') || ($.ajaxSettings && $.ajaxSettings.dataType);
114
+
115
+ if (element.is('form')) {
116
+ method = element.attr('method');
117
+ url = element.attr('action');
118
+ data = element.serializeArray();
119
+ // memoized value from clicked submit button
120
+ var button = element.data('ujs:submit-button');
121
+ if (button) {
122
+ data.push(button);
123
+ element.data('ujs:submit-button', null);
124
+ }
125
+ } else if (element.is(rails.inputChangeSelector)) {
126
+ method = element.data('method');
127
+ url = element.data('url');
128
+ data = element.serialize();
129
+ if (element.data('params')) data = data + "&" + element.data('params');
130
+ } else {
131
+ method = element.data('method');
132
+ url = rails.href(element);
133
+ data = element.data('params') || null;
134
+ }
135
+
136
+ options = {
137
+ type: method || 'GET', data: data, dataType: dataType, crossDomain: crossDomain,
138
+ // stopping the "ajax:beforeSend" event will cancel the ajax request
139
+ beforeSend: function(xhr, settings) {
140
+ if (settings.dataType === undefined) {
141
+ xhr.setRequestHeader('accept', '*/*;q=0.5, ' + settings.accepts.script);
142
+ }
143
+ return rails.fire(element, 'ajax:beforeSend', [xhr, settings]);
144
+ },
145
+ success: function(data, status, xhr) {
146
+ element.trigger('ajax:success', [data, status, xhr]);
147
+ },
148
+ complete: function(xhr, status) {
149
+ element.trigger('ajax:complete', [xhr, status]);
150
+ },
151
+ error: function(xhr, status, error) {
152
+ element.trigger('ajax:error', [xhr, status, error]);
153
+ }
154
+ };
155
+ // Only pass url to `ajax` options if not blank
156
+ if (url) { options.url = url; }
157
+
158
+ return rails.ajax(options);
159
+ } else {
160
+ return false;
161
+ }
162
+ },
163
+
164
+ // Handles "data-method" on links such as:
165
+ // <a href="/users/5" data-method="delete" rel="nofollow" data-confirm="Are you sure?">Delete</a>
166
+ handleMethod: function(link) {
167
+ var href = rails.href(link),
168
+ method = link.data('method'),
169
+ target = link.attr('target'),
170
+ csrf_token = $('meta[name=csrf-token]').attr('content'),
171
+ csrf_param = $('meta[name=csrf-param]').attr('content'),
172
+ form = $('<form method="post" action="' + href + '"></form>'),
173
+ metadata_input = '<input name="_method" value="' + method + '" type="hidden" />';
174
+
175
+ if (csrf_param !== undefined && csrf_token !== undefined) {
176
+ metadata_input += '<input name="' + csrf_param + '" value="' + csrf_token + '" type="hidden" />';
177
+ }
178
+
179
+ if (target) { form.attr('target', target); }
180
+
181
+ form.hide().append(metadata_input).appendTo('body');
182
+ form.submit();
183
+ },
184
+
185
+ /* Disables form elements:
186
+ - Caches element value in 'ujs:enable-with' data store
187
+ - Replaces element text with value of 'data-disable-with' attribute
188
+ - Sets disabled property to true
189
+ */
190
+ disableFormElements: function(form) {
191
+ form.find(rails.disableSelector).each(function() {
192
+ var element = $(this), method = element.is('button') ? 'html' : 'val';
193
+ element.data('ujs:enable-with', element[method]());
194
+ element[method](element.data('disable-with'));
195
+ element.prop('disabled', true);
196
+ });
197
+ },
198
+
199
+ /* Re-enables disabled form elements:
200
+ - Replaces element text with cached value from 'ujs:enable-with' data store (created in `disableFormElements`)
201
+ - Sets disabled property to false
202
+ */
203
+ enableFormElements: function(form) {
204
+ form.find(rails.enableSelector).each(function() {
205
+ var element = $(this), method = element.is('button') ? 'html' : 'val';
206
+ if (element.data('ujs:enable-with')) element[method](element.data('ujs:enable-with'));
207
+ element.prop('disabled', false);
208
+ });
209
+ },
210
+
211
+ /* For 'data-confirm' attribute:
212
+ - Fires `confirm` event
213
+ - Shows the confirmation dialog
214
+ - Fires the `confirm:complete` event
215
+
216
+ Returns `true` if no function stops the chain and user chose yes; `false` otherwise.
217
+ Attaching a handler to the element's `confirm` event that returns a `falsy` value cancels the confirmation dialog.
218
+ Attaching a handler to the element's `confirm:complete` event that returns a `falsy` value makes this function
219
+ return false. The `confirm:complete` event is fired whether or not the user answered true or false to the dialog.
220
+ */
221
+ allowAction: function(element) {
222
+ var message = element.data('confirm'),
223
+ answer = false, callback;
224
+ if (!message) { return true; }
225
+
226
+ if (rails.fire(element, 'confirm')) {
227
+ answer = rails.confirm(message);
228
+ callback = rails.fire(element, 'confirm:complete', [answer]);
229
+ }
230
+ return answer && callback;
231
+ },
232
+
233
+ // Helper function which checks for blank inputs in a form that match the specified CSS selector
234
+ blankInputs: function(form, specifiedSelector, nonBlank) {
235
+ var inputs = $(), input,
236
+ selector = specifiedSelector || 'input,textarea';
237
+ form.find(selector).each(function() {
238
+ input = $(this);
239
+ // Collect non-blank inputs if nonBlank option is true, otherwise, collect blank inputs
240
+ if (nonBlank ? input.val() : !input.val()) {
241
+ inputs = inputs.add(input);
242
+ }
243
+ });
244
+ return inputs.length ? inputs : false;
245
+ },
246
+
247
+ // Helper function which checks for non-blank inputs in a form that match the specified CSS selector
248
+ nonBlankInputs: function(form, specifiedSelector) {
249
+ return rails.blankInputs(form, specifiedSelector, true); // true specifies nonBlank
250
+ },
251
+
252
+ // Helper function, needed to provide consistent behavior in IE
253
+ stopEverything: function(e) {
254
+ $(e.target).trigger('ujs:everythingStopped');
255
+ e.stopImmediatePropagation();
256
+ return false;
257
+ },
258
+
259
+ // find all the submit events directly bound to the form and
260
+ // manually invoke them. If anyone returns false then stop the loop
261
+ callFormSubmitBindings: function(form, event) {
262
+ var events = form.data('events'), continuePropagation = true;
263
+ if (events !== undefined && events['submit'] !== undefined) {
264
+ $.each(events['submit'], function(i, obj){
265
+ if (typeof obj.handler === 'function') return continuePropagation = obj.handler(event);
266
+ });
267
+ }
268
+ return continuePropagation;
269
+ },
270
+
271
+ // replace element's html with the 'data-disable-with' after storing original html
272
+ // and prevent clicking on it
273
+ disableElement: function(element) {
274
+ element.data('ujs:enable-with', element.html()); // store enabled state
275
+ element.html(element.data('disable-with')); // set to disabled state
276
+ element.bind('click.railsDisable', function(e) { // prevent further clicking
277
+ return rails.stopEverything(e)
278
+ });
279
+ },
280
+
281
+ // restore element to its original state which was disabled by 'disableElement' above
282
+ enableElement: function(element) {
283
+ if (element.data('ujs:enable-with') !== undefined) {
284
+ element.html(element.data('ujs:enable-with')); // set to old enabled state
285
+ // this should be element.removeData('ujs:enable-with')
286
+ // but, there is currently a bug in jquery which makes hyphenated data attributes not get removed
287
+ element.data('ujs:enable-with', false); // clean up cache
288
+ }
289
+ element.unbind('click.railsDisable'); // enable element
290
+ }
291
+
292
+ };
293
+
294
+ $.ajaxPrefilter(function(options, originalOptions, xhr){ if ( !options.crossDomain ) { rails.CSRFProtection(xhr); }});
295
+
296
+ $(document).delegate(rails.linkDisableSelector, 'ajax:complete', function() {
297
+ rails.enableElement($(this));
298
+ });
299
+
300
+ $(document).delegate(rails.linkClickSelector, 'click.rails', function(e) {
301
+ var link = $(this), method = link.data('method'), data = link.data('params');
302
+ if (!rails.allowAction(link)) return rails.stopEverything(e);
303
+
304
+ if (link.is(rails.linkDisableSelector)) rails.disableElement(link);
305
+
306
+ if (link.data('remote') !== undefined) {
307
+ if ( (e.metaKey || e.ctrlKey) && (!method || method === 'GET') && !data ) { return true; }
308
+
309
+ if (rails.handleRemote(link) === false) { rails.enableElement(link); }
310
+ return false;
311
+
312
+ } else if (link.data('method')) {
313
+ rails.handleMethod(link);
314
+ return false;
315
+ }
316
+ });
317
+
318
+ $(document).delegate(rails.inputChangeSelector, 'change.rails', function(e) {
319
+ var link = $(this);
320
+ if (!rails.allowAction(link)) return rails.stopEverything(e);
321
+
322
+ rails.handleRemote(link);
323
+ return false;
324
+ });
325
+
326
+ $(document).delegate(rails.formSubmitSelector, 'submit.rails', function(e) {
327
+ var form = $(this),
328
+ remote = form.data('remote') !== undefined,
329
+ blankRequiredInputs = rails.blankInputs(form, rails.requiredInputSelector),
330
+ nonBlankFileInputs = rails.nonBlankInputs(form, rails.fileInputSelector);
331
+
332
+ if (!rails.allowAction(form)) return rails.stopEverything(e);
333
+
334
+ // skip other logic when required values are missing or file upload is present
335
+ if (blankRequiredInputs && form.attr("novalidate") == undefined && rails.fire(form, 'ajax:aborted:required', [blankRequiredInputs])) {
336
+ return rails.stopEverything(e);
337
+ }
338
+
339
+ if (remote) {
340
+ if (nonBlankFileInputs) {
341
+ return rails.fire(form, 'ajax:aborted:file', [nonBlankFileInputs]);
342
+ }
343
+
344
+ // If browser does not support submit bubbling, then this live-binding will be called before direct
345
+ // bindings. Therefore, we should directly call any direct bindings before remotely submitting form.
346
+ if (!$.support.submitBubbles && $().jquery < '1.7' && rails.callFormSubmitBindings(form, e) === false) return rails.stopEverything(e);
347
+
348
+ rails.handleRemote(form);
349
+ return false;
350
+
351
+ } else {
352
+ // slight timeout so that the submit button gets properly serialized
353
+ setTimeout(function(){ rails.disableFormElements(form); }, 13);
354
+ }
355
+ });
356
+
357
+ $(document).delegate(rails.formInputClickSelector, 'click.rails', function(event) {
358
+ var button = $(this);
359
+
360
+ if (!rails.allowAction(button)) return rails.stopEverything(event);
361
+
362
+ // register the pressed submit button
363
+ var name = button.attr('name'),
364
+ data = name ? {name:name, value:button.val()} : null;
365
+
366
+ button.closest('form').data('ujs:submit-button', data);
367
+ });
368
+
369
+ $(document).delegate(rails.formSubmitSelector, 'ajax:beforeSend.rails', function(event) {
370
+ if (this == event.target) rails.disableFormElements($(this));
371
+ });
372
+
373
+ $(document).delegate(rails.formSubmitSelector, 'ajax:complete.rails', function(event) {
374
+ if (this == event.target) rails.enableFormElements($(this));
375
+ });
376
+
377
+ })( jQuery );