-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
182 lines (159 loc) · 13.5 KB
/
index.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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
// icons created by https://smashicons.com/
const deletedFileSVGText = '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 58 58" style="enable-background:new 0 0 58 58;" xml:space="preserve"><g><g><polygon style="fill:#EFEBDE;" points="46.5,14 32.5,0 1.5,0 1.5,58 46.5,58 "/><g><path style="fill:#D5D0BB;" d="M11.5,23h25c0.552,0,1-0.447,1-1s-0.448-1-1-1h-25c-0.552,0-1,0.447-1,1S10.948,23,11.5,23z"/><path style="fill:#D5D0BB;" d="M11.5,15h10c0.552,0,1-0.447,1-1s-0.448-1-1-1h-10c-0.552,0-1,0.447-1,1S10.948,15,11.5,15z"/><path style="fill:#D5D0BB;" d="M36.5,29h-25c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S37.052,29,36.5,29z"/><path style="fill:#D5D0BB;" d="M36.5,37h-25c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S37.052,37,36.5,37z"/><path style="fill:#D5D0BB;" d="M36.5,45h-25c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S37.052,45,36.5,45z"/></g><polygon style="fill:#D5D0BB;" points="32.5,0 32.5,14 46.5,14 "/></g><g><circle style="fill:#ED7161;" cx="44.5" cy="46" r="12"/><path style="fill:#FFFFFF;" d="M45.914,46l3.536-3.536c0.391-0.391,0.391-1.023,0-1.414s-1.023-0.391-1.414,0L44.5,44.586 l-3.536-3.536c-0.391-0.391-1.023-0.391-1.414,0s-0.391,1.023,0,1.414L43.086,46l-3.536,3.536c-0.391,0.391-0.391,1.023,0,1.414 c0.195,0.195,0.451,0.293,0.707,0.293s0.512-0.098,0.707-0.293l3.536-3.536l3.536,3.536c0.195,0.195,0.451,0.293,0.707,0.293 s0.512-0.098,0.707-0.293c0.391-0.391,0.391-1.023,0-1.414L45.914,46z"/></g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g></svg>'
const upToDateFileSVGText = '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 58 58" style="enable-background:new 0 0 58 58;" xml:space="preserve"><g><g><polygon style="fill:#EFEBDE;" points="46.5,14 32.5,0 1.5,0 1.5,58 46.5,58 "/><g><path style="fill:#D5D0BB;" d="M11.5,23h25c0.552,0,1-0.447,1-1s-0.448-1-1-1h-25c-0.552,0-1,0.447-1,1S10.948,23,11.5,23z"/><path style="fill:#D5D0BB;" d="M11.5,15h10c0.552,0,1-0.447,1-1s-0.448-1-1-1h-10c-0.552,0-1,0.447-1,1S10.948,15,11.5,15z"/><path style="fill:#D5D0BB;" d="M36.5,29h-25c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S37.052,29,36.5,29z"/><path style="fill:#D5D0BB;" d="M36.5,37h-25c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S37.052,37,36.5,37z"/><path style="fill:#D5D0BB;" d="M36.5,45h-25c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S37.052,45,36.5,45z"/></g><polygon style="fill:#D5D0BB;" points="32.5,0 32.5,14 46.5,14 "/></g><g><circle style="fill:#26B999;" cx="44.5" cy="46" r="12"/><path style="fill:#FFFFFF;" d="M51.071,40.179c-0.455-0.316-1.077-0.204-1.392,0.25l-5.596,8.04l-3.949-3.242 c-0.426-0.351-1.057-0.288-1.407,0.139c-0.351,0.427-0.289,1.057,0.139,1.407l4.786,3.929c0.18,0.147,0.404,0.227,0.634,0.227 c0.045,0,0.091-0.003,0.137-0.009c0.276-0.039,0.524-0.19,0.684-0.419l6.214-8.929C51.636,41.118,51.524,40.495,51.071,40.179z"/></g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g></svg>'
const newerVersionAvailFileSvgText = '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 58 58" style="enable-background:new 0 0 58 58;" xml:space="preserve" width="512" height="512" class=""><g><g><g><polygon style="fill:#EFEBDE;" points="46,14 32,0 1,0 1,58 46,58 " data-original="#EFEBDE" class=""></polygon><g><path style="fill:#D5D0BB;" d="M11,23h25c0.552,0,1-0.447,1-1s-0.448-1-1-1H11c-0.552,0-1,0.447-1,1S10.448,23,11,23z" data-original="#D5D0BB" class=""></path><path style="fill:#D5D0BB;" d="M11,15h10c0.552,0,1-0.447,1-1s-0.448-1-1-1H11c-0.552,0-1,0.447-1,1S10.448,15,11,15z" data-original="#D5D0BB" class=""></path><path style="fill:#D5D0BB;" d="M36,29H11c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S36.552,29,36,29z" data-original="#D5D0BB" class=""></path><path style="fill:#D5D0BB;" d="M36,37H11c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S36.552,37,36,37z" data-original="#D5D0BB" class=""></path><path style="fill:#D5D0BB;" d="M36,45H11c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S36.552,45,36,45z" data-original="#D5D0BB" class=""></path></g><polygon style="fill:#D5D0BB;" points="32,0 32,14 46,14 " data-original="#D5D0BB" class=""></polygon></g><g><circle style="fill:#F29C21" cx="46" cy="47" r="11" data-original="#76C9B0" class="active-path" data-old_color="#76C9B0"></circle><path style="fill:#FFFFFF" d="M52,46h-5v-5c0-0.552-0.447-1-1-1s-1,0.448-1,1v6c0,0.552,0.447,1,1,1h6c0.553,0,1-0.448,1-1 S52.553,46,52,46z" data-original="#FFFFFF" class="" data-old_color="#F29C21"></path></g></g></g></svg>'
const neverExistedFileSVGText = '<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 58 58" style="enable-background:new 0 0 58 58;" xml:space="preserve"><g><g><polygon style="fill:#EFEBDE;" points="45,14 31,0 0,0 0,58 45,58 "/><g><path style="fill:#D5D0BB;" d="M10,23h25c0.552,0,1-0.447,1-1s-0.448-1-1-1H10c-0.552,0-1,0.447-1,1S9.448,23,10,23z"/><path style="fill:#D5D0BB;" d="M10,15h10c0.552,0,1-0.447,1-1s-0.448-1-1-1H10c-0.552,0-1,0.447-1,1S9.448,15,10,15z"/><path style="fill:#D5D0BB;" d="M35,29H10c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S35.552,29,35,29z"/><path style="fill:#D5D0BB;" d="M35,37H10c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S35.552,37,35,37z"/><path style="fill:#D5D0BB;" d="M35,45H10c-0.552,0-1,0.447-1,1s0.448,1,1,1h25c0.552,0,1-0.447,1-1S35.552,45,35,45z"/></g><polygon style="fill:#D5D0BB;" points="31,0 31,14 45,14 "/></g><g><path style="fill:#EFC41A;" d="M56.761,58H33.07c-0.955,0-1.55-1.036-1.069-1.861l11.845-20.306c0.478-0.819,1.66-0.819,2.138,0 L57.83,56.139C58.311,56.964,57.716,58,56.761,58z"/><path style="fill:#FFFFFF;" d="M45,51c-0.552,0-1-0.448-1-1v-8c0-0.552,0.448-1,1-1s1,0.448,1,1v8C46,50.552,45.552,51,45,51z"/><path style="fill:#FFFFFF;" d="M45,55c-0.26,0-0.52-0.11-0.71-0.29C44.11,54.52,44,54.26,44,54c0-0.26,0.11-0.52,0.29-0.71c0.38-0.37,1.04-0.37,1.42,0C45.89,53.48,46,53.74,46,54c0,0.26-0.11,0.52-0.29,0.71C45.52,54.89,45.27,55,45,55z"/></g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g></svg>'
const repoPathFromScriptAttribute = () => {
const currentScript = document.currentScript || Array.prototype.slice.call(document.getElementsByTagName('script')).find(s => s.src.includes('unbreakable-links'))
return currentScript.getAttribute('repoPath')
}
const rawGitLink = (repoPath, filePath, commitHash) => "https://cdn.rawgit.com/" + repoPath + "/" + (commitHash ? commitHash : "master") + "/" + filePath
const load = (repoPath, filePath, commitHash) => {
return // disabled for now
document.body.style.margin = "0 0 0 0px"
const iframe = document.createElement("iframe")
iframe.src = rawGitLink(repoPath, filePath, commitHash)
iframe.style.height = "100%"
iframe.style.width = "100%"
iframe.style.border = "none"
iframe.classList.add('unbreakable-links')
document.body.innerHTML = '';
document.body.appendChild(iframe)
}
const putCommitHashInURL = commitHash => {
const searchParams = new URLSearchParams()
searchParams.set("version", commitHash)
const urlWithoutSearch = window.location.toString().replace(window.location.search, "")
const newURL = urlWithoutSearch + "?" + searchParams.toString()
window.history.replaceState({}, null, newURL) // so as to now cause page to reload
}
const getMostRecentCommits = (repoPath, filePath) => fetch(
'https://exec.clay.run/steve/github-project-data', {
method: "POST",
body: JSON.stringify({
repo: repoPath,
path: filePath
})
})
.then(response => response.json())
const getFileExistsNow = (repoPath, filePath) => fetch(
rawGitLink(repoPath, filePath), {
method: "GET"
})
.then(resp => resp.status == 200)
const showBanner = (repoPath, filePath, status, newCommitHash) => {
return // disabled for now
// TODO add links to newCommitHash page in banner text
const onclick = `onclick="window.location.search = '?version=${newCommitHash}'"`
const bannerText = {
"FILE-NEVER-EXISTED": `This page doesn't exist in our archives.`,
"UP-TO-DATE": `This is the most recent version of this page.`,
"NEWER-VERSION-PAGE-AVAILABLE": `There is <a ${onclick}>a newer version of this page</a>.`,
"NEWER-VERSION-SITE-AVAILABLE": `This is the most recent version of this page, but there is <a ${onclick}>a new version of the site</a>.`,
"DELETED-MOST-RECENT": "This page has been deleted. You are viewing the most-up-to-date archived version.",
"NEWER-VERSION-DELETED-AVAILABLE": `This page has been deleted, but this is not <a ${onclick}>the most up-to-date version in the archive</a>.`
}[status]
const iconDiv = document.createElement('span')
iconDiv.style.width = "30px"
iconDiv.style.display = "inline-block"
iconDiv.innerHTML = {
"FILE-NEVER-EXISTED": neverExistedFileSVGText,
"UP-TO-DATE": upToDateFileSVGText,
"NEWER-VERSION-PAGE-AVAILABLE": newerVersionAvailFileSvgText,
"NEWER-VERSION-SITE-AVAILABLE": newerVersionAvailFileSvgText,
"DELETED-MOST-RECENT": deletedFileSVGText,
"NEWER-VERSION-DELETED-AVAILABLE": deletedFileSVGText
}[status]
const bannerCSS = [
"z-index:2",
"position:absolute",
"top:0px",
"width:100%",
"height: 50px",
"display: flex",
"align-items: center",
"justify-content: center",
// "border: 1px solid lightcyan",
// "background-color: lightblue",
"font-family: sans-serif"
]
const bannerHTML = `<div style="${bannerCSS.join(";")}">
<div>
${iconDiv.outerHTML + bannerText}
</div>
</div>`
document.body.innerHTML += bannerHTML
}
const filePathFromRepoPath = repoPath => {
const [userName, repoName] = repoPath.split("/")
const repoNameIndexInURLPath = window.location.pathname.indexOf(repoName + "/")
return repoNameIndexInURLPath == -1 ? window.location.pathname : window.location.pathname.substring(repoNameIndexInURLPath + (repoName + "/").length)
}
window.addEventListener("load", () => {
// do nothing if this library is being loaded inside itself
if (window.frameElement && window.frameElement.classList.contains('unbreakable-links')) { return }
const commitHashInURL = new URLSearchParams(window.location.search).get("version")
const repoPath = repoPathFromScriptAttribute()
if (!repoPath || !repoPath.includes("/")) {
throw new Error('You need to add a repoPath="" attribute with a valid github repo path to the <script> tag that contains this library. For example for http://github.com/stevekrouse/unbreakable-links, it would be repoPath="stevekrouse/unbreakable-links".')
}
const filePath = filePathFromRepoPath(repoPath)
const requests = [
getMostRecentCommits(repoPath),
getMostRecentCommits(repoPath, filePath),
getFileExistsNow(repoPath, filePath)
]
Promise.all(requests).then(([
mostRecentCommits,
mostRecentFileCommits,
fileExistsNow
]) => {
const fileNeverExisted = mostRecentFileCommits.length === 0
const mostRecentCommitHash = mostRecentCommits[0].sha
const mostRecentFileCommitHash = mostRecentFileCommits[0].sha
const mostRecentFileCommitHashBeforeDeletion = mostRecentFileCommits.length > 1 && mostRecentFileCommits[1].sha
const commitHashInURLOldForPage = mostRecentFileCommits.map(c => c.sha).includes(commitHashInURL) && commitHashInURL != mostRecentFileCommitHash
const commitHashInURLOldForSite = commitHashInURL != mostRecentCommitHash
if (fileNeverExisted) {
showBanner(repoPath, filePath, "FILE-NEVER-EXISTED")
return
}
if (fileExistsNow && !commitHashInURL) {
putCommitHashInURL(mostRecentCommitHash)
load(repoPath, filePath, mostRecentCommitHash)
showBanner(repoPath, filePath, "UP-TO-DATE")
return
}
if (fileExistsNow && commitHashInURL && commitHashInURLOldForPage) {
load(repoPath, filePath, commitHashInURL)
showBanner(repoPath, filePath, "NEWER-VERSION-PAGE-AVAILABLE", mostRecentFileCommitHash)
return
}
if (fileExistsNow && commitHashInURL && !commitHashInURLOldForPage && commitHashInURLOldForSite) {
load(repoPath, filePath, commitHashInURL)
showBanner(repoPath, filePath, "NEWER-VERSION-SITE-AVAILABLE", mostRecentCommitHash)
return
}
if (fileExistsNow && commitHashInURL && commitHashInURL == mostRecentCommitHash) {
// we load even when we technically don't need to here for consistancy
load(repoPath, filePath, commitHashInURL)
showBanner(repoPath, filePath, "UP-TO-DATE")
return
}
if (!fileNeverExisted && !fileExistsNow && !commitHashInURL) {
putCommitHashInURL(mostRecentFileCommitHashBeforeDeletion)
load(repoPath, filePath, mostRecentFileCommitHashBeforeDeletion)
showBanner(repoPath, filePath, "DELETED-MOST-RECENT")
}
if (!fileNeverExisted && !fileExistsNow && commitHashInURL && commitHashInURL == mostRecentFileCommitHashBeforeDeletion) {
load(repoPath, filePath, mostRecentFileCommitHashBeforeDeletion)
showBanner(repoPath, filePath, "DELETED-MOST-RECENT")
return
}
if (!fileNeverExisted && !fileExistsNow && commitHashInURL !== mostRecentFileCommitHashBeforeDeletion) {
load(repoPath, filePath, mostRecentFileCommitHashBeforeDeletion)
showBanner(repoPath, filePath, "NEWER-VERSION-DELETED-AVAILABLE", mostRecentFileCommitHashBeforeDeletion)
return
}
})
})