diff --git a/files/assets/css/main.css b/files/assets/css/main.css
index 8fcbd3f2a..4f22b86b5 100644
--- a/files/assets/css/main.css
+++ b/files/assets/css/main.css
@@ -5594,6 +5594,17 @@ img[src$="/i/hand.webp"]+img[src^="/pp/"], img[src$="/i/hand.webp"]+img[src$="/p
100% { transform: scale(1, 0.8) }
}
+@keyframes cide-anim {
+ 0% { transform: scale(1,1) rotate(0deg) }
+ 100% { transform: scale(0, 0) rotate(360deg) }
+}
+
+.cide, span[cide] {
+ display: inline-block;
+ animation: cide-anim 2s infinite;
+ animation-timing-function: linear;
+}
+
/* Fix for
being populated with in many contexts. */
.post-body li > p:first-child,
.comment-text li > p:first-child,
diff --git a/files/assets/js/markdown.js b/files/assets/js/markdown.js
index 90b938597..b34d37811 100644
--- a/files/assets/js/markdown.js
+++ b/files/assets/js/markdown.js
@@ -72,8 +72,51 @@ const MODIFIERS = {
REVERSED: 4,
USER: 5,
REVERSED_MODIFIER: 6,
+ GENOCIDE: 7,
};
+const findAllEmoteEndings = (word) => {
+ let hasReachedNonModifer = false;
+ let currWord = word;
+ const currEndings = [];
+ while(!hasReachedNonModifer) {
+ if(currWord.endsWith('pat')) {
+ if(currEndings.indexOf(MODIFIERS.PAT) !== -1) {
+ hasReachedNonModifer = true;
+ continue;
+ }
+ currWord = currWord.slice(0, -3);
+ currEndings.push(MODIFIERS.PAT);
+ continue;
+ }
+
+ if(currWord.endsWith('talking')) {
+ if(currEndings.indexOf(MODIFIERS.TALKING) !== -1) {
+ hasReachedNonModifer = true;
+ continue;
+ }
+ currWord = currWord.slice(0, -7);
+ currEndings.push(MODIFIERS.TALKING);
+ continue;
+ }
+
+ if(currWord.endsWith('genocide')) {
+ if(currEndings.indexOf(MODIFIERS.GENOCIDE) !== -1) {
+ hasReachedNonModifer = true;
+ continue;
+ }
+ currWord = currWord.slice(0, -8);
+ currEndings.push(MODIFIERS.GENOCIDE);
+ continue;
+ }
+
+ hasReachedNonModifer = true;
+ }
+
+
+ return [currEndings, currWord];
+}
+
function markdown(t) {
let input = t.value;
@@ -110,8 +153,8 @@ function markdown(t) {
const modifiers = new Set();
- let length = emoji.length
- if (emoji.includes('!!')) modifiers.add(MODIFIERS.REVERSED_MODIFIER);
+ let length = emoji.length;
+ if(emoji.includes('!!')) modifiers.add(MODIFIERS.REVERSED_MODIFIER);
emoji = emoji.replaceAll('!', '');
if (length !== emoji.length) {
modifiers.add(MODIFIERS.REVERSED);
@@ -121,15 +164,11 @@ function markdown(t) {
if (length !== emoji.length) {
modifiers.add(MODIFIERS.LARGE);
}
- const isTalkingFirst = !(emoji.endsWith('pat') && emoji.slice(0, -3).endsWith('talking'));
- if (emoji.endsWith('talking') || (emoji.endsWith('pat') && emoji.slice(0, -3).endsWith('talking'))) {
- modifiers.add(MODIFIERS.TALKING);
- emoji = emoji.endsWith('pat') ? [emoji.slice(0, -10), emoji.slice(-3)].join('') : emoji.slice(0, -7);
- }
- if (emoji.endsWith('pat')) {
- modifiers.add(MODIFIERS.PAT);
- emoji = emoji.slice(0, -3);
- }
+ let endingModifiers;
+ [endingModifiers, emoji] = findAllEmoteEndings(emoji);
+ const isTalkingFirst = endingModifiers.indexOf(MODIFIERS.PAT) > endingModifiers.indexOf(MODIFIERS.TALKING);
+
+ endingModifiers.forEach(modifiers.add, modifiers)
if (emoji.startsWith('@')) {
emoji = emoji.slice(1);
@@ -145,18 +184,19 @@ function markdown(t) {
}
const mirroredClass = 'mirrored';
+ const genocideClass = modifiers.has(MODIFIERS.GENOCIDE) ? 'cide' : '';
const emojiClass = modifiers.has(MODIFIERS.LARGE) ? 'emoji-lg' : 'emoji';
// patted emotes cannot be flipped back easily so they don't support double flipping
const spanClass = modifiers.has(MODIFIERS.REVERSED) && (modifiers.has(MODIFIERS.PAT) || !modifiers.has(MODIFIERS.REVERSED_MODIFIER)) ? mirroredClass : '';
const imgClass = modifiers.has(MODIFIERS.REVERSED) && modifiers.has(MODIFIERS.REVERSED_MODIFIER) ? mirroredClass : ''
- if (modifiers.has(MODIFIERS.PAT) || modifiers.has(MODIFIERS.TALKING)) {
+ if (modifiers.has(MODIFIERS.PAT) || modifiers.has(MODIFIERS.TALKING) || modifiers.has(MODIFIERS.GENOCIDE)) {
const talkingHtml = modifiers.has(MODIFIERS.TALKING) ? `` : '';
const patHtml = modifiers.has(MODIFIERS.PAT) ? `` : '';
const url = modifiers.has(MODIFIERS.USER) ? `/@${emoji}/pic` : `${SITE_FULL_IMAGES}/e/${emoji}.webp`;
const modifierHtml = isTalkingFirst ? `${talkingHtml}${patHtml}` : `${patHtml}${talkingHtml}`;
- input = input.replace(old, `${modifierHtml}`);
+ input = input.replace(old, `${modifierHtml}`);
} else {
input = input.replace(old, ``);
}
diff --git a/files/helpers/sanitize.py b/files/helpers/sanitize.py
index a0daceac1..9389645d7 100644
--- a/files/helpers/sanitize.py
+++ b/files/helpers/sanitize.py
@@ -99,6 +99,7 @@ def allowed_attributes(tag, name, value):
if name == 'data-bs-toggle' and value == 'tooltip': return True
if name == 'title': return True
if name == 'alt': return True
+ if name == 'cide' and not value: return True
if tag == 'table':
if name == 'class' and value == 'table': return True
@@ -212,6 +213,42 @@ def execute_blackjack(v, target, body, kind):
send_repeatable_notification_duplicated(id, f"Blackjack by @{v.username}: {extra_info}")
return True
+def find_all_emote_endings(word):
+ endings = list()
+ curr_word = word
+
+ is_non_ending_found = False
+ while not is_non_ending_found:
+ print(curr_word)
+ if curr_word.endswith('pat'):
+ if 'pat' in endings:
+ is_non_ending_found = True
+ continue
+ endings.append('pat')
+ curr_word = curr_word[:-3]
+ continue
+
+ if curr_word.endswith('talking'):
+ if 'talking' in endings:
+ is_non_ending_found = True
+ continue
+ endings.append('talking')
+ curr_word = curr_word[:-7]
+ continue
+
+ if curr_word.endswith('genocide'):
+ if 'genocide' in endings:
+ is_non_ending_found = True
+ continue
+ endings.append('genocide')
+ curr_word = curr_word[:-8]
+ continue
+
+ is_non_ending_found = True
+
+ return endings, curr_word
+
+
def render_emoji(html, regexp, golden, emojis_used, b=False, is_title=False):
emojis = list(regexp.finditer(html))
captured = set()
@@ -245,12 +282,13 @@ def render_emoji(html, regexp, golden, emojis_used, b=False, is_title=False):
emoji_partial = ''
emoji_html = None
- is_talking = emoji.endswith('talking') or (emoji[:-3].endswith('talking') and emoji.endswith('pat'))
- is_talking_first = emoji.endswith('talking')
- emoji = emoji[:-7] if emoji.endswith('talking') else emoji
- emoji = f'{emoji[:-10]}pat' if emoji[:-3].endswith('talking') and emoji.endswith('pat') else emoji
- is_patted = emoji.endswith('pat')
- emoji = emoji[:-3] if is_patted else emoji
+ ending_modifiers, emoji = find_all_emote_endings(emoji)
+
+ is_talking = 'talking' in ending_modifiers
+ is_patted = 'pat' in ending_modifiers
+ is_talking_first = ending_modifiers.index('pat') > ending_modifiers.index('talking') if is_talking and is_patted else False
+
+ is_genocided = 'genocide' in ending_modifiers
is_user = emoji.startswith('@')
end_modifier_length = 3 if is_patted else 0
@@ -258,8 +296,9 @@ def render_emoji(html, regexp, golden, emojis_used, b=False, is_title=False):
hand_html = f'' if is_patted and emoji != 'marseyunpettable' else ''
talking_html = f'' if is_talking else ''
+ genocide_attr = ' cide' if is_genocided else ''
- modifier_html = None
+ modifier_html = ''
if (is_talking and is_patted):
modifier_html = f'{talking_html}{hand_html}' if is_talking_first else f'{hand_html}{talking_html}'
elif (is_patted):
@@ -267,12 +306,12 @@ def render_emoji(html, regexp, golden, emojis_used, b=False, is_title=False):
elif (is_talking):
modifier_html = talking_html
- if (is_patted and emoji != 'marseyunpettable') or is_talking:
+ if (is_patted and emoji != 'marseyunpettable') or is_talking or is_genocided:
if path.isfile(f"files/assets/images/emojis/{emoji}.webp"):
- emoji_html = f'{modifier_html}{emoji_partial_pat.format(old, f"{SITE_FULL_IMAGES}/e/{emoji}.webp", attrs)}'
+ emoji_html = f'{modifier_html}{emoji_partial_pat.format(old, f"{SITE_FULL_IMAGES}/e/{emoji}.webp", attrs)}'
elif is_user:
if u := get_user(emoji[1:], graceful=True):
- emoji_html = f'{modifier_html}{emoji_partial_pat.format(old, f"/pp/{u.id}", attrs)}'
+ emoji_html = f'{modifier_html}{emoji_partial_pat.format(old, f"/pp/{u.id}", attrs)}'
elif path.isfile(f'files/assets/images/emojis/{emoji}.webp'):
emoji_html = emoji_partial.format(old, f'{SITE_FULL_IMAGES}/e/{emoji}.webp', attrs)
@@ -634,6 +673,7 @@ def allowed_attributes_emojis(tag, name, value):
if name == 'data-bs-toggle' and value == 'tooltip': return True
if name == 'title': return True
if name == 'alt': return True
+ if name == 'cide' and not value: return True
return False
diff --git a/files/templates/modals/emoji.html b/files/templates/modals/emoji.html
index dd2fd3aeb..a907885bb 100644
--- a/files/templates/modals/emoji.html
+++ b/files/templates/modals/emoji.html
@@ -38,6 +38,10 @@
+
+
+
+