muck-engine 0.2.26 → 0.2.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Rakefile CHANGED
@@ -57,15 +57,7 @@ begin
57
57
  gemspec.add_dependency "validation_reflection"
58
58
  gemspec.add_dependency "will_paginate"
59
59
  gemspec.add_dependency "git"
60
- gemspec.files.include %w( tasks/*
61
- db/migrate/*.rb
62
- app/**/**/**/*
63
- config/*
64
- locales/*
65
- rails/*
66
- test/*
67
- lib/**/*
68
- public/javascripts/* )
60
+ gemspec.add_development_dependency "shoulda"
69
61
  end
70
62
  Jeweler::RubyforgeTasks.new do |rubyforge|
71
63
  rubyforge.doc_task = "rdoc"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.26
1
+ 0.2.27
@@ -1,5 +1,5 @@
1
1
  class BasicMailer < ActionMailer::Base
2
-
2
+
3
3
  def mail(options)
4
4
  @recipients = options[:recipients] || GlobalConfig.support_email
5
5
  @from = options[:from] || GlobalConfig.email_from
@@ -11,5 +11,5 @@ class BasicMailer < ActionMailer::Base
11
11
  @charset = options[:charset] || "utf-8"
12
12
  @content_type = options[:content_type] || "text/plain"
13
13
  end
14
-
14
+
15
15
  end
@@ -0,0 +1,34 @@
1
+ module ActionMailer
2
+
3
+ module MuckMailer #:nodoc:
4
+
5
+ module ClassMethods
6
+ end
7
+
8
+ # All the methods available to a record that has had <tt>acts_as_muck_user</tt> specified.
9
+ module InstanceMethods
10
+
11
+ protected
12
+ def muck_setup_email(user)
13
+ if user.is_a?(String)
14
+ recipients user
15
+ else
16
+ recipients user.email
17
+ end
18
+ from "#{GlobalConfig.from_email_name} <#{GlobalConfig.from_email}>"
19
+ sent_on Time.now
20
+ content_type "text/html" # There is a bug in Rails that prevents multipart emails from working inside an engine.
21
+ # See: https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/2263-rails-232-breaks-implicit-multipart-actionmailer-tests#ticket-2263-22
22
+ end
23
+
24
+ end
25
+
26
+ def self.included(receiver)
27
+ receiver.extend ClassMethods
28
+ receiver.class_eval do
29
+ include InstanceMethods
30
+ end
31
+ end
32
+
33
+ end
34
+ end
data/lib/muck_engine.rb CHANGED
@@ -1,6 +1,7 @@
1
1
 
2
2
  ActionController::Base.send :include, ActionController::MuckApplication
3
3
  ActiveRecord::Base.send :include, ActiveRecord::MuckModel
4
+ ActionMailer::Base.send :include, ActionMailer::MuckMailer
4
5
  ActionController::Base.send :helper, MuckEngineHelper
5
6
  ActionController::Base.send :helper, MuckAdminHelper
6
7
 
@@ -47,7 +48,7 @@ class MuckEngine
47
48
  @@muck_dashboard_items << OpenStruct.new(:path => path,
48
49
  :locals => locals)
49
50
  end
50
-
51
+
51
52
  end
52
53
 
53
54
  # Add a link to admin home
data/muck-engine.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{muck-engine}
8
- s.version = "0.2.26"
8
+ s.version = "0.2.27"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Justin Ball", "Joel Duffin"]
12
- s.date = %q{2010-01-14}
12
+ s.date = %q{2010-01-20}
13
13
  s.description = %q{The base engine for the muck system. Contains common tables, custom for, css and javascript.}
14
14
  s.email = %q{justin@tatemae.com}
15
15
  s.extra_rdoc_files = [
@@ -65,6 +65,7 @@ Gem::Specification.new do |s|
65
65
  "db/migrate/20090426041103_create_states.rb",
66
66
  "install.rb",
67
67
  "lib/action_controller/muck_application.rb",
68
+ "lib/action_mailer/muck_mailer.rb",
68
69
  "lib/active_record/muck_model.rb",
69
70
  "lib/muck_engine.rb",
70
71
  "lib/muck_engine/initialize_routes.rb",
@@ -710,6 +711,8 @@ Gem::Specification.new do |s|
710
711
  "test/rails_root/app/controllers/default_controller.rb",
711
712
  "test/rails_root/app/helpers/application_helper.rb",
712
713
  "test/rails_root/app/models/.keep",
714
+ "test/rails_root/app/models/user.rb",
715
+ "test/rails_root/app/models/user_session.rb",
713
716
  "test/rails_root/app/views/admin/default/index.html.erb",
714
717
  "test/rails_root/app/views/default/index.html.erb",
715
718
  "test/rails_root/app/views/layouts/default.html.erb",
@@ -1308,6 +1311,8 @@ Gem::Specification.new do |s|
1308
1311
  "test/rails_root/app/controllers/application_controller.rb",
1309
1312
  "test/rails_root/app/controllers/default_controller.rb",
1310
1313
  "test/rails_root/app/helpers/application_helper.rb",
1314
+ "test/rails_root/app/models/user.rb",
1315
+ "test/rails_root/app/models/user_session.rb",
1311
1316
  "test/rails_root/config/boot.rb",
1312
1317
  "test/rails_root/config/environment.rb",
1313
1318
  "test/rails_root/config/environments/development.rb",
@@ -1344,15 +1349,18 @@ Gem::Specification.new do |s|
1344
1349
  s.add_runtime_dependency(%q<validation_reflection>, [">= 0"])
1345
1350
  s.add_runtime_dependency(%q<will_paginate>, [">= 0"])
1346
1351
  s.add_runtime_dependency(%q<git>, [">= 0"])
1352
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
1347
1353
  else
1348
1354
  s.add_dependency(%q<validation_reflection>, [">= 0"])
1349
1355
  s.add_dependency(%q<will_paginate>, [">= 0"])
1350
1356
  s.add_dependency(%q<git>, [">= 0"])
1357
+ s.add_dependency(%q<shoulda>, [">= 0"])
1351
1358
  end
1352
1359
  else
1353
1360
  s.add_dependency(%q<validation_reflection>, [">= 0"])
1354
1361
  s.add_dependency(%q<will_paginate>, [">= 0"])
1355
1362
  s.add_dependency(%q<git>, [">= 0"])
1363
+ s.add_dependency(%q<shoulda>, [">= 0"])
1356
1364
  end
1357
1365
  end
1358
1366
 
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * jQuery Form Plugin
3
- * version: 2.24 (10-MAR-2009)
4
- * @requires jQuery v1.2.2 or later
3
+ * version: 2.36 (07-NOV-2009)
4
+ * @requires jQuery v1.2.6 or later
5
5
  *
6
6
  * Examples and documentation at: http://malsup.com/jquery/form/
7
7
  * Dual licensed under the MIT and GPL licenses:
@@ -11,32 +11,32 @@
11
11
  ;(function($) {
12
12
 
13
13
  /*
14
- Usage Note:
15
- -----------
16
- Do not use both ajaxSubmit and ajaxForm on the same form. These
17
- functions are intended to be exclusive. Use ajaxSubmit if you want
18
- to bind your own submit handler to the form. For example,
19
-
20
- $(document).ready(function() {
21
- $('#myForm').bind('submit', function() {
22
- $(this).ajaxSubmit({
23
- target: '#output'
24
- });
25
- return false; // <-- important!
26
- });
27
- });
28
-
29
- Use ajaxForm when you want the plugin to manage all the event binding
30
- for you. For example,
31
-
32
- $(document).ready(function() {
33
- $('#myForm').ajaxForm({
34
- target: '#output'
35
- });
36
- });
37
-
38
- When using ajaxForm, the ajaxSubmit function will be invoked for you
39
- at the appropriate time.
14
+ Usage Note:
15
+ -----------
16
+ Do not use both ajaxSubmit and ajaxForm on the same form. These
17
+ functions are intended to be exclusive. Use ajaxSubmit if you want
18
+ to bind your own submit handler to the form. For example,
19
+
20
+ $(document).ready(function() {
21
+ $('#myForm').bind('submit', function() {
22
+ $(this).ajaxSubmit({
23
+ target: '#output'
24
+ });
25
+ return false; // <-- important!
26
+ });
27
+ });
28
+
29
+ Use ajaxForm when you want the plugin to manage all the event binding
30
+ for you. For example,
31
+
32
+ $(document).ready(function() {
33
+ $('#myForm').ajaxForm({
34
+ target: '#output'
35
+ });
36
+ });
37
+
38
+ When using ajaxForm, the ajaxSubmit function will be invoked for you
39
+ at the appropriate time.
40
40
  */
41
41
 
42
42
  /**
@@ -44,184 +44,192 @@
44
44
  * an HTML form using AJAX.
45
45
  */
46
46
  $.fn.ajaxSubmit = function(options) {
47
- // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
48
- if (!this.length) {
49
- log('ajaxSubmit: skipping submit process - no element selected');
50
- return this;
51
- }
52
-
53
- if (typeof options == 'function')
54
- options = { success: options };
55
-
56
- // clean url (don't include hash vaue)
57
- var url = this.attr('action') || window.location.href;
58
- url = (url.match(/^([^#]+)/)||[])[1];
59
- url = url || '';
60
-
61
- options = $.extend({
62
- url: url,
63
- type: this.attr('method') || 'GET'
64
- }, options || {});
65
-
66
- // hook for manipulating the form data before it is extracted;
67
- // convenient for use with rich editors like tinyMCE or FCKEditor
68
- var veto = {};
69
- this.trigger('form-pre-serialize', [this, options, veto]);
70
- if (veto.veto) {
71
- log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
72
- return this;
73
- }
74
-
75
- // provide opportunity to alter form data before it is serialized
76
- if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
77
- log('ajaxSubmit: submit aborted via beforeSerialize callback');
78
- return this;
79
- }
80
-
81
- var a = this.formToArray(options.semantic);
82
- if (options.data) {
83
- options.extraData = options.data;
84
- for (var n in options.data) {
85
- if(options.data[n] instanceof Array) {
86
- for (var k in options.data[n])
87
- a.push( { name: n, value: options.data[n][k] } );
88
- }
89
- else
90
- a.push( { name: n, value: options.data[n] } );
91
- }
92
- }
93
-
94
- // give pre-submit callback an opportunity to abort the submit
95
- if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
96
- log('ajaxSubmit: submit aborted via beforeSubmit callback');
97
- return this;
98
- }
99
-
100
- // fire vetoable 'validate' event
101
- this.trigger('form-submit-validate', [a, this, options, veto]);
102
- if (veto.veto) {
103
- log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
104
- return this;
105
- }
106
-
107
- var q = $.param(a);
108
-
109
- if (options.type.toUpperCase() == 'GET') {
110
- options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
111
- options.data = null; // data is null for 'get'
112
- }
113
- else
114
- options.data = q; // data is the query string for 'post'
115
-
116
- var $form = this, callbacks = [];
117
- if (options.resetForm) callbacks.push(function() { $form.resetForm(); });
118
- if (options.clearForm) callbacks.push(function() { $form.clearForm(); });
119
-
120
- // perform a load on the target only if dataType is not provided
121
- if (!options.dataType && options.target) {
122
- var oldSuccess = options.success || function(){};
123
- callbacks.push(function(data) {
124
- $(options.target).html(data).each(oldSuccess, arguments);
125
- });
126
- }
127
- else if (options.success)
128
- callbacks.push(options.success);
129
-
130
- options.success = function(data, status) {
131
- for (var i=0, max=callbacks.length; i < max; i++)
132
- callbacks[i].apply(options, [data, status, $form]);
133
- };
134
-
135
- // are there files to upload?
136
- var files = $('input:file', this).fieldValue();
137
- var found = false;
138
- for (var j=0; j < files.length; j++)
139
- if (files[j])
140
- found = true;
141
-
142
- // options.iframe allows user to force iframe mode
143
- if (options.iframe || found) {
144
- // hack to fix Safari hang (thanks to Tim Molendijk for this)
145
- // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
146
- if (options.closeKeepAlive)
147
- $.get(options.closeKeepAlive, fileUpload);
148
- else
149
- fileUpload();
150
- }
47
+ // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
48
+ if (!this.length) {
49
+ log('ajaxSubmit: skipping submit process - no element selected');
50
+ return this;
51
+ }
52
+
53
+ if (typeof options == 'function')
54
+ options = { success: options };
55
+
56
+ var url = $.trim(this.attr('action'));
57
+ if (url) {
58
+ // clean url (don't include hash vaue)
59
+ url = (url.match(/^([^#]+)/)||[])[1];
60
+ }
61
+ url = url || window.location.href || '';
62
+
63
+ options = $.extend({
64
+ url: url,
65
+ type: this.attr('method') || 'GET',
66
+ iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
67
+ }, options || {});
68
+
69
+ // hook for manipulating the form data before it is extracted;
70
+ // convenient for use with rich editors like tinyMCE or FCKEditor
71
+ var veto = {};
72
+ this.trigger('form-pre-serialize', [this, options, veto]);
73
+ if (veto.veto) {
74
+ log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
75
+ return this;
76
+ }
77
+
78
+ // provide opportunity to alter form data before it is serialized
79
+ if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
80
+ log('ajaxSubmit: submit aborted via beforeSerialize callback');
81
+ return this;
82
+ }
83
+
84
+ var a = this.formToArray(options.semantic);
85
+ if (options.data) {
86
+ options.extraData = options.data;
87
+ for (var n in options.data) {
88
+ if(options.data[n] instanceof Array) {
89
+ for (var k in options.data[n])
90
+ a.push( { name: n, value: options.data[n][k] } );
91
+ }
92
+ else
93
+ a.push( { name: n, value: options.data[n] } );
94
+ }
95
+ }
96
+
97
+ // give pre-submit callback an opportunity to abort the submit
98
+ if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
99
+ log('ajaxSubmit: submit aborted via beforeSubmit callback');
100
+ return this;
101
+ }
102
+
103
+ // fire vetoable 'validate' event
104
+ this.trigger('form-submit-validate', [a, this, options, veto]);
105
+ if (veto.veto) {
106
+ log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
107
+ return this;
108
+ }
109
+
110
+ var q = $.param(a);
111
+
112
+ if (options.type.toUpperCase() == 'GET') {
113
+ options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
114
+ options.data = null; // data is null for 'get'
115
+ }
116
+ else
117
+ options.data = q; // data is the query string for 'post'
118
+
119
+ var $form = this, callbacks = [];
120
+ if (options.resetForm) callbacks.push(function() { $form.resetForm(); });
121
+ if (options.clearForm) callbacks.push(function() { $form.clearForm(); });
122
+
123
+ // perform a load on the target only if dataType is not provided
124
+ if (!options.dataType && options.target) {
125
+ var oldSuccess = options.success || function(){};
126
+ callbacks.push(function(data) {
127
+ $(options.target).html(data).each(oldSuccess, arguments);
128
+ });
129
+ }
130
+ else if (options.success)
131
+ callbacks.push(options.success);
132
+
133
+ options.success = function(data, status) {
134
+ for (var i=0, max=callbacks.length; i < max; i++)
135
+ callbacks[i].apply(options, [data, status, $form]);
136
+ };
137
+
138
+ // are there files to upload?
139
+ var files = $('input:file', this).fieldValue();
140
+ var found = false;
141
+ for (var j=0; j < files.length; j++)
142
+ if (files[j])
143
+ found = true;
144
+
145
+ var multipart = false;
146
+ // var mp = 'multipart/form-data';
147
+ // multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
148
+
149
+ // options.iframe allows user to force iframe mode
150
+ // 06-NOV-09: now defaulting to iframe mode if file input is detected
151
+ if ((files.length && options.iframe !== false) || options.iframe || found || multipart) {
152
+ // hack to fix Safari hang (thanks to Tim Molendijk for this)
153
+ // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
154
+ if (options.closeKeepAlive)
155
+ $.get(options.closeKeepAlive, fileUpload);
156
+ else
157
+ fileUpload();
158
+ }
151
159
  else
152
- $.ajax(options);
153
-
154
- // fire 'notify' event
155
- this.trigger('form-submit-notify', [this, options]);
156
- return this;
157
-
158
-
159
- // private function for handling file uploads (hat tip to YAHOO!)
160
- function fileUpload() {
161
- var form = $form[0];
162
-
163
- if ($(':input[name=submit]', form).length) {
164
- alert('Error: Form elements must not be named "submit".');
165
- return;
166
- }
167
-
168
- var opts = $.extend({}, $.ajaxSettings, options);
169
- var s = jQuery.extend(true, {}, $.extend(true, {}, $.ajaxSettings), opts);
170
-
171
- var id = 'jqFormIO' + (new Date().getTime());
172
- var $io = $('<iframe id="' + id + '" name="' + id + '" src="about:blank" />');
173
- var io = $io[0];
174
-
175
- $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
176
-
177
- var xhr = { // mock object
178
- aborted: 0,
179
- responseText: null,
180
- responseXML: null,
181
- status: 0,
182
- statusText: 'n/a',
183
- getAllResponseHeaders: function() {},
184
- getResponseHeader: function() {},
185
- setRequestHeader: function() {},
186
- abort: function() {
187
- this.aborted = 1;
188
- $io.attr('src','about:blank'); // abort op in progress
189
- }
190
- };
191
-
192
- var g = opts.global;
193
- // trigger ajax global events so that activity/block indicators work like normal
194
- if (g && ! $.active++) $.event.trigger("ajaxStart");
195
- if (g) $.event.trigger("ajaxSend", [xhr, opts]);
160
+ $.ajax(options);
161
+
162
+ // fire 'notify' event
163
+ this.trigger('form-submit-notify', [this, options]);
164
+ return this;
165
+
166
+
167
+ // private function for handling file uploads (hat tip to YAHOO!)
168
+ function fileUpload() {
169
+ var form = $form[0];
170
+
171
+ if ($(':input[name=submit]', form).length) {
172
+ alert('Error: Form elements must not be named "submit".');
173
+ return;
174
+ }
175
+
176
+ var opts = $.extend({}, $.ajaxSettings, options);
177
+ var s = $.extend(true, {}, $.extend(true, {}, $.ajaxSettings), opts);
178
+
179
+ var id = 'jqFormIO' + (new Date().getTime());
180
+ var $io = $('<iframe id="' + id + '" name="' + id + '" src="'+ opts.iframeSrc +'" />');
181
+ var io = $io[0];
182
+
183
+ $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
184
+
185
+ var xhr = { // mock object
186
+ aborted: 0,
187
+ responseText: null,
188
+ responseXML: null,
189
+ status: 0,
190
+ statusText: 'n/a',
191
+ getAllResponseHeaders: function() {},
192
+ getResponseHeader: function() {},
193
+ setRequestHeader: function() {},
194
+ abort: function() {
195
+ this.aborted = 1;
196
+ $io.attr('src', opts.iframeSrc); // abort op in progress
197
+ }
198
+ };
199
+
200
+ var g = opts.global;
201
+ // trigger ajax global events so that activity/block indicators work like normal
202
+ if (g && ! $.active++) $.event.trigger("ajaxStart");
203
+ if (g) $.event.trigger("ajaxSend", [xhr, opts]);
196
204
 
197
205
  if (s.beforeSend && s.beforeSend(xhr, s) === false) {
198
- s.global && jQuery.active--;
206
+ s.global && $.active--;
207
+ return;
208
+ }
209
+ if (xhr.aborted)
199
210
  return;
200
- }
201
- if (xhr.aborted)
202
- return;
203
-
204
- var cbInvoked = 0;
205
- var timedOut = 0;
206
-
207
- // add submitting element to data if we know it
208
- var sub = form.clk;
209
- if (sub) {
210
- var n = sub.name;
211
- if (n && !sub.disabled) {
212
- options.extraData = options.extraData || {};
213
- options.extraData[n] = sub.value;
214
- if (sub.type == "image") {
215
- options.extraData[name+'.x'] = form.clk_x;
216
- options.extraData[name+'.y'] = form.clk_y;
217
- }
218
- }
219
- }
220
-
221
- // take a breath so that pending repaints get some cpu time before the upload starts
222
- setTimeout(function() {
223
- // make sure form attrs are set
224
- var t = $form.attr('target'), a = $form.attr('action');
211
+
212
+ var cbInvoked = 0;
213
+ var timedOut = 0;
214
+
215
+ // add submitting element to data if we know it
216
+ var sub = form.clk;
217
+ if (sub) {
218
+ var n = sub.name;
219
+ if (n && !sub.disabled) {
220
+ options.extraData = options.extraData || {};
221
+ options.extraData[n] = sub.value;
222
+ if (sub.type == "image") {
223
+ options.extraData[name+'.x'] = form.clk_x;
224
+ options.extraData[name+'.y'] = form.clk_y;
225
+ }
226
+ }
227
+ }
228
+
229
+ // take a breath so that pending repaints get some cpu time before the upload starts
230
+ setTimeout(function() {
231
+ // make sure form attrs are set
232
+ var t = $form.attr('target'), a = $form.attr('action');
225
233
 
226
234
  // update form attrs in IE friendly way
227
235
  form.setAttribute('target',id);
@@ -230,112 +238,125 @@ $.fn.ajaxSubmit = function(options) {
230
238
  if (form.getAttribute('action') != opts.url)
231
239
  form.setAttribute('action', opts.url);
232
240
 
233
- // ie borks in some cases when setting encoding
234
- if (! options.skipEncodingOverride) {
235
- $form.attr({
236
- encoding: 'multipart/form-data',
237
- enctype: 'multipart/form-data'
238
- });
239
- }
240
-
241
- // support timout
242
- if (opts.timeout)
243
- setTimeout(function() { timedOut = true; cb(); }, opts.timeout);
244
-
245
- // add "extra" data to form if provided in options
246
- var extraInputs = [];
247
- try {
248
- if (options.extraData)
249
- for (var n in options.extraData)
250
- extraInputs.push(
251
- $('<input type="hidden" name="'+n+'" value="'+options.extraData[n]+'" />')
252
- .appendTo(form)[0]);
253
-
254
- // add iframe to doc and submit the form
255
- $io.appendTo('body');
256
- io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
257
- form.submit();
258
- }
259
- finally {
260
- // reset attrs and remove "extra" input elements
241
+ // ie borks in some cases when setting encoding
242
+ if (! options.skipEncodingOverride) {
243
+ $form.attr({
244
+ encoding: 'multipart/form-data',
245
+ enctype: 'multipart/form-data'
246
+ });
247
+ }
248
+
249
+ // support timout
250
+ if (opts.timeout)
251
+ setTimeout(function() { timedOut = true; cb(); }, opts.timeout);
252
+
253
+ // add "extra" data to form if provided in options
254
+ var extraInputs = [];
255
+ try {
256
+ if (options.extraData)
257
+ for (var n in options.extraData)
258
+ extraInputs.push(
259
+ $('<input type="hidden" name="'+n+'" value="'+options.extraData[n]+'" />')
260
+ .appendTo(form)[0]);
261
+
262
+ // add iframe to doc and submit the form
263
+ $io.appendTo('body');
264
+ io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
265
+ form.submit();
266
+ }
267
+ finally {
268
+ // reset attrs and remove "extra" input elements
261
269
  form.setAttribute('action',a);
262
- t ? form.setAttribute('target', t) : $form.removeAttr('target');
263
- $(extraInputs).remove();
264
- }
265
- }, 10);
266
-
267
- var nullCheckFlag = 0;
268
-
269
- function cb() {
270
- if (cbInvoked++) return;
271
-
272
- io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);
273
-
274
- var ok = true;
275
- try {
276
- if (timedOut) throw 'timeout';
277
- // extract the server response from the iframe
278
- var data, doc;
279
-
280
- doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
281
-
282
- if ((doc.body == null || doc.body.innerHTML == '') && !nullCheckFlag) {
283
- // in some browsers (cough, Opera 9.2.x) the iframe DOM is not always traversable when
284
- // the onload callback fires, so we give them a 2nd chance
285
- nullCheckFlag = 1;
286
- cbInvoked--;
287
- setTimeout(cb, 100);
288
- return;
289
- }
290
-
291
- xhr.responseText = doc.body ? doc.body.innerHTML : null;
292
- xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
293
- xhr.getResponseHeader = function(header){
294
- var headers = {'content-type': opts.dataType};
295
- return headers[header];
296
- };
297
-
298
- if (opts.dataType == 'json' || opts.dataType == 'script') {
299
- var ta = doc.getElementsByTagName('textarea')[0];
300
- xhr.responseText = ta ? ta.value : xhr.responseText;
301
- }
302
- else if (opts.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
303
- xhr.responseXML = toXml(xhr.responseText);
304
- }
305
- data = $.httpData(xhr, opts.dataType);
306
- }
307
- catch(e){
308
- ok = false;
309
- $.handleError(opts, xhr, 'error', e);
310
- }
311
-
312
- // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
313
- if (ok) {
314
- opts.success(data, 'success');
315
- if (g) $.event.trigger("ajaxSuccess", [xhr, opts]);
316
- }
317
- if (g) $.event.trigger("ajaxComplete", [xhr, opts]);
318
- if (g && ! --$.active) $.event.trigger("ajaxStop");
319
- if (opts.complete) opts.complete(xhr, ok ? 'success' : 'error');
320
-
321
- // clean up
322
- setTimeout(function() {
323
- $io.remove();
324
- xhr.responseXML = null;
325
- }, 100);
326
- };
327
-
328
- function toXml(s, doc) {
329
- if (window.ActiveXObject) {
330
- doc = new ActiveXObject('Microsoft.XMLDOM');
331
- doc.async = 'false';
332
- doc.loadXML(s);
333
- }
334
- else
335
- doc = (new DOMParser()).parseFromString(s, 'text/xml');
336
- return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null;
337
- };
338
- };
270
+ t ? form.setAttribute('target', t) : $form.removeAttr('target');
271
+ $(extraInputs).remove();
272
+ }
273
+ }, 10);
274
+
275
+ var domCheckCount = 50;
276
+
277
+ function cb() {
278
+ if (cbInvoked++) return;
279
+
280
+ io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);
281
+
282
+ var ok = true;
283
+ try {
284
+ if (timedOut) throw 'timeout';
285
+ // extract the server response from the iframe
286
+ var data, doc;
287
+
288
+ doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
289
+
290
+ var isXml = opts.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
291
+ log('isXml='+isXml);
292
+ if (!isXml && (doc.body == null || doc.body.innerHTML == '')) {
293
+ if (--domCheckCount) {
294
+ // in some browsers (Opera) the iframe DOM is not always traversable when
295
+ // the onload callback fires, so we loop a bit to accommodate
296
+ cbInvoked = 0;
297
+ setTimeout(cb, 100);
298
+ return;
299
+ }
300
+ log('Could not access iframe DOM after 50 tries.');
301
+ return;
302
+ }
303
+
304
+ xhr.responseText = doc.body ? doc.body.innerHTML : null;
305
+ xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
306
+ xhr.getResponseHeader = function(header){
307
+ var headers = {'content-type': opts.dataType};
308
+ return headers[header];
309
+ };
310
+
311
+ if (opts.dataType == 'json' || opts.dataType == 'script') {
312
+ // see if user embedded response in textarea
313
+ var ta = doc.getElementsByTagName('textarea')[0];
314
+ if (ta)
315
+ xhr.responseText = ta.value;
316
+ else {
317
+ // account for browsers injecting pre around json response
318
+ var pre = doc.getElementsByTagName('pre')[0];
319
+ if (pre)
320
+ xhr.responseText = pre.innerHTML;
321
+ }
322
+ }
323
+ else if (opts.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
324
+ xhr.responseXML = toXml(xhr.responseText);
325
+ }
326
+ data = $.httpData(xhr, opts.dataType);
327
+ }
328
+ catch(e){
329
+ ok = false;
330
+ $.handleError(opts, xhr, 'error', e);
331
+ }
332
+
333
+ // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
334
+ if (ok) {
335
+ opts.success(data, 'success');
336
+ if (g) $.event.trigger("ajaxSuccess", [xhr, opts]);
337
+ }
338
+ if (g) $.event.trigger("ajaxComplete", [xhr, opts]);
339
+ if (g && ! --$.active) $.event.trigger("ajaxStop");
340
+ if (opts.complete) opts.complete(xhr, ok ? 'success' : 'error');
341
+
342
+ // clean up
343
+ setTimeout(function() {
344
+ $io.remove();
345
+ xhr.responseXML = null;
346
+ }, 100);
347
+ };
348
+
349
+ function toXml(s, doc) {
350
+ if (window.ActiveXObject) {
351
+ doc = new ActiveXObject('Microsoft.XMLDOM');
352
+ doc.async = 'false';
353
+ doc.loadXML(s);
354
+ }
355
+ else
356
+ doc = (new DOMParser()).parseFromString(s, 'text/xml');
357
+ return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null;
358
+ };
359
+ };
339
360
  };
340
361
 
341
362
  /**
@@ -344,9 +365,9 @@ $.fn.ajaxSubmit = function(options) {
344
365
  * The advantages of using this method instead of ajaxSubmit() are:
345
366
  *
346
367
  * 1: This method will include coordinates for <input type="image" /> elements (if the element
347
- * is used to submit the form).
368
+ * is used to submit the form).
348
369
  * 2. This method will include the submit element's name/value data (for the element that was
349
- * used to submit the form).
370
+ * used to submit the form).
350
371
  * 3. This method binds the submit() method to the form for you.
351
372
  *
352
373
  * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely
@@ -354,40 +375,42 @@ $.fn.ajaxSubmit = function(options) {
354
375
  * the form itself.
355
376
  */
356
377
  $.fn.ajaxForm = function(options) {
357
- return this.ajaxFormUnbind().bind('submit.form-plugin',function() {
358
- $(this).ajaxSubmit(options);
359
- return false;
360
- }).each(function() {
361
- // store options in hash
362
- $(":submit,input:image", this).bind('click.form-plugin',function(e) {
363
- var form = this.form;
364
- form.clk = this;
365
- if (this.type == 'image') {
366
- if (e.offsetX != undefined) {
367
- form.clk_x = e.offsetX;
368
- form.clk_y = e.offsetY;
369
- } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
370
- var offset = $(this).offset();
371
- form.clk_x = e.pageX - offset.left;
372
- form.clk_y = e.pageY - offset.top;
373
- } else {
374
- form.clk_x = e.pageX - this.offsetLeft;
375
- form.clk_y = e.pageY - this.offsetTop;
376
- }
377
- }
378
- // clear form vars
379
- setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 10);
380
- });
381
- });
378
+ return this.ajaxFormUnbind().bind('submit.form-plugin', function() {
379
+ $(this).ajaxSubmit(options);
380
+ return false;
381
+ }).bind('click.form-plugin', function(e) {
382
+ var target = e.target;
383
+ var $el = $(target);
384
+ if (!($el.is(":submit,input:image"))) {
385
+ // is this a child element of the submit el? (ex: a span within a button)
386
+ var t = $el.closest(':submit');
387
+ if (t.length == 0)
388
+ return;
389
+ target = t[0];
390
+ }
391
+ var form = this;
392
+ form.clk = target;
393
+ if (target.type == 'image') {
394
+ if (e.offsetX != undefined) {
395
+ form.clk_x = e.offsetX;
396
+ form.clk_y = e.offsetY;
397
+ } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
398
+ var offset = $el.offset();
399
+ form.clk_x = e.pageX - offset.left;
400
+ form.clk_y = e.pageY - offset.top;
401
+ } else {
402
+ form.clk_x = e.pageX - target.offsetLeft;
403
+ form.clk_y = e.pageY - target.offsetTop;
404
+ }
405
+ }
406
+ // clear form vars
407
+ setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
408
+ });
382
409
  };
