mirror of
				https://github.com/node-red/node-red.git
				synced 2025-03-01 10:36:34 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			420 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			420 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
| <!--
 | |
|   Copyright 2013, 2015 IBM Corp.
 | |
| 
 | |
|   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.
 | |
| -->
 | |
| 
 | |
| <script type="text/x-red" 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">
 | |
|     </div>
 | |
|     <div class="form-row">
 | |
|         <label for="node-input-console"><i class="fa fa-random"></i> <span data-i18n="debug.to"></span></label>
 | |
|         <select type="text" id="node-input-console" style="display: inline-block; width: 250px; vertical-align: top;">
 | |
|             <option value="false" data-i18n="debug.debtab"></option>
 | |
|             <option value="true" data-i18n="debug.tabcon"></option>
 | |
|         </select>
 | |
|     </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 type="text/x-red" data-help-name="debug">
 | |
|     <p>The Debug node can be connected to the output of any node. It can be used to display the output of any message
 | |
|     property in the debug tab of the sidebar. The default is to display <code>msg.payload</code>.</p>
 | |
|     <p>Each message will also display the timestamp, <code>msg.topic</code> and the type of property chosen to output.</p>
 | |
|     <p>The sidebar can be accessed under the options drop-down in the top right corner.</p>
 | |
|     <p>The button to the right of the node will toggle its output on and off so you can de-clutter the debug window.</p>
 | |
|     <p>If the payload is an object or buffer it will be stringified first for display and indicate that by saying "(Object)" or "(Buffer)".</p>
 | |
|     <p>Selecting any particular message will highlight (in red) the debug node that reported it. This is useful if you wire up multiple debug nodes.</p>
 | |
|     <p>Optionally can show the complete <code>msg</code> object, and send messages to the console log.</p>
 | |
|     <p>In addition any calls to node.warn or node.error will appear here.</p>
 | |
| </script>
 | |
| <script type="text/javascript">
 | |
