mirror of
https://github.com/WerySkok/nativegallery.git
synced 2024-12-22 16:41:17 +03:00
add comment rating!
This commit is contained in:
parent
399939e62e
commit
7a86eb54be
10 changed files with 300 additions and 12 deletions
|
@ -1,11 +1,11 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Controllers\Api\Images;
|
namespace App\Controllers\Api\Images\Comments;
|
||||||
|
|
||||||
use App\Services\{Auth, Router, GenerateRandomStr, DB, Json, Files, Shell};
|
use App\Services\{Auth, Router, GenerateRandomStr, DB, Json, Files, Shell};
|
||||||
use App\Models\Notification;
|
use App\Models\Notification;
|
||||||
|
|
||||||
class Comment
|
class Create
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Controllers\Api\Images;
|
namespace App\Controllers\Api\Images\Comments;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ use App\Services\{Auth, Router, GenerateRandomStr, DB, Json, EXIF};
|
||||||
use App\Models\{User, Vote, Comment};
|
use App\Models\{User, Vote, Comment};
|
||||||
|
|
||||||
|
|
||||||
class CommentsLoad
|
class Load
|
||||||
{
|
{
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
52
app/Controllers/Api/Images/Comments/Rate.php
Normal file
52
app/Controllers/Api/Images/Comments/Rate.php
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controllers\Api\Images\Comments;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
use App\Services\{Auth, Router, GenerateRandomStr, DB, Json, EXIF};
|
||||||
|
use App\Models\{User, Vote};
|
||||||
|
|
||||||
|
|
||||||
|
class Rate
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
|
||||||
|
if (isset($_GET['vote']) && isset($_GET['wid'])) {
|
||||||
|
if (Vote::comment(Auth::userid(), $_GET['wid']) === -1) {
|
||||||
|
DB::query('INSERT INTO photos_comments_rates VALUES (\'0\', :id, :wid, :type)', array(':id'=>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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,8 +7,9 @@ use \App\Core\Page;
|
||||||
use \App\Controllers\Api\{Login, Register};
|
use \App\Controllers\Api\{Login, Register};
|
||||||
use \App\Controllers\Api\Images\{Upload};
|
use \App\Controllers\Api\Images\{Upload};
|
||||||
use \App\Controllers\Api\Images\Rate as PhotoVote;
|
use \App\Controllers\Api\Images\Rate as PhotoVote;
|
||||||
use \App\Controllers\Api\Images\Comment as PhotoComment;
|
use \App\Controllers\Api\Images\Comments\Create as PhotoComment;
|
||||||
use \App\Controllers\Api\Images\CommentsLoad as PhotoCommentLoad;
|
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;
|
use \App\Controllers\Api\Profile\Update as ProfileUpdate;
|
||||||
class ApiController
|
class ApiController
|
||||||
{
|
{
|
||||||
|
@ -29,6 +30,9 @@ class ApiController
|
||||||
public static function photocomment() {
|
public static function photocomment() {
|
||||||
return new PhotoComment();
|
return new PhotoComment();
|
||||||
}
|
}
|
||||||
|
public static function photocommentvote() {
|
||||||
|
return new PhotoCommentVote();
|
||||||
|
}
|
||||||
public static function photocommentload() {
|
public static function photocommentload() {
|
||||||
return new PhotoCommentLoad();
|
return new PhotoCommentLoad();
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,9 +17,7 @@ class Routes
|
||||||
Router::get('/register', 'RegisterController@i');
|
Router::get('/register', 'RegisterController@i');
|
||||||
Router::get('/photo/$id', 'PhotoController@i');
|
Router::get('/photo/$id', 'PhotoController@i');
|
||||||
Router::get('/author/$id', 'ProfileController@i');
|
Router::get('/author/$id', 'ProfileController@i');
|
||||||
|
|
||||||
Router::post('/api/login', 'ApiController@login');
|
Router::post('/api/login', 'ApiController@login');
|
||||||
Router::get('/api/photo/vote', 'ApiController@photovote');
|
|
||||||
Router::post('/api/register', 'ApiController@register');
|
Router::post('/api/register', 'ApiController@register');
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,6 +32,9 @@ class Routes
|
||||||
Router::post('/api/profile/update', 'ApiController@updateprofile');
|
Router::post('/api/profile/update', 'ApiController@updateprofile');
|
||||||
Router::post('/api/photo/comment', 'ApiController@photocomment');
|
Router::post('/api/photo/comment', 'ApiController@photocomment');
|
||||||
Router::post('/api/photo/getcomments/$id', 'ApiController@photocommentload');
|
Router::post('/api/photo/getcomments/$id', 'ApiController@photocommentload');
|
||||||
|
Router::get('/api/photo/vote', 'ApiController@photovote');
|
||||||
|
Router::get('/api/photo/comment/rate', 'ApiController@photocommentvote');
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Router::redirect('/login?return='.$_SERVER['HTTP_REFERER']);
|
Router::redirect('/login?return='.$_SERVER['HTTP_REFERER']);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
use \App\Services\{DB, Date};
|
use \App\Services\{DB, Date};
|
||||||
use \App\Models\{User, Photo};
|
use \App\Models\{User, Photo, Vote};
|
||||||
|
|
||||||
class Comment {
|
class Comment {
|
||||||
|
|
||||||
|
@ -25,15 +25,26 @@ class Comment {
|
||||||
if (json_decode($user->i('content'), true)['aboutlive']['value'] != null) {
|
if (json_decode($user->i('content'), true)['aboutlive']['value'] != null) {
|
||||||
echo ' '.json_decode($user->i('content'), true)['aboutlive']['value'];
|
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 '</span></div>
|
echo '</span></div>
|
||||||
<div class="rank">Фото: '.Photo::fetchAll($this->c['user_id']).'</div>
|
<div class="rank">Фото: '.Photo::fetchAll($this->c['user_id']).'</div>
|
||||||
<div class="message-text">'.$this->c['body'].'</div>
|
<div class="message-text">'.$this->c['body'].'</div>
|
||||||
<div class="comment-votes-block">
|
<div class="comment-votes-block">
|
||||||
<div class="wvote" wid="'.$this->c['id'].'">
|
<div class="wvote" wid="'.$this->c['id'].'">
|
||||||
<div class="w-rating pro">+1</div>
|
<a href="#" vote="1" class="w-btn s2"><span>+</span></a>
|
||||||
|
<div class="w-rating '.$commclass.'">'.$symb.Vote::countcommrates($this->c['id'], -1).'</div>
|
||||||
<div class="w-rating-ext">
|
<div class="w-rating-ext">
|
||||||
<div><span class="pro">+1</span> / <span class="con">–0</span></div>
|
<div><span class="pro">+'.Vote::countcommrates($this->c['id'], 1).'</span> / <span class="con">'.Vote::countcommrates($this->c['id'], 0).'</span></div>
|
||||||
</div>
|
</div>
|
||||||
|
<a href="#" vote="0" class="w-btn s5"><span>–</span></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>';
|
</div>';
|
||||||
|
|
|
@ -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) {
|
public static function count( $pid) {
|
||||||
|
@ -34,6 +51,22 @@ class Vote
|
||||||
}
|
}
|
||||||
return $votes;
|
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()
|
public static function token()
|
||||||
{
|
{
|
||||||
|
|
187
static/js/comments.js
Normal file
187
static/js/comments.js
Normal file
|
@ -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('<div class="no-quote-last">' + msg + '</div>');
|
||||||
|
|
||||||
|
if (lastQuoteLinkBlock)
|
||||||
|
{
|
||||||
|
lastQuoteLinkBlock = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else $('.no-quote-last').remove();
|
||||||
|
|
||||||
|
if (selectedText == '')
|
||||||
|
mText = $('.message-text', comment).html();
|
||||||
|
else mText = $('<div>').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 href\=\"', 'ig'), '').replace(new RegExp('\" target\=\"\_blank\"\>[^>]*\<\/a\>', 'ig'), '');
|
||||||
|
mText = mText.replace(/<br/ig, '[br]').replace(/(<([^>]+)>)/ig, '').replace(/\[br\]/ig, '<br');
|
||||||
|
mText = mText.replace(/>/ig, '>').replace(/</ig, '<').replace(/"e;/ig, '"').replace(/&/ig, '&');
|
||||||
|
mTextArray = mText.split(/<br\s*\/?>\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');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -21,6 +21,7 @@
|
||||||
<script src="/static/js/progress.js"></script>
|
<script src="/static/js/progress.js"></script>
|
||||||
<script src="/static/js/notie.js"></script>
|
<script src="/static/js/notie.js"></script>
|
||||||
<script src="/static/js/photo.js"></script>
|
<script src="/static/js/photo.js"></script>
|
||||||
|
<script src="/static/js/comments.js"></script>
|
||||||
<div class="progress-container fixed-top">
|
<div class="progress-container fixed-top">
|
||||||
<span class="progress-bard"></span>
|
<span class="progress-bard"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -21,7 +21,6 @@ $photouser = new \App\Models\User($photo->i('user_id'));
|
||||||
<body>
|
<body>
|
||||||
<div id="backgr"></div>
|
<div id="backgr"></div>
|
||||||
<table class="tmain">
|
<table class="tmain">
|
||||||
<?=Vote::photo(Auth::userid(), $id)?>
|
|
||||||
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Navbar.php'); ?>
|
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Navbar.php'); ?>
|
||||||
<tr>
|
<tr>
|
||||||
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
|
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
|
||||||
|
|
Loading…
Reference in a new issue