1
0
mirror of https://github.com/BookStackApp/BookStack.git synced 2025-08-09 10:22:51 +03:00

Merge branch 'master' of git://github.com/Abijeet/BookStack into Abijeet-master

This commit is contained in:
Dan Brown
2017-08-01 19:24:33 +01:00
42 changed files with 1420 additions and 11 deletions

View File

@@ -675,4 +675,225 @@ module.exports = function (ngApp, events) {
}]);
// Controller used to reply to and add new comments
ngApp.controller('CommentReplyController', ['$scope', '$http', '$timeout', function ($scope, $http, $timeout) {
const MarkdownIt = require("markdown-it");
const md = new MarkdownIt({html: true});
let vm = this;
vm.saveComment = function () {
let pageId = $scope.comment.pageId || $scope.pageId;
let comment = $scope.comment.text;
if (!comment) {
return events.emit('warning', trans('errors.empty_comment'));
}
let commentHTML = md.render($scope.comment.text);
let serviceUrl = `/ajax/page/${pageId}/comment/`;
let httpMethod = 'post';
let reqObj = {
text: comment,
html: commentHTML
};
if ($scope.isEdit === true) {
// this will be set when editing the comment.
serviceUrl = `/ajax/page/${pageId}/comment/${$scope.comment.id}`;
httpMethod = 'put';
} else if ($scope.isReply === true) {
// if its reply, get the parent comment id
reqObj.parent_id = $scope.parentId;
}
$http[httpMethod](window.baseUrl(serviceUrl), reqObj).then(resp => {
if (!isCommentOpSuccess(resp)) {
return;
}
// hide the comments first, and then retrigger the refresh
if ($scope.isEdit) {
updateComment($scope.comment, resp.data);
$scope.$emit('evt.comment-success', $scope.comment.id);
} else {
$scope.comment.text = '';
if ($scope.isReply === true && $scope.parent.sub_comments) {
$scope.parent.sub_comments.push(resp.data.comment);
} else {
$scope.$emit('evt.new-comment', resp.data.comment);
}
$scope.$emit('evt.comment-success', null, true);
}
$scope.comment.is_hidden = true;
$timeout(function() {
$scope.comment.is_hidden = false;
});
events.emit('success', trans(resp.data.message));
}, checkError);
};
function checkError(response) {
let msg = null;
if (isCommentOpSuccess(response)) {
// all good
return;
} else if (response.data) {
msg = response.data.message;
} else {
msg = trans('errors.comment_add');
}
if (msg) {
events.emit('success', msg);
}
}
}]);
// Controller used to delete comments
ngApp.controller('CommentDeleteController', ['$scope', '$http', '$timeout', function ($scope, $http, $timeout) {
let vm = this;
vm.delete = function(comment) {
$http.delete(window.baseUrl(`/ajax/comment/${comment.id}`)).then(resp => {
if (!isCommentOpSuccess(resp)) {
return;
}
updateComment(comment, resp.data, $timeout, true);
}, function (resp) {
if (isCommentOpSuccess(resp)) {
events.emit('success', trans('entities.comment_deleted'));
} else {
events.emit('error', trans('error.comment_delete'));
}
});
};
}]);
// Controller used to fetch all comments for a page
ngApp.controller('CommentListController', ['$scope', '$http', '$timeout', '$location', function ($scope, $http, $timeout, $location) {
let vm = this;
$scope.errors = {};
// keep track of comment levels
$scope.level = 1;
vm.totalCommentsStr = trans('entities.comments_loading');
vm.permissions = {};
vm.trans = window.trans;
$scope.$on('evt.new-comment', function (event, comment) {
// add the comment to the comment list.
vm.comments.push(comment);
++vm.totalComments;
setTotalCommentMsg();
event.stopPropagation();
event.preventDefault();
});
vm.canEditDelete = function (comment, prop) {
if (!comment.active) {
return false;
}
let propAll = prop + '_all';
let propOwn = prop + '_own';
if (vm.permissions[propAll]) {
return true;
}
if (vm.permissions[propOwn] && comment.created_by.id === vm.current_user_id) {
return true;
}
return false;
};
vm.canComment = function () {
return vm.permissions.comment_create;
};
// check if there are is any direct linking
let linkedCommentId = $location.search().cm;
$timeout(function() {
$http.get(window.baseUrl(`/ajax/page/${$scope.pageId}/comments/`)).then(resp => {
if (!isCommentOpSuccess(resp)) {
// just show that no comments are available.
vm.totalComments = 0;
setTotalCommentMsg();
return;
}
vm.comments = resp.data.comments;
vm.totalComments = +resp.data.total;
vm.permissions = resp.data.permissions;
vm.current_user_id = resp.data.user_id;
setTotalCommentMsg();
if (!linkedCommentId) {
return;
}
$timeout(function() {
// wait for the UI to render.
focusLinkedComment(linkedCommentId);
});
}, checkError);
});
function setTotalCommentMsg () {
if (vm.totalComments === 0) {
vm.totalCommentsStr = trans('entities.no_comments');
} else if (vm.totalComments === 1) {
vm.totalCommentsStr = trans('entities.one_comment');
} else {
vm.totalCommentsStr = trans('entities.x_comments', {
numComments: vm.totalComments
});
}
}
function focusLinkedComment(linkedCommentId) {
let comment = angular.element('#' + linkedCommentId);
if (comment.length === 0) {
return;
}
window.setupPageShow.goToText(linkedCommentId);
}
function checkError(response) {
let msg = null;
if (isCommentOpSuccess(response)) {
// all good
return;
} else if (response.data) {
msg = response.data.message;
} else {
msg = trans('errors.comment_list');
}
if (msg) {
events.emit('success', msg);
}
}
}]);
function updateComment(comment, resp, $timeout, isDelete) {
comment.text = resp.comment.text;
comment.updated = resp.comment.updated;
comment.updated_by = resp.comment.updated_by;
comment.active = resp.comment.active;
if (isDelete && !resp.comment.active) {
comment.html = trans('entities.comment_deleted');
} else {
comment.html = resp.comment.html;
}
if (!$timeout) {
return;
}
comment.is_hidden = true;
$timeout(function() {
comment.is_hidden = false;
});
}
function isCommentOpSuccess(resp) {
if (resp && resp.data && resp.data.status === 'success') {
return true;
}
return false;
}
};