383
410
 
384
411
  // ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
385
412
  $.fn.ajaxFormUnbind = function() {
386
- this.unbind('submit.form-plugin');
387
- return this.each(function() {
388
- $(":submit,input:image", this).unbind('click.form-plugin');
389
- });
390
-
413
+ return this.unbind('submit.form-plugin click.form-plugin');
391
414
  };
392
415
 
393
416
  /**
@@ -402,44 +425,44 @@ $.fn.ajaxFormUnbind = function() {
402
425
  * ajaxSubmit() and ajaxForm() methods.
403
426
  */
404
427
  $.fn.formToArray = function(semantic) {
405
- var a = [];
406
- if (this.length == 0) return a;
407
-
408
- var form = this[0];
409
- var els = semantic ? form.getElementsByTagName('*') : form.elements;
410
- if (!els) return a;
411
- for(var i=0, max=els.length; i < max; i++) {
412
- var el = els[i];
413
- var n = el.name;
414
- if (!n) continue;
415
-
416
- if (semantic && form.clk && el.type == "image") {
417
- // handle image inputs on the fly when semantic == true
418
- if(!el.disabled && form.clk == el)
419
- a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
420
- continue;
421
- }
422
-
423
- var v = $.fieldValue(el, true);
424
- if (v && v.constructor == Array) {
425
- for(var j=0, jmax=v.length; j < jmax; j++)
426
- a.push({name: n, value: v[j]});
427
- }
428
- else if (v !== null && typeof v != 'undefined')
429
- a.push({name: n, value: v});
430
- }
431
-
432
- if (!semantic && form.clk) {
433
- // input type=='image' are not found in elements array! handle them here
434
- var inputs = form.getElementsByTagName("input");
435
- for(var i=0, max=inputs.length; i < max; i++) {
436
- var input = inputs[i];
437
- var n = input.name;
438
- if(n && !input.disabled && input.type == "image" && form.clk == input)
439
- a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
440
- }
441
- }
442
- return a;
428
+ var a = [];
429
+ if (this.length == 0) return a;
430
+
431
+ var form = this[0];
432
+ var els = semantic ? form.getElementsByTagName('*') : form.elements;
433
+ if (!els) return a;
434
+ for(var i=0, max=els.length; i < max; i++) {
435
+ var el = els[i];
436
+ var n = el.name;
437
+ if (!n) continue;
438
+
439
+ if (semantic && form.clk && el.type == "image") {
440
+ // handle image inputs on the fly when semantic == true
441
+ if(!el.disabled && form.clk == el) {
442
+ a.push({name: n, value: $(el).val()});
443
+ a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
444
+ }
445
+ continue;
446
+ }
447
+
448
+ var v = $.fieldValue(el, true);
449
+ if (v && v.constructor == Array) {
450
+ for(var j=0, jmax=v.length; j < jmax; j++)
451
+ a.push({name: n, value: v[j]});
452
+ }
453
+ else if (v !== null && typeof v != 'undefined')
454
+ a.push({name: n, value: v});
455
+ }
456
+
457
+ if (!semantic && form.clk) {
458
+ // input type=='image' are not found in elements array! handle it here
459
+ var $input = $(form.clk), input = $input[0], n = input.name;
460
+ if (n && !input.disabled && input.type == 'image') {
461
+ a.push({name: n, value: $input.val()});
462
+ a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
463
+ }
464
+ }
465
+ return a;
443
466
  };
