适应内容可编辑的文本区域

时间:2019-05-25 12:21:15

标签: javascript

我有一个在文本区域显示微笑的脚本。

我想知道如何使它适应可编辑内容而不是文本区域。

要查看完整的脚本:https://pastebin.com/HavdikMj

非常感谢

            // EMOJI CLICK EVENT
            $( document ).off( "click", "."  + emojiContainer +  " section .emojione" );
            $( document ).on( "click", "."  + emojiContainer +  " section .emojione",
                function()
                {       
                    var caretPos = activeEl.selectionStart;
                    var textAreaTxt = $( activeEl ).val();
                    var txtToAdd;
                    if( settings.type=="shortcode" )
                    {
                        txtToAdd = $( this ).attr( "title" ) + " ";
                    }else{
                        txtToAdd = $( this ).attr( "alt" ) + " ";
                    }

                    $( activeEl ).val( textAreaTxt.substring( 0, caretPos ) + txtToAdd + textAreaTxt.substring( caretPos ) );
                    $( activeEl ).focus();
                    activeEl.selectionStart = caretPos + txtToAdd.length;
                    activeEl.selectionEnd = caretPos + txtToAdd.length;
                }
            );
        };

1 个答案:

答案 0 :(得分:0)

问题在于表情符号文本区域选择器依赖于textarea元素的 selectionStart selectionEnd 属性。两者均不适用于div。此外,选择器使用element.val()获取并设置textarea内的文本,该文本也不适用于div。

尽管并非易事,但仍有希望。

我们需要使用selectionStart和selectionEnd属性来增强HTMLDivElement

HTMLDivElement.prototype.selectionStart = 0;
HTMLDivElement.prototype.selectionEnd = 0;

使用Selection API获取这些属性的值

function update(e) {
  var caret = window.getSelection().anchorOffset;
  e.target.selectionStart = caret;
  e.target.selectionEnd = caret + window.getSelection().focusOffset;
}

用户在div中单击或移动键后立即应用值

['mousedown', 'mouseup', 'keydown', 'keyup'].forEach(function(evt) {
  document.getElementById("theDiv").addEventListener(evt, update);
});

最后重写您发布的on-click函数,以使其了解div,如果它是div集并使用 element.firstChild.data 而不是 element.val获取文本()

  $(document).on("click", "." + emojiContainer + " section .emojione",
    function() {
      var textAreaTxt;
      var caretPos = activeEl.selectionStart;
      if (activeEl.constructor.name == "HTMLDivElement") {
        textAreaTxt = activeEl.firstChild.data;

      } else {
        textAreaTxt = $(activeEl).val();
      }
      var txtToAdd;
      if (settings.type == "shortcode") {
        txtToAdd = $(this).attr("title") + " ";
      } else {
        txtToAdd = $(this).attr("alt") + " ";
      }
      if (activeEl.constructor.name == "HTMLDivElement") {
        activeEl.firstChild.data = textAreaTxt.substring(0, caretPos) + txtToAdd + textAreaTxt.substring(caretPos);
      } else {
        $(activeEl).val(textAreaTxt.substring(0, caretPos) + txtToAdd + textAreaTxt.substring(caretPos));
      }
      $(activeEl).focus();
      activeEl.selectionStart = caretPos + txtToAdd.length;
      activeEl.selectionEnd = caretPos + txtToAdd.length;
    }
  );

这是一个可行的例子。请注意,由于每个帖子的上限为30000个字符,我不得不删除了很多表情符号。不过,这不会影响功能。

