webmaster@1
|
1 // $Id: ahah.js,v 1.7.2.1 2008/02/11 14:46:27 goba Exp $ |
webmaster@1
|
2 |
webmaster@1
|
3 /** |
webmaster@1
|
4 * Provides AJAX-like page updating via AHAH (Asynchronous HTML and HTTP). |
webmaster@1
|
5 * |
webmaster@1
|
6 * AHAH is a method of making a request via Javascript while viewing an HTML |
webmaster@1
|
7 * page. The request returns a small chunk of HTML, which is then directly |
webmaster@1
|
8 * injected into the page. |
webmaster@1
|
9 * |
webmaster@1
|
10 * Drupal uses this file to enhance form elements with #ahah[path] and |
webmaster@1
|
11 * #ahah[wrapper] properties. If set, this file will automatically be included |
webmaster@1
|
12 * to provide AHAH capabilities. |
webmaster@1
|
13 */ |
webmaster@1
|
14 |
webmaster@1
|
15 /** |
webmaster@1
|
16 * Attaches the ahah behavior to each ahah form element. |
webmaster@1
|
17 */ |
webmaster@1
|
18 Drupal.behaviors.ahah = function(context) { |
webmaster@1
|
19 for (var base in Drupal.settings.ahah) { |
webmaster@1
|
20 if (!$('#'+ base + '.ahah-processed').size()) { |
webmaster@1
|
21 var element_settings = Drupal.settings.ahah[base]; |
webmaster@1
|
22 |
webmaster@1
|
23 $(element_settings.selector).each(function() { |
webmaster@1
|
24 element_settings.element = this; |
webmaster@1
|
25 var ahah = new Drupal.ahah(base, element_settings); |
webmaster@1
|
26 }); |
webmaster@1
|
27 |
webmaster@1
|
28 $('#'+ base).addClass('ahah-processed'); |
webmaster@1
|
29 } |
webmaster@1
|
30 } |
webmaster@1
|
31 }; |
webmaster@1
|
32 |
webmaster@1
|
33 /** |
webmaster@1
|
34 * AHAH object. |
webmaster@1
|
35 */ |
webmaster@1
|
36 Drupal.ahah = function(base, element_settings) { |
webmaster@1
|
37 // Set the properties for this object. |
webmaster@1
|
38 this.element = element_settings.element; |
webmaster@1
|
39 this.selector = element_settings.selector; |
webmaster@1
|
40 this.event = element_settings.event; |
webmaster@1
|
41 this.keypress = element_settings.keypress; |
webmaster@1
|
42 this.url = element_settings.url; |
webmaster@1
|
43 this.wrapper = '#'+ element_settings.wrapper; |
webmaster@1
|
44 this.effect = element_settings.effect; |
webmaster@1
|
45 this.method = element_settings.method; |
webmaster@1
|
46 this.progress = element_settings.progress; |
webmaster@1
|
47 this.button = element_settings.button || { }; |
webmaster@1
|
48 |
webmaster@1
|
49 if (this.effect == 'none') { |
webmaster@1
|
50 this.showEffect = 'show'; |
webmaster@1
|
51 this.hideEffect = 'hide'; |
webmaster@1
|
52 this.showSpeed = ''; |
webmaster@1
|
53 } |
webmaster@1
|
54 else if (this.effect == 'fade') { |
webmaster@1
|
55 this.showEffect = 'fadeIn'; |
webmaster@1
|
56 this.hideEffect = 'fadeOut'; |
webmaster@1
|
57 this.showSpeed = 'slow'; |
webmaster@1
|
58 } |
webmaster@1
|
59 else { |
webmaster@1
|
60 this.showEffect = this.effect + 'Toggle'; |
webmaster@1
|
61 this.hideEffect = this.effect + 'Toggle'; |
webmaster@1
|
62 this.showSpeed = 'slow'; |
webmaster@1
|
63 } |
webmaster@1
|
64 |
webmaster@1
|
65 // Record the form action and target, needed for iFrame file uploads. |
webmaster@1
|
66 var form = $(this.element).parents('form'); |
webmaster@1
|
67 this.form_action = form.attr('action'); |
webmaster@1
|
68 this.form_target = form.attr('target'); |
webmaster@1
|
69 this.form_encattr = form.attr('encattr'); |
webmaster@1
|
70 |
webmaster@1
|
71 // Set the options for the ajaxSubmit function. |
webmaster@1
|
72 // The 'this' variable will not persist inside of the options object. |
webmaster@1
|
73 var ahah = this; |
webmaster@1
|
74 var options = { |
webmaster@1
|
75 url: ahah.url, |
webmaster@1
|
76 data: ahah.button, |
webmaster@1
|
77 beforeSubmit: function(form_values, element_settings, options) { |
webmaster@1
|
78 return ahah.beforeSubmit(form_values, element_settings, options); |
webmaster@1
|
79 }, |
webmaster@1
|
80 success: function(response, status) { |
webmaster@1
|
81 // Sanity check for browser support (object expected). |
webmaster@1
|
82 // When using iFrame uploads, responses must be returned as a string. |
webmaster@1
|
83 if (typeof(response) == 'string') { |
webmaster@1
|
84 response = Drupal.parseJson(response); |
webmaster@1
|
85 } |
webmaster@1
|
86 return ahah.success(response, status); |
webmaster@1
|
87 }, |
webmaster@1
|
88 complete: function(response, status) { |
webmaster@1
|
89 if (status == 'error' || status == 'parsererror') { |
webmaster@1
|
90 return ahah.error(response, ahah.url); |
webmaster@1
|
91 } |
webmaster@1
|
92 }, |
webmaster@1
|
93 dataType: 'json', |
webmaster@1
|
94 type: 'POST' |
webmaster@1
|
95 }; |
webmaster@1
|
96 |
webmaster@1
|
97 // Bind the ajaxSubmit function to the element event. |
webmaster@1
|
98 $(element_settings.element).bind(element_settings.event, function() { |
webmaster@1
|
99 $(element_settings.element).parents('form').ajaxSubmit(options); |
webmaster@1
|
100 return false; |
webmaster@1
|
101 }); |
webmaster@1
|
102 // If necessary, enable keyboard submission so that AHAH behaviors |
webmaster@1
|
103 // can be triggered through keyboard input as well as e.g. a mousedown |
webmaster@1
|
104 // action. |
webmaster@1
|
105 if (element_settings.keypress) { |
webmaster@1
|
106 $(element_settings.element).keypress(function(event) { |
webmaster@1
|
107 // Detect enter key. |
webmaster@1
|
108 if (event.keyCode == 13) { |
webmaster@1
|
109 $(element_settings.element).trigger(element_settings.event); |
webmaster@1
|
110 return false; |
webmaster@1
|
111 } |
webmaster@1
|
112 }); |
webmaster@1
|
113 } |
webmaster@1
|
114 }; |
webmaster@1
|
115 |
webmaster@1
|
116 /** |
webmaster@1
|
117 * Handler for the form redirection submission. |
webmaster@1
|
118 */ |
webmaster@1
|
119 Drupal.ahah.prototype.beforeSubmit = function (form_values, element, options) { |
webmaster@1
|
120 // Disable the element that received the change. |
webmaster@1
|
121 $(this.element).addClass('progress-disabled').attr('disabled', true); |
webmaster@1
|
122 |
webmaster@1
|
123 // Insert progressbar or throbber. |
webmaster@1
|
124 if (this.progress.type == 'bar') { |
webmaster@1
|
125 var progressBar = new Drupal.progressBar('ahah-progress-' + this.element.id, eval(this.progress.update_callback), this.progress.method, eval(this.progress.error_callback)); |
webmaster@1
|
126 if (this.progress.message) { |
webmaster@1
|
127 progressBar.setProgress(-1, this.progress.message); |
webmaster@1
|
128 } |
webmaster@1
|
129 if (this.progress.url) { |
webmaster@1
|
130 progressBar.startMonitoring(this.progress.url, this.progress.interval || 1500); |
webmaster@1
|
131 } |
webmaster@1
|
132 this.progress.element = $(progressBar.element).addClass('ahah-progress ahah-progress-bar'); |
webmaster@1
|
133 this.progress.object = progressBar; |
webmaster@1
|
134 $(this.element).after(this.progress.element); |
webmaster@1
|
135 } |
webmaster@1
|
136 else if (this.progress.type == 'throbber') { |
webmaster@1
|
137 this.progress.element = $('<div class="ahah-progress ahah-progress-throbber"><div class="throbber"> </div></div>'); |
webmaster@1
|
138 if (this.progress.message) { |
webmaster@1
|
139 $('.throbber', this.progress.element).after('<div class="message">' + this.progress.message + '</div>') |
webmaster@1
|
140 } |
webmaster@1
|
141 $(this.element).after(this.progress.element); |
webmaster@1
|
142 } |
webmaster@1
|
143 }; |
webmaster@1
|
144 |
webmaster@1
|
145 /** |
webmaster@1
|
146 * Handler for the form redirection completion. |
webmaster@1
|
147 */ |
webmaster@1
|
148 Drupal.ahah.prototype.success = function (response, status) { |
webmaster@1
|
149 var wrapper = $(this.wrapper); |
webmaster@1
|
150 var form = $(this.element).parents('form'); |
webmaster@1
|
151 // Manually insert HTML into the jQuery object, using $() directly crashes |
webmaster@1
|
152 // Safari with long string lengths. http://dev.jquery.com/ticket/1152 |
webmaster@1
|
153 var new_content = $('<div></div>').html(response.data); |
webmaster@1
|
154 |
webmaster@1
|
155 // Restore the previous action and target to the form. |
webmaster@1
|
156 form.attr('action', this.form_action); |
webmaster@1
|
157 this.form_target ? form.attr('target', this.form_target) : form.removeAttr('target'); |
webmaster@1
|
158 this.form_encattr ? form.attr('target', this.form_encattr) : form.removeAttr('encattr'); |
webmaster@1
|
159 |
webmaster@1
|
160 // Remove the progress element. |
webmaster@1
|
161 if (this.progress.element) { |
webmaster@1
|
162 $(this.progress.element).remove(); |
webmaster@1
|
163 } |
webmaster@1
|
164 if (this.progress.object) { |
webmaster@1
|
165 this.progress.object.stopMonitoring(); |
webmaster@1
|
166 } |
webmaster@1
|
167 $(this.element).removeClass('progress-disabled').attr('disabled', false); |
webmaster@1
|
168 |
webmaster@1
|
169 // Add the new content to the page. |
webmaster@1
|
170 Drupal.freezeHeight(); |
webmaster@1
|
171 if (this.method == 'replace') { |
webmaster@1
|
172 wrapper.empty().append(new_content); |
webmaster@1
|
173 } |
webmaster@1
|
174 else { |
webmaster@1
|
175 wrapper[this.method](new_content); |
webmaster@1
|
176 } |
webmaster@1
|
177 |
webmaster@1
|
178 // Immediately hide the new content if we're using any effects. |
webmaster@1
|
179 if (this.showEffect != 'show') { |
webmaster@1
|
180 new_content.hide(); |
webmaster@1
|
181 } |
webmaster@1
|
182 |
webmaster@1
|
183 // Determine what effect use and what content will receive the effect, then |
webmaster@1
|
184 // show the new content. For browser compatibility, Safari is excluded from |
webmaster@1
|
185 // using effects on table rows. |
webmaster@1
|
186 if (($.browser.safari && $("tr.ahah-new-content", new_content).size() > 0)) { |
webmaster@1
|
187 new_content.show(); |
webmaster@1
|
188 } |
webmaster@1
|
189 else if ($('.ahah-new-content', new_content).size() > 0) { |
webmaster@1
|
190 $('.ahah-new-content', new_content).hide(); |
webmaster@1
|
191 new_content.show(); |
webmaster@1
|
192 $(".ahah-new-content", new_content)[this.showEffect](this.showSpeed); |
webmaster@1
|
193 } |
webmaster@1
|
194 else if (this.showEffect != 'show') { |
webmaster@1
|
195 new_content[this.showEffect](this.showSpeed); |
webmaster@1
|
196 } |
webmaster@1
|
197 |
webmaster@1
|
198 // Attach all javascript behaviors to the new content, if it was successfully |
webmaster@1
|
199 // added to the page, this if statement allows #ahah[wrapper] to be optional. |
webmaster@1
|
200 if (new_content.parents('html').length > 0) { |
webmaster@1
|
201 Drupal.attachBehaviors(new_content); |
webmaster@1
|
202 } |
webmaster@1
|
203 |
webmaster@1
|
204 Drupal.unfreezeHeight(); |
webmaster@1
|
205 }; |
webmaster@1
|
206 |
webmaster@1
|
207 /** |
webmaster@1
|
208 * Handler for the form redirection error. |
webmaster@1
|
209 */ |
webmaster@1
|
210 Drupal.ahah.prototype.error = function (response, uri) { |
webmaster@1
|
211 alert(Drupal.ahahError(response, uri)); |
webmaster@1
|
212 // Resore the previous action and target to the form. |
webmaster@1
|
213 $(this.element).parent('form').attr( { action: this.form_action, target: this.form_target} ); |
webmaster@1
|
214 // Remove the progress element. |
webmaster@1
|
215 if (this.progress.element) { |
webmaster@1
|
216 $(this.progress.element).remove(); |
webmaster@1
|
217 } |
webmaster@1
|
218 if (this.progress.object) { |
webmaster@1
|
219 this.progress.object.stopMonitoring(); |
webmaster@1
|
220 } |
webmaster@1
|
221 // Undo hide. |
webmaster@1
|
222 $(this.wrapper).show(); |
webmaster@1
|
223 // Re-enable the element. |
webmaster@1
|
224 $(this.element).removeClass('progess-disabled').attr('disabled', false); |
webmaster@1
|
225 }; |