This commit is contained in:
leetNightshade 2019-01-03 16:13:23 -08:00
commit be0eca0ff5
10 changed files with 1071 additions and 391 deletions

View File

@ -1,6 +1,6 @@
# Grav Comments Plugin \[Fork\]
This plugin adds support for displaying pingbacks, toggling the display of pingbacks. I'm not yet sure how pingbacks work, so this may not include support for adding new pingbacks; if it won't take too much work I'll add more support for them. Also added support for user entered URLs, though I haven't gotten the form input to show up yet.
This plugin adds support for displaying pingbacks, toggling the display of pingbacks. I'm not yet sure how pingbacks work, so this may not include support for adding new pingbacks though I attempted to patch the php file so it could work in theory; if it won't take too much work I'll add more support for them. Also added support for user entered URLs, though I haven't gotten the form input to show up yet.
This fork adds support for Akismet, which is now basically working. Consider it alpha. Also has admin panel functionality, can toggle it, add api key, shows error on comment page if api key doesn't match site. Going to add amin panel checkbox for recaptcha.

86
assets/comments.css Normal file
View File

@ -0,0 +1,86 @@
/*
===============================================================================================================================
Comments Plugin Styles
===============================================================================================================================
*/
.comment {
margin-top: 0px;
width:100%;
}
.comment:first-child {
margin-top: 0px;
}
.comment,
.comment-body {
zoom: 1;
}
.comment-body {
overflow: hidden;
margin-left: 10px;
}
.comment-object {
display: block;
}
.comment-right,
.comment > .pull-right {
padding-left: 10px;
}
.comment-left,
.comment > .pull-left {
padding-right: 10px;
}
.comment-middle {
vertical-align: middle;
}
.comment-bottom {
vertical-align: bottom;
}
.comment-heading {
margin-top: 0px;
margin-bottom: 5px;
}
.comment-meta {
font-size: small;
}
.comment-text {
clear: both;
}
.comment-list {
padding-left: 0px;
list-style: none;
}
.comment-flag-new {
background-color: lightcyan;
}
.comment-wrapper {
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
}
.comment-avatar {
width: 20px;
height: 20px;
margin-left: -10px;
margin-right:5px;
vertical-align: middle;
}
/*.comment-thread-line:hover {
border-left:3px solid #1BB3E9;
}*/
.comment-thread-top {
margin-top:20px;
}
.comment-thread {
float: left;
border-left:3px solid #444;
margin-left:10px;
}
.comment-footer {
font-size: small;
}
.comment-reply {
display: inline;
}

216
assets/comments.js Normal file
View File

