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