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
  1. 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 = ':{0}:' 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 @@ +
    + + +