mirror of
https://github.com/zen-browser/desktop.git
synced 2025-10-16 06:46:12 +00:00
feat: Added workspace rearrange inline with the icons, b=no-bug, c=workspaces, common
This commit is contained in:
@@ -1101,11 +1101,6 @@ var gZenWorkspaces = new (class extends ZenMultiWindowFeature {
|
||||
}
|
||||
|
||||
addPopupListeners() {
|
||||
const popup = document.getElementById('PanelUI-zen-workspaces');
|
||||
|
||||
popup.addEventListener('popuphidden', this.handlePanelHidden.bind(this));
|
||||
popup.addEventListener('command', this.handlePanelCommand.bind(this));
|
||||
|
||||
const workspaceActions = document.getElementById('zenWorkspaceMoreActions');
|
||||
workspaceActions.addEventListener('popupshowing', this.updateWorkspaceActionsMenu.bind(this));
|
||||
|
||||
@@ -1136,19 +1131,6 @@ var gZenWorkspaces = new (class extends ZenMultiWindowFeature {
|
||||
}
|
||||
}
|
||||
|
||||
handlePanelCommand(event) {
|
||||
let target = event.target.closest('toolbarbutton');
|
||||
target ??= event.target.closest('button');
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
switch (target.id) {
|
||||
case 'PanelUI-zen-workspaces-reorder-mode':
|
||||
this.toggleReorderMode();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
updateWorkspaceActionsMenuContainer(event) {
|
||||
const workspace = this.getActiveWorkspaceFromCache();
|
||||
let containerTabId = workspace.containerTabId;
|
||||
@@ -1227,208 +1209,6 @@ var gZenWorkspaces = new (class extends ZenMultiWindowFeature {
|
||||
}
|
||||
|
||||
async _propagateWorkspaceDataForWindow(browser, { ignoreStrip = false, clearCache = true } = {}) {
|
||||
let workspaceList = browser.document.getElementById('PanelUI-zen-workspaces-list');
|
||||
const createWorkspaceElement = (workspace) => {
|
||||
let element = browser.document.createXULElement('toolbarbutton');
|
||||
element.className = 'subviewbutton zen-workspace-button';
|
||||
element.setAttribute('tooltiptext', workspace.name);
|
||||
element.setAttribute('zen-workspace-id', workspace.uuid);
|
||||
if (this.isWorkspaceActive(workspace)) {
|
||||
element.setAttribute('active', 'true');
|
||||
}
|
||||
let containerGroup = undefined;
|
||||
try {
|
||||
containerGroup = browser.ContextualIdentityService.getPublicIdentities().find(
|
||||
(container) => container.userContextId === workspace.containerTabId
|
||||
);
|
||||
} catch (e) {
|
||||
console.warn('gZenWorkspaces: Error setting container color', e);
|
||||
}
|
||||
if (containerGroup) {
|
||||
element.classList.add('identity-color-' + containerGroup.color);
|
||||
element.setAttribute('data-usercontextid', containerGroup.userContextId);
|
||||
}
|
||||
// Set draggable attribute based on reorder mode
|
||||
if (this.isReorderModeOn(browser)) {
|
||||
element.setAttribute('draggable', 'true');
|
||||
}
|
||||
element.addEventListener(
|
||||
'dragstart',
|
||||
function (event) {
|
||||
if (this.isReorderModeOn(browser)) {
|
||||
this.draggedElement = element;
|
||||
event.dataTransfer.effectAllowed = 'move';
|
||||
event.dataTransfer.setData('text/plain', element.getAttribute('zen-workspace-id'));
|
||||
|
||||
// Create a transparent drag image for Linux
|
||||
if (AppConstants.platform === 'linux') {
|
||||
const dragImage = document.createElement('canvas');
|
||||
dragImage.width = 1;
|
||||
dragImage.height = 1;
|
||||
event.dataTransfer.setDragImage(dragImage, 0, 0);
|
||||
}
|
||||
|
||||
element.classList.add('dragging');
|
||||
} else {
|
||||
event.preventDefault();
|
||||
}
|
||||
}.bind(browser.gZenWorkspaces)
|
||||
);
|
||||
|
||||
element.addEventListener(
|
||||
'dragover',
|
||||
function (event) {
|
||||
if (this.isReorderModeOn(browser) && this.draggedElement) {
|
||||
event.preventDefault();
|
||||
event.dataTransfer.dropEffect = 'move';
|
||||
|
||||
// Ensure the dragover effect is visible on Linux
|
||||
if (AppConstants.platform === 'linux') {
|
||||
const targetId = element.getAttribute('zen-workspace-id');
|
||||
const draggedId = this.draggedElement.getAttribute('zen-workspace-id');
|
||||
if (targetId !== draggedId) {
|
||||
element.classList.add('dragover');
|
||||
}
|
||||
}
|
||||
}
|
||||
}.bind(browser.gZenWorkspaces)
|
||||
);
|
||||
|
||||
element.addEventListener('dragenter', function (event) {
|
||||
if (this.isReorderModeOn(browser) && this.draggedElement) {
|
||||
element.classList.add('dragover');
|
||||
}
|
||||
});
|
||||
|
||||
element.addEventListener('dragleave', function (event) {
|
||||
element.classList.remove('dragover');
|
||||
});
|
||||
|
||||
element.addEventListener(
|
||||
'drop',
|
||||
async function (event) {
|
||||
event.preventDefault();
|
||||
element.classList.remove('dragover');
|
||||
if (this.isReorderModeOn(browser)) {
|
||||
const draggedWorkspaceId = event.dataTransfer.getData('text/plain');
|
||||
const targetWorkspaceId = element.getAttribute('zen-workspace-id');
|
||||
if (draggedWorkspaceId !== targetWorkspaceId) {
|
||||
await this.moveWorkspace(draggedWorkspaceId, targetWorkspaceId);
|
||||
}
|
||||
if (this.draggedElement) {
|
||||
this.draggedElement.classList.remove('dragging');
|
||||
this.draggedElement = null;
|
||||
}
|
||||
}
|
||||
}.bind(browser.gZenWorkspaces)
|
||||
);
|
||||
|
||||
element.addEventListener(
|
||||
'dragend',
|
||||
function (event) {
|
||||
if (this.draggedElement) {
|
||||
this.draggedElement.classList.remove('dragging');
|
||||
this.draggedElement = null;
|
||||
}
|
||||
const workspaceElements = browser.document.querySelectorAll('.zen-workspace-button');
|
||||
for (const elem of workspaceElements) {
|
||||
elem.classList.remove('dragover');
|
||||
}
|
||||
}.bind(browser.gZenWorkspaces)
|
||||
);
|
||||
|
||||
let childs = browser.MozXULElement.parseXULToFragment(`
|
||||
<div class="zen-workspace-icon">
|
||||
</div>
|
||||
<vbox>
|
||||
<div class="zen-workspace-name">
|
||||
</div>
|
||||
<div class="zen-workspace-container" ${containerGroup ? '' : 'hidden="true"'}>
|
||||
</div>
|
||||
</vbox>
|
||||
<image class="toolbarbutton-icon zen-workspace-actions-reorder-icon" ></image>
|
||||
`);
|
||||
|
||||
// use text content instead of innerHTML to avoid XSS
|
||||
childs.querySelector('.zen-workspace-icon').textContent =
|
||||
browser.gZenWorkspaces.getWorkspaceIcon(workspace);
|
||||
childs.querySelector('.zen-workspace-name').textContent = workspace.name;
|
||||
if (containerGroup) {
|
||||
childs.querySelector('.zen-workspace-container').textContent =
|
||||
ContextualIdentityService.getUserContextLabel(containerGroup.userContextId);
|
||||
}
|
||||
|
||||
element.appendChild(childs);
|
||||
element.onclick = (async () => {
|
||||
if (this.isReorderModeOn(browser)) {
|
||||
return; // Return early if reorder mode is on
|
||||
}
|
||||
const workspaceId = element.getAttribute('zen-workspace-id');
|
||||
const workspaces = await this._workspaces();
|
||||
const workspace = workspaces.workspaces.find((w) => w.uuid === workspaceId);
|
||||
await this.changeWorkspace(workspace);
|
||||
let panel = this.ownerWindow.document.getElementById('PanelUI-zen-workspaces');
|
||||
PanelMultiView.hidePopup(panel);
|
||||
}).bind(browser.gZenWorkspaces);
|
||||
return element;
|
||||
};
|
||||
|
||||
const createLastPositionDropTarget = () => {
|
||||
const element = browser.document.createXULElement('div');
|
||||
element.className = 'zen-workspace-last-place-drop-target';
|
||||
|
||||
element.addEventListener(
|
||||
'dragover',
|
||||
function (event) {
|
||||
if (this.isReorderModeOn(browser) && this.draggedElement) {
|
||||
event.preventDefault();
|
||||
event.dataTransfer.dropEffect = 'move';
|
||||
|
||||
// Ensure the dragover effect is visible on Linux
|
||||
if (AppConstants.platform === 'linux') {
|
||||
element.classList.add('dragover');
|
||||
}
|
||||
}
|
||||
}.bind(browser.gZenWorkspaces)
|
||||
);
|
||||
|
||||
element.addEventListener(
|
||||
'dragenter',
|
||||
function (event) {
|
||||
if (this.isReorderModeOn(browser) && this.draggedElement) {
|
||||
element.classList.add('dragover');
|
||||
}
|
||||
}.bind(browser.gZenWorkspaces)
|
||||
);
|
||||
|
||||
element.addEventListener(
|
||||
'dragleave',
|
||||
function (event) {
|
||||
element.classList.remove('dragover');
|
||||
}.bind(browser.gZenWorkspaces)
|
||||
);
|
||||
|
||||
element.addEventListener(
|
||||
'drop',
|
||||
async function (event) {
|
||||
event.preventDefault();
|
||||
element.classList.remove('dragover');
|
||||
|
||||
if (this.isReorderModeOn(browser)) {
|
||||
const draggedWorkspaceId = event.dataTransfer.getData('text/plain');
|
||||
await this.moveWorkspaceToEnd(draggedWorkspaceId);
|
||||
|
||||
if (this.draggedElement) {
|
||||
this.draggedElement.classList.remove('dragging');
|
||||
this.draggedElement = null;
|
||||
}
|
||||
}
|
||||
}.bind(browser.gZenWorkspaces)
|
||||
);
|
||||
|
||||
return element;
|
||||
};
|
||||
|
||||
if (clearCache) {
|
||||
browser.gZenWorkspaces._workspaceCache = null;
|
||||
browser.gZenWorkspaces._workspaceBookmarksCache = null;
|
||||
@@ -1446,21 +1226,6 @@ var gZenWorkspaces = new (class extends ZenMultiWindowFeature {
|
||||
);
|
||||
}
|
||||
await browser.gZenWorkspaces.workspaceBookmarks();
|
||||
workspaceList.innerHTML = '';
|
||||
workspaceList.parentNode.style.display = 'flex';
|
||||
if (workspaces.workspaces.length <= 0) {
|
||||
workspaceList.innerHTML = 'No workspaces available';
|
||||
workspaceList.setAttribute('empty', 'true');
|
||||
} else {
|
||||
workspaceList.removeAttribute('empty');
|
||||
}
|
||||
|
||||
for (let workspace of workspaces.workspaces) {
|
||||
let workspaceElement = createWorkspaceElement(workspace);
|
||||
workspaceList.appendChild(workspaceElement);
|
||||
}
|
||||
|
||||
workspaceList.appendChild(createLastPositionDropTarget());
|
||||
if (!ignoreStrip) {
|
||||
browser.gZenWorkspaces._fixIndicatorsNames(workspaces);
|
||||
}
|
||||
@@ -1491,55 +1256,33 @@ var gZenWorkspaces = new (class extends ZenMultiWindowFeature {
|
||||
});
|
||||
}
|
||||
|
||||
handlePanelHidden() {
|
||||
const workspacesList = document.getElementById('PanelUI-zen-workspaces-list');
|
||||
const reorderModeButton = document.getElementById('PanelUI-zen-workspaces-reorder-mode');
|
||||
|
||||
workspacesList?.removeAttribute('reorder-mode');
|
||||
reorderModeButton?.removeAttribute('active');
|
||||
}
|
||||
|
||||
async moveWorkspaceToEnd(draggedWorkspaceId) {
|
||||
const workspaces = (await this._workspaces()).workspaces;
|
||||
const draggedIndex = workspaces.findIndex((w) => w.uuid === draggedWorkspaceId);
|
||||
const draggedWorkspace = workspaces.splice(draggedIndex, 1)[0];
|
||||
workspaces.push(draggedWorkspace);
|
||||
|
||||
await ZenWorkspacesStorage.updateWorkspacePositions(workspaces);
|
||||
await this._propagateWorkspaceData();
|
||||
}
|
||||
|
||||
isReorderModeOn(browser) {
|
||||
return (
|
||||
browser.document
|
||||
.getElementById('PanelUI-zen-workspaces-list')
|
||||
.getAttribute('reorder-mode') === 'true'
|
||||
);
|
||||
}
|
||||
|
||||
toggleReorderMode() {
|
||||
const workspacesList = document.getElementById('PanelUI-zen-workspaces-list');
|
||||
const reorderModeButton = document.getElementById('PanelUI-zen-workspaces-reorder-mode');
|
||||
const isActive = workspacesList.getAttribute('reorder-mode') === 'true';
|
||||
if (isActive) {
|
||||
workspacesList.removeAttribute('reorder-mode');
|
||||
reorderModeButton.removeAttribute('active');
|
||||
} else {
|
||||
workspacesList.setAttribute('reorder-mode', 'true');
|
||||
reorderModeButton.setAttribute('active', 'true');
|
||||
async reorderWorkspace(id, newPosition) {
|
||||
if (this.privateWindowOrDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update draggable attribute
|
||||
const workspaceElements = document.querySelectorAll('.zen-workspace-button');
|
||||
workspaceElements.forEach((elem) => {
|
||||
// When reorder mode is toggled off, remove draggable attribute
|
||||
// When reorder mode is toggled on, set draggable attribute
|
||||
if (isActive) {
|
||||
elem.removeAttribute('draggable');
|
||||
} else {
|
||||
elem.setAttribute('draggable', 'true');
|
||||
}
|
||||
});
|
||||
const workspaces = (await this._workspaces()).workspaces;
|
||||
const workspace = workspaces.find((w) => w.uuid === id);
|
||||
if (!workspace) {
|
||||
console.warn(`Workspace with ID ${id} not found for reordering.`);
|
||||
return;
|
||||
}
|
||||
// Remove the workspace from its current position
|
||||
const currentIndex = workspaces.indexOf(workspace);
|
||||
if (currentIndex === -1) {
|
||||
console.warn(`Workspace with ID ${id} not found in the list.`);
|
||||
return;
|
||||
}
|
||||
workspaces.splice(currentIndex, 1);
|
||||
// Insert the workspace at the new position
|
||||
if (newPosition < 0 || newPosition > workspaces.length) {
|
||||
console.warn(`Invalid position ${newPosition} for reordering workspace with ID ${id}.`);
|
||||
return;
|
||||
}
|
||||
workspaces.splice(newPosition, 0, workspace);
|
||||
// Update the positions in the storage
|
||||
await ZenWorkspacesStorage.updateWorkspacePositions(workspaces);
|
||||
// Propagate the changes
|
||||
await this._propagateWorkspaceData();
|
||||
}
|
||||
|
||||
async moveWorkspace(draggedWorkspaceId, targetWorkspaceId) {
|
||||
@@ -1553,28 +1296,14 @@ var gZenWorkspaces = new (class extends ZenMultiWindowFeature {
|
||||
await this._propagateWorkspaceData();
|
||||
}
|
||||
|
||||
async openWorkspacesDialog(event) {
|
||||
if (!this.workspaceEnabled || this.isPrivateWindow) {
|
||||
return;
|
||||
}
|
||||
let target = this.activeWorkspaceIndicator || event.target;
|
||||
let panel = document.getElementById('PanelUI-zen-workspaces');
|
||||
await this._propagateWorkspaceData({
|
||||
ignoreStrip: true,
|
||||
clearCache: false,
|
||||
});
|
||||
PanelMultiView.openPopup(panel, target, {
|
||||
position: 'bottomright topright',
|
||||
triggerEvent: event,
|
||||
}).catch(console.error);
|
||||
}
|
||||
|
||||
async openWorkspaceCreation(event) {
|
||||
let createForm;
|
||||
const previousWorkspace = await this.getActiveWorkspace();
|
||||
await this.createAndSaveWorkspace('Space', undefined, false, 0, {
|
||||
beforeChangeCallback: async (workspace) => {
|
||||
createForm = document.createXULElement('zen-workspace-creation');
|
||||
createForm.setAttribute('workspace-id', workspace.uuid);
|
||||
createForm.setAttribute('previous-workspace-id', previousWorkspace?.uuid || '');
|
||||
gBrowser.tabContainer.after(createForm);
|
||||
await createForm.promiseInitialized;
|
||||
},
|
||||
@@ -1582,11 +1311,6 @@ var gZenWorkspaces = new (class extends ZenMultiWindowFeature {
|
||||
createForm.finishSetup();
|
||||
}
|
||||
|
||||
closeWorkspacesSubView() {
|
||||
let parentPanel = document.getElementById('PanelUI-zen-workspaces-multiview');
|
||||
parentPanel.goBack(parentPanel);
|
||||
}
|
||||
|
||||
// Workspaces management
|
||||
|
||||
_deleteAllTabsInWorkspace(workspaceID) {
|
||||
|
Reference in New Issue
Block a user