From 948bd00340d12fdd68aec06fee8eccd21d35b7e9 Mon Sep 17 00:00:00 2001
From: Joffrey JAFFEUX
Date: Thu, 16 Jan 2020 09:54:26 +0100
Subject: [PATCH] FEATURE: line with only 1 to 3 emojis will now display as
large emojis
---
.../engines/discourse-markdown/emoji.js.es6 | 66 ++++++++++++++++++-
app/assets/stylesheets/common/base/emoji.scss | 6 ++
spec/components/cooked_post_processor_spec.rb | 10 +--
spec/components/pretty_text_spec.rb | 46 ++++++++++++-
test/javascripts/lib/pretty-text-test.js.es6 | 8 +--
5 files changed, 124 insertions(+), 12 deletions(-)
diff --git a/app/assets/javascripts/pretty-text/engines/discourse-markdown/emoji.js.es6 b/app/assets/javascripts/pretty-text/engines/discourse-markdown/emoji.js.es6
index ba2c971541b..9f2c2dfacd1 100644
--- a/app/assets/javascripts/pretty-text/engines/discourse-markdown/emoji.js.es6
+++ b/app/assets/javascripts/pretty-text/engines/discourse-markdown/emoji.js.es6
@@ -231,9 +231,68 @@ function applyEmoji(
result.push(text);
}
+ // we check for a result <= 5 because we support maximum 3 large emojis
+ // EMOJI SPACE EMOJI SPACE EMOJI => 5 tokens
+ if (result && result.length > 0 && result.length <= 5) {
+ // we ensure line starts and ends with an emoji
+ // and has no more than 3 emojis
+ if (
+ result[0].type === "emoji" &&
+ result[result.length - 1].type === "emoji" &&
+ result.filter(r => r.type === "emoji").length <= 3
+ ) {
+ let allEmojiLine = true;
+ let index = 0;
+
+ const checkNextToken = t => {
+ if (!t) {
+ return;
+ }
+
+ if (!["emoji", "text"].includes(t.type)) {
+ allEmojiLine = false;
+ }
+
+ // a text token should always have an emoji before
+ // and be a space
+ if (
+ t.type === "text" &&
+ ((result[index - 1] && result[index - 1].type !== "emoji") ||
+ t.content !== " ")
+ ) {
+ allEmojiLine = false;
+ }
+
+ // exit as soon as possible
+ if (allEmojiLine) {
+ index += 1;
+ checkNextToken(result[index]);
+ }
+ };
+
+ checkNextToken(result[index]);
+
+ if (allEmojiLine) {
+ result.forEach(r => {
+ if (r.type === "emoji") {
+ applyAllEmojiClass(r);
+ }
+ });
+ }
+ }
+ }
+
return result;
}
+function applyAllEmojiClass(token) {
+ token.attrs.forEach(attr => {
+ if (attr[0] === "class") {
+ attr[1] = `${attr[1]} only-emoji`;
+ }
+ });
+}
+
export function setup(helper) {
helper.registerOptions((opts, siteSettings, state) => {
opts.features.emoji = !state.disableEmojis && !!siteSettings.enable_emoji;
@@ -257,5 +316,10 @@ export function setup(helper) {
);
});
- helper.whiteList(["img[class=emoji]", "img[class=emoji emoji-custom]"]);
+ helper.whiteList([
+ "img[class=emoji]",
+ "img[class=emoji emoji-custom]",
+ "img[class=emoji emoji-custom only-emoji]",
+ "img[class=emoji only-emoji]"
+ ]);
}
diff --git a/app/assets/stylesheets/common/base/emoji.scss b/app/assets/stylesheets/common/base/emoji.scss
index 0c59b17842d..09fde6478fe 100644
--- a/app/assets/stylesheets/common/base/emoji.scss
+++ b/app/assets/stylesheets/common/base/emoji.scss
@@ -4,6 +4,12 @@ img.emoji {
vertical-align: middle;
}
+img.emoji.only-emoji {
+ width: 32px;
+ height: 32px;
+ margin: 0.5em 0;
+}
+
small img.emoji,
sub img.emoji,
sup img.emoji {
diff --git a/spec/components/cooked_post_processor_spec.rb b/spec/components/cooked_post_processor_spec.rb
index 99fda0ad24f..f087616a936 100644
--- a/spec/components/cooked_post_processor_spec.rb
+++ b/spec/components/cooked_post_processor_spec.rb
@@ -1143,7 +1143,7 @@ describe CookedPostProcessor do
Google

text.txt (20 Bytes)
- 
+
HTML
end
@@ -1158,7 +1158,7 @@ describe CookedPostProcessor do
Google

text.txt (20 Bytes)
-
+
HTML
end
@@ -1171,7 +1171,7 @@ describe CookedPostProcessor do
Google

text.txt (20 Bytes)
-
+
HTML
end
@@ -1185,7 +1185,7 @@ describe CookedPostProcessor do
Google

text.txt (20 Bytes)
-
+
HTML
end
@@ -1199,7 +1199,7 @@ describe CookedPostProcessor do
Google

text.txt (20 Bytes)
-
+
HTML
end
diff --git a/spec/components/pretty_text_spec.rb b/spec/components/pretty_text_spec.rb
index c87a449964e..4beb8cfc473 100644
--- a/spec/components/pretty_text_spec.rb
+++ b/spec/components/pretty_text_spec.rb
@@ -109,6 +109,48 @@ describe PrettyText do
expect(cook(md)).to eq(html.strip)
end
+
+ it "adds an only-emoji class when a line has only one emoji" do
+ md = <<~MD
+ foo š
+ foo š bar
+ :smile_cat:
+ :smile_cat: :smile_cat:
+ :smile_cat: :smile_cat: :smile_cat: :smile_cat:
+ baz? :smile_cat:
+ š
+ š foo
+ š š
+ š š
+ š š š
+ ššš
+ š š š
+ šdš š
+ š š šd
+ šššš
+ MD
+
+ html = <<~HTML
+ foo 
+ foo
bar
+ 
+

+

+ baz? 
+ 
+
foo
+

+

+

+ 


+

+
dā:wink: 
+
d
+ 



+ HTML
+
+ expect(cook(md)).to eq(html.strip)
+ end
end
it "do off topic quoting of posts from secure categories" do
@@ -1064,7 +1106,7 @@ describe PrettyText do
it "can handle emoji by name" do
expected = <
+

HTML
expect(PrettyText.cook(":smile::sunny:")).to eq(expected.strip)
end
@@ -1076,7 +1118,7 @@ HTML
end
it "can handle emoji by translation" do
- expected = "
"
+ expected = "
"
expect(PrettyText.cook(";)")).to eq(expected)
end
diff --git a/test/javascripts/lib/pretty-text-test.js.es6 b/test/javascripts/lib/pretty-text-test.js.es6
index d43310392eb..ea8918d92f3 100644
--- a/test/javascripts/lib/pretty-text-test.js.es6
+++ b/test/javascripts/lib/pretty-text-test.js.es6
@@ -1333,15 +1333,15 @@ QUnit.test("enable/disable features", assert => {
QUnit.test("emoji", assert => {
assert.cooked(
":smile:",
- `
`
+ `
`
);
assert.cooked(
":(",
- `
`
+ `
`
);
assert.cooked(
"8-)",
- `
`
+ `
`
);
});
@@ -1363,7 +1363,7 @@ QUnit.test("emoji - emojiSet", assert => {
assert.cookedOptions(
":smile:",
{ siteSettings: { emoji_set: "twitter" } },
- `
`
+ `
`
);
});