157 lines
4.3 KiB
JavaScript
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()
|
|
}
|