diff --git a/build.js b/build.js index 1a683d7..ec6822a 100644 --- a/build.js +++ b/build.js @@ -14,7 +14,8 @@ const exec = require('util').promisify(require('child_process').exec); debug: isDebug, swc: { es: 'es2021', - jsx: '$er', + jsx: '$element', + jsxf: '$fragment', }, housekeep: [ pathJoin(__dirname, 'public', 'assets'), diff --git a/src/mami.js/array.js b/src/mami.js/array.js new file mode 100644 index 0000000..d3a0541 --- /dev/null +++ b/src/mami.js/array.js @@ -0,0 +1,27 @@ +const $arrayRemoveAt = function(array, index) { + array.splice(index, 1); +}; + +const $arrayRemoveValue = function(array, item) { + let index; + while(array.length > 0 && (index = array.indexOf(item)) >= 0) + $arrayRemoveAt(array, index); +}; + +const $arrayRemoveAny = function(array, predicate) { + let index; + while(array.length > 0 && (index = array.findIndex(predicate)) >= 0) + $arrayRemoveAt(array, index); +}; + +const $arrayShuffle = function(array) { + if(array.length < 2) + return; + + for(let i = array.length - 1; i > 0; --i) { + const j = Math.floor(Math.random() * (i + 1)); + const tmp = array[i]; + array[i] = array[j]; + array[j] = tmp; + } +}; diff --git a/src/mami.js/audio/autoplay.js b/src/mami.js/audio/autoplay.js index d1c0ccc..35d4f07 100644 --- a/src/mami.js/audio/autoplay.js +++ b/src/mami.js/audio/autoplay.js @@ -1,11 +1,10 @@ #include srle.js -#include utility.js const MamiDetectAutoPlaySource = '/+NIxA!!FhpbmcA#PA$wA@fgAV$#q$#/$#A#OUxBTUUzLjEwMAIeA!)UCCQC8CIA@gA@H49wpKWgA!%&/+MYxA$NIA$ExBTUUzLjEwMFV^%/+MYxDsA@NIA$FV&&/+MYxHYA@NIA$FV&&'; const MamiDetectAutoPlay = async () => { try { - await $e('audio', { src: 'data:audio/mpeg;base64,' + MamiSRLE.decode(MamiDetectAutoPlaySource) }).play(); + await $element('audio', { src: 'data:audio/mpeg;base64,' + MamiSRLE.decode(MamiDetectAutoPlaySource) }).play(); } catch(ex) { return false; } diff --git a/src/mami.js/audio/context.js b/src/mami.js/audio/context.js index 0f83467..c8f58d0 100644 --- a/src/mami.js/audio/context.js +++ b/src/mami.js/audio/context.js @@ -1,4 +1,3 @@ -#include xhr.js #include audio/source.js const MamiAudioContext = function() { @@ -62,8 +61,8 @@ const MamiAudioContext = function() { if(ctx === undefined) return undefined; - const result = await $x.get(url, { type: 'arraybuffer' }); - return await ctx.decodeAudioData(result.body); + const { body } = await $xhr.get(url, { type: 'arraybuffer' }); + return await ctx.decodeAudioData(body); }, createSource: (buffer, reverse) => { diff --git a/src/mami.js/colpick/picker.jsx b/src/mami.js/colpick/picker.jsx index 1da2d23..f0a26e3 100644 --- a/src/mami.js/colpick/picker.jsx +++ b/src/mami.js/colpick/picker.jsx @@ -1,6 +1,5 @@ #include args.js #include colour.js -#include utility.js #include controls/tabs.js #include colpick/tgrid.jsx #include colpick/tpresets.jsx @@ -101,8 +100,8 @@ const MamiColourPicker = function(options) { }, onRemove: ctx => { const name = ctx.info.name; - $rq(`.colpick-tab-${name}-button`); - $rq(`.colpick-tab-${name}-container`); + $query(`.colpick-tab-${name}-button`)?.remove(); + $query(`.colpick-tab-${name}-container`)?.remove(); }, onSwitch: ctx => { if(ctx.from !== undefined) { diff --git a/src/mami.js/common.js b/src/mami.js/common.js index 718fc45..f78ffbd 100644 --- a/src/mami.js/common.js +++ b/src/mami.js/common.js @@ -1,5 +1,3 @@ -#include xhr.js - const FutamiCommon = function(vars) { vars = vars || {}; @@ -15,14 +13,16 @@ const FutamiCommon = function(vars) { if(noCache) options.headers = { 'Cache-Control': 'no-cache' }; - return (await $x.get(get(name), options)).body; + const { body } = await $xhr.get(get(name), options); + return body; }, getApiJson: async (path, noCache) => { const options = { type: 'json' }; if(noCache) options.headers = { 'Cache-Control': 'no-cache' }; - return (await $x.get(get('api') + path, options)).body; + const { body } = await $xhr.get(get('api') + path, options); + return body; }, }; }; @@ -31,7 +31,7 @@ FutamiCommon.load = async url => { if(typeof url !== 'string' && 'FUTAMI_URL' in window) url = window.FUTAMI_URL + '?t=' + Date.now().toString(); - const { body } = await $x.get(url, { + const { body } = await $xhr.get(url, { type: 'json', headers: { 'Cache-Control': 'no-cache' diff --git a/src/mami.js/conman.js b/src/mami.js/conman.js index 0e520df..68cabde 100644 --- a/src/mami.js/conman.js +++ b/src/mami.js/conman.js @@ -1,5 +1,4 @@ #include awaitable.js -#include utility.js const MamiConnectionManager = function(client, settings, urls, eventTarget) { const validateClient = value => { @@ -42,7 +41,7 @@ const MamiConnectionManager = function(client, settings, urls, eventTarget) { url = undefined; }; - $as(urls); + $arrayShuffle(urls); const attempt = () => { started = Date.now(); diff --git a/src/mami.js/controls/msgbox.jsx b/src/mami.js/controls/msgbox.jsx index b0153c4..618f03e 100644 --- a/src/mami.js/controls/msgbox.jsx +++ b/src/mami.js/controls/msgbox.jsx @@ -1,6 +1,5 @@ #include animate.js #include args.js -#include utility.js const MamiMessageBoxContainer = function() { const container = <div class="msgbox-container"/>; @@ -229,7 +228,7 @@ const MamiMessageBoxDialog = function(info) { end: () => { dialog.style.opacity = '0'; }, }); - $r(dialog); + dialog.remove(); }, cancel: () => { doReject(); diff --git a/src/mami.js/controls/tabs.js b/src/mami.js/controls/tabs.js index 9a89962..fa153cb 100644 --- a/src/mami.js/controls/tabs.js +++ b/src/mami.js/controls/tabs.js @@ -1,5 +1,4 @@ #include args.js -#include uniqstr.js const MamiTabsControl = function(options) { options = MamiArgs('options', options, define => { @@ -21,8 +20,6 @@ const MamiTabsControl = function(options) { element = elementInfo; } else if('element' in elementInfo) { element = elementInfo.element; - } else if('getElement' in elementInfo) { - element = elementInfo.getElement(); } else throw 'elementInfo is not a valid type'; if(!(element instanceof Element)) @@ -126,7 +123,7 @@ const MamiTabsControl = function(options) { if(tabId !== undefined) throw 'tabInfo has already been added'; - tabId = MamiUniqueStr(8); + tabId = $rngs(8); tabs.set(tabId, tabInfo); if(title !== 'string' && 'title' in tabInfo) diff --git a/src/mami.js/controls/views.js b/src/mami.js/controls/views.js index 8e4586c..c75d486 100644 --- a/src/mami.js/controls/views.js +++ b/src/mami.js/controls/views.js @@ -1,5 +1,4 @@ #include args.js -#include utility.js const MamiViewsControl = function(options) { options = MamiArgs('options', options, define => { @@ -17,8 +16,6 @@ const MamiViewsControl = function(options) { element = elementInfo; } else if('element' in elementInfo) { element = elementInfo.element; - } else if('getElement' in elementInfo) { - element = elementInfo.getElement(); } else throw 'elementInfo is not a valid type'; if(!(element instanceof Element)) diff --git a/src/mami.js/eeprom/eeprom.js b/src/mami.js/eeprom/eeprom.js index 40e7a71..5bcbb5f 100644 --- a/src/mami.js/eeprom/eeprom.js +++ b/src/mami.js/eeprom/eeprom.js @@ -1,5 +1,3 @@ -#include xhr.js - const MamiEEPROM = function(endPoint, getAuthLine) { if(typeof endPoint !== 'string') throw 'endPoint must be a string'; @@ -40,7 +38,7 @@ const MamiEEPROM = function(endPoint, getAuthLine) { formData.append('src', appId); formData.append('file', fileInput); - const { status, body } = await $x.post(`${endPoint}/uploads`, { + const { status, body } = await $xhr.post(`${endPoint}/uploads`, { type: 'json', headers: { Authorization: getAuthLine(), @@ -77,7 +75,7 @@ const MamiEEPROM = function(endPoint, getAuthLine) { if(typeof fileInfo.urlf !== 'string') throw 'fileInfo.urlf must be a string'; - const { status, body } = await $x.delete(fileInfo.urlf, { + const { status, body } = await $xhr.delete(fileInfo.urlf, { type: 'json', headers: { Authorization: getAuthLine(), diff --git a/src/mami.js/eeprom/eepromv2.js b/src/mami.js/eeprom/eepromv2.js index e05d8ed..a4336ee 100644 --- a/src/mami.js/eeprom/eepromv2.js +++ b/src/mami.js/eeprom/eepromv2.js @@ -1,6 +1,5 @@ #include concurrent.js #include hash.js -#include xhr.js const MamiEEPROMv2 = function(baseUrl, getAuthLine, poolName) { if(typeof baseUrl !== 'string') @@ -37,7 +36,7 @@ const MamiEEPROMv2 = function(baseUrl, getAuthLine, poolName) { params.append('name', name); params.append('hash', await MamiHash(buffer)); - const { status, body } = await $x.post(`${baseUrl}/v1/storage/pools/${poolName}/uploads`, { + const { status, body } = await $xhr.post(`${baseUrl}/v1/storage/pools/${poolName}/uploads`, { type: 'json', headers: { Authorization: getAuthLine(), @@ -57,7 +56,7 @@ const MamiEEPROMv2 = function(baseUrl, getAuthLine, poolName) { const offset = size * index; buffer = buffer.subarray(offset, Math.min(buffer.length, offset + size)); - const { status, body } = await $x.put(taskInfo.task_url, { + const { status, body } = await $xhr.put(taskInfo.task_url, { type: 'json', headers: { 'X-Content-Index': index, @@ -73,7 +72,7 @@ const MamiEEPROMv2 = function(baseUrl, getAuthLine, poolName) { }; const finishTask = async (taskInfo) => { - const { status, body } = await $x.post(`${baseUrl}/v1/storage/tasks/${taskInfo.task_id}`, { type: 'json' }); + const { status, body } = await $xhr.post(`${baseUrl}/v1/storage/tasks/${taskInfo.task_id}`, { type: 'json' }); if(body === null) throw "Could not complete upload task for some reason."; @@ -146,7 +145,7 @@ const MamiEEPROMv2 = function(baseUrl, getAuthLine, poolName) { if(typeof fileInfo.id !== 'string') throw 'fileInfo.id must be a string'; - const { status, body } = await $x.delete(`${baseUrl}/v1/storage/uploads/${fileInfo.id}`, { + const { status, body } = await $xhr.delete(`${baseUrl}/v1/storage/uploads/${fileInfo.id}`, { type: 'json', headers: { Authorization: getAuthLine(), diff --git a/src/mami.js/emotes/picker.jsx b/src/mami.js/emotes/picker.jsx index 2b1ffac..78a45ce 100644 --- a/src/mami.js/emotes/picker.jsx +++ b/src/mami.js/emotes/picker.jsx @@ -1,5 +1,4 @@ #include args.js -#include utility.js const MamiEmotePicker = function(args) { args = MamiArgs('args', args, define => { @@ -35,7 +34,7 @@ const MamiEmotePicker = function(args) { </div>; const buildList = () => { - $rc(listElem); + $removeChildren(listElem); for(const emote of emotes) listElem.appendChild(<button class="emopick-emote" type="button" title={`:${emote.strings[0]}:`} data-strings={emote.strings.join(' ')} onclick={() => { diff --git a/src/mami.js/html.js b/src/mami.js/html.js new file mode 100644 index 0000000..35fe14d --- /dev/null +++ b/src/mami.js/html.js @@ -0,0 +1,139 @@ +const $id = document.getElementById.bind(document); +const $query = document.querySelector.bind(document); +const $queryAll = document.querySelectorAll.bind(document); +const $text = document.createTextNode.bind(document); + +const $insertBefore = function(target, element) { + target.parentNode.insertBefore(element, target); +}; + +const $appendChild = function(element, child) { + switch(typeof child) { + case 'undefined': + break; + + case 'string': + element.appendChild($text(child)); + break; + + case 'function': + $appendChild(element, child()); + break; + + case 'object': + if(child === null) + break; + + if(child instanceof Node) + element.appendChild(child); + else if(child?.element instanceof Node) + element.appendChild(child.element); + else if(typeof child?.toString === 'function') + element.appendChild($text(child.toString())); + break; + + default: + element.appendChild($text(child.toString())); + break; + } +}; + +const $appendChildren = function(element, ...children) { + for(const child of children) + $appendChild(element, child); +}; + +const $removeChildren = function(element) { + while(element.lastChild) + element.removeChild(element.lastChild); +}; + +const $fragment = function(props, ...children) { + const fragment = document.createDocumentFragment(); + $appendChildren(fragment, ...children); + return fragment; +}; + +const $element = function(type, props, ...children) { + if(typeof type === 'function') + return new type(props ?? {}, ...children); + + const element = document.createElement(type ?? 'div'); + + if(props) + for(let key in props) { + const prop = props[key]; + if(prop === undefined || prop === null) + continue; + + switch(typeof prop) { + case 'function': + if(key.substring(0, 2) === 'on') + key = key.substring(2).toLowerCase(); + element.addEventListener(key, prop); + break; + + case 'object': + if(prop instanceof Array) { + if(key === 'class') + key = 'classList'; + + const attr = element[key]; + let addFunc = null; + + if(attr instanceof Array) + addFunc = attr.push.bind(attr); + else if(attr instanceof DOMTokenList) + addFunc = attr.add.bind(attr); + + if(addFunc !== null) { + for(let j = 0; j < prop.length; ++j) + addFunc(prop[j]); + } else { + if(key === 'classList') + key = 'class'; + element.setAttribute(key, prop.toString()); + } + } else { + if(key === 'class' || key === 'className') + key = 'classList'; + + let setFunc = null; + if(element[key] instanceof DOMTokenList) + setFunc = (ak, av) => { if(av) element[key].add(ak); }; + else if(element[key] instanceof CSSStyleDeclaration) + setFunc = (ak, av) => { + if(ak.includes('-')) + element[key].setProperty(ak, av); + else + element[key][ak] = av; + }; + else + setFunc = (ak, av) => { element[key][ak] = av; }; + + for(const attrKey in prop) { + const attrValue = prop[attrKey]; + if(attrValue) + setFunc(attrKey, attrValue); + } + } + break; + + case 'boolean': + if(prop) + element.setAttribute(key, ''); + break; + + default: + if(key === 'className') + key = 'class'; + + element.setAttribute(key, prop.toString()); + break; + } + } + + $appendChildren(element, ...children); + + return element; +}; diff --git a/src/mami.js/main.js b/src/mami.js/main.js index bcd5dd0..824eb33 100644 --- a/src/mami.js/main.js +++ b/src/mami.js/main.js @@ -1,5 +1,10 @@ window.Umi = { UI: {} }; +#include array.js +#include html.js +#include uniqstr.js +#include xhr.js + #include animate.js #include args.js #include awaitable.js @@ -14,9 +19,7 @@ window.Umi = { UI: {} }; #include parsing.js #include themes.js #include txtrigs.js -#include uniqstr.js #include users.js -#include utility.js #include weeb.js #include audio/autoplay.js #include chatform/form.jsx @@ -262,13 +265,9 @@ const MamiInit = async args => { text: title, createdButton: button => { button.element.id = `umi-menu-icons-${baseId}`; - button.element.append($e({ - attrs: { className: `sidebar__selector-mode--${baseId}` }, - })); + button.element.append($element('div', { className: `sidebar__selector-mode--${baseId}` })); }, - element: $e({ - attrs: { 'class': `sidebar__menu--${baseId}`, id: `umi-menus-${baseId}` } - }), + element: $element('div', { 'class': `sidebar__menu--${baseId}`, id: `umi-menus-${baseId}` }), }); } }); @@ -313,7 +312,7 @@ const MamiInit = async args => { if(bbCode.tag === 'color') { if(colourPicker === undefined) { colourPicker = new MamiColourPicker({ presets: futami.get('colours') }); - layout.getElement().appendChild(colourPicker.element); + layout.element.appendChild(colourPicker.element); } if(colourPickerVisible) { @@ -339,19 +338,19 @@ const MamiInit = async args => { }); settings.watch('style', ev => { - for(const className of layout.getElement().classList) + for(const className of layout.element.classList) if(className.startsWith('umi--')) - layout.getElement().classList.remove(className); - layout.getElement().classList.add(`umi--${ev.detail.value}`); + layout.element.classList.remove(className); + layout.element.classList.add(`umi--${ev.detail.value}`); UmiThemeApply(ev.detail.value); }); settings.watch('compactView', ev => { - layout.getElement().classList.toggle('chat--compact', ev.detail.value); - layout.getInterface().getMessageList().getElement().classList.toggle('chat--compact', ev.detail.value); + layout.element.classList.toggle('chat--compact', ev.detail.value); + layout.interface.messageList.element.classList.toggle('chat--compact', ev.detail.value); }); settings.watch('preventOverflow', ev => { args.parent.classList.toggle('prevent-overflow', ev.detail.value); }); - settings.watch('doNotMarkLinksAsVisited', ev => { layout.getInterface().getMessageList().getElement().classList.toggle('mami-do-not-mark-links-as-visited', ev.detail.value); }); + settings.watch('doNotMarkLinksAsVisited', ev => { layout.interface.messageList.element.classList.toggle('mami-do-not-mark-links-as-visited', ev.detail.value); }); settings.watch('newLineOnEnter', ev => { chatForm.input.newLineOnEnter = ev.detail.value; }); settings.watch('expandTextBox', ev => { chatForm.input.growInputField = ev.detail.value; }); @@ -705,7 +704,7 @@ const MamiInit = async args => { getEmotes: () => MamiEmotes.all(Umi.User.getCurrentUser().perms.rank), setKeepOpenOnPick: value => { settings.set('keepEmotePickerOpen', value); }, }); - layout.getElement().appendChild(emotePicker.element); + layout.element.appendChild(emotePicker.element); settings.watch('keepEmotePickerOpen', ev => { emotePicker.keepOpenOnPick = ev.detail.value; }); } @@ -799,16 +798,13 @@ const MamiInit = async args => { } }; - const uploadForm = $e({ - tag: 'input', - attrs: { - type: 'file', - multiple: true, - style: { display: 'none' }, - onchange: ev => { - for(const file of ev.target.files) - doUpload(file); - }, + const uploadForm = $element('input', { + type: 'file', + multiple: true, + style: { display: 'none' }, + onchange: ev => { + for(const file of ev.target.files) + doUpload(file); }, }); args.parent.appendChild(uploadForm); @@ -981,18 +977,16 @@ 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', - }, + const prefix = $rngs(8); + const parent = $element('div', { + style: { + position: 'absolute', + bottom: '100px', + right: '100px', + zIndex: '9001', + width: '640px', + height: '480px', + background: '#0f0', }, }); diff --git a/src/mami.js/mszauth.js b/src/mami.js/mszauth.js index b7ede47..42bb0d3 100644 --- a/src/mami.js/mszauth.js +++ b/src/mami.js/mszauth.js @@ -1,5 +1,4 @@ #include common.js -#include xhr.js const MamiMisuzuAuth = (() => { let userId = null; @@ -18,7 +17,7 @@ const MamiMisuzuAuth = (() => { }; }, update: async () => { - const { body } = await $x.get(futami.get('token'), { authed: true, type: 'json' }); + const { body } = await $xhr.get(futami.get('token'), { authed: true, type: 'json' }); if(body.ok) { userId = body.usr.toString(); authToken = body.tkn; diff --git a/src/mami.js/parsing.js b/src/mami.js/parsing.js index cab838a..7ef6cbb 100644 --- a/src/mami.js/parsing.js +++ b/src/mami.js/parsing.js @@ -1,5 +1,3 @@ -#include utility.js - if(!Umi.Parser) Umi.Parser = {}; if(!Umi.Parser.SockChatBBcode) Umi.Parser.SockChatBBcode = {}; @@ -146,8 +144,9 @@ Umi.Parsing = (function() { }; }; const motivFrame = function(texts, body) { - return $e({ - attrs: { + return $element( + 'div', + { style: { display: 'inline-block', textAlign: 'center', @@ -158,48 +157,46 @@ Umi.Parsing = (function() { lineHeight: '1.4em', }, }, - child: [ + $element( + 'div', { - tag: 'div', - attrs: { - style: { - border: '3px double #fff', - maxWidth: '50vw', - maxHeight: '50vh', - marginTop: '30px', - marginLeft: '50px', - marginRight: '50px', - boxSizing: 'content-box', - display: 'inline-block', - }, - }, - child: body, - }, - { - tag: 'h1', - child: texts.top, - attrs: { - style: { - color: '#fff', - textDecoration: 'none !important', - margin: '10px', - textTransform: 'uppercase', - }, + style: { + border: '3px double #fff', + maxWidth: '50vw', + maxHeight: '50vh', + marginTop: '30px', + marginLeft: '50px', + marginRight: '50px', + boxSizing: 'content-box', + display: 'inline-block', }, }, + body + ), + $element( + 'h1', { - tag: 'p', - child: texts.bottom, - attrs: { - style: { - color: '#fff', - textDecoration: 'none !important', - margin: '10px', - }, + style: { + color: '#fff', + textDecoration: 'none !important', + margin: '10px', + textTransform: 'uppercase', }, }, - ], - }); + texts.top + ), + $element( + 'p', + { + style: { + color: '#fff', + textDecoration: 'none !important', + margin: '10px', + }, + }, + texts.bottom + ), + ); }; const toggleImage = function(element) { @@ -219,9 +216,9 @@ Umi.Parsing = (function() { element.dataset.embed = '1'; element.classList.add('markup__link--visited'); - let html = $e({ - tag: 'img', - attrs: { + let html = $element( + 'img', + { src: url, alt: url, style: { @@ -234,7 +231,7 @@ Umi.Parsing = (function() { container.scrollIntoView({ inline: 'end' }); }, }, - }); + ); if(mami.settings.get('motivationalImages')) html = motivFrame( @@ -256,16 +253,16 @@ Umi.Parsing = (function() { element.dataset.embed = '0'; element.textContent = 'Embed'; container.textContent = ''; - container.appendChild($e({ - tag: 'a', - attrs: { + container.appendChild($element( + 'a', + { href: url, target: '_blank', rel: 'nofollow noreferrer noopener', className: 'markup__link', }, - child: url, - })); + url, + )); } else { container.title = 'audio'; element.dataset.embed = '1'; @@ -273,9 +270,9 @@ Umi.Parsing = (function() { container.textContent = ''; element.classList.add('markup__link--visited'); - let media = $e({ - tag: 'audio', - attrs: { + let media = $element( + 'audio', + { src: url, controls: true, onloadedmetadata: () => { @@ -285,7 +282,7 @@ Umi.Parsing = (function() { media.play(); }, }, - }); + ); container.appendChild(media); } @@ -300,25 +297,25 @@ Umi.Parsing = (function() { element.dataset.embed = '0'; element.textContent = 'Embed'; container.textContent = ''; - container.appendChild($e({ - tag: 'a', - attrs: { + container.appendChild($element( + 'a', + { href: url, target: '_blank', rel: 'nofollow noreferrer noopener', className: 'markup__link', }, - child: url, - })); + url, + )); } else { container.title = 'video'; element.dataset.embed = '1'; element.textContent = 'Remove'; element.classList.add('markup__link--visited'); - let media = $e({ - tag: 'video', - attrs: { + let media = $element( + 'video', + { src: url, controls: true, style: { @@ -332,7 +329,7 @@ Umi.Parsing = (function() { media.play(); }, }, - }); + ); let html = media; diff --git a/src/mami.js/settings/backup.js b/src/mami.js/settings/backup.js index 0dd7967..34d9158 100644 --- a/src/mami.js/settings/backup.js +++ b/src/mami.js/settings/backup.js @@ -1,5 +1,3 @@ -#include utility.js - const MamiSettingsBackup = function(settings) { const header = 'Mami Settings Export'; const version = 1; @@ -88,7 +86,7 @@ const MamiSettingsBackup = function(settings) { fileName = 'settings.mami'; const data = exportData(); - const html = $e('a', { + const html = $element('a', { href: URL.createObjectURL(new Blob([data], { type: 'application/octet-stream' })), download: fileName, target: '_blank', @@ -102,7 +100,7 @@ const MamiSettingsBackup = function(settings) { importFile: importFile, importUpload: (target) => { return new Promise((resolve, reject) => { - const html = $e('input', { + const html = $element('input', { type: 'file', accept: '.mami', style: { display: 'none' }, diff --git a/src/mami.js/sidebar/act-collapse-all.jsx b/src/mami.js/sidebar/act-collapse-all.jsx index a030d52..5655376 100644 --- a/src/mami.js/sidebar/act-collapse-all.jsx +++ b/src/mami.js/sidebar/act-collapse-all.jsx @@ -1,5 +1,3 @@ -#include utility.js - const MamiSidebarActionCollapseAll = function() { // this should take a reference to the message container rather than just using $qa @@ -12,7 +10,7 @@ const MamiSidebarActionCollapseAll = function() { }, onclick: () => { - const buttons = $qa('[data-embed="1"]'); + const buttons = $queryAll('[data-embed="1"]'); for(const button of buttons) button.click(); }, diff --git a/src/mami.js/sidebar/pan-settings.jsx b/src/mami.js/sidebar/pan-settings.jsx index 7a67e67..909f307 100644 --- a/src/mami.js/sidebar/pan-settings.jsx +++ b/src/mami.js/sidebar/pan-settings.jsx @@ -191,7 +191,7 @@ const MamiSidebarPanelSettings = function(settings, msgBox) { const updateSelectOptions = () => { const options = setting.options(); - $rc(input); + $removeChildren(input); for(const name in options) input.appendChild(<option class={`setting__style setting__style--${setting.name}-${name}`} value={name}> {options[name]} diff --git a/src/mami.js/sidebar/pan-uploads.jsx b/src/mami.js/sidebar/pan-uploads.jsx index e61114d..e5d93be 100644 --- a/src/mami.js/sidebar/pan-uploads.jsx +++ b/src/mami.js/sidebar/pan-uploads.jsx @@ -1,5 +1,3 @@ -#include utility.js - const MamiSidebarPanelUploadsEntry = function(fileInfo) { const options = new Map; let uploadInfo; @@ -164,7 +162,7 @@ const MamiSidebarPanelUploads = function() { return; html.removeChild(entry.element); - $ari(entries, entry); + $arrayRemoveValue(entries, entry); }, addOption: option => { diff --git a/src/mami.js/sidebar/pan-users.jsx b/src/mami.js/sidebar/pan-users.jsx index b42f5da..f60f96f 100644 --- a/src/mami.js/sidebar/pan-users.jsx +++ b/src/mami.js/sidebar/pan-users.jsx @@ -1,6 +1,5 @@ #include animate.js #include users.js -#include utility.js const MamiSidebarPanelUsersEntry = function(info) { const id = info.id; diff --git a/src/mami.js/sound/sndmgr.js b/src/mami.js/sound/sndmgr.js index c5bd813..809c441 100644 --- a/src/mami.js/sound/sndmgr.js +++ b/src/mami.js/sound/sndmgr.js @@ -1,5 +1,3 @@ -#include utility.js - const MamiSoundManager = function(context) { const probablySupported = []; const maybeSupported = []; @@ -12,7 +10,7 @@ const MamiSoundManager = function(context) { }; (() => { - const elem = $e('audio'); + const elem = $element('audio'); for(const name in formats) { const format = formats[name]; const support = elem.canPlayType(format); diff --git a/src/mami.js/sound/sndtest.jsx b/src/mami.js/sound/sndtest.jsx index c1cac80..66d086a 100644 --- a/src/mami.js/sound/sndtest.jsx +++ b/src/mami.js/sound/sndtest.jsx @@ -130,7 +130,7 @@ const MamiSoundTest = function(settings, audio, manager, library, clickPos) { console.error(ex); state.textContent = `Error: ${ex}`; } finally { - $ari(sources, source); + $arrayRemoveValue(sources, source); await MamiSleep(2000); nowPlaying.removeChild(player); } diff --git a/src/mami.js/themes.js b/src/mami.js/themes.js index 2a39816..da61763 100644 --- a/src/mami.js/themes.js +++ b/src/mami.js/themes.js @@ -311,7 +311,7 @@ const UmiThemeApply = function(theme) { if(theme.colours) { if(typeof theme.colours['main-background'] === 'number') { - const themeColour = $q('meta[name="theme-color"]'); + const themeColour = $query('meta[name="theme-color"]'); if(themeColour instanceof Element) themeColour.content = MamiColour.hex(theme.colours['main-background']); } diff --git a/src/mami.js/ui/chat-interface.js b/src/mami.js/ui/chat-interface.js index a4606be..beff2e6 100644 --- a/src/mami.js/ui/chat-interface.js +++ b/src/mami.js/ui/chat-interface.js @@ -1,25 +1,12 @@ -#include utility.js #include ui/chat-message-list.js Umi.UI.ChatInterface = function(chatForm) { const messages = new Umi.UI.ChatMessageList; - const html = $e({ - attrs: { - className: 'main', - }, - child: [ - messages, - chatForm, - ], - }); + const element = $element('div', { className: 'main' }, messages, chatForm); return { - getMessageList: function() { - return messages; - }, - getElement: function() { - return html; - }, + get messageList() { return messages; }, + get element() { return element; }, }; }; diff --git a/src/mami.js/ui/chat-layout.js b/src/mami.js/ui/chat-layout.js index c4dc51c..90fd484 100644 --- a/src/mami.js/ui/chat-layout.js +++ b/src/mami.js/ui/chat-layout.js @@ -1,27 +1,12 @@ -#include utility.js #include ui/chat-interface.js // this needs revising at some point but will suffice for now Umi.UI.ChatLayout = function(chatForm, sideBar) { const main = new Umi.UI.ChatInterface(chatForm); - - const html = $e({ - attrs: { - id: 'umi-chat', - className: 'umi', - }, - child: [ - main, - sideBar, - ], - }); + const element = $element('div', { id: 'umi-chat', className: 'umi' }, main, sideBar); return { - getInterface: function() { - return main; - }, - getElement: function() { - return html; - }, + get interface() { return main; }, + get element() { return element; }, }; }; diff --git a/src/mami.js/ui/chat-message-list.js b/src/mami.js/ui/chat-message-list.js index 0b6df12..150fc05 100644 --- a/src/mami.js/ui/chat-message-list.js +++ b/src/mami.js/ui/chat-message-list.js @@ -1,16 +1,7 @@ -#include utility.js - Umi.UI.ChatMessageList = function() { - const html = $e({ - attrs: { - id: 'umi-messages', - className: 'chat', - }, - }); + const element = $element('div', { id: 'umi-messages', className: 'chat' }); return { - getElement: function() { - return html; - }, + get element() { return element; }, }; }; diff --git a/src/mami.js/ui/emotes.js b/src/mami.js/ui/emotes.js index 9ac53d7..f3a8c1e 100644 --- a/src/mami.js/ui/emotes.js +++ b/src/mami.js/ui/emotes.js @@ -1,5 +1,4 @@ #include emotes.js -#include utility.js Umi.UI.Emoticons = (function() { return { @@ -7,13 +6,7 @@ Umi.UI.Emoticons = (function() { let inner = element.innerHTML; MamiEmotes.forEach(author?.perms?.rank ?? 0, function(emote) { - const image = $e({ - tag: 'img', - attrs: { - className: 'emoticon', - src: emote.url, - }, - }); + const image = $element('img', { className: 'emoticon', src: emote.url }); for (const i in emote.strings) { const trigger = ':' + emote.strings[i] + ':', diff --git a/src/mami.js/ui/loading-overlay.jsx b/src/mami.js/ui/loading-overlay.jsx index d59575d..213c672 100644 --- a/src/mami.js/ui/loading-overlay.jsx +++ b/src/mami.js/ui/loading-overlay.jsx @@ -1,5 +1,3 @@ -#include utility.js - Umi.UI.LoadingOverlay = function(icon, header, message) { const icons = { 'spinner': 'fas fa-3x fa-fw fa-spinner fa-pulse', diff --git a/src/mami.js/ui/messages.jsx b/src/mami.js/ui/messages.jsx index af97f73..9ad2739 100644 --- a/src/mami.js/ui/messages.jsx +++ b/src/mami.js/ui/messages.jsx @@ -4,7 +4,6 @@ #include txtrigs.js #include url.js #include users.js -#include utility.js #include weeb.js #include sound/umisound.js #include ui/emotes.js @@ -97,7 +96,7 @@ Umi.UI.Messages = (function() { Add: function(msg) { const elementId = `message-${msg.id}`; - if(msg.id !== '' && $i(elementId)) + if(msg.id !== '' && $id(elementId)) return; let isTiny = false; @@ -254,8 +253,8 @@ Umi.UI.Messages = (function() { } if(mami.settings.get('weeaboo')) { - eUser.appendChild($t(Weeaboo.getNameSuffix(msgAuthor))); - eText.appendChild($t(Weeaboo.getTextSuffix(msgAuthor))); + eUser.appendChild($text(Weeaboo.getNameSuffix(msgAuthor))); + eText.appendChild($text(Weeaboo.getTextSuffix(msgAuthor))); const kaomoji = Weeaboo.getRandomKaomoji(true, msg); if(kaomoji) @@ -269,7 +268,7 @@ Umi.UI.Messages = (function() { else eAvatar.classList.add('message__avatar--disabled'); - const msgsList = $i('umi-messages'); + const msgsList = $id('umi-messages'); let insertAfter = msgsList.lastElementChild; if(insertAfter instanceof Element) { @@ -372,11 +371,11 @@ Umi.UI.Messages = (function() { mami.globalEvents.dispatch('umi:ui:message_add', { element: eBase }); }, IsScrolledToBottom: () => { - const msgsList = $i('umi-messages'); + const msgsList = $id('umi-messages'); return msgsList.scrollTop === (msgsList.scrollHeight - msgsList.offsetHeight); }, ScrollIfNeeded: (offsetOrForce = 0) => { - const msgsList = $i('umi-messages'); + const msgsList = $id('umi-messages'); if(!(msgsList instanceof Element)) return; @@ -397,7 +396,7 @@ Umi.UI.Messages = (function() { focusChannelName = channel; - const root = $i('umi-messages'); + const root = $id('umi-messages'); for(const elem of root.children) elem.classList.toggle('hidden', elem.dataset.channel !== undefined && elem.dataset.channel !== focusChannelName); @@ -409,7 +408,7 @@ Umi.UI.Messages = (function() { if(typeof retain !== 'number') return; - const root = $i('umi-messages'); + const root = $id('umi-messages'); // remove messages if(root.childElementCount > retain) @@ -419,7 +418,7 @@ Umi.UI.Messages = (function() { if(!elem.dataset.channel || elem.classList.contains('hidden') || --retain > 0) continue; - $r(elem); + elem.remove(); } // fix author display @@ -441,7 +440,7 @@ Umi.UI.Messages = (function() { if(msgId === '') return; - const elem = $i(`message-${msgId}`); + const elem = $id(`message-${msgId}`); if(!(elem instanceof Element)) return; @@ -449,7 +448,7 @@ Umi.UI.Messages = (function() { if(elem.nextElementSibling && elem.nextElementSibling.dataset.author === elem.dataset.author) elem.nextElementSibling.classList.add('message--first'); - $r(elem); + elem.remove(); }, }; })(); diff --git a/src/mami.js/uniqstr.js b/src/mami.js/uniqstr.js index 72a1111..9917cad 100644 --- a/src/mami.js/uniqstr.js +++ b/src/mami.js/uniqstr.js @@ -1,4 +1,4 @@ -const MamiRandomInt = (min, max) => { +const $rngi = (min, max) => { let ret = 0; const range = max - min; @@ -21,18 +21,18 @@ const MamiRandomInt = (min, max) => { ret &= mask; if(ret >= range) - return MamiRandomInt(min, max); + return $rngi(min, max); return min + ret; }; -const MamiUniqueStr = (() => { +const $rngs = (() => { const chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'; return length => { let str = ''; for(let i = 0; i < length; ++i) - str += chars[MamiRandomInt(0, chars.length)]; + str += chars[$rngi(0, chars.length)]; return str; }; })(); diff --git a/src/mami.js/utility.js b/src/mami.js/utility.js deleted file mode 100644 index abd1591..0000000 --- a/src/mami.js/utility.js +++ /dev/null @@ -1,170 +0,0 @@ -const $i = document.getElementById.bind(document); -const $c = document.getElementsByClassName.bind(document); -const $q = document.querySelector.bind(document); -const $qa = document.querySelectorAll.bind(document); -const $t = document.createTextNode.bind(document); - -const $r = function(element) { - if(element && element.parentNode) - element.parentNode.removeChild(element); -}; - -const $ri = function(name) { - $r($i(name)); -}; - -const $rq = function(query) { - $r($q(query)); -}; - -const $ib = function(ref, elem) { - ref.parentNode.insertBefore(elem, ref); -}; - -const $rc = function(element) { - while(element.lastChild) - element.removeChild(element.lastChild); -}; - -const $e = function(info, attrs, child, created) { - info = info || {}; - - if(typeof info === 'string') { - info = {tag: info}; - if(attrs) - info.attrs = attrs; - if(child) - info.child = child; - if(created) - info.created = created; - } - - const elem = document.createElement(info.tag || 'div'); - - if(info.attrs) { - const attrs = info.attrs; - - for(let key in attrs) { - const attr = attrs[key]; - if(attr === undefined || attr === null) - continue; - - switch(typeof attr) { - case 'function': - if(key.substring(0, 2) === 'on') - key = key.substring(2).toLowerCase(); - elem.addEventListener(key, attr); - break; - - case 'object': - if(attr instanceof Array) { - if(key === 'class') - key = 'classList'; - - const prop = elem[key]; - let addFunc = null; - - if(prop instanceof Array) - addFunc = prop.push.bind(prop); - else if(prop instanceof DOMTokenList) - addFunc = prop.add.bind(prop); - - if(addFunc !== null) { - for(let j = 0; j < attr.length; ++j) - addFunc(attr[j]); - } else { - if(key === 'classList') - key = 'class'; - elem.setAttribute(key, attr.toString()); - } - } else { - for(const attrKey in attr) - elem[key][attrKey] = attr[attrKey]; - } - break; - - case 'boolean': - if(attr) - elem.setAttribute(key, ''); - break; - - default: - if(key === 'className') - key = 'class'; - elem.setAttribute(key, attr.toString()); - break; - } - } - } - - if(info.child) { - let children = info.child; - - if(!Array.isArray(children)) - children = [children]; - - for(const child of children) { - switch(typeof child) { - case 'string': - elem.appendChild($t(child)); - break; - - case 'object': - if(child instanceof Element) { - elem.appendChild(child); - } else if('element' in child) { - const childElem = child.element; - if(childElem instanceof Element) - elem.appendChild(childElem); - else - elem.appendChild($e(child)); - } else if('getElement' in child) { - const childElem = child.getElement(); - if(childElem instanceof Element) - elem.appendChild(childElem); - else - elem.appendChild($e(child)); - } else { - elem.appendChild($e(child)); - } - break; - - default: - elem.appendChild($t(child.toString())); - break; - } - } - } - - if(info.created) - info.created(elem); - - return elem; -}; -const $er = (type, props, ...children) => $e({ tag: type, attrs: props, child: children }); - -const $ar = function(array, index) { - array.splice(index, 1); -}; -const $ari = function(array, item) { - let index; - while(array.length > 0 && (index = array.indexOf(item)) >= 0) - $ar(array, index); -}; -const $arf = function(array, predicate) { - let index; - while(array.length > 0 && (index = array.findIndex(predicate)) >= 0) - $ar(array, index); -}; - -const $as = function(array) { - if(array.length < 2) - return; - - for(let i = array.length - 1; i > 0; --i) { - let j = Math.floor(Math.random() * (i + 1)), - tmp = array[i]; - array[i] = array[j]; - array[j] = tmp; - } -}; diff --git a/src/mami.js/weeb.js b/src/mami.js/weeb.js index 7336544..0379aa5 100644 --- a/src/mami.js/weeb.js +++ b/src/mami.js/weeb.js @@ -1,6 +1,5 @@ #include common.js #include rng.js -#include xhr.js const Weeaboo = (function() { let kaomoji = []; @@ -16,7 +15,7 @@ const Weeaboo = (function() { if(kaomoji.length > 0) return; - $x.get(futami.get('kaomoji')) + $xhr.get(futami.get('kaomoji')) .then(resp => kaomoji = resp.text.split("\n")); }; diff --git a/src/mami.js/xhr.js b/src/mami.js/xhr.js index 66ab03f..491761a 100644 --- a/src/mami.js/xhr.js +++ b/src/mami.js/xhr.js @@ -1,4 +1,4 @@ -const $x = (function() { +const $xhr = (function() { const send = function(method, url, options, body) { if(options === undefined) options = {};