-
Notifications
You must be signed in to change notification settings - Fork 1
/
utils.js
157 lines (147 loc) · 4.29 KB
/
utils.js
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
export function makeId(length) {
let result = '';
const characters =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * characters.length));
}
return result;
}
export const makePromise = () => {
let resolve, reject;
const promise = new Promise((a, b) => {
resolve = a;
reject = b;
});
promise.resolve = resolve;
promise.reject = reject;
return promise;
};
export const loadImage = u => {
const p = makePromise();
const img = new Image();
img.crossOrigin = 'Anonymous';
img.onload = () => {
p.resolve(img);
};
img.onerror = p.reject;
img.src = u;
return p;
};
export const capitalize = (s) => s.charAt(0).toUpperCase() + s.slice(1);
export const capitalizeAllWords = (s) => {
let words = s.split(/\s+/);
words = words.map((word) => capitalize(word));
return words.join(" ");
};
export const ensureUrl = async (url) => {
const numRetries = 5;
for (let i = 0; i < numRetries; i++) {
const res = await fetch(url);
if (res.ok) {
return;
} else {
if (res.status === 408) {
continue;
} else {
throw new Error(`invalid status code: ${res.status}`);
}
}
}
};
export const cleanName = (name) => {
name = name.replace(/_/g, " ");
name = capitalizeAllWords(name);
return name;
};
export const isAllCaps = (name) => {
return !/[A-Z]/.test(name) || /^(?:[A-Z]+)$/.test(name);
};
// Format Images
export const formatImages = async (md, type) => {
md = md.replace(/\!\[([^\]]*?)\]\(([^\)]*?)\)/g, (all, title, url) => {
const match = title.match(/^([\s\S]*?)(\|[\s\S]*?)?$/);
if (match) {
title = match[1].trim();
url = match[2] ? match[2].trim() : title;
if (url) {
return `![${title}](/api/images/${type}s/${encodeURIComponent(
url
)}.png)`;
} else {
return null;
}
} else {
return all;
}
});
return md;
};
// Format URLs
export const formatUrls = async (md) => {
md = md.replace(
/(\!?)\[([\s\S]+?)\]\(([\s\S]+?)\)/g,
(all, q, title, url) => {
if (q) {
return all;
}
return `[${title}](${encodeURI(url)})`;
}
);
return md;
};
// Format Sections
// Section Title Separator
const sectionSeperator = "##";
// Title & Description Separator by first ":" in the string
const titleDescriptionSeperator = /:(.*)/s;
export const getSections = async (content) => {
const sections = [];
const sectionsArray = content.split(sectionSeperator);
await sectionsArray.map((section) => {
if (section) {
let sectionItem = {
title: section.split(titleDescriptionSeperator)[0].trim(),
content: section.split(titleDescriptionSeperator)[1].trim(),
};
sections.push(sectionItem);
}
});
return sections;
};
// Fetch Gallery Images as an Array
export const getGalleryArray = async (content) => {
const gallery = [];
const imagesArray = content.match(/\!\[([^\]]*?)\]\(([^\)]*?)\)/g);
if (imagesArray) {
await imagesArray.map((image) => {
const title = image.match(/(?<=\[).+?(?=\])/g)[0];
const url = image.match(/(?<=\().+?(?=\))/g)[0];
let galleryItem = {
caption: title,
url: url,
};
if (url) {
gallery.push(galleryItem);
}
});
}
return gallery;
};
export function mod(v, n) {
return ((v % n) + n) % n;
}
export const modUv = (uv) => {
uv.x = mod(uv.x, 1);
uv.y = mod(uv.y, 1);
return uv;
};
export const fetchArrayBuffer = async srcUrl => {
const res = await fetch(srcUrl);
if (res.ok) {
const arrayBuffer = await res.arrayBuffer();
return arrayBuffer;
} else {
throw new Error('failed to load: ' + res.status + ' ' + srcUrl);
}
};