Updates
Release rolling / release (push) Successful in 9m30s

This commit is contained in:
Raven Scott
2026-08-13 00:13:03 -04:00
parent 1187e30cf6
commit 15afc148d7
51 changed files with 8751 additions and 668 deletions
@@ -0,0 +1,361 @@
/** Tabs, history, bookmarks, about: pages. */
function bareSummonHome(ctx) {
var env = ctx && ctx.env && typeof ctx.env === 'object' ? ctx.env : {}
if (env.HOME) return String(env.HOME).replace(/\/+$/, '')
return '/home/guest'
}
function bareSummonPaths(ctx) {
var h = bareSummonHome(ctx)
return {
dir: h + '/.summon',
config: h + '/.summon/config.json',
cookies: h + '/.summon/cookies.json',
bookmarks: h + '/.summon/bookmarks.json',
history: h + '/.summon/history.jsonl'
}
}
function bareSummonCreateTab(url) {
return {
url: url || 'about:summon',
title: '',
loading: false,
status: 0,
error: '',
doc: null,
layout: null,
source: '',
reader: false,
find: '',
history: { back: [], forward: [] },
scriptsBlocked: 0,
stylesBlocked: 0
}
}
function bareSummonCreateSession(ctx, opts) {
opts = opts || {}
var jar = bareSummonCreateCookieJar()
return {
ctx: ctx,
jar: jar,
tabs: [bareSummonCreateTab(opts.url || 'about:summon')],
current: 0,
bookmarks: Array.isArray(opts.bookmarks) ? opts.bookmarks.slice() : [],
config: opts.config || { javascript: false, images: 'alt', numbers: true },
cols: opts.cols || 80
}
}
function bareSummonCurrent(session) {
return session.tabs[session.current] || session.tabs[0]
}
function bareSummonAboutBody(kind, session) {
if (kind === 'blank') return '<html><body></body></html>'
if (kind === 'bookmarks') {
var items = (session.bookmarks || [])
.map(function (b) {
return (
'<li><a href="' +
String(b.url || '') +
'">' +
String(b.title || b.url || '') +
'</a></li>'
)
})
.join('')
return (
'<html><body><h1>Bookmarks</h1><ul>' +
(items || '<li>(none)</li>') +
'</ul></body></html>'
)
}
if (kind === 'history') {
var t = bareSummonCurrent(session)
var h = (t.history.back || [])
.slice(-20)
.map(function (u) {
return '<li><a href="' + u + '">' + u + '</a></li>'
})
.join('')
return (
'<html><body><h1>History</h1><ul>' +
(h || '<li>(empty)</li>') +
'</ul></body></html>'
)
}
if (kind === 'cookies') {
var rows = session.jar
.toJSON()
.map(function (c) {
return '<li>' + c.name + ' @ ' + c.domain + c.path + '</li>'
})
.join('')
return (
'<html><body><h1>Cookies</h1><ul>' +
(rows || '<li>(none)</li>') +
'</ul></body></html>'
)
}
if (kind === 'net') {
return '<html><body><h1>Net</h1><p>HTTP via ctx.httpFetch. Allow/deny: BARE_OS_HTTP_ALLOWLIST / DENYLIST.</p></body></html>'
}
return (
'<html><body><h1>summon</h1><p>Text browser for Bare OS. JS is off. Default engine is first-party HTML/CSS.</p>' +
'<p>Type a URL (g) or open a bookmark. Try <a href="about:bookmarks">about:bookmarks</a>.</p></body></html>'
)
}
function bareSummonApplyDocument(session, tab, html, url) {
var doc = bareSummonParseHtml(html, {})
var inline = []
function collectStyle(n) {
if (n && n.type === 'element' && n.name === 'style') {
inline.push(bareSummonParseStylesheet(bareSummonTextContent(n)))
}
var ch = (n && n.children) || []
for (var i = 0; i < ch.length; i++) collectStyle(ch[i])
}
collectStyle(doc.head)
tab.sheets = inline
var layout = bareSummonLayout(doc, {
cols: session.cols,
sheets: inline,
numbers: session.config.numbers !== false
})
tab.doc = doc
tab.layout = layout
tab.source = html
tab.title = layout.title || doc.title || url
tab.scriptsBlocked = doc.scriptsBlocked || 0
tab.url = url
}
function bareSummonRelayout(session) {
var tab = bareSummonCurrent(session)
if (!tab || !tab.doc) return tab
tab.layout = bareSummonLayout(tab.doc, {
cols: session.cols,
sheets: tab.sheets || [],
numbers: session.config.numbers !== false
})
return tab
}
async function bareSummonNavigate(session, urlStr, opts) {
opts = opts || {}
var tab = bareSummonCurrent(session)
var resolved = bareSummonResolveUrl(urlStr, tab.url)
if (!resolved || !bareSummonUrlOk(resolved)) {
tab.error = 'bad URL'
tab.loading = false
return tab
}
if (!opts.replace && tab.url && tab.url !== resolved.href) {
tab.history.back.push(tab.url)
tab.history.forward = []
}
tab.loading = true
tab.error = ''
tab.reader = false
if (resolved.protocol === 'about:') {
var kind = resolved.pathname || 'summon'
if (kind.charAt(0) === ':') kind = kind.slice(1)
bareSummonApplyDocument(
session,
tab,
bareSummonAboutBody(kind, session),
resolved.href
)
tab.status = 200
tab.loading = false
return tab
}
if (resolved.protocol === 'file:') {
var ctx = session.ctx
var path = resolved.pathname || '/'
try {
var buf =
ctx.vfs && ctx.vfs.readFile ? await ctx.vfs.readFile(path) : null
var text = ''
if (buf) {
text =
ctx.b4a && typeof ctx.b4a.toString === 'function'
? ctx.b4a.toString(buf)
: String(buf)
}
bareSummonApplyDocument(
session,
tab,
text || '<html><body>(empty file)</body></html>',
resolved.href
)
tab.status = buf ? 200 : 404
} catch (e) {
tab.error = (e && e.message) || String(e)
tab.status = 0
}
tab.loading = false
return tab
}
var fetched = await bareSummonFetch(session.ctx, resolved.href, {
jar: session.jar,
method: opts.method || 'GET',
body: opts.body,
headers: opts.headers
})
if (!fetched.ok && !fetched.body) {
tab.error = fetched.error || 'fetch failed'
tab.status = fetched.status || 0
tab.loading = false
return tab
}
tab.status = fetched.status
var body = fetched.body || ''
var ct = (fetched.headers && fetched.headers['content-type']) || ''
if (!/html/i.test(ct) && body && body.charAt(0) !== '<') {
body =
'<html><body><pre>' +
body.replace(/&/g, '&amp;').replace(/</g, '&lt;') +
'</pre></body></html>'
}
bareSummonApplyDocument(session, tab, body, fetched.url || resolved.href)
tab.loading = false
return tab
}
function bareSummonBack(session) {
var tab = bareSummonCurrent(session)
if (!tab.history.back.length) return Promise.resolve(tab)
tab.history.forward.unshift(tab.url)
var prev = tab.history.back.pop()
return bareSummonNavigate(session, prev, { replace: true })
}
function bareSummonForward(session) {
var tab = bareSummonCurrent(session)
if (!tab.history.forward.length) return Promise.resolve(tab)
var next = tab.history.forward.shift()
return bareSummonNavigate(session, next, { replace: true })
}
function bareSummonAddBookmark(session, url, title) {
session.bookmarks.push({ url: url, title: title || url })
}
function bareSummonReload(session) {
var tab = bareSummonCurrent(session)
return bareSummonNavigate(session, tab.url, { replace: true })
}
function bareSummonFollowLink(session, id) {
var tab = bareSummonCurrent(session)
var links = (tab.layout && tab.layout.links) || []
var hit = null
var i
for (i = 0; i < links.length; i++) {
if (links[i].id === id) hit = links[i]
}
if (!hit) return Promise.resolve(tab)
return bareSummonNavigate(session, hit.href)
}
function bareSummonNewTab(session, url) {
session.tabs.push(bareSummonCreateTab(url || 'about:summon'))
session.current = session.tabs.length - 1
return bareSummonCurrent(session)
}
function bareSummonCloseTab(session) {
if (session.tabs.length <= 1) {
session.tabs[0] = bareSummonCreateTab('about:summon')
session.current = 0
return session.tabs[0]
}
session.tabs.splice(session.current, 1)
if (session.current >= session.tabs.length)
session.current = session.tabs.length - 1
return bareSummonCurrent(session)
}
function bareSummonSelectTab(session, index) {
if (index < 0 || index >= session.tabs.length)
return bareSummonCurrent(session)
session.current = index
return bareSummonCurrent(session)
}
function bareSummonCycleTab(session, dir) {
var n = session.tabs.length
if (!n) return bareSummonCurrent(session)
session.current = (session.current + dir + n) % n
return bareSummonCurrent(session)
}
function bareSummonBufToString(ctx, buf) {
if (buf == null) return ''
if (typeof buf === 'string') return buf
if (ctx && ctx.b4a && typeof ctx.b4a.toString === 'function') {
return ctx.b4a.toString(buf)
}
return String(buf)
}
async function bareSummonReadJson(ctx, path) {
if (!ctx || !ctx.vfs || typeof ctx.vfs.readFile !== 'function') return null
try {
var buf = ctx.vfs.readFile(path)
if (buf && typeof buf.then === 'function') buf = await buf
var t = String(bareSummonBufToString(ctx, buf) || '').trim()
if (!t) return null
return JSON.parse(t)
} catch (e) {
return null
}
}
async function bareSummonWriteJson(ctx, path, value) {
if (!ctx || !ctx.vfs || typeof ctx.vfs.writeFile !== 'function') return false
try {
var dir = path.slice(0, path.lastIndexOf('/'))
if (dir && ctx.vfs.mkdir) {
try {
var mk = ctx.vfs.mkdir(dir, { recursive: true })
if (mk && typeof mk.then === 'function') await mk
} catch (e) {
/* ignore */
}
}
var body = JSON.stringify(value, null, 2)
var w = ctx.vfs.writeFile(path, body)
if (w && typeof w.then === 'function') await w
return true
} catch (e2) {
return false
}
}
async function bareSummonLoadPersisted(session) {
var ctx = session.ctx
var paths = bareSummonPaths(ctx)
var cfg = await bareSummonReadJson(ctx, paths.config)
if (cfg && typeof cfg === 'object') {
session.config = Object.assign({}, session.config, cfg)
}
var marks = await bareSummonReadJson(ctx, paths.bookmarks)
if (Array.isArray(marks)) session.bookmarks = marks
var cookies = await bareSummonReadJson(ctx, paths.cookies)
if (Array.isArray(cookies)) session.jar.load(cookies)
return session
}
async function bareSummonSavePersisted(session) {
var ctx = session.ctx
var paths = bareSummonPaths(ctx)
await bareSummonWriteJson(ctx, paths.bookmarks, session.bookmarks || [])
await bareSummonWriteJson(ctx, paths.cookies, session.jar.toJSON())
await bareSummonWriteJson(ctx, paths.config, session.config || {})
}