add hw2
This commit is contained in:
205
node_modules/html-to-image/es/embed-webfonts.js
generated
vendored
Normal file
205
node_modules/html-to-image/es/embed-webfonts.js
generated
vendored
Normal file
@@ -0,0 +1,205 @@
|
||||
import { toArray } from './util';
|
||||
import { fetchAsDataURL } from './dataurl';
|
||||
import { shouldEmbed, embedResources } from './embed-resources';
|
||||
const cssFetchCache = {};
|
||||
async function fetchCSS(url) {
|
||||
let cache = cssFetchCache[url];
|
||||
if (cache != null) {
|
||||
return cache;
|
||||
}
|
||||
const res = await fetch(url);
|
||||
const cssText = await res.text();
|
||||
cache = { url, cssText };
|
||||
cssFetchCache[url] = cache;
|
||||
return cache;
|
||||
}
|
||||
async function embedFonts(data, options) {
|
||||
let cssText = data.cssText;
|
||||
const regexUrl = /url\(["']?([^"')]+)["']?\)/g;
|
||||
const fontLocs = cssText.match(/url\([^)]+\)/g) || [];
|
||||
const loadFonts = fontLocs.map(async (loc) => {
|
||||
let url = loc.replace(regexUrl, '$1');
|
||||
if (!url.startsWith('https://')) {
|
||||
url = new URL(url, data.url).href;
|
||||
}
|
||||
return fetchAsDataURL(url, options.fetchRequestInit, ({ result }) => {
|
||||
cssText = cssText.replace(loc, `url(${result})`);
|
||||
return [loc, result];
|
||||
});
|
||||
});
|
||||
return Promise.all(loadFonts).then(() => cssText);
|
||||
}
|
||||
function parseCSS(source) {
|
||||
if (source == null) {
|
||||
return [];
|
||||
}
|
||||
const result = [];
|
||||
const commentsRegex = /(\/\*[\s\S]*?\*\/)/gi;
|
||||
// strip out comments
|
||||
let cssText = source.replace(commentsRegex, '');
|
||||
// eslint-disable-next-line prefer-regex-literals
|
||||
const keyframesRegex = new RegExp('((@.*?keyframes [\\s\\S]*?){([\\s\\S]*?}\\s*?)})', 'gi');
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
const matches = keyframesRegex.exec(cssText);
|
||||
if (matches === null) {
|
||||
break;
|
||||
}
|
||||
result.push(matches[0]);
|
||||
}
|
||||
cssText = cssText.replace(keyframesRegex, '');
|
||||
const importRegex = /@import[\s\S]*?url\([^)]*\)[\s\S]*?;/gi;
|
||||
// to match css & media queries together
|
||||
const combinedCSSRegex = '((\\s*?(?:\\/\\*[\\s\\S]*?\\*\\/)?\\s*?@media[\\s\\S]' +
|
||||
'*?){([\\s\\S]*?)}\\s*?})|(([\\s\\S]*?){([\\s\\S]*?)})';
|
||||
// unified regex
|
||||
const unifiedRegex = new RegExp(combinedCSSRegex, 'gi');
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
let matches = importRegex.exec(cssText);
|
||||
if (matches === null) {
|
||||
matches = unifiedRegex.exec(cssText);
|
||||
if (matches === null) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
importRegex.lastIndex = unifiedRegex.lastIndex;
|
||||
}
|
||||
}
|
||||
else {
|
||||
unifiedRegex.lastIndex = importRegex.lastIndex;
|
||||
}
|
||||
result.push(matches[0]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
async function getCSSRules(styleSheets, options) {
|
||||
const ret = [];
|
||||
const deferreds = [];
|
||||
// First loop inlines imports
|
||||
styleSheets.forEach((sheet) => {
|
||||
if ('cssRules' in sheet) {
|
||||
try {
|
||||
toArray(sheet.cssRules || []).forEach((item, index) => {
|
||||
if (item.type === CSSRule.IMPORT_RULE) {
|
||||
let importIndex = index + 1;
|
||||
const url = item.href;
|
||||
const deferred = fetchCSS(url)
|
||||
.then((metadata) => embedFonts(metadata, options))
|
||||
.then((cssText) => parseCSS(cssText).forEach((rule) => {
|
||||
try {
|
||||
sheet.insertRule(rule, rule.startsWith('@import')
|
||||
? (importIndex += 1)
|
||||
: sheet.cssRules.length);
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error inserting rule from remote css', {
|
||||
rule,
|
||||
error,
|
||||
});
|
||||
}
|
||||
}))
|
||||
.catch((e) => {
|
||||
console.error('Error loading remote css', e.toString());
|
||||
});
|
||||
deferreds.push(deferred);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
const inline = styleSheets.find((a) => a.href == null) || document.styleSheets[0];
|
||||
if (sheet.href != null) {
|
||||
deferreds.push(fetchCSS(sheet.href)
|
||||
.then((metadata) => embedFonts(metadata, options))
|
||||
.then((cssText) => parseCSS(cssText).forEach((rule) => {
|
||||
inline.insertRule(rule, inline.cssRules.length);
|
||||
}))
|
||||
.catch((err) => {
|
||||
console.error('Error loading remote stylesheet', err);
|
||||
}));
|
||||
}
|
||||
console.error('Error inlining remote css file', e);
|
||||
}
|
||||
}
|
||||
});
|
||||
return Promise.all(deferreds).then(() => {
|
||||
// Second loop parses rules
|
||||
styleSheets.forEach((sheet) => {
|
||||
if ('cssRules' in sheet) {
|
||||
try {
|
||||
toArray(sheet.cssRules || []).forEach((item) => {
|
||||
ret.push(item);
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
console.error(`Error while reading CSS rules from ${sheet.href}`, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
});
|
||||
}
|
||||
function getWebFontRules(cssRules) {
|
||||
return cssRules
|
||||
.filter((rule) => rule.type === CSSRule.FONT_FACE_RULE)
|
||||
.filter((rule) => shouldEmbed(rule.style.getPropertyValue('src')));
|
||||
}
|
||||
async function parseWebFontRules(node, options) {
|
||||
if (node.ownerDocument == null) {
|
||||
throw new Error('Provided element is not within a Document');
|
||||
}
|
||||
const styleSheets = toArray(node.ownerDocument.styleSheets);
|
||||
const cssRules = await getCSSRules(styleSheets, options);
|
||||
return getWebFontRules(cssRules);
|
||||
}
|
||||
function normalizeFontFamily(font) {
|
||||
return font.trim().replace(/["']/g, '');
|
||||
}
|
||||
function getUsedFonts(node) {
|
||||
const fonts = new Set();
|
||||
function traverse(node) {
|
||||
const fontFamily = node.style.fontFamily || getComputedStyle(node).fontFamily;
|
||||
fontFamily.split(',').forEach((font) => {
|
||||
fonts.add(normalizeFontFamily(font));
|
||||
});
|
||||
Array.from(node.children).forEach((child) => {
|
||||
if (child instanceof HTMLElement) {
|
||||
traverse(child);
|
||||
}
|
||||
});
|
||||
}
|
||||
traverse(node);
|
||||
return fonts;
|
||||
}
|
||||
export async function getWebFontCSS(node, options) {
|
||||
const rules = await parseWebFontRules(node, options);
|
||||
const usedFonts = getUsedFonts(node);
|
||||
const cssTexts = await Promise.all(rules
|
||||
.filter((rule) => usedFonts.has(normalizeFontFamily(rule.style.fontFamily)))
|
||||
.map((rule) => {
|
||||
const baseUrl = rule.parentStyleSheet
|
||||
? rule.parentStyleSheet.href
|
||||
: null;
|
||||
return embedResources(rule.cssText, baseUrl, options);
|
||||
}));
|
||||
return cssTexts.join('\n');
|
||||
}
|
||||
export async function embedWebFonts(clonedNode, options) {
|
||||
const cssText = options.fontEmbedCSS != null
|
||||
? options.fontEmbedCSS
|
||||
: options.skipFonts
|
||||
? null
|
||||
: await getWebFontCSS(clonedNode, options);
|
||||
if (cssText) {
|
||||
const styleNode = document.createElement('style');
|
||||
const sytleContent = document.createTextNode(cssText);
|
||||
styleNode.appendChild(sytleContent);
|
||||
if (clonedNode.firstChild) {
|
||||
clonedNode.insertBefore(styleNode, clonedNode.firstChild);
|
||||
}
|
||||
else {
|
||||
clonedNode.appendChild(styleNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=embed-webfonts.js.map
|
||||
Reference in New Issue
Block a user