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