wheels 0.0.48 → 0.0.49

Sign up to get free protection for your applications and to get access to all the features.
Files changed (215) hide show
  1. data/VERSION +1 -1
  2. data/app/controllers/access_control_entries_controller.rb +4 -4
  3. data/app/controllers/external_links_controller.rb +5 -0
  4. data/app/controllers/feedbacks_controller.rb +10 -0
  5. data/app/controllers/menus_controller.rb +2 -0
  6. data/app/controllers/pages_controller.rb +16 -29
  7. data/app/controllers/sitemaps_controller.rb +135 -0
  8. data/app/helpers/application_helper.rb +4 -3
  9. data/app/helpers/external_links_helper.rb +2 -0
  10. data/app/helpers/feedbacks_helper.rb +2 -0
  11. data/app/helpers/menus_helper.rb +2 -0
  12. data/app/helpers/sitemaps_helper.rb +12 -0
  13. data/app/mailers/feedback_mailer.rb +10 -0
  14. data/app/models/ability.rb +2 -1
  15. data/app/models/access_control_entry.rb +17 -15
  16. data/app/models/external_link.rb +4 -0
  17. data/app/models/feedback.rb +13 -0
  18. data/app/models/image.rb +1 -1
  19. data/app/models/menu.rb +4 -0
  20. data/app/models/page.rb +2 -5
  21. data/app/models/sitemap.rb +153 -0
  22. data/app/models/user.rb +7 -1
  23. data/app/validators/email_validator.rb +22 -0
  24. data/app/views/access_control_entries/_form.html.haml +1 -1
  25. data/app/views/access_control_entries/_index.html.haml +3 -3
  26. data/app/views/access_control_entries/_show.html.haml +1 -1
  27. data/app/views/external_links/_fields_for.html.haml +2 -0
  28. data/app/views/external_links/_form.html.haml +18 -0
  29. data/app/views/external_links/_show.html.haml +7 -0
  30. data/app/views/external_links/edit.html.haml +7 -0
  31. data/app/views/external_links/index.html.haml +23 -0
  32. data/app/views/external_links/new.html.haml +5 -0
  33. data/app/views/external_links/show.html.haml +2 -0
  34. data/app/views/feedback_mailer/submit_feedback.html.haml +22 -0
  35. data/app/views/feedbacks/_form.html.haml +37 -0
  36. data/app/views/feedbacks/index.html.haml +27 -0
  37. data/app/views/feedbacks/new.html.haml +5 -0
  38. data/app/views/feedbacks/show.html.haml +19 -0
  39. data/app/views/layouts/application.html.haml +21 -16
  40. data/app/views/layouts/bare.html.haml +2 -0
  41. data/app/views/loadbehind/_view.js.haml +1 -2
  42. data/app/views/menus/_form.html.haml +13 -0
  43. data/app/views/menus/edit.html.haml +7 -0
  44. data/app/views/menus/index.html.haml +19 -0
  45. data/app/views/menus/new.html.haml +5 -0
  46. data/app/views/menus/show.html.haml +7 -0
  47. data/app/views/pages/_child_pages_links.html.haml +1 -1
  48. data/app/views/pages/_control_panel.html.haml +1 -6
  49. data/app/views/pages/_form.html.haml +2 -2
  50. data/app/views/pages/_form_fields.html.haml +7 -2
  51. data/app/views/pages/_show.html.haml +4 -0
  52. data/app/views/pages/create.js.haml +2 -1
  53. data/app/views/pages/destroy.js.haml +3 -0
  54. data/app/views/pages/edit.js.haml +4 -0
  55. data/app/views/pages/index.html.haml +4 -2
  56. data/app/views/pages/index.js.haml +3 -0
  57. data/app/views/pages/new.js.haml +3 -0
  58. data/app/views/pages/show.html.haml +2 -10
  59. data/app/views/pages/show.js.haml +3 -0
  60. data/app/views/pages/update.js.haml +2 -2
  61. data/app/views/sitemaps/edit.html.haml +12 -0
  62. data/app/views/sitemaps/edit.js.erb +0 -0
  63. data/app/views/sitemaps/index.html.haml +93 -0
  64. data/app/views/sitemaps/index.json.erb +23 -0
  65. data/app/views/sitemaps/new.html.haml +8 -0
  66. data/app/views/sitemaps/new.js.erb +0 -0
  67. data/app/views/users/edit.html.haml +45 -0
  68. data/db/migrate/{add_fields_to_users.rb → 0010_add_fields_to_users.rb} +0 -0
  69. data/db/migrate/{create_blogs.rb → 0020_create_blogs.rb} +0 -0
  70. data/db/migrate/{create_galleries.rb → 0030_create_galleries.rb} +0 -0
  71. data/db/migrate/{create_images.rb → 0040_create_images.rb} +0 -0
  72. data/db/migrate/{create_profiles.rb → 0050_create_profiles.rb} +0 -0
  73. data/db/migrate/{insert_admin_user_and_roles.rb → 0060_insert_admin_user_and_roles.rb} +0 -0
  74. data/db/migrate/{create_pages.rb → 0070_create_pages.rb} +0 -0
  75. data/db/migrate/{create_forums.rb → 0080_create_forums.rb} +0 -0
  76. data/db/migrate/{create_discussions.rb → 0090_create_discussions.rb} +0 -0
  77. data/db/migrate/{create_forum_messages.rb → 0100_create_forum_messages.rb} +0 -0
  78. data/db/migrate/{create_access_control_entries.rb → 0110_create_access_control_entries.rb} +3 -3
  79. data/db/migrate/{create_attachments.rb → 0120_create_attachments.rb} +0 -4
  80. data/db/migrate/{create_roles.rb → 0130_create_roles.rb} +0 -0
  81. data/db/migrate/0140_create_feedbacks.rb +20 -0
  82. data/db/migrate/0150_create_external_links.rb +14 -0
  83. data/db/migrate/0160_create_sitemaps.rb +17 -0
  84. data/db/migrate/0170_create_menus.rb +14 -0
  85. data/lib/development_mail_interceptor.rb +7 -0
  86. data/lib/generators/wheels/recipes/wheels.rb +18 -12
  87. data/lib/wheels/base.rb +7 -0
  88. data/lib/wheels/routes.rb +8 -3
  89. data/lib/wheels.rb +2 -0
  90. data/public/javascripts/jquery-validate/additional-methods.js +259 -0
  91. data/public/javascripts/jquery-validate/changelog.txt +239 -0
  92. data/public/javascripts/jquery-validate/jquery.validate.js +1146 -0
  93. data/public/javascripts/jquery-validate/jquery.validate.min.js +16 -0
  94. data/public/javascripts/jquery-validate/jquery.validate.pack.js +15 -0
  95. data/public/javascripts/jquery-validate/lib/jquery-1.4.2.js +6240 -0
  96. data/public/javascripts/jquery-validate/lib/jquery.form.js +660 -0
  97. data/public/javascripts/jquery-validate/lib/jquery.js +4376 -0
  98. data/public/javascripts/jquery-validate/lib/jquery.metadata.js +122 -0
  99. data/public/javascripts/jquery-validate/localization/messages_ar.js +24 -0
  100. data/public/javascripts/jquery-validate/localization/messages_bg.js +23 -0
  101. data/public/javascripts/jquery-validate/localization/messages_cn.js +23 -0
  102. data/public/javascripts/jquery-validate/localization/messages_cs.js +23 -0
  103. data/public/javascripts/jquery-validate/localization/messages_da.js +20 -0
  104. data/public/javascripts/jquery-validate/localization/messages_de.js +20 -0
  105. data/public/javascripts/jquery-validate/localization/messages_el.js +24 -0
  106. data/public/javascripts/jquery-validate/localization/messages_es.js +23 -0
  107. data/public/javascripts/jquery-validate/localization/messages_fa.js +23 -0
  108. data/public/javascripts/jquery-validate/localization/messages_fi.js +21 -0
  109. data/public/javascripts/jquery-validate/localization/messages_fr.js +23 -0
  110. data/public/javascripts/jquery-validate/localization/messages_he.js +23 -0
  111. data/public/javascripts/jquery-validate/localization/messages_hu.js +20 -0
  112. data/public/javascripts/jquery-validate/localization/messages_it.js +23 -0
  113. data/public/javascripts/jquery-validate/localization/messages_kk.js +23 -0
  114. data/public/javascripts/jquery-validate/localization/messages_lt.js +23 -0
  115. data/public/javascripts/jquery-validate/localization/messages_lv.js +23 -0
  116. data/public/javascripts/jquery-validate/localization/messages_nl.js +23 -0
  117. data/public/javascripts/jquery-validate/localization/messages_no.js +23 -0
  118. data/public/javascripts/jquery-validate/localization/messages_pl.js +23 -0
  119. data/public/javascripts/jquery-validate/localization/messages_ptbr.js +23 -0
  120. data/public/javascripts/jquery-validate/localization/messages_ptpt.js +23 -0
  121. data/public/javascripts/jquery-validate/localization/messages_ro.js +23 -0
  122. data/public/javascripts/jquery-validate/localization/messages_ru.js +23 -0
  123. data/public/javascripts/jquery-validate/localization/messages_se.js +21 -0
  124. data/public/javascripts/jquery-validate/localization/messages_sk.js +20 -0
  125. data/public/javascripts/jquery-validate/localization/messages_tr.js +23 -0
  126. data/public/javascripts/jquery-validate/localization/messages_tw.js +23 -0
  127. data/public/javascripts/jquery-validate/localization/messages_ua.js +23 -0
  128. data/public/javascripts/jquery-validate/localization/methods_de.js +12 -0
  129. data/public/javascripts/jquery-validate/localization/methods_nl.js +9 -0
  130. data/public/javascripts/jquery-validate/localization/methods_pt.js +9 -0
  131. data/public/javascripts/jquery-validate/todo +172 -0
  132. data/public/javascripts/jquery.cookie.js +96 -0
  133. data/public/javascripts/jquery.filedrop.js +253 -0
  134. data/public/javascripts/jquery.hotkeys.js +99 -0
  135. data/public/javascripts/jquery.js +6240 -0
  136. data/public/javascripts/jquery.jstree.js +3510 -0
  137. data/public/javascripts/jquery.uploadify.js +26 -0
  138. data/public/javascripts/jquery.validate.js +1147 -0
  139. data/public/javascripts/sitemap_jstree.js +329 -0
  140. data/public/javascripts/swfobject.js +4 -0
  141. data/public/jstree/_demo/_dump.sql +20 -0
  142. data/public/jstree/_demo/_inc/__mysql_errors.log +0 -0
  143. data/public/jstree/_demo/_inc/class._database.php +146 -0
  144. data/public/jstree/_demo/_inc/class._database_i.php +152 -0
  145. data/public/jstree/_demo/_inc/class.tree.php +602 -0
  146. data/public/jstree/_demo/_install.txt +6 -0
  147. data/public/jstree/_demo/config.php +14 -0
  148. data/public/jstree/_demo/index.html +262 -0
  149. data/public/jstree/_demo/server.php +69 -0
  150. data/public/jstree/_docs/!style.css +37 -0
  151. data/public/jstree/_docs/_drive.png +0 -0
  152. data/public/jstree/_docs/_html_data.html +2 -0
  153. data/public/jstree/_docs/_json_data.json +4 -0
  154. data/public/jstree/_docs/_search_data.json +6 -0
  155. data/public/jstree/_docs/_search_result.json +1 -0
  156. data/public/jstree/_docs/_xml_flat.xml +12 -0
  157. data/public/jstree/_docs/_xml_nest.xml +18 -0
  158. data/public/jstree/_docs/checkbox.html +148 -0
  159. data/public/jstree/_docs/contextmenu.html +120 -0
  160. data/public/jstree/_docs/cookies.html +96 -0
  161. data/public/jstree/_docs/core.html +622 -0
  162. data/public/jstree/_docs/crrm.html +315 -0
  163. data/public/jstree/_docs/dnd.html +197 -0
  164. data/public/jstree/_docs/hotkeys.html +81 -0
  165. data/public/jstree/_docs/html_data.html +174 -0
  166. data/public/jstree/_docs/index.html +75 -0
  167. data/public/jstree/_docs/json_data.html +240 -0
  168. data/public/jstree/_docs/languages.html +138 -0
  169. data/public/jstree/_docs/search.html +114 -0
  170. data/public/jstree/_docs/sort.html +84 -0
  171. data/public/jstree/_docs/syntax/!script.js +2232 -0
  172. data/public/jstree/_docs/syntax/!style.css +511 -0
  173. data/public/jstree/_docs/syntax/clipboard.swf +0 -0
  174. data/public/jstree/_docs/syntax/help.png +0 -0
  175. data/public/jstree/_docs/syntax/magnifier.png +0 -0
  176. data/public/jstree/_docs/syntax/page_white_code.png +0 -0
  177. data/public/jstree/_docs/syntax/page_white_copy.png +0 -0
  178. data/public/jstree/_docs/syntax/printer.png +0 -0
  179. data/public/jstree/_docs/syntax/wrapping.png +0 -0
  180. data/public/jstree/_docs/themeroller.html +98 -0
  181. data/public/jstree/_docs/themes.html +126 -0
  182. data/public/jstree/_docs/types.html +173 -0
  183. data/public/jstree/_docs/ui.html +188 -0
  184. data/public/jstree/_docs/unique.html +70 -0
  185. data/public/jstree/_docs/xml_data.html +214 -0
  186. data/public/jstree/_lib/jquery.cookie.js +96 -0
  187. data/public/jstree/_lib/jquery.hotkeys.js +99 -0
  188. data/public/jstree/_lib/jquery.js +6240 -0
  189. data/public/jstree/jquery.jstree.js +3510 -0
  190. data/public/jstree/jstree.html +237 -0
  191. data/public/jstree/themes/apple/bg.jpg +0 -0
  192. data/public/jstree/themes/apple/d.png +0 -0
  193. data/public/jstree/themes/apple/dot_for_ie.gif +0 -0
  194. data/public/jstree/themes/apple/style.css +60 -0
  195. data/public/jstree/themes/apple/throbber.gif +0 -0
  196. data/public/jstree/themes/classic/d.png +0 -0
  197. data/public/jstree/themes/classic/dot_for_ie.gif +0 -0
  198. data/public/jstree/themes/classic/style.css +59 -0
  199. data/public/jstree/themes/classic/throbber.gif +0 -0
  200. data/public/jstree/themes/default/d.gif +0 -0
  201. data/public/jstree/themes/default/d.png +0 -0
  202. data/public/jstree/themes/default/style.css +73 -0
  203. data/public/jstree/themes/default/throbber.gif +0 -0
  204. data/public/jstree/themes/default-rtl/d.gif +0 -0
  205. data/public/jstree/themes/default-rtl/d.png +0 -0
  206. data/public/jstree/themes/default-rtl/dots.gif +0 -0
  207. data/public/jstree/themes/default-rtl/style.css +83 -0
  208. data/public/jstree/themes/default-rtl/throbber.gif +0 -0
  209. data/public/stylesheets/sass/dreamy.sass +21 -56
  210. data/public/stylesheets/sass/menu.sass +43 -9
  211. data/public/stylesheets/sass/uploadify.sass +52 -0
  212. data/public/stylesheets/ui-lightness/images/ui-icons_228ef1_256x240.png +0 -0
  213. data/public/stylesheets/ui-lightness/jquery-ui-1.8.4.custom.css +549 -0
  214. data/wheels.gemspec +187 -15
  215. metadata +188 -16
