Skip to content

Commit

Permalink
[IMPROVE] Emoji picker for large amount of custom emojis (#27745)
Browse files Browse the repository at this point in the history
  • Loading branch information
sampaiodiego committed Jan 24, 2023
1 parent 712e4ad commit 2f8d5e1
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 48 deletions.
19 changes: 6 additions & 13 deletions apps/meteor/app/emoji-custom/client/lib/emojiCustom.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,18 @@ import { isSetNotNull } from './function-isSet';
import { RoomManager } from '../../../ui-utils/client';
import { emoji, EmojiPicker } from '../../../emoji/client';
import { CachedCollectionManager } from '../../../ui-cached-collection/client';
import { APIClient } from '../../../utils/client';
import { APIClient, getURL } from '../../../utils/client';

export const getEmojiUrlFromName = function (name, extension) {
Session.get;
if (name == null) {
return;
}

const key = `emoji_random_${name}`;

let random = 0;
if (isSetNotNull(() => Session.keys[key])) {
random = Session.keys[key];
}
const random = isSetNotNull(() => Session.keys[key]) ? Session.keys[key] : 0;

if (name == null) {
return;
}
const path = __meteor_runtime_config__.ROOT_URL_PATH_PREFIX || '';
return `${path}/emoji-custom/${encodeURIComponent(name)}.${extension}?_dc=${random}`;
return getURL(`/emoji-custom/${encodeURIComponent(name)}.${extension}?_dc=${random}`);
};

export const deleteEmojiCustom = function (emojiData) {
Expand Down Expand Up @@ -200,8 +195,6 @@ Meteor.startup(() =>
};
}
}

EmojiPicker.updateRecent('rocket');
} catch (e) {
console.error('Error getting custom emoji', e);
}
Expand Down
29 changes: 10 additions & 19 deletions apps/meteor/app/emoji-custom/server/startup/emoji-custom.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,36 +82,27 @@ Meteor.startup(function () {
return;
}

let fileUploadDate = undefined;
if (file.uploadDate != null) {
fileUploadDate = file.uploadDate.toUTCString();
}
const fileUploadDate = file.uploadDate != null ? file.uploadDate.toUTCString() : undefined;

const reqModifiedHeader = req.headers['if-modified-since'];
if (reqModifiedHeader != null) {
if (reqModifiedHeader === fileUploadDate) {
res.setHeader('Last-Modified', reqModifiedHeader);
res.writeHead(304);
res.end();
return;
}
if (reqModifiedHeader != null && reqModifiedHeader === fileUploadDate) {
res.setHeader('Last-Modified', reqModifiedHeader);
res.writeHead(304);
res.end();
return;
}

res.setHeader('Cache-Control', 'public, max-age=0');
res.setHeader('Expires', '-1');
if (fileUploadDate != null) {
res.setHeader('Last-Modified', fileUploadDate);
} else {
res.setHeader('Last-Modified', new Date().toUTCString());
}
res.setHeader('Cache-Control', 'public, max-age=31536000');
res.setHeader('Last-Modified', fileUploadDate || new Date().toUTCString());
res.setHeader('Content-Length', file.length);

if (/^svg$/i.test(params.emoji.split('.').pop())) {
res.setHeader('Content-Type', 'image/svg+xml');
} else if (/^png$/i.test(params.emoji.split('.').pop())) {
res.setHeader('Content-Type', 'image/png');
} else {
res.setHeader('Content-Type', 'image/jpeg');
}
res.setHeader('Content-Length', file.length);

file.readStream.pipe(res);
}),
Expand Down
66 changes: 53 additions & 13 deletions apps/meteor/app/emoji/client/emojiPicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,46 +17,66 @@ const emojiListByCategory = new ReactiveDict('emojiList');
const getEmojiElement = (emoji, image) =>
image && `<li class="emoji-${emoji} emoji-picker-item" data-emoji="${emoji}" title="${emoji}">${image}</li>`;

const createEmojiList = (category, actualTone) => {
// used as a function so `t` can use the user's language correctly when called
const loadMoreLink = () => `<li class="emoji-picker-load-more"><a href="#load-more">${t('Load_more')}</a></li>`;

let customItems = 90;

const createEmojiList = (category, actualTone, limit = null) => {
const html =
Object.values(emoji.packages)
.map((emojiPackage) => {
if (!emojiPackage.emojisByCategory || !emojiPackage.emojisByCategory[category]) {
return;
}

return emojiPackage.emojisByCategory[category]
.map((current) => {
const tone = actualTone > 0 && emojiPackage.toneList.hasOwnProperty(current) ? `_tone${actualTone}` : '';
return getEmojiElement(current, emojiPackage.renderPicker(`:${current}${tone}:`));
})
.join('');
const result = [];

const total = emojiPackage.emojisByCategory[category].length;

const listTotal = limit ? Math.min(limit, total) : total;

for (let i = 0; i < listTotal; i++) {
const current = emojiPackage.emojisByCategory[category][i];

const tone = actualTone > 0 && emojiPackage.toneList.hasOwnProperty(current) ? `_tone${actualTone}` : '';
result.push(getEmojiElement(current, emojiPackage.renderPicker(`:${current}${tone}:`)));
}

if (limit > 0 && total > limit) {
result.push(loadMoreLink());
}

return result.join('');
})
.join('') || `<li>${t('No_emojis_found')}</li>`;

return html;
};

export function updateRecentEmoji(category) {
emojiListByCategory.set(category, createEmojiList(category));
emojiListByCategory.set(category, createEmojiList(category, null, category === 'rocket' ? customItems : null));
}

const createPickerEmojis = (instance) => {
const categories = instance.categoriesList;
const actualTone = instance.tone;

categories.forEach((category) => emojiListByCategory.set(category.key, createEmojiList(category.key, actualTone)));
categories.forEach((category) =>
emojiListByCategory.set(category.key, createEmojiList(category.key, actualTone, category.key === 'rocket' ? customItems : null)),
);
};

function getEmojisBySearchTerm(searchTerm) {
function getEmojisBySearchTerm(searchTerm, limit) {
let html = '<ul class="emoji-list">';
const t = Template.instance();
const actualTone = t.tone;
const actualTone = Template.instance().tone;

EmojiPicker.currentCategory.set('');

const searchRegExp = new RegExp(escapeRegExp(searchTerm.replace(/:/g, '')), 'i');

let totalFound = 0;

for (let current in emoji.list) {
if (!emoji.list.hasOwnProperty(current)) {
continue;
Expand Down Expand Up @@ -89,8 +109,14 @@ function getEmojisBySearchTerm(searchTerm) {
if (emojiFound) {
const image = emoji.packages[emojiPackage].renderPicker(`:${current}${tone}:`);
html += getEmojiElement(current, image);
totalFound++;
}
}

if (totalFound >= limit) {
html += loadMoreLink();
break;
}
}
html += '</ul>';

Expand All @@ -116,7 +142,7 @@ Template.emojiPicker.helpers({
return Template.instance().currentSearchTerm.get().length > 0;
},
searchResults() {
return getEmojisBySearchTerm(Template.instance().currentSearchTerm.get());
return getEmojisBySearchTerm(Template.instance().currentSearchTerm.get(), Template.instance().searchTermItems.get());
},
emojiList(category) {
return emojiListByCategory.get(category);
Expand Down Expand Up @@ -190,6 +216,18 @@ Template.emojiPicker.events({

instance.$('.tone-selector').toggleClass('show');
},
'click .emoji-picker-load-more > a'(event, instance) {
event.stopPropagation();
event.preventDefault();

if (instance.currentSearchTerm.get().length > 0) {
instance.searchTermItems.set(instance.searchTermItems.get() + 90);
return;
}

customItems += 90;
emojiListByCategory.set('rocket', createEmojiList('rocket', 0, customItems));
},
'click .tone-selector .tone'(event, instance) {
event.stopPropagation();
event.preventDefault();
Expand Down Expand Up @@ -241,6 +279,7 @@ Template.emojiPicker.events({
input.val('');
}
instance.currentSearchTerm.set('');
instance.searchTermItems.set(90);

EmojiPicker.pickEmoji(_emoji + tone);
},
Expand All @@ -266,6 +305,7 @@ Template.emojiPicker.onCreated(function () {
const recent = EmojiPicker.getRecent();

this.currentSearchTerm = new ReactiveVar('');
this.searchTermItems = new ReactiveVar(90);

this.categoriesList = [];
for (const emojiPackage in emoji.packages) {
Expand Down
5 changes: 2 additions & 3 deletions apps/meteor/app/emoji/client/lib/EmojiPicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { ReactiveVar } from 'meteor/reactive-var';
import { Tracker } from 'meteor/tracker';

import { emoji } from '../../lib/rocketchat';
import { updateRecentEmoji } from '../emojiPicker';

let updatePositions = true;

Expand Down Expand Up @@ -153,9 +154,7 @@ export const EmojiPicker = {
this.recent.splice(pos, 1);
Meteor._localStorage.setItem('emoji.recent', this.recent);
},
async updateRecent(category) {
const emojiPickerImport = await import('../emojiPicker');
const { updateRecentEmoji } = emojiPickerImport;
updateRecent(category) {
updateRecentEmoji(category);
},
calculateCategoryPositions() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@
}
}

& li.emoji-picker-load-more {
text-align: center;
}

&.visible {
display: block;
}
Expand Down

0 comments on commit 2f8d5e1

Please sign in to comment.