talkie 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rspec +3 -0
- data/.travis.yml +14 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +205 -0
- data/LICENSE.txt +21 -0
- data/README.md +120 -0
- data/Rakefile +23 -0
- data/app/assets/javascripts/talkie/application.js +5 -0
- data/app/assets/stylesheets/talkie/_comment.scss +103 -0
- data/app/assets/stylesheets/talkie/_form.scss +50 -0
- data/app/assets/stylesheets/talkie/_variables.scss +71 -0
- data/app/assets/stylesheets/talkie/application.scss +3 -0
- data/app/controllers/talkie/comments_controller.rb +45 -0
- data/app/controllers/talkie_controller.rb +19 -0
- data/app/helpers/talkie/application_helper.rb +20 -0
- data/app/models/talkie/comment.rb +13 -0
- data/app/views/talkie/comments/_comment.html.erb +44 -0
- data/app/views/talkie/comments/_form.html.erb +11 -0
- data/app/views/talkie/comments/_template.html.erb +3 -0
- data/bin/console +14 -0
- data/bin/setup +10 -0
- data/config/locales/en.yml +16 -0
- data/config/locales/es.yml +16 -0
- data/config/routes.rb +3 -0
- data/lib/generators/talkie/install_generator.rb +27 -0
- data/lib/generators/talkie/templates/create_talkie_comments.rb +27 -0
- data/lib/generators/talkie/templates/talkie.rb +46 -0
- data/lib/talkie.rb +30 -0
- data/lib/talkie/acts_as_commentable.rb +27 -0
- data/lib/talkie/acts_as_talker.rb +29 -0
- data/lib/talkie/comments_renderer.rb +43 -0
- data/lib/talkie/controller.rb +18 -0
- data/lib/talkie/engine.rb +15 -0
- data/lib/talkie/permission.rb +16 -0
- data/lib/talkie/renderer_helper.rb +42 -0
- data/lib/talkie/version.rb +3 -0
- data/talkie.gemspec +41 -0
- metadata +251 -0
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'bundler/setup'
|
5
|
+
rescue LoadError
|
6
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
7
|
+
end
|
8
|
+
|
9
|
+
APP_RAKEFILE = File.expand_path('../spec/dummy/Rakefile', __FILE__)
|
10
|
+
|
11
|
+
load 'rails/tasks/engine.rake'
|
12
|
+
|
13
|
+
Bundler::GemHelper.install_tasks
|
14
|
+
|
15
|
+
Dir[File.join(File.dirname(__FILE__), 'tasks/**/*.rake')].each {|f| load f }
|
16
|
+
|
17
|
+
require 'rspec/core'
|
18
|
+
require 'rspec/core/rake_task'
|
19
|
+
|
20
|
+
desc 'Run all specs in spec directory (excluding plugin specs)'
|
21
|
+
RSpec::Core::RakeTask.new(spec: 'app:db:test:prepare')
|
22
|
+
|
23
|
+
task default: :spec
|
@@ -0,0 +1,103 @@
|
|
1
|
+
.talkie {
|
2
|
+
&-comments-count {
|
3
|
+
color: $talkie-comments-count-color;
|
4
|
+
margin: $talkie-comments-count-margin;
|
5
|
+
}
|
6
|
+
|
7
|
+
&-comment-holder {
|
8
|
+
border-bottom: $talkie-comment-holder-border-bottom;
|
9
|
+
margin-bottom: $talkie-comment-holder-margin-bottom;
|
10
|
+
padding-bottom: $talkie-comment-holder-padding-bottom;
|
11
|
+
width: 90%;
|
12
|
+
}
|
13
|
+
|
14
|
+
&-comment-body {
|
15
|
+
color: $talkie-comment-body-color;
|
16
|
+
font-size: $talkie-comment-body-font-size;
|
17
|
+
line-height: $talkie-comment-body-line-height;
|
18
|
+
margin: $talkie-comment-body-margin;
|
19
|
+
}
|
20
|
+
|
21
|
+
&-comment-delete {
|
22
|
+
color: $talkie-comment-delete-color;
|
23
|
+
display: inline-block;
|
24
|
+
font: $talkie-comment-delete-font;
|
25
|
+
margin-left: $talkie-comment-delete-margin-left;
|
26
|
+
text-decoration: none;
|
27
|
+
}
|
28
|
+
|
29
|
+
&-comment-content {
|
30
|
+
margin-left: $talkie-comment-content-margin-left;
|
31
|
+
|
32
|
+
&::after {
|
33
|
+
content: "";
|
34
|
+
clear: both;
|
35
|
+
display: table;
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
&-comment-footer {
|
40
|
+
margin-top: $talkie-comment-footer-margin-top;
|
41
|
+
|
42
|
+
.talkie-comment-reply {
|
43
|
+
margin-bottom: $talkie-comment-reply-margin-bottom;
|
44
|
+
}
|
45
|
+
|
46
|
+
.talkie-comment-reply-link {
|
47
|
+
color: $talkie-comment-reply-link-color;
|
48
|
+
font: $talkie-comment-reply-link-font;
|
49
|
+
text-transform: $talkie-comment-reply-link-text-transform;
|
50
|
+
text-decoration: none;
|
51
|
+
-webkit-transition: $talkie-comment-reply-link-transition; /* Safari */
|
52
|
+
transition: $talkie-comment-reply-link-transition;
|
53
|
+
|
54
|
+
&:hover {
|
55
|
+
color: $talkie-comment-reply-link-hover-color;
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
.talkie-comments-reply-form-container {
|
60
|
+
border-bottom: none;
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
&-comment-created-at {
|
65
|
+
font-size: $talkie-comment-created-at-font-size;
|
66
|
+
text-transform: $talkie-comment-created-at-text-transform;
|
67
|
+
}
|
68
|
+
|
69
|
+
&-comment-creator {
|
70
|
+
&-avatar {
|
71
|
+
float: left;
|
72
|
+
|
73
|
+
img {
|
74
|
+
border-radius: $talkie-comment-creator-avatar-border-radius;
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
&-link {
|
79
|
+
color: $talkie-comment-creator-link-color;
|
80
|
+
display: block;
|
81
|
+
text-decoration: none;
|
82
|
+
|
83
|
+
&:hover {
|
84
|
+
text-decoration: underline;
|
85
|
+
}
|
86
|
+
}
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
// Nesting resets
|
91
|
+
.talkie-comment-holder
|
92
|
+
.talkie-comment-holder {
|
93
|
+
border-bottom: none;
|
94
|
+
margin-bottom: 0;
|
95
|
+
width: 100%;
|
96
|
+
}
|
97
|
+
|
98
|
+
.talkie-comment-content
|
99
|
+
.talkie-comment-content
|
100
|
+
.talkie-comment-content
|
101
|
+
.talkie-comment-content {
|
102
|
+
margin-left: 0;
|
103
|
+
}
|
@@ -0,0 +1,50 @@
|
|
1
|
+
.talkie {
|
2
|
+
&-comments-form-container,
|
3
|
+
&-comments-reply-form-container {
|
4
|
+
border-bottom: $talkie-form-border-bottom;
|
5
|
+
padding-bottom: $talkie-form-padding-bottom;
|
6
|
+
margin-bottom: $talkie-form-margin-bottom;
|
7
|
+
|
8
|
+
textarea {
|
9
|
+
background-color: $talkie-form-textarea-background-color;
|
10
|
+
border: $talkie-form-textarea-border;
|
11
|
+
border-radius: $talkie-form-textarea-border-radius;
|
12
|
+
box-sizing: border-box;
|
13
|
+
color: $talkie-form-textarea-color;
|
14
|
+
display: inline-block;
|
15
|
+
font-size: $talkie-form-textarea-font-size;
|
16
|
+
height: $talkie-form-textarea-height;
|
17
|
+
line-height: $talkie-form-textarea-line-height;
|
18
|
+
margin-bottom: 10px;
|
19
|
+
padding: 10px;
|
20
|
+
vertical-align: top;
|
21
|
+
width: 100%;
|
22
|
+
-moz-box-sizing: border-box;
|
23
|
+
-webkit-box-sizing: border-box;
|
24
|
+
-webkit-border-radius: $talkie-form-textarea-border-radius;
|
25
|
+
-moz-border-radius: $talkie-form-textarea-border-radius;
|
26
|
+
-webkit-appearance: none;
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
&-comments-form-submit {
|
31
|
+
background-color: $talkie-form-submit-background-color;
|
32
|
+
border: $talkie-form-submit-border;
|
33
|
+
border-radius: $talkie-form-submit-border-radius;
|
34
|
+
color: $talkie-form-submit-color;
|
35
|
+
font-size: $talkie-form-submit-font-size;
|
36
|
+
font-weight: $talkie-form-submit-font-weight;
|
37
|
+
margin: $talkie-form-submit-margin;
|
38
|
+
padding: $talkie-form-submit-padding;
|
39
|
+
text-align: center;
|
40
|
+
text-shadow: $talkie-form-submit-text-shadow;
|
41
|
+
vertical-align: top;
|
42
|
+
|
43
|
+
-webkit-border-radius: $talkie-form-submit-border-radius;
|
44
|
+
-moz-border-radius: $talkie-form-submit-border-radius;
|
45
|
+
|
46
|
+
&:hover {
|
47
|
+
cursor: pointer;
|
48
|
+
}
|
49
|
+
}
|
50
|
+
}
|
@@ -0,0 +1,71 @@
|
|
1
|
+
// Form variable styles
|
2
|
+
|
3
|
+
$talkie-form-border-bottom: 1px solid #EEE !default;
|
4
|
+
$talkie-form-padding-bottom: 10px !default;
|
5
|
+
$talkie-form-margin-bottom: 10px !default;
|
6
|
+
|
7
|
+
$talkie-form-textarea-background-color: #FFF !default;
|
8
|
+
$talkie-form-textarea-border: 1px solid #E5E5E5 !default;
|
9
|
+
$talkie-form-textarea-border-radius: 5px !default;
|
10
|
+
$talkie-form-textarea-color: #222 !default;
|
11
|
+
$talkie-form-textarea-font-size: 13px !default;
|
12
|
+
$talkie-form-textarea-height: 60px !default;
|
13
|
+
$talkie-form-textarea-line-height: 1.5 !default;
|
14
|
+
|
15
|
+
$talkie-form-submit-background-color: #4D90F0 !default;
|
16
|
+
$talkie-form-submit-border: 1px solid #3079ED !default;
|
17
|
+
$talkie-form-submit-color: #FFF !default;
|
18
|
+
$talkie-form-submit-border-radius: 2px !default;
|
19
|
+
$talkie-form-submit-font-weight: bold !default;
|
20
|
+
$talkie-form-submit-margin: 0 8px 6px 0!default;
|
21
|
+
$talkie-form-submit-font-size: 11px !default;
|
22
|
+
$talkie-form-submit-padding: 10px 12px !default;
|
23
|
+
$talkie-form-submit-text-shadow: 0 1px rgba(0,0,0,.1) !default;
|
24
|
+
|
25
|
+
// Comment
|
26
|
+
//
|
27
|
+
// Comments count
|
28
|
+
$talkie-comments-count-color: #333 !default;
|
29
|
+
$talkie-comments-count-margin: 0 0 40px 0 !default;
|
30
|
+
|
31
|
+
// Comment holder
|
32
|
+
$talkie-comment-holder-border-bottom: 1px solid #EEE !default;
|
33
|
+
$talkie-comment-holder-margin-bottom: 40px !default;
|
34
|
+
$talkie-comment-holder-padding-bottom: 20px !default;
|
35
|
+
|
36
|
+
// Comment body
|
37
|
+
$talkie-comment-body-color: #222 !default;
|
38
|
+
$talkie-comment-body-font-size: 16px !default;
|
39
|
+
$talkie-comment-body-line-height: 1.2 !default;
|
40
|
+
$talkie-comment-body-margin: 25px 0 0 0 !default;
|
41
|
+
|
42
|
+
// Comment delete
|
43
|
+
$talkie-comment-delete-color: #666 !default;
|
44
|
+
$talkie-comment-delete-font: 11px 'Source Sans Pro', sans-serif !default;
|
45
|
+
$talkie-comment-delete-margin-left: 10px !default;
|
46
|
+
|
47
|
+
// Comment content
|
48
|
+
$talkie-comment-content-margin-left: 60px !default;
|
49
|
+
|
50
|
+
// Comment footer
|
51
|
+
$talkie-comment-footer-margin-top: 20px !default;
|
52
|
+
|
53
|
+
// Comment reply
|
54
|
+
$talkie-comment-reply-margin-bottom: 20px !default;
|
55
|
+
|
56
|
+
// Comment reply link
|
57
|
+
$talkie-comment-reply-link-color: #666 !default;
|
58
|
+
$talkie-comment-reply-link-font: 11px 'Source Sans Pro', sans-serif !default;
|
59
|
+
$talkie-comment-reply-link-text-transform: uppercase !default;
|
60
|
+
$talkie-comment-reply-link-transition: color 0.2s !default;
|
61
|
+
$talkie-comment-reply-link-hover-color: #222 !default;
|
62
|
+
|
63
|
+
// Comment created at
|
64
|
+
$talkie-comment-created-at-font-size: 10px !default;
|
65
|
+
$talkie-comment-created-at-text-transform: uppercase !default;
|
66
|
+
|
67
|
+
// Creator Avatar
|
68
|
+
$talkie-comment-creator-avatar-border-radius: 1000px !default;
|
69
|
+
|
70
|
+
// Creator link
|
71
|
+
$talkie-comment-creator-link-color: #222 !default;
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Talkie
|
2
|
+
class CommentsController < TalkieController
|
3
|
+
before_action :current_comment, only: [:destroy]
|
4
|
+
|
5
|
+
def create
|
6
|
+
@comment = Talkie::Comment.new(comment_params)
|
7
|
+
@comment.creator = current_user
|
8
|
+
|
9
|
+
respond_to do |format|
|
10
|
+
if @comment.save
|
11
|
+
make_child_comment if reply?
|
12
|
+
format.html { redirect_to main_app.polymorphic_path(@comment.commentable), notice: "Comment was successfully added." }
|
13
|
+
format.js
|
14
|
+
else
|
15
|
+
format.html { redirect_to :back, notice: "Something went wrong, blank comments are not allowed" }
|
16
|
+
format.js
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def destroy
|
22
|
+
current_comment.destroy
|
23
|
+
redirect_to main_app.polymorphic_path(current_comment.commentable)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def comment_params
|
29
|
+
params.require(:comment).permit(:body, :commentable_id, :commentable_type)
|
30
|
+
end
|
31
|
+
|
32
|
+
def reply?
|
33
|
+
params[:parent_comment_id].present?
|
34
|
+
end
|
35
|
+
|
36
|
+
def make_child_comment
|
37
|
+
parent_comment = Comment.find params[:parent_comment_id]
|
38
|
+
@comment.move_to_child_of(parent_comment)
|
39
|
+
end
|
40
|
+
|
41
|
+
def current_comment
|
42
|
+
@current_comment ||= Talkie::Comment.find_by(id: params[:id])
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class TalkieController < ApplicationController
|
4
|
+
include Talkie::Controller
|
5
|
+
|
6
|
+
before_action :authorize!
|
7
|
+
|
8
|
+
protected
|
9
|
+
|
10
|
+
def authorize!
|
11
|
+
if !current_permission.allow?(params[:action], current_comment)
|
12
|
+
redirect_back fallback_location: main_app.root_url, status: :unauthorized
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def current_comment
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Talkie
|
2
|
+
module ApplicationHelper
|
3
|
+
def link_to_creator(creator, options = {})
|
4
|
+
creator_handler = creator.send Talkie.comment_creator_handler
|
5
|
+
creator_path = Talkie.creator_path.call(creator, main_app)
|
6
|
+
|
7
|
+
link_to creator_handler, creator_path, options
|
8
|
+
end
|
9
|
+
|
10
|
+
def avatar_image_tag(creator)
|
11
|
+
creator_handler = creator.send Talkie.comment_creator_handler
|
12
|
+
|
13
|
+
image_tag avatar_url(creator), alt: creator_handler, title: creator_handler
|
14
|
+
end
|
15
|
+
|
16
|
+
def avatar_url(creator)
|
17
|
+
Talkie.creator_avatar_url.call(creator)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Talkie
|
2
|
+
class Comment < ActiveRecord::Base
|
3
|
+
default_scope Talkie.default_comments_scope
|
4
|
+
|
5
|
+
acts_as_nested_set :scope => [:commentable_id, :commentable_type],
|
6
|
+
:counter_cache => :children_count
|
7
|
+
|
8
|
+
belongs_to :creator, polymorphic: true, inverse_of: :comments
|
9
|
+
belongs_to :commentable, polymorphic: true, inverse_of: :comments
|
10
|
+
|
11
|
+
validates :body, :creator, :commentable, presence: true
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
<div class="talkie-comment-holder">
|
2
|
+
<% if display_user_avatar? %>
|
3
|
+
<div class="talkie-comment-creator-avatar">
|
4
|
+
<%= avatar_image_tag comment.creator %>
|
5
|
+
</div>
|
6
|
+
<% end %>
|
7
|
+
|
8
|
+
<div class="talkie-comment-content">
|
9
|
+
<header class="talkie-comment-header">
|
10
|
+
<% if display_user_handler? %>
|
11
|
+
<div class="talkie-comment-creator">
|
12
|
+
<%= link_to_creator comment.creator, class: "talkie-comment-creator-link" %>
|
13
|
+
</div>
|
14
|
+
<% end %>
|
15
|
+
<small class="talkie-comment-created-at"><%= l comment.created_at, format: :long %></small>
|
16
|
+
|
17
|
+
</header>
|
18
|
+
<p class="talkie-comment-body">
|
19
|
+
<%= comment.body %>
|
20
|
+
</p>
|
21
|
+
|
22
|
+
<div class="talkie-comment-footer">
|
23
|
+
<% if nested_enabled? %>
|
24
|
+
<div class="talkie-comment-reply">
|
25
|
+
<a href="#" class="talkie-comment-reply-link"><%= t("talkie.comment.reply") %></a>
|
26
|
+
<% if allow? :destroy, comment %>
|
27
|
+
<%= link_to t("talkie.comment.delete"), [talkie, comment], method: :delete, class: "talkie-comment-delete" %>
|
28
|
+
<% end %>
|
29
|
+
</div>
|
30
|
+
<div class="talkie-comments-reply-form-container" style="display:none">
|
31
|
+
<%= form_for [talkie, Talkie::Comment.new] do |f| %>
|
32
|
+
<%= f.hidden_field :commentable_id, value: commentable.id %>
|
33
|
+
<%= f.hidden_field :commentable_type, value: commentable.class.name %>
|
34
|
+
<%= hidden_field_tag :parent_comment_id, comment.id %>
|
35
|
+
|
36
|
+
<%= f.text_area :body, placeholder: t("talkie.comment.form.body_placeholder") %>
|
37
|
+
<%= submit_tag t("talkie.comment.form.reply"), class: 'talkie-comments-form-submit' %>
|
38
|
+
<% end %>
|
39
|
+
</div>
|
40
|
+
<%= render comment.children %>
|
41
|
+
<% end %>
|
42
|
+
</div>
|
43
|
+
</div>
|
44
|
+
</div>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<div class="talkie-comments-form-container">
|
2
|
+
<%= form_for [talkie, Talkie::Comment.new] do |f| %>
|
3
|
+
<%= f.hidden_field :commentable_id, value: commentable.id %>
|
4
|
+
<%= f.hidden_field :commentable_type, value: commentable.class.name %>
|
5
|
+
|
6
|
+
<%= f.text_area :body, placeholder: t("talkie.comments.form.body_placeholder") %>
|
7
|
+
<%= f.submit t("talkie.comments.form.submit"), class: "talkie-comments-form-submit" %>
|
8
|
+
<% end %>
|
9
|
+
</div>
|
10
|
+
|
11
|
+
<h5 class="talkie-comments-count"><%= pluralize commentable.comments.size, t("talkie.comments.count.singular"), plural: t("talkie.comments.count.plural") %></h5>
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "talkie"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|