simple_discussion 0.1.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +52 -8
- data/app/assets/stylesheets/simple_discussion.scss +63 -0
- data/app/controllers/simple_discussion/application_controller.rb +25 -0
- data/app/controllers/simple_discussion/forum_categories_controller.rb +17 -0
- data/app/controllers/simple_discussion/forum_posts_controller.rb +66 -0
- data/app/controllers/simple_discussion/forum_threads_controller.rb +72 -0
- data/app/controllers/simple_discussion/notifications_controller.rb +19 -0
- data/app/helpers/simple_discussion/forum_posts_helper.rb +29 -0
- data/app/helpers/simple_discussion/forum_threads_helper.rb +28 -0
- data/app/models/forum_category.rb +13 -0
- data/app/models/forum_post.rb +15 -0
- data/app/models/forum_subscription.rb +19 -0
- data/app/models/forum_thread.rb +75 -0
- data/app/views/layouts/simple_discussion.html.erb +59 -0
- data/app/views/shared/_spacer.html.erb +1 -0
- data/app/views/simple_discussion/forum_posts/_form.html.erb +32 -0
- data/app/views/simple_discussion/forum_posts/_forum_post.html.erb +58 -0
- data/app/views/simple_discussion/forum_posts/edit.html.erb +24 -0
- data/app/views/simple_discussion/forum_threads/_form.html.erb +44 -0
- data/app/views/simple_discussion/forum_threads/_forum_thread.html.erb +37 -0
- data/app/views/simple_discussion/forum_threads/edit.html.erb +7 -0
- data/app/views/simple_discussion/forum_threads/index.html.erb +11 -0
- data/app/views/simple_discussion/forum_threads/new.html.erb +5 -0
- data/app/views/simple_discussion/forum_threads/show.html.erb +19 -0
- data/config/routes.rb +24 -0
- data/db/migrate/20170417012930_create_forum_categories.rb +23 -0
- data/db/migrate/20170417012931_create_forum_threads.rb +15 -0
- data/db/migrate/20170417012932_create_forum_posts.rb +12 -0
- data/db/migrate/20170417012933_create_forum_subscriptions.rb +11 -0
- data/lib/simple_discussion/engine.rb +5 -0
- data/lib/simple_discussion/forum_user.rb +11 -0
- data/lib/simple_discussion/version.rb +1 -1
- data/lib/simple_discussion.rb +57 -1
- data/simple_discussion.gemspec +5 -3
- metadata +76 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ea112341c29ae6d453a260175e1fab4fe8742243
|
4
|
+
data.tar.gz: '08670316d53d01df1dfc1f0101d59f43e46be643'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 87914991332ab15ab141c77baf1924fc8c89b4f4e01c1fc9121eff52309daa4a23c1310833db545750d25dc82dd9c8805647ff834147d7fca3ed1da96d336390
|
7
|
+
data.tar.gz: fde66ad800d05ea86cf1251950f490f2d221d10b8e8807d67863c41f022a54a713391e0e10148a7ea9ede736276dcba5d03a92babd0f1c66fa1b45f084332846
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
# SimpleDiscussion
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
SimpleDiscussion is a Rails forum gem extracting the forum from
|
4
|
+
[GoRails' forum](https://gorails.com/forum). It includes categories,
|
5
|
+
simple moderation, the ability to mark threads as solved, and more.
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
9
|
+
Before you get started, SimpleDiscussion requires a `User` model in your application (for now).
|
10
|
+
|
9
11
|
Add this line to your application's Gemfile:
|
10
12
|
|
11
13
|
```ruby
|
@@ -14,15 +16,57 @@ gem 'simple_discussion'
|
|
14
16
|
|
15
17
|
And then execute:
|
16
18
|
|
17
|
-
|
19
|
+
```bash
|
20
|
+
bundle
|
21
|
+
```
|
22
|
+
|
23
|
+
Install the migrations and migrate:
|
24
|
+
|
25
|
+
```bash
|
26
|
+
rails simple_discussion:install:migrations
|
27
|
+
rails db:migrate
|
28
|
+
```
|
29
|
+
|
30
|
+
Add SimpleDiscussion to your `User` model. The model **must** have `name` method which will be used to display the user's name on the forum. Currently only a model named `User` will work, but this will be fixed shortly.
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
class User < ActiveRecord::Base
|
34
|
+
include SimpleDiscussion::ForumUser
|
35
|
+
|
36
|
+
def name
|
37
|
+
"#{first_name} #{last_name}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
```
|
41
|
+
|
42
|
+
Optionally, you can add a `moderator` flag to the `User` model to allow users to edit threads and posts they didn't write.
|
43
|
+
|
44
|
+
```bash
|
45
|
+
rails g migration AddModeratorToUsers moderator:boolean
|
46
|
+
rails db:migrate
|
47
|
+
```
|
48
|
+
|
49
|
+
Add the following line to your `config/routes.rb` file:
|
18
50
|
|
19
|
-
|
51
|
+
```ruby
|
52
|
+
mount SimpleDiscussion::Engine => "/forum"
|
53
|
+
```
|
20
54
|
|
21
|
-
|
55
|
+
You can also add the CSS to your `application.css` to load some helpful default styles.
|
56
|
+
|
57
|
+
```javascript
|
58
|
+
//= require simple_discussion
|
59
|
+
```
|
22
60
|
|
23
61
|
## Usage
|
24
62
|
|
25
|
-
|
63
|
+
To get all the basic functionality, the only thing you need to do is add a link to SimpleDiscussion in your navbar.
|
64
|
+
|
65
|
+
```erb
|
66
|
+
<%= link_to "Forum", simple_discussion_path %>
|
67
|
+
```
|
68
|
+
|
69
|
+
This will take the user to the views inside the Rails engine.
|
26
70
|
|
27
71
|
## Development
|
28
72
|
|
@@ -32,7 +76,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
32
76
|
|
33
77
|
## Contributing
|
34
78
|
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
79
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/excid3/simple_discussion. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
36
80
|
|
37
81
|
## License
|
38
82
|
|
@@ -0,0 +1,63 @@
|
|
1
|
+
/* Allow pagination to be centered */
|
2
|
+
.forum-threads-nav nav {
|
3
|
+
display: inline-block;
|
4
|
+
}
|
5
|
+
|
6
|
+
/* Highlight the active navigation item in the sidebar */
|
7
|
+
.forum-thread-filters {
|
8
|
+
a {
|
9
|
+
color: #555;
|
10
|
+
}
|
11
|
+
|
12
|
+
.active {
|
13
|
+
color: #222;
|
14
|
+
font-weight: bolder;
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
/* Formatting for the forum threads */
|
19
|
+
.forum-thread {
|
20
|
+
h4 a {
|
21
|
+
color: #222;
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
.thread-details {
|
26
|
+
color: #999;
|
27
|
+
font-size: 12px;
|
28
|
+
text-transform: uppercase;
|
29
|
+
}
|
30
|
+
|
31
|
+
/* Display the forum post count above the "posts" text on the index page */
|
32
|
+
.thread-posts-count {
|
33
|
+
color: #222;
|
34
|
+
text-align: center;
|
35
|
+
|
36
|
+
span, small {
|
37
|
+
display: block;
|
38
|
+
}
|
39
|
+
|
40
|
+
.count {
|
41
|
+
font-size: 1.5em;
|
42
|
+
font-weight: 300;
|
43
|
+
line-height: 1em;
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
/* Formatting for the forum posts themselves */
|
48
|
+
.forum-post {
|
49
|
+
position: relative;
|
50
|
+
|
51
|
+
/* When the URL anchor matches a post id, highlight that item */
|
52
|
+
&:target {
|
53
|
+
background-color: rgb(248, 238, 199);
|
54
|
+
}
|
55
|
+
|
56
|
+
/* Fill this out if you want to highlight the OPs posts */
|
57
|
+
&.original-poster {
|
58
|
+
}
|
59
|
+
|
60
|
+
&.solved {
|
61
|
+
border: 2px solid #5cb85c;
|
62
|
+
}
|
63
|
+
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class SimpleDiscussion::ApplicationController < ::ApplicationController
|
2
|
+
layout "simple_discussion"
|
3
|
+
|
4
|
+
def page_number
|
5
|
+
page = params.fetch(:page, '').gsub(/[^0-9]/, '').to_i
|
6
|
+
page = "1" if page.zero?
|
7
|
+
page
|
8
|
+
end
|
9
|
+
|
10
|
+
def is_moderator_or_owner?(object)
|
11
|
+
is_moderator? || object.user == current_user
|
12
|
+
end
|
13
|
+
helper_method :is_moderator_or_owner?
|
14
|
+
|
15
|
+
def is_moderator?
|
16
|
+
current_user.respond_to?(:moderator) && current_user.moderator?
|
17
|
+
end
|
18
|
+
helper_method :is_moderator?
|
19
|
+
|
20
|
+
def require_moderator_or_author!
|
21
|
+
unless is_moderator_or_owner?(@forum_thread)
|
22
|
+
redirect_to simple_discussion.root_path, alert: "You aren't allowed to do that."
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class SimpleDiscussion::ForumCategoriesController < SimpleDiscussion::ApplicationController
|
2
|
+
before_action :set_category
|
3
|
+
|
4
|
+
def index
|
5
|
+
@forum_threads = ForumThread.where(forum_category: @category) if @category.present?
|
6
|
+
@forum_threads = @forum_threads.pinned_first.sorted.includes(:user, :forum_category).paginate(per_page: 10, page: page_number)
|
7
|
+
render "simple_discussion/forum_threads/index"
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def set_category
|
13
|
+
@category = ForumCategory.friendly.find(params[:id])
|
14
|
+
rescue ActiveRecord::RecordNotFound
|
15
|
+
redirect_to simple_discussion.forum_threads_path
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
class SimpleDiscussion::ForumPostsController < SimpleDiscussion::ApplicationController
|
2
|
+
before_action :authenticate_user!
|
3
|
+
before_action :set_forum_thread
|
4
|
+
before_action :set_forum_post, only: [:edit, :update]
|
5
|
+
before_action :require_moderator_or_author!, only: [:edit, :update, :solved, :unsolved]
|
6
|
+
|
7
|
+
def create
|
8
|
+
@forum_post = @forum_thread.forum_posts.new(forum_post_params)
|
9
|
+
@forum_post.user_id = current_user.id
|
10
|
+
|
11
|
+
if @forum_post.save
|
12
|
+
#ForumNotificationJob.perform_later(@forum_post.id)
|
13
|
+
redirect_to simple_discussion.forum_thread_path(@forum_thread, anchor: "forum_post_#{@forum_post.id}")
|
14
|
+
else
|
15
|
+
render template: "simple_discussion/forum_threads/show"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def edit
|
20
|
+
end
|
21
|
+
|
22
|
+
def update
|
23
|
+
if @forum_post.update(forum_post_params)
|
24
|
+
redirect_to simple_discussion.forum_thread_path(@forum_thread)
|
25
|
+
else
|
26
|
+
render action: :edit
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def solved
|
31
|
+
@forum_post = @forum_thread.forum_posts.find(params[:id])
|
32
|
+
|
33
|
+
@forum_thread.forum_posts.update_all(solved: false)
|
34
|
+
@forum_post.update_column(:solved, true)
|
35
|
+
@forum_thread.update_column(:solved, true)
|
36
|
+
|
37
|
+
redirect_to simple_discussion.forum_thread_path(@forum_thread, anchor: ActionView::RecordIdentifier.dom_id(@forum_post))
|
38
|
+
end
|
39
|
+
|
40
|
+
def unsolved
|
41
|
+
@forum_post = @forum_thread.forum_posts.find(params[:id])
|
42
|
+
|
43
|
+
@forum_thread.forum_posts.update_all(solved: false)
|
44
|
+
@forum_thread.update_column(:solved, false)
|
45
|
+
|
46
|
+
redirect_to simple_discussion.forum_thread_path(@forum_thread, anchor: ActionView::RecordIdentifier.dom_id(@forum_post))
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def set_forum_thread
|
52
|
+
@forum_thread = ForumThread.friendly.find(params[:forum_thread_id])
|
53
|
+
end
|
54
|
+
|
55
|
+
def set_forum_post
|
56
|
+
if current_user.moderator?
|
57
|
+
@forum_post = @forum_thread.forum_posts.find(params[:id])
|
58
|
+
else
|
59
|
+
@forum_post = current_user.forum_posts.find(params[:id])
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def forum_post_params
|
64
|
+
params.require(:forum_post).permit(:body)
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
class SimpleDiscussion::ForumThreadsController < SimpleDiscussion::ApplicationController
|
2
|
+
before_action :authenticate_user!, only: [:mine, :participating, :new, :create]
|
3
|
+
before_action :set_forum_thread, only: [:show, :edit, :update]
|
4
|
+
before_action :require_moderator_or_author!, only: [:edit, :update]
|
5
|
+
|
6
|
+
def index
|
7
|
+
@forum_threads = ForumThread.pinned_first.sorted.includes(:user, :forum_category).paginate(page: page_number)
|
8
|
+
end
|
9
|
+
|
10
|
+
def answered
|
11
|
+
@forum_threads = ForumThread.solved.sorted.includes(:user, :forum_category).paginate(page: page_number)
|
12
|
+
render action: :index
|
13
|
+
end
|
14
|
+
|
15
|
+
def unanswered
|
16
|
+
@forum_threads = ForumThread.unsolved.sorted.includes(:user, :forum_category).paginate(page: page_number)
|
17
|
+
render action: :index
|
18
|
+
end
|
19
|
+
|
20
|
+
def mine
|
21
|
+
@forum_threads = ForumThread.where(user: current_user).sorted.includes(:user, :forum_category).paginate(page: page_number)
|
22
|
+
render action: :index
|
23
|
+
end
|
24
|
+
|
25
|
+
def participating
|
26
|
+
@forum_threads = ForumThread.includes(:user, :forum_category).joins(:forum_posts).where(forum_posts: { user_id: current_user.id }).distinct(forum_posts: :id).sorted.paginate(page: page_number)
|
27
|
+
render action: :index
|
28
|
+
end
|
29
|
+
|
30
|
+
def show
|
31
|
+
@forum_post = ForumPost.new
|
32
|
+
@forum_post.user = current_user
|
33
|
+
end
|
34
|
+
|
35
|
+
def new
|
36
|
+
@forum_thread = ForumThread.new
|
37
|
+
@forum_thread.forum_posts.new
|
38
|
+
end
|
39
|
+
|
40
|
+
def create
|
41
|
+
@forum_thread = current_user.forum_threads.new(forum_thread_params)
|
42
|
+
@forum_thread.forum_posts.each{ |post| post.user_id = current_user.id }
|
43
|
+
|
44
|
+
if @forum_thread.save
|
45
|
+
#ForumThreadNotificationJob.perform_later(@forum_thread.forum_posts.first.id)
|
46
|
+
redirect_to simple_discussion.forum_thread_path(@forum_thread)
|
47
|
+
else
|
48
|
+
render action: :new
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def edit
|
53
|
+
end
|
54
|
+
|
55
|
+
def update
|
56
|
+
if @forum_thread.update(forum_thread_params)
|
57
|
+
redirect_to simple_discussion.forum_thread_path(@forum_thread), notice: "Your changes were saved."
|
58
|
+
else
|
59
|
+
render action: :edit
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def set_forum_thread
|
66
|
+
@forum_thread = ForumThread.friendly.find(params[:id])
|
67
|
+
end
|
68
|
+
|
69
|
+
def forum_thread_params
|
70
|
+
params.require(:forum_thread).permit(:title, :forum_category_id, forum_posts_attributes: [:body])
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class SimpleDiscussion::NotificationsController < SimpleDiscussion::ApplicationController
|
2
|
+
before_action :authenticate_user!
|
3
|
+
before_action :set_forum_thread
|
4
|
+
|
5
|
+
def create
|
6
|
+
@forum_thread.toggle_subscription(current_user)
|
7
|
+
redirect_to simple_discussion.forum_thread_path(@forum_thread)
|
8
|
+
end
|
9
|
+
|
10
|
+
def show
|
11
|
+
redirect_to simple_discussion.forum_thread_path(@forum_thread)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def set_forum_thread
|
17
|
+
@forum_thread = ForumThread.friendly.find(params[:forum_thread_id])
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module SimpleDiscussion::ForumPostsHelper
|
2
|
+
# Override this to use avatars from other places than Gravatar
|
3
|
+
def avatar_tag(email)
|
4
|
+
gravatar_image_tag(email, gravatar: { size: 40 }, class: "rounded avatar")
|
5
|
+
end
|
6
|
+
|
7
|
+
def category_link(category)
|
8
|
+
link_to category.name, simple_discussion.forum_category_forum_threads_path(category),
|
9
|
+
style: "color: #{category.color}"
|
10
|
+
end
|
11
|
+
|
12
|
+
# Override this method to provide your own content formatting like Markdown
|
13
|
+
def formatted_content(text)
|
14
|
+
simple_format(text)
|
15
|
+
end
|
16
|
+
|
17
|
+
def forum_post_classes(forum_post)
|
18
|
+
klasses = ["forum-post", "card", "mb-3"]
|
19
|
+
klasses << "solved" if forum_post.solved?
|
20
|
+
klasses << "original-poster" if forum_post.user == @forum_thread.user
|
21
|
+
klasses
|
22
|
+
end
|
23
|
+
|
24
|
+
def forum_user_badge(user)
|
25
|
+
if user.respond_to?(:moderator) && user.moderator?
|
26
|
+
content_tag :span, "Mod", class: "badge badge-default"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module SimpleDiscussion::ForumThreadsHelper
|
2
|
+
# Used for flagging links in the navbar as active
|
3
|
+
def forum_link_to(path, opts={}, &block)
|
4
|
+
link_to path, class: forum_link_class(path, opts), &block
|
5
|
+
end
|
6
|
+
|
7
|
+
def forum_link_class(matches, opts={})
|
8
|
+
case matches
|
9
|
+
when Array
|
10
|
+
"active" if matches.any?{ |m| request.path.starts_with?(m) }
|
11
|
+
when String
|
12
|
+
"active" if opts.fetch(:exact, false) ? request.path == matches : request.path.starts_with?(matches)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# A nice hack to manipulate the layout so we can have sub-layouts
|
17
|
+
# without any changes in the user's application.
|
18
|
+
#
|
19
|
+
# We use this for rendering the sidebar layout for all the forum pages
|
20
|
+
#
|
21
|
+
# https://mattbrictson.com/easier-nested-layouts-in-rails
|
22
|
+
#
|
23
|
+
def parent_layout(layout)
|
24
|
+
@view_flow.set(:layout, output_buffer)
|
25
|
+
output = render(file: "layouts/#{layout}")
|
26
|
+
self.output_buffer = ActionView::OutputBuffer.new(output)
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class ForumCategory < ApplicationRecord
|
2
|
+
extend FriendlyId
|
3
|
+
friendly_id :name, use: :slugged
|
4
|
+
|
5
|
+
scope :sorted, ->{ order(name: :asc) }
|
6
|
+
|
7
|
+
validates :name, :slug, :color, presence: true
|
8
|
+
|
9
|
+
def color
|
10
|
+
colour = super
|
11
|
+
colour.start_with?("#") ? colour : "##{colour}"
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class ForumPost < ApplicationRecord
|
2
|
+
belongs_to :forum_thread, counter_cache: true, touch: true
|
3
|
+
belongs_to :user
|
4
|
+
has_many :reactions, as: :reactable
|
5
|
+
|
6
|
+
validates :user_id, :body, presence: true
|
7
|
+
|
8
|
+
scope :sorted, ->{ order(:created_at) }
|
9
|
+
|
10
|
+
after_update :solve_forum_thread, if: :solved?
|
11
|
+
|
12
|
+
def solve_forum_thread
|
13
|
+
forum_thread.update(solved: true)
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class ForumSubscription < ApplicationRecord
|
2
|
+
belongs_to :forum_thread
|
3
|
+
belongs_to :user
|
4
|
+
|
5
|
+
scope :optin, ->{ where(subscription_type: :optin) }
|
6
|
+
scope :optout, ->{ where(subscription_type: :optout) }
|
7
|
+
|
8
|
+
validates :subscription_type, presence: true, inclusion: { in: %w{ optin optout } }
|
9
|
+
validates :user_id, uniqueness: { scope: :forum_thread_id }
|
10
|
+
|
11
|
+
def toggle!
|
12
|
+
case subscription_type
|
13
|
+
when "optin"
|
14
|
+
update(subscription_type: "optout")
|
15
|
+
when "optout"
|
16
|
+
update(subscription_type: "optin")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
class ForumThread < ApplicationRecord
|
2
|
+
extend FriendlyId
|
3
|
+
friendly_id :title, use: :slugged
|
4
|
+
|
5
|
+
belongs_to :forum_category
|
6
|
+
belongs_to :user
|
7
|
+
has_many :forum_posts
|
8
|
+
has_many :forum_subscriptions
|
9
|
+
has_many :optin_subscribers, ->{ where(forum_subscriptions: { subscription_type: :optin }) }, through: :forum_subscriptions, source: :user
|
10
|
+
has_many :optout_subscribers, ->{ where(forum_subscriptions: { subscription_type: :optout }) }, through: :forum_subscriptions, source: :user
|
11
|
+
has_many :users, through: :forum_posts
|
12
|
+
|
13
|
+
accepts_nested_attributes_for :forum_posts
|
14
|
+
|
15
|
+
validates :forum_category, presence: true
|
16
|
+
validates :user_id, :title, presence: true
|
17
|
+
validates_associated :forum_posts
|
18
|
+
|
19
|
+
scope :pinned_first, ->{ order(pinned: :desc) }
|
20
|
+
scope :solved, ->{ where(solved: true) }
|
21
|
+
scope :sorted, ->{ order(updated_at: :desc) }
|
22
|
+
scope :unpinned, ->{ where.not(pinned: true) }
|
23
|
+
scope :unsolved, ->{ where.not(solved: true) }
|
24
|
+
|
25
|
+
def subscribed_users
|
26
|
+
(users + optin_subscribers).uniq - optout_subscribers
|
27
|
+
end
|
28
|
+
|
29
|
+
def subscription_for(user)
|
30
|
+
return nil if user.nil?
|
31
|
+
forum_subscriptions.find_by(user_id: user.id)
|
32
|
+
end
|
33
|
+
|
34
|
+
def subscribed?(user)
|
35
|
+
return false if user.nil?
|
36
|
+
|
37
|
+
subscription = subscription_for(user)
|
38
|
+
|
39
|
+
if subscription.present?
|
40
|
+
subscription.subscription_type == "optin"
|
41
|
+
else
|
42
|
+
forum_posts.where(user_id: user.id).any?
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def toggle_subscription(user)
|
47
|
+
subscription = subscription_for(user)
|
48
|
+
|
49
|
+
if subscription.present?
|
50
|
+
subscription.toggle!
|
51
|
+
elsif forum_posts.where(user_id: user.id).any?
|
52
|
+
forum_subscriptions.create(user: user, subscription_type: "optout")
|
53
|
+
else
|
54
|
+
forum_subscriptions.create(user: user, subscription_type: "optin")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def subscribed_reason(user)
|
59
|
+
return "You’re not receiving notifications from this thread." if user.nil?
|
60
|
+
|
61
|
+
subscription = subscription_for(user)
|
62
|
+
|
63
|
+
if subscription.present?
|
64
|
+
if subscription.subscription_type == "optout"
|
65
|
+
"You're ignoring this thread."
|
66
|
+
elsif subscription.subscription_type == "optin"
|
67
|
+
"You're receiving notifications because you've subscribed to this thread."
|
68
|
+
end
|
69
|
+
elsif forum_posts.where(user_id: user.id).any?
|
70
|
+
"You're receiving notifications because you've posted in this thread."
|
71
|
+
else
|
72
|
+
"You're not receiving notifications from this thread."
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
<div class="row">
|
2
|
+
<div class="col-sm-3">
|
3
|
+
|
4
|
+
<div class="card card-block">
|
5
|
+
<%= link_to 'Ask A Question', simple_discussion.new_forum_thread_path, class: "btn btn-outline-primary btn-block" %>
|
6
|
+
<hr />
|
7
|
+
|
8
|
+
<div class="forum-thread-filters">
|
9
|
+
<h5><strong>Filters</strong></h5>
|
10
|
+
<div><%= forum_link_to simple_discussion.forum_threads_path, exact: true do %><%= icon "bars" %> All Threads <% end %></div>
|
11
|
+
<% if user_signed_in? %>
|
12
|
+
<div><%= forum_link_to simple_discussion.mine_forum_threads_path do %><%= icon "user-circle-o" %> My Questions<% end %></div>
|
13
|
+
<div><%= forum_link_to simple_discussion.participating_forum_threads_path do %><%= icon "comments-o" %> Participating<% end %></div>
|
14
|
+
<% end %>
|
15
|
+
<div><%= forum_link_to simple_discussion.answered_forum_threads_path do %><%= icon "check" %> Answered<% end %></div>
|
16
|
+
<div><%= forum_link_to simple_discussion.unanswered_forum_threads_path do %><%= icon "question" %> Unanswered<% end %></div>
|
17
|
+
</div>
|
18
|
+
|
19
|
+
<hr />
|
20
|
+
|
21
|
+
<div class="forum-thread-filters">
|
22
|
+
<p><strong>By Category</strong></p>
|
23
|
+
<div><%= forum_link_to simple_discussion.forum_threads_path, exact: true do %><%= icon "circle" %> All<% end %></div>
|
24
|
+
<% ForumCategory.sorted.each do |category| %>
|
25
|
+
<div>
|
26
|
+
<%= forum_link_to simple_discussion.forum_category_forum_threads_path(category) do %>
|
27
|
+
<%= icon "circle", style: "color: #{category.color}" %>
|
28
|
+
<%= category.name %>
|
29
|
+
<% end %>
|
30
|
+
</div>
|
31
|
+
<% end %>
|
32
|
+
</div>
|
33
|
+
|
34
|
+
<% if @forum_thread.present? && @forum_thread.persisted? %>
|
35
|
+
<hr />
|
36
|
+
|
37
|
+
<%# User has not posted in the thread or subscribed %>
|
38
|
+
<h5>Notifications</h5>
|
39
|
+
|
40
|
+
<%= link_to simple_discussion.forum_thread_notifications_path(@forum_thread), method: :post, class: "btn btn-secondary btn-sm btn-block mb-2" do %>
|
41
|
+
<% if @forum_thread.subscribed? current_user %>
|
42
|
+
<%= icon "bell-slash" %> Unsubscribe
|
43
|
+
<% else %>
|
44
|
+
<%= icon "bell" %> Subscribe
|
45
|
+
<% end %>
|
46
|
+
<% end %>
|
47
|
+
|
48
|
+
<small><%= @forum_thread.subscribed_reason(current_user) %></small>
|
49
|
+
<% end %>
|
50
|
+
</div>
|
51
|
+
|
52
|
+
</div>
|
53
|
+
|
54
|
+
<div class="col">
|
55
|
+
<%= yield %>
|
56
|
+
</div>
|
57
|
+
</div>
|
58
|
+
|
59
|
+
<% parent_layout("application") %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<hr/>
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<%= form_for [@forum_thread, @forum_post],
|
2
|
+
url: (@forum_post.persisted? ? simple_discussion.forum_thread_forum_post_path(@forum_thread, @forum_post) : simple_discussion.forum_thread_forum_posts_path(@forum_thread)),
|
3
|
+
html: { data: { behavior: "comment-form" } } do |f| %>
|
4
|
+
|
5
|
+
<% if @forum_post.errors.any? %>
|
6
|
+
<div id="error_explanation">
|
7
|
+
<h2><%= pluralize(@forum_post.errors.count, "error") %> prohibited this forum_post from being saved:</h2>
|
8
|
+
|
9
|
+
<ul>
|
10
|
+
<% @forum_post.errors.full_messages.each do |message| %>
|
11
|
+
<li><%= message %></li>
|
12
|
+
<% end %>
|
13
|
+
</ul>
|
14
|
+
</div>
|
15
|
+
<% end %>
|
16
|
+
|
17
|
+
<div class="form-group">
|
18
|
+
<%= f.text_area :body, placeholder: "Add a comment", rows: 8, class: "form-control simplemde", data: { behavior: "comment-body" } %>
|
19
|
+
</div>
|
20
|
+
|
21
|
+
<div class="text-right">
|
22
|
+
<div class="pull-left">
|
23
|
+
<small>
|
24
|
+
<%# Describe text formatting options here with a link %>
|
25
|
+
<%#= link_to "Parsed with Markdown", "https://guides.github.com/features/mastering-markdown/", target: "_blank" %>
|
26
|
+
</small>
|
27
|
+
</div>
|
28
|
+
|
29
|
+
<%= f.button "#{"Update" unless f.object.new_record?} Comment", class: "btn btn-primary", data: {disable_with: "<i class='fa fa-spinner fa-spin'></i> Saving comment..."} %>
|
30
|
+
</div>
|
31
|
+
|
32
|
+
<% end %>
|
@@ -0,0 +1,58 @@
|
|
1
|
+
<%# We don't currently cache the forum posts because they have permissions to deal with %>
|
2
|
+
|
3
|
+
<%= content_tag :div, id: dom_id(forum_post), class: forum_post_classes(forum_post) do %>
|
4
|
+
<div class="card-header">
|
5
|
+
|
6
|
+
<% if is_moderator_or_owner?(forum_post) %>
|
7
|
+
<div class="pull-right">
|
8
|
+
<%= link_to icon("pencil"), simple_discussion.edit_forum_thread_forum_post_path(@forum_thread, forum_post),
|
9
|
+
class: "text-muted",
|
10
|
+
data: { toggle: "tooltip", placement: "left" },
|
11
|
+
title: "Edit this post"
|
12
|
+
%>
|
13
|
+
</div>
|
14
|
+
<% end %>
|
15
|
+
|
16
|
+
<div>
|
17
|
+
<%= avatar_tag(forum_post.user.email) %>
|
18
|
+
|
19
|
+
<strong class="forum-post-user">
|
20
|
+
<%= forum_post.user.name %> <%= forum_user_badge(forum_post.user) %>
|
21
|
+
</strong>
|
22
|
+
<small>
|
23
|
+
commented on
|
24
|
+
<%= link_to forum_post.created_at.strftime("%b %d, %Y"), simple_discussion.forum_thread_path(@forum_thread, anchor: "forum_post_#{forum_post.id}") %>:
|
25
|
+
</small>
|
26
|
+
</div>
|
27
|
+
</div>
|
28
|
+
|
29
|
+
<div class="card-block">
|
30
|
+
<%= formatted_content forum_post.body %>
|
31
|
+
</div>
|
32
|
+
|
33
|
+
<% if @forum_thread.solved? && forum_post.solved? %>
|
34
|
+
<div class="card-footer">
|
35
|
+
<div class="pull-right">
|
36
|
+
<strong class="text-success"><%= icon("check") %> Solved</strong>
|
37
|
+
|
38
|
+
<% if is_moderator_or_owner?(@forum_thread) %>
|
39
|
+
<small>
|
40
|
+
<%= link_to "Undo", simple_discussion.unsolved_forum_thread_forum_post_path(@forum_thread, forum_post), method: :put %>
|
41
|
+
</small
|
42
|
+
<% end %>
|
43
|
+
</div>
|
44
|
+
</div>
|
45
|
+
|
46
|
+
<% elsif is_moderator_or_owner?(@forum_thread) %>
|
47
|
+
<div class="card-footer">
|
48
|
+
<div class="pull-right">
|
49
|
+
<small>
|
50
|
+
<%= link_to simple_discussion.solved_forum_thread_forum_post_path(@forum_thread, forum_post), method: :put do %>
|
51
|
+
<%= icon("check") %>
|
52
|
+
This solved my question
|
53
|
+
<% end %>
|
54
|
+
</small>
|
55
|
+
</div>
|
56
|
+
</div>
|
57
|
+
<% end %>
|
58
|
+
<% end %>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<p><small><%= link_to "← Back to the thread", simple_discussion.forum_thread_path(@forum_thread) %></small></p>
|
2
|
+
|
3
|
+
<h2><%= content_tag :span, "Pinned", class: "text-muted" if @forum_thread.pinned? %> <%= @forum_thread.title %></h2>
|
4
|
+
|
5
|
+
<p class="thread-details">
|
6
|
+
<strong><%= category_link(@forum_thread.forum_category) %></strong>
|
7
|
+
• Asked <%= time_ago_in_words @forum_thread.created_at %> by <%= @forum_thread.user.name %>
|
8
|
+
</p>
|
9
|
+
|
10
|
+
<br />
|
11
|
+
|
12
|
+
<%= content_tag :div, id: dom_id(@forum_post), class: forum_post_classes(@forum_post) do %>
|
13
|
+
<div class="card-header">
|
14
|
+
<div>
|
15
|
+
<%= avatar_tag(@forum_post.user.email) %>
|
16
|
+
<strong class="forum-post-user"><%= @forum_post.user.name %></strong>
|
17
|
+
<small> commented on <%= link_to @forum_post.created_at.strftime("%b %d, %Y"), simple_discussion.forum_thread_url(@forum_thread, anchor: "forum_post_#{@forum_post.id}") %>:</small>
|
18
|
+
</div>
|
19
|
+
</div>
|
20
|
+
|
21
|
+
<div class="card-block">
|
22
|
+
<%= render "form" %>
|
23
|
+
</div>
|
24
|
+
<% end %>
|
@@ -0,0 +1,44 @@
|
|
1
|
+
<%= form_for @forum_thread,
|
2
|
+
url: (@forum_thread.persisted? ? simple_discussion.forum_thread_path(@forum_thread) : simple_discussion.forum_threads_path),
|
3
|
+
html: { data: {behavior: "comment-form"} } do |f| %>
|
4
|
+
|
5
|
+
<% if @forum_thread.errors.any? %>
|
6
|
+
<div id="error_explanation">
|
7
|
+
<h2><%= pluralize(@forum_thread.errors.count, "error") %> prohibited this forum_thread from being saved:</h2>
|
8
|
+
|
9
|
+
<ul>
|
10
|
+
<% @forum_thread.errors.full_messages.each do |message| %>
|
11
|
+
<li><%= message %></li>
|
12
|
+
<% end %>
|
13
|
+
</ul>
|
14
|
+
</div>
|
15
|
+
<% end %>
|
16
|
+
|
17
|
+
<div class="form-group">
|
18
|
+
<%= f.label :forum_category_id, "Choose a Category" %>
|
19
|
+
<%= f.collection_select :forum_category_id, ForumCategory.sorted, :id, :name, {include_blank: "Pick a category..."}, {autofocus: true, class: "form-control"} %>
|
20
|
+
</div>
|
21
|
+
|
22
|
+
<div class="form-group">
|
23
|
+
<%= f.label :title %>
|
24
|
+
<%= f.text_field :title, placeholder: "How do I...?", class: "form-control" %>
|
25
|
+
</div>
|
26
|
+
|
27
|
+
<% if local_assigns.fetch(:posts, true) %>
|
28
|
+
<%= f.fields_for :forum_posts do |p| %>
|
29
|
+
<div class="form-group">
|
30
|
+
<%= p.label :body, "What do you need help with?" %>
|
31
|
+
<%= p.text_area :body, placeholder: "Add a comment", rows: 10, class: "form-control simplemde", data: { behavior: "comment-body" } %>
|
32
|
+
</div>
|
33
|
+
<% end %>
|
34
|
+
<% end %>
|
35
|
+
|
36
|
+
<div class="form-group text-right">
|
37
|
+
<% if f.object.new_record? %>
|
38
|
+
<%= f.button "Ask Your Question", class: "btn btn-primary", data: {disable_with: "<i class='fa fa-spinner fa-spin'></i> Saving..."} %>
|
39
|
+
<% else %>
|
40
|
+
<%= f.button "Update Thread", class: "btn btn-primary", data: {disable_with: "<i class='fa fa-spinner fa-spin'></i> Saving..."} %>
|
41
|
+
<% end %>
|
42
|
+
</div>
|
43
|
+
|
44
|
+
<% end %>
|
@@ -0,0 +1,37 @@
|
|
1
|
+
<%= cache forum_thread do %>
|
2
|
+
<div class="forum-thread">
|
3
|
+
<div class="row">
|
4
|
+
|
5
|
+
<div class="col-sm-1 text-center">
|
6
|
+
<%= avatar_tag(forum_thread.user.email) %>
|
7
|
+
</div>
|
8
|
+
|
9
|
+
<div class="col">
|
10
|
+
<h4>
|
11
|
+
<% if forum_thread.solved? %>
|
12
|
+
<span class="text-success"><%= icon "check-circle" %></span>
|
13
|
+
<% end %>
|
14
|
+
|
15
|
+
<%= link_to simple_discussion.forum_thread_path(forum_thread) do %>
|
16
|
+
<%= icon "thumb-tack", class: "text-muted" if forum_thread.pinned? %> <%= forum_thread.title %>
|
17
|
+
<% end %>
|
18
|
+
</h4>
|
19
|
+
|
20
|
+
<div class="thread-details">
|
21
|
+
<strong><%= category_link(forum_thread.forum_category) %></strong>
|
22
|
+
• Asked <%= time_ago_in_words forum_thread.created_at %> by <%= forum_thread.user.name %>
|
23
|
+
</div>
|
24
|
+
|
25
|
+
<p class="text-muted"><%= truncate(forum_thread.forum_posts.first.body, length: 200) %></p>
|
26
|
+
</div>
|
27
|
+
|
28
|
+
<div class="col-sm-1 text-center">
|
29
|
+
<%= link_to simple_discussion.forum_thread_path(forum_thread), class: "thread-posts-count" do %>
|
30
|
+
<span class="count"><%= forum_thread.forum_posts_count %></span>
|
31
|
+
<small><%= "post".pluralize(forum_thread.forum_posts_count) %></small>
|
32
|
+
<% end %>
|
33
|
+
</div>
|
34
|
+
|
35
|
+
</div>
|
36
|
+
</div>
|
37
|
+
<% end %>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<div class="card card-block mb-3">
|
2
|
+
<%= render partial: "simple_discussion/forum_threads/forum_thread", collection: @forum_threads, spacer_template: "shared/spacer" %>
|
3
|
+
|
4
|
+
<% if @forum_threads.none? %>
|
5
|
+
<div>No results found for your search. Check out <%= link_to "the latest questions", simple_discussion.forum_threads_path %> instead?</div>
|
6
|
+
<% end %>
|
7
|
+
</div>
|
8
|
+
|
9
|
+
<div class="forum-threads-nav text-center">
|
10
|
+
<%= will_paginate @forum_threads, url_builder: simple_discussion, renderer: SimpleDiscussion::BootstrapLinkRenderer %>
|
11
|
+
</div>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<h1><%= icon "thumb-tack", class: "text-muted" if @forum_thread.pinned? %> <%= @forum_thread.title %></h1>
|
2
|
+
|
3
|
+
<% if is_moderator_or_owner?(@forum_thread) %>
|
4
|
+
<div class="pull-right">
|
5
|
+
<%= link_to icon("pencil"), simple_discussion.edit_forum_thread_path(@forum_thread),
|
6
|
+
class: "text-muted",
|
7
|
+
data: { toggle: "tooltip", placement: "left" },
|
8
|
+
title: "Edit this thread" %>
|
9
|
+
</div>
|
10
|
+
<% end %>
|
11
|
+
|
12
|
+
<p class="thread-details">
|
13
|
+
<strong><%= category_link(@forum_thread.forum_category) %></strong>
|
14
|
+
• Asked <%= time_ago_in_words @forum_thread.created_at %> by <%= @forum_thread.user.name %>
|
15
|
+
</p>
|
16
|
+
|
17
|
+
<%= render partial: "simple_discussion/forum_posts/forum_post", collection: @forum_thread.forum_posts.includes(:user).sorted %>
|
18
|
+
|
19
|
+
<%= render partial: "simple_discussion/forum_posts/form" if user_signed_in? %>
|
data/config/routes.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
SimpleDiscussion::Engine.routes.draw do
|
2
|
+
scope module: :simple_discussion do
|
3
|
+
resources :forum_threads, path: :threads do
|
4
|
+
collection do
|
5
|
+
get :answered
|
6
|
+
get :unanswered
|
7
|
+
get :mine
|
8
|
+
get :participating
|
9
|
+
get "category/:id", to: "forum_categories#index", as: :forum_category
|
10
|
+
end
|
11
|
+
|
12
|
+
resources :forum_posts, path: :posts do
|
13
|
+
member do
|
14
|
+
put :solved
|
15
|
+
put :unsolved
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
resource :notifications
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
root to: "simple_discussion/forum_threads#index"
|
24
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class CreateForumCategories < ActiveRecord::Migration[4.2]
|
2
|
+
def change
|
3
|
+
create_table :forum_categories, force: :cascade do |t|
|
4
|
+
t.string :name, null: false
|
5
|
+
t.string :slug, null: false
|
6
|
+
t.string :color, default: "000000"
|
7
|
+
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
|
11
|
+
ForumCategory.reset_column_information
|
12
|
+
|
13
|
+
ForumCategory.create(
|
14
|
+
name: "General",
|
15
|
+
color: "#4ea1d3",
|
16
|
+
)
|
17
|
+
|
18
|
+
ForumCategory.create(
|
19
|
+
name: "Feedback",
|
20
|
+
color: "#16bc9c",
|
21
|
+
)
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class CreateForumThreads < ActiveRecord::Migration[4.2]
|
2
|
+
def change
|
3
|
+
create_table :forum_threads, force: :cascade do |t|
|
4
|
+
t.references :forum_category, foreign_key: true
|
5
|
+
t.references :user, foreign_key: true
|
6
|
+
t.string :title, null: false
|
7
|
+
t.string :slug, null: false
|
8
|
+
t.integer :forum_posts_count, default: 0
|
9
|
+
t.boolean :pinned, default: false
|
10
|
+
t.boolean :solved, default: false
|
11
|
+
|
12
|
+
t.timestamps
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class CreateForumPosts < ActiveRecord::Migration[4.2]
|
2
|
+
def change
|
3
|
+
create_table :forum_posts, force: :cascade do |t|
|
4
|
+
t.references :forum_thread, foreign_key: true
|
5
|
+
t.references :user, foreign_key: true
|
6
|
+
t.text :body
|
7
|
+
t.boolean :solved, default: false
|
8
|
+
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class CreateForumSubscriptions < ActiveRecord::Migration[4.2]
|
2
|
+
def change
|
3
|
+
create_table :forum_subscriptions, force: :cascade do |t|
|
4
|
+
t.references :forum_thread, foreign_key: true
|
5
|
+
t.references :user, foreign_key: true
|
6
|
+
t.string :subscription_type
|
7
|
+
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/lib/simple_discussion.rb
CHANGED
@@ -1,5 +1,61 @@
|
|
1
|
+
require 'friendly_id'
|
2
|
+
require 'will_paginate'
|
3
|
+
require 'gravatar_image_tag'
|
4
|
+
|
1
5
|
require "simple_discussion/version"
|
6
|
+
require "simple_discussion/engine"
|
7
|
+
require "simple_discussion/forum_user"
|
8
|
+
|
9
|
+
require 'will_paginate/view_helpers/action_view'
|
2
10
|
|
3
11
|
module SimpleDiscussion
|
4
|
-
#
|
12
|
+
# This code serves two purposes
|
13
|
+
# 1. It patches will_paginate to work with scoped and mounted Rails engines
|
14
|
+
# by adding in the url_builder option
|
15
|
+
# 2. It adds Bootstrap 4 styling to will_paginate
|
16
|
+
|
17
|
+
class BootstrapLinkRenderer < WillPaginate::ActionView::LinkRenderer
|
18
|
+
|
19
|
+
# This method adds the `url_builder` option so we can pass in the
|
20
|
+
# mounted Rails engine's scope for will_paginate
|
21
|
+
def url(page)
|
22
|
+
@base_url_params ||= begin
|
23
|
+
url_params = merge_get_params(default_url_params)
|
24
|
+
merge_optional_params(url_params)
|
25
|
+
end
|
26
|
+
|
27
|
+
url_params = @base_url_params.dup
|
28
|
+
add_current_page_param(url_params, page)
|
29
|
+
|
30
|
+
# Add optional url_builder support
|
31
|
+
(@options[:url_builder] || @template).url_for(url_params)
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
def html_container(html)
|
36
|
+
tag :nav, tag(:ul, html, class: ul_class)
|
37
|
+
end
|
38
|
+
|
39
|
+
def page_number(page)
|
40
|
+
item_class = if(page == current_page)
|
41
|
+
'active page-item'
|
42
|
+
else
|
43
|
+
'page-item'
|
44
|
+
end
|
45
|
+
|
46
|
+
tag :li, link(page, page, :rel => rel_value(page), :class => 'page-link'), :class => item_class
|
47
|
+
end
|
48
|
+
|
49
|
+
def gap
|
50
|
+
tag :li, link('…'.html_safe, '#', :class => 'page-link'), :class => 'page-item disabled'
|
51
|
+
end
|
52
|
+
|
53
|
+
def previous_or_next_page(page, text, classname)
|
54
|
+
tag :li, link(text, page || '#', :class => 'page-link'), :class => [(classname[0..3] if @options[:page_links]), (classname if @options[:page_links]), ('disabled' unless page), 'page-item'].join(' ')
|
55
|
+
end
|
56
|
+
|
57
|
+
def ul_class
|
58
|
+
["pagination", container_attributes[:class]].compact.join(" ")
|
59
|
+
end
|
60
|
+
end
|
5
61
|
end
|
data/simple_discussion.gemspec
CHANGED
@@ -21,7 +21,9 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
22
|
spec.require_paths = ["lib"]
|
23
23
|
|
24
|
-
spec.
|
25
|
-
spec.
|
26
|
-
spec.
|
24
|
+
spec.add_dependency 'font-awesome-sass', '~> 4.7.0'
|
25
|
+
spec.add_dependency 'friendly_id', '>= 5.2.0'
|
26
|
+
spec.add_dependency 'gravatar_image_tag'
|
27
|
+
spec.add_dependency 'rails', '>= 4.2'
|
28
|
+
spec.add_dependency 'will_paginate', '>= 3.1.0'
|
27
29
|
end
|
metadata
CHANGED
@@ -1,57 +1,85 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple_discussion
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Oliver
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-08-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: font-awesome-sass
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
20
|
-
type: :
|
19
|
+
version: 4.7.0
|
20
|
+
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 4.7.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: friendly_id
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
34
|
-
type: :
|
33
|
+
version: 5.2.0
|
34
|
+
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 5.2.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: gravatar_image_tag
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
48
|
-
type: :
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rails
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '4.2'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '4.2'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: will_paginate
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 3.1.0
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
53
81
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
82
|
+
version: 3.1.0
|
55
83
|
description: A simple, extensible Rails forum
|
56
84
|
email:
|
57
85
|
- excid3@gmail.com
|
@@ -66,9 +94,39 @@ files:
|
|
66
94
|
- LICENSE.txt
|
67
95
|
- README.md
|
68
96
|
- Rakefile
|
97
|
+
- app/assets/stylesheets/simple_discussion.scss
|
98
|
+
- app/controllers/simple_discussion/application_controller.rb
|
99
|
+
- app/controllers/simple_discussion/forum_categories_controller.rb
|
100
|
+
- app/controllers/simple_discussion/forum_posts_controller.rb
|
101
|
+
- app/controllers/simple_discussion/forum_threads_controller.rb
|
102
|
+
- app/controllers/simple_discussion/notifications_controller.rb
|
103
|
+
- app/helpers/simple_discussion/forum_posts_helper.rb
|
104
|
+
- app/helpers/simple_discussion/forum_threads_helper.rb
|
105
|
+
- app/models/forum_category.rb
|
106
|
+
- app/models/forum_post.rb
|
107
|
+
- app/models/forum_subscription.rb
|
108
|
+
- app/models/forum_thread.rb
|
109
|
+
- app/views/layouts/simple_discussion.html.erb
|
110
|
+
- app/views/shared/_spacer.html.erb
|
111
|
+
- app/views/simple_discussion/forum_posts/_form.html.erb
|
112
|
+
- app/views/simple_discussion/forum_posts/_forum_post.html.erb
|
113
|
+
- app/views/simple_discussion/forum_posts/edit.html.erb
|
114
|
+
- app/views/simple_discussion/forum_threads/_form.html.erb
|
115
|
+
- app/views/simple_discussion/forum_threads/_forum_thread.html.erb
|
116
|
+
- app/views/simple_discussion/forum_threads/edit.html.erb
|
117
|
+
- app/views/simple_discussion/forum_threads/index.html.erb
|
118
|
+
- app/views/simple_discussion/forum_threads/new.html.erb
|
119
|
+
- app/views/simple_discussion/forum_threads/show.html.erb
|
69
120
|
- bin/console
|
70
121
|
- bin/setup
|
122
|
+
- config/routes.rb
|
123
|
+
- db/migrate/20170417012930_create_forum_categories.rb
|
124
|
+
- db/migrate/20170417012931_create_forum_threads.rb
|
125
|
+
- db/migrate/20170417012932_create_forum_posts.rb
|
126
|
+
- db/migrate/20170417012933_create_forum_subscriptions.rb
|
71
127
|
- lib/simple_discussion.rb
|
128
|
+
- lib/simple_discussion/engine.rb
|
129
|
+
- lib/simple_discussion/forum_user.rb
|
72
130
|
- lib/simple_discussion/version.rb
|
73
131
|
- simple_discussion.gemspec
|
74
132
|
homepage: https://github.com/excid3/simple_discussion
|