@ -0,0 +1,216 @@
function escapeRegExp(str) {
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
}
jQuery(document).ready(function() {
var commentForm = $('#comments-form'); //$(document).find('.comments-form').first();
var commentSection = $('#comments-section'); //$(document).find('.comments').first();
var commentAlert = $('#comments-alert'); //$(document).find('.alert').first();
//hide form, show link
commentForm.hide();
$(document).find('.comment-add-new').show();
//show comment form above comments section (new comment thread)
$('body').on('click', '.comment-add-new', function(e) {
e.preventDefault();
if ($(this).prev().filter('#comments-form').length > 0) {
//form is already in the right place.
//just make sure it is visible.
commentForm.show();
return;
}
commentForm.hide(); //hide it to make sure that it is not shown after move to make "show" transition work.
$(this).before(commentForm);
commentForm.show('slow');
commentAlert.empty().slideUp();
});
//show comment form below selected comment (reply to existing comment)
$('body').on('click', '.comment-add-reply', function(e) {
e.preventDefault();
var comment = $(this).closest('.comment');
if (comment.find('#comments-form').length > 0) {
//form is already in the right place.
//just make sure it is visible.
commentForm.show();
return;
}
commentForm.hide();
comment.find('.comment-body').last().append(commentForm);
commentForm.show('slow');
commentAlert.empty().slideUp();
});
//delete comment (authorized user only)
$('body').on('click', '.comment-delete', function(e) {
e.preventDefault();
var comment = $(this).closest('.comment');
var id = parseInt(comment.attr('data-id'), 10);
var level = parseInt(comment.attr('data-level'), 10);
var nonce = commentForm.find("input[name='form-nonce']").val();
if (comment.next().filter(".comment[data-level='" + (level + 1) + "']").length > 0) {
alert('Deletion not allowed. There are replies to this comment. Please delete them first.');
return;
}
var url = commentForm.attr("action");
var posting = $.post(url, {
action: 'delete',
id: id,
nonce: nonce
}, null, 'json');
// Register events to ajax call
posting.done(function(response) {
//make sure that commentForm is definitely not within the deleted DOM part.
//hide
//temporary move it outside the comment selected for deletion. (this definitely exists, not taking any chances here)
//finally move back to start of commentSection. (preferred target)
//Hint: Don't forget commentAlert as it is not inside the form.
commentAlert.empty().hide();
commentForm.hide();
comment.before(commentForm);
comment.before(commentAlert);
commentSection.prepend(commentAlert);
commentSection.prepend(commentForm);
//remove the comment and all content from DOM.
//detach would be a soft delete but as there is no reason to reuse the deleted comment, means should not be provided.
comment.remove();
});
posting.fail(function(status, error, title) {
//alert('error');
//console.log("Response Data (fail)", JSON.parse(JSON.stringify(status)));
commentForm.after(commentAlert);
commentAlert.show();
commentAlert.empty().append("<p>Error: </p>");
commentAlert.append("<p>" + JSON.stringify(status) + "</p>");
commentAlert.append("<p>" + JSON.stringify(error) + "</p>");
commentAlert.append("<p>" + JSON.stringify(title) + "</p>");
});
posting.always(function() {
//alert("finished, be it successful or not");
});
});
// Attach a submit handler to the form
$(commentForm).on('submit', function(event) {
event.preventDefault();
// Get form data:
var data = $(this).serialize();
//console.log("Form Data (submit)", JSON.parse(JSON.stringify(data)));
var url = $(this).attr("action");
//var url = '/nested-comments';
var parent = 0;
var ownLevel = 0;
if ($(this).parents('.comment').length > 0) {
parent = $(this).closest('.comment').attr('data-id');
ownLevel = parseInt($(this).closest('.comment').attr('data-level'), 10) + 1;
}
// Send the data using post
//var posting = $.post(url, { parent: parent, data: data }, null, 'json');
var posting = $.post(url, data + '&parent=' + parent, null, 'json');
// Register events to ajax call
posting.done(function(response) {
//alert('success');
//console.log("Response Data (done)", JSON.parse(JSON.stringify(response)));
//response = JSON.parse(response); //not needed, post was done using json
commentForm.after(commentAlert);
if (!response.status) {
//should not trigger at all, if all bad requests return the right http status code
//i.e. <> 200 success => thus triggering posting.fail()
//leave this check just in case
commentAlert.stop().css('opacity', 1).text('Error: ' + response.message).fadeIn(30).fadeOut(5000);
return;
}
if (response.status) {
commentAlert.css('color', 'green').empty().append(document.createTextNode(response.message)).fadeIn(30);
/*var newMedia = "<div class='comment comment-level-{{comment.level|e}} comment-flag-new' data-level='{{comment.level}}' data-id='{{comment.id}}' >" +
"<div class='comment-left'>" +
"<img class='comment-object' src='https://www.gravatar.com/avatar/{{comment.email|trim|lower|md5}}?d=identicon' alt='user icon'>" +
"</div>" +
"<div class='comment-body'>" +
"<div class='comment-heading'>" +
"<div class='comment-title'><h4>{{comment.title}}</h4></div>" +
"<div class='comment-reply'><a class='comment-add-reply' href='#'><i class='fa fa-reply' title='{{'PLUGIN_COMMENTS.ADD_REPLY'|t}}'></i> {{'PLUGIN_COMMENTS.REPLY'|t}}</a></div>" +
"<div class='comment-meta'>{{'PLUGIN_COMMENTS.WRITTEN_ON'|t}} {{comment.date|e}} {{'PLUGIN_COMMENTS.BY'|t}} {{comment.author}}</div>" +
"</div>" +
"<div class='comment-text' >" +
"{{comment.text}}" +
"</div>" +
"{{nested}}" +
"</div>" +
"</div>";*/
var newMedia = `<div id="comment-{{comment.id}}" class="comment comment-level-{{comment.level|e}}" data-id="{{comment.id}}" itemtype="http://schema.org/UserComments">
<header class="comment-heading">
<img class="comment-avatar" src="https://www.gravatar.com/avatar/{{comment.email|trim|lower|md5}}?size=20&d=identicon" alt="user icon">
<span class="comment-meta">
{% if comment.site %}
<a href="{{comment.site}}">{{comment.author}}</a>
{% else %}
{{comment.author}}
{% endif %}
<a href="{{uri.url(true)}}#comment-{{comment.id}}" title="Link to this comment" itemprop="url">
<time class="comment-date" datetime="{{comment.date|e}}" itemprop="commentTime">
{{comment.date|nicetime(false)}}
</time>
</a>
</span>
</header>
<div class="comment-body">
<div class="comment-text" >
{{comment.text}}
</div>
{{nested}}
<div class="comment-footer">
<span class="comment-reply">
{% if grav.twig.commenting_enabled %}
<a class="comment-add-reply" href="#"><i class="fa fa-reply" title="{{'PLUGIN_COMMENTS.ADD_REPLY'|t}}"></i> {{'PLUGIN_COMMENTS.REPLY'|t}}</a>
{% endif %}
{% if grav.user.access.admin.super %}
<a class="comment-delete" href="#"><i class="fa fa-trash" title="{{'PLUGIN_COMMENTS.DELETE_COMMENT'|t}}"></i> {{'PLUGIN_COMMENTS.DELETE'|t}}</a>
{% endif %}
</span>
</div>
</div>
</div>`;
newMedia = newMedia.replace(new RegExp(escapeRegExp("{{comment.id}}"), 'g'), response.data.id);
newMedia = newMedia.replace(new RegExp(escapeRegExp("{{comment.level|e}}"), 'g'), ownLevel);
newMedia = newMedia.replace(new RegExp(escapeRegExp("{{comment.level}}"), 'g'), ownLevel);
newMedia = newMedia.replace(new RegExp(escapeRegExp("{{comment.email|trim|lower|md5}}"), 'g'), response.data.hash);
newMedia = newMedia.replace(new RegExp(escapeRegExp("{{parent}}"), 'g'), response.data.parent);
newMedia = newMedia.replace(new RegExp(escapeRegExp("{{comment.title}}"), 'g'), response.data.title);
newMedia = newMedia.replace(new RegExp(escapeRegExp("{{comment.text}}"), 'g'), response.data.text);
newMedia = newMedia.replace(new RegExp(escapeRegExp("{{comment.author}}"), 'g'), response.data.name);
newMedia = newMedia.replace(new RegExp(escapeRegExp("{{comment.site}}"), 'g'), response.data.site);
newMedia = newMedia.replace(new RegExp(escapeRegExp("{{comment.date|e}}"), 'g'), response.data.date);
newMedia = newMedia.replace(new RegExp(escapeRegExp("{{nested}}"), 'g'), '');
newMedia = newMedia.replace(new RegExp(escapeRegExp("{{'PLUGIN_COMMENTS.ADD_REPLY'|t}}"), 'g'), response.data.ADD_REPLY);
newMedia = newMedia.replace(new RegExp(escapeRegExp("{{'PLUGIN_COMMENTS.REPLY'|t}}"), 'g'), response.data.REPLY);
newMedia = newMedia.replace(new RegExp(escapeRegExp("{{'PLUGIN_COMMENTS.WRITTEN_ON'|t}}"), 'g'), response.data.WRITTEN_ON);
if ($("div[data-id='" + response.data.parent + "']").length > 0) {
$("div[data-id='" + response.data.parent + "']").first().after(newMedia);
} else {
$("#comments").prepend(newMedia);
}
}
setTimeout(function() {
commentForm.slideUp();
commentAlert.fadeOut(5000);
}, 5000);
});
posting.fail(function(status, error, title) {
//alert('error');
//console.log("Response Data (fail)", JSON.parse(JSON.stringify(status)));
commentForm.after(commentAlert);
commentAlert.show();
commentAlert.empty().append("<p>Error: </p>");
commentAlert.append("<p>" + JSON.stringify(status) + "</p>");
commentAlert.append("<p>" + JSON.stringify(error) + "</p>");
commentAlert.append("<p>" + JSON.stringify(title) + "</p>");
});
posting.always(function() {
//alert("finished, be it successful or not");
});
});
});

