discord.js-html-transcript 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +470 -0
  3. package/dist/downloader/assets.d.ts +18 -0
  4. package/dist/downloader/assets.js +53 -0
  5. package/dist/downloader/assets.js.map +1 -0
  6. package/dist/downloader/images.d.ts +28 -0
  7. package/dist/downloader/images.js +119 -0
  8. package/dist/downloader/images.js.map +1 -0
  9. package/dist/generator/index.d.ts +24 -0
  10. package/dist/generator/index.js +112 -0
  11. package/dist/generator/index.js.map +1 -0
  12. package/dist/generator/renderers/attachment.d.ts +23 -0
  13. package/dist/generator/renderers/attachment.js +154 -0
  14. package/dist/generator/renderers/attachment.js.map +1 -0
  15. package/dist/generator/renderers/components/Attachment Gallery.d.ts +9 -0
  16. package/dist/generator/renderers/components/Attachment Gallery.js +26 -0
  17. package/dist/generator/renderers/components/Attachment Gallery.js.map +1 -0
  18. package/dist/generator/renderers/components/Button.d.ts +9 -0
  19. package/dist/generator/renderers/components/Button.js +23 -0
  20. package/dist/generator/renderers/components/Button.js.map +1 -0
  21. package/dist/generator/renderers/components/Container.d.ts +6 -0
  22. package/dist/generator/renderers/components/Container.js +26 -0
  23. package/dist/generator/renderers/components/Container.js.map +1 -0
  24. package/dist/generator/renderers/components/Media Gallery.d.ts +8 -0
  25. package/dist/generator/renderers/components/Media Gallery.js +45 -0
  26. package/dist/generator/renderers/components/Media Gallery.js.map +1 -0
  27. package/dist/generator/renderers/components/Select Menu.d.ts +10 -0
  28. package/dist/generator/renderers/components/Select Menu.js +34 -0
  29. package/dist/generator/renderers/components/Select Menu.js.map +1 -0
  30. package/dist/generator/renderers/components/Spacing.d.ts +7 -0
  31. package/dist/generator/renderers/components/Spacing.js +17 -0
  32. package/dist/generator/renderers/components/Spacing.js.map +1 -0
  33. package/dist/generator/renderers/components/Thumbnail.d.ts +7 -0
  34. package/dist/generator/renderers/components/Thumbnail.js +21 -0
  35. package/dist/generator/renderers/components/Thumbnail.js.map +1 -0
  36. package/dist/generator/renderers/components/poll.d.ts +7 -0
  37. package/dist/generator/renderers/components/poll.js +78 -0
  38. package/dist/generator/renderers/components/poll.js.map +1 -0
  39. package/dist/generator/renderers/components/section/Section.d.ts +11 -0
  40. package/dist/generator/renderers/components/section/Section.js +21 -0
  41. package/dist/generator/renderers/components/section/Section.js.map +1 -0
  42. package/dist/generator/renderers/components/section/SectionAccessory.d.ts +6 -0
  43. package/dist/generator/renderers/components/section/SectionAccessory.js +20 -0
  44. package/dist/generator/renderers/components/section/SectionAccessory.js.map +1 -0
  45. package/dist/generator/renderers/components/section/SectionContent.d.ts +6 -0
  46. package/dist/generator/renderers/components/section/SectionContent.js +21 -0
  47. package/dist/generator/renderers/components/section/SectionContent.js.map +1 -0
  48. package/dist/generator/renderers/components/styles.d.ts +21 -0
  49. package/dist/generator/renderers/components/styles.js +1639 -0
  50. package/dist/generator/renderers/components/styles.js.map +1 -0
  51. package/dist/generator/renderers/components/utils.d.ts +36 -0
  52. package/dist/generator/renderers/components/utils.js +98 -0
  53. package/dist/generator/renderers/components/utils.js.map +1 -0
  54. package/dist/generator/renderers/components/voice.d.ts +5 -0
  55. package/dist/generator/renderers/components/voice.js +50 -0
  56. package/dist/generator/renderers/components/voice.js.map +1 -0
  57. package/dist/generator/renderers/components.d.ts +13 -0
  58. package/dist/generator/renderers/components.js +78 -0
  59. package/dist/generator/renderers/components.js.map +1 -0
  60. package/dist/generator/renderers/content.d.ts +26 -0
  61. package/dist/generator/renderers/content.js +396 -0
  62. package/dist/generator/renderers/content.js.map +1 -0
  63. package/dist/generator/renderers/embed.d.ts +59 -0
  64. package/dist/generator/renderers/embed.js +216 -0
  65. package/dist/generator/renderers/embed.js.map +1 -0
  66. package/dist/generator/renderers/message.d.ts +7 -0
  67. package/dist/generator/renderers/message.js +106 -0
  68. package/dist/generator/renderers/message.js.map +1 -0
  69. package/dist/generator/renderers/reply.d.ts +7 -0
  70. package/dist/generator/renderers/reply.js +74 -0
  71. package/dist/generator/renderers/reply.js.map +1 -0
  72. package/dist/generator/renderers/systemMessage.d.ts +15 -0
  73. package/dist/generator/renderers/systemMessage.js +168 -0
  74. package/dist/generator/renderers/systemMessage.js.map +1 -0
  75. package/dist/generator/transcript.d.ts +3 -0
  76. package/dist/generator/transcript.js +148 -0
  77. package/dist/generator/transcript.js.map +1 -0
  78. package/dist/index.d.ts +26 -0
  79. package/dist/index.js +159 -0
  80. package/dist/index.js.map +1 -0
  81. package/dist/options.d.ts +37 -0
  82. package/dist/options.js +89 -0
  83. package/dist/options.js.map +1 -0
  84. package/dist/static/client.d.ts +6 -0
  85. package/dist/static/client.js +626 -0
  86. package/dist/static/client.js.map +1 -0
  87. package/dist/types.d.ts +193 -0
  88. package/dist/types.js +10 -0
  89. package/dist/types.js.map +1 -0
  90. package/dist/utils/buildProfiles.d.ts +14 -0
  91. package/dist/utils/buildProfiles.js +136 -0
  92. package/dist/utils/buildProfiles.js.map +1 -0
  93. package/dist/utils/embeds.d.ts +2 -0
  94. package/dist/utils/embeds.js +17 -0
  95. package/dist/utils/embeds.js.map +1 -0
  96. package/dist/utils/extend.d.ts +8 -0
  97. package/dist/utils/extend.js +8 -0
  98. package/dist/utils/extend.js.map +1 -0
  99. package/dist/utils/utils.d.ts +9 -0
  100. package/dist/utils/utils.js +44 -0
  101. package/dist/utils/utils.js.map +1 -0
  102. package/package.json +100 -0
