/** * Copyright JS Foundation and other contributors, http://js.foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. **/ RED.workspaces = (function() { var activeWorkspace = 0; var workspaceIndex = 0; var viewStack = []; var hideStack = []; var viewStackPos = 0; let flashingTab; let flashingTabTimer; function addToViewStack(id) { if (viewStackPos !== viewStack.length) { viewStack.splice(viewStackPos); } viewStack.push(id); viewStackPos = viewStack.length; } function removeFromHideStack(id) { hideStack = hideStack.filter(function(v) { if (v === id) { return false; } else if (Array.isArray(v)) { var i = v.indexOf(id); if (i > -1) { v.splice(i,1); } if (v.length === 0) { return false; } return true } return true; }) } function addWorkspace(ws,skipHistoryEntry,targetIndex) { if (ws) { if (!ws.closeable) { ws.hideable = true; } if (!ws.hasOwnProperty('locked')) { ws.locked = false } workspace_tabs.addTab(ws,targetIndex); var hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}"); if (hiddenTabs[ws.id]) { workspace_tabs.hideTab(ws.id); } workspace_tabs.resize(); } else { var tabId = RED.nodes.id(); do { workspaceIndex += 1; } while ($("#red-ui-workspace-tabs li[flowname='"+RED._('workspace.defaultName',{number:workspaceIndex})+"']").size() !== 0); ws = { type: "tab", id: tabId, disabled: false, locked: false, info: "", label: RED._('workspace.defaultName',{number:workspaceIndex}), env: [], hideable: true, }; if (!skipHistoryEntry) { ws.added = true } RED.nodes.addWorkspace(ws,targetIndex); workspace_tabs.addTab(ws,targetIndex); workspace_tabs.activateTab(tabId); if (!skipHistoryEntry) { RED.history.push({t:'add',workspaces:[ws],dirty:RED.nodes.dirty()}); RED.nodes.dirty(true); } } $("#red-ui-tab-"+(ws.id.replace(".","-"))).attr("flowname",ws.label).toggleClass('red-ui-workspace-changed',!!(ws.contentsChanged || ws.changed || ws.added)); RED.view.focus(); return ws; } function deleteWorkspace(ws) { if (workspaceTabCount === 1) { return; } if (ws.locked) { return } var workspaceOrder = RED.nodes.getWorkspaceOrder(); ws._index = workspaceOrder.indexOf(ws.id); removeWorkspace(ws); var historyEvent = RED.nodes.removeWorkspace(ws.id); historyEvent.t = 'delete'; historyEvent.dirty = RED.nodes.dirty(); historyEvent.workspaces = [ws]; RED.history.push(historyEvent); RED.nodes.dirty(true); RED.sidebar.config.refresh(); } function showEditWorkspaceDialog(id) { var workspace = RED.nodes.workspace(id); if (!workspace) { var subflow = RED.nodes.subflow(id); if (subflow) { RED.editor.editSubflow(subflow); } } else { if (!workspace.locked) { RED.editor.editFlow(workspace); } } } var workspace_tabs; var workspaceTabCount = 0; function getMenuItems(isMenuButton, tab) { let hiddenFlows = new Set() for (let i = 0; i < hideStack.length; i++) { let ids = hideStack[i] if (!Array.isArray(ids)) { ids = [ids] } ids.forEach(id => { if (RED.nodes.workspace(id)) { hiddenFlows.add(id) } }) } const hiddenflowCount = hiddenFlows.size; let activeWorkspace = tab || RED.nodes.workspace(RED.workspaces.active()) || RED.nodes.subflow(RED.workspaces.active()) let isFlowDisabled = activeWorkspace ? activeWorkspace.disabled : false const currentTabs = workspace_tabs.listTabs(); let flowCount = 0; currentTabs.forEach(tab => { if (RED.nodes.workspace(tab)) { flowCount++; } }); let isCurrentLocked = RED.workspaces.isLocked() if (tab) { isCurrentLocked = tab.locked } var menuItems = [] if (isMenuButton) { menuItems.push({ id:"red-ui-tabs-menu-option-search-flows", label: RED._("workspace.listFlows"), onselect: "core:list-flows" }, { id:"red-ui-tabs-menu-option-search-subflows", label: RED._("workspace.listSubflows"), onselect: "core:list-subflows" }, null) } menuItems.push( { id:"red-ui-tabs-menu-option-add-flow", label: RED._("workspace.addFlow"), onselect: "core:add-flow" } ) if (isMenuButton || !!tab) { menuItems.push( { id:"red-ui-tabs-menu-option-add-flow-right", label: RED._("workspace.addFlowToRight"), shortcut: RED.keyboard.getShortcut("core:add-flow-to-right"), onselect: function() { RED.actions.invoke("core:add-flow-to-right", tab) } }, null ) if (activeWorkspace && activeWorkspace.type === 'tab') { menuItems.push( isFlowDisabled ? { label: RED._("workspace.enableFlow"), shortcut: RED.keyboard.getShortcut("core:enable-flow"), onselect: function() { RED.actions.invoke("core:enable-flow", tab?tab.id:undefined) }, disabled: isCurrentLocked } : { label: RED._("workspace.disableFlow"), shortcut: RED.keyboard.getShortcut("core:disable-flow"), onselect: function() { RED.actions.invoke("core:disable-flow", tab?tab.id:undefined) }, disabled: isCurrentLocked }, isCurrentLocked? { label: RED._("workspace.unlockFlow"), shortcut: RED.keyboard.getShortcut("core:unlock-flow"), onselect: function() { RED.actions.invoke('core:unlock-flow', tab?tab.id:undefined) } } : { label: RED._("workspace.lockFlow"), shortcut: RED.keyboard.getShortcut("core:lock-flow"), onselect: function() { RED.actions.invoke('core:lock-flow', tab?tab.id:undefined) } }, null ) } const activeIndex = currentTabs.findIndex(id => (activeWorkspace && (id === activeWorkspace.id))); menuItems.push( { label: RED._("workspace.moveToStart"), shortcut: RED.keyboard.getShortcut("core:move-flow-to-start"), onselect: function() { RED.actions.invoke("core:move-flow-to-start", tab?tab.id:undefined) }, disabled: activeIndex === 0 }, { label: RED._("workspace.moveToEnd"), shortcut: RED.keyboard.getShortcut("core:move-flow-to-end"), onselect: function() { RED.actions.invoke("core:move-flow-to-end", tab?tab.id:undefined) }, disabled: activeIndex === currentTabs.length - 1 } ) } menuItems.push(null) if (isMenuButton || !!tab) { menuItems.push( { id:"red-ui-tabs-menu-option-add-hide-flows", label: RED._("workspace.hideFlow"), shortcut: RED.keyboard.getShortcut("core:hide-flow"), onselect: function() { RED.actions.invoke("core:hide-flow", tab) } }, { id:"red-ui-tabs-menu-option-add-hide-other-flows", label: RED._("workspace.hideOtherFlows"), shortcut: RED.keyboard.getShortcut("core:hide-other-flows"), onselect: function() { RED.actions.invoke("core:hide-other-flows", tab) } } ) } menuItems.push( { id:"red-ui-tabs-menu-option-add-hide-all-flows", label: RED._("workspace.hideAllFlows"), onselect: "core:hide-all-flows", disabled: (hiddenflowCount === flowCount) }, { id:"red-ui-tabs-menu-option-add-show-all-flows", disabled: hiddenflowCount === 0, label: RED._("workspace.showAllFlows", { count: hiddenflowCount }), onselect: "core:show-all-flows" }, { id:"red-ui-tabs-menu-option-add-show-last-flow", disabled: hideStack.length === 0, label: RED._("workspace.showLastHiddenFlow"), onselect: "core:show-last-hidden-flow" } ) if (tab) { menuItems.push( null, { label: RED._("common.label.delete"), onselect: function() { if (tab.type === 'tab') { RED.workspaces.delete(tab) } else if (tab.type === 'subflow') { RED.subflow.delete(tab.id) } }, disabled: isCurrentLocked || (workspaceTabCount === 1) }, { label: RED._("menu.label.export"), shortcut: RED.keyboard.getShortcut("core:show-export-dialog"), onselect: function() { RED.workspaces.show(tab.id) RED.actions.invoke('core:show-export-dialog', null, 'flow') } } ) } // if (isMenuButton && hiddenflowCount > 0) { // menuItems.unshift({ // label: RED._("workspace.hiddenFlows",{count: hiddenflowCount}), // onselect: "core:list-hidden-flows" // }) // } return menuItems; } function createWorkspaceTabs() { workspace_tabs = RED.tabs.create({ id: "red-ui-workspace-tabs", onchange: function(tab) { var event = { old: activeWorkspace } if (tab) { $("#red-ui-workspace-chart").show(); activeWorkspace = tab.id; window.location.hash = 'flow/'+tab.id; $("#red-ui-workspace").toggleClass("red-ui-workspace-disabled", !!tab.disabled); $("#red-ui-workspace").toggleClass("red-ui-workspace-locked", !!tab.locked); } else { $("#red-ui-workspace-chart").hide(); activeWorkspace = 0; window.location.hash = ''; } event.workspace = activeWorkspace; RED.events.emit("workspace:change",event); RED.sidebar.config.refresh(); RED.view.focus(); }, onclick: function(tab) { if (tab.id !== activeWorkspace) { addToViewStack(activeWorkspace); } RED.view.focus(); }, ondblclick: function(tab) { if (tab.type != "subflow") { showEditWorkspaceDialog(tab.id); } else { RED.editor.editSubflow(RED.nodes.subflow(tab.id)); } }, onadd: function(tab) { if (tab.type === "tab") { workspaceTabCount++; } $(' ').prependTo("#red-ui-tab-"+(tab.id.replace(".","-"))+" .red-ui-tab-label"); if (tab.disabled) { $("#red-ui-tab-"+(tab.id.replace(".","-"))).addClass('red-ui-workspace-disabled'); } $(' ').prependTo("#red-ui-tab-"+(tab.id.replace(".","-"))+" .red-ui-tab-label"); if (tab.locked) { $("#red-ui-tab-"+(tab.id.replace(".","-"))).addClass('red-ui-workspace-locked'); } const changeBadgeContainer = $('').appendTo("#red-ui-tab-"+(tab.id.replace(".","-"))) const changeBadge = document.createElementNS("http://www.w3.org/2000/svg","circle"); changeBadge.setAttribute("cx",5); changeBadge.setAttribute("cy",5); changeBadge.setAttribute("r",5); changeBadgeContainer.append(changeBadge) RED.menu.setDisabled("menu-item-workspace-delete",activeWorkspace === 0 || workspaceTabCount <= 1); if (workspaceTabCount === 1) { showWorkspace(); } }, onremove: function(tab) { if (tab.type === "tab") { workspaceTabCount--; } else { hideStack.push(tab.id); } RED.menu.setDisabled("menu-item-workspace-delete",activeWorkspace === 0 || workspaceTabCount <= 1); if (workspaceTabCount === 0) { hideWorkspace(); } }, onreorder: function(oldOrder, newOrder) { RED.history.push({ t:'reorder', workspaces: { from: oldOrder, to: newOrder }, dirty:RED.nodes.dirty() }); // Only mark flows dirty if flow-order has changed (excluding subflows) const filteredOldOrder = oldOrder.filter(id => !!RED.nodes.workspace(id)) const filteredNewOrder = newOrder.filter(id => !!RED.nodes.workspace(id)) if (JSON.stringify(filteredOldOrder) !== JSON.stringify(filteredNewOrder)) { RED.nodes.dirty(true); setWorkspaceOrder(newOrder); } }, onselect: function(selectedTabs) { RED.view.select(false) if (selectedTabs.length === 0) { $("#red-ui-workspace-chart svg").css({"pointer-events":"auto",filter:"none"}) $("#red-ui-workspace-toolbar").css({"pointer-events":"auto",filter:"none"}) $("#red-ui-palette-container").css({"pointer-events":"auto",filter:"none"}) $(".red-ui-sidebar-shade").hide(); } else { RED.view.select(false) $("#red-ui-workspace-chart svg").css({"pointer-events":"none",filter:"opacity(60%)"}) $("#red-ui-workspace-toolbar").css({"pointer-events":"none",filter:"opacity(60%)"}) $("#red-ui-palette-container").css({"pointer-events":"none",filter:"opacity(60%)"}) $(".red-ui-sidebar-shade").show(); } }, onhide: function(tab) { hideStack.push(tab.id); if (tab.type === "tab") { var hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}"); hiddenTabs[tab.id] = true; RED.settings.setLocal("hiddenTabs",JSON.stringify(hiddenTabs)); RED.events.emit("workspace:hide",{workspace: tab.id}) } }, onshow: function(tab) { removeFromHideStack(tab.id); var hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}"); delete hiddenTabs[tab.id]; RED.settings.setLocal("hiddenTabs",JSON.stringify(hiddenTabs)); RED.events.emit("workspace:show",{workspace: tab.id}) }, minimumActiveTabWidth: 150, scrollable: true, addButton: "core:add-flow", addButtonCaption: RED._("workspace.addFlow"), menu: function() { return getMenuItems(true) }, contextmenu: function(tab) { return getMenuItems(false, tab) } }); workspaceTabCount = 0; } function showWorkspace() { $("#red-ui-workspace .red-ui-tabs").show() $("#red-ui-workspace-chart").show() $("#red-ui-workspace-footer").children().show() } function hideWorkspace() { $("#red-ui-workspace .red-ui-tabs").hide() $("#red-ui-workspace-chart").hide() $("#red-ui-workspace-footer").children().hide() } function init() { $('').appendTo("#red-ui-workspace"); $('
').appendTo("#red-ui-workspace"); $('
').appendTo("#red-ui-workspace"); $('
').appendTo("#red-ui-workspace"); $('').appendTo("#red-ui-workspace"); $('
').appendTo("#red-ui-workspace"); createWorkspaceTabs(); RED.events.on("sidebar:resize",workspace_tabs.resize); RED.actions.add("core:show-next-tab",function() { var oldActive = activeWorkspace; workspace_tabs.nextTab(); if (oldActive !== activeWorkspace) { addToViewStack(oldActive) } }); RED.actions.add("core:show-previous-tab",function() { var oldActive = activeWorkspace; workspace_tabs.previousTab(); if (oldActive !== activeWorkspace) { addToViewStack(oldActive) } }); RED.menu.setAction('menu-item-workspace-delete',function() { deleteWorkspace(RED.nodes.workspace(activeWorkspace)); }); $(window).on("resize", function() { workspace_tabs.resize(); }); RED.actions.add("core:add-flow",function(opts) { addWorkspace(undefined,undefined,opts?opts.index:undefined)}); RED.actions.add("core:add-flow-to-right",function(workspace) { let index if (workspace) { index = workspace_tabs.getTabIndex(workspace.id)+1 } else { index = workspace_tabs.activeIndex()+1 } addWorkspace(undefined,undefined,index) }); RED.actions.add("core:edit-flow",editWorkspace); RED.actions.add("core:remove-flow",removeWorkspace); RED.actions.add("core:enable-flow",enableWorkspace); RED.actions.add("core:disable-flow",disableWorkspace); RED.actions.add("core:lock-flow",lockWorkspace); RED.actions.add("core:unlock-flow",unlockWorkspace); RED.actions.add("core:move-flow-to-start", function(id) { moveWorkspace(id, 'start') }); RED.actions.add("core:move-flow-to-end", function(id) { moveWorkspace(id, 'end') }); RED.actions.add("core:hide-flow", function(workspace) { let selection if (workspace) { selection = [workspace] } else { selection = workspace_tabs.selection(); if (selection.length === 0) { selection = [{id:activeWorkspace}] } } var hiddenTabs = []; selection.forEach(function(ws) { RED.workspaces.hide(ws.id); hideStack.pop(); hiddenTabs.push(ws.id); }) if (hiddenTabs.length > 0) { hideStack.push(hiddenTabs); } workspace_tabs.clearSelection(); }) RED.actions.add("core:hide-other-flows", function(workspace) { let selection if (workspace) { selection = [workspace] } else { selection = workspace_tabs.selection(); if (selection.length === 0) { selection = [{id:activeWorkspace}] } } var selected = new Set(selection.map(function(ws) { return ws.id })) var currentTabs = workspace_tabs.listTabs(); var hiddenTabs = []; currentTabs.forEach(function(id) { if (!selected.has(id)) { RED.workspaces.hide(id); hideStack.pop(); hiddenTabs.push(id); } }) if (hiddenTabs.length > 0) { hideStack.push(hiddenTabs); } }) RED.actions.add("core:hide-all-flows", function() { var currentTabs = workspace_tabs.listTabs(); currentTabs.forEach(function(id) { RED.workspaces.hide(id); hideStack.pop(); }) if (currentTabs.length > 0) { hideStack.push(currentTabs); } workspace_tabs.clearSelection(); }) RED.actions.add("core:show-all-flows", function() { var currentTabs = workspace_tabs.listTabs(); currentTabs.forEach(function(id) { RED.workspaces.show(id, null, true) }) }) // RED.actions.add("core:toggle-flows", function() { // var currentTabs = workspace_tabs.listTabs(); // var visibleCount = workspace_tabs.count(); // currentTabs.forEach(function(id) { // if (visibleCount === 0) { // RED.workspaces.show(id) // } else { // RED.workspaces.hide(id) // } // }) // }) RED.actions.add("core:show-last-hidden-flow", function() { var id = hideStack.pop(); if (id) { if (typeof id === 'string') { RED.workspaces.show(id); } else { var last = id.pop(); id.forEach(function(i) { RED.workspaces.show(i, null, true); }) setTimeout(function() { RED.workspaces.show(last); },150) } } }) RED.actions.add("core:list-modified-nodes",function() { RED.actions.invoke("core:search","is:modified "); }) RED.actions.add("core:list-hidden-flows",function() { RED.actions.invoke("core:search","is:hidden "); }) RED.actions.add("core:list-flows",function() { RED.actions.invoke("core:search","type:tab "); }) RED.actions.add("core:list-subflows",function() { RED.actions.invoke("core:search","type:subflow "); }) RED.actions.add("core:go-to-previous-location", function() { if (viewStackPos > 0) { if (viewStackPos === viewStack.length) { // We're at the end of the stack. Remember the activeWorkspace // so we can come back to it. viewStack.push(activeWorkspace); } RED.workspaces.show(viewStack[--viewStackPos],true); } }) RED.actions.add("core:go-to-next-location", function() { if (viewStackPos < viewStack.length - 1) { RED.workspaces.show(viewStack[++viewStackPos],true); } }) RED.events.on("flows:change", (ws) => { $("#red-ui-tab-"+(ws.id.replace(".","-"))).toggleClass('red-ui-workspace-changed',!!(ws.contentsChanged || ws.changed || ws.added)); }) hideWorkspace(); } function editWorkspace(id) { showEditWorkspaceDialog(id||activeWorkspace); } function enableWorkspace(id) { setWorkspaceState(id,false); } function disableWorkspace(id) { setWorkspaceState(id,true); } function setWorkspaceState(id,disabled) { var workspace = RED.nodes.workspace(id||activeWorkspace); if (!workspace || workspace.locked) { return; } if (workspace.disabled !== disabled) { var changes = { disabled: workspace.disabled }; workspace.disabled = disabled; $("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!workspace.disabled); if (!id || (id === activeWorkspace)) { $("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!workspace.disabled); } var historyEvent = { t: "edit", changes:changes, node: workspace, dirty: RED.nodes.dirty() } workspace.changed = true; RED.history.push(historyEvent); RED.events.emit("flows:change",workspace); RED.nodes.dirty(true); RED.sidebar.config.refresh(); var selection = RED.view.selection(); if (!selection.nodes && !selection.links && workspace.id === activeWorkspace) { RED.sidebar.info.refresh(workspace); } if (changes.hasOwnProperty('disabled')) { RED.nodes.eachNode(function(n) { if (n.z === workspace.id) { n.dirty = true; } }); RED.view.redraw(); } } } function lockWorkspace(id) { setWorkspaceLockState(id,true); } function unlockWorkspace(id) { setWorkspaceLockState(id,false); } function setWorkspaceLockState(id,locked) { var workspace = RED.nodes.workspace(id||activeWorkspace); if (!workspace) { return; } if (workspace.locked !== locked) { var changes = { locked: workspace.locked }; workspace.locked = locked; $("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-locked',!!workspace.locked); if (!id || (id === activeWorkspace)) { $("#red-ui-workspace").toggleClass("red-ui-workspace-locked",!!workspace.locked); } var historyEvent = { t: "edit", changes:changes, node: workspace, dirty: RED.nodes.dirty() } workspace.changed = true; RED.history.push(historyEvent); RED.events.emit("flows:change",workspace); RED.nodes.dirty(true); RED.nodes.filterNodes({z:workspace.id}).forEach(n => n.dirty = true) RED.view.redraw(true); } } function removeWorkspace(ws) { if (!ws) { ws = RED.nodes.workspace(activeWorkspace) if (ws && !ws.locked) { deleteWorkspace(RED.nodes.workspace(activeWorkspace)); } } else { if (ws.locked) { return } if (workspace_tabs.contains(ws.id)) { workspace_tabs.removeTab(ws.id); } if (ws.id === activeWorkspace) { activeWorkspace = 0; } } } function moveWorkspace(id, direction) { const workspace = RED.nodes.workspace(id||activeWorkspace) || RED.nodes.subflow(id||activeWorkspace); if (!workspace) { return; } const currentOrder = workspace_tabs.listTabs() const oldOrder = [...currentOrder] const currentIndex = currentOrder.findIndex(id => id === workspace.id) currentOrder.splice(currentIndex, 1) if (direction === 'start') { currentOrder.unshift(workspace.id) } else if (direction === 'end') { currentOrder.push(workspace.id) } const newOrder = setWorkspaceOrder(currentOrder) if (JSON.stringify(newOrder) !== JSON.stringify(oldOrder)) { RED.history.push({ t:'reorder', workspaces: { from:oldOrder, to:newOrder }, dirty:RED.nodes.dirty() }); const filteredOldOrder = oldOrder.filter(id => !!RED.nodes.workspace(id)) const filteredNewOrder = newOrder.filter(id => !!RED.nodes.workspace(id)) if (JSON.stringify(filteredOldOrder) !== JSON.stringify(filteredNewOrder)) { RED.nodes.dirty(true); } } } function setWorkspaceOrder(order) { var newOrder = order.filter(id => !!RED.nodes.workspace(id)) var currentOrder = RED.nodes.getWorkspaceOrder(); if (JSON.stringify(newOrder) !== JSON.stringify(currentOrder)) { RED.nodes.setWorkspaceOrder(newOrder); RED.events.emit("flows:reorder",newOrder); } workspace_tabs.order(order); return newOrder } function flashTab(tabId) { if(flashingTab && flashingTab.length) { //cancel current flashing node before flashing new node clearInterval(flashingTabTimer); flashingTabTimer = null; flashingTab.removeClass('highlighted'); flashingTab = null; } let tab = $("#red-ui-tab-" + tabId); if(!tab || !tab.length) { return; } flashingTabTimer = setInterval(function(flashEndTime) { if (flashEndTime >= Date.now()) { const highlighted = tab.hasClass("highlighted"); tab.toggleClass('highlighted', !highlighted) } else { clearInterval(flashingTabTimer); flashingTabTimer = null; flashingTab = null; tab.removeClass('highlighted'); } }, 100, Date.now() + 2200); flashingTab = tab; tab.addClass('highlighted'); } return { init: init, add: addWorkspace, // remove: remove workspace without editor history etc remove: removeWorkspace, // delete: remove workspace and update editor history delete: deleteWorkspace, order: setWorkspaceOrder, edit: editWorkspace, contains: function(id) { return workspace_tabs.contains(id); }, count: function() { return workspaceTabCount; }, active: function() { return activeWorkspace }, isLocked: function(id) { id = id || activeWorkspace var ws = RED.nodes.workspace(id) || RED.nodes.subflow(id) return ws && ws.locked }, selection: function() { return workspace_tabs.selection(); }, hide: function(id) { if (!id) { id = activeWorkspace; } if (workspace_tabs.contains(id)) { workspace_tabs.hideTab(id); } }, isHidden: function(id) { return hideStack.includes(id) }, show: function(id,skipStack,unhideOnly,flash) { if (!workspace_tabs.contains(id)) { var sf = RED.nodes.subflow(id); if (sf) { addWorkspace( {type:"subflow",id:id,icon:"red/images/subflow_tab.svg",label:sf.name, closeable: true}, null, workspace_tabs.activeIndex()+1 ); removeFromHideStack(id); } else { return; } } if (unhideOnly) { workspace_tabs.showTab(id); } else { if (!skipStack && activeWorkspace !== id) { addToViewStack(activeWorkspace) } workspace_tabs.activateTab(id); } if(flash) { flashTab(id.replace(".","-")) } }, refresh: function() { RED.nodes.eachWorkspace(function(ws) { workspace_tabs.renameTab(ws.id,ws.label); $("#red-ui-tab-"+(ws.id.replace(".","-"))).attr("flowname",ws.label) }) RED.nodes.eachSubflow(function(sf) { if (workspace_tabs.contains(sf.id)) { workspace_tabs.renameTab(sf.id,sf.name); } }); RED.sidebar.config.refresh(); }, resize: function() { workspace_tabs.resize(); }, enable: enableWorkspace, disable: disableWorkspace, lock: lockWorkspace, unlock: unlockWorkspace } })();