[help-sidebar] Add help sidebar

This commit is contained in:
Nick O'Leary 2020-05-06 16:15:12 +01:00
parent 010e20989a
commit 9f29149d87
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
15 changed files with 443 additions and 51 deletions

View File

@ -166,6 +166,7 @@ module.exports = function(grunt) {
"packages/node_modules/@node-red/editor-client/src/js/ui/palette.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-info.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-info-outliner.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-help.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-config.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/tab-context.js",
"packages/node_modules/@node-red/editor-client/src/js/ui/palette-editor.js",

View File

@ -584,7 +584,16 @@
"none":"None",
"arrayItems": "__count__ items",
"showTips":"You can open the tips from the settings panel",
"outline": "Outline"
"outline": "Outline",
"globalConfig": "Global Configuration Nodes"
},
"help": {
"name": "Help",
"label": "help",
"search": "Search help",
"nodeHelp": "Node Help",
"showHelp": "Show help",
"showTopics": "Show topics"
},
"config": {
"name": "Configuration nodes",

View File

@ -433,8 +433,7 @@ var RED = (function() {
'<img width="50px" src="red/images/node-red-icon.svg" />'+
'</div>';
RED.sidebar.info.set(aboutHeader+RED.utils.renderMarkdown(data));
RED.sidebar.info.show();
RED.sidebar.help.set(aboutHeader+RED.utils.renderMarkdown(data));
});
}

View File