@@ -0,0 +1,660 @@
1
+ /*
2
+ * jQuery Form Plugin
3
+ * version: 2.36 (07-NOV-2009)
4
+ * @requires jQuery v1.2.6 or later
5
+ *
6
+ * Examples and documentation at: http://malsup.com/jquery/form/
7
+ * Dual licensed under the MIT and GPL licenses:
8
+ * http://www.opensource.org/licenses/mit-license.php
9
+ * http://www.gnu.org/licenses/gpl.html
10
+ */
11
+ ;(function($) {
12
+
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.
40
+ */
41
+
42
+ /**
43
+ * ajaxSubmit() provides a mechanism for immediately submitting
44
+ * an HTML form using AJAX.
45
+ */
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
+ 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
+ }
159
+ else
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]);
204
+
205
+ if (s.beforeSend && s.beforeSend(xhr, s) === false) {
206
+ s.global && $.active--;
207
+ return;
208
+ }
209
+ if (xhr.aborted)
210
+ return;
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');
233
+
234
+ // update form attrs in IE friendly way
235
+ form.setAttribute('target',id);
236
+ if (form.getAttribute('method') != 'POST')
237
+ form.setAttribute('method', 'POST');
238
+ if (form.getAttribute('action') != opts.url)
239
+ form.setAttribute('action', opts.url);
240
+
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
269
+ form.setAttribute('action',a);
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
+ };
360
+ };
361
+
362
+ /**
363
+ * ajaxForm() provides a mechanism for fully automating form submission.
364
+ *
365
+ * The advantages of using this method instead of ajaxSubmit() are:
366
+ *
367
+ * 1: This method will include coordinates for <input type="image" /> elements (if the element
368
+ * is used to submit the form).
369
+ * 2. This method will include the submit element's name/value data (for the element that was
370
+ * used to submit the form).
371
+ * 3. This method binds the submit() method to the form for you.
372
+ *
373
+ * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely
374
+ * passes the options argument along after properly binding events for submit elements and
375
+ * the form itself.
376
+ */
377
+ $.fn.ajaxForm = function(options) {
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
+ });
409
+ };
410
+
411
+ // ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
412
+ $.fn.ajaxFormUnbind = function() {
413
+ return this.unbind('submit.form-plugin click.form-plugin');
414
+ };
415
+
416
+ /**
417
+ * formToArray() gathers form element data into an array of objects that can
418
+ * be passed to any of the following ajax functions: $.get, $.post, or load.
419
+ * Each object in the array has both a 'name' and 'value' property. An example of
420
+ * an array for a simple login form might be:
421
+ *
422
+ * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
423
+ *
424
+ * It is this array that is passed to pre-submit callback functions provided to the
425
+ * ajaxSubmit() and ajaxForm() methods.
426
+ */
427
+ $.fn.formToArray = function(semantic) {
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;
466
+ };
467
+
468
+ /**
469
+ * Serializes form data into a 'submittable' string. This method will return a string
470
+ * in the format: name1=value1&amp;name2=value2
471
+ */
472
+ $.fn.formSerialize = function(semantic) {
473
+ //hand off to jQuery.param for proper encoding
474
+ return $.param(this.formToArray(semantic));
475
+ };
476
+
477
+ /**
478
+ * Serializes all field elements in the jQuery object into a query string.
479
+ * This method will return a string in the format: name1=value1&amp;name2=value2
480
+ */
481
+ $.fn.fieldSerialize = function(successful) {
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);
496
+ };
497
+
498
+ /**
499
+ * Returns the value(s) of the element in the matched set. For example, consider the following form:
500
+ *
501
+ * <form><fieldset>
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" />
508
+ * </fieldset></form>
509
+ *
510
+ * var v = $(':text').fieldValue();
511
+ * // if no values are entered into the text inputs
512
+ * v == ['','']
513
+ * // if values entered into the text inputs are 'foo' and 'bar'
514
+ * v == ['foo','bar']
515
+ *
516
+ * var v = $(':checkbox').fieldValue();
517
+ * // if neither checkbox is checked
518
+ * v === undefined
519
+ * // if both checkboxes are checked
520
+ * v == ['B1', 'B2']
521
+ *
522
+ * var v = $(':radio').fieldValue();
523
+ * // if neither radio is checked
524
+ * v === undefined
525
+ * // if first radio is checked
526
+ * v == ['C1']
527
+ *
528
+ * The successful argument controls whether or not the field element must be 'successful'
529
+ * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
530
+ * The default value of the successful argument is true. If this value is false the value(s)
531
+ * for each element is returned.
532
+ *
533
+ * Note: This method *always* returns an array. If no valid value can be determined the
534
+ * array will be empty, otherwise it will contain one or more values.
535
+ */
536
+ $.fn.fieldValue = function(successful) {
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;
545
+ };
546
+
547
+ /**
548
+ * Returns the value of the field element.
549
+ */
550
+ $.fieldValue = function(el, successful) {
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) {
569
+ var v = op.value;
570
+ if (!v) // extra pain for IE...
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;
579
+ };
580
+
581
+ /**
582
+ * Clears the form data. Takes the following actions on the form's input fields:
583
+ * - input text fields will have their 'value' property set to the empty string
584
+ * - select elements will have their 'selectedIndex' property set to -1
585
+ * - checkbox and radio inputs will have their 'checked' property set to false
586
+ * - inputs of type submit, button, reset, and hidden will *not* be effected
587
+ * - button elements will *not* be effected
588
+ */
589
+ $.fn.clearForm = function() {
590
+ return this.each(function() {
591
+ $('input,select,textarea', this).clearFields();
592
+ });
593
+ };
594
+
595
+ /**
596
+ * Clears the selected form elements.
597
+ */
598
+ $.fn.clearFields = $.fn.clearInputs = function() {
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
+ });
608
+ };
609
+
610
+ /**
611
+ * Resets the form data. Causes all form elements to be reset to their original value.
612
+ */
613
+ $.fn.resetForm = function() {
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
+ });
620
+ };
621
+
622
+ /**
623
+ * Enables or disables any matching elements.
624
+ */
625
+ $.fn.enable = function(b) {
626
+ if (b == undefined) b = true;
627
+ return this.each(function() {
628
+ this.disabled = !b;
629
+ });
630
+ };
631
+
632
+ /**
633
+ * Checks/unchecks any matching checkboxes or radio buttons and
634
+ * selects/deselects and matching option elements.
635
+ */
636
+ $.fn.selected = function(select) {
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
+ });
651
+ };
652
+
653
+ // helper fn for console logging
654
+ // set $.fn.ajaxSubmit.debug to true to enable debug logging
655
+ function log() {
656
+ if ($.fn.ajaxSubmit.debug && window.console && window.console.log)
657
+ window.console.log('[jquery.form] ' + Array.prototype.join.call(arguments,''));
658
+ };
659
+
660
+ })(jQuery);