mirror of
https://github.com/discourse/discourse.git
synced 2024-11-25 09:42:07 +08:00
FIX: allows custom groups updates to be reflected without recompilation (#9421)
This commit is contained in:
parent
f07c4a781c
commit
d9db0e6691
|
@ -1,4 +1,5 @@
|
||||||
import { inject as service } from "@ember/service";
|
import { inject as service } from "@ember/service";
|
||||||
|
import { schedule } from "@ember/runloop";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import { on, observes } from "discourse-common/utils/decorators";
|
import { on, observes } from "discourse-common/utils/decorators";
|
||||||
import { findRawTemplate } from "discourse/lib/raw-templates";
|
import { findRawTemplate } from "discourse/lib/raw-templates";
|
||||||
|
@ -16,23 +17,16 @@ const { run } = Ember;
|
||||||
const PER_ROW = 11;
|
const PER_ROW = 11;
|
||||||
function customEmojis() {
|
function customEmojis() {
|
||||||
const list = extendedEmojiList();
|
const list = extendedEmojiList();
|
||||||
const emojis = Object.keys(list)
|
const groups = [];
|
||||||
.map(code => {
|
Object.keys(list).forEach(code => {
|
||||||
const { group } = list[code];
|
const emoji = list[code];
|
||||||
return {
|
groups[emoji.group] = groups[emoji.group] || [];
|
||||||
|
groups[emoji.group].push({
|
||||||
code,
|
code,
|
||||||
src: emojiUrlFor(code),
|
src: emojiUrlFor(code)
|
||||||
group,
|
});
|
||||||
key: `emoji_picker.${group || "default"}`
|
});
|
||||||
};
|
return groups;
|
||||||
})
|
|
||||||
.reduce((acc, curr) => {
|
|
||||||
if (!acc[curr.group]) acc[curr.group] = [];
|
|
||||||
acc[curr.group].push(curr);
|
|
||||||
return acc;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
return Object.values(emojis);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
|
@ -42,9 +36,8 @@ export default Component.extend({
|
||||||
close() {
|
close() {
|
||||||
this._unbindEvents();
|
this._unbindEvents();
|
||||||
|
|
||||||
this.$picker
|
this.$picker &&
|
||||||
.css({ width: "", left: "", bottom: "", display: "none" })
|
this.$picker.css({ width: "", left: "", bottom: "", display: "none" });
|
||||||
.empty();
|
|
||||||
|
|
||||||
this.$modal.removeClass("fadeIn");
|
this.$modal.removeClass("fadeIn");
|
||||||
|
|
||||||
|
@ -52,11 +45,6 @@ export default Component.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
show() {
|
show() {
|
||||||
const template = findRawTemplate("emoji-picker")({
|
|
||||||
customEmojis: customEmojis()
|
|
||||||
});
|
|
||||||
this.$picker.html(template);
|
|
||||||
|
|
||||||
this.$filter = this.$picker.find(".filter");
|
this.$filter = this.$picker.find(".filter");
|
||||||
this.$results = this.$picker.find(".results");
|
this.$results = this.$picker.find(".results");
|
||||||
this.$list = this.$picker.find(".list");
|
this.$list = this.$picker.find(".list");
|
||||||
|
@ -84,6 +72,7 @@ export default Component.extend({
|
||||||
|
|
||||||
@on("init")
|
@on("init")
|
||||||
_setInitialValues() {
|
_setInitialValues() {
|
||||||
|
this.set("customEmojis", customEmojis());
|
||||||
this._checkTimeout = null;
|
this._checkTimeout = null;
|
||||||
this.scrollPosition = 0;
|
this.scrollPosition = 0;
|
||||||
this.$visibleSections = [];
|
this.$visibleSections = [];
|
||||||
|
@ -100,14 +89,21 @@ export default Component.extend({
|
||||||
|
|
||||||
@on("didInsertElement")
|
@on("didInsertElement")
|
||||||
_setup() {
|
_setup() {
|
||||||
this.$picker = $(this.element.querySelector(".emoji-picker"));
|
|
||||||
this.$modal = $(this.element.querySelector(".emoji-picker-modal"));
|
|
||||||
this.appEvents.on("emoji-picker:close", this, "_closeEmojiPicker");
|
this.appEvents.on("emoji-picker:close", this, "_closeEmojiPicker");
|
||||||
},
|
},
|
||||||
|
|
||||||
@on("didUpdateAttrs")
|
@on("didUpdateAttrs")
|
||||||
_setState() {
|
_setState() {
|
||||||
|
schedule("afterRender", () => {
|
||||||
|
if (!this.element) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$picker = $(this.element.querySelector(".emoji-picker"));
|
||||||
|
this.$modal = $(this.element.querySelector(".emoji-picker-modal"));
|
||||||
|
|
||||||
this.active ? this.show() : this.close();
|
this.active ? this.show() : this.close();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@observes("filter")
|
@observes("filter")
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
<div class="emoji-picker"></div>
|
|
||||||
<div class="emoji-picker-modal"></div>
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
<div class="emoji-picker">
|
||||||
|
{{#if active}}
|
||||||
|
<div class='categories-column'>
|
||||||
|
<div class='category-icon'>
|
||||||
|
<button type="button" class="emoji" tabindex="-1" title="{{i18n 'emoji_picker.recent'}}" data-section="recent" data-tabicon="star"></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<% JSON.parse(File.read("lib/emoji/groups.json")).each.with_index do |group, group_index| %>
|
||||||
|
<div class='category-icon'>
|
||||||
|
<button type="button" class="emoji" tabindex="-1" data-tabicon="<%= group["tabicon"] %>" data-section="<%= group["name"] %>" title="{{i18n '<%= "emoji_picker.#{group["name"]}" %>'}}"></button>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
{{#each-in customEmojis as |group emojis|}}
|
||||||
|
<div class='category-icon'>
|
||||||
|
<button data-tabicon={{emojis.firstObject.code}} type="button" class="emoji" tabindex="-1" data-section="custom-{{group}}" title="{{i18n (concat 'emoji_picker.' group)}}"></button>
|
||||||
|
</div>
|
||||||
|
{{/each-in}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='main-column'>
|
||||||
|
<div class='filter'>
|
||||||
|
{{d-icon 'search'}}
|
||||||
|
<input type='text' name="filter" placeholder="{{i18n 'emoji_picker.filter_placeholder'}}" autocomplete="discourse"/>
|
||||||
|
<button class='clear-filter'>
|
||||||
|
{{d-icon 'times'}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='results'></div>
|
||||||
|
|
||||||
|
<div class='list'>
|
||||||
|
<div class='section' data-section='recent'>
|
||||||
|
<div class='section-header'>
|
||||||
|
<span class="title">{{i18n 'emoji_picker.recent'}}</span>
|
||||||
|
<a href='#' class='clear-recent'>{{d-icon "trash-alt"}}</a>
|
||||||
|
</div>
|
||||||
|
<div class='section-group'></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<% JSON.parse(File.read("lib/emoji/groups.json")).each.with_index do |group, group_index| %>
|
||||||
|
<div class='section' data-section='<%= group["name"] %>'>
|
||||||
|
<div class='section-header'>
|
||||||
|
<span class="title">{{i18n 'emoji_picker.<%= group["name"] %>'}}</span>
|
||||||
|
</div>
|
||||||
|
<div class='section-group'>
|
||||||
|
<% group["icons"].each do |icon| %>
|
||||||
|
<button type="button" class="emoji <%= "diversity" if icon["diversity"] %>" tabindex="-1" title="<%= icon['name']%>"></button>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
{{#each-in customEmojis as |group emojis|}}
|
||||||
|
<div class='section' data-section='custom-{{group}}'>
|
||||||
|
<div class='section-header'>
|
||||||
|
<span class="title">
|
||||||
|
{{i18n (concat 'emoji_picker.' group)}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{{#if emojis.length}}
|
||||||
|
<div class='section-group'>
|
||||||
|
{{#each emojis as |emoji|}}
|
||||||
|
<button type="button" class="emoji" tabindex="-1" title=":{{emoji.code}}:">
|
||||||
|
<img loading="lazy" class="emoji" src="{{emoji.src}}">
|
||||||
|
</button>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/each-in}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='footer'>
|
||||||
|
<div class='info'></div>
|
||||||
|
<div class='diversity-picker'>
|
||||||
|
<% ['default', 'light', 'medium-light', 'medium', 'medium-dark', 'dark'].each.with_index do |diversity, index| %>
|
||||||
|
<a href='#' title="{{i18n 'emoji_picker.<%= diversity.gsub('-', '_') %>_tone'}}" class='diversity-scale <%= diversity %>' data-level="<%= index + 1 %>">
|
||||||
|
{{d-icon "check"}}
|
||||||
|
</a>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="emoji-picker-modal"></div>
|
|
@ -1,81 +0,0 @@
|
||||||
<div class='categories-column'>
|
|
||||||
<div class='category-icon'>
|
|
||||||
<button type="button" class="emoji" tabindex="-1" title="{{i18n 'emoji_picker.recent'}}" data-section="recent" data-tabicon="star"></button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<% JSON.parse(File.read("lib/emoji/groups.json")).each.with_index do |group, group_index| %>
|
|
||||||
<div class='category-icon'>
|
|
||||||
<button type="button" class="emoji" tabindex="-1" data-tabicon="<%= group["tabicon"] %>" data-section="<%= group["name"] %>" title="{{i18n '<%= "emoji_picker.#{group["name"]}" %>'}}"></button>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<% Emoji.custom.group_by { |emoji| emoji.group }.each do |group, emojis| %>
|
|
||||||
<% if emojis.present? %>
|
|
||||||
<div class='category-icon'>
|
|
||||||
<button data-tabicon="<%= emojis.first.name %>" type="button" class="emoji" tabindex="-1" data-section="custom-<%= group %>" title="{{i18n 'emoji_picker.<%= group %>'}}"></button>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class='main-column'>
|
|
||||||
<div class='filter'>
|
|
||||||
{{d-icon 'search'}}
|
|
||||||
<input type='text' name="filter" placeholder="{{i18n 'emoji_picker.filter_placeholder'}}" autocomplete="discourse"/>
|
|
||||||
<button class='clear-filter'>
|
|
||||||
{{d-icon 'times'}}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class='results'></div>
|
|
||||||
|
|
||||||
<div class='list'>
|
|
||||||
<div class='section' data-section='recent'>
|
|
||||||
<div class='section-header'>
|
|
||||||
<span class="title">{{i18n 'emoji_picker.recent'}}</span>
|
|
||||||
<a href='#' class='clear-recent'>{{d-icon "trash-alt"}}</a>
|
|
||||||
</div>
|
|
||||||
<div class='section-group'></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<% JSON.parse(File.read("lib/emoji/groups.json")).each.with_index do |group, group_index| %>
|
|
||||||
<div class='section' data-section='<%= group["name"] %>'>
|
|
||||||
<div class='section-header'>
|
|
||||||
<span class="title">{{i18n 'emoji_picker.<%= group["name"] %>'}}</span>
|
|
||||||
</div>
|
|
||||||
<div class='section-group'>
|
|
||||||
<% group["icons"].each do |icon| %>
|
|
||||||
<button type="button" class="emoji <%= "diversity" if icon["diversity"] %>" tabindex="-1" title="<%= icon['name']%>"></button>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
{{#each customEmojis as |emojis|}}
|
|
||||||
{{#if emojis.length}}
|
|
||||||
<div class='section' data-section='custom-{{emojis.firstObject.group}}'>
|
|
||||||
<div class='section-header'>
|
|
||||||
<span class="title">
|
|
||||||
{{i18n emojis.firstObject.key}}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class='section-group'>
|
|
||||||
{{#each emojis as |emoji|}}
|
|
||||||
<button style="background-url: url("{{emoji.src}}")" type="button" class="emoji" tabindex="-1" title="{{emoji.code}}"></button>
|
|
||||||
{{/each}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
{{/each}}
|
|
||||||
</div>
|
|
||||||
<div class='footer'>
|
|
||||||
<div class='info'></div>
|
|
||||||
<div class='diversity-picker'>
|
|
||||||
<% ['default', 'light', 'medium-light', 'medium', 'medium-dark', 'dark'].each.with_index do |diversity, index| %>
|
|
||||||
<a href='#' title="{{i18n 'emoji_picker.<%= diversity.gsub('-', '_') %>_tone'}}" class='diversity-scale <%= diversity %>' data-level="<%= index + 1 %>">
|
|
||||||
{{d-icon "check"}}
|
|
||||||
</a>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -35,6 +35,13 @@ sup img.emoji {
|
||||||
color: $primary;
|
color: $primary;
|
||||||
background-color: $secondary;
|
background-color: $secondary;
|
||||||
border: 1px solid $primary-low;
|
border: 1px solid $primary-low;
|
||||||
|
|
||||||
|
img.emoji {
|
||||||
|
// custom emojis might import images of various sizes
|
||||||
|
// we don't want the picker to be difformed
|
||||||
|
width: 20px !important;
|
||||||
|
height: 20px !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.emoji-picker .categories-column {
|
.emoji-picker .categories-column {
|
||||||
|
|
|
@ -22,7 +22,7 @@ QUnit.test("emoji picker can be opened/closed", async assert => {
|
||||||
find(".emoji-picker")
|
find(".emoji-picker")
|
||||||
.html()
|
.html()
|
||||||
.trim(),
|
.trim(),
|
||||||
"",
|
"<!---->",
|
||||||
"it opens the picker"
|
"it opens the picker"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ QUnit.test("emoji picker can be opened/closed", async assert => {
|
||||||
find(".emoji-picker")
|
find(".emoji-picker")
|
||||||
.html()
|
.html()
|
||||||
.trim(),
|
.trim(),
|
||||||
"",
|
"<!---->",
|
||||||
"it closes the picker"
|
"it closes the picker"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue
Block a user