444
467
 
445
468
  /**
@@ -447,8 +470,8 @@ $.fn.formToArray = function(semantic) {
447
470
  * in the format: name1=value1&amp;name2=value2
448
471
  */
449
472
  $.fn.formSerialize = function(semantic) {
450
- //hand off to jQuery.param for proper encoding
451
- return $.param(this.formToArray(semantic));
473
+ //hand off to jQuery.param for proper encoding
474
+ return $.param(this.formToArray(semantic));
452
475
  };
453
476
 
454
477
  /**
@@ -456,32 +479,32 @@ $.fn.formSerialize = function(semantic) {
456
479
  * This method will return a string in the format: name1=value1&amp;name2=value2
457
480
  */
458
481
  $.fn.fieldSerialize = function(successful) {
459
- var a = [];
460
- this.each(function() {
461
- var n = this.name;
462
- if (!n) return;
463
- var v = $.fieldValue(this, successful);
464
- if (v && v.constructor == Array) {
465
- for (var i=0,max=v.length; i < max; i++)
466
- a.push({name: n, value: v[i]});
467
- }
468
- else if (v !== null && typeof v != 'undefined')
469
- a.push({name: this.name, value: v});
470
- });
471
- //hand off to jQuery.param for proper encoding
472
- return $.param(a);
482
+ var a = [];
483
+ this.each(function() {
484
+ var n = this.name;
485
+ if (!n) return;
486
+ var v = $.fieldValue(this, successful);
487
+ if (v && v.constructor == Array) {
488
+ for (var i=0,max=v.length; i < max; i++)
489
+ a.push({name: n, value: v[i]});
490
+ }
491
+ else if (v !== null && typeof v != 'undefined')
492
+ a.push({name: this.name, value: v});
493
+ });
494
+ //hand off to jQuery.param for proper encoding
495
+ return $.param(a);
473
496
  };
