From 08a66fce17936457be47b7096d1ee23f21cd5722 Mon Sep 17 00:00:00 2001 From: Elli Scharlin Date: Tue, 4 Dec 2018 16:45:28 -0500 Subject: [PATCH 1/2] an updated version Make sure to give the contenteditable div a class name of contenteditable. --- js/jquery.emojipicker.js | 323 ++++++++++++++++++++------------------- 1 file changed, 168 insertions(+), 155 deletions(-) diff --git a/js/jquery.emojipicker.js b/js/jquery.emojipicker.js index 1aad3a3..01e6be4 100644 --- a/js/jquery.emojipicker.js +++ b/js/jquery.emojipicker.js @@ -1,24 +1,25 @@ ;(function($) { var pluginName = "emojiPicker", - defaults = { - width: '200', - height: '350', - position: 'right', - fadeTime: 100, - iconColor: 'black', - iconBackgroundColor: '#eee', - recentCount: 36, - emojiSet: 'apple', - container: 'body', - button: true - }; + defaults = { + width: '200', + height: '350', + position: 'right', + fadeTime: 100, + iconColor: 'black', + iconBackgroundColor: '#eee', + recentCount: 36, + emojiSet: 'apple', + container: 'body', + button: true, + richInput: true, + }; var MIN_WIDTH = 280, - MAX_WIDTH = 600, - MIN_HEIGHT = 100, - MAX_HEIGHT = 350, - MAX_ICON_HEIGHT = 50; + MAX_WIDTH = 600, + MIN_HEIGHT = 100, + MAX_HEIGHT = 350, + MAX_ICON_HEIGHT = 50; var categories = [ { name: 'people', label: 'People' }, @@ -36,6 +37,9 @@ this.element = element; this.$el = $(element); + // This will either be the element or the rich text area. + this.$input = this.$el; + this.settings = $.extend( {}, defaults, options ); this.$container = $(this.settings.container); @@ -57,9 +61,9 @@ } var possiblePositions = [ 'left', - 'right' - /*,'top', - 'bottom'*/]; + 'right' + /*,'top', + 'bottom'*/]; if($.inArray(this.settings.position,possiblePositions) == -1) { this.settings.position = defaults.position; //current default } @@ -75,15 +79,21 @@ $.extend(EmojiPicker.prototype, { - init: function() { + init: function () { this.active = false; this.addPickerIcon(); this.createPicker(); this.listen(); }, - addPickerIcon: function() { - // The wrapper is not needed if they have chosen to not use a button + listen: function() { + // Click event for emoji + this.$picker.on('click', 'em', $.proxy(this.emojiClicked, this)); + }, + + // TODO : Placeholder http://stackoverflow.com/questions/20726174/placeholder-for-contenteditable-div + + addPickerIcon: function () { if (this.settings.button) { var elementHeight = this.$el.outerHeight(); var iconHeight = elementHeight > MAX_ICON_HEIGHT ? @@ -104,19 +114,18 @@ .width(iconHeight) .addClass(this.settings.iconColor) .css('backgroundColor', this.settings.iconBackgroundColor); - this.$wrapper.append( this.$icon ); + this.$wrapper.append(this.$icon); } - }, - createPicker: function() { + createPicker: function () { // Show template - this.$picker = $( getPickerHTML() ) - .appendTo( this.$container ) + this.$picker = $(getPickerHTML()) + .appendTo(this.$container) .width(this.settings.width) .height(this.settings.height) - .css('z-index',10000); + .css('z-index', 10000); // Picker height this.$picker.find('.sections') @@ -124,12 +133,12 @@ // Tab size based on width if (this.settings.width < 240) { - this.$picker.find('.emoji').css({'width':'1em', 'height':'1em'}); + this.$picker.find('.emoji').css({'width': '1em', 'height': '1em'}); } }, - destroyPicker: function() { + destroyPicker: function () { if (this.isMobile) return this; this.$picker.unbind('mouseover'); @@ -142,48 +151,7 @@ return this; }, - listen: function() { - // If the button is being used, wrapper has not been set, - // and will not need a listener - if (this.settings.button){ - // Clicking on the picker icon - this.$wrapper.find('.emojiPickerIcon') - .click( $.proxy(this.iconClicked, this) ); - } - - // Click event for emoji - this.$picker.on('click', 'em', $.proxy(this.emojiClicked, this)); - - // Hover event for emoji - this.$picker.on('mouseover', 'em', $.proxy(this.emojiMouseover, this) ); - this.$picker.on('mouseout', 'em', $.proxy(this.emojiMouseout, this) ); - - // Click event for active tab - this.$picker.find('nav .tab') - .click( $.proxy(this.emojiCategoryClicked, this) ) - .mouseover( $.proxy(this.emojiTabMouseover, this) ) - .mouseout( $.proxy(this.emojiMouseout, this) ); - - // Scroll event for active tab - this.$picker.find('.sections') - .scroll( $.proxy(this.emojiScroll, this) ); - - this.$picker.click( $.proxy(this.pickerClicked, this) ); - - // Key events for search - this.$picker.find('section.search input') - .on('keyup search', $.proxy(this.searchCharEntered, this) ); - - // Shortcode hover - this.$picker.find('.shortcode').mouseover(function(e) { e.stopPropagation(); }); - - $(document.body).click( $.proxy(this.clickOutside, this) ); - - // Resize events forces a reposition, which may or may not actually be required - $(window).resize( $.proxy(this.updatePosition, this) ); - }, - - updatePosition: function() { + updatePosition: function () { /* Process: 1. Find the nearest positioned element by crawling up the ancestors, record it's offset @@ -201,7 +169,7 @@ // Step 2 var elOffset = this.$el.offset(); - if(this.settings.position == 'right'){ + if (this.settings.position == 'right') { elOffset.left += this.$el.outerWidth() - this.settings.width; } elOffset.top += this.$el.outerHeight(); @@ -220,22 +188,22 @@ return this; }, - hide: function() { - this.$picker.hide(this.settings.fadeTime, 'linear', function() { + hide: function () { + this.$picker.hide(this.settings.fadeTime, 'linear', function () { this.active = false; if (this.settings.onHide) { - this.settings.onHide( this.$picker, this.settings, this.active ); + this.settings.onHide(this.$picker, this.settings, this.active); } }.bind(this)); }, - show: function() { + show: function () { this.$el.focus(); this.updatePosition(); - this.$picker.show(this.settings.fadeTime, 'linear', function() { + this.$picker.show(this.settings.fadeTime, 'linear', function () { this.active = true; if (this.settings.onShow) { - this.settings.onShow( this.$picker, this.settings, this.active ); + this.settings.onShow(this.$picker, this.settings, this.active); } }.bind(this)); }, @@ -244,10 +212,10 @@ * EVENTS * ************/ - iconClicked : function() { - if ( this.$picker.is(':hidden') ) { + iconClicked: function () { + if (this.$picker.is(':hidden')) { this.show(); - if( this.$picker.find('.search input').length > 0 ) { + if (this.$picker.find('.search input').length > 0) { this.$picker.find('.search input').focus(); } } else { @@ -255,7 +223,9 @@ } }, - emojiClicked: function(e) { var clickTarget = $(e.target); + emojiClicked: function (e) { + var clickTarget = $(e.target); + this.$input.focus(); var emojiSpan; if (clickTarget.is('em')) { emojiSpan = clickTarget.find('span'); @@ -266,7 +236,15 @@ var emojiShortcode = emojiSpan.attr('class').split('emoji-')[1]; var emojiUnicode = toUnicode(findEmoji(emojiShortcode).unicode[defaults.emojiSet]); - insertAtCaret(this.element, emojiUnicode); + console.log('about to insert emoji'); + console.log(emojiUnicode); + console.log(emojiShortcode); + console.log(this.$el); + console.log(this.$input); + + var emoji = angular.element('').html(emojiUnicode)[0]; + + insertTextAtCursor(emoji, this.$el); addToLocalStorage(emojiShortcode); updateRecentlyUsed(emojiShortcode); @@ -277,21 +255,22 @@ var event = document.createEvent("HTMLEvents"); event.initEvent("input", true, true); this.element.dispatchEvent(event); + this.$input.focus(); }, - emojiMouseover: function(e) { + emojiMouseover: function (e) { var emojiShortcode = $(e.target).parent().find('.emoji').attr('class').split('emoji-')[1]; var $shortcode = $(e.target).parents('.emojiPicker').find('.shortcode'); $shortcode.find('.random').hide(); $shortcode.find('.info').show().html('
' + emojiShortcode + ''); }, - emojiMouseout: function(e) { + emojiMouseout: function (e) { $(e.target).parents('.emojiPicker').find('.shortcode .info').empty().hide(); $(e.target).parents('.emojiPicker').find('.shortcode .random').show(); }, - emojiCategoryClicked: function(e) { + emojiCategoryClicked: function (e) { var section = ''; // Update tab @@ -312,20 +291,20 @@ var heightOfSectionsToPageTop = $section.parent().offset().top; var scrollDistance = heightOfSectionsHidden - + heightOfSectionToPageTop - - heightOfSectionsToPageTop; + + heightOfSectionToPageTop + - heightOfSectionsToPageTop; $('.sections').off('scroll'); // Disable scroll event until animation finishes var that = this; $('.sections').animate({ scrollTop: scrollDistance - }, 250, function() { - that.$picker.find('.sections').on('scroll', $.proxy(that.emojiScroll, that) ); // Enable scroll event + }, 250, function () { + that.$picker.find('.sections').on('scroll', $.proxy(that.emojiScroll, that)); // Enable scroll event }); }, - emojiTabMouseover: function(e) { + emojiTabMouseover: function (e) { var section = ''; if ($(e.target).parent().hasClass('tab')) { section = $(e.target).parent().attr('data-tab'); @@ -336,9 +315,13 @@ var categoryTitle = ''; for (var i = 0; i < categories.length; i++) { - if (categories[i].name == section) { categoryTitle = categories[i].label; } + if (categories[i].name == section) { + categoryTitle = categories[i].label; + } + } + if (categoryTitle == '') { + categoryTitle = 'Recently Used'; } - if (categoryTitle == '') { categoryTitle = 'Recently Used'; } var categoryCount = $('section.' + section).attr('data-count'); var categoryHtml = '' + categoryTitle + ' (' + categoryCount + ' emojis)'; @@ -348,9 +331,9 @@ $shortcode.find('.info').show().html(categoryHtml); }, - emojiScroll: function(e) { + emojiScroll: function (e) { var sections = $('section'); - $.each(sections, function(key, value) { + $.each(sections, function (key, value) { var section = sections[key]; var offsetFromTop = $(section).position().top; @@ -366,50 +349,14 @@ }); }, - pickerClicked: function(e) { - e.stopPropagation(); - }, - - clickOutside: function(e) { - if ( this.active ) { + clickOutside: function (e) { + if (this.active) { this.hide(); } }, - - searchCharEntered: function(e) { - var searchTerm = $(e.target).val(); - var searchEmojis = $(e.target).parents('.sections').find('section.search'); - var searchEmojiWrap = searchEmojis.find('.wrap'); - var sections = $(e.target).parents('.sections').find('section'); - - // Clear if X is clicked within input - if (searchTerm == '') { - sections.show(); - searchEmojiWrap.hide(); - } - - if (searchTerm.length > 0) { - sections.hide(); - searchEmojis.show(); - searchEmojiWrap.show(); - - var results = []; - searchEmojiWrap.find('em').remove(); - - $.each($.fn.emojiPicker.emojis, function(i, emoji) { - var shortcode = emoji.shortcode; - if ( shortcode.indexOf(searchTerm) > -1 ) { - results.push('
'); - } - }); - searchEmojiWrap.append(results.join('')); - } else { - sections.show(); - searchEmojiWrap.hide(); - } - } }); + $.fn[ pluginName ] = function ( options ) { // Calling a function @@ -439,6 +386,54 @@ /* ---------------------------------------------------------------------- */ + /* + * getStyleObject Plugin for jQuery JavaScript Library + * From: http://upshots.org/?p=112 + */ + $.fn.getStyleObject = function(){ + var dom = this.get(0); + var style; + var returns = {}; + if(window.getComputedStyle){ + var camelize = function(a,b){ + return b.toUpperCase(); + }; + style = window.getComputedStyle(dom, null); + for(var i = 0, l = style.length; i < l; i++){ + var prop = style[i]; + var camel = prop.replace(/\-([a-z])/g, camelize); + var val = style.getPropertyValue(prop); + returns[camel] = val; + }; + return returns; + }; + if(style = dom.currentStyle){ + for(var prop in style){ + returns[prop] = style[prop]; + }; + return returns; + }; + return this.css(); + } + + $.fn.copyCSS = function(source, attributes){ + var styles = $(source).getStyleObject(); + var copiedStyles = {}; + for (var i in attributes) { + var attr = attributes[i]; + if ( attr instanceof RegExp ) { + for (prop in styles) { + if (prop.match(attr)) + copiedStyles[ prop ] = styles[ prop ]; + } + } else { + if (attr in styles) + copiedStyles[ attr ] = styles[ attr ]; + } + }; + this.css(copiedStyles); + } + function getPickerHTML() { var nodes = []; var aliases = { @@ -466,12 +461,12 @@ var categories_length = categories.length; for (var i = 0; i < categories_length; i++) { nodes.push('
'); + ( !localStorageSupport && i == 0 ? ' active' : '' ) + + '" data-tab="' + + categories[i].name + + '">
'); } nodes.push(''); nodes.push('
'); @@ -485,12 +480,10 @@ // Recent Section, if localstorage support if (localStorageSupport) { var recentlyUsedEmojis = []; - var recentlyUsedCount = 0; var displayRecentlyUsed = ' style="display:none;"'; if (localStorage.emojis) { recentlyUsedEmojis = JSON.parse(localStorage.emojis); - recentlyUsedCount = recentlyUsedEmojis.length; displayRecentlyUsed = ' style="display:block;"'; } @@ -535,17 +528,37 @@ function findEmoji(emojiShortcode) { var emojis = $.fn.emojiPicker.emojis; for (var i = 0; i < emojis.length; i++) { - if (emojis[i].shortcode == emojiShortcode) { + if (emojis[i].shortcode === emojiShortcode) { return emojis[i]; } } } + // For contenteditable + function insertTextAtCursor(text, inputArea) { + var sel, range; + + if (window.getSelection()) { + // Add a space after the pill + sel = window.getSelection(); + if (inputArea.hasClass('.contenteditable') && sel.getRangeAt && sel.rangeCount && inputArea[0].hasChildNodes(window.getSelection().anchorNode)) { + range = sel.getRangeAt(0); + range.deleteContents(); + range.insertNode(text); + } else { + // We are not writting + console.log(text); + inputArea[0].appendChild(text).after(''); + } + sel.removeAllRanges(); + } + } + // For text area function insertAtCaret(inputField, myValue) { - if (document.selection) { + if (window.selection) { //For browsers like Internet Explorer inputField.focus(); - var sel = document.selection.createRange(); + var sel = window.getSelection(); sel.text = myValue; inputField.focus(); } @@ -561,7 +574,7 @@ inputField.scrollTop = scrollTop; } else { inputField.focus(); - inputField.value += myValue; + inputField.value } } @@ -623,14 +636,14 @@ if (!String.fromCodePoint) { // ES6 Unicode Shims 0.1 , © 2012 Steven Levithan http://slevithan.com/ , MIT License String.fromCodePoint = function fromCodePoint () { - var chars = [], point, offset, units, i; - for (i = 0; i < arguments.length; ++i) { - point = arguments[i]; - offset = point - 0x10000; - units = point > 0xFFFF ? [0xD800 + (offset >> 10), 0xDC00 + (offset & 0x3FF)] : [point]; - chars.push(String.fromCharCode.apply(null, units)); - } - return chars.join(""); + var chars = [], point, offset, units, i; + for (i = 0; i < arguments.length; ++i) { + point = arguments[i]; + offset = point - 0x10000; + units = point > 0xFFFF ? [0xD800 + (offset >> 10), 0xDC00 + (offset & 0x3FF)] : [point]; + chars.push(String.fromCharCode.apply(null, units)); + } + return chars.join(""); } } From fbce14fd597992178f09d0911a5ca2c94bfdb56b Mon Sep 17 00:00:00 2001 From: Elli Scharlin Date: Tue, 4 Dec 2018 16:48:21 -0500 Subject: [PATCH 2/2] Update jquery.emojipicker.js --- js/jquery.emojipicker.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/js/jquery.emojipicker.js b/js/jquery.emojipicker.js index 01e6be4..ba0fee7 100644 --- a/js/jquery.emojipicker.js +++ b/js/jquery.emojipicker.js @@ -236,11 +236,11 @@ var emojiShortcode = emojiSpan.attr('class').split('emoji-')[1]; var emojiUnicode = toUnicode(findEmoji(emojiShortcode).unicode[defaults.emojiSet]); - console.log('about to insert emoji'); - console.log(emojiUnicode); - console.log(emojiShortcode); - console.log(this.$el); - console.log(this.$input); +// console.log('about to insert emoji'); +// console.log(emojiUnicode); +// console.log(emojiShortcode); +// console.log(this.$el); +// console.log(this.$input); var emoji = angular.element('').html(emojiUnicode)[0]; @@ -547,7 +547,7 @@ range.insertNode(text); } else { // We are not writting - console.log(text); +// console.log(text); inputArea[0].appendChild(text).after(''); } sel.removeAllRanges();