Skip to content
Snippets Groups Projects
Commit 1318e7c2 authored by Valery Sizov's avatar Valery Sizov Committed by Rubén Dávila
Browse files

award emoji

parent 66bb4f3e
No related branches found
No related tags found
No related merge requests found
Showing
with 200 additions and 153 deletions
class @AwardsHandler
constructor: (@post_emoji_url, @noteable_type, @noteable_id) ->
addAward: (emoji) ->
@postEmoji emoji, =>
if @exist(emoji)
if @isActive(emoji)
@decrementCounter(emoji)
else
counter = $(".icon." + emoji).siblings(".counter")
counter.text(parseInt(counter.text()) + 1)
counter.parent().addClass("active")
else
@createEmoji(emoji)
exist: (emoji) ->
$(".icon").hasClass(emoji)
isActive: (emoji) ->
$(".icon." + emoji).parent().hasClass("active")
decrementCounter: (emoji) ->
counter = $(".icon." + emoji).siblings(".counter")
if parseInt(counter.text()) > 1
counter.text(parseInt(counter.text()) - 1)
counter.parent().removeClass("active")
else
counter.parent().remove()
createEmoji: (emoji) ->
nodes = []
nodes.push("<div class='award active'>")
nodes.push("<div class='icon " + emoji + "'>")
nodes.push(@getImage(emoji))
nodes.push("</div>")
nodes.push("<div class='counter'>1")
nodes.push("</div></div>")
$(".awards").append(nodes.join("\n"))
getImage: (emoji) ->
$("li." + emoji).html()
postEmoji: (emoji, callback) ->
emoji = emoji.replace("emoji-", "")
$.post @post_emoji_url, {
emoji: emoji
noteable_type: @noteable_type
noteable_id: @noteable_id
},(data) ->
if data.ok
callback.call()
\ No newline at end of file
Loading
Loading
@@ -113,13 +113,16 @@ class @Notes
renderNote: (note) ->
# render note if it not present in loaded list
# or skip if rendered
if @isNewNote(note)
if @isNewNote(note) && !note.award
@note_ids.push(note.id)
$('ul.main-notes-list').
append(note.html).
syntaxHighlight()
@initTaskList()
 
if note.award
awards_handler.addAward("emoji-" + note.note)
###
Check if note does not exists on page
###
Loading
Loading
@@ -255,7 +258,6 @@ class @Notes
###
addNote: (xhr, note, status) =>
@renderNote(note)
@updateVotes()
 
###
Called in response to the new note form being submitted
Loading
Loading
@@ -473,9 +475,6 @@ class @Notes
form = $(e.target).closest(".js-discussion-note-form")
@removeDiscussionNoteForm(form)
 
updateVotes: ->
true
###
Called after an attachment file has been selected.
 
Loading
Loading
Loading
Loading
@@ -101,3 +101,45 @@
background-color: $background-color;
}
}
.awards {
.award {
border: 1px solid;
padding: 1px 3px;
width: 50px;
border-radius: 5px;
float:left;
margin: 0 3px;
border-color: #ccc;
cursor: pointer;
&.active {
border-color: rgba(79,176,252,.4);
background-color: rgba(79,176,252,.08);
.counter {
font-weight: bold;
}
}
.icon {
float: left;
margin-right: 10px;
}
}
#add-award {
font-size: 20px;
border-radius: 5px;
float: left;
width: 50px;
font-weight: bold;
}
.awards-menu{
li {
float: left;
margin: 3px;
}
}
}
Loading
Loading
@@ -60,7 +60,7 @@ class Projects::IssuesController < Projects::ApplicationController
def show
@participants = @issue.participants(current_user)
@note = @project.notes.new(noteable: @issue)
@notes = @issue.notes.with_associations.fresh
@notes = @issue.notes.nonawards.with_associations.fresh
@noteable = @issue
 
respond_with(@issue)
Loading
Loading
Loading
Loading
@@ -254,7 +254,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
 
# Build a note object for comment form
@note = @project.notes.new(noteable: @merge_request)
@notes = @merge_request.mr_and_commit_notes.inc_author.fresh
@notes = @merge_request.nonawards.mr_and_commit_notes.inc_author.fresh
@discussions = Note.discussions_from_notes(@notes)
@noteable = @merge_request
 
