Adaptation textarea to contenteditable - javascript

I have a script that displays smiles in a textarea.
I would like to know how to adapt it to work with a contenteditable instead of a textarea.
To see the full script : https://pastebin.com/HavdikMj
thank you so much
// 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;
}
);
};

The problem is that the emojione textarea picker relies on the selectionStart and selectionEnd properties of the textarea element. Both aren't available for a div. Furthermore the picker gets & sets the text inside the textarea using element.val() which also doesn't work with divs.
There's hope though it isn't too easy.
We need to enhance the HTMLDivElement with selectionStart and selectionEnd properties
HTMLDivElement.prototype.selectionStart = 0;
HTMLDivElement.prototype.selectionEnd = 0;
Get the values for those properties using the Selection API
function update(e) {
var caret = window.getSelection().anchorOffset;
e.target.selectionStart = caret;
e.target.selectionEnd = caret + window.getSelection().focusOffset;
}
Apply the values as soon as the user either clicks or moves the keys inside a div
['mousedown', 'mouseup', 'keydown', 'keyup'].forEach(function(evt) {
document.getElementById("theDiv").addEventListener(evt, update);
});
Finally rewrite the on click function you've posted to make it aware of divs and if it's a div set & get the text using element.firstChild.data instead of 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;
}
);
Here's a working example. Please note I had to remove a lot of the emojis because of a 30000 chars per post limit. This doesn't affect the functionality though.
(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>

Related

form not clearing properly after submit and also for hidden input

I'm using a parsley validator and somehow it affects my form. After submission, it won't clear all the inputs; especially hidden inputs. And when I tried to set some input value from javascript it won't show up.
I think it's because of my <form method="post" id="transaction_form">. I've tried to re-evaluate my HTML but still, it won't work properly.
$(document).ready(function () {
$("#cust_num").val(55555);
var exam_num = 12345;
var prod_num = 88998;
var prod_name = "Hello";
var prod_price = 150000;
var transactionTable = $("#transaction_table");
var trxprodcount = 0;
var subTotal = 0;
var endTotal = 0;
function clearinput() {
$("#transaction_form")[0].reset();
$("#transaction_form").parsley().reset();
//$('#get_productdata').attr('disabled', 'disabled');
$("#subtotal").html(0);
$("#endtotal").html(0);
}
clearinput();
function recount() {
subTotal = transactionTable.DataTable().column(3).data().sum();
$("#subtotal").html(subTotal);
endTotal = subTotal - (subTotal * $("#trx_disc").val()) / 100;
$("#endtotal").html(endTotal);
}
transactionTable.DataTable({
ordering: false,
responsive: true,
searching: false,
paging: false,
info: false,
fnRender: function (Obj) {
return "Rp" + Obj.Data[3];
},
drawCallback: function () {
recount();
},
});
$("#trx_disc").on("change", function () {
recount();
});
trxprodcount = trxprodcount + 1;
var exam_num = $("#cust_num").val() + "S" + trxprodcount;
var col_exam_num =
exam_num +
'<input type="hidden" name="hidden_exam_num[]" id="exam_num' +
trxprodcount +
'" class="exam_num" value="' +
exam_num +
'" />';
var col_exam_prod =
prod_num +
'<input type="hidden" name="hidden_exam_prod[]" id="exam_prod' +
trxprodcount +
'" value="' +
prod_num +
'" />';
var del_btn =
'<button type="button" name="del_prodtrx" id="' +
trxprodcount +
'" class="btn btn-danger btn-sm del_prodtrx" >Delete</button>';
transactionTable
.DataTable()
.row.add([col_exam_num, col_exam_prod, prod_name, prod_price, del_btn])
.draw()
.node();
$("#transaction_table").on("click", ".del_prodtrx", function () {
var row = $(this).parents("tr");
if ($(row).hasClass("child")) {
transactionTable.DataTable().row($(row).prev("tr")).remove().draw();
} else {
transactionTable.DataTable().row($(this).parents("tr")).remove().draw();
}
});
$("#transaction_form").on("submit", function (event) {
event.preventDefault();
if ($("#transaction_form").parsley().isValid()) {
var count_data = 0;
$(".exam_num").each(function () {
count_data = count_data + 1;
});
if (count_data > 0) {
clearinput();
} else {
$("#message").html(
'<div class="alert alert-danger">Customer/Product Kosong'
);
}
setTimeout(function () {
$("#message").html("");
}, 3000);
}
});
});
Live Example: https://jsfiddle.net/azissofyanp/9p7j1d6u/30/
And I'm very confused about it.

I cannot add the class "unread" to the append content of a certain data-id

I want to add the "unread" class to an append content with a specific data-id. The following line of code works fine in the browser console. However, when the code is run it does not add the class "unread".
var idMessage = message[message.length-1].id;
$('#visitors').find('h5[data-id=' + idMessage + ']').addClass('unread');
The goal is to add "unread" in the following line of code:
$("#visitors").append('<h5 class="' + state + '" data-id=' + visitors[i].idSession + '>' + visitors[i].visitorOnline + '</h5>');
I will provide you with a code snippet
<div id="conexion-chat">
<button id="btn-conexion-chat" onclick="initWebSocket();">Iniciar chat</button>
</div>
<div id="display-chat" style="display: none;">
<div id="visitors"></div>
<br />
<textarea id="chatRoomField" rows="10" cols="30" readonly></textarea> <br/>
<input id="sendField" value="" type="text">
<button id="sendButton" onclick="send_message();">Enviar</button>
</div>
function initWebSocket(){
$('#conexion-chat').css('display', 'none');
$('#display-chat').css('display', '');
websocket = new WebSocket("ws://localhost:8080/o/echo");
websocket.onopen = function (event) {
websocket.send(json_user());
};
websocket.onclose = function(event) {
localStorage.clear();
console.log("DESCONECTADO");
};
websocket.onmessage = function(event) {
var message = event.data;
processMessage(message);
};
websocket.onerror = function(event) {
console.log("ERROR: " + event.data);
};
}
function visitorSelected(event){
var visitorSelected = $(event.target).data('id');
localStorage.setItem('visitorSelected', visitorSelected);
websocket.send(json_messages(visitorSelected, '${email}', '${read}'));
document.getElementById("chatRoomField").innerHTML = "";
}
function processMessage(message){
if(message == '${disconnected}'){
document.getElementById("chatRoomField").innerHTML += "El patrocinador no se encuentra conectado." + "\n";
}else {
var json_message = JSON.parse(message);
var visitorSelected = localStorage.getItem('visitorSelected');
if(json_message.hasOwnProperty('message') && message.length > 0){
var message = json_message.message;
var text = "";
if('${currentUserRol}' != '${rolPreferences}'){
for(var i=0; i<message.length; i++){
text += message[i].from + ": " + message[i].message + "\n";
document.getElementById("chatRoomField").innerHTML = text;
}
}else{
if(message[message.length-1].id == visitorSelected || message[message.length-1].idTo == visitorSelected){
for(var i=0; i<message.length; i++){
text += message[i].from + ": " + message[i].message + "\n";
document.getElementById("chatRoomField").innerHTML = text;
}
}else{
var idMessage = message[message.length-1].id;
$('#visitors').find('h5[data-id=' + idMessage + ']').addClass('unread');
}
}
}
if(json_message.hasOwnProperty('visitors') && json_message.visitors.length > 0){
var visitors = json_message.visitors;
var state;
$("#visitors h5").remove();
for (var i = 0; i < visitors.length; i++) {
state = (visitors[i].idSession == visitorSelected)? "selected" : "not-selected";
$("#visitors").append('<h5 class="' + state + '" data-id=' + visitors[i].idSession + '>' + visitors[i].visitorOnline + '</h5>');
}
if(visitorSelected == null){
$("#visitors h5:first-child").attr("class", "selected");
visitorSelected = $("#visitors h5:first-child").attr("data-id");
localStorage.setItem('visitorSelected', visitorSelected);
}
}
}
}
$('#visitors').on('click', 'h5.not-selected', visitorSelected);
*Note: The entire code has not been submitted, but a code snippet.
Thanks!
Regards!

Generate a multidimensional array for php post, using data attributes of inputs

I have set a code to generate dynamic tables to capture data, which will be used to send a message to the students regarding a timetable. Following generates the required user input form, so that the user can insert the data as required.
$(document).ready(function() {
var index = 1;
var tableindex = 0;
var daydd = '<select><option value="Saturday">Saturday</option><option value="Sunday">Sunday</option></select>';
$("#addRow").click(function() {
if (tableindex == 0) {
tableindex++;
$("#myTable").append("<tr data-day='" + tableindex + "'><td colspan=3>"+daydd+" " + tableindex + "</td><td><button class='dayclose' data-day='" + tableindex + "'>Close</button></td></tr>");
}
$("#myTable").append("<tr data-day='" + tableindex + "'><td>Day " + tableindex + "</td><td>row " + index + "</td><td><input type='text' data-clday='" + tableindex + "' data-subj='" + index + "' ></td><td><button class='subjclose' id='" + index + "'>Close</button></td></tr>");
index++;
});
$("#addtable").click(function() {
tableindex++;
$("#myTable").append("<tr data-day='" + tableindex + "'><td colspan=3>"+daydd+" " + tableindex + "</td><td><button class='dayclose' data-day='" + tableindex + "'>Close</button></td></tr><tr data-day='" + tableindex + "'><td>Day " + tableindex + "</td><td>row " + index + "</td><td><input type='text' data-clday='" + tableindex + "' data-subj='" + index + "' ></td><td><button class='subjclose' id='" + tableindex + "'>Close</button></td></tr>");
index++;
});
$('table').on('click', '.subjclose', function(e) {
e.preventDefault();
$(this).parents('tr').remove();
});
$('table').on('click', '.dayclose', function(e) {
e.preventDefault();
var closeday = $(this).attr("data-day");
$('tr[data-day="' + closeday + '"]').remove();
$(this).parents('tr').remove();
});
//$('.row-container[data="product_id"]').remove();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<table id="myTable">
</table>
<input type="button" id="addRow" value="add subject" />
<input type="button" id="addtable" value="add day" />
<input type="button" id="submit" value="Send Data" />
Now I am trying to capture data to be sent to a php script, so that it can send the message to a selected set of students. My message would be as follows; (consider rows 3,4,6,9 as deleted in this scenario)
Saturday Subjects
Row 1 data
Row 2 data
Sunday Subjects
Row 5 data
Row 7 data
Monday Subjects
Row 8 data
Row 10 data
I am trying to run a for each loop for this in my php script, but I do not have any idea how to achieve this with the data attributes.
How can I generate a multidimensional array to be sent to a php script using the data attributes of inputs so that it can be used to generate a foreach loop?
You can use the JQuery function like this
$.fn.onAddDefaultValue = function (options) {
// This is the easiest way to have default options.
var settings = $.extend({
// These are the defaults.
data: '',
profile_main_div_id: '',
server_div_id: '',
addi_id : '',
confirm_btn_id: ''
}, options);
$(settings.data).each(function(idx,obj){
var item_id = obj.item_id;
var item_title = obj.item_title;
// server pratik - 10112017 location widget interaction
var isLocationExist = false;
$("#"+settings.server_div_id).children().each(function () {
var child_div = $(this);
var localtion_value = child_div.find("span").text();
if (localtion_value == item_title) {
//child_div.find("span").css("border", "1px solid #f16262");
isLocationExist = true;
//return false;
}else {
//child_div.find("span").css("border", "0px solid #f16262");
}
});
if (!isLocationExist) {
var input_value = item_title;
var newTextBoxDiv = $(document.createElement('div'))
.attr({"class": 'customcheckbox',"style":'margin: 0px 0px 10px;'});
var chk_id = item_id;
newTextBoxDiv.after().html('<input type="checkbox" checked name="remember" id="'+chk_id+'" value="user_profile_remember_me-no">'+
'<input type="hidden" class="server_item_id" value="'+item_id+'" />'+
'<label style="float: right;position: relative;margin-right: 10px;border: 1px solid #000000;border-radius: 0px" for="'+chk_id+'">'+
'<div class="input-label"></div>'+
'</label>'+
'<span style="padding-left: 5px;" class="my-label1">'+input_value+'</span>');
newTextBoxDiv.appendTo("#"+settings.server_div_id);
//$("#"+settings.addi_id).slideUp();
//$(this).closest('#'+settings.profile_main_div_id).removeClass("additional-field-open");
// add new item
} else {
$('#'+settings.server_div_id).children().each(function () {
var child_div_appearance = $(this);
var title_v = $(this).find("span").text();
var status_v = $(this).find("input[type='checkbox']").prop("checked");
if((item_title == title_v) && (!status_v)){
$(this).find("input[type='checkbox']").click();//attr("checked",false)
// break loop
// return false;
}
});
}
$("#"+settings.confirm_btn_id).click();
//$("#"+settings.server_div_id).addClientNote({});
});
};
and remove added element like this
$.fn.removeDiagnosisValue = function (options) {
// This is the easiest way to have default options.
var settings = $.extend({
// These are the defaults.
title: ''
}, options);
$(this).children().each(function () {
var child_div = $(this);
var div_buttons = child_div.find("div");
var i = 0;
$(div_buttons).children().each(function () {
// delete icon
var child_span = $(this);
if (child_span.attr('name') == "delete") {
var img_delete = child_span.find("img");
img_delete.click(function () {
child_div.remove();
});
// break loop
return false;
}
});
});
};

How to insert fields using jQuery?

I'm trying to realise this code in the snippet, for the moment I'm working only on the button Label, so when I click on this button, it adds a small formular that allows to creat this a label in the right side by clicking on OK. However, even if I click on OK nothing happens, normally a label should appear with the name inserted in the textfield "label".
Does anyone know where is the problem? Thank you in advance.
$(function(){
$('button').click(function(){
var typeButton = $(this).text();
if(typeButton=='Label'){
$('hr').remove();
$('#formule').remove();
$('#droite').append('<hr>');
var elementLabel = 'Texte du label';
var elementTexte = '<input type="text" name="label"/>';
var elementButton = '<button>OK</button>';
var elementSpan = elementLabel+' '+elementTexte+' '+elementButton;
var elementDiv = '<div id="formule">'+elementSpan+'</div>'
$(elementDiv).insertAfter('hr');
};
if(typeButton=='OK'){
$('hr').remove();
var elementNom = $('input[name=label]').val();
var elementSpan = '<span>'+elementNom+'</span>';
$('#formule').remove();
$('#gauche').append('elementSpan');
};
});
});
body {
margin: 0;
}
#gauche {
float: left;
width: 70%;
height: 1000px;
background-color: #EFECCA;
}
#droite {
background-color: #CEFFF8;
height: 1000px;
padding : 10px;
padding-left: 71%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<div id="gauche">
</div>
<div id="droite">
Utilisez ces boutons pour créer votre formulaire<br><br>
<button>Label</button>
<button>Zone de texte</button>
<button>Bouton</button>
</div>
you need to delegate dynamically added elements using on event handler attachment with the document.
$(document).on('click', 'button', function () {
var typeButton = $(this).text();
if (typeButton == 'Label') {
$('hr').remove();
$('#formule').remove();
$('#droite').append('<hr>');
var elementLabel = 'Texte du label';
var elementTexte = '<input type="text" name="label"/>';
var elementButton = '<button>OK</button>';
var elementSpan = elementLabel + ' ' + elementTexte + ' ' + elementButton;
var elementDiv = '<div id="formule">' + elementSpan + '</div>'
$(elementDiv).insertAfter('hr');
};
if (typeButton == 'OK') {
$('hr').remove();
var elementNom = $('input[name=label]').val();
var elementSpan = '<span>' + elementNom + '</span>';
$('#formule').remove();
$('#gauche').append(elementSpan);
};
});
It's because the button that gets generated to the DOM (OK) doesn't have an event listener attached to it, so it has nothing to do when being pressed. $('button').click() doesn't get updated any time the DOM changes, so you have to do it yourself.
$(function() {
function listenToButtons() {
$('button').off().on('click', function() {
var typeButton = $(this).text();
if (typeButton == 'Label') {
$('hr').remove();
$('#formule').remove();
$('#droite').append('<hr>');
var elementLabel = 'Texte du label';
var elementTexte = '<input type="text" name="label"/>';
var elementButton = '<button>OK</button>';
var elementSpan = elementLabel + ' ' + elementTexte + ' ' + elementButton;
var elementDiv = '<div id="formule">' + elementSpan + '</div>'
$(elementDiv).insertAfter('hr');
listenToButtons();
};
if (typeButton == 'OK') {
$('hr').remove();
var elementNom = $('input[name=label]').val();
var elementSpan = '<span>' + elementNom + '</span>';
$('#formule').remove();
$('#gauche').append('elementSpan');
};
});
}
listenToButtons();
});

Masonry sometimes lays out in one column straight line

I have masonry initialized on some "tiles" that include an image. Most of the time I am not having issues but sometimes the tiles lay out in one column when there should be 3 columns. Do you have any idea what the issue might be?
On ready initialization:
$(document).ready(function() {
var $container = $('#news');
$container.masonry({
itemSelector: '.pageNewsItem',
transitionDuration: 0
});
$container.masonry( 'on', 'layoutComplete', function( msnryInstance, laidOutItems ) {debounced = true;} )
});
Dynamically append tiles:
var count = 0;
function placeNewsTiles(news){ //places news tiles
var length = (news.data.length > 20) ? 20 : news.data.length;
var elems ="";
for(var i = 0; i < length; i++){
elems += '<div class="pageNewsItem inactive" id="'+ count + i + '">\
<div class="outerTextWrap">\
<div class="textWrap">\
<a href="' + news.data[i]._url + '">\
<strong>' + news.data[i]._title + '</strong>\
</a>\
<span class="source">' + news.data[i]._source + '</span>\
</div>\
</div>\
<div class="imageWrap"></div>\
<div class="thumbsOverlay" style="display:none">\
<div class="thumbs">\
<div>\
\
\
</div>\
</div>\
<div class="title">\
<div>\
<a href="' + news.data[i]._url + '">\
<div class="theTitle">Read Article</div>\
</a>\
</div>\
</div>\
</div>\
</div>';
getTileImage({total: news.count, i:count + "" + i, url:news.data[i]._url});
}
elems = $(elems);
$('#news').append(elems).imagesLoaded(function(){
//for(var i = 0; i < length; i++) $('.pageNewsItem').removeClass('inactive'); //$('.pageNewsItem').show(1000);
$('#news').masonry( 'appended', elems);
});
newsPage = 0;
count++;
hoverTiles();
}
getTileImage function is called to conduct an ajax call to obtain the tile image. Masonry layout happens on complete:
var cnt = 0;
function getTileImage(args){
var _t = localStorage.getItem("token"),
url = args.url,
i = args.i;
$.ajax({
type: "GET",
url: apiHost+'/api/tileImg?url=' + url + '&token='+_t,
dataType: "json",
success: function(data) {
var img = (data && data.image.src) ? data.img.src : (data && data.image) ? data.image: "";
if(img.indexOf("spacer") > -1|| img.indexOf("blank") > -1 || img === ""){ $('.pageNewsItem#' + i).hide(); }
else $('.pageNewsItem#' + i).find('.imageWrap').append('<img src="' + img + '" />');
},
error: function(e) {
if (e.status == 404) {
//need to get a new token
getToken(getTileImage, url);
}
}, complete: function(){
cnt++;
if ((cnt ==20) || cnt == args.total) {
var $container = $('#news');
$container.imagesLoaded( function() {
$container.masonry( 'layout' );
$('.pageNewsItem').removeClass('inactive');
//$('.pageNewsItem').show();
});
cnt = 0;
}
/*$('#news').imagesLoaded( function() {
$('.pageNewsItem#' + i + ' .thumbs').height($('.pageNewsItem#' + i).outerHeight() - $('.pageNewsItem#' + i + ' .title').height() - 5);
//$('.pageNewsItem').show();
});*/
}
});//end ajax call
}
CSS:
.pageNewsItem {
width: 33.333%;
padding: 10px;
min-height: 150px;
opacity: 1;
transition: opacity 1s ease;
}
#news {
margin-right: 20px;
margin-top: 25px;
}
Try using the console and manually initialize masonry:
$('#news').masonry();
If it is not working, masonry might be already initialized and therefore it's not repositioning the elements. In that case you have to remove masonry from the div and reinitialize it:
$('#news').masonry('destroy');
$('#news').masonry();

Categories

Resources