Ported array and html funcs from Misuzu.

This commit is contained in:
flash 2025-02-20 19:19:55 +00:00
parent d6a6683bfa
commit 4638c60af4
35 changed files with 441 additions and 535 deletions

View file

@ -14,7 +14,8 @@ const exec = require('util').promisify(require('child_process').exec);
debug: isDebug, debug: isDebug,
swc: { swc: {
es: 'es5', es: 'es5',
jsx: 'er', jsx: '$element',
jsxf: '$fragment',
}, },
housekeep: [ housekeep: [
pathJoin(__dirname, 'public', 'assets'), pathJoin(__dirname, 'public', 'assets'),

11
public/polyfill/symbol.js Normal file

File diff suppressed because one or more lines are too long

View file

@ -23,6 +23,7 @@
</div> </div>
</div> </div>
</noscript> </noscript>
<script src="{ami.js}" type="text/javascript" charset="utf-8"></script> <script src="/polyfill/symbol.js" type="text/javascript"></script>
<script src="{ami.js}" type="text/javascript"></script>
</body> </body>
</html> </html>

27
src/ami.js/array.js Normal file
View file

@ -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;
}
};

View file

@ -1,21 +1,16 @@
#include utility.js
var AmiOptionButtons = function(parent) { var AmiOptionButtons = function(parent) {
var container = $e({ attrs: { id: 'bbCodeContainer' } }), var container = $element('div', { id: 'bbCodeContainer' });
buttons = new Map; var buttons = new Map;
parent.appendChild(container); parent.appendChild(container);
var createBtn = function(name, title, languageKey, style, onclick) { var createBtn = function(name, title, languageKey, style, onclick) {
var pub = {}; var pub = {};
var elem = $e({ var elem = $element('input', {
tag: 'input', type: 'button',
attrs: { name: typeof languageKey === 'string' ? languageKey : ';;',
type: 'button', value: title,
name: typeof languageKey === 'string' ? languageKey : ';;', style: style,
value: title, onclick: function(ev) { performClick(ev); },
style: style,
onclick: function(ev) { performClick(ev); },
},
}); });
var hide = function() { elem.classList.add('hidden'); }; var hide = function() { elem.classList.add('hidden'); };
@ -62,7 +57,7 @@ var AmiOptionButtons = function(parent) {
}, },
clear: function() { clear: function() {
buttons.clear(); buttons.clear();
$rc(container); $removeChildren(container);
}, },
hide: hide, hide: hide,
show: show, show: show,

View file

@ -8,10 +8,9 @@
#include status.js #include status.js
#include submitbox.js #include submitbox.js
#include title.js #include title.js
#include utility.js
var AmiChat = function(chat, title, parent) { var AmiChat = function(chat, title, parent) {
var container = $e({ attrs: { id: 'chat' } }); var container = $element('div', { id: 'chat' });
var pub = { var pub = {
getElement: function() { return container; }, getElement: function() { return container; },
@ -76,7 +75,7 @@ var AmiChat = function(chat, title, parent) {
pub.appendTo(parent); pub.appendTo(parent);
optionIcons.create('unembed', 'Unembed any embedded media', 'unembed', function() { optionIcons.create('unembed', 'Unembed any embedded media', 'unembed', function() {
var buttons = $c('js-unembed-btn'); var buttons = $queryAll('.js-unembed-btn');
while(buttons.length > 0) while(buttons.length > 0)
buttons[0].click(); buttons[0].click();
}); });

View file

@ -1,10 +1,9 @@
#include colour.js #include colour.js
#include utility.js
#include colpick/picker.jsx #include colpick/picker.jsx
var AmiColourPicker = function(parent) { var AmiColourPicker = function(parent) {
var container = $e({ attrs: { id: 'pickerNew', className: 'hidden' } }), var container = $element('div', { id: 'pickerNew', className: 'hidden' });
callback = undefined; var callback = undefined;
parent.appendChild(container); parent.appendChild(container);
var picker = new FwColourPicker( var picker = new FwColourPicker(

View file

@ -1,5 +1,3 @@
#include utility.js
if(!('WebSocket' in window) && 'MozWebSocket' in window) if(!('WebSocket' in window) && 'MozWebSocket' in window)
window.WebSocket = window.MozWebSocket; window.WebSocket = window.MozWebSocket;
@ -35,8 +33,8 @@ if(!('Map' in window))
var index = keys.indexOf(key); var index = keys.indexOf(key);
if(key < 0) return false; if(key < 0) return false;
$ar(keys, index); $arrayRemoveAt(keys, index);
$ar(values, index); $arrayRemoveAt(values, index);
--obj.size; --obj.size;
}; };

View file

@ -1,7 +1,5 @@
#include utility.js
var AmiCopyright = function(parent) { var AmiCopyright = function(parent) {
var container = $e({ attrs: { id: 'copyright' } }); var container = $element('div', { id: 'copyright' });
parent.appendChild(container); parent.appendChild(container);
return { return {
@ -13,20 +11,13 @@ var AmiCopyright = function(parent) {
if(typeof section === 'string') if(typeof section === 'string')
children.push(section); children.push(section);
else if(Array.isArray(section)) else if(Array.isArray(section))
children.push({ children.push($element('a', {
tag: 'a', href: section[1],
attrs: { target: '_blank',
href: section[1], }, section[0]));
target: '_blank',
},
child: section[0],
});
} }
container.appendChild($e({ container.appendChild($element('p', {}, ...children));
tag: 'p',
child: children,
}))
}, },
}; };
}; };

View file

@ -12,7 +12,6 @@
#include styles.js #include styles.js
#include title.js #include title.js
#include txtrigs.js #include txtrigs.js
#include utility.js
var AmiContext = function(title, auth, loading) { var AmiContext = function(title, auth, loading) {
var pub = {}; var pub = {};

View file

@ -1,23 +1,20 @@
#include watcher.js #include watcher.js
var AmiEmoticonList = function(parent) { var AmiEmoticonList = function(parent) {
var container = $e({ attrs: { id: 'emotes' } }), var container = $element('div', { id: 'emotes' });
watcher = new AmiWatcher; var watcher = new AmiWatcher;
parent.appendChild(container); parent.appendChild(container);
var clear = function() { var clear = function() {
$rc(container); $removeChildren(container);
}; };
var add = function(emote) { var add = function(emote) {
container.appendChild($e({ container.appendChild($element('img', {
tag: 'img', src: emote.url,
attrs: { alt: emote.strings[0],
src: emote.url, title: emote.strings[0],
alt: emote.strings[0], onclick: function() { watcher.call(emote, [emote]); },
title: emote.strings[0],
onclick: function() { watcher.call(emote, [emote]); },
},
})); }));
}; };

139
src/ami.js/html.js Normal file
View file

@ -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.indexOf('-') >= 0)
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;
};

View file

@ -1,21 +1,14 @@
#include utility.js
#include watcher.js #include watcher.js
var AmiInputBox = function(parent) { var AmiInputBox = function(parent) {
var watchers = new AmiWatcherCollection, var watchers = new AmiWatcherCollection;
input = $e({ var input = $element('textarea', {
tag: 'textarea', cols: '2',
attrs: { id: 'message',
cols: '2', autofocus: 'autofocus',
id: 'message', maxlength: '0',
autofocus: 'autofocus', });
maxlength: '0', var container = $element('div', { id: 'inputFieldContainer' }, input);
},
}),
container = $e({
attrs: { id: 'inputFieldContainer' },
child: input,
});
parent.appendChild(container); parent.appendChild(container);
@ -145,7 +138,7 @@ var AmiInputBox = function(parent) {
if(split[0] === value) if(split[0] === value)
input.style[name] = null; input.style[name] = null;
} else if(split.length > 1) { } else if(split.length > 1) {
$ari(split, value); $arrayRemoveValue(split, value);
input.style[name] = split.join(' '); input.style[name] = split.join(' ');
} }
} }

View file

@ -1,23 +1,23 @@
#include utility.js
var AmiLoadingOverlay = function(parent, indicatorShown) { var AmiLoadingOverlay = function(parent, indicatorShown) {
var text = $e({ var text = $element(
attrs: { id: 'conntxt' }, 'div',
child: 'Loading Sock Chat...', { id: 'conntxt' },
}); 'Loading Sock Chat...',
);
var indicator = $e({ attrs: { id: 'indicator' } }); var indicator = $element('div', { id: 'indicator' });
var container = $element(
var container = $e({ 'div',
attrs: { id: 'connmsg' }, { id: 'connmsg' },
child: { $element(
attrs: { id: 'info' }, 'div',
child: [text, indicator], { id: 'info' },
}, text,
}); indicator
),
);
var appendTo = function(parent) { parent.appendChild(container); }; var appendTo = function(parent) { parent.appendChild(container); };
var destroy = function() { $r(container); }; var destroy = function() { container.parentNode.removeChild(container); };
var showIndicator = function() { indicator.classList.remove('hidden'); }; var showIndicator = function() { indicator.classList.remove('hidden'); };
var hideIndicator = function() { indicator.classList.add('hidden'); }; var hideIndicator = function() { indicator.classList.add('hidden'); };

View file

@ -1,6 +1,9 @@
#vars self build #vars self build
#include compat.js #include compat.js
#include array.js
#include html.js
#include common.js #include common.js
#include ctx.js #include ctx.js
#include loadoverlay.js #include loadoverlay.js

View file

@ -1,11 +1,10 @@
#include utility.js
#include watcher.js #include watcher.js
var AmiMessageList = function(parent) { var AmiMessageList = function(parent) {
var container = $e({ attrs: { id: 'chatList', className: 'fullWidth' } }), var container = $element('div', { id: 'chatList', className: 'fullWidth' });
isEven = true, var isEven = true;
idPfx = 'sock_msg_', var idPfx = 'sock_msg_';
watchers = new AmiWatcherCollection; var watchers = new AmiWatcherCollection;
parent.appendChild(container); parent.appendChild(container);
watchers.define(['nameInsert', 'delete']); watchers.define(['nameInsert', 'delete']);
@ -29,90 +28,80 @@ var AmiMessageList = function(parent) {
var nameBody = msgInfo.sender.username; var nameBody = msgInfo.sender.username;
if(msgInfo.sender.isBot()) if(msgInfo.sender.isBot())
nameBody = { nameBody = $element(
tag: 'span', 'span',
attrs: { className: 'botName' }, { className: 'botName' },
child: nameBody, nameBody,
}; );
var messageBody = [ var messageBody = [
{ $element(
tag: 'span', 'span',
attrs: { className: 'date' }, { className: 'date' },
child: '(' + msgInfo.created.toLocaleTimeString() + ')', '(' + msgInfo.created.toLocaleTimeString() + ')',
}, ),
' ', ' ',
{ $element('span', {
tag: 'span', style: nameStyle,
attrs: { onclick: function() {
style: nameStyle, watchers.call('nameInsert', msgInfo, [msgInfo]);
onclick: function() {
watchers.call('nameInsert', msgInfo, [msgInfo]);
},
}, },
child: nameBody, }, nameBody),
},
]; ];
if(msgInfo.showColon) if(msgInfo.showColon)
messageBody.push({ messageBody.push($element(
tag: 'span', 'span',
attrs: { className: 'msgColon' }, { className: 'msgColon' },
child: ':', ':',
}); ));
if(msgInfo.isAction) { if(msgInfo.isAction) {
if(msgInfo.bodyText.indexOf("'") !== 0 || (msgInfo.bodyText.match(/\'/g).length % 2) === 0) if(msgInfo.bodyText.indexOf("'") !== 0 || (msgInfo.bodyText.match(/\'/g).length % 2) === 0)
messageBody.push(' '); messageBody.push(' ');
} else { } else {
messageBody.push(' '); messageBody.push(' ');
messageBody.push({ messageBody.push($element(
tag: 'span', 'span',
attrs: { className: 'msgBreak' }, { className: 'msgBreak' },
child: { tag: 'br' }, $element('br'),
}); ));
} }
if(msgInfo.isPM) { if(msgInfo.isPM) {
if(msgInfo.pmTargetName) if(msgInfo.pmTargetName)
messageBody.push({ messageBody.push($element(
tag: 'i', 'i', {},
child: AmiStrings.getMenuString('whisperto', msgInfo.pmTargetName), AmiStrings.getMenuString('whisperto', msgInfo.pmTargetName),
}); ));
else else
messageBody.push({ messageBody.push($element(
tag: 'i', 'i', {},
child: AmiStrings.getMenuString('whisper'), AmiStrings.getMenuString('whisper'),
}); ));
messageBody.push(' '); messageBody.push(' ');
} }
var message = $e({ var message = $element('div', {
attrs: { id: idPfx + msgInfo.id,
id: idPfx + msgInfo.id, className: isEven ? 'rowEven' : 'rowOdd'
className: isEven ? 'rowEven' : 'rowOdd' }, ...messageBody);
},
child: messageBody,
});
let msgBodyTarget = message; let msgBodyTarget = message;
if(msgInfo.isAction) if(msgInfo.isAction)
message.appendChild(msgBodyTarget = $e({ tag: 'i' })); message.appendChild(msgBodyTarget = $element('i'));
msgBodyTarget.insertAdjacentHTML('beforeend', msgInfo.bodyRaw); msgBodyTarget.insertAdjacentHTML('beforeend', msgInfo.bodyRaw);
if(msgInfo.canDelete) if(msgInfo.canDelete)
message.appendChild($e({ message.appendChild($element('a', {
tag: 'a', title: 'Delete this message',
attrs: { className: 'sprite-small sprite-delete',
title: 'Delete this message', style: {
className: 'sprite-small sprite-delete', float: 'right',
style: { margin: '2px 0 0 0',
float: 'right', },
margin: '2px 0 0 0', onclick: function() {
}, watchers.call('delete', msgInfo, [msgInfo]);
onclick: function() {
watchers.call('delete', msgInfo, [msgInfo]);
},
}, },
})); }));
@ -122,11 +111,13 @@ var AmiMessageList = function(parent) {
return message; return message;
}, },
remove: function(msgId) { remove: function(msgId) {
$ri(idPfx + msgId); const elem = $id(idPfx + msgId);
if(elem)
elem.parentNode.removeChild(elem);
reflow(); reflow();
}, },
clear: function() { clear: function() {
$rc(container); $removeChildren(container);
isEven = true; isEven = true;
}, },
reflow: reflow, reflow: reflow,

View file

@ -1,20 +1,15 @@
#include utility.js
var AmiOptionIcons = function(parent) { var AmiOptionIcons = function(parent) {
var container = $e({ attrs: { id: 'optionsContainer' } }), var container = $element('div', { id: 'optionsContainer' });
icons = new Map; var icons = new Map;
parent.appendChild(container); parent.appendChild(container);
var createIcon = function(name, title, icon, onclick, enabled) { var createIcon = function(name, title, icon, onclick, enabled) {
var pub = {}; var pub = {};
var elem = $e({ var elem = $element('a', {
tag: 'a', href: 'javascript:void(0);',
attrs: { title: title,
href: 'javascript:void(0);', className: 'optIcon sprite sprite-' + icon,
title: title, onclick: function(ev) { performClick(ev); },
className: 'optIcon sprite sprite-' + icon,
onclick: function(ev) { performClick(ev); },
},
}); });
var hasState = typeof enabled === 'boolean'; var hasState = typeof enabled === 'boolean';
@ -61,7 +56,7 @@ var AmiOptionIcons = function(parent) {
}, },
clear: function() { clear: function() {
icons.clear(); icons.clear();
$rc(container); $removeChildren(container);
}, },
}; };
}; };

View file

@ -1,5 +1,3 @@
#include utility.js
var AmiReconnecter = function(parent) { var AmiReconnecter = function(parent) {
var handler = new AmiReconnectHandler, var handler = new AmiReconnectHandler,
indicator = new AmiReconnectIndicator(parent, handler); indicator = new AmiReconnectIndicator(parent, handler);
@ -128,47 +126,35 @@ var AmiReconnectHandler = function() {
}; };
var AmiReconnectIndicator = function(parent, handler) { var AmiReconnectIndicator = function(parent, handler) {
var counterTime = $e({ var counterTime = $element('span', { id: 'reconnectCounterTime' }, '0.0');
tag: 'span', var counterBody = $element(
attrs: { 'div', {
id: 'reconnectCounterTime',
},
child: '0.0',
});
var counterBody = $e({
attrs: {
id: 'reconnectCounter', id: 'reconnectCounter',
className: 'hidden', className: 'hidden',
}, },
child: ['Reconnecting in ', counterTime, ' seconds.'], 'Reconnecting in ', counterTime, ' seconds.'
}); );
var connectEllipsis = $e({ var connectEllipsis = $element('span', { id: 'reconnectConnectEllipsis' }, '...');
tag: 'span', var connectBody = $element(
attrs: { 'div',
id: 'reconnectConnectEllipsis', {
},
child: '...',
});
var connectBody = $e({
attrs: {
id: 'reconnectConnect', id: 'reconnectConnect',
className: 'hidden', className: 'hidden',
}, },
child: ['Attempting to reconnect', connectEllipsis], 'Attempting to reconnect', connectEllipsis,
}); );
var body = $e({ var body = $element(
attrs: { 'div',
{
id: 'reconnectIndicator', id: 'reconnectIndicator',
className: 'hidden', className: 'hidden',
}, },
child: [ $element('div', {}, 'WARNING: Connection Problem'),
{ child: 'WARNING: Connection Problem' }, counterBody,
counterBody, connectBody,
connectBody, );
],
});
parent.appendChild(body); parent.appendChild(body);

View file

@ -1,11 +1,10 @@
#include common.js #include common.js
#include utility.js
var AmiServers = function() { var AmiServers = function() {
var servers = futami.get('servers').slice(0), var servers = futami.get('servers').slice(0),
index = 0xFFFF; index = 0xFFFF;
$as(servers); $arrayShuffle(servers);
return { return {
getServer: function(callback) { getServer: function(callback) {

View file

@ -1,5 +1,4 @@
#include cookies.js #include cookies.js
#include utility.js
#include watcher.js #include watcher.js
// really need to replace null with undefined where possible, in mami too // really need to replace null with undefined where possible, in mami too
@ -47,7 +46,7 @@ var AmiSettings = function() {
else AmiCookies.removeCookie(cookieName); else AmiCookies.removeCookie(cookieName);
callWatchers(); callWatchers();
$ari(locked, name); $arrayRemoveValue(locked, name);
}; };
var setValue = function(value) { var setValue = function(value) {
@ -68,7 +67,7 @@ var AmiSettings = function() {
else AmiCookies.setCookie(cookieName, value); else AmiCookies.setCookie(cookieName, value);
callWatchers(); callWatchers();
$ari(locked, name); $arrayRemoveValue(locked, name);
}; };
pub.getName = function() { return name; }; pub.getName = function() { return name; };
@ -113,7 +112,7 @@ var AmiSettings = function() {
else AmiCookies.setCookie(cookieName, value); else AmiCookies.setCookie(cookieName, value);
callWatchers(); callWatchers();
$ari(locked, name); $arrayRemoveValue(locked, name);
}; };
pub.watch = function(watcher) { pub.watch = function(watcher) {

View file

@ -1,4 +1,3 @@
#include utility.js
#include watcher.js #include watcher.js
var AmiSidebars = function(container) { var AmiSidebars = function(container) {
@ -21,14 +20,15 @@ var AmiSidebars = function(container) {
var classes = ['sidebar', 'hidden']; var classes = ['sidebar', 'hidden'];
if(wide) classes.push('widebar'); if(wide) classes.push('widebar');
var titleElem = $e({ attrs: { className: 'top' } }), var titleElem = $element('div', { className: 'top' });
elem = $e({ var elem = $element(
attrs: { 'div',
id: name, {
classList: classes, id: name,
}, classList: classes,
child: [titleElem, body], },
}); titleElem, body,
);
var hide = function() { var hide = function() {
elem.classList.add('hidden'); elem.classList.add('hidden');

View file

@ -1,9 +1,7 @@
#include utility.js
var AmiChannelsSidebar = function() { var AmiChannelsSidebar = function() {
var sbName = 'chanList', var sbName = 'chanList';
body = $e(), var body = $element('div');
activeChannel = undefined; var activeChannel = undefined;
var setTitle; var setTitle;
var rowEven = false; var rowEven = false;
@ -23,16 +21,14 @@ var AmiChannelsSidebar = function() {
return str; return str;
}; };
var nameElem = $e({ var nameElem = $element(
attrs: { style: { display: 'black' } }, 'div',
child: toString(), { style: { display: 'black' } },
}), toString(),
elem = $e({ );
attrs: { var elem = $element('div', {
className: (rowEven ? 'rowEven' : 'rowOdd'), className: (rowEven ? 'rowEven' : 'rowOdd'),
}, }, nameElem);
child: [nameElem],
});
rowEven = !rowEven; rowEven = !rowEven;

View file

@ -1,10 +1,9 @@
#include strings.js #include strings.js
#include utility.js
var AmiHelpSidebar = function() { var AmiHelpSidebar = function() {
var sbName = 'helpList', var sbName = 'helpList';
list = $e({ tag: 'table' }), var list = $element('table');
body = $e({ child: list }); var body = $element('div', {}, list);
var setTitle; var setTitle;
@ -35,7 +34,7 @@ var AmiHelpSidebar = function() {
title.textContent = helpInfo.title + ':'; title.textContent = helpInfo.title + ':';
var example = row.insertCell(1); var example = row.insertCell(1);
example.appendChild($e({ tag: 'i', child: helpInfo.format })); example.appendChild($element('i', {}, helpInfo.format));
rowEven = !rowEven; rowEven = !rowEven;
}); });

View file

@ -1,8 +1,6 @@
#include utility.js
var AmiSettingsSidebar = function() { var AmiSettingsSidebar = function() {
var sbName = 'settingsList', var sbName = 'settingsList';
body = $e({ child: { tag: 'table' } }); var body = $element('div', {}, $element('table'));
var setTitle; var setTitle;

View file

@ -1,42 +1,26 @@
#include utility.js
var AmiUploadsSidebar = function() { var AmiUploadsSidebar = function() {
var sbName = 'uploadList', var sbName = 'uploadList';
body = $e({ var body = $element(
child: [ 'div', {},
{ $element(
attrs: { 'div', { className: 'eepromForm' },
className: 'eepromForm', $element('input', {
}, id: 'uploadSelector',
child: [ type: 'file',
{ class: 'hidden',
tag: 'input', multiple: true,
attrs: { }),
id: 'uploadSelector', $element('input', {
type: 'file', id: 'uploadButton',
class: 'hidden', type: 'button',
multiple: true, value: 'Select file',
}, }),
}, ),
{ $element('table', {
tag: 'input', id: 'uploadHistory',
attrs: { class: 'eepromHistory',
id: 'uploadButton', }),
type: 'button', );
value: 'Select file',
},
},
],
},
{
tag: 'table',
attrs: {
id: 'uploadHistory',
class: 'eepromHistory',
},
},
],
});
var setTitle; var setTitle;

View file

@ -1,8 +1,6 @@
#include utility.js
var AmiUsersSidebar = function() { var AmiUsersSidebar = function() {
var sbName = 'userList', var sbName = 'userList';
body = $e(); var body = $element('div');
var setTitle; var setTitle;

View file

@ -1,5 +1,3 @@
#include utility.js
var AmiSound = function() { var AmiSound = function() {
var playing = []; var playing = [];
var isMuted = false, var isMuted = false,
@ -74,7 +72,7 @@ var AmiSound = function() {
}; };
(function() { (function() {
var elem = $e('audio'); var elem = $element('audio');
for(var name in formats) { for(var name in formats) {
var format = formats[name], var format = formats[name],
support = elem.canPlayType(format); support = elem.canPlayType(format);
@ -128,10 +126,7 @@ var AmiSound = function() {
if(rate === undefined) rate = 1.0; if(rate === undefined) rate = 1.0;
else rate = Math.min(4.0, Math.max(0.25, rate)); else rate = Math.min(4.0, Math.max(0.25, rate));
var audio = $e({ var audio = $element('audio', { src: url });
tag: 'audio',
attrs: { src: url },
});
audio.volume = Math.max(0.0, Math.min(1.0, volume * localVolume)); audio.volume = Math.max(0.0, Math.min(1.0, volume * localVolume));
audio.muted = isMuted; audio.muted = isMuted;
audio.preservesPitch = false; audio.preservesPitch = false;
@ -139,7 +134,7 @@ var AmiSound = function() {
playing.push(audio); playing.push(audio);
audio.addEventListener('ended', function() { audio.addEventListener('ended', function() {
$ari(playing, audio); $arrayRemoveValue(playing, audio);
}); });
audio.addEventListener('loadeddata', function() { audio.addEventListener('loadeddata', function() {

View file

@ -1,7 +1,5 @@
#include utility.js
var AmiStatusIndicator = function(parent) { var AmiStatusIndicator = function(parent) {
var icon = $e({ attrs: { id: 'statusIconContainer' } }); var icon = $element('div', { id: 'statusIconContainer' });
parent.appendChild(icon); parent.appendChild(icon);
var setState = function(colour, text) { var setState = function(colour, text) {

View file

@ -1,43 +1,32 @@
#include utility.js
#include watcher.js #include watcher.js
var AmiSubmitBox = function(parent) { var AmiSubmitBox = function(parent) {
var pub = {}, var pub = {};
watcher = new AmiWatcher, var watcher = new AmiWatcher;
maxLengthValue = 0, var maxLengthValue = 0;
click = function(ev) { var click = function(ev) {
watcher.call(pub, [ev]); watcher.call(pub, [ev]);
}; };
var button = $e({ var button = $element('input', {
tag: 'input', type: 'button',
attrs: { value: 'Send',
type: 'button', id: 'sendmsg',
value: 'Send', onclick: function(ev) { click(ev); },
id: 'sendmsg', });
onclick: function(ev) { click(ev); }, var curLength = $element('span', {}, '0');
}, var maxLength = $element('span', {}, maxLengthValue.toString());
}), var container = $element(
curLength = $e({ 'div',
tag: 'span', { id: 'submitButtonContainer' },
child: '0', $element(
}), 'span',
maxLength = $e({ { id: 'messageLengthCounter' },
tag: 'span', curLength, '/', maxLength
child: maxLengthValue.toString(), ),
}), ' ',
container = $e({ button,
attrs: { id: 'submitButtonContainer' }, );
child: [
{
tag: 'span',
attrs: { id: 'messageLengthCounter' },
child: [curLength, '/', maxLength],
},
' ',
button,
],
});
parent.appendChild(container); parent.appendChild(container);

View file

@ -1,8 +1,7 @@
#include common.js #include common.js
#include utility.js
var AmiChatTitle = function(parent, title) { var AmiChatTitle = function(parent, title) {
var elem = $e({ attrs: { id: 'chatTitle' }, child: title}); var elem = $element('div', { id: 'chatTitle' }, title);
parent.appendChild(elem); parent.appendChild(elem);
return { return {
@ -13,8 +12,8 @@ var AmiChatTitle = function(parent, title) {
}; };
var AmiWindowTitle = function(title) { var AmiWindowTitle = function(title) {
var baseTitle = '', var baseTitle = '';
activeFlash = undefined; var activeFlash = undefined;
var setTitle = function(text) { var setTitle = function(text) {
document.title = text; document.title = text;

View file

@ -5,7 +5,6 @@
#include ts_utils.js #include ts_utils.js
#include title.js #include title.js
#include strings.js #include strings.js
#include utility.js
var UI = (function () { var UI = (function () {
function UI() {} function UI() {}
@ -252,7 +251,7 @@ var UI = (function () {
msgDiv.id = "sock_user_" + u.id; msgDiv.id = "sock_user_" + u.id;
msgDiv.innerHTML = "<a style='color:" + u.color + "; display: block;' href='javascript:UI.ToggleUserMenu(" + u.id + ");'>" + u.username + "</a>"; msgDiv.innerHTML = "<a style='color:" + u.color + "; display: block;' href='javascript:UI.ToggleUserMenu(" + u.id + ");'>" + u.username + "</a>";
msgDiv.appendChild(UI.GenerateContextMenu(u)); msgDiv.appendChild(UI.GenerateContextMenu(u));
$i('userList').getElementsByClassName('body')[0].appendChild(msgDiv); $id('userList').getElementsByClassName('body')[0].appendChild(msgDiv);
this.rowEven[1] = !this.rowEven[1]; this.rowEven[1] = !this.rowEven[1];
} }
if (addToContext) { if (addToContext) {
@ -281,54 +280,53 @@ var UI = (function () {
}; };
UI.SwitchChannel = function(name) { UI.SwitchChannel = function(name) {
var channels = $c('js-sidebar-channel'); var channels = $queryAll('.js-sidebar-channel');
for(var i = 0; i < channels.length; ++i) { for(var i = 0; i < channels.length; ++i) {
var channel = channels[i]; var channel = channels[i];
if(channel.style.fontWeight === 'bold') if(channel.style.fontWeight === 'bold')
channel.style.fontWeight = null; channel.style.fontWeight = null;
} }
$i('sock_chan_' + name).style.fontWeight = 'bold'; $id('sock_chan_' + name).style.fontWeight = 'bold';
}; };
UI.AddChannel = function (name, ispwd, istemp, iscurr) { UI.AddChannel = function (name, ispwd, istemp, iscurr) {
var displayName = UI.MakeChannelDisplayName(name, ispwd, istemp); var displayName = UI.MakeChannelDisplayName(name, ispwd, istemp);
var html = $e({ var html = $element(
attrs: { 'div',
{
classList: ['js-sidebar-channel', this.rowEven[2] ? "rowEven" : "rowOdd"], classList: ['js-sidebar-channel', this.rowEven[2] ? "rowEven" : "rowOdd"],
id: 'sock_chan_' + name, id: 'sock_chan_' + name,
}, },
child: { $element('a', {
tag: 'a', style: { display: 'block' },
child: displayName, href: 'javascript:void(0);',
attrs: { onclick: function() {
style: { display: 'block' }, var cmd = '/join ' + name;
href: 'javascript:void(0);', if(ispwd && !UserContext.self.canModerate())
onclick: function() { cmd += ' ' + prompt(AmiStrings.getMenuString('chanpwd', [name]));
var cmd = '/join ' + name; ami.sockChat.sendMessage(cmd);
if(ispwd && !UserContext.self.canModerate())
cmd += ' ' + prompt(AmiStrings.getMenuString('chanpwd', [name]));
ami.sockChat.sendMessage(cmd);
},
}, },
} }, displayName),
}); );
if(iscurr) if(iscurr)
html.style.fontWeight = 'bold'; html.style.fontWeight = 'bold';
$i('chanList').getElementsByClassName('body')[0].appendChild(html); $id('chanList').getElementsByClassName('body')[0].appendChild(html);
this.rowEven[2] = !this.rowEven[2]; this.rowEven[2] = !this.rowEven[2];
}; };
UI.ModifyChannel = function (oldname, newname, ispwd, istemp) { UI.ModifyChannel = function (oldname, newname, ispwd, istemp) {
var displayName = UI.MakeChannelDisplayName(newname, ispwd, istemp); var displayName = UI.MakeChannelDisplayName(newname, ispwd, istemp);
$i('sock_chat_' + oldname).children[0].textContent = displayName; $id('sock_chat_' + oldname).children[0].textContent = displayName;
}; };
UI.RemoveChannel = function (name) { UI.RemoveChannel = function (name) {
$ri('sock_chat_' + oldname); const elem = $id('sock_chat_' + oldname);
if(elem)
elem.parentNode.removeChild(elem);
}; };
UI.RemoveUser = function (id) { UI.RemoveUser = function (id) {
@ -337,14 +335,14 @@ var UI = (function () {
}; };
UI.RedrawChannelList = function() { UI.RedrawChannelList = function() {
$i('chanList').getElementsByClassName('top')[0].innerHTML = AmiStrings.getMenuString('chans'); $id('chanList').getElementsByClassName('top')[0].innerHTML = AmiStrings.getMenuString('chans');
$i('chanList').getElementsByClassName('body')[0].innerHTML = ''; $id('chanList').getElementsByClassName('body')[0].innerHTML = '';
this.rowEven[2] = false; this.rowEven[2] = false;
}; };
UI.RedrawUserList = function () { UI.RedrawUserList = function () {
$i('userList').getElementsByClassName('top')[0].innerHTML = AmiStrings.getMenuString('online'); $id('userList').getElementsByClassName('top')[0].innerHTML = AmiStrings.getMenuString('online');
$i('userList').getElementsByClassName('body')[0].innerHTML = ''; $id('userList').getElementsByClassName('body')[0].innerHTML = '';
this.rowEven[1] = false; this.rowEven[1] = false;
if(UserContext.self !== undefined) if(UserContext.self !== undefined)
this.AddUser(UserContext.self, false); this.AddUser(UserContext.self, false);

View file

@ -1,7 +1,6 @@
#include ts_20_ui.js #include ts_20_ui.js
#include ts_10_user.js #include ts_10_user.js
#include z_eepromv1.js #include z_eepromv1.js
#include utility.js
#include sidebars/channelssb.js #include sidebars/channelssb.js
#include sidebars/helpsb.js #include sidebars/helpsb.js
#include sidebars/settingssb.js #include sidebars/settingssb.js
@ -17,14 +16,10 @@ var Chat = (function () {
type: "select", type: "select",
load: function(input) { load: function(input) {
ami.styles.forEach(function(style) { ami.styles.forEach(function(style) {
input.appendChild($e({ input.appendChild($element('option', {
tag: 'option', value: style.getName(),
child: style.getTitle(), className: style.getOptionClass(),
attrs: { }, style.getTitle()));
value: style.getName(),
className: style.getOptionClass(),
},
}));
if(style.isDefault() && !ami.settings.has('style')) if(style.isDefault() && !ami.settings.has('style'))
ami.settings.set('style', style.getName()); ami.settings.set('style', style.getName());
@ -475,7 +470,7 @@ var Chat = (function () {
ami.settings.set('soundPack', sounds.packs[0].name); ami.settings.set('soundPack', sounds.packs[0].name);
} }
var soundPackSetting = $i('chatSetting-spack'); var soundPackSetting = $id('chatSetting-spack');
if(soundPackSetting) { if(soundPackSetting) {
while(soundPackSetting.options.length > 0) while(soundPackSetting.options.length > 0)
soundPackSetting.options.remove(0); soundPackSetting.options.remove(0);

View file

@ -1,163 +0,0 @@
window.$i = document.getElementById.bind(document);
window.$c = document.getElementsByClassName.bind(document);
window.$q = document.querySelector.bind(document);
window.$qa = document.querySelectorAll.bind(document);
window.$t = document.createTextNode.bind(document);
window.$r = function(element) {
if(element && element.parentNode)
element.parentNode.removeChild(element);
};
window.$ri = function(name) {
$r($i(name));
};
window.$ib = function(ref, elem) {
ref.parentNode.insertBefore(elem, ref);
};
window.$rc = function(element) {
while(element.lastChild)
element.removeChild(element.lastChild);
};
window.$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;
}
var elem = document.createElement(info.tag || 'div');
if(info.attrs) {
var attrs = info.attrs,
keys = Object.keys(attrs);
for(var key in attrs) {
var 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';
var addFunc = null,
prop = elem[key];
if(prop instanceof Array)
addFunc = prop.push.bind(prop);
else if(prop instanceof DOMTokenList)
addFunc = prop.add.bind(prop);
if(addFunc !== null) {
for(var j = 0; j < attr.length; ++j)
addFunc(attr[j]);
} else {
if(key === 'classList')
key = 'class';
elem.setAttribute(key, attr.toString());
}
} else {
for(var 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) {
var children = info.child;
if(!Array.isArray(children))
children = [children];
for(var i in children) {
var child = children[i];
switch(typeof child) {
case 'string':
elem.appendChild($t(child));
break;
case 'object':
if(child instanceof Element)
elem.appendChild(child);
else if(child.getElement) {
var 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;
};
window.$er = (type, props, ...children) => $e({ tag: type, attrs: props, child: children });
window.$ar = function(array, index) {
array.splice(index, 1);
};
window.$ari = function(array, item) {
var index;
while(array.length > 0 && (index = array.indexOf(item)) >= 0)
$ar(array, index);
};
window.$arf = function(array, predicate) {
var index;
while(array.length > 0 && (index = array.findIndex(predicate)) >= 0)
$ar(array, index);
};
window.$as = function(array) {
if(array.length < 2)
return;
for(var i = array.length - 1; i > 0; --i) {
var j = Math.floor(Math.random() * (i + 1));
var tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
};

View file

@ -1,5 +1,3 @@
#include utility.js
var AmiWatcher = function() { var AmiWatcher = function() {
var watchers = []; var watchers = [];
@ -26,7 +24,7 @@ var AmiWatcher = function() {
} }
}, },
unwatch: function(watcher) { unwatch: function(watcher) {
$ari(watchers, watcher); $arrayRemoveValue(watchers, watcher);
}, },
call: function(thisArg, args) { call: function(thisArg, args) {
if(!Array.isArray(args)) { if(!Array.isArray(args)) {

View file

@ -1,6 +1,5 @@
#include common.js #include common.js
#include eeprom.js #include eeprom.js
#include utility.js
var eepromAppl = 1, var eepromAppl = 1,
eepromSupportImageEmbed = true, eepromSupportImageEmbed = true,
@ -10,13 +9,13 @@ var eepromInitialise = function(auth) {
window.eepromHistory = {}; window.eepromHistory = {};
window.eepromClient = new AmiEEPROM(futami.get('eeprom2'), auth.getHttpAuth); window.eepromClient = new AmiEEPROM(futami.get('eeprom2'), auth.getHttpAuth);
window.eepromUploadsTable = $i('uploadHistory'); window.eepromUploadsTable = $id('uploadHistory');
$i('uploadSelector').onchange = function() { $id('uploadSelector').onchange = function() {
for(var i = 0; i < this.files.length; ++i) for(var i = 0; i < this.files.length; ++i)
eepromFileUpload(this.files[i]); eepromFileUpload(this.files[i]);
}; };
$i('uploadButton').onclick = function() { $id('uploadButton').onclick = function() {
$i('uploadSelector').click(); $id('uploadSelector').click();
}; };
ami.chat.inputBox.watch('paste', function(ev) { ami.chat.inputBox.watch('paste', function(ev) {