Loading
Loading
Loading
Loading
@@ -3,7 +3,7 @@ class Projects::NotesController < Projects::ApplicationController
before_action :authorize_read_note!
before_action :authorize_create_note!, only: [:create]
before_action :authorize_admin_note!, only: [:update, :destroy]
before_action :find_current_user_notes, except: [:destroy, :delete_attachment]
before_action :find_current_user_notes, except: [:destroy, :delete_attachment, :award_toggle]]
 
def index
current_fetched_at = Time.now.to_i
Loading
Loading
@@ -58,6 +58,27 @@ class Projects::NotesController < Projects::ApplicationController
end
end
 
def award_toggle
noteable = params[:noteable_type] == "Issue" ? Issue : MergeRequest
noteable = noteable.find(params[:noteable_id])
data = {
noteable: noteable,
author: current_user,
is_award: true,
note: params[:emoji]
}
note = project.notes.find_by(data)
if note
note.destroy
else
project.notes.create(data)
end
render json: {ok: true}
end
private
 
def note
Loading
Loading
@@ -111,6 +132,8 @@ class Projects::NotesController < Projects::ApplicationController
id: note.id,
discussion_id: note.discussion_id,
html: note_to_html(note),
award: note.is_award,
note: note.note,
discussion_html: note_to_discussion_html(note),
discussion_with_diff_html: note_to_discussion_with_diff_html(note)
}
Loading
Loading
Loading
Loading
@@ -87,6 +87,11 @@ module IssuesHelper
merge_requests.map(&:to_reference).to_sentence(last_word_connector: ', or ')
end
 
def url_to_emoji(name)
emoji_path = "emoji/#{Emoji.emoji_filename(name)}.png"
url_to_image(emoji_path)
end
# Required for Gitlab::Markdown::IssueReferenceFilter
module_function :url_for_issue
end
Loading
Loading
@@ -89,41 +89,6 @@ module Issuable
opened? || reopened?
end
 
#
# Votes
#
# Return the number of -1 comments (downvotes)
def downvotes
filter_superceded_votes(notes.select(&:downvote?), notes).size
end
def downvotes_in_percent
if votes_count.zero?
0
else
100.0 - upvotes_in_percent
end
end
# Return the number of +1 comments (upvotes)
def upvotes
filter_superceded_votes(notes.select(&:upvote?), notes).size
end
def upvotes_in_percent
if votes_count.zero?
0
else
100.0 / votes_count * upvotes
end
end
# Return the total number of votes
def votes_count
upvotes + downvotes
end
def subscribed?(user)
subscription = subscriptions.find_by_user_id(user.id)
 
Loading
Loading
@@ -188,18 +153,4 @@ module Issuable
Taskable.get_updated_tasks(old_content: previous_changes['description'].first,
new_content: description)
end
private
def filter_superceded_votes(votes, notes)
filteredvotes = [] + votes
votes.each do |vote|
if vote.superceded?(notes)
filteredvotes.delete(vote)
end
end
filteredvotes
end
end
Loading
Loading
@@ -50,6 +50,8 @@ class Note < ActiveRecord::Base
mount_uploader :attachment, AttachmentUploader
 
# Scopes
scope :awards, ->{ where("is_award IS TRUE") }
scope :nonawards, ->{ where("is_award IS FALSE") }
scope :for_commit_id, ->(commit_id) { where(noteable_type: "Commit", commit_id: commit_id) }
scope :inline, ->{ where("line_code IS NOT NULL") }
scope :not_inline, ->{ where(line_code: [nil, '']) }
Loading
Loading
@@ -97,6 +99,12 @@ class Note < ActiveRecord::Base
def search(query)
where("LOWER(note) like :query", query: "%#{query.downcase}%")
end
def grouped_awards
select(:note).distinct.map do |note|
[ note.note, where(note: note.note) ]
end
end
end
 
def cross_reference?
Loading
Loading
@@ -288,44 +296,6 @@ class Note < ActiveRecord::Base
nil
end
 
DOWNVOTES = %w(-1 :-1: :thumbsdown: :thumbs_down_sign:)
# Check if the note is a downvote
def downvote?
votable? && note.start_with?(*DOWNVOTES)
end
UPVOTES = %w(+1 :+1: :thumbsup: :thumbs_up_sign:)
# Check if the note is an upvote
def upvote?
votable? && note.start_with?(*UPVOTES)
end
def superceded?(notes)
return false unless vote?
notes.each do |note|
next if note == self
if note.vote? &&
self[:author_id] == note[:author_id] &&
self[:created_at] <= note[:created_at]
return true
end
end
false
end
def vote?
upvote? || downvote?
end
def votable?
for_issue? || (for_merge_request? && !for_diff_line?)
end
# Mentionable override.
def gfm_reference(from_project = nil)
noteable.gfm_reference(from_project)
Loading
Loading
Loading
Loading
@@ -5,11 +5,16 @@ module Notes
note.author = current_user
note.system = false
 
if contains_emoji_only?(params[:note])
note.is_award = true
note.note = emoji_name(params[:note])
end
if note.save
notification_service.new_note(note)
 
# Skip system notes, like status changes and cross-references.
unless note.system
# Skip system notes, like status changes and cross-references and awards
unless note.system || note.is_award
event_service.leave_note(note, note.author)
note.create_cross_references!
execute_hooks(note)
Loading
Loading
@@ -28,5 +33,13 @@ module Notes
note.project.execute_hooks(note_data, :note_hooks)
note.project.execute_services(note_data, :note_hooks)
end
def contains_emoji_only?(note)
note =~ /^:[-_+[:alnum:]]*:\s?/
end
def emoji_name(note)
note.match(/\A:([-_+[:alnum:]]*):\s?/)[1]
end
end
end
Loading
Loading
@@ -102,6 +102,7 @@ class NotificationService
# ignore gitlab service messages
return true if note.note.start_with?('Status changed to closed')
return true if note.cross_reference? && note.system == true
return true if note.is_award
 
target = note.noteable
 
Loading
Loading
Loading
Loading
@@ -29,8 +29,6 @@
 
.issue-info
= "#{issue.to_reference} opened #{time_ago_with_tooltip(issue.created_at, placement: 'bottom')} by #{link_to_member(@project, issue.author, avatar: false)}".html_safe
- if issue.votes_count > 0
= render 'votes/votes_inline', votable: issue
- if issue.milestone
&nbsp;
%span
Loading
Loading
Loading
Loading
@@ -34,8 +34,6 @@
 
.merge-request-info
= "##{merge_request.iid} opened #{time_ago_with_tooltip(merge_request.created_at, placement: 'bottom')} by #{link_to_member(@project, merge_request.author, avatar: false)}".html_safe
- if merge_request.votes_count > 0
= render 'votes/votes_inline', votable: merge_request
- if merge_request.milestone_id?
&nbsp;
%span
Loading
Loading
Loading
Loading
@@ -35,26 +35,6 @@
- if note.updated_by && note.updated_by != note.author
by #{link_to_member(note.project, note.updated_by, avatar: false, author_class: nil)}
 
