Feature-comment-smiles complete (fix Retrospring/bugs#42)
This commit is contained in:
parent
1c80c70dd9
commit
2204227273
|
@ -0,0 +1,41 @@
|
|||
$(document).on "click", "button[name=ab-smile-comment]", ->
|
||||
btn = $(this)
|
||||
cid = btn[0].dataset.cId
|
||||
action = btn[0].dataset.action
|
||||
count = Number $("span#ab-comment-smile-count-#{cid}").html()
|
||||
btn[0].dataset.loadingText = "<i class=\"fa fa-meh-o fa-spin\"></i> <span id=\"ab-smile-count-#{cid}\">#{count}</span>"
|
||||
btn.button "loading"
|
||||
|
||||
target_url = switch action
|
||||
when 'smile'
|
||||
count++
|
||||
'/ajax/create_comment_smile'
|
||||
when 'unsmile'
|
||||
count--
|
||||
'/ajax/destroy_comment_smile'
|
||||
|
||||
success = false
|
||||
|
||||
$.ajax
|
||||
url: target_url
|
||||
type: 'POST'
|
||||
data:
|
||||
id: cid
|
||||
success: (data, status, jqxhr) ->
|
||||
success = data.success
|
||||
if success
|
||||
$("span#ab-comment-smile-count-#{cid}").html(count)
|
||||
showNotification data.message, data.success
|
||||
error: (jqxhr, status, error) ->
|
||||
console.log jqxhr, status, error
|
||||
showNotification "An error occurred, a developer should check the console for details", false
|
||||
complete: (jqxhr, status) ->
|
||||
btn.button "reset"
|
||||
if success
|
||||
switch action
|
||||
when 'smile'
|
||||
btn[0].dataset.action = 'unsmile'
|
||||
btn.html "<i class=\"fa fa-frown-o\"></i> <span id=\"ab-comment-smile-count-#{cid}\">#{count}</span>"
|
||||
when 'unsmile'
|
||||
btn[0].dataset.action = 'smile'
|
||||
btn.html "<i class=\"fa fa-smile-o\"></i> <span id=\"ab-comment-smile-count-#{cid}\">#{count}</span>"
|
|
@ -38,4 +38,4 @@ $(document).on "click", "button[name=ab-smile]", ->
|
|||
btn.html "<i class=\"fa fa-frown-o\"></i> <span id=\"ab-smile-count-#{aid}\">#{count}</span>"
|
||||
when 'unsmile'
|
||||
btn[0].dataset.action = 'smile'
|
||||
btn.html "<i class=\"fa fa-smile-o\"></i> <span id=\"ab-smile-count-#{aid}\">#{count}</span>"
|
||||
btn.html "<i class=\"fa fa-smile-o\"></i> <span id=\"ab-smile-count-#{aid}\">#{count}</span>"
|
||||
|
|
|
@ -6,6 +6,7 @@ body {
|
|||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
@import "scss/generic";
|
||||
@import "scss/answerbox";
|
||||
@import "scss/comments";
|
||||
@import "scss/entry";
|
||||
|
|
|
@ -41,3 +41,19 @@
|
|||
font-size: 12px;
|
||||
line-height: 1.3em;
|
||||
}
|
||||
|
||||
.answerbox [name="ab-smile"], .answerbox [name="ab-smile-comment"] {
|
||||
padding: 6px 11px;
|
||||
padding-left: 21px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border: none;
|
||||
|
||||
i.fa.fa-smile-o, i.fa.fa-frown-o, i.fa.fa-meh-o {
|
||||
position: absolute;
|
||||
font-size: 3em;
|
||||
left: -13px;
|
||||
top: -10px;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
.user-list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.user-list-entry-smiles {
|
||||
* {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
img {
|
||||
height: 64px
|
||||
}
|
||||
|
||||
span {
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
|
@ -36,4 +36,42 @@ class Ajax::SmileController < ApplicationController
|
|||
@message = "Successfully unsmiled answer."
|
||||
@success = true
|
||||
end
|
||||
|
||||
def create_comment
|
||||
params.require :id
|
||||
|
||||
comment = Comment.find(params[:id])
|
||||
|
||||
begin
|
||||
current_user.smile_comment comment
|
||||
rescue
|
||||
@status = :fail
|
||||
@message = "You have already smiled that comment."
|
||||
@success = false
|
||||
return
|
||||
end
|
||||
|
||||
@status = :okay
|
||||
@message = "Successfully smiled comment."
|
||||
@success = true
|
||||
end
|
||||
|
||||
def destroy_comment
|
||||
params.require :id
|
||||
|
||||
comment = Comment.find(params[:id])
|
||||
|
||||
begin
|
||||
current_user.unsmile_comment comment
|
||||
rescue
|
||||
@status = :fail
|
||||
@message = "You have not smiled that comment."
|
||||
@success = false
|
||||
return
|
||||
end
|
||||
|
||||
@status = :okay
|
||||
@message = "Successfully unsmiled comment."
|
||||
@success = true
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,6 +3,7 @@ class Comment < ActiveRecord::Base
|
|||
belongs_to :answer
|
||||
validates :user_id, presence: true
|
||||
validates :answer_id, presence: true
|
||||
has_many :smiles, class_name: "CommentSmile", foreign_key: :comment_id, dependent: :destroy
|
||||
|
||||
validates :content, length: { maximum: 160 }
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
class CommentSmile < ActiveRecord::Base
|
||||
belongs_to :user
|
||||
belongs_to :comment
|
||||
validates :user_id, presence: true, uniqueness: { scope: :comment_id, message: "already smiled comment" }
|
||||
validates :comment_id, presence: true
|
||||
|
||||
after_create do
|
||||
Notification.notify comment.user, self unless comment.user == user
|
||||
user.increment! :comment_smiled_count
|
||||
comment.increment! :smile_count
|
||||
end
|
||||
|
||||
before_destroy do
|
||||
Notification.denotify comment.user, self unless comment.user == user
|
||||
user.decrement! :comment_smiled_count
|
||||
comment.decrement! :smile_count
|
||||
end
|
||||
|
||||
def notification_type(*_args)
|
||||
Notifications::CommentSmiled
|
||||
end
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
class Notifications::CommentSmiled < Notification
|
||||
end
|
|
@ -20,6 +20,7 @@ class User < ActiveRecord::Base
|
|||
has_many :friends, through: :active_relationships, source: :target
|
||||
has_many :followers, through: :passive_relationships, source: :source
|
||||
has_many :smiles, dependent: :destroy
|
||||
has_many :comment_smiles, dependent: :destroy
|
||||
has_many :services, dependent: :destroy
|
||||
has_many :notifications, foreign_key: :recipient_id, dependent: :destroy
|
||||
has_many :reports, dependent: :destroy
|
||||
|
@ -140,10 +141,26 @@ class User < ActiveRecord::Base
|
|||
Smile.find_by(user: self, answer: answer).destroy
|
||||
end
|
||||
|
||||
# smiles a comment
|
||||
# @param comment [Comment] the comment to smile
|
||||
def smile_comment(comment)
|
||||
CommentSmile.create!(user: self, comment: comment)
|
||||
end
|
||||
|
||||
# unsmile an comment
|
||||
# @param comment [Comment] the comment to unsmile
|
||||
def unsmile_comment(comment)
|
||||
CommentSmile.find_by(user: self, comment: comment).destroy
|
||||
end
|
||||
|
||||
def smiled?(answer)
|
||||
answer.smiles.pluck(:user_id).include? self.id
|
||||
end
|
||||
|
||||
def smiled_comment?(comment)
|
||||
comment.smiles.pluck(:user_id).include? self.id
|
||||
end
|
||||
|
||||
def display_website
|
||||
website.match(/https?:\/\/([A-Za-z.\-0-9]+)\/?(?:.*)/i)[1]
|
||||
rescue NoMethodError
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
json.partial! 'ajax/shared/status'
|
|
@ -0,0 +1 @@
|
|||
json.partial! 'ajax/shared/status'
|
|
@ -50,6 +50,18 @@
|
|||
your answer
|
||||
= time_ago_in_words notification.target.created_at
|
||||
ago
|
||||
- when "CommentSmile"
|
||||
.pull-left
|
||||
%img.img-rounded.notification--dropdown-img{src: gravatar_url(notification.target.user)}
|
||||
.media-body
|
||||
%h6.media-heading.notification--dropdown-user
|
||||
= user_screen_name notification.target.user
|
||||
.notification--dropdown-text
|
||||
smiled at
|
||||
%a{href: show_user_answer_path(username: notification.target.user.screen_name, id: notification.target.comment.answer.id), title: "#{notification.target.comment.content[0..40]}...", data: { toggle: :tooltip, placement: :top }}
|
||||
your comment
|
||||
= time_ago_in_words notification.target.created_at
|
||||
ago
|
||||
- when "Comment"
|
||||
.pull-left
|
||||
%img.img-rounded.notification--dropdown-img{src: gravatar_url(notification.target.user)}
|
||||
|
@ -68,4 +80,4 @@
|
|||
answer
|
||||
= time_ago_in_words notification.target.created_at
|
||||
ago
|
||||
%li= link_to "Show all notifications#{" and mark them as read" if notifications.pluck(:new).any?}", notifications_path
|
||||
%li= link_to "Show all notifications#{" and mark them as read" if notifications.pluck(:new).any?}", notifications_path
|
||||
|
|
|
@ -44,6 +44,21 @@
|
|||
ago
|
||||
.notification--icon
|
||||
%i.fa.fa-smile-o
|
||||
- when "CommentSmile"
|
||||
.pull-left
|
||||
%img.img-rounded.notification--img{src: gravatar_url(notification.target.user)}
|
||||
.media-body
|
||||
%h6.media-heading.notification--user
|
||||
= user_screen_name notification.target.user
|
||||
%p.notification--text
|
||||
smiled at
|
||||
%a{href: show_user_answer_path(username: notification.target.user.screen_name, id: notification.target.comment.answer.id), title: "#{notification.target.comment.content[0..40]}...", data: { toggle: :tooltip, placement: :top }}
|
||||
your comment
|
||||
%span{title: notification.target.created_at, data: { toggle: :tooltip, placement: :bottom }}
|
||||
= time_ago_in_words notification.target.created_at
|
||||
ago
|
||||
.notification--icon
|
||||
%i.fa.fa-smile-o
|
||||
- when "Comment"
|
||||
.pull-left
|
||||
%img.img-rounded.notification--img{src: gravatar_url(notification.target.user)}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
%span.hidden-xs.text-muted
|
||||
- unless user_signed_in?
|
||||
- if a.smile_count > 0
|
||||
%span{id: "ab-smile-count-#{a.id}"}= a.smile_count
|
||||
users smiled this
|
||||
%button.btn.btn-info.btn-sm{name: 'ab-smile', disabled: true}
|
||||
%i.fa.fa-smile-o
|
||||
%span{id: "ab-smile-count-#{a.id}"}= a.smile_count
|
||||
- if user_signed_in?
|
||||
- if current_user.smiled? a
|
||||
%button.btn.btn-info.btn-sm{type: :button, name: 'ab-smile', data: { a_id: a.id, action: :unsmile }}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
.modal.fade{"id" => "modal-view-comment#{comment.id}-smiles","aria-hidden" => "true", "aria-labelledby" => "modal-view-comment#{comment.id}-smiles-label", :role => "dialog", :tabindex => "-1"}
|
||||
.modal-dialog
|
||||
.modal-content
|
||||
.modal-header
|
||||
%button.close{"data-dismiss" => "modal", :type => "button"}
|
||||
%span{"aria-hidden" => "true"} ×
|
||||
%span.sr-only Close
|
||||
%h4#modal-ask-followers-label.modal-title People who smiled this comment
|
||||
.modal-body
|
||||
- if comment.smiles.all.count == 0
|
||||
No one smiled this, yet.
|
||||
- else
|
||||
%ul.user-list.user-list-smiles
|
||||
- comment.smiles.all.each do |smile|
|
||||
%li.user-list-entry.user-list-entry-smiles
|
||||
%a{href: show_user_profile_path(smile.user.screen_name)}
|
||||
%img.img-rounded{src: gravatar_url(smile.user), alt: user_screen_name(smile.user, false, false)}
|
||||
%span= user_screen_name(smile.user, false, false)
|
|
@ -4,17 +4,36 @@
|
|||
%ul.comments
|
||||
- a.comments.order(:created_at).each do |comment|
|
||||
%li{data: { comment_id: comment.id }}
|
||||
%div{class: "ab-comment-smile-list", style: "height: 0; width: 0"}= render "shared/comment_smiles", comment: comment
|
||||
.media.comments--media
|
||||
.pull-left
|
||||
%img.img-rounded.answerbox--img{src: gravatar_url(comment.user)}
|
||||
.media-body.comments--body
|
||||
%h6.media-heading.answerbox--question-user= user_screen_name comment.user
|
||||
- if user_signed_in?
|
||||
.pull-right
|
||||
.pull-right
|
||||
%span.hidden-xs.text-muted
|
||||
- unless user_signed_in?
|
||||
- if comment.smile_count > 0
|
||||
%button.btn.btn-info.btn-sm{name: 'ab-smile-comment', disabled: true}
|
||||
%i.fa.fa-smile-o
|
||||
%span{id: "ab-comment-smile-count-#{comment.id}"}= comment.smile_count
|
||||
- if user_signed_in?
|
||||
- if current_user.smiled_comment? comment
|
||||
%button.btn.btn-info.btn-sm{type: :button, name: 'ab-smile-comment', data: { c_id: comment.id, action: :unsmile }}
|
||||
%i.fa.fa-frown-o
|
||||
%span{id: "ab-comment-smile-count-#{comment.id}"}= comment.smile_count
|
||||
- else
|
||||
%button.btn.btn-info.btn-sm{type: :button, name: 'ab-smile-comment', data: { c_id: comment.id, action: :smile }}
|
||||
%i.fa.fa-smile-o
|
||||
%span{id: "ab-comment-smile-count-#{comment.id}"}= comment.smile_count
|
||||
.btn-group
|
||||
%button.btn.btn-link.btn-sm.dropdown-toggle{data: { toggle: :dropdown }, aria: { expanded: :false }}
|
||||
%span.caret
|
||||
%ul.dropdown-menu.dropdown-menu-right{role: :menu}
|
||||
%li
|
||||
%a{href: '#', type: :button, data: { target: "#modal-view-comment#{comment.id}-smiles", toggle: :modal}}
|
||||
%i.fa.fa-smile-o
|
||||
View comment smiles
|
||||
- if privileged?(comment.user) or privileged?(a.user)
|
||||
%li.text-danger
|
||||
%a{href: '#', data: { action: 'ab-comment-destroy', c_id: comment.id }}
|
||||
|
|
|
@ -76,6 +76,8 @@ Rails.application.routes.draw do
|
|||
match '/destroy_friend', to: 'friend#destroy', via: :post, as: :destroy_friend
|
||||
match '/create_smile', to: 'smile#create', via: :post, as: :create_smile
|
||||
match '/destroy_smile', to: 'smile#destroy', via: :post, as: :destroy_smile
|
||||
match '/create_comment_smile', to: 'smile#create_comment', via: :post, as: :create_comment_smile
|
||||
match '/destroy_comment_smile', to: 'smile#destroy_comment', via: :post, as: :destroy_comment_smile
|
||||
match '/create_comment', to: 'comment#create', via: :post, as: :create_comment
|
||||
match '/destroy_comment', to: 'comment#destroy', via: :post, as: :destroy_comment
|
||||
match '/report', to: 'report#create', via: :post, as: :report
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
class CreateCommentSmiles < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :comment_smiles do |t|
|
||||
t.integer :user_id
|
||||
t.integer :comment_id
|
||||
|
||||
t.timestamps null: false
|
||||
end
|
||||
|
||||
add_index :comment_smiles, :user_id
|
||||
add_index :comment_smiles, :comment_id
|
||||
add_index :comment_smiles, [:user_id, :comment_id], unique: true
|
||||
|
||||
add_column :users, :comment_smiled_count, :integer, default: 0, null: false
|
||||
add_column :comments, :smile_count, :integer, default: 0, null: false
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe CommentSmile, :type => :model do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
end
|
Loading…
Reference in New Issue