feat: Improve options page and add toggles for the two main features. (#68)

Resolves #43.

Should leave archematics ready to submit.

Reviewed-on: #68
Co-authored-by: Glen Whitney <glen@studioinfinity.org>
Co-committed-by: Glen Whitney <glen@studioinfinity.org>
This commit is contained in:
Glen Whitney 2024-02-20 04:14:44 +00:00 committed by Glen Whitney
parent b74921341c
commit 0567da019f
12 changed files with 215 additions and 142 deletions

View file

@ -26,9 +26,9 @@ obs := new MutationObserver (mutationList) =>
width: parseInt(newNode.getAttribute('width') ?? '200'),
height: parseInt(newNode.getAttribute('height') ?? '200') }
config := childList: true, subtree: true
observerConfig := childList: true, subtree: true
obs.observe document.documentElement, config
obs.observe document.documentElement, observerConfig
function addScriptTag(url: string, params = '', module = false)
return new Promise (resolve, reject) =>
@ -41,6 +41,8 @@ function addScriptTag(url: string, params = '', module = false)
document.head.appendChild script
document.addEventListener "DOMContentLoaded", async =>
config := await browser.storage.local.get(flags) as ConfigType
unless config.joyce return
finalJoyceApplets := document.querySelectorAll "applet[code='Geometry']"
if finalJoyceApplets.length
joyceApplets = []
@ -58,7 +60,6 @@ document.addEventListener "DOMContentLoaded", async =>
width: parseInt(jApp.getAttribute('width') ?? '200'),
height: parseInt(jApp.getAttribute('height') ?? '200') }
if joyceApplets.length
config := await browser.storage.local.get(flags) as ConfigType
use3d .= false
for each jApp of joyceApplets
if contains3d jApp.params

View file

@ -1,7 +1,10 @@
// This file is a bit misnamed, as it has options for giveAwrl, too.
export const flags = [
'color', 'commands', 'showall', 'showaux', 'algebra', 'vrml97'] as const
'vrmlview', 'joyce',
// debugging
'color', 'commands', 'showall', 'showaux', 'algebra', 'vrml97'
] as const
export type FlagType = (typeof flags)[number]
export type ConfigType = Partial<Record<FlagType, boolean>>

View file

