##// END OF EJS Templates
Update metadata panel only once when a multiple of posts in updated during...
neko259 -
r1073:5583a4cb default
parent child Browse files
Show More
@@ -1,333 +1,331 b''
1 1 /*
2 2 @licstart The following is the entire license notice for the
3 3 JavaScript code in this page.
4 4
5 5
6 6 Copyright (C) 2013-2014 neko259
7 7
8 8 The JavaScript code in this page is free software: you can
9 9 redistribute it and/or modify it under the terms of the GNU
10 10 General Public License (GNU GPL) as published by the Free Software
11 11 Foundation, either version 3 of the License, or (at your option)
12 12 any later version. The code is distributed WITHOUT ANY WARRANTY;
13 13 without even the implied warranty of MERCHANTABILITY or FITNESS
14 14 FOR A PARTICULAR PURPOSE. See the GNU GPL for more details.
15 15
16 16 As additional permission under GNU GPL version 3 section 7, you
17 17 may distribute non-source (e.g., minimized or compacted) forms of
18 18 that code without the copy of the GNU GPL normally required by
19 19 section 4, provided you include this license notice and a URL
20 20 through which recipients can access the Corresponding Source.
21 21
22 22 @licend The above is the entire license notice
23 23 for the JavaScript code in this page.
24 24 */
25 25
26 26 var wsUser = '';
27 27
28 28 var unreadPosts = 0;
29 29 var documentOriginalTitle = '';
30 30
31 31 // Thread ID does not change, can be stored one time
32 32 var threadId = $('div.thread').children('.post').first().attr('id');
33 33
34 34 /**
35 35 * Connect to websocket server and subscribe to thread updates. On any update we
36 36 * request a thread diff.
37 37 *
38 38 * @returns {boolean} true if connected, false otherwise
39 39 */
40 40 function connectWebsocket() {
41 41 var metapanel = $('.metapanel')[0];
42 42
43 43 var wsHost = metapanel.getAttribute('data-ws-host');
44 44 var wsPort = metapanel.getAttribute('data-ws-port');
45 45
46 46 if (wsHost.length > 0 && wsPort.length > 0)
47 47 var centrifuge = new Centrifuge({
48 48 "url": 'ws://' + wsHost + ':' + wsPort + "/connection/websocket",
49 49 "project": metapanel.getAttribute('data-ws-project'),
50 50 "user": wsUser,
51 51 "timestamp": metapanel.getAttribute('data-last-update'),
52 52 "token": metapanel.getAttribute('data-ws-token'),
53 53 "debug": false
54 54 });
55 55
56 56 centrifuge.on('error', function(error_message) {
57 57 console.log("Error connecting to websocket server.");
58 58 return false;
59 59 });
60 60
61 61 centrifuge.on('connect', function() {
62 62 var channelName = 'thread:' + threadId;
63 63 centrifuge.subscribe(channelName, function(message) {
64 64 getThreadDiff();
65 65 });
66 66
67 67 // For the case we closed the browser and missed some updates
68 68 getThreadDiff();
69 69 $('#autoupdate').hide();
70 70 });
71 71
72 72 centrifuge.connect();
73 73
74 74 return true;
75 75 }
76 76
77 77 /**
78 78 * Get diff of the posts from the current thread timestamp.
79 79 * This is required if the browser was closed and some post updates were
80 80 * missed.
81 81 */
82 82 function getThreadDiff() {
83 83 var lastUpdateTime = $('.metapanel').attr('data-last-update');
84 84
85 85 var diffUrl = '/api/diff_thread/' + threadId + '/' + lastUpdateTime + '/';
86 86
87 87 $.getJSON(diffUrl)
88 88 .success(function(data) {
89 89 var addedPosts = data.added;
90 90
91 91 for (var i = 0; i < addedPosts.length; i++) {
92 92 var postText = addedPosts[i];
93 93 var post = $(postText);
94 94
95 95 updatePost(post)
96 96 }
97 97
98 98 var updatedPosts = data.updated;
99 99
100 100 for (var i = 0; i < updatedPosts.length; i++) {
101 101 var postText = updatedPosts[i];
102 102 var post = $(postText);
103 103
104 104 updatePost(post)
105 105 }
106 106
107 updateMetadataPanel();
108
107 109 // TODO Process removed posts if any
108 110 $('.metapanel').attr('data-last-update', data.last_update);
109 111 })
110 112 }
111 113
112 114 /**
113 115 * Add or update the post on html page.
114 116 */
115 117 function updatePost(postHtml) {
116 118 // This needs to be set on start because the page is scrolled after posts
117 119 // are added or updated
118 120 var bottom = isPageBottom();
119 121
120 122 var post = $(postHtml);
121 123
122 124 var threadBlock = $('div.thread');
123 125
124 var lastUpdate = '';
125
126 126 var postId = post.attr('id');
127 127
128 128 // If the post already exists, replace it. Otherwise add as a new one.
129 129 var existingPosts = threadBlock.children('.post[id=' + postId + ']');
130 130
131 131 if (existingPosts.size() > 0) {
132 132 existingPosts.replaceWith(post);
133 133 } else {
134 134 var threadPosts = threadBlock.children('.post');
135 135 var lastPost = threadPosts.last();
136 136
137 137 post.appendTo(lastPost.parent());
138 138
139 139 updateBumplimitProgress(1);
140 140 showNewPostsTitle(1);
141 141
142 lastUpdate = post.children('.post-info').first()
143 .children('.pub_time').first().html();
144
145 142 if (bottom) {
146 143 scrollToBottom();
147 144 }
148 145 }
149 146
150 147 processNewPost(post);
151 updateMetadataPanel(lastUpdate)
152 148 }
153 149
154 150 /**
155 151 * Initiate a blinking animation on a node to show it was updated.
156 152 */
157 153 function blink(node) {
158 154 var blinkCount = 2;
159 155
160 156 var nodeToAnimate = node;
161 157 for (var i = 0; i < blinkCount; i++) {
162 158 nodeToAnimate = nodeToAnimate.fadeTo('fast', 0.5).fadeTo('fast', 1.0);
163 159 }
164 160 }
165 161
166 162 function isPageBottom() {
167 163 var scroll = $(window).scrollTop() / ($(document).height()
168 164 - $(window).height());
169 165
170 166 return scroll == 1
171 167 }
172 168
173 169 function initAutoupdate() {
174 170 return connectWebsocket();
175 171 }
176 172
177 173 function getReplyCount() {
178 174 return $('.thread').children('.post').length
179 175 }
180 176
181 177 function getImageCount() {
182 178 return $('.thread').find('img').length
183 179 }
184 180
185 181 /**
186 182 * Update post count, images count and last update time in the metadata
187 183 * panel.
188 184 */
189 function updateMetadataPanel(lastUpdate) {
185 function updateMetadataPanel() {
190 186 var replyCountField = $('#reply-count');
191 187 var imageCountField = $('#image-count');
192 188
193 189 replyCountField.text(getReplyCount());
194 190 imageCountField.text(getImageCount());
195 191
192 var lastUpdate = $('.post:last').children('.post-info').first()
193 .children('.pub_time').first().html();
196 194 if (lastUpdate !== '') {
197 195 var lastUpdateField = $('#last-update');
198 196 lastUpdateField.html(lastUpdate);
199 197 blink(lastUpdateField);
200 198 }
201 199
202 200 blink(replyCountField);
203 201 blink(imageCountField);
204 202 }
205 203
206 204 /**
207 205 * Update bumplimit progress bar
208 206 */
209 207 function updateBumplimitProgress(postDelta) {
210 208 var progressBar = $('#bumplimit_progress');
211 209 if (progressBar) {
212 210 var postsToLimitElement = $('#left_to_limit');
213 211
214 212 var oldPostsToLimit = parseInt(postsToLimitElement.text());
215 213 var postCount = getReplyCount();
216 214 var bumplimit = postCount - postDelta + oldPostsToLimit;
217 215
218 216 var newPostsToLimit = bumplimit - postCount;
219 217 if (newPostsToLimit <= 0) {
220 218 $('.bar-bg').remove();
221 219 } else {
222 220 postsToLimitElement.text(newPostsToLimit);
223 221 progressBar.width((100 - postCount / bumplimit * 100.0) + '%');
224 222 }
225 223 }
226 224 }
227 225
228 226 /**
229 227 * Show 'new posts' text in the title if the document is not visible to a user
230 228 */
231 229 function showNewPostsTitle(newPostCount) {
232 230 if (document.hidden) {
233 231 if (documentOriginalTitle === '') {
234 232 documentOriginalTitle = document.title;
235 233 }
236 234 unreadPosts = unreadPosts + newPostCount;
237 235 document.title = '[' + unreadPosts + '] ' + documentOriginalTitle;
238 236
239 237 document.addEventListener('visibilitychange', function() {
240 238 if (documentOriginalTitle !== '') {
241 239 document.title = documentOriginalTitle;
242 240 documentOriginalTitle = '';
243 241 unreadPosts = 0;
244 242 }
245 243
246 244 document.removeEventListener('visibilitychange', null);
247 245 });
248 246 }
249 247 }
250 248
251 249 /**
252 250 * Clear all entered values in the form fields
253 251 */
254 252 function resetForm(form) {
255 253 form.find('input:text, input:password, input:file, select, textarea').val('');
256 254 form.find('input:radio, input:checkbox')
257 255 .removeAttr('checked').removeAttr('selected');
258 256 $('.file_wrap').find('.file-thumb').remove();
259 257 }
260 258
261 259 /**
262 260 * When the form is posted, this method will be run as a callback
263 261 */
264 262 function updateOnPost(response, statusText, xhr, form) {
265 263 var json = $.parseJSON(response);
266 264 var status = json.status;
267 265
268 266 showAsErrors(form, '');
269 267
270 268 if (status === 'ok') {
271 269 resetFormPosition();
272 270 resetForm(form);
273 271 getThreadDiff();
274 272 scrollToBottom();
275 273 } else {
276 274 var errors = json.errors;
277 275 for (var i = 0; i < errors.length; i++) {
278 276 var fieldErrors = errors[i];
279 277
280 278 var error = fieldErrors.errors;
281 279
282 280 showAsErrors(form, error);
283 281 }
284 282 }
285 283 }
286 284
287 285 /**
288 286 * Show text in the errors row of the form.
289 287 * @param form
290 288 * @param text
291 289 */
292 290 function showAsErrors(form, text) {
293 291 form.children('.form-errors').remove();
294 292
295 293 if (text.length > 0) {
296 294 var errorList = $('<div class="form-errors">' + text + '<div>');
297 295 errorList.appendTo(form);
298 296 }
299 297 }
300 298
301 299 /**
302 300 * Run js methods that are usually run on the document, on the new post
303 301 */
304 302 function processNewPost(post) {
305 303 addRefLinkPreview(post[0]);
306 304 highlightCode(post);
307 305 blink(post);
308 306 }
309 307
310 308 $(document).ready(function(){
311 309 if (initAutoupdate()) {
312 310 // Post form data over AJAX
313 311 var threadId = $('div.thread').children('.post').first().attr('id');
314 312
315 313 var form = $('#form');
316 314
317 315 if (form.length > 0) {
318 316 var options = {
319 317 beforeSubmit: function(arr, $form, options) {
320 318 showAsErrors($('form'), gettext('Sending message...'));
321 319 },
322 320 success: updateOnPost,
323 321 url: '/api/add_post/' + threadId + '/'
324 322 };
325 323
326 324 form.ajaxForm(options);
327 325
328 326 resetForm(form);
329 327 }
330 328 }
331 329
332 330 $('#autoupdate').click(getThreadDiff);
333 331 });
General Comments 0
You need to be logged in to leave comments. Login now