| (function() {
 | |
|     var subWindow = null;
 | |
|     RED.nodes.registerType('debug',{
 | |
|         category: 'output',
 | |
|         defaults: {
 | |
|             name: {value:""},
 | |
|             active: {value:true},
 | |
|             console: {value:"false"},
 | |
|             complete: {value:"false", required:true}
 | |
|         },
 | |
|         label: function() {
 | |
|             if (this.complete === true || this.complete === "true") {
 | |
|                 return this.name||"msg";
 | |
|             } else {
 | |
|                 return this.name || "msg." + ((!this.complete || this.complete === "false") ? "payload" : this.complete);
 | |
|             }
 | |
|         },
 | |
|         labelStyle: function() {
 | |
|             return this.name?"node_label_italic":"";
 | |
|         },
 | |
|         color:"#87a980",
 | |
|         inputs:1,
 | |
|         outputs:0,
 | |
|         icon: "debug.png",
 | |
|         align: "right",
 | |
|         button: {
 | |
|             toggle: "active",
 | |
|             onclick: function() {
 | |
|                 var label = this.name||"debug";
 | |
|                 var node = this;
 | |
|                 $.ajax({
 | |
|                     url: "debug/"+this.id+"/"+(this.active?"enable":"disable"),
 | |
|                     type: "POST",
 | |
|                     success: function(resp, textStatus, xhr) {
 | |
|                         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");
 | |
|                         }
 | |
|                     },
 | |
|                     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 {
 | |
|                             RED.notify(node._("common.notification.error",{message:node._("common.notification.errors.unexpected",{status:err.status,message:err.response})}),"error");
 | |
|                         }
 | |
|                     }
 | |
|                 });
 | |
|             }
 | |
|         },
 | |
|         onpaletteadd: function() {
 | |
|             var content = $("<div>").css({"position":"relative","height":"100%"});
 | |
|             var toolbar = $('<div class="sidebar-header">'+
 | |
|                 '<span class="button-group"><a id="debug-tab-filter" class="sidebar-header-button" href="#"><i class="fa fa-filter"></i></a></span>'+
 | |
|                 '<span class="button-group"><a id="debug-tab-clear" title="clear log" class="sidebar-header-button" href="#"><i class="fa fa-trash"></i></a></span></div>').appendTo(content);
 | |
| 
 | |
| 
 | |
|             var footerToolbar = $('<div>'+
 | |
|                 '<span class="button-group">'+
 | |
|                     '<a class="sidebar-footer-button-toggle text-button selected" id="debug-tab-view-list" href="#"><span data-i18n="">list</span></a>'+
 | |
|                     '<a class="sidebar-footer-button-toggle text-button" id="debug-tab-view-table" href="#"><span data-i18n="">table</span></a> '+
 | |
|                 '</span>'+
 | |
|                 '<span class="button-group"><a id="debug-tab-open" title="open in new window" class="sidebar-footer-button" href="#"><i class="fa fa-desktop"></i></a></span> ' +
 | |
|                 '</div>');
 | |
| 
 | |
|             var messageList = $('<div class="debug-content debug-content-list"/>').appendTo(content);
 | |
|             var messageTable = $('<div class="debug-content  debug-content-table hide"/>').appendTo(content);
 | |
| 
 | |
|             var filterDialog = $('<div class="debug-filter-box hide">'+
 | |
|                 '<div class="debug-filter-row">'+
 | |
|                 '<span class="button-group">'+
 | |
|                     '<a class="sidebar-header-button-toggle selected" id="debug-tab-filter-all" href="#"><span data-i18n="node-red:debug.sidebar.filterAll"></span></a>'+
 | |
|                     '<a class="sidebar-header-button-toggle" id="debug-tab-filter-current" href="#"><span data-i18n="node-red:debug.sidebar.filterCurrent"></span></a> '+
 | |
|                 '</span>'+
 | |
|                 '</div>'+
 | |
|             '</div>').appendTo(content);
 | |
| 
 | |
| 
 | |
|             content.i18n();
 | |
| 
 | |
|             RED.sidebar.addTab({
 | |
|                 id: "debug",
 | |
|                 label: this._("debug.sidebar.label"),
 | |
|                 name: this._("debug.sidebar.name"),
 | |
|                 content: content,
 | |
|                 toolbar: footerToolbar,
 | |
|                 enableOnEdit: true
 | |
|             });
 | |
| 
 | |
|             function getTimestamp() {
 | |
|                 var d = new Date();
 | |
|                 return d.toLocaleString();
 | |
|             }
 | |
| 
 | |
|             var sbc = messageList[0];
 | |
|             var filter = false;
 | |
|             var view = 'list';
 | |
|             var messages = [];
 | |
|             var messagesByNode = {};
 | |
| 
 | |
|             var that = this;
 | |
|             RED._debug = function(msg) {
 | |
|                 that.handleDebugMessage("",{
 | |
|                     name:"debug",
 | |
|                     msg:msg
 | |
|                 });
 | |
|             }
 | |
|             function sanitize(m) {
 | |
|                 return m.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">");
 | |
|             }
 | |
| 
 | |
|             function refreshMessageList() {
 | |
|                 $(".debug-message").each(function() {
 | |
|                     $(this).toggleClass('hide',filter&&!$(this).hasClass('debug-message-flow-'+RED.workspaces.active()));
 | |
|                 });
 | |
|             }
 | |
|             function refreshMessageTable() {
 | |
| 
 | |
|             }
 | |
| 
 | |
|             function showMessageList() {
 | |
|                 view = 'list';
 | |
|                 messageTable.hide();
 | |
|                 messageTable.empty();
 | |
| 
 | |
|                 messages.forEach(function(m) {
 | |
|                     messageList.append(m.el);
 | |
|                 })
 | |
|                 messageList.show();
 | |
|             }
 | |
|             function showMessageTable() {
 | |
|                 view = 'table';
 | |
|                 messageList.hide();
 | |
|                 messageList.empty();
 | |
| 
 | |
|                 Object.keys(messagesByNode).forEach(function(id) {
 | |
|                     var m = messagesByNode[id];
 | |
|                     var msg = m.el;
 | |
|                     var sourceNode = m.source;
 | |
|                     if (sourceNode) {
 | |
|                         var wrapper = $("<div>",{id:"debug-message-source-"+sourceNode.id.replace(/\./g,"_")}).appendTo(messageTable);
 | |
|                         wrapper.append(msg);
 | |
|                     }
 | |
|                 });
 | |
|                 messageTable.show();
 | |
|             }
 | |
| 
 | |
| 
 | |
|             function showFilterDialog() {
 | |
|                 filterDialog.slideDown();
 | |
|             }
 | |
| 
 | |
|             this.handleDebugMessage = function(t,o) {
 | |
| 
 | |
|                 if (subWindow) {
 | |
|                     try {
 | |
|                         subWindow.postMessage(o,"*")
 | |
|                     } catch(err) {
 | |
|                         console.log(err);
 | |
|                     }
 | |
|                 }
 | |
|                 var msg = document.createElement("div");
 | |
| 
 | |
|                 var sourceNode = RED.nodes.node(o.id) || RED.nodes.node(o.z);
 | |
| 
 | |
|                 msg.onmouseover = function() {
 | |
|                     msg.style.borderRightColor = "#999";
 | |
|                     var n = RED.nodes.node(o.id) || RED.nodes.node(o.z);
 | |
|                     if (n) {
 | |
|                         n.highlighted = true;
 | |
|                         n.dirty = true;
 | |
|                     }
 | |
|                     RED.view.redraw();
 | |
|                 };
 | |
|                 msg.onmouseout = function() {
 | |
|                     msg.style.borderRightColor = "";
 | |
|                     var n = RED.nodes.node(o.id) || RED.nodes.node(o.z);
 | |
|                     if (n) {
 | |
|                         n.highlighted = false;
 | |
|                         n.dirty = true;
 | |
|                     }
 | |
|                     RED.view.redraw();
 | |
|                 };
 | |
|                 $(msg).click(function() {
 | |
|                     var node = RED.nodes.node(o.id) || RED.nodes.node(o.z);
 | |
|                     if (node) {
 | |
|                         RED.view.reveal(node.id);
 | |
|                     }
 | |
|                 });
 | |
|                 var name = sanitize(((o.name?o.name:o.id)||"").toString());
 | |
|                 var topic = sanitize((o.topic||"").toString());
 | |
|                 var property = sanitize(o.property?o.property:'');
 | |
|                 var payload = sanitize((o.msg||"").toString());
 | |
|                 var format = sanitize((o.format||"").toString());
 | |
| 
 | |
|                 msg.className = 'debug-message'+(o.level?(' debug-message-level-'+o.level):'') +
 | |
|                                 ((sourceNode&&sourceNode.z)?((" debug-message-flow-"+sourceNode.z+((filter&&(RED.workspaces.active()!==sourceNode.z))?" hide":""))):"");
 | |
|                 msg.innerHTML = '<span class="debug-message-date">'+
 | |
|                                 getTimestamp()+'</span>'+
 | |
|                                 (name?'<span class="debug-message-name">'+name:'')+
 | |
|                                 '</span>';
 | |
|                 // NOTE: relying on function error to have a "type" that all other msgs don't
 | |
|                 if (o.hasOwnProperty("type") && (o.type === "function")) {
 | |
|                     var errorLvlType = 'error';
 | |
|                     var errorLvl = 20;
 | |
|                     if (o.hasOwnProperty("level") && o.level === 30) {
 | |
|                         errorLvl = 30;
 | |
|                         errorLvlType = 'warn';
 | |
|                     }
 | |
|                     msg.className = 'debug-message debug-message-level-' + errorLvl;
 | |
|                     msg.innerHTML += '<span class="debug-message-topic">function : (' + errorLvlType + ')</span>';
 | |
|                 } else {
 | |
|                     msg.innerHTML += '<span class="debug-message-topic">'+
 | |
|                                     (o.topic?topic+' : ':'')+
 | |
|                                     (o.property?'msg.'+property:'msg')+" : "+format+
 | |
| 
 | |
|                                     '</span>';
 | |
|                 }
 | |
|                 if (format === 'Object' || /^array/.test(format) || format === 'boolean' || format === 'number' ) {
 | |
|                     payload = JSON.parse(payload);
 | |
|                 } else if (format === 'null') {
 | |
|                     payload = null;
 | |
|                 } else if (format === 'undefined') {
 | |
|                     payload = undefined;
 | |
|                 } else if (/^buffer/.test(format)) {
 | |
|                     var buffer = payload;
 | |
|                     payload = [];
 | |
|                     for (var c = 0; c < buffer.length; c += 2) {
 | |
|                         payload.push(parseInt(buffer.substr(c, 2), 16));
 | |
|                     }
 | |
|                 }
 | |
|                 var el = $('<span class="debug-message-payload"></span>').appendTo(msg);
 | |
|                 RED.debug.buildMessageElement(payload,true,format).appendTo(el);
 | |
|                 var atBottom = (sbc.scrollHeight-messageList.height()-sbc.scrollTop) < 5;
 | |
|                 var m = {
 | |
|                     el: msg
 | |
|                 };
 | |
|                 messages.push(m);
 | |
|                 if (sourceNode) {
 | |
|                     m.source = sourceNode;
 | |
|                     messagesByNode[sourceNode.id] = m;
 | |
|                 }
 | |
|                 if (view == "list") {
 | |
|                     messageList.append(msg);
 | |
|                 } else {
 | |
|                     if (sourceNode) {
 | |
|                         var wrapper = $("#debug-message-source-"+sourceNode.id.replace(/\./g,"_"));
 | |
|                         if (wrapper.length === 0 ) {
 | |
|                             wrapper = $("<div>",{id:"debug-message-source-"+sourceNode.id.replace(/\./g,"_")}).appendTo(messageTable);
 | |
|                         }
 | |
|                         wrapper.empty();
 | |
|                         wrapper.append(msg);
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 if (messages.length === 100) {
 | |
|                     var m = messages.shift();
 | |
|                     if (view === "list") {
 | |
|                         m.el.remove();
 | |
|                     }
 | |
|                 }
 | |
|                 if (atBottom) {
 | |
|                     messageList.scrollTop(sbc.scrollHeight);
 | |
|                 }
 | |
|             };
 | |
|             RED.comms.subscribe("debug",this.handleDebugMessage);
 | |
| 
 | |
|             $("#debug-tab-clear").click(function() {
 | |
|                 $(".debug-message").remove();
 | |
|                 messageCount = 0;
 | |
|                 RED.nodes.eachNode(function(node) {
 | |
|                     node.highlighted = false;
 | |
|                     node.dirty = true;
 | |
|                 });
 | |
|                 RED.view.redraw();
 | |
|             });
 | |
|             $('#debug-tab-filter-all').on("click",function(e) {
 | |
|                 e.preventDefault();
 | |
|                 if (filter) {
 | |
|                     $(this).addClass('selected');
 | |
|                     $('#debug-tab-filter-current').removeClass('selected');
 | |
|                     filter = !filter;
 | |
|                     refreshMessageList();
 | |
|                 }
 | |
|             });
 | |
|             $('#debug-tab-filter-current').on("click",function(e) {
 | |
|                 e.preventDefault();
 | |
|                 if (!filter) {
 | |
|                     $(this).addClass('selected');
 | |
|                     $('#debug-tab-filter-all').removeClass('selected');
 | |
|                     filter = !filter;
 | |
|                     refreshMessageList();
 | |
|                 }
 | |
|             });
 | |
|             $('#debug-tab-view-list').on("click",function(e) {
 | |
|                 e.preventDefault();
 | |
|                 if (!$(this).hasClass('selected')) {
 | |
|                     $(this).addClass('selected');
 | |
|                     $('#debug-tab-view-table').removeClass('selected');
 | |
|                     showMessageList();
 | |
|                 }
 | |
|             });
 | |
|             $('#debug-tab-view-table').on("click",function(e) {
 | |
|                 e.preventDefault();
 | |
|                 if (!$(this).hasClass('selected')) {
 | |
|                     $(this).addClass('selected');
 | |
|                     $('#debug-tab-view-list').removeClass('selected');
 | |
|                     showMessageTable();
 | |
|                 }
 | |
|             });
 | |
| 
 | |
| 
 | |
|             $('#debug-tab-filter').on("click",function(e) {
 | |
|                 e.preventDefault();
 | |
|                 if ($(this).hasClass('selected')) {
 | |
|                     $(this).removeClass('selected');
 | |
|                     filterDialog.slideUp(200);
 | |
|                 } else {
 | |
|                     $(this).addClass('selected');
 | |
|                     filterDialog.slideDown(200);
 | |
|                 }
 | |
|             })
 | |
| 
 | |
| 
 | |
| 
 | |
|             RED.events.on("workspace:change", refreshMessageList);
 | |
|             $("#debug-tab-open").click(function(e) {
 | |
|                 e.preventDefault();
 | |
|                 subWindow = window.open(document.location.toString().replace(/#.*$/,"")+"debug/view/view.html","nodeREDDebugView","menubar=no,location=no,toolbar=no,chrome,height=500,width=600");
 | |
|             });
 | |
|         },
 | |
|         onpaletteremove: function() {
 | |
|             RED.comms.unsubscribe("debug",this.handleDebugMessage);
 | |
|             RED.sidebar.removeTab("debug");
 | |
|             RED.events.off("workspace:change", refreshMessageList);
 | |
|             delete RED._debug;
 | |
|         },
 | |
|         oneditprepare: function() {
 | |
|             $("#node-input-typed-complete").typedInput({types:['msg', {value:"full",label:RED._("node-red:debug.msgobj"),hasValue:false}]});
 | |
|             if (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');
 | |
|                 }
 | |
|             });
 | |
|         },
 | |
|         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'));
 | |
|             }
 | |
|         }
 | |
| 
 | |
|     });
 | |
| })();
 | |
| </script>
 | |
| <script src="debug/view/debug-utils.js"></script>
 | |
| <link rel="stylesheet" href="debug/view/style.css">
 |