about summary refs log tree commit diff
path: root/app/javascript/mastodon/features/emoji/emoji_mart_search_light.js
diff options
context:
space:
mode:
Diffstat (limited to 'app/javascript/mastodon/features/emoji/emoji_mart_search_light.js')
-rw-r--r--app/javascript/mastodon/features/emoji/emoji_mart_search_light.js154
1 files changed, 154 insertions, 0 deletions
diff --git a/app/javascript/mastodon/features/emoji/emoji_mart_search_light.js b/app/javascript/mastodon/features/emoji/emoji_mart_search_light.js
new file mode 100644
index 000000000..5da8de1cf
--- /dev/null
+++ b/app/javascript/mastodon/features/emoji/emoji_mart_search_light.js
@@ -0,0 +1,154 @@
+// This code is largely borrowed from:
+// https://github.com/missive/emoji-mart/blob/bbd4fbe/src/utils/emoji-index.js
+
+import data from './emoji_mart_data_light';
+import { getData, getSanitizedData, intersect } from './emoji_utils';
+
+let index = {};
+let emojisList = {};
+let emoticonsList = {};
+let previousInclude = [];
+let previousExclude = [];
+
+for (let emoji in data.emojis) {
+  let emojiData = data.emojis[emoji],
+    { short_names, emoticons } = emojiData,
+    id = short_names[0];
+
+  for (let emoticon of (emoticons || [])) {
+    if (!emoticonsList[emoticon]) {
+      emoticonsList[emoticon] = id;
+    }
+  }
+
+  emojisList[id] = getSanitizedData(id);
+}
+
+function search(value, { emojisToShowFilter, maxResults, include, exclude, custom = [] } = {}) {
+  maxResults = maxResults || 75;
+  include = include || [];
+  exclude = exclude || [];
+
+  if (custom.length) {
+    for (const emoji of custom) {
+      data.emojis[emoji.id] = getData(emoji);
+      emojisList[emoji.id] = getSanitizedData(emoji);
+    }
+
+    data.categories.push({
+      name: 'Custom',
+      emojis: custom.map(emoji => emoji.id),
+    });
+  }
+
+  let results = null;
+  let pool = data.emojis;
+
+  if (value.length) {
+    if (value === '-' || value === '-1') {
+      return [emojisList['-1']];
+    }
+
+    let values = value.toLowerCase().split(/[\s|,|\-|_]+/);
+
+    if (values.length > 2) {
+      values = [values[0], values[1]];
+    }
+
+    if (include.length || exclude.length) {
+      pool = {};
+
+      if (previousInclude !== include.sort().join(',') || previousExclude !== exclude.sort().join(',')) {
+        previousInclude = include.sort().join(',');
+        previousExclude = exclude.sort().join(',');
+        index = {};
+      }
+
+      for (let category of data.categories) {
+        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) {
+          continue;
+        }
+
+        for (let emojiId of category.emojis) {
+          pool[emojiId] = data.emojis[emojiId];
+        }
+      }
+    } else if (previousInclude.length || previousExclude.length) {
+      index = {};
+    }
+
+    let allResults = values.map((value) => {
+      let aPool = pool;
+      let aIndex = index;
+      let length = 0;
+
+      for (let char of value.split('')) {
+        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;
+    }).filter(a => a);
+
+    if (allResults.length > 1) {
+      results = intersect(...allResults);
+    } else if (allResults.length) {
+      results = allResults[0];
+    } else {
+      results = [];
+    }
+  }
+
+  if (results) {
+    if (emojisToShowFilter) {
+      results = results.filter((result) => emojisToShowFilter(data.emojis[result.id].unified));
+    }
+
+    if (results && results.length > maxResults) {
+      results = results.slice(0, maxResults);
+    }
+  }
+
+  return results;
+}
+
+export { search };