emojionearea-rails 0.1.0

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