/* @licstart The following is the entire license notice for the JavaScript code in this page. Copyright (C) 2013 neko259 The JavaScript code in this page is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License (GNU GPL) as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. The code is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU GPL for more details. As additional permission under GNU GPL version 3 section 7, you may distribute non-source (e.g., minimized or compacted) forms of that code without the copy of the GNU GPL normally required by section 4, provided you include this license notice and a URL through which recipients can access the Corresponding Source. @licend The above is the entire license notice for the JavaScript code in this page. */ var wsUrl = 'ws://localhost:9090/connection/websocket'; var wsUser = ''; var loading = false; var lastUpdateTime = null; var unreadPosts = 0; // Thread ID does not change, can be stored one time var threadId = $('div.thread').children('.post').first().attr('id'); function connectWebsocket() { var metapanel = $('.metapanel')[0]; var wsHost = metapanel.getAttribute('data-ws-host'); var wsPort = metapanel.getAttribute('data-ws-port'); if (wsHost.length > 0 && wsPort.length > 0) var centrifuge = new Centrifuge({ "url": 'ws://' + wsHost + ':' + wsPort + "/connection/websocket", "project": metapanel.getAttribute('data-ws-project'), "user": wsUser, "timestamp": metapanel.getAttribute('data-last-update'), "token": metapanel.getAttribute('data-ws-token'), "debug": false }); centrifuge.on('error', function(error_message) { console.log("Error connecting to websocket server."); return false; }); centrifuge.on('connect', function() { var channelName = 'thread:' + threadId; centrifuge.subscribe(channelName, function(message) { var postHtml = message.data['html']; var isAdded = (message.data['diff_type'] === 'added'); if (postHtml) { updatePost(postHtml, isAdded); } }); $('#autoupdate').text('[+]'); }); centrifuge.connect(); return true; } function updatePost(postHtml, isAdded) { // This needs to be set on start because the page is scrolled after posts // are added or updated var bottom = isPageBottom(); var post = $(postHtml); var threadPosts = $('div.thread').children('.post'); var lastUpdate = ''; if (isAdded) { var lastPost = threadPosts.last(); post.appendTo(lastPost.parent()); updateBumplimitProgress(1); showNewPostsTitle(1); lastUpdate = post.children('.post-info').first() .children('.pub_time').first().text(); if (bottom) { scrollToBottom(); } } else { var postId = post.attr('id'); var oldPost = $('div.thread').children('.post[id=' + postId + ']'); oldPost.replaceWith(post); } processNewPost(post); updateMetadataPanel(lastUpdate) } function blink(node) { var blinkCount = 2; var nodeToAnimate = node; for (var i = 0; i < blinkCount; i++) { nodeToAnimate = nodeToAnimate.fadeTo('fast', 0.5).fadeTo('fast', 1.0); } } function isPageBottom() { var scroll = $(window).scrollTop() / ($(document).height() - $(window).height()); return scroll == 1 } function initAutoupdate() { return connectWebsocket(); } function getReplyCount() { return $('.thread').children('.post').length } function getImageCount() { return $('.thread').find('img').length } function updateMetadataPanel(lastUpdate) { var replyCountField = $('#reply-count'); var imageCountField = $('#image-count'); replyCountField.text(getReplyCount()); imageCountField.text(getImageCount()); if (lastUpdate !== '') { var lastUpdateField = $('#last-update'); lastUpdateField.text(lastUpdate); blink(lastUpdateField); } blink(replyCountField); blink(imageCountField); } /** * Update bumplimit progress bar */ function updateBumplimitProgress(postDelta) { var progressBar = $('#bumplimit_progress'); if (progressBar) { var postsToLimitElement = $('#left_to_limit'); var oldPostsToLimit = parseInt(postsToLimitElement.text()); var postCount = getReplyCount(); var bumplimit = postCount - postDelta + oldPostsToLimit; var newPostsToLimit = bumplimit - postCount; if (newPostsToLimit <= 0) { $('.bar-bg').remove(); $('.thread').children('.post').addClass('dead_post'); } else { postsToLimitElement.text(newPostsToLimit); progressBar.width((100 - postCount / bumplimit * 100.0) + '%'); } } } var documentOriginalTitle = ''; /** * Show 'new posts' text in the title if the document is not visible to a user */ function showNewPostsTitle(newPostCount) { if (document.hidden) { if (documentOriginalTitle === '') { documentOriginalTitle = document.title; } unreadPosts = unreadPosts + newPostCount; document.title = '[' + unreadPosts + '] ' + documentOriginalTitle; document.addEventListener('visibilitychange', function() { if (documentOriginalTitle !== '') { document.title = documentOriginalTitle; documentOriginalTitle = ''; unreadPosts = 0; } document.removeEventListener('visibilitychange', null); }); } } /** * Clear all entered values in the form fields */ function resetForm(form) { form.find('input:text, input:password, input:file, select, textarea').val(''); form.find('input:radio, input:checkbox') .removeAttr('checked').removeAttr('selected'); $('.file_wrap').find('.file-thumb').remove(); } /** * When the form is posted, this method will be run as a callback */ function updateOnPost(response, statusText, xhr, form) { var json = $.parseJSON(response); var status = json.status; showAsErrors(form, ''); if (status === 'ok') { resetForm(form); } else { var errors = json.errors; for (var i = 0; i < errors.length; i++) { var fieldErrors = errors[i]; var error = fieldErrors.errors; showAsErrors(form, error); } } scrollToBottom(); } /** * Show text in the errors row of the form. * @param form * @param text */ function showAsErrors(form, text) { form.children('.form-errors').remove(); if (text.length > 0) { var errorList = $('
' + text + '
'); errorList.appendTo(form); } } /** * Run js methods that are usually run on the document, on the new post */ function processNewPost(post) { addRefLinkPreview(post[0]); highlightCode(post); blink(post); } $(document).ready(function(){ if ('WebSocket' in window) { if (initAutoupdate()) { // Post form data over AJAX var threadId = $('div.thread').children('.post').first().attr('id'); var form = $('#form'); var options = { beforeSubmit: function(arr, $form, options) { showAsErrors($('form'), gettext('Sending message...')); }, success: updateOnPost, url: '/api/add_post/' + threadId + '/' }; form.ajaxForm(options); resetForm(form); } } });