@node-red/editor-client 5.0.0-beta.0 → 5.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/public/red/red.js CHANGED
@@ -910,6 +910,7 @@ var RED = (function() {
910
910
  // Register the core set of sidebar panels now the menu is ready to receive items
911
911
  RED.palette.init();
912
912
  RED.sidebar.info.init();
913
+ RED.sidebar.info.outliner.init();
913
914
  RED.sidebar.help.init();
914
915
  RED.sidebar.config.init();
915
916
  RED.sidebar.context.init();
@@ -944,7 +945,6 @@ var RED = (function() {
944
945
  '<div id="red-ui-workspace"></div>'+
945
946
  '<div id="red-ui-sidebar"></div>'+
946
947
  '<div id="red-ui-editor-stack" tabindex="-1"></div>'+
947
- // '<div id="red-ui-palette"></div>'+
948
948
  '</div>').appendTo(options.target);
949
949
 
950
950
  // Don't use the `hide` class on this container, as the show reverts it to block rather
@@ -954,6 +954,7 @@ var RED = (function() {
954
954
  $('<div id="red-ui-editor-plugin-configs"></div>').appendTo(options.target);
955
955
  $('<div id="red-ui-editor-node-configs"></div>').appendTo(options.target);
956
956
  $('<div id="red-ui-full-shade" class="hide"></div>').appendTo(options.target);
957
+ $('<div id="red-ui-global-dialog-container"></div>').appendTo(options.target);
957
958
 
958
959
  loader.init().appendTo("#red-ui-main-container");
959
960
  loader.start("...",0);
@@ -10062,7 +10063,13 @@ RED.utils = (function() {
10062
10063
  var copyPayload = $('<button class="red-ui-button red-ui-button-small"><i class="fa fa-clipboard"></i></button>').appendTo(copyTools).on("click", function(e) {
10063
10064
  e.preventDefault();
10064
10065
  e.stopPropagation();
10065
- RED.clipboard.copyText(msg,copyPayload,"clipboard.copyMessageValue");
10066
+ var payloadToCopy;
10067
+ if (typeof msg === "number") {
10068
+ payloadToCopy = obj.find(".red-ui-debug-msg-type-number").first().text();
10069
+ } else {
10070
+ payloadToCopy = msg;
10071
+ }
10072
+ RED.clipboard.copyText(payloadToCopy, copyPayload, "clipboard.copyMessageValue");
10066
10073
  })
10067
10074
  RED.popover.tooltip(copyPayload,RED._("node-red:debug.sidebar.copyPayload"));
10068
10075
  if (enablePinning && strippedKey !== undefined && strippedKey !== '') {
@@ -10390,7 +10397,7 @@ RED.utils = (function() {
10390
10397
  var sr = $('<div class="red-ui-debug-msg-object-entry collapsed"></div>').appendTo(stringRow);
10391
10398
  var stringEncoding = "";
10392
10399
  try {
10393
- stringEncoding = String.fromCharCode.apply(null, new Uint16Array(data))
10400
+ stringEncoding = new TextDecoder().decode(new Uint8Array(data));
10394
10401
  } catch(err) {
10395
10402
  console.log(err);
10396
10403
  }
@@ -11683,8 +11690,10 @@ RED.utils = (function() {
11683
11690
  var deleteButton = $('<a/>',{href:"#",class:"red-ui-editableList-item-remove red-ui-button red-ui-button-small"}).appendTo(li);
11684
11691
  $('<i/>',{class:"fa fa-remove"}).appendTo(deleteButton);
11685
11692
  li.addClass("red-ui-editableList-item-removable");
11693
+ var removeTip = RED.popover.tooltip(deleteButton, RED._("common.label.delete"));
11686
11694
  deleteButton.on("click", function(evt) {
11687
11695
  evt.preventDefault();
11696
+ removeTip.close();
11688
11697
  var data = row.data('data');
11689
11698
  li.addClass("red-ui-editableList-item-deleting")
11690
11699
  li.fadeOut(300, function() {
@@ -11832,6 +11841,7 @@ RED.utils = (function() {
11832
11841
  * - autoSelect: boolean - default true - triggers item selection when navigating
11833
11842
  * list by keyboard. If the list has checkboxed items
11834
11843
  * you probably want to set this to false
11844
+ * - expandOnLabel: boolean - default true - items expand when their label is clicked
11835
11845
  *
11836
11846
  * methods:
11837
11847
  * - data(items) - clears existing items and replaces with new data
@@ -11895,6 +11905,7 @@ RED.utils = (function() {
11895
11905
  *
11896
11906
  *
11897
11907
  */
11908
+ const paddingPerDepth = 5;
11898
11909
 
11899
11910
  $.widget( "nodered.treeList", {
11900
11911
  _create: function() {
@@ -11992,7 +12003,10 @@ RED.utils = (function() {
11992
12003
  } else {
11993
12004
  that._topList.find(".focus").removeClass("focus")
11994
12005
  }
11995
- target.treeList.label.addClass('focus')
12006
+ if (target.treeList.label) {
12007
+ target.treeList.label.addClass('focus')
12008
+ }
12009
+ that.reveal(target);
11996
12010
  }
11997
12011
  });
11998
12012
  this._data = [];
@@ -12146,11 +12160,11 @@ RED.utils = (function() {
12146
12160
  if (child.depth !== parent.depth+1) {
12147
12161
  child.depth = parent.depth+1;
12148
12162
  // var labelPaddingWidth = ((child.gutter ? child.gutter[0].offsetWidth + 2 : 0) + (child.depth * 20));
12149
- var labelPaddingWidth = (((child.gutter&&!child.gutter.hasClass("red-ui-treeList-gutter-float"))?child.gutter.width()+2:0)+(child.depth*20));
12163
+ var labelPaddingWidth = (((child.gutter&&!child.gutter.hasClass("red-ui-treeList-gutter-float"))?child.gutter.width()+2:0)+(child.depth*paddingPerDepth));
12150
12164
  child.treeList.labelPadding.width(labelPaddingWidth+'px');
12151
12165
  if (child.element) {
12152
12166
  $(child.element).css({
12153
- width: "calc(100% - "+(labelPaddingWidth+20+(child.icon?20:0))+"px)"
12167
+ width: "calc(100% - "+(labelPaddingWidth+paddingPerDepth+(child.icon?paddingPerDepth:0))+"px)"
12154
12168
  })
12155
12169
  }
12156
12170
  // This corrects all child item depths
@@ -12279,7 +12293,7 @@ RED.utils = (function() {
12279
12293
  if (!childrenAdded) {
12280
12294
  startTime = Date.now();
12281
12295
  spinner = $('<div class="red-ui-treeList-spinner">').css({
12282
- "background-position": (35+depth*20)+'px 50%'
12296
+ "background-position": (35+depth*paddingPerDepth)+'px 50%'
12283
12297
  }).appendTo(container);
12284
12298
  }
12285
12299
 
@@ -12331,10 +12345,10 @@ RED.utils = (function() {
12331
12345
  $(element).appendTo(item.treeList.label);
12332
12346
  // using the JQuery Object, the gutter width will
12333
12347
  // be wrong when the element is reattached the second time
12334
- var labelPaddingWidth = (item.gutter ? item.gutter[0].offsetWidth + 2 : 0) + (item.depth * 20);
12348
+ var labelPaddingWidth = (item.gutter ? item.gutter[0].offsetWidth + 2 : 0) + (item.depth * paddingPerDepth);
12335
12349
 
12336
12350
  $(element).css({
12337
- width: "calc(100% - "+(labelPaddingWidth+20+(item.icon?20:0))+"px)"
12351
+ width: "calc(100% - "+(labelPaddingWidth+paddingPerDepth+(item.icon?paddingPerDepth:0))+"px)"
12338
12352
  })
12339
12353
  }
12340
12354
  item.element = element;
@@ -12369,7 +12383,7 @@ RED.utils = (function() {
12369
12383
 
12370
12384
  }
12371
12385
 
12372
- var labelPaddingWidth = ((item.gutter&&!item.gutter.hasClass("red-ui-treeList-gutter-float"))?item.gutter.width()+2:0)+(depth*20);
12386
+ var labelPaddingWidth = ((item.gutter&&!item.gutter.hasClass("red-ui-treeList-gutter-float"))?item.gutter.width()+2:0)+(depth*paddingPerDepth);
12373
12387
 
12374
12388
  item.treeList.labelPadding = $('<span>').css({
12375
12389
  display: "inline-block",
@@ -12431,12 +12445,14 @@ RED.utils = (function() {
12431
12445
  });
12432
12446
  // $('<span class="red-ui-treeList-icon"><i class="fa fa-folder-o" /></span>').appendTo(label);
12433
12447
  label.on("click.red-ui-treeList-expand", function(e) {
12434
- if (container.hasClass("expanded")) {
12435
- if (item.hasOwnProperty('selected') || label.hasClass("selected")) {
12436
- item.treeList.collapse();
12448
+ if (that.options.expandOnLabel !== false || item.expandOnLabel === true) {
12449
+ if (container.hasClass("expanded")) {
12450
+ if (item.hasOwnProperty('selected') || label.hasClass("selected")) {
12451
+ item.treeList.collapse();
12452
+ }
12453
+ } else {
12454
+ item.treeList.expand();
12437
12455
  }
12438
- } else {
12439
- item.treeList.expand();
12440
12456
  }
12441
12457
  })
12442
12458
  if (!item.children) {
@@ -12574,7 +12590,7 @@ RED.utils = (function() {
12574
12590
  } else if (item.element) {
12575
12591
  $(item.element).appendTo(label);
12576
12592
  $(item.element).css({
12577
- width: "calc(100% - "+(labelPaddingWidth+20+(item.icon?20:0))+"px)"
12593
+ width: "calc(100% - "+(labelPaddingWidth+paddingPerDepth+(item.icon?paddingPerDepth:0))+"px)"
12578
12594
  })
12579
12595
  }
12580
12596
  if (item.children) {
@@ -12683,6 +12699,10 @@ RED.utils = (function() {
12683
12699
  }
12684
12700
 
12685
12701
  that._topList.find(".focus").removeClass("focus");
12702
+
12703
+ if (item.treeList.label) {
12704
+ item.treeList.label.addClass("focus");
12705
+ }
12686
12706
 
12687
12707
  if (triggerEvent !== false) {
12688
12708
  this._trigger("select",null,item)
@@ -13308,6 +13328,13 @@ RED.panels = (function() {
13308
13328
  $(children[1]).addClass("red-ui-panel");
13309
13329
 
13310
13330
  var separator = $('<div class="red-ui-panels-separator"></div>').insertAfter(children[0]);
13331
+ if (options.invisibleSeparator) {
13332
+ if (!vertical) {
13333
+ throw new Error("invisibleSeparator option is only valid for vertical panels");
13334
+ }
13335
+ separator.addClass("red-ui-panels-separator-invisible");
13336
+ $('<div class="red-ui-panels-separator-handle"></div>').appendTo(separator)
13337
+ }
13311
13338
  var startPosition;
13312
13339
  var panelSizes = [];
13313
13340
  var modifiedSizes = false;
@@ -14782,12 +14809,18 @@ RED.tabs = (function() {
14782
14809
  }
14783
14810
  function activatePreviousTab() {
14784
14811
  var previous = findPreviousVisibleTab();
14812
+ if (previous.length === 0) {
14813
+ previous = ul.find("li.red-ui-tab:not(.hide-tab)").last();
14814
+ }
14785
14815
  if (previous.length > 0) {
14786
14816
  activateTab(previous.find("a"));
14787
14817
  }
14788
14818
  }
14789
14819
  function activateNextTab() {
14790
14820
  var next = findNextVisibleTab();
14821
+ if (next.length === 0) {
14822
+ next = ul.find("li.red-ui-tab:not(.hide-tab)").first();
14823
+ }
14791
14824
  if (next.length > 0) {
14792
14825
  activateTab(next.find("a"));
14793
14826
  }
@@ -17944,16 +17977,10 @@ RED.deploy = (function() {
17944
17977
  }
17945
17978
 
17946
17979
  function shadeShow() {
17947
- $("#red-ui-header-shade").show();
17948
- $("#red-ui-editor-shade").show();
17949
- $("#red-ui-palette-shade").show();
17950
- $(".red-ui-sidebar-shade").show();
17980
+ RED.notifications.shade.show();
17951
17981
  }
17952
17982
  function shadeHide() {
17953
- $("#red-ui-header-shade").hide();
17954
- $("#red-ui-editor-shade").hide();
17955
- $("#red-ui-palette-shade").hide();
17956
- $(".red-ui-sidebar-shade").hide();
17983
+ RED.notifications.shade.hide();
17957
17984
  }
17958
17985
  function deployButtonSetBusy(){
17959
17986
  $(".red-ui-deploy-button-content").css('opacity',0);
@@ -23631,8 +23658,8 @@ RED.view = (function() {
23631
23658
  element: $('<span class="button-group">'+
23632
23659
  '<button class="red-ui-footer-button" id="red-ui-view-searchtools-search"><i class="fa fa-search"></i></button>' +
23633
23660
  '</span>' +
23634
- '<span class="button-group search-counter">' +
23635
- '<span class="red-ui-footer-button" id="red-ui-view-searchtools-counter">? of ?</span>' +
23661
+ '<span class="button-group red-ui-view-searchtools-counter">' +
23662
+ '<span class="red-ui-footer-button" id="red-ui-view-searchtools-counter-label">? of ?</span>' +
23636
23663
  '</span>' +
23637
23664
  '<span class="button-group">' +
23638
23665
  '<button class="red-ui-footer-button" id="red-ui-view-searchtools-prev"><i class="fa fa-chevron-left"></i></button>' +
@@ -24406,6 +24433,13 @@ RED.view = (function() {
24406
24433
  quickAddLink.virtualLink = true;
24407
24434
  }
24408
24435
  hideDragLines();
24436
+ } else if (quickAddLink) {
24437
+ // continuing an existing quick add - set the filter accordingly
24438
+ if (quickAddLink.portType === PORT_TYPE_OUTPUT) {
24439
+ filter = {input:true}
24440
+ } else {
24441
+ filter = {output:true}
24442
+ }
24409
24443
  }
24410
24444
  if (linkToSplice || spliceMultipleLinks) {
24411
24445
  filter = {
@@ -30032,6 +30066,9 @@ RED.view = (function() {
30032
30066
  suggestedNodes = [suggestedNodes]
30033
30067
  }
30034
30068
  suggestedNodes = suggestedNodes.filter(n => {
30069
+ if (n.type === 'junction') {
30070
+ return true
30071
+ }
30035
30072
  const def = RED.nodes.getType(n.type)
30036
30073
  if (def?.set && def.set.enabled === false) {
30037
30074
  // Exclude disabled node set
@@ -30457,7 +30494,6 @@ RED.view = (function() {
30457
30494
  },
30458
30495
  selectNodes: function(options) {
30459
30496
  $("#red-ui-workspace-tabs-shade").show();
30460
- $("#red-ui-palette-shade").show();
30461
30497
  $(".red-ui-sidebar-shade").show();
30462
30498
  $("#red-ui-header-shade").show();
30463
30499
  $("#red-ui-workspace").addClass("red-ui-workspace-select-mode");
@@ -30479,7 +30515,6 @@ RED.view = (function() {
30479
30515
  var closeNotification = function() {
30480
30516
  clearSelection();
30481
30517
  $("#red-ui-workspace-tabs-shade").hide();
30482
- $("#red-ui-palette-shade").hide();
30483
30518
  $(".red-ui-sidebar-shade").hide();
30484
30519
  $("#red-ui-header-shade").hide();
30485
30520
  $("#red-ui-workspace").removeClass("red-ui-workspace-select-mode");
@@ -31072,10 +31107,12 @@ RED.view.navigator = (function() {
31072
31107
  scrollPos = [$("#red-ui-workspace-chart").scrollLeft(),$("#red-ui-workspace-chart").scrollTop()];
31073
31108
  // Convert scroll position (in scaled pixels) to workspace coordinates, then to minimap coordinates
31074
31109
  // scrollPos is in scaled canvas pixels, divide by scaleFactor to get workspace coords
31075
- navBorder.attr('x',scrollPos[0]/scaleFactor/nav_scale)
31076
- .attr('y',scrollPos[1]/scaleFactor/nav_scale)
31077
- .attr('width',chartSize[0]/nav_scale/scaleFactor)
31078
- .attr('height',chartSize[1]/nav_scale/scaleFactor)
31110
+ if (chartSize[0] > 0 && chartSize[1] > 0) {
31111
+ navBorder.attr('x',scrollPos[0]/scaleFactor/nav_scale)
31112
+ .attr('y',scrollPos[1]/scaleFactor/nav_scale)
31113
+ .attr('width',chartSize[0]/nav_scale/scaleFactor)
31114
+ .attr('height',chartSize[1]/nav_scale/scaleFactor)
31115
+ }
31079
31116
  }
31080
31117
  }
31081
31118
  function show () {
@@ -31139,8 +31176,8 @@ RED.view.navigator = (function() {
31139
31176
  RED.actions.add("core:toggle-navigator",toggle);
31140
31177
  navContainer = $('<div>').css({
31141
31178
  "position":"absolute",
31142
- "bottom":$("#red-ui-workspace-footer").height(),
31143
- "right":0,
31179
+ "bottom":$("#red-ui-workspace-footer").height() + 12,
31180
+ "right": 16,
31144
31181
  zIndex: 1
31145
31182
  }).addClass('red-ui-navigator-container').appendTo("#red-ui-workspace").hide();
31146
31183
  navBox = d3.select(navContainer[0])
@@ -31149,6 +31186,8 @@ RED.view.navigator = (function() {
31149
31186
  .attr("height", nav_height)
31150
31187
  .attr("pointer-events", "all")
31151
31188
  .attr("id","red-ui-navigator-canvas")
31189
+ navVis = navBox.append("svg:g")
31190
+
31152
31191
  navBox.append("rect").attr("x",0).attr("y",0).attr("width",nav_width).attr("height",nav_height).style({
31153
31192
  fill:"none",
31154
31193
  stroke:"none",
@@ -31189,7 +31228,6 @@ RED.view.navigator = (function() {
31189
31228
  }
31190
31229
  })
31191
31230
  navBorder = navBox.append("rect").attr("class","red-ui-navigator-border")
31192
- navVis = navBox.append("svg:g")
31193
31231
  RED.statusBar.add({
31194
31232
  id: "view-navigator",
31195
31233
  align: "right",
@@ -32688,6 +32726,7 @@ RED.view.tools = (function() {
32688
32726
  * limitations under the License.
32689
32727
  **/
32690
32728
  RED.sidebar = (function() {
32729
+ const sidebarLayoutVersion = 1
32691
32730
  const sidebars = {
32692
32731
  primary: {
32693
32732
  id: 'primary',
@@ -32695,7 +32734,8 @@ RED.sidebar = (function() {
32695
32734
  menuToggle: 'menu-item-sidebar',
32696
32735
  minimumWidth: 180,
32697
32736
  maximumWidth: 800,
32698
- defaultWidth: 300
32737
+ defaultWidth: 300,
32738
+ defaultTopHeight: 0.7
32699
32739
  },
32700
32740
  secondary: {
32701
32741
  id: 'secondary',
@@ -32704,29 +32744,38 @@ RED.sidebar = (function() {
32704
32744
  minimumWidth: 180,
32705
32745
  maximumWidth: 800,
32706
32746
  // Make LH side slightly narrower by default as its the palette that doesn't require a lot of width
32707
- defaultWidth: 210
32747
+ defaultWidth: 210,
32748
+ defaultTopHeight: 0.5
32708
32749
  }
32709
32750
  }
32710
32751
  const defaultSidebarConfiguration = {
32711
- primary: ['info','debug','help','config','context'],
32712
- secondary: ['palette']
32752
+ primary: [ ['info','help','config','context'], ['debug'] ],
32753
+ secondary: [ ['explorer'], ['palette'] ]
32713
32754
  }
32714
32755
 
32715
32756
  const knownTabs = {};
32716
32757
 
32717
32758
  function exportSidebarState () {
32718
32759
  const state = {
32719
- primary: [],
32720
- secondary: []
32760
+ primary: [[], []],
32761
+ secondary: [[], []],
32762
+ v: sidebarLayoutVersion
32721
32763
  }
32722
- sidebars.primary.tabBar.children('button').each(function() {
32723
- const tabId = $(this).attr('data-tab-id');
32724
- state.primary.push(tabId);
32725
- })
32726
- sidebars.secondary.tabBar.children('button').each(function() {
32727
- const tabId = $(this).attr('data-tab-id');
32728
- state.secondary.push(tabId);
32729
- })
32764
+ function getTabButtons(tabBar) {
32765
+ const result = []
32766
+ tabBar.children('button').each(function() {
32767
+ const tabId = $(this).attr('data-tab-id');
32768
+ if (tabId) {
32769
+ result.push(tabId);
32770
+ }
32771
+ })
32772
+ return result
32773
+ }
32774
+ state.primary[0] = getTabButtons(sidebars.primary.tabBars.top.container);
32775
+ state.primary[1] = getTabButtons(sidebars.primary.tabBars.bottom.container);
32776
+ state.secondary[0] = getTabButtons(sidebars.secondary.tabBars.top.container);
32777
+ state.secondary[1] = getTabButtons(sidebars.secondary.tabBars.bottom.container);
32778
+
32730
32779
  RED.settings.set('editor.sidebar.state', state)
32731
32780
  }
32732
32781
 
@@ -32758,18 +32807,36 @@ RED.sidebar = (function() {
32758
32807
  let targetTabButtonIndex = -1 // Append to end by default
32759
32808
 
32760
32809
  // Check the saved sidebar state to see if this tab should be added to the primary or secondary sidebar
32761
- const savedState = RED.settings.get('editor.sidebar.state', defaultSidebarConfiguration)
32810
+ let savedState = RED.settings.get('editor.sidebar.state', defaultSidebarConfiguration)
32811
+ if (typeof savedState.primary[0] === 'string' || typeof savedState.secondary[0] === 'string' || savedState.v === undefined) {
32812
+ // This is a beta.0/1 format. Reset it for beta.2
32813
+ savedState = defaultSidebarConfiguration
32814
+ RED.settings.set('editor.sidebar.state', savedState)
32815
+ }
32816
+ let targetSidebar = null
32817
+ let targetSection = null
32762
32818
  if (savedState) {
32763
- let targetSidebar = null
32764
32819
  let sidebarState
32765
- if (savedState.secondary.includes(options.id)) {
32820
+ if (savedState.secondary[0].includes(options.id)) {
32766
32821
  options.target = 'secondary'
32767
- sidebarState = savedState.secondary
32822
+ sidebarState = savedState.secondary[0]
32768
32823
  targetSidebar = sidebars.secondary
32769
- } else if (savedState.primary.includes(options.id)) {
32824
+ targetSection = 'top'
32825
+ } else if (savedState.secondary[1].includes(options.id)) {
32826
+ options.target = 'secondary'
32827
+ sidebarState = savedState.secondary[1]
32828
+ targetSidebar = sidebars.secondary
32829
+ targetSection = 'bottom'
32830
+ } else if (savedState.primary[0].includes(options.id)) {
32831
+ options.target = 'primary'
32832
+ sidebarState = savedState.primary[0]
32833
+ targetSidebar = sidebars.primary
32834
+ targetSection = 'top'
32835
+ } else if (savedState.primary[1].includes(options.id)) {
32770
32836
  options.target = 'primary'
32771
- sidebarState = savedState.primary
32837
+ sidebarState = savedState.primary[1]
32772
32838
  targetSidebar = sidebars.primary
32839
+ targetSection = 'bottom'
32773
32840
  }
32774
32841
  if (targetSidebar) {
32775
32842
  // This tab was found in the saved sidebar state. Now find the target position for the tab button
@@ -32778,10 +32845,13 @@ RED.sidebar = (function() {
32778
32845
  }
32779
32846
 
32780
32847
 
32781
- const targetSidebar = options.target === 'secondary' ? sidebars.secondary : sidebars.primary;
32848
+ targetSidebar = targetSidebar || (options.target === 'secondary' ? sidebars.secondary : sidebars.primary);
32849
+ targetSection = targetSection || 'top'
32850
+ options.targetSection = targetSection;
32851
+
32782
32852
  delete options.closeable;
32783
32853
 
32784
- options.wrapper = $('<div>',{style:"height:100%"}).appendTo(targetSidebar.content)
32854
+ options.wrapper = $('<div>',{style:"height:100%"}).appendTo(targetSidebar.sections[targetSection].content)
32785
32855
  options.wrapper.append(options.content);
32786
32856
  options.wrapper.hide();
32787
32857
 
@@ -32790,7 +32860,7 @@ RED.sidebar = (function() {
32790
32860
  }
32791
32861
 
32792
32862
  if (options.toolbar) {
32793
- targetSidebar.footer.append(options.toolbar);
32863
+ targetSidebar.sections[targetSection].footer.append(options.toolbar);
32794
32864
  $(options.toolbar).hide();
32795
32865
  }
32796
32866
  var id = options.id;
@@ -32810,12 +32880,12 @@ RED.sidebar = (function() {
32810
32880
  knownTabs[options.id] = options;
32811
32881
  options.tabButton = $('<button></button>')
32812
32882
  // Insert the tab button at the correct index
32813
- if (targetTabButtonIndex === -1 || targetTabButtonIndex >= targetSidebar.tabBar.children().length) {
32883
+ if (targetTabButtonIndex === -1) {
32814
32884
  // Append to end
32815
- options.tabButton = $('<button></button>').appendTo(targetSidebar.tabBar);
32885
+ targetSidebar.tabBars[targetSection].addButton(options.tabButton)
32816
32886
  } else {
32817
32887
  // Insert before the item at targetTabButtonIndex
32818
- options.tabButton = $('<button></button>').insertBefore(targetSidebar.tabBar.children().eq(targetTabButtonIndex));
32888
+ targetSidebar.tabBars[targetSection].addButton(options.tabButton, targetTabButtonIndex)
32819
32889
  }
32820
32890
  options.tabButton.attr('data-tab-id', options.id)
32821
32891
 
@@ -32831,15 +32901,22 @@ RED.sidebar = (function() {
32831
32901
  return
32832
32902
  }
32833
32903
  const targetSidebar = options.target === 'secondary' ? sidebars.secondary : sidebars.primary;
32834
- if (targetSidebar.activeTab === options.id && RED.menu.isSelected(targetSidebar.menuToggle)) {
32904
+ //
32905
+ if (targetSidebar.tabBars[options.targetSection].active === options.id && RED.menu.isSelected(targetSidebar.menuToggle)) {
32906
+ // if (!targetSidebar.sections[options.targetSection].hidden) {
32907
+ // targetSidebar.hideSection(options.targetSection)
32908
+ // } else {
32909
+ // targetSidebar.showSection(options.targetSection)
32910
+ // }
32835
32911
  RED.menu.setSelected(targetSidebar.menuToggle, false);
32836
32912
  } else {
32837
32913
  RED.sidebar.show(options.id)
32838
32914
  }
32839
32915
  })
32840
- if (targetSidebar.content.children().length === 1) {
32916
+ if (targetSidebar.sections[targetSection].content.children().length === 1) {
32841
32917
  RED.sidebar.show(options.id)
32842
32918
  }
32919
+ targetSidebar.resizeSidebarTabBar()
32843
32920
  }
32844
32921
 
32845
32922
  function removeTab(id) {
@@ -32862,47 +32939,148 @@ RED.sidebar = (function() {
32862
32939
  }
32863
32940
  }
32864
32941
 
32865
- function moveTab(id, srcSidebar, targetSidebar) {
32942
+ function moveTab(id, srcSidebar, srcPosition, targetSidebar, targetPosition) {
32866
32943
  const options = knownTabs[id];
32867
32944
  options.target = targetSidebar.id;
32868
- $(options.wrapper).appendTo(targetSidebar.content);
32945
+ options.targetSection = targetPosition;
32946
+
32947
+ $(options.wrapper).appendTo(targetSidebar.sections[targetPosition].content);
32869
32948
  if (options.toolbar) {
32870
- targetSidebar.footer.append(options.toolbar);
32949
+ targetSidebar.sections[targetPosition].footer.append(options.toolbar);
32871
32950
  }
32872
32951
  // Reset the tooltip so its left/right direction is recalculated
32873
32952
  options.tabButtonTooltip.delete()
32874
32953
  options.tabButtonTooltip = RED.popover.tooltip(options.tabButton, options.name, options.action);
32875
32954
 
32876
- if (targetSidebar.content.children().length === 1) {
32955
+ if (targetSidebar.sections[targetPosition].content.children().length === 1) {
32877
32956
  RED.sidebar.show(options.id)
32878
32957
  }
32879
- if (srcSidebar.content.children().length === 0) {
32880
- RED.menu.setSelected(srcSidebar.menuToggle, false);
32958
+ if (srcSidebar.sections[srcPosition].content.children().length === 0 && srcPosition === 'bottom') {
32959
+ srcSidebar.hideSection(srcPosition)
32960
+ } else if (targetSidebar.sections[targetPosition].hidden) {
32961
+ targetSidebar.showSection(targetPosition)
32881
32962
  }
32882
32963
  }
32883
32964
 
32884
32965
  let draggingTabButton = false
32966
+
32885
32967
  function setupSidebarTabs(sidebar) {
32886
32968
  const tabBar = $('<div class="red-ui-sidebar-tab-bar"></div>').addClass('red-ui-sidebar-' + sidebar.direction);
32887
- tabBar.attr('id', sidebar.container.attr('id') + '-tab-bar')
32888
- tabBar.data('sidebar', sidebar.id)
32889
32969
  if (sidebar.direction === 'right') {
32890
32970
  tabBar.insertAfter(sidebar.container);
32891
32971
  } else if (sidebar.direction === 'left') {
32892
32972
  tabBar.insertBefore(sidebar.container);
32893
32973
  }
32894
- tabBar.sortable({
32974
+
32975
+ // TODO: make this an API object, not just a jQuery object
32976
+ sidebar.tabBars = {
32977
+ top: setupTabSection(sidebar, tabBar, 'top'),
32978
+ bottom: setupTabSection(sidebar, tabBar, 'bottom')
32979
+ }
32980
+ sidebar.tabBar = sidebar.tabBars.top.container;
32981
+ sidebar.resizeSidebarTabBar = function () {
32982
+ sidebar.tabBars.top.resizeSidebarTabBar();
32983
+ sidebar.tabBars.bottom.resizeSidebarTabBar();
32984
+ }
32985
+ sidebar.hideSection = function (position) {
32986
+ sidebar.sections[position].container.hide()
32987
+ sidebar.sections[position].hidden = true
32988
+
32989
+ const otherPosition = position === 'top' ? 'bottom' : 'top'
32990
+ sidebar.sections[otherPosition].container.css('flex-grow', '1')
32991
+
32992
+ sidebar.tabBars[position].clearSelected()
32993
+ // sidebar.tabBars.top.container.css('flex-grow', '1')
32994
+ // sidebar.tabBars[position].container.css('flex-grow', '0')
32995
+ // sidebar.tabBars[position].container.css('height', '60px')
32996
+
32997
+ sidebar.resizeSidebar()
32998
+ }
32999
+ sidebar.showSection = function (position) {
33000
+ sidebar.sections[position].container.show()
33001
+ sidebar.sections[position].hidden = false
33002
+ const otherPosition = position === 'top' ? 'bottom' : 'top'
33003
+ sidebar.sections[otherPosition].container.css('flex-grow', '0')
33004
+ sidebar.sections[otherPosition].container.css('height', '70%')
33005
+ // sidebar.tabBars.top.container.css('flex-grow', '')
33006
+ // sidebar.tabBars[position].container.css('flex-grow', '')
33007
+ // sidebar.tabBars[position].container.css('height', '')
33008
+ // sidebar.tabBars[position].active
33009
+ sidebar.tabBars[position].container.find('button[data-tab-id="'+sidebar.tabBars[position].active+'"]').addClass('selected')
33010
+
33011
+ sidebar.resizeSidebar()
33012
+ }
33013
+ }
33014
+
33015
+ function setupTabSection(sidebar, tabBar, position) {
33016
+ const tabBarButtonsContainer = $('<div class="red-ui-sidebar-tab-bar-buttons"></div>').appendTo(tabBar);
33017
+ const tabOverflowButton = $('<button class="red-ui-sidebar-tab-bar-overflow-button"><i class="fa fa-ellipsis-h"></i></button>').appendTo(tabBarButtonsContainer);
33018
+ tabOverflowButton.hide()
33019
+ tabOverflowButton.on('click', function(evt) {
33020
+ try {
33021
+ const menuOptions = []
33022
+ tabBarButtonsContainer.find('button:not(.red-ui-sidebar-tab-bar-overflow-button)').each(function () {
33023
+ if ($(this).is(':visible')) {
33024
+ return
33025
+ }
33026
+ const tabId = $(this).attr('data-tab-id')
33027
+ const tabOptions = knownTabs[tabId]
33028
+ menuOptions.push({
33029
+ label: tabOptions.name,
33030
+ onselect: function() {
33031
+ RED.sidebar.show(tabId)
33032
+ }
33033
+ })
33034
+ })
33035
+ if (menuOptions.length === 0) {
33036
+ return
33037
+ }
33038
+ const menu = RED.menu.init({ options: menuOptions });
33039
+ menu.attr("id",sidebar.container.attr('id')+"-menu");
33040
+ menu.css({
33041
+ position: "absolute"
33042
+ })
33043
+ menu.appendTo("body");
33044
+ var elementPos = tabOverflowButton.offset();
33045
+ menu.css({
33046
+ top: (elementPos.top+tabOverflowButton.height()- menu.height() - 10)+"px",
33047
+ left: sidebar.direction === 'left' ? ((elementPos.left + tabOverflowButton.width() + 3)+"px") : ((elementPos.left - menu.width() - 3)+"px")
33048
+ })
33049
+ $(".red-ui-menu.red-ui-menu-dropdown").hide();
33050
+ setTimeout(() => {
33051
+ $(document).on("click.red-ui-sidebar-tabmenu", function(evt) {
33052
+ $(document).off("click.red-ui-sidebar-tabmenu");
33053
+ menu.remove();
33054
+ });
33055
+ }, 0)
33056
+ menu.show();
33057
+ } catch (err) {
33058
+ console.log(err)
33059
+ }
33060
+ })
33061
+ tabBarButtonsContainer.data('sidebar', sidebar.id)
33062
+ tabBarButtonsContainer.data('sidebar-position', position)
33063
+ tabBarButtonsContainer.sortable({
32895
33064
  distance: 10,
32896
33065
  cancel: false,
33066
+ items: "button:not(.red-ui-sidebar-tab-bar-overflow-button)",
32897
33067
  placeholder: "red-ui-sidebar-tab-bar-button-placeholder",
32898
- connectWith: ".red-ui-sidebar-tab-bar",
33068
+ connectWith: ".red-ui-sidebar-tab-bar-buttons",
32899
33069
  start: function(event, ui) {
32900
- // Remove the tooltip so it doesn't display unexpectedly whilst dragging
32901
33070
  const tabId = ui.item.attr('data-tab-id');
33071
+ const tabCount = tabBarButtonsContainer.children('button:not(.red-ui-sidebar-tab-bar-overflow-button):not(.red-ui-sidebar-tab-bar-button-placeholder)').length
33072
+ if (position === 'top' && tabCount === 1) {
33073
+ // Call in a timeout to allow the stortable start event to complete
33074
+ // processing - otherwise errors are thrown
33075
+ setTimeout(function () {
33076
+ tabBarButtonsContainer.sortable('cancel');
33077
+ }, 0);
33078
+ }
32902
33079
  const options = knownTabs[tabId];
32903
33080
  options.tabButtonTooltip.delete()
32904
33081
  draggingTabButton = true
32905
33082
  tabBar.css('z-index','inherit')
33083
+ $(".red-ui-sidebar-tab-bar").addClass("red-ui-sidebar-dragging-tab");
32906
33084
  },
32907
33085
  stop: function(event, ui) {
32908
33086
  // Restore the tooltip
@@ -32913,33 +33091,89 @@ RED.sidebar = (function() {
32913
33091
  // Save the sidebar state
32914
33092
  exportSidebarState()
32915
33093
  tabBar.css('z-index','')
33094
+ $(".red-ui-sidebar-tab-bar").removeClass("red-ui-sidebar-dragging-tab");
32916
33095
  },
32917
33096
  receive: function(event, ui) {
32918
33097
  // Tab has been moved from one sidebar to another
32919
33098
  const src = sidebars[ui.sender.data('sidebar')]
32920
33099
  const dest = sidebars[$(this).data('sidebar')]
33100
+ const srcPosition = ui.sender.data('sidebar-position')
33101
+ const destPosition = $(this).data('sidebar-position')
32921
33102
  const tabId = ui.item.attr('data-tab-id');
32922
- moveTab(tabId, src, dest)
33103
+ moveTab(tabId, src, srcPosition, dest, destPosition);
32923
33104
  if (ui.item.hasClass('selected')) {
32924
- const firstTab = src.tabBar.find('button').first().attr('data-tab-id');
33105
+ const firstTab = src.tabBars[srcPosition].container.find('button').first().attr('data-tab-id');
32925
33106
  if (firstTab) {
32926
33107
  RED.sidebar.show(firstTab);
32927
33108
  }
32928
33109
  }
33110
+ src.resizeSidebarTabBar();
33111
+ dest.resizeSidebarTabBar();
33112
+
32929
33113
  RED.sidebar.show(tabId)
32930
33114
  }
32931
33115
  })
32932
- // $(window).on("resize", function () {
32933
- // const lastChild = tabBar.children().last();
32934
- // if (lastChild.length > 0) {
32935
- // const tabBarHeight = tabBar.height();
32936
- // const lastChildBottom = lastChild.position().top + lastChild.outerHeight();
32937
- // if (lastChildBottom > tabBarHeight) {
32938
- // console.log('overflow')
32939
- // }
32940
- // }
32941
- // })
32942
- return tabBar
33116
+
33117
+ let hasHidden = false
33118
+ const resizeSidebarTabBar = function () {
33119
+ let tabBarButtonsBottom = tabBarButtonsContainer.position().top + tabBarButtonsContainer.outerHeight();
33120
+ const buttonHeight = tabOverflowButton.outerHeight()
33121
+ // Find the last visible button
33122
+ let bottomButton = tabBarButtonsContainer.children(":visible").last()
33123
+ if (bottomButton.length === 0) {
33124
+ // Nothing visible - bail out
33125
+ return
33126
+ }
33127
+ if (tabBarButtonsBottom < bottomButton.position().top + buttonHeight) {
33128
+ tabOverflowButton.show()
33129
+ let tabOverflowButtonBottom = tabOverflowButton.position().top + buttonHeight * 1.5;
33130
+ while (tabBarButtonsBottom < tabOverflowButtonBottom) {
33131
+ const lastVisible = tabBarButtonsContainer.children(':not(".red-ui-sidebar-tab-bar-overflow-button"):visible').last()
33132
+ if (lastVisible.length === 0) {
33133
+ // Nothing left to hide
33134
+ break
33135
+ }
33136
+ lastVisible.hide()
33137
+ tabOverflowButtonBottom = tabOverflowButton.position().top + buttonHeight * 1.5;
33138
+ }
33139
+ } else {
33140
+ const hiddenChildren = tabBarButtonsContainer.children(':not(".red-ui-sidebar-tab-bar-overflow-button"):hidden')
33141
+ if (hiddenChildren.length > 0) {
33142
+ // We may be able to show some more buttons
33143
+ let tabOverflowButtonBottom = tabOverflowButton.position().top + buttonHeight * 2;
33144
+ let shownCount = 0
33145
+ while (tabBarButtonsBottom > tabOverflowButtonBottom + buttonHeight) {
33146
+ const firstHidden = tabBarButtonsContainer.children(':not(".red-ui-sidebar-tab-bar-overflow-button"):hidden').first()
33147
+ if (firstHidden.length === 0) {
33148
+ // Nothing left to show
33149
+ break
33150
+ }
33151
+ firstHidden.show()
33152
+ shownCount++
33153
+ tabOverflowButtonBottom = tabOverflowButton.position().top + buttonHeight * 2;
33154
+ }
33155
+ if (hiddenChildren.length - shownCount <= 0) {
33156
+ // We were able to show all of the hidden buttons
33157
+ // so hide the overflow button again
33158
+ tabOverflowButton.hide()
33159
+ }
33160
+ }
33161
+ }
33162
+ }
33163
+ return {
33164
+ container: tabBarButtonsContainer,
33165
+ addButton: function(button, position) {
33166
+ if (position === undefined || position >= tabBarButtonsContainer.children().length) {
33167
+ button.insertBefore(tabOverflowButton);
33168
+ } else {
33169
+ button.insertBefore(tabBarButtonsContainer.children().eq(position));
33170
+ }
33171
+ },
33172
+ clearSelected: function() {
33173
+ tabBarButtonsContainer.children('button').removeClass('selected')
33174
+ },
33175
+ resizeSidebarTabBar
33176
+ }
32943
33177
  }
32944
33178
  function setupSidebarSeparator(sidebar) {
32945
33179
  const separator = $('<div class="red-ui-sidebar-separator"></div>');
@@ -33031,10 +33265,17 @@ RED.sidebar = (function() {
33031
33265
  if (!state) {
33032
33266
  sidebar.container.hide()
33033
33267
  sidebar.separator.hide()
33034
- sidebar.tabBar.find('button').removeClass('selected')
33268
+ sidebar.tabBars.top.clearSelected()
33269
+ sidebar.tabBars.bottom.clearSelected()
33035
33270
  } else {
33036
33271
  sidebar.container.show()
33037
33272
  sidebar.separator.show()
33273
+ if (sidebar.tabBars.top.active) {
33274
+ sidebar.tabBars.top.container.find('button[data-tab-id="'+sidebar.tabBars.top.active+'"]').addClass('selected')
33275
+ }
33276
+ if (sidebar.tabBars.bottom.active) {
33277
+ sidebar.tabBars.bottom.container.find('button[data-tab-id="'+sidebar.tabBars.bottom.active+'"]').addClass('selected')
33278
+ }
33038
33279
  }
33039
33280
  RED.events.emit("sidebar:resize");
33040
33281
  }
@@ -33044,11 +33285,13 @@ RED.sidebar = (function() {
33044
33285
  // Show the last selected tab for each sidebar
33045
33286
  Object.keys(sidebars).forEach(function(sidebarKey) {
33046
33287
  const sidebar = sidebars[sidebarKey];
33047
- let lastTabId = lastSessionSelectedTabs[sidebarKey];
33048
- if (!lastTabId) {
33049
- lastTabId = sidebar.tabBar.children('button').first().attr('data-tab-id');
33050
- }
33051
- showSidebar(lastTabId, true)
33288
+ ['top','bottom'].forEach(function(position) {
33289
+ let lastTabId = lastSessionSelectedTabs[sidebarKey + '-' + position];
33290
+ if (!lastTabId) {
33291
+ lastTabId = sidebar.tabBars[position].container.children('button').first().attr('data-tab-id');
33292
+ }
33293
+ showSidebar(lastTabId, true)
33294
+ })
33052
33295
  })
33053
33296
  return
33054
33297
  }
@@ -33056,23 +33299,30 @@ RED.sidebar = (function() {
33056
33299
  const tabOptions = knownTabs[id];
33057
33300
  if (tabOptions) {
33058
33301
  const targetSidebar = tabOptions.target === 'secondary' ? sidebars.secondary : sidebars.primary;
33059
- targetSidebar.content.children().hide();
33060
- targetSidebar.footer.children().hide();
33302
+ const targetSection = tabOptions.targetSection || 'top'
33303
+ targetSidebar.sections[targetSection].content.children().hide();
33304
+ targetSidebar.sections[targetSection].footer.children().hide();
33061
33305
  if (tabOptions.onchange) {
33062
33306
  tabOptions.onchange.call(tabOptions);
33063
33307
  }
33064
33308
  $(tabOptions.wrapper).show();
33065
33309
  if (tabOptions.toolbar) {
33066
33310
  $(tabOptions.toolbar).show();
33311
+ targetSidebar.sections[targetSection].footer.show();
33312
+ } else {
33313
+ targetSidebar.sections[targetSection].footer.hide();
33067
33314
  }
33068
- RED.settings.setLocal("last-sidebar-tab-" + targetSidebar.id, tabOptions.id)
33069
- targetSidebar.tabBar.find('button').removeClass('selected')
33070
- targetSidebar.tabBar.find('button[data-tab-id="'+id+'"]').addClass('selected')
33071
- targetSidebar.activeTab = id
33072
-
33315
+ RED.settings.setLocal("last-sidebar-tab-" + targetSidebar.id+'-'+targetSection, tabOptions.id)
33316
+ // TODO: find which tabBar the button is in
33317
+ targetSidebar.tabBars[targetSection].clearSelected()
33318
+ targetSidebar.tabBars[targetSection].container.find('button[data-tab-id="'+id+'"]').addClass('selected')
33319
+ targetSidebar.tabBars[targetSection].active = id
33073
33320
  if (!skipShowSidebar && !RED.menu.isSelected(targetSidebar.menuToggle)) {
33074
33321
  RED.menu.setSelected(targetSidebar.menuToggle,true);
33075
33322
  }
33323
+ if (targetSidebar.sections[targetSection].hidden) {
33324
+ targetSidebar.showSection(targetSection)
33325
+ }
33076
33326
  }
33077
33327
  }
33078
33328
  }
@@ -33082,13 +33332,93 @@ RED.sidebar = (function() {
33082
33332
  }
33083
33333
 
33084
33334
  function setupSidebar(sidebar) {
33335
+ // Get the appropriate height for the sidebar - as the sidebar will be hidden at this point in time, we need to use
33336
+ // the main-container height as a decent proxy
33337
+ const sidebarHeight = $("#red-ui-main-container").height();
33085
33338
  sidebar.container.addClass("red-ui-sidebar").addClass('red-ui-sidebar-' + sidebar.direction);
33086
33339
  sidebar.container.width(sidebar.defaultWidth);
33340
+ if (sidebar.direction === 'right') {
33341
+ $('<div>',{class:"red-ui-sidebar-shade hide"}).css("z-index", 0).appendTo(sidebar.container);
33342
+ }
33343
+ sidebar.sections = {};
33344
+ sidebar.sections.top = {}
33345
+ sidebar.sections.top.container = $('<div class="red-ui-sidebar-section red-ui-sidebar-section-top"></div>').appendTo(sidebar.container);
33346
+ // sidebar.sections.top.banner = $('<div class="red-ui-sidebar-banner">Head</div>').appendTo(sidebar.sections.top.container);
33347
+ sidebar.sections.top.content = $('<div class="red-ui-sidebar-content"></div>').appendTo(sidebar.sections.top.container);
33348
+ sidebar.sections.top.footer = $('<div class="red-ui-sidebar-footer"></div>').appendTo(sidebar.sections.top.container);
33349
+ sidebar.sectionsSeparator = $('<div class="red-ui-sidebar-tab-bar-separator"><div class="red-ui-sidebar-separator-handle"></div></div>').appendTo(sidebar.container);
33350
+ sidebar.sections.bottom = {}
33351
+ sidebar.sections.bottom.container = $('<div class="red-ui-sidebar-section red-ui-sidebar-section-bottom"></div>').appendTo(sidebar.container);
33352
+ // sidebar.sections.bottom.banner = $('<div class="red-ui-sidebar-banner">Head</div>').appendTo(sidebar.sections.bottom.container);
33353
+ sidebar.sections.bottom.content = $('<div class="red-ui-sidebar-content"></div>').appendTo(sidebar.sections.bottom.container);
33354
+ sidebar.sections.bottom.footer = $('<div class="red-ui-sidebar-footer"></div>').appendTo(sidebar.sections.bottom.container);
33355
+
33356
+ let startPosition
33357
+ let startTopSectionHeight
33358
+ let startTopTabSectionHeight
33359
+ let startSidebarHeight
33360
+ let lastSeparatorPosition
33361
+ sidebar.sectionsSeparator.draggable({
33362
+ axis: "y",
33363
+ containment: sidebar.container,
33364
+ scroll: false,
33365
+ start:function(event,ui) {
33366
+ startPosition = ui.position.top
33367
+ lastSeparatorPosition = ui.position.top
33368
+ startTopSectionHeight = sidebar.sections.top.container.outerHeight()
33369
+ startTopTabSectionHeight = sidebar.tabBars.top.container.outerHeight()
33370
+ startSidebarHeight = sidebar.container.height()
33371
+ },
33372
+ drag: function(event,ui) {
33373
+ const delta = ui.position.top - startPosition
33374
+ const newTopHeight = startTopSectionHeight + delta
33375
+ const newBottomHeight = startSidebarHeight - newTopHeight
33376
+ if (newTopHeight < 100 || newBottomHeight < 100) {
33377
+ ui.position.top = lastSeparatorPosition
33378
+ return
33379
+ }
33380
+ sidebar.sections.top.container.outerHeight(startTopSectionHeight + delta)
33381
+ sidebar.tabBars.top.container.outerHeight(startTopTabSectionHeight + delta)
33382
+ ui.position.top -= delta
33383
+ lastSeparatorPosition = ui.position.top
33384
+ sidebar.resizeSidebar()
33385
+ },
33386
+ stop:function(event,ui) {
33387
+ }
33388
+ });
33389
+
33390
+ // sidebar.shade = $('<div class="red-ui-sidebar-shade hide"></div>').appendTo(sidebar.container);
33391
+
33087
33392
  sidebar.separator = setupSidebarSeparator(sidebar);
33088
- sidebar.tabBar = setupSidebarTabs(sidebar)
33089
- sidebar.content = $('<div class="red-ui-sidebar-content"></div>').appendTo(sidebar.container);
33090
- sidebar.footer = $('<div class="red-ui-sidebar-footer"></div>').appendTo(sidebar.container);
33091
- sidebar.shade = $('<div class="red-ui-sidebar-shade hide"></div>').appendTo(sidebar.container);
33393
+ setupSidebarTabs(sidebar)
33394
+ sidebar.resizeSidebar = function () {
33395
+ // Resize sidebar sections as needed
33396
+ const topSectionHeight = sidebar.sections.top.container.outerHeight()
33397
+ if (!sidebar.sections.bottom.hidden) {
33398
+ const bottomSectionHeight = sidebar.sections.bottom.container.outerHeight()
33399
+
33400
+ // Shrink the top section if the bottom section is too small
33401
+ if (bottomSectionHeight < 90 && topSectionHeight > 90) {
33402
+ sidebar.sections.top.container.outerHeight(topSectionHeight - (90 - bottomSectionHeight));
33403
+ }
33404
+ sidebar.tabBars.top.container.height(sidebar.sections.top.container.outerHeight())
33405
+ // } else {
33406
+ // sidebar.tabBars.top.container.height(sidebar.sections.top.container.outerHeight() - 60)
33407
+ }
33408
+ // Trigger a resize of the tab bars to handle overflow
33409
+ sidebar.resizeSidebarTabBar()
33410
+ RED.events.emit("sidebar:resize");
33411
+
33412
+ }
33413
+ $(window).on("resize", sidebar.resizeSidebar)
33414
+ if (sidebar.defaultTopHeight > 0) {
33415
+ if (sidebar.defaultTopHeight === 1) {
33416
+ sidebar.hideSection('bottom')
33417
+ } else {
33418
+ sidebar.sections.top.container.outerHeight(sidebarHeight * sidebar.defaultTopHeight);
33419
+ }
33420
+ }
33421
+ sidebar.resizeSidebar()
33092
33422
 
33093
33423
  }
33094
33424
  function init () {
@@ -33115,7 +33445,8 @@ RED.sidebar = (function() {
33115
33445
  // Remember the last selected tab for each sidebar before
33116
33446
  // the tabs are readded causing the state to get updated
33117
33447
  Object.keys(sidebars).forEach(function(sidebarKey) {
33118
- lastSessionSelectedTabs[sidebarKey] = RED.settings.getLocal("last-sidebar-tab-" + sidebarKey)
33448
+ lastSessionSelectedTabs[sidebarKey + '-top'] = RED.settings.getLocal("last-sidebar-tab-" + sidebarKey + '-top');
33449
+ lastSessionSelectedTabs[sidebarKey + '-bottom'] = RED.settings.getLocal("last-sidebar-tab-" + sidebarKey + '-bottom');
33119
33450
  })
33120
33451
  }
33121
33452
 
@@ -33457,6 +33788,7 @@ RED.palette = (function() {
33457
33788
  var paletteWidth;
33458
33789
  var paletteTop;
33459
33790
  var dropEnabled;
33791
+ let chartOffset;
33460
33792
  $(d).draggable({
33461
33793
  helper: 'clone',
33462
33794
  appendTo: '#red-ui-editor',
@@ -33473,6 +33805,7 @@ RED.palette = (function() {
33473
33805
  if (activeGroup) {
33474
33806
  document.getElementById("group_select_"+activeGroup.id).classList.add("red-ui-flow-group-active-hovered");
33475
33807
  }
33808
+ chartOffset = chart.offset()
33476
33809
  RED.view.focus();
33477
33810
  },
33478
33811
  stop: function() {
@@ -33490,12 +33823,13 @@ RED.palette = (function() {
33490
33823
  },
33491
33824
  drag: function(e,ui) {
33492
33825
  var paletteNode = getPaletteNode(nt);
33493
- console.log(ui.originalPosition.left, paletteNode.offset().left)
33826
+ // console.log(ui.originalPosition.left, paletteNode.offset().left)
33494
33827
  // ui.originalPosition.left = paletteNode.offset().left;
33495
33828
  // console.log(paletteNode.offset())
33496
33829
  if (dropEnabled) {
33497
- mouseX = ui.position.left - paletteWidth + (ui.helper.width()/2) + chart.scrollLeft();
33498
- mouseY = ui.position.top - paletteTop + (ui.helper.height()/2) + chart.scrollTop() + 10;
33830
+ mouseX = ui.offset.left - chartOffset.left + (ui.helper.width()/2) + chart.scrollLeft();
33831
+ mouseY = ui.offset.top - chartOffset.top + (ui.helper.height()/2) + chart.scrollTop() + 10;
33832
+ // console.log(mouseX, mouseY)
33499
33833
  if (!groupTimer) {
33500
33834
  groupTimer = setTimeout(function() {
33501
33835
  var mx = mouseX / RED.view.scale();
@@ -33752,13 +34086,12 @@ RED.palette = (function() {
33752
34086
  content,
33753
34087
  toolbar,
33754
34088
  pinned: true,
33755
- enableOnEdit: true
34089
+ enableOnEdit: false
33756
34090
  });
33757
34091
 
33758
34092
  $('<img src="red/images/spin.svg" class="red-ui-palette-spinner hide"/>').appendTo("#red-ui-palette");
33759
34093
  $('<div id="red-ui-palette-search" class="red-ui-palette-search hide"><input type="text" data-i18n="[placeholder]palette.filter"></input></div>').appendTo("#red-ui-palette");
33760
34094
  $('<div id="red-ui-palette-container" class="red-ui-palette-scroll hide"></div>').appendTo("#red-ui-palette");
33761
- // $('<div id="red-ui-palette-shade" class="hide"></div>').appendTo("#red-ui-palette");
33762
34095
 
33763
34096
  $("#red-ui-palette > .red-ui-palette-spinner").show();
33764
34097
 
@@ -33959,10 +34292,6 @@ RED.sidebar.info = (function() {
33959
34292
 
33960
34293
  var stackContainer = $("<div>",{class:"red-ui-sidebar-info-stack"}).appendTo(content);
33961
34294
 
33962
- var outlinerPanel = $("<div>").css({
33963
- "overflow": "hidden",
33964
- "height": "calc(70%)"
33965
- }).appendTo(stackContainer);
33966
34295
  var propertiesPanel = $("<div>").css({
33967
34296
  "overflow":"hidden",
33968
34297
  "height":"100%",
@@ -33978,7 +34307,7 @@ RED.sidebar.info = (function() {
33978
34307
 
33979
34308
  propertiesPanelHeaderCopyLink = $('<button type="button" class="red-ui-button red-ui-button-small"><i class="fa fa-link"></button>').css({
33980
34309
  position: 'absolute',
33981
- top: '12px',
34310
+ top: '6px',
33982
34311
  right: '32px'
33983
34312
  }).on("click", function(evt) {
33984
34313
  RED.actions.invoke('core:copy-item-url',selectedObject)
@@ -33987,7 +34316,7 @@ RED.sidebar.info = (function() {
33987
34316
 
33988
34317
  propertiesPanelHeaderHelp = $('<button type="button" class="red-ui-button red-ui-button-small"><i class="fa fa-book"></button>').css({
33989
34318
  position: 'absolute',
33990
- top: '12px',
34319
+ top: '6px',
33991
34320
  right: '56px'
33992
34321
  }).on("click", function(evt) {
33993
34322
  evt.preventDefault();
@@ -34000,7 +34329,7 @@ RED.sidebar.info = (function() {
34000
34329
 
34001
34330
  propertiesPanelHeaderReveal = $('<button type="button" class="red-ui-button red-ui-button-small"><i class="fa fa-search"></button>').css({
34002
34331
  position: 'absolute',
34003
- top: '12px',
34332
+ top: '6px',
34004
34333
  right: '8px'
34005
34334
  }).on("click", function(evt) {
34006
34335
  evt.preventDefault();
@@ -34019,17 +34348,16 @@ RED.sidebar.info = (function() {
34019
34348
  }).appendTo(propertiesPanel);
34020
34349
 
34021
34350
 
34022
- panels = RED.panels.create({container: stackContainer})
34023
- panels.ratio(0.6);
34024
- RED.sidebar.info.outliner.build().appendTo(outlinerPanel);
34025
-
34351
+ // panels = RED.panels.create({container: stackContainer})
34352
+ // panels.ratio(0.6);
34353
+ // RED.sidebar.info.outliner.build().appendTo(outlinerPanel);
34026
34354
 
34027
34355
  RED.sidebar.addTab({
34028
34356
  id: "info",
34029
34357
  // target: "secondary",
34030
34358
  label: RED._("sidebar.info.label"),
34031
34359
  name: RED._("sidebar.info.name"),
34032
- icon: "red/images/explorer.svg",
34360
+ iconClass: "fa fa-info",
34033
34361
  action:"core:show-info-tab",
34034
34362
  content: content,
34035
34363
  pinned: true,
@@ -34537,11 +34865,13 @@ RED.sidebar.info = (function() {
34537
34865
  {
34538
34866
  label: RED._("menu.label.flows"),
34539
34867
  expanded: true,
34868
+ expandOnLabel: true,
34540
34869
  children: []
34541
34870
  },
34542
34871
  {
34543
34872
  id: "__subflow__",
34544
34873
  label: RED._("menu.label.subflows"),
34874
+ expandOnLabel: true,
34545
34875
  children: [
34546
34876
  getEmptyItem("__subflow__")
34547
34877
  ]
@@ -34550,6 +34880,7 @@ RED.sidebar.info = (function() {
34550
34880
  id: "__global__",
34551
34881
  flow: "__global__",
34552
34882
  label: RED._("sidebar.info.globalConfig"),
34883
+ expandOnLabel: true,
34553
34884
  types: {},
34554
34885
  children: [
34555
34886
  getEmptyItem("__global__")
@@ -34561,7 +34892,6 @@ RED.sidebar.info = (function() {
34561
34892
  subflowList = flowData[1];
34562
34893
  globalConfigNodes = flowData[2];
34563
34894
  configNodeTypes = { __global__: globalConfigNodes};
34564
-
34565
34895
  return flowData;
34566
34896
  }
34567
34897
 
@@ -34740,8 +35070,6 @@ RED.sidebar.info = (function() {
34740
35070
  }
34741
35071
  return RED._("common.label."+(((n.type==='tab' && n.disabled) || (n.type!=='tab' && n.d))?"enable":"disable"));
34742
35072
  });
34743
- } else {
34744
- $('<div class="red-ui-info-outline-item-control-spacer">').appendTo(controls)
34745
35073
  }
34746
35074
  if (n.type === 'tab') {
34747
35075
  var lockToggleButton = $('<button type="button" class="red-ui-info-outline-item-control-lock red-ui-button red-ui-button-small"><i class="fa fa-unlock-alt"></i><i class="fa fa-lock"></i></button>').appendTo(controls).on("click",function(evt) {
@@ -34756,7 +35084,7 @@ RED.sidebar.info = (function() {
34756
35084
  RED.popover.tooltip(lockToggleButton,function() {
34757
35085
  return RED._("common.label."+(n.locked?"unlock":"lock"));
34758
35086
  });
34759
- } else {
35087
+ } else if (n.type !== 'subflow') {
34760
35088
  $('<div class="red-ui-info-outline-item-control-spacer">').appendTo(controls)
34761
35089
  }
34762
35090
  controls.find("button").on("dblclick", function(evt) {
@@ -34815,12 +35143,18 @@ RED.sidebar.info = (function() {
34815
35143
  // <div class="red-ui-info-outline-item red-ui-info-outline-item-flow" style=";"><div class="red-ui-search-result-description red-ui-info-outline-item-label">Space Monkey</div><div class="red-ui-info-outline-item-controls"><button class="red-ui-button red-ui-button-small" style="position:absolute;right:5px;"><i class="fa fa-ellipsis-h"></i></button></div></div></div>').appendTo(container)
34816
35144
 
34817
35145
  treeList = $("<div>").css({width: "100%"}).appendTo(container).treeList({
34818
- data:getFlowData()
35146
+ data:getFlowData(),
35147
+ expandOnLabel: false
34819
35148
  })
34820
35149
  treeList.on('treelistselect', function(e,item) {
34821
35150
  var node = RED.nodes.node(item.id) || RED.nodes.group(item.id) || RED.nodes.workspace(item.id) || RED.nodes.subflow(item.id);
34822
35151
  if (node) {
34823
- RED.sidebar.info.refresh(node);
35152
+ if (node.type === 'tab' || node.type === 'subflow') {
35153
+ RED.workspaces.show(node.id)
35154
+ } else {
35155
+ RED.view.reveal(node.id);
35156
+ }
35157
+ // RED.sidebar.info.refresh(node);
34824
35158
  // if (node.type === 'group' || node._def.category !== "config") {
34825
35159
  // // RED.view.select({nodes:[node]})
34826
35160
  // } else if (node._def.category === "config") {
@@ -35104,14 +35438,15 @@ RED.sidebar.info = (function() {
35104
35438
  }
35105
35439
  }
35106
35440
  function getGutter(n) {
35107
- var span = $("<span>",{class:"red-ui-info-outline-gutter red-ui-treeList-gutter-float"});
35108
- var revealButton = $('<button type="button" class="red-ui-info-outline-item-control-reveal red-ui-button red-ui-button-small"><i class="fa fa-search"></i></button>').appendTo(span).on("click",function(evt) {
35109
- evt.preventDefault();
35110
- evt.stopPropagation();
35111
- RED.view.reveal(n.id);
35112
- })
35113
- RED.popover.tooltip(revealButton,RED._("sidebar.info.find"));
35114
- return span;
35441
+ // var span = $("<span>",{class:"red-ui-info-outline-gutter red-ui-treeList-gutter-float"});
35442
+ // var revealButton = $('<button type="button" class="red-ui-info-outline-item-control-reveal red-ui-button red-ui-button-small"><i class="fa fa-search"></i></button>').appendTo(span).on("click",function(evt) {
35443
+ // evt.preventDefault();
35444
+ // evt.stopPropagation();
35445
+ // RED.view.reveal(n.id);
35446
+ // })
35447
+ // RED.popover.tooltip(revealButton,RED._("sidebar.info.find"));
35448
+ // return span;
35449
+ return null;
35115
35450
  }
35116
35451
 
35117
35452
  function createFlowConfigNode(parent,type) {
@@ -35204,9 +35539,30 @@ RED.sidebar.info = (function() {
35204
35539
  function onSelectionChanged(selection) {
35205
35540
  // treeList.treeList('clearSelection');
35206
35541
  }
35542
+ function show() {
35543
+ RED.sidebar.show("explorer");
35544
+ }
35545
+ function init() {
35546
+ const content = build()
35547
+
35548
+ RED.actions.add("core:show-explorer-tab",show);
35549
+
35550
+
35551
+ RED.sidebar.addTab({
35552
+ id: "explorer",
35553
+ // target: "secondary",
35554
+ label: 'Explorer', // RED._("sidebar.info.label"),
35555
+ name: 'Explorer', //RED._("sidebar.info.name"),
35556
+ icon: "red/images/explorer.svg",
35557
+ action:"core:show-explorer-tab",
35558
+ content: content,
35559
+ pinned: true,
35560
+ enableOnEdit: true
35561
+ });
35562
+ }
35207
35563
 
35208
35564
  return {
35209
- build: build,
35565
+ init,
35210
35566
  search: function(val) {
35211
35567
  searchInput.searchBox('value',val)
35212
35568
  },
@@ -35371,6 +35727,7 @@ RED.sidebar.help = (function() {
35371
35727
 
35372
35728
  $(window).on("resize", resizeStack);
35373
35729
  $(window).on("focus", resizeStack);
35730
+ RED.events.on("sidebar:resize", resizeStack);
35374
35731
 
35375
35732
  RED.events.on('registry:node-type-added', queueRefresh);
35376
35733
  RED.events.on('registry:node-type-removed', queueRefresh);
@@ -46846,14 +47203,14 @@ RED.eventLog = (function() {
46846
47203
  }
46847
47204
  function showTray(options) {
46848
47205
  var el = $('<div class="red-ui-tray"></div>');
46849
- // `editor-tray-header` is deprecated - use red-ui-tray-body instead
46850
- var header = $('<div class="red-ui-tray-header editor-tray-header"></div>').appendTo(el);
46851
- var bodyWrapper = $('<div class="red-ui-tray-body-wrapper"></div>').appendTo(el);
46852
- // `editor-tray-body` is deprecated - use red-ui-tray-body instead
46853
- var body = $('<div class="red-ui-tray-body editor-tray-body"></div>').appendTo(bodyWrapper);
46854
- // `editor-tray-footer` is deprecated - use red-ui-tray-footer instead
46855
- var footer = $('<div class="red-ui-tray-footer"></div>').appendTo(el);
46856
47206
  var resizer = $('<div class="red-ui-tray-resize-handle"></div>').appendTo(el);
47207
+ var wrapper = $('<div class="red-ui-tray-wrapper"></div>').appendTo(el);
47208
+
47209
+ var header = $('<div class="red-ui-tray-header"></div>').appendTo(wrapper);
47210
+ var bodyWrapper = $('<div class="red-ui-tray-body-wrapper"></div>').appendTo(wrapper);
47211
+ var body = $('<div class="red-ui-tray-body"></div>').appendTo(bodyWrapper);
47212
+ // `editor-tray-footer` is deprecated - use red-ui-tray-footer instead
47213
+ var footer = $('<div class="red-ui-tray-footer"></div>').appendTo(wrapper);
46857
47214
  // var growButton = $('<a class="red-ui-tray-resize-button" style="cursor: w-resize;"><i class="fa fa-angle-left"></i></a>').appendTo(resizer);
46858
47215
  // var shrinkButton = $('<a class="red-ui-tray-resize-button" style="cursor: e-resize;"><i style="margin-left: 1px;" class="fa fa-angle-right"></i></a>').appendTo(resizer);
46859
47216
  if (options.title) {
@@ -46942,7 +47299,6 @@ RED.eventLog = (function() {
46942
47299
  function finishBuild() {
46943
47300
  $("#red-ui-header-shade").show();
46944
47301
  $("#red-ui-editor-shade").show();
46945
- $("#red-ui-palette-shade").show();
46946
47302
  $(".red-ui-sidebar-shade").show();
46947
47303
  tray.preferredWidth = Math.max(el.width(),500);
46948
47304
  if (!options.maximized) {
@@ -47015,8 +47371,8 @@ RED.eventLog = (function() {
47015
47371
  }
47016
47372
 
47017
47373
  function handleWindowResize() {
47018
- let sidebarWidth = $("#red-ui-sidebar").is(":visible") ? $("#red-ui-sidebar").outerWidth() + $("#red-ui-sidebar-separator").outerWidth() : 0;
47019
- $("#red-ui-editor-stack").css('right', sidebarWidth + $("#red-ui-sidebar-tab-bar").outerWidth() + 1);
47374
+ let sidebarWidth = $("#red-ui-sidebar").is(":visible") ? $("#red-ui-sidebar").outerWidth() : 0;
47375
+ $("#red-ui-editor-stack").css('right', sidebarWidth + $("#red-ui-sidebar + .red-ui-sidebar-tab-bar").outerWidth() + 4);
47020
47376
  if (stack.length > 0) {
47021
47377
  var tray = stack[stack.length-1];
47022
47378
  if (tray.options.maximized || tray.width > $("#red-ui-editor-stack").position().left-8) {
@@ -47041,11 +47397,11 @@ RED.eventLog = (function() {
47041
47397
  function raiseTrayZ() {
47042
47398
  setTimeout(function(){
47043
47399
  $('#red-ui-editor-stack').css("zIndex","13");
47044
- },300);
47400
+ },100);
47045
47401
  }
47046
47402
  //lower tray z-index back to original place for correct slide animation (related to fix for editor context menu clipped by sidebar)
47047
47403
  function lowerTrayZ(){
47048
- $('#red-ui-editor-stack').css("zIndex","9");
47404
+ $('#red-ui-editor-stack').css("zIndex","11");
47049
47405
  }
47050
47406
 
47051
47407
  return {
@@ -47062,7 +47418,6 @@ RED.eventLog = (function() {
47062
47418
  tray.tray.css({right:0});
47063
47419
  $("#red-ui-header-shade").show();
47064
47420
  $("#red-ui-editor-shade").show();
47065
- $("#red-ui-palette-shade").show();
47066
47421
  $(".red-ui-sidebar-shade").show();
47067
47422
  stackHidden = false;
47068
47423
  }
@@ -47099,7 +47454,6 @@ RED.eventLog = (function() {
47099
47454
  });
47100
47455
  $("#red-ui-header-shade").hide();
47101
47456
  $("#red-ui-editor-shade").hide();
47102
- $("#red-ui-palette-shade").hide();
47103
47457
  $(".red-ui-sidebar-shade").hide();
47104
47458
  stackHidden = true;
47105
47459
  }
@@ -47143,7 +47497,6 @@ RED.eventLog = (function() {
47143
47497
  if (stack.length === 0) {
47144
47498
  $("#red-ui-header-shade").hide();
47145
47499
  $("#red-ui-editor-shade").hide();
47146
- $("#red-ui-palette-shade").hide();
47147
47500
  $(".red-ui-sidebar-shade").hide();
47148
47501
  RED.events.emit("editor:close");
47149
47502
  RED.view.focus();
@@ -48844,7 +49197,7 @@ RED.library = (function() {
48844
49197
  icon: 'fa fa-cube',
48845
49198
  label: options.type,
48846
49199
  path: "",
48847
- expanded: false,
49200
+ expanded: true,
48848
49201
  children: function(done, item) {
48849
49202
  loadLibraryFolder(lib.id, options.url, "", function(children) {
48850
49203
  item.children = children;
@@ -49452,10 +49805,10 @@ RED.notifications = (function() {
49452
49805
  });
49453
49806
  */
49454
49807
 
49455
- var persistentNotifications = {};
49808
+ const persistentNotifications = {};
49456
49809
 
49457
- var shade = (function() {
49458
- var shadeUsers = 0;
49810
+ const shade = (function() {
49811
+ let shadeUsers = 0;
49459
49812
  return {
49460
49813
  show: function() {
49461
49814
  shadeUsers++;
@@ -49733,7 +50086,8 @@ RED.notifications = (function() {
49733
50086
  showPersistent();
49734
50087
  })
49735
50088
  },
49736
- notify: notify
50089
+ notify: notify,
50090
+ shade: shade
49737
50091
  }
49738
50092
  })();
49739
50093
  ;/**
@@ -49787,9 +50141,13 @@ RED.search = (function() {
49787
50141
  function indexNode(n) {
49788
50142
  var l = RED.utils.getNodeLabel(n);
49789
50143
  if (l) {
49790
- l = (""+l).toLowerCase();
49791
- index[l] = index[l] || {};
49792
- index[l][n.id] = {node:n,label:l}
50144
+ const originalLabel = "" + l;
50145
+ const indexLabel = originalLabel.toLowerCase();
50146
+ index[indexLabel] = index[indexLabel] || {};
50147
+ index[indexLabel][n.id] = {
50148
+ node: n,
50149
+ label: originalLabel
50150
+ };
49793
50151
  }
49794
50152
  l = l||n.label||n.name||n.id||"";
49795
50153
 
@@ -50005,7 +50363,7 @@ RED.search = (function() {
50005
50363
 
50006
50364
  }
50007
50365
  function createDialog() {
50008
- dialog = $("<div>",{id:"red-ui-search",class:"red-ui-search"}).appendTo("#red-ui-main-container");
50366
+ dialog = $("<div>",{id:"red-ui-search",class:"red-ui-search"}).appendTo("#red-ui-global-dialog-container");
50009
50367
  var searchDiv = $("<div>",{class:"red-ui-search-container"}).appendTo(dialog);
50010
50368
  searchInput = $('<input type="text" data-i18n="[placeholder]menu.label.searchInput">').appendTo(searchDiv).searchBox({
50011
50369
  delay: 200,
@@ -50259,10 +50617,8 @@ RED.search = (function() {
50259
50617
  }
50260
50618
  if (!visible) {
50261
50619
  previousActiveElement = document.activeElement;
50262
- $("#red-ui-header-shade").show();
50263
- $("#red-ui-editor-shade").show();
50264
- $("#red-ui-palette-shade").show();
50265
- $(".red-ui-sidebar-shade").show();
50620
+ RED.notifications.shade.show();
50621
+ $("#red-ui-full-shade").one('mousedown.red-ui-actionList', hide)
50266
50622
 
50267
50623
  if (dialog === null) {
50268
50624
  createDialog();
@@ -50283,10 +50639,8 @@ RED.search = (function() {
50283
50639
  function hide(el, keepSearchToolbar) {
50284
50640
  if (visible) {
50285
50641
  visible = false;
50286
- $("#red-ui-header-shade").hide();
50287
- $("#red-ui-editor-shade").hide();
50288
- $("#red-ui-palette-shade").hide();
50289
- $(".red-ui-sidebar-shade").hide();
50642
+ RED.notifications.shade.hide();
50643
+ $("#red-ui-full-shade").off('mousedown.red-ui-actionList')
50290
50644
  if (dialog !== null) {
50291
50645
  dialog.slideUp(200,function() {
50292
50646
  searchInput.searchBox('value','');
@@ -50317,7 +50671,7 @@ RED.search = (function() {
50317
50671
  result: (currentIndex + 1),
50318
50672
  count: activeResults.length
50319
50673
  }
50320
- $("#red-ui-view-searchtools-counter").text(RED._('actions.search-counter', i18nSearchCounterData));
50674
+ $("#red-ui-view-searchtools-counter-label").text(RED._('actions.search-counter', i18nSearchCounterData));
50321
50675
  $("#view-search-tools > :not(:first-child)").show(); //show other tools
50322
50676
  } else {
50323
50677
  clearActiveSearch();
@@ -50383,11 +50737,6 @@ RED.search = (function() {
50383
50737
  updateSearchToolbar();
50384
50738
  });
50385
50739
 
50386
- $("#red-ui-header-shade").on('mousedown',hide);
50387
- $("#red-ui-editor-shade").on('mousedown',hide);
50388
- $("#red-ui-palette-shade").on('mousedown',hide);
50389
- $(".red-ui-sidebar-shade").on('mousedown',hide);
50390
-
50391
50740
  $("#red-ui-view-searchtools-close").on("click", function close() {
50392
50741
  clearActiveSearch();
50393
50742
  updateSearchToolbar();
@@ -50419,10 +50768,20 @@ RED.search = (function() {
50419
50768
  show: show,
50420
50769
  hide: hide,
50421
50770
  search: search,
50422
- getSearchOptions: getSearchOptions
50771
+ getSearchOptions: getSearchOptions,
50772
+ // Expose internals for testing
50773
+ _indexNode: indexNode,
50774
+ get _index() { return index; },
50775
+ set _index(val) { index = val; }
50423
50776
  };
50424
50777
 
50425
50778
  })();
50779
+
50780
+
50781
+ // Allow CommonJS import for testing
50782
+ if (typeof module !== "undefined" && module.exports) {
50783
+ module.exports = RED.search;
50784
+ }
50426
50785
  ;RED.contextMenu = (function () {
50427
50786
 
50428
50787
  let menu;
@@ -50766,7 +51125,7 @@ RED.actionList = (function() {
50766
51125
  }
50767
51126
 
50768
51127
  function createDialog() {
50769
- dialog = $("<div>",{id:"red-ui-actionList",class:"red-ui-search"}).appendTo("#red-ui-main-container");
51128
+ dialog = $("<div>",{id:"red-ui-actionList",class:"red-ui-search"}).appendTo("#red-ui-global-dialog-container");
50770
51129
  var searchDiv = $("<div>",{class:"red-ui-search-container"}).appendTo(dialog);
50771
51130
  searchInput = $('<input type="text" data-i18n="[placeholder]keyboard.filterActions">').appendTo(searchDiv).searchBox({
50772
51131
  change: function() {
@@ -50874,10 +51233,8 @@ RED.actionList = (function() {
50874
51233
  }
50875
51234
  if (!visible) {
50876
51235
  previousActiveElement = document.activeElement;
50877
- $("#red-ui-header-shade").show();
50878
- $("#red-ui-editor-shade").show();
50879
- $("#red-ui-palette-shade").show();
50880
- $(".red-ui-sidebar-shade").show();
51236
+ RED.notifications.shade.show();
51237
+ $("#red-ui-full-shade").one('mousedown.red-ui-actionList', hide)
50881
51238
  if (dialog === null) {
50882
51239
  createDialog();
50883
51240
  }
@@ -50908,10 +51265,9 @@ RED.actionList = (function() {
50908
51265
  function hide() {
50909
51266
  if (visible) {
50910
51267
  visible = false;
50911
- $("#red-ui-header-shade").hide();
50912
- $("#red-ui-editor-shade").hide();
50913
- $("#red-ui-palette-shade").hide();
50914
- $(".red-ui-sidebar-shade").hide();
51268
+ RED.notifications.shade.hide();
51269
+ $("#red-ui-full-shade").off('mousedown.red-ui-actionList')
51270
+
50915
51271
  if (dialog !== null) {
50916
51272
  dialog.slideUp(200,function() {
50917
51273
  searchInput.searchBox('value','');
@@ -50938,12 +51294,6 @@ RED.actionList = (function() {
50938
51294
  RED.events.on("type-search:close",function() { disabled = false; });
50939
51295
 
50940
51296
  RED.keyboard.add("red-ui-actionList","escape",function(){hide()});
50941
-
50942
-
50943
- $("#red-ui-header-shade").on('mousedown',hide);
50944
- $("#red-ui-editor-shade").on('mousedown',hide);
50945
- $("#red-ui-palette-shade").on('mousedown',hide);
50946
- $(".red-ui-sidebar-shade").on('mousedown',hide);
50947
51297
  }
50948
51298
 
50949
51299
  return {
@@ -54729,7 +55079,7 @@ RED.projects = (function() {
54729
55079
  var validateForm = function() {
54730
55080
  var valid = true;
54731
55081
  var flowFile = projectFlowFileInput.val();
54732
- if (flowFile === "" || !/\.json$/.test(flowFile)) {
55082
+ if (flowFile === "" || !/^[a-zA-Z0-9\-_]+\.json$/.test(flowFile)) {
54733
55083
  valid = false;
54734
55084
  if (!projectFlowFileInput.hasClass("input-error")) {
54735
55085
  projectFlowFileInput.addClass("input-error");
@@ -55151,7 +55501,7 @@ RED.projects = (function() {
55151
55501
 
55152
55502
  } else if (projectType === 'empty') {
55153
55503
  var flowFile = projectFlowFileInput.val();
55154
- if (flowFile === "" || !/\.json$/.test(flowFile)) {
55504
+ if (flowFile === "" || !/^[a-zA-Z0-9\-_]+\.json$/.test(flowFile)) {
55155
55505
  valid = false;
55156
55506
  if (!projectFlowFileInput.hasClass("input-error")) {
55157
55507
  projectFlowFileInput.addClass("input-error");