mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Add autoComplete widget and add to TypedInput for msg. props
This commit is contained in:
parent
57386edb7c
commit
7f9e318214
@ -162,6 +162,7 @@ module.exports = function(grunt) {
|
|||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/stack.js",
|
"packages/node_modules/@node-red/editor-client/src/js/ui/common/stack.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js",
|
"packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/common/toggleButton.js",
|
"packages/node_modules/@node-red/editor-client/src/js/ui/common/toggleButton.js",
|
||||||
|
"packages/node_modules/@node-red/editor-client/src/js/ui/common/autoComplete.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/actions.js",
|
"packages/node_modules/@node-red/editor-client/src/js/ui/actions.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js",
|
"packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js",
|
||||||
"packages/node_modules/@node-red/editor-client/src/js/ui/diff.js",
|
"packages/node_modules/@node-red/editor-client/src/js/ui/diff.js",
|
||||||
|
108
packages/node_modules/@node-red/editor-client/src/js/ui/common/autoComplete.js
vendored
Normal file
108
packages/node_modules/@node-red/editor-client/src/js/ui/common/autoComplete.js
vendored
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
(function($) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* options:
|
||||||
|
*
|
||||||
|
* methods:
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
$.widget( "nodered.autoComplete", {
|
||||||
|
_create: function() {
|
||||||
|
var that = this;
|
||||||
|
this.completionMenuShown = false;
|
||||||
|
this.options.search = this.options.search || function() { return [] }
|
||||||
|
this.element.addClass("red-ui-autoComplete")
|
||||||
|
this.element.on("keydown.red-ui-autoComplete", function(evt) {
|
||||||
|
if ((evt.keyCode === 13 || evt.keyCode === 9) && that.completionMenuShown) {
|
||||||
|
var opts = that.menu.options();
|
||||||
|
that.element.val(opts[0].value);
|
||||||
|
that.menu.hide();
|
||||||
|
evt.preventDefault();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.element.on("keyup.red-ui-autoComplete", function(evt) {
|
||||||
|
if (evt.keyCode === 13 || evt.keyCode === 9 || evt.keyCode === 27) {
|
||||||
|
// ENTER / TAB / ESCAPE
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (evt.keyCode === 8 || evt.keyCode === 46) {
|
||||||
|
// Delete/Backspace
|
||||||
|
if (!that.completionMenuShown) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
that._updateCompletions(this.value);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
_showCompletionMenu: function(completions) {
|
||||||
|
if (this.completionMenuShown) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.menu = RED.popover.menu({
|
||||||
|
tabSelect: true,
|
||||||
|
width: 300,
|
||||||
|
maxHeight: 200,
|
||||||
|
class: "red-ui-autoComplete-container",
|
||||||
|
options: completions,
|
||||||
|
onselect: (opt) => { this.element.val(opt.value); this.element.focus() },
|
||||||
|
onclose: () => { this.completionMenuShown = false; delete this.menu; this.element.focus()}
|
||||||
|
});
|
||||||
|
this.menu.show({
|
||||||
|
target: this.element
|
||||||
|
})
|
||||||
|
this.completionMenuShown = true;
|
||||||
|
},
|
||||||
|
_updateCompletions: function(val) {
|
||||||
|
var that = this;
|
||||||
|
if (val.trim() === "") {
|
||||||
|
if (this.completionMenuShown) {
|
||||||
|
this.menu.hide();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
function displayResults(completions,requestId) {
|
||||||
|
if (requestId && requestId !== that.pendingRequest) {
|
||||||
|
// This request has been superseded
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!completions || completions.length === 0) {
|
||||||
|
if (that.completionMenuShown) {
|
||||||
|
that.menu.hide();
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (that.completionMenuShown) {
|
||||||
|
that.menu.options(completions);
|
||||||
|
} else {
|
||||||
|
that._showCompletionMenu(completions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.options.search.length === 2) {
|
||||||
|
var requestId = 1+Math.floor(Math.random()*10000);
|
||||||
|
this.pendingRequest = requestId;
|
||||||
|
this.options.search(val,function(completions) { displayResults(completions,requestId);})
|
||||||
|
} else {
|
||||||
|
displayResults(this.options.search(val))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_destroy: function() {
|
||||||
|
this.element.removeClass("red-ui-autoComplete")
|
||||||
|
this.element.off("keydown.red-ui-autoComplete")
|
||||||
|
this.element.off("keyup.red-ui-autoComplete")
|
||||||
|
if (this.completionMenuShown) {
|
||||||
|
this.menu.hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// disable: function(val) {
|
||||||
|
// if(val === undefined || !!val ) {
|
||||||
|
//
|
||||||
|
// } else {
|
||||||
|
// this.uiSelect.attr("disabled", null); //remove attr
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// enable: function() {
|
||||||
|
// this.uiSelect.attr("disabled", null); //remove attr
|
||||||
|
// },
|
||||||
|
});
|
||||||
|
})(jQuery);
|
@ -340,20 +340,47 @@ RED.popover = (function() {
|
|||||||
}
|
}
|
||||||
var menuOptions = options.options || [];
|
var menuOptions = options.options || [];
|
||||||
var first;
|
var first;
|
||||||
|
|
||||||
|
var container = RED.popover.panel(list);
|
||||||
|
if (options.width) {
|
||||||
|
container.container.width(options.width);
|
||||||
|
}
|
||||||
|
if (options.class) {
|
||||||
|
container.container.addClass(options.class);
|
||||||
|
}
|
||||||
|
if (options.maxHeight) {
|
||||||
|
container.container.css({
|
||||||
|
"max-height": options.maxHeight,
|
||||||
|
"overflow-y": 'auto'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
var menu = {
|
||||||
|
options: function(opts) {
|
||||||
|
if (opts === undefined) {
|
||||||
|
return menuOptions
|
||||||
|
}
|
||||||
|
menuOptions = opts || [];
|
||||||
|
list.empty();
|
||||||
menuOptions.forEach(function(opt) {
|
menuOptions.forEach(function(opt) {
|
||||||
var item = $('<li>').appendTo(list);
|
var item = $('<li>').appendTo(list);
|
||||||
var link = $('<a href="#"></a>').text(opt.label).appendTo(item);
|
var link = $('<a href="#"></a>').appendTo(item);
|
||||||
|
if (typeof opt.label == "string") {
|
||||||
|
link.text(opt.label)
|
||||||
|
} else if (opt.label){
|
||||||
|
opt.label.appendTo(link);
|
||||||
|
}
|
||||||
link.on("click", function(evt) {
|
link.on("click", function(evt) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
if (opt.onselect) {
|
if (opt.onselect) {
|
||||||
opt.onselect();
|
opt.onselect();
|
||||||
|
} else if (options.onselect) {
|
||||||
|
options.onselect(opt);
|
||||||
}
|
}
|
||||||
menu.hide();
|
menu.hide();
|
||||||
})
|
})
|
||||||
if (!first) { first = link}
|
if (!first) { first = link}
|
||||||
})
|
})
|
||||||
var container = RED.popover.panel(list);
|
},
|
||||||
var menu = {
|
|
||||||
show: function(opts) {
|
show: function(opts) {
|
||||||
$(document).on("keydown.red-ui-menu", function(evt) {
|
$(document).on("keydown.red-ui-menu", function(evt) {
|
||||||
var currentItem = list.find(":focus").parent();
|
var currentItem = list.find(":focus").parent();
|
||||||
@ -387,6 +414,11 @@ RED.popover = (function() {
|
|||||||
// ESCAPE
|
// ESCAPE
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
menu.hide(true);
|
menu.hide(true);
|
||||||
|
} else if (evt.keyCode === 9 && options.tabSelect) {
|
||||||
|
// TAB - with tabSelect enabled
|
||||||
|
evt.preventDefault();
|
||||||
|
currentItem.find("a").trigger("click");
|
||||||
|
|
||||||
}
|
}
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
})
|
})
|
||||||
@ -406,6 +438,7 @@ RED.popover = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
menu.options(menuOptions);
|
||||||
return menu;
|
return menu;
|
||||||
},
|
},
|
||||||
panel: function(content) {
|
panel: function(content) {
|
||||||
@ -434,7 +467,7 @@ RED.popover = (function() {
|
|||||||
|
|
||||||
var pos = target.offset();
|
var pos = target.offset();
|
||||||
var targetWidth = target.width();
|
var targetWidth = target.width();
|
||||||
var targetHeight = target.height();
|
var targetHeight = target.outerHeight();
|
||||||
var panelHeight = panel.height();
|
var panelHeight = panel.height();
|
||||||
var panelWidth = panel.width();
|
var panelWidth = panel.width();
|
||||||
|
|
||||||
|
@ -53,8 +53,88 @@
|
|||||||
}
|
}
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var autoComplete = function(options) {
|
||||||
|
return function(val) {
|
||||||
|
var matches = [];
|
||||||
|
options.forEach(opt => {
|
||||||
|
let v = opt.value;
|
||||||
|
var i = v.toLowerCase().indexOf(val.toLowerCase());
|
||||||
|
if (i > -1) {
|
||||||
|
var pre = v.substring(0,i);
|
||||||
|
var matchedVal = v.substring(i,i+val.length);
|
||||||
|
var post = v.substring(i+val.length)
|
||||||
|
|
||||||
|
var el = $('<div/>',{style:"white-space:nowrap; overflow: hidden; flex-grow:1"});
|
||||||
|
$('<span/>').text(pre).appendTo(el);
|
||||||
|
$('<span/>',{style:"font-weight: bold"}).text(matchedVal).appendTo(el);
|
||||||
|
$('<span/>').text(post).appendTo(el);
|
||||||
|
|
||||||
|
var element = $('<div>',{style: "display: flex"});
|
||||||
|
el.appendTo(element);
|
||||||
|
if (opt.source) {
|
||||||
|
$('<div>').css({
|
||||||
|
"font-size": "0.8em"
|
||||||
|
}).text(opt.source.join(",")).appendTo(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
matches.push({
|
||||||
|
value: v,
|
||||||
|
label: element,
|
||||||
|
i:i
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
matches.sort(function(A,B){return A.i-B.i})
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// This is a hand-generated list of completions for the core nodes (based on the node help html).
|
||||||
|
|
||||||
|
var msgCompletions = [
|
||||||
|
{ value: "payload" },
|
||||||
|
{ value: "req", source: ["http in"]},
|
||||||
|
{ value: "req.body", source: ["http in"]},
|
||||||
|
{ value: "req.headers", source: ["http in"]},
|
||||||
|
{ value: "req.query", source: ["http in"]},
|
||||||
|
{ value: "req.params", source: ["http in"]},
|
||||||
|
{ value: "req.cookies", source: ["http in"]},
|
||||||
|
{ value: "req.files", source: ["http in"]},
|
||||||
|
{ value: "complete", source: ["join"] },
|
||||||
|
{ value: "contentType", source: ["mqtt"] },
|
||||||
|
{ value: "cookies", source: ["http in","http request"] },
|
||||||
|
{ value: "correlationData", source: ["mqtt"] },
|
||||||
|
{ value: "delay", source: ["delay","trigger"] },
|
||||||
|
{ value: "encoding", source: ["file"] },
|
||||||
|
{ value: "error", source: ["catch"] },
|
||||||
|
{ value: "filename", source: ["file","file in"] },
|
||||||
|
{ value: "flush", source: ["delay"] },
|
||||||
|
{ value: "followRedirects", source: ["http request"] },
|
||||||
|
{ value: "headers", source: ["http in"," http request"] },
|
||||||
|
{ value: "kill", source: ["exec"] },
|
||||||
|
{ value: "messageExpiryInterval", source: ["mqtt"] },
|
||||||
|
{ value: "method", source: ["http-request"] },
|
||||||
|
{ value: "options", source: ["xml"] },
|
||||||
|
{ value: "parts", source: ["split","join"] },
|
||||||
|
{ value: "pid", source: ["exec"] },
|
||||||
|
{ value: "qos", source: ["mqtt"] },
|
||||||
|
{ value: "rate", source: ["delay"] },
|
||||||
|
{ value: "rejectUnauthorized", source: ["http request"] },
|
||||||
|
{ value: "requestTimeout", source: ["http request"] },
|
||||||
|
{ value: "reset", source: ["delay","trigger","join","rbe"] },
|
||||||
|
{ value: "responseTopic", source: ["mqtt"] },
|
||||||
|
{ value: "restartTimeout", source: ["join"] },
|
||||||
|
{ value: "retain", source: ["mqtt"] },
|
||||||
|
{ value: "select", source: ["html"] },
|
||||||
|
{ value: "statusCode", source: ["http in"] },
|
||||||
|
{ value: "template", source: ["template"] },
|
||||||
|
{ value: "toFront", source: ["delay"] },
|
||||||
|
{ value: "topic", source: ["inject","mqtt","rbe"] },
|
||||||
|
{ value: "url", source: ["http request"] },
|
||||||
|
{ value: "userProperties", source: ["mqtt"] }
|
||||||
|
]
|
||||||
var allOptions = {
|
var allOptions = {
|
||||||
msg: {value:"msg",label:"msg.",validate:RED.utils.validatePropertyExpression},
|
msg: {value:"msg",label:"msg.",validate:RED.utils.validatePropertyExpression, autoComplete: autoComplete(msgCompletions)},
|
||||||
flow: {value:"flow",label:"flow.",hasValue:true,
|
flow: {value:"flow",label:"flow.",hasValue:true,
|
||||||
options:[],
|
options:[],
|
||||||
validate:RED.utils.validatePropertyExpression,
|
validate:RED.utils.validatePropertyExpression,
|
||||||
@ -380,6 +460,9 @@
|
|||||||
that.element.trigger('paste',evt);
|
that.element.trigger('paste',evt);
|
||||||
});
|
});
|
||||||
this.input.on('keydown', function(evt) {
|
this.input.on('keydown', function(evt) {
|
||||||
|
if (that.typeMap[that.propertyType].autoComplete) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if (evt.keyCode >= 37 && evt.keyCode <= 40) {
|
if (evt.keyCode >= 37 && evt.keyCode <= 40) {
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
}
|
}
|
||||||
@ -795,6 +878,9 @@
|
|||||||
} else {
|
} else {
|
||||||
this.input.val(this.oldValues.hasOwnProperty("_")?this.oldValues["_"]:(opt.default||""))
|
this.input.val(this.oldValues.hasOwnProperty("_")?this.oldValues["_"]:(opt.default||""))
|
||||||
}
|
}
|
||||||
|
if (previousType.autoComplete) {
|
||||||
|
this.input.autoComplete("destroy");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.propertyType = type;
|
this.propertyType = type;
|
||||||
if (this.typeField) {
|
if (this.typeField) {
|
||||||
@ -985,6 +1071,11 @@
|
|||||||
} else {
|
} else {
|
||||||
this.valueLabelContainer.hide();
|
this.valueLabelContainer.hide();
|
||||||
this.elementDiv.show();
|
this.elementDiv.show();
|
||||||
|
if (opt.autoComplete) {
|
||||||
|
this.input.autoComplete({
|
||||||
|
search: opt.autoComplete
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (this.optionExpandButton) {
|
if (this.optionExpandButton) {
|
||||||
if (opt.expand) {
|
if (opt.expand) {
|
||||||
|
@ -61,6 +61,7 @@
|
|||||||
@import "ui/common/checkboxSet";
|
@import "ui/common/checkboxSet";
|
||||||
@import "ui/common/stack";
|
@import "ui/common/stack";
|
||||||
@import "ui/common/treeList";
|
@import "ui/common/treeList";
|
||||||
|
@import "ui/common/autoComplete";
|
||||||
|
|
||||||
@import "dragdrop";
|
@import "dragdrop";
|
||||||
|
|
||||||
|
5
packages/node_modules/@node-red/editor-client/src/sass/ui/common/autoComplete.scss
vendored
Normal file
5
packages/node_modules/@node-red/editor-client/src/sass/ui/common/autoComplete.scss
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
.red-ui-autoComplete-container {
|
||||||
|
&.red-ui-popover-panel {
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user