diff --git a/app/Controllers/Api/Images/Comment.php b/app/Controllers/Api/Images/Comments/Create.php similarity index 96% rename from app/Controllers/Api/Images/Comment.php rename to app/Controllers/Api/Images/Comments/Create.php index 7331169..fd46abc 100644 --- a/app/Controllers/Api/Images/Comment.php +++ b/app/Controllers/Api/Images/Comments/Create.php @@ -1,11 +1,11 @@ Auth::userid(), ':wid' => $_GET['wid'], ':type'=>$_GET['vote'])); + if (Vote::comment(Auth::userid(), $_GET['wid']) != $_GET['vote']) { + DB::query('DELETE FROM photos_comments_rates WHERE user_id=:id AND comment_id=:wid AND type=:type', array(':id'=>Auth::userid(), ':wid' => $_GET['wid'], ':type'=>Vote::comment(Auth::userid(), $_GET['wid']))); + } + } else if (Vote::comment(Auth::userid(), $_GET['wid']) === (int)$_GET['vote']) { + DB::query('DELETE FROM photos_comments_rates WHERE user_id=:id AND comment_id=:wid', array(':id'=>Auth::userid(), ':wid' => $_GET['wid'])); + } else { + DB::query('UPDATE photos_comments_rates SET type=:type WHERE user_id=:id AND comment_id=:wid', array(':id'=>Auth::userid(), ':wid' => $_GET['wid'], ':type'=>$_GET['vote'])); + + } + if (Vote::comment(Auth::userid(), $_GET['wid']) === 1) { + $pos = true; + $neg = true; + } else if (Vote::comment(Auth::userid(), $_GET['wid']) === 0) { + $pos = false; + $neg = true; + } else { + $pos = false; + $neg = false; + } + $array = [ + [1 => $pos, 0 => $neg], + [1 => Vote::countcommrates($_GET['wid'], 1), 0 => Vote::countcommrates($_GET['wid'], 0)], + Vote::countcommrates($_GET['wid'], -1) + ]; + + + $json = json_encode($array); + + + header('Content-Type: application/json'); + echo $json; + } + } +} diff --git a/app/Controllers/ApiController.php b/app/Controllers/ApiController.php index 921150a..6c30e05 100644 --- a/app/Controllers/ApiController.php +++ b/app/Controllers/ApiController.php @@ -7,8 +7,9 @@ use \App\Core\Page; use \App\Controllers\Api\{Login, Register}; use \App\Controllers\Api\Images\{Upload}; use \App\Controllers\Api\Images\Rate as PhotoVote; -use \App\Controllers\Api\Images\Comment as PhotoComment; -use \App\Controllers\Api\Images\CommentsLoad as PhotoCommentLoad; +use \App\Controllers\Api\Images\Comments\Create as PhotoComment; +use \App\Controllers\Api\Images\Comments\Load as PhotoCommentLoad; +use \App\Controllers\Api\Images\Comments\Rate as PhotoCommentVote; use \App\Controllers\Api\Profile\Update as ProfileUpdate; class ApiController { @@ -29,6 +30,9 @@ class ApiController public static function photocomment() { return new PhotoComment(); } + public static function photocommentvote() { + return new PhotoCommentVote(); + } public static function photocommentload() { return new PhotoCommentLoad(); } diff --git a/app/Core/Routes.php b/app/Core/Routes.php index fa9556b..056120d 100644 --- a/app/Core/Routes.php +++ b/app/Core/Routes.php @@ -17,9 +17,7 @@ class Routes Router::get('/register', 'RegisterController@i'); Router::get('/photo/$id', 'PhotoController@i'); Router::get('/author/$id', 'ProfileController@i'); - Router::post('/api/login', 'ApiController@login'); - Router::get('/api/photo/vote', 'ApiController@photovote'); Router::post('/api/register', 'ApiController@register'); @@ -34,6 +32,9 @@ class Routes Router::post('/api/profile/update', 'ApiController@updateprofile'); Router::post('/api/photo/comment', 'ApiController@photocomment'); Router::post('/api/photo/getcomments/$id', 'ApiController@photocommentload'); + Router::get('/api/photo/vote', 'ApiController@photovote'); + Router::get('/api/photo/comment/rate', 'ApiController@photocommentvote'); + } else { Router::redirect('/login?return='.$_SERVER['HTTP_REFERER']); } diff --git a/app/Models/Comment.php b/app/Models/Comment.php index 26d6427..827ae9e 100644 --- a/app/Models/Comment.php +++ b/app/Models/Comment.php @@ -1,7 +1,7 @@ i('content'), true)['aboutlive']['value'] != null) { echo ' '.json_decode($user->i('content'), true)['aboutlive']['value']; } + if ((int)Vote::countcommrates($this->c['id'], -1) >= 1) { + $commclass = 'pro'; + $symb = '+'; + } else if ((int)Vote::countcommrates($this->c['id'], -1) < 0) { + $commclass = 'con'; + $symb = '-'; + } else if ((int)Vote::countcommrates($this->c['id'], -1) === 0) { + $commclass = ''; + } echo '
Фото: '.Photo::fetchAll($this->c['user_id']).'
'.$this->c['body'].'
-
+1
+ + +
'.$symb.Vote::countcommrates($this->c['id'], -1).'
-
+1 / –0
+
+'.Vote::countcommrates($this->c['id'], 1).' / '.Vote::countcommrates($this->c['id'], 0).'
+
'; diff --git a/app/Models/Vote.php b/app/Models/Vote.php index f132a7a..71152f5 100644 --- a/app/Models/Vote.php +++ b/app/Models/Vote.php @@ -20,6 +20,23 @@ class Vote } + } + + public static function comment($user_id, $pid) + { + $result = DB::query('SELECT * FROM photos_comments_rates WHERE user_id=:uid AND comment_id=:pid', array(':uid' => $user_id, ':pid' => $pid)); + if (!empty($result)) { + $type = $result[0]['type']; + if ($type < 0) { + $type = -1; + } + + return $type; + } else { + return -1; + } + + } public static function count( $pid) { @@ -34,6 +51,22 @@ class Vote } return $votes; } + public static function countcommrates($pid, $type) { + if ($type === -1) { + $result = DB::query('SELECT * FROM photos_comments_rates WHERE comment_id=:pid', array(':pid' => $pid)); + } else { + $result = DB::query('SELECT * FROM photos_comments_rates WHERE comment_id=:pid AND type=:type', array(':pid' => $pid, ':type'=>$type)); + } + $votes = 0; + foreach ($result as $r) { + if ($r['type'] === 1) { + $votes++; + } else { + $votes--; + } + } + return $votes; + } public static function token() { diff --git a/static/js/comments.js b/static/js/comments.js new file mode 100644 index 0000000..bb7eaf8 --- /dev/null +++ b/static/js/comments.js @@ -0,0 +1,187 @@ +var navLock = false; +var lastQuoteLinkBlock = true; + +$(document).ready(function() +{ + // Изменение рейтинга комментария (с учётом форматирования) + function setComVote(cell, rating) + { + if (rating > 0) cell.removeClass('con').addClass('pro').html('+' + rating); else + if (rating < 0) cell.removeClass('pro').addClass('con').html('–' + parseInt(-rating)); + else cell.removeClass('pro con').html(0); + } + + + // Голосование за комментарии + $(document).on('click', '.w-btn', function() + { + var vote = $(this).attr('vote'); + if (vote != 0 && vote != 1) return false; + + var voted = $(this).is('.voted'); + $(this).toggleClass('voted'); + + var diff = (vote == 1 && !voted || vote == 0 && voted) ? 1 : -1; + + var otherButton = $(this).siblings('.w-btn'); + var votedOther = otherButton.is('.voted'); + + if (votedOther) + { + otherButton.removeClass('voted'); + diff *= 2; + } + + var cell = $(this).siblings('.w-rating'); + var rating = parseInt(cell.is('.con') ? -cell.html().substring(1) : cell.html()); + + setComVote(cell, rating + diff); + + + var cell_ext = $(this).siblings('.w-rating-ext'); + cell_ext.addClass('active-locked'); + + var pro = $('.pro', cell_ext); + var con = $('.con', cell_ext); + + if (vote == 1 || vote == 0 && votedOther) pro.html('+' + (parseInt(pro.text().substr(1)) + (vote == 1 && !voted ? 1 : -1))); + if (vote == 0 || vote == 1 && votedOther) con.html('–' + (parseInt(con.text().substr(1)) + (vote == 0 && !voted ? 1 : -1))); + + + var wvote = $(this).closest('.wvote'); + setTimeout(function() { $('.w-btn', wvote).removeClass('active'); }, 200); + setTimeout(function() { cell_ext.removeClass('active active-locked'); }, 1000); + + $.getJSON('/api/photo/comment/rate', { action: 'vote-comment', wid: wvote.attr('wid'), vote: vote }, function (data) + { + if (data && !data[3]) + { + $('.w-btn[vote="1"]', wvote)[data[0][1] ? 'addClass' : 'removeClass']('voted'); + $('.w-btn[vote="0"]', wvote)[data[0][0] ? 'addClass' : 'removeClass']('voted'); + + pro.html('+' + data[1][1]); + con.html('' + data[1][0]); + + setComVote(cell, data[2]); + } + else if (data[3]) alert(data[3]); + }) + .fail(function(jx) { if (jx.responseText != '') alert(jx.responseText); }); + + return false; + }) + // Отображение кнопок + .on('mouseenter mouseleave', '.w-btn[vote="1"]', function() { $(this).toggleClass('s2 s12'); }) + .on('mouseenter mouseleave', '.w-btn[vote="0"]', function() { $(this).toggleClass('s5 s15'); }) + .on('mouseenter touchstart', '.wvote', function() { $('.w-btn, .w-rating-ext', this).addClass('active'); }) + .on('mouseleave', '.wvote', function() { $('.w-btn, .w-rating-ext', this).removeClass('active'); }) + .on('touchstart', function(e) { if (!$(e.target).is('.wvote') && $(e.target).closest('.wvote').length == 0) $('.w-btn, .w-rating-ext').removeClass('active'); }); + + + // Подсветка комментария, если дана ссылка на комментарий + var anchorTestReg = /#(\d+)$/; + var arr = anchorTestReg.exec(window.location.href); + if (arr != null) $('.comment[wid="' + arr[1] + '"]').addClass('s2'); + + + // Ссылка на комментарий + $('.cmLink').on('click', function() + { + var comment = $(this).closest('.comment'); + comment.siblings().removeClass('s2'); + comment.addClass('s2'); + }); + + + // Удаление комментария + $('.delLink').on('click', function() { return confirm(_text['P_DEL_CONF']); }); + + + // Цитирование + $('.quoteLink').on('click', function() + { + var comment = $(this).closest('.comment'), mText, mTextArray; + var selection = window.getSelection(); + + var selectedText = selection.toString(); + var quotedText = (selectedText == '') ? $('.message-text', comment).text() : selectedText; + var msg = ''; + + if (selectedText == '' && comment.next('.comment').length == 0) msg = _text['P_QUOTE_MSG']; else + if (quotedText.length > 600) msg = _text['P_QUOTE_LEN']; + + if (msg != '') + { + if ($('.no-quote-last', comment).length == 0) comment.append('
' + msg + '
'); + + if (lastQuoteLinkBlock) + { + lastQuoteLinkBlock = false; + return false; + } + } + else $('.no-quote-last').remove(); + + if (selectedText == '') + mText = $('.message-text', comment).html(); + else mText = $('
').append(selection.getRangeAt(0).cloneContents()).html(); + + mText = mText.replace(/<\/?i[^>]*>/ig, '').replace(/<\/?u>/ig, '').replace(/<\/?span[^>]*>/ig, '').replace(/<\/?div[^>]*>/ig, ''); + mText = mText.replace(new RegExp('\[^>]*\<\/a\>', 'ig'), ''); + mText = mText.replace(/
]+)>)/ig, '').replace(/\[br\]/ig, '').replace(/</ig, '<').replace(/"e;/ig, '"').replace(/&/ig, '&'); + mTextArray = mText.split(/\s*/i); + + var mText2 = ''; + for (var i = 0; i < mTextArray.length; ++i) + mText2 += '> ' + mTextArray[i] + '\n'; + + var txtField = $('#wtext'); + if (txtField.length) + { + var messageText = txtField.val(); + var insertText = (messageText == '' ? '' : '\n') + _text['P_QUOTE_TXT'] + ' (' + $('.message_author', comment).text() + ', ' + $('.message_date', comment).text() + '):\n' + mText2 + '\n'; + + txtField.val(messageText + insertText); + txtField[0].focus(); + } + + return false; + }); + + + // Отправка комментария + $('#f1').on('submit', function() + { + if ($('#wtext').val().trim() == '') + { + alert(_text['P_ENTERTEXT'] + '.'); + return false; + } + else $('#sbmt').attr('disabled', true).val(_text['P_WAIT']); + }); + + + // Окно ввода комментария + $('#wtext').on('keypress', function(e) { if ((e.which == 10 || e.which == 13) && e.ctrlKey) $('#f1').submit(); }) + .on('focus', function() { navLock = true; }) + .on('blur', function() { navLock = false; }); + + + // Переключатель подписки + $('.toggle, .toggle-label').on('click', function(e) + { + if (e.target.tagName == 'A') return; + var toggle = $('.toggle').toggleClass('on'); + + $.get('/api.php', { action: 'subscribe', id: $('#id').val(), subj: $('#subj').val() }, function (r) + { + if (r != 0 && r != 1) + { + toggle.toggleClass('on'); + alert(r); + } + else toggle.attr('class', (r == 1) ? 'toggle on' : 'toggle'); + }); + }); +}); \ No newline at end of file diff --git a/views/components/LoadHead.php b/views/components/LoadHead.php index ca418b7..216fa24 100644 --- a/views/components/LoadHead.php +++ b/views/components/LoadHead.php @@ -21,6 +21,7 @@ +
diff --git a/views/pages/Photo.php b/views/pages/Photo.php index 2f9e755..79c89f4 100644 --- a/views/pages/Photo.php +++ b/views/pages/Photo.php @@ -21,7 +21,6 @@ $photouser = new \App\Models\User($photo->i('user_id'));
-