##// END OF EJS Templates
Show some more info on a server error in the form
neko259 -
r1634:ed076afa default
parent child Browse files
Show More
@@ -1,456 +1,460 b''
1 /*
1 /*
2 @licstart The following is the entire license notice for the
2 @licstart The following is the entire license notice for the
3 JavaScript code in this page.
3 JavaScript code in this page.
4
4
5
5
6 Copyright (C) 2013-2014 neko259
6 Copyright (C) 2013-2014 neko259
7
7
8 The JavaScript code in this page is free software: you can
8 The JavaScript code in this page is free software: you can
9 redistribute it and/or modify it under the terms of the GNU
9 redistribute it and/or modify it under the terms of the GNU
10 General Public License (GNU GPL) as published by the Free Software
10 General Public License (GNU GPL) as published by the Free Software
11 Foundation, either version 3 of the License, or (at your option)
11 Foundation, either version 3 of the License, or (at your option)
12 any later version. The code is distributed WITHOUT ANY WARRANTY;
12 any later version. The code is distributed WITHOUT ANY WARRANTY;
13 without even the implied warranty of MERCHANTABILITY or FITNESS
13 without even the implied warranty of MERCHANTABILITY or FITNESS
14 FOR A PARTICULAR PURPOSE. See the GNU GPL for more details.
14 FOR A PARTICULAR PURPOSE. See the GNU GPL for more details.
15
15
16 As additional permission under GNU GPL version 3 section 7, you
16 As additional permission under GNU GPL version 3 section 7, you
17 may distribute non-source (e.g., minimized or compacted) forms of
17 may distribute non-source (e.g., minimized or compacted) forms of
18 that code without the copy of the GNU GPL normally required by
18 that code without the copy of the GNU GPL normally required by
19 section 4, provided you include this license notice and a URL
19 section 4, provided you include this license notice and a URL
20 through which recipients can access the Corresponding Source.
20 through which recipients can access the Corresponding Source.
21
21
22 @licend The above is the entire license notice
22 @licend The above is the entire license notice
23 for the JavaScript code in this page.
23 for the JavaScript code in this page.
24 */
24 */
25
25
26 var CLASS_POST = '.post';
26 var CLASS_POST = '.post';
27
27
28 var POST_ADDED = 0;
28 var POST_ADDED = 0;
29 var POST_UPDATED = 1;
29 var POST_UPDATED = 1;
30
30
31 // TODO These need to be syncronized with board settings.
31 // TODO These need to be syncronized with board settings.
32 var JS_AUTOUPDATE_PERIOD = 20000;
32 var JS_AUTOUPDATE_PERIOD = 20000;
33 // TODO This needs to be the same for attachment download time limit.
33 // TODO This needs to be the same for attachment download time limit.
34 var POST_AJAX_TIMEOUT = 30000;
34 var POST_AJAX_TIMEOUT = 30000;
35 var BLINK_SPEED = 500;
35 var BLINK_SPEED = 500;
36
36
37 var ALLOWED_FOR_PARTIAL_UPDATE = [
37 var ALLOWED_FOR_PARTIAL_UPDATE = [
38 'refmap',
38 'refmap',
39 'post-info'
39 'post-info'
40 ];
40 ];
41
41
42 var ATTR_CLASS = 'class';
42 var ATTR_CLASS = 'class';
43 var ATTR_UID = 'data-uid';
43 var ATTR_UID = 'data-uid';
44
44
45 var wsUser = '';
45 var wsUser = '';
46
46
47 var unreadPosts = 0;
47 var unreadPosts = 0;
48 var documentOriginalTitle = '';
48 var documentOriginalTitle = '';
49
49
50 // Thread ID does not change, can be stored one time
50 // Thread ID does not change, can be stored one time
51 var threadId = $('div.thread').children(CLASS_POST).first().attr('id');
51 var threadId = $('div.thread').children(CLASS_POST).first().attr('id');
52 var blinkColor = $('<div class="post-blink"></div>').css('background-color');
52 var blinkColor = $('<div class="post-blink"></div>').css('background-color');
53
53
54 /**
54 /**
55 * Connect to websocket server and subscribe to thread updates. On any update we
55 * Connect to websocket server and subscribe to thread updates. On any update we
56 * request a thread diff.
56 * request a thread diff.
57 *
57 *
58 * @returns {boolean} true if connected, false otherwise
58 * @returns {boolean} true if connected, false otherwise
59 */
59 */
60 function connectWebsocket() {
60 function connectWebsocket() {
61 var metapanel = $('.metapanel')[0];
61 var metapanel = $('.metapanel')[0];
62
62
63 var wsHost = metapanel.getAttribute('data-ws-host');
63 var wsHost = metapanel.getAttribute('data-ws-host');
64 var wsPort = metapanel.getAttribute('data-ws-port');
64 var wsPort = metapanel.getAttribute('data-ws-port');
65
65
66 if (wsHost.length > 0 && wsPort.length > 0) {
66 if (wsHost.length > 0 && wsPort.length > 0) {
67 var centrifuge = new Centrifuge({
67 var centrifuge = new Centrifuge({
68 "url": 'ws://' + wsHost + ':' + wsPort + "/connection/websocket",
68 "url": 'ws://' + wsHost + ':' + wsPort + "/connection/websocket",
69 "project": metapanel.getAttribute('data-ws-project'),
69 "project": metapanel.getAttribute('data-ws-project'),
70 "user": wsUser,
70 "user": wsUser,
71 "timestamp": metapanel.getAttribute('data-ws-token-time'),
71 "timestamp": metapanel.getAttribute('data-ws-token-time'),
72 "token": metapanel.getAttribute('data-ws-token'),
72 "token": metapanel.getAttribute('data-ws-token'),
73 "debug": false
73 "debug": false
74 });
74 });
75
75
76 centrifuge.on('error', function(error_message) {
76 centrifuge.on('error', function(error_message) {
77 console.log("Error connecting to websocket server.");
77 console.log("Error connecting to websocket server.");
78 console.log(error_message);
78 console.log(error_message);
79 console.log("Using javascript update instead.");
79 console.log("Using javascript update instead.");
80
80
81 // If websockets don't work, enable JS update instead
81 // If websockets don't work, enable JS update instead
82 enableJsUpdate()
82 enableJsUpdate()
83 });
83 });
84
84
85 centrifuge.on('connect', function() {
85 centrifuge.on('connect', function() {
86 var channelName = 'thread:' + threadId;
86 var channelName = 'thread:' + threadId;
87 centrifuge.subscribe(channelName, function(message) {
87 centrifuge.subscribe(channelName, function(message) {
88 getThreadDiff();
88 getThreadDiff();
89 });
89 });
90
90
91 // For the case we closed the browser and missed some updates
91 // For the case we closed the browser and missed some updates
92 getThreadDiff();
92 getThreadDiff();
93 $('#autoupdate').hide();
93 $('#autoupdate').hide();
94 });
94 });
95
95
96 centrifuge.connect();
96 centrifuge.connect();
97
97
98 return true;
98 return true;
99 } else {
99 } else {
100 return false;
100 return false;
101 }
101 }
102 }
102 }
103
103
104 /**
104 /**
105 * Get diff of the posts from the current thread timestamp.
105 * Get diff of the posts from the current thread timestamp.
106 * This is required if the browser was closed and some post updates were
106 * This is required if the browser was closed and some post updates were
107 * missed.
107 * missed.
108 */
108 */
109 function getThreadDiff() {
109 function getThreadDiff() {
110 var all_posts = $('.post');
110 var all_posts = $('.post');
111
111
112 var uids = '';
112 var uids = '';
113 var posts = all_posts;
113 var posts = all_posts;
114 for (var i = 0; i < posts.length; i++) {
114 for (var i = 0; i < posts.length; i++) {
115 uids += posts[i].getAttribute('data-uid') + ' ';
115 uids += posts[i].getAttribute('data-uid') + ' ';
116 }
116 }
117
117
118 var data = {
118 var data = {
119 uids: uids,
119 uids: uids,
120 thread: threadId
120 thread: threadId
121 };
121 };
122
122
123 var diffUrl = '/api/diff_thread/';
123 var diffUrl = '/api/diff_thread/';
124
124
125 $.post(diffUrl,
125 $.post(diffUrl,
126 data,
126 data,
127 function(data) {
127 function(data) {
128 var updatedPosts = data.updated;
128 var updatedPosts = data.updated;
129 var addedPostCount = 0;
129 var addedPostCount = 0;
130
130
131 for (var i = 0; i < updatedPosts.length; i++) {
131 for (var i = 0; i < updatedPosts.length; i++) {
132 var postText = updatedPosts[i];
132 var postText = updatedPosts[i];
133 var post = $(postText);
133 var post = $(postText);
134
134
135 if (updatePost(post) == POST_ADDED) {
135 if (updatePost(post) == POST_ADDED) {
136 addedPostCount++;
136 addedPostCount++;
137 }
137 }
138 }
138 }
139
139
140 var hasMetaUpdates = updatedPosts.length > 0;
140 var hasMetaUpdates = updatedPosts.length > 0;
141 if (hasMetaUpdates) {
141 if (hasMetaUpdates) {
142 updateMetadataPanel();
142 updateMetadataPanel();
143 }
143 }
144
144
145 if (addedPostCount > 0) {
145 if (addedPostCount > 0) {
146 updateBumplimitProgress(addedPostCount);
146 updateBumplimitProgress(addedPostCount);
147 }
147 }
148
148
149 if (updatedPosts.length > 0) {
149 if (updatedPosts.length > 0) {
150 showNewPostsTitle(addedPostCount);
150 showNewPostsTitle(addedPostCount);
151 }
151 }
152
152
153 // TODO Process removed posts if any
153 // TODO Process removed posts if any
154 $('.metapanel').attr('data-last-update', data.last_update);
154 $('.metapanel').attr('data-last-update', data.last_update);
155
155
156 if (data.subscribed == 'True') {
156 if (data.subscribed == 'True') {
157 var favButton = $('.not_fav');
157 var favButton = $('.not_fav');
158
158
159 if (favButton.length > 0) {
159 if (favButton.length > 0) {
160 favButton.attr('value', 'unsubscribe');
160 favButton.attr('value', 'unsubscribe');
161 favButton.removeClass('not_fav');
161 favButton.removeClass('not_fav');
162 favButton.addClass('fav');
162 favButton.addClass('fav');
163 }
163 }
164 }
164 }
165 },
165 },
166 'json'
166 'json'
167 )
167 )
168 }
168 }
169
169
170 /**
170 /**
171 * Add or update the post on html page.
171 * Add or update the post on html page.
172 */
172 */
173 function updatePost(postHtml) {
173 function updatePost(postHtml) {
174 // This needs to be set on start because the page is scrolled after posts
174 // This needs to be set on start because the page is scrolled after posts
175 // are added or updated
175 // are added or updated
176 var bottom = isPageBottom();
176 var bottom = isPageBottom();
177
177
178 var post = $(postHtml);
178 var post = $(postHtml);
179
179
180 var threadBlock = $('div.thread');
180 var threadBlock = $('div.thread');
181
181
182 var postId = post.attr('id');
182 var postId = post.attr('id');
183
183
184 // If the post already exists, replace it. Otherwise add as a new one.
184 // If the post already exists, replace it. Otherwise add as a new one.
185 var existingPosts = threadBlock.children('.post[id=' + postId + ']');
185 var existingPosts = threadBlock.children('.post[id=' + postId + ']');
186
186
187 var type;
187 var type;
188
188
189 if (existingPosts.size() > 0) {
189 if (existingPosts.size() > 0) {
190 replacePartial(existingPosts.first(), post, false);
190 replacePartial(existingPosts.first(), post, false);
191 post = existingPosts.first();
191 post = existingPosts.first();
192
192
193 type = POST_UPDATED;
193 type = POST_UPDATED;
194 } else {
194 } else {
195 post.appendTo(threadBlock);
195 post.appendTo(threadBlock);
196
196
197 if (bottom) {
197 if (bottom) {
198 scrollToBottom();
198 scrollToBottom();
199 }
199 }
200
200
201 type = POST_ADDED;
201 type = POST_ADDED;
202 }
202 }
203
203
204 processNewPost(post);
204 processNewPost(post);
205
205
206 return type;
206 return type;
207 }
207 }
208
208
209 /**
209 /**
210 * Initiate a blinking animation on a node to show it was updated.
210 * Initiate a blinking animation on a node to show it was updated.
211 */
211 */
212 function blink(node) {
212 function blink(node) {
213 node.effect('highlight', { color: blinkColor }, BLINK_SPEED);
213 node.effect('highlight', { color: blinkColor }, BLINK_SPEED);
214 }
214 }
215
215
216 function isPageBottom() {
216 function isPageBottom() {
217 var scroll = $(window).scrollTop() / ($(document).height()
217 var scroll = $(window).scrollTop() / ($(document).height()
218 - $(window).height());
218 - $(window).height());
219
219
220 return scroll == 1
220 return scroll == 1
221 }
221 }
222
222
223 function enableJsUpdate() {
223 function enableJsUpdate() {
224 setInterval(getThreadDiff, JS_AUTOUPDATE_PERIOD);
224 setInterval(getThreadDiff, JS_AUTOUPDATE_PERIOD);
225 return true;
225 return true;
226 }
226 }
227
227
228 function initAutoupdate() {
228 function initAutoupdate() {
229 if (location.protocol === 'https:') {
229 if (location.protocol === 'https:') {
230 return enableJsUpdate();
230 return enableJsUpdate();
231 } else {
231 } else {
232 if (connectWebsocket()) {
232 if (connectWebsocket()) {
233 return true;
233 return true;
234 } else {
234 } else {
235 return enableJsUpdate();
235 return enableJsUpdate();
236 }
236 }
237 }
237 }
238 }
238 }
239
239
240 function getReplyCount() {
240 function getReplyCount() {
241 return $('.thread').children(CLASS_POST).length
241 return $('.thread').children(CLASS_POST).length
242 }
242 }
243
243
244 function getImageCount() {
244 function getImageCount() {
245 return $('.thread').find('img').length
245 return $('.thread').find('img').length
246 }
246 }
247
247
248 /**
248 /**
249 * Update post count, images count and last update time in the metadata
249 * Update post count, images count and last update time in the metadata
250 * panel.
250 * panel.
251 */
251 */
252 function updateMetadataPanel() {
252 function updateMetadataPanel() {
253 var replyCountField = $('#reply-count');
253 var replyCountField = $('#reply-count');
254 var imageCountField = $('#image-count');
254 var imageCountField = $('#image-count');
255
255
256 var replyCount = getReplyCount();
256 var replyCount = getReplyCount();
257 replyCountField.text(replyCount);
257 replyCountField.text(replyCount);
258 var imageCount = getImageCount();
258 var imageCount = getImageCount();
259 imageCountField.text(imageCount);
259 imageCountField.text(imageCount);
260
260
261 var lastUpdate = $('.post:last').children('.post-info').first()
261 var lastUpdate = $('.post:last').children('.post-info').first()
262 .children('.pub_time').first().html();
262 .children('.pub_time').first().html();
263 if (lastUpdate !== '') {
263 if (lastUpdate !== '') {
264 var lastUpdateField = $('#last-update');
264 var lastUpdateField = $('#last-update');
265 lastUpdateField.html(lastUpdate);
265 lastUpdateField.html(lastUpdate);
266 blink(lastUpdateField);
266 blink(lastUpdateField);
267 }
267 }
268
268
269 blink(replyCountField);
269 blink(replyCountField);
270 blink(imageCountField);
270 blink(imageCountField);
271
271
272 $('#message-count-text').text(ngettext('message', 'messages', replyCount));
272 $('#message-count-text').text(ngettext('message', 'messages', replyCount));
273 $('#image-count-text').text(ngettext('image', 'images', imageCount));
273 $('#image-count-text').text(ngettext('image', 'images', imageCount));
274 }
274 }
275
275
276 /**
276 /**
277 * Update bumplimit progress bar
277 * Update bumplimit progress bar
278 */
278 */
279 function updateBumplimitProgress(postDelta) {
279 function updateBumplimitProgress(postDelta) {
280 var progressBar = $('#bumplimit_progress');
280 var progressBar = $('#bumplimit_progress');
281 if (progressBar) {
281 if (progressBar) {
282 var postsToLimitElement = $('#left_to_limit');
282 var postsToLimitElement = $('#left_to_limit');
283
283
284 var oldPostsToLimit = parseInt(postsToLimitElement.text());
284 var oldPostsToLimit = parseInt(postsToLimitElement.text());
285 var postCount = getReplyCount();
285 var postCount = getReplyCount();
286 var bumplimit = postCount - postDelta + oldPostsToLimit;
286 var bumplimit = postCount - postDelta + oldPostsToLimit;
287
287
288 var newPostsToLimit = bumplimit - postCount;
288 var newPostsToLimit = bumplimit - postCount;
289 if (newPostsToLimit <= 0) {
289 if (newPostsToLimit <= 0) {
290 $('.bar-bg').remove();
290 $('.bar-bg').remove();
291 } else {
291 } else {
292 postsToLimitElement.text(newPostsToLimit);
292 postsToLimitElement.text(newPostsToLimit);
293 progressBar.width((100 - postCount / bumplimit * 100.0) + '%');
293 progressBar.width((100 - postCount / bumplimit * 100.0) + '%');
294 }
294 }
295 }
295 }
296 }
296 }
297
297
298 /**
298 /**
299 * Show 'new posts' text in the title if the document is not visible to a user
299 * Show 'new posts' text in the title if the document is not visible to a user
300 */
300 */
301 function showNewPostsTitle(newPostCount) {
301 function showNewPostsTitle(newPostCount) {
302 if (document.hidden) {
302 if (document.hidden) {
303 if (documentOriginalTitle === '') {
303 if (documentOriginalTitle === '') {
304 documentOriginalTitle = document.title;
304 documentOriginalTitle = document.title;
305 }
305 }
306 unreadPosts = unreadPosts + newPostCount;
306 unreadPosts = unreadPosts + newPostCount;
307
307
308 var newTitle = null;
308 var newTitle = null;
309 if (unreadPosts > 0) {
309 if (unreadPosts > 0) {
310 newTitle = '[' + unreadPosts + '] ';
310 newTitle = '[' + unreadPosts + '] ';
311 } else {
311 } else {
312 newTitle = '* ';
312 newTitle = '* ';
313 }
313 }
314 newTitle += documentOriginalTitle;
314 newTitle += documentOriginalTitle;
315
315
316 document.title = newTitle;
316 document.title = newTitle;
317
317
318 document.addEventListener('visibilitychange', function() {
318 document.addEventListener('visibilitychange', function() {
319 if (documentOriginalTitle !== '') {
319 if (documentOriginalTitle !== '') {
320 document.title = documentOriginalTitle;
320 document.title = documentOriginalTitle;
321 documentOriginalTitle = '';
321 documentOriginalTitle = '';
322 unreadPosts = 0;
322 unreadPosts = 0;
323 }
323 }
324
324
325 document.removeEventListener('visibilitychange', null);
325 document.removeEventListener('visibilitychange', null);
326 });
326 });
327 }
327 }
328 }
328 }
329
329
330 /**
330 /**
331 * Clear all entered values in the form fields
331 * Clear all entered values in the form fields
332 */
332 */
333 function resetForm(form) {
333 function resetForm(form) {
334 form.find('input:text, input:password, input:file, select, textarea').val('');
334 form.find('input:text, input:password, input:file, select, textarea').val('');
335 form.find('input:radio, input:checkbox')
335 form.find('input:radio, input:checkbox')
336 .removeAttr('checked').removeAttr('selected');
336 .removeAttr('checked').removeAttr('selected');
337 $('.file_wrap').find('.file-thumb').remove();
337 $('.file_wrap').find('.file-thumb').remove();
338 $('#preview-text').hide();
338 $('#preview-text').hide();
339 }
339 }
340
340
341 /**
341 /**
342 * When the form is posted, this method will be run as a callback
342 * When the form is posted, this method will be run as a callback
343 */
343 */
344 function updateOnPost(response, statusText, xhr, form) {
344 function updateOnPost(response, statusText, xhr, form) {
345 var json = $.parseJSON(response);
345 var json = $.parseJSON(response);
346 var status = json.status;
346 var status = json.status;
347
347
348 showAsErrors(form, '');
348 showAsErrors(form, '');
349
349
350 if (status === 'ok') {
350 if (status === 'ok') {
351 resetFormPosition();
351 resetFormPosition();
352 resetForm(form);
352 resetForm(form);
353 getThreadDiff();
353 getThreadDiff();
354 scrollToBottom();
354 scrollToBottom();
355 } else {
355 } else {
356 var errors = json.errors;
356 var errors = json.errors;
357 for (var i = 0; i < errors.length; i++) {
357 for (var i = 0; i < errors.length; i++) {
358 var fieldErrors = errors[i];
358 var fieldErrors = errors[i];
359
359
360 var error = fieldErrors.errors;
360 var error = fieldErrors.errors;
361
361
362 showAsErrors(form, error);
362 showAsErrors(form, error);
363 }
363 }
364 }
364 }
365 }
365 }
366
366
367
367
368 /**
368 /**
369 * Run js methods that are usually run on the document, on the new post
369 * Run js methods that are usually run on the document, on the new post
370 */
370 */
371 function processNewPost(post) {
371 function processNewPost(post) {
372 addScriptsToPost(post);
372 addScriptsToPost(post);
373 blink(post);
373 blink(post);
374 }
374 }
375
375
376 function replacePartial(oldNode, newNode, recursive) {
376 function replacePartial(oldNode, newNode, recursive) {
377 if (!equalNodes(oldNode, newNode)) {
377 if (!equalNodes(oldNode, newNode)) {
378 // Update parent node attributes
378 // Update parent node attributes
379 updateNodeAttr(oldNode, newNode, ATTR_CLASS);
379 updateNodeAttr(oldNode, newNode, ATTR_CLASS);
380 updateNodeAttr(oldNode, newNode, ATTR_UID);
380 updateNodeAttr(oldNode, newNode, ATTR_UID);
381
381
382 // Replace children
382 // Replace children
383 var children = oldNode.children();
383 var children = oldNode.children();
384 if (children.length == 0) {
384 if (children.length == 0) {
385 oldNode.replaceWith(newNode);
385 oldNode.replaceWith(newNode);
386 } else {
386 } else {
387 var newChildren = newNode.children();
387 var newChildren = newNode.children();
388 newChildren.each(function(i) {
388 newChildren.each(function(i) {
389 var newChild = newChildren.eq(i);
389 var newChild = newChildren.eq(i);
390 var newChildClass = newChild.attr(ATTR_CLASS);
390 var newChildClass = newChild.attr(ATTR_CLASS);
391
391
392 // Update only certain allowed blocks (e.g. not images)
392 // Update only certain allowed blocks (e.g. not images)
393 if (ALLOWED_FOR_PARTIAL_UPDATE.indexOf(newChildClass) > -1) {
393 if (ALLOWED_FOR_PARTIAL_UPDATE.indexOf(newChildClass) > -1) {
394 var oldChild = oldNode.children('.' + newChildClass);
394 var oldChild = oldNode.children('.' + newChildClass);
395
395
396 if (oldChild.length == 0) {
396 if (oldChild.length == 0) {
397 oldNode.append(newChild);
397 oldNode.append(newChild);
398 } else {
398 } else {
399 if (!equalNodes(oldChild, newChild)) {
399 if (!equalNodes(oldChild, newChild)) {
400 if (recursive) {
400 if (recursive) {
401 replacePartial(oldChild, newChild, false);
401 replacePartial(oldChild, newChild, false);
402 } else {
402 } else {
403 oldChild.replaceWith(newChild);
403 oldChild.replaceWith(newChild);
404 }
404 }
405 }
405 }
406 }
406 }
407 }
407 }
408 });
408 });
409 }
409 }
410 }
410 }
411 }
411 }
412
412
413 /**
413 /**
414 * Compare nodes by content
414 * Compare nodes by content
415 */
415 */
416 function equalNodes(node1, node2) {
416 function equalNodes(node1, node2) {
417 return node1[0].outerHTML == node2[0].outerHTML;
417 return node1[0].outerHTML == node2[0].outerHTML;
418 }
418 }
419
419
420 /**
420 /**
421 * Update attribute of a node if it has changed
421 * Update attribute of a node if it has changed
422 */
422 */
423 function updateNodeAttr(oldNode, newNode, attrName) {
423 function updateNodeAttr(oldNode, newNode, attrName) {
424 var oldAttr = oldNode.attr(attrName);
424 var oldAttr = oldNode.attr(attrName);
425 var newAttr = newNode.attr(attrName);
425 var newAttr = newNode.attr(attrName);
426 if (oldAttr != newAttr) {
426 if (oldAttr != newAttr) {
427 oldNode.attr(attrName, newAttr);
427 oldNode.attr(attrName, newAttr);
428 }
428 }
429 }
429 }
430
430
431 $(document).ready(function() {
431 $(document).ready(function() {
432 if (initAutoupdate()) {
432 if (initAutoupdate()) {
433 // Post form data over AJAX
433 // Post form data over AJAX
434 var threadId = $('div.thread').children('.post').first().attr('id');
434 var threadId = $('div.thread').children('.post').first().attr('id');
435
435
436 var form = $('#form');
436 var form = $('#form');
437
437
438 if (form.length > 0) {
438 if (form.length > 0) {
439 var options = {
439 var options = {
440 beforeSubmit: function(arr, form, options) {
440 beforeSubmit: function(arr, form, options) {
441 showAsErrors(form, gettext('Sending message...'));
441 showAsErrors(form, gettext('Sending message...'));
442 },
442 },
443 success: updateOnPost,
443 success: updateOnPost,
444 error: function() {
444 error: function(xhr, textStatus, errorString) {
445 showAsErrors(form, gettext('Server error!'));
445 var errorText = gettext('Server error: ') + textStatus;
446 if (errorString) {
447 errorText += ' / ' + errorString;
448 }
449 showAsErrors(form, errorText);
446 },
450 },
447 url: '/api/add_post/' + threadId + '/',
451 url: '/api/add_post/' + threadId + '/',
448 timeout: POST_AJAX_TIMEOUT
452 timeout: POST_AJAX_TIMEOUT
449 };
453 };
450
454
451 form.ajaxForm(options);
455 form.ajaxForm(options);
452
456
453 resetForm(form);
457 resetForm(form);
454 }
458 }
455 }
459 }
456 });
460 });
General Comments 0
You need to be logged in to leave comments. Login now