@ -29,6 +29,10 @@ RED.panels = (function() {
if (!vertical) {
container.addClass("red-ui-panels-horizontal");
}
$(children[0]).addClass("red-ui-panel");
$(children[1]).addClass("red-ui-panel");
var separator = $('<div class="red-ui-panels-separator"></div>').insertAfter(children[0]);
var startPosition;
var panelSizes = [];
@ -71,6 +75,9 @@ RED.panels = (function() {
var panel = {
ratio: function(ratio) {
if (ratio === undefined) {
return panelRatio;
}
panelRatio = ratio;
modifiedSizes = true;
if (ratio === 0 || ratio === 1) {

View File

@ -187,8 +187,7 @@
$(".red-ui-editor-type-buffer-type").on("click", function(e) {
e.preventDefault();
RED.sidebar.info.set(RED._("bufferEditor.modeDesc"));
RED.sidebar.info.show();
RED.sidebar.help.set(RED._("bufferEditor.modeDesc"));
})

View File

@ -237,8 +237,7 @@
var changeTimer;
$(".red-ui-editor-type-expression-legacy").on("click", function(e) {
e.preventDefault();
RED.sidebar.info.set(RED._("expressionEditor.compatModeDesc"));
RED.sidebar.info.show();
RED.sidebar.help.set(RED._("expressionEditor.compatModeDesc"));
})
var testExpression = function() {
var value = testDataEditor.getValue();

View File

@ -165,6 +165,7 @@ RED.palette = (function() {
metaData = typeInfo.set.module+" : ";
}
metaData += type;
$('<button type="button" onclick="RED.sidebar.help.show(\''+type+'\'); return false;" class="red-ui-button red-ui-button-small" style="float: right"><i class="fa fa-book"></i></button>').appendTo(popOverContent)
$('<p>',{style:"font-size: 0.8em"}).text(metaData).appendTo(popOverContent);
}
} catch(err) {
@ -255,6 +256,7 @@ RED.palette = (function() {
var popover = RED.popover.create({
target:d,
trigger: "hover",
interactive: true,
width: "300px",
content: "hi",
delay: { show: 750, hide: 50 }
@ -270,19 +272,19 @@ RED.palette = (function() {
// html: true,
// container:'body'
// });
d.on("click", function() {
RED.view.focus();
var helpText;
if (nt.indexOf("subflow:") === 0) {
helpText = RED.utils.renderMarkdown(RED.nodes.subflow(nt.substring(8)).info||"")||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>');
} else {
helpText = $("script[data-help-name='"+d.attr("data-palette-type")+"']").html()||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>');
}
// Don't look too closely. RED.sidebar.info.set will set the 'Description'
// section of the sidebar. Pass in the title of the Help section so it looks
// right.
RED.sidebar.info.set(helpText,RED._("sidebar.info.nodeHelp"));
});
// d.on("click", function() {
// RED.view.focus();
// var helpText;
// if (nt.indexOf("subflow:") === 0) {
// helpText = RED.utils.renderMarkdown(RED.nodes.subflow(nt.substring(8)).info||"")||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>');
// } else {
// helpText = $("script[data-help-name='"+d.attr("data-palette-type")+"']").html()||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>');
// }
// // Don't look too closely. RED.sidebar.info.set will set the 'Description'
// // section of the sidebar. Pass in the title of the Help section so it looks
// // right.
// RED.sidebar.type.show(helpText,RED._("sidebar.info.nodeHelp"));
// });
var chart = $("#red-ui-workspace-chart");
var chartSVG = $("#red-ui-workspace-chart>svg").get(0);
var activeSpliceLink;

View File

@ -250,6 +250,7 @@ RED.sidebar = (function() {
RED.popover.tooltip($("#red-ui-sidebar-separator").find(".red-ui-sidebar-control-right"),RED._("keyboard.toggleSidebar"),"core:toggle-sidebar");
showSidebar();
RED.sidebar.info.init();
RED.sidebar.help.init();
RED.sidebar.config.init();
RED.sidebar.context.init();
// hide info bar at start if screen rather narrow...

View File

@ -0,0 +1,355 @@
/**
* 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.help = (function() {
var content;
var toolbar;
var helpSection;
var panels;
var panelRatio;
var helpTopics = [];
var treeList;
var tocPanel;
var helpIndex = {};
function resizeStack() {
var h = $(content).parent().height() - toolbar.outerHeight();
panels.resize(h)
}
function init() {
content = document.createElement("div");
content.className = "red-ui-sidebar-info"
toolbar = $("<div>", {class:"red-ui-sidebar-header red-ui-info-toolbar"}).appendTo(content);
$('<span class="button-group"><a id="red-ui-sidebar-help-show-toc" class="red-ui-sidebar-header-button selected" href="#"><i class="fa fa-angle-right"></i> <i class="fa fa-list-alt"></i></a></span>').appendTo(toolbar)
var showTOCButton = toolbar.find('#red-ui-sidebar-help-show-toc')
RED.popover.tooltip(showTOCButton,RED._("sidebar.help.showTopics"));
showTOCButton.on("click",function(e) {
e.preventDefault();
if ($(this).hasClass('selected')) {
hideTOC();
} else {
showTOC();
}
});
// var searchInput = $('<input type="text">').appendTo(toolbar).searchBox({
// delay: 300,
// change: function() {}
// });
var stackContainer = $("<div>",{class:"red-ui-sidebar-help-stack"}).appendTo(content);
// var container = $("<div>", {class:"red-ui-info-outline"}).css({'height': '100%'});
tocPanel = $("<div>", {class: "red-ui-sidebar-help-toc"}).appendTo(stackContainer);
var helpPanel = $("<div>").css({
"overflow-y": "scroll"
}).appendTo(stackContainer);
panels = RED.panels.create({
container: stackContainer
})
panels.ratio(0.5);
// var searchDiv = $("<div>",{class: "red-ui-help-search"}).appendTo(tocPanel);
helpSearch = $('<input type="text" data-i18n="[placeholder]sidebar.help.search">').appendTo(toolbar).searchBox({
delay: 100,
change: function() {
var val = $(this).val();
if (val) {
showTOC();
var c = treeList.treeList('filter',function(item) {
if (item.depth === 0) {
return true;
}
return item.id && item.id.indexOf(val) > -1
},true)
} else {
treeList.treeList('filter',null);
var selected = treeList.treeList('selected');
if (selected.id) {
treeList.treeList('show',selected.id);
}
}
}
})
helpSection = $("<div>",{class:"red-ui-help"}).css({
"padding":"6px",
}).appendTo(helpPanel)
treeList = $("<div>").css({width: "100%"}).appendTo(tocPanel).treeList({data: []})
treeList.on('treelistselect', function(e,item) {
if (item.nodeType) {
showHelp(item.nodeType);
}
})
RED.sidebar.addTab({
id: "help",
label: RED._("sidebar.help.label"),
name: RED._("sidebar.help.name"),
iconClass: "fa fa-book",
action:"core:show-help-tab",
content: content,
pinned: true,
enableOnEdit: true,
onchange: function() {
resizeStack()
}
});
$(window).on("resize", resizeStack);
$(window).on("focus", resizeStack);
var refreshTimer;
RED.events.on('registry:node-type-added', function(nodeType) {
if (!refreshTimer) {
refreshTimer = setTimeout(function() {
refreshTimer = null;
refreshHelpIndex();
},500);
}
});
RED.actions.add("core:show-help-tab",show);
}
function hideTOC() {
var tocButton = $('#red-ui-sidebar-help-show-toc')
if (tocButton.hasClass('selected')) {
tocButton.removeClass('selected');
panelRatio = panels.ratio();
tocPanel.css({"transition":"height 0.2s"})
panels.ratio(0)
setTimeout(function() {
tocPanel.css({"transition":""})
},250);
}
}
function showTOC() {
var tocButton = $('#red-ui-sidebar-help-show-toc')
if (!tocButton.hasClass('selected')) {
tocButton.addClass('selected');
tocPanel.css({"transition":"height 0.2s"})
panels.ratio(Math.max(0.3,Math.min(panelRatio,0.7)));
setTimeout(function() {
tocPanel.css({"transition":""})
},250);
}
}
function refreshHelpIndex() {
helpTopics = [];
var modules = RED.nodes.registry.getModuleList();
var moduleNames = Object.keys(modules);
moduleNames.sort();
var helpData = [{
label: RED._("sidebar.help.nodeHelp"),
children: [],
expanded: true
}]
moduleNames.forEach(function(moduleName) {
var module = modules[moduleName];
var nodeTypes = [];
var setNames = Object.keys(module.sets);
setNames.forEach(function(setName) {
module.sets[setName].types.forEach(function(nodeType) {
if ($("script[data-help-name='"+nodeType+"']").length) {
nodeTypes.push({
id: moduleName+"/"+nodeType,
nodeType: nodeType,
element:getNodeLabel({_def:RED.nodes.getType(nodeType),type:nodeType})
})
}
})
})
if (nodeTypes.length > 0) {
helpData[0].children.push({
id: moduleName,
icon: "fa fa-cube",
label: moduleName,
children: nodeTypes
})
}
});
treeList.treeList("data",helpData);
}
function getNodeLabel(n) {
var div = $('<div>',{class:"red-ui-info-outline-item"});
RED.utils.createNodeIcon(n).appendTo(div);
var contentDiv = $('<div>',{class:"red-ui-search-result-description"}).appendTo(div);
$('<div>',{class:"red-ui-search-result-node-label red-ui-info-outline-item-label"}).text(n.type).appendTo(contentDiv);
return div;
}
function showHelp(nodeType) {
helpSection.empty();
var helpText = $("script[data-help-name='"+nodeType+"']").html()||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>');
var title = nodeType;
setInfoText(title, helpText, helpSection);
var ratio = panels.ratio();
if (ratio > 0.7) {
panels.ratio(0.7)
}
}
function show(type) {
RED.sidebar.show("help");
if (type) {
hideTOC();
showHelp(type);
}
}
// 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;
}
var subflowNode;
helpSection.empty();
if (node === null || Array.isArray(node)) {
return;
} else {
// A single 'thing' selected.
// Check to see if this is a subflow or subflow instance
var m = /^subflow(:(.+))?$/.exec(node.type);
if (m) {
if (m[2]) {
subflowNode = RED.nodes.subflow(m[2]);
} else {
subflowNode = node;
}
}
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||"")||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>'));
setInfoText(node.type, helpText, helpSection);
} else {
helpSearch.searchBox("value",node.type);
// helpText = $("script[data-help-name='"+node.type+"']").html()||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>');
}
}
// $(".red-ui-sidebar-info-stack").scrollTop(0);
}
}
function setInfoText(title, infoText,target) {
if (title) {
$("<h1>",{class:"red-ui-help-title"}).text(title).appendTo(target);
}
var info = addTargetToExternalLinks($('<div class="red-ui-help"><span class="red-ui-text-bidi-aware" dir=\"'+RED.text.bidi.resolveBaseTextDir(infoText)+'">'+infoText+'</span></div>')).appendTo(target);
info.find(".red-ui-text-bidi-aware").contents().filter(function() { return this.nodeType === 3 && this.textContent.trim() !== "" }).wrap( "<span></span>" );
var foldingHeader = "H3";
info.find(foldingHeader).wrapInner('<a class="red-ui-help-info-header expanded" href="#"></a>')
.find("a").prepend('<i class="fa fa-angle-right">').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);
})
target.parent().scrollTop(0);
}
function set(html,title) {
$(helpSection).empty();
setInfoText(title,html,helpSection);
show();
}
// 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,
set: set
}
})();

View File

@ -14,17 +14,17 @@ RED.sidebar.info.outliner = (function() {
function getFlowData() {
var flowData = [
{
label: "Flows",
label: RED._("menu.label.flows"),
expanded: true,
children: []
},
{
label: "Subflows",
label: RED._("menu.label.subflows"),
children: []
},
{
id: "__global__",
label: "Global Configuration Nodes",
label: RED._("sidebar.info.globalConfig"),
children: []
}
]
@ -194,12 +194,9 @@ RED.sidebar.info.outliner = (function() {
function build() {
var container = $("<div>", {class:"red-ui-info-outline"}).css({'height': '100%'});
var toolbar = $("<div>", {class:"red-ui-sidebar-header red-ui-info-outline-toolbar"}).appendTo(container);
toolbar.on("click", function(evt) {
evt.stopPropagation();
})
var toolbar = $("<div>", {class:"red-ui-sidebar-header red-ui-info-toolbar"}).appendTo(container);
searchInput = $('<input type="text">').appendTo(toolbar).searchBox({
searchInput = $('<input type="text" data-i18n="[placeholder]menu.label.search">').appendTo(toolbar).searchBox({
delay: 300,
change: function() {
var val = $(this).val();

View File

@ -48,7 +48,10 @@ RED.sidebar.info = (function() {
var stackContainer = $("<div>",{class:"red-ui-sidebar-info-stack"}).appendTo(content);
var outlinerPanel = $("<div>").height("calc(70%)").appendTo(stackContainer);
var outlinerPanel = $("<div>").css({
"overflow": "hidden",
"height": "calc(70%)"
}).appendTo(stackContainer);
var propertiesPanel = $("<div>").css({
"overflow":"hidden",
"height":"100%",
@ -61,7 +64,7 @@ RED.sidebar.info = (function() {
propertiesPanelHeaderIcon = $("<span>").appendTo(propertiesPanelHeader);
propertiesPanelHeaderLabel = $("<span>").appendTo(propertiesPanelHeader);
propertiesPanelHeaderHelp = $('<button class="red-ui-button red-ui-button-small"><i class="fa fa-question"></button>').css({
propertiesPanelHeaderHelp = $('<button class="red-ui-button red-ui-button-small"><i class="fa fa-book"></button>').css({
position: 'absolute',
top: '12px',
right: '38px'
@ -69,10 +72,10 @@ RED.sidebar.info = (function() {
evt.preventDefault();
evt.stopPropagation();
if (selectedObject) {
RED.sidebar.info.outliner.reveal(selectedObject);
RED.sidebar.help.show(selectedObject.type)
}
}).appendTo(propertiesPanelHeader);
RED.popover.tooltip(propertiesPanelHeaderHelp,"Show help");
RED.popover.tooltip(propertiesPanelHeaderHelp,RED._("sidebar.help.showHelp"));
propertiesPanelHeaderReveal = $('<button class="red-ui-button red-ui-button-small"><i class="fa fa-search"></button>').css({
@ -537,15 +540,8 @@ RED.sidebar.info = (function() {
}
function set(html,title) {
// tips.stop();
// sections.show();
refresh(null);
// propertiesSection.container.hide();
console.warn("Missing RED.sidebar.tab.set")
// infoSection.container.show();
// infoSection.title.text(title||RED._("sidebar.info.desc"));
// setInfoText(html,infoSection.content);
$(".red-ui-sidebar-info-stack").scrollTop(0);
console.warn("Deprecated use of RED.sidebar.info.set - use RED.sidebar.help.set instead")
RED.sidebar.help.set(html,title);
}
function refreshSelection(selection) {

View File

@ -47,6 +47,7 @@
.red-ui-panel {
overflow: auto;
height: calc(50% - 4px);
position: relative;
}
.red-ui-panels.red-ui-panels-horizontal {

View File

@ -42,6 +42,7 @@
@import "tab-config";
@import "tab-context";
@import "tab-info";
@import "tab-help";
@import "popover";
@import "flow";
@import "palette-editor";

View File

@ -0,0 +1,27 @@
.red-ui-sidebar-help-stack {
// height: calc(100% - 39px);
}
.red-ui-help-search {
border-bottom: 1px solid $secondary-border-color;
}
.red-ui-sidebar-help-toc {
.red-ui-treeList-label {
font-size: 13px;
padding: 2px 0;
overflow: hidden;
white-space: nowrap;
}
}
#red-ui-sidebar-help-show-toc {
i.fa-angle-right {
transition: all 0.2s ease-in-out;
}
&.selected {
i.fa-angle-right {
transform: rotate(90deg);
}
}
}

View File

@ -39,9 +39,7 @@ table.red-ui-info-table {
width: 100%;
}
table.red-ui-info-table tr:not(.blank) {
&:not(:first-child) {
border-top: 1px solid $secondary-border-color;
}
border-top: 1px solid $secondary-border-color;
border-bottom: 1px solid $secondary-border-color;
}
.red-ui-help-property-expand {
@ -143,6 +141,9 @@ div.red-ui-info-table {
font-size: 1.296em;
line-height: 1.3em;
margin: 8px auto;
&.red-ui-help-title {
border-bottom: 1px solid $tertiary-border-color;
}
}
h2 {
font-weight: 500;
@ -299,12 +300,7 @@ div.red-ui-info-table {
padding: 2px 4px 2px;
}
.red-ui-help-search {
border-bottom: 1px solid $secondary-border-color;
}
.red-ui-info-outline {
.red-ui-info-outline,.red-ui-sidebar-help-toc {
display: flex;
flex-direction: column;
@ -478,9 +474,11 @@ div.red-ui-info-table {
filter: brightness(2.5);
}
.red-ui-info-outline-toolbar {
.red-ui-info-toolbar {
min-height: 39px;
height: 39px;
box-sizing: border-box;
text-align: left;
// padding-left: 9px;
// box-sizing: border-box;
// background: $palette-header-background;