wobbly/main.js

157 lines
4.3 KiB
JavaScript

// DOM Elements
var wobblyWindow
var wobblyHelpButton
var wobblyHelp
var wobblyUp
var wobblyAddressBar
var wobblyGo
var wobblySpinner
var startpage = 'gemini://tildeverse.org/'
var xhr
function geminiInit() {
// Store references to all our DOM elements
wobblyWindow = document.getElementById("wobbly-window")
wobblyHelpButton = document.getElementById('wobbly-help-button')
wobblyHelp = document.getElementById('wobbly-help')
wobblyUp = document.getElementById('wobbly-up')
wobblyAddressBar = document.getElementById('wobbly-addressbar')
wobblyGo = document.getElementById('wobbly-go')
wobblySpinner = document.getElementById('wobbly-spinner')
// Set up listeners for DOM elements
wobblyHelpButton.addEventListener('click', geminiHelpToggle)
wobblyUp.addEventListener('click', geminiUp)
wobblyAddressBar.addEventListener('keypress', geminiEnterListener)
wobblyGo.addEventListener('click', geminiGo)
// Hijack all clicks to check for gemini links
document.addEventListener('click', geminiLinkClickListener, false)
// 'popstate' from History API will inform us when the browser changes.
// We use this to listen for the back/forward buttons
window.addEventListener('popstate', goFromURL)
// Clear screen
wobblyWindow.innerHTML = ""
// Manually trigger initial load from URL string
goFromURL()
}
// Get the location in wobbly address bar and push it to browser URL.
// This uses the History API so the browser back/forward will work.
function pushState() {
const url = wobblyAddressBar.value.trim().split("?")[0]
const pushurl = new URL(window.location.href.split('?')[0] + '?' + url)
window.history.pushState({}, '', pushurl)
}
// Assume our navigation is being triggered by a URL change
function goFromURL() {
// Check for URL query string to find destination. Falback on startpage
let dest = startpage
query_string = window.location.href.split('?')
if (query_string.length > 1){
dest = query_string[1]
}
// Update the wobbly addressbar with correct destination
wobblyAddressBar.value = dest
// Perform actual gemini navigation
geminiGo(true)
}
function geminiGo(fromURL) {
// get and validate URL destination
url = wobblyAddressBar.value.trim().split("?")[0]
if (url.length == 0) {
return
}
// TODO: Add a test for non-gemini protocol
// correct wobbly URL so it's always prefixed with gemini://
if (! url.startsWith("gemini://")) {
url = "gemini://" + url
}
// Any navigation not driven from a URL change store as new state
if (!fromURL) {
pushState()
}
// Enable throbber to indicate page loading
wobblySpinner.classList.add('active')
// If any unfinished xhrs, abort them and begin anew
if (xhr) {
xhr.abort()
}
// Setup gemini request for CGI
xhr = new XMLHttpRequest()
xhr.open( "GET", "browser.cgi?" + url )
// If success: show page contents and clear throbber
xhr.onload = () => {
const body = xhr.responseText
wobblyWindow.innerHTML = body
wobblySpinner.classList.remove('active')
}
// If error: show error contents on page
xhr.onerror = () => {
wobblySpinner.classList.remove('active')
wobblyWindow.innerHTML = `<h1>Something went wrong</h1><p>Error reported:</p><p>${xhr.statusText}</p>`
}
// Initiate request
xhr.send(null)
}
// Simple show/hide of help block
function geminiHelpToggle() {
if (wobblyHelpButton.innerHTML === 'Help') {
wobblyHelp.style.display = 'block'
wobblyHelpButton.innerHTML = "Unhelp"
} else {
wobblyHelp.style.display = 'none'
wobblyHelpButton.innerHTML = "Help"
}
}
// Move up one path in URL
function geminiUp() {
const components = wobblyAddressBar.value.match(/\/[^/]*/g)
if ("/" == components.pop()) components.pop()
if (components.length == 1) return
wobblyAddressBar.value = "gemini:" + components.join("") + "/"
geminiGo()
}
// Listen for Enter Key to trigger navigation
function geminiEnterListener(e) {
if(e.keyCode === 13) {
e.preventDefault()
geminiGo()
}
}
// Hijack any clicks from anchor links that use the gemini protocol
function geminiLinkClickListener(e) {
if (e.target.tagName === 'A' && e.target.href.startsWith("gemini://")) {
// We only care about clicked gemini:// links
e.preventDefault()
wobblyAddressBar.value = e.target.href
geminiGo()
} else {
return
}
}
// Begin init after DOM loads
window.onload = function () {
geminiInit()
}