/** * 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 selectedObject; var tipBox; // TODO: remove this var expandedSections = { "property": false }; function resizeStack() { var h = $(content).parent().height(); 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); propertiesPanelHeaderHelp = $('').css({ position: 'absolute', top: '12px', right: '38px' }).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); } }).appendTo(propertiesPanelHeader); RED.popover.tooltip(propertiesPanelHeaderReveal,"Show in outline"); propertiesPanelContent = $("
").css({ "flex":"1 1 auto", "overflow-y":"scroll", }).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 }); $(window).on("resize", resizeStack); $(window).on("focus", resizeStack); // Tip Box var 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) { return; } else if (Array.isArray(node)) { // Multiple things selected // - hide help and info sections propertiesPanelHeaderIcon.empty(); RED.utils.createNodeIcon({type:"_selection_"}).appendTo(propertiesPanelHeaderIcon); propertiesPanelHeaderLabel.text("Selection"); propertiesPanelHeaderReveal.hide(); propertiesPanelHeaderHelp.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. // 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; } subflowUserCount = 0; var subflowType = "subflow:"+subflowNode.id; RED.nodes.eachNode(function(n) { if (n.type === subflowType) { subflowUserCount++; } }); } propertiesPanelHeaderIcon.empty(); RED.utils.createNodeIcon(node).appendTo(propertiesPanelHeaderIcon); propertiesPanelHeaderLabel.text(RED.utils.getNodeLabel(node, node.type+" "+node.id)); propertiesPanelHeaderReveal.show(); selectedObject = node; if (node.type === "tab" || node.type === "subflow") { // If nothing is selected, but we're on a flow or subflow tab. propertiesPanelHeaderHelp.hide(); } else if (node.type === "group") { propertiesPanelHeaderHelp.hide(); propRow = $(''+RED._("sidebar.info.group")+'').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 { propertiesPanelHeaderHelp.show (); propRow = $('').appendTo(tableBody); if (!subflowRegex) { $(propRow.children()[0]).text(RED._("sidebar.info.node")) } else { $(propRow.children()[0]).text(RED._("sidebar.info.subflow")) } RED.utils.createObjectElement(node.id).appendTo(propRow.children()[1]); 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) { 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).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); } // var helpText = ""; // if (node.type === "tab" || node.type === "subflow") { // } else { // if (subflowNode && node.type !== "subflow") { // // Selected a subflow instance node. // // - The subflow template info goes into help // helpText = (RED.utils.renderMarkdown(subflowNode.info||"")||(''+RED._("sidebar.info.none")+'')); // } else { // helpText = $("script[data-help-name='"+node.type+"']").html()||(''+RED._("sidebar.info.none")+''); // } // setInfoText(helpText, helpSection.content); // } 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) // var editInfo = $('').appendTo(infoSectionContainer).on("click", function(evt) { // //.text(RED._("sidebar.info.editDescription")) // evt.preventDefault(); // evt.stopPropagation(); // if (node.type === 'tab') { // // } else if (node.type === 'subflow') { // // } else if (node.type === 'group') { // // } else if (node._def.category !== 'config') { // RED.editor.edit(node,"editor-tab-description"); // } else { // // } // }) 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); }) } 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=/(\[(.*?)\])/.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'); if (enabled) { if (!startTimeout && !refreshTimeout) { if (tipCount === -1) { do { tipCount++; } while(RED._("infotips:info.tip"+tipCount)!=="infotips:info.tip"+tipCount); } startTimeout = setTimeout(setTip,startDelay); } } } function stopTips() { $(".red-ui-sidebar-info").removeClass('show-tips'); 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 } })();