diff --git a/src/Extensions/Components/BootstrapBlazor.DockView/BootstrapBlazor.DockView.csproj b/src/Extensions/Components/BootstrapBlazor.DockView/BootstrapBlazor.DockView.csproj index 85fd06081b4..3b4bbdbb1f7 100644 --- a/src/Extensions/Components/BootstrapBlazor.DockView/BootstrapBlazor.DockView.csproj +++ b/src/Extensions/Components/BootstrapBlazor.DockView/BootstrapBlazor.DockView.csproj @@ -1,7 +1,7 @@ - 8.0.6 + 8.0.7 diff --git a/src/Extensions/Components/BootstrapBlazor.DockView/wwwroot/js/dockview-config.js b/src/Extensions/Components/BootstrapBlazor.DockView/wwwroot/js/dockview-config.js index b688f205351..19e03cb97b9 100644 --- a/src/Extensions/Components/BootstrapBlazor.DockView/wwwroot/js/dockview-config.js +++ b/src/Extensions/Components/BootstrapBlazor.DockView/wwwroot/js/dockview-config.js @@ -47,23 +47,24 @@ const getConfigFromLayoutString = options => { } const renewConfigFromOptions = (config, options) => { + removeEmptyGridViews(config, options) const optionPanels = getPanelsFromOptions(options) const localPanels = Object.values(config.panels) - optionPanels.forEach(optionPanel => {// 在结构中添加 + optionPanels.forEach(optionPanel => { const panel = localPanels.find(localPanel => localPanel.params.key == optionPanel.params.key) - if(panel){//找到了就替换数据 + if (panel) { optionPanel.params = { ...panel.params, ...optionPanel.params } config.panels[panel.id] = optionPanel } - else {// 本地没有Panel就需要添加 + else { const delPanels = JSON.parse(localStorage.getItem(options.localStorageKey + '-panels')) - if(delPanels?.find(delPanel => delPanel.params.key == optionPanel.params.key)) return + if (delPanels?.find(delPanel => delPanel.params.key == optionPanel.params.key)) return let index = optionPanels.findIndex(item => item.id == optionPanel.id) let brotherPanel, brotherType - if(index == 0){ + if (index == 0) { brotherPanel = optionPanels[1] brotherType = 'after' } @@ -73,67 +74,123 @@ const renewConfigFromOptions = (config, options) => { } config.panels[optionPanel.id] = optionPanel const brotherId = Object.keys(config.panels).find(key => config.panels[key].params.key == brotherPanel.params.key) - addPanel(config.grid.root, optionPanel, brotherPanel, brotherId, brotherType) - + const originFloatingGroupId = config.floatingGroups?.find(fg => fg.data.views.includes(brotherId))?.data.id.split('_')[0] + addPanel(config.grid.root, optionPanel, brotherPanel, brotherId, originFloatingGroupId) } }) localPanels.forEach(localPanel => { const panel = optionPanels.find(optionPanel => optionPanel.params.key == localPanel.params.key) - if(panel){ + if (panel) { } - else {// 在options里没有, 就需要在localPanels删除 - delete config.panels[localPanel.id] && config.panels[localPanel.id] - removePanel(config.grid.root, localPanel) + else { + delete config.panels[localPanel.id] && config.panels[localPanel.id] + if (config.floatingGroups + && config.floatingGroups.length > 0 + && config.floatingGroups.find(fg => fg.data.views.includes(localPanel.id)) + ) { + removeFloatingPanel(config, localPanel) + } + else { + removePanel(config.grid.root, localPanel) + } } }) return config } -const addPanel = (branch, panel, brotherPanel, brotherId, brotherType) => { - if(brotherPanel.params.parentType == 'group'){ - if(branch.type == 'leaf'){ - if(branch.data.views.includes(brotherId)){ +const removeFloatingPanel = (config, localPanel) => { + config.floatingGroups.forEach((fg, index) => { + fg.data.views = fg.data.views.filter(p => p.id !== localPanel.id) + }) + config.floatingGroups = config.floatingGroups.filter(fg => fg.data.views.lengt > 0) +} + +const removeEmptyGridViews = (config, options) => { + const delPanelsStr = localStorage.getItem(options.localStorageKey + '-panels') + const delPanels = delPanelsStr ? JSON.parse(delPanelsStr) : delPanelsStr + removeEmptyLeafViews(config.grid.root, config.floatingGroups || [], delPanels || []) +} +const removeEmptyLeafViews = (branch, floatingGroups, delPanels, parent) => { + if (branch.type == 'branch') { + branch.data.forEach(item => removeEmptyLeafViews(item, floatingGroups, delPanels, branch)) + } + else if (branch.type == 'leaf') { + if ( + branch.data.views.length == 0 + && !floatingGroups.find(fg => fg.data.id.split('_')[0] == branch.data.id) + && !delPanels.find(p => p.groupId == branch.data.id + '_floating') + ) { + parent && (parent.data = parent.data.filter(item => item.data.id != branch.data.id)) + } + } +} + +const addPanel = (branch, panel, brotherPanel, brotherId, originFloatingGroupId) => { + if (brotherPanel.params.parentType == 'group') { + if (branch.type == 'leaf') { + if (branch.data.views.includes(brotherId)) { branch.data.views.push(panel.id) } } - else if(branch.type == 'branch') { + else if (branch.type == 'branch') { branch.data.forEach(item => { - addPanel(item, panel, brotherPanel, brotherId) + addPanel(item, panel, brotherPanel, brotherId, originFloatingGroupId) }) } } - else { - if(branch.type == 'branch' && branch.data[0].type == 'leaf'){ - if(branch.data.find(leaf => leaf.data.views.includes(brotherId))){ - branch.data.push({ - data: { - activeView: panel.id, - id: Date.now() + '', - views: [panel.id] - }, - size: branch.data.reduce((pre, cur) => pre + cur.size, 0)/branch.data.length, - type: 'leaf' - }) - } + else if (branch.type == 'branch') { + + if (branch.data.length == 0) { + branch.data.push({ + data: { + activeView: panel.id, + id: Date.now() + Math.floor(Math.random() * 100) + '', + views: [panel.id] + }, + // size: branch.data.reduce((pre, cur) => pre + cur.size, 0)/branch.data.length, + type: 'leaf' + }) } else { - branch.data.forEach(item => { - addPanel(item, panel, brotherPanel, brotherId) + [...branch.data].forEach(item => { + if (item.type == 'leaf') { + if (item.data.views.includes(brotherId) || item.data.id == originFloatingGroupId) { + branch.data.push({ + data: { + activeView: panel.id, + id: Date.now() + Math.floor(Math.random() * 100) + '', + views: [panel.id] + }, + size: branch.data.reduce((pre, cur) => pre + cur.size, 0) / branch.data.length, + type: 'leaf' + }) + } + } + else { + addPanel(item, panel, brotherPanel, brotherId, originFloatingGroupId) + } }) } } } const removePanel = (branch, panel, parent) => { - if(branch.type == 'leaf'){ - branch.data.views = branch.data.views.filter(id => id != panel.id) - parent && (parent.data = parent.data.filter(child => child.data.views.length > 0)) + if (branch.type == 'leaf') { + if (branch.data.views.length > 0) { + branch.data.views = branch.data.views.filter(id => id != panel.id) + if (branch.data.views.length == 0) { + parent && (parent.data = parent.data.filter(child => child.data.id != branch.data.id)) + } + } } - else if(branch.type == 'branch') { + else if (branch.type == 'branch') { branch.data.forEach(item => { removePanel(item, panel, branch) }) + if (branch.data.length == 0) { + parent.data = parent.data.filter(b => !(b.type == 'branch' && b.data.length == 0)) + } } } diff --git a/src/Extensions/Components/BootstrapBlazor.DockView/wwwroot/js/dockview-group.js b/src/Extensions/Components/BootstrapBlazor.DockView/wwwroot/js/dockview-group.js index 5c8277bd9f8..4944ba35bf0 100644 --- a/src/Extensions/Components/BootstrapBlazor.DockView/wwwroot/js/dockview-group.js +++ b/src/Extensions/Components/BootstrapBlazor.DockView/wwwroot/js/dockview-group.js @@ -36,7 +36,7 @@ const addGroupWithPanel = (dockview, panel, panels, index) => { const addPanelWidthGroupId = (dockview, panel, index) => { let group = dockview.api.getGroup(panel.groupId) - let { position = {}, currentPosition, height, isPackup, isMaximized } = panel.params || {} + let { position = {}, currentPosition, packupHeight, isPackup, isMaximized } = panel.params || {} if (!group) { group = dockview.createGroup({ id: panel.groupId }) const floatingGroupPosition = isMaximized ? { @@ -66,13 +66,13 @@ const addPanelWidthGroupId = (dockview, panel, index) => { title: panel.title, component: panel.component, position: { referenceGroup: group, index: index || 0 }, - params: { ...panel.params, isPackup, height, isMaximized, position } + params: { ...panel.params, isPackup, packupHeight, isMaximized, position } }) dockview._panelVisibleChanged?.fire({ title: panel.title, status: true }); } const addPanelWidthCreatGroup = (dockview, panel, panels) => { - let { position = {}, currentPosition, height, isPackup, isMaximized } = panel.params || {} + let { position = {}, currentPosition, packupHeight, isPackup, isMaximized } = panel.params || {} let brothers = panels.filter(p => p.params.parentId == panel.params.parentId && p.id != panel.id) let group, direction if (brothers.length > 0 && brothers[0].params.parentType == 'group') { @@ -102,7 +102,7 @@ const addPanelWidthCreatGroup = (dockview, panel, panels) => { title: panel.title, component: panel.component, position: { referenceGroup: group }, - params: { ...panel.params, isPackup, height, isMaximized, position } + params: { ...panel.params, isPackup, packupHeight, isMaximized, position } } if (direction) option.position.direction = direction dockview.addPanel(option); @@ -141,14 +141,6 @@ const createGroupActions = group => { resetActionStates(group, actionContainer); }, 0) addActionEvent(group, actionContainer); - - // const dockview = group.api.accessor; - // if (dockview.params.observer === null) { - // dockview.params.observer = new ResizeObserver(setWidth); - // } - // dockview.params.observer.observe(group.header.element) - // dockview.params.observer.observe(group.header.tabContainer) - } const disposeGroup = group => { @@ -177,6 +169,9 @@ const resetActionStates = (group, actionContainer) => { actionContainer.classList.add('bb-float'); } } + if (showUp(group) && getUpState(group)) { + actionContainer.classList.add('bb-up') + } } const showLock = (dockview, group) => { @@ -192,7 +187,12 @@ const getLockState = (dockview, group) => { ? options.isLock : group.panels.some(p => p.params.isLock === true); } - +const showUp = (group) => { + return group.model.location.type == 'floating' +} +const getUpState = (group) => { + return group.panels.some(p => p.params.isPackup) +} const showMaximize = (dockview, group) => { const { options } = dockview.params; return group.panels.every(p => p.params.showMaximize === null) @@ -249,13 +249,7 @@ const addActionEvent = group => { close(group, actionContainer, true); } else if (e.target.classList.contains('dv-default-tab-content')) { - // const liEle = e.target.closest('li'); - // const tabEle = tabsContainer.children[0] - // liEle.tabWidth = tabEle.offsetWidth; - - // liEle.children[0].appendChild(tabEle); const targetTabEle = e.target.closest('.tab') - // tabsContainer.append(targetTabEle); group.api.accessor.moveGroupOrPanel({ from: { groupId: group.id, panelId: group.panels.find(p => p.view.tab.element.parentElement == targetTabEle).id }, to: { @@ -308,7 +302,7 @@ const float = group => { const gridGroups = dockview.groups.filter(group => group.panels.length > 0 && group.type === 'grid') if (gridGroups.length <= 1) return; - const { position = {}, isPackup, height, isMaximized } = group.getParams() + const { position = {} } = group.getParams() const floatingGroupPosition = { x: position.left || (x < 35 ? 35 : x), y: position.top || (y < 35 ? 35 : y), @@ -333,16 +327,15 @@ const float = group => { const dock = group => { if (group.locked) return; - const dockview = group.api.accessor const originGroup = dockview.groups.find(item => `${item.id}_floating` === group.id) dockview.setVisible(originGroup, true) - let { isPackup, height, isMaximized, position } = group.getParams() + let { isPackup, packupHeight, isMaximized, position } = group.getParams() if (!isMaximized) { position = { - width: group.width, - height: group.height, + width: group.element.parentElement.offsetWidth, + height: group.element.parentElement.offsetHeight, top: parseFloat(group.element.parentElement.style.top || 0), left: parseFloat(group.element.parentElement.style.left || 0) } @@ -352,22 +345,24 @@ const dock = group => { to: { group: originGroup, position: 'center' } }) - originGroup.setParams({ position, isPackup, height, isMaximized }) + originGroup.setParams({ position, isPackup, packupHeight, isMaximized }) + saveConfig(dockview) } const down = (group, actionContainer) => { const parentEle = group.element.parentElement - const { isPackup, height } = group.getParams(); + const { isPackup, packupHeight } = group.getParams(); if (isPackup) { group.setParams({ 'isPackup': false }) - parentEle.style.height = `${height}px`; + parentEle.style.height = `${packupHeight}px`; actionContainer.classList.remove('bb-up') } else { - group.setParams({ 'isPackup': true, 'height': parseFloat(parentEle.style.height) }); - parentEle.style.height = `${group.activePanel.view._tab._element.offsetHeight}px`; + group.setParams({ 'isPackup': true, 'packupHeight': parseFloat(parentEle.style.height) }); + parentEle.style.height = `${group.activePanel.view.tab.element.offsetHeight + 2}px`; actionContainer.classList.add('bb-up'); } + saveConfig(group.api.accessor) } close = group => { diff --git a/src/Extensions/Components/BootstrapBlazor.DockView/wwwroot/js/dockview-panel.js b/src/Extensions/Components/BootstrapBlazor.DockView/wwwroot/js/dockview-panel.js index 5a0deb4af5c..eb6740b7f27 100644 --- a/src/Extensions/Components/BootstrapBlazor.DockView/wwwroot/js/dockview-panel.js +++ b/src/Extensions/Components/BootstrapBlazor.DockView/wwwroot/js/dockview-panel.js @@ -4,8 +4,8 @@ import { getIcon } from "./dockview-icon.js" const onAddPanel = panel => { updateCloseButton(panel); updateTitle(panel); - panel.api.onDidActiveChange(({isActive}) => { - if(isActive && panel.group.panels.length > 1) { + panel.api.onDidActiveChange(({ isActive }) => { + if (isActive && panel.group.panels.length > 1) { saveConfig(panel.accessor) } }) @@ -29,10 +29,6 @@ const onRemovePanel = event => { index: event.group.delPanelIndex } } - - // if (event.params.groupInvisible) { - // panel.groupInvisible = event.params.groupInvisible - // } savePanel(dockview, panel) if (event.group.children) { diff --git a/src/Extensions/Components/BootstrapBlazor.DockView/wwwroot/js/dockview-utils.js b/src/Extensions/Components/BootstrapBlazor.DockView/wwwroot/js/dockview-utils.js index 33902937100..32a5d3d21cf 100644 --- a/src/Extensions/Components/BootstrapBlazor.DockView/wwwroot/js/dockview-utils.js +++ b/src/Extensions/Components/BootstrapBlazor.DockView/wwwroot/js/dockview-utils.js @@ -1,6 +1,6 @@ import { DockviewComponent } from "./dockview-core.esm.js" import { DockviewPanelContent } from "./dockview-content.js" -import { onAddGroup, addGroupWithPanel, toggleLock, disposeGroup } from "./dockview-group.js" +import { onAddGroup, addGroupWithPanel, toggleLock } from "./dockview-group.js" import { onAddPanel, onRemovePanel, getPanelsFromOptions, findContentFromPanels } from "./dockview-panel.js" import { getConfig, reloadFromConfig, loadPanelsFromLocalstorage, saveConfig } from './dockview-config.js' import './dockview-extensions.js' @@ -79,10 +79,8 @@ const initDockview = (dockview, options, template) => { floatingGroups.forEach(floatingGroup => { const group = dockview.groups.find(g => g.id == floatingGroup.data.id) if (!group) return - const { width, height, top, left } = floatingGroup.position + const { top, left } = floatingGroup.position const style = group.element.parentElement.style - style.width = width + 'px' - style.height = height + 'px' style.top = top + 'px' style.left = left + 'px' }) @@ -90,22 +88,21 @@ const initDockview = (dockview, options, template) => { dockview._inited = true; dockview._initialized?.fire() dockview.groups.forEach(group => { - // setWidth(group.model.header.element, dockview) if (dockview.params.observer === null) { dockview.params.observer = new ResizeObserver(observerList => resizeObserverHandle(observerList, dockview)); } dockview.params.observer.observe(group.header.element) dockview.params.observer.observe(group.header.tabContainer) for (let panel of group.panels) { - if(panel.params.isActive){ + if (panel.params.isActive) { panel.api.setActive() break } } }) - }, 0); + }, 100); }) - // 拖拽分割线后触发 + dockview.gridview.onDidChange(event => { dockview._groupSizeChanged.fire() saveConfig(dockview) @@ -132,7 +129,7 @@ const setWidth = (target, dockview) => { header = target tabsContainer = header.querySelector('.tabs-container') } - if(header.offsetWidth == 0) return + if (header.offsetWidth == 0) return let voidWidth = header.querySelector('.void-container').offsetWidth let dropdown = header.querySelector('.right-actions-container>.dropdown') if (!dropdown) return @@ -148,10 +145,6 @@ const setWidth = (target, dockview) => { aEle.append(lastTab) liEle.append(aEle) dropMenu.insertAdjacentElement("afterbegin", liEle) - // if(lastTab.classList.contains('active-tab')){ - // const group = dockview.groups.find(g => g.element === header.parentElement) - // group.panels[0].api.setActive() - // } } else { let firstLi = dropMenu.querySelector('li:has(.tab)') || dropMenu.children[0] @@ -164,11 +157,11 @@ const setWidth = (target, dockview) => { } } setTimeout(() => { - if([...tabsContainer.children].every(tab => !tab.classList.contains('active-tab'))){ + if ([...tabsContainer.children].every(tab => !tab.classList.contains('active-tab'))) { const group = dockview.groups.find(g => g.element === header.parentElement) group.panels[0].api.setActive() } - }, 100); + }, 0); } const toggleComponent = (dockview, options) => { @@ -180,7 +173,7 @@ const toggleComponent = (dockview, options) => { const panel = findContentFromPanels(dockview.params.panels, p); const groupPanels = panels.filter(p1 => p1.params.parentId == p.params.parentId) let indexOfOptions = groupPanels.findIndex(p => p.params.key == panel.params.key) - indexOfOptions = indexOfOptions == -1 ? 0 : indexOfOptions + indexOfOptions = indexOfOptions == -1 ? 0 : indexOfOptions const index = panel && panel.params.index addGroupWithPanel(dockview, panel || p, panels, index ?? indexOfOptions); }