From 263e48d0195f47b55bf499f3d259ed2964b1a308 Mon Sep 17 00:00:00 2001 From: Lim Chee Aun Date: Thu, 22 Dec 2022 19:24:07 +0800 Subject: [PATCH] New feature: :shortcode: expander in compose field Using `innerHTML` because easier to code but the `encodeHTML` function is troublesome --- public/sw.js | 2 +- src/components/compose.jsx | 127 +++++++++++++++++++++++++++++++------ 2 files changed, 107 insertions(+), 22 deletions(-) diff --git a/public/sw.js b/public/sw.js index b44db070..44af1ed5 100644 --- a/public/sw.js +++ b/public/sw.js @@ -29,7 +29,7 @@ registerRoute(imageRoute); // Cache /instance because masto.js has to keep calling it while initializing const apiExtendedRoute = new RegExpRoute( - /^https?:\/\/[^\/]+\/api\/v\d+\/instance/, + /^https?:\/\/[^\/]+\/api\/v\d+\/(instance|custom_emojis)/, new StaleWhileRevalidate({ cacheName: 'api-extended', plugins: [ diff --git a/src/components/compose.jsx b/src/components/compose.jsx index 120b79e5..b14ba6ae 100644 --- a/src/components/compose.jsx +++ b/src/components/compose.jsx @@ -36,6 +36,10 @@ const expiresInFromExpiresAt = (expiresAt) => { return expirySeconds.find((s) => s >= delta) || oneDay; }; +const menu = document.createElement('ul'); +menu.role = 'listbox'; +menu.className = 'text-expander-menu'; + function Compose({ onClose, replyToStatus, @@ -82,6 +86,15 @@ function Compose({ const [mediaAttachments, setMediaAttachments] = useState([]); const [poll, setPoll] = useState(null); + const customEmojis = useRef(); + useEffect(() => { + (async () => { + const emojis = await masto.customEmojis.fetchAll(); + console.log({ emojis }); + customEmojis.current = emojis; + })(); + }, []); + useEffect(() => { if (replyToStatus) { const { spoilerText, visibility, sensitive } = replyToStatus; @@ -167,6 +180,7 @@ function Compose({ // console.log('text-expander-change', e); const { key, provide, text } = e.detail; textExpanderTextRef.current = text; + if (text === '') { provide( Promise.resolve({ @@ -175,6 +189,34 @@ function Compose({ ); return; } + + if (key === ':') { + // const emojis = customEmojis.current.filter((emoji) => + // emoji.shortcode.startsWith(text), + // ); + const emojis = filterShortcodes(customEmojis.current, text); + let html = ''; + emojis.forEach((emoji) => { + const { shortcode, url } = emoji; + html += ` +
  • + + :${encodeHTML(shortcode)}: +
  • `; + }); + // console.log({ emojis, html }); + menu.innerHTML = html; + provide( + Promise.resolve({ + matched: emojis.length > 0, + fragment: menu, + }), + ); + return; + } + const type = { '@': 'accounts', '#': 'hashtags', @@ -192,9 +234,7 @@ function Compose({ } const results = value[type]; console.log('RESULTS', value, results); - const menu = document.createElement('ul'); - menu.role = 'listbox'; - menu.className = 'text-expander-menu'; + let html = ''; results.forEach((result) => { const { name, @@ -205,27 +245,29 @@ function Compose({ emojis, } = result; const displayNameWithEmoji = emojifyText(displayName, emojis); - const item = document.createElement('li'); - item.setAttribute('role', 'option'); + // const item = menuItem.cloneNode(); if (acct) { - item.dataset.value = acct; - // Want to use here, but will need to render to string 😅 - item.innerHTML = ` - - - - - ${displayNameWithEmoji || username} -
    @${acct} -
    + html += ` +
  • + + + + + ${encodeHTML(displayNameWithEmoji || username)} +
    @${encodeHTML(acct)} +
    +
  • `; } else { - item.dataset.value = name; - item.innerHTML = ` - #${name} + html += ` +
  • + #${encodeHTML(name)} +
  • `; } - menu.appendChild(item); + menu.innerHTML = html; }); console.log('MENU', results, menu); resolve({ @@ -244,7 +286,11 @@ function Compose({ textExpanderRef.current.addEventListener('text-expander-value', (e) => { const { key, item } = e.detail; - e.detail.value = key + item.dataset.value; + if (key === ':') { + e.detail.value = `:${item.dataset.value}:`; + } else { + e.detail.value = `${key}${item.dataset.value}`; + } }); } }, []); @@ -664,7 +710,7 @@ function Compose({ {' '} - +