Feat: Added filter and trigger options for autocomplete (#713)
* Feat: Added filter options for autocomplete * Feat: added trigger option for autocomplete * Fix: const/let => var
This commit is contained in:
parent
59290dd6c2
commit
85e0710097
16
docs/api.md
16
docs/api.md
|
@ -274,6 +274,22 @@ Constructs a new JSONEditor.
|
|||
|
||||
*autocomplete* will enable this feature in your editor in tree mode, the object have the following **subelements**:
|
||||
|
||||
- `{string} filter`
|
||||
- `{Function} filter`
|
||||
|
||||
Indicate the filter method of the autocomplete. Default to `start`.
|
||||
|
||||
- `start` : Match your input from the start, e.g. `ap` match `apple` but `pl` does not.
|
||||
- `contain` : Contain your input or not, e.g. `pl` match `apple` too.
|
||||
- Custom Function : Define custom filter rule, return `true` will match you input.
|
||||
|
||||
- `{string} trigger`
|
||||
|
||||
Indicate the way to trigger autocomplete menu. Default to `keydown`
|
||||
|
||||
- `keydown` : When you type something in the field or value, it will trigger autocomplete.
|
||||
- `focus` : When you focus in the field or value, it will trigger the autocomplete.
|
||||
|
||||
- `{number[]} confirmKeys`
|
||||
|
||||
Indicate the KeyCodes for trigger confirm completion, by default those keys are: [39, 35, 9] which are the code for [right, end, tab]
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
var options = {
|
||||
autocomplete: {
|
||||
applyTo:['value'],
|
||||
filter: 'contain',
|
||||
trigger: 'focus',
|
||||
getOptions: function (text, path, input, editor) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var options = extractUniqueWords(editor.get());
|
||||
|
|
|
@ -1,7 +1,18 @@
|
|||
'use strict';
|
||||
|
||||
var defaultFilterFunction = {
|
||||
start: function (token, match, config) {
|
||||
return match.indexOf(token) === 0;
|
||||
},
|
||||
contain: function (token, match, config) {
|
||||
return match.indexOf(token) > -1;
|
||||
}
|
||||
};
|
||||
|
||||
function completely(config) {
|
||||
config = config || {};
|
||||
config.filter = config.filter || 'start';
|
||||
config.trigger = config.trigger || 'keydown';
|
||||
config.confirmKeys = config.confirmKeys || [39, 35, 9] // right, end, tab
|
||||
config.caseSensitive = config.caseSensitive || false // autocomplete case sensitive
|
||||
|
||||
|
@ -47,22 +58,25 @@ function completely(config) {
|
|||
var distanceToBottom = vph - rect.bottom - 6; // distance from the browser border.
|
||||
|
||||
rows = [];
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
var filterFn = typeof config.filter === 'function' ? config.filter : defaultFilterFunction[config.filter];
|
||||
|
||||
if ( (config.caseSensitive && array[i].indexOf(token) !== 0)
|
||||
||(!config.caseSensitive && array[i].toLowerCase().indexOf(token.toLowerCase()) !== 0)) { continue; }
|
||||
var filtered = !filterFn ? [] : array.filter(function (match) {
|
||||
return filterFn(config.caseSensitive ? token : token.toLowerCase(), config.caseSensitive ? match : match.toLowerCase(), config);
|
||||
});
|
||||
|
||||
rows = filtered.map(function (row) {
|
||||
var divRow = document.createElement('div');
|
||||
divRow.className = 'item';
|
||||
//divRow.style.color = config.color;
|
||||
divRow.onmouseover = onMouseOver;
|
||||
divRow.onmouseout = onMouseOut;
|
||||
divRow.onmousedown = onMouseDown;
|
||||
divRow.__hint = row;
|
||||
divRow.innerHTML = row.substring(0, token.length) + '<b>' + row.substring(token.length) + '</b>';
|
||||
elem.appendChild(divRow);
|
||||
return divRow;
|
||||
});
|
||||
|
||||
var divRow = document.createElement('div');
|
||||
divRow.className = 'item';
|
||||
//divRow.style.color = config.color;
|
||||
divRow.onmouseover = onMouseOver;
|
||||
divRow.onmouseout = onMouseOut;
|
||||
divRow.onmousedown = onMouseDown;
|
||||
divRow.__hint = array[i];
|
||||
divRow.innerHTML = array[i].substring(0, token.length) + '<b>' + array[i].substring(token.length) + '</b>';
|
||||
rows.push(divRow);
|
||||
elem.appendChild(divRow);
|
||||
}
|
||||
if (rows.length === 0) {
|
||||
return; // nothing to show.
|
||||
}
|
||||
|
|
|
@ -1140,12 +1140,17 @@ treemode._onEvent = function (event) {
|
|||
return;
|
||||
}
|
||||
|
||||
var node = Node.getNodeFromTarget(event.target);
|
||||
|
||||
if (event.type === 'keydown') {
|
||||
this._onKeyDown(event);
|
||||
}
|
||||
|
||||
if (event.type === 'focus') {
|
||||
this.focusTarget = event.target;
|
||||
if (this.options.autocomplete && this.options.autocomplete.trigger === 'focus') {
|
||||
this._showAutoComplete(event.target);
|
||||
}
|
||||
}
|
||||
|
||||
if (event.type === 'mousedown') {
|
||||
|
@ -1155,7 +1160,6 @@ treemode._onEvent = function (event) {
|
|||
this._updateDragDistance(event);
|
||||
}
|
||||
|
||||
var node = Node.getNodeFromTarget(event.target);
|
||||
|
||||
if (node && this.options && this.options.navigationBar && node && (event.type === 'keydown' || event.type === 'mousedown')) {
|
||||
// apply on next tick, right after the new key press is applied
|
||||
|
@ -1505,6 +1509,51 @@ treemode._findTopLevelNodes = function (start, end) {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Show autocomplete menu
|
||||
* @param {Node} node
|
||||
* @param {HTMLElement} element
|
||||
* @private
|
||||
*/
|
||||
treemode._showAutoComplete = function (element) {
|
||||
var node = Node.getNodeFromTarget(element);
|
||||
|
||||
var jsonElementType = "";
|
||||
if (event.target.className.indexOf("jsoneditor-value") >= 0) jsonElementType = "value";
|
||||
if (event.target.className.indexOf("jsoneditor-field") >= 0) jsonElementType = "field";
|
||||
|
||||
var self = this;
|
||||
|
||||
setTimeout(function () {
|
||||
if (self.options.autocomplete.trigger === 'focus' || element.innerText.length > 0) {
|
||||
var result = self.options.autocomplete.getOptions(element.innerText, node.getPath(), jsonElementType, node.editor);
|
||||
if (result === null) {
|
||||
self.autocomplete.hideDropDown();
|
||||
} else if (typeof result.then === 'function') {
|
||||
// probably a promise
|
||||
if (result.then(function (obj) {
|
||||
if (obj === null) {
|
||||
self.autocomplete.hideDropDown();
|
||||
} else if (obj.options) {
|
||||
self.autocomplete.show(element, obj.startFrom, obj.options);
|
||||
} else {
|
||||
self.autocomplete.show(element, 0, obj);
|
||||
}
|
||||
}.bind(self)));
|
||||
} else {
|
||||
// definitely not a promise
|
||||
if (result.options)
|
||||
self.autocomplete.show(element, result.startFrom, result.options);
|
||||
else
|
||||
self.autocomplete.show(element, 0, result);
|
||||
}
|
||||
}
|
||||
else
|
||||
self.autocomplete.hideDropDown();
|
||||
|
||||
}, 50);
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handler for keydown. Handles shortcut keys
|
||||
* @param {Event} event
|
||||
|
@ -1562,41 +1611,11 @@ treemode._onKeyDown = function (event) {
|
|||
|
||||
if ((this.options.autocomplete) && (!handled)) {
|
||||
if (!ctrlKey && !altKey && !metaKey && (event.key.length == 1 || keynum == 8 || keynum == 46)) {
|
||||
handled = false;
|
||||
var jsonElementType = "";
|
||||
if (event.target.className.indexOf("jsoneditor-value") >= 0) jsonElementType = "value";
|
||||
if (event.target.className.indexOf("jsoneditor-field") >= 0) jsonElementType = "field";
|
||||
handled = false;
|
||||
var node = Node.getNodeFromTarget(event.target);
|
||||
|
||||
var node = Node.getNodeFromTarget(event.target);
|
||||
// Activate autocomplete
|
||||
setTimeout(function (hnode, element) {
|
||||
if (element.innerText.length > 0) {
|
||||
var result = this.options.autocomplete.getOptions(element.innerText, hnode.getPath(), jsonElementType, hnode.editor);
|
||||
if (result === null) {
|
||||
this.autocomplete.hideDropDown();
|
||||
} else if (typeof result.then === 'function') {
|
||||
// probably a promise
|
||||
if (result.then(function (obj) {
|
||||
if (obj === null) {
|
||||
this.autocomplete.hideDropDown();
|
||||
} else if (obj.options) {
|
||||
this.autocomplete.show(element, obj.startFrom, obj.options);
|
||||
} else {
|
||||
this.autocomplete.show(element, 0, obj);
|
||||
}
|
||||
}.bind(this)));
|
||||
} else {
|
||||
// definitely not a promise
|
||||
if (result.options)
|
||||
this.autocomplete.show(element, result.startFrom, result.options);
|
||||
else
|
||||
this.autocomplete.show(element, 0, result);
|
||||
}
|
||||
}
|
||||
else
|
||||
this.autocomplete.hideDropDown();
|
||||
|
||||
}.bind(this, node, event.target), 50);
|
||||
// Activate autocomplete
|
||||
this._showAutoComplete(event.target);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue