summaryrefslogtreecommitdiff
path: root/static/js/comment-reaction.js
diff options
context:
space:
mode:
Diffstat (limited to 'static/js/comment-reaction.js')
-rw-r--r--static/js/comment-reaction.js140
1 files changed, 75 insertions, 65 deletions
diff --git a/static/js/comment-reaction.js b/static/js/comment-reaction.js
index 4536717..1723c64 100644
--- a/static/js/comment-reaction.js
+++ b/static/js/comment-reaction.js
@@ -54,80 +54,90 @@ function postReaction(reaction, callback) {
xhr.send(encodeAsFormData(reaction));
}
-function selectorWidgetName(id) {
- return `emoji-picker-${id}`;
-}
+let allReactions = null;
+
+async function promptForReaction() {
+ const modal = document.getElementById('reaction-modal');
+ const searchInput = document.getElementById('reaction-search');
+ const listContainer = document.getElementById('reaction-list');
+ const closeBtn = document.getElementById('close-modal');
-// Simple Emoji picker widget.
-function selectorWidget(id) {
- function emojiButton(codepoint) {
- let span = document.createElement("span");
- span.innerHTML = String.fromCodePoint(codepoint);
- return span;
+ if (!allReactions) {
+ try {
+ const response = await fetch('/static/data-by-emoji.json');
+ allReactions = await response.json();
+ } catch (e) {
+ console.error("Failed to load reactions", e);
+ return null;
+ }
}
- let selector = document.createElement("div");
- selector.setAttribute("id", selectorWidgetName(id));
- selector.setAttribute("class", "emoji-picker");
+ return new Promise((resolve) => {
+ const render = (data) => {
+ listContainer.innerHTML = '';
+ Object.entries(data).forEach(([reaction, info]) => {
+ const span = document.createElement('span');
+ span.className = 'reaction-item';
+ span.textContent = reaction;
+ span.title = info.name;
+ span.onclick = () => cleanup(reaction);
+ listContainer.appendChild(span);
+ });
+ };
- for (let i = 0x1F600; i < 0x1F64F; i++) {
- selector.appendChild(emojiButton(i));
- }
- selector.appendChild(emojiButton(0x1F37B));
- selector.appendChild(emojiButton(0x1F440));
- selector.appendChild(emojiButton(0x1F446));
- selector.appendChild(emojiButton(0x1F447));
- selector.appendChild(emojiButton(0x1F448));
- selector.appendChild(emojiButton(0x1F449));
- selector.appendChild(emojiButton(0x1F450));
- selector.appendChild(emojiButton(0x270A));
- selector.appendChild(emojiButton(0x270B));
- selector.appendChild(emojiButton(0x270C));
- selector.appendChild(emojiButton(0x270D));
- for (let i = 0x1F90C; i < 0x1F9FF; i++) {
- selector.appendChild(emojiButton(i));
- }
- return selector;
-}
+ const handleSearch = (e) => {
+ const term = e.target.value.toLowerCase();
+ const filtered = Object.fromEntries(
+ Object.entries(allReactions).filter(([_, info]) =>
+ info.name.toLowerCase().includes(term) || info.slug.toLowerCase().includes(term)
+ )
+ );
+ render(filtered);
+ };
-// Add a "react" button to every local comment.
-window.addEventListener("load", () => {
- // Unhide additional comment actions if Javascript is enabled.
- let additionalActionsRows = document.querySelectorAll(".comment-additional-actions");
- for (let row of additionalActionsRows) {
- row.removeAttribute("hidden");
- }
+ const cleanup = (result) => {
+ modal.style.display = 'none';
+ closeBtn.onclick = null;
+ searchInput.oninput = null;
+ resolve(result);
+ };
- let reactButtons = document.querySelectorAll(".comment-react-button");
- for (let button of reactButtons) {
- let id = button.getAttribute("data-reply-to-id");
+ searchInput.value = '';
+ render(allReactions);
+ modal.style.display = 'flex';
- button.addEventListener('click', (e) => {
- // If we already made a selector widget for this comment, let's "hide" the
- // one that exists.
- let existingSelectorWidget = document.getElementById(selectorWidgetName(id));
- if (existingSelectorWidget !== null) {
- existingSelectorWidget.remove();
- e.preventDefault();
- return;
- }
+ closeBtn.onclick = () => cleanup(null);
+ searchInput.oninput = handleSearch;
- let emojiPicker = selectorWidget(id);
- button.parentNode.parentNode.insertBefore(emojiPicker, button.parentNode);
- for (let button of emojiPicker.children) {
- button.addEventListener('click', (e) => {
- postReaction({
- "id": button.getAttribute("data-react-to-id"),
- "reaction": button.innerHTML
- }, () => {
- let reactAcknowledgement = document.createElement("span");
- reactAcknowledgement.innerHTML = "successfully reacted!"
- button.replaceWith(reactAcknowledgement);
- });
- emojiPicker.remove();
- });
- }
+ modal.onclick = (e) => { if(e.target === modal) cleanup(null); };
+ });
+}
+window.addEventListener("load", () => {
+ const modalHTML = `
+<div id="reaction-modal" class="modal-overlay">
+ <div class="modal-content">
+ <div class="modal-header">
+ <span>Select a reaction</span>
+ <button id="close-modal">X</button>
+ </div>
+ <div class="search-container">
+ <input type="text" id="reaction-search" placeholder="Search reactions..." />
+ </div>
+ <div id="reaction-list" class="reaction-grid"></div>
+ </div>
+</div>`;
+ document.body.insertAdjacentHTML('beforeend', modalHTML);
+ const reactButtons = document.querySelectorAll(".add-reaction");
+ for (const button of reactButtons) {
+ button.removeAttribute("hidden");
+ button.addEventListener('click', async (e) => {
+ let reaction = await promptForReaction();
+ console.log(reaction);
+ postReaction({
+ "id": button.getAttribute("data-reply-to-id"),
+ "reaction": reaction
+ }, window.location.reload);
e.preventDefault();
});
}