base implementation of emoji picker [ci skip]
This commit is contained in:
parent
2b4a3bc524
commit
2eed8007bf
10 changed files with 1411 additions and 70 deletions
BIN
app/assets/images/emoji.png
Normal file
BIN
app/assets/images/emoji.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 813 KiB |
|
@ -1,12 +1,23 @@
|
|||
class @AwardsHandler
|
||||
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) ->
|
||||
emoji = @normilizeEmojiName(emoji)
|
||||
@postEmoji emoji, =>
|
||||
@addAwardToEmojiBar(emoji)
|
||||
|
||||
$(".emoji-menu").hide()
|
||||
|
||||
addAwardToEmojiBar: (emoji, custom_path = '') ->
|
||||
addAwardToEmojiBar: (emoji) ->
|
||||
emoji = @normilizeEmojiName(emoji)
|
||||
if @exist(emoji)
|
||||
if @isActive(emoji)
|
||||
|
@ -17,7 +28,7 @@ class @AwardsHandler
|
|||
counter.parent().addClass("active")
|
||||
@addMeToAuthorList(emoji)
|
||||
else
|
||||
@createEmoji(emoji, custom_path)
|
||||
@createEmoji(emoji)
|
||||
|
||||
exist: (emoji) ->
|
||||
@findEmojiIcon(emoji).length > 0
|
||||
|
@ -54,31 +65,29 @@ class @AwardsHandler
|
|||
resetTooltip: (award) ->
|
||||
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 (->
|
||||
award.tooltip()
|
||||
), 200
|
||||
|
||||
|
||||
createEmoji: (emoji, custom_path) ->
|
||||
createEmoji: (emoji) ->
|
||||
emojiCssClass = @resolveNameToCssClass(emoji)
|
||||
|
||||
nodes = []
|
||||
nodes.push("<div class='award active' title='me'>")
|
||||
nodes.push("<div class='icon' data-emoji='" + emoji + "'>")
|
||||
nodes.push(@getImage(emoji, custom_path))
|
||||
nodes.push("<div class='icon emoji-icon " + emojiCssClass + "' data-emoji='" + emoji + "'></div>")
|
||||
nodes.push("<div class='counter'>1</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()
|
||||
|
||||
getImage: (emoji, custom_path) ->
|
||||
if custom_path
|
||||
$("<img>").attr({src: custom_path, width: 20, height: 20}).wrap("<div>").parent().html()
|
||||
else
|
||||
$("li[data-emoji='" + emoji + "']").html()
|
||||
resolveNameToCssClass: (emoji) ->
|
||||
unicodeName = $(".emoji-menu-content [data-emoji='?']".replace("?", emoji)).data("unicode-name")
|
||||
|
||||
"emoji-" + unicodeName
|
||||
|
||||
postEmoji: (emoji, callback) ->
|
||||
$.post @post_emoji_url, { note: {
|
||||
|
@ -90,7 +99,7 @@ class @AwardsHandler
|
|||
callback.call()
|
||||
|
||||
findEmojiIcon: (emoji) ->
|
||||
$(".icon[data-emoji='" + emoji + "']")
|
||||
$(".award [data-emoji='" + emoji + "']")
|
||||
|
||||
scrollToAwards: ->
|
||||
$('body, html').animate({
|
||||
|
|
|
@ -127,7 +127,7 @@ class @Notes
|
|||
@initTaskList()
|
||||
|
||||
if note.award
|
||||
awards_handler.addAwardToEmojiBar(note.note, note.emoji_path)
|
||||
awards_handler.addAwardToEmojiBar(note.note)
|
||||
awards_handler.scrollToAwards()
|
||||
|
||||
###
|
||||
|
|
|
@ -2,6 +2,12 @@
|
|||
@include clearfix;
|
||||
line-height: 34px;
|
||||
|
||||
.emoji-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin: 7px 0 0 5px;
|
||||
}
|
||||
|
||||
.award {
|
||||
@include border-radius(5px);
|
||||
|
||||
|
@ -40,6 +46,7 @@
|
|||
}
|
||||
|
||||
.awards-controls {
|
||||
position: relative;
|
||||
margin-left: 10px;
|
||||
float: left;
|
||||
|
||||
|
@ -55,32 +62,58 @@
|
|||
}
|
||||
}
|
||||
|
||||
.awards-menu {
|
||||
padding: $gl-padding;
|
||||
min-width: 214px;
|
||||
.emoji-menu{
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
display: none;
|
||||
float: left;
|
||||
min-width: 160px;
|
||||
padding: 5px 0;
|
||||
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);
|
||||
|
||||
> li {
|
||||
cursor: pointer;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
text-align: center;
|
||||
@include border-radius(5px);
|
||||
.emoji-menu-content {
|
||||
padding: $gl-padding;
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
overflow-y: scroll;
|
||||
|
||||
img {
|
||||
margin-bottom: 2px;
|
||||
h4 {
|
||||
clear: left;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #ccc;
|
||||
ul {
|
||||
list-style-type: none;
|
||||
margin-left: -20px;
|
||||
}
|
||||
|
||||
li {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
1267
app/assets/stylesheets/pages/emojis.scss
Normal file
1267
app/assets/stylesheets/pages/emojis.scss
Normal file
File diff suppressed because it is too large
Load diff
|
@ -138,7 +138,6 @@ class Projects::NotesController < Projects::ApplicationController
|
|||
discussion_id: note.discussion_id,
|
||||
html: note_to_html(note),
|
||||
award: note.is_award,
|
||||
emoji_path: note.is_award ? view_context.image_url(::AwardEmoji.path_to_emoji_image(note.note)) : "",
|
||||
note: note.note,
|
||||
discussion_html: note_to_discussion_html(note),
|
||||
discussion_with_diff_html: note_to_discussion_with_diff_html(note)
|
||||
|
|
|
@ -94,11 +94,11 @@ module IssuesHelper
|
|||
end.sort.to_sentence(last_word_connector: ', or ')
|
||||
end
|
||||
|
||||
def url_to_emoji(name)
|
||||
emoji_path = ::AwardEmoji.path_to_emoji_image(name)
|
||||
url_to_image(emoji_path)
|
||||
rescue StandardError
|
||||
""
|
||||
def emoji_icon(name, unicode = nil)
|
||||
unicode ||= Emoji.emoji_filename(name)
|
||||
|
||||
content_tag :div, "", class: "icon emoji-icon emoji-#{unicode}",
|
||||
"data-emoji" => name, "data-unicode-name" => unicode
|
||||
end
|
||||
|
||||
def emoji_author_list(notes, current_user)
|
||||
|
@ -109,10 +109,6 @@ module IssuesHelper
|
|||
list.join(", ")
|
||||
end
|
||||
|
||||
def emoji_list
|
||||
::AwardEmoji::EMOJI_LIST
|
||||
end
|
||||
|
||||
def note_active_class(notes, current_user)
|
||||
if current_user && notes.pluck(:author_id).include?(current_user.id)
|
||||
"active"
|
||||
|
|
|
@ -1,18 +1,22 @@
|
|||
.awards.votes-block
|
||||
- votable.notes.awards.grouped_awards.each do |emoji, notes|
|
||||
.award{class: (note_active_class(notes, current_user)), title: emoji_author_list(notes, current_user)}
|
||||
.icon{"data-emoji" => "#{emoji}"}
|
||||
= image_tag url_to_emoji(emoji), height: "20px", width: "20px"
|
||||
= emoji_icon(emoji)
|
||||
.counter
|
||||
= notes.count
|
||||
|
||||
- if current_user
|
||||
.dropdown.awards-controls
|
||||
.awards-controls
|
||||
%a.add-award{"data-toggle" => "dropdown", "data-target" => "#", "href" => "#"}
|
||||
= icon('smile-o')
|
||||
%ul.dropdown-menu.awards-menu
|
||||
- emoji_list.each do |emoji|
|
||||
%li{"data-emoji" => "#{emoji}"}= image_tag url_to_emoji(emoji), height: "20px", width: "20px"
|
||||
.emoji-menu
|
||||
.emoji-menu-content
|
||||
- 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
|
||||
:coffeescript
|
||||
|
@ -20,10 +24,16 @@
|
|||
noteable_type = "#{votable.class.name.underscore}"
|
||||
noteable_id = "#{votable.id}"
|
||||
aliases = #{AwardEmoji::ALIASES.to_json}
|
||||
window.awards_handler = new AwardsHandler(post_emoji_url, noteable_type, noteable_id, aliases)
|
||||
|
||||
$(".awards-menu li").click (e)->
|
||||
emoji = $(this).data("emoji")
|
||||
window.awards_handler = new AwardsHandler(
|
||||
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").on "click", ".award", (e)->
|
||||
|
@ -31,3 +41,5 @@
|
|||
awards_handler.addAward(emoji)
|
||||
|
||||
$(".award").tooltip()
|
||||
|
||||
$(".emoji-menu-content").niceScroll({cursorwidth: "7px"})
|
||||
|
|
|
@ -1,11 +1,4 @@
|
|||
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 = {
|
||||
pout: "rage",
|
||||
satisfied: "laughing",
|
||||
|
@ -37,11 +30,49 @@ class AwardEmoji
|
|||
squirrel: "shipit"
|
||||
}.with_indifferent_access
|
||||
|
||||
def self.path_to_emoji_image(name)
|
||||
"emoji/#{Emoji.emoji_filename(name)}.png"
|
||||
CATEGORIES = {
|
||||
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
|
||||
|
||||
def self.normilize_emoji_name(name)
|
||||
ALIASES[name] || name
|
||||
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
|
||||
|
|
|
@ -127,12 +127,6 @@ describe IssuesHelper do
|
|||
it { is_expected.to eq("!1, !2, or !3") }
|
||||
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
|
||||
it "returns url" do
|
||||
expect(emoji_list).to be_kind_of(Array)
|
||||
|
|
Loading…
Reference in a new issue