jquery.emoji.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. /**
  2. * Created by Sky on 2015/12/11.
  3. */
  4. (function ($, window, document) {
  5. var PLUGIN_NAME = 'emoji',
  6. VERSION = '1.1.0',
  7. DEFAULTS = {
  8. showTab: true,
  9. animation: 'fade',
  10. icons: []
  11. };
  12. window.emoji_index = 0;
  13. function Plugin(element, options) {
  14. this.$content = $(element);
  15. this.options = options;
  16. this.index = emoji_index;
  17. switch (options.animation) {
  18. case 'none':
  19. this.showFunc = 'show';
  20. this.hideFunc = 'hide';
  21. this.toggleFunc = 'toggle';
  22. break;
  23. case 'slide':
  24. this.showFunc = 'slideDown';
  25. this.hideFunc = 'slideUp';
  26. this.toggleFunc = 'slideToggle';
  27. break;
  28. case 'fade':
  29. this.showFunc = 'fadeIn';
  30. this.hideFunc = 'fadeOut';
  31. this.toggleFunc = 'fadeToggle';
  32. break;
  33. default :
  34. this.showFunc = 'fadeIn';
  35. this.hideFunc = 'fadeOut';
  36. this.toggleFunc = 'fadeToggle';
  37. break;
  38. }
  39. this._init();
  40. }
  41. Plugin.prototype = {
  42. _init: function () {
  43. var that = this;
  44. var btn = this.options.button;
  45. var newBtn,
  46. contentTop,
  47. contentLeft,
  48. btnTop,
  49. btnLeft;
  50. var ix = that.index;
  51. if (!btn) {
  52. newBtn = '<input type="image" class="emoji_btn" id="emoji_btn_' + ix + '" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZBAMAAAA2x5hQAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAkUExURUxpcfTGAPTGAPTGAPTGAPTGAPTGAPTGAPTGAPTGAPTGAPTGAOfx6yUAAAALdFJOUwAzbVQOoYrzwdwkAoU+0gAAAM1JREFUGNN9kK0PQWEUxl8fM24iCYopwi0muuVuzGyKwATFZpJIU01RUG/RBMnHxfz+Oef9uNM84d1+23nO+zxHKVG2WWupRJkdcAwtpCK0lpbqWE01pB0QayonREMoIp7AawQrWSgGGb4pn6dSeSh68FAVXqHqy3wKrkJiDGDTg3dnp//w+WnwlwIOJauF+C7sXRVfdha4O4oIJfTbtdSxs2uqhs585A0ko8iLTMEcDE1n65A+29pYAlr72nz9dKu7GuNTcsL2fDQzB/wCPVJ69nZGb3gAAAAASUVORK5CYII="/>';
  53. contentTop = this.$content.offset().top + this.$content.outerHeight() + 10;
  54. contentLeft = this.$content.offset().left + 2;
  55. $(newBtn).appendTo($('body'));
  56. $('#emoji_btn_' + ix).css({'top': contentTop + 'px', 'left': contentLeft + 'px'});
  57. btn = '#emoji_btn_' + ix;
  58. }
  59. var showTab = this.options.showTab;
  60. var iconsGroup = this.options.icons;
  61. var groupLength = iconsGroup.length;
  62. if (groupLength === 0) {
  63. alert('Missing icons config!');
  64. return false;
  65. }
  66. var emoji_container = '<div class="emoji_container" id="emoji_container_' + ix + '">';
  67. var emoji_content = '<div class="emoji_content">';
  68. var emoji_tab = '<div class="emoji_tab" style="' + (groupLength === 1 && !showTab ? 'display:none;' : '') + '"><div class="emoji_tab_prev"></div><div class="emoji_tab_list"><ul>';
  69. var panel,
  70. name,
  71. path,
  72. maxNum,
  73. excludeNums,
  74. file,
  75. placeholder,
  76. alias,
  77. title,
  78. index,
  79. notation;
  80. for (var i = 0; i < groupLength; i++) {
  81. name = iconsGroup[i].name || 'group' + (i + 1);
  82. path = iconsGroup[i].path;
  83. maxNum = iconsGroup[i].maxNum;
  84. excludeNums = iconsGroup[i].excludeNums;
  85. file = iconsGroup[i].file || '.jpg';
  86. placeholder = iconsGroup[i].placeholder || '#em' + (i + 1) + '_{alias}#';
  87. alias = iconsGroup[i].alias;
  88. title = iconsGroup[i].title;
  89. index = 0;
  90. if (!path || !maxNum) {
  91. alert('The ' + i + ' index of icon groups has error config!');
  92. continue;
  93. }
  94. panel = '<div id="emoji' + i + '" class="emoji_icons" style="' + (i === 0 ? '' : 'display:none;') + '"><ul>';
  95. for (var j = 1; j <= maxNum; j++) {
  96. if (excludeNums && excludeNums.indexOf(j) >= 0) {
  97. continue;
  98. }
  99. if (alias) {
  100. if (typeof alias !== 'object') {
  101. alert('Error config about alias!');
  102. break;
  103. }
  104. notation = placeholder.replace(new RegExp('{alias}', 'gi'), alias[j].toString());
  105. } else {
  106. notation = placeholder.replace(new RegExp('{alias}', 'gi'), j.toString());
  107. }
  108. panel += '<li><a data-emoji_code="' + notation + '" data-index="' + index + '" title="' + (title && title[j] ? title[j] : '') + '"><img src="' + path + j + file + '"/></a></li>';
  109. index++;
  110. }
  111. panel += '</ul></div>';
  112. emoji_content += panel;
  113. emoji_tab += '<li data-emoji_tab="emoji' + i + '" class="' + (i === 0 ? 'selected' : '') + '" title="' + name + '">' + name + '</li>';
  114. }
  115. emoji_content += '</div>';
  116. emoji_tab += '</ul></div><div class="emoji_tab_next"></div></div>';
  117. var emoji_preview = '<div class="emoji_preview"><img/></div>';
  118. emoji_container += emoji_content;
  119. emoji_container += emoji_tab;
  120. emoji_container += emoji_preview;
  121. $(emoji_container).appendTo($('body'));
  122. btnTop = $(btn).offset().top + $(btn).outerHeight() + 5;
  123. btnLeft = $(btn).offset().left;
  124. $('#emoji_container_' + ix).css({'top': btnTop + 'px', 'left': btnLeft + 'px'});
  125. $('#emoji_container_' + ix + ' .emoji_content').mCustomScrollbar({
  126. theme: 'minimal-dark',
  127. scrollbarPosition: 'inside',
  128. mouseWheel: {
  129. scrollAmount: 275
  130. }
  131. });
  132. var pageCount = groupLength % 8 === 0 ? parseInt(groupLength / 8) : parseInt(groupLength / 8) + 1;
  133. var pageIndex = 1;
  134. $(document).on({
  135. 'click': function (e) {
  136. var target = e.target;
  137. var field = that.$content[0];
  138. var code,
  139. tab,
  140. imgSrc,
  141. insertHtml;
  142. if (target === $(btn)[0]) {
  143. $('#emoji_container_' + ix)[that.toggleFunc]();
  144. that.$content.focus();
  145. } else if ($(target).parents('#emoji_container_' + ix).length > 0) {
  146. code = $(target).data('emoji_code') || $(target).parent().data('emoji_code');
  147. tab = $(target).data('emoji_tab');
  148. if (code) {
  149. if (field.nodeName === 'DIV') {
  150. imgSrc = $('#emoji_container_' + ix + ' a[data-emoji_code="' + code + '"] img').attr('src');
  151. insertHtml = '<img class="emoji_icon" src="' + imgSrc + '"/>';
  152. that._insertAtCursor(field, insertHtml, false);
  153. } else {
  154. that._insertAtCursor(field, code);
  155. }
  156. that.hide();
  157. }
  158. else if (tab) {
  159. if (!$(target).hasClass('selected')) {
  160. $('#emoji_container_' + ix + ' .emoji_icons').hide();
  161. $('#emoji_container_' + ix + ' #' + tab).show();
  162. $(target).addClass('selected').siblings().removeClass('selected');
  163. }
  164. } else if ($(target).hasClass('emoji_tab_prev')) {
  165. if (pageIndex > 1) {
  166. $('#emoji_container_' + ix + ' .emoji_tab_list ul').css('margin-left', ('-503' * (pageIndex - 2)) + 'px');
  167. pageIndex--;
  168. }
  169. } else if ($(target).hasClass('emoji_tab_next')) {
  170. if (pageIndex < pageCount) {
  171. $('#emoji_container_' + ix + ' .emoji_tab_list ul').css('margin-left', ('-503' * pageIndex) + 'px');
  172. pageIndex++;
  173. }
  174. }
  175. that.$content.focus();
  176. } else if ($('#emoji_container_' + ix + ':visible').length > 0) {
  177. that.hide();
  178. that.$content.focus();
  179. }
  180. }
  181. });
  182. $('#emoji_container_' + ix + ' .emoji_icons a').mouseenter(function () {
  183. var index = $(this).data('index');
  184. if (parseInt(index / 5) % 2 === 0) {
  185. $('#emoji_container_' + ix + ' .emoji_preview').css({'left': 'auto', 'right': 0});
  186. } else {
  187. $('#emoji_container_' + ix + ' .emoji_preview').css({'left': 0, 'right': 'auto'});
  188. }
  189. var src = $(this).find('img').attr('src');
  190. $('#emoji_container_' + ix + ' .emoji_preview img').attr('src', src).parent().show();
  191. });
  192. $('#emoji_container_' + ix + ' .emoji_icons a').mouseleave(function () {
  193. $('#emoji_container_' + ix + ' .emoji_preview img').removeAttr('src').parent().hide();
  194. });
  195. },
  196. _insertAtCursor: function (field, value, selectPastedContent) {
  197. var sel, range;
  198. if (field.nodeName === 'DIV') {
  199. field.focus();
  200. if (window.getSelection) {
  201. sel = window.getSelection();
  202. if (sel.getRangeAt && sel.rangeCount) {
  203. range = sel.getRangeAt(0);
  204. range.deleteContents();
  205. var el = document.createElement('div');
  206. el.innerHTML = value;
  207. var frag = document.createDocumentFragment(), node, lastNode;
  208. while ((node = el.firstChild)) {
  209. lastNode = frag.appendChild(node);
  210. }
  211. var firstNode = frag.firstChild;
  212. range.insertNode(frag);
  213. if (lastNode) {
  214. range = range.cloneRange();
  215. range.setStartAfter(lastNode);
  216. if (selectPastedContent) {
  217. range.setStartBefore(firstNode);
  218. } else {
  219. range.collapse(true);
  220. }
  221. sel.removeAllRanges();
  222. sel.addRange(range);
  223. }
  224. }
  225. } else if ((sel = document.selection) && sel.type !== 'Control') {
  226. var originalRange = sel.createRange();
  227. originalRange.collapse(true);
  228. sel.createRange().pasteHTML(html);
  229. if (selectPastedContent) {
  230. range = sel.createRange();
  231. range.setEndPoint('StartToStart', originalRange);
  232. range.select();
  233. }
  234. }
  235. } else {
  236. if (document.selection) {
  237. field.focus();
  238. sel = document.selection.createRange();
  239. sel.text = value;
  240. sel.select();
  241. }
  242. else if (field.selectionStart || field.selectionStart === 0) {
  243. var startPos = field.selectionStart;
  244. var endPos = field.selectionEnd;
  245. var restoreTop = field.scrollTop;
  246. field.value = field.value.substring(0, startPos) + value + field.value.substring(endPos, field.value.length);
  247. if (restoreTop > 0) {
  248. field.scrollTop = restoreTop;
  249. }
  250. field.focus();
  251. field.selectionStart = startPos + value.length;
  252. field.selectionEnd = startPos + value.length;
  253. } else {
  254. field.value += value;
  255. field.focus();
  256. }
  257. }
  258. },
  259. show: function () {
  260. $('#emoji_container_' + this.index)[this.showFunc]();
  261. },
  262. hide: function () {
  263. $('#emoji_container_' + this.index)[this.hideFunc]();
  264. },
  265. toggle: function () {
  266. $('#emoji_container_' + this.index)[this.toggleFunc]();
  267. }
  268. };
  269. function fn(option) {
  270. emoji_index++;
  271. return this.each(function () {
  272. var $this = $(this);
  273. var data = $this.data('plugin_' + PLUGIN_NAME + emoji_index);
  274. var options = $.extend({}, DEFAULTS, $this.data(), typeof option === 'object' && option);
  275. if (!data) $this.data('plugin_' + PLUGIN_NAME + emoji_index, (data = new Plugin(this, options)));
  276. if (typeof option === 'string') data[option]();
  277. });
  278. }
  279. $.fn[PLUGIN_NAME] = fn;
  280. $.fn[PLUGIN_NAME].Constructor = Plugin;
  281. }(jQuery, window, document));
  282. (function ($, window, document) {
  283. var PLUGIN_NAME = 'emojiParse',
  284. VERSION = '1.1.0',
  285. DEFAULTS = {
  286. icons: []
  287. };
  288. function Plugin(element, options) {
  289. this.$content = $(element);
  290. this.options = options;
  291. this._init();
  292. }
  293. Plugin.prototype = {
  294. _init: function () {
  295. var that = this;
  296. var iconsGroup = this.options.icons;
  297. var groupLength = iconsGroup.length;
  298. var path,
  299. file,
  300. placeholder,
  301. alias,
  302. pattern,
  303. regexp,
  304. revertAlias = {};
  305. if (groupLength > 0) {
  306. for (var i = 0; i < groupLength; i++) {
  307. path = iconsGroup[i].path;
  308. file = iconsGroup[i].file || '.jpg';
  309. placeholder = iconsGroup[i].placeholder;
  310. alias = iconsGroup[i].alias;
  311. if (!path) {
  312. alert('Path not config!');
  313. continue;
  314. }
  315. if (alias) {
  316. for (var attr in alias) {
  317. if (alias.hasOwnProperty(attr)) {
  318. revertAlias[alias[attr]] = attr;
  319. }
  320. }
  321. pattern = placeholder.replace(new RegExp('{alias}', 'gi'), '([\\s\\S]+?)');
  322. regexp = new RegExp(pattern, 'gm');
  323. that.$content.html(that.$content.html().replace(regexp, function ($0, $1) {
  324. var n = revertAlias[$1];
  325. if (n) {
  326. return '<img class="emoji_icon" src="' + path + n + file + '"/>';
  327. } else {
  328. return $0;
  329. }
  330. }));
  331. } else {
  332. pattern = placeholder.replace(new RegExp('{alias}', 'gi'), '(\\d+?)');
  333. that.$content.html(that.$content.html().replace(new RegExp(pattern, 'gm'), '<img class="emoji_icon" src="' + path + '$1' + file + '"/>'));
  334. }
  335. }
  336. }
  337. }
  338. };
  339. function fn(option) {
  340. return this.each(function () {
  341. var $this = $(this);
  342. var data = $this.data('plugin_' + PLUGIN_NAME);
  343. var options = $.extend({}, DEFAULTS, $this.data(), typeof option === 'object' && option);
  344. if (!data) $this.data('plugin_' + PLUGIN_NAME, (data = new Plugin(this, options)));
  345. if (typeof option === 'string') data[option]();
  346. });
  347. }
  348. $.fn[PLUGIN_NAME] = fn;
  349. $.fn[PLUGIN_NAME].Constructor = Plugin;
  350. }(jQuery, window, document));