474
497
 
475
498
  /**
476
499
  * Returns the value(s) of the element in the matched set. For example, consider the following form:
477
500
  *
478
501
  * <form><fieldset>
479
- * <input name="A" type="text" />
480
- * <input name="A" type="text" />
481
- * <input name="B" type="checkbox" value="B1" />
482
- * <input name="B" type="checkbox" value="B2"/>
483
- * <input name="C" type="radio" value="C1" />
484
- * <input name="C" type="radio" value="C2" />
502
+ * <input name="A" type="text" />
503
+ * <input name="A" type="text" />
504
+ * <input name="B" type="checkbox" value="B1" />
505
+ * <input name="B" type="checkbox" value="B2"/>
506
+ * <input name="C" type="radio" value="C1" />
507
+ * <input name="C" type="radio" value="C2" />
485
508
  * </fieldset></form>
486
509
  *
487
510
  * var v = $(':text').fieldValue();
@@ -508,51 +531,51 @@ $.fn.fieldSerialize = function(successful) {
508
531
  * for each element is returned.
509
532
  *
510
533
  * Note: This method *always* returns an array. If no valid value can be determined the
511
- * array will be empty, otherwise it will contain one or more values.
534
+ * array will be empty, otherwise it will contain one or more values.
512
535
  */
513
536
  $.fn.fieldValue = function(successful) {
514
- for (var val=[], i=0, max=this.length; i < max; i++) {
515
- var el = this[i];
516
- var v = $.fieldValue(el, successful);
517
- if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length))
518
- continue;
519
- v.constructor == Array ? $.merge(val, v) : val.push(v);
520
- }
521
- return val;
537
+ for (var val=[], i=0, max=this.length; i < max; i++) {
538
+ var el = this[i];
539
+ var v = $.fieldValue(el, successful);
540
+ if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length))
541
+ continue;
542
+ v.constructor == Array ? $.merge(val, v) : val.push(v);
543
+ }
544
+ return val;
522
545
  };
