mirror of
				https://github.com/node-red/node-red.git
				synced 2025-03-01 10:36:34 +00:00 
			
		
		
		
	Move type editors into their own files
This commit is contained in:
		@@ -150,6 +150,7 @@ module.exports = function(grunt) {
 | 
				
			|||||||
                    "editor/js/ui/tab-config.js",
 | 
					                    "editor/js/ui/tab-config.js",
 | 
				
			||||||
                    "editor/js/ui/palette-editor.js",
 | 
					                    "editor/js/ui/palette-editor.js",
 | 
				
			||||||
                    "editor/js/ui/editor.js",
 | 
					                    "editor/js/ui/editor.js",
 | 
				
			||||||
 | 
					                    "editor/js/ui/editors/*.js",
 | 
				
			||||||
                    "editor/js/ui/tray.js",
 | 
					                    "editor/js/ui/tray.js",
 | 
				
			||||||
                    "editor/js/ui/clipboard.js",
 | 
					                    "editor/js/ui/clipboard.js",
 | 
				
			||||||
                    "editor/js/ui/library.js",
 | 
					                    "editor/js/ui/library.js",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1818,658 +1818,22 @@ RED.editor = (function() {
 | 
				
			|||||||
        RED.tray.show(trayOptions);
 | 
					        RED.tray.show(trayOptions);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function showTypeEditor(type, options) {
 | 
				
			||||||
    var expressionTestCache = {};
 | 
					        if (RED.editor.types.hasOwnProperty(type)) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
    function editExpression(options) {
 | 
					 | 
				
			||||||
        var expressionTestCacheId = "_";
 | 
					 | 
				
			||||||
            if (editStack.length > 0) {
 | 
					            if (editStack.length > 0) {
 | 
				
			||||||
            expressionTestCacheId = editStack[editStack.length-1].id;
 | 
					                options.parent = editStack[editStack.length-1].id;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        var value = options.value;
 | 
					 | 
				
			||||||
        var onComplete = options.complete;
 | 
					 | 
				
			||||||
        var type = "_expression"
 | 
					 | 
				
			||||||
            editStack.push({type:type});
 | 
					            editStack.push({type:type});
 | 
				
			||||||
        RED.view.state(RED.state.EDITING);
 | 
					            options.title = options.title || getEditStackTitle();
 | 
				
			||||||
        var expressionEditor;
 | 
					            options.onclose = function() {
 | 
				
			||||||
        var testDataEditor;
 | 
					 | 
				
			||||||
        var testResultEditor
 | 
					 | 
				
			||||||
        var panels;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        var trayOptions = {
 | 
					 | 
				
			||||||
            title: getEditStackTitle(),
 | 
					 | 
				
			||||||
            width: "inherit",
 | 
					 | 
				
			||||||
            buttons: [
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    id: "node-dialog-cancel",
 | 
					 | 
				
			||||||
                    text: RED._("common.label.cancel"),
 | 
					 | 
				
			||||||
                    click: function() {
 | 
					 | 
				
			||||||
                        RED.tray.close();
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    id: "node-dialog-ok",
 | 
					 | 
				
			||||||
                    text: RED._("common.label.done"),
 | 
					 | 
				
			||||||
                    class: "primary",
 | 
					 | 
				
			||||||
                    click: function() {
 | 
					 | 
				
			||||||
                        $("#node-input-expression-help").html("");
 | 
					 | 
				
			||||||
                        onComplete(expressionEditor.getValue());
 | 
					 | 
				
			||||||
                        RED.tray.close();
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
            resize: function(dimensions) {
 | 
					 | 
				
			||||||
                if (dimensions) {
 | 
					 | 
				
			||||||
                    editTrayWidthCache[type] = dimensions.width;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                var height = $("#dialog-form").height();
 | 
					 | 
				
			||||||
                if (panels) {
 | 
					 | 
				
			||||||
                    panels.resize(height);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            open: function(tray) {
 | 
					 | 
				
			||||||
                var trayBody = tray.find('.editor-tray-body');
 | 
					 | 
				
			||||||
                trayBody.addClass("node-input-expression-editor")
 | 
					 | 
				
			||||||
                var dialogForm = buildEditForm(tray.find('.editor-tray-body'),'dialog-form','_expression','editor');
 | 
					 | 
				
			||||||
                var funcSelect = $("#node-input-expression-func");
 | 
					 | 
				
			||||||
                Object.keys(jsonata.functions).forEach(function(f) {
 | 
					 | 
				
			||||||
                    funcSelect.append($("<option></option>").val(f).text(f));
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
                funcSelect.change(function(e) {
 | 
					 | 
				
			||||||
                    var f = $(this).val();
 | 
					 | 
				
			||||||
                    var args = RED._('jsonata:'+f+".args",{defaultValue:''});
 | 
					 | 
				
			||||||
                    var title = "<h5>"+f+"("+args+")</h5>";
 | 
					 | 
				
			||||||
                    var body = marked(RED._('jsonata:'+f+'.desc',{defaultValue:''}));
 | 
					 | 
				
			||||||
                    $("#node-input-expression-help").html(title+"<p>"+body+"</p>");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
                expressionEditor = RED.editor.createEditor({
 | 
					 | 
				
			||||||
                    id: 'node-input-expression',
 | 
					 | 
				
			||||||
                    value: "",
 | 
					 | 
				
			||||||
                    mode:"ace/mode/jsonata",
 | 
					 | 
				
			||||||
                    options: {
 | 
					 | 
				
			||||||
                        enableBasicAutocompletion:true,
 | 
					 | 
				
			||||||
                        enableSnippets:true,
 | 
					 | 
				
			||||||
                        enableLiveAutocompletion: true
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
                var currentToken = null;
 | 
					 | 
				
			||||||
                var currentTokenPos = -1;
 | 
					 | 
				
			||||||
                var currentFunctionMarker = null;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                expressionEditor.getSession().setValue(value||"",-1);
 | 
					 | 
				
			||||||
                expressionEditor.on("changeSelection", function() {
 | 
					 | 
				
			||||||
                    var c = expressionEditor.getCursorPosition();
 | 
					 | 
				
			||||||
                    var token = expressionEditor.getSession().getTokenAt(c.row,c.column);
 | 
					 | 
				
			||||||
                    if (token !== currentToken || (token && /paren/.test(token.type) && c.column !== currentTokenPos)) {
 | 
					 | 
				
			||||||
                        currentToken = token;
 | 
					 | 
				
			||||||
                        var r,p;
 | 
					 | 
				
			||||||
                        var scopedFunction = null;
 | 
					 | 
				
			||||||
                        if (token && token.type === 'keyword') {
 | 
					 | 
				
			||||||
                            r = c.row;
 | 
					 | 
				
			||||||
                            scopedFunction = token;
 | 
					 | 
				
			||||||
                        } else {
 | 
					 | 
				
			||||||
                            var depth = 0;
 | 
					 | 
				
			||||||
                            var next = false;
 | 
					 | 
				
			||||||
                            if (token) {
 | 
					 | 
				
			||||||
                                if (token.type === 'paren.rparen') {
 | 
					 | 
				
			||||||
                                    // If this is a block of parens ')))', set
 | 
					 | 
				
			||||||
                                    // depth to offset against the cursor position
 | 
					 | 
				
			||||||
                                    // within the block
 | 
					 | 
				
			||||||
                                    currentTokenPos = c.column;
 | 
					 | 
				
			||||||
                                    depth = c.column - (token.start + token.value.length);
 | 
					 | 
				
			||||||
                                }
 | 
					 | 
				
			||||||
                                r = c.row;
 | 
					 | 
				
			||||||
                                p = token.index;
 | 
					 | 
				
			||||||
                            } else {
 | 
					 | 
				
			||||||
                                r = c.row-1;
 | 
					 | 
				
			||||||
                                p = -1;
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                            while ( scopedFunction === null && r > -1) {
 | 
					 | 
				
			||||||
                                var rowTokens = expressionEditor.getSession().getTokens(r);
 | 
					 | 
				
			||||||
                                if (p === -1) {
 | 
					 | 
				
			||||||
                                    p = rowTokens.length-1;
 | 
					 | 
				
			||||||
                                }
 | 
					 | 
				
			||||||
                                while (p > -1) {
 | 
					 | 
				
			||||||
                                    var type = rowTokens[p].type;
 | 
					 | 
				
			||||||
                                    if (next) {
 | 
					 | 
				
			||||||
                                        if (type === 'keyword') {
 | 
					 | 
				
			||||||
                                            scopedFunction = rowTokens[p];
 | 
					 | 
				
			||||||
                                            // console.log("HIT",scopedFunction);
 | 
					 | 
				
			||||||
                                            break;
 | 
					 | 
				
			||||||
                                        }
 | 
					 | 
				
			||||||
                                        next = false;
 | 
					 | 
				
			||||||
                                    }
 | 
					 | 
				
			||||||
                                    if (type === 'paren.lparen') {
 | 
					 | 
				
			||||||
                                        depth-=rowTokens[p].value.length;
 | 
					 | 
				
			||||||
                                    } else if (type === 'paren.rparen') {
 | 
					 | 
				
			||||||
                                        depth+=rowTokens[p].value.length;
 | 
					 | 
				
			||||||
                                    }
 | 
					 | 
				
			||||||
                                    if (depth < 0) {
 | 
					 | 
				
			||||||
                                        next = true;
 | 
					 | 
				
			||||||
                                        depth = 0;
 | 
					 | 
				
			||||||
                                    }
 | 
					 | 
				
			||||||
                                    // console.log(r,p,depth,next,rowTokens[p]);
 | 
					 | 
				
			||||||
                                    p--;
 | 
					 | 
				
			||||||
                                }
 | 
					 | 
				
			||||||
                                if (!scopedFunction) {
 | 
					 | 
				
			||||||
                                    r--;
 | 
					 | 
				
			||||||
                                }
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        expressionEditor.session.removeMarker(currentFunctionMarker);
 | 
					 | 
				
			||||||
                        if (scopedFunction) {
 | 
					 | 
				
			||||||
                        //console.log(token,.map(function(t) { return t.type}));
 | 
					 | 
				
			||||||
                            funcSelect.val(scopedFunction.value).change();
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                dialogForm.i18n();
 | 
					 | 
				
			||||||
                $("#node-input-expression-func-insert").click(function(e) {
 | 
					 | 
				
			||||||
                    e.preventDefault();
 | 
					 | 
				
			||||||
                    var pos = expressionEditor.getCursorPosition();
 | 
					 | 
				
			||||||
                    var f = funcSelect.val();
 | 
					 | 
				
			||||||
                    var snippet = jsonata.getFunctionSnippet(f);
 | 
					 | 
				
			||||||
                    expressionEditor.insertSnippet(snippet);
 | 
					 | 
				
			||||||
                    expressionEditor.focus();
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
                $("#node-input-expression-reformat").click(function(evt) {
 | 
					 | 
				
			||||||
                    evt.preventDefault();
 | 
					 | 
				
			||||||
                    var v = expressionEditor.getValue()||"";
 | 
					 | 
				
			||||||
                    try {
 | 
					 | 
				
			||||||
                        v = jsonata.format(v);
 | 
					 | 
				
			||||||
                    } catch(err) {
 | 
					 | 
				
			||||||
                        // TODO: do an optimistic auto-format
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    expressionEditor.getSession().setValue(v||"",-1);
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                var tabs = RED.tabs.create({
 | 
					 | 
				
			||||||
                    element: $("#node-input-expression-tabs"),
 | 
					 | 
				
			||||||
                    onchange:function(tab) {
 | 
					 | 
				
			||||||
                        $(".node-input-expression-tab-content").hide();
 | 
					 | 
				
			||||||
                        tab.content.show();
 | 
					 | 
				
			||||||
                        trayOptions.resize();
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                tabs.addTab({
 | 
					 | 
				
			||||||
                    id: 'expression-help',
 | 
					 | 
				
			||||||
                    label: RED._('expressionEditor.functionReference'),
 | 
					 | 
				
			||||||
                    content: $("#node-input-expression-tab-help")
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
                tabs.addTab({
 | 
					 | 
				
			||||||
                    id: 'expression-tests',
 | 
					 | 
				
			||||||
                    label: RED._('expressionEditor.test'),
 | 
					 | 
				
			||||||
                    content: $("#node-input-expression-tab-test")
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
                testDataEditor = RED.editor.createEditor({
 | 
					 | 
				
			||||||
                    id: 'node-input-expression-test-data',
 | 
					 | 
				
			||||||
                    value: expressionTestCache[expressionTestCacheId] || '{\n    "payload": "hello world"\n}',
 | 
					 | 
				
			||||||
                    mode:"ace/mode/json",
 | 
					 | 
				
			||||||
                    lineNumbers: false
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
                var changeTimer;
 | 
					 | 
				
			||||||
                $(".node-input-expression-legacy").click(function(e) {
 | 
					 | 
				
			||||||
                    e.preventDefault();
 | 
					 | 
				
			||||||
                    RED.sidebar.info.set(RED._("expressionEditor.compatModeDesc"));
 | 
					 | 
				
			||||||
                    RED.sidebar.info.show();
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
                var testExpression = function() {
 | 
					 | 
				
			||||||
                    var value = testDataEditor.getValue();
 | 
					 | 
				
			||||||
                    var parsedData;
 | 
					 | 
				
			||||||
                    var currentExpression = expressionEditor.getValue();
 | 
					 | 
				
			||||||
                    var expr;
 | 
					 | 
				
			||||||
                    var usesContext = false;
 | 
					 | 
				
			||||||
                    var legacyMode = /(^|[^a-zA-Z0-9_'"])msg([^a-zA-Z0-9_'"]|$)/.test(currentExpression);
 | 
					 | 
				
			||||||
                    $(".node-input-expression-legacy").toggle(legacyMode);
 | 
					 | 
				
			||||||
                    try {
 | 
					 | 
				
			||||||
                        expr = jsonata(currentExpression);
 | 
					 | 
				
			||||||
                        expr.assign('flowContext',function(val) {
 | 
					 | 
				
			||||||
                            usesContext = true;
 | 
					 | 
				
			||||||
                            return null;
 | 
					 | 
				
			||||||
                        });
 | 
					 | 
				
			||||||
                        expr.assign('globalContext',function(val) {
 | 
					 | 
				
			||||||
                            usesContext = true;
 | 
					 | 
				
			||||||
                            return null;
 | 
					 | 
				
			||||||
                        });
 | 
					 | 
				
			||||||
                    } catch(err) {
 | 
					 | 
				
			||||||
                        testResultEditor.setValue(RED._("expressionEditor.errors.invalid-expr",{message:err.message}),-1);
 | 
					 | 
				
			||||||
                        return;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    try {
 | 
					 | 
				
			||||||
                        parsedData = JSON.parse(value);
 | 
					 | 
				
			||||||
                    } catch(err) {
 | 
					 | 
				
			||||||
                        testResultEditor.setValue(RED._("expressionEditor.errors.invalid-msg",{message:err.toString()}))
 | 
					 | 
				
			||||||
                        return;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    try {
 | 
					 | 
				
			||||||
                        var result = expr.evaluate(legacyMode?{msg:parsedData}:parsedData);
 | 
					 | 
				
			||||||
                        if (usesContext) {
 | 
					 | 
				
			||||||
                            testResultEditor.setValue(RED._("expressionEditor.errors.context-unsupported"),-1);
 | 
					 | 
				
			||||||
                            return;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        var formattedResult;
 | 
					 | 
				
			||||||
                        if (result !== undefined) {
 | 
					 | 
				
			||||||
                            formattedResult = JSON.stringify(result,null,4);
 | 
					 | 
				
			||||||
                        } else {
 | 
					 | 
				
			||||||
                            formattedResult = RED._("expressionEditor.noMatch");
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        testResultEditor.setValue(formattedResult,-1);
 | 
					 | 
				
			||||||
                    } catch(err) {
 | 
					 | 
				
			||||||
                        testResultEditor.setValue(RED._("expressionEditor.errors.eval",{message:err.message}),-1);
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                testDataEditor.getSession().on('change', function() {
 | 
					 | 
				
			||||||
                    clearTimeout(changeTimer);
 | 
					 | 
				
			||||||
                    changeTimer = setTimeout(testExpression,200);
 | 
					 | 
				
			||||||
                    expressionTestCache[expressionTestCacheId] = testDataEditor.getValue();
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
                expressionEditor.getSession().on('change', function() {
 | 
					 | 
				
			||||||
                    clearTimeout(changeTimer);
 | 
					 | 
				
			||||||
                    changeTimer = setTimeout(testExpression,200);
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                testResultEditor = RED.editor.createEditor({
 | 
					 | 
				
			||||||
                    id: 'node-input-expression-test-result',
 | 
					 | 
				
			||||||
                    value: "",
 | 
					 | 
				
			||||||
                    mode:"ace/mode/json",
 | 
					 | 
				
			||||||
                    lineNumbers: false,
 | 
					 | 
				
			||||||
                    readOnly: true
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
                panels = RED.panels.create({
 | 
					 | 
				
			||||||
                    id:"node-input-expression-panels",
 | 
					 | 
				
			||||||
                    resize: function(p1Height,p2Height) {
 | 
					 | 
				
			||||||
                        var p1 = $("#node-input-expression-panel-expr");
 | 
					 | 
				
			||||||
                        p1Height -= $(p1.children()[0]).outerHeight(true);
 | 
					 | 
				
			||||||
                        var editorRow = $(p1.children()[1]);
 | 
					 | 
				
			||||||
                        p1Height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
 | 
					 | 
				
			||||||
                        $("#node-input-expression").css("height",(p1Height-5)+"px");
 | 
					 | 
				
			||||||
                        expressionEditor.resize();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        var p2 = $("#node-input-expression-panel-info > .form-row > div:first-child");
 | 
					 | 
				
			||||||
                        p2Height -= p2.outerHeight(true) + 20;
 | 
					 | 
				
			||||||
                        $(".node-input-expression-tab-content").height(p2Height);
 | 
					 | 
				
			||||||
                        $("#node-input-expression-test-data").css("height",(p2Height-5)+"px");
 | 
					 | 
				
			||||||
                        testDataEditor.resize();
 | 
					 | 
				
			||||||
                        $("#node-input-expression-test-result").css("height",(p2Height-5)+"px");
 | 
					 | 
				
			||||||
                        testResultEditor.resize();
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                $("#node-input-example-reformat").click(function(evt) {
 | 
					 | 
				
			||||||
                    evt.preventDefault();
 | 
					 | 
				
			||||||
                    var v = testDataEditor.getValue()||"";
 | 
					 | 
				
			||||||
                    try {
 | 
					 | 
				
			||||||
                        v = JSON.stringify(JSON.parse(v),null,4);
 | 
					 | 
				
			||||||
                    } catch(err) {
 | 
					 | 
				
			||||||
                        // TODO: do an optimistic auto-format
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    testDataEditor.getSession().setValue(v||"",-1);
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                testExpression();
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            close: function() {
 | 
					 | 
				
			||||||
                editStack.pop();
 | 
					                editStack.pop();
 | 
				
			||||||
                expressionEditor.destroy();
 | 
					 | 
				
			||||||
                testDataEditor.destroy();
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            show: function() {}
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        RED.tray.show(trayOptions);
 | 
					            RED.editor.types[type].show(options);
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    function editJSON(options) {
 | 
					 | 
				
			||||||
        var value = options.value;
 | 
					 | 
				
			||||||
        var onComplete = options.complete;
 | 
					 | 
				
			||||||
        var type = "_json"
 | 
					 | 
				
			||||||
        editStack.push({type:type});
 | 
					 | 
				
			||||||
        RED.view.state(RED.state.EDITING);
 | 
					 | 
				
			||||||
        var expressionEditor;
 | 
					 | 
				
			||||||
        var changeTimer;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        var checkValid = function() {
 | 
					 | 
				
			||||||
            var v = expressionEditor.getValue();
 | 
					 | 
				
			||||||
            try {
 | 
					 | 
				
			||||||
                JSON.parse(v);
 | 
					 | 
				
			||||||
                $("#node-dialog-ok").removeClass('disabled');
 | 
					 | 
				
			||||||
                return true;
 | 
					 | 
				
			||||||
            } catch(err) {
 | 
					 | 
				
			||||||
                $("#node-dialog-ok").addClass('disabled');
 | 
					 | 
				
			||||||
                return false;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        var trayOptions = {
 | 
					 | 
				
			||||||
            title: options.title || getEditStackTitle(),
 | 
					 | 
				
			||||||
            width: "inherit",
 | 
					 | 
				
			||||||
            buttons: [
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    id: "node-dialog-cancel",
 | 
					 | 
				
			||||||
                    text: RED._("common.label.cancel"),
 | 
					 | 
				
			||||||
                    click: function() {
 | 
					 | 
				
			||||||
                        RED.tray.close();
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    id: "node-dialog-ok",
 | 
					 | 
				
			||||||
                    text: RED._("common.label.done"),
 | 
					 | 
				
			||||||
                    class: "primary",
 | 
					 | 
				
			||||||
                    click: function() {
 | 
					 | 
				
			||||||
                        if (options.requireValid && !checkValid()) {
 | 
					 | 
				
			||||||
                            return;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        onComplete(expressionEditor.getValue());
 | 
					 | 
				
			||||||
                        RED.tray.close();
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
            resize: function(dimensions) {
 | 
					 | 
				
			||||||
                editTrayWidthCache[type] = dimensions.width;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                var rows = $("#dialog-form>div:not(.node-text-editor-row)");
 | 
					 | 
				
			||||||
                var editorRow = $("#dialog-form>div.node-text-editor-row");
 | 
					 | 
				
			||||||
                var height = $("#dialog-form").height();
 | 
					 | 
				
			||||||
                for (var i=0;i<rows.size();i++) {
 | 
					 | 
				
			||||||
                    height -= $(rows[i]).outerHeight(true);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                height -= (parseInt($("#dialog-form").css("marginTop"))+parseInt($("#dialog-form").css("marginBottom")));
 | 
					 | 
				
			||||||
                $(".node-text-editor").css("height",height+"px");
 | 
					 | 
				
			||||||
                expressionEditor.resize();
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            open: function(tray) {
 | 
					 | 
				
			||||||
                var trayBody = tray.find('.editor-tray-body');
 | 
					 | 
				
			||||||
                var dialogForm = buildEditForm(tray.find('.editor-tray-body'),'dialog-form',type,'editor');
 | 
					 | 
				
			||||||
                expressionEditor = RED.editor.createEditor({
 | 
					 | 
				
			||||||
                    id: 'node-input-json',
 | 
					 | 
				
			||||||
                    value: "",
 | 
					 | 
				
			||||||
                    mode:"ace/mode/json"
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
                expressionEditor.getSession().setValue(value||"",-1);
 | 
					 | 
				
			||||||
                if (options.requireValid) {
 | 
					 | 
				
			||||||
                    expressionEditor.getSession().on('change', function() {
 | 
					 | 
				
			||||||
                        clearTimeout(changeTimer);
 | 
					 | 
				
			||||||
                        changeTimer = setTimeout(checkValid,200);
 | 
					 | 
				
			||||||
                    });
 | 
					 | 
				
			||||||
                    checkValid();
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                $("#node-input-json-reformat").click(function(evt) {
 | 
					 | 
				
			||||||
                    evt.preventDefault();
 | 
					 | 
				
			||||||
                    var v = expressionEditor.getValue()||"";
 | 
					 | 
				
			||||||
                    try {
 | 
					 | 
				
			||||||
                        v = JSON.stringify(JSON.parse(v),null,4);
 | 
					 | 
				
			||||||
                    } catch(err) {
 | 
					 | 
				
			||||||
                        // TODO: do an optimistic auto-format
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    expressionEditor.getSession().setValue(v||"",-1);
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
                dialogForm.i18n();
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            close: function() {
 | 
					 | 
				
			||||||
                editStack.pop();
 | 
					 | 
				
			||||||
                expressionEditor.destroy();
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            show: function() {}
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        RED.tray.show(trayOptions);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    function editMarkdown(options) {
 | 
					 | 
				
			||||||
        var value = options.value;
 | 
					 | 
				
			||||||
        var onComplete = options.complete;
 | 
					 | 
				
			||||||
        var type = "_markdown"
 | 
					 | 
				
			||||||
        editStack.push({type:type});
 | 
					 | 
				
			||||||
        RED.view.state(RED.state.EDITING);
 | 
					 | 
				
			||||||
        var expressionEditor;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        var trayOptions = {
 | 
					 | 
				
			||||||
            title: options.title || getEditStackTitle(),
 | 
					 | 
				
			||||||
            width: "inherit",
 | 
					 | 
				
			||||||
            buttons: [
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    id: "node-dialog-cancel",
 | 
					 | 
				
			||||||
                    text: RED._("common.label.cancel"),
 | 
					 | 
				
			||||||
                    click: function() {
 | 
					 | 
				
			||||||
                        RED.tray.close();
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    id: "node-dialog-ok",
 | 
					 | 
				
			||||||
                    text: RED._("common.label.done"),
 | 
					 | 
				
			||||||
                    class: "primary",
 | 
					 | 
				
			||||||
                    click: function() {
 | 
					 | 
				
			||||||
                        onComplete(expressionEditor.getValue());
 | 
					 | 
				
			||||||
                        RED.tray.close();
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
            resize: function(dimensions) {
 | 
					 | 
				
			||||||
                editTrayWidthCache[type] = dimensions.width;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                var rows = $("#dialog-form>div:not(.node-text-editor-row)");
 | 
					 | 
				
			||||||
                var editorRow = $("#dialog-form>div.node-text-editor-row");
 | 
					 | 
				
			||||||
                var height = $("#dialog-form").height();
 | 
					 | 
				
			||||||
                for (var i=0;i<rows.size();i++) {
 | 
					 | 
				
			||||||
                    height -= $(rows[i]).outerHeight(true);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                height -= (parseInt($("#dialog-form").css("marginTop"))+parseInt($("#dialog-form").css("marginBottom")));
 | 
					 | 
				
			||||||
                $(".node-text-editor").css("height",height+"px");
 | 
					 | 
				
			||||||
                expressionEditor.resize();
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            open: function(tray) {
 | 
					 | 
				
			||||||
                var trayBody = tray.find('.editor-tray-body');
 | 
					 | 
				
			||||||
                var dialogForm = buildEditForm(tray.find('.editor-tray-body'),'dialog-form',type,'editor');
 | 
					 | 
				
			||||||
                expressionEditor = RED.editor.createEditor({
 | 
					 | 
				
			||||||
                    id: 'node-input-markdown',
 | 
					 | 
				
			||||||
                    value: value,
 | 
					 | 
				
			||||||
                    mode:"ace/mode/markdown"
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
                if (options.header) {
 | 
					 | 
				
			||||||
                    options.header.appendTo(tray.find('#node-input-markdown-title'));
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                dialogForm.i18n();
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            close: function() {
 | 
					 | 
				
			||||||
                editStack.pop();
 | 
					 | 
				
			||||||
                expressionEditor.destroy();
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            show: function() {}
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        RED.tray.show(trayOptions);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    function stringToUTF8Array(str) {
 | 
					 | 
				
			||||||
        var data = [];
 | 
					 | 
				
			||||||
        var i=0, l = str.length;
 | 
					 | 
				
			||||||
        for (i=0; i<l; i++) {
 | 
					 | 
				
			||||||
            var char = str.charCodeAt(i);
 | 
					 | 
				
			||||||
            if (char < 0x80) {
 | 
					 | 
				
			||||||
                data.push(char);
 | 
					 | 
				
			||||||
            } else if (char < 0x800) {
 | 
					 | 
				
			||||||
                data.push(0xc0 | (char >> 6));
 | 
					 | 
				
			||||||
                data.push(0x80 | (char & 0x3f));
 | 
					 | 
				
			||||||
            } else if (char < 0xd800 || char >= 0xe000) {
 | 
					 | 
				
			||||||
                data.push(0xe0 | (char >> 12));
 | 
					 | 
				
			||||||
                data.push(0x80 | ((char>>6) & 0x3f));
 | 
					 | 
				
			||||||
                data.push(0x80 | (char & 0x3f));
 | 
					 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
                i++;
 | 
					            console.log("Unknown type editor:",type);
 | 
				
			||||||
                char = 0x10000 + (((char & 0x3ff)<<10) | (str.charAt(i) & 0x3ff));
 | 
					 | 
				
			||||||
                data.push(0xf0 | (char >>18));
 | 
					 | 
				
			||||||
                data.push(0x80 | ((char>>12) & 0x3f));
 | 
					 | 
				
			||||||
                data.push(0x80 | ((char>>6) & 0x3f));
 | 
					 | 
				
			||||||
                data.push(0x80 | (char & 0x3f));
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
        return data;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function editBuffer(options) {
 | 
					 | 
				
			||||||
        var value = options.value;
 | 
					 | 
				
			||||||
        var onComplete = options.complete;
 | 
					 | 
				
			||||||
        var type = "_buffer"
 | 
					 | 
				
			||||||
        editStack.push({type:type});
 | 
					 | 
				
			||||||
        RED.view.state(RED.state.EDITING);
 | 
					 | 
				
			||||||
        var bufferStringEditor = [];
 | 
					 | 
				
			||||||
        var bufferBinValue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        var panels;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        var trayOptions = {
 | 
					 | 
				
			||||||
            title: getEditStackTitle(),
 | 
					 | 
				
			||||||
            width: "inherit",
 | 
					 | 
				
			||||||
            buttons: [
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    id: "node-dialog-cancel",
 | 
					 | 
				
			||||||
                    text: RED._("common.label.cancel"),
 | 
					 | 
				
			||||||
                    click: function() {
 | 
					 | 
				
			||||||
                        RED.tray.close();
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    id: "node-dialog-ok",
 | 
					 | 
				
			||||||
                    text: RED._("common.label.done"),
 | 
					 | 
				
			||||||
                    class: "primary",
 | 
					 | 
				
			||||||
                    click: function() {
 | 
					 | 
				
			||||||
                        onComplete(JSON.stringify(bufferBinValue));
 | 
					 | 
				
			||||||
                        RED.tray.close();
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
            resize: function(dimensions) {
 | 
					 | 
				
			||||||
                if (dimensions) {
 | 
					 | 
				
			||||||
                    editTrayWidthCache[type] = dimensions.width;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                var height = $("#dialog-form").height();
 | 
					 | 
				
			||||||
                if (panels) {
 | 
					 | 
				
			||||||
                    panels.resize(height);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            open: function(tray) {
 | 
					 | 
				
			||||||
                var trayBody = tray.find('.editor-tray-body');
 | 
					 | 
				
			||||||
                var dialogForm = buildEditForm(tray.find('.editor-tray-body'),'dialog-form',type,'editor');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                bufferStringEditor = RED.editor.createEditor({
 | 
					 | 
				
			||||||
                    id: 'node-input-buffer-str',
 | 
					 | 
				
			||||||
                    value: "",
 | 
					 | 
				
			||||||
                    mode:"ace/mode/text"
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
                bufferStringEditor.getSession().setValue(value||"",-1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                bufferBinEditor = RED.editor.createEditor({
 | 
					 | 
				
			||||||
                    id: 'node-input-buffer-bin',
 | 
					 | 
				
			||||||
                    value: "",
 | 
					 | 
				
			||||||
                    mode:"ace/mode/text",
 | 
					 | 
				
			||||||
                    readOnly: true
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                var changeTimer;
 | 
					 | 
				
			||||||
                var buildBuffer = function(data) {
 | 
					 | 
				
			||||||
                    var valid = true;
 | 
					 | 
				
			||||||
                    var isString = typeof data === 'string';
 | 
					 | 
				
			||||||
                    var binBuffer = [];
 | 
					 | 
				
			||||||
                    if (isString) {
 | 
					 | 
				
			||||||
                        bufferBinValue = stringToUTF8Array(data);
 | 
					 | 
				
			||||||
                    } else {
 | 
					 | 
				
			||||||
                        bufferBinValue = data;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    var i=0,l=bufferBinValue.length;
 | 
					 | 
				
			||||||
                    var c = 0;
 | 
					 | 
				
			||||||
                    for(i=0;i<l;i++) {
 | 
					 | 
				
			||||||
                        var d = parseInt(bufferBinValue[i]);
 | 
					 | 
				
			||||||
                        if (!isString && (isNaN(d) || d < 0 || d > 255)) {
 | 
					 | 
				
			||||||
                            valid = false;
 | 
					 | 
				
			||||||
                            break;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        if (i>0) {
 | 
					 | 
				
			||||||
                            if (i%8 === 0) {
 | 
					 | 
				
			||||||
                                if (i%16 === 0) {
 | 
					 | 
				
			||||||
                                    binBuffer.push("\n");
 | 
					 | 
				
			||||||
                                } else {
 | 
					 | 
				
			||||||
                                    binBuffer.push("  ");
 | 
					 | 
				
			||||||
                                }
 | 
					 | 
				
			||||||
                            } else {
 | 
					 | 
				
			||||||
                                binBuffer.push(" ");
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        binBuffer.push((d<16?"0":"")+d.toString(16).toUpperCase());
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    if (valid) {
 | 
					 | 
				
			||||||
                        $("#node-input-buffer-type-string").toggle(isString);
 | 
					 | 
				
			||||||
                        $("#node-input-buffer-type-array").toggle(!isString);
 | 
					 | 
				
			||||||
                        bufferBinEditor.setValue(binBuffer.join(""),1);
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    return valid;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                var bufferStringUpdate = function() {
 | 
					 | 
				
			||||||
                    var value = bufferStringEditor.getValue();
 | 
					 | 
				
			||||||
                    var isValidArray = false;
 | 
					 | 
				
			||||||
                    if (/^[\s]*\[[\s\S]*\][\s]*$/.test(value)) {
 | 
					 | 
				
			||||||
                        isValidArray = true;
 | 
					 | 
				
			||||||
                        try {
 | 
					 | 
				
			||||||
                            var data = JSON.parse(value);
 | 
					 | 
				
			||||||
                            isValidArray = buildBuffer(data);
 | 
					 | 
				
			||||||
                        } catch(err) {
 | 
					 | 
				
			||||||
                            isValidArray = false;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    if (!isValidArray) {
 | 
					 | 
				
			||||||
                        buildBuffer(value);
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                bufferStringEditor.getSession().on('change', function() {
 | 
					 | 
				
			||||||
                    clearTimeout(changeTimer);
 | 
					 | 
				
			||||||
                    changeTimer = setTimeout(bufferStringUpdate,200);
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                bufferStringUpdate();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                dialogForm.i18n();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                panels = RED.panels.create({
 | 
					 | 
				
			||||||
                    id:"node-input-buffer-panels",
 | 
					 | 
				
			||||||
                    resize: function(p1Height,p2Height) {
 | 
					 | 
				
			||||||
                        var p1 = $("#node-input-buffer-panel-str");
 | 
					 | 
				
			||||||
                        p1Height -= $(p1.children()[0]).outerHeight(true);
 | 
					 | 
				
			||||||
                        var editorRow = $(p1.children()[1]);
 | 
					 | 
				
			||||||
                        p1Height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
 | 
					 | 
				
			||||||
                        $("#node-input-buffer-str").css("height",(p1Height-5)+"px");
 | 
					 | 
				
			||||||
                        bufferStringEditor.resize();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        var p2 = $("#node-input-buffer-panel-bin");
 | 
					 | 
				
			||||||
                        editorRow = $(p2.children()[0]);
 | 
					 | 
				
			||||||
                        p2Height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
 | 
					 | 
				
			||||||
                        $("#node-input-buffer-bin").css("height",(p2Height-5)+"px");
 | 
					 | 
				
			||||||
                        bufferBinEditor.resize();
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                $(".node-input-buffer-type").click(function(e) {
 | 
					 | 
				
			||||||
                    e.preventDefault();
 | 
					 | 
				
			||||||
                    RED.sidebar.info.set(RED._("bufferEditor.modeDesc"));
 | 
					 | 
				
			||||||
                    RED.sidebar.info.show();
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            close: function() {
 | 
					 | 
				
			||||||
                editStack.pop();
 | 
					 | 
				
			||||||
                bufferStringEditor.destroy();
 | 
					 | 
				
			||||||
                bufferBinEditor.destroy();
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            show: function() {}
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        RED.tray.show(trayOptions);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
        init: function() {
 | 
					        init: function() {
 | 
				
			||||||
@@ -2482,14 +1846,22 @@ RED.editor = (function() {
 | 
				
			|||||||
                $("#node-dialog-cancel").click();
 | 
					                $("#node-dialog-cancel").click();
 | 
				
			||||||
                $("#node-config-dialog-cancel").click();
 | 
					                $("#node-config-dialog-cancel").click();
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for (var type in RED.editor.types) {
 | 
				
			||||||
 | 
					                if (RED.editor.types.hasOwnProperty(type)) {
 | 
				
			||||||
 | 
					                    RED.editor.types[type].init();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        types: {},
 | 
				
			||||||
        edit: showEditDialog,
 | 
					        edit: showEditDialog,
 | 
				
			||||||
        editConfig: showEditConfigNodeDialog,
 | 
					        editConfig: showEditConfigNodeDialog,
 | 
				
			||||||
        editSubflow: showEditSubflowDialog,
 | 
					        editSubflow: showEditSubflowDialog,
 | 
				
			||||||
        editExpression: editExpression,
 | 
					        editExpression: function(options) { showTypeEditor("_expression", options) },
 | 
				
			||||||
        editJSON: editJSON,
 | 
					        editJSON: function(options) { showTypeEditor("_json", options) },
 | 
				
			||||||
        editMarkdown: editMarkdown,
 | 
					        editMarkdown: function(options) { showTypeEditor("_markdown", options) },
 | 
				
			||||||
        editBuffer: editBuffer,
 | 
					        editBuffer: function(options) { showTypeEditor("_buffer", options) },
 | 
				
			||||||
 | 
					        buildEditForm: buildEditForm,
 | 
				
			||||||
        validateNode: validateNode,
 | 
					        validateNode: validateNode,
 | 
				
			||||||
        updateNodeProperties: updateNodeProperties, // TODO: only exposed for edit-undo
 | 
					        updateNodeProperties: updateNodeProperties, // TODO: only exposed for edit-undo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										209
									
								
								editor/js/ui/editors/buffer.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										209
									
								
								editor/js/ui/editors/buffer.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,209 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Copyright JS Foundation and other contributors, http://js.foundation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					 * you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					 * You may obtain a copy of the License at
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					 * See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					 * limitations under the License.
 | 
				
			||||||
 | 
					 **/
 | 
				
			||||||
 | 
					RED.editor.types._buffer = (function() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var template = '<script type="text/x-red" data-template-name="_buffer"><div id="node-input-buffer-panels"><div id="node-input-buffer-panel-str" class="red-ui-panel"><div class="form-row" style="margin-bottom: 3px; text-align: right;"><span class="node-input-buffer-type"><i class="fa fa-exclamation-circle"></i> <span id="node-input-buffer-type-string" data-i18n="bufferEditor.modeString"></span><span id="node-input-buffer-type-array" data-i18n="bufferEditor.modeArray"></span></span></div><div class="form-row node-text-editor-row"><div class="node-text-editor" id="node-input-buffer-str"></div></div></div><div id="node-input-buffer-panel-bin" class="red-ui-panel"><div class="form-row node-text-editor-row" style="margin-top: 10px"><div class="node-text-editor" id="node-input-buffer-bin"></div></div></div></div></script>';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function stringToUTF8Array(str) {
 | 
				
			||||||
 | 
					        var data = [];
 | 
				
			||||||
 | 
					        var i=0, l = str.length;
 | 
				
			||||||
 | 
					        for (i=0; i<l; i++) {
 | 
				
			||||||
 | 
					            var char = str.charCodeAt(i);
 | 
				
			||||||
 | 
					            if (char < 0x80) {
 | 
				
			||||||
 | 
					                data.push(char);
 | 
				
			||||||
 | 
					            } else if (char < 0x800) {
 | 
				
			||||||
 | 
					                data.push(0xc0 | (char >> 6));
 | 
				
			||||||
 | 
					                data.push(0x80 | (char & 0x3f));
 | 
				
			||||||
 | 
					            } else if (char < 0xd800 || char >= 0xe000) {
 | 
				
			||||||
 | 
					                data.push(0xe0 | (char >> 12));
 | 
				
			||||||
 | 
					                data.push(0x80 | ((char>>6) & 0x3f));
 | 
				
			||||||
 | 
					                data.push(0x80 | (char & 0x3f));
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                i++;
 | 
				
			||||||
 | 
					                char = 0x10000 + (((char & 0x3ff)<<10) | (str.charAt(i) & 0x3ff));
 | 
				
			||||||
 | 
					                data.push(0xf0 | (char >>18));
 | 
				
			||||||
 | 
					                data.push(0x80 | ((char>>12) & 0x3f));
 | 
				
			||||||
 | 
					                data.push(0x80 | ((char>>6) & 0x3f));
 | 
				
			||||||
 | 
					                data.push(0x80 | (char & 0x3f));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return data;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        init: function() {
 | 
				
			||||||
 | 
					            $(template).appendTo(document.body);
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        show: function(options) {
 | 
				
			||||||
 | 
					            var value = options.value;
 | 
				
			||||||
 | 
					            var onComplete = options.complete;
 | 
				
			||||||
 | 
					            var type = "_buffer"
 | 
				
			||||||
 | 
					            RED.view.state(RED.state.EDITING);
 | 
				
			||||||
 | 
					            var bufferStringEditor = [];
 | 
				
			||||||
 | 
					            var bufferBinValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var panels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var trayOptions = {
 | 
				
			||||||
 | 
					                title: options.title,
 | 
				
			||||||
 | 
					                width: "inherit",
 | 
				
			||||||
 | 
					                buttons: [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        id: "node-dialog-cancel",
 | 
				
			||||||
 | 
					                        text: RED._("common.label.cancel"),
 | 
				
			||||||
 | 
					                        click: function() {
 | 
				
			||||||
 | 
					                            RED.tray.close();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        id: "node-dialog-ok",
 | 
				
			||||||
 | 
					                        text: RED._("common.label.done"),
 | 
				
			||||||
 | 
					                        class: "primary",
 | 
				
			||||||
 | 
					                        click: function() {
 | 
				
			||||||
 | 
					                            onComplete(JSON.stringify(bufferBinValue));
 | 
				
			||||||
 | 
					                            RED.tray.close();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                resize: function(dimensions) {
 | 
				
			||||||
 | 
					                    var height = $("#dialog-form").height();
 | 
				
			||||||
 | 
					                    if (panels) {
 | 
				
			||||||
 | 
					                        panels.resize(height);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                open: function(tray) {
 | 
				
			||||||
 | 
					                    var trayBody = tray.find('.editor-tray-body');
 | 
				
			||||||
 | 
					                    var dialogForm = RED.editor.buildEditForm(tray.find('.editor-tray-body'),'dialog-form',type,'editor');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    bufferStringEditor = RED.editor.createEditor({
 | 
				
			||||||
 | 
					                        id: 'node-input-buffer-str',
 | 
				
			||||||
 | 
					                        value: "",
 | 
				
			||||||
 | 
					                        mode:"ace/mode/text"
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                    bufferStringEditor.getSession().setValue(value||"",-1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    bufferBinEditor = RED.editor.createEditor({
 | 
				
			||||||
 | 
					                        id: 'node-input-buffer-bin',
 | 
				
			||||||
 | 
					                        value: "",
 | 
				
			||||||
 | 
					                        mode:"ace/mode/text",
 | 
				
			||||||
 | 
					                        readOnly: true
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var changeTimer;
 | 
				
			||||||
 | 
					                    var buildBuffer = function(data) {
 | 
				
			||||||
 | 
					                        var valid = true;
 | 
				
			||||||
 | 
					                        var isString = typeof data === 'string';
 | 
				
			||||||
 | 
					                        var binBuffer = [];
 | 
				
			||||||
 | 
					                        if (isString) {
 | 
				
			||||||
 | 
					                            bufferBinValue = stringToUTF8Array(data);
 | 
				
			||||||
 | 
					                        } else {
 | 
				
			||||||
 | 
					                            bufferBinValue = data;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        var i=0,l=bufferBinValue.length;
 | 
				
			||||||
 | 
					                        var c = 0;
 | 
				
			||||||
 | 
					                        for(i=0;i<l;i++) {
 | 
				
			||||||
 | 
					                            var d = parseInt(bufferBinValue[i]);
 | 
				
			||||||
 | 
					                            if (!isString && (isNaN(d) || d < 0 || d > 255)) {
 | 
				
			||||||
 | 
					                                valid = false;
 | 
				
			||||||
 | 
					                                break;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            if (i>0) {
 | 
				
			||||||
 | 
					                                if (i%8 === 0) {
 | 
				
			||||||
 | 
					                                    if (i%16 === 0) {
 | 
				
			||||||
 | 
					                                        binBuffer.push("\n");
 | 
				
			||||||
 | 
					                                    } else {
 | 
				
			||||||
 | 
					                                        binBuffer.push("  ");
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                } else {
 | 
				
			||||||
 | 
					                                    binBuffer.push(" ");
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            binBuffer.push((d<16?"0":"")+d.toString(16).toUpperCase());
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        if (valid) {
 | 
				
			||||||
 | 
					                            $("#node-input-buffer-type-string").toggle(isString);
 | 
				
			||||||
 | 
					                            $("#node-input-buffer-type-array").toggle(!isString);
 | 
				
			||||||
 | 
					                            bufferBinEditor.setValue(binBuffer.join(""),1);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        return valid;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    var bufferStringUpdate = function() {
 | 
				
			||||||
 | 
					                        var value = bufferStringEditor.getValue();
 | 
				
			||||||
 | 
					                        var isValidArray = false;
 | 
				
			||||||
 | 
					                        if (/^[\s]*\[[\s\S]*\][\s]*$/.test(value)) {
 | 
				
			||||||
 | 
					                            isValidArray = true;
 | 
				
			||||||
 | 
					                            try {
 | 
				
			||||||
 | 
					                                var data = JSON.parse(value);
 | 
				
			||||||
 | 
					                                isValidArray = buildBuffer(data);
 | 
				
			||||||
 | 
					                            } catch(err) {
 | 
				
			||||||
 | 
					                                isValidArray = false;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        if (!isValidArray) {
 | 
				
			||||||
 | 
					                            buildBuffer(value);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    bufferStringEditor.getSession().on('change', function() {
 | 
				
			||||||
 | 
					                        clearTimeout(changeTimer);
 | 
				
			||||||
 | 
					                        changeTimer = setTimeout(bufferStringUpdate,200);
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    bufferStringUpdate();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    dialogForm.i18n();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    panels = RED.panels.create({
 | 
				
			||||||
 | 
					                        id:"node-input-buffer-panels",
 | 
				
			||||||
 | 
					                        resize: function(p1Height,p2Height) {
 | 
				
			||||||
 | 
					                            var p1 = $("#node-input-buffer-panel-str");
 | 
				
			||||||
 | 
					                            p1Height -= $(p1.children()[0]).outerHeight(true);
 | 
				
			||||||
 | 
					                            var editorRow = $(p1.children()[1]);
 | 
				
			||||||
 | 
					                            p1Height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
 | 
				
			||||||
 | 
					                            $("#node-input-buffer-str").css("height",(p1Height-5)+"px");
 | 
				
			||||||
 | 
					                            bufferStringEditor.resize();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            var p2 = $("#node-input-buffer-panel-bin");
 | 
				
			||||||
 | 
					                            editorRow = $(p2.children()[0]);
 | 
				
			||||||
 | 
					                            p2Height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
 | 
				
			||||||
 | 
					                            $("#node-input-buffer-bin").css("height",(p2Height-5)+"px");
 | 
				
			||||||
 | 
					                            bufferBinEditor.resize();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    $(".node-input-buffer-type").click(function(e) {
 | 
				
			||||||
 | 
					                        e.preventDefault();
 | 
				
			||||||
 | 
					                        RED.sidebar.info.set(RED._("bufferEditor.modeDesc"));
 | 
				
			||||||
 | 
					                        RED.sidebar.info.show();
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                close: function() {
 | 
				
			||||||
 | 
					                    if (options.onclose) {
 | 
				
			||||||
 | 
					                        options.onclose();
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    bufferStringEditor.destroy();
 | 
				
			||||||
 | 
					                    bufferBinEditor.destroy();
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                show: function() {}
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            RED.tray.show(trayOptions);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					})();
 | 
				
			||||||
							
								
								
									
										325
									
								
								editor/js/ui/editors/expression.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										325
									
								
								editor/js/ui/editors/expression.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,325 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Copyright JS Foundation and other contributors, http://js.foundation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					 * you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					 * You may obtain a copy of the License at
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					 * See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					 * limitations under the License.
 | 
				
			||||||
 | 
					 **/
 | 
				
			||||||
 | 
					RED.editor.types._expression = (function() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var template = '<script type="text/x-red" data-template-name="_expression"><div id="node-input-expression-panels"><div id="node-input-expression-panel-expr" class="red-ui-panel"><div class="form-row" style="margin-bottom: 3px; text-align: right;"><span class="node-input-expression-legacy"><i class="fa fa-exclamation-circle"></i> <span data-i18n="expressionEditor.compatMode"></span></span><button id="node-input-expression-reformat" class="editor-button editor-button-small"><span data-i18n="expressionEditor.format"></span></button></div><div class="form-row node-text-editor-row"><div class="node-text-editor" id="node-input-expression"></div></div></div><div id="node-input-expression-panel-info" class="red-ui-panel"><div class="form-row"><ul id="node-input-expression-tabs"></ul><div id="node-input-expression-tab-help" class="node-input-expression-tab-content hide"><div><select id="node-input-expression-func"></select><button id="node-input-expression-func-insert" class="editor-button" data-i18n="expressionEditor.insert"></button></div><div id="node-input-expression-help"></div></div><div id="node-input-expression-tab-test" class="node-input-expression-tab-content hide"><div><span style="display: inline-block; width: calc(50% - 5px);"><span data-i18n="expressionEditor.data"></span><button style="float: right; margin-right: 5px;" id="node-input-example-reformat" class="editor-button editor-button-small"><span data-i18n="jsonEditor.format"></span></button></span><span style="display: inline-block; width: calc(50% - 5px);" data-i18n="expressionEditor.result"></span></div><div style="display: inline-block; width: calc(50% - 5px);" class="node-text-editor" id="node-input-expression-test-data"></div><div style="display: inline-block; width: calc(50% - 5px);" class="node-text-editor" id="node-input-expression-test-result"></div></div></div></div></div></script>';
 | 
				
			||||||
 | 
					    var expressionTestCache = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        init: function() {
 | 
				
			||||||
 | 
					            $(template).appendTo(document.body);
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        show: function(options) {
 | 
				
			||||||
 | 
					            var expressionTestCacheId = options.parent||"_";
 | 
				
			||||||
 | 
					            var value = options.value;
 | 
				
			||||||
 | 
					            var onComplete = options.complete;
 | 
				
			||||||
 | 
					            var type = "_expression"
 | 
				
			||||||
 | 
					            RED.view.state(RED.state.EDITING);
 | 
				
			||||||
 | 
					            var expressionEditor;
 | 
				
			||||||
 | 
					            var testDataEditor;
 | 
				
			||||||
 | 
					            var testResultEditor
 | 
				
			||||||
 | 
					            var panels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var trayOptions = {
 | 
				
			||||||
 | 
					                title: options.title,
 | 
				
			||||||
 | 
					                width: "inherit",
 | 
				
			||||||
 | 
					                buttons: [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        id: "node-dialog-cancel",
 | 
				
			||||||
 | 
					                        text: RED._("common.label.cancel"),
 | 
				
			||||||
 | 
					                        click: function() {
 | 
				
			||||||
 | 
					                            RED.tray.close();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        id: "node-dialog-ok",
 | 
				
			||||||
 | 
					                        text: RED._("common.label.done"),
 | 
				
			||||||
 | 
					                        class: "primary",
 | 
				
			||||||
 | 
					                        click: function() {
 | 
				
			||||||
 | 
					                            $("#node-input-expression-help").html("");
 | 
				
			||||||
 | 
					                            onComplete(expressionEditor.getValue());
 | 
				
			||||||
 | 
					                            RED.tray.close();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                resize: function(dimensions) {
 | 
				
			||||||
 | 
					                    var height = $("#dialog-form").height();
 | 
				
			||||||
 | 
					                    if (panels) {
 | 
				
			||||||
 | 
					                        panels.resize(height);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                open: function(tray) {
 | 
				
			||||||
 | 
					                    var trayBody = tray.find('.editor-tray-body');
 | 
				
			||||||
 | 
					                    trayBody.addClass("node-input-expression-editor")
 | 
				
			||||||
 | 
					                    var dialogForm = RED.editor.buildEditForm(tray.find('.editor-tray-body'),'dialog-form','_expression','editor');
 | 
				
			||||||
 | 
					                    var funcSelect = $("#node-input-expression-func");
 | 
				
			||||||
 | 
					                    Object.keys(jsonata.functions).forEach(function(f) {
 | 
				
			||||||
 | 
					                        funcSelect.append($("<option></option>").val(f).text(f));
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                    funcSelect.change(function(e) {
 | 
				
			||||||
 | 
					                        var f = $(this).val();
 | 
				
			||||||
 | 
					                        var args = RED._('jsonata:'+f+".args",{defaultValue:''});
 | 
				
			||||||
 | 
					                        var title = "<h5>"+f+"("+args+")</h5>";
 | 
				
			||||||
 | 
					                        var body = marked(RED._('jsonata:'+f+'.desc',{defaultValue:''}));
 | 
				
			||||||
 | 
					                        $("#node-input-expression-help").html(title+"<p>"+body+"</p>");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                    expressionEditor = RED.editor.createEditor({
 | 
				
			||||||
 | 
					                        id: 'node-input-expression',
 | 
				
			||||||
 | 
					                        value: "",
 | 
				
			||||||
 | 
					                        mode:"ace/mode/jsonata",
 | 
				
			||||||
 | 
					                        options: {
 | 
				
			||||||
 | 
					                            enableBasicAutocompletion:true,
 | 
				
			||||||
 | 
					                            enableSnippets:true,
 | 
				
			||||||
 | 
					                            enableLiveAutocompletion: true
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                    var currentToken = null;
 | 
				
			||||||
 | 
					                    var currentTokenPos = -1;
 | 
				
			||||||
 | 
					                    var currentFunctionMarker = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    expressionEditor.getSession().setValue(value||"",-1);
 | 
				
			||||||
 | 
					                    expressionEditor.on("changeSelection", function() {
 | 
				
			||||||
 | 
					                        var c = expressionEditor.getCursorPosition();
 | 
				
			||||||
 | 
					                        var token = expressionEditor.getSession().getTokenAt(c.row,c.column);
 | 
				
			||||||
 | 
					                        if (token !== currentToken || (token && /paren/.test(token.type) && c.column !== currentTokenPos)) {
 | 
				
			||||||
 | 
					                            currentToken = token;
 | 
				
			||||||
 | 
					                            var r,p;
 | 
				
			||||||
 | 
					                            var scopedFunction = null;
 | 
				
			||||||
 | 
					                            if (token && token.type === 'keyword') {
 | 
				
			||||||
 | 
					                                r = c.row;
 | 
				
			||||||
 | 
					                                scopedFunction = token;
 | 
				
			||||||
 | 
					                            } else {
 | 
				
			||||||
 | 
					                                var depth = 0;
 | 
				
			||||||
 | 
					                                var next = false;
 | 
				
			||||||
 | 
					                                if (token) {
 | 
				
			||||||
 | 
					                                    if (token.type === 'paren.rparen') {
 | 
				
			||||||
 | 
					                                        // If this is a block of parens ')))', set
 | 
				
			||||||
 | 
					                                        // depth to offset against the cursor position
 | 
				
			||||||
 | 
					                                        // within the block
 | 
				
			||||||
 | 
					                                        currentTokenPos = c.column;
 | 
				
			||||||
 | 
					                                        depth = c.column - (token.start + token.value.length);
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                    r = c.row;
 | 
				
			||||||
 | 
					                                    p = token.index;
 | 
				
			||||||
 | 
					                                } else {
 | 
				
			||||||
 | 
					                                    r = c.row-1;
 | 
				
			||||||
 | 
					                                    p = -1;
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                                while ( scopedFunction === null && r > -1) {
 | 
				
			||||||
 | 
					                                    var rowTokens = expressionEditor.getSession().getTokens(r);
 | 
				
			||||||
 | 
					                                    if (p === -1) {
 | 
				
			||||||
 | 
					                                        p = rowTokens.length-1;
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                    while (p > -1) {
 | 
				
			||||||
 | 
					                                        var type = rowTokens[p].type;
 | 
				
			||||||
 | 
					                                        if (next) {
 | 
				
			||||||
 | 
					                                            if (type === 'keyword') {
 | 
				
			||||||
 | 
					                                                scopedFunction = rowTokens[p];
 | 
				
			||||||
 | 
					                                                // console.log("HIT",scopedFunction);
 | 
				
			||||||
 | 
					                                                break;
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                            next = false;
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                        if (type === 'paren.lparen') {
 | 
				
			||||||
 | 
					                                            depth-=rowTokens[p].value.length;
 | 
				
			||||||
 | 
					                                        } else if (type === 'paren.rparen') {
 | 
				
			||||||
 | 
					                                            depth+=rowTokens[p].value.length;
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                        if (depth < 0) {
 | 
				
			||||||
 | 
					                                            next = true;
 | 
				
			||||||
 | 
					                                            depth = 0;
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                        // console.log(r,p,depth,next,rowTokens[p]);
 | 
				
			||||||
 | 
					                                        p--;
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                    if (!scopedFunction) {
 | 
				
			||||||
 | 
					                                        r--;
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            expressionEditor.session.removeMarker(currentFunctionMarker);
 | 
				
			||||||
 | 
					                            if (scopedFunction) {
 | 
				
			||||||
 | 
					                            //console.log(token,.map(function(t) { return t.type}));
 | 
				
			||||||
 | 
					                                funcSelect.val(scopedFunction.value).change();
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    dialogForm.i18n();
 | 
				
			||||||
 | 
					                    $("#node-input-expression-func-insert").click(function(e) {
 | 
				
			||||||
 | 
					                        e.preventDefault();
 | 
				
			||||||
 | 
					                        var pos = expressionEditor.getCursorPosition();
 | 
				
			||||||
 | 
					                        var f = funcSelect.val();
 | 
				
			||||||
 | 
					                        var snippet = jsonata.getFunctionSnippet(f);
 | 
				
			||||||
 | 
					                        expressionEditor.insertSnippet(snippet);
 | 
				
			||||||
 | 
					                        expressionEditor.focus();
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                    $("#node-input-expression-reformat").click(function(evt) {
 | 
				
			||||||
 | 
					                        evt.preventDefault();
 | 
				
			||||||
 | 
					                        var v = expressionEditor.getValue()||"";
 | 
				
			||||||
 | 
					                        try {
 | 
				
			||||||
 | 
					                            v = jsonata.format(v);
 | 
				
			||||||
 | 
					                        } catch(err) {
 | 
				
			||||||
 | 
					                            // TODO: do an optimistic auto-format
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        expressionEditor.getSession().setValue(v||"",-1);
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var tabs = RED.tabs.create({
 | 
				
			||||||
 | 
					                        element: $("#node-input-expression-tabs"),
 | 
				
			||||||
 | 
					                        onchange:function(tab) {
 | 
				
			||||||
 | 
					                            $(".node-input-expression-tab-content").hide();
 | 
				
			||||||
 | 
					                            tab.content.show();
 | 
				
			||||||
 | 
					                            trayOptions.resize();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    tabs.addTab({
 | 
				
			||||||
 | 
					                        id: 'expression-help',
 | 
				
			||||||
 | 
					                        label: RED._('expressionEditor.functionReference'),
 | 
				
			||||||
 | 
					                        content: $("#node-input-expression-tab-help")
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                    tabs.addTab({
 | 
				
			||||||
 | 
					                        id: 'expression-tests',
 | 
				
			||||||
 | 
					                        label: RED._('expressionEditor.test'),
 | 
				
			||||||
 | 
					                        content: $("#node-input-expression-tab-test")
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                    testDataEditor = RED.editor.createEditor({
 | 
				
			||||||
 | 
					                        id: 'node-input-expression-test-data',
 | 
				
			||||||
 | 
					                        value: expressionTestCache[expressionTestCacheId] || '{\n    "payload": "hello world"\n}',
 | 
				
			||||||
 | 
					                        mode:"ace/mode/json",
 | 
				
			||||||
 | 
					                        lineNumbers: false
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                    var changeTimer;
 | 
				
			||||||
 | 
					                    $(".node-input-expression-legacy").click(function(e) {
 | 
				
			||||||
 | 
					                        e.preventDefault();
 | 
				
			||||||
 | 
					                        RED.sidebar.info.set(RED._("expressionEditor.compatModeDesc"));
 | 
				
			||||||
 | 
					                        RED.sidebar.info.show();
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                    var testExpression = function() {
 | 
				
			||||||
 | 
					                        var value = testDataEditor.getValue();
 | 
				
			||||||
 | 
					                        var parsedData;
 | 
				
			||||||
 | 
					                        var currentExpression = expressionEditor.getValue();
 | 
				
			||||||
 | 
					                        var expr;
 | 
				
			||||||
 | 
					                        var usesContext = false;
 | 
				
			||||||
 | 
					                        var legacyMode = /(^|[^a-zA-Z0-9_'"])msg([^a-zA-Z0-9_'"]|$)/.test(currentExpression);
 | 
				
			||||||
 | 
					                        $(".node-input-expression-legacy").toggle(legacyMode);
 | 
				
			||||||
 | 
					                        try {
 | 
				
			||||||
 | 
					                            expr = jsonata(currentExpression);
 | 
				
			||||||
 | 
					                            expr.assign('flowContext',function(val) {
 | 
				
			||||||
 | 
					                                usesContext = true;
 | 
				
			||||||
 | 
					                                return null;
 | 
				
			||||||
 | 
					                            });
 | 
				
			||||||
 | 
					                            expr.assign('globalContext',function(val) {
 | 
				
			||||||
 | 
					                                usesContext = true;
 | 
				
			||||||
 | 
					                                return null;
 | 
				
			||||||
 | 
					                            });
 | 
				
			||||||
 | 
					                        } catch(err) {
 | 
				
			||||||
 | 
					                            testResultEditor.setValue(RED._("expressionEditor.errors.invalid-expr",{message:err.message}),-1);
 | 
				
			||||||
 | 
					                            return;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        try {
 | 
				
			||||||
 | 
					                            parsedData = JSON.parse(value);
 | 
				
			||||||
 | 
					                        } catch(err) {
 | 
				
			||||||
 | 
					                            testResultEditor.setValue(RED._("expressionEditor.errors.invalid-msg",{message:err.toString()}))
 | 
				
			||||||
 | 
					                            return;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        try {
 | 
				
			||||||
 | 
					                            var result = expr.evaluate(legacyMode?{msg:parsedData}:parsedData);
 | 
				
			||||||
 | 
					                            if (usesContext) {
 | 
				
			||||||
 | 
					                                testResultEditor.setValue(RED._("expressionEditor.errors.context-unsupported"),-1);
 | 
				
			||||||
 | 
					                                return;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            var formattedResult;
 | 
				
			||||||
 | 
					                            if (result !== undefined) {
 | 
				
			||||||
 | 
					                                formattedResult = JSON.stringify(result,null,4);
 | 
				
			||||||
 | 
					                            } else {
 | 
				
			||||||
 | 
					                                formattedResult = RED._("expressionEditor.noMatch");
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            testResultEditor.setValue(formattedResult,-1);
 | 
				
			||||||
 | 
					                        } catch(err) {
 | 
				
			||||||
 | 
					                            testResultEditor.setValue(RED._("expressionEditor.errors.eval",{message:err.message}),-1);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    testDataEditor.getSession().on('change', function() {
 | 
				
			||||||
 | 
					                        clearTimeout(changeTimer);
 | 
				
			||||||
 | 
					                        changeTimer = setTimeout(testExpression,200);
 | 
				
			||||||
 | 
					                        expressionTestCache[expressionTestCacheId] = testDataEditor.getValue();
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                    expressionEditor.getSession().on('change', function() {
 | 
				
			||||||
 | 
					                        clearTimeout(changeTimer);
 | 
				
			||||||
 | 
					                        changeTimer = setTimeout(testExpression,200);
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    testResultEditor = RED.editor.createEditor({
 | 
				
			||||||
 | 
					                        id: 'node-input-expression-test-result',
 | 
				
			||||||
 | 
					                        value: "",
 | 
				
			||||||
 | 
					                        mode:"ace/mode/json",
 | 
				
			||||||
 | 
					                        lineNumbers: false,
 | 
				
			||||||
 | 
					                        readOnly: true
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                    panels = RED.panels.create({
 | 
				
			||||||
 | 
					                        id:"node-input-expression-panels",
 | 
				
			||||||
 | 
					                        resize: function(p1Height,p2Height) {
 | 
				
			||||||
 | 
					                            var p1 = $("#node-input-expression-panel-expr");
 | 
				
			||||||
 | 
					                            p1Height -= $(p1.children()[0]).outerHeight(true);
 | 
				
			||||||
 | 
					                            var editorRow = $(p1.children()[1]);
 | 
				
			||||||
 | 
					                            p1Height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
 | 
				
			||||||
 | 
					                            $("#node-input-expression").css("height",(p1Height-5)+"px");
 | 
				
			||||||
 | 
					                            expressionEditor.resize();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            var p2 = $("#node-input-expression-panel-info > .form-row > div:first-child");
 | 
				
			||||||
 | 
					                            p2Height -= p2.outerHeight(true) + 20;
 | 
				
			||||||
 | 
					                            $(".node-input-expression-tab-content").height(p2Height);
 | 
				
			||||||
 | 
					                            $("#node-input-expression-test-data").css("height",(p2Height-5)+"px");
 | 
				
			||||||
 | 
					                            testDataEditor.resize();
 | 
				
			||||||
 | 
					                            $("#node-input-expression-test-result").css("height",(p2Height-5)+"px");
 | 
				
			||||||
 | 
					                            testResultEditor.resize();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    $("#node-input-example-reformat").click(function(evt) {
 | 
				
			||||||
 | 
					                        evt.preventDefault();
 | 
				
			||||||
 | 
					                        var v = testDataEditor.getValue()||"";
 | 
				
			||||||
 | 
					                        try {
 | 
				
			||||||
 | 
					                            v = JSON.stringify(JSON.parse(v),null,4);
 | 
				
			||||||
 | 
					                        } catch(err) {
 | 
				
			||||||
 | 
					                            // TODO: do an optimistic auto-format
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        testDataEditor.getSession().setValue(v||"",-1);
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    testExpression();
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                close: function() {
 | 
				
			||||||
 | 
					                    if (options.onclose) {
 | 
				
			||||||
 | 
					                        options.onclose();
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    expressionEditor.destroy();
 | 
				
			||||||
 | 
					                    testDataEditor.destroy();
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                show: function() {}
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            RED.tray.show(trayOptions);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					})();
 | 
				
			||||||
							
								
								
									
										118
									
								
								editor/js/ui/editors/json.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								editor/js/ui/editors/json.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,118 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Copyright JS Foundation and other contributors, http://js.foundation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					 * you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					 * You may obtain a copy of the License at
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					 * See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					 * limitations under the License.
 | 
				
			||||||
 | 
					 **/
 | 
				
			||||||
 | 
					RED.editor.types._json = (function() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var template = '<script type="text/x-red" data-template-name="_json"><div class="form-row" style="margin-bottom: 3px; text-align: right;"><button id="node-input-json-reformat" class="editor-button editor-button-small"><span data-i18n="jsonEditor.format"></span></button></div><div class="form-row node-text-editor-row"><div style="height: 200px;min-height: 150px;" class="node-text-editor" id="node-input-json"></div></div></script>';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        init: function() {
 | 
				
			||||||
 | 
					            $(template).appendTo(document.body);
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        show: function(options) {
 | 
				
			||||||
 | 
					            var value = options.value;
 | 
				
			||||||
 | 
					            var onComplete = options.complete;
 | 
				
			||||||
 | 
					            var type = "_json"
 | 
				
			||||||
 | 
					            RED.view.state(RED.state.EDITING);
 | 
				
			||||||
 | 
					            var expressionEditor;
 | 
				
			||||||
 | 
					            var changeTimer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var checkValid = function() {
 | 
				
			||||||
 | 
					                var v = expressionEditor.getValue();
 | 
				
			||||||
 | 
					                try {
 | 
				
			||||||
 | 
					                    JSON.parse(v);
 | 
				
			||||||
 | 
					                    $("#node-dialog-ok").removeClass('disabled');
 | 
				
			||||||
 | 
					                    return true;
 | 
				
			||||||
 | 
					                } catch(err) {
 | 
				
			||||||
 | 
					                    $("#node-dialog-ok").addClass('disabled');
 | 
				
			||||||
 | 
					                    return false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            var trayOptions = {
 | 
				
			||||||
 | 
					                title: options.title,
 | 
				
			||||||
 | 
					                width: "inherit",
 | 
				
			||||||
 | 
					                buttons: [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        id: "node-dialog-cancel",
 | 
				
			||||||
 | 
					                        text: RED._("common.label.cancel"),
 | 
				
			||||||
 | 
					                        click: function() {
 | 
				
			||||||
 | 
					                            RED.tray.close();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        id: "node-dialog-ok",
 | 
				
			||||||
 | 
					                        text: RED._("common.label.done"),
 | 
				
			||||||
 | 
					                        class: "primary",
 | 
				
			||||||
 | 
					                        click: function() {
 | 
				
			||||||
 | 
					                            if (options.requireValid && !checkValid()) {
 | 
				
			||||||
 | 
					                                return;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            onComplete(expressionEditor.getValue());
 | 
				
			||||||
 | 
					                            RED.tray.close();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                resize: function(dimensions) {
 | 
				
			||||||
 | 
					                    var rows = $("#dialog-form>div:not(.node-text-editor-row)");
 | 
				
			||||||
 | 
					                    var editorRow = $("#dialog-form>div.node-text-editor-row");
 | 
				
			||||||
 | 
					                    var height = $("#dialog-form").height();
 | 
				
			||||||
 | 
					                    for (var i=0;i<rows.size();i++) {
 | 
				
			||||||
 | 
					                        height -= $(rows[i]).outerHeight(true);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    height -= (parseInt($("#dialog-form").css("marginTop"))+parseInt($("#dialog-form").css("marginBottom")));
 | 
				
			||||||
 | 
					                    $(".node-text-editor").css("height",height+"px");
 | 
				
			||||||
 | 
					                    expressionEditor.resize();
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                open: function(tray) {
 | 
				
			||||||
 | 
					                    var trayBody = tray.find('.editor-tray-body');
 | 
				
			||||||
 | 
					                    var dialogForm = RED.editor.buildEditForm(tray.find('.editor-tray-body'),'dialog-form',type,'editor');
 | 
				
			||||||
 | 
					                    expressionEditor = RED.editor.createEditor({
 | 
				
			||||||
 | 
					                        id: 'node-input-json',
 | 
				
			||||||
 | 
					                        value: "",
 | 
				
			||||||
 | 
					                        mode:"ace/mode/json"
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                    expressionEditor.getSession().setValue(value||"",-1);
 | 
				
			||||||
 | 
					                    if (options.requireValid) {
 | 
				
			||||||
 | 
					                        expressionEditor.getSession().on('change', function() {
 | 
				
			||||||
 | 
					                            clearTimeout(changeTimer);
 | 
				
			||||||
 | 
					                            changeTimer = setTimeout(checkValid,200);
 | 
				
			||||||
 | 
					                        });
 | 
				
			||||||
 | 
					                        checkValid();
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    $("#node-input-json-reformat").click(function(evt) {
 | 
				
			||||||
 | 
					                        evt.preventDefault();
 | 
				
			||||||
 | 
					                        var v = expressionEditor.getValue()||"";
 | 
				
			||||||
 | 
					                        try {
 | 
				
			||||||
 | 
					                            v = JSON.stringify(JSON.parse(v),null,4);
 | 
				
			||||||
 | 
					                        } catch(err) {
 | 
				
			||||||
 | 
					                            // TODO: do an optimistic auto-format
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        expressionEditor.getSession().setValue(v||"",-1);
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                    dialogForm.i18n();
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                close: function() {
 | 
				
			||||||
 | 
					                    expressionEditor.destroy();
 | 
				
			||||||
 | 
					                    if (options.onclose) {
 | 
				
			||||||
 | 
					                        options.onclose();
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                show: function() {}
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            RED.tray.show(trayOptions);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					})();
 | 
				
			||||||
							
								
								
									
										90
									
								
								editor/js/ui/editors/markdown.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								editor/js/ui/editors/markdown.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,90 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Copyright JS Foundation and other contributors, http://js.foundation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					 * you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					 * You may obtain a copy of the License at
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					 * See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					 * limitations under the License.
 | 
				
			||||||
 | 
					 **/
 | 
				
			||||||
 | 
					RED.editor.types._markdown = (function() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var template = '<script type="text/x-red" data-template-name="_markdown"><div class="form-row" id="node-input-markdown-title" style="margin-bottom: 3px; text-align: right;"></div><div class="form-row node-text-editor-row"><div style="height: 200px;min-height: 150px;" class="node-text-editor" id="node-input-markdown"></div></div></script>';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        init: function() {
 | 
				
			||||||
 | 
					            $(template).appendTo(document.body);
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        show: function(options) {
 | 
				
			||||||
 | 
					            var value = options.value;
 | 
				
			||||||
 | 
					            var onComplete = options.complete;
 | 
				
			||||||
 | 
					            var type = "_markdown"
 | 
				
			||||||
 | 
					            RED.view.state(RED.state.EDITING);
 | 
				
			||||||
 | 
					            var expressionEditor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var trayOptions = {
 | 
				
			||||||
 | 
					                title: options.title,
 | 
				
			||||||
 | 
					                width: "inherit",
 | 
				
			||||||
 | 
					                buttons: [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        id: "node-dialog-cancel",
 | 
				
			||||||
 | 
					                        text: RED._("common.label.cancel"),
 | 
				
			||||||
 | 
					                        click: function() {
 | 
				
			||||||
 | 
					                            RED.tray.close();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        id: "node-dialog-ok",
 | 
				
			||||||
 | 
					                        text: RED._("common.label.done"),
 | 
				
			||||||
 | 
					                        class: "primary",
 | 
				
			||||||
 | 
					                        click: function() {
 | 
				
			||||||
 | 
					                            onComplete(expressionEditor.getValue());
 | 
				
			||||||
 | 
					                            RED.tray.close();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                resize: function(dimensions) {
 | 
				
			||||||
 | 
					                    var rows = $("#dialog-form>div:not(.node-text-editor-row)");
 | 
				
			||||||
 | 
					                    var editorRow = $("#dialog-form>div.node-text-editor-row");
 | 
				
			||||||
 | 
					                    var height = $("#dialog-form").height();
 | 
				
			||||||
 | 
					                    for (var i=0;i<rows.size();i++) {
 | 
				
			||||||
 | 
					                        height -= $(rows[i]).outerHeight(true);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    height -= (parseInt($("#dialog-form").css("marginTop"))+parseInt($("#dialog-form").css("marginBottom")));
 | 
				
			||||||
 | 
					                    $(".node-text-editor").css("height",height+"px");
 | 
				
			||||||
 | 
					                    expressionEditor.resize();
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                open: function(tray) {
 | 
				
			||||||
 | 
					                    var trayBody = tray.find('.editor-tray-body');
 | 
				
			||||||
 | 
					                    var dialogForm = RED.editor.buildEditForm(tray.find('.editor-tray-body'),'dialog-form',type,'editor');
 | 
				
			||||||
 | 
					                    expressionEditor = RED.editor.createEditor({
 | 
				
			||||||
 | 
					                        id: 'node-input-markdown',
 | 
				
			||||||
 | 
					                        value: value,
 | 
				
			||||||
 | 
					                        mode:"ace/mode/markdown"
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                    if (options.header) {
 | 
				
			||||||
 | 
					                        options.header.appendTo(tray.find('#node-input-markdown-title'));
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    dialogForm.i18n();
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                close: function() {
 | 
				
			||||||
 | 
					                    expressionEditor.destroy();
 | 
				
			||||||
 | 
					                    if (options.onclose) {
 | 
				
			||||||
 | 
					                        options.onclose();
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                show: function() {}
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            RED.tray.show(trayOptions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					})();
 | 
				
			||||||
@@ -18,6 +18,12 @@ RED.library = (function() {
 | 
				
			|||||||
    var exportToLibraryDialog;
 | 
					    var exportToLibraryDialog;
 | 
				
			||||||
    var elementPrefix = "node-input-";
 | 
					    var elementPrefix = "node-input-";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var _librarySaveConfirm = '<div id="node-dialog-library-save-confirm" class="hide"><form class="form-horizontal"><div style="text-align: center; padding-top: 30px;" id="node-dialog-library-save-content"></div></form></div>';
 | 
				
			||||||
 | 
					    var _librarySave = '<div id="node-dialog-library-save" class="hide"><form class="form-horizontal"><div class="form-row"><label for="node-dialog-library-save-folder" data-i18n="[append]library.folder"><i class="fa fa-folder-open"></i> </label><input type="text" id="node-dialog-library-save-folder" data-i18n="[placeholder]library.folderPlaceholder"></div><div class="form-row"><label for="node-dialog-library-save-filename" data-i18n="[append]library.filename"><i class="fa fa-file"></i> </label><input type="text" id="node-dialog-library-save-filename" data-i18n="[placeholder]library.filenamePlaceholder"></div></form></div>';
 | 
				
			||||||
 | 
					    var _libraryLookup = '<div id="node-dialog-library-lookup" class="hide"><form class="form-horizontal"><div class="form-row"><ul id="node-dialog-library-breadcrumbs" class="breadcrumb"><li class="active"><a href="#" data-i18n="[append]library.breadcrumb"></a></li></ul></div><div class="form-row"><div style="vertical-align: top; display: inline-block; height: 100%; width: 30%; padding-right: 20px;"><div id="node-select-library" style="border: 1px solid #999; width: 100%; height: 100%; overflow:scroll;"><ul></ul></div></div><div style="vertical-align: top; display: inline-block;width: 65%; height: 100%;"><div style="height: 100%; width: 95%;" class="node-text-editor" id="node-select-library-text" ></div></div></div></form></div>';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function loadFlowLibrary() {
 | 
					    function loadFlowLibrary() {
 | 
				
			||||||
        $.getJSON("library/flows",function(data) {
 | 
					        $.getJSON("library/flows",function(data) {
 | 
				
			||||||
            //console.log(data);
 | 
					            //console.log(data);
 | 
				
			||||||
@@ -410,6 +416,11 @@ RED.library = (function() {
 | 
				
			|||||||
    return {
 | 
					    return {
 | 
				
			||||||
        init: function() {
 | 
					        init: function() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $(_librarySave).appendTo(document.body);
 | 
				
			||||||
 | 
					            $(_librarySaveConfirm).appendTo(document.body);
 | 
				
			||||||
 | 
					            $(_libraryLookup).appendTo(document.body);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            RED.actions.add("core:library-export",exportFlow);
 | 
					            RED.actions.add("core:library-export",exportFlow);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            RED.events.on("view:selection-changed",function(selection) {
 | 
					            RED.events.on("view:selection-changed",function(selection) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,10 @@
 | 
				
			|||||||
RED.subflow = (function() {
 | 
					RED.subflow = (function() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var _subflowEditTemplate = '<script type="text/x-red" data-template-name="subflow"><div class="form-row"><label for="node-input-name" data-i18n="[append]editor:common.label.name"><i class="fa fa-tag"></i> </label><input type="text" id="node-input-name"></div></script>';
 | 
				
			||||||
 | 
					    var _subflowTemplateEditTemplate = '<script type="text/x-red" data-template-name="subflow-template"><div class="form-row"><i class="fa fa-tag"></i><label for="subflow-input-name" data-i18n="common.label.name"></label><input type="text" id="subflow-input-name"></div><div class="form-row" style="margin-bottom: 0px;"><label for="subflow-input-info" data-i18n="editor:subflow.info"></label><a href="https://help.github.com/articles/markdown-basics/" style="font-size: 0.8em; float: right;" data-i18n="[html]subflow.format"></a></div><div class="form-row node-text-editor-row"><div style="height: 250px;" class="node-text-editor" id="subflow-input-info-editor"></div></div><div class="form-row form-tips" id="subflow-dialog-user-count"></div></script>';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function getSubflow() {
 | 
					    function getSubflow() {
 | 
				
			||||||
        return RED.nodes.subflow(RED.workspaces.active());
 | 
					        return RED.nodes.subflow(RED.workspaces.active());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -386,6 +390,10 @@ RED.subflow = (function() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        RED.actions.add("core:create-subflow",createSubflow);
 | 
					        RED.actions.add("core:create-subflow",createSubflow);
 | 
				
			||||||
        RED.actions.add("core:convert-to-subflow",convertToSubflow);
 | 
					        RED.actions.add("core:convert-to-subflow",convertToSubflow);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $(_subflowEditTemplate).appendTo(document.body);
 | 
				
			||||||
 | 
					        $(_subflowTemplateEditTemplate).appendTo(document.body);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function createSubflow() {
 | 
					    function createSubflow() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -82,134 +82,6 @@
 | 
				
			|||||||
<div id="notifications"></div>
 | 
					<div id="notifications"></div>
 | 
				
			||||||
<div id="dropTarget"><div data-i18n="[append]workspace.dropFlowHere"><br/><i class="fa fa-download"></i></div></div>
 | 
					<div id="dropTarget"><div data-i18n="[append]workspace.dropFlowHere"><br/><i class="fa fa-download"></i></div></div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<div id="node-dialog-library-save-confirm" class="hide">
 | 
					 | 
				
			||||||
    <form class="form-horizontal">
 | 
					 | 
				
			||||||
        <div style="text-align: center; padding-top: 30px;" id="node-dialog-library-save-content">
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
    </form>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<div id="node-dialog-library-save" class="hide">
 | 
					 | 
				
			||||||
    <form class="form-horizontal">
 | 
					 | 
				
			||||||
        <div class="form-row">
 | 
					 | 
				
			||||||
            <label for="node-dialog-library-save-folder" data-i18n="[append]library.folder"><i class="fa fa-folder-open"></i> </label>
 | 
					 | 
				
			||||||
            <input type="text" id="node-dialog-library-save-folder" data-i18n="[placeholder]library.folderPlaceholder">
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
        <div class="form-row">
 | 
					 | 
				
			||||||
            <label for="node-dialog-library-save-filename" data-i18n="[append]library.filename"><i class="fa fa-file"></i> </label>
 | 
					 | 
				
			||||||
            <input type="text" id="node-dialog-library-save-filename" data-i18n="[placeholder]library.filenamePlaceholder">
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
    </form>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<div id="node-dialog-library-lookup" class="hide">
 | 
					 | 
				
			||||||
    <form class="form-horizontal">
 | 
					 | 
				
			||||||
        <div class="form-row">
 | 
					 | 
				
			||||||
            <ul id="node-dialog-library-breadcrumbs" class="breadcrumb">
 | 
					 | 
				
			||||||
                <li class="active"><a href="#" data-i18n="[append]library.breadcrumb"></a></li>
 | 
					 | 
				
			||||||
            </ul>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
        <div class="form-row">
 | 
					 | 
				
			||||||
            <div style="vertical-align: top; display: inline-block; height: 100%; width: 30%; padding-right: 20px;">
 | 
					 | 
				
			||||||
                <div id="node-select-library" style="border: 1px solid #999; width: 100%; height: 100%; overflow:scroll;"><ul></ul></div>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
            <div style="vertical-align: top; display: inline-block;width: 65%; height: 100%;">
 | 
					 | 
				
			||||||
                <div style="height: 100%; width: 95%;" class="node-text-editor" id="node-select-library-text" ></div>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
    </form>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
<script type="text/x-red" data-template-name="subflow">
 | 
					 | 
				
			||||||
    <div class="form-row">
 | 
					 | 
				
			||||||
        <label for="node-input-name" data-i18n="[append]editor:common.label.name"><i class="fa fa-tag"></i> </label>
 | 
					 | 
				
			||||||
        <input type="text" id="node-input-name">
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
</script>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<script type="text/x-red" data-template-name="subflow-template">
 | 
					 | 
				
			||||||
    <div class="form-row">
 | 
					 | 
				
			||||||
        <i class="fa fa-tag"></i>
 | 
					 | 
				
			||||||
        <label for="subflow-input-name" data-i18n="common.label.name"></label><input type="text" id="subflow-input-name">
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
    <div class="form-row" style="margin-bottom: 0px;">
 | 
					 | 
				
			||||||
        <label for="subflow-input-info" data-i18n="editor:subflow.info"></label>
 | 
					 | 
				
			||||||
        <a href="https://help.github.com/articles/markdown-basics/" style="font-size: 0.8em; float: right;" data-i18n="[html]subflow.format"></a>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
    <div class="form-row node-text-editor-row">
 | 
					 | 
				
			||||||
        <div style="height: 250px;" class="node-text-editor" id="subflow-input-info-editor"></div>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
    <div class="form-row form-tips" id="subflow-dialog-user-count"></div>
 | 
					 | 
				
			||||||
</script>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<script type="text/x-red" data-template-name="_expression">
 | 
					 | 
				
			||||||
    <div id="node-input-expression-panels">
 | 
					 | 
				
			||||||
        <div id="node-input-expression-panel-expr" class="red-ui-panel">
 | 
					 | 
				
			||||||
            <div class="form-row" style="margin-bottom: 3px; text-align: right;">
 | 
					 | 
				
			||||||
                <span class="node-input-expression-legacy"><i class="fa fa-exclamation-circle"></i> <span data-i18n="expressionEditor.compatMode"></span></span>
 | 
					 | 
				
			||||||
                <button id="node-input-expression-reformat" class="editor-button editor-button-small"><span data-i18n="expressionEditor.format"></span></button>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
            <div class="form-row node-text-editor-row">
 | 
					 | 
				
			||||||
                <div class="node-text-editor" id="node-input-expression"></div>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
        <div id="node-input-expression-panel-info" class="red-ui-panel">
 | 
					 | 
				
			||||||
            <div class="form-row">
 | 
					 | 
				
			||||||
                <ul id="node-input-expression-tabs"></ul>
 | 
					 | 
				
			||||||
                <div id="node-input-expression-tab-help" class="node-input-expression-tab-content hide">
 | 
					 | 
				
			||||||
                    <div>
 | 
					 | 
				
			||||||
                        <select id="node-input-expression-func"></select>
 | 
					 | 
				
			||||||
                        <button id="node-input-expression-func-insert" class="editor-button" data-i18n="expressionEditor.insert"></button>
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                    <div id="node-input-expression-help"></div>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
                <div id="node-input-expression-tab-test" class="node-input-expression-tab-content hide">
 | 
					 | 
				
			||||||
                    <div>
 | 
					 | 
				
			||||||
                        <span style="display: inline-block; width: calc(50% - 5px);">
 | 
					 | 
				
			||||||
                            <span data-i18n="expressionEditor.data"></span>
 | 
					 | 
				
			||||||
                            <button style="float: right; margin-right: 5px;" id="node-input-example-reformat" class="editor-button editor-button-small"><span data-i18n="jsonEditor.format"></span></button>
 | 
					 | 
				
			||||||
                        </span>
 | 
					 | 
				
			||||||
                        <span style="display: inline-block; width: calc(50% - 5px);" data-i18n="expressionEditor.result"></span>
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                    <div style="display: inline-block; width: calc(50% - 5px);" class="node-text-editor" id="node-input-expression-test-data"></div>
 | 
					 | 
				
			||||||
                    <div style="display: inline-block; width: calc(50% - 5px);" class="node-text-editor" id="node-input-expression-test-result"></div>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
</script>
 | 
					 | 
				
			||||||
<script type="text/x-red" data-template-name="_json">
 | 
					 | 
				
			||||||
    <div class="form-row" style="margin-bottom: 3px; text-align: right;">
 | 
					 | 
				
			||||||
        <button id="node-input-json-reformat" class="editor-button editor-button-small"><span data-i18n="jsonEditor.format"></span></button>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
    <div class="form-row node-text-editor-row">
 | 
					 | 
				
			||||||
        <div style="height: 200px;min-height: 150px;" class="node-text-editor" id="node-input-json"></div>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
</script>
 | 
					 | 
				
			||||||
<script type="text/x-red" data-template-name="_markdown">
 | 
					 | 
				
			||||||
    <div class="form-row" id="node-input-markdown-title" style="margin-bottom: 3px; text-align: right;">
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
    <div class="form-row node-text-editor-row">
 | 
					 | 
				
			||||||
        <div style="height: 200px;min-height: 150px;" class="node-text-editor" id="node-input-markdown"></div>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
</script>
 | 
					 | 
				
			||||||
<script type="text/x-red" data-template-name="_buffer">
 | 
					 | 
				
			||||||
    <div id="node-input-buffer-panels">
 | 
					 | 
				
			||||||
        <div id="node-input-buffer-panel-str" class="red-ui-panel">
 | 
					 | 
				
			||||||
            <div class="form-row" style="margin-bottom: 3px; text-align: right;">
 | 
					 | 
				
			||||||
                <span class="node-input-buffer-type"><i class="fa fa-exclamation-circle"></i> <span id="node-input-buffer-type-string" data-i18n="bufferEditor.modeString"></span><span id="node-input-buffer-type-array" data-i18n="bufferEditor.modeArray"></span></span>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
            <div class="form-row node-text-editor-row">
 | 
					 | 
				
			||||||
                <div class="node-text-editor" id="node-input-buffer-str"></div>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
        <div id="node-input-buffer-panel-bin" class="red-ui-panel">
 | 
					 | 
				
			||||||
            <div class="form-row node-text-editor-row" style="margin-top: 10px">
 | 
					 | 
				
			||||||
                <div class="node-text-editor" id="node-input-buffer-bin"></div>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
</script>
 | 
					 | 
				
			||||||
<script src="vendor/vendor.js"></script>
 | 
					<script src="vendor/vendor.js"></script>
 | 
				
			||||||
<script src="vendor/jsonata/jsonata.min.js"></script>
 | 
					<script src="vendor/jsonata/jsonata.min.js"></script>
 | 
				
			||||||
<script src="vendor/ace/ace.js"></script>
 | 
					<script src="vendor/ace/ace.js"></script>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user