- if note.superceded?(@notes)
- if note.upvote?
%span.vote.upvote.label.label-gray.strikethrough
= icon('thumbs-up')
\+1
- if note.downvote?
%span.vote.downvote.label.label-gray.strikethrough
= icon('thumbs-down')
\-1
- else
- if note.upvote?
%span.vote.upvote.label.label-success
= icon('thumbs-up')
\+1
- if note.downvote?
%span.vote.downvote.label.label-danger
= icon('thumbs-down')
\-1
.note-body{class: note_editable?(note) ? 'js-task-list-container' : ''}
.note-text
= preserve do
Loading
Loading
.votes.votes-block
.btn-group
- unless votable.upvotes.zero?
.btn.btn-sm.disabled.cgreen
%i.fa.fa-thumbs-up
= votable.upvotes
- unless votable.downvotes.zero?
.btn.btn-sm.disabled.cred
%i.fa.fa-thumbs-down
= votable.downvotes
.awards.votes-block
- votable.notes.awards.grouped_awards.each do | vote |
.award{class: ("active" if vote.last.pluck(:author_id).include?(current_user.id))}
.icon{class: "emoji-#{vote.first}"}
= image_tag url_to_emoji(vote.first), height: "20px", width: "20px"
.counter
= vote.last.count
%button.dropdown
%a#add-award{"data-toggle" => "dropdown", "data-target" => "#", "href" => "#"} +
%ul.dropdown-menu.awards-menu
- ["100", "blush", "heart", "smile", "rage", "beers", "thumbsup", "disappointed", "ok_hand", "helicopter"].each do |emoji|
%li{class: "emoji-#{emoji}"}= image_tag url_to_emoji(emoji), height: "20px", width: "20px"
:coffeescript
post_emoji_url = "#{award_toggle_namespace_project_notes_path(@project.namespace, @project)}"
noteable_type = "Issue"
noteable_id = #{@issue.id}
awards_handler = new AwardsHandler(post_emoji_url, noteable_type, noteable_id)
$ ->
$(".awards-menu li").click (e)->
emoji = $(this).attr("class")
awards_handler.addAward(emoji)
$(".awards").on "click", ".award", (e)->
emoji = /(emoji-\S*)/.exec($(this).find(".icon").attr("class"))[0]
awards_handler.addAward(emoji)
\ No newline at end of file
.votes.votes-inline
- unless votable.upvotes.zero?
%span.upvotes.cgreen
+ #{votable.upvotes}
- unless votable.downvotes.zero?
\/
- unless votable.downvotes.zero?
%span.downvotes.cred
\- #{votable.downvotes}
Loading
Loading
@@ -664,6 +664,10 @@ Gitlab::Application.routes.draw do
member do
delete :delete_attachment
end
collection do
post :award_toggle
end
end
 
resources :uploads, only: [:create] do
Loading
Loading
class AddIsAwardToNotes < ActiveRecord::Migration
def change
add_column :notes, :is_award, :boolean, default: false
end
end
Loading
Loading
@@ -531,7 +531,7 @@ ActiveRecord::Schema.define(version: 20151118162244) do
t.string "type"
t.string "description", default: "", null: false
t.string "avatar"
t.boolean "public", default: false
t.boolean "visible", default: false
end
 
add_index "namespaces", ["created_at", "id"], name: "index_namespaces_on_created_at_and_id", using: :btree
Loading
Loading
@@ -555,6 +555,7 @@ ActiveRecord::Schema.define(version: 20151118162244) do
t.boolean "system", default: false, null: false
t.text "st_diff"
t.integer "updated_by_id"
t.boolean "is_award", default: false
end
 
add_index "notes", ["author_id"], name: "index_notes_on_author_id", using: :btree
Loading
Loading
Loading
Loading
@@ -31,8 +31,6 @@ Parameters:
"project_id": 3,
"title": "test1",
"state": "opened",
"upvotes": 0,
"downvotes": 0,
"author": {
"id": 1,
"username": "admin",
Loading
Loading
@@ -77,8 +75,6 @@ Parameters:
"project_id": 3,
"title": "test1",
"state": "merged",
"upvotes": 0,
"downvotes": 0,
"author": {
"id": 1,
"username": "admin",
Loading
Loading
@@ -126,8 +122,6 @@ Parameters:
"updated_at": "2015-02-02T20:08:49.959Z",
"target_branch": "secret_token",
"source_branch": "version-1-9",
"upvotes": 0,
"downvotes": 0,
"author": {
"name": "Chad Hamill",
"username": "jarrett",
Loading
Loading
@@ -198,8 +192,6 @@ Parameters:
"project_id": 3,
"title": "test1",
"state": "opened",
"upvotes": 0,
"downvotes": 0,
"author": {
"id": 1,
"username": "admin",
Loading
Loading
@@ -250,8 +242,6 @@ Parameters:
"title": "test1",
"description": "description1",
"state": "opened",
"upvotes": 0,
"downvotes": 0,
"author": {
"id": 1,
"username": "admin",
Loading
Loading
@@ -304,8 +294,6 @@ Parameters:
"project_id": 3,
"title": "test1",
"state": "merged",
"upvotes": 0,
"downvotes": 0,
"author": {
"id": 1,
"username": "admin",
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment