@@ -9,14 +9,6 @@ const inIFrame = (() => {
99 }
1010} ) ( )
1111
12- let bus
13- let lastData
14- const refreshUI = ( ) => {
15- if ( bus . connected ) {
16- document . getElementById ( "connectDlg" ) . close ( )
17- }
18- }
19-
2012const stringFormat = ( s , args ) => s . replace ( / { ( \w + ) } / g, ( _ , id ) => args [ id ] )
2113
2214function simPostMessage ( channel , data ) {
@@ -32,131 +24,22 @@ function simPostMessage(channel, data) {
3224 }
3325}
3426
35- async function showModal ( id ) {
36- await bus . disconnect ( )
37- const el = document . getElementById ( id )
38- el . showModal ( )
39- }
40-
41- async function showOutdatedFirmwareDialog ( ) {
42- await showModal ( "outdatedDlg" )
43- }
44-
45- async function flashJacscriptServices ( services , data ) {
46- for ( const service of services ) await flashJacscriptService ( service , data )
47- }
48-
49- async function flashJacscriptService ( service , data ) {
50- if ( ! data ) return
51-
52- const dev = service . device
53- await dev . resolveProductIdentifier ( 3 )
54- const productIdentifier = dev . productIdentifier
55-
56- if ( productIdentifier !== MICROCODE_PRODUCT_IDENTIFIER ) {
57- console . debug (
58- `jacscript: invalid or unknown product identifier ${ productIdentifier } ` ,
59- )
60- trackEvent ( "firmware.wrongpid" )
61- await showOutdatedFirmwareDialog ( )
62- return
63- }
64-
65- await dev . resolveFirmwareVersion ( 3 )
66- const firmwareVersion = dev . firmwareVersion
67- console . debug ( `firmware version: ${ firmwareVersion } ` )
68- const webFirmwareVersion = document . body . dataset . version
69- const semweb = parseSemver ( webFirmwareVersion )
70- const semcur = parseSemver ( firmwareVersion )
71- if ( semweb [ 0 ] > semcur [ 0 ] || semweb [ 1 ] > semcur [ 1 ] ) {
72- console . debug ( `outdated firmware: ${ firmwareVersion } ` )
73- trackEvent ( "firmware.outdated" , {
74- firmwareVersion,
75- } )
76- await showOutdatedFirmwareDialog ( )
77- return
78- }
79-
80- if ( service . nodeData [ "bytecode" ] ) {
81- console . trace (
82- `jacscript: deployment to ${ service } in progress, skipping` ,
83- )
84- trackEvent ( "jacscript.deploy.concurrent" )
85- return
86- }
87-
88- try {
89- console . debug ( `jacscript: deploying to ${ service } ` )
90- trackEvent ( "firmware.deploy" , {
91- firmwareVersion,
92- bytes : data . length ,
93- } )
94- service . nodeData [ "bytecode" ] = data
95- await jacdac . OutPipe . sendBytes (
96- service ,
97- jacdac . JacscriptManagerCmd . DeployBytecode ,
98- data ,
99- )
100- console . debug ( `jacscript: deployed to ${ service } ` )
101- trackEvent ( "firmware.deploy.success" )
102- } catch ( e ) {
103- trackEvent ( "firmware.deploy.fail" )
104- window . appInsights ?. trackException ( {
105- exception : e ,
106- } )
107- throw e
108- } finally {
109- service . nodeData [ "bytecode" ] = undefined
110- }
111-
112- if ( data !== lastData ) {
113- console . debug (
114- `jacscript: restarting ${ service } deployment with newer bytecode` ,
115- )
116- trackEvent ( "firmware.deploy.redo" )
117- flashJacscriptService ( service , lastData )
118- }
119- }
120-
12127// docs
12228document . addEventListener ( "DOMContentLoaded" , async ( ) => {
12329 const build = document . body . dataset [ "build" ] || "local"
12430
125- initLang ( )
126- await loadTranslations ( build )
31+ // initLang()
32+ // await loadTranslations(build)
33+
12734 const docsbtn = document . getElementById ( "docsbtn" )
12835 if ( docsbtn )
12936 docsbtn . onclick = ( ) => {
13037 docsbtn . disabled = true
13138 simPostMessage ( "docs" , { type : "art" } )
13239 }
133- const screenshotbtn = document . getElementById ( "screenshotbtn" )
134- if ( screenshotbtn )
135- screenshotbtn . onclick = ( ) => {
136- simPostMessage ( "docs" , { type : "screenshot" } )
137- }
138-
139- const voicebtn = document . getElementById ( "voicebtn" )
140- if ( voicebtn ) {
141- if ( ! window . speechSynthesis ) voicebtn . remove ( )
142- else
143- voicebtn . onclick = ( ) => {
144- speakTooltips = ! speakTooltips
145- speak ( liveRegion . dataset [ "text" ] || "" )
146- }
147- }
148-
149- if ( supportedLanguages . indexOf ( editorLang ) > - 1 ) {
150- const fws = document . getElementsByClassName ( "firmware-download" )
151- for ( let i = 0 ; i < fws . length ; ++ i )
152- fws [ i ] . setAttribute (
153- "href" ,
154- `/microcode/assets/hex/microcode-${ editorLang . toLowerCase ( ) } .hex` ,
155- )
156- }
15740
15841 makeCodeRun ( {
159- js : `./assets/ js/binary- ${ editorLang . toLowerCase ( ) } .js?v=${ build } ` ,
42+ js : `./js/binary.js?v=${ build } ` ,
16043 } )
16144} )
16245
@@ -175,178 +58,18 @@ function stringToUint8Array(str) {
17558let liveRegion
17659let tooltipStrings = { }
17760
178- const supportedLanguages = [
179- "en" ,
180- "eu" ,
181- "ca" ,
182- "zh-CN" ,
183- "zh-HK" ,
184- "hr" ,
185- "nl" ,
186- "fil" ,
187- "fr" ,
188- "fr-CA" ,
189- "de" ,
190- "it" ,
191- "ja" ,
192- "pl" ,
193- "pt-BR" ,
194- "ru" ,
195- "es-ES" ,
196- "es-MX" ,
197- "tr" ,
198- "cy" ,
199- "ko" ,
200- ]
201-
20261async function fetchJSON ( url ) {
20362 const resp = await fetch ( url )
20463 if ( ! resp . ok ) return undefined
20564 return await resp . json ( )
20665}
20766
208- // load localized strings
209- let editorLang
210- function initLang ( ) {
211- const url = new URL ( window . location . href )
212- editorLang =
213- url . searchParams . get ( "lang" ) ||
214- ( document . firstElementChild . lang !== "en"
215- ? document . firstElementChild . lang
216- : undefined ) ||
217- navigator . language ||
218- "en"
219- if ( supportedLanguages . indexOf ( editorLang ) < 0 )
220- editorLang = editorLang . split ( "-" , 1 ) [ 0 ] || ""
221- if ( supportedLanguages . indexOf ( editorLang ) < 0 ) editorLang = "en"
222- window . editor = editorLang
223-
224- const noFooter = ! ! url . searchParams . get ( "nofooter" )
225- const embed = ! ! url . searchParams . get ( "embed" )
226- const root = document . querySelector ( "#root" )
227-
228- if ( noFooter ) {
229- const footer = document . querySelector ( "#footer" )
230- if ( root ) root . className += " nofooter"
231- if ( footer ) footer . remove ( )
232- }
233- if ( embed && root ) {
234- root . className += " embed"
235- }
236- }
237- let loadTranslationsPromise
238- async function loadTranslations ( build ) {
239- console . debug ( `loading translations for ${ editorLang } ` )
240- tooltipStrings =
241- ( await fetchJSON (
242- `./assets/strings/${ editorLang } /tooltips.json?v=${ build } ` ,
243- ) ) || { }
244- }
245-
246- function mapAriaId ( ariaId , missing ) {
247- return tooltipStrings [ ariaId ] || missing || ""
248- }
249-
25067function parseSemver ( v ) {
25168 const ver = / ^ v ? ( \d + ) \. ( \d + ) \. ( \d + ) $ / . exec ( v )
25269 if ( ver ) return [ parseInt ( ver [ 1 ] ) , parseInt ( ver [ 2 ] ) , parseInt ( ver [ 3 ] ) ]
25370 else return [ 0 , 0 , 0 ]
25471}
25572
256- let speakTooltips = false
257- let voice
258- function speak ( text ) {
259- if ( ! text || ! speakTooltips ) return
260-
261- console . debug ( `speak ${ text } ` )
262- const synth = window . speechSynthesis
263- synth . cancel ( )
264- if ( ! voice ) {
265- let voices = synth . getVoices ( ) . filter ( v => v . lang === editorLang )
266- if ( ! voices . length )
267- voices = synth
268- . getVoices ( )
269- . filter ( v => v . lang . indexOf ( editorLang ) === 0 )
270- if ( ! voices . length ) voices = synth . getVoices ( )
271- voice = voices [ 0 ]
272- console . debug ( `voice found` , { voice } )
273- }
274- const utterance = new SpeechSynthesisUtterance ( text )
275- utterance . lang = editorLang
276- utterance . voice = voice
277- utterance . rate = 1.2
278- synth . speak ( utterance )
279- synth . resume ( )
280- }
281-
282- addSimMessageHandler ( "accessibility" , data => {
283- // render message
284- const msg = JSON . parse ( uint8ArrayToString ( data ) )
285- //console.debug(`aria`, msg)
286- let value
287- const force = msg . force
288- if ( msg . type === "tile" || msg . type === "text" ) {
289- value = mapAriaId ( msg . value )
290- speak ( value )
291- } else if ( msg . type == "rule" ) {
292- value = mapAriaId ( "rule" )
293- value += `: ${ mapAriaId ( "when" ) } `
294- const whens = msg . whens
295- if ( whens && whens . length > 0 ) value += whens . map ( mapAriaId ) . join ( " " )
296- else value += mapAriaId ( "T10" )
297- value += `, ${ mapAriaId ( "do" ) } `
298- const dos = msg . dos
299- if ( dos && dos . length > 0 ) value += dos . map ( mapAriaId ) . join ( " " )
300- speak ( mapAriaId ( "rule" ) )
301- } else if ( msg . type == "led" ) {
302- const on = msg . on
303- const state = on ? mapAriaId ( "SR_ON" , "on" ) : mapAriaId ( "SR_OFF" , "off" )
304- const x = msg . x
305- const y = msg . y
306- const format = mapAriaId ( "SR_LED" , "LED {x} {y} {state}" )
307- value = stringFormat ( format , { state, x, y } )
308- speak ( value )
309- } else if ( msg . type == "note" ) {
310- const on = msg . on
311- const state = on ? mapAriaId ( "SR_ON" , "on" ) : mapAriaId ( "SR_OFF" , "off" )
312- const index = "CDEFGABCD" . charAt ( msg . index )
313- const format = mapAriaId ( "SR_NOTE" , "note {index} {state}" )
314- value = stringFormat ( format , { state, index } )
315- speak ( value )
316- } else {
317- console . error ( "unknown accessibility message" , msg )
318- }
319- setLiveRegion ( value , force )
320- } )
321-
322- function setLiveRegion ( value , force ) {
323- // apply to browser
324- if ( ! liveRegion ) {
325- const style =
326- "position: absolute !important;" +
327- "display: block;" +
328- "visibility: visible;" +
329- "overflow: hidden;" +
330- "width: 1px;" +
331- "height: 1px;" +
332- "margin: -1px;" +
333- "border: 0;" +
334- "padding: 0;" +
335- "clip: rect(0 0 0 0);"
336- liveRegion = document . createElement ( "div" )
337- liveRegion . setAttribute ( "role" , "status" )
338- liveRegion . setAttribute ( "aria-live" , "assertive" )
339- liveRegion . setAttribute ( "aria-hidden" , "false" )
340- liveRegion . setAttribute ( "style" , style )
341- document . body . appendChild ( liveRegion )
342- }
343- value = value || ""
344- if ( force && liveRegion . textContent === value ) liveRegion . textContent = ""
345- if ( value ) console . debug ( `aria-live: ${ value } ` )
346- liveRegion . dataset [ "text" ] = value
347- liveRegion . textContent = value
348- }
349-
35073function hexToUint8Array ( hex ) {
35174 const bytes = new Uint8Array ( Math . ceil ( hex . length / 2 ) )
35275 for ( let i = 0 ; i < bytes . length ; i ++ )
@@ -546,8 +269,3 @@ function trackEvent(name, props) {
546269 properties,
547270 } )
548271}
549-
550- addSimMessageHandler ( "analytics" , buf => {
551- const msg = JSON . parse ( uint8ArrayToString ( buf ) )
552- if ( msg . type === "event" ) trackEvent ( msg . msg , msg . data )
553- } )
0 commit comments