performance/memory optimizations

This commit is contained in:
Joffrey JAFFEUX 2017-07-19 09:57:23 +02:00
parent 2a0dcedb3d
commit 6a4d74d9f8

View File

@ -12,41 +12,30 @@ export const EMOJI_USAGE = "emojiUsage";
export const EMOJI_SCROLL_Y = "emojiScrollY"; export const EMOJI_SCROLL_Y = "emojiScrollY";
export const EMOJI_SELECTED_DIVERSITY = "emojiSelectedDiversity"; export const EMOJI_SELECTED_DIVERSITY = "emojiSelectedDiversity";
const PER_ROW = 11; const PER_ROW = 11;
const customEmojis = _.map(_.keys(extendedEmojiList()), function(code) {
return { code, src: emojiUrlFor(code) };
});
let $picker, $modal, $filter, $results, $list;
export default Ember.Component.extend({ export default Ember.Component.extend({
customEmojis: _.map(_.keys(extendedEmojiList()), function(code) {
return { code, src: emojiUrlFor(code) };
}),
$picker: Ember.computed("active", function() {
return this.$(".emoji-picker");
}),
$filter: Ember.computed("$picker", function() {
return this.get("$picker").find(".filter");
}),
$results: Ember.computed("$picker", function() {
return this.get("$picker").find(".results");
}),
$list: Ember.computed("$picker", function() {
return this.get("$picker").find(".list");
}),
willDestroyElement() { willDestroyElement() {
this._super(); this._super();
this._unbindEvents(); this._unbindEvents();
$picker = null;
$modal = null;
}, },
didInsertElement() { didInsertElement() {
this._super(); this._super();
$picker = this.$(".emoji-picker");
$modal = this.$(".emoji-picker-modal");
if (!keyValueStore.getObject(EMOJI_USAGE)) { if (!keyValueStore.getObject(EMOJI_USAGE)) {
keyValueStore.setObject({ key: EMOJI_USAGE, value: {} }); keyValueStore.setObject({ key: EMOJI_USAGE, value: {} });
} }
this.set("selectedDiversity", keyValueStore.getObject(EMOJI_SELECTED_DIVERSITY) || 1);
}, },
didUpdateAttrs() { didUpdateAttrs() {
@ -61,7 +50,7 @@ export default Ember.Component.extend({
@observes("filter") @observes("filter")
filterChanged() { filterChanged() {
this.get("$filter").find(".clear-filter").toggle(!_.isEmpty(this.get("filter"))); $filter.find(".clear-filter").toggle(!_.isEmpty(this.get("filter")));
Ember.run.debounce(this, this._filterEmojisList, 250); Ember.run.debounce(this, this._filterEmojisList, 250);
}, },
@ -69,12 +58,12 @@ export default Ember.Component.extend({
selectedDiversityChanged() { selectedDiversityChanged() {
keyValueStore.setObject({key: EMOJI_SELECTED_DIVERSITY, value: this.get("selectedDiversity")}); keyValueStore.setObject({key: EMOJI_SELECTED_DIVERSITY, value: this.get("selectedDiversity")});
$.each(this.get("$list").find(".emoji.diversity[src!='']"), (_, icon) => { $.each($list.find(".emoji.diversity[src!='']"), (_, icon) => {
this._updateIconSrc(icon); this._updateIconSrc(icon);
}); });
if(this.get("filter") !== "") { if(this.get("filter") !== "") {
$.each(this.get("$results").find(".emoji.diversity"), (_, icon) => { $.each($results.find(".emoji.diversity"), (_, icon) => {
this._updateIconSrc(icon); this._updateIconSrc(icon);
}); });
} }
@ -82,9 +71,9 @@ export default Ember.Component.extend({
@observes("recentEmojis") @observes("recentEmojis")
recentEmojisChanged() { recentEmojisChanged() {
const $recentSection = this.get("$list").find(".section[data-section='recent']"); const $recentSection = $list.find(".section[data-section='recent']");
const $recentSectionGroup = $recentSection.find(".section-group"); const $recentSectionGroup = $recentSection.find(".section-group");
const $recentCategory = this.get("$picker").find(".category-icon a[title='recent']").parent(); const $recentCategory = $picker.find(".category-icon a[title='recent']").parent();
if(_.isEmpty(this.get("recentEmojis"))) { if(_.isEmpty(this.get("recentEmojis"))) {
$recentCategory.hide(); $recentCategory.hide();
$recentSection.css("height", 0).hide(); $recentSection.css("height", 0).hide();
@ -99,22 +88,29 @@ export default Ember.Component.extend({
const model = { recentEmojis }; const model = { recentEmojis };
const template = recentTemplate(model); const template = recentTemplate(model);
$recentSectionGroup.html(template); $recentSectionGroup.html(template);
this._bindHover($recentSectionGroup.find("a")); this._bindHover($recentSectionGroup);
}, },
close() { close() {
this.get("$picker") $picker
.css({width: "", left: "", bottom: ""}) .css({width: "", left: "", bottom: ""})
.empty(); .empty();
this.$(".emoji-picker-modal").removeClass("fadeIn"); $modal.removeClass("fadeIn");
this._unbindEvents(); this._unbindEvents();
$filter, $results, $list = null;
}, },
show() { show() {
const model = { customEmojis: this.get("customEmojis") }; const template = pickerTemplate({ customEmojis });
const template = pickerTemplate(model); $picker.html(template);
this.get("$picker").html(template);
$filter = $picker.find(".filter");
$results = $picker.find(".results");
$list = $picker.find(".list");
this.set("selectedDiversity", keyValueStore.getObject(EMOJI_SELECTED_DIVERSITY) || 1);
this._bindEvents(); this._bindEvents();
@ -129,14 +125,14 @@ export default Ember.Component.extend({
_bindEvents() { _bindEvents() {
this._bindDiversityClick(); this._bindDiversityClick();
this._bindSectionsScroll(); this._bindSectionsScroll();
this._bindEmojiClick(); this._bindEmojiClick($list.find(".section-group"));
this._bindClearRecentEmojisGroup(); this._bindClearRecentEmojisGroup();
this._bindResizing(); this._bindResizing();
this._bindHover(); this._bindHover();
this._bindCategoryClick(); this._bindCategoryClick();
this._bindModalClick(); this._bindModalClick();
this._bindFilterInput(); this._bindFilterInput();
this._bindEscape(); // this._bindEscape();
}, },
_bindEscape() { _bindEscape() {
@ -149,29 +145,27 @@ export default Ember.Component.extend({
}, },
_bindModalClick() { _bindModalClick() {
this.$(".emoji-picker-modal").on("click", () => { $modal.on("click", () => {
this.set("active", false); this.set("active", false);
}); });
}, },
_unbindEvents() { _unbindEvents() {
this.$(window).off("resize"); this.$(window).off("resize");
this.$(".emoji-picker-modal").off("click"); $modal.off("click");
Ember.$("#reply-control").off("div-resized"); Ember.$("#reply-control").off("div-resized");
this.$().off("keydown"); // this.$().off("keydown");
}, },
_filterEmojisList() { _filterEmojisList() {
const $filter = this.get("$picker").find(".filter");
if (this.get("filter") === "") { if (this.get("filter") === "") {
$filter.find("input[name='filter']").val(""); $filter.find("input[name='filter']").val("");
this.get("$results").empty().hide(); $results.empty().hide();
this.get("$list").show(); $list.show();
} else { } else {
const regexp = new RegExp(this.get("filter"), "g"); const regexp = new RegExp(this.get("filter"), "g");
const filteredCodes = _.filter(emojis, code => regexp.test(code)).slice(0, 30); const filteredCodes = _.filter(emojis, code => regexp.test(code)).slice(0, 30);
this.get("$results").empty().html( $results.empty().html(
_.map(filteredCodes, (code) => { _.map(filteredCodes, (code) => {
const hasDiversity = isSkinTonableEmoji(code); const hasDiversity = isSkinTonableEmoji(code);
const diversity = hasDiversity ? "diversity" : ""; const diversity = hasDiversity ? "diversity" : "";
@ -181,14 +175,13 @@ export default Ember.Component.extend({
</a>`; </a>`;
}) })
).show(); ).show();
this._bindHover(this.get("$results").find("a")); this._bindHover($results);
this._bindEmojiClick(this.get("$results")); this._bindEmojiClick($results);
this.get("$list").hide(); $list.hide();
} }
}, },
_bindFilterInput() { _bindFilterInput() {
const $filter = this.get("$picker").find(".filter");
const $input = $filter.find("input"); const $input = $filter.find("input");
$input.on("input", (event) => { $input.on("input", (event) => {
@ -203,15 +196,14 @@ export default Ember.Component.extend({
}, },
_bindCategoryClick() { _bindCategoryClick() {
this.get("$picker").find(".category-icon").on("click", "a", (event) => { $picker.find(".category-icon").on("click", "a", (event) => {
this.set("filter", ""); this.set("filter", "");
this.get("$results").empty(); $results.empty();
this.get("$list").show(); $list.show();
const section = $(event.currentTarget).attr("title"); const section = $(event.currentTarget).attr("title");
const $section = this.get("$list").find(`.section[data-section="${section}"]`); const $section = $list.find(`.section[data-section="${section}"]`);
const scrollTop = this.get("$list").scrollTop() + const scrollTop = $list.scrollTop() + ($section.offset().top - $list.offset().top);
( $section.offset().top - this.get("$list").offset().top );
this._scrollTo(scrollTop); this._scrollTo(scrollTop);
return false; return false;
@ -220,17 +212,20 @@ export default Ember.Component.extend({
_bindHover(hoverables) { _bindHover(hoverables) {
const replaceInfoContent = (html) => { const replaceInfoContent = (html) => {
this.get("$picker").find(".footer .info").html(html || ""); $picker.find(".footer .info").html(html || "");
}; };
(hoverables || this.$(".section-group a")).hover(event => { (hoverables || this.$(".section-group")).on({
mouseover: (event) => {
const $a = $(event.currentTarget); const $a = $(event.currentTarget);
const code = this._codeWithDiversity($a.attr("title"), $a.find("img").hasClass("diversity")); const code = this._codeWithDiversity($a.attr("title"), $a.find("img").hasClass("diversity"));
const html = `<img src="${emojiUrlFor(code)}" class="emoji"> <span>:${code}:<span>`; const html = `<img src="${emojiUrlFor(code)}" class="emoji"> <span>:${code}:<span>`;
replaceInfoContent(html); replaceInfoContent(html);
}, },
() => replaceInfoContent() mouseleave: () => {
); replaceInfoContent();
}
}, "a")
}, },
_bindResizing() { _bindResizing() {
@ -244,7 +239,7 @@ export default Ember.Component.extend({
}, },
_bindClearRecentEmojisGroup() { _bindClearRecentEmojisGroup() {
const $recent = this.get("$picker").find(".section[data-section='recent'] .clear-recent"); const $recent = $picker.find(".section[data-section='recent'] .clear-recent");
$recent.on("click", () => { $recent.on("click", () => {
keyValueStore.setObject({ key: EMOJI_USAGE, value: {} }); keyValueStore.setObject({ key: EMOJI_USAGE, value: {} });
this.set("recentEmojis", {}); this.set("recentEmojis", {});
@ -253,8 +248,7 @@ export default Ember.Component.extend({
}); });
}, },
_bindEmojiClick(emojisContainer) { _bindEmojiClick($emojisContainer) {
const $emojisContainer = emojisContainer || this.get("$list").find(".section-group");
$emojisContainer.off("click").on("click", "a", e => { $emojisContainer.off("click").on("click", "a", e => {
const $icon = $(e.currentTarget); const $icon = $(e.currentTarget);
const title = $icon.attr("title"); const title = $icon.attr("title");
@ -271,14 +265,14 @@ export default Ember.Component.extend({
}, },
_bindSectionsScroll() { _bindSectionsScroll() {
this.get("$list").on("scroll", () => { $list.on("scroll", () => {
Ember.run.debounce(this, this._checkVisibleSection, 150); Ember.run.debounce(this, this._checkVisibleSection, 150);
Ember.run.debounce(this, this._storeScrollPosition, 50); Ember.run.debounce(this, this._storeScrollPosition, 50);
}); });
}, },
_checkVisibleSection() { _checkVisibleSection() {
const $sections = this.get("$list").find(".section"); const $sections = $list.find(".section");
const sections = []; const sections = [];
let cumulatedHeight = 0; let cumulatedHeight = 0;
@ -289,11 +283,11 @@ export default Ember.Component.extend({
}); });
let selectedSection; let selectedSection;
const currentScrollTop = this.get("$list").scrollTop(); const currentScrollTop = $list.scrollTop();
if (!_.isEmpty(this.get("recentEmojis")) && currentScrollTop === 0) { if (!_.isEmpty(this.get("recentEmojis")) && currentScrollTop === 0) {
selectedSection = _.first(sections); selectedSection = _.first(sections);
} else if (!_.isEmpty(this.get("customEmojis")) && } else if (!_.isEmpty(customEmojis) &&
currentScrollTop === this.get("$list")[0].scrollHeight - this.get("$list").innerHeight()) currentScrollTop === $list[0].scrollHeight - $list.innerHeight())
{ {
selectedSection = _.last(sections); selectedSection = _.last(sections);
} else { } else {
@ -303,8 +297,8 @@ export default Ember.Component.extend({
} }
if(selectedSection) { if(selectedSection) {
this.get("$picker").find(".category-icon").removeClass("current"); $picker.find(".category-icon").removeClass("current");
this.get("$picker").find(`.category-icon a[title='${selectedSection.$section.data("section")}']`) $picker.find(`.category-icon a[title='${selectedSection.$section.data("section")}']`)
.parent() .parent()
.addClass("current"); .addClass("current");
@ -325,7 +319,7 @@ export default Ember.Component.extend({
}, },
_bindDiversityClick() { _bindDiversityClick() {
const $diversityScales = this.get("$picker").find(".diversity-picker .diversity-scale"); const $diversityScales = $picker.find(".diversity-picker .diversity-scale");
$diversityScales.on("click", (event) => { $diversityScales.on("click", (event) => {
const $selectedDiversity = $(event.currentTarget); const $selectedDiversity = $(event.currentTarget);
$diversityScales.removeClass("selected"); $diversityScales.removeClass("selected");
@ -336,7 +330,7 @@ export default Ember.Component.extend({
}, },
_setDiversity() { _setDiversity() {
this.get("$picker") $picker
.find(`.diversity-picker .diversity-scale[data-level="${this.get("selectedDiversity")}"]`) .find(`.diversity-picker .diversity-scale[data-level="${this.get("selectedDiversity")}"]`)
.addClass("selected"); .addClass("selected");
}, },
@ -351,11 +345,12 @@ export default Ember.Component.extend({
let isLargePreview = this.$(window).height() - let isLargePreview = this.$(window).height() -
Ember.$(".d-header").height() - Ember.$(".d-header").height() -
Ember.$("#reply-control").height() < Ember.$("#reply-control").height() <
this.get("$picker").height() + 16; $picker.height() + 16;
if(this._isSmallViewport()) { if(this._isSmallViewport()) {
this.$(".emoji-picker-modal").addClass("fadeIn"); $modal.addClass("fadeIn");
this.get("$picker").css({
$picker.css({
width: this.site.isMobileDevice ? this.$(window).width() - 10 : 340, width: this.site.isMobileDevice ? this.$(window).width() - 10 : 340,
marginLeft: this.site.isMobileDevice ? -(this.$(window).width() - 10)/2 : -170, marginLeft: this.site.isMobileDevice ? -(this.$(window).width() - 10)/2 : -170,
marginTop: -150, marginTop: -150,
@ -363,9 +358,10 @@ export default Ember.Component.extend({
top: "50%" top: "50%"
}); });
} else { } else {
this.$(".emoji-picker-modal").removeClass("fadeIn"); $modal.removeClass("fadeIn");
let cssAttributes = { width: 400, marginLeft: "", marginTop: "", left: "", top: "" }; let cssAttributes = { width: 400, marginLeft: "", marginTop: "", left: "", top: "" };
if(isLargePreview) { if(isLargePreview) {
cssAttributes.left = (Ember.$("#reply-control").width() - Ember.$(".d-editor").width() ) / 2 + Ember.$(".d-editor-preview-wrapper").position().left; cssAttributes.left = (Ember.$("#reply-control").width() - Ember.$(".d-editor").width() ) / 2 + Ember.$(".d-editor-preview-wrapper").position().left;
cssAttributes.bottom = 32; cssAttributes.bottom = 32;
@ -374,14 +370,14 @@ export default Ember.Component.extend({
cssAttributes.bottom = Ember.$("#reply-control").height() - 48; cssAttributes.bottom = Ember.$("#reply-control").height() - 48;
} }
this.get("$picker").css(cssAttributes); $picker.css(cssAttributes);
} }
const infoMaxWidth = this.get("$picker").width() - const infoMaxWidth = $picker.width() -
this.get("$picker").find(".categories-column").width() - $picker.find(".categories-column").width() -
this.get("$picker").find(".diversity-picker").width() - $picker.find(".diversity-picker").width() -
32; 32;
this.get("$picker").find(".info").css("max-width", infoMaxWidth); $picker.find(".info").css("max-width", infoMaxWidth);
}, },
_loadVisibleEmojis($visibleEmojis) { _loadVisibleEmojis($visibleEmojis) {
@ -403,7 +399,7 @@ export default Ember.Component.extend({
_storeScrollPosition() { _storeScrollPosition() {
keyValueStore.setObject({ keyValueStore.setObject({
key: EMOJI_SCROLL_Y, key: EMOJI_SCROLL_Y,
value: this.get("$list").scrollTop() value: $list.scrollTop()
}); });
}, },
@ -432,11 +428,11 @@ export default Ember.Component.extend({
_scrollTo(y) { _scrollTo(y) {
const yPosition = _.isUndefined(y) ? keyValueStore.getObject(EMOJI_SCROLL_Y) : y; const yPosition = _.isUndefined(y) ? keyValueStore.getObject(EMOJI_SCROLL_Y) : y;
this.get("$list").scrollTop(yPosition); $list.scrollTop(yPosition);
// if we dont actually scroll we need to force it // if we dont actually scroll we need to force it
if(yPosition === 0) { if(yPosition === 0) {
this.get("$list").scroll(); $list.scroll();
} }
}, },