123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 |
- /*
- * Git HTML Archive Viewer
- *
- * Benedikt Bieringer <benedikt.b@wwu.de>
- * https://nuserv.uni-muenster.de:8443/bbieringer/statusarchiveviewer
- */
- class ArchiveCommit {
- constructor(message, time, sha) {
- this.message = message
- this.time = time
- this.sha = sha
- }
- }
- function replace_urls(text, url_before, url_after) {
- for(const key of ["src=\""]) {
- segments = text.split(key)
- result_text = segments[0]
- for(const segment of segments.slice(1)) {
- var index = segment.indexOf('"')
- var first = segment.substring(0, index)
- var second = segment.substring(index)
-
- var new_url = url_before + encodeURIComponent(first) + url_after
-
- result_text += key + new_url + second
- }
-
- text = result_text
- }
-
- return text
- }
- function hide_iframes(text) {
- return text.replaceAll("<iframe", "<div hidden ").replaceAll("/iframe>", "/div>")
- }
- function date_to_iso(value) {
- console.log(value)
- if ((value + "").includes("-")) {
- return value
- }
-
- var date = new Date(parseInt(value)*1000)
- return date.toISOString().substring(0,16)
- }
- function date_to_unix(value) {
- return parseInt(new Date(value + ":00+00:00").getTime() / 1000)
- }
- class ArchiveView {
- constructor(mindate, maindiv, token, url, project_id, branch, page_path, index) {
-
- this.token = token
- this.url = url
- this.project_id = project_id
- this.branch = branch
-
- this.maindiv = maindiv
-
- var outer_span = document.createElement("span")
- this.maindiv.appendChild(outer_span)
-
- // ---
-
- this.selecttype = document.createElement("select")
- outer_span.appendChild(this.selecttype)
-
- var option_date = document.createElement("option")
- option_date.value = "date"
- option_date.innerHTML = "Date"
- this.selecttype.appendChild(option_date)
-
- var option_range = document.createElement("option")
- option_range.value = "range"
- option_range.innerHTML = "Range"
- this.selecttype.appendChild(option_range)
-
- this.selecttype.addEventListener("input",(() => this.on_selecttype_selected()))
-
- // ---
-
- outer_span.append(" (" + mindate + " to today): ")
-
- this.dateselector = document.createElement("input")
- this.dateselector.type = "date"
-
- // Alternative, doesn't allow selecting today in first two hours of day:
- // var maxdate = new Date().toISOString().split("T")[0]
- var maxdate = new Date().toLocaleDateString('en-ca')
- this.dateselector.value = ""
- this.dateselector.max = maxdate
- this.dateselector.addEventListener("input",((event) => this.on_date_selected(event)))
-
- outer_span.appendChild(this.dateselector)
-
- // ---
-
- this.rangespan = document.createElement("span")
- outer_span.appendChild(this.rangespan)
-
-
- this.range_from = document.createElement("input")
- this.range_from.type = "datetime-local"
-
- this.range_from.value = ""
- this.range_from.min = mindate + "T00:00"
- this.range_from.max = maxdate + "T23:59"
- this.range_from.addEventListener("input",(() => this.on_range_from_selected()))
-
- this.rangespan.appendChild(this.range_from)
-
-
- this.rangespan.insertAdjacentHTML('beforeend', " – ")
-
-
- this.range_to = document.createElement("input")
- this.range_to.type = "datetime-local"
- this.range_to.disabled = true
-
- this.range_to.value = ""
- this.range_to.max = maxdate + "T23:59"
- this.range_to.addEventListener("input",(() => this.on_range_to_selected()))
- this.rangespan.appendChild(this.range_to)
-
- // ---
-
- outer_span.append(" | Version: ")
-
- this.commitsSelect = document.createElement("select")
- this.commitsSelect.className = "archive commits"
- this.commitsSelect.addEventListener("input",(() => this.on_commit_selected()))
- outer_span.appendChild(this.commitsSelect)
-
- outer_span.insertAdjacentHTML('beforeend', "<br/><i>Note: Large time ranges can slow the version selection down.</i>")
-
- // ---
-
- this.content = document.createElement("iframe")
- this.content.className = "archive content"
- this.content.height = "100%"
-
- this.maindiv.appendChild(this.content)
-
- this.page_path = page_path
-
- this.index = index
-
- const blobContent = new Blob([`
- <!doctype html><html><head>
- <style>
- body {
- min-height: 100vh;
- display: flex;
- align-items: center;
- justify-content: space-around;
- }
-
- h1,h2 {
- display: flex;
- align-items: center;
- justify-content: center;
- }
- </style>
- </head>
- <body style="background:#aaa; color:#fff;">
- <div>
- <h1>Welcome to the archive viewer!</h1>
- <h2>Select a date and version to start.</h2>
- </div>
- </body>
- </html>
- `], {type: "text/html"})
- this.content.src = URL.createObjectURL(blobContent)
-
- window.addEventListener('hashchange', (event) => this.on_hash_changed(event))
-
- // Updates
- this.on_hash_changed(null)
- this.on_selecttype_selected() // Update visibilities
- this.load_pages() // Update version list
- }
-
- on_hash_changed(event) {
- var remaining_hash = window.location.hash.substring(1).split("&")
-
- var date_from = null
- var length = null
- var to = null
-
- var provided_full_range = false;
- while (remaining_hash.length > 0) {
- var current_part = remaining_hash.pop()
-
- var [key, value] = current_part.split("=")
-
- if (key == "from") {
- date_from = value
- }
- else if (key == "length") {
- length = value
- }
- else if (key == "to") {
- to = value
- }
- }
-
- if (date_from != null) {
- this.selecttype.value = "range"
- var from_iso = date_to_iso(date_from)
- console.log(date_from, from_iso)
- this.range_from.value = from_iso
- this.on_range_from_selected()
-
- if (length != null) {
- // Only works when given UNIX timestamps
- console.log(from_iso)
- console.log(from_iso,date_to_iso(date_to_unix(from_iso)))
- this.range_to.value = date_to_iso(date_to_unix(from_iso)+parseInt(length))
- provided_full_range = true
- }
- }
-
- if (to != null) {
- if (date_from != nullptr) {
- provided_full_range = true
- }
-
- this.selecttype.value = "range"
- this.on_selecttype_selected() // Update visibilities
- this.range_to.value = date_to_iso(to)
- }
-
- if (provided_full_range) {
- this.load_pages(true)
- }
- }
-
- add_commits(commits, open_first) {
- var to_open = open_first
- commits.map(commit => {
- var elem = document.createElement("option")
- elem.innerHTML = commit.message
- elem.value = commit.sha
- this.commitsSelect.appendChild(elem)
-
- if (to_open) {
- this.commitsSelect.value = elem.value
- this.on_commit_selected()
- to_open = false
- }
- })
- }
-
- on_selecttype_selected() {
- this.dateselector.value = ""
-
- var is_date = this.selecttype.value == "date"
-
- this.dateselector.hidden = !is_date
- this.rangespan.hidden = is_date
- }
-
- on_date_selected(event) {
- if (!event.target.value)
- return
- var date_from = event.target.value
-
- var date_to_obj = new Date(date_from)
- date_to_obj.setDate(date_to_obj.getDate() + 1)
- // Works also across months, years
- var date_to = date_to_obj.toJSON().slice(0, 10);
-
- this.range_from.value = date_from + "T00:00"
- this.on_range_from_selected()
- this.range_to.value = date_to + "T00:00"
- this.on_range_to_selected()
- }
-
- on_range_from_selected() {
- var val = this.range_from.value
- this.range_to.min = val
- this.range_to.disabled = (val == "")
-
- this.load_pages()
- }
-
- on_range_to_selected() {
- this.load_pages()
- }
-
- on_commit_selected() {
- var sha = this.commitsSelect.value
- var url_before = 'https://' + this.url + '/api/v4/projects/' + this.project_id + '/repository/files/' + encodeURIComponent(this.page_path + "/")
- var url_after = '/raw?ref=' + sha + '&private_token=' + this.token
- var url = url_before + encodeURIComponent(this.index) + url_after
- fetch(url)
- .then(response => response.text())
- .then(text => {
- var cleaned_text = hide_iframes(replace_urls(text, url_before, url_after))
-
- const blobContent = new Blob([cleaned_text], {type: "text/html"})
- this.content.src = URL.createObjectURL(blobContent)
- })
- }
-
- load_pages(open_first=false) {
- var date_from = this.range_from.value
- var date_to = this.range_to.value
-
- this.load_pages_recursive(1, date_from, date_to, open_first)
- }
-
- load_pages_recursive(page, date_from, date_to, open_first) {
- if (page == 1) {
- // Clean commits list
- this.commitsSelect.innerHTML = ""
- this.commitsSelect.appendChild(document.createElement("option"))
- }
-
- if (date_from == "" || date_to == "") {
- return
- }
-
- var commits_url = 'https://' + this.url + '/api/v4/projects/' + this.project_id + '/repository/commits?ref_name=' + this.branch + '&private_token=' + this.token + "&since="+date_from+"&until="+date_to+"&per_page=100&page=" + page;
-
- var length_promise = fetch(commits_url)
- .then(response => response.json())
- .then(
- // Translate response to commits
- json => json.map(
- gitlab_commit => new ArchiveCommit(
- gitlab_commit.message,
- gitlab_commit.created_at,
- gitlab_commit.id
- )
- )
- ).then((commits) => {
- // Skip if new date is selected
- if (date_from != this.range_from.value
- || date_to != this.range_to.value) {
- return 0;
- }
-
- this.add_commits(commits, open_first)
- return commits.length
- }
- ).then((length) => {
- if (length > 0) {
- this.load_pages_recursive(page+1, date_from, date_to, false)
- }
- })
- }
- }
|