mirror of
https://github.com/Icinga/icinga-php-library.git
synced 2025-07-02 03:14:30 +02:00
751 lines
27 KiB
JavaScript
751 lines
27 KiB
JavaScript
define(["../notjQuery"], function ($) {
|
|
|
|
"use strict";
|
|
|
|
class Completer {
|
|
constructor(input, instrumented = false) {
|
|
this.input = input;
|
|
this.instrumented = instrumented;
|
|
this.selectionStartInput = null;
|
|
this.selectionActive = false;
|
|
this.mouseSelectionActive = false;
|
|
this.nextSuggestion = null;
|
|
this.activeSuggestion = null;
|
|
this.suggestionKiller = null;
|
|
this.completedInput = null;
|
|
this.completedValue = null;
|
|
this.completedData = null;
|
|
this._termSuggestions = null;
|
|
}
|
|
|
|
get termSuggestions() {
|
|
if (this._termSuggestions === null) {
|
|
this._termSuggestions = document.querySelector(this.input.dataset.termSuggestions);
|
|
}
|
|
|
|
return this._termSuggestions;
|
|
}
|
|
|
|
bind(to = null) {
|
|
// Form submissions
|
|
$(this.input.form).on('submit', this.onSubmit, this);
|
|
|
|
// User interactions
|
|
$(this.termSuggestions).on('focusout', '[type="button"]', this.onFocusOut, this);
|
|
$(this.termSuggestions).on('click', '[type="button"]', this.onSuggestionClick, this);
|
|
$(this.termSuggestions).on('keydown', '[type="button"]', this.onSuggestionKeyDown, this);
|
|
|
|
if (this.selectionEnabled()) {
|
|
$(this.termSuggestions).on('keyup', '[type="button"]', this.onSuggestionKeyUp, this);
|
|
$(this.termSuggestions).on('mouseover', '[type="button"]', this.onSuggestionMouseOver, this);
|
|
$(this.termSuggestions).on('mousedown', '[type="button"]', this.onSuggestionMouseDown, this);
|
|
$(this.termSuggestions).on('mouseup', '[type="button"]', this.onSuggestionsMouseUp, this);
|
|
$(this.termSuggestions).on('mouseleave', this.onSuggestionsMouseLeave, this);
|
|
}
|
|
|
|
if (this.instrumented) {
|
|
if (to !== null) {
|
|
$(to).on('focusout', 'input[type="text"]', this.onFocusOut, this);
|
|
$(to).on('keydown', 'input[type="text"]', this.onKeyDown, this);
|
|
$(to).on('complete', 'input[type="text"]', this.onComplete, this);
|
|
}
|
|
|
|
$(this.input).on('complete', this.onComplete, this);
|
|
} else {
|
|
$(this.input).on('input', this.onInput, this);
|
|
}
|
|
|
|
$(this.input).on('focusout', this.onFocusOut, this);
|
|
$(this.input).on('keydown', this.onKeyDown, this);
|
|
|
|
return this;
|
|
}
|
|
|
|
refresh(input, bindTo = null) {
|
|
if (input === this.input) {
|
|
// If the DOM node is still the same, nothing has changed
|
|
return;
|
|
}
|
|
|
|
this._termSuggestions = null;
|
|
this.abort();
|
|
|
|
this.input = input;
|
|
this.bind(bindTo);
|
|
}
|
|
|
|
reset() {
|
|
this.abort();
|
|
this.hideSuggestions();
|
|
}
|
|
|
|
destroy() {
|
|
this._termSuggestions = null;
|
|
this.input = null;
|
|
}
|
|
|
|
renderSuggestions(html) {
|
|
let template = document.createElement('template');
|
|
template.innerHTML = html;
|
|
|
|
return template.content;
|
|
}
|
|
|
|
showSuggestions(suggestions, input) {
|
|
this.termSuggestions.innerHTML = '';
|
|
this.termSuggestions.appendChild(suggestions);
|
|
this.termSuggestions.style.display = '';
|
|
|
|
let containingBlock = this.termSuggestions.offsetParent || document.body;
|
|
let containingBlockRect = containingBlock.getBoundingClientRect();
|
|
let inputRect = input.getBoundingClientRect();
|
|
let inputPosX = inputRect.left - containingBlockRect.left;
|
|
let inputPosY = inputRect.bottom - containingBlockRect.top;
|
|
let suggestionWidth = this.termSuggestions.offsetWidth;
|
|
|
|
let maxAvailableHeight = document.body.clientHeight - inputRect.bottom;
|
|
let localMarginBottom = window.getComputedStyle(this.termSuggestions).marginBottom;
|
|
|
|
this.termSuggestions.style.top = `${ inputPosY }px`;
|
|
this.termSuggestions.style.maxHeight = `calc(${maxAvailableHeight}px - ${localMarginBottom})`;
|
|
if (inputPosX + suggestionWidth > containingBlockRect.right - containingBlockRect.left) {
|
|
this.termSuggestions.style.left =
|
|
`${ containingBlockRect.right - containingBlockRect.left - suggestionWidth }px`;
|
|
} else {
|
|
this.termSuggestions.style.left = `${ inputPosX }px`;
|
|
}
|
|
}
|
|
|
|
hasSuggestions() {
|
|
return this.termSuggestions.childNodes.length > 0;
|
|
}
|
|
|
|
hideSuggestions() {
|
|
if (this.nextSuggestion !== null || this.activeSuggestion !== null) {
|
|
return;
|
|
}
|
|
|
|
if (this.suggestionKiller !== null) {
|
|
// onFocusOut initiates this timer in order to hide the suggestions if the user
|
|
// doesn't navigate them. Since it does this by checking after a short interval
|
|
// if the focus is inside the suggestions, the interval has to be long enough to
|
|
// have a chance to detect the focus. `focusout` runs before `blur` and `focus`,
|
|
// so this may lead to a race condition which is addressed by the timeout. Though,
|
|
// to not close the newly opened suggestions of the next input the timer has to
|
|
// be cancelled here since it's purpose is already fulfilled.
|
|
clearTimeout(this.suggestionKiller);
|
|
this.suggestionKiller = null;
|
|
}
|
|
|
|
this.termSuggestions.style.display = 'none';
|
|
this.termSuggestions.innerHTML = '';
|
|
|
|
this.completedInput = null;
|
|
this.completedValue = null;
|
|
this.completedData = null;
|
|
|
|
this.endSelection();
|
|
}
|
|
|
|
prepareCompletionData(input, data = null) {
|
|
if (data === null) {
|
|
data = { term: { ...input.dataset } };
|
|
data.term.label = input.value;
|
|
}
|
|
|
|
let value = data.term.label;
|
|
data.term.search = value;
|
|
data.term.label = this.addWildcards(value);
|
|
|
|
if (input.parentElement instanceof HTMLFieldSetElement) {
|
|
for (let element of input.parentElement.elements) {
|
|
if (element !== input
|
|
&& element.name !== input.name + '-search'
|
|
&& (element.name.substr(-7) === '-search'
|
|
|| typeof input.form[element.name + '-search'] === 'undefined')
|
|
) {
|
|
// Make sure we'll use a key that the server can understand..
|
|
let dataName = element.name;
|
|
if (dataName.substr(-7) === '-search') {
|
|
dataName = dataName.substr(0, dataName.length - 7);
|
|
}
|
|
if (dataName.substr(0, input.parentElement.name.length) === input.parentElement.name) {
|
|
dataName = dataName.substr(input.parentElement.name.length);
|
|
}
|
|
|
|
if (! dataName in data || element.value) {
|
|
data[dataName] = element.value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return [value, data];
|
|
}
|
|
|
|
addWildcards(value) {
|
|
if (! value) {
|
|
return '*';
|
|
}
|
|
|
|
if (value.slice(0, 1) !== '*' && value.slice(-1) !== '*') {
|
|
return '*' + value + '*';
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
abort() {
|
|
if (this.activeSuggestion !== null) {
|
|
this.activeSuggestion.abort();
|
|
this.activeSuggestion = null;
|
|
}
|
|
|
|
if (this.nextSuggestion !== null) {
|
|
clearTimeout(this.nextSuggestion);
|
|
this.nextSuggestion = null;
|
|
}
|
|
}
|
|
|
|
requestCompletion(input, data, trigger = 'user') {
|
|
this.abort();
|
|
|
|
this.nextSuggestion = setTimeout(() => {
|
|
let req = new XMLHttpRequest();
|
|
req.open('POST', this.input.dataset.suggestUrl, true);
|
|
req.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
|
req.setRequestHeader('Content-Type', 'application/json');
|
|
|
|
if (typeof icinga !== 'undefined') {
|
|
let windowId = icinga.ui.getWindowId();
|
|
let containerId = icinga.ui.getUniqueContainerId(this.termSuggestions);
|
|
if (containerId) {
|
|
req.setRequestHeader('X-Icinga-WindowId', windowId + '_' + containerId);
|
|
} else {
|
|
req.setRequestHeader('X-Icinga-WindowId', windowId);
|
|
}
|
|
}
|
|
|
|
req.addEventListener('loadend', () => {
|
|
if (req.readyState > 0) {
|
|
if (req.responseText) {
|
|
let suggestions = this.renderSuggestions(req.responseText);
|
|
if (trigger === 'script') {
|
|
// If the suggestions are to be displayed due to a scripted event,
|
|
// show them only if the completed input is still focused..
|
|
if (document.activeElement === input) {
|
|
this.showSuggestions(suggestions, input);
|
|
}
|
|
} else {
|
|
this.showSuggestions(suggestions, input);
|
|
}
|
|
} else {
|
|
this.hideSuggestions();
|
|
}
|
|
}
|
|
|
|
this.activeSuggestion = null;
|
|
this.nextSuggestion = null;
|
|
});
|
|
|
|
req.send(JSON.stringify(data));
|
|
|
|
this.activeSuggestion = req;
|
|
}, 200);
|
|
}
|
|
|
|
suggest(input, value, data = {}) {
|
|
if (this.instrumented) {
|
|
if (! Object.keys(data).length) {
|
|
data = value;
|
|
}
|
|
|
|
$(input).trigger('suggestion', data);
|
|
} else {
|
|
input.value = value;
|
|
}
|
|
}
|
|
|
|
complete(input, value, data) {
|
|
$(input).focus({ scripted: true });
|
|
|
|
if (this.instrumented) {
|
|
if (! Object.keys(data).length) {
|
|
data = value;
|
|
}
|
|
|
|
$(input).trigger('completion', data);
|
|
} else {
|
|
input.value = value;
|
|
|
|
for (let name in data) {
|
|
let dataElement = input.form[input.name + '-' + name];
|
|
if (typeof dataElement !== 'undefined') {
|
|
if (dataElement instanceof RadioNodeList) {
|
|
dataElement = dataElement[dataElement.length - 1];
|
|
}
|
|
|
|
dataElement.value = data[name];
|
|
} else if (name === 'title') {
|
|
input.title = data[name];
|
|
}
|
|
}
|
|
}
|
|
|
|
this.hideSuggestions();
|
|
}
|
|
|
|
moveToSuggestion(backwards = false, stopAtEdge = false) {
|
|
let focused = this.termSuggestions.querySelector('[type="button"]:focus');
|
|
let inputs = Array.from(this.termSuggestions.querySelectorAll('[type="button"]'));
|
|
|
|
let input;
|
|
if (focused !== null) {
|
|
let sibling = inputs[backwards ? inputs.indexOf(focused) - 1 : inputs.indexOf(focused) + 1];
|
|
if (sibling) {
|
|
input = sibling;
|
|
} else if (stopAtEdge) {
|
|
return null;
|
|
} else {
|
|
input = this.completedInput;
|
|
}
|
|
} else {
|
|
input = inputs[backwards ? inputs.length - 1 : 0];
|
|
}
|
|
|
|
$(input).focus();
|
|
|
|
if (! stopAtEdge && this.completedValue !== null) {
|
|
if (input === this.completedInput) {
|
|
this.suggest(this.completedInput, this.completedValue);
|
|
} else {
|
|
this.suggest(this.completedInput, input.value, { ...input.dataset });
|
|
}
|
|
}
|
|
|
|
return input;
|
|
}
|
|
|
|
isBeingCompleted(input, activeElement = null) {
|
|
if (activeElement === null) {
|
|
activeElement = document.activeElement;
|
|
}
|
|
|
|
return input === this.completedInput && this.hasSuggestions()
|
|
&& (! activeElement || input === activeElement || this.termSuggestions.contains(activeElement));
|
|
}
|
|
|
|
selectionEnabled() {
|
|
return this.instrumented && 'withMultiCompletion' in this.input.dataset;
|
|
}
|
|
|
|
selectionAllowed() {
|
|
return this.completedInput === this.input && this.selectionEnabled();
|
|
}
|
|
|
|
startSelection(input) {
|
|
this.selectionActive = true;
|
|
this.selectionStartInput = input;
|
|
}
|
|
|
|
isSelectionActive() {
|
|
return this.selectionActive;
|
|
}
|
|
|
|
endSelection() {
|
|
this.selectionStartInput = null;
|
|
this.selectionActive = false;
|
|
this.mouseSelectionActive = false;
|
|
}
|
|
|
|
selectSuggestion(input) {
|
|
input.classList.add('selected');
|
|
}
|
|
|
|
deselectSuggestion(input) {
|
|
input.classList.remove('selected');
|
|
}
|
|
|
|
toggleSelection(input) {
|
|
input.classList.toggle('selected');
|
|
let selected = input.classList.contains('selected');
|
|
if (selected && ! this.isSelectionActive()) {
|
|
this.startSelection(input);
|
|
$(input).focus();
|
|
}
|
|
|
|
if (! selected && input === this.selectionStartInput) {
|
|
this.selectionStartInput = this.termSuggestions.querySelector('[type="button"].selected');
|
|
if (! this.selectionStartInput) {
|
|
this.endSelection();
|
|
$(this.input).focus();
|
|
} else {
|
|
$(this.selectionStartInput).focus();
|
|
}
|
|
}
|
|
|
|
return selected;
|
|
}
|
|
|
|
isSelectedSuggestion(input) {
|
|
return input.classList.contains('selected');
|
|
}
|
|
|
|
getSelectedSuggestions() {
|
|
return this.termSuggestions.querySelectorAll('[type="button"].selected');
|
|
}
|
|
|
|
clearSelection() {
|
|
if (! this.isSelectionActive()) {
|
|
return;
|
|
}
|
|
|
|
for (const selectedInput of this.getSelectedSuggestions()) {
|
|
this.deselectSuggestion(selectedInput);
|
|
}
|
|
|
|
this.endSelection();
|
|
}
|
|
|
|
handleKeySelection(input, newInput) {
|
|
if (! this.isSelectionActive()) {
|
|
this.startSelection(input);
|
|
this.selectSuggestion(input);
|
|
this.selectSuggestion(newInput);
|
|
this.suggest(this.completedInput, '');
|
|
} else if (this.isSelectedSuggestion(newInput)) {
|
|
this.deselectSuggestion(input);
|
|
} else {
|
|
this.selectSuggestion(newInput);
|
|
}
|
|
}
|
|
|
|
startMouseSelection(input) {
|
|
this.startSelection(input);
|
|
this.mouseSelectionActive = true;
|
|
}
|
|
|
|
isMouseSelectionActive() {
|
|
return this.mouseSelectionActive;
|
|
}
|
|
|
|
finishMouseSelection() {
|
|
if (! this.mouseSelectionActive) {
|
|
return;
|
|
}
|
|
|
|
this.mouseSelectionActive = false;
|
|
this.selectSuggestion(this.selectionStartInput);
|
|
|
|
let selectionFound = false;
|
|
let selectionCandidates = [];
|
|
for (const input of this.termSuggestions.querySelectorAll('[type="button"]')) {
|
|
if (input.classList.contains('selected')) {
|
|
if (selectionFound) {
|
|
for (const candidate of selectionCandidates) {
|
|
this.selectSuggestion(candidate);
|
|
}
|
|
|
|
selectionCandidates = [];
|
|
} else {
|
|
selectionFound = true;
|
|
}
|
|
} else if (selectionFound) {
|
|
selectionCandidates.push(input);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Event listeners
|
|
*/
|
|
|
|
onSubmit(event) {
|
|
if (! event.detail || ! event.detail.submittedBy) {
|
|
// Reset all states, the user is about to navigate away
|
|
this.reset();
|
|
}
|
|
}
|
|
|
|
onFocusOut(event) {
|
|
if (this.completedInput === null) {
|
|
// If there are multiple instances of Completer bound to the same suggestion container
|
|
// all of them try to handle the event. Though, only one of them is responsible and
|
|
// that's the one which has a completed input set.
|
|
return;
|
|
}
|
|
|
|
let input = event.target;
|
|
let completedInput = this.completedInput;
|
|
this.suggestionKiller = setTimeout(() => {
|
|
if (completedInput !== this.completedInput) {
|
|
// Don't hide another input's suggestions
|
|
} else if (document.activeElement !== completedInput
|
|
&& ! this.termSuggestions.contains(document.activeElement)
|
|
) {
|
|
// Hide the suggestions if the user doesn't navigate them
|
|
if (input !== completedInput) {
|
|
// Restore input if a suggestion lost focus
|
|
this.suggest(completedInput, this.completedValue);
|
|
}
|
|
|
|
this.hideSuggestions();
|
|
}
|
|
}, 250);
|
|
}
|
|
|
|
onSuggestionMouseDown(event) {
|
|
if (! this.selectionAllowed()) {
|
|
return;
|
|
}
|
|
|
|
if (event.ctrlKey || event.metaKey) {
|
|
// onSuggestionClick only toggles the suggestion's selection and should
|
|
// be the only one who decides which other suggestion should be focused
|
|
event.preventDefault();
|
|
} else {
|
|
this.clearSelection();
|
|
this.startMouseSelection(event.target);
|
|
}
|
|
}
|
|
|
|
onSuggestionsMouseUp(event) {
|
|
if (! event.ctrlKey && ! event.metaKey) {
|
|
this.finishMouseSelection();
|
|
}
|
|
}
|
|
|
|
onSuggestionsMouseLeave(_) {
|
|
this.finishMouseSelection();
|
|
}
|
|
|
|
onSuggestionMouseOver(event) {
|
|
if (this.isMouseSelectionActive()) {
|
|
this.selectSuggestion(event.target);
|
|
}
|
|
}
|
|
|
|
onSuggestionKeyUp(event) {
|
|
if (this.completedInput === null) {
|
|
return;
|
|
}
|
|
|
|
let input = event.target;
|
|
|
|
switch (event.key) {
|
|
case 'Shift':
|
|
if (this.isSelectionActive()) {
|
|
event.preventDefault();
|
|
|
|
if (input === this.selectionStartInput && this.getSelectedSuggestions().length === 1) {
|
|
this.deselectSuggestion(input);
|
|
this.endSelection();
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
onSuggestionKeyDown(event) {
|
|
if (this.completedInput === null) {
|
|
return;
|
|
}
|
|
|
|
let newInput;
|
|
let input = event.target;
|
|
let allowSelection = event.shiftKey && this.selectionAllowed();
|
|
|
|
switch (event.key) {
|
|
case 'Escape':
|
|
$(this.completedInput).focus({ scripted: true });
|
|
this.suggest(this.completedInput, this.completedValue);
|
|
this.clearSelection();
|
|
break;
|
|
case 'Tab':
|
|
event.preventDefault();
|
|
this.moveToSuggestion(event.shiftKey);
|
|
break;
|
|
case 'ArrowLeft':
|
|
case 'ArrowUp':
|
|
event.preventDefault();
|
|
|
|
newInput = this.moveToSuggestion(true, allowSelection);
|
|
if (allowSelection) {
|
|
if (newInput !== null) {
|
|
this.handleKeySelection(input, newInput);
|
|
}
|
|
} else {
|
|
this.clearSelection();
|
|
}
|
|
|
|
break;
|
|
case 'ArrowRight':
|
|
case 'ArrowDown':
|
|
event.preventDefault();
|
|
|
|
newInput = this.moveToSuggestion(false, allowSelection);
|
|
if (allowSelection) {
|
|
if (newInput !== null) {
|
|
this.handleKeySelection(input, newInput);
|
|
}
|
|
} else {
|
|
this.clearSelection();
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
onSuggestionClick(event) {
|
|
if (this.completedInput === null) {
|
|
return;
|
|
}
|
|
|
|
if (event.ctrlKey || event.metaKey) {
|
|
if (this.selectionAllowed()) {
|
|
this.toggleSelection(event.target);
|
|
event.preventDefault();
|
|
}
|
|
} else if (this.isSelectionActive() && this.isSelectedSuggestion(event.target)) {
|
|
let terms = [];
|
|
for (const suggestion of this.getSelectedSuggestions()) {
|
|
terms.push({ ...suggestion.dataset });
|
|
}
|
|
|
|
this.complete(this.completedInput, null, { type: 'terms', terms: terms });
|
|
} else {
|
|
let input = event.currentTarget;
|
|
|
|
this.complete(this.completedInput, input.value, { ...input.dataset });
|
|
}
|
|
}
|
|
|
|
onKeyDown(event) {
|
|
let suggestions;
|
|
|
|
switch (event.key) {
|
|
case ' ':
|
|
if (this.instrumented) {
|
|
break;
|
|
}
|
|
|
|
let input = event.target;
|
|
|
|
if (! input.value) {
|
|
if (input.minLength <= 0) {
|
|
let [value, data] = this.prepareCompletionData(input);
|
|
this.completedInput = input;
|
|
this.completedValue = value;
|
|
this.completedData = data;
|
|
this.requestCompletion(input, data);
|
|
}
|
|
|
|
event.preventDefault();
|
|
}
|
|
|
|
break;
|
|
case 'Tab':
|
|
suggestions = this.termSuggestions.querySelectorAll('[type="button"]');
|
|
if (suggestions.length === 1) {
|
|
event.preventDefault();
|
|
let input = event.target;
|
|
let suggestion = suggestions[0];
|
|
|
|
this.complete(input, suggestion.value, { ...suggestion.dataset });
|
|
}
|
|
|
|
break;
|
|
case 'Enter':
|
|
let defaultSuggestion = this.termSuggestions.querySelector('.default > [type="button"]');
|
|
if (defaultSuggestion !== null) {
|
|
event.preventDefault();
|
|
let input = event.target;
|
|
|
|
this.complete(input, defaultSuggestion.value, { ...defaultSuggestion.dataset });
|
|
}
|
|
|
|
break;
|
|
case 'Escape':
|
|
if (this.hasSuggestions()) {
|
|
this.hideSuggestions()
|
|
event.preventDefault();
|
|
}
|
|
|
|
break;
|
|
case 'ArrowUp':
|
|
suggestions = this.termSuggestions.querySelectorAll('[type="button"]');
|
|
if (suggestions.length) {
|
|
event.preventDefault();
|
|
this.moveToSuggestion(true);
|
|
}
|
|
|
|
break;
|
|
case 'ArrowDown':
|
|
suggestions = this.termSuggestions.querySelectorAll('[type="button"]');
|
|
if (suggestions.length) {
|
|
event.preventDefault();
|
|
this.moveToSuggestion();
|
|
}
|
|
|
|
break;
|
|
default:
|
|
if (/[A-Z]/.test(event.key.charAt(0)) || event.key === '"') {
|
|
// Ignore control keys not resulting in new input data
|
|
break;
|
|
}
|
|
|
|
let typedSuggestion = this.termSuggestions.querySelector(`[value="${ event.key }"]`);
|
|
if (typedSuggestion !== null) {
|
|
this.hideSuggestions();
|
|
}
|
|
}
|
|
}
|
|
|
|
onInput(event) {
|
|
let input = event.target;
|
|
|
|
if (input.minLength > 0 && input.value.length < input.minLength) {
|
|
return;
|
|
}
|
|
|
|
// Set the input's value as search value. This ensures that if the user doesn't
|
|
// choose a suggestion, an up2date contextual value will be transmitted with
|
|
// completion requests and the server can properly identify a new value upon submit
|
|
input.dataset.search = input.value;
|
|
if (typeof input.form[input.name + '-search'] !== 'undefined') {
|
|
let dataElement = input.form[input.name + '-search'];
|
|
if (dataElement instanceof RadioNodeList) {
|
|
dataElement = dataElement[dataElement.length - 1];
|
|
}
|
|
|
|
dataElement.value = input.value;
|
|
}
|
|
|
|
let [value, data] = this.prepareCompletionData(input);
|
|
this.completedInput = input;
|
|
this.completedValue = value;
|
|
this.completedData = data;
|
|
this.requestCompletion(input, data);
|
|
}
|
|
|
|
onComplete(event) {
|
|
let input = event.target;
|
|
let { trigger = 'user' , ...detail } = event.detail;
|
|
|
|
let [value, data] = this.prepareCompletionData(input, detail);
|
|
this.completedInput = input;
|
|
this.completedValue = value;
|
|
this.completedData = data;
|
|
|
|
if (typeof data.suggestions !== 'undefined') {
|
|
this.showSuggestions(data.suggestions, input);
|
|
} else {
|
|
this.requestCompletion(input, data, trigger);
|
|
}
|
|
}
|
|
}
|
|
|
|
return Completer;
|
|
});
|