mirror of
				https://github.com/node-red/node-red.git
				synced 2025-03-01 10:36:34 +00:00 
			
		
		
		
	autocomplete improvements...
* add minInput - fixes #3479 * Add missing entries for catch, status, tcp, udp, websocket * corrections for http request * match visibility improvements (mono font + match color) * match to variable source as well as variable name
This commit is contained in:
		@@ -9,12 +9,14 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * options:
 | 
					 * options:
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *  search : function(value, [done])
 | 
					 *  search:    function(value, [done])
 | 
				
			||||||
 *             A function that is passed the current contents of the input whenever
 | 
					 *             A function that is passed the current contents of the input whenever
 | 
				
			||||||
 *             it changes.
 | 
					 *             it changes.
 | 
				
			||||||
 *             The function must either return auto-complete options, or pass them
 | 
					 *             The function must either return auto-complete options, or pass them
 | 
				
			||||||
 *             to the optional 'done' parameter.
 | 
					 *             to the optional 'done' parameter.
 | 
				
			||||||
 *             If the function signature includes 'done', it must be used
 | 
					 *             If the function signature includes 'done', it must be used
 | 
				
			||||||
 | 
					 *  minLength: number
 | 
				
			||||||
 | 
					 *             If `minLength` is 0, pressing down arrow will show the list
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * The auto-complete options should be an array of objects in the form:
 | 
					 * The auto-complete options should be an array of objects in the form:
 | 
				
			||||||
 *  {
 | 
					 *  {
 | 
				
			||||||
@@ -26,10 +28,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    $.widget( "nodered.autoComplete", {
 | 
					    $.widget( "nodered.autoComplete", {
 | 
				
			||||||
        _create: function() {
 | 
					        _create: function() {
 | 
				
			||||||
            var that = this;
 | 
					            const that = this;
 | 
				
			||||||
            this.completionMenuShown = false;
 | 
					            this.completionMenuShown = false;
 | 
				
			||||||
            this.options.search = this.options.search || function() { return [] }
 | 
					            this.options.minLength = parseInteger(this.options.minLength, 1, 0);
 | 
				
			||||||
            this.element.addClass("red-ui-autoComplete")
 | 
					            this.options.search = this.options.search || function() { return [] };
 | 
				
			||||||
 | 
					            this.element.addClass("red-ui-autoComplete");
 | 
				
			||||||
            this.element.on("keydown.red-ui-autoComplete", function(evt) {
 | 
					            this.element.on("keydown.red-ui-autoComplete", function(evt) {
 | 
				
			||||||
                if ((evt.keyCode === 13 || evt.keyCode === 9) && that.completionMenuShown) {
 | 
					                if ((evt.keyCode === 13 || evt.keyCode === 9) && that.completionMenuShown) {
 | 
				
			||||||
                    var opts = that.menu.options();
 | 
					                    var opts = that.menu.options();
 | 
				
			||||||
@@ -71,8 +74,8 @@
 | 
				
			|||||||
            this.completionMenuShown = true;
 | 
					            this.completionMenuShown = true;
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        _updateCompletions: function(val) {
 | 
					        _updateCompletions: function(val) {
 | 
				
			||||||
            var that = this;
 | 
					            const that = this;
 | 
				
			||||||
            if (val.trim() === "") {
 | 
					            if (val.trim().length < this.options.minLength) {
 | 
				
			||||||
                if (this.completionMenuShown) {
 | 
					                if (this.completionMenuShown) {
 | 
				
			||||||
                    this.menu.hide();
 | 
					                    this.menu.hide();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@@ -96,7 +99,7 @@
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (this.options.search.length === 2) {
 | 
					            if (this.options.search.length === 2) {
 | 
				
			||||||
                var requestId = 1+Math.floor(Math.random()*10000);
 | 
					                const requestId = 1+Math.floor(Math.random()*10000);
 | 
				
			||||||
                this.pendingRequest = requestId;
 | 
					                this.pendingRequest = requestId;
 | 
				
			||||||
                this.options.search(val,function(completions) { displayResults(completions,requestId);})
 | 
					                this.options.search(val,function(completions) { displayResults(completions,requestId);})
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
@@ -112,4 +115,12 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					    function parseInteger(input, def, min, max) {
 | 
				
			||||||
 | 
					        if(input == null) { return (def || 0); }
 | 
				
			||||||
 | 
					        min = min == null ? Number.NEGATIVE_INFINITY : min; 
 | 
				
			||||||
 | 
					        max = max == null ? Number.POSITIVE_INFINITY : max; 
 | 
				
			||||||
 | 
					        let n = parseInt(input);
 | 
				
			||||||
 | 
					        if(isNaN(n) || n < min || n > max) { n = def || 0; }
 | 
				
			||||||
 | 
					        return n;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
})(jQuery);
 | 
					})(jQuery);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -55,34 +55,46 @@
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var autoComplete = function(options) {
 | 
					    var autoComplete = function(options) {
 | 
				
			||||||
 | 
					        function getMatch(value, searchValue) {
 | 
				
			||||||
 | 
					            const idx = value.toLowerCase().indexOf(searchValue.toLowerCase());
 | 
				
			||||||
 | 
					            const len = idx > -1 ? searchValue.length : 0;
 | 
				
			||||||
 | 
					            return {
 | 
				
			||||||
 | 
					                index: idx,
 | 
				
			||||||
 | 
					                found: idx > -1,
 | 
				
			||||||
 | 
					                pre: value.substring(0,idx),
 | 
				
			||||||
 | 
					                match: value.substring(idx,idx+len),
 | 
				
			||||||
 | 
					                post: value.substring(idx+len),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        function generateSpans(match) {
 | 
				
			||||||
 | 
					            const els = [];
 | 
				
			||||||
 | 
					            if(match.pre) { els.push($('<span/>').text(match.pre)); }
 | 
				
			||||||
 | 
					            if(match.match) { els.push($('<span/>',{style:"font-weight: bold; color: var(--red-ui-text-color-link);"}).text(match.match)); }
 | 
				
			||||||
 | 
					            if(match.post) { els.push($('<span/>').text(match.post)); }
 | 
				
			||||||
 | 
					            return els;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        return function(val) {
 | 
					        return function(val) {
 | 
				
			||||||
            var matches = [];
 | 
					            var matches = [];
 | 
				
			||||||
            options.forEach(opt => {
 | 
					            options.forEach(opt => {
 | 
				
			||||||
                let v = opt.value;
 | 
					                const optVal = opt.value;
 | 
				
			||||||
                var i = v.toLowerCase().indexOf(val.toLowerCase());
 | 
					                const optSrc = (opt.source||[]).join(",");
 | 
				
			||||||
                if (i > -1) {
 | 
					                const valMatch = getMatch(optVal, val);
 | 
				
			||||||
                    var pre = v.substring(0,i);
 | 
					                const srcMatch = getMatch(optSrc, val);
 | 
				
			||||||
                    var matchedVal = v.substring(i,i+val.length);
 | 
					                if (valMatch.found || srcMatch.found) {
 | 
				
			||||||
                    var post = v.substring(i+val.length)
 | 
					                    const element = $('<div>',{style: "display: flex"});
 | 
				
			||||||
 | 
					                    const valEl = $('<div/>',{style:"font-family: var(--red-ui-monospace-font); white-space:nowrap; overflow: hidden; flex-grow:1"});
 | 
				
			||||||
                    var el = $('<div/>',{style:"white-space:nowrap; overflow: hidden; flex-grow:1"});
 | 
					                    valEl.append(generateSpans(valMatch));
 | 
				
			||||||
                    $('<span/>').text(pre).appendTo(el);
 | 
					                    valEl.appendTo(element);
 | 
				
			||||||
                    $('<span/>',{style:"font-weight: bold"}).text(matchedVal).appendTo(el);
 | 
					                    if (optSrc) {
 | 
				
			||||||
                    $('<span/>').text(post).appendTo(el);
 | 
					                        const optEl = $('<div>').css({ "font-size": "0.8em" });
 | 
				
			||||||
 | 
					                        optEl.append(generateSpans(srcMatch));
 | 
				
			||||||
                    var element = $('<div>',{style: "display: flex"});
 | 
					                        optEl.appendTo(element);
 | 
				
			||||||
                    el.appendTo(element);
 | 
					 | 
				
			||||||
                    if (opt.source) {
 | 
					 | 
				
			||||||
                        $('<div>').css({
 | 
					 | 
				
			||||||
                            "font-size": "0.8em"
 | 
					 | 
				
			||||||
                        }).text(opt.source.join(",")).appendTo(element);
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
                    matches.push({ 
 | 
					                    matches.push({ 
 | 
				
			||||||
                        value: v,
 | 
					                        value: optVal, 
 | 
				
			||||||
                        label: element, 
 | 
					                        label: element, 
 | 
				
			||||||
                        i:i
 | 
					                        i: (valMatch.found ? valMatch.index : srcMatch.index) 
 | 
				
			||||||
                    })
 | 
					                    });
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
            matches.sort(function(A,B){return A.i-B.i})
 | 
					            matches.sort(function(A,B){return A.i-B.i})
 | 
				
			||||||
@@ -93,6 +105,36 @@
 | 
				
			|||||||
    // This is a hand-generated list of completions for the core nodes (based on the node help html).
 | 
					    // This is a hand-generated list of completions for the core nodes (based on the node help html).
 | 
				
			||||||
    var msgCompletions = [
 | 
					    var msgCompletions = [
 | 
				
			||||||
        { value: "payload" },
 | 
					        { value: "payload" },
 | 
				
			||||||
 | 
					        { value: "topic", source: ["mqtt","inject","rbe"] },
 | 
				
			||||||
 | 
					        { value: "action", source: ["mqtt"] },
 | 
				
			||||||
 | 
					        { value: "complete", source: ["join"] },
 | 
				
			||||||
 | 
					        { value: "contentType", source: ["mqtt"] },
 | 
				
			||||||
 | 
					        { value: "cookies", source: ["http request","http response"] },
 | 
				
			||||||
 | 
					        { value: "correlationData", source: ["mqtt"] },
 | 
				
			||||||
 | 
					        { value: "delay", source: ["delay","trigger"] },
 | 
				
			||||||
 | 
					        { value: "encoding", source: ["file"] },
 | 
				
			||||||
 | 
					        { value: "error", source: ["catch"] },
 | 
				
			||||||
 | 
					        { value: "error.message", source: ["catch"] },
 | 
				
			||||||
 | 
					        { value: "error.source", source: ["catch"] },
 | 
				
			||||||
 | 
					        { value: "error.source.id", source: ["catch"] },
 | 
				
			||||||
 | 
					        { value: "error.source.type", source: ["catch"] },
 | 
				
			||||||
 | 
					        { value: "error.source.name", source: ["catch"] },
 | 
				
			||||||
 | 
					        { value: "filename", source: ["file","file in"] },
 | 
				
			||||||
 | 
					        { value: "flush", source: ["delay"] },
 | 
				
			||||||
 | 
					        { value: "followRedirects", source: ["http request"] },
 | 
				
			||||||
 | 
					        { value: "headers", source: ["http response","http request"] },
 | 
				
			||||||
 | 
					        { value: "host", source: ["tcp request","http request"] },
 | 
				
			||||||
 | 
					        { value: "ip", source: ["udp out"] },
 | 
				
			||||||
 | 
					        { value: "kill", source: ["exec"] },
 | 
				
			||||||
 | 
					        { value: "messageExpiryInterval", source: ["mqtt"] },
 | 
				
			||||||
 | 
					        { value: "method", source: ["http request"] },
 | 
				
			||||||
 | 
					        { value: "options", source: ["xml"] },
 | 
				
			||||||
 | 
					        { value: "parts", source: ["split","join","batch","sort"] },
 | 
				
			||||||
 | 
					        { value: "pid", source: ["exec"] },
 | 
				
			||||||
 | 
					        { value: "port", source: ["tcp request"," udp out"] },
 | 
				
			||||||
 | 
					        { value: "qos", source: ["mqtt"] },
 | 
				
			||||||
 | 
					        { value: "rate", source: ["delay"] },
 | 
				
			||||||
 | 
					        { value: "rejectUnauthorized", source: ["http request"] },
 | 
				
			||||||
        { value: "req", source: ["http in"]},
 | 
					        { value: "req", source: ["http in"]},
 | 
				
			||||||
        { value: "req.body", source: ["http in"]},
 | 
					        { value: "req.body", source: ["http in"]},
 | 
				
			||||||
        { value: "req.headers", source: ["http in"]},
 | 
					        { value: "req.headers", source: ["http in"]},
 | 
				
			||||||
@@ -100,38 +142,28 @@
 | 
				
			|||||||
        { value: "req.params", source: ["http in"]},
 | 
					        { value: "req.params", source: ["http in"]},
 | 
				
			||||||
        { value: "req.cookies", source: ["http in"]},
 | 
					        { value: "req.cookies", source: ["http in"]},
 | 
				
			||||||
        { value: "req.files", 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: "requestTimeout", source: ["http request"] },
 | 
				
			||||||
        { value: "reset", source: ["delay","trigger","join","rbe"] },
 | 
					        { value: "reset", source: ["delay","trigger","join","rbe"] },
 | 
				
			||||||
 | 
					        { value: "responseCookies", source: ["http request"] },
 | 
				
			||||||
        { value: "responseTopic", source: ["mqtt"] },
 | 
					        { value: "responseTopic", source: ["mqtt"] },
 | 
				
			||||||
 | 
					        { value: "responseURL", source: ["http request"] },
 | 
				
			||||||
        { value: "restartTimeout", source: ["join"] },
 | 
					        { value: "restartTimeout", source: ["join"] },
 | 
				
			||||||
        { value: "retain", source: ["mqtt"] },
 | 
					        { value: "retain", source: ["mqtt"] },
 | 
				
			||||||
 | 
					        { value: "schema", source: ["json"] },
 | 
				
			||||||
        { value: "select", source: ["html"] },
 | 
					        { value: "select", source: ["html"] },
 | 
				
			||||||
        { value: "statusCode", source: ["http in"] },
 | 
					        { value: "statusCode", source: ["http response","http request"] },
 | 
				
			||||||
 | 
					        { value: "status", source: ["status"] },
 | 
				
			||||||
 | 
					        { value: "status.text", source: ["status"] },
 | 
				
			||||||
 | 
					        { value: "status.source", source: ["status"] },
 | 
				
			||||||
 | 
					        { value: "status.source.type", source: ["status"] },
 | 
				
			||||||
 | 
					        { value: "status.source.id", source: ["status"] },
 | 
				
			||||||
 | 
					        { value: "status.source.name", source: ["status"] },
 | 
				
			||||||
 | 
					        { value: "target", source: ["link call"] },
 | 
				
			||||||
        { value: "template", source: ["template"] },
 | 
					        { value: "template", source: ["template"] },
 | 
				
			||||||
        { value: "toFront", source: ["delay"] },
 | 
					        { value: "toFront", source: ["delay"] },
 | 
				
			||||||
        { value: "topic", source: ["inject","mqtt","rbe"] },
 | 
					 | 
				
			||||||
        { value: "url", source: ["http request"] },
 | 
					        { value: "url", source: ["http request"] },
 | 
				
			||||||
        { value: "userProperties", source: ["mqtt"] }
 | 
					        { value: "userProperties", source: ["mqtt"] },
 | 
				
			||||||
 | 
					        { value: "_session", source: ["websocket out","tcp out"] },
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
    var allOptions = {
 | 
					    var allOptions = {
 | 
				
			||||||
        msg: {value:"msg",label:"msg.",validate:RED.utils.validatePropertyExpression, autoComplete: autoComplete(msgCompletions)},
 | 
					        msg: {value:"msg",label:"msg.",validate:RED.utils.validatePropertyExpression, autoComplete: autoComplete(msgCompletions)},
 | 
				
			||||||
@@ -1147,7 +1179,8 @@
 | 
				
			|||||||
                            this.elementDiv.show();
 | 
					                            this.elementDiv.show();
 | 
				
			||||||
                            if (opt.autoComplete) {
 | 
					                            if (opt.autoComplete) {
 | 
				
			||||||
                                this.input.autoComplete({
 | 
					                                this.input.autoComplete({
 | 
				
			||||||
                                    search: opt.autoComplete
 | 
					                                    search: opt.autoComplete,
 | 
				
			||||||
 | 
					                                    minLength: 0
 | 
				
			||||||
                                })
 | 
					                                })
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user