Rewrote emoticon picker.
This commit is contained in:
parent
5dc701cca4
commit
81c06d4289
13 changed files with 314 additions and 96 deletions
|
@ -1,17 +1,13 @@
|
||||||
.colpick {
|
.colpick {
|
||||||
accent-color: var(--colpick-colour, #000);
|
accent-color: var(--colpick-colour, #000);
|
||||||
border-radius: 5px;
|
|
||||||
border: 2px solid var(--colpick-colour, #000);
|
border: 2px solid var(--colpick-colour, #000);
|
||||||
padding: 3px;
|
padding: 2px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
background-color: #444;
|
background-color: #444;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
box-shadow: 0 3px 10px #000;
|
box-shadow: 0 3px 10px #000;
|
||||||
font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 20px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.colpick-tabbed {
|
.colpick-tabbed {
|
||||||
|
@ -20,14 +16,12 @@
|
||||||
}
|
}
|
||||||
.colpick-tabbed-container {
|
.colpick-tabbed-container {
|
||||||
border: 2px solid var(--colpick-colour, #000);
|
border: 2px solid var(--colpick-colour, #000);
|
||||||
border-radius: 5px 5px 0 0;
|
|
||||||
height: 234px;
|
height: 234px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
scrollbar-width: thin;
|
scrollbar-width: thin;
|
||||||
}
|
}
|
||||||
.colpick-tabbed-list {
|
.colpick-tabbed-list {
|
||||||
background-color: #222;
|
background-color: #222;
|
||||||
border-radius: 0 0 5px 5px;
|
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +65,6 @@
|
||||||
display: block;
|
display: block;
|
||||||
width: 60px;
|
width: 60px;
|
||||||
height: 60px;
|
height: 60px;
|
||||||
border-radius: 5px;
|
|
||||||
background: var(--colpick-colour, #000);
|
background: var(--colpick-colour, #000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +111,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.colpick-buttons-button {
|
.colpick-buttons-button {
|
||||||
border-radius: 5px;
|
border-radius: 0;
|
||||||
background: #222;
|
background: #222;
|
||||||
border-width: 0;
|
border-width: 0;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
@ -156,7 +149,7 @@
|
||||||
border: 0;
|
border: 0;
|
||||||
width: 42px;
|
width: 42px;
|
||||||
height: 42px;
|
height: 42px;
|
||||||
border-radius: 5px;
|
border-radius: 0;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
95
src/mami.css/emopick.css
Normal file
95
src/mami.css/emopick.css
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
.emopick {
|
||||||
|
padding: 2px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: absolute;
|
||||||
|
background-color: #444;
|
||||||
|
color: #fff;
|
||||||
|
box-shadow: 0 3px 10px #000;
|
||||||
|
max-width: 334px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emopick-emote {
|
||||||
|
background: transparent;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background .1s;
|
||||||
|
}
|
||||||
|
.emopick-emote:hover,
|
||||||
|
.emopick-emote:focus {
|
||||||
|
background: #fff4;
|
||||||
|
}
|
||||||
|
.emopick-emote:active {
|
||||||
|
background: #0004;
|
||||||
|
}
|
||||||
|
.emopick-emote img {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
display: block;
|
||||||
|
image-rendering: crisp-edges;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emopick-list {
|
||||||
|
max-height: 250px;
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
scrollbar-width: thin;
|
||||||
|
background: #333;
|
||||||
|
}
|
||||||
|
.emopick-list-scroll {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 2px;
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emopick-search {
|
||||||
|
display: flex;
|
||||||
|
margin: 2px 0;
|
||||||
|
}
|
||||||
|
.emopick-search-input {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 1;
|
||||||
|
padding: 4px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
color: inherit;
|
||||||
|
background: #333;
|
||||||
|
font-size: inherit;
|
||||||
|
font-family: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emopick-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emopick-action-toggle {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.emopick-action-toggle-box {
|
||||||
|
margin: 0 2px;
|
||||||
|
}
|
||||||
|
.emopick-action-toggle-label {
|
||||||
|
margin: 0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emopick-action-button {
|
||||||
|
display: block;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
background: #555;
|
||||||
|
color: #fff;
|
||||||
|
font-family: inherit;
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
|
.emopick-action-button:focus {
|
||||||
|
box-shadow: 0 0 0 1px #000, inset 0 0 0 1px #fff;
|
||||||
|
}
|
|
@ -89,6 +89,7 @@ a:hover {
|
||||||
@include youare.css;
|
@include youare.css;
|
||||||
|
|
||||||
@include colpick.css;
|
@include colpick.css;
|
||||||
|
@include emopick.css;
|
||||||
|
|
||||||
@include themes/archaic.css;
|
@include themes/archaic.css;
|
||||||
@include themes/blue.css;
|
@include themes/blue.css;
|
||||||
|
|
|
@ -42,7 +42,7 @@ const MamiColourPicker = function(options) {
|
||||||
let tabsElem, tabsContainer, tabsList;
|
let tabsElem, tabsContainer, tabsList;
|
||||||
let values, buttons;
|
let values, buttons;
|
||||||
|
|
||||||
const html = <form class="colpick" style={{ zIndex: '9001' }} onsubmit={ev => { ev.preventDefault(); runResolve(); return false; }}>
|
const html = <form class="colpick" style="z-index: 9001;" onsubmit={ev => { ev.preventDefault(); runResolve(); return false; }}>
|
||||||
{tabsElem = <div class="colpick-tabbed">
|
{tabsElem = <div class="colpick-tabbed">
|
||||||
{tabsContainer = <div class="colpick-tabbed-container"/>}
|
{tabsContainer = <div class="colpick-tabbed-container"/>}
|
||||||
{tabsList = <div class="colpick-tabbed-list"/>}
|
{tabsList = <div class="colpick-tabbed-list"/>}
|
||||||
|
@ -58,7 +58,7 @@ const MamiColourPicker = function(options) {
|
||||||
</div>
|
</div>
|
||||||
</form>;
|
</form>;
|
||||||
|
|
||||||
const close = () => html.parentNode.removeChild(html);
|
const close = () => html.classList.add('hidden');
|
||||||
|
|
||||||
const setColour = (raw, mask) => {
|
const setColour = (raw, mask) => {
|
||||||
raw = typeof raw === 'number' ? (parseInt(raw) & 0xFFFFFF) : 0;
|
raw = typeof raw === 'number' ? (parseInt(raw) & 0xFFFFFF) : 0;
|
||||||
|
@ -79,15 +79,15 @@ const MamiColourPicker = function(options) {
|
||||||
if(typeof pos !== 'object')
|
if(typeof pos !== 'object')
|
||||||
throw 'pos must be an object';
|
throw 'pos must be an object';
|
||||||
|
|
||||||
html.style.top = 'y' in pos && pos.y >= 0 ? `${pos.y}px` : null;
|
html.style.bottom = 'y' in pos && pos.y >= 0 ? `${pos.y}px` : null;
|
||||||
html.style.left = 'x' in pos && pos.x >= 0 ? `${pos.x}px` : '';
|
html.style.left = 'x' in pos && pos.x >= 0 ? `${pos.x}px` : null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const tabs = new MamiTabsControl({
|
const tabs = new MamiTabsControl({
|
||||||
onAdd: ctx => {
|
onAdd: ctx => {
|
||||||
const name = ctx.info.name,
|
const name = ctx.info.name;
|
||||||
containerName = `colpick-tab-${name}-container`,
|
const containerName = `colpick-tab-${name}-container`;
|
||||||
buttonName = `colpick-tab-${name}-button`;
|
const buttonName = `colpick-tab-${name}-button`;
|
||||||
|
|
||||||
needsColour.push(ctx.info);
|
needsColour.push(ctx.info);
|
||||||
ctx.info.onChange(setColour);
|
ctx.info.onChange(setColour);
|
||||||
|
@ -107,11 +107,11 @@ const MamiColourPicker = function(options) {
|
||||||
onSwitch: ctx => {
|
onSwitch: ctx => {
|
||||||
if(ctx.from !== undefined) {
|
if(ctx.from !== undefined) {
|
||||||
ctx.from.elem.classList.toggle('colpick-tab-container-inactive', true);
|
ctx.from.elem.classList.toggle('colpick-tab-container-inactive', true);
|
||||||
$q(`.colpick-tab-${ctx.from.info.name}-button`).classList.toggle('colpick-tab-button-active', false);
|
tabsList.querySelector(`.colpick-tab-${ctx.from.info.name}-button`).classList.toggle('colpick-tab-button-active', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.elem.classList.toggle('colpick-tab-container-inactive', false);
|
ctx.elem.classList.toggle('colpick-tab-container-inactive', false);
|
||||||
$q(`.colpick-tab-${ctx.info.name}-button`).classList.toggle('colpick-tab-button-active', true);
|
tabsList.querySelector(`.colpick-tab-${ctx.info.name}-button`).classList.toggle('colpick-tab-button-active', true);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -168,6 +168,20 @@ const MamiColourPicker = function(options) {
|
||||||
setPosition: setPosition,
|
setPosition: setPosition,
|
||||||
close: close,
|
close: close,
|
||||||
dialog: pos => {
|
dialog: pos => {
|
||||||
|
html.classList.remove('hidden');
|
||||||
|
|
||||||
|
if(pos instanceof MouseEvent) {
|
||||||
|
const mbb = html.getBoundingClientRect();
|
||||||
|
const pbb = html.parentNode.getBoundingClientRect();
|
||||||
|
let x = pos.clientX;
|
||||||
|
let y = pbb.height - pos.clientY;
|
||||||
|
|
||||||
|
if(x > (pbb.width - mbb.width))
|
||||||
|
x = 10;
|
||||||
|
|
||||||
|
pos = { x: x, y: y };
|
||||||
|
}
|
||||||
|
|
||||||
if(pos !== undefined)
|
if(pos !== undefined)
|
||||||
setPosition(pos);
|
setPosition(pos);
|
||||||
|
|
||||||
|
@ -176,22 +190,5 @@ const MamiColourPicker = function(options) {
|
||||||
promiseReject = reject;
|
promiseReject = reject;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
suggestPosition: mouseEvent => {
|
|
||||||
let x = 10, y = 10;
|
|
||||||
|
|
||||||
if(html.parentNode.clientWidth > 340) {
|
|
||||||
x = mouseEvent.clientX;
|
|
||||||
y = mouseEvent.clientY;
|
|
||||||
|
|
||||||
const bb = html.getBoundingClientRect();
|
|
||||||
|
|
||||||
if(y > bb.height + 20)
|
|
||||||
y -= bb.height;
|
|
||||||
if(x > html.parentNode.clientWidth - bb.width - 20)
|
|
||||||
x -= bb.width;
|
|
||||||
}
|
|
||||||
|
|
||||||
return { x: x, y: y };
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -37,6 +37,14 @@ const MamiEmotes = (function() {
|
||||||
if(emote.minRank <= minRank)
|
if(emote.minRank <= minRank)
|
||||||
callback(emote);
|
callback(emote);
|
||||||
},
|
},
|
||||||
|
all: minRank => {
|
||||||
|
const items = [];
|
||||||
|
for(const emote of emotes)
|
||||||
|
if(emote.minRank <= minRank)
|
||||||
|
items.push(emote);
|
||||||
|
|
||||||
|
return items;
|
||||||
|
},
|
||||||
findByName: function(minRank, name, returnString) {
|
findByName: function(minRank, name, returnString) {
|
||||||
const found = [];
|
const found = [];
|
||||||
for(const emote of emotes)
|
for(const emote of emotes)
|
||||||
|
|
139
src/mami.js/emotes/picker.jsx
Normal file
139
src/mami.js/emotes/picker.jsx
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
#include args.js
|
||||||
|
#include utility.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 = () => {
|
||||||
|
$rc(listElem);
|
||||||
|
|
||||||
|
for(const emote of emotes)
|
||||||
|
listElem.appendChild(<button class="emopick-emote" type="button" 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';
|
||||||
|
|
||||||
|
html.style.bottom = 'y' in pos && pos.y >= 0 ? `${pos.y}px` : null;
|
||||||
|
html.style.right = 'x' in pos && pos.x >= 0 ? `${pos.x}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) {
|
||||||
|
const mbb = html.getBoundingClientRect();
|
||||||
|
const pbb = html.parentNode.getBoundingClientRect();
|
||||||
|
let x = pbb.width - pos.clientX;
|
||||||
|
let y = pbb.height - pos.clientY;
|
||||||
|
|
||||||
|
if(x > mbb.width)
|
||||||
|
x -= mbb.width;
|
||||||
|
|
||||||
|
pos = { x: x, y: y };
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pos !== undefined)
|
||||||
|
setPosition(pos);
|
||||||
|
|
||||||
|
searchElem.focus();
|
||||||
|
|
||||||
|
return new Promise(resolve => { promiseResolve = resolve; });
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
|
@ -23,6 +23,7 @@ window.Umi = { UI: {} };
|
||||||
#include controls/ping.jsx
|
#include controls/ping.jsx
|
||||||
#include controls/views.js
|
#include controls/views.js
|
||||||
#include eeprom/eeprom.js
|
#include eeprom/eeprom.js
|
||||||
|
#include emotes/picker.jsx
|
||||||
#include notices/baka.jsx
|
#include notices/baka.jsx
|
||||||
#include notices/youare.jsx
|
#include notices/youare.jsx
|
||||||
#include settings/backup.js
|
#include settings/backup.js
|
||||||
|
@ -150,6 +151,7 @@ const MamiInit = async args => {
|
||||||
settings.define('dbgAnimDurationMulti').default(1).min(0).max(10).create();
|
settings.define('dbgAnimDurationMulti').default(1).min(0).max(10).create();
|
||||||
settings.define('newLineOnEnter').default(false).create();
|
settings.define('newLineOnEnter').default(false).create();
|
||||||
settings.define('showMarkupSelector').type(['always', 'focus', 'never']).default('focus').create();
|
settings.define('showMarkupSelector').type(['always', 'focus', 'never']).default('focus').create();
|
||||||
|
settings.define('keepEmotePickerOpen').default(true).create();
|
||||||
|
|
||||||
const noNotifSupport = !('Notification' in window);
|
const noNotifSupport = !('Notification' in window);
|
||||||
settings.define('enableNotifications').default(false).immutable(noNotifSupport).critical().create();
|
settings.define('enableNotifications').default(false).immutable(noNotifSupport).critical().create();
|
||||||
|
@ -229,13 +231,8 @@ const MamiInit = async args => {
|
||||||
MamiEmotes.loadLegacy(emotes);
|
MamiEmotes.loadLegacy(emotes);
|
||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
console.error('Failed to load emoticons.', ex);
|
console.error('Failed to load emoticons.', ex);
|
||||||
} finally {
|
|
||||||
// this is currently called in the sock chat handlers
|
|
||||||
// does a permissions check which it can't do at this point
|
|
||||||
//Umi.UI.Emoticons.Init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const onHashChange = () => {
|
const onHashChange = () => {
|
||||||
if(location.hash === '#reset') {
|
if(location.hash === '#reset') {
|
||||||
settings.clear(true);
|
settings.clear(true);
|
||||||
|
@ -461,6 +458,7 @@ const MamiInit = async args => {
|
||||||
category.setting('eepromAutoInsert').title('Auto-insert uploads').done();
|
category.setting('eepromAutoInsert').title('Auto-insert uploads').done();
|
||||||
category.setting('autoEmbedV1').title('Auto-embed media').done();
|
category.setting('autoEmbedV1').title('Auto-embed media').done();
|
||||||
category.setting('autoEmbedPlay').title('Auto-play embedded media').done();
|
category.setting('autoEmbedPlay').title('Auto-play embedded media').done();
|
||||||
|
category.setting('keepEmotePickerOpen').title('Keep emoticon picker open').done();
|
||||||
category.setting('newLineOnEnter').title('Swap Enter and Shift+Enter behaviour').done();
|
category.setting('newLineOnEnter').title('Swap Enter and Shift+Enter behaviour').done();
|
||||||
category.setting('showMarkupSelector').title('Show markup buttons').type('select').options(() => {
|
category.setting('showMarkupSelector').title('Show markup buttons').type('select').options(() => {
|
||||||
return {
|
return {
|
||||||
|
@ -558,7 +556,6 @@ const MamiInit = async args => {
|
||||||
MamiEmotes.clear();
|
MamiEmotes.clear();
|
||||||
MamiEmotes.loadLegacy(emotes);
|
MamiEmotes.loadLegacy(emotes);
|
||||||
} finally {
|
} finally {
|
||||||
Umi.UI.Emoticons.Init();
|
|
||||||
button.textContent = textOrig;
|
button.textContent = textOrig;
|
||||||
button.disabled = false;
|
button.disabled = false;
|
||||||
}
|
}
|
||||||
|
@ -669,7 +666,34 @@ const MamiInit = async args => {
|
||||||
sidebar.createAction(sbActPing);
|
sidebar.createAction(sbActPing);
|
||||||
|
|
||||||
Umi.UI.InputMenus.Add('markup');
|
Umi.UI.InputMenus.Add('markup');
|
||||||
Umi.UI.InputMenus.Add('emotes', 'Emoticons');
|
Umi.UI.Markup.SetPickerTarget(layout.getElement());
|
||||||
|
|
||||||
|
let emotePicker, emotePickerVisible = false;
|
||||||
|
Umi.UI.InputMenus.AddButton('emotes', 'Emoticons', ev => {
|
||||||
|
if(emotePicker === undefined) {
|
||||||
|
emotePicker = new MamiEmotePicker({
|
||||||
|
onClose: () => { emotePickerVisible = false; },
|
||||||
|
onPick: emote => {
|
||||||
|
const emoteStr = `:${emote.strings[0]}:`;
|
||||||
|
Umi.UI.View.EnterAtCursor(emoteStr);
|
||||||
|
Umi.UI.View.SetPosition(Umi.UI.View.GetPosition() + emoteStr.length);
|
||||||
|
Umi.UI.View.SetPosition(Umi.UI.View.GetPosition(), true);
|
||||||
|
Umi.UI.View.Focus();
|
||||||
|
},
|
||||||
|
getEmotes: () => MamiEmotes.all(Umi.User.getCurrentUser().perms.rank),
|
||||||
|
setKeepOpenOnPick: value => { settings.set('keepEmotePickerOpen', value); },
|
||||||
|
});
|
||||||
|
layout.getElement().appendChild(emotePicker.element);
|
||||||
|
settings.watch('keepEmotePickerOpen', ev => { emotePicker.keepOpenOnPick = ev.detail.value; });
|
||||||
|
}
|
||||||
|
|
||||||
|
if(emotePickerVisible) {
|
||||||
|
emotePicker.close();
|
||||||
|
} else {
|
||||||
|
emotePickerVisible = true;
|
||||||
|
emotePicker.dialog(ev);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
settings.watch('showMarkupSelector', ev => {
|
settings.watch('showMarkupSelector', ev => {
|
||||||
Umi.UI.InputMenus.Toggle('markup', ev.detail.value === 'always');
|
Umi.UI.InputMenus.Toggle('markup', ev.detail.value === 'always');
|
||||||
|
|
|
@ -104,7 +104,6 @@ const MamiSockChatHandlers = function(
|
||||||
sbUsers.createEntry(ev.detail.user);
|
sbUsers.createEntry(ev.detail.user);
|
||||||
|
|
||||||
Umi.UI.Markup.Reset();
|
Umi.UI.Markup.Reset();
|
||||||
Umi.UI.Emoticons.Init();
|
|
||||||
Umi.Parsing.Init();
|
Umi.Parsing.Init();
|
||||||
|
|
||||||
if(ctx.views.count > 1)
|
if(ctx.views.count > 1)
|
||||||
|
|
|
@ -1,41 +1,12 @@
|
||||||
#include emotes.js
|
#include emotes.js
|
||||||
#include utility.js
|
#include utility.js
|
||||||
#include ui/input-menus.js
|
|
||||||
#include ui/view.js
|
|
||||||
|
|
||||||
Umi.UI.Emoticons = (function() {
|
Umi.UI.Emoticons = (function() {
|
||||||
return {
|
return {
|
||||||
Init: function() {
|
Parse: function(element, author) {
|
||||||
const menu = Umi.UI.InputMenus.Get('emotes');
|
|
||||||
menu.innerHTML = '';
|
|
||||||
|
|
||||||
MamiEmotes.forEach(Umi.User.getCurrentUser().perms.rank, function(emote) {
|
|
||||||
menu.appendChild($e({
|
|
||||||
tag: 'button',
|
|
||||||
attrs: {
|
|
||||||
type: 'button',
|
|
||||||
className: 'emoticon emoticon--button',
|
|
||||||
title: emote.strings[0],
|
|
||||||
dataset: {
|
|
||||||
umiEmoticon: ':' + emote.strings[0] + ':',
|
|
||||||
},
|
|
||||||
onclick: 'Umi.UI.Emoticons.Insert(this)',
|
|
||||||
},
|
|
||||||
child: {
|
|
||||||
tag: 'img',
|
|
||||||
attrs: {
|
|
||||||
className: 'emoticon',
|
|
||||||
src: emote.url,
|
|
||||||
alt: emote.strings[0],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
},
|
|
||||||
Parse: function(element, message) {
|
|
||||||
let inner = element.innerHTML;
|
let inner = element.innerHTML;
|
||||||
|
|
||||||
MamiEmotes.forEach(message?.author?.perms?.rank ?? 0, function(emote) {
|
MamiEmotes.forEach(author?.perms?.rank ?? 0, function(emote) {
|
||||||
const image = $e({
|
const image = $e({
|
||||||
tag: 'img',
|
tag: 'img',
|
||||||
attrs: {
|
attrs: {
|
||||||
|
@ -54,12 +25,5 @@ Umi.UI.Emoticons = (function() {
|
||||||
|
|
||||||
element.innerHTML = inner;
|
element.innerHTML = inner;
|
||||||
},
|
},
|
||||||
Insert: function(sender) {
|
|
||||||
const emoticon = sender.getAttribute('data-umi-emoticon');
|
|
||||||
Umi.UI.View.EnterAtCursor(sender.getAttribute('data-umi-emoticon'));
|
|
||||||
Umi.UI.View.SetPosition(Umi.UI.View.GetPosition() + emoticon.length);
|
|
||||||
Umi.UI.View.SetPosition(Umi.UI.View.GetPosition(), true);
|
|
||||||
Umi.UI.View.Focus();
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -23,15 +23,11 @@ Umi.UI.Hooks = (function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
msgForm.addEventListener('focusin', ev => {
|
msgForm.addEventListener('focusin', ev => {
|
||||||
console.info(ev);
|
|
||||||
|
|
||||||
if(mami.settings.get('showMarkupSelector') === 'focus' && Umi.UI.InputMenus.Current() === '')
|
if(mami.settings.get('showMarkupSelector') === 'focus' && Umi.UI.InputMenus.Current() === '')
|
||||||
Umi.UI.InputMenus.Toggle('markup', true);
|
Umi.UI.InputMenus.Toggle('markup', true);
|
||||||
});
|
});
|
||||||
msgForm.addEventListener('focusout', ev => {
|
msgForm.addEventListener('focusout', ev => {
|
||||||
console.info(ev);
|
if(msgForm.contains(ev.relatedTarget))
|
||||||
|
|
||||||
if(ev.relatedTarget instanceof Element && msgForm.contains(ev.relatedTarget))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(mami.settings.get('showMarkupSelector') === 'focus' && Umi.UI.InputMenus.Current() === 'markup')
|
if(mami.settings.get('showMarkupSelector') === 'focus' && Umi.UI.InputMenus.Current() === 'markup')
|
||||||
|
|
|
@ -55,6 +55,9 @@ Umi.UI.InputMenus = (function() {
|
||||||
Current: () => current,
|
Current: () => current,
|
||||||
Toggle: toggle,
|
Toggle: toggle,
|
||||||
Add: function(baseId, title, beforeButtonId) {
|
Add: function(baseId, title, beforeButtonId) {
|
||||||
|
if(baseId !== 'markup')
|
||||||
|
throw 'only baseId "markup" may be added';
|
||||||
|
|
||||||
if(ids.includes(baseId))
|
if(ids.includes(baseId))
|
||||||
return;
|
return;
|
||||||
ids.push(baseId);
|
ids.push(baseId);
|
||||||
|
|
|
@ -17,21 +17,19 @@ Umi.UI.Markup = (function() {
|
||||||
Umi.UI.View.Focus();
|
Umi.UI.View.Focus();
|
||||||
};
|
};
|
||||||
|
|
||||||
const pickerTarget = document.body;
|
let pickerTarget = document.body;
|
||||||
let picker, pickerVisible = false;
|
let picker, pickerVisible = false;
|
||||||
|
|
||||||
const insert = function(ev) {
|
const insert = function(ev) {
|
||||||
if(this.dataset.umiTagName === 'color' && !pickerVisible) {
|
if(this.dataset.umiTagName === 'color' && !pickerVisible) {
|
||||||
pickerVisible = true;
|
pickerVisible = true;
|
||||||
|
|
||||||
if(picker === undefined)
|
if(picker === undefined) {
|
||||||
picker = new MamiColourPicker({
|
picker = new MamiColourPicker({ presets: futami.get('colours') });
|
||||||
presets: futami.get('colours'),
|
pickerTarget.appendChild(picker.element);
|
||||||
});
|
}
|
||||||
|
|
||||||
pickerTarget.appendChild(picker.element);
|
picker.dialog(ev)
|
||||||
|
|
||||||
picker.dialog(picker.suggestPosition(ev))
|
|
||||||
.then(colour => insertRaw(`[color=${MamiColour.hex(colour)}]`, '[/color]'))
|
.then(colour => insertRaw(`[color=${MamiColour.hex(colour)}]`, '[/color]'))
|
||||||
.finally(() => pickerVisible = false);
|
.finally(() => pickerVisible = false);
|
||||||
} else
|
} else
|
||||||
|
@ -42,6 +40,7 @@ Umi.UI.Markup = (function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
SetPickerTarget: target => { pickerTarget = target; },
|
||||||
Add: function(name, text, beforeCursor, afterCursor) {
|
Add: function(name, text, beforeCursor, afterCursor) {
|
||||||
Umi.UI.InputMenus.Get('markup').appendChild($e({
|
Umi.UI.InputMenus.Get('markup').appendChild($e({
|
||||||
tag: 'button',
|
tag: 'button',
|
||||||
|
|
|
@ -240,7 +240,7 @@ Umi.UI.Messages = (function() {
|
||||||
eText.innerText = msgText;
|
eText.innerText = msgText;
|
||||||
|
|
||||||
if(!skipTextParsing) {
|
if(!skipTextParsing) {
|
||||||
Umi.UI.Emoticons.Parse(eText, msg);
|
Umi.UI.Emoticons.Parse(eText, msgAuthor);
|
||||||
Umi.Parsing.Parse(eText, msg);
|
Umi.Parsing.Parse(eText, msg);
|
||||||
|
|
||||||
const textSplit = eText.innerText.split(' ');
|
const textSplit = eText.innerText.split(' ');
|
||||||
|
|
Loading…
Reference in a new issue