-
Notifications
You must be signed in to change notification settings - Fork 462
Expand file tree
/
Copy pathicons.tsx
More file actions
120 lines (105 loc) · 2.97 KB
/
icons.tsx
File metadata and controls
120 lines (105 loc) · 2.97 KB
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
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import type {
Action,
ThunkAction,
IconWithClassName,
} from 'firefox-profiler/types';
import { assertExhaustiveCheck } from 'firefox-profiler/utils/types';
export function iconHasLoaded(iconWithClassName: {
readonly icon: string;
readonly className: string;
}): Action {
return {
type: 'ICON_HAS_LOADED',
iconWithClassName,
};
}
export function iconIsInError(icon: string): Action {
return {
type: 'ICON_IN_ERROR',
icon,
};
}
const icons: Set<string> = new Set<string>();
let iconCounter = 0;
type IconRequestResult =
| { type: 'error' | 'cached' }
| {
type: 'loaded';
iconWithClassName: IconWithClassName;
};
async function _getIcon(icon: string): Promise<IconRequestResult> {
if (icons.has(icon)) {
return Promise.resolve({ type: 'cached' });
}
icons.add(icon);
// New class name for an icon. They are guaranteed to be unique, that's why
// just increment the icon counter and return that string.
const className = `favicon-${++iconCounter}`;
const result = new Promise<IconRequestResult>((resolve) => {
const image = new Image();
image.src = icon;
image.referrerPolicy = 'no-referrer';
image.onload = () => {
resolve({ type: 'loaded', iconWithClassName: { icon, className } });
};
image.onerror = () => {
resolve({ type: 'error' });
};
});
return result;
}
export function iconStartLoading(icon: string): ThunkAction<Promise<void>> {
return (dispatch) => {
return _getIcon(icon).then((result) => {
switch (result.type) {
case 'loaded':
dispatch(iconHasLoaded(result.iconWithClassName));
break;
case 'error':
dispatch(iconIsInError(icon));
break;
case 'cached':
// nothing to do
break;
default:
throw assertExhaustiveCheck(result, 'Unknown icon load result');
}
});
};
}
/**
* Batch load the data url icons.
*
* We don't need to check if they are valid images or not, so we can omit doing
* this extra work for these icons. Just add them directly to our cache and state.
*/
export function batchLoadDataUrlIcons(
iconsToAdd: Array<string | null>
): ThunkAction<void> {
return (dispatch) => {
const newIcons = [];
for (const icon of iconsToAdd) {
if (!icon || icons.has(icon)) {
continue;
}
icons.add(icon);
// New class name for an icon. They are guaranteed to be unique, that's why
// just increment the icon counter and return that string.
const className = `favicon-${++iconCounter}`;
newIcons.push({ icon, className });
}
dispatch({
type: 'ICON_BATCH_ADD',
icons: newIcons,
});
};
}
/**
* Only use it in tests!
*/
export function _resetIconCounter() {
iconCounter = 0;
}