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**:
|
*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`
|
- `{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]
|
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 = {
|
var options = {
|
||||||
autocomplete: {
|
autocomplete: {
|
||||||
applyTo:['value'],
|
applyTo:['value'],
|
||||||
|
filter: 'contain',
|
||||||
|
trigger: 'focus',
|
||||||
getOptions: function (text, path, input, editor) {
|
getOptions: function (text, path, input, editor) {
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
var options = extractUniqueWords(editor.get());
|
var options = extractUniqueWords(editor.get());
|
||||||
|
|
|
@ -1,7 +1,18 @@
|
||||||
'use strict';
|
'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) {
|
function completely(config) {
|
||||||
config = config || {};
|
config = config || {};
|
||||||
|
config.filter = config.filter || 'start';
|
||||||
|
config.trigger = config.trigger || 'keydown';
|
||||||
config.confirmKeys = config.confirmKeys || [39, 35, 9] // right, end, tab
|
config.confirmKeys = config.confirmKeys || [39, 35, 9] // right, end, tab
|
||||||
config.caseSensitive = config.caseSensitive || false // autocomplete case sensitive
|
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.
|
var distanceToBottom = vph - rect.bottom - 6; // distance from the browser border.
|
||||||
|
|
||||||
rows = [];
|
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)
|
var filtered = !filterFn ? [] : array.filter(function (match) {
|
||||||
||(!config.caseSensitive && array[i].toLowerCase().indexOf(token.toLowerCase()) !== 0)) { continue; }
|
return filterFn(config.caseSensitive ? token : token.toLowerCase(), config.caseSensitive ? match : match.toLowerCase(), config);
|
||||||
|
});
|
||||||
|
|
||||||
|
rows = filtered.map(function (row) {
|
||||||
var divRow = document.createElement('div');
|
var divRow = document.createElement('div');
|
||||||
divRow.className = 'item';
|
divRow.className = 'item';
|
||||||
//divRow.style.color = config.color;
|
//divRow.style.color = config.color;
|
||||||
divRow.onmouseover = onMouseOver;
|
divRow.onmouseover = onMouseOver;
|
||||||
divRow.onmouseout = onMouseOut;
|
divRow.onmouseout = onMouseOut;
|
||||||
divRow.onmousedown = onMouseDown;
|
divRow.onmousedown = onMouseDown;
|
||||||
divRow.__hint = array[i];
|
divRow.__hint = row;
|
||||||
divRow.innerHTML = array[i].substring(0, token.length) + '<b>' + array[i].substring(token.length) + '</b>';
|
divRow.innerHTML = row.substring(0, token.length) + '<b>' + row.substring(token.length) + '</b>';
|
||||||
rows.push(divRow);
|
|
||||||
elem.appendChild(divRow);
|
elem.appendChild(divRow);
|
||||||
}
|
return divRow;
|
||||||
|
});
|
||||||
|
|
||||||
if (rows.length === 0) {
|
if (rows.length === 0) {
|
||||||
return; // nothing to show.
|
return; // nothing to show.
|
||||||
}
|
}
|
||||||
|
|
|
@ -1140,12 +1140,17 @@ treemode._onEvent = function (event) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var node = Node.getNodeFromTarget(event.target);
|
||||||
|
|
||||||
if (event.type === 'keydown') {
|
if (event.type === 'keydown') {
|
||||||
this._onKeyDown(event);
|
this._onKeyDown(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.type === 'focus') {
|
if (event.type === 'focus') {
|
||||||
this.focusTarget = event.target;
|
this.focusTarget = event.target;
|
||||||
|
if (this.options.autocomplete && this.options.autocomplete.trigger === 'focus') {
|
||||||
|
this._showAutoComplete(event.target);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.type === 'mousedown') {
|
if (event.type === 'mousedown') {
|
||||||
|
@ -1155,7 +1160,6 @@ treemode._onEvent = function (event) {
|
||||||
this._updateDragDistance(event);
|
this._updateDragDistance(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
var node = Node.getNodeFromTarget(event.target);
|
|
||||||
|
|
||||||
if (node && this.options && this.options.navigationBar && node && (event.type === 'keydown' || event.type === 'mousedown')) {
|
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
|
// 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
|
* Event handler for keydown. Handles shortcut keys
|
||||||
* @param {Event} event
|
* @param {Event} event
|
||||||
|
@ -1563,40 +1612,10 @@ treemode._onKeyDown = function (event) {
|
||||||
if ((this.options.autocomplete) && (!handled)) {
|
if ((this.options.autocomplete) && (!handled)) {
|
||||||
if (!ctrlKey && !altKey && !metaKey && (event.key.length == 1 || keynum == 8 || keynum == 46)) {
|
if (!ctrlKey && !altKey && !metaKey && (event.key.length == 1 || keynum == 8 || keynum == 46)) {
|
||||||
handled = false;
|
handled = false;
|
||||||
var jsonElementType = "";
|
|
||||||
if (event.target.className.indexOf("jsoneditor-value") >= 0) jsonElementType = "value";
|
|
||||||
if (event.target.className.indexOf("jsoneditor-field") >= 0) jsonElementType = "field";
|
|
||||||
|
|
||||||
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