-
-
Notifications
You must be signed in to change notification settings - Fork 18
/
content.ts
163 lines (137 loc) · 4.85 KB
/
content.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
157
158
159
160
161
162
163
// import { v4 as uuidv4 } from 'uuid';
import {
type ShowdexEventDetail,
createShowdexEvent,
env,
getShowdexEventName,
} from '@showdex/utils/core';
import { logger } from '@showdex/utils/debug';
interface ContentInjectable<T = unknown> {
id: string;
component: keyof JSX.IntrinsicElements;
into: keyof JSX.IntrinsicElements;
props?: Partial<T extends keyof JSX.IntrinsicElements ? JSX.IntrinsicElements[T] : T>;
}
const l = logger('@showdex/content');
const { runtime } = chrome || browser;
if (typeof document === 'undefined' || !runtime?.id) {
l.error('Extension will not run properly since no valid runtime.id was found!');
throw new Error('Did you forget this is a WebExtension? :o');
}
// obtain the extension runtime ID with this one simple trick
// (using runtime.id will work on Chrome, but not on Firefox since it'll return the ID defined in the manifest)
// (e.g., 'chrome-extension://dabpnahpcemkfbgfbmegmncjllieilai/main.js', 'moz-extension://81b2e17b-928f-4689-a33f-501eae139258/main.js')
const mainUrl = runtime.getURL('main.js');
const extensionId = mainUrl?.endsWith('main.js')
? mainUrl.split('/')[2] // e.g., ['chrome-extension:', '', 'dabpnahpcemkfbgfbmegmncjllieilai', 'main.js']
: runtime.id;
const injectables: ContentInjectable<HTMLElement>[] = [
{
id: 'showdex-preconnect-googleapis',
component: 'link',
into: 'head',
props: {
rel: 'preconnect',
href: 'https://fonts.googleapis.com',
},
} as ContentInjectable<HTMLLinkElement>,
{
id: 'showdex-stylesheet-work-sans',
component: 'link',
into: 'head',
props: {
rel: 'stylesheet',
href: 'https://fonts.googleapis.com/css2?family=Work+Sans:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap',
},
} as ContentInjectable<HTMLLinkElement>,
{
id: 'showdex-stylesheet-fira-code',
component: 'link',
into: 'head',
props: {
rel: 'stylesheet',
href: 'https://fonts.googleapis.com/css2?family=Fira+Code:wght@300;400;500;600;700&display=swap',
},
} as ContentInjectable<HTMLLinkElement>,
{
id: 'showdex-script-main',
component: 'script',
into: 'body',
props: {
src: mainUrl,
async: true,
'data-ext-id': extensionId,
},
} as ContentInjectable<HTMLScriptElement>,
];
l.info(
'Starting Showdex for', env('build-target', 'probably chrome??'),
'with extension ID', extensionId, 'and runtime.id', runtime.id,
);
l.debug('Injecting the following injectables:', injectables);
injectables.forEach(({
id,
component,
into,
props,
}) => {
const source = document.getElementById(id) || document.createElement(component);
const destination = into === 'head' ? document.head : document.body;
if (source.id !== id) {
source.id = id;
}
Object.entries(props).forEach(([key, value]) => {
if (value !== undefined) {
source.setAttribute(key, value as string);
}
});
// l.debug('Injecting', source, 'into', destination, 'with props', props);
destination.appendChild(source);
});
// Firefox needs this for importing settings from the clipboard
// cause they don't support navigator.clipboard.getText() yet lmao
// (at the time of writing of course)
// found this at the wayyyy bottom of the MDN docs for readText(),
// specifically in the browser compatibility section after clicking on the lil asterisk:
// https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/readText#browser_compatibility
// "Firefox only supports reading the clipboard in browser extensions,
// "using the "clipboardRead" extension permission." ... LOL
if (env('build-target') === 'firefox') {
l.debug('Adding onShowdexRequest event handler');
window.addEventListener(getShowdexEventName('request'), (e: CustomEvent<ShowdexEventDetail>) => {
l.debug(
'Received onShowdexRequest event', e?.detail?.type || '(missing event.detail.type)',
'\n', 'event', e,
);
if (e?.detail?.type !== 'clipboardReadText') {
return;
}
void (async () => {
l.debug(
'Sending message to background script via browser.runtime.sendMessage()',
'\n', 'event.detail.type', e.detail.type,
'\n', 'event', e,
);
try {
const response = await navigator.clipboard.readText();
l.debug(
'Firing onShowdexResponse for', e.detail.type,
'\n', 'response', response,
);
window.dispatchEvent(createShowdexEvent('response', {
type: 'clipboardReadText',
payload: response,
}));
} catch (error) {
if (__DEV__) {
l.error(
'Failed to handle message event', `${e.type || '(missing event.type)'}:`,
'\n', error,
'\n', 'event', e,
'\n', '(You will only see this error on development.)',
);
}
}
})();
});
}