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