mirror of
https://github.com/zen-browser/components.git
synced 2025-07-08 19:39:57 +02:00
Merge pull request #54 from kristijanribaric/feature/workspace-reordering
Feature: Workspace reordering
This commit is contained in:
commit
ec791a3ea1
2 changed files with 231 additions and 142 deletions
|
@ -4,6 +4,7 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
|
||||||
*/
|
*/
|
||||||
_lastSelectedWorkspaceTabs = {};
|
_lastSelectedWorkspaceTabs = {};
|
||||||
_inChangingWorkspace = false;
|
_inChangingWorkspace = false;
|
||||||
|
draggedElement = null;
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
if (!this.shouldHaveWorkspaces) {
|
if (!this.shouldHaveWorkspaces) {
|
||||||
|
@ -305,11 +306,10 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
|
||||||
|
|
||||||
async _propagateWorkspaceData({ ignoreStrip = false } = {}) {
|
async _propagateWorkspaceData({ ignoreStrip = false } = {}) {
|
||||||
await this.foreachWindowAsActive(async (browser) => {
|
await this.foreachWindowAsActive(async (browser) => {
|
||||||
let currentContainer = browser.document.getElementById('PanelUI-zen-workspaces-current-info');
|
|
||||||
let workspaceList = browser.document.getElementById('PanelUI-zen-workspaces-list');
|
let workspaceList = browser.document.getElementById('PanelUI-zen-workspaces-list');
|
||||||
const createWorkspaceElement = (workspace) => {
|
const createWorkspaceElement = (workspace) => {
|
||||||
let element = browser.document.createXULElement('toolbarbutton');
|
let element = browser.document.createXULElement('toolbarbutton');
|
||||||
element.className = 'subviewbutton';
|
element.className = 'subviewbutton zen-workspace-button';
|
||||||
element.setAttribute('tooltiptext', workspace.name);
|
element.setAttribute('tooltiptext', workspace.name);
|
||||||
element.setAttribute('zen-workspace-id', workspace.uuid);
|
element.setAttribute('zen-workspace-id', workspace.uuid);
|
||||||
if (this.isWorkspaceActive(workspace)) {
|
if (this.isWorkspaceActive(workspace)) {
|
||||||
|
@ -325,6 +325,66 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
|
||||||
element.classList.add('identity-color-' + containerGroup.color);
|
element.classList.add('identity-color-' + containerGroup.color);
|
||||||
element.setAttribute('data-usercontextid', containerGroup.userContextId);
|
element.setAttribute('data-usercontextid', containerGroup.userContextId);
|
||||||
}
|
}
|
||||||
|
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'));
|
||||||
|
element.classList.add('dragging');
|
||||||
|
} else {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
}.bind(browser.ZenWorkspaces));
|
||||||
|
|
||||||
|
element.addEventListener('dragover', function (event) {
|
||||||
|
if (this.isReorderModeOn(browser) && this.draggedElement) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.dataTransfer.dropEffect = 'move';
|
||||||
|
}
|
||||||
|
}.bind(browser.ZenWorkspaces));
|
||||||
|
|
||||||
|
element.addEventListener('dragenter', function (event) {
|
||||||
|
if (this.isReorderModeOn(browser) && this.draggedElement) {
|
||||||
|
element.classList.add('dragover');
|
||||||
|
}
|
||||||
|
}.bind(browser.ZenWorkspaces));
|
||||||
|
|
||||||
|
element.addEventListener('dragleave', function (event) {
|
||||||
|
element.classList.remove('dragover');
|
||||||
|
}.bind(browser.ZenWorkspaces));
|
||||||
|
|
||||||
|
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);
|
||||||
|
await this._propagateWorkspaceData();
|
||||||
|
}
|
||||||
|
if (this.draggedElement) {
|
||||||
|
this.draggedElement.classList.remove('dragging');
|
||||||
|
this.draggedElement = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.bind(browser.ZenWorkspaces));
|
||||||
|
|
||||||
|
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.ZenWorkspaces));
|
||||||
|
|
||||||
let childs = browser.MozXULElement.parseXULToFragment(`
|
let childs = browser.MozXULElement.parseXULToFragment(`
|
||||||
<div class="zen-workspace-icon">
|
<div class="zen-workspace-icon">
|
||||||
</div>
|
</div>
|
||||||
|
@ -334,6 +394,7 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
|
||||||
<div class="zen-workspace-container" ${containerGroup ? '' : 'hidden="true"'}>
|
<div class="zen-workspace-container" ${containerGroup ? '' : 'hidden="true"'}>
|
||||||
</div>
|
</div>
|
||||||
</vbox>
|
</vbox>
|
||||||
|
<image class="toolbarbutton-icon zen-workspace-actions-reorder-icon" ></image>
|
||||||
<toolbarbutton closemenu="none" class="toolbarbutton-1 zen-workspace-actions">
|
<toolbarbutton closemenu="none" class="toolbarbutton-1 zen-workspace-actions">
|
||||||
<image class="toolbarbutton-icon" id="zen-workspace-actions-menu-icon"></image>
|
<image class="toolbarbutton-icon" id="zen-workspace-actions-menu-icon"></image>
|
||||||
</toolbarbutton>
|
</toolbarbutton>
|
||||||
|
@ -358,6 +419,9 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
|
||||||
}).bind(browser.ZenWorkspaces));
|
}).bind(browser.ZenWorkspaces));
|
||||||
element.appendChild(childs);
|
element.appendChild(childs);
|
||||||
element.onclick = (async () => {
|
element.onclick = (async () => {
|
||||||
|
if (this.isReorderModeOn(browser)) {
|
||||||
|
return; // Return early if reorder mode is on
|
||||||
|
}
|
||||||
if (event.target.closest('.zen-workspace-actions')) {
|
if (event.target.closest('.zen-workspace-actions')) {
|
||||||
return; // Ignore clicks on the actions button
|
return; // Ignore clicks on the actions button
|
||||||
}
|
}
|
||||||
|
@ -373,24 +437,16 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
|
||||||
};
|
};
|
||||||
browser.ZenWorkspaces._workspaceCache = null;
|
browser.ZenWorkspaces._workspaceCache = null;
|
||||||
let workspaces = await browser.ZenWorkspaces._workspaces();
|
let workspaces = await browser.ZenWorkspaces._workspaces();
|
||||||
let activeWorkspace = await browser.ZenWorkspaces.getActiveWorkspace();
|
|
||||||
currentContainer.innerHTML = '';
|
|
||||||
workspaceList.innerHTML = '';
|
workspaceList.innerHTML = '';
|
||||||
workspaceList.parentNode.style.display = 'flex';
|
workspaceList.parentNode.style.display = 'flex';
|
||||||
if (workspaces.workspaces.length - 1 <= 0) {
|
if (workspaces.workspaces.length <= 0) {
|
||||||
workspaceList.innerHTML = 'No workspaces available';
|
workspaceList.innerHTML = 'No workspaces available';
|
||||||
workspaceList.setAttribute('empty', 'true');
|
workspaceList.setAttribute('empty', 'true');
|
||||||
} else {
|
} else {
|
||||||
workspaceList.removeAttribute('empty');
|
workspaceList.removeAttribute('empty');
|
||||||
}
|
}
|
||||||
if (activeWorkspace) {
|
|
||||||
let currentWorkspace = createWorkspaceElement(activeWorkspace);
|
|
||||||
currentContainer.appendChild(currentWorkspace);
|
|
||||||
}
|
|
||||||
for (let workspace of workspaces.workspaces) {
|
for (let workspace of workspaces.workspaces) {
|
||||||
if (browser.ZenWorkspaces.isWorkspaceActive(workspace)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let workspaceElement = createWorkspaceElement(workspace);
|
let workspaceElement = createWorkspaceElement(workspace);
|
||||||
workspaceList.appendChild(workspaceElement);
|
workspaceList.appendChild(workspaceElement);
|
||||||
}
|
}
|
||||||
|
@ -400,6 +456,46 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update draggable attribute
|
||||||
|
const workspaceElements = document.querySelectorAll('.zen-workspace-button');
|
||||||
|
workspaceElements.forEach(elem => {
|
||||||
|
if (isActive) {
|
||||||
|
elem.removeAttribute('draggable');
|
||||||
|
} else {
|
||||||
|
elem.setAttribute('draggable', 'true');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async moveWorkspace(draggedWorkspaceId, targetWorkspaceId) {
|
||||||
|
const workspaces = (await this._workspaces()).workspaces;
|
||||||
|
const draggedIndex = workspaces.findIndex(w => w.uuid === draggedWorkspaceId);
|
||||||
|
const draggedWorkspace = workspaces.splice(draggedIndex, 1)[0];
|
||||||
|
const targetIndex = workspaces.findIndex(w => w.uuid === targetWorkspaceId);
|
||||||
|
workspaces.splice(targetIndex, 0, draggedWorkspace);
|
||||||
|
|
||||||
|
await ZenWorkspacesStorage.updateWorkspacePositions(workspaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async openWorkspacesDialog(event) {
|
async openWorkspacesDialog(event) {
|
||||||
if (!this.workspaceEnabled) {
|
if (!this.workspaceEnabled) {
|
||||||
return;
|
return;
|
||||||
|
@ -426,96 +522,116 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
|
||||||
await this._expandWorkspacesStrip();
|
await this._expandWorkspacesStrip();
|
||||||
}
|
}
|
||||||
|
|
||||||
async _expandWorkspacesStrip(browser = undefined) {
|
async _expandWorkspacesStrip(browser = window) {
|
||||||
if (typeof browser === 'undefined' || typeof browser.ZenWorkspaces === 'undefined') {
|
if (typeof browser.ZenWorkspaces === 'undefined') {
|
||||||
browser = window;
|
browser = window;
|
||||||
}
|
}
|
||||||
let workspaces = await browser.ZenWorkspaces._workspaces();
|
let button = browser.document.getElementById('zen-workspaces-button');
|
||||||
let workspaceList = browser.document.getElementById('zen-workspaces-button');
|
|
||||||
const newWorkspacesButton = browser.document.createXULElement('toolbarbutton');
|
if (!button) {
|
||||||
newWorkspacesButton.id = 'zen-workspaces-button';
|
button = browser.document.createXULElement('toolbarbutton');
|
||||||
newWorkspacesButton.setAttribute('removable', 'true');
|
button.id = 'zen-workspaces-button';
|
||||||
newWorkspacesButton.setAttribute('showInPrivateBrowsing', 'false');
|
let navbar = browser.document.getElementById('nav-bar');
|
||||||
newWorkspacesButton.setAttribute('tooltiptext', 'Workspaces');
|
navbar.appendChild(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (button.firstChild) {
|
||||||
|
button.firstChild.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let attr of [...button.attributes]) {
|
||||||
|
if (attr.name !== 'id') {
|
||||||
|
button.removeAttribute(attr.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button.className = '';
|
||||||
|
|
||||||
|
if (this._workspacesButtonClickListener) {
|
||||||
|
button.removeEventListener('click', this._workspacesButtonClickListener);
|
||||||
|
this._workspacesButtonClickListener = null;
|
||||||
|
}
|
||||||
|
if (this._workspaceButtonContextMenuListener) {
|
||||||
|
button.removeEventListener('contextmenu', this._workspaceButtonContextMenuListener);
|
||||||
|
this._workspaceButtonContextMenuListener = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.shouldShowIconStrip) {
|
if (this.shouldShowIconStrip) {
|
||||||
|
button.setAttribute('removable', 'true');
|
||||||
|
button.setAttribute('showInPrivateBrowsing', 'false');
|
||||||
|
button.setAttribute('tooltiptext', 'Workspaces');
|
||||||
|
|
||||||
|
let workspaces = await this._workspaces();
|
||||||
|
|
||||||
for (let workspace of workspaces.workspaces) {
|
for (let workspace of workspaces.workspaces) {
|
||||||
let button = browser.document.createXULElement('toolbarbutton');
|
let workspaceButton = browser.document.createXULElement('toolbarbutton');
|
||||||
button.className = 'subviewbutton';
|
workspaceButton.className = 'subviewbutton';
|
||||||
button.setAttribute('tooltiptext', workspace.name);
|
workspaceButton.setAttribute('tooltiptext', workspace.name);
|
||||||
button.setAttribute('zen-workspace-id', workspace.uuid);
|
workspaceButton.setAttribute('zen-workspace-id', workspace.uuid);
|
||||||
|
|
||||||
if (this.isWorkspaceActive(workspace)) {
|
if (this.isWorkspaceActive(workspace)) {
|
||||||
button.setAttribute('active', 'true');
|
workspaceButton.setAttribute('active', 'true');
|
||||||
|
} else {
|
||||||
|
workspaceButton.removeAttribute('active');
|
||||||
}
|
}
|
||||||
if (workspace.default) {
|
if (workspace.default) {
|
||||||
button.setAttribute('default', 'true');
|
workspaceButton.setAttribute('default', 'true');
|
||||||
|
} else {
|
||||||
|
workspaceButton.removeAttribute('default');
|
||||||
}
|
}
|
||||||
button.onclick = (async (_, event) => {
|
|
||||||
// Make sure it's not a context menu event
|
workspaceButton.addEventListener('click', async (event) => {
|
||||||
if (event.button !== 0) {
|
if (event.button !== 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await this.changeWorkspace(workspace);
|
await this.changeWorkspace(workspace);
|
||||||
}).bind(browser.ZenWorkspaces, workspace);
|
});
|
||||||
|
|
||||||
let icon = browser.document.createXULElement('div');
|
let icon = browser.document.createXULElement('div');
|
||||||
icon.className = 'zen-workspace-icon';
|
icon.className = 'zen-workspace-icon';
|
||||||
icon.textContent = this.getWorkspaceIcon(workspace);
|
icon.textContent = this.getWorkspaceIcon(workspace);
|
||||||
button.appendChild(icon);
|
workspaceButton.appendChild(icon);
|
||||||
newWorkspacesButton.appendChild(button);
|
button.appendChild(workspaceButton);
|
||||||
}
|
}
|
||||||
// Listen for context menu events and open the all workspaces dialog
|
|
||||||
newWorkspacesButton.addEventListener(
|
|
||||||
'contextmenu',
|
|
||||||
((event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
browser.ZenWorkspaces.openWorkspacesDialog(event);
|
|
||||||
}).bind(this)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
workspaceList.after(newWorkspacesButton);
|
this._workspaceButtonContextMenuListener = (event) => {
|
||||||
workspaceList.remove();
|
event.preventDefault();
|
||||||
|
browser.ZenWorkspaces.openWorkspacesDialog(event);
|
||||||
|
};
|
||||||
|
button.addEventListener('contextmenu', this._workspaceButtonContextMenuListener);
|
||||||
|
} else {
|
||||||
|
let activeWorkspace = await this.getActiveWorkspace();
|
||||||
|
if (activeWorkspace) {
|
||||||
|
button.setAttribute('as-button', 'true');
|
||||||
|
button.classList.add('toolbarbutton-1', 'zen-sidebar-action-button');
|
||||||
|
|
||||||
if (!this.shouldShowIconStrip) {
|
this._workspacesButtonClickListener = browser.ZenWorkspaces.openWorkspacesDialog.bind(browser.ZenWorkspaces);
|
||||||
await this._updateWorkspacesButton(browser);
|
button.addEventListener('click', this._workspacesButtonClickListener);
|
||||||
|
|
||||||
|
const wrapper = browser.document.createXULElement('hbox');
|
||||||
|
wrapper.className = 'zen-workspace-sidebar-wrapper';
|
||||||
|
|
||||||
|
const icon = browser.document.createXULElement('div');
|
||||||
|
icon.className = 'zen-workspace-sidebar-icon';
|
||||||
|
icon.textContent = this.getWorkspaceIcon(activeWorkspace);
|
||||||
|
|
||||||
|
const name = browser.document.createXULElement('div');
|
||||||
|
name.className = 'zen-workspace-sidebar-name';
|
||||||
|
name.textContent = activeWorkspace.name;
|
||||||
|
|
||||||
|
if (!this.workspaceHasIcon(activeWorkspace)) {
|
||||||
|
icon.setAttribute('no-icon', 'true');
|
||||||
|
}
|
||||||
|
|
||||||
|
wrapper.appendChild(icon);
|
||||||
|
wrapper.appendChild(name);
|
||||||
|
|
||||||
|
button.appendChild(wrapper);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async _updateWorkspacesButton(browser = window) {
|
|
||||||
let button = browser.document.getElementById('zen-workspaces-button');
|
|
||||||
if (!button) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let activeWorkspace = await this.getActiveWorkspace();
|
|
||||||
if (activeWorkspace) {
|
|
||||||
button.setAttribute('as-button', 'true');
|
|
||||||
button.classList.add('toolbarbutton-1', 'zen-sidebar-action-button');
|
|
||||||
|
|
||||||
button.addEventListener('click', browser.ZenWorkspaces.openWorkspacesDialog.bind(browser.ZenWorkspaces));
|
|
||||||
|
|
||||||
const wrapper = browser.document.createXULElement('hbox');
|
|
||||||
wrapper.className = 'zen-workspace-sidebar-wrapper';
|
|
||||||
|
|
||||||
const icon = browser.document.createElement('div');
|
|
||||||
icon.className = 'zen-workspace-sidebar-icon';
|
|
||||||
icon.textContent = this.getWorkspaceIcon(activeWorkspace);
|
|
||||||
|
|
||||||
// use text content instead of innerHTML to avoid XSS
|
|
||||||
const name = browser.document.createElement('div');
|
|
||||||
name.className = 'zen-workspace-sidebar-name';
|
|
||||||
name.textContent = activeWorkspace.name;
|
|
||||||
|
|
||||||
if (!this.workspaceHasIcon(activeWorkspace)) {
|
|
||||||
icon.setAttribute('no-icon', 'true');
|
|
||||||
}
|
|
||||||
|
|
||||||
wrapper.appendChild(icon);
|
|
||||||
wrapper.appendChild(name);
|
|
||||||
|
|
||||||
button.innerHTML = '';
|
|
||||||
button.appendChild(wrapper);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Workspaces management
|
// Workspaces management
|
||||||
|
|
||||||
|
@ -575,7 +691,6 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
|
||||||
let icon = document.querySelector('#PanelUI-zen-workspaces-icon-picker [selected]');
|
let icon = document.querySelector('#PanelUI-zen-workspaces-icon-picker [selected]');
|
||||||
icon?.removeAttribute('selected');
|
icon?.removeAttribute('selected');
|
||||||
await this.createAndSaveWorkspace(workspaceName, false, icon?.label);
|
await this.createAndSaveWorkspace(workspaceName, false, icon?.label);
|
||||||
await this._updateWorkspacesButton();
|
|
||||||
await this._propagateWorkspaceData();
|
await this._propagateWorkspaceData();
|
||||||
this.closeWorkspacesSubView();
|
this.closeWorkspacesSubView();
|
||||||
}
|
}
|
||||||
|
|
|
@ -257,68 +257,6 @@ var ZenWorkspacesStorage = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
async updateWorkspaceOrder(uuid, newPosition, notifyObservers = true) {
|
|
||||||
const changedUUIDs = new Set([uuid]);
|
|
||||||
|
|
||||||
await PlacesUtils.withConnectionWrapper('ZenWorkspacesStorage.updateWorkspaceOrder', async (db) => {
|
|
||||||
await db.executeTransaction(async () => {
|
|
||||||
const now = Date.now();
|
|
||||||
|
|
||||||
// Get the positions of the workspaces before and after the new position
|
|
||||||
const neighborPositions = await db.execute(`
|
|
||||||
SELECT
|
|
||||||
(SELECT MAX("position") FROM zen_workspaces WHERE "position" < :newPosition) as before_position,
|
|
||||||
(SELECT MIN("position") FROM zen_workspaces WHERE "position" > :newPosition) as after_position
|
|
||||||
`, { newPosition });
|
|
||||||
|
|
||||||
let beforePosition = neighborPositions[0].getResultByName('before_position');
|
|
||||||
let afterPosition = neighborPositions[0].getResultByName('after_position');
|
|
||||||
|
|
||||||
// Calculate the new position
|
|
||||||
if (beforePosition === null && afterPosition === null) {
|
|
||||||
// This is the only workspace
|
|
||||||
newPosition = 1000;
|
|
||||||
} else if (beforePosition === null) {
|
|
||||||
// This will be the first workspace
|
|
||||||
newPosition = Math.floor(afterPosition / 2);
|
|
||||||
} else if (afterPosition === null) {
|
|
||||||
// This will be the last workspace
|
|
||||||
newPosition = beforePosition + 1000;
|
|
||||||
} else {
|
|
||||||
// This workspace will be between two others
|
|
||||||
newPosition = Math.floor((beforePosition + afterPosition) / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the workspace's position
|
|
||||||
await db.execute(`
|
|
||||||
UPDATE zen_workspaces
|
|
||||||
SET "position" = :newPosition
|
|
||||||
WHERE uuid = :uuid
|
|
||||||
`, { uuid, newPosition });
|
|
||||||
|
|
||||||
// Record the change
|
|
||||||
await db.execute(`
|
|
||||||
INSERT OR REPLACE INTO zen_workspaces_changes (uuid, timestamp)
|
|
||||||
VALUES (:uuid, :timestamp)
|
|
||||||
`, {
|
|
||||||
uuid,
|
|
||||||
timestamp: Math.floor(now / 1000)
|
|
||||||
});
|
|
||||||
|
|
||||||
await this.updateLastChangeTimestamp(db);
|
|
||||||
|
|
||||||
// Check if reordering is necessary
|
|
||||||
if (this.shouldReorderWorkspaces(beforePosition, newPosition, afterPosition)) {
|
|
||||||
await this.reorderAllWorkspaces(db, changedUUIDs);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
if (notifyObservers) {
|
|
||||||
this._notifyWorkspacesChanged("zen-workspace-updated", Array.from(changedUUIDs));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
shouldReorderWorkspaces(before, current, after) {
|
shouldReorderWorkspaces(before, current, after) {
|
||||||
const minGap = 1; // Minimum allowed gap between positions
|
const minGap = 1; // Minimum allowed gap between positions
|
||||||
return (before !== null && current - before < minGap) || (after !== null && after - current < minGap);
|
return (before !== null && current - before < minGap) || (after !== null && after - current < minGap);
|
||||||
|
@ -357,4 +295,40 @@ var ZenWorkspacesStorage = {
|
||||||
`);
|
`);
|
||||||
return result.length ? parseInt(result[0].getResultByName('value'), 10) : 0;
|
return result.length ? parseInt(result[0].getResultByName('value'), 10) : 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async updateWorkspacePositions(workspaces) {
|
||||||
|
const changedUUIDs = new Set();
|
||||||
|
|
||||||
|
await PlacesUtils.withConnectionWrapper('ZenWorkspacesStorage.updateWorkspacePositions', async (db) => {
|
||||||
|
await db.executeTransaction(async () => {
|
||||||
|
const now = Date.now();
|
||||||
|
|
||||||
|
for (let i = 0; i < workspaces.length; i++) {
|
||||||
|
const workspace = workspaces[i];
|
||||||
|
const newPosition = (i + 1) * 1000;
|
||||||
|
|
||||||
|
await db.execute(`
|
||||||
|
UPDATE zen_workspaces
|
||||||
|
SET "position" = :newPosition
|
||||||
|
WHERE uuid = :uuid
|
||||||
|
`, { newPosition, uuid: workspace.uuid });
|
||||||
|
|
||||||
|
changedUUIDs.add(workspace.uuid);
|
||||||
|
|
||||||
|
// Record the change
|
||||||
|
await db.execute(`
|
||||||
|
INSERT OR REPLACE INTO zen_workspaces_changes (uuid, timestamp)
|
||||||
|
VALUES (:uuid, :timestamp)
|
||||||
|
`, {
|
||||||
|
uuid: workspace.uuid,
|
||||||
|
timestamp: Math.floor(now / 1000)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.updateLastChangeTimestamp(db);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this._notifyWorkspacesChanged("zen-workspace-updated", Array.from(changedUUIDs));
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue