##// END OF EJS Templates
Scroll to bottom after posting
neko259 -
r857:7e00dc33 default
parent child Browse files
Show More
@@ -1,280 +1,282 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 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 wsUrl = 'ws://localhost:9090/connection/websocket';
27 27 var wsUser = '';
28 28
29 29 var loading = false;
30 30 var lastUpdateTime = null;
31 31 var unreadPosts = 0;
32 32
33 33 // Thread ID does not change, can be stored one time
34 34 var threadId = $('div.thread').children('.post').first().attr('id');
35 35
36 36 function connectWebsocket() {
37 37 var metapanel = $('.metapanel')[0];
38 38
39 39 var wsHost = metapanel.getAttribute('data-ws-host');
40 40 var wsPort = metapanel.getAttribute('data-ws-port');
41 41
42 42 if (wsHost.length > 0 && wsPort.length > 0)
43 43 var centrifuge = new Centrifuge({
44 44 "url": 'ws://' + wsHost + ':' + wsPort + "/connection/websocket",
45 45 "project": metapanel.getAttribute('data-ws-project'),
46 46 "user": wsUser,
47 47 "timestamp": metapanel.getAttribute('data-last-update'),
48 48 "token": metapanel.getAttribute('data-ws-token'),
49 49 "debug": false
50 50 });
51 51
52 52 centrifuge.on('error', function(error_message) {
53 53 alert("Error connecting to websocket server.");
54 54 });
55 55
56 56 centrifuge.on('connect', function() {
57 57 var channelName = 'thread:' + threadId;
58 58 centrifuge.subscribe(channelName, function(message) {
59 59 var postHtml = message.data['html'];
60 60 var isAdded = (message.data['diff_type'] === 'added');
61 61
62 62 if (postHtml) {
63 63 updatePost(postHtml, isAdded);
64 64 }
65 65 });
66 66
67 67 $('#autoupdate').text('[+]');
68 68 });
69 69
70 70 centrifuge.connect();
71 71 }
72 72
73 73 function updatePost(postHtml, isAdded) {
74 74 // This needs to be set on start because the page is scrolled after posts
75 75 // are added or updated
76 76 var bottom = isPageBottom();
77 77
78 78 var post = $(postHtml);
79 79
80 80 var threadPosts = $('div.thread').children('.post');
81 81
82 82 var lastUpdate = '';
83 83
84 84 if (isAdded) {
85 85 var lastPost = threadPosts.last();
86 86
87 87 post.appendTo(lastPost.parent());
88 88
89 89 updateBumplimitProgress(1);
90 90 showNewPostsTitle(1);
91 91
92 92 lastUpdate = post.children('.post-info').first()
93 93 .children('.pub_time').first().text();
94 94
95 95 if (bottom) {
96 96 scrollToBottom();
97 97 }
98 98 } else {
99 99 var postId = post.attr('id');
100 100
101 101 var oldPost = $('div.thread').children('.post[id=' + postId + ']');
102 102
103 103 oldPost.replaceWith(post);
104 104 }
105 105
106 106 processNewPost(post);
107 107 updateMetadataPanel(lastUpdate)
108 108 }
109 109
110 110 function blink(node) {
111 111 var blinkCount = 2;
112 112
113 113 var nodeToAnimate = node;
114 114 for (var i = 0; i < blinkCount; i++) {
115 115 nodeToAnimate = nodeToAnimate.fadeTo('fast', 0.5).fadeTo('fast', 1.0);
116 116 }
117 117 }
118 118
119 119 function isPageBottom() {
120 120 var scroll = $(window).scrollTop() / ($(document).height()
121 121 - $(window).height());
122 122
123 123 return scroll == 1
124 124 }
125 125
126 126 function initAutoupdate() {
127 127 connectWebsocket();
128 128 }
129 129
130 130 function getReplyCount() {
131 131 return $('.thread').children('.post').length
132 132 }
133 133
134 134 function getImageCount() {
135 135 return $('.thread').find('img').length
136 136 }
137 137
138 138 function updateMetadataPanel(lastUpdate) {
139 139 var replyCountField = $('#reply-count');
140 140 var imageCountField = $('#image-count');
141 141
142 142 replyCountField.text(getReplyCount());
143 143 imageCountField.text(getImageCount());
144 144
145 145 if (lastUpdate !== '') {
146 146 var lastUpdateField = $('#last-update');
147 147 lastUpdateField.text(lastUpdate);
148 148 blink(lastUpdateField);
149 149 }
150 150
151 151 blink(replyCountField);
152 152 blink(imageCountField);
153 153 }
154 154
155 155 /**
156 156 * Update bumplimit progress bar
157 157 */
158 158 function updateBumplimitProgress(postDelta) {
159 159 var progressBar = $('#bumplimit_progress');
160 160 if (progressBar) {
161 161 var postsToLimitElement = $('#left_to_limit');
162 162
163 163 var oldPostsToLimit = parseInt(postsToLimitElement.text());
164 164 var postCount = getReplyCount();
165 165 var bumplimit = postCount - postDelta + oldPostsToLimit;
166 166
167 167 var newPostsToLimit = bumplimit - postCount;
168 168 if (newPostsToLimit <= 0) {
169 169 $('.bar-bg').remove();
170 170 $('.thread').children('.post').addClass('dead_post');
171 171 } else {
172 172 postsToLimitElement.text(newPostsToLimit);
173 173 progressBar.width((100 - postCount / bumplimit * 100.0) + '%');
174 174 }
175 175 }
176 176 }
177 177
178 178 var documentOriginalTitle = '';
179 179 /**
180 180 * Show 'new posts' text in the title if the document is not visible to a user
181 181 */
182 182 function showNewPostsTitle(newPostCount) {
183 183 if (document.hidden) {
184 184 if (documentOriginalTitle === '') {
185 185 documentOriginalTitle = document.title;
186 186 }
187 187 unreadPosts = unreadPosts + newPostCount;
188 188 document.title = '[' + unreadPosts + '] ' + documentOriginalTitle;
189 189
190 190 document.addEventListener('visibilitychange', function() {
191 191 if (documentOriginalTitle !== '') {
192 192 document.title = documentOriginalTitle;
193 193 documentOriginalTitle = '';
194 194 unreadPosts = 0;
195 195 }
196 196
197 197 document.removeEventListener('visibilitychange', null);
198 198 });
199 199 }
200 200 }
201 201
202 202 /**
203 203 * Clear all entered values in the form fields
204 204 */
205 205 function resetForm(form) {
206 206 form.find('input:text, input:password, input:file, select, textarea').val('');
207 207 form.find('input:radio, input:checkbox')
208 208 .removeAttr('checked').removeAttr('selected');
209 209 $('.file_wrap').find('.file-thumb').remove();
210 210 }
211 211
212 212 /**
213 213 * When the form is posted, this method will be run as a callback
214 214 */
215 215 function updateOnPost(response, statusText, xhr, form) {
216 216 var json = $.parseJSON(response);
217 217 var status = json.status;
218 218
219 219 showAsErrors(form, '');
220 220
221 221 if (status === 'ok') {
222 222 resetForm(form);
223 223 } else {
224 224 var errors = json.errors;
225 225 for (var i = 0; i < errors.length; i++) {
226 226 var fieldErrors = errors[i];
227 227
228 228 var error = fieldErrors.errors;
229 229
230 230 showAsErrors(form, error);
231 231 }
232 232 }
233
234 scrollToBottom();
233 235 }
234 236
235 237 /**
236 238 * Show text in the errors row of the form.
237 239 * @param form
238 240 * @param text
239 241 */
240 242 function showAsErrors(form, text) {
241 243 form.children('.form-errors').remove();
242 244
243 245 if (text.length > 0) {
244 246 var errorList = $('<div class="form-errors">' + text
245 247 + '<div>');
246 248 errorList.appendTo(form);
247 249 }
248 250 }
249 251
250 252 /**
251 253 * Run js methods that are usually run on the document, on the new post
252 254 */
253 255 function processNewPost(post) {
254 256 addRefLinkPreview(post[0]);
255 257 highlightCode(post);
256 258 blink(post);
257 259 }
258 260
259 261 $(document).ready(function(){
260 262 if ('WebSocket' in window) {
261 263 initAutoupdate();
262 264
263 265 // Post form data over AJAX
264 266 var threadId = $('div.thread').children('.post').first().attr('id');
265 267
266 268 var form = $('#form');
267 269
268 270 var options = {
269 271 beforeSubmit: function(arr, $form, options) {
270 272 showAsErrors($('form'), gettext('Sending message...'));
271 273 },
272 274 success: updateOnPost,
273 275 url: '/api/add_post/' + threadId + '/'
274 276 };
275 277
276 278 form.ajaxForm(options);
277 279
278 280 resetForm(form);
279 281 }
280 282 });
General Comments 0
You need to be logged in to leave comments. Login now