From a5accb5be336d821ee43f368c6087eee1c3f5786 Mon Sep 17 00:00:00 2001 From: isqua Date: Thu, 5 Feb 2015 22:28:01 +0300 Subject: [PATCH] =?UTF-8?q?=D0=92=D1=8B=D0=BD=D0=B5=D1=81=D1=82=D0=B8=20aj?= =?UTF-8?q?ax-=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD=D1=82=D0=B0=D1=80=D0=B8?= =?UTF-8?q?=D0=B8,=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D1=82=D1=8C=20?= =?UTF-8?q?=D0=B1=D0=B8=D0=BD=D0=B4=D0=B8=D0=BD=D0=B3=20=D0=BD=D0=B0=20?= =?UTF-8?q?=D0=BE=D1=82=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D1=83=20=D1=84=D0=BE?= =?UTF-8?q?=D1=80=D0=BC=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- chrome_point_plus/js/point-plus.js | 98 +--------- chrome_point_plus/modules/ajax-comments.js | 209 +++++++++++++++++++++ 2 files changed, 213 insertions(+), 94 deletions(-) create mode 100644 chrome_point_plus/modules/ajax-comments.js diff --git a/chrome_point_plus/js/point-plus.js b/chrome_point_plus/js/point-plus.js index 44efbd5..17e1c9e 100644 --- a/chrome_point_plus/js/point-plus.js +++ b/chrome_point_plus/js/point-plus.js @@ -503,100 +503,10 @@ function PointPlus(ppVersion) { if (options.is('option_ajax')) { // Comments if (options.is('option_ajax_comments')) { - // Removing old bindings - // Dirty hack for page context - $('#comments').replaceWith($('#comments').clone()); - - // Binding new - $('#comments').on('keypress.pp', '.reply-form textarea', function (evt) { - var $textarea = $(this); - var $post; - var $form; - var processClass = 'pp-progress' - var csRf; - - if ((evt.keyCode === 10 || evt.keyCode === 13) && (evt.ctrlKey || evt.metaKey)) { - evt.stopPropagation(); - evt.preventDefault(); - - $post = $textarea.parents('.post').first(); - csRf = $textarea.siblings('input[name="csrf_token"]').val(); - - $textarea.prop('disabled', true); - $form = $textarea.parent(); - $form.addClass(processClass); - - $.ajax({ - type: 'POST', - url: '/api/post/' + $post.data('id'), - data: { - text: $textarea.val(), - comment_id: $post.data('comment-id') - }, - error: function(req, status, error) { - console.error('AJAX request error while sending the comment: %s', error); - console.log('Status: %s', status); - - alert(chrome.i18n.getMessage('msg_comment_send_failed') + '\n' + error); - - $textarea.prop('disabled', false); - $form.removeClass(processClass); - }, - /** - * @param {object} data Response data - * @param {number} data.comment_id ID of the created comment - * @param {string} data.id ID of the post - * @param {string} textStatus Text of request status - */ - success: function(data, textStatus) { - console.log('data %O', data); - console.log('status %O', textStatus); - - if (textStatus === 'success') { - // Hiding form - $('#reply-' + $post.data('id') + '_' + $post.data('comment-id')).prop('checked', false); - - // Creating the comment HTML - create_comment_elements({ - id: data.comment_id, - toId: $post.data('comment-id') || null, - postId: $post.data('id'), - author: $('#name h1').text(), - text: $textarea.val(), - fadeOut: true - }, function($comment) { - // If list mode or not addressed to other comment - if ($('#comments #tree-switch a').eq(0).hasClass('active') || ($post.data('comment-id') === undefined)) { - // Adding to the end of the list - $('.content-wrap #comments #post-reply').before($comment); - } else { - // Check for children - $parentCommentChildren = $post.next('.comments'); - - // @fixme Find a bug with lost indentation of new comment - // If child comment already exist - if ($parentCommentChildren.length) { - console.log('Child comments found. Appending...'); - $parentCommentChildren.append($comment); - } else { - console.log('No child comments found. Creating...'); - $post.after($('
').addClass('comments').append($comment)); - } - } - }); - - // Cleaning textarea - $textarea.val(''); - $textarea.prop('disabled', false); - - $form.removeClass(processClass); - } - }, - beforeSend: function (xhr) { - xhr.setRequestHeader('X-CSRF', csRf); - } - }); - } + messenger.js({ + file: 'modules/ajax-comments.js' + }, function() { + var ajaxComments = new AjaxComments(); }); } } diff --git a/chrome_point_plus/modules/ajax-comments.js b/chrome_point_plus/modules/ajax-comments.js new file mode 100644 index 0000000..61fadde --- /dev/null +++ b/chrome_point_plus/modules/ajax-comments.js @@ -0,0 +1,209 @@ +/** + * Находит элемент #comments, и если он есть, начинает слушать на нём события + * @constructor + */ +function AjaxComments() { + var comments = document.querySelector('#comments'); + + if (comments) { + this._comments = comments; + this.listen(comments); + } + + this.listenFirstComments(); +} + +/** + * Вешает обработчики. Магия в последнем параметре addEventListener + */ +AjaxComments.prototype.listen = function(elem) { + elem.addEventListener('submit', this.onSubmit.bind(this), true); + elem.addEventListener('keypress', this.onKeypress.bind(this), true); +}; + +/** + * Слушает отправки первых комментариев + */ +AjaxComments.prototype.listenFirstComments = function() { + var posts = document.querySelectorAll('.post-content'); + + // Чтобы не ловить события на чём попало и мочь использовать useCapture, приходится + // получать все post-content и на каждый вешать обработчики. + Array.prototype.forEach.call(posts, this.listen.bind(this)); +}; + +/** + * Обрабатывает событие отправки формы + * @param {Event} event Событие отправки + */ +AjaxComments.prototype.onSubmit = function(event) { + var $form = $(event.target); + var proc; + + event.preventDefault(); + event.stopPropagation(); + + if ($form.hasClass('reply-form')) { + proc = new AjaxCommentProcessor($form); + } +}; + +/** + * Обрабатывает нажатия кнопок. Если это сочетание Ctrl|⌘+Enter, отправляет коммент + * @param {Event} event Событие нажатия кнопки + */ +AjaxComments.prototype.onKeypress = function(event) { + var $form; + var proc; + + if (this.isProperKeys(event)) { + event.preventDefault(); + event.stopPropagation(); + + $form = $(event.target).closest('.reply-form'); + + if ($form.length) { + proc = new AjaxCommentProcessor($form); + } + } +}; + +/** + * Проверяет, что нажато нужное сочетание клавишь + * @param {Event} event Событие нажатия + * @return {Boolean} + */ +AjaxComments.prototype.isProperKeys = function(event) { + return (event.keyCode === 10 || event.keyCode === 13) && (event.ctrlKey || event.metaKey); +}; + +/** + * Создаётся при каждой отправке комментария + * @param {jQuery} $form Элемент формы, на которой это произошло + */ +function AjaxCommentProcessor($form) { + this._$form = $form; + this._$post = $form.closest('.post'); + this._$textarea = $form.find('textarea'); + + this._text = this._$textarea.val(); + this._CSRF = $form.get(0).elements.csrf_token.value; + + this._postId = this._$post.data('id'); + this._commentId = this._$post.data('comment-id'); + + this.sendComment(); +} + +/** + * Отправляет комментарий + */ +AjaxCommentProcessor.prototype.sendComment = function() { + this.setProgress(true); + + $.ajax({ + type: 'POST', + url: '/api/post/' + this._postId, + data: { + text: this._text, + comment_id: this._commentId + }, + beforeSend: this.beforeSend.bind(this), + error: this.onError.bind(this), + success: this.onSuccess.bind(this) + }); +}; + +/** + * Подкладывает CSRF-токен в заголовки запроса + * @param {XMLHttpRequest} xhr Объект запроса + */ +AjaxCommentProcessor.prototype.beforeSend = function(xhr) { + xhr.setRequestHeader('X-CSRF', this._CSRF); +}; + +/** + * Скрывает форму отправки комментария + * @return {[type]} [description] + */ +AjaxCommentProcessor.prototype.hideForm = function() { + this._$form.prev().prop('checked', false); +}; + +/** + * Создаёт новый комментарий, скрывает форму, снимает прогресс. + * @param {Object} data Ответ сервера + * @param {String} textStatus Статус ответа + */ +AjaxCommentProcessor.prototype.onSuccess = function(data, textStatus) { + var $textarea = this._$textarea; + + if (textStatus === 'success') { + this.hideForm(); + + // Creating the comment HTML + create_comment_elements({ + id: data.comment_id, + toId: this._commentId || null, + postId: this._postId, + author: $('#name h1').text(), + text: this._text, + fadeOut: true + }, this.insertComment.bind(this)); + + // Cleaning textarea + $textarea.val(''); + this.setProgress(false); + } +}; + +/** + * Вставляет комментарий в DOM + * @param {jQuery} $comment + */ +AjaxCommentProcessor.prototype.insertComment = function($comment) { + var $parentCommentChildren; + + if ($('#comments #tree-switch a').eq(0).hasClass('active') || (this._commentId === undefined)) { + // Adding to the end of the list + $('.content-wrap #comments #post-reply').before($comment); + } else { + // Check for children + $parentCommentChildren = this._$post.next('.comments'); + + // @fixme Find a bug with lost indentation of new comment + // If child comment already exist + if ($parentCommentChildren.length) { + console.log('Child comments found. Appending...'); + $parentCommentChildren.append($comment); + } else { + console.log('No child comments found. Creating...'); + this._$post.after( + $('
') + .addClass('comments') + .append($comment) + ); + } + } +}; + +/** + * Показывает алерт с ошибкой и снимает прогресс, если коммент не отправился + * @param {*} req + * @param {*} status + * @param {String} error + */ +AjaxCommentProcessor.prototype.onError = function(req, status, error) { + alert(chrome.i18n.getMessage('msg_comment_send_failed') + '\n' + error); + + this.setProgress(false); +}; + +/** + * Устанавливает прогресс + * @param {Boolean} isProgress true — включить прогресс, false — отключить + */ +AjaxCommentProcessor.prototype.setProgress = function(isProgress) { + this._$textarea.prop('disabled', isProgress); + this._$form.toggleClass('pp-progress', isProgress); +};