@@ -0,0 +1,626 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fixEmbedBorders = exports.enableMessageSearch = exports.enableImagePreview = exports.applyServerTags = exports.revealSpoiler = exports.scrollToMessage = void 0;
4
+ exports.scrollToMessage = 'document.addEventListener("click",t=>{let e=t.target;if(!e)return;let o=e?.getAttribute("data-goto");if(o){let r=document.getElementById(`m-${o}`);r?(r.scrollIntoView({behavior:"smooth",block:"center"}),r.style.backgroundColor="rgba(148, 156, 247, 0.1)",r.style.transition="background-color 0.5s ease",setTimeout(()=>{r.style.backgroundColor="transparent"},1e3)):console.warn("Message ${goto} not found.")}});';
5
+ exports.revealSpoiler = 'document.addEventListener("click",e=>{const t=e.target;if(!(t instanceof Element))return;const o=t.closest(".discord-spoiler");o&&o.classList.contains("discord-spoiler")&&(o.classList.remove("discord-spoiler"),o.classList.add("discord-spoiler--revealed"))});';
6
+ exports.applyServerTags = `
7
+ (() => {
8
+ const hostSelector = 'discord-message[profile], discord-reply[profile], discord-thread-message[profile], discord-command[profile]';
9
+ const rootSelector = 'discord-message, discord-reply, discord-thread-message, discord-command';
10
+
11
+ const getProfiles = () => window.$discordMessage?.profiles ?? {};
12
+ const getOwningHost = (element) => element.closest(rootSelector);
13
+
14
+ const getInjectedTag = (host) =>
15
+ Array.from(host.querySelectorAll('.discord-server-tag[data-transcript-server-tag="true"]')).find(
16
+ (element) => getOwningHost(element) === host
17
+ ) ?? null;
18
+
19
+ const getInjectedRoleIcon = (host) =>
20
+ Array.from(host.querySelectorAll('.discord-author-role-icon[data-transcript-role-icon="true"]')).find(
21
+ (element) => getOwningHost(element) === host
22
+ ) ?? null;
23
+
24
+ const getNativeRoleIcon = (host) =>
25
+ Array.from(host.querySelectorAll('.discord-author-role-icon')).find(
26
+ (element) => getOwningHost(element) === host && element.dataset.transcriptRoleIcon !== 'true'
27
+ ) ?? null;
28
+
29
+ const getUsernameElement = (host) => {
30
+ const usernameSelector =
31
+ host.tagName === 'DISCORD-MESSAGE' || host.tagName === 'DISCORD-THREAD-MESSAGE'
32
+ ? '.discord-author-username'
33
+ : '.discord-replied-message-username';
34
+
35
+ return Array.from(host.querySelectorAll(usernameSelector)).find((element) => getOwningHost(element) === host) ?? null;
36
+ };
37
+
38
+ const createServerTag = (tagText, badgeUrl, guildId) => {
39
+ const container = document.createElement('span');
40
+ container.className = 'discord-server-tag';
41
+ container.dataset.transcriptServerTag = 'true';
42
+ container.dataset.tag = tagText;
43
+ container.dataset.badge = badgeUrl ?? '';
44
+ container.title = 'Server Tag: ' + tagText;
45
+
46
+ if (guildId) {
47
+ container.dataset.guildId = guildId;
48
+ }
49
+
50
+ if (badgeUrl) {
51
+ const badge = document.createElement('img');
52
+ badge.className = 'discord-server-tag-badge';
53
+ badge.src = badgeUrl;
54
+ badge.alt = '';
55
+ badge.loading = 'lazy';
56
+ badge.decoding = 'async';
57
+ badge.draggable = false;
58
+ container.appendChild(badge);
59
+ }
60
+
61
+ const label = document.createElement('span');
62
+ label.className = 'discord-server-tag-text';
63
+ label.textContent = tagText;
64
+ container.appendChild(label);
65
+
66
+ return container;
67
+ };
68
+
69
+ const createRoleIcon = (iconUrl, roleName) => {
70
+ const icon = document.createElement('img');
71
+ icon.className = 'discord-author-role-icon';
72
+ icon.dataset.transcriptRoleIcon = 'true';
73
+ icon.src = iconUrl;
74
+ icon.alt = roleName || '';
75
+ icon.loading = 'lazy';
76
+ icon.decoding = 'async';
77
+ icon.draggable = false;
78
+
79
+ if (roleName) {
80
+ icon.title = roleName;
81
+ }
82
+
83
+ return icon;
84
+ };
85
+
86
+ const applyToHost = (host) => {
87
+ const profileId = host.getAttribute('profile');
88
+ if (!profileId) {
89
+ return;
90
+ }
91
+
92
+ const profile = getProfiles()[profileId];
93
+ const tagText = typeof profile?.serverTagText === 'string' ? profile.serverTagText.trim() : '';
94
+ const badgeUrl = typeof profile?.serverTagBadge === 'string' ? profile.serverTagBadge : '';
95
+ const guildId = typeof profile?.serverTagGuildId === 'string' ? profile.serverTagGuildId : '';
96
+ const existing = getInjectedTag(host);
97
+
98
+ if (!tagText) {
99
+ existing?.remove();
100
+ return;
101
+ }
102
+
103
+ const username = getUsernameElement(host);
104
+ if (!username) {
105
+ return;
106
+ }
107
+
108
+ if (existing?.dataset.tag === tagText && (existing.dataset.badge ?? '') === badgeUrl) {
109
+ return;
110
+ }
111
+
112
+ existing?.remove();
113
+ username.insertAdjacentElement('afterend', createServerTag(tagText, badgeUrl || undefined, guildId || undefined));
114
+ };
115
+
116
+ const applyRoleIconToHost = (host) => {
117
+ const profileId = host.getAttribute('profile');
118
+ if (!profileId) {
119
+ return;
120
+ }
121
+
122
+ const profile = getProfiles()[profileId];
123
+ const roleIcon = typeof profile?.roleIcon === 'string' ? profile.roleIcon : '';
124
+ const roleName = typeof profile?.roleName === 'string' ? profile.roleName : '';
125
+ const existing = getInjectedRoleIcon(host);
126
+ const nativeIcon = getNativeRoleIcon(host);
127
+
128
+ if (!roleIcon) {
129
+ existing?.remove();
130
+ return;
131
+ }
132
+
133
+ if (nativeIcon) {
134
+ if (nativeIcon.getAttribute('src') !== roleIcon) {
135
+ nativeIcon.setAttribute('src', roleIcon);
136
+ }
137
+
138
+ nativeIcon.setAttribute('alt', roleName);
139
+ if (roleName) {
140
+ nativeIcon.setAttribute('title', roleName);
141
+ }
142
+ return;
143
+ }
144
+
145
+ const username = getUsernameElement(host);
146
+ if (!username) {
147
+ return;
148
+ }
149
+
150
+ const anchor = getInjectedTag(host) ?? username;
151
+ if (existing) {
152
+ if (existing.getAttribute('src') !== roleIcon) {
153
+ existing.setAttribute('src', roleIcon);
154
+ }
155
+
156
+ existing.setAttribute('alt', roleName);
157
+ if (roleName) {
158
+ existing.setAttribute('title', roleName);
159
+ } else {
160
+ existing.removeAttribute('title');
161
+ }
162
+
163
+ if (existing.previousElementSibling !== anchor) {
164
+ anchor.insertAdjacentElement('afterend', existing);
165
+ }
166
+ return;
167
+ }
168
+
169
+ anchor.insertAdjacentElement('afterend', createRoleIcon(roleIcon, roleName));
170
+ };
171
+
172
+ const normalizeApplicationTags = () => {
173
+ document.querySelectorAll('.discord-application-tag').forEach((tag) => {
174
+ const label = Array.from(tag.childNodes)
175
+ .map((node) => node.textContent ?? '')
176
+ .join('')
177
+ .replace(/\\s+/g, ' ')
178
+ .trim()
179
+ .toLowerCase();
180
+
181
+ if (label === 'bot') {
182
+ tag.setAttribute('data-transcript-app-tag-kind', 'bot');
183
+ return;
184
+ }
185
+
186
+ if (label === 'server') {
187
+ tag.setAttribute('data-transcript-app-tag-kind', 'server');
188
+ return;
189
+ }
190
+
191
+ tag.removeAttribute('data-transcript-app-tag-kind');
192
+ });
193
+ };
194
+
195
+ let scheduled = false;
196
+
197
+ const applyAll = () => {
198
+ document.querySelectorAll(hostSelector).forEach((host) => applyToHost(host));
199
+ document.querySelectorAll(hostSelector).forEach((host) => applyRoleIconToHost(host));
200
+ normalizeApplicationTags();
201
+ };
202
+
203
+ const schedule = () => {
204
+ if (scheduled) {
205
+ return;
206
+ }
207
+
208
+ scheduled = true;
209
+ requestAnimationFrame(() => {
210
+ scheduled = false;
211
+ applyAll();
212
+ });
213
+ };
214
+
215
+ if (document.readyState === 'loading') {
216
+ document.addEventListener('DOMContentLoaded', schedule, { once: true });
217
+ } else {
218
+ schedule();
219
+ }
220
+
221
+ window.addEventListener('load', schedule);
222
+ new MutationObserver(schedule).observe(document.documentElement, { childList: true, subtree: true });
223
+ })();
224
+ `;
225
+ exports.enableImagePreview = `
226
+ (() => {
227
+ const overlay = document.createElement('div');
228
+ overlay.className = 'discord-image-preview-overlay';
229
+ overlay.innerHTML = \`
230
+ <button type="button" class="discord-image-preview-close" aria-label="Close image preview">
231
+ <svg width="20" height="20" viewBox="0 0 24 24" aria-hidden="true">
232
+ <path fill="currentColor" d="M17.66 6.34a1 1 0 0 0-1.41 0L12 10.59 7.76 6.34a1 1 0 1 0-1.41 1.41L10.59 12l-4.24 4.24a1 1 0 1 0 1.41 1.41L12 13.41l4.24 4.24a1 1 0 0 0 1.41-1.41L13.41 12l4.24-4.24a1 1 0 0 0 0-1.41Z" />
233
+ </svg>
234
+ </button>
235
+ <div class="discord-image-preview-stage">
236
+ <img class="discord-image-preview-image" alt="" />
237
+ </div>
238
+ \`;
239
+
240
+ const previewImage = overlay.querySelector('.discord-image-preview-image');
241
+ const closeButton = overlay.querySelector('.discord-image-preview-close');
242
+ const ignoredAncestors =
243
+ '.discord-image-preview-overlay, .discord-author-avatar, .discord-replied-message, .discord-button, .discord-select-menu-option, .discord-server-tag, .discord-thread-preview-message, .discord-poll-emoji, .discord-invite';
244
+ let previousOverflow = '';
245
+
246
+ const closePreview = () => {
247
+ overlay.classList.remove('is-open');
248
+ previewImage.removeAttribute('src');
249
+ previewImage.alt = '';
250
+ document.body.style.overflow = previousOverflow;
251
+ };
252
+
253
+ const openPreview = (src, alt) => {
254
+ if (!src) {
255
+ return;
256
+ }
257
+
258
+ previousOverflow = document.body.style.overflow;
259
+ previewImage.src = src;
260
+ previewImage.alt = alt || 'Image preview';
261
+ overlay.classList.add('is-open');
262
+ document.body.style.overflow = 'hidden';
263
+ };
264
+
265
+ const getPreviewCandidate = (target) => {
266
+ const attachment = target.closest('discord-attachment[type="image"]');
267
+ if (attachment) {
268
+ return {
269
+ src: attachment.getAttribute('url') || '',
270
+ alt: attachment.getAttribute('alt') || 'Image preview',
271
+ };
272
+ }
273
+
274
+ const image = target.closest('img');
275
+ if (!image) {
276
+ return null;
277
+ }
278
+
279
+ if (
280
+ image.classList.contains('discord-button-emoji') ||
281
+ image.classList.contains('discord-select-menu-option-emoji') ||
282
+ image.classList.contains('discord-server-tag-badge') ||
283
+ image.classList.contains('discord-author-role-icon') ||
284
+ image.closest(ignoredAncestors)
285
+ ) {
286
+ return null;
287
+ }
288
+
289
+ const src = image.currentSrc || image.getAttribute('src') || '';
290
+ if (!src) {
291
+ return null;
292
+ }
293
+
294
+ return {
295
+ src,
296
+ alt: image.getAttribute('alt') || 'Image preview',
297
+ };
298
+ };
299
+
300
+ document.addEventListener(
301
+ 'click',
302
+ (event) => {
303
+ const target = event.target;
304
+ if (!(target instanceof Element)) {
305
+ return;
306
+ }
307
+
308
+ if (target === overlay || target.closest('.discord-image-preview-close')) {
309
+ event.preventDefault();
310
+ closePreview();
311
+ return;
312
+ }
313
+
314
+ const candidate = getPreviewCandidate(target);
315
+ if (!candidate) {
316
+ return;
317
+ }
318
+
319
+ event.preventDefault();
320
+ event.stopPropagation();
321
+ openPreview(candidate.src, candidate.alt);
322
+ },
323
+ true
324
+ );
325
+
326
+ overlay.querySelector('.discord-image-preview-stage')?.addEventListener('click', (event) => {
327
+ if (event.target === event.currentTarget) {
328
+ closePreview();
329
+ }
330
+ });
331
+
332
+ document.addEventListener('keydown', (event) => {
333
+ if (event.key === 'Escape' && overlay.classList.contains('is-open')) {
334
+ closePreview();
335
+ }
336
+ });
337
+
338
+ if (document.readyState === 'loading') {
339
+ document.addEventListener('DOMContentLoaded', () => document.body.appendChild(overlay), { once: true });
340
+ } else {
341
+ document.body.appendChild(overlay);
342
+ }
343
+ })();
344
+ `;
345
+ exports.enableMessageSearch = `
346
+ (() => {
347
+ const SEARCH_SELECTOR = 'discord-message[id^="m-"]';
348
+ const MATCH_CLASS = 'discord-search-match';
349
+ const ACTIVE_CLASS = 'discord-search-match--active';
350
+ const SHELL_CLASS = 'discord-transcript-search-shell';
351
+ const PANEL_CLASS = 'discord-transcript-search';
352
+ const OPEN_CLASS = 'is-open';
353
+
354
+ const normalize = (value) => value.toLowerCase().replace(/\\s+/g, ' ').trim();
355
+
356
+ const extractMessageId = (value) => {
357
+ const trimmed = value.trim();
358
+ const directMatch = trimmed.match(/^(?:m-)?(\\d{15,21})$/);
359
+ if (directMatch) {
360
+ return directMatch[1];
361
+ }
362
+
363
+ const linkMatch = trimmed.match(/\\/(\\d{15,21})(?:\\/?(?:\\?.*)?)?$/);
364
+ return linkMatch ? linkMatch[1] : null;
365
+ };
366
+
367
+ const getMessages = () =>
368
+ Array.from(document.querySelectorAll(SEARCH_SELECTOR))
369
+ .filter((element) => element instanceof HTMLElement)
370
+ .map((element) => ({
371
+ element,
372
+ id: (element.id || '').replace(/^m-/, ''),
373
+ text: normalize(element.textContent || ''),
374
+ }));
375
+
376
+ const shell = document.createElement('div');
377
+ shell.className = SHELL_CLASS;
378
+ shell.innerHTML =
379
+ '<button class="discord-transcript-search-toggle" type="button" aria-label="Toggle transcript search" aria-expanded="false">' +
380
+ '<svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M10 2a8 8 0 1 1 0 16a8 8 0 0 1 0-16Zm0 2a6 6 0 1 0 0 12a6 6 0 0 0 0-12Zm11.71 15.29a1 1 0 0 1 0 1.42a1 1 0 0 1-1.42 0l-3.4-3.39a1 1 0 0 1 1.42-1.42l3.4 3.39Z"/></svg>' +
381
+ '</button>' +
382
+ '<div class="' +
383
+ PANEL_CLASS +
384
+ '" role="search" aria-hidden="true">' +
385
+ '<label class="discord-transcript-search-bar">' +
386
+ '<input class="discord-transcript-search-input" type="search" aria-label="Search transcript messages" />' +
387
+ '<button class="discord-transcript-search-submit" type="button" data-action="next" aria-label="Search transcript">' +
388
+ '<svg width="16" height="16" viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M10 2a8 8 0 1 1 0 16a8 8 0 0 1 0-16Zm0 2a6 6 0 1 0 0 12a6 6 0 0 0 0-12Zm11.71 15.29a1 1 0 0 1 0 1.42a1 1 0 0 1-1.42 0l-3.4-3.39a1 1 0 0 1 1.42-1.42l3.4 3.39Z"/></svg>' +
389
+ '</button>' +
390
+ '</label>' +
391
+ '<div class="discord-transcript-search-meta">' +
392
+ '<span class="discord-transcript-search-count" aria-live="polite">Ready</span>' +
393
+ '<div class="discord-transcript-search-actions">' +
394
+ '<button class="discord-transcript-search-button" type="button" data-action="prev" aria-label="Previous match">↑</button>' +
395
+ '<button class="discord-transcript-search-button" type="button" data-action="next" aria-label="Next match">↓</button>' +
396
+ '<button class="discord-transcript-search-button discord-transcript-search-button--ghost" type="button" data-action="clear" aria-label="Clear search">✕</button>' +
397
+ '</div>' +
398
+ '</div>' +
399
+ '</div>';
400
+
401
+ const desktopMedia = window.matchMedia('(min-width: 901px)');
402
+ const panel = shell.querySelector('.discord-transcript-search');
403
+ const toggleButton = shell.querySelector('.discord-transcript-search-toggle');
404
+ const input = shell.querySelector('.discord-transcript-search-input');
405
+ const count = shell.querySelector('.discord-transcript-search-count');
406
+ const previousButton = shell.querySelector('[data-action="prev"]');
407
+ const nextButton = shell.querySelectorAll('[data-action="next"]')[1];
408
+ const submitButton = shell.querySelector('.discord-transcript-search-submit');
409
+ const clearButton = shell.querySelector('[data-action="clear"]');
410
+ const headerChannel =
411
+ document.querySelector('.discord-transcript-header-bar')?.getAttribute('data-channel-name') ||
412
+ document.querySelector('discord-header')?.getAttribute('channel') ||
413
+ document.title ||
414
+ 'transcript';
415
+
416
+ let matches = [];
417
+ let activeIndex = -1;
418
+ let scheduled = false;
419
+ let hasUserToggled = false;
420
+
421
+ input.placeholder = 'Search ' + headerChannel;
422
+
423
+ const setOpen = (next, focus = false) => {
424
+ shell.classList.toggle(OPEN_CLASS, next);
425
+ toggleButton.setAttribute('aria-expanded', String(next));
426
+ panel.setAttribute('aria-hidden', String(!next));
427
+
428
+ if (focus && next) {
429
+ requestAnimationFrame(() => {
430
+ input.focus();
431
+ input.select();
432
+ });
433
+ }
434
+
435
+ if (!next) {
436
+ input.blur();
437
+ }
438
+ };
439
+
440
+ const syncDefaultVisibility = (force = false) => {
441
+ if (!force && hasUserToggled) {
442
+ return;
443
+ }
444
+
445
+ setOpen(desktopMedia.matches, false);
446
+ };
447
+
448
+ const clearHighlights = () => {
449
+ document.querySelectorAll(SEARCH_SELECTOR + '.' + MATCH_CLASS).forEach((message) => {
450
+ message.classList.remove(MATCH_CLASS, ACTIVE_CLASS);
451
+ });
452
+ };
453
+
454
+ const updateControls = () => {
455
+ const total = matches.length;
456
+ const query = (input.value || '').trim();
457
+ panel.classList.toggle('has-query', Boolean(query));
458
+ count.textContent =
459
+ !query ? 'Ready' : total > 0 && activeIndex >= 0 ? activeIndex + 1 + ' of ' + total : 'No matches';
460
+ previousButton.disabled = total === 0;
461
+ nextButton.disabled = total === 0;
462
+ clearButton.disabled = !(input.value || '').trim();
463
+ };
464
+
465
+ const focusMatch = (index, scroll = true) => {
466
+ if (matches.length === 0) {
467
+ activeIndex = -1;
468
+ updateControls();
469
+ return;
470
+ }
471
+
472
+ if (activeIndex >= 0 && matches[activeIndex]) {
473
+ matches[activeIndex].element.classList.remove(ACTIVE_CLASS);
474
+ }
475
+
476
+ activeIndex = ((index % matches.length) + matches.length) % matches.length;
477
+ const match = matches[activeIndex];
478
+ match.element.classList.add(ACTIVE_CLASS);
479
+
480
+ if (scroll) {
481
+ match.element.scrollIntoView({ behavior: 'smooth', block: 'center' });
482
+ }
483
+
484
+ updateControls();
485
+ };
486
+
487
+ const runSearch = (scroll = true) => {
488
+ clearHighlights();
489
+ matches = [];
490
+ activeIndex = -1;
491
+
492
+ const rawQuery = (input.value || '').trim();
493
+ if (!rawQuery) {
494
+ updateControls();
495
+ return;
496
+ }
497
+
498
+ const normalizedQuery = normalize(rawQuery.replace(/^m-/, ''));
499
+ const exactMessageId = extractMessageId(rawQuery);
500
+ const availableMessages = getMessages();
501
+
502
+ matches = availableMessages.filter((message) => {
503
+ if (exactMessageId) {
504
+ return message.id === exactMessageId;
505
+ }
506
+
507
+ return message.id.includes(normalizedQuery) || message.text.includes(normalizedQuery);
508
+ });
509
+
510
+ matches.forEach((match) => match.element.classList.add(MATCH_CLASS));
511
+ focusMatch(0, scroll);
512
+ };
513
+
514
+ const scheduleSearchRefresh = () => {
515
+ if (scheduled || !(input.value || '').trim()) {
516
+ return;
517
+ }
518
+
519
+ scheduled = true;
520
+ requestAnimationFrame(() => {
521
+ scheduled = false;
522
+ runSearch(false);
523
+ });
524
+ };
525
+
526
+ input.addEventListener('input', () => runSearch(false));
527
+ input.addEventListener('keydown', (event) => {
528
+ if (event.key === 'Enter') {
529
+ event.preventDefault();
530
+ if (matches.length > 0) {
531
+ focusMatch(activeIndex + (event.shiftKey ? -1 : 1));
532
+ } else {
533
+ runSearch();
534
+ }
535
+ return;
536
+ }
537
+
538
+ if (event.key === 'Escape') {
539
+ if ((input.value || '').trim()) {
540
+ input.value = '';
541
+ runSearch(false);
542
+ } else {
543
+ setOpen(false, false);
544
+ }
545
+ }
546
+ });
547
+
548
+ toggleButton.addEventListener('click', () => {
549
+ hasUserToggled = true;
550
+ setOpen(!shell.classList.contains(OPEN_CLASS), !shell.classList.contains(OPEN_CLASS));
551
+ });
552
+
553
+ previousButton.addEventListener('click', () => focusMatch(activeIndex - 1));
554
+ nextButton.addEventListener('click', () => {
555
+ if (matches.length > 0) {
556
+ focusMatch(activeIndex + 1);
557
+ return;
558
+ }
559
+
560
+ runSearch();
561
+ });
562
+ submitButton.addEventListener('click', () => {
563
+ if (matches.length > 0) {
564
+ focusMatch(activeIndex + 1);
565
+ return;
566
+ }
567
+
568
+ runSearch();
569
+ });
570
+ clearButton.addEventListener('click', () => {
571
+ input.value = '';
572
+ runSearch(false);
573
+ input.focus();
574
+ });
575
+
576
+ document.addEventListener('keydown', (event) => {
577
+ const isFindShortcut = (event.ctrlKey || event.metaKey) && !event.altKey && !event.shiftKey && event.key.toLowerCase() === 'f';
578
+ if (!isFindShortcut) {
579
+ return;
580
+ }
581
+
582
+ event.preventDefault();
583
+ setOpen(true, true);
584
+ });
585
+
586
+ document.addEventListener(
587
+ 'pointerdown',
588
+ (event) => {
589
+ const target = event.target;
590
+ if (!(target instanceof Element) || desktopMedia.matches || !shell.classList.contains(OPEN_CLASS)) {
591
+ return;
592
+ }
593
+
594
+ if (!shell.contains(target)) {
595
+ setOpen(false, false);
596
+ }
597
+ },
598
+ true
599
+ );
600
+
601
+ desktopMedia.addEventListener('change', () => syncDefaultVisibility(false));
602
+
603
+ const mount = () => {
604
+ const mountTarget = document.querySelector('.discord-transcript-header-search-slot') || document.body;
605
+
606
+ if (!mountTarget.contains(shell)) {
607
+ mountTarget.appendChild(shell);
608
+ syncDefaultVisibility(true);
609
+ updateControls();
610
+ }
611
+ };
612
+
613
+ if (document.readyState === 'loading') {
614
+ document.addEventListener('DOMContentLoaded', mount, { once: true });
615
+ } else {
616
+ mount();
617
+ }
618
+
619
+ const transcriptRoot = document.querySelector('discord-messages');
620
+ if (transcriptRoot) {
621
+ new MutationObserver(scheduleSearchRefresh).observe(transcriptRoot, { childList: true, subtree: true });
622
+ }
623
+ })();
624
+ `;
625
+ exports.fixEmbedBorders = 'setTimeout(()=>{document.querySelectorAll(".discord-embed-wrapper").forEach(e=>{e.style.border="1px solid rgba(255, 255, 255, 0.06)";e.style.borderRadius="4px"});},500);setTimeout(()=>{document.querySelectorAll(".discord-embed-wrapper").forEach(e=>{e.style.border="1px solid rgba(255, 255, 255, 0.06)";e.style.borderRadius="4px"});},2000);';
626
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/static/client.ts"],"names":[],"mappings":";;;AAAa,QAAA,eAAe,GAC1B,2ZAA2Z,CAAC;AAEjZ,QAAA,aAAa,GACxB,oQAAoQ,CAAC;AAE1P,QAAA,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0N9B,CAAC;AAEW,QAAA,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuHjC,CAAC;AAEW,QAAA,mBAAmB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuRlC,CAAC;AAEW,QAAA,eAAe,GAC1B,qVAAqV,CAAC"}