@ -1,12 +1,15 @@
import ./deps/jquery.js
{convert} from ./deps/vrml1to97/index.js
{ConfigType} from ./adapptypes.ts
import type {ConfigType} from ./adapptypes.ts
configPromise := browser.storage.local.get(['vrmlview', 'vrml97'])
knownExtensions := /[.](?:wrl|x3d|gltf|glb|obj|stl|ply)$/
certainlyHandled :=
knownExtensions.source.slice(0, -2).split('wrl|')[1].split '|'
function makeBrowser(url: string, width: string, height: string)
function makeBrowser(url: string, width: string, height: string,
config: ConfigType)
x_ite_rel := 'deps/x_ite/x_ite.mjs'
x_ite_url .= './' + x_ite_rel
unless typeof browser is 'undefined'
@ -43,141 +46,149 @@ function makeBrowser(url: string, width: string, height: string)
text .= await response.text()
if /#\s*VRML\s*V?1[.]/i.test text
text = convert text
maybeDebug text
maybeDebug text, config
browser3D.baseURL = url
scene := await browser3D.createX3DFromString text
browser3D.replaceWorld scene
{canvas, browser3D}
// Put eye icons after all of the eligible links
links := $('a').filter -> knownExtensions.test @.getAttribute('href') ?? ''
links.after ->
newSpan := $('<span>👁</span>')
newSpan.css 'overflow', 'visible'
floatLike := this.lastElementChild as HTMLElement
float .= ''
if floatLike
float = (floatLike.getAttribute('align') ?? '')
or floatLike.style.getPropertyValue 'float'
or window.getComputedStyle(floatLike).getPropertyValue 'float'
switch float
/left/i
float = 'left'
newSpan.css {float, position: 'relative'}
/right/i
float = 'right'
newSpan.css {float, position: 'relative'}
else float = ''
newSpan.hover
(-> $(@).css 'background-color', 'lightblue'),
(-> $(@).css 'background-color', 'inherit')
newSpan.on 'click', @,
(e) =>
eye := e.target
state .= eye.getAttribute 'data'
unless state
state = 'off'
url := e.data.getAttribute('href') ?? ''
overImg := floatLike and floatLike.tagName is 'IMG'
width := overImg ? ($(floatLike).width() + 'px') : '150px'
height := overImg ? ($(floatLike).height() + 'px') : '150px'
{canvas} := await makeBrowser url, width, height
if float
canvas.style.float = float
if overImg
canvas.style.position = 'absolute'
imgSty := window.getComputedStyle floatLike
canvas.style.marginTop = imgSty.getPropertyValue 'margin-top'
canvas.style.marginLeft = imgSty.getPropertyValue 'margin-left'
canvas.style.marginRight = imgSty.getPropertyValue 'margin-right'
if float is 'right'
canvas.style.left = $(eye).width() + 'px'
else if float is 'left'
canvas.style.right = $(eye).width() + 'px'
else canvas.style.left = floatLike.offsetLeft
$(eye).append canvas
if state is 'off'
eye.setAttribute 'data', 'on'
$(eye).css 'text-decoration', 'line-through 3px'
$(eye.lastElementChild as Element).show()
else
eye.setAttribute 'data', 'off'
$(eye).css 'text-decoration', 'none'
$(eye.lastElementChild as Element).hide()
configPromise.then((config) =>
// Put eye icons after all of the eligible links
links := $('a').filter -> knownExtensions.test @.getAttribute('href') ?? ''
links.after ->
unless config.vrmlview return ''
newSpan := $('<span>👁</span>')
newSpan.css 'overflow', 'visible'
floatLike := this.lastElementChild as HTMLElement
float .= ''
if floatLike
float = (floatLike.getAttribute('align') ?? '')
or floatLike.style.getPropertyValue 'float'
or window.getComputedStyle(floatLike).getPropertyValue 'float'
switch float
/left/i
float = 'left'
newSpan.css {float, position: 'relative'}
/right/i
float = 'right'
newSpan.css {float, position: 'relative'}
else float = ''
newSpan.hover
(-> $(@).css 'background-color', 'lightblue'),
(-> $(@).css 'background-color', 'inherit')
newSpan.on 'click', @,
(e) =>
eye := e.target
state .= eye.getAttribute 'data'
unless state
state = 'off'
url := e.data.getAttribute('href') ?? ''
overImg := floatLike and floatLike.tagName is 'IMG'
width := overImg ? ($(floatLike).width() + 'px') : '150px'
height := overImg ? ($(floatLike).height() + 'px') : '150px'
{canvas} := await makeBrowser url, width, height, config
if float
canvas.style.float = float
if overImg
canvas.style.position = 'absolute'
imgSty := window.getComputedStyle floatLike
canvas.style.marginTop =
imgSty.getPropertyValue 'margin-top'
canvas.style.marginLeft =
imgSty.getPropertyValue 'margin-left'
canvas.style.marginRight =
imgSty.getPropertyValue 'margin-right'
if float is 'right'
canvas.style.left = $(eye).width() + 'px'
else if float is 'left'
canvas.style.right = $(eye).width() + 'px'
else canvas.style.left = floatLike.offsetLeft
$(eye).append canvas
if state is 'off'
eye.setAttribute 'data', 'on'
$(eye).css 'text-decoration', 'line-through 3px'
$(eye.lastElementChild as Element).show()
else
eye.setAttribute 'data', 'off'
$(eye).css 'text-decoration', 'none'
$(eye.lastElementChild as Element).hide()
function maybeDebug(vrml: string)
config := await browser.storage.local.get(['vrml97']) as ConfigType
let conwayBrowser: any
madeConway .= false
// See if we are on George Hart's Conway-notation generator page
inputs := $('input[type="button"][value="Generate"][onclick="viewVRML()"]')
if config.vrmlview and inputs.length is 1
// Seems so, fix the generator
// Note that modifying the onclick prop is not the recommended way to
// change button click functionality, but we need to clear out the old
// behavior so I wasn't sure how else to do it
inputs.prop 'onclick', (i, val) => () =>
import(browser.runtime.getURL('conway.js')).then (conway) =>
notation := $('input[name="notation"]').val()
unless notation then return
vrml := conway.generateVRML notation.toString()
maybeDebug vrml, config
unless madeConway
{canvas, browser3D} :=
await makeBrowser '', '250px', '250px', config
conwayBrowser = browser3D
canvas.style.float = 'left'
canvas.style.marginRight = '1em'
$('form[name="input"]').first().before canvas
madeConway = true
scene := await conwayBrowser.createX3DFromString vrml
conwayBrowser.replaceWorld scene
// See if we are on George Hart's prism generator page
panelFrame := $('frame[name="panel"][src="prism-maker-subpanel.html"]')
if config.vrmlview and panelFrame.length is 1
// Seems so, fix the generator
panelFrame.on "load", =>
panelDoc := frames[1].document
vrmlDoc := frames[0].document
vrmlBody := $('body', vrmlDoc)
// Grab the initial text while it is still easy to get
textNode := vrmlBody.contents()[0]
initialVrml1: string := textNode.textContent or ''
// Now build up the vrml frame as we want it
viewerDiv := $('<div></div>')
$('head').after $('<body></body>')
$('body').append viewerDiv
// We are presuming here that the body just contains a single
// text node. That should stay true unless GWH changes the page.
initialVrml97 := convert initialVrml1
{canvas, browser3D: prismBrowser} :=
await makeBrowser '', '300px', '300px', config
viewerDiv.append canvas
initialScene := await prismBrowser.createX3DFromString initialVrml97
prismBrowser.replaceWorld initialScene
$(textNode).remove()
$('frame[name="vrml"]').remove()
// OK, finally have the layout cleaned up. Now we can set up our
// replacement generator:
prismBtn :=
$('input[type="button"][value="View"][onclick="ViewVRML()"]',
panelDoc)
unless prismBtn.length is 1 return
prismBtn.prop 'onclick', (i, val) => =>
import(browser.runtime.getURL('prism.js')).then (prism) =>
numerator := parseInt(
$('input[name="numerator"]', panelDoc).val() as string)
denominator := parseInt(
$('input[name="denominator"]', panelDoc).val() as string)
checks: boolean[] := []
$('input[name="what"]', panelDoc).each ->
checks.push (@ as HTMLInputElement).checked
return
{vrml, err} := prism.generateVRML numerator, denominator, checks
maybeDebug vrml, config
if err then alert err
if vrml
scene := await prismBrowser.createX3DFromString vrml
prismBrowser.replaceWorld scene
) // end of then for configPromise
function maybeDebug(vrml: string, config: ConfigType)
if config.vrml97 then console.log 'Generated VRML97', vrml
let conwayBrowser: any
madeConway .= false
// See if we are on George Hart's Conway-notation generator page
inputs := $('input[type="button"][value="Generate"][onclick="viewVRML()"]')
if inputs.length is 1
// Seems so, fix the generator
// Note that modifying the onclick prop is not the recommended way to
// change button click functionality, but we need to clear out the old
// behavior so I wasn't sure how else to do it
inputs.prop 'onclick', (i, val) => () =>
import(browser.runtime.getURL('conway.js')).then (conway) =>
notation := $('input[name="notation"]').val()
unless notation then return
vrml := conway.generateVRML notation.toString()
maybeDebug vrml
unless madeConway
{canvas, browser3D} := await makeBrowser '', '250px', '250px'
conwayBrowser = browser3D
canvas.style.float = 'left'
canvas.style.marginRight = '1em'
$('form[name="input"]').first().before canvas
madeConway = true
scene := await conwayBrowser.createX3DFromString vrml
conwayBrowser.replaceWorld scene
// See if we are on George Hart's prism generator page
panelFrame := $('frame[name="panel"][src="prism-maker-subpanel.html"]')
if panelFrame.length is 1
// Seems so, fix the generator
panelFrame.on "load", =>
panelDoc := frames[1].document
vrmlDoc := frames[0].document
vrmlBody := $('body', vrmlDoc)
// Grab the initial text while it is still easy to get
textNode := vrmlBody.contents()[0]
initialVrml1: string := textNode.textContent or ''
// Now build up the vrml frame as we want it
viewerDiv := $('<div></div>')
$('head').after $('<body></body>')
$('body').append viewerDiv
// We are presuming here that the body just contains a single
// text node. That should stay true unless GWH changes the page.
initialVrml97 := convert initialVrml1
{canvas, browser3D: prismBrowser} := await makeBrowser '', '300px', '300px'
viewerDiv.append canvas
initialScene := await prismBrowser.createX3DFromString initialVrml97
prismBrowser.replaceWorld initialScene
$(textNode).remove()
$('frame[name="vrml"]').remove()
// OK, finally have the layout cleaned up. Now we can set up our
// replacement generator:
prismBtn := $('input[type="button"][value="View"][onclick="ViewVRML()"]',
panelDoc)
unless prismBtn.length is 1 return
prismBtn.prop 'onclick', (i, val) => =>
import(browser.runtime.getURL('prism.js')).then (prism) =>
numerator :=
parseInt $('input[name="numerator"]', panelDoc).val() as string
denominator :=
parseInt $('input[name="denominator"]', panelDoc).val() as string
checks: boolean[] := []
$('input[name="what"]', panelDoc).each ->
checks.push (@ as HTMLInputElement).checked
return
{vrml, err} := prism.generateVRML numerator, denominator, checks
maybeDebug vrml
if err then alert err
if vrml
scene := await prismBrowser.createX3DFromString vrml
prismBrowser.replaceWorld scene

View file

@ -5,7 +5,7 @@ cache := await browser.storage.local.get flags
for each box of flags
checkbox := document.getElementById(box) as HTMLInputElement
unless checkbox then continue
checkbox.checked = cache[box] ?? false
checkbox.checked = cache[box] ?? (box is 'vrmlview' or box is 'joyce')
document.body.addEventListener 'click', (event) ->
elt := event.target as HTMLInputElement