emojionearea.js 60 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321
  1. /*!
  2. * EmojioneArea v3.1.8
  3. * https://github.com/mervick/emojionearea
  4. * Copyright Andrey Izman and other contributors
  5. * Released under the MIT license
  6. * Date: 2017-03-06T21:02Z
  7. */
  8. window = ( typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {} );
  9. document = window.document || {};
  10. ; ( function ( factory, global ) {
  11. if ( typeof require === "function" && typeof exports === "object" && typeof module === "object" ) {
  12. // CommonJS
  13. factory( require( "jquery" ) );
  14. } else if ( typeof define === "function" && define.amd ) {
  15. // AMD
  16. define( [ "jquery" ], factory );
  17. } else {
  18. // Normal script tag
  19. factory( global.jQuery );
  20. }
  21. }( function ( $ ) {
  22. "use strict";
  23. var unique = 0;
  24. var eventStorage = {};
  25. var possibleEvents = {};
  26. var emojione = window.emojione;
  27. var readyCallbacks = [];
  28. function emojioneReady (fn) {
  29. if (emojione) {
  30. fn();
  31. } else {
  32. readyCallbacks.push(fn);
  33. }
  34. };
  35. var blankImg = 'data:image/gif;base64,R0lGODlhAQABAJH/AP///wAAAMDAwAAAACH5BAEAAAIALAAAAAABAAEAAAICVAEAOw==';
  36. var slice = [].slice;
  37. var css_class = "emojionearea";
  38. var emojioneSupportMode = 0;
  39. var invisibleChar = '​';
  40. function trigger(self, event, args) {
  41. var result = true, j = 1;
  42. if (event) {
  43. event = event.toLowerCase();
  44. do {
  45. var _event = j==1 ? '@' + event : event;
  46. if (eventStorage[self.id][_event] && eventStorage[self.id][_event].length) {
  47. $.each(eventStorage[self.id][_event], function (i, fn) {
  48. return result = fn.apply(self, args|| []) !== false;
  49. });
  50. }
  51. } while (result && !!j--);
  52. }
  53. return result;
  54. }
  55. function attach(self, element, events, target) {
  56. target = target || function (event, callerEvent) { return $(callerEvent.currentTarget) };
  57. $.each(events, function(event, link) {
  58. event = $.isArray(events) ? link : event;
  59. (possibleEvents[self.id][link] || (possibleEvents[self.id][link] = []))
  60. .push([element, event, target]);
  61. });
  62. }
  63. function getTemplate(template, unicode, shortname) {
  64. var imageType = emojione.imageType, imagePath;
  65. if (imageType=='svg'){
  66. imagePath = emojione.imagePathSVG;
  67. } else {
  68. imagePath = emojione.imagePathPNG;
  69. }
  70. var friendlyName = '';
  71. if (shortname) {
  72. friendlyName = shortname.substr(1, shortname.length - 2).replace(/_/g, ' ').replace(/\w\S*/g, function(txt) { return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
  73. }
  74. return template
  75. .replace('{name}', shortname || '')
  76. .replace('{friendlyName}', friendlyName)
  77. .replace('{img}', imagePath + (emojioneSupportMode < 2 ? unicode.toUpperCase() : unicode) + '.' + imageType)
  78. .replace('{uni}', unicode)
  79. .replace('{alt}', emojione.convert(unicode));
  80. };
  81. function shortnameTo(str, template, clear) {
  82. return str.replace(/:?\+?[\w_\-]+:?/g, function(shortname) {
  83. shortname = ":" + shortname.replace(/:$/,'').replace(/^:/,'') + ":";
  84. var unicode = emojione.emojioneList[shortname];
  85. if (unicode) {
  86. if (emojioneSupportMode > 3) unicode = unicode.unicode;
  87. return getTemplate(template, unicode[unicode.length-1], shortname);
  88. }
  89. return clear ? '' : shortname;
  90. });
  91. };
  92. function pasteHtmlAtCaret(html) {
  93. var sel, range;
  94. if (window.getSelection) {
  95. sel = window.getSelection();
  96. if (sel.getRangeAt && sel.rangeCount) {
  97. range = sel.getRangeAt(0);
  98. range.deleteContents();
  99. var el = document.createElement("div");
  100. el.innerHTML = html;
  101. var frag = document.createDocumentFragment(), node, lastNode;
  102. while ( (node = el.firstChild) ) {
  103. lastNode = frag.appendChild(node);
  104. }
  105. range.insertNode(frag);
  106. if (lastNode) {
  107. range = range.cloneRange();
  108. range.setStartAfter(lastNode);
  109. range.collapse(true);
  110. sel.removeAllRanges();
  111. sel.addRange(range);
  112. }
  113. }
  114. } else if (document.selection && document.selection.type != "Control") {
  115. document.selection.createRange().pasteHTML(html);
  116. }
  117. }
  118. var getDefaultOptions = function () {
  119. return $.fn.emojioneArea && $.fn.emojioneArea.defaults ? $.fn.emojioneArea.defaults : {
  120. attributes: {
  121. dir : "ltr",
  122. spellcheck : false,
  123. autocomplete : "off",
  124. autocorrect : "off",
  125. autocapitalize : "off",
  126. },
  127. placeholder : null,
  128. emojiPlaceholder : ":smiley:",
  129. container : null,
  130. hideSource : true,
  131. shortnames : true,
  132. sprite : true,
  133. pickerPosition : "top", // top | bottom | right
  134. filtersPosition : "top", // top | bottom
  135. hidePickerOnBlur : true,
  136. buttonTitle : "Use the TAB key to insert emoji faster",
  137. tones : true,
  138. tonesStyle : "bullet", // bullet | radio | square | checkbox
  139. inline : null, // null - auto
  140. saveEmojisAs : "unicode", // unicode | shortname | image
  141. shortcuts : true,
  142. autocomplete : true,
  143. autocompleteTones : false,
  144. standalone : false,
  145. useInternalCDN : true, // Use the self loading mechanism
  146. imageType : "png", // Default image type used by internal CDN
  147. recentEmojis : true,
  148. textcomplete: {
  149. maxCount : 15,
  150. placement : null // null - default | top | absleft | absright
  151. },
  152. filters: {
  153. tones: {
  154. title: "Diversity",
  155. emoji: "santa runner surfer swimmer lifter ear nose point_up_2 point_down point_left point_right punch " +
  156. "wave ok_hand thumbsup thumbsdown clap open_hands boy girl man woman cop bride_with_veil person_with_blond_hair " +
  157. "man_with_gua_pi_mao man_with_turban older_man grandma baby construction_worker princess angel " +
  158. "information_desk_person guardsman dancer nail_care massage haircut muscle spy hand_splayed middle_finger " +
  159. "vulcan no_good ok_woman bow raising_hand raised_hands person_frowning person_with_pouting_face pray rowboat " +
  160. "bicyclist mountain_bicyclist walking bath metal point_up basketball_player fist raised_hand v writing_hand"
  161. },
  162. recent: {
  163. icon: "clock3",
  164. title: "Recent",
  165. emoji: ""
  166. },
  167. smileys_people: {
  168. icon: "yum",
  169. title: "Smileys & People",
  170. emoji: "grinning grimacing grin joy smiley smile sweat_smile laughing innocent wink blush slight_smile " +
  171. "upside_down relaxed yum relieved heart_eyes kissing_heart kissing kissing_smiling_eyes " +
  172. "kissing_closed_eyes stuck_out_tongue_winking_eye stuck_out_tongue_closed_eyes stuck_out_tongue " +
  173. "money_mouth nerd sunglasses hugging smirk no_mouth neutral_face expressionless unamused rolling_eyes " +
  174. "thinking flushed disappointed worried angry rage pensive confused slight_frown frowning2 persevere " +
  175. "confounded tired_face weary triumph open_mouth scream fearful cold_sweat hushed frowning anguished " +
  176. "cry disappointed_relieved sleepy sweat sob dizzy_face astonished zipper_mouth mask thermometer_face " +
  177. "head_bandage sleeping zzz poop smiling_imp imp japanese_ogre japanese_goblin skull ghost alien robot " +
  178. "smiley_cat smile_cat joy_cat heart_eyes_cat smirk_cat kissing_cat scream_cat crying_cat_face " +
  179. "pouting_cat raised_hands clap wave thumbsup thumbsdown punch fist v ok_hand raised_hand open_hands " +
  180. "muscle pray point_up point_up_2 point_down point_left point_right middle_finger hand_splayed metal " +
  181. "vulcan writing_hand nail_care lips tongue ear nose eye eyes bust_in_silhouette busts_in_silhouette " +
  182. "speaking_head baby boy girl man woman person_with_blond_hair older_man older_woman man_with_gua_pi_mao " +
  183. "man_with_turban cop construction_worker guardsman spy santa angel princess bride_with_veil walking " +
  184. "runner dancer dancers couple two_men_holding_hands two_women_holding_hands bow information_desk_person " +
  185. "no_good ok_woman raising_hand person_with_pouting_face person_frowning haircut massage couple_with_heart " +
  186. "couple_ww couple_mm couplekiss kiss_ww kiss_mm family family_mwg family_mwgb family_mwbb family_mwgg " +
  187. "family_wwb family_wwg family_wwgb family_wwbb family_wwgg family_mmb family_mmg family_mmgb family_mmbb " +
  188. "family_mmgg womans_clothes shirt jeans necktie dress bikini kimono lipstick kiss footprints high_heel " +
  189. "sandal boot mans_shoe athletic_shoe womans_hat tophat helmet_with_cross mortar_board crown school_satchel " +
  190. "pouch purse handbag briefcase eyeglasses dark_sunglasses ring closed_umbrella"
  191. },
  192. animals_nature: {
  193. icon: "hamster",
  194. title: "Animals & Nature",
  195. emoji: "dog cat mouse hamster rabbit bear panda_face koala tiger lion_face cow pig pig_nose frog " +
  196. "octopus monkey_face see_no_evil hear_no_evil speak_no_evil monkey chicken penguin bird baby_chick " +
  197. "hatching_chick hatched_chick wolf boar horse unicorn bee bug snail beetle ant spider scorpion crab " +
  198. "snake turtle tropical_fish fish blowfish dolphin whale whale2 crocodile leopard tiger2 water_buffalo " +
  199. "ox cow2 dromedary_camel camel elephant goat ram sheep racehorse pig2 rat mouse2 rooster turkey dove " +
  200. "dog2 poodle cat2 rabbit2 chipmunk feet dragon dragon_face cactus christmas_tree evergreen_tree " +
  201. "deciduous_tree palm_tree seedling herb shamrock four_leaf_clover bamboo tanabata_tree leaves " +
  202. "fallen_leaf maple_leaf ear_of_rice hibiscus sunflower rose tulip blossom cherry_blossom bouquet " +
  203. "mushroom chestnut jack_o_lantern shell spider_web earth_americas earth_africa earth_asia full_moon " +
  204. "waning_gibbous_moon last_quarter_moon waning_crescent_moon new_moon waxing_crescent_moon " +
  205. "first_quarter_moon waxing_gibbous_moon new_moon_with_face full_moon_with_face first_quarter_moon_with_face " +
  206. "last_quarter_moon_with_face sun_with_face crescent_moon star star2 dizzy sparkles comet sunny " +
  207. "white_sun_small_cloud partly_sunny white_sun_cloud white_sun_rain_cloud cloud cloud_rain " +
  208. "thunder_cloud_rain cloud_lightning zap fire boom snowflake cloud_snow snowman2 snowman wind_blowing_face " +
  209. "dash cloud_tornado fog umbrella2 umbrella droplet sweat_drops ocean"
  210. },
  211. food_drink: {
  212. icon: "pizza",
  213. title: "Food & Drink",
  214. emoji: "green_apple apple pear tangerine lemon banana watermelon grapes strawberry melon cherries peach " +
  215. "pineapple tomato eggplant hot_pepper corn sweet_potato honey_pot bread cheese poultry_leg meat_on_bone " +
  216. "fried_shrimp egg hamburger fries hotdog pizza spaghetti taco burrito ramen stew fish_cake sushi bento " +
  217. "curry rice_ball rice rice_cracker oden dango shaved_ice ice_cream icecream cake birthday custard candy " +
  218. "lollipop chocolate_bar popcorn doughnut cookie beer beers wine_glass cocktail tropical_drink champagne " +
  219. "sake tea coffee baby_bottle fork_and_knife fork_knife_plate"
  220. },
  221. activity: {
  222. icon: "basketball",
  223. title: "Activity",
  224. emoji: "soccer basketball football baseball tennis volleyball rugby_football 8ball golf golfer ping_pong " +
  225. "badminton hockey field_hockey cricket ski skier snowboarder ice_skate bow_and_arrow fishing_pole_and_fish " +
  226. "rowboat swimmer surfer bath basketball_player lifter bicyclist mountain_bicyclist horse_racing levitate " +
  227. "trophy running_shirt_with_sash medal military_medal reminder_ribbon rosette ticket tickets performing_arts " +
  228. "art circus_tent microphone headphones musical_score musical_keyboard saxophone trumpet guitar violin " +
  229. "clapper video_game space_invader dart game_die slot_machine bowling"
  230. },
  231. travel_places: {
  232. icon: "rocket",
  233. title: "Travel & Places",
  234. emoji: "red_car taxi blue_car bus trolleybus race_car police_car ambulance fire_engine minibus truck " +
  235. "articulated_lorry tractor motorcycle bike rotating_light oncoming_police_car oncoming_bus " +
  236. "oncoming_automobile oncoming_taxi aerial_tramway mountain_cableway suspension_railway railway_car " +
  237. "train monorail bullettrain_side bullettrain_front light_rail mountain_railway steam_locomotive train2 " +
  238. "metro tram station helicopter airplane_small airplane airplane_departure airplane_arriving sailboat " +
  239. "motorboat speedboat ferry cruise_ship rocket satellite_orbital seat anchor construction fuelpump busstop " +
  240. "vertical_traffic_light traffic_light checkered_flag ship ferris_wheel roller_coaster carousel_horse " +
  241. "construction_site foggy tokyo_tower factory fountain rice_scene mountain mountain_snow mount_fuji volcano " +
  242. "japan camping tent park motorway railway_track sunrise sunrise_over_mountains desert beach island " +
  243. "city_sunset city_dusk cityscape night_with_stars bridge_at_night milky_way stars sparkler fireworks " +
  244. "rainbow homes european_castle japanese_castle stadium statue_of_liberty house house_with_garden " +
  245. "house_abandoned office department_store post_office european_post_office hospital bank hotel " +
  246. "convenience_store school love_hotel wedding classical_building church mosque synagogue kaaba shinto_shrine"
  247. },
  248. objects: {
  249. icon: "bulb",
  250. title: "Objects",
  251. emoji: "watch iphone calling computer keyboard desktop printer mouse_three_button trackball joystick " +
  252. "compression minidisc floppy_disk cd dvd vhs camera camera_with_flash video_camera movie_camera projector " +
  253. "film_frames telephone_receiver telephone pager fax tv radio microphone2 level_slider control_knobs " +
  254. "stopwatch timer alarm_clock clock hourglass_flowing_sand hourglass satellite battery electric_plug bulb " +
  255. "flashlight candle wastebasket oil money_with_wings dollar yen euro pound moneybag credit_card gem scales " +
  256. "wrench hammer hammer_pick tools pick nut_and_bolt gear chains gun bomb knife dagger crossed_swords shield " +
  257. "smoking skull_crossbones coffin urn amphora crystal_ball prayer_beads barber alembic telescope microscope " +
  258. "hole pill syringe thermometer label bookmark toilet shower bathtub key key2 couch sleeping_accommodation " +
  259. "bed door bellhop frame_photo map beach_umbrella moyai shopping_bags balloon flags ribbon gift confetti_ball " +
  260. "tada dolls wind_chime crossed_flags izakaya_lantern envelope envelope_with_arrow incoming_envelope e-mail " +
  261. "love_letter postbox mailbox_closed mailbox mailbox_with_mail mailbox_with_no_mail package postal_horn " +
  262. "inbox_tray outbox_tray scroll page_with_curl bookmark_tabs bar_chart chart_with_upwards_trend " +
  263. "chart_with_downwards_trend page_facing_up date calendar calendar_spiral card_index card_box ballot_box " +
  264. "file_cabinet clipboard notepad_spiral file_folder open_file_folder dividers newspaper2 newspaper notebook " +
  265. "closed_book green_book blue_book orange_book notebook_with_decorative_cover ledger books book link " +
  266. "paperclip paperclips scissors triangular_ruler straight_ruler pushpin round_pushpin triangular_flag_on_post " +
  267. "flag_white flag_black closed_lock_with_key lock unlock lock_with_ink_pen pen_ballpoint pen_fountain " +
  268. "black_nib pencil pencil2 crayon paintbrush mag mag_right"
  269. },
  270. symbols: {
  271. icon: "heartpulse",
  272. title: "Symbols",
  273. emoji: "heart yellow_heart green_heart blue_heart purple_heart broken_heart heart_exclamation two_hearts " +
  274. "revolving_hearts heartbeat heartpulse sparkling_heart cupid gift_heart heart_decoration peace cross " +
  275. "star_and_crescent om_symbol wheel_of_dharma star_of_david six_pointed_star menorah yin_yang orthodox_cross " +
  276. "place_of_worship ophiuchus aries taurus gemini cancer leo virgo libra scorpius sagittarius capricorn " +
  277. "aquarius pisces id atom u7a7a u5272 radioactive biohazard mobile_phone_off vibration_mode u6709 u7121 " +
  278. "u7533 u55b6 u6708 eight_pointed_black_star vs accept white_flower ideograph_advantage secret congratulations " +
  279. "u5408 u6e80 u7981 a b ab cl o2 sos no_entry name_badge no_entry_sign x o anger hotsprings no_pedestrians " +
  280. "do_not_litter no_bicycles non-potable_water underage no_mobile_phones exclamation grey_exclamation question " +
  281. "grey_question bangbang interrobang 100 low_brightness high_brightness trident fleur-de-lis part_alternation_mark " +
  282. "warning children_crossing beginner recycle u6307 chart sparkle eight_spoked_asterisk negative_squared_cross_mark " +
  283. "white_check_mark diamond_shape_with_a_dot_inside cyclone loop globe_with_meridians m atm sa passport_control " +
  284. "customs baggage_claim left_luggage wheelchair no_smoking wc parking potable_water mens womens baby_symbol " +
  285. "restroom put_litter_in_its_place cinema signal_strength koko ng ok up cool new free zero one two three four " +
  286. "five six seven eight nine ten 1234 arrow_forward pause_button play_pause stop_button record_button track_next " +
  287. "track_previous fast_forward rewind twisted_rightwards_arrows repeat repeat_one arrow_backward arrow_up_small " +
  288. "arrow_down_small arrow_double_up arrow_double_down arrow_right arrow_left arrow_up arrow_down arrow_upper_right " +
  289. "arrow_lower_right arrow_lower_left arrow_upper_left arrow_up_down left_right_arrow arrows_counterclockwise " +
  290. "arrow_right_hook leftwards_arrow_with_hook arrow_heading_up arrow_heading_down hash asterisk information_source " +
  291. "abc abcd capital_abcd symbols musical_note notes wavy_dash curly_loop heavy_check_mark arrows_clockwise " +
  292. "heavy_plus_sign heavy_minus_sign heavy_division_sign heavy_multiplication_x heavy_dollar_sign currency_exchange " +
  293. "copyright registered tm end back on top soon ballot_box_with_check radio_button white_circle black_circle " +
  294. "red_circle large_blue_circle small_orange_diamond small_blue_diamond large_orange_diamond large_blue_diamond " +
  295. "small_red_triangle black_small_square white_small_square black_large_square white_large_square small_red_triangle_down " +
  296. "black_medium_square white_medium_square black_medium_small_square white_medium_small_square black_square_button " +
  297. "white_square_button speaker sound loud_sound mute mega loudspeaker bell no_bell black_joker mahjong spades " +
  298. "clubs hearts diamonds flower_playing_cards thought_balloon anger_right speech_balloon clock1 clock2 clock3 " +
  299. "clock4 clock5 clock6 clock7 clock8 clock9 clock10 clock11 clock12 clock130 clock230 clock330 clock430 " +
  300. "clock530 clock630 clock730 clock830 clock930 clock1030 clock1130 clock1230 eye_in_speech_bubble"
  301. },
  302. flags: {
  303. icon: "flag_gb",
  304. title: "Flags",
  305. emoji: "ac af al dz ad ao ai ag ar am aw au at az bs bh bd bb by be bz bj bm bt bo ba bw br bn bg bf bi " +
  306. "cv kh cm ca ky cf td flag_cl cn co km cg flag_cd cr hr cu cy cz dk dj dm do ec eg sv gq er ee et fk fo " +
  307. "fj fi fr pf ga gm ge de gh gi gr gl gd gu gt gn gw gy ht hn hk hu is in flag_id ir iq ie il it ci jm jp " +
  308. "je jo kz ke ki xk kw kg la lv lb ls lr ly li lt lu mo mk mg mw my mv ml mt mh mr mu mx fm md mc mn me " +
  309. "ms ma mz mm na nr np nl nc nz ni ne flag_ng nu kp no om pk pw ps pa pg py pe ph pl pt pr qa ro ru rw " +
  310. "sh kn lc vc ws sm st flag_sa sn rs sc sl sg sk si sb so za kr es lk sd sr sz se ch sy tw tj tz th tl " +
  311. "tg to tt tn tr flag_tm flag_tm ug ua ae gb us vi uy uz vu va ve vn wf eh ye zm zw re ax ta io bq cx " +
  312. "cc gg im yt nf pn bl pm gs tk bv hm sj um ic ea cp dg as aq vg ck cw eu gf tf gp mq mp sx ss tc "
  313. }
  314. }
  315. };
  316. };
  317. function isObject(variable) {
  318. return typeof variable === 'object';
  319. };
  320. function getOptions(options) {
  321. var default_options = getDefaultOptions();
  322. if (options && options['filters']) {
  323. var filters = default_options.filters;
  324. $.each(options['filters'], function(filter, data) {
  325. if (!isObject(data) || $.isEmptyObject(data)) {
  326. delete filters[filter];
  327. return;
  328. }
  329. $.each(data, function(key, val) {
  330. filters[filter][key] = val;
  331. });
  332. });
  333. options['filters'] = filters;
  334. }
  335. return $.extend({}, default_options, options);
  336. };
  337. var saveSelection, restoreSelection;
  338. if (window.getSelection && document.createRange) {
  339. saveSelection = function(el) {
  340. var sel = window.getSelection && window.getSelection();
  341. if (sel && sel.rangeCount > 0) {
  342. return sel.getRangeAt(0);
  343. }
  344. };
  345. restoreSelection = function(el, sel) {
  346. var range = document.createRange();
  347. range.setStart(sel.startContainer, sel.startOffset);
  348. range.setEnd(sel.endContainer, sel.endOffset)
  349. sel = window.getSelection();
  350. sel.removeAllRanges();
  351. sel.addRange(range);
  352. }
  353. } else if (document.selection && document.body.createTextRange) {
  354. saveSelection = function(el) {
  355. return document.selection.createRange();
  356. };
  357. restoreSelection = function(el, sel) {
  358. var textRange = document.body.createTextRange();
  359. textRange.moveToElementText(el);
  360. textRange.setStart(sel.startContanier, sel.startOffset);
  361. textRange.setEnd(sel.endContainer, sel.endOffset);
  362. textRange.select();
  363. };
  364. }
  365. var uniRegexp;
  366. function unicodeTo(str, template) {
  367. return str.replace(uniRegexp, function(unicodeChar) {
  368. var map = emojione[(emojioneSupportMode === 0 ? 'jsecapeMap' : 'jsEscapeMap')];
  369. if (typeof unicodeChar !== 'undefined' && unicodeChar in map) {
  370. return getTemplate(template, map[unicodeChar]);
  371. }
  372. return unicodeChar;
  373. });
  374. }
  375. function htmlFromText(str, self) {
  376. str = str
  377. .replace(/&/g, '&amp;')
  378. .replace(/</g, '&lt;')
  379. .replace(/>/g, '&gt;')
  380. .replace(/"/g, '&quot;')
  381. .replace(/'/g, '&#x27;')
  382. .replace(/`/g, '&#x60;')
  383. .replace(/(?:\r\n|\r|\n)/g, '\n')
  384. .replace(/(\n+)/g, '<div>$1</div>')
  385. .replace(/\n/g, '<br/>')
  386. .replace(/<br\/><\/div>/g, '</div>');
  387. if (self.shortnames) {
  388. str = emojione.shortnameToUnicode(str);
  389. }
  390. return unicodeTo(str, self.emojiTemplate)
  391. .replace(/\t/g, '&nbsp;&nbsp;&nbsp;&nbsp;')
  392. .replace(/ /g, '&nbsp;&nbsp;');
  393. }
  394. function textFromHtml(str, self) {
  395. str = str
  396. .replace(/<img[^>]*alt="([^"]+)"[^>]*>/ig, '$1')
  397. .replace(/\n|\r/g, '')
  398. .replace(/<br[^>]*>/ig, '\n')
  399. .replace(/(?:<(?:div|p|ol|ul|li|pre|code|object)[^>]*>)+/ig, '<div>')
  400. .replace(/(?:<\/(?:div|p|ol|ul|li|pre|code|object)>)+/ig, '</div>')
  401. .replace(/\n<div><\/div>/ig, '\n')
  402. .replace(/<div><\/div>\n/ig, '\n')
  403. .replace(/(?:<div>)+<\/div>/ig, '\n')
  404. .replace(/([^\n])<\/div><div>/ig, '$1\n')
  405. .replace(/(?:<\/div>)+/ig, '</div>')
  406. .replace(/([^\n])<\/div>([^\n])/ig, '$1\n$2')
  407. .replace(/<\/div>/ig, '')
  408. .replace(/([^\n])<div>/ig, '$1\n')
  409. .replace(/\n<div>/ig, '\n')
  410. .replace(/<div>\n/ig, '\n\n')
  411. .replace(/<(?:[^>]+)?>/g, '')
  412. .replace(new RegExp(invisibleChar, 'g'), '')
  413. .replace(/&nbsp;/g, ' ')
  414. .replace(/&lt;/g, '<')
  415. .replace(/&gt;/g, '>')
  416. .replace(/&quot;/g, '"')
  417. .replace(/&#x27;/g, "'")
  418. .replace(/&#x60;/g, '`')
  419. .replace(/&amp;/g, '&');
  420. switch (self.saveEmojisAs) {
  421. case 'image':
  422. str = unicodeTo(str, self.emojiTemplate);
  423. break;
  424. case 'shortname':
  425. str = emojione.toShort(str);
  426. }
  427. return str;
  428. }
  429. function calcButtonPosition() {
  430. var self = this,
  431. offset = self.editor[0].offsetWidth - self.editor[0].clientWidth,
  432. current = parseInt(self.button.css('marginRight'));
  433. if (current !== offset) {
  434. self.button.css({marginRight: offset});
  435. if (self.floatingPicker) {
  436. self.picker.css({right: parseInt(self.picker.css('right')) - current + offset});
  437. }
  438. }
  439. }
  440. function lazyLoading() {
  441. var self = this;
  442. if (!self.sprite && self.lasyEmoji[0]) {
  443. var pickerTop = self.picker.offset().top,
  444. pickerBottom = pickerTop + self.picker.height() + 20;
  445. self.lasyEmoji.each(function() {
  446. var e = $(this), top = e.offset().top;
  447. if (top > pickerTop && top < pickerBottom) {
  448. e.attr("src", e.data("src")).removeClass("lazy-emoji");
  449. }
  450. })
  451. self.lasyEmoji = self.lasyEmoji.filter(".lazy-emoji");
  452. }
  453. }
  454. function selector (prefix, skip_dot) {
  455. return (skip_dot ? '' : '.') + css_class + (prefix ? ("-" + prefix) : "");
  456. }
  457. function div(prefix) {
  458. var parent = $('<div/>', isObject(prefix) ? prefix : {"class" : selector(prefix, true)});
  459. $.each(slice.call(arguments).slice(1), function(i, child) {
  460. if ($.isFunction(child)) {
  461. child = child.call(parent);
  462. }
  463. if (child) {
  464. $(child).appendTo(parent);
  465. }
  466. });
  467. return parent;
  468. }
  469. function getRecent () {
  470. return localStorage.getItem("recent_emojis") || "";
  471. }
  472. function updateRecent(self) {
  473. var emojis = getRecent();
  474. if (!self.recent || self.recent !== emojis) {
  475. if (emojis.length) {
  476. var skinnable = self.scrollArea.is(".skinnable"),
  477. scrollTop, height;
  478. if (!skinnable) {
  479. scrollTop = self.scrollArea.scrollTop();
  480. height = self.recentCategory.is(":visible") ? self.recentCategory.height() : 0;
  481. }
  482. var items = shortnameTo(emojis, self.emojiBtnTemplate, true).split('|').join('');
  483. self.recentCategory.children(".emojibtn").remove();
  484. $(items).insertAfter(self.recentCategory.children("h1"));
  485. self.recentCategory.children(".emojibtn").on("click", function() {
  486. self.trigger("emojibtn.click", $(this));
  487. });
  488. self.recentFilter.show();
  489. if (!skinnable) {
  490. self.recentCategory.show();
  491. var height2 = self.recentCategory.height();
  492. if (height !== height2) {
  493. self.scrollArea.scrollTop(scrollTop + height2 - height);
  494. }
  495. }
  496. } else {
  497. if (self.recentFilter.hasClass("active")) {
  498. self.recentFilter.removeClass("active").next().addClass("active");
  499. }
  500. self.recentCategory.hide();
  501. self.recentFilter.hide();
  502. }
  503. self.recent = emojis;
  504. }
  505. };
  506. function setRecent(self, emoji) {
  507. var recent = getRecent();
  508. var emojis = recent.split("|");
  509. var index = emojis.indexOf(emoji);
  510. if (index !== -1) {
  511. emojis.splice(index, 1);
  512. }
  513. emojis.unshift(emoji);
  514. if (emojis.length > 9) {
  515. emojis.pop();
  516. }
  517. localStorage.setItem("recent_emojis", emojis.join("|"));
  518. updateRecent(self);
  519. };
  520. // see https://github.com/Modernizr/Modernizr/blob/master/feature-detects/storage/localstorage.js
  521. function supportsLocalStorage () {
  522. var test = 'test';
  523. try {
  524. localStorage.setItem(test, test);
  525. localStorage.removeItem(test);
  526. return true;
  527. } catch(e) {
  528. return false;
  529. }
  530. }
  531. function init(self, source, options) {
  532. //calcElapsedTime('init', function() {
  533. options = getOptions(options);
  534. self.sprite = options.sprite && emojioneSupportMode < 3;
  535. self.inline = options.inline === null ? source.is("INPUT") : options.inline;
  536. self.shortnames = options.shortnames;
  537. self.saveEmojisAs = options.saveEmojisAs;
  538. self.standalone = options.standalone;
  539. self.emojiTemplate = '<img alt="{alt}" class="emojione' + (self.sprite ? '-{uni}" src="' + blankImg + '"/>' : 'emoji" src="{img}"/>');
  540. self.emojiTemplateAlt = self.sprite ? '<i class="emojione-{uni}"/>' : '<img class="emojioneemoji" src="{img}"/>';
  541. self.emojiBtnTemplate = '<i class="emojibtn" role="button" data-name="{name}" title="{friendlyName}">' + self.emojiTemplateAlt + '</i>';
  542. self.recentEmojis = options.recentEmojis && supportsLocalStorage();
  543. var pickerPosition = options.pickerPosition;
  544. self.floatingPicker = pickerPosition === 'top' || pickerPosition === 'bottom';
  545. var sourceValFunc = source.is("TEXTAREA") || source.is("INPUT") ? "val" : "text",
  546. editor, button, picker, tones, filters, filtersBtns, search, emojisList, categories, scrollArea,
  547. app = div({
  548. "class" : css_class + ((self.standalone) ? " " + css_class + "-standalone " : " ") + (source.attr("class") || ""),
  549. role: "application"
  550. },
  551. editor = self.editor = div("editor").attr({
  552. contenteditable: (self.standalone) ? false : true,
  553. placeholder: options["placeholder"] || source.data("placeholder") || source.attr("placeholder") || "",
  554. tabindex: 0
  555. }),
  556. button = self.button = div('button',
  557. div('button-open'),
  558. div('button-close')
  559. ).attr('title', options.buttonTitle),
  560. picker = self.picker = div('picker',
  561. div('wrapper',
  562. filters = div('filters'),
  563. search = div('search',
  564. function() {
  565. self.search = $("<input/>", {
  566. "placeholder": "SEARCH",
  567. "type": "text",
  568. "class": "search"
  569. });
  570. this.append(self.search);
  571. }
  572. ),
  573. tones = div('tones',
  574. function() {
  575. if (options.tones) {
  576. this.addClass(selector('tones-' + options.tonesStyle, true));
  577. for (var i = 0; i <= 5; i++) {
  578. this.append($("<i/>", {
  579. "class": "btn-tone btn-tone-" + i + (!i ? " active" : ""),
  580. "data-skin": i,
  581. role: "button"
  582. }));
  583. }
  584. }
  585. }
  586. ),
  587. scrollArea = div('scroll-area',
  588. emojisList = div('emojis-list')
  589. )
  590. )
  591. ).addClass(selector('picker-position-' + options.pickerPosition, true))
  592. .addClass(selector('filters-position-' + options.filtersPosition, true))
  593. .addClass('hidden')
  594. );
  595. self.searchSel = null;
  596. editor.data(source.data());
  597. $.each(options.attributes, function(attr, value) {
  598. editor.attr(attr, value);
  599. });
  600. $.each(options.filters, function(filter, params) {
  601. var skin = 0;
  602. if (filter === 'recent' && !self.recentEmojis) {
  603. return;
  604. }
  605. if (filter !== 'tones') {
  606. $("<i/>", {
  607. "class": selector("filter", true) + " " + selector("filter-" + filter, true),
  608. "data-filter": filter,
  609. title: params.title
  610. })
  611. .wrapInner(shortnameTo(params.icon, self.emojiTemplateAlt))
  612. .appendTo(filters);
  613. } else if (options.tones) {
  614. skin = 5;
  615. } else {
  616. return;
  617. }
  618. do {
  619. var category = div('category').attr({name: filter, "data-tone": skin}).appendTo(emojisList),
  620. items = params.emoji.replace(/[\s,;]+/g, '|');
  621. if (skin > 0) {
  622. category.hide();
  623. items = items.split('|').join('_tone' + skin + '|') + '_tone' + skin;
  624. }
  625. if (filter === 'recent') {
  626. items = getRecent();
  627. }
  628. items = shortnameTo(items,
  629. self.sprite ?
  630. '<i class="emojibtn" role="button" data-name="{name}" title="{friendlyName}"><i class="emojione-{uni}"></i></i>' :
  631. '<i class="emojibtn" role="button" data-name="{name}" title="{friendlyName}"><img class="emojioneemoji lazy-emoji" data-src="{img}"/></i>',
  632. true).split('|').join('');
  633. category.html(items);
  634. $('<h1/>').text(params.title).prependTo(category);
  635. } while (--skin > 0);
  636. });
  637. options.filters = null;
  638. if (!self.sprite) {
  639. self.lasyEmoji = emojisList.find(".lazy-emoji");
  640. }
  641. filtersBtns = filters.find(selector("filter"));
  642. filtersBtns.eq(0).addClass("active");
  643. categories = emojisList.find(selector("category"));
  644. self.recentFilter = filtersBtns.filter('[data-filter="recent"]');
  645. self.recentCategory = categories.filter("[name=recent]");
  646. self.scrollArea = scrollArea;
  647. if (options.container) {
  648. $(options.container).wrapInner(app);
  649. } else {
  650. app.insertAfter(source);
  651. }
  652. if (options.hideSource) {
  653. source.hide();
  654. }
  655. self.setText(source[sourceValFunc]());
  656. source[sourceValFunc](self.getText());
  657. calcButtonPosition.apply(self);
  658. // if in standalone mode and no value is set, initialise with a placeholder
  659. if (self.standalone && !self.getText().length) {
  660. var placeholder = $(source).data("emoji-placeholder") || options.emojiPlaceholder;
  661. self.setText(placeholder);
  662. editor.addClass("has-placeholder");
  663. }
  664. // attach() must be called before any .on() methods !!!
  665. // 1) attach() stores events into possibleEvents{},
  666. // 2) .on() calls bindEvent() and stores handlers into eventStorage{},
  667. // 3) bindEvent() finds events in possibleEvents{} and bind founded via jQuery.on()
  668. // 4) attached events via jQuery.on() calls trigger()
  669. // 5) trigger() calls handlers stored into eventStorage{}
  670. attach(self, emojisList.find(".emojibtn"), {click: "emojibtn.click"});
  671. attach(self, window, {resize: "!resize"});
  672. attach(self, tones.children(), {click: "tone.click"});
  673. attach(self, [picker, button], {mousedown: "!mousedown"}, editor);
  674. attach(self, button, {click: "button.click"});
  675. attach(self, editor, {paste :"!paste"}, editor);
  676. attach(self, editor, ["focus", "blur"], function() { return self.stayFocused ? false : editor } );
  677. attach(self, picker, {mousedown: "picker.mousedown", mouseup: "picker.mouseup", click: "picker.click",
  678. keyup: "picker.keyup", keydown: "picker.keydown", keypress: "picker.keypress"});
  679. attach(self, editor, ["mousedown", "mouseup", "click", "keyup", "keydown", "keypress"]);
  680. attach(self, picker.find(".emojionearea-filter"), {click: "filter.click"});
  681. attach(self, self.search, {keyup: "search.keypress", focus: "search.focus", blur: "search.blur"});
  682. var noListenScroll = false;
  683. scrollArea.on('scroll', function () {
  684. if (!noListenScroll) {
  685. lazyLoading.call(self);
  686. if (scrollArea.is(":not(.skinnable)")) {
  687. var item = categories.eq(0), scrollTop = scrollArea.offset().top;
  688. categories.each(function (i, e) {
  689. if ($(e).offset().top - scrollTop >= 10) {
  690. return false;
  691. }
  692. item = $(e);
  693. });
  694. var filter = filtersBtns.filter('[data-filter="' + item.attr("name") + '"]');
  695. if (filter[0] && !filter.is(".active")) {
  696. filtersBtns.removeClass("active");
  697. filter.addClass("active");
  698. }
  699. }
  700. }
  701. });
  702. self.on("@filter.click", function(filter) {
  703. var isActive = filter.is(".active");
  704. if (scrollArea.is(".skinnable")) {
  705. if (isActive) return;
  706. tones.children().eq(0).click();
  707. }
  708. noListenScroll = true;
  709. if (!isActive) {
  710. filtersBtns.filter(".active").removeClass("active");
  711. filter.addClass("active");
  712. }
  713. var headerOffset = categories.filter('[name="' + filter.data('filter') + '"]').offset().top,
  714. scroll = scrollArea.scrollTop(),
  715. offsetTop = scrollArea.offset().top;
  716. scrollArea.stop().animate({
  717. scrollTop: headerOffset + scroll - offsetTop - 2
  718. }, 200, 'swing', function () {
  719. lazyLoading.call(self);
  720. noListenScroll = false;
  721. });
  722. })
  723. .on("@picker.show", function() {
  724. if (self.recentEmojis) {
  725. updateRecent(self);
  726. }
  727. lazyLoading.call(self);
  728. })
  729. .on("@tone.click", function(tone) {
  730. tones.children().removeClass("active");
  731. var skin = tone.addClass("active").data("skin");
  732. if (skin) {
  733. scrollArea.addClass("skinnable");
  734. categories.hide().filter("[data-tone=" + skin + "]").show();
  735. if (filtersBtns.eq(0).is('.active[data-filter="recent"]')) {
  736. filtersBtns.eq(0).removeClass("active").next().addClass("active");
  737. }
  738. } else {
  739. scrollArea.removeClass("skinnable");
  740. categories.hide().filter("[data-tone=0]").show();
  741. filtersBtns.eq(0).click();
  742. }
  743. lazyLoading.call(self);
  744. })
  745. .on("@button.click", function(button) {
  746. if (button.is(".active")) {
  747. self.hidePicker();
  748. } else {
  749. self.showPicker();
  750. self.searchSel = null;
  751. }
  752. })
  753. .on("@!paste", function(editor, event) {
  754. var pasteText = function(text) {
  755. var caretID = "caret-" + (new Date()).getTime();
  756. var html = htmlFromText(text, self);
  757. pasteHtmlAtCaret(html);
  758. pasteHtmlAtCaret('<i id="' + caretID +'"></i>');
  759. editor.scrollTop(editorScrollTop);
  760. var caret = $("#" + caretID),
  761. top = caret.offset().top - editor.offset().top,
  762. height = editor.height();
  763. if (editorScrollTop + top >= height || editorScrollTop > top) {
  764. editor.scrollTop(editorScrollTop + top - 2 * height/3);
  765. }
  766. caret.remove();
  767. self.stayFocused = false;
  768. calcButtonPosition.apply(self);
  769. trigger(self, 'paste', [editor, text, html]);
  770. }
  771. if (event.originalEvent.clipboardData) {
  772. var text = event.originalEvent.clipboardData.getData('text/plain');
  773. pasteText(text);
  774. if (event.preventDefault){
  775. event.preventDefault();
  776. } else {
  777. event.stop();
  778. };
  779. event.returnValue = false;
  780. event.stopPropagation();
  781. return false;
  782. }
  783. self.stayFocused = true;
  784. // insert invisible character for fix caret position
  785. pasteHtmlAtCaret('<span>' + invisibleChar + '</span>');
  786. var sel = saveSelection(editor[0]),
  787. editorScrollTop = editor.scrollTop(),
  788. clipboard = $("<div/>", {contenteditable: true})
  789. .css({position: "fixed", left: "-999px", width: "1px", height: "1px", top: "20px", overflow: "hidden"})
  790. .appendTo($("BODY"))
  791. .focus();
  792. window.setTimeout(function() {
  793. editor.focus();
  794. restoreSelection(editor[0], sel);
  795. var text = textFromHtml(clipboard.html().replace(/\r\n|\n|\r/g, '<br>'), self);
  796. clipboard.remove();
  797. pasteText(text);
  798. }, 200);
  799. })
  800. .on("@emojibtn.click", function(emojibtn) {
  801. editor.removeClass("has-placeholder");
  802. if (self.searchSel !== null) {
  803. editor.focus();
  804. restoreSelection(editor[0], self.searchSel);
  805. self.searchSel = null;
  806. }
  807. if (self.standalone) {
  808. editor.html(shortnameTo(emojibtn.data("name"), self.emojiTemplate));
  809. self.trigger("blur");
  810. } else {
  811. saveSelection(editor[0]);
  812. pasteHtmlAtCaret(shortnameTo(emojibtn.data("name"), self.emojiTemplate));
  813. }
  814. if (self.recentEmojis) {
  815. setRecent(self, emojibtn.data("name"));
  816. }
  817. self.search.val('');
  818. self.trigger('search.keypress');
  819. })
  820. .on("@!resize @keyup @emojibtn.click", calcButtonPosition)
  821. .on("@!mousedown", function(editor, event) {
  822. if ($(event.target).hasClass('search')) {
  823. // Allow search clicks
  824. self.stayFocused = true;
  825. if (self.searchSel == null) {
  826. self.searchSel = saveSelection(editor[0]);
  827. }
  828. } else {
  829. if (!app.is(".focused")) {
  830. editor.focus();
  831. }
  832. event.preventDefault();
  833. }
  834. return false;
  835. })
  836. .on("@change", function() {
  837. var html = self.editor.html().replace(/<\/?(?:div|span|p)[^>]*>/ig, '');
  838. // clear input: chrome adds <br> when contenteditable is empty
  839. if (!html.length || /^<br[^>]*>$/i.test(html)) {
  840. self.editor.html(self.content = '');
  841. }
  842. source[sourceValFunc](self.getText());
  843. })
  844. .on("@focus", function() {
  845. app.addClass("focused");
  846. })
  847. .on("@blur", function() {
  848. app.removeClass("focused");
  849. if (options.hidePickerOnBlur) {
  850. self.hidePicker();
  851. }
  852. var content = self.editor.html();
  853. if (self.content !== content) {
  854. self.content = content;
  855. trigger(self, 'change', [self.editor]);
  856. source.blur().trigger("change");
  857. } else {
  858. source.blur();
  859. }
  860. self.search.val('');
  861. self.trigger('search.keypress');
  862. })
  863. .on("@search.focus", function() {
  864. self.stayFocused = true;
  865. self.search.addClass("focused");
  866. })
  867. .on("@search.keypress", function() {
  868. var filterBtns = picker.find(".emojionearea-filter");
  869. var term = self.search.val().replace( / /g, "_" ).replace(/"/g, "\\\"");
  870. if (term !== "") {
  871. categories.filter('[data-tone="' + tones.find("i.active").data("skin") + '"]:not([name="recent"])').each(function() {
  872. var $category = $(this);
  873. var $matched = $category.find('.emojibtn[data-name*="' + term + '"]');
  874. if ($matched.length === 0) {
  875. $category.hide();
  876. filterBtns.filter('[data-filter="' + $category.attr('name') + '"]').hide();
  877. } else {
  878. var $notMatched = $category.find('.emojibtn:not([data-name*="' + term + '"])')
  879. $notMatched.hide();
  880. $matched.show();
  881. $category.show();
  882. filterBtns.filter('[data-filter="' + $category.attr('name') + '"]').show();
  883. }
  884. });
  885. if (!noListenScroll) {
  886. scrollArea.trigger('scroll');
  887. } else {
  888. lazyLoading.call(self);
  889. }
  890. } else {
  891. categories.filter('[data-tone="' + tones.find("i.active").data("skin") + '"]:not([name="recent"])').show();
  892. $('.emojibtn', categories).show();
  893. filterBtns.show();
  894. }
  895. })
  896. .on("@search.blur", function() {
  897. self.stayFocused = false;
  898. self.search.removeClass("focused");
  899. self.trigger("blur");
  900. });
  901. if (options.shortcuts) {
  902. self.on("@keydown", function(_, e) {
  903. if (!e.ctrlKey) {
  904. if (e.which == 9) {
  905. e.preventDefault();
  906. button.click();
  907. }
  908. else if (e.which == 27) {
  909. e.preventDefault();
  910. if (button.is(".active")) {
  911. self.hidePicker();
  912. }
  913. }
  914. }
  915. });
  916. }
  917. if (isObject(options.events) && !$.isEmptyObject(options.events)) {
  918. $.each(options.events, function(event, handler) {
  919. self.on(event.replace(/_/g, '.'), handler);
  920. });
  921. }
  922. if (options.autocomplete) {
  923. var autocomplete = function() {
  924. var textcompleteOptions = {
  925. maxCount: options.textcomplete.maxCount,
  926. placement: options.textcomplete.placement
  927. };
  928. if (options.shortcuts) {
  929. textcompleteOptions.onKeydown = function (e, commands) {
  930. if (!e.ctrlKey && e.which == 13) {
  931. return commands.KEY_ENTER;
  932. }
  933. };
  934. }
  935. var map = $.map(emojione.emojioneList, function (_, emoji) {
  936. return !options.autocompleteTones ? /_tone[12345]/.test(emoji) ? null : emoji : emoji;
  937. });
  938. map.sort();
  939. editor.textcomplete([
  940. {
  941. id: css_class,
  942. match: /\B(:[\-+\w]*)$/,
  943. search: function (term, callback) {
  944. callback($.map(map, function (emoji) {
  945. return emoji.indexOf(term) === 0 ? emoji : null;
  946. }));
  947. },
  948. template: function (value) {
  949. return shortnameTo(value, self.emojiTemplate) + " " + value.replace(/:/g, '');
  950. },
  951. replace: function (value) {
  952. return shortnameTo(value, self.emojiTemplate);
  953. },
  954. cache: true,
  955. index: 1
  956. }
  957. ], textcompleteOptions);
  958. if (options.textcomplete.placement) {
  959. // Enable correct positioning for textcomplete
  960. if ($(editor.data('textComplete').option.appendTo).css("position") == "static") {
  961. $(editor.data('textComplete').option.appendTo).css("position", "relative");
  962. }
  963. }
  964. };
  965. if ($.fn.textcomplete) {
  966. autocomplete();
  967. } else {
  968. $.getScript("https://cdn.rawgit.com/yuku-t/jquery-textcomplete/v1.3.4/dist/jquery.textcomplete.js",
  969. autocomplete);
  970. }
  971. }
  972. if (self.inline) {
  973. app.addClass(selector('inline', true));
  974. self.on("@keydown", function(_, e) {
  975. if (e.which == 13) {
  976. e.preventDefault();
  977. }
  978. });
  979. }
  980. if (/firefox/i.test(navigator.userAgent)) {
  981. // disabling resize images on Firefox
  982. document.execCommand("enableObjectResizing", false, false);
  983. }
  984. //}, self.id === 1); // calcElapsedTime()
  985. };
  986. var emojioneVersion = window.emojioneVersion || '2.1.4';
  987. var cdn = {
  988. defaultBase: "https://cdnjs.cloudflare.com/ajax/libs/emojione/",
  989. base: null,
  990. isLoading: false
  991. };
  992. function loadEmojione(options) {
  993. function detectVersion(emojione) {
  994. var version = emojione.cacheBustParam;
  995. if (!isObject(emojione['jsEscapeMap'])) return '1.5.2';
  996. if (version === "?v=1.2.4") return '2.0.0';
  997. if (version === "?v=2.0.1") return '2.1.0'; // v2.0.1 || v2.1.0
  998. if (version === "?v=2.1.1") return '2.1.1';
  999. if (version === "?v=2.1.2") return '2.1.2';
  1000. if (version === "?v=2.1.3") return '2.1.3';
  1001. if (version === "?v=2.1.4") return '2.1.4';
  1002. if (version === "?v=2.2.7") return '2.2.7';
  1003. return '2.2.7';
  1004. }
  1005. function getSupportMode(version) {
  1006. switch (version) {
  1007. case '1.5.2': return 0;
  1008. case '2.0.0': return 1;
  1009. case '2.1.0':
  1010. case '2.1.1': return 2;
  1011. case '2.1.2': return 3;
  1012. case '2.1.3':
  1013. case '2.1.4':
  1014. case '2.2.7':
  1015. default: return 4;
  1016. }
  1017. }
  1018. options = getOptions(options);
  1019. if (!cdn.isLoading) {
  1020. if (!emojione || getSupportMode(detectVersion(emojione)) < 2) {
  1021. cdn.isLoading = true;
  1022. $.getScript(cdn.defaultBase + emojioneVersion + "/lib/js/emojione.min.js", function () {
  1023. emojione = window.emojione;
  1024. emojioneVersion = detectVersion(emojione);
  1025. emojioneSupportMode = getSupportMode(emojioneVersion);
  1026. cdn.base = cdn.defaultBase + emojioneVersion + "/assets";
  1027. if (options.sprite) {
  1028. var sprite = cdn.base + "/sprites/emojione.sprites.css";
  1029. if (document.createStyleSheet) {
  1030. document.createStyleSheet(sprite);
  1031. } else {
  1032. $('<link/>', {rel: 'stylesheet', href: sprite}).appendTo('head');
  1033. }
  1034. }
  1035. while (readyCallbacks.length) {
  1036. readyCallbacks.shift().call();
  1037. }
  1038. cdn.isLoading = false;
  1039. });
  1040. } else {
  1041. emojioneVersion = detectVersion(emojione);
  1042. emojioneSupportMode = getSupportMode(emojioneVersion);
  1043. cdn.base = cdn.defaultBase + emojioneVersion + "/assets";
  1044. }
  1045. }
  1046. emojioneReady(function() {
  1047. if (options.useInternalCDN) {
  1048. emojione.imagePathPNG = cdn.base + "/png/";
  1049. emojione.imagePathSVG = cdn.base + "/svg/";
  1050. emojione.imagePathSVGSprites = cdn.base + "/sprites/emojione.sprites.svg";
  1051. emojione.imageType = options.imageType;
  1052. }
  1053. uniRegexp = new RegExp("<object[^>]*>.*?<\/object>|<span[^>]*>.*?<\/span>|<(?:object|embed|svg|img|div|span|p|a)[^>]*>|(" + emojione.unicodeRegexp + ")", "gi");
  1054. });
  1055. };
  1056. var EmojioneArea = function(element, options) {
  1057. var self = this;
  1058. loadEmojione(options);
  1059. eventStorage[self.id = ++unique] = {};
  1060. possibleEvents[self.id] = {};
  1061. emojioneReady(function() {
  1062. init(self, element, options);
  1063. });
  1064. };
  1065. function bindEvent(self, event) {
  1066. event = event.replace(/^@/, '');
  1067. var id = self.id;
  1068. if (possibleEvents[id][event]) {
  1069. $.each(possibleEvents[id][event], function(i, ev) {
  1070. // ev[0] = element
  1071. // ev[1] = event
  1072. // ev[2] = target
  1073. $.each($.isArray(ev[0]) ? ev[0] : [ev[0]], function(i, el) {
  1074. $(el).on(ev[1], function() {
  1075. var args = slice.call(arguments),
  1076. target = $.isFunction(ev[2]) ? ev[2].apply(self, [event].concat(args)) : ev[2];
  1077. if (target) {
  1078. trigger(self, event, [target].concat(args));
  1079. }
  1080. });
  1081. });
  1082. });
  1083. possibleEvents[id][event] = null;
  1084. }
  1085. }
  1086. EmojioneArea.prototype.on = function(events, handler) {
  1087. if (events && $.isFunction(handler)) {
  1088. var self = this;
  1089. $.each(events.toLowerCase().split(' '), function(i, event) {
  1090. bindEvent(self, event);
  1091. (eventStorage[self.id][event] || (eventStorage[self.id][event] = [])).push(handler);
  1092. });
  1093. }
  1094. return this;
  1095. };
  1096. EmojioneArea.prototype.off = function(events, handler) {
  1097. if (events) {
  1098. var id = this.id;
  1099. $.each(events.toLowerCase().replace(/_/g, '.').split(' '), function(i, event) {
  1100. if (eventStorage[id][event] && !/^@/.test(event)) {
  1101. if (handler) {
  1102. $.each(eventStorage[id][event], function(j, fn) {
  1103. if (fn === handler) {
  1104. eventStorage[id][event] = eventStorage[id][event].splice(j, 1);
  1105. }
  1106. });
  1107. } else {
  1108. eventStorage[id][event] = [];
  1109. }
  1110. }
  1111. });
  1112. }
  1113. return this;
  1114. };
  1115. EmojioneArea.prototype.trigger = function() {
  1116. var args = slice.call(arguments),
  1117. call_args = [this].concat(args.slice(0,1));
  1118. call_args.push(args.slice(1));
  1119. return trigger.apply(this, call_args);
  1120. };
  1121. EmojioneArea.prototype.setFocus = function () {
  1122. var self = this;
  1123. emojioneReady(function () {
  1124. self.editor.focus();
  1125. });
  1126. return self;
  1127. };
  1128. EmojioneArea.prototype.setText = function (str) {
  1129. var self = this;
  1130. emojioneReady(function () {
  1131. self.editor.html(htmlFromText(str, self));
  1132. self.content = self.editor.html();
  1133. trigger(self, 'change', [self.editor]);
  1134. calcButtonPosition.apply(self);
  1135. });
  1136. return self;
  1137. }
  1138. EmojioneArea.prototype.getText = function() {
  1139. return textFromHtml(this.editor.html(), this);
  1140. }
  1141. EmojioneArea.prototype.showPicker = function () {
  1142. var self = this;
  1143. if (self._sh_timer) {
  1144. window.clearTimeout(self._sh_timer);
  1145. }
  1146. self.picker.removeClass("hidden");
  1147. self._sh_timer = window.setTimeout(function() {
  1148. self.button.addClass("active");
  1149. }, 50);
  1150. trigger(self, "picker.show", [self.picker]);
  1151. return self;
  1152. }
  1153. EmojioneArea.prototype.hidePicker = function () {
  1154. var self = this;
  1155. if (self._sh_timer) {
  1156. window.clearTimeout(self._sh_timer);
  1157. }
  1158. self.button.removeClass("active");
  1159. self._sh_timer = window.setTimeout(function() {
  1160. self.picker.addClass("hidden");
  1161. }, 500);
  1162. trigger(self, "picker.hide", [self.picker]);
  1163. return self;
  1164. }
  1165. EmojioneArea.prototype.enable = function () {
  1166. var self = this;
  1167. emojioneReady(function () {
  1168. self.editor.prop('contenteditable', true);
  1169. self.button.show();
  1170. });
  1171. return self;
  1172. }
  1173. EmojioneArea.prototype.disable = function () {
  1174. var self = this;
  1175. emojioneReady(function () {
  1176. self.editor.prop('contenteditable', false);
  1177. self.hidePicker();
  1178. self.button.hide();
  1179. });
  1180. return self;
  1181. }
  1182. $.fn.emojioneArea = function(options) {
  1183. return this.each(function() {
  1184. if (!!this.emojioneArea) return this.emojioneArea;
  1185. $.data(this, 'emojioneArea', this.emojioneArea = new EmojioneArea($(this), options));
  1186. return this.emojioneArea;
  1187. });
  1188. };
  1189. $.fn.emojioneArea.defaults = getDefaultOptions();
  1190. $.fn.emojioneAreaText = function(options) {
  1191. var self = this, pseudoSelf = {
  1192. shortnames: (options && typeof options.shortnames !== 'undefined' ? options.shortnames : true),
  1193. emojiTemplate: '<img alt="{alt}" class="emojione' + (options && options.sprite && emojioneSupportMode < 3 ? '-{uni}" src="' + blankImg : 'emoji" src="{img}') + '"/>'
  1194. };
  1195. loadEmojione(options);
  1196. emojioneReady(function() {
  1197. self.each(function() {
  1198. var $this = $(this);
  1199. if (!$this.hasClass('emojionearea-text')) {
  1200. $this.addClass('emojionearea-text').html(htmlFromText(($this.is('TEXTAREA') || $this.is('INPUT') ? $this.val() : $this.text()), pseudoSelf));
  1201. }
  1202. return $this;
  1203. });
  1204. });
  1205. return this;
  1206. };
  1207. }, window ) );