523
546
 
524
547
  /**
525
548
  * Returns the value of the field element.
526
549
  */
527
550
  $.fieldValue = function(el, successful) {
528
- var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
529
- if (typeof successful == 'undefined') successful = true;
530
-
531
- if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
532
- (t == 'checkbox' || t == 'radio') && !el.checked ||
533
- (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
534
- tag == 'select' && el.selectedIndex == -1))
535
- return null;
536
-
537
- if (tag == 'select') {
538
- var index = el.selectedIndex;
539
- if (index < 0) return null;
540
- var a = [], ops = el.options;
541
- var one = (t == 'select-one');
542
- var max = (one ? index+1 : ops.length);
543
- for(var i=(one ? index : 0); i < max; i++) {
544
- var op = ops[i];
545
- if (op.selected) {
551
+ var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
552
+ if (typeof successful == 'undefined') successful = true;
553
+
554
+ if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
555
+ (t == 'checkbox' || t == 'radio') && !el.checked ||
556
+ (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
557
+ tag == 'select' && el.selectedIndex == -1))
558
+ return null;
559
+
560
+ if (tag == 'select') {
561
+ var index = el.selectedIndex;
562
+ if (index < 0) return null;
563
+ var a = [], ops = el.options;
564
+ var one = (t == 'select-one');
565
+ var max = (one ? index+1 : ops.length);
566
+ for(var i=(one ? index : 0); i < max; i++) {
567
+ var op = ops[i];
568
+ if (op.selected) {
546
569
  var v = op.value;
547
570
  if (!v) // extra pain for IE...
548
- v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
549
- if (one) return v;
550
- a.push(v);
551
- }
552
- }
553
- return a;
554
- }
555
- return el.value;
571
+ v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
572
+ if (one) return v;
573
+ a.push(v);
574
+ }
575
+ }
576
+ return a;
577
+ }
578
+ return el.value;
556
579
  };
