148 lines
4.8 KiB
JavaScript
148 lines
4.8 KiB
JavaScript
#include args.js
|
|
|
|
const MamiEmotePicker = function(args) {
|
|
args = MamiArgs('args', args, define => {
|
|
define('getEmotes').type('function').done();
|
|
define('setKeepOpenOnPick').type('function').done();
|
|
define('onPick').type('function').done();
|
|
define('onClose').type('function').done();
|
|
});
|
|
|
|
let emotes;
|
|
|
|
let listElem, searchElem, keepOpenToggleElem;
|
|
const html = <div class="emopick" style="z-index: 9001;" onfocusout={ev => {
|
|
if(!keepOpenToggleElem.checked && !html.contains(ev.relatedTarget))
|
|
close();
|
|
}} tabindex="0">
|
|
<div class="emopick-list" tabindex="0">
|
|
{listElem = <div class="emopick-list-scroll" tabindex="0"/>}
|
|
</div>
|
|
<div class="emopick-search" tabindex="0">
|
|
{searchElem = <input class="emopick-search-input" type="search" placeholder="Filter..." tabindex="0" />}
|
|
</div>
|
|
<div class="emopick-actions" tabindex="0">
|
|
<label class="emopick-action-toggle" tabindex="0">
|
|
{keepOpenToggleElem = <input type="checkbox" class="emopick-action-toggle-box" onchange={() => {
|
|
if(args.setKeepOpenOnPick !== undefined)
|
|
args.setKeepOpenOnPick(keepOpenToggleElem.checked);
|
|
}} />}
|
|
<span class="emopick-action-toggle-label">Keep picker open</span>
|
|
</label>
|
|
<button class="emopick-action-button" type="button" onclick={() => { close(); }}>Close</button>
|
|
</div>
|
|
</div>;
|
|
|
|
const buildList = () => {
|
|
$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={() => {
|
|
args.onPick(emote);
|
|
if(!keepOpenToggleElem.checked)
|
|
close();
|
|
}}>
|
|
<img src={emote.url} alt={`:${emote.strings[0]}:`} />
|
|
</button>);
|
|
};
|
|
|
|
searchElem.addEventListener('keyup', ev => {
|
|
const elems = Array.from(listElem.children);
|
|
|
|
if(ev.key === 'Escape') {
|
|
close();
|
|
return;
|
|
}
|
|
|
|
if(ev.key === 'Enter' || ev.key === 'NumpadEnter') {
|
|
for(const elem of elems)
|
|
if(!elem.classList.contains('hidden')) {
|
|
elem.click();
|
|
break;
|
|
}
|
|
|
|
searchElem.focus();
|
|
return;
|
|
}
|
|
|
|
for(const elem of elems) {
|
|
const filter = searchElem.value.trim();
|
|
let hidden = false;
|
|
if(filter !== '') {
|
|
hidden = true;
|
|
const strings = elem.dataset.strings.split(' ');
|
|
for(const string of strings)
|
|
if(string.includes(filter)) {
|
|
hidden = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
elem.classList.toggle('hidden', hidden);
|
|
}
|
|
});
|
|
|
|
let promiseResolve;
|
|
const close = () => {
|
|
if(promiseResolve !== undefined) {
|
|
promiseResolve();
|
|
promiseResolve = undefined;
|
|
}
|
|
|
|
if(args.onClose !== undefined)
|
|
args.onClose();
|
|
|
|
html.classList.add('hidden');
|
|
};
|
|
|
|
const setPosition = pos => {
|
|
if(typeof pos !== 'object')
|
|
throw 'pos must be an object';
|
|
|
|
for(const attr of ['top', 'left', 'right', 'bottom'])
|
|
html.style[attr] = typeof pos[attr] === 'number' ? `${pos[attr]}px` : null;
|
|
};
|
|
|
|
return {
|
|
get element() { return html; },
|
|
get keepOpenOnPick() { return keepOpenToggleElem.checked; },
|
|
set keepOpenOnPick(value) { keepOpenToggleElem.checked = value; },
|
|
setPosition: setPosition,
|
|
close: close,
|
|
dialog: pos => {
|
|
emotes = args.getEmotes();
|
|
buildList();
|
|
|
|
html.classList.remove('hidden');
|
|
|
|
if(pos instanceof MouseEvent)
|
|
pos = pos.target;
|
|
if(pos instanceof Element)
|
|
pos = pos.getBoundingClientRect();
|
|
if(pos instanceof DOMRect) {
|
|
const bbb = pos;
|
|
pos = {};
|
|
|
|
const mbb = html.getBoundingClientRect();
|
|
const pbb = html.parentNode.getBoundingClientRect();
|
|
|
|
pos.right = pbb.width - bbb.left;
|
|
pos.bottom = pbb.height - bbb.top;
|
|
|
|
if(pos.right + mbb.width > pbb.width)
|
|
pos.right = 0;
|
|
else if(pos.right > mbb.width)
|
|
pos.right -= mbb.width;
|
|
else
|
|
pos.right -= bbb.width;
|
|
}
|
|
|
|
if(pos !== undefined)
|
|
setPosition(pos);
|
|
|
|
searchElem.focus();
|
|
|
|
return new Promise(resolve => { promiseResolve = resolve; });
|
|
},
|
|
};
|
|
};
|