var EMOJI_BAR = (function() { var dom = document.createElement("div") ,overlay = document.createElement("div") ,emojisDom = document.createElement("div") ,unicodeEmojis = document.createElement("ul") ,customEmojis = document.createElement("ul") ,searchBar = document.createElement("input") ,emojiCache = { unicode: {}, custom: {}} ,emojiDetail = document.createElement("div") ,emojiDetailImg = document.createElement("span") ,emojiDetailName = document.createElement("span") /** @type {function((string|null))|undefined} */ ,emojiSelectedHandler /** @type {function():boolean} */ ,isSupported = function() { return ("searchEmojis" in window); } ,makeHeader = function(imgSrc) { var img = document.createElement("img") ,dom = document.createElement("div"); img.src = imgSrc; dom.appendChild(img); dom.className = R.klass.emojibar.header; return dom; } /** @type {function(string, Element):{dom:Element,visible:boolean}} */ ,wrapEmojiLi = function(emojiName, emojiDom) { var dom = document.createElement("li"); dom.appendChild(emojiDom); dom.className = R.klass.emojibar.item; dom.id = "emojibar-" +emojiName; return { visible: false ,dom: dom }; } /** @type {function(string, *):{dom:Element,visible:boolean}} */ ,makeUnicodeEmojiLi = function(emojiName, emoji) { var domEmoji = window['makeEmoji'](emoji) ,domParent = document.createElement("span"); domParent.appendChild(domEmoji); domParent.className = R.klass.emoji.medium; return wrapEmojiLi(emojiName, domParent); } /** @type {function(string, string):{dom:Element,visible:boolean}} */ ,makeCustomEmoji = function(emojiName, emojiSrc) { var domEmoji = document.createElement("span") ,domParent = document.createElement("span"); domEmoji.className = R.klass.emoji.emoji +' ' +R.klass.emoji.custom; domEmoji.style.backgroundImage = 'url("' +emojiSrc +'")'; domParent.appendChild(domEmoji); domParent.className = R.klass.emoji.medium; return wrapEmojiLi(emojiName, domParent); } /** @type {function(Object., Object.):Array.<{name:string, pos:number, count:number}>} */ ,sortEmojis = function(emojiObj, favoriteEmojis) { var names = [] ,index = 0; for (var i in emojiObj) names.push({ name: i, pos: index, count: favoriteEmojis[i] || 0 }); names = names.sort(function(a, b) { var diff = b.count -a.count; if (diff) return diff; return a.pos -b.pos; }); return names; } /** @type function(string=):number */ ,search = function(queryString) { var emojiCount = 0 ,toRemove = [] /** @type {Array.<{name:string, pos:number, count:number}>} */ ,sortedEmojiNames; queryString = queryString === undefined ? searchBar.value : queryString; // Service emojis if (isSupported()) { /** @type {Object.} */ var foundEmojis = window['searchEmojis'](queryString); sortedEmojiNames = sortEmojis(foundEmojis, SLACK.context.self.prefs.favoriteEmojis); for (var i in emojiCache.unicode) { if (emojiCache.unicode[i].visible) { // We remove every item to reorder them (add them in order) emojiCache.unicode[i].visible = false; unicodeEmojis.removeChild(emojiCache.unicode[i].dom); } } for (var i =0, nbEmojis = sortedEmojiNames.length; i < nbEmojis; i++) { var emojiName = sortedEmojiNames[i].name ,e = emojiCache.unicode[emojiName]; if (!e) e = emojiCache.unicode[emojiName] = makeUnicodeEmojiLi(emojiName, foundEmojis[emojiName]); if (!e.visible) { e.visible = true; unicodeEmojis.appendChild(e.dom); } emojiCount++; } } // Custom emojis for (var i in emojiCache.custom) { if (emojiCache.custom[i].visible) { emojiCache.custom[i].visible = false; customEmojis.removeChild(emojiCache.custom[i].dom); } } sortedEmojiNames = sortEmojis(SLACK.context.emojis.data, SLACK.context.self.prefs.favoriteEmojis); for (var i =0, nbEmojis = sortedEmojiNames.length; i < nbEmojis; i++) { var emojiName = sortedEmojiNames[i].name; if ((queryString === '' || emojiName.substr(0, queryString.length) === queryString) && SLACK.context.emojis.data[emojiName].substr(0, 6) !== 'alias:') { var e = emojiCache.custom[emojiName]; if (!e) e = emojiCache.custom[emojiName] = makeCustomEmoji(emojiName, SLACK.context.emojis.data[emojiName]); if (!e.visible) { e.visible = true; customEmojis.appendChild(e.dom); } emojiCount++; } } return emojiCount; } /** @type function(Element, function((string|null))=):boolean */ ,spawn = function(domParent, handler) { if (isSupported()) { emojiSelectedHandler = handler; domParent.appendChild(overlay); domParent.appendChild(dom); searchBar.value = ""; search(); searchBar.focus(); return true; } return false; } /** @type {function():boolean} */ ,doClose = function() { if (dom.parentElement) { dom.parentElement.removeChild(overlay); dom.parentElement.removeChild(dom); return true; } return false; } /** @type {function():boolean} */ ,close = function() { var closed = doClose(); if (!closed) return false; if (emojiSelectedHandler) emojiSelectedHandler(null); return true; } ,onEmojiSelected = function(emojiName) { if (doClose() && emojiSelectedHandler) emojiSelectedHandler(emojiName); } ; overlay.addEventListener("click", function(e) { var bounds = dom.getBoundingClientRect(); if (e.screenY < bounds.top || e.screenY > bounds.bottom || e.screenX < bounds.left || e.screenX > bounds.right) close(); }); overlay.className = R.klass.emojibar.overlay; dom.className = R.klass.emojibar.container; emojisDom.className = R.klass.emojibar.emojis; emojiDetail.className = R.klass.emojibar.detail.container; emojiDetailImg.className = R.klass.emojibar.detail.img; emojiDetailName.className = R.klass.emojibar.detail.name; unicodeEmojis.className = customEmojis.className = R.klass.emojibar.list; searchBar.className = R.klass.emojibar.search; emojiDetail.appendChild(emojiDetailImg); emojiDetail.appendChild(emojiDetailName); emojisDom.appendChild(makeHeader(window['emojiProviderHeader'])); emojisDom.appendChild(unicodeEmojis); emojisDom.appendChild(makeHeader("emojicustom.png")); emojisDom.appendChild(customEmojis); dom.appendChild(emojisDom); dom.appendChild(emojiDetail); dom.appendChild(searchBar); searchBar.addEventListener("keyup", function() { search(); }); var makeDelegate = function(e, cb) { var target = e.target; while (target !== dom && target && target.nodeName !== "LI") target = target.parentElement; if (target && target.nodeName === "LI" && target.id && target.id.substr(0, "emojibar-".length) === "emojibar-") { var emojiId = target.id.substr("emojibar-".length); return cb(emojiId); } cb(null); }; dom.addEventListener("mousemove", function(e) { makeDelegate(e, function(emoji) { var emojiCached = emoji ? (emojiCache.unicode[emoji] || emojiCache.custom[emoji]) : null; if (emojiCached) { emojiDetailImg.innerHTML = emojiCached.dom.outerHTML; emojiDetailName.textContent = ':' +emoji +':'; } else { emojiDetailImg.textContent = ""; emojiDetailName.textContent = ""; } }); }); dom.addEventListener("click", function(e) { makeDelegate(e, function(emoji) { if (emoji) onEmojiSelected(emoji); }); }); return { isSupported: isSupported ,spawn: spawn ,search: search ,close: close }; })();