diff --git a/plugins/emoji/assets/javascripts/emoji-autocomplete.js b/plugins/emoji/assets/javascripts/emoji-autocomplete.js new file mode 100644 index 00000000000..977d8ccebeb --- /dev/null +++ b/plugins/emoji/assets/javascripts/emoji-autocomplete.js @@ -0,0 +1,46 @@ + +// TODO: Make this a proper ES6 import +var ComposerView = require('discourse/views/composer').default; +ComposerView.on("initWmdEditor", function(){ + if (!Discourse.SiteSettings.enable_emoji) { return; } + + var template = Handlebars.compile("
" + + "" + + "
"); + + $('#wmd-input').autocomplete({ + template: template, + key: ":", + transformComplete: function(v){ return v.code + ":"; }, + dataSource: function(term){ + return new Ember.RSVP.Promise(function(resolve) { + var full = ":" + term; + term = term.toLowerCase(); + + if (term === "") { + return resolve(["smile", "smiley", "wink", "sunny", "blush"]); + } + + if (Discourse.Emoji.translations[full]) { + return resolve([Discourse.Emoji.translations[full]]); + } + + var options = Discourse.Emoji.search(term, {maxResults: 5}); + + return resolve(options); + }).then(function(list) { + return list.map(function(i) { + return {code: i, src: Discourse.Emoji.urlFor(i)}; + }); + }); + } + }); +}); diff --git a/plugins/emoji/assets/javascripts/emoji-toolbar.js b/plugins/emoji/assets/javascripts/emoji-toolbar.js new file mode 100644 index 00000000000..e3b38407168 --- /dev/null +++ b/plugins/emoji/assets/javascripts/emoji-toolbar.js @@ -0,0 +1,71 @@ + +var groups = [ +{ + name: "emoticons", + icons: ["smile","smiley","grinning","blush","relaxed","wink","heart_eyes","kissing_heart","kissing_closed_eyes","kissing","kissing_smiling_eyes","stuck_out_tongue_winking_eye","stuck_out_tongue_closed_eyes","stuck_out_tongue","flushed","grin","pensive","relieved","unamused","disappointed","persevere","cry","joy","sob","sleepy","disappointed_relieved","cold_sweat","sweat_smile","sweat","weary","tired_face","fearful","scream","angry","rage","triumph","confounded","laughing","yum","mask","sunglasses","sleeping","dizzy_face","astonished","worried","frowning","anguished","smiling_imp","imp","open_mouth","grimacing","neutral_face","confused","hushed","no_mouth","innocent","smirk","expressionless","man_with_gua_pi_mao","man_with_turban","cop","construction_worker","guardsman","baby","boy","girl","man","woman","older_man","older_woman","person_with_blond_hair","angel","princess","smiley_cat","smile_cat","heart_eyes_cat","kissing_cat","smirk_cat","scream_cat","crying_cat_face","joy_cat","pouting_cat","japanese_ogre","japanese_goblin","see_no_evil","hear_no_evil","speak_no_evil","skull","alien","poop","fire","sparkles","star2","dizzy","boom","anger","sweat_drops","droplet","zzz","dash","ear","eyes","nose","tongue","lips","thumbsup","thumbsdown","ok_hand","punch","fist","v","wave","raised_hand","open_hands","point_up_2","point_down","point_right","point_left","raised_hands","pray","point_up","clap","muscle","walking","runner","dancer","couple","family","two_men_holding_hands","two_women_holding_hands","couplekiss","couple_with_heart","dancers","ok_woman","no_good","information_desk_person","raising_hand","massage","haircut","nail_care","bride_with_veil","person_with_pouting_face","person_frowning","bow","tophat","crown","womans_hat","athletic_shoe","mans_shoe","sandal","high_heel","boot","shirt","necktie","womans_clothes","dress","running_shirt_with_sash","jeans","kimono","bikini","briefcase","handbag","pouch","purse","eyeglasses","ribbon","closed_umbrella","lipstick","yellow_heart","blue_heart","purple_heart","green_heart","heart","broken_heart","heartpulse","heartbeat","two_hearts","sparkling_heart","revolving_hearts","cupid","love_letter","kiss","ring","gem","bust_in_silhouette","busts_in_silhouette","speech_balloon","footprints","thought_balloon"] +}, +{ + name: "nature", + icons: ["dog","wolf","cat","mouse","hamster","rabbit","frog","tiger","koala","bear","pig","pig_nose","cow","boar","monkey_face","monkey","horse","sheep","elephant","panda_face","penguin","bird","baby_chick","hatched_chick","hatching_chick","chicken","snake","turtle","bug","bee","ant","beetle","snail","octopus","shell","tropical_fish","fish","dolphin","whale","whale2","cow2","ram","rat","water_buffalo","tiger2","rabbit2","dragon","racehorse","goat","rooster","dog2","pig2","mouse2","ox","dragon_face","blowfish","crocodile","camel","dromedary_camel","leopard","cat2","poodle","feet","bouquet","cherry_blossom","tulip","four_leaf_clover","rose","sunflower","hibiscus","maple_leaf","leaves","fallen_leaf","herb","ear_of_rice","mushroom","cactus","palm_tree","evergreen_tree","deciduous_tree","chestnut","seedling","blossom","globe_with_meridians","sun_with_face","full_moon_with_face","new_moon_with_face","new_moon","waxing_crescent_moon","first_quarter_moon","waxing_gibbous_moon","full_moon","waning_gibbous_moon","last_quarter_moon","waning_crescent_moon","last_quarter_moon_with_face","first_quarter_moon_with_face","crescent_moon","earth_africa","earth_americas","earth_asia","volcano","milky_way","stars","star","sunny","partly_sunny","cloud","zap","umbrella","snowflake","snowman","cyclone","foggy","rainbow","ocean"] +}, +{ + name: "objects", + icons: ["dog","wolf","cat","mouse","hamster","rabbit","frog","tiger","koala","bear","pig","pig_nose","cow","boar","monkey_face","monkey","horse","sheep","elephant","panda_face","penguin","bird","baby_chick","hatched_chick","hatching_chick","chicken","snake","turtle","bug","bee","ant","beetle","snail","octopus","shell","tropical_fish","fish","dolphin","whale","whale2","cow2","ram","rat","water_buffalo","tiger2","rabbit2","dragon","racehorse","goat","rooster","dog2","pig2","mouse2","ox","dragon_face","blowfish","crocodile","camel","dromedary_camel","leopard","cat2","poodle","feet","bouquet","cherry_blossom","tulip","four_leaf_clover","rose","sunflower","hibiscus","maple_leaf","leaves","fallen_leaf","herb","ear_of_rice","mushroom","cactus","palm_tree","evergreen_tree","deciduous_tree","chestnut","seedling","blossom","globe_with_meridians","sun_with_face","full_moon_with_face","new_moon_with_face","new_moon","waxing_crescent_moon","first_quarter_moon","waxing_gibbous_moon","full_moon","waning_gibbous_moon","last_quarter_moon","waning_crescent_moon","last_quarter_moon_with_face","first_quarter_moon_with_face","crescent_moon","earth_africa","earth_americas","earth_asia","volcano","milky_way","stars","star","sunny","partly_sunny","cloud","zap","umbrella","snowflake","snowman","cyclone","foggy","rainbow","ocean"] +}, +{ + name: "places", + icons: ["house","house_with_garden","school","office","post_office","hospital","bank","convenience_store","love_hotel","hotel","wedding","church","department_store","european_post_office","city_sunset","city_dusk","japanese_castle","european_castle","tent","factory","tokyo_tower","japan","mount_fuji","sunrise_over_mountains","sunrise","night_with_stars","statue_of_liberty","bridge_at_night","carousel_horse","ferris_wheel","fountain","roller_coaster","ship","sailboat","speedboat","rowboat","anchor","rocket","airplane","seat","helicopter","steam_locomotive","tram","station","mountain_railway","train2","bullettrain_side","bullettrain_front","light_rail","metro","monorail","train","railway_car","trolleybus","bus","oncoming_bus","blue_car","oncoming_automobile","red_car","taxi","oncoming_taxi","articulated_lorry","truck","rotating_light","police_car","oncoming_police_car","fire_engine","ambulance","minibus","bike","aerial_tramway","suspension_railway","mountain_cableway","tractor","barber","busstop","ticket","vertical_traffic_light","traffic_light","warning","construction","beginner","fuelpump","izakaya_lantern","slot_machine","hotsprings","moyai","circus_tent","performing_arts","round_pushpin","triangular_flag_on_post","cn","us","in","jp","br","ru","de","ng","gb","fr","mx","kr","id","ph","eg","vn","tr","it","es","ca","pl","ar","co","ir","za","my","pk","au","th","ma","tw","nl","ua","sa","ke","ve","pe","ro","cl","uz","bd","kz","be","se","cz","sd","hu","pt","ch","at","tz"] +}, +{ + name: "symbols", + icons: ["hash","one","two","three","four","five","six","seven","eight","nine","zero","keycap_ten","1234","symbols","arrow_up","arrow_down","arrow_left","arrow_right","capital_abcd","abcd","abc","arrow_upper_right","arrow_upper_left","arrow_lower_right","arrow_lower_left","left_right_arrow","arrow_up_down","arrows_counterclockwise","arrow_backward","arrow_forward","arrow_up_small","arrow_down_small","leftwards_arrow_with_hook","arrow_right_hook","information_source","rewind","fast_forward","arrow_double_up","arrow_double_down","arrow_heading_down","arrow_heading_up","ok","twisted_rightwards_arrows","repeat","repeat_one","new","up","cool","free","ng","signal_strength","cinema","koko","u6307","u7a7a","u6e80","u5408","u7981","ideograph_advantage","u5272","u55b6","u6709","u7121","restroom","mens","womens","baby_symbol","wc","potable_water","put_litter_in_its_place","parking","wheelchair","no_smoking","u6708","u7533","sa","m","passport_control","baggage_claim","left_luggage","customs","accept","secret","congratulations","cl","sos","id","no_entry_sign","underage","no_mobile_phones","do_not_litter","non-potable_water","no_bicycles","no_pedestrians","children_crossing","no_entry","eight_spoked_asterisk","sparkle","negative_squared_cross_mark","white_check_mark","eight_pointed_black_star","heart_decoration","vs","vibration_mode","mobile_phone_off","a","b","ab","o2","diamond_shape_with_a_dot_inside","loop","recycle","aries","taurus","gemini","cancer","leo","virgo","libra","scorpius","sagittarius","capricorn","aquarius","pisces","ophiuchus","six_pointed_star","atm","chart","heavy_dollar_sign","currency_exchange","copyright","registered","tm","part_alternation_mark","wavy_dash","top","end","back","on","soon","x","o","exclamation","question","grey_exclamation","grey_question","bangbang","interrobang","arrows_clockwise","clock12","clock1230","clock1","clock130","clock2","clock230","clock3","clock330","clock4","clock430","clock5","clock530","clock6","clock7","clock8","clock9","clock10","clock11","clock630","clock730","clock830","clock930","clock1030","clock1130","heavy_multiplication_x","heavy_plus_sign","heavy_minus_sign","heavy_division_sign","spades","hearts","clubs","diamonds","white_flower","100","heavy_check_mark","ballot_box_with_check","radio_button","link","curly_loop","trident","black_square_button","white_square_button","black_medium_square","white_medium_square","black_medium_small_square","white_medium_small_square","black_small_square","white_small_square","small_red_triangle","white_large_square","black_large_square","black_circle","white_circle","red_circle","large_blue_circle","small_red_triangle_down","large_orange_diamond","large_blue_diamond","small_orange_diamond","small_blue_diamond"] +}]; + +var renderPage = Handlebars.compile( + "" + + "{{#each this}}"+ + "{{#each this}}" + + "" + + "{{/each}}" + + "{{/each}}"+ + "
"); + +var closeSelector = function(){ + $('.emoji-modal, .emoji-modal-wrapper').remove(); +}; + +var showSelector = function(){ + + $('body').append('
'); + + $('.emoji-modal-wrapper').click(function(){ + closeSelector(); + }); + + var rows = []; + var row = []; + var icons = groups[0].icons; + + for(var i=0; i<50; i++){ + if(row.length === 10){ + rows.push(row); + row = []; + } + row.push({src: Discourse.Emoji.urlFor(icons[i]), title: icons[i]}); + } + rows.push(row); + + $('body').append('
' + renderPage(rows) + '
'); + + var composerController = Discourse.__container__.lookup('controller:composer'); + $('.emoji-page a').click(function(){ + composerController.appendText(":" + $(this).attr('title') + ":", {space: true}); + closeSelector(); + }); +}; + +window.PagedownCustom.appendButtons.push({ + id: 'wmd-emoji-button', + description: I18n.t("composer.emoji"), + execute: showSelector +}); diff --git a/plugins/emoji/assets/javascripts/emoji.js.erb b/plugins/emoji/assets/javascripts/emoji.js.erb index 2133626cdd3..9a029375b00 100644 --- a/plugins/emoji/assets/javascripts/emoji.js.erb +++ b/plugins/emoji/assets/javascripts/emoji.js.erb @@ -1,262 +1,162 @@ -(function() { - var emoji = <%= Dir.glob(File.expand_path("../../../public/images/*.png", __FILE__)).map{|f| File.basename(f).split(".")[0]}.inspect %>; +var emoji = <%= Dir.glob(File.expand_path("../../../public/images/*.png", __FILE__)).map{|f| File.basename(f).split(".")[0]}.inspect %>; - var _extendedEmoji = {}; - Discourse.Dialect.registerEmoji = function(code, url) { - _extendedEmoji[code] = url; - }; +// TODO @robin to move this whole thing to es6 +Discourse.Emoji = {}; - function urlFor(code) { - var url = _extendedEmoji[code]; - if (!url && emoji.indexOf(code) !== -1) { - url = Discourse.getURL('/plugins/emoji/images/' + code + '.png'); - } - return url; +var _extendedEmoji = {}; +Discourse.Dialect.registerEmoji = function(code, url) { + _extendedEmoji[code] = url; +}; + +var toSearch; + +var search = function(term, options) { + var maxResults = (options && options["maxResults"]) || -1; + + toSearch = toSearch || emoji.concat(Object.keys(_extendedEmoji)); + + if(maxResults === 0) { + return []; } - function imageFor(code) { - var url = urlFor(code); - if (url) { - return ['img', {href: url, title: ':' + code + ':', 'class': 'emoji', alt: code}]; + var results = []; + + var done = function(){ + return maxResults > 0 && results.length >= maxResults; + } + + for (i=0; i < toSearch.length; i++) { + if (toSearch[i].indexOf(term) === 0) { + results.push(toSearch[i]); + if(done()) { break; } } } - // Also support default emotions - var translations = { - ':)' : 'smile', - ':-)' : 'smile', - ':(' : 'frowning', - ':-(' : 'frowning', - ';)' : 'wink', - ';-)' : 'wink', - ':\'(' : 'cry', - ':\'-(' : 'cry', - ':-\'(' : 'cry', - ':p' : 'stuck_out_tongue', - ':P' : 'stuck_out_tongue', - ':-P' : 'stuck_out_tongue', - ':O' : 'open_mouth', - ':-O' : 'open_mouth', - ':D' : 'smiley', - ':-D' : 'smiley', - ':|' : 'expressionless', - ':-|' : 'expressionless', - ";P" : 'stuck_out_tongue_winking_eye', - ";-P" : 'stuck_out_tongue_winking_eye', - ';)' : 'wink', - ';-)' : 'wink', - ":$" : 'blush', - ":-$" : 'blush' - }; - - var groups = [ - { - name: "emoticons", - icons: ["smile","smiley","grinning","blush","relaxed","wink","heart_eyes","kissing_heart","kissing_closed_eyes","kissing","kissing_smiling_eyes","stuck_out_tongue_winking_eye","stuck_out_tongue_closed_eyes","stuck_out_tongue","flushed","grin","pensive","relieved","unamused","disappointed","persevere","cry","joy","sob","sleepy","disappointed_relieved","cold_sweat","sweat_smile","sweat","weary","tired_face","fearful","scream","angry","rage","triumph","confounded","laughing","yum","mask","sunglasses","sleeping","dizzy_face","astonished","worried","frowning","anguished","smiling_imp","imp","open_mouth","grimacing","neutral_face","confused","hushed","no_mouth","innocent","smirk","expressionless","man_with_gua_pi_mao","man_with_turban","cop","construction_worker","guardsman","baby","boy","girl","man","woman","older_man","older_woman","person_with_blond_hair","angel","princess","smiley_cat","smile_cat","heart_eyes_cat","kissing_cat","smirk_cat","scream_cat","crying_cat_face","joy_cat","pouting_cat","japanese_ogre","japanese_goblin","see_no_evil","hear_no_evil","speak_no_evil","skull","alien","poop","fire","sparkles","star2","dizzy","boom","anger","sweat_drops","droplet","zzz","dash","ear","eyes","nose","tongue","lips","thumbsup","thumbsdown","ok_hand","punch","fist","v","wave","raised_hand","open_hands","point_up_2","point_down","point_right","point_left","raised_hands","pray","point_up","clap","muscle","walking","runner","dancer","couple","family","two_men_holding_hands","two_women_holding_hands","couplekiss","couple_with_heart","dancers","ok_woman","no_good","information_desk_person","raising_hand","massage","haircut","nail_care","bride_with_veil","person_with_pouting_face","person_frowning","bow","tophat","crown","womans_hat","athletic_shoe","mans_shoe","sandal","high_heel","boot","shirt","necktie","womans_clothes","dress","running_shirt_with_sash","jeans","kimono","bikini","briefcase","handbag","pouch","purse","eyeglasses","ribbon","closed_umbrella","lipstick","yellow_heart","blue_heart","purple_heart","green_heart","heart","broken_heart","heartpulse","heartbeat","two_hearts","sparkling_heart","revolving_hearts","cupid","love_letter","kiss","ring","gem","bust_in_silhouette","busts_in_silhouette","speech_balloon","footprints","thought_balloon"] - }, - { - name: "nature", - icons: ["dog","wolf","cat","mouse","hamster","rabbit","frog","tiger","koala","bear","pig","pig_nose","cow","boar","monkey_face","monkey","horse","sheep","elephant","panda_face","penguin","bird","baby_chick","hatched_chick","hatching_chick","chicken","snake","turtle","bug","bee","ant","beetle","snail","octopus","shell","tropical_fish","fish","dolphin","whale","whale2","cow2","ram","rat","water_buffalo","tiger2","rabbit2","dragon","racehorse","goat","rooster","dog2","pig2","mouse2","ox","dragon_face","blowfish","crocodile","camel","dromedary_camel","leopard","cat2","poodle","feet","bouquet","cherry_blossom","tulip","four_leaf_clover","rose","sunflower","hibiscus","maple_leaf","leaves","fallen_leaf","herb","ear_of_rice","mushroom","cactus","palm_tree","evergreen_tree","deciduous_tree","chestnut","seedling","blossom","globe_with_meridians","sun_with_face","full_moon_with_face","new_moon_with_face","new_moon","waxing_crescent_moon","first_quarter_moon","waxing_gibbous_moon","full_moon","waning_gibbous_moon","last_quarter_moon","waning_crescent_moon","last_quarter_moon_with_face","first_quarter_moon_with_face","crescent_moon","earth_africa","earth_americas","earth_asia","volcano","milky_way","stars","star","sunny","partly_sunny","cloud","zap","umbrella","snowflake","snowman","cyclone","foggy","rainbow","ocean"] - }, - { - name: "objects", - icons: ["dog","wolf","cat","mouse","hamster","rabbit","frog","tiger","koala","bear","pig","pig_nose","cow","boar","monkey_face","monkey","horse","sheep","elephant","panda_face","penguin","bird","baby_chick","hatched_chick","hatching_chick","chicken","snake","turtle","bug","bee","ant","beetle","snail","octopus","shell","tropical_fish","fish","dolphin","whale","whale2","cow2","ram","rat","water_buffalo","tiger2","rabbit2","dragon","racehorse","goat","rooster","dog2","pig2","mouse2","ox","dragon_face","blowfish","crocodile","camel","dromedary_camel","leopard","cat2","poodle","feet","bouquet","cherry_blossom","tulip","four_leaf_clover","rose","sunflower","hibiscus","maple_leaf","leaves","fallen_leaf","herb","ear_of_rice","mushroom","cactus","palm_tree","evergreen_tree","deciduous_tree","chestnut","seedling","blossom","globe_with_meridians","sun_with_face","full_moon_with_face","new_moon_with_face","new_moon","waxing_crescent_moon","first_quarter_moon","waxing_gibbous_moon","full_moon","waning_gibbous_moon","last_quarter_moon","waning_crescent_moon","last_quarter_moon_with_face","first_quarter_moon_with_face","crescent_moon","earth_africa","earth_americas","earth_asia","volcano","milky_way","stars","star","sunny","partly_sunny","cloud","zap","umbrella","snowflake","snowman","cyclone","foggy","rainbow","ocean"] - }, - { - name: "places", - icons: ["house","house_with_garden","school","office","post_office","hospital","bank","convenience_store","love_hotel","hotel","wedding","church","department_store","european_post_office","city_sunset","city_dusk","japanese_castle","european_castle","tent","factory","tokyo_tower","japan","mount_fuji","sunrise_over_mountains","sunrise","night_with_stars","statue_of_liberty","bridge_at_night","carousel_horse","ferris_wheel","fountain","roller_coaster","ship","sailboat","speedboat","rowboat","anchor","rocket","airplane","seat","helicopter","steam_locomotive","tram","station","mountain_railway","train2","bullettrain_side","bullettrain_front","light_rail","metro","monorail","train","railway_car","trolleybus","bus","oncoming_bus","blue_car","oncoming_automobile","red_car","taxi","oncoming_taxi","articulated_lorry","truck","rotating_light","police_car","oncoming_police_car","fire_engine","ambulance","minibus","bike","aerial_tramway","suspension_railway","mountain_cableway","tractor","barber","busstop","ticket","vertical_traffic_light","traffic_light","warning","construction","beginner","fuelpump","izakaya_lantern","slot_machine","hotsprings","moyai","circus_tent","performing_arts","round_pushpin","triangular_flag_on_post","cn","us","in","jp","br","ru","de","ng","gb","fr","mx","kr","id","ph","eg","vn","tr","it","es","ca","pl","ar","co","ir","za","my","pk","au","th","ma","tw","nl","ua","sa","ke","ve","pe","ro","cl","uz","bd","kz","be","se","cz","sd","hu","pt","ch","at","tz"] - }, - { - name: "symbols", - icons: ["hash","one","two","three","four","five","six","seven","eight","nine","zero","keycap_ten","1234","symbols","arrow_up","arrow_down","arrow_left","arrow_right","capital_abcd","abcd","abc","arrow_upper_right","arrow_upper_left","arrow_lower_right","arrow_lower_left","left_right_arrow","arrow_up_down","arrows_counterclockwise","arrow_backward","arrow_forward","arrow_up_small","arrow_down_small","leftwards_arrow_with_hook","arrow_right_hook","information_source","rewind","fast_forward","arrow_double_up","arrow_double_down","arrow_heading_down","arrow_heading_up","ok","twisted_rightwards_arrows","repeat","repeat_one","new","up","cool","free","ng","signal_strength","cinema","koko","u6307","u7a7a","u6e80","u5408","u7981","ideograph_advantage","u5272","u55b6","u6709","u7121","restroom","mens","womens","baby_symbol","wc","potable_water","put_litter_in_its_place","parking","wheelchair","no_smoking","u6708","u7533","sa","m","passport_control","baggage_claim","left_luggage","customs","accept","secret","congratulations","cl","sos","id","no_entry_sign","underage","no_mobile_phones","do_not_litter","non-potable_water","no_bicycles","no_pedestrians","children_crossing","no_entry","eight_spoked_asterisk","sparkle","negative_squared_cross_mark","white_check_mark","eight_pointed_black_star","heart_decoration","vs","vibration_mode","mobile_phone_off","a","b","ab","o2","diamond_shape_with_a_dot_inside","loop","recycle","aries","taurus","gemini","cancer","leo","virgo","libra","scorpius","sagittarius","capricorn","aquarius","pisces","ophiuchus","six_pointed_star","atm","chart","heavy_dollar_sign","currency_exchange","copyright","registered","tm","part_alternation_mark","wavy_dash","top","end","back","on","soon","x","o","exclamation","question","grey_exclamation","grey_question","bangbang","interrobang","arrows_clockwise","clock12","clock1230","clock1","clock130","clock2","clock230","clock3","clock330","clock4","clock430","clock5","clock530","clock6","clock7","clock8","clock9","clock10","clock11","clock630","clock730","clock830","clock930","clock1030","clock1130","heavy_multiplication_x","heavy_plus_sign","heavy_minus_sign","heavy_division_sign","spades","hearts","clubs","diamonds","white_flower","100","heavy_check_mark","ballot_box_with_check","radio_button","link","curly_loop","trident","black_square_button","white_square_button","black_medium_square","white_medium_square","black_medium_small_square","white_medium_small_square","black_small_square","white_small_square","small_red_triangle","white_large_square","black_large_square","black_circle","white_circle","red_circle","large_blue_circle","small_red_triangle_down","large_orange_diamond","large_blue_diamond","small_orange_diamond","small_blue_diamond"] - }]; - - function checkPrev(prev) { - if (prev && prev.length) { - var lastToken = prev[prev.length-1]; - if (lastToken && lastToken.charAt) { - var lastChar = lastToken.charAt(lastToken.length-1); - if (lastChar !== ' ' && lastChar !== "\n") return false; + if(!done()){ + for (i=0; i < toSearch.length; i++) { + if (toSearch[i].indexOf(term) > 0) { + results.push(toSearch[i]); + if(done()) { break; } } } - return true; } - var translationsWithColon = {}; - Object.keys(translations).forEach(function (t) { - if (t[0] === ':') { - translationsWithColon[t] = translations[t]; - } else { - var replacement = translations[t]; - Discourse.Dialect.inlineReplace(t, function (token, match, prev) { - if (!Discourse.SiteSettings.enable_emoji) { return token; } - return checkPrev(prev) ? imageFor(replacement) : token; - }); - } - }); + return results; +} - function escapeRegExp(s) { - return s.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&') +Discourse.Emoji.search = search; + +var urlFor = function(code) { + var url = _extendedEmoji[code]; + if (!url && emoji.indexOf(code) !== -1) { + url = Discourse.getURL('/plugins/emoji/images/' + code + '.png'); } + return url; +} - var translationColonRegexp = new RegExp(Object.keys(translationsWithColon).map(function (t) { - return "(" + escapeRegExp(t) + ")"; - }).join("|")); +Discourse.Emoji.urlFor = urlFor; - Discourse.Dialect.registerInline(':', function(text, match, prev) { - if (!Discourse.SiteSettings.enable_emoji) { return; } +function imageFor(code) { + var url = urlFor(code); + if (url) { + return ['img', {href: url, title: ':' + code + ':', 'class': 'emoji', alt: code}]; + } +} - var endPos = text.indexOf(':', 1), - firstSpace = text.search(/\s/), - contents; +// Also support default emotions +var translations = { + ':)' : 'smile', + ':-)' : 'smile', + ':(' : 'frowning', + ':-(' : 'frowning', + ';)' : 'wink', + ';-)' : 'wink', + ':\'(' : 'cry', + ':\'-(' : 'cry', + ':-\'(' : 'cry', + ':p' : 'stuck_out_tongue', + ':P' : 'stuck_out_tongue', + ':-P' : 'stuck_out_tongue', + ':O' : 'open_mouth', + ':-O' : 'open_mouth', + ':D' : 'smiley', + ':-D' : 'smiley', + ':|' : 'expressionless', + ':-|' : 'expressionless', + ";P" : 'stuck_out_tongue_winking_eye', + ";-P" : 'stuck_out_tongue_winking_eye', + ":$" : 'blush', + ":-$" : 'blush' +}; - if (!checkPrev(prev)) { return; } +Discourse.Emoji.translations = translations; - // If there is no trailing colon, check our translations that begin with colons - if (endPos === -1 || (firstSpace !== -1 && endPos > firstSpace)) { - translationColonRegexp.lastIndex = 0; - var m = translationColonRegexp.exec(text); - if (m && m[0] && text.indexOf(m[0]) === 0) { - - // Check outer edge - var lastChar = text.charAt(m[0].length); - if (lastChar && (lastChar !== ' ' && lastChar !== "\n")) return; - contents = imageFor(translationsWithColon[m[0]]); - if (contents) { - return [m[0].length, contents]; - } - } - return; +function checkPrev(prev) { + if (prev && prev.length) { + var lastToken = prev[prev.length-1]; + if (lastToken && lastToken.charAt) { + var lastChar = lastToken.charAt(lastToken.length-1); + if (lastChar !== ' ' && lastChar !== "\n") return false; } + } + return true; +} - // Simple find and replace from our array - var between = text.slice(1, endPos); - contents = imageFor(between); - if (contents) { - return [endPos+1, contents]; - } - }); - - - if(window.PagedownCustom) { - var renderPage = Handlebars.compile( - "" + - "{{#each this}}"+ - "{{#each this}}" + - "" + - "{{/each}}" + - "{{/each}}"+ - "
"); - - var closeSelector = function(){ - $('.emoji-modal, .emoji-modal-wrapper').remove(); - }; - - var showSelector = function(){ - - $('body').append('
'); - - $('.emoji-modal-wrapper').click(function(){ - closeSelector(); - }); - - var rows = []; - var row = []; - var icons = groups[0].icons; - - for(var i=0; i<50; i++){ - if(row.length === 10){ - rows.push(row); - row = []; - } - row.push({src: urlFor(icons[i]), title: icons[i]}); - } - rows.push(row); - - $('body').append('
' + renderPage(rows) + '
'); - - var composerController = Discourse.__container__.lookup('controller:composer'); - $('.emoji-page a').click(function(){ - composerController.appendText(":" + $(this).attr('title') + ":", {space: true}); - closeSelector(); - }); - }; - - window.PagedownCustom.appendButtons.push({ - id: 'wmd-emoji-button', - description: I18n.t("composer.emoji"), - execute: showSelector +var translationsWithColon = {}; +Object.keys(translations).forEach(function (t) { + if (t[0] === ':') { + translationsWithColon[t] = translations[t]; + } else { + var replacement = translations[t]; + Discourse.Dialect.inlineReplace(t, function (token, match, prev) { + if (!Discourse.SiteSettings.enable_emoji) { return token; } + return checkPrev(prev) ? imageFor(replacement) : token; }); } +}); - // TODO: Make this a proper ES6 import - var ComposerView = (Discourse && Discourse.ComposerView) || (typeof require !== "undefined" && require('discourse/views/composer').default); - if (ComposerView) { - ComposerView.on("initWmdEditor", function(event){ - if (!Discourse.SiteSettings.enable_emoji) { return; } +function escapeRegExp(s) { + return s.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'); +} - var baseUrl = Discourse.getURL("/"); +var translationColonRegexp = new RegExp(Object.keys(translationsWithColon).map(function (t) { + return "(" + escapeRegExp(t) + ")"; + }).join("|")); - template = Handlebars.compile("
" + - "" + - "
"); +Discourse.Dialect.registerInline(':', function(text, match, prev) { + if (!Discourse.SiteSettings.enable_emoji) { return; } - var toSearch = emoji.concat(Object.keys(_extendedEmoji)); + var endPos = text.indexOf(':', 1), + firstSpace = text.search(/\s/), + contents; - $('#wmd-input').autocomplete({ - template: template, - key: ":", - transformComplete: function(v){ return v.code + ":"; }, - dataSource: function(term){ - return new Ember.RSVP.Promise(function(resolve) { - var full = ":" + term; - term = term.toLowerCase(); + if (!checkPrev(prev)) { return; } - if (term === "") { - return resolve(["smile", "smiley", "wink", "sunny", "blush"]); - } + // If there is no trailing colon, check our translations that begin with colons + if (endPos === -1 || (firstSpace !== -1 && endPos > firstSpace)) { + translationColonRegexp.lastIndex = 0; + var m = translationColonRegexp.exec(text); + if (m && m[0] && text.indexOf(m[0]) === 0) { - if (translations[full]) { - return resolve([translations[full]]); - } - - var options = []; - var i; - for (i=0; i < toSearch.length; i++) { - if (toSearch[i].indexOf(term) === 0) { - options.push(toSearch[i]); - if(options.length > 4) { break; } - } - } - - if (options.length <= 4) { - for (i=0; i < toSearch.length; i++) { - if (toSearch[i].indexOf(term) > 0) { - options.push(toSearch[i]); - if(options.length > 4) { break; } - } - } - } - - return resolve(options); - }).then(function(list) { - return list.map(function(i) { - return {code: i, src: urlFor(i)}; - }); - }); - } - }); - }); + // Check outer edge + var lastChar = text.charAt(m[0].length); + if (lastChar && (lastChar !== ' ' && lastChar !== "\n")) return; + contents = imageFor(translationsWithColon[m[0]]); + if (contents) { + return [m[0].length, contents]; + } + } + return; } - Discourse.Markdown.whiteListTag('img', 'class', 'emoji'); + // Simple find and replace from our array + var between = text.slice(1, endPos); + contents = imageFor(between); + if (contents) { + return [endPos+1, contents]; + } +}); + + +Discourse.Markdown.whiteListTag('img', 'class', 'emoji'); -}).call(this); diff --git a/plugins/emoji/plugin.rb b/plugins/emoji/plugin.rb index 261b6686343..9209cca369d 100644 --- a/plugins/emoji/plugin.rb +++ b/plugins/emoji/plugin.rb @@ -4,6 +4,8 @@ # authors: Sam Saffron, Robin Ward register_asset('javascripts/emoji.js.erb', :server_side) +register_asset('javascripts/emoji-autocomplete.js', :composer) +register_asset('javascripts/emoji-toolbar.js', :composer) register_asset('stylesheets/emoji.css') after_initialize do