/** * 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.sidebar.info = (function() { var content; var panels; var infoSection; var propertiesPanelContent; var propertiesPanelHeader; var propertiesPanelHeaderIcon; var propertiesPanelHeaderLabel; var propertiesPanelHeaderReveal; var propertiesPanelHeaderHelp; var propertiesPanelHeaderCopyLink; var selectedObject; var tipContainer; var tipBox; // TODO: remove this var expandedSections = { "property": false }; function resizeStack() { if (panels) { var h = $(content).parent().height() - tipContainer.outerHeight(); panels.resize(h) } } function init() { content = document.createElement("div"); content.className = "red-ui-sidebar-info" RED.actions.add("core:show-info-tab",show); var stackContainer = $("
",{class:"red-ui-sidebar-info-stack"}).appendTo(content); var outlinerPanel = $("
").css({ "overflow": "hidden", "height": "calc(70%)" }).appendTo(stackContainer); var propertiesPanel = $("
").css({ "overflow":"hidden", "height":"100%", "display": "flex", "flex-direction": "column" }).appendTo(stackContainer); propertiesPanelHeader = $("
", {class:"red-ui-palette-header red-ui-info-header"}).css({ "flex":"0 0 auto" }).appendTo(propertiesPanel); propertiesPanelHeaderIcon = $("").appendTo(propertiesPanelHeader); propertiesPanelHeaderLabel = $("").appendTo(propertiesPanelHeader); propertiesPanelHeaderCopyLink = $('').css({ position: 'absolute', top: '12px', right: '32px' }).on("click", function(evt) { RED.actions.invoke('core:copy-item-url',selectedObject) }).appendTo(propertiesPanelHeader); RED.popover.tooltip(propertiesPanelHeaderCopyLink,RED._("sidebar.info.copyItemUrl")); propertiesPanelHeaderHelp = $('').css({ position: 'absolute', top: '12px', right: '56px' }).on("click", function(evt) { evt.preventDefault(); evt.stopPropagation(); if (selectedObject) { RED.sidebar.help.show(selectedObject.type); } }).appendTo(propertiesPanelHeader); RED.popover.tooltip(propertiesPanelHeaderHelp,RED._("sidebar.help.showHelp")); propertiesPanelHeaderReveal = $('').css({ position: 'absolute', top: '12px', right: '8px' }).on("click", function(evt) { evt.preventDefault(); evt.stopPropagation(); if (selectedObject) { RED.sidebar.info.outliner.reveal(selectedObject); RED.view.reveal(selectedObject.id); } }).appendTo(propertiesPanelHeader); RED.popover.tooltip(propertiesPanelHeaderReveal,RED._("sidebar.help.showInOutline")); propertiesPanelContent = $("
").css({ "flex":"1 1 auto", "overflow-y":"auto", }).appendTo(propertiesPanel); panels = RED.panels.create({container: stackContainer}) panels.ratio(0.6); RED.sidebar.info.outliner.build().appendTo(outlinerPanel); RED.sidebar.addTab({ id: "info", label: RED._("sidebar.info.label"), name: RED._("sidebar.info.name"), iconClass: "fa fa-info", action:"core:show-info-tab", content: content, pinned: true, enableOnEdit: true }); RED.events.on("sidebar:resize", resizeStack); $(window).on("resize", resizeStack); $(window).on("focus", resizeStack); // Tip Box tipContainer = $('
').appendTo(content); tipBox = $('
').appendTo(tipContainer); var tipButtons = $('
').appendTo(tipContainer); var tipRefresh = $('').appendTo(tipButtons); tipRefresh.on("click", function(e) { e.preventDefault(); tips.next(); }) var tipClose = $('').appendTo(tipButtons); tipClose.on("click", function(e) { e.preventDefault(); RED.actions.invoke("core:toggle-show-tips"); RED.notify(RED._("sidebar.info.showTips")); }); if (tips.enabled()) { tips.start(); } else { tips.stop(); } } function show() { RED.sidebar.show("info"); } // TODO: DRY - projects.js function addTargetToExternalLinks(el) { $(el).find("a").each(function(el) { var href = $(this).attr('href'); if (/^https?:/.test(href)) { $(this).attr('target','_blank'); } }); return el; } function refresh(node) { if (node === undefined) { refreshSelection(); return; } $(propertiesPanelContent).empty(); var propRow; var table = $('
').appendTo(propertiesPanelContent); var tableBody = $('').appendTo(table); var subflowNode; var subflowUserCount; if (node === null) { RED.sidebar.info.outliner.select(null); propertiesPanelHeaderIcon.empty(); propertiesPanelHeaderLabel.text(""); propertiesPanelHeaderReveal.hide(); propertiesPanelHeaderHelp.hide(); propertiesPanelHeaderCopyLink.hide(); return; } else if (Array.isArray(node)) { // Multiple things selected // - hide help and info sections RED.sidebar.info.outliner.select(node); propertiesPanelHeaderIcon.empty(); RED.utils.createNodeIcon({type:"_selection_"}).appendTo(propertiesPanelHeaderIcon); propertiesPanelHeaderLabel.text("Selection"); propertiesPanelHeaderReveal.hide(); propertiesPanelHeaderHelp.hide(); propertiesPanelHeaderCopyLink.hide(); selectedObject = null; var types = { nodes:0, flows:0, subflows:0, groups: 0 } node.forEach(function(n) { if (n.type === 'tab') { types.flows++; types.nodes += RED.nodes.filterNodes({z:n.id}).length; } else if (n.type === 'subflow') { types.subflows++; } else if (n.type === 'group') { types.groups++; } else { types.nodes++; } }); // infoSection.container.hide(); // - show the count of selected nodes propRow = $(''+RED._("sidebar.info.selection")+"").appendTo(tableBody); var counts = $('
').appendTo($(propRow.children()[1])); if (types.flows > 0) { $('
').text(RED._("clipboard.flow",{count:types.flows})).appendTo(counts); } if (types.subflows > 0) { $('
').text(RED._("clipboard.subflow",{count:types.subflows})).appendTo(counts); } if (types.nodes > 0) { $('
').text(RED._("clipboard.node",{count:types.nodes})).appendTo(counts); } if (types.groups > 0) { $('
').text(RED._("clipboard.group",{count:types.groups})).appendTo(counts); } } else { // A single 'thing' selected. RED.sidebar.info.outliner.select(node); // Check to see if this is a subflow or subflow instance var subflowRegex = /^subflow(:(.+))?$/.exec(node.type); if (subflowRegex) { if (subflowRegex[2]) { subflowNode = RED.nodes.subflow(subflowRegex[2]); } else { subflowNode = node; } var subflowType = "subflow:"+subflowNode.id; subflowUserCount = subflowNode.instances.length; } propertiesPanelHeaderIcon.empty(); RED.utils.createNodeIcon(node).appendTo(propertiesPanelHeaderIcon); var objectLabel = RED.utils.getNodeLabel(node, node.type+": "+node.id) var newlineIndex = objectLabel.indexOf("\\n"); if (newlineIndex > -1) { objectLabel = objectLabel.substring(0,newlineIndex)+"..."; } propertiesPanelHeaderLabel.text(objectLabel); propertiesPanelHeaderReveal.show(); selectedObject = node; propRow = $('').appendTo(tableBody); var objectType = "node"; if (node.type === "subflow" || subflowRegex) { objectType = "subflow"; } else if (node.type === "tab") { objectType = "flow"; }else if (node.type === "group") { objectType = "group"; } $(propRow.children()[0]).text(RED._("sidebar.info."+objectType)) RED.utils.createObjectElement(node.id,{sourceId: node.id}).appendTo(propRow.children()[1]); if (node.type === "tab" || node.type === "subflow") { // If nothing is selected, but we're on a flow or subflow tab. propertiesPanelHeaderHelp.hide(); propertiesPanelHeaderCopyLink.show(); } else if (node.type === "group") { propertiesPanelHeaderHelp.hide(); propertiesPanelHeaderCopyLink.show(); propRow = $(' ').appendTo(tableBody); var typeCounts = { nodes:0, groups: 0 } var allNodes = RED.group.getNodes(node,true); allNodes.forEach(function(n) { if (n.type === "group") { typeCounts.groups++; } else { typeCounts.nodes++ } }); var counts = $('
').appendTo($(propRow.children()[1])); if (typeCounts.nodes > 0) { $('
').text(RED._("clipboard.node",{count:typeCounts.nodes})).appendTo(counts); } if (typeCounts.groups > 0) { $('
').text(RED._("clipboard.group",{count:typeCounts.groups})).appendTo(counts); } } else if (node.type === 'junction') { propertiesPanelHeaderHelp.hide(); propertiesPanelHeaderCopyLink.hide(); } else { propertiesPanelHeaderHelp.show(); propertiesPanelHeaderCopyLink.show(); if (!subflowRegex) { propRow = $(''+RED._("sidebar.info.type")+'').appendTo(tableBody); $(propRow.children()[1]).text((node.type === "unknown")?node._orig.type:node.type); if (node.type === "unknown") { $('').prependTo($(propRow.children()[1])) } } var count = 0; if (!subflowRegex && node.type != "subflow" && node.type != "group") { var blankRow = $('').appendTo(tableBody); var defaults; if (node.type === 'unknown') { defaults = {}; Object.keys(node._orig).forEach(function(k) { if (k !== 'type') { defaults[k] = {}; } }) } else if (node._def) { defaults = node._def.defaults; propRow = $(''+RED._("sidebar.info.module")+"").appendTo(tableBody); $(propRow.children()[1]).text(RED.nodes.getType(node.type).set.module); count++; } if (defaults) { for (var n in defaults) { if (n != "name" && n != "info" && defaults.hasOwnProperty(n)) { var val = node[n]; var type = typeof val; count++; propRow = $('').appendTo(tableBody); $(propRow.children()[0]).text(n); if (defaults[n].type && !defaults[n]._type.array) { var configNode = RED.nodes.node(val); if (!configNode) { RED.utils.createObjectElement(undefined).appendTo(propRow.children()[1]); } else { var configLabel = RED.utils.getNodeLabel(configNode,val); var container = propRow.children()[1]; var div = $('',{class:""}).appendTo(container); var nodeDiv = $('
',{class:"red-ui-palette-node red-ui-palette-node-small"}).appendTo(div); var colour = RED.utils.getNodeColor(configNode.type,configNode._def); var icon_url = RED.utils.getNodeIcon(configNode._def); nodeDiv.css({'backgroundColor':colour, "cursor":"pointer"}); var iconContainer = $('
',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv); $('
',{class:"red-ui-palette-icon",style:"background-image: url("+icon_url+")"}).appendTo(iconContainer); var nodeContainer = $('').css({"verticalAlign":"top","marginLeft":"6px"}).text(configLabel).appendTo(container); nodeDiv.on('dblclick',function() { RED.editor.editConfig("", configNode.type, configNode.id); }) } } else { RED.utils.createObjectElement(val,{sourceId: node.id}).appendTo(propRow.children()[1]); } } } } if (count > 0) { $(''+RED._("sidebar.info.showMore")+''+RED._("sidebar.info.showLess")+' ').appendTo(blankRow.children()[0]); } } if (node.type !== 'tab') { if (subflowRegex) { $(''+RED._("sidebar.info.subflow")+'').appendTo(tableBody); $(''+RED._("common.label.name")+''+RED.utils.sanitize(subflowNode.name)+'').appendTo(tableBody); } } } if (subflowRegex) { propRow = $(''+RED._("subflow.category")+'').appendTo(tableBody); var category = subflowNode.category||"subflows"; $(propRow.children()[1]).text(RED._("palette.label."+category,{defaultValue:category})) $(''+RED._("sidebar.info.instances")+""+subflowUserCount+'').appendTo(tableBody); if (subflowNode.meta) { propRow = $(''+RED._("subflow.module")+'').appendTo(tableBody); $(propRow.children()[1]).text(subflowNode.meta.module||"") propRow = $(''+RED._("subflow.version")+'').appendTo(tableBody); $(propRow.children()[1]).text(subflowNode.meta.version||"") } } var infoText = ""; if (node._def && node._def.info) { var info = node._def.info; var textInfo = (typeof info === "function" ? info.call(node) : info); infoText = infoText + RED.utils.renderMarkdown(textInfo); } if (node.info) { infoText = infoText + RED.utils.renderMarkdown(node.info || "") } var infoSectionContainer = $("
").css("padding","0 6px 6px").appendTo(propertiesPanelContent) setInfoText(infoText, infoSectionContainer); $(".red-ui-sidebar-info-stack").scrollTop(0); $(".node-info-property-header").on("click", function(e) { e.preventDefault(); expandedSections["property"] = !expandedSections["property"]; $(this).toggleClass("expanded",expandedSections["property"]); $(".red-ui-help-info-property-row").toggle(expandedSections["property"]); }); } // $('').appendTo(tableBody); // propRow = $('Actions').appendTo(tableBody); // var actionBar = $(propRow.children()[1]); // // // var actionBar = $('
',{style:"background: #fefefe; padding: 3px;"}).appendTo(propertiesPanel); // $('').appendTo(actionBar); // $('').appendTo(actionBar); // $('').appendTo(actionBar); // $('').appendTo(actionBar); } function setInfoText(infoText,target) { var info = addTargetToExternalLinks($('
'+infoText+'
')).appendTo(target); info.find(".red-ui-text-bidi-aware").contents().filter(function() { return this.nodeType === 3 && this.textContent.trim() !== "" }).wrap( "" ); var foldingHeader = "H3"; info.find(foldingHeader).wrapInner('') .find("a").prepend('').on("click", function(e) { e.preventDefault(); var isExpanded = $(this).hasClass('expanded'); var el = $(this).parent().next(); while(el.length === 1 && el[0].nodeName !== foldingHeader) { el.toggle(!isExpanded); el = el.next(); } $(this).toggleClass('expanded',!isExpanded); }); RED.editor.mermaid.render() } var tips = (function() { var enabled = true; var startDelay = 1000; var cycleDelay = 15000; var startTimeout; var refreshTimeout; var tipCount = -1; RED.actions.add("core:toggle-show-tips",function(state) { if (state === undefined) { RED.userSettings.toggle("view-show-tips"); } else { enabled = state; if (enabled) { startTips(); } else { stopTips(); } } }); function setTip() { var r = Math.floor(Math.random() * tipCount); var tip = RED._("infotips:info.tip"+r); var m; while ((m=/({{(.*?)}})/.exec(tip))) { var shortcut = RED.keyboard.getShortcut(m[2]); if (shortcut) { tip = tip.replace(m[1],RED.keyboard.formatKey(shortcut.key)); } else { return; } } while ((m=/(\[([a-z]*?)\])/.exec(tip))) { tip = tip.replace(m[1],RED.keyboard.formatKey(m[2])); } tipBox.html(tip).fadeIn(200); if (startTimeout) { startTimeout = null; refreshTimeout = setInterval(cycleTips,cycleDelay); } } function cycleTips() { tipBox.fadeOut(300,function() { setTip(); }) } function startTips() { $(".red-ui-sidebar-info").addClass('show-tips'); resizeStack(); if (enabled) { if (!startTimeout && !refreshTimeout) { if (tipCount === -1) { do { tipCount++; } while(RED._("infotips:info.tip"+tipCount)!=="info.tip"+tipCount); } startTimeout = setTimeout(setTip,startDelay); } } } function stopTips() { $(".red-ui-sidebar-info").removeClass('show-tips'); resizeStack(); clearInterval(refreshTimeout); clearTimeout(startTimeout); refreshTimeout = null; startTimeout = null; } function nextTip() { clearInterval(refreshTimeout); startTimeout = true; setTip(); } return { start: startTips, stop: stopTips, next: nextTip, enabled: function() { return enabled; } } })(); function clear() { // sections.hide(); refresh(null); } function set(html,title) { console.warn("Deprecated use of RED.sidebar.info.set - use RED.sidebar.help.set instead") RED.sidebar.help.set(html,title); } function refreshSelection(selection) { if (selection === undefined) { selection = RED.view.selection(); } if (selection.nodes) { if (selection.nodes.length == 1) { var node = selection.nodes[0]; if (node.type === "subflow" && node.direction) { refresh(RED.nodes.subflow(node.z)); } else { refresh(node); } } else { refresh(selection.nodes); } } else if (selection.flows || selection.subflows) { refresh(selection.flows); } else { var activeWS = RED.workspaces.active(); var flow = RED.nodes.workspace(activeWS) || RED.nodes.subflow(activeWS); if (flow) { refresh(flow); } else { var workspace = RED.nodes.workspace(RED.workspaces.active()); if (workspace && workspace.info) { refresh(workspace); } else { refresh(null) // clear(); } } } } RED.events.on("view:selection-changed",refreshSelection); return { init: init, show: show, refresh: refresh, clear: clear, set: set } })();