View File

@@ -863,4 +863,128 @@ module.exports = function (ngApp, events) {
}
};
}]);
ngApp.directive('commentReply', [function () {
return {
restrict: 'E',
templateUrl: 'comment-reply.html',
scope: {
pageId: '=',
parentId: '=',
parent: '='
},
link: function (scope, element) {
scope.isReply = true;
element.find('textarea').focus();
scope.$on('evt.comment-success', function (event) {
// no need for the event to do anything more.
event.stopPropagation();
event.preventDefault();
scope.closeBox();
});
scope.closeBox = function () {
element.remove();
scope.$destroy();
};
}
};
}]);
ngApp.directive('commentEdit', [function () {
return {
restrict: 'E',
templateUrl: 'comment-reply.html',
scope: {
comment: '='
},
link: function (scope, element) {
scope.isEdit = true;
element.find('textarea').focus();
scope.$on('evt.comment-success', function (event, commentId) {
// no need for the event to do anything more.
event.stopPropagation();
event.preventDefault();
if (commentId === scope.comment.id && !scope.isNew) {
scope.closeBox();
}
});
scope.closeBox = function () {
element.remove();
scope.$destroy();
};
}
};
}]);
ngApp.directive('commentReplyLink', ['$document', '$compile', function ($document, $compile) {
return {
scope: {
comment: '='
},
link: function (scope, element, attr) {
element.on('$destroy', function () {
element.off('click');
scope.$destroy();
});
element.on('click', function (e) {
e.preventDefault();
var $container = element.parents('.comment-actions').first();
if (!$container.length) {
console.error('commentReplyLink directive should be placed inside a container with class comment-box!');
return;
}
if (attr.noCommentReplyDupe) {
removeDupe();
}
compileHtml($container, scope, attr.isReply === 'true');
});
}
};
function compileHtml($container, scope, isReply) {
let lnkFunc = null;
if (isReply) {
lnkFunc = $compile('<comment-reply page-id="comment.pageId" parent-id="comment.id" parent="comment"></comment-reply>');
} else {
lnkFunc = $compile('<comment-edit comment="comment"></comment-add>');
}
var compiledHTML = lnkFunc(scope);
$container.append(compiledHTML);
}
function removeDupe() {
let $existingElement = $document.find('.comments-list comment-reply, .comments-list comment-edit');
if (!$existingElement.length) {
return;
}
$existingElement.remove();
}
}]);
ngApp.directive('commentDeleteLink', ['$window', function ($window) {
return {
controller: 'CommentDeleteController',
scope: {
comment: '='
},
link: function (scope, element, attr, ctrl) {
element.on('click', function(e) {
e.preventDefault();
var resp = $window.confirm(trans('entities.comment_delete_confirm'));
if (!resp) {
return;
}
ctrl.delete(scope.comment);
});
}
};
}]);
};

View File

@@ -161,6 +161,8 @@ let setupPageShow = window.setupPageShow = function (pageId) {
}
});
// in order to call from other places.
window.setupPageShow.goToText = goToText;
};
module.exports = setupPageShow;

View File

@@ -0,0 +1,82 @@
.comments-list {
.comment-box {
border-bottom: 1px solid $comment-border;
}
.comment-box:last-child {
border-bottom: 0px;
}
}
.page-comment {
.comment-container {
margin-left: 42px;
}
.comment-actions {
font-size: 0.8em;
padding-bottom: 2px;
ul {
padding-left: 0px;
margin-bottom: 2px;
}
li {
float: left;
list-style-type: none;
}
li:after {
content: '';
color: #707070;
padding: 0 5px;
font-size: 1em;
}
li:last-child:after {
content: none;
}
}
.comment-actions {
border-bottom: 1px solid #DDD;
}
.comment-actions:last-child {
border-bottom: 0px;
}
.comment-header {
font-size: 1.25em;
margin-top: 0.6em;
}
.comment-body p {
margin-bottom: 1em;
}
.comment-inactive {
font-style: italic;
font-size: 0.85em;
padding-top: 5px;
}
.user-image {
float: left;
margin-right: 10px;
width: 32px;
img {
width: 100%;
}
}
}
.comment-editor {
margin-top: 2em;
textarea {
display: block;
width: 100%;
max-width: 100%;
min-height: 120px;
}
}

View File

@@ -310,4 +310,8 @@
background-color: #EEE;
}
}
}
.comment-editor .CodeMirror, .comment-editor .CodeMirror-scroll {
min-height: 175px;
}

View File

@@ -56,3 +56,6 @@ $text-light: #EEE;
$bs-light: 0 0 4px 1px #CCC;
$bs-med: 0 1px 3px 1px rgba(76, 76, 76, 0.26);
$bs-hover: 0 2px 2px 1px rgba(0,0,0,.13);
// comments
$comment-border: #DDD;

View File

@@ -10,6 +10,7 @@
@import "header";
@import "lists";
@import "pages";
@import "comments";
table {
border-spacing: 0;

View File

@@ -16,6 +16,7 @@
@import "header";
@import "lists";
@import "pages";
@import "comments";
[v-cloak], [v-show] {
display: none; opacity: 0;

View File

@@ -213,4 +213,27 @@ return [
'profile_not_created_pages' => ':userName hat bisher keine Seiten angelegt.',
'profile_not_created_chapters' => ':userName hat bisher keine Kapitel angelegt.',
'profile_not_created_books' => ':userName hat bisher keine B&uuml;cher angelegt.',
/**
* Comnents
*/
'comment' => 'Kommentar',
'comments' => 'Kommentare',
'comment_placeholder' => 'Geben Sie hier Ihre Kommentare ein, Markdown unterstützt ...',
'no_comments' => 'Keine Kommentare',
'x_comments' => ':numComments Kommentare',
'one_comment' => '1 Kommentar',
'comments_loading' => 'Laden ...',
'comment_save' => 'Kommentar speichern',
'comment_reply' => 'Antworten',
'comment_edit' => 'Bearbeiten',
'comment_delete' => 'Löschen',
'comment_cancel' => 'Abbrechen',
'comment_created' => 'Kommentar hinzugefügt',
'comment_updated' => 'Kommentar aktualisiert',
'comment_deleted' => 'Kommentar gelöscht',
'comment_updated_text' => 'Aktualisiert vor :updateDiff von',
'comment_delete_confirm' => 'Damit wird der Inhalt des Kommentars entfernt. Bist du sicher, dass du diesen Kommentar löschen möchtest?',
'comment_create' => 'Erstellt'
];

View File

@@ -67,4 +67,11 @@ return [
'error_occurred' => 'Es ist ein Fehler aufgetreten',
'app_down' => ':appName befindet sich aktuell im Wartungsmodus.',
'back_soon' => 'Wir werden so schnell wie m&ouml;glich wieder online sein.',
// Comments
'comment_list' => 'Beim Abrufen der Kommentare ist ein Fehler aufgetreten.',
'cannot_add_comment_to_draft' => 'Du kannst keine Kommentare zu einem Entwurf hinzufügen.',
'comment_add' => 'Beim Hinzufügen des Kommentars ist ein Fehler aufgetreten.',
'comment_delete' => 'Beim Löschen des Kommentars ist ein Fehler aufgetreten.',
'empty_comment' => 'Kann keinen leeren Kommentar hinzufügen',
];

View File

@@ -234,4 +234,27 @@ return [
'profile_not_created_pages' => ':userName has not created any pages',
'profile_not_created_chapters' => ':userName has not created any chapters',
'profile_not_created_books' => ':userName has not created any books',
/**
* Comments
*/
'comment' => 'Comment',
'comments' => 'Comments',
'comment_placeholder' => 'Enter your comments here, markdown supported...',
'no_comments' => 'No Comments',
'x_comments' => ':numComments Comments',
'one_comment' => '1 Comment',
'comments_loading' => 'Loading...',
'comment_save' => 'Save Comment',
'comment_reply' => 'Reply',
'comment_edit' => 'Edit',
'comment_delete' => 'Delete',
'comment_cancel' => 'Cancel',
'comment_created' => 'Comment added',
'comment_updated' => 'Comment updated',
'comment_deleted' => 'Comment deleted',
'comment_updated_text' => 'Updated :updateDiff by',
'comment_delete_confirm' => 'This will remove the contents of the comment. Are you sure you want to delete this comment?',
'comment_create' => 'Created'
];

View File

@@ -60,6 +60,13 @@ return [
'role_system_cannot_be_deleted' => 'This role is a system role and cannot be deleted',
'role_registration_default_cannot_delete' => 'This role cannot be deleted while set as the default registration role',
// Comments
'comment_list' => 'An error occurred while fetching the comments.',
'cannot_add_comment_to_draft' => 'You cannot add comments to a draft.',
'comment_add' => 'An error occurred while adding the comment.',
'comment_delete' => 'An error occurred while deleting the comment.',
'empty_comment' => 'Cannot add an empty comment.',
// Error pages
'404_page_not_found' => 'Page Not Found',
'sorry_page_not_found' => 'Sorry, The page you were looking for could not be found.',

View File

@@ -214,4 +214,26 @@ return [
'profile_not_created_pages' => ':userName no ha creado ninguna página',
'profile_not_created_chapters' => ':userName no ha creado ningún capítulo',
'profile_not_created_books' => ':userName no ha creado ningún libro',
/**
* Comments
*/
'comment' => 'Comentario',
'comments' => 'Comentarios',
'comment_placeholder' => 'Introduzca sus comentarios aquí, markdown supported ...',
'no_comments' => 'No hay comentarios',
'x_comments' => ':numComments Comentarios',
'one_comment' => '1 Comentario',
'comments_loading' => 'Cargando ...',
'comment_save' => 'Guardar comentario',
'comment_reply' => 'Responder',
'comment_edit' => 'Editar',
'comment_delete' => 'Eliminar',
'comment_cancel' => 'Cancelar',
'comment_created' => 'Comentario añadido',
'comment_updated' => 'Comentario actualizado',
'comment_deleted' => 'Comentario eliminado',
'comment_updated_text' => 'Actualizado hace :updateDiff por',
'comment_delete_confirm' => 'Esto eliminará el contenido del comentario. ¿Estás seguro de que quieres eliminar este comentario?',
'comment_create' => 'Creado'
];

View File

@@ -67,4 +67,11 @@ return [
'error_occurred' => 'Ha ocurrido un error',
'app_down' => 'La aplicación :appName se encuentra caída en este momento',
'back_soon' => 'Volverá a estar operativa en corto tiempo.',
// Comments
'comment_list' => 'Se ha producido un error al buscar los comentarios.',
'cannot_add_comment_to_draft' => 'No puedes añadir comentarios a un borrador.',
'comment_add' => 'Se ha producido un error al añadir el comentario.',
'comment_delete' => 'Se ha producido un error al eliminar el comentario.',
'empty_comment' => 'No se puede agregar un comentario vacío.',
];

View File

@@ -213,4 +213,26 @@ return [
'profile_not_created_pages' => ':userName n\'a pas créé de page',
'profile_not_created_chapters' => ':userName n\'a pas créé de chapitre',
'profile_not_created_books' => ':userName n\'a pas créé de livre',
/**
* Comments
*/
'comment' => 'Commentaire',
'comments' => 'Commentaires',
'comment_placeholder' => 'Entrez vos commentaires ici, merci supporté ...',
'no_comments' => 'No Comments',
'x_comments' => ':numComments Commentaires',
'one_comment' => '1 Commentaire',
'comments_loading' => 'Loading ...',
'comment_save' => 'Enregistrer le commentaire',
'comment_reply' => 'Répondre',
'comment_edit' => 'Modifier',
'comment_delete' => 'Supprimer',
'comment_cancel' => 'Annuler',
'comment_created' => 'Commentaire ajouté',
'comment_updated' => 'Commentaire mis à jour',
'comment_deleted' => 'Commentaire supprimé',
'comment_updated_text' => 'Mis à jour il y a :updateDiff par',
'comment_delete_confirm' => 'Cela supprime le contenu du commentaire. Êtes-vous sûr de vouloir supprimer ce commentaire?',
'comment_create' => 'Créé'
];

View File

@@ -67,4 +67,11 @@ return [
'error_occurred' => 'Une erreur est survenue',
'app_down' => ':appName n\'est pas en service pour le moment',
'back_soon' => 'Nous serons bientôt de retour.',
// comments
'comment_list' => 'Une erreur s\'est produite lors de la récupération des commentaires.',
'cannot_add_comment_to_draft' => 'Vous ne pouvez pas ajouter de commentaires à un projet.',
'comment_add' => 'Une erreur s\'est produite lors de l\'ajout du commentaire.',
'comment_delete' => 'Une erreur s\'est produite lors de la suppression du commentaire.',
'empty_comment' => 'Impossible d\'ajouter un commentaire vide.',
];

View File

@@ -214,4 +214,26 @@ return [
'profile_not_created_pages' => ':userName heeft geen pagina\'s gemaakt',
'profile_not_created_chapters' => ':userName heeft geen hoofdstukken gemaakt',
'profile_not_created_books' => ':userName heeft geen boeken gemaakt',
/**
* Comments
*/
'comment' => 'Commentaar',
'comments' => 'Commentaren',
'comment_placeholder' => 'Vul hier uw reacties in, markdown ondersteund ...',
'no_comments' => 'No Comments',
'x_comments' => ':numComments Opmerkingen',
'one_comment' => '1 commentaar',
'comments_loading' => 'Loading ...',
'comment_save' => 'Opslaan opslaan',
'comment_reply' => 'Antwoord',
'comment_edit' => 'Bewerken',
'comment_delete' => 'Verwijderen',
'comment_cancel' => 'Annuleren',
'comment_created' => 'Opmerking toegevoegd',
'comment_updated' => 'Opmerking bijgewerkt',
'comment_deleted' => 'Opmerking verwijderd',
'comment_updated_text' => 'Bijgewerkt :updateDiff geleden door',
'comment_delete_confirm' => 'Hiermee verwijdert u de inhoud van de reactie. Weet u zeker dat u deze reactie wilt verwijderen?',
'comment_create' => 'Gemaakt'
];

View File

@@ -67,4 +67,11 @@ return [
'error_occurred' => 'Er Ging Iets Fout',
'app_down' => ':appName is nu niet beschikbaar',
'back_soon' => 'Komt snel weer online.',
// Comments
'comment_list' => 'Er is een fout opgetreden tijdens het ophalen van de reacties.',
'cannot_add_comment_to_draft' => 'U kunt geen reacties toevoegen aan een ontwerp.',
'comment_add' => 'Er is een fout opgetreden tijdens het toevoegen van de reactie.',
'comment_delete' => 'Er is een fout opgetreden tijdens het verwijderen van de reactie.',
'empty_comment' => 'Kan geen lege reactie toevoegen.',
];

View File

@@ -214,4 +214,26 @@ return [
'profile_not_created_pages' => ':userName não criou páginas',
'profile_not_created_chapters' => ':userName não criou capítulos',
'profile_not_created_books' => ':userName não criou livros',
/**
* Comments
*/
'comentário' => 'Comentário',
'comentários' => 'Comentários',
'comment_placeholder' => 'Digite seus comentários aqui, markdown suportado ...',
'no_comments' => 'No Comments',
'x_comments' => ':numComments Comentários',
'one_comment' => '1 comentário',
'comments_loading' => 'Carregando ....',
'comment_save' => 'Salvar comentário',
'comment_reply' => 'Responder',
'comment_edit' => 'Editar',
'comment_delete' => 'Excluir',
'comment_cancel' => 'Cancelar',
'comment_created' => 'Comentário adicionado',
'comment_updated' => 'Comentário atualizado',
'comment_deleted' => 'Comentário eliminado',
'comment_updated_text' => 'Atualizado :updatedDiff atrás por',
'comment_delete_confirm' => 'Isso removerá o conteúdo do comentário. Tem certeza de que deseja excluir esse comentário?',
'comment_create' => 'Criada'
];

View File

@@ -67,4 +67,11 @@ return [
'error_occurred' => 'Um erro ocorreu',
'app_down' => ':appName está fora do ar no momento',
'back_soon' => 'Voltaremos em seguida.',
// comments
'comment_list' => 'Ocorreu um erro ao buscar os comentários.',
'cannot_add_comment_to_draft' => 'Você não pode adicionar comentários a um rascunho.',
'comment_add' => 'Ocorreu um erro ao adicionar o comentário.',
'comment_delete' => 'Ocorreu um erro ao excluir o comentário.',
'empty_comment' => 'Não é possível adicionar um comentário vazio.',
];

View File

@@ -223,4 +223,26 @@ return [
'profile_not_created_pages' => ':userName nevytvoril žiadne stránky',
'profile_not_created_chapters' => ':userName nevytvoril žiadne kapitoly',
'profile_not_created_books' => ':userName nevytvoril žiadne knihy',
/**
* Comments
*/
'comment' => 'Komentár',
'comments' => 'Komentáre',
'comment_placeholder' => 'Tu zadajte svoje pripomienky, podporované označenie ...',
'no_comments' => 'No Comments',
'x_comments' => ':numComments komentárov',
'one_comment' => '1 komentár',
'comments_loading' => 'Loading ..',
'comment_save' => 'Uložiť komentár',
'comment_reply' => 'Odpovedať',
'comment_edit' => 'Upraviť',
'comment_delete' => 'Odstrániť',
'comment_cancel' => 'Zrušiť',
'comment_created' => 'Pridaný komentár',
'comment_updated' => 'Komentár aktualizovaný',
'comment_deleted' => 'Komentár bol odstránený',
'comment_updated_text' => 'Aktualizované pred :updateDiff',
'comment_delete_confirm' => 'Tým sa odstráni obsah komentára. Naozaj chcete odstrániť tento komentár?',
'comment_create' => 'Vytvorené'
];

View File

@@ -67,4 +67,11 @@ return [
'error_occurred' => 'Nastala chyba',
'app_down' => ':appName je momentálne nedostupná',
'back_soon' => 'Čoskoro bude opäť dostupná.',
// comments
'comment_list' => 'Pri načítaní komentárov sa vyskytla chyba',
'cannot_add_comment_to_draft' => 'Do konceptu nemôžete pridávať komentáre.',
'comment_add' => 'Počas pridávania komentára sa vyskytla chyba',
'comment_delete' => 'Pri odstraňovaní komentára došlo k chybe',
'empty_comment' => 'Nelze pridať prázdny komentár.',
];

View File

@@ -0,0 +1,12 @@
<div class="comment-editor" ng-controller="CommentReplyController as vm" ng-cloak>
<form novalidate>
<textarea name="markdown" rows="3" ng-model="comment.text" placeholder="{{ trans('entities.comment_placeholder') }}"></textarea>
<input type="hidden" ng-model="comment.pageId" name="comment.pageId" value="{{$pageId}}" ng-init="comment.pageId = {{$pageId }}">
<button type="button" ng-if="::(isReply || isEdit)" class="button muted" ng-click="closeBox()">{{ trans('entities.comment_cancel') }}</button>
<button type="submit" class="button pos" ng-click="vm.saveComment()">{{ trans('entities.comment_save') }}</button>
</form>
</div>
@if($errors->has('markdown'))
<div class="text-neg text-small">{{ $errors->first('markdown') }}</div>
@endif

View File

@@ -0,0 +1,18 @@
<script type="text/ng-template" id="comment-list-item.html">
@include('comments/list-item')
</script>
<script type="text/ng-template" id="comment-reply.html">
@include('comments/comment-reply', ['pageId' => $pageId])
</script>
<div ng-controller="CommentListController as vm" ng-init="pageId = <?= $page->id ?>" class="comments-list" ng-cloak>
<h3>@{{vm.totalCommentsStr}}</h3>
<hr>
<div class="comment-box" ng-repeat="comment in vm.comments track by comment.id">
<div ng-include src="'comment-list-item.html'">
</div>
</div>
<div ng-if="::vm.canComment()">
@include('comments/comment-reply', ['pageId' => $pageId])
</div>
</div>

View File

@@ -0,0 +1,30 @@
<div class='page-comment' id="comment-@{{::pageId}}-@{{::comment.id}}">
<div class="user-image">
<img ng-src="@{{::comment.created_by.avatar_url}}" alt="user avatar">
</div>
<div class="comment-container">
<div class="comment-header">
<a href="@{{::comment.created_by.profile_url}}">@{{ ::comment.created_by.name }}</a>
</div>
<div ng-bind-html="comment.html" ng-if="::comment.active" class="comment-body" ng-class="!comment.active ? 'comment-inactive' : ''">
</div>
<div ng-if="::!comment.active" class="comment-body comment-inactive">
{{ trans('entities.comment_deleted') }}
</div>
<div class="comment-actions">
<ul ng-if="!comment.is_hidden">
<li ng-if="::(level < 3 && vm.canComment())"><a href="#" comment-reply-link no-comment-reply-dupe="true" comment="comment" is-reply="true">{{ trans('entities.comment_reply') }}</a></li>
<li ng-if="::vm.canEditDelete(comment, 'comment_update')"><a href="#" comment-reply-link no-comment-reply-dupe="true" comment="comment" >{{ trans('entities.comment_edit') }}</a></li>
<li ng-if="::vm.canEditDelete(comment, 'comment_delete')"><a href="#" comment-delete-link comment="comment" >{{ trans('entities.comment_delete') }}</a></li>
<li>{{ trans('entities.comment_create') }} <a title="@{{::comment.created.day_time_str}}" href="#?cm=comment-@{{::pageId}}-@{{::comment.id}}">@{{::comment.created.diff}}</a></li>
<li ng-if="::comment.updated"><span title="@{{::comment.updated.day_time_str}}">@{{ ::vm.trans('entities.comment_updated_text', { updateDiff: comment.updated.diff }) }}
<a href="@{{::comment.updated_by.profile_url}}">@{{::comment.updated_by.name}}</a></span></li>
</ul>
</div>
<div class="comment-box" ng-repeat="comment in comments = comment.sub_comments track by comment.id" ng-init="level = level + 1">
<div ng-include src="'comment-list-item.html'">
</div>
</div>
</div>
</div>

View File

@@ -46,13 +46,13 @@
</div>
<div class="container" id="page-show" ng-non-bindable>
<div class="container" id="page-show">
<div class="row">
<div class="col-md-9 print-full-width">
<div class="page-content">
<div class="page-content" ng-non-bindable>
<div class="pointer-container" id="pointer">
<div class="pointer anim">
<div class="pointer anim" >
<span class="icon text-primary"><i class="zmdi zmdi-link"></i></span>
<input readonly="readonly" type="text" id="pointer-url" placeholder="url">
<button class="button icon" data-clipboard-target="#pointer-url" type="button" title="{{ trans('entities.pages_copy_link') }}"><i class="zmdi zmdi-copy"></i></button>
@@ -66,6 +66,7 @@
@include('partials.entity-meta', ['entity' => $page])
</div>
@include('comments/comments', ['pageId' => $page->id])
</div>
<div class="col-md-3 print-hidden">
@@ -109,7 +110,6 @@
</div>
</div>
@stop
@section('scripts')

View File

@@ -117,6 +117,19 @@
<label>@include('settings/roles/checkbox', ['permission' => 'attachment-delete-all']) {{ trans('settings.role_all') }}</label>
</td>
</tr>
<tr>
<td>{{ trans('entities.comments') }}</td>
<td>@include('settings/roles/checkbox', ['permission' => 'comment-create-all'])</td>
<td style="line-height:1.2;"><small class="faded">{{ trans('settings.role_controlled_by_asset') }}</small></td>
<td>
<label>@include('settings/roles/checkbox', ['permission' => 'comment-update-own']) {{ trans('settings.role_own') }}</label>
<label>@include('settings/roles/checkbox', ['permission' => 'comment-update-all']) {{ trans('settings.role_all') }}</label>
</td>
<td>
<label>@include('settings/roles/checkbox', ['permission' => 'comment-delete-own']) {{ trans('settings.role_own') }}</label>
<label>@include('settings/roles/checkbox', ['permission' => 'comment-delete-all']) {{ trans('settings.role_all') }}</label>
</td>
</tr>
</table>
</div>
</div>