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.
Files changed (35) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +68 -14
  3. data/app/assets/javascripts/biovision/comment/biovision-comments.js +118 -0
  4. data/app/assets/stylesheets/biovision/comment/comments.scss +111 -38
  5. data/app/controllers/admin/comments_controller.rb +18 -5
  6. data/app/controllers/comments_controller.rb +45 -32
  7. data/app/helpers/comments_helper.rb +20 -0
  8. data/app/models/comment.rb +88 -19
  9. data/app/models/concerns/commentable_item.rb +15 -0
  10. data/app/services/biovision/components/comments_component.rb +39 -0
  11. data/app/services/comment_handler.rb +49 -0
  12. data/app/services/comments_manager.rb +24 -0
  13. data/app/views/admin/comments/entity/_in_list.html.erb +8 -5
  14. data/app/views/admin/comments/index.html.erb +2 -1
  15. data/app/views/admin/comments/show.html.erb +25 -10
  16. data/app/views/admin/components/links/_comments.html.erb +3 -0
  17. data/app/views/comment_mailer/entry_reply.text.erb +2 -6
  18. data/app/views/comments/_comment.html.erb +66 -16
  19. data/app/views/comments/_form.html.erb +92 -19
  20. data/app/views/comments/_list.html.erb +17 -19
  21. data/app/views/comments/_reply_container.html.erb +15 -0
  22. data/app/views/comments/_section.html.erb +34 -0
  23. data/app/views/comments/edit.html.erb +6 -5
  24. data/app/views/comments/new.html.erb +2 -2
  25. data/config/locales/comments-ru.yml +32 -2
  26. data/config/routes.rb +18 -10
  27. data/db/migrate/20170914000001_create_comments.rb +48 -23
  28. data/db/migrate/20190203090909_add_fields_to_comments.rb +14 -0
  29. data/db/migrate/20190428212121_add_approved_to_comments.rb +14 -0
  30. data/db/migrate/20190428212122_create_comments_component.rb +21 -0
  31. data/db/migrate/20190628101010_add_data_to_comments.rb +15 -0
  32. data/lib/biovision/comment/engine.rb +7 -2
  33. data/lib/biovision/comment/version.rb +3 -1
  34. metadata +19 -8
  35. data/app/views/comments/show.html.erb +0 -27
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: f90194297e55ad450ea7bbf54b5793c70d1f8a59
4
- data.tar.gz: 7ff6561739d214e95fc48ba9fc9ce7740e798e89
2
+ SHA256:
3
+ metadata.gz: a602c3288d543c9a10860099700cb6657f206b3b6dce1b88a82c5ad1c239b5c8
4
+ data.tar.gz: 552231814a6ad6ed6b43c1edbc12b195192090e2ef821d73b962c1c6cd1850b4
5
5
  SHA512:
6
- metadata.gz: 64bb4f5aa97526081b06a577c0ee26ba5a43a00637acd3af6b796422055124fe3e21210e66c2c418e1846bb6fa6bdaefa89edf3d916645c497efa42e964ff17c
7
- data.tar.gz: 10fb7f85ddc4d8eb23d6628a1845d6bc4190d220b1cb3655d3169dfb6fddc88799bd7c5b781920f504a6b6a22543a90dbd9c20159fd1ca1692693298f9755624
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
- ## Usage
5
- How to use my plugin.
3
+ Компонент с комментариями для проектов на базе `Biovision`.
6
4
 
7
- ## Installation
8
- Add this line to your application's Gemfile:
5
+ Находится в стадии разработки. Используйте на свой страх и риск.
6
+
7
+ ## Использование
8
+
9
+ ### Подготовка моделей
10
+
11
+ Для моделей, которым нужны комментарии, следует в классе добавить это:
9
12
 
10
13
  ```ruby
11
- gem 'biovision-comment'
14
+ has_many :comments, as: :commentable
12
15
  ```
13
16
 
14
- And then execute:
17
+ Тамже всем моделям с комментариями нужно поле `comments_count` для счётчика
18
+ комментарием:
19
+
15
20
  ```bash
16
- $ bundle
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
- Or install it yourself as:
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
- $ gem install biovision-comment
68
+ $ bundle
69
+ $ rails railties:install:migrations
70
+ $ rails db:migrate
22
71
  ```
23
72
 
24
- ## Contributing
25
- Contribution directions go here.
73
+ ## Вклад в разработку
74
+
75
+ Особых инструкций нет. Fork/update/PR, как обычно. Или просто опишите свои идеи
76
+ в разделе `issues`.
77
+
78
+ ## Лицензия
79
+
80
+ [MIT License](http://opensource.org/licenses/MIT).
26
81
 
27
- ## License
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-primary: .1rem solid rgb(127, 127, 127) !default;
2
- $font-size-decreased: 1.2rem !default;
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
- section.comments {
8
- margin: 1.6rem 0;
9
- padding: 0 0.8rem;
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
- > div {
17
- background-color: $row-background-odd;
18
- padding: 0.4rem;
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
- div.comment {
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: $font-size-decreased;
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
- padding: 0 0 0.4rem 0;
45
- border-bottom: dotted 0.1rem;
46
- margin: 0.8rem 0;
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
- margin: 0.8rem;
62
- padding: 0.8rem;
109
+ flex: 1;
110
+ margin: var(--spacer-xs, .8rem);
111
+ padding: var(--spacer-xs, .8rem);
63
112
  position: relative;
64
113
  }
65
114
 
66
- .author {
67
- display: flex;
68
- justify-content: space-between;
69
- align-items: center;
70
- padding: 0 0.8rem;
115
+ p {
116
+ &:first-of-type {
117
+ margin-top: 0;
118
+ }
71
119
 
72
- time {
73
- font-size: $font-size-decreased;
74
- font-style: italic;
120
+ &:last-of-type {
121
+ margin-bottom: 0;
75
122
  }
76
123
  }
77
124
 
78
125
  .footer {
79
- padding: 0.8rem 1.6rem;
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 0.4rem;
136
+ margin: 0 var(--spacer-xxs, .4rem);
90
137
  padding: 0;
91
- font-size: $font-size-small;
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: [:index]
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
- require_privilege :moderator
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