Autocomplete integrated and 3 samples.
This commit is contained in:
parent
26a1a84602
commit
ae287d48e9
|
@ -5,7 +5,7 @@
|
|||
|
||||
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
|
||||
<script src="../dist/jsoneditor.js"></script>
|
||||
<script src="autocomplete.js"></script>
|
||||
|
||||
|
||||
<style type="text/css">
|
||||
#jsoneditor {
|
||||
|
@ -34,19 +34,19 @@
|
|||
|
||||
<script>
|
||||
// create the editor
|
||||
var container = document.getElementById('jsoneditor');
|
||||
var pv = autocomplete({
|
||||
fontSize: '10pt',
|
||||
fontFamily: 'droid sans mono, consolas, monospace, courier new, courier, sans-serif'
|
||||
});
|
||||
|
||||
var container = document.getElementById('jsoneditor');
|
||||
var options = {
|
||||
modes: ['text', 'tree'],
|
||||
autocomplete: {
|
||||
ActivationChar: '',
|
||||
ApplyTo:['values'],
|
||||
Show: function (node, element) {
|
||||
Config: {
|
||||
ConfirmKeys: [39, 35, 9, 190] // Confirm Autocomplete Keys: [right, end, tab, '.'] // By default are only [right, end, tab]
|
||||
},
|
||||
ActivationChar: '*', // ActivationChar indicate if the value starts with this Char then autocompletion will be activated. ('' will be ignored).
|
||||
ApplyTo:['value'],
|
||||
GetOptions: function (autocomplete, node, text) {
|
||||
|
||||
var YaskON = {
|
||||
// Return first level json paths by the node 'o'
|
||||
stringify: function (o, prefix, activationChar) {
|
||||
prefix = prefix || '';
|
||||
switch (typeof o) {
|
||||
|
@ -74,14 +74,14 @@
|
|||
}
|
||||
};
|
||||
var data = {};
|
||||
pv.startFrom = 0;
|
||||
var text = element.innerText;
|
||||
autocomplete.startFrom = 0;
|
||||
var lastPoint = text.lastIndexOf('.');
|
||||
if ((lastPoint > 0) && (text.length > 1)) {
|
||||
var fnode = node.editor.node.findNode('.' + text.substring(this.ActivationChar.length, lastPoint));
|
||||
if (fnode && typeof fnode.getValue() == 'object') {
|
||||
data = fnode.getValue();
|
||||
pv.startFrom = text.lastIndexOf('.') + 1;
|
||||
// Indicate that autocompletion should start after the . (ignoring the first part)
|
||||
autocomplete.startFrom = text.lastIndexOf('.') + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -90,11 +90,7 @@
|
|||
var optionsStr = YaskON.stringify(data, null, this.ActivationChar);
|
||||
var options = optionsStr.split("\n");
|
||||
|
||||
if (options.length > 0)
|
||||
pv.Show(element, options);
|
||||
},
|
||||
Hide: function () {
|
||||
pv.hideDropDown();
|
||||
return options;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,151 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>JSONEditor | Auto Complete</title>
|
||||
|
||||
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
|
||||
<link href="horsey/horsey.css" rel="stylesheet" type="text/css">
|
||||
|
||||
<script src="../dist/jsoneditor.js"></script>
|
||||
<script src="horsey/horsey.js"></script>
|
||||
|
||||
<style type="text/css">
|
||||
#jsoneditor {
|
||||
width: 500px;
|
||||
height: 500px;
|
||||
}
|
||||
|
||||
p {
|
||||
width: 500px;
|
||||
font-family: "DejaVu Sans", sans-serif;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
This example demonstrates how to use JSONEditor with Horsey autocomplete,
|
||||
https://github.com/bevacqua/horsey
|
||||
</p>
|
||||
|
||||
<div id="jsoneditor"></div>
|
||||
|
||||
<script>
|
||||
// create the editor
|
||||
var container = document.getElementById('jsoneditor');
|
||||
var hy = null;
|
||||
var startFrom = 0;
|
||||
var activeOptions = [];
|
||||
|
||||
var options = {
|
||||
modes: ['text', 'tree'],
|
||||
autocomplete: {
|
||||
ActivationChar: '',
|
||||
ApplyTo:['values'],
|
||||
Show: function (node, element) {
|
||||
function setEndOfContenteditable(contentEditableElement) {
|
||||
var range, selection;
|
||||
if (document.createRange)//Firefox, Chrome, Opera, Safari, IE 9+
|
||||
{
|
||||
range = document.createRange();//Create a range (a range is a like the selection but invisible)
|
||||
range.selectNodeContents(contentEditableElement);//Select the entire contents of the element with the range
|
||||
range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
|
||||
selection = window.getSelection();//get the selection object (allows you to change selection)
|
||||
selection.removeAllRanges();//remove any selections already made
|
||||
selection.addRange(range);//make the range you have just created the visible selection
|
||||
}
|
||||
else if (document.selection)//IE 8 and lower
|
||||
{
|
||||
range = document.body.createTextRange();//Create a range (a range is a like the selection but invisible)
|
||||
range.moveToElementText(contentEditableElement);//Select the entire contents of the element with the range
|
||||
range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
|
||||
range.select();//Select the range (make it the visible selection
|
||||
}
|
||||
}
|
||||
var YaskON = {
|
||||
stringify: function (o, prefix, activationChar) {
|
||||
prefix = prefix || '';
|
||||
switch (typeof o) {
|
||||
case 'object':
|
||||
var output = "";
|
||||
if (Array.isArray(o)) {
|
||||
o.forEach(function (e, index) {
|
||||
output += activationChar + prefix + '[' + index + ']' + '\n';
|
||||
}.bind(this));
|
||||
return output;
|
||||
}
|
||||
output = "";
|
||||
for (var k in o) {
|
||||
if (o.hasOwnProperty(k)) {
|
||||
if (prefix == "") output += this.stringify(o[k], k, activationChar);
|
||||
}
|
||||
}
|
||||
if (prefix != "") output += activationChar + prefix + '\n'
|
||||
return output;
|
||||
case 'function':
|
||||
return "";
|
||||
default:
|
||||
if (prefix != "")
|
||||
return prefix + '\n';
|
||||
else
|
||||
return '';
|
||||
}
|
||||
}
|
||||
};
|
||||
var data = {};
|
||||
startFrom = 0;
|
||||
var text = element.innerText;
|
||||
var lastPoint = text.lastIndexOf('.');
|
||||
if ((lastPoint > 0) && (text.length > 1)) {
|
||||
var fnode = node.editor.node.findNode('.' + text.substring(this.ActivationChar.length, lastPoint));
|
||||
if (fnode && typeof fnode.getValue() == 'object') {
|
||||
data = fnode.getValue();
|
||||
startFrom = text.lastIndexOf('.') + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
data = node.editor.get();
|
||||
|
||||
var optionsStr = YaskON.stringify(data, null, this.ActivationChar);
|
||||
var options = (optionsStr == "") ? [] : optionsStr.split("\n");
|
||||
activeOptions = options;
|
||||
|
||||
if (activeOptions.length > 0) {
|
||||
if (hy && hy.attachment != element) {
|
||||
hy.destroy();
|
||||
hy = null;
|
||||
}
|
||||
if (hy == null)
|
||||
hy = horsey(element, {
|
||||
source(data, done) {
|
||||
setTimeout(() => done(null, [{
|
||||
list: activeOptions.filter(item => item.startsWith(data.input.substring(startFrom)))
|
||||
}]), 50);
|
||||
},
|
||||
set: function (value) {
|
||||
element.innerText = element.innerText.substring(0, startFrom) + value;
|
||||
setEndOfContenteditable(element);
|
||||
},
|
||||
filter: function (q, suggestion) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
Hide: function () {
|
||||
if (hy) hy.hide();
|
||||
}
|
||||
}
|
||||
};
|
||||
var json = {
|
||||
'array': [{'field1':'v1', 'field2':'v2'}, 2, 3],
|
||||
'boolean': true,
|
||||
'null': null,
|
||||
'number': 123,
|
||||
'object': {'a': 'b', 'c': 'd'},
|
||||
'string': 'Hello World'
|
||||
};
|
||||
var editor = new JSONEditor(container, options, json);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,95 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>JSONEditor | Auto Complete</title>
|
||||
|
||||
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
|
||||
<script src="../dist/jsoneditor.js"></script>
|
||||
|
||||
|
||||
<style type="text/css">
|
||||
#jsoneditor {
|
||||
width: 500px;
|
||||
height: 500px;
|
||||
}
|
||||
|
||||
p {
|
||||
width: 500px;
|
||||
font-family: "DejaVu Sans", sans-serif;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--<link href="./css/darktheme.css" rel="stylesheet" type="text/css">-->
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
This example demonstrates how to customize the look of JSONEditor,
|
||||
the editor below has a dark theme. Note that the example isn't worked
|
||||
out for the mode <code>code</code>. To do that, you can load and configure
|
||||
a custom theme for the Ace editor.
|
||||
</p>
|
||||
|
||||
<div id="jsoneditor"></div>
|
||||
|
||||
<script>
|
||||
|
||||
// create the editor
|
||||
var container = document.getElementById('jsoneditor');
|
||||
var options = {
|
||||
modes: ['text', 'tree'],
|
||||
autocomplete: {
|
||||
ApplyTo:['value'],
|
||||
GetOptions: function (autocomplete, node, text) {
|
||||
|
||||
// Return all strings in json
|
||||
function stringify(o, prefix) {
|
||||
prefix = prefix || '';
|
||||
switch (typeof o) {
|
||||
case 'object':
|
||||
var output = "";
|
||||
if (Array.isArray(o)) {
|
||||
if ((prefix != "") && (prefix != text)) output += prefix + '\n';
|
||||
o.forEach(function (e, index) {
|
||||
output += stringify(e, null);
|
||||
}.bind(this));
|
||||
return output;
|
||||
}
|
||||
output = "";
|
||||
for (var k in o) {
|
||||
if (o.hasOwnProperty(k)) {
|
||||
if (prefix == "") output += stringify(o[k], k);
|
||||
}
|
||||
}
|
||||
if ((prefix != "") && (prefix != text)) output += prefix + '\n';
|
||||
return output;
|
||||
case 'function':
|
||||
return "";
|
||||
default:
|
||||
var output = "";
|
||||
if ((prefix != "") && (prefix != text)) output += prefix + '\n';
|
||||
if ((o != "") && (o != text)) output += o + '\n';
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
var data = node.editor.get();
|
||||
var optionsStr = stringify(data, null);
|
||||
var options = optionsStr.split("\n");
|
||||
|
||||
return options;
|
||||
}
|
||||
}
|
||||
};
|
||||
var json = {
|
||||
'array': [{'field1':'v1', 'field2':'v2'}, 2, 3],
|
||||
'boolean': true,
|
||||
'null': null,
|
||||
'number': 123,
|
||||
'object': {'a': 'b', 'c': 'd'},
|
||||
'string': 'Hello World'
|
||||
};
|
||||
var editor = new JSONEditor(container, options, json);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,59 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>JSONEditor | Auto Complete</title>
|
||||
|
||||
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
|
||||
<script src="../dist/jsoneditor.js"></script>
|
||||
|
||||
|
||||
<style type="text/css">
|
||||
#jsoneditor {
|
||||
width: 500px;
|
||||
height: 500px;
|
||||
}
|
||||
|
||||
p {
|
||||
width: 500px;
|
||||
font-family: "DejaVu Sans", sans-serif;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--<link href="./css/darktheme.css" rel="stylesheet" type="text/css">-->
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
This example demonstrates how to customize the look of JSONEditor,
|
||||
the editor below has a dark theme. Note that the example isn't worked
|
||||
out for the mode <code>code</code>. To do that, you can load and configure
|
||||
a custom theme for the Ace editor.
|
||||
</p>
|
||||
|
||||
<div id="jsoneditor"></div>
|
||||
|
||||
<script>
|
||||
|
||||
// create the editor
|
||||
var container = document.getElementById('jsoneditor');
|
||||
var options = {
|
||||
modes: ['text', 'tree'],
|
||||
autocomplete: {
|
||||
ApplyTo:['name','value'], // This indicates the autocomplete is going to be applied to json properties names and values.
|
||||
GetOptions: function () {
|
||||
return ["apple","cranberry","raspberry","pie"];
|
||||
}
|
||||
}
|
||||
};
|
||||
var json = {
|
||||
'array': [{'field1':'v1', 'field2':'v2'}, 2, 3],
|
||||
'boolean': true,
|
||||
'null': null,
|
||||
'number': 123,
|
||||
'object': {'a': 'b', 'c': 'd'},
|
||||
'string': 'Hello World'
|
||||
};
|
||||
var editor = new JSONEditor(container, options, json);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,9 +1,34 @@
|
|||
'use strict';
|
||||
|
||||
function autocomplete(config) {
|
||||
(function (arr) {
|
||||
arr.forEach(function (item) {
|
||||
if (item.hasOwnProperty('remove')) {
|
||||
return;
|
||||
}
|
||||
Object.defineProperty(item, 'remove', {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
writable: true,
|
||||
value: function remove() {
|
||||
if (this.parentNode != null)
|
||||
this.parentNode.removeChild(this);
|
||||
}
|
||||
});
|
||||
});
|
||||
})([Element.prototype, CharacterData.prototype, DocumentType.prototype]);
|
||||
|
||||
if (!String.prototype.startsWith) {
|
||||
String.prototype.startsWith = function (searchString, position) {
|
||||
position = position || 0;
|
||||
return this.substr(position, searchString.length) === searchString;
|
||||
};
|
||||
}
|
||||
|
||||
function completely(config) {
|
||||
config = config || {};
|
||||
config.fontSize = config.fontSize || '16px';
|
||||
config.fontFamily = config.fontFamily || 'sans-serif';
|
||||
config.ConfirmKeys = config.ConfirmKeys || [39, 35, 9] // right, end, tab
|
||||
config.fontSize = config.fontSize || '';
|
||||
config.fontFamily = config.fontFamily || '';
|
||||
config.promptInnerHTML = config.promptInnerHTML || '';
|
||||
config.color = config.color || '#333';
|
||||
config.hintColor = config.hintColor || '#aaa';
|
||||
|
@ -183,6 +208,16 @@ function autocomplete(config) {
|
|||
this.elementHint.remove();
|
||||
this.elementHint = null;
|
||||
}
|
||||
|
||||
if (config.fontSize == '') {
|
||||
config.fontSize = window.getComputedStyle(element).getPropertyValue('font-size');
|
||||
dropDown.style.fontSize = config.fontSize;
|
||||
}
|
||||
if (config.fontFamily == '') {
|
||||
config.fontFamily = window.getComputedStyle(element).getPropertyValue('font-family');
|
||||
dropDown.style.fontFamily = config.fontFamily;
|
||||
}
|
||||
|
||||
var w = element.getBoundingClientRect().right - element.getBoundingClientRect().left;
|
||||
dropDown.style.marginLeft = '0';
|
||||
dropDown.style.marginTop = element.getBoundingClientRect().height + 'px';
|
||||
|
@ -268,7 +303,7 @@ function autocomplete(config) {
|
|||
// moving the dropDown and refreshing it.
|
||||
dropDown.style.left = calculateWidthForText(leftSide) + 'px';
|
||||
dropDownController.refresh(token, this.options);
|
||||
this.elementHint.style.width = calculateWidthForText(this.elementHint.innerText) + 'px'
|
||||
this.elementHint.style.width = calculateWidthForText(this.elementHint.innerText) + 10 + 'px'
|
||||
var wasDropDownHidden = (dropDown.style.visibility == 'hidden');
|
||||
if (!wasDropDownHidden)
|
||||
this.elementHint.style.width = calculateWidthForText(this.elementHint.innerText) + dropDown.clientWidth + 'px';
|
||||
|
@ -294,8 +329,8 @@ function autocomplete(config) {
|
|||
e.stopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
if (keyCode == 39 || keyCode == 35 || keyCode == 9 || keyCode == 190) { // right, end, tab, '.' (autocomplete triggered)
|
||||
config.ConfirmKeys
|
||||
if (config.ConfirmKeys.indexOf(keyCode) >= 0) { // (autocomplete triggered)
|
||||
if (keyCode == 9) {
|
||||
if (this.elementHint.innerText.length == 0) {
|
||||
rs.onTab();
|
||||
|
@ -376,5 +411,4 @@ function autocomplete(config) {
|
|||
return rs;
|
||||
}
|
||||
|
||||
if (window.module != undefined)
|
||||
module.exports = completely;
|
||||
module.exports = completely;
|
|
@ -8,7 +8,7 @@ var ContextMenu = require('./ContextMenu');
|
|||
var Node = require('./Node');
|
||||
var ModeSwitcher = require('./ModeSwitcher');
|
||||
var util = require('./util');
|
||||
|
||||
var autocomplete = require('./autocomplete');
|
||||
|
||||
// create a mixin with the functions for tree mode
|
||||
var treemode = {};
|
||||
|
@ -52,6 +52,9 @@ treemode.create = function (container, options) {
|
|||
|
||||
this._setOptions(options);
|
||||
|
||||
if (options.autocomplete)
|
||||
this.autocomplete = new autocomplete(options.autocomplete.Config);
|
||||
|
||||
if (this.options.history && this.options.mode !== 'view') {
|
||||
this.history = new History(this);
|
||||
}
|
||||
|
@ -1104,15 +1107,18 @@ treemode._onKeyDown = function (event) {
|
|||
if ((this.options.autocomplete) && (!handled)) {
|
||||
if (!ctrlKey && !altKey && !metaKey && (event.key.length == 1 || keynum == 8 || keynum == 46)) {
|
||||
handled = false;
|
||||
if ((this.options.autocomplete.ApplyTo.indexOf('values') >= 0 && event.target.className.indexOf("jsoneditor-value") >= 0) ||
|
||||
if ((this.options.autocomplete.ApplyTo.indexOf('value') >= 0 && event.target.className.indexOf("jsoneditor-value") >= 0) ||
|
||||
(this.options.autocomplete.ApplyTo.indexOf('name') >= 0 && event.target.className.indexOf("jsoneditor-field") >= 0)) {
|
||||
var node = Node.getNodeFromTarget(event.target);
|
||||
if (this.options.autocomplete.ActivationChar == null || event.target.innerText.startsWith(this.options.autocomplete.ActivationChar)) { // Activate autocomplete
|
||||
setTimeout(function (hnode, element) {
|
||||
if (element.innerText.length > 0)
|
||||
this.options.autocomplete.Show(hnode, element);
|
||||
if (element.innerText.length > 0) {
|
||||
var options = this.options.autocomplete.GetOptions(this.autocomplete, hnode, element.innerText);
|
||||
if (options.length > 0)
|
||||
this.autocomplete.Show(element, options);
|
||||
}
|
||||
else
|
||||
this.options.autocomplete.Hide();
|
||||
this.autocomplete.hideDropDown();
|
||||
|
||||
}.bind(this, node, event.target), 100);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue