summaryrefslogtreecommitdiff
path: root/haunt/static/js/comment-reaction.js
blob: 844f60498c039b28939ac166d65e26e8c1a115ad (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/*
 * comment-reaction.js -- Simple emoji picker and glue for reaction endpoint
 * Copyright © 2023 Jakob L. Kreuze <zerodaysfordays@sdf.org>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */

function encodeAsFormData(obj) {
  // Turn the data object into an array of URL-encoded key/value pairs.
  let urlEncodedDataPairs = [];
  for (let key in obj) {
    urlEncodedDataPairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(obj[key]));
  }
  return urlEncodedDataPairs.join('&');
}

function postReaction(reaction) {
  let xhr = new XMLHttpRequest();
  xhr.open('POST', "/api/comment/react", true);

  // Endpoint expects HTML form data.
  xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');

  xhr.onload = function(data) {
    if (xhr.status != 200) {
      alert("Failed to react.");
    } else {
    }
  }
  xhr.onerror = function(error) {
    throw new Error(`Request failed: ${error}`);
  }

  xhr.send(encodeAsFormData(reaction));
}


// Simple Emoji picker widget.
function selectorWidget() {
  function emojiButton(codepoint) {
    let span = document.createElement("span");
    span.innerHTML = String.fromCodePoint(codepoint);
    return span;
  }

  let selector = document.createElement("div");
  selector.setAttribute("class", "emoji-picker");

  for (let i = 0x1F600; i < 0x1F64F; i++) {
    selector.appendElement(emojiButton(i));
  }
  selector.appendElement(emojiButton(0x1F37B));
  selector.appendElement(emojiButton(0x1F440));
  selector.appendElement(emojiButton(0x1F446));
  selector.appendElement(emojiButton(0x1F447));
  selector.appendElement(emojiButton(0x1F448));
  selector.appendElement(emojiButton(0x1F449));
  selector.appendElement(emojiButton(0x1F450));
  selector.appendElement(emojiButton(0x270A));
  selector.appendElement(emojiButton(0x270B));
  selector.appendElement(emojiButton(0x270C));
  selector.appendElement(emojiButton(0x270D));
  for (let i = 0x1F90C; i < 0x1F9FF; i++) {
    selector.appendElement(emojiButton(i));
  }
  return selector;
}

// Add a "react" button to every local comment.
window.addEventListener("load", () => {
  // First pass to add a separator for the buttons.
  let replyButtons = document.querySelectorAll(".comment-reply-button");
  for (let button of replyButtons) {
    let parent = button.parentNode;
    parent.innerHTML += " - ";

  }

  // Second pass to add the actual "react" button.
  replyButtons = document.querySelectorAll(".comment-reply-button");
  for (let button of replyButtons) {
    let reactButton = document.createElement("a");
    reactButton.setAttribute("class", "comment-react-button");
    reactButton.setAttribute("href", "#");
    reactButton.setAttribute("data-react-to-id", button.getAttribute("data-reply-to-id"));
    reactButton.innerHTML = "react";
    button.parentNode.appendChild(reactButton);

    reactButton.addEventListener('click', (e) => {
      let emojiPicker = selectorWidget();
      button.parentNode.parentNode.insertBefore(emojiPicker, button.parentNode);
      for (let button of emojiPicker.children) {
        button.addEventListener('click', (e) => {
          postReaction({
            "id": reactButton.getAttribute("data-react-to-id"),
            "reaction": button.innerHTML
          });
          emojiPicker.remove();
        });
      }

      e.preventDefault();
    });
  }
});