aboutsummaryrefslogtreecommitdiffstats
path: root/recipes/thelounge/webview.js
blob: 606228898024f93eefc78a2679f48b65a28d2798 (plain) (blame)
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
118
119
120
121
122
123
124
125
function _interopRequireDefault(obj) {
  return obj && obj.__esModule ? obj : { default: obj };
}

const _path = _interopRequireDefault(require('path'));

function countsOfUnreadMessagesAfterMarker(unreadMarker) {
  const children = unreadMarker.parentElement.childNodes;
  let unread = 0;
  let unreadHighlighted = 0;

  for (let i = children.length - 1; i >= 0; i -= 1) {
    if (children[i] === unreadMarker) {
      break;
    }

    if (children[i].classList === undefined) {
      continue;
    }

    if (children[i].classList.contains('msg')) {
      unread += 1;

      if (children[i].classList.contains('highlight')) {
        unreadHighlighted += 1;
      }
    }
  }

  return [unread, unreadHighlighted];
}

function isBadgeInMutedChannel(badgeElement) {
  const channelListItem = badgeElement.closest('.channel-list-item');
  return (
    channelListItem === null || channelListItem.classList.contains('is-muted')
  );
}

module.exports = Ferdium => {
  let unreadMessagesAtLastActivity = 0;
  let unreadHighlightedMessagesAtLastActivity = 0;

  const getMessages = () => {
    // In order to get a correct tally of unread messages, we must
    // consider both the badges on the various channels, plus the
    // number of messages that appear after the 'unread' banner that
    // appears in the page. In the latter case, we should ignore any
    // messages that arrived before or while the app has focus.

    let direct = 0;
    const directElements = document.querySelectorAll('.badge.highlight');

    for (const directElement of directElements) {
      // Note: muted channels don't have highlighted badges for direct notifications,
      // but muted networks do
      if (isBadgeInMutedChannel(directElement)) {
        continue;
      }

      if (directElement.textContent.length > 0) {
        direct += Ferdium.safeParseInt(directElement.textContent);
      }
    }

    let indirect = 0;
    const indirectElements = document.querySelectorAll(
      '.badge:not(.highlight)',
    );

    for (const indirectElement of indirectElements) {
      if (isBadgeInMutedChannel(indirectElement)) {
        continue;
      }

      if (indirectElement.textContent.length > 0) {
        indirect += 1;
      }
    }

    // Only want to count unread messages if the active channel is unmuted
    if (
      document.querySelectorAll('.channel-list-item.active:not(.is-muted)')
        .length > 0
    ) {
      const unreadMarkers = document.querySelectorAll('div.unread-marker');

      if (unreadMarkers.length > 0) {
        const counts = countsOfUnreadMessagesAfterMarker(unreadMarkers[0]);
        const unread = counts[0];
        const unreadHighlighted = counts[1];

        if (document.hasFocus()) {
          unreadMessagesAtLastActivity = unread;
          unreadHighlightedMessagesAtLastActivity = unreadHighlighted;
        }

        if (unread > unreadMessagesAtLastActivity) {
          if (
            unreadHighlighted > 0 &&
            unreadHighlighted > unreadHighlightedMessagesAtLastActivity
          ) {
            direct +=
              unreadHighlighted - unreadHighlightedMessagesAtLastActivity;
          } else {
            indirect += 1;
          }
        }
      } else {
        unreadMessagesAtLastActivity = 0;
        unreadHighlightedMessagesAtLastActivity = 0;
      }
    }

    Ferdium.setBadge(direct, indirect);
  };

  Ferdium.loop(getMessages);

  Ferdium.injectCSS(_path.default.join(__dirname, 'service.css'));

  // We need to monkey patch ServierWorker.postMessage so that notifications
  // will work, and that needs to be done without context isolation:
  Ferdium.injectJSUnsafe(_path.default.join(__dirname, 'webview-unsafe.js'));
};