diff --git a/src/mami.js/args.js b/src/mami.js/args.js index 4bf0ccc..2f808fb 100644 --- a/src/mami.js/args.js +++ b/src/mami.js/args.js @@ -112,7 +112,7 @@ const MamiArgs = (argName, input, builder) => { return blueprint; }); - const inputIsNull = input === null; + const inputIsNull = input === undefined || input === null; if(inputIsNull) input = {}; diff --git a/src/mami.js/events.js b/src/mami.js/events.js index f4bcdff..f9a67ea 100644 --- a/src/mami.js/events.js +++ b/src/mami.js/events.js @@ -1,3 +1,17 @@ +const MamiIsEventTarget = value => { + if(typeof value !== 'object' || value === null) + return false; + + if(typeof value.scopeTo !== 'function' + || typeof value.create !== 'function' + || typeof value.watch !== 'function' + || typeof value.unwatch !== 'function' + || typeof value.dispatch !== 'function') + return false; + + return true; +}; + const MamiEventTargetScoped = function(eventTarget, prefix) { if(typeof eventTarget !== 'object' || eventTarget === null) throw 'eventTarget must be a non-null object'; diff --git a/src/mami.js/main.js b/src/mami.js/main.js index 7dc3a5e..6b2a9d6 100644 --- a/src/mami.js/main.js +++ b/src/mami.js/main.js @@ -1,6 +1,7 @@ window.Umi = { UI: {} }; #include animate.js +#include args.js #include awaitable.js #include common.js #include compat.js @@ -11,6 +12,7 @@ window.Umi = { UI: {} }; #include mobile.js #include mszauth.js #include txtrigs.js +#include uniqstr.js #include users.js #include utility.js #include weeb.js @@ -48,52 +50,63 @@ window.Umi = { UI: {} }; #include ui/markup.js #include ui/view.js -(async () => { - const eventTarget = new MamiEventTargetWindow; +const MamiInit = async args => { + args = MamiArgs('args', args, define => { + define('parent').default(document.body).constraint(value => value instanceof Element).done(); + define('eventTarget').required().constraint(MamiIsEventTarget).done(); + define('settingsPrefix').default('umi-').done(); + }); - const ctx = new MamiContext(eventTarget); - Object.defineProperty(window, 'mami', { enumerable: true, value: ctx }); + const ctx = new MamiContext(args.eventTarget); - ctx.views = new MamiViewsControl({ body: document.body }); - ctx.msgbox = new MamiMessageBoxControl({ parent: document.body }); + // remove this later and replace with the one commented out way below + if(!('mami' in window)) + Object.defineProperty(window, 'mami', { enumerable: true, value: ctx }); + + ctx.views = new MamiViewsControl({ body: args.parent }); + ctx.msgbox = new MamiMessageBoxControl({ parent: args.parent }); const loadingOverlay = new Umi.UI.LoadingOverlay('spinner', 'Loading...'); await ctx.views.push(loadingOverlay); - loadingOverlay.setMessage('Loading environment...'); - try { - window.futami = await FutamiCommon.load(); - } catch(ex) { - console.error('Failed to load common settings.', ex); - loadingOverlay.setIcon('cross'); - loadingOverlay.setHeader('Failed!'); - loadingOverlay.setMessage('Failed to load common settings.'); - return; + if(!('futami' in window)) { + loadingOverlay.setMessage('Loading environment...'); + try { + window.futami = await FutamiCommon.load(); + } catch(ex) { + console.error('Failed to load common settings.', ex); + loadingOverlay.setIcon('cross'); + loadingOverlay.setHeader('Failed!'); + loadingOverlay.setMessage('Failed to load common settings.'); + return; + } } - loadingOverlay.setMessage('Fetching credentials...'); - try { - const auth = await MamiMisuzuAuth.update(); - if(!auth.ok) - throw 'Authentication failed.'; - } catch(ex) { - console.error(ex); - location.assign(futami.get('login')); - return; - } + if(!MamiMisuzuAuth.hasInfo()) { + loadingOverlay.setMessage('Fetching credentials...'); + try { + const auth = await MamiMisuzuAuth.update(); + if(!auth.ok) + throw 'Authentication failed.'; + } catch(ex) { + console.error(ex); + location.assign(futami.get('login')); + return; + } - setInterval(() => { - MamiMisuzuAuth.update() - .then(auth => { - if(!auth.ok) - location.assign(futami.get('login')); - }) - }, 600000); + setInterval(() => { + MamiMisuzuAuth.update() + .then(auth => { + if(!auth.ok) + location.assign(futami.get('login')); + }) + }, 600000); + } loadingOverlay.setMessage('Loading settings...'); - const settings = new MamiSettings('umi-', ctx.events.scopeTo('settings')); + const settings = new MamiSettings(args.settingsPrefix, ctx.events.scopeTo('settings')); ctx.settings = settings; settings.define('style').default('dark').create(); @@ -284,7 +297,7 @@ window.Umi = { UI: {} }; settings.watch('style', ev => { if(!ev.detail.initial) Umi.UI.View.AccentReload(); }); settings.watch('compactView', ev => { if(!ev.detail.initial) Umi.UI.View.AccentReload(); }); - settings.watch('preventOverflow', ev => document.body.classList.toggle('prevent-overflow', ev.detail.value)); + settings.watch('preventOverflow', ev => args.parent.classList.toggle('prevent-overflow', ev.detail.value)); settings.watch('tmpDisableOldThemeSys', ev => { if(!ev.detail.initial) Umi.UI.View.AccentReload(); }); settings.watch('minecraft', ev => { @@ -565,7 +578,7 @@ window.Umi = { UI: {} }; sbSettings.category(category => { category.header('Settings'); category.button('Import settings', () => { - (new MamiSettingsBackup(settings)).importUpload(document.body); + (new MamiSettingsBackup(settings)).importUpload(args.parent); }, ['Your current settings will be replaced with the ones in the export.', 'Are you sure you want to continue?']); category.button('Export settings', () => { const user = Umi.User.getCurrentUser(); @@ -573,7 +586,7 @@ window.Umi = { UI: {} }; if(user !== null) fileName = `${user.name}'s settings.mami`; - (new MamiSettingsBackup(settings)).exportDownload(document.body, fileName); + (new MamiSettingsBackup(settings)).exportDownload(args.parent, fileName); }); category.button('Reset settings', () => { settings.clear(); @@ -729,7 +742,7 @@ window.Umi = { UI: {} }; }, }, }); - document.body.appendChild(uploadForm); + args.parent.appendChild(uploadForm); Umi.UI.InputMenus.AddButton('upload', 'Upload', () => uploadForm.click(), 'markup'); @@ -741,10 +754,10 @@ window.Umi = { UI: {} }; }); // figure out how to display a UI for this someday - //document.body.addEventListener('dragenter', ev => { console.info('dragenter', ev); }); - //document.body.addEventListener('dragleave', ev => { console.info('dragleave', ev); }); - document.body.addEventListener('dragover', ev => { ev.preventDefault(); }); - document.body.addEventListener('drop', ev => { + //args.parent.addEventListener('dragenter', ev => { console.info('dragenter', ev); }); + //args.parent.addEventListener('dragleave', ev => { console.info('dragleave', ev); }); + args.parent.addEventListener('dragover', ev => { ev.preventDefault(); }); + args.parent.addEventListener('drop', ev => { if(ev.dataTransfer === undefined || ev.dataTransfer === null || ev.dataTransfer.files.length < 1) return; @@ -897,7 +910,7 @@ window.Umi = { UI: {} }; initWorker(); }); - window.addEventListener('visibilitychange', () => { + document.addEventListener('visibilitychange', () => { if(document.visibilityState === 'visible') { protoWorker.ping().catch(ex => { console.warn('worker died', ex); @@ -907,4 +920,45 @@ window.Umi = { UI: {} }; }); await initWorker(); + + return ctx; +}; + +(() => { + const eventTarget = new MamiEventTargetWindow; + Object.defineProperty(window, 'mamiEventTarget', { enumerable: true, value: eventTarget }); + + MamiInit({ + eventTarget: eventTarget, + }).then(mami => { + //Object.defineProperty(window, 'mami', { enumerable: true, value: mami }); + }); })(); + +const MamiDbgCreateFloatingInstance = async () => { + if(!FUTAMI_DEBUG) + return; + + const prefix = MamiUniqueStr(8); + const parent = $e({ + attrs: { + style: { + position: 'absolute', + bottom: '100px', + right: '100px', + zIndex: '9001', + width: '640px', + height: '480px', + background: '#0f0', + }, + }, + }); + + document.body.appendChild(parent); + + return await MamiInit({ + parent: parent, + settingsPrefix: `dbg:${prefix}:`, + eventTarget: mamiEventTarget.scopeTo(prefix), + }); +}; diff --git a/src/mami.js/mszauth.js b/src/mami.js/mszauth.js index e945dc5..5aba6c6 100644 --- a/src/mami.js/mszauth.js +++ b/src/mami.js/mszauth.js @@ -7,6 +7,7 @@ const MamiMisuzuAuth = (() => { let authToken = null; return { + hasInfo: () => userId !== null && authToken !== null, getUserId: () => userId, getAuthToken: () => authToken, getLine: () => `${authMethod} ${authToken}`,