44
class/Comment.php Normal file
View File

@ -0,0 +1,44 @@
<?php
namespace Grav\Plugin;
class Comment
{
private $id = 0;
private $value = array();
private $parent = null;
private $children = array();
public function __construct($id, $content) {
$this->id = $id;
$this->value = $content;
}
public function addItem($obj, $key = null) {
}
public function deleteItem($key) {
}
public function getItem($key) {
}
public function getContent($level = 0) {
$this->value['level'] = $level;
$comments[] = $this->value;
foreach($this->children as $child) {
//$comments[] = $child->getContent($level + 1); //produces nested result array.
$comments = array_merge($comments, $child->getContent($level + 1)); //produces flat result array.
}
return $comments;
}
public function setParent($parent) {
$this->parent = $parent;
}
public function addSubComment($obj) {
$this->children[] = $obj;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -3,14 +3,13 @@ pingbacks: true
commenting: true
akismet_enabled: true
warning_message: ""
built_in_css: true
ajax_callback: /nested-comments
enable_on_routes:
- '/blog'
disable_on_routes:
- /blog/blog-post-to-ignore
- /ignore-this-route
form:
name: comments
fields:
@ -29,9 +28,9 @@ form:
validate:
required: true
- name: blah
- name: site
label: PLUGIN_COMMENTS.SITE_LABEL
placeholder: "https://leetnightshade.com"
placeholder:
type: text
validate:
required: false
@ -48,10 +47,6 @@ form:
process:
fillWithCurrentDateTime: true
- name: title
type: hidden
evaluateDefault: grav.page.header.title
- name: lang
type: hidden
evaluateDefault: grav.language.getLanguage

View File

@ -1,13 +1,22 @@
de:
PLUGIN_COMMENTS:
ADD_NEW: Kommentar hinzufügen
ADD_REPLY: Auf Kommentar antworten
ADD_COMMENT: Kommentar hinzufügen
AKISMET: Akismet
AKISMET_KEY_API: Akismet API Key
AKISMET_SITE_OVERRIDE: Akismet Site Override
DELETE_COMMENT: Kommentar löschen
REPLY: Antworten
DELETE: Löschen
SUCCESS: "Der Kommentar wurde erfolgreich gespeichert."
COMMENTS: Kommentare
COMMENTS_NESTED: Nested Comments
COMMENTS_NONE: There are no comments yet.
COMMENTS_PINGBACKS: Pingbacks
COMMENTS_STATS: Kommentare
RECENT_COMMENTS: Neue Kommentare
RECENT_PAGES: Kommentierte Seiten
EMAIL_NOT_CONFIGURED: Email nicht konfiguriert
NEW_COMMENT_EMAIL_SUBJECT: 'Neuer Kommentar für %1$s'
NEW_COMMENT_EMAIL_BODY: '<p>Ein neuer Kommentar am %1$s von %3$s (%4$s).</p><p>Seite: %2$s</p><p>Text: %5$s</p>'
@ -30,14 +39,23 @@ de:
en:
PLUGIN_COMMENTS:
ADD_NEW: Add a comment
ADD_REPLY: Reply to comment
ADD_COMMENT: Add a comment
AKISMET: Akismet
AKISMET_KEY_API: Akismet API Key
AKISMET_SITE_OVERRIDE: Akismet Site Override
DELETE_COMMENT: Delete comment
REPLY: Reply
DELETE: Delete
SUCCESS: "Comment has been saved successfully."
COMMENTS: Comments
COMMENTS_NESTED: Nested Comments
COMMENTS_NONE: There are no comments yet.
COMMENTS_PINGBACKS: Pingbacks
COMMENTS_STATS: Comments
RECENT_COMMENTS: Recent comments
RECENT_PAGES: Commented pages
EMAIL_NOT_CONFIGURED: Email not configured
NEW_COMMENT_EMAIL_SUBJECT: 'New comment on %1$s'
NEW_COMMENT_EMAIL_BODY: '<p>A new comment was made on %1$s by %3$s (%4$s).</p><p>Page: %2$s</p><p>Text: %5$s</p>'

View File

@ -0,0 +1,37 @@
<form id="comments-form" name="{{ grav.config.plugins.comments.form.name }}" class="comments-form"
action="{{ grav.config.plugins.comments.form.action ? base_url ~ grav.config.plugins.comments.form.action : page.url }}"
method="{{ grav.config.plugins.comments.form.method|upper|default('POST') }}">
{% for field in grav.config.plugins.comments.form.fields %}
{% set value = form.value(field.name) %}
{% if field.evaluateDefault %}
{% set value = evaluate(field.evaluateDefault) %}
{% endif %}
{% if config.plugins.login.enabled and grav.user.authenticated %}
{% if field.name == 'name' %}
<input type="hidden" name="{{ (scope ~ field.name)|fieldName }}" value="{{grav.user.fullname}}">
{% elseif field.name == 'email' %}
<input type="hidden" name="{{ (scope ~ field.name)|fieldName }}" value="{{grav.user.email}}">
{% else %}
<div>
{% include "forms/fields/#{field.type}/#{field.type}.html.twig" %}
</div>
{% endif %}
{% else %}
<div>
{% include "forms/fields/#{field.type}/#{field.type}.html.twig" %}
</div>
{% endif %}
{% endfor %}
{% include "forms/fields/formname/formname.html.twig" %}
<div class="buttons">
{% for button in grav.config.plugins.comments.form.buttons %}
<button class="button" type="{{ button.type|default('submit') }}">{{ button.value|t|default('Submit') }}</button>
{% endfor %}
</div>
{{ nonce_field('comments', 'form-nonce')|raw }}
</form>
<div id="comments-alert" class="alert">{{ form.message }}</div>

View File

@ -1,135 +1,67 @@
{% if grav.twig.enable_comments_plugin %}
{% set scope = scope ?: 'data.' %}
<section id="comments-section">
<h2>{{'PLUGIN_COMMENTS.COMMENTS'|t}}</h2>
{% if grav.twig.pingbacks_enabled %}
{% if grav.twig.pingbacks|length %}
{% set comments_visible = false %}
{% for pingback in grav.twig.pingbacks %}
{% if pingback.approved == "true" %}
{% set comments_visible = true %}
{% endif %}
{% endfor %}
{% if comments_visible %}
<h3>{{'PLUGIN_COMMENTS.COMMENTS_PINGBACKS'|t}}</h3>
<table>
{% for pingback in grav.twig.pingbacks %}
{% if pingback.approved == "true" %}
<tr>
<td>
<article id="pingback-{{loop.index0}}" class="pingback" itemtype="http://schema.org/UserComments">
<header class="pingback-meta">
<span class="pingback-author" itemprop="author" itemscope itemtype="http://schema.org/Person">
{{'PLUGIN_COMMENTS.BY'|t}}
<span itemprop="name">
{% if pingback.site %}
<a href="{{pingback.site}}">{{pingback.author}}</a>
{% else %}
{{pingback.author}}
{% endif %}
</span>
</span>
<a href="{{uri.url(true)}}#pingback-{{loop.index0}}" title="Link to this pingback" itemprop="url">
<time class="pingback-date" datetime="{{pingback.date|e}}" itemprop="commentTime">
{{pingback.date|nicetime(false)}}
</time>
</a>
</header>
<div class="pingback-content" itemprop="commentText">
{{pingback.text}}
</div>
</article>
</td>
</tr>
{% endif %}
{% endfor %}
</table
{% endif %}
</table>
{% if grav.twig.commenting_enabled %}
<a class="comment-add-new" href="#"><i class="fa fa-plus" title="{{'PLUGIN_COMMENTS.ADD_NEW'|t}}"></i> {{'PLUGIN_COMMENTS.ADD_NEW'|t}}</a>
{% endif %}
{% endif %}
{% if grav.twig.commenting_enabled %}
<h3>{{'PLUGIN_COMMENTS.ADD_COMMENT'|t}}</h3>
{% include 'partials/comments.form.html.twig' %}
<form name="{{ grav.config.plugins.comments.form.name }}"
action="{{ grav.config.plugins.comments.form.action ? base_url ~ grav.config.plugins.comments.form.action : page.url }}"
method="{{ grav.config.plugins.comments.form.method|upper|default('POST') }}">
{% for field in grav.config.plugins.comments.form.fields %}
{% set value = form.value(field.name) %}
{% if field.evaluateDefault %}
{% set value = evaluate(field.evaluateDefault) %}
{% endif %}
{% if config.plugins.login.enabled and grav.user.authenticated %}
{% if field.name == 'name' %}
<input type="hidden" name="{{ (scope ~ field.name)|fieldName }}" value="{{grav.user.fullname}}">
{% elseif field.name == 'email' %}
<input type="hidden" name="{{ (scope ~ field.name)|fieldName }}" value="{{grav.user.email}}">
{% else %}
<div>
{% include "forms/fields/#{field.type}/#{field.type}.html.twig" %}
</div>
{% endif %}
{% else %}
<div>
{% include "forms/fields/#{field.type}/#{field.type}.html.twig" %}
</div>
{% endif %}
{% endfor %}
{% include "forms/fields/formname/formname.html.twig" %}
<div class="buttons">
{% for button in grav.config.plugins.comments.form.buttons %}
<button class="button" type="{{ button.type|default('submit') }}">{{ button.value|t|default('Submit') }}</button>
{% endfor %}
</div>
{{ nonce_field('form', 'form-nonce')|raw }}
</form>
<div class="alert">{{ form.message }}</div>
{% endif %}
{% if grav.twig.comments|length %}
<h3>{{'PLUGIN_COMMENTS.COMMENTS'|t}}</h3>
<table class="comments">
{% set comments_visible = false %}
{% for comment in grav.twig.comments %}
{% if comment.approved == "true" %}
{% set comments_visible = true %}
<tr>
<td>
<article id="comment-{{loop.index0}}" class="comment" itemtype="http://schema.org/UserComments">
<header class="comment-meta">
<span class="comment-author" itemprop="author" itemscope itemtype="http://schema.org/Person">
<img class="comment-avatar" itemprop="image" src="https://www.gravatar.com/avatar/{{comment.email|ltrim()|rtrim()|md5}}?size=30&d=identicon">
{{'PLUGIN_COMMENTS.BY'|t}}
<span itemprop="name">
{% if comment.site %}
<a href="{{comment.site}}">{{comment.author}}</a>
{% else %}
{{comment.author}}
{% endif %}
</span>
</span>
<a href="{{uri.url(true)}}#comment-{{loop.index0}}" title="Link to this comment" itemprop="url">
<div id="comments" class="row comments">
{% if grav.twig.comments|length %}
{% set comments_visible = false %}
{% for comment in grav.twig.comments %}
{% if comment.approved == "true" %}
<div class="comment-wrapper">
{% set comments_visible = true %}
{% for level in range(0, comment.level|e) %}
{% if level == comment.level|e %}
<div id="thread-{{level}}" class="comment-thread-top comment-thread">
</div>
{% else %}
<div id="thread-{{level}}" class="comment-thread">
</div>
{% endif %}
{% endfor %}
<div id="comment-{{comment.id}}" class="comment comment-level-{{comment.level|e}}" data-id="{{comment.id}}" itemtype="http://schema.org/UserComments">
<header class="comment-heading">
<img class="comment-avatar" src="https://www.gravatar.com/avatar/{{comment.email|trim|lower|md5}}?size=20&d=identicon" alt="user icon">
<span class="comment-meta">
{% if comment.site %}
<a href="{{comment.site}}">{{comment.author}}</a>
{% else %}
{{comment.author}}
{% endif %}
<a href="{{uri.url(true)}}#comment-{{comment.id}}" title="Link to this comment" itemprop="url">
<time class="comment-date" datetime="{{comment.date|e}}" itemprop="commentTime">
{{comment.date|nicetime(false)}}
</time>
</a>
</span>
</header>
<div class="comment-content" itemprop="commentText">
{{comment.text}}
<div class="comment-body">
<div class="comment-text" >
{{comment.text}}
</div>
{{nested}}
<div class="comment-footer">
<span class="comment-reply">
{% if grav.twig.commenting_enabled %}
<a class="comment-add-reply" href="#"><i class="fa fa-reply" title="{{'PLUGIN_COMMENTS.ADD_REPLY'|t}}"></i> {{'PLUGIN_COMMENTS.REPLY'|t}}</a>
{% endif %}
{% if grav.user.access.admin.super %}
<a class="comment-delete" href="#"><i class="fa fa-trash" title="{{'PLUGIN_COMMENTS.DELETE_COMMENT'|t}}"></i> {{'PLUGIN_COMMENTS.DELETE'|t}}</a>
{% endif %}
</span>
</div>
</div>
</article>
</td>
</tr>
{% endif %}
{% endfor %}
</div>
</div>
{% endif %}
{% endfor %}
{% endif %}
{% if not comments_visible %}
<tr>
@ -138,6 +70,6 @@
</td>
</tr>
{% endif %}
</table>
{% endif %}
</div>
</section>
{% endif %}

View File

@ -0,0 +1,54 @@
{# you may set options when using this partial. Example: include 'partials/recentcomments.html.twig' with {'limit': 5, 'pages_limit': 3} #}
{% if grav.twig.enable_comments_plugin %}
<h1>{{'PLUGIN_COMMENTS.COMMENTS_STATS'|t}}</h1>
{% set stats = recent_comments(limit|default(5), pages_limit|default(3)) %}
{% if stats.global_stats.active_entries %}
<i class="fa fa-comments" title="active_entries"></i> {{stats.global_stats.active_entries}}
(<i class="fa fa-trash" title="deleted_entries"></i> {{stats.global_stats.deleted_entries}})
- <i class="fa fa-comment" title="active_comments"></i>{{stats.global_stats.active_comments}}
(<i class="fa fa-trash" title="deleted_comments"></i> {{stats.global_stats.deleted_comments}})
- <i class="fa fa-commenting" title="active_replies"></i>{{stats.global_stats.active_replies}}
(<i class="fa fa-trash" title="deleted_replies"></i> {{stats.global_stats.deleted_replies}})
- <i class="fa fa-files-o" title="pages_with_active_entries"></i> {{stats.global_stats.pages_with_active_entries}}
{% endif %}
{% for key, entry in stats.pages %}
{% if loop.first %}
<h2>{{'PLUGIN_COMMENTS.RECENT_PAGES'|t}} (limit {{stats.options.pages_limit}})</h2>
<ul class="fa-ul">
{% endif %}
<li><i class="fa-li fa fa-file" title="{{entry.route}}"></i>
{% if entry.route %}
<a href="{{entry.route}}#comments">
{% endif %}
{{entry.active_entries}}
{% if entry.route %}
</a>
{% endif %}
</li>
{% if loop.last %}
</ul>
{% endif %}
{% endfor %}
{% for key, entry in stats.comments %}
{% if loop.first %}
<h2>{{'PLUGIN_COMMENTS.RECENT_COMMENTS'|t}} (limit {{stats.options.comments_limit}})</h2>
<ul class="fa-ul">
{% endif %}
{% set entry_icon = 'fa-comment' %}
{% if not empty(entry.parent) %}
{% set entry_icon = 'fa-commenting' %}
{% endif %}
<li><i class="fa-li fa {{entry_icon}}" title="{{key}}: {{entry.id}}, {{entry.parent}}"></i>
{% if entry.route %}
<a href="{{entry.route}}#comments">
{% endif %}
{{entry.date}}, {{entry.author}}, {{entry.text|truncate(15)}}
{% if entry.route %}
</a>
{% endif %}
</li>
{% if loop.last %}
</ul>
{% endif %}
{% endfor %}
{% endif %}