mami/src/mami.js/main.js

489 lines
16 KiB
JavaScript

const Umi = { UI: {} };
#include animate.js
#include common.js
#include context.js
#include emotes.js
#include messages.js
#include mszauth.js
#include server.js
#include settings.js
#include utility.js
#include ui/chat-layout.js
#include ui/domaintrans.jsx
#include ui/elems.js
#include ui/hooks.js
#include ui/input-menus.js
#include ui/loading-overlay.jsx
#include ui/markup.js
#include ui/menus.js
#include ui/view.js
#include ui/settings.js
#include ui/title.js
#include ui/toggles.js
#include ui/uploads.js
#include audio/context.js
#include eeprom/eeprom.js
(async () => {
const ctx = new MamiContext(document.body),
views = ctx.getViews();
Object.defineProperty(window, 'mami', {
value: ctx,
writable: false,
});
const sndLib = ctx.getSoundLibrary(),
sndPacks = ctx.getSoundPacks();
const lo = new Umi.UI.LoadingOverlay('spinner', 'Loading...');
await views.push(lo);
lo.setMessage('Loading environment...');
try {
window.futami = await FutamiCommon.load();
localStorage.setItem('mami:common', JSON.stringify(window.futami));
} catch(ex) {
try {
const cached = JSON.parse(localStorage.getItem('mami:common'));
if(cached === null)
throw 'Cached data is null.';
window.futami = new FutamiCommon(cached);
} catch(ex) {
console.error(ex);
lo.setIcon('cross');
lo.setHeader('Failed!');
lo.setMessage('Failed to load common settings!');
return;
}
}
lo.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);
lo.setMessage('Getting element references...');
// should be dynamic when possible
const layout = new Umi.UI.ChatLayout;
await views.unshift(layout);
Umi.UI.Elements.Chat = layout.getElement();
Umi.UI.Elements.Messages = $i('umi-messages');
Umi.UI.Elements.Menus = $i('umi-menus');
Umi.UI.Elements.Icons = $i('umi-menu-icons');
Umi.UI.Elements.Toggles = $i('umi-toggles');
Umi.UI.Elements.MessageContainer = $i('umi-msg-container');
Umi.UI.Elements.MessageInput = $i('umi-msg-text');
Umi.UI.Elements.MessageSend = $i('umi-msg-send');
Umi.UI.Elements.MessageMenus = $i('umi-msg-menu');
lo.setMessage('Loading sounds...');
try {
const sounds = await futami.getJson('sounds2');
if(Array.isArray(sounds.library))
sndLib.loadSounds(sounds.library, true);
if(Array.isArray(sounds.packs))
sndPacks.loadPacks(sounds.packs, true);
} catch(ex) {
console.error(ex);
}
lo.setMessage('Loading emoticons...');
try {
const emotes = await futami.getJson('emotes');
MamiEmotes.loadLegacy(emotes);
} catch(ex) {
console.error(ex);
}
lo.setMessage('Loading settings...');
Umi.Settings = new Umi.Settings(UmiSettings.settings);
if(!await MamiDetectAutoPlay()) {
Umi.Settings.set('soundEnable', false);
Umi.Settings.virtualise('soundEnable');
}
const meta = UmiSettings.settings;
for(const setting of UmiSettings.settings)
if(setting.watcher)
Umi.Settings.watch(setting.id, setting.watcher);
if(!Umi.Settings.get('tmpSkipDomainPopUpThing'))
await (() => {
return new Promise((resolve) => {
views.push(new MamiDomainTransition(() => {
for(const setting of UmiSettings.settings)
if(setting.id === 'settingsImport') {
setting.click();
break;
}
}, () => {
Umi.Settings.set('tmpSkipDomainPopUpThing', true);
views.pop();
resolve();
}));
});
})();
const onHashChange = () => {
if(location.hash === '#reset') {
for(const setting of UmiSettings.settings)
if(setting.emergencyReset)
Umi.Settings.remove(setting.id);
location.assign('/');
}
};
window.addEventListener('hashchange', onHashChange);
onHashChange();
window.addEventListener('keydown', ev => {
if(ev.altKey && ev.shiftKey && (ev.key === 'R' || ev.key === 'r')) {
Umi.Server.close();
location.hash = 'reset';
}
});
lo.setMessage('Preparing UI...');
Umi.UI.Title.Set(futami.get('title'));
Umi.UI.View.AccentReload();
Umi.UI.Hooks.AddMessageHooks();
Umi.UI.Hooks.AddUserHooks();
Umi.UI.Hooks.AddChannelHooks();
Umi.UI.Hooks.AddTextHooks();
const mcPortalSnd = 'minecraft:nether:enter';
if(Umi.Settings.get('minecraft') !== 'no' && ctx.hasSound() && sndLib.hasSound(mcPortalSnd))
ctx.getSound().load(mcPortalSnd, sndLib.getSound(mcPortalSnd).getSources(), function(success, buffer) {
if(success)
buffer.createSource().play();
});
lo.setMessage('Loading EEPROM...');
try {
await MamiEEPROM.init();
ctx.createEEPROM(
futami.get('eeprom'),
function() { return 'Misuzu ' + MamiMisuzuAuth.getAuthToken(); }
);
} catch(ex) {
console.error(ex);
}
lo.setMessage('Building menus...');
Umi.UI.Menus.Add('users', 'Users');
Umi.UI.Menus.Add('channels', 'Channels', !Umi.Settings.get('showChannelList'));
Umi.UI.Menus.Add('settings', 'Settings');
let sidebarAnimation = null;
Umi.UI.Settings.Init();
Umi.UI.Toggles.Add('menu-toggle', {
'click': function() {
const sidebar = $c('sidebar')[0],
toggle = Umi.UI.Toggles.Get('menu-toggle'),
toggleOpened = 'sidebar__selector-mode--menu-toggle-opened',
toggleClosed = 'sidebar__selector-mode--menu-toggle-closed',
isClosed = toggle.classList.contains(toggleClosed);
if(sidebarAnimation !== null) {
sidebarAnimation.cancel();
sidebarAnimation = null;
}
if(isClosed) {
toggle.classList.add(toggleOpened);
toggle.classList.remove(toggleClosed);
} else {
toggle.classList.add(toggleClosed);
toggle.classList.remove(toggleOpened);
}
let update;
if(isClosed)
update = function(t) {
sidebar.style.width = (40 + (220 * t)).toString() + 'px';
};
else
update = function(t) {
sidebar.style.width = (260 - (220 * t)).toString() + 'px';
};
sidebarAnimation = MamiAnimate({
duration: 500,
easing: 'easeOutExpo',
update: update,
});
}
}, 'Toggle Sidebar');
Umi.UI.Toggles.Get('menu-toggle').classList.add('sidebar__selector-mode--menu-toggle-opened');
Umi.UI.Toggles.Add('scroll', {
'click': function() {
Umi.Settings.toggle('autoScroll');
}
}, 'Autoscroll');
Umi.Settings.watch('autoScroll', function(value) {
Umi.UI.Toggles.Get('scroll').classList[value ? 'remove' : 'add']('sidebar__selector-mode--scroll-off');
});
if(window.innerWidth < 768)
Umi.UI.Toggles.Get('menu-toggle').click();
Umi.UI.Toggles.Add('audio', {
'click': function() {
Umi.Settings.toggle('soundEnable');
}
}, 'Sounds');
Umi.Settings.watch('soundEnable', function(value) {
Umi.UI.Toggles.Get('audio').classList[value ? 'remove' : 'add']('sidebar__selector-mode--audio-off');
});
Umi.UI.Toggles.Add('unembed', {
'click': function() {
const buttons = $qa('[data-embed="1"]');
for(const button of buttons)
button.click();
}
}, 'Unembed any embedded media');
Umi.UI.Toggles.Add('clear', {
'click': function() {
if(confirm('ARE YOU SURE ABOUT THAT???')) {
const limit = Umi.Settings.get('explosionRadius');
const explode = $e({
tag: 'img',
attrs: {
src: '//static.flash.moe/images/explode.gif',
alt: '',
style: {
position: 'absolute',
zIndex: 9001,
bottom: 0,
right: 0,
pointerEvents: 'none',
},
onLoad: function() {
setTimeout(function(){
$r(explode);
}, 1700);
ctx.playLibrarySound('misc:explode');
},
},
});
document.body.appendChild(explode);
let backLog = Umi.Messages.All();
backLog = backLog.slice(Math.max(backLog.length - limit, 0));
Umi.Messages.Clear();
for(const blMsg of backLog)
Umi.Messages.Add(blMsg);
}
}
}, 'Clear Logs');
if(ctx.hasEEPROM()) {
Umi.UI.Menus.Add('uploads', 'Upload History', !FUTAMI_DEBUG);
const doUpload = function(file) {
const uploadEntry = Umi.UI.Uploads.create(file.name),
uploadTask = ctx.getEEPROM().createUpload(file);
uploadTask.onProgress = function(progressInfo) {
uploadEntry.setProgress(progressInfo.total, progressInfo.loaded);
};
uploadTask.onFailure = function(errorInfo) {
if(!errorInfo.userAborted) {
let errorText = 'Was unable to upload file.';
switch(errorInfo.error) {
case EEPROM.ERR_INVALID:
errorText = 'Upload request was invalid.';
break;
case EEPROM.ERR_AUTH:
errorText = 'Upload authentication failed, refresh and try again.';
break;
case EEPROM.ERR_ACCESS:
errorText = 'You\'re not allowed to upload files.';
break;
case EEPROM.ERR_GONE:
errorText = 'Upload client has a configuration error or the server is gone.';
break;
case EEPROM.ERR_DMCA:
errorText = 'This file has been uploaded before and was removed for copyright reasons, you cannot upload this file.';
break;
case EEPROM.ERR_SERVER:
errorText = 'Upload server returned a critical error, try again later.';
break;
case EEPROM.ERR_SIZE:
if(errorInfo.maxSize < 1)
errorText = 'Selected file is too large.';
else {
const _t = ['bytes', 'KB', 'MB', 'GB', 'TB'],
_i = parseInt(Math.floor(Math.log(errorInfo.maxSize) / Math.log(1024))),
_s = Math.round(errorInfo.maxSize / Math.pow(1024, _i), 2);
errorText = 'Upload may not be larger than %1 %2.'.replace('%1', _s).replace('%2', _t[_i]);
}
break;
}
alert(errorText);
}
uploadEntry.remove();
};
uploadTask.onComplete = function(fileInfo) {
uploadEntry.hideOptions();
uploadEntry.clearOptions();
uploadEntry.removeProgress();
uploadEntry.addOption('Open', fileInfo.url);
uploadEntry.addOption('Insert', function() {
Umi.UI.Markup.InsertRaw(insertText, '');
});
uploadEntry.addOption('Delete', function() {
ctx.getEEPROM().deleteUpload(fileInfo).start();
uploadEntry.remove();
});
let insertText = location.protocol + fileInfo.url;
if(fileInfo.isImage()) {
insertText = '[img]' + fileInfo.url + '[/img]';
uploadEntry.setThumbnail(fileInfo.thumb);
} else if(fileInfo.isAudio() || fileInfo.type === 'application/x-font-gdos') {
insertText = '[audio]' + fileInfo.url + '[/audio]';
uploadEntry.setThumbnail(fileInfo.thumb);
} else if(fileInfo.isVideo()) {
insertText = '[video]' + fileInfo.url + '[/video]';
uploadEntry.setThumbnail(fileInfo.thumb);
}
if(Umi.Settings.get('eepromAutoInsert'))
Umi.UI.Markup.InsertRaw(insertText, '');
};
uploadEntry.addOption('Cancel', function() {
uploadTask.abort();
});
uploadTask.start();
};
const uploadForm = $e({
tag: 'input',
attrs: {
type: 'file',
multiple: true,
style: {
display: 'none',
},
onchange: function(ev) {
for(let i = 0; i < ev.target.files.length; ++i)
doUpload(ev.target.files[i]);
},
},
});
document.body.appendChild(uploadForm);
Umi.UI.InputMenus.AddButton('upload', 'Upload', function() {
uploadForm.click();
});
Umi.UI.Elements.MessageInput.onpaste = function(ev) {
if(ev.clipboardData && ev.clipboardData.files.length > 0)
for(const file of ev.clipboardData.files)
doUpload(file);
};
document.body.ondragenter = function(ev) {
ev.preventDefault();
ev.stopPropagation();
};
document.body.ondragover = function(ev) {
ev.preventDefault();
ev.stopPropagation();
};
document.body.ondragleave = function(ev) {
ev.preventDefault();
ev.stopPropagation();
};
document.body.ondrop = function(ev) {
ev.preventDefault();
ev.stopPropagation();
if(ev.dataTransfer && ev.dataTransfer.files.length > 0)
for(const file of ev.dataTransfer.files) {
if(file.name.slice(-5) === '.mami'
&& confirm('This file appears to be a settings export. Do you want to import it?')) {
Umi.Settings.importFile(file);
return;
}
doUpload(file);
}
};
}
Umi.UI.InputMenus.Add('markup', 'BB Code');
Umi.UI.InputMenus.Add('emotes', 'Emoticons');
window.addEventListener('beforeunload', function(ev) {
if(Umi.Settings.get('closeTabConfirm')) {
ev.preventDefault();
return ev.returnValue = 'Are you sure you want to close the tab?';
}
});
lo.setMessage('Connecting...');
Umi.Server.open(views);
if(window.dispatchEvent)
window.dispatchEvent(new Event('umi:connect'));
})();
#include compat.js