Commit a48dd40a authored by Valery Sizov's avatar Valery Sizov

base implementation of emoji picker [ci skip]

parent 3b61dc47
class @AwardsHandler class @AwardsHandler
constructor: (@post_emoji_url, @noteable_type, @noteable_id, @aliases) -> constructor: (@post_emoji_url, @noteable_type, @noteable_id, @aliases) ->
$(".add-award").click (event)->
event.stopPropagation()
event.preventDefault()
$(".emoji-menu").show()
$("html").click ->
if !$(event.target).closest(".emoji-menu").length
if $(".emoji-menu").is(":visible")
$(".emoji-menu").hide()
addAward: (emoji) -> addAward: (emoji) ->
emoji = @normilizeEmojiName(emoji) emoji = @normilizeEmojiName(emoji)
@postEmoji emoji, => @postEmoji emoji, =>
@addAwardToEmojiBar(emoji) @addAwardToEmojiBar(emoji)
$(".emoji-menu").hide()
addAwardToEmojiBar: (emoji, custom_path = '') -> addAwardToEmojiBar: (emoji) ->
emoji = @normilizeEmojiName(emoji) emoji = @normilizeEmojiName(emoji)
if @exist(emoji) if @exist(emoji)
if @isActive(emoji) if @isActive(emoji)
...@@ -17,7 +28,7 @@ class @AwardsHandler ...@@ -17,7 +28,7 @@ class @AwardsHandler
counter.parent().addClass("active") counter.parent().addClass("active")
@addMeToAuthorList(emoji) @addMeToAuthorList(emoji)
else else
@createEmoji(emoji, custom_path) @createEmoji(emoji)
exist: (emoji) -> exist: (emoji) ->
@findEmojiIcon(emoji).length > 0 @findEmojiIcon(emoji).length > 0
...@@ -54,31 +65,29 @@ class @AwardsHandler ...@@ -54,31 +65,29 @@ class @AwardsHandler
resetTooltip: (award) -> resetTooltip: (award) ->
award.tooltip("destroy") award.tooltip("destroy")
# "destroy" call is asynchronous, this is why we need to set timeout. # "destroy" call is asynchronous and there is no appropriate callnack on it, this is why we need to set timeout.
setTimeout (-> setTimeout (->
award.tooltip() award.tooltip()
), 200 ), 200
createEmoji: (emoji, custom_path) -> createEmoji: (emoji) ->
emojiCssClass = @resolveNameToCssClass(emoji)
nodes = [] nodes = []
nodes.push("<div class='award active' title='me'>") nodes.push("<div class='award active' title='me'>")
nodes.push("<div class='icon' data-emoji='" + emoji + "'>") nodes.push("<div class='icon emoji-icon " + emojiCssClass + "' data-emoji='" + emoji + "'></div>")
nodes.push(@getImage(emoji, custom_path)) nodes.push("<div class='counter'>1</div>")
nodes.push("</div>") nodes.push("</div>")
nodes.push("<div class='counter'>1")
nodes.push("</div></div>")
$(".awards-controls").before(nodes.join("\n")) emoji_node = $(nodes.join("\n")).insertBefore(".awards-controls").find(".emoji-icon").data("emoji", emoji)
$(".award").tooltip() $(".award").tooltip()
getImage: (emoji, custom_path) -> resolveNameToCssClass: (emoji) ->
if custom_path unicodeName = $(".emoji-menu-content [data-emoji='?']".replace("?", emoji)).data("unicode-name")
$("<img>").attr({src: custom_path, width: 20, height: 20}).wrap("<div>").parent().html()
else
$("li[data-emoji='" + emoji + "']").html()
"emoji-" + unicodeName
postEmoji: (emoji, callback) -> postEmoji: (emoji, callback) ->
$.post @post_emoji_url, { note: { $.post @post_emoji_url, { note: {
...@@ -90,7 +99,7 @@ class @AwardsHandler ...@@ -90,7 +99,7 @@ class @AwardsHandler
callback.call() callback.call()
findEmojiIcon: (emoji) -> findEmojiIcon: (emoji) ->
$(".icon[data-emoji='" + emoji + "']") $(".award [data-emoji='" + emoji + "']")
scrollToAwards: -> scrollToAwards: ->
$('body, html').animate({ $('body, html').animate({
......
...@@ -127,7 +127,7 @@ class @Notes ...@@ -127,7 +127,7 @@ class @Notes
@initTaskList() @initTaskList()
if note.award if note.award
awards_handler.addAwardToEmojiBar(note.note, note.emoji_path) awards_handler.addAwardToEmojiBar(note.note)
awards_handler.scrollToAwards() awards_handler.scrollToAwards()
### ###
......
...@@ -2,6 +2,12 @@ ...@@ -2,6 +2,12 @@
@include clearfix; @include clearfix;
line-height: 34px; line-height: 34px;
.emoji-icon {
width: 20px;
height: 20px;
margin: 7px 0 0 5px;
}
.award { .award {
@include border-radius(5px); @include border-radius(5px);
...@@ -40,6 +46,7 @@ ...@@ -40,6 +46,7 @@
} }
.awards-controls { .awards-controls {
position: relative;
margin-left: 10px; margin-left: 10px;
float: left; float: left;
...@@ -55,32 +62,58 @@ ...@@ -55,32 +62,58 @@
} }
} }
.awards-menu { .emoji-menu{
padding: $gl-padding; position: absolute;
min-width: 214px; top: 100%;
left: 0;
> li { z-index: 1000;
cursor: pointer; display: none;
width: 30px; float: left;
height: 30px; min-width: 160px;
text-align: center; padding: 5px 0;
@include border-radius(5px); margin: 2px 0 0;
font-size: 14px;
text-align: left;
list-style: none;
background-color: #fff;
-webkit-background-clip: padding-box;
background-clip: padding-box;
border: 1px solid #ccc;
border: 1px solid rgba(0,0,0,.15);
border-radius: 4px;
-webkit-box-shadow: 0 6px 12px rgba(0,0,0,.175);
box-shadow: 0 6px 12px rgba(0,0,0,.175);
.emoji-menu-content {
padding: $gl-padding;
width: 300px;
height: 300px;
overflow-y: scroll;
h4 {
clear: left;
}
img { ul {
margin-bottom: 2px; list-style-type: none;
margin-left: -20px;
} }
&:hover { li {
background-color: #ccc; cursor: pointer;
width: 30px;
height: 30px;
text-align: center;
float: left;
margin: 3px;
list-decorate: none;
@include border-radius(5px);
&:hover {
background-color: #ccc;
}
} }
} }
} }
} }
.awards-menu{
li {
float: left;
margin: 3px;
}
}
} }
This diff is collapsed.
...@@ -139,7 +139,6 @@ class Projects::NotesController < Projects::ApplicationController ...@@ -139,7 +139,6 @@ class Projects::NotesController < Projects::ApplicationController
discussion_id: note.discussion_id, discussion_id: note.discussion_id,
html: note_to_html(note), html: note_to_html(note),
award: note.is_award, award: note.is_award,
emoji_path: note.is_award ? view_context.image_url(::AwardEmoji.path_to_emoji_image(note.note)) : "",
note: note.note, note: note.note,
discussion_html: note_to_discussion_html(note), discussion_html: note_to_discussion_html(note),
discussion_with_diff_html: note_to_discussion_with_diff_html(note) discussion_with_diff_html: note_to_discussion_with_diff_html(note)
......
...@@ -94,11 +94,11 @@ module IssuesHelper ...@@ -94,11 +94,11 @@ module IssuesHelper
end.sort.to_sentence(last_word_connector: ', or ') end.sort.to_sentence(last_word_connector: ', or ')
end end
def url_to_emoji(name) def emoji_icon(name, unicode = nil)
emoji_path = ::AwardEmoji.path_to_emoji_image(name) unicode ||= Emoji.emoji_filename(name)
url_to_image(emoji_path)
rescue StandardError content_tag :div, "", class: "icon emoji-icon emoji-#{unicode}",
"" "data-emoji" => name, "data-unicode-name" => unicode
end end
def emoji_author_list(notes, current_user) def emoji_author_list(notes, current_user)
...@@ -109,10 +109,6 @@ module IssuesHelper ...@@ -109,10 +109,6 @@ module IssuesHelper
list.join(", ") list.join(", ")
end end
def emoji_list
::AwardEmoji::EMOJI_LIST
end
def note_active_class(notes, current_user) def note_active_class(notes, current_user)
if current_user && notes.pluck(:author_id).include?(current_user.id) if current_user && notes.pluck(:author_id).include?(current_user.id)
"active" "active"
......
.awards.votes-block .awards.votes-block
- votable.notes.awards.grouped_awards.each do |emoji, notes| - votable.notes.awards.grouped_awards.each do |emoji, notes|
.award{class: (note_active_class(notes, current_user)), title: emoji_author_list(notes, current_user)} .award{class: (note_active_class(notes, current_user)), title: emoji_author_list(notes, current_user)}
.icon{"data-emoji" => "#{emoji}"} = emoji_icon(emoji)
= image_tag url_to_emoji(emoji), height: "20px", width: "20px"
.counter .counter
= notes.count = notes.count
- if current_user - if current_user
.dropdown.awards-controls .awards-controls
%a.add-award{"data-toggle" => "dropdown", "data-target" => "#", "href" => "#"} %a.add-award{"data-toggle" => "dropdown", "data-target" => "#", "href" => "#"}
= icon('smile-o') = icon('smile-o')
%ul.dropdown-menu.awards-menu .emoji-menu
- emoji_list.each do |emoji| .emoji-menu-content
%li{"data-emoji" => "#{emoji}"}= image_tag url_to_emoji(emoji), height: "20px", width: "20px" - AwardEmoji.emoji_by_category.each do |category, emojis|
%h4= AwardEmoji::CATEGORIES[category]
%ul
- emojis.each do |emoji|
%li
= emoji_icon(emoji["name"], emoji["unicode"])
- if current_user - if current_user
:coffeescript :coffeescript
...@@ -20,10 +24,16 @@ ...@@ -20,10 +24,16 @@
noteable_type = "#{votable.class.name.underscore}" noteable_type = "#{votable.class.name.underscore}"
noteable_id = "#{votable.id}" noteable_id = "#{votable.id}"
aliases = #{AwardEmoji::ALIASES.to_json} aliases = #{AwardEmoji::ALIASES.to_json}
window.awards_handler = new AwardsHandler(post_emoji_url, noteable_type, noteable_id, aliases)
$(".awards-menu li").click (e)-> window.awards_handler = new AwardsHandler(
emoji = $(this).data("emoji") post_emoji_url,
noteable_type,
noteable_id,
aliases
)
$(".emoji-menu-content li").click (e)->
emoji = $(this).find(".emoji-icon").data("emoji")
awards_handler.addAward(emoji) awards_handler.addAward(emoji)
$(".awards").on "click", ".award", (e)-> $(".awards").on "click", ".award", (e)->
...@@ -31,3 +41,5 @@ ...@@ -31,3 +41,5 @@
awards_handler.addAward(emoji) awards_handler.addAward(emoji)
$(".award").tooltip() $(".award").tooltip()
$(".emoji-menu-content").niceScroll({cursorwidth: "7px"})
class AwardEmoji class AwardEmoji
EMOJI_LIST = [
"+1", "-1", "100", "blush", "heart", "smile", "rage",
"beers", "disappointed", "ok_hand",
"helicopter", "shit", "airplane", "alarm_clock",
"ambulance", "anguished", "two_hearts", "wink"
]
ALIASES = { ALIASES = {
pout: "rage", pout: "rage",
satisfied: "laughing", satisfied: "laughing",
...@@ -37,11 +30,49 @@ class AwardEmoji ...@@ -37,11 +30,49 @@ class AwardEmoji
squirrel: "shipit" squirrel: "shipit"
}.with_indifferent_access }.with_indifferent_access
def self.path_to_emoji_image(name) CATEGORIES = {
"emoji/#{Emoji.emoji_filename(name)}.png" other: "Other",
objects: "Objects",
places: "Places",
travel_places: "Travel",
emoticons: "Emoticons",
objects_symbols: "Symbols",
nature: "Nature",
celebration: "Celebration",
people: "People",
activity: "Activity",
flags: "Flags",
food_drink: "Food"
}.with_indifferent_access
def self.positions_by_name(name)
emoji = emojis_json.find do |emoji|
emoji["short_names"].include?(name)
end
[emoji["sheet_x"], emoji["sheet_y"]]
end end
def self.normilize_emoji_name(name) def self.normilize_emoji_name(name)
ALIASES[name] || name ALIASES[name] || name
end end
def self.emoji_by_category
unless @emoji_by_category
@emoji_by_category = {}
emojis_added = []
Emoji.emojis.each do |emoji_name, data|
next if emojis_added.include?(data["name"])
emojis_added << data["name"]
@emoji_by_category[data["category"]] ||= []
@emoji_by_category[data["category"]] << data
end
@emoji_by_category = @emoji_by_category.sort.to_h
end
@emoji_by_category
end
end end
...@@ -127,12 +127,6 @@ describe IssuesHelper do ...@@ -127,12 +127,6 @@ describe IssuesHelper do
it { is_expected.to eq("!1, !2, or !3") } it { is_expected.to eq("!1, !2, or !3") }
end end
describe "#url_to_emoji" do
it "returns url" do
expect(url_to_emoji("smile")).to include("emoji/1F604.png")
end
end
describe "#emoji_list" do describe "#emoji_list" do
it "returns url" do it "returns url" do
expect(emoji_list).to be_kind_of(Array) expect(emoji_list).to be_kind_of(Array)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment