biovision-comment 0.1.170914 → 0.7.190905.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +68 -14
- data/app/assets/javascripts/biovision/comment/biovision-comments.js +118 -0
- data/app/assets/stylesheets/biovision/comment/comments.scss +111 -38
- data/app/controllers/admin/comments_controller.rb +18 -5
- data/app/controllers/comments_controller.rb +45 -32
- data/app/helpers/comments_helper.rb +20 -0
- data/app/models/comment.rb +88 -19
- data/app/models/concerns/commentable_item.rb +15 -0
- data/app/services/biovision/components/comments_component.rb +39 -0
- data/app/services/comment_handler.rb +49 -0
- data/app/services/comments_manager.rb +24 -0
- data/app/views/admin/comments/entity/_in_list.html.erb +8 -5
- data/app/views/admin/comments/index.html.erb +2 -1
- data/app/views/admin/comments/show.html.erb +25 -10
- data/app/views/admin/components/links/_comments.html.erb +3 -0
- data/app/views/comment_mailer/entry_reply.text.erb +2 -6
- data/app/views/comments/_comment.html.erb +66 -16
- data/app/views/comments/_form.html.erb +92 -19
- data/app/views/comments/_list.html.erb +17 -19
- data/app/views/comments/_reply_container.html.erb +15 -0
- data/app/views/comments/_section.html.erb +34 -0
- data/app/views/comments/edit.html.erb +6 -5
- data/app/views/comments/new.html.erb +2 -2
- data/config/locales/comments-ru.yml +32 -2
- data/config/routes.rb +18 -10
- data/db/migrate/20170914000001_create_comments.rb +48 -23
- data/db/migrate/20190203090909_add_fields_to_comments.rb +14 -0
- data/db/migrate/20190428212121_add_approved_to_comments.rb +14 -0
- data/db/migrate/20190428212122_create_comments_component.rb +21 -0
- data/db/migrate/20190628101010_add_data_to_comments.rb +15 -0
- data/lib/biovision/comment/engine.rb +7 -2
- data/lib/biovision/comment/version.rb +3 -1
- metadata +19 -8
- data/app/views/comments/show.html.erb +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a602c3288d543c9a10860099700cb6657f206b3b6dce1b88a82c5ad1c239b5c8
|
4
|
+
data.tar.gz: 552231814a6ad6ed6b43c1edbc12b195192090e2ef821d73b962c1c6cd1850b4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba351318a8b74404e890374ae9c9a1cfab90924d25c10dc0374660fba6b014005e7ce4105ca3f6ce4805939935cbd52fd4517d4cda960057e1e2c23bbbc6badb
|
7
|
+
data.tar.gz: 5272919b6715ef8641f458257d9d35f2638b5c4cb6b593163c1fe44e0e3c5d8da2a265477a205bc338b7bd5625282d9330b7db042de7e1b3556fd04a14ea3a1e
|
data/README.md
CHANGED
@@ -1,28 +1,82 @@
|
|
1
1
|
# Biovision::Comment
|
2
|
-
Short description and motivation.
|
3
2
|
|
4
|
-
|
5
|
-
How to use my plugin.
|
3
|
+
Компонент с комментариями для проектов на базе `Biovision`.
|
6
4
|
|
7
|
-
|
8
|
-
|
5
|
+
Находится в стадии разработки. Используйте на свой страх и риск.
|
6
|
+
|
7
|
+
## Использование
|
8
|
+
|
9
|
+
### Подготовка моделей
|
10
|
+
|
11
|
+
Для моделей, которым нужны комментарии, следует в классе добавить это:
|
9
12
|
|
10
13
|
```ruby
|
11
|
-
|
14
|
+
has_many :comments, as: :commentable
|
12
15
|
```
|
13
16
|
|
14
|
-
|
17
|
+
Тамже всем моделям с комментариями нужно поле `comments_count` для счётчика
|
18
|
+
комментарием:
|
19
|
+
|
15
20
|
```bash
|
16
|
-
|
21
|
+
rails g migration add_comments_count_to_sample comments_count:integer
|
22
|
+
```
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
# frozen_string_literal: true
|
26
|
+
|
27
|
+
# Add counter for comments to Sample model
|
28
|
+
class AddCommentsCountToSample < ActiveRecord::Migration[5.2]
|
29
|
+
def change
|
30
|
+
add_column :samples, :comments_count, :integer, default: 0, null: false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
```
|
34
|
+
|
35
|
+
### В представлениях
|
36
|
+
|
37
|
+
Для вывода комментариев используется код такого вида:
|
38
|
+
|
39
|
+
```erb
|
40
|
+
<%= render(partial: 'comments/section', locals: { entity: entity }) %>
|
41
|
+
```
|
42
|
+
|
43
|
+
Здесь `entity` — это объект модели с комментариями.
|
44
|
+
|
45
|
+
### Стили и сценарии
|
46
|
+
|
47
|
+
Для работы переноса формы ответа нужно включить в сценарии JS код компонента
|
48
|
+
в `application.js` после добавления `biovision/base/biovision`:
|
49
|
+
|
50
|
+
```
|
51
|
+
//= require biovision/comment/biovision-comments
|
17
52
|
```
|
18
53
|
|
19
|
-
|
54
|
+
Стили по умолчанию описаны в `biovision/comment/comments.scss`.
|
55
|
+
|
56
|
+
## Установка
|
57
|
+
|
58
|
+
Нужно добавить компонент в `Gemfile`:
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
gem 'biovision-comment', git: 'https://github.com/Biovision/biovision-comment'
|
62
|
+
# gem 'biovision-comment', path: '/Users/maxim/Projects/Biovision/gems/biovision-comment'
|
63
|
+
```
|
64
|
+
|
65
|
+
После этого:
|
66
|
+
|
20
67
|
```bash
|
21
|
-
$
|
68
|
+
$ bundle
|
69
|
+
$ rails railties:install:migrations
|
70
|
+
$ rails db:migrate
|
22
71
|
```
|
23
72
|
|
24
|
-
##
|
25
|
-
|
73
|
+
## Вклад в разработку
|
74
|
+
|
75
|
+
Особых инструкций нет. Fork/update/PR, как обычно. Или просто опишите свои идеи
|
76
|
+
в разделе `issues`.
|
77
|
+
|
78
|
+
## Лицензия
|
79
|
+
|
80
|
+
[MIT License](http://opensource.org/licenses/MIT).
|
26
81
|
|
27
|
-
|
28
|
-
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
82
|
+
Продукт предоставляется «как есть». Используйте на свой страх и риск.
|
@@ -0,0 +1,118 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Biovision Comments component
|
5
|
+
*
|
6
|
+
* @type {Object}
|
7
|
+
*/
|
8
|
+
const Comments = {
|
9
|
+
initialized: false,
|
10
|
+
autoInitComponents: true,
|
11
|
+
components: {}
|
12
|
+
};
|
13
|
+
|
14
|
+
/**
|
15
|
+
* Move new comment form to different parent comment
|
16
|
+
*
|
17
|
+
* Handles click on "Reply" button and moves form under parent comment.
|
18
|
+
* Click on "Cancel" button moves form back to top-level reply.
|
19
|
+
*
|
20
|
+
* @type {Object}
|
21
|
+
*/
|
22
|
+
Comments.components.replyFormMover = {
|
23
|
+
initialized: false,
|
24
|
+
/**
|
25
|
+
* Container for list of comments
|
26
|
+
*
|
27
|
+
* @type {HTMLElement}
|
28
|
+
*/
|
29
|
+
listContainer: undefined,
|
30
|
+
/**
|
31
|
+
* Container for reply form
|
32
|
+
*
|
33
|
+
* @type {HTMLElement}
|
34
|
+
*/
|
35
|
+
mainContainer: undefined,
|
36
|
+
form: undefined,
|
37
|
+
/**
|
38
|
+
* @type {HTMLElement}
|
39
|
+
*/
|
40
|
+
parentId: undefined,
|
41
|
+
replyButtons: [],
|
42
|
+
cancelButtons: [],
|
43
|
+
replySelector: ".comment-reply-button button",
|
44
|
+
cancelSelector: ".container button.cancel",
|
45
|
+
/**
|
46
|
+
* Initialize
|
47
|
+
*/
|
48
|
+
init: function () {
|
49
|
+
this.listContainer = document.getElementById("comments");
|
50
|
+
this.form = document.getElementById("comment-form");
|
51
|
+
|
52
|
+
if (this.listContainer && this.form) {
|
53
|
+
this.parentId = document.getElementById("comment_parent_id");
|
54
|
+
this.mainContainer = this.listContainer.querySelector(".reply-container .container");
|
55
|
+
this.listContainer.querySelectorAll(this.replySelector).forEach(this.applyToReplyButton);
|
56
|
+
this.listContainer.querySelectorAll(this.cancelSelector).forEach(this.applyToCancelButton);
|
57
|
+
|
58
|
+
this.initialized = true;
|
59
|
+
}
|
60
|
+
},
|
61
|
+
/**
|
62
|
+
* Apply handler for pressing "Reply" button
|
63
|
+
*
|
64
|
+
* @param {HTMLElement} button
|
65
|
+
* @type {Function}
|
66
|
+
*/
|
67
|
+
applyToReplyButton: function (button) {
|
68
|
+
const component = Comments.components.replyFormMover;
|
69
|
+
|
70
|
+
component.replyButtons.push(button);
|
71
|
+
button.addEventListener("click", component.move);
|
72
|
+
},
|
73
|
+
/**
|
74
|
+
* Apply handler for pressing "Cancel" button
|
75
|
+
*
|
76
|
+
* @param {HTMLElement} button
|
77
|
+
* @type {Function}
|
78
|
+
*/
|
79
|
+
applyToCancelButton: function (button) {
|
80
|
+
const component = Comments.components.replyFormMover;
|
81
|
+
|
82
|
+
component.cancelButtons.push(button);
|
83
|
+
button.addEventListener("click", component.cancel);
|
84
|
+
},
|
85
|
+
/**
|
86
|
+
* Move reply form to parent comment
|
87
|
+
*
|
88
|
+
* @param {Event} event
|
89
|
+
* @type {Function}
|
90
|
+
*/
|
91
|
+
move: function (event) {
|
92
|
+
const component = Comments.components.replyFormMover;
|
93
|
+
const button = event.target;
|
94
|
+
const container = button.closest(".comment-reply-block").querySelector(".container");
|
95
|
+
|
96
|
+
if (container) {
|
97
|
+
component.parentId.value = button.closest(".comment-item").getAttribute("data-id");
|
98
|
+
container.appendChild(component.form);
|
99
|
+
container.classList.remove("hidden");
|
100
|
+
}
|
101
|
+
},
|
102
|
+
/**
|
103
|
+
* Handler for pressing "Cancel" button
|
104
|
+
*
|
105
|
+
* @param {Event} event
|
106
|
+
* @type {Function}
|
107
|
+
*/
|
108
|
+
cancel: function (event) {
|
109
|
+
const component = Comments.components.replyFormMover;
|
110
|
+
const button = event.target;
|
111
|
+
button.parentNode.classList.add("hidden");
|
112
|
+
|
113
|
+
component.parentId.value = "";
|
114
|
+
component.mainContainer.appendChild(component.form);
|
115
|
+
}
|
116
|
+
};
|
117
|
+
|
118
|
+
Biovision.components.comments = Comments;
|
@@ -1,35 +1,37 @@
|
|
1
|
-
$border-
|
2
|
-
$
|
3
|
-
$font-size-small: 1rem !default;
|
1
|
+
$border-secondary: .1rem solid #aaa !default;
|
2
|
+
$text-color-secondary: #777 !default;
|
4
3
|
$row-background-even: #f0f0f0 !default;
|
5
4
|
$row-background-odd: #fafafa !default;
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
border-top: $border-primary;
|
11
|
-
|
12
|
-
> h2 {
|
13
|
-
margin: 0.8rem 0;
|
6
|
+
.comments {
|
7
|
+
h3::first-letter {
|
8
|
+
text-transform: uppercase;
|
14
9
|
}
|
10
|
+
}
|
15
11
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
&:nth-of-type(even) {
|
21
|
-
background-color: $row-background-even;
|
22
|
-
}
|
23
|
-
}
|
12
|
+
.comments-list {
|
13
|
+
border-bottom: $border-secondary;
|
14
|
+
margin: var(--spacer-s, 1.6rem) 0;
|
15
|
+
padding: 0 0 var(--spacer-s, 1.6rem);
|
24
16
|
}
|
25
17
|
|
26
|
-
|
18
|
+
.comment-item {
|
27
19
|
position: relative;
|
20
|
+
background-color: $row-background-odd;
|
21
|
+
padding: var(--spacer-xxs, .4rem);
|
22
|
+
|
23
|
+
&:first-of-type {
|
24
|
+
margin-top: var(--spacer-s, 1.6rem);
|
25
|
+
}
|
26
|
+
|
27
|
+
&:nth-of-type(even) {
|
28
|
+
background-color: $row-background-even;
|
29
|
+
}
|
28
30
|
|
29
31
|
.deleted {
|
30
|
-
font-size:
|
32
|
+
font-size: var(--font-size-decreased, 1.4rem);
|
31
33
|
font-style: italic;
|
32
|
-
padding: 0 .8rem;
|
34
|
+
padding: 0 var(--spacer-xs, .8rem);
|
33
35
|
|
34
36
|
&::before {
|
35
37
|
content: '[';
|
@@ -41,9 +43,9 @@ div.comment {
|
|
41
43
|
}
|
42
44
|
|
43
45
|
.title {
|
44
|
-
|
45
|
-
|
46
|
-
|
46
|
+
border-bottom: dotted .1rem;
|
47
|
+
margin: var(--spacer-xs, .8rem) 0;
|
48
|
+
padding: 0 0 var(--spacer-xxs, .4rem) 0;
|
47
49
|
|
48
50
|
cite {
|
49
51
|
&:before {
|
@@ -56,39 +58,84 @@ div.comment {
|
|
56
58
|
}
|
57
59
|
}
|
58
60
|
|
61
|
+
.meta {
|
62
|
+
display: flex;
|
63
|
+
flex-wrap: wrap;
|
64
|
+
}
|
65
|
+
|
66
|
+
.avatar {
|
67
|
+
height: 4.8rem;
|
68
|
+
margin: 0 var(--spacer-xs, .8rem) 0 0;
|
69
|
+
width: 4.8rem;
|
70
|
+
}
|
71
|
+
|
72
|
+
.info {
|
73
|
+
display: flex;
|
74
|
+
flex-direction: column;
|
75
|
+
|
76
|
+
time {
|
77
|
+
color: $text-color-secondary;
|
78
|
+
font-size: var(--font-size-decreased, 1.4rem);
|
79
|
+
margin-top: auto;
|
80
|
+
}
|
81
|
+
}
|
82
|
+
|
83
|
+
.comment-wrapper {
|
84
|
+
display: flex;
|
85
|
+
}
|
86
|
+
|
87
|
+
.vote-block {
|
88
|
+
align-items: center;
|
89
|
+
display: flex;
|
90
|
+
flex-direction: column;
|
91
|
+
flex: none;
|
92
|
+
justify-content: center;
|
93
|
+
width: 3.2rem;
|
94
|
+
|
95
|
+
.result {
|
96
|
+
color: $text-color-secondary;
|
97
|
+
font-size: var(--font-size-decreased, 1.4rem);
|
98
|
+
margin: var(--spacer-xxs, .4rem) 0;
|
99
|
+
}
|
100
|
+
}
|
101
|
+
|
102
|
+
.vote {
|
103
|
+
height: 1.6rem;
|
104
|
+
width: .8rem;
|
105
|
+
}
|
106
|
+
|
59
107
|
.body {
|
60
108
|
background: #ffffff;
|
61
|
-
|
62
|
-
|
109
|
+
flex: 1;
|
110
|
+
margin: var(--spacer-xs, .8rem);
|
111
|
+
padding: var(--spacer-xs, .8rem);
|
63
112
|
position: relative;
|
64
113
|
}
|
65
114
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
padding: 0 0.8rem;
|
115
|
+
p {
|
116
|
+
&:first-of-type {
|
117
|
+
margin-top: 0;
|
118
|
+
}
|
71
119
|
|
72
|
-
|
73
|
-
|
74
|
-
font-style: italic;
|
120
|
+
&:last-of-type {
|
121
|
+
margin-bottom: 0;
|
75
122
|
}
|
76
123
|
}
|
77
124
|
|
78
125
|
.footer {
|
79
|
-
padding:
|
126
|
+
padding: var(--spacer-xs, .8rem) var(--spacer-s, 1.6rem);
|
80
127
|
|
81
128
|
> ul {
|
82
129
|
display: flex;
|
130
|
+
justify-content: flex-end;
|
83
131
|
margin: 0;
|
84
132
|
padding: 0;
|
85
|
-
justify-content: flex-end;
|
86
133
|
|
87
134
|
> li {
|
88
135
|
list-style: none;
|
89
|
-
margin: 0
|
136
|
+
margin: 0 var(--spacer-xxs, .4rem);
|
90
137
|
padding: 0;
|
91
|
-
font-size:
|
138
|
+
font-size: var(--font-size-small, 1.2rem);
|
92
139
|
text-align: right;
|
93
140
|
|
94
141
|
&:before {
|
@@ -102,3 +149,29 @@ div.comment {
|
|
102
149
|
}
|
103
150
|
}
|
104
151
|
}
|
152
|
+
|
153
|
+
.comment-form {
|
154
|
+
.fields {
|
155
|
+
padding: var(--spacer-s, 1.6rem) 0;
|
156
|
+
|
157
|
+
label {
|
158
|
+
display: block;
|
159
|
+
}
|
160
|
+
|
161
|
+
textarea {
|
162
|
+
margin: 0;
|
163
|
+
padding: var(--spacer-xs, .8rem);
|
164
|
+
width: 100%;
|
165
|
+
}
|
166
|
+
}
|
167
|
+
|
168
|
+
.required {
|
169
|
+
label {
|
170
|
+
&::before {
|
171
|
+
color: rgb(255, 63, 0);
|
172
|
+
content: '*';
|
173
|
+
margin: 0 var(--spacer-xxs, .4rem) 0 0;
|
174
|
+
}
|
175
|
+
}
|
176
|
+
}
|
177
|
+
}
|
@@ -1,8 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Administrative handling comments
|
1
4
|
class Admin::CommentsController < AdminController
|
2
5
|
include ToggleableEntity
|
3
6
|
include LockableEntity
|
4
7
|
|
5
|
-
before_action :set_entity, except:
|
8
|
+
before_action :set_entity, except: :index
|
6
9
|
|
7
10
|
# get /admin/comments
|
8
11
|
def index
|
@@ -13,16 +16,26 @@ class Admin::CommentsController < AdminController
|
|
13
16
|
def show
|
14
17
|
end
|
15
18
|
|
19
|
+
# put /admin/comments/:id/approve
|
20
|
+
def approve
|
21
|
+
@entity.update(approved: true)
|
22
|
+
|
23
|
+
head :no_content
|
24
|
+
end
|
25
|
+
|
16
26
|
protected
|
17
27
|
|
28
|
+
def component_slug
|
29
|
+
Biovision::Components::CommentsComponent::SLUG
|
30
|
+
end
|
31
|
+
|
18
32
|
def restrict_access
|
19
|
-
|
33
|
+
error = 'Managing comments is not allowed'
|
34
|
+
handle_http_401(error) unless component_handler.allow?('moderator')
|
20
35
|
end
|
21
36
|
|
22
37
|
def set_entity
|
23
38
|
@entity = Comment.find_by(id: params[:id])
|
24
|
-
if @entity.nil?
|
25
|
-
handle_http_404('Cannot find comment')
|
26
|
-
end
|
39
|
+
handle_http_404('Cannot find comment') if @entity.nil?
|
27
40
|
end
|
28
41
|
end
|