mirror of
https://github.com/zen-browser/desktop.git
synced 2026-02-02 18:14:38 +00:00
259 lines
9.3 KiB
JavaScript
259 lines
9.3 KiB
JavaScript
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
{
|
|
class nsZenWorkspace extends MozXULElement {
|
|
static get markup() {
|
|
return `
|
|
<vbox class="zen-workspace-tabs-section zen-current-workspace-indicator" flex="1" context="zenWorkspaceMoreActions">
|
|
<hbox class="zen-current-workspace-indicator-icon" />
|
|
<label class="zen-current-workspace-indicator-name" flex="1" />
|
|
<toolbarbutton class="toolbarbutton-1 chromeclass-toolbar-additional zen-workspaces-actions" context="zenWorkspaceMoreActions" />
|
|
</vbox>
|
|
<arrowscrollbox orient="vertical" class="workspace-arrowscrollbox">
|
|
<vbox class="zen-workspace-tabs-section zen-workspace-pinned-tabs-section" hide-separator="true">
|
|
<html:div class="pinned-tabs-container-separator"></html:div>
|
|
</vbox>
|
|
<vbox class="zen-workspace-tabs-section zen-workspace-normal-tabs-section">
|
|
<!-- Let it me as an ID to mantain compatibility with firefox's tabbrowser -->
|
|
<hbox id="tabbrowser-arrowscrollbox-periphery">
|
|
<toolbartabstop/>
|
|
<toolbarbutton id="tabs-newtab-button"
|
|
class="toolbarbutton-1"
|
|
command="cmd_newNavigatorTab"
|
|
tooltip="dynamic-shortcut-tooltip"
|
|
data-l10n-id="tabs-toolbar-new-tab"/>
|
|
<spacer class="closing-tabs-spacer" style="width: 0;"/>
|
|
</hbox>
|
|
</vbox>
|
|
</arrowscrollbox>
|
|
<vbox class="zen-workspace-empty-space" flex="1" />
|
|
`;
|
|
}
|
|
|
|
static get inheritedAttributes() {
|
|
return {
|
|
'.zen-workspace-tabs-section': 'zen-workspace-id=id',
|
|
};
|
|
}
|
|
|
|
constructor() {
|
|
super();
|
|
}
|
|
|
|
connectedCallback() {
|
|
if (this.delayConnectedCallback() || this._hasConnected) {
|
|
// If we are not ready yet, or if we have already connected, we
|
|
// don't need to do anything.
|
|
return;
|
|
}
|
|
|
|
this._hasConnected = true;
|
|
this.appendChild(this.constructor.fragment);
|
|
|
|
this.tabsContainer = this.querySelector('.zen-workspace-normal-tabs-section');
|
|
this.indicator = this.querySelector('.zen-current-workspace-indicator');
|
|
this.pinnedTabsContainer = this.querySelector('.zen-workspace-pinned-tabs-section');
|
|
this.initializeAttributeInheritance();
|
|
|
|
this.scrollbox = this.querySelector('arrowscrollbox');
|
|
this.scrollbox.smoothScroll = Services.prefs.getBoolPref(
|
|
'zen.startup.smooth-scroll-in-tabs',
|
|
false
|
|
);
|
|
|
|
this.scrollbox.addEventListener('wheel', this, true);
|
|
this.scrollbox.addEventListener('underflow', this);
|
|
this.scrollbox.addEventListener('overflow', this);
|
|
|
|
this.indicator.querySelector('.zen-current-workspace-indicator-name').onRenameFinished =
|
|
this.onIndicatorRenameFinished.bind(this);
|
|
|
|
this.pinnedTabsContainer.scrollbox = this.scrollbox;
|
|
|
|
this.indicator
|
|
.querySelector('.zen-workspaces-actions')
|
|
.addEventListener('click', this.onActionsCommand.bind(this));
|
|
|
|
this.indicator
|
|
.querySelector('.zen-current-workspace-indicator-icon')
|
|
.addEventListener('dblclick', (event) => {
|
|
event.stopPropagation();
|
|
gZenWorkspaces.changeWorkspaceIcon();
|
|
});
|
|
|
|
this.scrollbox._getScrollableElements = () => {
|
|
const children = [...this.pinnedTabsContainer.children, ...this.tabsContainer.children];
|
|
if (Services.prefs.getBoolPref('zen.view.show-newtab-button-top', false)) {
|
|
// Move the perifery to the first non-pinned tab
|
|
const periphery = this.tabsContainer.querySelector(
|
|
'#tabbrowser-arrowscrollbox-periphery'
|
|
);
|
|
if (periphery) {
|
|
const firstNonPinnedTabIndex = children.findIndex(
|
|
(child) => gBrowser.isTab(child) && !child.pinned
|
|
);
|
|
if (firstNonPinnedTabIndex > -1) {
|
|
// Change to new location and remove from the old one on the list
|
|
const peripheryIndex = children.indexOf(periphery);
|
|
if (peripheryIndex > -1) {
|
|
children.splice(peripheryIndex, 1);
|
|
}
|
|
children.splice(firstNonPinnedTabIndex, 0, periphery);
|
|
}
|
|
}
|
|
}
|
|
return Array.prototype.filter.call(
|
|
children,
|
|
this.scrollbox._canScrollToElement,
|
|
this.scrollbox
|
|
);
|
|
};
|
|
|
|
this.scrollbox._canScrollToElement = (element) => {
|
|
if (gBrowser.isTab(element)) {
|
|
return (
|
|
!element.hasAttribute('zen-essential') &&
|
|
!this.hasAttribute('positionpinnedtabs') &&
|
|
!element.hasAttribute('zen-empty-tab')
|
|
);
|
|
}
|
|
return true;
|
|
};
|
|
|
|
// Override for performance reasons. This is the size of a single element
|
|
// that can be scrolled when using mouse wheel scrolling. If we don't do
|
|
// this then arrowscrollbox computes this value by calling
|
|
// _getScrollableElements and dividing the box size by that number.
|
|
// However in the tabstrip case we already know the answer to this as,
|
|
// when we're overflowing, it is always the same as the tab min width or
|
|
// height. For tab group labels, the number won't exactly match, but
|
|
// that shouldn't be a problem in practice since the arrowscrollbox
|
|
// stops at element bounds when finishing scrolling.
|
|
try {
|
|
Object.defineProperty(this.scrollbox, 'lineScrollAmount', {
|
|
get: () => 36,
|
|
});
|
|
} catch (e) {
|
|
console.warn('Failed to set lineScrollAmount', e);
|
|
}
|
|
|
|
// Add them manually since attribute inheritance doesn't work
|
|
// for multiple layers of shadow DOM.
|
|
this.tabsContainer.setAttribute('zen-workspace-id', this.id);
|
|
this.pinnedTabsContainer.setAttribute('zen-workspace-id', this.id);
|
|
|
|
this.#updateOverflow();
|
|
|
|
this.onGradientCacheChanged = this.#onGradientCacheChanged.bind(this);
|
|
window.addEventListener('ZenGradientCacheChanged', this.onGradientCacheChanged);
|
|
|
|
this.dispatchEvent(
|
|
new CustomEvent('ZenWorkspaceAttached', {
|
|
bubbles: true,
|
|
composed: true,
|
|
detail: { workspace: this },
|
|
})
|
|
);
|
|
}
|
|
|
|
disconnectedCallback() {
|
|
window.removeEventListener('ZenGradientCacheChanged', this.onGradientCacheChanged);
|
|
}
|
|
|
|
get active() {
|
|
return this.hasAttribute('active');
|
|
}
|
|
|
|
set active(value) {
|
|
if (value) {
|
|
this.setAttribute('active', 'true');
|
|
} else {
|
|
this.removeAttribute('active');
|
|
}
|
|
this.#updateOverflow();
|
|
}
|
|
|
|
#updateOverflow() {
|
|
if (!this.scrollbox) return;
|
|
if (this.overflows) {
|
|
this.#dispatchEventFromScrollbox('overflow');
|
|
} else {
|
|
this.#dispatchEventFromScrollbox('underflow');
|
|
}
|
|
}
|
|
|
|
#dispatchEventFromScrollbox(type) {
|
|
this.scrollbox.dispatchEvent(new CustomEvent(type, {}));
|
|
}
|
|
|
|
get overflows() {
|
|
return this.scrollbox.overflowing;
|
|
}
|
|
|
|
handleEvent(event) {
|
|
if (this.active) {
|
|
gBrowser.tabContainer.handleEvent(event);
|
|
}
|
|
}
|
|
|
|
get workspaceUuid() {
|
|
return this.id;
|
|
}
|
|
|
|
async onIndicatorRenameFinished(newName) {
|
|
if (newName === '') {
|
|
return;
|
|
}
|
|
let workspaces = (await gZenWorkspaces._workspaces()).workspaces;
|
|
let workspaceData = workspaces.find((workspace) => workspace.uuid === this.workspaceUuid);
|
|
workspaceData.name = newName;
|
|
await gZenWorkspaces.saveWorkspace(workspaceData);
|
|
this.indicator.querySelector('.zen-current-workspace-indicator-name').textContent = newName;
|
|
gZenUIManager.showToast('zen-workspace-renamed-toast');
|
|
}
|
|
|
|
onActionsCommand(event) {
|
|
event.stopPropagation();
|
|
const popup = document.getElementById('zenWorkspaceMoreActions');
|
|
const target = event.target;
|
|
target.setAttribute('open', 'true');
|
|
this.indicator.setAttribute('open', 'true');
|
|
const handlePopupHidden = (event) => {
|
|
if (event.target !== popup) return;
|
|
target.removeAttribute('open');
|
|
this.indicator.removeAttribute('open');
|
|
popup.removeEventListener('popuphidden', handlePopupHidden);
|
|
};
|
|
popup.addEventListener('popuphidden', handlePopupHidden);
|
|
popup.openPopup(event.target, 'after_start');
|
|
}
|
|
|
|
get newTabButton() {
|
|
return this.querySelector('#tabs-newtab-button');
|
|
}
|
|
|
|
#onGradientCacheChanged() {
|
|
const { isDarkMode, isExplicitMode, toolbarColor, primaryColor } =
|
|
gZenThemePicker.getGradientForWorkspace(
|
|
gZenWorkspaces.getWorkspaceFromId(this.workspaceUuid)
|
|
);
|
|
if (isExplicitMode) {
|
|
this.style.colorScheme = isDarkMode ? 'dark' : 'light';
|
|
} else {
|
|
this.style.colorScheme = '';
|
|
}
|
|
this.style.setProperty('--toolbox-textcolor', `rgba(${toolbarColor.join(',')})`);
|
|
this.style.setProperty('--zen-primary-color', primaryColor);
|
|
}
|
|
|
|
clearThemeStyles() {
|
|
this.style.colorScheme = '';
|
|
this.style.removeProperty('--toolbox-textcolor');
|
|
this.style.removeProperty('--zen-primary-color');
|
|
}
|
|
}
|
|
|
|
customElements.define('zen-workspace', nsZenWorkspace);
|
|
}
|