2022-02-21 15:35:52 +00:00
"use strict" ;
// 8bitworkshop IDE user interface
var _ _createBinding = ( this && this . _ _createBinding ) || ( Object . create ? ( function ( o , m , k , k2 ) {
if ( k2 === undefined ) k2 = k ;
Object . defineProperty ( o , k2 , { enumerable : true , get : function ( ) { return m [ k ] ; } } ) ;
} ) : ( function ( o , m , k , k2 ) {
if ( k2 === undefined ) k2 = k ;
o [ k2 ] = m [ k ] ;
} ) ) ;
var _ _setModuleDefault = ( this && this . _ _setModuleDefault ) || ( Object . create ? ( function ( o , v ) {
Object . defineProperty ( o , "default" , { enumerable : true , value : v } ) ;
} ) : function ( o , v ) {
o [ "default" ] = v ;
} ) ;
var _ _importStar = ( this && this . _ _importStar ) || function ( mod ) {
if ( mod && mod . _ _esModule ) return mod ;
var result = { } ;
if ( mod != null ) for ( var k in mod ) if ( k !== "default" && Object . prototype . hasOwnProperty . call ( mod , k ) ) _ _createBinding ( result , mod , k ) ;
_ _setModuleDefault ( result , mod ) ;
return result ;
} ;
Object . defineProperty ( exports , "__esModule" , { value : true } ) ;
2022-09-01 22:26:06 +00:00
exports . highlightSearch = exports . reloadWorkspaceFile = exports . emulationHalted = exports . getSaveState = exports . getTestOutput = exports . setTestInput = exports . startUI = exports . getPlatformAndRepo = exports . setupSplits = exports . haltEmulation = exports . setFrameRateUI = exports . clearBreakpoint = exports . runToPC = exports . setupBreakpoint = exports . lastDebugState = exports . compparams = exports . projectWindows = exports . current _project = exports . platform = exports . repo _id = exports . store _id = exports . platform _id = exports . qs = void 0 ;
2022-02-21 15:35:52 +00:00
const localforage = _ _importStar ( require ( "localforage" ) ) ;
const project _1 = require ( "./project" ) ;
const windows _1 = require ( "./windows" ) ;
const baseplatform _1 = require ( "../common/baseplatform" ) ;
const emu _1 = require ( "../common/emu" ) ;
const toolbar _1 = require ( "../common/toolbar" ) ;
const util _1 = require ( "../common/util" ) ;
const recorder _1 = require ( "../common/recorder" ) ;
const services _1 = require ( "./services" ) ;
const Split = require ( "split.js" ) ;
const _index _1 = require ( "../platform/_index" ) ;
const editors _1 = require ( "./views/editors" ) ;
const debugviews _1 = require ( "./views/debugviews" ) ;
const asseteditor _1 = require ( "./views/asseteditor" ) ;
const baseviews _1 = require ( "./views/baseviews" ) ;
const treeviews _1 = require ( "./views/treeviews" ) ;
const file _saver _1 = require ( "file-saver" ) ;
exports . qs = ( 0 , util _1 . decodeQueryString ) ( window . location . search || '?' ) ;
const isElectron = ( 0 , util _1 . parseBool ) ( exports . qs . electron ) ;
const isEmbed = ( 0 , util _1 . parseBool ) ( exports . qs . embed ) ;
/// GLOBALS (TODO: remove)
var PRESETS ; // presets array
var toolbar = $ ( "#controls_top" ) ;
var uitoolbar ;
var stateRecorder ;
var userPaused ; // did user explicitly pause?
var current _output ; // current ROM (or other object)
var current _preset ; // current preset object (if selected)
var store ; // persistent store
var lastDebugInfo ; // last debug info (CPU text)
var debugCategory ; // current debug category
var debugTickPaused = false ;
var recorderActive = false ;
var lastViewClicked = null ;
2022-08-31 00:57:30 +00:00
var lastDebugCommand = null ;
2022-02-21 15:35:52 +00:00
var errorWasRuntime = false ;
var lastBreakExpr = "c.PC == 0x6000" ;
// TODO: codemirror multiplex support?
// TODO: move to views.ts?
const TOOL _TO _SOURCE _STYLE = {
'dasm' : '6502' ,
'acme' : '6502' ,
'cc65' : 'text/x-csrc' ,
'ca65' : '6502' ,
'nesasm' : '6502' ,
'z80asm' : 'z80' ,
'sdasz80' : 'z80' ,
'sdcc' : 'text/x-csrc' ,
'verilator' : 'verilog' ,
'jsasm' : 'z80' ,
'zmac' : 'z80' ,
'bataribasic' : 'bataribasic' ,
'markdown' : 'markdown' ,
'js' : 'javascript' ,
'xasm6809' : 'z80' ,
'cmoc' : 'text/x-csrc' ,
'yasm' : 'gas' ,
'smlrc' : 'text/x-csrc' ,
'inform6' : 'inform6' ,
'fastbasic' : 'fastbasic' ,
'basic' : 'basic' ,
'silice' : 'verilog' ,
'wiz' : 'text/x-wiz' ,
'vasmarm' : 'vasm' ,
2022-06-30 18:34:04 +00:00
'armips' : 'vasm' ,
'ecs' : 'ecs' ,
2022-02-21 15:35:52 +00:00
} ;
const TOOL _TO _HELPURL = {
'dasm' : 'https://github.com/dasm-assembler/dasm/blob/master/docs/dasm.pdf' ,
'cc65' : 'https://cc65.github.io/doc/cc65.html' ,
'ca65' : 'https://cc65.github.io/doc/ca65.html' ,
'sdcc' : 'http://sdcc.sourceforge.net/doc/sdccman.pdf' ,
'verilator' : 'https://www.veripool.org/ftp/verilator_doc.pdf' ,
'fastbasic' : 'https://github.com/dmsc/fastbasic/blob/master/manual.md'
} ;
function gaEvent ( category , action , label , value ) {
if ( window [ 'ga' ] )
ga ( 'send' , 'event' , category , action , label , value ) ;
}
function alertError ( s ) {
setWaitDialog ( false ) ;
bootbox . alert ( {
title : '<span class="glyphicon glyphicon-alert" aria-hidden="true"></span> Alert' ,
message : s
} ) ;
}
function alertInfo ( s ) {
setWaitDialog ( false ) ;
bootbox . alert ( s ) ;
}
function fatalError ( s ) {
alertError ( s ) ;
throw new Error ( s ) ;
}
function newWorker ( ) {
// TODO: return new Worker("https://8bitworkshop.com.s3-website-us-east-1.amazonaws.com/dev/gen/worker/bundle.js");
return new Worker ( "./gen/worker/bundle.js" ) ;
}
const hasLocalStorage = function ( ) {
try {
const key = "__some_random_key_you_are_not_going_to_use__" ;
localStorage . setItem ( key , key ) ;
var has = localStorage . getItem ( key ) == key ;
localStorage . removeItem ( key ) ;
return has ;
}
catch ( e ) {
return false ;
}
} ( ) ;
// wrapper for localstorage
class UserPrefs {
setLastPreset ( id ) {
if ( hasLocalStorage && ! isEmbed ) {
if ( exports . repo _id && exports . platform _id && ! isElectron )
localStorage . setItem ( "__lastrepo_" + exports . platform _id , exports . repo _id ) ;
else
localStorage . removeItem ( "__lastrepo_" + exports . platform _id ) ;
localStorage . setItem ( "__lastplatform" , exports . platform _id ) ;
localStorage . setItem ( "__lastid_" + exports . store _id , id ) ;
}
}
unsetLastPreset ( ) {
if ( hasLocalStorage && ! isEmbed ) {
delete exports . qs . file ;
localStorage . removeItem ( "__lastid_" + exports . store _id ) ;
}
}
getLastPreset ( ) {
return hasLocalStorage && ! isEmbed && localStorage . getItem ( "__lastid_" + exports . store _id ) ;
}
getLastPlatformID ( ) {
return hasLocalStorage && ! isEmbed && localStorage . getItem ( "__lastplatform" ) ;
}
getLastRepoID ( platform ) {
return hasLocalStorage && ! isEmbed && platform && localStorage . getItem ( "__lastrepo_" + platform ) ;
}
shouldCompleteTour ( ) {
return hasLocalStorage && ! isEmbed && ! localStorage . getItem ( "8bitworkshop.hello" ) ;
}
completedTour ( ) {
if ( hasLocalStorage && ! isEmbed )
localStorage . setItem ( "8bitworkshop.hello" , "true" ) ;
}
}
var userPrefs = new UserPrefs ( ) ;
// https://developers.google.com/web/updates/2016/06/persistent-storage
function requestPersistPermission ( interactive , failureonly ) {
if ( navigator . storage && navigator . storage . persist ) {
navigator . storage . persist ( ) . then ( persistent => {
console . log ( "requestPersistPermission =" , persistent ) ;
if ( persistent ) {
interactive && ! failureonly && alertInfo ( "Your browser says it will persist your local file edits, but you may want to back up your work anyway." ) ;
}
else {
interactive && alertError ( "Your browser refused to expand the peristent storage quota. Your edits may not be preserved after closing the page." ) ;
}
} ) ;
}
else {
interactive && alertError ( "Your browser may not persist edits after closing the page. Try a different browser." ) ;
}
}
function getCurrentPresetTitle ( ) {
if ( ! current _preset )
return exports . current _project . mainPath || "ROM" ;
else
return current _preset . title || current _preset . name || exports . current _project . mainPath || "ROM" ;
}
async function newFilesystem ( ) {
var basefs = new project _1 . WebPresetsFileSystem ( exports . platform _id ) ;
if ( isElectron ) {
console . log ( 'using electron with local filesystem' , alternateLocalFilesystem ) ;
return new project _1 . OverlayFilesystem ( basefs , alternateLocalFilesystem ) ;
}
else if ( exports . qs . localfs != null ) {
return new project _1 . OverlayFilesystem ( basefs , await getLocalFilesystem ( exports . qs . localfs ) ) ;
}
else {
return new project _1 . OverlayFilesystem ( basefs , new project _1 . LocalForageFilesystem ( store ) ) ;
}
}
async function initProject ( ) {
var filesystem = await newFilesystem ( ) ;
exports . current _project = new project _1 . CodeProject ( newWorker ( ) , exports . platform _id , exports . platform , filesystem ) ;
exports . projectWindows = new windows _1 . ProjectWindows ( $ ( "#workspace" ) [ 0 ] , exports . current _project ) ;
exports . current _project . callbackBuildResult = ( result ) => {
setCompileOutput ( result ) ;
} ;
exports . current _project . callbackBuildStatus = ( busy ) => {
setBusyStatus ( busy ) ;
} ;
}
function setBusyStatus ( busy ) {
if ( busy ) {
toolbar . addClass ( "is-busy" ) ;
}
else {
toolbar . removeClass ( "is-busy" ) ;
}
$ ( '#compile_spinner' ) . css ( 'visibility' , busy ? 'visible' : 'hidden' ) ;
}
function refreshWindowList ( ) {
var ul = $ ( "#windowMenuList" ) . empty ( ) ;
var separate = false ;
function addWindowItem ( id , name , createfn ) {
if ( separate ) {
ul . append ( document . createElement ( "hr" ) ) ;
separate = false ;
}
var li = document . createElement ( "li" ) ;
var a = document . createElement ( "a" ) ;
a . setAttribute ( "class" , "dropdown-item" ) ;
a . setAttribute ( "href" , "#" ) ;
a . setAttribute ( "data-wndid" , id ) ;
if ( id == exports . projectWindows . getActiveID ( ) )
$ ( a ) . addClass ( "dropdown-item-checked" ) ;
a . appendChild ( document . createTextNode ( name ) ) ;
li . appendChild ( a ) ;
ul . append ( li ) ;
if ( createfn ) {
var onopen = ( id , wnd ) => {
ul . find ( 'a' ) . removeClass ( "dropdown-item-checked" ) ;
$ ( a ) . addClass ( "dropdown-item-checked" ) ;
} ;
exports . projectWindows . setCreateFunc ( id , createfn ) ;
exports . projectWindows . setShowFunc ( id , onopen ) ;
$ ( a ) . click ( ( e ) => {
exports . projectWindows . createOrShow ( id ) ;
lastViewClicked = id ;
} ) ;
}
}
function loadEditor ( path ) {
var tool = exports . platform . getToolForFilename ( path ) ;
var mode = tool && TOOL _TO _SOURCE _STYLE [ tool ] ;
return new editors _1 . SourceEditor ( path , mode ) ;
}
function addEditorItem ( id ) {
addWindowItem ( id , ( 0 , util _1 . getFilenameForPath ) ( id ) , ( ) => {
var data = exports . current _project . getFile ( id ) ;
if ( typeof data === 'string' )
return loadEditor ( id ) ;
else if ( data instanceof Uint8Array )
return new debugviews _1 . BinaryFileView ( id , data ) ;
} ) ;
}
// add main file editor
addEditorItem ( exports . current _project . mainPath ) ;
// add other source files
exports . current _project . iterateFiles ( ( id , text ) => {
if ( text && id != exports . current _project . mainPath ) {
addEditorItem ( id ) ;
}
} ) ;
// add listings
separate = true ;
var listings = exports . current _project . getListings ( ) ;
if ( listings ) {
for ( var lstfn in listings ) {
var lst = listings [ lstfn ] ;
// add listing if source/assembly file exists and has text
2022-06-30 18:34:04 +00:00
if ( ( lst . assemblyfile && lst . assemblyfile . text ) || ( lst . sourcefile && lst . sourcefile . text ) || lst . text ) {
2022-02-21 15:35:52 +00:00
addWindowItem ( lstfn , ( 0 , util _1 . getFilenameForPath ) ( lstfn ) , ( path ) => {
return new editors _1 . ListingView ( path ) ;
} ) ;
}
}
}
// add other tools
separate = true ;
if ( exports . platform . disassemble && exports . platform . saveState ) {
addWindowItem ( "#disasm" , "Disassembly" , ( ) => {
return new editors _1 . DisassemblerView ( ) ;
} ) ;
}
if ( exports . platform . readAddress ) {
addWindowItem ( "#memory" , "Memory Browser" , ( ) => {
return new debugviews _1 . MemoryView ( ) ;
} ) ;
}
if ( exports . current _project . segments && exports . current _project . segments . length ) {
addWindowItem ( "#memmap" , "Memory Map" , ( ) => {
return new debugviews _1 . MemoryMapView ( ) ;
} ) ;
}
if ( exports . platform . readVRAMAddress ) {
addWindowItem ( "#memvram" , "VRAM Browser" , ( ) => {
return new debugviews _1 . VRAMMemoryView ( ) ;
} ) ;
}
if ( exports . platform . startProbing ) {
addWindowItem ( "#memheatmap" , "Memory Probe" , ( ) => {
return new debugviews _1 . AddressHeatMapView ( ) ;
} ) ;
// TODO: only if raster
addWindowItem ( "#crtheatmap" , "CRT Probe" , ( ) => {
2022-08-31 00:57:30 +00:00
//return new RasterPCHeatMapView();
return new debugviews _1 . RasterStackMapView ( ) ;
2022-02-21 15:35:52 +00:00
} ) ;
addWindowItem ( "#probelog" , "Probe Log" , ( ) => {
return new debugviews _1 . ProbeLogView ( ) ;
} ) ;
addWindowItem ( "#scanlineio" , "Scanline I/O" , ( ) => {
return new debugviews _1 . ScanlineIOView ( ) ;
} ) ;
addWindowItem ( "#symbolprobe" , "Symbol Profiler" , ( ) => {
return new debugviews _1 . ProbeSymbolView ( ) ;
} ) ;
addWindowItem ( "#callstack" , "Call Stack" , ( ) => {
return new treeviews _1 . CallStackView ( ) ;
} ) ;
/ *
addWindowItem ( "#framecalls" , "Frame Profiler" , ( ) => {
return new FrameCallsView ( ) ;
} ) ;
* /
}
if ( exports . platform . getDebugTree ) {
addWindowItem ( "#debugview" , "Debug Tree" , ( ) => {
return new treeviews _1 . DebugBrowserView ( ) ;
} ) ;
}
addWindowItem ( '#asseteditor' , 'Asset Editor' , ( ) => {
return new asseteditor _1 . AssetEditorView ( ) ;
} ) ;
}
function highlightLines ( path , hispec ) {
if ( hispec ) {
var toks = exports . qs . highlight . split ( ',' ) ;
var start = parseInt ( toks [ 0 ] ) - 1 ;
var end = parseInt ( toks [ 1 ] ) - 1 ;
var editor = exports . projectWindows . createOrShow ( path ) ;
editor . highlightLines ( start , end ) ;
}
}
function loadMainWindow ( preset _id ) {
// we need this to build create functions for the editor
refreshWindowList ( ) ;
// show main file
exports . projectWindows . createOrShow ( preset _id ) ;
// build project
exports . current _project . setMainFile ( preset _id ) ;
// highlighting?
highlightLines ( preset _id , exports . qs . highlight ) ;
}
async function loadProject ( preset _id ) {
// set current file ID
// TODO: this is done twice (mainPath and mainpath!)
exports . current _project . mainPath = preset _id ;
userPrefs . setLastPreset ( preset _id ) ;
// load files from storage or web URLs
var result = await exports . current _project . loadFiles ( [ preset _id ] ) ;
measureTimeLoad = new Date ( ) ; // for timing calc.
if ( result && result . length ) {
// file found; continue
loadMainWindow ( preset _id ) ;
}
else {
var skel = await getSkeletonFile ( preset _id ) ;
exports . current _project . filedata [ preset _id ] = skel || "\n" ;
loadMainWindow ( preset _id ) ;
// don't alert if we selected "new file"
if ( ! exports . qs . newfile ) {
alertInfo ( "Could not find file \"" + preset _id + "\". Loading default file." ) ;
}
else {
requestPersistPermission ( true , true ) ;
}
delete exports . qs . newfile ;
replaceURLState ( ) ;
}
}
function reloadProject ( id ) {
// leave repository == '/'
if ( id == '/' ) {
exports . qs = { repo : '/' } ;
}
else if ( id . indexOf ( '://' ) >= 0 ) {
var urlparse = ( 0 , services _1 . parseGithubURL ) ( id ) ;
if ( urlparse ) {
exports . qs = { repo : urlparse . repopath } ;
}
}
else {
exports . qs . platform = exports . platform _id ;
exports . qs . file = id ;
}
gotoNewLocation ( ) ;
}
async function getSkeletonFile ( fileid ) {
var ext = exports . platform . getToolForFilename ( fileid ) ;
try {
return await $ . get ( "presets/" + ( 0 , util _1 . getBasePlatform ) ( exports . platform _id ) + "/skeleton." + ext , 'text' ) ;
}
catch ( e ) {
alertError ( "Could not load skeleton for " + exports . platform _id + "/" + ext + "; using blank file" ) ;
}
}
function checkEnteredFilename ( fn ) {
if ( fn . indexOf ( " " ) >= 0 ) {
alertError ( "No spaces in filenames, please." ) ;
return false ;
}
return true ;
}
function _createNewFile ( e ) {
// TODO: support spaces
bootbox . prompt ( {
title : "Enter the name of your new main source file." ,
placeholder : "newfile" + exports . platform . getDefaultExtension ( ) ,
callback : ( filename ) => {
if ( filename && filename . trim ( ) . length > 0 ) {
if ( ! checkEnteredFilename ( filename ) )
return ;
if ( filename . indexOf ( "." ) < 0 ) {
filename += exports . platform . getDefaultExtension ( ) ;
}
var path = filename ;
gaEvent ( 'workspace' , 'file' , 'new' ) ;
exports . qs . newfile = '1' ;
reloadProject ( path ) ;
}
}
} ) ;
return true ;
}
function _uploadNewFile ( e ) {
const uploadFileElem = $ ( ` <input type="file" multiple accept="*" style="display:none"> ` ) ;
const file = uploadFileElem [ 0 ] ;
uploadFileElem . change ( ( e ) => { handleFileUpload ( file . files ) ; } ) ;
uploadFileElem . click ( ) ;
}
// called from index.html
function handleFileUpload ( files ) {
console . log ( files ) ;
var index = 0 ;
function uploadNextFile ( ) {
var f = files [ index ++ ] ;
if ( ! f ) {
console . log ( "Done uploading" , index ) ;
if ( index > 2 ) {
alertInfo ( "Files uploaded." ) ;
setTimeout ( updateSelector , 1000 ) ; // TODO: wait for files to upload
}
else {
exports . qs . file = files [ 0 ] . name ;
bootbox . confirm ( {
message : "Open '" + exports . qs . file + "' as main project file?" ,
buttons : {
confirm : { label : "Open As New Project" } ,
cancel : { label : "Include/Link With Project Later" } ,
} ,
callback : ( result ) => {
if ( result )
gotoNewLocation ( ) ;
else
setTimeout ( updateSelector , 1000 ) ; // TODO: wait for files to upload
}
} ) ;
}
gaEvent ( 'workspace' , 'file' , 'upload' ) ;
}
else {
var path = f . name ;
var reader = new FileReader ( ) ;
reader . onload = function ( e ) {
var arrbuf = e . target . result ;
var data = new Uint8Array ( arrbuf ) ;
// convert to UTF8, unless it's a binary file
if ( ( 0 , util _1 . isProbablyBinary ) ( path , data ) ) {
//gotoMainFile = false;
}
else {
data = ( 0 , util _1 . byteArrayToUTF8 ) ( data ) . replace ( '\r\n' , '\n' ) ; // convert CRLF to LF
}
// store in local forage
exports . projectWindows . updateFile ( path , data ) ;
console . log ( "Uploaded " + path + " " + data . length + " bytes" ) ;
uploadNextFile ( ) ;
} ;
reader . readAsArrayBuffer ( f ) ; // read as binary
}
}
if ( files )
uploadNextFile ( ) ;
}
async function _openLocalDirectory ( e ) {
var pickerfn = window [ 'showDirectoryPicker' ] ;
if ( ! pickerfn ) {
bootbox . alert ( ` This browser can't open local files on your computer, yet. Try Chrome. ` ) ;
}
var dirHandle = await pickerfn ( ) ;
var repoid = dirHandle . name ;
var storekey = '__localfs__' + repoid ;
var fsdata = {
handle : dirHandle ,
} ;
var lstore = localforage . createInstance ( {
name : storekey ,
version : 2.0
} ) ;
await lstore . setItem ( storekey , fsdata ) ;
exports . qs = { localfs : repoid } ;
gotoNewLocation ( true ) ;
}
async function promptUser ( message ) {
return new Promise ( ( resolve , reject ) => {
bootbox . prompt ( message , ( result ) => {
resolve ( result ) ;
} ) ;
} ) ;
}
async function getLocalFilesystem ( repoid ) {
const options = { mode : 'readwrite' } ;
var storekey = '__localfs__' + repoid ;
var lstore = localforage . createInstance ( {
name : storekey ,
version : 2.0
} ) ;
var fsdata = await lstore . getItem ( storekey ) ;
var dirHandle = fsdata . handle ;
console . log ( fsdata , dirHandle ) ;
var granted = await dirHandle . queryPermission ( options ) ;
console . log ( granted ) ;
if ( granted !== 'granted' ) {
await promptUser ( ` Request permissions to access filesystem? ` ) ;
granted = await dirHandle . requestPermission ( options ) ;
}
if ( granted !== 'granted' ) {
bootbox . alert ( ` Could not get permission to access filesystem. ` ) ;
return ;
}
return {
getFileData : async ( path ) => {
console . log ( 'getFileData' , path ) ;
let fileHandle = await dirHandle . getFileHandle ( path , { create : false } ) ;
console . log ( 'getFileData' , fileHandle ) ;
let file = await fileHandle . getFile ( ) ;
console . log ( 'getFileData' , file ) ;
let contents = await ( ( 0 , util _1 . isProbablyBinary ) ( path ) ? file . binary ( ) : file . text ( ) ) ;
console . log ( fileHandle , file , contents ) ;
return contents ;
} ,
setFileData : async ( path , data ) => {
//let vh = await dirHandle.getFileHandle(path, { create: true });
}
} ;
}
function getCurrentMainFilename ( ) {
return ( 0 , util _1 . getFilenameForPath ) ( exports . current _project . mainPath ) ;
}
function getCurrentEditorFilename ( ) {
return ( 0 , util _1 . getFilenameForPath ) ( exports . projectWindows . getActiveID ( ) ) ;
}
// GITHUB stuff (TODO: move)
var githubService ;
function getCookie ( name ) {
var nameEQ = name + "=" ;
var ca = document . cookie . split ( ';' ) ;
for ( var i = 0 ; i < ca . length ; i ++ ) {
var c = ca [ i ] ;
while ( c . charAt ( 0 ) == ' ' )
c = c . substring ( 1 , c . length ) ;
if ( c . indexOf ( nameEQ ) == 0 )
return c . substring ( nameEQ . length , c . length ) ;
}
return null ;
}
async function getGithubService ( ) {
if ( ! githubService ) {
// load github API client
await ( 0 , util _1 . loadScript ) ( 'lib/octokat.js' ) ;
// load firebase
await ( 0 , util _1 . loadScript ) ( 'https://www.gstatic.com/firebasejs/8.8.1/firebase-app.js' ) ;
await ( 0 , util _1 . loadScript ) ( 'https://www.gstatic.com/firebasejs/8.8.1/firebase-auth.js' ) ;
2022-02-21 15:42:49 +00:00
await ( 0 , util _1 . loadScript ) ( 'https://8bitworkshop.com/config.js' ) ;
2022-02-21 15:35:52 +00:00
// get github API key from cookie
// TODO: move to service?
var ghkey = getCookie ( '__github_key' ) ;
githubService = new services _1 . GithubService ( Octokat , ghkey , store , exports . current _project ) ;
console . log ( "loaded github service" ) ;
}
return githubService ;
}
function getBoundGithubURL ( ) {
var toks = ( exports . repo _id || '' ) . split ( '/' ) ;
if ( toks . length != 2 ) {
alertError ( "<p>You are not in a GitHub repository.</p><p>Choose one from the pulldown, or Import or Publish one.</p>" ) ;
return null ;
}
return 'https://github.com/' + toks [ 0 ] + '/' + toks [ 1 ] ;
}
async function importProjectFromGithub ( githuburl , replaceURL ) {
var sess ;
var urlparse = ( 0 , services _1 . parseGithubURL ) ( githuburl ) ;
if ( ! urlparse ) {
alertError ( 'Could not parse Github URL.' ) ;
return ;
}
// redirect to repo if exists
var existing = ( 0 , services _1 . getRepos ) ( ) [ urlparse . repopath ] ;
if ( existing && ! confirm ( "You've already imported " + urlparse . repopath + " -- do you want to replace all local files?" ) ) {
return ;
}
// create new store for imported repository
setWaitDialog ( true ) ;
var newstore = ( 0 , project _1 . createNewPersistentStore ) ( urlparse . repopath ) ;
// import into new store
setWaitProgress ( 0.25 ) ;
var gh = await getGithubService ( ) ;
return gh . import ( githuburl ) . then ( ( sess1 ) => {
sess = sess1 ;
setWaitProgress ( 0.75 ) ;
return gh . pull ( githuburl , newstore ) ;
} ) . then ( ( sess2 ) => {
// TODO: only first session has mainPath?
// reload repo
exports . qs = { repo : sess . repopath } ; // file:sess.mainPath, platform:sess.platform_id};
setWaitDialog ( false ) ;
gaEvent ( 'sync' , 'import' , githuburl ) ;
gotoNewLocation ( replaceURL ) ;
} ) . catch ( ( e ) => {
setWaitDialog ( false ) ;
console . log ( e ) ;
alertError ( "<p>Could not import " + githuburl + ".</p>" + e ) ;
} ) ;
}
async function _loginToGithub ( e ) {
var gh = await getGithubService ( ) ;
gh . login ( ) . then ( ( ) => {
alertInfo ( "You are signed in to Github." ) ;
} ) . catch ( ( e ) => {
alertError ( "<p>Could not sign in.</p>" + e ) ;
} ) ;
}
async function _logoutOfGithub ( e ) {
var gh = await getGithubService ( ) ;
gh . logout ( ) . then ( ( ) => {
alertInfo ( "You are logged out of Github." ) ;
} ) ;
}
function _importProjectFromGithub ( e ) {
var modal = $ ( "#importGithubModal" ) ;
var btn = $ ( "#importGithubButton" ) ;
modal . modal ( 'show' ) ;
btn . off ( 'click' ) . on ( 'click' , ( ) => {
var githuburl = $ ( "#importGithubURL" ) . val ( ) + "" ;
modal . modal ( 'hide' ) ;
importProjectFromGithub ( githuburl , false ) ;
} ) ;
}
function _publishProjectToGithub ( e ) {
if ( exports . repo _id ) {
if ( ! confirm ( "This project (" + exports . current _project . mainPath + ") is already bound to a Github repository. Do you want to re-publish to a new repository? (You can instead choose 'Push Changes' to update files in the existing repository.)" ) )
return ;
}
var modal = $ ( "#publishGithubModal" ) ;
var btn = $ ( "#publishGithubButton" ) ;
$ ( "#githubRepoName" ) . val ( ( 0 , util _1 . getFilenamePrefix ) ( ( 0 , util _1 . getFilenameForPath ) ( exports . current _project . mainPath ) ) ) ;
modal . modal ( 'show' ) ;
btn . off ( 'click' ) . on ( 'click' , async ( ) => {
var name = $ ( "#githubRepoName" ) . val ( ) + "" ;
var desc = $ ( "#githubRepoDesc" ) . val ( ) + "" ;
var priv = $ ( "#githubRepoPrivate" ) . val ( ) == 'private' ;
var license = $ ( "#githubRepoLicense" ) . val ( ) + "" ;
var sess ;
if ( ! name ) {
alertError ( "You did not enter a project name." ) ;
return ;
}
modal . modal ( 'hide' ) ;
setWaitDialog ( true ) ;
var gh = await getGithubService ( ) ;
gh . login ( ) . then ( ( ) => {
setWaitProgress ( 0.25 ) ;
return gh . publish ( name , desc , license , priv ) ;
} ) . then ( ( _sess ) => {
sess = _sess ;
setWaitProgress ( 0.5 ) ;
exports . repo _id = exports . qs . repo = sess . repopath ;
return pushChangesToGithub ( 'initial import from 8bitworkshop.com' ) ;
} ) . then ( ( ) => {
gaEvent ( 'sync' , 'publish' , priv ? "" : name ) ;
importProjectFromGithub ( sess . url , false ) ;
} ) . catch ( ( e ) => {
setWaitDialog ( false ) ;
console . log ( e ) ;
alertError ( "Could not publish GitHub repository: " + e ) ;
} ) ;
} ) ;
}
function _pushProjectToGithub ( e ) {
var ghurl = getBoundGithubURL ( ) ;
if ( ! ghurl )
return ;
var modal = $ ( "#pushGithubModal" ) ;
var btn = $ ( "#pushGithubButton" ) ;
modal . modal ( 'show' ) ;
btn . off ( 'click' ) . on ( 'click' , ( ) => {
var commitMsg = $ ( "#githubCommitMsg" ) . val ( ) + "" ;
modal . modal ( 'hide' ) ;
pushChangesToGithub ( commitMsg ) ;
} ) ;
}
function _pullProjectFromGithub ( e ) {
var ghurl = getBoundGithubURL ( ) ;
if ( ! ghurl )
return ;
bootbox . confirm ( "Pull from repository and replace all local files? Any changes you've made will be overwritten." , async ( ok ) => {
if ( ok ) {
setWaitDialog ( true ) ;
var gh = await getGithubService ( ) ;
gh . pull ( ghurl ) . then ( ( sess ) => {
setWaitDialog ( false ) ;
exports . projectWindows . updateAllOpenWindows ( store ) ;
} ) ;
}
} ) ;
}
function confirmCommit ( sess ) {
return new Promise ( ( resolve , reject ) => {
var files = sess . commit . files ;
console . log ( files ) ;
// anything changed?
if ( files . length == 0 ) {
setWaitDialog ( false ) ;
bootbox . alert ( "No files changed." ) ;
return ;
}
// build commit confirm message
var msg = "" ;
for ( var f of files ) {
msg += f . filename + ": " + f . status ;
if ( f . additions || f . deletions || f . changes ) {
msg += " (" + f . additions + " additions, " + f . deletions + " deletions, " + f . changes + " changes)" ;
}
;
msg += "<br/>" ;
}
// show dialog, continue when yes
bootbox . confirm ( msg , ( ok ) => {
if ( ok ) {
resolve ( sess ) ;
}
else {
setWaitDialog ( false ) ;
}
} ) ;
} ) ;
}
async function pushChangesToGithub ( message ) {
var ghurl = getBoundGithubURL ( ) ;
if ( ! ghurl )
return ;
// build file list for push
var files = [ ] ;
for ( var path in exports . current _project . filedata ) {
var newpath = exports . current _project . stripLocalPath ( path ) ;
var data = exports . current _project . filedata [ path ] ;
if ( newpath && data ) {
files . push ( { path : newpath , data : data } ) ;
}
}
// include built ROM file in bin/[mainfile].rom
if ( current _output instanceof Uint8Array ) {
let binpath = "bin/" + getCurrentMainFilename ( ) + ".rom" ;
files . push ( { path : binpath , data : current _output } ) ;
}
// push files
setWaitDialog ( true ) ;
var gh = await getGithubService ( ) ;
return gh . login ( ) . then ( ( ) => {
setWaitProgress ( 0.5 ) ;
return gh . commit ( ghurl , message , files ) ;
} ) . then ( ( sess ) => {
return confirmCommit ( sess ) ;
} ) . then ( ( sess ) => {
return gh . push ( sess ) ;
} ) . then ( ( sess ) => {
setWaitDialog ( false ) ;
alertInfo ( "Pushed files to " + ghurl ) ;
return sess ;
} ) . catch ( ( e ) => {
setWaitDialog ( false ) ;
console . log ( e ) ;
alertError ( "Could not push GitHub repository: " + e ) ;
} ) ;
}
function _deleteRepository ( ) {
var ghurl = getBoundGithubURL ( ) ;
if ( ! ghurl )
return ;
bootbox . prompt ( "<p>Are you sure you want to delete this repository (" + ghurl + ") from browser storage?</p><p>All changes since last commit will be lost.</p><p>Type DELETE to proceed.<p>" , ( yes ) => {
if ( yes . trim ( ) . toUpperCase ( ) == "DELETE" ) {
deleteRepository ( ) ;
}
} ) ;
}
function deleteRepository ( ) {
var ghurl = getBoundGithubURL ( ) ;
var gh ;
setWaitDialog ( true ) ;
// delete all keys in storage
store . keys ( ) . then ( ( keys ) => {
return Promise . all ( keys . map ( ( key ) => {
return store . removeItem ( key ) ;
} ) ) ;
} ) . then ( ( ) => {
gh = getGithubService ( ) ;
return gh . getGithubSession ( ghurl ) ;
} ) . then ( ( sess ) => {
// un-bind repo from list
gh . bind ( sess , false ) ;
} ) . then ( ( ) => {
setWaitDialog ( false ) ;
// leave repository
exports . qs = { repo : '/' } ;
gotoNewLocation ( ) ;
} ) ;
}
function _shareEmbedLink ( e ) {
if ( current _output == null ) {
alertError ( "Please fix errors before sharing." ) ;
return true ;
}
if ( ! ( current _output instanceof Uint8Array ) ) {
alertError ( "Can't share a Verilog executable yet. (It's not actually a ROM...)" ) ;
return true ;
}
loadClipboardLibrary ( ) ;
( 0 , util _1 . loadScript ) ( 'lib/liblzg.js' ) . then ( ( ) => {
// TODO: Module is bad var name (conflicts with MAME)
var lzgrom = ( 0 , util _1 . compressLZG ) ( window [ 'Module' ] , Array . from ( current _output ) ) ;
window [ 'Module' ] = null ; // so we load it again next time
var lzgb64 = btoa ( ( 0 , util _1 . byteArrayToString ) ( lzgrom ) ) ;
var embed = {
p : exports . platform _id ,
//n: current_project.mainPath,
r : lzgb64
} ;
var linkqs = $ . param ( embed ) ;
var fulllink = get8bitworkshopLink ( linkqs , 'player.html' ) ;
var iframelink = '<iframe width=640 height=600 src="' + fulllink + '">' ;
$ ( "#embedLinkTextarea" ) . text ( fulllink ) ;
$ ( "#embedIframeTextarea" ) . text ( iframelink ) ;
$ ( "#embedLinkModal" ) . modal ( 'show' ) ;
$ ( "#embedAdviceWarnAll" ) . hide ( ) ;
$ ( "#embedAdviceWarnIE" ) . hide ( ) ;
if ( fulllink . length >= 65536 )
$ ( "#embedAdviceWarnAll" ) . show ( ) ;
else if ( fulllink . length >= 5120 )
$ ( "#embedAdviceWarnIE" ) . show ( ) ;
} ) ;
return true ;
}
function loadClipboardLibrary ( ) {
// can happen in background because it won't be used until user clicks
console . log ( 'clipboard' ) ;
Promise . resolve ( ) . then ( ( ) => _ _importStar ( require ( 'clipboard' ) ) ) . then ( ( clipmod ) => {
let ClipboardJS = clipmod . default ;
new ClipboardJS ( ".btn" ) ;
} ) ;
}
function get8bitworkshopLink ( linkqs , fn ) {
console . log ( linkqs ) ;
var loc = window . location ;
var prefix = loc . pathname . replace ( 'index.html' , '' ) ;
var protocol = ( loc . host == '8bitworkshop.com' ) ? 'https:' : loc . protocol ;
var fulllink = protocol + '//' + loc . host + prefix + fn + '?' + linkqs ;
return fulllink ;
}
function _downloadCassetteFile _apple2 ( e ) {
var addr = exports . compparams && exports . compparams . code _start ;
( 0 , util _1 . loadScript ) ( 'lib/c2t.js' ) . then ( ( ) => {
var stdout = '' ;
var print _fn = function ( s ) { stdout += s + "\n" ; } ;
var c2t = window [ 'c2t' ] ( {
noInitialRun : true ,
print : print _fn ,
printErr : print _fn
} ) ;
var FS = c2t [ 'FS' ] ;
var rompath = getCurrentMainFilename ( ) + ".bin" ;
var audpath = getCurrentMainFilename ( ) + ".wav" ;
FS . writeFile ( rompath , current _output , { encoding : 'binary' } ) ;
var args = [ "-2bc" , rompath + ',' + addr . toString ( 16 ) , audpath ] ;
c2t . callMain ( args ) ;
var audout = FS . readFile ( audpath , { 'encoding' : 'binary' } ) ;
if ( audout ) {
var blob = new Blob ( [ audout ] , { type : "audio/wav" } ) ;
( 0 , file _saver _1 . saveAs ) ( blob , audpath ) ;
stdout += "Then connect your audio output to the cassette input, turn up the volume, and play the audio file." ;
alertInfo ( '<pre style="white-space: pre-wrap">' + stdout + '</pre>' ) ;
}
} ) ;
}
function _downloadCassetteFile _vcs ( e ) {
( 0 , util _1 . loadScript ) ( 'lib/makewav.js' ) . then ( ( ) => {
let stdout = '' ;
let print _fn = function ( s ) { stdout += s + "\n" ; } ;
var prefix = ( 0 , util _1 . getFilenamePrefix ) ( getCurrentMainFilename ( ) ) ;
let rompath = prefix + ".bin" ;
let audpath = prefix + ".wav" ;
let _makewav = window [ 'makewav' ] ( {
noInitialRun : false ,
print : print _fn ,
printErr : print _fn ,
arguments : [ '-ts' , '-f0' , '-v10' , rompath ] ,
preRun : ( mod ) => {
let FS = mod [ 'FS' ] ;
FS . writeFile ( rompath , current _output , { encoding : 'binary' } ) ;
}
} ) ;
_makewav . ready . then ( ( makewav ) => {
let args = [ rompath ] ;
makewav . run ( args ) ;
console . log ( stdout ) ;
let FS = makewav [ 'FS' ] ;
let audout = FS . readFile ( audpath , { 'encoding' : 'binary' } ) ;
if ( audout ) {
let blob = new Blob ( [ audout ] , { type : "audio/wav" } ) ;
( 0 , file _saver _1 . saveAs ) ( blob , audpath ) ;
stdout += "\nConnect your audio output to the SuperCharger input, turn up the volume, and play the audio file." ;
alertInfo ( '<pre style="white-space: pre-wrap">' + stdout + '</pre>' ) ;
}
} ) ;
} ) ;
}
function _downloadCassetteFile ( e ) {
if ( current _output == null ) {
alertError ( "Please fix errors before exporting." ) ;
return true ;
}
var fn ;
switch ( ( 0 , util _1 . getBasePlatform ) ( exports . platform _id ) ) {
case 'vcs' :
fn = _downloadCassetteFile _vcs ;
break ;
case 'apple2' :
fn = _downloadCassetteFile _apple2 ;
break ;
}
if ( fn === undefined ) {
alertError ( "Cassette export is not supported on this platform." ) ;
return true ;
}
fn ( e ) ;
}
function _revertFile ( e ) {
var wnd = exports . projectWindows . getActive ( ) ;
if ( wnd && wnd . setText ) {
var fn = exports . projectWindows . getActiveID ( ) ;
$ . get ( "presets/" + ( 0 , util _1 . getBasePlatform ) ( exports . platform _id ) + "/" + fn , ( text ) => {
bootbox . confirm ( "Reset '" + fn + "' to default?" , ( ok ) => {
if ( ok ) {
wnd . setText ( text ) ;
}
} ) ;
} , 'text' )
. fail ( ( ) => {
if ( exports . repo _id )
alertError ( "Can only revert built-in examples. If you want to revert all files, You can pull from the repository." ) ;
else
alertError ( "Can only revert built-in examples." ) ;
} ) ;
}
else {
alertError ( "Cannot revert the active window. Please choose a text file." ) ;
}
}
function _deleteFile ( e ) {
var wnd = exports . projectWindows . getActive ( ) ;
if ( wnd && wnd . getPath ) {
var fn = exports . projectWindows . getActiveID ( ) ;
bootbox . confirm ( "Delete '" + fn + "'?" , ( ok ) => {
if ( ok ) {
store . removeItem ( fn ) . then ( ( ) => {
// if we delete what is selected
if ( exports . qs . file == fn ) {
userPrefs . unsetLastPreset ( ) ;
gotoNewLocation ( ) ;
}
else {
updateSelector ( ) ;
alertInfo ( "Deleted " + fn ) ;
}
} ) ;
}
} ) ;
}
else {
alertError ( "Cannot delete the active window." ) ;
}
}
function _renameFile ( e ) {
var wnd = exports . projectWindows . getActive ( ) ;
if ( wnd && wnd . getPath && exports . current _project . getFile ( wnd . getPath ( ) ) ) {
var fn = exports . projectWindows . getActiveID ( ) ;
bootbox . prompt ( {
title : "Rename '" + fn + "' to?" ,
value : fn ,
callback : ( newfn ) => {
var data = exports . current _project . getFile ( wnd . getPath ( ) ) ;
if ( newfn && newfn != fn && data ) {
if ( ! checkEnteredFilename ( newfn ) )
return ;
store . removeItem ( fn ) . then ( ( ) => {
return store . setItem ( newfn , data ) ;
} ) . then ( ( ) => {
updateSelector ( ) ;
alert ( "Renamed " + fn + " to " + newfn ) ; // need alert() so it pauses
if ( fn == exports . current _project . mainPath ) {
reloadProject ( newfn ) ;
}
} ) ;
}
}
} ) ;
}
else {
alertError ( "Cannot rename the active window." ) ;
}
}
function _downloadROMImage ( e ) {
if ( current _output == null ) {
alertError ( "Please finish compiling with no errors before downloading ROM." ) ;
return true ;
}
var prefix = ( 0 , util _1 . getFilenamePrefix ) ( getCurrentMainFilename ( ) ) ;
if ( exports . platform . getDownloadFile ) {
var dl = exports . platform . getDownloadFile ( ) ;
var prefix = ( 0 , util _1 . getFilenamePrefix ) ( getCurrentMainFilename ( ) ) ;
( 0 , file _saver _1 . saveAs ) ( dl . blob , prefix + dl . extension ) ;
}
else if ( current _output instanceof Uint8Array ) {
var blob = new Blob ( [ current _output ] , { type : "application/octet-stream" } ) ;
var suffix = ( exports . platform . getROMExtension && exports . platform . getROMExtension ( current _output ) )
|| "-" + ( 0 , util _1 . getBasePlatform ) ( exports . platform _id ) + ".bin" ;
( 0 , file _saver _1 . saveAs ) ( blob , prefix + suffix ) ;
}
else {
alertError ( ` The " ${ exports . platform _id } " platform doesn't have downloadable ROMs. ` ) ;
}
}
function _downloadSourceFile ( e ) {
var text = exports . projectWindows . getCurrentText ( ) ;
if ( ! text )
return false ;
var blob = new Blob ( [ text ] , { type : "text/plain;charset=utf-8" } ) ;
( 0 , file _saver _1 . saveAs ) ( blob , getCurrentEditorFilename ( ) , { autoBom : false } ) ;
}
async function newJSZip ( ) {
let JSZip = ( await Promise . resolve ( ) . then ( ( ) => _ _importStar ( require ( 'jszip' ) ) ) ) . default ;
return new JSZip ( ) ;
}
async function _downloadProjectZipFile ( e ) {
var zip = await newJSZip ( ) ;
exports . current _project . iterateFiles ( ( id , data ) => {
if ( data ) {
zip . file ( ( 0 , util _1 . getFilenameForPath ) ( id ) , data ) ;
}
} ) ;
zip . generateAsync ( { type : "blob" } ) . then ( ( content ) => {
( 0 , file _saver _1 . saveAs ) ( content , getCurrentMainFilename ( ) + "-" + ( 0 , util _1 . getBasePlatform ) ( exports . platform _id ) + ".zip" ) ;
} ) ;
}
2022-07-29 23:30:11 +00:00
function _downloadSymFile ( e ) {
let symfile = exports . platform . getDebugSymbolFile && exports . platform . getDebugSymbolFile ( ) ;
if ( ! symfile ) {
alertError ( "This project does not have debug information." ) ;
return ;
}
var prefix = ( 0 , util _1 . getFilenamePrefix ) ( getCurrentMainFilename ( ) ) ;
( 0 , file _saver _1 . saveAs ) ( symfile . blob , prefix + symfile . extension , { autoBom : false } ) ;
}
2022-02-21 15:35:52 +00:00
async function _downloadAllFilesZipFile ( e ) {
var zip = await newJSZip ( ) ;
var keys = await store . keys ( ) ;
setWaitDialog ( true ) ;
try {
var i = 0 ;
await Promise . all ( keys . map ( ( path ) => {
return store . getItem ( path ) . then ( ( text ) => {
setWaitProgress ( i ++ / ( k e y s . l e n g t h + 1 ) ) ;
if ( text ) {
zip . file ( path , text ) ;
}
} ) ;
} ) ) ;
var content = await zip . generateAsync ( { type : "blob" } ) ;
( 0 , file _saver _1 . saveAs ) ( content , ( 0 , util _1 . getBasePlatform ) ( exports . platform _id ) + "-all.zip" ) ;
}
finally {
setWaitDialog ( false ) ;
}
}
function populateExamples ( sel ) {
var files = { } ;
sel . append ( $ ( "<option />" ) . text ( "--------- Examples ---------" ) . attr ( 'disabled' , 'true' ) ) ;
for ( var i = 0 ; i < PRESETS . length ; i ++ ) {
var preset = PRESETS [ i ] ;
var name = preset . chapter ? ( preset . chapter + ". " + preset . name ) : preset . name ;
var isCurrentPreset = preset . id == exports . current _project . mainPath ;
sel . append ( $ ( "<option />" ) . val ( preset . id ) . text ( name ) . attr ( 'selected' , isCurrentPreset ? 'selected' : null ) ) ;
if ( isCurrentPreset )
current _preset = preset ;
files [ preset . id ] = name ;
}
return files ;
}
function populateRepos ( sel ) {
if ( hasLocalStorage && ! isElectron ) {
var n = 0 ;
var repos = ( 0 , services _1 . getRepos ) ( ) ;
if ( repos ) {
for ( let repopath in repos ) {
var repo = repos [ repopath ] ;
if ( repo . platform _id && ( 0 , util _1 . getBasePlatform ) ( repo . platform _id ) == ( 0 , util _1 . getBasePlatform ) ( exports . platform _id ) ) {
if ( n ++ == 0 )
sel . append ( $ ( "<option />" ) . text ( "------ Repositories ------" ) . attr ( 'disabled' , 'true' ) ) ;
sel . append ( $ ( "<option />" ) . val ( repo . url ) . text ( repo . url . substring ( repo . url . indexOf ( '/' ) ) ) ) ;
}
}
}
}
}
async function populateFiles ( sel , category , prefix , foundFiles ) {
var keys = await store . keys ( ) ;
var numFound = 0 ;
if ( ! keys )
keys = [ ] ;
for ( var i = 0 ; i < keys . length ; i ++ ) {
var key = keys [ i ] ;
if ( key . startsWith ( prefix ) && ! foundFiles [ key ] ) {
if ( numFound ++ == 0 )
sel . append ( $ ( "<option />" ) . text ( "------- " + category + " -------" ) . attr ( 'disabled' , 'true' ) ) ;
var name = key . substring ( prefix . length ) ;
sel . append ( $ ( "<option />" ) . val ( key ) . text ( name ) . attr ( 'selected' , ( key == exports . current _project . mainPath ) ? 'selected' : null ) ) ;
}
}
}
function finishSelector ( sel ) {
sel . css ( 'visibility' , 'visible' ) ;
// create option if not selected
var main = exports . current _project . mainPath ;
if ( sel . val ( ) != main ) {
sel . append ( $ ( "<option />" ) . val ( main ) . text ( main ) . attr ( 'selected' , 'selected' ) ) ;
}
}
async function updateSelector ( ) {
var sel = $ ( "#preset_select" ) . empty ( ) ;
if ( ! exports . repo _id ) {
// normal: populate repos, examples, and local files
populateRepos ( sel ) ;
var foundFiles = populateExamples ( sel ) ;
await populateFiles ( sel , "Local Files" , "" , foundFiles ) ;
finishSelector ( sel ) ;
}
else {
sel . append ( $ ( "<option />" ) . val ( '/' ) . text ( 'Leave Repository' ) ) ;
$ ( "#repo_name" ) . text ( ( 0 , util _1 . getFilenameForPath ) ( exports . repo _id ) + '/' ) . show ( ) ;
// repo: populate all files
await populateFiles ( sel , exports . repo _id , "" , { } ) ;
finishSelector ( sel ) ;
}
// set click handlers
sel . off ( 'change' ) . change ( function ( e ) {
reloadProject ( $ ( this ) . val ( ) . toString ( ) ) ;
} ) ;
}
function getErrorElement ( err ) {
var span = $ ( '<p/>' ) ;
if ( err . path != null ) {
var s = err . line ? err . label ? ` ( ${ err . path } @ ${ err . label } ) ` : ` ( ${ err . path } : ${ err . line } ) ` : ` ( ${ err . path } ) ` ;
var link = $ ( '<a/>' ) . text ( s ) ;
var path = err . path ;
// TODO: hack because examples/foo.a only gets listed as foo.a
if ( path == getCurrentMainFilename ( ) )
path = exports . current _project . mainPath ;
// click link to open file, if it's available...
if ( exports . projectWindows . isWindow ( path ) ) {
link . click ( ( ev ) => {
var wnd = exports . projectWindows . createOrShow ( path ) ;
if ( wnd instanceof editors _1 . SourceEditor ) {
wnd . setCurrentLine ( err , true ) ;
}
} ) ;
}
span . append ( link ) ;
span . append ( ' ' ) ;
}
span . append ( $ ( '<span/>' ) . text ( err . msg ) ) ;
return span ;
}
function hideErrorAlerts ( ) {
$ ( "#error_alert" ) . hide ( ) ;
errorWasRuntime = false ;
}
function showErrorAlert ( errors , runtime ) {
var div = $ ( "#error_alert_msg" ) . empty ( ) ;
for ( var err of errors . slice ( 0 , 10 ) ) {
div . append ( getErrorElement ( err ) ) ;
}
$ ( "#error_alert" ) . show ( ) ;
errorWasRuntime = runtime ;
}
function showExceptionAsError ( err , msg ) {
if ( msg != null ) {
var werr = { msg : msg , line : 0 } ;
if ( err instanceof emu _1 . EmuHalt && err . $loc ) {
werr = Object . create ( err . $loc ) ;
werr . msg = msg ;
console . log ( werr ) ;
}
showErrorAlert ( [ werr ] , true ) ;
}
}
var measureTimeStart = new Date ( ) ;
var measureTimeLoad ;
function measureBuildTime ( ) {
if ( window [ 'ga' ] && measureTimeLoad ) {
var measureTimeBuild = new Date ( ) ;
ga ( 'send' , 'timing' , 'load' , exports . platform _id , ( measureTimeLoad . getTime ( ) - measureTimeStart . getTime ( ) ) ) ;
ga ( 'send' , 'timing' , 'build' , exports . platform _id , ( measureTimeBuild . getTime ( ) - measureTimeLoad . getTime ( ) ) ) ;
measureTimeLoad = null ; // only measure once
}
//gaEvent('build', platform_id);
}
async function setCompileOutput ( data ) {
// errors? mark them in editor
if ( 'errors' in data && data . errors . length > 0 ) {
toolbar . addClass ( "has-errors" ) ;
exports . projectWindows . setErrors ( data . errors ) ;
refreshWindowList ( ) ; // to make sure windows are created for showErrorAlert()
showErrorAlert ( data . errors , false ) ;
}
else {
toolbar . removeClass ( "has-errors" ) ; // may be added in next callback
exports . projectWindows . setErrors ( null ) ;
hideErrorAlerts ( ) ;
// exit if compile output unchanged
if ( data == null || ( 'unchanged' in data && data . unchanged ) )
return ;
// make sure it's a WorkerOutputResult
if ( ! ( 'output' in data ) )
return ;
// process symbol map
exports . platform . debugSymbols = new baseplatform _1 . DebugSymbols ( data . symbolmap , data . debuginfo ) ;
exports . compparams = data . params ;
// load ROM
var rom = data . output ;
if ( rom != null ) {
try {
clearBreakpoint ( ) ; // so we can replace memory (TODO: change toolbar btn)
_resetRecording ( ) ;
await exports . platform . loadROM ( getCurrentPresetTitle ( ) , rom ) ;
current _output = rom ;
if ( ! userPaused )
_resume ( ) ;
measureBuildTime ( ) ;
writeOutputROMFile ( ) ;
}
catch ( e ) {
console . log ( e ) ;
toolbar . addClass ( "has-errors" ) ;
showExceptionAsError ( e , e + "" ) ;
current _output = null ;
refreshWindowList ( ) ;
return ;
}
}
// update all windows (listings)
refreshWindowList ( ) ;
exports . projectWindows . refresh ( false ) ;
}
}
async function loadBIOSFromProject ( ) {
if ( exports . platform . loadBIOS ) {
var biospath = exports . platform _id + '.rom' ;
var biosdata = await store . getItem ( biospath ) ;
if ( biosdata instanceof Uint8Array ) {
console . log ( 'loading BIOS' , biospath , biosdata . length + " bytes" ) ;
exports . platform . loadBIOS ( biospath , biosdata ) ;
}
else {
console . log ( 'BIOS file must be binary' ) ;
}
}
}
function hideDebugInfo ( ) {
var meminfo = $ ( "#mem_info" ) ;
meminfo . hide ( ) ;
lastDebugInfo = null ;
}
function showDebugInfo ( state ) {
if ( ! ( 0 , baseplatform _1 . isDebuggable ) ( exports . platform ) )
return ;
var meminfo = $ ( "#mem_info" ) ;
var allcats = exports . platform . getDebugCategories ( ) ;
if ( allcats && ! debugCategory )
debugCategory = allcats [ 0 ] ;
var s = state && exports . platform . getDebugInfo ( debugCategory , state ) ;
if ( s ) {
var hs = lastDebugInfo ? ( 0 , util _1 . highlightDifferences ) ( lastDebugInfo , s ) : s ;
meminfo . show ( ) . html ( hs ) ;
var catspan = $ ( '<div class="mem_info_links">' ) ;
var addCategoryLink = ( cat ) => {
var catlink = $ ( '<a>' + cat + '</a>' ) ;
if ( cat == debugCategory )
catlink . addClass ( 'selected' ) ;
catlink . click ( ( e ) => {
debugCategory = cat ;
lastDebugInfo = null ;
showDebugInfo ( exports . lastDebugState ) ;
} ) ;
catspan . append ( catlink ) ;
catspan . append ( '<span> </span>' ) ;
} ;
for ( var cat of allcats ) {
addCategoryLink ( cat ) ;
}
meminfo . append ( '<br>' ) ;
meminfo . append ( catspan ) ;
lastDebugInfo = s ;
}
else {
hideDebugInfo ( ) ;
}
}
function setDebugButtonState ( btnid , btnstate ) {
$ ( "#debug_bar, #run_bar" ) . find ( "button" ) . removeClass ( "btn_active" ) . removeClass ( "btn_stopped" ) ;
$ ( "#dbg_" + btnid ) . addClass ( "btn_" + btnstate ) ;
}
function isPlatformReady ( ) {
return exports . platform && current _output != null ;
}
function checkRunReady ( ) {
if ( ! isPlatformReady ( ) ) {
alertError ( "Can't do this until build successfully completes." ) ;
return false ;
}
else
return true ;
}
function openRelevantListing ( state ) {
2022-08-31 00:57:30 +00:00
// if we clicked on a specific tool, don't switch windows
if ( lastViewClicked && lastViewClicked . startsWith ( '#' ) )
return ;
// don't switch windows for specific debug commands
if ( [ 'toline' , 'restart' , 'tovsync' , 'stepover' ] . includes ( lastDebugCommand ) )
2022-02-21 15:35:52 +00:00
return ;
// has to support disassembly, at least
if ( ! exports . platform . disassemble )
return ;
// search through listings
2022-08-31 00:57:30 +00:00
let listings = exports . current _project . getListings ( ) ;
let bestid = "#disasm" ;
let bestscore = 256 ;
2022-02-21 15:35:52 +00:00
if ( listings ) {
2022-08-31 00:57:30 +00:00
let pc = state . c ? ( state . c . EPC || state . c . PC ) : 0 ;
for ( let lstfn in listings ) {
let lst = listings [ lstfn ] ;
let file = lst . assemblyfile || lst . sourcefile ;
2022-02-21 15:35:52 +00:00
// pick either listing or source file
2022-08-31 00:57:30 +00:00
let wndid = exports . current _project . filename2path [ lstfn ] || lstfn ;
2022-02-21 15:35:52 +00:00
if ( file == lst . sourcefile )
wndid = exports . projectWindows . findWindowWithFilePrefix ( lstfn ) ;
// does this window exist?
if ( exports . projectWindows . isWindow ( wndid ) ) {
2022-08-31 00:57:30 +00:00
// find the source line at the PC or closely before it
let srcline1 = file && file . findLineForOffset ( pc , editors _1 . PC _LINE _LOOKAHEAD ) ;
if ( srcline1 ) {
// try to find the next line and bound the PC
let srcline2 = file . lines [ srcline1 . line + 1 ] ;
if ( ! srcline2 || pc < srcline2 . offset ) {
let score = pc - srcline1 . offset ;
if ( score < bestscore ) {
bestid = wndid ;
bestscore = score ;
}
}
//console.log(hex(pc,4), srcline1, srcline2, wndid, lstfn, bestid, bestscore);
2022-02-21 15:35:52 +00:00
}
}
}
}
// if no appropriate listing found, use disassembly view
exports . projectWindows . createOrShow ( bestid , true ) ;
}
function uiDebugCallback ( state ) {
exports . lastDebugState = state ;
showDebugInfo ( state ) ;
openRelevantListing ( state ) ;
exports . projectWindows . refresh ( true ) ; // move cursor
debugTickPaused = true ;
}
function setupDebugCallback ( btnid ) {
2022-08-31 00:57:30 +00:00
if ( exports . platform . setupDebug ) {
2022-02-21 15:35:52 +00:00
exports . platform . setupDebug ( ( state , msg ) => {
uiDebugCallback ( state ) ;
setDebugButtonState ( btnid || "pause" , "stopped" ) ;
msg && showErrorAlert ( [ { msg : "STOPPED: " + msg , line : 0 } ] , true ) ;
} ) ;
2022-08-31 00:57:30 +00:00
lastDebugCommand = btnid ;
}
2022-02-21 15:35:52 +00:00
}
function setupBreakpoint ( btnid ) {
if ( ! checkRunReady ( ) )
return ;
_disableRecording ( ) ;
setupDebugCallback ( btnid ) ;
if ( btnid )
setDebugButtonState ( btnid , "active" ) ;
}
2022-09-01 22:26:06 +00:00
exports . setupBreakpoint = setupBreakpoint ;
2022-02-21 15:35:52 +00:00
function _pause ( ) {
if ( exports . platform && exports . platform . isRunning ( ) ) {
exports . platform . pause ( ) ;
console . log ( "Paused" ) ;
}
setDebugButtonState ( "pause" , "stopped" ) ;
}
function pause ( ) {
if ( ! checkRunReady ( ) )
return ;
clearBreakpoint ( ) ;
_pause ( ) ;
userPaused = true ;
}
function _resume ( ) {
if ( ! exports . platform . isRunning ( ) ) {
exports . platform . resume ( ) ;
console . log ( "Resumed" ) ;
}
setDebugButtonState ( "go" , "active" ) ;
if ( errorWasRuntime ) {
hideErrorAlerts ( ) ;
}
}
function resume ( ) {
if ( ! checkRunReady ( ) )
return ;
clearBreakpoint ( ) ;
if ( ! exports . platform . isRunning ( ) ) {
exports . projectWindows . refresh ( false ) ;
}
_resume ( ) ;
userPaused = false ;
lastViewClicked = null ;
}
function singleStep ( ) {
if ( ! checkRunReady ( ) )
return ;
setupBreakpoint ( "step" ) ;
exports . platform . step ( ) ;
}
function stepOver ( ) {
if ( ! checkRunReady ( ) )
return ;
setupBreakpoint ( "stepover" ) ;
exports . platform . stepOver ( ) ;
}
function singleFrameStep ( ) {
if ( ! checkRunReady ( ) )
return ;
setupBreakpoint ( "tovsync" ) ;
exports . platform . runToVsync ( ) ;
}
function getEditorPC ( ) {
var wnd = exports . projectWindows . getActive ( ) ;
return wnd && wnd . getCursorPC && wnd . getCursorPC ( ) ;
}
function runToPC ( pc ) {
if ( ! checkRunReady ( ) || ! ( pc >= 0 ) )
return ;
setupBreakpoint ( "toline" ) ;
console . log ( "Run to" , pc . toString ( 16 ) ) ;
if ( exports . platform . runToPC ) {
exports . platform . runToPC ( pc ) ;
}
else {
exports . platform . runEval ( ( c ) => {
return c . PC == pc ;
} ) ;
}
}
exports . runToPC = runToPC ;
function restartAtCursor ( ) {
if ( exports . platform . restartAtPC ( getEditorPC ( ) ) ) {
resume ( ) ;
}
else
alertError ( ` Could not restart program at selected line. ` ) ;
}
function runToCursor ( ) {
runToPC ( getEditorPC ( ) ) ;
}
function runUntilReturn ( ) {
if ( ! checkRunReady ( ) )
return ;
setupBreakpoint ( "stepout" ) ;
exports . platform . runUntilReturn ( ) ;
}
function runStepBackwards ( ) {
if ( ! checkRunReady ( ) )
return ;
setupBreakpoint ( "stepback" ) ;
exports . platform . stepBack ( ) ;
}
function clearBreakpoint ( ) {
exports . lastDebugState = null ;
if ( exports . platform . clearDebug )
exports . platform . clearDebug ( ) ;
setupDebugCallback ( ) ; // in case of BRK/trap
showDebugInfo ( ) ;
}
2022-09-01 22:26:06 +00:00
exports . clearBreakpoint = clearBreakpoint ;
2022-02-21 15:35:52 +00:00
function resetPlatform ( ) {
exports . platform . reset ( ) ;
_resetRecording ( ) ;
}
function resetAndRun ( ) {
if ( ! checkRunReady ( ) )
return ;
clearBreakpoint ( ) ;
resetPlatform ( ) ;
_resume ( ) ;
}
function resetAndDebug ( ) {
if ( ! checkRunReady ( ) )
return ;
var wasRecording = recorderActive ;
_disableRecording ( ) ;
if ( exports . platform . setupDebug && exports . platform . runEval ) { // TODO??
clearBreakpoint ( ) ;
_resume ( ) ;
resetPlatform ( ) ;
setupBreakpoint ( "restart" ) ;
exports . platform . runEval ( ( c ) => { return true ; } ) ; // break immediately
}
else {
resetPlatform ( ) ;
_resume ( ) ;
}
if ( wasRecording )
_enableRecording ( ) ;
}
function _breakExpression ( ) {
var modal = $ ( "#debugExprModal" ) ;
var btn = $ ( "#debugExprSubmit" ) ;
$ ( "#debugExprInput" ) . val ( lastBreakExpr ) ;
$ ( "#debugExprExamples" ) . text ( getDebugExprExamples ( ) ) ;
modal . modal ( 'show' ) ;
btn . off ( 'click' ) . on ( 'click' , ( ) => {
var exprs = $ ( "#debugExprInput" ) . val ( ) + "" ;
modal . modal ( 'hide' ) ;
breakExpression ( exprs ) ;
} ) ;
}
function getDebugExprExamples ( ) {
var state = exports . platform . saveState && exports . platform . saveState ( ) ;
var cpu = state . c ;
console . log ( cpu , state ) ;
var s = '' ;
if ( cpu . PC )
s += "c.PC == 0x" + ( 0 , util _1 . hex ) ( cpu . PC ) + "\n" ;
if ( cpu . SP )
s += "c.SP < 0x" + ( 0 , util _1 . hex ) ( cpu . SP ) + "\n" ;
if ( cpu [ 'HL' ] )
s += "c.HL == 0x4000\n" ;
if ( exports . platform . readAddress )
s += "this.readAddress(0x1234) == 0x0\n" ;
if ( exports . platform . readVRAMAddress )
s += "this.readVRAMAddress(0x1234) != 0x80\n" ;
if ( exports . platform [ 'getRasterScanline' ] )
s += "this.getRasterScanline() > 222\n" ;
return s ;
}
function breakExpression ( exprs ) {
var fn = new Function ( 'c' , 'return (' + exprs + ');' ) . bind ( exports . platform ) ;
setupBreakpoint ( ) ;
exports . platform . runEval ( fn ) ;
lastBreakExpr = exprs ;
}
function updateDebugWindows ( ) {
if ( exports . platform . isRunning ( ) ) {
exports . projectWindows . tick ( ) ;
debugTickPaused = false ;
}
else if ( ! debugTickPaused ) { // final tick after pausing
exports . projectWindows . tick ( ) ;
debugTickPaused = true ;
}
setTimeout ( updateDebugWindows , 100 ) ;
}
function setWaitDialog ( b ) {
if ( b ) {
setWaitProgress ( 0 ) ;
$ ( "#pleaseWaitModal" ) . modal ( 'show' ) ;
}
else {
setWaitProgress ( 1 ) ;
$ ( "#pleaseWaitModal" ) . modal ( 'hide' ) ;
}
}
function setWaitProgress ( prog ) {
$ ( "#pleaseWaitProgressBar" ) . css ( 'width' , ( prog * 100 ) + '%' ) . show ( ) ;
}
var recordingVideo = false ;
function _recordVideo ( ) {
if ( recordingVideo )
return ;
( 0 , util _1 . loadScript ) ( "lib/gif.js" ) . then ( ( ) => {
var canvas = $ ( "#emulator" ) . find ( "canvas" ) [ 0 ] ;
if ( ! canvas ) {
alertError ( "Could not find canvas element to record video!" ) ;
return ;
}
var rotate = 0 ;
if ( canvas . style && canvas . style . transform ) {
if ( canvas . style . transform . indexOf ( "rotate(-90deg)" ) >= 0 )
rotate = - 1 ;
else if ( canvas . style . transform . indexOf ( "rotate(90deg)" ) >= 0 )
rotate = 1 ;
}
var gif = new GIF ( {
workerScript : 'lib/gif.worker.js' ,
workers : 4 ,
quality : 10 ,
rotate : rotate
} ) ;
var img = $ ( '#videoPreviewImage' ) ;
gif . on ( 'progress' , ( prog ) => {
setWaitProgress ( prog ) ;
} ) ;
gif . on ( 'finished' , ( blob ) => {
img . attr ( 'src' , URL . createObjectURL ( blob ) ) ;
setWaitDialog ( false ) ;
_resume ( ) ;
$ ( "#videoPreviewModal" ) . modal ( 'show' ) ;
} ) ;
var intervalMsec = 20 ;
var maxFrames = 300 ;
var nframes = 0 ;
console . log ( "Recording video" , canvas ) ;
$ ( "#emulator" ) . css ( 'backgroundColor' , '#cc3333' ) ;
var f = ( ) => {
if ( nframes ++ > maxFrames ) {
console . log ( "Rendering video" ) ;
$ ( "#emulator" ) . css ( 'backgroundColor' , 'inherit' ) ;
setWaitDialog ( true ) ;
_pause ( ) ;
gif . render ( ) ;
recordingVideo = false ;
}
else {
gif . addFrame ( canvas , { delay : intervalMsec , copy : true } ) ;
setTimeout ( f , intervalMsec ) ;
recordingVideo = true ;
}
} ;
f ( ) ;
} ) ;
}
function setFrameRateUI ( fps ) {
exports . platform . setFrameRate ( fps ) ;
if ( fps > 0.01 )
$ ( "#fps_label" ) . text ( fps . toFixed ( 2 ) ) ;
else
$ ( "#fps_label" ) . text ( "1/" + Math . round ( 1 / fps ) ) ;
}
exports . setFrameRateUI = setFrameRateUI ;
function _slowerFrameRate ( ) {
var fps = exports . platform . getFrameRate ( ) ;
fps = fps / 2 ;
if ( fps > 0.00001 )
setFrameRateUI ( fps ) ;
}
function _fasterFrameRate ( ) {
var fps = exports . platform . getFrameRate ( ) ;
fps = Math . min ( 60 , fps * 2 ) ;
setFrameRateUI ( fps ) ;
}
function _slowestFrameRate ( ) {
setFrameRateUI ( 60 / 65536 ) ;
}
function _fastestFrameRate ( ) {
_resume ( ) ;
setFrameRateUI ( 60 ) ;
}
function traceTiming ( ) {
exports . projectWindows . refresh ( false ) ;
var wnd = exports . projectWindows . getActive ( ) ;
if ( wnd . getSourceFile && wnd . setTimingResult ) { // is editor active?
var analyzer = exports . platform . newCodeAnalyzer ( ) ;
analyzer . showLoopTimingForPC ( 0 ) ;
wnd . setTimingResult ( analyzer ) ;
}
}
function _disableRecording ( ) {
if ( recorderActive ) {
exports . platform . setRecorder ( null ) ;
$ ( "#dbg_record" ) . removeClass ( "btn_recording" ) ;
$ ( "#replaydiv" ) . hide ( ) ;
hideDebugInfo ( ) ;
recorderActive = false ;
}
}
function _resetRecording ( ) {
if ( recorderActive ) {
stateRecorder . reset ( ) ;
}
}
function _enableRecording ( ) {
stateRecorder . reset ( ) ;
exports . platform . setRecorder ( stateRecorder ) ;
$ ( "#dbg_record" ) . addClass ( "btn_recording" ) ;
$ ( "#replaydiv" ) . show ( ) ;
recorderActive = true ;
}
function _toggleRecording ( ) {
if ( recorderActive ) {
_disableRecording ( ) ;
}
else {
_enableRecording ( ) ;
}
}
function _lookupHelp ( ) {
if ( exports . platform . showHelp ) {
let tool = exports . platform . getToolForFilename ( exports . current _project . mainPath ) ;
exports . platform . showHelp ( tool ) ; // TODO: tool, identifier
}
}
function addFileToProject ( type , ext , linefn ) {
var wnd = exports . projectWindows . getActive ( ) ;
if ( wnd && wnd . insertText ) {
bootbox . prompt ( {
title : "Add " + type + " File to Project" ,
value : "filename" + ext ,
callback : ( filename ) => {
if ( filename && filename . trim ( ) . length > 0 ) {
if ( ! checkEnteredFilename ( filename ) )
return ;
var path = filename ;
var newline = "\n" + linefn ( filename ) + "\n" ;
exports . current _project . loadFiles ( [ path ] ) . then ( ( result ) => {
if ( result && result . length ) {
alertError ( filename + " already exists; including anyway" ) ;
}
else {
exports . current _project . updateFile ( path , "\n" ) ;
}
wnd . insertText ( newline ) ;
refreshWindowList ( ) ;
} ) ;
}
}
} ) ;
}
else {
alertError ( "Can't insert text in this window -- switch back to main file" ) ;
}
}
// TODO: lwtools and smaller c
function _addIncludeFile ( ) {
var fn = getCurrentMainFilename ( ) ;
var tool = exports . platform . getToolForFilename ( fn ) ;
// TODO: more tools? make this a function of the platform / tool provider
if ( fn . endsWith ( ".c" ) || tool == 'sdcc' || tool == 'cc65' || tool == 'cmoc' || tool == 'smlrc' )
addFileToProject ( "Header" , ".h" , ( s ) => { return '#include "' + s + '"' ; } ) ;
else if ( tool == 'dasm' || tool == 'zmac' )
addFileToProject ( "Include" , ".inc" , ( s ) => { return '\tinclude "' + s + '"' ; } ) ;
else if ( tool == 'ca65' || tool == 'sdasz80' || tool == 'vasm' || tool == 'armips' )
addFileToProject ( "Include" , ".inc" , ( s ) => { return '\t.include "' + s + '"' ; } ) ;
else if ( tool == 'verilator' )
addFileToProject ( "Verilog" , ".v" , ( s ) => { return '`include "' + s + '"' ; } ) ;
else if ( tool == 'wiz' )
addFileToProject ( "Include" , ".wiz" , ( s ) => { return 'import "' + s + '";' ; } ) ;
2022-06-30 18:34:04 +00:00
else if ( tool == 'ecs' )
addFileToProject ( "Include" , ".ecs" , ( s ) => { return 'import "' + s + '"' ; } ) ;
2022-02-21 15:35:52 +00:00
else
alertError ( "Can't add include file to this project type (" + tool + ")" ) ;
}
function _addLinkFile ( ) {
var fn = getCurrentMainFilename ( ) ;
var tool = exports . platform . getToolForFilename ( fn ) ;
if ( fn . endsWith ( ".c" ) || tool == 'sdcc' || tool == 'cc65' || tool == 'cmoc' || tool == 'smlrc' )
addFileToProject ( "Linked C (or .s)" , ".c" , ( s ) => { return '//#link "' + s + '"' ; } ) ;
else if ( fn . endsWith ( "asm" ) || fn . endsWith ( ".s" ) || tool == 'ca65' || tool == 'lwasm' )
addFileToProject ( "Linked ASM" , ".inc" , ( s ) => { return ';#link "' + s + '"' ; } ) ;
else
alertError ( "Can't add linked file to this project type (" + tool + ")" ) ;
}
function setupDebugControls ( ) {
// create toolbar buttons
uitoolbar = new toolbar _1 . Toolbar ( $ ( "#toolbar" ) [ 0 ] , null ) ;
uitoolbar . grp . prop ( 'id' , 'run_bar' ) ;
uitoolbar . add ( 'ctrl+alt+r' , 'Reset' , 'glyphicon-refresh' , resetAndRun ) . prop ( 'id' , 'dbg_reset' ) ;
uitoolbar . add ( 'ctrl+alt+,' , 'Pause' , 'glyphicon-pause' , pause ) . prop ( 'id' , 'dbg_pause' ) ;
uitoolbar . add ( 'ctrl+alt+.' , 'Resume' , 'glyphicon-play' , resume ) . prop ( 'id' , 'dbg_go' ) ;
if ( exports . platform . restartAtPC ) {
uitoolbar . add ( 'ctrl+alt+/' , 'Restart at Cursor' , 'glyphicon-play-circle' , restartAtCursor ) . prop ( 'id' , 'dbg_restartatline' ) ;
}
uitoolbar . newGroup ( ) ;
uitoolbar . grp . prop ( 'id' , 'debug_bar' ) ;
if ( exports . platform . runEval ) {
uitoolbar . add ( 'ctrl+alt+e' , 'Reset and Debug' , 'glyphicon-fast-backward' , resetAndDebug ) . prop ( 'id' , 'dbg_restart' ) ;
}
if ( exports . platform . stepBack ) {
uitoolbar . add ( 'ctrl+alt+b' , 'Step Backwards' , 'glyphicon-step-backward' , runStepBackwards ) . prop ( 'id' , 'dbg_stepback' ) ;
}
if ( exports . platform . step ) {
uitoolbar . add ( 'ctrl+alt+s' , 'Single Step' , 'glyphicon-step-forward' , singleStep ) . prop ( 'id' , 'dbg_step' ) ;
}
if ( exports . platform . stepOver ) {
uitoolbar . add ( 'ctrl+alt+t' , 'Step Over' , 'glyphicon-hand-right' , stepOver ) . prop ( 'id' , 'dbg_stepover' ) ;
}
if ( exports . platform . runUntilReturn ) {
uitoolbar . add ( 'ctrl+alt+o' , 'Step Out of Subroutine' , 'glyphicon-hand-up' , runUntilReturn ) . prop ( 'id' , 'dbg_stepout' ) ;
}
if ( exports . platform . runToVsync ) {
uitoolbar . add ( 'ctrl+alt+n' , 'Next Frame/Interrupt' , 'glyphicon-forward' , singleFrameStep ) . prop ( 'id' , 'dbg_tovsync' ) ;
}
if ( ( exports . platform . runEval || exports . platform . runToPC ) && ! exports . platform _id . startsWith ( 'verilog' ) ) {
uitoolbar . add ( 'ctrl+alt+l' , 'Run To Line' , 'glyphicon-save' , runToCursor ) . prop ( 'id' , 'dbg_toline' ) ;
}
uitoolbar . newGroup ( ) ;
uitoolbar . grp . prop ( 'id' , 'xtra_bar' ) ;
// add menu clicks
$ ( ".dropdown-menu" ) . collapse ( { toggle : false } ) ;
$ ( "#item_new_file" ) . click ( _createNewFile ) ;
$ ( "#item_upload_file" ) . click ( _uploadNewFile ) ;
$ ( "#item_open_directory" ) . click ( _openLocalDirectory ) ;
$ ( "#item_github_login" ) . click ( _loginToGithub ) ;
$ ( "#item_github_logout" ) . click ( _logoutOfGithub ) ;
$ ( "#item_github_import" ) . click ( _importProjectFromGithub ) ;
$ ( "#item_github_publish" ) . click ( _publishProjectToGithub ) ;
$ ( "#item_github_push" ) . click ( _pushProjectToGithub ) ;
$ ( "#item_github_pull" ) . click ( _pullProjectFromGithub ) ;
$ ( "#item_repo_delete" ) . click ( _deleteRepository ) ;
$ ( "#item_share_file" ) . click ( _shareEmbedLink ) ;
$ ( "#item_reset_file" ) . click ( _revertFile ) ;
$ ( "#item_rename_file" ) . click ( _renameFile ) ;
$ ( "#item_delete_file" ) . click ( _deleteFile ) ;
if ( exports . platform . runEval )
$ ( "#item_debug_expr" ) . click ( _breakExpression ) . show ( ) ;
else
$ ( "#item_debug_expr" ) . hide ( ) ;
$ ( "#item_download_rom" ) . click ( _downloadROMImage ) ;
$ ( "#item_download_file" ) . click ( _downloadSourceFile ) ;
$ ( "#item_download_zip" ) . click ( _downloadProjectZipFile ) ;
2022-07-29 23:30:11 +00:00
$ ( "#item_download_sym" ) . click ( _downloadSymFile ) ;
2022-02-21 15:35:52 +00:00
$ ( "#item_download_allzip" ) . click ( _downloadAllFilesZipFile ) ;
$ ( "#item_record_video" ) . click ( _recordVideo ) ;
if ( exports . platform _id . startsWith ( 'apple2' ) || exports . platform _id . startsWith ( 'vcs' ) ) // TODO: look for function
$ ( "#item_export_cassette" ) . click ( _downloadCassetteFile ) ;
else
$ ( "#item_export_cassette" ) . hide ( ) ;
if ( exports . platform . setFrameRate && exports . platform . getFrameRate ) {
$ ( "#dbg_slower" ) . click ( _slowerFrameRate ) ;
$ ( "#dbg_faster" ) . click ( _fasterFrameRate ) ;
$ ( "#dbg_slowest" ) . click ( _slowestFrameRate ) ;
$ ( "#dbg_fastest" ) . click ( _fastestFrameRate ) ;
}
$ ( "#item_addfile_include" ) . click ( _addIncludeFile ) ;
$ ( "#item_addfile_link" ) . click ( _addLinkFile ) ;
$ ( "#item_request_persist" ) . click ( ( ) => requestPersistPermission ( true , false ) ) ;
updateDebugWindows ( ) ;
// show help button?
if ( exports . platform . showHelp ) {
uitoolbar . add ( 'ctrl+alt+?' , 'Show Help' , 'glyphicon-question-sign' , _lookupHelp ) ;
}
if ( exports . platform . newCodeAnalyzer ) {
uitoolbar . add ( null , 'Analyze CPU Timing' , 'glyphicon-time' , traceTiming ) ;
}
// setup replay slider
if ( exports . platform . setRecorder && exports . platform . advance ) {
setupReplaySlider ( ) ;
}
}
function setupReplaySlider ( ) {
var replayslider = $ ( "#replayslider" ) ;
var clockslider = $ ( "#clockslider" ) ;
var replayframeno = $ ( "#replay_frame" ) ;
var clockno = $ ( "#replay_clock" ) ;
if ( ! exports . platform . advanceFrameClock )
$ ( "#clockdiv" ) . hide ( ) ; // TODO: put this test in recorder?
var updateFrameNo = ( ) => {
replayframeno . text ( stateRecorder . lastSeekFrame + "" ) ;
clockno . text ( stateRecorder . lastSeekStep + "" ) ;
} ;
var sliderChanged = ( e ) => {
_pause ( ) ;
var frame = parseInt ( replayslider . val ( ) . toString ( ) ) ;
var step = parseInt ( clockslider . val ( ) . toString ( ) ) ;
if ( stateRecorder . loadFrame ( frame , step ) >= 0 ) {
clockslider . attr ( 'min' , 0 ) ;
clockslider . attr ( 'max' , stateRecorder . lastStepCount ) ;
updateFrameNo ( ) ;
uiDebugCallback ( exports . platform . saveState ( ) ) ;
}
} ;
var setFrameTo = ( frame ) => {
_pause ( ) ;
if ( stateRecorder . loadFrame ( frame ) >= 0 ) {
replayslider . val ( frame ) ;
updateFrameNo ( ) ;
uiDebugCallback ( exports . platform . saveState ( ) ) ;
}
} ;
var setClockTo = ( clock ) => {
_pause ( ) ;
var frame = parseInt ( replayslider . val ( ) . toString ( ) ) ;
if ( stateRecorder . loadFrame ( frame , clock ) >= 0 ) {
clockslider . val ( clock ) ;
updateFrameNo ( ) ;
uiDebugCallback ( exports . platform . saveState ( ) ) ;
}
} ;
stateRecorder . callbackStateChanged = ( ) => {
replayslider . attr ( 'min' , 0 ) ;
replayslider . attr ( 'max' , stateRecorder . numFrames ( ) ) ;
replayslider . val ( stateRecorder . currentFrame ( ) ) ;
clockslider . val ( stateRecorder . currentStep ( ) ) ;
updateFrameNo ( ) ;
showDebugInfo ( exports . platform . saveState ( ) ) ;
} ;
replayslider . on ( 'input' , sliderChanged ) ;
clockslider . on ( 'input' , sliderChanged ) ;
//replayslider.on('change', sliderChanged);
$ ( "#replay_min" ) . click ( ( ) => { setFrameTo ( 1 ) ; } ) ;
$ ( "#replay_max" ) . click ( ( ) => { setFrameTo ( stateRecorder . numFrames ( ) ) ; } ) ;
$ ( "#replay_back" ) . click ( ( ) => { setFrameTo ( parseInt ( replayslider . val ( ) . toString ( ) ) - 1 ) ; } ) ;
$ ( "#replay_fwd" ) . click ( ( ) => { setFrameTo ( parseInt ( replayslider . val ( ) . toString ( ) ) + 1 ) ; } ) ;
$ ( "#clock_back" ) . click ( ( ) => { setClockTo ( parseInt ( clockslider . val ( ) . toString ( ) ) - 1 ) ; } ) ;
$ ( "#clock_fwd" ) . click ( ( ) => { setClockTo ( parseInt ( clockslider . val ( ) . toString ( ) ) + 1 ) ; } ) ;
$ ( "#replay_bar" ) . show ( ) ;
uitoolbar . add ( 'ctrl+alt+0' , 'Start/Stop Replay Recording' , 'glyphicon-record' , _toggleRecording ) . prop ( 'id' , 'dbg_record' ) ;
}
function isLandscape ( ) {
try {
var object = window . screen [ 'orientation' ] || window . screen [ 'msOrientation' ] || window . screen [ 'mozOrientation' ] || null ;
if ( object ) {
if ( object . type . indexOf ( 'landscape' ) !== - 1 ) {
return true ;
}
if ( object . type . indexOf ( 'portrait' ) !== - 1 ) {
return false ;
}
}
if ( 'orientation' in window ) {
var value = window . orientation ;
if ( value === 0 || value === 180 ) {
return false ;
}
else if ( value === 90 || value === 270 ) {
return true ;
}
}
}
catch ( e ) { }
// fallback to comparing width to height
return window . innerWidth > window . innerHeight ;
}
async function showWelcomeMessage ( ) {
if ( userPrefs . shouldCompleteTour ( ) ) {
await ( 0 , util _1 . loadScript ) ( 'lib/bootstrap-tourist.js' ) ;
var is _vcs = exports . platform _id . startsWith ( 'vcs' ) ;
var steps = [
{
element : "#platformsMenuButton" ,
placement : 'right' ,
title : "Platform Selector" ,
content : "You're currently on the \"<b>" + exports . platform _id + "</b>\" platform. You can choose a different one from the menu."
} ,
{
element : "#preset_select" ,
title : "Project Selector" ,
content : "You can choose different code examples, create your own files, or import projects from GitHub."
} ,
{
element : "#workspace" ,
title : "Code Editor" ,
content : is _vcs ? "Type your 6502 assembly code into the editor, and it'll be assembled in real-time."
: "Type your source code into the editor, and it'll be compiled in real-time."
} ,
{
element : "#emulator" ,
placement : 'left' ,
title : "Emulator" ,
content : "We'll load your compiled code into the emulator whenever you make changes."
} ,
{
element : "#debug_bar" ,
placement : 'bottom' ,
title : "Debug Tools" ,
content : "Use these buttons to set breakpoints, single step through code, pause/resume, and use debugging tools."
} ,
{
element : "#dropdownMenuButton" ,
title : "Main Menu" ,
content : "Click the menu to create new files, download your code, or share your work with others."
} ,
{
element : "#sidebar" ,
title : "Sidebar" ,
content : "Pull right to expose the sidebar. It lets you switch between source files, view assembly listings, and use other tools like Disassembler, Memory Browser, and Asset Editor."
}
] ;
if ( ! isLandscape ( ) ) {
steps . unshift ( {
element : "#controls_top" ,
placement : 'bottom' ,
title : "Portrait mode detected" ,
content : "This site works best on desktop browsers. For best results, rotate your device to landscape orientation."
} ) ;
}
if ( window . location . host . endsWith ( '8bitworkshop.com' ) ) {
steps . unshift ( {
element : "#dropdownMenuButton" ,
placement : 'right' ,
title : "Cookie Consent" ,
content : 'Before we start, we should tell you that this website stores cookies and other data in your browser. You can review our <a href="/privacy.html" target="_new">privacy policy</a>.'
} ) ;
steps . push ( {
element : "#booksMenuButton" ,
placement : 'left' ,
title : "Books" ,
content : "Get some books that explain how to program all of this stuff, and write some games!"
} ) ;
}
if ( isElectron ) {
steps . unshift ( {
element : "#dropdownMenuButton" ,
placement : 'right' ,
title : "Developer Analytics" ,
content : 'BTW, we send stack traces to sentry.io when exceptions are thrown. Hope that\'s ok.'
} ) ;
steps . unshift ( {
element : "#dropdownMenuButton" ,
placement : 'right' ,
title : "Welcome to 8bitworkshop Desktop!" ,
content : 'The directory "~/8bitworkshop" contains all of your file edits and built ROM images. You can create new projects under the platform directories (e.g. "c64/myproject")'
} ) ;
}
var tour = new Tour ( {
autoscroll : false ,
//storage:false,
steps : steps ,
onEnd : ( ) => {
userPrefs . completedTour ( ) ;
//requestPersistPermission(false, true);
}
} ) ;
setTimeout ( ( ) => { tour . start ( ) ; } , 2500 ) ;
}
}
///////////////////////////////////////////////////
function globalErrorHandler ( msgevent ) {
var msg = ( msgevent . message || msgevent . error || msgevent ) + "" ;
// storage quota full? (Chrome) try to expand it
if ( msg . indexOf ( "QuotaExceededError" ) >= 0 ) {
requestPersistPermission ( false , false ) ;
}
else {
var err = msgevent . error || msgevent . reason ;
if ( err != null && err instanceof emu _1 . EmuHalt ) {
haltEmulation ( err ) ;
}
}
}
function haltEmulation ( err ) {
console . log ( "haltEmulation" ) ;
_pause ( ) ;
emulationHalted ( err ) ;
// TODO: reset platform?
}
exports . haltEmulation = haltEmulation ;
// catch errors
function installErrorHandler ( ) {
window . addEventListener ( 'error' , globalErrorHandler ) ;
window . addEventListener ( 'unhandledrejection' , globalErrorHandler ) ;
}
function uninstallErrorHandler ( ) {
window . removeEventListener ( 'error' , globalErrorHandler ) ;
window . removeEventListener ( 'unhandledrejection' , globalErrorHandler ) ;
}
function gotoNewLocation ( replaceHistory ) {
uninstallErrorHandler ( ) ;
if ( replaceHistory )
window . location . replace ( "?" + $ . param ( exports . qs ) ) ;
else
window . location . href = "?" + $ . param ( exports . qs ) ;
}
function replaceURLState ( ) {
if ( exports . platform _id )
exports . qs . platform = exports . platform _id ;
delete exports . qs [ '' ] ; // remove null parameter
history . replaceState ( { } , "" , "?" + $ . param ( exports . qs ) ) ;
}
function addPageFocusHandlers ( ) {
var hidden = false ;
document . addEventListener ( "visibilitychange" , ( ) => {
if ( document . visibilityState == 'hidden' && exports . platform && exports . platform . isRunning ( ) ) {
_pause ( ) ;
hidden = true ;
}
else if ( document . visibilityState == 'visible' && hidden ) {
_resume ( ) ;
hidden = false ;
}
} ) ;
$ ( window ) . on ( "focus" , ( ) => {
if ( hidden ) {
_resume ( ) ;
hidden = false ;
}
} ) ;
$ ( window ) . on ( "blur" , ( ) => {
if ( exports . platform && exports . platform . isRunning ( ) ) {
_pause ( ) ;
hidden = true ;
}
} ) ;
$ ( window ) . on ( "orientationchange" , ( ) => {
if ( exports . platform && exports . platform . resize )
setTimeout ( exports . platform . resize . bind ( exports . platform ) , 200 ) ;
} ) ;
}
// TODO: merge w/ player.html somehow?
function showInstructions ( ) {
var div = $ ( document ) . find ( ".emucontrols-" + ( 0 , util _1 . getRootBasePlatform ) ( exports . platform _id ) ) ;
if ( exports . platform _id . endsWith ( ".mame" ) )
div . show ( ) ; // TODO: MAME seems to eat the focus() event
var vcanvas = $ ( "#emulator" ) . find ( "canvas" ) ;
if ( vcanvas ) {
vcanvas . on ( 'focus' , ( ) => {
if ( exports . platform . isRunning ( ) ) {
div . fadeIn ( 200 ) ;
// toggle sound for browser autoplay
exports . platform . resume ( ) ;
}
} ) ;
vcanvas . on ( 'blur' , ( ) => {
div . fadeOut ( 200 ) ;
} ) ;
}
}
function installGAHooks ( ) {
if ( window [ 'ga' ] ) {
$ ( ".dropdown-item" ) . click ( ( e ) => {
if ( e . target && e . target . id ) {
gaEvent ( 'menu' , e . target . id ) ;
}
} ) ;
ga ( 'send' , 'pageview' , location . pathname + '?platform=' + exports . platform _id + ( exports . repo _id ? ( '&repo=' + exports . repo _id ) : ( '&file=' + exports . qs . file ) ) ) ;
}
}
async function startPlatform ( ) {
if ( ! emu _1 . PLATFORMS [ exports . platform _id ] )
throw Error ( "Invalid platform '" + exports . platform _id + "'." ) ;
2022-02-21 22:58:50 +00:00
let emudiv = $ ( "#emuscreen" ) [ 0 ] ;
let options = ( 0 , util _1 . decodeQueryString ) ( exports . qs . options || '' ) ;
exports . platform = new emu _1 . PLATFORMS [ exports . platform _id ] ( emudiv , options ) ;
2022-02-21 15:35:52 +00:00
setPlatformUI ( ) ;
stateRecorder = new recorder _1 . StateRecorderImpl ( exports . platform ) ;
PRESETS = exports . platform . getPresets ? exports . platform . getPresets ( ) : [ ] ;
if ( ! exports . qs . file ) {
// try to load last file (redirect)
var lastid = userPrefs . getLastPreset ( ) ;
// load first preset file, unless we're in a repo
var defaultfile = lastid || ( exports . repo _id ? null : PRESETS [ 0 ] . id ) ;
exports . qs . file = defaultfile || 'DEFAULT' ;
if ( ! defaultfile ) {
alertError ( "There is no default main file for this project. Try selecting one from the pulldown." ) ;
}
}
// legacy vcs stuff
if ( exports . platform _id == 'vcs' && exports . qs . file . startsWith ( 'examples/' ) && ! exports . qs . file . endsWith ( '.a' ) ) {
exports . qs . file += '.a' ;
}
// start platform and load file
replaceURLState ( ) ;
installErrorHandler ( ) ;
installGAHooks ( ) ;
await exports . platform . start ( ) ;
await loadBIOSFromProject ( ) ;
await initProject ( ) ;
await loadProject ( exports . qs . file ) ;
exports . platform . sourceFileFetch = ( path ) => exports . current _project . filedata [ path ] ;
setupDebugControls ( ) ;
addPageFocusHandlers ( ) ;
showInstructions ( ) ;
if ( isEmbed ) {
hideControlsForEmbed ( ) ;
}
else {
updateSelector ( ) ;
updateBooksMenu ( ) ;
showWelcomeMessage ( ) ;
}
revealTopBar ( ) ;
}
function hideControlsForEmbed ( ) {
$ ( '#dropdownMenuButton' ) . hide ( ) ;
$ ( '#platformsMenuButton' ) . hide ( ) ;
$ ( '#booksMenuButton' ) . hide ( ) ;
}
function updateBooksMenu ( ) {
if ( ( 0 , util _1 . getRootBasePlatform ) ( exports . platform _id ) == 'nes' )
$ ( ".book-nes" ) . addClass ( "book-active" ) ;
else if ( ( 0 , util _1 . getRootBasePlatform ) ( exports . platform _id ) == 'vcs' )
$ ( ".book-vcs" ) . addClass ( "book-active" ) ;
else if ( ( 0 , util _1 . getRootBasePlatform ) ( exports . platform _id ) == 'verilog' )
$ ( ".book-verilog" ) . addClass ( "book-active" ) ;
else if ( exports . platform . getToolForFilename ( getCurrentMainFilename ( ) ) == 'sdcc' )
$ ( ".book-arcade" ) . addClass ( "book-active" ) ;
}
function revealTopBar ( ) {
setTimeout ( ( ) => { $ ( "#controls_dynamic" ) . css ( 'visibility' , 'inherit' ) ; } , 250 ) ;
}
function setupSplits ( ) {
var splitName = 'workspace-split3-' + exports . platform _id ;
if ( isEmbed )
splitName = 'embed-' + splitName ;
var sizes ;
if ( exports . platform _id . startsWith ( 'vcs' ) )
sizes = [ 0 , 50 , 50 ] ;
else if ( isEmbed || baseviews _1 . isMobileDevice )
sizes = [ 0 , 55 , 45 ] ;
else
sizes = [ 12 , 44 , 44 ] ;
var sizesStr = hasLocalStorage && localStorage . getItem ( splitName ) ;
if ( sizesStr ) {
try {
sizes = JSON . parse ( sizesStr ) ;
}
catch ( e ) {
console . log ( e ) ;
}
}
var split = Split ( [ '#sidebar' , '#workspace' , '#emulator' ] , {
sizes : sizes ,
minSize : [ 0 , 250 , 250 ] ,
onDrag : ( ) => {
if ( exports . platform && exports . platform . resize )
exports . platform . resize ( ) ;
} ,
onDragEnd : ( ) => {
if ( hasLocalStorage )
localStorage . setItem ( splitName , JSON . stringify ( split . getSizes ( ) ) ) ;
if ( exports . projectWindows )
exports . projectWindows . resize ( ) ;
} ,
} ) ;
}
exports . setupSplits = setupSplits ;
function loadImportedURL ( url ) {
// TODO: zip file?
const ignore = ( 0 , util _1 . parseBool ) ( exports . qs . ignore ) || isEmbed ;
setWaitDialog ( true ) ;
( 0 , util _1 . getWithBinary ) ( url , async ( data ) => {
if ( data ) {
var path = ( 0 , util _1 . getFilenameForPath ) ( url ) ;
console . log ( "Importing " + data . length + " bytes as " + path ) ;
try {
var olddata = await store . getItem ( path ) ;
setWaitDialog ( false ) ;
if ( olddata != null && ignore ) {
// ignore=1, do nothing
}
else if ( olddata == null || confirm ( "Replace existing file '" + path + "'?" ) ) {
await store . setItem ( path , data ) ;
}
delete exports . qs . importURL ;
exports . qs . file = path ;
replaceURLState ( ) ;
loadAndStartPlatform ( ) ;
}
finally {
setWaitDialog ( false ) ;
}
}
else {
alertError ( "Could not load source code from URL: " + url ) ;
setWaitDialog ( false ) ;
}
} , 'text' ) ;
}
async function loadFormDataUpload ( ) {
var ignore = ( 0 , util _1 . parseBool ) ( exports . qs . ignore ) ;
var force = ( 0 , util _1 . parseBool ) ( exports . qs . force ) ;
if ( isEmbed ) {
ignore = ! force ; // ignore is default when embed=1 unless force=1
}
else {
force = false ; // can't use force w/o embed=1
}
for ( var i = 0 ; i < 20 ; i ++ ) {
let path = exports . qs [ 'file' + i + '_name' ] ;
let dataenc = exports . qs [ 'file' + i + '_data' ] ;
if ( path == null || dataenc == null )
break ;
var olddata = await store . getItem ( path ) ;
if ( ! ( ignore && olddata ) ) {
let value = dataenc ;
if ( exports . qs [ 'file' + i + '_type' ] == 'binary' ) {
value = ( 0 , util _1 . stringToByteArray ) ( atob ( value ) ) ;
}
if ( ! olddata || force || confirm ( "Replace existing file '" + path + "'?" ) ) {
await store . setItem ( path , value ) ;
}
}
if ( i == 0 ) {
exports . qs . file = path ;
} // set main filename
delete exports . qs [ 'file' + i + '_name' ] ;
delete exports . qs [ 'file' + i + '_data' ] ;
delete exports . qs [ 'file' + i + '_type' ] ;
}
delete exports . qs . ignore ;
delete exports . qs . force ;
replaceURLState ( ) ;
}
function setPlatformUI ( ) {
var name = exports . platform . getPlatformName && exports . platform . getPlatformName ( ) ;
var menuitem = $ ( 'a[href="?platform=' + exports . platform _id + '"]' ) ;
if ( menuitem . length ) {
menuitem . addClass ( "dropdown-item-checked" ) ;
name = name || menuitem . text ( ) || name ;
}
$ ( ".platform_name" ) . text ( name || exports . platform _id ) ;
}
function getPlatformAndRepo ( ) {
// lookup repository for this platform (TODO: enable cross-platform repos)
exports . platform _id = exports . qs . platform || userPrefs . getLastPlatformID ( ) ;
exports . repo _id = exports . qs . repo ;
// only look at cached repo_id if file= is not present, so back button works
if ( ! exports . qs . repo && ! exports . qs . file )
exports . repo _id = userPrefs . getLastRepoID ( exports . platform _id ) ;
// are we in a repo?
if ( hasLocalStorage && exports . repo _id && exports . repo _id !== '/' ) {
var repo = ( 0 , services _1 . getRepos ) ( ) [ exports . repo _id ] ;
// override query string params w/ repo settings
if ( repo ) {
console . log ( exports . platform _id , exports . qs , repo ) ;
exports . qs . repo = exports . repo _id ;
if ( repo . platform _id && ! exports . qs . platform )
exports . qs . platform = exports . platform _id = repo . platform _id ;
if ( ! exports . qs . file && repo . mainPath )
exports . qs . file = repo . mainPath ;
//requestPersistPermission(true, true);
}
}
else {
exports . repo _id = '' ;
delete exports . qs . repo ;
}
// add default platform
if ( ! exports . platform _id ) {
if ( isEmbed )
fatalError ( ` The 'platform' must be specified when embed=1 ` ) ;
exports . platform _id = exports . qs . platform = "vcs" ;
}
}
exports . getPlatformAndRepo = getPlatformAndRepo ;
// start
async function startUI ( ) {
// import from github?
if ( exports . qs . githubURL ) {
importProjectFromGithub ( exports . qs . githubURL , true ) ;
return ;
}
getPlatformAndRepo ( ) ;
setupSplits ( ) ;
// get store ID, repo id or platform id
exports . store _id = exports . repo _id || ( 0 , util _1 . getBasePlatform ) ( exports . platform _id ) ;
// are we embedded?
if ( isEmbed ) {
exports . store _id = ( document . referrer || document . location . href ) + exports . store _id ;
}
// create store
store = ( 0 , project _1 . createNewPersistentStore ) ( exports . store _id ) ;
// is this an importURL?
if ( exports . qs . importURL ) {
loadImportedURL ( exports . qs . importURL ) ;
return ; // TODO: make async
}
// is this a file POST?
if ( exports . qs . file0 _name ) {
await loadFormDataUpload ( ) ;
}
// load and start platform object
loadAndStartPlatform ( ) ;
}
exports . startUI = startUI ;
async function loadAndStartPlatform ( ) {
try {
var module = await ( 0 , _index _1 . importPlatform ) ( ( 0 , util _1 . getRootBasePlatform ) ( exports . platform _id ) ) ;
console . log ( "starting platform" , exports . platform _id ) ; // loaded required <platform_id>.js file
await startPlatform ( ) ;
document . title = document . title + " [" + exports . platform _id + "] - " + ( exports . repo _id ? ( '[' + exports . repo _id + '] - ' ) : '' ) + exports . current _project . mainPath ;
}
catch ( e ) {
console . log ( e ) ;
alertError ( 'Platform "' + exports . platform _id + '" failed to load.' ) ;
}
finally {
revealTopBar ( ) ;
}
}
// HTTPS REDIRECT
const useHTTPSCookieName = "__use_https" ;
function setHTTPSCookie ( val ) {
document . cookie = useHTTPSCookieName + "=" + val + ";domain=8bitworkshop.com;path=/;max-age=315360000" ;
}
function shouldRedirectHTTPS ( ) {
// cookie set? either true or false
var shouldRedir = getCookie ( useHTTPSCookieName ) ;
if ( typeof shouldRedir === 'string' ) {
return ! ! shouldRedir ; // convert to bool
}
// set a 10yr cookie, value depends on if it's our first time here
var val = hasLocalStorage && ! localStorage . getItem ( "__lastplatform" ) ? 1 : 0 ;
setHTTPSCookie ( val ) ;
return ! ! val ;
}
function _switchToHTTPS ( ) {
bootbox . confirm ( '<p>Do you want to force the browser to use HTTPS from now on?</p>' +
'<p>WARNING: This will make all of your local files unavailable, so you should "Download All Changes" first for each platform where you have done work.</p>' +
'<p>You can go back to HTTP by setting the "' + useHTTPSCookieName + '" cookie to 0.</p>' , ( ok ) => {
if ( ok ) {
setHTTPSCookie ( 1 ) ;
redirectToHTTPS ( ) ;
}
} ) ;
}
function redirectToHTTPS ( ) {
if ( window . location . protocol == 'http:' && window . location . host == '8bitworkshop.com' ) {
if ( shouldRedirectHTTPS ( ) ) {
uninstallErrorHandler ( ) ;
window . location . replace ( window . location . href . replace ( /^http:/ , 'https:' ) ) ;
}
else {
$ ( "#item_switch_https" ) . click ( _switchToHTTPS ) . show ( ) ;
}
}
}
// redirect to HTTPS after script loads?
redirectToHTTPS ( ) ;
//// ELECTRON (and other external) STUFF
function setTestInput ( path , data ) {
exports . platform . writeFile ( path , data ) ;
}
exports . setTestInput = setTestInput ;
function getTestOutput ( path ) {
return exports . platform . readFile ( path ) ;
}
exports . getTestOutput = getTestOutput ;
function getSaveState ( ) {
return exports . platform . saveState ( ) ;
}
exports . getSaveState = getSaveState ;
function emulationHalted ( err ) {
var msg = ( err && err . message ) || msg ;
showExceptionAsError ( err , msg ) ;
exports . projectWindows . refresh ( false ) ; // don't mess with cursor
if ( exports . platform . saveState )
showDebugInfo ( exports . platform . saveState ( ) ) ;
}
exports . emulationHalted = emulationHalted ;
async function reloadWorkspaceFile ( path ) {
var oldval = exports . current _project . filedata [ path ] ;
if ( oldval != null ) {
exports . projectWindows . updateFile ( path , await alternateLocalFilesystem . getFileData ( path ) ) ;
console . log ( 'updating file' , path ) ;
}
}
exports . reloadWorkspaceFile = reloadWorkspaceFile ;
function writeOutputROMFile ( ) {
if ( isElectron && current _output instanceof Uint8Array ) {
var prefix = ( 0 , util _1 . getFilenamePrefix ) ( getCurrentMainFilename ( ) ) ;
var suffix = ( exports . platform . getROMExtension && exports . platform . getROMExtension ( current _output ) )
|| "-" + ( 0 , util _1 . getBasePlatform ) ( exports . platform _id ) + ".bin" ;
alternateLocalFilesystem . setFileData ( ` bin/ ${ prefix } ${ suffix } ` , current _output ) ;
}
}
function highlightSearch ( query ) {
var wnd = exports . projectWindows . getActive ( ) ;
if ( wnd instanceof editors _1 . SourceEditor ) {
var sc = wnd . editor . getSearchCursor ( query ) ;
if ( sc . findNext ( ) ) {
wnd . editor . setSelection ( sc . pos . to , sc . pos . from ) ;
}
}
}
exports . highlightSearch = highlightSearch ;
function startUIWhenVisible ( ) {
let started = false ;
let observer = new IntersectionObserver ( ( entries , observer ) => {
for ( var entry of entries ) {
if ( entry . isIntersecting && ! started ) {
startUI ( ) ;
started = true ;
}
if ( entry . intersectionRatio == 0 && isPlatformReady ( ) && exports . platform . isRunning ( ) ) {
_pause ( ) ;
}
if ( entry . intersectionRatio > 0 && isPlatformReady ( ) && ! exports . platform . isRunning ( ) ) {
_resume ( ) ;
}
}
} , { } ) ;
observer . observe ( $ ( "#emulator" ) [ 0 ] ) ; //window.document.body);
}
/// start UI if in browser (not node)
if ( typeof process === 'undefined' ) {
// if embedded, do not start UI until we scroll past it
if ( isEmbed && typeof IntersectionObserver === 'function' ) {
startUIWhenVisible ( ) ;
}
else {
startUI ( ) ;
}
}
//# sourceMappingURL=ui.js.map