@node-red/editor-client 5.0.0-beta.3 → 5.0.0-beta.4
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/package.json +1 -1
- package/public/red/about +37 -0
- package/public/red/red.js +986 -170
- package/public/red/red.min.js +3 -3
- package/public/red/style.min.css +2 -2
- package/public/red/tours/welcome.js +4 -4
- package/public/vendor/ace/ace-bootstrap.js +14 -0
- package/public/vendor/monaco/monaco-bootstrap.js +10 -2
- package/public/vendor/vendor.js +1 -25
- package/templates/index.mst +4 -1
package/public/red/red.js
CHANGED
|
@@ -706,7 +706,7 @@ var RED = (function() {
|
|
|
706
706
|
|
|
707
707
|
loader.end();
|
|
708
708
|
|
|
709
|
-
$("
|
|
709
|
+
$("#red-ui-header-toolbar").removeClass('hide');
|
|
710
710
|
RED.sidebar.show(":first", true);
|
|
711
711
|
|
|
712
712
|
setTimeout(function() {
|
|
@@ -941,8 +941,7 @@ var RED = (function() {
|
|
|
941
941
|
const logoContainer = $('<div id="red-ui-header-logo"></div>').appendTo(header);
|
|
942
942
|
let logo = $('<span class="red-ui-header-logo"></span>').appendTo(logoContainer);
|
|
943
943
|
$('<div id="red-ui-header-tabs" class="hide"></div>').appendTo(header);
|
|
944
|
-
$('<
|
|
945
|
-
$('<div id="red-ui-header-shade" class="hide"></div>').appendTo(header);
|
|
944
|
+
$('<div id="red-ui-header-toolbar" class="hide"><div id="red-ui-header-shade" class="hide"></div><ul class="red-ui-header-toolbar"></ul></div>').appendTo(header);
|
|
946
945
|
$('<div id="red-ui-main-container">'+
|
|
947
946
|
'<div id="red-ui-sidebar-left"></div>'+
|
|
948
947
|
'<div id="red-ui-workspace"></div>'+
|
|
@@ -1384,6 +1383,7 @@ RED.i18n = (function() {
|
|
|
1384
1383
|
apiRootUrl = options.apiRootUrl||"";
|
|
1385
1384
|
var preferredLanguage = localStorage.getItem("editor-language") || detectLanguage();
|
|
1386
1385
|
var opts = {
|
|
1386
|
+
showSupportNotice: false,
|
|
1387
1387
|
backend: {
|
|
1388
1388
|
loadPath: apiRootUrl+'locales/__ns__?lng=__lng__',
|
|
1389
1389
|
},
|
|
@@ -10039,9 +10039,14 @@ RED.utils = (function() {
|
|
|
10039
10039
|
window._marked.use({extensions: [descriptionList, description] } );
|
|
10040
10040
|
|
|
10041
10041
|
function renderMarkdown(txt) {
|
|
10042
|
-
|
|
10043
|
-
|
|
10044
|
-
|
|
10042
|
+
try {
|
|
10043
|
+
var rendered = _marked.parse(txt);
|
|
10044
|
+
const cleaned = DOMPurify.sanitize(rendered);
|
|
10045
|
+
return cleaned;
|
|
10046
|
+
} catch (err) {
|
|
10047
|
+
console.warn(err);
|
|
10048
|
+
return txt
|
|
10049
|
+
}
|
|
10045
10050
|
}
|
|
10046
10051
|
|
|
10047
10052
|
function formatString(str) {
|
|
@@ -11227,6 +11232,9 @@ RED.utils = (function() {
|
|
|
11227
11232
|
|
|
11228
11233
|
function getNodeColor(type, def) {
|
|
11229
11234
|
def = def || {};
|
|
11235
|
+
if (type === 'subflow') {
|
|
11236
|
+
return def.color
|
|
11237
|
+
}
|
|
11230
11238
|
if (!nodeColorCache.hasOwnProperty(type)) {
|
|
11231
11239
|
const paletteTheme = RED.settings.theme('palette.theme') || [];
|
|
11232
11240
|
if (paletteTheme.length > 0) {
|
|
@@ -12593,12 +12601,12 @@ RED.utils = (function() {
|
|
|
12593
12601
|
});
|
|
12594
12602
|
// $('<span class="red-ui-treeList-icon"><i class="fa fa-folder-o" /></span>').appendTo(label);
|
|
12595
12603
|
label.on("click.red-ui-treeList-expand", function(e) {
|
|
12596
|
-
if (
|
|
12597
|
-
if (
|
|
12598
|
-
|
|
12599
|
-
|
|
12600
|
-
|
|
12601
|
-
|
|
12604
|
+
if (container.hasClass("expanded")) {
|
|
12605
|
+
if (item.expandOnLabel === true || label.hasClass("selected")) {
|
|
12606
|
+
item.treeList.collapse();
|
|
12607
|
+
}
|
|
12608
|
+
} else {
|
|
12609
|
+
if (item.expandOnLabel === true || label.hasClass("selected")) {
|
|
12602
12610
|
item.treeList.expand();
|
|
12603
12611
|
}
|
|
12604
12612
|
}
|
|
@@ -13078,9 +13086,75 @@ RED.utils = (function() {
|
|
|
13078
13086
|
**/
|
|
13079
13087
|
RED.menu = (function() {
|
|
13080
13088
|
|
|
13089
|
+
var currentPortaledSubmenu = null;
|
|
13081
13090
|
var menuItems = {};
|
|
13082
13091
|
let menuItemCount = 0
|
|
13083
13092
|
|
|
13093
|
+
/**
|
|
13094
|
+
* Position a submenu relative to its parent item, handling viewport collisions.
|
|
13095
|
+
* @param {HTMLElement} parentMenuEl - The parent menu item
|
|
13096
|
+
* @param {HTMLElement} submenuEl - The submenu to position
|
|
13097
|
+
* @param {string} preferredSide - 'left' or 'right'
|
|
13098
|
+
* @returns {{x: number, y: number, placement: string}}
|
|
13099
|
+
*/
|
|
13100
|
+
function getSubmenuPosition(parentMenuEl, submenuEl, preferredSide) {
|
|
13101
|
+
var parentMenuRect = parentMenuEl.getBoundingClientRect();
|
|
13102
|
+
var submenuWidth = submenuEl.offsetWidth || 230;
|
|
13103
|
+
var submenuHeight = submenuEl.offsetHeight || 200;
|
|
13104
|
+
var viewportWidth = window.innerWidth;
|
|
13105
|
+
var viewportHeight = window.innerHeight;
|
|
13106
|
+
var padding = 10;
|
|
13107
|
+
|
|
13108
|
+
// Initial position variables
|
|
13109
|
+
var x;
|
|
13110
|
+
var y = parentMenuRect.top;
|
|
13111
|
+
|
|
13112
|
+
// Shift y if it would overflow bottom of viewport
|
|
13113
|
+
if (y + submenuHeight > viewportHeight - padding) {
|
|
13114
|
+
y = viewportHeight - submenuHeight - padding;
|
|
13115
|
+
}
|
|
13116
|
+
|
|
13117
|
+
// Shift y if it would overflow top of viewport
|
|
13118
|
+
if (y < padding) {
|
|
13119
|
+
y = padding;
|
|
13120
|
+
}
|
|
13121
|
+
|
|
13122
|
+
// Calculate x position based on preferred side
|
|
13123
|
+
if (preferredSide === 'left') {
|
|
13124
|
+
x = parentMenuRect.left - submenuWidth;
|
|
13125
|
+
// Flip to right if not enough space on left
|
|
13126
|
+
if (x < padding) {
|
|
13127
|
+
x = parentMenuRect.right;
|
|
13128
|
+
// If still not enough space, shift to fit
|
|
13129
|
+
if (x + submenuWidth > viewportWidth - padding) {
|
|
13130
|
+
x = viewportWidth - submenuWidth - padding;
|
|
13131
|
+
}
|
|
13132
|
+
}
|
|
13133
|
+
} else {
|
|
13134
|
+
x = parentMenuRect.right;
|
|
13135
|
+
// Flip to left if not enough space on right
|
|
13136
|
+
if (x + submenuWidth > viewportWidth - padding) {
|
|
13137
|
+
x = parentMenuRect.left - submenuWidth;
|
|
13138
|
+
// If still not enough space, shift to fit
|
|
13139
|
+
if (x < padding) {
|
|
13140
|
+
x = padding;
|
|
13141
|
+
}
|
|
13142
|
+
}
|
|
13143
|
+
}
|
|
13144
|
+
|
|
13145
|
+
return { x: x, y: y };
|
|
13146
|
+
}
|
|
13147
|
+
|
|
13148
|
+
/**
|
|
13149
|
+
* Clean up the currently portaled submenu (return it to original position)
|
|
13150
|
+
*/
|
|
13151
|
+
function cleanupPortaledSubmenus() {
|
|
13152
|
+
if (currentPortaledSubmenu && currentPortaledSubmenu.isPortaled) {
|
|
13153
|
+
currentPortaledSubmenu.cleanUpSubmenu();
|
|
13154
|
+
}
|
|
13155
|
+
currentPortaledSubmenu = null;
|
|
13156
|
+
}
|
|
13157
|
+
|
|
13084
13158
|
function createMenuItem(opt) {
|
|
13085
13159
|
var item;
|
|
13086
13160
|
|
|
@@ -13092,7 +13166,10 @@ RED.menu = (function() {
|
|
|
13092
13166
|
}
|
|
13093
13167
|
|
|
13094
13168
|
function setInitialState() {
|
|
13095
|
-
|
|
13169
|
+
let savedStateActive;
|
|
13170
|
+
if (!opt.doNotPersist) {
|
|
13171
|
+
savedStateActive = RED.settings.get("menu-" + opt.id);
|
|
13172
|
+
}
|
|
13096
13173
|
if (opt.setting) {
|
|
13097
13174
|
// May need to migrate pre-0.17 setting
|
|
13098
13175
|
|
|
@@ -13125,6 +13202,7 @@ RED.menu = (function() {
|
|
|
13125
13202
|
item = $('<li></li>');
|
|
13126
13203
|
if (!opt.id) {
|
|
13127
13204
|
opt.id = 'red-ui-menu-item-'+(menuItemCount++)
|
|
13205
|
+
opt.doNotPersist = true;
|
|
13128
13206
|
}
|
|
13129
13207
|
if (opt.group) {
|
|
13130
13208
|
item.addClass("red-ui-menu-group-"+opt.group);
|
|
@@ -13192,6 +13270,14 @@ RED.menu = (function() {
|
|
|
13192
13270
|
link.on("click", function(event) {
|
|
13193
13271
|
event.preventDefault();
|
|
13194
13272
|
});
|
|
13273
|
+
} else {
|
|
13274
|
+
// This is an item with a submenu. Clicking on it should not trigger the
|
|
13275
|
+
// document level click handler that closes the submenu.
|
|
13276
|
+
// This allows touch screen users to reliably open the submenu
|
|
13277
|
+
link.on("click", function (event) {
|
|
13278
|
+
event.preventDefault();
|
|
13279
|
+
event.stopPropagation();
|
|
13280
|
+
})
|
|
13195
13281
|
}
|
|
13196
13282
|
if (opt.options) {
|
|
13197
13283
|
item.addClass("red-ui-menu-dropdown-submenu"+(opt.direction!=='right'?" pull-left":""));
|
|
@@ -13209,7 +13295,7 @@ RED.menu = (function() {
|
|
|
13209
13295
|
opt.options[i].onpostselect = opt.onpostselect
|
|
13210
13296
|
}
|
|
13211
13297
|
opt.options[i].direction = opt.direction
|
|
13212
|
-
hasIcons = hasIcons ||
|
|
13298
|
+
hasIcons = hasIcons || opt.options[i].icon || opt.options[i].toggle;
|
|
13213
13299
|
hasSubmenus = hasSubmenus || (opt.options[i].options);
|
|
13214
13300
|
}
|
|
13215
13301
|
|
|
@@ -13225,6 +13311,138 @@ RED.menu = (function() {
|
|
|
13225
13311
|
submenu.addClass("red-ui-menu-dropdown-submenus")
|
|
13226
13312
|
}
|
|
13227
13313
|
|
|
13314
|
+
// Setup submenu portaling for scrollable parent menus
|
|
13315
|
+
(function(item, submenu, direction) {
|
|
13316
|
+
var isPortaled = false;
|
|
13317
|
+
var originalParentItem = item;
|
|
13318
|
+
|
|
13319
|
+
function doesSubmenuNeedPortaling() {
|
|
13320
|
+
var parentMenu = item.closest(".red-ui-menu-dropdown");
|
|
13321
|
+
var overflowY = parentMenu.css("overflow-y");
|
|
13322
|
+
// If scroll, portal it
|
|
13323
|
+
if (overflowY === "auto" || overflowY === "scroll") {
|
|
13324
|
+
return true;
|
|
13325
|
+
}
|
|
13326
|
+
|
|
13327
|
+
var itemRect = item[0].getBoundingClientRect();
|
|
13328
|
+
var submenuWidth = submenu.outerWidth() || 230;
|
|
13329
|
+
var viewportWidth = window.innerWidth;
|
|
13330
|
+
var padding = 10;
|
|
13331
|
+
|
|
13332
|
+
// If right overflow, portal it
|
|
13333
|
+
if (itemRect.right + submenuWidth > viewportWidth - padding) {
|
|
13334
|
+
return true;
|
|
13335
|
+
}
|
|
13336
|
+
return false;
|
|
13337
|
+
}
|
|
13338
|
+
|
|
13339
|
+
function portalSubmenu() {
|
|
13340
|
+
if (!doesSubmenuNeedPortaling()) {
|
|
13341
|
+
return;
|
|
13342
|
+
}
|
|
13343
|
+
if (isPortaled) {
|
|
13344
|
+
updatePositionOfSubmenu();
|
|
13345
|
+
return;
|
|
13346
|
+
}
|
|
13347
|
+
|
|
13348
|
+
isPortaled = true;
|
|
13349
|
+
submenu.appendTo('body');
|
|
13350
|
+
submenu.addClass('red-ui-menu-dropdown-portaled');
|
|
13351
|
+
updatePositionOfSubmenu();
|
|
13352
|
+
}
|
|
13353
|
+
|
|
13354
|
+
function updatePositionOfSubmenu() {
|
|
13355
|
+
if (!isPortaled) {
|
|
13356
|
+
return;
|
|
13357
|
+
}
|
|
13358
|
+
var {x, y} = getSubmenuPosition(item[0], submenu[0], direction);
|
|
13359
|
+
submenu.css({
|
|
13360
|
+
'top': y + 'px',
|
|
13361
|
+
'left': x + 'px',
|
|
13362
|
+
maxHeight: ""
|
|
13363
|
+
});
|
|
13364
|
+
const windowHeight = $(window).height();
|
|
13365
|
+
const menuHeight = submenu.outerHeight();
|
|
13366
|
+
const spaceAbove = y;
|
|
13367
|
+
const bottomOverlap = menuHeight - (windowHeight - y);
|
|
13368
|
+
if (bottomOverlap > 0) {
|
|
13369
|
+
if (spaceAbove > bottomOverlap + 5) {
|
|
13370
|
+
// There is room to move the menu up and still show it all
|
|
13371
|
+
submenu.css({
|
|
13372
|
+
top: (menuHeight - bottomOverlap - 5) + "px"
|
|
13373
|
+
})
|
|
13374
|
+
} else {
|
|
13375
|
+
// There is not room for the whole menu.
|
|
13376
|
+
// 1. move it to the top
|
|
13377
|
+
// 2. enable overflow/scrolling
|
|
13378
|
+
submenu.css({
|
|
13379
|
+
top: "5px",
|
|
13380
|
+
maxHeight: (windowHeight - 25) + "px",
|
|
13381
|
+
overflowY: "auto"
|
|
13382
|
+
});
|
|
13383
|
+
}
|
|
13384
|
+
}
|
|
13385
|
+
}
|
|
13386
|
+
|
|
13387
|
+
function cleanUpSubmenu() {
|
|
13388
|
+
if (!isPortaled) {
|
|
13389
|
+
return;
|
|
13390
|
+
}
|
|
13391
|
+
isPortaled = false;
|
|
13392
|
+
submenu.removeClass('red-ui-menu-dropdown-portaled');
|
|
13393
|
+
submenu.appendTo(originalParentItem);
|
|
13394
|
+
|
|
13395
|
+
if (currentPortaledSubmenu && currentPortaledSubmenu.submenu === submenu) {
|
|
13396
|
+
currentPortaledSubmenu = null;
|
|
13397
|
+
}
|
|
13398
|
+
}
|
|
13399
|
+
|
|
13400
|
+
var submenuInfo = {
|
|
13401
|
+
submenu,
|
|
13402
|
+
cleanUpSubmenu
|
|
13403
|
+
};
|
|
13404
|
+
|
|
13405
|
+
Object.defineProperty(submenuInfo, 'isPortaled', {
|
|
13406
|
+
get: function() { return isPortaled; }
|
|
13407
|
+
});
|
|
13408
|
+
|
|
13409
|
+
item.on("mouseenter", function() {
|
|
13410
|
+
if (currentPortaledSubmenu && currentPortaledSubmenu.isPortaled && currentPortaledSubmenu.submenu !== submenu) {
|
|
13411
|
+
currentPortaledSubmenu.cleanUpSubmenu();
|
|
13412
|
+
}
|
|
13413
|
+
|
|
13414
|
+
portalSubmenu();
|
|
13415
|
+
|
|
13416
|
+
if (isPortaled) {
|
|
13417
|
+
currentPortaledSubmenu = submenuInfo;
|
|
13418
|
+
}
|
|
13419
|
+
});
|
|
13420
|
+
|
|
13421
|
+
item.on("mouseleave", function(e) {
|
|
13422
|
+
if (!isPortaled) {
|
|
13423
|
+
return;
|
|
13424
|
+
}
|
|
13425
|
+
// Check if mouse moved to the submenu
|
|
13426
|
+
var related = e.relatedTarget;
|
|
13427
|
+
if (related && (submenu[0].contains(related) || submenu[0] === related)) {
|
|
13428
|
+
return;
|
|
13429
|
+
}
|
|
13430
|
+
cleanUpSubmenu();
|
|
13431
|
+
});
|
|
13432
|
+
|
|
13433
|
+
submenu.on("mouseleave", function(e) {
|
|
13434
|
+
if (!isPortaled) {
|
|
13435
|
+
return;
|
|
13436
|
+
}
|
|
13437
|
+
// Check if mouse moved back to parent item
|
|
13438
|
+
var related = e.relatedTarget;
|
|
13439
|
+
if (related && (item[0].contains(related) || item[0] === related)) {
|
|
13440
|
+
return;
|
|
13441
|
+
}
|
|
13442
|
+
cleanUpSubmenu();
|
|
13443
|
+
});
|
|
13444
|
+
|
|
13445
|
+
})(item, submenu, opt.direction);
|
|
13228
13446
|
|
|
13229
13447
|
}
|
|
13230
13448
|
if (opt.disabled) {
|
|
@@ -13240,10 +13458,11 @@ RED.menu = (function() {
|
|
|
13240
13458
|
|
|
13241
13459
|
}
|
|
13242
13460
|
function createMenu(options) {
|
|
13243
|
-
var topMenu = $("<ul/>",{class:"red-ui-menu red-ui-menu-dropdown pull-right"});
|
|
13461
|
+
var topMenu = $("<ul/>",{class: "red-ui-menu red-ui-menu-dropdown pull-right"});
|
|
13244
13462
|
if (options.direction) {
|
|
13245
13463
|
topMenu.addClass("red-ui-menu-dropdown-direction-"+options.direction)
|
|
13246
13464
|
}
|
|
13465
|
+
|
|
13247
13466
|
if (options.id) {
|
|
13248
13467
|
topMenu.attr({id:options.id+"-submenu"});
|
|
13249
13468
|
var menuParent = $("#"+options.id);
|
|
@@ -13254,15 +13473,31 @@ RED.menu = (function() {
|
|
|
13254
13473
|
evt.preventDefault();
|
|
13255
13474
|
if (topMenu.is(":visible")) {
|
|
13256
13475
|
$(document).off("click.red-ui-menu");
|
|
13476
|
+
cleanupPortaledSubmenus();
|
|
13257
13477
|
topMenu.hide();
|
|
13478
|
+
topMenu.css({ maxHeight: "", overflowY: "" });
|
|
13258
13479
|
} else {
|
|
13259
13480
|
$(document).on("click.red-ui-menu", function(evt) {
|
|
13260
13481
|
$(document).off("click.red-ui-menu");
|
|
13261
13482
|
activeMenu = null;
|
|
13483
|
+
cleanupPortaledSubmenus();
|
|
13262
13484
|
topMenu.hide();
|
|
13485
|
+
topMenu.css({ maxHeight: "", overflowY: "" });
|
|
13263
13486
|
});
|
|
13264
13487
|
$(".red-ui-menu.red-ui-menu-dropdown").hide();
|
|
13265
13488
|
topMenu.show();
|
|
13489
|
+
|
|
13490
|
+
// Enable scrolling if menu exceeds viewport
|
|
13491
|
+
var menuOffset = topMenu.offset();
|
|
13492
|
+
var menuHeight = topMenu.outerHeight();
|
|
13493
|
+
var windowHeight = $(window).height();
|
|
13494
|
+
var spaceBelow = windowHeight - menuOffset.top;
|
|
13495
|
+
if (menuHeight > spaceBelow - 10) {
|
|
13496
|
+
topMenu.css({
|
|
13497
|
+
maxHeight: (spaceBelow - 10) + "px",
|
|
13498
|
+
overflowY: "auto"
|
|
13499
|
+
});
|
|
13500
|
+
}
|
|
13266
13501
|
}
|
|
13267
13502
|
})
|
|
13268
13503
|
}
|
|
@@ -13283,7 +13518,7 @@ RED.menu = (function() {
|
|
|
13283
13518
|
opt.direction = options.direction || 'left'
|
|
13284
13519
|
}
|
|
13285
13520
|
if (opt !== null || !lastAddedSeparator) {
|
|
13286
|
-
hasIcons = hasIcons || (opt && opt.icon);
|
|
13521
|
+
hasIcons = hasIcons || (opt && (opt.icon || opt.toggle));
|
|
13287
13522
|
hasSubmenus = hasSubmenus || (opt && opt.options);
|
|
13288
13523
|
var li = createMenuItem(opt);
|
|
13289
13524
|
if (li) {
|
|
@@ -14670,8 +14905,9 @@ RED.tabs = (function() {
|
|
|
14670
14905
|
})
|
|
14671
14906
|
menu.appendTo("body");
|
|
14672
14907
|
var elementPos = menuButton.offset();
|
|
14908
|
+
var top = elementPos.top + menuButton.height() - 2;
|
|
14673
14909
|
menu.css({
|
|
14674
|
-
top:
|
|
14910
|
+
top: top + "px",
|
|
14675
14911
|
left: (elementPos.left - menu.width() + menuButton.width())+"px"
|
|
14676
14912
|
})
|
|
14677
14913
|
$(".red-ui-menu.red-ui-menu-dropdown").hide();
|
|
@@ -14681,6 +14917,17 @@ RED.tabs = (function() {
|
|
|
14681
14917
|
menu.remove();
|
|
14682
14918
|
});
|
|
14683
14919
|
menu.show();
|
|
14920
|
+
|
|
14921
|
+
// Enable scrolling if menu exceeds viewport
|
|
14922
|
+
var menuHeight = menu.outerHeight();
|
|
14923
|
+
var windowHeight = $(window).height();
|
|
14924
|
+
var spaceBelow = windowHeight - top;
|
|
14925
|
+
if (menuHeight > spaceBelow - 10) {
|
|
14926
|
+
menu.css({
|
|
14927
|
+
maxHeight: (spaceBelow - 10) + "px",
|
|
14928
|
+
overflowY: "auto"
|
|
14929
|
+
});
|
|
14930
|
+
}
|
|
14684
14931
|
})
|
|
14685
14932
|
}
|
|
14686
14933
|
|
|
@@ -14748,20 +14995,36 @@ RED.tabs = (function() {
|
|
|
14748
14995
|
collapsibleMenu.appendTo("body");
|
|
14749
14996
|
}
|
|
14750
14997
|
var elementPos = selectButton.offset();
|
|
14998
|
+
var top = elementPos.top + selectButton.height() - 2;
|
|
14751
14999
|
collapsibleMenu.css({
|
|
14752
|
-
top:
|
|
15000
|
+
top: top + "px",
|
|
14753
15001
|
left: (elementPos.left - collapsibleMenu.width() + selectButton.width())+"px"
|
|
14754
15002
|
})
|
|
14755
15003
|
if (collapsibleMenu.is(":visible")) {
|
|
14756
15004
|
$(document).off("click.red-ui-tabmenu");
|
|
15005
|
+
collapsibleMenu.css({ maxHeight: "", overflowY: "" });
|
|
14757
15006
|
} else {
|
|
14758
15007
|
$(".red-ui-menu.red-ui-menu-dropdown").hide();
|
|
14759
15008
|
$(document).on("click.red-ui-tabmenu", function(evt) {
|
|
14760
15009
|
$(document).off("click.red-ui-tabmenu");
|
|
14761
15010
|
collapsibleMenu.hide();
|
|
15011
|
+
collapsibleMenu.css({ maxHeight: "", overflowY: "" });
|
|
14762
15012
|
});
|
|
14763
15013
|
}
|
|
14764
15014
|
collapsibleMenu.toggle();
|
|
15015
|
+
|
|
15016
|
+
// Enable scrolling if menu exceeds viewport
|
|
15017
|
+
if (collapsibleMenu.is(":visible")) {
|
|
15018
|
+
var menuHeight = collapsibleMenu.outerHeight();
|
|
15019
|
+
var windowHeight = $(window).height();
|
|
15020
|
+
var spaceBelow = windowHeight - top;
|
|
15021
|
+
if (menuHeight > spaceBelow - 10) {
|
|
15022
|
+
collapsibleMenu.css({
|
|
15023
|
+
maxHeight: (spaceBelow - 10) + "px",
|
|
15024
|
+
overflowY: "auto"
|
|
15025
|
+
});
|
|
15026
|
+
}
|
|
15027
|
+
}
|
|
14765
15028
|
})
|
|
14766
15029
|
}
|
|
14767
15030
|
|
|
@@ -22322,6 +22585,9 @@ RED.workspaces = (function() {
|
|
|
22322
22585
|
const chartSize = [ $("#red-ui-workspace-scroll-spacer").width(), $("#red-ui-workspace-scroll-spacer").height()];
|
|
22323
22586
|
const scrollPos = [$("#red-ui-workspace-chart").scrollLeft(), $("#red-ui-workspace-chart").scrollTop()];
|
|
22324
22587
|
const scrollRatio = [scrollPos[0]/(chartSize[0] - chartWindowSize[0]), scrollPos[1]/(chartSize[1] - chartWindowSize[1]) ];
|
|
22588
|
+
const toolbar = $("#red-ui-workspace-toolbar");
|
|
22589
|
+
const toolbarOffset = toolbar.is(":visible") ? toolbar.outerHeight() : 0;
|
|
22590
|
+
scrollbars.v.bar.css({ top: toolbarOffset + 2 });
|
|
22325
22591
|
const scrollbarSize = [scrollbars.h.bar.width(), scrollbars.v.bar.height()]
|
|
22326
22592
|
// Set the height of the handles to be the same ratio of chartWindowSize to chartSize, with a minimum size to ensure they are always draggable
|
|
22327
22593
|
|
|
@@ -22416,7 +22682,7 @@ RED.workspaces = (function() {
|
|
|
22416
22682
|
$("#red-ui-workspace-scroll-h").css({ width: workspaceTargetWidth - 15 })
|
|
22417
22683
|
|
|
22418
22684
|
const paletteWidth = $("#red-ui-sidebar-left").width()
|
|
22419
|
-
$("#red-ui-header-logo").width(paletteWidth -
|
|
22685
|
+
$("#red-ui-header-logo").width(paletteWidth - 3)
|
|
22420
22686
|
|
|
22421
22687
|
// const workspacePosition = $("#red-ui-workspace").position()
|
|
22422
22688
|
// $("#red-ui-header-tabs").css({ left: workspacePosition.left, width: workspaceTargetWidth })
|
|
@@ -23853,11 +24119,20 @@ RED.view = (function() {
|
|
|
23853
24119
|
// Regular scroll - prevent default and manually handle both axes
|
|
23854
24120
|
evt.preventDefault();
|
|
23855
24121
|
evt.stopPropagation();
|
|
23856
|
-
|
|
23857
24122
|
// Apply scroll deltas directly to both axes
|
|
23858
24123
|
var deltaX = evt.originalEvent.deltaX;
|
|
23859
24124
|
var deltaY = evt.originalEvent.deltaY;
|
|
23860
24125
|
|
|
24126
|
+
if (evt.shiftKey) {
|
|
24127
|
+
// Shift key pressed - this should cause a scroll on the X-axis
|
|
24128
|
+
// But - some OS/browser combinations don't flip them, so we'll do it ourselves.
|
|
24129
|
+
if (deltaX === 0 && deltaY !== 0) {
|
|
24130
|
+
// swap the deltas
|
|
24131
|
+
deltaX = deltaY
|
|
24132
|
+
deltaY = 0
|
|
24133
|
+
}
|
|
24134
|
+
}
|
|
24135
|
+
|
|
23861
24136
|
chart.scrollLeft(chart.scrollLeft() + deltaX);
|
|
23862
24137
|
chart.scrollTop(chart.scrollTop() + deltaY);
|
|
23863
24138
|
|
|
@@ -24240,10 +24515,11 @@ RED.view = (function() {
|
|
|
24240
24515
|
show: function(n) { return !n.valid }
|
|
24241
24516
|
})
|
|
24242
24517
|
|
|
24518
|
+
setScaleFactor(1)
|
|
24243
24519
|
if (RED.settings.get("editor.view.view-store-zoom")) {
|
|
24244
24520
|
var userZoomLevel = parseFloat(RED.settings.getLocal('zoom-level'))
|
|
24245
24521
|
if (!isNaN(userZoomLevel)) {
|
|
24246
|
-
|
|
24522
|
+
setScaleFactor(userZoomLevel)
|
|
24247
24523
|
}
|
|
24248
24524
|
}
|
|
24249
24525
|
|
|
@@ -25947,8 +26223,8 @@ RED.view = (function() {
|
|
|
25947
26223
|
var boundingWidth = maxX - minX;
|
|
25948
26224
|
var boundingHeight = maxY - minY;
|
|
25949
26225
|
|
|
25950
|
-
// Get viewport dimensions
|
|
25951
|
-
var viewportWidth = chart.width();
|
|
26226
|
+
// Get viewport dimensions - accounting for the sidebar if visible
|
|
26227
|
+
var viewportWidth = chart.width() - $("#red-ui-sidebar").width();
|
|
25952
26228
|
var viewportHeight = chart.height();
|
|
25953
26229
|
|
|
25954
26230
|
// Calculate zoom level that fits bounding box in viewport
|
|
@@ -26046,7 +26322,7 @@ RED.view = (function() {
|
|
|
26046
26322
|
center = [(scrollPos[0] + screenSize[0]/2)/oldScaleFactor, (scrollPos[1] + screenSize[1]/2)/oldScaleFactor];
|
|
26047
26323
|
}
|
|
26048
26324
|
|
|
26049
|
-
|
|
26325
|
+
setScaleFactor(factor)
|
|
26050
26326
|
|
|
26051
26327
|
// Calculate new scroll position to keep the center point at the same screen position
|
|
26052
26328
|
if (focalPoint) {
|
|
@@ -26132,7 +26408,7 @@ RED.view = (function() {
|
|
|
26132
26408
|
interpolateValue: true, // Use exponential interpolation for zoom
|
|
26133
26409
|
onStep: function(values) {
|
|
26134
26410
|
var currentFactor = values.zoom;
|
|
26135
|
-
|
|
26411
|
+
setScaleFactor(currentFactor);
|
|
26136
26412
|
|
|
26137
26413
|
// Calculate new scroll position to maintain focal point
|
|
26138
26414
|
var currentScreenSize = [chart.width(), chart.height()];
|
|
@@ -26170,7 +26446,7 @@ RED.view = (function() {
|
|
|
26170
26446
|
onEnd: function() {
|
|
26171
26447
|
cancelInProgressAnimation = null;
|
|
26172
26448
|
// Ensure scaleFactor is exactly the target to prevent precision issues
|
|
26173
|
-
|
|
26449
|
+
setScaleFactor(targetFactor);
|
|
26174
26450
|
// Full redraw at the end to ensure everything is correct
|
|
26175
26451
|
_redraw();
|
|
26176
26452
|
if (RED.settings.get("editor.view.view-store-zoom")) {
|
|
@@ -26181,7 +26457,7 @@ RED.view = (function() {
|
|
|
26181
26457
|
onCancel: function() {
|
|
26182
26458
|
cancelInProgressAnimation = null;
|
|
26183
26459
|
// Ensure scaleFactor is set to current target on cancel
|
|
26184
|
-
|
|
26460
|
+
setScaleFactor(targetFactor)
|
|
26185
26461
|
_redraw();
|
|
26186
26462
|
RED.events.emit("view:navigate");
|
|
26187
26463
|
}
|
|
@@ -26383,6 +26659,9 @@ RED.view = (function() {
|
|
|
26383
26659
|
movingSet.clear();
|
|
26384
26660
|
selectedLinks.clear();
|
|
26385
26661
|
selectedGroups.clear();
|
|
26662
|
+
$(".red-ui-flow-node-highlighted").removeClass("red-ui-flow-node-highlighted");
|
|
26663
|
+
$(".red-ui-flow-group-highlighted").removeClass("red-ui-flow-group-highlighted");
|
|
26664
|
+
cancelFlash();
|
|
26386
26665
|
}
|
|
26387
26666
|
|
|
26388
26667
|
var lastSelection = null;
|
|
@@ -26981,7 +27260,8 @@ RED.view = (function() {
|
|
|
26981
27260
|
clearSuggestedFlow();
|
|
26982
27261
|
RED.contextMenu.hide();
|
|
26983
27262
|
evt = evt || d3.event;
|
|
26984
|
-
|
|
27263
|
+
|
|
27264
|
+
if (!evt.touches && evt.button !== 0) {
|
|
26985
27265
|
return;
|
|
26986
27266
|
}
|
|
26987
27267
|
if (mouse_mode === RED.state.SELECTING_NODE) {
|
|
@@ -27846,7 +28126,7 @@ RED.view = (function() {
|
|
|
27846
28126
|
d3.event.stopPropagation();
|
|
27847
28127
|
return;
|
|
27848
28128
|
}
|
|
27849
|
-
if (d3.event.button !== 0) {
|
|
28129
|
+
if (!d3.event.touches && d3.event.button !== 0) {
|
|
27850
28130
|
return
|
|
27851
28131
|
}
|
|
27852
28132
|
mousedown_link = d;
|
|
@@ -28115,17 +28395,17 @@ RED.view = (function() {
|
|
|
28115
28395
|
img.src = iconUrl;
|
|
28116
28396
|
img.onload = function() {
|
|
28117
28397
|
if (!iconUrl.match(/\.svg$/)) {
|
|
28118
|
-
|
|
28119
|
-
|
|
28398
|
+
const largestEdge = Math.max(img.width,img.height);
|
|
28399
|
+
let imgScaleFactor = 1;
|
|
28120
28400
|
if (largestEdge > 30) {
|
|
28121
|
-
|
|
28401
|
+
imgScaleFactor = 30/largestEdge;
|
|
28122
28402
|
}
|
|
28123
|
-
var width = img.width *
|
|
28403
|
+
var width = img.width * imgScaleFactor;
|
|
28124
28404
|
if (width > 20) {
|
|
28125
|
-
|
|
28405
|
+
imgScaleFactor *= 20/width;
|
|
28126
28406
|
width = 20;
|
|
28127
28407
|
}
|
|
28128
|
-
var height = img.height *
|
|
28408
|
+
var height = img.height * imgScaleFactor;
|
|
28129
28409
|
icon.attr("width",width);
|
|
28130
28410
|
icon.attr("height",height);
|
|
28131
28411
|
icon.attr("x",15-width/2);
|
|
@@ -28156,6 +28436,7 @@ RED.view = (function() {
|
|
|
28156
28436
|
// - node is disabled
|
|
28157
28437
|
if (!showStatus || !d.status || d.d === true) {
|
|
28158
28438
|
nodeEl.__statusGroup__.style.display = "none";
|
|
28439
|
+
d.statusHeight = 0;
|
|
28159
28440
|
} else {
|
|
28160
28441
|
nodeEl.__statusGroup__.style.display = "inline";
|
|
28161
28442
|
let backgroundWidth = 15
|
|
@@ -28182,6 +28463,7 @@ RED.view = (function() {
|
|
|
28182
28463
|
if (backgroundWidth > 0 && textSize.width > 0) {
|
|
28183
28464
|
backgroundWidth += 6
|
|
28184
28465
|
}
|
|
28466
|
+
d.statusHeight = nodeEl.__statusGroup__.getBBox().height
|
|
28185
28467
|
nodeEl.__statusBackground__.setAttribute('width', backgroundWidth)
|
|
28186
28468
|
}
|
|
28187
28469
|
delete d.dirtyStatus;
|
|
@@ -28226,7 +28508,7 @@ RED.view = (function() {
|
|
|
28226
28508
|
.on("touchstart",nodeTouchStart)
|
|
28227
28509
|
.on("touchend",nodeTouchEnd)
|
|
28228
28510
|
nodeContents.appendChild(mainRect);
|
|
28229
|
-
|
|
28511
|
+
|
|
28230
28512
|
const port_label_group = document.createElementNS("http://www.w3.org/2000/svg","g");
|
|
28231
28513
|
port_label_group.setAttribute("x",0);
|
|
28232
28514
|
port_label_group.setAttribute("y",0);
|
|
@@ -28640,6 +28922,15 @@ RED.view = (function() {
|
|
|
28640
28922
|
|
|
28641
28923
|
nodeContents.appendChild(statusEl);
|
|
28642
28924
|
|
|
28925
|
+
const nodeHalo = document.createElementNS("http://www.w3.org/2000/svg","rect");
|
|
28926
|
+
nodeHalo.setAttribute("class", "red-ui-flow-node-highlight");
|
|
28927
|
+
nodeHalo.setAttribute("rx", 5);
|
|
28928
|
+
nodeHalo.setAttribute("ry", 5);
|
|
28929
|
+
nodeHalo.setAttribute("x", -10)
|
|
28930
|
+
nodeHalo.setAttribute("y", -10)
|
|
28931
|
+
node[0][0].__halo__ = nodeHalo;
|
|
28932
|
+
nodeContents.appendChild(nodeHalo);
|
|
28933
|
+
|
|
28643
28934
|
node[0][0].appendChild(nodeContents);
|
|
28644
28935
|
|
|
28645
28936
|
if (!d.__ghost) {
|
|
@@ -28707,11 +28998,15 @@ RED.view = (function() {
|
|
|
28707
28998
|
// This might be the first redraw after a node has been click-dragged to start a move.
|
|
28708
28999
|
// So its selected state might have changed since the last redraw.
|
|
28709
29000
|
this.classList.toggle("red-ui-flow-node-selected", !!d.selected )
|
|
29001
|
+
this.classList.toggle("red-ui-flow-node-highlighted",!!d.highlighted );
|
|
28710
29002
|
if (mouse_mode != RED.state.MOVING_ACTIVE) {
|
|
28711
29003
|
this.classList.toggle("red-ui-flow-node-disabled", d.d === true);
|
|
28712
29004
|
this.__mainRect__.setAttribute("width", d.w)
|
|
28713
29005
|
this.__mainRect__.setAttribute("height", d.h)
|
|
28714
|
-
|
|
29006
|
+
|
|
29007
|
+
this.__halo__.setAttribute("width", d.w + 20)
|
|
29008
|
+
this.__halo__.setAttribute("height", d.h + 20 + (d.statusHeight || 0))
|
|
29009
|
+
|
|
28715
29010
|
|
|
28716
29011
|
if (labelParts) {
|
|
28717
29012
|
// The label has changed
|
|
@@ -28932,6 +29227,7 @@ RED.view = (function() {
|
|
|
28932
29227
|
});
|
|
28933
29228
|
|
|
28934
29229
|
if (d._def.button) {
|
|
29230
|
+
let buttonVisible = true
|
|
28935
29231
|
var buttonEnabled = isButtonEnabled(d);
|
|
28936
29232
|
this.__buttonGroup__.classList.toggle("red-ui-flow-node-button-disabled", !buttonEnabled);
|
|
28937
29233
|
if (RED.runtime && RED.runtime.started !== undefined) {
|
|
@@ -28952,11 +29248,18 @@ RED.view = (function() {
|
|
|
28952
29248
|
if (typeof d._def.button.visible === "function") { // is defined and a function...
|
|
28953
29249
|
if (d._def.button.visible.call(d) === false) {
|
|
28954
29250
|
this.__buttonGroup__.style.display = "none";
|
|
28955
|
-
|
|
28956
|
-
else {
|
|
29251
|
+
buttonVisible = false
|
|
29252
|
+
} else {
|
|
28957
29253
|
this.__buttonGroup__.style.display = "inherit";
|
|
28958
29254
|
}
|
|
28959
29255
|
}
|
|
29256
|
+
// Need to adjust the halo to encompass the button
|
|
29257
|
+
if (buttonVisible) {
|
|
29258
|
+
this.__halo__.setAttribute("width", d.w + 40)
|
|
29259
|
+
if (d._def.align !== 'right') {
|
|
29260
|
+
this.__halo__.setAttribute("x", -30)
|
|
29261
|
+
}
|
|
29262
|
+
}
|
|
28960
29263
|
}
|
|
28961
29264
|
// thisNode.selectAll(".node_badge_group").attr("transform",function(d){return "translate("+(d.w-40)+","+(d.h+3)+")";});
|
|
28962
29265
|
// thisNode.selectAll("text.node_badge_label").text(function(d,i) {
|
|
@@ -29507,6 +29810,11 @@ RED.view = (function() {
|
|
|
29507
29810
|
} else {
|
|
29508
29811
|
selectGroup.classList.remove("red-ui-flow-group-selected")
|
|
29509
29812
|
}
|
|
29813
|
+
if (d.highlighted) {
|
|
29814
|
+
selectGroup.classList.add("red-ui-flow-group-highlighted")
|
|
29815
|
+
} else {
|
|
29816
|
+
selectGroup.classList.remove("red-ui-flow-group-highlighted")
|
|
29817
|
+
}
|
|
29510
29818
|
var selectGroupRect = selectGroup.children[0];
|
|
29511
29819
|
// Background
|
|
29512
29820
|
selectGroupRect.setAttribute("width",d.w+6)
|
|
@@ -29515,19 +29823,12 @@ RED.view = (function() {
|
|
|
29515
29823
|
selectGroupRect = selectGroup.children[1];
|
|
29516
29824
|
selectGroupRect.setAttribute("width",d.w+6)
|
|
29517
29825
|
selectGroupRect.setAttribute("height",d.h+6)
|
|
29518
|
-
selectGroupRect.style.strokeOpacity = (d.selected || d.highlighted)?0.8:0;
|
|
29826
|
+
// selectGroupRect.style.strokeOpacity = (d.selected || d.highlighted)?0.8:0;
|
|
29519
29827
|
// Line
|
|
29520
29828
|
selectGroupRect = selectGroup.children[2];
|
|
29521
29829
|
selectGroupRect.setAttribute("width",d.w+6)
|
|
29522
29830
|
selectGroupRect.setAttribute("height",d.h+6)
|
|
29523
|
-
selectGroupRect.style.strokeOpacity = (d.selected || d.highlighted)?0.8:0;
|
|
29524
|
-
|
|
29525
|
-
if (d.highlighted) {
|
|
29526
|
-
selectGroup.classList.add("red-ui-flow-node-highlighted");
|
|
29527
|
-
} else {
|
|
29528
|
-
selectGroup.classList.remove("red-ui-flow-node-highlighted");
|
|
29529
|
-
}
|
|
29530
|
-
|
|
29831
|
+
// selectGroupRect.style.strokeOpacity = (d.selected || d.highlighted)?0.8:0;
|
|
29531
29832
|
|
|
29532
29833
|
g.selectAll(".red-ui-flow-group-body")
|
|
29533
29834
|
.attr("width",d.w)
|
|
@@ -30240,33 +30541,28 @@ RED.view = (function() {
|
|
|
30240
30541
|
return result;
|
|
30241
30542
|
}
|
|
30242
30543
|
|
|
30243
|
-
|
|
30244
|
-
|
|
30245
|
-
|
|
30246
|
-
|
|
30247
|
-
if(!node) { return; }
|
|
30248
|
-
|
|
30249
|
-
const flashingNode = flashingNodeId && RED.nodes.node(flashingNodeId);
|
|
30250
|
-
if(flashingNode) {
|
|
30251
|
-
//cancel current flashing node before flashing new node
|
|
30252
|
-
clearInterval(flashingNode.__flashTimer);
|
|
30544
|
+
function cancelFlash() {
|
|
30545
|
+
const flashingNode = flashingNodeId && (RED.nodes.node(flashingNodeId) || RED.nodes.group(flashingNodeId));
|
|
30546
|
+
if (flashingNode) {
|
|
30547
|
+
clearTimeout(flashingNode.__flashTimer);
|
|
30253
30548
|
delete flashingNode.__flashTimer;
|
|
30254
30549
|
flashingNode.dirty = true;
|
|
30255
30550
|
flashingNode.highlighted = false;
|
|
30551
|
+
_redraw()
|
|
30256
30552
|
}
|
|
30257
|
-
|
|
30553
|
+
}
|
|
30554
|
+
function flashNode(n) {
|
|
30555
|
+
let node = n;
|
|
30556
|
+
if (typeof node === "string") { node = RED.nodes.node(n); }
|
|
30557
|
+
if (!node) { return; }
|
|
30558
|
+
cancelFlash()
|
|
30559
|
+
node.__flashTimer = setTimeout(function(n) {
|
|
30258
30560
|
n.dirty = true;
|
|
30259
|
-
|
|
30260
|
-
n.highlighted = !n.highlighted;
|
|
30261
|
-
} else {
|
|
30262
|
-
clearInterval(n.__flashTimer);
|
|
30263
|
-
delete n.__flashTimer;
|
|
30264
|
-
flashingNodeId = null;
|
|
30265
|
-
n.highlighted = false;
|
|
30266
|
-
}
|
|
30561
|
+
n.highlighted = false;
|
|
30267
30562
|
RED.view.redraw();
|
|
30268
|
-
},
|
|
30563
|
+
}, 8100, node)
|
|
30269
30564
|
flashingNodeId = node.id;
|
|
30565
|
+
node.dirty = true;
|
|
30270
30566
|
node.highlighted = true;
|
|
30271
30567
|
RED.view.redraw();
|
|
30272
30568
|
}
|
|
@@ -30583,6 +30879,20 @@ RED.view = (function() {
|
|
|
30583
30879
|
}
|
|
30584
30880
|
}
|
|
30585
30881
|
|
|
30882
|
+
function setScaleFactor(sf) {
|
|
30883
|
+
scaleFactor = sf;
|
|
30884
|
+
if (sf <= 0.5) {
|
|
30885
|
+
chart.removeClass('red-ui-workspace-zoom-level-1')
|
|
30886
|
+
chart.addClass('red-ui-workspace-zoom-level-2')
|
|
30887
|
+
} else if (sf <= 0.75) {
|
|
30888
|
+
chart.addClass('red-ui-workspace-zoom-level-1')
|
|
30889
|
+
chart.removeClass('red-ui-workspace-zoom-level-2')
|
|
30890
|
+
} else {
|
|
30891
|
+
chart.removeClass('red-ui-workspace-zoom-level-1')
|
|
30892
|
+
chart.removeClass('red-ui-workspace-zoom-level-2')
|
|
30893
|
+
}
|
|
30894
|
+
}
|
|
30895
|
+
|
|
30586
30896
|
return {
|
|
30587
30897
|
init: init,
|
|
30588
30898
|
state:function(state) {
|
|
@@ -30706,7 +31016,7 @@ RED.view = (function() {
|
|
|
30706
31016
|
if (node.type === "group" && !node.w && !node.h) {
|
|
30707
31017
|
_redraw();
|
|
30708
31018
|
}
|
|
30709
|
-
var screenSize = [chart[0].clientWidth/scaleFactor,chart[0].clientHeight/scaleFactor];
|
|
31019
|
+
var screenSize = [(chart[0].clientWidth - $("#red-ui-sidebar").width())/scaleFactor,chart[0].clientHeight/scaleFactor];
|
|
30710
31020
|
var scrollPos = [chart.scrollLeft()/scaleFactor,chart.scrollTop()/scaleFactor];
|
|
30711
31021
|
var cx = node.x;
|
|
30712
31022
|
var cy = node.y;
|
|
@@ -33148,6 +33458,9 @@ RED.sidebar = (function() {
|
|
|
33148
33458
|
|
|
33149
33459
|
if (options.toolbar) {
|
|
33150
33460
|
targetSidebar.sections[targetSection].footer.append(options.toolbar);
|
|
33461
|
+
if (!options.enableOnEdit) {
|
|
33462
|
+
$('<div>',{class:"red-ui-sidebar-shade hide"}).appendTo(options.toolbar);
|
|
33463
|
+
}
|
|
33151
33464
|
$(options.toolbar).hide();
|
|
33152
33465
|
}
|
|
33153
33466
|
var id = options.id;
|
|
@@ -33263,6 +33576,54 @@ RED.sidebar = (function() {
|
|
|
33263
33576
|
|
|
33264
33577
|
let draggingTabButton = false
|
|
33265
33578
|
|
|
33579
|
+
|
|
33580
|
+
function getSidebarOptions(sidebar, targetSection) {
|
|
33581
|
+
const menuOptions = []
|
|
33582
|
+
const active = sidebar.tabBars[targetSection].active
|
|
33583
|
+
sidebar.tabBars[targetSection].container.find('button:not(.red-ui-sidebar-tab-bar-overflow-button)').each(function () {
|
|
33584
|
+
const tabId = $(this).attr('data-tab-id')
|
|
33585
|
+
const tabOptions = knownTabs[tabId]
|
|
33586
|
+
let initialStateSet = false
|
|
33587
|
+
menuOptions.push({
|
|
33588
|
+
label: tabOptions.name,
|
|
33589
|
+
selected: tabId === active,
|
|
33590
|
+
toggle: true,
|
|
33591
|
+
onselect: function(state) {
|
|
33592
|
+
if (!initialStateSet) {
|
|
33593
|
+
// This is called when showing the menu to initialise the state properly. This made
|
|
33594
|
+
// sense for other menus, but is inconvenient here. So we swallow the first call to onselect
|
|
33595
|
+
// without taking any action.
|
|
33596
|
+
initialStateSet = true
|
|
33597
|
+
return
|
|
33598
|
+
}
|
|
33599
|
+
if (state) {
|
|
33600
|
+
RED.sidebar.show(tabId)
|
|
33601
|
+
} else {
|
|
33602
|
+
// DRY: overlapping logic with the mouseup handler on the inidividual tab buttons
|
|
33603
|
+
if (!sidebar.sections[targetSection].hidden) {
|
|
33604
|
+
const otherSectionHidden = sidebar.sections[targetSection === 'top' ? 'bottom' : 'top'].hidden
|
|
33605
|
+
if (otherSectionHidden) {
|
|
33606
|
+
// Both sections are going to be hidden, so hide the sidebar first.
|
|
33607
|
+
// We do this *before* hiding the last section so that we remember which the 'last' section was and it can be
|
|
33608
|
+
// restored when the sidebar is shown again.
|
|
33609
|
+
RED.menu.setSelected(sidebar.menuToggle, false);
|
|
33610
|
+
} else {
|
|
33611
|
+
// Hiding just one section, clear its active setting
|
|
33612
|
+
sidebar.tabBars[targetSection].active = null
|
|
33613
|
+
}
|
|
33614
|
+
sidebar.hideSection(targetSection)
|
|
33615
|
+
} else {
|
|
33616
|
+
sidebar.showSection(targetSection)
|
|
33617
|
+
}
|
|
33618
|
+
exportSidebarState()
|
|
33619
|
+
}
|
|
33620
|
+
|
|
33621
|
+
}
|
|
33622
|
+
})
|
|
33623
|
+
})
|
|
33624
|
+
return menuOptions
|
|
33625
|
+
}
|
|
33626
|
+
|
|
33266
33627
|
function setupSidebarTabs(sidebar) {
|
|
33267
33628
|
const tabBar = $('<div class="red-ui-sidebar-tab-bar"></div>').addClass('red-ui-sidebar-' + sidebar.direction);
|
|
33268
33629
|
if (sidebar.direction === 'right') {
|
|
@@ -33286,6 +33647,48 @@ RED.sidebar = (function() {
|
|
|
33286
33647
|
// toggleSidebarButton.prependTo(tabBar);
|
|
33287
33648
|
// }
|
|
33288
33649
|
|
|
33650
|
+
sidebar.tabOverflowButton = $('<button class="red-ui-sidebar-tab-bar-overflow-button"><i class="fa fa-ellipsis-h"></i></button>');
|
|
33651
|
+
sidebar.tabOverflowButton.hide()
|
|
33652
|
+
sidebar.tabOverflowButton.on('click', function(evt) {
|
|
33653
|
+
try {
|
|
33654
|
+
const menuOptions = getSidebarOptions(sidebar, 'top')
|
|
33655
|
+
const bottomMenuOptions = getSidebarOptions(sidebar, 'bottom')
|
|
33656
|
+
if (menuOptions.length > 0 && bottomMenuOptions.length > 0) {
|
|
33657
|
+
menuOptions.push(null) // separator
|
|
33658
|
+
}
|
|
33659
|
+
menuOptions.push(...bottomMenuOptions)
|
|
33660
|
+
if (menuOptions.length === 0) {
|
|
33661
|
+
return
|
|
33662
|
+
}
|
|
33663
|
+
const menu = RED.menu.init({ options: menuOptions });
|
|
33664
|
+
menu.attr("id",sidebar.container.attr('id')+"-menu");
|
|
33665
|
+
menu.css({
|
|
33666
|
+
position: "absolute"
|
|
33667
|
+
})
|
|
33668
|
+
menu.appendTo("body");
|
|
33669
|
+
var elementPos = sidebar.tabOverflowButton.offset();
|
|
33670
|
+
menu.css({
|
|
33671
|
+
top: (elementPos.top+sidebar.tabOverflowButton.height()- menu.height() - 10)+"px",
|
|
33672
|
+
left: sidebar.direction === 'left' ? ((elementPos.left + sidebar.tabOverflowButton.width() + 3)+"px") : ((elementPos.left - menu.width() - 3)+"px")
|
|
33673
|
+
})
|
|
33674
|
+
$(".red-ui-menu.red-ui-menu-dropdown").hide();
|
|
33675
|
+
setTimeout(() => {
|
|
33676
|
+
$(document).on("click.red-ui-sidebar-tabmenu", function(evt) {
|
|
33677
|
+
$(document).off("click.red-ui-sidebar-tabmenu");
|
|
33678
|
+
menu.remove();
|
|
33679
|
+
});
|
|
33680
|
+
}, 0)
|
|
33681
|
+
menu.show();
|
|
33682
|
+
} catch (err) {
|
|
33683
|
+
console.log(err)
|
|
33684
|
+
}
|
|
33685
|
+
})
|
|
33686
|
+
|
|
33687
|
+
if (sidebar.direction === 'right') {
|
|
33688
|
+
sidebar.tabOverflowButton.appendTo(tabBar);
|
|
33689
|
+
} else if (sidebar.direction === 'left') {
|
|
33690
|
+
sidebar.tabOverflowButton.prependTo(tabBar);
|
|
33691
|
+
}
|
|
33289
33692
|
|
|
33290
33693
|
|
|
33291
33694
|
sidebar.tabBar = tabBar // sidebar.tabBars.top.container;
|
|
@@ -33324,51 +33727,7 @@ RED.sidebar = (function() {
|
|
|
33324
33727
|
}
|
|
33325
33728
|
|
|
33326
33729
|
function setupTabSection(sidebar, tabBar, position) {
|
|
33327
|
-
const tabBarButtonsContainer = $('<div class="red-ui-sidebar-tab-bar-buttons"></div>').appendTo(tabBar);
|
|
33328
|
-
const tabOverflowButton = $('<button class="red-ui-sidebar-tab-bar-overflow-button"><i class="fa fa-ellipsis-h"></i></button>').appendTo(tabBarButtonsContainer);
|
|
33329
|
-
tabOverflowButton.hide()
|
|
33330
|
-
tabOverflowButton.on('click', function(evt) {
|
|
33331
|
-
try {
|
|
33332
|
-
const menuOptions = []
|
|
33333
|
-
tabBarButtonsContainer.find('button:not(.red-ui-sidebar-tab-bar-overflow-button)').each(function () {
|
|
33334
|
-
if ($(this).is(':visible')) {
|
|
33335
|
-
return
|
|
33336
|
-
}
|
|
33337
|
-
const tabId = $(this).attr('data-tab-id')
|
|
33338
|
-
const tabOptions = knownTabs[tabId]
|
|
33339
|
-
menuOptions.push({
|
|
33340
|
-
label: tabOptions.name,
|
|
33341
|
-
onselect: function() {
|
|
33342
|
-
RED.sidebar.show(tabId)
|
|
33343
|
-
}
|
|
33344
|
-
})
|
|
33345
|
-
})
|
|
33346
|
-
if (menuOptions.length === 0) {
|
|
33347
|
-
return
|
|
33348
|
-
}
|
|
33349
|
-
const menu = RED.menu.init({ options: menuOptions });
|
|
33350
|
-
menu.attr("id",sidebar.container.attr('id')+"-menu");
|
|
33351
|
-
menu.css({
|
|
33352
|
-
position: "absolute"
|
|
33353
|
-
})
|
|
33354
|
-
menu.appendTo("body");
|
|
33355
|
-
var elementPos = tabOverflowButton.offset();
|
|
33356
|
-
menu.css({
|
|
33357
|
-
top: (elementPos.top+tabOverflowButton.height()- menu.height() - 10)+"px",
|
|
33358
|
-
left: sidebar.direction === 'left' ? ((elementPos.left + tabOverflowButton.width() + 3)+"px") : ((elementPos.left - menu.width() - 3)+"px")
|
|
33359
|
-
})
|
|
33360
|
-
$(".red-ui-menu.red-ui-menu-dropdown").hide();
|
|
33361
|
-
setTimeout(() => {
|
|
33362
|
-
$(document).on("click.red-ui-sidebar-tabmenu", function(evt) {
|
|
33363
|
-
$(document).off("click.red-ui-sidebar-tabmenu");
|
|
33364
|
-
menu.remove();
|
|
33365
|
-
});
|
|
33366
|
-
}, 0)
|
|
33367
|
-
menu.show();
|
|
33368
|
-
} catch (err) {
|
|
33369
|
-
console.log(err)
|
|
33370
|
-
}
|
|
33371
|
-
})
|
|
33730
|
+
const tabBarButtonsContainer = $('<div class="red-ui-sidebar-tab-bar-buttons red-ui-sidebar-tab-bar-empty"></div>').appendTo(tabBar);
|
|
33372
33731
|
tabBarButtonsContainer.data('sidebar', sidebar.id)
|
|
33373
33732
|
tabBarButtonsContainer.data('sidebar-position', position)
|
|
33374
33733
|
tabBarButtonsContainer.sortable({
|
|
@@ -33418,8 +33777,9 @@ RED.sidebar = (function() {
|
|
|
33418
33777
|
return {
|
|
33419
33778
|
container: tabBarButtonsContainer,
|
|
33420
33779
|
addButton: function(button, position) {
|
|
33780
|
+
tabBarButtonsContainer.removeClass('red-ui-sidebar-tab-bar-empty');
|
|
33421
33781
|
if (position === undefined || position >= tabBarButtonsContainer.children().length) {
|
|
33422
|
-
button.
|
|
33782
|
+
button.appendTo(tabBarButtonsContainer);
|
|
33423
33783
|
} else {
|
|
33424
33784
|
button.insertBefore(tabBarButtonsContainer.children().eq(position));
|
|
33425
33785
|
}
|
|
@@ -33492,7 +33852,9 @@ RED.sidebar = (function() {
|
|
|
33492
33852
|
}
|
|
33493
33853
|
sidebar.container.width(newSidebarWidth);
|
|
33494
33854
|
ui.position.left -= scaleFactor * d
|
|
33495
|
-
sidebar.
|
|
33855
|
+
if (sidebar.direction === 'left') {
|
|
33856
|
+
sidebar.tabBar.css('min-width', sidebar.container.width() - 5)
|
|
33857
|
+
}
|
|
33496
33858
|
RED.events.emit("sidebar:resize");
|
|
33497
33859
|
},
|
|
33498
33860
|
stop:function(event,ui) {
|
|
@@ -33508,7 +33870,9 @@ RED.sidebar = (function() {
|
|
|
33508
33870
|
} else {
|
|
33509
33871
|
sidebar.width = sidebar.container.width();
|
|
33510
33872
|
}
|
|
33511
|
-
sidebar.
|
|
33873
|
+
if (sidebar.direction === 'left') {
|
|
33874
|
+
sidebar.tabBar.css('min-width', sidebar.container.width() - 5)
|
|
33875
|
+
}
|
|
33512
33876
|
RED.events.emit("sidebar:resize");
|
|
33513
33877
|
}
|
|
33514
33878
|
});
|
|
@@ -33552,7 +33916,9 @@ RED.sidebar = (function() {
|
|
|
33552
33916
|
}
|
|
33553
33917
|
}
|
|
33554
33918
|
sidebar.container.width(sidebar.width || sidebar.defaultWidth)
|
|
33555
|
-
sidebar.
|
|
33919
|
+
if (sidebar.direction === 'left') {
|
|
33920
|
+
sidebar.tabBar.css('min-width', sidebar.container.width() - 5)
|
|
33921
|
+
}
|
|
33556
33922
|
sidebar.separator.show()
|
|
33557
33923
|
if (sidebar.tabBars.top.active && !sidebar.sections.top.hidden) {
|
|
33558
33924
|
sidebar.tabBars.top.container.find('button[data-tab-id="'+sidebar.tabBars.top.active+'"]').addClass('selected')
|
|
@@ -33624,8 +33990,8 @@ RED.sidebar = (function() {
|
|
|
33624
33990
|
const sidebarHeight = $("#red-ui-main-container").height();
|
|
33625
33991
|
sidebar.container.addClass("red-ui-sidebar").addClass('red-ui-sidebar-' + sidebar.direction);
|
|
33626
33992
|
sidebar.container.width(sidebar.defaultWidth);
|
|
33627
|
-
if (sidebar.direction === '
|
|
33628
|
-
$('<div>',{class:"red-ui-sidebar-shade hide"}).css("z-index", 0).appendTo(sidebar.container);
|
|
33993
|
+
if (sidebar.direction === 'left') {
|
|
33994
|
+
// $('<div>',{class:"red-ui-sidebar-shade hide"}).css("z-index", 0).appendTo(sidebar.container);
|
|
33629
33995
|
}
|
|
33630
33996
|
sidebar.sections = {};
|
|
33631
33997
|
sidebar.sections.top = {}
|
|
@@ -33689,9 +34055,37 @@ RED.sidebar = (function() {
|
|
|
33689
34055
|
}
|
|
33690
34056
|
}
|
|
33691
34057
|
// Trigger a resize of the tab bars to handle overflow
|
|
33692
|
-
sidebar.
|
|
34058
|
+
if (sidebar.direction === 'left') {
|
|
34059
|
+
sidebar.tabBar.css('min-width', sidebar.container.width() - 5)
|
|
34060
|
+
}
|
|
33693
34061
|
RED.events.emit("sidebar:resize");
|
|
33694
34062
|
|
|
34063
|
+
if (sidebar.direction === 'right') {
|
|
34064
|
+
const windowWidth = $("#red-ui-editor").width();
|
|
34065
|
+
if (sidebar.tabOverflowButtonShown) {
|
|
34066
|
+
// Check if there's space to show the tab bar again
|
|
34067
|
+
if ($(window).width() - (sidebars.secondary.tabBar.width() + sidebar.tabOverflowButtonStatusBarWidth + sidebar.tabOverflowButtonSpace) > 0) {
|
|
34068
|
+
sidebar.tabOverflowButtonShown = false
|
|
34069
|
+
sidebar.tabOverflowButton.hide()
|
|
34070
|
+
sidebar.tabBars.top.container.show()
|
|
34071
|
+
sidebar.tabBars.bottom.container.show()
|
|
34072
|
+
|
|
34073
|
+
}
|
|
34074
|
+
}
|
|
34075
|
+
if (!sidebar.tabOverflowButtonShown) {
|
|
34076
|
+
const tabBarWidth = sidebar.tabBar.width()
|
|
34077
|
+
const tabBarPosition = sidebar.tabBar.position()
|
|
34078
|
+
if (tabBarWidth + tabBarPosition.left > windowWidth) {
|
|
34079
|
+
sidebar.tabOverflowButtonStatusBarWidth = $("#red-ui-statusbar").width()
|
|
34080
|
+
sidebar.tabOverflowButtonSpace = tabBarWidth
|
|
34081
|
+
sidebar.tabOverflowButtonShown = true
|
|
34082
|
+
sidebar.tabOverflowButton.show()
|
|
34083
|
+
sidebar.tabBars.top.container.hide()
|
|
34084
|
+
sidebar.tabBars.bottom.container.hide()
|
|
34085
|
+
}
|
|
34086
|
+
}
|
|
34087
|
+
}
|
|
34088
|
+
|
|
33695
34089
|
}
|
|
33696
34090
|
$(window).on("resize", sidebar.resizeSidebar)
|
|
33697
34091
|
|
|
@@ -35381,10 +35775,10 @@ RED.sidebar.info = (function() {
|
|
|
35381
35775
|
|
|
35382
35776
|
function build() {
|
|
35383
35777
|
var container = $("<div>", {class:"red-ui-info-outline"}).css({'height': '100%'});
|
|
35384
|
-
var toolbar = $("<div>", {class:"red-ui-
|
|
35778
|
+
var toolbar = $("<div>", {class:"red-ui-info-toolbar red-ui-palette-search"}).appendTo(container);
|
|
35385
35779
|
|
|
35386
35780
|
searchInput = $('<input type="text" data-i18n="[placeholder]menu.label.search">').appendTo(toolbar).searchBox({
|
|
35387
|
-
style: "compact",
|
|
35781
|
+
// style: "compact",
|
|
35388
35782
|
delay: 500,
|
|
35389
35783
|
change: function() {
|
|
35390
35784
|
var val = $(this).val();
|
|
@@ -35439,8 +35833,6 @@ RED.sidebar.info = (function() {
|
|
|
35439
35833
|
// } else {
|
|
35440
35834
|
// // RED.view.select({nodes:[]})
|
|
35441
35835
|
// }
|
|
35442
|
-
} else {
|
|
35443
|
-
RED.sidebar.info.refresh(null);
|
|
35444
35836
|
}
|
|
35445
35837
|
})
|
|
35446
35838
|
treeList.on('treelistconfirm', function(e,item) {
|
|
@@ -35738,6 +36130,7 @@ RED.sidebar.info = (function() {
|
|
|
35738
36130
|
config: true,
|
|
35739
36131
|
flow: parent,
|
|
35740
36132
|
types: {},
|
|
36133
|
+
expandOnLabel: true,
|
|
35741
36134
|
label: RED._("menu.label.displayConfig"),
|
|
35742
36135
|
children: []
|
|
35743
36136
|
}
|
|
@@ -35748,6 +36141,7 @@ RED.sidebar.info = (function() {
|
|
|
35748
36141
|
configNodeTypes[parent].types[type] = {
|
|
35749
36142
|
config: true,
|
|
35750
36143
|
label: type,
|
|
36144
|
+
expandOnLabel: true,
|
|
35751
36145
|
children: []
|
|
35752
36146
|
}
|
|
35753
36147
|
configNodeTypes[parent].treeList.addChild(configNodeTypes[parent].types[type]);
|
|
@@ -36788,24 +37182,16 @@ RED.sidebar.config = (function() {
|
|
|
36788
37182
|
//cancel current flashing node before flashing new node
|
|
36789
37183
|
clearInterval(flashingConfigNodeTimer);
|
|
36790
37184
|
flashingConfigNodeTimer = null;
|
|
36791
|
-
flashingConfigNode.children("div").removeClass('highlighted');
|
|
37185
|
+
flashingConfigNode.children("div").removeClass('red-ui-flow-node-highlighted');
|
|
36792
37186
|
flashingConfigNode = null;
|
|
36793
37187
|
}
|
|
36794
37188
|
if(!el || !el.children("div").length) { return; }
|
|
36795
37189
|
|
|
36796
|
-
flashingConfigNodeTimer =
|
|
36797
|
-
|
|
36798
|
-
|
|
36799
|
-
el.children("div").toggleClass('highlighted', !highlighted)
|
|
36800
|
-
} else {
|
|
36801
|
-
clearInterval(flashingConfigNodeTimer);
|
|
36802
|
-
flashingConfigNodeTimer = null;
|
|
36803
|
-
flashingConfigNode = null;
|
|
36804
|
-
el.children("div").removeClass('highlighted');
|
|
36805
|
-
}
|
|
36806
|
-
}, 100, Date.now() + 2200);
|
|
37190
|
+
flashingConfigNodeTimer = setTimeout(function() {
|
|
37191
|
+
flashingConfigNode.children("div").removeClass('red-ui-flow-node-highlighted');
|
|
37192
|
+
}, 8100)
|
|
36807
37193
|
flashingConfigNode = el;
|
|
36808
|
-
|
|
37194
|
+
flashingConfigNode.children("div").addClass('red-ui-flow-node-highlighted');
|
|
36809
37195
|
}
|
|
36810
37196
|
|
|
36811
37197
|
function show(id) {
|
|
@@ -36880,8 +37266,6 @@ RED.sidebar.context = (function() {
|
|
|
36880
37266
|
content = $("<div>").css({"position":"relative","height":"100%"});
|
|
36881
37267
|
content.className = "red-ui-sidebar-context"
|
|
36882
37268
|
|
|
36883
|
-
var footerToolbar = $('<div></div>');
|
|
36884
|
-
|
|
36885
37269
|
var stackContainer = $("<div>",{class:"red-ui-sidebar-context-stack"}).appendTo(content);
|
|
36886
37270
|
sections = RED.stack.create({
|
|
36887
37271
|
container: stackContainer
|
|
@@ -36978,7 +37362,6 @@ RED.sidebar.context = (function() {
|
|
|
36978
37362
|
name: RED._("sidebar.context.name"),
|
|
36979
37363
|
iconClass: "fa fa-database",
|
|
36980
37364
|
content: content,
|
|
36981
|
-
toolbar: footerToolbar,
|
|
36982
37365
|
// pinned: true,
|
|
36983
37366
|
enableOnEdit: true,
|
|
36984
37367
|
action: "core:show-context-tab"
|
|
@@ -41445,7 +41828,6 @@ RED.editor = (function() {
|
|
|
41445
41828
|
}
|
|
41446
41829
|
return {
|
|
41447
41830
|
init: function() {
|
|
41448
|
-
if(window.ace) { window.ace.config.set('basePath', 'vendor/ace'); }
|
|
41449
41831
|
RED.tray.init();
|
|
41450
41832
|
RED.actions.add("core:confirm-edit-tray", function() {
|
|
41451
41833
|
$(document.activeElement).blur();
|
|
@@ -41457,7 +41839,6 @@ RED.editor = (function() {
|
|
|
41457
41839
|
$("#node-dialog-cancel").trigger("click");
|
|
41458
41840
|
$("#node-config-dialog-cancel").trigger("click");
|
|
41459
41841
|
});
|
|
41460
|
-
RED.editor.codeEditor.init();
|
|
41461
41842
|
},
|
|
41462
41843
|
generateViewStateId: generateViewStateId,
|
|
41463
41844
|
edit: showEditDialog,
|
|
@@ -42921,7 +43302,7 @@ RED.editor = (function() {
|
|
|
42921
43302
|
* @namespace RED.editor.codeEditor
|
|
42922
43303
|
*/
|
|
42923
43304
|
RED.editor.codeEditor = (function() {
|
|
42924
|
-
|
|
43305
|
+
const BASIC = "basic";
|
|
42925
43306
|
const MONACO = "monaco";
|
|
42926
43307
|
const ACE = "ace";
|
|
42927
43308
|
const defaultEditor = MONACO;
|
|
@@ -42931,22 +43312,30 @@ RED.editor = (function() {
|
|
|
42931
43312
|
|
|
42932
43313
|
function init() {
|
|
42933
43314
|
var codeEditorSettings = RED.editor.codeEditor.settings;
|
|
42934
|
-
var editorChoice = codeEditorSettings.lib
|
|
43315
|
+
var editorChoice = codeEditorSettings.lib || defaultEditor;
|
|
43316
|
+
if (![MONACO, ACE, BASIC].includes(editorChoice)) {
|
|
43317
|
+
console.warn("Invalid code editor specified in settings - '" + editorChoice + "'. Falling back to basic editor.")
|
|
43318
|
+
editorChoice = BASIC;
|
|
43319
|
+
}
|
|
42935
43320
|
try {
|
|
42936
|
-
var browser = RED.utils.getBrowserInfo();
|
|
42937
43321
|
selectedCodeEditor = RED.editor.codeEditor[editorChoice];
|
|
42938
|
-
//
|
|
42939
|
-
|
|
42940
|
-
|
|
43322
|
+
// On first uncached load, editor may not yet be downloaded and in the DOM, so we check for the presence in `window` and defer
|
|
43323
|
+
// initialization until the editor is actually loaded. Not relevant for basic editor as it is always present.
|
|
43324
|
+
if (editorChoice === MONACO && !window.monaco) {
|
|
43325
|
+
console.debug("Monaco editor is not yet loaded, delaying initialization");
|
|
43326
|
+
return
|
|
43327
|
+
} else if (editorChoice === ACE && !window.ace) {
|
|
43328
|
+
console.debug("ACE editor is not yet loaded, delaying initialization");
|
|
43329
|
+
return
|
|
42941
43330
|
}
|
|
42942
|
-
initialised = selectedCodeEditor.init();
|
|
43331
|
+
initialised = selectedCodeEditor && selectedCodeEditor.init();
|
|
42943
43332
|
} catch (error) {
|
|
42944
43333
|
selectedCodeEditor = null;
|
|
42945
43334
|
console.warn("Problem initialising '" + editorChoice + "' code editor", error);
|
|
42946
43335
|
}
|
|
42947
43336
|
if(!initialised) {
|
|
42948
43337
|
selectedCodeEditor = RED.editor.codeEditor[defaultEditor];
|
|
42949
|
-
initialised = selectedCodeEditor.init();
|
|
43338
|
+
initialised = selectedCodeEditor && selectedCodeEditor.init();
|
|
42950
43339
|
}
|
|
42951
43340
|
|
|
42952
43341
|
$('<div id="red-ui-drop-target-markdown-editor"><div><i class="fa fa-download"></i><br></div></div>').appendTo('#red-ui-editor');
|
|
@@ -42954,16 +43343,13 @@ RED.editor = (function() {
|
|
|
42954
43343
|
}
|
|
42955
43344
|
|
|
42956
43345
|
function create(options) {
|
|
42957
|
-
|
|
42958
|
-
|
|
42959
|
-
|
|
42960
|
-
|
|
42961
|
-
|
|
42962
|
-
|
|
42963
|
-
|
|
42964
|
-
// Because one (or more) contrib nodes have left this bad code in place, how would we handle this?
|
|
42965
|
-
// For compatibility, I have decided to create a hidden element so that at least an editor is created & errors do not occur.
|
|
42966
|
-
// IMO, we should warn and exit as it is a coding error by the contrib author.
|
|
43346
|
+
if(!initialised) {
|
|
43347
|
+
RED.editor.codeEditor.init(); // try to initialize again in case ace/monaco have loaded since the first attempt
|
|
43348
|
+
if(!initialised) {
|
|
43349
|
+
console.debug("Preferred code editor is not initialised, falling back to basic code editor until it is loaded");
|
|
43350
|
+
return RED.editor.codeEditor.basic.create(options); // fallback to basic editor
|
|
43351
|
+
}
|
|
43352
|
+
}
|
|
42967
43353
|
|
|
42968
43354
|
if (!options) {
|
|
42969
43355
|
console.warn("createEditor() options are missing");
|
|
@@ -45663,6 +46049,7 @@ RED.editor.codeEditor.ace = (function() {
|
|
|
45663
46049
|
var initOptions = {};
|
|
45664
46050
|
|
|
45665
46051
|
function init(options) {
|
|
46052
|
+
window.ace.config.set('basePath', 'vendor/ace');
|
|
45666
46053
|
initOptions = options || {};
|
|
45667
46054
|
initialised = true;
|
|
45668
46055
|
return initialised;
|
|
@@ -45843,7 +46230,404 @@ RED.editor.codeEditor.ace = (function() {
|
|
|
45843
46230
|
*/
|
|
45844
46231
|
create: create
|
|
45845
46232
|
}
|
|
45846
|
-
})()
|
|
46233
|
+
})();;
|
|
46234
|
+
/**
|
|
46235
|
+
* @namespace RED.editor.codeEditor.basic
|
|
46236
|
+
*/
|
|
46237
|
+
|
|
46238
|
+
/*
|
|
46239
|
+
The code editor currenlty supports 2 functions init and create.
|
|
46240
|
+
* Init() - setup the editor / must return true
|
|
46241
|
+
* Create() - create an editor instance / returns an editor as generated by the editor lib
|
|
46242
|
+
* To be compatable with the original ace lib (for contrib nodes using it), the object returned by create() must (at minimum) support the following...
|
|
46243
|
+
property .selection = {};
|
|
46244
|
+
function .selection.getRange();
|
|
46245
|
+
property .session //the editor object
|
|
46246
|
+
function .session.insert = function(position, text)
|
|
46247
|
+
function .setReadOnly(readOnly)
|
|
46248
|
+
property .renderer = {};
|
|
46249
|
+
function .renderer.updateFull()
|
|
46250
|
+
function setMode(mode, cb)
|
|
46251
|
+
function getRange();
|
|
46252
|
+
function replace(range, text)
|
|
46253
|
+
function selectAll
|
|
46254
|
+
function clearSelection
|
|
46255
|
+
function getSelectedText()
|
|
46256
|
+
function destroy()
|
|
46257
|
+
function resize()
|
|
46258
|
+
function getSession()
|
|
46259
|
+
function getLength()
|
|
46260
|
+
function scrollToLine(lineNumber, scrollType)
|
|
46261
|
+
function moveCursorTo(lineNumber, colNumber)
|
|
46262
|
+
function getAnnotations()
|
|
46263
|
+
function gotoLine(row, col)
|
|
46264
|
+
function getCursorPosition()
|
|
46265
|
+
function setTheme(name)
|
|
46266
|
+
function setFontSize(size:Number) //Set a new font size (in pixels) for the editor text.
|
|
46267
|
+
function on(name, cb)
|
|
46268
|
+
function getUndoManager()
|
|
46269
|
+
|
|
46270
|
+
*/
|
|
46271
|
+
|
|
46272
|
+
RED.editor.codeEditor.basic = (function() {
|
|
46273
|
+
var initialised = false;
|
|
46274
|
+
const type = "basic";
|
|
46275
|
+
|
|
46276
|
+
|
|
46277
|
+
function init(options) {
|
|
46278
|
+
options = options || {};
|
|
46279
|
+
initialised = true;
|
|
46280
|
+
return initialised;
|
|
46281
|
+
}
|
|
46282
|
+
|
|
46283
|
+
function create(options) {
|
|
46284
|
+
const editorSettings = RED.editor.codeEditor.settings || {};
|
|
46285
|
+
if(!options.stateId && options.stateId !== false) {
|
|
46286
|
+
options.stateId = RED.editor.generateViewStateId("basic", options, (options.mode || options.title || "").split("/").pop());
|
|
46287
|
+
}
|
|
46288
|
+
let el = options.element || $("#"+options.id)[0];
|
|
46289
|
+
const toolbarRow = $("<div>").appendTo(el);
|
|
46290
|
+
el = $("<div>").appendTo(el).addClass("red-ui-editor-text-container")[0];
|
|
46291
|
+
const textarea = $("<textarea>").appendTo(el)
|
|
46292
|
+
textarea.attr("id", options.id + "_editor");
|
|
46293
|
+
textarea.css({ width: "100%", height: "100%" });
|
|
46294
|
+
textarea.addClass("red-ui-editor-text-basic");
|
|
46295
|
+
|
|
46296
|
+
/** @type {HTMLTextAreaElement} */
|
|
46297
|
+
const textareaEl = textarea[0];
|
|
46298
|
+
const editorOptions = $.extend({}, editorSettings.options, options);
|
|
46299
|
+
editorOptions.language = options.mode;
|
|
46300
|
+
editorOptions.value = options.value || "";
|
|
46301
|
+
textarea.val(editorOptions.value);
|
|
46302
|
+
|
|
46303
|
+
/*********** Create the basic editor ***************/
|
|
46304
|
+
const ed = {
|
|
46305
|
+
selection: {},
|
|
46306
|
+
session: {},
|
|
46307
|
+
renderer: {},
|
|
46308
|
+
}
|
|
46309
|
+
|
|
46310
|
+
// #region "ACE compatability"
|
|
46311
|
+
ed.setMode = function(mode, cb) {
|
|
46312
|
+
editorOptions.language = mode;
|
|
46313
|
+
if (cb && typeof cb == "function") {
|
|
46314
|
+
cb();
|
|
46315
|
+
}
|
|
46316
|
+
}
|
|
46317
|
+
|
|
46318
|
+
ed.getRange = function getRange(){
|
|
46319
|
+
const value = textareaEl.value;
|
|
46320
|
+
const range = { start: { row: 0, column: 0 }, end: { row: 0, column: 0 } };
|
|
46321
|
+
range.start.row = value.substring(0, textareaEl.selectionStart).split("\n").length - 1;
|
|
46322
|
+
range.start.column = textareaEl.selectionStart - value.lastIndexOf("\n", textareaEl.selectionStart - 1) - 1;
|
|
46323
|
+
range.end.row = value.substring(0, textareaEl.selectionEnd).split("\n").length - 1;
|
|
46324
|
+
range.end.column = textareaEl.selectionEnd - value.lastIndexOf("\n", textareaEl.selectionEnd - 1) - 1;
|
|
46325
|
+
return range;
|
|
46326
|
+
}
|
|
46327
|
+
|
|
46328
|
+
ed.selection.getRange = ed.getRange;
|
|
46329
|
+
|
|
46330
|
+
ed.session.insert = function insert(position, text) {
|
|
46331
|
+
//position is zero based
|
|
46332
|
+
const col = position.column || 0;
|
|
46333
|
+
const row = position.row || 0;
|
|
46334
|
+
// calculate selectionStart and selectionEnd based on row and column
|
|
46335
|
+
const value = textareaEl.value;
|
|
46336
|
+
const lines = value.split("\n");
|
|
46337
|
+
let selectionStart = 0;
|
|
46338
|
+
for (let i = 0; i < row; i++) {
|
|
46339
|
+
selectionStart += lines[i].length + 1; // +1 for the newline character
|
|
46340
|
+
}
|
|
46341
|
+
selectionStart += col;
|
|
46342
|
+
const selectionEnd = selectionStart;
|
|
46343
|
+
textareaEl.focus();
|
|
46344
|
+
textareaEl.setSelectionRange(selectionStart, selectionEnd);
|
|
46345
|
+
textareaEl.setRangeText(text)
|
|
46346
|
+
}
|
|
46347
|
+
|
|
46348
|
+
ed.setReadOnly = function setReadOnly(readOnly) {
|
|
46349
|
+
textareaEl.readOnly = readOnly;
|
|
46350
|
+
}
|
|
46351
|
+
|
|
46352
|
+
ed.session.replace = function replace(range, text) {
|
|
46353
|
+
const value = textareaEl.value;
|
|
46354
|
+
const lines = value.split("\n");
|
|
46355
|
+
let selectionStart = 0;
|
|
46356
|
+
for (let i = 0; i < (range.start.row || 0); i++) {
|
|
46357
|
+
selectionStart += lines[i].length + 1; // +1 for the newline character
|
|
46358
|
+
}
|
|
46359
|
+
selectionStart += (range.start.column || 0);
|
|
46360
|
+
let selectionEnd = 0;
|
|
46361
|
+
for (let i = 0; i < (range.end.row || 0); i++) {
|
|
46362
|
+
selectionEnd += lines[i].length + 1; // +1 for the newline character
|
|
46363
|
+
}
|
|
46364
|
+
selectionEnd += (range.end.column || 0);
|
|
46365
|
+
textareaEl.focus();
|
|
46366
|
+
textareaEl.setSelectionRange(selectionStart, selectionEnd);
|
|
46367
|
+
textareaEl.setRangeText(text)
|
|
46368
|
+
}
|
|
46369
|
+
|
|
46370
|
+
ed.getValue = function getValue() {
|
|
46371
|
+
return textareaEl.value;
|
|
46372
|
+
}
|
|
46373
|
+
|
|
46374
|
+
ed.setValue = function setValue(value, cursorPos) {
|
|
46375
|
+
textareaEl.value = value;
|
|
46376
|
+
if (cursorPos === -1) {
|
|
46377
|
+
ed.clearSelection();
|
|
46378
|
+
} else if (cursorPos) {
|
|
46379
|
+
textareaEl.setSelectionRange(cursorPos, cursorPos);
|
|
46380
|
+
}
|
|
46381
|
+
}
|
|
46382
|
+
|
|
46383
|
+
ed.renderer.updateFull = function updateFull() {
|
|
46384
|
+
// no need to do anything as the textarea will handle this
|
|
46385
|
+
}
|
|
46386
|
+
|
|
46387
|
+
ed.selectAll = function selectAll() {
|
|
46388
|
+
textareaEl.focus();
|
|
46389
|
+
textareaEl.select();
|
|
46390
|
+
}
|
|
46391
|
+
|
|
46392
|
+
ed.clearSelection = function clearSelection() {
|
|
46393
|
+
textareaEl.focus();
|
|
46394
|
+
const selectionStart = textareaEl.selectionDirection == "backward" ? textareaEl.selectionEnd : textareaEl.selectionStart;
|
|
46395
|
+
textareaEl.setSelectionRange(selectionStart, selectionStart);
|
|
46396
|
+
}
|
|
46397
|
+
|
|
46398
|
+
ed.getSelectedText = function getSelectedText() {
|
|
46399
|
+
return textareaEl.value.substring(textareaEl.selectionStart, textareaEl.selectionEnd);
|
|
46400
|
+
}
|
|
46401
|
+
|
|
46402
|
+
ed.on = function (name, cb) {
|
|
46403
|
+
textareaEl.addEventListener(name, cb)
|
|
46404
|
+
}
|
|
46405
|
+
|
|
46406
|
+
ed.off = function (name, cb) {
|
|
46407
|
+
textarea.on(name, cb)
|
|
46408
|
+
}
|
|
46409
|
+
|
|
46410
|
+
ed.destroy = function destroy() {
|
|
46411
|
+
try {
|
|
46412
|
+
ed.saveView();
|
|
46413
|
+
ed._initState = null;
|
|
46414
|
+
textarea.off()
|
|
46415
|
+
} catch (e) { }
|
|
46416
|
+
$(textareaEl).remove();
|
|
46417
|
+
$(toolbarRow).remove();
|
|
46418
|
+
}
|
|
46419
|
+
ed.on("blur", function () {
|
|
46420
|
+
ed.focusMemory = false;
|
|
46421
|
+
ed.saveView();
|
|
46422
|
+
})
|
|
46423
|
+
ed.on("focus", function () {
|
|
46424
|
+
if (ed._initState) {
|
|
46425
|
+
ed.restoreView(ed._initState);
|
|
46426
|
+
ed._initState = null;
|
|
46427
|
+
}
|
|
46428
|
+
})
|
|
46429
|
+
|
|
46430
|
+
ed.focus = function focus() {
|
|
46431
|
+
textareaEl.focus();
|
|
46432
|
+
}
|
|
46433
|
+
|
|
46434
|
+
ed.resize = function resize() {
|
|
46435
|
+
// not needed as the textarea will handle this
|
|
46436
|
+
}
|
|
46437
|
+
|
|
46438
|
+
ed.getSession = function getSession() {
|
|
46439
|
+
return ed;
|
|
46440
|
+
}
|
|
46441
|
+
|
|
46442
|
+
ed.getLength = function getLength() {
|
|
46443
|
+
return textareaEl.value.length;
|
|
46444
|
+
}
|
|
46445
|
+
|
|
46446
|
+
/**
|
|
46447
|
+
* Scroll vertically as necessary and reveal a line.
|
|
46448
|
+
* @param {Number} lineNumber
|
|
46449
|
+
* @param {ScrollType|Number} [scrollType] Immediate: = 1, Smooth: = 0
|
|
46450
|
+
*/
|
|
46451
|
+
ed.scrollToLine = function scrollToLine(lineNumber, scrollType) {
|
|
46452
|
+
const computedStyle = getComputedStyle(textareaEl);
|
|
46453
|
+
let lineHeight = parseFloat(computedStyle.lineHeight);
|
|
46454
|
+
if (isNaN(lineHeight)) { lineHeight = parseFloat(computedStyle.fontSize) }
|
|
46455
|
+
if (isNaN(lineHeight)) { lineHeight = 12 }
|
|
46456
|
+
const scrollTop = (lineNumber - 1) * lineHeight;
|
|
46457
|
+
if (scrollType === 0) {
|
|
46458
|
+
textareaEl.scrollTo({
|
|
46459
|
+
top: scrollTop,
|
|
46460
|
+
behavior: "smooth"
|
|
46461
|
+
});
|
|
46462
|
+
} else {
|
|
46463
|
+
textareaEl.scrollTop = scrollTop;
|
|
46464
|
+
}
|
|
46465
|
+
}
|
|
46466
|
+
|
|
46467
|
+
ed.moveCursorTo = function moveCursorTo(lineNumber, colNumber) {
|
|
46468
|
+
const value = textareaEl.value;
|
|
46469
|
+
const lines = value.split("\n");
|
|
46470
|
+
let selectionStart = 0;
|
|
46471
|
+
for (let i = 0; i < lineNumber - 1; i++) {
|
|
46472
|
+
selectionStart += lines[i].length + 1; // +1 for the newline character
|
|
46473
|
+
}
|
|
46474
|
+
selectionStart += colNumber - 1;
|
|
46475
|
+
textareaEl.focus();
|
|
46476
|
+
textareaEl.setSelectionRange(selectionStart, selectionStart);
|
|
46477
|
+
}
|
|
46478
|
+
|
|
46479
|
+
ed.getAnnotations = function getAnnotations() {
|
|
46480
|
+
return []
|
|
46481
|
+
}
|
|
46482
|
+
|
|
46483
|
+
//ACE row and col are zero based
|
|
46484
|
+
ed.gotoLine = function gotoLine(row, col) {
|
|
46485
|
+
ed.moveCursorTo(row, col);
|
|
46486
|
+
ed.scrollToLine(row);
|
|
46487
|
+
}
|
|
46488
|
+
//ACE row and col are zero based
|
|
46489
|
+
ed.getCursorPosition = function getCursorPosition() {
|
|
46490
|
+
const value = textareaEl.value;
|
|
46491
|
+
const lineNumber = value.substring(0, textareaEl.selectionStart).split("\n").length;
|
|
46492
|
+
const column = textareaEl.selectionStart - value.lastIndexOf("\n", textareaEl.selectionStart - 1);
|
|
46493
|
+
return { row: lineNumber-1, column: column-1 };
|
|
46494
|
+
}
|
|
46495
|
+
|
|
46496
|
+
ed.setTheme = function(theme) {
|
|
46497
|
+
const oldTheme = userSelectedTheme || editorSettings.options.theme || "light";
|
|
46498
|
+
userSelectedTheme = theme;//remember users choice for this session
|
|
46499
|
+
if (oldTheme) { el.classList.remove(oldTheme) }
|
|
46500
|
+
el.classList.add(theme)
|
|
46501
|
+
}
|
|
46502
|
+
|
|
46503
|
+
ed.on = function (name, cb) {
|
|
46504
|
+
textareaEl.addEventListener(name, cb)
|
|
46505
|
+
}
|
|
46506
|
+
ed.getUndoManager = function getUndoManager() {
|
|
46507
|
+
console.warn("Node-RED basic code editor does not support getUndoManager. Consider switching to Monaco or ACE editor.");
|
|
46508
|
+
return null
|
|
46509
|
+
}
|
|
46510
|
+
ed.setFontSize = function setFontSize(size) {
|
|
46511
|
+
textareaEl.style.fontSize = size + "px"
|
|
46512
|
+
}
|
|
46513
|
+
//#endregion "ACE compatability"
|
|
46514
|
+
|
|
46515
|
+
//final setup
|
|
46516
|
+
ed.focusMemory = options.focus
|
|
46517
|
+
ed.mode = editorOptions.language
|
|
46518
|
+
|
|
46519
|
+
if (editorOptions.language === 'markdown' || options.mode === "ace/mode/markdown") {
|
|
46520
|
+
$(el).addClass("red-ui-editor-text-container-toolbar");
|
|
46521
|
+
ed.toolbar = RED.editor.customEditTypes['_markdown'].buildToolbar(toolbarRow, ed);
|
|
46522
|
+
if (options.expandable !== false) {
|
|
46523
|
+
var expandButton = $('<button type="button" class="red-ui-button" style="float: right;"><i class="fa fa-expand"></i></button>').appendTo(ed.toolbar);
|
|
46524
|
+
RED.popover.tooltip(expandButton, RED._("markdownEditor.expand"));
|
|
46525
|
+
expandButton.on("click", function (e) {
|
|
46526
|
+
e.preventDefault();
|
|
46527
|
+
var value = textareaEl.value;
|
|
46528
|
+
RED.editor.editMarkdown({
|
|
46529
|
+
value: value,
|
|
46530
|
+
width: "Infinity",
|
|
46531
|
+
stateId: options.stateId,
|
|
46532
|
+
cancel: function () {
|
|
46533
|
+
ed.focus();
|
|
46534
|
+
},
|
|
46535
|
+
complete: function (v, cursor) {
|
|
46536
|
+
textareaEl.value = v;
|
|
46537
|
+
setTimeout(function () {
|
|
46538
|
+
ed.focus();
|
|
46539
|
+
// ed.restoreView();
|
|
46540
|
+
}, 300);
|
|
46541
|
+
}
|
|
46542
|
+
})
|
|
46543
|
+
});
|
|
46544
|
+
}
|
|
46545
|
+
var helpButton = $('<button type="button" class="red-ui-editor-text-help red-ui-button red-ui-button-small"><i class="fa fa-question"></i></button>').appendTo($(el).parent());
|
|
46546
|
+
RED.popover.create({
|
|
46547
|
+
target: helpButton,
|
|
46548
|
+
trigger: 'click',
|
|
46549
|
+
size: "small",
|
|
46550
|
+
direction: "left",
|
|
46551
|
+
content: RED._("markdownEditor.format"),
|
|
46552
|
+
autoClose: 50
|
|
46553
|
+
});
|
|
46554
|
+
}
|
|
46555
|
+
ed.getView = function () {
|
|
46556
|
+
const selection = {
|
|
46557
|
+
selectionStart: textareaEl.selectionStart,
|
|
46558
|
+
selectionEnd: textareaEl.selectionEnd,
|
|
46559
|
+
selectionDirection: textareaEl.selectionDirection
|
|
46560
|
+
}
|
|
46561
|
+
const scroll = {
|
|
46562
|
+
scrollTop: textareaEl.scrollTop,
|
|
46563
|
+
scrollLeft: textareaEl.scrollLeft
|
|
46564
|
+
}
|
|
46565
|
+
return {
|
|
46566
|
+
selection: selection,
|
|
46567
|
+
scroll: scroll
|
|
46568
|
+
}
|
|
46569
|
+
}
|
|
46570
|
+
ed.saveView = function () {
|
|
46571
|
+
if (!options.stateId) { return; } // only possible if created with a unique stateId
|
|
46572
|
+
window._editorStateBasic = window._editorStateBasic || {};
|
|
46573
|
+
const state = ed.getView();
|
|
46574
|
+
window._editorStateBasic[options.stateId] = state;
|
|
46575
|
+
return state;
|
|
46576
|
+
}
|
|
46577
|
+
ed.restoreView = function (state) {
|
|
46578
|
+
if (!window._editorStateBasic) { return; }
|
|
46579
|
+
var _state = state || window._editorStateBasic[options.stateId];
|
|
46580
|
+
if (_state) {
|
|
46581
|
+
try {
|
|
46582
|
+
const selection = _state.selection || {};
|
|
46583
|
+
const scroll = _state.scroll || {};
|
|
46584
|
+
textareaEl.setSelectionRange(selection.selectionStart, selection.selectionEnd, selection.selectionDirection);
|
|
46585
|
+
textareaEl.scrollTop = scroll.scrollTop;
|
|
46586
|
+
textareaEl.scrollLeft = scroll.scrollLeft;
|
|
46587
|
+
ed._initState = _state;
|
|
46588
|
+
} catch (error) {
|
|
46589
|
+
delete window._editorStateBasic[options.stateId];
|
|
46590
|
+
}
|
|
46591
|
+
}
|
|
46592
|
+
};
|
|
46593
|
+
ed.restoreView();
|
|
46594
|
+
|
|
46595
|
+
if (options.cursor && !ed._initState) {
|
|
46596
|
+
var row = options.cursor.row || options.cursor.lineNumber;
|
|
46597
|
+
var col = options.cursor.column || options.cursor.col;
|
|
46598
|
+
ed.gotoLine(row, col);
|
|
46599
|
+
}
|
|
46600
|
+
ed.type = type;
|
|
46601
|
+
|
|
46602
|
+
return ed;
|
|
46603
|
+
}
|
|
46604
|
+
|
|
46605
|
+
return {
|
|
46606
|
+
/**
|
|
46607
|
+
* Editor type
|
|
46608
|
+
* @memberof RED.editor.codeEditor.basic
|
|
46609
|
+
*/
|
|
46610
|
+
get type() { return type; },
|
|
46611
|
+
/**
|
|
46612
|
+
* Editor initialised
|
|
46613
|
+
* @memberof RED.editor.codeEditor.basic
|
|
46614
|
+
*/
|
|
46615
|
+
get initialised() { return initialised; },
|
|
46616
|
+
/**
|
|
46617
|
+
* Initialise code editor
|
|
46618
|
+
* @param {object} options - initialisation options
|
|
46619
|
+
* @memberof RED.editor.codeEditor.basic
|
|
46620
|
+
*/
|
|
46621
|
+
init: init,
|
|
46622
|
+
/**
|
|
46623
|
+
* Create a code editor
|
|
46624
|
+
* @param {object} options - the editor options
|
|
46625
|
+
* @memberof RED.editor.codeEditor.basic
|
|
46626
|
+
*/
|
|
46627
|
+
create: create
|
|
46628
|
+
}
|
|
46629
|
+
})();
|
|
46630
|
+
;/*
|
|
45847
46631
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
45848
46632
|
* you may not use this file except in compliance with the License.
|
|
45849
46633
|
* You may obtain a copy of the License at
|
|
@@ -47711,6 +48495,14 @@ RED.eventLog = (function() {
|
|
|
47711
48495
|
editorStack = $("#red-ui-editor-stack");
|
|
47712
48496
|
$(window).on("resize", handleWindowResize);
|
|
47713
48497
|
RED.events.on("sidebar:resize",handleWindowResize);
|
|
48498
|
+
$("#red-ui-editor-shade").on("click", function() {
|
|
48499
|
+
if (!openingTray) {
|
|
48500
|
+
var tray = stack[stack.length-1];
|
|
48501
|
+
if (tray && tray.primaryButton) {
|
|
48502
|
+
tray.primaryButton.click();
|
|
48503
|
+
}
|
|
48504
|
+
}
|
|
48505
|
+
});
|
|
47714
48506
|
},
|
|
47715
48507
|
show: function show(options) {
|
|
47716
48508
|
lowerTrayZ();
|
|
@@ -51343,17 +52135,11 @@ if (typeof module !== "undefined" && module.exports) {
|
|
|
51343
52135
|
})
|
|
51344
52136
|
menu.appendTo("body");
|
|
51345
52137
|
|
|
51346
|
-
// TODO: prevent the menu from overflowing the window.
|
|
51347
|
-
|
|
51348
52138
|
var top = options.y
|
|
51349
52139
|
var left = options.x
|
|
52140
|
+
var windowHeight = $(window).height();
|
|
52141
|
+
var windowWidth = $(window).width();
|
|
51350
52142
|
|
|
51351
|
-
if (top + menu.height() - $(document).scrollTop() > $(window).height()) {
|
|
51352
|
-
top -= (top + menu.height()) - $(window).height() + 22;
|
|
51353
|
-
}
|
|
51354
|
-
if (left + menu.width() - $(document).scrollLeft() > $(window).width()) {
|
|
51355
|
-
left -= (left + menu.width()) - $(window).width() + 18;
|
|
51356
|
-
}
|
|
51357
52143
|
menu.css({
|
|
51358
52144
|
top: top + "px",
|
|
51359
52145
|
left: left + "px"
|
|
@@ -51366,6 +52152,36 @@ if (typeof module !== "undefined" && module.exports) {
|
|
|
51366
52152
|
disposeMenu()
|
|
51367
52153
|
});
|
|
51368
52154
|
menu.show();
|
|
52155
|
+
|
|
52156
|
+
const menuHeight = menu.outerHeight();
|
|
52157
|
+
const menuWidth = menu.outerWidth();
|
|
52158
|
+
const spaceAbove = top;
|
|
52159
|
+
const bottomOverlap = menuHeight - (windowHeight - top);
|
|
52160
|
+
|
|
52161
|
+
// Adjust horizontal position if menu would overflow right edge
|
|
52162
|
+
if (left + menuWidth > windowWidth - 10) {
|
|
52163
|
+
left = windowWidth - menuWidth - 10;
|
|
52164
|
+
menu.css({ left: left + "px" });
|
|
52165
|
+
}
|
|
52166
|
+
|
|
52167
|
+
// Check if menu overflows below viewport
|
|
52168
|
+
if (bottomOverlap > 0) {
|
|
52169
|
+
if (spaceAbove > bottomOverlap + 5) {
|
|
52170
|
+
// There is room to move the menu up and still show it all
|
|
52171
|
+
menu.css({
|
|
52172
|
+
top: (top - bottomOverlap - 5) + "px"
|
|
52173
|
+
})
|
|
52174
|
+
} else {
|
|
52175
|
+
// There is not room for the whole menu.
|
|
52176
|
+
// 1. move it to the top
|
|
52177
|
+
// 2. enable overflow/scrolling
|
|
52178
|
+
menu.css({
|
|
52179
|
+
top: "5px",
|
|
52180
|
+
maxHeight: (windowHeight - 25) + "px",
|
|
52181
|
+
overflowY: "auto"
|
|
52182
|
+
});
|
|
52183
|
+
}
|
|
52184
|
+
}
|
|
51369
52185
|
// set focus to first item so that pressing escape key closes the menu
|
|
51370
52186
|
$("#red-ui-workspace-context-menu :first(ul) > a").trigger("focus")
|
|
51371
52187
|
|