forked from giscus/giscus
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathclient.ts
156 lines (136 loc) · 5.04 KB
/
client.ts
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
const GISCUS_SESSION_KEY = 'giscus-session';
const script = document.currentScript as HTMLScriptElement;
const giscusOrigin = new URL(script.src).origin;
function formatError(message: string) {
return `[giscus] An error occurred. Error message: "${message}".`;
}
// Set up iframeResizer
declare let iFrameResize: (options: Record<string, unknown>, selector: string) => void;
function loadScript(url: string, callback: VoidFunction) {
const target = document.createElement('script');
target.setAttribute('src', url);
target.onload = callback;
script.insertAdjacentElement('beforeend', target);
}
loadScript('https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.3.1/iframeResizer.min.js', () =>
iFrameResize({ checkOrigin: [giscusOrigin], resizeFrom: 'child' }, '.giscus-frame'),
);
// Set up iframe src URL and params
const url = new URL(location.href);
let session = url.searchParams.get('giscus');
const savedSession = localStorage.getItem(GISCUS_SESSION_KEY);
if (session) {
localStorage.setItem(GISCUS_SESSION_KEY, JSON.stringify(session));
url.searchParams.delete('giscus');
history.replaceState(undefined, document.title, url.toString());
} else {
try {
session = JSON.parse(savedSession) || '';
} catch (e) {
session = '';
localStorage.removeItem(GISCUS_SESSION_KEY);
console.warn(`${formatError(e?.message)} Session has been cleared.`);
}
}
const attributes = script.dataset;
const params: Record<string, string> = {};
const ogDescriptionMeta = document.querySelector(
`meta[property='og:description'],meta[name='description']`,
) as HTMLMetaElement;
params.origin = location.href;
params.session = session;
params.theme = attributes.theme;
params.reactionsEnabled = attributes.reactionsEnabled || '1';
params.emitMetadata = attributes.emitMetadata || '0';
params.repo = attributes.repo;
params.repoId = attributes.repoId;
params.category = attributes.category || '';
params.categoryId = attributes.categoryId;
params.description = ogDescriptionMeta ? ogDescriptionMeta.content : '';
switch (attributes.mapping) {
case 'url':
params.term = location.href;
break;
case 'title':
params.term = document.title;
break;
case 'og:title':
{
const ogtitleMeta = document.querySelector(
`meta[property='og:title'],meta[name='og:title']`,
) as HTMLMetaElement;
params.term = ogtitleMeta ? ogtitleMeta.content : '';
}
break;
case 'specific':
params.term = attributes.term;
break;
case 'number':
params.number = attributes.term;
break;
case 'pathname':
default:
params.term =
location.pathname.length < 2 ? 'index' : location.pathname.substr(1).replace(/\.\w+$/, '');
break;
}
const src = `${giscusOrigin}/widget?${new URLSearchParams(params)}`;
// Set up iframe element
const iframeElement = document.createElement('iframe');
const iframeAttributes = {
class: 'giscus-frame',
title: 'Comments',
scrolling: 'no',
src,
};
Object.entries(iframeAttributes).forEach(([key, value]) => iframeElement.setAttribute(key, value));
// Create default style and prepend as <head>'s first child to make override possible.
const style = document.getElementById('giscus-css') || document.createElement('style');
style.id = 'giscus-css';
style.textContent = `
.giscus, .giscus-frame {
width: 100%;
}
.giscus-frame {
border: none;
color-scheme: auto;
}
`;
document.head.prepend(style);
// Insert iframe element
const existingContainer = document.querySelector('.giscus');
if (!existingContainer) {
const iframeContainer = document.createElement('div');
iframeContainer.setAttribute('class', 'giscus');
iframeContainer.appendChild(iframeElement);
script.insertAdjacentElement('afterend', iframeContainer);
} else {
while (existingContainer.firstChild) existingContainer.firstChild.remove();
existingContainer.appendChild(iframeElement);
}
const suggestion = `Please consider reporting this error at https://github.com/laymonage/giscus/issues/new.`;
// Listen to error messages
window.addEventListener('message', (event) => {
if (event.origin !== giscusOrigin) return;
const { data } = event;
if (!(typeof data === 'object' && data?.giscus?.error)) return;
const message: string = data.giscus.error;
if (message.includes('Bad credentials') || message.includes('Invalid state value')) {
// Might be because token is expired or other causes
if (localStorage.getItem(GISCUS_SESSION_KEY) !== null) {
localStorage.removeItem(GISCUS_SESSION_KEY);
console.warn(`${formatError(message)} Session has been cleared.`);
delete params.session;
const src = `${giscusOrigin}/widget?${new URLSearchParams(params)}`;
iframeElement.src = src; // Force reload
} else if (!savedSession) {
console.error(`${formatError(message)} No session is stored initially. ${suggestion}`);
}
} else if (message.includes('Discussion not found')) {
console.warn(
`[giscus] ${message}. A new discussion will be created if a comment/reaction is submitted.`,
);
} else {
console.error(`${formatError(message)} ${suggestion}`);
}
});