-
-
Notifications
You must be signed in to change notification settings - Fork 229
/
Copy pathformatting.tsx
91 lines (79 loc) · 3.26 KB
/
formatting.tsx
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
import cheerio from "cheerio"
import { FormattedPost, Country, capitalize, Url } from "@ourworldindata/utils"
import { countryProfileDefaultCountryPlaceholder } from "../site/countryProfileProjects.js"
import { BAKED_BASE_URL } from "../settings/serverSettings.js"
import { getBodyHtml } from "../site/formatting.js"
import path from "path"
export const DEEP_LINK_CLASS = "deep-link"
export const formatCountryProfile = (
post: FormattedPost,
country: Country
): FormattedPost => {
// Localize country selector
const htmlWithLocalizedCountrySelector = post.html.replace(
countryProfileDefaultCountryPlaceholder,
country.code
)
const cheerioEl = cheerio.load(htmlWithLocalizedCountrySelector)
// Inject country names on h3 headings which have been already identified as subsections
// (filtering them out based on whether they have a deep link anchor attached to them)
cheerioEl(`h3 a.${DEEP_LINK_CLASS}`).each((_, deepLinkAnchor) => {
const $deepLinkAnchor = cheerioEl(deepLinkAnchor)
$deepLinkAnchor.parent().prepend(`${country.name}: `)
})
return { ...post, html: getBodyHtml(cheerioEl) }
}
// Assumes formatUrls URL standardisation
export const isCanonicalInternalUrl = (url: Url): boolean => {
if (!url.originAndPath) return false
// no origin === links without e.g. https://ourworldindata.org
return !url.origin || url.origin.startsWith(BAKED_BASE_URL)
}
/**
* Format images
*
* Assumptions:
* - original images are not uploaded with a suffix "-[number]x[number]"
* (without the quotes).
* - variants are being generated by wordpress when the original is uploaded
* - images are never legitimate direct descendants of <a> tags. <a><img /></a>
* is considered deprecated (was used to create direct links to the full
* resolution variant) and wrapping <a> will be removed to prevent conflicts
* with lightboxes. Chosen over preventDefault() in front-end code to avoid
* clicks before javascript executes.
*/
export const formatImages = ($: CheerioStatic) => {
for (const el of $("img").toArray()) {
const $el = $(el)
if ($el.closest("[data-no-img-formatting]").length) continue
// Recreate source image path by removing automatically added image
// dimensions (e.g. remove 800x600).
const src = el.attribs["src"]
const parsedPath = path.parse(src)
let originalFilename = ""
if (parsedPath.ext !== ".svg") {
originalFilename = parsedPath.name.replace(/-\d+x\d+$/, "")
const originalSrc = path.format({
dir: parsedPath.dir,
name: originalFilename,
ext: parsedPath.ext,
})
el.attribs["data-high-res-src"] = originalSrc
} else {
originalFilename = parsedPath.name
}
// Remove wrapping <a> tag, conflicting with lightbox (cf. assumptions above)
if (el.parent.tagName === "a") {
const $a = $(el.parent)
$a.replaceWith($el)
}
if (!el.attribs["alt"]) {
el.attribs["alt"] = capitalize(
originalFilename.replace(/[-_]/g, " ")
)
}
if (!el.attribs["loading"]) {
el.attribs["loading"] = "lazy"
}
}
}