(function($) {
  $.fn.emojionePicker = function(options) {
    var emojiContainer = "emojionepicker",
      activeEl;

    // DEFAULT SETTINGS
    var settings = $.extend({
      pickerTop: 5, // Picker top margin
      pickerRight: 5, // Picker right margin
      type: "shortcode", // What to send to textarea, valid values are "shortcode" and "unicode"

    }, options);

    var $el = this;

    // EMOJI LIST
    var emojiList = {
      people: {
        header: ":smiley:",
        content: ":grinning: :grin: :joy: :rofl: :smiley: :smile: :sweat_smile: :laughing: :wink: :blush: :yum: :sunglasses: :heart_eyes: :kissing_heart: :kissing: :kissing_smiling_eyes: :kissing_closed_eyes: :relaxed: :slight_smile: :hugging: :thinking: :neutral_face: :expressionless: :no_mouth: :rolling_eyes: :smirk: :persevere: :disappointed_relieved: :open_mouth: :zipper_mouth: :hushed: :sleepy: :tired_face: :sleeping: :relieved: :nerd: :stuck_out_tongue: :stuck_out_tongue_winking_eye: :stuck_out_tongue_closed_eyes: :drooling_face: :unamused: :sweat: :pensive: :confused: :upside_down: :money_mouth: :astonished: :frowning2: :slight_frown: :confounded: :disappointed: :worried: :triumph: :cry: :sob: :frowning: :anguished: :fearful: :weary: :grimacing: :cold_sweat: :scream: :flushed: :dizzy_face: :rage: :angry: :innocent: :cowboy: :clown: :lying_face: :mask: :thermometer_face: :head_bandage: :nauseated_face: :sneezing_face: :smiling_imp: :imp: :japanese_ogre: :japanese_goblin: :skull: :ghost: :alien: :robot: :poop: :smiley_cat: :smile_cat: :joy_cat: :heart_eyes_cat: :smirk_cat: :kissing_cat: :scream_cat: :crying_cat_face: :pouting_cat: :boy: :boy_tone1: :boy_tone2: :boy_tone3: :boy_tone4: :boy_tone5: :girl: :girl_tone1: :girl_tone2: :girl_tone3: :girl_tone4: :girl_tone5: :man: :man_tone1: :man_tone2: :man_tone3: :man_tone4: :man_tone5: :woman: :woman_tone1: :woman_tone2: :woman_tone3: :woman_tone4: :woman_tone5: :older_man: :older_man_tone1: :older_man_tone2: :older_man_tone3: :older_man_tone4: :older_man_tone5: :older_woman: :older_woman_tone1: :older_woman_tone2: :older_woman_tone3: :older_woman_tone4: :older_woman_tone5: :baby: :baby_tone1: :baby_tone2: :baby_tone3: :baby_tone4: :baby_tone5: :angel: :angel_tone1: :angel_tone2: :angel_tone3: :angel_tone4: :angel_tone5: :cop: :cop_tone1: :cop_tone2: :cop_tone3: :cop_tone4: :cop_tone5: :spy: :spy_tone1: :spy_tone2: :spy_tone3: :spy_tone4: :spy_tone5: :guardsman: :guardsman_tone1: :guardsman_tone2: :guardsman_tone3: :guardsman_tone4: :guardsman_tone5: :construction_worker: :construction_worker_tone1: :construction_worker_tone2: :construction_worker_tone3: :construction_worker_tone4: :construction_worker_tone5: :man_with_turban: :man_with_turban_tone1: :man_with_turban_tone2: :man_with_turban_tone3: :man_with_turban_tone4: :man_with_turban_tone5: :person_with_blond_hair: :person_with_blond_hair_tone1: :person_with_blond_hair_tone2: :person_with_blond_hair_tone3: :person_with_blond_hair_tone4: :person_with_blond_hair_tone5: :santa: :santa_tone1: :santa_tone2: :santa_tone3: :santa_tone4: :santa_tone5: :mrs_claus: :mrs_claus_tone1: :mrs_claus_tone2: :mrs_claus_tone3: :mrs_claus_tone4: :mrs_claus_tone5: :princess: :princess_tone1: :princess_tone2: :princess_tone3: :princess_tone4: :princess_tone5: :prince: :prince_tone1: :prince_tone2: :prince_tone3: :prince_tone4: :prince_tone5: :bride_with_veil: :bride_with_veil_tone1: :bride_with_veil_tone2: :bride_with_veil_tone3: :bride_with_veil_tone4: :bride_with_veil_tone5: :man_in_tuxedo: :man_in_tuxedo_tone1: :man_in_tuxedo_tone2: :man_in_tuxedo_tone3: :man_in_tuxedo_tone4: :raised_hands_tone1: :raised_hands_tone2: :raised_hands_tone3: :raised_hands_tone4: :raised_hands_tone5: :pray: :pray_tone1: :pray_tone2: :pray_tone3: :pray_tone4: :pray_tone5: :handshake: :handshake_tone1: :handshake_tone2: :handshake_tone3: :handshake_tone4: :handshake_tone5: :nail_care: :nail_care_tone1: :nail_care_tone2: :nail_care_tone3: :nail_care_tone4: :nail_care_tone5: :ear: :ear_tone1: :ear_tone2: :ear_tone3: :ear_tone4: :ear_tone5: :nose: :nose_tone1: :nose_tone2: :nose_tone3: :nose_tone4: :nose_tone5: :footprints: :eyes: :eye: :tongue: :lips: :kiss: :zzz: :eyeglasses: :dark_sunglasses: :necktie: :shirt: :jeans: :dress: :kimono: :bikini: :womans_clothes: :purse: :handbag: :pouch: :school_satchel: :mans_shoe: :athletic_shoe: :high_heel: :sandal: :boot: :crown: :womans_hat: :tophat: :mortar_board: :helmet_with_cross: :lipstick: :ring: :closed_umbrella: :briefcase:".split(" ")
      },
      nature: {
        header: ":four_leaf_clover:",
        content: ":see_no_evil: :hear_no_evil: :speak_no_evil: :sweat_drops: :dash: :monkey_face: :monkey: :gorilla: :dog: :dog2: :poodle: :wolf: :fox: :cat: :cat2: :lion_face: :tiger: :tiger2: :leopard: :horse: :racehorse: :deer: :unicorn: :cow: :ox: :water_buffalo: :cow2: :pig: :pig2: :boar: :pig_nose: :ram: :sheep: :goat: :dromedary_camel: :camel: :elephant: :rhino: :mouse: :mouse2: :rat: :hamster: :rabbit: :rabbit2: :chipmunk: :bat: :bear: :koala: :panda_face: :feet: :turkey: :chicken: :rooster: :hatching_chick: :baby_chick: :hatched_chick: :bird: :penguin: :dove: :eagle: :duck: :owl: :frog: :crocodile: :turtle: :lizard: :snake: :dragon_face: :dragon: :whale: :whale2: :dolphin: :fish: :tropical_fish: :blowfish: :shark: :octopus: :shell: :crab: :shrimp: :squid: :butterfly: :snail: :bug: :ant: :bee: :beetle: :spider: :spider_web: :scorpion: :bouquet: :cherry_blossom: :rosette: :rose: :wilted_rose: :hibiscus: :sunflower: :blossom: :tulip: :seedling: :evergreen_tree: :deciduous_tree: :palm_tree: :cactus: :ear_of_rice: :herb: :shamrock: :four_leaf_clover: :maple_leaf: :fallen_leaf: :leaves: :mushroom: :chestnut: :earth_africa: :earth_americas: :earth_asia: :new_moon: :waxing_crescent_moon: :first_quarter_moon: :waxing_gibbous_moon: :full_moon: :waning_gibbous_moon: :last_quarter_moon: :waning_crescent_moon: :crescent_moon: :new_moon_with_face: :first_quarter_moon_with_face: :last_quarter_moon_with_face: :sunny: :full_moon_with_face: :sun_with_face: :star: :star2: :cloud: :partly_sunny: :thunder_cloud_rain: :white_sun_small_cloud: :white_sun_cloud: :white_sun_rain_cloud: :cloud_rain: :cloud_snow: :cloud_lightning: :cloud_tornado: :fog: :wind_blowing_face: :umbrella2: :umbrella: :zap: :snowflake: :snowman2: :snowman: :comet: :fire: :droplet: :ocean: :jack_o_lantern: :christmas_tree: :sparkles: :tanabata_tree: :bamboo:".split(" ")
      },
      food: {
        header: ":hamburger:",
        content: ":grapes: :melon: :watermelon: :tangerine: :lemon: :banana: :pineapple: :apple: :green_apple: :pear: :peach: :cherries: :strawberry: :kiwi: :tomato: :avocado: :eggplant: :potato: :carrot: :corn: :hot_pepper: :cucumber: :peanuts: :bread: :croissant: :french_bread: :pancakes: :cheese: :meat_on_bone: :poultry_leg: :bacon: :hamburger: :fries: :pizza: :hotdog: :taco: :burrito: :stuffed_flatbread: :egg: :cooking: :shallow_pan_of_food: :stew: :salad: :popcorn: :bento: :rice_cracker: :rice_ball: :rice: :curry: :ramen: :spaghetti: :sweet_potato: :oden: :sushi: :fried_shrimp: :fish_cake: :dango: :icecream: :shaved_ice: :ice_cream: :doughnut: :cookie: :birthday: :cake: :chocolate_bar: :candy: :lollipop: :custard: :honey_pot: :baby_bottle: :milk: :coffee: :tea: :sake: :champagne: :wine_glass: :cocktail: :tropical_drink: :beer: :beers: :champagne_glass: :tumbler_glass: :fork_knife_plate: :fork_and_knife: :spoon:".split(" ")
      },
      objects: {
        header: ":bulb:",
        content: ":skull_crossbones: :love_letter: :bomb: :hole: :shopping_bags: :prayer_beads: :gem: :knife: :amphora: :map: :barber: :frame_photo: :bellhop: :door: :sleeping_accommodation: :bed: :couch: :toilet: :shower: :bathtub: :hourglass: :hourglass_flowing_sand: :watch: :alarm_clock: :stopwatch: :timer: :clock: :thermometer: :beach_umbrella: :balloon: :tada: :confetti_ball: :dolls: :flags: :wind_chime: :ribbon: :gift: :joystick: :postal_horn: :microphone2: :level_slider: :control_knobs: :radio: :iphone: :calling: :telephone: :telephone_receiver: :pager: :fax: :battery: :electric_plug: :computer: :desktop: :printer: :keyboard: :mouse_three_button: :trackball: :minidisc: :floppy_disk: :cd: :dvd: :movie_camera: :film_frames: :projector: :tv: :camera: :camera_with_flash: :video_camera: :vhs: :mag: :mag_right: :microscope: :telescope: :satellite: :candle: :bulb: :flashlight: :izakaya_lantern: :notebook_with_decorative_cover: :closed_book: :book: :green_book: :blue_book: :orange_book: :books: :notebook: :ledger: :page_with_curl: :scroll: :page_facing_up: :newspaper: :shopping_cart: :triangular_flag_on_post: :crossed_flags: :flag_black: :flag_white: :rainbow_flag:".split(" ")
      },
      activity: {
        header: ":football:",
        content: ":space_invader: :levitate: :fencer: :trumpet: :violin: :drum: :clapper: :bow_and_arrow:".split(" ")
      },
      travel: {
        header: ":red_car:",
        content: ":race_car: :motorcycle: :japan: :mountain_snow: :mountain: :volcano: :mount_fuji: :camping: :beach: :desert: :island: :park: :stadium: :classical_building: :construction_site: :homes: :cityscape: :house_abandoned: :house: :house_with_garden: :office: :post_office: :european_post_office: :hospital: :bank: :hotel: :love_hotel: :convenience_store: :school: :department_store: :factory: :japanese_castle: :european_castle: :wedding: :tokyo_tower: :statue_of_liberty: :church: :mosque: :synagogue: :shinto_shrine: :kaaba: :fountain: :tent: :foggy: :night_with_stars: :sunrise_over_mountains: :sunrise: :city_dusk: :city_sunset: :bridge_at_night: :milky_way: :carousel_horse: :ferris_wheel: :roller_coaster: :steam_locomotive: :railway_car: :bullettrain_side: :bullettrain_front: :train2: :metro: :light_rail: :station: :tram: :monorail: :mountain_railway: :train: :bus: :oncoming_bus: :trolleybus: :minibus: :ambulance: :fire_engine: :police_car: :oncoming_police_car: :taxi: :oncoming_taxi: :red_car: :oncoming_automobile: :blue_car: :truck: :articulated_lorry: :tractor: :bike: :scooter: :motor_scooter: :busstop: :motorway: :railway_track: :fuelpump: :rotating_light: :traffic_light: :vertical_traffic_light: :construction: :anchor: :sailboat: :canoe: :speedboat: :cruise_ship: :ferry: :motorboat: :ship: :airplane: :airplane_small: :airplane_departure: :airplane_arriving: :seat: :helicopter: :suspension_railway: :mountain_cableway: :aerial_tramway: :rocket: :satellite_orbital: :stars: :rainbow: :fireworks: :sparkler: :rice_scene: :checkered_flag:".split(" ")
      },
      symbols: {
        header: ":hash:",
        content: ":100: :1234: :eye_in_speech_bubble: :cupid: :heart: :heartbeat: :broken_heart: :two_hearts: :sparkling_heart: :heartpulse: :blue_heart: :green_heart: :yellow_heart: :purple_heart: :black_heart: :gift_heart: :revolving_hearts: :heart_decoration: :heart_exclamation: :anger: :boom: :dizzy: :speech_balloon: :speech_left: :anger_right: :thought_balloon: :white_flower: :globe_with_meridians: :hotsprings: :octagonal_sign: :clock12: :clock1230: :clock1: :clock130: :clock2: :clock230: :clock3: :clock330: :clock4: :clock430: :clock5: :clock530: :clock6: :clock630: :clock7: :clock730: :clock8: :clock830: :clock9: :clock930: :clock10: :clock1030: :clock11: :clock1130: :cyclone: :spades: :hearts: :diamonds: :clubs: :black_joker: :mahjong: :flower_playing_cards: :mute: :speaker: :sound: :loud_sound: :loudspeaker: :mega: :bell: :no_bell: :musical_note: :notes: :chart: :currency_exchange: :heavy_dollar_sign: :atm: :put_litter_in_its_place: :potable_water: :wheelchair: :mens: :womens: :restroom: :baby_symbol: :wc: :passport_control: :customs: :baggage_claim: :regional_indicator_c: :regional_indicator_b: :regional_indicator_a:".split(" ")
      },
      flags: {
        header: ":flag_black:",
        content: ":flag_ac: :flag_ad: :flag_ae: :flag_af: :flag_ag: :flag_ai: :flag_al: :flag_am: :flag_ao: :flag_aq: :flag_ar: :flag_as: :flag_at: :flag_au: :flag_aw: :flag_ax: :flag_az: :flag_ba: :flag_bb: :flag_bd: :flag_be: :flag_bf: :flag_bg: :flag_bh: :flag_bi: :flag_bj: :flag_bl: :flag_bm: :flag_bn: :flag_bo: :flag_bq: :flag_br: :flag_bs: :flag_bt: :flag_bv: :flag_bw: :flag_by: :flag_bz: :flag_ca: :flag_cc: :flag_cd: :flag_cf: :flag_cg: :flag_ch: :flag_ci: :flag_ck: :flag_cl: :flag_cm: :flag_cn: :flag_co: :flag_cp: :flag_cr: :flag_cu: :flag_cv: :flag_cw: :flag_cx: :flag_cy: :flag_cz: :flag_de: :flag_dg: :flag_dj: :flag_dk: :flag_dm: :flag_do: :flag_dz: :flag_ea: :flag_ec: :flag_ee: :flag_eg: :flag_eh: :flag_er: :flag_es: :flag_et: :flag_eu: :flag_fi: :flag_fj: :flag_fk: :flag_fm: :flag_fo: :flag_fr: :flag_ga: :flag_gb: :flag_gd: :flag_ge: :flag_gf: :flag_gg: :flag_gh: :flag_gi: :flag_gl: :flag_gm: :flag_gn: :flag_gp: :flag_gq: :flag_gr: :flag_gs: :flag_gt: :flag_gu: :flag_gw: :flag_gy: :flag_hk: :flag_hm: :flag_hn: :flag_hr: :flag_ht: :flag_hu: :flag_ic: :flag_id: :flag_ie: :flag_il: :flag_im: :flag_in: :flag_io: :flag_iq: :flag_ir: :flag_is: :flag_it: :flag_je: :flag_jm: :flag_jo: :flag_jp: :flag_ke: :flag_kg: :flag_kh: :flag_ki: :flag_km: :flag_kn: :flag_kp: :flag_kr: :flag_kw: :flag_ky: :flag_kz: :flag_la: :flag_lb: :flag_lc: :flag_li: :flag_lk: :flag_lr: :flag_ls: :flag_lt: :flag_lu: :flag_lv: :flag_ly: :flag_ma: :flag_mc: :flag_md: :flag_me: :flag_mf: :flag_mg: :flag_mh: :flag_mk: :flag_ml: :flag_mm: :flag_mn: :flag_mo: :flag_mp: :flag_mq: :flag_mr: :flag_ms: :flag_mt: :flag_mu: :flag_mv: :flag_mw: :flag_mx: :flag_my: :flag_mz: :flag_na: :flag_nc: :flag_ne: :flag_nf: :flag_ng: :flag_ni: :flag_nl: :flag_no: :flag_np: :flag_nr: :flag_nu: :flag_nz: :flag_om: :flag_pa: :flag_pe: :flag_pf: :flag_pg: :flag_ph: :flag_pk: :flag_pl: :flag_pm: :flag_pn: :flag_pr: :flag_ps: :flag_pt: :flag_pw: :flag_py: :flag_qa: :flag_re: :flag_ro: :flag_rs: :flag_ru: :flag_rw: :flag_sa: :flag_sb: :flag_sc: :flag_sd: :flag_se: :flag_sg: :flag_sh: :flag_si: :flag_sj: :flag_sk: :flag_sl: :flag_sm: :flag_sn: :flag_so: :flag_sr: :flag_ss: :flag_st: :flag_sv: :flag_sx: :flag_sy: :flag_sz: :flag_ta: :flag_tc: :flag_td: :flag_tf: :flag_tg: :flag_th: :flag_tj: :flag_tk: :flag_tl: :flag_tm: :flag_tn: :flag_to: :flag_tr: :flag_tt: :flag_tv: :flag_tw: :flag_tz: :flag_ua: :flag_ug: :flag_um: :flag_us: :flag_uy: :flag_uz: :flag_va: :flag_vc: :flag_ve: :flag_vg: :flag_vi: :flag_vn: :flag_vu: :flag_wf: :flag_ws: :flag_xk: :flag_ye: :flag_yt: :flag_za: :flag_zm: :flag_zw:".split(" ")
      }
    };

    // CREATE EMOJI CONTAINER AND LOAD SECTION HEADER
    var createContainer = function(el) {
      $('<div class="' + emojiContainer + '"><nav></nav></div>').insertAfter(el);

      var navItems = '';
      $.each(emojiList,
        function(k, v) {
          var emoji = emojione.shortnameToImage(v["header"]);
          navItems += '<div class="tab' + (navItems == "" ? ' active' : '') + '" data-tab="' + k + '" onclick="">' + emoji + '</div>';
        }
      );

      $("." + emojiContainer + " nav").append(navItems);

      $("." + emojiContainer + " nav .tab").click(
        function() {
          loadEmojies($(this).attr("data-tab"));
        }
      );

      // EMOJI CLICK EVENT
      $(document).off("click", "." + emojiContainer + " section .emojione");
      $(document).on("click", "." + emojiContainer + " section .emojione",
        function() {
          var textAreaTxt;
          var caretPos = activeEl.selectionStart;
          if (activeEl.constructor.name == "HTMLDivElement") {
            textAreaTxt = activeEl.firstChild.data;

          } else {
            textAreaTxt = $(activeEl).val();
          }
          var txtToAdd;
          if (settings.type == "shortcode") {
            txtToAdd = $(this).attr("title") + " ";
          } else {
            txtToAdd = $(this).attr("alt") + " ";
          }
          if (activeEl.constructor.name == "HTMLDivElement") {
            activeEl.firstChild.data = textAreaTxt.substring(0, caretPos) + txtToAdd + textAreaTxt.substring(caretPos);
          } else {
            $(activeEl).val(textAreaTxt.substring(0, caretPos) + txtToAdd + textAreaTxt.substring(caretPos));
          }
          $(activeEl).focus();
          activeEl.selectionStart = caretPos + txtToAdd.length;
          activeEl.selectionEnd = caretPos + txtToAdd.length;
        }
      );
    };

    // GENERATE / CHANGE EMOJI SECTION
    var loadEmojies = function(section) {
      if ($("." + emojiContainer + " section." + section).length > 0) {
        if ($("." + emojiContainer + " .tab[data-tab='" + section + "']").hasClass("active")) {
          return;
        }

        $("." + emojiContainer + " section").fadeOut().promise().done(
          function() {
            $(this).hide();
            $("." + emojiContainer + " section." + section).fadeIn();
            $("." + emojiContainer + " .tab").removeClass("active");
            $("." + emojiContainer + " .tab[data-tab='" + section + "']").addClass("active");
          }
        );

        return;
      }

      if (typeof(emojiList[section]) == "undefined") {
        return;
      }

      var sectionHtml = '';
      $.each(emojiList[section].content,
        function(k, v) {
          sectionHtml += emojione.shortnameToImage(v);
        }
      );

      $('<section class="' + section + '">' + sectionHtml + '</section>').insertAfter("." + emojiContainer + " nav");

      $("." + emojiContainer + " section").fadeOut().promise().done(
        function() {
          $("." + emojiContainer + " section." + section).fadeIn();
          $("." + emojiContainer + " .tab").removeClass("active");
          $("." + emojiContainer + " .tab[data-tab='" + section + "']").addClass("active");
        }
      );
    };

    // LOAD EMOJIONE
    var init = (function() {
      var script = document.createElement("script"),
        head = document.querySelector("head"),
        style = document.createElement('link');

      script.src = 'https://cdn.jsdelivr.net/emojione/2.2.7/lib/js/emojione.min.js';
      style.type = "text/css";
      style.href = "https://cdn.jsdelivr.net/emojione/2.2.7/assets/css/emojione.min.css";

      head.appendChild(style);
      head.appendChild(script);

      script.onload = function() {
        createContainer($el[0]);

        $.each($el, function(i, el) {
          var picker = $('<div class="emojionepicker-picker" data-index="' + i + '"></div>').insertAfter(el);

          // SET ACTIVE TEXTAREA
          picker.bind("click", function() {
            activeEl = el;
          });

          var elOffset = $(el).offset();

          picker.css({
            "top": elOffset["top"] + settings.pickerTop + "px",
            "left": $(el).width() + elOffset["left"] - $(".emojionepicker-picker").width() - settings.pickerRight + "px",
          }).show();
        });

        // EMOJI PICKER CLICK EVENT
        $(".emojionepicker-picker").click(
          function() {
            if ($("." + emojiContainer).is(":visible")) {
              $("." + emojiContainer).fadeOut();
              return;
            }

            // LOAD SECTION EMOJIES
            loadEmojies($("." + emojiContainer + " nav div.active").attr("data-tab"));

            var containerH = $("." + emojiContainer).height();
            var containerW = $("." + emojiContainer).width();
            var pickerOffset = $(this).offset();

            var top, left;
            if (pickerOffset["top"] > (containerH - 15)) {
              top = pickerOffset["top"] - containerH - 15;
            } else {
              top = pickerOffset["top"] + $(this).height() + 15;
            }

            if (pickerOffset["left"] > containerW) {
              left = pickerOffset["left"] - containerW + $(this).width();
            } else {
              left = pickerOffset["left"];
            }

            $("." + emojiContainer).css({
              "top": top + "px",
              "left": left + "px",
            }).fadeIn();
          }
        );

        // HIDE EMOJI CONTAINER ON CLICK ANYWHERE OUTSIDE THE ELEMENT
        $(document).on("click",
          function(e) {
            if ($("." + emojiContainer).is(":visible") == false || $(e.target).is(".emojionepicker-picker, .emojione")) {
              return;
            }

            $("." + emojiContainer).fadeOut();
          }
        );
      }
    })();

    return this;
  };
}(jQuery));

HTMLDivElement.prototype.selectionStart = 0;
HTMLDivElement.prototype.selectionEnd = 0;

function update(e) {
  var caret = window.getSelection().anchorOffset;
  e.target.selectionStart = caret;
  e.target.selectionEnd = caret + window.getSelection().focusOffset;
}

['mousedown', 'mouseup', 'keydown', 'keyup'].forEach(function(evt) {
  document.getElementById("theDiv").addEventListener(evt, update);
});


$("#theDiv").emojionePicker();
#theDiv {
  margin-top: 2em;
  height: 75px;
  width: 90%;
  border: 1px solid #000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://www.jqueryscript.net/demo/jQuery-EmojiOne-Based-Emoji-Picker-For-Textarea/dist/emojione.picker.css" rel="stylesheet" type="text/css">
<div id="theDiv" contentEditable="true">
  A contentEditable div
</div>