##// END OF EJS Templates
Speed up post hiding, do not load the hidden posts list for each post being processed
neko259 -
r2082:47f758c2 default
parent child Browse files
Show More
@@ -1,360 +1,362
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 neko259
6 Copyright (C) 2013 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 ITEM_VOLUME_LEVEL = 'volumeLevel';
26 var ITEM_VOLUME_LEVEL = 'volumeLevel';
27 var ITEM_HIDDEN_POSTS = 'hiddenPosts';
27 var ITEM_HIDDEN_POSTS = 'hiddenPosts';
28
28
29 var IMAGE_TYPES = ['image/png', 'image/jpg', 'image/jpeg', 'image/bmp', 'image/gif'];
29 var IMAGE_TYPES = ['image/png', 'image/jpg', 'image/jpeg', 'image/bmp', 'image/gif'];
30
30
31 /**
31 /**
32 * An email is a hidden file to prevent spam bots from posting. It has to be
32 * An email is a hidden file to prevent spam bots from posting. It has to be
33 * hidden.
33 * hidden.
34 */
34 */
35 function hideEmailFromForm() {
35 function hideEmailFromForm() {
36 $('.form-email').parent().parent().hide();
36 $('.form-email').parent().parent().hide();
37 }
37 }
38
38
39 /**
39 /**
40 * Highlight code blocks with code highlighter
40 * Highlight code blocks with code highlighter
41 */
41 */
42 function highlightCode(node) {
42 function highlightCode(node) {
43 node.find('pre code').each(function(i, e) {
43 node.find('pre code').each(function(i, e) {
44 hljs.highlightBlock(e);
44 hljs.highlightBlock(e);
45 });
45 });
46 }
46 }
47
47
48 function updateFavPosts(data) {
48 function updateFavPosts(data) {
49 var includePostBody = $('#fav-panel').is(":visible");
49 var includePostBody = $('#fav-panel').is(":visible");
50
50
51 var allNewPostCount = 0;
51 var allNewPostCount = 0;
52
52
53 if (includePostBody) {
53 if (includePostBody) {
54 var favoriteThreadPanel = $('#fav-panel');
54 var favoriteThreadPanel = $('#fav-panel');
55 favoriteThreadPanel.empty();
55 favoriteThreadPanel.empty();
56 }
56 }
57
57
58 $.each($.parseJSON(data), function (_, dict) {
58 $.each($.parseJSON(data), function (_, dict) {
59 var newPostCount = dict.new_post_count;
59 var newPostCount = dict.new_post_count;
60 allNewPostCount += newPostCount;
60 allNewPostCount += newPostCount;
61
61
62 if (includePostBody) {
62 if (includePostBody) {
63 var favThreadNode = $('<div class="post"></div>');
63 var favThreadNode = $('<div class="post"></div>');
64 favThreadNode.append($(dict.post_url));
64 favThreadNode.append($(dict.post_url));
65 favThreadNode.append(' ');
65 favThreadNode.append(' ');
66 favThreadNode.append($('<span class="title">' + dict.title + '</span>'));
66 favThreadNode.append($('<span class="title">' + dict.title + '</span>'));
67
67
68 if (newPostCount > 0) {
68 if (newPostCount > 0) {
69 favThreadNode.append(' (<a href="' + dict.newest_post_link + '">+' + newPostCount + "</a>)");
69 favThreadNode.append(' (<a href="' + dict.newest_post_link + '">+' + newPostCount + "</a>)");
70 }
70 }
71
71
72 favoriteThreadPanel.append(favThreadNode);
72 favoriteThreadPanel.append(favThreadNode);
73
73
74 addRefLinkPreview(favThreadNode[0]);
74 addRefLinkPreview(favThreadNode[0]);
75 }
75 }
76 });
76 });
77
77
78 var newPostCountNode = $('#new-fav-post-count');
78 var newPostCountNode = $('#new-fav-post-count');
79 if (allNewPostCount > 0) {
79 if (allNewPostCount > 0) {
80 newPostCountNode.text('(+' + allNewPostCount + ')');
80 newPostCountNode.text('(+' + allNewPostCount + ')');
81 newPostCountNode.show();
81 newPostCountNode.show();
82 } else {
82 } else {
83 newPostCountNode.hide();
83 newPostCountNode.hide();
84 }
84 }
85 }
85 }
86
86
87 function initFavPanel() {
87 function initFavPanel() {
88 var favPanelButton = $('#fav-panel-btn');
88 var favPanelButton = $('#fav-panel-btn');
89 if (favPanelButton.length > 0 && typeof SharedWorker != 'undefined') {
89 if (favPanelButton.length > 0 && typeof SharedWorker != 'undefined') {
90 var worker = new SharedWorker($('body').attr('data-update-script'));
90 var worker = new SharedWorker($('body').attr('data-update-script'));
91 worker.port.onmessage = function(e) {
91 worker.port.onmessage = function(e) {
92 updateFavPosts(e.data);
92 updateFavPosts(e.data);
93 };
93 };
94 worker.onerror = function(event){
94 worker.onerror = function(event){
95 throw new Error(event.message + " (" + event.filename + ":" + event.lineno + ")");
95 throw new Error(event.message + " (" + event.filename + ":" + event.lineno + ")");
96 };
96 };
97 worker.port.start();
97 worker.port.start();
98
98
99 $(favPanelButton).click(function() {
99 $(favPanelButton).click(function() {
100 var favPanel = $('#fav-panel');
100 var favPanel = $('#fav-panel');
101 favPanel.toggle();
101 favPanel.toggle();
102
102
103 worker.port.postMessage({ includePostBody: favPanel.is(':visible')});
103 worker.port.postMessage({ includePostBody: favPanel.is(':visible')});
104
104
105 return false;
105 return false;
106 });
106 });
107
107
108 $(document).on('keyup.removepic', function(e) {
108 $(document).on('keyup.removepic', function(e) {
109 if(e.which === 27) {
109 if(e.which === 27) {
110 $('#fav-panel').hide();
110 $('#fav-panel').hide();
111 }
111 }
112 });
112 });
113 }
113 }
114 }
114 }
115
115
116 function setVolumeLevel(level) {
116 function setVolumeLevel(level) {
117 localStorage.setItem(ITEM_VOLUME_LEVEL, level);
117 localStorage.setItem(ITEM_VOLUME_LEVEL, level);
118 }
118 }
119
119
120 function getVolumeLevel() {
120 function getVolumeLevel() {
121 var level = localStorage.getItem(ITEM_VOLUME_LEVEL);
121 var level = localStorage.getItem(ITEM_VOLUME_LEVEL);
122 if (level == null) {
122 if (level == null) {
123 level = 1.0;
123 level = 1.0;
124 }
124 }
125 return level
125 return level
126 }
126 }
127
127
128 function processVolumeUser(node) {
128 function processVolumeUser(node) {
129 if (!window.localStorage) return;
129 if (!window.localStorage) return;
130 node.prop("volume", getVolumeLevel());
130 node.prop("volume", getVolumeLevel());
131 node.on('volumechange', function(event) {
131 node.on('volumechange', function(event) {
132 setVolumeLevel(event.target.volume);
132 setVolumeLevel(event.target.volume);
133 $("video,audio").prop("volume", getVolumeLevel());
133 $("video,audio").prop("volume", getVolumeLevel());
134 });
134 });
135 }
135 }
136
136
137 function getHiddenPosts() {
137 function getHiddenPosts() {
138 var arr = Array();
138 var arr = Array();
139 var hiddenPosts = localStorage.getItem(ITEM_HIDDEN_POSTS);
139 var hiddenPosts = localStorage.getItem(ITEM_HIDDEN_POSTS);
140 if (hiddenPosts) {
140 if (hiddenPosts) {
141 arr = JSON.parse(hiddenPosts);
141 arr = JSON.parse(hiddenPosts);
142 }
142 }
143 return arr;
143 return arr;
144 }
144 }
145
145
146 function processPostHiding(post) {
146 function processPostHiding(posts) {
147 var hiddenPosts = getHiddenPosts();
147 var hiddenPosts = getHiddenPosts();
148 if (hiddenPosts.indexOf(post.attr("id")) > -1) {
148
149 post.toggleClass("hidden_post");
149 $.each(posts, function(index) {
150 }
150 var post = $(this);
151 if (hiddenPosts.indexOf(post.attr("id")) > -1) {
152 post.toggleClass("hidden_post");
153 }
154 });
151 }
155 }
152
156
153 /**
157 /**
154 * Add all scripts than need to work on post, when the post is added to the
158 * Add all scripts than need to work on post, when the post is added to the
155 * document.
159 * document.
156 */
160 */
157 function addScriptsToPost(post) {
161 function addScriptsToPost(post) {
158 addRefLinkPreview(post[0]);
162 addRefLinkPreview(post[0]);
159 highlightCode(post);
163 highlightCode(post);
160 processVolumeUser(post.find("video,audio"));
164 processVolumeUser(post.find("video,audio"));
161 processPostHiding(post);
165 processPostHiding([post]);
162 }
166 }
163
167
164 /**
168 /**
165 * Fix compatibility issues with some rare browsers
169 * Fix compatibility issues with some rare browsers
166 */
170 */
167 function compatibilityCrutches() {
171 function compatibilityCrutches() {
168 if (window.operamini) {
172 if (window.operamini) {
169 $('#form textarea').each(function() { this.placeholder = ''; });
173 $('#form textarea').each(function() { this.placeholder = ''; });
170 }
174 }
171 }
175 }
172
176
173 function togglePostHidden(postId) {
177 function togglePostHidden(postId) {
174 var hiddenPosts = getHiddenPosts();
178 var hiddenPosts = getHiddenPosts();
175
179
176 var elIndex = hiddenPosts.indexOf(postId);
180 var elIndex = hiddenPosts.indexOf(postId);
177 if (elIndex > -1) {
181 if (elIndex > -1) {
178 hiddenPosts.splice(elIndex, 1);
182 hiddenPosts.splice(elIndex, 1);
179 } else {
183 } else {
180 hiddenPosts.push(postId);
184 hiddenPosts.push(postId);
181 }
185 }
182 localStorage.setItem(ITEM_HIDDEN_POSTS, JSON.stringify(hiddenPosts));
186 localStorage.setItem(ITEM_HIDDEN_POSTS, JSON.stringify(hiddenPosts));
183
187
184 $('#' + postId).toggleClass("hidden_post");
188 $('#' + postId).toggleClass("hidden_post");
185 }
189 }
186
190
187 function addContextMenu() {
191 function addContextMenu() {
188 $.contextMenu({
192 $.contextMenu({
189 selector: '.file-menu',
193 selector: '.file-menu',
190 trigger: 'left',
194 trigger: 'left',
191
195
192 build: function($trigger, e) {
196 build: function($trigger, e) {
193 var fileSearchUrl = $trigger.data('search-url');
197 var fileSearchUrl = $trigger.data('search-url');
194 var isImage = IMAGE_TYPES.indexOf($trigger.data('type')) > -1;
198 var isImage = IMAGE_TYPES.indexOf($trigger.data('type')) > -1;
195 var hasUrl = fileSearchUrl.length > 0;
199 var hasUrl = fileSearchUrl.length > 0;
196 var id = $trigger.data('id');
200 var id = $trigger.data('id');
197 return {
201 return {
198 items: {
202 items: {
199 duplicates: {
203 duplicates: {
200 name: gettext('Duplicates search'),
204 name: gettext('Duplicates search'),
201 callback: function(key, opts) {
205 callback: function(key, opts) {
202 window.location = '/feed/?image=' + $trigger.data('filename');
206 window.location = '/feed/?image=' + $trigger.data('filename');
203 }
207 }
204 },
208 },
205 google: {
209 google: {
206 name: 'Google',
210 name: 'Google',
207 visible: isImage && hasUrl,
211 visible: isImage && hasUrl,
208 callback: function(key, opts) {
212 callback: function(key, opts) {
209 window.location = 'https://www.google.com/searchbyimage?image_url=' + fileSearchUrl;
213 window.location = 'https://www.google.com/searchbyimage?image_url=' + fileSearchUrl;
210 }
214 }
211 },
215 },
212 iqdb: {
216 iqdb: {
213 name: 'IQDB',
217 name: 'IQDB',
214 visible: isImage && hasUrl,
218 visible: isImage && hasUrl,
215 callback: function(key, opts) {
219 callback: function(key, opts) {
216 window.location = 'http://iqdb.org/?url=' + fileSearchUrl;
220 window.location = 'http://iqdb.org/?url=' + fileSearchUrl;
217 }
221 }
218 },
222 },
219 tineye: {
223 tineye: {
220 name: 'TinEye',
224 name: 'TinEye',
221 visible: isImage && hasUrl,
225 visible: isImage && hasUrl,
222 callback: function(key, opts) {
226 callback: function(key, opts) {
223 window.location = 'http://tineye.com/search?url=' + fileSearchUrl;
227 window.location = 'http://tineye.com/search?url=' + fileSearchUrl;
224 }
228 }
225 },
229 },
226 addAlias: {
230 addAlias: {
227 name: gettext('Add local sticker'),
231 name: gettext('Add local sticker'),
228 callback: function(key, opts) {
232 callback: function(key, opts) {
229 var alias = prompt(gettext('Input sticker name'));
233 var alias = prompt(gettext('Input sticker name'));
230 if (alias) {
234 if (alias) {
231 window.location = '/stickers/?action=add&name=' + alias + '&id=' + id;
235 window.location = '/stickers/?action=add&name=' + alias + '&id=' + id;
232 }
236 }
233 }
237 }
234 }
238 }
235 }
239 }
236 };
240 };
237 }
241 }
238 });
242 });
239
243
240 $.contextMenu({
244 $.contextMenu({
241 selector: '.post .post-menu',
245 selector: '.post .post-menu',
242 trigger: 'left',
246 trigger: 'left',
243 build: function($trigger, e) {
247 build: function($trigger, e) {
244 var canEditPost = PERMS['change_post'];
248 var canEditPost = PERMS['change_post'];
245 var canDeletePost = PERMS['delete_post'];
249 var canDeletePost = PERMS['delete_post'];
246 var canEditThread = PERMS['change_thread'];
250 var canEditThread = PERMS['change_thread'];
247 var canDeleteThread = PERMS['delete_thread'];
251 var canDeleteThread = PERMS['delete_thread'];
248
252
249 var post = $trigger.parents('.post');
253 var post = $trigger.parents('.post');
250
254
251 var isOpening = post.data('opening') === 'True';
255 var isOpening = post.data('opening') === 'True';
252 var threadId = post.data('thread-id');
256 var threadId = post.data('thread-id');
253 var hasGlobalId = post.data('has-global-id') === 'True';
257 var hasGlobalId = post.data('has-global-id') === 'True';
254
258
255 var posterIp = $trigger.siblings('.pub_time').attr('title');
259 var posterIp = $trigger.siblings('.pub_time').attr('title');
256 var hasIp = posterIp != null;
260 var hasIp = posterIp != null;
257
261
258 var postId = post.attr('id');
262 var postId = post.attr('id');
259
263
260 return {
264 return {
261 items: {
265 items: {
262 hide: {
266 hide: {
263 name: gettext('Hide/show'),
267 name: gettext('Hide/show'),
264 callback: function(key, opt) {
268 callback: function(key, opt) {
265 togglePostHidden(postId);
269 togglePostHidden(postId);
266 }
270 }
267 },
271 },
268 edit: {
272 edit: {
269 name: gettext('Edit'),
273 name: gettext('Edit'),
270 callback: function(key, opt) {
274 callback: function(key, opt) {
271 window.location = '/admin/boards/post/' + postId + '/change/';
275 window.location = '/admin/boards/post/' + postId + '/change/';
272 },
276 },
273 visible: canEditPost
277 visible: canEditPost
274 },
278 },
275 deletePost: {
279 deletePost: {
276 name: gettext('Delete post'),
280 name: gettext('Delete post'),
277 callback: function(key, opt) {
281 callback: function(key, opt) {
278 window.location = '/admin/boards/post/' + postId + '/delete/';
282 window.location = '/admin/boards/post/' + postId + '/delete/';
279 },
283 },
280 visible: !isOpening && canDeletePost
284 visible: !isOpening && canDeletePost
281 },
285 },
282 editThread: {
286 editThread: {
283 name: gettext('Edit thread'),
287 name: gettext('Edit thread'),
284 callback: function(key, opt) {
288 callback: function(key, opt) {
285 window.location = '/admin/boards/thread/' + threadId + '/change/';
289 window.location = '/admin/boards/thread/' + threadId + '/change/';
286 },
290 },
287 visible: isOpening && canEditThread
291 visible: isOpening && canEditThread
288 },
292 },
289 deleteThread: {
293 deleteThread: {
290 name: gettext('Delete thread'),
294 name: gettext('Delete thread'),
291 callback: function(key, opt) {
295 callback: function(key, opt) {
292 window.location = '/admin/boards/thread/' + threadId + '/delete/';
296 window.location = '/admin/boards/thread/' + threadId + '/delete/';
293 },
297 },
294 visible: isOpening && canDeleteThread
298 visible: isOpening && canDeleteThread
295 },
299 },
296 findByIp: {
300 findByIp: {
297 name: 'IP = ' + posterIp,
301 name: 'IP = ' + posterIp,
298 callback: function(key, opt) {
302 callback: function(key, opt) {
299 window.location = '/feed/?ip=' + posterIp;
303 window.location = '/feed/?ip=' + posterIp;
300 },
304 },
301 visible: canEditPost && hasIp
305 visible: canEditPost && hasIp
302 },
306 },
303 raw: {
307 raw: {
304 name: 'RAW',
308 name: 'RAW',
305 callback: function(key, opt) {
309 callback: function(key, opt) {
306 window.location = '/post_xml/' + postId;
310 window.location = '/post_xml/' + postId;
307 },
311 },
308 visible: canEditPost && hasGlobalId
312 visible: canEditPost && hasGlobalId
309 },
313 },
310 ban: {
314 ban: {
311 name: gettext('Ban'),
315 name: gettext('Ban'),
312 callback: function(key, opt) {
316 callback: function(key, opt) {
313 if (confirm(gettext('Are you sure?'))) {
317 if (confirm(gettext('Are you sure?'))) {
314 window.location = '/utils?method=ban&post_id=' + postId;
318 window.location = '/utils?method=ban&post_id=' + postId;
315 }
319 }
316 },
320 },
317 visible: canEditPost && hasIp
321 visible: canEditPost && hasIp
318 },
322 },
319 banAndDelete: {
323 banAndDelete: {
320 name: gettext('Ban and delete'),
324 name: gettext('Ban and delete'),
321 callback: function(key, opt) {
325 callback: function(key, opt) {
322 if (confirm(gettext('Are you sure?'))) {
326 if (confirm(gettext('Are you sure?'))) {
323 window.location = '/utils?method=ban_and_delete&post_id=' + postId;
327 window.location = '/utils?method=ban_and_delete&post_id=' + postId;
324 }
328 }
325 },
329 },
326 visible: hasIp && canDeletePost
330 visible: hasIp && canDeletePost
327 }
331 }
328 }
332 }
329 };
333 };
330 }
334 }
331 });
335 });
332 }
336 }
333
337
334 $( document ).ready(function() {
338 $( document ).ready(function() {
335 hideEmailFromForm();
339 hideEmailFromForm();
336
340
337 $("a[href='#top']").click(function() {
341 $("a[href='#top']").click(function() {
338 $("html, body").animate({ scrollTop: 0 }, "slow");
342 $("html, body").animate({ scrollTop: 0 }, "slow");
339 return false;
343 return false;
340 });
344 });
341
345
342 addImgPreview();
346 addImgPreview();
343
347
344 addRefLinkPreview();
348 addRefLinkPreview();
345
349
346 highlightCode($(document));
350 highlightCode($(document));
347
351
348 initFavPanel();
352 initFavPanel();
349
353
350 var volumeUsers = $("video,audio");
354 var volumeUsers = $("video,audio");
351 processVolumeUser(volumeUsers);
355 processVolumeUser(volumeUsers);
352
356
353 addContextMenu();
357 addContextMenu();
354
358
355 compatibilityCrutches();
359 compatibilityCrutches();
356
360
357 $('.post').each(function(index) {
361 processPostHiding($('.post'));
358 processPostHiding($(this));
359 });
360 });
362 });
General Comments 0
You need to be logged in to leave comments. Login now