Skip to content

Instantly share code, notes, and snippets.

@marionebl
Last active February 21, 2020 08:16
Show Gist options
  • Save marionebl/bf86cb48e2bf399569165e89c0949289 to your computer and use it in GitHub Desktop.
Save marionebl/bf86cb48e2bf399569165e89c0949289 to your computer and use it in GitHub Desktop.
Typeahead
Typeahead
Inactive*
Initial*
type trigger -> Empty
Completed
tick -> Initial
Active
Empty*
type Esc -> Initial
type Return -> Initial
type char -> List Options
type whitespace -> Initial
delete -> Initial
select -> Initial
List Options
type Esc -> Initial
type Return -> Has Matches?
type char -> List Options
type whitespace -> Has Matches?
delete -> Is Empty?
select -> Inactive
pick -> Completed
Queries
Has Matches?
has match -> Completed
no match -> Initial
Is Empty?
is empty -> Empty
is not empty -> List Options
window.picked = false;
window.query = '';
window.results = [];
const haystack = 'aabbbbcccccddeeffgggghhhhhhhhiiiijjkkkklllllllmmmmnopqrstuvwxyz'.split('');
function getType(trigger) {
switch(trigger.trim()) {
case ':':
return 'Emoji';
case '/':
return 'QuickInsert';
case '@':
return 'Mention';
default:
return trigger;
}
}
function isTrigger(charCode) {
// [':', '@', '/']
return [59, 50, 191].includes(charCode);
}
function renderResults(model) {
return $('ul', ...window.results.map(item=> $('li', [item.type, item.result].join(': '))))
}
function renderInput(model) {
const name = model.active_states[0].name;
return $("div",
$("input", {
'data-id': 'input',
onBlur: () => {
setTimeout(() => !window.picked ? model.emit('select') : undefined);
},
onKeyDown: e => {
if (e.keyCode === 8) {
return model.emit('delete');
}
if (isTrigger(e.keyCode)) {
return model.emit('type trigger')
}
if (e.keyCode === 32) {
return model.emit('type whitespace');
}
if (e.keyCode === 27) {
e.preventDefault();
return model.emit('type Esc');
}
if (e.keyCode === 13) {
e.preventDefault();
return model.emit('type Return');
}
return model.emit('type char');
},
onChange(e) {
window.query = e.target.value.length > 0 ? e.target.value.slice(1) : '';
window.trigger = e.target.value.length > 0 ? e.target.value[0] : '';
}
})
);
}
function renderOptions(model) {
const name = model.active_states[0].name;
if (name !== 'List Options' && name !== 'Has Matches?') {
return null;
}
const matches = haystack.filter(item => item === window.query);
return $('ul', ...matches.map(item=> $('li', { onClick() {
window.picked = true;
model.emit('pick')
} }, item)))
}
function render(model){
const name = model.active_states[0].name;
if (name === 'Has Matches?') {
const matchedItems = haystack.filter(item => item === window.query.trim());
setTimeout(() => {
model.emit(matchedItems.length > 0 ? 'has match' : 'no match');
}, 1000);
}
if (name === 'Is Empty?') {
setTimeout(() => {
model.emit(window.query.length > 1 ? 'is not empty' : 'is empty');
}, 1000);
}
if (name === 'Completed') {
const matchedItems = haystack.filter(item => item === window.query.trim());
const result = matchedItems[0];
setTimeout(() => {
if (result) {
results.push({ type: getType(window.trigger), result });
}
model.emit('tick');
}, 1000)
}
if (name === 'Initial') {
const input = document.querySelector('[data-id=input]');
input ? input.value = '' : undefined;
window.query = '';
window.trigger = '';
window.picked = false;
}
return $("div", {
style: {
fontFamily: 'sans-serif',
padding: '12px'
}
},
$("h4", "Input"), renderInput(model),
$("h4", "Options"), renderOptions(model),
$("h4", "Results"), renderResults(model));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment