186 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			186 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| // This code is largely borrowed from:
 | |
| // https://github.com/missive/emoji-mart/blob/5f2ffcc/src/utils/emoji-index.js
 | |
| 
 | |
| import data from './emoji_mart_data_light';
 | |
| import { getData, getSanitizedData, uniq, intersect } from './emoji_utils';
 | |
| 
 | |
| let originalPool = {};
 | |
| let index = {};
 | |
| let emojisList = {};
 | |
| let emoticonsList = {};
 | |
| let customEmojisList = [];
 | |
| 
 | |
| for (let emoji in data.emojis) {
 | |
|   let emojiData = data.emojis[emoji];
 | |
|   let { short_names, emoticons } = emojiData;
 | |
|   let id = short_names[0];
 | |
| 
 | |
|   if (emoticons) {
 | |
|     emoticons.forEach(emoticon => {
 | |
|       if (emoticonsList[emoticon]) {
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|       emoticonsList[emoticon] = id;
 | |
|     });
 | |
|   }
 | |
| 
 | |
|   emojisList[id] = getSanitizedData(id);
 | |
|   originalPool[id] = emojiData;
 | |
| }
 | |
| 
 | |
| function clearCustomEmojis(pool) {
 | |
|   customEmojisList.forEach((emoji) => {
 | |
|     let emojiId = emoji.id || emoji.short_names[0];
 | |
| 
 | |
|     delete pool[emojiId];
 | |
|     delete emojisList[emojiId];
 | |
|   });
 | |
| }
 | |
| 
 | |
| function addCustomToPool(custom, pool) {
 | |
|   if (customEmojisList.length) clearCustomEmojis(pool);
 | |
| 
 | |
|   custom.forEach((emoji) => {
 | |
|     let emojiId = emoji.id || emoji.short_names[0];
 | |
| 
 | |
|     if (emojiId && !pool[emojiId]) {
 | |
|       pool[emojiId] = getData(emoji);
 | |
|       emojisList[emojiId] = getSanitizedData(emoji);
 | |
|     }
 | |
|   });
 | |
| 
 | |
|   customEmojisList = custom;
 | |
|   index = {};
 | |
| }
 | |
| 
 | |
| function search(value, { emojisToShowFilter, maxResults, include, exclude, custom } = {}) {
 | |
|   if (custom !== undefined) {
 | |
|     if (customEmojisList !== custom)
 | |
|       addCustomToPool(custom, originalPool);
 | |
|   } else {
 | |
|     custom = [];
 | |
|   }
 | |
| 
 | |
|   maxResults = maxResults || 75;
 | |
|   include = include || [];
 | |
|   exclude = exclude || [];
 | |
| 
 | |
|   let results = null,
 | |
|     pool = originalPool;
 | |
| 
 | |
|   if (value.length) {
 | |
|     if (value === '-' || value === '-1') {
 | |
|       return [emojisList['-1']];
 | |
|     }
 | |
| 
 | |
|     let values = value.toLowerCase().split(/[\s|,\-_]+/),
 | |
|       allResults = [];
 | |
| 
 | |
|     if (values.length > 2) {
 | |
|       values = [values[0], values[1]];
 | |
|     }
 | |
| 
 | |
|     if (include.length || exclude.length) {
 | |
|       pool = {};
 | |
| 
 | |
|       data.categories.forEach(category => {
 | |
|         let isIncluded = include && include.length ? include.indexOf(category.name.toLowerCase()) > -1 : true;
 | |
|         let isExcluded = exclude && exclude.length ? exclude.indexOf(category.name.toLowerCase()) > -1 : false;
 | |
|         if (!isIncluded || isExcluded) {
 | |
|           return;
 | |
|         }
 | |
| 
 | |
|         category.emojis.forEach(emojiId => pool[emojiId] = data.emojis[emojiId]);
 | |
|       });
 | |
| 
 | |
|       if (custom.length) {
 | |
|         let customIsIncluded = include && include.length ? include.indexOf('custom') > -1 : true;
 | |
|         let customIsExcluded = exclude && exclude.length ? exclude.indexOf('custom') > -1 : false;
 | |
|         if (customIsIncluded && !customIsExcluded) {
 | |
|           addCustomToPool(custom, pool);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     const searchValue = (value) => {
 | |
|       let aPool = pool,
 | |
|         aIndex = index,
 | |
|         length = 0;
 | |
| 
 | |
|       for (let charIndex = 0; charIndex < value.length; charIndex++) {
 | |
|         const char = value[charIndex];
 | |
|         length++;
 | |
| 
 | |
|         aIndex[char] = aIndex[char] || {};
 | |
|         aIndex = aIndex[char];
 | |
| 
 | |
|         if (!aIndex.results) {
 | |
|           let scores = {};
 | |
| 
 | |
|           aIndex.results = [];
 | |
|           aIndex.pool = {};
 | |
| 
 | |
|           for (let id in aPool) {
 | |
|             let emoji = aPool[id],
 | |
|               { search } = emoji,
 | |
|               sub = value.substr(0, length),
 | |
|               subIndex = search.indexOf(sub);
 | |
| 
 | |
|             if (subIndex !== -1) {
 | |
|               let score = subIndex + 1;
 | |
|               if (sub === id) score = 0;
 | |
| 
 | |
|               aIndex.results.push(emojisList[id]);
 | |
|               aIndex.pool[id] = emoji;
 | |
| 
 | |
|               scores[id] = score;
 | |
|             }
 | |
|           }
 | |
| 
 | |
|           aIndex.results.sort((a, b) => {
 | |
|             let aScore = scores[a.id],
 | |
|               bScore = scores[b.id];
 | |
| 
 | |
|             return aScore - bScore;
 | |
|           });
 | |
|         }
 | |
| 
 | |
|         aPool = aIndex.pool;
 | |
|       }
 | |
| 
 | |
|       return aIndex.results;
 | |
|     };
 | |
| 
 | |
|     if (values.length > 1) {
 | |
|       results = searchValue(value);
 | |
|     } else {
 | |
|       results = [];
 | |
|     }
 | |
| 
 | |
|     allResults = values.map(searchValue).filter(a => a);
 | |
| 
 | |
|     if (allResults.length > 1) {
 | |
|       allResults = intersect.apply(null, allResults);
 | |
|     } else if (allResults.length) {
 | |
|       allResults = allResults[0];
 | |
|     }
 | |
| 
 | |
|     results = uniq(results.concat(allResults));
 | |
|   }
 | |
| 
 | |
|   if (results) {
 | |
|     if (emojisToShowFilter) {
 | |
|       results = results.filter((result) => emojisToShowFilter(data.emojis[result.id]));
 | |
|     }
 | |
| 
 | |
|     if (results && results.length > maxResults) {
 | |
|       results = results.slice(0, maxResults);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return results;
 | |
| }
 | |
| 
 | |
| export { search };
 |