<commit_before>
<script type="text/html" data-template-name="debug">
    <div class="form-row">
        <label for="node-input-typed-complete"><i class="fa fa-list"></i> <span data-i18n="debug.output"></span></label>
        <input id="node-input-typed-complete" type="text" style="width: 70%">
        <input id="node-input-complete" type="hidden">
        <input id="node-input-targetType" type="hidden">
    </div>
    <div class="form-row">
        <label for="node-input-tosidebar"><i class="fa fa-random"></i> <span data-i18n="debug.to"></span></label>
        <label for="node-input-tosidebar" style="width:70%">
        <input type="checkbox" id="node-input-tosidebar" style="display:inline-block; width:22px; vertical-align:top;"><span data-i18n="debug.toSidebar"></span>
        </label>
    </div>
    <div class="form-row">
        <label for="node-input-console"> </label>
        <label for="node-input-console" style="width:70%">
        <input type="checkbox" id="node-input-console" style="display:inline-block; width:22px; vertical-align:top;"><span data-i18n="debug.toConsole"></span>
        </label>
    </div>
    <div class="form-row">
    <label for="node-input-tostatus"> </label>
    <label for="node-input-tostatus" style="width:70%">
        <input type="checkbox" id="node-input-tostatus" style="display:inline-block; width:22px; vertical-align:top;"><span data-i18n="debug.toStatus"></span>
    </label>
    </div>
    <div class="form-row" id="node-tostatus-line">
        <label for="node-input-typed-status"></label>
        <input id="node-input-typed-status" type="text" style="width: 70%">
        <input id="node-input-statusVal" type="hidden">
        <input id="node-input-statusType" type="hidden">
    </div>
    <div class="form-row">
        <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
        <input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
    </div>
</script>

<script src="debug/view/debug-utils.js"></script>