557
580
 
558
581
  /**
@@ -564,46 +587,46 @@ $.fieldValue = function(el, successful) {
564
587
  * - button elements will *not* be effected
565
588
  */
566
589
  $.fn.clearForm = function() {
567
- return this.each(function() {
568
- $('input,select,textarea', this).clearFields();
569
- });
590
+ return this.each(function() {
591
+ $('input,select,textarea', this).clearFields();
592
+ });
570
593
  };
571
594
 
572
595
  /**
573
596
  * Clears the selected form elements.
574
597
  */
575
598
  $.fn.clearFields = $.fn.clearInputs = function() {
576
- return this.each(function() {
577
- var t = this.type, tag = this.tagName.toLowerCase();
578
- if (t == 'text' || t == 'password' || tag == 'textarea')
579
- this.value = '';
580
- else if (t == 'checkbox' || t == 'radio')
581
- this.checked = false;
582
- else if (tag == 'select')
583
- this.selectedIndex = -1;
584
- });
599
+ return this.each(function() {
600
+ var t = this.type, tag = this.tagName.toLowerCase();
601
+ if (t == 'text' || t == 'password' || tag == 'textarea')
602
+ this.value = '';
603
+ else if (t == 'checkbox' || t == 'radio')
604
+ this.checked = false;
605
+ else if (tag == 'select')
606
+ this.selectedIndex = -1;
607
+ });
585
608
  };
586
609
 
587
610
  /**
588
611
  * Resets the form data. Causes all form elements to be reset to their original value.
589
612
  */
590
613
  $.fn.resetForm = function() {
591
- return this.each(function() {
592
- // guard against an input with the name of 'reset'
593
- // note that IE reports the reset function as an 'object'
594
- if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType))
595
- this.reset();
596
- });
614
+ return this.each(function() {
615
+ // guard against an input with the name of 'reset'
616
+ // note that IE reports the reset function as an 'object'
617
+ if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType))
618
+ this.reset();
619
+ });
597
620
  };
598
621
 
599
622
  /**
600
623
  * Enables or disables any matching elements.
601
624
  */
602
625
  $.fn.enable = function(b) {
603
- if (b == undefined) b = true;
604
- return this.each(function() {
605
- this.disabled = !b;
606
- });
626
+ if (b == undefined) b = true;
627
+ return this.each(function() {
628
+ this.disabled = !b;
629
+ });
607
630
  };
608
631
 
609
632
  /**
@@ -611,27 +634,27 @@ $.fn.enable = function(b) {
611
634
  * selects/deselects and matching option elements.
612
635
  */
613
636
  $.fn.selected = function(select) {
614
- if (select == undefined) select = true;
615
- return this.each(function() {
616
- var t = this.type;
617
- if (t == 'checkbox' || t == 'radio')
618
- this.checked = select;
619
- else if (this.tagName.toLowerCase() == 'option') {
620
- var $sel = $(this).parent('select');
621
- if (select && $sel[0] && $sel[0].type == 'select-one') {
622
- // deselect all other options
623
- $sel.find('option').selected(false);
624
- }
625
- this.selected = select;
626
- }
627
- });
637
+ if (select == undefined) select = true;
638
+ return this.each(function() {
639
+ var t = this.type;
640
+ if (t == 'checkbox' || t == 'radio')
641
+ this.checked = select;
642
+ else if (this.tagName.toLowerCase() == 'option') {
643
+ var $sel = $(this).parent('select');
644
+ if (select && $sel[0] && $sel[0].type == 'select-one') {
645
+ // deselect all other options
646
+ $sel.find('option').selected(false);
647
+ }
648
+ this.selected = select;
649
+ }
650
+ });
628
651
  };
629
652
 
630
653
  // helper fn for console logging
631
654
  // set $.fn.ajaxSubmit.debug to true to enable debug logging
632
655
  function log() {
633
- if ($.fn.ajaxSubmit.debug && window.console && window.console.log)
634
- window.console.log('[jquery.form] ' + Array.prototype.join.call(arguments,''));
656
+ if ($.fn.ajaxSubmit.debug && window.console && window.console.log)
657
+ window.console.log('[jquery.form] ' + Array.prototype.join.call(arguments,''));
635
658
  };
636
659
 
637
660
  })(jQuery);