<script type="text/javascript">
(function() {
    var subWindow = null;

    function activateAjaxCall(node, active, successCallback) {
        var url;
        var body;

        if (Array.isArray(node)) {
            url = "debug/"+(active?"enable":"disable");
            body = {nodes: node.map(function(n) { return n.id})}
            node = node[0];
        } else {
            url = "debug/"+node.id+"/"+(active?"enable":"disable");
        }
        $.ajax({
            url: url,
            type: "POST",
            data: body,
            success: successCallback,
            error: function(jqXHR,textStatus,errorThrown) {
                if (jqXHR.status == 404) {
                    RED.notify(node._("common.notification.error", {message: node._("common.notification.errors.not-deployed")}),"error");
                } else if (jqXHR.status === 0) {
                    RED.notify(node._("common.notification.error", {message: node._("common.notification.errors.no-response")}),"error");
                } else {
                    // TODO where is the err.status comming from?
                    RED.notify(node._("common.notification.error",{message:node._("common.notification.errors.unexpected",{status:err.status,message:err.response})}),"error");
                }
            }
        });
    }

    RED.nodes.registerType('debug',{
        category: 'common',
        defaults: {
            name: {value:""},
            active: {value:true},
            tosidebar: {value:true},
            console: {value:false},
            tostatus: {value:false},
            complete: {value:"false", required:true},
            targetType: {value:undefined},
            statusVal: {value:""},
            statusType: {value:"auto"}
        },
        label: function() {
            var suffix = "";
            if (this.console === true || this.console === "true") { suffix = " ⇲"; }
            if (this.targetType === "jsonata") {
                return (this.name || "JSONata") + suffix;
            }
            if (this.complete === true || this.complete === "true") {
                return (this.name||"msg") + suffix;
            } else {
                return (this.name || "msg." + ((!this.complete || this.complete === "false") ? "payload" : this.complete)) + suffix;
            }
        },
        labelStyle: function() {
            return this.name?"node_label_italic":"";
        },
        color:"#87a980",
        inputs:1,
        outputs:0,
        icon: "debug.svg",
        align: "right",
        button: {
            toggle: "active",
            visible: function() { return this.tosidebar; },
            onclick: function() {
                var label = this.name||"debug";
                var node = this;
                activateAjaxCall(node, node.active, function(resp, textStatus, xhr) {
                    var historyEvent = {
                        t:'edit',
                        node:node,
                        changes:{
                            active:!node.active
                        },
                        dirty:node.dirty,
                        changed:node.changed,
                        callback: function(ev) {
                            activateAjaxCall(ev.node, ev.node.active);
                        }
                    };
                    node.changed = true;
                    node.dirty = true;
                    RED.nodes.dirty(true);
                    RED.history.push(historyEvent);
                    RED.view.redraw();
                    if (xhr.status == 200) {
                        RED.notify(node._("debug.notification.activated",{label:label}),"success");
                    } else if (xhr.status == 201) {
                        RED.notify(node._("debug.notification.deactivated",{label:label}),"success");
                    }
                });
            }
        },
        onpaletteadd: function() {
            var options = {
                messageMouseEnter: function(sourceId) {
                    if (sourceId) {
                        var n = RED.nodes.node(sourceId);
                        if (n) {
                            n.highlighted = true;
                            n.dirty = true;
                        }
                        RED.view.redraw();
                    }
                },
                messageMouseLeave: function(sourceId) {
                    if (sourceId) {
                        var n = RED.nodes.node(sourceId);
                        if (n) {
                            n.highlighted = false;
                            n.dirty = true;
                        }
                        RED.view.redraw();
                    }
                },
                messageSourceClick: function(sourceId, aliasId, path) {
                    // Get all of the nodes that could have logged this message
                    var candidateNodes = [RED.nodes.node(sourceId)]
                    if (path) {
                        for (var i=2;i<path.length;i++) {
                            candidateNodes.push(RED.nodes.node(path[i]))
                        }
                    }
                    if (aliasId) {
                        candidateNodes.push(RED.nodes.node(aliasId));
                    }
                    if (candidateNodes.length > 1) {
                        // The node is in a subflow. Check to see if the active
                        // workspace is a subflow in the node's parentage. If
                        // so, reveal the relevant subflow instance node.
                        var ws = RED.workspaces.active();
                        for (var i=0;i<candidateNodes.length;i++) {
                            if (candidateNodes[i].z === ws) {
                                RED.view.reveal(candidateNodes[i].id);
                                return
                            }
                        }
                        // The active workspace is unrelated to the node. So
                        // fall back to revealing the top most node
                    }
                    RED.view.reveal(candidateNodes[0].id);
                },
                clear: function() {
                    RED.nodes.eachNode(function(node) {
                        node.highlighted = false;
                        node.dirty = true;
                    });
                    RED.view.redraw();
                }
            };

            var uiComponents = RED.debug.init(options);

            RED.sidebar.addTab({
                id: "debug",
                label: this._("debug.sidebar.label"),
                name: this._("debug.sidebar.name"),
                content: uiComponents.content,
                toolbar: uiComponents.footer,
                enableOnEdit: true,
                pinned: true,
                iconClass: "fa fa-bug",
                action: "core:show-debug-tab"
            });
            RED.actions.add("core:show-debug-tab",function() { RED.sidebar.show('debug'); });

            var that = this;
            RED._debug = function(msg) {
                that.handleDebugMessage("", {
                    name:"debug",
                    msg:msg
                });
            };

            this.refreshMessageList = function() {
                RED.debug.refreshMessageList(RED.workspaces.active());
                if (subWindow) {
                    try {
                        subWindow.postMessage({event:"workspaceChange",activeWorkspace:RED.workspaces.active()},"*");
                    } catch(err) {
                        console.log(err);
                    }
                }
            };
            RED.events.on("workspace:change", this.refreshMessageList);

            this.handleDebugMessage = function(t,o) {
                // console.log("->",o.id,o.z,o._alias);
                //
                // sourceNode should be the top-level node - one that is on a flow.
                var sourceNode;
                var pathParts;
                if (o.path) {
                    // Path is a `/`-separated list of ids that identifies the
                    // complete parentage of the node that generated this message.
                    //    flow-id/subflow-A-instance/subflow-A-type/subflow-B-instance/subflow-B-type/node-id

                    // If it has one id, that is a top level flow
                    // each subsequent id is the instance id of a subflow node
                    //
                    pathParts = o.path.split("/");
                    if (pathParts.length === 1) {
                        // The source node is on a flow - so can use its id to find
                        sourceNode = RED.nodes.node(o.id);
                    } else if (pathParts.length > 1) {
                        // Highlight the subflow instance node.
                        sourceNode = RED.nodes.node(pathParts[1]);
                    }
                } else {
                    // This is probably redundant...
                    sourceNode = RED.nodes.node(o.id) || RED.nodes.node(o.z);
                }
                if (sourceNode) {
                    o._source = {
                        id:sourceNode.id,
                        z:sourceNode.z,
                        name:sourceNode.name,
                        type:sourceNode.type,
                        // _alias identifies the actual logging node. This is
                        // not necessarily the same as sourceNode, which will be
                        // the top-level subflow instance node.
                        // This means the node's name is displayed in the sidebar.
                        _alias:o._alias,
                        path: pathParts
                    };
                }
                RED.debug.handleDebugMessage(o);
                if (subWindow) {
                    try {
                        subWindow.postMessage({event:"message",msg:o},"*");
                    } catch(err) {
                        console.log(err);
                    }
                }
            };
            RED.comms.subscribe("debug",this.handleDebugMessage);

            this.clearMessageList = function() {
                RED.debug.clearMessageList(true);
                if (subWindow) {
                    try {
                        subWindow.postMessage({event:"projectChange"},"*");
                    } catch(err) {
                        console.log(err);
                    }
                }
            };
            RED.events.on("project:change", this.clearMessageList);
            RED.actions.add("core:clear-debug-messages", function() { RED.debug.clearMessageList(true) });

            RED.actions.add("core:activate-selected-debug-nodes", function() { setDebugNodeState(getSelectedDebugNodes(true), true); });
            RED.actions.add("core:activate-all-debug-nodes", function() { setDebugNodeState(getMatchingDebugNodes(true, true),true); });
            RED.actions.add("core:activate-all-flow-debug-nodes", function() { setDebugNodeState(getMatchingDebugNodes(true, false),true); });

            RED.actions.add("core:deactivate-selected-debug-nodes", function() { setDebugNodeState(getSelectedDebugNodes(false), false); });
            RED.actions.add("core:deactivate-all-debug-nodes", function() { setDebugNodeState(getMatchingDebugNodes(false, true),false); });
            RED.actions.add("core:deactivate-all-flow-debug-nodes", function() { setDebugNodeState(getMatchingDebugNodes(false, false),false); });

            function getSelectedDebugNodes(state) {
                var nodes = [];
                var selection = RED.view.selection();
                if (selection.nodes) {
                    selection.nodes.forEach(function(n) {
                        if (RED.nodes.subflow(n.z)) {
                            return;
                        }
                        if (n.type === 'debug' && n.active !== state) {
                            nodes.push(n);
                        } else if (n.type === 'group') {
                            nodes = nodes.concat( RED.group.getNodes(n,true).filter(function(n) {
                                return n.type === 'debug' && n.active !== state
                            }));
                        }
                    });
                }
                return nodes;

            }
            function getMatchingDebugNodes(state,globally) {
                var nodes = [];
                var filter = {type:"debug"};
                if (!globally) {
                    filter.z = RED.workspaces.active();
                }
                var candidateNodes = RED.nodes.filterNodes(filter);
                nodes = candidateNodes.filter(function(n) {
                    return n.active !== state && !RED.nodes.subflow(n.z)
                })
                return nodes;
            }

            function setDebugNodeState(nodes,state) {
                var historyEvents = [];
                if (nodes.length > 0) {
                    activateAjaxCall(nodes,false, function(resp, textStatus, xhr) {
                        nodes.forEach(function(n) {
                            historyEvents.push({
                                t: "edit",
                                node: n,
                                changed: n.changed,
                                changes: {
                                    active: n.active
                                }
                            });
                            n.active = state;
                            n.changed = true;
                            n.dirty = true;
                        })
                        RED.history.push({
                            t: "multi",
                            events: historyEvents,
                            dirty: RED.nodes.dirty(),
                            callback: function() {
                                activateAjaxCall(nodes,nodes[0].active);
                            }
                        });
                        RED.nodes.dirty(true);
                        RED.view.redraw();
                    });
                }
            }

            $("#red-ui-sidebar-debug-open").on("click", function(e) {
                e.preventDefault();
                subWindow = window.open(document.location.toString().replace(/[?#].*$/,"")+"debug/view/view.html"+document.location.search,"nodeREDDebugView","menubar=no,location=no,toolbar=no,chrome,height=500,width=600");
                subWindow.onload = function() {
                    subWindow.postMessage({event:"workspaceChange",activeWorkspace:RED.workspaces.active()},"*");
                };
            });
            RED.popover.tooltip($("#red-ui-sidebar-debug-open"),RED._('node-red:debug.sidebar.openWindow'));



            $(window).on('beforeunload',function() {
                if (subWindow) {
                    try {
                        subWindow.close();
                    } catch(err) {
                        console.log(err);
                    }
                }
            });

            this.handleWindowMessage = function(evt) {
                var msg = evt.data;
                if (msg.event === "mouseEnter") {
                    options.messageMouseEnter(msg.id);
                } else if (msg.event === "mouseLeave") {
                    options.messageMouseLeave(msg.id);
                } else if (msg.event === "mouseClick") {
                    options.messageSourceClick(msg.id,msg._alias,msg.path);
                } else if (msg.event === "clear") {
                    options.clear();
                }
            };
            window.addEventListener('message',this.handleWindowMessage);
        },
        onpaletteremove: function() {
            RED.comms.unsubscribe("debug",this.handleDebugMessage);
            RED.sidebar.removeTab("debug");
            RED.events.off("workspace:change", this.refreshMessageList);
            window.removeEventListener("message",this.handleWindowMessage);
            RED.actions.remove("core:show-debug-tab");
            RED.actions.remove("core:clear-debug-messages");
            delete RED._debug;
        },
        oneditprepare: function() {
            var autoType = {
                value: "auto",
                label: RED._("node-red:debug.autostatus"),
                hasValue: false
            };
            $("#node-input-typed-status").typedInput({
                default: "auto",
                types:[autoType, "msg", "jsonata"],
                typeField: $("#node-input-statusType")
            });
            var that = this;
            var none = {
                value: "none",
                label: RED._("node-red:debug.none"),
                hasValue: false
            };
            if (this.tosidebar === undefined) {
                this.tosidebar = true;
                $("#node-input-tosidebar").prop('checked', true);
            }
            if (this.statusVal === undefined) {
                this.statusVal = (this.complete === "false") ? "payload" : ((this.complete === "true") ? "payload" : this.complete+"");
                $("#node-input-typed-status").typedInput('value',this.statusVal || "");
            }
            if (this.statusType === undefined) {
                this.statusType = "auto";
                $("#node-input-typed-status").typedInput('type',this.statusType || "auto");
            }
            if (typeof this.console === "string") {
                this.console = (this.console == 'true');
                $("#node-input-console").prop('checked', this.console);
                $("#node-input-tosidebar").prop('checked', true);
            }
            var fullType = {
                value: "full",
                label: RED._("node-red:debug.msgobj"),
                hasValue: false
            };

            $("#node-input-typed-complete").typedInput({
                default: "msg",
                types:['msg', fullType, "jsonata"],
                typeField: $("#node-input-targetType")
            });
            if (this.targetType === "jsonata") {
                var property = this.complete || "";
                $("#node-input-typed-complete").typedInput('type','jsonata');
                $("#node-input-typed-complete").typedInput('value',property);
            } else if ((this.targetType === "full") || this.complete === "true" || this.complete === true) {
                // show complete message object
                $("#node-input-typed-complete").typedInput('type','full');
            } else {
                var property = (!this.complete||(this.complete === "false")) ? "payload" : this.complete+"";
                $("#node-input-typed-complete").typedInput('type','msg');
                $("#node-input-typed-complete").typedInput('value',property);
            }
            $("#node-input-typed-complete").on('change',function() {
                if ($("#node-input-typed-complete").typedInput('type') === 'msg' &&
                    $("#node-input-typed-complete").typedInput('value') === ''
                ) {
                    $("#node-input-typed-complete").typedInput('value','payload');
                }
            });

            $("#node-input-tostatus").on('change',function() {
                if ($(this).is(":checked")) {
                    if (!that.hasOwnProperty("statusVal") || that.statusVal === "") {
                        var type = $("#node-input-typed-complete").typedInput('type');
                        var comp = "payload";
                        if (type !== 'full') {
                            comp = $("#node-input-typed-complete").typedInput('value');
                        }
                        that.statusType = "auto";
                        that.statusVal = comp;
                    }
                    $("#node-input-typed-status").typedInput('type',that.statusType);
                    $("#node-input-typed-status").typedInput('value',that.statusVal);
                    $("#node-tostatus-line").show();
                }
                else {
                    $("#node-tostatus-line").hide();
                    that.statusType = "auto";
                    that.statusVal = "";
                    $("#node-input-typed-status").typedInput('type',that.statusType);
                    $("#node-input-typed-status").typedInput('value',that.statusVal);
                }
            });
        },
        oneditsave: function() {
            var type = $("#node-input-typed-complete").typedInput('type');
            if (type === 'full') {
                $("#node-input-complete").val("true");
            } else {
                $("#node-input-complete").val($("#node-input-typed-complete").typedInput('value'));
            }
            $("#node-input-statusVal").val($("#node-input-typed-status").typedInput('value'));
        }
    });
})();
</script>
<commit_msg>Sanitize Debug node name when display enable/disable message<commit_after>
<script type="text/html" data-template-name="debug">
    <div class="form-row">
        <label for="node-input-typed-complete"><i class="fa fa-list"></i> <span data-i18n="debug.output"></span></label>
        <input id="node-input-typed-complete" type="text" style="width: 70%">
        <input id="node-input-complete" type="hidden">
        <input id="node-input-targetType" type="hidden">
    </div>
    <div class="form-row">
        <label for="node-input-tosidebar"><i class="fa fa-random"></i> <span data-i18n="debug.to"></span></label>
        <label for="node-input-tosidebar" style="width:70%">
        <input type="checkbox" id="node-input-tosidebar" style="display:inline-block; width:22px; vertical-align:top;"><span data-i18n="debug.toSidebar"></span>
        </label>
    </div>
    <div class="form-row">
        <label for="node-input-console"> </label>
        <label for="node-input-console" style="width:70%">
        <input type="checkbox" id="node-input-console" style="display:inline-block; width:22px; vertical-align:top;"><span data-i18n="debug.toConsole"></span>
        </label>
    </div>
    <div class="form-row">
    <label for="node-input-tostatus"> </label>
    <label for="node-input-tostatus" style="width:70%">
        <input type="checkbox" id="node-input-tostatus" style="display:inline-block; width:22px; vertical-align:top;"><span data-i18n="debug.toStatus"></span>
    </label>
    </div>
    <div class="form-row" id="node-tostatus-line">
        <label for="node-input-typed-status"></label>
        <input id="node-input-typed-status" type="text" style="width: 70%">
        <input id="node-input-statusVal" type="hidden">
        <input id="node-input-statusType" type="hidden">
    </div>
    <div class="form-row">
        <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
        <input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
    </div>
</script>

<script src="debug/view/debug-utils.js"></script>

<script type="text/javascript">
(function() {
    var subWindow = null;

    function activateAjaxCall(node, active, successCallback) {
        var url;
        var body;

        if (Array.isArray(node)) {
            url = "debug/"+(active?"enable":"disable");
            body = {nodes: node.map(function(n) { return n.id})}
            node = node[0];
        } else {
            url = "debug/"+node.id+"/"+(active?"enable":"disable");
        }
        $.ajax({
            url: url,
            type: "POST",
            data: body,
            success: successCallback,
            error: function(jqXHR,textStatus,errorThrown) {
                if (jqXHR.status == 404) {
                    RED.notify(node._("common.notification.error", {message: node._("common.notification.errors.not-deployed")}),"error");
                } else if (jqXHR.status === 0) {
                    RED.notify(node._("common.notification.error", {message: node._("common.notification.errors.no-response")}),"error");
                } else {
                    // TODO where is the err.status comming from?
                    RED.notify(node._("common.notification.error",{message:node._("common.notification.errors.unexpected",{status:err.status,message:err.response})}),"error");
                }
            }
        });
    }

    RED.nodes.registerType('debug',{
        category: 'common',
        defaults: {
            name: {value:""},
            active: {value:true},
            tosidebar: {value:true},
            console: {value:false},
            tostatus: {value:false},
            complete: {value:"false", required:true},
            targetType: {value:undefined},
            statusVal: {value:""},
            statusType: {value:"auto"}
        },
        label: function() {
            var suffix = "";
            if (this.console === true || this.console === "true") { suffix = " ⇲"; }
            if (this.targetType === "jsonata") {
                return (this.name || "JSONata") + suffix;
            }
            if (this.complete === true || this.complete === "true") {
                return (this.name||"msg") + suffix;
            } else {
                return (this.name || "msg." + ((!this.complete || this.complete === "false") ? "payload" : this.complete)) + suffix;
            }
        },
        labelStyle: function() {
            return this.name?"node_label_italic":"";
        },
        color:"#87a980",
        inputs:1,
        outputs:0,
        icon: "debug.svg",
        align: "right",
        button: {
            toggle: "active",
            visible: function() { return this.tosidebar; },
            onclick: function() {
                var label = RED.utils.sanitize(this.name||"debug");
                var node = this;
                activateAjaxCall(node, node.active, function(resp, textStatus, xhr) {
                    var historyEvent = {
                        t:'edit',
                        node:node,
                        changes:{
                            active:!node.active
                        },
                        dirty:node.dirty,
                        changed:node.changed,
                        callback: function(ev) {
                            activateAjaxCall(ev.node, ev.node.active);
                        }
                    };
                    node.changed = true;
                    node.dirty = true;
                    RED.nodes.dirty(true);
                    RED.history.push(historyEvent);
                    RED.view.redraw();
                    if (xhr.status == 200) {
                        RED.notify(node._("debug.notification.activated",{label:label}),"success");
                    } else if (xhr.status == 201) {
                        RED.notify(node._("debug.notification.deactivated",{label:label}),"success");
                    }
                });
            }
        },
        onpaletteadd: function() {
            var options = {
                messageMouseEnter: function(sourceId) {
                    if (sourceId) {
                        var n = RED.nodes.node(sourceId);
                        if (n) {
                            n.highlighted = true;
                            n.dirty = true;
                        }
                        RED.view.redraw();
                    }
                },
                messageMouseLeave: function(sourceId) {
                    if (sourceId) {
                        var n = RED.nodes.node(sourceId);
                        if (n) {
                            n.highlighted = false;
                            n.dirty = true;
                        }
                        RED.view.redraw();
                    }
                },
                messageSourceClick: function(sourceId, aliasId, path) {
                    // Get all of the nodes that could have logged this message
                    var candidateNodes = [RED.nodes.node(sourceId)]
                    if (path) {
                        for (var i=2;i<path.length;i++) {
                            candidateNodes.push(RED.nodes.node(path[i]))
                        }
                    }
                    if (aliasId) {
                        candidateNodes.push(RED.nodes.node(aliasId));
                    }
                    if (candidateNodes.length > 1) {
                        // The node is in a subflow. Check to see if the active
                        // workspace is a subflow in the node's parentage. If
                        // so, reveal the relevant subflow instance node.
                        var ws = RED.workspaces.active();
                        for (var i=0;i<candidateNodes.length;i++) {
                            if (candidateNodes[i].z === ws) {
                                RED.view.reveal(candidateNodes[i].id);
                                return
                            }
                        }
                        // The active workspace is unrelated to the node. So
                        // fall back to revealing the top most node
                    }
                    RED.view.reveal(candidateNodes[0].id);
                },
                clear: function() {
                    RED.nodes.eachNode(function(node) {
                        node.highlighted = false;
                        node.dirty = true;
                    });
                    RED.view.redraw();
                }
            };

            var uiComponents = RED.debug.init(options);

            RED.sidebar.addTab({
                id: "debug",
                label: this._("debug.sidebar.label"),
                name: this._("debug.sidebar.name"),
                content: uiComponents.content,
                toolbar: uiComponents.footer,
                enableOnEdit: true,
                pinned: true,
                iconClass: "fa fa-bug",
                action: "core:show-debug-tab"
            });
            RED.actions.add("core:show-debug-tab",function() { RED.sidebar.show('debug'); });

            var that = this;
            RED._debug = function(msg) {
                that.handleDebugMessage("", {
                    name:"debug",
                    msg:msg
                });
            };

            this.refreshMessageList = function() {
                RED.debug.refreshMessageList(RED.workspaces.active());
                if (subWindow) {
                    try {
                        subWindow.postMessage({event:"workspaceChange",activeWorkspace:RED.workspaces.active()},"*");
                    } catch(err) {
                        console.log(err);
                    }
                }
            };
            RED.events.on("workspace:change", this.refreshMessageList);

            this.handleDebugMessage = function(t,o) {
                // console.log("->",o.id,o.z,o._alias);
                //
                // sourceNode should be the top-level node - one that is on a flow.
                var sourceNode;
                var pathParts;
                if (o.path) {
                    // Path is a `/`-separated list of ids that identifies the
                    // complete parentage of the node that generated this message.
                    //    flow-id/subflow-A-instance/subflow-A-type/subflow-B-instance/subflow-B-type/node-id

                    // If it has one id, that is a top level flow
                    // each subsequent id is the instance id of a subflow node
                    //
                    pathParts = o.path.split("/");
                    if (pathParts.length === 1) {
                        // The source node is on a flow - so can use its id to find
                        sourceNode = RED.nodes.node(o.id);
                    } else if (pathParts.length > 1) {
                        // Highlight the subflow instance node.
                        sourceNode = RED.nodes.node(pathParts[1]);
                    }
                } else {
                    // This is probably redundant...
                    sourceNode = RED.nodes.node(o.id) || RED.nodes.node(o.z);
                }
                if (sourceNode) {
                    o._source = {
                        id:sourceNode.id,
                        z:sourceNode.z,
                        name:sourceNode.name,
                        type:sourceNode.type,
                        // _alias identifies the actual logging node. This is
                        // not necessarily the same as sourceNode, which will be
                        // the top-level subflow instance node.
                        // This means the node's name is displayed in the sidebar.
                        _alias:o._alias,
                        path: pathParts
                    };
                }
                RED.debug.handleDebugMessage(o);
                if (subWindow) {
                    try {
                        subWindow.postMessage({event:"message",msg:o},"*");
                    } catch(err) {
                        console.log(err);
                    }
                }
            };
            RED.comms.subscribe("debug",this.handleDebugMessage);

            this.clearMessageList = function() {
                RED.debug.clearMessageList(true);
                if (subWindow) {
                    try {
                        subWindow.postMessage({event:"projectChange"},"*");
                    } catch(err) {
                        console.log(err);
                    }
                }
            };
            RED.events.on("project:change", this.clearMessageList);
            RED.actions.add("core:clear-debug-messages", function() { RED.debug.clearMessageList(true) });

            RED.actions.add("core:activate-selected-debug-nodes", function() { setDebugNodeState(getSelectedDebugNodes(true), true); });
            RED.actions.add("core:activate-all-debug-nodes", function() { setDebugNodeState(getMatchingDebugNodes(true, true),true); });
            RED.actions.add("core:activate-all-flow-debug-nodes", function() { setDebugNodeState(getMatchingDebugNodes(true, false),true); });

            RED.actions.add("core:deactivate-selected-debug-nodes", function() { setDebugNodeState(getSelectedDebugNodes(false), false); });
            RED.actions.add("core:deactivate-all-debug-nodes", function() { setDebugNodeState(getMatchingDebugNodes(false, true),false); });
            RED.actions.add("core:deactivate-all-flow-debug-nodes", function() { setDebugNodeState(getMatchingDebugNodes(false, false),false); });

            function getSelectedDebugNodes(state) {
                var nodes = [];
                var selection = RED.view.selection();
                if (selection.nodes) {
                    selection.nodes.forEach(function(n) {
                        if (RED.nodes.subflow(n.z)) {
                            return;
                        }
                        if (n.type === 'debug' && n.active !== state) {
                            nodes.push(n);
                        } else if (n.type === 'group') {
                            nodes = nodes.concat( RED.group.getNodes(n,true).filter(function(n) {
                                return n.type === 'debug' && n.active !== state
                            }));
                        }
                    });
                }
                return nodes;

            }
            function getMatchingDebugNodes(state,globally) {
                var nodes = [];
                var filter = {type:"debug"};
                if (!globally) {
                    filter.z = RED.workspaces.active();
                }
                var candidateNodes = RED.nodes.filterNodes(filter);
                nodes = candidateNodes.filter(function(n) {
                    return n.active !== state && !RED.nodes.subflow(n.z)
                })
                return nodes;
            }

            function setDebugNodeState(nodes,state) {
                var historyEvents = [];
                if (nodes.length > 0) {
                    activateAjaxCall(nodes,false, function(resp, textStatus, xhr) {
                        nodes.forEach(function(n) {
                            historyEvents.push({
                                t: "edit",
                                node: n,
                                changed: n.changed,
                                changes: {
                                    active: n.active
                                }
                            });
                            n.active = state;
                            n.changed = true;
                            n.dirty = true;
                        })
                        RED.history.push({
                            t: "multi",
                            events: historyEvents,
                            dirty: RED.nodes.dirty(),
                            callback: function() {
                                activateAjaxCall(nodes,nodes[0].active);
                            }
                        });
                        RED.nodes.dirty(true);
                        RED.view.redraw();
                    });
                }
            }

            $("#red-ui-sidebar-debug-open").on("click", function(e) {
                e.preventDefault();
                subWindow = window.open(document.location.toString().replace(/[?#].*$/,"")+"debug/view/view.html"+document.location.search,"nodeREDDebugView","menubar=no,location=no,toolbar=no,chrome,height=500,width=600");
                subWindow.onload = function() {
                    subWindow.postMessage({event:"workspaceChange",activeWorkspace:RED.workspaces.active()},"*");
                };
            });
            RED.popover.tooltip($("#red-ui-sidebar-debug-open"),RED._('node-red:debug.sidebar.openWindow'));



            $(window).on('beforeunload',function() {
                if (subWindow) {
                    try {
                        subWindow.close();
                    } catch(err) {
                        console.log(err);
                    }
                }
            });

            this.handleWindowMessage = function(evt) {
                var msg = evt.data;
                if (msg.event === "mouseEnter") {
                    options.messageMouseEnter(msg.id);
                } else if (msg.event === "mouseLeave") {
                    options.messageMouseLeave(msg.id);
                } else if (msg.event === "mouseClick") {
                    options.messageSourceClick(msg.id,msg._alias,msg.path);
                } else if (msg.event === "clear") {
                    options.clear();
                }
            };
            window.addEventListener('message',this.handleWindowMessage);
        },
        onpaletteremove: function() {
            RED.comms.unsubscribe("debug",this.handleDebugMessage);
            RED.sidebar.removeTab("debug");
            RED.events.off("workspace:change", this.refreshMessageList);
            window.removeEventListener("message",this.handleWindowMessage);
            RED.actions.remove("core:show-debug-tab");
            RED.actions.remove("core:clear-debug-messages");
            delete RED._debug;
        },
        oneditprepare: function() {
            var autoType = {
                value: "auto",
                label: RED._("node-red:debug.autostatus"),
                hasValue: false
            };
            $("#node-input-typed-status").typedInput({
                default: "auto",
                types:[autoType, "msg", "jsonata"],
                typeField: $("#node-input-statusType")
            });
            var that = this;
            var none = {
                value: "none",
                label: RED._("node-red:debug.none"),
                hasValue: false
            };
            if (this.tosidebar === undefined) {
                this.tosidebar = true;
                $("#node-input-tosidebar").prop('checked', true);
            }
            if (this.statusVal === undefined) {
                this.statusVal = (this.complete === "false") ? "payload" : ((this.complete === "true") ? "payload" : this.complete+"");
                $("#node-input-typed-status").typedInput('value',this.statusVal || "");
            }
            if (this.statusType === undefined) {
                this.statusType = "auto";
                $("#node-input-typed-status").typedInput('type',this.statusType || "auto");
            }
            if (typeof this.console === "string") {
                this.console = (this.console == 'true');
                $("#node-input-console").prop('checked', this.console);
                $("#node-input-tosidebar").prop('checked', true);
            }
            var fullType = {
                value: "full",
                label: RED._("node-red:debug.msgobj"),
                hasValue: false
            };

            $("#node-input-typed-complete").typedInput({
                default: "msg",
                types:['msg', fullType, "jsonata"],
                typeField: $("#node-input-targetType")
            });
            if (this.targetType === "jsonata") {
                var property = this.complete || "";
                $("#node-input-typed-complete").typedInput('type','jsonata');
                $("#node-input-typed-complete").typedInput('value',property);
            } else if ((this.targetType === "full") || this.complete === "true" || this.complete === true) {
                // show complete message object
                $("#node-input-typed-complete").typedInput('type','full');
            } else {
                var property = (!this.complete||(this.complete === "false")) ? "payload" : this.complete+"";
                $("#node-input-typed-complete").typedInput('type','msg');
                $("#node-input-typed-complete").typedInput('value',property);
            }
            $("#node-input-typed-complete").on('change',function() {
                if ($("#node-input-typed-complete").typedInput('type') === 'msg' &&
                    $("#node-input-typed-complete").typedInput('value') === ''
                ) {
                    $("#node-input-typed-complete").typedInput('value','payload');
                }
            });

            $("#node-input-tostatus").on('change',function() {
                if ($(this).is(":checked")) {
                    if (!that.hasOwnProperty("statusVal") || that.statusVal === "") {
                        var type = $("#node-input-typed-complete").typedInput('type');
                        var comp = "payload";
                        if (type !== 'full') {
                            comp = $("#node-input-typed-complete").typedInput('value');
                        }
                        that.statusType = "auto";
                        that.statusVal = comp;
                    }
                    $("#node-input-typed-status").typedInput('type',that.statusType);
                    $("#node-input-typed-status").typedInput('value',that.statusVal);
                    $("#node-tostatus-line").show();
                }
                else {
                    $("#node-tostatus-line").hide();
                    that.statusType = "auto";
                    that.statusVal = "";
                    $("#node-input-typed-status").typedInput('type',that.statusType);
                    $("#node-input-typed-status").typedInput('value',that.statusVal);
                }
            });
        },
        oneditsave: function() {
            var type = $("#node-input-typed-complete").typedInput('type');
            if (type === 'full') {
                $("#node-input-complete").val("true");
            } else {
                $("#node-input-complete").val($("#node-input-typed-complete").typedInput('value'));
            }
            $("#node-input-statusVal").val($("#node-input-typed-status").typedInput('value'));
        }
    });
})();
</script>

{'fraction_non_alphanumeric': 0.13983335136889946, 'fraction_numerical': 0.0027269775998268585, 'mean_word_length': 1.2932155441957418, 'pattern_counts': {'":': 8, '<': 135, '<?xml version=': 0, '>': 139, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2891455', 'n_tokens_mistral': 12147, 'n_tokens_neox': 11351, 'n_words': 1929}